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