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
winWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)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 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