summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c124
1 files changed, 73 insertions, 51 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 48383560..5cf0f6a6 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -251,9 +251,9 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
251 render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d); 251 render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d);
252 updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); 252 updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window()));
253 /* Remember scroll positions of recently visited pages. */ { 253 /* Remember scroll positions of recently visited pages. */ {
254 iHistoryItem *it = item_History(history_App()); 254 iRecentUrl *recent = mostRecentUrl_History(history_App());
255 if (it) { 255 if (recent) {
256 it->scrollY = d->scrollY / gap_UI; 256 recent->scrollY = d->scrollY / gap_UI;
257 } 257 }
258 } 258 }
259} 259}
@@ -318,16 +318,16 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
318 d->state = ready_DocumentState; 318 d->state = ready_DocumentState;
319} 319}
320 320
321static void updateSource_DocumentWidget_(iDocumentWidget *d) { 321static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse *response) {
322 if (d->state == ready_DocumentState) { 322 if (d->state == ready_DocumentState) {
323 return; 323 return;
324 } 324 }
325 /* TODO: Do this in the background. However, that requires a text metrics calculator 325 /* TODO: Do this in the background. However, that requires a text metrics calculator
326 that does not try to cache the glyph bitmaps. */ 326 that does not try to cache the glyph bitmaps. */
327 const enum iGmStatusCode statusCode = status_GmRequest(d->request); 327 const enum iGmStatusCode statusCode = response->statusCode;
328 if (category_GmStatusCode(statusCode) != categoryInput_GmStatusCode) { 328 if (category_GmStatusCode(statusCode) != categoryInput_GmStatusCode) {
329 iString str; 329 iString str;
330 /* Theming. */ { 330 /* Update theme. */ {
331 if (isEmpty_String(d->titleUser)) { 331 if (isEmpty_String(d->titleUser)) {
332 setThemeSeed_GmDocument(d->doc, 332 setThemeSeed_GmDocument(d->doc,
333 collect_Block(newRange_Block(urlHost_String(d->url)))); 333 collect_Block(newRange_Block(urlHost_String(d->url))));
@@ -336,10 +336,10 @@ static void updateSource_DocumentWidget_(iDocumentWidget *d) {
336 setThemeSeed_GmDocument(d->doc, &d->titleUser->chars); 336 setThemeSeed_GmDocument(d->doc, &d->titleUser->chars);
337 } 337 }
338 } 338 }
339 initBlock_String(&str, body_GmRequest(d->request)); 339 initBlock_String(&str, &response->body);
340 if (category_GmStatusCode(statusCode) == categorySuccess_GmStatusCode) { 340 if (category_GmStatusCode(statusCode) == categorySuccess_GmStatusCode) {
341 /* Check the MIME type. */ 341 /* Check the MIME type. */
342 const iString *mime = meta_GmRequest(d->request); 342 const iString *mime = &response->meta;
343 if (startsWith_String(mime, "text/plain")) { 343 if (startsWith_String(mime, "text/plain")) {
344 setFormat_GmDocument(d->doc, plainText_GmDocumentFormat); 344 setFormat_GmDocument(d->doc, plainText_GmDocumentFormat);
345 } 345 }
@@ -347,17 +347,17 @@ static void updateSource_DocumentWidget_(iDocumentWidget *d) {
347 setFormat_GmDocument(d->doc, gemini_GmDocumentFormat); 347 setFormat_GmDocument(d->doc, gemini_GmDocumentFormat);
348 } 348 }
349 else if (startsWith_String(mime, "image/")) { 349 else if (startsWith_String(mime, "image/")) {
350 if (isFinished_GmRequest(d->request)) { 350 if (!d->request || isFinished_GmRequest(d->request)) {
351 /* Make a simple document with an image. */ 351 /* Make a simple document with an image. */
352 const char *imageTitle = "Image"; 352 const char *imageTitle = "Image";
353 iUrl parts; 353 iUrl parts;
354 init_Url(&parts, url_GmRequest(d->request)); 354 init_Url(&parts, d->url); // url_GmRequest(d->request));
355 if (!isEmpty_Range(&parts.path)) { 355 if (!isEmpty_Range(&parts.path)) {
356 imageTitle = baseName_Path(collect_String(newRange_String(parts.path))).start; 356 imageTitle = baseName_Path(collect_String(newRange_String(parts.path))).start;
357 } 357 }
358 format_String( 358 format_String(
359 &str, "=> %s %s\n", cstr_String(url_GmRequest(d->request)), imageTitle); 359 &str, "=> %s %s\n", cstr_String(d->url), imageTitle);
360 setImage_GmDocument(d->doc, 1, mime, body_GmRequest(d->request)); 360 setImage_GmDocument(d->doc, 1, mime, &response->body);
361 } 361 }
362 else { 362 else {
363 clear_String(&str); 363 clear_String(&str);
@@ -392,25 +392,70 @@ static void fetch_DocumentWidget_(iDocumentWidget *d) {
392 submit_GmRequest(d->request); 392 submit_GmRequest(d->request);
393} 393}
394 394
395void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) { 395static void updateTrust_DocumentWidget_(iDocumentWidget *d, const iGmResponse *response) {
396#define openLock_CStr "\U0001f513"
397#define closedLock_CStr "\U0001f512"
398 d->certFlags = response->certFlags;
399 d->certExpiry = response->certValidUntil;
400 iLabelWidget *lock = findWidget_App("navbar.lock");
401 if (~d->certFlags & available_GmCertFlag) {
402 setFlags_Widget(as_Widget(lock), disabled_WidgetFlag, iTrue);
403 updateTextCStr_LabelWidget(lock, gray50_ColorEscape openLock_CStr);
404 return;
405 }
406 setFlags_Widget(as_Widget(lock), disabled_WidgetFlag, iFalse);
407 if (~d->certFlags & domainVerified_GmCertFlag) {
408 updateTextCStr_LabelWidget(lock, red_ColorEscape closedLock_CStr);
409 }
410 else if (d->certFlags & trusted_GmCertFlag) {
411 updateTextCStr_LabelWidget(lock, green_ColorEscape closedLock_CStr);
412 }
413 else {
414 updateTextCStr_LabelWidget(lock, orange_ColorEscape closedLock_CStr);
415 }
416}
417
418void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBool isFromCache) {
396 if (cmpStringSc_String(d->url, url, &iCaseInsensitive)) { 419 if (cmpStringSc_String(d->url, url, &iCaseInsensitive)) {
397 set_String(d->url, url); 420 set_String(d->url, url);
398 fetch_DocumentWidget_(d); 421 /* See if there a username in the URL. */ {
399 } 422 clear_String(d->titleUser);
400 /* See if there a username in the URL. */ { 423 iRegExp *userPats[2] = { new_RegExp("~([^/?]+)", 0),
401 clear_String(d->titleUser); 424 new_RegExp("/users/([^/?]+)", caseInsensitive_RegExpOption) };
402 iRegExp *userPats[2] = { new_RegExp("~([^/?]+)", 0), 425 iRegExpMatch m;
403 new_RegExp("/users/([^/?]+)", caseInsensitive_RegExpOption) }; 426 iForIndices(i, userPats) {
404 iRegExpMatch m; 427 if (matchString_RegExp(userPats[i], d->url, &m)) {
405 iForIndices(i, userPats) { 428 setRange_String(d->titleUser, capturedRange_RegExpMatch(&m, 1));
406 if (matchString_RegExp(userPats[i], d->url, &m)) { 429 }
407 setRange_String(d->titleUser, capturedRange_RegExpMatch(&m, 1)); 430 iRelease(userPats[i]);
408 } 431 }
409 iRelease(userPats[i]); 432 }
433 const iRecentUrl *recent = mostRecentUrl_History(history_App());
434 if (isFromCache && recent && recent->cachedResponse) {
435 const iGmResponse *resp = recent->cachedResponse;
436 d->state = fetching_DocumentState;
437 /* Use the cached response data. */
438 printf("cached response: %d [%s] %zu bytes\n{%s}\n",
439 resp->statusCode,
440 cstr_String(&resp->meta),
441 size_Block(&resp->body),
442 cstr_Block(&resp->body));
443 d->scrollY = d->initialScrollY;
444 updateTrust_DocumentWidget_(d, resp);
445 updateDocument_DocumentWidget_(d, resp);
446 d->state = ready_DocumentState;
447 postCommandf_App("document.changed url:%s", cstr_String(d->url));
448 }
449 else {
450 fetch_DocumentWidget_(d);
410 } 451 }
411 } 452 }
412} 453}
413 454
455void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) {
456 setUrlFromCache_DocumentWidget(d, url, iFalse);
457}
458
414void setInitialScroll_DocumentWidget (iDocumentWidget *d, int scrollY) { 459void setInitialScroll_DocumentWidget (iDocumentWidget *d, int scrollY) {
415 d->initialScrollY = scrollY; 460 d->initialScrollY = scrollY;
416} 461}
@@ -440,30 +485,6 @@ static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY) {
440 scroll_DocumentWidget_(d, 0); /* clamp it */ 485 scroll_DocumentWidget_(d, 0); /* clamp it */
441} 486}
442 487
443static void updateTrust_DocumentWidget_(iDocumentWidget *d) {
444 iAssert(d->request);
445#define openLock_CStr "\U0001f513"
446#define closedLock_CStr "\U0001f512"
447 d->certFlags = certFlags_GmRequest(d->request);
448 d->certExpiry = certExpirationDate_GmRequest(d->request);
449 iLabelWidget *lock = findWidget_App("navbar.lock");
450 if (~d->certFlags & available_GmCertFlag) {
451 setFlags_Widget(as_Widget(lock), disabled_WidgetFlag, iTrue);
452 updateTextCStr_LabelWidget(lock, gray50_ColorEscape openLock_CStr);
453 return;
454 }
455 setFlags_Widget(as_Widget(lock), disabled_WidgetFlag, iFalse);
456 if (~d->certFlags & domainVerified_GmCertFlag) {
457 updateTextCStr_LabelWidget(lock, red_ColorEscape closedLock_CStr);
458 }
459 else if (d->certFlags & trusted_GmCertFlag) {
460 updateTextCStr_LabelWidget(lock, green_ColorEscape closedLock_CStr);
461 }
462 else {
463 updateTextCStr_LabelWidget(lock, orange_ColorEscape closedLock_CStr);
464 }
465}
466
467static void checkResponse_DocumentWidget_(iDocumentWidget *d) { 488static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
468 if (!d->request) { 489 if (!d->request) {
469 return; 490 return;
@@ -474,7 +495,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
474 } 495 }
475 if (d->state == fetching_DocumentState) { 496 if (d->state == fetching_DocumentState) {
476 d->state = receivedPartialResponse_DocumentState; 497 d->state = receivedPartialResponse_DocumentState;
477 updateTrust_DocumentWidget_(d); 498 updateTrust_DocumentWidget_(d, response_GmRequest(d->request));
478 switch (category_GmStatusCode(statusCode)) { 499 switch (category_GmStatusCode(statusCode)) {
479 case categoryInput_GmStatusCode: { 500 case categoryInput_GmStatusCode: {
480 iUrl parts; 501 iUrl parts;
@@ -498,7 +519,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
498 case categorySuccess_GmStatusCode: 519 case categorySuccess_GmStatusCode:
499 d->scrollY = d->initialScrollY; 520 d->scrollY = d->initialScrollY;
500 reset_GmDocument(d->doc); /* new content incoming */ 521 reset_GmDocument(d->doc); /* new content incoming */
501 updateSource_DocumentWidget_(d); 522 updateDocument_DocumentWidget_(d, response_GmRequest(d->request));
502 break; 523 break;
503 case categoryRedirect_GmStatusCode: 524 case categoryRedirect_GmStatusCode:
504 if (isEmpty_String(meta_GmRequest(d->request))) { 525 if (isEmpty_String(meta_GmRequest(d->request))) {
@@ -531,7 +552,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
531 switch (category_GmStatusCode(statusCode)) { 552 switch (category_GmStatusCode(statusCode)) {
532 case categorySuccess_GmStatusCode: 553 case categorySuccess_GmStatusCode:
533 /* More content available. */ 554 /* More content available. */
534 updateSource_DocumentWidget_(d); 555 updateDocument_DocumentWidget_(d, response_GmRequest(d->request));
535 break; 556 break;
536 default: 557 default:
537 break; 558 break;
@@ -739,6 +760,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
739 pointerLabel_Command(command_UserEvent(ev), "request") == d->request) { 760 pointerLabel_Command(command_UserEvent(ev), "request") == d->request) {
740 checkResponse_DocumentWidget_(d); 761 checkResponse_DocumentWidget_(d);
741 d->state = ready_DocumentState; 762 d->state = ready_DocumentState;
763 setCachedResponse_History(history_App(), response_GmRequest(d->request));
742 iReleasePtr(&d->request); 764 iReleasePtr(&d->request);
743 postCommandf_App("document.changed url:%s", cstr_String(d->url)); 765 postCommandf_App("document.changed url:%s", cstr_String(d->url));
744 return iFalse; 766 return iFalse;