winmultiwindowwm.c revision 05b261ec
1/* 2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 3 * 4 *Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 *"Software"), to deal in the Software without restriction, including 7 *without limitation the rights to use, copy, modify, merge, publish, 8 *distribute, sublicense, and/or sell copies of the Software, and to 9 *permit persons to whom the Software is furnished to do so, subject to 10 *the following conditions: 11 * 12 *The above copyright notice and this permission notice shall be 13 *included in all copies or substantial portions of the Software. 14 * 15 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 19 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 20 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 *Except as contained in this notice, the name of the XFree86 Project 24 *shall not be used in advertising or otherwise to promote the sale, use 25 *or other dealings in this Software without prior written authorization 26 *from the XFree86 Project. 27 * 28 * Authors: Kensuke Matsuzaki 29 */ 30 31/* X headers */ 32#ifdef HAVE_XWIN_CONFIG_H 33#include <xwin-config.h> 34#endif 35#include <stdio.h> 36#include <stdlib.h> 37#include <unistd.h> 38#ifdef __CYGWIN__ 39#include <sys/select.h> 40#endif 41#include <fcntl.h> 42#include <setjmp.h> 43#define HANDLE void * 44#include <pthread.h> 45#undef HANDLE 46#include <X11/X.h> 47#include <X11/Xatom.h> 48#include <X11/Xlib.h> 49#include <X11/Xlocale.h> 50#include <X11/Xproto.h> 51#include <X11/Xutil.h> 52#include <X11/cursorfont.h> 53 54/* Windows headers */ 55#ifdef __CYGWIN__ 56/* Fixups to prevent collisions between Windows and X headers */ 57#define ATOM DWORD 58 59#include <windows.h> 60#else 61#include <Xwindows.h> 62#endif 63 64/* Local headers */ 65#include "objbase.h" 66#include "ddraw.h" 67#include "winwindow.h" 68#ifdef XWIN_MULTIWINDOWEXTWM 69#include "windowswmstr.h" 70#endif 71 72extern void winDebug(const char *format, ...); 73 74#ifndef CYGDEBUG 75#define CYGDEBUG NO 76#endif 77 78/* 79 * Constant defines 80 */ 81 82#define WIN_CONNECT_RETRIES 5 83#define WIN_CONNECT_DELAY 5 84#ifdef HAS_DEVWINDOWS 85# define WIN_MSG_QUEUE_FNAME "/dev/windows" 86#endif 87#define WIN_JMP_OKAY 0 88#define WIN_JMP_ERROR_IO 2 89 90 91/* 92 * Local structures 93 */ 94 95typedef struct _WMMsgNodeRec { 96 winWMMessageRec msg; 97 struct _WMMsgNodeRec *pNext; 98} WMMsgNodeRec, *WMMsgNodePtr; 99 100typedef struct _WMMsgQueueRec { 101 struct _WMMsgNodeRec *pHead; 102 struct _WMMsgNodeRec *pTail; 103 pthread_mutex_t pmMutex; 104 pthread_cond_t pcNotEmpty; 105 int nQueueSize; 106} WMMsgQueueRec, *WMMsgQueuePtr; 107 108typedef struct _WMInfo { 109 Display *pDisplay; 110 WMMsgQueueRec wmMsgQueue; 111 Atom atmWmProtos; 112 Atom atmWmDelete; 113 Atom atmPrivMap; 114 Bool fAllowOtherWM; 115} WMInfoRec, *WMInfoPtr; 116 117typedef struct _WMProcArgRec { 118 DWORD dwScreen; 119 WMInfoPtr pWMInfo; 120 pthread_mutex_t *ppmServerStarted; 121} WMProcArgRec, *WMProcArgPtr; 122 123typedef struct _XMsgProcArgRec { 124 Display *pDisplay; 125 DWORD dwScreen; 126 WMInfoPtr pWMInfo; 127 pthread_mutex_t *ppmServerStarted; 128 HWND hwndScreen; 129} XMsgProcArgRec, *XMsgProcArgPtr; 130 131 132/* 133 * References to external symbols 134 */ 135 136extern char *display; 137extern void ErrorF (const char* /*f*/, ...); 138 139 140/* 141 * Prototypes for local functions 142 */ 143 144static void 145PushMessage (WMMsgQueuePtr pQueue, WMMsgNodePtr pNode); 146 147static WMMsgNodePtr 148PopMessage (WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo); 149 150static Bool 151InitQueue (WMMsgQueuePtr pQueue); 152 153static void 154GetWindowName (Display * pDpy, Window iWin, char **ppName); 155 156static int 157SendXMessage (Display *pDisplay, Window iWin, Atom atmType, long nData); 158 159static void 160UpdateName (WMInfoPtr pWMInfo, Window iWindow); 161 162static void* 163winMultiWindowWMProc (void* pArg); 164 165static int 166winMultiWindowWMErrorHandler (Display *pDisplay, XErrorEvent *pErr); 167 168static int 169winMultiWindowWMIOErrorHandler (Display *pDisplay); 170 171static void * 172winMultiWindowXMsgProc (void *pArg); 173 174static int 175winMultiWindowXMsgProcErrorHandler (Display *pDisplay, XErrorEvent *pErr); 176 177static int 178winMultiWindowXMsgProcIOErrorHandler (Display *pDisplay); 179 180static int 181winRedirectErrorHandler (Display *pDisplay, XErrorEvent *pErr); 182 183static void 184winInitMultiWindowWM (WMInfoPtr pWMInfo, WMProcArgPtr pProcArg); 185 186#if 0 187static void 188PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction); 189#endif 190 191static Bool 192CheckAnotherWindowManager (Display *pDisplay, DWORD dwScreen); 193 194 195/* 196 * Local globals 197 */ 198 199static jmp_buf g_jmpWMEntry; 200static jmp_buf g_jmpXMsgProcEntry; 201static Bool g_shutdown = FALSE; 202static Bool redirectError = FALSE; 203static Bool g_fAnotherWMRunnig = FALSE; 204 205/* 206 * PushMessage - Push a message onto the queue 207 */ 208 209static void 210PushMessage (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 { 220 pQueue->pTail->pNext = pNode; 221 } 222 pQueue->pTail = pNode; 223 224 if (pQueue->pHead == NULL) 225 { 226 pQueue->pHead = pNode; 227 } 228 229 230#if 0 231 switch (pNode->msg.msg) 232 { 233 case WM_WM_MOVE: 234 ErrorF ("\tWM_WM_MOVE\n"); 235 break; 236 case WM_WM_SIZE: 237 ErrorF ("\tWM_WM_SIZE\n"); 238 break; 239 case WM_WM_RAISE: 240 ErrorF ("\tWM_WM_RAISE\n"); 241 break; 242 case WM_WM_LOWER: 243 ErrorF ("\tWM_WM_LOWER\n"); 244 break; 245 case WM_WM_MAP: 246 ErrorF ("\tWM_WM_MAP\n"); 247 break; 248 case WM_WM_UNMAP: 249 ErrorF ("\tWM_WM_UNMAP\n"); 250 break; 251 case WM_WM_KILL: 252 ErrorF ("\tWM_WM_KILL\n"); 253 break; 254 case WM_WM_ACTIVATE: 255 ErrorF ("\tWM_WM_ACTIVATE\n"); 256 break; 257 default: 258 ErrorF ("\tUnknown Message.\n"); 259 break; 260 } 261#endif 262 263 /* Increase the count of elements in the queue by one */ 264 ++(pQueue->nQueueSize); 265 266 /* Release the queue mutex */ 267 pthread_mutex_unlock (&pQueue->pmMutex); 268 269 /* Signal that the queue is not empty */ 270 pthread_cond_signal (&pQueue->pcNotEmpty); 271} 272 273 274#if CYGMULTIWINDOW_DEBUG 275/* 276 * QueueSize - Return the size of the queue 277 */ 278 279static int 280QueueSize (WMMsgQueuePtr pQueue) 281{ 282 WMMsgNodePtr pNode; 283 int nSize = 0; 284 285 /* Loop through all elements in the queue */ 286 for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) 287 ++nSize; 288 289 return nSize; 290} 291#endif 292 293 294/* 295 * PopMessage - Pop a message from the queue 296 */ 297 298static WMMsgNodePtr 299PopMessage (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 { 309 pthread_cond_wait (&pQueue->pcNotEmpty, &pQueue->pmMutex); 310 } 311 312 pNode = pQueue->pHead; 313 if (pQueue->pHead != NULL) 314 { 315 pQueue->pHead = pQueue->pHead->pNext; 316 } 317 318 if (pQueue->pTail == pNode) 319 { 320 pQueue->pTail = NULL; 321 } 322 323 /* Drop the number of elements in the queue by one */ 324 --(pQueue->nQueueSize); 325 326#if CYGMULTIWINDOW_DEBUG 327 ErrorF ("Queue Size %d %d\n", pQueue->nQueueSize, QueueSize(pQueue)); 328#endif 329 330 /* Release the queue mutex */ 331 pthread_mutex_unlock (&pQueue->pmMutex); 332 333 return pNode; 334} 335 336 337#if 0 338/* 339 * HaveMessage - 340 */ 341 342static Bool 343HaveMessage (WMMsgQueuePtr pQueue, UINT msg, Window iWindow) 344{ 345 WMMsgNodePtr pNode; 346 347 for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) 348 { 349 if (pNode->msg.msg==msg && pNode->msg.iWindow==iWindow) 350 return True; 351 } 352 353 return False; 354} 355#endif 356 357 358/* 359 * InitQueue - Initialize the Window Manager message queue 360 */ 361 362static 363Bool 364InitQueue (WMMsgQueuePtr pQueue) 365{ 366 /* Check if the pQueue pointer is NULL */ 367 if (pQueue == NULL) 368 { 369 ErrorF ("InitQueue - pQueue is NULL. Exiting.\n"); 370 return FALSE; 371 } 372 373 /* Set the head and tail to NULL */ 374 pQueue->pHead = NULL; 375 pQueue->pTail = NULL; 376 377 /* There are no elements initially */ 378 pQueue->nQueueSize = 0; 379 380#if CYGMULTIWINDOW_DEBUG 381 ErrorF ("InitQueue - Queue Size %d %d\n", pQueue->nQueueSize, 382 QueueSize(pQueue)); 383#endif 384 385 ErrorF ("InitQueue - Calling pthread_mutex_init\n"); 386 387 /* Create synchronization objects */ 388 pthread_mutex_init (&pQueue->pmMutex, NULL); 389 390 ErrorF ("InitQueue - pthread_mutex_init returned\n"); 391 ErrorF ("InitQueue - Calling pthread_cond_init\n"); 392 393 pthread_cond_init (&pQueue->pcNotEmpty, NULL); 394 395 ErrorF ("InitQueue - pthread_cond_init returned\n"); 396 397 return TRUE; 398} 399 400 401/* 402 * GetWindowName - Retrieve the title of an X Window 403 */ 404 405static void 406GetWindowName (Display *pDisplay, Window iWin, char **ppName) 407{ 408 int nResult, nNum; 409 char **ppList; 410 XTextProperty xtpName; 411 412#if CYGMULTIWINDOW_DEBUG 413 ErrorF ("GetWindowName\n"); 414#endif 415 416 /* Intialize ppName to NULL */ 417 *ppName = NULL; 418 419 /* Try to get --- */ 420 nResult = XGetWMName (pDisplay, iWin, &xtpName); 421 if (!nResult || !xtpName.value || !xtpName.nitems) 422 { 423#if CYGMULTIWINDOW_DEBUG 424 ErrorF ("GetWindowName - XGetWMName failed. No name.\n"); 425#endif 426 return; 427 } 428 429 /* */ 430 if (xtpName.encoding == XA_STRING) 431 { 432 /* */ 433 if (xtpName.value) 434 { 435 int size = xtpName.nitems * (xtpName.format >> 3); 436 *ppName = malloc(size + 1); 437 strncpy(*ppName, xtpName.value, size); 438 (*ppName)[size] = 0; 439 XFree (xtpName.value); 440 } 441 442#if CYGMULTIWINDOW_DEBUG 443 ErrorF ("GetWindowName - XA_STRING %s\n", *ppName); 444#endif 445 } 446 else 447 { 448 if (XmbTextPropertyToTextList (pDisplay, &xtpName, &ppList, &nNum) >= Success && nNum > 0 && *ppList) 449 { 450 *ppName = strdup (*ppList); 451 XFreeStringList (ppList); 452 } 453 XFree (xtpName.value); 454 455#if CYGMULTIWINDOW_DEBUG 456 ErrorF ("GetWindowName - %s %s\n", 457 XGetAtomName (pDisplay, xtpName.encoding), *ppName); 458#endif 459 } 460 461#if CYGMULTIWINDOW_DEBUG 462 ErrorF ("GetWindowName - Returning\n"); 463#endif 464} 465 466 467/* 468 * Send a message to the X server from the WM thread 469 */ 470 471static int 472SendXMessage (Display *pDisplay, Window iWin, Atom atmType, long nData) 473{ 474 XEvent e; 475 476 /* Prepare the X event structure */ 477 e.type = ClientMessage; 478 e.xclient.window = iWin; 479 e.xclient.message_type = atmType; 480 e.xclient.format = 32; 481 e.xclient.data.l[0] = nData; 482 e.xclient.data.l[1] = CurrentTime; 483 484 /* Send the event to X */ 485 return XSendEvent (pDisplay, iWin, False, NoEventMask, &e); 486} 487 488 489/* 490 * Updates the name of a HWND according to its X WM_NAME property 491 */ 492 493static void 494UpdateName (WMInfoPtr pWMInfo, Window iWindow) 495{ 496 char *pszName; 497 Atom atmType; 498 int fmtRet; 499 unsigned long items, remain; 500 HWND *retHwnd, hWnd; 501 XWindowAttributes attr; 502 503 hWnd = 0; 504 505 /* See if we can get the cached HWND for this window... */ 506 if (XGetWindowProperty (pWMInfo->pDisplay, 507 iWindow, 508 pWMInfo->atmPrivMap, 509 0, 510 1, 511 False, 512 XA_INTEGER,//pWMInfo->atmPrivMap, 513 &atmType, 514 &fmtRet, 515 &items, 516 &remain, 517 (unsigned char **) &retHwnd) == Success) 518 { 519 if (retHwnd) 520 { 521 hWnd = *retHwnd; 522 XFree (retHwnd); 523 } 524 } 525 526 /* Some sanity checks */ 527 if (!hWnd) return; 528 if (!IsWindow (hWnd)) return; 529 530 /* Set the Windows window name */ 531 GetWindowName (pWMInfo->pDisplay, iWindow, &pszName); 532 if (pszName) 533 { 534 /* Get the window attributes */ 535 XGetWindowAttributes (pWMInfo->pDisplay, 536 iWindow, 537 &attr); 538 if (!attr.override_redirect) 539 { 540 SetWindowText (hWnd, pszName); 541 winUpdateIcon (iWindow); 542 } 543 544 free (pszName); 545 } 546} 547 548 549#if 0 550/* 551 * Fix up any differences between the X11 and Win32 window stacks 552 * starting at the window passed in 553 */ 554static void 555PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction) 556{ 557 Atom atmType; 558 int fmtRet; 559 unsigned long items, remain; 560 HWND hWnd, *retHwnd; 561 DWORD myWinProcID, winProcID; 562 Window xWindow; 563 WINDOWPLACEMENT wndPlace; 564 565 hWnd = NULL; 566 /* See if we can get the cached HWND for this window... */ 567 if (XGetWindowProperty (pWMInfo->pDisplay, 568 iWindow, 569 pWMInfo->atmPrivMap, 570 0, 571 1, 572 False, 573 XA_INTEGER,//pWMInfo->atmPrivMap, 574 &atmType, 575 &fmtRet, 576 &items, 577 &remain, 578 (unsigned char **) &retHwnd) == Success) 579 { 580 if (retHwnd) 581 { 582 hWnd = *retHwnd; 583 XFree (retHwnd); 584 } 585 } 586 587 if (!hWnd) return; 588 589 GetWindowThreadProcessId (hWnd, &myWinProcID); 590 hWnd = GetNextWindow (hWnd, direction); 591 592 while (hWnd) { 593 GetWindowThreadProcessId (hWnd, &winProcID); 594 if (winProcID == myWinProcID) 595 { 596 wndPlace.length = sizeof(WINDOWPLACEMENT); 597 GetWindowPlacement (hWnd, &wndPlace); 598 if ( !(wndPlace.showCmd==SW_HIDE || 599 wndPlace.showCmd==SW_MINIMIZE) ) 600 { 601 xWindow = (Window)GetProp (hWnd, WIN_WID_PROP); 602 if (xWindow) 603 { 604 if (direction==GW_HWNDPREV) 605 XRaiseWindow (pWMInfo->pDisplay, xWindow); 606 else 607 XLowerWindow (pWMInfo->pDisplay, xWindow); 608 } 609 } 610 } 611 hWnd = GetNextWindow(hWnd, direction); 612 } 613} 614#endif /* PreserveWin32Stack */ 615 616 617/* 618 * winMultiWindowWMProc 619 */ 620 621static void * 622winMultiWindowWMProc (void *pArg) 623{ 624 WMProcArgPtr pProcArg = (WMProcArgPtr)pArg; 625 WMInfoPtr pWMInfo = pProcArg->pWMInfo; 626 627 /* Initialize the Window Manager */ 628 winInitMultiWindowWM (pWMInfo, pProcArg); 629 630#if CYGMULTIWINDOW_DEBUG 631 ErrorF ("winMultiWindowWMProc ()\n"); 632#endif 633 634 /* Loop until we explicity break out */ 635 for (;;) 636 { 637 WMMsgNodePtr pNode; 638 639 if(g_fAnotherWMRunnig)/* Another Window manager exists. */ 640 { 641 Sleep (1000); 642 continue; 643 } 644 645 /* Pop a message off of our queue */ 646 pNode = PopMessage (&pWMInfo->wmMsgQueue, pWMInfo); 647 if (pNode == NULL) 648 { 649 /* Bail if PopMessage returns without a message */ 650 /* NOTE: Remember that PopMessage is a blocking function. */ 651 ErrorF ("winMultiWindowWMProc - Queue is Empty? Exiting.\n"); 652 pthread_exit (NULL); 653 } 654 655#if CYGMULTIWINDOW_DEBUG 656 ErrorF ("winMultiWindowWMProc - %d ms MSG: %d ID: %d\n", 657 GetTickCount (), (int)pNode->msg.msg, (int)pNode->msg.dwID); 658#endif 659 660 /* Branch on the message type */ 661 switch (pNode->msg.msg) 662 { 663#if 0 664 case WM_WM_MOVE: 665 ErrorF ("\tWM_WM_MOVE\n"); 666 break; 667 668 case WM_WM_SIZE: 669 ErrorF ("\tWM_WM_SIZE\n"); 670 break; 671#endif 672 673 case WM_WM_RAISE: 674#if CYGMULTIWINDOW_DEBUG 675 ErrorF ("\tWM_WM_RAISE\n"); 676#endif 677 /* Raise the window */ 678 XRaiseWindow (pWMInfo->pDisplay, pNode->msg.iWindow); 679#if 0 680 PreserveWin32Stack (pWMInfo, pNode->msg.iWindow, GW_HWNDPREV); 681#endif 682 break; 683 684 case WM_WM_LOWER: 685#if CYGMULTIWINDOW_DEBUG 686 ErrorF ("\tWM_WM_LOWER\n"); 687#endif 688 689 /* Lower the window */ 690 XLowerWindow (pWMInfo->pDisplay, pNode->msg.iWindow); 691 break; 692 693 case WM_WM_MAP: 694#if CYGMULTIWINDOW_DEBUG 695 ErrorF ("\tWM_WM_MAP\n"); 696#endif 697 /* Put a note as to the HWND associated with this Window */ 698 XChangeProperty (pWMInfo->pDisplay, 699 pNode->msg.iWindow, 700 pWMInfo->atmPrivMap, 701 XA_INTEGER,//pWMInfo->atmPrivMap, 702 32, 703 PropModeReplace, 704 (unsigned char *) &(pNode->msg.hwndWindow), 705 1); 706 UpdateName (pWMInfo, pNode->msg.iWindow); 707 winUpdateIcon (pNode->msg.iWindow); 708#if 0 709 /* Handles the case where there are AOT windows above it in W32 */ 710 PreserveWin32Stack (pWMInfo, pNode->msg.iWindow, GW_HWNDPREV); 711#endif 712 break; 713 714 case WM_WM_UNMAP: 715#if CYGMULTIWINDOW_DEBUG 716 ErrorF ("\tWM_WM_UNMAP\n"); 717#endif 718 719 /* Unmap the window */ 720 XUnmapWindow (pWMInfo->pDisplay, pNode->msg.iWindow); 721 break; 722 723 case WM_WM_KILL: 724#if CYGMULTIWINDOW_DEBUG 725 ErrorF ("\tWM_WM_KILL\n"); 726#endif 727 { 728 int i, n, found = 0; 729 Atom *protocols; 730 731 /* --- */ 732 if (XGetWMProtocols (pWMInfo->pDisplay, 733 pNode->msg.iWindow, 734 &protocols, 735 &n)) 736 { 737 for (i = 0; i < n; ++i) 738 if (protocols[i] == pWMInfo->atmWmDelete) 739 ++found; 740 741 XFree (protocols); 742 } 743 744 /* --- */ 745 if (found) 746 SendXMessage (pWMInfo->pDisplay, 747 pNode->msg.iWindow, 748 pWMInfo->atmWmProtos, 749 pWMInfo->atmWmDelete); 750 else 751 XKillClient (pWMInfo->pDisplay, 752 pNode->msg.iWindow); 753 } 754 break; 755 756 case WM_WM_ACTIVATE: 757#if CYGMULTIWINDOW_DEBUG 758 ErrorF ("\tWM_WM_ACTIVATE\n"); 759#endif 760 761 /* Set the input focus */ 762 XSetInputFocus (pWMInfo->pDisplay, 763 pNode->msg.iWindow, 764 RevertToPointerRoot, 765 CurrentTime); 766 break; 767 768 case WM_WM_NAME_EVENT: 769 UpdateName (pWMInfo, pNode->msg.iWindow); 770 break; 771 772 case WM_WM_HINTS_EVENT: 773 winUpdateIcon (pNode->msg.iWindow); 774 break; 775 776 case WM_WM_CHANGE_STATE: 777 /* Minimize the window in Windows */ 778 winMinimizeWindow (pNode->msg.iWindow); 779 break; 780 781 default: 782 ErrorF ("winMultiWindowWMProc - Unknown Message. Exiting.\n"); 783 pthread_exit (NULL); 784 break; 785 } 786 787 /* Free the retrieved message */ 788 free (pNode); 789 790 /* Flush any pending events on our display */ 791 XFlush (pWMInfo->pDisplay); 792 } 793 794 /* Free the condition variable */ 795 pthread_cond_destroy (&pWMInfo->wmMsgQueue.pcNotEmpty); 796 797 /* Free the mutex variable */ 798 pthread_mutex_destroy (&pWMInfo->wmMsgQueue.pmMutex); 799 800 /* Free the passed-in argument */ 801 free (pProcArg); 802 803#if CYGMULTIWINDOW_DEBUG 804 ErrorF("-winMultiWindowWMProc ()\n"); 805#endif 806} 807 808 809/* 810 * X message procedure 811 */ 812 813static void * 814winMultiWindowXMsgProc (void *pArg) 815{ 816 winWMMessageRec msg; 817 XMsgProcArgPtr pProcArg = (XMsgProcArgPtr) pArg; 818 char pszDisplay[512]; 819 int iRetries; 820 XEvent event; 821 Atom atmWmName; 822 Atom atmWmHints; 823 Atom atmWmChange; 824 int iReturn; 825 XIconSize *xis; 826 827 ErrorF ("winMultiWindowXMsgProc - Hello\n"); 828 829 /* Check that argument pointer is not invalid */ 830 if (pProcArg == NULL) 831 { 832 ErrorF ("winMultiWindowXMsgProc - pProcArg is NULL. Exiting.\n"); 833 pthread_exit (NULL); 834 } 835 836 ErrorF ("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n"); 837 838 /* Grab the server started mutex - pause until we get it */ 839 iReturn = pthread_mutex_lock (pProcArg->ppmServerStarted); 840 if (iReturn != 0) 841 { 842 ErrorF ("winMultiWindowXMsgProc - pthread_mutex_lock () failed: %d. " 843 "Exiting.\n", 844 iReturn); 845 pthread_exit (NULL); 846 } 847 848 ErrorF ("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n"); 849 850 /* Allow multiple threads to access Xlib */ 851 if (XInitThreads () == 0) 852 { 853 ErrorF ("winMultiWindowXMsgProc - XInitThreads () failed. Exiting.\n"); 854 pthread_exit (NULL); 855 } 856 857 /* See if X supports the current locale */ 858 if (XSupportsLocale () == False) 859 { 860 ErrorF ("winMultiWindowXMsgProc - Locale not supported by X. " 861 "Exiting.\n"); 862 pthread_exit (NULL); 863 } 864 865 /* Release the server started mutex */ 866 pthread_mutex_unlock (pProcArg->ppmServerStarted); 867 868 ErrorF ("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n"); 869 870 /* Set jump point for IO Error exits */ 871 iReturn = setjmp (g_jmpXMsgProcEntry); 872 873 /* Check if we should continue operations */ 874 if (iReturn != WIN_JMP_ERROR_IO 875 && iReturn != WIN_JMP_OKAY) 876 { 877 /* setjmp returned an unknown value, exit */ 878 ErrorF ("winInitMultiWindowXMsgProc - setjmp returned: %d. Exiting.\n", 879 iReturn); 880 pthread_exit (NULL); 881 } 882 else if (iReturn == WIN_JMP_ERROR_IO) 883 { 884 ErrorF ("winInitMultiWindowXMsgProc - Caught IO Error. Exiting.\n"); 885 pthread_exit (NULL); 886 } 887 888 /* Install our error handler */ 889 XSetErrorHandler (winMultiWindowXMsgProcErrorHandler); 890 XSetIOErrorHandler (winMultiWindowXMsgProcIOErrorHandler); 891 892 /* Setup the display connection string x */ 893 snprintf (pszDisplay, 894 512, "127.0.0.1:%s.%d", display, (int)pProcArg->dwScreen); 895 896 /* Print the display connection string */ 897 ErrorF ("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay); 898 899 /* Initialize retry count */ 900 iRetries = 0; 901 902 /* Open the X display */ 903 do 904 { 905 /* Try to open the display */ 906 pProcArg->pDisplay = XOpenDisplay (pszDisplay); 907 if (pProcArg->pDisplay == NULL) 908 { 909 ErrorF ("winMultiWindowXMsgProc - Could not open display, try: %d, " 910 "sleeping: %d\n\f", 911 iRetries + 1, WIN_CONNECT_DELAY); 912 ++iRetries; 913 sleep (WIN_CONNECT_DELAY); 914 continue; 915 } 916 else 917 break; 918 } 919 while (pProcArg->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES); 920 921 /* Make sure that the display opened */ 922 if (pProcArg->pDisplay == NULL) 923 { 924 ErrorF ("winMultiWindowXMsgProc - Failed opening the display. " 925 "Exiting.\n"); 926 pthread_exit (NULL); 927 } 928 929 ErrorF ("winMultiWindowXMsgProc - XOpenDisplay () returned and " 930 "successfully opened the display.\n"); 931 932 /* Check if another window manager is already running */ 933 if (pProcArg->pWMInfo->fAllowOtherWM) 934 { 935 g_fAnotherWMRunnig = CheckAnotherWindowManager (pProcArg->pDisplay, pProcArg->dwScreen); 936 } else { 937 redirectError = FALSE; 938 XSetErrorHandler (winRedirectErrorHandler); 939 XSelectInput(pProcArg->pDisplay, 940 RootWindow (pProcArg->pDisplay, pProcArg->dwScreen), 941 SubstructureNotifyMask | ButtonPressMask); 942 XSync (pProcArg->pDisplay, 0); 943 XSetErrorHandler (winMultiWindowXMsgProcErrorHandler); 944 if (redirectError) 945 { 946 ErrorF ("winMultiWindowXMsgProc - " 947 "another window manager is running. Exiting.\n"); 948 pthread_exit (NULL); 949 } 950 g_fAnotherWMRunnig = FALSE; 951 } 952 953 /* Set up the supported icon sizes */ 954 xis = XAllocIconSize (); 955 if (xis) 956 { 957 xis->min_width = xis->min_height = 16; 958 xis->max_width = xis->max_height = 48; 959 xis->width_inc = xis->height_inc = 16; 960 XSetIconSizes (pProcArg->pDisplay, 961 RootWindow (pProcArg->pDisplay, pProcArg->dwScreen), 962 xis, 963 1); 964 XFree (xis); 965 } 966 967 atmWmName = XInternAtom (pProcArg->pDisplay, 968 "WM_NAME", 969 False); 970 atmWmHints = XInternAtom (pProcArg->pDisplay, 971 "WM_HINTS", 972 False); 973 atmWmChange = XInternAtom (pProcArg->pDisplay, 974 "WM_CHANGE_STATE", 975 False); 976 977 /* Loop until we explicitly break out */ 978 while (1) 979 { 980 if (g_shutdown) 981 break; 982 983 if (pProcArg->pWMInfo->fAllowOtherWM && !XPending (pProcArg->pDisplay)) 984 { 985 if (CheckAnotherWindowManager (pProcArg->pDisplay, pProcArg->dwScreen)) 986 { 987 if (!g_fAnotherWMRunnig) 988 { 989 g_fAnotherWMRunnig = TRUE; 990 SendMessage(*(HWND*)pProcArg->hwndScreen, WM_UNMANAGE, 0, 0); 991 } 992 } 993 else 994 { 995 if (g_fAnotherWMRunnig) 996 { 997 g_fAnotherWMRunnig = FALSE; 998 SendMessage(*(HWND*)pProcArg->hwndScreen, WM_MANAGE, 0, 0); 999 } 1000 } 1001 Sleep (500); 1002 continue; 1003 } 1004 1005 /* Fetch next event */ 1006 XNextEvent (pProcArg->pDisplay, &event); 1007 1008 /* Branch on event type */ 1009 if (event.type == CreateNotify) 1010 { 1011 XWindowAttributes attr; 1012 1013 XSelectInput (pProcArg->pDisplay, 1014 event.xcreatewindow.window, 1015 PropertyChangeMask); 1016 1017 /* Get the window attributes */ 1018 XGetWindowAttributes (pProcArg->pDisplay, 1019 event.xcreatewindow.window, 1020 &attr); 1021 1022 if (!attr.override_redirect) 1023 XSetWindowBorderWidth(pProcArg->pDisplay, 1024 event.xcreatewindow.window, 1025 0); 1026 } 1027 else if (event.type == PropertyNotify 1028 && event.xproperty.atom == atmWmName) 1029 { 1030 memset (&msg, 0, sizeof (msg)); 1031 1032 msg.msg = WM_WM_NAME_EVENT; 1033 msg.iWindow = event.xproperty.window; 1034 1035 /* Other fields ignored */ 1036 winSendMessageToWM (pProcArg->pWMInfo, &msg); 1037 } 1038 else if (event.type == PropertyNotify 1039 && event.xproperty.atom == atmWmHints) 1040 { 1041 memset (&msg, 0, sizeof (msg)); 1042 1043 msg.msg = WM_WM_HINTS_EVENT; 1044 msg.iWindow = event.xproperty.window; 1045 1046 /* Other fields ignored */ 1047 winSendMessageToWM (pProcArg->pWMInfo, &msg); 1048 } 1049 else if (event.type == ClientMessage 1050 && event.xclient.message_type == atmWmChange 1051 && event.xclient.data.l[0] == IconicState) 1052 { 1053 ErrorF ("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n"); 1054 1055 memset (&msg, 0, sizeof (msg)); 1056 1057 msg.msg = WM_WM_CHANGE_STATE; 1058 msg.iWindow = event.xclient.window; 1059 1060 winSendMessageToWM (pProcArg->pWMInfo, &msg); 1061 } 1062 } 1063 1064 XCloseDisplay (pProcArg->pDisplay); 1065 pthread_exit (NULL); 1066 1067} 1068 1069 1070/* 1071 * winInitWM - Entry point for the X server to spawn 1072 * the Window Manager thread. Called from 1073 * winscrinit.c/winFinishScreenInitFB (). 1074 */ 1075 1076Bool 1077winInitWM (void **ppWMInfo, 1078 pthread_t *ptWMProc, 1079 pthread_t *ptXMsgProc, 1080 pthread_mutex_t *ppmServerStarted, 1081 int dwScreen, 1082 HWND hwndScreen, 1083 BOOL allowOtherWM) 1084{ 1085 WMProcArgPtr pArg = (WMProcArgPtr) malloc (sizeof(WMProcArgRec)); 1086 WMInfoPtr pWMInfo = (WMInfoPtr) malloc (sizeof(WMInfoRec)); 1087 XMsgProcArgPtr pXMsgArg = (XMsgProcArgPtr) malloc (sizeof(XMsgProcArgRec)); 1088 1089 /* Bail if the input parameters are bad */ 1090 if (pArg == NULL || pWMInfo == NULL) 1091 { 1092 ErrorF ("winInitWM - malloc failed.\n"); 1093 return FALSE; 1094 } 1095 1096 /* Zero the allocated memory */ 1097 ZeroMemory (pArg, sizeof (WMProcArgRec)); 1098 ZeroMemory (pWMInfo, sizeof (WMInfoRec)); 1099 ZeroMemory (pXMsgArg, sizeof (XMsgProcArgRec)); 1100 1101 /* Set a return pointer to the Window Manager info structure */ 1102 *ppWMInfo = pWMInfo; 1103 pWMInfo->fAllowOtherWM = allowOtherWM; 1104 1105 /* Setup the argument structure for the thread function */ 1106 pArg->dwScreen = dwScreen; 1107 pArg->pWMInfo = pWMInfo; 1108 pArg->ppmServerStarted = ppmServerStarted; 1109 1110 /* Intialize the message queue */ 1111 if (!InitQueue (&pWMInfo->wmMsgQueue)) 1112 { 1113 ErrorF ("winInitWM - InitQueue () failed.\n"); 1114 return FALSE; 1115 } 1116 1117 /* Spawn a thread for the Window Manager */ 1118 if (pthread_create (ptWMProc, NULL, winMultiWindowWMProc, pArg)) 1119 { 1120 /* Bail if thread creation failed */ 1121 ErrorF ("winInitWM - pthread_create failed for Window Manager.\n"); 1122 return FALSE; 1123 } 1124 1125 /* Spawn the XNextEvent thread, will send messages to WM */ 1126 pXMsgArg->dwScreen = dwScreen; 1127 pXMsgArg->pWMInfo = pWMInfo; 1128 pXMsgArg->ppmServerStarted = ppmServerStarted; 1129 pXMsgArg->hwndScreen = hwndScreen; 1130 if (pthread_create (ptXMsgProc, NULL, winMultiWindowXMsgProc, pXMsgArg)) 1131 { 1132 /* Bail if thread creation failed */ 1133 ErrorF ("winInitWM - pthread_create failed on XMSG.\n"); 1134 return FALSE; 1135 } 1136 1137#if CYGDEBUG || YES 1138 winDebug ("winInitWM - Returning.\n"); 1139#endif 1140 1141 return TRUE; 1142} 1143 1144 1145/* 1146 * Window manager thread - setup 1147 */ 1148 1149static void 1150winInitMultiWindowWM (WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) 1151{ 1152 int iRetries = 0; 1153 char pszDisplay[512]; 1154 int iReturn; 1155 1156 ErrorF ("winInitMultiWindowWM - Hello\n"); 1157 1158 /* Check that argument pointer is not invalid */ 1159 if (pProcArg == NULL) 1160 { 1161 ErrorF ("winInitMultiWindowWM - pProcArg is NULL. Exiting.\n"); 1162 pthread_exit (NULL); 1163 } 1164 1165 ErrorF ("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n"); 1166 1167 /* Grab our garbage mutex to satisfy pthread_cond_wait */ 1168 iReturn = pthread_mutex_lock (pProcArg->ppmServerStarted); 1169 if (iReturn != 0) 1170 { 1171 ErrorF ("winInitMultiWindowWM - pthread_mutex_lock () failed: %d. " 1172 "Exiting.\n", 1173 iReturn); 1174 pthread_exit (NULL); 1175 } 1176 1177 ErrorF ("winInitMultiWindowWM - pthread_mutex_lock () returned.\n"); 1178 1179 /* Allow multiple threads to access Xlib */ 1180 if (XInitThreads () == 0) 1181 { 1182 ErrorF ("winInitMultiWindowWM - XInitThreads () failed. Exiting.\n"); 1183 pthread_exit (NULL); 1184 } 1185 1186 /* See if X supports the current locale */ 1187 if (XSupportsLocale () == False) 1188 { 1189 ErrorF ("winInitMultiWindowWM - Locale not supported by X. Exiting.\n"); 1190 pthread_exit (NULL); 1191 } 1192 1193 /* Release the server started mutex */ 1194 pthread_mutex_unlock (pProcArg->ppmServerStarted); 1195 1196 ErrorF ("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n"); 1197 1198 /* Set jump point for IO Error exits */ 1199 iReturn = setjmp (g_jmpWMEntry); 1200 1201 /* Check if we should continue operations */ 1202 if (iReturn != WIN_JMP_ERROR_IO 1203 && iReturn != WIN_JMP_OKAY) 1204 { 1205 /* setjmp returned an unknown value, exit */ 1206 ErrorF ("winInitMultiWindowWM - setjmp returned: %d. Exiting.\n", 1207 iReturn); 1208 pthread_exit (NULL); 1209 } 1210 else if (iReturn == WIN_JMP_ERROR_IO) 1211 { 1212 ErrorF ("winInitMultiWindowWM - Caught IO Error. Exiting.\n"); 1213 pthread_exit (NULL); 1214 } 1215 1216 /* Install our error handler */ 1217 XSetErrorHandler (winMultiWindowWMErrorHandler); 1218 XSetIOErrorHandler (winMultiWindowWMIOErrorHandler); 1219 1220 /* Setup the display connection string x */ 1221 snprintf (pszDisplay, 1222 512, 1223 "127.0.0.1:%s.%d", 1224 display, 1225 (int) pProcArg->dwScreen); 1226 1227 /* Print the display connection string */ 1228 ErrorF ("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay); 1229 1230 /* Open the X display */ 1231 do 1232 { 1233 /* Try to open the display */ 1234 pWMInfo->pDisplay = XOpenDisplay (pszDisplay); 1235 if (pWMInfo->pDisplay == NULL) 1236 { 1237 ErrorF ("winInitMultiWindowWM - Could not open display, try: %d, " 1238 "sleeping: %d\n\f", 1239 iRetries + 1, WIN_CONNECT_DELAY); 1240 ++iRetries; 1241 sleep (WIN_CONNECT_DELAY); 1242 continue; 1243 } 1244 else 1245 break; 1246 } 1247 while (pWMInfo->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES); 1248 1249 /* Make sure that the display opened */ 1250 if (pWMInfo->pDisplay == NULL) 1251 { 1252 ErrorF ("winInitMultiWindowWM - Failed opening the display. " 1253 "Exiting.\n"); 1254 pthread_exit (NULL); 1255 } 1256 1257 ErrorF ("winInitMultiWindowWM - XOpenDisplay () returned and " 1258 "successfully opened the display.\n"); 1259 1260 1261 /* Create some atoms */ 1262 pWMInfo->atmWmProtos = XInternAtom (pWMInfo->pDisplay, 1263 "WM_PROTOCOLS", 1264 False); 1265 pWMInfo->atmWmDelete = XInternAtom (pWMInfo->pDisplay, 1266 "WM_DELETE_WINDOW", 1267 False); 1268#ifdef XWIN_MULTIWINDOWEXTWM 1269 pWMInfo->atmPrivMap = XInternAtom (pWMInfo->pDisplay, 1270 WINDOWSWM_NATIVE_HWND, 1271 False); 1272#endif 1273 1274 1275 if (1) { 1276 Cursor cursor = XCreateFontCursor (pWMInfo->pDisplay, XC_left_ptr); 1277 if (cursor) 1278 { 1279 XDefineCursor (pWMInfo->pDisplay, DefaultRootWindow(pWMInfo->pDisplay), cursor); 1280 XFreeCursor (pWMInfo->pDisplay, cursor); 1281 } 1282 } 1283} 1284 1285 1286/* 1287 * winSendMessageToWM - Send a message from the X thread to the WM thread 1288 */ 1289 1290void 1291winSendMessageToWM (void *pWMInfo, winWMMessagePtr pMsg) 1292{ 1293 WMMsgNodePtr pNode; 1294 1295#if CYGMULTIWINDOW_DEBUG 1296 ErrorF ("winSendMessageToWM ()\n"); 1297#endif 1298 1299 pNode = (WMMsgNodePtr)malloc(sizeof(WMMsgNodeRec)); 1300 if (pNode != NULL) 1301 { 1302 memcpy (&pNode->msg, pMsg, sizeof(winWMMessageRec)); 1303 PushMessage (&((WMInfoPtr)pWMInfo)->wmMsgQueue, pNode); 1304 } 1305} 1306 1307 1308/* 1309 * Window manager error handler 1310 */ 1311 1312static int 1313winMultiWindowWMErrorHandler (Display *pDisplay, XErrorEvent *pErr) 1314{ 1315 char pszErrorMsg[100]; 1316 1317 if (pErr->request_code == X_ChangeWindowAttributes 1318 && pErr->error_code == BadAccess) 1319 { 1320 ErrorF ("winMultiWindowWMErrorHandler - ChangeWindowAttributes " 1321 "BadAccess.\n"); 1322 return 0; 1323 } 1324 1325 XGetErrorText (pDisplay, 1326 pErr->error_code, 1327 pszErrorMsg, 1328 sizeof (pszErrorMsg)); 1329 ErrorF ("winMultiWindowWMErrorHandler - ERROR: %s\n", pszErrorMsg); 1330 1331 return 0; 1332} 1333 1334 1335/* 1336 * Window manager IO error handler 1337 */ 1338 1339static int 1340winMultiWindowWMIOErrorHandler (Display *pDisplay) 1341{ 1342 ErrorF ("\nwinMultiWindowWMIOErrorHandler!\n\n"); 1343 1344 if (g_shutdown) 1345 pthread_exit(NULL); 1346 1347 /* Restart at the main entry point */ 1348 longjmp (g_jmpWMEntry, WIN_JMP_ERROR_IO); 1349 1350 return 0; 1351} 1352 1353 1354/* 1355 * X message procedure error handler 1356 */ 1357 1358static int 1359winMultiWindowXMsgProcErrorHandler (Display *pDisplay, XErrorEvent *pErr) 1360{ 1361 char pszErrorMsg[100]; 1362 1363 XGetErrorText (pDisplay, 1364 pErr->error_code, 1365 pszErrorMsg, 1366 sizeof (pszErrorMsg)); 1367 ErrorF ("winMultiWindowXMsgProcErrorHandler - ERROR: %s\n", pszErrorMsg); 1368 1369 return 0; 1370} 1371 1372 1373/* 1374 * X message procedure IO error handler 1375 */ 1376 1377static int 1378winMultiWindowXMsgProcIOErrorHandler (Display *pDisplay) 1379{ 1380 ErrorF ("\nwinMultiWindowXMsgProcIOErrorHandler!\n\n"); 1381 1382 /* Restart at the main entry point */ 1383 longjmp (g_jmpXMsgProcEntry, WIN_JMP_ERROR_IO); 1384 1385 return 0; 1386} 1387 1388 1389/* 1390 * Catch RedirectError to detect other window manager running 1391 */ 1392 1393static int 1394winRedirectErrorHandler (Display *pDisplay, XErrorEvent *pErr) 1395{ 1396 redirectError = TRUE; 1397 return 0; 1398} 1399 1400 1401/* 1402 * Check if another window manager is running 1403 */ 1404 1405static Bool 1406CheckAnotherWindowManager (Display *pDisplay, DWORD dwScreen) 1407{ 1408 redirectError = FALSE; 1409 XSetErrorHandler (winRedirectErrorHandler); 1410 XSelectInput(pDisplay, RootWindow (pDisplay, dwScreen), 1411 // SubstructureNotifyMask | ButtonPressMask 1412 ColormapChangeMask | EnterWindowMask | PropertyChangeMask | 1413 SubstructureRedirectMask | KeyPressMask | 1414 ButtonPressMask | ButtonReleaseMask); 1415 XSync (pDisplay, 0); 1416 XSetErrorHandler (winMultiWindowXMsgProcErrorHandler); 1417 XSelectInput(pDisplay, RootWindow (pDisplay, dwScreen), 1418 SubstructureNotifyMask); 1419 XSync (pDisplay, 0); 1420 if (redirectError) 1421 { 1422 //ErrorF ("CheckAnotherWindowManager() - another window manager is running. Exiting.\n"); 1423 return TRUE; 1424 } 1425 else 1426 { 1427 return FALSE; 1428 } 1429} 1430 1431/* 1432 * Notify the MWM thread we're exiting and not to reconnect 1433 */ 1434 1435void 1436winDeinitMultiWindowWM () 1437{ 1438 ErrorF ("winDeinitMultiWindowWM - Noting shutdown in progress\n"); 1439 g_shutdown = TRUE; 1440} 1441