diff --git a/hw/xwin/InitOutput.c b/hw/xwin/InitOutput.c index 4bcd3a006..f4d4e9095 100644 --- a/hw/xwin/InitOutput.c +++ b/hw/xwin/InitOutput.c @@ -204,6 +204,9 @@ ddxGiveUp(enum ExitCode error) } #ifdef XWIN_MULTIWINDOW + /* Unload libraries for taskbar grouping */ + winPropertyStoreDestroy(); + /* Notify the worker threads we're exiting */ winDeinitMultiWindowWM(); #endif @@ -951,6 +954,10 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char *argv[]) /* Detect supported engines */ winDetectSupportedEngines(); +#ifdef XWIN_MULTIWINDOW + /* Load libraries for taskbar grouping */ + winPropertyStoreInit(); +#endif /* Store the instance handle */ g_hInstance = GetModuleHandle(NULL); diff --git a/hw/xwin/Makefile.am b/hw/xwin/Makefile.am index 3fcaf9d0b..2df1dbea9 100644 --- a/hw/xwin/Makefile.am +++ b/hw/xwin/Makefile.am @@ -23,8 +23,11 @@ SRCS_MULTIWINDOW = \ winmultiwindowshape.c \ winmultiwindowwindow.c \ winmultiwindowwm.c \ - winmultiwindowwndproc.c + winmultiwindowwndproc.c \ + propertystore.h \ + winSetAppUserModelID.c DEFS_MULTIWINDOW = -DXWIN_MULTIWINDOW +MULTIWINDOW_LIBS = -lshlwapi -lole32 endif if XWIN_MULTIWINDOWEXTWM @@ -150,7 +153,7 @@ INCLUDES = -I$(top_srcdir)/miext/rootless XWIN_SYS_LIBS += -ldxguid XWin_DEPENDENCIES = $(MULTIWINDOWEXTWM_LIBS) $(XWIN_GLX_LIBS) $(XWIN_LIBS) $(MAIN_LIB) $(XSERVER_LIBS) -XWin_LDADD = $(MULTIWINDOWEXTWM_LIBS) $(XWIN_GLX_LIBS) $(XWIN_GLX_LINK_FLAGS) $(XWIN_LIBS) $(MAIN_LIB) $(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XWIN_SYS_LIBS) +XWin_LDADD = $(MULTIWINDOW_LIBS) $(MULTIWINDOWEXTWM_LIBS) $(XWIN_GLX_LIBS) $(XWIN_GLX_LINK_FLAGS) $(XWIN_LIBS) $(MAIN_LIB) $(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XWIN_SYS_LIBS) XWin_LDFLAGS = -mwindows -static .rc.o: diff --git a/hw/xwin/propertystore.h b/hw/xwin/propertystore.h new file mode 100644 index 000000000..6afc6c954 --- /dev/null +++ b/hw/xwin/propertystore.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011 Tobias Häußler + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef PROPERTYSTORE_H +#define PROPERTYSTORE_H + +#include + +#ifdef __MINGW64_VERSION_MAJOR +/* If we are using headers from mingw-w64 project, it provides the PSDK headers this needs ... */ +#include +#include +#else /* !__MINGW64_VERSION_MAJOR */ +/* ... otherwise, we need to define all this stuff ourselves */ + +typedef struct _tagpropertykey { + GUID fmtid; + DWORD pid; +} PROPERTYKEY; + +#define REFPROPERTYKEY const PROPERTYKEY * +#define REFPROPVARIANT const PROPVARIANT * + +WINOLEAPI PropVariantClear(PROPVARIANT *pvar); + +#ifdef INTERFACE +#undef INTERFACE +#endif + +#define INTERFACE IPropertyStore +DECLARE_INTERFACE_(IPropertyStore, IUnknown) +{ + STDMETHOD(QueryInterface) (THIS_ REFIID, PVOID *) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + STDMETHOD(GetCount) (THIS_ DWORD) PURE; + STDMETHOD(GetAt) (THIS_ DWORD, PROPERTYKEY) PURE; + STDMETHOD(GetValue) (THIS_ REFPROPERTYKEY, PROPVARIANT) PURE; + STDMETHOD(SetValue) (THIS_ REFPROPERTYKEY, REFPROPVARIANT) PURE; + STDMETHOD(Commit) (THIS) PURE; +}; + +#undef INTERFACE +typedef IPropertyStore *LPPROPERTYSTORE; + +DEFINE_GUID(IID_IPropertyStore, 0x886d8eeb, 0x8cf2, 0x4446, 0x8d, 0x02, 0xcd, + 0xba, 0x1d, 0xbd, 0xcf, 0x99); + +#ifdef INITGUID +#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) GUID_EXT const PROPERTYKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid } +#else +#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) GUID_EXT const PROPERTYKEY name +#endif + +DEFINE_PROPERTYKEY(PKEY_AppUserModel_ID, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, + 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 5); + +#endif /* !__MINGW64_VERSION_MAJOR */ + +typedef HRESULT(__stdcall * SHGETPROPERTYSTOREFORWINDOWPROC) (HWND, REFIID, + void **); + +#endif diff --git a/hw/xwin/winSetAppUserModelID.c b/hw/xwin/winSetAppUserModelID.c new file mode 100644 index 000000000..ce9da5e7d --- /dev/null +++ b/hw/xwin/winSetAppUserModelID.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2011 Tobias Häußler + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif + +#include +#include +#include +#include "winwindow.h" +#include "os.h" +#include "winmsg.h" + +#include + +#define INITGUID +#include "initguid.h" +#include "propertystore.h" +#undef INITGUID + +static HMODULE g_hmodShell32Dll = NULL; +static SHGETPROPERTYSTOREFORWINDOWPROC g_pSHGetPropertyStoreForWindow = NULL; + +void +winPropertyStoreInit(void) +{ + /* + Load library and get function pointer to SHGetPropertyStoreForWindow() + + SHGetPropertyStoreForWindow is only supported since Windows 7. On previous + versions the pointer will be NULL and taskbar grouping is not supported. + winSetAppUserModelID() will do nothing in this case. + */ + g_hmodShell32Dll = LoadLibrary("shell32.dll"); + if (g_hmodShell32Dll == NULL) { + ErrorF("winPropertyStoreInit - Could not load shell32.dll\n"); + return; + } + + g_pSHGetPropertyStoreForWindow = + (SHGETPROPERTYSTOREFORWINDOWPROC) GetProcAddress(g_hmodShell32Dll, + "SHGetPropertyStoreForWindow"); + if (g_pSHGetPropertyStoreForWindow == NULL) { + ErrorF + ("winPropertyStoreInit - Could not get SHGetPropertyStoreForWindow address\n"); + return; + } +} + +void +winPropertyStoreDestroy(void) +{ + if (g_hmodShell32Dll != NULL) { + FreeLibrary(g_hmodShell32Dll); + g_hmodShell32Dll = NULL; + g_pSHGetPropertyStoreForWindow = NULL; + } +} + +void +winSetAppUserModelID(HWND hWnd, const char *AppID) +{ + PROPVARIANT pv; + IPropertyStore *pps = NULL; + HRESULT hr; + + if (g_pSHGetPropertyStoreForWindow == NULL) { + return; + } + + winDebug("winSetAppUserMOdelID - hwnd 0x%08x appid '%s'\n", hWnd, AppID); + + hr = g_pSHGetPropertyStoreForWindow(hWnd, &IID_IPropertyStore, + (void **) &pps); + if (SUCCEEDED(hr) && pps) { + memset(&pv, 0, sizeof(PROPVARIANT)); + if (AppID) { + pv.vt = VT_LPWSTR; + hr = SHStrDupA(AppID, &pv.pwszVal); + } + + if (SUCCEEDED(hr)) { + pps->lpVtbl->SetValue(pps, &PKEY_AppUserModel_ID, &pv); + PropVariantClear(&pv); + } + pps->lpVtbl->Release(pps); + } +} diff --git a/hw/xwin/winmultiwindowwm.c b/hw/xwin/winmultiwindowwm.c index 42925e36d..fbf984df2 100644 --- a/hw/xwin/winmultiwindowwm.c +++ b/hw/xwin/winmultiwindowwm.c @@ -1630,10 +1630,14 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) XFree(normal_hint); } - /* Override hint settings from above with settings from config file */ + /* + Override hint settings from above with settings from config file and set + application id for grouping. + */ { XClassHint class_hint = { 0, 0 }; char *window_name = 0; + char *application_id = 0; if (XGetClassHint(pDisplay, iWindow, &class_hint)) { XFetchName(pDisplay, iWindow, &window_name); @@ -1642,10 +1646,24 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) winOverrideStyle(class_hint.res_name, class_hint.res_class, window_name); +#define APPLICATION_ID_FORMAT "%s.xwin.%s" +#define APPLICATION_ID_UNKNOWN "unknown" + if (class_hint.res_class) { + asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME, + class_hint.res_class); + } + else { + asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME, + APPLICATION_ID_UNKNOWN); + } + winSetAppUserModelID(hWnd, application_id); + if (class_hint.res_name) XFree(class_hint.res_name); if (class_hint.res_class) XFree(class_hint.res_class); + if (application_id) + free(application_id); if (window_name) XFree(window_name); } diff --git a/hw/xwin/winmultiwindowwndproc.c b/hw/xwin/winmultiwindowwndproc.c index af917d6fc..4180a3aa3 100644 --- a/hw/xwin/winmultiwindowwndproc.c +++ b/hw/xwin/winmultiwindowwndproc.c @@ -825,6 +825,8 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_CLOSE: + /* Removep AppUserModelID property */ + winSetAppUserModelID(hwnd, NULL); /* Branch on if the window was killed in X already */ if (pWinPriv->fXKilled) { /* Window was killed, go ahead and destroy the window */ diff --git a/hw/xwin/winwindow.h b/hw/xwin/winwindow.h index 49a720a67..4540dd03e 100644 --- a/hw/xwin/winwindow.h +++ b/hw/xwin/winwindow.h @@ -148,5 +148,14 @@ void void winMinimizeWindow(Window id); +void + winPropertyStoreInit(void); + +void + winPropertyStoreDestroy(void); + +void + winSetAppUserModelID(HWND hWnd, const char *AppID); + #endif /* XWIN_MULTIWINDOW */ #endif