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