--- programs/winemenubuilder/winemenubuilder.c | 123 ++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 10 deletions(-)
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index 76d8f3a..2e258a9 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -90,6 +90,8 @@ #include <shlwapi.h> #include <initguid.h> #include <wincodec.h> +#include <propsys.h> +#include <propvarutil.h>
#include "wine/unicode.h" #include "wine/debug.h" @@ -97,6 +99,9 @@ #include "wine/list.h" #include "wine/rbtree.h"
+#include <initguid.h> +#include <propkey.h> + WINE_DEFAULT_DEBUG_CHANNEL(menubuilder);
#define in_desktop_dir(csidl) ((csidl)==CSIDL_DESKTOPDIRECTORY || \ @@ -1474,7 +1479,7 @@ static DWORD register_menus_entry(const char *unix_file, const char *windows_fil
static BOOL write_desktop_entry(const char *unix_link, const char *location, const char *linkname, const char *path, const char *args, const char *descr, - const char *workdir, const char *icon) + const char *workdir, const char *icon, const char *appusermodelid) { FILE *file;
@@ -1498,6 +1503,8 @@ static BOOL write_desktop_entry(const char *unix_link, const char *location, con fprintf(file, "Path=%s\n", workdir); if (icon && lstrlenA(icon)) fprintf(file, "Icon=%s\n", icon); + if (appusermodelid && lstrlenA(appusermodelid)) + fprintf(file, "StartupWMClass=%s\n", appusermodelid);
fclose(file);
@@ -1643,7 +1650,7 @@ end: }
static BOOL write_menu_entry(const char *unix_link, const char *link, const char *path, const char *args, - const char *descr, const char *workdir, const char *icon) + const char *descr, const char *workdir, const char *icon, const char *appusermodelid) { const char *linkname; char *desktopPath = NULL; @@ -1651,9 +1658,9 @@ static BOOL write_menu_entry(const char *unix_link, const char *link, const char char *filename = NULL; BOOL ret = TRUE;
- WINE_TRACE("(%s, %s, %s, %s, %s, %s, %s)\n", wine_dbgstr_a(unix_link), wine_dbgstr_a(link), + WINE_TRACE("(%s, %s, %s, %s, %s, %s, %s, %s)\n", wine_dbgstr_a(unix_link), wine_dbgstr_a(link), wine_dbgstr_a(path), wine_dbgstr_a(args), wine_dbgstr_a(descr), - wine_dbgstr_a(workdir), wine_dbgstr_a(icon)); + wine_dbgstr_a(workdir), wine_dbgstr_a(icon), wine_dbgstr_a(appusermodelid));
linkname = strrchr(link, '/'); if (linkname == NULL) @@ -1677,7 +1684,7 @@ static BOOL write_menu_entry(const char *unix_link, const char *link, const char goto end; } *desktopDir = '/'; - if (!write_desktop_entry(unix_link, desktopPath, linkname, path, args, descr, workdir, icon)) + if (!write_desktop_entry(unix_link, desktopPath, linkname, path, args, descr, workdir, icon, appusermodelid)) { WINE_WARN("couldn't make desktop entry %s\n", wine_dbgstr_a(desktopPath)); ret = FALSE; @@ -1756,6 +1763,45 @@ end: return utf8_string; }
+/* escapes strings for normal keys (i.e. everything but Exec */ +static char *escape_string(const char *source) +{ + char *dst = HeapAlloc(GetProcessHeap(), 0, lstrlenA(source)*2+1); + char *d = dst; + const char *s = source; + + if (!dst) + return NULL; + + for (; *s; ++s) + { + switch (*s) + { + case '\r': + *d++ = '\'; + *d++ = 'r'; + break; + case '\n': + *d++ = '\'; + *d++ = 'n'; + break; + case '\t': + *d++ = '\'; + *d++ = 't'; + break; + case '\': + *d++ = '\'; + *d++ = '\'; + break; + default: + *d++ = *s; + } + } + *d = 0; + + return dst; +} + /* Return a heap-allocated copy of the unix format difference between the two * Windows-format paths. * locn is the owning location @@ -2811,6 +2857,58 @@ static char* escape_unix_link_arg(LPCSTR unix_link) return ret; }
+static char *get_appusermodel_id( IShellLinkW *link ) +{ + char *id = NULL; + IPropertyStore *store = NULL; + WCHAR buffer[MAX_PATH]; + HRESULT hr; + + /* search an explicit id */ + hr = IShellLinkW_QueryInterface(link, &IID_IPropertyStore, (void**)&store); + if (SUCCEEDED(hr)) + { + PROPVARIANT v; + PropVariantInit(&v); + + hr = IPropertyStore_GetValue(store, &PKEY_AppUserModel_ID, &v); + if (SUCCEEDED(hr) && v.vt == VT_LPWSTR) + { + DWORD u8len = WideCharToMultiByte(CP_UTF8, 0, v.u.pwszVal, -1, NULL, 0, NULL, NULL); + if (u8len && (id = HeapAlloc(GetProcessHeap(), 0, u8len))) + { + WideCharToMultiByte(CP_UTF8, 0, v.u.pwszVal, -1, id, u8len, NULL, NULL); + } + } + + PropVariantClear(&v); + IPropertyStore_Release(store); + } + + /* use the link target */ + if (!id) + { + hr = IShellLinkW_GetPath(link, buffer, MAX_PATH, NULL, 0); + if (SUCCEEDED(hr)) + { + DWORD u8len = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL); + if (u8len && (id = HeapAlloc(GetProcessHeap(), 0, u8len))) + { + WideCharToMultiByte(CP_UTF8, 0, buffer, -1, id, u8len, NULL, NULL); + } + } + } + + if (id) + { + char *tmp = escape_string(id); + HeapFree(GetProcessHeap(), 0, id); + return tmp; + } + + return NULL; +} + static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait ) { static const WCHAR startW[] = {'\','c','o','m','m','a','n','d', @@ -2825,6 +2923,7 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait ) HANDLE hsem = NULL; char *unix_link = NULL; char *start_path = NULL; + char *appusermodelid = NULL;
if ( !link ) { @@ -2864,6 +2963,9 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait ) ExpandEnvironmentStringsW(szTmp, szIconPath, MAX_PATH); WINE_TRACE("icon file : %s\n", wine_dbgstr_w(szIconPath) );
+ appusermodelid = get_appusermodel_id( sl ); + WINE_TRACE("AppUserModelID : %s\n", wine_dbgstr_a(appusermodelid)); + if( !szPath[0] ) { LPITEMIDLIST pidl = NULL; @@ -2982,12 +3084,12 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait ) if (link_arg) { r = !write_desktop_entry(unix_link, location, lastEntry, - start_path, link_arg, description, work_dir, icon_name); + start_path, link_arg, description, work_dir, icon_name, appusermodelid); HeapFree(GetProcessHeap(), 0, link_arg); } } else - r = !write_desktop_entry(NULL, location, lastEntry, escaped_path, escaped_args, description, work_dir, icon_name); + r = !write_desktop_entry(NULL, location, lastEntry, escaped_path, escaped_args, description, work_dir, icon_name, appusermodelid); if (r == 0) chmod(location, 0755); HeapFree(GetProcessHeap(), 0, location); @@ -2998,7 +3100,7 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait ) char *link_arg = escape_unix_link_arg(unix_link); if (link_arg) { - r = !write_menu_entry(unix_link, link_name, start_path, link_arg, description, work_dir, icon_name); + r = !write_menu_entry(unix_link, link_name, start_path, link_arg, description, work_dir, icon_name, appusermodelid); HeapFree(GetProcessHeap(), 0, link_arg); } } @@ -3015,6 +3117,7 @@ cleanup: HeapFree( GetProcessHeap(), 0, description ); HeapFree( GetProcessHeap(), 0, unix_link ); HeapFree( GetProcessHeap(), 0, start_path ); + HeapFree( GetProcessHeap(), 0, appusermodelid );
if (r && !bWait) WINE_ERR("failed to build the menu\n" ); @@ -3148,14 +3251,14 @@ static BOOL InvokeShellLinkerForURL( IUniformResourceLocatorW *url, LPCWSTR link location = heap_printf("%s/%s.desktop", xdg_desktop_dir, lastEntry); if (location) { - r = !write_desktop_entry(NULL, location, lastEntry, start_path, escaped_urlPath, NULL, NULL, icon_name); + r = !write_desktop_entry(NULL, location, lastEntry, start_path, escaped_urlPath, NULL, NULL, icon_name, NULL); if (r == 0) chmod(location, 0755); HeapFree(GetProcessHeap(), 0, location); } } else - r = !write_menu_entry(unix_link, link_name, start_path, escaped_urlPath, NULL, NULL, icon_name); + r = !write_menu_entry(unix_link, link_name, start_path, escaped_urlPath, NULL, NULL, icon_name, NULL); ret = (r == 0); ReleaseSemaphore(hSem, 1, NULL);