Commit | Line | Data |
---|---|---|
a09e091a JB |
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 <X11/X.h> | |
49 | #include <X11/Xatom.h> | |
50 | #include <X11/Xlib.h> | |
51 | #include <X11/Xlocale.h> | |
52 | #include <X11/Xproto.h> | |
53 | #include <X11/Xutil.h> | |
54 | #include <X11/cursorfont.h> | |
55 | #include <X11/Xwindows.h> | |
56 | ||
57 | /* Local headers */ | |
58 | #include "winwindow.h" | |
59 | #include "winprefs.h" | |
60 | #include "window.h" | |
61 | #include "pixmapstr.h" | |
62 | #include "windowstr.h" | |
63 | ||
64 | #ifdef XWIN_MULTIWINDOWEXTWM | |
65 | #include <X11/extensions/windowswmstr.h> | |
66 | #else | |
67 | /* We need the native HWND atom for intWM, so for consistency use the | |
68 | same name as extWM would if we were building with enabled... */ | |
69 | #define WINDOWSWM_NATIVE_HWND "_WINDOWSWM_NATIVE_HWND" | |
70 | #endif | |
71 | ||
72 | extern void winDebug(const char *format, ...); | |
73 | extern void winReshapeMultiWindow(WindowPtr pWin); | |
74 | extern void winUpdateRgnMultiWindow(WindowPtr pWin); | |
75 | ||
76 | #ifndef CYGDEBUG | |
77 | #define CYGDEBUG NO | |
78 | #endif | |
79 | ||
80 | /* | |
81 | * Constant defines | |
82 | */ | |
83 | ||
84 | #define WIN_CONNECT_RETRIES 5 | |
85 | #define WIN_CONNECT_DELAY 5 | |
86 | #ifdef HAS_DEVWINDOWS | |
87 | #define WIN_MSG_QUEUE_FNAME "/dev/windows" | |
88 | #endif | |
89 | #define WIN_JMP_OKAY 0 | |
90 | #define WIN_JMP_ERROR_IO 2 | |
91 | ||
92 | /* | |
93 | * Local structures | |
94 | */ | |
95 | ||
96 | typedef struct _WMMsgNodeRec { | |
97 | winWMMessageRec msg; | |
98 | struct _WMMsgNodeRec *pNext; | |
99 | } WMMsgNodeRec, *WMMsgNodePtr; | |
100 | ||
101 | typedef struct _WMMsgQueueRec { | |
102 | struct _WMMsgNodeRec *pHead; | |
103 | struct _WMMsgNodeRec *pTail; | |
104 | pthread_mutex_t pmMutex; | |
105 | pthread_cond_t pcNotEmpty; | |
106 | int nQueueSize; | |
107 | } WMMsgQueueRec, *WMMsgQueuePtr; | |
108 | ||
109 | typedef struct _WMInfo { | |
110 | Display *pDisplay; | |
111 | WMMsgQueueRec wmMsgQueue; | |
112 | Atom atmWmProtos; | |
113 | Atom atmWmDelete; | |
114 | Atom atmPrivMap; | |
115 | Bool fAllowOtherWM; | |
116 | } WMInfoRec, *WMInfoPtr; | |
117 | ||
118 | typedef struct _WMProcArgRec { | |
119 | DWORD dwScreen; | |
120 | WMInfoPtr pWMInfo; | |
121 | pthread_mutex_t *ppmServerStarted; | |
122 | } WMProcArgRec, *WMProcArgPtr; | |
123 | ||
124 | typedef struct _XMsgProcArgRec { | |
125 | Display *pDisplay; | |
126 | DWORD dwScreen; | |
127 | WMInfoPtr pWMInfo; | |
128 | pthread_mutex_t *ppmServerStarted; | |
129 | HWND hwndScreen; | |
130 | } XMsgProcArgRec, *XMsgProcArgPtr; | |
131 | ||
132 | /* | |
133 | * Prototypes for local functions | |
134 | */ | |
135 | ||
136 | static void | |
137 | PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode); | |
138 | ||
139 | static WMMsgNodePtr PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo); | |
140 | ||
141 | static Bool | |
142 | InitQueue(WMMsgQueuePtr pQueue); | |
143 | ||
144 | static void | |
145 | GetWindowName(Display * pDpy, Window iWin, char **ppWindowName); | |
146 | ||
147 | static int | |
148 | SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData); | |
149 | ||
150 | static void | |
151 | UpdateName(WMInfoPtr pWMInfo, Window iWindow); | |
152 | ||
153 | static void *winMultiWindowWMProc(void *pArg); | |
154 | ||
155 | static int | |
156 | winMultiWindowWMErrorHandler(Display * pDisplay, XErrorEvent * pErr); | |
157 | ||
158 | static int | |
159 | winMultiWindowWMIOErrorHandler(Display * pDisplay); | |
160 | ||
161 | static void *winMultiWindowXMsgProc(void *pArg); | |
162 | ||
163 | static int | |
164 | winMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr); | |
165 | ||
166 | static int | |
167 | winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay); | |
168 | ||
169 | static int | |
170 | winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr); | |
171 | ||
172 | static void | |
173 | winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg); | |
174 | ||
175 | #if 0 | |
176 | static void | |
177 | PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction); | |
178 | #endif | |
179 | ||
180 | static Bool | |
181 | ||
182 | CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen, | |
183 | Bool fAllowOtherWM); | |
184 | ||
185 | static void | |
186 | winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle); | |
187 | ||
188 | void | |
189 | winUpdateWindowPosition(HWND hWnd, HWND * zstyle); | |
190 | ||
191 | /* | |
192 | * Local globals | |
193 | */ | |
194 | ||
195 | static jmp_buf g_jmpWMEntry; | |
196 | static XIOErrorHandler g_winMultiWindowWMOldIOErrorHandler; | |
197 | static pthread_t g_winMultiWindowWMThread; | |
198 | static jmp_buf g_jmpXMsgProcEntry; | |
199 | static XIOErrorHandler g_winMultiWindowXMsgProcOldIOErrorHandler; | |
200 | static pthread_t g_winMultiWindowXMsgProcThread; | |
201 | static Bool g_shutdown = FALSE; | |
202 | static Bool redirectError = FALSE; | |
203 | static Bool g_fAnotherWMRunning = FALSE; | |
204 | ||
205 | /* | |
206 | * PushMessage - Push a message onto the queue | |
207 | */ | |
208 | ||
209 | static void | |
210 | PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode) | |
211 | { | |
212 | ||
213 | /* Lock the queue mutex */ | |
214 | pthread_mutex_lock(&pQueue->pmMutex); | |
215 | ||
216 | pNode->pNext = NULL; | |
217 | ||
218 | if (pQueue->pTail != NULL) { | |
219 | pQueue->pTail->pNext = pNode; | |
220 | } | |
221 | pQueue->pTail = pNode; | |
222 | ||
223 | if (pQueue->pHead == NULL) { | |
224 | pQueue->pHead = pNode; | |
225 | } | |
226 | ||
227 | #if 0 | |
228 | switch (pNode->msg.msg) { | |
229 | case WM_WM_MOVE: | |
230 | ErrorF("\tWM_WM_MOVE\n"); | |
231 | break; | |
232 | case WM_WM_SIZE: | |
233 | ErrorF("\tWM_WM_SIZE\n"); | |
234 | break; | |
235 | case WM_WM_RAISE: | |
236 | ErrorF("\tWM_WM_RAISE\n"); | |
237 | break; | |
238 | case WM_WM_LOWER: | |
239 | ErrorF("\tWM_WM_LOWER\n"); | |
240 | break; | |
241 | case WM_WM_MAP: | |
242 | ErrorF("\tWM_WM_MAP\n"); | |
243 | break; | |
244 | case WM_WM_MAP2: | |
245 | ErrorF("\tWM_WM_MAP2\n"); | |
246 | break; | |
247 | case WM_WM_MAP3: | |
248 | ErrorF("\tWM_WM_MAP3\n"); | |
249 | break; | |
250 | case WM_WM_UNMAP: | |
251 | ErrorF("\tWM_WM_UNMAP\n"); | |
252 | break; | |
253 | case WM_WM_KILL: | |
254 | ErrorF("\tWM_WM_KILL\n"); | |
255 | break; | |
256 | case WM_WM_ACTIVATE: | |
257 | ErrorF("\tWM_WM_ACTIVATE\n"); | |
258 | break; | |
259 | default: | |
260 | ErrorF("\tUnknown Message.\n"); | |
261 | break; | |
262 | } | |
263 | #endif | |
264 | ||
265 | /* Increase the count of elements in the queue by one */ | |
266 | ++(pQueue->nQueueSize); | |
267 | ||
268 | /* Release the queue mutex */ | |
269 | pthread_mutex_unlock(&pQueue->pmMutex); | |
270 | ||
271 | /* Signal that the queue is not empty */ | |
272 | pthread_cond_signal(&pQueue->pcNotEmpty); | |
273 | } | |
274 | ||
275 | #if CYGMULTIWINDOW_DEBUG | |
276 | /* | |
277 | * QueueSize - Return the size of the queue | |
278 | */ | |
279 | ||
280 | static int | |
281 | QueueSize(WMMsgQueuePtr pQueue) | |
282 | { | |
283 | WMMsgNodePtr pNode; | |
284 | int nSize = 0; | |
285 | ||
286 | /* Loop through all elements in the queue */ | |
287 | for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) | |
288 | ++nSize; | |
289 | ||
290 | return nSize; | |
291 | } | |
292 | #endif | |
293 | ||
294 | /* | |
295 | * PopMessage - Pop a message from the queue | |
296 | */ | |
297 | ||
298 | static WMMsgNodePtr | |
299 | PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo) | |
300 | { | |
301 | WMMsgNodePtr pNode; | |
302 | ||
303 | /* Lock the queue mutex */ | |
304 | pthread_mutex_lock(&pQueue->pmMutex); | |
305 | ||
306 | /* Wait for --- */ | |
307 | while (pQueue->pHead == NULL) { | |
308 | pthread_cond_wait(&pQueue->pcNotEmpty, &pQueue->pmMutex); | |
309 | } | |
310 | ||
311 | pNode = pQueue->pHead; | |
312 | if (pQueue->pHead != NULL) { | |
313 | pQueue->pHead = pQueue->pHead->pNext; | |
314 | } | |
315 | ||
316 | if (pQueue->pTail == pNode) { | |
317 | pQueue->pTail = NULL; | |
318 | } | |
319 | ||
320 | /* Drop the number of elements in the queue by one */ | |
321 | --(pQueue->nQueueSize); | |
322 | ||
323 | #if CYGMULTIWINDOW_DEBUG | |
324 | ErrorF("Queue Size %d %d\n", pQueue->nQueueSize, QueueSize(pQueue)); | |
325 | #endif | |
326 | ||
327 | /* Release the queue mutex */ | |
328 | pthread_mutex_unlock(&pQueue->pmMutex); | |
329 | ||
330 | return pNode; | |
331 | } | |
332 | ||
333 | #if 0 | |
334 | /* | |
335 | * HaveMessage - | |
336 | */ | |
337 | ||
338 | static Bool | |
339 | HaveMessage(WMMsgQueuePtr pQueue, UINT msg, Window iWindow) | |
340 | { | |
341 | WMMsgNodePtr pNode; | |
342 | ||
343 | for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) { | |
344 | if (pNode->msg.msg == msg && pNode->msg.iWindow == iWindow) | |
345 | return True; | |
346 | } | |
347 | ||
348 | return False; | |
349 | } | |
350 | #endif | |
351 | ||
352 | /* | |
353 | * InitQueue - Initialize the Window Manager message queue | |
354 | */ | |
355 | ||
356 | static | |
357 | Bool | |
358 | InitQueue(WMMsgQueuePtr pQueue) | |
359 | { | |
360 | /* Check if the pQueue pointer is NULL */ | |
361 | if (pQueue == NULL) { | |
362 | ErrorF("InitQueue - pQueue is NULL. Exiting.\n"); | |
363 | return FALSE; | |
364 | } | |
365 | ||
366 | /* Set the head and tail to NULL */ | |
367 | pQueue->pHead = NULL; | |
368 | pQueue->pTail = NULL; | |
369 | ||
370 | /* There are no elements initially */ | |
371 | pQueue->nQueueSize = 0; | |
372 | ||
373 | #if CYGMULTIWINDOW_DEBUG | |
374 | winDebug("InitQueue - Queue Size %d %d\n", pQueue->nQueueSize, | |
375 | QueueSize(pQueue)); | |
376 | #endif | |
377 | ||
378 | winDebug("InitQueue - Calling pthread_mutex_init\n"); | |
379 | ||
380 | /* Create synchronization objects */ | |
381 | pthread_mutex_init(&pQueue->pmMutex, NULL); | |
382 | ||
383 | winDebug("InitQueue - pthread_mutex_init returned\n"); | |
384 | winDebug("InitQueue - Calling pthread_cond_init\n"); | |
385 | ||
386 | pthread_cond_init(&pQueue->pcNotEmpty, NULL); | |
387 | ||
388 | winDebug("InitQueue - pthread_cond_init returned\n"); | |
389 | ||
390 | return TRUE; | |
391 | } | |
392 | ||
393 | static | |
394 | char * | |
395 | Xutf8TextPropertyToString(Display * pDisplay, XTextProperty * xtp) | |
396 | { | |
397 | int nNum; | |
398 | char **ppList; | |
399 | char *pszReturnData; | |
400 | ||
401 | if (Xutf8TextPropertyToTextList(pDisplay, xtp, &ppList, &nNum) >= Success && | |
402 | nNum > 0 && *ppList) { | |
403 | int i; | |
404 | int iLen = 0; | |
405 | ||
406 | for (i = 0; i < nNum; i++) | |
407 | iLen += strlen(ppList[i]); | |
408 | pszReturnData = (char *) malloc(iLen + 1); | |
409 | pszReturnData[0] = '\0'; | |
410 | for (i = 0; i < nNum; i++) | |
411 | strcat(pszReturnData, ppList[i]); | |
412 | if (ppList) | |
413 | XFreeStringList(ppList); | |
414 | } | |
415 | else { | |
416 | pszReturnData = (char *) malloc(1); | |
417 | pszReturnData[0] = '\0'; | |
418 | } | |
419 | ||
420 | return pszReturnData; | |
421 | } | |
422 | ||
423 | /* | |
424 | * GetWindowName - Retrieve the title of an X Window | |
425 | */ | |
426 | ||
427 | static void | |
428 | GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName) | |
429 | { | |
430 | int nResult; | |
431 | XTextProperty xtpWindowName; | |
432 | char *pszWindowName; | |
433 | ||
434 | #if CYGMULTIWINDOW_DEBUG | |
435 | ErrorF("GetWindowName\n"); | |
436 | #endif | |
437 | ||
438 | /* Intialize ppWindowName to NULL */ | |
439 | *ppWindowName = NULL; | |
440 | ||
441 | /* Try to get window name */ | |
442 | nResult = XGetWMName(pDisplay, iWin, &xtpWindowName); | |
443 | if (!nResult || !xtpWindowName.value || !xtpWindowName.nitems) { | |
444 | #if CYGMULTIWINDOW_DEBUG | |
445 | ErrorF("GetWindowName - XGetWMName failed. No name.\n"); | |
446 | #endif | |
447 | return; | |
448 | } | |
449 | ||
450 | pszWindowName = Xutf8TextPropertyToString(pDisplay, &xtpWindowName); | |
451 | XFree(xtpWindowName.value); | |
452 | *ppWindowName = pszWindowName; | |
453 | } | |
454 | ||
455 | /* | |
456 | * Send a message to the X server from the WM thread | |
457 | */ | |
458 | ||
459 | static int | |
460 | SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData) | |
461 | { | |
462 | XEvent e; | |
463 | ||
464 | /* Prepare the X event structure */ | |
465 | e.type = ClientMessage; | |
466 | e.xclient.window = iWin; | |
467 | e.xclient.message_type = atmType; | |
468 | e.xclient.format = 32; | |
469 | e.xclient.data.l[0] = nData; | |
470 | e.xclient.data.l[1] = CurrentTime; | |
471 | ||
472 | /* Send the event to X */ | |
473 | return XSendEvent(pDisplay, iWin, False, NoEventMask, &e); | |
474 | } | |
475 | ||
476 | /* | |
477 | * See if we can get the stored HWND for this window... | |
478 | */ | |
479 | static HWND | |
480 | getHwnd(WMInfoPtr pWMInfo, Window iWindow) | |
481 | { | |
482 | Atom atmType; | |
483 | int fmtRet; | |
484 | unsigned long items, remain; | |
485 | HWND *retHwnd, hWnd = NULL; | |
486 | ||
487 | if (XGetWindowProperty(pWMInfo->pDisplay, | |
488 | iWindow, | |
489 | pWMInfo->atmPrivMap, | |
490 | 0, | |
491 | sizeof(HWND)/4, | |
492 | False, | |
493 | XA_INTEGER, | |
494 | &atmType, | |
495 | &fmtRet, | |
496 | &items, | |
497 | &remain, (unsigned char **) &retHwnd) == Success) { | |
498 | if (retHwnd) { | |
499 | hWnd = *retHwnd; | |
500 | XFree(retHwnd); | |
501 | } | |
502 | } | |
503 | ||
504 | /* Some sanity checks */ | |
505 | if (!hWnd) | |
506 | return NULL; | |
507 | if (!IsWindow(hWnd)) | |
508 | return NULL; | |
509 | ||
510 | return hWnd; | |
511 | } | |
512 | ||
513 | /* | |
514 | * Updates the name of a HWND according to its X WM_NAME property | |
515 | */ | |
516 | ||
517 | static void | |
518 | UpdateName(WMInfoPtr pWMInfo, Window iWindow) | |
519 | { | |
520 | HWND hWnd; | |
521 | XWindowAttributes attr; | |
522 | ||
523 | hWnd = getHwnd(pWMInfo, iWindow); | |
524 | if (!hWnd) | |
525 | return; | |
526 | ||
527 | /* If window isn't override-redirect */ | |
528 | XGetWindowAttributes(pWMInfo->pDisplay, iWindow, &attr); | |
529 | if (!attr.override_redirect) { | |
530 | char *pszWindowName; | |
531 | ||
532 | /* Get the X windows window name */ | |
533 | GetWindowName(pWMInfo->pDisplay, iWindow, &pszWindowName); | |
534 | ||
535 | if (pszWindowName) { | |
536 | /* Convert from UTF-8 to wide char */ | |
537 | int iLen = | |
538 | MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1, NULL, 0); | |
539 | wchar_t *pwszWideWindowName = | |
540 | (wchar_t *) malloc(sizeof(wchar_t) * (iLen + 1)); | |
541 | MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1, | |
542 | pwszWideWindowName, iLen); | |
543 | ||
544 | /* Set the Windows window name */ | |
545 | SetWindowTextW(hWnd, pwszWideWindowName); | |
546 | ||
547 | free(pwszWideWindowName); | |
548 | free(pszWindowName); | |
549 | } | |
550 | } | |
551 | } | |
552 | ||
553 | /* | |
554 | * Updates the icon of a HWND according to its X icon properties | |
555 | */ | |
556 | ||
557 | static void | |
558 | UpdateIcon(WMInfoPtr pWMInfo, Window iWindow) | |
559 | { | |
560 | HWND hWnd; | |
561 | HICON hIconNew = NULL; | |
562 | XWindowAttributes attr; | |
563 | ||
564 | hWnd = getHwnd(pWMInfo, iWindow); | |
565 | if (!hWnd) | |
566 | return; | |
567 | ||
568 | /* If window isn't override-redirect */ | |
569 | XGetWindowAttributes(pWMInfo->pDisplay, iWindow, &attr); | |
570 | if (!attr.override_redirect) { | |
571 | XClassHint class_hint = { 0, 0 }; | |
572 | char *window_name = 0; | |
573 | ||
574 | if (XGetClassHint(pWMInfo->pDisplay, iWindow, &class_hint)) { | |
575 | XFetchName(pWMInfo->pDisplay, iWindow, &window_name); | |
576 | ||
577 | hIconNew = | |
578 | (HICON) winOverrideIcon(class_hint.res_name, | |
579 | class_hint.res_class, window_name); | |
580 | ||
581 | if (class_hint.res_name) | |
582 | XFree(class_hint.res_name); | |
583 | if (class_hint.res_class) | |
584 | XFree(class_hint.res_class); | |
585 | if (window_name) | |
586 | XFree(window_name); | |
587 | } | |
588 | } | |
589 | ||
590 | winUpdateIcon(hWnd, pWMInfo->pDisplay, iWindow, hIconNew); | |
591 | } | |
592 | ||
593 | /* | |
594 | * Updates the style of a HWND according to its X style properties | |
595 | */ | |
596 | ||
597 | static void | |
598 | UpdateStyle(WMInfoPtr pWMInfo, Window iWindow) | |
599 | { | |
600 | HWND hWnd; | |
601 | HWND zstyle = HWND_NOTOPMOST; | |
602 | UINT flags; | |
603 | ||
604 | hWnd = getHwnd(pWMInfo, iWindow); | |
605 | if (!hWnd) | |
606 | return; | |
607 | ||
608 | /* Determine the Window style, which determines borders and clipping region... */ | |
609 | winApplyHints(pWMInfo->pDisplay, iWindow, hWnd, &zstyle); | |
610 | winUpdateWindowPosition(hWnd, &zstyle); | |
611 | ||
612 | /* Apply the updated window style, without changing it's show or activation state */ | |
613 | flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE; | |
614 | if (zstyle == HWND_NOTOPMOST) | |
615 | flags |= SWP_NOZORDER | SWP_NOOWNERZORDER; | |
616 | SetWindowPos(hWnd, NULL, 0, 0, 0, 0, flags); | |
617 | ||
618 | /* | |
619 | Use the WS_EX_TOOLWINDOW style to remove window from Alt-Tab window switcher | |
620 | ||
621 | According to MSDN, this is supposed to remove the window from the taskbar as well, | |
622 | if we SW_HIDE before changing the style followed by SW_SHOW afterwards. | |
623 | ||
624 | But that doesn't seem to work reliably, and causes the window to flicker, so use | |
625 | the iTaskbarList interface to tell the taskbar to show or hide this window. | |
626 | */ | |
627 | winShowWindowOnTaskbar(hWnd, | |
628 | (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & | |
629 | WS_EX_APPWINDOW) ? TRUE : FALSE); | |
630 | } | |
631 | ||
632 | #if 0 | |
633 | /* | |
634 | * Fix up any differences between the X11 and Win32 window stacks | |
635 | * starting at the window passed in | |
636 | */ | |
637 | static void | |
638 | PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction) | |
639 | { | |
640 | HWND hWnd; | |
641 | DWORD myWinProcID, winProcID; | |
642 | Window xWindow; | |
643 | WINDOWPLACEMENT wndPlace; | |
644 | ||
645 | hWnd = getHwnd(pWMInfo, iWindow); | |
646 | if (!hWnd) | |
647 | return; | |
648 | ||
649 | GetWindowThreadProcessId(hWnd, &myWinProcID); | |
650 | hWnd = GetNextWindow(hWnd, direction); | |
651 | ||
652 | while (hWnd) { | |
653 | GetWindowThreadProcessId(hWnd, &winProcID); | |
654 | if (winProcID == myWinProcID) { | |
655 | wndPlace.length = sizeof(WINDOWPLACEMENT); | |
656 | GetWindowPlacement(hWnd, &wndPlace); | |
657 | if (!(wndPlace.showCmd == SW_HIDE || | |
658 | wndPlace.showCmd == SW_MINIMIZE)) { | |
659 | xWindow = (Window) GetProp(hWnd, WIN_WID_PROP); | |
660 | if (xWindow) { | |
661 | if (direction == GW_HWNDPREV) | |
662 | XRaiseWindow(pWMInfo->pDisplay, xWindow); | |
663 | else | |
664 | XLowerWindow(pWMInfo->pDisplay, xWindow); | |
665 | } | |
666 | } | |
667 | } | |
668 | hWnd = GetNextWindow(hWnd, direction); | |
669 | } | |
670 | } | |
671 | #endif /* PreserveWin32Stack */ | |
672 | ||
673 | /* | |
674 | * winMultiWindowWMProc | |
675 | */ | |
676 | ||
677 | static void * | |
678 | winMultiWindowWMProc(void *pArg) | |
679 | { | |
680 | WMProcArgPtr pProcArg = (WMProcArgPtr) pArg; | |
681 | WMInfoPtr pWMInfo = pProcArg->pWMInfo; | |
682 | ||
683 | /* Initialize the Window Manager */ | |
684 | winInitMultiWindowWM(pWMInfo, pProcArg); | |
685 | ||
686 | #if CYGMULTIWINDOW_DEBUG | |
687 | ErrorF("winMultiWindowWMProc ()\n"); | |
688 | #endif | |
689 | ||
690 | /* Loop until we explicitly break out */ | |
691 | for (;;) { | |
692 | WMMsgNodePtr pNode; | |
693 | ||
694 | if (g_fAnotherWMRunning) { /* Another Window manager exists. */ | |
695 | Sleep(1000); | |
696 | continue; | |
697 | } | |
698 | ||
699 | /* Pop a message off of our queue */ | |
700 | pNode = PopMessage(&pWMInfo->wmMsgQueue, pWMInfo); | |
701 | if (pNode == NULL) { | |
702 | /* Bail if PopMessage returns without a message */ | |
703 | /* NOTE: Remember that PopMessage is a blocking function. */ | |
704 | ErrorF("winMultiWindowWMProc - Queue is Empty? Exiting.\n"); | |
705 | pthread_exit(NULL); | |
706 | } | |
707 | ||
708 | #if CYGMULTIWINDOW_DEBUG | |
709 | ErrorF("winMultiWindowWMProc - %d ms MSG: %d ID: %d\n", | |
710 | GetTickCount(), (int) pNode->msg.msg, (int) pNode->msg.dwID); | |
711 | #endif | |
712 | ||
713 | /* Branch on the message type */ | |
714 | switch (pNode->msg.msg) { | |
715 | #if 0 | |
716 | case WM_WM_MOVE: | |
717 | ErrorF("\tWM_WM_MOVE\n"); | |
718 | break; | |
719 | ||
720 | case WM_WM_SIZE: | |
721 | ErrorF("\tWM_WM_SIZE\n"); | |
722 | break; | |
723 | #endif | |
724 | ||
725 | case WM_WM_RAISE: | |
726 | #if CYGMULTIWINDOW_DEBUG | |
727 | ErrorF("\tWM_WM_RAISE\n"); | |
728 | #endif | |
729 | /* Raise the window */ | |
730 | XRaiseWindow(pWMInfo->pDisplay, pNode->msg.iWindow); | |
731 | #if 0 | |
732 | PreserveWin32Stack(pWMInfo, pNode->msg.iWindow, GW_HWNDPREV); | |
733 | #endif | |
734 | break; | |
735 | ||
736 | case WM_WM_LOWER: | |
737 | #if CYGMULTIWINDOW_DEBUG | |
738 | ErrorF("\tWM_WM_LOWER\n"); | |
739 | #endif | |
740 | ||
741 | /* Lower the window */ | |
742 | XLowerWindow(pWMInfo->pDisplay, pNode->msg.iWindow); | |
743 | break; | |
744 | ||
745 | case WM_WM_MAP: | |
746 | #if CYGMULTIWINDOW_DEBUG | |
747 | ErrorF("\tWM_WM_MAP\n"); | |
748 | #endif | |
749 | /* Put a note as to the HWND associated with this Window */ | |
750 | XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER, | |
751 | 32, | |
752 | PropModeReplace, | |
753 | (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4); | |
754 | UpdateName(pWMInfo, pNode->msg.iWindow); | |
755 | UpdateIcon(pWMInfo, pNode->msg.iWindow); | |
756 | break; | |
757 | ||
758 | case WM_WM_MAP2: | |
759 | #if CYGMULTIWINDOW_DEBUG | |
760 | ErrorF("\tWM_WM_MAP2\n"); | |
761 | #endif | |
762 | XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER, | |
763 | 32, | |
764 | PropModeReplace, | |
765 | (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4); | |
766 | break; | |
767 | ||
768 | case WM_WM_MAP3: | |
769 | #if CYGMULTIWINDOW_DEBUG | |
770 | ErrorF("\tWM_WM_MAP3\n"); | |
771 | #endif | |
772 | /* Put a note as to the HWND associated with this Window */ | |
773 | XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER, | |
774 | 32, | |
775 | PropModeReplace, | |
776 | (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4); | |
777 | UpdateName(pWMInfo, pNode->msg.iWindow); | |
778 | UpdateIcon(pWMInfo, pNode->msg.iWindow); | |
779 | UpdateStyle(pWMInfo, pNode->msg.iWindow); | |
780 | ||
781 | ||
782 | /* Reshape */ | |
783 | { | |
784 | WindowPtr pWin = | |
785 | GetProp(pNode->msg.hwndWindow, WIN_WINDOW_PROP); | |
786 | if (pWin) { | |
787 | winReshapeMultiWindow(pWin); | |
788 | winUpdateRgnMultiWindow(pWin); | |
789 | } | |
790 | } | |
791 | ||
792 | break; | |
793 | ||
794 | case WM_WM_UNMAP: | |
795 | #if CYGMULTIWINDOW_DEBUG | |
796 | ErrorF("\tWM_WM_UNMAP\n"); | |
797 | #endif | |
798 | ||
799 | /* Unmap the window */ | |
800 | XUnmapWindow(pWMInfo->pDisplay, pNode->msg.iWindow); | |
801 | break; | |
802 | ||
803 | case WM_WM_KILL: | |
804 | #if CYGMULTIWINDOW_DEBUG | |
805 | ErrorF("\tWM_WM_KILL\n"); | |
806 | #endif | |
807 | { | |
808 | int i, n, found = 0; | |
809 | Atom *protocols; | |
810 | ||
811 | /* --- */ | |
812 | if (XGetWMProtocols(pWMInfo->pDisplay, | |
813 | pNode->msg.iWindow, &protocols, &n)) { | |
814 | for (i = 0; i < n; ++i) | |
815 | if (protocols[i] == pWMInfo->atmWmDelete) | |
816 | ++found; | |
817 | ||
818 | XFree(protocols); | |
819 | } | |
820 | ||
821 | /* --- */ | |
822 | if (found) | |
823 | SendXMessage(pWMInfo->pDisplay, | |
824 | pNode->msg.iWindow, | |
825 | pWMInfo->atmWmProtos, pWMInfo->atmWmDelete); | |
826 | else | |
827 | XKillClient(pWMInfo->pDisplay, pNode->msg.iWindow); | |
828 | } | |
829 | break; | |
830 | ||
831 | case WM_WM_ACTIVATE: | |
832 | #if CYGMULTIWINDOW_DEBUG | |
833 | ErrorF("\tWM_WM_ACTIVATE\n"); | |
834 | #endif | |
835 | ||
836 | /* Set the input focus */ | |
837 | XSetInputFocus(pWMInfo->pDisplay, | |
838 | pNode->msg.iWindow, | |
839 | RevertToPointerRoot, CurrentTime); | |
840 | break; | |
841 | ||
842 | case WM_WM_NAME_EVENT: | |
843 | UpdateName(pWMInfo, pNode->msg.iWindow); | |
844 | break; | |
845 | ||
846 | case WM_WM_ICON_EVENT: | |
847 | UpdateIcon(pWMInfo, pNode->msg.iWindow); | |
848 | break; | |
849 | ||
850 | case WM_WM_HINTS_EVENT: | |
851 | { | |
852 | XWindowAttributes attr; | |
853 | ||
854 | /* Don't do anything if this is an override-redirect window */ | |
855 | XGetWindowAttributes (pWMInfo->pDisplay, pNode->msg.iWindow, &attr); | |
856 | if (attr.override_redirect) | |
857 | break; | |
858 | ||
859 | UpdateStyle(pWMInfo, pNode->msg.iWindow); | |
860 | } | |
861 | break; | |
862 | ||
863 | case WM_WM_CHANGE_STATE: | |
864 | /* Minimize the window in Windows */ | |
865 | winMinimizeWindow(pNode->msg.iWindow); | |
866 | break; | |
867 | ||
868 | default: | |
869 | ErrorF("winMultiWindowWMProc - Unknown Message. Exiting.\n"); | |
870 | pthread_exit(NULL); | |
871 | break; | |
872 | } | |
873 | ||
874 | /* Free the retrieved message */ | |
875 | free(pNode); | |
876 | ||
877 | /* Flush any pending events on our display */ | |
878 | XFlush(pWMInfo->pDisplay); | |
879 | } | |
880 | ||
881 | /* Free the condition variable */ | |
882 | pthread_cond_destroy(&pWMInfo->wmMsgQueue.pcNotEmpty); | |
883 | ||
884 | /* Free the mutex variable */ | |
885 | pthread_mutex_destroy(&pWMInfo->wmMsgQueue.pmMutex); | |
886 | ||
887 | /* Free the passed-in argument */ | |
888 | free(pProcArg); | |
889 | ||
890 | #if CYGMULTIWINDOW_DEBUG | |
891 | ErrorF("-winMultiWindowWMProc ()\n"); | |
892 | #endif | |
893 | return NULL; | |
894 | } | |
895 | ||
896 | /* | |
897 | * X message procedure | |
898 | */ | |
899 | ||
900 | static void * | |
901 | winMultiWindowXMsgProc(void *pArg) | |
902 | { | |
903 | winWMMessageRec msg; | |
904 | XMsgProcArgPtr pProcArg = (XMsgProcArgPtr) pArg; | |
905 | char pszDisplay[512]; | |
906 | int iRetries; | |
907 | XEvent event; | |
908 | Atom atmWmName; | |
909 | Atom atmWmHints; | |
910 | Atom atmWmChange; | |
911 | Atom atmNetWmIcon; | |
912 | Atom atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints; | |
913 | int iReturn; | |
914 | XIconSize *xis; | |
915 | ||
916 | winDebug("winMultiWindowXMsgProc - Hello\n"); | |
917 | ||
918 | /* Check that argument pointer is not invalid */ | |
919 | if (pProcArg == NULL) { | |
920 | ErrorF("winMultiWindowXMsgProc - pProcArg is NULL. Exiting.\n"); | |
921 | pthread_exit(NULL); | |
922 | } | |
923 | ||
924 | ErrorF("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n"); | |
925 | ||
926 | /* Grab the server started mutex - pause until we get it */ | |
927 | iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted); | |
928 | if (iReturn != 0) { | |
929 | ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () failed: %d. " | |
930 | "Exiting.\n", iReturn); | |
931 | pthread_exit(NULL); | |
932 | } | |
933 | ||
934 | ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n"); | |
935 | ||
936 | /* Allow multiple threads to access Xlib */ | |
937 | if (XInitThreads() == 0) { | |
938 | ErrorF("winMultiWindowXMsgProc - XInitThreads () failed. Exiting.\n"); | |
939 | pthread_exit(NULL); | |
940 | } | |
941 | ||
942 | /* See if X supports the current locale */ | |
943 | if (XSupportsLocale() == False) { | |
944 | ErrorF("winMultiWindowXMsgProc - Warning: locale not supported by X\n"); | |
945 | } | |
946 | ||
947 | /* Release the server started mutex */ | |
948 | pthread_mutex_unlock(pProcArg->ppmServerStarted); | |
949 | ||
950 | ErrorF("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n"); | |
951 | ||
952 | /* Install our error handler */ | |
953 | XSetErrorHandler(winMultiWindowXMsgProcErrorHandler); | |
954 | g_winMultiWindowXMsgProcThread = pthread_self(); | |
955 | g_winMultiWindowXMsgProcOldIOErrorHandler = | |
956 | XSetIOErrorHandler(winMultiWindowXMsgProcIOErrorHandler); | |
957 | ||
958 | /* Set jump point for IO Error exits */ | |
959 | iReturn = setjmp(g_jmpXMsgProcEntry); | |
960 | ||
961 | /* Check if we should continue operations */ | |
962 | if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) { | |
963 | /* setjmp returned an unknown value, exit */ | |
964 | ErrorF("winInitMultiWindowXMsgProc - setjmp returned: %d. Exiting.\n", | |
965 | iReturn); | |
966 | pthread_exit(NULL); | |
967 | } | |
968 | else if (iReturn == WIN_JMP_ERROR_IO) { | |
969 | ErrorF("winInitMultiWindowXMsgProc - Caught IO Error. Exiting.\n"); | |
970 | pthread_exit(NULL); | |
971 | } | |
972 | ||
973 | /* Setup the display connection string x */ | |
974 | snprintf(pszDisplay, | |
975 | 512, "127.0.0.1:%s.%d", display, (int) pProcArg->dwScreen); | |
976 | ||
977 | /* Print the display connection string */ | |
978 | ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay); | |
979 | ||
980 | /* Use our generated cookie for authentication */ | |
981 | winSetAuthorization(); | |
982 | ||
983 | /* Initialize retry count */ | |
984 | iRetries = 0; | |
985 | ||
986 | /* Open the X display */ | |
987 | do { | |
988 | /* Try to open the display */ | |
989 | pProcArg->pDisplay = XOpenDisplay(pszDisplay); | |
990 | if (pProcArg->pDisplay == NULL) { | |
991 | ErrorF("winMultiWindowXMsgProc - Could not open display, try: %d, " | |
992 | "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY); | |
993 | ++iRetries; | |
994 | sleep(WIN_CONNECT_DELAY); | |
995 | continue; | |
996 | } | |
997 | else | |
998 | break; | |
999 | } | |
1000 | while (pProcArg->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES); | |
1001 | ||
1002 | /* Make sure that the display opened */ | |
1003 | if (pProcArg->pDisplay == NULL) { | |
1004 | ErrorF("winMultiWindowXMsgProc - Failed opening the display. " | |
1005 | "Exiting.\n"); | |
1006 | pthread_exit(NULL); | |
1007 | } | |
1008 | ||
1009 | ErrorF("winMultiWindowXMsgProc - XOpenDisplay () returned and " | |
1010 | "successfully opened the display.\n"); | |
1011 | ||
1012 | /* Check if another window manager is already running */ | |
1013 | g_fAnotherWMRunning = | |
1014 | CheckAnotherWindowManager(pProcArg->pDisplay, pProcArg->dwScreen, | |
1015 | pProcArg->pWMInfo->fAllowOtherWM); | |
1016 | ||
1017 | if (g_fAnotherWMRunning && !pProcArg->pWMInfo->fAllowOtherWM) { | |
1018 | ErrorF("winMultiWindowXMsgProc - " | |
1019 | "another window manager is running. Exiting.\n"); | |
1020 | pthread_exit(NULL); | |
1021 | } | |
1022 | ||
1023 | /* Set up the supported icon sizes */ | |
1024 | xis = XAllocIconSize(); | |
1025 | if (xis) { | |
1026 | xis->min_width = xis->min_height = 16; | |
1027 | xis->max_width = xis->max_height = 48; | |
1028 | xis->width_inc = xis->height_inc = 16; | |
1029 | XSetIconSizes(pProcArg->pDisplay, | |
1030 | RootWindow(pProcArg->pDisplay, pProcArg->dwScreen), | |
1031 | xis, 1); | |
1032 | XFree(xis); | |
1033 | } | |
1034 | ||
1035 | atmWmName = XInternAtom(pProcArg->pDisplay, "WM_NAME", False); | |
1036 | atmWmHints = XInternAtom(pProcArg->pDisplay, "WM_HINTS", False); | |
1037 | atmWmChange = XInternAtom(pProcArg->pDisplay, "WM_CHANGE_STATE", False); | |
1038 | atmNetWmIcon = XInternAtom(pProcArg->pDisplay, "_NET_WM_ICON", False); | |
1039 | atmWindowState = XInternAtom(pProcArg->pDisplay, "_NET_WM_STATE", False); | |
1040 | atmMotifWmHints = XInternAtom(pProcArg->pDisplay, "_MOTIF_WM_HINTS", False); | |
1041 | atmWindowType = XInternAtom(pProcArg->pDisplay, "_NET_WM_WINDOW_TYPE", False); | |
1042 | atmNormalHints = XInternAtom(pProcArg->pDisplay, "WM_NORMAL_HINTS", False); | |
1043 | ||
1044 | /* | |
1045 | iiimxcf had a bug until 2009-04-27, assuming that the | |
1046 | WM_STATE atom exists, causing clients to fail with | |
1047 | a BadAtom X error if it doesn't. | |
1048 | ||
1049 | Since this is on in the default Solaris 10 install, | |
1050 | workaround this by making sure it does exist... | |
1051 | */ | |
1052 | XInternAtom(pProcArg->pDisplay, "WM_STATE", 0); | |
1053 | ||
1054 | /* Loop until we explicitly break out */ | |
1055 | while (1) { | |
1056 | if (g_shutdown) | |
1057 | break; | |
1058 | ||
1059 | if (pProcArg->pWMInfo->fAllowOtherWM && !XPending(pProcArg->pDisplay)) { | |
1060 | if (CheckAnotherWindowManager | |
1061 | (pProcArg->pDisplay, pProcArg->dwScreen, TRUE)) { | |
1062 | if (!g_fAnotherWMRunning) { | |
1063 | g_fAnotherWMRunning = TRUE; | |
1064 | SendMessage(pProcArg->hwndScreen, WM_UNMANAGE, 0, 0); | |
1065 | } | |
1066 | } | |
1067 | else { | |
1068 | if (g_fAnotherWMRunning) { | |
1069 | g_fAnotherWMRunning = FALSE; | |
1070 | SendMessage(pProcArg->hwndScreen, WM_MANAGE, 0, 0); | |
1071 | } | |
1072 | } | |
1073 | Sleep(500); | |
1074 | continue; | |
1075 | } | |
1076 | ||
1077 | /* Fetch next event */ | |
1078 | XNextEvent(pProcArg->pDisplay, &event); | |
1079 | ||
1080 | /* Branch on event type */ | |
1081 | if (event.type == CreateNotify) { | |
1082 | XWindowAttributes attr; | |
1083 | ||
1084 | XSelectInput(pProcArg->pDisplay, | |
1085 | event.xcreatewindow.window, PropertyChangeMask); | |
1086 | ||
1087 | /* Get the window attributes */ | |
1088 | XGetWindowAttributes(pProcArg->pDisplay, | |
1089 | event.xcreatewindow.window, &attr); | |
1090 | ||
1091 | if (!attr.override_redirect) | |
1092 | XSetWindowBorderWidth(pProcArg->pDisplay, | |
1093 | event.xcreatewindow.window, 0); | |
1094 | } | |
1095 | else if (event.type == MapNotify) { | |
1096 | /* Fake a reparentNotify event as SWT/Motif expects a | |
1097 | Window Manager to reparent a top-level window when | |
1098 | it is mapped and waits until they do. | |
1099 | ||
1100 | We don't actually need to reparent, as the frame is | |
1101 | a native window, not an X window | |
1102 | ||
1103 | We do this on MapNotify, not MapRequest like a real | |
1104 | Window Manager would, so we don't have do get involved | |
1105 | in actually mapping the window via it's (non-existent) | |
1106 | parent... | |
1107 | ||
1108 | See sourceware bugzilla #9848 | |
1109 | */ | |
1110 | ||
1111 | XWindowAttributes attr; | |
1112 | Window root; | |
1113 | Window parent; | |
1114 | Window *children; | |
1115 | unsigned int nchildren; | |
1116 | ||
1117 | if (XGetWindowAttributes(event.xmap.display, | |
1118 | event.xmap.window, | |
1119 | &attr) && | |
1120 | XQueryTree(event.xmap.display, | |
1121 | event.xmap.window, | |
1122 | &root, &parent, &children, &nchildren)) { | |
1123 | if (children) | |
1124 | XFree(children); | |
1125 | ||
1126 | /* | |
1127 | It's a top-level window if the parent window is a root window | |
1128 | Only non-override_redirect windows can get reparented | |
1129 | */ | |
1130 | if ((attr.root == parent) && !event.xmap.override_redirect) { | |
1131 | XEvent event_send; | |
1132 | ||
1133 | event_send.type = ReparentNotify; | |
1134 | event_send.xreparent.event = event.xmap.window; | |
1135 | event_send.xreparent.window = event.xmap.window; | |
1136 | event_send.xreparent.parent = parent; | |
1137 | event_send.xreparent.x = attr.x; | |
1138 | event_send.xreparent.y = attr.y; | |
1139 | ||
1140 | XSendEvent(event.xmap.display, | |
1141 | event.xmap.window, | |
1142 | True, StructureNotifyMask, &event_send); | |
1143 | } | |
1144 | } | |
1145 | } | |
1146 | else if (event.type == ConfigureNotify) { | |
1147 | if (!event.xconfigure.send_event) { | |
1148 | /* | |
1149 | Java applications using AWT on JRE 1.6.0 break with non-reparenting WMs AWT | |
1150 | doesn't explicitly know about (See sun bug #6434227) | |
1151 | ||
1152 | XDecoratedPeer.handleConfigureNotifyEvent() only processes non-synthetic | |
1153 | ConfigureNotify events to update window location if it's identified the | |
1154 | WM as a non-reparenting WM it knows about (compiz or lookingglass) | |
1155 | ||
1156 | Rather than tell all sorts of lies to get XWM to recognize us as one of | |
1157 | those, simply send a synthetic ConfigureNotify for every non-synthetic one | |
1158 | */ | |
1159 | XEvent event_send = event; | |
1160 | ||
1161 | event_send.xconfigure.send_event = TRUE; | |
1162 | event_send.xconfigure.event = event.xconfigure.window; | |
1163 | XSendEvent(event.xconfigure.display, | |
1164 | event.xconfigure.window, | |
1165 | True, StructureNotifyMask, &event_send); | |
1166 | } | |
1167 | } | |
1168 | else if (event.type == PropertyNotify) { | |
1169 | if (event.xproperty.atom == atmWmName) { | |
1170 | memset(&msg, 0, sizeof(msg)); | |
1171 | ||
1172 | msg.msg = WM_WM_NAME_EVENT; | |
1173 | msg.iWindow = event.xproperty.window; | |
1174 | ||
1175 | /* Other fields ignored */ | |
1176 | winSendMessageToWM(pProcArg->pWMInfo, &msg); | |
1177 | } | |
1178 | else { | |
1179 | /* | |
1180 | Several properties are considered for WM hints, check if this property change affects any of them... | |
1181 | (this list needs to be kept in sync with winApplyHints()) | |
1182 | */ | |
1183 | if ((event.xproperty.atom == atmWmHints) || | |
1184 | (event.xproperty.atom == atmWindowState) || | |
1185 | (event.xproperty.atom == atmMotifWmHints) || | |
1186 | (event.xproperty.atom == atmWindowType) || | |
1187 | (event.xproperty.atom == atmNormalHints)) { | |
1188 | memset(&msg, 0, sizeof(msg)); | |
1189 | msg.msg = WM_WM_HINTS_EVENT; | |
1190 | msg.iWindow = event.xproperty.window; | |
1191 | ||
1192 | /* Other fields ignored */ | |
1193 | winSendMessageToWM(pProcArg->pWMInfo, &msg); | |
1194 | } | |
1195 | ||
1196 | /* Not an else as WM_HINTS affects both style and icon */ | |
1197 | if ((event.xproperty.atom == atmWmHints) || | |
1198 | (event.xproperty.atom == atmNetWmIcon)) { | |
1199 | memset(&msg, 0, sizeof(msg)); | |
1200 | msg.msg = WM_WM_ICON_EVENT; | |
1201 | msg.iWindow = event.xproperty.window; | |
1202 | ||
1203 | /* Other fields ignored */ | |
1204 | winSendMessageToWM(pProcArg->pWMInfo, &msg); | |
1205 | } | |
1206 | } | |
1207 | } | |
1208 | else if (event.type == ClientMessage | |
1209 | && event.xclient.message_type == atmWmChange | |
1210 | && event.xclient.data.l[0] == IconicState) { | |
1211 | ErrorF("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n"); | |
1212 | ||
1213 | memset(&msg, 0, sizeof(msg)); | |
1214 | ||
1215 | msg.msg = WM_WM_CHANGE_STATE; | |
1216 | msg.iWindow = event.xclient.window; | |
1217 | ||
1218 | winSendMessageToWM(pProcArg->pWMInfo, &msg); | |
1219 | } | |
1220 | } | |
1221 | ||
1222 | XCloseDisplay(pProcArg->pDisplay); | |
1223 | pthread_exit(NULL); | |
1224 | return NULL; | |
1225 | } | |
1226 | ||
1227 | /* | |
1228 | * winInitWM - Entry point for the X server to spawn | |
1229 | * the Window Manager thread. Called from | |
1230 | * winscrinit.c/winFinishScreenInitFB (). | |
1231 | */ | |
1232 | ||
1233 | Bool | |
1234 | winInitWM(void **ppWMInfo, | |
1235 | pthread_t * ptWMProc, | |
1236 | pthread_t * ptXMsgProc, | |
1237 | pthread_mutex_t * ppmServerStarted, | |
1238 | int dwScreen, HWND hwndScreen, BOOL allowOtherWM) | |
1239 | { | |
1240 | WMProcArgPtr pArg = (WMProcArgPtr) malloc(sizeof(WMProcArgRec)); | |
1241 | WMInfoPtr pWMInfo = (WMInfoPtr) malloc(sizeof(WMInfoRec)); | |
1242 | XMsgProcArgPtr pXMsgArg = (XMsgProcArgPtr) malloc(sizeof(XMsgProcArgRec)); | |
1243 | ||
1244 | /* Bail if the input parameters are bad */ | |
1245 | if (pArg == NULL || pWMInfo == NULL || pXMsgArg == NULL) { | |
1246 | ErrorF("winInitWM - malloc failed.\n"); | |
1247 | free(pArg); | |
1248 | free(pWMInfo); | |
1249 | free(pXMsgArg); | |
1250 | return FALSE; | |
1251 | } | |
1252 | ||
1253 | /* Zero the allocated memory */ | |
1254 | ZeroMemory(pArg, sizeof(WMProcArgRec)); | |
1255 | ZeroMemory(pWMInfo, sizeof(WMInfoRec)); | |
1256 | ZeroMemory(pXMsgArg, sizeof(XMsgProcArgRec)); | |
1257 | ||
1258 | /* Set a return pointer to the Window Manager info structure */ | |
1259 | *ppWMInfo = pWMInfo; | |
1260 | pWMInfo->fAllowOtherWM = allowOtherWM; | |
1261 | ||
1262 | /* Setup the argument structure for the thread function */ | |
1263 | pArg->dwScreen = dwScreen; | |
1264 | pArg->pWMInfo = pWMInfo; | |
1265 | pArg->ppmServerStarted = ppmServerStarted; | |
1266 | ||
1267 | /* Intialize the message queue */ | |
1268 | if (!InitQueue(&pWMInfo->wmMsgQueue)) { | |
1269 | ErrorF("winInitWM - InitQueue () failed.\n"); | |
1270 | return FALSE; | |
1271 | } | |
1272 | ||
1273 | /* Spawn a thread for the Window Manager */ | |
1274 | if (pthread_create(ptWMProc, NULL, winMultiWindowWMProc, pArg)) { | |
1275 | /* Bail if thread creation failed */ | |
1276 | ErrorF("winInitWM - pthread_create failed for Window Manager.\n"); | |
1277 | return FALSE; | |
1278 | } | |
1279 | ||
1280 | /* Spawn the XNextEvent thread, will send messages to WM */ | |
1281 | pXMsgArg->dwScreen = dwScreen; | |
1282 | pXMsgArg->pWMInfo = pWMInfo; | |
1283 | pXMsgArg->ppmServerStarted = ppmServerStarted; | |
1284 | pXMsgArg->hwndScreen = hwndScreen; | |
1285 | if (pthread_create(ptXMsgProc, NULL, winMultiWindowXMsgProc, pXMsgArg)) { | |
1286 | /* Bail if thread creation failed */ | |
1287 | ErrorF("winInitWM - pthread_create failed on XMSG.\n"); | |
1288 | return FALSE; | |
1289 | } | |
1290 | ||
1291 | #if CYGDEBUG || YES | |
1292 | winDebug("winInitWM - Returning.\n"); | |
1293 | #endif | |
1294 | ||
1295 | return TRUE; | |
1296 | } | |
1297 | ||
1298 | /* | |
1299 | * Window manager thread - setup | |
1300 | */ | |
1301 | ||
1302 | static void | |
1303 | winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) | |
1304 | { | |
1305 | int iRetries = 0; | |
1306 | char pszDisplay[512]; | |
1307 | int iReturn; | |
1308 | ||
1309 | winDebug("winInitMultiWindowWM - Hello\n"); | |
1310 | ||
1311 | /* Check that argument pointer is not invalid */ | |
1312 | if (pProcArg == NULL) { | |
1313 | ErrorF("winInitMultiWindowWM - pProcArg is NULL. Exiting.\n"); | |
1314 | pthread_exit(NULL); | |
1315 | } | |
1316 | ||
1317 | ErrorF("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n"); | |
1318 | ||
1319 | /* Grab our garbage mutex to satisfy pthread_cond_wait */ | |
1320 | iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted); | |
1321 | if (iReturn != 0) { | |
1322 | ErrorF("winInitMultiWindowWM - pthread_mutex_lock () failed: %d. " | |
1323 | "Exiting.\n", iReturn); | |
1324 | pthread_exit(NULL); | |
1325 | } | |
1326 | ||
1327 | ErrorF("winInitMultiWindowWM - pthread_mutex_lock () returned.\n"); | |
1328 | ||
1329 | /* Allow multiple threads to access Xlib */ | |
1330 | if (XInitThreads() == 0) { | |
1331 | ErrorF("winInitMultiWindowWM - XInitThreads () failed. Exiting.\n"); | |
1332 | pthread_exit(NULL); | |
1333 | } | |
1334 | ||
1335 | /* See if X supports the current locale */ | |
1336 | if (XSupportsLocale() == False) { | |
1337 | ErrorF("winInitMultiWindowWM - Warning: Locale not supported by X.\n"); | |
1338 | } | |
1339 | ||
1340 | /* Release the server started mutex */ | |
1341 | pthread_mutex_unlock(pProcArg->ppmServerStarted); | |
1342 | ||
1343 | ErrorF("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n"); | |
1344 | ||
1345 | /* Install our error handler */ | |
1346 | XSetErrorHandler(winMultiWindowWMErrorHandler); | |
1347 | g_winMultiWindowWMThread = pthread_self(); | |
1348 | g_winMultiWindowWMOldIOErrorHandler = | |
1349 | XSetIOErrorHandler(winMultiWindowWMIOErrorHandler); | |
1350 | ||
1351 | /* Set jump point for IO Error exits */ | |
1352 | iReturn = setjmp(g_jmpWMEntry); | |
1353 | ||
1354 | /* Check if we should continue operations */ | |
1355 | if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) { | |
1356 | /* setjmp returned an unknown value, exit */ | |
1357 | ErrorF("winInitMultiWindowWM - setjmp returned: %d. Exiting.\n", | |
1358 | iReturn); | |
1359 | pthread_exit(NULL); | |
1360 | } | |
1361 | else if (iReturn == WIN_JMP_ERROR_IO) { | |
1362 | ErrorF("winInitMultiWindowWM - Caught IO Error. Exiting.\n"); | |
1363 | pthread_exit(NULL); | |
1364 | } | |
1365 | ||
1366 | /* Setup the display connection string x */ | |
1367 | snprintf(pszDisplay, | |
1368 | 512, "127.0.0.1:%s.%d", display, (int) pProcArg->dwScreen); | |
1369 | ||
1370 | /* Print the display connection string */ | |
1371 | ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay); | |
1372 | ||
1373 | /* Use our generated cookie for authentication */ | |
1374 | winSetAuthorization(); | |
1375 | ||
1376 | /* Open the X display */ | |
1377 | do { | |
1378 | /* Try to open the display */ | |
1379 | pWMInfo->pDisplay = XOpenDisplay(pszDisplay); | |
1380 | if (pWMInfo->pDisplay == NULL) { | |
1381 | ErrorF("winInitMultiWindowWM - Could not open display, try: %d, " | |
1382 | "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY); | |
1383 | ++iRetries; | |
1384 | sleep(WIN_CONNECT_DELAY); | |
1385 | continue; | |
1386 | } | |
1387 | else | |
1388 | break; | |
1389 | } | |
1390 | while (pWMInfo->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES); | |
1391 | ||
1392 | /* Make sure that the display opened */ | |
1393 | if (pWMInfo->pDisplay == NULL) { | |
1394 | ErrorF("winInitMultiWindowWM - Failed opening the display. " | |
1395 | "Exiting.\n"); | |
1396 | pthread_exit(NULL); | |
1397 | } | |
1398 | ||
1399 | ErrorF("winInitMultiWindowWM - XOpenDisplay () returned and " | |
1400 | "successfully opened the display.\n"); | |
1401 | ||
1402 | /* Create some atoms */ | |
1403 | pWMInfo->atmWmProtos = XInternAtom(pWMInfo->pDisplay, | |
1404 | "WM_PROTOCOLS", False); | |
1405 | pWMInfo->atmWmDelete = XInternAtom(pWMInfo->pDisplay, | |
1406 | "WM_DELETE_WINDOW", False); | |
1407 | ||
1408 | pWMInfo->atmPrivMap = XInternAtom(pWMInfo->pDisplay, | |
1409 | WINDOWSWM_NATIVE_HWND, False); | |
1410 | ||
1411 | if (1) { | |
1412 | Cursor cursor = XCreateFontCursor(pWMInfo->pDisplay, XC_left_ptr); | |
1413 | ||
1414 | if (cursor) { | |
1415 | XDefineCursor(pWMInfo->pDisplay, | |
1416 | DefaultRootWindow(pWMInfo->pDisplay), cursor); | |
1417 | XFreeCursor(pWMInfo->pDisplay, cursor); | |
1418 | } | |
1419 | } | |
1420 | } | |
1421 | ||
1422 | /* | |
1423 | * winSendMessageToWM - Send a message from the X thread to the WM thread | |
1424 | */ | |
1425 | ||
1426 | void | |
1427 | winSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg) | |
1428 | { | |
1429 | WMMsgNodePtr pNode; | |
1430 | ||
1431 | #if CYGMULTIWINDOW_DEBUG | |
1432 | ErrorF("winSendMessageToWM ()\n"); | |
1433 | #endif | |
1434 | ||
1435 | pNode = (WMMsgNodePtr) malloc(sizeof(WMMsgNodeRec)); | |
1436 | if (pNode != NULL) { | |
1437 | memcpy(&pNode->msg, pMsg, sizeof(winWMMessageRec)); | |
1438 | PushMessage(&((WMInfoPtr) pWMInfo)->wmMsgQueue, pNode); | |
1439 | } | |
1440 | } | |
1441 | ||
1442 | /* | |
1443 | * Window manager error handler | |
1444 | */ | |
1445 | ||
1446 | static int | |
1447 | winMultiWindowWMErrorHandler(Display * pDisplay, XErrorEvent * pErr) | |
1448 | { | |
1449 | char pszErrorMsg[100]; | |
1450 | ||
1451 | if (pErr->request_code == X_ChangeWindowAttributes | |
1452 | && pErr->error_code == BadAccess) { | |
1453 | ErrorF("winMultiWindowWMErrorHandler - ChangeWindowAttributes " | |
1454 | "BadAccess.\n"); | |
1455 | return 0; | |
1456 | } | |
1457 | ||
1458 | XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg)); | |
1459 | ErrorF("winMultiWindowWMErrorHandler - ERROR: %s\n", pszErrorMsg); | |
1460 | ||
1461 | return 0; | |
1462 | } | |
1463 | ||
1464 | /* | |
1465 | * Window manager IO error handler | |
1466 | */ | |
1467 | ||
1468 | static int | |
1469 | winMultiWindowWMIOErrorHandler(Display * pDisplay) | |
1470 | { | |
1471 | ErrorF("winMultiWindowWMIOErrorHandler!\n"); | |
1472 | ||
1473 | if (pthread_equal(pthread_self(), g_winMultiWindowWMThread)) { | |
1474 | if (g_shutdown) | |
1475 | pthread_exit(NULL); | |
1476 | ||
1477 | /* Restart at the main entry point */ | |
1478 | longjmp(g_jmpWMEntry, WIN_JMP_ERROR_IO); | |
1479 | } | |
1480 | ||
1481 | if (g_winMultiWindowWMOldIOErrorHandler) | |
1482 | g_winMultiWindowWMOldIOErrorHandler(pDisplay); | |
1483 | ||
1484 | return 0; | |
1485 | } | |
1486 | ||
1487 | /* | |
1488 | * X message procedure error handler | |
1489 | */ | |
1490 | ||
1491 | static int | |
1492 | winMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr) | |
1493 | { | |
1494 | char pszErrorMsg[100]; | |
1495 | ||
1496 | XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg)); | |
1497 | #if CYGMULTIWINDOW_DEBUG | |
1498 | ErrorF("winMultiWindowXMsgProcErrorHandler - ERROR: %s\n", pszErrorMsg); | |
1499 | #endif | |
1500 | ||
1501 | return 0; | |
1502 | } | |
1503 | ||
1504 | /* | |
1505 | * X message procedure IO error handler | |
1506 | */ | |
1507 | ||
1508 | static int | |
1509 | winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay) | |
1510 | { | |
1511 | ErrorF("winMultiWindowXMsgProcIOErrorHandler!\n"); | |
1512 | ||
1513 | if (pthread_equal(pthread_self(), g_winMultiWindowXMsgProcThread)) { | |
1514 | /* Restart at the main entry point */ | |
1515 | longjmp(g_jmpXMsgProcEntry, WIN_JMP_ERROR_IO); | |
1516 | } | |
1517 | ||
1518 | if (g_winMultiWindowXMsgProcOldIOErrorHandler) | |
1519 | g_winMultiWindowXMsgProcOldIOErrorHandler(pDisplay); | |
1520 | ||
1521 | return 0; | |
1522 | } | |
1523 | ||
1524 | /* | |
1525 | * Catch RedirectError to detect other window manager running | |
1526 | */ | |
1527 | ||
1528 | static int | |
1529 | winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr) | |
1530 | { | |
1531 | redirectError = TRUE; | |
1532 | return 0; | |
1533 | } | |
1534 | ||
1535 | /* | |
1536 | * Check if another window manager is running | |
1537 | */ | |
1538 | ||
1539 | static Bool | |
1540 | CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen, | |
1541 | Bool fAllowOtherWM) | |
1542 | { | |
1543 | /* | |
1544 | Try to select the events which only one client at a time is allowed to select. | |
1545 | If this causes an error, another window manager is already running... | |
1546 | */ | |
1547 | redirectError = FALSE; | |
1548 | XSetErrorHandler(winRedirectErrorHandler); | |
1549 | XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen), | |
1550 | ResizeRedirectMask | SubstructureRedirectMask | | |
1551 | ButtonPressMask); | |
1552 | XSync(pDisplay, 0); | |
1553 | XSetErrorHandler(winMultiWindowXMsgProcErrorHandler); | |
1554 | ||
1555 | /* | |
1556 | Side effect: select the events we are actually interested in... | |
1557 | ||
1558 | If other WMs are not allowed, also select one of the events which only one client | |
1559 | at a time is allowed to select, so other window managers won't start... | |
1560 | */ | |
1561 | XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen), | |
1562 | SubstructureNotifyMask | (!fAllowOtherWM ? ButtonPressMask : | |
1563 | 0)); | |
1564 | XSync(pDisplay, 0); | |
1565 | return redirectError; | |
1566 | } | |
1567 | ||
1568 | /* | |
1569 | * Notify the MWM thread we're exiting and not to reconnect | |
1570 | */ | |
1571 | ||
1572 | void | |
1573 | winDeinitMultiWindowWM(void) | |
1574 | { | |
1575 | ErrorF("winDeinitMultiWindowWM - Noting shutdown in progress\n"); | |
1576 | g_shutdown = TRUE; | |
1577 | } | |
1578 | ||
1579 | /* Windows window styles */ | |
1580 | #define HINT_NOFRAME (1l<<0) | |
1581 | #define HINT_BORDER (1L<<1) | |
1582 | #define HINT_SIZEBOX (1l<<2) | |
1583 | #define HINT_CAPTION (1l<<3) | |
1584 | #define HINT_NOMAXIMIZE (1L<<4) | |
1585 | #define HINT_NOMINIMIZE (1L<<5) | |
1586 | #define HINT_NOSYSMENU (1L<<6) | |
1587 | #define HINT_SKIPTASKBAR (1L<<7) | |
1588 | /* These two are used on their own */ | |
1589 | #define HINT_MAX (1L<<0) | |
1590 | #define HINT_MIN (1L<<1) | |
1591 | ||
1592 | static void | |
1593 | winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) | |
1594 | { | |
1595 | static Atom windowState, motif_wm_hints, windowType; | |
1596 | static Atom hiddenState, fullscreenState, belowState, aboveState, | |
1597 | skiptaskbarState; | |
1598 | static Atom dockWindow; | |
1599 | static int generation; | |
1600 | Atom type, *pAtom = NULL; | |
1601 | int format; | |
1602 | unsigned long hint = 0, maxmin = 0, nitems = 0, left = 0; | |
1603 | unsigned long style, exStyle; | |
1604 | MwmHints *mwm_hint = NULL; | |
1605 | ||
1606 | if (!hWnd) | |
1607 | return; | |
1608 | if (!IsWindow(hWnd)) | |
1609 | return; | |
1610 | ||
1611 | if (generation != serverGeneration) { | |
1612 | generation = serverGeneration; | |
1613 | windowState = XInternAtom(pDisplay, "_NET_WM_STATE", False); | |
1614 | motif_wm_hints = XInternAtom(pDisplay, "_MOTIF_WM_HINTS", False); | |
1615 | windowType = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE", False); | |
1616 | hiddenState = XInternAtom(pDisplay, "_NET_WM_STATE_HIDDEN", False); | |
1617 | fullscreenState = | |
1618 | XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", False); | |
1619 | belowState = XInternAtom(pDisplay, "_NET_WM_STATE_BELOW", False); | |
1620 | aboveState = XInternAtom(pDisplay, "_NET_WM_STATE_ABOVE", False); | |
1621 | dockWindow = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE_DOCK", False); | |
1622 | skiptaskbarState = | |
1623 | XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", False); | |
1624 | } | |
1625 | ||
1626 | if (XGetWindowProperty(pDisplay, iWindow, windowState, 0L, | |
1627 | MAXINT, False, XA_ATOM, &type, &format, | |
1628 | &nitems, &left, | |
1629 | (unsigned char **) &pAtom) == Success) { | |
1630 | if (pAtom ) { | |
1631 | unsigned long i; | |
1632 | ||
1633 | for (i = 0; i < nitems; i++) { | |
1634 | if (pAtom[i] == skiptaskbarState) | |
1635 | hint |= HINT_SKIPTASKBAR; | |
1636 | if (pAtom[i] == hiddenState) | |
1637 | maxmin |= HINT_MIN; | |
1638 | else if (pAtom[i] == fullscreenState) | |
1639 | maxmin |= HINT_MAX; | |
1640 | if (pAtom[i] == belowState) | |
1641 | *zstyle = HWND_BOTTOM; | |
1642 | else if (pAtom[i] == aboveState) | |
1643 | *zstyle = HWND_TOPMOST; | |
1644 | } | |
1645 | ||
1646 | XFree(pAtom); | |
1647 | } | |
1648 | } | |
1649 | ||
1650 | nitems = left = 0; | |
1651 | if (XGetWindowProperty(pDisplay, iWindow, motif_wm_hints, 0L, | |
1652 | PropMwmHintsElements, False, motif_wm_hints, &type, | |
1653 | &format, &nitems, &left, | |
1654 | (unsigned char **) &mwm_hint) == Success) { | |
1655 | if (mwm_hint && nitems == PropMwmHintsElements && | |
1656 | (mwm_hint->flags & MwmHintsDecorations)) { | |
1657 | if (!mwm_hint->decorations) | |
1658 | hint |= HINT_NOFRAME; | |
1659 | else if (!(mwm_hint->decorations & MwmDecorAll)) { | |
1660 | if (mwm_hint->decorations & MwmDecorBorder) | |
1661 | hint |= HINT_BORDER; | |
1662 | if (mwm_hint->decorations & MwmDecorHandle) | |
1663 | hint |= HINT_SIZEBOX; | |
1664 | if (mwm_hint->decorations & MwmDecorTitle) | |
1665 | hint |= HINT_CAPTION; | |
1666 | if (!(mwm_hint->decorations & MwmDecorMenu)) | |
1667 | hint |= HINT_NOSYSMENU; | |
1668 | if (!(mwm_hint->decorations & MwmDecorMinimize)) | |
1669 | hint |= HINT_NOMINIMIZE; | |
1670 | if (!(mwm_hint->decorations & MwmDecorMaximize)) | |
1671 | hint |= HINT_NOMAXIMIZE; | |
1672 | } | |
1673 | else { | |
1674 | /* | |
1675 | MwmDecorAll means all decorations *except* those specified by other flag | |
1676 | bits that are set. Not yet implemented. | |
1677 | */ | |
1678 | } | |
1679 | } | |
1680 | if (mwm_hint) | |
1681 | XFree(mwm_hint); | |
1682 | } | |
1683 | ||
1684 | nitems = left = 0; | |
1685 | pAtom = NULL; | |
1686 | if (XGetWindowProperty(pDisplay, iWindow, windowType, 0L, | |
1687 | 1L, False, XA_ATOM, &type, &format, | |
1688 | &nitems, &left, | |
1689 | (unsigned char **) &pAtom) == Success) { | |
1690 | if (pAtom && nitems == 1) { | |
1691 | if (*pAtom == dockWindow) { | |
1692 | hint = (hint & ~HINT_NOFRAME) | HINT_SIZEBOX; /* Xming puts a sizebox on dock windows */ | |
1693 | *zstyle = HWND_TOPMOST; | |
1694 | } | |
1695 | } | |
1696 | if (pAtom) | |
1697 | XFree(pAtom); | |
1698 | } | |
1699 | ||
1700 | { | |
1701 | XSizeHints *normal_hint = XAllocSizeHints(); | |
1702 | long supplied; | |
1703 | ||
1704 | if (normal_hint && | |
1705 | (XGetWMNormalHints(pDisplay, iWindow, normal_hint, &supplied) == | |
1706 | Success)) { | |
1707 | if (normal_hint->flags & PMaxSize) { | |
1708 | /* Not maximizable if a maximum size is specified */ | |
1709 | hint |= HINT_NOMAXIMIZE; | |
1710 | ||
1711 | if (normal_hint->flags & PMinSize) { | |
1712 | /* | |
1713 | If both minimum size and maximum size are specified and are the same, | |
1714 | don't bother with a resizing frame | |
1715 | */ | |
1716 | if ((normal_hint->min_width == normal_hint->max_width) | |
1717 | && (normal_hint->min_height == normal_hint->max_height)) | |
1718 | hint = (hint & ~HINT_SIZEBOX); | |
1719 | } | |
1720 | } | |
1721 | } | |
1722 | XFree(normal_hint); | |
1723 | } | |
1724 | ||
1725 | /* | |
1726 | Override hint settings from above with settings from config file and set | |
1727 | application id for grouping. | |
1728 | */ | |
1729 | { | |
1730 | XClassHint class_hint = { 0, 0 }; | |
1731 | char *window_name = 0; | |
1732 | char *application_id = 0; | |
1733 | ||
1734 | if (XGetClassHint(pDisplay, iWindow, &class_hint)) { | |
1735 | XFetchName(pDisplay, iWindow, &window_name); | |
1736 | ||
1737 | style = | |
1738 | winOverrideStyle(class_hint.res_name, class_hint.res_class, | |
1739 | window_name); | |
1740 | ||
1741 | #define APPLICATION_ID_FORMAT "%s.xwin.%s" | |
1742 | #define APPLICATION_ID_UNKNOWN "unknown" | |
1743 | if (class_hint.res_class) { | |
1744 | asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME, | |
1745 | class_hint.res_class); | |
1746 | } | |
1747 | else { | |
1748 | asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME, | |
1749 | APPLICATION_ID_UNKNOWN); | |
1750 | } | |
1751 | winSetAppUserModelID(hWnd, application_id); | |
1752 | ||
1753 | if (class_hint.res_name) | |
1754 | XFree(class_hint.res_name); | |
1755 | if (class_hint.res_class) | |
1756 | XFree(class_hint.res_class); | |
1757 | if (application_id) | |
1758 | free(application_id); | |
1759 | if (window_name) | |
1760 | XFree(window_name); | |
1761 | } | |
1762 | else { | |
1763 | style = STYLE_NONE; | |
1764 | } | |
1765 | } | |
1766 | ||
1767 | if (style & STYLE_TOPMOST) | |
1768 | *zstyle = HWND_TOPMOST; | |
1769 | else if (style & STYLE_MAXIMIZE) | |
1770 | maxmin = (hint & ~HINT_MIN) | HINT_MAX; | |
1771 | else if (style & STYLE_MINIMIZE) | |
1772 | maxmin = (hint & ~HINT_MAX) | HINT_MIN; | |
1773 | else if (style & STYLE_BOTTOM) | |
1774 | *zstyle = HWND_BOTTOM; | |
1775 | ||
1776 | if (maxmin & HINT_MAX) | |
1777 | SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0); | |
1778 | else if (maxmin & HINT_MIN) | |
1779 | SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); | |
1780 | ||
1781 | if (style & STYLE_NOTITLE) | |
1782 | hint = | |
1783 | (hint & ~HINT_NOFRAME & ~HINT_BORDER & ~HINT_CAPTION) | | |
1784 | HINT_SIZEBOX; | |
1785 | else if (style & STYLE_OUTLINE) | |
1786 | hint = | |
1787 | (hint & ~HINT_NOFRAME & ~HINT_SIZEBOX & ~HINT_CAPTION) | | |
1788 | HINT_BORDER; | |
1789 | else if (style & STYLE_NOFRAME) | |
1790 | hint = | |
1791 | (hint & ~HINT_BORDER & ~HINT_CAPTION & ~HINT_SIZEBOX) | | |
1792 | HINT_NOFRAME; | |
1793 | ||
1794 | /* Now apply styles to window */ | |
1795 | style = GetWindowLongPtr(hWnd, GWL_STYLE); | |
1796 | if (!style) | |
1797 | return; /* GetWindowLongPointer returns 0 on failure, we hope this isn't a valid style */ | |
1798 | ||
1799 | style &= ~WS_CAPTION & ~WS_SIZEBOX; /* Just in case */ | |
1800 | ||
1801 | if (!(hint & ~HINT_SKIPTASKBAR)) /* No hints, default */ | |
1802 | style = style | WS_CAPTION | WS_SIZEBOX; | |
1803 | else if (hint & HINT_NOFRAME) /* No frame, no decorations */ | |
1804 | style = style & ~WS_CAPTION & ~WS_SIZEBOX; | |
1805 | else | |
1806 | style = style | ((hint & HINT_BORDER) ? WS_BORDER : 0) | | |
1807 | ((hint & HINT_SIZEBOX) ? WS_SIZEBOX : 0) | | |
1808 | ((hint & HINT_CAPTION) ? WS_CAPTION : 0); | |
1809 | ||
1810 | if (hint & HINT_NOMAXIMIZE) | |
1811 | style = style & ~WS_MAXIMIZEBOX; | |
1812 | ||
1813 | if (hint & HINT_NOMINIMIZE) | |
1814 | style = style & ~WS_MINIMIZEBOX; | |
1815 | ||
1816 | if (hint & HINT_NOSYSMENU) | |
1817 | style = style & ~WS_SYSMENU; | |
1818 | ||
1819 | if (hint & HINT_SKIPTASKBAR) | |
1820 | style = style & ~WS_MINIMIZEBOX; /* window will become lost if minimized */ | |
1821 | ||
1822 | SetWindowLongPtr(hWnd, GWL_STYLE, style); | |
1823 | ||
1824 | exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE); | |
1825 | if (hint & HINT_SKIPTASKBAR) | |
1826 | exStyle = (exStyle & ~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW; | |
1827 | else | |
1828 | exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW; | |
1829 | SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle); | |
1830 | ||
1831 | winDebug | |
1832 | ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n", | |
1833 | iWindow, hint, style, exStyle); | |
1834 | } | |
1835 | ||
1836 | void | |
1837 | winUpdateWindowPosition(HWND hWnd, HWND * zstyle) | |
1838 | { | |
1839 | int iX, iY, iWidth, iHeight; | |
1840 | int iDx, iDy; | |
1841 | RECT rcNew; | |
1842 | WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP); | |
1843 | DrawablePtr pDraw = NULL; | |
1844 | ||
1845 | if (!pWin) | |
1846 | return; | |
1847 | pDraw = &pWin->drawable; | |
1848 | if (!pDraw) | |
1849 | return; | |
1850 | ||
1851 | /* Get the X and Y location of the X window */ | |
1852 | iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN); | |
1853 | iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN); | |
1854 | ||
1855 | /* Get the height and width of the X window */ | |
1856 | iWidth = pWin->drawable.width; | |
1857 | iHeight = pWin->drawable.height; | |
1858 | ||
1859 | /* Setup a rectangle with the X window position and size */ | |
1860 | SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight); | |
1861 | ||
1862 | winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n", | |
1863 | rcNew.left, rcNew.top, rcNew.right, rcNew.bottom); | |
1864 | ||
1865 | AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE, | |
1866 | GetWindowLongPtr(hWnd, GWL_EXSTYLE)); | |
1867 | ||
1868 | /* Don't allow window decoration to disappear off to top-left as a result of this adjustment */ | |
1869 | if (rcNew.left < GetSystemMetrics(SM_XVIRTUALSCREEN)) { | |
1870 | iDx = GetSystemMetrics(SM_XVIRTUALSCREEN) - rcNew.left; | |
1871 | rcNew.left += iDx; | |
1872 | rcNew.right += iDx; | |
1873 | } | |
1874 | ||
1875 | if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) { | |
1876 | iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top; | |
1877 | rcNew.top += iDy; | |
1878 | rcNew.bottom += iDy; | |
1879 | } | |
1880 | ||
1881 | winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n", | |
1882 | rcNew.left, rcNew.top, rcNew.right, rcNew.bottom); | |
1883 | ||
1884 | /* Position the Windows window */ | |
1885 | SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top, | |
1886 | rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0); | |
1887 | ||
1888 | } |