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