[PATCH rebase 2/2] winemenubuilder: Create .desktop files for programs that open URIs

Alex Henrie alexhenrie24 at gmail.com
Mon Apr 4 00:31:47 CDT 2022


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22904
Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
 programs/winemenubuilder/winemenubuilder.c | 148 ++++++++++++---------
 1 file changed, 86 insertions(+), 62 deletions(-)

diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
index ef280954b67..abe5b5469ae 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)
@@ -2032,11 +2035,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)
@@ -2064,12 +2071,19 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic
 
     for (i = 0; ; i++)
     {
-        WCHAR *extensionW;
+        WCHAR *winTypeW;
+        BOOL is_protocol_type = 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)
+                is_protocol_type = TRUE;
+        }
+
+        if (is_protocol_type || (winTypeW[0] == '.' && !is_extension_banned(winTypeW)))
         {
             WCHAR *commandW = NULL;
             WCHAR *executableW = NULL;
@@ -2083,7 +2097,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;
@@ -2092,78 +2106,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);
+            wcslwr(winTypeW);
+            friendlyDocNameW = assoc_query(ASSOCSTR_FRIENDLYDOCNAME, winTypeW, NULL);
 
-            iconW = assoc_query(ASSOCSTR_DEFAULTICON, extensionW, NULL);
+            iconW = assoc_query(ASSOCSTR_DEFAULTICON, winTypeW, NULL);
 
-            contentTypeW = assoc_query(ASSOCSTR_CONTENTTYPE, extensionW, NULL);
+            contentTypeW = assoc_query(ASSOCSTR_CONTENTTYPE, winTypeW, NULL);
             if (contentTypeW)
                 wcslwr(contentTypeW);
 
-            mimeType = freedesktop_mime_type_for_extension(&nativeMimeTypes, extensionW);
-
-            if (mimeType == NULL)
+            if (is_protocol_type)
+            {
+                mimeType = heap_wprintf(L"x-scheme-handler/%s", winTypeW);
+            }
+            else
             {
-                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)
+                mimeType = freedesktop_mime_type_for_extension(&nativeMimeTypes, winTypeW);
+
+                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 (is_protocol_type)
+                    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);
             }
@@ -2180,7 +2204,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);
-- 
2.35.1




More information about the wine-devel mailing list