xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

winmultiwindowwm.c (65362B)


      1 /*
      2  *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
      3  *Copyright (C) Colin Harrison 2005-2009
      4  *
      5  *Permission is hereby granted, free of charge, to any person obtaining
      6  * a copy of this software and associated documentation files (the
      7  *"Software"), to deal in the Software without restriction, including
      8  *without limitation the rights to use, copy, modify, merge, publish,
      9  *distribute, sublicense, and/or sell copies of the Software, and to
     10  *permit persons to whom the Software is furnished to do so, subject to
     11  *the following conditions:
     12  *
     13  *The above copyright notice and this permission notice shall be
     14  *included in all copies or substantial portions of the Software.
     15  *
     16  *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     17  *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18  *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     19  *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
     20  *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     21  *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     22  *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  *Except as contained in this notice, the name of the XFree86 Project
     25  *shall not be used in advertising or otherwise to promote the sale, use
     26  *or other dealings in this Software without prior written authorization
     27  *from the XFree86 Project.
     28  *
     29  * Authors:	Kensuke Matsuzaki
     30  *              Colin Harrison
     31  */
     32 
     33 /* X headers */
     34 #ifdef HAVE_XWIN_CONFIG_H
     35 #include <xwin-config.h>
     36 #endif
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <unistd.h>
     40 #ifdef __CYGWIN__
     41 #include <sys/select.h>
     42 #endif
     43 #include <fcntl.h>
     44 #include <setjmp.h>
     45 #define HANDLE void *
     46 #include <pthread.h>
     47 #undef HANDLE
     48 #include <xcb/xcb.h>
     49 #include <xcb/xcb_icccm.h>
     50 #include <xcb/xcb_ewmh.h>
     51 #include <xcb/xcb_aux.h>
     52 #include <xcb/composite.h>
     53 
     54 #include <X11/Xwindows.h>
     55 
     56 /* Local headers */
     57 #include "X11/Xdefs.h" // for Bool type
     58 #include "winwindow.h"
     59 #include "winprefs.h"
     60 #include "window.h"
     61 #include "pixmapstr.h"
     62 #include "windowstr.h"
     63 #include "winglobals.h"
     64 #include "windisplay.h"
     65 #include "winmultiwindowicons.h"
     66 #include "winauth.h"
     67 
     68 /* We need the native HWND atom for intWM, so for consistency use the
     69    same name as extWM does */
     70 #define WINDOWSWM_NATIVE_HWND "_WINDOWSWM_NATIVE_HWND"
     71 
     72 #ifndef HOST_NAME_MAX
     73 #define HOST_NAME_MAX 255
     74 #endif
     75 
     76 extern void winDebug(const char *format, ...);
     77 extern void winReshapeMultiWindow(WindowPtr pWin);
     78 extern void winUpdateRgnMultiWindow(WindowPtr pWin);
     79 
     80 #ifndef CYGDEBUG
     81 #define CYGDEBUG NO
     82 #endif
     83 
     84 /*
     85  * Constant defines
     86  */
     87 
     88 #define WIN_CONNECT_RETRIES	5
     89 #define WIN_CONNECT_DELAY	5
     90 #ifdef HAS_DEVWINDOWS
     91 #define WIN_MSG_QUEUE_FNAME	"/dev/windows"
     92 #endif
     93 
     94 /*
     95  * Local structures
     96  */
     97 
     98 typedef struct _WMMsgNodeRec {
     99     winWMMessageRec msg;
    100     struct _WMMsgNodeRec *pNext;
    101 } WMMsgNodeRec, *WMMsgNodePtr;
    102 
    103 typedef struct _WMMsgQueueRec {
    104     struct _WMMsgNodeRec *pHead;
    105     struct _WMMsgNodeRec *pTail;
    106     pthread_mutex_t pmMutex;
    107     pthread_cond_t pcNotEmpty;
    108 } WMMsgQueueRec, *WMMsgQueuePtr;
    109 
    110 typedef struct _WMInfo {
    111     xcb_connection_t *conn;
    112     WMMsgQueueRec wmMsgQueue;
    113     xcb_atom_t atmWmProtos;
    114     xcb_atom_t atmWmDelete;
    115     xcb_atom_t atmWmTakeFocus;
    116     xcb_atom_t atmPrivMap;
    117     xcb_atom_t atmUtf8String;
    118     xcb_atom_t atmNetWmName;
    119     xcb_atom_t atmCurrentDesktop;
    120     xcb_atom_t atmNumberDesktops;
    121     xcb_atom_t atmDesktopNames;
    122     xcb_ewmh_connection_t ewmh;
    123     Bool fCompositeWM;
    124 } WMInfoRec, *WMInfoPtr;
    125 
    126 typedef struct _WMProcArgRec {
    127     DWORD dwScreen;
    128     WMInfoPtr pWMInfo;
    129     pthread_mutex_t *ppmServerStarted;
    130 } WMProcArgRec, *WMProcArgPtr;
    131 
    132 typedef struct _XMsgProcArgRec {
    133     xcb_connection_t *conn;
    134     DWORD dwScreen;
    135     WMInfoPtr pWMInfo;
    136     pthread_mutex_t *ppmServerStarted;
    137     HWND hwndScreen;
    138 } XMsgProcArgRec, *XMsgProcArgPtr;
    139 
    140 /*
    141  * Prototypes for local functions
    142  */
    143 
    144 static void
    145  PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode);
    146 
    147 static WMMsgNodePtr PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo);
    148 
    149 static Bool
    150  InitQueue(WMMsgQueuePtr pQueue);
    151 
    152 static void
    153  GetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName);
    154 
    155 static void
    156  SendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData);
    157 
    158 static void
    159  UpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow);
    160 
    161 static void *winMultiWindowWMProc(void *pArg);
    162 
    163 static void *winMultiWindowXMsgProc(void *pArg);
    164 
    165 static void
    166  winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg);
    167 
    168 #if 0
    169 static void
    170  PreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction);
    171 #endif
    172 
    173 static Bool
    174 CheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen);
    175 
    176 static void
    177  winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle);
    178 
    179 void
    180  winUpdateWindowPosition(HWND hWnd, HWND * zstyle);
    181 
    182 /*
    183  * Local globals
    184  */
    185 
    186 static Bool g_shutdown = FALSE;
    187 
    188 /*
    189  * Translate msg id to text, for debug purposes
    190  */
    191 
    192 #if CYGMULTIWINDOW_DEBUG
    193 static const char *
    194 MessageName(winWMMessagePtr msg)
    195 {
    196   switch (msg->msg)
    197     {
    198     case WM_WM_MOVE:
    199       return "WM_WM_MOVE";
    200       break;
    201     case WM_WM_SIZE:
    202       return "WM_WM_SIZE";
    203       break;
    204     case WM_WM_RAISE:
    205       return "WM_WM_RAISE";
    206       break;
    207     case WM_WM_LOWER:
    208       return "WM_WM_LOWER";
    209       break;
    210     case WM_WM_UNMAP:
    211       return "WM_WM_UNMAP";
    212       break;
    213     case WM_WM_KILL:
    214       return "WM_WM_KILL";
    215       break;
    216     case WM_WM_ACTIVATE:
    217       return "WM_WM_ACTIVATE";
    218       break;
    219     case WM_WM_NAME_EVENT:
    220       return "WM_WM_NAME_EVENT";
    221       break;
    222     case WM_WM_ICON_EVENT:
    223       return "WM_WM_ICON_EVENT";
    224       break;
    225     case WM_WM_CHANGE_STATE:
    226       return "WM_WM_CHANGE_STATE";
    227       break;
    228     case WM_WM_MAP_UNMANAGED:
    229       return "WM_WM_MAP_UNMANAGED";
    230       break;
    231     case WM_WM_MAP_MANAGED:
    232       return "WM_WM_MAP_MANAGED";
    233       break;
    234     case WM_WM_HINTS_EVENT:
    235       return "WM_WM_HINTS_EVENT";
    236       break;
    237     default:
    238       return "Unknown Message";
    239       break;
    240     }
    241 }
    242 #endif
    243 
    244 
    245 /*
    246  * PushMessage - Push a message onto the queue
    247  */
    248 
    249 static void
    250 PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode)
    251 {
    252 
    253     /* Lock the queue mutex */
    254     pthread_mutex_lock(&pQueue->pmMutex);
    255 
    256     pNode->pNext = NULL;
    257 
    258     if (pQueue->pTail != NULL) {
    259         pQueue->pTail->pNext = pNode;
    260     }
    261     pQueue->pTail = pNode;
    262 
    263     if (pQueue->pHead == NULL) {
    264         pQueue->pHead = pNode;
    265     }
    266 
    267     /* Release the queue mutex */
    268     pthread_mutex_unlock(&pQueue->pmMutex);
    269 
    270     /* Signal that the queue is not empty */
    271     pthread_cond_signal(&pQueue->pcNotEmpty);
    272 }
    273 
    274 /*
    275  * PopMessage - Pop a message from the queue
    276  */
    277 
    278 static WMMsgNodePtr
    279 PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo)
    280 {
    281     WMMsgNodePtr pNode;
    282 
    283     /* Lock the queue mutex */
    284     pthread_mutex_lock(&pQueue->pmMutex);
    285 
    286     /* Wait for --- */
    287     while (pQueue->pHead == NULL) {
    288         pthread_cond_wait(&pQueue->pcNotEmpty, &pQueue->pmMutex);
    289     }
    290 
    291     pNode = pQueue->pHead;
    292     if (pQueue->pHead != NULL) {
    293         pQueue->pHead = pQueue->pHead->pNext;
    294     }
    295 
    296     if (pQueue->pTail == pNode) {
    297         pQueue->pTail = NULL;
    298     }
    299 
    300     /* Release the queue mutex */
    301     pthread_mutex_unlock(&pQueue->pmMutex);
    302 
    303     return pNode;
    304 }
    305 
    306 #if 0
    307 /*
    308  * HaveMessage -
    309  */
    310 
    311 static Bool
    312 HaveMessage(WMMsgQueuePtr pQueue, UINT msg, xcb_window_t iWindow)
    313 {
    314     WMMsgNodePtr pNode;
    315 
    316     for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) {
    317         if (pNode->msg.msg == msg && pNode->msg.iWindow == iWindow)
    318             return True;
    319     }
    320 
    321     return False;
    322 }
    323 #endif
    324 
    325 /*
    326  * InitQueue - Initialize the Window Manager message queue
    327  */
    328 
    329 static
    330     Bool
    331 InitQueue(WMMsgQueuePtr pQueue)
    332 {
    333     /* Check if the pQueue pointer is NULL */
    334     if (pQueue == NULL) {
    335         ErrorF("InitQueue - pQueue is NULL.  Exiting.\n");
    336         return FALSE;
    337     }
    338 
    339     /* Set the head and tail to NULL */
    340     pQueue->pHead = NULL;
    341     pQueue->pTail = NULL;
    342 
    343     winDebug("InitQueue - Calling pthread_mutex_init\n");
    344 
    345     /* Create synchronization objects */
    346     pthread_mutex_init(&pQueue->pmMutex, NULL);
    347 
    348     winDebug("InitQueue - pthread_mutex_init returned\n");
    349     winDebug("InitQueue - Calling pthread_cond_init\n");
    350 
    351     pthread_cond_init(&pQueue->pcNotEmpty, NULL);
    352 
    353     winDebug("InitQueue - pthread_cond_init returned\n");
    354 
    355     return TRUE;
    356 }
    357 
    358 static
    359 char *
    360 Xutf8TextPropertyToString(WMInfoPtr pWMInfo, xcb_icccm_get_text_property_reply_t *xtp)
    361 {
    362     char *pszReturnData;
    363 
    364     if ((xtp->encoding == XCB_ATOM_STRING) ||        // Latin1 ISO 8859-1
    365         (xtp->encoding == pWMInfo->atmUtf8String)) { // UTF-8  ISO 10646
    366         pszReturnData = strndup(xtp->name, xtp->name_len);
    367     }
    368     else {
    369         // Converting from COMPOUND_TEXT to UTF-8 properly is complex to
    370         // implement, and not very much use unless you have an old
    371         // application which isn't UTF-8 aware.
    372         ErrorF("Xutf8TextPropertyToString: text encoding %d is not implemented\n", xtp->encoding);
    373         pszReturnData = strdup("");
    374     }
    375 
    376     return pszReturnData;
    377 }
    378 
    379 /*
    380  * GetWindowName - Retrieve the title of an X Window
    381  */
    382 
    383 static void
    384 GetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName)
    385 {
    386     xcb_connection_t *conn = pWMInfo->conn;
    387     char *pszWindowName = NULL;
    388 
    389 #if CYGMULTIWINDOW_DEBUG
    390     ErrorF("GetWindowName\n");
    391 #endif
    392 
    393     /* Try to get window name from _NET_WM_NAME */
    394     {
    395         xcb_get_property_cookie_t cookie;
    396         xcb_get_property_reply_t *reply;
    397 
    398         cookie = xcb_get_property(pWMInfo->conn, FALSE, iWin,
    399                                   pWMInfo->atmNetWmName,
    400                                   XCB_GET_PROPERTY_TYPE_ANY, 0, INT_MAX);
    401         reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL);
    402         if (reply && (reply->type != XCB_NONE)) {
    403             pszWindowName = strndup(xcb_get_property_value(reply),
    404                                     xcb_get_property_value_length(reply));
    405             free(reply);
    406         }
    407     }
    408 
    409     /* Otherwise, try to get window name from WM_NAME */
    410     if (!pszWindowName)
    411         {
    412             xcb_get_property_cookie_t cookie;
    413             xcb_icccm_get_text_property_reply_t reply;
    414 
    415             cookie = xcb_icccm_get_wm_name(conn, iWin);
    416             if (!xcb_icccm_get_wm_name_reply(conn, cookie, &reply, NULL)) {
    417                 ErrorF("GetWindowName - xcb_icccm_get_wm_name_reply failed.  No name.\n");
    418                 *ppWindowName = NULL;
    419                 return;
    420             }
    421 
    422             pszWindowName = Xutf8TextPropertyToString(pWMInfo, &reply);
    423             xcb_icccm_get_text_property_reply_wipe(&reply);
    424         }
    425 
    426     /* return the window name, unless... */
    427     *ppWindowName = pszWindowName;
    428 
    429     if (g_fHostInTitle) {
    430         xcb_get_property_cookie_t cookie;
    431         xcb_icccm_get_text_property_reply_t reply;
    432 
    433         /* Try to get client machine name */
    434         cookie = xcb_icccm_get_wm_client_machine(conn, iWin);
    435         if (xcb_icccm_get_wm_client_machine_reply(conn, cookie, &reply, NULL)) {
    436             char *pszClientMachine;
    437             char *pszClientHostname;
    438             char *dot;
    439             char hostname[HOST_NAME_MAX + 1];
    440 
    441             pszClientMachine = Xutf8TextPropertyToString(pWMInfo, &reply);
    442             xcb_icccm_get_text_property_reply_wipe(&reply);
    443 
    444             /* If client machine name looks like a FQDN, find the hostname */
    445             pszClientHostname = strdup(pszClientMachine);
    446             dot = strchr(pszClientHostname, '.');
    447             if (dot)
    448                 *dot = '\0';
    449 
    450             /*
    451                If we have a client machine hostname
    452                and it's not the local hostname
    453                and it's not already in the window title...
    454              */
    455             if (strlen(pszClientHostname) &&
    456                 !gethostname(hostname, HOST_NAME_MAX + 1) &&
    457                 strcmp(hostname, pszClientHostname) &&
    458                 (strstr(pszWindowName, pszClientHostname) == 0)) {
    459                 /* ... add '@<clientmachine>' to end of window name */
    460                 *ppWindowName =
    461                     malloc(strlen(pszWindowName) +
    462                            strlen(pszClientMachine) + 2);
    463                 strcpy(*ppWindowName, pszWindowName);
    464                 strcat(*ppWindowName, "@");
    465                 strcat(*ppWindowName, pszClientMachine);
    466 
    467                 free(pszWindowName);
    468             }
    469 
    470             free(pszClientMachine);
    471             free(pszClientHostname);
    472         }
    473     }
    474 }
    475 
    476 /*
    477  * Does the client support the specified WM_PROTOCOLS protocol?
    478  */
    479 
    480 static Bool
    481 IsWmProtocolAvailable(WMInfoPtr pWMInfo, xcb_window_t iWindow, xcb_atom_t atmProtocol)
    482 {
    483   int i, found = 0;
    484   xcb_get_property_cookie_t cookie;
    485   xcb_icccm_get_wm_protocols_reply_t reply;
    486   xcb_connection_t *conn = pWMInfo->conn;
    487 
    488   cookie = xcb_icccm_get_wm_protocols(conn, iWindow, pWMInfo->ewmh.WM_PROTOCOLS);
    489   if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &reply, NULL)) {
    490     for (i = 0; i < reply.atoms_len; ++i)
    491       if (reply.atoms[i] == atmProtocol) {
    492               ++found;
    493               break;
    494       }
    495     xcb_icccm_get_wm_protocols_reply_wipe(&reply);
    496   }
    497 
    498   return found > 0;
    499 }
    500 
    501 /*
    502  * Send a message to the X server from the WM thread
    503  */
    504 
    505 static void
    506 SendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData)
    507 {
    508     xcb_client_message_event_t e;
    509 
    510     /* Prepare the X event structure */
    511     memset(&e, 0, sizeof(e));
    512     e.response_type = XCB_CLIENT_MESSAGE;
    513     e.window = iWin;
    514     e.type = atmType;
    515     e.format = 32;
    516     e.data.data32[0] = nData;
    517     e.data.data32[1] = XCB_CURRENT_TIME;
    518 
    519     /* Send the event to X */
    520     xcb_send_event(conn, FALSE, iWin, XCB_EVENT_MASK_NO_EVENT, (const char *)&e);
    521 }
    522 
    523 /*
    524  * See if we can get the stored HWND for this window...
    525  */
    526 static HWND
    527 getHwnd(WMInfoPtr pWMInfo, xcb_window_t iWindow)
    528 {
    529     HWND hWnd = NULL;
    530     xcb_get_property_cookie_t cookie;
    531     xcb_get_property_reply_t *reply;
    532 
    533     cookie = xcb_get_property(pWMInfo->conn, FALSE, iWindow, pWMInfo->atmPrivMap,
    534                               XCB_ATOM_INTEGER, 0L, sizeof(HWND)/4L);
    535     reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL);
    536 
    537     if (reply) {
    538         int length = xcb_get_property_value_length(reply);
    539         HWND *value = xcb_get_property_value(reply);
    540 
    541         if (value && (length == sizeof(HWND))) {
    542             hWnd = *value;
    543         }
    544         free(reply);
    545     }
    546 
    547     /* Some sanity checks */
    548     if (!hWnd)
    549         return NULL;
    550     if (!IsWindow(hWnd))
    551         return NULL;
    552 
    553     return hWnd;
    554 }
    555 
    556 /*
    557  * Helper function to check for override-redirect
    558  */
    559 static Bool
    560 IsOverrideRedirect(xcb_connection_t *conn, xcb_window_t iWin)
    561 {
    562     Bool result = FALSE;
    563     xcb_get_window_attributes_reply_t *reply;
    564     xcb_get_window_attributes_cookie_t cookie;
    565 
    566     cookie = xcb_get_window_attributes(conn, iWin);
    567     reply = xcb_get_window_attributes_reply(conn, cookie, NULL);
    568     if (reply) {
    569         result = (reply->override_redirect != 0);
    570         free(reply);
    571     }
    572     else {
    573         ErrorF("IsOverrideRedirect: Failed to get window attributes\n");
    574     }
    575 
    576     return result;
    577 }
    578 
    579 /*
    580  * Helper function to get class and window names
    581 */
    582 static void
    583 GetClassNames(WMInfoPtr pWMInfo, xcb_window_t iWindow, char **res_name,
    584               char **res_class, char **window_name)
    585 {
    586     xcb_get_property_cookie_t cookie1;
    587     xcb_icccm_get_wm_class_reply_t reply1;
    588     xcb_get_property_cookie_t cookie2;
    589     xcb_icccm_get_text_property_reply_t reply2;
    590 
    591     cookie1 = xcb_icccm_get_wm_class(pWMInfo->conn, iWindow);
    592     if (xcb_icccm_get_wm_class_reply(pWMInfo->conn, cookie1, &reply1,
    593                                      NULL)) {
    594         *res_name = strdup(reply1.instance_name);
    595         *res_class = strdup(reply1.class_name);
    596         xcb_icccm_get_wm_class_reply_wipe(&reply1);
    597     }
    598     else {
    599         *res_name = strdup("");
    600         *res_class = strdup("");
    601     }
    602 
    603     cookie2 = xcb_icccm_get_wm_name(pWMInfo->conn, iWindow);
    604     if (xcb_icccm_get_wm_name_reply(pWMInfo->conn, cookie2, &reply2, NULL)) {
    605         *window_name = strndup(reply2.name, reply2.name_len);
    606         xcb_icccm_get_text_property_reply_wipe(&reply2);
    607     }
    608     else {
    609         *window_name = strdup("");
    610     }
    611 }
    612 
    613 /*
    614  * Updates the name of a HWND according to its X WM_NAME property
    615  */
    616 
    617 static void
    618 UpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow)
    619 {
    620     HWND hWnd;
    621 
    622     hWnd = getHwnd(pWMInfo, iWindow);
    623     if (!hWnd)
    624         return;
    625 
    626     /* If window isn't override-redirect */
    627     if (!IsOverrideRedirect(pWMInfo->conn, iWindow)) {
    628         char *pszWindowName;
    629 
    630         /* Get the X windows window name */
    631         GetWindowName(pWMInfo, iWindow, &pszWindowName);
    632 
    633         if (pszWindowName) {
    634             /* Convert from UTF-8 to wide char */
    635             int iLen =
    636                 MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1, NULL, 0);
    637             wchar_t *pwszWideWindowName =
    638                 malloc(sizeof(wchar_t)*(iLen + 1));
    639             MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1,
    640                                 pwszWideWindowName, iLen);
    641 
    642             /* Set the Windows window name */
    643             SetWindowTextW(hWnd, pwszWideWindowName);
    644 
    645             free(pwszWideWindowName);
    646             free(pszWindowName);
    647         }
    648     }
    649 }
    650 
    651 /*
    652  * Updates the icon of a HWND according to its X icon properties
    653  */
    654 
    655 static void
    656 UpdateIcon(WMInfoPtr pWMInfo, xcb_window_t iWindow)
    657 {
    658     HWND hWnd;
    659     HICON hIconNew = NULL;
    660 
    661     hWnd = getHwnd(pWMInfo, iWindow);
    662     if (!hWnd)
    663         return;
    664 
    665     /* If window isn't override-redirect */
    666     if (!IsOverrideRedirect(pWMInfo->conn, iWindow)) {
    667         char *window_name = 0;
    668         char *res_name = 0;
    669         char *res_class = 0;
    670 
    671         GetClassNames(pWMInfo, iWindow, &res_name, &res_class, &window_name);
    672 
    673         hIconNew = winOverrideIcon(res_name, res_class, window_name);
    674 
    675         free(res_name);
    676         free(res_class);
    677         free(window_name);
    678         winUpdateIcon(hWnd, pWMInfo->conn, iWindow, hIconNew);
    679     }
    680 }
    681 
    682 /*
    683  * Updates the style of a HWND according to its X style properties
    684  */
    685 
    686 static void
    687 UpdateStyle(WMInfoPtr pWMInfo, xcb_window_t iWindow)
    688 {
    689     HWND hWnd;
    690     HWND zstyle = HWND_NOTOPMOST;
    691     UINT flags;
    692 
    693     hWnd = getHwnd(pWMInfo, iWindow);
    694     if (!hWnd)
    695         return;
    696 
    697     /* Determine the Window style, which determines borders and clipping region... */
    698     winApplyHints(pWMInfo, iWindow, hWnd, &zstyle);
    699     winUpdateWindowPosition(hWnd, &zstyle);
    700 
    701     /* Apply the updated window style, without changing its show or activation state */
    702     flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE;
    703     if (zstyle == HWND_NOTOPMOST)
    704         flags |= SWP_NOZORDER | SWP_NOOWNERZORDER;
    705     SetWindowPos(hWnd, NULL, 0, 0, 0, 0, flags);
    706 
    707     /*
    708        Use the WS_EX_TOOLWINDOW style to remove window from Alt-Tab window switcher
    709 
    710        According to MSDN, this is supposed to remove the window from the taskbar as well,
    711        if we SW_HIDE before changing the style followed by SW_SHOW afterwards.
    712 
    713        But that doesn't seem to work reliably, and causes the window to flicker, so use
    714        the iTaskbarList interface to tell the taskbar to show or hide this window.
    715      */
    716     winShowWindowOnTaskbar(hWnd,
    717                            (GetWindowLongPtr(hWnd, GWL_EXSTYLE) &
    718                             WS_EX_APPWINDOW) ? TRUE : FALSE);
    719 }
    720 
    721 /*
    722  * Updates the state of a HWND
    723  * (only minimization supported at the moment)
    724  */
    725 
    726 static void
    727 UpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow)
    728 {
    729     HWND hWnd;
    730 
    731     winDebug("UpdateState: iWindow 0x%08x\n", (int)iWindow);
    732 
    733     hWnd = getHwnd(pWMInfo, iWindow);
    734     if (!hWnd)
    735         return;
    736 
    737     ShowWindow(hWnd, SW_MINIMIZE);
    738 }
    739 
    740 #if 0
    741 /*
    742  * Fix up any differences between the X11 and Win32 window stacks
    743  * starting at the window passed in
    744  */
    745 static void
    746 PreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction)
    747 {
    748     HWND hWnd;
    749     DWORD myWinProcID, winProcID;
    750     xcb_window_t xWindow;
    751     WINDOWPLACEMENT wndPlace;
    752 
    753     hWnd = getHwnd(pWMInfo, iWindow);
    754     if (!hWnd)
    755         return;
    756 
    757     GetWindowThreadProcessId(hWnd, &myWinProcID);
    758     hWnd = GetNextWindow(hWnd, direction);
    759 
    760     while (hWnd) {
    761         GetWindowThreadProcessId(hWnd, &winProcID);
    762         if (winProcID == myWinProcID) {
    763             wndPlace.length = sizeof(WINDOWPLACEMENT);
    764             GetWindowPlacement(hWnd, &wndPlace);
    765             if (!(wndPlace.showCmd == SW_HIDE ||
    766                   wndPlace.showCmd == SW_MINIMIZE)) {
    767                 xWindow = (Window) GetProp(hWnd, WIN_WID_PROP);
    768                 if (xWindow) {
    769                     if (direction == GW_HWNDPREV)
    770                         XRaiseWindow(pWMInfo->pDisplay, xWindow);
    771                     else
    772                         XLowerWindow(pWMInfo->pDisplay, xWindow);
    773                 }
    774             }
    775         }
    776         hWnd = GetNextWindow(hWnd, direction);
    777     }
    778 }
    779 #endif                          /* PreserveWin32Stack */
    780 
    781 /*
    782  * winMultiWindowWMProc
    783  */
    784 
    785 static void *
    786 winMultiWindowWMProc(void *pArg)
    787 {
    788     WMProcArgPtr pProcArg = (WMProcArgPtr) pArg;
    789     WMInfoPtr pWMInfo = pProcArg->pWMInfo;
    790 
    791     /* Initialize the Window Manager */
    792     winInitMultiWindowWM(pWMInfo, pProcArg);
    793 
    794 #if CYGMULTIWINDOW_DEBUG
    795     ErrorF("winMultiWindowWMProc ()\n");
    796 #endif
    797 
    798     /* Loop until we explicitly break out */
    799     for (;;) {
    800         WMMsgNodePtr pNode;
    801 
    802         /* Pop a message off of our queue */
    803         pNode = PopMessage(&pWMInfo->wmMsgQueue, pWMInfo);
    804         if (pNode == NULL) {
    805             /* Bail if PopMessage returns without a message */
    806             /* NOTE: Remember that PopMessage is a blocking function. */
    807             ErrorF("winMultiWindowWMProc - Queue is Empty?  Exiting.\n");
    808             pthread_exit(NULL);
    809         }
    810 
    811 #if CYGMULTIWINDOW_DEBUG
    812         ErrorF("winMultiWindowWMProc - MSG: %s (%d) ID: %d\n",
    813                MessageName(&(pNode->msg)), (int)pNode->msg.msg, (int)pNode->msg.dwID);
    814 #endif
    815 
    816         /* Branch on the message type */
    817         switch (pNode->msg.msg) {
    818 #if 0
    819         case WM_WM_MOVE:
    820             break;
    821 
    822         case WM_WM_SIZE:
    823             break;
    824 #endif
    825 
    826         case WM_WM_RAISE:
    827             /* Raise the window */
    828             {
    829                 const static uint32_t values[] = { XCB_STACK_MODE_ABOVE };
    830                 xcb_configure_window(pWMInfo->conn, pNode->msg.iWindow,
    831                                      XCB_CONFIG_WINDOW_STACK_MODE, values);
    832             }
    833 
    834 #if 0
    835             PreserveWin32Stack(pWMInfo, pNode->msg.iWindow, GW_HWNDPREV);
    836 #endif
    837             break;
    838 
    839         case WM_WM_LOWER:
    840             /* Lower the window */
    841             {
    842                 const static uint32_t values[] = { XCB_STACK_MODE_BELOW };
    843                 xcb_configure_window(pWMInfo->conn, pNode->msg.iWindow,
    844                                      XCB_CONFIG_WINDOW_STACK_MODE, values);
    845             }
    846             break;
    847 
    848         case WM_WM_MAP_UNMANAGED:
    849             /* Put a note as to the HWND associated with this Window */
    850             xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE,
    851                                 pNode->msg.iWindow, pWMInfo->atmPrivMap,
    852                                 XCB_ATOM_INTEGER, 32,
    853                                 sizeof(HWND)/4, &(pNode->msg.hwndWindow));
    854 
    855             break;
    856 
    857         case WM_WM_MAP_MANAGED:
    858             /* Put a note as to the HWND associated with this Window */
    859             xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE,
    860                                 pNode->msg.iWindow, pWMInfo->atmPrivMap,
    861                                 XCB_ATOM_INTEGER, 32,
    862                                 sizeof(HWND)/4, &(pNode->msg.hwndWindow));
    863 
    864             UpdateName(pWMInfo, pNode->msg.iWindow);
    865             UpdateIcon(pWMInfo, pNode->msg.iWindow);
    866             UpdateStyle(pWMInfo, pNode->msg.iWindow);
    867 
    868 
    869             /* Reshape */
    870             {
    871                 WindowPtr pWin =
    872                     GetProp(pNode->msg.hwndWindow, WIN_WINDOW_PROP);
    873                 if (pWin) {
    874                     winReshapeMultiWindow(pWin);
    875                     winUpdateRgnMultiWindow(pWin);
    876                 }
    877             }
    878 
    879             break;
    880 
    881         case WM_WM_UNMAP:
    882 
    883             /* Unmap the window */
    884             xcb_unmap_window(pWMInfo->conn, pNode->msg.iWindow);
    885             break;
    886 
    887         case WM_WM_KILL:
    888             {
    889                 /* --- */
    890                 if (IsWmProtocolAvailable(pWMInfo,
    891                                           pNode->msg.iWindow,
    892                                           pWMInfo->atmWmDelete))
    893                     SendXMessage(pWMInfo->conn,
    894                                  pNode->msg.iWindow,
    895                                  pWMInfo->atmWmProtos, pWMInfo->atmWmDelete);
    896                 else
    897                     xcb_kill_client(pWMInfo->conn, pNode->msg.iWindow);
    898             }
    899             break;
    900 
    901         case WM_WM_ACTIVATE:
    902             /* Set the input focus */
    903 
    904             /*
    905                ICCCM 4.1.7 is pretty opaque, but it appears that the rules are
    906                actually quite simple:
    907                -- the WM_HINTS input field determines whether the WM should call
    908                XSetInputFocus()
    909                -- independently, the WM_TAKE_FOCUS protocol determines whether
    910                the WM should send a WM_TAKE_FOCUS ClientMessage.
    911             */
    912             {
    913               Bool neverFocus = FALSE;
    914               xcb_get_property_cookie_t cookie;
    915               xcb_icccm_wm_hints_t hints;
    916 
    917               cookie = xcb_icccm_get_wm_hints(pWMInfo->conn, pNode->msg.iWindow);
    918               if (xcb_icccm_get_wm_hints_reply(pWMInfo->conn, cookie, &hints,
    919                                                NULL)) {
    920                 if (hints.flags & XCB_ICCCM_WM_HINT_INPUT)
    921                   neverFocus = !hints.input;
    922               }
    923 
    924               if (!neverFocus)
    925                 xcb_set_input_focus(pWMInfo->conn, XCB_INPUT_FOCUS_POINTER_ROOT,
    926                                     pNode->msg.iWindow, XCB_CURRENT_TIME);
    927 
    928               if (IsWmProtocolAvailable(pWMInfo,
    929                                         pNode->msg.iWindow,
    930                                         pWMInfo->atmWmTakeFocus))
    931                 SendXMessage(pWMInfo->conn,
    932                              pNode->msg.iWindow,
    933                              pWMInfo->atmWmProtos, pWMInfo->atmWmTakeFocus);
    934 
    935             }
    936             break;
    937 
    938         case WM_WM_NAME_EVENT:
    939             UpdateName(pWMInfo, pNode->msg.iWindow);
    940             break;
    941 
    942         case WM_WM_ICON_EVENT:
    943             UpdateIcon(pWMInfo, pNode->msg.iWindow);
    944             break;
    945 
    946         case WM_WM_HINTS_EVENT:
    947             {
    948             /* Don't do anything if this is an override-redirect window */
    949             if (IsOverrideRedirect(pWMInfo->conn, pNode->msg.iWindow))
    950               break;
    951 
    952             UpdateStyle(pWMInfo, pNode->msg.iWindow);
    953             }
    954             break;
    955 
    956         case WM_WM_CHANGE_STATE:
    957             UpdateState(pWMInfo, pNode->msg.iWindow);
    958             break;
    959 
    960         default:
    961             ErrorF("winMultiWindowWMProc - Unknown Message.  Exiting.\n");
    962             pthread_exit(NULL);
    963             break;
    964         }
    965 
    966         /* Free the retrieved message */
    967         free(pNode);
    968 
    969         /* Flush any pending events on our display */
    970         xcb_flush(pWMInfo->conn);
    971 
    972         /* This is just laziness rather than making sure we used _checked everywhere */
    973         {
    974             xcb_generic_event_t *event = xcb_poll_for_event(pWMInfo->conn);
    975             if (event) {
    976                 if ((event->response_type & ~0x80) == 0) {
    977                     xcb_generic_error_t *err = (xcb_generic_error_t *)event;
    978                     ErrorF("winMultiWindowWMProc - Error code: %i, ID: 0x%08x, "
    979                            "Major opcode: %i, Minor opcode: %i\n",
    980                            err->error_code, err->resource_id,
    981                            err->major_code, err->minor_code);
    982                 }
    983             }
    984         }
    985 
    986         /* I/O errors etc. */
    987         {
    988             int e = xcb_connection_has_error(pWMInfo->conn);
    989             if (e) {
    990                 ErrorF("winMultiWindowWMProc - Fatal error %d on xcb connection\n", e);
    991                 break;
    992             }
    993         }
    994     }
    995 
    996     /* Free the condition variable */
    997     pthread_cond_destroy(&pWMInfo->wmMsgQueue.pcNotEmpty);
    998 
    999     /* Free the mutex variable */
   1000     pthread_mutex_destroy(&pWMInfo->wmMsgQueue.pmMutex);
   1001 
   1002     /* Free the passed-in argument */
   1003     free(pProcArg);
   1004 
   1005 #if CYGMULTIWINDOW_DEBUG
   1006     ErrorF("-winMultiWindowWMProc ()\n");
   1007 #endif
   1008     return NULL;
   1009 }
   1010 
   1011 static xcb_atom_t
   1012 intern_atom(xcb_connection_t *conn, const char *atomName)
   1013 {
   1014   xcb_intern_atom_reply_t *atom_reply;
   1015   xcb_intern_atom_cookie_t atom_cookie;
   1016   xcb_atom_t atom = XCB_ATOM_NONE;
   1017 
   1018   atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName);
   1019   atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL);
   1020   if (atom_reply) {
   1021     atom = atom_reply->atom;
   1022     free(atom_reply);
   1023   }
   1024   return atom;
   1025 }
   1026 
   1027 /*
   1028  * X message procedure
   1029  */
   1030 
   1031 static void *
   1032 winMultiWindowXMsgProc(void *pArg)
   1033 {
   1034     winWMMessageRec msg;
   1035     XMsgProcArgPtr pProcArg = (XMsgProcArgPtr) pArg;
   1036     char pszDisplay[512];
   1037     int iRetries;
   1038     xcb_atom_t atmWmName;
   1039     xcb_atom_t atmNetWmName;
   1040     xcb_atom_t atmWmHints;
   1041     xcb_atom_t atmWmChange;
   1042     xcb_atom_t atmNetWmIcon;
   1043     xcb_atom_t atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints;
   1044     int iReturn;
   1045     xcb_auth_info_t *auth_info;
   1046     xcb_screen_t *root_screen;
   1047     xcb_window_t root_window_id;
   1048 
   1049     winDebug("winMultiWindowXMsgProc - Hello\n");
   1050 
   1051     /* Check that argument pointer is not invalid */
   1052     if (pProcArg == NULL) {
   1053         ErrorF("winMultiWindowXMsgProc - pProcArg is NULL.  Exiting.\n");
   1054         pthread_exit(NULL);
   1055     }
   1056 
   1057     winDebug("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n");
   1058 
   1059     /* Grab the server started mutex - pause until we get it */
   1060     iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
   1061     if (iReturn != 0) {
   1062         ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () failed: %d.  "
   1063                "Exiting.\n", iReturn);
   1064         pthread_exit(NULL);
   1065     }
   1066 
   1067     winDebug("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n");
   1068 
   1069     /* Release the server started mutex */
   1070     pthread_mutex_unlock(pProcArg->ppmServerStarted);
   1071 
   1072     winDebug("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n");
   1073 
   1074     /* Setup the display connection string x */
   1075     winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen);
   1076 
   1077     /* Print the display connection string */
   1078     ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay);
   1079 
   1080     /* Use our generated cookie for authentication */
   1081     auth_info = winGetXcbAuthInfo();
   1082 
   1083     /* Initialize retry count */
   1084     iRetries = 0;
   1085 
   1086     /* Open the X display */
   1087     do {
   1088         /* Try to open the display */
   1089         pProcArg->conn = xcb_connect_to_display_with_auth_info(pszDisplay,
   1090                                                                auth_info, NULL);
   1091         if (xcb_connection_has_error(pProcArg->conn)) {
   1092             ErrorF("winMultiWindowXMsgProc - Could not open display, try: %d, "
   1093                    "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
   1094             ++iRetries;
   1095             sleep(WIN_CONNECT_DELAY);
   1096             continue;
   1097         }
   1098         else
   1099             break;
   1100     }
   1101     while (xcb_connection_has_error(pProcArg->conn) && iRetries < WIN_CONNECT_RETRIES);
   1102 
   1103     /* Make sure that the display opened */
   1104     if (xcb_connection_has_error(pProcArg->conn)) {
   1105         ErrorF("winMultiWindowXMsgProc - Failed opening the display.  "
   1106                "Exiting.\n");
   1107         pthread_exit(NULL);
   1108     }
   1109 
   1110     ErrorF("winMultiWindowXMsgProc - xcb_connect() returned and "
   1111            "successfully opened the display.\n");
   1112 
   1113     /* Check if another window manager is already running */
   1114     if (CheckAnotherWindowManager(pProcArg->conn, pProcArg->dwScreen)) {
   1115         ErrorF("winMultiWindowXMsgProc - "
   1116                "another window manager is running.  Exiting.\n");
   1117         pthread_exit(NULL);
   1118     }
   1119 
   1120     /* Get root window id */
   1121     root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen);
   1122     root_window_id = root_screen->root;
   1123 
   1124     {
   1125         /* Set WM_ICON_SIZE property indicating desired icon sizes */
   1126         typedef struct {
   1127             uint32_t min_width, min_height;
   1128             uint32_t max_width, max_height;
   1129             int32_t width_inc, height_inc;
   1130         } xcb_wm_icon_size_hints_hints_t;
   1131 
   1132         xcb_wm_icon_size_hints_hints_t xis;
   1133         xis.min_width = xis.min_height = 16;
   1134         xis.max_width = xis.max_height = 48;
   1135         xis.width_inc = xis.height_inc = 16;
   1136 
   1137         xcb_change_property(pProcArg->conn, XCB_PROP_MODE_REPLACE, root_window_id,
   1138                             XCB_ATOM_WM_ICON_SIZE, XCB_ATOM_WM_ICON_SIZE, 32,
   1139                             sizeof(xis)/4, &xis);
   1140     }
   1141 
   1142     atmWmName = intern_atom(pProcArg->conn, "WM_NAME");
   1143     atmNetWmName = intern_atom(pProcArg->conn, "_NET_WM_NAME");
   1144     atmWmHints = intern_atom(pProcArg->conn, "WM_HINTS");
   1145     atmWmChange = intern_atom(pProcArg->conn, "WM_CHANGE_STATE");
   1146     atmNetWmIcon = intern_atom(pProcArg->conn, "_NET_WM_ICON");
   1147     atmWindowState = intern_atom(pProcArg->conn, "_NET_WM_STATE");
   1148     atmMotifWmHints = intern_atom(pProcArg->conn, "_MOTIF_WM_HINTS");
   1149     atmWindowType = intern_atom(pProcArg->conn, "_NET_WM_WINDOW_TYPE");
   1150     atmNormalHints = intern_atom(pProcArg->conn, "WM_NORMAL_HINTS");
   1151 
   1152     /*
   1153        iiimxcf had a bug until 2009-04-27, assuming that the
   1154        WM_STATE atom exists, causing clients to fail with
   1155        a BadAtom X error if it doesn't.
   1156 
   1157        Since this is on in the default Solaris 10 install,
   1158        workaround this by making sure it does exist...
   1159      */
   1160     intern_atom(pProcArg->conn, "WM_STATE");
   1161 
   1162     /*
   1163       Enable Composite extension and redirect subwindows of the root window
   1164      */
   1165     if (pProcArg->pWMInfo->fCompositeWM) {
   1166         const char *extension_name = "Composite";
   1167         xcb_query_extension_cookie_t cookie;
   1168         xcb_query_extension_reply_t *reply;
   1169 
   1170         cookie = xcb_query_extension(pProcArg->conn, strlen(extension_name), extension_name);
   1171         reply = xcb_query_extension_reply(pProcArg->conn, cookie, NULL);
   1172 
   1173         if (reply && (reply->present)) {
   1174             xcb_composite_redirect_subwindows(pProcArg->conn,
   1175                                               root_window_id,
   1176                                               XCB_COMPOSITE_REDIRECT_AUTOMATIC);
   1177 
   1178             /*
   1179               We use automatic updating of the root window for two
   1180               reasons:
   1181 
   1182               1) redirected window contents are mirrored to the root
   1183               window so that the root window draws correctly when shown.
   1184 
   1185               2) updating the root window causes damage against the
   1186               shadow framebuffer, which ultimately causes WM_PAINT to be
   1187               sent to the affected window(s) to cause the damage regions
   1188               to be redrawn.
   1189             */
   1190 
   1191             ErrorF("Using Composite redirection\n");
   1192 
   1193             free(reply);
   1194         }
   1195     }
   1196 
   1197     /* Loop until we explicitly break out */
   1198     while (1) {
   1199         xcb_generic_event_t *event;
   1200         uint8_t type;
   1201         Bool send_event;
   1202 
   1203         if (g_shutdown)
   1204             break;
   1205 
   1206         /* Fetch next event */
   1207         event = xcb_wait_for_event(pProcArg->conn);
   1208         if (!event) { // returns NULL on I/O error
   1209             int e = xcb_connection_has_error(pProcArg->conn);
   1210             ErrorF("winMultiWindowXMsgProc - Fatal error %d on xcb connection\n", e);
   1211             break;
   1212         }
   1213 
   1214         type = event->response_type & ~0x80;
   1215         send_event = event->response_type & 0x80;
   1216 
   1217         winDebug("winMultiWindowXMsgProc - event %d\n", type);
   1218 
   1219         /* Branch on event type */
   1220         if (type == 0) {
   1221             xcb_generic_error_t *err = (xcb_generic_error_t *)event;
   1222             ErrorF("winMultiWindowXMsgProc - Error code: %i, ID: 0x%08x, "
   1223                    "Major opcode: %i, Minor opcode: %i\n",
   1224                    err->error_code, err->resource_id,
   1225                    err->major_code, err->minor_code);
   1226             }
   1227         else if (type == XCB_CREATE_NOTIFY) {
   1228             xcb_create_notify_event_t *notify = (xcb_create_notify_event_t *)event;
   1229 
   1230             /* Request property change events */
   1231             const static uint32_t mask_value[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
   1232             xcb_change_window_attributes (pProcArg->conn, notify->window,
   1233                                           XCB_CW_EVENT_MASK, mask_value);
   1234 
   1235             /* If it's not override-redirect, set the border-width to 0 */
   1236             if (!IsOverrideRedirect(pProcArg->conn, notify->window)) {
   1237                 const static uint32_t width_value[] = { 0 };
   1238                 xcb_configure_window(pProcArg->conn, notify->window,
   1239                                      XCB_CONFIG_WINDOW_BORDER_WIDTH, width_value);
   1240             }
   1241         }
   1242         else if (type == XCB_MAP_NOTIFY) {
   1243             /* Fake a reparentNotify event as SWT/Motif expects a
   1244                Window Manager to reparent a top-level window when
   1245                it is mapped and waits until they do.
   1246 
   1247                We don't actually need to reparent, as the frame is
   1248                a native window, not an X window
   1249 
   1250                We do this on MapNotify, not MapRequest like a real
   1251                Window Manager would, so we don't have do get involved
   1252                in actually mapping the window via it's (non-existent)
   1253                parent...
   1254 
   1255                See sourceware bugzilla #9848
   1256              */
   1257 
   1258             xcb_map_notify_event_t *notify = (xcb_map_notify_event_t *)event;
   1259 
   1260             xcb_get_geometry_cookie_t cookie;
   1261             xcb_get_geometry_reply_t *reply;
   1262             xcb_query_tree_cookie_t cookie_qt;
   1263             xcb_query_tree_reply_t *reply_qt;
   1264 
   1265             cookie = xcb_get_geometry(pProcArg->conn, notify->window);
   1266             cookie_qt = xcb_query_tree(pProcArg->conn, notify->window);
   1267             reply = xcb_get_geometry_reply(pProcArg->conn, cookie, NULL);
   1268             reply_qt = xcb_query_tree_reply(pProcArg->conn, cookie_qt, NULL);
   1269 
   1270             if (reply && reply_qt) {
   1271                 /*
   1272                    It's a top-level window if the parent window is a root window
   1273                    Only non-override_redirect windows can get reparented
   1274                  */
   1275                 if ((reply->root == reply_qt->parent) && !notify->override_redirect) {
   1276                     xcb_reparent_notify_event_t event_send;
   1277 
   1278                     event_send.response_type = XCB_REPARENT_NOTIFY;
   1279                     event_send.event = notify->window;
   1280                     event_send.window = notify->window;
   1281                     event_send.parent = reply_qt->parent;
   1282                     event_send.x = reply->x;
   1283                     event_send.y = reply->y;
   1284 
   1285                     xcb_send_event (pProcArg->conn, TRUE, notify->window,
   1286                                     XCB_EVENT_MASK_STRUCTURE_NOTIFY,
   1287                                     (const char *)&event_send);
   1288 
   1289                     free(reply_qt);
   1290                     free(reply);
   1291                 }
   1292             }
   1293         }
   1294         else if (type == XCB_CONFIGURE_NOTIFY) {
   1295             if (!send_event) {
   1296                 /*
   1297                    Java applications using AWT on JRE 1.6.0 break with non-reparenting WMs AWT
   1298                    doesn't explicitly know about (See sun bug #6434227)
   1299 
   1300                    XDecoratedPeer.handleConfigureNotifyEvent() only processes non-synthetic
   1301                    ConfigureNotify events to update window location if it's identified the
   1302                    WM as a non-reparenting WM it knows about (compiz or lookingglass)
   1303 
   1304                    Rather than tell all sorts of lies to get XWM to recognize us as one of
   1305                    those, simply send a synthetic ConfigureNotify for every non-synthetic one
   1306                  */
   1307                 xcb_configure_notify_event_t *notify = (xcb_configure_notify_event_t *)event;
   1308                 xcb_configure_notify_event_t event_send = *notify;
   1309 
   1310                 event_send.event = notify->window;
   1311 
   1312                 xcb_send_event(pProcArg->conn, TRUE, notify->window,
   1313                                XCB_EVENT_MASK_STRUCTURE_NOTIFY,
   1314                                (const char *)&event_send);
   1315             }
   1316         }
   1317         else if (type ==  XCB_PROPERTY_NOTIFY) {
   1318             xcb_property_notify_event_t *notify = (xcb_property_notify_event_t *)event;
   1319 
   1320             if ((notify->atom == atmWmName) ||
   1321                 (notify->atom == atmNetWmName)) {
   1322                 memset(&msg, 0, sizeof(msg));
   1323 
   1324                 msg.msg = WM_WM_NAME_EVENT;
   1325                 msg.iWindow = notify->window;
   1326 
   1327                 /* Other fields ignored */
   1328                 winSendMessageToWM(pProcArg->pWMInfo, &msg);
   1329             }
   1330             else {
   1331                 /*
   1332                    Several properties are considered for WM hints, check if this property change affects any of them...
   1333                    (this list needs to be kept in sync with winApplyHints())
   1334                  */
   1335                 if ((notify->atom == atmWmHints) ||
   1336                     (notify->atom == atmWindowState) ||
   1337                     (notify->atom == atmMotifWmHints) ||
   1338                     (notify->atom == atmWindowType) ||
   1339                     (notify->atom == atmNormalHints)) {
   1340                     memset(&msg, 0, sizeof(msg));
   1341                     msg.msg = WM_WM_HINTS_EVENT;
   1342                     msg.iWindow = notify->window;
   1343 
   1344                     /* Other fields ignored */
   1345                     winSendMessageToWM(pProcArg->pWMInfo, &msg);
   1346                 }
   1347 
   1348                 /* Not an else as WM_HINTS affects both style and icon */
   1349                 if ((notify->atom == atmWmHints) ||
   1350                     (notify->atom == atmNetWmIcon)) {
   1351                     memset(&msg, 0, sizeof(msg));
   1352                     msg.msg = WM_WM_ICON_EVENT;
   1353                     msg.iWindow = notify->window;
   1354 
   1355                     /* Other fields ignored */
   1356                     winSendMessageToWM(pProcArg->pWMInfo, &msg);
   1357                 }
   1358             }
   1359         }
   1360         else if (type == XCB_CLIENT_MESSAGE) {
   1361             xcb_client_message_event_t *client_msg = (xcb_client_message_event_t *)event;
   1362 
   1363             if (client_msg->type == atmWmChange
   1364                  && client_msg->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) {
   1365                 ErrorF("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n");
   1366 
   1367                 memset(&msg, 0, sizeof(msg));
   1368 
   1369                 msg.msg = WM_WM_CHANGE_STATE;
   1370                 msg.iWindow = client_msg->window;
   1371 
   1372                 winSendMessageToWM(pProcArg->pWMInfo, &msg);
   1373             }
   1374         }
   1375 
   1376         /* Free the event */
   1377         free(event);
   1378     }
   1379 
   1380     xcb_disconnect(pProcArg->conn);
   1381     pthread_exit(NULL);
   1382     return NULL;
   1383 }
   1384 
   1385 /*
   1386  * winInitWM - Entry point for the X server to spawn
   1387  * the Window Manager thread.  Called from
   1388  * winscrinit.c/winFinishScreenInitFB ().
   1389  */
   1390 
   1391 Bool
   1392 winInitWM(void **ppWMInfo,
   1393           pthread_t * ptWMProc,
   1394           pthread_t * ptXMsgProc,
   1395           pthread_mutex_t * ppmServerStarted,
   1396           int dwScreen, HWND hwndScreen, Bool compositeWM)
   1397 {
   1398     WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec));
   1399     WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec));
   1400     XMsgProcArgPtr pXMsgArg = malloc(sizeof(XMsgProcArgRec));
   1401 
   1402     /* Bail if the input parameters are bad */
   1403     if (pArg == NULL || pWMInfo == NULL || pXMsgArg == NULL) {
   1404         ErrorF("winInitWM - malloc failed.\n");
   1405         free(pArg);
   1406         free(pWMInfo);
   1407         free(pXMsgArg);
   1408         return FALSE;
   1409     }
   1410 
   1411     /* Zero the allocated memory */
   1412     ZeroMemory(pArg, sizeof(WMProcArgRec));
   1413     ZeroMemory(pWMInfo, sizeof(WMInfoRec));
   1414     ZeroMemory(pXMsgArg, sizeof(XMsgProcArgRec));
   1415 
   1416     /* Set a return pointer to the Window Manager info structure */
   1417     *ppWMInfo = pWMInfo;
   1418     pWMInfo->fCompositeWM = compositeWM;
   1419 
   1420     /* Setup the argument structure for the thread function */
   1421     pArg->dwScreen = dwScreen;
   1422     pArg->pWMInfo = pWMInfo;
   1423     pArg->ppmServerStarted = ppmServerStarted;
   1424 
   1425     /* Initialize the message queue */
   1426     if (!InitQueue(&pWMInfo->wmMsgQueue)) {
   1427         ErrorF("winInitWM - InitQueue () failed.\n");
   1428         return FALSE;
   1429     }
   1430 
   1431     /* Spawn a thread for the Window Manager */
   1432     if (pthread_create(ptWMProc, NULL, winMultiWindowWMProc, pArg)) {
   1433         /* Bail if thread creation failed */
   1434         ErrorF("winInitWM - pthread_create failed for Window Manager.\n");
   1435         return FALSE;
   1436     }
   1437 
   1438     /* Spawn the XNextEvent thread, will send messages to WM */
   1439     pXMsgArg->dwScreen = dwScreen;
   1440     pXMsgArg->pWMInfo = pWMInfo;
   1441     pXMsgArg->ppmServerStarted = ppmServerStarted;
   1442     pXMsgArg->hwndScreen = hwndScreen;
   1443     if (pthread_create(ptXMsgProc, NULL, winMultiWindowXMsgProc, pXMsgArg)) {
   1444         /* Bail if thread creation failed */
   1445         ErrorF("winInitWM - pthread_create failed on XMSG.\n");
   1446         return FALSE;
   1447     }
   1448 
   1449 #if CYGDEBUG || YES
   1450     winDebug("winInitWM - Returning.\n");
   1451 #endif
   1452 
   1453     return TRUE;
   1454 }
   1455 
   1456 /*
   1457  * Window manager thread - setup
   1458  */
   1459 
   1460 static void
   1461 winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg)
   1462 {
   1463     int iRetries = 0;
   1464     char pszDisplay[512];
   1465     int iReturn;
   1466     xcb_auth_info_t *auth_info;
   1467     xcb_screen_t *root_screen;
   1468     xcb_window_t root_window_id;
   1469 
   1470     winDebug("winInitMultiWindowWM - Hello\n");
   1471 
   1472     /* Check that argument pointer is not invalid */
   1473     if (pProcArg == NULL) {
   1474         ErrorF("winInitMultiWindowWM - pProcArg is NULL.  Exiting.\n");
   1475         pthread_exit(NULL);
   1476     }
   1477 
   1478     winDebug("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n");
   1479 
   1480     /* Grab our garbage mutex to satisfy pthread_cond_wait */
   1481     iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted);
   1482     if (iReturn != 0) {
   1483         ErrorF("winInitMultiWindowWM - pthread_mutex_lock () failed: %d.  "
   1484                "Exiting.\n", iReturn);
   1485         pthread_exit(NULL);
   1486     }
   1487 
   1488     winDebug("winInitMultiWindowWM - pthread_mutex_lock () returned.\n");
   1489 
   1490     /* Release the server started mutex */
   1491     pthread_mutex_unlock(pProcArg->ppmServerStarted);
   1492 
   1493     winDebug("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n");
   1494 
   1495     /* Setup the display connection string x */
   1496     winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen);
   1497 
   1498     /* Print the display connection string */
   1499     ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay);
   1500 
   1501     /* Use our generated cookie for authentication */
   1502     auth_info = winGetXcbAuthInfo();
   1503 
   1504     /* Open the X display */
   1505     do {
   1506         /* Try to open the display */
   1507         pWMInfo->conn = xcb_connect_to_display_with_auth_info(pszDisplay,
   1508                                                               auth_info, NULL);
   1509         if (xcb_connection_has_error(pWMInfo->conn)) {
   1510             ErrorF("winInitMultiWindowWM - Could not open display, try: %d, "
   1511                    "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
   1512             ++iRetries;
   1513             sleep(WIN_CONNECT_DELAY);
   1514             continue;
   1515         }
   1516         else
   1517             break;
   1518     }
   1519     while (xcb_connection_has_error(pWMInfo->conn) && iRetries < WIN_CONNECT_RETRIES);
   1520 
   1521     /* Make sure that the display opened */
   1522     if (xcb_connection_has_error(pWMInfo->conn)) {
   1523         ErrorF("winInitMultiWindowWM - Failed opening the display.  "
   1524                "Exiting.\n");
   1525         pthread_exit(NULL);
   1526     }
   1527 
   1528     ErrorF("winInitMultiWindowWM - xcb_connect () returned and "
   1529            "successfully opened the display.\n");
   1530 
   1531     /* Create some atoms */
   1532     pWMInfo->atmWmProtos = intern_atom(pWMInfo->conn, "WM_PROTOCOLS");
   1533     pWMInfo->atmWmDelete = intern_atom(pWMInfo->conn, "WM_DELETE_WINDOW");
   1534     pWMInfo->atmWmTakeFocus = intern_atom(pWMInfo->conn, "WM_TAKE_FOCUS");
   1535     pWMInfo->atmPrivMap = intern_atom(pWMInfo->conn, WINDOWSWM_NATIVE_HWND);
   1536     pWMInfo->atmUtf8String = intern_atom(pWMInfo->conn, "UTF8_STRING");
   1537     pWMInfo->atmNetWmName = intern_atom(pWMInfo->conn, "_NET_WM_NAME");
   1538     pWMInfo->atmCurrentDesktop = intern_atom(pWMInfo->conn, "_NET_CURRENT_DESKTOP");
   1539     pWMInfo->atmNumberDesktops = intern_atom(pWMInfo->conn, "_NET_NUMBER_OF_DESKTOPS");
   1540     pWMInfo->atmDesktopNames = intern_atom(pWMInfo->conn, "__NET_DESKTOP_NAMES");
   1541 
   1542     /* Initialization for the xcb_ewmh and EWMH atoms */
   1543     {
   1544         xcb_intern_atom_cookie_t *atoms_cookie;
   1545         atoms_cookie = xcb_ewmh_init_atoms(pWMInfo->conn, &pWMInfo->ewmh);
   1546         if (xcb_ewmh_init_atoms_replies(&pWMInfo->ewmh, atoms_cookie, NULL)) {
   1547             /* Set the _NET_SUPPORTED atom for this context.
   1548 
   1549                TODO: Audit to ensure we implement everything defined as MUSTs
   1550                for window managers in the EWMH standard.*/
   1551             xcb_atom_t supported[] =
   1552                 {
   1553                     pWMInfo->ewmh.WM_PROTOCOLS,
   1554                     pWMInfo->ewmh._NET_SUPPORTED,
   1555                     pWMInfo->ewmh._NET_SUPPORTING_WM_CHECK,
   1556                     pWMInfo->ewmh._NET_CLOSE_WINDOW,
   1557                     pWMInfo->ewmh._NET_WM_WINDOW_TYPE,
   1558                     pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK,
   1559                     pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH,
   1560                     pWMInfo->ewmh._NET_WM_STATE,
   1561                     pWMInfo->ewmh._NET_WM_STATE_HIDDEN,
   1562                     pWMInfo->ewmh._NET_WM_STATE_ABOVE,
   1563                     pWMInfo->ewmh._NET_WM_STATE_BELOW,
   1564                     pWMInfo->ewmh._NET_WM_STATE_SKIP_TASKBAR,
   1565                 };
   1566 
   1567             xcb_ewmh_set_supported(&pWMInfo->ewmh, pProcArg->dwScreen,
   1568                                    ARRAY_SIZE(supported), supported);
   1569         }
   1570         else {
   1571             ErrorF("winInitMultiWindowWM - xcb_ewmh_init_atoms() failed\n");
   1572         }
   1573     }
   1574 
   1575     /* Get root window id */
   1576     root_screen = xcb_aux_get_screen(pWMInfo->conn, pProcArg->dwScreen);
   1577     root_window_id = root_screen->root;
   1578 
   1579     /*
   1580       Set root window properties for describing multiple desktops to describe
   1581       the one desktop we have
   1582     */
   1583     {
   1584         int data;
   1585         const char buf[] = "Desktop";
   1586 
   1587         data = 0;
   1588         xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id,
   1589                             pWMInfo->atmCurrentDesktop, XCB_ATOM_CARDINAL, 32,
   1590                             1, &data);
   1591         data = 1;
   1592         xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id,
   1593                             pWMInfo->atmNumberDesktops, XCB_ATOM_CARDINAL, 32,
   1594                             1, &data);
   1595 
   1596         xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id,
   1597                             pWMInfo->atmDesktopNames, pWMInfo->atmUtf8String, 8,
   1598                             strlen(buf), (unsigned char *) buf);
   1599     }
   1600 
   1601     /*
   1602       Set the root window cursor to left_ptr (this controls the cursor an
   1603       application gets over its windows when it doesn't set one)
   1604     */
   1605     {
   1606 #define XC_left_ptr 68
   1607         xcb_cursor_t cursor = xcb_generate_id(pWMInfo->conn);
   1608         xcb_font_t font = xcb_generate_id(pWMInfo->conn);
   1609         xcb_font_t *mask_font = &font; /* An alias to clarify */
   1610         int shape = XC_left_ptr;
   1611         uint32_t mask = XCB_CW_CURSOR;
   1612         uint32_t value_list = cursor;
   1613 
   1614         static const uint16_t fgred = 0, fggreen = 0, fgblue = 0;
   1615         static const uint16_t bgred = 0xFFFF, bggreen = 0xFFFF, bgblue = 0xFFFF;
   1616 
   1617         xcb_open_font(pWMInfo->conn, font, sizeof("cursor"), "cursor");
   1618 
   1619         xcb_create_glyph_cursor(pWMInfo->conn, cursor, font, *mask_font,
   1620                                 shape, shape + 1,
   1621                                 fgred, fggreen, fgblue, bgred, bggreen, bgblue);
   1622 
   1623         xcb_change_window_attributes(pWMInfo->conn, root_window_id, mask, &value_list);
   1624 
   1625         xcb_free_cursor(pWMInfo->conn, cursor);
   1626         xcb_close_font(pWMInfo->conn, font);
   1627     }
   1628 }
   1629 
   1630 /*
   1631  * winSendMessageToWM - Send a message from the X thread to the WM thread
   1632  */
   1633 
   1634 void
   1635 winSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg)
   1636 {
   1637     WMMsgNodePtr pNode;
   1638 
   1639 #if CYGMULTIWINDOW_DEBUG
   1640     ErrorF("winSendMessageToWM %s\n", MessageName(pMsg));
   1641 #endif
   1642 
   1643     pNode = malloc(sizeof(WMMsgNodeRec));
   1644     if (pNode != NULL) {
   1645         memcpy(&pNode->msg, pMsg, sizeof(winWMMessageRec));
   1646         PushMessage(&((WMInfoPtr) pWMInfo)->wmMsgQueue, pNode);
   1647     }
   1648 }
   1649 
   1650 /*
   1651  * Check if another window manager is running
   1652  */
   1653 
   1654 static Bool
   1655 CheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen)
   1656 {
   1657     Bool redirectError = FALSE;
   1658 
   1659     /* Get root window id */
   1660     xcb_screen_t *root_screen = xcb_aux_get_screen(conn, dwScreen);
   1661     xcb_window_t root_window_id = root_screen->root;
   1662 
   1663     /*
   1664        Try to select the events which only one client at a time is allowed to select.
   1665        If this causes an error, another window manager is already running...
   1666      */
   1667     const static uint32_t test_mask[] = { XCB_EVENT_MASK_RESIZE_REDIRECT |
   1668                                        XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
   1669                                        XCB_EVENT_MASK_BUTTON_PRESS };
   1670 
   1671     xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(conn,
   1672                                                                     root_window_id,
   1673                                                                     XCB_CW_EVENT_MASK,
   1674                                                                     test_mask);
   1675     xcb_generic_error_t *error;
   1676     if ((error = xcb_request_check(conn, cookie)))
   1677         {
   1678             redirectError = TRUE;
   1679             free(error);
   1680         }
   1681 
   1682     /*
   1683        Side effect: select the events we are actually interested in...
   1684 
   1685        Other WMs are not allowed, also select one of the events which only one client
   1686        at a time is allowed to select, so other window managers won't start...
   1687      */
   1688     {
   1689         const uint32_t mask[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
   1690                                   XCB_EVENT_MASK_BUTTON_PRESS };
   1691 
   1692         xcb_change_window_attributes(conn, root_window_id, XCB_CW_EVENT_MASK, mask);
   1693     }
   1694 
   1695     return redirectError;
   1696 }
   1697 
   1698 /*
   1699  * Notify the MWM thread we're exiting and not to reconnect
   1700  */
   1701 
   1702 void
   1703 winDeinitMultiWindowWM(void)
   1704 {
   1705     ErrorF("winDeinitMultiWindowWM - Noting shutdown in progress\n");
   1706     g_shutdown = TRUE;
   1707 }
   1708 
   1709 /* Windows window styles */
   1710 #define HINT_NOFRAME	(1L<<0)
   1711 #define HINT_BORDER	(1L<<1)
   1712 #define HINT_SIZEBOX	(1L<<2)
   1713 #define HINT_CAPTION	(1L<<3)
   1714 #define HINT_NOMAXIMIZE (1L<<4)
   1715 #define HINT_NOMINIMIZE (1L<<5)
   1716 #define HINT_NOSYSMENU  (1L<<6)
   1717 #define HINT_SKIPTASKBAR (1L<<7)
   1718 /* These two are used on their own */
   1719 #define HINT_MAX	(1L<<0)
   1720 #define HINT_MIN	(1L<<1)
   1721 
   1722 static void
   1723 winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle)
   1724 {
   1725 
   1726     xcb_connection_t *conn = pWMInfo->conn;
   1727     static xcb_atom_t windowState, motif_wm_hints;
   1728     static xcb_atom_t hiddenState, fullscreenState, belowState, aboveState,
   1729         skiptaskbarState;
   1730     static xcb_atom_t splashType;
   1731     static int generation;
   1732 
   1733     unsigned long hint = 0, maxmin = 0;
   1734     unsigned long style, exStyle;
   1735 
   1736     if (!hWnd)
   1737         return;
   1738     if (!IsWindow(hWnd))
   1739         return;
   1740 
   1741     if (generation != serverGeneration) {
   1742         generation = serverGeneration;
   1743         windowState = intern_atom(conn, "_NET_WM_STATE");
   1744         motif_wm_hints = intern_atom(conn, "_MOTIF_WM_HINTS");
   1745         hiddenState = intern_atom(conn, "_NET_WM_STATE_HIDDEN");
   1746         fullscreenState = intern_atom(conn, "_NET_WM_STATE_FULLSCREEN");
   1747         belowState = intern_atom(conn, "_NET_WM_STATE_BELOW");
   1748         aboveState = intern_atom(conn, "_NET_WM_STATE_ABOVE");
   1749         skiptaskbarState = intern_atom(conn, "_NET_WM_STATE_SKIP_TASKBAR");
   1750         splashType = intern_atom(conn, "_NET_WM_WINDOW_TYPE_SPLASHSCREEN");
   1751     }
   1752 
   1753     {
   1754       xcb_get_property_cookie_t cookie_wm_state = xcb_get_property(conn, FALSE, iWindow, windowState, XCB_ATOM_ATOM, 0L, INT_MAX);
   1755       xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie_wm_state, NULL);
   1756       if (reply) {
   1757         int i;
   1758         int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t);
   1759         xcb_atom_t *pAtom = xcb_get_property_value(reply);
   1760 
   1761             for (i = 0; i < nitems; i++) {
   1762                 if (pAtom[i] == skiptaskbarState)
   1763                     hint |= HINT_SKIPTASKBAR;
   1764                 if (pAtom[i] == hiddenState)
   1765                     maxmin |= HINT_MIN;
   1766                 else if (pAtom[i] == fullscreenState)
   1767                     maxmin |= HINT_MAX;
   1768                 if (pAtom[i] == belowState)
   1769                     *zstyle = HWND_BOTTOM;
   1770                 else if (pAtom[i] == aboveState)
   1771                     *zstyle = HWND_TOPMOST;
   1772             }
   1773 
   1774             free(reply);
   1775       }
   1776     }
   1777 
   1778     {
   1779       xcb_get_property_cookie_t cookie_mwm_hint = xcb_get_property(conn, FALSE, iWindow, motif_wm_hints, motif_wm_hints, 0L, sizeof(MwmHints));
   1780       xcb_get_property_reply_t *reply =  xcb_get_property_reply(conn, cookie_mwm_hint, NULL);
   1781       if (reply) {
   1782         int nitems = xcb_get_property_value_length(reply)/4;
   1783         MwmHints *mwm_hint = xcb_get_property_value(reply);
   1784         if (mwm_hint && (nitems >= PropMwmHintsElements) &&
   1785             (mwm_hint->flags & MwmHintsDecorations)) {
   1786             if (!mwm_hint->decorations)
   1787                 hint |= (HINT_NOFRAME | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE);
   1788             else if (!(mwm_hint->decorations & MwmDecorAll)) {
   1789                 if (mwm_hint->decorations & MwmDecorBorder)
   1790                     hint |= HINT_BORDER;
   1791                 if (mwm_hint->decorations & MwmDecorHandle)
   1792                     hint |= HINT_SIZEBOX;
   1793                 if (mwm_hint->decorations & MwmDecorTitle)
   1794                     hint |= HINT_CAPTION;
   1795                 if (!(mwm_hint->decorations & MwmDecorMenu))
   1796                     hint |= HINT_NOSYSMENU;
   1797                 if (!(mwm_hint->decorations & MwmDecorMinimize))
   1798                     hint |= HINT_NOMINIMIZE;
   1799                 if (!(mwm_hint->decorations & MwmDecorMaximize))
   1800                     hint |= HINT_NOMAXIMIZE;
   1801             }
   1802             else {
   1803                 /*
   1804                    MwmDecorAll means all decorations *except* those specified by other flag
   1805                    bits that are set.  Not yet implemented.
   1806                  */
   1807             }
   1808         }
   1809         free(reply);
   1810       }
   1811     }
   1812 
   1813     {
   1814       int i;
   1815       xcb_ewmh_get_atoms_reply_t type;
   1816       xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_window_type(&pWMInfo->ewmh, iWindow);
   1817       if (xcb_ewmh_get_wm_window_type_reply(&pWMInfo->ewmh, cookie, &type, NULL)) {
   1818         for (i = 0; i < type.atoms_len; i++) {
   1819             if (type.atoms[i] ==  pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK) {
   1820                 hint = (hint & ~HINT_NOFRAME) | HINT_SKIPTASKBAR | HINT_SIZEBOX;
   1821                 *zstyle = HWND_TOPMOST;
   1822             }
   1823             else if ((type.atoms[i] == pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH)
   1824                      || (type.atoms[i] == splashType)) {
   1825                 hint |= (HINT_SKIPTASKBAR | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE);
   1826                 *zstyle = HWND_TOPMOST;
   1827             }
   1828         }
   1829       }
   1830     }
   1831 
   1832     {
   1833         xcb_size_hints_t size_hints;
   1834         xcb_get_property_cookie_t cookie;
   1835 
   1836         cookie = xcb_icccm_get_wm_normal_hints(conn, iWindow);
   1837         if (xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &size_hints, NULL)) {
   1838             if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) {
   1839 
   1840                 /* Not maximizable if a maximum size is specified, and that size
   1841                    is smaller (in either dimension) than the screen size */
   1842                 if ((size_hints.max_width < GetSystemMetrics(SM_CXVIRTUALSCREEN))
   1843                     || (size_hints.max_height < GetSystemMetrics(SM_CYVIRTUALSCREEN)))
   1844                     hint |= HINT_NOMAXIMIZE;
   1845 
   1846                 if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) {
   1847                     /*
   1848                        If both minimum size and maximum size are specified and are the same,
   1849                        don't bother with a resizing frame
   1850                      */
   1851                     if ((size_hints.min_width == size_hints.max_width)
   1852                         && (size_hints.min_height == size_hints.max_height))
   1853                         hint = (hint & ~HINT_SIZEBOX);
   1854                 }
   1855             }
   1856         }
   1857     }
   1858 
   1859     /*
   1860        Override hint settings from above with settings from config file and set
   1861        application id for grouping.
   1862      */
   1863     {
   1864         char *application_id = 0;
   1865         char *window_name = 0;
   1866         char *res_name = 0;
   1867         char *res_class = 0;
   1868 
   1869         GetClassNames(pWMInfo, iWindow, &res_name, &res_class, &window_name);
   1870 
   1871         style = STYLE_NONE;
   1872         style = winOverrideStyle(res_name, res_class, window_name);
   1873 
   1874 #define APPLICATION_ID_FORMAT	"%s.xwin.%s"
   1875 #define APPLICATION_ID_UNKNOWN "unknown"
   1876         if (res_class) {
   1877             asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
   1878                      res_class);
   1879         }
   1880         else {
   1881             asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME,
   1882                      APPLICATION_ID_UNKNOWN);
   1883         }
   1884         winSetAppUserModelID(hWnd, application_id);
   1885 
   1886         free(application_id);
   1887         free(res_name);
   1888         free(res_class);
   1889         free(window_name);
   1890     }
   1891 
   1892     if (style & STYLE_TOPMOST)
   1893         *zstyle = HWND_TOPMOST;
   1894     else if (style & STYLE_MAXIMIZE)
   1895         maxmin = (hint & ~HINT_MIN) | HINT_MAX;
   1896     else if (style & STYLE_MINIMIZE)
   1897         maxmin = (hint & ~HINT_MAX) | HINT_MIN;
   1898     else if (style & STYLE_BOTTOM)
   1899         *zstyle = HWND_BOTTOM;
   1900 
   1901     if (maxmin & HINT_MAX)
   1902         SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
   1903     else if (maxmin & HINT_MIN)
   1904         SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
   1905 
   1906     if (style & STYLE_NOTITLE)
   1907         hint =
   1908             (hint & ~HINT_NOFRAME & ~HINT_BORDER & ~HINT_CAPTION) |
   1909             HINT_SIZEBOX;
   1910     else if (style & STYLE_OUTLINE)
   1911         hint =
   1912             (hint & ~HINT_NOFRAME & ~HINT_SIZEBOX & ~HINT_CAPTION) |
   1913             HINT_BORDER;
   1914     else if (style & STYLE_NOFRAME)
   1915         hint =
   1916             (hint & ~HINT_BORDER & ~HINT_CAPTION & ~HINT_SIZEBOX) |
   1917             HINT_NOFRAME;
   1918 
   1919     /* Now apply styles to window */
   1920     style = GetWindowLongPtr(hWnd, GWL_STYLE);
   1921     if (!style)
   1922         return;                 /* GetWindowLongPointer returns 0 on failure, we hope this isn't a valid style */
   1923 
   1924     style &= ~WS_CAPTION & ~WS_SIZEBOX; /* Just in case */
   1925 
   1926     if (!(hint & ~HINT_SKIPTASKBAR))    /* No hints, default */
   1927         style = style | WS_CAPTION | WS_SIZEBOX;
   1928     else if (hint & HINT_NOFRAME)       /* No frame, no decorations */
   1929         style = style & ~WS_CAPTION & ~WS_SIZEBOX;
   1930     else
   1931         style = style | ((hint & HINT_BORDER) ? WS_BORDER : 0) |
   1932             ((hint & HINT_SIZEBOX) ? WS_SIZEBOX : 0) |
   1933             ((hint & HINT_CAPTION) ? WS_CAPTION : 0);
   1934 
   1935     if (hint & HINT_NOMAXIMIZE)
   1936         style = style & ~WS_MAXIMIZEBOX;
   1937 
   1938     if (hint & HINT_NOMINIMIZE)
   1939         style = style & ~WS_MINIMIZEBOX;
   1940 
   1941     if (hint & HINT_NOSYSMENU)
   1942         style = style & ~WS_SYSMENU;
   1943 
   1944     if (hint & HINT_SKIPTASKBAR)
   1945         style = style & ~WS_MINIMIZEBOX;        /* window will become lost if minimized */
   1946 
   1947     SetWindowLongPtr(hWnd, GWL_STYLE, style);
   1948 
   1949     exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
   1950     if (hint & HINT_SKIPTASKBAR)
   1951         exStyle = (exStyle & ~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW;
   1952     else
   1953         exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW;
   1954     SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle);
   1955 
   1956     winDebug
   1957         ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n",
   1958          iWindow, hint, style, exStyle);
   1959 }
   1960 
   1961 void
   1962 winUpdateWindowPosition(HWND hWnd, HWND * zstyle)
   1963 {
   1964     int iX, iY, iWidth, iHeight;
   1965     int iDx, iDy;
   1966     RECT rcNew;
   1967     WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP);
   1968     DrawablePtr pDraw = NULL;
   1969 
   1970     if (!pWin)
   1971         return;
   1972     pDraw = &pWin->drawable;
   1973     if (!pDraw)
   1974         return;
   1975 
   1976     /* Get the X and Y location of the X window */
   1977     iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN);
   1978     iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN);
   1979 
   1980     /* Get the height and width of the X window */
   1981     iWidth = pWin->drawable.width;
   1982     iHeight = pWin->drawable.height;
   1983 
   1984     /* Setup a rectangle with the X window position and size */
   1985     SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight);
   1986 
   1987     winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n",
   1988              rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
   1989 
   1990     AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE,
   1991                        GetWindowLongPtr(hWnd, GWL_EXSTYLE));
   1992 
   1993     /* Don't allow window decoration to disappear off to top-left as a result of this adjustment */
   1994     if (rcNew.left < GetSystemMetrics(SM_XVIRTUALSCREEN)) {
   1995         iDx = GetSystemMetrics(SM_XVIRTUALSCREEN) - rcNew.left;
   1996         rcNew.left += iDx;
   1997         rcNew.right += iDx;
   1998     }
   1999 
   2000     if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) {
   2001         iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top;
   2002         rcNew.top += iDy;
   2003         rcNew.bottom += iDy;
   2004     }
   2005 
   2006     winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n",
   2007              rcNew.left, rcNew.top, rcNew.right, rcNew.bottom);
   2008 
   2009     /* Position the Windows window */
   2010     SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top,
   2011                  rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0);
   2012 
   2013 }