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