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