=> c58985ed3105ff7fc29fc0d53ba81ba55882e05e
[1mdiff --git a/res/about/version.gmi b/res/about/version.gmi[m [1mindex 020373e4..b5750c8c 100644[m [1m--- a/res/about/version.gmi[m [1m+++ b/res/about/version.gmi[m [36m@@ -8,6 +8,8 @@[m [m ## 1.8.3[m * Fixed clicking on UI elements that are over the page top banner. The banner would always get clicked instead.[m [32m+[m[32m* Titan upload identity is remembered as a site-specific setting. It is no longer affected by selections in the Identities sidebar.[m [32m+[m[32m* macOS: Fixed updating items in native menus, e.g., upload identity selection.[m [m ## 1.8.2[m * Fixed encoding of `+` characters in URLs as per RFC 3986.[m [1mdiff --git a/src/gmcerts.c b/src/gmcerts.c[m [1mindex 36fd7d55..f95fea7d 100644[m [1m--- a/src/gmcerts.c[m [1m+++ b/src/gmcerts.c[m [36m@@ -295,6 +295,9 @@[m [mstatic void loadIdentities_GmCerts_(iGmCerts *d) {[m }[m [m iGmIdentity *findIdentity_GmCerts(iGmCerts *d, const iBlock *fingerprint) {[m [32m+[m[32m if (isEmpty_Block(fingerprint)) {[m [32m+[m[32m return NULL;[m [32m+[m[32m }[m iForEach(PtrArray, i, &d->idents) {[m iGmIdentity *ident = i.ptr;[m if (cmp_Block(fingerprint, &ident->fingerprint) == 0) { /* TODO: could use a hash */[m [36m@@ -549,6 +552,9 @@[m [mconst iGmIdentity *constIdentity_GmCerts(const iGmCerts *d, unsigned int id) {[m }[m [m const iGmIdentity *identityForUrl_GmCerts(const iGmCerts *d, const iString *url) {[m [32m+[m[32m if (isEmpty_String(url)) {[m [32m+[m[32m return NULL;[m [32m+[m[32m }[m lock_Mutex(d->mtx);[m const iGmIdentity *found = NULL;[m iConstForEach(PtrArray, i, &d->idents) {[m [1mdiff --git a/src/sitespec.c b/src/sitespec.c[m [1mindex 0332af2d..6f4546f0 100644[m [1m--- a/src/sitespec.c[m [1m+++ b/src/sitespec.c[m [36m@@ -33,17 +33,19 @@[m [miDeclareObjectConstruction(SiteParams)[m struct Impl_SiteParams {[m iObject object;[m uint16_t titanPort;[m [32m+[m[32m iString titanIdentity; /* fingerprint */[m int dismissWarnings;[m /* TODO: theme seed, style settings */[m };[m [m void init_SiteParams(iSiteParams *d) {[m [31m- d->titanPort = 0; /* undefined */[m [32m+[m[32m d->titanPort = 0; /* undefined */[m [32m+[m[32m init_String(&d->titanIdentity);[m d->dismissWarnings = 0;[m }[m [m void deinit_SiteParams(iSiteParams *d) {[m [31m- iUnused(d);[m [32m+[m[32m deinit_String(&d->titanIdentity);[m }[m [m iDefineClass(SiteParams)[m [36m@@ -122,6 +124,9 @@[m [mstatic void handleIniKeyValue_SiteSpec_(void *context, const iString *table, con[m if (!cmp_String(key, "titanPort")) {[m d->loadParams->titanPort = number_TomlValue(value);[m }[m [32m+[m[32m else if (!cmp_String(key, "titanIdentity") && value->type == string_TomlType) {[m [32m+[m[32m set_String(&d->loadParams->titanIdentity, value->value.string);[m [32m+[m[32m }[m else if (!cmp_String(key, "dismissWarnings") && value->type == int64_TomlType) {[m d->loadParams->dismissWarnings = value->value.int64;[m }[m [36m@@ -152,6 +157,10 @@[m [mstatic void save_SiteSpec_(iSiteSpec *d) {[m if (params->titanPort) {[m appendFormat_String(buf, "titanPort = %u\n", params->titanPort);[m }[m [32m+[m[32m if (!isEmpty_String(¶ms->titanIdentity)) {[m [32m+[m[32m appendFormat_String([m [32m+[m[32m buf, "titanIdentity = \"%s\"\n", cstr_String(¶ms->titanIdentity));[m [32m+[m[32m }[m if (params->dismissWarnings) {[m appendFormat_String(buf, "dismissWarnings = 0x%x\n", params->dismissWarnings);[m }[m [36m@@ -205,6 +214,30 @@[m [mvoid setValue_SiteSpec(const iString *site, enum iSiteSpecKey key, int value) {[m }[m }[m [m [32m+[m[32mvoid setValueString_SiteSpec(const iString *site, enum iSiteSpecKey key, const iString *value) {[m [32m+[m[32m iSiteSpec *d = &siteSpec_;[m [32m+[m[32m const iString *hashKey = collect_String(lower_String(site));[m [32m+[m[32m iSiteParams *params = value_StringHash(&d->sites, hashKey);[m [32m+[m[32m if (!params) {[m [32m+[m[32m params = new_SiteParams();[m [32m+[m[32m insert_StringHash(&d->sites, hashKey, params);[m [32m+[m[32m }[m [32m+[m[32m iBool needSave = iFalse;[m [32m+[m[32m switch (key) {[m [32m+[m[32m case titanIdentity_SiteSpecKey:[m [32m+[m[32m if (!equal_String(¶ms->titanIdentity, value)) {[m [32m+[m[32m needSave = iTrue;[m [32m+[m[32m set_String(¶ms->titanIdentity, value);[m [32m+[m[32m }[m [32m+[m[32m break;[m [32m+[m[32m default:[m [32m+[m[32m break;[m [32m+[m[32m }[m [32m+[m[32m if (needSave) {[m [32m+[m[32m save_SiteSpec_(d);[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m int value_SiteSpec(const iString *site, enum iSiteSpecKey key) {[m iSiteSpec *d = &siteSpec_;[m const iSiteParams *params = constValue_StringHash(&d->sites, collect_String(lower_String(site)));[m [36m@@ -220,3 +253,17 @@[m [mint value_SiteSpec(const iString *site, enum iSiteSpecKey key) {[m return 0;[m } [m }[m [32m+[m [32m+[m[32mconst iString *valueString_SiteSpec(const iString *site, enum iSiteSpecKey key) {[m [32m+[m[32m iSiteSpec *d = &siteSpec_;[m [32m+[m[32m const iSiteParams *params = constValue_StringHash(&d->sites, collect_String(lower_String(site)));[m [32m+[m[32m if (!params) {[m [32m+[m[32m return 0;[m [32m+[m[32m }[m [32m+[m[32m switch (key) {[m [32m+[m[32m case titanIdentity_SiteSpecKey:[m [32m+[m[32m return ¶ms->titanIdentity;[m [32m+[m[32m default:[m [32m+[m[32m return collectNew_String();[m [32m+[m[32m }[m[41m [m [32m+[m[32m}[m [1mdiff --git a/src/sitespec.h b/src/sitespec.h[m [1mindex 6b64f073..5adaeb8c 100644[m [1m--- a/src/sitespec.h[m [1m+++ b/src/sitespec.h[m [36m@@ -28,11 +28,16 @@[m [miDeclareType(SiteSpec)[m [m enum iSiteSpecKey {[m titanPort_SiteSpecKey,[m [32m+[m[32m titanIdentity_SiteSpecKey,[m dismissWarnings_SiteSpecKey,[m };[m [m void init_SiteSpec (const char *saveDir);[m void deinit_SiteSpec (void);[m [m [31m-void setValue_SiteSpec (const iString *site, enum iSiteSpecKey key, int value); /* changes saved immediately */[m [31m-int value_SiteSpec (const iString *site, enum iSiteSpecKey key);[m [32m+[m[32m/* changes saved immediately */[m [32m+[m[32mvoid setValue_SiteSpec (const iString *site, enum iSiteSpecKey key, int value);[m[41m [m [32m+[m[32mvoid setValueString_SiteSpec (const iString *site, enum iSiteSpecKey key, const iString *value);[m [32m+[m [32m+[m[32mint value_SiteSpec (const iString *site, enum iSiteSpecKey key);[m [32m+[m[32mconst iString * valueString_SiteSpec (const iString *site, enum iSiteSpecKey key);[m [1mdiff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c[m [1mindex 90df1958..bad00071 100644[m [1m--- a/src/ui/uploadwidget.c[m [1m+++ b/src/ui/uploadwidget.c[m [36m@@ -45,7 +45,7 @@[m [miDefineObjectConstruction(UploadWidget)[m [m enum iUploadIdentity {[m none_UploadIdentity,[m [31m- defaultForUrl_UploadIdentity,[m [32m+[m[32m defaultForSite_UploadIdentity,[m dropdown_UploadIdentity,[m };[m [m [36m@@ -104,9 +104,16 @@[m [mstatic void updateInputMaxHeight_UploadWidget_(iUploadWidget *d) {[m (avail - inputPos.y) / lineHeight_Text(font_InputWidget(d->input))));[m }[m [m [32m+[m[32mstatic const iGmIdentity *titanIdentityForUrl_(const iString *url) {[m [32m+[m[32m return findIdentity_GmCerts([m [32m+[m[32m certs_App(),[m [32m+[m[32m collect_Block(hexDecode_Rangecc(range_String(valueString_SiteSpec([m [32m+[m[32m collectNewRange_String(urlRoot_String(url)), titanIdentity_SiteSpecKey)))));[m [32m+[m[32m}[m [32m+[m static const iArray *makeIdentityItems_UploadWidget_(const iUploadWidget *d) {[m iArray *items = collectNew_Array(sizeof(iMenuItem));[m [31m- const iGmIdentity *urlId = identityForUrl_GmCerts(certs_App(), &d->url);[m [32m+[m[32m const iGmIdentity *urlId = titanIdentityForUrl_(&d->url);[m pushBack_Array(items,[m &(iMenuItem){ format_CStr("${dlg.upload.id.default} (%s)",[m urlId ? cstr_String(name_GmIdentity(urlId))[m [36m@@ -147,7 +154,7 @@[m [mvoid init_UploadWidget(iUploadWidget *d) {[m d->request = NULL;[m init_String(&d->filePath);[m d->fileSize = 0;[m [31m- d->idMode = defaultForUrl_UploadIdentity;[m [32m+[m[32m d->idMode = defaultForSite_UploadIdentity;[m init_Block(&d->idFingerprint, 0);[m const iMenuItem actions[] = {[m { "${upload.port}", 0, 0, "upload.setport" },[m [36m@@ -289,16 +296,22 @@[m [mvoid deinit_UploadWidget(iUploadWidget *d) {[m [m static void remakeIdentityItems_UploadWidget_(iUploadWidget *d) {[m iWidget *dropMenu = findChild_Widget(findChild_Widget(as_Widget(d), "upload.id"), "menu");[m [31m- releaseChildren_Widget(dropMenu);[m const iArray *items = makeIdentityItems_UploadWidget_(d);[m [31m- makeMenuItems_Widget(dropMenu, constData_Array(items), size_Array(items));[m [32m+[m[32m /* TODO: Make the following a utility method. */[m [32m+[m[32m if (flags_Widget(dropMenu) & nativeMenu_WidgetFlag) {[m [32m+[m[32m setNativeMenuItems_Widget(dropMenu, constData_Array(items), size_Array(items));[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m releaseChildren_Widget(dropMenu);[m [32m+[m[32m makeMenuItems_Widget(dropMenu, constData_Array(items), size_Array(items));[m [32m+[m[32m }[m }[m [m static void updateIdentityDropdown_UploadWidget_(iUploadWidget *d) {[m updateDropdownSelection_LabelWidget([m findChild_Widget(as_Widget(d), "upload.id"),[m d->idMode == none_UploadIdentity ? " arg:0"[m [31m- : d->idMode == defaultForUrl_UploadIdentity[m [32m+[m[32m : d->idMode == defaultForSite_UploadIdentity[m ? " arg:1"[m : format_CStr(" fp:%s", cstrCollect_String(hexEncode_Block(&d->idFingerprint))));[m }[m [36m@@ -422,7 +435,7 @@[m [mstatic iBool processEvent_UploadWidget_(iUploadWidget *d, const SDL_Event *ev) {[m }[m else if (arg_Command(cmd)) {[m clear_Block(&d->idFingerprint);[m [31m- d->idMode = defaultForUrl_UploadIdentity;[m [32m+[m[32m d->idMode = defaultForSite_UploadIdentity;[m }[m else {[m clear_Block(&d->idFingerprint);[m [36m@@ -452,19 +465,27 @@[m [mstatic iBool processEvent_UploadWidget_(iUploadWidget *d, const SDL_Event *ev) {[m setSendProgressFunc_GmRequest(d->request, updateProgress_UploadWidget_);[m setUserData_Object(d->request, d);[m setUrl_GmRequest(d->request, &d->url);[m [32m+[m[32m const iString *site = collectNewRange_String(urlRoot_String(&d->url));[m switch (d->idMode) {[m [31m- case defaultForUrl_UploadIdentity:[m [31m- break; /* GmRequest handles it */[m case none_UploadIdentity:[m [31m- setIdentity_GmRequest(d->request, NULL);[m [32m+[m[32m /* Ensure no identity will be used for this specific URL. */[m signOut_GmCerts(certs_App(), url_GmRequest(d->request));[m [32m+[m[32m setValueString_SiteSpec(site, titanIdentity_SiteSpecKey, collectNew_String());[m break;[m case dropdown_UploadIdentity: {[m iGmIdentity *ident = findIdentity_GmCerts(certs_App(), &d->idFingerprint);[m [31m- setIdentity_GmRequest(d->request, ident);[m [31m- signIn_GmCerts(certs_App(), ident, url_GmRequest(d->request));[m [32m+[m[32m if (ident) {[m [32m+[m[32m setValueString_SiteSpec(site,[m [32m+[m[32m titanIdentity_SiteSpecKey,[m [32m+[m[32m collect_String(hexEncode_Block(&ident->fingerprint)));[m [32m+[m[32m }[m break;[m }[m [32m+[m[32m default:[m [32m+[m[32m break;[m [32m+[m[32m }[m [32m+[m[32m if (d->idMode != none_UploadIdentity) {[m [32m+[m[32m setIdentity_GmRequest(d->request, titanIdentityForUrl_(&d->url));[m }[m if (isText) {[m /* Uploading text. */[m [1mdiff --git a/src/ui/util.c b/src/ui/util.c[m [1mindex 2624bf2b..0a9dde0c 100644[m [1m--- a/src/ui/util.c[m [1m+++ b/src/ui/util.c[m [36m@@ -809,14 +809,27 @@[m [mstatic void deleteMenuItems_(iArray *items) {[m delete_Array(items);[m }[m [m [31m-iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) {[m [31m- iWidget *menu = new_Widget();[m [32m+[m[32mvoid releaseNativeMenu_Widget(iWidget *d) {[m #if defined (iHaveNativeContextMenus)[m [31m- setFlags_Widget(menu, hidden_WidgetFlag | nativeMenu_WidgetFlag, iTrue);[m [32m+[m[32m iArray *items = userData_Object(d);[m [32m+[m[32m if (items) {[m [32m+[m[32m iAssert(flags_Widget(d) & nativeMenu_WidgetFlag);[m [32m+[m[32m iAssert(items);[m [32m+[m[32m deleteMenuItems_(items);[m [32m+[m[32m setUserData_Object(d, NULL);[m [32m+[m[32m }[m [32m+[m[32m#else[m [32m+[m[32m iUnused(d);[m [32m+[m[32m#endif[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid setNativeMenuItems_Widget(iWidget *menu, const iMenuItem *items, size_t n) {[m [32m+[m[32m#if defined (iHaveNativeContextMenus)[m [32m+[m[32m iAssert(flags_Widget(menu) & nativeMenu_WidgetFlag);[m [32m+[m[32m releaseNativeMenu_Widget(menu);[m setUserData_Object(menu, deepCopyMenuItems_(menu, items, n));[m [31m- addChild_Widget(parent, menu);[m [31m- iRelease(menu); /* owned by parent now */[m /* Keyboard shortcuts still need to triggerable via the menu, although the items don't exist. */ {[m [32m+[m[32m releaseChildren_Widget(menu);[m for (size_t i = 0; i < n; i++) {[m const iMenuItem *item = &items[i];[m if (item->key) {[m [36m@@ -824,6 +837,17 @@[m [miWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) {[m }[m }[m }[m [32m+[m[32m#endif[m[41m [m [32m+[m[32m}[m [32m+[m [32m+[m[32miWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) {[m [32m+[m[32m iWidget *menu = new_Widget();[m [32m+[m[32m#if defined (iHaveNativeContextMenus)[m [32m+[m[32m setFlags_Widget(menu, hidden_WidgetFlag | nativeMenu_WidgetFlag, iTrue);[m [32m+[m[32m addChild_Widget(parent, menu);[m [32m+[m[32m iRelease(menu); /* owned by parent now */[m [32m+[m[32m setUserData_Object(menu, NULL);[m [32m+[m[32m setNativeMenuItems_Widget(menu, items, n);[m #else[m /* Non-native custom popup menu. This may still be displayed inside a separate window. */[m setDrawBufferEnabled_Widget(menu, iTrue);[m [36m@@ -990,18 +1014,6 @@[m [miLocalDef iBool isUsingMenuPopupWindows_(void) {[m #endif[m }[m [m [31m-void releaseNativeMenu_Widget(iWidget *d) {[m [31m-#if defined (iHaveNativeContextMenus)[m [31m- iArray *items = userData_Object(d);[m [31m- iAssert(flags_Widget(d) & nativeMenu_WidgetFlag);[m [31m- iAssert(items);[m [31m- deleteMenuItems_(items);[m [31m- setUserData_Object(d, NULL);[m [31m-#else[m [31m- iUnused(d);[m [31m-#endif[m [31m-}[m [31m-[m void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) {[m const iBool postCommands = (menuOpenFlags & postCommands_MenuOpenFlags) != 0;[m #if defined (iHaveNativeContextMenus)[m [36m@@ -1263,8 +1275,8 @@[m [mvoid updateDropdownSelection_LabelWidget(iLabelWidget *dropButton, const char *s[m iMenuItem *item = findNativeMenuItem_Widget(menu, selectedCommand);[m if (item) {[m setSelected_NativeMenuItem(item, iTrue);[m [31m- updateText_LabelWidget(dropButton,[m [31m- removeMenuItemLabelPrefixes_String(collectNewCStr_String(item->label)));[m [32m+[m[32m updateText_LabelWidget([m [32m+[m[32m dropButton, removeMenuItemLabelPrefixes_String(collectNewCStr_String(item->label)));[m }[m return;[m }[m [1mdiff --git a/src/ui/util.h b/src/ui/util.h[m [1mindex cf96dfe4..52b3a692 100644[m [1m--- a/src/ui/util.h[m [1m+++ b/src/ui/util.h[m [36m@@ -249,6 +249,7 @@[m [mvoid setMenuItemDisabled_Widget (iWidget *menu, const char *comm[m void setMenuItemDisabledByIndex_Widget(iWidget *menu, size_t index, iBool disable);[m void setMenuItemLabel_Widget (iWidget *menu, const char *command, const char *newLabel);[m void setMenuItemLabelByIndex_Widget (iWidget *menu, size_t index, const char *newLabel);[m [32m+[m[32mvoid setNativeMenuItems_Widget (iWidget *, const iMenuItem *items, size_t n);[m [m int checkContextMenu_Widget (iWidget *, const SDL_Event *ev); /* see macro below */[m [m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).