[PATCH v3 0/2] MR2740: winemenubuilder: Create .desktop files for programs that open URIs
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22904 -- v3: winecfg: Mention protocol associations. winemenubuilder: Create .desktop files for programs that open URIs. https://gitlab.winehq.org/wine/wine/-/merge_requests/2740
From: Alex Henrie <alexhenrie24(a)gmail.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22904 --- programs/winemenubuilder/winemenubuilder.c | 164 ++++++++++++--------- 1 file changed, 96 insertions(+), 68 deletions(-) diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index ae657d87bb1..d8ab78d1de8 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -1833,10 +1833,13 @@ static BOOL has_association_changed(LPCWSTR extensionW, const WCHAR *mimeType, c ret = TRUE; heap_free(value); - value = reg_get_valW(assocKey, extensionW, L"ProgID"); - if (!value || wcscmp(value, progId)) - ret = TRUE; - heap_free(value); + if (progId) + { + value = reg_get_valW(assocKey, extensionW, L"ProgID"); + if (!value || wcscmp(value, progId)) + ret = TRUE; + heap_free(value); + } value = reg_get_valW(assocKey, extensionW, L"AppName"); if (!value || wcscmp(value, appName)) @@ -1880,7 +1883,7 @@ static void update_association(LPCWSTR extension, const WCHAR *mimeType, const W } RegSetValueExW(subkey, L"MimeType", 0, REG_SZ, (const BYTE*) mimeType, (lstrlenW(mimeType) + 1) * sizeof(WCHAR)); - RegSetValueExW(subkey, L"ProgID", 0, REG_SZ, (const BYTE*) progId, (lstrlenW(progId) + 1) * sizeof(WCHAR)); + if (progId) RegSetValueExW(subkey, L"ProgID", 0, REG_SZ, (const BYTE*) progId, (lstrlenW(progId) + 1) * sizeof(WCHAR)); RegSetValueExW(subkey, L"AppName", 0, REG_SZ, (const BYTE*) appName, (lstrlenW(appName) + 1) * sizeof(WCHAR)); RegSetValueExW(subkey, L"DesktopFile", 0, REG_SZ, (const BYTE*) desktopFile, (lstrlenW(desktopFile) + 1) * sizeof(WCHAR)); if (openWithIcon) @@ -1964,12 +1967,16 @@ static BOOL write_freedesktop_mime_type_entry(const WCHAR *packages_dir, const W return ret; } -static BOOL is_extension_banned(LPCWSTR extension) +static BOOL is_type_banned(const WCHAR *win_type) { /* These are managed through external tools like wine.desktop, to evade malware created file type associations */ - if (!wcsicmp(extension, L".com") || - !wcsicmp(extension, L".exe") || - !wcsicmp(extension, L".msi")) + if (!wcsicmp(win_type, L".com") || + !wcsicmp(win_type, L".exe") || + !wcsicmp(win_type, L".msi")) + return TRUE; + /* Associating a program with the file URI scheme is like associating it with all file types, which is not allowed + * for the same reasons */ + if (!wcsicmp(win_type, L"file")) return TRUE; return FALSE; } @@ -2043,11 +2050,15 @@ static BOOL write_freedesktop_association_entry(const WCHAR *desktopPath, const if (prefix) { char *path = wine_get_unix_file_name( prefix ); - fprintf(desktop, "Exec=env WINEPREFIX=\"%s\" wine start /ProgIDOpen %s %%f\n", path, escape(progId)); + fprintf(desktop, "Exec=env WINEPREFIX=\"%s\" wine start ", path); heap_free( path ); } else - fprintf(desktop, "Exec=wine start /ProgIDOpen %s %%f\n", escape(progId)); + fprintf(desktop, "Exec=wine start "); + if (progId) /* file association */ + fprintf(desktop, "/ProgIDOpen %s %%f\n", escape(progId)); + else /* protocol association */ + fprintf(desktop, "%%u\n"); fprintf(desktop, "NoDisplay=true\n"); fprintf(desktop, "StartupNotify=true\n"); if (openWithIcon) @@ -2075,12 +2086,19 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic for (i = 0; ; i++) { - WCHAR *extensionW; + WCHAR *winTypeW; + BOOL isProtocolType = FALSE; - if (!(extensionW = reg_enum_keyW(HKEY_CLASSES_ROOT, i))) + if (!(winTypeW = reg_enum_keyW(HKEY_CLASSES_ROOT, i))) break; - if (extensionW[0] == '.' && !is_extension_banned(extensionW)) + if (winTypeW[0] != '.') + { + if (RegGetValueW(HKEY_CLASSES_ROOT, winTypeW, L"URL Protocol", RRF_RT_ANY, NULL, NULL, NULL) == ERROR_SUCCESS) + isProtocolType = TRUE; + } + + if ((winTypeW[0] == '.' || isProtocolType) && !is_type_banned(winTypeW)) { WCHAR *commandW = NULL; WCHAR *executableW = NULL; @@ -2094,7 +2112,7 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic WCHAR *mimeProgId = NULL; struct rb_string_entry *entry; - commandW = assoc_query(ASSOCSTR_COMMAND, extensionW, L"open"); + commandW = assoc_query(ASSOCSTR_COMMAND, winTypeW, L"open"); if (commandW == NULL) /* no command => no application is associated */ goto end; @@ -2103,78 +2121,88 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic /* command is on the exclude list => desktop integration is not desirable */ goto end; - wcslwr(extensionW); - friendlyDocNameW = assoc_query(ASSOCSTR_FRIENDLYDOCNAME, extensionW, NULL); + iconW = assoc_query(ASSOCSTR_DEFAULTICON, winTypeW, NULL); - iconW = assoc_query(ASSOCSTR_DEFAULTICON, extensionW, NULL); + if (isProtocolType) + { + mimeType = heap_wprintf(L"x-scheme-handler/%s", winTypeW); + } + else + { + wcslwr(winTypeW); + friendlyDocNameW = assoc_query(ASSOCSTR_FRIENDLYDOCNAME, winTypeW, NULL); - contentTypeW = assoc_query(ASSOCSTR_CONTENTTYPE, extensionW, NULL); - if (contentTypeW) - wcslwr(contentTypeW); + contentTypeW = assoc_query(ASSOCSTR_CONTENTTYPE, winTypeW, NULL); + if (contentTypeW) + wcslwr(contentTypeW); - mimeType = freedesktop_mime_type_for_extension(&nativeMimeTypes, extensionW); + mimeType = freedesktop_mime_type_for_extension(&nativeMimeTypes, winTypeW); - if (mimeType == NULL) - { - if (contentTypeW != NULL && wcschr(contentTypeW, '/')) - mimeType = xwcsdup(contentTypeW); - else if (!(mimeType = get_special_mime_type(extensionW))) - mimeType = heap_wprintf(L"application/x-wine-extension-%s", &extensionW[1]); - - /* GNOME seems to ignore the <icon> tag in MIME packages, - * and the default name is more intuitive anyway. - */ - if (iconW) + if (mimeType == NULL) { - WCHAR *flattened_mime = slashes_to_minuses(mimeType); - int index = 0; - WCHAR *comma = wcsrchr(iconW, ','); - if (comma) + if (contentTypeW != NULL && wcschr(contentTypeW, '/')) + mimeType = xwcsdup(contentTypeW); + else if (!(mimeType = get_special_mime_type(winTypeW))) + mimeType = heap_wprintf(L"application/x-wine-extension-%s", &winTypeW[1]); + + /* GNOME seems to ignore the <icon> tag in MIME packages, + * and the default name is more intuitive anyway. + */ + if (iconW) { - *comma = 0; - index = wcstol(comma + 1, NULL, 10); + WCHAR *flattened_mime = slashes_to_minuses(mimeType); + int index = 0; + WCHAR *comma = wcsrchr(iconW, ','); + if (comma) + { + *comma = 0; + index = wcstol(comma + 1, NULL, 10); + } + extract_icon(iconW, index, flattened_mime, FALSE); + heap_free(flattened_mime); } - extract_icon(iconW, index, flattened_mime, FALSE); - heap_free(flattened_mime); + + write_freedesktop_mime_type_entry(packages_dir, winTypeW, mimeType, friendlyDocNameW); + hasChanged = TRUE; } - write_freedesktop_mime_type_entry(packages_dir, extensionW, mimeType, friendlyDocNameW); - hasChanged = TRUE; + progIdW = reg_get_valW(HKEY_CLASSES_ROOT, winTypeW, NULL); + if (!progIdW) goto end; /* no progID => not a file type association */ + + /* Do not allow duplicate ProgIDs for a MIME type, it causes unnecessary duplication in Open dialogs */ + mimeProgId = heap_wprintf(L"%s=>%s", mimeType, progIdW); + if (wine_rb_get(&mimeProgidTree, mimeProgId)) + { + heap_free(mimeProgId); + goto end; + } + entry = xmalloc(sizeof(struct rb_string_entry)); + entry->string = mimeProgId; + if (wine_rb_put(&mimeProgidTree, mimeProgId, &entry->entry)) + { + WINE_ERR("error updating rb tree\n"); + goto end; + } } - executableW = assoc_query(ASSOCSTR_EXECUTABLE, extensionW, L"open"); + executableW = assoc_query(ASSOCSTR_EXECUTABLE, winTypeW, L"open"); if (executableW) openWithIcon = compute_native_identifier(0, executableW, NULL); - friendlyAppName = assoc_query(ASSOCSTR_FRIENDLYAPPNAME, extensionW, L"open"); + friendlyAppName = assoc_query(ASSOCSTR_FRIENDLYAPPNAME, winTypeW, L"open"); if (!friendlyAppName) friendlyAppName = L"A Wine application"; - progIdW = reg_get_valW(HKEY_CLASSES_ROOT, extensionW, NULL); - if (!progIdW) goto end; /* no progID => not a file type association */ - - /* Do not allow duplicate ProgIDs for a MIME type, it causes unnecessary duplication in Open dialogs */ - mimeProgId = heap_wprintf(L"%s=>%s", mimeType, progIdW); - if (wine_rb_get(&mimeProgidTree, mimeProgId)) + if (has_association_changed(winTypeW, mimeType, progIdW, friendlyAppName, openWithIcon)) { - heap_free(mimeProgId); - goto end; - } - entry = xmalloc(sizeof(struct rb_string_entry)); - entry->string = mimeProgId; - if (wine_rb_put(&mimeProgidTree, mimeProgId, &entry->entry)) - { - WINE_ERR("error updating rb tree\n"); - goto end; - } - - if (has_association_changed(extensionW, mimeType, progIdW, friendlyAppName, openWithIcon)) - { - WCHAR *desktopPath = heap_wprintf(L"%s\\wine-extension-%s.desktop", - applications_dir, extensionW + 1 ); + WCHAR *desktopPath; + if (isProtocolType) + desktopPath = heap_wprintf(L"%s\\wine-protocol-%s.desktop", applications_dir, winTypeW); + else + desktopPath = heap_wprintf(L"%s\\wine-extension-%s.desktop", applications_dir, winTypeW + 1); if (write_freedesktop_association_entry(desktopPath, friendlyAppName, mimeType, progIdW, openWithIcon)) { hasChanged = TRUE; - update_association(extensionW, mimeType, progIdW, friendlyAppName, desktopPath, openWithIcon); + update_association(winTypeW, mimeType, progIdW, friendlyAppName, desktopPath, openWithIcon); } heap_free(desktopPath); } @@ -2191,7 +2219,7 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic heap_free(mimeType); heap_free(progIdW); } - heap_free(extensionW); + heap_free(winTypeW); } wine_rb_destroy(&mimeProgidTree, winemenubuilder_rb_destroy, NULL); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2740
From: Alex Henrie <alexhenrie24(a)gmail.com> --- programs/winecfg/winecfg.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/winecfg/winecfg.rc b/programs/winecfg/winecfg.rc index b2b51ffbf70..48fe0b9f9f0 100644 --- a/programs/winecfg/winecfg.rc +++ b/programs/winecfg/winecfg.rc @@ -307,7 +307,7 @@ BEGIN CONTROL "",IDC_SYSPARAM_SIZE_UD,UPDOWN_CLASSA,UDS_SETBUDDYINT | UDS_ALIGNRIGHT | WS_DISABLED, 185,75,15,13 GROUPBOX "MIME types",IDC_STATIC,8,95,244,23 - CONTROL "Manage file &associations",IDC_ENABLE_FILE_ASSOCIATIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,105,230,10 + CONTROL "Manage file and protocol &associations",IDC_ENABLE_FILE_ASSOCIATIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,105,230,10 PUSHBUTTON "&Font...",IDC_SYSPARAM_FONT,190,75,55,13,WS_DISABLED GROUPBOX "Folders",IDC_STATIC,8,120,244,94 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2740
On Sun May 7 21:56:46 2023 +0000, Zebediah Figura wrote:
I agree that Wine shouldn't advertise `file:` URI handlers to the desktop environment, because Windows programs can't use Unix file paths. I just pushed a new patch that adds the `file` "protocol" to the blacklist. We may not want to translate protocol handlers for file: for other reasons, but it's worth pointing out that Wine actually does allow using Unix paths. You can try it yourself by opening cmd and running `explorer /some/unix/path/`. [Note that this translation isn't specific to cmd or anything; it's done at the ntdll level.] That's really interesting, I didn't know that Wine could do that. I tried it and `explorer file:///some/unix/path/` works too.
However, as you alluded to, there is a bigger reason why we don't want desktop integration for file URIs: Associating a program with the file "protocol" is like associating it with all file types, which would be obnoxious and lend itself to the same kinds of abuse as associating a program with .com, .exe, or .msi. (Incidentally, desktop integration for third-party associations with .bat really shouldn't be allowed either.) I've pushed a new patch that changes the comment in is_type_banned to explain the above reasoning for prohibiting desktop integration for file URI associations. Please let me know if you have any further concerns. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/2740#note_32131
On Mon May 8 04:35:44 2023 +0000, Alex Henrie wrote:
That's really interesting, I didn't know that Wine could do that. I tried it and `explorer file:///some/unix/path/` works too. However, as you alluded to, there is a bigger reason why we don't want desktop integration for file URIs: Associating a program with the file "protocol" is like associating it with all file types, which would be obnoxious and lend itself to the same kinds of abuse as associating a program with .com, .exe, or .msi. (Incidentally, desktop integration for third-party associations with .bat really shouldn't be allowed either.) I've pushed a new patch that changes the comment in is_type_banned to explain the above reasoning for prohibiting desktop integration for file URI associations. Please let me know if you have any further concerns. The `file:` protocol should be handled by the already existing `wine-extension-%s.desktop` files.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/2740#note_32527
Could protocol and file handling be in separate check boxes? Or is that WIP and will be in a wine MR in the future? Using `HKCU\Software\Wine\ProtocolAssociations\Enable` could be an alternative too. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/2740#note_35260
On Sat Jun 10 19:13:53 2023 +0000, Loïc Rebmeister wrote:
Could protocol and file handling be in separate check boxes? Or is that WIP and will be in a wine MR in the future? Using `HKCU\Software\Wine\ProtocolAssociations\Enable` could be an alternative too. Perhaps we should get this patch into Wine Staging and see if it annoys people in practice before giving protocol associations special treatment.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/2740#note_35337
On Sat Jun 10 19:13:53 2023 +0000, Alex Henrie wrote:
Perhaps we should get this patch into Wine Staging and see if it annoys people in practice before giving protocol associations special treatment. I think wine-staging is the way to go here. I think the community feedback could help a lot with improving this patch. Especially because of edge cases.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/2740#note_35396
On Sun Jun 11 23:49:45 2023 +0000, Loïc Rebmeister wrote:
I think wine-staging is the way to go here. I think the community feedback could help a lot with improving this patch. Especially because of edge cases. Possibly, but I will warn that we don't really get community feedback. E.g. when Alex's winemenubuilder patches were in wine-staging, I don't recall seeing any comments about them being a good or bad thing. Perhaps there's a ground that someone can keep an ear to, but I don't know of it.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/2740#note_35397
On Mon Jun 12 00:32:23 2023 +0000, Zebediah Figura wrote:
Possibly, but I will warn that we don't really get community feedback. E.g. when Alex's winemenubuilder patches were in wine-staging, I don't recall seeing any comments about them being a good or bad thing. Perhaps there's a ground that someone can keep an ear to, but I don't know of it. After the patch has been in Staging for a while, I could ask for feedback on the [WineHQ Forums](https://forum.winehq.org/). It would also be interesting to just google it and see if there are any blogs or forum posts out there that comment on the feature, or to just ask people in your local Linux user community, if you have one. (I can do that because I am fortunate enough to know people locally who use Wine.)
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/2740#note_35398
On Mon Jun 12 00:49:31 2023 +0000, Alex Henrie wrote:
After the patch has been in Staging for a while, I could ask for feedback on the [WineHQ Forums](https://forum.winehq.org/). It would also be interesting to just google it and see if there are any blogs or forum posts out there that comment on the feature, or to just ask people in your local Linux user community, if you have one. (I can do that because I am fortunate enough to know people locally who use Wine.) If you want to talk to more peoples you can go on wine-tkg and linux gaming dev Discords WineTkg Discord: https://discord.gg/jRy3Nxk Linux Gaming Dev Discord: https://discord.gg/linuxgamingdev I'll share this patch there to try getting more feedback!
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/2740#note_35436
On Mon Jun 12 11:08:48 2023 +0000, Loïc Rebmeister wrote:
If you want to talk to more peoples you can go on wine-tkg and linux gaming dev Discords WineTkg Discord: https://discord.gg/jRy3Nxk Linux Gaming Dev Discord: https://discord.gg/linuxgamingdev I'll share this patch there to try getting more feedback! I'm not sure that a community focused on gaming is going to be a good place to get commentary on this kind of functionality.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/2740#note_35670
participants (4)
-
Alex Henrie -
Alex Henrie (@alexhenrie) -
Loïc Rebmeister -
Zebediah Figura (@zfigura)