winmultiwindowwm.c revision 35c4bbdf
105b261ecSmrg/*
205b261ecSmrg *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
36747b715Smrg *Copyright (C) Colin Harrison 2005-2009
405b261ecSmrg *
505b261ecSmrg *Permission is hereby granted, free of charge, to any person obtaining
605b261ecSmrg * a copy of this software and associated documentation files (the
705b261ecSmrg *"Software"), to deal in the Software without restriction, including
805b261ecSmrg *without limitation the rights to use, copy, modify, merge, publish,
905b261ecSmrg *distribute, sublicense, and/or sell copies of the Software, and to
1005b261ecSmrg *permit persons to whom the Software is furnished to do so, subject to
1105b261ecSmrg *the following conditions:
1205b261ecSmrg *
1305b261ecSmrg *The above copyright notice and this permission notice shall be
1405b261ecSmrg *included in all copies or substantial portions of the Software.
1505b261ecSmrg *
1605b261ecSmrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1705b261ecSmrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1805b261ecSmrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1905b261ecSmrg *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
2005b261ecSmrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
2105b261ecSmrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2205b261ecSmrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2305b261ecSmrg *
2405b261ecSmrg *Except as contained in this notice, the name of the XFree86 Project
2505b261ecSmrg *shall not be used in advertising or otherwise to promote the sale, use
2605b261ecSmrg *or other dealings in this Software without prior written authorization
2705b261ecSmrg *from the XFree86 Project.
2805b261ecSmrg *
2905b261ecSmrg * Authors:	Kensuke Matsuzaki
306747b715Smrg *              Colin Harrison
3105b261ecSmrg */
3205b261ecSmrg
3305b261ecSmrg/* X headers */
3405b261ecSmrg#ifdef HAVE_XWIN_CONFIG_H
3505b261ecSmrg#include <xwin-config.h>
3605b261ecSmrg#endif
3705b261ecSmrg#include <stdio.h>
3805b261ecSmrg#include <stdlib.h>
3905b261ecSmrg#include <unistd.h>
4005b261ecSmrg#ifdef __CYGWIN__
4105b261ecSmrg#include <sys/select.h>
4205b261ecSmrg#endif
4305b261ecSmrg#include <fcntl.h>
4405b261ecSmrg#include <setjmp.h>
4505b261ecSmrg#define HANDLE void *
4605b261ecSmrg#include <pthread.h>
4705b261ecSmrg#undef HANDLE
4805b261ecSmrg#include <X11/X.h>
4905b261ecSmrg#include <X11/Xatom.h>
5005b261ecSmrg#include <X11/Xlib.h>
5105b261ecSmrg#include <X11/Xlocale.h>
5205b261ecSmrg#include <X11/Xproto.h>
5305b261ecSmrg#include <X11/Xutil.h>
5405b261ecSmrg#include <X11/cursorfont.h>
556747b715Smrg#include <X11/Xwindows.h>
5605b261ecSmrg
5705b261ecSmrg/* Local headers */
5805b261ecSmrg#include "winwindow.h"
596747b715Smrg#include "winprefs.h"
606747b715Smrg#include "window.h"
616747b715Smrg#include "pixmapstr.h"
626747b715Smrg#include "windowstr.h"
6335c4bbdfSmrg#include "winglobals.h"
6435c4bbdfSmrg#include "windisplay.h"
656747b715Smrg
6605b261ecSmrg#ifdef XWIN_MULTIWINDOWEXTWM
676747b715Smrg#include <X11/extensions/windowswmstr.h>
686747b715Smrg#else
696747b715Smrg/* We need the native HWND atom for intWM, so for consistency use the
706747b715Smrg   same name as extWM would if we were building with enabled... */
716747b715Smrg#define WINDOWSWM_NATIVE_HWND "_WINDOWSWM_NATIVE_HWND"
7205b261ecSmrg#endif
7305b261ecSmrg
7435c4bbdfSmrg#ifndef HOST_NAME_MAX
7535c4bbdfSmrg#define HOST_NAME_MAX 255
7635c4bbdfSmrg#endif
7735c4bbdfSmrg
7805b261ecSmrgextern void winDebug(const char *format, ...);
796747b715Smrgextern void winReshapeMultiWindow(WindowPtr pWin);
806747b715Smrgextern void winUpdateRgnMultiWindow(WindowPtr pWin);
8105b261ecSmrg
8205b261ecSmrg#ifndef CYGDEBUG
8305b261ecSmrg#define CYGDEBUG NO
8405b261ecSmrg#endif
8505b261ecSmrg
8605b261ecSmrg/*
8705b261ecSmrg * Constant defines
8805b261ecSmrg */
8905b261ecSmrg
9005b261ecSmrg#define WIN_CONNECT_RETRIES	5
9105b261ecSmrg#define WIN_CONNECT_DELAY	5
9205b261ecSmrg#ifdef HAS_DEVWINDOWS
9335c4bbdfSmrg#define WIN_MSG_QUEUE_FNAME	"/dev/windows"
9405b261ecSmrg#endif
9505b261ecSmrg#define WIN_JMP_OKAY		0
9605b261ecSmrg#define WIN_JMP_ERROR_IO	2
9705b261ecSmrg
9805b261ecSmrg/*
9905b261ecSmrg * Local structures
10005b261ecSmrg */
10105b261ecSmrg
10205b261ecSmrgtypedef struct _WMMsgNodeRec {
10335c4bbdfSmrg    winWMMessageRec msg;
10435c4bbdfSmrg    struct _WMMsgNodeRec *pNext;
10505b261ecSmrg} WMMsgNodeRec, *WMMsgNodePtr;
10605b261ecSmrg
10705b261ecSmrgtypedef struct _WMMsgQueueRec {
10835c4bbdfSmrg    struct _WMMsgNodeRec *pHead;
10935c4bbdfSmrg    struct _WMMsgNodeRec *pTail;
11035c4bbdfSmrg    pthread_mutex_t pmMutex;
11135c4bbdfSmrg    pthread_cond_t pcNotEmpty;
11235c4bbdfSmrg    int nQueueSize;
11305b261ecSmrg} WMMsgQueueRec, *WMMsgQueuePtr;
11405b261ecSmrg
11505b261ecSmrgtypedef struct _WMInfo {
11635c4bbdfSmrg    Display *pDisplay;
11735c4bbdfSmrg    WMMsgQueueRec wmMsgQueue;
11835c4bbdfSmrg    Atom atmWmProtos;
11935c4bbdfSmrg    Atom atmWmDelete;
12035c4bbdfSmrg    Atom atmWmTakeFocus;
12135c4bbdfSmrg    Atom atmPrivMap;
12235c4bbdfSmrg    Bool fAllowOtherWM;
12305b261ecSmrg} WMInfoRec, *WMInfoPtr;
12405b261ecSmrg
12505b261ecSmrgtypedef struct _WMProcArgRec {
12635c4bbdfSmrg    DWORD dwScreen;
12735c4bbdfSmrg    WMInfoPtr pWMInfo;
12835c4bbdfSmrg    pthread_mutex_t *ppmServerStarted;
12905b261ecSmrg} WMProcArgRec, *WMProcArgPtr;
13005b261ecSmrg
13105b261ecSmrgtypedef struct _XMsgProcArgRec {
13235c4bbdfSmrg    Display *pDisplay;
13335c4bbdfSmrg    DWORD dwScreen;
13435c4bbdfSmrg    WMInfoPtr pWMInfo;
13535c4bbdfSmrg    pthread_mutex_t *ppmServerStarted;
13635c4bbdfSmrg    HWND hwndScreen;
13705b261ecSmrg} XMsgProcArgRec, *XMsgProcArgPtr;
13805b261ecSmrg
13905b261ecSmrg/*
14005b261ecSmrg * Prototypes for local functions
14105b261ecSmrg */
14205b261ecSmrg
14305b261ecSmrgstatic void
14435c4bbdfSmrg PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode);
14505b261ecSmrg
14635c4bbdfSmrgstatic WMMsgNodePtr PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo);
14705b261ecSmrg
14805b261ecSmrgstatic Bool
14935c4bbdfSmrg InitQueue(WMMsgQueuePtr pQueue);
15005b261ecSmrg
15105b261ecSmrgstatic void
15235c4bbdfSmrg GetWindowName(Display * pDpy, Window iWin, char **ppWindowName);
15305b261ecSmrg
15405b261ecSmrgstatic int
15535c4bbdfSmrg SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData);
15605b261ecSmrg
15705b261ecSmrgstatic void
15835c4bbdfSmrg UpdateName(WMInfoPtr pWMInfo, Window iWindow);
15905b261ecSmrg
16035c4bbdfSmrgstatic void *winMultiWindowWMProc(void *pArg);
16105b261ecSmrg
16205b261ecSmrgstatic int
16335c4bbdfSmrg winMultiWindowWMErrorHandler(Display * pDisplay, XErrorEvent * pErr);
16405b261ecSmrg
16505b261ecSmrgstatic int
16635c4bbdfSmrg winMultiWindowWMIOErrorHandler(Display * pDisplay);
16705b261ecSmrg
16835c4bbdfSmrgstatic void *winMultiWindowXMsgProc(void *pArg);
16905b261ecSmrg
17005b261ecSmrgstatic int
17135c4bbdfSmrg winMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr);
17205b261ecSmrg
17305b261ecSmrgstatic int
17435c4bbdfSmrg winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay);
17505b261ecSmrg
17605b261ecSmrgstatic int
17735c4bbdfSmrg winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr);
17805b261ecSmrg
17905b261ecSmrgstatic void
18035c4bbdfSmrg winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg);
18105b261ecSmrg
18205b261ecSmrg#if 0
18305b261ecSmrgstatic void
18435c4bbdfSmrg PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction);
18505b261ecSmrg#endif
18605b261ecSmrg
18705b261ecSmrgstatic Bool
18835c4bbdfSmrg
18935c4bbdfSmrgCheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen,
19035c4bbdfSmrg                          Bool fAllowOtherWM);
19105b261ecSmrg
1926747b715Smrgstatic void
19335c4bbdfSmrg winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle);
1946747b715Smrg
1956747b715Smrgvoid
19635c4bbdfSmrg winUpdateWindowPosition(HWND hWnd, HWND * zstyle);
19705b261ecSmrg
19805b261ecSmrg/*
19905b261ecSmrg * Local globals
20005b261ecSmrg */
20105b261ecSmrg
20235c4bbdfSmrgstatic jmp_buf g_jmpWMEntry;
20335c4bbdfSmrgstatic XIOErrorHandler g_winMultiWindowWMOldIOErrorHandler;
20435c4bbdfSmrgstatic pthread_t g_winMultiWindowWMThread;
20535c4bbdfSmrgstatic jmp_buf g_jmpXMsgProcEntry;
20635c4bbdfSmrgstatic XIOErrorHandler g_winMultiWindowXMsgProcOldIOErrorHandler;
20735c4bbdfSmrgstatic pthread_t g_winMultiWindowXMsgProcThread;
20835c4bbdfSmrgstatic Bool g_shutdown = FALSE;
20935c4bbdfSmrgstatic Bool redirectError = FALSE;
21035c4bbdfSmrgstatic Bool g_fAnotherWMRunning = FALSE;
21105b261ecSmrg
21205b261ecSmrg/*
21305b261ecSmrg * PushMessage - Push a message onto the queue
21405b261ecSmrg */
21505b261ecSmrg
21605b261ecSmrgstatic void
21735c4bbdfSmrgPushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode)
21805b261ecSmrg{
21905b261ecSmrg
22035c4bbdfSmrg    /* Lock the queue mutex */
22135c4bbdfSmrg    pthread_mutex_lock(&pQueue->pmMutex);
22205b261ecSmrg
22335c4bbdfSmrg    pNode->pNext = NULL;
22435c4bbdfSmrg
22535c4bbdfSmrg    if (pQueue->pTail != NULL) {
22635c4bbdfSmrg        pQueue->pTail->pNext = pNode;
22705b261ecSmrg    }
22835c4bbdfSmrg    pQueue->pTail = pNode;
22905b261ecSmrg
23035c4bbdfSmrg    if (pQueue->pHead == NULL) {
23135c4bbdfSmrg        pQueue->pHead = pNode;
23235c4bbdfSmrg    }
23305b261ecSmrg
23405b261ecSmrg#if 0
23535c4bbdfSmrg    switch (pNode->msg.msg) {
23605b261ecSmrg    case WM_WM_MOVE:
23735c4bbdfSmrg        ErrorF("\tWM_WM_MOVE\n");
23835c4bbdfSmrg        break;
23905b261ecSmrg    case WM_WM_SIZE:
24035c4bbdfSmrg        ErrorF("\tWM_WM_SIZE\n");
24135c4bbdfSmrg        break;
24205b261ecSmrg    case WM_WM_RAISE:
24335c4bbdfSmrg        ErrorF("\tWM_WM_RAISE\n");
24435c4bbdfSmrg        break;
24505b261ecSmrg    case WM_WM_LOWER:
24635c4bbdfSmrg        ErrorF("\tWM_WM_LOWER\n");
24735c4bbdfSmrg        break;
24805b261ecSmrg    case WM_WM_MAP:
24935c4bbdfSmrg        ErrorF("\tWM_WM_MAP\n");
25035c4bbdfSmrg        break;
2516747b715Smrg    case WM_WM_MAP2:
25235c4bbdfSmrg        ErrorF("\tWM_WM_MAP2\n");
25335c4bbdfSmrg        break;
2546747b715Smrg    case WM_WM_MAP3:
25535c4bbdfSmrg        ErrorF("\tWM_WM_MAP3\n");
25635c4bbdfSmrg        break;
25705b261ecSmrg    case WM_WM_UNMAP:
25835c4bbdfSmrg        ErrorF("\tWM_WM_UNMAP\n");
25935c4bbdfSmrg        break;
26005b261ecSmrg    case WM_WM_KILL:
26135c4bbdfSmrg        ErrorF("\tWM_WM_KILL\n");
26235c4bbdfSmrg        break;
26305b261ecSmrg    case WM_WM_ACTIVATE:
26435c4bbdfSmrg        ErrorF("\tWM_WM_ACTIVATE\n");
26535c4bbdfSmrg        break;
26605b261ecSmrg    default:
26735c4bbdfSmrg        ErrorF("\tUnknown Message.\n");
26835c4bbdfSmrg        break;
26905b261ecSmrg    }
27005b261ecSmrg#endif
27105b261ecSmrg
27235c4bbdfSmrg    /* Increase the count of elements in the queue by one */
27335c4bbdfSmrg    ++(pQueue->nQueueSize);
27405b261ecSmrg
27535c4bbdfSmrg    /* Release the queue mutex */
27635c4bbdfSmrg    pthread_mutex_unlock(&pQueue->pmMutex);
27705b261ecSmrg
27835c4bbdfSmrg    /* Signal that the queue is not empty */
27935c4bbdfSmrg    pthread_cond_signal(&pQueue->pcNotEmpty);
28005b261ecSmrg}
28105b261ecSmrg
28205b261ecSmrg#if CYGMULTIWINDOW_DEBUG
28305b261ecSmrg/*
28405b261ecSmrg * QueueSize - Return the size of the queue
28505b261ecSmrg */
28605b261ecSmrg
28705b261ecSmrgstatic int
28835c4bbdfSmrgQueueSize(WMMsgQueuePtr pQueue)
28905b261ecSmrg{
29035c4bbdfSmrg    WMMsgNodePtr pNode;
29135c4bbdfSmrg    int nSize = 0;
29235c4bbdfSmrg
29335c4bbdfSmrg    /* Loop through all elements in the queue */
29435c4bbdfSmrg    for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext)
29535c4bbdfSmrg        ++nSize;
29635c4bbdfSmrg
29735c4bbdfSmrg    return nSize;
29805b261ecSmrg}
29905b261ecSmrg#endif
30005b261ecSmrg
30105b261ecSmrg/*
30205b261ecSmrg * PopMessage - Pop a message from the queue
30305b261ecSmrg */
30405b261ecSmrg
30505b261ecSmrgstatic WMMsgNodePtr
30635c4bbdfSmrgPopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo)
30705b261ecSmrg{
30835c4bbdfSmrg    WMMsgNodePtr pNode;
30905b261ecSmrg
31035c4bbdfSmrg    /* Lock the queue mutex */
31135c4bbdfSmrg    pthread_mutex_lock(&pQueue->pmMutex);
31205b261ecSmrg
31335c4bbdfSmrg    /* Wait for --- */
31435c4bbdfSmrg    while (pQueue->pHead == NULL) {
31535c4bbdfSmrg        pthread_cond_wait(&pQueue->pcNotEmpty, &pQueue->pmMutex);
31605b261ecSmrg    }
31735c4bbdfSmrg
31835c4bbdfSmrg    pNode = pQueue->pHead;
31935c4bbdfSmrg    if (pQueue->pHead != NULL) {
32035c4bbdfSmrg        pQueue->pHead = pQueue->pHead->pNext;
32105b261ecSmrg    }
32205b261ecSmrg
32335c4bbdfSmrg    if (pQueue->pTail == pNode) {
32435c4bbdfSmrg        pQueue->pTail = NULL;
32505b261ecSmrg    }
32605b261ecSmrg
32735c4bbdfSmrg    /* Drop the number of elements in the queue by one */
32835c4bbdfSmrg    --(pQueue->nQueueSize);
32905b261ecSmrg
33005b261ecSmrg#if CYGMULTIWINDOW_DEBUG
33135c4bbdfSmrg    ErrorF("Queue Size %d %d\n", pQueue->nQueueSize, QueueSize(pQueue));
33205b261ecSmrg#endif
33305b261ecSmrg
33435c4bbdfSmrg    /* Release the queue mutex */
33535c4bbdfSmrg    pthread_mutex_unlock(&pQueue->pmMutex);
33605b261ecSmrg
33735c4bbdfSmrg    return pNode;
33835c4bbdfSmrg}
33905b261ecSmrg
34005b261ecSmrg#if 0
34105b261ecSmrg/*
34235c4bbdfSmrg * HaveMessage -
34305b261ecSmrg */
34405b261ecSmrg
34505b261ecSmrgstatic Bool
34635c4bbdfSmrgHaveMessage(WMMsgQueuePtr pQueue, UINT msg, Window iWindow)
34705b261ecSmrg{
34835c4bbdfSmrg    WMMsgNodePtr pNode;
34935c4bbdfSmrg
35035c4bbdfSmrg    for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) {
35135c4bbdfSmrg        if (pNode->msg.msg == msg && pNode->msg.iWindow == iWindow)
35235c4bbdfSmrg            return True;
35305b261ecSmrg    }
35435c4bbdfSmrg
35535c4bbdfSmrg    return False;
35605b261ecSmrg}
35705b261ecSmrg#endif
35805b261ecSmrg
35905b261ecSmrg/*
36005b261ecSmrg * InitQueue - Initialize the Window Manager message queue
36105b261ecSmrg */
36205b261ecSmrg
36305b261ecSmrgstatic
36435c4bbdfSmrg    Bool
36535c4bbdfSmrgInitQueue(WMMsgQueuePtr pQueue)
36605b261ecSmrg{
36735c4bbdfSmrg    /* Check if the pQueue pointer is NULL */
36835c4bbdfSmrg    if (pQueue == NULL) {
36935c4bbdfSmrg        ErrorF("InitQueue - pQueue is NULL.  Exiting.\n");
37035c4bbdfSmrg        return FALSE;
37105b261ecSmrg    }
37205b261ecSmrg
37335c4bbdfSmrg    /* Set the head and tail to NULL */
37435c4bbdfSmrg    pQueue->pHead = NULL;
37535c4bbdfSmrg    pQueue->pTail = NULL;
37605b261ecSmrg
37735c4bbdfSmrg    /* There are no elements initially */
37835c4bbdfSmrg    pQueue->nQueueSize = 0;
37905b261ecSmrg
38005b261ecSmrg#if CYGMULTIWINDOW_DEBUG
38135c4bbdfSmrg    winDebug("InitQueue - Queue Size %d %d\n", pQueue->nQueueSize,
38235c4bbdfSmrg             QueueSize(pQueue));
38305b261ecSmrg#endif
38405b261ecSmrg
38535c4bbdfSmrg    winDebug("InitQueue - Calling pthread_mutex_init\n");
38605b261ecSmrg
38735c4bbdfSmrg    /* Create synchronization objects */
38835c4bbdfSmrg    pthread_mutex_init(&pQueue->pmMutex, NULL);
38905b261ecSmrg
39035c4bbdfSmrg    winDebug("InitQueue - pthread_mutex_init returned\n");
39135c4bbdfSmrg    winDebug("InitQueue - Calling pthread_cond_init\n");
39205b261ecSmrg
39335c4bbdfSmrg    pthread_cond_init(&pQueue->pcNotEmpty, NULL);
39405b261ecSmrg
39535c4bbdfSmrg    winDebug("InitQueue - pthread_cond_init returned\n");
39605b261ecSmrg
39735c4bbdfSmrg    return TRUE;
39805b261ecSmrg}
39905b261ecSmrg
40035c4bbdfSmrgstatic
40135c4bbdfSmrgchar *
40235c4bbdfSmrgXutf8TextPropertyToString(Display * pDisplay, XTextProperty * xtp)
40335c4bbdfSmrg{
40435c4bbdfSmrg    int nNum;
40535c4bbdfSmrg    char **ppList;
40635c4bbdfSmrg    char *pszReturnData;
40735c4bbdfSmrg
40835c4bbdfSmrg    if (Xutf8TextPropertyToTextList(pDisplay, xtp, &ppList, &nNum) >= Success &&
40935c4bbdfSmrg        nNum > 0 && *ppList) {
41035c4bbdfSmrg        int i;
41135c4bbdfSmrg        int iLen = 0;
41235c4bbdfSmrg
41335c4bbdfSmrg        for (i = 0; i < nNum; i++)
41435c4bbdfSmrg            iLen += strlen(ppList[i]);
41535c4bbdfSmrg        pszReturnData = malloc(iLen + 1);
41635c4bbdfSmrg        pszReturnData[0] = '\0';
41735c4bbdfSmrg        for (i = 0; i < nNum; i++)
41835c4bbdfSmrg            strcat(pszReturnData, ppList[i]);
41935c4bbdfSmrg        if (ppList)
42035c4bbdfSmrg            XFreeStringList(ppList);
42135c4bbdfSmrg    }
42235c4bbdfSmrg    else {
42335c4bbdfSmrg        pszReturnData = malloc(1);
42435c4bbdfSmrg        pszReturnData[0] = '\0';
42535c4bbdfSmrg    }
42635c4bbdfSmrg
42735c4bbdfSmrg    return pszReturnData;
42835c4bbdfSmrg}
42905b261ecSmrg
43005b261ecSmrg/*
43105b261ecSmrg * GetWindowName - Retrieve the title of an X Window
43205b261ecSmrg */
43305b261ecSmrg
43405b261ecSmrgstatic void
43535c4bbdfSmrgGetWindowName(Display * pDisplay, Window iWin, char **ppWindowName)
43605b261ecSmrg{
43735c4bbdfSmrg    int nResult;
43835c4bbdfSmrg    XTextProperty xtpWindowName;
43935c4bbdfSmrg    XTextProperty xtpClientMachine;
44035c4bbdfSmrg    char *pszWindowName;
44135c4bbdfSmrg    char *pszClientMachine;
44235c4bbdfSmrg    char hostname[HOST_NAME_MAX + 1];
44335c4bbdfSmrg
44405b261ecSmrg#if CYGMULTIWINDOW_DEBUG
44535c4bbdfSmrg    ErrorF("GetWindowName\n");
44605b261ecSmrg#endif
44705b261ecSmrg
44835c4bbdfSmrg    /* Intialize ppWindowName to NULL */
44935c4bbdfSmrg    *ppWindowName = NULL;
45005b261ecSmrg
45135c4bbdfSmrg    /* Try to get window name */
45235c4bbdfSmrg    nResult = XGetWMName(pDisplay, iWin, &xtpWindowName);
45335c4bbdfSmrg    if (!nResult || !xtpWindowName.value || !xtpWindowName.nitems) {
45405b261ecSmrg#if CYGMULTIWINDOW_DEBUG
45535c4bbdfSmrg        ErrorF("GetWindowName - XGetWMName failed.  No name.\n");
45605b261ecSmrg#endif
45735c4bbdfSmrg        return;
45805b261ecSmrg    }
45905b261ecSmrg
46035c4bbdfSmrg    pszWindowName = Xutf8TextPropertyToString(pDisplay, &xtpWindowName);
46135c4bbdfSmrg    XFree(xtpWindowName.value);
46235c4bbdfSmrg
46335c4bbdfSmrg    if (g_fHostInTitle) {
46435c4bbdfSmrg        /* Try to get client machine name */
46535c4bbdfSmrg        nResult = XGetWMClientMachine(pDisplay, iWin, &xtpClientMachine);
46635c4bbdfSmrg        if (nResult && xtpClientMachine.value && xtpClientMachine.nitems) {
46735c4bbdfSmrg            pszClientMachine =
46835c4bbdfSmrg                Xutf8TextPropertyToString(pDisplay, &xtpClientMachine);
46935c4bbdfSmrg            XFree(xtpClientMachine.value);
47035c4bbdfSmrg
47135c4bbdfSmrg            /*
47235c4bbdfSmrg               If we have a client machine name
47335c4bbdfSmrg               and it's not the local host name
47435c4bbdfSmrg               and it's not already in the window title...
47535c4bbdfSmrg             */
47635c4bbdfSmrg            if (strlen(pszClientMachine) &&
47735c4bbdfSmrg                !gethostname(hostname, HOST_NAME_MAX + 1) &&
47835c4bbdfSmrg                strcmp(hostname, pszClientMachine) &&
47935c4bbdfSmrg                (strstr(pszWindowName, pszClientMachine) == 0)) {
48035c4bbdfSmrg                /* ... add '@<clientmachine>' to end of window name */
48135c4bbdfSmrg                *ppWindowName =
48235c4bbdfSmrg                    malloc(strlen(pszWindowName) +
48335c4bbdfSmrg                           strlen(pszClientMachine) + 2);
48435c4bbdfSmrg                strcpy(*ppWindowName, pszWindowName);
48535c4bbdfSmrg                strcat(*ppWindowName, "@");
48635c4bbdfSmrg                strcat(*ppWindowName, pszClientMachine);
48735c4bbdfSmrg
48835c4bbdfSmrg                free(pszWindowName);
48935c4bbdfSmrg                free(pszClientMachine);
49035c4bbdfSmrg
49135c4bbdfSmrg                return;
49235c4bbdfSmrg            }
49335c4bbdfSmrg        }
49435c4bbdfSmrg    }
49505b261ecSmrg
49635c4bbdfSmrg    /* otherwise just return the window name */
49735c4bbdfSmrg    *ppWindowName = pszWindowName;
49805b261ecSmrg}
49905b261ecSmrg
50035c4bbdfSmrg/*
50135c4bbdfSmrg * Does the client support the specified WM_PROTOCOLS protocol?
50235c4bbdfSmrg */
50335c4bbdfSmrg
50435c4bbdfSmrgstatic Bool
50535c4bbdfSmrgIsWmProtocolAvailable(Display * pDisplay, Window iWindow, Atom atmProtocol)
50635c4bbdfSmrg{
50735c4bbdfSmrg  int i, n, found = 0;
50835c4bbdfSmrg  Atom *protocols;
50935c4bbdfSmrg
51035c4bbdfSmrg  if (XGetWMProtocols(pDisplay, iWindow, &protocols, &n)) {
51135c4bbdfSmrg    for (i = 0; i < n; ++i)
51235c4bbdfSmrg      if (protocols[i] == atmProtocol)
51335c4bbdfSmrg        ++found;
51435c4bbdfSmrg
51535c4bbdfSmrg    XFree(protocols);
51635c4bbdfSmrg  }
51735c4bbdfSmrg
51835c4bbdfSmrg  return found > 0;
51935c4bbdfSmrg}
52005b261ecSmrg
52105b261ecSmrg/*
52205b261ecSmrg * Send a message to the X server from the WM thread
52305b261ecSmrg */
52405b261ecSmrg
52505b261ecSmrgstatic int
52635c4bbdfSmrgSendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData)
52705b261ecSmrg{
52835c4bbdfSmrg    XEvent e;
52935c4bbdfSmrg
53035c4bbdfSmrg    /* Prepare the X event structure */
53135c4bbdfSmrg    e.type = ClientMessage;
53235c4bbdfSmrg    e.xclient.window = iWin;
53335c4bbdfSmrg    e.xclient.message_type = atmType;
53435c4bbdfSmrg    e.xclient.format = 32;
53535c4bbdfSmrg    e.xclient.data.l[0] = nData;
53635c4bbdfSmrg    e.xclient.data.l[1] = CurrentTime;
53735c4bbdfSmrg
53835c4bbdfSmrg    /* Send the event to X */
53935c4bbdfSmrg    return XSendEvent(pDisplay, iWin, False, NoEventMask, &e);
54005b261ecSmrg}
54105b261ecSmrg
54235c4bbdfSmrg/*
54335c4bbdfSmrg * See if we can get the stored HWND for this window...
54435c4bbdfSmrg */
54535c4bbdfSmrgstatic HWND
54635c4bbdfSmrggetHwnd(WMInfoPtr pWMInfo, Window iWindow)
54735c4bbdfSmrg{
54835c4bbdfSmrg    Atom atmType;
54935c4bbdfSmrg    int fmtRet;
55035c4bbdfSmrg    unsigned long items, remain;
55135c4bbdfSmrg    HWND *retHwnd, hWnd = NULL;
55235c4bbdfSmrg
55335c4bbdfSmrg    if (XGetWindowProperty(pWMInfo->pDisplay,
55435c4bbdfSmrg                           iWindow,
55535c4bbdfSmrg                           pWMInfo->atmPrivMap,
55635c4bbdfSmrg                           0,
55735c4bbdfSmrg                           sizeof(HWND)/4,
55835c4bbdfSmrg                           False,
55935c4bbdfSmrg                           XA_INTEGER,
56035c4bbdfSmrg                           &atmType,
56135c4bbdfSmrg                           &fmtRet,
56235c4bbdfSmrg                           &items,
56335c4bbdfSmrg                           &remain, (unsigned char **) &retHwnd) == Success) {
56435c4bbdfSmrg        if (retHwnd) {
56535c4bbdfSmrg            hWnd = *retHwnd;
56635c4bbdfSmrg            XFree(retHwnd);
56735c4bbdfSmrg        }
56835c4bbdfSmrg    }
56935c4bbdfSmrg
57035c4bbdfSmrg    /* Some sanity checks */
57135c4bbdfSmrg    if (!hWnd)
57235c4bbdfSmrg        return NULL;
57335c4bbdfSmrg    if (!IsWindow(hWnd))
57435c4bbdfSmrg        return NULL;
57535c4bbdfSmrg
57635c4bbdfSmrg    return hWnd;
57735c4bbdfSmrg}
57805b261ecSmrg
57905b261ecSmrg/*
58005b261ecSmrg * Updates the name of a HWND according to its X WM_NAME property
58105b261ecSmrg */
58205b261ecSmrg
58305b261ecSmrgstatic void
58435c4bbdfSmrgUpdateName(WMInfoPtr pWMInfo, Window iWindow)
58505b261ecSmrg{
58635c4bbdfSmrg    HWND hWnd;
58735c4bbdfSmrg    XWindowAttributes attr;
58835c4bbdfSmrg
58935c4bbdfSmrg    hWnd = getHwnd(pWMInfo, iWindow);
59035c4bbdfSmrg    if (!hWnd)
59135c4bbdfSmrg        return;
59235c4bbdfSmrg
59335c4bbdfSmrg    /* If window isn't override-redirect */
59435c4bbdfSmrg    XGetWindowAttributes(pWMInfo->pDisplay, iWindow, &attr);
59535c4bbdfSmrg    if (!attr.override_redirect) {
59635c4bbdfSmrg        char *pszWindowName;
59735c4bbdfSmrg
59835c4bbdfSmrg        /* Get the X windows window name */
59935c4bbdfSmrg        GetWindowName(pWMInfo->pDisplay, iWindow, &pszWindowName);
60035c4bbdfSmrg
60135c4bbdfSmrg        if (pszWindowName) {
60235c4bbdfSmrg            /* Convert from UTF-8 to wide char */
60335c4bbdfSmrg            int iLen =
60435c4bbdfSmrg                MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1, NULL, 0);
60535c4bbdfSmrg            wchar_t *pwszWideWindowName =
60635c4bbdfSmrg                malloc(sizeof(wchar_t)*(iLen + 1));
60735c4bbdfSmrg            MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1,
60835c4bbdfSmrg                                pwszWideWindowName, iLen);
60935c4bbdfSmrg
61035c4bbdfSmrg            /* Set the Windows window name */
61135c4bbdfSmrg            SetWindowTextW(hWnd, pwszWideWindowName);
61235c4bbdfSmrg
61335c4bbdfSmrg            free(pwszWideWindowName);
61435c4bbdfSmrg            free(pszWindowName);
61535c4bbdfSmrg        }
61605b261ecSmrg    }
61735c4bbdfSmrg}
61835c4bbdfSmrg
61935c4bbdfSmrg/*
62035c4bbdfSmrg * Updates the icon of a HWND according to its X icon properties
62135c4bbdfSmrg */
62235c4bbdfSmrg
62335c4bbdfSmrgstatic void
62435c4bbdfSmrgUpdateIcon(WMInfoPtr pWMInfo, Window iWindow)
62535c4bbdfSmrg{
62635c4bbdfSmrg    HWND hWnd;
62735c4bbdfSmrg    HICON hIconNew = NULL;
62835c4bbdfSmrg    XWindowAttributes attr;
62935c4bbdfSmrg
63035c4bbdfSmrg    hWnd = getHwnd(pWMInfo, iWindow);
63135c4bbdfSmrg    if (!hWnd)
63235c4bbdfSmrg        return;
63335c4bbdfSmrg
63435c4bbdfSmrg    /* If window isn't override-redirect */
63535c4bbdfSmrg    XGetWindowAttributes(pWMInfo->pDisplay, iWindow, &attr);
63635c4bbdfSmrg    if (!attr.override_redirect) {
63735c4bbdfSmrg        XClassHint class_hint = { 0, 0 };
63835c4bbdfSmrg        char *window_name = 0;
63935c4bbdfSmrg
64035c4bbdfSmrg        if (XGetClassHint(pWMInfo->pDisplay, iWindow, &class_hint)) {
64135c4bbdfSmrg            XFetchName(pWMInfo->pDisplay, iWindow, &window_name);
64235c4bbdfSmrg
64335c4bbdfSmrg            hIconNew =
64435c4bbdfSmrg                (HICON) winOverrideIcon(class_hint.res_name,
64535c4bbdfSmrg                                        class_hint.res_class, window_name);
64635c4bbdfSmrg
64735c4bbdfSmrg            if (class_hint.res_name)
64835c4bbdfSmrg                XFree(class_hint.res_name);
64935c4bbdfSmrg            if (class_hint.res_class)
65035c4bbdfSmrg                XFree(class_hint.res_class);
65135c4bbdfSmrg            if (window_name)
65235c4bbdfSmrg                XFree(window_name);
65335c4bbdfSmrg        }
65405b261ecSmrg    }
65535c4bbdfSmrg
65635c4bbdfSmrg    winUpdateIcon(hWnd, pWMInfo->pDisplay, iWindow, hIconNew);
65705b261ecSmrg}
65805b261ecSmrg
65935c4bbdfSmrg/*
66035c4bbdfSmrg * Updates the style of a HWND according to its X style properties
66135c4bbdfSmrg */
66235c4bbdfSmrg
66335c4bbdfSmrgstatic void
66435c4bbdfSmrgUpdateStyle(WMInfoPtr pWMInfo, Window iWindow)
66535c4bbdfSmrg{
66635c4bbdfSmrg    HWND hWnd;
66735c4bbdfSmrg    HWND zstyle = HWND_NOTOPMOST;
66835c4bbdfSmrg    UINT flags;
66935c4bbdfSmrg
67035c4bbdfSmrg    hWnd = getHwnd(pWMInfo, iWindow);
67135c4bbdfSmrg    if (!hWnd)
67235c4bbdfSmrg        return;
67335c4bbdfSmrg
67435c4bbdfSmrg    /* Determine the Window style, which determines borders and clipping region... */
67535c4bbdfSmrg    winApplyHints(pWMInfo->pDisplay, iWindow, hWnd, &zstyle);
67635c4bbdfSmrg    winUpdateWindowPosition(hWnd, &zstyle);
67735c4bbdfSmrg
67835c4bbdfSmrg    /* Apply the updated window style, without changing it's show or activation state */
67935c4bbdfSmrg    flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE;
68035c4bbdfSmrg    if (zstyle == HWND_NOTOPMOST)
68135c4bbdfSmrg        flags |= SWP_NOZORDER | SWP_NOOWNERZORDER;
68235c4bbdfSmrg    SetWindowPos(hWnd, NULL, 0, 0, 0, 0, flags);
68335c4bbdfSmrg
68435c4bbdfSmrg    /*
68535c4bbdfSmrg       Use the WS_EX_TOOLWINDOW style to remove window from Alt-Tab window switcher
68635c4bbdfSmrg
68735c4bbdfSmrg       According to MSDN, this is supposed to remove the window from the taskbar as well,
68835c4bbdfSmrg       if we SW_HIDE before changing the style followed by SW_SHOW afterwards.
68935c4bbdfSmrg
69035c4bbdfSmrg       But that doesn't seem to work reliably, and causes the window to flicker, so use
69135c4bbdfSmrg       the iTaskbarList interface to tell the taskbar to show or hide this window.
69235c4bbdfSmrg     */
69335c4bbdfSmrg    winShowWindowOnTaskbar(hWnd,
69435c4bbdfSmrg                           (GetWindowLongPtr(hWnd, GWL_EXSTYLE) &
69535c4bbdfSmrg                            WS_EX_APPWINDOW) ? TRUE : FALSE);
69635c4bbdfSmrg}
69705b261ecSmrg
69805b261ecSmrg#if 0
69905b261ecSmrg/*
70005b261ecSmrg * Fix up any differences between the X11 and Win32 window stacks
70105b261ecSmrg * starting at the window passed in
70205b261ecSmrg */
70305b261ecSmrgstatic void
70405b261ecSmrgPreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction)
70505b261ecSmrg{
70635c4bbdfSmrg    HWND hWnd;
70735c4bbdfSmrg    DWORD myWinProcID, winProcID;
70835c4bbdfSmrg    Window xWindow;
70935c4bbdfSmrg    WINDOWPLACEMENT wndPlace;
71035c4bbdfSmrg
71135c4bbdfSmrg    hWnd = getHwnd(pWMInfo, iWindow);
71235c4bbdfSmrg    if (!hWnd)
71335c4bbdfSmrg        return;
71435c4bbdfSmrg
71535c4bbdfSmrg    GetWindowThreadProcessId(hWnd, &myWinProcID);
71605b261ecSmrg    hWnd = GetNextWindow(hWnd, direction);
71705b261ecSmrg
71835c4bbdfSmrg    while (hWnd) {
71935c4bbdfSmrg        GetWindowThreadProcessId(hWnd, &winProcID);
72035c4bbdfSmrg        if (winProcID == myWinProcID) {
72135c4bbdfSmrg            wndPlace.length = sizeof(WINDOWPLACEMENT);
72235c4bbdfSmrg            GetWindowPlacement(hWnd, &wndPlace);
72335c4bbdfSmrg            if (!(wndPlace.showCmd == SW_HIDE ||
72435c4bbdfSmrg                  wndPlace.showCmd == SW_MINIMIZE)) {
72535c4bbdfSmrg                xWindow = (Window) GetProp(hWnd, WIN_WID_PROP);
72635c4bbdfSmrg                if (xWindow) {
72735c4bbdfSmrg                    if (direction == GW_HWNDPREV)
72835c4bbdfSmrg                        XRaiseWindow(pWMInfo->pDisplay, xWindow);
72935c4bbdfSmrg                    else
73035c4bbdfSmrg                        XLowerWindow(pWMInfo->pDisplay, xWindow);
73135c4bbdfSmrg                }
73235c4bbdfSmrg            }
73335c4bbdfSmrg        }
73435c4bbdfSmrg        hWnd = GetNextWindow(hWnd, direction);
73535c4bbdfSmrg    }
73635c4bbdfSmrg}
73735c4bbdfSmrg#endif                          /* PreserveWin32Stack */
73805b261ecSmrg
73905b261ecSmrg/*
74005b261ecSmrg * winMultiWindowWMProc
74105b261ecSmrg */
74205b261ecSmrg
74305b261ecSmrgstatic void *
74435c4bbdfSmrgwinMultiWindowWMProc(void *pArg)
74505b261ecSmrg{
74635c4bbdfSmrg    WMProcArgPtr pProcArg = (WMProcArgPtr) pArg;
74735c4bbdfSmrg    WMInfoPtr pWMInfo = pProcArg->pWMInfo;
74835c4bbdfSmrg
74935c4bbdfSmrg    /* Initialize the Window Manager */
75035c4bbdfSmrg    winInitMultiWindowWM(pWMInfo, pProcArg);
75135c4bbdfSmrg
75205b261ecSmrg#if CYGMULTIWINDOW_DEBUG
75335c4bbdfSmrg    ErrorF("winMultiWindowWMProc ()\n");
75405b261ecSmrg#endif
75505b261ecSmrg
75635c4bbdfSmrg    /* Loop until we explicitly break out */
75735c4bbdfSmrg    for (;;) {
75835c4bbdfSmrg        WMMsgNodePtr pNode;
75935c4bbdfSmrg
76035c4bbdfSmrg        if (g_fAnotherWMRunning) {      /* Another Window manager exists. */
76135c4bbdfSmrg            Sleep(1000);
76235c4bbdfSmrg            continue;
76335c4bbdfSmrg        }
76435c4bbdfSmrg
76535c4bbdfSmrg        /* Pop a message off of our queue */
76635c4bbdfSmrg        pNode = PopMessage(&pWMInfo->wmMsgQueue, pWMInfo);
76735c4bbdfSmrg        if (pNode == NULL) {
76835c4bbdfSmrg            /* Bail if PopMessage returns without a message */
76935c4bbdfSmrg            /* NOTE: Remember that PopMessage is a blocking function. */
77035c4bbdfSmrg            ErrorF("winMultiWindowWMProc - Queue is Empty?  Exiting.\n");
77135c4bbdfSmrg            pthread_exit(NULL);
77235c4bbdfSmrg        }
77305b261ecSmrg
77405b261ecSmrg#if CYGMULTIWINDOW_DEBUG
77535c4bbdfSmrg        ErrorF("winMultiWindowWMProc - MSG: %d ID: %d\n",
77635c4bbdfSmrg               (int) pNode->msg.msg, (int) pNode->msg.dwID);
77705b261ecSmrg#endif
77805b261ecSmrg
77935c4bbdfSmrg        /* Branch on the message type */
78035c4bbdfSmrg        switch (pNode->msg.msg) {
78105b261ecSmrg#if 0
78235c4bbdfSmrg        case WM_WM_MOVE:
78335c4bbdfSmrg            ErrorF("\tWM_WM_MOVE\n");
78435c4bbdfSmrg            break;
78505b261ecSmrg
78635c4bbdfSmrg        case WM_WM_SIZE:
78735c4bbdfSmrg            ErrorF("\tWM_WM_SIZE\n");
78835c4bbdfSmrg            break;
78905b261ecSmrg#endif
79005b261ecSmrg
79135c4bbdfSmrg        case WM_WM_RAISE:
79205b261ecSmrg#if CYGMULTIWINDOW_DEBUG
79335c4bbdfSmrg            ErrorF("\tWM_WM_RAISE\n");
79405b261ecSmrg#endif
79535c4bbdfSmrg            /* Raise the window */
79635c4bbdfSmrg            XRaiseWindow(pWMInfo->pDisplay, pNode->msg.iWindow);
79705b261ecSmrg#if 0
79835c4bbdfSmrg            PreserveWin32Stack(pWMInfo, pNode->msg.iWindow, GW_HWNDPREV);
79905b261ecSmrg#endif
80035c4bbdfSmrg            break;
80105b261ecSmrg
80235c4bbdfSmrg        case WM_WM_LOWER:
80305b261ecSmrg#if CYGMULTIWINDOW_DEBUG
80435c4bbdfSmrg            ErrorF("\tWM_WM_LOWER\n");
80505b261ecSmrg#endif
80605b261ecSmrg
80735c4bbdfSmrg            /* Lower the window */
80835c4bbdfSmrg            XLowerWindow(pWMInfo->pDisplay, pNode->msg.iWindow);
80935c4bbdfSmrg            break;
81005b261ecSmrg
81135c4bbdfSmrg        case WM_WM_MAP:
81205b261ecSmrg#if CYGMULTIWINDOW_DEBUG
81335c4bbdfSmrg            ErrorF("\tWM_WM_MAP\n");
81405b261ecSmrg#endif
81535c4bbdfSmrg            /* Put a note as to the HWND associated with this Window */
81635c4bbdfSmrg            XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER,
81735c4bbdfSmrg                            32,
81835c4bbdfSmrg                            PropModeReplace,
81935c4bbdfSmrg                            (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4);
82035c4bbdfSmrg            UpdateName(pWMInfo, pNode->msg.iWindow);
82135c4bbdfSmrg            UpdateIcon(pWMInfo, pNode->msg.iWindow);
82235c4bbdfSmrg            break;
82335c4bbdfSmrg
82435c4bbdfSmrg        case WM_WM_MAP2:
8256747b715Smrg#if CYGMULTIWINDOW_DEBUG
82635c4bbdfSmrg            ErrorF("\tWM_WM_MAP2\n");
82705b261ecSmrg#endif
82835c4bbdfSmrg            XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER,
82935c4bbdfSmrg                            32,
83035c4bbdfSmrg                            PropModeReplace,
83135c4bbdfSmrg                            (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4);
83235c4bbdfSmrg            break;
83335c4bbdfSmrg
83435c4bbdfSmrg        case WM_WM_MAP3:
8356747b715Smrg#if CYGMULTIWINDOW_DEBUG
83635c4bbdfSmrg            ErrorF("\tWM_WM_MAP3\n");
8376747b715Smrg#endif
83835c4bbdfSmrg            /* Put a note as to the HWND associated with this Window */
83935c4bbdfSmrg            XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER,
84035c4bbdfSmrg                            32,
84135c4bbdfSmrg                            PropModeReplace,
84235c4bbdfSmrg                            (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4);
84335c4bbdfSmrg            UpdateName(pWMInfo, pNode->msg.iWindow);
84435c4bbdfSmrg            UpdateIcon(pWMInfo, pNode->msg.iWindow);
84535c4bbdfSmrg            UpdateStyle(pWMInfo, pNode->msg.iWindow);
84635c4bbdfSmrg
84735c4bbdfSmrg
84835c4bbdfSmrg            /* Reshape */
84935c4bbdfSmrg            {
85035c4bbdfSmrg                WindowPtr pWin =
85135c4bbdfSmrg                    GetProp(pNode->msg.hwndWindow, WIN_WINDOW_PROP);
85235c4bbdfSmrg                if (pWin) {
85335c4bbdfSmrg                    winReshapeMultiWindow(pWin);
85435c4bbdfSmrg                    winUpdateRgnMultiWindow(pWin);
85535c4bbdfSmrg                }
85635c4bbdfSmrg            }
85735c4bbdfSmrg
85835c4bbdfSmrg            break;
85935c4bbdfSmrg
86035c4bbdfSmrg        case WM_WM_UNMAP:
86105b261ecSmrg#if CYGMULTIWINDOW_DEBUG
86235c4bbdfSmrg            ErrorF("\tWM_WM_UNMAP\n");
86305b261ecSmrg#endif
86405b261ecSmrg
86535c4bbdfSmrg            /* Unmap the window */
86635c4bbdfSmrg            XUnmapWindow(pWMInfo->pDisplay, pNode->msg.iWindow);
86735c4bbdfSmrg            break;
86835c4bbdfSmrg
86935c4bbdfSmrg        case WM_WM_KILL:
87005b261ecSmrg#if CYGMULTIWINDOW_DEBUG
87135c4bbdfSmrg            ErrorF("\tWM_WM_KILL\n");
87205b261ecSmrg#endif
87335c4bbdfSmrg            {
87435c4bbdfSmrg                /* --- */
87535c4bbdfSmrg                if (IsWmProtocolAvailable(pWMInfo->pDisplay,
87635c4bbdfSmrg                                          pNode->msg.iWindow,
87735c4bbdfSmrg                                          pWMInfo->atmWmDelete))
87835c4bbdfSmrg                    SendXMessage(pWMInfo->pDisplay,
87935c4bbdfSmrg                                 pNode->msg.iWindow,
88035c4bbdfSmrg                                 pWMInfo->atmWmProtos, pWMInfo->atmWmDelete);
88135c4bbdfSmrg                else
88235c4bbdfSmrg                    XKillClient(pWMInfo->pDisplay, pNode->msg.iWindow);
88335c4bbdfSmrg            }
88435c4bbdfSmrg            break;
88535c4bbdfSmrg
88635c4bbdfSmrg        case WM_WM_ACTIVATE:
88705b261ecSmrg#if CYGMULTIWINDOW_DEBUG
88835c4bbdfSmrg            ErrorF("\tWM_WM_ACTIVATE\n");
88905b261ecSmrg#endif
89035c4bbdfSmrg            /* Set the input focus */
89135c4bbdfSmrg
89235c4bbdfSmrg            /*
89335c4bbdfSmrg               ICCCM 4.1.7 is pretty opaque, but it appears that the rules are
89435c4bbdfSmrg               actually quite simple:
89535c4bbdfSmrg               -- the WM_HINTS input field determines whether the WM should call
89635c4bbdfSmrg               XSetInputFocus()
89735c4bbdfSmrg               -- independently, the WM_TAKE_FOCUS protocol determines whether
89835c4bbdfSmrg               the WM should send a WM_TAKE_FOCUS ClientMessage.
89935c4bbdfSmrg            */
90035c4bbdfSmrg            {
90135c4bbdfSmrg              Bool neverFocus = FALSE;
90235c4bbdfSmrg              XWMHints *hints = XGetWMHints(pWMInfo->pDisplay, pNode->msg.iWindow);
90335c4bbdfSmrg
90435c4bbdfSmrg              if (hints) {
90535c4bbdfSmrg                if (hints->flags & InputHint)
90635c4bbdfSmrg                  neverFocus = !hints->input;
90735c4bbdfSmrg                XFree(hints);
90835c4bbdfSmrg              }
90935c4bbdfSmrg
91035c4bbdfSmrg              if (!neverFocus)
91135c4bbdfSmrg                XSetInputFocus(pWMInfo->pDisplay,
91235c4bbdfSmrg                               pNode->msg.iWindow,
91335c4bbdfSmrg                               RevertToPointerRoot, CurrentTime);
91435c4bbdfSmrg
91535c4bbdfSmrg              if (IsWmProtocolAvailable(pWMInfo->pDisplay,
91635c4bbdfSmrg                                        pNode->msg.iWindow,
91735c4bbdfSmrg                                        pWMInfo->atmWmTakeFocus))
91835c4bbdfSmrg                SendXMessage(pWMInfo->pDisplay,
91935c4bbdfSmrg                             pNode->msg.iWindow,
92035c4bbdfSmrg                             pWMInfo->atmWmProtos, pWMInfo->atmWmTakeFocus);
92135c4bbdfSmrg
92235c4bbdfSmrg            }
92335c4bbdfSmrg            break;
92435c4bbdfSmrg
92535c4bbdfSmrg        case WM_WM_NAME_EVENT:
92635c4bbdfSmrg            UpdateName(pWMInfo, pNode->msg.iWindow);
92735c4bbdfSmrg            break;
92835c4bbdfSmrg
92935c4bbdfSmrg        case WM_WM_ICON_EVENT:
93035c4bbdfSmrg            UpdateIcon(pWMInfo, pNode->msg.iWindow);
93135c4bbdfSmrg            break;
93235c4bbdfSmrg
93335c4bbdfSmrg        case WM_WM_HINTS_EVENT:
93435c4bbdfSmrg            {
93535c4bbdfSmrg            XWindowAttributes attr;
93635c4bbdfSmrg
93735c4bbdfSmrg            /* Don't do anything if this is an override-redirect window */
93835c4bbdfSmrg            XGetWindowAttributes (pWMInfo->pDisplay, pNode->msg.iWindow, &attr);
93935c4bbdfSmrg            if (attr.override_redirect)
94035c4bbdfSmrg              break;
94135c4bbdfSmrg
94235c4bbdfSmrg            UpdateStyle(pWMInfo, pNode->msg.iWindow);
94335c4bbdfSmrg            }
94435c4bbdfSmrg            break;
94535c4bbdfSmrg
94635c4bbdfSmrg        case WM_WM_CHANGE_STATE:
94735c4bbdfSmrg            /* Minimize the window in Windows */
94835c4bbdfSmrg            winMinimizeWindow(pNode->msg.iWindow);
94935c4bbdfSmrg            break;
95035c4bbdfSmrg
95135c4bbdfSmrg        default:
95235c4bbdfSmrg            ErrorF("winMultiWindowWMProc - Unknown Message.  Exiting.\n");
95335c4bbdfSmrg            pthread_exit(NULL);
95435c4bbdfSmrg            break;
95535c4bbdfSmrg        }
95635c4bbdfSmrg
95735c4bbdfSmrg        /* Free the retrieved message */
95835c4bbdfSmrg        free(pNode);
95935c4bbdfSmrg
96035c4bbdfSmrg        /* Flush any pending events on our display */
96135c4bbdfSmrg        XFlush(pWMInfo->pDisplay);
96205b261ecSmrg    }
96305b261ecSmrg
96435c4bbdfSmrg    /* Free the condition variable */
96535c4bbdfSmrg    pthread_cond_destroy(&pWMInfo->wmMsgQueue.pcNotEmpty);
96635c4bbdfSmrg
96735c4bbdfSmrg    /* Free the mutex variable */
96835c4bbdfSmrg    pthread_mutex_destroy(&pWMInfo->wmMsgQueue.pmMutex);
96935c4bbdfSmrg
97035c4bbdfSmrg    /* Free the passed-in argument */
97135c4bbdfSmrg    free(pProcArg);
97235c4bbdfSmrg
97305b261ecSmrg#if CYGMULTIWINDOW_DEBUG
97435c4bbdfSmrg    ErrorF("-winMultiWindowWMProc ()\n");
97505b261ecSmrg#endif
97635c4bbdfSmrg    return NULL;
97705b261ecSmrg}
97805b261ecSmrg
97905b261ecSmrg/*
98005b261ecSmrg * X message procedure
98105b261ecSmrg */
98205b261ecSmrg
98305b261ecSmrgstatic void *
98435c4bbdfSmrgwinMultiWindowXMsgProc(void *pArg)
98505b261ecSmrg{
98635c4bbdfSmrg    winWMMessageRec msg;
98735c4bbdfSmrg    XMsgProcArgPtr pProcArg = (XMsgProcArgPtr) pArg;
98835c4bbdfSmrg    char pszDisplay[512];
98935c4bbdfSmrg    int iRetries;
99035c4bbdfSmrg    XEvent event;
99135c4bbdfSmrg    Atom atmWmName;
99235c4bbdfSmrg    Atom atmWmHints;
99335c4bbdfSmrg    Atom atmWmChange;
99435c4bbdfSmrg    Atom atmNetWmIcon;
99535c4bbdfSmrg    Atom atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints;
99635c4bbdfSmrg    int iReturn;
99735c4bbdfSmrg    XIconSize *xis;
99835c4bbdfSmrg
99935c4bbdfSmrg    winDebug("winMultiWindowXMsgProc - Hello\n");
100035c4bbdfSmrg
100135c4bbdfSmrg    /* Check that argument pointer is not invalid */
100235c4bbdfSmrg    if (pProcArg == NULL) {
100335c4bbdfSmrg        ErrorF("winMultiWindowXMsgProc - pProcArg is NULL.  Exiting.\n");
100435c4bbdfSmrg        pthread_exit(NULL);
100505b261ecSmrg    }
100605b261ecSmrg
100735c4bbdfSmrg    ErrorF("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n");
100805b261ecSmrg
100935c4bbdfSmrg    /* Grab the server started mutex - pause until we get it */
101035c4bbdfSmrg    iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
101135c4bbdfSmrg    if (iReturn != 0) {
101235c4bbdfSmrg        ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () failed: %d.  "
101335c4bbdfSmrg               "Exiting.\n", iReturn);
101435c4bbdfSmrg        pthread_exit(NULL);
101505b261ecSmrg    }
101605b261ecSmrg
101735c4bbdfSmrg    ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n");
101805b261ecSmrg
101935c4bbdfSmrg    /* Allow multiple threads to access Xlib */
102035c4bbdfSmrg    if (XInitThreads() == 0) {
102135c4bbdfSmrg        ErrorF("winMultiWindowXMsgProc - XInitThreads () failed.  Exiting.\n");
102235c4bbdfSmrg        pthread_exit(NULL);
102305b261ecSmrg    }
102405b261ecSmrg
102535c4bbdfSmrg    /* See if X supports the current locale */
102635c4bbdfSmrg    if (XSupportsLocale() == False) {
102735c4bbdfSmrg        ErrorF("winMultiWindowXMsgProc - Warning: locale not supported by X\n");
102805b261ecSmrg    }
102905b261ecSmrg
103035c4bbdfSmrg    /* Release the server started mutex */
103135c4bbdfSmrg    pthread_mutex_unlock(pProcArg->ppmServerStarted);
103205b261ecSmrg
103335c4bbdfSmrg    ErrorF("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n");
103405b261ecSmrg
103535c4bbdfSmrg    /* Install our error handler */
103635c4bbdfSmrg    XSetErrorHandler(winMultiWindowXMsgProcErrorHandler);
103735c4bbdfSmrg    g_winMultiWindowXMsgProcThread = pthread_self();
103835c4bbdfSmrg    g_winMultiWindowXMsgProcOldIOErrorHandler =
103935c4bbdfSmrg        XSetIOErrorHandler(winMultiWindowXMsgProcIOErrorHandler);
104035c4bbdfSmrg
104135c4bbdfSmrg    /* Set jump point for IO Error exits */
104235c4bbdfSmrg    iReturn = setjmp(g_jmpXMsgProcEntry);
104335c4bbdfSmrg
104435c4bbdfSmrg    /* Check if we should continue operations */
104535c4bbdfSmrg    if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) {
104635c4bbdfSmrg        /* setjmp returned an unknown value, exit */
104735c4bbdfSmrg        ErrorF("winInitMultiWindowXMsgProc - setjmp returned: %d.  Exiting.\n",
104835c4bbdfSmrg               iReturn);
104935c4bbdfSmrg        pthread_exit(NULL);
105005b261ecSmrg    }
105135c4bbdfSmrg    else if (iReturn == WIN_JMP_ERROR_IO) {
105235c4bbdfSmrg        ErrorF("winInitMultiWindowXMsgProc - Caught IO Error.  Exiting.\n");
105335c4bbdfSmrg        pthread_exit(NULL);
105405b261ecSmrg    }
105505b261ecSmrg
105635c4bbdfSmrg    /* Setup the display connection string x */
105735c4bbdfSmrg    winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen);
105805b261ecSmrg
105935c4bbdfSmrg    /* Print the display connection string */
106035c4bbdfSmrg    ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay);
106105b261ecSmrg
106235c4bbdfSmrg    /* Use our generated cookie for authentication */
106335c4bbdfSmrg    winSetAuthorization();
10646747b715Smrg
106535c4bbdfSmrg    /* Initialize retry count */
106635c4bbdfSmrg    iRetries = 0;
106705b261ecSmrg
106835c4bbdfSmrg    /* Open the X display */
106935c4bbdfSmrg    do {
107035c4bbdfSmrg        /* Try to open the display */
107135c4bbdfSmrg        pProcArg->pDisplay = XOpenDisplay(pszDisplay);
107235c4bbdfSmrg        if (pProcArg->pDisplay == NULL) {
107335c4bbdfSmrg            ErrorF("winMultiWindowXMsgProc - Could not open display, try: %d, "
107435c4bbdfSmrg                   "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
107535c4bbdfSmrg            ++iRetries;
107635c4bbdfSmrg            sleep(WIN_CONNECT_DELAY);
107735c4bbdfSmrg            continue;
107835c4bbdfSmrg        }
107935c4bbdfSmrg        else
108035c4bbdfSmrg            break;
108105b261ecSmrg    }
108235c4bbdfSmrg    while (pProcArg->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES);
108335c4bbdfSmrg
108435c4bbdfSmrg    /* Make sure that the display opened */
108535c4bbdfSmrg    if (pProcArg->pDisplay == NULL) {
108635c4bbdfSmrg        ErrorF("winMultiWindowXMsgProc - Failed opening the display.  "
108735c4bbdfSmrg               "Exiting.\n");
108835c4bbdfSmrg        pthread_exit(NULL);
108905b261ecSmrg    }
109005b261ecSmrg
109135c4bbdfSmrg    ErrorF("winMultiWindowXMsgProc - XOpenDisplay () returned and "
109235c4bbdfSmrg           "successfully opened the display.\n");
109305b261ecSmrg
109435c4bbdfSmrg    /* Check if another window manager is already running */
109535c4bbdfSmrg    g_fAnotherWMRunning =
109635c4bbdfSmrg        CheckAnotherWindowManager(pProcArg->pDisplay, pProcArg->dwScreen,
109735c4bbdfSmrg                                  pProcArg->pWMInfo->fAllowOtherWM);
10986747b715Smrg
109935c4bbdfSmrg    if (g_fAnotherWMRunning && !pProcArg->pWMInfo->fAllowOtherWM) {
110035c4bbdfSmrg        ErrorF("winMultiWindowXMsgProc - "
110135c4bbdfSmrg               "another window manager is running.  Exiting.\n");
110235c4bbdfSmrg        pthread_exit(NULL);
110305b261ecSmrg    }
11046747b715Smrg
110535c4bbdfSmrg    /* Set up the supported icon sizes */
110635c4bbdfSmrg    xis = XAllocIconSize();
110735c4bbdfSmrg    if (xis) {
110835c4bbdfSmrg        xis->min_width = xis->min_height = 16;
110935c4bbdfSmrg        xis->max_width = xis->max_height = 48;
111035c4bbdfSmrg        xis->width_inc = xis->height_inc = 16;
111135c4bbdfSmrg        XSetIconSizes(pProcArg->pDisplay,
111235c4bbdfSmrg                      RootWindow(pProcArg->pDisplay, pProcArg->dwScreen),
111335c4bbdfSmrg                      xis, 1);
111435c4bbdfSmrg        XFree(xis);
111505b261ecSmrg    }
111605b261ecSmrg
111735c4bbdfSmrg    atmWmName = XInternAtom(pProcArg->pDisplay, "WM_NAME", False);
111835c4bbdfSmrg    atmWmHints = XInternAtom(pProcArg->pDisplay, "WM_HINTS", False);
111935c4bbdfSmrg    atmWmChange = XInternAtom(pProcArg->pDisplay, "WM_CHANGE_STATE", False);
112035c4bbdfSmrg    atmNetWmIcon = XInternAtom(pProcArg->pDisplay, "_NET_WM_ICON", False);
112135c4bbdfSmrg    atmWindowState = XInternAtom(pProcArg->pDisplay, "_NET_WM_STATE", False);
112235c4bbdfSmrg    atmMotifWmHints = XInternAtom(pProcArg->pDisplay, "_MOTIF_WM_HINTS", False);
112335c4bbdfSmrg    atmWindowType = XInternAtom(pProcArg->pDisplay, "_NET_WM_WINDOW_TYPE", False);
112435c4bbdfSmrg    atmNormalHints = XInternAtom(pProcArg->pDisplay, "WM_NORMAL_HINTS", False);
112535c4bbdfSmrg
112635c4bbdfSmrg    /*
112735c4bbdfSmrg       iiimxcf had a bug until 2009-04-27, assuming that the
112835c4bbdfSmrg       WM_STATE atom exists, causing clients to fail with
112935c4bbdfSmrg       a BadAtom X error if it doesn't.
113035c4bbdfSmrg
113135c4bbdfSmrg       Since this is on in the default Solaris 10 install,
113235c4bbdfSmrg       workaround this by making sure it does exist...
113335c4bbdfSmrg     */
113435c4bbdfSmrg    XInternAtom(pProcArg->pDisplay, "WM_STATE", 0);
113535c4bbdfSmrg
113635c4bbdfSmrg    /* Loop until we explicitly break out */
113735c4bbdfSmrg    while (1) {
113835c4bbdfSmrg        if (g_shutdown)
113935c4bbdfSmrg            break;
114035c4bbdfSmrg
114135c4bbdfSmrg        if (pProcArg->pWMInfo->fAllowOtherWM && !XPending(pProcArg->pDisplay)) {
114235c4bbdfSmrg            if (CheckAnotherWindowManager
114335c4bbdfSmrg                (pProcArg->pDisplay, pProcArg->dwScreen, TRUE)) {
114435c4bbdfSmrg                if (!g_fAnotherWMRunning) {
114535c4bbdfSmrg                    g_fAnotherWMRunning = TRUE;
114635c4bbdfSmrg                    SendMessage(pProcArg->hwndScreen, WM_UNMANAGE, 0, 0);
114735c4bbdfSmrg                }
114835c4bbdfSmrg            }
114935c4bbdfSmrg            else {
115035c4bbdfSmrg                if (g_fAnotherWMRunning) {
115135c4bbdfSmrg                    g_fAnotherWMRunning = FALSE;
115235c4bbdfSmrg                    SendMessage(pProcArg->hwndScreen, WM_MANAGE, 0, 0);
115335c4bbdfSmrg                }
115435c4bbdfSmrg            }
115535c4bbdfSmrg            Sleep(500);
115635c4bbdfSmrg            continue;
115735c4bbdfSmrg        }
115805b261ecSmrg
115935c4bbdfSmrg        /* Fetch next event */
116035c4bbdfSmrg        XNextEvent(pProcArg->pDisplay, &event);
116135c4bbdfSmrg
116235c4bbdfSmrg        /* Branch on event type */
116335c4bbdfSmrg        if (event.type == CreateNotify) {
116435c4bbdfSmrg            XWindowAttributes attr;
116535c4bbdfSmrg
116635c4bbdfSmrg            XSelectInput(pProcArg->pDisplay,
116735c4bbdfSmrg                         event.xcreatewindow.window, PropertyChangeMask);
116835c4bbdfSmrg
116935c4bbdfSmrg            /* Get the window attributes */
117035c4bbdfSmrg            XGetWindowAttributes(pProcArg->pDisplay,
117135c4bbdfSmrg                                 event.xcreatewindow.window, &attr);
117235c4bbdfSmrg
117335c4bbdfSmrg            if (!attr.override_redirect)
117435c4bbdfSmrg                XSetWindowBorderWidth(pProcArg->pDisplay,
117535c4bbdfSmrg                                      event.xcreatewindow.window, 0);
117635c4bbdfSmrg        }
117735c4bbdfSmrg        else if (event.type == MapNotify) {
117835c4bbdfSmrg            /* Fake a reparentNotify event as SWT/Motif expects a
117935c4bbdfSmrg               Window Manager to reparent a top-level window when
118035c4bbdfSmrg               it is mapped and waits until they do.
118135c4bbdfSmrg
118235c4bbdfSmrg               We don't actually need to reparent, as the frame is
118335c4bbdfSmrg               a native window, not an X window
118435c4bbdfSmrg
118535c4bbdfSmrg               We do this on MapNotify, not MapRequest like a real
118635c4bbdfSmrg               Window Manager would, so we don't have do get involved
118735c4bbdfSmrg               in actually mapping the window via it's (non-existent)
118835c4bbdfSmrg               parent...
118935c4bbdfSmrg
119035c4bbdfSmrg               See sourceware bugzilla #9848
119135c4bbdfSmrg             */
119235c4bbdfSmrg
119335c4bbdfSmrg            XWindowAttributes attr;
119435c4bbdfSmrg            Window root;
119535c4bbdfSmrg            Window parent;
119635c4bbdfSmrg            Window *children;
119735c4bbdfSmrg            unsigned int nchildren;
119835c4bbdfSmrg
119935c4bbdfSmrg            if (XGetWindowAttributes(event.xmap.display,
120035c4bbdfSmrg                                     event.xmap.window,
120135c4bbdfSmrg                                     &attr) &&
120235c4bbdfSmrg                XQueryTree(event.xmap.display,
120335c4bbdfSmrg                           event.xmap.window,
120435c4bbdfSmrg                           &root, &parent, &children, &nchildren)) {
120535c4bbdfSmrg                if (children)
120635c4bbdfSmrg                    XFree(children);
120735c4bbdfSmrg
120835c4bbdfSmrg                /*
120935c4bbdfSmrg                   It's a top-level window if the parent window is a root window
121035c4bbdfSmrg                   Only non-override_redirect windows can get reparented
121135c4bbdfSmrg                 */
121235c4bbdfSmrg                if ((attr.root == parent) && !event.xmap.override_redirect) {
121335c4bbdfSmrg                    XEvent event_send;
121435c4bbdfSmrg
121535c4bbdfSmrg                    event_send.type = ReparentNotify;
121635c4bbdfSmrg                    event_send.xreparent.event = event.xmap.window;
121735c4bbdfSmrg                    event_send.xreparent.window = event.xmap.window;
121835c4bbdfSmrg                    event_send.xreparent.parent = parent;
121935c4bbdfSmrg                    event_send.xreparent.x = attr.x;
122035c4bbdfSmrg                    event_send.xreparent.y = attr.y;
122135c4bbdfSmrg
122235c4bbdfSmrg                    XSendEvent(event.xmap.display,
122335c4bbdfSmrg                               event.xmap.window,
122435c4bbdfSmrg                               True, StructureNotifyMask, &event_send);
122535c4bbdfSmrg                }
122635c4bbdfSmrg            }
122735c4bbdfSmrg        }
122835c4bbdfSmrg        else if (event.type == ConfigureNotify) {
122935c4bbdfSmrg            if (!event.xconfigure.send_event) {
123035c4bbdfSmrg                /*
123135c4bbdfSmrg                   Java applications using AWT on JRE 1.6.0 break with non-reparenting WMs AWT
123235c4bbdfSmrg                   doesn't explicitly know about (See sun bug #6434227)
123335c4bbdfSmrg
123435c4bbdfSmrg                   XDecoratedPeer.handleConfigureNotifyEvent() only processes non-synthetic
123535c4bbdfSmrg                   ConfigureNotify events to update window location if it's identified the
123635c4bbdfSmrg                   WM as a non-reparenting WM it knows about (compiz or lookingglass)
123735c4bbdfSmrg
123835c4bbdfSmrg                   Rather than tell all sorts of lies to get XWM to recognize us as one of
123935c4bbdfSmrg                   those, simply send a synthetic ConfigureNotify for every non-synthetic one
124035c4bbdfSmrg                 */
124135c4bbdfSmrg                XEvent event_send = event;
124235c4bbdfSmrg
124335c4bbdfSmrg                event_send.xconfigure.send_event = TRUE;
124435c4bbdfSmrg                event_send.xconfigure.event = event.xconfigure.window;
124535c4bbdfSmrg                XSendEvent(event.xconfigure.display,
124635c4bbdfSmrg                           event.xconfigure.window,
124735c4bbdfSmrg                           True, StructureNotifyMask, &event_send);
124835c4bbdfSmrg            }
124935c4bbdfSmrg        }
125035c4bbdfSmrg        else if (event.type == PropertyNotify) {
125135c4bbdfSmrg            if (event.xproperty.atom == atmWmName) {
125235c4bbdfSmrg                memset(&msg, 0, sizeof(msg));
125335c4bbdfSmrg
125435c4bbdfSmrg                msg.msg = WM_WM_NAME_EVENT;
125535c4bbdfSmrg                msg.iWindow = event.xproperty.window;
125635c4bbdfSmrg
125735c4bbdfSmrg                /* Other fields ignored */
125835c4bbdfSmrg                winSendMessageToWM(pProcArg->pWMInfo, &msg);
125935c4bbdfSmrg            }
126035c4bbdfSmrg            else {
126135c4bbdfSmrg                /*
126235c4bbdfSmrg                   Several properties are considered for WM hints, check if this property change affects any of them...
126335c4bbdfSmrg                   (this list needs to be kept in sync with winApplyHints())
126435c4bbdfSmrg                 */
126535c4bbdfSmrg                if ((event.xproperty.atom == atmWmHints) ||
126635c4bbdfSmrg                    (event.xproperty.atom == atmWindowState) ||
126735c4bbdfSmrg                    (event.xproperty.atom == atmMotifWmHints) ||
126835c4bbdfSmrg                    (event.xproperty.atom == atmWindowType) ||
126935c4bbdfSmrg                    (event.xproperty.atom == atmNormalHints)) {
127035c4bbdfSmrg                    memset(&msg, 0, sizeof(msg));
127135c4bbdfSmrg                    msg.msg = WM_WM_HINTS_EVENT;
127235c4bbdfSmrg                    msg.iWindow = event.xproperty.window;
127335c4bbdfSmrg
127435c4bbdfSmrg                    /* Other fields ignored */
127535c4bbdfSmrg                    winSendMessageToWM(pProcArg->pWMInfo, &msg);
127635c4bbdfSmrg                }
127735c4bbdfSmrg
127835c4bbdfSmrg                /* Not an else as WM_HINTS affects both style and icon */
127935c4bbdfSmrg                if ((event.xproperty.atom == atmWmHints) ||
128035c4bbdfSmrg                    (event.xproperty.atom == atmNetWmIcon)) {
128135c4bbdfSmrg                    memset(&msg, 0, sizeof(msg));
128235c4bbdfSmrg                    msg.msg = WM_WM_ICON_EVENT;
128335c4bbdfSmrg                    msg.iWindow = event.xproperty.window;
128435c4bbdfSmrg
128535c4bbdfSmrg                    /* Other fields ignored */
128635c4bbdfSmrg                    winSendMessageToWM(pProcArg->pWMInfo, &msg);
12876747b715Smrg                }
12886747b715Smrg            }
12896747b715Smrg        }
129035c4bbdfSmrg        else if (event.type == ClientMessage
129135c4bbdfSmrg                 && event.xclient.message_type == atmWmChange
129235c4bbdfSmrg                 && event.xclient.data.l[0] == IconicState) {
129335c4bbdfSmrg            ErrorF("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n");
129435c4bbdfSmrg
129535c4bbdfSmrg            memset(&msg, 0, sizeof(msg));
129635c4bbdfSmrg
129735c4bbdfSmrg            msg.msg = WM_WM_CHANGE_STATE;
129835c4bbdfSmrg            msg.iWindow = event.xclient.window;
129935c4bbdfSmrg
130035c4bbdfSmrg            winSendMessageToWM(pProcArg->pWMInfo, &msg);
130135c4bbdfSmrg        }
130205b261ecSmrg    }
130305b261ecSmrg
130435c4bbdfSmrg    XCloseDisplay(pProcArg->pDisplay);
130535c4bbdfSmrg    pthread_exit(NULL);
130635c4bbdfSmrg    return NULL;
130705b261ecSmrg}
130805b261ecSmrg
130905b261ecSmrg/*
131005b261ecSmrg * winInitWM - Entry point for the X server to spawn
131105b261ecSmrg * the Window Manager thread.  Called from
131205b261ecSmrg * winscrinit.c/winFinishScreenInitFB ().
131305b261ecSmrg */
131405b261ecSmrg
131505b261ecSmrgBool
131635c4bbdfSmrgwinInitWM(void **ppWMInfo,
131735c4bbdfSmrg          pthread_t * ptWMProc,
131835c4bbdfSmrg          pthread_t * ptXMsgProc,
131935c4bbdfSmrg          pthread_mutex_t * ppmServerStarted,
132035c4bbdfSmrg          int dwScreen, HWND hwndScreen, BOOL allowOtherWM)
132105b261ecSmrg{
132235c4bbdfSmrg    WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec));
132335c4bbdfSmrg    WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec));
132435c4bbdfSmrg    XMsgProcArgPtr pXMsgArg = malloc(sizeof(XMsgProcArgRec));
132535c4bbdfSmrg
132635c4bbdfSmrg    /* Bail if the input parameters are bad */
132735c4bbdfSmrg    if (pArg == NULL || pWMInfo == NULL || pXMsgArg == NULL) {
132835c4bbdfSmrg        ErrorF("winInitWM - malloc failed.\n");
132935c4bbdfSmrg        free(pArg);
133035c4bbdfSmrg        free(pWMInfo);
133135c4bbdfSmrg        free(pXMsgArg);
133235c4bbdfSmrg        return FALSE;
133305b261ecSmrg    }
133435c4bbdfSmrg
133535c4bbdfSmrg    /* Zero the allocated memory */
133635c4bbdfSmrg    ZeroMemory(pArg, sizeof(WMProcArgRec));
133735c4bbdfSmrg    ZeroMemory(pWMInfo, sizeof(WMInfoRec));
133835c4bbdfSmrg    ZeroMemory(pXMsgArg, sizeof(XMsgProcArgRec));
133935c4bbdfSmrg
134035c4bbdfSmrg    /* Set a return pointer to the Window Manager info structure */
134135c4bbdfSmrg    *ppWMInfo = pWMInfo;
134235c4bbdfSmrg    pWMInfo->fAllowOtherWM = allowOtherWM;
134335c4bbdfSmrg
134435c4bbdfSmrg    /* Setup the argument structure for the thread function */
134535c4bbdfSmrg    pArg->dwScreen = dwScreen;
134635c4bbdfSmrg    pArg->pWMInfo = pWMInfo;
134735c4bbdfSmrg    pArg->ppmServerStarted = ppmServerStarted;
134835c4bbdfSmrg
134935c4bbdfSmrg    /* Intialize the message queue */
135035c4bbdfSmrg    if (!InitQueue(&pWMInfo->wmMsgQueue)) {
135135c4bbdfSmrg        ErrorF("winInitWM - InitQueue () failed.\n");
135235c4bbdfSmrg        return FALSE;
135305b261ecSmrg    }
135435c4bbdfSmrg
135535c4bbdfSmrg    /* Spawn a thread for the Window Manager */
135635c4bbdfSmrg    if (pthread_create(ptWMProc, NULL, winMultiWindowWMProc, pArg)) {
135735c4bbdfSmrg        /* Bail if thread creation failed */
135835c4bbdfSmrg        ErrorF("winInitWM - pthread_create failed for Window Manager.\n");
135935c4bbdfSmrg        return FALSE;
136005b261ecSmrg    }
136105b261ecSmrg
136235c4bbdfSmrg    /* Spawn the XNextEvent thread, will send messages to WM */
136335c4bbdfSmrg    pXMsgArg->dwScreen = dwScreen;
136435c4bbdfSmrg    pXMsgArg->pWMInfo = pWMInfo;
136535c4bbdfSmrg    pXMsgArg->ppmServerStarted = ppmServerStarted;
136635c4bbdfSmrg    pXMsgArg->hwndScreen = hwndScreen;
136735c4bbdfSmrg    if (pthread_create(ptXMsgProc, NULL, winMultiWindowXMsgProc, pXMsgArg)) {
136835c4bbdfSmrg        /* Bail if thread creation failed */
136935c4bbdfSmrg        ErrorF("winInitWM - pthread_create failed on XMSG.\n");
137035c4bbdfSmrg        return FALSE;
137105b261ecSmrg    }
137205b261ecSmrg
137305b261ecSmrg#if CYGDEBUG || YES
137435c4bbdfSmrg    winDebug("winInitWM - Returning.\n");
137505b261ecSmrg#endif
137605b261ecSmrg
137735c4bbdfSmrg    return TRUE;
137805b261ecSmrg}
137905b261ecSmrg
138005b261ecSmrg/*
138105b261ecSmrg * Window manager thread - setup
138205b261ecSmrg */
138305b261ecSmrg
138405b261ecSmrgstatic void
138535c4bbdfSmrgwinInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg)
138605b261ecSmrg{
138735c4bbdfSmrg    int iRetries = 0;
138835c4bbdfSmrg    char pszDisplay[512];
138935c4bbdfSmrg    int iReturn;
139005b261ecSmrg
139135c4bbdfSmrg    winDebug("winInitMultiWindowWM - Hello\n");
139205b261ecSmrg
139335c4bbdfSmrg    /* Check that argument pointer is not invalid */
139435c4bbdfSmrg    if (pProcArg == NULL) {
139535c4bbdfSmrg        ErrorF("winInitMultiWindowWM - pProcArg is NULL.  Exiting.\n");
139635c4bbdfSmrg        pthread_exit(NULL);
139705b261ecSmrg    }
139805b261ecSmrg
139935c4bbdfSmrg    ErrorF("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n");
140005b261ecSmrg
140135c4bbdfSmrg    /* Grab our garbage mutex to satisfy pthread_cond_wait */
140235c4bbdfSmrg    iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
140335c4bbdfSmrg    if (iReturn != 0) {
140435c4bbdfSmrg        ErrorF("winInitMultiWindowWM - pthread_mutex_lock () failed: %d.  "
140535c4bbdfSmrg               "Exiting.\n", iReturn);
140635c4bbdfSmrg        pthread_exit(NULL);
140705b261ecSmrg    }
140805b261ecSmrg
140935c4bbdfSmrg    ErrorF("winInitMultiWindowWM - pthread_mutex_lock () returned.\n");
141005b261ecSmrg
141135c4bbdfSmrg    /* Allow multiple threads to access Xlib */
141235c4bbdfSmrg    if (XInitThreads() == 0) {
141335c4bbdfSmrg        ErrorF("winInitMultiWindowWM - XInitThreads () failed.  Exiting.\n");
141435c4bbdfSmrg        pthread_exit(NULL);
141505b261ecSmrg    }
141605b261ecSmrg
141735c4bbdfSmrg    /* See if X supports the current locale */
141835c4bbdfSmrg    if (XSupportsLocale() == False) {
141935c4bbdfSmrg        ErrorF("winInitMultiWindowWM - Warning: Locale not supported by X.\n");
142005b261ecSmrg    }
142105b261ecSmrg
142235c4bbdfSmrg    /* Release the server started mutex */
142335c4bbdfSmrg    pthread_mutex_unlock(pProcArg->ppmServerStarted);
142405b261ecSmrg
142535c4bbdfSmrg    ErrorF("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n");
142605b261ecSmrg
142735c4bbdfSmrg    /* Install our error handler */
142835c4bbdfSmrg    XSetErrorHandler(winMultiWindowWMErrorHandler);
142935c4bbdfSmrg    g_winMultiWindowWMThread = pthread_self();
143035c4bbdfSmrg    g_winMultiWindowWMOldIOErrorHandler =
143135c4bbdfSmrg        XSetIOErrorHandler(winMultiWindowWMIOErrorHandler);
143205b261ecSmrg
143335c4bbdfSmrg    /* Set jump point for IO Error exits */
143435c4bbdfSmrg    iReturn = setjmp(g_jmpWMEntry);
143505b261ecSmrg
143635c4bbdfSmrg    /* Check if we should continue operations */
143735c4bbdfSmrg    if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) {
143835c4bbdfSmrg        /* setjmp returned an unknown value, exit */
143935c4bbdfSmrg        ErrorF("winInitMultiWindowWM - setjmp returned: %d.  Exiting.\n",
144035c4bbdfSmrg               iReturn);
144135c4bbdfSmrg        pthread_exit(NULL);
144235c4bbdfSmrg    }
144335c4bbdfSmrg    else if (iReturn == WIN_JMP_ERROR_IO) {
144435c4bbdfSmrg        ErrorF("winInitMultiWindowWM - Caught IO Error.  Exiting.\n");
144535c4bbdfSmrg        pthread_exit(NULL);
144635c4bbdfSmrg    }
14476747b715Smrg
144835c4bbdfSmrg    /* Setup the display connection string x */
144935c4bbdfSmrg    winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen);
145035c4bbdfSmrg
145135c4bbdfSmrg    /* Print the display connection string */
145235c4bbdfSmrg    ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay);
145335c4bbdfSmrg
145435c4bbdfSmrg    /* Use our generated cookie for authentication */
145535c4bbdfSmrg    winSetAuthorization();
145635c4bbdfSmrg
145735c4bbdfSmrg    /* Open the X display */
145835c4bbdfSmrg    do {
145935c4bbdfSmrg        /* Try to open the display */
146035c4bbdfSmrg        pWMInfo->pDisplay = XOpenDisplay(pszDisplay);
146135c4bbdfSmrg        if (pWMInfo->pDisplay == NULL) {
146235c4bbdfSmrg            ErrorF("winInitMultiWindowWM - Could not open display, try: %d, "
146335c4bbdfSmrg                   "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
146435c4bbdfSmrg            ++iRetries;
146535c4bbdfSmrg            sleep(WIN_CONNECT_DELAY);
146635c4bbdfSmrg            continue;
146735c4bbdfSmrg        }
146835c4bbdfSmrg        else
146935c4bbdfSmrg            break;
147005b261ecSmrg    }
147135c4bbdfSmrg    while (pWMInfo->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES);
147235c4bbdfSmrg
147335c4bbdfSmrg    /* Make sure that the display opened */
147435c4bbdfSmrg    if (pWMInfo->pDisplay == NULL) {
147535c4bbdfSmrg        ErrorF("winInitMultiWindowWM - Failed opening the display.  "
147635c4bbdfSmrg               "Exiting.\n");
147735c4bbdfSmrg        pthread_exit(NULL);
147805b261ecSmrg    }
147905b261ecSmrg
148035c4bbdfSmrg    ErrorF("winInitMultiWindowWM - XOpenDisplay () returned and "
148135c4bbdfSmrg           "successfully opened the display.\n");
148205b261ecSmrg
148335c4bbdfSmrg    /* Create some atoms */
148435c4bbdfSmrg    pWMInfo->atmWmProtos = XInternAtom(pWMInfo->pDisplay,
148535c4bbdfSmrg                                       "WM_PROTOCOLS", False);
148635c4bbdfSmrg    pWMInfo->atmWmDelete = XInternAtom(pWMInfo->pDisplay,
148735c4bbdfSmrg                                       "WM_DELETE_WINDOW", False);
148835c4bbdfSmrg    pWMInfo->atmWmTakeFocus = XInternAtom(pWMInfo->pDisplay,
148935c4bbdfSmrg                                       "WM_TAKE_FOCUS", False);
14906747b715Smrg
149135c4bbdfSmrg    pWMInfo->atmPrivMap = XInternAtom(pWMInfo->pDisplay,
149235c4bbdfSmrg                                      WINDOWSWM_NATIVE_HWND, False);
149305b261ecSmrg
149435c4bbdfSmrg    if (1) {
149535c4bbdfSmrg        Cursor cursor = XCreateFontCursor(pWMInfo->pDisplay, XC_left_ptr);
149605b261ecSmrg
149735c4bbdfSmrg        if (cursor) {
149835c4bbdfSmrg            XDefineCursor(pWMInfo->pDisplay,
149935c4bbdfSmrg                          DefaultRootWindow(pWMInfo->pDisplay), cursor);
150035c4bbdfSmrg            XFreeCursor(pWMInfo->pDisplay, cursor);
150135c4bbdfSmrg        }
150205b261ecSmrg    }
150305b261ecSmrg}
150405b261ecSmrg
150505b261ecSmrg/*
150605b261ecSmrg * winSendMessageToWM - Send a message from the X thread to the WM thread
150705b261ecSmrg */
150805b261ecSmrg
150905b261ecSmrgvoid
151035c4bbdfSmrgwinSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg)
151105b261ecSmrg{
151235c4bbdfSmrg    WMMsgNodePtr pNode;
151335c4bbdfSmrg
151405b261ecSmrg#if CYGMULTIWINDOW_DEBUG
151535c4bbdfSmrg    ErrorF("winSendMessageToWM ()\n");
151605b261ecSmrg#endif
151735c4bbdfSmrg
151835c4bbdfSmrg    pNode = malloc(sizeof(WMMsgNodeRec));
151935c4bbdfSmrg    if (pNode != NULL) {
152035c4bbdfSmrg        memcpy(&pNode->msg, pMsg, sizeof(winWMMessageRec));
152135c4bbdfSmrg        PushMessage(&((WMInfoPtr) pWMInfo)->wmMsgQueue, pNode);
152205b261ecSmrg    }
152305b261ecSmrg}
152405b261ecSmrg
152505b261ecSmrg/*
152605b261ecSmrg * Window manager error handler
152705b261ecSmrg */
152805b261ecSmrg
152905b261ecSmrgstatic int
153035c4bbdfSmrgwinMultiWindowWMErrorHandler(Display * pDisplay, XErrorEvent * pErr)
153105b261ecSmrg{
153235c4bbdfSmrg    char pszErrorMsg[100];
153305b261ecSmrg
153435c4bbdfSmrg    if (pErr->request_code == X_ChangeWindowAttributes
153535c4bbdfSmrg        && pErr->error_code == BadAccess) {
153635c4bbdfSmrg        ErrorF("winMultiWindowWMErrorHandler - ChangeWindowAttributes "
153735c4bbdfSmrg               "BadAccess.\n");
153835c4bbdfSmrg        return 0;
153905b261ecSmrg    }
154005b261ecSmrg
154135c4bbdfSmrg    XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg));
154235c4bbdfSmrg    ErrorF("winMultiWindowWMErrorHandler - ERROR: %s\n", pszErrorMsg);
154335c4bbdfSmrg
154435c4bbdfSmrg    return 0;
154535c4bbdfSmrg}
154605b261ecSmrg
154705b261ecSmrg/*
154805b261ecSmrg * Window manager IO error handler
154905b261ecSmrg */
155005b261ecSmrg
155105b261ecSmrgstatic int
155235c4bbdfSmrgwinMultiWindowWMIOErrorHandler(Display * pDisplay)
155305b261ecSmrg{
155435c4bbdfSmrg    ErrorF("winMultiWindowWMIOErrorHandler!\n");
155505b261ecSmrg
155635c4bbdfSmrg    if (pthread_equal(pthread_self(), g_winMultiWindowWMThread)) {
155735c4bbdfSmrg        if (g_shutdown)
155835c4bbdfSmrg            pthread_exit(NULL);
155905b261ecSmrg
156035c4bbdfSmrg        /* Restart at the main entry point */
156135c4bbdfSmrg        longjmp(g_jmpWMEntry, WIN_JMP_ERROR_IO);
156235c4bbdfSmrg    }
156305b261ecSmrg
156435c4bbdfSmrg    if (g_winMultiWindowWMOldIOErrorHandler)
156535c4bbdfSmrg        g_winMultiWindowWMOldIOErrorHandler(pDisplay);
156635c4bbdfSmrg
156735c4bbdfSmrg    return 0;
156835c4bbdfSmrg}
156905b261ecSmrg
157005b261ecSmrg/*
157105b261ecSmrg * X message procedure error handler
157205b261ecSmrg */
157305b261ecSmrg
157405b261ecSmrgstatic int
157535c4bbdfSmrgwinMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr)
157605b261ecSmrg{
157735c4bbdfSmrg    char pszErrorMsg[100];
157835c4bbdfSmrg
157935c4bbdfSmrg    XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg));
15806747b715Smrg#if CYGMULTIWINDOW_DEBUG
158135c4bbdfSmrg    ErrorF("winMultiWindowXMsgProcErrorHandler - ERROR: %s\n", pszErrorMsg);
15826747b715Smrg#endif
158305b261ecSmrg
158435c4bbdfSmrg    return 0;
158535c4bbdfSmrg}
158605b261ecSmrg
158705b261ecSmrg/*
158805b261ecSmrg * X message procedure IO error handler
158905b261ecSmrg */
159005b261ecSmrg
159105b261ecSmrgstatic int
159235c4bbdfSmrgwinMultiWindowXMsgProcIOErrorHandler(Display * pDisplay)
159305b261ecSmrg{
159435c4bbdfSmrg    ErrorF("winMultiWindowXMsgProcIOErrorHandler!\n");
159505b261ecSmrg
159635c4bbdfSmrg    if (pthread_equal(pthread_self(), g_winMultiWindowXMsgProcThread)) {
159735c4bbdfSmrg        /* Restart at the main entry point */
159835c4bbdfSmrg        longjmp(g_jmpXMsgProcEntry, WIN_JMP_ERROR_IO);
159935c4bbdfSmrg    }
160005b261ecSmrg
160135c4bbdfSmrg    if (g_winMultiWindowXMsgProcOldIOErrorHandler)
160235c4bbdfSmrg        g_winMultiWindowXMsgProcOldIOErrorHandler(pDisplay);
160335c4bbdfSmrg
160435c4bbdfSmrg    return 0;
160535c4bbdfSmrg}
160605b261ecSmrg
160705b261ecSmrg/*
160805b261ecSmrg * Catch RedirectError to detect other window manager running
160905b261ecSmrg */
161005b261ecSmrg
161105b261ecSmrgstatic int
161235c4bbdfSmrgwinRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr)
161305b261ecSmrg{
161435c4bbdfSmrg    redirectError = TRUE;
161535c4bbdfSmrg    return 0;
161605b261ecSmrg}
161705b261ecSmrg
161805b261ecSmrg/*
161905b261ecSmrg * Check if another window manager is running
162005b261ecSmrg */
162105b261ecSmrg
162205b261ecSmrgstatic Bool
162335c4bbdfSmrgCheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen,
162435c4bbdfSmrg                          Bool fAllowOtherWM)
162505b261ecSmrg{
162635c4bbdfSmrg    /*
162735c4bbdfSmrg       Try to select the events which only one client at a time is allowed to select.
162835c4bbdfSmrg       If this causes an error, another window manager is already running...
162935c4bbdfSmrg     */
163035c4bbdfSmrg    redirectError = FALSE;
163135c4bbdfSmrg    XSetErrorHandler(winRedirectErrorHandler);
163235c4bbdfSmrg    XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen),
163335c4bbdfSmrg                 ResizeRedirectMask | SubstructureRedirectMask |
163435c4bbdfSmrg                 ButtonPressMask);
163535c4bbdfSmrg    XSync(pDisplay, 0);
163635c4bbdfSmrg    XSetErrorHandler(winMultiWindowXMsgProcErrorHandler);
163735c4bbdfSmrg
163835c4bbdfSmrg    /*
163935c4bbdfSmrg       Side effect: select the events we are actually interested in...
164035c4bbdfSmrg
164135c4bbdfSmrg       If other WMs are not allowed, also select one of the events which only one client
164235c4bbdfSmrg       at a time is allowed to select, so other window managers won't start...
164335c4bbdfSmrg     */
164435c4bbdfSmrg    XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen),
164535c4bbdfSmrg                 SubstructureNotifyMask | (!fAllowOtherWM ? ButtonPressMask :
164635c4bbdfSmrg                                           0));
164735c4bbdfSmrg    XSync(pDisplay, 0);
164835c4bbdfSmrg    return redirectError;
164905b261ecSmrg}
165005b261ecSmrg
165105b261ecSmrg/*
165205b261ecSmrg * Notify the MWM thread we're exiting and not to reconnect
165305b261ecSmrg */
165405b261ecSmrg
165505b261ecSmrgvoid
165635c4bbdfSmrgwinDeinitMultiWindowWM(void)
165705b261ecSmrg{
165835c4bbdfSmrg    ErrorF("winDeinitMultiWindowWM - Noting shutdown in progress\n");
165935c4bbdfSmrg    g_shutdown = TRUE;
166005b261ecSmrg}
16616747b715Smrg
16626747b715Smrg/* Windows window styles */
166335c4bbdfSmrg#define HINT_NOFRAME	(1L<<0)
16646747b715Smrg#define HINT_BORDER	(1L<<1)
166535c4bbdfSmrg#define HINT_SIZEBOX	(1L<<2)
166635c4bbdfSmrg#define HINT_CAPTION	(1L<<3)
16676747b715Smrg#define HINT_NOMAXIMIZE (1L<<4)
166835c4bbdfSmrg#define HINT_NOMINIMIZE (1L<<5)
166935c4bbdfSmrg#define HINT_NOSYSMENU  (1L<<6)
167035c4bbdfSmrg#define HINT_SKIPTASKBAR (1L<<7)
16716747b715Smrg/* These two are used on their own */
16726747b715Smrg#define HINT_MAX	(1L<<0)
16736747b715Smrg#define HINT_MIN	(1L<<1)
16746747b715Smrg
16756747b715Smrgstatic void
167635c4bbdfSmrgwinApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle)
16776747b715Smrg{
167835c4bbdfSmrg    static Atom windowState, motif_wm_hints, windowType;
167935c4bbdfSmrg    static Atom hiddenState, fullscreenState, belowState, aboveState,
168035c4bbdfSmrg        skiptaskbarState;
168135c4bbdfSmrg    static Atom dockWindow;
168235c4bbdfSmrg    static int generation;
168335c4bbdfSmrg    Atom type, *pAtom = NULL;
168435c4bbdfSmrg    int format;
168535c4bbdfSmrg    unsigned long hint = 0, maxmin = 0, nitems = 0, left = 0;
168635c4bbdfSmrg    unsigned long style, exStyle;
168735c4bbdfSmrg    MwmHints *mwm_hint = NULL;
168835c4bbdfSmrg
168935c4bbdfSmrg    if (!hWnd)
169035c4bbdfSmrg        return;
169135c4bbdfSmrg    if (!IsWindow(hWnd))
169235c4bbdfSmrg        return;
169335c4bbdfSmrg
169435c4bbdfSmrg    if (generation != serverGeneration) {
169535c4bbdfSmrg        generation = serverGeneration;
169635c4bbdfSmrg        windowState = XInternAtom(pDisplay, "_NET_WM_STATE", False);
169735c4bbdfSmrg        motif_wm_hints = XInternAtom(pDisplay, "_MOTIF_WM_HINTS", False);
169835c4bbdfSmrg        windowType = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE", False);
169935c4bbdfSmrg        hiddenState = XInternAtom(pDisplay, "_NET_WM_STATE_HIDDEN", False);
170035c4bbdfSmrg        fullscreenState =
170135c4bbdfSmrg            XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", False);
170235c4bbdfSmrg        belowState = XInternAtom(pDisplay, "_NET_WM_STATE_BELOW", False);
170335c4bbdfSmrg        aboveState = XInternAtom(pDisplay, "_NET_WM_STATE_ABOVE", False);
170435c4bbdfSmrg        dockWindow = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE_DOCK", False);
170535c4bbdfSmrg        skiptaskbarState =
170635c4bbdfSmrg            XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", False);
170735c4bbdfSmrg    }
17086747b715Smrg
170935c4bbdfSmrg    if (XGetWindowProperty(pDisplay, iWindow, windowState, 0L,
171035c4bbdfSmrg                           MAXINT, False, XA_ATOM, &type, &format,
171135c4bbdfSmrg                           &nitems, &left,
171235c4bbdfSmrg                           (unsigned char **) &pAtom) == Success) {
171335c4bbdfSmrg        if (pAtom ) {
171435c4bbdfSmrg            unsigned long i;
171535c4bbdfSmrg
171635c4bbdfSmrg            for (i = 0; i < nitems; i++) {
171735c4bbdfSmrg                if (pAtom[i] == skiptaskbarState)
171835c4bbdfSmrg                    hint |= HINT_SKIPTASKBAR;
171935c4bbdfSmrg                if (pAtom[i] == hiddenState)
172035c4bbdfSmrg                    maxmin |= HINT_MIN;
172135c4bbdfSmrg                else if (pAtom[i] == fullscreenState)
172235c4bbdfSmrg                    maxmin |= HINT_MAX;
172335c4bbdfSmrg                if (pAtom[i] == belowState)
172435c4bbdfSmrg                    *zstyle = HWND_BOTTOM;
172535c4bbdfSmrg                else if (pAtom[i] == aboveState)
172635c4bbdfSmrg                    *zstyle = HWND_TOPMOST;
172735c4bbdfSmrg            }
172835c4bbdfSmrg
172935c4bbdfSmrg            XFree(pAtom);
173035c4bbdfSmrg        }
17316747b715Smrg    }
17326747b715Smrg
173335c4bbdfSmrg    nitems = left = 0;
173435c4bbdfSmrg    if (XGetWindowProperty(pDisplay, iWindow, motif_wm_hints, 0L,
173535c4bbdfSmrg                           PropMwmHintsElements, False, motif_wm_hints, &type,
173635c4bbdfSmrg                           &format, &nitems, &left,
173735c4bbdfSmrg                           (unsigned char **) &mwm_hint) == Success) {
173835c4bbdfSmrg        if (mwm_hint && nitems == PropMwmHintsElements &&
173935c4bbdfSmrg            (mwm_hint->flags & MwmHintsDecorations)) {
174035c4bbdfSmrg            if (!mwm_hint->decorations)
174135c4bbdfSmrg                hint |= (HINT_NOFRAME | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE);
174235c4bbdfSmrg            else if (!(mwm_hint->decorations & MwmDecorAll)) {
174335c4bbdfSmrg                if (mwm_hint->decorations & MwmDecorBorder)
174435c4bbdfSmrg                    hint |= HINT_BORDER;
174535c4bbdfSmrg                if (mwm_hint->decorations & MwmDecorHandle)
174635c4bbdfSmrg                    hint |= HINT_SIZEBOX;
174735c4bbdfSmrg                if (mwm_hint->decorations & MwmDecorTitle)
174835c4bbdfSmrg                    hint |= HINT_CAPTION;
174935c4bbdfSmrg                if (!(mwm_hint->decorations & MwmDecorMenu))
175035c4bbdfSmrg                    hint |= HINT_NOSYSMENU;
175135c4bbdfSmrg                if (!(mwm_hint->decorations & MwmDecorMinimize))
175235c4bbdfSmrg                    hint |= HINT_NOMINIMIZE;
175335c4bbdfSmrg                if (!(mwm_hint->decorations & MwmDecorMaximize))
175435c4bbdfSmrg                    hint |= HINT_NOMAXIMIZE;
175535c4bbdfSmrg            }
175635c4bbdfSmrg            else {
175735c4bbdfSmrg                /*
175835c4bbdfSmrg                   MwmDecorAll means all decorations *except* those specified by other flag
175935c4bbdfSmrg                   bits that are set.  Not yet implemented.
176035c4bbdfSmrg                 */
176135c4bbdfSmrg            }
176235c4bbdfSmrg        }
176335c4bbdfSmrg        if (mwm_hint)
176435c4bbdfSmrg            XFree(mwm_hint);
176535c4bbdfSmrg    }
176635c4bbdfSmrg
176735c4bbdfSmrg    nitems = left = 0;
176835c4bbdfSmrg    pAtom = NULL;
176935c4bbdfSmrg    if (XGetWindowProperty(pDisplay, iWindow, windowType, 0L,
177035c4bbdfSmrg                           1L, False, XA_ATOM, &type, &format,
177135c4bbdfSmrg                           &nitems, &left,
177235c4bbdfSmrg                           (unsigned char **) &pAtom) == Success) {
177335c4bbdfSmrg        if (pAtom && nitems == 1) {
177435c4bbdfSmrg            if (*pAtom == dockWindow) {
177535c4bbdfSmrg                hint = (hint & ~HINT_NOFRAME) | HINT_SKIPTASKBAR | HINT_SIZEBOX;
177635c4bbdfSmrg                *zstyle = HWND_TOPMOST;
177735c4bbdfSmrg            }
177835c4bbdfSmrg        }
177935c4bbdfSmrg        if (pAtom)
178035c4bbdfSmrg            XFree(pAtom);
17816747b715Smrg    }
17826747b715Smrg
17836747b715Smrg    {
178435c4bbdfSmrg        XSizeHints *normal_hint = XAllocSizeHints();
178535c4bbdfSmrg        long supplied;
178635c4bbdfSmrg
178735c4bbdfSmrg        if (normal_hint &&
178835c4bbdfSmrg            XGetWMNormalHints(pDisplay, iWindow, normal_hint, &supplied)) {
178935c4bbdfSmrg            if (normal_hint->flags & PMaxSize) {
179035c4bbdfSmrg                /* Not maximizable if a maximum size is specified */
179135c4bbdfSmrg                hint |= HINT_NOMAXIMIZE;
179235c4bbdfSmrg
179335c4bbdfSmrg                if (normal_hint->flags & PMinSize) {
179435c4bbdfSmrg                    /*
179535c4bbdfSmrg                       If both minimum size and maximum size are specified and are the same,
179635c4bbdfSmrg                       don't bother with a resizing frame
179735c4bbdfSmrg                     */
179835c4bbdfSmrg                    if ((normal_hint->min_width == normal_hint->max_width)
179935c4bbdfSmrg                        && (normal_hint->min_height == normal_hint->max_height))
180035c4bbdfSmrg                        hint = (hint & ~HINT_SIZEBOX);
180135c4bbdfSmrg                }
180235c4bbdfSmrg            }
180335c4bbdfSmrg        }
180435c4bbdfSmrg        XFree(normal_hint);
18056747b715Smrg    }
18066747b715Smrg
180735c4bbdfSmrg    /*
180835c4bbdfSmrg       Override hint settings from above with settings from config file and set
180935c4bbdfSmrg       application id for grouping.
181035c4bbdfSmrg     */
181135c4bbdfSmrg    {
181235c4bbdfSmrg        XClassHint class_hint = { 0, 0 };
181335c4bbdfSmrg        char *window_name = 0;
181435c4bbdfSmrg        char *application_id = 0;
181535c4bbdfSmrg
181635c4bbdfSmrg        if (XGetClassHint(pDisplay, iWindow, &class_hint)) {
181735c4bbdfSmrg            XFetchName(pDisplay, iWindow, &window_name);
181835c4bbdfSmrg
181935c4bbdfSmrg            style =
182035c4bbdfSmrg                winOverrideStyle(class_hint.res_name, class_hint.res_class,
182135c4bbdfSmrg                                 window_name);
182235c4bbdfSmrg
182335c4bbdfSmrg#define APPLICATION_ID_FORMAT	"%s.xwin.%s"
182435c4bbdfSmrg#define APPLICATION_ID_UNKNOWN "unknown"
182535c4bbdfSmrg            if (class_hint.res_class) {
182635c4bbdfSmrg                asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
182735c4bbdfSmrg                         class_hint.res_class);
182835c4bbdfSmrg            }
182935c4bbdfSmrg            else {
183035c4bbdfSmrg                asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
183135c4bbdfSmrg                         APPLICATION_ID_UNKNOWN);
183235c4bbdfSmrg            }
183335c4bbdfSmrg            winSetAppUserModelID(hWnd, application_id);
183435c4bbdfSmrg
183535c4bbdfSmrg            if (class_hint.res_name)
183635c4bbdfSmrg                XFree(class_hint.res_name);
183735c4bbdfSmrg            if (class_hint.res_class)
183835c4bbdfSmrg                XFree(class_hint.res_class);
183935c4bbdfSmrg            if (application_id)
184035c4bbdfSmrg                free(application_id);
184135c4bbdfSmrg            if (window_name)
184235c4bbdfSmrg                XFree(window_name);
184335c4bbdfSmrg        }
184435c4bbdfSmrg        else {
184535c4bbdfSmrg            style = STYLE_NONE;
184635c4bbdfSmrg        }
184735c4bbdfSmrg    }
18486747b715Smrg
184935c4bbdfSmrg    if (style & STYLE_TOPMOST)
185035c4bbdfSmrg        *zstyle = HWND_TOPMOST;
185135c4bbdfSmrg    else if (style & STYLE_MAXIMIZE)
185235c4bbdfSmrg        maxmin = (hint & ~HINT_MIN) | HINT_MAX;
185335c4bbdfSmrg    else if (style & STYLE_MINIMIZE)
185435c4bbdfSmrg        maxmin = (hint & ~HINT_MAX) | HINT_MIN;
185535c4bbdfSmrg    else if (style & STYLE_BOTTOM)
185635c4bbdfSmrg        *zstyle = HWND_BOTTOM;
185735c4bbdfSmrg
185835c4bbdfSmrg    if (maxmin & HINT_MAX)
185935c4bbdfSmrg        SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
186035c4bbdfSmrg    else if (maxmin & HINT_MIN)
186135c4bbdfSmrg        SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
186235c4bbdfSmrg
186335c4bbdfSmrg    if (style & STYLE_NOTITLE)
186435c4bbdfSmrg        hint =
186535c4bbdfSmrg            (hint & ~HINT_NOFRAME & ~HINT_BORDER & ~HINT_CAPTION) |
186635c4bbdfSmrg            HINT_SIZEBOX;
186735c4bbdfSmrg    else if (style & STYLE_OUTLINE)
186835c4bbdfSmrg        hint =
186935c4bbdfSmrg            (hint & ~HINT_NOFRAME & ~HINT_SIZEBOX & ~HINT_CAPTION) |
187035c4bbdfSmrg            HINT_BORDER;
187135c4bbdfSmrg    else if (style & STYLE_NOFRAME)
187235c4bbdfSmrg        hint =
187335c4bbdfSmrg            (hint & ~HINT_BORDER & ~HINT_CAPTION & ~HINT_SIZEBOX) |
187435c4bbdfSmrg            HINT_NOFRAME;
187535c4bbdfSmrg
187635c4bbdfSmrg    /* Now apply styles to window */
187735c4bbdfSmrg    style = GetWindowLongPtr(hWnd, GWL_STYLE);
187835c4bbdfSmrg    if (!style)
187935c4bbdfSmrg        return;                 /* GetWindowLongPointer returns 0 on failure, we hope this isn't a valid style */
188035c4bbdfSmrg
188135c4bbdfSmrg    style &= ~WS_CAPTION & ~WS_SIZEBOX; /* Just in case */
188235c4bbdfSmrg
188335c4bbdfSmrg    if (!(hint & ~HINT_SKIPTASKBAR))    /* No hints, default */
188435c4bbdfSmrg        style = style | WS_CAPTION | WS_SIZEBOX;
188535c4bbdfSmrg    else if (hint & HINT_NOFRAME)       /* No frame, no decorations */
188635c4bbdfSmrg        style = style & ~WS_CAPTION & ~WS_SIZEBOX;
188735c4bbdfSmrg    else
188835c4bbdfSmrg        style = style | ((hint & HINT_BORDER) ? WS_BORDER : 0) |
188935c4bbdfSmrg            ((hint & HINT_SIZEBOX) ? WS_SIZEBOX : 0) |
189035c4bbdfSmrg            ((hint & HINT_CAPTION) ? WS_CAPTION : 0);
189135c4bbdfSmrg
189235c4bbdfSmrg    if (hint & HINT_NOMAXIMIZE)
189335c4bbdfSmrg        style = style & ~WS_MAXIMIZEBOX;
189435c4bbdfSmrg
189535c4bbdfSmrg    if (hint & HINT_NOMINIMIZE)
189635c4bbdfSmrg        style = style & ~WS_MINIMIZEBOX;
189735c4bbdfSmrg
189835c4bbdfSmrg    if (hint & HINT_NOSYSMENU)
189935c4bbdfSmrg        style = style & ~WS_SYSMENU;
190035c4bbdfSmrg
190135c4bbdfSmrg    if (hint & HINT_SKIPTASKBAR)
190235c4bbdfSmrg        style = style & ~WS_MINIMIZEBOX;        /* window will become lost if minimized */
190335c4bbdfSmrg
190435c4bbdfSmrg    SetWindowLongPtr(hWnd, GWL_STYLE, style);
190535c4bbdfSmrg
190635c4bbdfSmrg    exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
190735c4bbdfSmrg    if (hint & HINT_SKIPTASKBAR)
190835c4bbdfSmrg        exStyle = (exStyle & ~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW;
190935c4bbdfSmrg    else
191035c4bbdfSmrg        exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW;
191135c4bbdfSmrg    SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle);
191235c4bbdfSmrg
191335c4bbdfSmrg    winDebug
191435c4bbdfSmrg        ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n",
191535c4bbdfSmrg         iWindow, hint, style, exStyle);
19166747b715Smrg}
19176747b715Smrg
19186747b715Smrgvoid
191935c4bbdfSmrgwinUpdateWindowPosition(HWND hWnd, HWND * zstyle)
19206747b715Smrg{
192135c4bbdfSmrg    int iX, iY, iWidth, iHeight;
192235c4bbdfSmrg    int iDx, iDy;
192335c4bbdfSmrg    RECT rcNew;
192435c4bbdfSmrg    WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP);
192535c4bbdfSmrg    DrawablePtr pDraw = NULL;
192635c4bbdfSmrg
192735c4bbdfSmrg    if (!pWin)
192835c4bbdfSmrg        return;
192935c4bbdfSmrg    pDraw = &pWin->drawable;
193035c4bbdfSmrg    if (!pDraw)
193135c4bbdfSmrg        return;
193235c4bbdfSmrg
193335c4bbdfSmrg    /* Get the X and Y location of the X window */
193435c4bbdfSmrg    iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN);
193535c4bbdfSmrg    iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN);
193635c4bbdfSmrg
193735c4bbdfSmrg    /* Get the height and width of the X window */
193835c4bbdfSmrg    iWidth = pWin->drawable.width;
193935c4bbdfSmrg    iHeight = pWin->drawable.height;
194035c4bbdfSmrg
194135c4bbdfSmrg    /* Setup a rectangle with the X window position and size */
194235c4bbdfSmrg    SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight);
194335c4bbdfSmrg
194435c4bbdfSmrg    winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n",
194535c4bbdfSmrg             rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
194635c4bbdfSmrg
194735c4bbdfSmrg    AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE,
194835c4bbdfSmrg                       GetWindowLongPtr(hWnd, GWL_EXSTYLE));
194935c4bbdfSmrg
195035c4bbdfSmrg    /* Don't allow window decoration to disappear off to top-left as a result of this adjustment */
195135c4bbdfSmrg    if (rcNew.left < GetSystemMetrics(SM_XVIRTUALSCREEN)) {
195235c4bbdfSmrg        iDx = GetSystemMetrics(SM_XVIRTUALSCREEN) - rcNew.left;
195335c4bbdfSmrg        rcNew.left += iDx;
195435c4bbdfSmrg        rcNew.right += iDx;
19556747b715Smrg    }
19566747b715Smrg
195735c4bbdfSmrg    if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) {
195835c4bbdfSmrg        iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top;
195935c4bbdfSmrg        rcNew.top += iDy;
196035c4bbdfSmrg        rcNew.bottom += iDy;
19616747b715Smrg    }
19626747b715Smrg
196335c4bbdfSmrg    winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n",
196435c4bbdfSmrg             rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
19656747b715Smrg
196635c4bbdfSmrg    /* Position the Windows window */
196735c4bbdfSmrg    SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top,
196835c4bbdfSmrg                 rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0);
19696747b715Smrg
19706747b715Smrg}
1971