public inbox for cygwin-xfree@sourceware.org
help / color / mirror / Atom feed
From: "Tobias Häußler" <tobias.haeussler@gmx.de>
To: cygwin-xfree@cygwin.com
Subject: Re: Taskbar grouping in Windows 7
Date: Sat, 02 Jul 2011 16:51:00 -0000	[thread overview]
Message-ID: <4E0E303B.9000802@gmx.de> (raw)
In-Reply-To: <4E0B27DA.20701@dronecode.org.uk>

[-- Attachment #1: Type: text/plain, Size: 2694 bytes --]

On 29/06/2011 15:25, Jon TURNEY wrote:
> On 25/06/2011 13:48, Tobias Häußler wrote:
>> I created a small patch for XWin that adds correct grouping of taskbar
>> icons when 'Always combine, hide labels' is set in the taskbar
>> properties. It uses the new taskbar APIs introduced in Windows 7 to set
>> an application id for each window. The id is based on the X11 class hints.
>> Maybe it is useful for someone...
> 
> Firstly, thanks very much for this patch.
> 
> Getting Windows to correctly group XWin windows on the taskbar is something
> that has needed fixing for a while, so it's great to have it done :-)
> 

Thanks for your suggestions! I changed the code you mentioned.

> A few minor comments included inline:
>> [...]
> Can you start this file with the license information, like all other files.
> 
> This should also serve to confirm that you are happy for me to forward this
> upstream to be distributed under the MIT/X11 license [1]
> 

Done. I copied the license text from another file...

>> [...]
> 
> Looks like this function can be made static?
> 

Yes, however for proper cleanup this function is now also called from
the WM_DESTROY handler and I left it non-static.

>> [...]
> 
> Since the results of LoadLibrary/GetProcAddress are invariant at run-time, I'd
> rather these calls were done once, rather than every time we want to use those
> results.
> 
> It would also be useful to include a comment mentioning which version of
> Windows these interfaces were added in (so future generations will know when
> they can directly link to those functions :-))
> 
> I assume that there is no way to achieve this functionality prior for Windows
> 7, rather than an alternative interface which you chose not to use?
> 

The initialization/deinitialization is now done only once when XWin is
started/stopped. I am not sure if there is an API to control the taskbar
grouping on older versions of Windows, therefore I have choosen this one...


>> [...]
> 
> Should be PropVariantInit() ?
> 

I cannot use PropVariantInit() for the initialization of the PROPVARIANT
structure because it is not supported bei the w32api of cygwin (or at
least I cannot find it). According to the Microsoft SDK, PropVariantInit
only calls memset.


>> [...]
> 
> The MSDN description of SHGetPropertyStoreForWindow() says:
> "A window's properties must be removed before the window is closed. If this is
> not done, the resources used by those properties are not returned to the system."
> 
> Does this not apply in this case, or is some cleanup needed?
> 

You are right about that, I added code for cleanup.

>> [...]
> 
> [1] http://cgit.freedesktop.org/xorg/xserver/tree/COPYING
> 

  Tobias

[-- Attachment #2: taskbar.patch --]
[-- Type: text/plain, Size: 11243 bytes --]

diff -uNr src/xserver-cygwin-1.10.1-1/hw/xwin/InitOutput.c src/xserver-cygwin-1.10.1-1/hw/xwin/InitOutput.c
--- src/xserver-cygwin-1.10.1-1/hw/xwin/InitOutput.c	2011-04-22 18:03:27.000000000 +0200
+++ src/xserver-cygwin-1.10.1-1/hw/xwin/InitOutput.c	2011-07-01 20:11:55.028448200 +0200
@@ -219,6 +219,9 @@
     }
 
 #ifdef XWIN_MULTIWINDOW
+  /* Unload libraries for taskbar grouping */
+  winTaskbarDestroy ();
+
   /* Notify the worker threads we're exiting */
   winDeinitMultiWindowWM ();
 #endif
@@ -984,6 +987,11 @@
   /* Detect supported engines */
   winDetectSupportedEngines ();
 
+#ifdef XWIN_MULTIWINDOW
+  /* Load libraries for taskbar grouping */
+  winTaskbarInit ();
+#endif
+
   /* Store the instance handle */
   g_hInstance = GetModuleHandle (NULL);
 
diff -uNr src/xserver-cygwin-1.10.1-1/hw/xwin/Makefile.am src/xserver-cygwin-1.10.1-1/hw/xwin/Makefile.am
--- src/xserver-cygwin-1.10.1-1/hw/xwin/Makefile.am	2011-04-22 18:03:27.000000000 +0200
+++ src/xserver-cygwin-1.10.1-1/hw/xwin/Makefile.am	2011-07-01 21:27:18.840399400 +0200
@@ -26,6 +26,7 @@
 	winmultiwindowwm.c \
 	winmultiwindowwndproc.c
 DEFS_MULTIWINDOW = -DXWIN_MULTIWINDOW
+MULTIWINDOW_LIBS = -lshlwapi
 endif
 
 if XWIN_MULTIWINDOWEXTWM
@@ -149,7 +150,7 @@
 INCLUDES = -I$(top_srcdir)/miext/rootless
 
 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 -uNr src/xserver-cygwin-1.10.1-1/hw/xwin/taskbar.h src/xserver-cygwin-1.10.1-1/hw/xwin/taskbar.h
--- src/xserver-cygwin-1.10.1-1/hw/xwin/taskbar.h	1970-01-01 01:00:00.000000000 +0100
+++ src/xserver-cygwin-1.10.1-1/hw/xwin/taskbar.h	2011-07-01 21:10:40.698151400 +0200
@@ -0,0 +1,72 @@
+/*
+ *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
+ *
+ *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 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 XFREE86 PROJECT 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.
+ *
+ *Except as contained in this notice, the name of the XFree86 Project
+ *shall not be used in advertising or otherwise to promote the sale, use
+ *or other dealings in this Software without prior written authorization
+ *from the XFree86 Project.
+ */
+
+#ifndef _TASKBAR_H
+#define _TASKBAR_H
+
+#include <windows.h>
+
+typedef struct _tagpropertykey {
+    GUID fmtid;
+    DWORD pid;
+} PROPERTYKEY;
+#define REFPROPERTYKEY const PROPERTYKEY *
+#define REFPROPVARIANT const PROPVARIANT *
+
+#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);
+
+typedef HRESULT (__stdcall *SHGETPROPERTYSTOREFORWINDOWPROC)(HWND,REFIID,void**);
+typedef HRESULT (__stdcall *PROPVARIANTCLEARPROC)(PROPVARIANT*);
+
+#endif
diff -uNr src/xserver-cygwin-1.10.1-1/hw/xwin/winmultiwindowwm.c src/xserver-cygwin-1.10.1-1/hw/xwin/winmultiwindowwm.c
--- src/xserver-cygwin-1.10.1-1/hw/xwin/winmultiwindowwm.c	2011-04-22 18:03:27.000000000 +0200
+++ src/xserver-cygwin-1.10.1-1/hw/xwin/winmultiwindowwm.c	2011-07-01 22:05:50.932997900 +0200
@@ -62,6 +62,13 @@
 #include "pixmapstr.h"
 #include "windowstr.h"
 
+#include <shlwapi.h>
+
+#define INITGUID
+#include "initguid.h"
+#include "taskbar.h"
+#undef INITGUID
+
 #ifdef XWIN_MULTIWINDOWEXTWM
 #include <X11/extensions/windowswmstr.h>
 #else
@@ -213,6 +220,10 @@
 static Bool			g_shutdown = FALSE;
 static Bool			redirectError = FALSE;
 static Bool			g_fAnotherWMRunning = FALSE;
+static HMODULE      g_hmodShell32Dll = NULL;
+static HMODULE      g_hmodOle32Dll = NULL;
+static SHGETPROPERTYSTOREFORWINDOWPROC g_pSHGetPropertyStoreForWindow = NULL;
+static PROPVARIANTCLEARPROC g_pPropVariantClear = NULL;
 
 /*
  * PushMessage - Push a message onto the queue
@@ -1671,19 +1682,36 @@
     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);
 
         style = 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);
+          }
+        winSetAppID (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);
       }
     else
@@ -1691,7 +1719,7 @@
         style = STYLE_NONE;
       }
   }
-
+  
   if (style & STYLE_TOPMOST) *zstyle = HWND_TOPMOST;
   else if (style & STYLE_MAXIMIZE) maxmin = (hint & ~HINT_MIN) | HINT_MAX;
   else if (style & STYLE_MINIMIZE) maxmin = (hint & ~HINT_MAX) | HINT_MIN;
@@ -1789,3 +1817,97 @@
     winUpdateRgnMultiWindow(pWin);
   }
 }
+
+void
+winTaskbarInit (void)
+{
+  /* Load libraries and get function pointers to SHGetPropertyStoreForWindow 
+     and PropVariantClear for winSetAppID().
+     SHGetPropertyStoreForWindow is only supported since Windows 7. On previous
+     versions the pointer will be NULL and taskbar grouping is not supported. 
+     winSetAppID() will do nothing in this case. */
+     
+  g_hmodShell32Dll = LoadLibrary ("shell32.dll");
+  if (g_hmodShell32Dll == NULL)
+    {
+      ErrorF ("winTaskbarInit - Could not load shell32.dll\n");
+      return;
+    }
+    
+  g_pSHGetPropertyStoreForWindow = (SHGETPROPERTYSTOREFORWINDOWPROC)
+                                        GetProcAddress (g_hmodShell32Dll,
+                                          "SHGetPropertyStoreForWindow");
+  if (g_pSHGetPropertyStoreForWindow == NULL)
+    {
+      ErrorF ("winTaskbarInit - Could not get "
+              "SHGetPropertyStoreForWindow address\n");
+      return;
+    }
+
+    
+  g_hmodOle32Dll = LoadLibrary ("ole32.dll");
+  if (g_hmodOle32Dll == NULL)
+    {
+      ErrorF ("winTaskbarInit - Could not load ole32.dll\n");
+      return;
+    }
+    
+  g_pPropVariantClear = (PROPVARIANTCLEARPROC)
+                            GetProcAddress (g_hmodOle32Dll,
+                              "PropVariantClear");
+  if (g_pPropVariantClear == NULL)
+    {
+      ErrorF ("winTaskbarInit - Could not get "
+              "g_pPropVariantClear address\n");
+      return;
+    }
+}
+
+void
+winTaskbarDestroy (void)
+{
+  if (g_hmodOle32Dll != NULL)
+    {
+      FreeLibrary (g_hmodOle32Dll);
+      g_hmodOle32Dll = NULL;
+      g_pPropVariantClear = NULL;
+    }
+  if (g_hmodShell32Dll != NULL)
+    {
+      FreeLibrary (g_hmodShell32Dll);
+      g_hmodShell32Dll = NULL;
+      g_pSHGetPropertyStoreForWindow = NULL;
+    }
+}
+
+void
+winSetAppID (HWND hWnd, const char* AppID)
+{
+  PROPVARIANT pv;
+  IPropertyStore *pps = NULL;
+  HRESULT hr;
+  
+  if (g_pSHGetPropertyStoreForWindow == NULL ||
+      g_pPropVariantClear == NULL)
+    {
+      return;
+    }
+    
+  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))
+        {
+          hr = pps->lpVtbl->SetValue(pps, &PKEY_AppUserModel_ID, &pv);
+          g_pPropVariantClear(&pv);
+        }
+      pps->lpVtbl->Release(pps);
+    }
+}
diff -uNr src/xserver-cygwin-1.10.1-1/hw/xwin/winmultiwindowwndproc.c src/xserver-cygwin-1.10.1-1/hw/xwin/winmultiwindowwndproc.c
--- src/xserver-cygwin-1.10.1-1/hw/xwin/winmultiwindowwndproc.c	2011-04-22 18:03:27.000000000 +0200
+++ src/xserver-cygwin-1.10.1-1/hw/xwin/winmultiwindowwndproc.c	2011-07-01 19:23:06.977633000 +0200
@@ -832,6 +832,9 @@
       break;
 
     case WM_CLOSE:
+      /* Remove property AppUserModelID */
+      winSetAppID (hwnd, NULL);
+      
       /* Branch on if the window was killed in X already */
       if (pWinPriv->fXKilled)
         {
diff -uNr src/xserver-cygwin-1.10.1-1/hw/xwin/winwindow.h src/xserver-cygwin-1.10.1-1/hw/xwin/winwindow.h
--- src/xserver-cygwin-1.10.1-1/hw/xwin/winwindow.h	2011-04-22 18:03:27.000000000 +0200
+++ src/xserver-cygwin-1.10.1-1/hw/xwin/winwindow.h	2011-07-01 20:15:07.290362400 +0200
@@ -159,6 +159,14 @@
 void
 winMinimizeWindow (Window id);
 
+void
+winTaskbarInit (void);
+
+void
+winTaskbarDestroy (void);
+
+void
+winSetAppID (HWND hWnd, const char* AppID);
 
 /*
  * winmultiwindowicons.c


[-- Attachment #3: Type: text/plain, Size: 223 bytes --]

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://x.cygwin.com/docs/
FAQ:                   http://x.cygwin.com/docs/faq/

  reply	other threads:[~2011-07-01 20:38 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-06-25 12:49 Tobias Häußler
2011-06-29 13:26 ` Jon TURNEY
2011-07-02 16:51   ` Tobias Häußler [this message]
2011-07-19 15:31     ` Jon TURNEY
2011-07-25 11:20       ` Tobias Häußler

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4E0E303B.9000802@gmx.de \
    --to=tobias.haeussler@gmx.de \
    --cc=cygwin-xfree@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).