1/*
2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3 *Copyright (C) Colin Harrison 2005-2008
4 *
5 *Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 *"Software"), to deal in the Software without restriction, including
8 *without limitation the rights to use, copy, modify, merge, publish,
9 *distribute, sublicense, and/or sell copies of the Software, and to
10 *permit persons to whom the Software is furnished to do so, subject to
11 *the following conditions:
12 *
13 *The above copyright notice and this permission notice shall be
14 *included in all copies or substantial portions of the Software.
15 *
16 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
20 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 *Except as contained in this notice, the name of the XFree86 Project
25 *shall not be used in advertising or otherwise to promote the sale, use
26 *or other dealings in this Software without prior written authorization
27 *from the XFree86 Project.
28 *
29 * Authors:	Kensuke Matsuzaki
30 *		Earle F. Philhower, III
31 *		Harold L Hunt II
32 *              Colin Harrison
33 */
34
35#ifdef HAVE_XWIN_CONFIG_H
36#include <xwin-config.h>
37#endif
38#include "win.h"
39#include "dixevents.h"
40#include "winmultiwindowclass.h"
41#include "winprefs.h"
42#include "winmsg.h"
43#include "inputstr.h"
44
45extern void winUpdateWindowPosition (HWND hWnd, Bool reshape, HWND *zstyle);
46
47
48/*
49 * Local globals
50 */
51
52static UINT_PTR		g_uipMousePollingTimerID = 0;
53
54
55/*
56 * Constant defines
57 */
58
59#define WIN_MULTIWINDOW_SHAPE		YES
60
61
62/*
63 * ConstrainSize - Taken from TWM sources - Respects hints for sizing
64 */
65#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
66static void
67ConstrainSize (WinXSizeHints hints, int *widthp, int *heightp)
68{
69  int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
70  int baseWidth, baseHeight;
71  int dwidth = *widthp, dheight = *heightp;
72
73  if (hints.flags & PMinSize)
74    {
75      minWidth = hints.min_width;
76      minHeight = hints.min_height;
77    }
78  else if (hints.flags & PBaseSize)
79    {
80      minWidth = hints.base_width;
81      minHeight = hints.base_height;
82    }
83  else
84    minWidth = minHeight = 1;
85
86  if (hints.flags & PBaseSize)
87    {
88      baseWidth = hints.base_width;
89      baseHeight = hints.base_height;
90    }
91  else if (hints.flags & PMinSize)
92    {
93      baseWidth = hints.min_width;
94      baseHeight = hints.min_height;
95    }
96  else
97    baseWidth = baseHeight = 0;
98
99  if (hints.flags & PMaxSize)
100    {
101      maxWidth = hints.max_width;
102      maxHeight = hints.max_height;
103    }
104  else
105    {
106      maxWidth = MAXINT;
107      maxHeight = MAXINT;
108    }
109
110  if (hints.flags & PResizeInc)
111    {
112      xinc = hints.width_inc;
113      yinc = hints.height_inc;
114    }
115  else
116    xinc = yinc = 1;
117
118  /*
119   * First, clamp to min and max values
120   */
121  if (dwidth < minWidth)
122    dwidth = minWidth;
123  if (dheight < minHeight)
124    dheight = minHeight;
125
126  if (dwidth > maxWidth)
127    dwidth = maxWidth;
128  if (dheight > maxHeight)
129    dheight = maxHeight;
130
131  /*
132   * Second, fit to base + N * inc
133   */
134  dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
135  dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
136
137  /*
138   * Third, adjust for aspect ratio
139   */
140
141  /*
142   * The math looks like this:
143   *
144   * minAspectX    dwidth     maxAspectX
145   * ---------- <= ------- <= ----------
146   * minAspectY    dheight    maxAspectY
147   *
148   * If that is multiplied out, then the width and height are
149   * invalid in the following situations:
150   *
151   * minAspectX * dheight > minAspectY * dwidth
152   * maxAspectX * dheight < maxAspectY * dwidth
153   *
154   */
155
156  if (hints.flags & PAspect)
157    {
158      if (hints.min_aspect.x * dheight > hints.min_aspect.y * dwidth)
159        {
160	  delta = makemult(hints.min_aspect.x * dheight / hints.min_aspect.y - dwidth, xinc);
161	  if (dwidth + delta <= maxWidth)
162	    dwidth += delta;
163	  else
164            {
165	      delta = makemult(dheight - dwidth*hints.min_aspect.y/hints.min_aspect.x, yinc);
166	      if (dheight - delta >= minHeight)
167		dheight -= delta;
168            }
169        }
170
171      if (hints.max_aspect.x * dheight < hints.max_aspect.y * dwidth)
172        {
173	  delta = makemult(dwidth * hints.max_aspect.y / hints.max_aspect.x - dheight, yinc);
174	  if (dheight + delta <= maxHeight)
175	    dheight += delta;
176	  else
177            {
178	      delta = makemult(dwidth - hints.max_aspect.x*dheight/hints.max_aspect.y, xinc);
179	      if (dwidth - delta >= minWidth)
180		dwidth -= delta;
181            }
182        }
183    }
184
185  /* Return computed values */
186  *widthp = dwidth;
187  *heightp = dheight;
188}
189#undef makemult
190
191
192
193/*
194 * ValidateSizing - Ensures size request respects hints
195 */
196static int
197ValidateSizing (HWND hwnd, WindowPtr pWin,
198		WPARAM wParam, LPARAM lParam)
199{
200  WinXSizeHints sizeHints;
201  RECT *rect;
202  int iWidth, iHeight;
203  RECT rcClient, rcWindow;
204  int iBorderWidthX, iBorderWidthY;
205
206  /* Invalid input checking */
207  if (pWin==NULL || lParam==0)
208    return FALSE;
209
210  /* No size hints, no checking */
211  if (!winMultiWindowGetWMNormalHints (pWin, &sizeHints))
212    return FALSE;
213
214  /* Avoid divide-by-zero */
215  if (sizeHints.flags & PResizeInc)
216    {
217      if (sizeHints.width_inc == 0) sizeHints.width_inc = 1;
218      if (sizeHints.height_inc == 0) sizeHints.height_inc = 1;
219    }
220
221  rect = (RECT*)lParam;
222
223  iWidth = rect->right - rect->left;
224  iHeight = rect->bottom - rect->top;
225
226  /* Now remove size of any borders and title bar */
227  GetClientRect(hwnd, &rcClient);
228  GetWindowRect(hwnd, &rcWindow);
229  iBorderWidthX = (rcWindow.right - rcWindow.left) - (rcClient.right - rcClient.left);
230  iBorderWidthY = (rcWindow.bottom - rcWindow.top) - (rcClient.bottom - rcClient.top);
231  iWidth -= iBorderWidthX;
232  iHeight -= iBorderWidthY;
233
234  /* Constrain the size to legal values */
235  ConstrainSize (sizeHints, &iWidth, &iHeight);
236
237  /* Add back the size of borders and title bar */
238  iWidth += iBorderWidthX;
239  iHeight += iBorderWidthY;
240
241  /* Adjust size according to where we're dragging from */
242  switch(wParam) {
243  case WMSZ_TOP:
244  case WMSZ_TOPRIGHT:
245  case WMSZ_BOTTOM:
246  case WMSZ_BOTTOMRIGHT:
247  case WMSZ_RIGHT:
248    rect->right = rect->left + iWidth;
249    break;
250  default:
251    rect->left = rect->right - iWidth;
252    break;
253  }
254  switch(wParam) {
255  case WMSZ_BOTTOM:
256  case WMSZ_BOTTOMRIGHT:
257  case WMSZ_BOTTOMLEFT:
258  case WMSZ_RIGHT:
259  case WMSZ_LEFT:
260    rect->bottom = rect->top + iHeight;
261    break;
262  default:
263    rect->top = rect->bottom - iHeight;
264    break;
265  }
266  return TRUE;
267}
268
269extern Bool winInDestroyWindowsWindow;
270static Bool winInRaiseWindow = FALSE;
271static void winRaiseWindow(WindowPtr pWin)
272{
273  if (!winInDestroyWindowsWindow && !winInRaiseWindow)
274  {
275    BOOL oldstate = winInRaiseWindow;
276    XID vlist[1] = { 0 };
277    winInRaiseWindow = TRUE;
278    /* Call configure window directly to make sure it gets processed
279     * in time
280     */
281    ConfigureWindow(pWin, CWStackMode, vlist, serverClient);
282    winInRaiseWindow = oldstate;
283  }
284}
285
286static
287void winStartMousePolling(winPrivScreenPtr s_pScreenPriv)
288{
289  /*
290   * Timer to poll mouse position.  This is needed to make
291   * programs like xeyes follow the mouse properly when the
292   * mouse pointer is outside of any X window.
293   */
294  if (g_uipMousePollingTimerID == 0)
295    g_uipMousePollingTimerID = SetTimer (s_pScreenPriv->hwndScreen,
296					 WIN_POLLING_MOUSE_TIMER_ID,
297					 MOUSE_POLLING_INTERVAL,
298					 NULL);
299}
300
301/*
302 * winTopLevelWindowProc - Window procedure for all top-level Windows windows.
303 */
304
305LRESULT CALLBACK
306winTopLevelWindowProc (HWND hwnd, UINT message,
307		       WPARAM wParam, LPARAM lParam)
308{
309  POINT			ptMouse;
310  HDC			hdcUpdate;
311  PAINTSTRUCT		ps;
312  WindowPtr		pWin = NULL;
313  winPrivWinPtr	        pWinPriv = NULL;
314  ScreenPtr		s_pScreen = NULL;
315  winPrivScreenPtr	s_pScreenPriv = NULL;
316  winScreenInfo		*s_pScreenInfo = NULL;
317  HWND			hwndScreen = NULL;
318  DrawablePtr		pDraw = NULL;
319  winWMMessageRec	wmMsg;
320  Bool                  fWMMsgInitialized = FALSE;
321  static Bool		s_fTracking = FALSE;
322  Bool			needRestack = FALSE;
323  LRESULT		ret;
324
325#if CYGDEBUG
326  winDebugWin32Message("winTopLevelWindowProc", hwnd, message, wParam, lParam);
327#endif
328
329  /* Check if the Windows window property for our X window pointer is valid */
330  if ((pWin = GetProp (hwnd, WIN_WINDOW_PROP)) != NULL)
331    {
332      /* Our X window pointer is valid */
333
334      /* Get pointers to the drawable and the screen */
335      pDraw		= &pWin->drawable;
336      s_pScreen		= pWin->drawable.pScreen;
337
338      /* Get a pointer to our window privates */
339      pWinPriv		= winGetWindowPriv(pWin);
340
341      /* Get pointers to our screen privates and screen info */
342      s_pScreenPriv	= pWinPriv->pScreenPriv;
343      s_pScreenInfo	= s_pScreenPriv->pScreenInfo;
344
345      /* Get the handle for our screen-sized window */
346      hwndScreen	= s_pScreenPriv->hwndScreen;
347
348      /* */
349      wmMsg.msg		= 0;
350      wmMsg.hwndWindow	= hwnd;
351      wmMsg.iWindow	= (Window)GetProp (hwnd, WIN_WID_PROP);
352
353      wmMsg.iX		= pDraw->x;
354      wmMsg.iY		= pDraw->y;
355      wmMsg.iWidth	= pDraw->width;
356      wmMsg.iHeight	= pDraw->height;
357
358      fWMMsgInitialized = TRUE;
359
360#if 0
361      /*
362       * Print some debugging information
363       */
364
365      ErrorF ("hWnd %08X\n", hwnd);
366      ErrorF ("pWin %08X\n", pWin);
367      ErrorF ("pDraw %08X\n", pDraw);
368      ErrorF ("\ttype %08X\n", pWin->drawable.type);
369      ErrorF ("\tclass %08X\n", pWin->drawable.class);
370      ErrorF ("\tdepth %08X\n", pWin->drawable.depth);
371      ErrorF ("\tbitsPerPixel %08X\n", pWin->drawable.bitsPerPixel);
372      ErrorF ("\tid %08X\n", pWin->drawable.id);
373      ErrorF ("\tx %08X\n", pWin->drawable.x);
374      ErrorF ("\ty %08X\n", pWin->drawable.y);
375      ErrorF ("\twidth %08X\n", pWin->drawable.width);
376      ErrorF ("\thenght %08X\n", pWin->drawable.height);
377      ErrorF ("\tpScreen %08X\n", pWin->drawable.pScreen);
378      ErrorF ("\tserialNumber %08X\n", pWin->drawable.serialNumber);
379      ErrorF ("g_iWindowPrivateKey %p\n", g_iWindowPrivateKey);
380      ErrorF ("pWinPriv %08X\n", pWinPriv);
381      ErrorF ("s_pScreenPriv %08X\n", s_pScreenPriv);
382      ErrorF ("s_pScreenInfo %08X\n", s_pScreenInfo);
383      ErrorF ("hwndScreen %08X\n", hwndScreen);
384#endif
385    }
386
387  /* Branch on message type */
388  switch (message)
389    {
390    case WM_CREATE:
391
392      /* */
393      SetProp (hwnd,
394	       WIN_WINDOW_PROP,
395	       (HANDLE)((LPCREATESTRUCT) lParam)->lpCreateParams);
396
397      /* */
398      SetProp (hwnd,
399	       WIN_WID_PROP,
400	       (HANDLE)winGetWindowID (((LPCREATESTRUCT) lParam)->lpCreateParams));
401
402      /*
403       * Make X windows' Z orders sync with Windows windows because
404       * there can be AlwaysOnTop windows overlapped on the window
405       * currently being created.
406       */
407      winReorderWindowsMultiWindow ();
408
409      /* Fix a 'round title bar corner background should be transparent not black' problem when first painted */
410      {
411        RECT rWindow;
412        HRGN hRgnWindow;
413        GetWindowRect(hwnd, &rWindow);
414        hRgnWindow = CreateRectRgnIndirect(&rWindow);
415        SetWindowRgn (hwnd, hRgnWindow, TRUE);
416        DeleteObject(hRgnWindow);
417      }
418
419      SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)XMING_SIGNATURE);
420
421      return 0;
422
423    case WM_INIT_SYS_MENU:
424      /*
425       * Add whatever the setup file wants to for this window
426       */
427      SetupSysMenu ((unsigned long)hwnd);
428      return 0;
429
430    case WM_SYSCOMMAND:
431      /*
432       * Any window menu items go through here
433       */
434      if (HandleCustomWM_COMMAND ((unsigned long)hwnd, LOWORD(wParam)))
435      {
436        /* Don't pass customized menus to DefWindowProc */
437        return 0;
438      }
439      if (wParam == SC_RESTORE || wParam == SC_MAXIMIZE)
440      {
441        WINDOWPLACEMENT wndpl;
442	wndpl.length = sizeof(wndpl);
443	if (GetWindowPlacement(hwnd, &wndpl) && wndpl.showCmd == SW_SHOWMINIMIZED)
444          needRestack = TRUE;
445      }
446      break;
447
448    case WM_INITMENU:
449      /* Checks/Unchecks any menu items before they are displayed */
450      HandleCustomWM_INITMENU ((unsigned long)hwnd, wParam);
451      break;
452
453    case WM_ERASEBKGND:
454      /*
455       * Pretend that we did erase the background but we don't care,
456       * since we repaint the entire region anyhow
457       * This avoids some flickering when resizing.
458       */
459      return TRUE;
460
461    case WM_PAINT:
462      /* Only paint if our window handle is valid */
463      if (hwndScreen == NULL)
464	break;
465
466      /* BeginPaint gives us an hdc that clips to the invalidated region */
467      hdcUpdate = BeginPaint (hwnd, &ps);
468      /* Avoid the BitBlt's if the PAINTSTRUCT is bogus */
469      if (ps.rcPaint.right==0 && ps.rcPaint.bottom==0 && ps.rcPaint.left==0 && ps.rcPaint.top==0)
470      {
471	EndPaint (hwnd, &ps);
472	return 0;
473      }
474
475      /* Try to copy from the shadow buffer */
476      if (!BitBlt (hdcUpdate,
477		   ps.rcPaint.left, ps.rcPaint.top,
478		   ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
479		   s_pScreenPriv->hdcShadow,
480		   ps.rcPaint.left + pWin->drawable.x, ps.rcPaint.top + pWin->drawable.y,
481		   SRCCOPY))
482	{
483	  LPVOID lpMsgBuf;
484
485	  /* Display a fancy error message */
486	  FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
487			 FORMAT_MESSAGE_FROM_SYSTEM |
488			 FORMAT_MESSAGE_IGNORE_INSERTS,
489			 NULL,
490			 GetLastError (),
491			 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
492			 (LPTSTR) &lpMsgBuf,
493			 0, NULL);
494
495	  ErrorF ("winTopLevelWindowProc - BitBlt failed: %s\n",
496		  (LPSTR)lpMsgBuf);
497	  LocalFree (lpMsgBuf);
498	}
499
500      /* EndPaint frees the DC */
501      EndPaint (hwnd, &ps);
502      return 0;
503
504    case WM_MOUSEMOVE:
505      /* Unpack the client area mouse coordinates */
506      ptMouse.x = GET_X_LPARAM(lParam);
507      ptMouse.y = GET_Y_LPARAM(lParam);
508
509      /* Translate the client area mouse coordinates to screen coordinates */
510      ClientToScreen (hwnd, &ptMouse);
511
512      /* Screen Coords from (-X, -Y) -> Root Window (0, 0) */
513      ptMouse.x -= GetSystemMetrics (SM_XVIRTUALSCREEN);
514      ptMouse.y -= GetSystemMetrics (SM_YVIRTUALSCREEN);
515
516      /* We can't do anything without privates */
517      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
518	break;
519
520      /* Has the mouse pointer crossed screens? */
521      if (s_pScreen != miPointerGetScreen(g_pwinPointer))
522	miPointerSetScreen (g_pwinPointer, s_pScreenInfo->dwScreen,
523			       ptMouse.x - s_pScreenInfo->dwXOffset,
524			       ptMouse.y - s_pScreenInfo->dwYOffset);
525
526      /* Are we tracking yet? */
527      if (!s_fTracking)
528	{
529	  TRACKMOUSEEVENT		tme;
530
531	  /* Setup data structure */
532	  ZeroMemory (&tme, sizeof (tme));
533	  tme.cbSize = sizeof (tme);
534	  tme.dwFlags = TME_LEAVE;
535	  tme.hwndTrack = hwnd;
536
537	  /* Call the tracking function */
538	  if (!(*g_fpTrackMouseEvent) (&tme))
539	    ErrorF ("winTopLevelWindowProc - _TrackMouseEvent failed\n");
540
541	  /* Flag that we are tracking now */
542	  s_fTracking = TRUE;
543	}
544
545      /* Hide or show the Windows mouse cursor */
546      if (g_fSoftwareCursor && g_fCursor)
547	{
548	  /* Hide Windows cursor */
549	  g_fCursor = FALSE;
550	  ShowCursor (FALSE);
551	}
552
553      /* Kill the timer used to poll mouse events */
554      if (g_uipMousePollingTimerID != 0)
555	{
556	  KillTimer (s_pScreenPriv->hwndScreen, WIN_POLLING_MOUSE_TIMER_ID);
557	  g_uipMousePollingTimerID = 0;
558	}
559
560      /* Deliver absolute cursor position to X Server */
561      winEnqueueMotion(ptMouse.x - s_pScreenInfo->dwXOffset,
562		       ptMouse.y - s_pScreenInfo->dwYOffset);
563
564      return 0;
565
566    case WM_NCMOUSEMOVE:
567      /*
568       * We break instead of returning 0 since we need to call
569       * DefWindowProc to get the mouse cursor changes
570       * and min/max/close button highlighting in Windows XP.
571       * The Platform SDK says that you should return 0 if you
572       * process this message, but it fails to mention that you
573       * will give up any default functionality if you do return 0.
574       */
575
576      /* We can't do anything without privates */
577      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
578	break;
579
580      /* Non-client mouse movement, show Windows cursor */
581      if (g_fSoftwareCursor && !g_fCursor)
582	{
583	  g_fCursor = TRUE;
584	  ShowCursor (TRUE);
585	}
586
587      winStartMousePolling(s_pScreenPriv);
588
589      break;
590
591    case WM_MOUSELEAVE:
592      /* Mouse has left our client area */
593
594      /* Flag that we are no longer tracking */
595      s_fTracking = FALSE;
596
597      /* Show the mouse cursor, if necessary */
598      if (g_fSoftwareCursor && !g_fCursor)
599	{
600	  g_fCursor = TRUE;
601	  ShowCursor (TRUE);
602	}
603
604      winStartMousePolling(s_pScreenPriv);
605
606      return 0;
607
608    case WM_LBUTTONDBLCLK:
609    case WM_LBUTTONDOWN:
610      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
611	break;
612      g_fButton[0] = TRUE;
613      SetCapture(hwnd);
614      return winMouseButtonsHandle (s_pScreen, ButtonPress, Button1, wParam);
615
616    case WM_LBUTTONUP:
617      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
618	break;
619      g_fButton[0] = FALSE;
620      ReleaseCapture();
621      winStartMousePolling(s_pScreenPriv);
622      return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button1, wParam);
623
624    case WM_MBUTTONDBLCLK:
625    case WM_MBUTTONDOWN:
626      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
627	break;
628      g_fButton[1] = TRUE;
629      SetCapture(hwnd);
630      return winMouseButtonsHandle (s_pScreen, ButtonPress, Button2, wParam);
631
632    case WM_MBUTTONUP:
633      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
634	break;
635      g_fButton[1] = FALSE;
636      ReleaseCapture();
637      winStartMousePolling(s_pScreenPriv);
638      return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button2, wParam);
639
640    case WM_RBUTTONDBLCLK:
641    case WM_RBUTTONDOWN:
642      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
643	break;
644      g_fButton[2] = TRUE;
645      SetCapture(hwnd);
646      return winMouseButtonsHandle (s_pScreen, ButtonPress, Button3, wParam);
647
648    case WM_RBUTTONUP:
649      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
650	break;
651      g_fButton[2] = FALSE;
652      ReleaseCapture();
653      winStartMousePolling(s_pScreenPriv);
654      return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button3, wParam);
655
656    case WM_XBUTTONDBLCLK:
657    case WM_XBUTTONDOWN:
658      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
659	break;
660	SetCapture(hwnd);
661      return winMouseButtonsHandle (s_pScreen, ButtonPress, HIWORD(wParam) + 5, wParam);
662
663    case WM_XBUTTONUP:
664      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
665	break;
666      ReleaseCapture();
667      winStartMousePolling(s_pScreenPriv);
668      return winMouseButtonsHandle (s_pScreen, ButtonRelease, HIWORD(wParam) + 5, wParam);
669
670    case WM_MOUSEWHEEL:
671      if (SendMessage(hwnd, WM_NCHITTEST, 0, MAKELONG(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) == HTCLIENT)
672	{
673	  /* Pass the message to the root window */
674	  SendMessage (hwndScreen, message, wParam, lParam);
675	  return 0;
676	}
677      else break;
678
679    case WM_SETFOCUS:
680      if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
681	break;
682
683      {
684	/* Get the parent window for transient handling */
685	HWND hParent = GetParent(hwnd);
686	if (hParent && IsIconic(hParent)) ShowWindow (hParent, SW_RESTORE);
687      }
688
689      winRestoreModeKeyStates ();
690
691      /* Add the keyboard hook if possible */
692      if (g_fKeyboardHookLL)
693	g_fKeyboardHookLL = winInstallKeyboardHookLL ();
694      return 0;
695
696    case WM_KILLFOCUS:
697      /* Pop any pressed keys since we are losing keyboard focus */
698      winKeybdReleaseKeys ();
699
700      /* Remove our keyboard hook if it is installed */
701      winRemoveKeyboardHookLL ();
702      if (!wParam)
703	/* Revert the X focus as well, but only if the Windows focus is going to another window */
704	DeleteWindowFromAnyEvents(pWin, FALSE);
705      return 0;
706
707    case WM_SYSDEADCHAR:
708    case WM_DEADCHAR:
709      /*
710       * NOTE: We do nothing with WM_*CHAR messages,
711       * nor does the root window, so we can just toss these messages.
712       */
713      return 0;
714
715    case WM_SYSKEYDOWN:
716    case WM_KEYDOWN:
717
718      /*
719       * Don't pass Alt-F4 key combo to root window,
720       * let Windows translate to WM_CLOSE and close this top-level window.
721       *
722       * NOTE: We purposely don't check the fUseWinKillKey setting because
723       * it should only apply to the key handling for the root window,
724       * not for top-level window-manager windows.
725       *
726       * ALSO NOTE: We do pass Ctrl-Alt-Backspace to the root window
727       * because that is a key combo that no X app should be expecting to
728       * receive, since it has historically been used to shutdown the X server.
729       * Passing Ctrl-Alt-Backspace to the root window preserves that
730       * behavior, assuming that -unixkill has been passed as a parameter.
731       */
732      if (wParam == VK_F4 && (GetKeyState (VK_MENU) & 0x8000))
733	  break;
734
735#if CYGWINDOWING_DEBUG
736      if (wParam == VK_ESCAPE)
737	{
738	  /* Place for debug: put any tests and dumps here */
739	  WINDOWPLACEMENT windPlace;
740	  RECT rc;
741	  LPRECT pRect;
742
743	  windPlace.length = sizeof (WINDOWPLACEMENT);
744	  GetWindowPlacement (hwnd, &windPlace);
745	  pRect = &windPlace.rcNormalPosition;
746	  ErrorF ("\nCYGWINDOWING Dump:\n"
747		  "\tdrawable: (%hd, %hd) - %hdx%hd\n", pDraw->x,
748		  pDraw->y, pDraw->width, pDraw->height);
749	  ErrorF ("\twindPlace: (%ld, %ld) - %ldx%ld\n", pRect->left,
750		  pRect->top, pRect->right - pRect->left,
751		  pRect->bottom - pRect->top);
752	  if (GetClientRect (hwnd, &rc))
753	    {
754	      pRect = &rc;
755	      ErrorF ("\tClientRect: (%ld, %ld) - %ldx%ld\n", pRect->left,
756		      pRect->top, pRect->right - pRect->left,
757		      pRect->bottom - pRect->top);
758	    }
759	  if (GetWindowRect (hwnd, &rc))
760	    {
761	      pRect = &rc;
762	      ErrorF ("\tWindowRect: (%ld, %ld) - %ldx%ld\n", pRect->left,
763		      pRect->top, pRect->right - pRect->left,
764		      pRect->bottom - pRect->top);
765	    }
766	  ErrorF ("\n");
767	}
768#endif
769
770      /* Pass the message to the root window */
771      return winWindowProc(hwndScreen, message, wParam, lParam);
772
773    case WM_SYSKEYUP:
774    case WM_KEYUP:
775
776
777      /* Pass the message to the root window */
778      return winWindowProc(hwndScreen, message, wParam, lParam);
779
780    case WM_HOTKEY:
781
782      /* Pass the message to the root window */
783      SendMessage (hwndScreen, message, wParam, lParam);
784      return 0;
785
786    case WM_ACTIVATE:
787
788      /* Pass the message to the root window */
789      SendMessage (hwndScreen, message, wParam, lParam);
790
791      if (LOWORD(wParam) != WA_INACTIVE)
792	{
793	  /* Raise the window to the top in Z order */
794          /* ago: Activate does not mean putting it to front! */
795          /*
796	  wmMsg.msg = WM_WM_RAISE;
797	  if (fWMMsgInitialized)
798	    winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg);
799          */
800
801	  /* Tell our Window Manager thread to activate the window */
802	  wmMsg.msg = WM_WM_ACTIVATE;
803	  if (fWMMsgInitialized)
804	    if (!pWin || !pWin->overrideRedirect) /* for OOo menus */
805	      winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg);
806	}
807      /* Prevent the mouse wheel from stalling when another window is minimized */
808      if (HIWORD(wParam) == 0 && LOWORD(wParam) == WA_ACTIVE &&
809	  (HWND)lParam != NULL && (HWND)lParam != (HWND)GetParent(hwnd))
810	SetFocus(hwnd);
811      return 0;
812
813    case WM_ACTIVATEAPP:
814      /*
815       * This message is also sent to the root window
816       * so we do nothing for individual multiwindow windows
817       */
818      break;
819
820    case WM_CLOSE:
821      /* Branch on if the window was killed in X already */
822      if (pWinPriv->fXKilled)
823        {
824	  /* Window was killed, go ahead and destroy the window */
825	  DestroyWindow (hwnd);
826	}
827      else
828	{
829	  /* Tell our Window Manager thread to kill the window */
830	  wmMsg.msg = WM_WM_KILL;
831	  if (fWMMsgInitialized)
832	    winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg);
833	}
834      return 0;
835
836    case WM_DESTROY:
837
838      /* Branch on if the window was killed in X already */
839      if (pWinPriv && !pWinPriv->fXKilled)
840	{
841	  ErrorF ("winTopLevelWindowProc - WM_DESTROY - WM_WM_KILL\n");
842
843	  /* Tell our Window Manager thread to kill the window */
844	  wmMsg.msg = WM_WM_KILL;
845	  if (fWMMsgInitialized)
846	    winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg);
847	}
848
849      RemoveProp (hwnd, WIN_WINDOW_PROP);
850      RemoveProp (hwnd, WIN_WID_PROP);
851      RemoveProp (hwnd, WIN_NEEDMANAGE_PROP);
852
853      break;
854
855    case WM_MOVE:
856      /* Adjust the X Window to the moved Windows window */
857      winAdjustXWindow (pWin, hwnd);
858      return 0;
859
860    case WM_SHOWWINDOW:
861      /* Bail out if the window is being hidden */
862      if (!wParam)
863	return 0;
864
865      /* */
866      if (!pWin->overrideRedirect)
867	{
868	  /* Flag that this window needs to be made active when clicked */
869	  SetProp (hwnd, WIN_NEEDMANAGE_PROP, (HANDLE) 1);
870
871	  if (!(GetWindowLongPtr (hwnd, GWL_EXSTYLE) & WS_EX_APPWINDOW))
872	    {
873	      HWND		zstyle = HWND_NOTOPMOST;
874
875	      /* Set the window extended style flags */
876	      SetWindowLongPtr (hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW);
877
878	      /* Set the transient style flags */
879	      if (GetParent(hwnd)) SetWindowLongPtr (hwnd, GWL_STYLE,
880		   WS_POPUP | WS_OVERLAPPED | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
881	      /* Set the window standard style flags */
882	      else SetWindowLongPtr (hwnd, GWL_STYLE,
883		   (WS_POPUP | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
884		   & ~WS_CAPTION & ~WS_SIZEBOX);
885
886	      winUpdateWindowPosition (hwnd, FALSE, &zstyle);
887	      SetForegroundWindow (hwnd);
888	    }
889	  wmMsg.msg = WM_WM_MAP3;
890	}
891      else /* It is an overridden window so make it top of Z stack */
892	{
893	  HWND forHwnd = GetForegroundWindow();
894#if CYGWINDOWING_DEBUG
895	  ErrorF ("overridden window is shown\n");
896#endif
897	  if (forHwnd != NULL)
898	  {
899	    if (GetWindowLongPtr(forHwnd, GWLP_USERDATA) & (LONG_PTR)XMING_SIGNATURE)
900	    {
901	      if (GetWindowLongPtr(forHwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
902		SetWindowPos (hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
903	      else
904		SetWindowPos (hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
905	    }
906	  }
907	  wmMsg.msg = WM_WM_MAP2;
908	}
909
910      /* Tell our Window Manager thread to map the window */
911      if (fWMMsgInitialized)
912	winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg);
913
914      winStartMousePolling(s_pScreenPriv);
915
916      return 0;
917
918    case WM_SIZING:
919      /* Need to legalize the size according to WM_NORMAL_HINTS */
920      /* for applications like xterm */
921      return ValidateSizing (hwnd, pWin, wParam, lParam);
922
923    case WM_WINDOWPOSCHANGED:
924      {
925	LPWINDOWPOS pWinPos = (LPWINDOWPOS) lParam;
926
927	if (!(pWinPos->flags & SWP_NOZORDER))
928	  {
929#if CYGWINDOWING_DEBUG
930	    winDebug ("\twindow z order was changed\n");
931#endif
932	    if (pWinPos->hwndInsertAfter == HWND_TOP
933		||pWinPos->hwndInsertAfter == HWND_TOPMOST
934		||pWinPos->hwndInsertAfter == HWND_NOTOPMOST)
935	      {
936#if CYGWINDOWING_DEBUG
937		winDebug ("\traise to top\n");
938#endif
939		/* Raise the window to the top in Z order */
940		winRaiseWindow(pWin);
941	      }
942	    else if (pWinPos->hwndInsertAfter == HWND_BOTTOM)
943	      {
944	      }
945	    else
946	      {
947		/* Check if this window is top of X windows. */
948		HWND hWndAbove = NULL;
949		DWORD dwCurrentProcessID = GetCurrentProcessId ();
950		DWORD dwWindowProcessID = 0;
951
952		for (hWndAbove = pWinPos->hwndInsertAfter;
953		     hWndAbove != NULL;
954		     hWndAbove = GetNextWindow (hWndAbove, GW_HWNDPREV))
955		  {
956		    /* Ignore other XWin process's window */
957		    GetWindowThreadProcessId (hWndAbove, &dwWindowProcessID);
958
959		    if ((dwWindowProcessID == dwCurrentProcessID)
960			&& GetProp (hWndAbove, WIN_WINDOW_PROP)
961			&& !IsWindowVisible (hWndAbove)
962			&& !IsIconic (hWndAbove) ) /* ignore minimized windows */
963		      break;
964		  }
965		/* If this is top of X windows in Windows stack,
966		   raise it in X stack. */
967		if (hWndAbove == NULL)
968		  {
969#if CYGWINDOWING_DEBUG
970		    winDebug ("\traise to top\n");
971#endif
972		    winRaiseWindow(pWin);
973		  }
974	      }
975	  }
976      }
977      /*
978       * Pass the message to DefWindowProc to let the function
979       * break down WM_WINDOWPOSCHANGED to WM_MOVE and WM_SIZE.
980      */
981      break;
982
983    case WM_SIZE:
984      /* see dix/window.c */
985#if CYGWINDOWING_DEBUG
986      {
987	char buf[64];
988	switch (wParam)
989	  {
990	  case SIZE_MINIMIZED:
991	    strcpy(buf, "SIZE_MINIMIZED");
992	    break;
993	  case SIZE_MAXIMIZED:
994	    strcpy(buf, "SIZE_MAXIMIZED");
995	    break;
996	  case SIZE_RESTORED:
997	    strcpy(buf, "SIZE_RESTORED");
998	    break;
999	  default:
1000	    strcpy(buf, "UNKNOWN_FLAG");
1001	  }
1002	ErrorF ("winTopLevelWindowProc - WM_SIZE to %dx%d (%s) - %d ms\n",
1003		(int)LOWORD(lParam), (int)HIWORD(lParam), buf,
1004		(int)(GetTickCount ()));
1005      }
1006#endif
1007      /* Adjust the X Window to the moved Windows window */
1008      winAdjustXWindow (pWin, hwnd);
1009      return 0; /* end of WM_SIZE handler */
1010
1011    case WM_MOUSEACTIVATE:
1012
1013      /* Check if this window needs to be made active when clicked */
1014      if (!GetProp (pWinPriv->hWnd, WIN_NEEDMANAGE_PROP))
1015	{
1016#if CYGMULTIWINDOW_DEBUG
1017	  ErrorF ("winTopLevelWindowProc - WM_MOUSEACTIVATE - "
1018		  "MA_NOACTIVATE\n");
1019#endif
1020
1021	  /* */
1022	  return MA_NOACTIVATE;
1023	}
1024      break;
1025
1026    case WM_SETCURSOR:
1027      if (LOWORD(lParam) == HTCLIENT)
1028	{
1029	  if (!g_fSoftwareCursor) SetCursor (s_pScreenPriv->cursor.handle);
1030	  return TRUE;
1031	}
1032      break;
1033
1034    default:
1035      break;
1036    }
1037
1038  ret = DefWindowProc (hwnd, message, wParam, lParam);
1039  /*
1040   * If the window was minized we get the stack change before the window is restored
1041   * and so it gets lost. Ensure there stacking order is correct.
1042   */
1043  if (needRestack)
1044    winReorderWindowsMultiWindow();
1045  return ret;
1046}
1047