=> e39721581f082a20f1ef3a6f81b83c5e489cf7c7
[1mdiff --git a/src/app.c b/src/app.c[m [1mindex eea3689f..3ee2345c 100644[m [1m--- a/src/app.c[m [1m+++ b/src/app.c[m [36m@@ -92,7 +92,10 @@[m [mstatic const char *defaultDataDir_App_ = "~/Library/Application Support";[m #define EMB_BIN "../resources.lgr"[m static const char *defaultDataDir_App_ = "~/AppData/Roaming/fi.skyjake.Lagrange";[m #endif[m [31m-#if defined (iPlatformLinux) || defined (iPlatformOther)[m [32m+[m[32m#if defined (iPlatformAndroidMobile)[m [32m+[m[32m#define EMB_BIN "resources.lgr" /* loaded from assets with SDL_rwops */[m [32m+[m[32mstatic const char *defaultDataDir_App_ = NULL; /* will ask SDL */[m [32m+[m[32m#elif defined (iPlatformLinux) || defined (iPlatformOther)[m #define EMB_BIN "../../share/lagrange/resources.lgr"[m #define EMB_BIN2 "../../../share/lagrange/resources.lgr"[m static const char *defaultDataDir_App_ = "~/.config/lagrange";[m [36m@@ -139,6 +142,9 @@[m [mstruct Impl_App {[m int autoReloadTimer;[m iPeriodic periodic;[m int warmupFrames; /* forced refresh just after resuming from background; FIXME: shouldn't be needed */[m [32m+[m[32m#if defined (iPlatformAndroidMobile)[m [32m+[m[32m float displayDensity;[m [32m+[m[32m#endif[m /* Preferences: */[m iBool commandEcho; /* --echo */[m iBool forceSoftwareRender; /* --sw */[m [36m@@ -307,7 +313,10 @@[m [mstatic const char *dataDir_App_(void) {[m return userDir;[m }[m #endif[m [31m- return defaultDataDir_App_;[m [32m+[m[32m if (defaultDataDir_App_) {[m [32m+[m[32m return defaultDataDir_App_;[m [32m+[m[32m }[m [32m+[m[32m return SDL_GetPrefPath("Jaakko Keränen", "fi.skyjake.lagrange");[m }[m [m static const char *downloadDir_App_(void) {[m [36m@@ -715,7 +724,7 @@[m [mstatic iBool hasCommandLineOpenableScheme_(const iRangecc uri) {[m }[m [m static void init_App_(iApp *d, int argc, char **argv) {[m [31m-#if defined (iPlatformLinux)[m [32m+[m[32m#if defined (iPlatformLinux) && !defined (iPlatformAndroid)[m d->isRunningUnderWindowSystem = !iCmpStr(SDL_GetCurrentVideoDriver(), "x11") ||[m !iCmpStr(SDL_GetCurrentVideoDriver(), "wayland");[m #else[m [36m@@ -763,6 +772,8 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m }[m }[m init_Lang();[m [32m+[m[32m iStringList *openCmds = new_StringList();[m [32m+[m[32m#if !defined (iPlatformAndroidMobile)[m /* Configure the valid command line options. */ {[m defineValues_CommandLine(&d->args, "close-tab", 0);[m defineValues_CommandLine(&d->args, "echo;E", 0);[m [36m@@ -777,7 +788,6 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m defineValues_CommandLine(&d->args, "sw", 0);[m defineValues_CommandLine(&d->args, "version;V", 0);[m }[m [31m- iStringList *openCmds = new_StringList();[m /* Handle command line options. */ {[m if (contains_CommandLine(&d->args, "help")) {[m puts(cstr_Block(&blobArghelp_Resources));[m [36m@@ -826,6 +836,7 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m }[m }[m }[m [32m+[m[32m#endif[m #if defined (LAGRANGE_ENABLE_IPC)[m /* Only one instance is allowed to run at a time; the runtime files (bookmarks, etc.)[m are not shareable. */ {[m [36m@@ -860,7 +871,7 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m /* Must scale by UI scaling factor. */[m mulfv_I2(&d->initialWindowRect.size, desktopDPI_Win32());[m #endif[m [31m-#if defined (iPlatformLinux)[m [32m+[m[32m#if defined (iPlatformLinux) && !defined (iPlatformAndroid)[m /* Scale by the primary (?) monitor DPI. */[m if (isRunningUnderWindowSystem_App()) {[m float vdpi;[m [36m@@ -1325,6 +1336,15 @@[m [mvoid processEvents_App(enum iAppEventMode eventMode) {[m }[m ev.key.keysym.mod = mapMods_Keys(ev.key.keysym.mod & ~KMOD_CAPS);[m }[m [32m+[m[32m#if defined (iPlatformAndroidMobile)[m [32m+[m[32m /* Ignore all mouse events; just use touch. */[m [32m+[m[32m if (ev.type == SDL_MOUSEBUTTONDOWN ||[m [32m+[m[32m ev.type == SDL_MOUSEBUTTONUP ||[m [32m+[m[32m ev.type == SDL_MOUSEMOTION ||[m [32m+[m[32m ev.type == SDL_MOUSEWHEEL) {[m [32m+[m[32m continue;[m [32m+[m[32m }[m [32m+[m[32m#endif[m /* Scroll events may be per-pixel or mouse wheel steps. */[m if (ev.type == SDL_MOUSEWHEEL) {[m #if defined (iPlatformMsys)[m [36m@@ -1773,6 +1793,8 @@[m [menum iAppDeviceType deviceType_App(void) {[m return tablet_AppDeviceType;[m #elif defined (iPlatformAppleMobile)[m return isPhone_iOS() ? phone_AppDeviceType : tablet_AppDeviceType;[m [32m+[m[32m#elif defined (iPlatformAndroidMobile)[m [32m+[m[32m return phone_AppDeviceType; /* TODO: Java side could tell us via cmdline if this is a tablet. */[m #else[m return desktop_AppDeviceType;[m #endif[m [36m@@ -3408,3 +3430,10 @@[m [mvoid closePopups_App(void) {[m }[m }[m }[m [32m+[m [32m+[m[32m#if defined (iPlatformAndroidMobile)[m [32m+[m[32mfloat displayDensity_Android(void) {[m [32m+[m[32m iApp *d = &app_;[m [32m+[m[32m return toFloat_String(at_CommandLine(&d->args, 1));[m [32m+[m[32m}[m [32m+[m[32m#endif[m [1mdiff --git a/src/resources.c b/src/resources.c[m [1mindex bb601cca..e3d92946 100644[m [1m--- a/src/resources.c[m [1m+++ b/src/resources.c[m [36m@@ -26,7 +26,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m #include[m [m static iArchive *archive_;[m [31m- [m [32m+[m iBlock blobAbout_Resources;[m iBlock blobHelp_Resources;[m iBlock blobLagrange_Resources;[m [36m@@ -101,7 +101,23 @@[m [mstatic struct {[m [m iBool init_Resources(const char *path) {[m archive_ = new_Archive();[m [31m- if (openFile_Archive(archive_, collectNewCStr_String(path))) {[m [32m+[m[32m iBool ok = iFalse;[m [32m+[m[32m#if defined (iPlatformAndroidMobile)[m [32m+[m[32m /* Resources are bundled as assets so they cannot be loaded as a regular file.[m [32m+[m[32m Fortunately, SDL implements a file wrapper. */[m [32m+[m[32m SDL_RWops *io = SDL_RWFromFile(path, "rb");[m [32m+[m[32m if (io) {[m [32m+[m[32m iBlock buf;[m [32m+[m[32m init_Block(&buf, (size_t) SDL_RWsize(io));[m [32m+[m[32m SDL_RWread(io, data_Block(&buf), size_Block(&buf), 1);[m [32m+[m[32m SDL_RWclose(io);[m [32m+[m[32m ok = openData_Archive(archive_, &buf);[m [32m+[m[32m deinit_Block(&buf);[m [32m+[m[32m }[m [32m+[m[32m#else[m [32m+[m[32m ok = openFile_Archive(archive_, collectNewCStr_String(path));[m [32m+[m[32m#endif[m [32m+[m[32m if (ok) {[m iVersion appVer;[m init_Version(&appVer, range_CStr(LAGRANGE_APP_VERSION));[m iVersion resVer;[m [1mdiff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c[m [1mindex e93fb586..b20ae672 100644[m [1m--- a/src/ui/documentwidget.c[m [1m+++ b/src/ui/documentwidget.c[m [36m@@ -225,7 +225,7 @@[m [menum iDocumentWidgetFlag {[m animationPlaceholder_DocumentWidgetFlag = iBit(16), /* avoid slow operations */[m invalidationPending_DocumentWidgetFlag = iBit(17), /* invalidate as soon as convenient */[m leftWheelSwipe_DocumentWidgetFlag = iBit(18), /* swipe state flags are used on desktop */[m [31m- rightWheelSwipe_DocumentWidgetFlag = iBit(19), [m [32m+[m[32m rightWheelSwipe_DocumentWidgetFlag = iBit(19),[m eitherWheelSwipe_DocumentWidgetFlag = leftWheelSwipe_DocumentWidgetFlag |[m rightWheelSwipe_DocumentWidgetFlag,[m };[m [36m@@ -242,8 +242,8 @@[m [menum iWheelSwipeState {[m [m /* TODO: DocumentView is supposed to be useful on its own; move to a separate source file. */[m iDeclareType(DocumentView)[m [31m- [m [31m-struct Impl_DocumentView { [m [32m+[m [32m+[m[32mstruct Impl_DocumentView {[m iDocumentWidget *owner; /* TODO: Convert to an abstract provider of metrics? */[m iGmDocument * doc;[m int pageMargin;[m [36m@@ -253,7 +253,7 @@[m [mstruct Impl_DocumentView {[m iGmRunRange visibleRuns;[m iPtrArray visibleLinks;[m iPtrArray visiblePre;[m [31m- iPtrArray visibleMedia; /* currently playing audio / ongoing downloads */ [m [32m+[m[32m iPtrArray visibleMedia; /* currently playing audio / ongoing downloads */[m iPtrArray visibleWideRuns; /* scrollable blocks; TODO: merge into `visiblePre` */[m const iGmRun * hoverPre; /* for clicking */[m const iGmRun * hoverAltPre; /* for drawing alt text */[m [36m@@ -263,7 +263,7 @@[m [mstruct Impl_DocumentView {[m uint16_t animWideRunId;[m iGmRunRange animWideRunRange;[m iDrawBufs * drawBufs; /* dynamic state for drawing */[m [31m- iVisBuf * visBuf; [m [32m+[m[32m iVisBuf * visBuf;[m iVisBufMeta * visBufMeta;[m iGmRunRange renderRuns;[m iPtrSet * invalidRuns;[m [36m@@ -272,7 +272,7 @@[m [mstruct Impl_DocumentView {[m struct Impl_DocumentWidget {[m iWidget widget;[m int flags; /* internal behavior, see enum iDocumentWidgetFlag */[m [31m- [m [32m+[m /* User interface: */[m enum iDocumentLinkOrdinalMode ordinalMode;[m size_t ordinalBase;[m [36m@@ -293,7 +293,7 @@[m [mstruct Impl_DocumentWidget {[m enum iWheelSwipeState wheelSwipeState;[m iString pendingGotoHeading;[m iString linePrecedingLink;[m [31m- [m [32m+[m /* Network request: */[m enum iRequestState state;[m iGmRequest * request;[m [36m@@ -304,7 +304,7 @@[m [mstruct Impl_DocumentWidget {[m iString * certSubject;[m int redirectCount;[m iObjectList * media; /* inline media requests */[m [31m- [m [32m+[m /* Document: */[m iPersistentDocumentState mod;[m iString * titleUser;[m [36m@@ -316,12 +316,12 @@[m [mstruct Impl_DocumentWidget {[m iGempub * sourceGempub; /* NULL unless the page is Gempub content */[m iBanner * banner;[m float initNormScrollY;[m [31m- [m [32m+[m /* Rendering: */[m iDocumentView view;[m iLinkInfo * linkInfo;[m [31m- [m [31m- /* Widget structure: */ [m [32m+[m [32m+[m[32m /* Widget structure: */[m iScrollWidget *scroll;[m iWidget * footerButtons;[m iWidget * menu;[m [36m@@ -332,7 +332,7 @@[m [mstruct Impl_DocumentWidget {[m };[m [m iDefineObjectConstruction(DocumentWidget)[m [31m- [m [32m+[m /* Sorted by proximity to F and J. */[m static const int homeRowKeys_[] = {[m 'f', 'd', 's', 'a',[m [36m@@ -344,7 +344,7 @@[m [mstatic const int homeRowKeys_[] = {[m 'g', 'h',[m 'b',[m 't', 'y',[m [31m-}; [m [32m+[m[32m};[m static int docEnum_ = 0;[m [m static void animate_DocumentWidget_ (void *ticker);[m [36m@@ -909,7 +909,7 @@[m [mstatic void updateTimestampBuf_DocumentView_(const iDocumentView *d) {[m [m static void invalidate_DocumentView_(iDocumentView *d) {[m invalidate_VisBuf(d->visBuf);[m [31m- clear_PtrSet(d->invalidRuns); [m [32m+[m[32m clear_PtrSet(d->invalidRuns);[m }[m [m static void documentRunsInvalidated_DocumentView_(iDocumentView *d) {[m [36m@@ -928,11 +928,11 @@[m [mstatic void resetScroll_DocumentView_(iDocumentView *d) {[m }[m [m static void updateWidth_DocumentView_(iDocumentView *d) {[m [31m- updateWidth_GmDocument(d->doc, documentWidth_DocumentView_(d), width_Widget(d->owner)); [m [32m+[m[32m updateWidth_GmDocument(d->doc, documentWidth_DocumentView_(d), width_Widget(d->owner));[m }[m [m static void updateWidthAndRedoLayout_DocumentView_(iDocumentView *d) {[m [31m- setWidth_GmDocument(d->doc, documentWidth_DocumentView_(d), width_Widget(d->owner)); [m [32m+[m[32m setWidth_GmDocument(d->doc, documentWidth_DocumentView_(d), width_Widget(d->owner));[m }[m [m static void clampScroll_DocumentView_(iDocumentView *d) {[m [36m@@ -1025,7 +1025,7 @@[m [mstatic iRangecc sourceLoc_DocumentView_(const iDocumentView *d, iInt2 pos) {[m }[m [m iDeclareType(MiddleRunParams)[m [31m- [m [32m+[m struct Impl_MiddleRunParams {[m int midY;[m const iGmRun *closest;[m [36m@@ -1126,7 +1126,7 @@[m [mstatic iRect runRect_DocumentView_(const iDocumentView *d, const iGmRun *run) {[m }[m [m iDeclareType(DrawContext)[m [31m- [m [32m+[m struct Impl_DrawContext {[m const iDocumentView *view;[m iRect widgetBounds;[m [36m@@ -1260,7 +1260,7 @@[m [mstatic void drawRun_DrawContext_(void *context, const iGmRun *run) {[m isInlineImageCaption = iFalse;[m }[m #endif[m [31m- /* While this is consistent, it's a bit excessive to indicate that an inlined image [m [32m+[m[32m /* While this is consistent, it's a bit excessive to indicate that an inlined image[m is open: the image itself is the indication. */[m const iBool isInlineImageCaption = iFalse;[m if (run->linkId && (linkFlags & isOpen_GmLinkFlag || isInlineImageCaption)) {[m [36m@@ -1285,7 +1285,7 @@[m [mstatic void drawRun_DrawContext_(void *context, const iGmRun *run) {[m }[m fillRect_Paint(&d->paint, wideRect, bg);[m }[m [31m- else { [m [32m+[m[32m else {[m /* Normal background for other runs. There are cases when runs get drawn multiple times,[m e.g., at the buffer boundary, and there are slightly overlapping characters in[m monospace blocks. Clearing the background here ensures a cleaner visual appearance[m [36m@@ -2095,7 +2095,7 @@[m [mstatic void invalidate_DocumentWidget_(iDocumentWidget *d) {[m }[m [m static iRangecc siteText_DocumentWidget_(const iDocumentWidget *d) {[m [31m- return isEmpty_String(d->titleUser) ? urlHost_String(d->mod.url) [m [32m+[m[32m return isEmpty_String(d->titleUser) ? urlHost_String(d->mod.url)[m : range_String(d->titleUser);[m }[m [m [36m@@ -2161,7 +2161,7 @@[m [mstatic void updateBanner_DocumentWidget_(iDocumentWidget *d) {[m static void updateTheme_DocumentWidget_(iDocumentWidget *d) {[m if (document_App() != d || category_GmStatusCode(d->sourceStatus) == categoryInput_GmStatusCode) {[m return;[m [31m- } [m [32m+[m[32m }[m d->view.drawBufs->flags |= updateTimestampBuf_DrawBufsFlag;[m updateBanner_DocumentWidget_(d);[m }[m [36m@@ -2620,7 +2620,7 @@[m [mstatic void updateDocument_DocumentWidget_(iDocumentWidget *d,[m appendFormat_String(&str,[m cstr_Lang("doc.archive"),[m cstr_Rangecc(baseName_Path(d->mod.url)));[m [31m- appendCStr_String(&str, "\n"); [m [32m+[m[32m appendCStr_String(&str, "\n");[m }[m appendCStr_String(&str, "\n");[m iString *localPath = localFilePathFromUrl_String(d->mod.url);[m [36m@@ -2768,7 +2768,7 @@[m [mstatic void updateTrust_DocumentWidget_(iDocumentWidget *d, const iGmResponse *r[m }[m else if (~d->certFlags & timeVerified_GmCertFlag) {[m updateTextCStr_LabelWidget(lock, isDarkMode ? orange_ColorEscape warning_Icon[m [31m- : black_ColorEscape warning_Icon); [m [32m+[m[32m : black_ColorEscape warning_Icon);[m }[m else {[m updateTextCStr_LabelWidget(lock, green_ColorEscape closedLock_Icon);[m [36m@@ -3067,7 +3067,7 @@[m [mstatic void checkResponse_DocumentWidget_(iDocumentWidget *d) {[m it is only displayed as an input dialog. */[m visitUrl_Visited(visited_App(), d->mod.url, transient_VisitedUrlFlag);[m iUrl parts;[m [31m- init_Url(&parts, d->mod.url); [m [32m+[m[32m init_Url(&parts, d->mod.url);[m iWidget *dlg = makeValueInput_Widget([m as_Widget(d),[m NULL,[m [36m@@ -3132,7 +3132,7 @@[m [mstatic void checkResponse_DocumentWidget_(iDocumentWidget *d) {[m setFont_LabelWidget(menu, font_LabelWidget((iLabelWidget *) lastChild_Widget(buttons)));[m setTextColor_LabelWidget(menu, uiTextAction_ColorId);[m }[m [31m- } [m [32m+[m[32m }[m setValidator_InputWidget(findChild_Widget(dlg, "input"), inputQueryValidator_, d);[m setSensitiveContent_InputWidget(findChild_Widget(dlg, "input"),[m statusCode == sensitiveInput_GmStatusCode);[m [36m@@ -3491,7 +3491,7 @@[m [mstatic iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {[m }[m /* The temporary "swipein" will display the previous page until the finger is lifted. */[m iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein");[m [31m- if (!swipeIn) { [m [32m+[m[32m if (!swipeIn) {[m swipeIn = new_DocumentWidget();[m swipeIn->flags |= animationPlaceholder_DocumentWidgetFlag;[m setId_Widget(as_Widget(swipeIn), "swipein");[m [36m@@ -3531,7 +3531,7 @@[m [mstatic iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {[m iWidget *swipeParent = swipeParent_DocumentWidget_(d);[m if (findChild_Widget(swipeParent, "swipeout")) {[m return iTrue; /* too fast, previous animation hasn't finished */[m [31m- } [m [32m+[m[32m }[m /* Setup the drag. `d` will be moving with the finger. */[m animSpan = 0;[m postCommand_Widget(d, "navigate.forward");[m [36m@@ -3694,7 +3694,7 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m else if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed") ||[m equal_Command(cmd, "keyroot.changed")) {[m if (equal_Command(cmd, "font.changed")) {[m [31m- invalidateCachedLayout_History(d->mod.history); [m [32m+[m[32m invalidateCachedLayout_History(d->mod.history);[m }[m /* Alt/Option key may be involved in window size changes. */[m setLinkNumberMode_DocumentWidget_(d, iFalse);[m [36m@@ -4056,7 +4056,7 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m }[m return wasHandled;[m }[m [31m- else if (equal_Command(cmd, "document.upload") && d == document_App()) { [m [32m+[m[32m else if (equal_Command(cmd, "document.upload") && d == document_App()) {[m if (findChild_Widget(root_Widget(w), "upload")) {[m return iTrue; /* already open */[m }[m [36m@@ -4124,7 +4124,7 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m if (equalCase_Rangecc(urlScheme_String(d->mod.url), "titan")) {[m /* Reopen so the Upload dialog gets shown. */[m postCommandf_App("open url:%s", cstr_String(d->mod.url));[m [31m- return iTrue; [m [32m+[m[32m return iTrue;[m }[m fetch_DocumentWidget_(d);[m return iTrue;[m [36m@@ -4416,7 +4416,7 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m if (argLabel_Command(cmd, "ttf")) {[m iAssert(!cmp_String(&d->sourceMime, "font/ttf"));[m installFontFile_Fonts(collect_String(suffix_Command(cmd, "name")), &d->sourceContent);[m [31m- postCommand_App("open url:about:fonts"); [m [32m+[m[32m postCommand_App("open url:about:fonts");[m }[m else {[m const iString *id = idFromUrl_FontPack(d->mod.url);[m [36m@@ -5435,7 +5435,7 @@[m [mvoid init_DocumentWidget(iDocumentWidget *d) {[m init_Widget(w);[m setId_Widget(w, format_CStr("document%03d", ++docEnum_));[m setFlags_Widget(w, hover_WidgetFlag | noBackground_WidgetFlag, iTrue);[m [31m-#if defined (iPlatformAppleDesktop) [m [32m+[m[32m#if defined (iPlatformAppleDesktop)[m iBool enableSwipeNavigation = iTrue; /* swipes on the trackpad */[m #else[m iBool enableSwipeNavigation = (deviceType_App() != desktop_AppDeviceType);[m [36m@@ -5671,7 +5671,7 @@[m [miBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) {[m void takeRequest_DocumentWidget(iDocumentWidget *d, iGmRequest *finishedRequest) {[m cancelRequest_DocumentWidget_(d, iFalse /* don't post anything */);[m const iString *url = url_GmRequest(finishedRequest);[m [31m- [m [32m+[m add_History(d->mod.history, url);[m setUrl_DocumentWidget_(d, url);[m d->state = fetching_RequestState;[m [1mdiff --git a/src/ui/touch.c b/src/ui/touch.c[m [1mindex 0749bc7c..3d318dfb 100644[m [1m--- a/src/ui/touch.c[m [1m+++ b/src/ui/touch.c[m [36m@@ -42,7 +42,11 @@[m [miDeclareType(TouchState)[m [m static const uint32_t longPressSpanMs_ = 500;[m static const uint32_t shortPressSpanMs_ = 250;[m [32m+[m[32m#if defined (iPlatformAndroidMobile)[m [32m+[m[32mstatic const int tapRadiusPt_ = 30; /* inaccurate sensors? */[m [32m+[m[32m#else[m static const int tapRadiusPt_ = 10;[m [32m+[m[32m#endif[m [m enum iTouchEdge {[m none_TouchEdge,[m [1mdiff --git a/src/ui/window.c b/src/ui/window.c[m [1mindex 0e13a57f..7f3371c8 100644[m [1m--- a/src/ui/window.c[m [1m+++ b/src/ui/window.c[m [36m@@ -263,6 +263,10 @@[m [mstatic float pixelRatio_Window_(const iWindow *d) {[m # define baseDPI_Window 96.0f[m #endif[m [m [32m+[m[32m#if defined (iPlatformAndroidMobile)[m [32m+[m[32mfloat displayDensity_Android(void);[m [32m+[m[32m#endif[m [32m+[m static float displayScale_Window_(const iWindow *d) {[m /* The environment variable LAGRANGE_OVERRIDE_DPI can be used to override the automatic[m display DPI detection. If not set, or is an empty string, ignore it.[m [36m@@ -289,6 +293,8 @@[m [mstatic float displayScale_Window_(const iWindow *d) {[m #elif defined (iPlatformMsys)[m iUnused(d);[m return desktopDPI_Win32();[m [32m+[m[32m#elif defined (iPlatformAndroidMobile)[m [32m+[m[32m return displayDensity_Android();[m #else[m if (isRunningUnderWindowSystem_App()) {[m float vdpi = 0.0f;[m [36m@@ -457,7 +463,7 @@[m [mvoid init_Window(iWindow *d, enum iWindowType type, iRect rect, uint32_t flags)[m d->mouseGrab = NULL;[m d->focus = NULL;[m d->pendingCursor = NULL;[m [31m- d->isExposed = iFalse;[m [32m+[m[32m d->isExposed = (deviceType_App() != desktop_AppDeviceType);[m d->isMinimized = iFalse;[m d->isInvalidated = iFalse; /* set when posting event, to avoid repeated events */[m d->isMouseInside = iTrue;[m [36m@@ -541,6 +547,8 @@[m [mvoid init_MainWindow(iMainWindow *d, iRect rect) {[m SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal");[m flags |= SDL_WINDOW_METAL;[m d->base.isExposed = iTrue;[m [32m+[m[32m#elif defined (iPlatformAndroidMobile)[m [32m+[m[32m d->base.isExposed = iTrue;[m #else[m if (!forceSoftwareRender_App()) {[m flags |= SDL_WINDOW_OPENGL;[m
text/gemini; charset=utf-8
This content has been proxied by September (3851b).