summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-08-06 19:03:17 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-08-06 19:03:17 +0300
commit9d7469ded746cbfa1e86c1ecd67e4a36f29f635b (patch)
treeebff33e64e8953ef46ef5de54559fce234c20303
parent7c7af3b7425f0496203d68d9bc42be0603048a9b (diff)
parent186573dae1d0eab4560f02fe3b999418ea0f4614 (diff)
Merge branch 'dev' into work/v1.7
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.md6
-rw-r--r--po/eo.po12
-rw-r--r--po/fi.po16
-rw-r--r--po/ie.po22
-rw-r--r--po/sr.po58
-rw-r--r--po/tok.po8
-rw-r--r--res/about/version.gmi12
-rw-r--r--res/arg-help.txt1
-rw-r--r--res/fi.skyjake.Lagrange.appdata.xml36
-rw-r--r--res/lang/fi.binbin24879 -> 24893 bytes
-rw-r--r--res/lang/ie.binbin24133 -> 24247 bytes
-rw-r--r--res/lang/sr.binbin35978 -> 36801 bytes
-rw-r--r--res/lang/tok.binbin22702 -> 22683 bytes
-rw-r--r--src/app.c10
-rw-r--r--src/ipc.c2
-rw-r--r--src/ui/color.c9
-rw-r--r--src/ui/documentwidget.c2
-rw-r--r--src/ui/inputwidget.c140
-rw-r--r--src/ui/inputwidget.h3
-rw-r--r--src/ui/root.c9
-rw-r--r--src/ui/uploadwidget.c2
22 files changed, 286 insertions, 64 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 89bdcdb4..7b43b6de 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@
18cmake_minimum_required (VERSION 3.9) 18cmake_minimum_required (VERSION 3.9)
19 19
20project (Lagrange 20project (Lagrange
21 VERSION 1.6.2 21 VERSION 1.6.3
22 DESCRIPTION "A Beautiful Gemini Client" 22 DESCRIPTION "A Beautiful Gemini Client"
23 LANGUAGES C 23 LANGUAGES C
24) 24)
diff --git a/README.md b/README.md
index 3aa3d4e8..3d9df1db 100644
--- a/README.md
+++ b/README.md
@@ -49,16 +49,16 @@ The required tools are a C11 compiler (e.g., Clang or GCC), CMake and `pkg-confi
49 49
50### Unicode text rendering 50### Unicode text rendering
51 51
52Lagrange relies on the [HarfBuzz](https://harfbuzz.github.io) and [GNU FriBidi](https://github.com/fribidi/fribidi/) libraries for handling complex scripts and bidirectional text. This repository includes these two libraries as submodules. By default, HarfBuzz and GNU FriBidi will be compiled as part of the app, without any additional dependencies. This allows the app to be built on systems where these libraries are not readily available. 52Lagrange relies on the [HarfBuzz](https://harfbuzz.github.io) and [GNU FriBidi](https://github.com/fribidi/fribidi/) libraries for handling complex scripts and bidirectional text. This repository includes these two libraries as submodules. By default, if HarfBuzz and GNU FriBidi are not available on the system, they will be compiled as part of the app without any additional dependencies.
53 53
54Note that compiling these libraries has the following requirements: 54Note that compiling these libraries has the following requirements:
55 55
56* HarfBuzz requires a C++ compiler. 56* HarfBuzz requires a C++ compiler.
57* GNU FriBidi cannot be compiled with CMake; you need to have [Meson](https://mesonbuild.com) and [Ninja](https://ninja-build.org). 57* GNU FriBidi cannot be compiled with CMake; you need to have [Meson](https://mesonbuild.com) and [Ninja](https://ninja-build.org).
58 58
59If these requirements cannot be met, or you would prefer the use the system-provided HarfBuzz and GNU FriBidi, the build options can be changed. See the table below for `ENABLE_HARFBUZZ_MINIMAL` and `ENABLE_FRIBIDI_BUILD` (set both to **NO**). Note that a system-provided HarfBuzz likely has dependencies to other libraries, such as FreeType and GLib. 59If these requirements cannot be met, or you would prefer the use the system-provided HarfBuzz and GNU FriBidi, please refer to the list of build options below: `ENABLE_HARFBUZZ_MINIMAL` and `ENABLE_FRIBIDI_BUILD` should both be set to **NO**. Note that a system-provided HarfBuzz likely has dependencies to other libraries, such as FreeType and GLib.
60 60
61You also may disable HarfBuzz and/or GNU FriBidi entirely. The old text renderer that supports only non-complex left-to-right scripts is then used. 61You also may disable HarfBuzz and/or GNU FriBidi entirely. The old text renderer that only supports non-complex left-to-right scripts is then used.
62 62
63### Installing to a custom directory 63### Installing to a custom directory
64 64
diff --git a/po/eo.po b/po/eo.po
index 2dd2cb79..e6b3705e 100644
--- a/po/eo.po
+++ b/po/eo.po
@@ -1,7 +1,7 @@
1msgid "" 1msgid ""
2msgstr "" 2msgstr ""
3"Report-Msgid-Bugs-To: jaakko.keranen@iki.fi\n" 3"Report-Msgid-Bugs-To: jaakko.keranen@iki.fi\n"
4"PO-Revision-Date: 2021-05-15 06:18+0000\n" 4"PO-Revision-Date: 2021-07-31 12:07+0000\n"
5"Last-Translator: Nikolay Korotkiy <sikmir@gmail.com>\n" 5"Last-Translator: Nikolay Korotkiy <sikmir@gmail.com>\n"
6"Language-Team: Esperanto <http://weblate.skyjake.fi/projects/lagrange/ui/eo/>" 6"Language-Team: Esperanto <http://weblate.skyjake.fi/projects/lagrange/ui/eo/>"
7"\n" 7"\n"
@@ -169,7 +169,7 @@ msgid "panel.back"
169msgstr "Malantaŭen" 169msgstr "Malantaŭen"
170 170
171msgid "hint.findtext" 171msgid "hint.findtext"
172msgstr "Serĉi tekston sur la paĝo" 172msgstr "serĉi tekston sur la paĝo"
173 173
174msgid "sidebar.entry.bookmark" 174msgid "sidebar.entry.bookmark"
175msgstr "Aldoni legosignon…" 175msgstr "Aldoni legosignon…"
@@ -414,7 +414,7 @@ msgid "heading.prefs"
414msgstr "AGORDOJ" 414msgstr "AGORDOJ"
415 415
416msgid "heading.prefs.fonts" 416msgid "heading.prefs.fonts"
417msgstr "TIPAROJ" 417msgstr "Tiparoj"
418 418
419# tab button 419# tab button
420msgid "heading.prefs.network" 420msgid "heading.prefs.network"
@@ -698,3 +698,9 @@ msgstr "Versio"
698 698
699msgid "lang.pl" 699msgid "lang.pl"
700msgstr "Pola" 700msgstr "Pola"
701
702msgid "close"
703msgstr "Fermi"
704
705msgid "menu.openfile"
706msgstr "Malfermi dosieron…"
diff --git a/po/fi.po b/po/fi.po
index 5e166db3..afbc98b2 100644
--- a/po/fi.po
+++ b/po/fi.po
@@ -3,7 +3,7 @@ msgstr ""
3"Project-Id-Version: PACKAGE VERSION\n" 3"Project-Id-Version: PACKAGE VERSION\n"
4"Report-Msgid-Bugs-To: jaakko.keranen@iki.fi\n" 4"Report-Msgid-Bugs-To: jaakko.keranen@iki.fi\n"
5"POT-Creation-Date: 2021-03-23 09:09+0000\n" 5"POT-Creation-Date: 2021-03-23 09:09+0000\n"
6"PO-Revision-Date: 2021-07-24 05:45+0000\n" 6"PO-Revision-Date: 2021-08-03 05:24+0000\n"
7"Last-Translator: Weblate Admin <jaakko.keranen@iki.fi>\n" 7"Last-Translator: Weblate Admin <jaakko.keranen@iki.fi>\n"
8"Language-Team: Finnish <http://weblate.skyjake.fi/projects/lagrange/ui/fi/>\n" 8"Language-Team: Finnish <http://weblate.skyjake.fi/projects/lagrange/ui/fi/>\n"
9"Language: fi\n" 9"Language: fi\n"
@@ -1766,3 +1766,17 @@ msgstr ""
1766 1766
1767msgid "dlg.uploadport.set" 1767msgid "dlg.uploadport.set"
1768msgstr "Aseta portti" 1768msgstr "Aseta portti"
1769
1770msgid "media.untitled.image"
1771msgstr "Kuva"
1772
1773msgid "media.untitled.audio"
1774msgstr "Ääni"
1775
1776msgid "feeds.atom.translated"
1777msgstr ""
1778"Tämä Atom-XML-dokumentti on automaattisesti käännetty Gemini-syötteeksi, "
1779"jotta siihen voi tehdä tilauksen."
1780
1781msgid "bookmark.export.title.folder"
1782msgstr "Kirjanmerkit"
diff --git a/po/ie.po b/po/ie.po
index 634776e1..c7f0e829 100644
--- a/po/ie.po
+++ b/po/ie.po
@@ -1,7 +1,7 @@
1msgid "" 1msgid ""
2msgstr "" 2msgstr ""
3"Report-Msgid-Bugs-To: jaakko.keranen@iki.fi\n" 3"Report-Msgid-Bugs-To: jaakko.keranen@iki.fi\n"
4"PO-Revision-Date: 2021-07-25 18:06+0000\n" 4"PO-Revision-Date: 2021-08-03 05:24+0000\n"
5"Last-Translator: Olga Smirnova <mistresssilvara@hotmail.com>\n" 5"Last-Translator: Olga Smirnova <mistresssilvara@hotmail.com>\n"
6"Language-Team: Occidental <http://weblate.skyjake.fi/projects/lagrange/ui/ie/" 6"Language-Team: Occidental <http://weblate.skyjake.fi/projects/lagrange/ui/ie/"
7">\n" 7">\n"
@@ -1772,3 +1772,23 @@ msgstr "Code de carga:"
1772 1772
1773msgid "hint.upload.token" 1773msgid "hint.upload.token"
1774msgstr "vi instructiones del servitor" 1774msgstr "vi instructiones del servitor"
1775
1776msgid "media.untitled.image"
1777msgstr "Image"
1778
1779msgid "media.untitled.audio"
1780msgstr "Audio"
1781
1782msgid "bookmark.export.title.folder"
1783msgstr "Marca-págines"
1784
1785msgid "bookmark.export.title.time"
1786msgstr "Creat marca-págines"
1787
1788msgid "bookmark.export.count"
1789msgid_plural "bookmark.export.count.n"
1790msgstr[0] "Hay %d marca-págine."
1791msgstr[1] "Hay %d marca-págines."
1792
1793msgid "bookmark.export.format.linklines"
1794msgstr "Chascun ligament representa un marca-págine."
diff --git a/po/sr.po b/po/sr.po
index 40be3acd..f409ce13 100644
--- a/po/sr.po
+++ b/po/sr.po
@@ -1,7 +1,7 @@
1msgid "" 1msgid ""
2msgstr "" 2msgstr ""
3"Report-Msgid-Bugs-To: jaakko.keranen@iki.fi\n" 3"Report-Msgid-Bugs-To: jaakko.keranen@iki.fi\n"
4"PO-Revision-Date: 2021-07-25 18:06+0000\n" 4"PO-Revision-Date: 2021-08-03 05:24+0000\n"
5"Last-Translator: Страхиња Радић <contact@strahinja.org>\n" 5"Last-Translator: Страхиња Радић <contact@strahinja.org>\n"
6"Language-Team: Serbian <http://weblate.skyjake.fi/projects/lagrange/ui/sr/>\n" 6"Language-Team: Serbian <http://weblate.skyjake.fi/projects/lagrange/ui/sr/>\n"
7"Language: sr\n" 7"Language: sr\n"
@@ -1806,3 +1806,59 @@ msgstr ""
1806 1806
1807msgid "keys.upload" 1807msgid "keys.upload"
1808msgstr "Слање странице преко Титана" 1808msgstr "Слање странице преко Титана"
1809
1810msgid "media.untitled.image"
1811msgstr "Слика"
1812
1813msgid "feeds.atom.translated"
1814msgstr ""
1815"Овај Atom XML документ је аутоматски преведен у Џемини фид да би се на њега "
1816"омогућила претплата."
1817
1818msgid "bookmark.export.count"
1819msgid_plural "bookmark.export.count.n"
1820msgstr[0] "Имате %d обележивач."
1821msgstr[1] "Имате %d обележивача."
1822msgstr[2] "Имате %d обележивача."
1823
1824msgid "bookmark.export.taginfo"
1825msgstr ""
1826"У овој листи сваки наслов представља ознаку обележивача. Приказани су само "
1827"означени обележивачи. Обележивачи са више ознака су поновљени под сваком "
1828"ознаком."
1829
1830msgid "bookmark.export.format.otherlines"
1831msgstr ""
1832"Набрајања и цитати су резервисани за додатне информације о претходном "
1833"обележивачу. Текстуални редови и преформатирани текст се сматрају "
1834"коментарима и биће игнорисани."
1835
1836msgid "media.untitled.audio"
1837msgstr "Аудио"
1838
1839msgid "bookmark.export.title.folder"
1840msgstr "Обележивачи"
1841
1842msgid "bookmark.export.title.tag"
1843msgstr "Ознаке обележивача"
1844
1845msgid "bookmark.export.title.time"
1846msgstr "Креирани обележивачи"
1847
1848msgid "bookmark.export.saving"
1849msgstr ""
1850"Сачувајте ову страницу да бисте их извезли, или их ископирајте на клипборд."
1851
1852msgid "bookmark.export.format.sub"
1853msgstr ""
1854"Ова страница је форматирана према додатку спецификације „Subscribing to "
1855"Gemini pages“."
1856
1857msgid "bookmark.export.format.linklines"
1858msgstr "Свака веза представља обележивач."
1859
1860msgid "bookmark.export.format.folders"
1861msgstr "Структура фасцикли је дефинисана преко наслова нивоа 2 и 3."
1862
1863msgid "bookmark.export.format.tags"
1864msgstr "Ознаке су задате насловима нивоа 2."
diff --git a/po/tok.po b/po/tok.po
index 8a71b34a..f678090e 100644
--- a/po/tok.po
+++ b/po/tok.po
@@ -1,7 +1,7 @@
1msgid "" 1msgid ""
2msgstr "" 2msgstr ""
3"Report-Msgid-Bugs-To: jaakko.keranen@iki.fi\n" 3"Report-Msgid-Bugs-To: jaakko.keranen@iki.fi\n"
4"PO-Revision-Date: 2021-07-28 13:07+0000\n" 4"PO-Revision-Date: 2021-07-31 12:07+0000\n"
5"Last-Translator: jan Anja <cyber@sysrq.in>\n" 5"Last-Translator: jan Anja <cyber@sysrq.in>\n"
6"Language-Team: Toki Pona <http://weblate.skyjake.fi/projects/lagrange/ui/tok/" 6"Language-Team: Toki Pona <http://weblate.skyjake.fi/projects/lagrange/ui/tok/"
7">\n" 7">\n"
@@ -767,7 +767,7 @@ msgid "heading.prefs.colors"
767msgstr "kule" 767msgstr "kule"
768 768
769msgid "heading.prefs.fonts" 769msgid "heading.prefs.fonts"
770msgstr "Nasin lukin tawa sitelen" 770msgstr "sitelen"
771 771
772# tab button 772# tab button
773msgid "heading.prefs.interface" 773msgid "heading.prefs.interface"
@@ -819,7 +819,7 @@ msgstr "SULI MUTE"
819 819
820# tab button 820# tab button
821msgid "heading.prefs.style" 821msgid "heading.prefs.style"
822msgstr "sitelen" 822msgstr "lipu"
823 823
824msgid "prefs.theme" 824msgid "prefs.theme"
825msgstr "nasin lukin:" 825msgstr "nasin lukin:"
@@ -1717,7 +1717,7 @@ msgid "error.certexpired"
1717msgstr "sitelen len li tawa weka" 1717msgstr "sitelen len li tawa weka"
1718 1718
1719msgid "error.certexpired.msg" 1719msgid "error.certexpired.msg"
1720msgstr "tenpo pini la sitelen len li tawa weka. tan ni la kon li weka." 1720msgstr "tenpo pini la sitelen len li tawa weka. tan ni la toki li pini."
1721 1721
1722msgid "error.certverify" 1722msgid "error.certverify"
1723msgstr "ilo pana li ike lukin" 1723msgstr "ilo pana li ike lukin"
diff --git a/res/about/version.gmi b/res/about/version.gmi
index b56a9311..72b46e23 100644
--- a/res/about/version.gmi
+++ b/res/about/version.gmi
@@ -6,13 +6,23 @@
6``` 6```
7# Release notes 7# Release notes
8 8
9## 1.6.3
10* Select all text in an input field using Shift+Ctrl+A (macOS: ⌘A).
11* Input fields do not lose focus when the window becomes inactive, making it easier to resume input afterwards.
12* Fixed the line break key modifier inadvertently affecting URL input fields, where line breaks are not allowed.
13* Fixed the line break key modifier affecting the upload dialog's text field.
14
9## 1.6.2 15## 1.6.2
16* Added `--tab-url` to print currently active tab's URL.
10* Upload dialog expands to full window height when the entered text is long. 17* Upload dialog expands to full window height when the entered text is long.
11* Home/End keys in an input field move to start/end of the wrapped line segment. 18* Home/End keys in an input field move to start/end of the wrapped line segment.
19* Scroll with mouse wheel in input fields.
20* Slower cursor blink rate in input fields.
21* Adjusted dark mode colors for focused input fields.
12* Fixed incorrect behavior in input fields when typing or deleting text while holding down the Shift key. 22* Fixed incorrect behavior in input fields when typing or deleting text while holding down the Shift key.
13* Fixed crash in Upload dialog if server responds with a redirect. 23* Fixed crash in Upload dialog if server responds with a redirect.
14* Fixed buffered graphics (UI, fonts) getting lost under rare circumstances. 24* Fixed buffered graphics (UI, fonts) getting lost under rare circumstances.
15* Fixed drawing of wrapped text when the app is compiled with HarfBuzz. 25* Fixed drawing of wrapped text when the app is compiled without HarfBuzz.
16* macOS: Fixed UI not updating when system dark mode is toggled while the window is hidden. 26* macOS: Fixed UI not updating when system dark mode is toggled while the window is hidden.
17 27
18## 1.6.1 28## 1.6.1
diff --git a/res/arg-help.txt b/res/arg-help.txt
index e87881d3..9f6548f2 100644
--- a/res/arg-help.txt
+++ b/res/arg-help.txt
@@ -21,3 +21,4 @@ Options that control a running instance of Lagrange:
21 running, nothing is printed. 21 running, nothing is printed.
22 --new-tab [URL] Open a new tab. If the URL is omitted, the user's 22 --new-tab [URL] Open a new tab. If the URL is omitted, the user's
23 homepage is opened. 23 homepage is opened.
24 --tab-url Print the URL of the active tab.
diff --git a/res/fi.skyjake.Lagrange.appdata.xml b/res/fi.skyjake.Lagrange.appdata.xml
index 0110e8c5..1db2717c 100644
--- a/res/fi.skyjake.Lagrange.appdata.xml
+++ b/res/fi.skyjake.Lagrange.appdata.xml
@@ -45,6 +45,39 @@
45 <update_contact>jaakko.keranen@iki.fi</update_contact> 45 <update_contact>jaakko.keranen@iki.fi</update_contact>
46 46
47 <releases> 47 <releases>
48 <release version="1.6.2" date="2021-08-03">
49 <description>
50 <p>Version 1.6 adds support for bidirectional text and complex scripts,
51 right-to-left paragraph layout, uploads using the Titan protocol,
52 and has an improved mechanism for tracking trust in server
53 certificates. Page contents can be fully cached in memory for more
54 efficient backward navigation. There are also UI improvements like
55 a reorganized Preferences and a setting for smooth scrolling
56 speed.</p>
57 <p>Changes and fixes in v1.6.2:</p>
58 <ul>
59 <li>Added --tab-url to print currently active tab's URL.</li>
60 <li>Upload dialog expands to full window height when the entered
61 text is long.</li>
62 <li>Home/End keys in an input field move to start/end of the
63 wrapped line segment.</li>
64 <li>Scroll with mouse wheel in input fields.</li>
65 <li>Slower cursor blink rate in input fields.</li>
66 <li>Adjusted dark mode colors for focused input fields.</li>
67 <li>Fixed incorrect behavior in input fields when typing or
68 deleting text while holding down the Shift key.</li>
69 <li>Fixed crash in Upload dialog if server responds with a
70 redirect.</li>
71 <li>Fixed buffered graphics (UI, fonts) getting lost under rare
72 circumstances.</li>
73 <li>macOS: Fixed UI not updating when system dark mode is toggled
74 while the window is hidden.</li>
75 </ul>
76 <p>The full release notes can be viewed inside the app by opening
77 the "about:version" page.</p>
78 </description>
79 <url>https://github.com/skyjake/lagrange/releases/tag/v1.6.2</url>
80 </release>
48 <release version="1.6.1" date="2021-07-30"> 81 <release version="1.6.1" date="2021-07-30">
49 <description> 82 <description>
50 <p>Version 1.6 adds support for bidirectional text and complex scripts, 83 <p>Version 1.6 adds support for bidirectional text and complex scripts,
@@ -59,7 +92,8 @@
59 <li>Potential crash when inserting a line break.</li> 92 <li>Potential crash when inserting a line break.</li>
60 <li>Cursor positioning in fixed-length input fields.</li> 93 <li>Cursor positioning in fixed-length input fields.</li>
61 <li>Copying text in input fields (the wrong region was copied).</li> 94 <li>Copying text in input fields (the wrong region was copied).</li>
62 <li>URL input field contents not being selected after opening a new tab.</li> 95 <li>URL input field contents not being selected after opening
96 a new tab.</li>
63 <li>Upload dialog not showing when reloading a Titan URL.</li> 97 <li>Upload dialog not showing when reloading a Titan URL.</li>
64 </ul> 98 </ul>
65 <p>The full release notes can be viewed inside the app by opening 99 <p>The full release notes can be viewed inside the app by opening
diff --git a/res/lang/fi.bin b/res/lang/fi.bin
index 7b7b6c28..2f1bb18f 100644
--- a/res/lang/fi.bin
+++ b/res/lang/fi.bin
Binary files differ
diff --git a/res/lang/ie.bin b/res/lang/ie.bin
index 97c02a90..a8bce39d 100644
--- a/res/lang/ie.bin
+++ b/res/lang/ie.bin
Binary files differ
diff --git a/res/lang/sr.bin b/res/lang/sr.bin
index 4a299323..df8e532b 100644
--- a/res/lang/sr.bin
+++ b/res/lang/sr.bin
Binary files differ
diff --git a/res/lang/tok.bin b/res/lang/tok.bin
index 4cd4212d..f2b59891 100644
--- a/res/lang/tok.bin
+++ b/res/lang/tok.bin
Binary files differ
diff --git a/src/app.c b/src/app.c
index abfd584a..8318eee4 100644
--- a/src/app.c
+++ b/src/app.c
@@ -581,6 +581,9 @@ static void communicateWithRunningInstance_App_(iApp *d, iProcessId instance,
581 else if (equal_CommandLineConstIterator(&i, "close-tab")) { 581 else if (equal_CommandLineConstIterator(&i, "close-tab")) {
582 appendCStr_String(cmds, "tabs.close\n"); 582 appendCStr_String(cmds, "tabs.close\n");
583 } 583 }
584 else if (equal_CommandLineConstIterator(&i, "tab-url")) {
585 appendFormat_String(cmds, "ipc.active.url pid:%d\n", pid);
586 }
584 else if (equal_CommandLineConstIterator(&i, listTabUrls_CommandLineOption)) { 587 else if (equal_CommandLineConstIterator(&i, listTabUrls_CommandLineOption)) {
585 appendFormat_String(cmds, "ipc.list.urls pid:%d\n", pid); 588 appendFormat_String(cmds, "ipc.list.urls pid:%d\n", pid);
586 } 589 }
@@ -658,6 +661,7 @@ static void init_App_(iApp *d, int argc, char **argv) {
658 defineValues_CommandLine(&d->args, listTabUrls_CommandLineOption, 0); 661 defineValues_CommandLine(&d->args, listTabUrls_CommandLineOption, 0);
659 defineValues_CommandLine(&d->args, openUrlOrSearch_CommandLineOption, 1); 662 defineValues_CommandLine(&d->args, openUrlOrSearch_CommandLineOption, 1);
660 defineValuesN_CommandLine(&d->args, "new-tab", 0, 1); 663 defineValuesN_CommandLine(&d->args, "new-tab", 0, 1);
664 defineValues_CommandLine(&d->args, "tab-url", 0);
661 defineValues_CommandLine(&d->args, "sw", 0); 665 defineValues_CommandLine(&d->args, "sw", 0);
662 defineValues_CommandLine(&d->args, "version;V", 0); 666 defineValues_CommandLine(&d->args, "version;V", 0);
663 } 667 }
@@ -2772,6 +2776,12 @@ iBool handleCommand_App(const char *cmd) {
2772 } 2776 }
2773 return iTrue; 2777 return iTrue;
2774 } 2778 }
2779 else if (equal_Command(cmd, "ipc.active.url")) {
2780 write_Ipc(argLabel_Command(cmd, "pid"),
2781 collectNewFormat_String("%s\n", cstr_String(url_DocumentWidget(document_App()))),
2782 response_IpcWrite);
2783 return iTrue;
2784 }
2775 else if (equal_Command(cmd, "ipc.signal")) { 2785 else if (equal_Command(cmd, "ipc.signal")) {
2776 if (argLabel_Command(cmd, "raise")) { 2786 if (argLabel_Command(cmd, "raise")) {
2777 if (d->window && d->window->win) { 2787 if (d->window && d->window->win) {
diff --git a/src/ipc.c b/src/ipc.c
index ce98b6cf..e4c95c50 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -172,6 +172,7 @@ static void handleSignal_IpcResponse_(int sig) {
172} 172}
173 173
174iBool write_Ipc(iProcessId pid, const iString *input, enum iIpcWrite type) { 174iBool write_Ipc(iProcessId pid, const iString *input, enum iIpcWrite type) {
175 if (!pid) return iFalse;
175 iBool ok = iFalse; 176 iBool ok = iFalse;
176 iFile *f = newCStr_File(inputFilePath_(&ipc_, pid)); 177 iFile *f = newCStr_File(inputFilePath_(&ipc_, pid));
177 if (open_File(f, text_FileMode | append_FileMode)) { 178 if (open_File(f, text_FileMode | append_FileMode)) {
@@ -281,6 +282,7 @@ void listen_Ipc(void) {
281} 282}
282 283
283iBool write_Ipc(iProcessId pid, const iString *input, enum iIpcWrite type) { 284iBool write_Ipc(iProcessId pid, const iString *input, enum iIpcWrite type) {
285 if (!pid) return iFalse;
284 iUnused(type); 286 iUnused(type);
285 HANDLE slot = CreateFile(slotName_(pid), 287 HANDLE slot = CreateFile(slotName_(pid),
286 GENERIC_WRITE, 288 GENERIC_WRITE,
diff --git a/src/ui/color.c b/src/ui/color.c
index 05ec1f6f..656de6f0 100644
--- a/src/ui/color.c
+++ b/src/ui/color.c
@@ -85,6 +85,7 @@ void setThemePalette_Color(enum iColorTheme theme) {
85 const int accentLo = (prefs->accent == cyan_ColorAccent ? teal_ColorId : brown_ColorId); 85 const int accentLo = (prefs->accent == cyan_ColorAccent ? teal_ColorId : brown_ColorId);
86 const int altAccentHi = (prefs->accent == cyan_ColorAccent ? orange_ColorId : cyan_ColorId); 86 const int altAccentHi = (prefs->accent == cyan_ColorAccent ? orange_ColorId : cyan_ColorId);
87 const int altAccentLo = (prefs->accent == cyan_ColorAccent ? brown_ColorId : teal_ColorId); 87 const int altAccentLo = (prefs->accent == cyan_ColorAccent ? brown_ColorId : teal_ColorId);
88 const iColor altAccentMid = mix_Color(get_Color(altAccentHi), get_Color(altAccentLo), 0.5f);
88 switch (theme) { 89 switch (theme) {
89 case pureBlack_ColorTheme: { 90 case pureBlack_ColorTheme: {
90 copy_(uiBackground_ColorId, black_ColorId); 91 copy_(uiBackground_ColorId, black_ColorId);
@@ -123,7 +124,7 @@ void setThemePalette_Color(enum iColorTheme theme) {
123 copy_(uiInputTextFocused_ColorId, white_ColorId); 124 copy_(uiInputTextFocused_ColorId, white_ColorId);
124 copy_(uiInputFrame_ColorId, gray25_ColorId); 125 copy_(uiInputFrame_ColorId, gray25_ColorId);
125 copy_(uiInputFrameHover_ColorId, accentHi); 126 copy_(uiInputFrameHover_ColorId, accentHi);
126 copy_(uiInputFrameFocused_ColorId, altAccentHi); 127 set_Color(uiInputFrameFocused_ColorId, altAccentMid);
127 copy_(uiInputCursor_ColorId, altAccentHi); 128 copy_(uiInputCursor_ColorId, altAccentHi);
128 copy_(uiInputCursorText_ColorId, black_ColorId); 129 copy_(uiInputCursorText_ColorId, black_ColorId);
129 copy_(uiHeading_ColorId, accentHi); 130 copy_(uiHeading_ColorId, accentHi);
@@ -171,10 +172,12 @@ void setThemePalette_Color(enum iColorTheme theme) {
171 mix_Color(get_Color(black_ColorId), get_Color(gray25_ColorId), 0.7f)); 172 mix_Color(get_Color(black_ColorId), get_Color(gray25_ColorId), 0.7f));
172 copy_(uiInputBackgroundFocused_ColorId, black_ColorId); 173 copy_(uiInputBackgroundFocused_ColorId, black_ColorId);
173 copy_(uiInputText_ColorId, gray75_ColorId); 174 copy_(uiInputText_ColorId, gray75_ColorId);
174 copy_(uiInputTextFocused_ColorId, white_ColorId); 175 //copy_(uiInputTextFocused_ColorId, white_ColorId);
176 set_Color(uiInputTextFocused_ColorId, mix_Color(get_Color(white_ColorId),
177 get_Color(altAccentHi), 0.15f));
175 copy_(uiInputFrame_ColorId, uiInputBackground_ColorId); 178 copy_(uiInputFrame_ColorId, uiInputBackground_ColorId);
176 copy_(uiInputFrameHover_ColorId, accentHi); 179 copy_(uiInputFrameHover_ColorId, accentHi);
177 copy_(uiInputFrameFocused_ColorId, altAccentHi); 180 set_Color(uiInputFrameFocused_ColorId, altAccentMid);
178 copy_(uiInputCursor_ColorId, altAccentHi); 181 copy_(uiInputCursor_ColorId, altAccentHi);
179 copy_(uiInputCursorText_ColorId, black_ColorId); 182 copy_(uiInputCursorText_ColorId, black_ColorId);
180 copy_(uiHeading_ColorId, accentHi); 183 copy_(uiHeading_ColorId, accentHi);
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 8de1162f..674b0352 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -493,7 +493,7 @@ static int documentWidth_DocumentWidget_(const iDocumentWidget *d) {
493 const iPrefs * prefs = prefs_App(); 493 const iPrefs * prefs = prefs_App();
494 const int minWidth = 50 * gap_UI; /* lines must fit a word at least */ 494 const int minWidth = 50 * gap_UI; /* lines must fit a word at least */
495 const float adjust = iClamp((float) bounds.size.x / gap_UI / 11 - 12, 495 const float adjust = iClamp((float) bounds.size.x / gap_UI / 11 - 12,
496 -2.0f, 10.0f); /* adapt to width */ 496 -1.0f, 10.0f); /* adapt to width */
497 //printf("%f\n", adjust); fflush(stdout); 497 //printf("%f\n", adjust); fflush(stdout);
498 return iMini(iMax(minWidth, bounds.size.x - gap_UI * (d->pageMargin + adjust) * 2), 498 return iMini(iMax(minWidth, bounds.size.x - gap_UI * (d->pageMargin + adjust) * 2),
499 fontSize_UI * prefs->lineWidth * prefs->zoomPercent / 100); 499 fontSize_UI * prefs->lineWidth * prefs->zoomPercent / 100);
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index 8ed52022..f1f368b6 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -39,7 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
39# include "macos.h" 39# include "macos.h"
40#endif 40#endif
41 41
42static const int refreshInterval_InputWidget_ = 256; 42static const int refreshInterval_InputWidget_ = 512;
43static const size_t maxUndo_InputWidget_ = 64; 43static const size_t maxUndo_InputWidget_ = 64;
44static const int unlimitedWidth_InputWidget_ = 1000000; /* TODO: WrapText disables some functionality if maxWidth==0 */ 44static const int unlimitedWidth_InputWidget_ = 1000000; /* TODO: WrapText disables some functionality if maxWidth==0 */
45 45
@@ -188,9 +188,9 @@ enum iInputWidgetFlag {
188 markWords_InputWidgetFlag = iBit(8), 188 markWords_InputWidgetFlag = iBit(8),
189 needUpdateBuffer_InputWidgetFlag = iBit(9), 189 needUpdateBuffer_InputWidgetFlag = iBit(9),
190 enterKeyEnabled_InputWidgetFlag = iBit(10), 190 enterKeyEnabled_InputWidgetFlag = iBit(10),
191 enterKeyInsertsLineFeed_InputWidgetFlag 191 lineBreaksEnabled_InputWidgetFlag= iBit(11),
192 = iBit(11),
193 needBackup_InputWidgetFlag = iBit(12), 192 needBackup_InputWidgetFlag = iBit(12),
193 useReturnKeyBehavior_InputWidgetFlag = iBit(13),
194}; 194};
195 195
196/*----------------------------------------------------------------------------------------------*/ 196/*----------------------------------------------------------------------------------------------*/
@@ -216,6 +216,7 @@ struct Impl_InputWidget {
216 iArray undoStack; 216 iArray undoStack;
217 int font; 217 int font;
218 iClick click; 218 iClick click;
219 int wheelAccum;
219 int cursorVis; 220 int cursorVis;
220 uint32_t timer; 221 uint32_t timer;
221 iTextBuf * buffered; /* pre-rendered static text */ 222 iTextBuf * buffered; /* pre-rendered static text */
@@ -566,6 +567,28 @@ static void updateAllLinesAndResizeHeight_InputWidget_(iInputWidget *d) {
566 } 567 }
567} 568}
568 569
570static uint32_t cursorTimer_(uint32_t interval, void *w) {
571 iInputWidget *d = w;
572 if (d->cursorVis > 1) {
573 d->cursorVis--;
574 }
575 else {
576 d->cursorVis ^= 1;
577 }
578 refresh_Widget(w);
579 return interval;
580}
581
582static void startOrStopCursorTimer_InputWidget_(iInputWidget *d, iBool doStart) {
583 if (doStart && !d->timer) {
584 d->timer = SDL_AddTimer(refreshInterval_InputWidget_, cursorTimer_, d);
585 }
586 else if (!doStart && d->timer) {
587 SDL_RemoveTimer(d->timer);
588 d->timer = 0;
589 }
590}
591
569void init_InputWidget(iInputWidget *d, size_t maxLen) { 592void init_InputWidget(iInputWidget *d, size_t maxLen) {
570 iWidget *w = &d->widget; 593 iWidget *w = &d->widget;
571 init_Widget(w); 594 init_Widget(w);
@@ -587,10 +610,11 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) {
587 d->cursor = zero_I2(); 610 d->cursor = zero_I2();
588 d->prevCursor = zero_I2(); 611 d->prevCursor = zero_I2();
589 d->lastUpdateWidth = 0; 612 d->lastUpdateWidth = 0;
590 d->inFlags = eatEscape_InputWidgetFlag | enterKeyEnabled_InputWidgetFlag; 613 d->inFlags = eatEscape_InputWidgetFlag | enterKeyEnabled_InputWidgetFlag |
591 if (deviceType_App() != desktop_AppDeviceType) { 614 lineBreaksEnabled_InputWidgetFlag | useReturnKeyBehavior_InputWidgetFlag;
592 d->inFlags |= enterKeyInsertsLineFeed_InputWidgetFlag; 615 // if (deviceType_App() != desktop_AppDeviceType) {
593 } 616 // d->inFlags |= enterKeyInsertsLineFeed_InputWidgetFlag;
617 // }
594 iZap(d->mark); 618 iZap(d->mark);
595 setMaxLen_InputWidget(d, maxLen); 619 setMaxLen_InputWidget(d, maxLen);
596 d->visWrapLines.start = 0; 620 d->visWrapLines.start = 0;
@@ -600,6 +624,7 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) {
600 splitToLines_(&iStringLiteral(""), &d->lines); 624 splitToLines_(&iStringLiteral(""), &d->lines);
601 setFlags_Widget(w, fixedHeight_WidgetFlag, iTrue); /* resizes its own height */ 625 setFlags_Widget(w, fixedHeight_WidgetFlag, iTrue); /* resizes its own height */
602 init_Click(&d->click, d, SDL_BUTTON_LEFT); 626 init_Click(&d->click, d, SDL_BUTTON_LEFT);
627 d->wheelAccum = 0;
603 d->timer = 0; 628 d->timer = 0;
604 d->cursorVis = 0; 629 d->cursorVis = 0;
605 d->buffered = NULL; 630 d->buffered = NULL;
@@ -625,9 +650,7 @@ void deinit_InputWidget(iInputWidget *d) {
625 delete_TextBuf(d->buffered); 650 delete_TextBuf(d->buffered);
626 clearUndo_InputWidget_(d); 651 clearUndo_InputWidget_(d);
627 deinit_Array(&d->undoStack); 652 deinit_Array(&d->undoStack);
628 if (d->timer) { 653 startOrStopCursorTimer_InputWidget_(d, iFalse);
629 SDL_RemoveTimer(d->timer);
630 }
631 deinit_String(&d->srcHint); 654 deinit_String(&d->srcHint);
632 deinit_String(&d->hint); 655 deinit_String(&d->hint);
633 deinit_String(&d->oldText); 656 deinit_String(&d->oldText);
@@ -730,14 +753,18 @@ void setValidator_InputWidget(iInputWidget *d, iInputWidgetValidatorFunc validat
730 d->validatorContext = context; 753 d->validatorContext = context;
731} 754}
732 755
733void setEnterInsertsLF_InputWidget(iInputWidget *d, iBool enterInsertsLF) { 756void setLineBreaksEnabled_InputWidget(iInputWidget *d, iBool lineBreaksEnabled) {
734 iChangeFlags(d->inFlags, enterKeyInsertsLineFeed_InputWidgetFlag, enterInsertsLF); 757 iChangeFlags(d->inFlags, lineBreaksEnabled_InputWidgetFlag, lineBreaksEnabled);
735} 758}
736 759
737void setEnterKeyEnabled_InputWidget(iInputWidget *d, iBool enterKeyEnabled) { 760void setEnterKeyEnabled_InputWidget(iInputWidget *d, iBool enterKeyEnabled) {
738 iChangeFlags(d->inFlags, enterKeyEnabled_InputWidgetFlag, enterKeyEnabled); 761 iChangeFlags(d->inFlags, enterKeyEnabled_InputWidgetFlag, enterKeyEnabled);
739} 762}
740 763
764void setUseReturnKeyBehavior_InputWidget(iInputWidget *d, iBool useReturnKeyBehavior) {
765 iChangeFlags(d->inFlags, useReturnKeyBehavior_InputWidgetFlag, useReturnKeyBehavior);
766}
767
741void setHint_InputWidget(iInputWidget *d, const char *hintText) { 768void setHint_InputWidget(iInputWidget *d, const char *hintText) {
742 /* Keep original for retranslations. */ 769 /* Keep original for retranslations. */
743 setCStr_String(&d->srcHint, hintText); 770 setCStr_String(&d->srcHint, hintText);
@@ -864,18 +891,6 @@ void setTextCStr_InputWidget(iInputWidget *d, const char *cstr) {
864 delete_String(str); 891 delete_String(str);
865} 892}
866 893
867static uint32_t cursorTimer_(uint32_t interval, void *w) {
868 iInputWidget *d = w;
869 if (d->cursorVis > 1) {
870 d->cursorVis--;
871 }
872 else {
873 d->cursorVis ^= 1;
874 }
875 refresh_Widget(w);
876 return interval;
877}
878
879static size_t cursorToIndex_InputWidget_(const iInputWidget *d, iInt2 pos) { 894static size_t cursorToIndex_InputWidget_(const iInputWidget *d, iInt2 pos) {
880 if (pos.y < 0) { 895 if (pos.y < 0) {
881 return 0; 896 return 0;
@@ -928,7 +943,7 @@ void begin_InputWidget(iInputWidget *d) {
928 setFlags_Widget(w, selected_WidgetFlag, iTrue); 943 setFlags_Widget(w, selected_WidgetFlag, iTrue);
929 showCursor_InputWidget_(d); 944 showCursor_InputWidget_(d);
930 refresh_Widget(w); 945 refresh_Widget(w);
931 d->timer = SDL_AddTimer(refreshInterval_InputWidget_, cursorTimer_, d); 946 startOrStopCursorTimer_InputWidget_(d, iTrue);
932 d->inFlags &= ~enterPressed_InputWidgetFlag; 947 d->inFlags &= ~enterPressed_InputWidgetFlag;
933 if (d->inFlags & selectAllOnFocus_InputWidgetFlag) { 948 if (d->inFlags & selectAllOnFocus_InputWidgetFlag) {
934 d->mark = (iRanges){ 0, lastLine_InputWidget_(d)->range.end }; 949 d->mark = (iRanges){ 0, lastLine_InputWidget_(d)->range.end };
@@ -953,8 +968,7 @@ void end_InputWidget(iInputWidget *d, iBool accept) {
953 splitToLines_(&d->oldText, &d->lines); 968 splitToLines_(&d->oldText, &d->lines);
954 } 969 }
955 d->inFlags |= needUpdateBuffer_InputWidgetFlag; 970 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
956 SDL_RemoveTimer(d->timer); 971 startOrStopCursorTimer_InputWidget_(d, iFalse);
957 d->timer = 0;
958 SDL_StopTextInput(); 972 SDL_StopTextInput();
959 setFlags_Widget(w, selected_WidgetFlag | keepOnTop_WidgetFlag, iFalse); 973 setFlags_Widget(w, selected_WidgetFlag | keepOnTop_WidgetFlag, iFalse);
960 const char *id = cstr_String(id_Widget(as_Widget(d))); 974 const char *id = cstr_String(id_Widget(as_Widget(d)));
@@ -1381,6 +1395,20 @@ static iBool isArrowUpDownConsumed_InputWidget_(const iInputWidget *d) {
1381 return d->maxWrapLines > 1; 1395 return d->maxWrapLines > 1;
1382} 1396}
1383 1397
1398static iBool checkLineBreakMods_InputWidget_(const iInputWidget *d, int mods) {
1399 if (d->inFlags & useReturnKeyBehavior_InputWidgetFlag) {
1400 return mods == lineBreakKeyMod_ReturnKeyBehavior(prefs_App()->returnKey);
1401 }
1402 return mods == 0;
1403}
1404
1405static iBool checkAcceptMods_InputWidget_(const iInputWidget *d, int mods) {
1406 if (d->inFlags & useReturnKeyBehavior_InputWidgetFlag) {
1407 return mods == acceptKeyMod_ReturnKeyBehavior(prefs_App()->returnKey);
1408 }
1409 return mods == 0;
1410}
1411
1384static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { 1412static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1385 iWidget *w = as_Widget(d); 1413 iWidget *w = as_Widget(d);
1386 /* Resize according to width immediately. */ 1414 /* Resize according to width immediately. */
@@ -1399,6 +1427,13 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1399 begin_InputWidget(d); 1427 begin_InputWidget(d);
1400 return iFalse; 1428 return iFalse;
1401 } 1429 }
1430 else if (isEditing_InputWidget_(d) && (isCommand_UserEvent(ev, "window.focus.lost") ||
1431 isCommand_UserEvent(ev, "window.focus.gained"))) {
1432 startOrStopCursorTimer_InputWidget_(d, isCommand_UserEvent(ev, "window.focus.gained"));
1433 d->cursorVis = 1;
1434 refresh_Widget(d);
1435 return iFalse;
1436 }
1402 else if (isCommand_UserEvent(ev, "keyroot.changed")) { 1437 else if (isCommand_UserEvent(ev, "keyroot.changed")) {
1403 d->inFlags |= needUpdateBuffer_InputWidgetFlag; 1438 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
1404 } 1439 }
@@ -1467,6 +1502,31 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1467 ? SDL_SYSTEM_CURSOR_IBEAM 1502 ? SDL_SYSTEM_CURSOR_IBEAM
1468 : SDL_SYSTEM_CURSOR_ARROW); 1503 : SDL_SYSTEM_CURSOR_ARROW);
1469 } 1504 }
1505 if (ev->type == SDL_MOUSEWHEEL && contains_Widget(w, coord_MouseWheelEvent(&ev->wheel))) {
1506 const int lineHeight = lineHeight_Text(d->font);
1507 if (isPerPixel_MouseWheelEvent(&ev->wheel)) {
1508 d->wheelAccum -= ev->wheel.y;
1509 }
1510 else {
1511 d->wheelAccum -= ev->wheel.y * 3 * lineHeight;
1512 }
1513 int lineDelta = d->wheelAccum / lineHeight;
1514 if (lineDelta < 0) {
1515 lineDelta = iMax(lineDelta, -d->visWrapLines.start);
1516 if (!lineDelta) d->wheelAccum = 0;
1517 }
1518 else if (lineDelta > 0) {
1519 lineDelta = iMin(lineDelta,
1520 lastLine_InputWidget_(d)->wrapLines.end - d->visWrapLines.end);
1521 if (!lineDelta) d->wheelAccum = 0;
1522 }
1523 d->wheelAccum -= lineDelta * lineHeight;
1524 d->visWrapLines.start += lineDelta;
1525 d->visWrapLines.end += lineDelta;
1526 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
1527 refresh_Widget(d);
1528 return iTrue;
1529 }
1470 switch (processEvent_Click(&d->click, ev)) { 1530 switch (processEvent_Click(&d->click, ev)) {
1471 case none_ClickResult: 1531 case none_ClickResult:
1472 break; 1532 break;
@@ -1497,6 +1557,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1497 selectAll_InputWidget(d); 1557 selectAll_InputWidget(d);
1498 } 1558 }
1499 } 1559 }
1560 refresh_Widget(d);
1500 return iTrue; 1561 return iTrue;
1501 } 1562 }
1502 case aborted_ClickResult: 1563 case aborted_ClickResult:
@@ -1586,10 +1647,10 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1586 return iTrue; 1647 return iTrue;
1587 case SDLK_RETURN: 1648 case SDLK_RETURN:
1588 case SDLK_KP_ENTER: 1649 case SDLK_KP_ENTER:
1589 if (~d->inFlags & isSensitive_InputWidgetFlag && d->maxLen == 0) { 1650 if (~d->inFlags & isSensitive_InputWidgetFlag &&
1590 if (mods == lineBreakKeyMod_ReturnKeyBehavior(prefs_App()->returnKey) || 1651 ~d->inFlags & isUrl_InputWidgetFlag &&
1591 (~d->inFlags & isUrl_InputWidgetFlag && 1652 d->inFlags & lineBreaksEnabled_InputWidgetFlag && d->maxLen == 0) {
1592 d->inFlags & enterKeyInsertsLineFeed_InputWidgetFlag)) { 1653 if (checkLineBreakMods_InputWidget_(d, mods)) {
1593 pushUndo_InputWidget_(d); 1654 pushUndo_InputWidget_(d);
1594 deleteMarked_InputWidget_(d); 1655 deleteMarked_InputWidget_(d);
1595 insertChar_InputWidget_(d, '\n'); 1656 insertChar_InputWidget_(d, '\n');
@@ -1598,7 +1659,8 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1598 } 1659 }
1599 } 1660 }
1600 if (d->inFlags & enterKeyEnabled_InputWidgetFlag && 1661 if (d->inFlags & enterKeyEnabled_InputWidgetFlag &&
1601 mods == acceptKeyMod_ReturnKeyBehavior(prefs_App()->returnKey)) { 1662 (checkAcceptMods_InputWidget_(d, mods) ||
1663 (~d->inFlags & lineBreaksEnabled_InputWidgetFlag))) {
1602 d->inFlags |= enterPressed_InputWidgetFlag; 1664 d->inFlags |= enterPressed_InputWidgetFlag;
1603 setFocus_Widget(NULL); 1665 setFocus_Widget(NULL);
1604 return iTrue; 1666 return iTrue;
@@ -1700,6 +1762,9 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1700 case SDLK_a: 1762 case SDLK_a:
1701#if defined (iPlatformApple) 1763#if defined (iPlatformApple)
1702 if (mods == KMOD_PRIMARY) { 1764 if (mods == KMOD_PRIMARY) {
1765#else
1766 if (mods == (KMOD_PRIMARY | KMOD_SHIFT)) {
1767#endif
1703 selectAll_InputWidget(d); 1768 selectAll_InputWidget(d);
1704 d->mark.start = 0; 1769 d->mark.start = 0;
1705 d->mark.end = cursorToIndex_InputWidget_(d, curMax); 1770 d->mark.end = cursorToIndex_InputWidget_(d, curMax);
@@ -1708,7 +1773,6 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1708 refresh_Widget(w); 1773 refresh_Widget(w);
1709 return iTrue; 1774 return iTrue;
1710 } 1775 }
1711#endif
1712 /* fall through for Emacs-style Home/End */ 1776 /* fall through for Emacs-style Home/End */
1713 case SDLK_e: 1777 case SDLK_e:
1714 if (mods == KMOD_CTRL || mods == (KMOD_CTRL | KMOD_SHIFT)) { 1778 if (mods == KMOD_CTRL || mods == (KMOD_CTRL | KMOD_SHIFT)) {
@@ -1889,12 +1953,11 @@ static void draw_InputWidget_(const iInputWidget *d) {
1889 wrapText.wrapFunc = NULL; 1953 wrapText.wrapFunc = NULL;
1890 wrapText.context = NULL; 1954 wrapText.context = NULL;
1891 } 1955 }
1892 unsetClip_Paint(&p);
1893 /* Draw the insertion point. */ 1956 /* Draw the insertion point. */
1894 if (isFocused && d->cursorVis) { 1957 if (isFocused && d->cursorVis && contains_Range(&visLines, d->cursor.y)) {
1895 iInt2 curSize; 1958 iInt2 curSize;
1896 iRangecc cursorChar = iNullRange; 1959 iRangecc cursorChar = iNullRange;
1897 int visWrapsAbove = 0; 1960 int visWrapsAbove = 0;
1898 for (int i = d->cursor.y - 1; i >= visLines.start; i--) { 1961 for (int i = d->cursor.y - 1; i >= visLines.start; i--) {
1899 const iInputLine *line = constAt_Array(&d->lines, i); 1962 const iInputLine *line = constAt_Array(&d->lines, i);
1900 visWrapsAbove += numWrapLines_InputLine_(line); 1963 visWrapsAbove += numWrapLines_InputLine_(line);
@@ -1938,6 +2001,7 @@ static void draw_InputWidget_(const iInputWidget *d) {
1938 cursorChar); 2001 cursorChar);
1939 } 2002 }
1940 } 2003 }
2004 unsetClip_Paint(&p);
1941 drawChildren_Widget(w); 2005 drawChildren_Widget(w);
1942} 2006}
1943 2007
diff --git a/src/ui/inputwidget.h b/src/ui/inputwidget.h
index a94291ed..0d327ca6 100644
--- a/src/ui/inputwidget.h
+++ b/src/ui/inputwidget.h
@@ -50,8 +50,9 @@ void setFont_InputWidget (iInputWidget *, int fontId);
50void setContentPadding_InputWidget (iInputWidget *, int left, int right); /* only affects the text entry */ 50void setContentPadding_InputWidget (iInputWidget *, int left, int right); /* only affects the text entry */
51void setLineLimits_InputWidget (iInputWidget *, int minLines, int maxLines); 51void setLineLimits_InputWidget (iInputWidget *, int minLines, int maxLines);
52void setValidator_InputWidget (iInputWidget *, iInputWidgetValidatorFunc validator, void *context); 52void setValidator_InputWidget (iInputWidget *, iInputWidgetValidatorFunc validator, void *context);
53void setEnterInsertsLF_InputWidget (iInputWidget *, iBool enterInsertsLF); 53void setLineBreaksEnabled_InputWidget(iInputWidget *, iBool lineBreaksEnabled);
54void setEnterKeyEnabled_InputWidget (iInputWidget *, iBool enterKeyEnabled); 54void setEnterKeyEnabled_InputWidget (iInputWidget *, iBool enterKeyEnabled);
55void setUseReturnKeyBehavior_InputWidget(iInputWidget *, iBool useReturnKeyBehavior);
55void setBackupFileName_InputWidget (iInputWidget *, const char *fileName); 56void setBackupFileName_InputWidget (iInputWidget *, const char *fileName);
56void begin_InputWidget (iInputWidget *); 57void begin_InputWidget (iInputWidget *);
57void end_InputWidget (iInputWidget *, iBool accept); 58void end_InputWidget (iInputWidget *, iBool accept);
diff --git a/src/ui/root.c b/src/ui/root.c
index 9d92c44e..a8b9f998 100644
--- a/src/ui/root.c
+++ b/src/ui/root.c
@@ -358,9 +358,9 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) {
358 return iTrue; 358 return iTrue;
359 } 359 }
360 else if (equal_Command(cmd, "window.focus.lost")) { 360 else if (equal_Command(cmd, "window.focus.lost")) {
361#if !defined (iPlatformMobile) /* apps don't share input focus on mobile */ 361//#if !defined (iPlatformMobile) /* apps don't share input focus on mobile */
362 setFocus_Widget(NULL); 362// setFocus_Widget(NULL);
363#endif 363//#endif
364 setTextColor_LabelWidget(findWidget_App("winbar.app"), uiAnnotation_ColorId); 364 setTextColor_LabelWidget(findWidget_App("winbar.app"), uiAnnotation_ColorId);
365 setTextColor_LabelWidget(findWidget_App("winbar.title"), uiAnnotation_ColorId); 365 setTextColor_LabelWidget(findWidget_App("winbar.title"), uiAnnotation_ColorId);
366 return iFalse; 366 return iFalse;
@@ -1077,6 +1077,7 @@ void createUserInterface_Root(iRoot *d) {
1077 setSelectAllOnFocus_InputWidget(url, iTrue); 1077 setSelectAllOnFocus_InputWidget(url, iTrue);
1078 setId_Widget(as_Widget(url), "url"); 1078 setId_Widget(as_Widget(url), "url");
1079 setLineLimits_InputWidget(url, 1, 1); /* just one line while not focused */ 1079 setLineLimits_InputWidget(url, 1, 1); /* just one line while not focused */
1080 setLineBreaksEnabled_InputWidget(url, iFalse);
1080 setUrlContent_InputWidget(url, iTrue); 1081 setUrlContent_InputWidget(url, iTrue);
1081 setNotifyEdits_InputWidget(url, iTrue); 1082 setNotifyEdits_InputWidget(url, iTrue);
1082 setTextCStr_InputWidget(url, "gemini://"); 1083 setTextCStr_InputWidget(url, "gemini://");
@@ -1272,7 +1273,7 @@ void createUserInterface_Root(iRoot *d) {
1272 setHint_InputWidget(input, "${hint.findtext}"); 1273 setHint_InputWidget(input, "${hint.findtext}");
1273 setSelectAllOnFocus_InputWidget(input, iTrue); 1274 setSelectAllOnFocus_InputWidget(input, iTrue);
1274 setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */ 1275 setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */
1275 setEnterInsertsLF_InputWidget(input, iFalse); 1276 setLineBreaksEnabled_InputWidget(input, iFalse);
1276 setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag), 1277 setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag),
1277 "find.input"); 1278 "find.input");
1278 addChild_Widget(searchBar, iClob(newIcon_LabelWidget(" \u2b9f ", 'g', KMOD_PRIMARY, "find.next"))); 1279 addChild_Widget(searchBar, iClob(newIcon_LabelWidget(" \u2b9f ", 'g', KMOD_PRIMARY, "find.next")));
diff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c
index 7bfa73bd..57b6b6b7 100644
--- a/src/ui/uploadwidget.c
+++ b/src/ui/uploadwidget.c
@@ -116,8 +116,8 @@ void init_UploadWidget(iUploadWidget *d) {
116 setId_Widget(as_Widget(d->input), "upload.text"); 116 setId_Widget(as_Widget(d->input), "upload.text");
117 setFont_InputWidget(d->input, monospace_FontId); 117 setFont_InputWidget(d->input, monospace_FontId);
118 setLineLimits_InputWidget(d->input, 7, 20); 118 setLineLimits_InputWidget(d->input, 7, 20);
119 setUseReturnKeyBehavior_InputWidget(d->input, iFalse); /* traditional text editor */
119 setHint_InputWidget(d->input, "${hint.upload.text}"); 120 setHint_InputWidget(d->input, "${hint.upload.text}");
120 setEnterInsertsLF_InputWidget(d->input, iTrue);
121 setFixedSize_Widget(as_Widget(d->input), init_I2(120 * gap_UI, -1)); 121 setFixedSize_Widget(as_Widget(d->input), init_I2(120 * gap_UI, -1));
122 addChild_Widget(page, iClob(d->input)); 122 addChild_Widget(page, iClob(d->input));
123 appendFramelessTabPage_Widget(tabs, iClob(page), "${heading.upload.text}", '1', 0); 123 appendFramelessTabPage_Widget(tabs, iClob(page), "${heading.upload.text}", '1', 0);