xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

winwndproc.c (40315B)


      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 
     51 Bool g_fCursor = TRUE;
     52 Bool g_fButton[3] = { FALSE, FALSE, FALSE };
     53 
     54 /*
     55  * Called by winWakeupHandler
     56  * Processes current Windows message
     57  */
     58 
     59 LRESULT CALLBACK
     60 winWindowProc(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 }