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