winwndproc.c revision 1b5d61b8
1/* 2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 3 * 4 *Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 *"Software"), to deal in the Software without restriction, including 7 *without limitation the rights to use, copy, modify, merge, publish, 8 *distribute, sublicense, and/or sell copies of the Software, and to 9 *permit persons to whom the Software is furnished to do so, subject to 10 *the following conditions: 11 * 12 *The above copyright notice and this permission notice shall be 13 *included in all copies or substantial portions of the Software. 14 * 15 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 19 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 20 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 *Except as contained in this notice, the name of the XFree86 Project 24 *shall not be used in advertising or otherwise to promote the sale, use 25 *or other dealings in this Software without prior written authorization 26 *from the XFree86 Project. 27 * 28 * Authors: Dakshinamurthy Karra 29 * Suhaib M Siddiqi 30 * Peter Busch 31 * Harold L Hunt II 32 * MATSUZAKI Kensuke 33 */ 34 35#ifdef HAVE_XWIN_CONFIG_H 36#include <xwin-config.h> 37#endif 38#include "win.h" 39#include <commctrl.h> 40#include "winprefs.h" 41#include "winconfig.h" 42#include "winmsg.h" 43#include "winmonitors.h" 44#include "inputstr.h" 45#include "winclipboard/winclipboard.h" 46 47/* 48 * Global variables 49 */ 50 51Bool g_fCursor = TRUE; 52Bool g_fButton[3] = { FALSE, FALSE, FALSE }; 53 54/* 55 * Called by winWakeupHandler 56 * Processes current Windows message 57 */ 58 59LRESULT CALLBACK 60winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 61{ 62 static winPrivScreenPtr s_pScreenPriv = NULL; 63 static winScreenInfo *s_pScreenInfo = NULL; 64 static ScreenPtr s_pScreen = NULL; 65 static HWND s_hwndLastPrivates = NULL; 66 static Bool s_fTracking = FALSE; 67 static unsigned long s_ulServerGeneration = 0; 68 static UINT s_uTaskbarRestart = 0; 69 int iScanCode; 70 int i; 71 72#if CYGDEBUG 73 winDebugWin32Message("winWindowProc", hwnd, message, wParam, lParam); 74#endif 75 76 /* Watch for server regeneration */ 77 if (g_ulServerGeneration != s_ulServerGeneration) { 78 /* Store new server generation */ 79 s_ulServerGeneration = g_ulServerGeneration; 80 } 81 82 /* Only retrieve new privates pointers if window handle is null or changed */ 83 if ((s_pScreenPriv == NULL || hwnd != s_hwndLastPrivates) 84 && (s_pScreenPriv = GetProp(hwnd, WIN_SCR_PROP)) != NULL) { 85#if CYGDEBUG 86 winDebug("winWindowProc - Setting privates handle\n"); 87#endif 88 s_pScreenInfo = s_pScreenPriv->pScreenInfo; 89 s_pScreen = s_pScreenInfo->pScreen; 90 s_hwndLastPrivates = hwnd; 91 } 92 else if (s_pScreenPriv == NULL) { 93 /* For safety, handle case that should never happen */ 94 s_pScreenInfo = NULL; 95 s_pScreen = NULL; 96 s_hwndLastPrivates = NULL; 97 } 98 99 /* Branch on message type */ 100 switch (message) { 101 case WM_TRAYICON: 102 return winHandleIconMessage(hwnd, message, wParam, lParam, 103 s_pScreenPriv); 104 105 case WM_CREATE: 106#if CYGDEBUG 107 winDebug("winWindowProc - WM_CREATE\n"); 108#endif 109 110 /* 111 * Add a property to our display window that references 112 * this screens' privates. 113 * 114 * This allows the window procedure to refer to the 115 * appropriate window DC and shadow DC for the window that 116 * it is processing. We use this to repaint exposed 117 * areas of our display window. 118 */ 119 s_pScreenPriv = ((LPCREATESTRUCT) lParam)->lpCreateParams; 120 s_pScreenInfo = s_pScreenPriv->pScreenInfo; 121 s_pScreen = s_pScreenInfo->pScreen; 122 s_hwndLastPrivates = hwnd; 123 s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); 124 SetProp(hwnd, WIN_SCR_PROP, s_pScreenPriv); 125 126 /* Setup tray icon */ 127 if (!s_pScreenInfo->fNoTrayIcon) { 128 /* 129 * NOTE: The WM_CREATE message is processed before CreateWindowEx 130 * returns, so s_pScreenPriv->hwndScreen is invalid at this point. 131 * We go ahead and copy our hwnd parameter over top of the screen 132 * privates hwndScreen so that we have a valid value for 133 * that member. Otherwise, the tray icon will disappear 134 * the first time you move the mouse over top of it. 135 */ 136 137 s_pScreenPriv->hwndScreen = hwnd; 138 139 winInitNotifyIcon(s_pScreenPriv); 140 } 141 return 0; 142 143 case WM_DISPLAYCHANGE: 144 /* 145 WM_DISPLAYCHANGE seems to be sent when the monitor layout or 146 any monitor's resolution or depth changes, but it's lParam and 147 wParam always indicate the resolution and bpp for the primary 148 monitor (so ignore that as we could be on any monitor...) 149 */ 150 151 /* We cannot handle a display mode change during initialization */ 152 if (s_pScreenInfo == NULL) 153 FatalError("winWindowProc - WM_DISPLAYCHANGE - The display " 154 "mode changed while we were intializing. This is " 155 "very bad and unexpected. Exiting.\n"); 156 157 /* 158 * We do not care about display changes with 159 * fullscreen DirectDraw engines, because those engines set 160 * their own mode when they become active. 161 */ 162 if (s_pScreenInfo->fFullScreen 163 && (s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL)) { 164 break; 165 } 166 167 ErrorF("winWindowProc - WM_DISPLAYCHANGE - new width: %d " 168 "new height: %d new bpp: %d\n", 169 LOWORD(lParam), HIWORD(lParam), (int)wParam); 170 171 /* 0 bpp has no defined meaning, ignore this message */ 172 if (wParam == 0) 173 break; 174 175 /* 176 * Check for a disruptive change in depth. 177 * We can only display a message for a disruptive depth change, 178 * we cannot do anything to correct the situation. 179 */ 180 /* 181 XXX: maybe we need to check if GetSystemMetrics(SM_SAMEDISPLAYFORMAT) 182 has changed as well... 183 */ 184 if (s_pScreenInfo->dwBPP != 185 GetDeviceCaps(s_pScreenPriv->hdcScreen, BITSPIXEL)) { 186 if (s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL) { 187 /* Cannot display the visual until the depth is restored */ 188 ErrorF("winWindowProc - Disruptive change in depth\n"); 189 190 /* Display depth change dialog */ 191 winDisplayDepthChangeDialog(s_pScreenPriv); 192 193 /* Flag that we have an invalid screen depth */ 194 s_pScreenPriv->fBadDepth = TRUE; 195 196 /* Minimize the display window */ 197 ShowWindow(hwnd, SW_MINIMIZE); 198 } 199 else { 200 /* For GDI, performance may suffer until original depth is restored */ 201 ErrorF 202 ("winWindowProc - Performance may be non-optimal after change in depth\n"); 203 } 204 } 205 else { 206 /* Flag that we have a valid screen depth */ 207 s_pScreenPriv->fBadDepth = FALSE; 208 } 209 210 /* 211 If we could cheaply check if this WM_DISPLAYCHANGE change 212 affects the monitor(s) which this X screen is displayed on 213 then we should do so here. For the moment, assume it does. 214 (this is probably usually the case so that might be an 215 overoptimization) 216 */ 217 { 218 /* 219 In rootless modes which are monitor or virtual desktop size 220 use RandR to resize the X screen 221 */ 222 if ((!s_pScreenInfo->fUserGaveHeightAndWidth) && 223 (s_pScreenInfo->iResizeMode == resizeWithRandr) && (FALSE 224#ifdef XWIN_MULTIWINDOWEXTWM 225 || 226 s_pScreenInfo-> 227 fMWExtWM 228#endif 229 || 230 s_pScreenInfo-> 231 fRootless 232 || 233 s_pScreenInfo-> 234 fMultiWindow 235 )) { 236 DWORD dwWidth = 0, dwHeight = 0; 237 238 if (s_pScreenInfo->fMultipleMonitors) { 239 /* resize to new virtual desktop size */ 240 dwWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); 241 dwHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); 242 } 243 else { 244 /* resize to new size of specified monitor */ 245 struct GetMonitorInfoData data; 246 247 if (QueryMonitor(s_pScreenInfo->iMonitor, &data)) { 248 if (data.bMonitorSpecifiedExists == TRUE) { 249 dwWidth = data.monitorWidth; 250 dwHeight = data.monitorHeight; 251 /* 252 XXX: monitor may have changed position, 253 so we might need to update xinerama data 254 */ 255 } 256 else { 257 ErrorF("Monitor number %d no longer exists!\n", 258 s_pScreenInfo->iMonitor); 259 } 260 } 261 } 262 263 /* 264 XXX: probably a small bug here: we don't compute the work area 265 and allow for task bar 266 267 XXX: generally, we don't allow for the task bar being moved after 268 the server is started 269 */ 270 271 /* Set screen size to match new size, if it is different to current */ 272 if (((dwWidth != 0) && (dwHeight != 0)) && 273 ((s_pScreenInfo->dwWidth != dwWidth) || 274 (s_pScreenInfo->dwHeight != dwHeight))) { 275 winDoRandRScreenSetSize(s_pScreen, 276 dwWidth, 277 dwHeight, 278 (dwWidth * 25.4) / 279 monitorResolution, 280 (dwHeight * 25.4) / 281 monitorResolution); 282 } 283 } 284 else { 285 /* 286 * We can simply recreate the same-sized primary surface when 287 * the display dimensions change. 288 */ 289 290 winDebug 291 ("winWindowProc - WM_DISPLAYCHANGE - Releasing and recreating primary surface\n"); 292 293 /* Release the old primary surface */ 294 if (*s_pScreenPriv->pwinReleasePrimarySurface) 295 (*s_pScreenPriv->pwinReleasePrimarySurface) (s_pScreen); 296 297 /* Create the new primary surface */ 298 if (*s_pScreenPriv->pwinCreatePrimarySurface) 299 (*s_pScreenPriv->pwinCreatePrimarySurface) (s_pScreen); 300 } 301 } 302 303 break; 304 305 case WM_SIZE: 306 { 307 SCROLLINFO si; 308 RECT rcWindow; 309 int iWidth, iHeight; 310 311#if CYGDEBUG 312 winDebug("winWindowProc - WM_SIZE\n"); 313#endif 314 315 /* Break if we do not allow resizing */ 316 if ((s_pScreenInfo->iResizeMode == resizeNotAllowed) 317 || !s_pScreenInfo->fDecoration 318#ifdef XWIN_MULTIWINDOWEXTWM 319 || s_pScreenInfo->fMWExtWM 320#endif 321 || s_pScreenInfo->fRootless 322 || s_pScreenInfo->fMultiWindow 323 || s_pScreenInfo->fFullScreen) 324 break; 325 326 /* No need to resize if we get minimized */ 327 if (wParam == SIZE_MINIMIZED) 328 return 0; 329 330 ErrorF("winWindowProc - WM_SIZE - new client area w: %d h: %d\n", 331 LOWORD(lParam), HIWORD(lParam)); 332 333 if (s_pScreenInfo->iResizeMode == resizeWithRandr) { 334 /* Actual resizing is done on WM_EXITSIZEMOVE */ 335 return 0; 336 } 337 338 /* Otherwise iResizeMode == resizeWithScrollbars */ 339 340 /* 341 * Get the size of the whole window, including client area, 342 * scrollbars, and non-client area decorations (caption, borders). 343 * We do this because we need to check if the client area 344 * without scrollbars is large enough to display the whole visual. 345 * The new client area size passed by lParam already subtracts 346 * the size of the scrollbars if they are currently displayed. 347 * So checking is LOWORD(lParam) == visual_width and 348 * HIWORD(lParam) == visual_height will never tell us to hide 349 * the scrollbars because the client area would always be too small. 350 * GetClientRect returns the same sizes given by lParam, so we 351 * cannot use GetClientRect either. 352 */ 353 GetWindowRect(hwnd, &rcWindow); 354 iWidth = rcWindow.right - rcWindow.left; 355 iHeight = rcWindow.bottom - rcWindow.top; 356 357 /* Subtract the frame size from the window size. */ 358 iWidth -= 2 * GetSystemMetrics(SM_CXSIZEFRAME); 359 iHeight -= (2 * GetSystemMetrics(SM_CYSIZEFRAME) 360 + GetSystemMetrics(SM_CYCAPTION)); 361 362 /* 363 * Update scrollbar page sizes. 364 * NOTE: If page size == range, then the scrollbar is 365 * automatically hidden. 366 */ 367 368 /* Is the naked client area large enough to show the whole visual? */ 369 if (iWidth < s_pScreenInfo->dwWidth 370 || iHeight < s_pScreenInfo->dwHeight) { 371 /* Client area too small to display visual, use scrollbars */ 372 iWidth -= GetSystemMetrics(SM_CXVSCROLL); 373 iHeight -= GetSystemMetrics(SM_CYHSCROLL); 374 } 375 376 /* Set the horizontal scrollbar page size */ 377 si.cbSize = sizeof(si); 378 si.fMask = SIF_PAGE | SIF_RANGE; 379 si.nMin = 0; 380 si.nMax = s_pScreenInfo->dwWidth - 1; 381 si.nPage = iWidth; 382 SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); 383 384 /* Set the vertical scrollbar page size */ 385 si.cbSize = sizeof(si); 386 si.fMask = SIF_PAGE | SIF_RANGE; 387 si.nMin = 0; 388 si.nMax = s_pScreenInfo->dwHeight - 1; 389 si.nPage = iHeight; 390 SetScrollInfo(hwnd, SB_VERT, &si, TRUE); 391 392 /* 393 * NOTE: Scrollbars may have moved if they were at the 394 * far right/bottom, so we query their current position. 395 */ 396 397 /* Get the horizontal scrollbar position and set the offset */ 398 si.cbSize = sizeof(si); 399 si.fMask = SIF_POS; 400 GetScrollInfo(hwnd, SB_HORZ, &si); 401 s_pScreenInfo->dwXOffset = -si.nPos; 402 403 /* Get the vertical scrollbar position and set the offset */ 404 si.cbSize = sizeof(si); 405 si.fMask = SIF_POS; 406 GetScrollInfo(hwnd, SB_VERT, &si); 407 s_pScreenInfo->dwYOffset = -si.nPos; 408 } 409 return 0; 410 411 case WM_SYSCOMMAND: 412 if (s_pScreenInfo->iResizeMode == resizeWithRandr && 413 ((wParam & 0xfff0) == SC_MAXIMIZE || 414 (wParam & 0xfff0) == SC_RESTORE)) 415 PostMessage(hwnd, WM_EXITSIZEMOVE, 0, 0); 416 break; 417 418 case WM_ENTERSIZEMOVE: 419 ErrorF("winWindowProc - WM_ENTERSIZEMOVE\n"); 420 break; 421 422 case WM_EXITSIZEMOVE: 423 ErrorF("winWindowProc - WM_EXITSIZEMOVE\n"); 424 425 if (s_pScreenInfo->iResizeMode == resizeWithRandr) { 426 /* Set screen size to match new client area, if it is different to current */ 427 RECT rcClient; 428 DWORD dwWidth, dwHeight; 429 430 GetClientRect(hwnd, &rcClient); 431 dwWidth = rcClient.right - rcClient.left; 432 dwHeight = rcClient.bottom - rcClient.top; 433 434 if ((s_pScreenInfo->dwWidth != dwWidth) || 435 (s_pScreenInfo->dwHeight != dwHeight)) { 436 /* mm = dots * (25.4 mm / inch) / (dots / inch) */ 437 winDoRandRScreenSetSize(s_pScreen, 438 dwWidth, 439 dwHeight, 440 (dwWidth * 25.4) / monitorResolution, 441 (dwHeight * 25.4) / monitorResolution); 442 } 443 } 444 445 break; 446 447 case WM_VSCROLL: 448 { 449 SCROLLINFO si; 450 int iVertPos; 451 452#if CYGDEBUG 453 winDebug("winWindowProc - WM_VSCROLL\n"); 454#endif 455 456 /* Get vertical scroll bar info */ 457 si.cbSize = sizeof(si); 458 si.fMask = SIF_ALL; 459 GetScrollInfo(hwnd, SB_VERT, &si); 460 461 /* Save the vertical position for comparison later */ 462 iVertPos = si.nPos; 463 464 /* 465 * Don't forget: 466 * moving the scrollbar to the DOWN, scroll the content UP 467 */ 468 switch (LOWORD(wParam)) { 469 case SB_TOP: 470 si.nPos = si.nMin; 471 break; 472 473 case SB_BOTTOM: 474 si.nPos = si.nMax - si.nPage + 1; 475 break; 476 477 case SB_LINEUP: 478 si.nPos -= 1; 479 break; 480 481 case SB_LINEDOWN: 482 si.nPos += 1; 483 break; 484 485 case SB_PAGEUP: 486 si.nPos -= si.nPage; 487 break; 488 489 case SB_PAGEDOWN: 490 si.nPos += si.nPage; 491 break; 492 493 case SB_THUMBTRACK: 494 si.nPos = si.nTrackPos; 495 break; 496 497 default: 498 break; 499 } 500 501 /* 502 * We retrieve the position after setting it, 503 * because Windows may adjust it. 504 */ 505 si.fMask = SIF_POS; 506 SetScrollInfo(hwnd, SB_VERT, &si, TRUE); 507 GetScrollInfo(hwnd, SB_VERT, &si); 508 509 /* Scroll the window if the position has changed */ 510 if (si.nPos != iVertPos) { 511 /* Save the new offset for bit block transfers, etc. */ 512 s_pScreenInfo->dwYOffset = -si.nPos; 513 514 /* Change displayed region in the window */ 515 ScrollWindowEx(hwnd, 516 0, 517 iVertPos - si.nPos, 518 NULL, NULL, NULL, NULL, SW_INVALIDATE); 519 520 /* Redraw the window contents */ 521 UpdateWindow(hwnd); 522 } 523 } 524 return 0; 525 526 case WM_HSCROLL: 527 { 528 SCROLLINFO si; 529 int iHorzPos; 530 531#if CYGDEBUG 532 winDebug("winWindowProc - WM_HSCROLL\n"); 533#endif 534 535 /* Get horizontal scroll bar info */ 536 si.cbSize = sizeof(si); 537 si.fMask = SIF_ALL; 538 GetScrollInfo(hwnd, SB_HORZ, &si); 539 540 /* Save the horizontal position for comparison later */ 541 iHorzPos = si.nPos; 542 543 /* 544 * Don't forget: 545 * moving the scrollbar to the RIGHT, scroll the content LEFT 546 */ 547 switch (LOWORD(wParam)) { 548 case SB_LEFT: 549 si.nPos = si.nMin; 550 break; 551 552 case SB_RIGHT: 553 si.nPos = si.nMax - si.nPage + 1; 554 break; 555 556 case SB_LINELEFT: 557 si.nPos -= 1; 558 break; 559 560 case SB_LINERIGHT: 561 si.nPos += 1; 562 break; 563 564 case SB_PAGELEFT: 565 si.nPos -= si.nPage; 566 break; 567 568 case SB_PAGERIGHT: 569 si.nPos += si.nPage; 570 break; 571 572 case SB_THUMBTRACK: 573 si.nPos = si.nTrackPos; 574 break; 575 576 default: 577 break; 578 } 579 580 /* 581 * We retrieve the position after setting it, 582 * because Windows may adjust it. 583 */ 584 si.fMask = SIF_POS; 585 SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); 586 GetScrollInfo(hwnd, SB_HORZ, &si); 587 588 /* Scroll the window if the position has changed */ 589 if (si.nPos != iHorzPos) { 590 /* Save the new offset for bit block transfers, etc. */ 591 s_pScreenInfo->dwXOffset = -si.nPos; 592 593 /* Change displayed region in the window */ 594 ScrollWindowEx(hwnd, 595 iHorzPos - si.nPos, 596 0, NULL, NULL, NULL, NULL, SW_INVALIDATE); 597 598 /* Redraw the window contents */ 599 UpdateWindow(hwnd); 600 } 601 } 602 return 0; 603 604 case WM_GETMINMAXINFO: 605 { 606 MINMAXINFO *pMinMaxInfo = (MINMAXINFO *) lParam; 607 int iCaptionHeight; 608 int iBorderHeight, iBorderWidth; 609 610#if CYGDEBUG 611 winDebug("winWindowProc - WM_GETMINMAXINFO - pScreenInfo: %p\n", 612 s_pScreenInfo); 613#endif 614 615 /* Can't do anything without screen info */ 616 if (s_pScreenInfo == NULL 617 || (s_pScreenInfo->iResizeMode != resizeWithScrollbars) 618 || s_pScreenInfo->fFullScreen || !s_pScreenInfo->fDecoration 619#ifdef XWIN_MULTIWINDOWEXTWM 620 || s_pScreenInfo->fMWExtWM 621#endif 622 || s_pScreenInfo->fRootless 623 || s_pScreenInfo->fMultiWindow 624 ) 625 break; 626 627 /* 628 * Here we can override the maximum tracking size, which 629 * is the largest size that can be assigned to our window 630 * via the sizing border. 631 */ 632 633 /* 634 * FIXME: Do we only need to do this once, since our visual size 635 * does not change? Does Windows store this value statically 636 * once we have set it once? 637 */ 638 639 /* Get the border and caption sizes */ 640 iCaptionHeight = GetSystemMetrics(SM_CYCAPTION); 641 iBorderWidth = 2 * GetSystemMetrics(SM_CXSIZEFRAME); 642 iBorderHeight = 2 * GetSystemMetrics(SM_CYSIZEFRAME); 643 644 /* Allow the full visual to be displayed */ 645 pMinMaxInfo->ptMaxTrackSize.x = s_pScreenInfo->dwWidth + iBorderWidth; 646 pMinMaxInfo->ptMaxTrackSize.y 647 = s_pScreenInfo->dwHeight + iBorderHeight + iCaptionHeight; 648 } 649 return 0; 650 651 case WM_ERASEBKGND: 652#if CYGDEBUG 653 winDebug("winWindowProc - WM_ERASEBKGND\n"); 654#endif 655 /* 656 * Pretend that we did erase the background but we don't care, 657 * the application uses the full window estate. This avoids some 658 * flickering when resizing. 659 */ 660 return TRUE; 661 662 case WM_PAINT: 663#if CYGDEBUG 664 winDebug("winWindowProc - WM_PAINT\n"); 665#endif 666 /* Only paint if we have privates and the server is enabled */ 667 if (s_pScreenPriv == NULL 668 || !s_pScreenPriv->fEnabled 669 || (s_pScreenInfo->fFullScreen && !s_pScreenPriv->fActive) 670 || s_pScreenPriv->fBadDepth) { 671 /* We don't want to paint */ 672 break; 673 } 674 675 /* Break out here if we don't have a valid paint routine */ 676 if (s_pScreenPriv->pwinBltExposedRegions == NULL) 677 break; 678 679 /* Call the engine dependent repainter */ 680 (*s_pScreenPriv->pwinBltExposedRegions) (s_pScreen); 681 return 0; 682 683 case WM_PALETTECHANGED: 684 { 685#if CYGDEBUG 686 winDebug("winWindowProc - WM_PALETTECHANGED\n"); 687#endif 688 /* 689 * Don't process if we don't have privates or a colormap, 690 * or if we have an invalid depth. 691 */ 692 if (s_pScreenPriv == NULL 693 || s_pScreenPriv->pcmapInstalled == NULL 694 || s_pScreenPriv->fBadDepth) 695 break; 696 697 /* Return if we caused the palette to change */ 698 if ((HWND) wParam == hwnd) { 699 /* Redraw the screen */ 700 (*s_pScreenPriv->pwinRedrawScreen) (s_pScreen); 701 return 0; 702 } 703 704 /* Reinstall the windows palette */ 705 (*s_pScreenPriv->pwinRealizeInstalledPalette) (s_pScreen); 706 707 /* Redraw the screen */ 708 (*s_pScreenPriv->pwinRedrawScreen) (s_pScreen); 709 return 0; 710 } 711 712 case WM_MOUSEMOVE: 713 /* We can't do anything without privates */ 714 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 715 break; 716 717 /* We can't do anything without g_pwinPointer */ 718 if (g_pwinPointer == NULL) 719 break; 720 721 /* Has the mouse pointer crossed screens? */ 722 if (s_pScreen != miPointerGetScreen(g_pwinPointer)) 723 miPointerSetScreen(g_pwinPointer, s_pScreenInfo->dwScreen, 724 GET_X_LPARAM(lParam) - s_pScreenInfo->dwXOffset, 725 GET_Y_LPARAM(lParam) - s_pScreenInfo->dwYOffset); 726 727 /* Are we tracking yet? */ 728 if (!s_fTracking) { 729 TRACKMOUSEEVENT tme; 730 731 /* Setup data structure */ 732 ZeroMemory(&tme, sizeof(tme)); 733 tme.cbSize = sizeof(tme); 734 tme.dwFlags = TME_LEAVE; 735 tme.hwndTrack = hwnd; 736 737 /* Call the tracking function */ 738 if (!TrackMouseEvent(&tme)) 739 ErrorF("winWindowProc - TrackMouseEvent failed\n"); 740 741 /* Flag that we are tracking now */ 742 s_fTracking = TRUE; 743 } 744 745 /* Hide or show the Windows mouse cursor */ 746 if (g_fSoftwareCursor && g_fCursor && 747 (s_pScreenPriv->fActive || s_pScreenInfo->fLessPointer)) { 748 /* Hide Windows cursor */ 749 g_fCursor = FALSE; 750 ShowCursor(FALSE); 751 } 752 else if (g_fSoftwareCursor && !g_fCursor && !s_pScreenPriv->fActive 753 && !s_pScreenInfo->fLessPointer) { 754 /* Show Windows cursor */ 755 g_fCursor = TRUE; 756 ShowCursor(TRUE); 757 } 758 759 /* Deliver absolute cursor position to X Server */ 760 winEnqueueMotion(GET_X_LPARAM(lParam) - s_pScreenInfo->dwXOffset, 761 GET_Y_LPARAM(lParam) - s_pScreenInfo->dwYOffset); 762 return 0; 763 764 case WM_NCMOUSEMOVE: 765 /* 766 * We break instead of returning 0 since we need to call 767 * DefWindowProc to get the mouse cursor changes 768 * and min/max/close button highlighting in Windows XP. 769 * The Platform SDK says that you should return 0 if you 770 * process this message, but it fails to mention that you 771 * will give up any default functionality if you do return 0. 772 */ 773 774 /* We can't do anything without privates */ 775 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 776 break; 777 778 /* Non-client mouse movement, show Windows cursor */ 779 if (g_fSoftwareCursor && !g_fCursor) { 780 g_fCursor = TRUE; 781 ShowCursor(TRUE); 782 } 783 break; 784 785 case WM_MOUSELEAVE: 786 /* Mouse has left our client area */ 787 788 /* Flag that we are no longer tracking */ 789 s_fTracking = FALSE; 790 791 /* Show the mouse cursor, if necessary */ 792 if (g_fSoftwareCursor && !g_fCursor) { 793 g_fCursor = TRUE; 794 ShowCursor(TRUE); 795 } 796 return 0; 797 798 case WM_LBUTTONDBLCLK: 799 case WM_LBUTTONDOWN: 800 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 801 break; 802 if (s_pScreenInfo->fRootless 803#ifdef XWIN_MULTIWINDOWEXTWM 804 || s_pScreenInfo->fMWExtWM 805#endif 806 ) 807 SetCapture(hwnd); 808 return winMouseButtonsHandle(s_pScreen, ButtonPress, Button1, wParam); 809 810 case WM_LBUTTONUP: 811 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 812 break; 813 if (s_pScreenInfo->fRootless 814#ifdef XWIN_MULTIWINDOWEXTWM 815 || s_pScreenInfo->fMWExtWM 816#endif 817 ) 818 ReleaseCapture(); 819 return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button1, wParam); 820 821 case WM_MBUTTONDBLCLK: 822 case WM_MBUTTONDOWN: 823 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 824 break; 825 if (s_pScreenInfo->fRootless 826#ifdef XWIN_MULTIWINDOWEXTWM 827 || s_pScreenInfo->fMWExtWM 828#endif 829 ) 830 SetCapture(hwnd); 831 return winMouseButtonsHandle(s_pScreen, ButtonPress, Button2, wParam); 832 833 case WM_MBUTTONUP: 834 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 835 break; 836 if (s_pScreenInfo->fRootless 837#ifdef XWIN_MULTIWINDOWEXTWM 838 || s_pScreenInfo->fMWExtWM 839#endif 840 ) 841 ReleaseCapture(); 842 return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button2, wParam); 843 844 case WM_RBUTTONDBLCLK: 845 case WM_RBUTTONDOWN: 846 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 847 break; 848 if (s_pScreenInfo->fRootless 849#ifdef XWIN_MULTIWINDOWEXTWM 850 || s_pScreenInfo->fMWExtWM 851#endif 852 ) 853 SetCapture(hwnd); 854 return winMouseButtonsHandle(s_pScreen, ButtonPress, Button3, wParam); 855 856 case WM_RBUTTONUP: 857 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 858 break; 859 if (s_pScreenInfo->fRootless 860#ifdef XWIN_MULTIWINDOWEXTWM 861 || s_pScreenInfo->fMWExtWM 862#endif 863 ) 864 ReleaseCapture(); 865 return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button3, wParam); 866 867 case WM_XBUTTONDBLCLK: 868 case WM_XBUTTONDOWN: 869 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 870 break; 871 if (s_pScreenInfo->fRootless 872#ifdef XWIN_MULTIWINDOWEXTWM 873 || s_pScreenInfo->fMWExtWM 874#endif 875 ) 876 SetCapture(hwnd); 877 return winMouseButtonsHandle(s_pScreen, ButtonPress, HIWORD(wParam) + 7, 878 wParam); 879 case WM_XBUTTONUP: 880 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 881 break; 882 if (s_pScreenInfo->fRootless 883#ifdef XWIN_MULTIWINDOWEXTWM 884 || s_pScreenInfo->fMWExtWM 885#endif 886 ) 887 ReleaseCapture(); 888 return winMouseButtonsHandle(s_pScreen, ButtonRelease, 889 HIWORD(wParam) + 7, wParam); 890 891 case WM_TIMER: 892 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 893 break; 894 895 /* Branch on the timer id */ 896 switch (wParam) { 897 case WIN_E3B_TIMER_ID: 898 /* Send delayed button press */ 899 winMouseButtonsSendEvent(ButtonPress, 900 s_pScreenPriv->iE3BCachedPress); 901 902 /* Kill this timer */ 903 KillTimer(s_pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); 904 905 /* Clear screen privates flags */ 906 s_pScreenPriv->iE3BCachedPress = 0; 907 break; 908 909 case WIN_POLLING_MOUSE_TIMER_ID: 910 { 911 static POINT last_point; 912 POINT point; 913 WPARAM wL, wM, wR, wShift, wCtrl; 914 LPARAM lPos; 915 916 /* Get the current position of the mouse cursor */ 917 GetCursorPos(&point); 918 919 /* Map from screen (-X, -Y) to root (0, 0) */ 920 point.x -= GetSystemMetrics(SM_XVIRTUALSCREEN); 921 point.y -= GetSystemMetrics(SM_YVIRTUALSCREEN); 922 923 /* If the mouse pointer has moved, deliver absolute cursor position to X Server */ 924 if (last_point.x != point.x || last_point.y != point.y) { 925 winEnqueueMotion(point.x, point.y); 926 last_point.x = point.x; 927 last_point.y = point.y; 928 } 929 930 /* Check if a button was released but we didn't see it */ 931 GetCursorPos(&point); 932 wL = (GetKeyState(VK_LBUTTON) & 0x8000) ? MK_LBUTTON : 0; 933 wM = (GetKeyState(VK_MBUTTON) & 0x8000) ? MK_MBUTTON : 0; 934 wR = (GetKeyState(VK_RBUTTON) & 0x8000) ? MK_RBUTTON : 0; 935 wShift = (GetKeyState(VK_SHIFT) & 0x8000) ? MK_SHIFT : 0; 936 wCtrl = (GetKeyState(VK_CONTROL) & 0x8000) ? MK_CONTROL : 0; 937 lPos = MAKELPARAM(point.x, point.y); 938 if (g_fButton[0] && !wL) 939 PostMessage(hwnd, WM_LBUTTONUP, wCtrl | wM | wR | wShift, lPos); 940 if (g_fButton[1] && !wM) 941 PostMessage(hwnd, WM_MBUTTONUP, wCtrl | wL | wR | wShift, lPos); 942 if (g_fButton[2] && !wR) 943 PostMessage(hwnd, WM_RBUTTONUP, wCtrl | wL | wM | wShift, lPos); 944 } 945 } 946 return 0; 947 948 case WM_CTLCOLORSCROLLBAR: 949 FatalError("winWindowProc - WM_CTLCOLORSCROLLBAR - We are not " 950 "supposed to get this message. Exiting.\n"); 951 return 0; 952 953 case WM_MOUSEWHEEL: 954 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 955 break; 956#if CYGDEBUG 957 winDebug("winWindowProc - WM_MOUSEWHEEL\n"); 958#endif 959 /* Button4 = WheelUp */ 960 /* Button5 = WheelDown */ 961 winMouseWheel(&(s_pScreenPriv->iDeltaZ), GET_WHEEL_DELTA_WPARAM(wParam), Button4, Button5); 962 break; 963 964 case WM_MOUSEHWHEEL: 965 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 966 break; 967#if CYGDEBUG 968 winDebug("winWindowProc - WM_MOUSEHWHEEL\n"); 969#endif 970 /* Button7 = TiltRight */ 971 /* Button6 = TiltLeft */ 972 winMouseWheel(&(s_pScreenPriv->iDeltaV), GET_WHEEL_DELTA_WPARAM(wParam), 7, 6); 973 break; 974 975 case WM_SETFOCUS: 976 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 977 break; 978 979 /* Restore the state of all mode keys */ 980 winRestoreModeKeyStates(); 981 982 /* Add the keyboard hook if possible */ 983 if (g_fKeyboardHookLL) 984 g_fKeyboardHookLL = winInstallKeyboardHookLL(); 985 return 0; 986 987 case WM_KILLFOCUS: 988 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 989 break; 990 991 /* Release any pressed keys */ 992 winKeybdReleaseKeys(); 993 994 /* Remove our keyboard hook if it is installed */ 995 winRemoveKeyboardHookLL(); 996 return 0; 997 998 case WM_SYSKEYDOWN: 999 case WM_KEYDOWN: 1000 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 1001 break; 1002 1003 /* 1004 * FIXME: Catching Alt-F4 like this is really terrible. This should 1005 * be generalized to handle other Windows keyboard signals. Actually, 1006 * the list keys to catch and the actions to perform when caught should 1007 * be configurable; that way user's can customize the keys that they 1008 * need to have passed through to their window manager or apps, or they 1009 * can remap certain actions to new key codes that do not conflict 1010 * with the X apps that they are using. Yeah, that'll take awhile. 1011 */ 1012 if ((s_pScreenInfo->fUseWinKillKey && wParam == VK_F4 1013 && (GetKeyState(VK_MENU) & 0x8000)) 1014 || (s_pScreenInfo->fUseUnixKillKey && wParam == VK_BACK 1015 && (GetKeyState(VK_MENU) & 0x8000) 1016 && (GetKeyState(VK_CONTROL) & 0x8000))) { 1017 /* 1018 * Better leave this message here, just in case some unsuspecting 1019 * user enters Alt + F4 and is surprised when the application 1020 * quits. 1021 */ 1022 ErrorF("winWindowProc - WM_*KEYDOWN - Closekey hit, quitting\n"); 1023 1024 /* Display Exit dialog */ 1025 winDisplayExitDialog(s_pScreenPriv); 1026 return 0; 1027 } 1028 1029 /* 1030 * Don't do anything for the Windows keys, as focus will soon 1031 * be returned to Windows. We may be able to trap the Windows keys, 1032 * but we should determine if that is desirable before doing so. 1033 */ 1034 if ((wParam == VK_LWIN || wParam == VK_RWIN) && !g_fKeyboardHookLL) 1035 break; 1036 1037 /* Discard fake Ctrl_L events that precede AltGR on non-US keyboards */ 1038 if (winIsFakeCtrl_L(message, wParam, lParam)) 1039 return 0; 1040 1041 /* 1042 * Discard presses generated from Windows auto-repeat 1043 */ 1044 if (lParam & (1 << 30)) { 1045 switch (wParam) { 1046 /* ago: Pressing LControl while RControl is pressed is 1047 * Indicated as repeat. Fix this! 1048 */ 1049 case VK_CONTROL: 1050 case VK_SHIFT: 1051 if (winCheckKeyPressed(wParam, lParam)) 1052 return 0; 1053 break; 1054 default: 1055 return 0; 1056 } 1057 } 1058 1059 /* Translate Windows key code to X scan code */ 1060 iScanCode = winTranslateKey(wParam, lParam); 1061 1062 /* Ignore repeats for CapsLock */ 1063 if (wParam == VK_CAPITAL) 1064 lParam = 1; 1065 1066 /* Send the key event(s) */ 1067 for (i = 0; i < LOWORD(lParam); ++i) 1068 winSendKeyEvent(iScanCode, TRUE); 1069 return 0; 1070 1071 case WM_SYSKEYUP: 1072 case WM_KEYUP: 1073 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 1074 break; 1075 1076 /* 1077 * Don't do anything for the Windows keys, as focus will soon 1078 * be returned to Windows. We may be able to trap the Windows keys, 1079 * but we should determine if that is desirable before doing so. 1080 */ 1081 if ((wParam == VK_LWIN || wParam == VK_RWIN) && !g_fKeyboardHookLL) 1082 break; 1083 1084 /* Ignore the fake Ctrl_L that follows an AltGr release */ 1085 if (winIsFakeCtrl_L(message, wParam, lParam)) 1086 return 0; 1087 1088 /* Enqueue a keyup event */ 1089 iScanCode = winTranslateKey(wParam, lParam); 1090 winSendKeyEvent(iScanCode, FALSE); 1091 1092 /* Release all pressed shift keys */ 1093 if (wParam == VK_SHIFT) 1094 winFixShiftKeys(iScanCode); 1095 return 0; 1096 1097 case WM_ACTIVATE: 1098 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 1099 break; 1100 1101 /* TODO: Override display of window when we have a bad depth */ 1102 if (LOWORD(wParam) != WA_INACTIVE && s_pScreenPriv->fBadDepth) { 1103 ErrorF("winWindowProc - WM_ACTIVATE - Bad depth, trying " 1104 "to override window activation\n"); 1105 1106 /* Minimize the window */ 1107 ShowWindow(hwnd, SW_MINIMIZE); 1108 1109 /* Display dialog box */ 1110 if (g_hDlgDepthChange != NULL) { 1111 /* Make the existing dialog box active */ 1112 SetActiveWindow(g_hDlgDepthChange); 1113 } 1114 else { 1115 /* TODO: Recreate the dialog box and bring to the top */ 1116 ShowWindow(g_hDlgDepthChange, SW_SHOWDEFAULT); 1117 } 1118 1119 /* Don't do any other processing of this message */ 1120 return 0; 1121 } 1122 1123#if CYGDEBUG 1124 winDebug("winWindowProc - WM_ACTIVATE\n"); 1125#endif 1126 1127 /* 1128 * Focus is being changed to another window. 1129 * The other window may or may not belong to 1130 * our process. 1131 */ 1132 1133 /* Clear any lingering wheel delta */ 1134 s_pScreenPriv->iDeltaZ = 0; 1135 s_pScreenPriv->iDeltaV = 0; 1136 1137 /* Reshow the Windows mouse cursor if we are being deactivated */ 1138 if (g_fSoftwareCursor && LOWORD(wParam) == WA_INACTIVE && !g_fCursor) { 1139 /* Show Windows cursor */ 1140 g_fCursor = TRUE; 1141 ShowCursor(TRUE); 1142 } 1143 return 0; 1144 1145 case WM_ACTIVATEAPP: 1146 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 1147 break; 1148 1149#if CYGDEBUG || TRUE 1150 winDebug("winWindowProc - WM_ACTIVATEAPP\n"); 1151#endif 1152 1153 /* Activate or deactivate */ 1154 s_pScreenPriv->fActive = wParam; 1155 1156 /* Reshow the Windows mouse cursor if we are being deactivated */ 1157 if (g_fSoftwareCursor && !s_pScreenPriv->fActive && !g_fCursor) { 1158 /* Show Windows cursor */ 1159 g_fCursor = TRUE; 1160 ShowCursor(TRUE); 1161 } 1162 1163 /* Make sure the clipboard chain is ok. */ 1164 winFixClipboardChain(); 1165 1166 /* Call engine specific screen activation/deactivation function */ 1167 (*s_pScreenPriv->pwinActivateApp) (s_pScreen); 1168 1169#ifdef XWIN_MULTIWINDOWEXTWM 1170 if (s_pScreenPriv->fActive) { 1171 /* Restack all window unless using built-in wm. */ 1172 if (s_pScreenInfo->fMWExtWM) 1173 winMWExtWMRestackWindows(s_pScreen); 1174 } 1175#endif 1176 1177 return 0; 1178 1179 case WM_COMMAND: 1180 switch (LOWORD(wParam)) { 1181 case ID_APP_EXIT: 1182 /* Display Exit dialog */ 1183 winDisplayExitDialog(s_pScreenPriv); 1184 return 0; 1185 1186 case ID_APP_HIDE_ROOT: 1187 if (s_pScreenPriv->fRootWindowShown) 1188 ShowWindow(s_pScreenPriv->hwndScreen, SW_HIDE); 1189 else 1190 ShowWindow(s_pScreenPriv->hwndScreen, SW_SHOW); 1191 s_pScreenPriv->fRootWindowShown = !s_pScreenPriv->fRootWindowShown; 1192 return 0; 1193 1194 case ID_APP_MONITOR_PRIMARY: 1195 fPrimarySelection = !fPrimarySelection; 1196 return 0; 1197 1198 case ID_APP_ABOUT: 1199 /* Display the About box */ 1200 winDisplayAboutDialog(s_pScreenPriv); 1201 return 0; 1202 1203 default: 1204 /* It's probably one of the custom menus... */ 1205 if (HandleCustomWM_COMMAND(0, LOWORD(wParam), s_pScreenPriv)) 1206 return 0; 1207 } 1208 break; 1209 1210 case WM_GIVEUP: 1211 /* Tell X that we are giving up */ 1212 if (s_pScreenInfo->fMultiWindow) 1213 winDeinitMultiWindowWM(); 1214 GiveUp(0); 1215 return 0; 1216 1217 case WM_CLOSE: 1218 /* Display Exit dialog */ 1219 winDisplayExitDialog(s_pScreenPriv); 1220 return 0; 1221 1222 case WM_SETCURSOR: 1223 if (LOWORD(lParam) == HTCLIENT) { 1224 if (!g_fSoftwareCursor) 1225 SetCursor(s_pScreenPriv->cursor.handle); 1226 return TRUE; 1227 } 1228 break; 1229 1230 default: 1231 if (message == s_uTaskbarRestart) { 1232 winInitNotifyIcon(s_pScreenPriv); 1233 } 1234 break; 1235 } 1236 1237 return DefWindowProc(hwnd, message, wParam, lParam); 1238} 1239