Fixed one more bug in clip_children.
[wine] / dlls / x11drv / winpos.c
1 /*
2  * Window position related functions.
3  *
4  * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
5  * Copyright 1995, 1996, 1999 Alex Korobka
6  */
7
8 #include "config.h"
9
10 #include "ts_xlib.h"
11 #include "ts_xutil.h"
12 #include "ts_shape.h"
13
14 #include "winbase.h"
15 #include "wingdi.h"
16 #include "winuser.h"
17
18 #include "x11drv.h"
19 #include "hook.h"
20 #include "win.h"
21 #include "winpos.h"
22 #include "region.h"
23 #include "dce.h"
24 #include "cursoricon.h"
25 #include "nonclient.h"
26 #include "message.h"
27
28 #include "debugtools.h"
29
30 DEFAULT_DEBUG_CHANNEL(x11drv);
31
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)
38
39 #define SWP_EX_NOCOPY       0x0001
40 #define SWP_EX_PAINTSELF    0x0002
41 #define SWP_EX_NONCLIENT    0x0004
42
43 #define HAS_THICKFRAME(style,exStyle) \
44     (((style) & WS_THICKFRAME) && \
45      !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
46
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))
55
56
57 /***********************************************************************
58  *              clip_children
59  *
60  * Clip all children of a given window out of the visible region
61  */
62 static void clip_children( WND *win, WND *last, HRGN hrgn, int whole_window )
63 {
64     WND *ptr;
65     HRGN rectRgn;
66     int x, y;
67
68     /* first check if we have anything to do */
69     for (ptr = win->child; ptr && ptr != last; ptr = ptr->next)
70         if (ptr->dwStyle & WS_VISIBLE) break;
71     if (!ptr || ptr == last) return; /* no children to clip */
72
73     if (whole_window)
74     {
75         x = win->rectWindow.left - win->rectClient.left;
76         y = win->rectWindow.top - win->rectClient.top;
77     }
78     else x = y = 0;
79
80     rectRgn = CreateRectRgn( 0, 0, 0, 0 );
81     while (ptr && ptr != last)
82     {
83         if (ptr->dwStyle & WS_VISIBLE)
84         {
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 */
89         }
90         ptr = ptr->next;
91     }
92     DeleteObject( rectRgn );
93 }
94
95
96 /***********************************************************************
97  *              get_visible_region
98  *
99  * Compute the visible region of a window
100  */
101 static HRGN get_visible_region( WND *win, WND *top, UINT flags, int mode )
102 {
103     HRGN rgn;
104     RECT rect;
105     int xoffset, yoffset;
106     X11DRV_WND_DATA *data = win->pDriverData;
107
108     if (flags & DCX_WINDOW)
109     {
110         xoffset = win->rectWindow.left;
111         yoffset = win->rectWindow.top;
112     }
113     else
114     {
115         xoffset = win->rectClient.left;
116         yoffset = win->rectClient.top;
117     }
118
119     if (flags & DCX_PARENTCLIP)
120         GetClientRect( win->parent->hwndSelf, &rect );
121     else if (flags & DCX_WINDOW)
122         rect = data->whole_rect;
123     else
124         rect = win->rectClient;
125
126     /* vis region is relative to the start of the client/window area */
127     OffsetRect( &rect, -xoffset, -yoffset );
128
129     if (!(rgn = CreateRectRgn( rect.left, rect.top, rect.right, rect.bottom ))) return 0;
130
131     if ((flags & DCX_CLIPCHILDREN) && (mode != ClipByChildren))
132     {
133         /* we need to clip children by hand */
134         clip_children( win, NULL, rgn, (flags & DCX_WINDOW) );
135     }
136
137     if (top && top != win)  /* need to clip siblings of ancestors */
138     {
139         WND *ptr = win;
140
141         OffsetRgn( rgn, xoffset, yoffset );
142         for (;;)
143         {
144             if (ptr->dwStyle & WS_CLIPSIBLINGS) clip_children( ptr->parent, ptr, rgn, FALSE );
145             if (ptr == top) break;
146             ptr = ptr->parent;
147             OffsetRgn( rgn, ptr->rectClient.left, ptr->rectClient.top );
148             xoffset += ptr->rectClient.left;
149             yoffset += ptr->rectClient.top;
150         }
151         /* make it relative to the target window again */
152         OffsetRgn( rgn, -xoffset, -yoffset );
153     }
154
155     return rgn;
156 }
157
158
159 /***********************************************************************
160  *              X11DRV_GetDC
161  *
162  * Set the drawable, origin and dimensions for the DC associated to
163  * a given window.
164  */
165 BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
166 {
167     WND *win = WIN_FindWndPtr( hwnd );
168     WND *ptr, *top;
169     X11DRV_WND_DATA *data = win->pDriverData;
170     Drawable drawable;
171     int org_x, org_y, mode = IncludeInferiors;
172
173     /* don't clip siblings if using parent clip region */
174     if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS;
175
176     /* find the top parent in the hierarchy that isn't clipping siblings */
177     top = NULL;
178     for (ptr = win->parent; ptr && ptr->parent; ptr = ptr->parent)
179         if (!(ptr->dwStyle & WS_CLIPSIBLINGS)) top = ptr;
180
181     if (!top && !(flags & DCX_CLIPSIBLINGS)) top = win;
182
183     if (top)
184     {
185         org_x = org_y = 0;
186         if (flags & DCX_WINDOW)
187         {
188             org_x = win->rectWindow.left - win->rectClient.left;
189             org_y = win->rectWindow.top - win->rectClient.top;
190         }
191         for (ptr = win; ptr != top->parent; ptr = ptr->parent)
192         {
193             org_x += ptr->rectClient.left;
194             org_y += ptr->rectClient.top;
195         }
196         /* have to use the parent so that we include siblings */
197         if (top->parent) drawable = get_client_window( top->parent );
198         else drawable = root_window;
199     }
200     else
201     {
202         if (IsIconic( hwnd ))
203         {
204             drawable = data->icon_window ? data->icon_window : data->whole_window;
205             org_x = 0;
206             org_y = 0;
207         }
208         else if (flags & DCX_WINDOW)
209         {
210             drawable = data->whole_window;
211             org_x = win->rectWindow.left - data->whole_rect.left;
212             org_y = win->rectWindow.top - data->whole_rect.top;
213         }
214         else
215         {
216             drawable = data->client_window;
217             org_x = 0;
218             org_y = 0;
219             if (flags & DCX_CLIPCHILDREN) mode = ClipByChildren;  /* can use X11 clipping */
220         }
221     }
222
223     X11DRV_SetDrawable( hdc, drawable, mode, org_x, org_y );
224
225     if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) ||
226         SetHookFlags16( hdc, DCHF_VALIDATEVISRGN ))  /* DC was dirty */
227     {
228         /* need to recompute the visible region */
229         HRGN visRgn = get_visible_region( win, top, flags, mode );
230
231         if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
232             CombineRgn( visRgn, visRgn, hrgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
233
234         /* make it relative to the drawable origin */
235         OffsetRgn( visRgn, org_x, org_y );
236         SelectVisRgn16( hdc, visRgn );
237         DeleteObject( visRgn );
238     }
239
240     WIN_ReleaseWndPtr( win );
241     return TRUE;
242 }
243
244
245
246 /***********************************************************************
247  *           SWP_DoWinPosChanging
248  */
249 static BOOL SWP_DoWinPosChanging( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT* pNewClientRect )
250 {
251     WND *wndPtr;
252
253     /* Send WM_WINDOWPOSCHANGING message */
254
255     if (!(pWinpos->flags & SWP_NOSENDCHANGING))
256         SendMessageA( pWinpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
257
258     if (!(wndPtr = WIN_FindWndPtr( pWinpos->hwnd ))) return FALSE;
259
260     /* Calculate new position and size */
261
262     *pNewWindowRect = wndPtr->rectWindow;
263     *pNewClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
264                                                     : wndPtr->rectClient;
265
266     if (!(pWinpos->flags & SWP_NOSIZE))
267     {
268         pNewWindowRect->right  = pNewWindowRect->left + pWinpos->cx;
269         pNewWindowRect->bottom = pNewWindowRect->top + pWinpos->cy;
270     }
271     if (!(pWinpos->flags & SWP_NOMOVE))
272     {
273         pNewWindowRect->left    = pWinpos->x;
274         pNewWindowRect->top     = pWinpos->y;
275         pNewWindowRect->right  += pWinpos->x - wndPtr->rectWindow.left;
276         pNewWindowRect->bottom += pWinpos->y - wndPtr->rectWindow.top;
277
278         OffsetRect( pNewClientRect, pWinpos->x - wndPtr->rectWindow.left,
279                                     pWinpos->y - wndPtr->rectWindow.top );
280     }
281     pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
282     WIN_ReleaseWndPtr( wndPtr );
283     return TRUE;
284 }
285
286 /***********************************************************************
287  *           SWP_DoNCCalcSize
288  */
289 static UINT SWP_DoNCCalcSize( WND* wndPtr, WINDOWPOS* pWinpos,
290                               RECT* pNewWindowRect, RECT* pNewClientRect )
291 {
292     UINT wvrFlags = 0;
293
294       /* Send WM_NCCALCSIZE message to get new client area */
295     if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
296     {
297          wvrFlags = WINPOS_SendNCCalcSize( pWinpos->hwnd, TRUE, pNewWindowRect,
298                                     &wndPtr->rectWindow, &wndPtr->rectClient,
299                                     pWinpos, pNewClientRect );
300          /* FIXME: WVR_ALIGNxxx */
301
302          if( pNewClientRect->left != wndPtr->rectClient.left ||
303              pNewClientRect->top != wndPtr->rectClient.top )
304              pWinpos->flags &= ~SWP_NOCLIENTMOVE;
305
306          if( (pNewClientRect->right - pNewClientRect->left !=
307               wndPtr->rectClient.right - wndPtr->rectClient.left) ||
308              (pNewClientRect->bottom - pNewClientRect->top !=
309               wndPtr->rectClient.bottom - wndPtr->rectClient.top) )
310              pWinpos->flags &= ~SWP_NOCLIENTSIZE;
311     }
312     else
313       if( !(pWinpos->flags & SWP_NOMOVE) && (pNewClientRect->left != wndPtr->rectClient.left ||
314                                              pNewClientRect->top != wndPtr->rectClient.top) )
315             pWinpos->flags &= ~SWP_NOCLIENTMOVE;
316     return wvrFlags;
317 }
318
319 /***********************************************************************
320  *           SWP_DoOwnedPopups
321  *
322  * fix Z order taking into account owned popups -
323  * basically we need to maintain them above the window that owns them
324  *
325  * FIXME: hide/show owned popups when owner visibility changes.
326  */
327 static HWND SWP_DoOwnedPopups(WND* pDesktop, WND* wndPtr, HWND hwndInsertAfter, WORD flags)
328 {
329     WND *w = WIN_LockWndPtr(pDesktop->child);
330
331     WARN("(%04x) hInsertAfter = %04x\n", wndPtr->hwndSelf, hwndInsertAfter );
332
333     if( (wndPtr->dwStyle & WS_POPUP) && wndPtr->owner )
334     {
335         /* make sure this popup stays above the owner */
336
337         HWND hwndLocalPrev = HWND_TOP;
338
339         if( hwndInsertAfter != HWND_TOP )
340         {
341             while( w && w != wndPtr->owner )
342             {
343                 if (w != wndPtr) hwndLocalPrev = w->hwndSelf;
344                 if( hwndLocalPrev == hwndInsertAfter ) break;
345                 WIN_UpdateWndPtr(&w,w->next);
346             }
347             hwndInsertAfter = hwndLocalPrev;
348         }
349     }
350     else if( wndPtr->dwStyle & WS_CHILD )
351         goto END;
352
353     WIN_UpdateWndPtr(&w, pDesktop->child);
354
355     while( w )
356     {
357         if( w == wndPtr ) break;
358
359         if( (w->dwStyle & WS_POPUP) && w->owner == wndPtr )
360         {
361             SetWindowPos(w->hwndSelf, hwndInsertAfter, 0, 0, 0, 0,
362                          SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE);
363             hwndInsertAfter = w->hwndSelf;
364         }
365         WIN_UpdateWndPtr(&w, w->next);
366     }
367
368 END:
369     WIN_ReleaseWndPtr(w);
370     return hwndInsertAfter;
371 }
372
373
374 /* fix redundant flags and values in the WINDOWPOS structure */
375 static BOOL fixup_flags( WINDOWPOS *winpos )
376 {
377     WND *wndPtr = WIN_FindWndPtr( winpos->hwnd );
378     BOOL ret = TRUE;
379
380     if (!wndPtr) return FALSE;
381
382     if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
383     else
384     {
385         winpos->flags &= ~SWP_HIDEWINDOW;
386         if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
387     }
388
389     if (winpos->cx < 0) winpos->cx = 0;
390     if (winpos->cy < 0) winpos->cy = 0;
391
392     if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == winpos->cx) &&
393         (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == winpos->cy))
394         winpos->flags |= SWP_NOSIZE;    /* Already the right size */
395
396     if ((wndPtr->rectWindow.left == winpos->x) && (wndPtr->rectWindow.top == winpos->y))
397         winpos->flags |= SWP_NOMOVE;    /* Already the right position */
398
399     if (winpos->hwnd == GetForegroundWindow())
400         winpos->flags |= SWP_NOACTIVATE;   /* Already active */
401     else if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
402     {
403         if (!(winpos->flags & SWP_NOACTIVATE)) /* Bring to the top when activating */
404         {
405             winpos->flags &= ~SWP_NOZORDER;
406             winpos->hwndInsertAfter = HWND_TOP;
407             goto done;
408         }
409     }
410
411     /* Check hwndInsertAfter */
412
413       /* FIXME: TOPMOST not supported yet */
414     if ((winpos->hwndInsertAfter == HWND_TOPMOST) ||
415         (winpos->hwndInsertAfter == HWND_NOTOPMOST)) winpos->hwndInsertAfter = HWND_TOP;
416
417     /* hwndInsertAfter must be a sibling of the window */
418     if ((winpos->hwndInsertAfter != HWND_TOP) && (winpos->hwndInsertAfter != HWND_BOTTOM))
419     {
420         WND* wnd = WIN_FindWndPtr(winpos->hwndInsertAfter);
421         if (wnd)
422         {
423             if (wnd->parent != wndPtr->parent) ret = FALSE;
424             else
425             {
426                 /* don't need to change the Zorder of hwnd if it's already inserted
427                  * after hwndInsertAfter or when inserting hwnd after itself.
428                  */
429                 if ((wnd->next == wndPtr ) || (winpos->hwnd == winpos->hwndInsertAfter))
430                     winpos->flags |= SWP_NOZORDER;
431             }
432             WIN_ReleaseWndPtr(wnd);
433         }
434     }
435  done:
436     WIN_ReleaseWndPtr(wndPtr);
437     return ret;
438 }
439
440
441 /***********************************************************************
442  *              SetWindowPos   (X11DRV.@)
443  */
444 BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
445 {
446     WND *wndPtr;
447     RECT newWindowRect, newClientRect;
448     RECT oldWindowRect, oldClientRect;
449     UINT wvrFlags = 0;
450     BOOL bChangePos;
451
452     TRACE( "hwnd %04x, swp (%i,%i)-(%i,%i) flags %08x\n",
453            winpos->hwnd, winpos->x, winpos->y,
454            winpos->x + winpos->cx, winpos->y + winpos->cy, winpos->flags);
455
456     bChangePos = !(winpos->flags & SWP_WINE_NOHOSTMOVE);
457     winpos->flags &= ~SWP_WINE_NOHOSTMOVE;
458
459     /* Check window handle */
460     if (winpos->hwnd == GetDesktopWindow()) return FALSE;
461
462     /* Fix redundant flags */
463     if (!fixup_flags( winpos )) return FALSE;
464
465     SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect );
466
467     if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
468
469     TRACE("\tcurrent (%i,%i)-(%i,%i), style %08x\n",
470           wndPtr->rectWindow.left, wndPtr->rectWindow.top,
471           wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle );
472
473     if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
474     {
475         if( wndPtr->parent->hwndSelf == GetDesktopWindow() )
476             winpos->hwndInsertAfter = SWP_DoOwnedPopups( wndPtr->parent, wndPtr,
477                                                          winpos->hwndInsertAfter, winpos->flags );
478     }
479
480     /* Common operations */
481
482     wvrFlags = SWP_DoNCCalcSize( wndPtr, winpos, &newWindowRect, &newClientRect );
483
484     if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter)
485     {
486         if ( WIN_UnlinkWindow( winpos->hwnd ) )
487             WIN_LinkWindow( winpos->hwnd, winpos->hwndInsertAfter );
488     }
489
490     /* Reset active DCEs */
491
492     if( (((winpos->flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) &&
493          wndPtr->dwStyle & WS_VISIBLE) ||
494         (winpos->flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) )
495     {
496         RECT rect;
497
498         UnionRect(&rect, &newWindowRect, &wndPtr->rectWindow);
499         DCE_InvalidateDCE(wndPtr, &rect);
500     }
501
502     oldWindowRect = wndPtr->rectWindow;
503     oldClientRect = wndPtr->rectClient;
504
505     /* Find out if we have to redraw the whole client rect */
506
507     if( oldClientRect.bottom - oldClientRect.top ==
508         newClientRect.bottom - newClientRect.top ) wvrFlags &= ~WVR_VREDRAW;
509
510     if( oldClientRect.right - oldClientRect.left ==
511         newClientRect.right - newClientRect.left ) wvrFlags &= ~WVR_HREDRAW;
512
513     /* FIXME: actually do something with WVR_VALIDRECTS */
514
515     wndPtr->rectWindow = newWindowRect;
516     wndPtr->rectClient = newClientRect;
517
518     if (winpos->flags & SWP_SHOWWINDOW) wndPtr->dwStyle |= WS_VISIBLE;
519     else if (winpos->flags & SWP_HIDEWINDOW)
520     {
521         /* clear the update region */
522         RedrawWindow( winpos->hwnd, NULL, 0, RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
523                                              RDW_NOINTERNALPAINT | RDW_ALLCHILDREN );
524         wndPtr->dwStyle &= ~WS_VISIBLE;
525     }
526
527     if (get_whole_window(wndPtr))  /* don't do anything if X window not created yet */
528     {
529         Display *display = thread_display();
530
531         wine_tsx11_lock();
532         if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW))
533         {
534             if (!IsRectEmpty( &oldWindowRect ))
535             {
536                 XUnmapWindow( display, get_whole_window(wndPtr) );
537                 TRACE( "unmapping win %x\n", winpos->hwnd );
538             }
539             else TRACE( "not unmapping zero size win %x\n", winpos->hwnd );
540         }
541         else if ((wndPtr->dwStyle & WS_VISIBLE) &&
542                  !IsRectEmpty( &oldWindowRect ) && IsRectEmpty( &newWindowRect ))
543         {
544             /* resizing to zero size -> unmap */
545             TRACE( "unmapping zero size win %x\n", winpos->hwnd );
546             XUnmapWindow( display, get_whole_window(wndPtr) );
547         }
548
549         if (bChangePos)
550             X11DRV_sync_whole_window_position( display, wndPtr, !(winpos->flags & SWP_NOZORDER) );
551         else
552         {
553             struct x11drv_win_data *data = wndPtr->pDriverData;
554             data->whole_rect = wndPtr->rectWindow;
555             X11DRV_window_to_X_rect( wndPtr, &data->whole_rect );
556         }
557
558         if (X11DRV_sync_client_window_position( display, wndPtr ) ||
559             (winpos->flags & SWP_FRAMECHANGED))
560         {
561             /* if we moved the client area, repaint the whole non-client window */
562             XClearArea( display, get_whole_window(wndPtr), 0, 0, 0, 0, True );
563         }
564         if (winpos->flags & SWP_SHOWWINDOW)
565         {
566             if (!IsRectEmpty( &newWindowRect ))
567             {
568                 XMapWindow( display, get_whole_window(wndPtr) );
569                 TRACE( "mapping win %x\n", winpos->hwnd );
570             }
571             else TRACE( "not mapping win %x, size is zero\n", winpos->hwnd );
572         }
573         else if ((wndPtr->dwStyle & WS_VISIBLE) &&
574                  IsRectEmpty( &oldWindowRect ) && !IsRectEmpty( &newWindowRect ))
575         {
576             /* resizing from zero size to non-zero -> map */
577             TRACE( "mapping non zero size win %x\n", winpos->hwnd );
578             XMapWindow( display, get_whole_window(wndPtr) );
579         }
580         XFlush( display );  /* FIXME: should not be necessary */
581         wine_tsx11_unlock();
582     }
583
584     WIN_ReleaseWndPtr(wndPtr);
585
586     if (wvrFlags & WVR_REDRAW) RedrawWindow( winpos->hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE );
587
588     if (winpos->hwnd == CARET_GetHwnd())
589     {
590         if( winpos->flags & SWP_HIDEWINDOW )
591             HideCaret(winpos->hwnd);
592         else if (winpos->flags & SWP_SHOWWINDOW)
593             ShowCaret(winpos->hwnd);
594     }
595
596     if (!(winpos->flags & SWP_NOACTIVATE))
597         WINPOS_ChangeActiveWindow( winpos->hwnd, FALSE );
598
599       /* And last, send the WM_WINDOWPOSCHANGED message */
600
601     TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
602
603     if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE) &&
604           !(winpos->flags & SWP_NOSENDCHANGING))
605         SendMessageA( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
606
607     return TRUE;
608 }
609
610
611 /***********************************************************************
612  *           WINPOS_FindIconPos
613  *
614  * Find a suitable place for an iconic window.
615  */
616 static POINT WINPOS_FindIconPos( WND* wndPtr, POINT pt )
617 {
618     RECT rectParent;
619     short x, y, xspacing, yspacing;
620
621     GetClientRect( wndPtr->parent->hwndSelf, &rectParent );
622     if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics(SM_CXICON) < rectParent.right) &&
623         (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics(SM_CYICON) < rectParent.bottom))
624         return pt;  /* The icon already has a suitable position */
625
626     xspacing = GetSystemMetrics(SM_CXICONSPACING);
627     yspacing = GetSystemMetrics(SM_CYICONSPACING);
628
629     y = rectParent.bottom;
630     for (;;)
631     {
632         x = rectParent.left;
633         do
634         {
635               /* Check if another icon already occupies this spot */
636             WND *childPtr = WIN_LockWndPtr(wndPtr->parent->child);
637             while (childPtr)
638             {
639                 if ((childPtr->dwStyle & WS_MINIMIZE) && (childPtr != wndPtr))
640                 {
641                     if ((childPtr->rectWindow.left < x + xspacing) &&
642                         (childPtr->rectWindow.right >= x) &&
643                         (childPtr->rectWindow.top <= y) &&
644                         (childPtr->rectWindow.bottom > y - yspacing))
645                         break;  /* There's a window in there */
646                 }
647                 WIN_UpdateWndPtr(&childPtr,childPtr->next);
648             }
649             WIN_ReleaseWndPtr(childPtr);
650             if (!childPtr) /* No window was found, so it's OK for us */
651             {
652                 pt.x = x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2;
653                 pt.y = y - (yspacing + GetSystemMetrics(SM_CYICON)) / 2;
654                 return pt;
655             }
656             x += xspacing;
657         } while(x <= rectParent.right-xspacing);
658         y -= yspacing;
659     }
660 }
661
662
663
664
665
666 UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
667 {
668     WND *wndPtr = WIN_FindWndPtr( hwnd );
669     UINT swpFlags = 0;
670     POINT size;
671     WINDOWPLACEMENT wpl;
672
673     TRACE("0x%04x %u\n", hwnd, cmd );
674
675     wpl.length = sizeof(wpl);
676     GetWindowPlacement( hwnd, &wpl );
677
678     size.x = wndPtr->rectWindow.left;
679     size.y = wndPtr->rectWindow.top;
680
681     if (!HOOK_CallHooksA(WH_CBT, HCBT_MINMAX, wndPtr->hwndSelf, cmd))
682     {
683         if( wndPtr->dwStyle & WS_MINIMIZE )
684         {
685             if( !SendMessageA( wndPtr->hwndSelf, WM_QUERYOPEN, 0, 0L ) )
686             {
687                 swpFlags = SWP_NOSIZE | SWP_NOMOVE;
688                 goto done;
689             }
690             swpFlags |= SWP_NOCOPYBITS;
691         }
692         switch( cmd )
693         {
694         case SW_MINIMIZE:
695             if( wndPtr->dwStyle & WS_MAXIMIZE)
696             {
697                 wndPtr->flags |= WIN_RESTORE_MAX;
698                 wndPtr->dwStyle &= ~WS_MAXIMIZE;
699             }
700             else
701                 wndPtr->flags &= ~WIN_RESTORE_MAX;
702             wndPtr->dwStyle |= WS_MINIMIZE;
703
704             X11DRV_set_iconic_state( wndPtr );
705
706             wpl.ptMinPosition = WINPOS_FindIconPos( wndPtr, wpl.ptMinPosition );
707
708             SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
709                      GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) );
710             swpFlags |= SWP_NOCOPYBITS;
711             break;
712
713         case SW_MAXIMIZE:
714             WINPOS_GetMinMaxInfo( wndPtr, &size, &wpl.ptMaxPosition, NULL, NULL );
715
716             if( wndPtr->dwStyle & WS_MINIMIZE )
717             {
718                 wndPtr->dwStyle &= ~WS_MINIMIZE;
719                 WINPOS_ShowIconTitle( wndPtr, FALSE );
720                 X11DRV_set_iconic_state( wndPtr );
721             }
722             wndPtr->dwStyle |= WS_MAXIMIZE;
723
724             SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
725             break;
726
727         case SW_RESTORE:
728             if( wndPtr->dwStyle & WS_MINIMIZE )
729             {
730                 wndPtr->dwStyle &= ~WS_MINIMIZE;
731                 WINPOS_ShowIconTitle( wndPtr, FALSE );
732                 X11DRV_set_iconic_state( wndPtr );
733
734                 if( wndPtr->flags & WIN_RESTORE_MAX)
735                 {
736                     /* Restore to maximized position */
737                     WINPOS_GetMinMaxInfo( wndPtr, &size, &wpl.ptMaxPosition, NULL, NULL);
738                     wndPtr->dwStyle |= WS_MAXIMIZE;
739                     SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
740                     break;
741                 }
742             }
743             else
744                 if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
745                 {
746                     swpFlags = (UINT16)(-1);
747                     goto done;
748                 }
749                 else wndPtr->dwStyle &= ~WS_MAXIMIZE;
750
751             /* Restore to normal position */
752
753             *rect = wpl.rcNormalPosition;
754             rect->right -= rect->left;
755             rect->bottom -= rect->top;
756
757             break;
758         }
759     } else swpFlags |= SWP_NOSIZE | SWP_NOMOVE;
760
761  done:
762     WIN_ReleaseWndPtr( wndPtr );
763     return swpFlags;
764 }
765
766
767 /***********************************************************************
768  *              X11DRV_ShowWindow   (X11DRV.@)
769  */
770 BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd )
771 {
772     WND*        wndPtr = WIN_FindWndPtr( hwnd );
773     BOOL        wasVisible, showFlag;
774     RECT        newPos = {0, 0, 0, 0};
775     UINT        swp = 0;
776
777     if (!wndPtr) return FALSE;
778
779     TRACE("hwnd=%04x, cmd=%d\n", hwnd, cmd);
780
781     wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
782
783     switch(cmd)
784     {
785         case SW_HIDE:
786             if (!wasVisible) goto END;;
787             swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | 
788                         SWP_NOACTIVATE | SWP_NOZORDER;
789             break;
790
791         case SW_SHOWMINNOACTIVE:
792             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
793             /* fall through */
794         case SW_SHOWMINIMIZED:
795             swp |= SWP_SHOWWINDOW;
796             /* fall through */
797         case SW_MINIMIZE:
798             swp |= SWP_FRAMECHANGED;
799             if( !(wndPtr->dwStyle & WS_MINIMIZE) )
800                  swp |= WINPOS_MinMaximize( hwnd, SW_MINIMIZE, &newPos );
801             else swp |= SWP_NOSIZE | SWP_NOMOVE;
802             break;
803
804         case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
805             swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
806             if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
807                  swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
808             else swp |= SWP_NOSIZE | SWP_NOMOVE;
809             break;
810
811         case SW_SHOWNA:
812             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
813             /* fall through */
814         case SW_SHOW:
815             swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
816
817             /*
818              * ShowWindow has a little peculiar behavior that if the
819              * window is already the topmost window, it will not
820              * activate it.
821              */
822             if (GetTopWindow((HWND)0)==hwnd && (wasVisible || GetActiveWindow() == hwnd))
823               swp |= SWP_NOACTIVATE;
824
825             break;
826
827         case SW_SHOWNOACTIVATE:
828             swp |= SWP_NOZORDER;
829             if (GetActiveWindow()) swp |= SWP_NOACTIVATE;
830             /* fall through */
831         case SW_SHOWNORMAL:  /* same as SW_NORMAL: */
832         case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
833         case SW_RESTORE:
834             swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
835
836             if( wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE) )
837                  swp |= WINPOS_MinMaximize( hwnd, SW_RESTORE, &newPos );
838             else swp |= SWP_NOSIZE | SWP_NOMOVE;
839             break;
840     }
841
842     showFlag = (cmd != SW_HIDE);
843     if (showFlag != wasVisible)
844     {
845         SendMessageA( hwnd, WM_SHOWWINDOW, showFlag, 0 );
846         if (!IsWindow( hwnd )) goto END;
847     }
848
849     /* We can't activate a child window */
850     if ((wndPtr->dwStyle & WS_CHILD) &&
851         !(wndPtr->dwExStyle & WS_EX_MDICHILD))
852         swp |= SWP_NOACTIVATE | SWP_NOZORDER;
853
854     SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
855                   newPos.right, newPos.bottom, LOWORD(swp) );
856     if (cmd == SW_HIDE)
857     {
858         /* FIXME: This will cause the window to be activated irrespective
859          * of whether it is owned by the same thread. Has to be done
860          * asynchronously.
861          */
862
863         if (hwnd == GetActiveWindow())
864             WINPOS_ActivateOtherWindow(wndPtr);
865
866         /* Revert focus to parent */
867         if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
868             SetFocus( GetParent(hwnd) );
869     }
870     if (!IsWindow( hwnd )) goto END;
871     else if( wndPtr->dwStyle & WS_MINIMIZE ) WINPOS_ShowIconTitle( wndPtr, TRUE );
872
873     if (wndPtr->flags & WIN_NEED_SIZE)
874     {
875         /* should happen only in CreateWindowEx() */
876         int wParam = SIZE_RESTORED;
877
878         wndPtr->flags &= ~WIN_NEED_SIZE;
879         if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
880         else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
881         SendMessageA( hwnd, WM_SIZE, wParam,
882                      MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
883                             wndPtr->rectClient.bottom-wndPtr->rectClient.top));
884         SendMessageA( hwnd, WM_MOVE, 0,
885                    MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
886     }
887
888 END:
889     WIN_ReleaseWndPtr(wndPtr);
890     return wasVisible;
891 }
892
893
894 /**********************************************************************
895  *              X11DRV_MapNotify
896  */
897 void X11DRV_MapNotify( HWND hwnd, XMapEvent *event )
898 {
899     HWND hwndFocus = GetFocus();
900     WND *win;
901
902     if (!(win = WIN_FindWndPtr( hwnd ))) return;
903
904     if ((win->dwStyle & WS_VISIBLE) &&
905         (win->dwStyle & WS_MINIMIZE) &&
906         (win->dwExStyle & WS_EX_MANAGED))
907     {
908         int x, y;
909         unsigned int width, height, border, depth;
910         Window root, top;
911         RECT rect;
912
913         DCE_InvalidateDCE( win, &win->rectWindow );
914         win->dwStyle &= ~WS_MINIMIZE;
915         win->dwStyle |= WS_VISIBLE;
916         WIN_InternalShowOwnedPopups( hwnd, TRUE, TRUE );
917
918         if (win->flags & WIN_RESTORE_MAX)
919             win->dwStyle |= WS_MAXIMIZE;
920         else
921             win->dwStyle &= ~WS_MAXIMIZE;
922
923         /* FIXME: hack */
924         wine_tsx11_lock();
925         XGetGeometry( event->display, get_whole_window(win), &root, &x, &y, &width, &height,
926                         &border, &depth );
927         XTranslateCoordinates( event->display, get_whole_window(win), root, 0, 0, &x, &y, &top );
928         wine_tsx11_unlock();
929         rect.left   = x;
930         rect.top    = y;
931         rect.right  = x + width;
932         rect.bottom = y + height;
933         X11DRV_X_to_window_rect( win, &rect );
934
935         SendMessageA( hwnd, WM_SHOWWINDOW, SW_RESTORE, 0 );
936         SetWindowPos( hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
937                       SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
938     }
939     if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus);  /* FIXME */
940     WIN_ReleaseWndPtr( win );
941 }
942
943
944 /**********************************************************************
945  *              X11DRV_UnmapNotify
946  */
947 void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event )
948 {
949     WND *win;
950
951     if (!(win = WIN_FindWndPtr( hwnd ))) return;
952
953     if ((win->dwStyle & WS_VISIBLE) && (win->dwExStyle & WS_EX_MANAGED))
954     {
955         EndMenu();
956         SendMessageA( hwnd, WM_SHOWWINDOW, SW_MINIMIZE, 0 );
957
958         win->flags &= ~WIN_RESTORE_MAX;
959         win->dwStyle |= WS_MINIMIZE;
960
961         if (win->dwStyle & WS_MAXIMIZE)
962         {
963             win->flags |= WIN_RESTORE_MAX;
964             win->dwStyle &= ~WS_MAXIMIZE;
965         }
966
967         SetWindowPos( hwnd, 0, 0, 0, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
968                       SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
969
970         WIN_InternalShowOwnedPopups( hwnd, FALSE, TRUE );
971     }
972     WIN_ReleaseWndPtr( win );
973 }
974
975
976 /***********************************************************************
977  *           query_zorder
978  *
979  * Synchronize internal z-order with the window manager's.
980  */
981 static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
982 {
983     /* return TRUE if we have at least two managed windows */
984
985     for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
986         if( ((*pWndA)->dwExStyle & WS_EX_MANAGED) &&
987             ((*pWndA)->dwStyle & WS_VISIBLE )) break;
988     if( *pWndA )
989         for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
990             if( ((*pWndB)->dwExStyle & WS_EX_MANAGED) &&
991                 ((*pWndB)->dwStyle & WS_VISIBLE )) break;
992     return ((*pWndB) != NULL);
993 }
994
995 static Window __get_common_ancestor( Display *display, Window A, Window B,
996                                      Window** children, unsigned* total )
997 {
998     /* find the real root window */
999
1000     Window      root, *childrenB;
1001     unsigned    totalB;
1002
1003     while( A != B && A && B )
1004     {
1005       TSXQueryTree( display, A, &root, &A, children, total );
1006       TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
1007       if( childrenB ) TSXFree( childrenB );
1008       if( *children ) TSXFree( *children ), *children = NULL;
1009     }
1010
1011     if( A && B )
1012     {
1013         TSXQueryTree( display, A, &root, &B, children, total );
1014         return A;
1015     }
1016     return 0 ;
1017 }
1018
1019 static Window __get_top_decoration( Display *display, Window w, Window ancestor )
1020 {
1021     Window*     children, root, prev = w, parent = w;
1022     unsigned    total;
1023
1024     do
1025     {
1026         w = parent;
1027         TSXQueryTree( display, w, &root, &parent, &children, &total );
1028         if( children ) TSXFree( children );
1029     } while( parent && parent != ancestor );
1030     TRACE("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
1031     return ( parent ) ? w : 0 ;
1032 }
1033
1034 static unsigned __td_lookup( Window w, Window* list, unsigned max )
1035 {
1036     unsigned    i;
1037     for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
1038     return i;
1039 }
1040
1041 static HWND query_zorder( Display *display, HWND hWndCheck)
1042 {
1043     HWND      hwndInsertAfter = HWND_TOP;
1044     WND      *pWndCheck = WIN_FindWndPtr(hWndCheck);
1045     WND      *pDesktop = WIN_GetDesktop();
1046     WND      *pWnd, *pWndZ = WIN_LockWndPtr(pDesktop->child);
1047     Window      w, parent, *children = NULL;
1048     unsigned    total, check, pos, best;
1049
1050     if( !__check_query_condition(&pWndZ, &pWnd) )
1051     {
1052         WIN_ReleaseWndPtr(pWndCheck);
1053         WIN_ReleaseWndPtr(pDesktop->child);
1054         WIN_ReleaseDesktop();
1055         return hwndInsertAfter;
1056     }
1057     WIN_LockWndPtr(pWndZ);
1058     WIN_LockWndPtr(pWnd);
1059     WIN_ReleaseWndPtr(pDesktop->child);
1060     WIN_ReleaseDesktop();
1061
1062     parent = __get_common_ancestor( display, get_whole_window(pWndZ),
1063                                     get_whole_window(pWnd), &children, &total );
1064     if( parent && children )
1065     {
1066         /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
1067
1068         w = __get_top_decoration( display, get_whole_window(pWndCheck), parent );
1069
1070         if( w != children[total-1] ) /* check if at the top */
1071         {
1072             /* X child at index 0 is at the bottom, at index total-1 is at the top */
1073             check = __td_lookup( w, children, total );
1074             best = total;
1075
1076             for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
1077             {
1078                 /* go through all windows in Wine z-order... */
1079
1080                 if( pWnd != pWndCheck )
1081                 {
1082                     if( !(pWnd->dwExStyle & WS_EX_MANAGED) ||
1083                         !(w = __get_top_decoration( display, get_whole_window(pWnd), parent )) )
1084                         continue;
1085                     pos = __td_lookup( w, children, total );
1086                     if( pos < best && pos > check )
1087                     {
1088                         /* find a nearest Wine window precedes 
1089                          * pWndCheck in the real z-order... */
1090                         best = pos;
1091                         hwndInsertAfter = pWnd->hwndSelf;
1092                     }
1093                     if( best - check == 1 ) break;
1094                 }
1095             }
1096         }
1097     }
1098     if( children ) TSXFree( children );
1099     WIN_ReleaseWndPtr(pWnd);
1100     WIN_ReleaseWndPtr(pWndZ);
1101     WIN_ReleaseWndPtr(pWndCheck);
1102     return hwndInsertAfter;
1103 }
1104
1105
1106 /***********************************************************************
1107  *              X11DRV_ConfigureNotify
1108  */
1109 void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
1110 {
1111     HWND oldInsertAfter;
1112     struct x11drv_win_data *data;
1113     WND *win;
1114     RECT rect;
1115     WINDOWPOS winpos;
1116     int x = event->x, y = event->y;
1117
1118     if (!(win = WIN_FindWndPtr( hwnd ))) return;
1119     data = win->pDriverData;
1120
1121     /* Get geometry */
1122
1123     if (!event->send_event)  /* normal event, need to map coordinates to the root */
1124     {
1125         Window child;
1126         wine_tsx11_lock();
1127         XTranslateCoordinates( event->display, data->whole_window, root_window,
1128                                0, 0, &x, &y, &child );
1129         wine_tsx11_unlock();
1130     }
1131     rect.left   = x;
1132     rect.top    = y;
1133     rect.right  = x + event->width;
1134     rect.bottom = y + event->height;
1135     TRACE( "win %x new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1136            hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1137            event->x, event->y, event->width, event->height );
1138     X11DRV_X_to_window_rect( win, &rect );
1139     WIN_ReleaseWndPtr( win );
1140
1141     winpos.hwnd  = hwnd;
1142     winpos.x     = rect.left;
1143     winpos.y     = rect.top;
1144     winpos.cx    = rect.right - rect.left;
1145     winpos.cy    = rect.bottom - rect.top;
1146     winpos.flags = SWP_NOACTIVATE;
1147
1148     /* Get Z-order (FIXME) */
1149
1150     winpos.hwndInsertAfter = query_zorder( event->display, hwnd );
1151
1152     /* needs to find the first Visible Window above the current one */
1153     oldInsertAfter = hwnd;
1154     for (;;)
1155     {
1156         oldInsertAfter = GetWindow( oldInsertAfter, GW_HWNDPREV );
1157         if (!oldInsertAfter)
1158         {
1159             oldInsertAfter = HWND_TOP;
1160             break;
1161         }
1162         if (GetWindowLongA( oldInsertAfter, GWL_STYLE ) & WS_VISIBLE) break;
1163     }
1164
1165     /* Compare what has changed */
1166
1167     GetWindowRect( hwnd, &rect );
1168     if (rect.left == winpos.x && rect.top == winpos.y) winpos.flags |= SWP_NOMOVE;
1169     else
1170         TRACE( "%04x moving from (%d,%d) to (%d,%d)\n",
1171                hwnd, rect.left, rect.top, winpos.x, winpos.y );
1172
1173     if (rect.right - rect.left == winpos.cx &&
1174         rect.bottom - rect.top == winpos.cy) winpos.flags |= SWP_NOSIZE;
1175     else
1176         TRACE( "%04x resizing from (%dx%d) to (%dx%d)\n",
1177                hwnd, rect.right - rect.left, rect.bottom - rect.top,
1178                winpos.cx, winpos.cy );
1179
1180     if (winpos.hwndInsertAfter == oldInsertAfter) winpos.flags |= SWP_NOZORDER;
1181     else
1182         TRACE( "%04x restacking from after %04x to after %04x\n",
1183                hwnd, oldInsertAfter, winpos.hwndInsertAfter );
1184
1185     /* if nothing changed, don't do anything */
1186     if (winpos.flags == (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE)) return;
1187
1188     SetWindowPos( hwnd, winpos.hwndInsertAfter, winpos.x, winpos.y,
1189                   winpos.cx, winpos.cy, winpos.flags | SWP_WINE_NOHOSTMOVE );
1190 }
1191
1192
1193 /***********************************************************************
1194  *              SetWindowRgn  (X11DRV.@)
1195  *
1196  * Assign specified region to window (for non-rectangular windows)
1197  */
1198 BOOL X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
1199 {
1200     RECT rect;
1201     WND *wndPtr = WIN_FindWndPtr(hwnd);
1202     int ret = FALSE;
1203
1204     if (!wndPtr) return FALSE;
1205
1206     if (wndPtr->hrgnWnd == hrgn)
1207     {
1208         ret = TRUE;
1209         goto done;
1210     }
1211
1212     if (hrgn) /* verify that region really exists */
1213     {
1214         if (GetRgnBox( hrgn, &rect ) == ERROR) goto done;
1215     }
1216
1217     if (wndPtr->hrgnWnd)
1218     {
1219         /* delete previous region */
1220         DeleteObject(wndPtr->hrgnWnd);
1221         wndPtr->hrgnWnd = 0;
1222     }
1223     wndPtr->hrgnWnd = hrgn;
1224
1225     /* Size the window to the rectangle of the new region (if it isn't NULL) */
1226     if (hrgn) SetWindowPos( hwnd, 0, rect.left, rect.top,
1227                             rect.right  - rect.left, rect.bottom - rect.top,
1228                             SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOACTIVATE |
1229                             SWP_NOZORDER | (redraw ? 0 : SWP_NOREDRAW) );
1230 #ifdef HAVE_LIBXSHAPE
1231     {
1232         Display *display = thread_display();
1233         X11DRV_WND_DATA *data = wndPtr->pDriverData;
1234
1235         if (data->whole_window)
1236         {
1237             if (!hrgn)
1238             {
1239                 TSXShapeCombineMask( display, data->whole_window,
1240                                      ShapeBounding, 0, 0, None, ShapeSet );
1241             }
1242             else
1243             {
1244                 XRectangle *aXRect;
1245                 int x_offset, y_offset;
1246                 DWORD size;
1247                 DWORD dwBufferSize = GetRegionData(hrgn, 0, NULL);
1248                 PRGNDATA pRegionData = HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
1249                 if (!pRegionData) goto done;
1250
1251                 GetRegionData(hrgn, dwBufferSize, pRegionData);
1252                 size = pRegionData->rdh.nCount;
1253                 x_offset = wndPtr->rectWindow.left - data->whole_rect.left;
1254                 y_offset = wndPtr->rectWindow.top - data->whole_rect.top;
1255                 /* convert region's "Windows rectangles" to XRectangles */
1256                 aXRect = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*aXRect) );
1257                 if (aXRect)
1258                 {
1259                     XRectangle* pCurrRect = aXRect;
1260                     RECT *pRect = (RECT*) pRegionData->Buffer;
1261                     for (; pRect < ((RECT*) pRegionData->Buffer) + size ; ++pRect, ++pCurrRect)
1262                     {
1263                         pCurrRect->x      = pRect->left + x_offset;
1264                         pCurrRect->y      = pRect->top + y_offset;
1265                         pCurrRect->height = pRect->bottom - pRect->top;
1266                         pCurrRect->width  = pRect->right  - pRect->left;
1267
1268                         TRACE("Rectangle %04d of %04ld data: X=%04d, Y=%04d, Height=%04d, Width=%04d.\n",
1269                               pRect - (RECT*) pRegionData->Buffer,
1270                               size,
1271                               pCurrRect->x,
1272                               pCurrRect->y,
1273                               pCurrRect->height,
1274                               pCurrRect->width);
1275                     }
1276
1277                     /* shape = non-rectangular windows (X11/extensions) */
1278                     TSXShapeCombineRectangles( display, data->whole_window, ShapeBounding,
1279                                                0, 0, aXRect,
1280                                                pCurrRect - aXRect, ShapeSet, YXBanded );
1281                     HeapFree(GetProcessHeap(), 0, aXRect );
1282                 }
1283                 HeapFree(GetProcessHeap(), 0, pRegionData);
1284             }
1285         }
1286     }
1287 #endif  /* HAVE_LIBXSHAPE */
1288
1289     ret = TRUE;
1290
1291  done:
1292     WIN_ReleaseWndPtr(wndPtr);
1293     return ret;
1294 }
1295
1296
1297 /***********************************************************************
1298  *           draw_moving_frame
1299  *
1300  * Draw the frame used when moving or resizing window.
1301  *
1302  * FIXME:  This causes problems in Win95 mode.  (why?)
1303  */
1304 static void draw_moving_frame( HDC hdc, RECT *rect, BOOL thickframe )
1305 {
1306     if (thickframe)
1307     {
1308         const int width = GetSystemMetrics(SM_CXFRAME);
1309         const int height = GetSystemMetrics(SM_CYFRAME);
1310
1311         HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
1312         PatBlt( hdc, rect->left, rect->top,
1313                 rect->right - rect->left - width, height, PATINVERT );
1314         PatBlt( hdc, rect->left, rect->top + height, width,
1315                 rect->bottom - rect->top - height, PATINVERT );
1316         PatBlt( hdc, rect->left + width, rect->bottom - 1,
1317                 rect->right - rect->left - width, -height, PATINVERT );
1318         PatBlt( hdc, rect->right - 1, rect->top, -width,
1319                 rect->bottom - rect->top - height, PATINVERT );
1320         SelectObject( hdc, hbrush );
1321     }
1322     else DrawFocusRect( hdc, rect );
1323 }
1324
1325
1326 /***********************************************************************
1327  *           start_size_move
1328  *
1329  * Initialisation of a move or resize, when initiatied from a menu choice.
1330  * Return hit test code for caption or sizing border.
1331  */
1332 static LONG start_size_move( WND* wndPtr, WPARAM wParam, POINT *capturePoint )
1333 {
1334     LONG hittest = 0;
1335     POINT pt;
1336     MSG msg;
1337     RECT rectWindow;
1338
1339     GetWindowRect(wndPtr->hwndSelf,&rectWindow);
1340
1341     if ((wParam & 0xfff0) == SC_MOVE)
1342     {
1343         /* Move pointer at the center of the caption */
1344         RECT rect;
1345         NC_GetInsideRect( wndPtr->hwndSelf, &rect );
1346         if (wndPtr->dwStyle & WS_SYSMENU)
1347             rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1348         if (wndPtr->dwStyle & WS_MINIMIZEBOX)
1349             rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1350         if (wndPtr->dwStyle & WS_MAXIMIZEBOX)
1351             rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1352         pt.x = rectWindow.left + (rect.right - rect.left) / 2;
1353         pt.y = rectWindow.top + rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1354         hittest = HTCAPTION;
1355         *capturePoint = pt;
1356     }
1357     else  /* SC_SIZE */
1358     {
1359         while(!hittest)
1360         {
1361             MSG_InternalGetMessage( &msg, 0, 0, WM_KEYFIRST, WM_MOUSELAST,
1362                                     MSGF_SIZE, PM_REMOVE, FALSE, NULL );
1363             switch(msg.message)
1364             {
1365             case WM_MOUSEMOVE:
1366                 hittest = NC_HandleNCHitTest( wndPtr->hwndSelf, msg.pt );
1367                 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT))
1368                     hittest = 0;
1369                 break;
1370
1371             case WM_LBUTTONUP:
1372                 return 0;
1373
1374             case WM_KEYDOWN:
1375                 switch(msg.wParam)
1376                 {
1377                 case VK_UP:
1378                     hittest = HTTOP;
1379                     pt.x =(rectWindow.left+rectWindow.right)/2;
1380                     pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
1381                     break;
1382                 case VK_DOWN:
1383                     hittest = HTBOTTOM;
1384                     pt.x =(rectWindow.left+rectWindow.right)/2;
1385                     pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
1386                     break;
1387                 case VK_LEFT:
1388                     hittest = HTLEFT;
1389                     pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
1390                     pt.y =(rectWindow.top+rectWindow.bottom)/2;
1391                     break;
1392                 case VK_RIGHT:
1393                     hittest = HTRIGHT;
1394                     pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
1395                     pt.y =(rectWindow.top+rectWindow.bottom)/2;
1396                     break;
1397                 case VK_RETURN:
1398                 case VK_ESCAPE: return 0;
1399                 }
1400             }
1401         }
1402         *capturePoint = pt;
1403     }
1404     SetCursorPos( pt.x, pt.y );
1405     NC_HandleSetCursor( wndPtr->hwndSelf,
1406                         wndPtr->hwndSelf, MAKELONG( hittest, WM_MOUSEMOVE ));
1407     return hittest;
1408 }
1409
1410
1411 /***********************************************************************
1412  *           X11DRV_SysCommandSizeMove   (X11DRV.@)
1413  *
1414  * Perform SC_MOVE and SC_SIZE commands.
1415  */
1416 void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
1417 {
1418     MSG msg;
1419     RECT sizingRect, mouseRect, origRect;
1420     HDC hdc;
1421     LONG hittest = (LONG)(wParam & 0x0f);
1422     HCURSOR16 hDragCursor = 0, hOldCursor = 0;
1423     POINT minTrack, maxTrack;
1424     POINT capturePoint, pt;
1425     WND *     wndPtr = WIN_FindWndPtr( hwnd );
1426     BOOL    thickframe = HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle );
1427     BOOL    iconic = wndPtr->dwStyle & WS_MINIMIZE;
1428     BOOL    moved = FALSE;
1429     DWORD     dwPoint = GetMessagePos ();
1430     BOOL DragFullWindows = FALSE;
1431     BOOL grab;
1432     int iWndsLocks;
1433     Display *old_gdi_display = NULL;
1434     Display *display = thread_display();
1435
1436     SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
1437
1438     pt.x = SLOWORD(dwPoint);
1439     pt.y = SHIWORD(dwPoint);
1440     capturePoint = pt;
1441
1442     if (IsZoomed(hwnd) || !IsWindowVisible(hwnd) ||
1443         (wndPtr->dwExStyle & WS_EX_MANAGED)) goto END;
1444
1445     if ((wParam & 0xfff0) == SC_MOVE)
1446     {
1447         if (!hittest) hittest = start_size_move( wndPtr, wParam, &capturePoint );
1448         if (!hittest) goto END;
1449     }
1450     else  /* SC_SIZE */
1451     {
1452         if (!thickframe) goto END;
1453         if ( hittest && hittest != HTSYSMENU ) hittest += 2;
1454         else
1455         {
1456             SetCapture(hwnd);
1457             hittest = start_size_move( wndPtr, wParam, &capturePoint );
1458             if (!hittest)
1459             {
1460                 ReleaseCapture();
1461                 goto END;
1462             }
1463         }
1464     }
1465
1466       /* Get min/max info */
1467
1468     WINPOS_GetMinMaxInfo( wndPtr, NULL, NULL, &minTrack, &maxTrack );
1469     sizingRect = wndPtr->rectWindow;
1470     origRect = sizingRect;
1471     if (wndPtr->dwStyle & WS_CHILD)
1472         GetClientRect( wndPtr->parent->hwndSelf, &mouseRect );
1473     else
1474         SetRect(&mouseRect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1475     if (ON_LEFT_BORDER(hittest))
1476     {
1477         mouseRect.left  = max( mouseRect.left, sizingRect.right-maxTrack.x );
1478         mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x );
1479     }
1480     else if (ON_RIGHT_BORDER(hittest))
1481     {
1482         mouseRect.left  = max( mouseRect.left, sizingRect.left+minTrack.x );
1483         mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x );
1484     }
1485     if (ON_TOP_BORDER(hittest))
1486     {
1487         mouseRect.top    = max( mouseRect.top, sizingRect.bottom-maxTrack.y );
1488         mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y);
1489     }
1490     else if (ON_BOTTOM_BORDER(hittest))
1491     {
1492         mouseRect.top    = max( mouseRect.top, sizingRect.top+minTrack.y );
1493         mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y );
1494     }
1495     if (wndPtr->dwStyle & WS_CHILD)
1496     {
1497         MapWindowPoints( wndPtr->parent->hwndSelf, 0, (LPPOINT)&mouseRect, 2 );
1498     }
1499
1500     /* Retrieve a default cache DC (without using the window style) */
1501     hdc = GetDCEx( wndPtr->parent->hwndSelf, 0, DCX_CACHE );
1502
1503     if( iconic ) /* create a cursor for dragging */
1504     {
1505         HICON hIcon = GetClassLongA( hwnd, GCL_HICON);
1506         if(!hIcon) hIcon = (HICON)SendMessageA( hwnd, WM_QUERYDRAGICON, 0, 0L);
1507         if( hIcon ) hDragCursor =  CURSORICON_IconToCursor( hIcon, TRUE );
1508         if( !hDragCursor ) iconic = FALSE;
1509     }
1510
1511     /* repaint the window before moving it around */
1512     RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
1513
1514     SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
1515     SetCapture( hwnd );
1516
1517     /* grab the server only when moving top-level windows without desktop */
1518     grab = (!DragFullWindows && (root_window == DefaultRootWindow(gdi_display)) &&
1519             (wndPtr->parent->hwndSelf == GetDesktopWindow()));
1520
1521     wine_tsx11_lock();
1522     if (grab)
1523     {
1524         XSync( gdi_display, False );
1525         XGrabServer( display );
1526         XSync( display, False );
1527         /* switch gdi display to the thread display, since the server is grabbed */
1528         old_gdi_display = gdi_display;
1529         gdi_display = display;
1530     }
1531     XGrabPointer( display, get_whole_window(wndPtr), False,
1532                   PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1533                   GrabModeAsync, GrabModeAsync, get_client_window(wndPtr->parent),
1534                   None, CurrentTime );
1535     wine_tsx11_unlock();
1536
1537     while(1)
1538     {
1539         int dx = 0, dy = 0;
1540
1541         MSG_InternalGetMessage( &msg, 0, 0, WM_KEYFIRST, WM_MOUSELAST,
1542                                 MSGF_SIZE, PM_REMOVE, FALSE, NULL );
1543
1544         /* Exit on button-up, Return, or Esc */
1545         if ((msg.message == WM_LBUTTONUP) ||
1546             ((msg.message == WM_KEYDOWN) &&
1547              ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
1548
1549         if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
1550             continue;  /* We are not interested in other messages */
1551
1552         pt = msg.pt;
1553
1554         if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1555         {
1556         case VK_UP:    pt.y -= 8; break;
1557         case VK_DOWN:  pt.y += 8; break;
1558         case VK_LEFT:  pt.x -= 8; break;
1559         case VK_RIGHT: pt.x += 8; break;
1560         }
1561
1562         pt.x = max( pt.x, mouseRect.left );
1563         pt.x = min( pt.x, mouseRect.right );
1564         pt.y = max( pt.y, mouseRect.top );
1565         pt.y = min( pt.y, mouseRect.bottom );
1566
1567         dx = pt.x - capturePoint.x;
1568         dy = pt.y - capturePoint.y;
1569
1570         if (dx || dy)
1571         {
1572             if( !moved )
1573             {
1574                 moved = TRUE;
1575
1576                 if( iconic ) /* ok, no system popup tracking */
1577                 {
1578                     hOldCursor = SetCursor(hDragCursor);
1579                     ShowCursor( TRUE );
1580                     WINPOS_ShowIconTitle( wndPtr, FALSE );
1581                 }
1582                 else if(!DragFullWindows)
1583                     draw_moving_frame( hdc, &sizingRect, thickframe );
1584             }
1585
1586             if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
1587             else
1588             {
1589                 RECT newRect = sizingRect;
1590                 WPARAM wpSizingHit = 0;
1591
1592                 if (hittest == HTCAPTION) OffsetRect( &newRect, dx, dy );
1593                 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
1594                 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
1595                 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
1596                 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
1597                 if(!iconic && !DragFullWindows) draw_moving_frame( hdc, &sizingRect, thickframe );
1598                 capturePoint = pt;
1599
1600                 /* determine the hit location */
1601                 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
1602                     wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
1603                 SendMessageA( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&newRect );
1604
1605                 if (!iconic)
1606                 {
1607                     if(!DragFullWindows)
1608                         draw_moving_frame( hdc, &newRect, thickframe );
1609                     else {
1610                         /* To avoid any deadlocks, all the locks on the windows
1611                            structures must be suspended before the SetWindowPos */
1612                         iWndsLocks = WIN_SuspendWndsLock();
1613                         SetWindowPos( hwnd, 0, newRect.left, newRect.top,
1614                                       newRect.right - newRect.left,
1615                                       newRect.bottom - newRect.top,
1616                                       ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
1617                         WIN_RestoreWndsLock(iWndsLocks);
1618                     }
1619                 }
1620                 sizingRect = newRect;
1621             }
1622         }
1623     }
1624
1625     ReleaseCapture();
1626     if( iconic )
1627     {
1628         if( moved ) /* restore cursors, show icon title later on */
1629         {
1630             ShowCursor( FALSE );
1631             SetCursor( hOldCursor );
1632         }
1633         DestroyCursor( hDragCursor );
1634     }
1635     else if (moved && !DragFullWindows)
1636         draw_moving_frame( hdc, &sizingRect, thickframe );
1637
1638     ReleaseDC( wndPtr->parent->hwndSelf, hdc );
1639
1640     wine_tsx11_lock();
1641     XUngrabPointer( display, CurrentTime );
1642     if (grab)
1643     {
1644         XSync( display, False );
1645         XUngrabServer( display );
1646         XSync( display, False );
1647         gdi_display = old_gdi_display;
1648     }
1649     wine_tsx11_unlock();
1650
1651     if (HOOK_CallHooksA( WH_CBT, HCBT_MOVESIZE, hwnd, (LPARAM)&sizingRect ))
1652         sizingRect = wndPtr->rectWindow;
1653
1654     SendMessageA( hwnd, WM_EXITSIZEMOVE, 0, 0 );
1655     SendMessageA( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
1656
1657     /* window moved or resized */
1658     if (moved)
1659     {
1660         /* To avoid any deadlocks, all the locks on the windows
1661            structures must be suspended before the SetWindowPos */
1662         iWndsLocks = WIN_SuspendWndsLock();
1663
1664         /* if the moving/resizing isn't canceled call SetWindowPos
1665          * with the new position or the new size of the window
1666          */
1667         if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
1668         {
1669             /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
1670             if(!DragFullWindows)
1671                 SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
1672                               sizingRect.right - sizingRect.left,
1673                               sizingRect.bottom - sizingRect.top,
1674                               ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
1675         }
1676         else
1677         { /* restore previous size/position */
1678             if(DragFullWindows)
1679                 SetWindowPos( hwnd, 0, origRect.left, origRect.top,
1680                               origRect.right - origRect.left,
1681                               origRect.bottom - origRect.top,
1682                               ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
1683         }
1684
1685         WIN_RestoreWndsLock(iWndsLocks);
1686     }
1687
1688     if (IsIconic(hwnd))
1689     {
1690         /* Single click brings up the system menu when iconized */
1691
1692         if( !moved )
1693         {
1694             if( wndPtr->dwStyle & WS_SYSMENU )
1695                 SendMessageA( hwnd, WM_SYSCOMMAND,
1696                               SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
1697         }
1698         else WINPOS_ShowIconTitle( wndPtr, TRUE );
1699     }
1700
1701 END:
1702     WIN_ReleaseWndPtr(wndPtr);
1703 }