1 /*
2  *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3  *Copyright (C) Colin Harrison 2005-2009
4  *
5  *Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  *"Software"), to deal in the Software without restriction, including
8  *without limitation the rights to use, copy, modify, merge, publish,
9  *distribute, sublicense, and/or sell copies of the Software, and to
10  *permit persons to whom the Software is furnished to do so, subject to
11  *the following conditions:
12  *
13  *The above copyright notice and this permission notice shall be
14  *included in all copies or substantial portions of the Software.
15  *
16  *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
20  *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21  *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  *Except as contained in this notice, the name of the XFree86 Project
25  *shall not be used in advertising or otherwise to promote the sale, use
26  *or other dealings in this Software without prior written authorization
27  *from the XFree86 Project.
28  *
29  * Authors:	Kensuke Matsuzaki
30  *              Colin Harrison
31  */
32 
33 /* X headers */
34 #ifdef HAVE_XWIN_CONFIG_H
35 #include <xwin-config.h>
36 #endif
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #ifdef __CYGWIN__
41 #include <sys/select.h>
42 #endif
43 #include <fcntl.h>
44 #include <setjmp.h>
45 #define HANDLE void *
46 #include <pthread.h>
47 #undef HANDLE
48 #include <xcb/xcb.h>
49 #include <xcb/xcb_icccm.h>
50 #include <xcb/xcb_ewmh.h>
51 #include <xcb/xcb_aux.h>
52 
53 #include <X11/Xwindows.h>
54 
55 /* Local headers */
56 #include "X11/Xdefs.h" // for Bool type
57 #include "winwindow.h"
58 #include "winprefs.h"
59 #include "window.h"
60 #include "pixmapstr.h"
61 #include "windowstr.h"
62 #include "winglobals.h"
63 #include "windisplay.h"
64 #include "winmultiwindowicons.h"
65 
66 /* We need the native HWND atom for intWM, so for consistency use the
67    same name as extWM does */
68 #define WINDOWSWM_NATIVE_HWND "_WINDOWSWM_NATIVE_HWND"
69 
70 #ifndef HOST_NAME_MAX
71 #define HOST_NAME_MAX 255
72 #endif
73 
74 extern void winDebug(const char *format, ...);
75 extern void winReshapeMultiWindow(WindowPtr pWin);
76 extern void winUpdateRgnMultiWindow(WindowPtr pWin);
77 extern xcb_auth_info_t *winGetXcbAuthInfo(void);
78 
79 #ifndef CYGDEBUG
80 #define CYGDEBUG NO
81 #endif
82 
83 /*
84  * Constant defines
85  */
86 
87 #define WIN_CONNECT_RETRIES	5
88 #define WIN_CONNECT_DELAY	5
89 #ifdef HAS_DEVWINDOWS
90 #define WIN_MSG_QUEUE_FNAME	"/dev/windows"
91 #endif
92 
93 /*
94  * Local structures
95  */
96 
97 typedef struct _WMMsgNodeRec {
98     winWMMessageRec msg;
99     struct _WMMsgNodeRec *pNext;
100 } WMMsgNodeRec, *WMMsgNodePtr;
101 
102 typedef struct _WMMsgQueueRec {
103     struct _WMMsgNodeRec *pHead;
104     struct _WMMsgNodeRec *pTail;
105     pthread_mutex_t pmMutex;
106     pthread_cond_t pcNotEmpty;
107 } WMMsgQueueRec, *WMMsgQueuePtr;
108 
109 typedef struct _WMInfo {
110     xcb_connection_t *conn;
111     WMMsgQueueRec wmMsgQueue;
112     xcb_atom_t atmWmProtos;
113     xcb_atom_t atmWmDelete;
114     xcb_atom_t atmWmTakeFocus;
115     xcb_atom_t atmPrivMap;
116     xcb_atom_t atmUtf8String;
117     xcb_atom_t atmNetWmName;
118     xcb_ewmh_connection_t ewmh;
119 } WMInfoRec, *WMInfoPtr;
120 
121 typedef struct _WMProcArgRec {
122     DWORD dwScreen;
123     WMInfoPtr pWMInfo;
124     pthread_mutex_t *ppmServerStarted;
125 } WMProcArgRec, *WMProcArgPtr;
126 
127 typedef struct _XMsgProcArgRec {
128     xcb_connection_t *conn;
129     DWORD dwScreen;
130     WMInfoPtr pWMInfo;
131     pthread_mutex_t *ppmServerStarted;
132     HWND hwndScreen;
133 } XMsgProcArgRec, *XMsgProcArgPtr;
134 
135 /*
136  * Prototypes for local functions
137  */
138 
139 static void
140  PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode);
141 
142 static WMMsgNodePtr PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo);
143 
144 static Bool
145  InitQueue(WMMsgQueuePtr pQueue);
146 
147 static void
148  GetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName);
149 
150 static void
151  SendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData);
152 
153 static void
154  UpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow);
155 
156 static void *winMultiWindowWMProc(void *pArg);
157 
158 static void *winMultiWindowXMsgProc(void *pArg);
159 
160 static void
161  winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg);
162 
163 #if 0
164 static void
165  PreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction);
166 #endif
167 
168 static Bool
169 CheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen);
170 
171 static void
172  winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle);
173 
174 void
175  winUpdateWindowPosition(HWND hWnd, HWND * zstyle);
176 
177 /*
178  * Local globals
179  */
180 
181 static Bool g_shutdown = FALSE;
182 
183 /*
184  * Translate msg id to text, for debug purposes
185  */
186 
187 #if CYGMULTIWINDOW_DEBUG
188 static const char *
MessageName(winWMMessagePtr msg)189 MessageName(winWMMessagePtr msg)
190 {
191   switch (msg->msg)
192     {
193     case WM_WM_MOVE:
194       return "WM_WM_MOVE";
195       break;
196     case WM_WM_SIZE:
197       return "WM_WM_SIZE";
198       break;
199     case WM_WM_RAISE:
200       return "WM_WM_RAISE";
201       break;
202     case WM_WM_LOWER:
203       return "WM_WM_LOWER";
204       break;
205     case WM_WM_UNMAP:
206       return "WM_WM_UNMAP";
207       break;
208     case WM_WM_KILL:
209       return "WM_WM_KILL";
210       break;
211     case WM_WM_ACTIVATE:
212       return "WM_WM_ACTIVATE";
213       break;
214     case WM_WM_NAME_EVENT:
215       return "WM_WM_NAME_EVENT";
216       break;
217     case WM_WM_ICON_EVENT:
218       return "WM_WM_ICON_EVENT";
219       break;
220     case WM_WM_CHANGE_STATE:
221       return "WM_WM_CHANGE_STATE";
222       break;
223     case WM_WM_MAP2:
224       return "WM_WM_MAP2";
225       break;
226     case WM_WM_MAP3:
227       return "WM_WM_MAP3";
228       break;
229     case WM_WM_HINTS_EVENT:
230       return "WM_WM_HINTS_EVENT";
231       break;
232     default:
233       return "Unknown Message";
234       break;
235     }
236 }
237 #endif
238 
239 
240 /*
241  * PushMessage - Push a message onto the queue
242  */
243 
244 static void
PushMessage(WMMsgQueuePtr pQueue,WMMsgNodePtr pNode)245 PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode)
246 {
247 
248     /* Lock the queue mutex */
249     pthread_mutex_lock(&pQueue->pmMutex);
250 
251     pNode->pNext = NULL;
252 
253     if (pQueue->pTail != NULL) {
254         pQueue->pTail->pNext = pNode;
255     }
256     pQueue->pTail = pNode;
257 
258     if (pQueue->pHead == NULL) {
259         pQueue->pHead = pNode;
260     }
261 
262     /* Release the queue mutex */
263     pthread_mutex_unlock(&pQueue->pmMutex);
264 
265     /* Signal that the queue is not empty */
266     pthread_cond_signal(&pQueue->pcNotEmpty);
267 }
268 
269 /*
270  * PopMessage - Pop a message from the queue
271  */
272 
273 static WMMsgNodePtr
PopMessage(WMMsgQueuePtr pQueue,WMInfoPtr pWMInfo)274 PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo)
275 {
276     WMMsgNodePtr pNode;
277 
278     /* Lock the queue mutex */
279     pthread_mutex_lock(&pQueue->pmMutex);
280 
281     /* Wait for --- */
282     while (pQueue->pHead == NULL) {
283         pthread_cond_wait(&pQueue->pcNotEmpty, &pQueue->pmMutex);
284     }
285 
286     pNode = pQueue->pHead;
287     if (pQueue->pHead != NULL) {
288         pQueue->pHead = pQueue->pHead->pNext;
289     }
290 
291     if (pQueue->pTail == pNode) {
292         pQueue->pTail = NULL;
293     }
294 
295     /* Release the queue mutex */
296     pthread_mutex_unlock(&pQueue->pmMutex);
297 
298     return pNode;
299 }
300 
301 #if 0
302 /*
303  * HaveMessage -
304  */
305 
306 static Bool
307 HaveMessage(WMMsgQueuePtr pQueue, UINT msg, xcb_window_t iWindow)
308 {
309     WMMsgNodePtr pNode;
310 
311     for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) {
312         if (pNode->msg.msg == msg && pNode->msg.iWindow == iWindow)
313             return True;
314     }
315 
316     return False;
317 }
318 #endif
319 
320 /*
321  * InitQueue - Initialize the Window Manager message queue
322  */
323 
324 static
325     Bool
InitQueue(WMMsgQueuePtr pQueue)326 InitQueue(WMMsgQueuePtr pQueue)
327 {
328     /* Check if the pQueue pointer is NULL */
329     if (pQueue == NULL) {
330         ErrorF("InitQueue - pQueue is NULL.  Exiting.\n");
331         return FALSE;
332     }
333 
334     /* Set the head and tail to NULL */
335     pQueue->pHead = NULL;
336     pQueue->pTail = NULL;
337 
338     winDebug("InitQueue - Calling pthread_mutex_init\n");
339 
340     /* Create synchronization objects */
341     pthread_mutex_init(&pQueue->pmMutex, NULL);
342 
343     winDebug("InitQueue - pthread_mutex_init returned\n");
344     winDebug("InitQueue - Calling pthread_cond_init\n");
345 
346     pthread_cond_init(&pQueue->pcNotEmpty, NULL);
347 
348     winDebug("InitQueue - pthread_cond_init returned\n");
349 
350     return TRUE;
351 }
352 
353 static
354 char *
Xutf8TextPropertyToString(WMInfoPtr pWMInfo,xcb_icccm_get_text_property_reply_t * xtp)355 Xutf8TextPropertyToString(WMInfoPtr pWMInfo, xcb_icccm_get_text_property_reply_t *xtp)
356 {
357     char *pszReturnData;
358 
359     if ((xtp->encoding == XCB_ATOM_STRING) ||        // Latin1 ISO 8859-1
360         (xtp->encoding == pWMInfo->atmUtf8String)) { // UTF-8  ISO 10646
361         pszReturnData = strndup(xtp->name, xtp->name_len);
362     }
363     else {
364         // Converting from COMPOUND_TEXT to UTF-8 properly is complex to
365         // implement, and not very much use unless you have an old
366         // application which isn't UTF-8 aware.
367         ErrorF("Xutf8TextPropertyToString: text encoding %d is not implemented\n", xtp->encoding);
368         pszReturnData = strdup("");
369     }
370 
371     return pszReturnData;
372 }
373 
374 /*
375  * GetWindowName - Retrieve the title of an X Window
376  */
377 
378 static void
GetWindowName(WMInfoPtr pWMInfo,xcb_window_t iWin,char ** ppWindowName)379 GetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName)
380 {
381     xcb_connection_t *conn = pWMInfo->conn;
382     char *pszWindowName = NULL;
383 
384 #if CYGMULTIWINDOW_DEBUG
385     ErrorF("GetWindowName\n");
386 #endif
387 
388     /* Try to get window name from _NET_WM_NAME */
389     {
390         xcb_get_property_cookie_t cookie;
391         xcb_get_property_reply_t *reply;
392 
393         cookie = xcb_get_property(pWMInfo->conn, FALSE, iWin,
394                                   pWMInfo->atmNetWmName,
395                                   XCB_GET_PROPERTY_TYPE_ANY, 0, INT_MAX);
396         reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL);
397         if (reply && (reply->type != XCB_NONE)) {
398             pszWindowName = strndup(xcb_get_property_value(reply),
399                                     xcb_get_property_value_length(reply));
400             free(reply);
401         }
402     }
403 
404     /* Otherwise, try to get window name from WM_NAME */
405     if (!pszWindowName)
406         {
407             xcb_get_property_cookie_t cookie;
408             xcb_icccm_get_text_property_reply_t reply;
409 
410             cookie = xcb_icccm_get_wm_name(conn, iWin);
411             if (!xcb_icccm_get_wm_name_reply(conn, cookie, &reply, NULL)) {
412                 ErrorF("GetWindowName - xcb_icccm_get_wm_name_reply failed.  No name.\n");
413                 *ppWindowName = NULL;
414                 return;
415             }
416 
417             pszWindowName = Xutf8TextPropertyToString(pWMInfo, &reply);
418             xcb_icccm_get_text_property_reply_wipe(&reply);
419         }
420 
421     /* return the window name, unless... */
422     *ppWindowName = pszWindowName;
423 
424     if (g_fHostInTitle) {
425         xcb_get_property_cookie_t cookie;
426         xcb_icccm_get_text_property_reply_t reply;
427 
428         /* Try to get client machine name */
429         cookie = xcb_icccm_get_wm_client_machine(conn, iWin);
430         if (xcb_icccm_get_wm_client_machine_reply(conn, cookie, &reply, NULL)) {
431             char *pszClientMachine;
432             char *pszClientHostname;
433             char *dot;
434             char hostname[HOST_NAME_MAX + 1];
435 
436             pszClientMachine = Xutf8TextPropertyToString(pWMInfo, &reply);
437             xcb_icccm_get_text_property_reply_wipe(&reply);
438 
439             /* If client machine name looks like a FQDN, find the hostname */
440             pszClientHostname = strdup(pszClientMachine);
441             dot = strchr(pszClientHostname, '.');
442             if (dot)
443                 *dot = '\0';
444 
445             /*
446                If we have a client machine hostname
447                and it's not the local hostname
448                and it's not already in the window title...
449              */
450             if (strlen(pszClientHostname) &&
451                 !gethostname(hostname, HOST_NAME_MAX + 1) &&
452                 strcmp(hostname, pszClientHostname) &&
453                 (strstr(pszWindowName, pszClientHostname) == 0)) {
454                 /* ... add '@<clientmachine>' to end of window name */
455                 *ppWindowName =
456                     malloc(strlen(pszWindowName) +
457                            strlen(pszClientMachine) + 2);
458                 strcpy(*ppWindowName, pszWindowName);
459                 strcat(*ppWindowName, "@");
460                 strcat(*ppWindowName, pszClientMachine);
461 
462                 free(pszWindowName);
463             }
464 
465             free(pszClientMachine);
466             free(pszClientHostname);
467         }
468     }
469 }
470 
471 /*
472  * Does the client support the specified WM_PROTOCOLS protocol?
473  */
474 
475 static Bool
IsWmProtocolAvailable(WMInfoPtr pWMInfo,xcb_window_t iWindow,xcb_atom_t atmProtocol)476 IsWmProtocolAvailable(WMInfoPtr pWMInfo, xcb_window_t iWindow, xcb_atom_t atmProtocol)
477 {
478   int i, found = 0;
479   xcb_get_property_cookie_t cookie;
480   xcb_icccm_get_wm_protocols_reply_t reply;
481   xcb_connection_t *conn = pWMInfo->conn;
482 
483   cookie = xcb_icccm_get_wm_protocols(conn, iWindow, pWMInfo->ewmh.WM_PROTOCOLS);
484   if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &reply, NULL)) {
485     for (i = 0; i < reply.atoms_len; ++i)
486       if (reply.atoms[i] == atmProtocol) {
487               ++found;
488               break;
489       }
490     xcb_icccm_get_wm_protocols_reply_wipe(&reply);
491   }
492 
493   return found > 0;
494 }
495 
496 /*
497  * Send a message to the X server from the WM thread
498  */
499 
500 static void
SendXMessage(xcb_connection_t * conn,xcb_window_t iWin,xcb_atom_t atmType,long nData)501 SendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData)
502 {
503     xcb_client_message_event_t e;
504 
505     /* Prepare the X event structure */
506     memset(&e, 0, sizeof(e));
507     e.response_type = XCB_CLIENT_MESSAGE;
508     e.window = iWin;
509     e.type = atmType;
510     e.format = 32;
511     e.data.data32[0] = nData;
512     e.data.data32[1] = XCB_CURRENT_TIME;
513 
514     /* Send the event to X */
515     xcb_send_event(conn, FALSE, iWin, XCB_EVENT_MASK_NO_EVENT, (const char *)&e);
516 }
517 
518 /*
519  * See if we can get the stored HWND for this window...
520  */
521 static HWND
getHwnd(WMInfoPtr pWMInfo,xcb_window_t iWindow)522 getHwnd(WMInfoPtr pWMInfo, xcb_window_t iWindow)
523 {
524     HWND hWnd = NULL;
525     xcb_get_property_cookie_t cookie;
526     xcb_get_property_reply_t *reply;
527 
528     cookie = xcb_get_property(pWMInfo->conn, FALSE, iWindow, pWMInfo->atmPrivMap,
529                               XCB_ATOM_INTEGER, 0L, sizeof(HWND)/4L);
530     reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL);
531 
532     if (reply) {
533         int length = xcb_get_property_value_length(reply);
534         HWND *value = xcb_get_property_value(reply);
535 
536         if (value && (length == sizeof(HWND))) {
537             hWnd = *value;
538         }
539         free(reply);
540     }
541 
542     /* Some sanity checks */
543     if (!hWnd)
544         return NULL;
545     if (!IsWindow(hWnd))
546         return NULL;
547 
548     return hWnd;
549 }
550 
551 /*
552  * Helper function to check for override-redirect
553  */
554 static Bool
IsOverrideRedirect(xcb_connection_t * conn,xcb_window_t iWin)555 IsOverrideRedirect(xcb_connection_t *conn, xcb_window_t iWin)
556 {
557     Bool result = FALSE;
558     xcb_get_window_attributes_reply_t *reply;
559     xcb_get_window_attributes_cookie_t cookie;
560 
561     cookie = xcb_get_window_attributes(conn, iWin);
562     reply = xcb_get_window_attributes_reply(conn, cookie, NULL);
563     if (reply) {
564         result = (reply->override_redirect != 0);
565         free(reply);
566     }
567     else {
568         ErrorF("IsOverrideRedirect: Failed to get window attributes\n");
569     }
570 
571     return result;
572 }
573 
574 /*
575  * Helper function to get class and window names
576 */
577 static void
GetClassNames(WMInfoPtr pWMInfo,xcb_window_t iWindow,char ** res_name,char ** res_class,char ** window_name)578 GetClassNames(WMInfoPtr pWMInfo, xcb_window_t iWindow, char **res_name,
579               char **res_class, char **window_name)
580 {
581     xcb_get_property_cookie_t cookie1;
582     xcb_icccm_get_wm_class_reply_t reply1;
583     xcb_get_property_cookie_t cookie2;
584     xcb_icccm_get_text_property_reply_t reply2;
585 
586     cookie1 = xcb_icccm_get_wm_class(pWMInfo->conn, iWindow);
587     if (xcb_icccm_get_wm_class_reply(pWMInfo->conn, cookie1, &reply1,
588                                      NULL)) {
589         *res_name = strdup(reply1.instance_name);
590         *res_class = strdup(reply1.class_name);
591         xcb_icccm_get_wm_class_reply_wipe(&reply1);
592     }
593     else {
594         *res_name = strdup("");
595         *res_class = strdup("");
596     }
597 
598     cookie2 = xcb_icccm_get_wm_name(pWMInfo->conn, iWindow);
599     if (xcb_icccm_get_wm_name_reply(pWMInfo->conn, cookie2, &reply2, NULL)) {
600         *window_name = strndup(reply2.name, reply2.name_len);
601         xcb_icccm_get_text_property_reply_wipe(&reply2);
602     }
603     else {
604         *window_name = strdup("");
605     }
606 }
607 
608 /*
609  * Updates the name of a HWND according to its X WM_NAME property
610  */
611 
612 static void
UpdateName(WMInfoPtr pWMInfo,xcb_window_t iWindow)613 UpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow)
614 {
615     HWND hWnd;
616 
617     hWnd = getHwnd(pWMInfo, iWindow);
618     if (!hWnd)
619         return;
620 
621     /* If window isn't override-redirect */
622     if (!IsOverrideRedirect(pWMInfo->conn, iWindow)) {
623         char *pszWindowName;
624 
625         /* Get the X windows window name */
626         GetWindowName(pWMInfo, iWindow, &pszWindowName);
627 
628         if (pszWindowName) {
629             /* Convert from UTF-8 to wide char */
630             int iLen =
631                 MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1, NULL, 0);
632             wchar_t *pwszWideWindowName =
633                 malloc(sizeof(wchar_t)*(iLen + 1));
634             MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1,
635                                 pwszWideWindowName, iLen);
636 
637             /* Set the Windows window name */
638             SetWindowTextW(hWnd, pwszWideWindowName);
639 
640             free(pwszWideWindowName);
641             free(pszWindowName);
642         }
643     }
644 }
645 
646 /*
647  * Updates the icon of a HWND according to its X icon properties
648  */
649 
650 static void
UpdateIcon(WMInfoPtr pWMInfo,xcb_window_t iWindow)651 UpdateIcon(WMInfoPtr pWMInfo, xcb_window_t iWindow)
652 {
653     HWND hWnd;
654     HICON hIconNew = NULL;
655 
656     hWnd = getHwnd(pWMInfo, iWindow);
657     if (!hWnd)
658         return;
659 
660     /* If window isn't override-redirect */
661     if (!IsOverrideRedirect(pWMInfo->conn, iWindow)) {
662         char *window_name = 0;
663         char *res_name = 0;
664         char *res_class = 0;
665 
666         GetClassNames(pWMInfo, iWindow, &res_name, &res_class, &window_name);
667 
668         hIconNew = winOverrideIcon(res_name, res_class, window_name);
669 
670         free(res_name);
671         free(res_class);
672         free(window_name);
673         winUpdateIcon(hWnd, pWMInfo->conn, iWindow, hIconNew);
674     }
675 }
676 
677 /*
678  * Updates the style of a HWND according to its X style properties
679  */
680 
681 static void
UpdateStyle(WMInfoPtr pWMInfo,xcb_window_t iWindow)682 UpdateStyle(WMInfoPtr pWMInfo, xcb_window_t iWindow)
683 {
684     HWND hWnd;
685     HWND zstyle = HWND_NOTOPMOST;
686     UINT flags;
687 
688     hWnd = getHwnd(pWMInfo, iWindow);
689     if (!hWnd)
690         return;
691 
692     /* Determine the Window style, which determines borders and clipping region... */
693     winApplyHints(pWMInfo, iWindow, hWnd, &zstyle);
694     winUpdateWindowPosition(hWnd, &zstyle);
695 
696     /* Apply the updated window style, without changing it's show or activation state */
697     flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE;
698     if (zstyle == HWND_NOTOPMOST)
699         flags |= SWP_NOZORDER | SWP_NOOWNERZORDER;
700     SetWindowPos(hWnd, NULL, 0, 0, 0, 0, flags);
701 
702     /*
703        Use the WS_EX_TOOLWINDOW style to remove window from Alt-Tab window switcher
704 
705        According to MSDN, this is supposed to remove the window from the taskbar as well,
706        if we SW_HIDE before changing the style followed by SW_SHOW afterwards.
707 
708        But that doesn't seem to work reliably, and causes the window to flicker, so use
709        the iTaskbarList interface to tell the taskbar to show or hide this window.
710      */
711     winShowWindowOnTaskbar(hWnd,
712                            (GetWindowLongPtr(hWnd, GWL_EXSTYLE) &
713                             WS_EX_APPWINDOW) ? TRUE : FALSE);
714 }
715 
716 /*
717  * Updates the state of a HWND
718  * (only minimization supported at the moment)
719  */
720 
721 static void
UpdateState(WMInfoPtr pWMInfo,xcb_window_t iWindow)722 UpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow)
723 {
724     HWND hWnd;
725 
726     winDebug("UpdateState: iWindow 0x%08x\n", (int)iWindow);
727 
728     hWnd = getHwnd(pWMInfo, iWindow);
729     if (!hWnd)
730         return;
731 
732     ShowWindow(hWnd, SW_MINIMIZE);
733 }
734 
735 #if 0
736 /*
737  * Fix up any differences between the X11 and Win32 window stacks
738  * starting at the window passed in
739  */
740 static void
741 PreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction)
742 {
743     HWND hWnd;
744     DWORD myWinProcID, winProcID;
745     xcb_window_t xWindow;
746     WINDOWPLACEMENT wndPlace;
747 
748     hWnd = getHwnd(pWMInfo, iWindow);
749     if (!hWnd)
750         return;
751 
752     GetWindowThreadProcessId(hWnd, &myWinProcID);
753     hWnd = GetNextWindow(hWnd, direction);
754 
755     while (hWnd) {
756         GetWindowThreadProcessId(hWnd, &winProcID);
757         if (winProcID == myWinProcID) {
758             wndPlace.length = sizeof(WINDOWPLACEMENT);
759             GetWindowPlacement(hWnd, &wndPlace);
760             if (!(wndPlace.showCmd == SW_HIDE ||
761                   wndPlace.showCmd == SW_MINIMIZE)) {
762                 xWindow = (Window) GetProp(hWnd, WIN_WID_PROP);
763                 if (xWindow) {
764                     if (direction == GW_HWNDPREV)
765                         XRaiseWindow(pWMInfo->pDisplay, xWindow);
766                     else
767                         XLowerWindow(pWMInfo->pDisplay, xWindow);
768                 }
769             }
770         }
771         hWnd = GetNextWindow(hWnd, direction);
772     }
773 }
774 #endif                          /* PreserveWin32Stack */
775 
776 /*
777  * winMultiWindowWMProc
778  */
779 
780 static void *
winMultiWindowWMProc(void * pArg)781 winMultiWindowWMProc(void *pArg)
782 {
783     WMProcArgPtr pProcArg = (WMProcArgPtr) pArg;
784     WMInfoPtr pWMInfo = pProcArg->pWMInfo;
785 
786     /* Initialize the Window Manager */
787     winInitMultiWindowWM(pWMInfo, pProcArg);
788 
789 #if CYGMULTIWINDOW_DEBUG
790     ErrorF("winMultiWindowWMProc ()\n");
791 #endif
792 
793     /* Loop until we explicitly break out */
794     for (;;) {
795         WMMsgNodePtr pNode;
796 
797         /* Pop a message off of our queue */
798         pNode = PopMessage(&pWMInfo->wmMsgQueue, pWMInfo);
799         if (pNode == NULL) {
800             /* Bail if PopMessage returns without a message */
801             /* NOTE: Remember that PopMessage is a blocking function. */
802             ErrorF("winMultiWindowWMProc - Queue is Empty?  Exiting.\n");
803             pthread_exit(NULL);
804         }
805 
806 #if CYGMULTIWINDOW_DEBUG
807         ErrorF("winMultiWindowWMProc - MSG: %s (%d) ID: %d\n",
808                MessageName(&(pNode->msg)), (int)pNode->msg.msg, (int)pNode->msg.dwID);
809 #endif
810 
811         /* Branch on the message type */
812         switch (pNode->msg.msg) {
813 #if 0
814         case WM_WM_MOVE:
815             break;
816 
817         case WM_WM_SIZE:
818             break;
819 #endif
820 
821         case WM_WM_RAISE:
822             /* Raise the window */
823             {
824                 const static uint32_t values[] = { XCB_STACK_MODE_ABOVE };
825                 xcb_configure_window(pWMInfo->conn, pNode->msg.iWindow,
826                                      XCB_CONFIG_WINDOW_STACK_MODE, values);
827             }
828 
829 #if 0
830             PreserveWin32Stack(pWMInfo, pNode->msg.iWindow, GW_HWNDPREV);
831 #endif
832             break;
833 
834         case WM_WM_LOWER:
835             /* Lower the window */
836             {
837                 const static uint32_t values[] = { XCB_STACK_MODE_BELOW };
838                 xcb_configure_window(pWMInfo->conn, pNode->msg.iWindow,
839                                      XCB_CONFIG_WINDOW_STACK_MODE, values);
840             }
841             break;
842 
843         case WM_WM_MAP2:
844             /* Put a note as to the HWND associated with this Window */
845             xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE,
846                                 pNode->msg.iWindow, pWMInfo->atmPrivMap,
847                                 XCB_ATOM_INTEGER, 32,
848                                 sizeof(HWND)/4, &(pNode->msg.hwndWindow));
849 
850             break;
851 
852         case WM_WM_MAP3:
853             /* Put a note as to the HWND associated with this Window */
854             xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE,
855                                 pNode->msg.iWindow, pWMInfo->atmPrivMap,
856                                 XCB_ATOM_INTEGER, 32,
857                                 sizeof(HWND)/4, &(pNode->msg.hwndWindow));
858 
859             UpdateName(pWMInfo, pNode->msg.iWindow);
860             UpdateIcon(pWMInfo, pNode->msg.iWindow);
861             UpdateStyle(pWMInfo, pNode->msg.iWindow);
862 
863 
864             /* Reshape */
865             {
866                 WindowPtr pWin =
867                     GetProp(pNode->msg.hwndWindow, WIN_WINDOW_PROP);
868                 if (pWin) {
869                     winReshapeMultiWindow(pWin);
870                     winUpdateRgnMultiWindow(pWin);
871                 }
872             }
873 
874             break;
875 
876         case WM_WM_UNMAP:
877 
878             /* Unmap the window */
879             xcb_unmap_window(pWMInfo->conn, pNode->msg.iWindow);
880             break;
881 
882         case WM_WM_KILL:
883             {
884                 /* --- */
885                 if (IsWmProtocolAvailable(pWMInfo,
886                                           pNode->msg.iWindow,
887                                           pWMInfo->atmWmDelete))
888                     SendXMessage(pWMInfo->conn,
889                                  pNode->msg.iWindow,
890                                  pWMInfo->atmWmProtos, pWMInfo->atmWmDelete);
891                 else
892                     xcb_kill_client(pWMInfo->conn, pNode->msg.iWindow);
893             }
894             break;
895 
896         case WM_WM_ACTIVATE:
897             /* Set the input focus */
898 
899             /*
900                ICCCM 4.1.7 is pretty opaque, but it appears that the rules are
901                actually quite simple:
902                -- the WM_HINTS input field determines whether the WM should call
903                XSetInputFocus()
904                -- independently, the WM_TAKE_FOCUS protocol determines whether
905                the WM should send a WM_TAKE_FOCUS ClientMessage.
906             */
907             {
908               Bool neverFocus = FALSE;
909               xcb_get_property_cookie_t cookie;
910               xcb_icccm_wm_hints_t hints;
911 
912               cookie = xcb_icccm_get_wm_hints(pWMInfo->conn, pNode->msg.iWindow);
913               if (xcb_icccm_get_wm_hints_reply(pWMInfo->conn, cookie, &hints,
914                                                NULL)) {
915                 if (hints.flags & XCB_ICCCM_WM_HINT_INPUT)
916                   neverFocus = !hints.input;
917               }
918 
919               if (!neverFocus)
920                 xcb_set_input_focus(pWMInfo->conn, XCB_INPUT_FOCUS_POINTER_ROOT,
921                                     pNode->msg.iWindow, XCB_CURRENT_TIME);
922 
923               if (IsWmProtocolAvailable(pWMInfo,
924                                         pNode->msg.iWindow,
925                                         pWMInfo->atmWmTakeFocus))
926                 SendXMessage(pWMInfo->conn,
927                              pNode->msg.iWindow,
928                              pWMInfo->atmWmProtos, pWMInfo->atmWmTakeFocus);
929 
930             }
931             break;
932 
933         case WM_WM_NAME_EVENT:
934             UpdateName(pWMInfo, pNode->msg.iWindow);
935             break;
936 
937         case WM_WM_ICON_EVENT:
938             UpdateIcon(pWMInfo, pNode->msg.iWindow);
939             break;
940 
941         case WM_WM_HINTS_EVENT:
942             {
943             /* Don't do anything if this is an override-redirect window */
944             if (IsOverrideRedirect(pWMInfo->conn, pNode->msg.iWindow))
945               break;
946 
947             UpdateStyle(pWMInfo, pNode->msg.iWindow);
948             }
949             break;
950 
951         case WM_WM_CHANGE_STATE:
952             UpdateState(pWMInfo, pNode->msg.iWindow);
953             break;
954 
955         default:
956             ErrorF("winMultiWindowWMProc - Unknown Message.  Exiting.\n");
957             pthread_exit(NULL);
958             break;
959         }
960 
961         /* Free the retrieved message */
962         free(pNode);
963 
964         /* Flush any pending events on our display */
965         xcb_flush(pWMInfo->conn);
966 
967         /* This is just laziness rather than making sure we used _checked everywhere */
968         {
969             xcb_generic_event_t *event = xcb_poll_for_event(pWMInfo->conn);
970             if (event) {
971                 if ((event->response_type & ~0x80) == 0) {
972                     xcb_generic_error_t *err = (xcb_generic_error_t *)event;
973                     ErrorF("winMultiWindowWMProc - Error code: %i, ID: 0x%08x, "
974                            "Major opcode: %i, Minor opcode: %i\n",
975                            err->error_code, err->resource_id,
976                            err->major_code, err->minor_code);
977                 }
978             }
979         }
980 
981         /* I/O errors etc. */
982         {
983             int e = xcb_connection_has_error(pWMInfo->conn);
984             if (e) {
985                 ErrorF("winMultiWindowWMProc - Fatal error %d on xcb connection\n", e);
986                 break;
987             }
988         }
989     }
990 
991     /* Free the condition variable */
992     pthread_cond_destroy(&pWMInfo->wmMsgQueue.pcNotEmpty);
993 
994     /* Free the mutex variable */
995     pthread_mutex_destroy(&pWMInfo->wmMsgQueue.pmMutex);
996 
997     /* Free the passed-in argument */
998     free(pProcArg);
999 
1000 #if CYGMULTIWINDOW_DEBUG
1001     ErrorF("-winMultiWindowWMProc ()\n");
1002 #endif
1003     return NULL;
1004 }
1005 
1006 static xcb_atom_t
intern_atom(xcb_connection_t * conn,const char * atomName)1007 intern_atom(xcb_connection_t *conn, const char *atomName)
1008 {
1009   xcb_intern_atom_reply_t *atom_reply;
1010   xcb_intern_atom_cookie_t atom_cookie;
1011   xcb_atom_t atom = XCB_ATOM_NONE;
1012 
1013   atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName);
1014   atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL);
1015   if (atom_reply) {
1016     atom = atom_reply->atom;
1017     free(atom_reply);
1018   }
1019   return atom;
1020 }
1021 
1022 /*
1023  * X message procedure
1024  */
1025 
1026 static void *
winMultiWindowXMsgProc(void * pArg)1027 winMultiWindowXMsgProc(void *pArg)
1028 {
1029     winWMMessageRec msg;
1030     XMsgProcArgPtr pProcArg = (XMsgProcArgPtr) pArg;
1031     char pszDisplay[512];
1032     int iRetries;
1033     xcb_atom_t atmWmName;
1034     xcb_atom_t atmNetWmName;
1035     xcb_atom_t atmWmHints;
1036     xcb_atom_t atmWmChange;
1037     xcb_atom_t atmNetWmIcon;
1038     xcb_atom_t atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints;
1039     int iReturn;
1040     xcb_auth_info_t *auth_info;
1041 
1042     winDebug("winMultiWindowXMsgProc - Hello\n");
1043 
1044     /* Check that argument pointer is not invalid */
1045     if (pProcArg == NULL) {
1046         ErrorF("winMultiWindowXMsgProc - pProcArg is NULL.  Exiting.\n");
1047         pthread_exit(NULL);
1048     }
1049 
1050     winDebug("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n");
1051 
1052     /* Grab the server started mutex - pause until we get it */
1053     iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
1054     if (iReturn != 0) {
1055         ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () failed: %d.  "
1056                "Exiting.\n", iReturn);
1057         pthread_exit(NULL);
1058     }
1059 
1060     winDebug("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n");
1061 
1062     /* Release the server started mutex */
1063     pthread_mutex_unlock(pProcArg->ppmServerStarted);
1064 
1065     winDebug("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n");
1066 
1067     /* Setup the display connection string x */
1068     winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen);
1069 
1070     /* Print the display connection string */
1071     ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay);
1072 
1073     /* Use our generated cookie for authentication */
1074     auth_info = winGetXcbAuthInfo();
1075 
1076     /* Initialize retry count */
1077     iRetries = 0;
1078 
1079     /* Open the X display */
1080     do {
1081         /* Try to open the display */
1082         pProcArg->conn = xcb_connect_to_display_with_auth_info(pszDisplay,
1083                                                                auth_info, NULL);
1084         if (xcb_connection_has_error(pProcArg->conn)) {
1085             ErrorF("winMultiWindowXMsgProc - Could not open display, try: %d, "
1086                    "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
1087             ++iRetries;
1088             sleep(WIN_CONNECT_DELAY);
1089             continue;
1090         }
1091         else
1092             break;
1093     }
1094     while (xcb_connection_has_error(pProcArg->conn) && iRetries < WIN_CONNECT_RETRIES);
1095 
1096     /* Make sure that the display opened */
1097     if (xcb_connection_has_error(pProcArg->conn)) {
1098         ErrorF("winMultiWindowXMsgProc - Failed opening the display.  "
1099                "Exiting.\n");
1100         pthread_exit(NULL);
1101     }
1102 
1103     ErrorF("winMultiWindowXMsgProc - xcb_connect() returned and "
1104            "successfully opened the display.\n");
1105 
1106     /* Check if another window manager is already running */
1107     if (CheckAnotherWindowManager(pProcArg->conn, pProcArg->dwScreen)) {
1108         ErrorF("winMultiWindowXMsgProc - "
1109                "another window manager is running.  Exiting.\n");
1110         pthread_exit(NULL);
1111     }
1112 
1113     {
1114         /* Get root window id */
1115         xcb_screen_t *root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen);
1116         xcb_window_t root_window_id = root_screen->root;
1117 
1118         /* Set WM_ICON_SIZE property indicating desired icon sizes */
1119         typedef struct {
1120             uint32_t min_width, min_height;
1121             uint32_t max_width, max_height;
1122             int32_t width_inc, height_inc;
1123         } xcb_wm_icon_size_hints_hints_t;
1124 
1125         xcb_wm_icon_size_hints_hints_t xis;
1126         xis.min_width = xis.min_height = 16;
1127         xis.max_width = xis.max_height = 48;
1128         xis.width_inc = xis.height_inc = 16;
1129 
1130         xcb_change_property(pProcArg->conn, XCB_PROP_MODE_REPLACE, root_window_id,
1131                             XCB_ATOM_WM_ICON_SIZE, XCB_ATOM_WM_ICON_SIZE, 32,
1132                             sizeof(xis)/4, &xis);
1133     }
1134 
1135     atmWmName = intern_atom(pProcArg->conn, "WM_NAME");
1136     atmNetWmName = intern_atom(pProcArg->conn, "_NET_WM_NAME");
1137     atmWmHints = intern_atom(pProcArg->conn, "WM_HINTS");
1138     atmWmChange = intern_atom(pProcArg->conn, "WM_CHANGE_STATE");
1139     atmNetWmIcon = intern_atom(pProcArg->conn, "_NET_WM_ICON");
1140     atmWindowState = intern_atom(pProcArg->conn, "_NET_WM_STATE");
1141     atmMotifWmHints = intern_atom(pProcArg->conn, "_MOTIF_WM_HINTS");
1142     atmWindowType = intern_atom(pProcArg->conn, "_NET_WM_WINDOW_TYPE");
1143     atmNormalHints = intern_atom(pProcArg->conn, "WM_NORMAL_HINTS");
1144 
1145     /*
1146        iiimxcf had a bug until 2009-04-27, assuming that the
1147        WM_STATE atom exists, causing clients to fail with
1148        a BadAtom X error if it doesn't.
1149 
1150        Since this is on in the default Solaris 10 install,
1151        workaround this by making sure it does exist...
1152      */
1153     intern_atom(pProcArg->conn, "WM_STATE");
1154 
1155     /* Loop until we explicitly break out */
1156     while (1) {
1157         xcb_generic_event_t *event;
1158         uint8_t type;
1159         Bool send_event;
1160 
1161         if (g_shutdown)
1162             break;
1163 
1164         /* Fetch next event */
1165         event = xcb_wait_for_event(pProcArg->conn);
1166         if (!event) { // returns NULL on I/O error
1167             int e = xcb_connection_has_error(pProcArg->conn);
1168             ErrorF("winMultiWindowXMsgProc - Fatal error %d on xcb connection\n", e);
1169             break;
1170         }
1171 
1172         type = event->response_type & ~0x80;
1173         send_event = event->response_type & 0x80;
1174 
1175         winDebug("winMultiWindowXMsgProc - event %d\n", type);
1176 
1177         /* Branch on event type */
1178         if (type == 0) {
1179             xcb_generic_error_t *err = (xcb_generic_error_t *)event;
1180             ErrorF("winMultiWindowXMsgProc - Error code: %i, ID: 0x%08x, "
1181                    "Major opcode: %i, Minor opcode: %i\n",
1182                    err->error_code, err->resource_id,
1183                    err->major_code, err->minor_code);
1184             }
1185         else if (type == XCB_CREATE_NOTIFY) {
1186             xcb_create_notify_event_t *notify = (xcb_create_notify_event_t *)event;
1187 
1188             /* Request property change events */
1189             const static uint32_t mask_value[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
1190             xcb_change_window_attributes (pProcArg->conn, notify->window,
1191                                           XCB_CW_EVENT_MASK, mask_value);
1192 
1193             /* If it's not override-redirect, set the border-width to 0 */
1194             if (!IsOverrideRedirect(pProcArg->conn, notify->window)) {
1195                 const static uint32_t width_value[] = { 0 };
1196                 xcb_configure_window(pProcArg->conn, notify->window,
1197                                      XCB_CONFIG_WINDOW_BORDER_WIDTH, width_value);
1198             }
1199         }
1200         else if (type == XCB_MAP_NOTIFY) {
1201             /* Fake a reparentNotify event as SWT/Motif expects a
1202                Window Manager to reparent a top-level window when
1203                it is mapped and waits until they do.
1204 
1205                We don't actually need to reparent, as the frame is
1206                a native window, not an X window
1207 
1208                We do this on MapNotify, not MapRequest like a real
1209                Window Manager would, so we don't have do get involved
1210                in actually mapping the window via it's (non-existent)
1211                parent...
1212 
1213                See sourceware bugzilla #9848
1214              */
1215 
1216             xcb_map_notify_event_t *notify = (xcb_map_notify_event_t *)event;
1217 
1218             xcb_get_geometry_cookie_t cookie;
1219             xcb_get_geometry_reply_t *reply;
1220             xcb_query_tree_cookie_t cookie_qt;
1221             xcb_query_tree_reply_t *reply_qt;
1222 
1223             cookie = xcb_get_geometry(pProcArg->conn, notify->window);
1224             cookie_qt = xcb_query_tree(pProcArg->conn, notify->window);
1225             reply = xcb_get_geometry_reply(pProcArg->conn, cookie, NULL);
1226             reply_qt = xcb_query_tree_reply(pProcArg->conn, cookie_qt, NULL);
1227 
1228             if (reply && reply_qt) {
1229                 /*
1230                    It's a top-level window if the parent window is a root window
1231                    Only non-override_redirect windows can get reparented
1232                  */
1233                 if ((reply->root == reply_qt->parent) && !notify->override_redirect) {
1234                     xcb_reparent_notify_event_t event_send;
1235 
1236                     event_send.response_type = ReparentNotify;
1237                     event_send.event = notify->window;
1238                     event_send.window = notify->window;
1239                     event_send.parent = reply_qt->parent;
1240                     event_send.x = reply->x;
1241                     event_send.y = reply->y;
1242 
1243                     xcb_send_event (pProcArg->conn, TRUE, notify->window,
1244                                     XCB_EVENT_MASK_STRUCTURE_NOTIFY,
1245                                     (const char *)&event_send);
1246 
1247                     free(reply_qt);
1248                     free(reply);
1249                 }
1250             }
1251         }
1252         else if (type == XCB_CONFIGURE_NOTIFY) {
1253             if (!send_event) {
1254                 /*
1255                    Java applications using AWT on JRE 1.6.0 break with non-reparenting WMs AWT
1256                    doesn't explicitly know about (See sun bug #6434227)
1257 
1258                    XDecoratedPeer.handleConfigureNotifyEvent() only processes non-synthetic
1259                    ConfigureNotify events to update window location if it's identified the
1260                    WM as a non-reparenting WM it knows about (compiz or lookingglass)
1261 
1262                    Rather than tell all sorts of lies to get XWM to recognize us as one of
1263                    those, simply send a synthetic ConfigureNotify for every non-synthetic one
1264                  */
1265                 xcb_configure_notify_event_t *notify = (xcb_configure_notify_event_t *)event;
1266                 xcb_configure_notify_event_t event_send = *notify;
1267 
1268                 event_send.event = notify->window;
1269 
1270                 xcb_send_event(pProcArg->conn, TRUE, notify->window,
1271                                XCB_EVENT_MASK_STRUCTURE_NOTIFY,
1272                                (const char *)&event_send);
1273             }
1274         }
1275         else if (type ==  XCB_PROPERTY_NOTIFY) {
1276             xcb_property_notify_event_t *notify = (xcb_property_notify_event_t *)event;
1277 
1278             if ((notify->atom == atmWmName) ||
1279                 (notify->atom == atmNetWmName)) {
1280                 memset(&msg, 0, sizeof(msg));
1281 
1282                 msg.msg = WM_WM_NAME_EVENT;
1283                 msg.iWindow = notify->window;
1284 
1285                 /* Other fields ignored */
1286                 winSendMessageToWM(pProcArg->pWMInfo, &msg);
1287             }
1288             else {
1289                 /*
1290                    Several properties are considered for WM hints, check if this property change affects any of them...
1291                    (this list needs to be kept in sync with winApplyHints())
1292                  */
1293                 if ((notify->atom == atmWmHints) ||
1294                     (notify->atom == atmWindowState) ||
1295                     (notify->atom == atmMotifWmHints) ||
1296                     (notify->atom == atmWindowType) ||
1297                     (notify->atom == atmNormalHints)) {
1298                     memset(&msg, 0, sizeof(msg));
1299                     msg.msg = WM_WM_HINTS_EVENT;
1300                     msg.iWindow = notify->window;
1301 
1302                     /* Other fields ignored */
1303                     winSendMessageToWM(pProcArg->pWMInfo, &msg);
1304                 }
1305 
1306                 /* Not an else as WM_HINTS affects both style and icon */
1307                 if ((notify->atom == atmWmHints) ||
1308                     (notify->atom == atmNetWmIcon)) {
1309                     memset(&msg, 0, sizeof(msg));
1310                     msg.msg = WM_WM_ICON_EVENT;
1311                     msg.iWindow = notify->window;
1312 
1313                     /* Other fields ignored */
1314                     winSendMessageToWM(pProcArg->pWMInfo, &msg);
1315                 }
1316             }
1317         }
1318         else if (type == XCB_CLIENT_MESSAGE) {
1319             xcb_client_message_event_t *client_msg = (xcb_client_message_event_t *)event;
1320 
1321             if (client_msg->type == atmWmChange
1322                  && client_msg->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) {
1323                 ErrorF("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n");
1324 
1325                 memset(&msg, 0, sizeof(msg));
1326 
1327                 msg.msg = WM_WM_CHANGE_STATE;
1328                 msg.iWindow = client_msg->window;
1329 
1330                 winSendMessageToWM(pProcArg->pWMInfo, &msg);
1331             }
1332         }
1333 
1334         /* Free the event */
1335         free(event);
1336     }
1337 
1338     xcb_disconnect(pProcArg->conn);
1339     pthread_exit(NULL);
1340     return NULL;
1341 }
1342 
1343 /*
1344  * winInitWM - Entry point for the X server to spawn
1345  * the Window Manager thread.  Called from
1346  * winscrinit.c/winFinishScreenInitFB ().
1347  */
1348 
1349 Bool
winInitWM(void ** ppWMInfo,pthread_t * ptWMProc,pthread_t * ptXMsgProc,pthread_mutex_t * ppmServerStarted,int dwScreen,HWND hwndScreen)1350 winInitWM(void **ppWMInfo,
1351           pthread_t * ptWMProc,
1352           pthread_t * ptXMsgProc,
1353           pthread_mutex_t * ppmServerStarted,
1354           int dwScreen, HWND hwndScreen)
1355 {
1356     WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec));
1357     WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec));
1358     XMsgProcArgPtr pXMsgArg = malloc(sizeof(XMsgProcArgRec));
1359 
1360     /* Bail if the input parameters are bad */
1361     if (pArg == NULL || pWMInfo == NULL || pXMsgArg == NULL) {
1362         ErrorF("winInitWM - malloc failed.\n");
1363         free(pArg);
1364         free(pWMInfo);
1365         free(pXMsgArg);
1366         return FALSE;
1367     }
1368 
1369     /* Zero the allocated memory */
1370     ZeroMemory(pArg, sizeof(WMProcArgRec));
1371     ZeroMemory(pWMInfo, sizeof(WMInfoRec));
1372     ZeroMemory(pXMsgArg, sizeof(XMsgProcArgRec));
1373 
1374     /* Set a return pointer to the Window Manager info structure */
1375     *ppWMInfo = pWMInfo;
1376 
1377     /* Setup the argument structure for the thread function */
1378     pArg->dwScreen = dwScreen;
1379     pArg->pWMInfo = pWMInfo;
1380     pArg->ppmServerStarted = ppmServerStarted;
1381 
1382     /* Intialize the message queue */
1383     if (!InitQueue(&pWMInfo->wmMsgQueue)) {
1384         ErrorF("winInitWM - InitQueue () failed.\n");
1385         return FALSE;
1386     }
1387 
1388     /* Spawn a thread for the Window Manager */
1389     if (pthread_create(ptWMProc, NULL, winMultiWindowWMProc, pArg)) {
1390         /* Bail if thread creation failed */
1391         ErrorF("winInitWM - pthread_create failed for Window Manager.\n");
1392         return FALSE;
1393     }
1394 
1395     /* Spawn the XNextEvent thread, will send messages to WM */
1396     pXMsgArg->dwScreen = dwScreen;
1397     pXMsgArg->pWMInfo = pWMInfo;
1398     pXMsgArg->ppmServerStarted = ppmServerStarted;
1399     pXMsgArg->hwndScreen = hwndScreen;
1400     if (pthread_create(ptXMsgProc, NULL, winMultiWindowXMsgProc, pXMsgArg)) {
1401         /* Bail if thread creation failed */
1402         ErrorF("winInitWM - pthread_create failed on XMSG.\n");
1403         return FALSE;
1404     }
1405 
1406 #if CYGDEBUG || YES
1407     winDebug("winInitWM - Returning.\n");
1408 #endif
1409 
1410     return TRUE;
1411 }
1412 
1413 /*
1414  * Window manager thread - setup
1415  */
1416 
1417 static void
winInitMultiWindowWM(WMInfoPtr pWMInfo,WMProcArgPtr pProcArg)1418 winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg)
1419 {
1420     int iRetries = 0;
1421     char pszDisplay[512];
1422     int iReturn;
1423     xcb_auth_info_t *auth_info;
1424 
1425     winDebug("winInitMultiWindowWM - Hello\n");
1426 
1427     /* Check that argument pointer is not invalid */
1428     if (pProcArg == NULL) {
1429         ErrorF("winInitMultiWindowWM - pProcArg is NULL.  Exiting.\n");
1430         pthread_exit(NULL);
1431     }
1432 
1433     winDebug("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n");
1434 
1435     /* Grab our garbage mutex to satisfy pthread_cond_wait */
1436     iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
1437     if (iReturn != 0) {
1438         ErrorF("winInitMultiWindowWM - pthread_mutex_lock () failed: %d.  "
1439                "Exiting.\n", iReturn);
1440         pthread_exit(NULL);
1441     }
1442 
1443     winDebug("winInitMultiWindowWM - pthread_mutex_lock () returned.\n");
1444 
1445     /* Release the server started mutex */
1446     pthread_mutex_unlock(pProcArg->ppmServerStarted);
1447 
1448     winDebug("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n");
1449 
1450     /* Setup the display connection string x */
1451     winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen);
1452 
1453     /* Print the display connection string */
1454     ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay);
1455 
1456     /* Use our generated cookie for authentication */
1457     auth_info = winGetXcbAuthInfo();
1458 
1459     /* Open the X display */
1460     do {
1461         /* Try to open the display */
1462         pWMInfo->conn = xcb_connect_to_display_with_auth_info(pszDisplay,
1463                                                               auth_info, NULL);
1464         if (xcb_connection_has_error(pWMInfo->conn)) {
1465             ErrorF("winInitMultiWindowWM - Could not open display, try: %d, "
1466                    "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
1467             ++iRetries;
1468             sleep(WIN_CONNECT_DELAY);
1469             continue;
1470         }
1471         else
1472             break;
1473     }
1474     while (xcb_connection_has_error(pWMInfo->conn) && iRetries < WIN_CONNECT_RETRIES);
1475 
1476     /* Make sure that the display opened */
1477     if (xcb_connection_has_error(pWMInfo->conn)) {
1478         ErrorF("winInitMultiWindowWM - Failed opening the display.  "
1479                "Exiting.\n");
1480         pthread_exit(NULL);
1481     }
1482 
1483     ErrorF("winInitMultiWindowWM - xcb_connect () returned and "
1484            "successfully opened the display.\n");
1485 
1486     /* Create some atoms */
1487     pWMInfo->atmWmProtos = intern_atom(pWMInfo->conn, "WM_PROTOCOLS");
1488     pWMInfo->atmWmDelete = intern_atom(pWMInfo->conn, "WM_DELETE_WINDOW");
1489     pWMInfo->atmWmTakeFocus = intern_atom(pWMInfo->conn, "WM_TAKE_FOCUS");
1490     pWMInfo->atmPrivMap = intern_atom(pWMInfo->conn, WINDOWSWM_NATIVE_HWND);
1491     pWMInfo->atmUtf8String = intern_atom(pWMInfo->conn, "UTF8_STRING");
1492     pWMInfo->atmNetWmName = intern_atom(pWMInfo->conn, "_NET_WM_NAME");
1493 
1494     /* Initialization for the xcb_ewmh and EWMH atoms */
1495     {
1496         xcb_intern_atom_cookie_t *atoms_cookie;
1497         atoms_cookie = xcb_ewmh_init_atoms(pWMInfo->conn, &pWMInfo->ewmh);
1498         if (xcb_ewmh_init_atoms_replies(&pWMInfo->ewmh, atoms_cookie, NULL)) {
1499             /* Set the _NET_SUPPORTED atom for this context.
1500 
1501                TODO: Audit to ensure we implement everything defined as MUSTs
1502                for window managers in the EWMH standard.*/
1503             xcb_atom_t supported[] =
1504                 {
1505                     pWMInfo->ewmh.WM_PROTOCOLS,
1506                     pWMInfo->ewmh._NET_SUPPORTED,
1507                     pWMInfo->ewmh._NET_SUPPORTING_WM_CHECK,
1508                     pWMInfo->ewmh._NET_CLOSE_WINDOW,
1509                     pWMInfo->ewmh._NET_WM_WINDOW_TYPE,
1510                     pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK,
1511                     pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH,
1512                     pWMInfo->ewmh._NET_WM_STATE,
1513                     pWMInfo->ewmh._NET_WM_STATE_HIDDEN,
1514                     pWMInfo->ewmh._NET_WM_STATE_ABOVE,
1515                     pWMInfo->ewmh._NET_WM_STATE_BELOW,
1516                     pWMInfo->ewmh._NET_WM_STATE_SKIP_TASKBAR,
1517                 };
1518 
1519             xcb_ewmh_set_supported(&pWMInfo->ewmh, pProcArg->dwScreen,
1520                                    ARRAY_SIZE(supported), supported);
1521         }
1522         else {
1523             ErrorF("winInitMultiWindowWM - xcb_ewmh_init_atoms() failed\n");
1524         }
1525     }
1526 
1527     /*
1528       Set the root window cursor to left_ptr (this controls the cursor an
1529       application gets over it's windows when it doesn't set one)
1530     */
1531     {
1532 #define XC_left_ptr 68
1533         xcb_cursor_t cursor = xcb_generate_id(pWMInfo->conn);
1534         xcb_font_t font = xcb_generate_id(pWMInfo->conn);
1535         xcb_font_t *mask_font = &font; /* An alias to clarify */
1536         int shape = XC_left_ptr;
1537         uint32_t mask = XCB_CW_CURSOR;
1538         uint32_t value_list = cursor;
1539 
1540         xcb_screen_t *root_screen = xcb_aux_get_screen(pWMInfo->conn, pProcArg->dwScreen);
1541         xcb_window_t window = root_screen->root;
1542 
1543         static const uint16_t fgred = 0, fggreen = 0, fgblue = 0;
1544         static const uint16_t bgred = 0xFFFF, bggreen = 0xFFFF, bgblue = 0xFFFF;
1545 
1546         xcb_open_font(pWMInfo->conn, font, sizeof("cursor"), "cursor");
1547 
1548         xcb_create_glyph_cursor(pWMInfo->conn, cursor, font, *mask_font,
1549                                 shape, shape + 1,
1550                                 fgred, fggreen, fgblue, bgred, bggreen, bgblue);
1551 
1552         xcb_change_window_attributes(pWMInfo->conn, window, mask, &value_list);
1553 
1554         xcb_free_cursor(pWMInfo->conn, cursor);
1555         xcb_close_font(pWMInfo->conn, font);
1556     }
1557 }
1558 
1559 /*
1560  * winSendMessageToWM - Send a message from the X thread to the WM thread
1561  */
1562 
1563 void
winSendMessageToWM(void * pWMInfo,winWMMessagePtr pMsg)1564 winSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg)
1565 {
1566     WMMsgNodePtr pNode;
1567 
1568 #if CYGMULTIWINDOW_DEBUG
1569     ErrorF("winSendMessageToWM %s\n", MessageName(pMsg));
1570 #endif
1571 
1572     pNode = malloc(sizeof(WMMsgNodeRec));
1573     if (pNode != NULL) {
1574         memcpy(&pNode->msg, pMsg, sizeof(winWMMessageRec));
1575         PushMessage(&((WMInfoPtr) pWMInfo)->wmMsgQueue, pNode);
1576     }
1577 }
1578 
1579 /*
1580  * Check if another window manager is running
1581  */
1582 
1583 static Bool
CheckAnotherWindowManager(xcb_connection_t * conn,DWORD dwScreen)1584 CheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen)
1585 {
1586     Bool redirectError = FALSE;
1587 
1588     /* Get root window id */
1589     xcb_screen_t *root_screen = xcb_aux_get_screen(conn, dwScreen);
1590     xcb_window_t root_window_id = root_screen->root;
1591 
1592     /*
1593        Try to select the events which only one client at a time is allowed to select.
1594        If this causes an error, another window manager is already running...
1595      */
1596     const static uint32_t test_mask[] = { XCB_EVENT_MASK_RESIZE_REDIRECT |
1597                                        XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
1598                                        XCB_EVENT_MASK_BUTTON_PRESS };
1599 
1600     xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(conn,
1601                                                                     root_window_id,
1602                                                                     XCB_CW_EVENT_MASK,
1603                                                                     test_mask);
1604     xcb_generic_error_t *error;
1605     if ((error = xcb_request_check(conn, cookie)))
1606         {
1607             redirectError = TRUE;
1608             free(error);
1609         }
1610 
1611     /*
1612        Side effect: select the events we are actually interested in...
1613 
1614        Other WMs are not allowed, also select one of the events which only one client
1615        at a time is allowed to select, so other window managers won't start...
1616      */
1617     {
1618         const uint32_t mask[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
1619                                   XCB_EVENT_MASK_BUTTON_PRESS };
1620 
1621         xcb_change_window_attributes(conn, root_window_id, XCB_CW_EVENT_MASK, mask);
1622     }
1623 
1624     return redirectError;
1625 }
1626 
1627 /*
1628  * Notify the MWM thread we're exiting and not to reconnect
1629  */
1630 
1631 void
winDeinitMultiWindowWM(void)1632 winDeinitMultiWindowWM(void)
1633 {
1634     ErrorF("winDeinitMultiWindowWM - Noting shutdown in progress\n");
1635     g_shutdown = TRUE;
1636 }
1637 
1638 /* Windows window styles */
1639 #define HINT_NOFRAME	(1L<<0)
1640 #define HINT_BORDER	(1L<<1)
1641 #define HINT_SIZEBOX	(1L<<2)
1642 #define HINT_CAPTION	(1L<<3)
1643 #define HINT_NOMAXIMIZE (1L<<4)
1644 #define HINT_NOMINIMIZE (1L<<5)
1645 #define HINT_NOSYSMENU  (1L<<6)
1646 #define HINT_SKIPTASKBAR (1L<<7)
1647 /* These two are used on their own */
1648 #define HINT_MAX	(1L<<0)
1649 #define HINT_MIN	(1L<<1)
1650 
1651 static void
winApplyHints(WMInfoPtr pWMInfo,xcb_window_t iWindow,HWND hWnd,HWND * zstyle)1652 winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle)
1653 {
1654 
1655     xcb_connection_t *conn = pWMInfo->conn;
1656     static xcb_atom_t windowState, motif_wm_hints;
1657     static xcb_atom_t hiddenState, fullscreenState, belowState, aboveState,
1658         skiptaskbarState;
1659     static xcb_atom_t splashType;
1660     static int generation;
1661 
1662     unsigned long hint = 0, maxmin = 0;
1663     unsigned long style, exStyle;
1664 
1665     if (!hWnd)
1666         return;
1667     if (!IsWindow(hWnd))
1668         return;
1669 
1670     if (generation != serverGeneration) {
1671         generation = serverGeneration;
1672         windowState = intern_atom(conn, "_NET_WM_STATE");
1673         motif_wm_hints = intern_atom(conn, "_MOTIF_WM_HINTS");
1674         hiddenState = intern_atom(conn, "_NET_WM_STATE_HIDDEN");
1675         fullscreenState = intern_atom(conn, "_NET_WM_STATE_FULLSCREEN");
1676         belowState = intern_atom(conn, "_NET_WM_STATE_BELOW");
1677         aboveState = intern_atom(conn, "_NET_WM_STATE_ABOVE");
1678         skiptaskbarState = intern_atom(conn, "_NET_WM_STATE_SKIP_TASKBAR");
1679         splashType = intern_atom(conn, "_NET_WM_WINDOW_TYPE_SPLASHSCREEN");
1680     }
1681 
1682     {
1683       xcb_get_property_cookie_t cookie_wm_state = xcb_get_property(conn, FALSE, iWindow, windowState, XCB_ATOM_ATOM, 0L, INT_MAX);
1684       xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie_wm_state, NULL);
1685       if (reply) {
1686         int i;
1687         int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t);
1688         xcb_atom_t *pAtom = xcb_get_property_value(reply);
1689 
1690             for (i = 0; i < nitems; i++) {
1691                 if (pAtom[i] == skiptaskbarState)
1692                     hint |= HINT_SKIPTASKBAR;
1693                 if (pAtom[i] == hiddenState)
1694                     maxmin |= HINT_MIN;
1695                 else if (pAtom[i] == fullscreenState)
1696                     maxmin |= HINT_MAX;
1697                 if (pAtom[i] == belowState)
1698                     *zstyle = HWND_BOTTOM;
1699                 else if (pAtom[i] == aboveState)
1700                     *zstyle = HWND_TOPMOST;
1701             }
1702 
1703             free(reply);
1704       }
1705     }
1706 
1707     {
1708       xcb_get_property_cookie_t cookie_mwm_hint = xcb_get_property(conn, FALSE, iWindow, motif_wm_hints, motif_wm_hints, 0L, sizeof(MwmHints));
1709       xcb_get_property_reply_t *reply =  xcb_get_property_reply(conn, cookie_mwm_hint, NULL);
1710       if (reply) {
1711         int nitems = xcb_get_property_value_length(reply)/4;
1712         MwmHints *mwm_hint = xcb_get_property_value(reply);
1713         if (mwm_hint && (nitems >= PropMwmHintsElements) &&
1714             (mwm_hint->flags & MwmHintsDecorations)) {
1715             if (!mwm_hint->decorations)
1716                 hint |= (HINT_NOFRAME | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE);
1717             else if (!(mwm_hint->decorations & MwmDecorAll)) {
1718                 if (mwm_hint->decorations & MwmDecorBorder)
1719                     hint |= HINT_BORDER;
1720                 if (mwm_hint->decorations & MwmDecorHandle)
1721                     hint |= HINT_SIZEBOX;
1722                 if (mwm_hint->decorations & MwmDecorTitle)
1723                     hint |= HINT_CAPTION;
1724                 if (!(mwm_hint->decorations & MwmDecorMenu))
1725                     hint |= HINT_NOSYSMENU;
1726                 if (!(mwm_hint->decorations & MwmDecorMinimize))
1727                     hint |= HINT_NOMINIMIZE;
1728                 if (!(mwm_hint->decorations & MwmDecorMaximize))
1729                     hint |= HINT_NOMAXIMIZE;
1730             }
1731             else {
1732                 /*
1733                    MwmDecorAll means all decorations *except* those specified by other flag
1734                    bits that are set.  Not yet implemented.
1735                  */
1736             }
1737         }
1738         free(reply);
1739       }
1740     }
1741 
1742     {
1743       int i;
1744       xcb_ewmh_get_atoms_reply_t type;
1745       xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_window_type(&pWMInfo->ewmh, iWindow);
1746       if (xcb_ewmh_get_wm_window_type_reply(&pWMInfo->ewmh, cookie, &type, NULL)) {
1747         for (i = 0; i < type.atoms_len; i++) {
1748             if (type.atoms[i] ==  pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK) {
1749                 hint = (hint & ~HINT_NOFRAME) | HINT_SKIPTASKBAR | HINT_SIZEBOX;
1750                 *zstyle = HWND_TOPMOST;
1751             }
1752             else if ((type.atoms[i] == pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH)
1753                      || (type.atoms[i] == splashType)) {
1754                 hint |= (HINT_SKIPTASKBAR | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE);
1755                 *zstyle = HWND_TOPMOST;
1756             }
1757         }
1758       }
1759     }
1760 
1761     {
1762         xcb_size_hints_t size_hints;
1763         xcb_get_property_cookie_t cookie;
1764 
1765         cookie = xcb_icccm_get_wm_normal_hints(conn, iWindow);
1766         if (xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &size_hints, NULL)) {
1767             if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) {
1768 
1769                 /* Not maximizable if a maximum size is specified, and that size
1770                    is smaller (in either dimension) than the screen size */
1771                 if ((size_hints.max_width < GetSystemMetrics(SM_CXVIRTUALSCREEN))
1772                     || (size_hints.max_height < GetSystemMetrics(SM_CYVIRTUALSCREEN)))
1773                     hint |= HINT_NOMAXIMIZE;
1774 
1775                 if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) {
1776                     /*
1777                        If both minimum size and maximum size are specified and are the same,
1778                        don't bother with a resizing frame
1779                      */
1780                     if ((size_hints.min_width == size_hints.max_width)
1781                         && (size_hints.min_height == size_hints.max_height))
1782                         hint = (hint & ~HINT_SIZEBOX);
1783                 }
1784             }
1785         }
1786     }
1787 
1788     /*
1789        Override hint settings from above with settings from config file and set
1790        application id for grouping.
1791      */
1792     {
1793         char *application_id = 0;
1794         char *window_name = 0;
1795         char *res_name = 0;
1796         char *res_class = 0;
1797 
1798         GetClassNames(pWMInfo, iWindow, &res_name, &res_class, &window_name);
1799 
1800         style = STYLE_NONE;
1801         style = winOverrideStyle(res_name, res_class, window_name);
1802 
1803 #define APPLICATION_ID_FORMAT	"%s.xwin.%s"
1804 #define APPLICATION_ID_UNKNOWN "unknown"
1805         if (res_class) {
1806             asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
1807                      res_class);
1808         }
1809         else {
1810             asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
1811                      APPLICATION_ID_UNKNOWN);
1812         }
1813         winSetAppUserModelID(hWnd, application_id);
1814 
1815         free(application_id);
1816         free(res_name);
1817         free(res_class);
1818         free(window_name);
1819     }
1820 
1821     if (style & STYLE_TOPMOST)
1822         *zstyle = HWND_TOPMOST;
1823     else if (style & STYLE_MAXIMIZE)
1824         maxmin = (hint & ~HINT_MIN) | HINT_MAX;
1825     else if (style & STYLE_MINIMIZE)
1826         maxmin = (hint & ~HINT_MAX) | HINT_MIN;
1827     else if (style & STYLE_BOTTOM)
1828         *zstyle = HWND_BOTTOM;
1829 
1830     if (maxmin & HINT_MAX)
1831         SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
1832     else if (maxmin & HINT_MIN)
1833         SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1834 
1835     if (style & STYLE_NOTITLE)
1836         hint =
1837             (hint & ~HINT_NOFRAME & ~HINT_BORDER & ~HINT_CAPTION) |
1838             HINT_SIZEBOX;
1839     else if (style & STYLE_OUTLINE)
1840         hint =
1841             (hint & ~HINT_NOFRAME & ~HINT_SIZEBOX & ~HINT_CAPTION) |
1842             HINT_BORDER;
1843     else if (style & STYLE_NOFRAME)
1844         hint =
1845             (hint & ~HINT_BORDER & ~HINT_CAPTION & ~HINT_SIZEBOX) |
1846             HINT_NOFRAME;
1847 
1848     /* Now apply styles to window */
1849     style = GetWindowLongPtr(hWnd, GWL_STYLE);
1850     if (!style)
1851         return;                 /* GetWindowLongPointer returns 0 on failure, we hope this isn't a valid style */
1852 
1853     style &= ~WS_CAPTION & ~WS_SIZEBOX; /* Just in case */
1854 
1855     if (!(hint & ~HINT_SKIPTASKBAR))    /* No hints, default */
1856         style = style | WS_CAPTION | WS_SIZEBOX;
1857     else if (hint & HINT_NOFRAME)       /* No frame, no decorations */
1858         style = style & ~WS_CAPTION & ~WS_SIZEBOX;
1859     else
1860         style = style | ((hint & HINT_BORDER) ? WS_BORDER : 0) |
1861             ((hint & HINT_SIZEBOX) ? WS_SIZEBOX : 0) |
1862             ((hint & HINT_CAPTION) ? WS_CAPTION : 0);
1863 
1864     if (hint & HINT_NOMAXIMIZE)
1865         style = style & ~WS_MAXIMIZEBOX;
1866 
1867     if (hint & HINT_NOMINIMIZE)
1868         style = style & ~WS_MINIMIZEBOX;
1869 
1870     if (hint & HINT_NOSYSMENU)
1871         style = style & ~WS_SYSMENU;
1872 
1873     if (hint & HINT_SKIPTASKBAR)
1874         style = style & ~WS_MINIMIZEBOX;        /* window will become lost if minimized */
1875 
1876     SetWindowLongPtr(hWnd, GWL_STYLE, style);
1877 
1878     exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
1879     if (hint & HINT_SKIPTASKBAR)
1880         exStyle = (exStyle & ~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW;
1881     else
1882         exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW;
1883     SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle);
1884 
1885     winDebug
1886         ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n",
1887          iWindow, hint, style, exStyle);
1888 }
1889 
1890 void
winUpdateWindowPosition(HWND hWnd,HWND * zstyle)1891 winUpdateWindowPosition(HWND hWnd, HWND * zstyle)
1892 {
1893     int iX, iY, iWidth, iHeight;
1894     int iDx, iDy;
1895     RECT rcNew;
1896     WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP);
1897     DrawablePtr pDraw = NULL;
1898 
1899     if (!pWin)
1900         return;
1901     pDraw = &pWin->drawable;
1902     if (!pDraw)
1903         return;
1904 
1905     /* Get the X and Y location of the X window */
1906     iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN);
1907     iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN);
1908 
1909     /* Get the height and width of the X window */
1910     iWidth = pWin->drawable.width;
1911     iHeight = pWin->drawable.height;
1912 
1913     /* Setup a rectangle with the X window position and size */
1914     SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight);
1915 
1916     winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n",
1917              rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
1918 
1919     AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE,
1920                        GetWindowLongPtr(hWnd, GWL_EXSTYLE));
1921 
1922     /* Don't allow window decoration to disappear off to top-left as a result of this adjustment */
1923     if (rcNew.left < GetSystemMetrics(SM_XVIRTUALSCREEN)) {
1924         iDx = GetSystemMetrics(SM_XVIRTUALSCREEN) - rcNew.left;
1925         rcNew.left += iDx;
1926         rcNew.right += iDx;
1927     }
1928 
1929     if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) {
1930         iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top;
1931         rcNew.top += iDy;
1932         rcNew.bottom += iDy;
1933     }
1934 
1935     winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n",
1936              rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
1937 
1938     /* Position the Windows window */
1939     SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top,
1940                  rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0);
1941 
1942 }
1943