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