[2/2] winemenubuilder: group file open associations by application
Damjan Jovanovic
damjan.jov at gmail.com
Sun Feb 27 10:41:59 CST 2011
Changelog:
* winemenubuilder: group file open associations by application
Damjan Jovanovic
-------------- next part --------------
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
index 9aae73f..de28032 100644
--- a/programs/winemenubuilder/winemenubuilder.c
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -163,12 +163,24 @@ struct xdg_mime_type
struct list entry;
};
-struct rb_string_entry
-{
- char *string;
+struct rb_application_entry
+{
+ WCHAR *commandW;
+ WCHAR *extensionW;
+ char *extensionA;
+ char *mimeTypesA;
+ WCHAR *progIdsW;
+ char *friendlyAppNameA;
+ char *openWithIconA;
struct wine_rb_entry entry;
};
+struct app_context
+{
+ BOOL hasChanged;
+ const char *applicationsDir;
+};
+
DEFINE_GUID(CLSID_WICIcnsEncoder, 0x312fb6f1,0xb767,0x409d,0x8a,0x6d,0x0f,0xc1,0x54,0xd4,0xf0,0x5c);
static char *xdg_config_dir;
@@ -236,11 +248,40 @@ static char* heap_printf(const char *format, ...)
return ret;
}
-static int winemenubuilder_rb_string_compare(const void *key, const struct wine_rb_entry *entry)
+static WCHAR* heap_printfW(const WCHAR *format, ...)
{
- const struct rb_string_entry *t = WINE_RB_ENTRY_VALUE(entry, const struct rb_string_entry, entry);
+ va_list args;
+ int size = 4096;
+ WCHAR *buffer, *ret;
+ int n;
- return strcmp((char*)key, t->string);
+ va_start(args, format);
+ while (1)
+ {
+ buffer = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
+ if (buffer == NULL)
+ break;
+ n = vsnprintfW(buffer, size, format, args);
+ if (n == -1)
+ size *= 2;
+ else if (n >= size)
+ size = n + 1;
+ else
+ break;
+ HeapFree(GetProcessHeap(), 0, buffer);
+ }
+ va_end(args);
+ if (!buffer) return NULL;
+ ret = HeapReAlloc(GetProcessHeap(), 0, buffer, (strlenW(buffer) + 1)*sizeof(WCHAR) );
+ if (!ret) ret = buffer;
+ return ret;
+}
+
+static int winemenubuilder_rb_application_compare(const void *key, const struct wine_rb_entry *entry)
+{
+ const struct rb_application_entry *t = WINE_RB_ENTRY_VALUE(entry, const struct rb_application_entry, entry);
+
+ return strcmpW((WCHAR*)key, t->commandW);
}
static void *winemenubuilder_rb_alloc(size_t size)
@@ -260,8 +301,14 @@ static void winemenubuilder_rb_free(void *ptr)
static void winemenubuilder_rb_destroy(struct wine_rb_entry *entry, void *context)
{
- struct rb_string_entry *t = WINE_RB_ENTRY_VALUE(entry, struct rb_string_entry, entry);
- HeapFree(GetProcessHeap(), 0, t->string);
+ struct rb_application_entry *t = WINE_RB_ENTRY_VALUE(entry, struct rb_application_entry, entry);
+ HeapFree(GetProcessHeap(), 0, t->commandW);
+ HeapFree(GetProcessHeap(), 0, t->extensionW);
+ HeapFree(GetProcessHeap(), 0, t->extensionA);
+ HeapFree(GetProcessHeap(), 0, t->mimeTypesA);
+ HeapFree(GetProcessHeap(), 0, t->progIdsW);
+ HeapFree(GetProcessHeap(), 0, t->friendlyAppNameA);
+ HeapFree(GetProcessHeap(), 0, t->openWithIconA);
HeapFree(GetProcessHeap(), 0, t);
}
@@ -270,7 +317,7 @@ static const struct wine_rb_functions winemenubuilder_rb_functions =
winemenubuilder_rb_alloc,
winemenubuilder_rb_realloc,
winemenubuilder_rb_free,
- winemenubuilder_rb_string_compare,
+ winemenubuilder_rb_application_compare,
};
static void write_xml_text(FILE *file, const char *text)
@@ -2226,14 +2273,14 @@ static const char* get_special_mime_type(LPCWSTR extension)
static BOOL write_freedesktop_association_entry(const char *desktopPath, const char *dot_extension,
const char *friendlyAppName, const char *mimeType,
- const char *progId, const char *openWithIcon)
+ const char *openWithIcon)
{
BOOL ret = FALSE;
FILE *desktop;
- WINE_TRACE("writing association for file type %s, friendlyAppName=%s, MIME type %s, progID=%s, icon=%s to file %s\n",
+ WINE_TRACE("writing association for file type %s, friendlyAppName=%s, MIME type %s, icon=%s to file %s\n",
wine_dbgstr_a(dot_extension), wine_dbgstr_a(friendlyAppName), wine_dbgstr_a(mimeType),
- wine_dbgstr_a(progId), wine_dbgstr_a(openWithIcon), wine_dbgstr_a(desktopPath));
+ wine_dbgstr_a(openWithIcon), wine_dbgstr_a(desktopPath));
desktop = fopen(desktopPath, "w");
if (desktop)
@@ -2242,7 +2289,7 @@ static BOOL write_freedesktop_association_entry(const char *desktopPath, const c
fprintf(desktop, "Type=Application\n");
fprintf(desktop, "Name=%s\n", friendlyAppName);
fprintf(desktop, "MimeType=%s;\n", mimeType);
- fprintf(desktop, "Exec=wine start /ProgIDOpen %s %%f\n", progId);
+ fprintf(desktop, "Exec=wine start /ProgIDOpen2 %s %%f\n", dot_extension);
fprintf(desktop, "NoDisplay=true\n");
fprintf(desktop, "StartupNotify=true\n");
if (openWithIcon)
@@ -2255,16 +2302,40 @@ static BOOL write_freedesktop_association_entry(const char *desktopPath, const c
return ret;
}
+static void update_application(struct wine_rb_entry *entry, void *context)
+{
+ struct rb_application_entry *app;
+ struct app_context *appContext = (struct app_context*)context;
+ app = WINE_RB_ENTRY_VALUE(entry, struct rb_application_entry, entry);
+ if (has_association_changed(app->extensionW, app->mimeTypesA, app->progIdsW, app->friendlyAppNameA, app->openWithIconA))
+ {
+ char *desktopPath = heap_printf("%s/wine-extension-%s.desktop", appContext->applicationsDir, &app->extensionA[1]);
+ if (desktopPath)
+ {
+ if (write_freedesktop_association_entry(desktopPath, app->extensionA, app->friendlyAppNameA, app->mimeTypesA,
+ app->openWithIconA))
+ {
+ appContext->hasChanged = TRUE;
+ update_association(app->extensionW, app->mimeTypesA, app->progIdsW, app->friendlyAppNameA, desktopPath,
+ app->openWithIconA);
+ }
+ HeapFree(GetProcessHeap(), 0, desktopPath);
+ }
+ }
+}
+
static BOOL generate_associations(const char *xdg_data_home, const char *packages_dir, const char *applications_dir)
{
static const WCHAR openW[] = {'o','p','e','n',0};
- struct wine_rb_tree mimeProgidTree;
+ struct wine_rb_tree applicationTree;
struct list *nativeMimeTypes = NULL;
LSTATUS ret = 0;
int i;
- BOOL hasChanged = FALSE;
+ struct app_context appContext;
- if (wine_rb_init(&mimeProgidTree, &winemenubuilder_rb_functions))
+ appContext.applicationsDir = applications_dir;
+ appContext.hasChanged = FALSE;
+ if (wine_rb_init(&applicationTree, &winemenubuilder_rb_functions))
{
WINE_ERR("wine_rb_init failed\n");
return FALSE;
@@ -2309,8 +2380,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package
WCHAR *friendlyAppNameW = NULL;
char *friendlyAppNameA = NULL;
WCHAR *progIdW = NULL;
- char *progIdA = NULL;
- char *mimeProgId = NULL;
+ struct wine_rb_entry *entry;
extensionA = wchars_to_utf8_chars(strlwrW(extensionW));
if (extensionA == NULL)
@@ -2371,7 +2441,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package
}
write_freedesktop_mime_type_entry(packages_dir, extensionA, mimeTypeA, friendlyDocNameA);
- hasChanged = TRUE;
+ appContext.hasChanged = TRUE;
}
else
{
@@ -2385,78 +2455,94 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package
/* no command => no application is associated */
goto end;
- executableW = assoc_query(ASSOCSTR_EXECUTABLE, extensionW, openW);
- if (executableW)
- openWithIconA = extract_icon(executableW, 0, NULL, FALSE);
+ progIdW = reg_get_valW(HKEY_CLASSES_ROOT, extensionW, NULL);
+ if (progIdW == NULL)
+ goto end; /* no progID => not a file type association */
- friendlyAppNameW = assoc_query(ASSOCSTR_FRIENDLYAPPNAME, extensionW, NULL);
- if (friendlyAppNameW)
+ entry = wine_rb_get(&applicationTree, commandW);
+ if (entry == NULL)
{
- friendlyAppNameA = wchars_to_utf8_chars(friendlyAppNameW);
- if (friendlyAppNameA == NULL)
+ struct rb_application_entry *applicationEntry;
+
+ executableW = assoc_query(ASSOCSTR_EXECUTABLE, extensionW, openW);
+ if (executableW)
+ openWithIconA = extract_icon(executableW, 0, NULL, FALSE);
+
+ friendlyAppNameW = assoc_query(ASSOCSTR_FRIENDLYAPPNAME, extensionW, NULL);
+ if (friendlyAppNameW)
{
- WINE_ERR("out of memory\n");
- goto end;
+ friendlyAppNameA = wchars_to_utf8_chars(friendlyAppNameW);
+ if (friendlyAppNameA == NULL)
+ {
+ WINE_ERR("out of memory\n");
+ goto end;
+ }
}
- }
- else
- {
- friendlyAppNameA = heap_printf("A Wine application");
- if (friendlyAppNameA == NULL)
+ else
{
- WINE_ERR("out of memory\n");
- goto end;
+ friendlyAppNameA = heap_printf("A Wine application");
+ if (friendlyAppNameA == NULL)
+ {
+ WINE_ERR("out of memory\n");
+ goto end;
+ }
}
- }
- progIdW = reg_get_valW(HKEY_CLASSES_ROOT, extensionW, NULL);
- if (progIdW)
- {
- progIdA = escape(progIdW);
- if (progIdA == NULL)
+ applicationEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct rb_application_entry));
+ if (applicationEntry == NULL)
{
WINE_ERR("out of memory\n");
goto end;
}
- }
- else
- 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_printf("%s=>%s", mimeTypeA, progIdA);
- if (mimeProgId)
- {
- struct rb_string_entry *entry;
- if (wine_rb_get(&mimeProgidTree, mimeProgId))
- {
- HeapFree(GetProcessHeap(), 0, mimeProgId);
- goto end;
- }
- entry = HeapAlloc(GetProcessHeap(), 0, sizeof(struct rb_string_entry));
- if (!entry)
+ applicationEntry->commandW = commandW;
+ commandW = NULL;
+ applicationEntry->extensionW = extensionW;
+ extensionW = NULL;
+ applicationEntry->extensionA = extensionA;
+ extensionA = NULL;
+ applicationEntry->mimeTypesA = mimeTypeA;
+ mimeTypeA = NULL;
+ applicationEntry->progIdsW = progIdW;
+ progIdW = NULL;
+ applicationEntry->friendlyAppNameA = friendlyAppNameA;
+ friendlyAppNameA = NULL;
+ applicationEntry->openWithIconA = openWithIconA;
+ openWithIconA = NULL;
+ if (wine_rb_put(&applicationTree, applicationEntry->commandW, &applicationEntry->entry))
{
- WINE_ERR("out of memory allocating rb_string_entry\n");
- goto end;
- }
- entry->string = mimeProgId;
- if (wine_rb_put(&mimeProgidTree, mimeProgId, &entry->entry))
- {
- WINE_ERR("error updating rb tree\n");
+ WINE_ERR("error updating applications rb tree (out of memory?)\n");
+ winemenubuilder_rb_destroy(&applicationEntry->entry, NULL);
goto end;
}
}
-
- if (has_association_changed(extensionW, mimeTypeA, progIdW, friendlyAppNameA, openWithIconA))
+ else
{
- char *desktopPath = heap_printf("%s/wine-extension-%s.desktop", applications_dir, &extensionA[1]);
- if (desktopPath)
+ static const WCHAR progid_fmtW[] = {'%','s',';','%','s',0};
+ char *mimeTypes;
+ struct rb_application_entry *applicationEntry =
+ WINE_RB_ENTRY_VALUE(entry, struct rb_application_entry, entry);
+ mimeTypes = heap_printf("%s;%s", applicationEntry->mimeTypesA, mimeTypeA);
+ if (mimeTypes)
{
- if (write_freedesktop_association_entry(desktopPath, extensionA, friendlyAppNameA, mimeTypeA, progIdA, openWithIconA))
+ WCHAR *progIds = heap_printfW(progid_fmtW, applicationEntry->progIdsW, progIdW);
+ if (progIds)
{
- hasChanged = TRUE;
- update_association(extensionW, mimeTypeA, progIdW, friendlyAppNameA, desktopPath, openWithIconA);
+ HeapFree(GetProcessHeap(), 0, applicationEntry->mimeTypesA);
+ applicationEntry->mimeTypesA = mimeTypes;
+ HeapFree(GetProcessHeap(), 0, applicationEntry->progIdsW);
+ applicationEntry->progIdsW = progIds;
}
- HeapFree(GetProcessHeap(), 0, desktopPath);
+ else
+ {
+ HeapFree(GetProcessHeap(), 0, mimeTypes);
+ WINE_ERR("out of memory\n");
+ goto end;
+ }
+ }
+ else
+ {
+ WINE_ERR("out of memory\n");
+ goto end;
}
}
@@ -2474,16 +2560,17 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package
HeapFree(GetProcessHeap(), 0, friendlyAppNameW);
HeapFree(GetProcessHeap(), 0, friendlyAppNameA);
HeapFree(GetProcessHeap(), 0, progIdW);
- HeapFree(GetProcessHeap(), 0, progIdA);
}
HeapFree(GetProcessHeap(), 0, extensionW);
if (ret != ERROR_SUCCESS)
break;
}
- wine_rb_destroy(&mimeProgidTree, winemenubuilder_rb_destroy, NULL);
+ wine_rb_for_each_entry(&applicationTree, update_application, &appContext);
+
+ wine_rb_destroy(&applicationTree, winemenubuilder_rb_destroy, NULL);
free_native_mime_types(nativeMimeTypes);
- return hasChanged;
+ return appContext.hasChanged;
}
static char *get_start_exe_path(void)
More information about the wine-patches
mailing list