winex11: Don't attempt to dock into the system tray in desktop mode.
[wine.git] / dlls / winex11.drv / winpos.c
blobad62236a6710c13fedbc8b5ce09e23c788284aa2
1 /*
2 * Window position related functions.
4 * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
5 * Copyright 1995, 1996, 1999 Alex Korobka
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <stdarg.h>
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"
35 #include "x11drv.h"
37 #include "wine/server.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
42 #define SWP_AGG_NOPOSCHANGE \
43 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
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 */
57 #define _NET_WM_STATE_REMOVE 0
58 #define _NET_WM_STATE_ADD 1
59 #define _NET_WM_STATE_TOGGLE 2
61 static const char managed_prop[] = "__wine_x11_managed";
63 /***********************************************************************
64 * X11DRV_Expose
66 void X11DRV_Expose( HWND hwnd, XEvent *xev )
68 XExposeEvent *event = &xev->xexpose;
69 RECT rect;
70 struct x11drv_win_data *data;
71 int flags = RDW_INVALIDATE | RDW_ERASE;
73 TRACE( "win %p (%lx) %d,%d %dx%d\n",
74 hwnd, event->window, event->x, event->y, event->width, event->height );
76 if (!(data = X11DRV_get_win_data( hwnd ))) return;
78 if (event->window == data->whole_window)
80 rect.left = data->whole_rect.left + event->x;
81 rect.top = data->whole_rect.top + event->y;
82 flags |= RDW_FRAME;
84 else
86 rect.left = data->client_rect.left + event->x;
87 rect.top = data->client_rect.top + event->y;
89 rect.right = rect.left + event->width;
90 rect.bottom = rect.top + event->height;
92 if (event->window != root_window)
94 SERVER_START_REQ( update_window_zorder )
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 );
103 SERVER_END_REQ;
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;
110 RedrawWindow( hwnd, &rect, 0, flags );
113 /***********************************************************************
114 * SetWindowStyle (X11DRV.@)
116 * Update the X state of a window to reflect a style change
118 void X11DRV_SetWindowStyle( HWND hwnd, DWORD old_style )
120 Display *display = thread_display();
121 struct x11drv_win_data *data;
122 DWORD new_style, changed;
124 if (hwnd == GetDesktopWindow()) return;
125 new_style = GetWindowLongW( hwnd, GWL_STYLE );
126 changed = new_style ^ old_style;
128 if ((changed & WS_VISIBLE) && (new_style & WS_VISIBLE))
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;
134 if (data->whole_window && X11DRV_is_window_rect_mapped( &data->window_rect ))
136 X11DRV_set_wm_hints( display, data );
137 if (!data->mapped)
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;
151 if (changed & WS_DISABLED)
153 data = X11DRV_get_win_data( hwnd );
154 if (data && data->wm_hints)
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();
165 /***********************************************************************
166 * update_net_wm_states
168 static void update_net_wm_states( Display *display, struct x11drv_win_data *data )
170 static const unsigned int state_atoms[NB_NET_WM_STATES] =
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
179 DWORD i, style, ex_style, new_state = 0;
180 XEvent xev;
182 if (!data->managed) return;
183 if (!data->mapped) return;
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)
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);
194 else if (style & WS_MAXIMIZE)
195 new_state |= (1 << NET_WM_STATE_MAXIMIZED);
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);
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;
214 for (i = 0; i < NB_NET_WM_STATES; i++)
216 if (!((data->net_wm_state ^ new_state) & (1 << i))) continue; /* unchanged */
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 );
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();
230 data->net_wm_state = new_state;
234 /***********************************************************************
235 * move_window_bits
237 * Move the window bits when a window is moved.
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 )
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;
249 if (!data->whole_window)
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 );
256 else
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 );
265 code = X11DRV_START_EXPOSURES;
266 ExtEscape( hdc_dst, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
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 );
275 code = X11DRV_END_EXPOSURES;
276 ExtEscape( hdc_dst, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, sizeof(rgn), (LPSTR)&rgn );
278 ReleaseDC( data->hwnd, hdc_dst );
279 if (hdc_src != hdc_dst) ReleaseDC( parent, hdc_src );
281 if (rgn)
283 if (!data->whole_window)
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 );
291 else RedrawWindow( data->hwnd, NULL, rgn, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
292 DeleteObject( rgn );
296 /***********************************************************************
297 * SetWindowPos (X11DRV.@)
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 )
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;
308 if (!data)
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;
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 ))
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)
323 wine_tsx11_lock();
324 XUnmapWindow( display, data->whole_window );
325 wine_tsx11_unlock();
326 data->mapped = FALSE;
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) ))
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 )
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 );
351 SERVER_END_REQ;
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 );
357 if (!IsRectEmpty( &valid_rects[0] ))
359 int x_offset = old_whole_rect.left - data->whole_rect.left;
360 int y_offset = old_whole_rect.top - data->whole_rect.top;
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) ))
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 );
376 else
377 move_window_bits( data, &valid_rects[1], &valid_rects[0], &old_client_rect );
380 X11DRV_sync_client_position( display, data, swp_flags, &old_client_rect, &old_whole_rect );
382 if (!data->whole_window || data->lock_changes) return; /* nothing more to do */
384 if (data->mapped && (!(new_style & WS_VISIBLE) || !X11DRV_is_window_rect_mapped( rectWindow )))
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;
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 );
400 if ((new_style & WS_VISIBLE) &&
401 ((new_style & WS_MINIMIZE) || X11DRV_is_window_rect_mapped( rectWindow )))
403 if (!data->mapped || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
404 X11DRV_set_wm_hints( display, data );
406 if (!data->mapped)
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;
418 else if ((swp_flags & SWP_STATECHANGED) && (!data->iconic != !(new_style & WS_MINIMIZE)))
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();
429 update_net_wm_states( display, data );
434 /**********************************************************************
435 * X11DRV_MapNotify
437 void X11DRV_MapNotify( HWND hwnd, XEvent *event )
439 struct x11drv_win_data *data;
440 int state;
442 if (!(data = X11DRV_get_win_data( hwnd ))) return;
443 if (!data->mapped) return;
445 if (!data->managed)
447 HWND hwndFocus = GetFocus();
448 if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus); /* FIXME */
449 return;
451 if (!data->iconic) return;
453 state = get_window_wm_state( event->xmap.display, data );
454 if (state == NormalState)
456 int x, y;
457 unsigned int width, height, border, depth;
458 Window root, top;
459 WINDOWPLACEMENT wp;
460 RECT rect;
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 );
475 wp.length = sizeof(wp);
476 GetWindowPlacement( hwnd, &wp );
477 wp.flags = 0;
478 wp.showCmd = SW_RESTORE;
479 wp.rcNormalPosition = rect;
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--;
487 else TRACE( "win %p/%lx ignoring since state=%d\n", hwnd, data->whole_window, state );
491 /**********************************************************************
492 * X11DRV_UnmapNotify
494 void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
496 struct x11drv_win_data *data;
497 int state;
499 if (!(data = X11DRV_get_win_data( hwnd ))) return;
500 if (!data->managed || !data->mapped || data->iconic) return;
502 state = get_window_wm_state( event->xunmap.display, data );
503 if (state == IconicState)
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--;
511 else TRACE( "win %p/%lx ignoring since state=%d\n", hwnd, data->whole_window, state );
514 struct desktop_resize_data
516 RECT old_screen_rect;
517 RECT old_virtual_rect;
520 static BOOL CALLBACK update_windows_on_desktop_resize( HWND hwnd, LPARAM lparam )
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;
527 if (!(data = X11DRV_get_win_data( hwnd ))) return TRUE;
529 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
531 /* update the full screen state */
532 update_net_wm_states( display, data );
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)
539 XWindowChanges changes;
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();
548 return TRUE;
552 /***********************************************************************
553 * X11DRV_resize_desktop
555 void X11DRV_resize_desktop( unsigned int width, unsigned int height )
557 HWND hwnd = GetDesktopWindow();
558 struct desktop_resize_data resize_data;
560 SetRect( &resize_data.old_screen_rect, 0, 0, screen_width, screen_height );
561 resize_data.old_virtual_rect = virtual_screen_rect;
563 xinerama_init( width, height );
565 if (GetWindowThreadProcessId( hwnd, NULL ) != GetCurrentThreadId())
567 SendMessageW( hwnd, WM_X11DRV_RESIZE_DESKTOP, 0, MAKELPARAM( width, height ) );
569 else
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 );
580 EnumWindows( update_windows_on_desktop_resize, (LPARAM)&resize_data );
584 /***********************************************************************
585 * X11DRV_ConfigureNotify
587 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
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;
595 if (!hwnd) return;
596 if (!(data = X11DRV_get_win_data( hwnd ))) return;
598 /* Get geometry */
600 if (!event->send_event) /* normal event, need to map coordinates to the root */
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();
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 );
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;
624 /* Compare what has changed */
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 );
632 if ((rect.right - rect.left == cx && rect.bottom - rect.top == cy) ||
633 IsIconic(hwnd) ||
634 (IsRectEmpty( &rect ) && event->width == 1 && event->height == 1))
636 if (flags & SWP_NOMOVE) return; /* if nothing changed, don't do anything */
637 flags |= SWP_NOSIZE;
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 );
643 data->lock_changes++;
644 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
645 data->lock_changes--;
649 /***********************************************************************
650 * is_netwm_supported
652 static BOOL is_netwm_supported( Display *display, Atom atom )
654 static Atom *net_supported;
655 static int net_supported_count = -1;
656 int i;
658 wine_tsx11_lock();
659 if (net_supported_count == -1)
661 Atom type;
662 int format;
663 unsigned long count, remaining;
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;
672 wine_tsx11_unlock();
674 for (i = 0; i < net_supported_count; i++)
675 if (net_supported[i] == atom) return TRUE;
676 return FALSE;
680 /***********************************************************************
681 * SysCommandSizeMove (X11DRV.@)
683 * Perform SC_MOVE and SC_SIZE commands.
685 BOOL X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wparam )
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;
695 if (!(data = X11DRV_get_win_data( hwnd ))) return FALSE;
696 if (!data->whole_window || !data->managed) return FALSE;
698 if (!is_netwm_supported( display, x11drv_atom(_NET_WM_MOVERESIZE) ))
700 TRACE( "_NET_WM_MOVERESIZE not supported\n" );
701 return FALSE;
704 if (syscommand == SC_MOVE)
706 if (!hittest) dir = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
707 else dir = _NET_WM_MOVERESIZE_MOVE;
709 else
711 /* windows without WS_THICKFRAME are not resizable through the window manager */
712 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_THICKFRAME)) return FALSE;
714 switch (hittest)
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;
728 dwPoint = GetMessagePos();
729 x = (short)LOWORD(dwPoint);
730 y = (short)HIWORD(dwPoint);
732 TRACE("hwnd %p, x %d, y %d, dir %d\n", hwnd, x, y, dir);
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 */
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;