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