2 * Window position related functions.
4 * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
5 * Copyright 1995, 1996, 1999 Alex Korobka
24 #include "cursoricon.h"
25 #include "nonclient.h"
28 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(x11drv);
32 #define SWP_AGG_NOGEOMETRYCHANGE \
33 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
34 #define SWP_AGG_NOPOSCHANGE \
35 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
36 #define SWP_AGG_STATUSFLAGS \
37 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
39 #define SWP_EX_NOCOPY 0x0001
40 #define SWP_EX_PAINTSELF 0x0002
41 #define SWP_EX_NONCLIENT 0x0004
43 #define HAS_THICKFRAME(style,exStyle) \
44 (((style) & WS_THICKFRAME) && \
45 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
47 #define ON_LEFT_BORDER(hit) \
48 (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
49 #define ON_RIGHT_BORDER(hit) \
50 (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
51 #define ON_TOP_BORDER(hit) \
52 (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
53 #define ON_BOTTOM_BORDER(hit) \
54 (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
57 /***********************************************************************
60 * Clip all children of a given window out of the visible region
62 static void clip_children( WND *win, HRGN hrgn, int whole_window )
68 /* first check if we have anything to do */
69 for (ptr = win->child; ptr; ptr = ptr->next)
70 if (ptr->dwStyle & WS_VISIBLE) break;
71 if (!ptr) return; /* no children to clip */
75 x = win->rectWindow.left - win->rectClient.left;
76 y = win->rectWindow.top - win->rectClient.top;
80 rectRgn = CreateRectRgn( 0, 0, 0, 0 );
83 if (ptr->dwStyle & WS_VISIBLE)
85 SetRectRgn( rectRgn, ptr->rectWindow.left + x, ptr->rectWindow.top + y,
86 ptr->rectWindow.right + x, ptr->rectWindow.bottom + y );
87 if (CombineRgn( hrgn, hrgn, rectRgn, RGN_DIFF ) == NULLREGION)
88 break; /* no need to go on, region is empty */
92 DeleteObject( rectRgn );
96 /***********************************************************************
99 * Compute the visible region of a window
101 static HRGN get_visible_region( WND *win, UINT flags )
105 int xoffset, yoffset;
106 X11DRV_WND_DATA *data = win->pDriverData;
108 if (flags & DCX_WINDOW)
110 xoffset = win->rectWindow.left;
111 yoffset = win->rectWindow.top;
115 xoffset = win->rectClient.left;
116 yoffset = win->rectClient.top;
119 if (flags & DCX_PARENTCLIP)
120 GetClientRect( win->parent->hwndSelf, &rect );
121 else if (flags & DCX_WINDOW)
122 rect = data->whole_rect;
124 rect = win->rectClient;
126 /* vis region is relative to the start of the client/window area */
127 OffsetRect( &rect, -xoffset, -yoffset );
129 if (!(rgn = CreateRectRgn( rect.left, rect.top, rect.right, rect.bottom ))) return 0;
131 if (flags & DCX_CLIPCHILDREN)
133 /* if we are clipping siblings and using the client area,
134 * X will do the clipping for us; otherwise, we need to
135 * clip children by hand here
137 if ((flags & DCX_WINDOW) || !(flags & DCX_CLIPSIBLINGS))
138 clip_children( win, rgn, (flags & DCX_WINDOW) );
144 /***********************************************************************
147 * Set the drawable, origin and dimensions for the DC associated to
150 BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
152 WND *win = WIN_FindWndPtr( hwnd );
153 X11DRV_WND_DATA *data = win->pDriverData;
155 int org_x, org_y, mode = IncludeInferiors;
157 /* don't clip siblings if using parent clip region */
158 if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS;
160 if (flags & DCX_CLIPSIBLINGS)
162 if (IsIconic( hwnd ))
164 drawable = data->icon_window ? data->icon_window : data->whole_window;
168 else if (flags & DCX_WINDOW)
170 drawable = data->whole_window;
171 org_x = win->rectWindow.left - data->whole_rect.left;
172 org_y = win->rectWindow.top - data->whole_rect.top;
176 drawable = data->client_window;
179 if (flags & DCX_CLIPCHILDREN) mode = ClipByChildren; /* can use X11 clipping */
184 /* not clipping siblings -> have to use parent client drawable */
185 if (win->parent) drawable = get_client_window( win->parent );
186 else drawable = root_window;
187 if (flags & DCX_WINDOW)
189 org_x = win->rectWindow.left;
190 org_y = win->rectWindow.top;
194 org_x = win->rectClient.left;
195 org_y = win->rectClient.top;
199 X11DRV_SetDrawable( hdc, drawable, mode, org_x, org_y );
201 if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) ||
202 SetHookFlags16( hdc, DCHF_VALIDATEVISRGN )) /* DC was dirty */
204 /* need to recompute the visible region */
205 HRGN visRgn = get_visible_region( win, flags );
207 if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
208 CombineRgn( visRgn, visRgn, hrgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
210 /* make it relative to the drawable origin */
211 OffsetRgn( visRgn, org_x, org_y );
212 SelectVisRgn16( hdc, visRgn );
213 DeleteObject( visRgn );
216 WIN_ReleaseWndPtr( win );
222 /***********************************************************************
223 * SWP_DoWinPosChanging
225 static BOOL SWP_DoWinPosChanging( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT* pNewClientRect )
229 /* Send WM_WINDOWPOSCHANGING message */
231 if (!(pWinpos->flags & SWP_NOSENDCHANGING))
232 SendMessageA( pWinpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
234 if (!(wndPtr = WIN_FindWndPtr( pWinpos->hwnd ))) return FALSE;
236 /* Calculate new position and size */
238 *pNewWindowRect = wndPtr->rectWindow;
239 *pNewClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
240 : wndPtr->rectClient;
242 if (!(pWinpos->flags & SWP_NOSIZE))
244 pNewWindowRect->right = pNewWindowRect->left + pWinpos->cx;
245 pNewWindowRect->bottom = pNewWindowRect->top + pWinpos->cy;
247 if (!(pWinpos->flags & SWP_NOMOVE))
249 pNewWindowRect->left = pWinpos->x;
250 pNewWindowRect->top = pWinpos->y;
251 pNewWindowRect->right += pWinpos->x - wndPtr->rectWindow.left;
252 pNewWindowRect->bottom += pWinpos->y - wndPtr->rectWindow.top;
254 OffsetRect( pNewClientRect, pWinpos->x - wndPtr->rectWindow.left,
255 pWinpos->y - wndPtr->rectWindow.top );
257 pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
258 WIN_ReleaseWndPtr( wndPtr );
262 /***********************************************************************
265 static UINT SWP_DoNCCalcSize( WND* wndPtr, WINDOWPOS* pWinpos,
266 RECT* pNewWindowRect, RECT* pNewClientRect )
270 /* Send WM_NCCALCSIZE message to get new client area */
271 if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
273 wvrFlags = WINPOS_SendNCCalcSize( pWinpos->hwnd, TRUE, pNewWindowRect,
274 &wndPtr->rectWindow, &wndPtr->rectClient,
275 pWinpos, pNewClientRect );
276 /* FIXME: WVR_ALIGNxxx */
278 if( pNewClientRect->left != wndPtr->rectClient.left ||
279 pNewClientRect->top != wndPtr->rectClient.top )
280 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
282 if( (pNewClientRect->right - pNewClientRect->left !=
283 wndPtr->rectClient.right - wndPtr->rectClient.left) ||
284 (pNewClientRect->bottom - pNewClientRect->top !=
285 wndPtr->rectClient.bottom - wndPtr->rectClient.top) )
286 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
289 if( !(pWinpos->flags & SWP_NOMOVE) && (pNewClientRect->left != wndPtr->rectClient.left ||
290 pNewClientRect->top != wndPtr->rectClient.top) )
291 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
295 /***********************************************************************
298 * fix Z order taking into account owned popups -
299 * basically we need to maintain them above the window that owns them
301 * FIXME: hide/show owned popups when owner visibility changes.
303 static HWND SWP_DoOwnedPopups(WND* pDesktop, WND* wndPtr, HWND hwndInsertAfter, WORD flags)
305 WND *w = WIN_LockWndPtr(pDesktop->child);
307 WARN("(%04x) hInsertAfter = %04x\n", wndPtr->hwndSelf, hwndInsertAfter );
309 if( (wndPtr->dwStyle & WS_POPUP) && wndPtr->owner )
311 /* make sure this popup stays above the owner */
313 HWND hwndLocalPrev = HWND_TOP;
315 if( hwndInsertAfter != HWND_TOP )
317 while( w && w != wndPtr->owner )
319 if (w != wndPtr) hwndLocalPrev = w->hwndSelf;
320 if( hwndLocalPrev == hwndInsertAfter ) break;
321 WIN_UpdateWndPtr(&w,w->next);
323 hwndInsertAfter = hwndLocalPrev;
326 else if( wndPtr->dwStyle & WS_CHILD )
329 WIN_UpdateWndPtr(&w, pDesktop->child);
333 if( w == wndPtr ) break;
335 if( (w->dwStyle & WS_POPUP) && w->owner == wndPtr )
337 SetWindowPos(w->hwndSelf, hwndInsertAfter, 0, 0, 0, 0,
338 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE);
339 hwndInsertAfter = w->hwndSelf;
341 WIN_UpdateWndPtr(&w, w->next);
345 WIN_ReleaseWndPtr(w);
346 return hwndInsertAfter;
350 /* fix redundant flags and values in the WINDOWPOS structure */
351 static BOOL fixup_flags( WINDOWPOS *winpos )
353 WND *wndPtr = WIN_FindWndPtr( winpos->hwnd );
356 if (!wndPtr) return FALSE;
358 if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
361 winpos->flags &= ~SWP_HIDEWINDOW;
362 if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
365 if (winpos->cx < 0) winpos->cx = 0;
366 if (winpos->cy < 0) winpos->cy = 0;
368 if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == winpos->cx) &&
369 (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == winpos->cy))
370 winpos->flags |= SWP_NOSIZE; /* Already the right size */
372 if ((wndPtr->rectWindow.left == winpos->x) && (wndPtr->rectWindow.top == winpos->y))
373 winpos->flags |= SWP_NOMOVE; /* Already the right position */
375 if (winpos->hwnd == GetForegroundWindow())
376 winpos->flags |= SWP_NOACTIVATE; /* Already active */
377 else if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
379 if (!(winpos->flags & SWP_NOACTIVATE)) /* Bring to the top when activating */
381 winpos->flags &= ~SWP_NOZORDER;
382 winpos->hwndInsertAfter = HWND_TOP;
387 /* Check hwndInsertAfter */
389 /* FIXME: TOPMOST not supported yet */
390 if ((winpos->hwndInsertAfter == HWND_TOPMOST) ||
391 (winpos->hwndInsertAfter == HWND_NOTOPMOST)) winpos->hwndInsertAfter = HWND_TOP;
393 /* hwndInsertAfter must be a sibling of the window */
394 if ((winpos->hwndInsertAfter != HWND_TOP) && (winpos->hwndInsertAfter != HWND_BOTTOM))
396 WND* wnd = WIN_FindWndPtr(winpos->hwndInsertAfter);
399 if (wnd->parent != wndPtr->parent) ret = FALSE;
402 /* don't need to change the Zorder of hwnd if it's already inserted
403 * after hwndInsertAfter or when inserting hwnd after itself.
405 if ((wnd->next == wndPtr ) || (winpos->hwnd == winpos->hwndInsertAfter))
406 winpos->flags |= SWP_NOZORDER;
408 WIN_ReleaseWndPtr(wnd);
412 WIN_ReleaseWndPtr(wndPtr);
417 /***********************************************************************
418 * SetWindowPos (X11DRV.@)
420 BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
423 RECT newWindowRect, newClientRect;
424 RECT oldWindowRect, oldClientRect;
428 TRACE( "hwnd %04x, swp (%i,%i)-(%i,%i) flags %08x\n",
429 winpos->hwnd, winpos->x, winpos->y,
430 winpos->x + winpos->cx, winpos->y + winpos->cy, winpos->flags);
432 bChangePos = !(winpos->flags & SWP_WINE_NOHOSTMOVE);
433 winpos->flags &= ~SWP_WINE_NOHOSTMOVE;
435 /* Check window handle */
436 if (winpos->hwnd == GetDesktopWindow()) return FALSE;
438 /* Fix redundant flags */
439 if (!fixup_flags( winpos )) return FALSE;
441 SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect );
443 if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
445 TRACE("\tcurrent (%i,%i)-(%i,%i), style %08x\n",
446 wndPtr->rectWindow.left, wndPtr->rectWindow.top,
447 wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle );
449 if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
451 if( wndPtr->parent->hwndSelf == GetDesktopWindow() )
452 winpos->hwndInsertAfter = SWP_DoOwnedPopups( wndPtr->parent, wndPtr,
453 winpos->hwndInsertAfter, winpos->flags );
456 /* Common operations */
458 wvrFlags = SWP_DoNCCalcSize( wndPtr, winpos, &newWindowRect, &newClientRect );
460 if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter)
462 if ( WIN_UnlinkWindow( winpos->hwnd ) )
463 WIN_LinkWindow( winpos->hwnd, winpos->hwndInsertAfter );
466 /* Reset active DCEs */
468 if( (((winpos->flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) &&
469 wndPtr->dwStyle & WS_VISIBLE) ||
470 (winpos->flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) )
474 UnionRect(&rect, &newWindowRect, &wndPtr->rectWindow);
475 DCE_InvalidateDCE(wndPtr, &rect);
478 oldWindowRect = wndPtr->rectWindow;
479 oldClientRect = wndPtr->rectClient;
481 /* Find out if we have to redraw the whole client rect */
483 if( oldClientRect.bottom - oldClientRect.top ==
484 newClientRect.bottom - newClientRect.top ) wvrFlags &= ~WVR_VREDRAW;
486 if( oldClientRect.right - oldClientRect.left ==
487 newClientRect.right - newClientRect.left ) wvrFlags &= ~WVR_HREDRAW;
489 /* FIXME: actually do something with WVR_VALIDRECTS */
491 wndPtr->rectWindow = newWindowRect;
492 wndPtr->rectClient = newClientRect;
494 if (winpos->flags & SWP_SHOWWINDOW) wndPtr->dwStyle |= WS_VISIBLE;
495 else if (winpos->flags & SWP_HIDEWINDOW)
497 /* clear the update region */
498 RedrawWindow( winpos->hwnd, NULL, 0, RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
499 RDW_NOINTERNALPAINT | RDW_ALLCHILDREN );
500 wndPtr->dwStyle &= ~WS_VISIBLE;
503 if (get_whole_window(wndPtr)) /* don't do anything if X window not created yet */
505 Display *display = thread_display();
508 if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW))
510 if (!IsRectEmpty( &oldWindowRect ))
512 XUnmapWindow( display, get_whole_window(wndPtr) );
513 TRACE( "unmapping win %x\n", winpos->hwnd );
515 else TRACE( "not unmapping zero size win %x\n", winpos->hwnd );
517 else if ((wndPtr->dwStyle & WS_VISIBLE) &&
518 !IsRectEmpty( &oldWindowRect ) && IsRectEmpty( &newWindowRect ))
520 /* resizing to zero size -> unmap */
521 TRACE( "unmapping zero size win %x\n", winpos->hwnd );
522 XUnmapWindow( display, get_whole_window(wndPtr) );
526 X11DRV_sync_whole_window_position( display, wndPtr, !(winpos->flags & SWP_NOZORDER) );
529 struct x11drv_win_data *data = wndPtr->pDriverData;
530 data->whole_rect = wndPtr->rectWindow;
531 X11DRV_window_to_X_rect( wndPtr, &data->whole_rect );
534 if (X11DRV_sync_client_window_position( display, wndPtr ) ||
535 (winpos->flags & SWP_FRAMECHANGED))
537 /* if we moved the client area, repaint the whole non-client window */
538 XClearArea( display, get_whole_window(wndPtr), 0, 0, 0, 0, True );
540 if (winpos->flags & SWP_SHOWWINDOW)
542 if (!IsRectEmpty( &newWindowRect ))
544 XMapWindow( display, get_whole_window(wndPtr) );
545 TRACE( "mapping win %x\n", winpos->hwnd );
547 else TRACE( "not mapping win %x, size is zero\n", winpos->hwnd );
549 else if ((wndPtr->dwStyle & WS_VISIBLE) &&
550 IsRectEmpty( &oldWindowRect ) && !IsRectEmpty( &newWindowRect ))
552 /* resizing from zero size to non-zero -> map */
553 TRACE( "mapping non zero size win %x\n", winpos->hwnd );
554 XMapWindow( display, get_whole_window(wndPtr) );
556 XFlush( display ); /* FIXME: should not be necessary */
560 WIN_ReleaseWndPtr(wndPtr);
562 if (wvrFlags & WVR_REDRAW) RedrawWindow( winpos->hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE );
564 if (winpos->hwnd == CARET_GetHwnd())
566 if( winpos->flags & SWP_HIDEWINDOW )
567 HideCaret(winpos->hwnd);
568 else if (winpos->flags & SWP_SHOWWINDOW)
569 ShowCaret(winpos->hwnd);
572 if (!(winpos->flags & SWP_NOACTIVATE))
573 WINPOS_ChangeActiveWindow( winpos->hwnd, FALSE );
575 /* And last, send the WM_WINDOWPOSCHANGED message */
577 TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
579 if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE) &&
580 !(winpos->flags & SWP_NOSENDCHANGING))
581 SendMessageA( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
587 /***********************************************************************
590 * Find a suitable place for an iconic window.
592 static POINT WINPOS_FindIconPos( WND* wndPtr, POINT pt )
595 short x, y, xspacing, yspacing;
597 GetClientRect( wndPtr->parent->hwndSelf, &rectParent );
598 if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics(SM_CXICON) < rectParent.right) &&
599 (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics(SM_CYICON) < rectParent.bottom))
600 return pt; /* The icon already has a suitable position */
602 xspacing = GetSystemMetrics(SM_CXICONSPACING);
603 yspacing = GetSystemMetrics(SM_CYICONSPACING);
605 y = rectParent.bottom;
611 /* Check if another icon already occupies this spot */
612 WND *childPtr = WIN_LockWndPtr(wndPtr->parent->child);
615 if ((childPtr->dwStyle & WS_MINIMIZE) && (childPtr != wndPtr))
617 if ((childPtr->rectWindow.left < x + xspacing) &&
618 (childPtr->rectWindow.right >= x) &&
619 (childPtr->rectWindow.top <= y) &&
620 (childPtr->rectWindow.bottom > y - yspacing))
621 break; /* There's a window in there */
623 WIN_UpdateWndPtr(&childPtr,childPtr->next);
625 WIN_ReleaseWndPtr(childPtr);
626 if (!childPtr) /* No window was found, so it's OK for us */
628 pt.x = x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2;
629 pt.y = y - (yspacing + GetSystemMetrics(SM_CYICON)) / 2;
633 } while(x <= rectParent.right-xspacing);
642 UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
644 WND *wndPtr = WIN_FindWndPtr( hwnd );
649 TRACE("0x%04x %u\n", hwnd, cmd );
651 wpl.length = sizeof(wpl);
652 GetWindowPlacement( hwnd, &wpl );
654 size.x = wndPtr->rectWindow.left;
655 size.y = wndPtr->rectWindow.top;
657 if (!HOOK_CallHooksA(WH_CBT, HCBT_MINMAX, wndPtr->hwndSelf, cmd))
659 if( wndPtr->dwStyle & WS_MINIMIZE )
661 if( !SendMessageA( wndPtr->hwndSelf, WM_QUERYOPEN, 0, 0L ) )
663 swpFlags = SWP_NOSIZE | SWP_NOMOVE;
666 swpFlags |= SWP_NOCOPYBITS;
671 if( wndPtr->dwStyle & WS_MAXIMIZE)
673 wndPtr->flags |= WIN_RESTORE_MAX;
674 wndPtr->dwStyle &= ~WS_MAXIMIZE;
677 wndPtr->flags &= ~WIN_RESTORE_MAX;
678 wndPtr->dwStyle |= WS_MINIMIZE;
680 X11DRV_set_iconic_state( wndPtr );
682 wpl.ptMinPosition = WINPOS_FindIconPos( wndPtr, wpl.ptMinPosition );
684 SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
685 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) );
686 swpFlags |= SWP_NOCOPYBITS;
690 WINPOS_GetMinMaxInfo( wndPtr, &size, &wpl.ptMaxPosition, NULL, NULL );
692 if( wndPtr->dwStyle & WS_MINIMIZE )
694 wndPtr->dwStyle &= ~WS_MINIMIZE;
695 WINPOS_ShowIconTitle( wndPtr, FALSE );
696 X11DRV_set_iconic_state( wndPtr );
698 wndPtr->dwStyle |= WS_MAXIMIZE;
700 SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
704 if( wndPtr->dwStyle & WS_MINIMIZE )
706 wndPtr->dwStyle &= ~WS_MINIMIZE;
707 WINPOS_ShowIconTitle( wndPtr, FALSE );
708 X11DRV_set_iconic_state( wndPtr );
710 if( wndPtr->flags & WIN_RESTORE_MAX)
712 /* Restore to maximized position */
713 WINPOS_GetMinMaxInfo( wndPtr, &size, &wpl.ptMaxPosition, NULL, NULL);
714 wndPtr->dwStyle |= WS_MAXIMIZE;
715 SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
720 if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
722 swpFlags = (UINT16)(-1);
725 else wndPtr->dwStyle &= ~WS_MAXIMIZE;
727 /* Restore to normal position */
729 *rect = wpl.rcNormalPosition;
730 rect->right -= rect->left;
731 rect->bottom -= rect->top;
735 } else swpFlags |= SWP_NOSIZE | SWP_NOMOVE;
738 WIN_ReleaseWndPtr( wndPtr );
743 /***********************************************************************
744 * X11DRV_ShowWindow (X11DRV.@)
746 BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd )
748 WND* wndPtr = WIN_FindWndPtr( hwnd );
749 BOOL wasVisible, showFlag;
750 RECT newPos = {0, 0, 0, 0};
753 if (!wndPtr) return FALSE;
755 TRACE("hwnd=%04x, cmd=%d\n", hwnd, cmd);
757 wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
762 if (!wasVisible) goto END;;
763 swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
764 SWP_NOACTIVATE | SWP_NOZORDER;
767 case SW_SHOWMINNOACTIVE:
768 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
770 case SW_SHOWMINIMIZED:
771 swp |= SWP_SHOWWINDOW;
774 swp |= SWP_FRAMECHANGED;
775 if( !(wndPtr->dwStyle & WS_MINIMIZE) )
776 swp |= WINPOS_MinMaximize( hwnd, SW_MINIMIZE, &newPos );
777 else swp |= SWP_NOSIZE | SWP_NOMOVE;
780 case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
781 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
782 if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
783 swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
784 else swp |= SWP_NOSIZE | SWP_NOMOVE;
788 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
791 swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
794 * ShowWindow has a little peculiar behavior that if the
795 * window is already the topmost window, it will not
798 if (GetTopWindow((HWND)0)==hwnd && (wasVisible || GetActiveWindow() == hwnd))
799 swp |= SWP_NOACTIVATE;
803 case SW_SHOWNOACTIVATE:
805 if (GetActiveWindow()) swp |= SWP_NOACTIVATE;
807 case SW_SHOWNORMAL: /* same as SW_NORMAL: */
808 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
810 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
812 if( wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE) )
813 swp |= WINPOS_MinMaximize( hwnd, SW_RESTORE, &newPos );
814 else swp |= SWP_NOSIZE | SWP_NOMOVE;
818 showFlag = (cmd != SW_HIDE);
819 if (showFlag != wasVisible)
821 SendMessageA( hwnd, WM_SHOWWINDOW, showFlag, 0 );
822 if (!IsWindow( hwnd )) goto END;
825 /* We can't activate a child window */
826 if ((wndPtr->dwStyle & WS_CHILD) &&
827 !(wndPtr->dwExStyle & WS_EX_MDICHILD))
828 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
830 SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
831 newPos.right, newPos.bottom, LOWORD(swp) );
834 /* FIXME: This will cause the window to be activated irrespective
835 * of whether it is owned by the same thread. Has to be done
839 if (hwnd == GetActiveWindow())
840 WINPOS_ActivateOtherWindow(wndPtr);
842 /* Revert focus to parent */
843 if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
844 SetFocus( GetParent(hwnd) );
846 if (!IsWindow( hwnd )) goto END;
847 else if( wndPtr->dwStyle & WS_MINIMIZE ) WINPOS_ShowIconTitle( wndPtr, TRUE );
849 if (wndPtr->flags & WIN_NEED_SIZE)
851 /* should happen only in CreateWindowEx() */
852 int wParam = SIZE_RESTORED;
854 wndPtr->flags &= ~WIN_NEED_SIZE;
855 if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
856 else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
857 SendMessageA( hwnd, WM_SIZE, wParam,
858 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
859 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
860 SendMessageA( hwnd, WM_MOVE, 0,
861 MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
865 WIN_ReleaseWndPtr(wndPtr);
870 /**********************************************************************
873 void X11DRV_MapNotify( HWND hwnd, XMapEvent *event )
875 HWND hwndFocus = GetFocus();
878 if (!(win = WIN_FindWndPtr( hwnd ))) return;
880 if ((win->dwStyle & WS_VISIBLE) &&
881 (win->dwStyle & WS_MINIMIZE) &&
882 (win->dwExStyle & WS_EX_MANAGED))
885 unsigned int width, height, border, depth;
889 DCE_InvalidateDCE( win, &win->rectWindow );
890 win->dwStyle &= ~WS_MINIMIZE;
891 win->dwStyle |= WS_VISIBLE;
892 WIN_InternalShowOwnedPopups( hwnd, TRUE, TRUE );
894 if (win->flags & WIN_RESTORE_MAX)
895 win->dwStyle |= WS_MAXIMIZE;
897 win->dwStyle &= ~WS_MAXIMIZE;
901 XGetGeometry( event->display, get_whole_window(win), &root, &x, &y, &width, &height,
903 XTranslateCoordinates( event->display, get_whole_window(win), root, 0, 0, &x, &y, &top );
907 rect.right = x + width;
908 rect.bottom = y + height;
909 X11DRV_X_to_window_rect( win, &rect );
911 SendMessageA( hwnd, WM_SHOWWINDOW, SW_RESTORE, 0 );
912 SetWindowPos( hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
913 SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
915 if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus); /* FIXME */
916 WIN_ReleaseWndPtr( win );
920 /**********************************************************************
923 void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event )
927 if (!(win = WIN_FindWndPtr( hwnd ))) return;
929 if ((win->dwStyle & WS_VISIBLE) && (win->dwExStyle & WS_EX_MANAGED))
932 SendMessageA( hwnd, WM_SHOWWINDOW, SW_MINIMIZE, 0 );
934 win->flags &= ~WIN_RESTORE_MAX;
935 win->dwStyle |= WS_MINIMIZE;
937 if (win->dwStyle & WS_MAXIMIZE)
939 win->flags |= WIN_RESTORE_MAX;
940 win->dwStyle &= ~WS_MAXIMIZE;
943 SetWindowPos( hwnd, 0, 0, 0, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
944 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
946 WIN_InternalShowOwnedPopups( hwnd, FALSE, TRUE );
948 WIN_ReleaseWndPtr( win );
952 /***********************************************************************
955 * Synchronize internal z-order with the window manager's.
957 static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
959 /* return TRUE if we have at least two managed windows */
961 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
962 if( ((*pWndA)->dwExStyle & WS_EX_MANAGED) &&
963 ((*pWndA)->dwStyle & WS_VISIBLE )) break;
965 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
966 if( ((*pWndB)->dwExStyle & WS_EX_MANAGED) &&
967 ((*pWndB)->dwStyle & WS_VISIBLE )) break;
968 return ((*pWndB) != NULL);
971 static Window __get_common_ancestor( Display *display, Window A, Window B,
972 Window** children, unsigned* total )
974 /* find the real root window */
976 Window root, *childrenB;
979 while( A != B && A && B )
981 TSXQueryTree( display, A, &root, &A, children, total );
982 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
983 if( childrenB ) TSXFree( childrenB );
984 if( *children ) TSXFree( *children ), *children = NULL;
989 TSXQueryTree( display, A, &root, &B, children, total );
995 static Window __get_top_decoration( Display *display, Window w, Window ancestor )
997 Window* children, root, prev = w, parent = w;
1003 TSXQueryTree( display, w, &root, &parent, &children, &total );
1004 if( children ) TSXFree( children );
1005 } while( parent && parent != ancestor );
1006 TRACE("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
1007 return ( parent ) ? w : 0 ;
1010 static unsigned __td_lookup( Window w, Window* list, unsigned max )
1013 for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
1017 static HWND query_zorder( Display *display, HWND hWndCheck)
1019 HWND hwndInsertAfter = HWND_TOP;
1020 WND *pWndCheck = WIN_FindWndPtr(hWndCheck);
1021 WND *pDesktop = WIN_GetDesktop();
1022 WND *pWnd, *pWndZ = WIN_LockWndPtr(pDesktop->child);
1023 Window w, parent, *children = NULL;
1024 unsigned total, check, pos, best;
1026 if( !__check_query_condition(&pWndZ, &pWnd) )
1028 WIN_ReleaseWndPtr(pWndCheck);
1029 WIN_ReleaseWndPtr(pDesktop->child);
1030 WIN_ReleaseDesktop();
1031 return hwndInsertAfter;
1033 WIN_LockWndPtr(pWndZ);
1034 WIN_LockWndPtr(pWnd);
1035 WIN_ReleaseWndPtr(pDesktop->child);
1036 WIN_ReleaseDesktop();
1038 parent = __get_common_ancestor( display, get_whole_window(pWndZ),
1039 get_whole_window(pWnd), &children, &total );
1040 if( parent && children )
1042 /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
1044 w = __get_top_decoration( display, get_whole_window(pWndCheck), parent );
1046 if( w != children[total-1] ) /* check if at the top */
1048 /* X child at index 0 is at the bottom, at index total-1 is at the top */
1049 check = __td_lookup( w, children, total );
1052 for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
1054 /* go through all windows in Wine z-order... */
1056 if( pWnd != pWndCheck )
1058 if( !(pWnd->dwExStyle & WS_EX_MANAGED) ||
1059 !(w = __get_top_decoration( display, get_whole_window(pWnd), parent )) )
1061 pos = __td_lookup( w, children, total );
1062 if( pos < best && pos > check )
1064 /* find a nearest Wine window precedes
1065 * pWndCheck in the real z-order... */
1067 hwndInsertAfter = pWnd->hwndSelf;
1069 if( best - check == 1 ) break;
1074 if( children ) TSXFree( children );
1075 WIN_ReleaseWndPtr(pWnd);
1076 WIN_ReleaseWndPtr(pWndZ);
1077 WIN_ReleaseWndPtr(pWndCheck);
1078 return hwndInsertAfter;
1082 /***********************************************************************
1083 * X11DRV_ConfigureNotify
1085 void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
1087 HWND oldInsertAfter;
1088 struct x11drv_win_data *data;
1092 int x = event->x, y = event->y;
1094 if (!(win = WIN_FindWndPtr( hwnd ))) return;
1095 data = win->pDriverData;
1099 if (!event->send_event) /* normal event, need to map coordinates to the root */
1103 XTranslateCoordinates( event->display, data->whole_window, root_window,
1104 0, 0, &x, &y, &child );
1105 wine_tsx11_unlock();
1109 rect.right = x + event->width;
1110 rect.bottom = y + event->height;
1111 TRACE( "win %x new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1112 hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1113 event->x, event->y, event->width, event->height );
1114 X11DRV_X_to_window_rect( win, &rect );
1115 WIN_ReleaseWndPtr( win );
1118 winpos.x = rect.left;
1119 winpos.y = rect.top;
1120 winpos.cx = rect.right - rect.left;
1121 winpos.cy = rect.bottom - rect.top;
1122 winpos.flags = SWP_NOACTIVATE;
1124 /* Get Z-order (FIXME) */
1126 winpos.hwndInsertAfter = query_zorder( event->display, hwnd );
1128 /* needs to find the first Visible Window above the current one */
1129 oldInsertAfter = hwnd;
1132 oldInsertAfter = GetWindow( oldInsertAfter, GW_HWNDPREV );
1133 if (!oldInsertAfter)
1135 oldInsertAfter = HWND_TOP;
1138 if (GetWindowLongA( oldInsertAfter, GWL_STYLE ) & WS_VISIBLE) break;
1141 /* Compare what has changed */
1143 GetWindowRect( hwnd, &rect );
1144 if (rect.left == winpos.x && rect.top == winpos.y) winpos.flags |= SWP_NOMOVE;
1146 TRACE( "%04x moving from (%d,%d) to (%d,%d)\n",
1147 hwnd, rect.left, rect.top, winpos.x, winpos.y );
1149 if (rect.right - rect.left == winpos.cx &&
1150 rect.bottom - rect.top == winpos.cy) winpos.flags |= SWP_NOSIZE;
1152 TRACE( "%04x resizing from (%dx%d) to (%dx%d)\n",
1153 hwnd, rect.right - rect.left, rect.bottom - rect.top,
1154 winpos.cx, winpos.cy );
1156 if (winpos.hwndInsertAfter == oldInsertAfter) winpos.flags |= SWP_NOZORDER;
1158 TRACE( "%04x restacking from after %04x to after %04x\n",
1159 hwnd, oldInsertAfter, winpos.hwndInsertAfter );
1161 /* if nothing changed, don't do anything */
1162 if (winpos.flags == (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE)) return;
1164 SetWindowPos( hwnd, winpos.hwndInsertAfter, winpos.x, winpos.y,
1165 winpos.cx, winpos.cy, winpos.flags | SWP_WINE_NOHOSTMOVE );
1169 /***********************************************************************
1170 * SetWindowRgn (X11DRV.@)
1172 * Assign specified region to window (for non-rectangular windows)
1174 BOOL X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
1177 WND *wndPtr = WIN_FindWndPtr(hwnd);
1180 if (!wndPtr) return FALSE;
1182 if (wndPtr->hrgnWnd == hrgn)
1188 if (hrgn) /* verify that region really exists */
1190 if (GetRgnBox( hrgn, &rect ) == ERROR) goto done;
1193 if (wndPtr->hrgnWnd)
1195 /* delete previous region */
1196 DeleteObject(wndPtr->hrgnWnd);
1197 wndPtr->hrgnWnd = 0;
1199 wndPtr->hrgnWnd = hrgn;
1201 /* Size the window to the rectangle of the new region (if it isn't NULL) */
1202 if (hrgn) SetWindowPos( hwnd, 0, rect.left, rect.top,
1203 rect.right - rect.left, rect.bottom - rect.top,
1204 SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOACTIVATE |
1205 SWP_NOZORDER | (redraw ? 0 : SWP_NOREDRAW) );
1206 #ifdef HAVE_LIBXSHAPE
1208 Display *display = thread_display();
1209 X11DRV_WND_DATA *data = wndPtr->pDriverData;
1211 if (data->whole_window)
1215 TSXShapeCombineMask( display, data->whole_window,
1216 ShapeBounding, 0, 0, None, ShapeSet );
1221 int x_offset, y_offset;
1223 DWORD dwBufferSize = GetRegionData(hrgn, 0, NULL);
1224 PRGNDATA pRegionData = HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
1225 if (!pRegionData) goto done;
1227 GetRegionData(hrgn, dwBufferSize, pRegionData);
1228 size = pRegionData->rdh.nCount;
1229 x_offset = wndPtr->rectWindow.left - data->whole_rect.left;
1230 y_offset = wndPtr->rectWindow.top - data->whole_rect.top;
1231 /* convert region's "Windows rectangles" to XRectangles */
1232 aXRect = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*aXRect) );
1235 XRectangle* pCurrRect = aXRect;
1236 RECT *pRect = (RECT*) pRegionData->Buffer;
1237 for (; pRect < ((RECT*) pRegionData->Buffer) + size ; ++pRect, ++pCurrRect)
1239 pCurrRect->x = pRect->left + x_offset;
1240 pCurrRect->y = pRect->top + y_offset;
1241 pCurrRect->height = pRect->bottom - pRect->top;
1242 pCurrRect->width = pRect->right - pRect->left;
1244 TRACE("Rectangle %04d of %04ld data: X=%04d, Y=%04d, Height=%04d, Width=%04d.\n",
1245 pRect - (RECT*) pRegionData->Buffer,
1253 /* shape = non-rectangular windows (X11/extensions) */
1254 TSXShapeCombineRectangles( display, data->whole_window, ShapeBounding,
1256 pCurrRect - aXRect, ShapeSet, YXBanded );
1257 HeapFree(GetProcessHeap(), 0, aXRect );
1259 HeapFree(GetProcessHeap(), 0, pRegionData);
1263 #endif /* HAVE_LIBXSHAPE */
1268 WIN_ReleaseWndPtr(wndPtr);
1273 /***********************************************************************
1276 * Draw the frame used when moving or resizing window.
1278 * FIXME: This causes problems in Win95 mode. (why?)
1280 static void draw_moving_frame( HDC hdc, RECT *rect, BOOL thickframe )
1284 const int width = GetSystemMetrics(SM_CXFRAME);
1285 const int height = GetSystemMetrics(SM_CYFRAME);
1287 HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
1288 PatBlt( hdc, rect->left, rect->top,
1289 rect->right - rect->left - width, height, PATINVERT );
1290 PatBlt( hdc, rect->left, rect->top + height, width,
1291 rect->bottom - rect->top - height, PATINVERT );
1292 PatBlt( hdc, rect->left + width, rect->bottom - 1,
1293 rect->right - rect->left - width, -height, PATINVERT );
1294 PatBlt( hdc, rect->right - 1, rect->top, -width,
1295 rect->bottom - rect->top - height, PATINVERT );
1296 SelectObject( hdc, hbrush );
1298 else DrawFocusRect( hdc, rect );
1302 /***********************************************************************
1305 * Initialisation of a move or resize, when initiatied from a menu choice.
1306 * Return hit test code for caption or sizing border.
1308 static LONG start_size_move( WND* wndPtr, WPARAM wParam, POINT *capturePoint )
1315 GetWindowRect(wndPtr->hwndSelf,&rectWindow);
1317 if ((wParam & 0xfff0) == SC_MOVE)
1319 /* Move pointer at the center of the caption */
1321 NC_GetInsideRect( wndPtr->hwndSelf, &rect );
1322 if (wndPtr->dwStyle & WS_SYSMENU)
1323 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1324 if (wndPtr->dwStyle & WS_MINIMIZEBOX)
1325 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1326 if (wndPtr->dwStyle & WS_MAXIMIZEBOX)
1327 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1328 pt.x = rectWindow.left + (rect.right - rect.left) / 2;
1329 pt.y = rectWindow.top + rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1330 hittest = HTCAPTION;
1337 MSG_InternalGetMessage( &msg, 0, 0, WM_KEYFIRST, WM_MOUSELAST,
1338 MSGF_SIZE, PM_REMOVE, FALSE, NULL );
1342 hittest = NC_HandleNCHitTest( wndPtr->hwndSelf, msg.pt );
1343 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT))
1355 pt.x =(rectWindow.left+rectWindow.right)/2;
1356 pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
1360 pt.x =(rectWindow.left+rectWindow.right)/2;
1361 pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
1365 pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
1366 pt.y =(rectWindow.top+rectWindow.bottom)/2;
1370 pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
1371 pt.y =(rectWindow.top+rectWindow.bottom)/2;
1374 case VK_ESCAPE: return 0;
1380 SetCursorPos( pt.x, pt.y );
1381 NC_HandleSetCursor( wndPtr->hwndSelf,
1382 wndPtr->hwndSelf, MAKELONG( hittest, WM_MOUSEMOVE ));
1387 /***********************************************************************
1388 * X11DRV_SysCommandSizeMove (X11DRV.@)
1390 * Perform SC_MOVE and SC_SIZE commands.
1392 void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
1395 RECT sizingRect, mouseRect, origRect;
1397 LONG hittest = (LONG)(wParam & 0x0f);
1398 HCURSOR16 hDragCursor = 0, hOldCursor = 0;
1399 POINT minTrack, maxTrack;
1400 POINT capturePoint, pt;
1401 WND * wndPtr = WIN_FindWndPtr( hwnd );
1402 BOOL thickframe = HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle );
1403 BOOL iconic = wndPtr->dwStyle & WS_MINIMIZE;
1405 DWORD dwPoint = GetMessagePos ();
1406 BOOL DragFullWindows = FALSE;
1409 Display *old_gdi_display = NULL;
1410 Display *display = thread_display();
1412 SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
1414 pt.x = SLOWORD(dwPoint);
1415 pt.y = SHIWORD(dwPoint);
1418 if (IsZoomed(hwnd) || !IsWindowVisible(hwnd) ||
1419 (wndPtr->dwExStyle & WS_EX_MANAGED)) goto END;
1421 if ((wParam & 0xfff0) == SC_MOVE)
1423 if (!hittest) hittest = start_size_move( wndPtr, wParam, &capturePoint );
1424 if (!hittest) goto END;
1428 if (!thickframe) goto END;
1429 if ( hittest && hittest != HTSYSMENU ) hittest += 2;
1433 hittest = start_size_move( wndPtr, wParam, &capturePoint );
1442 /* Get min/max info */
1444 WINPOS_GetMinMaxInfo( wndPtr, NULL, NULL, &minTrack, &maxTrack );
1445 sizingRect = wndPtr->rectWindow;
1446 origRect = sizingRect;
1447 if (wndPtr->dwStyle & WS_CHILD)
1448 GetClientRect( wndPtr->parent->hwndSelf, &mouseRect );
1450 SetRect(&mouseRect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1451 if (ON_LEFT_BORDER(hittest))
1453 mouseRect.left = max( mouseRect.left, sizingRect.right-maxTrack.x );
1454 mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x );
1456 else if (ON_RIGHT_BORDER(hittest))
1458 mouseRect.left = max( mouseRect.left, sizingRect.left+minTrack.x );
1459 mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x );
1461 if (ON_TOP_BORDER(hittest))
1463 mouseRect.top = max( mouseRect.top, sizingRect.bottom-maxTrack.y );
1464 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y);
1466 else if (ON_BOTTOM_BORDER(hittest))
1468 mouseRect.top = max( mouseRect.top, sizingRect.top+minTrack.y );
1469 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y );
1471 if (wndPtr->dwStyle & WS_CHILD)
1473 MapWindowPoints( wndPtr->parent->hwndSelf, 0, (LPPOINT)&mouseRect, 2 );
1476 /* Retrieve a default cache DC (without using the window style) */
1477 hdc = GetDCEx( wndPtr->parent->hwndSelf, 0, DCX_CACHE );
1479 if( iconic ) /* create a cursor for dragging */
1481 HICON hIcon = GetClassLongA( hwnd, GCL_HICON);
1482 if(!hIcon) hIcon = (HICON)SendMessageA( hwnd, WM_QUERYDRAGICON, 0, 0L);
1483 if( hIcon ) hDragCursor = CURSORICON_IconToCursor( hIcon, TRUE );
1484 if( !hDragCursor ) iconic = FALSE;
1487 /* repaint the window before moving it around */
1488 RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
1490 SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
1493 /* grab the server only when moving top-level windows without desktop */
1494 grab = (!DragFullWindows && (root_window == DefaultRootWindow(gdi_display)) &&
1495 (wndPtr->parent->hwndSelf == GetDesktopWindow()));
1500 XSync( gdi_display, False );
1501 XGrabServer( display );
1502 XSync( display, False );
1503 /* switch gdi display to the thread display, since the server is grabbed */
1504 old_gdi_display = gdi_display;
1505 gdi_display = display;
1507 XGrabPointer( display, get_whole_window(wndPtr), False,
1508 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1509 GrabModeAsync, GrabModeAsync, get_client_window(wndPtr->parent),
1510 None, CurrentTime );
1511 wine_tsx11_unlock();
1517 MSG_InternalGetMessage( &msg, 0, 0, WM_KEYFIRST, WM_MOUSELAST,
1518 MSGF_SIZE, PM_REMOVE, FALSE, NULL );
1520 /* Exit on button-up, Return, or Esc */
1521 if ((msg.message == WM_LBUTTONUP) ||
1522 ((msg.message == WM_KEYDOWN) &&
1523 ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
1525 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
1526 continue; /* We are not interested in other messages */
1530 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1532 case VK_UP: pt.y -= 8; break;
1533 case VK_DOWN: pt.y += 8; break;
1534 case VK_LEFT: pt.x -= 8; break;
1535 case VK_RIGHT: pt.x += 8; break;
1538 pt.x = max( pt.x, mouseRect.left );
1539 pt.x = min( pt.x, mouseRect.right );
1540 pt.y = max( pt.y, mouseRect.top );
1541 pt.y = min( pt.y, mouseRect.bottom );
1543 dx = pt.x - capturePoint.x;
1544 dy = pt.y - capturePoint.y;
1552 if( iconic ) /* ok, no system popup tracking */
1554 hOldCursor = SetCursor(hDragCursor);
1556 WINPOS_ShowIconTitle( wndPtr, FALSE );
1558 else if(!DragFullWindows)
1559 draw_moving_frame( hdc, &sizingRect, thickframe );
1562 if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
1565 RECT newRect = sizingRect;
1566 WPARAM wpSizingHit = 0;
1568 if (hittest == HTCAPTION) OffsetRect( &newRect, dx, dy );
1569 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
1570 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
1571 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
1572 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
1573 if(!iconic && !DragFullWindows) draw_moving_frame( hdc, &sizingRect, thickframe );
1576 /* determine the hit location */
1577 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
1578 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
1579 SendMessageA( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&newRect );
1583 if(!DragFullWindows)
1584 draw_moving_frame( hdc, &newRect, thickframe );
1586 /* To avoid any deadlocks, all the locks on the windows
1587 structures must be suspended before the SetWindowPos */
1588 iWndsLocks = WIN_SuspendWndsLock();
1589 SetWindowPos( hwnd, 0, newRect.left, newRect.top,
1590 newRect.right - newRect.left,
1591 newRect.bottom - newRect.top,
1592 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
1593 WIN_RestoreWndsLock(iWndsLocks);
1596 sizingRect = newRect;
1604 if( moved ) /* restore cursors, show icon title later on */
1606 ShowCursor( FALSE );
1607 SetCursor( hOldCursor );
1609 DestroyCursor( hDragCursor );
1611 else if (moved && !DragFullWindows)
1612 draw_moving_frame( hdc, &sizingRect, thickframe );
1614 ReleaseDC( wndPtr->parent->hwndSelf, hdc );
1617 XUngrabPointer( display, CurrentTime );
1620 XSync( display, False );
1621 XUngrabServer( display );
1622 XSync( display, False );
1623 gdi_display = old_gdi_display;
1625 wine_tsx11_unlock();
1627 if (HOOK_CallHooksA( WH_CBT, HCBT_MOVESIZE, hwnd, (LPARAM)&sizingRect ))
1628 sizingRect = wndPtr->rectWindow;
1630 SendMessageA( hwnd, WM_EXITSIZEMOVE, 0, 0 );
1631 SendMessageA( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
1633 /* window moved or resized */
1636 /* To avoid any deadlocks, all the locks on the windows
1637 structures must be suspended before the SetWindowPos */
1638 iWndsLocks = WIN_SuspendWndsLock();
1640 /* if the moving/resizing isn't canceled call SetWindowPos
1641 * with the new position or the new size of the window
1643 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
1645 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
1646 if(!DragFullWindows)
1647 SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
1648 sizingRect.right - sizingRect.left,
1649 sizingRect.bottom - sizingRect.top,
1650 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
1653 { /* restore previous size/position */
1655 SetWindowPos( hwnd, 0, origRect.left, origRect.top,
1656 origRect.right - origRect.left,
1657 origRect.bottom - origRect.top,
1658 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
1661 WIN_RestoreWndsLock(iWndsLocks);
1666 /* Single click brings up the system menu when iconized */
1670 if( wndPtr->dwStyle & WS_SYSMENU )
1671 SendMessageA( hwnd, WM_SYSCOMMAND,
1672 SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
1674 else WINPOS_ShowIconTitle( wndPtr, TRUE );
1678 WIN_ReleaseWndPtr(wndPtr);