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 its 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 initializing. 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) && (s_pScreenInfo-> 224 fRootless 225 || 226 s_pScreenInfo-> 227 fMultiWindow 228 )) { 229 DWORD dwWidth = 0, dwHeight = 0; 230 231 if (s_pScreenInfo->fMultipleMonitors) { 232 /* resize to new virtual desktop size */ 233 dwWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); 234 dwHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); 235 } 236 else { 237 /* resize to new size of specified monitor */ 238 struct GetMonitorInfoData data; 239 240 if (QueryMonitor(s_pScreenInfo->iMonitor, &data)) { 241 dwWidth = data.monitorWidth; 242 dwHeight = data.monitorHeight; 243 /* 244 XXX: monitor may have changed position, 245 so we might need to update xinerama data 246 */ 247 } 248 else { 249 ErrorF("Monitor number %d no longer exists!\n", 250 s_pScreenInfo->iMonitor); 251 } 252 } 253 254 /* 255 XXX: probably a small bug here: we don't compute the work area 256 and allow for task bar 257 258 XXX: generally, we don't allow for the task bar being moved after 259 the server is started 260 */ 261 262 /* Set screen size to match new size, if it is different to current */ 263 if (((dwWidth != 0) && (dwHeight != 0)) && 264 ((s_pScreenInfo->dwWidth != dwWidth) || 265 (s_pScreenInfo->dwHeight != dwHeight))) { 266 winDoRandRScreenSetSize(s_pScreen, 267 dwWidth, 268 dwHeight, 269 (dwWidth * 25.4) / 270 monitorResolution, 271 (dwHeight * 25.4) / 272 monitorResolution); 273 } 274 } 275 else { 276 /* 277 * We can simply recreate the same-sized primary surface when 278 * the display dimensions change. 279 */ 280 281 winDebug 282 ("winWindowProc - WM_DISPLAYCHANGE - Releasing and recreating primary surface\n"); 283 284 /* Release the old primary surface */ 285 if (*s_pScreenPriv->pwinReleasePrimarySurface) 286 (*s_pScreenPriv->pwinReleasePrimarySurface) (s_pScreen); 287 288 /* Create the new primary surface */ 289 if (*s_pScreenPriv->pwinCreatePrimarySurface) 290 (*s_pScreenPriv->pwinCreatePrimarySurface) (s_pScreen); 291 } 292 } 293 294 break; 295 296 case WM_SIZE: 297 { 298 SCROLLINFO si; 299 RECT rcWindow; 300 int iWidth, iHeight; 301 302#if CYGDEBUG 303 winDebug("winWindowProc - WM_SIZE\n"); 304#endif 305 306 /* Break if we do not allow resizing */ 307 if ((s_pScreenInfo->iResizeMode == resizeNotAllowed) 308 || !s_pScreenInfo->fDecoration 309 || s_pScreenInfo->fRootless 310 || s_pScreenInfo->fMultiWindow 311 || s_pScreenInfo->fFullScreen) 312 break; 313 314 /* No need to resize if we get minimized */ 315 if (wParam == SIZE_MINIMIZED) 316 return 0; 317 318 ErrorF("winWindowProc - WM_SIZE - new client area w: %d h: %d\n", 319 LOWORD(lParam), HIWORD(lParam)); 320 321 if (s_pScreenInfo->iResizeMode == resizeWithRandr) { 322 /* Actual resizing is done on WM_EXITSIZEMOVE */ 323 return 0; 324 } 325 326 /* Otherwise iResizeMode == resizeWithScrollbars */ 327 328 /* 329 * Get the size of the whole window, including client area, 330 * scrollbars, and non-client area decorations (caption, borders). 331 * We do this because we need to check if the client area 332 * without scrollbars is large enough to display the whole visual. 333 * The new client area size passed by lParam already subtracts 334 * the size of the scrollbars if they are currently displayed. 335 * So checking is LOWORD(lParam) == visual_width and 336 * HIWORD(lParam) == visual_height will never tell us to hide 337 * the scrollbars because the client area would always be too small. 338 * GetClientRect returns the same sizes given by lParam, so we 339 * cannot use GetClientRect either. 340 */ 341 GetWindowRect(hwnd, &rcWindow); 342 iWidth = rcWindow.right - rcWindow.left; 343 iHeight = rcWindow.bottom - rcWindow.top; 344 345 /* Subtract the frame size from the window size. */ 346 iWidth -= 2 * GetSystemMetrics(SM_CXSIZEFRAME); 347 iHeight -= (2 * GetSystemMetrics(SM_CYSIZEFRAME) 348 + GetSystemMetrics(SM_CYCAPTION)); 349 350 /* 351 * Update scrollbar page sizes. 352 * NOTE: If page size == range, then the scrollbar is 353 * automatically hidden. 354 */ 355 356 /* Is the naked client area large enough to show the whole visual? */ 357 if (iWidth < s_pScreenInfo->dwWidth 358 || iHeight < s_pScreenInfo->dwHeight) { 359 /* Client area too small to display visual, use scrollbars */ 360 iWidth -= GetSystemMetrics(SM_CXVSCROLL); 361 iHeight -= GetSystemMetrics(SM_CYHSCROLL); 362 } 363 364 /* Set the horizontal scrollbar page size */ 365 si.cbSize = sizeof(si); 366 si.fMask = SIF_PAGE | SIF_RANGE; 367 si.nMin = 0; 368 si.nMax = s_pScreenInfo->dwWidth - 1; 369 si.nPage = iWidth; 370 SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); 371 372 /* Set the vertical scrollbar page size */ 373 si.cbSize = sizeof(si); 374 si.fMask = SIF_PAGE | SIF_RANGE; 375 si.nMin = 0; 376 si.nMax = s_pScreenInfo->dwHeight - 1; 377 si.nPage = iHeight; 378 SetScrollInfo(hwnd, SB_VERT, &si, TRUE); 379 380 /* 381 * NOTE: Scrollbars may have moved if they were at the 382 * far right/bottom, so we query their current position. 383 */ 384 385 /* Get the horizontal scrollbar position and set the offset */ 386 si.cbSize = sizeof(si); 387 si.fMask = SIF_POS; 388 GetScrollInfo(hwnd, SB_HORZ, &si); 389 s_pScreenInfo->dwXOffset = -si.nPos; 390 391 /* Get the vertical scrollbar position and set the offset */ 392 si.cbSize = sizeof(si); 393 si.fMask = SIF_POS; 394 GetScrollInfo(hwnd, SB_VERT, &si); 395 s_pScreenInfo->dwYOffset = -si.nPos; 396 } 397 return 0; 398 399 case WM_SYSCOMMAND: 400 if (s_pScreenInfo->iResizeMode == resizeWithRandr && 401 ((wParam & 0xfff0) == SC_MAXIMIZE || 402 (wParam & 0xfff0) == SC_RESTORE)) 403 PostMessage(hwnd, WM_EXITSIZEMOVE, 0, 0); 404 break; 405 406 case WM_ENTERSIZEMOVE: 407 ErrorF("winWindowProc - WM_ENTERSIZEMOVE\n"); 408 break; 409 410 case WM_EXITSIZEMOVE: 411 ErrorF("winWindowProc - WM_EXITSIZEMOVE\n"); 412 413 if (s_pScreenInfo->iResizeMode == resizeWithRandr) { 414 /* Set screen size to match new client area, if it is different to current */ 415 RECT rcClient; 416 DWORD dwWidth, dwHeight; 417 418 GetClientRect(hwnd, &rcClient); 419 dwWidth = rcClient.right - rcClient.left; 420 dwHeight = rcClient.bottom - rcClient.top; 421 422 if ((s_pScreenInfo->dwWidth != dwWidth) || 423 (s_pScreenInfo->dwHeight != dwHeight)) { 424 /* mm = dots * (25.4 mm / inch) / (dots / inch) */ 425 winDoRandRScreenSetSize(s_pScreen, 426 dwWidth, 427 dwHeight, 428 (dwWidth * 25.4) / monitorResolution, 429 (dwHeight * 25.4) / monitorResolution); 430 } 431 } 432 433 break; 434 435 case WM_VSCROLL: 436 { 437 SCROLLINFO si; 438 int iVertPos; 439 440#if CYGDEBUG 441 winDebug("winWindowProc - WM_VSCROLL\n"); 442#endif 443 444 /* Get vertical scroll bar info */ 445 si.cbSize = sizeof(si); 446 si.fMask = SIF_ALL; 447 GetScrollInfo(hwnd, SB_VERT, &si); 448 449 /* Save the vertical position for comparison later */ 450 iVertPos = si.nPos; 451 452 /* 453 * Don't forget: 454 * moving the scrollbar to the DOWN, scroll the content UP 455 */ 456 switch (LOWORD(wParam)) { 457 case SB_TOP: 458 si.nPos = si.nMin; 459 break; 460 461 case SB_BOTTOM: 462 si.nPos = si.nMax - si.nPage + 1; 463 break; 464 465 case SB_LINEUP: 466 si.nPos -= 1; 467 break; 468 469 case SB_LINEDOWN: 470 si.nPos += 1; 471 break; 472 473 case SB_PAGEUP: 474 si.nPos -= si.nPage; 475 break; 476 477 case SB_PAGEDOWN: 478 si.nPos += si.nPage; 479 break; 480 481 case SB_THUMBTRACK: 482 si.nPos = si.nTrackPos; 483 break; 484 485 default: 486 break; 487 } 488 489 /* 490 * We retrieve the position after setting it, 491 * because Windows may adjust it. 492 */ 493 si.fMask = SIF_POS; 494 SetScrollInfo(hwnd, SB_VERT, &si, TRUE); 495 GetScrollInfo(hwnd, SB_VERT, &si); 496 497 /* Scroll the window if the position has changed */ 498 if (si.nPos != iVertPos) { 499 /* Save the new offset for bit block transfers, etc. */ 500 s_pScreenInfo->dwYOffset = -si.nPos; 501 502 /* Change displayed region in the window */ 503 ScrollWindowEx(hwnd, 504 0, 505 iVertPos - si.nPos, 506 NULL, NULL, NULL, NULL, SW_INVALIDATE); 507 508 /* Redraw the window contents */ 509 UpdateWindow(hwnd); 510 } 511 } 512 return 0; 513 514 case WM_HSCROLL: 515 { 516 SCROLLINFO si; 517 int iHorzPos; 518 519#if CYGDEBUG 520 winDebug("winWindowProc - WM_HSCROLL\n"); 521#endif 522 523 /* Get horizontal scroll bar info */ 524 si.cbSize = sizeof(si); 525 si.fMask = SIF_ALL; 526 GetScrollInfo(hwnd, SB_HORZ, &si); 527 528 /* Save the horizontal position for comparison later */ 529 iHorzPos = si.nPos; 530 531 /* 532 * Don't forget: 533 * moving the scrollbar to the RIGHT, scroll the content LEFT 534 */ 535 switch (LOWORD(wParam)) { 536 case SB_LEFT: 537 si.nPos = si.nMin; 538 break; 539 540 case SB_RIGHT: 541 si.nPos = si.nMax - si.nPage + 1; 542 break; 543 544 case SB_LINELEFT: 545 si.nPos -= 1; 546 break; 547 548 case SB_LINERIGHT: 549 si.nPos += 1; 550 break; 551 552 case SB_PAGELEFT: 553 si.nPos -= si.nPage; 554 break; 555 556 case SB_PAGERIGHT: 557 si.nPos += si.nPage; 558 break; 559 560 case SB_THUMBTRACK: 561 si.nPos = si.nTrackPos; 562 break; 563 564 default: 565 break; 566 } 567 568 /* 569 * We retrieve the position after setting it, 570 * because Windows may adjust it. 571 */ 572 si.fMask = SIF_POS; 573 SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); 574 GetScrollInfo(hwnd, SB_HORZ, &si); 575 576 /* Scroll the window if the position has changed */ 577 if (si.nPos != iHorzPos) { 578 /* Save the new offset for bit block transfers, etc. */ 579 s_pScreenInfo->dwXOffset = -si.nPos; 580 581 /* Change displayed region in the window */ 582 ScrollWindowEx(hwnd, 583 iHorzPos - si.nPos, 584 0, NULL, NULL, NULL, NULL, SW_INVALIDATE); 585 586 /* Redraw the window contents */ 587 UpdateWindow(hwnd); 588 } 589 } 590 return 0; 591 592 case WM_GETMINMAXINFO: 593 { 594 MINMAXINFO *pMinMaxInfo = (MINMAXINFO *) lParam; 595 int iCaptionHeight; 596 int iBorderHeight, iBorderWidth; 597 598#if CYGDEBUG 599 winDebug("winWindowProc - WM_GETMINMAXINFO - pScreenInfo: %p\n", 600 s_pScreenInfo); 601#endif 602 603 /* Can't do anything without screen info */ 604 if (s_pScreenInfo == NULL 605 || (s_pScreenInfo->iResizeMode != resizeWithScrollbars) 606 || s_pScreenInfo->fFullScreen || !s_pScreenInfo->fDecoration 607 || s_pScreenInfo->fRootless 608 || s_pScreenInfo->fMultiWindow 609 ) 610 break; 611 612 /* 613 * Here we can override the maximum tracking size, which 614 * is the largest size that can be assigned to our window 615 * via the sizing border. 616 */ 617 618 /* 619 * FIXME: Do we only need to do this once, since our visual size 620 * does not change? Does Windows store this value statically 621 * once we have set it once? 622 */ 623 624 /* Get the border and caption sizes */ 625 iCaptionHeight = GetSystemMetrics(SM_CYCAPTION); 626 iBorderWidth = 2 * GetSystemMetrics(SM_CXSIZEFRAME); 627 iBorderHeight = 2 * GetSystemMetrics(SM_CYSIZEFRAME); 628 629 /* Allow the full visual to be displayed */ 630 pMinMaxInfo->ptMaxTrackSize.x = s_pScreenInfo->dwWidth + iBorderWidth; 631 pMinMaxInfo->ptMaxTrackSize.y 632 = s_pScreenInfo->dwHeight + iBorderHeight + iCaptionHeight; 633 } 634 return 0; 635 636 case WM_ERASEBKGND: 637#if CYGDEBUG 638 winDebug("winWindowProc - WM_ERASEBKGND\n"); 639#endif 640 /* 641 * Pretend that we did erase the background but we don't care, 642 * the application uses the full window estate. This avoids some 643 * flickering when resizing. 644 */ 645 return TRUE; 646 647 case WM_PAINT: 648#if CYGDEBUG 649 winDebug("winWindowProc - WM_PAINT\n"); 650#endif 651 /* Only paint if we have privates and the server is enabled */ 652 if (s_pScreenPriv == NULL 653 || !s_pScreenPriv->fEnabled 654 || (s_pScreenInfo->fFullScreen && !s_pScreenPriv->fActive) 655 || s_pScreenPriv->fBadDepth) { 656 /* We don't want to paint */ 657 break; 658 } 659 660 /* Break out here if we don't have a valid paint routine */ 661 if (s_pScreenPriv->pwinBltExposedRegions == NULL) 662 break; 663 664 /* Call the engine dependent repainter */ 665 (*s_pScreenPriv->pwinBltExposedRegions) (s_pScreen); 666 return 0; 667 668 case WM_PALETTECHANGED: 669 { 670#if CYGDEBUG 671 winDebug("winWindowProc - WM_PALETTECHANGED\n"); 672#endif 673 /* 674 * Don't process if we don't have privates or a colormap, 675 * or if we have an invalid depth. 676 */ 677 if (s_pScreenPriv == NULL 678 || s_pScreenPriv->pcmapInstalled == NULL 679 || s_pScreenPriv->fBadDepth) 680 break; 681 682 /* Return if we caused the palette to change */ 683 if ((HWND) wParam == hwnd) { 684 /* Redraw the screen */ 685 (*s_pScreenPriv->pwinRedrawScreen) (s_pScreen); 686 return 0; 687 } 688 689 /* Reinstall the windows palette */ 690 (*s_pScreenPriv->pwinRealizeInstalledPalette) (s_pScreen); 691 692 /* Redraw the screen */ 693 (*s_pScreenPriv->pwinRedrawScreen) (s_pScreen); 694 return 0; 695 } 696 697 case WM_MOUSEMOVE: 698 /* We can't do anything without privates */ 699 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 700 break; 701 702 /* We can't do anything without g_pwinPointer */ 703 if (g_pwinPointer == NULL) 704 break; 705 706 /* Has the mouse pointer crossed screens? */ 707 if (s_pScreen != miPointerGetScreen(g_pwinPointer)) 708 miPointerSetScreen(g_pwinPointer, s_pScreenInfo->dwScreen, 709 GET_X_LPARAM(lParam) - s_pScreenInfo->dwXOffset, 710 GET_Y_LPARAM(lParam) - s_pScreenInfo->dwYOffset); 711 712 /* Are we tracking yet? */ 713 if (!s_fTracking) { 714 TRACKMOUSEEVENT tme; 715 716 /* Setup data structure */ 717 ZeroMemory(&tme, sizeof(tme)); 718 tme.cbSize = sizeof(tme); 719 tme.dwFlags = TME_LEAVE; 720 tme.hwndTrack = hwnd; 721 722 /* Call the tracking function */ 723 if (!TrackMouseEvent(&tme)) 724 ErrorF("winWindowProc - TrackMouseEvent failed\n"); 725 726 /* Flag that we are tracking now */ 727 s_fTracking = TRUE; 728 } 729 730 /* Hide or show the Windows mouse cursor */ 731 if (g_fSoftwareCursor && g_fCursor && 732 (s_pScreenPriv->fActive || s_pScreenInfo->fLessPointer)) { 733 /* Hide Windows cursor */ 734 g_fCursor = FALSE; 735 ShowCursor(FALSE); 736 } 737 else if (g_fSoftwareCursor && !g_fCursor && !s_pScreenPriv->fActive 738 && !s_pScreenInfo->fLessPointer) { 739 /* Show Windows cursor */ 740 g_fCursor = TRUE; 741 ShowCursor(TRUE); 742 } 743 744 /* Deliver absolute cursor position to X Server */ 745 winEnqueueMotion(GET_X_LPARAM(lParam) - s_pScreenInfo->dwXOffset, 746 GET_Y_LPARAM(lParam) - s_pScreenInfo->dwYOffset); 747 return 0; 748 749 case WM_NCMOUSEMOVE: 750 /* 751 * We break instead of returning 0 since we need to call 752 * DefWindowProc to get the mouse cursor changes 753 * and min/max/close button highlighting in Windows XP. 754 * The Platform SDK says that you should return 0 if you 755 * process this message, but it fails to mention that you 756 * will give up any default functionality if you do return 0. 757 */ 758 759 /* We can't do anything without privates */ 760 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 761 break; 762 763 /* Non-client mouse movement, show Windows cursor */ 764 if (g_fSoftwareCursor && !g_fCursor) { 765 g_fCursor = TRUE; 766 ShowCursor(TRUE); 767 } 768 break; 769 770 case WM_MOUSELEAVE: 771 /* Mouse has left our client area */ 772 773 /* Flag that we are no longer tracking */ 774 s_fTracking = FALSE; 775 776 /* Show the mouse cursor, if necessary */ 777 if (g_fSoftwareCursor && !g_fCursor) { 778 g_fCursor = TRUE; 779 ShowCursor(TRUE); 780 } 781 return 0; 782 783 case WM_LBUTTONDBLCLK: 784 case WM_LBUTTONDOWN: 785 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 786 break; 787 if (s_pScreenInfo->fRootless) 788 SetCapture(hwnd); 789 return winMouseButtonsHandle(s_pScreen, ButtonPress, Button1, wParam); 790 791 case WM_LBUTTONUP: 792 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 793 break; 794 if (s_pScreenInfo->fRootless) 795 ReleaseCapture(); 796 return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button1, wParam); 797 798 case WM_MBUTTONDBLCLK: 799 case WM_MBUTTONDOWN: 800 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 801 break; 802 if (s_pScreenInfo->fRootless) 803 SetCapture(hwnd); 804 return winMouseButtonsHandle(s_pScreen, ButtonPress, Button2, wParam); 805 806 case WM_MBUTTONUP: 807 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 808 break; 809 if (s_pScreenInfo->fRootless) 810 ReleaseCapture(); 811 return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button2, wParam); 812 813 case WM_RBUTTONDBLCLK: 814 case WM_RBUTTONDOWN: 815 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 816 break; 817 if (s_pScreenInfo->fRootless) 818 SetCapture(hwnd); 819 return winMouseButtonsHandle(s_pScreen, ButtonPress, Button3, wParam); 820 821 case WM_RBUTTONUP: 822 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 823 break; 824 if (s_pScreenInfo->fRootless) 825 ReleaseCapture(); 826 return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button3, wParam); 827 828 case WM_XBUTTONDBLCLK: 829 case WM_XBUTTONDOWN: 830 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 831 break; 832 if (s_pScreenInfo->fRootless) 833 SetCapture(hwnd); 834 return winMouseButtonsHandle(s_pScreen, ButtonPress, HIWORD(wParam) + 7, 835 wParam); 836 case WM_XBUTTONUP: 837 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 838 break; 839 if (s_pScreenInfo->fRootless) 840 ReleaseCapture(); 841 return winMouseButtonsHandle(s_pScreen, ButtonRelease, 842 HIWORD(wParam) + 7, wParam); 843 844 case WM_TIMER: 845 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 846 break; 847 848 /* Branch on the timer id */ 849 switch (wParam) { 850 case WIN_E3B_TIMER_ID: 851 /* Send delayed button press */ 852 winMouseButtonsSendEvent(ButtonPress, 853 s_pScreenPriv->iE3BCachedPress); 854 855 /* Kill this timer */ 856 KillTimer(s_pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); 857 858 /* Clear screen privates flags */ 859 s_pScreenPriv->iE3BCachedPress = 0; 860 break; 861 862 case WIN_POLLING_MOUSE_TIMER_ID: 863 { 864 static POINT last_point; 865 POINT point; 866 WPARAM wL, wM, wR, wShift, wCtrl; 867 LPARAM lPos; 868 869 /* Get the current position of the mouse cursor */ 870 GetCursorPos(&point); 871 872 /* Map from screen (-X, -Y) to root (0, 0) */ 873 point.x -= GetSystemMetrics(SM_XVIRTUALSCREEN); 874 point.y -= GetSystemMetrics(SM_YVIRTUALSCREEN); 875 876 /* If the mouse pointer has moved, deliver absolute cursor position to X Server */ 877 if (last_point.x != point.x || last_point.y != point.y) { 878 winEnqueueMotion(point.x, point.y); 879 last_point.x = point.x; 880 last_point.y = point.y; 881 } 882 883 /* Check if a button was released but we didn't see it */ 884 GetCursorPos(&point); 885 wL = (GetKeyState(VK_LBUTTON) & 0x8000) ? MK_LBUTTON : 0; 886 wM = (GetKeyState(VK_MBUTTON) & 0x8000) ? MK_MBUTTON : 0; 887 wR = (GetKeyState(VK_RBUTTON) & 0x8000) ? MK_RBUTTON : 0; 888 wShift = (GetKeyState(VK_SHIFT) & 0x8000) ? MK_SHIFT : 0; 889 wCtrl = (GetKeyState(VK_CONTROL) & 0x8000) ? MK_CONTROL : 0; 890 lPos = MAKELPARAM(point.x, point.y); 891 if (g_fButton[0] && !wL) 892 PostMessage(hwnd, WM_LBUTTONUP, wCtrl | wM | wR | wShift, lPos); 893 if (g_fButton[1] && !wM) 894 PostMessage(hwnd, WM_MBUTTONUP, wCtrl | wL | wR | wShift, lPos); 895 if (g_fButton[2] && !wR) 896 PostMessage(hwnd, WM_RBUTTONUP, wCtrl | wL | wM | wShift, lPos); 897 } 898 } 899 return 0; 900 901 case WM_CTLCOLORSCROLLBAR: 902 FatalError("winWindowProc - WM_CTLCOLORSCROLLBAR - We are not " 903 "supposed to get this message. Exiting.\n"); 904 return 0; 905 906 case WM_MOUSEWHEEL: 907 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 908 break; 909#if CYGDEBUG 910 winDebug("winWindowProc - WM_MOUSEWHEEL\n"); 911#endif 912 /* Button4 = WheelUp */ 913 /* Button5 = WheelDown */ 914 winMouseWheel(&(s_pScreenPriv->iDeltaZ), GET_WHEEL_DELTA_WPARAM(wParam), Button4, Button5); 915 break; 916 917 case WM_MOUSEHWHEEL: 918 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 919 break; 920#if CYGDEBUG 921 winDebug("winWindowProc - WM_MOUSEHWHEEL\n"); 922#endif 923 /* Button7 = TiltRight */ 924 /* Button6 = TiltLeft */ 925 winMouseWheel(&(s_pScreenPriv->iDeltaV), GET_WHEEL_DELTA_WPARAM(wParam), 7, 6); 926 break; 927 928 case WM_SETFOCUS: 929 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 930 break; 931 932 /* Restore the state of all mode keys */ 933 winRestoreModeKeyStates(); 934 935 /* Add the keyboard hook if possible */ 936 if (g_fKeyboardHookLL) 937 g_fKeyboardHookLL = winInstallKeyboardHookLL(); 938 return 0; 939 940 case WM_KILLFOCUS: 941 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 942 break; 943 944 /* Release any pressed keys */ 945 winKeybdReleaseKeys(); 946 947 /* Remove our keyboard hook if it is installed */ 948 winRemoveKeyboardHookLL(); 949 return 0; 950 951 case WM_SYSKEYDOWN: 952 case WM_KEYDOWN: 953 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 954 break; 955 956 /* 957 * FIXME: Catching Alt-F4 like this is really terrible. This should 958 * be generalized to handle other Windows keyboard signals. Actually, 959 * the list keys to catch and the actions to perform when caught should 960 * be configurable; that way user's can customize the keys that they 961 * need to have passed through to their window manager or apps, or they 962 * can remap certain actions to new key codes that do not conflict 963 * with the X apps that they are using. Yeah, that'll take awhile. 964 */ 965 if ((s_pScreenInfo->fUseWinKillKey && wParam == VK_F4 966 && (GetKeyState(VK_MENU) & 0x8000)) 967 || (s_pScreenInfo->fUseUnixKillKey && wParam == VK_BACK 968 && (GetKeyState(VK_MENU) & 0x8000) 969 && (GetKeyState(VK_CONTROL) & 0x8000))) { 970 /* 971 * Better leave this message here, just in case some unsuspecting 972 * user enters Alt + F4 and is surprised when the application 973 * quits. 974 */ 975 ErrorF("winWindowProc - WM_*KEYDOWN - Closekey hit, quitting\n"); 976 977 /* Display Exit dialog */ 978 winDisplayExitDialog(s_pScreenPriv); 979 return 0; 980 } 981 982 /* 983 * Don't do anything for the Windows keys, as focus will soon 984 * be returned to Windows. We may be able to trap the Windows keys, 985 * but we should determine if that is desirable before doing so. 986 */ 987 if ((wParam == VK_LWIN || wParam == VK_RWIN) && !g_fKeyboardHookLL) 988 break; 989 990 /* Discard fake Ctrl_L events that precede AltGR on non-US keyboards */ 991 if (winIsFakeCtrl_L(message, wParam, lParam)) 992 return 0; 993 994 /* 995 * Discard presses generated from Windows auto-repeat 996 */ 997 if (lParam & (1 << 30)) { 998 switch (wParam) { 999 /* ago: Pressing LControl while RControl is pressed is 1000 * Indicated as repeat. Fix this! 1001 */ 1002 case VK_CONTROL: 1003 case VK_SHIFT: 1004 if (winCheckKeyPressed(wParam, lParam)) 1005 return 0; 1006 break; 1007 default: 1008 return 0; 1009 } 1010 } 1011 1012 /* Translate Windows key code to X scan code */ 1013 iScanCode = winTranslateKey(wParam, lParam); 1014 1015 /* Ignore repeats for CapsLock */ 1016 if (wParam == VK_CAPITAL) 1017 lParam = 1; 1018 1019 /* Send the key event(s) */ 1020 for (i = 0; i < LOWORD(lParam); ++i) 1021 winSendKeyEvent(iScanCode, TRUE); 1022 return 0; 1023 1024 case WM_SYSKEYUP: 1025 case WM_KEYUP: 1026 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 1027 break; 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 /* Ignore the fake Ctrl_L that follows an AltGr release */ 1038 if (winIsFakeCtrl_L(message, wParam, lParam)) 1039 return 0; 1040 1041 /* Enqueue a keyup event */ 1042 iScanCode = winTranslateKey(wParam, lParam); 1043 winSendKeyEvent(iScanCode, FALSE); 1044 1045 /* Release all pressed shift keys */ 1046 if (wParam == VK_SHIFT) 1047 winFixShiftKeys(iScanCode); 1048 return 0; 1049 1050 case WM_ACTIVATE: 1051 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 1052 break; 1053 1054 /* TODO: Override display of window when we have a bad depth */ 1055 if (LOWORD(wParam) != WA_INACTIVE && s_pScreenPriv->fBadDepth) { 1056 ErrorF("winWindowProc - WM_ACTIVATE - Bad depth, trying " 1057 "to override window activation\n"); 1058 1059 /* Minimize the window */ 1060 ShowWindow(hwnd, SW_MINIMIZE); 1061 1062 /* Display dialog box */ 1063 if (g_hDlgDepthChange != NULL) { 1064 /* Make the existing dialog box active */ 1065 SetActiveWindow(g_hDlgDepthChange); 1066 } 1067 else { 1068 /* TODO: Recreate the dialog box and bring to the top */ 1069 ShowWindow(g_hDlgDepthChange, SW_SHOWDEFAULT); 1070 } 1071 1072 /* Don't do any other processing of this message */ 1073 return 0; 1074 } 1075 1076#if CYGDEBUG 1077 winDebug("winWindowProc - WM_ACTIVATE\n"); 1078#endif 1079 1080 /* 1081 * Focus is being changed to another window. 1082 * The other window may or may not belong to 1083 * our process. 1084 */ 1085 1086 /* Clear any lingering wheel delta */ 1087 s_pScreenPriv->iDeltaZ = 0; 1088 s_pScreenPriv->iDeltaV = 0; 1089 1090 /* Reshow the Windows mouse cursor if we are being deactivated */ 1091 if (g_fSoftwareCursor && LOWORD(wParam) == WA_INACTIVE && !g_fCursor) { 1092 /* Show Windows cursor */ 1093 g_fCursor = TRUE; 1094 ShowCursor(TRUE); 1095 } 1096 return 0; 1097 1098 case WM_ACTIVATEAPP: 1099 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) 1100 break; 1101 1102#if CYGDEBUG || TRUE 1103 winDebug("winWindowProc - WM_ACTIVATEAPP\n"); 1104#endif 1105 1106 /* Activate or deactivate */ 1107 s_pScreenPriv->fActive = wParam; 1108 1109 /* Reshow the Windows mouse cursor if we are being deactivated */ 1110 if (g_fSoftwareCursor && !s_pScreenPriv->fActive && !g_fCursor) { 1111 /* Show Windows cursor */ 1112 g_fCursor = TRUE; 1113 ShowCursor(TRUE); 1114 } 1115 1116 /* Call engine specific screen activation/deactivation function */ 1117 (*s_pScreenPriv->pwinActivateApp) (s_pScreen); 1118 1119 return 0; 1120 1121 case WM_COMMAND: 1122 switch (LOWORD(wParam)) { 1123 case ID_APP_EXIT: 1124 /* Display Exit dialog */ 1125 winDisplayExitDialog(s_pScreenPriv); 1126 return 0; 1127 1128 case ID_APP_HIDE_ROOT: 1129 if (s_pScreenPriv->fRootWindowShown) 1130 ShowWindow(s_pScreenPriv->hwndScreen, SW_HIDE); 1131 else 1132 ShowWindow(s_pScreenPriv->hwndScreen, SW_SHOW); 1133 s_pScreenPriv->fRootWindowShown = !s_pScreenPriv->fRootWindowShown; 1134 return 0; 1135 1136 case ID_APP_MONITOR_PRIMARY: 1137 fPrimarySelection = !fPrimarySelection; 1138 return 0; 1139 1140 case ID_APP_ABOUT: 1141 /* Display the About box */ 1142 winDisplayAboutDialog(s_pScreenPriv); 1143 return 0; 1144 1145 default: 1146 /* It's probably one of the custom menus... */ 1147 if (HandleCustomWM_COMMAND(0, LOWORD(wParam), s_pScreenPriv)) 1148 return 0; 1149 } 1150 break; 1151 1152 case WM_GIVEUP: 1153 /* Tell X that we are giving up */ 1154 if (s_pScreenInfo->fMultiWindow) 1155 winDeinitMultiWindowWM(); 1156 GiveUp(0); 1157 return 0; 1158 1159 case WM_CLOSE: 1160 /* Display Exit dialog */ 1161 winDisplayExitDialog(s_pScreenPriv); 1162 return 0; 1163 1164 case WM_SETCURSOR: 1165 if (LOWORD(lParam) == HTCLIENT) { 1166 if (!g_fSoftwareCursor) 1167 SetCursor(s_pScreenPriv->cursor.handle); 1168 return TRUE; 1169 } 1170 break; 1171 1172 default: 1173 if ((message == s_uTaskbarRestart) && !s_pScreenInfo->fNoTrayIcon) { 1174 winInitNotifyIcon(s_pScreenPriv); 1175 } 1176 break; 1177 } 1178 1179 return DefWindowProc(hwnd, message, wParam, lParam); 1180} 1181