summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-08-04 11:24:13 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-08-04 11:24:13 +0300
commit7a69d53ba72f9e5581c781dd4c54dd3a3e6b89b4 (patch)
treed84af4e3d72eb02c7cc3a15e08ceda42f59f9b02 /src/ui
parent7fff669f5be5021862ae634b65f3ab18b17021dd (diff)
Remember scroll positions on visited pages
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/documentwidget.c42
-rw-r--r--src/ui/documentwidget.h1
-rw-r--r--src/ui/text.c8
3 files changed, 40 insertions, 11 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 7450ba12..dd119e3e 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -5,6 +5,7 @@
5#include "paint.h" 5#include "paint.h"
6#include "command.h" 6#include "command.h"
7#include "util.h" 7#include "util.h"
8#include "history.h"
8#include "app.h" 9#include "app.h"
9#include "../gmdocument.h" 10#include "../gmdocument.h"
10#include "../gmrequest.h" 11#include "../gmrequest.h"
@@ -91,6 +92,7 @@ struct Impl_DocumentWidget {
91 iPtrArray visibleLinks; 92 iPtrArray visibleLinks;
92 const iGmRun *hoverLink; 93 const iGmRun *hoverLink;
93 iClick click; 94 iClick click;
95 int initialScrollY;
94 iScrollWidget *scroll; 96 iScrollWidget *scroll;
95 iWidget *menu; 97 iWidget *menu;
96 SDL_Cursor *arrowCursor; 98 SDL_Cursor *arrowCursor;
@@ -242,6 +244,12 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
242 clear_PtrArray(&d->visibleLinks); 244 clear_PtrArray(&d->visibleLinks);
243 render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d); 245 render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d);
244 updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); 246 updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window()));
247 /* Remember scroll positions of recently visited pages. */ {
248 iHistoryItem *it = item_History(history_App());
249 if (it) {
250 it->scrollY = d->scrollY / gap_UI;
251 }
252 }
245} 253}
246 254
247static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { 255static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) {
@@ -300,9 +308,14 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
300 break; 308 break;
301 } 309 }
302 setSource_DocumentWidget_(d, src); 310 setSource_DocumentWidget_(d, src);
311 d->scrollY = 0;
312 d->state = ready_DocumentState;
303} 313}
304 314
305static void updateSource_DocumentWidget_(iDocumentWidget *d) { 315static void updateSource_DocumentWidget_(iDocumentWidget *d) {
316 if (d->state == ready_DocumentState) {
317 return;
318 }
306 /* TODO: Do this in the background. However, that requires a text metrics calculator 319 /* TODO: Do this in the background. However, that requires a text metrics calculator
307 that does not try to cache the glyph bitmaps. */ 320 that does not try to cache the glyph bitmaps. */
308 const enum iGmStatusCode statusCode = status_GmRequest(d->request); 321 const enum iGmStatusCode statusCode = status_GmRequest(d->request);
@@ -384,6 +397,10 @@ void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) {
384 } 397 }
385} 398}
386 399
400void setInitialScroll_DocumentWidget (iDocumentWidget *d, int scrollY) {
401 d->initialScrollY = scrollY;
402}
403
387iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) { 404iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) {
388 return d->state == fetching_DocumentState || d->state == receivedPartialResponse_DocumentState; 405 return d->state == fetching_DocumentState || d->state == receivedPartialResponse_DocumentState;
389} 406}
@@ -437,11 +454,14 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
437 return; 454 return;
438 } 455 }
439 enum iGmStatusCode statusCode = status_GmRequest(d->request); 456 enum iGmStatusCode statusCode = status_GmRequest(d->request);
457 if (statusCode == none_GmStatusCode) {
458 return;
459 }
440 if (d->state == fetching_DocumentState) { 460 if (d->state == fetching_DocumentState) {
441 d->state = receivedPartialResponse_DocumentState; 461 d->state = receivedPartialResponse_DocumentState;
442 updateTrust_DocumentWidget_(d); 462 updateTrust_DocumentWidget_(d);
443 switch (statusCode / 10) { 463 switch (category_GmStatusCode(statusCode)) {
444 case 1: /* input required */ { 464 case categoryInput_GmStatusCode: {
445 iUrl parts; 465 iUrl parts;
446 init_Url(&parts, d->url); 466 init_Url(&parts, d->url);
447 printf("%s\n", cstr_String(meta_GmRequest(d->request))); 467 printf("%s\n", cstr_String(meta_GmRequest(d->request)));
@@ -460,16 +480,17 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
460 statusCode == sensitiveInput_GmStatusCode); 480 statusCode == sensitiveInput_GmStatusCode);
461 break; 481 break;
462 } 482 }
463 case 2: /* success */ 483 case categorySuccess_GmStatusCode:
464 d->scrollY = 0; 484 d->scrollY = d->initialScrollY;
465 reset_GmDocument(d->doc); /* new content incoming */ 485 reset_GmDocument(d->doc); /* new content incoming */
466 updateSource_DocumentWidget_(d); 486 updateSource_DocumentWidget_(d);
467 break; 487 break;
468 case 3: /* redirect */ 488 case categoryRedirect_GmStatusCode:
469 if (isEmpty_String(meta_GmRequest(d->request))) { 489 if (isEmpty_String(meta_GmRequest(d->request))) {
470 showErrorPage_DocumentWidget_(d, invalidRedirect_GmStatusCode); 490 showErrorPage_DocumentWidget_(d, invalidRedirect_GmStatusCode);
471 } 491 }
472 else { 492 else {
493 /* TODO: only accept redirects that use gemini protocol */
473 postCommandf_App( 494 postCommandf_App(
474 "open redirect:1 url:%s", 495 "open redirect:1 url:%s",
475 cstr_String(absoluteUrl_String(d->url, meta_GmRequest(d->request)))); 496 cstr_String(absoluteUrl_String(d->url, meta_GmRequest(d->request))));
@@ -480,18 +501,20 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
480 if (isDefined_GmError(statusCode)) { 501 if (isDefined_GmError(statusCode)) {
481 showErrorPage_DocumentWidget_(d, statusCode); 502 showErrorPage_DocumentWidget_(d, statusCode);
482 } 503 }
483 else if (statusCode / 10 == 4) { 504 else if (category_GmStatusCode(statusCode) ==
505 categoryTemporaryFailure_GmStatusCode) {
484 showErrorPage_DocumentWidget_(d, temporaryFailure_GmStatusCode); 506 showErrorPage_DocumentWidget_(d, temporaryFailure_GmStatusCode);
485 } 507 }
486 else if (statusCode / 10 == 5) { 508 else if (category_GmStatusCode(statusCode) ==
509 categoryPermanentFailure_GmStatusCode) {
487 showErrorPage_DocumentWidget_(d, permanentFailure_GmStatusCode); 510 showErrorPage_DocumentWidget_(d, permanentFailure_GmStatusCode);
488 } 511 }
489 break; 512 break;
490 } 513 }
491 } 514 }
492 else if (d->state == receivedPartialResponse_DocumentState) { 515 else if (d->state == receivedPartialResponse_DocumentState) {
493 switch (statusCode) { 516 switch (category_GmStatusCode(statusCode)) {
494 case success_GmStatusCode: 517 case categorySuccess_GmStatusCode:
495 /* More content available. */ 518 /* More content available. */
496 updateSource_DocumentWidget_(d); 519 updateSource_DocumentWidget_(d);
497 break; 520 break;
@@ -649,7 +672,6 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
649 } 672 }
650 else if (isCommand_Widget(w, ev, "document.request.finished") && 673 else if (isCommand_Widget(w, ev, "document.request.finished") &&
651 pointerLabel_Command(command_UserEvent(ev), "request") == d->request) { 674 pointerLabel_Command(command_UserEvent(ev), "request") == d->request) {
652 iAssert(d->state == receivedPartialResponse_DocumentState); /* must already have been updated at least once */
653 checkResponse_DocumentWidget_(d); 675 checkResponse_DocumentWidget_(d);
654 d->state = ready_DocumentState; 676 d->state = ready_DocumentState;
655 iReleasePtr(&d->request); 677 iReleasePtr(&d->request);
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h
index dfd342af..6b0ea607 100644
--- a/src/ui/documentwidget.h
+++ b/src/ui/documentwidget.h
@@ -6,4 +6,5 @@ iDeclareWidgetClass(DocumentWidget)
6iDeclareObjectConstruction(DocumentWidget) 6iDeclareObjectConstruction(DocumentWidget)
7 7
8void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); 8void setUrl_DocumentWidget (iDocumentWidget *, const iString *url);
9void setInitialScroll_DocumentWidget (iDocumentWidget *, int scrollY); /* set after content received */
9iBool isRequestOngoing_DocumentWidget (const iDocumentWidget *); 10iBool isRequestOngoing_DocumentWidget (const iDocumentWidget *);
diff --git a/src/ui/text.c b/src/ui/text.c
index 50b3bbab..f562e642 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -356,6 +356,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
356 iChar prevCh = 0; 356 iChar prevCh = 0;
357 for (const char *chPos = text.start; chPos != text.end; ) { 357 for (const char *chPos = text.start; chPos != text.end; ) {
358 iAssert(chPos < text.end); 358 iAssert(chPos < text.end);
359 const char *currentPos = chPos;
359 if (*chPos == 0x1b) { 360 if (*chPos == 0x1b) {
360 /* ANSI escape. */ 361 /* ANSI escape. */
361 chPos++; 362 chPos++;
@@ -394,7 +395,12 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
394 int x2 = x1 + glyph->rect[hoff].size.x; 395 int x2 = x1 + glyph->rect[hoff].size.x;
395 /* Out of the allotted space? */ 396 /* Out of the allotted space? */
396 if (xposLimit > 0 && x2 > xposLimit) { 397 if (xposLimit > 0 && x2 > xposLimit) {
397 *continueFrom_out = lastWordEnd; 398 if (lastWordEnd != text.start) {
399 *continueFrom_out = lastWordEnd;
400 }
401 else {
402 *continueFrom_out = currentPos; /* forced break */
403 }
398 break; 404 break;
399 } 405 }
400 const SDL_Rect dst = { x1 + glyph->d[hoff].x, 406 const SDL_Rect dst = { x1 + glyph->d[hoff].x,