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 76extern void winDebug(const char *format, ...); 77extern void winReshapeMultiWindow(WindowPtr pWin); 78extern 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 98typedef struct _WMMsgNodeRec { 99 winWMMessageRec msg; 100 struct _WMMsgNodeRec *pNext; 101} WMMsgNodeRec, *WMMsgNodePtr; 102 103typedef struct _WMMsgQueueRec { 104 struct _WMMsgNodeRec *pHead; 105 struct _WMMsgNodeRec *pTail; 106 pthread_mutex_t pmMutex; 107 pthread_cond_t pcNotEmpty; 108} WMMsgQueueRec, *WMMsgQueuePtr; 109 110typedef 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 126typedef struct _WMProcArgRec { 127 DWORD dwScreen; 128 WMInfoPtr pWMInfo; 129 pthread_mutex_t *ppmServerStarted; 130} WMProcArgRec, *WMProcArgPtr; 131 132typedef 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 144static void 145 PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode); 146 147static WMMsgNodePtr PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo); 148 149static Bool 150 InitQueue(WMMsgQueuePtr pQueue); 151 152static void 153 GetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName); 154 155static void 156 SendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData); 157 158static void 159 UpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow); 160 161static void *winMultiWindowWMProc(void *pArg); 162 163static void *winMultiWindowXMsgProc(void *pArg); 164 165static void 166 winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg); 167 168#if 0 169static void 170 PreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction); 171#endif 172 173static Bool 174CheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen); 175 176static void 177 winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle); 178 179void 180 winUpdateWindowPosition(HWND hWnd, HWND * zstyle); 181 182/* 183 * Local globals 184 */ 185 186static Bool g_shutdown = FALSE; 187 188/* 189 * Translate msg id to text, for debug purposes 190 */ 191 192#if CYGMULTIWINDOW_DEBUG 193static const char * 194MessageName(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 249static void 250PushMessage(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 278static WMMsgNodePtr 279PopMessage(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 311static Bool 312HaveMessage(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 329static 330 Bool 331InitQueue(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 358static 359char * 360Xutf8TextPropertyToString(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 383static void 384GetWindowName(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 480static Bool 481IsWmProtocolAvailable(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 505static void 506SendXMessage(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 */ 526static HWND 527getHwnd(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 */ 559static Bool 560IsOverrideRedirect(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*/ 582static void 583GetClassNames(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 617static void 618UpdateName(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 655static void 656UpdateIcon(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 686static void 687UpdateStyle(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 726static void 727UpdateState(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 */ 745static void 746PreserveWin32Stack(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 785static void * 786winMultiWindowWMProc(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 1011static xcb_atom_t 1012intern_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 1031static void * 1032winMultiWindowXMsgProc(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 1391Bool 1392winInitWM(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 1460static void 1461winInitMultiWindowWM(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 1634void 1635winSendMessageToWM(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 1654static Bool 1655CheckAnotherWindowManager(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 1702void 1703winDeinitMultiWindowWM(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 1722static void 1723winApplyHints(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 1961void 1962winUpdateWindowPosition(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} 2014