Added some sanity checks on window dimensions.
[wine/multimedia.git] / dlls / x11drv / winpos.c
blobd9459fea680b01bd0c5132bbdde86677231c9972
1 /*
2 * Window position related functions.
4 * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
5 * Copyright 1995, 1996, 1999 Alex Korobka
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
24 #include <X11/Xlib.h>
25 #ifdef HAVE_LIBXSHAPE
26 #include <X11/IntrinsicP.h>
27 #include <X11/extensions/shape.h>
28 #endif /* HAVE_LIBXSHAPE */
29 #include <stdarg.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winerror.h"
36 #include "ntstatus.h"
37 #include "wownt32.h"
38 #include "wine/wingdi16.h"
40 #include "x11drv.h"
41 #include "win.h"
42 #include "winpos.h"
43 #include "dce.h"
44 #include "cursoricon.h"
45 #include "nonclient.h"
47 #include "wine/server.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
52 #define SWP_AGG_NOGEOMETRYCHANGE \
53 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
54 #define SWP_AGG_NOPOSCHANGE \
55 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
56 #define SWP_AGG_STATUSFLAGS \
57 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
59 #define SWP_EX_NOCOPY 0x0001
60 #define SWP_EX_PAINTSELF 0x0002
61 #define SWP_EX_NONCLIENT 0x0004
63 #define HAS_THICKFRAME(style,exStyle) \
64 (((style) & WS_THICKFRAME) && \
65 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
67 #define ON_LEFT_BORDER(hit) \
68 (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
69 #define ON_RIGHT_BORDER(hit) \
70 (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
71 #define ON_TOP_BORDER(hit) \
72 (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
73 #define ON_BOTTOM_BORDER(hit) \
74 (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
76 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
77 #define _NET_WM_MOVERESIZE_SIZE_TOP 1
78 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
79 #define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
80 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
81 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
82 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
83 #define _NET_WM_MOVERESIZE_SIZE_LEFT 7
84 #define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
85 #define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
86 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
89 /***********************************************************************
90 * get_server_visible_region
92 static HRGN get_server_visible_region( HWND hwnd, HWND top, UINT flags )
94 RGNDATA *data;
95 NTSTATUS status;
96 HRGN ret = 0;
97 size_t size = 256;
101 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ))) return 0;
102 SERVER_START_REQ( get_visible_region )
104 req->window = hwnd;
105 req->top_win = top;
106 req->flags = flags;
107 wine_server_set_reply( req, data->Buffer, size );
108 if (!(status = wine_server_call( req )))
110 size_t reply_size = wine_server_reply_size( reply );
111 data->rdh.dwSize = sizeof(data->rdh);
112 data->rdh.iType = RDH_RECTANGLES;
113 data->rdh.nCount = reply_size / sizeof(RECT);
114 data->rdh.nRgnSize = reply_size;
115 ret = ExtCreateRegion( NULL, size, data );
117 else size = reply->total_size;
119 SERVER_END_REQ;
120 HeapFree( GetProcessHeap(), 0, data );
121 } while (status == STATUS_BUFFER_OVERFLOW);
123 if (status) SetLastError( RtlNtStatusToDosError(status) );
124 return ret;
128 /***********************************************************************
129 * get_top_clipping_window
131 * Get the top window to clip against (i.e. the top parent that has
132 * an associated X window).
134 static HWND get_top_clipping_window( HWND hwnd )
136 HWND ret = 0;
138 if (!using_wine_desktop) ret = GetAncestor( hwnd, GA_ROOT );
139 if (!ret) ret = GetDesktopWindow();
140 return ret;
144 /***********************************************************************
145 * expose_window
147 * Expose a region of a given window.
149 static void expose_window( HWND hwnd, RECT *rect, HRGN rgn, int flags )
151 POINT offset;
152 HWND top = 0;
153 HWND *list;
154 int i;
156 /* find the top most parent that doesn't clip children or siblings and
157 * invalidate the area on its parent, including all children */
158 if ((list = WIN_ListParents( hwnd )))
160 HWND current = hwnd;
161 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
162 for (i = 0; list[i] && list[i] != GetDesktopWindow(); i++)
164 if (!(style & WS_CLIPSIBLINGS)) top = current;
165 style = GetWindowLongW( list[i], GWL_STYLE );
166 if (!(style & WS_CLIPCHILDREN)) top = current;
167 current = list[i];
170 if (top)
172 /* find the parent of the top window, reusing the parent list */
173 if (top == hwnd) i = 0;
174 else
176 for (i = 0; list[i]; i++) if (list[i] == top) break;
177 if (list[i] && list[i+1]) i++;
179 if (list[i] != GetDesktopWindow()) top = list[i];
180 flags &= ~RDW_FRAME; /* parent will invalidate children frame anyway */
181 flags |= RDW_ALLCHILDREN;
183 HeapFree( GetProcessHeap(), 0, list );
186 if (!top) top = hwnd;
188 /* make coords relative to top */
189 offset.x = offset.y = 0;
190 MapWindowPoints( hwnd, top, &offset, 1 );
192 if (rect)
194 OffsetRect( rect, offset.x, offset.y );
195 RedrawWindow( top, rect, 0, flags );
197 else
199 OffsetRgn( rgn, offset.x, offset.y );
200 RedrawWindow( top, NULL, rgn, flags );
205 /***********************************************************************
206 * X11DRV_Expose
208 void X11DRV_Expose( HWND hwnd, XExposeEvent *event )
210 RECT rect;
211 struct x11drv_win_data *data;
212 int flags = RDW_INVALIDATE | RDW_ERASE;
213 WND *win;
215 TRACE( "win %p (%lx) %d,%d %dx%d\n",
216 hwnd, event->window, event->x, event->y, event->width, event->height );
218 rect.left = event->x;
219 rect.top = event->y;
220 rect.right = rect.left + event->width;
221 rect.bottom = rect.top + event->height;
223 if (!(win = WIN_GetPtr( hwnd ))) return;
224 data = win->pDriverData;
226 if (event->window != data->client_window) /* whole window or icon window */
228 flags |= RDW_FRAME;
229 /* make position relative to client area instead of window */
230 OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top );
232 WIN_ReleasePtr( win );
234 expose_window( hwnd, &rect, 0, flags );
238 /***********************************************************************
239 * GetDC (X11DRV.@)
241 * Set the drawable, origin and dimensions for the DC associated to
242 * a given window.
244 BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
246 HWND top = get_top_clipping_window( hwnd );
247 WND *win = WIN_GetPtr( hwnd );
248 X11DRV_WND_DATA *data = win->pDriverData;
249 struct x11drv_escape_set_drawable escape;
251 escape.mode = IncludeInferiors;
252 /* don't clip siblings if using parent clip region */
253 if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS;
255 if (top != hwnd)
257 /* find the top most parent that doesn't clip siblings */
258 HWND clipping_parent = 0;
259 HWND *list = WIN_ListParents( hwnd );
260 if (list)
262 int i;
263 for (i = 0; list[i] != top; i++)
265 LONG style = GetWindowLongW( list[i], GWL_STYLE );
266 if (!(style & WS_CLIPSIBLINGS)) clipping_parent = list[i];
268 HeapFree( GetProcessHeap(), 0, list );
270 if (clipping_parent)
271 clipping_parent = GetAncestor( clipping_parent, GA_PARENT );
272 else if (!(flags & DCX_CLIPSIBLINGS) || (flags & DCX_WINDOW))
273 clipping_parent = GetAncestor( hwnd, GA_PARENT );
274 else
275 clipping_parent = hwnd;
277 escape.org.x = escape.org.y = 0;
278 escape.drawable_org.x = escape.drawable_org.y = 0;
279 if (flags & DCX_WINDOW)
281 escape.org.x = win->rectWindow.left - win->rectClient.left;
282 escape.org.y = win->rectWindow.top - win->rectClient.top;
284 MapWindowPoints( hwnd, clipping_parent, &escape.org, 1 );
285 MapWindowPoints( clipping_parent, 0, &escape.drawable_org, 1 );
286 escape.drawable = X11DRV_get_client_window( clipping_parent );
288 else
290 if (IsIconic( hwnd ))
292 escape.drawable = data->icon_window ? data->icon_window : data->whole_window;
293 escape.org.x = 0;
294 escape.org.y = 0;
295 escape.drawable_org = escape.org;
297 else if (flags & DCX_WINDOW)
299 escape.drawable = data->whole_window;
300 escape.drawable_org.x = data->whole_rect.left;
301 escape.drawable_org.y = data->whole_rect.top;
302 escape.org.x = win->rectWindow.left - data->whole_rect.left;
303 escape.org.y = win->rectWindow.top - data->whole_rect.top;
305 else
307 escape.drawable = data->client_window;
308 escape.drawable_org.x = win->rectClient.left;
309 escape.drawable_org.y = win->rectClient.top;
310 escape.org.x = 0;
311 escape.org.y = 0;
315 escape.code = X11DRV_SET_DRAWABLE;
316 ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL );
318 if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) ||
319 SetHookFlags16( HDC_16(hdc), DCHF_VALIDATEVISRGN )) /* DC was dirty */
321 /* need to recompute the visible region */
322 HRGN visRgn = get_server_visible_region( hwnd, top, flags );
324 if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
325 CombineRgn( visRgn, visRgn, hrgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
327 SelectVisRgn16( HDC_16(hdc), HRGN_16(visRgn) );
328 DeleteObject( visRgn );
331 WIN_ReleasePtr( win );
332 return TRUE;
336 /***********************************************************************
337 * ReleaseDC (X11DRV.@)
339 void X11DRV_ReleaseDC( HWND hwnd, HDC hdc )
341 struct x11drv_escape_set_drawable escape;
343 escape.code = X11DRV_SET_DRAWABLE;
344 escape.drawable = root_window;
345 escape.mode = IncludeInferiors;
346 escape.org.x = escape.org.y = 0;
347 escape.drawable_org.x = escape.drawable_org.y = 0;
349 ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL );
353 /***********************************************************************
354 * SWP_DoWinPosChanging
356 static BOOL SWP_DoWinPosChanging( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT* pNewClientRect )
358 WND *wndPtr;
360 /* Send WM_WINDOWPOSCHANGING message */
362 if (!(pWinpos->flags & SWP_NOSENDCHANGING))
363 SendMessageW( pWinpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
365 if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return FALSE;
367 /* Calculate new position and size */
369 *pNewWindowRect = wndPtr->rectWindow;
370 *pNewClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
371 : wndPtr->rectClient;
373 if (!(pWinpos->flags & SWP_NOSIZE))
375 pNewWindowRect->right = pNewWindowRect->left + pWinpos->cx;
376 pNewWindowRect->bottom = pNewWindowRect->top + pWinpos->cy;
378 if (!(pWinpos->flags & SWP_NOMOVE))
380 pNewWindowRect->left = pWinpos->x;
381 pNewWindowRect->top = pWinpos->y;
382 pNewWindowRect->right += pWinpos->x - wndPtr->rectWindow.left;
383 pNewWindowRect->bottom += pWinpos->y - wndPtr->rectWindow.top;
385 OffsetRect( pNewClientRect, pWinpos->x - wndPtr->rectWindow.left,
386 pWinpos->y - wndPtr->rectWindow.top );
388 pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
390 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
391 pWinpos->hwnd, pWinpos->hwndInsertAfter, pWinpos->x, pWinpos->y,
392 pWinpos->cx, pWinpos->cy, pWinpos->flags );
393 TRACE( "current %s style %08lx new %s\n",
394 wine_dbgstr_rect( &wndPtr->rectWindow ), wndPtr->dwStyle,
395 wine_dbgstr_rect( pNewWindowRect ));
397 WIN_ReleasePtr( wndPtr );
398 return TRUE;
401 /***********************************************************************
402 * SWP_DoNCCalcSize
404 static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, const RECT* pNewWindowRect, RECT* pNewClientRect )
406 UINT wvrFlags = 0;
407 WND *wndPtr;
409 if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
411 /* Send WM_NCCALCSIZE message to get new client area */
412 if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
414 NCCALCSIZE_PARAMS params;
415 WINDOWPOS winposCopy;
417 params.rgrc[0] = *pNewWindowRect;
418 params.rgrc[1] = wndPtr->rectWindow;
419 params.rgrc[2] = wndPtr->rectClient;
420 params.lppos = &winposCopy;
421 winposCopy = *pWinpos;
422 WIN_ReleasePtr( wndPtr );
424 wvrFlags = SendMessageW( pWinpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)&params );
426 TRACE( "(%ld,%ld)-(%ld,%ld)\n", params.rgrc[0].left, params.rgrc[0].top,
427 params.rgrc[0].right, params.rgrc[0].bottom );
429 /* If the application sends back garbage, ignore it */
431 if (params.rgrc[0].left < pNewWindowRect->left) params.rgrc[0].left = pNewWindowRect->left;
432 if (params.rgrc[0].top < pNewWindowRect->top) params.rgrc[0].top = pNewWindowRect->top;
433 if (params.rgrc[0].right > pNewWindowRect->right) params.rgrc[0].right = pNewWindowRect->right;
434 if (params.rgrc[0].bottom > pNewWindowRect->bottom) params.rgrc[0].bottom = pNewWindowRect->bottom;
436 if (params.rgrc[0].left <= params.rgrc[0].right &&
437 params.rgrc[0].top <= params.rgrc[0].bottom)
438 *pNewClientRect = params.rgrc[0];
440 if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
442 if( pNewClientRect->left != wndPtr->rectClient.left ||
443 pNewClientRect->top != wndPtr->rectClient.top )
444 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
446 if( (pNewClientRect->right - pNewClientRect->left !=
447 wndPtr->rectClient.right - wndPtr->rectClient.left) ||
448 (pNewClientRect->bottom - pNewClientRect->top !=
449 wndPtr->rectClient.bottom - wndPtr->rectClient.top) )
450 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
452 else
454 if (!(pWinpos->flags & SWP_NOMOVE) &&
455 (pNewClientRect->left != wndPtr->rectClient.left ||
456 pNewClientRect->top != wndPtr->rectClient.top))
457 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
459 WIN_ReleasePtr( wndPtr );
460 return wvrFlags;
464 /***********************************************************************
465 * SWP_DoOwnedPopups
467 * fix Z order taking into account owned popups -
468 * basically we need to maintain them above the window that owns them
470 * FIXME: hide/show owned popups when owner visibility changes.
472 static HWND SWP_DoOwnedPopups(HWND hwnd, HWND hwndInsertAfter)
474 HWND *list = NULL;
475 HWND owner = GetWindow( hwnd, GW_OWNER );
476 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
478 WARN("(%p) hInsertAfter = %p\n", hwnd, hwndInsertAfter );
480 if ((style & WS_POPUP) && owner)
482 /* make sure this popup stays above the owner */
484 HWND hwndLocalPrev = HWND_TOP;
486 if( hwndInsertAfter != HWND_TOP )
488 if ((list = WIN_ListChildren( GetDesktopWindow() )))
490 int i;
491 for (i = 0; list[i]; i++)
493 if (list[i] == owner) break;
494 if (list[i] != hwnd) hwndLocalPrev = list[i];
495 if (hwndLocalPrev == hwndInsertAfter) break;
497 hwndInsertAfter = hwndLocalPrev;
501 else if (style & WS_CHILD) return hwndInsertAfter;
503 if (!list) list = WIN_ListChildren( GetDesktopWindow() );
504 if (list)
506 int i;
507 for (i = 0; list[i]; i++)
509 if (list[i] == hwnd) break;
510 if ((GetWindowLongW( list[i], GWL_STYLE ) & WS_POPUP) &&
511 GetWindow( list[i], GW_OWNER ) == hwnd)
513 SetWindowPos( list[i], hwndInsertAfter, 0, 0, 0, 0,
514 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
515 SWP_NOSENDCHANGING | SWP_DEFERERASE );
516 hwndInsertAfter = list[i];
519 HeapFree( GetProcessHeap(), 0, list );
522 return hwndInsertAfter;
526 /* fix redundant flags and values in the WINDOWPOS structure */
527 static BOOL fixup_flags( WINDOWPOS *winpos )
529 WND *wndPtr = WIN_GetPtr( winpos->hwnd );
530 BOOL ret = TRUE;
532 if (!wndPtr || wndPtr == WND_OTHER_PROCESS)
534 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
535 return FALSE;
537 winpos->hwnd = wndPtr->hwndSelf; /* make it a full handle */
539 /* Finally make sure that all coordinates are valid */
540 if (winpos->x < -32768) winpos->x = -32768;
541 else if (winpos->x > 32767) winpos->x = 32767;
542 if (winpos->y < -32768) winpos->y = -32768;
543 else if (winpos->y > 32767) winpos->y = 32767;
545 if (winpos->cx < 0) winpos->cx = 0;
546 else if (winpos->cx > 32767) winpos->cx = 32767;
547 if (winpos->cy < 0) winpos->cy = 0;
548 else if (winpos->cy > 32767) winpos->cy = 32767;
550 if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
551 else
553 winpos->flags &= ~SWP_HIDEWINDOW;
554 if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
557 if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == winpos->cx) &&
558 (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == winpos->cy))
559 winpos->flags |= SWP_NOSIZE; /* Already the right size */
561 if ((wndPtr->rectWindow.left == winpos->x) && (wndPtr->rectWindow.top == winpos->y))
562 winpos->flags |= SWP_NOMOVE; /* Already the right position */
564 if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
566 if (!(winpos->flags & SWP_NOACTIVATE)) /* Bring to the top when activating */
568 winpos->flags &= ~SWP_NOZORDER;
569 winpos->hwndInsertAfter = HWND_TOP;
573 /* Check hwndInsertAfter */
574 if (winpos->flags & SWP_NOZORDER) goto done;
576 /* fix sign extension */
577 if (winpos->hwndInsertAfter == (HWND)0xffff) winpos->hwndInsertAfter = HWND_TOPMOST;
578 else if (winpos->hwndInsertAfter == (HWND)0xfffe) winpos->hwndInsertAfter = HWND_NOTOPMOST;
580 /* FIXME: TOPMOST not supported yet */
581 if ((winpos->hwndInsertAfter == HWND_TOPMOST) ||
582 (winpos->hwndInsertAfter == HWND_NOTOPMOST)) winpos->hwndInsertAfter = HWND_TOP;
584 /* hwndInsertAfter must be a sibling of the window */
585 if (winpos->hwndInsertAfter == HWND_TOP)
587 if (GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
588 winpos->flags |= SWP_NOZORDER;
590 else if (winpos->hwndInsertAfter == HWND_BOTTOM)
592 if (GetWindow(winpos->hwnd, GW_HWNDLAST) == winpos->hwnd)
593 winpos->flags |= SWP_NOZORDER;
595 else
597 if (GetAncestor( winpos->hwndInsertAfter, GA_PARENT ) != wndPtr->parent) ret = FALSE;
598 else
600 /* don't need to change the Zorder of hwnd if it's already inserted
601 * after hwndInsertAfter or when inserting hwnd after itself.
603 if ((winpos->hwnd == winpos->hwndInsertAfter) ||
604 (winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
605 winpos->flags |= SWP_NOZORDER;
608 done:
609 WIN_ReleasePtr( wndPtr );
610 return ret;
614 /***********************************************************************
615 * SetWindowStyle (X11DRV.@)
617 * Update the X state of a window to reflect a style change
619 void X11DRV_SetWindowStyle( HWND hwnd, LONG oldStyle )
621 Display *display = thread_display();
622 WND *wndPtr;
623 LONG changed;
625 if (hwnd == GetDesktopWindow()) return;
626 if (!(wndPtr = WIN_GetPtr( hwnd ))) return;
627 if (wndPtr == WND_OTHER_PROCESS) return;
629 changed = wndPtr->dwStyle ^ oldStyle;
631 if (changed & WS_VISIBLE)
633 if (X11DRV_is_window_rect_mapped( &wndPtr->rectWindow ))
635 if (wndPtr->dwStyle & WS_VISIBLE)
637 TRACE( "mapping win %p\n", hwnd );
638 if (is_window_top_level(wndPtr))
640 X11DRV_sync_window_style( display, wndPtr );
641 X11DRV_set_wm_hints( display, wndPtr );
643 wine_tsx11_lock();
644 XMapWindow( display, get_whole_window(wndPtr) );
645 wine_tsx11_unlock();
647 else if (!is_window_top_level(wndPtr)) /* don't unmap managed windows */
649 TRACE( "unmapping win %p\n", hwnd );
650 wine_tsx11_lock();
651 XUnmapWindow( display, get_whole_window(wndPtr) );
652 wine_tsx11_unlock();
657 if (changed & WS_DISABLED)
659 if (wndPtr->dwExStyle & WS_EX_MANAGED)
661 XWMHints *wm_hints;
662 wine_tsx11_lock();
663 if (!(wm_hints = XGetWMHints( display, get_whole_window(wndPtr) )))
664 wm_hints = XAllocWMHints();
665 if (wm_hints)
667 wm_hints->flags |= InputHint;
668 wm_hints->input = !(wndPtr->dwStyle & WS_DISABLED);
669 XSetWMHints( display, get_whole_window(wndPtr), wm_hints );
670 XFree(wm_hints);
672 wine_tsx11_unlock();
675 WIN_ReleasePtr(wndPtr);
679 /***********************************************************************
680 * X11DRV_set_window_pos
682 * Set a window position and Z order.
684 BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow,
685 const RECT *rectClient, UINT swp_flags, UINT wvr_flags )
687 HWND top = get_top_clipping_window( hwnd );
688 WND *win = WIN_GetPtr( hwnd );
689 DWORD old_style, new_style;
690 BOOL ret;
692 if (!win) return FALSE;
693 if (win == WND_OTHER_PROCESS)
695 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd );
696 return FALSE;
698 old_style = win->dwStyle;
699 SERVER_START_REQ( set_window_pos )
701 req->handle = hwnd;
702 req->top_win = top;
703 req->previous = insert_after;
704 req->flags = swp_flags & ~SWP_WINE_NOHOSTMOVE;
705 req->redraw_flags = wvr_flags;
706 req->window.left = rectWindow->left;
707 req->window.top = rectWindow->top;
708 req->window.right = rectWindow->right;
709 req->window.bottom = rectWindow->bottom;
710 req->client.left = rectClient->left;
711 req->client.top = rectClient->top;
712 req->client.right = rectClient->right;
713 req->client.bottom = rectClient->bottom;
714 ret = !wine_server_call( req );
715 new_style = reply->new_style;
717 SERVER_END_REQ;
719 if (ret)
721 struct x11drv_win_data *data = win->pDriverData;
722 Display *display = thread_display();
724 /* invalidate DCEs */
726 if ((((swp_flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) && (new_style & WS_VISIBLE)) ||
727 (swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)))
729 RECT rect;
730 UnionRect( &rect, rectWindow, &win->rectWindow );
731 DCE_InvalidateDCE( hwnd, &rect );
734 win->rectWindow = *rectWindow;
735 win->rectClient = *rectClient;
736 win->dwStyle = new_style;
738 TRACE( "win %p window %s client %s style %08lx\n",
739 hwnd, wine_dbgstr_rect(rectWindow), wine_dbgstr_rect(rectClient), new_style );
741 /* FIXME: copy the valid bits */
743 if (swp_flags & SWP_WINE_NOHOSTMOVE)
745 data->whole_rect = *rectWindow;
746 X11DRV_window_to_X_rect( win, &data->whole_rect );
747 if (data->client_window != data->whole_window)
748 X11DRV_sync_client_window_position( display, win );
750 else if (data->whole_window) /* don't do anything if X window not created yet */
752 if ((old_style & WS_VISIBLE) && !(new_style & WS_VISIBLE))
754 /* window got hidden, unmap it */
755 TRACE( "unmapping win %p\n", hwnd );
756 wine_tsx11_lock();
757 XUnmapWindow( thread_display(), data->whole_window );
758 wine_tsx11_unlock();
760 else if ((new_style & WS_VISIBLE) && !X11DRV_is_window_rect_mapped( rectWindow ))
762 /* resizing to zero size or off screen -> unmap */
763 TRACE( "unmapping zero size or off-screen win %p\n", hwnd );
764 wine_tsx11_lock();
765 XUnmapWindow( display, data->whole_window );
766 wine_tsx11_unlock();
769 X11DRV_sync_whole_window_position( display, win, !(swp_flags & SWP_NOZORDER) );
770 X11DRV_sync_client_window_position( display, win );
772 if (!(old_style & WS_VISIBLE) && (new_style & WS_VISIBLE))
774 /* window got shown, map it */
775 if (X11DRV_is_window_rect_mapped( rectWindow ))
777 TRACE( "mapping win %p\n", hwnd );
778 if (is_window_top_level(win))
780 X11DRV_sync_window_style( display, win );
781 X11DRV_set_wm_hints( display, win );
783 wine_tsx11_lock();
784 XMapWindow( display, data->whole_window );
785 wine_tsx11_unlock();
788 else if ((new_style & WS_VISIBLE) && X11DRV_is_window_rect_mapped( rectWindow ))
790 /* resizing from zero size to non-zero -> map */
791 TRACE( "mapping non zero size or off-screen win %p\n", hwnd );
792 wine_tsx11_lock();
793 XMapWindow( display, data->whole_window );
794 wine_tsx11_unlock();
796 wine_tsx11_lock();
797 XFlush( display ); /* FIXME: should not be necessary */
798 wine_tsx11_unlock();
801 WIN_ReleasePtr( win );
802 return ret;
806 /***********************************************************************
807 * SetWindowPos (X11DRV.@)
809 BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
811 RECT newWindowRect, newClientRect;
812 UINT wvr_flags, orig_flags;
814 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
815 winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
816 winpos->cx, winpos->cy, winpos->flags);
818 orig_flags = winpos->flags;
819 winpos->flags &= ~SWP_WINE_NOHOSTMOVE;
821 /* Check window handle */
822 if (winpos->hwnd == GetDesktopWindow()) return FALSE;
824 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
825 if (!(winpos->flags & SWP_NOMOVE))
827 if (winpos->x < -32768) winpos->x = -32768;
828 else if (winpos->x > 32767) winpos->x = 32767;
829 if (winpos->y < -32768) winpos->y = -32768;
830 else if (winpos->y > 32767) winpos->y = 32767;
832 if (!(winpos->flags & SWP_NOSIZE))
834 if (winpos->cx < 0) winpos->cx = 0;
835 else if (winpos->cx > 32767) winpos->cx = 32767;
836 if (winpos->cy < 0) winpos->cy = 0;
837 else if (winpos->cy > 32767) winpos->cy = 32767;
840 if (!SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect )) return FALSE;
842 /* Fix redundant flags */
843 if (!fixup_flags( winpos )) return FALSE;
845 if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
847 if (GetAncestor( winpos->hwnd, GA_PARENT ) == GetDesktopWindow())
848 winpos->hwndInsertAfter = SWP_DoOwnedPopups( winpos->hwnd, winpos->hwndInsertAfter );
851 /* Common operations */
853 wvr_flags = SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect );
855 /* FIXME: actually do something with WVR_VALIDRECTS */
857 if (!X11DRV_set_window_pos( winpos->hwnd, winpos->hwndInsertAfter,
858 &newWindowRect, &newClientRect,
859 orig_flags, wvr_flags ))
860 return FALSE;
862 if( winpos->flags & SWP_HIDEWINDOW )
863 HideCaret(winpos->hwnd);
864 else if (winpos->flags & SWP_SHOWWINDOW)
865 ShowCaret(winpos->hwnd);
867 if (!(winpos->flags & SWP_NOACTIVATE))
869 /* child windows get WM_CHILDACTIVATE message */
870 if ((GetWindowLongW( winpos->hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
871 SendMessageA( winpos->hwnd, WM_CHILDACTIVATE, 0, 0 );
872 else
873 SetForegroundWindow( winpos->hwnd );
876 /* And last, send the WM_WINDOWPOSCHANGED message */
878 TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
880 if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE))
882 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
883 and always contains final window position.
885 winpos->x = newWindowRect.left;
886 winpos->y = newWindowRect.top;
887 winpos->cx = newWindowRect.right - newWindowRect.left;
888 winpos->cy = newWindowRect.bottom - newWindowRect.top;
889 SendMessageW( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
892 return TRUE;
896 /***********************************************************************
897 * WINPOS_FindIconPos
899 * Find a suitable place for an iconic window.
901 static POINT WINPOS_FindIconPos( WND* wndPtr, POINT pt )
903 RECT rectParent;
904 HWND *list;
905 short x, y, xspacing, yspacing;
907 GetClientRect( wndPtr->parent, &rectParent );
908 if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics(SM_CXICON) < rectParent.right) &&
909 (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics(SM_CYICON) < rectParent.bottom))
910 return pt; /* The icon already has a suitable position */
912 xspacing = GetSystemMetrics(SM_CXICONSPACING);
913 yspacing = GetSystemMetrics(SM_CYICONSPACING);
915 list = WIN_ListChildren( wndPtr->parent );
916 y = rectParent.bottom;
917 for (;;)
919 x = rectParent.left;
922 /* Check if another icon already occupies this spot */
923 /* FIXME: this is completely inefficient */
924 if (list)
926 int i;
927 WND *childPtr;
929 for (i = 0; list[i]; i++)
931 if (list[i] == wndPtr->hwndSelf) continue;
932 if (!IsIconic( list[i] )) continue;
933 if (!(childPtr = WIN_FindWndPtr( list[i] ))) continue;
934 if ((childPtr->rectWindow.left < x + xspacing) &&
935 (childPtr->rectWindow.right >= x) &&
936 (childPtr->rectWindow.top <= y) &&
937 (childPtr->rectWindow.bottom > y - yspacing))
939 WIN_ReleaseWndPtr( childPtr );
940 break; /* There's a window in there */
942 WIN_ReleaseWndPtr( childPtr );
944 if (list[i])
946 /* found something here, try next spot */
947 x += xspacing;
948 continue;
952 /* No window was found, so it's OK for us */
953 pt.x = x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2;
954 pt.y = y - (yspacing + GetSystemMetrics(SM_CYICON)) / 2;
955 HeapFree( GetProcessHeap(), 0, list );
956 return pt;
958 } while(x <= rectParent.right-xspacing);
959 y -= yspacing;
967 UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
969 WND *wndPtr;
970 UINT swpFlags = 0;
971 POINT size;
972 LONG old_style;
973 WINDOWPLACEMENT wpl;
975 TRACE("%p %u\n", hwnd, cmd );
977 wpl.length = sizeof(wpl);
978 GetWindowPlacement( hwnd, &wpl );
980 if (HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE ))
981 return SWP_NOSIZE | SWP_NOMOVE;
983 if (IsIconic( hwnd ))
985 if (cmd == SW_MINIMIZE) return SWP_NOSIZE | SWP_NOMOVE;
986 if (!SendMessageA( hwnd, WM_QUERYOPEN, 0, 0 )) return SWP_NOSIZE | SWP_NOMOVE;
987 swpFlags |= SWP_NOCOPYBITS;
990 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
992 size.x = wndPtr->rectWindow.left;
993 size.y = wndPtr->rectWindow.top;
995 switch( cmd )
997 case SW_MINIMIZE:
998 if( wndPtr->dwStyle & WS_MAXIMIZE) wndPtr->flags |= WIN_RESTORE_MAX;
999 else wndPtr->flags &= ~WIN_RESTORE_MAX;
1001 WIN_SetStyle( hwnd, (wndPtr->dwStyle & ~WS_MAXIMIZE) | WS_MINIMIZE );
1003 X11DRV_set_iconic_state( wndPtr );
1005 wpl.ptMinPosition = WINPOS_FindIconPos( wndPtr, wpl.ptMinPosition );
1007 SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
1008 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) );
1009 swpFlags |= SWP_NOCOPYBITS;
1010 break;
1012 case SW_MAXIMIZE:
1013 WINPOS_GetMinMaxInfo( hwnd, &size, &wpl.ptMaxPosition, NULL, NULL );
1015 old_style = WIN_SetStyle( hwnd, (wndPtr->dwStyle & ~WS_MINIMIZE) | WS_MAXIMIZE );
1016 if (old_style & WS_MINIMIZE)
1018 WINPOS_ShowIconTitle( hwnd, FALSE );
1019 X11DRV_set_iconic_state( wndPtr );
1021 SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
1022 break;
1024 case SW_RESTORE:
1025 old_style = WIN_SetStyle( hwnd, wndPtr->dwStyle & ~(WS_MINIMIZE|WS_MAXIMIZE) );
1026 if (old_style & WS_MINIMIZE)
1028 WINPOS_ShowIconTitle( hwnd, FALSE );
1029 X11DRV_set_iconic_state( wndPtr );
1031 if( wndPtr->flags & WIN_RESTORE_MAX)
1033 /* Restore to maximized position */
1034 WINPOS_GetMinMaxInfo( hwnd, &size, &wpl.ptMaxPosition, NULL, NULL);
1035 WIN_SetStyle( hwnd, wndPtr->dwStyle | WS_MAXIMIZE );
1036 SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
1037 break;
1040 else if (!(old_style & WS_MAXIMIZE)) break;
1042 /* Restore to normal position */
1044 *rect = wpl.rcNormalPosition;
1045 rect->right -= rect->left;
1046 rect->bottom -= rect->top;
1048 break;
1051 WIN_ReleaseWndPtr( wndPtr );
1052 return swpFlags;
1056 /***********************************************************************
1057 * ShowWindow (X11DRV.@)
1059 BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd )
1061 WND* wndPtr = WIN_FindWndPtr( hwnd );
1062 BOOL wasVisible, showFlag;
1063 RECT newPos = {0, 0, 0, 0};
1064 UINT swp = 0;
1066 if (!wndPtr) return FALSE;
1067 hwnd = wndPtr->hwndSelf; /* make it a full handle */
1069 wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
1071 TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible);
1073 switch(cmd)
1075 case SW_HIDE:
1076 if (!wasVisible) goto END;
1077 swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1078 SWP_NOACTIVATE | SWP_NOZORDER;
1079 break;
1081 case SW_SHOWMINNOACTIVE:
1082 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1083 /* fall through */
1084 case SW_SHOWMINIMIZED:
1085 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
1086 swp |= SWP_SHOWWINDOW;
1087 /* fall through */
1088 case SW_MINIMIZE:
1089 swp |= SWP_FRAMECHANGED;
1090 if( !(wndPtr->dwStyle & WS_MINIMIZE) )
1091 swp |= WINPOS_MinMaximize( hwnd, SW_MINIMIZE, &newPos );
1092 else swp |= SWP_NOSIZE | SWP_NOMOVE;
1093 break;
1095 case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
1096 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1097 if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
1098 swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
1099 else swp |= SWP_NOSIZE | SWP_NOMOVE;
1100 break;
1102 case SW_SHOWNA:
1103 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1104 /* fall through */
1105 case SW_SHOW:
1106 if (wasVisible) goto END;
1108 swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1109 break;
1111 case SW_RESTORE:
1112 swp |= SWP_FRAMECHANGED;
1113 /* fall through */
1114 case SW_SHOWNOACTIVATE:
1115 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1116 /* fall through */
1117 case SW_SHOWNORMAL: /* same as SW_NORMAL: */
1118 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1119 swp |= SWP_SHOWWINDOW;
1121 if( wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE) )
1122 swp |= WINPOS_MinMaximize( hwnd, SW_RESTORE, &newPos );
1123 else swp |= SWP_NOSIZE | SWP_NOMOVE;
1124 break;
1127 showFlag = (cmd != SW_HIDE);
1128 if (showFlag != wasVisible)
1130 SendMessageW( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1131 if (!IsWindow( hwnd )) goto END;
1134 /* ShowWindow won't activate a not being maximized child window */
1135 if ((wndPtr->dwStyle & WS_CHILD) && cmd != SW_MAXIMIZE)
1136 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1138 SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
1139 newPos.right, newPos.bottom, LOWORD(swp) );
1140 if (cmd == SW_HIDE)
1142 HWND hFocus;
1144 /* FIXME: This will cause the window to be activated irrespective
1145 * of whether it is owned by the same thread. Has to be done
1146 * asynchronously.
1149 if (hwnd == GetActiveWindow())
1150 WINPOS_ActivateOtherWindow(hwnd);
1152 /* Revert focus to parent */
1153 hFocus = GetFocus();
1154 if (hwnd == hFocus || IsChild(hwnd, hFocus))
1156 HWND parent = GetAncestor(hwnd, GA_PARENT);
1157 if (parent == GetDesktopWindow()) parent = 0;
1158 SetFocus(parent);
1161 if (!IsWindow( hwnd )) goto END;
1162 else if( wndPtr->dwStyle & WS_MINIMIZE ) WINPOS_ShowIconTitle( hwnd, TRUE );
1164 if (wndPtr->flags & WIN_NEED_SIZE)
1166 /* should happen only in CreateWindowEx() */
1167 int wParam = SIZE_RESTORED;
1169 wndPtr->flags &= ~WIN_NEED_SIZE;
1170 if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
1171 else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
1172 SendMessageA( hwnd, WM_SIZE, wParam,
1173 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
1174 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
1175 SendMessageA( hwnd, WM_MOVE, 0,
1176 MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
1179 END:
1180 WIN_ReleaseWndPtr(wndPtr);
1181 return wasVisible;
1185 /**********************************************************************
1186 * X11DRV_MapNotify
1188 void X11DRV_MapNotify( HWND hwnd, XMapEvent *event )
1190 HWND hwndFocus = GetFocus();
1191 WND *win;
1193 if (!(win = WIN_GetPtr( hwnd ))) return;
1195 if ((win->dwStyle & WS_VISIBLE) &&
1196 (win->dwStyle & WS_MINIMIZE) &&
1197 (win->dwExStyle & WS_EX_MANAGED))
1199 int x, y;
1200 unsigned int width, height, border, depth;
1201 Window root, top;
1202 RECT rect;
1203 LONG style = (win->dwStyle & ~(WS_MINIMIZE|WS_MAXIMIZE)) | WS_VISIBLE;
1205 /* FIXME: hack */
1206 wine_tsx11_lock();
1207 XGetGeometry( event->display, get_whole_window(win), &root, &x, &y, &width, &height,
1208 &border, &depth );
1209 XTranslateCoordinates( event->display, get_whole_window(win), root, 0, 0, &x, &y, &top );
1210 wine_tsx11_unlock();
1211 rect.left = x;
1212 rect.top = y;
1213 rect.right = x + width;
1214 rect.bottom = y + height;
1215 X11DRV_X_to_window_rect( win, &rect );
1217 DCE_InvalidateDCE( hwnd, &win->rectWindow );
1219 if (win->flags & WIN_RESTORE_MAX) style |= WS_MAXIMIZE;
1220 WIN_SetStyle( hwnd, style );
1221 WIN_ReleasePtr( win );
1223 SendMessageA( hwnd, WM_SHOWWINDOW, SW_RESTORE, 0 );
1224 SetWindowPos( hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1225 SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
1227 else WIN_ReleasePtr( win );
1228 if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus); /* FIXME */
1232 /**********************************************************************
1233 * X11DRV_UnmapNotify
1235 void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event )
1237 WND *win;
1239 if (!(win = WIN_GetPtr( hwnd ))) return;
1241 if ((win->dwStyle & WS_VISIBLE) && (win->dwExStyle & WS_EX_MANAGED) &&
1242 X11DRV_is_window_rect_mapped( &win->rectWindow ))
1244 if (win->dwStyle & WS_MAXIMIZE)
1245 win->flags |= WIN_RESTORE_MAX;
1246 else
1247 win->flags &= ~WIN_RESTORE_MAX;
1249 WIN_SetStyle( hwnd, (win->dwStyle & ~WS_MAXIMIZE) | WS_MINIMIZE );
1250 WIN_ReleasePtr( win );
1252 EndMenu();
1253 SendMessageA( hwnd, WM_SHOWWINDOW, SW_MINIMIZE, 0 );
1254 SetWindowPos( hwnd, 0, 0, 0, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
1255 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
1257 else WIN_ReleasePtr( win );
1261 /***********************************************************************
1262 * query_zorder
1264 * Synchronize internal z-order with the window manager's.
1266 static Window __get_common_ancestor( Display *display, Window A, Window B,
1267 Window** children, unsigned* total )
1269 /* find the real root window */
1271 Window root, *childrenB;
1272 unsigned totalB;
1274 wine_tsx11_lock();
1275 while( A != B && A && B )
1277 XQueryTree( display, A, &root, &A, children, total );
1278 XQueryTree( display, B, &root, &B, &childrenB, &totalB );
1279 if( childrenB ) XFree( childrenB );
1280 if( *children ) XFree( *children ), *children = NULL;
1283 if( A && B )
1285 XQueryTree( display, A, &root, &B, children, total );
1286 wine_tsx11_unlock();
1287 return A;
1289 wine_tsx11_unlock();
1290 return 0 ;
1293 static Window __get_top_decoration( Display *display, Window w, Window ancestor )
1295 Window* children, root, prev = w, parent = w;
1296 unsigned total;
1298 wine_tsx11_lock();
1301 w = parent;
1302 XQueryTree( display, w, &root, &parent, &children, &total );
1303 if( children ) XFree( children );
1304 } while( parent && parent != ancestor );
1305 wine_tsx11_unlock();
1306 TRACE("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
1307 return ( parent ) ? w : 0 ;
1310 static unsigned __td_lookup( Window w, Window* list, unsigned max )
1312 unsigned i;
1313 for( i = max; i > 0; i-- ) if( list[i - 1] == w ) break;
1314 return i;
1317 static HWND query_zorder( Display *display, HWND hWndCheck)
1319 HWND hwndInsertAfter = HWND_TOP;
1320 Window w, parent, *children = NULL;
1321 unsigned total, check, pos, best;
1322 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1323 HWND hwndA = 0, hwndB = 0;
1324 int i;
1326 /* find at least two managed windows */
1327 if (!list) return 0;
1328 for (i = 0; list[i]; i++)
1330 if (!(GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_MANAGED)) continue;
1331 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) continue;
1332 if (!hwndA) hwndA = list[i];
1333 else
1335 hwndB = list[i];
1336 break;
1339 if (!hwndA || !hwndB) goto done;
1341 parent = __get_common_ancestor( display, X11DRV_get_whole_window(hwndA),
1342 X11DRV_get_whole_window(hwndB), &children, &total );
1343 if( parent && children )
1345 /* w is the ancestor if hWndCheck that is a direct descendant of 'parent' */
1347 w = __get_top_decoration( display, X11DRV_get_whole_window(hWndCheck), parent );
1349 if( w != children[total-1] ) /* check if at the top */
1351 /* X child at index 0 is at the bottom, at index total-1 is at the top */
1352 check = __td_lookup( w, children, total );
1353 best = total;
1355 /* go through all windows in Wine z-order... */
1356 for (i = 0; list[i]; i++)
1358 if (list[i] == hWndCheck) continue;
1359 if (!(GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_MANAGED)) continue;
1360 if (!(w = __get_top_decoration( display, X11DRV_get_whole_window(list[i]),
1361 parent ))) continue;
1362 pos = __td_lookup( w, children, total );
1363 if( pos < best && pos > check )
1365 /* find a nearest Wine window precedes hWndCheck in the real z-order */
1366 best = pos;
1367 hwndInsertAfter = list[i];
1369 if( best - check == 1 ) break;
1373 wine_tsx11_lock();
1374 if( children ) XFree( children );
1375 wine_tsx11_unlock();
1377 done:
1378 HeapFree( GetProcessHeap(), 0, list );
1379 return hwndInsertAfter;
1383 /***********************************************************************
1384 * X11DRV_handle_desktop_resize
1386 void X11DRV_handle_desktop_resize( unsigned int width, unsigned int height )
1388 RECT rect;
1389 HWND hwnd = GetDesktopWindow();
1391 screen_width = width;
1392 screen_height = height;
1393 TRACE("desktop %p change to (%dx%d)\n", hwnd, width, height);
1394 SetRect( &rect, 0, 0, width, height );
1395 X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER|SWP_NOMOVE|SWP_WINE_NOHOSTMOVE, 0 );
1396 SendMessageTimeoutW( HWND_BROADCAST, WM_DISPLAYCHANGE, screen_depth,
1397 MAKELPARAM( width, height ), SMTO_ABORTIFHUNG, 2000, NULL );
1401 /***********************************************************************
1402 * X11DRV_ConfigureNotify
1404 void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
1406 HWND oldInsertAfter;
1407 struct x11drv_win_data *data;
1408 WND *win;
1409 RECT rect;
1410 WINDOWPOS winpos;
1411 int x = event->x, y = event->y;
1413 if (!(win = WIN_GetPtr( hwnd ))) return;
1414 data = win->pDriverData;
1416 /* Get geometry */
1418 if (!event->send_event) /* normal event, need to map coordinates to the root */
1420 Window child;
1421 wine_tsx11_lock();
1422 XTranslateCoordinates( event->display, data->whole_window, root_window,
1423 0, 0, &x, &y, &child );
1424 wine_tsx11_unlock();
1426 rect.left = x;
1427 rect.top = y;
1428 rect.right = x + event->width;
1429 rect.bottom = y + event->height;
1430 TRACE( "win %p new X rect %ld,%ld,%ldx%ld (event %d,%d,%dx%d)\n",
1431 hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1432 event->x, event->y, event->width, event->height );
1433 X11DRV_X_to_window_rect( win, &rect );
1434 WIN_ReleasePtr( win );
1436 winpos.hwnd = hwnd;
1437 winpos.x = rect.left;
1438 winpos.y = rect.top;
1439 winpos.cx = rect.right - rect.left;
1440 winpos.cy = rect.bottom - rect.top;
1441 winpos.flags = SWP_NOACTIVATE;
1443 /* Get Z-order (FIXME) */
1445 winpos.hwndInsertAfter = query_zorder( event->display, hwnd );
1447 /* needs to find the first Visible Window above the current one */
1448 oldInsertAfter = hwnd;
1449 for (;;)
1451 oldInsertAfter = GetWindow( oldInsertAfter, GW_HWNDPREV );
1452 if (!oldInsertAfter)
1454 oldInsertAfter = HWND_TOP;
1455 break;
1457 if (GetWindowLongA( oldInsertAfter, GWL_STYLE ) & WS_VISIBLE) break;
1460 /* Compare what has changed */
1462 GetWindowRect( hwnd, &rect );
1463 if (rect.left == winpos.x && rect.top == winpos.y) winpos.flags |= SWP_NOMOVE;
1464 else
1465 TRACE( "%p moving from (%ld,%ld) to (%d,%d)\n",
1466 hwnd, rect.left, rect.top, winpos.x, winpos.y );
1468 if ((rect.right - rect.left == winpos.cx && rect.bottom - rect.top == winpos.cy) ||
1469 IsIconic(hwnd) ||
1470 (IsRectEmpty( &rect ) && winpos.cx == 1 && winpos.cy == 1))
1471 winpos.flags |= SWP_NOSIZE;
1472 else
1473 TRACE( "%p resizing from (%ldx%ld) to (%dx%d)\n",
1474 hwnd, rect.right - rect.left, rect.bottom - rect.top,
1475 winpos.cx, winpos.cy );
1477 if (winpos.hwndInsertAfter == oldInsertAfter) winpos.flags |= SWP_NOZORDER;
1478 else
1479 TRACE( "%p restacking from after %p to after %p\n",
1480 hwnd, oldInsertAfter, winpos.hwndInsertAfter );
1482 /* if nothing changed, don't do anything */
1483 if (winpos.flags == (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE)) return;
1485 SetWindowPos( hwnd, winpos.hwndInsertAfter, winpos.x, winpos.y,
1486 winpos.cx, winpos.cy, winpos.flags | SWP_WINE_NOHOSTMOVE );
1490 /***********************************************************************
1491 * SetWindowRgn (X11DRV.@)
1493 * Assign specified region to window (for non-rectangular windows)
1495 int X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
1497 WND *wndPtr;
1499 if ((wndPtr = WIN_GetPtr( hwnd )) == WND_OTHER_PROCESS)
1501 if (IsWindow( hwnd ))
1502 FIXME( "not supported on other process window %p\n", hwnd );
1503 wndPtr = NULL;
1505 if (!wndPtr)
1507 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1508 return FALSE;
1511 #ifdef HAVE_LIBXSHAPE
1513 Display *display = thread_display();
1514 X11DRV_WND_DATA *data = wndPtr->pDriverData;
1516 if (data->whole_window)
1518 if (!hrgn)
1520 wine_tsx11_lock();
1521 XShapeCombineMask( display, data->whole_window,
1522 ShapeBounding, 0, 0, None, ShapeSet );
1523 wine_tsx11_unlock();
1525 else
1527 RGNDATA *pRegionData = X11DRV_GetRegionData( hrgn, 0 );
1528 if (pRegionData)
1530 wine_tsx11_lock();
1531 XShapeCombineRectangles( display, data->whole_window, ShapeBounding,
1532 wndPtr->rectWindow.left - data->whole_rect.left,
1533 wndPtr->rectWindow.top - data->whole_rect.top,
1534 (XRectangle *)pRegionData->Buffer,
1535 pRegionData->rdh.nCount,
1536 ShapeSet, YXBanded );
1537 wine_tsx11_unlock();
1538 HeapFree(GetProcessHeap(), 0, pRegionData);
1543 #endif /* HAVE_LIBXSHAPE */
1545 WIN_ReleasePtr( wndPtr );
1546 return TRUE;
1550 /***********************************************************************
1551 * draw_moving_frame
1553 * Draw the frame used when moving or resizing window.
1555 * FIXME: This causes problems in Win95 mode. (why?)
1557 static void draw_moving_frame( HDC hdc, RECT *rect, BOOL thickframe )
1559 if (thickframe)
1561 const int width = GetSystemMetrics(SM_CXFRAME);
1562 const int height = GetSystemMetrics(SM_CYFRAME);
1564 HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
1565 PatBlt( hdc, rect->left, rect->top,
1566 rect->right - rect->left - width, height, PATINVERT );
1567 PatBlt( hdc, rect->left, rect->top + height, width,
1568 rect->bottom - rect->top - height, PATINVERT );
1569 PatBlt( hdc, rect->left + width, rect->bottom - 1,
1570 rect->right - rect->left - width, -height, PATINVERT );
1571 PatBlt( hdc, rect->right - 1, rect->top, -width,
1572 rect->bottom - rect->top - height, PATINVERT );
1573 SelectObject( hdc, hbrush );
1575 else DrawFocusRect( hdc, rect );
1579 /***********************************************************************
1580 * start_size_move
1582 * Initialisation of a move or resize, when initiatied from a menu choice.
1583 * Return hit test code for caption or sizing border.
1585 static LONG start_size_move( HWND hwnd, WPARAM wParam, POINT *capturePoint, LONG style )
1587 LONG hittest = 0;
1588 POINT pt;
1589 MSG msg;
1590 RECT rectWindow;
1592 GetWindowRect( hwnd, &rectWindow );
1594 if ((wParam & 0xfff0) == SC_MOVE)
1596 /* Move pointer at the center of the caption */
1597 RECT rect;
1598 NC_GetInsideRect( hwnd, &rect );
1599 if (style & WS_SYSMENU)
1600 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1601 if (style & WS_MINIMIZEBOX)
1602 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1603 if (style & WS_MAXIMIZEBOX)
1604 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1605 pt.x = rectWindow.left + (rect.right - rect.left) / 2;
1606 pt.y = rectWindow.top + rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1607 hittest = HTCAPTION;
1608 *capturePoint = pt;
1610 else /* SC_SIZE */
1612 while(!hittest)
1614 GetMessageW( &msg, 0, WM_KEYFIRST, WM_MOUSELAST );
1615 if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
1617 switch(msg.message)
1619 case WM_MOUSEMOVE:
1620 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1621 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT))
1622 hittest = 0;
1623 break;
1625 case WM_LBUTTONUP:
1626 return 0;
1628 case WM_KEYDOWN:
1629 switch(msg.wParam)
1631 case VK_UP:
1632 hittest = HTTOP;
1633 pt.x =(rectWindow.left+rectWindow.right)/2;
1634 pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
1635 break;
1636 case VK_DOWN:
1637 hittest = HTBOTTOM;
1638 pt.x =(rectWindow.left+rectWindow.right)/2;
1639 pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
1640 break;
1641 case VK_LEFT:
1642 hittest = HTLEFT;
1643 pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
1644 pt.y =(rectWindow.top+rectWindow.bottom)/2;
1645 break;
1646 case VK_RIGHT:
1647 hittest = HTRIGHT;
1648 pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
1649 pt.y =(rectWindow.top+rectWindow.bottom)/2;
1650 break;
1651 case VK_RETURN:
1652 case VK_ESCAPE: return 0;
1656 *capturePoint = pt;
1658 SetCursorPos( pt.x, pt.y );
1659 NC_HandleSetCursor( hwnd, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
1660 return hittest;
1664 /***********************************************************************
1665 * set_movesize_capture
1667 static void set_movesize_capture( HWND hwnd )
1669 HWND previous = 0;
1671 SERVER_START_REQ( set_capture_window )
1673 req->handle = hwnd;
1674 req->flags = CAPTURE_MOVESIZE;
1675 if (!wine_server_call_err( req ))
1677 previous = reply->previous;
1678 hwnd = reply->full_handle;
1681 SERVER_END_REQ;
1682 if (previous && previous != hwnd)
1683 SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
1686 /***********************************************************************
1687 * X11DRV_WMMoveResizeWindow
1689 * Tells the window manager to initiate a move or resize operation.
1691 * SEE
1692 * http://freedesktop.org/Standards/wm-spec/1.3/ar01s04.html
1693 * or search for "_NET_WM_MOVERESIZE"
1695 static void X11DRV_WMMoveResizeWindow( HWND hwnd, int x, int y, int dir )
1697 XEvent xev;
1698 Display *display = thread_display();
1700 wine_tsx11_lock();
1702 /* need to ungrab the pointer that may have been automatically grabbed
1703 * with a ButtonPress event */
1704 XUngrabPointer( display, CurrentTime );
1706 xev.xclient.type = ClientMessage;
1707 xev.xclient.window = X11DRV_get_whole_window(hwnd);
1708 xev.xclient.message_type = x11drv_atom(_NET_WM_MOVERESIZE);
1709 xev.xclient.serial = 0;
1710 xev.xclient.display = display;
1711 xev.xclient.send_event = True;
1712 xev.xclient.format = 32;
1713 xev.xclient.data.l[0] = x; /* x coord */
1714 xev.xclient.data.l[1] = y; /* y coord */
1715 xev.xclient.data.l[2] = dir; /* direction */
1716 xev.xclient.data.l[3] = 1; /* button */
1717 xev.xclient.data.l[4] = 0; /* unused */
1718 XSendEvent(display, root_window, False, SubstructureNotifyMask, &xev);
1720 wine_tsx11_unlock();
1723 /***********************************************************************
1724 * SysCommandSizeMove (X11DRV.@)
1726 * Perform SC_MOVE and SC_SIZE commands.
1728 void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
1730 MSG msg;
1731 RECT sizingRect, mouseRect, origRect;
1732 HDC hdc;
1733 HWND parent;
1734 LONG hittest = (LONG)(wParam & 0x0f);
1735 WPARAM syscommand = wParam & 0xfff0;
1736 HCURSOR hDragCursor = 0, hOldCursor = 0;
1737 POINT minTrack, maxTrack;
1738 POINT capturePoint, pt;
1739 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1740 LONG exstyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
1741 BOOL thickframe = HAS_THICKFRAME( style, exstyle );
1742 BOOL iconic = style & WS_MINIMIZE;
1743 BOOL moved = FALSE;
1744 DWORD dwPoint = GetMessagePos ();
1745 BOOL DragFullWindows = FALSE;
1746 BOOL grab;
1747 int iWndsLocks;
1748 Display *old_gdi_display = NULL;
1749 Display *display = thread_display();
1751 pt.x = (short)LOWORD(dwPoint);
1752 pt.y = (short)HIWORD(dwPoint);
1753 capturePoint = pt;
1755 if (IsZoomed(hwnd) || !IsWindowVisible(hwnd)) return;
1757 /* if we are managed then we let the WM do all the work */
1758 if (exstyle & WS_EX_MANAGED)
1760 int dir;
1761 if (syscommand == SC_MOVE)
1763 if (!hittest) dir = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
1764 else dir = _NET_WM_MOVERESIZE_MOVE;
1766 else if (!hittest) dir = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
1767 else
1768 switch (hittest)
1770 case WMSZ_LEFT: dir = _NET_WM_MOVERESIZE_SIZE_LEFT; break;
1771 case WMSZ_RIGHT: dir = _NET_WM_MOVERESIZE_SIZE_RIGHT; break;
1772 case WMSZ_TOP: dir = _NET_WM_MOVERESIZE_SIZE_TOP; break;
1773 case WMSZ_TOPLEFT: dir = _NET_WM_MOVERESIZE_SIZE_TOPLEFT; break;
1774 case WMSZ_TOPRIGHT: dir = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT; break;
1775 case WMSZ_BOTTOM: dir = _NET_WM_MOVERESIZE_SIZE_BOTTOM; break;
1776 case WMSZ_BOTTOMLEFT: dir = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; break;
1777 case WMSZ_BOTTOMRIGHT: dir = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; break;
1778 default:
1779 ERR("Invalid hittest value: %ld\n", hittest);
1780 dir = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
1782 X11DRV_WMMoveResizeWindow( hwnd, pt.x, pt.y, dir );
1783 return;
1786 SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
1788 if (syscommand == SC_MOVE)
1790 if (!hittest) hittest = start_size_move( hwnd, wParam, &capturePoint, style );
1791 if (!hittest) return;
1793 else /* SC_SIZE */
1795 if ( hittest && (syscommand != SC_MOUSEMENU) )
1796 hittest += (HTLEFT - WMSZ_LEFT);
1797 else
1799 set_movesize_capture( hwnd );
1800 hittest = start_size_move( hwnd, wParam, &capturePoint, style );
1801 if (!hittest)
1803 set_movesize_capture(0);
1804 return;
1809 /* Get min/max info */
1811 WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack );
1812 GetWindowRect( hwnd, &sizingRect );
1813 if (style & WS_CHILD)
1815 parent = GetParent(hwnd);
1816 /* make sizing rect relative to parent */
1817 MapWindowPoints( 0, parent, (POINT*)&sizingRect, 2 );
1818 GetClientRect( parent, &mouseRect );
1820 else
1822 parent = 0;
1823 SetRect(&mouseRect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1825 origRect = sizingRect;
1827 if (ON_LEFT_BORDER(hittest))
1829 mouseRect.left = max( mouseRect.left, sizingRect.right-maxTrack.x );
1830 mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x );
1832 else if (ON_RIGHT_BORDER(hittest))
1834 mouseRect.left = max( mouseRect.left, sizingRect.left+minTrack.x );
1835 mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x );
1837 if (ON_TOP_BORDER(hittest))
1839 mouseRect.top = max( mouseRect.top, sizingRect.bottom-maxTrack.y );
1840 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y);
1842 else if (ON_BOTTOM_BORDER(hittest))
1844 mouseRect.top = max( mouseRect.top, sizingRect.top+minTrack.y );
1845 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y );
1847 if (parent) MapWindowPoints( parent, 0, (LPPOINT)&mouseRect, 2 );
1849 /* Retrieve a default cache DC (without using the window style) */
1850 hdc = GetDCEx( parent, 0, DCX_CACHE );
1852 if( iconic ) /* create a cursor for dragging */
1854 hDragCursor = (HCURSOR)GetClassLongA( hwnd, GCL_HICON);
1855 if( !hDragCursor ) hDragCursor = (HCURSOR)SendMessageA( hwnd, WM_QUERYDRAGICON, 0, 0L);
1856 if( !hDragCursor ) iconic = FALSE;
1859 /* repaint the window before moving it around */
1860 RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
1862 SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
1863 set_movesize_capture( hwnd );
1865 /* grab the server only when moving top-level windows without desktop */
1866 grab = (!DragFullWindows && !parent && (root_window == DefaultRootWindow(gdi_display)));
1868 wine_tsx11_lock();
1869 if (grab)
1871 XSync( gdi_display, False );
1872 XGrabServer( display );
1873 XSync( display, False );
1874 /* switch gdi display to the thread display, since the server is grabbed */
1875 old_gdi_display = gdi_display;
1876 gdi_display = display;
1878 XGrabPointer( display, X11DRV_get_whole_window(hwnd), False,
1879 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1880 GrabModeAsync, GrabModeAsync,
1881 parent ? X11DRV_get_client_window(parent) : root_window,
1882 None, CurrentTime );
1883 wine_tsx11_unlock();
1885 while(1)
1887 int dx = 0, dy = 0;
1889 if (!GetMessageW( &msg, 0, WM_KEYFIRST, WM_MOUSELAST )) break;
1890 if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
1892 /* Exit on button-up, Return, or Esc */
1893 if ((msg.message == WM_LBUTTONUP) ||
1894 ((msg.message == WM_KEYDOWN) &&
1895 ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
1897 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
1898 continue; /* We are not interested in other messages */
1900 pt = msg.pt;
1902 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1904 case VK_UP: pt.y -= 8; break;
1905 case VK_DOWN: pt.y += 8; break;
1906 case VK_LEFT: pt.x -= 8; break;
1907 case VK_RIGHT: pt.x += 8; break;
1910 pt.x = max( pt.x, mouseRect.left );
1911 pt.x = min( pt.x, mouseRect.right );
1912 pt.y = max( pt.y, mouseRect.top );
1913 pt.y = min( pt.y, mouseRect.bottom );
1915 dx = pt.x - capturePoint.x;
1916 dy = pt.y - capturePoint.y;
1918 if (dx || dy)
1920 if( !moved )
1922 moved = TRUE;
1924 if( iconic ) /* ok, no system popup tracking */
1926 hOldCursor = SetCursor(hDragCursor);
1927 ShowCursor( TRUE );
1928 WINPOS_ShowIconTitle( hwnd, FALSE );
1930 else if(!DragFullWindows)
1931 draw_moving_frame( hdc, &sizingRect, thickframe );
1934 if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
1935 else
1937 RECT newRect = sizingRect;
1938 WPARAM wpSizingHit = 0;
1940 if (hittest == HTCAPTION) OffsetRect( &newRect, dx, dy );
1941 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
1942 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
1943 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
1944 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
1945 if(!iconic && !DragFullWindows) draw_moving_frame( hdc, &sizingRect, thickframe );
1946 capturePoint = pt;
1948 /* determine the hit location */
1949 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
1950 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
1951 SendMessageA( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&newRect );
1953 if (!iconic)
1955 if(!DragFullWindows)
1956 draw_moving_frame( hdc, &newRect, thickframe );
1957 else {
1958 /* To avoid any deadlocks, all the locks on the windows
1959 structures must be suspended before the SetWindowPos */
1960 iWndsLocks = WIN_SuspendWndsLock();
1961 SetWindowPos( hwnd, 0, newRect.left, newRect.top,
1962 newRect.right - newRect.left,
1963 newRect.bottom - newRect.top,
1964 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
1965 WIN_RestoreWndsLock(iWndsLocks);
1968 sizingRect = newRect;
1973 set_movesize_capture(0);
1974 if( iconic )
1976 if( moved ) /* restore cursors, show icon title later on */
1978 ShowCursor( FALSE );
1979 SetCursor( hOldCursor );
1982 else if (moved && !DragFullWindows)
1983 draw_moving_frame( hdc, &sizingRect, thickframe );
1985 ReleaseDC( parent, hdc );
1987 wine_tsx11_lock();
1988 XUngrabPointer( display, CurrentTime );
1989 if (grab)
1991 XSync( display, False );
1992 XUngrabServer( display );
1993 XSync( display, False );
1994 gdi_display = old_gdi_display;
1996 wine_tsx11_unlock();
1998 if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE ))
1999 moved = FALSE;
2001 SendMessageA( hwnd, WM_EXITSIZEMOVE, 0, 0 );
2002 SendMessageA( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
2004 /* window moved or resized */
2005 if (moved)
2007 /* To avoid any deadlocks, all the locks on the windows
2008 structures must be suspended before the SetWindowPos */
2009 iWndsLocks = WIN_SuspendWndsLock();
2011 /* if the moving/resizing isn't canceled call SetWindowPos
2012 * with the new position or the new size of the window
2014 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
2016 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
2017 if(!DragFullWindows)
2018 SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
2019 sizingRect.right - sizingRect.left,
2020 sizingRect.bottom - sizingRect.top,
2021 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
2023 else
2024 { /* restore previous size/position */
2025 if(DragFullWindows)
2026 SetWindowPos( hwnd, 0, origRect.left, origRect.top,
2027 origRect.right - origRect.left,
2028 origRect.bottom - origRect.top,
2029 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
2032 WIN_RestoreWndsLock(iWndsLocks);
2035 if (IsIconic(hwnd))
2037 /* Single click brings up the system menu when iconized */
2039 if( !moved )
2041 if(style & WS_SYSMENU )
2042 SendMessageA( hwnd, WM_SYSCOMMAND,
2043 SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
2045 else WINPOS_ShowIconTitle( hwnd, TRUE );
2050 /***********************************************************************
2051 * ForceWindowRaise (X11DRV.@)
2053 * Raise a window on top of the X stacking order, while preserving
2054 * the correct Windows Z order.
2056 * FIXME: this should go away.
2058 void X11DRV_ForceWindowRaise( HWND hwnd )
2060 int i = 0;
2061 HWND *list;
2062 XWindowChanges winChanges;
2063 Display *display = thread_display();
2064 WND *wndPtr = WIN_FindWndPtr( hwnd );
2066 if (!wndPtr) return;
2068 if ((wndPtr->dwExStyle & WS_EX_MANAGED) ||
2069 wndPtr->parent != GetDesktopWindow() ||
2070 IsRectEmpty( &wndPtr->rectWindow ) ||
2071 !get_whole_window(wndPtr))
2073 WIN_ReleaseWndPtr( wndPtr );
2074 return;
2076 WIN_ReleaseWndPtr( wndPtr );
2078 /* Raise all windows up to wndPtr according to their Z order.
2079 * (it would be easier with sibling-related Below but it doesn't
2080 * work very well with SGI mwm for instance)
2082 winChanges.stack_mode = Above;
2083 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return;
2084 while (list[i] && list[i] != hwnd) i++;
2085 if (list[i])
2087 for ( ; i >= 0; i--)
2089 WND *ptr = WIN_FindWndPtr( list[i] );
2090 if (!ptr) continue;
2091 if (!IsRectEmpty( &ptr->rectWindow ) && get_whole_window(ptr))
2093 wine_tsx11_lock();
2094 XReconfigureWMWindow( display, get_whole_window(ptr), 0, CWStackMode, &winChanges );
2095 wine_tsx11_unlock();
2097 WIN_ReleaseWndPtr( ptr );
2100 HeapFree( GetProcessHeap(), 0, list );