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
481b5d61b8Smrg#include <xcb/xcb.h>
491b5d61b8Smrg#include <xcb/xcb_icccm.h>
501b5d61b8Smrg#include <xcb/xcb_ewmh.h>
511b5d61b8Smrg#include <xcb/xcb_aux.h>
52ed6184dfSmrg#include <xcb/composite.h>
531b5d61b8Smrg
546747b715Smrg#include <X11/Xwindows.h>
5505b261ecSmrg
5605b261ecSmrg/* Local headers */
571b5d61b8Smrg#include "X11/Xdefs.h" // for Bool type
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"
651b5d61b8Smrg#include "winmultiwindowicons.h"
66ed6184dfSmrg#include "winauth.h"
676747b715Smrg
686747b715Smrg/* We need the native HWND atom for intWM, so for consistency use the
691b5d61b8Smrg   same name as extWM does */
706747b715Smrg#define WINDOWSWM_NATIVE_HWND "_WINDOWSWM_NATIVE_HWND"
7105b261ecSmrg
7235c4bbdfSmrg#ifndef HOST_NAME_MAX
7335c4bbdfSmrg#define HOST_NAME_MAX 255
7435c4bbdfSmrg#endif
7535c4bbdfSmrg
7605b261ecSmrgextern void winDebug(const char *format, ...);
776747b715Smrgextern void winReshapeMultiWindow(WindowPtr pWin);
786747b715Smrgextern void winUpdateRgnMultiWindow(WindowPtr pWin);
7905b261ecSmrg
8005b261ecSmrg#ifndef CYGDEBUG
8105b261ecSmrg#define CYGDEBUG NO
8205b261ecSmrg#endif
8305b261ecSmrg
8405b261ecSmrg/*
8505b261ecSmrg * Constant defines
8605b261ecSmrg */
8705b261ecSmrg
8805b261ecSmrg#define WIN_CONNECT_RETRIES	5
8905b261ecSmrg#define WIN_CONNECT_DELAY	5
9005b261ecSmrg#ifdef HAS_DEVWINDOWS
9135c4bbdfSmrg#define WIN_MSG_QUEUE_FNAME	"/dev/windows"
9205b261ecSmrg#endif
9305b261ecSmrg
9405b261ecSmrg/*
9505b261ecSmrg * Local structures
9605b261ecSmrg */
9705b261ecSmrg
9805b261ecSmrgtypedef struct _WMMsgNodeRec {
9935c4bbdfSmrg    winWMMessageRec msg;
10035c4bbdfSmrg    struct _WMMsgNodeRec *pNext;
10105b261ecSmrg} WMMsgNodeRec, *WMMsgNodePtr;
10205b261ecSmrg
10305b261ecSmrgtypedef struct _WMMsgQueueRec {
10435c4bbdfSmrg    struct _WMMsgNodeRec *pHead;
10535c4bbdfSmrg    struct _WMMsgNodeRec *pTail;
10635c4bbdfSmrg    pthread_mutex_t pmMutex;
10735c4bbdfSmrg    pthread_cond_t pcNotEmpty;
10805b261ecSmrg} WMMsgQueueRec, *WMMsgQueuePtr;
10905b261ecSmrg
11005b261ecSmrgtypedef struct _WMInfo {
1111b5d61b8Smrg    xcb_connection_t *conn;
11235c4bbdfSmrg    WMMsgQueueRec wmMsgQueue;
1131b5d61b8Smrg    xcb_atom_t atmWmProtos;
1141b5d61b8Smrg    xcb_atom_t atmWmDelete;
1151b5d61b8Smrg    xcb_atom_t atmWmTakeFocus;
1161b5d61b8Smrg    xcb_atom_t atmPrivMap;
1171b5d61b8Smrg    xcb_atom_t atmUtf8String;
1181b5d61b8Smrg    xcb_atom_t atmNetWmName;
119ed6184dfSmrg    xcb_atom_t atmCurrentDesktop;
120ed6184dfSmrg    xcb_atom_t atmNumberDesktops;
121ed6184dfSmrg    xcb_atom_t atmDesktopNames;
1221b5d61b8Smrg    xcb_ewmh_connection_t ewmh;
123ed6184dfSmrg    Bool fCompositeWM;
12405b261ecSmrg} WMInfoRec, *WMInfoPtr;
12505b261ecSmrg
12605b261ecSmrgtypedef struct _WMProcArgRec {
12735c4bbdfSmrg    DWORD dwScreen;
12835c4bbdfSmrg    WMInfoPtr pWMInfo;
12935c4bbdfSmrg    pthread_mutex_t *ppmServerStarted;
13005b261ecSmrg} WMProcArgRec, *WMProcArgPtr;
13105b261ecSmrg
13205b261ecSmrgtypedef struct _XMsgProcArgRec {
1331b5d61b8Smrg    xcb_connection_t *conn;
13435c4bbdfSmrg    DWORD dwScreen;
13535c4bbdfSmrg    WMInfoPtr pWMInfo;
13635c4bbdfSmrg    pthread_mutex_t *ppmServerStarted;
13735c4bbdfSmrg    HWND hwndScreen;
13805b261ecSmrg} XMsgProcArgRec, *XMsgProcArgPtr;
13905b261ecSmrg
14005b261ecSmrg/*
14105b261ecSmrg * Prototypes for local functions
14205b261ecSmrg */
14305b261ecSmrg
14405b261ecSmrgstatic void
14535c4bbdfSmrg PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode);
14605b261ecSmrg
14735c4bbdfSmrgstatic WMMsgNodePtr PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo);
14805b261ecSmrg
14905b261ecSmrgstatic Bool
15035c4bbdfSmrg InitQueue(WMMsgQueuePtr pQueue);
15105b261ecSmrg
15205b261ecSmrgstatic void
1531b5d61b8Smrg GetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName);
15405b261ecSmrg
1551b5d61b8Smrgstatic void
1561b5d61b8Smrg SendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData);
15705b261ecSmrg
15805b261ecSmrgstatic void
1591b5d61b8Smrg UpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow);
16005b261ecSmrg
16135c4bbdfSmrgstatic void *winMultiWindowWMProc(void *pArg);
16205b261ecSmrg
16335c4bbdfSmrgstatic void *winMultiWindowXMsgProc(void *pArg);
16405b261ecSmrg
16505b261ecSmrgstatic void
16635c4bbdfSmrg winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg);
16705b261ecSmrg
16805b261ecSmrg#if 0
16905b261ecSmrgstatic void
1701b5d61b8Smrg PreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction);
17105b261ecSmrg#endif
17205b261ecSmrg
17305b261ecSmrgstatic Bool
1741b5d61b8SmrgCheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen);
17505b261ecSmrg
1766747b715Smrgstatic void
1771b5d61b8Smrg winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle);
1786747b715Smrg
1796747b715Smrgvoid
18035c4bbdfSmrg winUpdateWindowPosition(HWND hWnd, HWND * zstyle);
18105b261ecSmrg
18205b261ecSmrg/*
18305b261ecSmrg * Local globals
18405b261ecSmrg */
18505b261ecSmrg
18635c4bbdfSmrgstatic Bool g_shutdown = FALSE;
1871b5d61b8Smrg
1881b5d61b8Smrg/*
1891b5d61b8Smrg * Translate msg id to text, for debug purposes
1901b5d61b8Smrg */
1911b5d61b8Smrg
1921b5d61b8Smrg#if CYGMULTIWINDOW_DEBUG
1931b5d61b8Smrgstatic const char *
1941b5d61b8SmrgMessageName(winWMMessagePtr msg)
1951b5d61b8Smrg{
1961b5d61b8Smrg  switch (msg->msg)
1971b5d61b8Smrg    {
1981b5d61b8Smrg    case WM_WM_MOVE:
1991b5d61b8Smrg      return "WM_WM_MOVE";
2001b5d61b8Smrg      break;
2011b5d61b8Smrg    case WM_WM_SIZE:
2021b5d61b8Smrg      return "WM_WM_SIZE";
2031b5d61b8Smrg      break;
2041b5d61b8Smrg    case WM_WM_RAISE:
2051b5d61b8Smrg      return "WM_WM_RAISE";
2061b5d61b8Smrg      break;
2071b5d61b8Smrg    case WM_WM_LOWER:
2081b5d61b8Smrg      return "WM_WM_LOWER";
2091b5d61b8Smrg      break;
2101b5d61b8Smrg    case WM_WM_UNMAP:
2111b5d61b8Smrg      return "WM_WM_UNMAP";
2121b5d61b8Smrg      break;
2131b5d61b8Smrg    case WM_WM_KILL:
2141b5d61b8Smrg      return "WM_WM_KILL";
2151b5d61b8Smrg      break;
2161b5d61b8Smrg    case WM_WM_ACTIVATE:
2171b5d61b8Smrg      return "WM_WM_ACTIVATE";
2181b5d61b8Smrg      break;
2191b5d61b8Smrg    case WM_WM_NAME_EVENT:
2201b5d61b8Smrg      return "WM_WM_NAME_EVENT";
2211b5d61b8Smrg      break;
2221b5d61b8Smrg    case WM_WM_ICON_EVENT:
2231b5d61b8Smrg      return "WM_WM_ICON_EVENT";
2241b5d61b8Smrg      break;
2251b5d61b8Smrg    case WM_WM_CHANGE_STATE:
2261b5d61b8Smrg      return "WM_WM_CHANGE_STATE";
2271b5d61b8Smrg      break;
228ed6184dfSmrg    case WM_WM_MAP_UNMANAGED:
229ed6184dfSmrg      return "WM_WM_MAP_UNMANAGED";
2301b5d61b8Smrg      break;
231ed6184dfSmrg    case WM_WM_MAP_MANAGED:
232ed6184dfSmrg      return "WM_WM_MAP_MANAGED";
2331b5d61b8Smrg      break;
2341b5d61b8Smrg    case WM_WM_HINTS_EVENT:
2351b5d61b8Smrg      return "WM_WM_HINTS_EVENT";
2361b5d61b8Smrg      break;
2371b5d61b8Smrg    default:
2381b5d61b8Smrg      return "Unknown Message";
2391b5d61b8Smrg      break;
2401b5d61b8Smrg    }
2411b5d61b8Smrg}
2421b5d61b8Smrg#endif
2431b5d61b8Smrg
24405b261ecSmrg
24505b261ecSmrg/*
24605b261ecSmrg * PushMessage - Push a message onto the queue
24705b261ecSmrg */
24805b261ecSmrg
24905b261ecSmrgstatic void
25035c4bbdfSmrgPushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode)
25105b261ecSmrg{
25205b261ecSmrg
25335c4bbdfSmrg    /* Lock the queue mutex */
25435c4bbdfSmrg    pthread_mutex_lock(&pQueue->pmMutex);
25505b261ecSmrg
25635c4bbdfSmrg    pNode->pNext = NULL;
25735c4bbdfSmrg
25835c4bbdfSmrg    if (pQueue->pTail != NULL) {
25935c4bbdfSmrg        pQueue->pTail->pNext = pNode;
26005b261ecSmrg    }
26135c4bbdfSmrg    pQueue->pTail = pNode;
26205b261ecSmrg
26335c4bbdfSmrg    if (pQueue->pHead == NULL) {
26435c4bbdfSmrg        pQueue->pHead = pNode;
26535c4bbdfSmrg    }
26605b261ecSmrg
26735c4bbdfSmrg    /* Release the queue mutex */
26835c4bbdfSmrg    pthread_mutex_unlock(&pQueue->pmMutex);
26905b261ecSmrg
27035c4bbdfSmrg    /* Signal that the queue is not empty */
27135c4bbdfSmrg    pthread_cond_signal(&pQueue->pcNotEmpty);
27205b261ecSmrg}
27305b261ecSmrg
27405b261ecSmrg/*
27505b261ecSmrg * PopMessage - Pop a message from the queue
27605b261ecSmrg */
27705b261ecSmrg
27805b261ecSmrgstatic WMMsgNodePtr
27935c4bbdfSmrgPopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo)
28005b261ecSmrg{
28135c4bbdfSmrg    WMMsgNodePtr pNode;
28205b261ecSmrg
28335c4bbdfSmrg    /* Lock the queue mutex */
28435c4bbdfSmrg    pthread_mutex_lock(&pQueue->pmMutex);
28505b261ecSmrg
28635c4bbdfSmrg    /* Wait for --- */
28735c4bbdfSmrg    while (pQueue->pHead == NULL) {
28835c4bbdfSmrg        pthread_cond_wait(&pQueue->pcNotEmpty, &pQueue->pmMutex);
28905b261ecSmrg    }
29035c4bbdfSmrg
29135c4bbdfSmrg    pNode = pQueue->pHead;
29235c4bbdfSmrg    if (pQueue->pHead != NULL) {
29335c4bbdfSmrg        pQueue->pHead = pQueue->pHead->pNext;
29405b261ecSmrg    }
29505b261ecSmrg
29635c4bbdfSmrg    if (pQueue->pTail == pNode) {
29735c4bbdfSmrg        pQueue->pTail = NULL;
29805b261ecSmrg    }
29905b261ecSmrg
30035c4bbdfSmrg    /* Release the queue mutex */
30135c4bbdfSmrg    pthread_mutex_unlock(&pQueue->pmMutex);
30205b261ecSmrg
30335c4bbdfSmrg    return pNode;
30435c4bbdfSmrg}
30505b261ecSmrg
30605b261ecSmrg#if 0
30705b261ecSmrg/*
30835c4bbdfSmrg * HaveMessage -
30905b261ecSmrg */
31005b261ecSmrg
31105b261ecSmrgstatic Bool
3121b5d61b8SmrgHaveMessage(WMMsgQueuePtr pQueue, UINT msg, xcb_window_t iWindow)
31305b261ecSmrg{
31435c4bbdfSmrg    WMMsgNodePtr pNode;
31535c4bbdfSmrg
31635c4bbdfSmrg    for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) {
31735c4bbdfSmrg        if (pNode->msg.msg == msg && pNode->msg.iWindow == iWindow)
31835c4bbdfSmrg            return True;
31905b261ecSmrg    }
32035c4bbdfSmrg
32135c4bbdfSmrg    return False;
32205b261ecSmrg}
32305b261ecSmrg#endif
32405b261ecSmrg
32505b261ecSmrg/*
32605b261ecSmrg * InitQueue - Initialize the Window Manager message queue
32705b261ecSmrg */
32805b261ecSmrg
32905b261ecSmrgstatic
33035c4bbdfSmrg    Bool
33135c4bbdfSmrgInitQueue(WMMsgQueuePtr pQueue)
33205b261ecSmrg{
33335c4bbdfSmrg    /* Check if the pQueue pointer is NULL */
33435c4bbdfSmrg    if (pQueue == NULL) {
33535c4bbdfSmrg        ErrorF("InitQueue - pQueue is NULL.  Exiting.\n");
33635c4bbdfSmrg        return FALSE;
33705b261ecSmrg    }
33805b261ecSmrg
33935c4bbdfSmrg    /* Set the head and tail to NULL */
34035c4bbdfSmrg    pQueue->pHead = NULL;
34135c4bbdfSmrg    pQueue->pTail = NULL;
34205b261ecSmrg
34335c4bbdfSmrg    winDebug("InitQueue - Calling pthread_mutex_init\n");
34405b261ecSmrg
34535c4bbdfSmrg    /* Create synchronization objects */
34635c4bbdfSmrg    pthread_mutex_init(&pQueue->pmMutex, NULL);
34705b261ecSmrg
34835c4bbdfSmrg    winDebug("InitQueue - pthread_mutex_init returned\n");
34935c4bbdfSmrg    winDebug("InitQueue - Calling pthread_cond_init\n");
35005b261ecSmrg
35135c4bbdfSmrg    pthread_cond_init(&pQueue->pcNotEmpty, NULL);
35205b261ecSmrg
35335c4bbdfSmrg    winDebug("InitQueue - pthread_cond_init returned\n");
35405b261ecSmrg
35535c4bbdfSmrg    return TRUE;
35605b261ecSmrg}
35705b261ecSmrg
35835c4bbdfSmrgstatic
35935c4bbdfSmrgchar *
3601b5d61b8SmrgXutf8TextPropertyToString(WMInfoPtr pWMInfo, xcb_icccm_get_text_property_reply_t *xtp)
36135c4bbdfSmrg{
36235c4bbdfSmrg    char *pszReturnData;
36335c4bbdfSmrg
3641b5d61b8Smrg    if ((xtp->encoding == XCB_ATOM_STRING) ||        // Latin1 ISO 8859-1
3651b5d61b8Smrg        (xtp->encoding == pWMInfo->atmUtf8String)) { // UTF-8  ISO 10646
3661b5d61b8Smrg        pszReturnData = strndup(xtp->name, xtp->name_len);
36735c4bbdfSmrg    }
36835c4bbdfSmrg    else {
3691b5d61b8Smrg        // Converting from COMPOUND_TEXT to UTF-8 properly is complex to
3701b5d61b8Smrg        // implement, and not very much use unless you have an old
3711b5d61b8Smrg        // application which isn't UTF-8 aware.
3721b5d61b8Smrg        ErrorF("Xutf8TextPropertyToString: text encoding %d is not implemented\n", xtp->encoding);
3731b5d61b8Smrg        pszReturnData = strdup("");
37435c4bbdfSmrg    }
37535c4bbdfSmrg
37635c4bbdfSmrg    return pszReturnData;
37735c4bbdfSmrg}
37805b261ecSmrg
37905b261ecSmrg/*
38005b261ecSmrg * GetWindowName - Retrieve the title of an X Window
38105b261ecSmrg */
38205b261ecSmrg
38305b261ecSmrgstatic void
3841b5d61b8SmrgGetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName)
38505b261ecSmrg{
3861b5d61b8Smrg    xcb_connection_t *conn = pWMInfo->conn;
3871b5d61b8Smrg    char *pszWindowName = NULL;
38835c4bbdfSmrg
38905b261ecSmrg#if CYGMULTIWINDOW_DEBUG
39035c4bbdfSmrg    ErrorF("GetWindowName\n");
39105b261ecSmrg#endif
39205b261ecSmrg
3931b5d61b8Smrg    /* Try to get window name from _NET_WM_NAME */
3941b5d61b8Smrg    {
3951b5d61b8Smrg        xcb_get_property_cookie_t cookie;
3961b5d61b8Smrg        xcb_get_property_reply_t *reply;
3971b5d61b8Smrg
3981b5d61b8Smrg        cookie = xcb_get_property(pWMInfo->conn, FALSE, iWin,
3991b5d61b8Smrg                                  pWMInfo->atmNetWmName,
4001b5d61b8Smrg                                  XCB_GET_PROPERTY_TYPE_ANY, 0, INT_MAX);
4011b5d61b8Smrg        reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL);
4021b5d61b8Smrg        if (reply && (reply->type != XCB_NONE)) {
4031b5d61b8Smrg            pszWindowName = strndup(xcb_get_property_value(reply),
4041b5d61b8Smrg                                    xcb_get_property_value_length(reply));
4051b5d61b8Smrg            free(reply);
4061b5d61b8Smrg        }
40705b261ecSmrg    }
40805b261ecSmrg
4091b5d61b8Smrg    /* Otherwise, try to get window name from WM_NAME */
4101b5d61b8Smrg    if (!pszWindowName)
4111b5d61b8Smrg        {
4121b5d61b8Smrg            xcb_get_property_cookie_t cookie;
4131b5d61b8Smrg            xcb_icccm_get_text_property_reply_t reply;
4141b5d61b8Smrg
4151b5d61b8Smrg            cookie = xcb_icccm_get_wm_name(conn, iWin);
4161b5d61b8Smrg            if (!xcb_icccm_get_wm_name_reply(conn, cookie, &reply, NULL)) {
4171b5d61b8Smrg                ErrorF("GetWindowName - xcb_icccm_get_wm_name_reply failed.  No name.\n");
4181b5d61b8Smrg                *ppWindowName = NULL;
4191b5d61b8Smrg                return;
4201b5d61b8Smrg            }
4211b5d61b8Smrg
4221b5d61b8Smrg            pszWindowName = Xutf8TextPropertyToString(pWMInfo, &reply);
4231b5d61b8Smrg            xcb_icccm_get_text_property_reply_wipe(&reply);
4241b5d61b8Smrg        }
4251b5d61b8Smrg
4261b5d61b8Smrg    /* return the window name, unless... */
4271b5d61b8Smrg    *ppWindowName = pszWindowName;
42835c4bbdfSmrg
42935c4bbdfSmrg    if (g_fHostInTitle) {
4301b5d61b8Smrg        xcb_get_property_cookie_t cookie;
4311b5d61b8Smrg        xcb_icccm_get_text_property_reply_t reply;
4321b5d61b8Smrg
43335c4bbdfSmrg        /* Try to get client machine name */
4341b5d61b8Smrg        cookie = xcb_icccm_get_wm_client_machine(conn, iWin);
4351b5d61b8Smrg        if (xcb_icccm_get_wm_client_machine_reply(conn, cookie, &reply, NULL)) {
4361b5d61b8Smrg            char *pszClientMachine;
4371b5d61b8Smrg            char *pszClientHostname;
4381b5d61b8Smrg            char *dot;
4391b5d61b8Smrg            char hostname[HOST_NAME_MAX + 1];
4401b5d61b8Smrg
4411b5d61b8Smrg            pszClientMachine = Xutf8TextPropertyToString(pWMInfo, &reply);
4421b5d61b8Smrg            xcb_icccm_get_text_property_reply_wipe(&reply);
4431b5d61b8Smrg
4441b5d61b8Smrg            /* If client machine name looks like a FQDN, find the hostname */
4451b5d61b8Smrg            pszClientHostname = strdup(pszClientMachine);
4461b5d61b8Smrg            dot = strchr(pszClientHostname, '.');
4471b5d61b8Smrg            if (dot)
4481b5d61b8Smrg                *dot = '\0';
44935c4bbdfSmrg
45035c4bbdfSmrg            /*
4511b5d61b8Smrg               If we have a client machine hostname
4521b5d61b8Smrg               and it's not the local hostname
45335c4bbdfSmrg               and it's not already in the window title...
45435c4bbdfSmrg             */
4551b5d61b8Smrg            if (strlen(pszClientHostname) &&
45635c4bbdfSmrg                !gethostname(hostname, HOST_NAME_MAX + 1) &&
4571b5d61b8Smrg                strcmp(hostname, pszClientHostname) &&
4581b5d61b8Smrg                (strstr(pszWindowName, pszClientHostname) == 0)) {
45935c4bbdfSmrg                /* ... add '@<clientmachine>' to end of window name */
46035c4bbdfSmrg                *ppWindowName =
46135c4bbdfSmrg                    malloc(strlen(pszWindowName) +
46235c4bbdfSmrg                           strlen(pszClientMachine) + 2);
46335c4bbdfSmrg                strcpy(*ppWindowName, pszWindowName);
46435c4bbdfSmrg                strcat(*ppWindowName, "@");
46535c4bbdfSmrg                strcat(*ppWindowName, pszClientMachine);
46635c4bbdfSmrg
46735c4bbdfSmrg                free(pszWindowName);
46835c4bbdfSmrg            }
4691b5d61b8Smrg
4701b5d61b8Smrg            free(pszClientMachine);
4711b5d61b8Smrg            free(pszClientHostname);
47235c4bbdfSmrg        }
47335c4bbdfSmrg    }
47405b261ecSmrg}
47505b261ecSmrg
47635c4bbdfSmrg/*
47735c4bbdfSmrg * Does the client support the specified WM_PROTOCOLS protocol?
47835c4bbdfSmrg */
47935c4bbdfSmrg
48035c4bbdfSmrgstatic Bool
4811b5d61b8SmrgIsWmProtocolAvailable(WMInfoPtr pWMInfo, xcb_window_t iWindow, xcb_atom_t atmProtocol)
48235c4bbdfSmrg{
4831b5d61b8Smrg  int i, found = 0;
4841b5d61b8Smrg  xcb_get_property_cookie_t cookie;
4851b5d61b8Smrg  xcb_icccm_get_wm_protocols_reply_t reply;
4861b5d61b8Smrg  xcb_connection_t *conn = pWMInfo->conn;
4871b5d61b8Smrg
4881b5d61b8Smrg  cookie = xcb_icccm_get_wm_protocols(conn, iWindow, pWMInfo->ewmh.WM_PROTOCOLS);
4891b5d61b8Smrg  if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &reply, NULL)) {
4901b5d61b8Smrg    for (i = 0; i < reply.atoms_len; ++i)
4911b5d61b8Smrg      if (reply.atoms[i] == atmProtocol) {
4921b5d61b8Smrg              ++found;
4931b5d61b8Smrg              break;
4941b5d61b8Smrg      }
4951b5d61b8Smrg    xcb_icccm_get_wm_protocols_reply_wipe(&reply);
49635c4bbdfSmrg  }
49735c4bbdfSmrg
49835c4bbdfSmrg  return found > 0;
49935c4bbdfSmrg}
50005b261ecSmrg
50105b261ecSmrg/*
50205b261ecSmrg * Send a message to the X server from the WM thread
50305b261ecSmrg */
50405b261ecSmrg
5051b5d61b8Smrgstatic void
5061b5d61b8SmrgSendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData)
50705b261ecSmrg{
5081b5d61b8Smrg    xcb_client_message_event_t e;
50935c4bbdfSmrg
51035c4bbdfSmrg    /* Prepare the X event structure */
5111b5d61b8Smrg    memset(&e, 0, sizeof(e));
5121b5d61b8Smrg    e.response_type = XCB_CLIENT_MESSAGE;
5131b5d61b8Smrg    e.window = iWin;
5141b5d61b8Smrg    e.type = atmType;
5151b5d61b8Smrg    e.format = 32;
5161b5d61b8Smrg    e.data.data32[0] = nData;
5171b5d61b8Smrg    e.data.data32[1] = XCB_CURRENT_TIME;
51835c4bbdfSmrg
51935c4bbdfSmrg    /* Send the event to X */
5201b5d61b8Smrg    xcb_send_event(conn, FALSE, iWin, XCB_EVENT_MASK_NO_EVENT, (const char *)&e);
52105b261ecSmrg}
52205b261ecSmrg
52335c4bbdfSmrg/*
52435c4bbdfSmrg * See if we can get the stored HWND for this window...
52535c4bbdfSmrg */
52635c4bbdfSmrgstatic HWND
5271b5d61b8SmrggetHwnd(WMInfoPtr pWMInfo, xcb_window_t iWindow)
52835c4bbdfSmrg{
5291b5d61b8Smrg    HWND hWnd = NULL;
5301b5d61b8Smrg    xcb_get_property_cookie_t cookie;
5311b5d61b8Smrg    xcb_get_property_reply_t *reply;
5321b5d61b8Smrg
5331b5d61b8Smrg    cookie = xcb_get_property(pWMInfo->conn, FALSE, iWindow, pWMInfo->atmPrivMap,
5341b5d61b8Smrg                              XCB_ATOM_INTEGER, 0L, sizeof(HWND)/4L);
5351b5d61b8Smrg    reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL);
5361b5d61b8Smrg
5371b5d61b8Smrg    if (reply) {
5381b5d61b8Smrg        int length = xcb_get_property_value_length(reply);
5391b5d61b8Smrg        HWND *value = xcb_get_property_value(reply);
5401b5d61b8Smrg
5411b5d61b8Smrg        if (value && (length == sizeof(HWND))) {
5421b5d61b8Smrg            hWnd = *value;
54335c4bbdfSmrg        }
5441b5d61b8Smrg        free(reply);
54535c4bbdfSmrg    }
54635c4bbdfSmrg
54735c4bbdfSmrg    /* Some sanity checks */
54835c4bbdfSmrg    if (!hWnd)
54935c4bbdfSmrg        return NULL;
55035c4bbdfSmrg    if (!IsWindow(hWnd))
55135c4bbdfSmrg        return NULL;
55235c4bbdfSmrg
55335c4bbdfSmrg    return hWnd;
55435c4bbdfSmrg}
55505b261ecSmrg
5561b5d61b8Smrg/*
5571b5d61b8Smrg * Helper function to check for override-redirect
5581b5d61b8Smrg */
5591b5d61b8Smrgstatic Bool
5601b5d61b8SmrgIsOverrideRedirect(xcb_connection_t *conn, xcb_window_t iWin)
5611b5d61b8Smrg{
5621b5d61b8Smrg    Bool result = FALSE;
5631b5d61b8Smrg    xcb_get_window_attributes_reply_t *reply;
5641b5d61b8Smrg    xcb_get_window_attributes_cookie_t cookie;
5651b5d61b8Smrg
5661b5d61b8Smrg    cookie = xcb_get_window_attributes(conn, iWin);
5671b5d61b8Smrg    reply = xcb_get_window_attributes_reply(conn, cookie, NULL);
5681b5d61b8Smrg    if (reply) {
5691b5d61b8Smrg        result = (reply->override_redirect != 0);
5701b5d61b8Smrg        free(reply);
5711b5d61b8Smrg    }
5721b5d61b8Smrg    else {
5731b5d61b8Smrg        ErrorF("IsOverrideRedirect: Failed to get window attributes\n");
5741b5d61b8Smrg    }
5751b5d61b8Smrg
5761b5d61b8Smrg    return result;
5771b5d61b8Smrg}
5781b5d61b8Smrg
5791b5d61b8Smrg/*
5801b5d61b8Smrg * Helper function to get class and window names
5811b5d61b8Smrg*/
5821b5d61b8Smrgstatic void
5831b5d61b8SmrgGetClassNames(WMInfoPtr pWMInfo, xcb_window_t iWindow, char **res_name,
5841b5d61b8Smrg              char **res_class, char **window_name)
5851b5d61b8Smrg{
5861b5d61b8Smrg    xcb_get_property_cookie_t cookie1;
5871b5d61b8Smrg    xcb_icccm_get_wm_class_reply_t reply1;
5881b5d61b8Smrg    xcb_get_property_cookie_t cookie2;
5891b5d61b8Smrg    xcb_icccm_get_text_property_reply_t reply2;
5901b5d61b8Smrg
5911b5d61b8Smrg    cookie1 = xcb_icccm_get_wm_class(pWMInfo->conn, iWindow);
5921b5d61b8Smrg    if (xcb_icccm_get_wm_class_reply(pWMInfo->conn, cookie1, &reply1,
5931b5d61b8Smrg                                     NULL)) {
5941b5d61b8Smrg        *res_name = strdup(reply1.instance_name);
5951b5d61b8Smrg        *res_class = strdup(reply1.class_name);
5961b5d61b8Smrg        xcb_icccm_get_wm_class_reply_wipe(&reply1);
5971b5d61b8Smrg    }
5981b5d61b8Smrg    else {
5991b5d61b8Smrg        *res_name = strdup("");
6001b5d61b8Smrg        *res_class = strdup("");
6011b5d61b8Smrg    }
6021b5d61b8Smrg
6031b5d61b8Smrg    cookie2 = xcb_icccm_get_wm_name(pWMInfo->conn, iWindow);
6041b5d61b8Smrg    if (xcb_icccm_get_wm_name_reply(pWMInfo->conn, cookie2, &reply2, NULL)) {
6051b5d61b8Smrg        *window_name = strndup(reply2.name, reply2.name_len);
6061b5d61b8Smrg        xcb_icccm_get_text_property_reply_wipe(&reply2);
6071b5d61b8Smrg    }
6081b5d61b8Smrg    else {
6091b5d61b8Smrg        *window_name = strdup("");
6101b5d61b8Smrg    }
6111b5d61b8Smrg}
6121b5d61b8Smrg
61305b261ecSmrg/*
61405b261ecSmrg * Updates the name of a HWND according to its X WM_NAME property
61505b261ecSmrg */
61605b261ecSmrg
61705b261ecSmrgstatic void
6181b5d61b8SmrgUpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow)
61905b261ecSmrg{
62035c4bbdfSmrg    HWND hWnd;
62135c4bbdfSmrg
62235c4bbdfSmrg    hWnd = getHwnd(pWMInfo, iWindow);
62335c4bbdfSmrg    if (!hWnd)
62435c4bbdfSmrg        return;
62535c4bbdfSmrg
62635c4bbdfSmrg    /* If window isn't override-redirect */
6271b5d61b8Smrg    if (!IsOverrideRedirect(pWMInfo->conn, iWindow)) {
62835c4bbdfSmrg        char *pszWindowName;
62935c4bbdfSmrg
63035c4bbdfSmrg        /* Get the X windows window name */
6311b5d61b8Smrg        GetWindowName(pWMInfo, iWindow, &pszWindowName);
63235c4bbdfSmrg
63335c4bbdfSmrg        if (pszWindowName) {
63435c4bbdfSmrg            /* Convert from UTF-8 to wide char */
63535c4bbdfSmrg            int iLen =
63635c4bbdfSmrg                MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1, NULL, 0);
63735c4bbdfSmrg            wchar_t *pwszWideWindowName =
63835c4bbdfSmrg                malloc(sizeof(wchar_t)*(iLen + 1));
63935c4bbdfSmrg            MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1,
64035c4bbdfSmrg                                pwszWideWindowName, iLen);
64135c4bbdfSmrg
64235c4bbdfSmrg            /* Set the Windows window name */
64335c4bbdfSmrg            SetWindowTextW(hWnd, pwszWideWindowName);
64435c4bbdfSmrg
64535c4bbdfSmrg            free(pwszWideWindowName);
64635c4bbdfSmrg            free(pszWindowName);
64735c4bbdfSmrg        }
64805b261ecSmrg    }
64935c4bbdfSmrg}
65035c4bbdfSmrg
65135c4bbdfSmrg/*
65235c4bbdfSmrg * Updates the icon of a HWND according to its X icon properties
65335c4bbdfSmrg */
65435c4bbdfSmrg
65535c4bbdfSmrgstatic void
6561b5d61b8SmrgUpdateIcon(WMInfoPtr pWMInfo, xcb_window_t iWindow)
65735c4bbdfSmrg{
65835c4bbdfSmrg    HWND hWnd;
65935c4bbdfSmrg    HICON hIconNew = NULL;
66035c4bbdfSmrg
66135c4bbdfSmrg    hWnd = getHwnd(pWMInfo, iWindow);
66235c4bbdfSmrg    if (!hWnd)
66335c4bbdfSmrg        return;
66435c4bbdfSmrg
66535c4bbdfSmrg    /* If window isn't override-redirect */
6661b5d61b8Smrg    if (!IsOverrideRedirect(pWMInfo->conn, iWindow)) {
66735c4bbdfSmrg        char *window_name = 0;
6681b5d61b8Smrg        char *res_name = 0;
6691b5d61b8Smrg        char *res_class = 0;
67035c4bbdfSmrg
6711b5d61b8Smrg        GetClassNames(pWMInfo, iWindow, &res_name, &res_class, &window_name);
67235c4bbdfSmrg
6731b5d61b8Smrg        hIconNew = winOverrideIcon(res_name, res_class, window_name);
67435c4bbdfSmrg
6751b5d61b8Smrg        free(res_name);
6761b5d61b8Smrg        free(res_class);
6771b5d61b8Smrg        free(window_name);
6781b5d61b8Smrg        winUpdateIcon(hWnd, pWMInfo->conn, iWindow, hIconNew);
67905b261ecSmrg    }
68005b261ecSmrg}
68105b261ecSmrg
68235c4bbdfSmrg/*
68335c4bbdfSmrg * Updates the style of a HWND according to its X style properties
68435c4bbdfSmrg */
68535c4bbdfSmrg
68635c4bbdfSmrgstatic void
6871b5d61b8SmrgUpdateStyle(WMInfoPtr pWMInfo, xcb_window_t iWindow)
68835c4bbdfSmrg{
68935c4bbdfSmrg    HWND hWnd;
69035c4bbdfSmrg    HWND zstyle = HWND_NOTOPMOST;
69135c4bbdfSmrg    UINT flags;
69235c4bbdfSmrg
69335c4bbdfSmrg    hWnd = getHwnd(pWMInfo, iWindow);
69435c4bbdfSmrg    if (!hWnd)
69535c4bbdfSmrg        return;
69635c4bbdfSmrg
69735c4bbdfSmrg    /* Determine the Window style, which determines borders and clipping region... */
6981b5d61b8Smrg    winApplyHints(pWMInfo, iWindow, hWnd, &zstyle);
69935c4bbdfSmrg    winUpdateWindowPosition(hWnd, &zstyle);
70035c4bbdfSmrg
701ed6184dfSmrg    /* Apply the updated window style, without changing its show or activation state */
70235c4bbdfSmrg    flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE;
70335c4bbdfSmrg    if (zstyle == HWND_NOTOPMOST)
70435c4bbdfSmrg        flags |= SWP_NOZORDER | SWP_NOOWNERZORDER;
70535c4bbdfSmrg    SetWindowPos(hWnd, NULL, 0, 0, 0, 0, flags);
70635c4bbdfSmrg
70735c4bbdfSmrg    /*
70835c4bbdfSmrg       Use the WS_EX_TOOLWINDOW style to remove window from Alt-Tab window switcher
70935c4bbdfSmrg
71035c4bbdfSmrg       According to MSDN, this is supposed to remove the window from the taskbar as well,
71135c4bbdfSmrg       if we SW_HIDE before changing the style followed by SW_SHOW afterwards.
71235c4bbdfSmrg
71335c4bbdfSmrg       But that doesn't seem to work reliably, and causes the window to flicker, so use
71435c4bbdfSmrg       the iTaskbarList interface to tell the taskbar to show or hide this window.
71535c4bbdfSmrg     */
71635c4bbdfSmrg    winShowWindowOnTaskbar(hWnd,
71735c4bbdfSmrg                           (GetWindowLongPtr(hWnd, GWL_EXSTYLE) &
71835c4bbdfSmrg                            WS_EX_APPWINDOW) ? TRUE : FALSE);
71935c4bbdfSmrg}
72005b261ecSmrg
7211b5d61b8Smrg/*
7221b5d61b8Smrg * Updates the state of a HWND
7231b5d61b8Smrg * (only minimization supported at the moment)
7241b5d61b8Smrg */
7251b5d61b8Smrg
7261b5d61b8Smrgstatic void
7271b5d61b8SmrgUpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow)
7281b5d61b8Smrg{
7291b5d61b8Smrg    HWND hWnd;
7301b5d61b8Smrg
7311b5d61b8Smrg    winDebug("UpdateState: iWindow 0x%08x\n", (int)iWindow);
7321b5d61b8Smrg
7331b5d61b8Smrg    hWnd = getHwnd(pWMInfo, iWindow);
7341b5d61b8Smrg    if (!hWnd)
7351b5d61b8Smrg        return;
7361b5d61b8Smrg
7371b5d61b8Smrg    ShowWindow(hWnd, SW_MINIMIZE);
7381b5d61b8Smrg}
7391b5d61b8Smrg
74005b261ecSmrg#if 0
74105b261ecSmrg/*
74205b261ecSmrg * Fix up any differences between the X11 and Win32 window stacks
74305b261ecSmrg * starting at the window passed in
74405b261ecSmrg */
74505b261ecSmrgstatic void
7461b5d61b8SmrgPreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction)
74705b261ecSmrg{
74835c4bbdfSmrg    HWND hWnd;
74935c4bbdfSmrg    DWORD myWinProcID, winProcID;
7501b5d61b8Smrg    xcb_window_t xWindow;
75135c4bbdfSmrg    WINDOWPLACEMENT wndPlace;
75235c4bbdfSmrg
75335c4bbdfSmrg    hWnd = getHwnd(pWMInfo, iWindow);
75435c4bbdfSmrg    if (!hWnd)
75535c4bbdfSmrg        return;
75635c4bbdfSmrg
75735c4bbdfSmrg    GetWindowThreadProcessId(hWnd, &myWinProcID);
75805b261ecSmrg    hWnd = GetNextWindow(hWnd, direction);
75905b261ecSmrg
76035c4bbdfSmrg    while (hWnd) {
76135c4bbdfSmrg        GetWindowThreadProcessId(hWnd, &winProcID);
76235c4bbdfSmrg        if (winProcID == myWinProcID) {
76335c4bbdfSmrg            wndPlace.length = sizeof(WINDOWPLACEMENT);
76435c4bbdfSmrg            GetWindowPlacement(hWnd, &wndPlace);
76535c4bbdfSmrg            if (!(wndPlace.showCmd == SW_HIDE ||
76635c4bbdfSmrg                  wndPlace.showCmd == SW_MINIMIZE)) {
76735c4bbdfSmrg                xWindow = (Window) GetProp(hWnd, WIN_WID_PROP);
76835c4bbdfSmrg                if (xWindow) {
76935c4bbdfSmrg                    if (direction == GW_HWNDPREV)
77035c4bbdfSmrg                        XRaiseWindow(pWMInfo->pDisplay, xWindow);
77135c4bbdfSmrg                    else
77235c4bbdfSmrg                        XLowerWindow(pWMInfo->pDisplay, xWindow);
77335c4bbdfSmrg                }
77435c4bbdfSmrg            }
77535c4bbdfSmrg        }
77635c4bbdfSmrg        hWnd = GetNextWindow(hWnd, direction);
77735c4bbdfSmrg    }
77835c4bbdfSmrg}
77935c4bbdfSmrg#endif                          /* PreserveWin32Stack */
78005b261ecSmrg
78105b261ecSmrg/*
78205b261ecSmrg * winMultiWindowWMProc
78305b261ecSmrg */
78405b261ecSmrg
78505b261ecSmrgstatic void *
78635c4bbdfSmrgwinMultiWindowWMProc(void *pArg)
78705b261ecSmrg{
78835c4bbdfSmrg    WMProcArgPtr pProcArg = (WMProcArgPtr) pArg;
78935c4bbdfSmrg    WMInfoPtr pWMInfo = pProcArg->pWMInfo;
79035c4bbdfSmrg
79135c4bbdfSmrg    /* Initialize the Window Manager */
79235c4bbdfSmrg    winInitMultiWindowWM(pWMInfo, pProcArg);
79335c4bbdfSmrg
79405b261ecSmrg#if CYGMULTIWINDOW_DEBUG
79535c4bbdfSmrg    ErrorF("winMultiWindowWMProc ()\n");
79605b261ecSmrg#endif
79705b261ecSmrg
79835c4bbdfSmrg    /* Loop until we explicitly break out */
79935c4bbdfSmrg    for (;;) {
80035c4bbdfSmrg        WMMsgNodePtr pNode;
80135c4bbdfSmrg
80235c4bbdfSmrg        /* Pop a message off of our queue */
80335c4bbdfSmrg        pNode = PopMessage(&pWMInfo->wmMsgQueue, pWMInfo);
80435c4bbdfSmrg        if (pNode == NULL) {
80535c4bbdfSmrg            /* Bail if PopMessage returns without a message */
80635c4bbdfSmrg            /* NOTE: Remember that PopMessage is a blocking function. */
80735c4bbdfSmrg            ErrorF("winMultiWindowWMProc - Queue is Empty?  Exiting.\n");
80835c4bbdfSmrg            pthread_exit(NULL);
80935c4bbdfSmrg        }
81005b261ecSmrg
81105b261ecSmrg#if CYGMULTIWINDOW_DEBUG
8121b5d61b8Smrg        ErrorF("winMultiWindowWMProc - MSG: %s (%d) ID: %d\n",
8131b5d61b8Smrg               MessageName(&(pNode->msg)), (int)pNode->msg.msg, (int)pNode->msg.dwID);
81405b261ecSmrg#endif
81505b261ecSmrg
81635c4bbdfSmrg        /* Branch on the message type */
81735c4bbdfSmrg        switch (pNode->msg.msg) {
81805b261ecSmrg#if 0
81935c4bbdfSmrg        case WM_WM_MOVE:
82035c4bbdfSmrg            break;
82105b261ecSmrg
82235c4bbdfSmrg        case WM_WM_SIZE:
82335c4bbdfSmrg            break;
82405b261ecSmrg#endif
82505b261ecSmrg
82635c4bbdfSmrg        case WM_WM_RAISE:
82735c4bbdfSmrg            /* Raise the window */
8281b5d61b8Smrg            {
8291b5d61b8Smrg                const static uint32_t values[] = { XCB_STACK_MODE_ABOVE };
8301b5d61b8Smrg                xcb_configure_window(pWMInfo->conn, pNode->msg.iWindow,
8311b5d61b8Smrg                                     XCB_CONFIG_WINDOW_STACK_MODE, values);
8321b5d61b8Smrg            }
8331b5d61b8Smrg
83405b261ecSmrg#if 0
83535c4bbdfSmrg            PreserveWin32Stack(pWMInfo, pNode->msg.iWindow, GW_HWNDPREV);
83605b261ecSmrg#endif
83735c4bbdfSmrg            break;
83805b261ecSmrg
83935c4bbdfSmrg        case WM_WM_LOWER:
84035c4bbdfSmrg            /* Lower the window */
8411b5d61b8Smrg            {
8421b5d61b8Smrg                const static uint32_t values[] = { XCB_STACK_MODE_BELOW };
8431b5d61b8Smrg                xcb_configure_window(pWMInfo->conn, pNode->msg.iWindow,
8441b5d61b8Smrg                                     XCB_CONFIG_WINDOW_STACK_MODE, values);
8451b5d61b8Smrg            }
84635c4bbdfSmrg            break;
84705b261ecSmrg
848ed6184dfSmrg        case WM_WM_MAP_UNMANAGED:
84935c4bbdfSmrg            /* Put a note as to the HWND associated with this Window */
8501b5d61b8Smrg            xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE,
8511b5d61b8Smrg                                pNode->msg.iWindow, pWMInfo->atmPrivMap,
8521b5d61b8Smrg                                XCB_ATOM_INTEGER, 32,
8531b5d61b8Smrg                                sizeof(HWND)/4, &(pNode->msg.hwndWindow));
85435c4bbdfSmrg
85535c4bbdfSmrg            break;
85635c4bbdfSmrg
857ed6184dfSmrg        case WM_WM_MAP_MANAGED:
85835c4bbdfSmrg            /* Put a note as to the HWND associated with this Window */
8591b5d61b8Smrg            xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE,
8601b5d61b8Smrg                                pNode->msg.iWindow, pWMInfo->atmPrivMap,
8611b5d61b8Smrg                                XCB_ATOM_INTEGER, 32,
8621b5d61b8Smrg                                sizeof(HWND)/4, &(pNode->msg.hwndWindow));
8631b5d61b8Smrg
86435c4bbdfSmrg            UpdateName(pWMInfo, pNode->msg.iWindow);
86535c4bbdfSmrg            UpdateIcon(pWMInfo, pNode->msg.iWindow);
86635c4bbdfSmrg            UpdateStyle(pWMInfo, pNode->msg.iWindow);
86735c4bbdfSmrg
86835c4bbdfSmrg
86935c4bbdfSmrg            /* Reshape */
87035c4bbdfSmrg            {
87135c4bbdfSmrg                WindowPtr pWin =
87235c4bbdfSmrg                    GetProp(pNode->msg.hwndWindow, WIN_WINDOW_PROP);
87335c4bbdfSmrg                if (pWin) {
87435c4bbdfSmrg                    winReshapeMultiWindow(pWin);
87535c4bbdfSmrg                    winUpdateRgnMultiWindow(pWin);
87635c4bbdfSmrg                }
87735c4bbdfSmrg            }
87835c4bbdfSmrg
87935c4bbdfSmrg            break;
88035c4bbdfSmrg
88135c4bbdfSmrg        case WM_WM_UNMAP:
88205b261ecSmrg
88335c4bbdfSmrg            /* Unmap the window */
8841b5d61b8Smrg            xcb_unmap_window(pWMInfo->conn, pNode->msg.iWindow);
88535c4bbdfSmrg            break;
88635c4bbdfSmrg
88735c4bbdfSmrg        case WM_WM_KILL:
88835c4bbdfSmrg            {
88935c4bbdfSmrg                /* --- */
8901b5d61b8Smrg                if (IsWmProtocolAvailable(pWMInfo,
89135c4bbdfSmrg                                          pNode->msg.iWindow,
89235c4bbdfSmrg                                          pWMInfo->atmWmDelete))
8931b5d61b8Smrg                    SendXMessage(pWMInfo->conn,
89435c4bbdfSmrg                                 pNode->msg.iWindow,
89535c4bbdfSmrg                                 pWMInfo->atmWmProtos, pWMInfo->atmWmDelete);
89635c4bbdfSmrg                else
8971b5d61b8Smrg                    xcb_kill_client(pWMInfo->conn, pNode->msg.iWindow);
89835c4bbdfSmrg            }
89935c4bbdfSmrg            break;
90035c4bbdfSmrg
90135c4bbdfSmrg        case WM_WM_ACTIVATE:
90235c4bbdfSmrg            /* Set the input focus */
90335c4bbdfSmrg
90435c4bbdfSmrg            /*
90535c4bbdfSmrg               ICCCM 4.1.7 is pretty opaque, but it appears that the rules are
90635c4bbdfSmrg               actually quite simple:
90735c4bbdfSmrg               -- the WM_HINTS input field determines whether the WM should call
90835c4bbdfSmrg               XSetInputFocus()
90935c4bbdfSmrg               -- independently, the WM_TAKE_FOCUS protocol determines whether
91035c4bbdfSmrg               the WM should send a WM_TAKE_FOCUS ClientMessage.
91135c4bbdfSmrg            */
91235c4bbdfSmrg            {
91335c4bbdfSmrg              Bool neverFocus = FALSE;
9141b5d61b8Smrg              xcb_get_property_cookie_t cookie;
9151b5d61b8Smrg              xcb_icccm_wm_hints_t hints;
9161b5d61b8Smrg
9171b5d61b8Smrg              cookie = xcb_icccm_get_wm_hints(pWMInfo->conn, pNode->msg.iWindow);
9181b5d61b8Smrg              if (xcb_icccm_get_wm_hints_reply(pWMInfo->conn, cookie, &hints,
9191b5d61b8Smrg                                               NULL)) {
9201b5d61b8Smrg                if (hints.flags & XCB_ICCCM_WM_HINT_INPUT)
9211b5d61b8Smrg                  neverFocus = !hints.input;
92235c4bbdfSmrg              }
92335c4bbdfSmrg
92435c4bbdfSmrg              if (!neverFocus)
9251b5d61b8Smrg                xcb_set_input_focus(pWMInfo->conn, XCB_INPUT_FOCUS_POINTER_ROOT,
9261b5d61b8Smrg                                    pNode->msg.iWindow, XCB_CURRENT_TIME);
92735c4bbdfSmrg
9281b5d61b8Smrg              if (IsWmProtocolAvailable(pWMInfo,
92935c4bbdfSmrg                                        pNode->msg.iWindow,
93035c4bbdfSmrg                                        pWMInfo->atmWmTakeFocus))
9311b5d61b8Smrg                SendXMessage(pWMInfo->conn,
93235c4bbdfSmrg                             pNode->msg.iWindow,
93335c4bbdfSmrg                             pWMInfo->atmWmProtos, pWMInfo->atmWmTakeFocus);
93435c4bbdfSmrg
93535c4bbdfSmrg            }
93635c4bbdfSmrg            break;
93735c4bbdfSmrg
93835c4bbdfSmrg        case WM_WM_NAME_EVENT:
93935c4bbdfSmrg            UpdateName(pWMInfo, pNode->msg.iWindow);
94035c4bbdfSmrg            break;
94135c4bbdfSmrg
94235c4bbdfSmrg        case WM_WM_ICON_EVENT:
94335c4bbdfSmrg            UpdateIcon(pWMInfo, pNode->msg.iWindow);
94435c4bbdfSmrg            break;
94535c4bbdfSmrg
94635c4bbdfSmrg        case WM_WM_HINTS_EVENT:
94735c4bbdfSmrg            {
94835c4bbdfSmrg            /* Don't do anything if this is an override-redirect window */
9491b5d61b8Smrg            if (IsOverrideRedirect(pWMInfo->conn, pNode->msg.iWindow))
95035c4bbdfSmrg              break;
95135c4bbdfSmrg
95235c4bbdfSmrg            UpdateStyle(pWMInfo, pNode->msg.iWindow);
95335c4bbdfSmrg            }
95435c4bbdfSmrg            break;
95535c4bbdfSmrg
95635c4bbdfSmrg        case WM_WM_CHANGE_STATE:
9571b5d61b8Smrg            UpdateState(pWMInfo, pNode->msg.iWindow);
95835c4bbdfSmrg            break;
95935c4bbdfSmrg
96035c4bbdfSmrg        default:
96135c4bbdfSmrg            ErrorF("winMultiWindowWMProc - Unknown Message.  Exiting.\n");
96235c4bbdfSmrg            pthread_exit(NULL);
96335c4bbdfSmrg            break;
96435c4bbdfSmrg        }
96535c4bbdfSmrg
96635c4bbdfSmrg        /* Free the retrieved message */
96735c4bbdfSmrg        free(pNode);
96835c4bbdfSmrg
96935c4bbdfSmrg        /* Flush any pending events on our display */
9701b5d61b8Smrg        xcb_flush(pWMInfo->conn);
9711b5d61b8Smrg
9721b5d61b8Smrg        /* This is just laziness rather than making sure we used _checked everywhere */
9731b5d61b8Smrg        {
9741b5d61b8Smrg            xcb_generic_event_t *event = xcb_poll_for_event(pWMInfo->conn);
9751b5d61b8Smrg            if (event) {
9761b5d61b8Smrg                if ((event->response_type & ~0x80) == 0) {
9771b5d61b8Smrg                    xcb_generic_error_t *err = (xcb_generic_error_t *)event;
9781b5d61b8Smrg                    ErrorF("winMultiWindowWMProc - Error code: %i, ID: 0x%08x, "
9791b5d61b8Smrg                           "Major opcode: %i, Minor opcode: %i\n",
9801b5d61b8Smrg                           err->error_code, err->resource_id,
9811b5d61b8Smrg                           err->major_code, err->minor_code);
9821b5d61b8Smrg                }
9831b5d61b8Smrg            }
9841b5d61b8Smrg        }
9851b5d61b8Smrg
9861b5d61b8Smrg        /* I/O errors etc. */
9871b5d61b8Smrg        {
9881b5d61b8Smrg            int e = xcb_connection_has_error(pWMInfo->conn);
9891b5d61b8Smrg            if (e) {
9901b5d61b8Smrg                ErrorF("winMultiWindowWMProc - Fatal error %d on xcb connection\n", e);
9911b5d61b8Smrg                break;
9921b5d61b8Smrg            }
9931b5d61b8Smrg        }
99405b261ecSmrg    }
99505b261ecSmrg
99635c4bbdfSmrg    /* Free the condition variable */
99735c4bbdfSmrg    pthread_cond_destroy(&pWMInfo->wmMsgQueue.pcNotEmpty);
99835c4bbdfSmrg
99935c4bbdfSmrg    /* Free the mutex variable */
100035c4bbdfSmrg    pthread_mutex_destroy(&pWMInfo->wmMsgQueue.pmMutex);
100135c4bbdfSmrg
100235c4bbdfSmrg    /* Free the passed-in argument */
100335c4bbdfSmrg    free(pProcArg);
100435c4bbdfSmrg
100505b261ecSmrg#if CYGMULTIWINDOW_DEBUG
100635c4bbdfSmrg    ErrorF("-winMultiWindowWMProc ()\n");
100705b261ecSmrg#endif
100835c4bbdfSmrg    return NULL;
100905b261ecSmrg}
101005b261ecSmrg
10111b5d61b8Smrgstatic xcb_atom_t
10121b5d61b8Smrgintern_atom(xcb_connection_t *conn, const char *atomName)
10131b5d61b8Smrg{
10141b5d61b8Smrg  xcb_intern_atom_reply_t *atom_reply;
10151b5d61b8Smrg  xcb_intern_atom_cookie_t atom_cookie;
10161b5d61b8Smrg  xcb_atom_t atom = XCB_ATOM_NONE;
10171b5d61b8Smrg
10181b5d61b8Smrg  atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName);
10191b5d61b8Smrg  atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL);
10201b5d61b8Smrg  if (atom_reply) {
10211b5d61b8Smrg    atom = atom_reply->atom;
10221b5d61b8Smrg    free(atom_reply);
10231b5d61b8Smrg  }
10241b5d61b8Smrg  return atom;
10251b5d61b8Smrg}
10261b5d61b8Smrg
102705b261ecSmrg/*
102805b261ecSmrg * X message procedure
102905b261ecSmrg */
103005b261ecSmrg
103105b261ecSmrgstatic void *
103235c4bbdfSmrgwinMultiWindowXMsgProc(void *pArg)
103305b261ecSmrg{
103435c4bbdfSmrg    winWMMessageRec msg;
103535c4bbdfSmrg    XMsgProcArgPtr pProcArg = (XMsgProcArgPtr) pArg;
103635c4bbdfSmrg    char pszDisplay[512];
103735c4bbdfSmrg    int iRetries;
10381b5d61b8Smrg    xcb_atom_t atmWmName;
10391b5d61b8Smrg    xcb_atom_t atmNetWmName;
10401b5d61b8Smrg    xcb_atom_t atmWmHints;
10411b5d61b8Smrg    xcb_atom_t atmWmChange;
10421b5d61b8Smrg    xcb_atom_t atmNetWmIcon;
10431b5d61b8Smrg    xcb_atom_t atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints;
104435c4bbdfSmrg    int iReturn;
10451b5d61b8Smrg    xcb_auth_info_t *auth_info;
1046ed6184dfSmrg    xcb_screen_t *root_screen;
1047ed6184dfSmrg    xcb_window_t root_window_id;
104835c4bbdfSmrg
104935c4bbdfSmrg    winDebug("winMultiWindowXMsgProc - Hello\n");
105035c4bbdfSmrg
105135c4bbdfSmrg    /* Check that argument pointer is not invalid */
105235c4bbdfSmrg    if (pProcArg == NULL) {
105335c4bbdfSmrg        ErrorF("winMultiWindowXMsgProc - pProcArg is NULL.  Exiting.\n");
105435c4bbdfSmrg        pthread_exit(NULL);
105505b261ecSmrg    }
105605b261ecSmrg
10571b5d61b8Smrg    winDebug("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n");
105805b261ecSmrg
105935c4bbdfSmrg    /* Grab the server started mutex - pause until we get it */
106035c4bbdfSmrg    iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
106135c4bbdfSmrg    if (iReturn != 0) {
106235c4bbdfSmrg        ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () failed: %d.  "
106335c4bbdfSmrg               "Exiting.\n", iReturn);
106435c4bbdfSmrg        pthread_exit(NULL);
106505b261ecSmrg    }
106605b261ecSmrg
10671b5d61b8Smrg    winDebug("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n");
106805b261ecSmrg
106935c4bbdfSmrg    /* Release the server started mutex */
107035c4bbdfSmrg    pthread_mutex_unlock(pProcArg->ppmServerStarted);
107105b261ecSmrg
10721b5d61b8Smrg    winDebug("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n");
107305b261ecSmrg
107435c4bbdfSmrg    /* Setup the display connection string x */
107535c4bbdfSmrg    winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen);
107605b261ecSmrg
107735c4bbdfSmrg    /* Print the display connection string */
107835c4bbdfSmrg    ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay);
107905b261ecSmrg
108035c4bbdfSmrg    /* Use our generated cookie for authentication */
10811b5d61b8Smrg    auth_info = winGetXcbAuthInfo();
10826747b715Smrg
108335c4bbdfSmrg    /* Initialize retry count */
108435c4bbdfSmrg    iRetries = 0;
108505b261ecSmrg
108635c4bbdfSmrg    /* Open the X display */
108735c4bbdfSmrg    do {
108835c4bbdfSmrg        /* Try to open the display */
10891b5d61b8Smrg        pProcArg->conn = xcb_connect_to_display_with_auth_info(pszDisplay,
10901b5d61b8Smrg                                                               auth_info, NULL);
10911b5d61b8Smrg        if (xcb_connection_has_error(pProcArg->conn)) {
109235c4bbdfSmrg            ErrorF("winMultiWindowXMsgProc - Could not open display, try: %d, "
109335c4bbdfSmrg                   "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
109435c4bbdfSmrg            ++iRetries;
109535c4bbdfSmrg            sleep(WIN_CONNECT_DELAY);
109635c4bbdfSmrg            continue;
109735c4bbdfSmrg        }
109835c4bbdfSmrg        else
109935c4bbdfSmrg            break;
110005b261ecSmrg    }
11011b5d61b8Smrg    while (xcb_connection_has_error(pProcArg->conn) && iRetries < WIN_CONNECT_RETRIES);
110235c4bbdfSmrg
110335c4bbdfSmrg    /* Make sure that the display opened */
11041b5d61b8Smrg    if (xcb_connection_has_error(pProcArg->conn)) {
110535c4bbdfSmrg        ErrorF("winMultiWindowXMsgProc - Failed opening the display.  "
110635c4bbdfSmrg               "Exiting.\n");
110735c4bbdfSmrg        pthread_exit(NULL);
110805b261ecSmrg    }
110905b261ecSmrg
11101b5d61b8Smrg    ErrorF("winMultiWindowXMsgProc - xcb_connect() returned and "
111135c4bbdfSmrg           "successfully opened the display.\n");
111205b261ecSmrg
111335c4bbdfSmrg    /* Check if another window manager is already running */
11141b5d61b8Smrg    if (CheckAnotherWindowManager(pProcArg->conn, pProcArg->dwScreen)) {
111535c4bbdfSmrg        ErrorF("winMultiWindowXMsgProc - "
111635c4bbdfSmrg               "another window manager is running.  Exiting.\n");
111735c4bbdfSmrg        pthread_exit(NULL);
111805b261ecSmrg    }
11196747b715Smrg
1120ed6184dfSmrg    /* Get root window id */
1121ed6184dfSmrg    root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen);
1122ed6184dfSmrg    root_window_id = root_screen->root;
11231b5d61b8Smrg
1124ed6184dfSmrg    {
11251b5d61b8Smrg        /* Set WM_ICON_SIZE property indicating desired icon sizes */
11261b5d61b8Smrg        typedef struct {
11271b5d61b8Smrg            uint32_t min_width, min_height;
11281b5d61b8Smrg            uint32_t max_width, max_height;
11291b5d61b8Smrg            int32_t width_inc, height_inc;
11301b5d61b8Smrg        } xcb_wm_icon_size_hints_hints_t;
11311b5d61b8Smrg
11321b5d61b8Smrg        xcb_wm_icon_size_hints_hints_t xis;
11331b5d61b8Smrg        xis.min_width = xis.min_height = 16;
11341b5d61b8Smrg        xis.max_width = xis.max_height = 48;
11351b5d61b8Smrg        xis.width_inc = xis.height_inc = 16;
11361b5d61b8Smrg
11371b5d61b8Smrg        xcb_change_property(pProcArg->conn, XCB_PROP_MODE_REPLACE, root_window_id,
11381b5d61b8Smrg                            XCB_ATOM_WM_ICON_SIZE, XCB_ATOM_WM_ICON_SIZE, 32,
11391b5d61b8Smrg                            sizeof(xis)/4, &xis);
114005b261ecSmrg    }
114105b261ecSmrg
11421b5d61b8Smrg    atmWmName = intern_atom(pProcArg->conn, "WM_NAME");
11431b5d61b8Smrg    atmNetWmName = intern_atom(pProcArg->conn, "_NET_WM_NAME");
11441b5d61b8Smrg    atmWmHints = intern_atom(pProcArg->conn, "WM_HINTS");
11451b5d61b8Smrg    atmWmChange = intern_atom(pProcArg->conn, "WM_CHANGE_STATE");
11461b5d61b8Smrg    atmNetWmIcon = intern_atom(pProcArg->conn, "_NET_WM_ICON");
11471b5d61b8Smrg    atmWindowState = intern_atom(pProcArg->conn, "_NET_WM_STATE");
11481b5d61b8Smrg    atmMotifWmHints = intern_atom(pProcArg->conn, "_MOTIF_WM_HINTS");
11491b5d61b8Smrg    atmWindowType = intern_atom(pProcArg->conn, "_NET_WM_WINDOW_TYPE");
11501b5d61b8Smrg    atmNormalHints = intern_atom(pProcArg->conn, "WM_NORMAL_HINTS");
115135c4bbdfSmrg
115235c4bbdfSmrg    /*
115335c4bbdfSmrg       iiimxcf had a bug until 2009-04-27, assuming that the
115435c4bbdfSmrg       WM_STATE atom exists, causing clients to fail with
115535c4bbdfSmrg       a BadAtom X error if it doesn't.
115635c4bbdfSmrg
115735c4bbdfSmrg       Since this is on in the default Solaris 10 install,
115835c4bbdfSmrg       workaround this by making sure it does exist...
115935c4bbdfSmrg     */
11601b5d61b8Smrg    intern_atom(pProcArg->conn, "WM_STATE");
116135c4bbdfSmrg
1162ed6184dfSmrg    /*
1163ed6184dfSmrg      Enable Composite extension and redirect subwindows of the root window
1164ed6184dfSmrg     */
1165ed6184dfSmrg    if (pProcArg->pWMInfo->fCompositeWM) {
1166ed6184dfSmrg        const char *extension_name = "Composite";
1167ed6184dfSmrg        xcb_query_extension_cookie_t cookie;
1168ed6184dfSmrg        xcb_query_extension_reply_t *reply;
1169ed6184dfSmrg
1170ed6184dfSmrg        cookie = xcb_query_extension(pProcArg->conn, strlen(extension_name), extension_name);
1171ed6184dfSmrg        reply = xcb_query_extension_reply(pProcArg->conn, cookie, NULL);
1172ed6184dfSmrg
1173ed6184dfSmrg        if (reply && (reply->present)) {
1174ed6184dfSmrg            xcb_composite_redirect_subwindows(pProcArg->conn,
1175ed6184dfSmrg                                              root_window_id,
1176ed6184dfSmrg                                              XCB_COMPOSITE_REDIRECT_AUTOMATIC);
1177ed6184dfSmrg
1178ed6184dfSmrg            /*
1179ed6184dfSmrg              We use automatic updating of the root window for two
1180ed6184dfSmrg              reasons:
1181ed6184dfSmrg
1182ed6184dfSmrg              1) redirected window contents are mirrored to the root
1183ed6184dfSmrg              window so that the root window draws correctly when shown.
1184ed6184dfSmrg
1185ed6184dfSmrg              2) updating the root window causes damage against the
1186ed6184dfSmrg              shadow framebuffer, which ultimately causes WM_PAINT to be
1187ed6184dfSmrg              sent to the affected window(s) to cause the damage regions
1188ed6184dfSmrg              to be redrawn.
1189ed6184dfSmrg            */
1190ed6184dfSmrg
1191ed6184dfSmrg            ErrorF("Using Composite redirection\n");
1192ed6184dfSmrg
1193ed6184dfSmrg            free(reply);
1194ed6184dfSmrg        }
1195ed6184dfSmrg    }
1196ed6184dfSmrg
119735c4bbdfSmrg    /* Loop until we explicitly break out */
119835c4bbdfSmrg    while (1) {
11991b5d61b8Smrg        xcb_generic_event_t *event;
12001b5d61b8Smrg        uint8_t type;
12011b5d61b8Smrg        Bool send_event;
12021b5d61b8Smrg
120335c4bbdfSmrg        if (g_shutdown)
120435c4bbdfSmrg            break;
120535c4bbdfSmrg
120635c4bbdfSmrg        /* Fetch next event */
12071b5d61b8Smrg        event = xcb_wait_for_event(pProcArg->conn);
12081b5d61b8Smrg        if (!event) { // returns NULL on I/O error
12091b5d61b8Smrg            int e = xcb_connection_has_error(pProcArg->conn);
12101b5d61b8Smrg            ErrorF("winMultiWindowXMsgProc - Fatal error %d on xcb connection\n", e);
12111b5d61b8Smrg            break;
12121b5d61b8Smrg        }
121335c4bbdfSmrg
12141b5d61b8Smrg        type = event->response_type & ~0x80;
12151b5d61b8Smrg        send_event = event->response_type & 0x80;
121635c4bbdfSmrg
12171b5d61b8Smrg        winDebug("winMultiWindowXMsgProc - event %d\n", type);
121835c4bbdfSmrg
12191b5d61b8Smrg        /* Branch on event type */
12201b5d61b8Smrg        if (type == 0) {
12211b5d61b8Smrg            xcb_generic_error_t *err = (xcb_generic_error_t *)event;
12221b5d61b8Smrg            ErrorF("winMultiWindowXMsgProc - Error code: %i, ID: 0x%08x, "
12231b5d61b8Smrg                   "Major opcode: %i, Minor opcode: %i\n",
12241b5d61b8Smrg                   err->error_code, err->resource_id,
12251b5d61b8Smrg                   err->major_code, err->minor_code);
12261b5d61b8Smrg            }
12271b5d61b8Smrg        else if (type == XCB_CREATE_NOTIFY) {
12281b5d61b8Smrg            xcb_create_notify_event_t *notify = (xcb_create_notify_event_t *)event;
12291b5d61b8Smrg
12301b5d61b8Smrg            /* Request property change events */
12311b5d61b8Smrg            const static uint32_t mask_value[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
12321b5d61b8Smrg            xcb_change_window_attributes (pProcArg->conn, notify->window,
12331b5d61b8Smrg                                          XCB_CW_EVENT_MASK, mask_value);
12341b5d61b8Smrg
12351b5d61b8Smrg            /* If it's not override-redirect, set the border-width to 0 */
12361b5d61b8Smrg            if (!IsOverrideRedirect(pProcArg->conn, notify->window)) {
12371b5d61b8Smrg                const static uint32_t width_value[] = { 0 };
12381b5d61b8Smrg                xcb_configure_window(pProcArg->conn, notify->window,
12391b5d61b8Smrg                                     XCB_CONFIG_WINDOW_BORDER_WIDTH, width_value);
12401b5d61b8Smrg            }
124135c4bbdfSmrg        }
12421b5d61b8Smrg        else if (type == XCB_MAP_NOTIFY) {
124335c4bbdfSmrg            /* Fake a reparentNotify event as SWT/Motif expects a
124435c4bbdfSmrg               Window Manager to reparent a top-level window when
124535c4bbdfSmrg               it is mapped and waits until they do.
124635c4bbdfSmrg
124735c4bbdfSmrg               We don't actually need to reparent, as the frame is
124835c4bbdfSmrg               a native window, not an X window
124935c4bbdfSmrg
125035c4bbdfSmrg               We do this on MapNotify, not MapRequest like a real
125135c4bbdfSmrg               Window Manager would, so we don't have do get involved
125235c4bbdfSmrg               in actually mapping the window via it's (non-existent)
125335c4bbdfSmrg               parent...
125435c4bbdfSmrg
125535c4bbdfSmrg               See sourceware bugzilla #9848
125635c4bbdfSmrg             */
125735c4bbdfSmrg
12581b5d61b8Smrg            xcb_map_notify_event_t *notify = (xcb_map_notify_event_t *)event;
12591b5d61b8Smrg
12601b5d61b8Smrg            xcb_get_geometry_cookie_t cookie;
12611b5d61b8Smrg            xcb_get_geometry_reply_t *reply;
12621b5d61b8Smrg            xcb_query_tree_cookie_t cookie_qt;
12631b5d61b8Smrg            xcb_query_tree_reply_t *reply_qt;
12641b5d61b8Smrg
12651b5d61b8Smrg            cookie = xcb_get_geometry(pProcArg->conn, notify->window);
12661b5d61b8Smrg            cookie_qt = xcb_query_tree(pProcArg->conn, notify->window);
12671b5d61b8Smrg            reply = xcb_get_geometry_reply(pProcArg->conn, cookie, NULL);
12681b5d61b8Smrg            reply_qt = xcb_query_tree_reply(pProcArg->conn, cookie_qt, NULL);
126935c4bbdfSmrg
12701b5d61b8Smrg            if (reply && reply_qt) {
127135c4bbdfSmrg                /*
127235c4bbdfSmrg                   It's a top-level window if the parent window is a root window
127335c4bbdfSmrg                   Only non-override_redirect windows can get reparented
127435c4bbdfSmrg                 */
12751b5d61b8Smrg                if ((reply->root == reply_qt->parent) && !notify->override_redirect) {
12761b5d61b8Smrg                    xcb_reparent_notify_event_t event_send;
12771b5d61b8Smrg
1278ed6184dfSmrg                    event_send.response_type = XCB_REPARENT_NOTIFY;
12791b5d61b8Smrg                    event_send.event = notify->window;
12801b5d61b8Smrg                    event_send.window = notify->window;
12811b5d61b8Smrg                    event_send.parent = reply_qt->parent;
12821b5d61b8Smrg                    event_send.x = reply->x;
12831b5d61b8Smrg                    event_send.y = reply->y;
12841b5d61b8Smrg
12851b5d61b8Smrg                    xcb_send_event (pProcArg->conn, TRUE, notify->window,
12861b5d61b8Smrg                                    XCB_EVENT_MASK_STRUCTURE_NOTIFY,
12871b5d61b8Smrg                                    (const char *)&event_send);
12881b5d61b8Smrg
12891b5d61b8Smrg                    free(reply_qt);
12901b5d61b8Smrg                    free(reply);
129135c4bbdfSmrg                }
129235c4bbdfSmrg            }
129335c4bbdfSmrg        }
12941b5d61b8Smrg        else if (type == XCB_CONFIGURE_NOTIFY) {
12951b5d61b8Smrg            if (!send_event) {
129635c4bbdfSmrg                /*
129735c4bbdfSmrg                   Java applications using AWT on JRE 1.6.0 break with non-reparenting WMs AWT
129835c4bbdfSmrg                   doesn't explicitly know about (See sun bug #6434227)
129935c4bbdfSmrg
130035c4bbdfSmrg                   XDecoratedPeer.handleConfigureNotifyEvent() only processes non-synthetic
130135c4bbdfSmrg                   ConfigureNotify events to update window location if it's identified the
130235c4bbdfSmrg                   WM as a non-reparenting WM it knows about (compiz or lookingglass)
130335c4bbdfSmrg
130435c4bbdfSmrg                   Rather than tell all sorts of lies to get XWM to recognize us as one of
130535c4bbdfSmrg                   those, simply send a synthetic ConfigureNotify for every non-synthetic one
130635c4bbdfSmrg                 */
13071b5d61b8Smrg                xcb_configure_notify_event_t *notify = (xcb_configure_notify_event_t *)event;
13081b5d61b8Smrg                xcb_configure_notify_event_t event_send = *notify;
130935c4bbdfSmrg
13101b5d61b8Smrg                event_send.event = notify->window;
13111b5d61b8Smrg
13121b5d61b8Smrg                xcb_send_event(pProcArg->conn, TRUE, notify->window,
13131b5d61b8Smrg                               XCB_EVENT_MASK_STRUCTURE_NOTIFY,
13141b5d61b8Smrg                               (const char *)&event_send);
131535c4bbdfSmrg            }
131635c4bbdfSmrg        }
13171b5d61b8Smrg        else if (type ==  XCB_PROPERTY_NOTIFY) {
13181b5d61b8Smrg            xcb_property_notify_event_t *notify = (xcb_property_notify_event_t *)event;
13191b5d61b8Smrg
13201b5d61b8Smrg            if ((notify->atom == atmWmName) ||
13211b5d61b8Smrg                (notify->atom == atmNetWmName)) {
132235c4bbdfSmrg                memset(&msg, 0, sizeof(msg));
132335c4bbdfSmrg
132435c4bbdfSmrg                msg.msg = WM_WM_NAME_EVENT;
13251b5d61b8Smrg                msg.iWindow = notify->window;
132635c4bbdfSmrg
132735c4bbdfSmrg                /* Other fields ignored */
132835c4bbdfSmrg                winSendMessageToWM(pProcArg->pWMInfo, &msg);
132935c4bbdfSmrg            }
133035c4bbdfSmrg            else {
133135c4bbdfSmrg                /*
133235c4bbdfSmrg                   Several properties are considered for WM hints, check if this property change affects any of them...
133335c4bbdfSmrg                   (this list needs to be kept in sync with winApplyHints())
133435c4bbdfSmrg                 */
13351b5d61b8Smrg                if ((notify->atom == atmWmHints) ||
13361b5d61b8Smrg                    (notify->atom == atmWindowState) ||
13371b5d61b8Smrg                    (notify->atom == atmMotifWmHints) ||
13381b5d61b8Smrg                    (notify->atom == atmWindowType) ||
13391b5d61b8Smrg                    (notify->atom == atmNormalHints)) {
134035c4bbdfSmrg                    memset(&msg, 0, sizeof(msg));
134135c4bbdfSmrg                    msg.msg = WM_WM_HINTS_EVENT;
13421b5d61b8Smrg                    msg.iWindow = notify->window;
134335c4bbdfSmrg
134435c4bbdfSmrg                    /* Other fields ignored */
134535c4bbdfSmrg                    winSendMessageToWM(pProcArg->pWMInfo, &msg);
134635c4bbdfSmrg                }
134735c4bbdfSmrg
134835c4bbdfSmrg                /* Not an else as WM_HINTS affects both style and icon */
13491b5d61b8Smrg                if ((notify->atom == atmWmHints) ||
13501b5d61b8Smrg                    (notify->atom == atmNetWmIcon)) {
135135c4bbdfSmrg                    memset(&msg, 0, sizeof(msg));
135235c4bbdfSmrg                    msg.msg = WM_WM_ICON_EVENT;
13531b5d61b8Smrg                    msg.iWindow = notify->window;
135435c4bbdfSmrg
135535c4bbdfSmrg                    /* Other fields ignored */
135635c4bbdfSmrg                    winSendMessageToWM(pProcArg->pWMInfo, &msg);
13576747b715Smrg                }
13586747b715Smrg            }
13596747b715Smrg        }
13601b5d61b8Smrg        else if (type == XCB_CLIENT_MESSAGE) {
13611b5d61b8Smrg            xcb_client_message_event_t *client_msg = (xcb_client_message_event_t *)event;
136235c4bbdfSmrg
13631b5d61b8Smrg            if (client_msg->type == atmWmChange
13641b5d61b8Smrg                 && client_msg->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) {
13651b5d61b8Smrg                ErrorF("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n");
136635c4bbdfSmrg
13671b5d61b8Smrg                memset(&msg, 0, sizeof(msg));
136835c4bbdfSmrg
13691b5d61b8Smrg                msg.msg = WM_WM_CHANGE_STATE;
13701b5d61b8Smrg                msg.iWindow = client_msg->window;
13711b5d61b8Smrg
13721b5d61b8Smrg                winSendMessageToWM(pProcArg->pWMInfo, &msg);
13731b5d61b8Smrg            }
137435c4bbdfSmrg        }
13751b5d61b8Smrg
13761b5d61b8Smrg        /* Free the event */
13771b5d61b8Smrg        free(event);
137805b261ecSmrg    }
137905b261ecSmrg
13801b5d61b8Smrg    xcb_disconnect(pProcArg->conn);
138135c4bbdfSmrg    pthread_exit(NULL);
138235c4bbdfSmrg    return NULL;
138305b261ecSmrg}
138405b261ecSmrg
138505b261ecSmrg/*
138605b261ecSmrg * winInitWM - Entry point for the X server to spawn
138705b261ecSmrg * the Window Manager thread.  Called from
138805b261ecSmrg * winscrinit.c/winFinishScreenInitFB ().
138905b261ecSmrg */
139005b261ecSmrg
139105b261ecSmrgBool
139235c4bbdfSmrgwinInitWM(void **ppWMInfo,
139335c4bbdfSmrg          pthread_t * ptWMProc,
139435c4bbdfSmrg          pthread_t * ptXMsgProc,
139535c4bbdfSmrg          pthread_mutex_t * ppmServerStarted,
1396ed6184dfSmrg          int dwScreen, HWND hwndScreen, Bool compositeWM)
139705b261ecSmrg{
139835c4bbdfSmrg    WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec));
139935c4bbdfSmrg    WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec));
140035c4bbdfSmrg    XMsgProcArgPtr pXMsgArg = malloc(sizeof(XMsgProcArgRec));
140135c4bbdfSmrg
140235c4bbdfSmrg    /* Bail if the input parameters are bad */
140335c4bbdfSmrg    if (pArg == NULL || pWMInfo == NULL || pXMsgArg == NULL) {
140435c4bbdfSmrg        ErrorF("winInitWM - malloc failed.\n");
140535c4bbdfSmrg        free(pArg);
140635c4bbdfSmrg        free(pWMInfo);
140735c4bbdfSmrg        free(pXMsgArg);
140835c4bbdfSmrg        return FALSE;
140905b261ecSmrg    }
141035c4bbdfSmrg
141135c4bbdfSmrg    /* Zero the allocated memory */
141235c4bbdfSmrg    ZeroMemory(pArg, sizeof(WMProcArgRec));
141335c4bbdfSmrg    ZeroMemory(pWMInfo, sizeof(WMInfoRec));
141435c4bbdfSmrg    ZeroMemory(pXMsgArg, sizeof(XMsgProcArgRec));
141535c4bbdfSmrg
141635c4bbdfSmrg    /* Set a return pointer to the Window Manager info structure */
141735c4bbdfSmrg    *ppWMInfo = pWMInfo;
1418ed6184dfSmrg    pWMInfo->fCompositeWM = compositeWM;
141935c4bbdfSmrg
142035c4bbdfSmrg    /* Setup the argument structure for the thread function */
142135c4bbdfSmrg    pArg->dwScreen = dwScreen;
142235c4bbdfSmrg    pArg->pWMInfo = pWMInfo;
142335c4bbdfSmrg    pArg->ppmServerStarted = ppmServerStarted;
142435c4bbdfSmrg
1425ed6184dfSmrg    /* Initialize the message queue */
142635c4bbdfSmrg    if (!InitQueue(&pWMInfo->wmMsgQueue)) {
142735c4bbdfSmrg        ErrorF("winInitWM - InitQueue () failed.\n");
142835c4bbdfSmrg        return FALSE;
142905b261ecSmrg    }
143035c4bbdfSmrg
143135c4bbdfSmrg    /* Spawn a thread for the Window Manager */
143235c4bbdfSmrg    if (pthread_create(ptWMProc, NULL, winMultiWindowWMProc, pArg)) {
143335c4bbdfSmrg        /* Bail if thread creation failed */
143435c4bbdfSmrg        ErrorF("winInitWM - pthread_create failed for Window Manager.\n");
143535c4bbdfSmrg        return FALSE;
143605b261ecSmrg    }
143705b261ecSmrg
143835c4bbdfSmrg    /* Spawn the XNextEvent thread, will send messages to WM */
143935c4bbdfSmrg    pXMsgArg->dwScreen = dwScreen;
144035c4bbdfSmrg    pXMsgArg->pWMInfo = pWMInfo;
144135c4bbdfSmrg    pXMsgArg->ppmServerStarted = ppmServerStarted;
144235c4bbdfSmrg    pXMsgArg->hwndScreen = hwndScreen;
144335c4bbdfSmrg    if (pthread_create(ptXMsgProc, NULL, winMultiWindowXMsgProc, pXMsgArg)) {
144435c4bbdfSmrg        /* Bail if thread creation failed */
144535c4bbdfSmrg        ErrorF("winInitWM - pthread_create failed on XMSG.\n");
144635c4bbdfSmrg        return FALSE;
144705b261ecSmrg    }
144805b261ecSmrg
144905b261ecSmrg#if CYGDEBUG || YES
145035c4bbdfSmrg    winDebug("winInitWM - Returning.\n");
145105b261ecSmrg#endif
145205b261ecSmrg
145335c4bbdfSmrg    return TRUE;
145405b261ecSmrg}
145505b261ecSmrg
145605b261ecSmrg/*
145705b261ecSmrg * Window manager thread - setup
145805b261ecSmrg */
145905b261ecSmrg
146005b261ecSmrgstatic void
146135c4bbdfSmrgwinInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg)
146205b261ecSmrg{
146335c4bbdfSmrg    int iRetries = 0;
146435c4bbdfSmrg    char pszDisplay[512];
146535c4bbdfSmrg    int iReturn;
14661b5d61b8Smrg    xcb_auth_info_t *auth_info;
1467ed6184dfSmrg    xcb_screen_t *root_screen;
1468ed6184dfSmrg    xcb_window_t root_window_id;
146905b261ecSmrg
147035c4bbdfSmrg    winDebug("winInitMultiWindowWM - Hello\n");
147105b261ecSmrg
147235c4bbdfSmrg    /* Check that argument pointer is not invalid */
147335c4bbdfSmrg    if (pProcArg == NULL) {
147435c4bbdfSmrg        ErrorF("winInitMultiWindowWM - pProcArg is NULL.  Exiting.\n");
147535c4bbdfSmrg        pthread_exit(NULL);
147605b261ecSmrg    }
147705b261ecSmrg
14781b5d61b8Smrg    winDebug("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n");
147905b261ecSmrg
148035c4bbdfSmrg    /* Grab our garbage mutex to satisfy pthread_cond_wait */
148135c4bbdfSmrg    iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
148235c4bbdfSmrg    if (iReturn != 0) {
148335c4bbdfSmrg        ErrorF("winInitMultiWindowWM - pthread_mutex_lock () failed: %d.  "
148435c4bbdfSmrg               "Exiting.\n", iReturn);
148535c4bbdfSmrg        pthread_exit(NULL);
148605b261ecSmrg    }
148705b261ecSmrg
14881b5d61b8Smrg    winDebug("winInitMultiWindowWM - pthread_mutex_lock () returned.\n");
148905b261ecSmrg
149035c4bbdfSmrg    /* Release the server started mutex */
149135c4bbdfSmrg    pthread_mutex_unlock(pProcArg->ppmServerStarted);
149205b261ecSmrg
14931b5d61b8Smrg    winDebug("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n");
14946747b715Smrg
149535c4bbdfSmrg    /* Setup the display connection string x */
149635c4bbdfSmrg    winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen);
149735c4bbdfSmrg
149835c4bbdfSmrg    /* Print the display connection string */
149935c4bbdfSmrg    ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay);
150035c4bbdfSmrg
150135c4bbdfSmrg    /* Use our generated cookie for authentication */
15021b5d61b8Smrg    auth_info = winGetXcbAuthInfo();
150335c4bbdfSmrg
150435c4bbdfSmrg    /* Open the X display */
150535c4bbdfSmrg    do {
150635c4bbdfSmrg        /* Try to open the display */
15071b5d61b8Smrg        pWMInfo->conn = xcb_connect_to_display_with_auth_info(pszDisplay,
15081b5d61b8Smrg                                                              auth_info, NULL);
15091b5d61b8Smrg        if (xcb_connection_has_error(pWMInfo->conn)) {
151035c4bbdfSmrg            ErrorF("winInitMultiWindowWM - Could not open display, try: %d, "
151135c4bbdfSmrg                   "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
151235c4bbdfSmrg            ++iRetries;
151335c4bbdfSmrg            sleep(WIN_CONNECT_DELAY);
151435c4bbdfSmrg            continue;
151535c4bbdfSmrg        }
151635c4bbdfSmrg        else
151735c4bbdfSmrg            break;
151805b261ecSmrg    }
15191b5d61b8Smrg    while (xcb_connection_has_error(pWMInfo->conn) && iRetries < WIN_CONNECT_RETRIES);
152035c4bbdfSmrg
152135c4bbdfSmrg    /* Make sure that the display opened */
15221b5d61b8Smrg    if (xcb_connection_has_error(pWMInfo->conn)) {
152335c4bbdfSmrg        ErrorF("winInitMultiWindowWM - Failed opening the display.  "
152435c4bbdfSmrg               "Exiting.\n");
152535c4bbdfSmrg        pthread_exit(NULL);
152605b261ecSmrg    }
152705b261ecSmrg
15281b5d61b8Smrg    ErrorF("winInitMultiWindowWM - xcb_connect () returned and "
152935c4bbdfSmrg           "successfully opened the display.\n");
153005b261ecSmrg
153135c4bbdfSmrg    /* Create some atoms */
15321b5d61b8Smrg    pWMInfo->atmWmProtos = intern_atom(pWMInfo->conn, "WM_PROTOCOLS");
15331b5d61b8Smrg    pWMInfo->atmWmDelete = intern_atom(pWMInfo->conn, "WM_DELETE_WINDOW");
15341b5d61b8Smrg    pWMInfo->atmWmTakeFocus = intern_atom(pWMInfo->conn, "WM_TAKE_FOCUS");
15351b5d61b8Smrg    pWMInfo->atmPrivMap = intern_atom(pWMInfo->conn, WINDOWSWM_NATIVE_HWND);
15361b5d61b8Smrg    pWMInfo->atmUtf8String = intern_atom(pWMInfo->conn, "UTF8_STRING");
15371b5d61b8Smrg    pWMInfo->atmNetWmName = intern_atom(pWMInfo->conn, "_NET_WM_NAME");
1538ed6184dfSmrg    pWMInfo->atmCurrentDesktop = intern_atom(pWMInfo->conn, "_NET_CURRENT_DESKTOP");
1539ed6184dfSmrg    pWMInfo->atmNumberDesktops = intern_atom(pWMInfo->conn, "_NET_NUMBER_OF_DESKTOPS");
1540ed6184dfSmrg    pWMInfo->atmDesktopNames = intern_atom(pWMInfo->conn, "__NET_DESKTOP_NAMES");
15411b5d61b8Smrg
15421b5d61b8Smrg    /* Initialization for the xcb_ewmh and EWMH atoms */
15431b5d61b8Smrg    {
15441b5d61b8Smrg        xcb_intern_atom_cookie_t *atoms_cookie;
15451b5d61b8Smrg        atoms_cookie = xcb_ewmh_init_atoms(pWMInfo->conn, &pWMInfo->ewmh);
15461b5d61b8Smrg        if (xcb_ewmh_init_atoms_replies(&pWMInfo->ewmh, atoms_cookie, NULL)) {
15471b5d61b8Smrg            /* Set the _NET_SUPPORTED atom for this context.
15481b5d61b8Smrg
15491b5d61b8Smrg               TODO: Audit to ensure we implement everything defined as MUSTs
15501b5d61b8Smrg               for window managers in the EWMH standard.*/
15511b5d61b8Smrg            xcb_atom_t supported[] =
15521b5d61b8Smrg                {
15531b5d61b8Smrg                    pWMInfo->ewmh.WM_PROTOCOLS,
15541b5d61b8Smrg                    pWMInfo->ewmh._NET_SUPPORTED,
15551b5d61b8Smrg                    pWMInfo->ewmh._NET_SUPPORTING_WM_CHECK,
15561b5d61b8Smrg                    pWMInfo->ewmh._NET_CLOSE_WINDOW,
15571b5d61b8Smrg                    pWMInfo->ewmh._NET_WM_WINDOW_TYPE,
15581b5d61b8Smrg                    pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK,
15591b5d61b8Smrg                    pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH,
15601b5d61b8Smrg                    pWMInfo->ewmh._NET_WM_STATE,
15611b5d61b8Smrg                    pWMInfo->ewmh._NET_WM_STATE_HIDDEN,
15621b5d61b8Smrg                    pWMInfo->ewmh._NET_WM_STATE_ABOVE,
15631b5d61b8Smrg                    pWMInfo->ewmh._NET_WM_STATE_BELOW,
15641b5d61b8Smrg                    pWMInfo->ewmh._NET_WM_STATE_SKIP_TASKBAR,
15651b5d61b8Smrg                };
15661b5d61b8Smrg
15671b5d61b8Smrg            xcb_ewmh_set_supported(&pWMInfo->ewmh, pProcArg->dwScreen,
15681b5d61b8Smrg                                   ARRAY_SIZE(supported), supported);
15691b5d61b8Smrg        }
15701b5d61b8Smrg        else {
15711b5d61b8Smrg            ErrorF("winInitMultiWindowWM - xcb_ewmh_init_atoms() failed\n");
157235c4bbdfSmrg        }
157305b261ecSmrg    }
157405b261ecSmrg
1575ed6184dfSmrg    /* Get root window id */
1576ed6184dfSmrg    root_screen = xcb_aux_get_screen(pWMInfo->conn, pProcArg->dwScreen);
1577ed6184dfSmrg    root_window_id = root_screen->root;
1578ed6184dfSmrg
1579ed6184dfSmrg    /*
1580ed6184dfSmrg      Set root window properties for describing multiple desktops to describe
1581ed6184dfSmrg      the one desktop we have
1582ed6184dfSmrg    */
1583ed6184dfSmrg    {
1584ed6184dfSmrg        int data;
1585ed6184dfSmrg        const char buf[] = "Desktop";
1586ed6184dfSmrg
1587ed6184dfSmrg        data = 0;
1588ed6184dfSmrg        xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id,
1589ed6184dfSmrg                            pWMInfo->atmCurrentDesktop, XCB_ATOM_CARDINAL, 32,
1590ed6184dfSmrg                            1, &data);
1591ed6184dfSmrg        data = 1;
1592ed6184dfSmrg        xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id,
1593ed6184dfSmrg                            pWMInfo->atmNumberDesktops, XCB_ATOM_CARDINAL, 32,
1594ed6184dfSmrg                            1, &data);
1595ed6184dfSmrg
1596ed6184dfSmrg        xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id,
1597ed6184dfSmrg                            pWMInfo->atmDesktopNames, pWMInfo->atmUtf8String, 8,
1598ed6184dfSmrg                            strlen(buf), (unsigned char *) buf);
1599ed6184dfSmrg    }
1600ed6184dfSmrg
16011b5d61b8Smrg    /*
16021b5d61b8Smrg      Set the root window cursor to left_ptr (this controls the cursor an
1603ed6184dfSmrg      application gets over its windows when it doesn't set one)
16041b5d61b8Smrg    */
16051b5d61b8Smrg    {
16061b5d61b8Smrg#define XC_left_ptr 68
16071b5d61b8Smrg        xcb_cursor_t cursor = xcb_generate_id(pWMInfo->conn);
16081b5d61b8Smrg        xcb_font_t font = xcb_generate_id(pWMInfo->conn);
16091b5d61b8Smrg        xcb_font_t *mask_font = &font; /* An alias to clarify */
16101b5d61b8Smrg        int shape = XC_left_ptr;
16111b5d61b8Smrg        uint32_t mask = XCB_CW_CURSOR;
16121b5d61b8Smrg        uint32_t value_list = cursor;
161305b261ecSmrg
16141b5d61b8Smrg        static const uint16_t fgred = 0, fggreen = 0, fgblue = 0;
16151b5d61b8Smrg        static const uint16_t bgred = 0xFFFF, bggreen = 0xFFFF, bgblue = 0xFFFF;
161605b261ecSmrg
16171b5d61b8Smrg        xcb_open_font(pWMInfo->conn, font, sizeof("cursor"), "cursor");
161805b261ecSmrg
16191b5d61b8Smrg        xcb_create_glyph_cursor(pWMInfo->conn, cursor, font, *mask_font,
16201b5d61b8Smrg                                shape, shape + 1,
16211b5d61b8Smrg                                fgred, fggreen, fgblue, bgred, bggreen, bgblue);
162205b261ecSmrg
1623ed6184dfSmrg        xcb_change_window_attributes(pWMInfo->conn, root_window_id, mask, &value_list);
162405b261ecSmrg
16251b5d61b8Smrg        xcb_free_cursor(pWMInfo->conn, cursor);
16261b5d61b8Smrg        xcb_close_font(pWMInfo->conn, font);
162735c4bbdfSmrg    }
162835c4bbdfSmrg}
162905b261ecSmrg
163005b261ecSmrg/*
16311b5d61b8Smrg * winSendMessageToWM - Send a message from the X thread to the WM thread
163205b261ecSmrg */
163305b261ecSmrg
16341b5d61b8Smrgvoid
16351b5d61b8SmrgwinSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg)
163605b261ecSmrg{
16371b5d61b8Smrg    WMMsgNodePtr pNode;
163835c4bbdfSmrg
16396747b715Smrg#if CYGMULTIWINDOW_DEBUG
16401b5d61b8Smrg    ErrorF("winSendMessageToWM %s\n", MessageName(pMsg));
16416747b715Smrg#endif
164205b261ecSmrg
16431b5d61b8Smrg    pNode = malloc(sizeof(WMMsgNodeRec));
16441b5d61b8Smrg    if (pNode != NULL) {
16451b5d61b8Smrg        memcpy(&pNode->msg, pMsg, sizeof(winWMMessageRec));
16461b5d61b8Smrg        PushMessage(&((WMInfoPtr) pWMInfo)->wmMsgQueue, pNode);
164735c4bbdfSmrg    }
164805b261ecSmrg}
164905b261ecSmrg
165005b261ecSmrg/*
165105b261ecSmrg * Check if another window manager is running
165205b261ecSmrg */
165305b261ecSmrg
165405b261ecSmrgstatic Bool
16551b5d61b8SmrgCheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen)
165605b261ecSmrg{
16571b5d61b8Smrg    Bool redirectError = FALSE;
16581b5d61b8Smrg
16591b5d61b8Smrg    /* Get root window id */
16601b5d61b8Smrg    xcb_screen_t *root_screen = xcb_aux_get_screen(conn, dwScreen);
16611b5d61b8Smrg    xcb_window_t root_window_id = root_screen->root;
16621b5d61b8Smrg
166335c4bbdfSmrg    /*
166435c4bbdfSmrg       Try to select the events which only one client at a time is allowed to select.
166535c4bbdfSmrg       If this causes an error, another window manager is already running...
166635c4bbdfSmrg     */
16671b5d61b8Smrg    const static uint32_t test_mask[] = { XCB_EVENT_MASK_RESIZE_REDIRECT |
16681b5d61b8Smrg                                       XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
16691b5d61b8Smrg                                       XCB_EVENT_MASK_BUTTON_PRESS };
16701b5d61b8Smrg
16711b5d61b8Smrg    xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(conn,
16721b5d61b8Smrg                                                                    root_window_id,
16731b5d61b8Smrg                                                                    XCB_CW_EVENT_MASK,
16741b5d61b8Smrg                                                                    test_mask);
16751b5d61b8Smrg    xcb_generic_error_t *error;
16761b5d61b8Smrg    if ((error = xcb_request_check(conn, cookie)))
16771b5d61b8Smrg        {
16781b5d61b8Smrg            redirectError = TRUE;
16791b5d61b8Smrg            free(error);
16801b5d61b8Smrg        }
168135c4bbdfSmrg
168235c4bbdfSmrg    /*
168335c4bbdfSmrg       Side effect: select the events we are actually interested in...
168435c4bbdfSmrg
16851b5d61b8Smrg       Other WMs are not allowed, also select one of the events which only one client
168635c4bbdfSmrg       at a time is allowed to select, so other window managers won't start...
168735c4bbdfSmrg     */
16881b5d61b8Smrg    {
16891b5d61b8Smrg        const uint32_t mask[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
16901b5d61b8Smrg                                  XCB_EVENT_MASK_BUTTON_PRESS };
16911b5d61b8Smrg
16921b5d61b8Smrg        xcb_change_window_attributes(conn, root_window_id, XCB_CW_EVENT_MASK, mask);
16931b5d61b8Smrg    }
16941b5d61b8Smrg
169535c4bbdfSmrg    return redirectError;
169605b261ecSmrg}
169705b261ecSmrg
169805b261ecSmrg/*
169905b261ecSmrg * Notify the MWM thread we're exiting and not to reconnect
170005b261ecSmrg */
170105b261ecSmrg
170205b261ecSmrgvoid
170335c4bbdfSmrgwinDeinitMultiWindowWM(void)
170405b261ecSmrg{
170535c4bbdfSmrg    ErrorF("winDeinitMultiWindowWM - Noting shutdown in progress\n");
170635c4bbdfSmrg    g_shutdown = TRUE;
170705b261ecSmrg}
17086747b715Smrg
17096747b715Smrg/* Windows window styles */
171035c4bbdfSmrg#define HINT_NOFRAME	(1L<<0)
17116747b715Smrg#define HINT_BORDER	(1L<<1)
171235c4bbdfSmrg#define HINT_SIZEBOX	(1L<<2)
171335c4bbdfSmrg#define HINT_CAPTION	(1L<<3)
17146747b715Smrg#define HINT_NOMAXIMIZE (1L<<4)
171535c4bbdfSmrg#define HINT_NOMINIMIZE (1L<<5)
171635c4bbdfSmrg#define HINT_NOSYSMENU  (1L<<6)
171735c4bbdfSmrg#define HINT_SKIPTASKBAR (1L<<7)
17186747b715Smrg/* These two are used on their own */
17196747b715Smrg#define HINT_MAX	(1L<<0)
17206747b715Smrg#define HINT_MIN	(1L<<1)
17216747b715Smrg
17226747b715Smrgstatic void
17231b5d61b8SmrgwinApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle)
17246747b715Smrg{
17251b5d61b8Smrg
17261b5d61b8Smrg    xcb_connection_t *conn = pWMInfo->conn;
17271b5d61b8Smrg    static xcb_atom_t windowState, motif_wm_hints;
17281b5d61b8Smrg    static xcb_atom_t hiddenState, fullscreenState, belowState, aboveState,
172935c4bbdfSmrg        skiptaskbarState;
17301b5d61b8Smrg    static xcb_atom_t splashType;
173135c4bbdfSmrg    static int generation;
17321b5d61b8Smrg
17331b5d61b8Smrg    unsigned long hint = 0, maxmin = 0;
173435c4bbdfSmrg    unsigned long style, exStyle;
173535c4bbdfSmrg
173635c4bbdfSmrg    if (!hWnd)
173735c4bbdfSmrg        return;
173835c4bbdfSmrg    if (!IsWindow(hWnd))
173935c4bbdfSmrg        return;
174035c4bbdfSmrg
174135c4bbdfSmrg    if (generation != serverGeneration) {
174235c4bbdfSmrg        generation = serverGeneration;
17431b5d61b8Smrg        windowState = intern_atom(conn, "_NET_WM_STATE");
17441b5d61b8Smrg        motif_wm_hints = intern_atom(conn, "_MOTIF_WM_HINTS");
17451b5d61b8Smrg        hiddenState = intern_atom(conn, "_NET_WM_STATE_HIDDEN");
17461b5d61b8Smrg        fullscreenState = intern_atom(conn, "_NET_WM_STATE_FULLSCREEN");
17471b5d61b8Smrg        belowState = intern_atom(conn, "_NET_WM_STATE_BELOW");
17481b5d61b8Smrg        aboveState = intern_atom(conn, "_NET_WM_STATE_ABOVE");
17491b5d61b8Smrg        skiptaskbarState = intern_atom(conn, "_NET_WM_STATE_SKIP_TASKBAR");
17501b5d61b8Smrg        splashType = intern_atom(conn, "_NET_WM_WINDOW_TYPE_SPLASHSCREEN");
175135c4bbdfSmrg    }
17526747b715Smrg
17531b5d61b8Smrg    {
17541b5d61b8Smrg      xcb_get_property_cookie_t cookie_wm_state = xcb_get_property(conn, FALSE, iWindow, windowState, XCB_ATOM_ATOM, 0L, INT_MAX);
17551b5d61b8Smrg      xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie_wm_state, NULL);
17561b5d61b8Smrg      if (reply) {
17571b5d61b8Smrg        int i;
17581b5d61b8Smrg        int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t);
17591b5d61b8Smrg        xcb_atom_t *pAtom = xcb_get_property_value(reply);
176035c4bbdfSmrg
176135c4bbdfSmrg            for (i = 0; i < nitems; i++) {
176235c4bbdfSmrg                if (pAtom[i] == skiptaskbarState)
176335c4bbdfSmrg                    hint |= HINT_SKIPTASKBAR;
176435c4bbdfSmrg                if (pAtom[i] == hiddenState)
176535c4bbdfSmrg                    maxmin |= HINT_MIN;
176635c4bbdfSmrg                else if (pAtom[i] == fullscreenState)
176735c4bbdfSmrg                    maxmin |= HINT_MAX;
176835c4bbdfSmrg                if (pAtom[i] == belowState)
176935c4bbdfSmrg                    *zstyle = HWND_BOTTOM;
177035c4bbdfSmrg                else if (pAtom[i] == aboveState)
177135c4bbdfSmrg                    *zstyle = HWND_TOPMOST;
177235c4bbdfSmrg            }
177335c4bbdfSmrg
17741b5d61b8Smrg            free(reply);
17751b5d61b8Smrg      }
17766747b715Smrg    }
17776747b715Smrg
17781b5d61b8Smrg    {
17791b5d61b8Smrg      xcb_get_property_cookie_t cookie_mwm_hint = xcb_get_property(conn, FALSE, iWindow, motif_wm_hints, motif_wm_hints, 0L, sizeof(MwmHints));
17801b5d61b8Smrg      xcb_get_property_reply_t *reply =  xcb_get_property_reply(conn, cookie_mwm_hint, NULL);
17811b5d61b8Smrg      if (reply) {
17821b5d61b8Smrg        int nitems = xcb_get_property_value_length(reply)/4;
17831b5d61b8Smrg        MwmHints *mwm_hint = xcb_get_property_value(reply);
17841b5d61b8Smrg        if (mwm_hint && (nitems >= PropMwmHintsElements) &&
178535c4bbdfSmrg            (mwm_hint->flags & MwmHintsDecorations)) {
178635c4bbdfSmrg            if (!mwm_hint->decorations)
178735c4bbdfSmrg                hint |= (HINT_NOFRAME | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE);
178835c4bbdfSmrg            else if (!(mwm_hint->decorations & MwmDecorAll)) {
178935c4bbdfSmrg                if (mwm_hint->decorations & MwmDecorBorder)
179035c4bbdfSmrg                    hint |= HINT_BORDER;
179135c4bbdfSmrg                if (mwm_hint->decorations & MwmDecorHandle)
179235c4bbdfSmrg                    hint |= HINT_SIZEBOX;
179335c4bbdfSmrg                if (mwm_hint->decorations & MwmDecorTitle)
179435c4bbdfSmrg                    hint |= HINT_CAPTION;
179535c4bbdfSmrg                if (!(mwm_hint->decorations & MwmDecorMenu))
179635c4bbdfSmrg                    hint |= HINT_NOSYSMENU;
179735c4bbdfSmrg                if (!(mwm_hint->decorations & MwmDecorMinimize))
179835c4bbdfSmrg                    hint |= HINT_NOMINIMIZE;
179935c4bbdfSmrg                if (!(mwm_hint->decorations & MwmDecorMaximize))
180035c4bbdfSmrg                    hint |= HINT_NOMAXIMIZE;
180135c4bbdfSmrg            }
180235c4bbdfSmrg            else {
180335c4bbdfSmrg                /*
180435c4bbdfSmrg                   MwmDecorAll means all decorations *except* those specified by other flag
180535c4bbdfSmrg                   bits that are set.  Not yet implemented.
180635c4bbdfSmrg                 */
180735c4bbdfSmrg            }
180835c4bbdfSmrg        }
18091b5d61b8Smrg        free(reply);
18101b5d61b8Smrg      }
181135c4bbdfSmrg    }
181235c4bbdfSmrg
18131b5d61b8Smrg    {
18141b5d61b8Smrg      int i;
18151b5d61b8Smrg      xcb_ewmh_get_atoms_reply_t type;
18161b5d61b8Smrg      xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_window_type(&pWMInfo->ewmh, iWindow);
18171b5d61b8Smrg      if (xcb_ewmh_get_wm_window_type_reply(&pWMInfo->ewmh, cookie, &type, NULL)) {
18181b5d61b8Smrg        for (i = 0; i < type.atoms_len; i++) {
18191b5d61b8Smrg            if (type.atoms[i] ==  pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK) {
182035c4bbdfSmrg                hint = (hint & ~HINT_NOFRAME) | HINT_SKIPTASKBAR | HINT_SIZEBOX;
182135c4bbdfSmrg                *zstyle = HWND_TOPMOST;
182235c4bbdfSmrg            }
18231b5d61b8Smrg            else if ((type.atoms[i] == pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH)
18241b5d61b8Smrg                     || (type.atoms[i] == splashType)) {
18251b5d61b8Smrg                hint |= (HINT_SKIPTASKBAR | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE);
18261b5d61b8Smrg                *zstyle = HWND_TOPMOST;
18271b5d61b8Smrg            }
182835c4bbdfSmrg        }
18291b5d61b8Smrg      }
18306747b715Smrg    }
18316747b715Smrg
18326747b715Smrg    {
18331b5d61b8Smrg        xcb_size_hints_t size_hints;
18341b5d61b8Smrg        xcb_get_property_cookie_t cookie;
18351b5d61b8Smrg
18361b5d61b8Smrg        cookie = xcb_icccm_get_wm_normal_hints(conn, iWindow);
18371b5d61b8Smrg        if (xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &size_hints, NULL)) {
18381b5d61b8Smrg            if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) {
183935c4bbdfSmrg
18401b5d61b8Smrg                /* Not maximizable if a maximum size is specified, and that size
18411b5d61b8Smrg                   is smaller (in either dimension) than the screen size */
18421b5d61b8Smrg                if ((size_hints.max_width < GetSystemMetrics(SM_CXVIRTUALSCREEN))
18431b5d61b8Smrg                    || (size_hints.max_height < GetSystemMetrics(SM_CYVIRTUALSCREEN)))
18441b5d61b8Smrg                    hint |= HINT_NOMAXIMIZE;
184535c4bbdfSmrg
18461b5d61b8Smrg                if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) {
184735c4bbdfSmrg                    /*
184835c4bbdfSmrg                       If both minimum size and maximum size are specified and are the same,
184935c4bbdfSmrg                       don't bother with a resizing frame
185035c4bbdfSmrg                     */
18511b5d61b8Smrg                    if ((size_hints.min_width == size_hints.max_width)
18521b5d61b8Smrg                        && (size_hints.min_height == size_hints.max_height))
185335c4bbdfSmrg                        hint = (hint & ~HINT_SIZEBOX);
185435c4bbdfSmrg                }
185535c4bbdfSmrg            }
185635c4bbdfSmrg        }
18576747b715Smrg    }
18586747b715Smrg
185935c4bbdfSmrg    /*
186035c4bbdfSmrg       Override hint settings from above with settings from config file and set
186135c4bbdfSmrg       application id for grouping.
186235c4bbdfSmrg     */
186335c4bbdfSmrg    {
186435c4bbdfSmrg        char *application_id = 0;
18651b5d61b8Smrg        char *window_name = 0;
18661b5d61b8Smrg        char *res_name = 0;
18671b5d61b8Smrg        char *res_class = 0;
186835c4bbdfSmrg
18691b5d61b8Smrg        GetClassNames(pWMInfo, iWindow, &res_name, &res_class, &window_name);
187035c4bbdfSmrg
18711b5d61b8Smrg        style = STYLE_NONE;
18721b5d61b8Smrg        style = winOverrideStyle(res_name, res_class, window_name);
187335c4bbdfSmrg
187435c4bbdfSmrg#define APPLICATION_ID_FORMAT	"%s.xwin.%s"
187535c4bbdfSmrg#define APPLICATION_ID_UNKNOWN "unknown"
18761b5d61b8Smrg        if (res_class) {
18771b5d61b8Smrg            asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
18781b5d61b8Smrg                     res_class);
187935c4bbdfSmrg        }
188035c4bbdfSmrg        else {
18811b5d61b8Smrg            asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
18821b5d61b8Smrg                     APPLICATION_ID_UNKNOWN);
188335c4bbdfSmrg        }
18841b5d61b8Smrg        winSetAppUserModelID(hWnd, application_id);
18851b5d61b8Smrg
18861b5d61b8Smrg        free(application_id);
18871b5d61b8Smrg        free(res_name);
18881b5d61b8Smrg        free(res_class);
18891b5d61b8Smrg        free(window_name);
189035c4bbdfSmrg    }
18916747b715Smrg
189235c4bbdfSmrg    if (style & STYLE_TOPMOST)
189335c4bbdfSmrg        *zstyle = HWND_TOPMOST;
189435c4bbdfSmrg    else if (style & STYLE_MAXIMIZE)
189535c4bbdfSmrg        maxmin = (hint & ~HINT_MIN) | HINT_MAX;
189635c4bbdfSmrg    else if (style & STYLE_MINIMIZE)
189735c4bbdfSmrg        maxmin = (hint & ~HINT_MAX) | HINT_MIN;
189835c4bbdfSmrg    else if (style & STYLE_BOTTOM)
189935c4bbdfSmrg        *zstyle = HWND_BOTTOM;
190035c4bbdfSmrg
190135c4bbdfSmrg    if (maxmin & HINT_MAX)
190235c4bbdfSmrg        SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
190335c4bbdfSmrg    else if (maxmin & HINT_MIN)
190435c4bbdfSmrg        SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
190535c4bbdfSmrg
190635c4bbdfSmrg    if (style & STYLE_NOTITLE)
190735c4bbdfSmrg        hint =
190835c4bbdfSmrg            (hint & ~HINT_NOFRAME & ~HINT_BORDER & ~HINT_CAPTION) |
190935c4bbdfSmrg            HINT_SIZEBOX;
191035c4bbdfSmrg    else if (style & STYLE_OUTLINE)
191135c4bbdfSmrg        hint =
191235c4bbdfSmrg            (hint & ~HINT_NOFRAME & ~HINT_SIZEBOX & ~HINT_CAPTION) |
191335c4bbdfSmrg            HINT_BORDER;
191435c4bbdfSmrg    else if (style & STYLE_NOFRAME)
191535c4bbdfSmrg        hint =
191635c4bbdfSmrg            (hint & ~HINT_BORDER & ~HINT_CAPTION & ~HINT_SIZEBOX) |
191735c4bbdfSmrg            HINT_NOFRAME;
191835c4bbdfSmrg
191935c4bbdfSmrg    /* Now apply styles to window */
192035c4bbdfSmrg    style = GetWindowLongPtr(hWnd, GWL_STYLE);
192135c4bbdfSmrg    if (!style)
192235c4bbdfSmrg        return;                 /* GetWindowLongPointer returns 0 on failure, we hope this isn't a valid style */
192335c4bbdfSmrg
192435c4bbdfSmrg    style &= ~WS_CAPTION & ~WS_SIZEBOX; /* Just in case */
192535c4bbdfSmrg
192635c4bbdfSmrg    if (!(hint & ~HINT_SKIPTASKBAR))    /* No hints, default */
192735c4bbdfSmrg        style = style | WS_CAPTION | WS_SIZEBOX;
192835c4bbdfSmrg    else if (hint & HINT_NOFRAME)       /* No frame, no decorations */
192935c4bbdfSmrg        style = style & ~WS_CAPTION & ~WS_SIZEBOX;
193035c4bbdfSmrg    else
193135c4bbdfSmrg        style = style | ((hint & HINT_BORDER) ? WS_BORDER : 0) |
193235c4bbdfSmrg            ((hint & HINT_SIZEBOX) ? WS_SIZEBOX : 0) |
193335c4bbdfSmrg            ((hint & HINT_CAPTION) ? WS_CAPTION : 0);
193435c4bbdfSmrg
193535c4bbdfSmrg    if (hint & HINT_NOMAXIMIZE)
193635c4bbdfSmrg        style = style & ~WS_MAXIMIZEBOX;
193735c4bbdfSmrg
193835c4bbdfSmrg    if (hint & HINT_NOMINIMIZE)
193935c4bbdfSmrg        style = style & ~WS_MINIMIZEBOX;
194035c4bbdfSmrg
194135c4bbdfSmrg    if (hint & HINT_NOSYSMENU)
194235c4bbdfSmrg        style = style & ~WS_SYSMENU;
194335c4bbdfSmrg
194435c4bbdfSmrg    if (hint & HINT_SKIPTASKBAR)
194535c4bbdfSmrg        style = style & ~WS_MINIMIZEBOX;        /* window will become lost if minimized */
194635c4bbdfSmrg
194735c4bbdfSmrg    SetWindowLongPtr(hWnd, GWL_STYLE, style);
194835c4bbdfSmrg
194935c4bbdfSmrg    exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
195035c4bbdfSmrg    if (hint & HINT_SKIPTASKBAR)
195135c4bbdfSmrg        exStyle = (exStyle & ~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW;
195235c4bbdfSmrg    else
195335c4bbdfSmrg        exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW;
195435c4bbdfSmrg    SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle);
195535c4bbdfSmrg
195635c4bbdfSmrg    winDebug
195735c4bbdfSmrg        ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n",
195835c4bbdfSmrg         iWindow, hint, style, exStyle);
19596747b715Smrg}
19606747b715Smrg
19616747b715Smrgvoid
196235c4bbdfSmrgwinUpdateWindowPosition(HWND hWnd, HWND * zstyle)
19636747b715Smrg{
196435c4bbdfSmrg    int iX, iY, iWidth, iHeight;
196535c4bbdfSmrg    int iDx, iDy;
196635c4bbdfSmrg    RECT rcNew;
196735c4bbdfSmrg    WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP);
196835c4bbdfSmrg    DrawablePtr pDraw = NULL;
196935c4bbdfSmrg
197035c4bbdfSmrg    if (!pWin)
197135c4bbdfSmrg        return;
197235c4bbdfSmrg    pDraw = &pWin->drawable;
197335c4bbdfSmrg    if (!pDraw)
197435c4bbdfSmrg        return;
197535c4bbdfSmrg
197635c4bbdfSmrg    /* Get the X and Y location of the X window */
197735c4bbdfSmrg    iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN);
197835c4bbdfSmrg    iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN);
197935c4bbdfSmrg
198035c4bbdfSmrg    /* Get the height and width of the X window */
198135c4bbdfSmrg    iWidth = pWin->drawable.width;
198235c4bbdfSmrg    iHeight = pWin->drawable.height;
198335c4bbdfSmrg
198435c4bbdfSmrg    /* Setup a rectangle with the X window position and size */
198535c4bbdfSmrg    SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight);
198635c4bbdfSmrg
198735c4bbdfSmrg    winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n",
198835c4bbdfSmrg             rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
198935c4bbdfSmrg
199035c4bbdfSmrg    AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE,
199135c4bbdfSmrg                       GetWindowLongPtr(hWnd, GWL_EXSTYLE));
199235c4bbdfSmrg
199335c4bbdfSmrg    /* Don't allow window decoration to disappear off to top-left as a result of this adjustment */
199435c4bbdfSmrg    if (rcNew.left < GetSystemMetrics(SM_XVIRTUALSCREEN)) {
199535c4bbdfSmrg        iDx = GetSystemMetrics(SM_XVIRTUALSCREEN) - rcNew.left;
199635c4bbdfSmrg        rcNew.left += iDx;
199735c4bbdfSmrg        rcNew.right += iDx;
19986747b715Smrg    }
19996747b715Smrg
200035c4bbdfSmrg    if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) {
200135c4bbdfSmrg        iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top;
200235c4bbdfSmrg        rcNew.top += iDy;
200335c4bbdfSmrg        rcNew.bottom += iDy;
20046747b715Smrg    }
20056747b715Smrg
200635c4bbdfSmrg    winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n",
200735c4bbdfSmrg             rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
20086747b715Smrg
200935c4bbdfSmrg    /* Position the Windows window */
201035c4bbdfSmrg    SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top,
201135c4bbdfSmrg                 rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0);
20126747b715Smrg
20136747b715Smrg}
2014