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