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