advapi32: Create MachineGuid value if it doesn't exist.
[wine] / dlls / winex11.drv / 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  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <stdarg.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winerror.h"
33 #include "wine/wingdi16.h"
34
35 #include "x11drv.h"
36
37 #include "wine/server.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
41
42 #define SWP_AGG_NOPOSCHANGE \
43     (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
44
45 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
46 #define _NET_WM_MOVERESIZE_SIZE_TOP          1
47 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
48 #define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
49 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
50 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
51 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
52 #define _NET_WM_MOVERESIZE_SIZE_LEFT         7
53 #define _NET_WM_MOVERESIZE_MOVE              8   /* movement only */
54 #define _NET_WM_MOVERESIZE_SIZE_KEYBOARD     9   /* size via keyboard */
55 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD    10   /* move via keyboard */
56
57 #define _NET_WM_STATE_REMOVE  0
58 #define _NET_WM_STATE_ADD     1
59 #define _NET_WM_STATE_TOGGLE  2
60
61 static const char managed_prop[] = "__wine_x11_managed";
62
63 /***********************************************************************
64  *           X11DRV_Expose
65  */
66 void X11DRV_Expose( HWND hwnd, XEvent *xev )
67 {
68     XExposeEvent *event = &xev->xexpose;
69     RECT rect;
70     struct x11drv_win_data *data;
71     int flags = RDW_INVALIDATE | RDW_ERASE;
72
73     TRACE( "win %p (%lx) %d,%d %dx%d\n",
74            hwnd, event->window, event->x, event->y, event->width, event->height );
75
76     if (!(data = X11DRV_get_win_data( hwnd ))) return;
77
78     if (event->window == data->whole_window)
79     {
80         rect.left = data->whole_rect.left + event->x;
81         rect.top  = data->whole_rect.top + event->y;
82         flags |= RDW_FRAME;
83     }
84     else
85     {
86         rect.left = data->client_rect.left + event->x;
87         rect.top  = data->client_rect.top + event->y;
88     }
89     rect.right  = rect.left + event->width;
90     rect.bottom = rect.top + event->height;
91
92     if (event->window != root_window)
93     {
94         SERVER_START_REQ( update_window_zorder )
95         {
96             req->window      = hwnd;
97             req->rect.left   = rect.left;
98             req->rect.top    = rect.top;
99             req->rect.right  = rect.right;
100             req->rect.bottom = rect.bottom;
101             wine_server_call( req );
102         }
103         SERVER_END_REQ;
104
105         /* make position relative to client area instead of parent */
106         OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top );
107         flags |= RDW_ALLCHILDREN;
108     }
109
110     RedrawWindow( hwnd, &rect, 0, flags );
111 }
112
113 /***********************************************************************
114  *              SetWindowStyle   (X11DRV.@)
115  *
116  * Update the X state of a window to reflect a style change
117  */
118 void X11DRV_SetWindowStyle( HWND hwnd, DWORD old_style )
119 {
120     Display *display = thread_display();
121     struct x11drv_win_data *data;
122     DWORD new_style, changed;
123
124     if (hwnd == GetDesktopWindow()) return;
125     new_style = GetWindowLongW( hwnd, GWL_STYLE );
126     changed = new_style ^ old_style;
127
128     if ((changed & WS_VISIBLE) && (new_style & WS_VISIBLE))
129     {
130         /* we don't unmap windows, that causes trouble with the window manager */
131         if (!(data = X11DRV_get_win_data( hwnd )) &&
132             !(data = X11DRV_create_win_data( hwnd ))) return;
133
134         if (data->whole_window && X11DRV_is_window_rect_mapped( &data->window_rect ))
135         {
136             X11DRV_set_wm_hints( display, data );
137             if (!data->mapped)
138             {
139                 TRACE( "mapping win %p/%lx\n", hwnd, data->whole_window );
140                 wait_for_withdrawn_state( display, data, TRUE );
141                 X11DRV_sync_window_style( display, data );
142                 wine_tsx11_lock();
143                 XMapWindow( display, data->whole_window );
144                 wine_tsx11_unlock();
145                 data->mapped = TRUE;
146                 data->iconic = (new_style & WS_MINIMIZE) != 0;
147             }
148         }
149     }
150
151     if (changed & WS_DISABLED)
152     {
153         data = X11DRV_get_win_data( hwnd );
154         if (data && data->wm_hints)
155         {
156             wine_tsx11_lock();
157             data->wm_hints->input = !(new_style & WS_DISABLED);
158             XSetWMHints( display, data->whole_window, data->wm_hints );
159             wine_tsx11_unlock();
160         }
161     }
162 }
163
164
165 /***********************************************************************
166  *     update_net_wm_states
167  */
168 static void update_net_wm_states( Display *display, struct x11drv_win_data *data )
169 {
170     static const unsigned int state_atoms[NB_NET_WM_STATES] =
171     {
172         XATOM__NET_WM_STATE_FULLSCREEN,
173         XATOM__NET_WM_STATE_ABOVE,
174         XATOM__NET_WM_STATE_MAXIMIZED_VERT,
175         XATOM__NET_WM_STATE_SKIP_PAGER,
176         XATOM__NET_WM_STATE_SKIP_TASKBAR
177     };
178
179     DWORD i, style, ex_style, new_state = 0;
180     XEvent xev;
181
182     if (!data->managed) return;
183     if (!data->mapped) return;
184
185     style = GetWindowLongW( data->hwnd, GWL_STYLE );
186     if (data->whole_rect.left <= 0 && data->whole_rect.right >= screen_width &&
187         data->whole_rect.top <= 0 && data->whole_rect.bottom >= screen_height)
188     {
189         if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION)
190             new_state |= (1 << NET_WM_STATE_MAXIMIZED);
191         else
192             new_state |= (1 << NET_WM_STATE_FULLSCREEN);
193     }
194     else if (style & WS_MAXIMIZE)
195         new_state |= (1 << NET_WM_STATE_MAXIMIZED);
196
197     ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
198     if (ex_style & WS_EX_TOPMOST)
199         new_state |= (1 << NET_WM_STATE_ABOVE);
200     if (ex_style & WS_EX_TOOLWINDOW)
201         new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR) | (1 << NET_WM_STATE_SKIP_PAGER);
202     if (GetWindow( data->hwnd, GW_OWNER ))
203         new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR);
204
205     xev.xclient.type = ClientMessage;
206     xev.xclient.window = data->whole_window;
207     xev.xclient.message_type = x11drv_atom(_NET_WM_STATE);
208     xev.xclient.serial = 0;
209     xev.xclient.display = display;
210     xev.xclient.send_event = True;
211     xev.xclient.format = 32;
212     xev.xclient.data.l[3] = 1;
213
214     for (i = 0; i < NB_NET_WM_STATES; i++)
215     {
216         if (!((data->net_wm_state ^ new_state) & (1 << i))) continue;  /* unchanged */
217
218         TRACE( "setting wm state %u for window %p/%lx to %u prev %u\n",
219                i, data->hwnd, data->whole_window,
220                (new_state & (1 << i)) != 0, (data->net_wm_state & (1 << i)) != 0 );
221
222         xev.xclient.data.l[0] = (new_state & (1 << i)) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
223         xev.xclient.data.l[1] = X11DRV_Atoms[state_atoms[i] - FIRST_XATOM];
224         xev.xclient.data.l[2] = ((state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT) ?
225                                  x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ) : 0);
226         wine_tsx11_lock();
227         XSendEvent( display, root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev );
228         wine_tsx11_unlock();
229     }
230     data->net_wm_state = new_state;
231 }
232
233
234 /***********************************************************************
235  *              move_window_bits
236  *
237  * Move the window bits when a window is moved.
238  */
239 static void move_window_bits( struct x11drv_win_data *data, const RECT *old_rect, const RECT *new_rect,
240                               const RECT *old_client_rect )
241 {
242     RECT src_rect = *old_rect;
243     RECT dst_rect = *new_rect;
244     HDC hdc_src, hdc_dst;
245     INT code;
246     HRGN rgn = 0;
247     HWND parent = 0;
248
249     if (!data->whole_window)
250     {
251         OffsetRect( &dst_rect, -data->window_rect.left, -data->window_rect.top );
252         parent = GetAncestor( data->hwnd, GA_PARENT );
253         hdc_src = GetDCEx( parent, 0, DCX_CACHE );
254         hdc_dst = GetDCEx( data->hwnd, 0, DCX_CACHE | DCX_WINDOW );
255     }
256     else
257     {
258         OffsetRect( &dst_rect, -data->client_rect.left, -data->client_rect.top );
259         /* make src rect relative to the old position of the window */
260         OffsetRect( &src_rect, -old_client_rect->left, -old_client_rect->top );
261         if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
262         hdc_src = hdc_dst = GetDCEx( data->hwnd, 0, DCX_CACHE );
263     }
264
265     code = X11DRV_START_EXPOSURES;
266     ExtEscape( hdc_dst, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
267
268     TRACE( "copying bits for win %p/%lx/%lx %s -> %s\n",
269            data->hwnd, data->whole_window, data->client_window,
270            wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect) );
271     BitBlt( hdc_dst, dst_rect.left, dst_rect.top,
272             dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
273             hdc_src, src_rect.left, src_rect.top, SRCCOPY );
274
275     code = X11DRV_END_EXPOSURES;
276     ExtEscape( hdc_dst, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, sizeof(rgn), (LPSTR)&rgn );
277
278     ReleaseDC( data->hwnd, hdc_dst );
279     if (hdc_src != hdc_dst) ReleaseDC( parent, hdc_src );
280
281     if (rgn)
282     {
283         if (!data->whole_window)
284         {
285             /* map region to client rect since we are using DCX_WINDOW */
286             OffsetRgn( rgn, data->window_rect.left - data->client_rect.left,
287                        data->window_rect.top - data->client_rect.top );
288             RedrawWindow( data->hwnd, NULL, rgn,
289                           RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN );
290         }
291         else RedrawWindow( data->hwnd, NULL, rgn, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
292         DeleteObject( rgn );
293     }
294 }
295
296 /***********************************************************************
297  *              SetWindowPos   (X11DRV.@)
298  */
299 void X11DRV_SetWindowPos( HWND hwnd, HWND insert_after, UINT swp_flags,
300                           const RECT *rectWindow, const RECT *rectClient,
301                           const RECT *visible_rect, const RECT *valid_rects )
302 {
303     Display *display = thread_display();
304     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
305     DWORD new_style = GetWindowLongW( hwnd, GWL_STYLE );
306     RECT old_window_rect, old_whole_rect, old_client_rect;
307
308     if (!data)
309     {
310         /* create the win data if the window is being made visible */
311         if (!(new_style & WS_VISIBLE)) return;
312         if (!(data = X11DRV_create_win_data( hwnd ))) return;
313     }
314
315     /* check if we need to switch the window to managed */
316     if (!data->managed && data->whole_window && is_window_managed( hwnd, swp_flags, rectWindow ))
317     {
318         TRACE( "making win %p/%lx managed\n", hwnd, data->whole_window );
319         data->managed = TRUE;
320         SetPropA( hwnd, managed_prop, (HANDLE)1 );
321         if (data->mapped)
322         {
323             wine_tsx11_lock();
324             XUnmapWindow( display, data->whole_window );
325             wine_tsx11_unlock();
326             data->mapped = FALSE;
327         }
328     }
329
330     old_window_rect = data->window_rect;
331     old_whole_rect  = data->whole_rect;
332     old_client_rect = data->client_rect;
333     data->window_rect = *rectWindow;
334     data->whole_rect  = *rectWindow;
335     data->client_rect = *rectClient;
336     X11DRV_window_to_X_rect( data, &data->whole_rect );
337     if (memcmp( visible_rect, &data->whole_rect, sizeof(RECT) ))
338     {
339         TRACE( "%p: need to update visible rect %s -> %s\n", hwnd,
340                wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(&data->whole_rect) );
341         SERVER_START_REQ( set_window_visible_rect )
342         {
343             req->handle         = hwnd;
344             req->flags          = swp_flags;
345             req->visible.left   = data->whole_rect.left;
346             req->visible.top    = data->whole_rect.top;
347             req->visible.right  = data->whole_rect.right;
348             req->visible.bottom = data->whole_rect.bottom;
349             wine_server_call( req );
350         }
351         SERVER_END_REQ;
352     }
353
354     TRACE( "win %p window %s client %s style %08x flags %08x\n",
355            hwnd, wine_dbgstr_rect(rectWindow), wine_dbgstr_rect(rectClient), new_style, swp_flags );
356
357     if (!IsRectEmpty( &valid_rects[0] ))
358     {
359         int x_offset = old_whole_rect.left - data->whole_rect.left;
360         int y_offset = old_whole_rect.top - data->whole_rect.top;
361
362         /* if all that happened is that the whole window moved, copy everything */
363         if (!(swp_flags & SWP_FRAMECHANGED) &&
364             old_whole_rect.right   - data->whole_rect.right   == x_offset &&
365             old_whole_rect.bottom  - data->whole_rect.bottom  == y_offset &&
366             old_client_rect.left   - data->client_rect.left   == x_offset &&
367             old_client_rect.right  - data->client_rect.right  == x_offset &&
368             old_client_rect.top    - data->client_rect.top    == y_offset &&
369             old_client_rect.bottom - data->client_rect.bottom == y_offset &&
370             !memcmp( &valid_rects[0], &data->client_rect, sizeof(RECT) ))
371         {
372             /* if we have an X window the bits will be moved by the X server */
373             if (!data->whole_window)
374                 move_window_bits( data, &old_whole_rect, &data->whole_rect, &old_client_rect );
375         }
376         else
377             move_window_bits( data, &valid_rects[1], &valid_rects[0], &old_client_rect );
378     }
379
380     X11DRV_sync_client_position( display, data, swp_flags, &old_client_rect, &old_whole_rect );
381
382     if (!data->whole_window || data->lock_changes) return;  /* nothing more to do */
383
384     if (data->mapped && (!(new_style & WS_VISIBLE) || !X11DRV_is_window_rect_mapped( rectWindow )))
385     {
386         TRACE( "unmapping win %p/%lx\n", hwnd, data->whole_window );
387         wait_for_withdrawn_state( display, data, FALSE );
388         wine_tsx11_lock();
389         if (data->managed) XWithdrawWindow( display, data->whole_window, DefaultScreen(display) );
390         else XUnmapWindow( display, data->whole_window );
391         wine_tsx11_unlock();
392         data->mapped = FALSE;
393         data->net_wm_state = 0;
394     }
395
396     /* don't change position if we are about to minimize or maximize a managed window */
397     if (!(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE))))
398         X11DRV_sync_window_position( display, data, swp_flags, &old_client_rect, &old_whole_rect );
399
400     if ((new_style & WS_VISIBLE) &&
401         ((new_style & WS_MINIMIZE) || X11DRV_is_window_rect_mapped( rectWindow )))
402     {
403         if (!data->mapped || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
404             X11DRV_set_wm_hints( display, data );
405
406         if (!data->mapped)
407         {
408             TRACE( "mapping win %p/%lx\n", hwnd, data->whole_window );
409             wait_for_withdrawn_state( display, data, TRUE );
410             X11DRV_sync_window_style( display, data );
411             wine_tsx11_lock();
412             XMapWindow( display, data->whole_window );
413             XFlush( display );
414             wine_tsx11_unlock();
415             data->mapped = TRUE;
416             data->iconic = (new_style & WS_MINIMIZE) != 0;
417         }
418         else if ((swp_flags & SWP_STATECHANGED) && (!data->iconic != !(new_style & WS_MINIMIZE)))
419         {
420             data->iconic = (new_style & WS_MINIMIZE) != 0;
421             TRACE( "changing win %p iconic state to %u\n", data->hwnd, data->iconic );
422             wine_tsx11_lock();
423             if (data->iconic)
424                 XIconifyWindow( display, data->whole_window, DefaultScreen(display) );
425             else if (X11DRV_is_window_rect_mapped( rectWindow ))
426                 XMapWindow( display, data->whole_window );
427             wine_tsx11_unlock();
428         }
429         update_net_wm_states( display, data );
430     }
431 }
432
433
434 /**********************************************************************
435  *              X11DRV_MapNotify
436  */
437 void X11DRV_MapNotify( HWND hwnd, XEvent *event )
438 {
439     struct x11drv_win_data *data;
440     int state;
441
442     if (!(data = X11DRV_get_win_data( hwnd ))) return;
443     if (!data->mapped) return;
444
445     if (!data->managed)
446     {
447         HWND hwndFocus = GetFocus();
448         if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus);  /* FIXME */
449         return;
450     }
451     if (!data->iconic) return;
452
453     state = get_window_wm_state( event->xmap.display, data );
454     if (state == NormalState)
455     {
456         int x, y;
457         unsigned int width, height, border, depth;
458         Window root, top;
459         WINDOWPLACEMENT wp;
460         RECT rect;
461
462         /* FIXME: hack */
463         wine_tsx11_lock();
464         XGetGeometry( event->xmap.display, data->whole_window, &root, &x, &y, &width, &height,
465                         &border, &depth );
466         XTranslateCoordinates( event->xmap.display, data->whole_window, root, 0, 0, &x, &y, &top );
467         wine_tsx11_unlock();
468         rect.left   = x;
469         rect.top    = y;
470         rect.right  = x + width;
471         rect.bottom = y + height;
472         OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
473         X11DRV_X_to_window_rect( data, &rect );
474
475         wp.length = sizeof(wp);
476         GetWindowPlacement( hwnd, &wp );
477         wp.flags = 0;
478         wp.showCmd = SW_RESTORE;
479         wp.rcNormalPosition = rect;
480
481         TRACE( "restoring win %p/%lx\n", hwnd, data->whole_window );
482         data->iconic = FALSE;
483         data->lock_changes++;
484         SetWindowPlacement( hwnd, &wp );
485         data->lock_changes--;
486     }
487     else TRACE( "win %p/%lx ignoring since state=%d\n", hwnd, data->whole_window, state );
488 }
489
490
491 /**********************************************************************
492  *              X11DRV_UnmapNotify
493  */
494 void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
495 {
496     struct x11drv_win_data *data;
497     int state;
498
499     if (!(data = X11DRV_get_win_data( hwnd ))) return;
500     if (!data->managed || !data->mapped || data->iconic) return;
501
502     state = get_window_wm_state( event->xunmap.display, data );
503     if (state == IconicState)
504     {
505         TRACE( "minimizing win %p/%lx\n", hwnd, data->whole_window );
506         data->iconic = TRUE;
507         data->lock_changes++;
508         ShowWindow( hwnd, SW_MINIMIZE );
509         data->lock_changes--;
510     }
511     else TRACE( "win %p/%lx ignoring since state=%d\n", hwnd, data->whole_window, state );
512 }
513
514 struct desktop_resize_data
515 {
516     RECT  old_screen_rect;
517     RECT  old_virtual_rect;
518 };
519
520 static BOOL CALLBACK update_windows_on_desktop_resize( HWND hwnd, LPARAM lparam )
521 {
522     struct x11drv_win_data *data;
523     Display *display = thread_display();
524     struct desktop_resize_data *resize_data = (struct desktop_resize_data *)lparam;
525     int mask = 0;
526
527     if (!(data = X11DRV_get_win_data( hwnd ))) return TRUE;
528
529     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
530     {
531         /* update the full screen state */
532         update_net_wm_states( display, data );
533     }
534
535     if (resize_data->old_virtual_rect.left != virtual_screen_rect.left) mask |= CWX;
536     if (resize_data->old_virtual_rect.top != virtual_screen_rect.top) mask |= CWY;
537     if (mask && data->whole_window)
538     {
539         XWindowChanges changes;
540
541         wine_tsx11_lock();
542         changes.x = data->whole_rect.left - virtual_screen_rect.left;
543         changes.y = data->whole_rect.top - virtual_screen_rect.top;
544         XReconfigureWMWindow( display, data->whole_window,
545                               DefaultScreen(display), mask, &changes );
546         wine_tsx11_unlock();
547     }
548     return TRUE;
549 }
550
551
552 /***********************************************************************
553  *              X11DRV_resize_desktop
554  */
555 void X11DRV_resize_desktop( unsigned int width, unsigned int height )
556 {
557     HWND hwnd = GetDesktopWindow();
558     struct desktop_resize_data resize_data;
559
560     SetRect( &resize_data.old_screen_rect, 0, 0, screen_width, screen_height );
561     resize_data.old_virtual_rect = virtual_screen_rect;
562
563     xinerama_init( width, height );
564
565     if (GetWindowThreadProcessId( hwnd, NULL ) != GetCurrentThreadId())
566     {
567         SendMessageW( hwnd, WM_X11DRV_RESIZE_DESKTOP, 0, MAKELPARAM( width, height ) );
568     }
569     else
570     {
571         TRACE( "desktop %p change to (%dx%d)\n", hwnd, width, height );
572         SetWindowPos( hwnd, 0, virtual_screen_rect.left, virtual_screen_rect.top,
573                       virtual_screen_rect.right - virtual_screen_rect.left,
574                       virtual_screen_rect.bottom - virtual_screen_rect.top,
575                       SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE );
576         SendMessageTimeoutW( HWND_BROADCAST, WM_DISPLAYCHANGE, screen_bpp,
577                              MAKELPARAM( width, height ), SMTO_ABORTIFHUNG, 2000, NULL );
578     }
579
580     EnumWindows( update_windows_on_desktop_resize, (LPARAM)&resize_data );
581 }
582
583
584 /***********************************************************************
585  *              X11DRV_ConfigureNotify
586  */
587 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
588 {
589     XConfigureEvent *event = &xev->xconfigure;
590     struct x11drv_win_data *data;
591     RECT rect;
592     UINT flags;
593     int cx, cy, x = event->x, y = event->y;
594
595     if (!hwnd) return;
596     if (!(data = X11DRV_get_win_data( hwnd ))) return;
597
598     /* Get geometry */
599
600     if (!event->send_event)  /* normal event, need to map coordinates to the root */
601     {
602         Window child;
603         wine_tsx11_lock();
604         XTranslateCoordinates( event->display, data->whole_window, root_window,
605                                0, 0, &x, &y, &child );
606         wine_tsx11_unlock();
607     }
608     rect.left   = x;
609     rect.top    = y;
610     rect.right  = x + event->width;
611     rect.bottom = y + event->height;
612     OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
613     TRACE( "win %p new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
614            hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
615            event->x, event->y, event->width, event->height );
616     X11DRV_X_to_window_rect( data, &rect );
617
618     x     = rect.left;
619     y     = rect.top;
620     cx    = rect.right - rect.left;
621     cy    = rect.bottom - rect.top;
622     flags = SWP_NOACTIVATE | SWP_NOZORDER;
623
624     /* Compare what has changed */
625
626     GetWindowRect( hwnd, &rect );
627     if (rect.left == x && rect.top == y) flags |= SWP_NOMOVE;
628     else
629         TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
630                hwnd, rect.left, rect.top, x, y );
631
632     if ((rect.right - rect.left == cx && rect.bottom - rect.top == cy) ||
633         IsIconic(hwnd) ||
634         (IsRectEmpty( &rect ) && event->width == 1 && event->height == 1))
635     {
636         if (flags & SWP_NOMOVE) return;  /* if nothing changed, don't do anything */
637         flags |= SWP_NOSIZE;
638     }
639     else
640         TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
641                hwnd, rect.right - rect.left, rect.bottom - rect.top, cx, cy );
642
643     data->lock_changes++;
644     SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
645     data->lock_changes--;
646 }
647
648
649 /***********************************************************************
650  *              is_netwm_supported
651  */
652 static BOOL is_netwm_supported( Display *display, Atom atom )
653 {
654     static Atom *net_supported;
655     static int net_supported_count = -1;
656     int i;
657
658     wine_tsx11_lock();
659     if (net_supported_count == -1)
660     {
661         Atom type;
662         int format;
663         unsigned long count, remaining;
664
665         if (!XGetWindowProperty( display, DefaultRootWindow(display), x11drv_atom(_NET_SUPPORTED), 0,
666                                  ~0UL, False, XA_ATOM, &type, &format, &count,
667                                  &remaining, (unsigned char **)&net_supported ))
668             net_supported_count = count * (format / 8) / sizeof(Atom);
669         else
670             net_supported_count = 0;
671     }
672     wine_tsx11_unlock();
673
674     for (i = 0; i < net_supported_count; i++)
675         if (net_supported[i] == atom) return TRUE;
676     return FALSE;
677 }
678
679
680 /***********************************************************************
681  *           SysCommandSizeMove   (X11DRV.@)
682  *
683  * Perform SC_MOVE and SC_SIZE commands.
684  */
685 BOOL X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wparam )
686 {
687     WPARAM syscommand = wparam & 0xfff0;
688     WPARAM hittest = wparam & 0x0f;
689     DWORD dwPoint;
690     int x, y, dir;
691     XEvent xev;
692     Display *display = thread_display();
693     struct x11drv_win_data *data;
694
695     if (!(data = X11DRV_get_win_data( hwnd ))) return FALSE;
696     if (!data->whole_window || !data->managed) return FALSE;
697
698     if (!is_netwm_supported( display, x11drv_atom(_NET_WM_MOVERESIZE) ))
699     {
700         TRACE( "_NET_WM_MOVERESIZE not supported\n" );
701         return FALSE;
702     }
703
704     if (syscommand == SC_MOVE)
705     {
706         if (!hittest) dir = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
707         else dir = _NET_WM_MOVERESIZE_MOVE;
708     }
709     else
710     {
711         /* windows without WS_THICKFRAME are not resizable through the window manager */
712         if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_THICKFRAME)) return FALSE;
713
714         switch (hittest)
715         {
716         case WMSZ_LEFT:        dir = _NET_WM_MOVERESIZE_SIZE_LEFT; break;
717         case WMSZ_RIGHT:       dir = _NET_WM_MOVERESIZE_SIZE_RIGHT; break;
718         case WMSZ_TOP:         dir = _NET_WM_MOVERESIZE_SIZE_TOP; break;
719         case WMSZ_TOPLEFT:     dir = _NET_WM_MOVERESIZE_SIZE_TOPLEFT; break;
720         case WMSZ_TOPRIGHT:    dir = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT; break;
721         case WMSZ_BOTTOM:      dir = _NET_WM_MOVERESIZE_SIZE_BOTTOM; break;
722         case WMSZ_BOTTOMLEFT:  dir = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; break;
723         case WMSZ_BOTTOMRIGHT: dir = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; break;
724         default:               dir = _NET_WM_MOVERESIZE_SIZE_KEYBOARD; break;
725         }
726     }
727
728     dwPoint = GetMessagePos();
729     x = (short)LOWORD(dwPoint);
730     y = (short)HIWORD(dwPoint);
731
732     TRACE("hwnd %p, x %d, y %d, dir %d\n", hwnd, x, y, dir);
733
734     xev.xclient.type = ClientMessage;
735     xev.xclient.window = X11DRV_get_whole_window(hwnd);
736     xev.xclient.message_type = x11drv_atom(_NET_WM_MOVERESIZE);
737     xev.xclient.serial = 0;
738     xev.xclient.display = display;
739     xev.xclient.send_event = True;
740     xev.xclient.format = 32;
741     xev.xclient.data.l[0] = x; /* x coord */
742     xev.xclient.data.l[1] = y; /* y coord */
743     xev.xclient.data.l[2] = dir; /* direction */
744     xev.xclient.data.l[3] = 1; /* button */
745     xev.xclient.data.l[4] = 0; /* unused */
746
747     /* need to ungrab the pointer that may have been automatically grabbed
748      * with a ButtonPress event */
749     wine_tsx11_lock();
750     XUngrabPointer( display, CurrentTime );
751     XSendEvent(display, root_window, False, SubstructureNotifyMask, &xev);
752     wine_tsx11_unlock();
753     return TRUE;
754 }