summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app.c14
-rw-r--r--src/app.h8
-rw-r--r--src/ui/command.c2
-rw-r--r--src/ui/documentwidget.c117
-rw-r--r--src/ui/widget.c15
-rw-r--r--src/ui/widget.h2
-rw-r--r--src/ui/window.c52
7 files changed, 132 insertions, 78 deletions
diff --git a/src/app.c b/src/app.c
index 5b31faa7..e88abe20 100644
--- a/src/app.c
+++ b/src/app.c
@@ -389,6 +389,20 @@ iBool handleCommand_App(const char *cmd) {
389#endif 389#endif
390 return iFalse; 390 return iFalse;
391 } 391 }
392 else if (equal_Command(cmd, "tabs.new")) {
393 iWidget *tabs = findWidget_App("doctabs");
394 iWidget *newTabButton = findChild_Widget(tabs, "newtab");
395 removeChild_Widget(newTabButton->parent, newTabButton);
396 iDocumentWidget *newDoc = new_DocumentWidget();
397 setId_Widget(as_Widget(newDoc), format_CStr("document%03d", tabCount_Widget(tabs)));
398 appendTabPage_Widget(tabs, iClob(newDoc), "", 0, 0);
399 addChild_Widget(findChild_Widget(tabs, "tabs.buttons"), iClob(newTabButton));
400 postCommandf_App("tabs.switch page:%p", newDoc);
401 postCommand_App("navigate.home");
402 arrange_Widget(tabs);
403 refresh_Widget(tabs);
404 return iTrue;
405 }
392 else if (equal_Command(cmd, "quit")) { 406 else if (equal_Command(cmd, "quit")) {
393 SDL_Event ev; 407 SDL_Event ev;
394 ev.type = SDL_QUIT; 408 ev.type = SDL_QUIT;
diff --git a/src/app.h b/src/app.h
index 64c1f64d..d10da7c3 100644
--- a/src/app.h
+++ b/src/app.h
@@ -5,6 +5,7 @@
5#include <the_Foundation/string.h> 5#include <the_Foundation/string.h>
6#include <the_Foundation/time.h> 6#include <the_Foundation/time.h>
7 7
8iDeclareType(DocumentWidget)
8iDeclareType(GmCerts) 9iDeclareType(GmCerts)
9iDeclareType(Visited) 10iDeclareType(Visited)
10iDeclareType(Window) 11iDeclareType(Window)
@@ -26,8 +27,11 @@ void processEvents_App (enum iAppEventMode mode);
26iBool handleCommand_App (const char *cmd); 27iBool handleCommand_App (const char *cmd);
27void refresh_App (void); 28void refresh_App (void);
28 29
29iGmCerts * certs_App (void); 30iGmCerts * certs_App (void);
30iVisited * visited_App (void); 31iVisited * visited_App (void);
32iDocumentWidget * document_App (void);
33iDocumentWidget * document_Command (const char *cmd);
34
31 35
32iAny * findWidget_App (const char *id); 36iAny * findWidget_App (const char *id);
33void addTicker_App (void (*ticker)(iAny *), iAny *context); 37void addTicker_App (void (*ticker)(iAny *), iAny *context);
diff --git a/src/ui/command.c b/src/ui/command.c
index b79c8bcf..c0828343 100644
--- a/src/ui/command.c
+++ b/src/ui/command.c
@@ -6,7 +6,7 @@
6 6
7iBool equal_Command(const char *cmdWithArgs, const char *cmd) { 7iBool equal_Command(const char *cmdWithArgs, const char *cmd) {
8 if (strchr(cmdWithArgs, ':')) { 8 if (strchr(cmdWithArgs, ':')) {
9 return beginsWith_CStr(cmdWithArgs, cmd) && cmdWithArgs[strlen(cmd)] == ' '; 9 return startsWith_CStr(cmdWithArgs, cmd) && cmdWithArgs[strlen(cmd)] == ' ';
10 } 10 }
11 return equal_CStr(cmdWithArgs, cmd); 11 return equal_CStr(cmdWithArgs, cmd);
12} 12}
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index a1299727..7ae43458 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -109,7 +109,7 @@ iDefineObjectConstruction(DocumentWidget)
109void init_DocumentWidget(iDocumentWidget *d) { 109void init_DocumentWidget(iDocumentWidget *d) {
110 iWidget *w = as_Widget(d); 110 iWidget *w = as_Widget(d);
111 init_Widget(w); 111 init_Widget(w);
112 setId_Widget(w, "document"); 112 setId_Widget(w, "document000");
113 iZap(d->certExpiry); 113 iZap(d->certExpiry);
114 d->history = new_History(); 114 d->history = new_History();
115 d->state = blank_DocumentState; 115 d->state = blank_DocumentState;
@@ -195,13 +195,13 @@ static void requestUpdated_DocumentWidget_(iAnyObject *obj) {
195 iDocumentWidget *d = obj; 195 iDocumentWidget *d = obj;
196 const int wasUpdated = exchange_Atomic(&d->isRequestUpdated, iTrue); 196 const int wasUpdated = exchange_Atomic(&d->isRequestUpdated, iTrue);
197 if (!wasUpdated) { 197 if (!wasUpdated) {
198 postCommand_Widget(obj, "document.request.updated request:%p", d->request); 198 postCommand_Widget(obj, "document.request.updated doc:%p request:%p", d, d->request);
199 } 199 }
200} 200}
201 201
202static void requestFinished_DocumentWidget_(iAnyObject *obj) { 202static void requestFinished_DocumentWidget_(iAnyObject *obj) {
203 iDocumentWidget *d = obj; 203 iDocumentWidget *d = obj;
204 postCommand_Widget(obj, "document.request.finished request:%p", d->request); 204 postCommand_Widget(obj, "document.request.finished doc:%p request:%p", d, d->request);
205} 205}
206 206
207static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) { 207static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) {
@@ -330,6 +330,16 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
330 d->state = ready_DocumentState; 330 d->state = ready_DocumentState;
331} 331}
332 332
333static void updateTheme_DocumentWidget_(iDocumentWidget *d) {
334 if (isEmpty_String(d->titleUser)) {
335 setThemeSeed_GmDocument(d->doc,
336 collect_Block(newRange_Block(urlHost_String(d->url))));
337 }
338 else {
339 setThemeSeed_GmDocument(d->doc, &d->titleUser->chars);
340 }
341}
342
333static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse *response) { 343static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse *response) {
334 if (d->state == ready_DocumentState) { 344 if (d->state == ready_DocumentState) {
335 return; 345 return;
@@ -339,15 +349,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse
339 const enum iGmStatusCode statusCode = response->statusCode; 349 const enum iGmStatusCode statusCode = response->statusCode;
340 if (category_GmStatusCode(statusCode) != categoryInput_GmStatusCode) { 350 if (category_GmStatusCode(statusCode) != categoryInput_GmStatusCode) {
341 iString str; 351 iString str;
342 /* Update theme. */ { 352 updateTheme_DocumentWidget_(d);
343 if (isEmpty_String(d->titleUser)) {
344 setThemeSeed_GmDocument(d->doc,
345 collect_Block(newRange_Block(urlHost_String(d->url))));
346 }
347 else {
348 setThemeSeed_GmDocument(d->doc, &d->titleUser->chars);
349 }
350 }
351 initBlock_String(&str, &response->body); 353 initBlock_String(&str, &response->body);
352 if (category_GmStatusCode(statusCode) == categorySuccess_GmStatusCode) { 354 if (category_GmStatusCode(statusCode) == categorySuccess_GmStatusCode) {
353 /* Check the MIME type. */ 355 /* Check the MIME type. */
@@ -392,7 +394,7 @@ static void fetch_DocumentWidget_(iDocumentWidget *d) {
392 iRelease(d->request); 394 iRelease(d->request);
393 d->request = NULL; 395 d->request = NULL;
394 } 396 }
395 postCommandf_App("document.request.started url:%s", cstr_String(d->url)); 397 postCommandf_App("document.request.started doc:%p url:%s", d, cstr_String(d->url));
396 clear_ObjectList(d->media); 398 clear_ObjectList(d->media);
397 d->certFlags = 0; 399 d->certFlags = 0;
398 d->state = fetching_DocumentState; 400 d->state = fetching_DocumentState;
@@ -632,7 +634,7 @@ static iBool requestMedia_DocumentWidget_(iDocumentWidget *d, iGmLinkId linkId)
632 return iFalse; 634 return iFalse;
633} 635}
634 636
635static iBool handleMediaEvent_DocumentWidget_(iDocumentWidget *d, const char *cmd) { 637static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
636 iMediaRequest *req = pointerLabel_Command(cmd, "request"); 638 iMediaRequest *req = pointerLabel_Command(cmd, "request");
637 if (!req || req->doc != d) { 639 if (!req || req->doc != d) {
638 return iFalse; /* not our request */ 640 return iFalse; /* not our request */
@@ -680,9 +682,9 @@ static void changeTextSize_DocumentWidget_(iDocumentWidget *d, int delta) {
680 postCommandf_App("font.setfactor arg:%d", d->textSizePercent); 682 postCommandf_App("font.setfactor arg:%d", d->textSizePercent);
681} 683}
682 684
683static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *ev) { 685static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
684 iWidget *w = as_Widget(d); 686 iWidget *w = as_Widget(d);
685 if (isResize_UserEvent(ev) || isCommand_UserEvent(ev, "font.changed")) { 687 if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed")) {
686 const iGmRun *mid = middleRun_DocumentWidget_(d); 688 const iGmRun *mid = middleRun_DocumentWidget_(d);
687 const char *midLoc = (mid ? mid->text.start : NULL); 689 const char *midLoc = (mid ? mid->text.start : NULL);
688 setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); 690 setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d));
@@ -696,9 +698,16 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
696 } 698 }
697 refresh_Widget(w); 699 refresh_Widget(w);
698 } 700 }
699 else if (isCommand_UserEvent(ev, "server.showcert")) { 701 else if (equal_Command(cmd, "tabs.changed")) {
702 if (cmp_String(id_Widget(w), suffixPtr_Command(cmd, "id")) == 0) {
703 /* Set palette for our document. */
704 updateTheme_DocumentWidget_(d);
705 }
706 return iFalse;
707 }
708 else if (equal_Command(cmd, "server.showcert")) {
700 const char *unchecked = red_ColorEscape "\u2610"; 709 const char *unchecked = red_ColorEscape "\u2610";
701 const char *checked = green_ColorEscape "\u2611"; 710 const char *checked = green_ColorEscape "\u2611";
702 makeMessage_Widget( 711 makeMessage_Widget(
703 cyan_ColorEscape "CERTIFICATE STATUS", 712 cyan_ColorEscape "CERTIFICATE STATUS",
704 format_CStr("%s%s Domain name %s\n" 713 format_CStr("%s%s Domain name %s\n"
@@ -721,7 +730,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
721 d->certFlags & trusted_GmCertFlag ? "Trusted on first use" : "Not trusted")); 730 d->certFlags & trusted_GmCertFlag ? "Trusted on first use" : "Not trusted"));
722 return iTrue; 731 return iTrue;
723 } 732 }
724 else if (isCommand_UserEvent(ev, "copy")) { 733 else if (equal_Command(cmd, "copy")) {
725 if (d->selectMark.start) { 734 if (d->selectMark.start) {
726 iRangecc mark = d->selectMark; 735 iRangecc mark = d->selectMark;
727 if (mark.start > mark.end) { 736 if (mark.start > mark.end) {
@@ -733,7 +742,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
733 return iTrue; 742 return iTrue;
734 } 743 }
735 } 744 }
736 else if (isCommand_Widget(w, ev, "document.copylink")) { 745 else if (equalWidget_Command(cmd, w, "document.copylink")) {
737 if (d->hoverLink) { 746 if (d->hoverLink) {
738 SDL_SetClipboardText(cstr_String( 747 SDL_SetClipboardText(cstr_String(
739 absoluteUrl_String(d->url, linkUrl_GmDocument(d->doc, d->hoverLink->linkId)))); 748 absoluteUrl_String(d->url, linkUrl_GmDocument(d->doc, d->hoverLink->linkId))));
@@ -743,8 +752,8 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
743 } 752 }
744 return iTrue; 753 return iTrue;
745 } 754 }
746 else if (isCommand_UserEvent(ev, "document.input.submit")) { 755 else if (equal_Command(cmd, "document.input.submit")) {
747 iString *value = collect_String(suffix_Command(command_UserEvent(ev), "value")); 756 iString *value = collect_String(suffix_Command(cmd, "value"));
748 urlEncode_String(value); 757 urlEncode_String(value);
749 iString *url = collect_String(copy_String(d->url)); 758 iString *url = collect_String(copy_String(d->url));
750 const size_t qPos = indexOfCStr_String(url, "?"); 759 const size_t qPos = indexOfCStr_String(url, "?");
@@ -756,19 +765,18 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
756 postCommandf_App("open url:%s", cstr_String(url)); 765 postCommandf_App("open url:%s", cstr_String(url));
757 return iTrue; 766 return iTrue;
758 } 767 }
759 else if (isCommand_UserEvent(ev, "valueinput.cancelled") && 768 else if (equal_Command(cmd, "valueinput.cancelled") &&
760 cmp_String(string_Command(command_UserEvent(ev), "id"), "document.input.submit") == 769 cmp_String(string_Command(cmd, "id"), "document.input.submit") == 0) {
761 0) {
762 postCommand_App("navigate.back"); 770 postCommand_App("navigate.back");
763 return iTrue; 771 return iTrue;
764 } 772 }
765 else if (isCommand_Widget(w, ev, "document.request.updated") && 773 else if (equalWidget_Command(cmd, w, "document.request.updated") &&
766 pointerLabel_Command(command_UserEvent(ev), "request") == d->request) { 774 pointerLabel_Command(cmd, "request") == d->request) {
767 checkResponse_DocumentWidget_(d); 775 checkResponse_DocumentWidget_(d);
768 return iFalse; 776 return iFalse;
769 } 777 }
770 else if (isCommand_Widget(w, ev, "document.request.finished") && 778 else if (equalWidget_Command(cmd, w, "document.request.finished") &&
771 pointerLabel_Command(command_UserEvent(ev), "request") == d->request) { 779 pointerLabel_Command(cmd, "request") == d->request) {
772 checkResponse_DocumentWidget_(d); 780 checkResponse_DocumentWidget_(d);
773 d->state = ready_DocumentState; 781 d->state = ready_DocumentState;
774 setCachedResponse_History(d->history, response_GmRequest(d->request)); 782 setCachedResponse_History(d->history, response_GmRequest(d->request));
@@ -776,45 +784,46 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
776 postCommandf_App("document.changed url:%s", cstr_String(d->url)); 784 postCommandf_App("document.changed url:%s", cstr_String(d->url));
777 return iFalse; 785 return iFalse;
778 } 786 }
779 else if (isCommand_UserEvent(ev, "document.request.cancelled")) { 787 else if (equal_Command(cmd, "document.request.cancelled") && document_Command(cmd) == d) {
780 postCommand_App("navigate.back"); 788 postCommand_App("navigate.back");
781 return iFalse; 789 return iFalse;
782 } 790 }
783 else if (isCommand_UserEvent(ev, "document.stop")) { 791 else if (equal_Command(cmd, "document.stop")) {
784 if (d->request) { 792 if (d->request) {
785 postCommandf_App("document.request.cancelled url:%s", cstr_String(d->url)); 793 postCommandf_App("document.request.cancelled doc:%p url:%s", d, cstr_String(d->url));
786 iReleasePtr(&d->request); 794 iReleasePtr(&d->request);
787 d->state = ready_DocumentState; 795 d->state = ready_DocumentState;
796 return iTrue;
788 } 797 }
789 return iTrue;
790 } 798 }
791 else if (isCommand_UserEvent(ev, "media.updated") || isCommand_UserEvent(ev, "media.finished")) { 799 else if (equal_Command(cmd, "media.updated") || equal_Command(cmd, "media.finished")) {
792 return handleMediaEvent_DocumentWidget_(d, command_UserEvent(ev)); 800 return handleMediaCommand_DocumentWidget_(d, cmd);
793 } 801 }
794 else if (isCommand_UserEvent(ev, "document.reload")) { 802 else if (equal_Command(cmd, "document.reload") && document_App() == d) {
795 fetch_DocumentWidget_(d); 803 fetch_DocumentWidget_(d);
796 return iTrue; 804 return iTrue;
797 } 805 }
798 else if (isCommand_UserEvent(ev, "navigate.back")) { 806 else if (equal_Command(cmd, "navigate.back") && document_App() == d) {
799 goBack_History(d->history); 807 goBack_History(d->history);
800 return iTrue; 808 return iTrue;
801 } 809 }
802 else if (isCommand_UserEvent(ev, "navigate.forward")) { 810 else if (equal_Command(cmd, "navigate.forward") && document_App() == d) {
803 goForward_History(d->history); 811 goForward_History(d->history);
804 return iTrue; 812 return iTrue;
805 } 813 }
806 else if (isCommand_Widget(w, ev, "scroll.moved")) { 814 else if (equalWidget_Command(cmd, w, "scroll.moved")) {
807 d->scrollY = arg_Command(command_UserEvent(ev)); 815 d->scrollY = arg_Command(cmd);
808 updateVisible_DocumentWidget_(d); 816 updateVisible_DocumentWidget_(d);
809 return iTrue; 817 return iTrue;
810 } 818 }
811 else if (isCommand_Widget(w, ev, "scroll.page")) { 819 else if (equalWidget_Command(cmd, w, "scroll.page")) {
812 scroll_DocumentWidget_( 820 scroll_DocumentWidget_(d,
813 d, arg_Command(command_UserEvent(ev)) * height_Rect(documentBounds_DocumentWidget_(d))); 821 arg_Command(cmd) * height_Rect(documentBounds_DocumentWidget_(d)));
814 return iTrue; 822 return iTrue;
815 } 823 }
816 else if (isCommand_UserEvent(ev, "find.next") || isCommand_UserEvent(ev, "find.prev")) { 824 else if ((equal_Command(cmd, "find.next") || equal_Command(cmd, "find.prev")) &&
817 const int dir = isCommand_UserEvent(ev, "find.next") ? +1 : -1; 825 document_App() == d) {
826 const int dir = equal_Command(cmd, "find.next") ? +1 : -1;
818 iRangecc (*finder)(const iGmDocument *, const iString *, const char *) = 827 iRangecc (*finder)(const iGmDocument *, const iString *, const char *) =
819 dir > 0 ? findText_GmDocument : findTextBefore_GmDocument; 828 dir > 0 ? findText_GmDocument : findTextBefore_GmDocument;
820 iInputWidget *find = findWidget_App("find.input"); 829 iInputWidget *find = findWidget_App("find.input");
@@ -824,7 +833,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
824 else { 833 else {
825 const iBool wrap = d->foundMark.start != NULL; 834 const iBool wrap = d->foundMark.start != NULL;
826 d->foundMark = finder(d->doc, text_InputWidget(find), dir > 0 ? d->foundMark.end 835 d->foundMark = finder(d->doc, text_InputWidget(find), dir > 0 ? d->foundMark.end
827 : d->foundMark.start); 836 : d->foundMark.start);
828 if (!d->foundMark.start && wrap) { 837 if (!d->foundMark.start && wrap) {
829 /* Wrap around. */ 838 /* Wrap around. */
830 d->foundMark = finder(d->doc, text_InputWidget(find), NULL); 839 d->foundMark = finder(d->doc, text_InputWidget(find), NULL);
@@ -838,14 +847,26 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
838 } 847 }
839 refresh_Widget(w); 848 refresh_Widget(w);
840 return iTrue; 849 return iTrue;
841 } 850 }
842 else if (isCommand_UserEvent(ev, "find.clearmark")) { 851 else if (equal_Command(cmd, "find.clearmark")) {
843 if (d->foundMark.start) { 852 if (d->foundMark.start) {
844 d->foundMark = iNullRange; 853 d->foundMark = iNullRange;
845 refresh_Widget(w); 854 refresh_Widget(w);
846 } 855 }
847 return iTrue; 856 return iTrue;
848 } 857 }
858 return iFalse;
859}
860
861static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *ev) {
862 iWidget *w = as_Widget(d);
863 if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) {
864 if (!handleCommand_DocumentWidget_(d, command_UserEvent(ev))) {
865 /* Base class commands. */
866 return processEvent_Widget(w, ev);
867 }
868 return iTrue;
869 }
849 if (ev->type == SDL_KEYDOWN) { 870 if (ev->type == SDL_KEYDOWN) {
850 const int mods = keyMods_Sym(ev->key.keysym.mod); 871 const int mods = keyMods_Sym(ev->key.keysym.mod);
851 const int key = ev->key.keysym.sym; 872 const int key = ev->key.keysym.sym;
diff --git a/src/ui/widget.c b/src/ui/widget.c
index b07b5709..0db8b8fd 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -551,11 +551,18 @@ iBool isSelected_Widget(const iWidget *d) {
551 return (d->flags & selected_WidgetFlag) != 0; 551 return (d->flags & selected_WidgetFlag) != 0;
552} 552}
553 553
554iBool equalWidget_Command(const char *cmd, const iWidget *widget, const char *checkCommand) {
555 if (equal_Command(cmd, checkCommand)) {
556 const iWidget *src = pointer_Command(cmd);
557 iAssert(!src || strstr(cmd, " ptr:"));
558 return src == widget || hasParent_Widget(src, widget);
559 }
560 return iFalse;
561}
562
554iBool isCommand_Widget(const iWidget *d, const SDL_Event *ev, const char *cmd) { 563iBool isCommand_Widget(const iWidget *d, const SDL_Event *ev, const char *cmd) {
555 if (isCommand_UserEvent(ev, cmd)) { 564 if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) {
556 const iWidget *src = pointer_Command(command_UserEvent(ev)); 565 return equalWidget_Command(command_UserEvent(ev), d, cmd);
557 iAssert(!src || strstr(ev->user.data1, " ptr:"));
558 return src == d || hasParent_Widget(src, d);
559 } 566 }
560 return iFalse; 567 return iFalse;
561} 568}
diff --git a/src/ui/widget.h b/src/ui/widget.h
index 7208a755..0aff6505 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -140,3 +140,5 @@ iWidget *hover_Widget (void);
140void unhover_Widget (void); 140void unhover_Widget (void);
141void setMouseGrab_Widget (iWidget *); 141void setMouseGrab_Widget (iWidget *);
142iWidget *mouseGrab_Widget (void); 142iWidget *mouseGrab_Widget (void);
143
144iBool equalWidget_Command (const char *cmd, const iWidget *widget, const char *checkCommand);
diff --git a/src/ui/window.c b/src/ui/window.c
index defe998f..1f05b80d 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -107,29 +107,34 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) {
107 return iTrue; 107 return iTrue;
108 } 108 }
109 } 109 }
110 else if (equal_Command(cmd, "document.changed")) { 110 else if (startsWith_CStr(cmd, "document.")) {
111 iInputWidget *url = findWidget_App("url"); 111 /* React to the current document only. */
112 const iString *urlStr = collect_String(suffix_Command(cmd, "url")); 112 if (document_Command(cmd) == document_App()) {
113 visitUrl_Visited(visited_App(), urlStr); 113 iLabelWidget *reloadButton = findChild_Widget(navBar, "reload");
114 setText_InputWidget(url, urlStr); 114 if (equal_Command(cmd, "document.changed")) {
115 updateTextCStr_LabelWidget(findChild_Widget(navBar, "reload"), reloadCStr_); 115 iInputWidget *url = findWidget_App("url");
116 return iFalse; 116 const iString *urlStr = collect_String(suffix_Command(cmd, "url"));
117 } 117 setText_InputWidget(url, urlStr);
118 else if (equal_Command(cmd, "document.request.cancelled")) { 118 updateTextCStr_LabelWidget(reloadButton, reloadCStr_);
119 updateTextCStr_LabelWidget(findChild_Widget(navBar, "reload"), reloadCStr_); 119 return iFalse;
120 return iFalse; 120 }
121 } 121 else if (equal_Command(cmd, "document.request.cancelled")) {
122 else if (equal_Command(cmd, "document.request.started")) { 122 updateTextCStr_LabelWidget(reloadButton, reloadCStr_);
123 iInputWidget *url = findChild_Widget(navBar, "url"); 123 return iFalse;
124 if (isFocused_Widget(as_Widget(url))) { 124 }
125 setFocus_Widget(NULL); 125 else if (equal_Command(cmd, "document.request.started")) {
126 iInputWidget *url = findChild_Widget(navBar, "url");
127 if (isFocused_Widget(as_Widget(url))) {
128 setFocus_Widget(NULL);
129 }
130 setTextCStr_InputWidget(url, suffixPtr_Command(cmd, "url"));
131 updateTextCStr_LabelWidget(reloadButton, stopCStr_);
132 return iFalse;
133 }
126 } 134 }
127 setTextCStr_InputWidget(url, suffixPtr_Command(cmd, "url"));
128 updateTextCStr_LabelWidget(findChild_Widget(navBar, "reload"), stopCStr_);
129 return iFalse;
130 } 135 }
131 else if (equal_Command(cmd, "navigate.reload")) { 136 else if (equal_Command(cmd, "navigate.reload")) {
132 iDocumentWidget *doc = findWidget_App("document"); 137 iDocumentWidget *doc = document_Command(cmd);
133 if (isRequestOngoing_DocumentWidget(doc)) { 138 if (isRequestOngoing_DocumentWidget(doc)) {
134 postCommand_App("document.stop"); 139 postCommand_App("document.stop");
135 } 140 }
@@ -224,15 +229,16 @@ static void setupUserInterface_Window(iWindow *d) {
224 setAlignVisually_LabelWidget(fileMenu, iTrue); 229 setAlignVisually_LabelWidget(fileMenu, iTrue);
225 addChild_Widget(navBar, iClob(fileMenu)); 230 addChild_Widget(navBar, iClob(fileMenu));
226 } 231 }
227
228 /* Tab bar. */ { 232 /* Tab bar. */ {
229 iWidget *tabBar = makeTabs_Widget(div); 233 iWidget *tabBar = makeTabs_Widget(div);
230 setId_Widget(tabBar, "doctabs"); 234 setId_Widget(tabBar, "doctabs");
231 setFlags_Widget(tabBar, expand_WidgetFlag, iTrue); 235 setFlags_Widget(tabBar, expand_WidgetFlag, iTrue);
232 setBackgroundColor_Widget(tabBar, gray25_ColorId); 236 setBackgroundColor_Widget(tabBar, gray25_ColorId);
233 appendTabPage_Widget(tabBar, iClob(new_DocumentWidget()), "Document", '1', KMOD_PRIMARY); 237 appendTabPage_Widget(tabBar, iClob(new_DocumentWidget()), "Document", '1', KMOD_PRIMARY);
234 addChild_Widget(findChild_Widget(tabBar, "tabs.buttons"), 238 setId_Widget(
235 iClob(newIcon_LabelWidget("\u2795", 't', KMOD_PRIMARY, "tabs.new"))); 239 addChild_Widget(findChild_Widget(tabBar, "tabs.buttons"),
240 iClob(newIcon_LabelWidget("\u2795", 't', KMOD_PRIMARY, "tabs.new"))),
241 "newtab");
236 } 242 }
237 /* Search bar. */ { 243 /* Search bar. */ {
238 iWidget *searchBar = new_Widget(); 244 iWidget *searchBar = new_Widget();