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
45 extern void winUpdateWindowPosition(HWND hWnd, HWND * zstyle);
46
47 /*
48 * Local globals
49 */
50
51 static 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)) )
63 static void
ConstrainSize(WinXSizeHints hints,int * widthp,int * heightp)64 ConstrainSize(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 */
190 static int
ValidateSizing(HWND hwnd,WindowPtr pWin,WPARAM wParam,LPARAM lParam)191 ValidateSizing(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
265 extern Bool winInDestroyWindowsWindow;
266 static Bool winInRaiseWindow = FALSE;
267 static void
winRaiseWindow(WindowPtr pWin)268 winRaiseWindow(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
282 static
283 void
winStartMousePolling(winPrivScreenPtr s_pScreenPriv)284 winStartMousePolling(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
301 LRESULT CALLBACK
winTopLevelWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)302 winTopLevelWindowProc(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 static Bool hasEnteredSizeMove = FALSE;
320
321 #if CYGDEBUG
322 winDebugWin32Message("winTopLevelWindowProc", hwnd, message, wParam,
323 lParam);
324 #endif
325
326 /* Check if the Windows window property for our X window pointer is valid */
327 if ((pWin = GetProp(hwnd, WIN_WINDOW_PROP)) != NULL) {
328 /* Our X window pointer is valid */
329
330 /* Get pointers to the drawable and the screen */
331 pDraw = &pWin->drawable;
332 s_pScreen = pWin->drawable.pScreen;
333
334 /* Get a pointer to our window privates */
335 pWinPriv = winGetWindowPriv(pWin);
336
337 /* Get pointers to our screen privates and screen info */
338 s_pScreenPriv = pWinPriv->pScreenPriv;
339 s_pScreenInfo = s_pScreenPriv->pScreenInfo;
340
341 /* Get the handle for our screen-sized window */
342 hwndScreen = s_pScreenPriv->hwndScreen;
343
344 /* */
345 wmMsg.msg = 0;
346 wmMsg.hwndWindow = hwnd;
347 wmMsg.iWindow = (Window) (INT_PTR) GetProp(hwnd, WIN_WID_PROP);
348
349 wmMsg.iX = pDraw->x;
350 wmMsg.iY = pDraw->y;
351 wmMsg.iWidth = pDraw->width;
352 wmMsg.iHeight = pDraw->height;
353
354 fWMMsgInitialized = TRUE;
355
356 #if 0
357 /*
358 * Print some debugging information
359 */
360
361 ErrorF("hWnd %08X\n", hwnd);
362 ErrorF("pWin %08X\n", pWin);
363 ErrorF("pDraw %08X\n", pDraw);
364 ErrorF("\ttype %08X\n", pWin->drawable.type);
365 ErrorF("\tclass %08X\n", pWin->drawable.class);
366 ErrorF("\tdepth %08X\n", pWin->drawable.depth);
367 ErrorF("\tbitsPerPixel %08X\n", pWin->drawable.bitsPerPixel);
368 ErrorF("\tid %08X\n", pWin->drawable.id);
369 ErrorF("\tx %08X\n", pWin->drawable.x);
370 ErrorF("\ty %08X\n", pWin->drawable.y);
371 ErrorF("\twidth %08X\n", pWin->drawable.width);
372 ErrorF("\thenght %08X\n", pWin->drawable.height);
373 ErrorF("\tpScreen %08X\n", pWin->drawable.pScreen);
374 ErrorF("\tserialNumber %08X\n", pWin->drawable.serialNumber);
375 ErrorF("g_iWindowPrivateKey %p\n", g_iWindowPrivateKey);
376 ErrorF("pWinPriv %08X\n", pWinPriv);
377 ErrorF("s_pScreenPriv %08X\n", s_pScreenPriv);
378 ErrorF("s_pScreenInfo %08X\n", s_pScreenInfo);
379 ErrorF("hwndScreen %08X\n", hwndScreen);
380 #endif
381 }
382
383 /* Branch on message type */
384 switch (message) {
385 case WM_CREATE:
386
387 /* */
388 SetProp(hwnd,
389 WIN_WINDOW_PROP,
390 (HANDLE) ((LPCREATESTRUCT) lParam)->lpCreateParams);
391
392 /* */
393 SetProp(hwnd,
394 WIN_WID_PROP,
395 (HANDLE) (INT_PTR) winGetWindowID(((LPCREATESTRUCT) lParam)->
396 lpCreateParams));
397
398 /*
399 * Make X windows' Z orders sync with Windows windows because
400 * there can be AlwaysOnTop windows overlapped on the window
401 * currently being created.
402 */
403 winReorderWindowsMultiWindow();
404
405 /* Fix a 'round title bar corner background should be transparent not black' problem when first painted */
406 {
407 RECT rWindow;
408 HRGN hRgnWindow;
409
410 GetWindowRect(hwnd, &rWindow);
411 hRgnWindow = CreateRectRgnIndirect(&rWindow);
412 SetWindowRgn(hwnd, hRgnWindow, TRUE);
413 DeleteObject(hRgnWindow);
414 }
415
416 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) XMING_SIGNATURE);
417
418 return 0;
419
420 case WM_INIT_SYS_MENU:
421 /*
422 * Add whatever the setup file wants to for this window
423 */
424 SetupSysMenu(hwnd);
425 return 0;
426
427 case WM_SYSCOMMAND:
428 /*
429 * Any window menu items go through here
430 */
431 if (HandleCustomWM_COMMAND(hwnd, LOWORD(wParam), s_pScreenPriv)) {
432 /* Don't pass customized menus to DefWindowProc */
433 return 0;
434 }
435 if (wParam == SC_RESTORE || wParam == SC_MAXIMIZE) {
436 WINDOWPLACEMENT wndpl;
437
438 wndpl.length = sizeof(wndpl);
439 if (GetWindowPlacement(hwnd, &wndpl) &&
440 wndpl.showCmd == SW_SHOWMINIMIZED)
441 needRestack = TRUE;
442 }
443 break;
444
445 case WM_INITMENU:
446 /* Checks/Unchecks any menu items before they are displayed */
447 HandleCustomWM_INITMENU(hwnd, (HMENU)wParam);
448 break;
449
450 case WM_ERASEBKGND:
451 /*
452 * Pretend that we did erase the background but we don't care,
453 * since we repaint the entire region anyhow
454 * This avoids some flickering when resizing.
455 */
456 return TRUE;
457
458 case WM_PAINT:
459 /* Only paint if our window handle is valid */
460 if (hwndScreen == NULL)
461 break;
462
463 /* BeginPaint gives us an hdc that clips to the invalidated region */
464 hdcUpdate = BeginPaint(hwnd, &ps);
465 /* Avoid the BitBlt's if the PAINTSTRUCT is bogus */
466 if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 &&
467 ps.rcPaint.left == 0 && ps.rcPaint.top == 0) {
468 EndPaint(hwnd, &ps);
469 return 0;
470 }
471
472 #ifdef XWIN_GLX_WINDOWS
473 if (pWinPriv->fWglUsed) {
474 /*
475 For regions which are being drawn by GL, the shadow framebuffer doesn't have the
476 correct bits, so don't bitblt from the shadow framebuffer
477
478 XXX: For now, just leave it alone, but ideally we want to send an expose event to
479 the window so it really redraws the affected region...
480 */
481 ValidateRect(hwnd, &(ps.rcPaint));
482 }
483 else
484 #endif
485 /* Try to copy from the shadow buffer */
486 if (!BitBlt(hdcUpdate,
487 ps.rcPaint.left, ps.rcPaint.top,
488 ps.rcPaint.right - ps.rcPaint.left,
489 ps.rcPaint.bottom - ps.rcPaint.top,
490 s_pScreenPriv->hdcShadow,
491 ps.rcPaint.left + pWin->drawable.x,
492 ps.rcPaint.top + pWin->drawable.y, SRCCOPY)) {
493 LPVOID lpMsgBuf;
494
495 /* Display a fancy error message */
496 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
497 FORMAT_MESSAGE_FROM_SYSTEM |
498 FORMAT_MESSAGE_IGNORE_INSERTS,
499 NULL,
500 GetLastError(),
501 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
502 (LPTSTR) &lpMsgBuf, 0, NULL);
503
504 ErrorF("winTopLevelWindowProc - BitBlt failed: %s\n",
505 (LPSTR) lpMsgBuf);
506 LocalFree(lpMsgBuf);
507 }
508
509 /* EndPaint frees the DC */
510 EndPaint(hwnd, &ps);
511 return 0;
512
513 case WM_MOUSEMOVE:
514 /* Unpack the client area mouse coordinates */
515 ptMouse.x = GET_X_LPARAM(lParam);
516 ptMouse.y = GET_Y_LPARAM(lParam);
517
518 /* Translate the client area mouse coordinates to screen coordinates */
519 ClientToScreen(hwnd, &ptMouse);
520
521 /* Screen Coords from (-X, -Y) -> Root Window (0, 0) */
522 ptMouse.x -= GetSystemMetrics(SM_XVIRTUALSCREEN);
523 ptMouse.y -= GetSystemMetrics(SM_YVIRTUALSCREEN);
524
525 /* We can't do anything without privates */
526 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
527 break;
528
529 /* Has the mouse pointer crossed screens? */
530 if (s_pScreen != miPointerGetScreen(g_pwinPointer))
531 miPointerSetScreen(g_pwinPointer, s_pScreenInfo->dwScreen,
532 ptMouse.x - s_pScreenInfo->dwXOffset,
533 ptMouse.y - s_pScreenInfo->dwYOffset);
534
535 /* Are we tracking yet? */
536 if (!s_fTracking) {
537 TRACKMOUSEEVENT tme;
538
539 /* Setup data structure */
540 ZeroMemory(&tme, sizeof(tme));
541 tme.cbSize = sizeof(tme);
542 tme.dwFlags = TME_LEAVE;
543 tme.hwndTrack = hwnd;
544
545 /* Call the tracking function */
546 if (!TrackMouseEvent(&tme))
547 ErrorF("winTopLevelWindowProc - TrackMouseEvent failed\n");
548
549 /* Flag that we are tracking now */
550 s_fTracking = TRUE;
551 }
552
553 /* Hide or show the Windows mouse cursor */
554 if (g_fSoftwareCursor && g_fCursor) {
555 /* Hide Windows cursor */
556 g_fCursor = FALSE;
557 ShowCursor(FALSE);
558 }
559
560 /* Kill the timer used to poll mouse events */
561 if (g_uipMousePollingTimerID != 0) {
562 KillTimer(s_pScreenPriv->hwndScreen, WIN_POLLING_MOUSE_TIMER_ID);
563 g_uipMousePollingTimerID = 0;
564 }
565
566 /* Deliver absolute cursor position to X Server */
567 winEnqueueMotion(ptMouse.x - s_pScreenInfo->dwXOffset,
568 ptMouse.y - s_pScreenInfo->dwYOffset);
569
570 return 0;
571
572 case WM_NCMOUSEMOVE:
573 /*
574 * We break instead of returning 0 since we need to call
575 * DefWindowProc to get the mouse cursor changes
576 * and min/max/close button highlighting in Windows XP.
577 * The Platform SDK says that you should return 0 if you
578 * process this message, but it fails to mention that you
579 * will give up any default functionality if you do return 0.
580 */
581
582 /* We can't do anything without privates */
583 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
584 break;
585
586 /* Non-client mouse movement, show Windows cursor */
587 if (g_fSoftwareCursor && !g_fCursor) {
588 g_fCursor = TRUE;
589 ShowCursor(TRUE);
590 }
591
592 winStartMousePolling(s_pScreenPriv);
593
594 break;
595
596 case WM_MOUSELEAVE:
597 /* Mouse has left our client area */
598
599 /* Flag that we are no longer tracking */
600 s_fTracking = FALSE;
601
602 /* Show the mouse cursor, if necessary */
603 if (g_fSoftwareCursor && !g_fCursor) {
604 g_fCursor = TRUE;
605 ShowCursor(TRUE);
606 }
607
608 winStartMousePolling(s_pScreenPriv);
609
610 return 0;
611
612 case WM_LBUTTONDBLCLK:
613 case WM_LBUTTONDOWN:
614 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
615 break;
616 g_fButton[0] = TRUE;
617 SetCapture(hwnd);
618 return winMouseButtonsHandle(s_pScreen, ButtonPress, Button1, wParam);
619
620 case WM_LBUTTONUP:
621 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
622 break;
623 g_fButton[0] = FALSE;
624 ReleaseCapture();
625 winStartMousePolling(s_pScreenPriv);
626 return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button1, wParam);
627
628 case WM_MBUTTONDBLCLK:
629 case WM_MBUTTONDOWN:
630 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
631 break;
632 g_fButton[1] = TRUE;
633 SetCapture(hwnd);
634 return winMouseButtonsHandle(s_pScreen, ButtonPress, Button2, wParam);
635
636 case WM_MBUTTONUP:
637 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
638 break;
639 g_fButton[1] = FALSE;
640 ReleaseCapture();
641 winStartMousePolling(s_pScreenPriv);
642 return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button2, wParam);
643
644 case WM_RBUTTONDBLCLK:
645 case WM_RBUTTONDOWN:
646 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
647 break;
648 g_fButton[2] = TRUE;
649 SetCapture(hwnd);
650 return winMouseButtonsHandle(s_pScreen, ButtonPress, Button3, wParam);
651
652 case WM_RBUTTONUP:
653 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
654 break;
655 g_fButton[2] = FALSE;
656 ReleaseCapture();
657 winStartMousePolling(s_pScreenPriv);
658 return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button3, wParam);
659
660 case WM_XBUTTONDBLCLK:
661 case WM_XBUTTONDOWN:
662 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
663 break;
664 SetCapture(hwnd);
665 return winMouseButtonsHandle(s_pScreen, ButtonPress, HIWORD(wParam) + 7,
666 wParam);
667
668 case WM_XBUTTONUP:
669 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
670 break;
671 ReleaseCapture();
672 winStartMousePolling(s_pScreenPriv);
673 return winMouseButtonsHandle(s_pScreen, ButtonRelease,
674 HIWORD(wParam) + 7, wParam);
675
676 case WM_MOUSEWHEEL:
677 if (SendMessage
678 (hwnd, WM_NCHITTEST, 0,
679 MAKELONG(GET_X_LPARAM(lParam),
680 GET_Y_LPARAM(lParam))) == HTCLIENT) {
681 /* Pass the message to the root window */
682 SendMessage(hwndScreen, message, wParam, lParam);
683 return 0;
684 }
685 else
686 break;
687
688 case WM_MOUSEHWHEEL:
689 if (SendMessage
690 (hwnd, WM_NCHITTEST, 0,
691 MAKELONG(GET_X_LPARAM(lParam),
692 GET_Y_LPARAM(lParam))) == HTCLIENT) {
693 /* Pass the message to the root window */
694 SendMessage(hwndScreen, message, wParam, lParam);
695 return 0;
696 }
697 else
698 break;
699
700 case WM_SETFOCUS:
701 if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
702 break;
703
704 {
705 /* Get the parent window for transient handling */
706 HWND hParent = GetParent(hwnd);
707
708 if (hParent && IsIconic(hParent))
709 ShowWindow(hParent, SW_RESTORE);
710 }
711
712 winRestoreModeKeyStates();
713
714 /* Add the keyboard hook if possible */
715 if (g_fKeyboardHookLL)
716 g_fKeyboardHookLL = winInstallKeyboardHookLL();
717 return 0;
718
719 case WM_KILLFOCUS:
720 /* Pop any pressed keys since we are losing keyboard focus */
721 winKeybdReleaseKeys();
722
723 /* Remove our keyboard hook if it is installed */
724 winRemoveKeyboardHookLL();
725
726 /* Revert the X focus as well, but only if the Windows focus is going to another window */
727 if (!wParam && pWin)
728 DeleteWindowFromAnyEvents(pWin, FALSE);
729
730 return 0;
731
732 case WM_SYSDEADCHAR:
733 case WM_DEADCHAR:
734 /*
735 * NOTE: We do nothing with WM_*CHAR messages,
736 * nor does the root window, so we can just toss these messages.
737 */
738 return 0;
739
740 case WM_SYSKEYDOWN:
741 case WM_KEYDOWN:
742
743 /*
744 * Don't pass Alt-F4 key combo to root window,
745 * let Windows translate to WM_CLOSE and close this top-level window.
746 *
747 * NOTE: We purposely don't check the fUseWinKillKey setting because
748 * it should only apply to the key handling for the root window,
749 * not for top-level window-manager windows.
750 *
751 * ALSO NOTE: We do pass Ctrl-Alt-Backspace to the root window
752 * because that is a key combo that no X app should be expecting to
753 * receive, since it has historically been used to shutdown the X server.
754 * Passing Ctrl-Alt-Backspace to the root window preserves that
755 * behavior, assuming that -unixkill has been passed as a parameter.
756 */
757 if (wParam == VK_F4 && (GetKeyState(VK_MENU) & 0x8000))
758 break;
759
760 #if CYGWINDOWING_DEBUG
761 if (wParam == VK_ESCAPE) {
762 /* Place for debug: put any tests and dumps here */
763 WINDOWPLACEMENT windPlace;
764 RECT rc;
765 LPRECT pRect;
766
767 windPlace.length = sizeof(WINDOWPLACEMENT);
768 GetWindowPlacement(hwnd, &windPlace);
769 pRect = &windPlace.rcNormalPosition;
770 ErrorF("\nCYGWINDOWING Dump:\n"
771 "\tdrawable: (%hd, %hd) - %hdx%hd\n", pDraw->x,
772 pDraw->y, pDraw->width, pDraw->height);
773 ErrorF("\twindPlace: (%d, %d) - %dx%d\n", (int)pRect->left,
774 (int)pRect->top, (int)(pRect->right - pRect->left),
775 (int)(pRect->bottom - pRect->top));
776 if (GetClientRect(hwnd, &rc)) {
777 pRect = &rc;
778 ErrorF("\tClientRect: (%d, %d) - %dx%d\n", (int)pRect->left,
779 (int)pRect->top, (int)(pRect->right - pRect->left),
780 (int)(pRect->bottom - pRect->top));
781 }
782 if (GetWindowRect(hwnd, &rc)) {
783 pRect = &rc;
784 ErrorF("\tWindowRect: (%d, %d) - %dx%d\n", (int)pRect->left,
785 (int)pRect->top, (int)(pRect->right - pRect->left),
786 (int)(pRect->bottom - pRect->top));
787 }
788 ErrorF("\n");
789 }
790 #endif
791
792 /* Pass the message to the root window */
793 return winWindowProc(hwndScreen, message, wParam, lParam);
794
795 case WM_SYSKEYUP:
796 case WM_KEYUP:
797
798 /* Pass the message to the root window */
799 return winWindowProc(hwndScreen, message, wParam, lParam);
800
801 case WM_HOTKEY:
802
803 /* Pass the message to the root window */
804 SendMessage(hwndScreen, message, wParam, lParam);
805 return 0;
806
807 case WM_ACTIVATE:
808
809 /* Pass the message to the root window */
810 SendMessage(hwndScreen, message, wParam, lParam);
811
812 if (LOWORD(wParam) != WA_INACTIVE) {
813 /* Raise the window to the top in Z order */
814 /* ago: Activate does not mean putting it to front! */
815 /*
816 wmMsg.msg = WM_WM_RAISE;
817 if (fWMMsgInitialized)
818 winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg);
819 */
820
821 /* Tell our Window Manager thread to activate the window */
822 wmMsg.msg = WM_WM_ACTIVATE;
823 if (fWMMsgInitialized)
824 if (!pWin || !pWin->overrideRedirect) /* for OOo menus */
825 winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
826 }
827 /* Prevent the mouse wheel from stalling when another window is minimized */
828 if (HIWORD(wParam) == 0 && LOWORD(wParam) == WA_ACTIVE &&
829 (HWND) lParam != NULL && (HWND) lParam != GetParent(hwnd))
830 SetFocus(hwnd);
831 return 0;
832
833 case WM_ACTIVATEAPP:
834 /*
835 * This message is also sent to the root window
836 * so we do nothing for individual multiwindow windows
837 */
838 break;
839
840 case WM_CLOSE:
841 /* Remove AppUserModelID property */
842 winSetAppUserModelID(hwnd, NULL);
843 /* Branch on if the window was killed in X already */
844 if (pWinPriv->fXKilled) {
845 /* Window was killed, go ahead and destroy the window */
846 DestroyWindow(hwnd);
847 }
848 else {
849 /* Tell our Window Manager thread to kill the window */
850 wmMsg.msg = WM_WM_KILL;
851 if (fWMMsgInitialized)
852 winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
853 }
854 return 0;
855
856 case WM_DESTROY:
857
858 /* Branch on if the window was killed in X already */
859 if (pWinPriv && !pWinPriv->fXKilled) {
860 ErrorF("winTopLevelWindowProc - WM_DESTROY - WM_WM_KILL\n");
861
862 /* Tell our Window Manager thread to kill the window */
863 wmMsg.msg = WM_WM_KILL;
864 if (fWMMsgInitialized)
865 winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
866 }
867
868 RemoveProp(hwnd, WIN_WINDOW_PROP);
869 RemoveProp(hwnd, WIN_WID_PROP);
870 RemoveProp(hwnd, WIN_NEEDMANAGE_PROP);
871
872 break;
873
874 case WM_MOVE:
875 /* Adjust the X Window to the moved Windows window */
876 if (!hasEnteredSizeMove)
877 winAdjustXWindow(pWin, hwnd);
878 /* else: Wait for WM_EXITSIZEMOVE */
879 return 0;
880
881 case WM_SHOWWINDOW:
882 /* Bail out if the window is being hidden */
883 if (!wParam)
884 return 0;
885
886 /* */
887 if (!pWin->overrideRedirect) {
888 HWND zstyle = HWND_NOTOPMOST;
889
890 /* Flag that this window needs to be made active when clicked */
891 SetProp(hwnd, WIN_NEEDMANAGE_PROP, (HANDLE) 1);
892
893 /* Set the transient style flags */
894 if (GetParent(hwnd))
895 SetWindowLongPtr(hwnd, GWL_STYLE,
896 WS_POPUP | WS_OVERLAPPED | WS_SYSMENU |
897 WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
898 /* Set the window standard style flags */
899 else
900 SetWindowLongPtr(hwnd, GWL_STYLE,
901 (WS_POPUP | WS_OVERLAPPEDWINDOW |
902 WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
903 & ~WS_CAPTION & ~WS_SIZEBOX);
904
905 winUpdateWindowPosition(hwnd, &zstyle);
906
907 {
908 WinXWMHints hints;
909
910 if (winMultiWindowGetWMHints(pWin, &hints)) {
911 /*
912 Give the window focus, unless it has an InputHint
913 which is FALSE (this is used by e.g. glean to
914 avoid every test window grabbing the focus)
915 */
916 if (!((hints.flags & InputHint) && (!hints.input))) {
917 SetForegroundWindow(hwnd);
918 }
919 }
920 }
921 wmMsg.msg = WM_WM_MAP3;
922 }
923 else { /* It is an overridden window so make it top of Z stack */
924
925 HWND forHwnd = GetForegroundWindow();
926
927 #if CYGWINDOWING_DEBUG
928 ErrorF("overridden window is shown\n");
929 #endif
930 if (forHwnd != NULL) {
931 if (GetWindowLongPtr(forHwnd, GWLP_USERDATA) & (LONG_PTR)
932 XMING_SIGNATURE) {
933 if (GetWindowLongPtr(forHwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
934 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
935 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
936 else
937 SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
938 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
939 }
940 }
941 wmMsg.msg = WM_WM_MAP2;
942 }
943
944 /* Tell our Window Manager thread to map the window */
945 if (fWMMsgInitialized)
946 winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
947
948 winStartMousePolling(s_pScreenPriv);
949
950 return 0;
951
952 case WM_SIZING:
953 /* Need to legalize the size according to WM_NORMAL_HINTS */
954 /* for applications like xterm */
955 return ValidateSizing(hwnd, pWin, wParam, lParam);
956
957 case WM_WINDOWPOSCHANGED:
958 {
959 LPWINDOWPOS pWinPos = (LPWINDOWPOS) lParam;
960
961 if (!(pWinPos->flags & SWP_NOZORDER)) {
962 #if CYGWINDOWING_DEBUG
963 winDebug("\twindow z order was changed\n");
964 #endif
965 if (pWinPos->hwndInsertAfter == HWND_TOP
966 || pWinPos->hwndInsertAfter == HWND_TOPMOST
967 || pWinPos->hwndInsertAfter == HWND_NOTOPMOST) {
968 #if CYGWINDOWING_DEBUG
969 winDebug("\traise to top\n");
970 #endif
971 /* Raise the window to the top in Z order */
972 winRaiseWindow(pWin);
973 }
974 else if (pWinPos->hwndInsertAfter == HWND_BOTTOM) {
975 }
976 else {
977 /* Check if this window is top of X windows. */
978 HWND hWndAbove = NULL;
979 DWORD dwCurrentProcessID = GetCurrentProcessId();
980 DWORD dwWindowProcessID = 0;
981
982 for (hWndAbove = pWinPos->hwndInsertAfter;
983 hWndAbove != NULL;
984 hWndAbove = GetNextWindow(hWndAbove, GW_HWNDPREV)) {
985 /* Ignore other XWin process's window */
986 GetWindowThreadProcessId(hWndAbove, &dwWindowProcessID);
987
988 if ((dwWindowProcessID == dwCurrentProcessID)
989 && GetProp(hWndAbove, WIN_WINDOW_PROP)
990 && !IsWindowVisible(hWndAbove)
991 && !IsIconic(hWndAbove)) /* ignore minimized windows */
992 break;
993 }
994 /* If this is top of X windows in Windows stack,
995 raise it in X stack. */
996 if (hWndAbove == NULL) {
997 #if CYGWINDOWING_DEBUG
998 winDebug("\traise to top\n");
999 #endif
1000 winRaiseWindow(pWin);
1001 }
1002 }
1003 }
1004 }
1005 /*
1006 * Pass the message to DefWindowProc to let the function
1007 * break down WM_WINDOWPOSCHANGED to WM_MOVE and WM_SIZE.
1008 */
1009 break;
1010
1011 case WM_ENTERSIZEMOVE:
1012 hasEnteredSizeMove = TRUE;
1013 return 0;
1014
1015 case WM_EXITSIZEMOVE:
1016 /* Adjust the X Window to the moved Windows window */
1017 hasEnteredSizeMove = FALSE;
1018 winAdjustXWindow(pWin, hwnd);
1019 return 0;
1020
1021 case WM_SIZE:
1022 /* see dix/window.c */
1023 #if CYGWINDOWING_DEBUG
1024 {
1025 char buf[64];
1026
1027 switch (wParam) {
1028 case SIZE_MINIMIZED:
1029 strcpy(buf, "SIZE_MINIMIZED");
1030 break;
1031 case SIZE_MAXIMIZED:
1032 strcpy(buf, "SIZE_MAXIMIZED");
1033 break;
1034 case SIZE_RESTORED:
1035 strcpy(buf, "SIZE_RESTORED");
1036 break;
1037 default:
1038 strcpy(buf, "UNKNOWN_FLAG");
1039 }
1040 ErrorF("winTopLevelWindowProc - WM_SIZE to %dx%d (%s)\n",
1041 (int) LOWORD(lParam), (int) HIWORD(lParam), buf);
1042 }
1043 #endif
1044 if (!hasEnteredSizeMove) {
1045 /* Adjust the X Window to the moved Windows window */
1046 winAdjustXWindow(pWin, hwnd);
1047 }
1048 /* else: wait for WM_EXITSIZEMOVE */
1049 return 0; /* end of WM_SIZE handler */
1050
1051 case WM_STYLECHANGING:
1052 /*
1053 When the style changes, adjust the Windows window size so the client area remains the same size,
1054 and adjust the Windows window position so that the client area remains in the same place.
1055 */
1056 {
1057 RECT newWinRect;
1058 DWORD dwExStyle;
1059 DWORD dwStyle;
1060 DWORD newStyle = ((STYLESTRUCT *) lParam)->styleNew;
1061 WINDOWINFO wi;
1062
1063 dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
1064 dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
1065
1066 winDebug("winTopLevelWindowProc - WM_STYLECHANGING from %08x %08x\n",
1067 (unsigned int)dwStyle, (unsigned int)dwExStyle);
1068
1069 if (wParam == GWL_EXSTYLE)
1070 dwExStyle = newStyle;
1071
1072 if (wParam == GWL_STYLE)
1073 dwStyle = newStyle;
1074
1075 winDebug("winTopLevelWindowProc - WM_STYLECHANGING to %08x %08x\n",
1076 (unsigned int)dwStyle, (unsigned int)dwExStyle);
1077
1078 /* Get client rect in screen coordinates */
1079 wi.cbSize = sizeof(WINDOWINFO);
1080 GetWindowInfo(hwnd, &wi);
1081
1082 winDebug
1083 ("winTopLevelWindowProc - WM_STYLECHANGING client area {%d, %d, %d, %d}, {%d x %d}\n",
1084 (int)wi.rcClient.left, (int)wi.rcClient.top, (int)wi.rcClient.right,
1085 (int)wi.rcClient.bottom, (int)(wi.rcClient.right - wi.rcClient.left),
1086 (int)(wi.rcClient.bottom - wi.rcClient.top));
1087
1088 newWinRect = wi.rcClient;
1089 if (!AdjustWindowRectEx(&newWinRect, dwStyle, FALSE, dwExStyle))
1090 winDebug
1091 ("winTopLevelWindowProc - WM_STYLECHANGING AdjustWindowRectEx failed\n");
1092
1093 winDebug
1094 ("winTopLevelWindowProc - WM_STYLECHANGING window area should be {%d, %d, %d, %d}, {%d x %d}\n",
1095 (int)newWinRect.left, (int)newWinRect.top, (int)newWinRect.right,
1096 (int)newWinRect.bottom, (int)(newWinRect.right - newWinRect.left),
1097 (int)(newWinRect.bottom - newWinRect.top));
1098
1099 /*
1100 Style change hasn't happened yet, so we can't adjust the window size yet, as the winAdjustXWindow()
1101 which WM_SIZE does will use the current (unchanged) style. Instead make a note to change it when
1102 WM_STYLECHANGED is received...
1103 */
1104 pWinPriv->hDwp = BeginDeferWindowPos(1);
1105 pWinPriv->hDwp =
1106 DeferWindowPos(pWinPriv->hDwp, hwnd, NULL, newWinRect.left,
1107 newWinRect.top, newWinRect.right - newWinRect.left,
1108 newWinRect.bottom - newWinRect.top,
1109 SWP_NOACTIVATE | SWP_NOZORDER);
1110 }
1111 return 0;
1112
1113 case WM_STYLECHANGED:
1114 {
1115 if (pWinPriv->hDwp) {
1116 EndDeferWindowPos(pWinPriv->hDwp);
1117 pWinPriv->hDwp = NULL;
1118 }
1119 winDebug("winTopLevelWindowProc - WM_STYLECHANGED done\n");
1120 }
1121 return 0;
1122
1123 case WM_MOUSEACTIVATE:
1124
1125 /* Check if this window needs to be made active when clicked */
1126 if (!GetProp(pWinPriv->hWnd, WIN_NEEDMANAGE_PROP)) {
1127 #if CYGMULTIWINDOW_DEBUG
1128 ErrorF("winTopLevelWindowProc - WM_MOUSEACTIVATE - "
1129 "MA_NOACTIVATE\n");
1130 #endif
1131
1132 /* */
1133 return MA_NOACTIVATE;
1134 }
1135 break;
1136
1137 case WM_SETCURSOR:
1138 if (LOWORD(lParam) == HTCLIENT) {
1139 if (!g_fSoftwareCursor)
1140 SetCursor(s_pScreenPriv->cursor.handle);
1141 return TRUE;
1142 }
1143 break;
1144
1145 default:
1146 break;
1147 }
1148
1149 ret = DefWindowProc(hwnd, message, wParam, lParam);
1150 /*
1151 * If the window was minized we get the stack change before the window is restored
1152 * and so it gets lost. Ensure there stacking order is correct.
1153 */
1154 if (needRestack)
1155 winReorderWindowsMultiWindow();
1156 return ret;
1157 }
1158