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