diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-12-13 10:58:59 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-12-23 13:34:57 +0200 |
commit | e39721581f082a20f1ef3a6f81b83c5e489cf7c7 (patch) | |
tree | ce16e9a85d344d21eaa146f49e237eeaa3d1a1b9 | |
parent | 74de1ab589b80b7719e97341ec98869ecf3da8aa (diff) |
Android: Various fixes to get things up and running
Resource paths, runtime data, ignore mouse events. Assume that
the Java side tells us the display pixel density via a command
line argument.
-rw-r--r-- | src/app.c | 39 | ||||
-rw-r--r-- | src/resources.c | 20 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 68 | ||||
-rw-r--r-- | src/ui/touch.c | 4 | ||||
-rw-r--r-- | src/ui/window.c | 10 |
5 files changed, 99 insertions, 42 deletions
@@ -92,7 +92,10 @@ static const char *defaultDataDir_App_ = "~/Library/Application Support"; | |||
92 | #define EMB_BIN "../resources.lgr" | 92 | #define EMB_BIN "../resources.lgr" |
93 | static const char *defaultDataDir_App_ = "~/AppData/Roaming/fi.skyjake.Lagrange"; | 93 | static const char *defaultDataDir_App_ = "~/AppData/Roaming/fi.skyjake.Lagrange"; |
94 | #endif | 94 | #endif |
95 | #if defined (iPlatformLinux) || defined (iPlatformOther) | 95 | #if defined (iPlatformAndroidMobile) |
96 | #define EMB_BIN "resources.lgr" /* loaded from assets with SDL_rwops */ | ||
97 | static const char *defaultDataDir_App_ = NULL; /* will ask SDL */ | ||
98 | #elif defined (iPlatformLinux) || defined (iPlatformOther) | ||
96 | #define EMB_BIN "../../share/lagrange/resources.lgr" | 99 | #define EMB_BIN "../../share/lagrange/resources.lgr" |
97 | #define EMB_BIN2 "../../../share/lagrange/resources.lgr" | 100 | #define EMB_BIN2 "../../../share/lagrange/resources.lgr" |
98 | static const char *defaultDataDir_App_ = "~/.config/lagrange"; | 101 | static const char *defaultDataDir_App_ = "~/.config/lagrange"; |
@@ -139,6 +142,9 @@ struct Impl_App { | |||
139 | int autoReloadTimer; | 142 | int autoReloadTimer; |
140 | iPeriodic periodic; | 143 | iPeriodic periodic; |
141 | int warmupFrames; /* forced refresh just after resuming from background; FIXME: shouldn't be needed */ | 144 | int warmupFrames; /* forced refresh just after resuming from background; FIXME: shouldn't be needed */ |
145 | #if defined (iPlatformAndroidMobile) | ||
146 | float displayDensity; | ||
147 | #endif | ||
142 | /* Preferences: */ | 148 | /* Preferences: */ |
143 | iBool commandEcho; /* --echo */ | 149 | iBool commandEcho; /* --echo */ |
144 | iBool forceSoftwareRender; /* --sw */ | 150 | iBool forceSoftwareRender; /* --sw */ |
@@ -307,7 +313,10 @@ static const char *dataDir_App_(void) { | |||
307 | return userDir; | 313 | return userDir; |
308 | } | 314 | } |
309 | #endif | 315 | #endif |
310 | return defaultDataDir_App_; | 316 | if (defaultDataDir_App_) { |
317 | return defaultDataDir_App_; | ||
318 | } | ||
319 | return SDL_GetPrefPath("Jaakko Keränen", "fi.skyjake.lagrange"); | ||
311 | } | 320 | } |
312 | 321 | ||
313 | static const char *downloadDir_App_(void) { | 322 | static const char *downloadDir_App_(void) { |
@@ -715,7 +724,7 @@ static iBool hasCommandLineOpenableScheme_(const iRangecc uri) { | |||
715 | } | 724 | } |
716 | 725 | ||
717 | static void init_App_(iApp *d, int argc, char **argv) { | 726 | static void init_App_(iApp *d, int argc, char **argv) { |
718 | #if defined (iPlatformLinux) | 727 | #if defined (iPlatformLinux) && !defined (iPlatformAndroid) |
719 | d->isRunningUnderWindowSystem = !iCmpStr(SDL_GetCurrentVideoDriver(), "x11") || | 728 | d->isRunningUnderWindowSystem = !iCmpStr(SDL_GetCurrentVideoDriver(), "x11") || |
720 | !iCmpStr(SDL_GetCurrentVideoDriver(), "wayland"); | 729 | !iCmpStr(SDL_GetCurrentVideoDriver(), "wayland"); |
721 | #else | 730 | #else |
@@ -763,6 +772,8 @@ static void init_App_(iApp *d, int argc, char **argv) { | |||
763 | } | 772 | } |
764 | } | 773 | } |
765 | init_Lang(); | 774 | init_Lang(); |
775 | iStringList *openCmds = new_StringList(); | ||
776 | #if !defined (iPlatformAndroidMobile) | ||
766 | /* Configure the valid command line options. */ { | 777 | /* Configure the valid command line options. */ { |
767 | defineValues_CommandLine(&d->args, "close-tab", 0); | 778 | defineValues_CommandLine(&d->args, "close-tab", 0); |
768 | defineValues_CommandLine(&d->args, "echo;E", 0); | 779 | defineValues_CommandLine(&d->args, "echo;E", 0); |
@@ -777,7 +788,6 @@ static void init_App_(iApp *d, int argc, char **argv) { | |||
777 | defineValues_CommandLine(&d->args, "sw", 0); | 788 | defineValues_CommandLine(&d->args, "sw", 0); |
778 | defineValues_CommandLine(&d->args, "version;V", 0); | 789 | defineValues_CommandLine(&d->args, "version;V", 0); |
779 | } | 790 | } |
780 | iStringList *openCmds = new_StringList(); | ||
781 | /* Handle command line options. */ { | 791 | /* Handle command line options. */ { |
782 | if (contains_CommandLine(&d->args, "help")) { | 792 | if (contains_CommandLine(&d->args, "help")) { |
783 | puts(cstr_Block(&blobArghelp_Resources)); | 793 | puts(cstr_Block(&blobArghelp_Resources)); |
@@ -826,6 +836,7 @@ static void init_App_(iApp *d, int argc, char **argv) { | |||
826 | } | 836 | } |
827 | } | 837 | } |
828 | } | 838 | } |
839 | #endif | ||
829 | #if defined (LAGRANGE_ENABLE_IPC) | 840 | #if defined (LAGRANGE_ENABLE_IPC) |
830 | /* Only one instance is allowed to run at a time; the runtime files (bookmarks, etc.) | 841 | /* Only one instance is allowed to run at a time; the runtime files (bookmarks, etc.) |
831 | are not shareable. */ { | 842 | are not shareable. */ { |
@@ -860,7 +871,7 @@ static void init_App_(iApp *d, int argc, char **argv) { | |||
860 | /* Must scale by UI scaling factor. */ | 871 | /* Must scale by UI scaling factor. */ |
861 | mulfv_I2(&d->initialWindowRect.size, desktopDPI_Win32()); | 872 | mulfv_I2(&d->initialWindowRect.size, desktopDPI_Win32()); |
862 | #endif | 873 | #endif |
863 | #if defined (iPlatformLinux) | 874 | #if defined (iPlatformLinux) && !defined (iPlatformAndroid) |
864 | /* Scale by the primary (?) monitor DPI. */ | 875 | /* Scale by the primary (?) monitor DPI. */ |
865 | if (isRunningUnderWindowSystem_App()) { | 876 | if (isRunningUnderWindowSystem_App()) { |
866 | float vdpi; | 877 | float vdpi; |
@@ -1325,6 +1336,15 @@ void processEvents_App(enum iAppEventMode eventMode) { | |||
1325 | } | 1336 | } |
1326 | ev.key.keysym.mod = mapMods_Keys(ev.key.keysym.mod & ~KMOD_CAPS); | 1337 | ev.key.keysym.mod = mapMods_Keys(ev.key.keysym.mod & ~KMOD_CAPS); |
1327 | } | 1338 | } |
1339 | #if defined (iPlatformAndroidMobile) | ||
1340 | /* Ignore all mouse events; just use touch. */ | ||
1341 | if (ev.type == SDL_MOUSEBUTTONDOWN || | ||
1342 | ev.type == SDL_MOUSEBUTTONUP || | ||
1343 | ev.type == SDL_MOUSEMOTION || | ||
1344 | ev.type == SDL_MOUSEWHEEL) { | ||
1345 | continue; | ||
1346 | } | ||
1347 | #endif | ||
1328 | /* Scroll events may be per-pixel or mouse wheel steps. */ | 1348 | /* Scroll events may be per-pixel or mouse wheel steps. */ |
1329 | if (ev.type == SDL_MOUSEWHEEL) { | 1349 | if (ev.type == SDL_MOUSEWHEEL) { |
1330 | #if defined (iPlatformMsys) | 1350 | #if defined (iPlatformMsys) |
@@ -1773,6 +1793,8 @@ enum iAppDeviceType deviceType_App(void) { | |||
1773 | return tablet_AppDeviceType; | 1793 | return tablet_AppDeviceType; |
1774 | #elif defined (iPlatformAppleMobile) | 1794 | #elif defined (iPlatformAppleMobile) |
1775 | return isPhone_iOS() ? phone_AppDeviceType : tablet_AppDeviceType; | 1795 | return isPhone_iOS() ? phone_AppDeviceType : tablet_AppDeviceType; |
1796 | #elif defined (iPlatformAndroidMobile) | ||
1797 | return phone_AppDeviceType; /* TODO: Java side could tell us via cmdline if this is a tablet. */ | ||
1776 | #else | 1798 | #else |
1777 | return desktop_AppDeviceType; | 1799 | return desktop_AppDeviceType; |
1778 | #endif | 1800 | #endif |
@@ -3408,3 +3430,10 @@ void closePopups_App(void) { | |||
3408 | } | 3430 | } |
3409 | } | 3431 | } |
3410 | } | 3432 | } |
3433 | |||
3434 | #if defined (iPlatformAndroidMobile) | ||
3435 | float displayDensity_Android(void) { | ||
3436 | iApp *d = &app_; | ||
3437 | return toFloat_String(at_CommandLine(&d->args, 1)); | ||
3438 | } | ||
3439 | #endif | ||
diff --git a/src/resources.c b/src/resources.c index bb601cca..e3d92946 100644 --- a/src/resources.c +++ b/src/resources.c | |||
@@ -26,7 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
26 | #include <the_Foundation/version.h> | 26 | #include <the_Foundation/version.h> |
27 | 27 | ||
28 | static iArchive *archive_; | 28 | static iArchive *archive_; |
29 | 29 | ||
30 | iBlock blobAbout_Resources; | 30 | iBlock blobAbout_Resources; |
31 | iBlock blobHelp_Resources; | 31 | iBlock blobHelp_Resources; |
32 | iBlock blobLagrange_Resources; | 32 | iBlock blobLagrange_Resources; |
@@ -101,7 +101,23 @@ static struct { | |||
101 | 101 | ||
102 | iBool init_Resources(const char *path) { | 102 | iBool init_Resources(const char *path) { |
103 | archive_ = new_Archive(); | 103 | archive_ = new_Archive(); |
104 | if (openFile_Archive(archive_, collectNewCStr_String(path))) { | 104 | iBool ok = iFalse; |
105 | #if defined (iPlatformAndroidMobile) | ||
106 | /* Resources are bundled as assets so they cannot be loaded as a regular file. | ||
107 | Fortunately, SDL implements a file wrapper. */ | ||
108 | SDL_RWops *io = SDL_RWFromFile(path, "rb"); | ||
109 | if (io) { | ||
110 | iBlock buf; | ||
111 | init_Block(&buf, (size_t) SDL_RWsize(io)); | ||
112 | SDL_RWread(io, data_Block(&buf), size_Block(&buf), 1); | ||
113 | SDL_RWclose(io); | ||
114 | ok = openData_Archive(archive_, &buf); | ||
115 | deinit_Block(&buf); | ||
116 | } | ||
117 | #else | ||
118 | ok = openFile_Archive(archive_, collectNewCStr_String(path)); | ||
119 | #endif | ||
120 | if (ok) { | ||
105 | iVersion appVer; | 121 | iVersion appVer; |
106 | init_Version(&appVer, range_CStr(LAGRANGE_APP_VERSION)); | 122 | init_Version(&appVer, range_CStr(LAGRANGE_APP_VERSION)); |
107 | iVersion resVer; | 123 | iVersion resVer; |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index e93fb586..b20ae672 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -225,7 +225,7 @@ enum iDocumentWidgetFlag { | |||
225 | animationPlaceholder_DocumentWidgetFlag = iBit(16), /* avoid slow operations */ | 225 | animationPlaceholder_DocumentWidgetFlag = iBit(16), /* avoid slow operations */ |
226 | invalidationPending_DocumentWidgetFlag = iBit(17), /* invalidate as soon as convenient */ | 226 | invalidationPending_DocumentWidgetFlag = iBit(17), /* invalidate as soon as convenient */ |
227 | leftWheelSwipe_DocumentWidgetFlag = iBit(18), /* swipe state flags are used on desktop */ | 227 | leftWheelSwipe_DocumentWidgetFlag = iBit(18), /* swipe state flags are used on desktop */ |
228 | rightWheelSwipe_DocumentWidgetFlag = iBit(19), | 228 | rightWheelSwipe_DocumentWidgetFlag = iBit(19), |
229 | eitherWheelSwipe_DocumentWidgetFlag = leftWheelSwipe_DocumentWidgetFlag | | 229 | eitherWheelSwipe_DocumentWidgetFlag = leftWheelSwipe_DocumentWidgetFlag | |
230 | rightWheelSwipe_DocumentWidgetFlag, | 230 | rightWheelSwipe_DocumentWidgetFlag, |
231 | }; | 231 | }; |
@@ -242,8 +242,8 @@ enum iWheelSwipeState { | |||
242 | 242 | ||
243 | /* TODO: DocumentView is supposed to be useful on its own; move to a separate source file. */ | 243 | /* TODO: DocumentView is supposed to be useful on its own; move to a separate source file. */ |
244 | iDeclareType(DocumentView) | 244 | iDeclareType(DocumentView) |
245 | 245 | ||
246 | struct Impl_DocumentView { | 246 | struct Impl_DocumentView { |
247 | iDocumentWidget *owner; /* TODO: Convert to an abstract provider of metrics? */ | 247 | iDocumentWidget *owner; /* TODO: Convert to an abstract provider of metrics? */ |
248 | iGmDocument * doc; | 248 | iGmDocument * doc; |
249 | int pageMargin; | 249 | int pageMargin; |
@@ -253,7 +253,7 @@ struct Impl_DocumentView { | |||
253 | iGmRunRange visibleRuns; | 253 | iGmRunRange visibleRuns; |
254 | iPtrArray visibleLinks; | 254 | iPtrArray visibleLinks; |
255 | iPtrArray visiblePre; | 255 | iPtrArray visiblePre; |
256 | iPtrArray visibleMedia; /* currently playing audio / ongoing downloads */ | 256 | iPtrArray visibleMedia; /* currently playing audio / ongoing downloads */ |
257 | iPtrArray visibleWideRuns; /* scrollable blocks; TODO: merge into `visiblePre` */ | 257 | iPtrArray visibleWideRuns; /* scrollable blocks; TODO: merge into `visiblePre` */ |
258 | const iGmRun * hoverPre; /* for clicking */ | 258 | const iGmRun * hoverPre; /* for clicking */ |
259 | const iGmRun * hoverAltPre; /* for drawing alt text */ | 259 | const iGmRun * hoverAltPre; /* for drawing alt text */ |
@@ -263,7 +263,7 @@ struct Impl_DocumentView { | |||
263 | uint16_t animWideRunId; | 263 | uint16_t animWideRunId; |
264 | iGmRunRange animWideRunRange; | 264 | iGmRunRange animWideRunRange; |
265 | iDrawBufs * drawBufs; /* dynamic state for drawing */ | 265 | iDrawBufs * drawBufs; /* dynamic state for drawing */ |
266 | iVisBuf * visBuf; | 266 | iVisBuf * visBuf; |
267 | iVisBufMeta * visBufMeta; | 267 | iVisBufMeta * visBufMeta; |
268 | iGmRunRange renderRuns; | 268 | iGmRunRange renderRuns; |
269 | iPtrSet * invalidRuns; | 269 | iPtrSet * invalidRuns; |
@@ -272,7 +272,7 @@ struct Impl_DocumentView { | |||
272 | struct Impl_DocumentWidget { | 272 | struct Impl_DocumentWidget { |
273 | iWidget widget; | 273 | iWidget widget; |
274 | int flags; /* internal behavior, see enum iDocumentWidgetFlag */ | 274 | int flags; /* internal behavior, see enum iDocumentWidgetFlag */ |
275 | 275 | ||
276 | /* User interface: */ | 276 | /* User interface: */ |
277 | enum iDocumentLinkOrdinalMode ordinalMode; | 277 | enum iDocumentLinkOrdinalMode ordinalMode; |
278 | size_t ordinalBase; | 278 | size_t ordinalBase; |
@@ -293,7 +293,7 @@ struct Impl_DocumentWidget { | |||
293 | enum iWheelSwipeState wheelSwipeState; | 293 | enum iWheelSwipeState wheelSwipeState; |
294 | iString pendingGotoHeading; | 294 | iString pendingGotoHeading; |
295 | iString linePrecedingLink; | 295 | iString linePrecedingLink; |
296 | 296 | ||
297 | /* Network request: */ | 297 | /* Network request: */ |
298 | enum iRequestState state; | 298 | enum iRequestState state; |
299 | iGmRequest * request; | 299 | iGmRequest * request; |
@@ -304,7 +304,7 @@ struct Impl_DocumentWidget { | |||
304 | iString * certSubject; | 304 | iString * certSubject; |
305 | int redirectCount; | 305 | int redirectCount; |
306 | iObjectList * media; /* inline media requests */ | 306 | iObjectList * media; /* inline media requests */ |
307 | 307 | ||
308 | /* Document: */ | 308 | /* Document: */ |
309 | iPersistentDocumentState mod; | 309 | iPersistentDocumentState mod; |
310 | iString * titleUser; | 310 | iString * titleUser; |
@@ -316,12 +316,12 @@ struct Impl_DocumentWidget { | |||
316 | iGempub * sourceGempub; /* NULL unless the page is Gempub content */ | 316 | iGempub * sourceGempub; /* NULL unless the page is Gempub content */ |
317 | iBanner * banner; | 317 | iBanner * banner; |
318 | float initNormScrollY; | 318 | float initNormScrollY; |
319 | 319 | ||
320 | /* Rendering: */ | 320 | /* Rendering: */ |
321 | iDocumentView view; | 321 | iDocumentView view; |
322 | iLinkInfo * linkInfo; | 322 | iLinkInfo * linkInfo; |
323 | 323 | ||
324 | /* Widget structure: */ | 324 | /* Widget structure: */ |
325 | iScrollWidget *scroll; | 325 | iScrollWidget *scroll; |
326 | iWidget * footerButtons; | 326 | iWidget * footerButtons; |
327 | iWidget * menu; | 327 | iWidget * menu; |
@@ -332,7 +332,7 @@ struct Impl_DocumentWidget { | |||
332 | }; | 332 | }; |
333 | 333 | ||
334 | iDefineObjectConstruction(DocumentWidget) | 334 | iDefineObjectConstruction(DocumentWidget) |
335 | 335 | ||
336 | /* Sorted by proximity to F and J. */ | 336 | /* Sorted by proximity to F and J. */ |
337 | static const int homeRowKeys_[] = { | 337 | static const int homeRowKeys_[] = { |
338 | 'f', 'd', 's', 'a', | 338 | 'f', 'd', 's', 'a', |
@@ -344,7 +344,7 @@ static const int homeRowKeys_[] = { | |||
344 | 'g', 'h', | 344 | 'g', 'h', |
345 | 'b', | 345 | 'b', |
346 | 't', 'y', | 346 | 't', 'y', |
347 | }; | 347 | }; |
348 | static int docEnum_ = 0; | 348 | static int docEnum_ = 0; |
349 | 349 | ||
350 | static void animate_DocumentWidget_ (void *ticker); | 350 | static void animate_DocumentWidget_ (void *ticker); |
@@ -909,7 +909,7 @@ static void updateTimestampBuf_DocumentView_(const iDocumentView *d) { | |||
909 | 909 | ||
910 | static void invalidate_DocumentView_(iDocumentView *d) { | 910 | static void invalidate_DocumentView_(iDocumentView *d) { |
911 | invalidate_VisBuf(d->visBuf); | 911 | invalidate_VisBuf(d->visBuf); |
912 | clear_PtrSet(d->invalidRuns); | 912 | clear_PtrSet(d->invalidRuns); |
913 | } | 913 | } |
914 | 914 | ||
915 | static void documentRunsInvalidated_DocumentView_(iDocumentView *d) { | 915 | static void documentRunsInvalidated_DocumentView_(iDocumentView *d) { |
@@ -928,11 +928,11 @@ static void resetScroll_DocumentView_(iDocumentView *d) { | |||
928 | } | 928 | } |
929 | 929 | ||
930 | static void updateWidth_DocumentView_(iDocumentView *d) { | 930 | static void updateWidth_DocumentView_(iDocumentView *d) { |
931 | updateWidth_GmDocument(d->doc, documentWidth_DocumentView_(d), width_Widget(d->owner)); | 931 | updateWidth_GmDocument(d->doc, documentWidth_DocumentView_(d), width_Widget(d->owner)); |
932 | } | 932 | } |
933 | 933 | ||
934 | static void updateWidthAndRedoLayout_DocumentView_(iDocumentView *d) { | 934 | static void updateWidthAndRedoLayout_DocumentView_(iDocumentView *d) { |
935 | setWidth_GmDocument(d->doc, documentWidth_DocumentView_(d), width_Widget(d->owner)); | 935 | setWidth_GmDocument(d->doc, documentWidth_DocumentView_(d), width_Widget(d->owner)); |
936 | } | 936 | } |
937 | 937 | ||
938 | static void clampScroll_DocumentView_(iDocumentView *d) { | 938 | static void clampScroll_DocumentView_(iDocumentView *d) { |
@@ -1025,7 +1025,7 @@ static iRangecc sourceLoc_DocumentView_(const iDocumentView *d, iInt2 pos) { | |||
1025 | } | 1025 | } |
1026 | 1026 | ||
1027 | iDeclareType(MiddleRunParams) | 1027 | iDeclareType(MiddleRunParams) |
1028 | 1028 | ||
1029 | struct Impl_MiddleRunParams { | 1029 | struct Impl_MiddleRunParams { |
1030 | int midY; | 1030 | int midY; |
1031 | const iGmRun *closest; | 1031 | const iGmRun *closest; |
@@ -1126,7 +1126,7 @@ static iRect runRect_DocumentView_(const iDocumentView *d, const iGmRun *run) { | |||
1126 | } | 1126 | } |
1127 | 1127 | ||
1128 | iDeclareType(DrawContext) | 1128 | iDeclareType(DrawContext) |
1129 | 1129 | ||
1130 | struct Impl_DrawContext { | 1130 | struct Impl_DrawContext { |
1131 | const iDocumentView *view; | 1131 | const iDocumentView *view; |
1132 | iRect widgetBounds; | 1132 | iRect widgetBounds; |
@@ -1260,7 +1260,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
1260 | isInlineImageCaption = iFalse; | 1260 | isInlineImageCaption = iFalse; |
1261 | } | 1261 | } |
1262 | #endif | 1262 | #endif |
1263 | /* While this is consistent, it's a bit excessive to indicate that an inlined image | 1263 | /* While this is consistent, it's a bit excessive to indicate that an inlined image |
1264 | is open: the image itself is the indication. */ | 1264 | is open: the image itself is the indication. */ |
1265 | const iBool isInlineImageCaption = iFalse; | 1265 | const iBool isInlineImageCaption = iFalse; |
1266 | if (run->linkId && (linkFlags & isOpen_GmLinkFlag || isInlineImageCaption)) { | 1266 | if (run->linkId && (linkFlags & isOpen_GmLinkFlag || isInlineImageCaption)) { |
@@ -1285,7 +1285,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
1285 | } | 1285 | } |
1286 | fillRect_Paint(&d->paint, wideRect, bg); | 1286 | fillRect_Paint(&d->paint, wideRect, bg); |
1287 | } | 1287 | } |
1288 | else { | 1288 | else { |
1289 | /* Normal background for other runs. There are cases when runs get drawn multiple times, | 1289 | /* Normal background for other runs. There are cases when runs get drawn multiple times, |
1290 | e.g., at the buffer boundary, and there are slightly overlapping characters in | 1290 | e.g., at the buffer boundary, and there are slightly overlapping characters in |
1291 | monospace blocks. Clearing the background here ensures a cleaner visual appearance | 1291 | monospace blocks. Clearing the background here ensures a cleaner visual appearance |
@@ -2095,7 +2095,7 @@ static void invalidate_DocumentWidget_(iDocumentWidget *d) { | |||
2095 | } | 2095 | } |
2096 | 2096 | ||
2097 | static iRangecc siteText_DocumentWidget_(const iDocumentWidget *d) { | 2097 | static iRangecc siteText_DocumentWidget_(const iDocumentWidget *d) { |
2098 | return isEmpty_String(d->titleUser) ? urlHost_String(d->mod.url) | 2098 | return isEmpty_String(d->titleUser) ? urlHost_String(d->mod.url) |
2099 | : range_String(d->titleUser); | 2099 | : range_String(d->titleUser); |
2100 | } | 2100 | } |
2101 | 2101 | ||
@@ -2161,7 +2161,7 @@ static void updateBanner_DocumentWidget_(iDocumentWidget *d) { | |||
2161 | static void updateTheme_DocumentWidget_(iDocumentWidget *d) { | 2161 | static void updateTheme_DocumentWidget_(iDocumentWidget *d) { |
2162 | if (document_App() != d || category_GmStatusCode(d->sourceStatus) == categoryInput_GmStatusCode) { | 2162 | if (document_App() != d || category_GmStatusCode(d->sourceStatus) == categoryInput_GmStatusCode) { |
2163 | return; | 2163 | return; |
2164 | } | 2164 | } |
2165 | d->view.drawBufs->flags |= updateTimestampBuf_DrawBufsFlag; | 2165 | d->view.drawBufs->flags |= updateTimestampBuf_DrawBufsFlag; |
2166 | updateBanner_DocumentWidget_(d); | 2166 | updateBanner_DocumentWidget_(d); |
2167 | } | 2167 | } |
@@ -2620,7 +2620,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, | |||
2620 | appendFormat_String(&str, | 2620 | appendFormat_String(&str, |
2621 | cstr_Lang("doc.archive"), | 2621 | cstr_Lang("doc.archive"), |
2622 | cstr_Rangecc(baseName_Path(d->mod.url))); | 2622 | cstr_Rangecc(baseName_Path(d->mod.url))); |
2623 | appendCStr_String(&str, "\n"); | 2623 | appendCStr_String(&str, "\n"); |
2624 | } | 2624 | } |
2625 | appendCStr_String(&str, "\n"); | 2625 | appendCStr_String(&str, "\n"); |
2626 | iString *localPath = localFilePathFromUrl_String(d->mod.url); | 2626 | iString *localPath = localFilePathFromUrl_String(d->mod.url); |
@@ -2768,7 +2768,7 @@ static void updateTrust_DocumentWidget_(iDocumentWidget *d, const iGmResponse *r | |||
2768 | } | 2768 | } |
2769 | else if (~d->certFlags & timeVerified_GmCertFlag) { | 2769 | else if (~d->certFlags & timeVerified_GmCertFlag) { |
2770 | updateTextCStr_LabelWidget(lock, isDarkMode ? orange_ColorEscape warning_Icon | 2770 | updateTextCStr_LabelWidget(lock, isDarkMode ? orange_ColorEscape warning_Icon |
2771 | : black_ColorEscape warning_Icon); | 2771 | : black_ColorEscape warning_Icon); |
2772 | } | 2772 | } |
2773 | else { | 2773 | else { |
2774 | updateTextCStr_LabelWidget(lock, green_ColorEscape closedLock_Icon); | 2774 | updateTextCStr_LabelWidget(lock, green_ColorEscape closedLock_Icon); |
@@ -3067,7 +3067,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { | |||
3067 | it is only displayed as an input dialog. */ | 3067 | it is only displayed as an input dialog. */ |
3068 | visitUrl_Visited(visited_App(), d->mod.url, transient_VisitedUrlFlag); | 3068 | visitUrl_Visited(visited_App(), d->mod.url, transient_VisitedUrlFlag); |
3069 | iUrl parts; | 3069 | iUrl parts; |
3070 | init_Url(&parts, d->mod.url); | 3070 | init_Url(&parts, d->mod.url); |
3071 | iWidget *dlg = makeValueInput_Widget( | 3071 | iWidget *dlg = makeValueInput_Widget( |
3072 | as_Widget(d), | 3072 | as_Widget(d), |
3073 | NULL, | 3073 | NULL, |
@@ -3132,7 +3132,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { | |||
3132 | setFont_LabelWidget(menu, font_LabelWidget((iLabelWidget *) lastChild_Widget(buttons))); | 3132 | setFont_LabelWidget(menu, font_LabelWidget((iLabelWidget *) lastChild_Widget(buttons))); |
3133 | setTextColor_LabelWidget(menu, uiTextAction_ColorId); | 3133 | setTextColor_LabelWidget(menu, uiTextAction_ColorId); |
3134 | } | 3134 | } |
3135 | } | 3135 | } |
3136 | setValidator_InputWidget(findChild_Widget(dlg, "input"), inputQueryValidator_, d); | 3136 | setValidator_InputWidget(findChild_Widget(dlg, "input"), inputQueryValidator_, d); |
3137 | setSensitiveContent_InputWidget(findChild_Widget(dlg, "input"), | 3137 | setSensitiveContent_InputWidget(findChild_Widget(dlg, "input"), |
3138 | statusCode == sensitiveInput_GmStatusCode); | 3138 | statusCode == sensitiveInput_GmStatusCode); |
@@ -3491,7 +3491,7 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | |||
3491 | } | 3491 | } |
3492 | /* The temporary "swipein" will display the previous page until the finger is lifted. */ | 3492 | /* The temporary "swipein" will display the previous page until the finger is lifted. */ |
3493 | iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); | 3493 | iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); |
3494 | if (!swipeIn) { | 3494 | if (!swipeIn) { |
3495 | swipeIn = new_DocumentWidget(); | 3495 | swipeIn = new_DocumentWidget(); |
3496 | swipeIn->flags |= animationPlaceholder_DocumentWidgetFlag; | 3496 | swipeIn->flags |= animationPlaceholder_DocumentWidgetFlag; |
3497 | setId_Widget(as_Widget(swipeIn), "swipein"); | 3497 | setId_Widget(as_Widget(swipeIn), "swipein"); |
@@ -3531,7 +3531,7 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | |||
3531 | iWidget *swipeParent = swipeParent_DocumentWidget_(d); | 3531 | iWidget *swipeParent = swipeParent_DocumentWidget_(d); |
3532 | if (findChild_Widget(swipeParent, "swipeout")) { | 3532 | if (findChild_Widget(swipeParent, "swipeout")) { |
3533 | return iTrue; /* too fast, previous animation hasn't finished */ | 3533 | return iTrue; /* too fast, previous animation hasn't finished */ |
3534 | } | 3534 | } |
3535 | /* Setup the drag. `d` will be moving with the finger. */ | 3535 | /* Setup the drag. `d` will be moving with the finger. */ |
3536 | animSpan = 0; | 3536 | animSpan = 0; |
3537 | postCommand_Widget(d, "navigate.forward"); | 3537 | postCommand_Widget(d, "navigate.forward"); |
@@ -3694,7 +3694,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
3694 | else if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed") || | 3694 | else if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed") || |
3695 | equal_Command(cmd, "keyroot.changed")) { | 3695 | equal_Command(cmd, "keyroot.changed")) { |
3696 | if (equal_Command(cmd, "font.changed")) { | 3696 | if (equal_Command(cmd, "font.changed")) { |
3697 | invalidateCachedLayout_History(d->mod.history); | 3697 | invalidateCachedLayout_History(d->mod.history); |
3698 | } | 3698 | } |
3699 | /* Alt/Option key may be involved in window size changes. */ | 3699 | /* Alt/Option key may be involved in window size changes. */ |
3700 | setLinkNumberMode_DocumentWidget_(d, iFalse); | 3700 | setLinkNumberMode_DocumentWidget_(d, iFalse); |
@@ -4056,7 +4056,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
4056 | } | 4056 | } |
4057 | return wasHandled; | 4057 | return wasHandled; |
4058 | } | 4058 | } |
4059 | else if (equal_Command(cmd, "document.upload") && d == document_App()) { | 4059 | else if (equal_Command(cmd, "document.upload") && d == document_App()) { |
4060 | if (findChild_Widget(root_Widget(w), "upload")) { | 4060 | if (findChild_Widget(root_Widget(w), "upload")) { |
4061 | return iTrue; /* already open */ | 4061 | return iTrue; /* already open */ |
4062 | } | 4062 | } |
@@ -4124,7 +4124,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
4124 | if (equalCase_Rangecc(urlScheme_String(d->mod.url), "titan")) { | 4124 | if (equalCase_Rangecc(urlScheme_String(d->mod.url), "titan")) { |
4125 | /* Reopen so the Upload dialog gets shown. */ | 4125 | /* Reopen so the Upload dialog gets shown. */ |
4126 | postCommandf_App("open url:%s", cstr_String(d->mod.url)); | 4126 | postCommandf_App("open url:%s", cstr_String(d->mod.url)); |
4127 | return iTrue; | 4127 | return iTrue; |
4128 | } | 4128 | } |
4129 | fetch_DocumentWidget_(d); | 4129 | fetch_DocumentWidget_(d); |
4130 | return iTrue; | 4130 | return iTrue; |
@@ -4416,7 +4416,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
4416 | if (argLabel_Command(cmd, "ttf")) { | 4416 | if (argLabel_Command(cmd, "ttf")) { |
4417 | iAssert(!cmp_String(&d->sourceMime, "font/ttf")); | 4417 | iAssert(!cmp_String(&d->sourceMime, "font/ttf")); |
4418 | installFontFile_Fonts(collect_String(suffix_Command(cmd, "name")), &d->sourceContent); | 4418 | installFontFile_Fonts(collect_String(suffix_Command(cmd, "name")), &d->sourceContent); |
4419 | postCommand_App("open url:about:fonts"); | 4419 | postCommand_App("open url:about:fonts"); |
4420 | } | 4420 | } |
4421 | else { | 4421 | else { |
4422 | const iString *id = idFromUrl_FontPack(d->mod.url); | 4422 | const iString *id = idFromUrl_FontPack(d->mod.url); |
@@ -5435,7 +5435,7 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
5435 | init_Widget(w); | 5435 | init_Widget(w); |
5436 | setId_Widget(w, format_CStr("document%03d", ++docEnum_)); | 5436 | setId_Widget(w, format_CStr("document%03d", ++docEnum_)); |
5437 | setFlags_Widget(w, hover_WidgetFlag | noBackground_WidgetFlag, iTrue); | 5437 | setFlags_Widget(w, hover_WidgetFlag | noBackground_WidgetFlag, iTrue); |
5438 | #if defined (iPlatformAppleDesktop) | 5438 | #if defined (iPlatformAppleDesktop) |
5439 | iBool enableSwipeNavigation = iTrue; /* swipes on the trackpad */ | 5439 | iBool enableSwipeNavigation = iTrue; /* swipes on the trackpad */ |
5440 | #else | 5440 | #else |
5441 | iBool enableSwipeNavigation = (deviceType_App() != desktop_AppDeviceType); | 5441 | iBool enableSwipeNavigation = (deviceType_App() != desktop_AppDeviceType); |
@@ -5671,7 +5671,7 @@ iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) { | |||
5671 | void takeRequest_DocumentWidget(iDocumentWidget *d, iGmRequest *finishedRequest) { | 5671 | void takeRequest_DocumentWidget(iDocumentWidget *d, iGmRequest *finishedRequest) { |
5672 | cancelRequest_DocumentWidget_(d, iFalse /* don't post anything */); | 5672 | cancelRequest_DocumentWidget_(d, iFalse /* don't post anything */); |
5673 | const iString *url = url_GmRequest(finishedRequest); | 5673 | const iString *url = url_GmRequest(finishedRequest); |
5674 | 5674 | ||
5675 | add_History(d->mod.history, url); | 5675 | add_History(d->mod.history, url); |
5676 | setUrl_DocumentWidget_(d, url); | 5676 | setUrl_DocumentWidget_(d, url); |
5677 | d->state = fetching_RequestState; | 5677 | d->state = fetching_RequestState; |
diff --git a/src/ui/touch.c b/src/ui/touch.c index 0749bc7c..3d318dfb 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c | |||
@@ -42,7 +42,11 @@ iDeclareType(TouchState) | |||
42 | 42 | ||
43 | static const uint32_t longPressSpanMs_ = 500; | 43 | static const uint32_t longPressSpanMs_ = 500; |
44 | static const uint32_t shortPressSpanMs_ = 250; | 44 | static const uint32_t shortPressSpanMs_ = 250; |
45 | #if defined (iPlatformAndroidMobile) | ||
46 | static const int tapRadiusPt_ = 30; /* inaccurate sensors? */ | ||
47 | #else | ||
45 | static const int tapRadiusPt_ = 10; | 48 | static const int tapRadiusPt_ = 10; |
49 | #endif | ||
46 | 50 | ||
47 | enum iTouchEdge { | 51 | enum iTouchEdge { |
48 | none_TouchEdge, | 52 | none_TouchEdge, |
diff --git a/src/ui/window.c b/src/ui/window.c index 0e13a57f..7f3371c8 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -263,6 +263,10 @@ static float pixelRatio_Window_(const iWindow *d) { | |||
263 | # define baseDPI_Window 96.0f | 263 | # define baseDPI_Window 96.0f |
264 | #endif | 264 | #endif |
265 | 265 | ||
266 | #if defined (iPlatformAndroidMobile) | ||
267 | float displayDensity_Android(void); | ||
268 | #endif | ||
269 | |||
266 | static float displayScale_Window_(const iWindow *d) { | 270 | static float displayScale_Window_(const iWindow *d) { |
267 | /* The environment variable LAGRANGE_OVERRIDE_DPI can be used to override the automatic | 271 | /* The environment variable LAGRANGE_OVERRIDE_DPI can be used to override the automatic |
268 | display DPI detection. If not set, or is an empty string, ignore it. | 272 | display DPI detection. If not set, or is an empty string, ignore it. |
@@ -289,6 +293,8 @@ static float displayScale_Window_(const iWindow *d) { | |||
289 | #elif defined (iPlatformMsys) | 293 | #elif defined (iPlatformMsys) |
290 | iUnused(d); | 294 | iUnused(d); |
291 | return desktopDPI_Win32(); | 295 | return desktopDPI_Win32(); |
296 | #elif defined (iPlatformAndroidMobile) | ||
297 | return displayDensity_Android(); | ||
292 | #else | 298 | #else |
293 | if (isRunningUnderWindowSystem_App()) { | 299 | if (isRunningUnderWindowSystem_App()) { |
294 | float vdpi = 0.0f; | 300 | float vdpi = 0.0f; |
@@ -457,7 +463,7 @@ void init_Window(iWindow *d, enum iWindowType type, iRect rect, uint32_t flags) | |||
457 | d->mouseGrab = NULL; | 463 | d->mouseGrab = NULL; |
458 | d->focus = NULL; | 464 | d->focus = NULL; |
459 | d->pendingCursor = NULL; | 465 | d->pendingCursor = NULL; |
460 | d->isExposed = iFalse; | 466 | d->isExposed = (deviceType_App() != desktop_AppDeviceType); |
461 | d->isMinimized = iFalse; | 467 | d->isMinimized = iFalse; |
462 | d->isInvalidated = iFalse; /* set when posting event, to avoid repeated events */ | 468 | d->isInvalidated = iFalse; /* set when posting event, to avoid repeated events */ |
463 | d->isMouseInside = iTrue; | 469 | d->isMouseInside = iTrue; |
@@ -541,6 +547,8 @@ void init_MainWindow(iMainWindow *d, iRect rect) { | |||
541 | SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal"); | 547 | SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal"); |
542 | flags |= SDL_WINDOW_METAL; | 548 | flags |= SDL_WINDOW_METAL; |
543 | d->base.isExposed = iTrue; | 549 | d->base.isExposed = iTrue; |
550 | #elif defined (iPlatformAndroidMobile) | ||
551 | d->base.isExposed = iTrue; | ||
544 | #else | 552 | #else |
545 | if (!forceSoftwareRender_App()) { | 553 | if (!forceSoftwareRender_App()) { |
546 | flags |= SDL_WINDOW_OPENGL; | 554 | flags |= SDL_WINDOW_OPENGL; |