diff options
-rw-r--r-- | src/gmcerts.c | 14 | ||||
-rw-r--r-- | src/gmcerts.h | 5 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 186 |
3 files changed, 145 insertions, 60 deletions
diff --git a/src/gmcerts.c b/src/gmcerts.c index 96013392..b24a6d9c 100644 --- a/src/gmcerts.c +++ b/src/gmcerts.c | |||
@@ -170,6 +170,10 @@ void clearUse_GmIdentity(iGmIdentity *d) { | |||
170 | clear_StringSet(d->useUrls); | 170 | clear_StringSet(d->useUrls); |
171 | } | 171 | } |
172 | 172 | ||
173 | const iString *name_GmIdentity(const iGmIdentity *d) { | ||
174 | return collect_String(subject_TlsCertificate(d->cert)); | ||
175 | } | ||
176 | |||
173 | iDefineTypeConstruction(GmIdentity) | 177 | iDefineTypeConstruction(GmIdentity) |
174 | 178 | ||
175 | /*-----------------------------------------------------------------------------------------------*/ | 179 | /*-----------------------------------------------------------------------------------------------*/ |
@@ -481,3 +485,13 @@ const iPtrArray *identities_GmCerts(const iGmCerts *d) { | |||
481 | return &d->idents; | 485 | return &d->idents; |
482 | } | 486 | } |
483 | 487 | ||
488 | void signIn_GmCerts(iGmCerts *d, iGmIdentity *identity, const iString *url) { | ||
489 | signOut_GmCerts(d, url); | ||
490 | setUse_GmIdentity(identity, url, iTrue); | ||
491 | } | ||
492 | |||
493 | void signOut_GmCerts(iGmCerts *d, const iString *url) { | ||
494 | iForEach(PtrArray, i, &d->idents) { | ||
495 | setUse_GmIdentity(i.ptr, url, iFalse); | ||
496 | } | ||
497 | } | ||
diff --git a/src/gmcerts.h b/src/gmcerts.h index 4be23169..92a12a6a 100644 --- a/src/gmcerts.h +++ b/src/gmcerts.h | |||
@@ -50,6 +50,8 @@ iBool isUsedOn_GmIdentity (const iGmIdentity *, const iString *url); | |||
50 | void setUse_GmIdentity (iGmIdentity *, const iString *url, iBool use); | 50 | void setUse_GmIdentity (iGmIdentity *, const iString *url, iBool use); |
51 | void clearUse_GmIdentity (iGmIdentity *); | 51 | void clearUse_GmIdentity (iGmIdentity *); |
52 | 52 | ||
53 | const iString *name_GmIdentity(const iGmIdentity *); | ||
54 | |||
53 | /*----------------------------------------------------------------------------------------------*/ | 55 | /*----------------------------------------------------------------------------------------------*/ |
54 | 56 | ||
55 | iDeclareType(GmCerts) | 57 | iDeclareType(GmCerts) |
@@ -81,3 +83,6 @@ iGmIdentity * identity_GmCerts (iGmCerts *, unsigned int id); | |||
81 | const iGmIdentity * constIdentity_GmCerts (const iGmCerts *, unsigned int id); | 83 | const iGmIdentity * constIdentity_GmCerts (const iGmCerts *, unsigned int id); |
82 | const iGmIdentity * identityForUrl_GmCerts (const iGmCerts *, const iString *url); | 84 | const iGmIdentity * identityForUrl_GmCerts (const iGmCerts *, const iString *url); |
83 | const iPtrArray * identities_GmCerts (const iGmCerts *); | 85 | const iPtrArray * identities_GmCerts (const iGmCerts *); |
86 | |||
87 | void signIn_GmCerts (iGmCerts *, iGmIdentity *identity, const iString *url); | ||
88 | void signOut_GmCerts (iGmCerts *, const iString *url); | ||
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 325e8e2b..7d616469 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -49,6 +49,7 @@ struct Impl_SidebarItem { | |||
49 | iString meta; | 49 | iString meta; |
50 | iString url; | 50 | iString url; |
51 | iBool isSeparator; | 51 | iBool isSeparator; |
52 | iBool isSelected; | ||
52 | }; | 53 | }; |
53 | 54 | ||
54 | void init_SidebarItem(iSidebarItem *d) { | 55 | void init_SidebarItem(iSidebarItem *d) { |
@@ -59,6 +60,7 @@ void init_SidebarItem(iSidebarItem *d) { | |||
59 | init_String(&d->meta); | 60 | init_String(&d->meta); |
60 | init_String(&d->url); | 61 | init_String(&d->url); |
61 | d->isSeparator = iFalse; | 62 | d->isSeparator = iFalse; |
63 | d->isSelected = iFalse; | ||
62 | } | 64 | } |
63 | 65 | ||
64 | void deinit_SidebarItem(iSidebarItem *d) { | 66 | void deinit_SidebarItem(iSidebarItem *d) { |
@@ -218,9 +220,9 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
218 | break; | 220 | break; |
219 | } | 221 | } |
220 | case identities_SidebarMode: { | 222 | case identities_SidebarMode: { |
223 | const iString *tabUrl = url_DocumentWidget(document_App()); | ||
221 | iConstForEach(PtrArray, i, identities_GmCerts(certs_App())) { | 224 | iConstForEach(PtrArray, i, identities_GmCerts(certs_App())) { |
222 | const iGmIdentity *ident = i.ptr; | 225 | const iGmIdentity *ident = i.ptr; |
223 | /* icon, common name, used URLs, expiration, isTemp, free-form notes */ | ||
224 | iSidebarItem item; | 226 | iSidebarItem item; |
225 | init_SidebarItem(&item); | 227 | init_SidebarItem(&item); |
226 | item.id = index_PtrArrayConstIterator(&i); | 228 | item.id = index_PtrArrayConstIterator(&i); |
@@ -228,17 +230,26 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
228 | set_String(&item.label, collect_String(subject_TlsCertificate(ident->cert))); | 230 | set_String(&item.label, collect_String(subject_TlsCertificate(ident->cert))); |
229 | iDate until; | 231 | iDate until; |
230 | validUntil_TlsCertificate(ident->cert, &until); | 232 | validUntil_TlsCertificate(ident->cert, &until); |
231 | set_String( | 233 | const iBool isActive = isUsedOn_GmIdentity(ident, tabUrl); |
234 | format_String( | ||
232 | &item.meta, | 235 | &item.meta, |
233 | collectNewFormat_String( | 236 | "%s", |
234 | "%s \u2014 %s\n%s", | 237 | isActive ? "Using" |
235 | isUsed_GmIdentity(ident) | 238 | : isUsed_GmIdentity(ident) |
236 | ? format_CStr("Used on %zu URLs", size_StringSet(ident->useUrls)) | 239 | ? format_CStr("Used on %zu URLs", size_StringSet(ident->useUrls)) |
237 | : "Not used", | 240 | : "Not used"); |
238 | ident->flags & temporary_GmIdentityFlag | 241 | const char *expiry = |
239 | ? "Temporary" | 242 | ident->flags & temporary_GmIdentityFlag |
240 | : cstrCollect_String(format_Date(&until, "Expires %b %d, %Y")), | 243 | ? "Temporary" |
241 | cstr_String(&ident->notes))); | 244 | : cstrCollect_String(format_Date(&until, "Expires %b %d, %Y")); |
245 | if (isEmpty_String(&ident->notes)) { | ||
246 | appendFormat_String(&item.meta, "\n%s", expiry); | ||
247 | } | ||
248 | else { | ||
249 | appendFormat_String( | ||
250 | &item.meta, " \u2014 %s\n%s", expiry, cstr_String(&ident->notes)); | ||
251 | } | ||
252 | item.isSelected = isActive; | ||
242 | pushBack_Array(&d->items, &item); | 253 | pushBack_Array(&d->items, &item); |
243 | } | 254 | } |
244 | const iMenuItem menuItems[] = { | 255 | const iMenuItem menuItems[] = { |
@@ -287,7 +298,7 @@ void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) { | |||
287 | for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) { | 298 | for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) { |
288 | setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode); | 299 | setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode); |
289 | } | 300 | } |
290 | const float heights[max_SidebarMode] = { 1.333f, 1.333f, 3.0f, 1.2f }; | 301 | const float heights[max_SidebarMode] = { 1.333f, 1.333f, 3.5f, 1.2f }; |
291 | d->itemHeight = heights[mode] * lineHeight_Text(uiContent_FontId); | 302 | d->itemHeight = heights[mode] * lineHeight_Text(uiContent_FontId); |
292 | invalidate_SidebarWidget_(d); | 303 | invalidate_SidebarWidget_(d); |
293 | /* Restore previous scroll position. */ | 304 | /* Restore previous scroll position. */ |
@@ -388,6 +399,51 @@ static size_t itemIndex_SidebarWidget_(const iSidebarWidget *d, iInt2 pos) { | |||
388 | return index; | 399 | return index; |
389 | } | 400 | } |
390 | 401 | ||
402 | static const iSidebarItem *constHoverItem_SidebarWidget_(const iSidebarWidget *d) { | ||
403 | if (d->hoverItem < size_Array(&d->items)) { | ||
404 | return constAt_Array(&d->items, d->hoverItem); | ||
405 | } | ||
406 | return NULL; | ||
407 | } | ||
408 | |||
409 | static iSidebarItem *hoverItem_SidebarWidget_(iSidebarWidget *d) { | ||
410 | if (d->hoverItem < size_Array(&d->items)) { | ||
411 | return at_Array(&d->items, d->hoverItem); | ||
412 | } | ||
413 | return NULL; | ||
414 | } | ||
415 | |||
416 | static const iGmIdentity *constHoverIdentity_SidebarWidget_(const iSidebarWidget *d) { | ||
417 | if (d->mode == identities_SidebarMode) { | ||
418 | const iSidebarItem *hoverItem = constHoverItem_SidebarWidget_(d); | ||
419 | if (hoverItem) { | ||
420 | return identity_GmCerts(certs_App(), hoverItem->id); | ||
421 | } | ||
422 | } | ||
423 | return NULL; | ||
424 | } | ||
425 | |||
426 | static iGmIdentity *hoverIdentity_SidebarWidget_(const iSidebarWidget *d) { | ||
427 | return iConstCast(iGmIdentity *, constHoverIdentity_SidebarWidget_(d)); | ||
428 | } | ||
429 | |||
430 | static void setHoverItem_SidebarWidget_(iSidebarWidget *d, size_t index) { | ||
431 | if (index < size_Array(&d->items)) { | ||
432 | if (constValue_Array(&d->items, index, iSidebarItem).isSeparator) { | ||
433 | index = iInvalidPos; | ||
434 | } | ||
435 | } | ||
436 | if (d->hoverItem != index) { | ||
437 | d->hoverItem = index; | ||
438 | invalidate_SidebarWidget_(d); | ||
439 | } | ||
440 | } | ||
441 | |||
442 | static void updateMouseHover_SidebarWidget_(iSidebarWidget *d) { | ||
443 | const iInt2 mouse = mouseCoord_Window(get_Window()); | ||
444 | setHoverItem_SidebarWidget_(d, itemIndex_SidebarWidget_(d, mouse)); | ||
445 | } | ||
446 | |||
391 | static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) { | 447 | static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) { |
392 | const iSidebarItem *item = constAt_Array(&d->items, index); | 448 | const iSidebarItem *item = constAt_Array(&d->items, index); |
393 | switch (d->mode) { | 449 | switch (d->mode) { |
@@ -405,6 +461,18 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) { | |||
405 | break; | 461 | break; |
406 | } | 462 | } |
407 | case identities_SidebarMode: { | 463 | case identities_SidebarMode: { |
464 | iGmIdentity *ident = hoverIdentity_SidebarWidget_(d); | ||
465 | if (ident) { | ||
466 | const iString *tabUrl = url_DocumentWidget(document_App()); | ||
467 | if (isUsedOn_GmIdentity(ident, tabUrl)) { | ||
468 | signOut_GmCerts(certs_App(), tabUrl); | ||
469 | } | ||
470 | else { | ||
471 | signIn_GmCerts(certs_App(), ident, tabUrl); | ||
472 | } | ||
473 | updateItems_SidebarWidget_(d); | ||
474 | updateMouseHover_SidebarWidget_(d); | ||
475 | } | ||
408 | break; | 476 | break; |
409 | } | 477 | } |
410 | default: | 478 | default: |
@@ -427,20 +495,6 @@ static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) { | |||
427 | } | 495 | } |
428 | } | 496 | } |
429 | 497 | ||
430 | static const iSidebarItem *constHoverItem_SidebarWidget_(const iSidebarWidget *d) { | ||
431 | if (d->hoverItem < size_Array(&d->items)) { | ||
432 | return constAt_Array(&d->items, d->hoverItem); | ||
433 | } | ||
434 | return NULL; | ||
435 | } | ||
436 | |||
437 | static iSidebarItem *hoverItem_SidebarWidget_(iSidebarWidget *d) { | ||
438 | if (d->hoverItem < size_Array(&d->items)) { | ||
439 | return at_Array(&d->items, d->hoverItem); | ||
440 | } | ||
441 | return NULL; | ||
442 | } | ||
443 | |||
444 | void setWidth_SidebarWidget(iSidebarWidget *d, int width) { | 498 | void setWidth_SidebarWidget(iSidebarWidget *d, int width) { |
445 | iWidget *w = as_Widget(d); | 499 | iWidget *w = as_Widget(d); |
446 | width = iMax(30 * gap_UI, width); | 500 | width = iMax(30 * gap_UI, width); |
@@ -478,27 +532,6 @@ iBool handleBookmarkEditorCommands_SidebarWidget_(iWidget *editor, const char *c | |||
478 | return iFalse; | 532 | return iFalse; |
479 | } | 533 | } |
480 | 534 | ||
481 | static const iGmIdentity *constHoverIdentity_SidebarWidget_(const iSidebarWidget *d) { | ||
482 | if (d->mode == identities_SidebarMode) { | ||
483 | const iSidebarItem *hoverItem = constHoverItem_SidebarWidget_(d); | ||
484 | if (hoverItem) { | ||
485 | return identity_GmCerts(certs_App(), hoverItem->id); | ||
486 | } | ||
487 | } | ||
488 | return NULL; | ||
489 | } | ||
490 | |||
491 | static iGmIdentity *hoverIdentity_SidebarWidget_(const iSidebarWidget *d) { | ||
492 | return iConstCast(iGmIdentity *, constHoverIdentity_SidebarWidget_(d)); | ||
493 | } | ||
494 | |||
495 | static void setHoverItem_SidebarWidget_(iSidebarWidget *d, size_t index) { | ||
496 | if (d->hoverItem != index) { | ||
497 | d->hoverItem = index; | ||
498 | invalidate_SidebarWidget_(d); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) { | 535 | static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) { |
503 | iWidget *w = as_Widget(d); | 536 | iWidget *w = as_Widget(d); |
504 | /* Handle commands. */ | 537 | /* Handle commands. */ |
@@ -607,14 +640,17 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
607 | updateItems_SidebarWidget_(d); | 640 | updateItems_SidebarWidget_(d); |
608 | } | 641 | } |
609 | else if (isCommand_Widget(w, ev, "ident.use")) { | 642 | else if (isCommand_Widget(w, ev, "ident.use")) { |
610 | iGmIdentity *ident = hoverIdentity_SidebarWidget_(d); | 643 | iGmIdentity * ident = hoverIdentity_SidebarWidget_(d); |
644 | const iString *tabUrl = url_DocumentWidget(document_App()); | ||
611 | if (ident) { | 645 | if (ident) { |
612 | if (argLabel_Command(cmd, "clear")) { | 646 | if (argLabel_Command(cmd, "clear")) { |
613 | clearUse_GmIdentity(ident); | 647 | clearUse_GmIdentity(ident); |
614 | } | 648 | } |
649 | else if (arg_Command(cmd)) { | ||
650 | signIn_GmCerts(certs_App(), ident, tabUrl); | ||
651 | } | ||
615 | else { | 652 | else { |
616 | setUse_GmIdentity( | 653 | signOut_GmCerts(certs_App(), tabUrl); |
617 | ident, url_DocumentWidget(document_App()), arg_Command(cmd) != 0); | ||
618 | } | 654 | } |
619 | updateItems_SidebarWidget_(d); | 655 | updateItems_SidebarWidget_(d); |
620 | } | 656 | } |
@@ -629,6 +665,23 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
629 | return iTrue; | 665 | return iTrue; |
630 | } | 666 | } |
631 | else if (isCommand_Widget(w, ev, "ident.edit")) { | 667 | else if (isCommand_Widget(w, ev, "ident.edit")) { |
668 | const iGmIdentity *ident = constHoverIdentity_SidebarWidget_(d); | ||
669 | if (ident) { | ||
670 | makeValueInput_Widget(get_Window()->root, | ||
671 | &ident->notes, | ||
672 | uiHeading_ColorEscape "IDENTITY NOTES", | ||
673 | format_CStr("Notes about %s:", cstr_String(name_GmIdentity(ident))), | ||
674 | uiTextAction_ColorEscape "OK", | ||
675 | format_CStr("ident.setnotes ident:%p", ident)); | ||
676 | } | ||
677 | return iTrue; | ||
678 | } | ||
679 | else if (equal_Command(cmd, "ident.setnotes")) { | ||
680 | iGmIdentity *ident = pointerLabel_Command(cmd, "ident"); | ||
681 | if (ident) { | ||
682 | setCStr_String(&ident->notes, suffixPtr_Command(cmd, "value")); | ||
683 | updateItems_SidebarWidget_(d); | ||
684 | } | ||
632 | return iTrue; | 685 | return iTrue; |
633 | } | 686 | } |
634 | else if (isCommand_Widget(w, ev, "ident.pickicon")) { | 687 | else if (isCommand_Widget(w, ev, "ident.pickicon")) { |
@@ -907,20 +960,33 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) { | |||
907 | else if (d->mode == identities_SidebarMode) { | 960 | else if (d->mode == identities_SidebarMode) { |
908 | const int fg = isHover ? (isPressing ? uiTextPressed_ColorId | 961 | const int fg = isHover ? (isPressing ? uiTextPressed_ColorId |
909 | : uiTextFramelessHover_ColorId) | 962 | : uiTextFramelessHover_ColorId) |
910 | : uiText_ColorId; | 963 | : uiTextStrong_ColorId; |
964 | if (item->isSelected) { | ||
965 | drawRectThickness_Paint(&p, | ||
966 | adjusted_Rect(itemRect, zero_I2(), init_I2(-2, -1)), | ||
967 | gap_UI / 4, | ||
968 | isHover && isPressing ? uiTextPressed_ColorId | ||
969 | : uiIcon_ColorId); | ||
970 | } | ||
911 | iString icon; | 971 | iString icon; |
912 | initUnicodeN_String(&icon, &item->icon, 1); | 972 | initUnicodeN_String(&icon, &item->icon, 1); |
913 | drawRange_Text(font, add_I2(topLeft_Rect(itemRect), init_I2(3 * gap_UI, 0)), | 973 | iInt2 cPos = topLeft_Rect(itemRect); |
914 | iconColor, range_String(&icon)); | 974 | addv_I2(&cPos, |
975 | init_I2(3 * gap_UI, | ||
976 | (d->itemHeight - lineHeight_Text(default_FontId) * 2 - | ||
977 | lineHeight_Text(font)) / 2)); | ||
978 | const int metaFg = isHover ? (isPressing ? uiTextPressed_ColorId | ||
979 | : uiTextFramelessHover_ColorId) | ||
980 | : uiText_ColorId; | ||
981 | drawRange_Text( | ||
982 | font, cPos, item->isSelected ? iconColor : metaFg, range_String(&icon)); | ||
915 | deinit_String(&icon); | 983 | deinit_String(&icon); |
916 | drawRange_Text(font, add_I2(topLeft_Rect(itemRect), init_I2(10 * gap_UI, 0)), | 984 | drawRange_Text(font, add_I2(cPos, init_I2(7 * gap_UI, 0)), |
917 | fg, range_String(&item->label)); | 985 | fg, range_String(&item->label)); |
918 | drawRange_Text( | 986 | drawRange_Text( |
919 | font, | 987 | default_FontId, |
920 | add_I2(topLeft_Rect(itemRect), init_I2(3 * gap_UI, lineHeight_Text(font))), | 988 | add_I2(cPos, init_I2(0, lineHeight_Text(font))), |
921 | isHover | 989 | metaFg, |
922 | ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) | ||
923 | : uiAnnotation_ColorId, | ||
924 | range_String(&item->meta)); | 990 | range_String(&item->meta)); |
925 | } | 991 | } |
926 | unsetClip_Paint(&p); | 992 | unsetClip_Paint(&p); |