winmultiwindowwm.c revision 1b5d61b8
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> 521b5d61b8Smrg 536747b715Smrg#include <X11/Xwindows.h> 5405b261ecSmrg 5505b261ecSmrg/* Local headers */ 561b5d61b8Smrg#include "X11/Xdefs.h" // for Bool type 5705b261ecSmrg#include "winwindow.h" 586747b715Smrg#include "winprefs.h" 596747b715Smrg#include "window.h" 606747b715Smrg#include "pixmapstr.h" 616747b715Smrg#include "windowstr.h" 6235c4bbdfSmrg#include "winglobals.h" 6335c4bbdfSmrg#include "windisplay.h" 641b5d61b8Smrg#include "winmultiwindowicons.h" 656747b715Smrg 666747b715Smrg/* We need the native HWND atom for intWM, so for consistency use the 671b5d61b8Smrg same name as extWM does */ 686747b715Smrg#define WINDOWSWM_NATIVE_HWND "_WINDOWSWM_NATIVE_HWND" 6905b261ecSmrg 7035c4bbdfSmrg#ifndef HOST_NAME_MAX 7135c4bbdfSmrg#define HOST_NAME_MAX 255 7235c4bbdfSmrg#endif 7335c4bbdfSmrg 7405b261ecSmrgextern void winDebug(const char *format, ...); 756747b715Smrgextern void winReshapeMultiWindow(WindowPtr pWin); 766747b715Smrgextern void winUpdateRgnMultiWindow(WindowPtr pWin); 771b5d61b8Smrgextern xcb_auth_info_t *winGetXcbAuthInfo(void); 7805b261ecSmrg 7905b261ecSmrg#ifndef CYGDEBUG 8005b261ecSmrg#define CYGDEBUG NO 8105b261ecSmrg#endif 8205b261ecSmrg 8305b261ecSmrg/* 8405b261ecSmrg * Constant defines 8505b261ecSmrg */ 8605b261ecSmrg 8705b261ecSmrg#define WIN_CONNECT_RETRIES 5 8805b261ecSmrg#define WIN_CONNECT_DELAY 5 8905b261ecSmrg#ifdef HAS_DEVWINDOWS 9035c4bbdfSmrg#define WIN_MSG_QUEUE_FNAME "/dev/windows" 9105b261ecSmrg#endif 9205b261ecSmrg 9305b261ecSmrg/* 9405b261ecSmrg * Local structures 9505b261ecSmrg */ 9605b261ecSmrg 9705b261ecSmrgtypedef struct _WMMsgNodeRec { 9835c4bbdfSmrg winWMMessageRec msg; 9935c4bbdfSmrg struct _WMMsgNodeRec *pNext; 10005b261ecSmrg} WMMsgNodeRec, *WMMsgNodePtr; 10105b261ecSmrg 10205b261ecSmrgtypedef struct _WMMsgQueueRec { 10335c4bbdfSmrg struct _WMMsgNodeRec *pHead; 10435c4bbdfSmrg struct _WMMsgNodeRec *pTail; 10535c4bbdfSmrg pthread_mutex_t pmMutex; 10635c4bbdfSmrg pthread_cond_t pcNotEmpty; 10705b261ecSmrg} WMMsgQueueRec, *WMMsgQueuePtr; 10805b261ecSmrg 10905b261ecSmrgtypedef struct _WMInfo { 1101b5d61b8Smrg xcb_connection_t *conn; 11135c4bbdfSmrg WMMsgQueueRec wmMsgQueue; 1121b5d61b8Smrg xcb_atom_t atmWmProtos; 1131b5d61b8Smrg xcb_atom_t atmWmDelete; 1141b5d61b8Smrg xcb_atom_t atmWmTakeFocus; 1151b5d61b8Smrg xcb_atom_t atmPrivMap; 1161b5d61b8Smrg xcb_atom_t atmUtf8String; 1171b5d61b8Smrg xcb_atom_t atmNetWmName; 1181b5d61b8Smrg xcb_ewmh_connection_t ewmh; 11905b261ecSmrg} WMInfoRec, *WMInfoPtr; 12005b261ecSmrg 12105b261ecSmrgtypedef struct _WMProcArgRec { 12235c4bbdfSmrg DWORD dwScreen; 12335c4bbdfSmrg WMInfoPtr pWMInfo; 12435c4bbdfSmrg pthread_mutex_t *ppmServerStarted; 12505b261ecSmrg} WMProcArgRec, *WMProcArgPtr; 12605b261ecSmrg 12705b261ecSmrgtypedef struct _XMsgProcArgRec { 1281b5d61b8Smrg xcb_connection_t *conn; 12935c4bbdfSmrg DWORD dwScreen; 13035c4bbdfSmrg WMInfoPtr pWMInfo; 13135c4bbdfSmrg pthread_mutex_t *ppmServerStarted; 13235c4bbdfSmrg HWND hwndScreen; 13305b261ecSmrg} XMsgProcArgRec, *XMsgProcArgPtr; 13405b261ecSmrg 13505b261ecSmrg/* 13605b261ecSmrg * Prototypes for local functions 13705b261ecSmrg */ 13805b261ecSmrg 13905b261ecSmrgstatic void 14035c4bbdfSmrg PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode); 14105b261ecSmrg 14235c4bbdfSmrgstatic WMMsgNodePtr PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo); 14305b261ecSmrg 14405b261ecSmrgstatic Bool 14535c4bbdfSmrg InitQueue(WMMsgQueuePtr pQueue); 14605b261ecSmrg 14705b261ecSmrgstatic void 1481b5d61b8Smrg GetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName); 14905b261ecSmrg 1501b5d61b8Smrgstatic void 1511b5d61b8Smrg SendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData); 15205b261ecSmrg 15305b261ecSmrgstatic void 1541b5d61b8Smrg UpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow); 15505b261ecSmrg 15635c4bbdfSmrgstatic void *winMultiWindowWMProc(void *pArg); 15705b261ecSmrg 15835c4bbdfSmrgstatic void *winMultiWindowXMsgProc(void *pArg); 15905b261ecSmrg 16005b261ecSmrgstatic void 16135c4bbdfSmrg winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg); 16205b261ecSmrg 16305b261ecSmrg#if 0 16405b261ecSmrgstatic void 1651b5d61b8Smrg PreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction); 16605b261ecSmrg#endif 16705b261ecSmrg 16805b261ecSmrgstatic Bool 1691b5d61b8SmrgCheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen); 17005b261ecSmrg 1716747b715Smrgstatic void 1721b5d61b8Smrg winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle); 1736747b715Smrg 1746747b715Smrgvoid 17535c4bbdfSmrg winUpdateWindowPosition(HWND hWnd, HWND * zstyle); 17605b261ecSmrg 17705b261ecSmrg/* 17805b261ecSmrg * Local globals 17905b261ecSmrg */ 18005b261ecSmrg 18135c4bbdfSmrgstatic Bool g_shutdown = FALSE; 1821b5d61b8Smrg 1831b5d61b8Smrg/* 1841b5d61b8Smrg * Translate msg id to text, for debug purposes 1851b5d61b8Smrg */ 1861b5d61b8Smrg 1871b5d61b8Smrg#if CYGMULTIWINDOW_DEBUG 1881b5d61b8Smrgstatic const char * 1891b5d61b8SmrgMessageName(winWMMessagePtr msg) 1901b5d61b8Smrg{ 1911b5d61b8Smrg switch (msg->msg) 1921b5d61b8Smrg { 1931b5d61b8Smrg case WM_WM_MOVE: 1941b5d61b8Smrg return "WM_WM_MOVE"; 1951b5d61b8Smrg break; 1961b5d61b8Smrg case WM_WM_SIZE: 1971b5d61b8Smrg return "WM_WM_SIZE"; 1981b5d61b8Smrg break; 1991b5d61b8Smrg case WM_WM_RAISE: 2001b5d61b8Smrg return "WM_WM_RAISE"; 2011b5d61b8Smrg break; 2021b5d61b8Smrg case WM_WM_LOWER: 2031b5d61b8Smrg return "WM_WM_LOWER"; 2041b5d61b8Smrg break; 2051b5d61b8Smrg case WM_WM_UNMAP: 2061b5d61b8Smrg return "WM_WM_UNMAP"; 2071b5d61b8Smrg break; 2081b5d61b8Smrg case WM_WM_KILL: 2091b5d61b8Smrg return "WM_WM_KILL"; 2101b5d61b8Smrg break; 2111b5d61b8Smrg case WM_WM_ACTIVATE: 2121b5d61b8Smrg return "WM_WM_ACTIVATE"; 2131b5d61b8Smrg break; 2141b5d61b8Smrg case WM_WM_NAME_EVENT: 2151b5d61b8Smrg return "WM_WM_NAME_EVENT"; 2161b5d61b8Smrg break; 2171b5d61b8Smrg case WM_WM_ICON_EVENT: 2181b5d61b8Smrg return "WM_WM_ICON_EVENT"; 2191b5d61b8Smrg break; 2201b5d61b8Smrg case WM_WM_CHANGE_STATE: 2211b5d61b8Smrg return "WM_WM_CHANGE_STATE"; 2221b5d61b8Smrg break; 2231b5d61b8Smrg case WM_WM_MAP2: 2241b5d61b8Smrg return "WM_WM_MAP2"; 2251b5d61b8Smrg break; 2261b5d61b8Smrg case WM_WM_MAP3: 2271b5d61b8Smrg return "WM_WM_MAP3"; 2281b5d61b8Smrg break; 2291b5d61b8Smrg case WM_WM_HINTS_EVENT: 2301b5d61b8Smrg return "WM_WM_HINTS_EVENT"; 2311b5d61b8Smrg break; 2321b5d61b8Smrg default: 2331b5d61b8Smrg return "Unknown Message"; 2341b5d61b8Smrg break; 2351b5d61b8Smrg } 2361b5d61b8Smrg} 2371b5d61b8Smrg#endif 2381b5d61b8Smrg 23905b261ecSmrg 24005b261ecSmrg/* 24105b261ecSmrg * PushMessage - Push a message onto the queue 24205b261ecSmrg */ 24305b261ecSmrg 24405b261ecSmrgstatic void 24535c4bbdfSmrgPushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode) 24605b261ecSmrg{ 24705b261ecSmrg 24835c4bbdfSmrg /* Lock the queue mutex */ 24935c4bbdfSmrg pthread_mutex_lock(&pQueue->pmMutex); 25005b261ecSmrg 25135c4bbdfSmrg pNode->pNext = NULL; 25235c4bbdfSmrg 25335c4bbdfSmrg if (pQueue->pTail != NULL) { 25435c4bbdfSmrg pQueue->pTail->pNext = pNode; 25505b261ecSmrg } 25635c4bbdfSmrg pQueue->pTail = pNode; 25705b261ecSmrg 25835c4bbdfSmrg if (pQueue->pHead == NULL) { 25935c4bbdfSmrg pQueue->pHead = pNode; 26035c4bbdfSmrg } 26105b261ecSmrg 26235c4bbdfSmrg /* Release the queue mutex */ 26335c4bbdfSmrg pthread_mutex_unlock(&pQueue->pmMutex); 26405b261ecSmrg 26535c4bbdfSmrg /* Signal that the queue is not empty */ 26635c4bbdfSmrg pthread_cond_signal(&pQueue->pcNotEmpty); 26705b261ecSmrg} 26805b261ecSmrg 26905b261ecSmrg/* 27005b261ecSmrg * PopMessage - Pop a message from the queue 27105b261ecSmrg */ 27205b261ecSmrg 27305b261ecSmrgstatic WMMsgNodePtr 27435c4bbdfSmrgPopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo) 27505b261ecSmrg{ 27635c4bbdfSmrg WMMsgNodePtr pNode; 27705b261ecSmrg 27835c4bbdfSmrg /* Lock the queue mutex */ 27935c4bbdfSmrg pthread_mutex_lock(&pQueue->pmMutex); 28005b261ecSmrg 28135c4bbdfSmrg /* Wait for --- */ 28235c4bbdfSmrg while (pQueue->pHead == NULL) { 28335c4bbdfSmrg pthread_cond_wait(&pQueue->pcNotEmpty, &pQueue->pmMutex); 28405b261ecSmrg } 28535c4bbdfSmrg 28635c4bbdfSmrg pNode = pQueue->pHead; 28735c4bbdfSmrg if (pQueue->pHead != NULL) { 28835c4bbdfSmrg pQueue->pHead = pQueue->pHead->pNext; 28905b261ecSmrg } 29005b261ecSmrg 29135c4bbdfSmrg if (pQueue->pTail == pNode) { 29235c4bbdfSmrg pQueue->pTail = NULL; 29305b261ecSmrg } 29405b261ecSmrg 29535c4bbdfSmrg /* Release the queue mutex */ 29635c4bbdfSmrg pthread_mutex_unlock(&pQueue->pmMutex); 29705b261ecSmrg 29835c4bbdfSmrg return pNode; 29935c4bbdfSmrg} 30005b261ecSmrg 30105b261ecSmrg#if 0 30205b261ecSmrg/* 30335c4bbdfSmrg * HaveMessage - 30405b261ecSmrg */ 30505b261ecSmrg 30605b261ecSmrgstatic Bool 3071b5d61b8SmrgHaveMessage(WMMsgQueuePtr pQueue, UINT msg, xcb_window_t iWindow) 30805b261ecSmrg{ 30935c4bbdfSmrg WMMsgNodePtr pNode; 31035c4bbdfSmrg 31135c4bbdfSmrg for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) { 31235c4bbdfSmrg if (pNode->msg.msg == msg && pNode->msg.iWindow == iWindow) 31335c4bbdfSmrg return True; 31405b261ecSmrg } 31535c4bbdfSmrg 31635c4bbdfSmrg return False; 31705b261ecSmrg} 31805b261ecSmrg#endif 31905b261ecSmrg 32005b261ecSmrg/* 32105b261ecSmrg * InitQueue - Initialize the Window Manager message queue 32205b261ecSmrg */ 32305b261ecSmrg 32405b261ecSmrgstatic 32535c4bbdfSmrg Bool 32635c4bbdfSmrgInitQueue(WMMsgQueuePtr pQueue) 32705b261ecSmrg{ 32835c4bbdfSmrg /* Check if the pQueue pointer is NULL */ 32935c4bbdfSmrg if (pQueue == NULL) { 33035c4bbdfSmrg ErrorF("InitQueue - pQueue is NULL. Exiting.\n"); 33135c4bbdfSmrg return FALSE; 33205b261ecSmrg } 33305b261ecSmrg 33435c4bbdfSmrg /* Set the head and tail to NULL */ 33535c4bbdfSmrg pQueue->pHead = NULL; 33635c4bbdfSmrg pQueue->pTail = NULL; 33705b261ecSmrg 33835c4bbdfSmrg winDebug("InitQueue - Calling pthread_mutex_init\n"); 33905b261ecSmrg 34035c4bbdfSmrg /* Create synchronization objects */ 34135c4bbdfSmrg pthread_mutex_init(&pQueue->pmMutex, NULL); 34205b261ecSmrg 34335c4bbdfSmrg winDebug("InitQueue - pthread_mutex_init returned\n"); 34435c4bbdfSmrg winDebug("InitQueue - Calling pthread_cond_init\n"); 34505b261ecSmrg 34635c4bbdfSmrg pthread_cond_init(&pQueue->pcNotEmpty, NULL); 34705b261ecSmrg 34835c4bbdfSmrg winDebug("InitQueue - pthread_cond_init returned\n"); 34905b261ecSmrg 35035c4bbdfSmrg return TRUE; 35105b261ecSmrg} 35205b261ecSmrg 35335c4bbdfSmrgstatic 35435c4bbdfSmrgchar * 3551b5d61b8SmrgXutf8TextPropertyToString(WMInfoPtr pWMInfo, xcb_icccm_get_text_property_reply_t *xtp) 35635c4bbdfSmrg{ 35735c4bbdfSmrg char *pszReturnData; 35835c4bbdfSmrg 3591b5d61b8Smrg if ((xtp->encoding == XCB_ATOM_STRING) || // Latin1 ISO 8859-1 3601b5d61b8Smrg (xtp->encoding == pWMInfo->atmUtf8String)) { // UTF-8 ISO 10646 3611b5d61b8Smrg pszReturnData = strndup(xtp->name, xtp->name_len); 36235c4bbdfSmrg } 36335c4bbdfSmrg else { 3641b5d61b8Smrg // Converting from COMPOUND_TEXT to UTF-8 properly is complex to 3651b5d61b8Smrg // implement, and not very much use unless you have an old 3661b5d61b8Smrg // application which isn't UTF-8 aware. 3671b5d61b8Smrg ErrorF("Xutf8TextPropertyToString: text encoding %d is not implemented\n", xtp->encoding); 3681b5d61b8Smrg pszReturnData = strdup(""); 36935c4bbdfSmrg } 37035c4bbdfSmrg 37135c4bbdfSmrg return pszReturnData; 37235c4bbdfSmrg} 37305b261ecSmrg 37405b261ecSmrg/* 37505b261ecSmrg * GetWindowName - Retrieve the title of an X Window 37605b261ecSmrg */ 37705b261ecSmrg 37805b261ecSmrgstatic void 3791b5d61b8SmrgGetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName) 38005b261ecSmrg{ 3811b5d61b8Smrg xcb_connection_t *conn = pWMInfo->conn; 3821b5d61b8Smrg char *pszWindowName = NULL; 38335c4bbdfSmrg 38405b261ecSmrg#if CYGMULTIWINDOW_DEBUG 38535c4bbdfSmrg ErrorF("GetWindowName\n"); 38605b261ecSmrg#endif 38705b261ecSmrg 3881b5d61b8Smrg /* Try to get window name from _NET_WM_NAME */ 3891b5d61b8Smrg { 3901b5d61b8Smrg xcb_get_property_cookie_t cookie; 3911b5d61b8Smrg xcb_get_property_reply_t *reply; 3921b5d61b8Smrg 3931b5d61b8Smrg cookie = xcb_get_property(pWMInfo->conn, FALSE, iWin, 3941b5d61b8Smrg pWMInfo->atmNetWmName, 3951b5d61b8Smrg XCB_GET_PROPERTY_TYPE_ANY, 0, INT_MAX); 3961b5d61b8Smrg reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL); 3971b5d61b8Smrg if (reply && (reply->type != XCB_NONE)) { 3981b5d61b8Smrg pszWindowName = strndup(xcb_get_property_value(reply), 3991b5d61b8Smrg xcb_get_property_value_length(reply)); 4001b5d61b8Smrg free(reply); 4011b5d61b8Smrg } 40205b261ecSmrg } 40305b261ecSmrg 4041b5d61b8Smrg /* Otherwise, try to get window name from WM_NAME */ 4051b5d61b8Smrg if (!pszWindowName) 4061b5d61b8Smrg { 4071b5d61b8Smrg xcb_get_property_cookie_t cookie; 4081b5d61b8Smrg xcb_icccm_get_text_property_reply_t reply; 4091b5d61b8Smrg 4101b5d61b8Smrg cookie = xcb_icccm_get_wm_name(conn, iWin); 4111b5d61b8Smrg if (!xcb_icccm_get_wm_name_reply(conn, cookie, &reply, NULL)) { 4121b5d61b8Smrg ErrorF("GetWindowName - xcb_icccm_get_wm_name_reply failed. No name.\n"); 4131b5d61b8Smrg *ppWindowName = NULL; 4141b5d61b8Smrg return; 4151b5d61b8Smrg } 4161b5d61b8Smrg 4171b5d61b8Smrg pszWindowName = Xutf8TextPropertyToString(pWMInfo, &reply); 4181b5d61b8Smrg xcb_icccm_get_text_property_reply_wipe(&reply); 4191b5d61b8Smrg } 4201b5d61b8Smrg 4211b5d61b8Smrg /* return the window name, unless... */ 4221b5d61b8Smrg *ppWindowName = pszWindowName; 42335c4bbdfSmrg 42435c4bbdfSmrg if (g_fHostInTitle) { 4251b5d61b8Smrg xcb_get_property_cookie_t cookie; 4261b5d61b8Smrg xcb_icccm_get_text_property_reply_t reply; 4271b5d61b8Smrg 42835c4bbdfSmrg /* Try to get client machine name */ 4291b5d61b8Smrg cookie = xcb_icccm_get_wm_client_machine(conn, iWin); 4301b5d61b8Smrg if (xcb_icccm_get_wm_client_machine_reply(conn, cookie, &reply, NULL)) { 4311b5d61b8Smrg char *pszClientMachine; 4321b5d61b8Smrg char *pszClientHostname; 4331b5d61b8Smrg char *dot; 4341b5d61b8Smrg char hostname[HOST_NAME_MAX + 1]; 4351b5d61b8Smrg 4361b5d61b8Smrg pszClientMachine = Xutf8TextPropertyToString(pWMInfo, &reply); 4371b5d61b8Smrg xcb_icccm_get_text_property_reply_wipe(&reply); 4381b5d61b8Smrg 4391b5d61b8Smrg /* If client machine name looks like a FQDN, find the hostname */ 4401b5d61b8Smrg pszClientHostname = strdup(pszClientMachine); 4411b5d61b8Smrg dot = strchr(pszClientHostname, '.'); 4421b5d61b8Smrg if (dot) 4431b5d61b8Smrg *dot = '\0'; 44435c4bbdfSmrg 44535c4bbdfSmrg /* 4461b5d61b8Smrg If we have a client machine hostname 4471b5d61b8Smrg and it's not the local hostname 44835c4bbdfSmrg and it's not already in the window title... 44935c4bbdfSmrg */ 4501b5d61b8Smrg if (strlen(pszClientHostname) && 45135c4bbdfSmrg !gethostname(hostname, HOST_NAME_MAX + 1) && 4521b5d61b8Smrg strcmp(hostname, pszClientHostname) && 4531b5d61b8Smrg (strstr(pszWindowName, pszClientHostname) == 0)) { 45435c4bbdfSmrg /* ... add '@<clientmachine>' to end of window name */ 45535c4bbdfSmrg *ppWindowName = 45635c4bbdfSmrg malloc(strlen(pszWindowName) + 45735c4bbdfSmrg strlen(pszClientMachine) + 2); 45835c4bbdfSmrg strcpy(*ppWindowName, pszWindowName); 45935c4bbdfSmrg strcat(*ppWindowName, "@"); 46035c4bbdfSmrg strcat(*ppWindowName, pszClientMachine); 46135c4bbdfSmrg 46235c4bbdfSmrg free(pszWindowName); 46335c4bbdfSmrg } 4641b5d61b8Smrg 4651b5d61b8Smrg free(pszClientMachine); 4661b5d61b8Smrg free(pszClientHostname); 46735c4bbdfSmrg } 46835c4bbdfSmrg } 46905b261ecSmrg} 47005b261ecSmrg 47135c4bbdfSmrg/* 47235c4bbdfSmrg * Does the client support the specified WM_PROTOCOLS protocol? 47335c4bbdfSmrg */ 47435c4bbdfSmrg 47535c4bbdfSmrgstatic Bool 4761b5d61b8SmrgIsWmProtocolAvailable(WMInfoPtr pWMInfo, xcb_window_t iWindow, xcb_atom_t atmProtocol) 47735c4bbdfSmrg{ 4781b5d61b8Smrg int i, found = 0; 4791b5d61b8Smrg xcb_get_property_cookie_t cookie; 4801b5d61b8Smrg xcb_icccm_get_wm_protocols_reply_t reply; 4811b5d61b8Smrg xcb_connection_t *conn = pWMInfo->conn; 4821b5d61b8Smrg 4831b5d61b8Smrg cookie = xcb_icccm_get_wm_protocols(conn, iWindow, pWMInfo->ewmh.WM_PROTOCOLS); 4841b5d61b8Smrg if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &reply, NULL)) { 4851b5d61b8Smrg for (i = 0; i < reply.atoms_len; ++i) 4861b5d61b8Smrg if (reply.atoms[i] == atmProtocol) { 4871b5d61b8Smrg ++found; 4881b5d61b8Smrg break; 4891b5d61b8Smrg } 4901b5d61b8Smrg xcb_icccm_get_wm_protocols_reply_wipe(&reply); 49135c4bbdfSmrg } 49235c4bbdfSmrg 49335c4bbdfSmrg return found > 0; 49435c4bbdfSmrg} 49505b261ecSmrg 49605b261ecSmrg/* 49705b261ecSmrg * Send a message to the X server from the WM thread 49805b261ecSmrg */ 49905b261ecSmrg 5001b5d61b8Smrgstatic void 5011b5d61b8SmrgSendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData) 50205b261ecSmrg{ 5031b5d61b8Smrg xcb_client_message_event_t e; 50435c4bbdfSmrg 50535c4bbdfSmrg /* Prepare the X event structure */ 5061b5d61b8Smrg memset(&e, 0, sizeof(e)); 5071b5d61b8Smrg e.response_type = XCB_CLIENT_MESSAGE; 5081b5d61b8Smrg e.window = iWin; 5091b5d61b8Smrg e.type = atmType; 5101b5d61b8Smrg e.format = 32; 5111b5d61b8Smrg e.data.data32[0] = nData; 5121b5d61b8Smrg e.data.data32[1] = XCB_CURRENT_TIME; 51335c4bbdfSmrg 51435c4bbdfSmrg /* Send the event to X */ 5151b5d61b8Smrg xcb_send_event(conn, FALSE, iWin, XCB_EVENT_MASK_NO_EVENT, (const char *)&e); 51605b261ecSmrg} 51705b261ecSmrg 51835c4bbdfSmrg/* 51935c4bbdfSmrg * See if we can get the stored HWND for this window... 52035c4bbdfSmrg */ 52135c4bbdfSmrgstatic HWND 5221b5d61b8SmrggetHwnd(WMInfoPtr pWMInfo, xcb_window_t iWindow) 52335c4bbdfSmrg{ 5241b5d61b8Smrg HWND hWnd = NULL; 5251b5d61b8Smrg xcb_get_property_cookie_t cookie; 5261b5d61b8Smrg xcb_get_property_reply_t *reply; 5271b5d61b8Smrg 5281b5d61b8Smrg cookie = xcb_get_property(pWMInfo->conn, FALSE, iWindow, pWMInfo->atmPrivMap, 5291b5d61b8Smrg XCB_ATOM_INTEGER, 0L, sizeof(HWND)/4L); 5301b5d61b8Smrg reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL); 5311b5d61b8Smrg 5321b5d61b8Smrg if (reply) { 5331b5d61b8Smrg int length = xcb_get_property_value_length(reply); 5341b5d61b8Smrg HWND *value = xcb_get_property_value(reply); 5351b5d61b8Smrg 5361b5d61b8Smrg if (value && (length == sizeof(HWND))) { 5371b5d61b8Smrg hWnd = *value; 53835c4bbdfSmrg } 5391b5d61b8Smrg free(reply); 54035c4bbdfSmrg } 54135c4bbdfSmrg 54235c4bbdfSmrg /* Some sanity checks */ 54335c4bbdfSmrg if (!hWnd) 54435c4bbdfSmrg return NULL; 54535c4bbdfSmrg if (!IsWindow(hWnd)) 54635c4bbdfSmrg return NULL; 54735c4bbdfSmrg 54835c4bbdfSmrg return hWnd; 54935c4bbdfSmrg} 55005b261ecSmrg 5511b5d61b8Smrg/* 5521b5d61b8Smrg * Helper function to check for override-redirect 5531b5d61b8Smrg */ 5541b5d61b8Smrgstatic Bool 5551b5d61b8SmrgIsOverrideRedirect(xcb_connection_t *conn, xcb_window_t iWin) 5561b5d61b8Smrg{ 5571b5d61b8Smrg Bool result = FALSE; 5581b5d61b8Smrg xcb_get_window_attributes_reply_t *reply; 5591b5d61b8Smrg xcb_get_window_attributes_cookie_t cookie; 5601b5d61b8Smrg 5611b5d61b8Smrg cookie = xcb_get_window_attributes(conn, iWin); 5621b5d61b8Smrg reply = xcb_get_window_attributes_reply(conn, cookie, NULL); 5631b5d61b8Smrg if (reply) { 5641b5d61b8Smrg result = (reply->override_redirect != 0); 5651b5d61b8Smrg free(reply); 5661b5d61b8Smrg } 5671b5d61b8Smrg else { 5681b5d61b8Smrg ErrorF("IsOverrideRedirect: Failed to get window attributes\n"); 5691b5d61b8Smrg } 5701b5d61b8Smrg 5711b5d61b8Smrg return result; 5721b5d61b8Smrg} 5731b5d61b8Smrg 5741b5d61b8Smrg/* 5751b5d61b8Smrg * Helper function to get class and window names 5761b5d61b8Smrg*/ 5771b5d61b8Smrgstatic void 5781b5d61b8SmrgGetClassNames(WMInfoPtr pWMInfo, xcb_window_t iWindow, char **res_name, 5791b5d61b8Smrg char **res_class, char **window_name) 5801b5d61b8Smrg{ 5811b5d61b8Smrg xcb_get_property_cookie_t cookie1; 5821b5d61b8Smrg xcb_icccm_get_wm_class_reply_t reply1; 5831b5d61b8Smrg xcb_get_property_cookie_t cookie2; 5841b5d61b8Smrg xcb_icccm_get_text_property_reply_t reply2; 5851b5d61b8Smrg 5861b5d61b8Smrg cookie1 = xcb_icccm_get_wm_class(pWMInfo->conn, iWindow); 5871b5d61b8Smrg if (xcb_icccm_get_wm_class_reply(pWMInfo->conn, cookie1, &reply1, 5881b5d61b8Smrg NULL)) { 5891b5d61b8Smrg *res_name = strdup(reply1.instance_name); 5901b5d61b8Smrg *res_class = strdup(reply1.class_name); 5911b5d61b8Smrg xcb_icccm_get_wm_class_reply_wipe(&reply1); 5921b5d61b8Smrg } 5931b5d61b8Smrg else { 5941b5d61b8Smrg *res_name = strdup(""); 5951b5d61b8Smrg *res_class = strdup(""); 5961b5d61b8Smrg } 5971b5d61b8Smrg 5981b5d61b8Smrg cookie2 = xcb_icccm_get_wm_name(pWMInfo->conn, iWindow); 5991b5d61b8Smrg if (xcb_icccm_get_wm_name_reply(pWMInfo->conn, cookie2, &reply2, NULL)) { 6001b5d61b8Smrg *window_name = strndup(reply2.name, reply2.name_len); 6011b5d61b8Smrg xcb_icccm_get_text_property_reply_wipe(&reply2); 6021b5d61b8Smrg } 6031b5d61b8Smrg else { 6041b5d61b8Smrg *window_name = strdup(""); 6051b5d61b8Smrg } 6061b5d61b8Smrg} 6071b5d61b8Smrg 60805b261ecSmrg/* 60905b261ecSmrg * Updates the name of a HWND according to its X WM_NAME property 61005b261ecSmrg */ 61105b261ecSmrg 61205b261ecSmrgstatic void 6131b5d61b8SmrgUpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow) 61405b261ecSmrg{ 61535c4bbdfSmrg HWND hWnd; 61635c4bbdfSmrg 61735c4bbdfSmrg hWnd = getHwnd(pWMInfo, iWindow); 61835c4bbdfSmrg if (!hWnd) 61935c4bbdfSmrg return; 62035c4bbdfSmrg 62135c4bbdfSmrg /* If window isn't override-redirect */ 6221b5d61b8Smrg if (!IsOverrideRedirect(pWMInfo->conn, iWindow)) { 62335c4bbdfSmrg char *pszWindowName; 62435c4bbdfSmrg 62535c4bbdfSmrg /* Get the X windows window name */ 6261b5d61b8Smrg GetWindowName(pWMInfo, iWindow, &pszWindowName); 62735c4bbdfSmrg 62835c4bbdfSmrg if (pszWindowName) { 62935c4bbdfSmrg /* Convert from UTF-8 to wide char */ 63035c4bbdfSmrg int iLen = 63135c4bbdfSmrg MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1, NULL, 0); 63235c4bbdfSmrg wchar_t *pwszWideWindowName = 63335c4bbdfSmrg malloc(sizeof(wchar_t)*(iLen + 1)); 63435c4bbdfSmrg MultiByteToWideChar(CP_UTF8, 0, pszWindowName, -1, 63535c4bbdfSmrg pwszWideWindowName, iLen); 63635c4bbdfSmrg 63735c4bbdfSmrg /* Set the Windows window name */ 63835c4bbdfSmrg SetWindowTextW(hWnd, pwszWideWindowName); 63935c4bbdfSmrg 64035c4bbdfSmrg free(pwszWideWindowName); 64135c4bbdfSmrg free(pszWindowName); 64235c4bbdfSmrg } 64305b261ecSmrg } 64435c4bbdfSmrg} 64535c4bbdfSmrg 64635c4bbdfSmrg/* 64735c4bbdfSmrg * Updates the icon of a HWND according to its X icon properties 64835c4bbdfSmrg */ 64935c4bbdfSmrg 65035c4bbdfSmrgstatic void 6511b5d61b8SmrgUpdateIcon(WMInfoPtr pWMInfo, xcb_window_t iWindow) 65235c4bbdfSmrg{ 65335c4bbdfSmrg HWND hWnd; 65435c4bbdfSmrg HICON hIconNew = NULL; 65535c4bbdfSmrg 65635c4bbdfSmrg hWnd = getHwnd(pWMInfo, iWindow); 65735c4bbdfSmrg if (!hWnd) 65835c4bbdfSmrg return; 65935c4bbdfSmrg 66035c4bbdfSmrg /* If window isn't override-redirect */ 6611b5d61b8Smrg if (!IsOverrideRedirect(pWMInfo->conn, iWindow)) { 66235c4bbdfSmrg char *window_name = 0; 6631b5d61b8Smrg char *res_name = 0; 6641b5d61b8Smrg char *res_class = 0; 66535c4bbdfSmrg 6661b5d61b8Smrg GetClassNames(pWMInfo, iWindow, &res_name, &res_class, &window_name); 66735c4bbdfSmrg 6681b5d61b8Smrg hIconNew = winOverrideIcon(res_name, res_class, window_name); 66935c4bbdfSmrg 6701b5d61b8Smrg free(res_name); 6711b5d61b8Smrg free(res_class); 6721b5d61b8Smrg free(window_name); 6731b5d61b8Smrg winUpdateIcon(hWnd, pWMInfo->conn, iWindow, hIconNew); 67405b261ecSmrg } 67505b261ecSmrg} 67605b261ecSmrg 67735c4bbdfSmrg/* 67835c4bbdfSmrg * Updates the style of a HWND according to its X style properties 67935c4bbdfSmrg */ 68035c4bbdfSmrg 68135c4bbdfSmrgstatic void 6821b5d61b8SmrgUpdateStyle(WMInfoPtr pWMInfo, xcb_window_t iWindow) 68335c4bbdfSmrg{ 68435c4bbdfSmrg HWND hWnd; 68535c4bbdfSmrg HWND zstyle = HWND_NOTOPMOST; 68635c4bbdfSmrg UINT flags; 68735c4bbdfSmrg 68835c4bbdfSmrg hWnd = getHwnd(pWMInfo, iWindow); 68935c4bbdfSmrg if (!hWnd) 69035c4bbdfSmrg return; 69135c4bbdfSmrg 69235c4bbdfSmrg /* Determine the Window style, which determines borders and clipping region... */ 6931b5d61b8Smrg winApplyHints(pWMInfo, iWindow, hWnd, &zstyle); 69435c4bbdfSmrg winUpdateWindowPosition(hWnd, &zstyle); 69535c4bbdfSmrg 69635c4bbdfSmrg /* Apply the updated window style, without changing it's show or activation state */ 69735c4bbdfSmrg flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE; 69835c4bbdfSmrg if (zstyle == HWND_NOTOPMOST) 69935c4bbdfSmrg flags |= SWP_NOZORDER | SWP_NOOWNERZORDER; 70035c4bbdfSmrg SetWindowPos(hWnd, NULL, 0, 0, 0, 0, flags); 70135c4bbdfSmrg 70235c4bbdfSmrg /* 70335c4bbdfSmrg Use the WS_EX_TOOLWINDOW style to remove window from Alt-Tab window switcher 70435c4bbdfSmrg 70535c4bbdfSmrg According to MSDN, this is supposed to remove the window from the taskbar as well, 70635c4bbdfSmrg if we SW_HIDE before changing the style followed by SW_SHOW afterwards. 70735c4bbdfSmrg 70835c4bbdfSmrg But that doesn't seem to work reliably, and causes the window to flicker, so use 70935c4bbdfSmrg the iTaskbarList interface to tell the taskbar to show or hide this window. 71035c4bbdfSmrg */ 71135c4bbdfSmrg winShowWindowOnTaskbar(hWnd, 71235c4bbdfSmrg (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & 71335c4bbdfSmrg WS_EX_APPWINDOW) ? TRUE : FALSE); 71435c4bbdfSmrg} 71505b261ecSmrg 7161b5d61b8Smrg/* 7171b5d61b8Smrg * Updates the state of a HWND 7181b5d61b8Smrg * (only minimization supported at the moment) 7191b5d61b8Smrg */ 7201b5d61b8Smrg 7211b5d61b8Smrgstatic void 7221b5d61b8SmrgUpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow) 7231b5d61b8Smrg{ 7241b5d61b8Smrg HWND hWnd; 7251b5d61b8Smrg 7261b5d61b8Smrg winDebug("UpdateState: iWindow 0x%08x\n", (int)iWindow); 7271b5d61b8Smrg 7281b5d61b8Smrg hWnd = getHwnd(pWMInfo, iWindow); 7291b5d61b8Smrg if (!hWnd) 7301b5d61b8Smrg return; 7311b5d61b8Smrg 7321b5d61b8Smrg ShowWindow(hWnd, SW_MINIMIZE); 7331b5d61b8Smrg} 7341b5d61b8Smrg 73505b261ecSmrg#if 0 73605b261ecSmrg/* 73705b261ecSmrg * Fix up any differences between the X11 and Win32 window stacks 73805b261ecSmrg * starting at the window passed in 73905b261ecSmrg */ 74005b261ecSmrgstatic void 7411b5d61b8SmrgPreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction) 74205b261ecSmrg{ 74335c4bbdfSmrg HWND hWnd; 74435c4bbdfSmrg DWORD myWinProcID, winProcID; 7451b5d61b8Smrg xcb_window_t xWindow; 74635c4bbdfSmrg WINDOWPLACEMENT wndPlace; 74735c4bbdfSmrg 74835c4bbdfSmrg hWnd = getHwnd(pWMInfo, iWindow); 74935c4bbdfSmrg if (!hWnd) 75035c4bbdfSmrg return; 75135c4bbdfSmrg 75235c4bbdfSmrg GetWindowThreadProcessId(hWnd, &myWinProcID); 75305b261ecSmrg hWnd = GetNextWindow(hWnd, direction); 75405b261ecSmrg 75535c4bbdfSmrg while (hWnd) { 75635c4bbdfSmrg GetWindowThreadProcessId(hWnd, &winProcID); 75735c4bbdfSmrg if (winProcID == myWinProcID) { 75835c4bbdfSmrg wndPlace.length = sizeof(WINDOWPLACEMENT); 75935c4bbdfSmrg GetWindowPlacement(hWnd, &wndPlace); 76035c4bbdfSmrg if (!(wndPlace.showCmd == SW_HIDE || 76135c4bbdfSmrg wndPlace.showCmd == SW_MINIMIZE)) { 76235c4bbdfSmrg xWindow = (Window) GetProp(hWnd, WIN_WID_PROP); 76335c4bbdfSmrg if (xWindow) { 76435c4bbdfSmrg if (direction == GW_HWNDPREV) 76535c4bbdfSmrg XRaiseWindow(pWMInfo->pDisplay, xWindow); 76635c4bbdfSmrg else 76735c4bbdfSmrg XLowerWindow(pWMInfo->pDisplay, xWindow); 76835c4bbdfSmrg } 76935c4bbdfSmrg } 77035c4bbdfSmrg } 77135c4bbdfSmrg hWnd = GetNextWindow(hWnd, direction); 77235c4bbdfSmrg } 77335c4bbdfSmrg} 77435c4bbdfSmrg#endif /* PreserveWin32Stack */ 77505b261ecSmrg 77605b261ecSmrg/* 77705b261ecSmrg * winMultiWindowWMProc 77805b261ecSmrg */ 77905b261ecSmrg 78005b261ecSmrgstatic void * 78135c4bbdfSmrgwinMultiWindowWMProc(void *pArg) 78205b261ecSmrg{ 78335c4bbdfSmrg WMProcArgPtr pProcArg = (WMProcArgPtr) pArg; 78435c4bbdfSmrg WMInfoPtr pWMInfo = pProcArg->pWMInfo; 78535c4bbdfSmrg 78635c4bbdfSmrg /* Initialize the Window Manager */ 78735c4bbdfSmrg winInitMultiWindowWM(pWMInfo, pProcArg); 78835c4bbdfSmrg 78905b261ecSmrg#if CYGMULTIWINDOW_DEBUG 79035c4bbdfSmrg ErrorF("winMultiWindowWMProc ()\n"); 79105b261ecSmrg#endif 79205b261ecSmrg 79335c4bbdfSmrg /* Loop until we explicitly break out */ 79435c4bbdfSmrg for (;;) { 79535c4bbdfSmrg WMMsgNodePtr pNode; 79635c4bbdfSmrg 79735c4bbdfSmrg /* Pop a message off of our queue */ 79835c4bbdfSmrg pNode = PopMessage(&pWMInfo->wmMsgQueue, pWMInfo); 79935c4bbdfSmrg if (pNode == NULL) { 80035c4bbdfSmrg /* Bail if PopMessage returns without a message */ 80135c4bbdfSmrg /* NOTE: Remember that PopMessage is a blocking function. */ 80235c4bbdfSmrg ErrorF("winMultiWindowWMProc - Queue is Empty? Exiting.\n"); 80335c4bbdfSmrg pthread_exit(NULL); 80435c4bbdfSmrg } 80505b261ecSmrg 80605b261ecSmrg#if CYGMULTIWINDOW_DEBUG 8071b5d61b8Smrg ErrorF("winMultiWindowWMProc - MSG: %s (%d) ID: %d\n", 8081b5d61b8Smrg MessageName(&(pNode->msg)), (int)pNode->msg.msg, (int)pNode->msg.dwID); 80905b261ecSmrg#endif 81005b261ecSmrg 81135c4bbdfSmrg /* Branch on the message type */ 81235c4bbdfSmrg switch (pNode->msg.msg) { 81305b261ecSmrg#if 0 81435c4bbdfSmrg case WM_WM_MOVE: 81535c4bbdfSmrg break; 81605b261ecSmrg 81735c4bbdfSmrg case WM_WM_SIZE: 81835c4bbdfSmrg break; 81905b261ecSmrg#endif 82005b261ecSmrg 82135c4bbdfSmrg case WM_WM_RAISE: 82235c4bbdfSmrg /* Raise the window */ 8231b5d61b8Smrg { 8241b5d61b8Smrg const static uint32_t values[] = { XCB_STACK_MODE_ABOVE }; 8251b5d61b8Smrg xcb_configure_window(pWMInfo->conn, pNode->msg.iWindow, 8261b5d61b8Smrg XCB_CONFIG_WINDOW_STACK_MODE, values); 8271b5d61b8Smrg } 8281b5d61b8Smrg 82905b261ecSmrg#if 0 83035c4bbdfSmrg PreserveWin32Stack(pWMInfo, pNode->msg.iWindow, GW_HWNDPREV); 83105b261ecSmrg#endif 83235c4bbdfSmrg break; 83305b261ecSmrg 83435c4bbdfSmrg case WM_WM_LOWER: 83535c4bbdfSmrg /* Lower the window */ 8361b5d61b8Smrg { 8371b5d61b8Smrg const static uint32_t values[] = { XCB_STACK_MODE_BELOW }; 8381b5d61b8Smrg xcb_configure_window(pWMInfo->conn, pNode->msg.iWindow, 8391b5d61b8Smrg XCB_CONFIG_WINDOW_STACK_MODE, values); 8401b5d61b8Smrg } 84135c4bbdfSmrg break; 84205b261ecSmrg 8431b5d61b8Smrg case WM_WM_MAP2: 84435c4bbdfSmrg /* Put a note as to the HWND associated with this Window */ 8451b5d61b8Smrg xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, 8461b5d61b8Smrg pNode->msg.iWindow, pWMInfo->atmPrivMap, 8471b5d61b8Smrg XCB_ATOM_INTEGER, 32, 8481b5d61b8Smrg sizeof(HWND)/4, &(pNode->msg.hwndWindow)); 84935c4bbdfSmrg 85035c4bbdfSmrg break; 85135c4bbdfSmrg 85235c4bbdfSmrg case WM_WM_MAP3: 85335c4bbdfSmrg /* Put a note as to the HWND associated with this Window */ 8541b5d61b8Smrg xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, 8551b5d61b8Smrg pNode->msg.iWindow, pWMInfo->atmPrivMap, 8561b5d61b8Smrg XCB_ATOM_INTEGER, 32, 8571b5d61b8Smrg sizeof(HWND)/4, &(pNode->msg.hwndWindow)); 8581b5d61b8Smrg 85935c4bbdfSmrg UpdateName(pWMInfo, pNode->msg.iWindow); 86035c4bbdfSmrg UpdateIcon(pWMInfo, pNode->msg.iWindow); 86135c4bbdfSmrg UpdateStyle(pWMInfo, pNode->msg.iWindow); 86235c4bbdfSmrg 86335c4bbdfSmrg 86435c4bbdfSmrg /* Reshape */ 86535c4bbdfSmrg { 86635c4bbdfSmrg WindowPtr pWin = 86735c4bbdfSmrg GetProp(pNode->msg.hwndWindow, WIN_WINDOW_PROP); 86835c4bbdfSmrg if (pWin) { 86935c4bbdfSmrg winReshapeMultiWindow(pWin); 87035c4bbdfSmrg winUpdateRgnMultiWindow(pWin); 87135c4bbdfSmrg } 87235c4bbdfSmrg } 87335c4bbdfSmrg 87435c4bbdfSmrg break; 87535c4bbdfSmrg 87635c4bbdfSmrg case WM_WM_UNMAP: 87705b261ecSmrg 87835c4bbdfSmrg /* Unmap the window */ 8791b5d61b8Smrg xcb_unmap_window(pWMInfo->conn, pNode->msg.iWindow); 88035c4bbdfSmrg break; 88135c4bbdfSmrg 88235c4bbdfSmrg case WM_WM_KILL: 88335c4bbdfSmrg { 88435c4bbdfSmrg /* --- */ 8851b5d61b8Smrg if (IsWmProtocolAvailable(pWMInfo, 88635c4bbdfSmrg pNode->msg.iWindow, 88735c4bbdfSmrg pWMInfo->atmWmDelete)) 8881b5d61b8Smrg SendXMessage(pWMInfo->conn, 88935c4bbdfSmrg pNode->msg.iWindow, 89035c4bbdfSmrg pWMInfo->atmWmProtos, pWMInfo->atmWmDelete); 89135c4bbdfSmrg else 8921b5d61b8Smrg xcb_kill_client(pWMInfo->conn, pNode->msg.iWindow); 89335c4bbdfSmrg } 89435c4bbdfSmrg break; 89535c4bbdfSmrg 89635c4bbdfSmrg case WM_WM_ACTIVATE: 89735c4bbdfSmrg /* Set the input focus */ 89835c4bbdfSmrg 89935c4bbdfSmrg /* 90035c4bbdfSmrg ICCCM 4.1.7 is pretty opaque, but it appears that the rules are 90135c4bbdfSmrg actually quite simple: 90235c4bbdfSmrg -- the WM_HINTS input field determines whether the WM should call 90335c4bbdfSmrg XSetInputFocus() 90435c4bbdfSmrg -- independently, the WM_TAKE_FOCUS protocol determines whether 90535c4bbdfSmrg the WM should send a WM_TAKE_FOCUS ClientMessage. 90635c4bbdfSmrg */ 90735c4bbdfSmrg { 90835c4bbdfSmrg Bool neverFocus = FALSE; 9091b5d61b8Smrg xcb_get_property_cookie_t cookie; 9101b5d61b8Smrg xcb_icccm_wm_hints_t hints; 9111b5d61b8Smrg 9121b5d61b8Smrg cookie = xcb_icccm_get_wm_hints(pWMInfo->conn, pNode->msg.iWindow); 9131b5d61b8Smrg if (xcb_icccm_get_wm_hints_reply(pWMInfo->conn, cookie, &hints, 9141b5d61b8Smrg NULL)) { 9151b5d61b8Smrg if (hints.flags & XCB_ICCCM_WM_HINT_INPUT) 9161b5d61b8Smrg neverFocus = !hints.input; 91735c4bbdfSmrg } 91835c4bbdfSmrg 91935c4bbdfSmrg if (!neverFocus) 9201b5d61b8Smrg xcb_set_input_focus(pWMInfo->conn, XCB_INPUT_FOCUS_POINTER_ROOT, 9211b5d61b8Smrg pNode->msg.iWindow, XCB_CURRENT_TIME); 92235c4bbdfSmrg 9231b5d61b8Smrg if (IsWmProtocolAvailable(pWMInfo, 92435c4bbdfSmrg pNode->msg.iWindow, 92535c4bbdfSmrg pWMInfo->atmWmTakeFocus)) 9261b5d61b8Smrg SendXMessage(pWMInfo->conn, 92735c4bbdfSmrg pNode->msg.iWindow, 92835c4bbdfSmrg pWMInfo->atmWmProtos, pWMInfo->atmWmTakeFocus); 92935c4bbdfSmrg 93035c4bbdfSmrg } 93135c4bbdfSmrg break; 93235c4bbdfSmrg 93335c4bbdfSmrg case WM_WM_NAME_EVENT: 93435c4bbdfSmrg UpdateName(pWMInfo, pNode->msg.iWindow); 93535c4bbdfSmrg break; 93635c4bbdfSmrg 93735c4bbdfSmrg case WM_WM_ICON_EVENT: 93835c4bbdfSmrg UpdateIcon(pWMInfo, pNode->msg.iWindow); 93935c4bbdfSmrg break; 94035c4bbdfSmrg 94135c4bbdfSmrg case WM_WM_HINTS_EVENT: 94235c4bbdfSmrg { 94335c4bbdfSmrg /* Don't do anything if this is an override-redirect window */ 9441b5d61b8Smrg if (IsOverrideRedirect(pWMInfo->conn, pNode->msg.iWindow)) 94535c4bbdfSmrg break; 94635c4bbdfSmrg 94735c4bbdfSmrg UpdateStyle(pWMInfo, pNode->msg.iWindow); 94835c4bbdfSmrg } 94935c4bbdfSmrg break; 95035c4bbdfSmrg 95135c4bbdfSmrg case WM_WM_CHANGE_STATE: 9521b5d61b8Smrg UpdateState(pWMInfo, pNode->msg.iWindow); 95335c4bbdfSmrg break; 95435c4bbdfSmrg 95535c4bbdfSmrg default: 95635c4bbdfSmrg ErrorF("winMultiWindowWMProc - Unknown Message. Exiting.\n"); 95735c4bbdfSmrg pthread_exit(NULL); 95835c4bbdfSmrg break; 95935c4bbdfSmrg } 96035c4bbdfSmrg 96135c4bbdfSmrg /* Free the retrieved message */ 96235c4bbdfSmrg free(pNode); 96335c4bbdfSmrg 96435c4bbdfSmrg /* Flush any pending events on our display */ 9651b5d61b8Smrg xcb_flush(pWMInfo->conn); 9661b5d61b8Smrg 9671b5d61b8Smrg /* This is just laziness rather than making sure we used _checked everywhere */ 9681b5d61b8Smrg { 9691b5d61b8Smrg xcb_generic_event_t *event = xcb_poll_for_event(pWMInfo->conn); 9701b5d61b8Smrg if (event) { 9711b5d61b8Smrg if ((event->response_type & ~0x80) == 0) { 9721b5d61b8Smrg xcb_generic_error_t *err = (xcb_generic_error_t *)event; 9731b5d61b8Smrg ErrorF("winMultiWindowWMProc - Error code: %i, ID: 0x%08x, " 9741b5d61b8Smrg "Major opcode: %i, Minor opcode: %i\n", 9751b5d61b8Smrg err->error_code, err->resource_id, 9761b5d61b8Smrg err->major_code, err->minor_code); 9771b5d61b8Smrg } 9781b5d61b8Smrg } 9791b5d61b8Smrg } 9801b5d61b8Smrg 9811b5d61b8Smrg /* I/O errors etc. */ 9821b5d61b8Smrg { 9831b5d61b8Smrg int e = xcb_connection_has_error(pWMInfo->conn); 9841b5d61b8Smrg if (e) { 9851b5d61b8Smrg ErrorF("winMultiWindowWMProc - Fatal error %d on xcb connection\n", e); 9861b5d61b8Smrg break; 9871b5d61b8Smrg } 9881b5d61b8Smrg } 98905b261ecSmrg } 99005b261ecSmrg 99135c4bbdfSmrg /* Free the condition variable */ 99235c4bbdfSmrg pthread_cond_destroy(&pWMInfo->wmMsgQueue.pcNotEmpty); 99335c4bbdfSmrg 99435c4bbdfSmrg /* Free the mutex variable */ 99535c4bbdfSmrg pthread_mutex_destroy(&pWMInfo->wmMsgQueue.pmMutex); 99635c4bbdfSmrg 99735c4bbdfSmrg /* Free the passed-in argument */ 99835c4bbdfSmrg free(pProcArg); 99935c4bbdfSmrg 100005b261ecSmrg#if CYGMULTIWINDOW_DEBUG 100135c4bbdfSmrg ErrorF("-winMultiWindowWMProc ()\n"); 100205b261ecSmrg#endif 100335c4bbdfSmrg return NULL; 100405b261ecSmrg} 100505b261ecSmrg 10061b5d61b8Smrgstatic xcb_atom_t 10071b5d61b8Smrgintern_atom(xcb_connection_t *conn, const char *atomName) 10081b5d61b8Smrg{ 10091b5d61b8Smrg xcb_intern_atom_reply_t *atom_reply; 10101b5d61b8Smrg xcb_intern_atom_cookie_t atom_cookie; 10111b5d61b8Smrg xcb_atom_t atom = XCB_ATOM_NONE; 10121b5d61b8Smrg 10131b5d61b8Smrg atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName); 10141b5d61b8Smrg atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL); 10151b5d61b8Smrg if (atom_reply) { 10161b5d61b8Smrg atom = atom_reply->atom; 10171b5d61b8Smrg free(atom_reply); 10181b5d61b8Smrg } 10191b5d61b8Smrg return atom; 10201b5d61b8Smrg} 10211b5d61b8Smrg 102205b261ecSmrg/* 102305b261ecSmrg * X message procedure 102405b261ecSmrg */ 102505b261ecSmrg 102605b261ecSmrgstatic void * 102735c4bbdfSmrgwinMultiWindowXMsgProc(void *pArg) 102805b261ecSmrg{ 102935c4bbdfSmrg winWMMessageRec msg; 103035c4bbdfSmrg XMsgProcArgPtr pProcArg = (XMsgProcArgPtr) pArg; 103135c4bbdfSmrg char pszDisplay[512]; 103235c4bbdfSmrg int iRetries; 10331b5d61b8Smrg xcb_atom_t atmWmName; 10341b5d61b8Smrg xcb_atom_t atmNetWmName; 10351b5d61b8Smrg xcb_atom_t atmWmHints; 10361b5d61b8Smrg xcb_atom_t atmWmChange; 10371b5d61b8Smrg xcb_atom_t atmNetWmIcon; 10381b5d61b8Smrg xcb_atom_t atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints; 103935c4bbdfSmrg int iReturn; 10401b5d61b8Smrg xcb_auth_info_t *auth_info; 104135c4bbdfSmrg 104235c4bbdfSmrg winDebug("winMultiWindowXMsgProc - Hello\n"); 104335c4bbdfSmrg 104435c4bbdfSmrg /* Check that argument pointer is not invalid */ 104535c4bbdfSmrg if (pProcArg == NULL) { 104635c4bbdfSmrg ErrorF("winMultiWindowXMsgProc - pProcArg is NULL. Exiting.\n"); 104735c4bbdfSmrg pthread_exit(NULL); 104805b261ecSmrg } 104905b261ecSmrg 10501b5d61b8Smrg winDebug("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n"); 105105b261ecSmrg 105235c4bbdfSmrg /* Grab the server started mutex - pause until we get it */ 105335c4bbdfSmrg iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted); 105435c4bbdfSmrg if (iReturn != 0) { 105535c4bbdfSmrg ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () failed: %d. " 105635c4bbdfSmrg "Exiting.\n", iReturn); 105735c4bbdfSmrg pthread_exit(NULL); 105805b261ecSmrg } 105905b261ecSmrg 10601b5d61b8Smrg winDebug("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n"); 106105b261ecSmrg 106235c4bbdfSmrg /* Release the server started mutex */ 106335c4bbdfSmrg pthread_mutex_unlock(pProcArg->ppmServerStarted); 106405b261ecSmrg 10651b5d61b8Smrg winDebug("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n"); 106605b261ecSmrg 106735c4bbdfSmrg /* Setup the display connection string x */ 106835c4bbdfSmrg winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen); 106905b261ecSmrg 107035c4bbdfSmrg /* Print the display connection string */ 107135c4bbdfSmrg ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay); 107205b261ecSmrg 107335c4bbdfSmrg /* Use our generated cookie for authentication */ 10741b5d61b8Smrg auth_info = winGetXcbAuthInfo(); 10756747b715Smrg 107635c4bbdfSmrg /* Initialize retry count */ 107735c4bbdfSmrg iRetries = 0; 107805b261ecSmrg 107935c4bbdfSmrg /* Open the X display */ 108035c4bbdfSmrg do { 108135c4bbdfSmrg /* Try to open the display */ 10821b5d61b8Smrg pProcArg->conn = xcb_connect_to_display_with_auth_info(pszDisplay, 10831b5d61b8Smrg auth_info, NULL); 10841b5d61b8Smrg if (xcb_connection_has_error(pProcArg->conn)) { 108535c4bbdfSmrg ErrorF("winMultiWindowXMsgProc - Could not open display, try: %d, " 108635c4bbdfSmrg "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY); 108735c4bbdfSmrg ++iRetries; 108835c4bbdfSmrg sleep(WIN_CONNECT_DELAY); 108935c4bbdfSmrg continue; 109035c4bbdfSmrg } 109135c4bbdfSmrg else 109235c4bbdfSmrg break; 109305b261ecSmrg } 10941b5d61b8Smrg while (xcb_connection_has_error(pProcArg->conn) && iRetries < WIN_CONNECT_RETRIES); 109535c4bbdfSmrg 109635c4bbdfSmrg /* Make sure that the display opened */ 10971b5d61b8Smrg if (xcb_connection_has_error(pProcArg->conn)) { 109835c4bbdfSmrg ErrorF("winMultiWindowXMsgProc - Failed opening the display. " 109935c4bbdfSmrg "Exiting.\n"); 110035c4bbdfSmrg pthread_exit(NULL); 110105b261ecSmrg } 110205b261ecSmrg 11031b5d61b8Smrg ErrorF("winMultiWindowXMsgProc - xcb_connect() returned and " 110435c4bbdfSmrg "successfully opened the display.\n"); 110505b261ecSmrg 110635c4bbdfSmrg /* Check if another window manager is already running */ 11071b5d61b8Smrg if (CheckAnotherWindowManager(pProcArg->conn, pProcArg->dwScreen)) { 110835c4bbdfSmrg ErrorF("winMultiWindowXMsgProc - " 110935c4bbdfSmrg "another window manager is running. Exiting.\n"); 111035c4bbdfSmrg pthread_exit(NULL); 111105b261ecSmrg } 11126747b715Smrg 11131b5d61b8Smrg { 11141b5d61b8Smrg /* Get root window id */ 11151b5d61b8Smrg xcb_screen_t *root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen); 11161b5d61b8Smrg xcb_window_t root_window_id = root_screen->root; 11171b5d61b8Smrg 11181b5d61b8Smrg /* Set WM_ICON_SIZE property indicating desired icon sizes */ 11191b5d61b8Smrg typedef struct { 11201b5d61b8Smrg uint32_t min_width, min_height; 11211b5d61b8Smrg uint32_t max_width, max_height; 11221b5d61b8Smrg int32_t width_inc, height_inc; 11231b5d61b8Smrg } xcb_wm_icon_size_hints_hints_t; 11241b5d61b8Smrg 11251b5d61b8Smrg xcb_wm_icon_size_hints_hints_t xis; 11261b5d61b8Smrg xis.min_width = xis.min_height = 16; 11271b5d61b8Smrg xis.max_width = xis.max_height = 48; 11281b5d61b8Smrg xis.width_inc = xis.height_inc = 16; 11291b5d61b8Smrg 11301b5d61b8Smrg xcb_change_property(pProcArg->conn, XCB_PROP_MODE_REPLACE, root_window_id, 11311b5d61b8Smrg XCB_ATOM_WM_ICON_SIZE, XCB_ATOM_WM_ICON_SIZE, 32, 11321b5d61b8Smrg sizeof(xis)/4, &xis); 113305b261ecSmrg } 113405b261ecSmrg 11351b5d61b8Smrg atmWmName = intern_atom(pProcArg->conn, "WM_NAME"); 11361b5d61b8Smrg atmNetWmName = intern_atom(pProcArg->conn, "_NET_WM_NAME"); 11371b5d61b8Smrg atmWmHints = intern_atom(pProcArg->conn, "WM_HINTS"); 11381b5d61b8Smrg atmWmChange = intern_atom(pProcArg->conn, "WM_CHANGE_STATE"); 11391b5d61b8Smrg atmNetWmIcon = intern_atom(pProcArg->conn, "_NET_WM_ICON"); 11401b5d61b8Smrg atmWindowState = intern_atom(pProcArg->conn, "_NET_WM_STATE"); 11411b5d61b8Smrg atmMotifWmHints = intern_atom(pProcArg->conn, "_MOTIF_WM_HINTS"); 11421b5d61b8Smrg atmWindowType = intern_atom(pProcArg->conn, "_NET_WM_WINDOW_TYPE"); 11431b5d61b8Smrg atmNormalHints = intern_atom(pProcArg->conn, "WM_NORMAL_HINTS"); 114435c4bbdfSmrg 114535c4bbdfSmrg /* 114635c4bbdfSmrg iiimxcf had a bug until 2009-04-27, assuming that the 114735c4bbdfSmrg WM_STATE atom exists, causing clients to fail with 114835c4bbdfSmrg a BadAtom X error if it doesn't. 114935c4bbdfSmrg 115035c4bbdfSmrg Since this is on in the default Solaris 10 install, 115135c4bbdfSmrg workaround this by making sure it does exist... 115235c4bbdfSmrg */ 11531b5d61b8Smrg intern_atom(pProcArg->conn, "WM_STATE"); 115435c4bbdfSmrg 115535c4bbdfSmrg /* Loop until we explicitly break out */ 115635c4bbdfSmrg while (1) { 11571b5d61b8Smrg xcb_generic_event_t *event; 11581b5d61b8Smrg uint8_t type; 11591b5d61b8Smrg Bool send_event; 11601b5d61b8Smrg 116135c4bbdfSmrg if (g_shutdown) 116235c4bbdfSmrg break; 116335c4bbdfSmrg 116435c4bbdfSmrg /* Fetch next event */ 11651b5d61b8Smrg event = xcb_wait_for_event(pProcArg->conn); 11661b5d61b8Smrg if (!event) { // returns NULL on I/O error 11671b5d61b8Smrg int e = xcb_connection_has_error(pProcArg->conn); 11681b5d61b8Smrg ErrorF("winMultiWindowXMsgProc - Fatal error %d on xcb connection\n", e); 11691b5d61b8Smrg break; 11701b5d61b8Smrg } 117135c4bbdfSmrg 11721b5d61b8Smrg type = event->response_type & ~0x80; 11731b5d61b8Smrg send_event = event->response_type & 0x80; 117435c4bbdfSmrg 11751b5d61b8Smrg winDebug("winMultiWindowXMsgProc - event %d\n", type); 117635c4bbdfSmrg 11771b5d61b8Smrg /* Branch on event type */ 11781b5d61b8Smrg if (type == 0) { 11791b5d61b8Smrg xcb_generic_error_t *err = (xcb_generic_error_t *)event; 11801b5d61b8Smrg ErrorF("winMultiWindowXMsgProc - Error code: %i, ID: 0x%08x, " 11811b5d61b8Smrg "Major opcode: %i, Minor opcode: %i\n", 11821b5d61b8Smrg err->error_code, err->resource_id, 11831b5d61b8Smrg err->major_code, err->minor_code); 11841b5d61b8Smrg } 11851b5d61b8Smrg else if (type == XCB_CREATE_NOTIFY) { 11861b5d61b8Smrg xcb_create_notify_event_t *notify = (xcb_create_notify_event_t *)event; 11871b5d61b8Smrg 11881b5d61b8Smrg /* Request property change events */ 11891b5d61b8Smrg const static uint32_t mask_value[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; 11901b5d61b8Smrg xcb_change_window_attributes (pProcArg->conn, notify->window, 11911b5d61b8Smrg XCB_CW_EVENT_MASK, mask_value); 11921b5d61b8Smrg 11931b5d61b8Smrg /* If it's not override-redirect, set the border-width to 0 */ 11941b5d61b8Smrg if (!IsOverrideRedirect(pProcArg->conn, notify->window)) { 11951b5d61b8Smrg const static uint32_t width_value[] = { 0 }; 11961b5d61b8Smrg xcb_configure_window(pProcArg->conn, notify->window, 11971b5d61b8Smrg XCB_CONFIG_WINDOW_BORDER_WIDTH, width_value); 11981b5d61b8Smrg } 119935c4bbdfSmrg } 12001b5d61b8Smrg else if (type == XCB_MAP_NOTIFY) { 120135c4bbdfSmrg /* Fake a reparentNotify event as SWT/Motif expects a 120235c4bbdfSmrg Window Manager to reparent a top-level window when 120335c4bbdfSmrg it is mapped and waits until they do. 120435c4bbdfSmrg 120535c4bbdfSmrg We don't actually need to reparent, as the frame is 120635c4bbdfSmrg a native window, not an X window 120735c4bbdfSmrg 120835c4bbdfSmrg We do this on MapNotify, not MapRequest like a real 120935c4bbdfSmrg Window Manager would, so we don't have do get involved 121035c4bbdfSmrg in actually mapping the window via it's (non-existent) 121135c4bbdfSmrg parent... 121235c4bbdfSmrg 121335c4bbdfSmrg See sourceware bugzilla #9848 121435c4bbdfSmrg */ 121535c4bbdfSmrg 12161b5d61b8Smrg xcb_map_notify_event_t *notify = (xcb_map_notify_event_t *)event; 12171b5d61b8Smrg 12181b5d61b8Smrg xcb_get_geometry_cookie_t cookie; 12191b5d61b8Smrg xcb_get_geometry_reply_t *reply; 12201b5d61b8Smrg xcb_query_tree_cookie_t cookie_qt; 12211b5d61b8Smrg xcb_query_tree_reply_t *reply_qt; 12221b5d61b8Smrg 12231b5d61b8Smrg cookie = xcb_get_geometry(pProcArg->conn, notify->window); 12241b5d61b8Smrg cookie_qt = xcb_query_tree(pProcArg->conn, notify->window); 12251b5d61b8Smrg reply = xcb_get_geometry_reply(pProcArg->conn, cookie, NULL); 12261b5d61b8Smrg reply_qt = xcb_query_tree_reply(pProcArg->conn, cookie_qt, NULL); 122735c4bbdfSmrg 12281b5d61b8Smrg if (reply && reply_qt) { 122935c4bbdfSmrg /* 123035c4bbdfSmrg It's a top-level window if the parent window is a root window 123135c4bbdfSmrg Only non-override_redirect windows can get reparented 123235c4bbdfSmrg */ 12331b5d61b8Smrg if ((reply->root == reply_qt->parent) && !notify->override_redirect) { 12341b5d61b8Smrg xcb_reparent_notify_event_t event_send; 12351b5d61b8Smrg 12361b5d61b8Smrg event_send.response_type = ReparentNotify; 12371b5d61b8Smrg event_send.event = notify->window; 12381b5d61b8Smrg event_send.window = notify->window; 12391b5d61b8Smrg event_send.parent = reply_qt->parent; 12401b5d61b8Smrg event_send.x = reply->x; 12411b5d61b8Smrg event_send.y = reply->y; 12421b5d61b8Smrg 12431b5d61b8Smrg xcb_send_event (pProcArg->conn, TRUE, notify->window, 12441b5d61b8Smrg XCB_EVENT_MASK_STRUCTURE_NOTIFY, 12451b5d61b8Smrg (const char *)&event_send); 12461b5d61b8Smrg 12471b5d61b8Smrg free(reply_qt); 12481b5d61b8Smrg free(reply); 124935c4bbdfSmrg } 125035c4bbdfSmrg } 125135c4bbdfSmrg } 12521b5d61b8Smrg else if (type == XCB_CONFIGURE_NOTIFY) { 12531b5d61b8Smrg if (!send_event) { 125435c4bbdfSmrg /* 125535c4bbdfSmrg Java applications using AWT on JRE 1.6.0 break with non-reparenting WMs AWT 125635c4bbdfSmrg doesn't explicitly know about (See sun bug #6434227) 125735c4bbdfSmrg 125835c4bbdfSmrg XDecoratedPeer.handleConfigureNotifyEvent() only processes non-synthetic 125935c4bbdfSmrg ConfigureNotify events to update window location if it's identified the 126035c4bbdfSmrg WM as a non-reparenting WM it knows about (compiz or lookingglass) 126135c4bbdfSmrg 126235c4bbdfSmrg Rather than tell all sorts of lies to get XWM to recognize us as one of 126335c4bbdfSmrg those, simply send a synthetic ConfigureNotify for every non-synthetic one 126435c4bbdfSmrg */ 12651b5d61b8Smrg xcb_configure_notify_event_t *notify = (xcb_configure_notify_event_t *)event; 12661b5d61b8Smrg xcb_configure_notify_event_t event_send = *notify; 126735c4bbdfSmrg 12681b5d61b8Smrg event_send.event = notify->window; 12691b5d61b8Smrg 12701b5d61b8Smrg xcb_send_event(pProcArg->conn, TRUE, notify->window, 12711b5d61b8Smrg XCB_EVENT_MASK_STRUCTURE_NOTIFY, 12721b5d61b8Smrg (const char *)&event_send); 127335c4bbdfSmrg } 127435c4bbdfSmrg } 12751b5d61b8Smrg else if (type == XCB_PROPERTY_NOTIFY) { 12761b5d61b8Smrg xcb_property_notify_event_t *notify = (xcb_property_notify_event_t *)event; 12771b5d61b8Smrg 12781b5d61b8Smrg if ((notify->atom == atmWmName) || 12791b5d61b8Smrg (notify->atom == atmNetWmName)) { 128035c4bbdfSmrg memset(&msg, 0, sizeof(msg)); 128135c4bbdfSmrg 128235c4bbdfSmrg msg.msg = WM_WM_NAME_EVENT; 12831b5d61b8Smrg msg.iWindow = notify->window; 128435c4bbdfSmrg 128535c4bbdfSmrg /* Other fields ignored */ 128635c4bbdfSmrg winSendMessageToWM(pProcArg->pWMInfo, &msg); 128735c4bbdfSmrg } 128835c4bbdfSmrg else { 128935c4bbdfSmrg /* 129035c4bbdfSmrg Several properties are considered for WM hints, check if this property change affects any of them... 129135c4bbdfSmrg (this list needs to be kept in sync with winApplyHints()) 129235c4bbdfSmrg */ 12931b5d61b8Smrg if ((notify->atom == atmWmHints) || 12941b5d61b8Smrg (notify->atom == atmWindowState) || 12951b5d61b8Smrg (notify->atom == atmMotifWmHints) || 12961b5d61b8Smrg (notify->atom == atmWindowType) || 12971b5d61b8Smrg (notify->atom == atmNormalHints)) { 129835c4bbdfSmrg memset(&msg, 0, sizeof(msg)); 129935c4bbdfSmrg msg.msg = WM_WM_HINTS_EVENT; 13001b5d61b8Smrg msg.iWindow = notify->window; 130135c4bbdfSmrg 130235c4bbdfSmrg /* Other fields ignored */ 130335c4bbdfSmrg winSendMessageToWM(pProcArg->pWMInfo, &msg); 130435c4bbdfSmrg } 130535c4bbdfSmrg 130635c4bbdfSmrg /* Not an else as WM_HINTS affects both style and icon */ 13071b5d61b8Smrg if ((notify->atom == atmWmHints) || 13081b5d61b8Smrg (notify->atom == atmNetWmIcon)) { 130935c4bbdfSmrg memset(&msg, 0, sizeof(msg)); 131035c4bbdfSmrg msg.msg = WM_WM_ICON_EVENT; 13111b5d61b8Smrg msg.iWindow = notify->window; 131235c4bbdfSmrg 131335c4bbdfSmrg /* Other fields ignored */ 131435c4bbdfSmrg winSendMessageToWM(pProcArg->pWMInfo, &msg); 13156747b715Smrg } 13166747b715Smrg } 13176747b715Smrg } 13181b5d61b8Smrg else if (type == XCB_CLIENT_MESSAGE) { 13191b5d61b8Smrg xcb_client_message_event_t *client_msg = (xcb_client_message_event_t *)event; 132035c4bbdfSmrg 13211b5d61b8Smrg if (client_msg->type == atmWmChange 13221b5d61b8Smrg && client_msg->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) { 13231b5d61b8Smrg ErrorF("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n"); 132435c4bbdfSmrg 13251b5d61b8Smrg memset(&msg, 0, sizeof(msg)); 132635c4bbdfSmrg 13271b5d61b8Smrg msg.msg = WM_WM_CHANGE_STATE; 13281b5d61b8Smrg msg.iWindow = client_msg->window; 13291b5d61b8Smrg 13301b5d61b8Smrg winSendMessageToWM(pProcArg->pWMInfo, &msg); 13311b5d61b8Smrg } 133235c4bbdfSmrg } 13331b5d61b8Smrg 13341b5d61b8Smrg /* Free the event */ 13351b5d61b8Smrg free(event); 133605b261ecSmrg } 133705b261ecSmrg 13381b5d61b8Smrg xcb_disconnect(pProcArg->conn); 133935c4bbdfSmrg pthread_exit(NULL); 134035c4bbdfSmrg return NULL; 134105b261ecSmrg} 134205b261ecSmrg 134305b261ecSmrg/* 134405b261ecSmrg * winInitWM - Entry point for the X server to spawn 134505b261ecSmrg * the Window Manager thread. Called from 134605b261ecSmrg * winscrinit.c/winFinishScreenInitFB (). 134705b261ecSmrg */ 134805b261ecSmrg 134905b261ecSmrgBool 135035c4bbdfSmrgwinInitWM(void **ppWMInfo, 135135c4bbdfSmrg pthread_t * ptWMProc, 135235c4bbdfSmrg pthread_t * ptXMsgProc, 135335c4bbdfSmrg pthread_mutex_t * ppmServerStarted, 13541b5d61b8Smrg int dwScreen, HWND hwndScreen) 135505b261ecSmrg{ 135635c4bbdfSmrg WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec)); 135735c4bbdfSmrg WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec)); 135835c4bbdfSmrg XMsgProcArgPtr pXMsgArg = malloc(sizeof(XMsgProcArgRec)); 135935c4bbdfSmrg 136035c4bbdfSmrg /* Bail if the input parameters are bad */ 136135c4bbdfSmrg if (pArg == NULL || pWMInfo == NULL || pXMsgArg == NULL) { 136235c4bbdfSmrg ErrorF("winInitWM - malloc failed.\n"); 136335c4bbdfSmrg free(pArg); 136435c4bbdfSmrg free(pWMInfo); 136535c4bbdfSmrg free(pXMsgArg); 136635c4bbdfSmrg return FALSE; 136705b261ecSmrg } 136835c4bbdfSmrg 136935c4bbdfSmrg /* Zero the allocated memory */ 137035c4bbdfSmrg ZeroMemory(pArg, sizeof(WMProcArgRec)); 137135c4bbdfSmrg ZeroMemory(pWMInfo, sizeof(WMInfoRec)); 137235c4bbdfSmrg ZeroMemory(pXMsgArg, sizeof(XMsgProcArgRec)); 137335c4bbdfSmrg 137435c4bbdfSmrg /* Set a return pointer to the Window Manager info structure */ 137535c4bbdfSmrg *ppWMInfo = pWMInfo; 137635c4bbdfSmrg 137735c4bbdfSmrg /* Setup the argument structure for the thread function */ 137835c4bbdfSmrg pArg->dwScreen = dwScreen; 137935c4bbdfSmrg pArg->pWMInfo = pWMInfo; 138035c4bbdfSmrg pArg->ppmServerStarted = ppmServerStarted; 138135c4bbdfSmrg 138235c4bbdfSmrg /* Intialize the message queue */ 138335c4bbdfSmrg if (!InitQueue(&pWMInfo->wmMsgQueue)) { 138435c4bbdfSmrg ErrorF("winInitWM - InitQueue () failed.\n"); 138535c4bbdfSmrg return FALSE; 138605b261ecSmrg } 138735c4bbdfSmrg 138835c4bbdfSmrg /* Spawn a thread for the Window Manager */ 138935c4bbdfSmrg if (pthread_create(ptWMProc, NULL, winMultiWindowWMProc, pArg)) { 139035c4bbdfSmrg /* Bail if thread creation failed */ 139135c4bbdfSmrg ErrorF("winInitWM - pthread_create failed for Window Manager.\n"); 139235c4bbdfSmrg return FALSE; 139305b261ecSmrg } 139405b261ecSmrg 139535c4bbdfSmrg /* Spawn the XNextEvent thread, will send messages to WM */ 139635c4bbdfSmrg pXMsgArg->dwScreen = dwScreen; 139735c4bbdfSmrg pXMsgArg->pWMInfo = pWMInfo; 139835c4bbdfSmrg pXMsgArg->ppmServerStarted = ppmServerStarted; 139935c4bbdfSmrg pXMsgArg->hwndScreen = hwndScreen; 140035c4bbdfSmrg if (pthread_create(ptXMsgProc, NULL, winMultiWindowXMsgProc, pXMsgArg)) { 140135c4bbdfSmrg /* Bail if thread creation failed */ 140235c4bbdfSmrg ErrorF("winInitWM - pthread_create failed on XMSG.\n"); 140335c4bbdfSmrg return FALSE; 140405b261ecSmrg } 140505b261ecSmrg 140605b261ecSmrg#if CYGDEBUG || YES 140735c4bbdfSmrg winDebug("winInitWM - Returning.\n"); 140805b261ecSmrg#endif 140905b261ecSmrg 141035c4bbdfSmrg return TRUE; 141105b261ecSmrg} 141205b261ecSmrg 141305b261ecSmrg/* 141405b261ecSmrg * Window manager thread - setup 141505b261ecSmrg */ 141605b261ecSmrg 141705b261ecSmrgstatic void 141835c4bbdfSmrgwinInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) 141905b261ecSmrg{ 142035c4bbdfSmrg int iRetries = 0; 142135c4bbdfSmrg char pszDisplay[512]; 142235c4bbdfSmrg int iReturn; 14231b5d61b8Smrg xcb_auth_info_t *auth_info; 142405b261ecSmrg 142535c4bbdfSmrg winDebug("winInitMultiWindowWM - Hello\n"); 142605b261ecSmrg 142735c4bbdfSmrg /* Check that argument pointer is not invalid */ 142835c4bbdfSmrg if (pProcArg == NULL) { 142935c4bbdfSmrg ErrorF("winInitMultiWindowWM - pProcArg is NULL. Exiting.\n"); 143035c4bbdfSmrg pthread_exit(NULL); 143105b261ecSmrg } 143205b261ecSmrg 14331b5d61b8Smrg winDebug("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n"); 143405b261ecSmrg 143535c4bbdfSmrg /* Grab our garbage mutex to satisfy pthread_cond_wait */ 143635c4bbdfSmrg iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted); 143735c4bbdfSmrg if (iReturn != 0) { 143835c4bbdfSmrg ErrorF("winInitMultiWindowWM - pthread_mutex_lock () failed: %d. " 143935c4bbdfSmrg "Exiting.\n", iReturn); 144035c4bbdfSmrg pthread_exit(NULL); 144105b261ecSmrg } 144205b261ecSmrg 14431b5d61b8Smrg winDebug("winInitMultiWindowWM - pthread_mutex_lock () returned.\n"); 144405b261ecSmrg 144535c4bbdfSmrg /* Release the server started mutex */ 144635c4bbdfSmrg pthread_mutex_unlock(pProcArg->ppmServerStarted); 144705b261ecSmrg 14481b5d61b8Smrg winDebug("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n"); 14496747b715Smrg 145035c4bbdfSmrg /* Setup the display connection string x */ 145135c4bbdfSmrg winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen); 145235c4bbdfSmrg 145335c4bbdfSmrg /* Print the display connection string */ 145435c4bbdfSmrg ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay); 145535c4bbdfSmrg 145635c4bbdfSmrg /* Use our generated cookie for authentication */ 14571b5d61b8Smrg auth_info = winGetXcbAuthInfo(); 145835c4bbdfSmrg 145935c4bbdfSmrg /* Open the X display */ 146035c4bbdfSmrg do { 146135c4bbdfSmrg /* Try to open the display */ 14621b5d61b8Smrg pWMInfo->conn = xcb_connect_to_display_with_auth_info(pszDisplay, 14631b5d61b8Smrg auth_info, NULL); 14641b5d61b8Smrg if (xcb_connection_has_error(pWMInfo->conn)) { 146535c4bbdfSmrg ErrorF("winInitMultiWindowWM - Could not open display, try: %d, " 146635c4bbdfSmrg "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY); 146735c4bbdfSmrg ++iRetries; 146835c4bbdfSmrg sleep(WIN_CONNECT_DELAY); 146935c4bbdfSmrg continue; 147035c4bbdfSmrg } 147135c4bbdfSmrg else 147235c4bbdfSmrg break; 147305b261ecSmrg } 14741b5d61b8Smrg while (xcb_connection_has_error(pWMInfo->conn) && iRetries < WIN_CONNECT_RETRIES); 147535c4bbdfSmrg 147635c4bbdfSmrg /* Make sure that the display opened */ 14771b5d61b8Smrg if (xcb_connection_has_error(pWMInfo->conn)) { 147835c4bbdfSmrg ErrorF("winInitMultiWindowWM - Failed opening the display. " 147935c4bbdfSmrg "Exiting.\n"); 148035c4bbdfSmrg pthread_exit(NULL); 148105b261ecSmrg } 148205b261ecSmrg 14831b5d61b8Smrg ErrorF("winInitMultiWindowWM - xcb_connect () returned and " 148435c4bbdfSmrg "successfully opened the display.\n"); 148505b261ecSmrg 148635c4bbdfSmrg /* Create some atoms */ 14871b5d61b8Smrg pWMInfo->atmWmProtos = intern_atom(pWMInfo->conn, "WM_PROTOCOLS"); 14881b5d61b8Smrg pWMInfo->atmWmDelete = intern_atom(pWMInfo->conn, "WM_DELETE_WINDOW"); 14891b5d61b8Smrg pWMInfo->atmWmTakeFocus = intern_atom(pWMInfo->conn, "WM_TAKE_FOCUS"); 14901b5d61b8Smrg pWMInfo->atmPrivMap = intern_atom(pWMInfo->conn, WINDOWSWM_NATIVE_HWND); 14911b5d61b8Smrg pWMInfo->atmUtf8String = intern_atom(pWMInfo->conn, "UTF8_STRING"); 14921b5d61b8Smrg pWMInfo->atmNetWmName = intern_atom(pWMInfo->conn, "_NET_WM_NAME"); 14931b5d61b8Smrg 14941b5d61b8Smrg /* Initialization for the xcb_ewmh and EWMH atoms */ 14951b5d61b8Smrg { 14961b5d61b8Smrg xcb_intern_atom_cookie_t *atoms_cookie; 14971b5d61b8Smrg atoms_cookie = xcb_ewmh_init_atoms(pWMInfo->conn, &pWMInfo->ewmh); 14981b5d61b8Smrg if (xcb_ewmh_init_atoms_replies(&pWMInfo->ewmh, atoms_cookie, NULL)) { 14991b5d61b8Smrg /* Set the _NET_SUPPORTED atom for this context. 15001b5d61b8Smrg 15011b5d61b8Smrg TODO: Audit to ensure we implement everything defined as MUSTs 15021b5d61b8Smrg for window managers in the EWMH standard.*/ 15031b5d61b8Smrg xcb_atom_t supported[] = 15041b5d61b8Smrg { 15051b5d61b8Smrg pWMInfo->ewmh.WM_PROTOCOLS, 15061b5d61b8Smrg pWMInfo->ewmh._NET_SUPPORTED, 15071b5d61b8Smrg pWMInfo->ewmh._NET_SUPPORTING_WM_CHECK, 15081b5d61b8Smrg pWMInfo->ewmh._NET_CLOSE_WINDOW, 15091b5d61b8Smrg pWMInfo->ewmh._NET_WM_WINDOW_TYPE, 15101b5d61b8Smrg pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK, 15111b5d61b8Smrg pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH, 15121b5d61b8Smrg pWMInfo->ewmh._NET_WM_STATE, 15131b5d61b8Smrg pWMInfo->ewmh._NET_WM_STATE_HIDDEN, 15141b5d61b8Smrg pWMInfo->ewmh._NET_WM_STATE_ABOVE, 15151b5d61b8Smrg pWMInfo->ewmh._NET_WM_STATE_BELOW, 15161b5d61b8Smrg pWMInfo->ewmh._NET_WM_STATE_SKIP_TASKBAR, 15171b5d61b8Smrg }; 15181b5d61b8Smrg 15191b5d61b8Smrg xcb_ewmh_set_supported(&pWMInfo->ewmh, pProcArg->dwScreen, 15201b5d61b8Smrg ARRAY_SIZE(supported), supported); 15211b5d61b8Smrg } 15221b5d61b8Smrg else { 15231b5d61b8Smrg ErrorF("winInitMultiWindowWM - xcb_ewmh_init_atoms() failed\n"); 152435c4bbdfSmrg } 152505b261ecSmrg } 152605b261ecSmrg 15271b5d61b8Smrg /* 15281b5d61b8Smrg Set the root window cursor to left_ptr (this controls the cursor an 15291b5d61b8Smrg application gets over it's windows when it doesn't set one) 15301b5d61b8Smrg */ 15311b5d61b8Smrg { 15321b5d61b8Smrg#define XC_left_ptr 68 15331b5d61b8Smrg xcb_cursor_t cursor = xcb_generate_id(pWMInfo->conn); 15341b5d61b8Smrg xcb_font_t font = xcb_generate_id(pWMInfo->conn); 15351b5d61b8Smrg xcb_font_t *mask_font = &font; /* An alias to clarify */ 15361b5d61b8Smrg int shape = XC_left_ptr; 15371b5d61b8Smrg uint32_t mask = XCB_CW_CURSOR; 15381b5d61b8Smrg uint32_t value_list = cursor; 153905b261ecSmrg 15401b5d61b8Smrg xcb_screen_t *root_screen = xcb_aux_get_screen(pWMInfo->conn, pProcArg->dwScreen); 15411b5d61b8Smrg xcb_window_t window = root_screen->root; 154235c4bbdfSmrg 15431b5d61b8Smrg static const uint16_t fgred = 0, fggreen = 0, fgblue = 0; 15441b5d61b8Smrg static const uint16_t bgred = 0xFFFF, bggreen = 0xFFFF, bgblue = 0xFFFF; 154505b261ecSmrg 15461b5d61b8Smrg xcb_open_font(pWMInfo->conn, font, sizeof("cursor"), "cursor"); 154705b261ecSmrg 15481b5d61b8Smrg xcb_create_glyph_cursor(pWMInfo->conn, cursor, font, *mask_font, 15491b5d61b8Smrg shape, shape + 1, 15501b5d61b8Smrg fgred, fggreen, fgblue, bgred, bggreen, bgblue); 155105b261ecSmrg 15521b5d61b8Smrg xcb_change_window_attributes(pWMInfo->conn, window, mask, &value_list); 155305b261ecSmrg 15541b5d61b8Smrg xcb_free_cursor(pWMInfo->conn, cursor); 15551b5d61b8Smrg xcb_close_font(pWMInfo->conn, font); 155635c4bbdfSmrg } 155735c4bbdfSmrg} 155805b261ecSmrg 155905b261ecSmrg/* 15601b5d61b8Smrg * winSendMessageToWM - Send a message from the X thread to the WM thread 156105b261ecSmrg */ 156205b261ecSmrg 15631b5d61b8Smrgvoid 15641b5d61b8SmrgwinSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg) 156505b261ecSmrg{ 15661b5d61b8Smrg WMMsgNodePtr pNode; 156735c4bbdfSmrg 15686747b715Smrg#if CYGMULTIWINDOW_DEBUG 15691b5d61b8Smrg ErrorF("winSendMessageToWM %s\n", MessageName(pMsg)); 15706747b715Smrg#endif 157105b261ecSmrg 15721b5d61b8Smrg pNode = malloc(sizeof(WMMsgNodeRec)); 15731b5d61b8Smrg if (pNode != NULL) { 15741b5d61b8Smrg memcpy(&pNode->msg, pMsg, sizeof(winWMMessageRec)); 15751b5d61b8Smrg PushMessage(&((WMInfoPtr) pWMInfo)->wmMsgQueue, pNode); 157635c4bbdfSmrg } 157705b261ecSmrg} 157805b261ecSmrg 157905b261ecSmrg/* 158005b261ecSmrg * Check if another window manager is running 158105b261ecSmrg */ 158205b261ecSmrg 158305b261ecSmrgstatic Bool 15841b5d61b8SmrgCheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen) 158505b261ecSmrg{ 15861b5d61b8Smrg Bool redirectError = FALSE; 15871b5d61b8Smrg 15881b5d61b8Smrg /* Get root window id */ 15891b5d61b8Smrg xcb_screen_t *root_screen = xcb_aux_get_screen(conn, dwScreen); 15901b5d61b8Smrg xcb_window_t root_window_id = root_screen->root; 15911b5d61b8Smrg 159235c4bbdfSmrg /* 159335c4bbdfSmrg Try to select the events which only one client at a time is allowed to select. 159435c4bbdfSmrg If this causes an error, another window manager is already running... 159535c4bbdfSmrg */ 15961b5d61b8Smrg const static uint32_t test_mask[] = { XCB_EVENT_MASK_RESIZE_REDIRECT | 15971b5d61b8Smrg XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | 15981b5d61b8Smrg XCB_EVENT_MASK_BUTTON_PRESS }; 15991b5d61b8Smrg 16001b5d61b8Smrg xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(conn, 16011b5d61b8Smrg root_window_id, 16021b5d61b8Smrg XCB_CW_EVENT_MASK, 16031b5d61b8Smrg test_mask); 16041b5d61b8Smrg xcb_generic_error_t *error; 16051b5d61b8Smrg if ((error = xcb_request_check(conn, cookie))) 16061b5d61b8Smrg { 16071b5d61b8Smrg redirectError = TRUE; 16081b5d61b8Smrg free(error); 16091b5d61b8Smrg } 161035c4bbdfSmrg 161135c4bbdfSmrg /* 161235c4bbdfSmrg Side effect: select the events we are actually interested in... 161335c4bbdfSmrg 16141b5d61b8Smrg Other WMs are not allowed, also select one of the events which only one client 161535c4bbdfSmrg at a time is allowed to select, so other window managers won't start... 161635c4bbdfSmrg */ 16171b5d61b8Smrg { 16181b5d61b8Smrg const uint32_t mask[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | 16191b5d61b8Smrg XCB_EVENT_MASK_BUTTON_PRESS }; 16201b5d61b8Smrg 16211b5d61b8Smrg xcb_change_window_attributes(conn, root_window_id, XCB_CW_EVENT_MASK, mask); 16221b5d61b8Smrg } 16231b5d61b8Smrg 162435c4bbdfSmrg return redirectError; 162505b261ecSmrg} 162605b261ecSmrg 162705b261ecSmrg/* 162805b261ecSmrg * Notify the MWM thread we're exiting and not to reconnect 162905b261ecSmrg */ 163005b261ecSmrg 163105b261ecSmrgvoid 163235c4bbdfSmrgwinDeinitMultiWindowWM(void) 163305b261ecSmrg{ 163435c4bbdfSmrg ErrorF("winDeinitMultiWindowWM - Noting shutdown in progress\n"); 163535c4bbdfSmrg g_shutdown = TRUE; 163605b261ecSmrg} 16376747b715Smrg 16386747b715Smrg/* Windows window styles */ 163935c4bbdfSmrg#define HINT_NOFRAME (1L<<0) 16406747b715Smrg#define HINT_BORDER (1L<<1) 164135c4bbdfSmrg#define HINT_SIZEBOX (1L<<2) 164235c4bbdfSmrg#define HINT_CAPTION (1L<<3) 16436747b715Smrg#define HINT_NOMAXIMIZE (1L<<4) 164435c4bbdfSmrg#define HINT_NOMINIMIZE (1L<<5) 164535c4bbdfSmrg#define HINT_NOSYSMENU (1L<<6) 164635c4bbdfSmrg#define HINT_SKIPTASKBAR (1L<<7) 16476747b715Smrg/* These two are used on their own */ 16486747b715Smrg#define HINT_MAX (1L<<0) 16496747b715Smrg#define HINT_MIN (1L<<1) 16506747b715Smrg 16516747b715Smrgstatic void 16521b5d61b8SmrgwinApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle) 16536747b715Smrg{ 16541b5d61b8Smrg 16551b5d61b8Smrg xcb_connection_t *conn = pWMInfo->conn; 16561b5d61b8Smrg static xcb_atom_t windowState, motif_wm_hints; 16571b5d61b8Smrg static xcb_atom_t hiddenState, fullscreenState, belowState, aboveState, 165835c4bbdfSmrg skiptaskbarState; 16591b5d61b8Smrg static xcb_atom_t splashType; 166035c4bbdfSmrg static int generation; 16611b5d61b8Smrg 16621b5d61b8Smrg unsigned long hint = 0, maxmin = 0; 166335c4bbdfSmrg unsigned long style, exStyle; 166435c4bbdfSmrg 166535c4bbdfSmrg if (!hWnd) 166635c4bbdfSmrg return; 166735c4bbdfSmrg if (!IsWindow(hWnd)) 166835c4bbdfSmrg return; 166935c4bbdfSmrg 167035c4bbdfSmrg if (generation != serverGeneration) { 167135c4bbdfSmrg generation = serverGeneration; 16721b5d61b8Smrg windowState = intern_atom(conn, "_NET_WM_STATE"); 16731b5d61b8Smrg motif_wm_hints = intern_atom(conn, "_MOTIF_WM_HINTS"); 16741b5d61b8Smrg hiddenState = intern_atom(conn, "_NET_WM_STATE_HIDDEN"); 16751b5d61b8Smrg fullscreenState = intern_atom(conn, "_NET_WM_STATE_FULLSCREEN"); 16761b5d61b8Smrg belowState = intern_atom(conn, "_NET_WM_STATE_BELOW"); 16771b5d61b8Smrg aboveState = intern_atom(conn, "_NET_WM_STATE_ABOVE"); 16781b5d61b8Smrg skiptaskbarState = intern_atom(conn, "_NET_WM_STATE_SKIP_TASKBAR"); 16791b5d61b8Smrg splashType = intern_atom(conn, "_NET_WM_WINDOW_TYPE_SPLASHSCREEN"); 168035c4bbdfSmrg } 16816747b715Smrg 16821b5d61b8Smrg { 16831b5d61b8Smrg xcb_get_property_cookie_t cookie_wm_state = xcb_get_property(conn, FALSE, iWindow, windowState, XCB_ATOM_ATOM, 0L, INT_MAX); 16841b5d61b8Smrg xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie_wm_state, NULL); 16851b5d61b8Smrg if (reply) { 16861b5d61b8Smrg int i; 16871b5d61b8Smrg int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t); 16881b5d61b8Smrg xcb_atom_t *pAtom = xcb_get_property_value(reply); 168935c4bbdfSmrg 169035c4bbdfSmrg for (i = 0; i < nitems; i++) { 169135c4bbdfSmrg if (pAtom[i] == skiptaskbarState) 169235c4bbdfSmrg hint |= HINT_SKIPTASKBAR; 169335c4bbdfSmrg if (pAtom[i] == hiddenState) 169435c4bbdfSmrg maxmin |= HINT_MIN; 169535c4bbdfSmrg else if (pAtom[i] == fullscreenState) 169635c4bbdfSmrg maxmin |= HINT_MAX; 169735c4bbdfSmrg if (pAtom[i] == belowState) 169835c4bbdfSmrg *zstyle = HWND_BOTTOM; 169935c4bbdfSmrg else if (pAtom[i] == aboveState) 170035c4bbdfSmrg *zstyle = HWND_TOPMOST; 170135c4bbdfSmrg } 170235c4bbdfSmrg 17031b5d61b8Smrg free(reply); 17041b5d61b8Smrg } 17056747b715Smrg } 17066747b715Smrg 17071b5d61b8Smrg { 17081b5d61b8Smrg xcb_get_property_cookie_t cookie_mwm_hint = xcb_get_property(conn, FALSE, iWindow, motif_wm_hints, motif_wm_hints, 0L, sizeof(MwmHints)); 17091b5d61b8Smrg xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie_mwm_hint, NULL); 17101b5d61b8Smrg if (reply) { 17111b5d61b8Smrg int nitems = xcb_get_property_value_length(reply)/4; 17121b5d61b8Smrg MwmHints *mwm_hint = xcb_get_property_value(reply); 17131b5d61b8Smrg if (mwm_hint && (nitems >= PropMwmHintsElements) && 171435c4bbdfSmrg (mwm_hint->flags & MwmHintsDecorations)) { 171535c4bbdfSmrg if (!mwm_hint->decorations) 171635c4bbdfSmrg hint |= (HINT_NOFRAME | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE); 171735c4bbdfSmrg else if (!(mwm_hint->decorations & MwmDecorAll)) { 171835c4bbdfSmrg if (mwm_hint->decorations & MwmDecorBorder) 171935c4bbdfSmrg hint |= HINT_BORDER; 172035c4bbdfSmrg if (mwm_hint->decorations & MwmDecorHandle) 172135c4bbdfSmrg hint |= HINT_SIZEBOX; 172235c4bbdfSmrg if (mwm_hint->decorations & MwmDecorTitle) 172335c4bbdfSmrg hint |= HINT_CAPTION; 172435c4bbdfSmrg if (!(mwm_hint->decorations & MwmDecorMenu)) 172535c4bbdfSmrg hint |= HINT_NOSYSMENU; 172635c4bbdfSmrg if (!(mwm_hint->decorations & MwmDecorMinimize)) 172735c4bbdfSmrg hint |= HINT_NOMINIMIZE; 172835c4bbdfSmrg if (!(mwm_hint->decorations & MwmDecorMaximize)) 172935c4bbdfSmrg hint |= HINT_NOMAXIMIZE; 173035c4bbdfSmrg } 173135c4bbdfSmrg else { 173235c4bbdfSmrg /* 173335c4bbdfSmrg MwmDecorAll means all decorations *except* those specified by other flag 173435c4bbdfSmrg bits that are set. Not yet implemented. 173535c4bbdfSmrg */ 173635c4bbdfSmrg } 173735c4bbdfSmrg } 17381b5d61b8Smrg free(reply); 17391b5d61b8Smrg } 174035c4bbdfSmrg } 174135c4bbdfSmrg 17421b5d61b8Smrg { 17431b5d61b8Smrg int i; 17441b5d61b8Smrg xcb_ewmh_get_atoms_reply_t type; 17451b5d61b8Smrg xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_window_type(&pWMInfo->ewmh, iWindow); 17461b5d61b8Smrg if (xcb_ewmh_get_wm_window_type_reply(&pWMInfo->ewmh, cookie, &type, NULL)) { 17471b5d61b8Smrg for (i = 0; i < type.atoms_len; i++) { 17481b5d61b8Smrg if (type.atoms[i] == pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK) { 174935c4bbdfSmrg hint = (hint & ~HINT_NOFRAME) | HINT_SKIPTASKBAR | HINT_SIZEBOX; 175035c4bbdfSmrg *zstyle = HWND_TOPMOST; 175135c4bbdfSmrg } 17521b5d61b8Smrg else if ((type.atoms[i] == pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH) 17531b5d61b8Smrg || (type.atoms[i] == splashType)) { 17541b5d61b8Smrg hint |= (HINT_SKIPTASKBAR | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE); 17551b5d61b8Smrg *zstyle = HWND_TOPMOST; 17561b5d61b8Smrg } 175735c4bbdfSmrg } 17581b5d61b8Smrg } 17596747b715Smrg } 17606747b715Smrg 17616747b715Smrg { 17621b5d61b8Smrg xcb_size_hints_t size_hints; 17631b5d61b8Smrg xcb_get_property_cookie_t cookie; 17641b5d61b8Smrg 17651b5d61b8Smrg cookie = xcb_icccm_get_wm_normal_hints(conn, iWindow); 17661b5d61b8Smrg if (xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &size_hints, NULL)) { 17671b5d61b8Smrg if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) { 176835c4bbdfSmrg 17691b5d61b8Smrg /* Not maximizable if a maximum size is specified, and that size 17701b5d61b8Smrg is smaller (in either dimension) than the screen size */ 17711b5d61b8Smrg if ((size_hints.max_width < GetSystemMetrics(SM_CXVIRTUALSCREEN)) 17721b5d61b8Smrg || (size_hints.max_height < GetSystemMetrics(SM_CYVIRTUALSCREEN))) 17731b5d61b8Smrg hint |= HINT_NOMAXIMIZE; 177435c4bbdfSmrg 17751b5d61b8Smrg if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { 177635c4bbdfSmrg /* 177735c4bbdfSmrg If both minimum size and maximum size are specified and are the same, 177835c4bbdfSmrg don't bother with a resizing frame 177935c4bbdfSmrg */ 17801b5d61b8Smrg if ((size_hints.min_width == size_hints.max_width) 17811b5d61b8Smrg && (size_hints.min_height == size_hints.max_height)) 178235c4bbdfSmrg hint = (hint & ~HINT_SIZEBOX); 178335c4bbdfSmrg } 178435c4bbdfSmrg } 178535c4bbdfSmrg } 17866747b715Smrg } 17876747b715Smrg 178835c4bbdfSmrg /* 178935c4bbdfSmrg Override hint settings from above with settings from config file and set 179035c4bbdfSmrg application id for grouping. 179135c4bbdfSmrg */ 179235c4bbdfSmrg { 179335c4bbdfSmrg char *application_id = 0; 17941b5d61b8Smrg char *window_name = 0; 17951b5d61b8Smrg char *res_name = 0; 17961b5d61b8Smrg char *res_class = 0; 179735c4bbdfSmrg 17981b5d61b8Smrg GetClassNames(pWMInfo, iWindow, &res_name, &res_class, &window_name); 179935c4bbdfSmrg 18001b5d61b8Smrg style = STYLE_NONE; 18011b5d61b8Smrg style = winOverrideStyle(res_name, res_class, window_name); 180235c4bbdfSmrg 180335c4bbdfSmrg#define APPLICATION_ID_FORMAT "%s.xwin.%s" 180435c4bbdfSmrg#define APPLICATION_ID_UNKNOWN "unknown" 18051b5d61b8Smrg if (res_class) { 18061b5d61b8Smrg asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME, 18071b5d61b8Smrg res_class); 180835c4bbdfSmrg } 180935c4bbdfSmrg else { 18101b5d61b8Smrg asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME, 18111b5d61b8Smrg APPLICATION_ID_UNKNOWN); 181235c4bbdfSmrg } 18131b5d61b8Smrg winSetAppUserModelID(hWnd, application_id); 18141b5d61b8Smrg 18151b5d61b8Smrg free(application_id); 18161b5d61b8Smrg free(res_name); 18171b5d61b8Smrg free(res_class); 18181b5d61b8Smrg free(window_name); 181935c4bbdfSmrg } 18206747b715Smrg 182135c4bbdfSmrg if (style & STYLE_TOPMOST) 182235c4bbdfSmrg *zstyle = HWND_TOPMOST; 182335c4bbdfSmrg else if (style & STYLE_MAXIMIZE) 182435c4bbdfSmrg maxmin = (hint & ~HINT_MIN) | HINT_MAX; 182535c4bbdfSmrg else if (style & STYLE_MINIMIZE) 182635c4bbdfSmrg maxmin = (hint & ~HINT_MAX) | HINT_MIN; 182735c4bbdfSmrg else if (style & STYLE_BOTTOM) 182835c4bbdfSmrg *zstyle = HWND_BOTTOM; 182935c4bbdfSmrg 183035c4bbdfSmrg if (maxmin & HINT_MAX) 183135c4bbdfSmrg SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0); 183235c4bbdfSmrg else if (maxmin & HINT_MIN) 183335c4bbdfSmrg SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); 183435c4bbdfSmrg 183535c4bbdfSmrg if (style & STYLE_NOTITLE) 183635c4bbdfSmrg hint = 183735c4bbdfSmrg (hint & ~HINT_NOFRAME & ~HINT_BORDER & ~HINT_CAPTION) | 183835c4bbdfSmrg HINT_SIZEBOX; 183935c4bbdfSmrg else if (style & STYLE_OUTLINE) 184035c4bbdfSmrg hint = 184135c4bbdfSmrg (hint & ~HINT_NOFRAME & ~HINT_SIZEBOX & ~HINT_CAPTION) | 184235c4bbdfSmrg HINT_BORDER; 184335c4bbdfSmrg else if (style & STYLE_NOFRAME) 184435c4bbdfSmrg hint = 184535c4bbdfSmrg (hint & ~HINT_BORDER & ~HINT_CAPTION & ~HINT_SIZEBOX) | 184635c4bbdfSmrg HINT_NOFRAME; 184735c4bbdfSmrg 184835c4bbdfSmrg /* Now apply styles to window */ 184935c4bbdfSmrg style = GetWindowLongPtr(hWnd, GWL_STYLE); 185035c4bbdfSmrg if (!style) 185135c4bbdfSmrg return; /* GetWindowLongPointer returns 0 on failure, we hope this isn't a valid style */ 185235c4bbdfSmrg 185335c4bbdfSmrg style &= ~WS_CAPTION & ~WS_SIZEBOX; /* Just in case */ 185435c4bbdfSmrg 185535c4bbdfSmrg if (!(hint & ~HINT_SKIPTASKBAR)) /* No hints, default */ 185635c4bbdfSmrg style = style | WS_CAPTION | WS_SIZEBOX; 185735c4bbdfSmrg else if (hint & HINT_NOFRAME) /* No frame, no decorations */ 185835c4bbdfSmrg style = style & ~WS_CAPTION & ~WS_SIZEBOX; 185935c4bbdfSmrg else 186035c4bbdfSmrg style = style | ((hint & HINT_BORDER) ? WS_BORDER : 0) | 186135c4bbdfSmrg ((hint & HINT_SIZEBOX) ? WS_SIZEBOX : 0) | 186235c4bbdfSmrg ((hint & HINT_CAPTION) ? WS_CAPTION : 0); 186335c4bbdfSmrg 186435c4bbdfSmrg if (hint & HINT_NOMAXIMIZE) 186535c4bbdfSmrg style = style & ~WS_MAXIMIZEBOX; 186635c4bbdfSmrg 186735c4bbdfSmrg if (hint & HINT_NOMINIMIZE) 186835c4bbdfSmrg style = style & ~WS_MINIMIZEBOX; 186935c4bbdfSmrg 187035c4bbdfSmrg if (hint & HINT_NOSYSMENU) 187135c4bbdfSmrg style = style & ~WS_SYSMENU; 187235c4bbdfSmrg 187335c4bbdfSmrg if (hint & HINT_SKIPTASKBAR) 187435c4bbdfSmrg style = style & ~WS_MINIMIZEBOX; /* window will become lost if minimized */ 187535c4bbdfSmrg 187635c4bbdfSmrg SetWindowLongPtr(hWnd, GWL_STYLE, style); 187735c4bbdfSmrg 187835c4bbdfSmrg exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE); 187935c4bbdfSmrg if (hint & HINT_SKIPTASKBAR) 188035c4bbdfSmrg exStyle = (exStyle & ~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW; 188135c4bbdfSmrg else 188235c4bbdfSmrg exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW; 188335c4bbdfSmrg SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle); 188435c4bbdfSmrg 188535c4bbdfSmrg winDebug 188635c4bbdfSmrg ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n", 188735c4bbdfSmrg iWindow, hint, style, exStyle); 18886747b715Smrg} 18896747b715Smrg 18906747b715Smrgvoid 189135c4bbdfSmrgwinUpdateWindowPosition(HWND hWnd, HWND * zstyle) 18926747b715Smrg{ 189335c4bbdfSmrg int iX, iY, iWidth, iHeight; 189435c4bbdfSmrg int iDx, iDy; 189535c4bbdfSmrg RECT rcNew; 189635c4bbdfSmrg WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP); 189735c4bbdfSmrg DrawablePtr pDraw = NULL; 189835c4bbdfSmrg 189935c4bbdfSmrg if (!pWin) 190035c4bbdfSmrg return; 190135c4bbdfSmrg pDraw = &pWin->drawable; 190235c4bbdfSmrg if (!pDraw) 190335c4bbdfSmrg return; 190435c4bbdfSmrg 190535c4bbdfSmrg /* Get the X and Y location of the X window */ 190635c4bbdfSmrg iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN); 190735c4bbdfSmrg iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN); 190835c4bbdfSmrg 190935c4bbdfSmrg /* Get the height and width of the X window */ 191035c4bbdfSmrg iWidth = pWin->drawable.width; 191135c4bbdfSmrg iHeight = pWin->drawable.height; 191235c4bbdfSmrg 191335c4bbdfSmrg /* Setup a rectangle with the X window position and size */ 191435c4bbdfSmrg SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight); 191535c4bbdfSmrg 191635c4bbdfSmrg winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n", 191735c4bbdfSmrg rcNew.left, rcNew.top, rcNew.right, rcNew.bottom); 191835c4bbdfSmrg 191935c4bbdfSmrg AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE, 192035c4bbdfSmrg GetWindowLongPtr(hWnd, GWL_EXSTYLE)); 192135c4bbdfSmrg 192235c4bbdfSmrg /* Don't allow window decoration to disappear off to top-left as a result of this adjustment */ 192335c4bbdfSmrg if (rcNew.left < GetSystemMetrics(SM_XVIRTUALSCREEN)) { 192435c4bbdfSmrg iDx = GetSystemMetrics(SM_XVIRTUALSCREEN) - rcNew.left; 192535c4bbdfSmrg rcNew.left += iDx; 192635c4bbdfSmrg rcNew.right += iDx; 19276747b715Smrg } 19286747b715Smrg 192935c4bbdfSmrg if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) { 193035c4bbdfSmrg iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top; 193135c4bbdfSmrg rcNew.top += iDy; 193235c4bbdfSmrg rcNew.bottom += iDy; 19336747b715Smrg } 19346747b715Smrg 193535c4bbdfSmrg winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n", 193635c4bbdfSmrg rcNew.left, rcNew.top, rcNew.right, rcNew.bottom); 19376747b715Smrg 193835c4bbdfSmrg /* Position the Windows window */ 193935c4bbdfSmrg SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top, 194035c4bbdfSmrg rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0); 19416747b715Smrg 19426747b715Smrg} 1943