1/* 2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 3 *Copyright (C) Colin Harrison 2005-2008 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 * Earle F. Philhower, III 31 * Harold L Hunt II 32 * Colin Harrison 33 */ 34 35#ifdef HAVE_XWIN_CONFIG_H 36#include <xwin-config.h> 37#endif 38#include "win.h" 39#include "dixevents.h" 40#include "winmultiwindowclass.h" 41#include "winprefs.h" 42#include "winmsg.h" 43#include "inputstr.h" 44 45extern void winUpdateWindowPosition (HWND hWnd, Bool reshape, HWND *zstyle); 46 47 48/* 49 * Local globals 50 */ 51 52static UINT_PTR g_uipMousePollingTimerID = 0; 53 54 55/* 56 * Constant defines 57 */ 58 59#define WIN_MULTIWINDOW_SHAPE YES 60 61 62/* 63 * ConstrainSize - Taken from TWM sources - Respects hints for sizing 64 */ 65#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) ) 66static void 67ConstrainSize (WinXSizeHints hints, int *widthp, int *heightp) 68{ 69 int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta; 70 int baseWidth, baseHeight; 71 int dwidth = *widthp, dheight = *heightp; 72 73 if (hints.flags & PMinSize) 74 { 75 minWidth = hints.min_width; 76 minHeight = hints.min_height; 77 } 78 else if (hints.flags & PBaseSize) 79 { 80 minWidth = hints.base_width; 81 minHeight = hints.base_height; 82 } 83 else 84 minWidth = minHeight = 1; 85 86 if (hints.flags & PBaseSize) 87 { 88 baseWidth = hints.base_width; 89 baseHeight = hints.base_height; 90 } 91 else if (hints.flags & PMinSize) 92 { 93 baseWidth = hints.min_width; 94 baseHeight = hints.min_height; 95 } 96 else 97 baseWidth = baseHeight = 0; 98 99 if (hints.flags & PMaxSize) 100 { 101 maxWidth = hints.max_width; 102 maxHeight = hints.max_height; 103 } 104 else 105 { 106 maxWidth = MAXINT; 107 maxHeight = MAXINT; 108 } 109 110 if (hints.flags & PResizeInc) 111 { 112 xinc = hints.width_inc; 113 yinc = hints.height_inc; 114 } 115 else 116 xinc = yinc = 1; 117 118 /* 119 * First, clamp to min and max values 120 */ 121 if (dwidth < minWidth) 122 dwidth = minWidth; 123 if (dheight < minHeight) 124 dheight = minHeight; 125 126 if (dwidth > maxWidth) 127 dwidth = maxWidth; 128 if (dheight > maxHeight) 129 dheight = maxHeight; 130 131 /* 132 * Second, fit to base + N * inc 133 */ 134 dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth; 135 dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight; 136 137 /* 138 * Third, adjust for aspect ratio 139 */ 140 141 /* 142 * The math looks like this: 143 * 144 * minAspectX dwidth maxAspectX 145 * ---------- <= ------- <= ---------- 146 * minAspectY dheight maxAspectY 147 * 148 * If that is multiplied out, then the width and height are 149 * invalid in the following situations: 150 * 151 * minAspectX * dheight > minAspectY * dwidth 152 * maxAspectX * dheight < maxAspectY * dwidth 153 * 154 */ 155 156 if (hints.flags & PAspect) 157 { 158 if (hints.min_aspect.x * dheight > hints.min_aspect.y * dwidth) 159 { 160 delta = makemult(hints.min_aspect.x * dheight / hints.min_aspect.y - dwidth, xinc); 161 if (dwidth + delta <= maxWidth) 162 dwidth += delta; 163 else 164 { 165 delta = makemult(dheight - dwidth*hints.min_aspect.y/hints.min_aspect.x, yinc); 166 if (dheight - delta >= minHeight) 167 dheight -= delta; 168 } 169 } 170 171 if (hints.max_aspect.x * dheight < hints.max_aspect.y * dwidth) 172 { 173 delta = makemult(dwidth * hints.max_aspect.y / hints.max_aspect.x - dheight, yinc); 174 if (dheight + delta <= maxHeight) 175 dheight += delta; 176 else 177 { 178 delta = makemult(dwidth - hints.max_aspect.x*dheight/hints.max_aspect.y, xinc); 179 if (dwidth - delta >= minWidth) 180 dwidth -= delta; 181 } 182 } 183 } 184 185 /* Return computed values */ 186 *widthp = dwidth; 187 *heightp = dheight; 188} 189#undef makemult 190 191 192 193/* 194 * ValidateSizing - Ensures size request respects hints 195 */ 196static int 197ValidateSizing (HWND hwnd, WindowPtr pWin, 198 WPARAM wParam, LPARAM lParam) 199{ 200 WinXSizeHints sizeHints; 201 RECT *rect; 202 int iWidth, iHeight; 203 RECT rcClient, rcWindow; 204 int iBorderWidthX, iBorderWidthY; 205 206 /* Invalid input checking */ 207 if (pWin==NULL || lParam==0) 208 return FALSE; 209 210 /* No size hints, no checking */ 211 if (!winMultiWindowGetWMNormalHints (pWin, &sizeHints)) 212 return FALSE; 213 214 /* Avoid divide-by-zero */ 215 if (sizeHints.flags & PResizeInc) 216 { 217 if (sizeHints.width_inc == 0) sizeHints.width_inc = 1; 218 if (sizeHints.height_inc == 0) sizeHints.height_inc = 1; 219 } 220 221 rect = (RECT*)lParam; 222 223 iWidth = rect->right - rect->left; 224 iHeight = rect->bottom - rect->top; 225 226 /* Now remove size of any borders and title bar */ 227 GetClientRect(hwnd, &rcClient); 228 GetWindowRect(hwnd, &rcWindow); 229 iBorderWidthX = (rcWindow.right - rcWindow.left) - (rcClient.right - rcClient.left); 230 iBorderWidthY = (rcWindow.bottom - rcWindow.top) - (rcClient.bottom - rcClient.top); 231 iWidth -= iBorderWidthX; 232 iHeight -= iBorderWidthY; 233 234 /* Constrain the size to legal values */ 235 ConstrainSize (sizeHints, &iWidth, &iHeight); 236 237 /* Add back the size of borders and title bar */ 238 iWidth += iBorderWidthX; 239 iHeight += iBorderWidthY; 240 241 /* Adjust size according to where we're dragging from */ 242 switch(wParam) { 243 case WMSZ_TOP: 244 case WMSZ_TOPRIGHT: 245 case WMSZ_BOTTOM: 246 case WMSZ_BOTTOMRIGHT: 247 case WMSZ_RIGHT: 248 rect->right = rect->left + iWidth; 249 break; 250 default: 251 rect->left = rect->right - iWidth; 252 break; 253 } 254 switch(wParam) { 255 case WMSZ_BOTTOM: 256 case WMSZ_BOTTOMRIGHT: 257 case WMSZ_BOTTOMLEFT: 258 case WMSZ_RIGHT: 259 case WMSZ_LEFT: 260 rect->bottom = rect->top + iHeight; 261 break; 262 default: 263 rect->top = rect->bottom - iHeight; 264 break; 265 } 266 return TRUE; 267} 268 269extern Bool winInDestroyWindowsWindow; 270static Bool winInRaiseWindow = FALSE; 271static void winRaiseWindow(WindowPtr pWin) 272{ 273 if (!winInDestroyWindowsWindow && !winInRaiseWindow) 274 { 275 BOOL oldstate = winInRaiseWindow; 276 XID vlist[1] = { 0 }; 277 winInRaiseWindow = TRUE; 278 /* Call configure window directly to make sure it gets processed 279 * in time 280 */ 281 ConfigureWindow(pWin, CWStackMode, vlist, serverClient); 282 winInRaiseWindow = oldstate; 283 } 284} 285 286static 287void winStartMousePolling(winPrivScreenPtr s_pScreenPriv) 288{ 289 /* 290 * Timer to poll mouse position. This is needed to make 291 * programs like xeyes follow the mouse properly when the 292 * mouse pointer is outside of any X window. 293 */ 294 if (g_uipMousePollingTimerID == 0) 295 g_uipMousePollingTimerID = SetTimer (s_pScreenPriv->hwndScreen, 296 WIN_POLLING_MOUSE_TIMER_ID, 297 MOUSE_POLLING_INTERVAL, 298 NULL); 299} 300 301/* 302 * winTopLevelWindowProc - Window procedure for all top-level Windows windows. 303 */ 304 305LRESULT CALLBACK 306winTopLevelWindowProc (HWND hwnd, UINT message, 307 WPARAM wParam, LPARAM lParam) 308{ 309 POINT ptMouse; 310 HDC hdcUpdate; 311 PAINTSTRUCT ps; 312 WindowPtr pWin = NULL; 313 winPrivWinPtr pWinPriv = NULL; 314 ScreenPtr s_pScreen = NULL; 315 winPrivScreenPtr s_pScreenPriv = NULL; 316 winScreenInfo *s_pScreenInfo = NULL; 317 HWND hwndScreen = NULL; 318 DrawablePtr pDraw = NULL; 319 winWMMessageRec wmMsg; 320 Bool fWMMsgInitialized = FALSE; 321 static Bool s_fTracking = FALSE; 322 Bool needRestack = FALSE; 323 LRESULT ret; 324 325#if CYGDEBUG 326 winDebugWin32Message("winTopLevelWindowProc", hwnd, message, wParam, lParam); 327#endif 328 329 /* Check if the Windows window property for our X window pointer is valid */ 330 if ((pWin = GetProp (hwnd, WIN_WINDOW_PROP)) != NULL) 331 { 332 /* Our X window pointer is valid */ 333 334 /* Get pointers to the drawable and the screen */ 335 pDraw = &pWin->drawable; 336 s_pScreen = pWin->drawable.pScreen; 337 338 /* Get a pointer to our window privates */ 339 pWinPriv = winGetWindowPriv(pWin); 340 341 /* Get pointers to our screen privates and screen info */ 342 s_pScreenPriv = pWinPriv->pScreenPriv; 343 s_pScreenInfo = s_pScreenPriv->pScreenInfo; 344 345 /* Get the handle for our screen-sized window */ 346 hwndScreen = s_pScreenPriv->hwndScreen; 347 348 /* */ 349 wmMsg.msg = 0; 350 wmMsg.hwndWindow = hwnd; 351 wmMsg.iWindow = (Window)GetProp (hwnd, WIN_WID_PROP); 352 353 wmMsg.iX = pDraw->x; 354 wmMsg.iY = pDraw->y; 355 wmMsg.iWidth = pDraw->width; 356 wmMsg.iHeight = pDraw->height; 357 358 fWMMsgInitialized = TRUE; 359 360#if 0 361 /* 362 * Print some debugging information 363 */ 364 365 ErrorF ("hWnd %08X\n", hwnd); 366 ErrorF ("pWin %08X\n", pWin); 367 ErrorF ("pDraw %08X\n", pDraw); 368 ErrorF ("\ttype %08X\n", pWin->drawable.type); 369 ErrorF ("\tclass %08X\n", pWin->drawable.class); 370 ErrorF ("\tdepth %08X\n", pWin->drawable.depth); 371 ErrorF ("\tbitsPerPixel %08X\n", pWin->drawable.bitsPerPixel); 372 ErrorF ("\tid %08X\n", pWin->drawable.id); 373 ErrorF ("\tx %08X\n", pWin->drawable.x); 374 ErrorF ("\ty %08X\n", pWin->drawable.y); 375 ErrorF ("\twidth %08X\n", pWin->drawable.width); 376 ErrorF ("\thenght %08X\n", pWin->drawable.height); 377 ErrorF ("\tpScreen %08X\n", pWin->drawable.pScreen); 378 ErrorF ("\tserialNumber %08X\n", pWin->drawable.serialNumber); 379 ErrorF ("g_iWindowPrivateKey %p\n", g_iWindowPrivateKey); 380 ErrorF ("pWinPriv %08X\n", pWinPriv); 381 ErrorF ("s_pScreenPriv %08X\n", s_pScreenPriv); 382 ErrorF ("s_pScreenInfo %08X\n", s_pScreenInfo); 383 ErrorF ("hwndScreen %08X\n", hwndScreen); 384#endif 385 } 386 387 /* Branch on message type */ 388 switch (message) 389 { 390 case WM_CREATE: 391 392 /* */ 393 SetProp (hwnd, 394 WIN_WINDOW_PROP, 395 (HANDLE)((LPCREATESTRUCT) lParam)->lpCreateParams); 396 397 /* */ 398 SetProp (hwnd, 399 WIN_WID_PROP, 400 (HANDLE)winGetWindowID (((LPCREATESTRUCT) lParam)->lpCreateParams)); 401 402 /* 403 * Make X windows' Z orders sync with Windows windows because 404 * there can be AlwaysOnTop windows overlapped on the window 405 * currently being created. 406 */ 407 winReorderWindowsMultiWindow (); 408 409 /* Fix a 'round title bar corner background should be transparent not black' problem when first painted */ 410 { 411 RECT rWindow; 412 HRGN hRgnWindow; 413 GetWindowRect(hwnd, &rWindow); 414 hRgnWindow = CreateRectRgnIndirect(&rWindow); 415 SetWindowRgn (hwnd, hRgnWindow, TRUE); 416 DeleteObject(hRgnWindow); 417 } 418 419 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)XMING_SIGNATURE); 420 421 return 0; 422 423 case WM_INIT_SYS_MENU: 424 /* 425 * Add whatever the setup file wants to for this window 426 */ 427 SetupSysMenu ((unsigned long)hwnd); 428 return 0; 429 430 case WM_SYSCOMMAND: 431 /* 432 * Any window menu items go through here 433 */ 434 if (HandleCustomWM_COMMAND ((unsigned long)hwnd, LOWORD(wParam))) 435 { 436 /* Don't pass customized menus to DefWindowProc */ 437 return 0; 438 } 439 if (wParam == SC_RESTORE || wParam == SC_MAXIMIZE) 440 { 441 WINDOWPLACEMENT wndpl; 442 wndpl.length = sizeof(wndpl); 443 if (GetWindowPlacement(hwnd, &wndpl) && wndpl.showCmd == SW_SHOWMINIMIZED) 444 needRestack = TRUE; 445 } 446 break; 447 448 case WM_INITMENU: 449 /* Checks/Unchecks any menu items before they are displayed */ 450 HandleCustomWM_INITMENU ((unsigned long)hwnd, wParam); 451 break; 452 453 case WM_ERASEBKGND: 454 /* 455 * Pretend that we did erase the background but we don't care, 456 * since we repaint the entire region anyhow 457 * This avoids some flickering when resizing. 458 */ 459 return TRUE; 460 461 case WM_PAINT: 462 /* Only paint if our window handle is valid */ 463 if (hwndScreen == NULL) 464 break; 465 466 /* BeginPaint gives us an hdc that clips to the invalidated region */ 467 hdcUpdate = BeginPaint (hwnd, &ps); 468 /* Avoid the BitBlt's if the PAINTSTRUCT is bogus */ 469 if (ps.rcPaint.right==0 && ps.rcPaint.bottom==0 && ps.rcPaint.left==0 && ps.rcPaint.top==0) 470 { 471 EndPaint (hwnd, &ps); 472 return 0; 473 } 474 475 /* Try to copy from the shadow buffer */ 476 if (!BitBlt (hdcUpdate, 477 ps.rcPaint.left, ps.rcPaint.top, 478 ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, 479 s_pScreenPriv->hdcShadow, 480 ps.rcPaint.left + pWin->drawable.x, ps.rcPaint.top + pWin->drawable.y, 481 SRCCOPY)) 482 { 483 LPVOID lpMsgBuf; 484 485 /* Display a fancy error message */ 486 FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | 487 FORMAT_MESSAGE_FROM_SYSTEM | 488 FORMAT_MESSAGE_IGNORE_INSERTS, 489 NULL, 490 GetLastError (), 491 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 492 (LPTSTR) &lpMsgBuf, 493 0, NULL); 494 495 ErrorF ("winTopLevelWindowProc - BitBlt failed: %s\n", 496 (LPSTR)lpMsgBuf); 497 LocalFree (lpMsgBuf); 498 } 499 500 /* EndPaint frees the DC */ 501 EndPaint (hwnd, &ps); 502 return 0; 503 504 case WM_MOUSEMOVE: 505 /* Unpack the client area mouse coordinates */ 506 ptMouse.x = GET_X_LPARAM(lParam); 507 ptMouse.y = GET_Y_LPARAM(lParam); 508 509 /* Translate the client area mouse coordinates to screen coordinates */ 510 ClientToScreen (hwnd, &ptMouse); 511 512 /* Screen Coords from (-X, -Y) -> Root Window (0, 0) */ 513 ptMouse.x -= GetSystemMetrics (SM_XVIRTUALSCREEN); 514 ptMouse.y -= GetSystemMetrics (SM_YVIRTUALSCREEN); 515 516 /* We can't do anything without privates */ 517 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 518 break; 519 520 /* Has the mouse pointer crossed screens? */ 521 if (s_pScreen != miPointerGetScreen(g_pwinPointer)) 522 miPointerSetScreen (g_pwinPointer, s_pScreenInfo->dwScreen, 523 ptMouse.x - s_pScreenInfo->dwXOffset, 524 ptMouse.y - s_pScreenInfo->dwYOffset); 525 526 /* Are we tracking yet? */ 527 if (!s_fTracking) 528 { 529 TRACKMOUSEEVENT tme; 530 531 /* Setup data structure */ 532 ZeroMemory (&tme, sizeof (tme)); 533 tme.cbSize = sizeof (tme); 534 tme.dwFlags = TME_LEAVE; 535 tme.hwndTrack = hwnd; 536 537 /* Call the tracking function */ 538 if (!(*g_fpTrackMouseEvent) (&tme)) 539 ErrorF ("winTopLevelWindowProc - _TrackMouseEvent failed\n"); 540 541 /* Flag that we are tracking now */ 542 s_fTracking = TRUE; 543 } 544 545 /* Hide or show the Windows mouse cursor */ 546 if (g_fSoftwareCursor && g_fCursor) 547 { 548 /* Hide Windows cursor */ 549 g_fCursor = FALSE; 550 ShowCursor (FALSE); 551 } 552 553 /* Kill the timer used to poll mouse events */ 554 if (g_uipMousePollingTimerID != 0) 555 { 556 KillTimer (s_pScreenPriv->hwndScreen, WIN_POLLING_MOUSE_TIMER_ID); 557 g_uipMousePollingTimerID = 0; 558 } 559 560 /* Deliver absolute cursor position to X Server */ 561 winEnqueueMotion(ptMouse.x - s_pScreenInfo->dwXOffset, 562 ptMouse.y - s_pScreenInfo->dwYOffset); 563 564 return 0; 565 566 case WM_NCMOUSEMOVE: 567 /* 568 * We break instead of returning 0 since we need to call 569 * DefWindowProc to get the mouse cursor changes 570 * and min/max/close button highlighting in Windows XP. 571 * The Platform SDK says that you should return 0 if you 572 * process this message, but it fails to mention that you 573 * will give up any default functionality if you do return 0. 574 */ 575 576 /* We can't do anything without privates */ 577 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 578 break; 579 580 /* Non-client mouse movement, show Windows cursor */ 581 if (g_fSoftwareCursor && !g_fCursor) 582 { 583 g_fCursor = TRUE; 584 ShowCursor (TRUE); 585 } 586 587 winStartMousePolling(s_pScreenPriv); 588 589 break; 590 591 case WM_MOUSELEAVE: 592 /* Mouse has left our client area */ 593 594 /* Flag that we are no longer tracking */ 595 s_fTracking = FALSE; 596 597 /* Show the mouse cursor, if necessary */ 598 if (g_fSoftwareCursor && !g_fCursor) 599 { 600 g_fCursor = TRUE; 601 ShowCursor (TRUE); 602 } 603 604 winStartMousePolling(s_pScreenPriv); 605 606 return 0; 607 608 case WM_LBUTTONDBLCLK: 609 case WM_LBUTTONDOWN: 610 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 611 break; 612 g_fButton[0] = TRUE; 613 SetCapture(hwnd); 614 return winMouseButtonsHandle (s_pScreen, ButtonPress, Button1, wParam); 615 616 case WM_LBUTTONUP: 617 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 618 break; 619 g_fButton[0] = FALSE; 620 ReleaseCapture(); 621 winStartMousePolling(s_pScreenPriv); 622 return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button1, wParam); 623 624 case WM_MBUTTONDBLCLK: 625 case WM_MBUTTONDOWN: 626 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 627 break; 628 g_fButton[1] = TRUE; 629 SetCapture(hwnd); 630 return winMouseButtonsHandle (s_pScreen, ButtonPress, Button2, wParam); 631 632 case WM_MBUTTONUP: 633 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 634 break; 635 g_fButton[1] = FALSE; 636 ReleaseCapture(); 637 winStartMousePolling(s_pScreenPriv); 638 return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button2, wParam); 639 640 case WM_RBUTTONDBLCLK: 641 case WM_RBUTTONDOWN: 642 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 643 break; 644 g_fButton[2] = TRUE; 645 SetCapture(hwnd); 646 return winMouseButtonsHandle (s_pScreen, ButtonPress, Button3, wParam); 647 648 case WM_RBUTTONUP: 649 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 650 break; 651 g_fButton[2] = FALSE; 652 ReleaseCapture(); 653 winStartMousePolling(s_pScreenPriv); 654 return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button3, wParam); 655 656 case WM_XBUTTONDBLCLK: 657 case WM_XBUTTONDOWN: 658 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 659 break; 660 SetCapture(hwnd); 661 return winMouseButtonsHandle (s_pScreen, ButtonPress, HIWORD(wParam) + 5, wParam); 662 663 case WM_XBUTTONUP: 664 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 665 break; 666 ReleaseCapture(); 667 winStartMousePolling(s_pScreenPriv); 668 return winMouseButtonsHandle (s_pScreen, ButtonRelease, HIWORD(wParam) + 5, wParam); 669 670 case WM_MOUSEWHEEL: 671 if (SendMessage(hwnd, WM_NCHITTEST, 0, MAKELONG(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) == HTCLIENT) 672 { 673 /* Pass the message to the root window */ 674 SendMessage (hwndScreen, message, wParam, lParam); 675 return 0; 676 } 677 else break; 678 679 case WM_SETFOCUS: 680 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 681 break; 682 683 { 684 /* Get the parent window for transient handling */ 685 HWND hParent = GetParent(hwnd); 686 if (hParent && IsIconic(hParent)) ShowWindow (hParent, SW_RESTORE); 687 } 688 689 winRestoreModeKeyStates (); 690 691 /* Add the keyboard hook if possible */ 692 if (g_fKeyboardHookLL) 693 g_fKeyboardHookLL = winInstallKeyboardHookLL (); 694 return 0; 695 696 case WM_KILLFOCUS: 697 /* Pop any pressed keys since we are losing keyboard focus */ 698 winKeybdReleaseKeys (); 699 700 /* Remove our keyboard hook if it is installed */ 701 winRemoveKeyboardHookLL (); 702 if (!wParam) 703 /* Revert the X focus as well, but only if the Windows focus is going to another window */ 704 DeleteWindowFromAnyEvents(pWin, FALSE); 705 return 0; 706 707 case WM_SYSDEADCHAR: 708 case WM_DEADCHAR: 709 /* 710 * NOTE: We do nothing with WM_*CHAR messages, 711 * nor does the root window, so we can just toss these messages. 712 */ 713 return 0; 714 715 case WM_SYSKEYDOWN: 716 case WM_KEYDOWN: 717 718 /* 719 * Don't pass Alt-F4 key combo to root window, 720 * let Windows translate to WM_CLOSE and close this top-level window. 721 * 722 * NOTE: We purposely don't check the fUseWinKillKey setting because 723 * it should only apply to the key handling for the root window, 724 * not for top-level window-manager windows. 725 * 726 * ALSO NOTE: We do pass Ctrl-Alt-Backspace to the root window 727 * because that is a key combo that no X app should be expecting to 728 * receive, since it has historically been used to shutdown the X server. 729 * Passing Ctrl-Alt-Backspace to the root window preserves that 730 * behavior, assuming that -unixkill has been passed as a parameter. 731 */ 732 if (wParam == VK_F4 && (GetKeyState (VK_MENU) & 0x8000)) 733 break; 734 735#if CYGWINDOWING_DEBUG 736 if (wParam == VK_ESCAPE) 737 { 738 /* Place for debug: put any tests and dumps here */ 739 WINDOWPLACEMENT windPlace; 740 RECT rc; 741 LPRECT pRect; 742 743 windPlace.length = sizeof (WINDOWPLACEMENT); 744 GetWindowPlacement (hwnd, &windPlace); 745 pRect = &windPlace.rcNormalPosition; 746 ErrorF ("\nCYGWINDOWING Dump:\n" 747 "\tdrawable: (%hd, %hd) - %hdx%hd\n", pDraw->x, 748 pDraw->y, pDraw->width, pDraw->height); 749 ErrorF ("\twindPlace: (%ld, %ld) - %ldx%ld\n", pRect->left, 750 pRect->top, pRect->right - pRect->left, 751 pRect->bottom - pRect->top); 752 if (GetClientRect (hwnd, &rc)) 753 { 754 pRect = &rc; 755 ErrorF ("\tClientRect: (%ld, %ld) - %ldx%ld\n", pRect->left, 756 pRect->top, pRect->right - pRect->left, 757 pRect->bottom - pRect->top); 758 } 759 if (GetWindowRect (hwnd, &rc)) 760 { 761 pRect = &rc; 762 ErrorF ("\tWindowRect: (%ld, %ld) - %ldx%ld\n", pRect->left, 763 pRect->top, pRect->right - pRect->left, 764 pRect->bottom - pRect->top); 765 } 766 ErrorF ("\n"); 767 } 768#endif 769 770 /* Pass the message to the root window */ 771 return winWindowProc(hwndScreen, message, wParam, lParam); 772 773 case WM_SYSKEYUP: 774 case WM_KEYUP: 775 776 777 /* Pass the message to the root window */ 778 return winWindowProc(hwndScreen, message, wParam, lParam); 779 780 case WM_HOTKEY: 781 782 /* Pass the message to the root window */ 783 SendMessage (hwndScreen, message, wParam, lParam); 784 return 0; 785 786 case WM_ACTIVATE: 787 788 /* Pass the message to the root window */ 789 SendMessage (hwndScreen, message, wParam, lParam); 790 791 if (LOWORD(wParam) != WA_INACTIVE) 792 { 793 /* Raise the window to the top in Z order */ 794 /* ago: Activate does not mean putting it to front! */ 795 /* 796 wmMsg.msg = WM_WM_RAISE; 797 if (fWMMsgInitialized) 798 winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg); 799 */ 800 801 /* Tell our Window Manager thread to activate the window */ 802 wmMsg.msg = WM_WM_ACTIVATE; 803 if (fWMMsgInitialized) 804 if (!pWin || !pWin->overrideRedirect) /* for OOo menus */ 805 winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg); 806 } 807 /* Prevent the mouse wheel from stalling when another window is minimized */ 808 if (HIWORD(wParam) == 0 && LOWORD(wParam) == WA_ACTIVE && 809 (HWND)lParam != NULL && (HWND)lParam != (HWND)GetParent(hwnd)) 810 SetFocus(hwnd); 811 return 0; 812 813 case WM_ACTIVATEAPP: 814 /* 815 * This message is also sent to the root window 816 * so we do nothing for individual multiwindow windows 817 */ 818 break; 819 820 case WM_CLOSE: 821 /* Branch on if the window was killed in X already */ 822 if (pWinPriv->fXKilled) 823 { 824 /* Window was killed, go ahead and destroy the window */ 825 DestroyWindow (hwnd); 826 } 827 else 828 { 829 /* Tell our Window Manager thread to kill the window */ 830 wmMsg.msg = WM_WM_KILL; 831 if (fWMMsgInitialized) 832 winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg); 833 } 834 return 0; 835 836 case WM_DESTROY: 837 838 /* Branch on if the window was killed in X already */ 839 if (pWinPriv && !pWinPriv->fXKilled) 840 { 841 ErrorF ("winTopLevelWindowProc - WM_DESTROY - WM_WM_KILL\n"); 842 843 /* Tell our Window Manager thread to kill the window */ 844 wmMsg.msg = WM_WM_KILL; 845 if (fWMMsgInitialized) 846 winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg); 847 } 848 849 RemoveProp (hwnd, WIN_WINDOW_PROP); 850 RemoveProp (hwnd, WIN_WID_PROP); 851 RemoveProp (hwnd, WIN_NEEDMANAGE_PROP); 852 853 break; 854 855 case WM_MOVE: 856 /* Adjust the X Window to the moved Windows window */ 857 winAdjustXWindow (pWin, hwnd); 858 return 0; 859 860 case WM_SHOWWINDOW: 861 /* Bail out if the window is being hidden */ 862 if (!wParam) 863 return 0; 864 865 /* */ 866 if (!pWin->overrideRedirect) 867 { 868 /* Flag that this window needs to be made active when clicked */ 869 SetProp (hwnd, WIN_NEEDMANAGE_PROP, (HANDLE) 1); 870 871 if (!(GetWindowLongPtr (hwnd, GWL_EXSTYLE) & WS_EX_APPWINDOW)) 872 { 873 HWND zstyle = HWND_NOTOPMOST; 874 875 /* Set the window extended style flags */ 876 SetWindowLongPtr (hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW); 877 878 /* Set the transient style flags */ 879 if (GetParent(hwnd)) SetWindowLongPtr (hwnd, GWL_STYLE, 880 WS_POPUP | WS_OVERLAPPED | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); 881 /* Set the window standard style flags */ 882 else SetWindowLongPtr (hwnd, GWL_STYLE, 883 (WS_POPUP | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS) 884 & ~WS_CAPTION & ~WS_SIZEBOX); 885 886 winUpdateWindowPosition (hwnd, FALSE, &zstyle); 887 SetForegroundWindow (hwnd); 888 } 889 wmMsg.msg = WM_WM_MAP3; 890 } 891 else /* It is an overridden window so make it top of Z stack */ 892 { 893 HWND forHwnd = GetForegroundWindow(); 894#if CYGWINDOWING_DEBUG 895 ErrorF ("overridden window is shown\n"); 896#endif 897 if (forHwnd != NULL) 898 { 899 if (GetWindowLongPtr(forHwnd, GWLP_USERDATA) & (LONG_PTR)XMING_SIGNATURE) 900 { 901 if (GetWindowLongPtr(forHwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) 902 SetWindowPos (hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 903 else 904 SetWindowPos (hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 905 } 906 } 907 wmMsg.msg = WM_WM_MAP2; 908 } 909 910 /* Tell our Window Manager thread to map the window */ 911 if (fWMMsgInitialized) 912 winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg); 913 914 winStartMousePolling(s_pScreenPriv); 915 916 return 0; 917 918 case WM_SIZING: 919 /* Need to legalize the size according to WM_NORMAL_HINTS */ 920 /* for applications like xterm */ 921 return ValidateSizing (hwnd, pWin, wParam, lParam); 922 923 case WM_WINDOWPOSCHANGED: 924 { 925 LPWINDOWPOS pWinPos = (LPWINDOWPOS) lParam; 926 927 if (!(pWinPos->flags & SWP_NOZORDER)) 928 { 929#if CYGWINDOWING_DEBUG 930 winDebug ("\twindow z order was changed\n"); 931#endif 932 if (pWinPos->hwndInsertAfter == HWND_TOP 933 ||pWinPos->hwndInsertAfter == HWND_TOPMOST 934 ||pWinPos->hwndInsertAfter == HWND_NOTOPMOST) 935 { 936#if CYGWINDOWING_DEBUG 937 winDebug ("\traise to top\n"); 938#endif 939 /* Raise the window to the top in Z order */ 940 winRaiseWindow(pWin); 941 } 942 else if (pWinPos->hwndInsertAfter == HWND_BOTTOM) 943 { 944 } 945 else 946 { 947 /* Check if this window is top of X windows. */ 948 HWND hWndAbove = NULL; 949 DWORD dwCurrentProcessID = GetCurrentProcessId (); 950 DWORD dwWindowProcessID = 0; 951 952 for (hWndAbove = pWinPos->hwndInsertAfter; 953 hWndAbove != NULL; 954 hWndAbove = GetNextWindow (hWndAbove, GW_HWNDPREV)) 955 { 956 /* Ignore other XWin process's window */ 957 GetWindowThreadProcessId (hWndAbove, &dwWindowProcessID); 958 959 if ((dwWindowProcessID == dwCurrentProcessID) 960 && GetProp (hWndAbove, WIN_WINDOW_PROP) 961 && !IsWindowVisible (hWndAbove) 962 && !IsIconic (hWndAbove) ) /* ignore minimized windows */ 963 break; 964 } 965 /* If this is top of X windows in Windows stack, 966 raise it in X stack. */ 967 if (hWndAbove == NULL) 968 { 969#if CYGWINDOWING_DEBUG 970 winDebug ("\traise to top\n"); 971#endif 972 winRaiseWindow(pWin); 973 } 974 } 975 } 976 } 977 /* 978 * Pass the message to DefWindowProc to let the function 979 * break down WM_WINDOWPOSCHANGED to WM_MOVE and WM_SIZE. 980 */ 981 break; 982 983 case WM_SIZE: 984 /* see dix/window.c */ 985#if CYGWINDOWING_DEBUG 986 { 987 char buf[64]; 988 switch (wParam) 989 { 990 case SIZE_MINIMIZED: 991 strcpy(buf, "SIZE_MINIMIZED"); 992 break; 993 case SIZE_MAXIMIZED: 994 strcpy(buf, "SIZE_MAXIMIZED"); 995 break; 996 case SIZE_RESTORED: 997 strcpy(buf, "SIZE_RESTORED"); 998 break; 999 default: 1000 strcpy(buf, "UNKNOWN_FLAG"); 1001 } 1002 ErrorF ("winTopLevelWindowProc - WM_SIZE to %dx%d (%s) - %d ms\n", 1003 (int)LOWORD(lParam), (int)HIWORD(lParam), buf, 1004 (int)(GetTickCount ())); 1005 } 1006#endif 1007 /* Adjust the X Window to the moved Windows window */ 1008 winAdjustXWindow (pWin, hwnd); 1009 return 0; /* end of WM_SIZE handler */ 1010 1011 case WM_MOUSEACTIVATE: 1012 1013 /* Check if this window needs to be made active when clicked */ 1014 if (!GetProp (pWinPriv->hWnd, WIN_NEEDMANAGE_PROP)) 1015 { 1016#if CYGMULTIWINDOW_DEBUG 1017 ErrorF ("winTopLevelWindowProc - WM_MOUSEACTIVATE - " 1018 "MA_NOACTIVATE\n"); 1019#endif 1020 1021 /* */ 1022 return MA_NOACTIVATE; 1023 } 1024 break; 1025 1026 case WM_SETCURSOR: 1027 if (LOWORD(lParam) == HTCLIENT) 1028 { 1029 if (!g_fSoftwareCursor) SetCursor (s_pScreenPriv->cursor.handle); 1030 return TRUE; 1031 } 1032 break; 1033 1034 default: 1035 break; 1036 } 1037 1038 ret = DefWindowProc (hwnd, message, wParam, lParam); 1039 /* 1040 * If the window was minized we get the stack change before the window is restored 1041 * and so it gets lost. Ensure there stacking order is correct. 1042 */ 1043 if (needRestack) 1044 winReorderWindowsMultiWindow(); 1045 return ret; 1046} 1047