diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-23 14:33:12 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-23 14:33:12 +0200 |
commit | b1a919108e3c447bbcbb7c0110663713b7c9b83c (patch) | |
tree | 4f5964698bee8ce728f1084c6a94f2ce71687453 | |
parent | 0fdf297a5750f736eddbdbfe73cdb86522cb302c (diff) |
Option to auto-reload a tab at a given interval
IssueID #116
-rw-r--r-- | src/app.c | 11 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 90 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 3 | ||||
-rw-r--r-- | src/ui/util.c | 24 |
4 files changed, 102 insertions, 26 deletions
@@ -126,6 +126,7 @@ struct Impl_App { | |||
126 | iStringList *launchCommands; | 126 | iStringList *launchCommands; |
127 | iBool isFinishedLaunching; | 127 | iBool isFinishedLaunching; |
128 | iTime lastDropTime; /* for detecting drops of multiple items */ | 128 | iTime lastDropTime; /* for detecting drops of multiple items */ |
129 | int autoReloadTimer; | ||
129 | /* Preferences: */ | 130 | /* Preferences: */ |
130 | iBool commandEcho; /* --echo */ | 131 | iBool commandEcho; /* --echo */ |
131 | iBool forceSoftwareRender; /* --sw */ | 132 | iBool forceSoftwareRender; /* --sw */ |
@@ -414,6 +415,12 @@ static uint32_t checkAsleep_App_(uint32_t interval, void *param) { | |||
414 | } | 415 | } |
415 | #endif | 416 | #endif |
416 | 417 | ||
418 | static uint32_t postAutoReloadCommand_App_(uint32_t interval, void *param) { | ||
419 | iUnused(param); | ||
420 | postCommand_App("document.autoreload"); | ||
421 | return interval; | ||
422 | } | ||
423 | |||
417 | static void init_App_(iApp *d, int argc, char **argv) { | 424 | static void init_App_(iApp *d, int argc, char **argv) { |
418 | init_CommandLine(&d->args, argc, argv); | 425 | init_CommandLine(&d->args, argc, argv); |
419 | /* Where was the app started from? We ask SDL first because the command line alone is | 426 | /* Where was the app started from? We ask SDL first because the command line alone is |
@@ -512,7 +519,9 @@ static void init_App_(iApp *d, int argc, char **argv) { | |||
512 | postCommand_App("open url:about:help"); | 519 | postCommand_App("open url:about:help"); |
513 | } | 520 | } |
514 | postCommand_App("window.unfreeze"); | 521 | postCommand_App("window.unfreeze"); |
515 | d->isFinishedLaunching = iTrue; | 522 | d->autoReloadTimer = SDL_AddTimer(60 * 1000, postAutoReloadCommand_App_, NULL); |
523 | postCommand_App("document.autoreload"); | ||
524 | d->isFinishedLaunching = iTrue; | ||
516 | /* Run any commands that were pending completion of launch. */ { | 525 | /* Run any commands that were pending completion of launch. */ { |
517 | iForEach(StringList, i, d->launchCommands) { | 526 | iForEach(StringList, i, d->launchCommands) { |
518 | postCommandString_App(i.value); | 527 | postCommandString_App(i.value); |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index fbfb94f3..7bf0beca 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -67,14 +67,49 @@ iDeclareType(PersistentDocumentState) | |||
67 | iDeclareTypeConstruction(PersistentDocumentState) | 67 | iDeclareTypeConstruction(PersistentDocumentState) |
68 | iDeclareTypeSerialization(PersistentDocumentState) | 68 | iDeclareTypeSerialization(PersistentDocumentState) |
69 | 69 | ||
70 | enum iReloadInterval { | ||
71 | never_RelodPeriod, | ||
72 | minute_ReloadInterval, | ||
73 | fiveMinutes_ReloadInterval, | ||
74 | fifteenMinutes_ReloadInterval, | ||
75 | hour_ReloadInterval, | ||
76 | fourHours_ReloadInterval, | ||
77 | twicePerDay_ReloadInterval, | ||
78 | day_ReloadInterval, | ||
79 | max_ReloadInterval | ||
80 | }; | ||
81 | |||
82 | static int seconds_ReloadInterval_(enum iReloadInterval d) { | ||
83 | static const int times[] = { 0, 1, 5, 15, 60, 4 * 60, 12 * 60, 24 * 60 }; | ||
84 | if (d < 0 || d >= max_ReloadInterval) return 0; | ||
85 | return times[d]; | ||
86 | } | ||
87 | |||
88 | static const char *label_ReloadInterval_(enum iReloadInterval d) { | ||
89 | static const char *labels[] = { | ||
90 | "Never", | ||
91 | "1 minute", | ||
92 | "5 minutes", | ||
93 | "15 minutes", | ||
94 | "1 hour", | ||
95 | "4 hours", | ||
96 | "12 hours", | ||
97 | "Once per day" | ||
98 | }; | ||
99 | if (d < 0 || d >= max_ReloadInterval) return 0; | ||
100 | return labels[d]; | ||
101 | } | ||
102 | |||
70 | struct Impl_PersistentDocumentState { | 103 | struct Impl_PersistentDocumentState { |
71 | iHistory *history; | 104 | iHistory *history; |
72 | iString * url; | 105 | iString * url; |
106 | enum iReloadInterval reloadInterval; | ||
73 | }; | 107 | }; |
74 | 108 | ||
75 | void init_PersistentDocumentState(iPersistentDocumentState *d) { | 109 | void init_PersistentDocumentState(iPersistentDocumentState *d) { |
76 | d->history = new_History(); | 110 | d->history = new_History(); |
77 | d->url = new_String(); | 111 | d->url = new_String(); |
112 | d->reloadInterval = 0; | ||
78 | } | 113 | } |
79 | 114 | ||
80 | void deinit_PersistentDocumentState(iPersistentDocumentState *d) { | 115 | void deinit_PersistentDocumentState(iPersistentDocumentState *d) { |
@@ -84,7 +119,7 @@ void deinit_PersistentDocumentState(iPersistentDocumentState *d) { | |||
84 | 119 | ||
85 | void serialize_PersistentDocumentState(const iPersistentDocumentState *d, iStream *outs) { | 120 | void serialize_PersistentDocumentState(const iPersistentDocumentState *d, iStream *outs) { |
86 | serialize_String(d->url, outs); | 121 | serialize_String(d->url, outs); |
87 | write16_Stream(outs, 0 /*d->zoomPercent*/); | 122 | writeU16_Stream(outs, d->reloadInterval & 7); |
88 | serialize_History(d->history, outs); | 123 | serialize_History(d->history, outs); |
89 | } | 124 | } |
90 | 125 | ||
@@ -94,7 +129,8 @@ void deserialize_PersistentDocumentState(iPersistentDocumentState *d, iStream *i | |||
94 | /* Oopsie, this should not have been written; invalid URL. */ | 129 | /* Oopsie, this should not have been written; invalid URL. */ |
95 | clear_String(d->url); | 130 | clear_String(d->url); |
96 | } | 131 | } |
97 | /*d->zoomPercent =*/ read16_Stream(ins); | 132 | const uint16_t params = readU16_Stream(ins); |
133 | d->reloadInterval = params & 7; | ||
98 | deserialize_History(d->history, ins); | 134 | deserialize_History(d->history, ins); |
99 | } | 135 | } |
100 | 136 | ||
@@ -1868,7 +1904,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1868 | } | 1904 | } |
1869 | return iTrue; | 1905 | return iTrue; |
1870 | } | 1906 | } |
1871 | else if (equal_Command(cmd, "document.reload") && document_App() == d) { | 1907 | else if (equal_Command(cmd, "document.reload") && document_Command(cmd) == d) { |
1872 | d->initNormScrollY = normScrollPos_DocumentWidget_(d); | 1908 | d->initNormScrollY = normScrollPos_DocumentWidget_(d); |
1873 | fetch_DocumentWidget_(d); | 1909 | fetch_DocumentWidget_(d); |
1874 | return iTrue; | 1910 | return iTrue; |
@@ -2083,13 +2119,6 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2083 | size_PtrArray(links), | 2119 | size_PtrArray(links), |
2084 | plural), 0, 0, "bookmark.links" } }, | 2120 | plural), 0, 0, "bookmark.links" } }, |
2085 | 2); | 2121 | 2); |
2086 | |||
2087 | // (const char *[]){ "Cancel", | ||
2088 | // format_CStr(uiTextAction_ColorEscape "Add %d | ||
2089 | // Bookmark%s", | ||
2090 | // size_PtrArray(links), plural) }, | ||
2091 | // (const char *[]){ "cancel", "bookmark.links" }, | ||
2092 | // 2); | ||
2093 | } | 2122 | } |
2094 | else { | 2123 | else { |
2095 | iConstForEach(PtrArray, j, links) { | 2124 | iConstForEach(PtrArray, j, links) { |
@@ -2112,16 +2141,38 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2112 | else if (equalWidget_Command(cmd, w, "menu.closed")) { | 2141 | else if (equalWidget_Command(cmd, w, "menu.closed")) { |
2113 | updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); | 2142 | updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); |
2114 | } | 2143 | } |
2144 | else if (equal_Command(cmd, "document.autoreload")) { | ||
2145 | if (d->mod.reloadInterval) { | ||
2146 | if (isValid_Time(&d->sourceTime) && | ||
2147 | elapsedSeconds_Time(&d->sourceTime) >= | ||
2148 | seconds_ReloadInterval_(d->mod.reloadInterval)) { | ||
2149 | postCommand_Widget(w, "document.reload"); | ||
2150 | } | ||
2151 | } | ||
2152 | } | ||
2153 | else if (equal_Command(cmd, "document.autoreload.menu") && document_App() == d) { | ||
2154 | iWidget *dlg = makeQuestion_Widget(uiTextAction_ColorEscape "AUTO-RELOAD", | ||
2155 | "Select the auto-reload interval for this tab.", | ||
2156 | (iMenuItem[]){ { "Cancel", 0, 0, NULL } }, | ||
2157 | 1); | ||
2158 | for (int i = 0; i < max_ReloadInterval; ++i) { | ||
2159 | insertChildAfterFlags_Widget( | ||
2160 | dlg, | ||
2161 | iClob(new_LabelWidget(label_ReloadInterval_(i), | ||
2162 | format_CStr("document.autoreload.set arg:%d", i))), | ||
2163 | i + 1, | ||
2164 | resizeToParentWidth_WidgetFlag | | ||
2165 | ((int) d->mod.reloadInterval == i ? selected_WidgetFlag : 0)); | ||
2166 | } | ||
2167 | arrange_Widget(dlg); | ||
2168 | return iTrue; | ||
2169 | } | ||
2170 | else if (equal_Command(cmd, "document.autoreload.set") && document_App() == d) { | ||
2171 | d->mod.reloadInterval = arg_Command(cmd); | ||
2172 | } | ||
2115 | return iFalse; | 2173 | return iFalse; |
2116 | } | 2174 | } |
2117 | 2175 | ||
2118 | #if 0 | ||
2119 | static int outlineHeight_DocumentWidget_(const iDocumentWidget *d) { | ||
2120 | if (isEmpty_Array(&d->outline)) return 0; | ||
2121 | return bottom_Rect(((const iOutlineItem *) constBack_Array(&d->outline))->rect); | ||
2122 | } | ||
2123 | #endif | ||
2124 | |||
2125 | static iRect playerRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun *run) { | 2176 | static iRect playerRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun *run) { |
2126 | const iRect docBounds = documentBounds_DocumentWidget_(d); | 2177 | const iRect docBounds = documentBounds_DocumentWidget_(d); |
2127 | return moved_Rect(run->bounds, addY_I2(topLeft_Rect(docBounds), -value_Anim(&d->scrollY))); | 2178 | return moved_Rect(run->bounds, addY_I2(topLeft_Rect(docBounds), -value_Anim(&d->scrollY))); |
@@ -2538,6 +2589,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2538 | { "Go to Root", navigateRoot_KeyShortcut, "navigate.root" }, | 2589 | { "Go to Root", navigateRoot_KeyShortcut, "navigate.root" }, |
2539 | { "---", 0, 0, NULL }, | 2590 | { "---", 0, 0, NULL }, |
2540 | { "Reload Page", reload_KeyShortcut, "navigate.reload" }, | 2591 | { "Reload Page", reload_KeyShortcut, "navigate.reload" }, |
2592 | { "Set Auto-Reload...", 0, 0, "document.autoreload.menu" }, | ||
2541 | { "---", 0, 0, NULL }, | 2593 | { "---", 0, 0, NULL }, |
2542 | { "Bookmark Page...", SDLK_d, KMOD_PRIMARY, "bookmark.add" }, | 2594 | { "Bookmark Page...", SDLK_d, KMOD_PRIMARY, "bookmark.add" }, |
2543 | { "Subscribe to Page...", subscribeToPage_KeyModifier, "feeds.subscribe" }, | 2595 | { "Subscribe to Page...", subscribeToPage_KeyModifier, "feeds.subscribe" }, |
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 17640aaa..9ca09fe8 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -1356,7 +1356,8 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, | |||
1356 | iString str; | 1356 | iString str; |
1357 | init_String(&str); | 1357 | init_String(&str); |
1358 | appendChar_String(&str, d->icon ? d->icon : 0x1f588); | 1358 | appendChar_String(&str, d->icon ? d->icon : 0x1f588); |
1359 | const iRect iconArea = { addX_I2(pos, gap_UI), init_I2(1.9f * lineHeight_Text(font), itemHeight) }; | 1359 | const iRect iconArea = { addX_I2(pos, gap_UI), |
1360 | init_I2(1.75f * lineHeight_Text(font), itemHeight) }; | ||
1360 | drawCentered_Text(font, | 1361 | drawCentered_Text(font, |
1361 | iconArea, | 1362 | iconArea, |
1362 | iTrue, | 1363 | iTrue, |
diff --git a/src/ui/util.c b/src/ui/util.c index f8151807..04edbfd9 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -382,10 +382,20 @@ iWidget *addAction_Widget(iWidget *parent, int key, int kmods, const char *comma | |||
382 | /*-----------------------------------------------------------------------------------------------*/ | 382 | /*-----------------------------------------------------------------------------------------------*/ |
383 | 383 | ||
384 | static iBool isCommandIgnoredByMenus_(const char *cmd) { | 384 | static iBool isCommandIgnoredByMenus_(const char *cmd) { |
385 | return equal_Command(cmd, "media.updated") || equal_Command(cmd, "media.player.update") || | 385 | /* TODO: Perhaps a common way of indicating which commands are notifications and should not |
386 | be reacted to by menus? */ | ||
387 | return equal_Command(cmd, "media.updated") || | ||
388 | equal_Command(cmd, "media.player.update") || | ||
386 | startsWith_CStr(cmd, "feeds.update.") || | 389 | startsWith_CStr(cmd, "feeds.update.") || |
387 | equal_Command(cmd, "document.request.updated") || | 390 | equal_Command(cmd, "bookmarks.request.started") || |
388 | equal_Command(cmd, "bookmarks.request.finished") || | 391 | equal_Command(cmd, "bookmarks.request.finished") || |
392 | equal_Command(cmd, "document.autoreload") || | ||
393 | equal_Command(cmd, "document.reload") || | ||
394 | equal_Command(cmd, "document.request.started") || | ||
395 | equal_Command(cmd, "document.request.updated") || | ||
396 | equal_Command(cmd, "document.request.finished") || | ||
397 | equal_Command(cmd, "document.changed") || | ||
398 | equal_Command(cmd, "visited.changed") || | ||
389 | (deviceType_App() == desktop_AppDeviceType && equal_Command(cmd, "window.resized")) || | 399 | (deviceType_App() == desktop_AppDeviceType && equal_Command(cmd, "window.resized")) || |
390 | equal_Command(cmd, "window.reload.update") || | 400 | equal_Command(cmd, "window.reload.update") || |
391 | equal_Command(cmd, "window.mouse.exited") || | 401 | equal_Command(cmd, "window.mouse.exited") || |
@@ -1028,10 +1038,13 @@ void updateValueInput_Widget(iWidget *d, const char *title, const char *prompt) | |||
1028 | 1038 | ||
1029 | static iBool messageHandler_(iWidget *msg, const char *cmd) { | 1039 | static iBool messageHandler_(iWidget *msg, const char *cmd) { |
1030 | /* Almost any command dismisses the sheet. */ | 1040 | /* Almost any command dismisses the sheet. */ |
1031 | if (!(equal_Command(cmd, "media.updated") || | 1041 | if (!(equal_Command(cmd, "media.updated") || |
1032 | equal_Command(cmd, "media.player.update") || | 1042 | equal_Command(cmd, "media.player.update") || |
1033 | equal_Command(cmd, "bookmarks.request.finished") || | 1043 | equal_Command(cmd, "bookmarks.request.finished") || |
1034 | equal_Command(cmd, "document.request.updated") || startsWith_CStr(cmd, "window."))) { | 1044 | equal_Command(cmd, "document.autoreload") || |
1045 | equal_Command(cmd, "document.reload") || | ||
1046 | equal_Command(cmd, "document.request.updated") || | ||
1047 | startsWith_CStr(cmd, "window."))) { | ||
1035 | destroy_Widget(msg); | 1048 | destroy_Widget(msg); |
1036 | } | 1049 | } |
1037 | return iFalse; | 1050 | return iFalse; |
@@ -1053,7 +1066,7 @@ iWidget *makeQuestion_Widget(const char *title, const char *msg, | |||
1053 | addChildFlags_Widget(dlg, iClob(new_LabelWidget(title, NULL)), frameless_WidgetFlag); | 1066 | addChildFlags_Widget(dlg, iClob(new_LabelWidget(title, NULL)), frameless_WidgetFlag); |
1054 | addChildFlags_Widget(dlg, iClob(new_LabelWidget(msg, NULL)), frameless_WidgetFlag); | 1067 | addChildFlags_Widget(dlg, iClob(new_LabelWidget(msg, NULL)), frameless_WidgetFlag); |
1055 | addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI))); | 1068 | addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI))); |
1056 | iWidget *buttons = addChild_Widget(dlg, iClob(makeDialogButtons_(items, numItems))); | 1069 | addChild_Widget(dlg, iClob(makeDialogButtons_(items, numItems))); |
1057 | addChild_Widget(get_Window()->root, iClob(dlg)); | 1070 | addChild_Widget(get_Window()->root, iClob(dlg)); |
1058 | arrange_Widget(dlg); /* BUG: This extra arrange shouldn't be needed but the dialog won't | 1071 | arrange_Widget(dlg); /* BUG: This extra arrange shouldn't be needed but the dialog won't |
1059 | be arranged correctly unless it's here. */ | 1072 | be arranged correctly unless it's here. */ |
@@ -1307,6 +1320,7 @@ iWidget *makePreferences_Widget(void) { | |||
1307 | setFlags_Widget(as_Widget(bind), borderTop_WidgetFlag, iTrue); | 1320 | setFlags_Widget(as_Widget(bind), borderTop_WidgetFlag, iTrue); |
1308 | appendFramelessTabPage_(tabs, iClob(bind), "Keys", '6', KMOD_PRIMARY); | 1321 | appendFramelessTabPage_(tabs, iClob(bind), "Keys", '6', KMOD_PRIMARY); |
1309 | } | 1322 | } |
1323 | addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI))); | ||
1310 | resizeToLargestPage_Widget(tabs); | 1324 | resizeToLargestPage_Widget(tabs); |
1311 | arrange_Widget(dlg); | 1325 | arrange_Widget(dlg); |
1312 | /* Set input field sizes. */ { | 1326 | /* Set input field sizes. */ { |