diff options
Diffstat (limited to 'src/app.c')
-rw-r--r-- | src/app.c | 156 |
1 files changed, 147 insertions, 9 deletions
@@ -59,6 +59,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
59 | #include <stdarg.h> | 59 | #include <stdarg.h> |
60 | #include <errno.h> | 60 | #include <errno.h> |
61 | 61 | ||
62 | //#define LAGRANGE_ENABLE_MOUSE_TOUCH_EMULATION 1 | ||
63 | |||
62 | #if defined (iPlatformAppleDesktop) | 64 | #if defined (iPlatformAppleDesktop) |
63 | # include "macos.h" | 65 | # include "macos.h" |
64 | #endif | 66 | #endif |
@@ -210,6 +212,7 @@ static iString *serializePrefs_App_(const iApp *d) { | |||
210 | appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling); | 212 | appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling); |
211 | appendFormat_String(str, "imageloadscroll arg:%d\n", d->prefs.loadImageInsteadOfScrolling); | 213 | appendFormat_String(str, "imageloadscroll arg:%d\n", d->prefs.loadImageInsteadOfScrolling); |
212 | appendFormat_String(str, "cachesize.set arg:%d\n", d->prefs.maxCacheSize); | 214 | appendFormat_String(str, "cachesize.set arg:%d\n", d->prefs.maxCacheSize); |
215 | appendFormat_String(str, "memorysize.set arg:%d\n", d->prefs.maxMemorySize); | ||
213 | appendFormat_String(str, "decodeurls arg:%d\n", d->prefs.decodeUserVisibleURLs); | 216 | appendFormat_String(str, "decodeurls arg:%d\n", d->prefs.decodeUserVisibleURLs); |
214 | appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); | 217 | appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); |
215 | /* TODO: Set up an array of booleans in Prefs and do these in a loop. */ | 218 | /* TODO: Set up an array of booleans in Prefs and do these in a loop. */ |
@@ -760,6 +763,7 @@ static void init_App_(iApp *d, int argc, char **argv) { | |||
760 | setupApplication_iOS(); | 763 | setupApplication_iOS(); |
761 | #endif | 764 | #endif |
762 | init_Keys(); | 765 | init_Keys(); |
766 | loadPalette_Color(dataDir_App_()); | ||
763 | setThemePalette_Color(d->prefs.theme); /* default UI colors */ | 767 | setThemePalette_Color(d->prefs.theme); /* default UI colors */ |
764 | loadPrefs_App_(d); | 768 | loadPrefs_App_(d); |
765 | load_Keys(dataDir_App_()); | 769 | load_Keys(dataDir_App_()); |
@@ -918,13 +922,25 @@ const iString *debugInfo_App(void) { | |||
918 | extern char **environ; /* The environment variables. */ | 922 | extern char **environ; /* The environment variables. */ |
919 | iApp *d = &app_; | 923 | iApp *d = &app_; |
920 | iString *msg = collectNew_String(); | 924 | iString *msg = collectNew_String(); |
925 | iObjectList *docs = iClob(listDocuments_App(NULL)); | ||
921 | format_String(msg, "# Debug information\n"); | 926 | format_String(msg, "# Debug information\n"); |
927 | appendFormat_String(msg, "## Memory usage\n"); { | ||
928 | iMemInfo total = { 0, 0 }; | ||
929 | iForEach(ObjectList, i, docs) { | ||
930 | iDocumentWidget *doc = i.object; | ||
931 | iMemInfo usage = memoryUsage_History(history_DocumentWidget(doc)); | ||
932 | total.cacheSize += usage.cacheSize; | ||
933 | total.memorySize += usage.memorySize; | ||
934 | } | ||
935 | appendFormat_String(msg, "Total cache: %.3f MB\n", total.cacheSize / 1.0e6f); | ||
936 | appendFormat_String(msg, "Total memory: %.3f MB\n", total.memorySize / 1.0e6f); | ||
937 | } | ||
922 | appendFormat_String(msg, "## Documents\n"); | 938 | appendFormat_String(msg, "## Documents\n"); |
923 | iForEach(ObjectList, k, iClob(listDocuments_App(NULL))) { | 939 | iForEach(ObjectList, k, docs) { |
924 | iDocumentWidget *doc = k.object; | 940 | iDocumentWidget *doc = k.object; |
925 | appendFormat_String(msg, "### Tab %d.%zu: %s\n", | 941 | appendFormat_String(msg, "### Tab %d.%zu: %s\n", |
926 | constAs_Widget(doc)->root == get_Window()->roots[0] ? 0 : 1, | 942 | constAs_Widget(doc)->root == get_Window()->roots[0] ? 1 : 2, |
927 | childIndex_Widget(constAs_Widget(doc)->parent, k.object), | 943 | childIndex_Widget(constAs_Widget(doc)->parent, k.object) + 1, |
928 | cstr_String(bookmarkTitle_DocumentWidget(doc))); | 944 | cstr_String(bookmarkTitle_DocumentWidget(doc))); |
929 | append_String(msg, collect_String(debugInfo_History(history_DocumentWidget(doc)))); | 945 | append_String(msg, collect_String(debugInfo_History(history_DocumentWidget(doc)))); |
930 | } | 946 | } |
@@ -979,6 +995,33 @@ void trimCache_App(void) { | |||
979 | iRelease(docs); | 995 | iRelease(docs); |
980 | } | 996 | } |
981 | 997 | ||
998 | void trimMemory_App(void) { | ||
999 | iApp *d = &app_; | ||
1000 | size_t memorySize = 0; | ||
1001 | const size_t limit = d->prefs.maxMemorySize * 1000000; | ||
1002 | iObjectList *docs = listDocuments_App(NULL); | ||
1003 | iForEach(ObjectList, i, docs) { | ||
1004 | memorySize += memorySize_History(history_DocumentWidget(i.object)); | ||
1005 | } | ||
1006 | init_ObjectListIterator(&i, docs); | ||
1007 | iBool wasPruned = iFalse; | ||
1008 | while (memorySize > limit) { | ||
1009 | iDocumentWidget *doc = i.object; | ||
1010 | const size_t pruned = pruneLeastImportantMemory_History(history_DocumentWidget(doc)); | ||
1011 | if (pruned) { | ||
1012 | memorySize -= pruned; | ||
1013 | wasPruned = iTrue; | ||
1014 | } | ||
1015 | next_ObjectListIterator(&i); | ||
1016 | if (!i.value) { | ||
1017 | if (!wasPruned) break; | ||
1018 | wasPruned = iFalse; | ||
1019 | init_ObjectListIterator(&i, docs); | ||
1020 | } | ||
1021 | } | ||
1022 | iRelease(docs); | ||
1023 | } | ||
1024 | |||
982 | iLocalDef iBool isWaitingAllowed_App_(iApp *d) { | 1025 | iLocalDef iBool isWaitingAllowed_App_(iApp *d) { |
983 | if (!isEmpty_Periodic(&d->periodic)) { | 1026 | if (!isEmpty_Periodic(&d->periodic)) { |
984 | return iFalse; | 1027 | return iFalse; |
@@ -1049,6 +1092,13 @@ void processEvents_App(enum iAppEventMode eventMode) { | |||
1049 | postRefresh_App(); | 1092 | postRefresh_App(); |
1050 | break; | 1093 | break; |
1051 | case SDL_APP_WILLENTERBACKGROUND: | 1094 | case SDL_APP_WILLENTERBACKGROUND: |
1095 | #if defined (iPlatformAppleMobile) | ||
1096 | updateNowPlayingInfo_iOS(); | ||
1097 | #endif | ||
1098 | setFreezeDraw_Window(d->window, iTrue); | ||
1099 | savePrefs_App_(d); | ||
1100 | saveState_App_(d); | ||
1101 | break; | ||
1052 | case SDL_APP_TERMINATING: | 1102 | case SDL_APP_TERMINATING: |
1053 | setFreezeDraw_Window(d->window, iTrue); | 1103 | setFreezeDraw_Window(d->window, iTrue); |
1054 | savePrefs_App_(d); | 1104 | savePrefs_App_(d); |
@@ -1149,6 +1199,45 @@ void processEvents_App(enum iAppEventMode eventMode) { | |||
1149 | ev.wheel.x = -ev.wheel.x; | 1199 | ev.wheel.x = -ev.wheel.x; |
1150 | #endif | 1200 | #endif |
1151 | } | 1201 | } |
1202 | #if defined (LAGRANGE_ENABLE_MOUSE_TOUCH_EMULATION) | ||
1203 | /* Convert mouse events to finger events to test the touch handling. */ { | ||
1204 | static float xPrev = 0.0f; | ||
1205 | static float yPrev = 0.0f; | ||
1206 | if (ev.type == SDL_MOUSEBUTTONDOWN || ev.type == SDL_MOUSEBUTTONUP) { | ||
1207 | const float xf = (d->window->pixelRatio * ev.button.x) / (float) d->window->size.x; | ||
1208 | const float yf = (d->window->pixelRatio * ev.button.y) / (float) d->window->size.y; | ||
1209 | ev.type = (ev.type == SDL_MOUSEBUTTONDOWN ? SDL_FINGERDOWN : SDL_FINGERUP); | ||
1210 | ev.tfinger.x = xf; | ||
1211 | ev.tfinger.y = yf; | ||
1212 | ev.tfinger.dx = xf - xPrev; | ||
1213 | ev.tfinger.dy = yf - yPrev; | ||
1214 | xPrev = xf; | ||
1215 | yPrev = yf; | ||
1216 | ev.tfinger.fingerId = 0x1234; | ||
1217 | ev.tfinger.pressure = 1.0f; | ||
1218 | ev.tfinger.timestamp = SDL_GetTicks(); | ||
1219 | ev.tfinger.touchId = SDL_TOUCH_MOUSEID; | ||
1220 | } | ||
1221 | else if (ev.type == SDL_MOUSEMOTION) { | ||
1222 | if (~ev.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT)) { | ||
1223 | continue; /* only when pressing a button */ | ||
1224 | } | ||
1225 | const float xf = (d->window->pixelRatio * ev.motion.x) / (float) d->window->size.x; | ||
1226 | const float yf = (d->window->pixelRatio * ev.motion.y) / (float) d->window->size.y; | ||
1227 | ev.type = SDL_FINGERMOTION; | ||
1228 | ev.tfinger.x = xf; | ||
1229 | ev.tfinger.y = yf; | ||
1230 | ev.tfinger.dx = xf - xPrev; | ||
1231 | ev.tfinger.dy = yf - yPrev; | ||
1232 | xPrev = xf; | ||
1233 | yPrev = yf; | ||
1234 | ev.tfinger.fingerId = 0x1234; | ||
1235 | ev.tfinger.pressure = 1.0f; | ||
1236 | ev.tfinger.timestamp = SDL_GetTicks(); | ||
1237 | ev.tfinger.touchId = SDL_TOUCH_MOUSEID; | ||
1238 | } | ||
1239 | } | ||
1240 | #endif | ||
1152 | iBool wasUsed = processEvent_Window(d->window, &ev); | 1241 | iBool wasUsed = processEvent_Window(d->window, &ev); |
1153 | if (!wasUsed) { | 1242 | if (!wasUsed) { |
1154 | /* There may be a key bindings for this. */ | 1243 | /* There may be a key bindings for this. */ |
@@ -1565,7 +1654,9 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) { | |||
1565 | postCommandf_App("searchurl address:%s", | 1654 | postCommandf_App("searchurl address:%s", |
1566 | cstrText_InputWidget(findChild_Widget(d, "prefs.searchurl"))); | 1655 | cstrText_InputWidget(findChild_Widget(d, "prefs.searchurl"))); |
1567 | postCommandf_App("cachesize.set arg:%d", | 1656 | postCommandf_App("cachesize.set arg:%d", |
1568 | toInt_String(text_InputWidget(findChild_Widget(d, "prefs.cachesize")))); | 1657 | toInt_String(text_InputWidget(findChild_Widget(d, "prefs.cachesize")))); |
1658 | postCommandf_App("memorysize.set arg:%d", | ||
1659 | toInt_String(text_InputWidget(findChild_Widget(d, "prefs.memorysize")))); | ||
1569 | postCommandf_App("ca.file path:%s", | 1660 | postCommandf_App("ca.file path:%s", |
1570 | cstrText_InputWidget(findChild_Widget(d, "prefs.ca.file"))); | 1661 | cstrText_InputWidget(findChild_Widget(d, "prefs.ca.file"))); |
1571 | postCommandf_App("ca.path path:%s", | 1662 | postCommandf_App("ca.path path:%s", |
@@ -1978,7 +2069,7 @@ iBool handleCommand_App(const char *cmd) { | |||
1978 | else if (equal_Command(cmd, "hidetoolbarscroll")) { | 2069 | else if (equal_Command(cmd, "hidetoolbarscroll")) { |
1979 | d->prefs.hideToolbarOnScroll = arg_Command(cmd); | 2070 | d->prefs.hideToolbarOnScroll = arg_Command(cmd); |
1980 | if (!d->prefs.hideToolbarOnScroll) { | 2071 | if (!d->prefs.hideToolbarOnScroll) { |
1981 | showToolbars_Root(get_Root(), iTrue); | 2072 | showToolbar_Root(get_Root(), iTrue); |
1982 | } | 2073 | } |
1983 | return iTrue; | 2074 | return iTrue; |
1984 | } | 2075 | } |
@@ -2127,6 +2218,13 @@ iBool handleCommand_App(const char *cmd) { | |||
2127 | } | 2218 | } |
2128 | return iTrue; | 2219 | return iTrue; |
2129 | } | 2220 | } |
2221 | else if (equal_Command(cmd, "memorysize.set")) { | ||
2222 | d->prefs.maxMemorySize = arg_Command(cmd); | ||
2223 | if (d->prefs.maxMemorySize <= 0) { | ||
2224 | d->prefs.maxMemorySize = 0; | ||
2225 | } | ||
2226 | return iTrue; | ||
2227 | } | ||
2130 | else if (equal_Command(cmd, "searchurl")) { | 2228 | else if (equal_Command(cmd, "searchurl")) { |
2131 | iString *url = &d->prefs.searchUrl; | 2229 | iString *url = &d->prefs.searchUrl; |
2132 | setCStr_String(url, suffixPtr_Command(cmd, "address")); | 2230 | setCStr_String(url, suffixPtr_Command(cmd, "address")); |
@@ -2188,7 +2286,8 @@ iBool handleCommand_App(const char *cmd) { | |||
2188 | } | 2286 | } |
2189 | else if (equal_Command(cmd, "open")) { | 2287 | else if (equal_Command(cmd, "open")) { |
2190 | iString *url = collectNewCStr_String(suffixPtr_Command(cmd, "url")); | 2288 | iString *url = collectNewCStr_String(suffixPtr_Command(cmd, "url")); |
2191 | const iBool noProxy = argLabel_Command(cmd, "noproxy"); | 2289 | const iBool noProxy = argLabel_Command(cmd, "noproxy") != 0; |
2290 | const iBool fromSidebar = argLabel_Command(cmd, "fromsidebar") != 0; | ||
2192 | iUrl parts; | 2291 | iUrl parts; |
2193 | init_Url(&parts, url); | 2292 | init_Url(&parts, url); |
2194 | if (argLabel_Command(cmd, "default") || equalCase_Rangecc(parts.scheme, "mailto") || | 2293 | if (argLabel_Command(cmd, "default") || equalCase_Rangecc(parts.scheme, "mailto") || |
@@ -2239,7 +2338,9 @@ iBool handleCommand_App(const char *cmd) { | |||
2239 | else { | 2338 | else { |
2240 | urlEncodePath_String(url); | 2339 | urlEncodePath_String(url); |
2241 | } | 2340 | } |
2242 | setUrlFromCache_DocumentWidget(doc, url, isHistory); | 2341 | setUrlFlags_DocumentWidget(doc, url, |
2342 | (isHistory ? useCachedContentIfAvailable_DocumentWidgetSetUrlFlag : 0) | | ||
2343 | (fromSidebar ? openedFromSidebar_DocumentWidgetSetUrlFlag : 0)); | ||
2243 | /* Optionally, jump to a text in the document. This will only work if the document | 2344 | /* Optionally, jump to a text in the document. This will only work if the document |
2244 | is already available, e.g., it's from "about:" or restored from cache. */ | 2345 | is already available, e.g., it's from "about:" or restored from cache. */ |
2245 | const iRangecc gotoHeading = range_Command(cmd, "gotoheading"); | 2346 | const iRangecc gotoHeading = range_Command(cmd, "gotoheading"); |
@@ -2254,6 +2355,36 @@ iBool handleCommand_App(const char *cmd) { | |||
2254 | } | 2355 | } |
2255 | setCurrent_Root(oldRoot); | 2356 | setCurrent_Root(oldRoot); |
2256 | } | 2357 | } |
2358 | else if (equal_Command(cmd, "file.open")) { | ||
2359 | const char *path = suffixPtr_Command(cmd, "path"); | ||
2360 | if (path) { | ||
2361 | postCommandf_App("open temp:%d url:%s", | ||
2362 | argLabel_Command(cmd, "temp"), | ||
2363 | makeFileUrl_CStr(path)); | ||
2364 | return iTrue; | ||
2365 | } | ||
2366 | #if defined (iPlatformAppleMobile) | ||
2367 | pickFileForOpening_iOS(); | ||
2368 | #endif | ||
2369 | return iTrue; | ||
2370 | } | ||
2371 | else if (equal_Command(cmd, "file.delete")) { | ||
2372 | const char *path = suffixPtr_Command(cmd, "path"); | ||
2373 | if (argLabel_Command(cmd, "confirm")) { | ||
2374 | makeQuestion_Widget( | ||
2375 | uiHeading_ColorEscape "${heading.file.delete}", | ||
2376 | format_CStr("${dlg.file.delete.confirm}\n%s", path), | ||
2377 | (iMenuItem[]){ | ||
2378 | { "${cancel}", 0, 0, NULL }, | ||
2379 | { uiTextCaution_ColorEscape "${dlg.file.delete}", 0, 0, | ||
2380 | format_CStr("!file.delete path:%s", path) } }, | ||
2381 | 2); | ||
2382 | } | ||
2383 | else { | ||
2384 | remove(path); | ||
2385 | } | ||
2386 | return iTrue; | ||
2387 | } | ||
2257 | else if (equal_Command(cmd, "document.request.cancelled")) { | 2388 | else if (equal_Command(cmd, "document.request.cancelled")) { |
2258 | /* TODO: How should cancelled requests be treated in the history? */ | 2389 | /* TODO: How should cancelled requests be treated in the history? */ |
2259 | #if 0 | 2390 | #if 0 |
@@ -2405,6 +2536,8 @@ iBool handleCommand_App(const char *cmd) { | |||
2405 | iTrue); | 2536 | iTrue); |
2406 | setText_InputWidget(findChild_Widget(dlg, "prefs.cachesize"), | 2537 | setText_InputWidget(findChild_Widget(dlg, "prefs.cachesize"), |
2407 | collectNewFormat_String("%d", d->prefs.maxCacheSize)); | 2538 | collectNewFormat_String("%d", d->prefs.maxCacheSize)); |
2539 | setText_InputWidget(findChild_Widget(dlg, "prefs.memorysize"), | ||
2540 | collectNewFormat_String("%d", d->prefs.maxMemorySize)); | ||
2408 | setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs); | 2541 | setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs); |
2409 | setText_InputWidget(findChild_Widget(dlg, "prefs.searchurl"), &d->prefs.searchUrl); | 2542 | setText_InputWidget(findChild_Widget(dlg, "prefs.searchurl"), &d->prefs.searchUrl); |
2410 | setText_InputWidget(findChild_Widget(dlg, "prefs.ca.file"), &d->prefs.caFile); | 2543 | setText_InputWidget(findChild_Widget(dlg, "prefs.ca.file"), &d->prefs.caFile); |
@@ -2491,11 +2624,16 @@ iBool handleCommand_App(const char *cmd) { | |||
2491 | return iTrue; | 2624 | return iTrue; |
2492 | } | 2625 | } |
2493 | else if (equal_Command(cmd, "feeds.update.started")) { | 2626 | else if (equal_Command(cmd, "feeds.update.started")) { |
2494 | showCollapsed_Widget(findWidget_App("feeds.progress"), iTrue); | 2627 | iAnyObject *prog = findWidget_Root("feeds.progress"); |
2628 | const iWidget *navBar = findWidget_Root("navbar"); | ||
2629 | updateTextAndResizeWidthCStr_LabelWidget( | ||
2630 | prog, flags_Widget(navBar) & tight_WidgetFlag || deviceType_App() == phone_AppDeviceType ? | ||
2631 | "\u2605" : "\u2605 ${status.feeds}"); | ||
2632 | showCollapsed_Widget(prog, iTrue); | ||
2495 | return iFalse; | 2633 | return iFalse; |
2496 | } | 2634 | } |
2497 | else if (equal_Command(cmd, "feeds.update.finished")) { | 2635 | else if (equal_Command(cmd, "feeds.update.finished")) { |
2498 | showCollapsed_Widget(findWidget_App("feeds.progress"), iFalse); | 2636 | showCollapsed_Widget(findWidget_Root("feeds.progress"), iFalse); |
2499 | refreshFinished_Feeds(); | 2637 | refreshFinished_Feeds(); |
2500 | postRefresh_App(); | 2638 | postRefresh_App(); |
2501 | return iFalse; | 2639 | return iFalse; |