Skip to content

Commit 37ccf13

Browse files
committed
Merge branch 'dev' into release
2 parents a7470a3 + cee5f32 commit 37ccf13

16 files changed

+133
-27
lines changed

CMakeLists.txt

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,20 @@
1818
cmake_minimum_required (VERSION 3.9)
1919

2020
project (Lagrange
21-
VERSION 1.17.4
21+
VERSION 1.17.5
2222
DESCRIPTION "A Beautiful Gemini Client"
2323
LANGUAGES C
2424
)
2525
set (COPYRIGHT_YEAR 2023)
2626
if (IOS)
2727
set (PROJECT_VERSION 1.17)
28-
set (IOS_BUNDLE_VERSION 4)
29-
set (IOS_BUILD_DATE "2023-11-04")
28+
set (IOS_BUNDLE_VERSION 6)
29+
set (IOS_BUILD_DATE "2023-12-04")
3030
endif ()
3131
if (ANDROID)
3232
set (PROJECT_VERSION 1.17)
33-
set (ANDROID_BUILD_VERSION b24) # remember to update Gradle, AndroidManifest.xml
34-
set (ANDROID_BUILD_DATE "2023-11-04")
33+
set (ANDROID_BUILD_VERSION b25) # remember to update Gradle, AndroidManifest.xml
34+
set (ANDROID_BUILD_DATE "2023-12-04")
3535
endif ()
3636

3737
# Load modules from the source tree

lib/the_Foundation

Submodule the_Foundation updated from a6a8f58 to a963029

po/eo.po

+42-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ msgstr ""
33
"Project-Id-Version: PACKAGE VERSION\n"
44
"Report-Msgid-Bugs-To: [email protected]\n"
55
"POT-Creation-Date: 2023-01-19 04:46+0000\n"
6-
"PO-Revision-Date: 2023-03-30 18:15+0000\n"
6+
"PO-Revision-Date: 2023-11-28 17:14+0000\n"
77
"Last-Translator: Nikolay Korotkiy <[email protected]>\n"
88
"Language-Team: Esperanto <http://weblate.skyjake.fi/projects/lagrange/ui/eo/>"
99
"\n"
@@ -841,7 +841,7 @@ msgid "heading.upload.id"
841841
msgstr "Rajtigo"
842842

843843
msgid "dlg.upload.id.default"
844-
msgstr "Defaŭlto"
844+
msgstr "Defaŭlta identeco"
845845

846846
# used on mobile
847847
msgid "dlg.upload.file"
@@ -1316,3 +1316,43 @@ msgstr "Turka"
13161316
# A language choice in the Translation dialog.
13171317
msgid "lang.uk"
13181318
msgstr "Ukraina"
1319+
1320+
msgid "menu.snip.prefs"
1321+
msgstr "Agordi…"
1322+
1323+
msgid "menu.snip.delete"
1324+
msgstr "Forigi"
1325+
1326+
msgid "snip.name"
1327+
msgstr "Nomo:"
1328+
1329+
msgid "heading.snip.new"
1330+
msgstr "Nova fragmento"
1331+
1332+
msgid "error.ansi"
1333+
msgstr "Terminalimitilo"
1334+
1335+
# Action label
1336+
msgid "fontpack.meta.viewfile"
1337+
msgstr "Montri dosieron"
1338+
1339+
msgid "fontpack.export"
1340+
msgstr "Montri la ŝablonon fontpack.ini"
1341+
1342+
msgid "sniped.new"
1343+
msgstr "Nova fragmento"
1344+
1345+
msgid "snip.accept"
1346+
msgstr "Konservi fragmenton"
1347+
1348+
msgid "snip.content"
1349+
msgstr "Enhavo:"
1350+
1351+
msgid "heading.snip.edit"
1352+
msgstr "Redakti fragmenton"
1353+
1354+
msgid "menu.snip.clipboard"
1355+
msgstr "Kopii al tondujo"
1356+
1357+
msgid "menu.snip.edit"
1358+
msgstr "Redakti…"

res/about/android-version.gmi

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
```
77
# Release notes
88

9+
## 1.17 (Beta 25)
10+
* Fixed a few small memory leaks.
11+
* Gopher: Detect audio media type from file extension with the `s` item type (it's not always WAV).
12+
* Content that uses `charset=utf-8` is checked for validity. If the encoding is invalid, the content is instead decoded as CP437 (if it has ANSI escapes; possibly it's ASCII art) or just Latin-1.
13+
* Modified rule for when 'text/plain' is assumed to actually be 'text/gemini' based on the file extension.
14+
* Updated dependencies to newer versions (OpenSSL, GNU FriBidi, libiconv, libunistring).
15+
916
## 1.17 (Beta 24)
1017
* Tabs opened in background are immediately added to the URL history.
1118
* Fixed initial scope of a created identity when using the default selection.

res/about/ios-version.gmi

+8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66
```
77
# Release notes
88

9+
## 1.17 (6)
10+
* Fixed a few small memory leaks.
11+
* Fixed unnecessary copying of data while waiting for an audio buffer to become playable. This potentially caused the operating system to terminate the app due to excessive memory use.
12+
* Gopher: Detect audio media type from file extension with the `s` item type (it's not always WAV).
13+
* Content that uses `charset=utf-8` is checked for validity. If the encoding is invalid, the content is instead decoded as CP437 (if it has ANSI escapes; possibly it's ASCII art) or just Latin-1.
14+
* Modified rule for when 'text/plain' is assumed to actually be 'text/gemini' based on the file extension.
15+
* Updated UI translations.
16+
917
## 1.17 (4)
1018
* Tabs opened in background are immediately added to the URL history.
1119
* Fixed initial scope of a created identity when using the default selection.

res/about/version.gmi

+8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66
```
77
# Release notes
88

9+
## 1.17.5
10+
* Fixed a few small memory leaks.
11+
* Fixed unnecessary copying of data while waiting for an audio buffer to become playable.
12+
* Gopher: Detect audio media type from file extension with the `s` item type (it's not always WAV).
13+
* Content that uses `charset=utf-8` is checked for validity. If the encoding is invalid, the content is instead decoded as CP437 (if it has ANSI escapes; possibly it's ASCII art) or just Latin-1.
14+
* Remove ANSI escapes from window titles.
15+
* Modified rule for when 'text/plain' is assumed to actually be 'text/gemini' based on the file extension.
16+
917
## 1.17.4
1018
* Removed automatic horizontal scrolling of wide preformatted blocks. Instead, hold down the Shift key to scroll horizontally with the mouse wheel.
1119
* Fixed an event processing issue where some events were not handled as expected, for instance when opening a link into split view the opened link was not highlighted.

res/lang/eo.bin

35 Bytes
Binary file not shown.

src/audio/player.c

+11-4
Original file line numberDiff line numberDiff line change
@@ -475,12 +475,11 @@ static iRangecc mediaType_(const iString *str) {
475475
return part;
476476
}
477477

478-
static iContentSpec contentSpec_Player_(const iPlayer *d) {
478+
static iContentSpec detectContentSpec_Player_(const iPlayer *d) {
479479
iContentSpec content;
480480
iZap(content);
481481
const size_t dataSize = size_InputBuf(d->data);
482-
iBuffer *buf = iClob(new_Buffer());
483-
open_Buffer(buf, &d->data->data);
482+
iBuffer *buf = NULL;
484483
const iRangecc mediaType = mediaType_(&d->mime);
485484
if (equal_Rangecc(mediaType, "audio/wave") || equal_Rangecc(mediaType, "audio/wav") ||
486485
equal_Rangecc(mediaType, "audio/x-wav") || equal_Rangecc(mediaType, "audio/x-pn-wav")) {
@@ -499,6 +498,12 @@ static iContentSpec contentSpec_Player_(const iPlayer *d) {
499498
/* TODO: Could try decoders to see if one works? */
500499
content.type = none_DecoderType;
501500
}
501+
if (content.type != none_DecoderType) {
502+
buf = iClob(new_Buffer());
503+
/* This holds a reference to the data block. The decoder runs in a background
504+
thread so it needs its own copy of the data. */
505+
open_Buffer(buf, &d->data->data);
506+
}
502507
if (content.type == wav_DecoderType && dataSize >= 44) {
503508
/* Read the RIFF/WAVE header. */
504509
iStream *is = stream_Buffer(buf);
@@ -713,6 +718,8 @@ void updateSourceData_Player(iPlayer *d, const iString *mimeType, const iBlock *
713718
break;
714719
}
715720
/* The old parts cannot have changed. */
721+
/* NOTE: The decoder will hold a reference to the data block, which means
722+
appending here will cause a copy-on-write detach to occur. */
716723
appendData_Block(&input->data, constBegin_Block(data) + oldSize, newSize - oldSize);
717724
break;
718725
}
@@ -769,7 +776,7 @@ iBool start_Player(iPlayer *d) {
769776
return iTrue;
770777
}
771778
#endif
772-
iContentSpec content = contentSpec_Player_(d);
779+
iContentSpec content = detectContentSpec_Player_(d);
773780
if (!content.output.freq) {
774781
return iFalse;
775782
}

src/gopher.c

+11-4
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ void open_Gopher(iGopher *d, const iString *url) {
235235
return;
236236
}
237237
/* MIME type determined by the item type. */
238+
const iString *reqPath =
239+
collect_String(urlDecodeExclude_String(collectNewRange_String(parts.path), "\t"));
238240
switch (d->type) {
239241
case '0':
240242
setCStr_String(d->meta, "text/plain");
@@ -261,17 +263,22 @@ void open_Gopher(iGopher *d, const iString *url) {
261263
case 'I':
262264
setCStr_String(d->meta, "image/generic");
263265
break;
264-
case 's':
265-
setCStr_String(d->meta, "audio/wave");
266+
case 's': {
267+
const char *detected = mediaTypeFromFileExtension_String(reqPath);
268+
if (startsWith_CStr(detected, "audio/")) {
269+
setCStr_String(d->meta, detected); /* could be .mp3, for example */
270+
}
271+
else {
272+
setCStr_String(d->meta, "audio/wave");
273+
}
266274
break;
275+
}
267276
default:
268277
setCStr_String(d->meta, "application/octet-stream");
269278
break;
270279
}
271280
d->isPre = iFalse;
272281
open_Socket(d->socket);
273-
const iString *reqPath =
274-
collect_String(urlDecodeExclude_String(collectNewRange_String(parts.path), "\t"));
275282
writeData_Socket(d->socket, cstr_String(reqPath), size_String(reqPath));
276283
if (!isEmpty_Range(&parts.query)) {
277284
iAssert(*parts.query.start == '?');

src/media.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -469,8 +469,9 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo
469469
}
470470
pushBack_PtrArray(&d->items[audio_MediaType], audio);
471471
/* Start playing right away. */
472-
start_Player(audio->player);
473-
postCommandf_App("media.player.started player:%p", audio->player);
472+
if (start_Player(audio->player)) {
473+
postCommandf_App("media.player.started player:%p", audio->player);
474+
}
474475
isNew = iTrue;
475476
#endif /* LAGRANGE_ENABLE_AUDIO */
476477
}

src/ui/documentwidget.c

+23-2
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,7 @@ static void releaseViewDocument_DocumentWidget_(iDocumentWidget *d) {
904904
if (d->view == d->swipeView) {
905905
/* The view is being switched away for swiping, so allocate a new one for the
906906
actual document. */
907+
d->swipeBanner = d->banner;
907908
d->banner = new_Banner();
908909
setOwner_Banner(d->banner, d);
909910
setWidth_Banner(d->banner, documentWidth_DocumentView(d->view));
@@ -1333,9 +1334,18 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d,
13331334
endsWithCase_Rangecc(fileName, ".markdown")) {
13341335
param = range_CStr("text/markdown");
13351336
}
1336-
else if (endsWithCase_Rangecc(fileName, ".gmi") ||
1337-
endsWithCase_Rangecc(fileName, ".gemini")) {
1337+
else if ((endsWithCase_Rangecc(fileName, ".gmi") ||
1338+
endsWithCase_Rangecc(fileName, ".gemini")) &&
1339+
isEmpty_Range(&parts.query)) {
1340+
/* The server _probably_ sent us the wrong media type, so assume
1341+
they meant this is a Gemtext document based on the file extension.
1342+
However, if the query string is present, the server likely knows
1343+
what it's doing so only "fix" the type when a query component
1344+
was not present. */
13381345
param = range_CStr("text/gemini");
1346+
/* TODO: A better way to do this would be to preserve the original
1347+
media type and force a Gemtext view mode on the document.
1348+
(https://github.com/skyjake/lagrange/issues/359) */
13391349
}
13401350
}
13411351
}
@@ -1567,6 +1577,17 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d,
15671577
}
15681578
setFormat_GmDocument(d->view->doc, docFormat);
15691579
/* Convert the source to UTF-8 if needed. */
1580+
if (equalCase_Rangecc(charset, "utf-8")) {
1581+
/* Verify that it actually is valid UTF-8. */
1582+
if (!isUtf8_Rangecc(range_String(&str))) {
1583+
if (strstr(cstr_String(&str), "\x1b[")) {
1584+
charset = range_CStr("cp437"); /* An educated guess. */
1585+
}
1586+
else {
1587+
charset = range_CStr("latin1");
1588+
}
1589+
}
1590+
}
15701591
if (!equalCase_Rangecc(charset, "utf-8")) {
15711592
set_String(&str,
15721593
collect_String(decode_Block(&str.chars, cstr_Rangecc(charset))));

src/ui/linkinfo.c

+3
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ iBool update_LinkInfo(iLinkInfo *d, const iDocumentWidget *doc, iGmLinkId linkId
150150
/* Draw to a buffer, wrapped. */
151151
const int avail = iMax(minWidth_LinkInfo_, maxWidth) - 2 * hPad_LinkInfo_;
152152
iWrapText wt = { .text = range_String(&str), .maxWidth = avail, .mode = word_WrapTextMode };
153+
if (d->buf) {
154+
delete_TextBuf(d->buf);
155+
}
153156
d->buf = new_TextBuf(&wt, uiLabel_FontId, tmQuote_ColorId);
154157
deinit_String(&str);
155158
}

src/ui/root.c

+1
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,7 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) {
11581158
"open notinline:1 url:%s",
11591159
cstr_String(absoluteUrl_String(&iStringLiteral(""), text_InputWidget(url))));
11601160
}
1161+
delete_String(newUrl);
11611162
return iFalse;
11621163
}
11631164
}

src/ui/sidebarwidget.c

+5-4
Original file line numberDiff line numberDiff line change
@@ -2224,14 +2224,15 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
22242224
/* Update the menu before opening. */
22252225
/* TODO: This kind of updating is already done above, and in `updateContextMenu_`... */
22262226
if (d->mode == bookmarks_SidebarMode) {
2227-
/* Remote bookmarks have limitations. */
22282227
const iSidebarItem *hoverItem = hoverItem_ListWidget(d->list);
2229-
iAssert(hoverItem);
2228+
if (!hoverItem) {
2229+
return iTrue;
2230+
}
22302231
const iBookmark *bm = get_Bookmarks(bookmarks_App(), hoverItem->id);
22312232
if (isFolder_Bookmark(bm)) {
22322233
contextMenu = d->folderMenu;
22332234
}
2234-
else if (!isVisible_Widget(d->menu)) {
2235+
else if (!isVisible_Widget(d->menu)) {
22352236
const iBool isRemote = (bm->flags & remote_BookmarkFlag) != 0;
22362237
static const char *localOnlyCmds[] = { "bookmark.edit",
22372238
"bookmark.delete",
@@ -2240,7 +2241,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
22402241
"bookmark.tag tag:remotesource" };
22412242
iForIndices(i, localOnlyCmds) {
22422243
setFlags_Widget(as_Widget(findMenuItem_Widget(contextMenu, localOnlyCmds[i])),
2243-
disabled_WidgetFlag,
2244+
disabled_WidgetFlag, /* Remote bookmarks have limitations. */
22442245
isRemote);
22452246
}
22462247
}

src/ui/text.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ int ansiFlags_Text(void) {
8484
}
8585

8686
iRegExp *makeAnsiEscapePattern_Text(iBool includeEscChar) {
87-
const char *pattern = "\x1b[[()][?]?([0-9;AB]*?)([ABCDEFGHJKSTfhilmn])";
87+
const char *pattern = "\x1b[[\\(\\)][?]?([0-9;AB]*?)([ABCDEFGHJKSTfhilmn])";
8888
if (!includeEscChar) {
8989
pattern++;
9090
}
@@ -251,7 +251,7 @@ void drawOutline_Text(int fontId, iInt2 pos, int outlineColor, int fillColor, iR
251251
}
252252
#else
253253
drawRange_Text(fontId, pos, fillColor | fillBackground_ColorId, text);
254-
#endif
254+
#endif
255255
}
256256

257257
iTextMetrics measureWrapRange_Text(int fontId, int maxWidth, iRangecc text) {

src/ui/window.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -1815,7 +1815,9 @@ void resize_MainWindow(iMainWindow *d, int w, int h) {
18151815
}
18161816

18171817
void setTitle_Window(iWindow *d, const iString *title) {
1818-
SDL_SetWindowTitle(d->win, cstr_String(title));
1818+
iString *clean = collect_String(copy_String(title));
1819+
replaceRegExp_String(clean, iClob(makeAnsiEscapePattern_Text(iTrue)), "", NULL, NULL);
1820+
SDL_SetWindowTitle(d->win, cstr_String(clean));
18191821
iLabelWidget *bar = findChild_Widget(get_Root()->widget, "winbar.title");
18201822
if (bar) {
18211823
updateText_LabelWidget(bar, title);

0 commit comments

Comments
 (0)