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
25 #include <X11/Xutil.h>
33 #include "wine/wingdi16.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 /***********************************************************************
66 void X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
68 XExposeEvent
*event
= &xev
->xexpose
;
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
;
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
)
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
);
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
);
114 /***********************************************************************
115 * update_net_wm_states
117 static void update_net_wm_states( Display
*display
, struct x11drv_win_data
*data
)
119 static const unsigned int state_atoms
[NB_NET_WM_STATES
] =
121 XATOM__NET_WM_STATE_FULLSCREEN
,
122 XATOM__NET_WM_STATE_ABOVE
,
123 XATOM__NET_WM_STATE_MAXIMIZED_VERT
,
124 XATOM__NET_WM_STATE_SKIP_PAGER
,
125 XATOM__NET_WM_STATE_SKIP_TASKBAR
128 DWORD i
, style
, ex_style
, new_state
= 0;
130 if (!data
->managed
) return;
131 if (data
->whole_window
== root_window
) return;
133 style
= GetWindowLongW( data
->hwnd
, GWL_STYLE
);
134 if (data
->whole_rect
.left
<= 0 && data
->whole_rect
.right
>= screen_width
&&
135 data
->whole_rect
.top
<= 0 && data
->whole_rect
.bottom
>= screen_height
)
137 if ((style
& WS_MAXIMIZE
) && (style
& WS_CAPTION
) == WS_CAPTION
)
138 new_state
|= (1 << NET_WM_STATE_MAXIMIZED
);
140 new_state
|= (1 << NET_WM_STATE_FULLSCREEN
);
142 else if (style
& WS_MAXIMIZE
)
143 new_state
|= (1 << NET_WM_STATE_MAXIMIZED
);
145 ex_style
= GetWindowLongW( data
->hwnd
, GWL_EXSTYLE
);
146 if (ex_style
& WS_EX_TOPMOST
)
147 new_state
|= (1 << NET_WM_STATE_ABOVE
);
148 if (ex_style
& WS_EX_TOOLWINDOW
)
149 new_state
|= (1 << NET_WM_STATE_SKIP_TASKBAR
) | (1 << NET_WM_STATE_SKIP_PAGER
);
150 if (!(ex_style
& WS_EX_APPWINDOW
) && GetWindow( data
->hwnd
, GW_OWNER
))
151 new_state
|= (1 << NET_WM_STATE_SKIP_TASKBAR
);
153 if (!data
->mapped
) /* set the _NET_WM_STATE atom directly */
155 Atom atoms
[NB_NET_WM_STATES
+1];
158 for (i
= count
= 0; i
< NB_NET_WM_STATES
; i
++)
160 if (!(new_state
& (1 << i
))) continue;
161 TRACE( "setting wm state %u for unmapped window %p/%lx\n",
162 i
, data
->hwnd
, data
->whole_window
);
163 atoms
[count
++] = X11DRV_Atoms
[state_atoms
[i
] - FIRST_XATOM
];
164 if (state_atoms
[i
] == XATOM__NET_WM_STATE_MAXIMIZED_VERT
)
165 atoms
[count
++] = x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ
);
168 XChangeProperty( display
, data
->whole_window
, x11drv_atom(_NET_WM_STATE
), XA_ATOM
,
169 32, PropModeReplace
, (unsigned char *)atoms
, count
);
172 else /* ask the window manager to do it for us */
176 xev
.xclient
.type
= ClientMessage
;
177 xev
.xclient
.window
= data
->whole_window
;
178 xev
.xclient
.message_type
= x11drv_atom(_NET_WM_STATE
);
179 xev
.xclient
.serial
= 0;
180 xev
.xclient
.display
= display
;
181 xev
.xclient
.send_event
= True
;
182 xev
.xclient
.format
= 32;
183 xev
.xclient
.data
.l
[3] = 1;
185 for (i
= 0; i
< NB_NET_WM_STATES
; i
++)
187 if (!((data
->net_wm_state
^ new_state
) & (1 << i
))) continue; /* unchanged */
189 TRACE( "setting wm state %u for window %p/%lx to %u prev %u\n",
190 i
, data
->hwnd
, data
->whole_window
,
191 (new_state
& (1 << i
)) != 0, (data
->net_wm_state
& (1 << i
)) != 0 );
193 xev
.xclient
.data
.l
[0] = (new_state
& (1 << i
)) ? _NET_WM_STATE_ADD
: _NET_WM_STATE_REMOVE
;
194 xev
.xclient
.data
.l
[1] = X11DRV_Atoms
[state_atoms
[i
] - FIRST_XATOM
];
195 xev
.xclient
.data
.l
[2] = ((state_atoms
[i
] == XATOM__NET_WM_STATE_MAXIMIZED_VERT
) ?
196 x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ
) : 0);
198 XSendEvent( display
, root_window
, False
,
199 SubstructureRedirectMask
| SubstructureNotifyMask
, &xev
);
203 data
->net_wm_state
= new_state
;
207 /***********************************************************************
210 static void set_xembed_flags( Display
*display
, struct x11drv_win_data
*data
, unsigned long flags
)
212 unsigned long info
[2];
214 info
[0] = 0; /* protocol version */
217 XChangeProperty( display
, data
->whole_window
, x11drv_atom(_XEMBED_INFO
),
218 x11drv_atom(_XEMBED_INFO
), 32, PropModeReplace
, (unsigned char*)info
, 2 );
223 /***********************************************************************
226 static void map_window( Display
*display
, struct x11drv_win_data
*data
, DWORD new_style
)
228 TRACE( "win %p/%lx\n", data
->hwnd
, data
->whole_window
);
230 wait_for_withdrawn_state( display
, data
, TRUE
);
234 update_net_wm_states( display
, data
);
235 X11DRV_sync_window_style( display
, data
);
237 XMapWindow( display
, data
->whole_window
);
240 else set_xembed_flags( display
, data
, XEMBED_MAPPED
);
243 data
->iconic
= (new_style
& WS_MINIMIZE
) != 0;
247 /***********************************************************************
250 static void unmap_window( Display
*display
, struct x11drv_win_data
*data
)
252 TRACE( "win %p/%lx\n", data
->hwnd
, data
->whole_window
);
256 wait_for_withdrawn_state( display
, data
, FALSE
);
258 if (data
->managed
) XWithdrawWindow( display
, data
->whole_window
, DefaultScreen(display
) );
259 else XUnmapWindow( display
, data
->whole_window
);
262 else set_xembed_flags( display
, data
, 0 );
264 data
->mapped
= FALSE
;
265 data
->net_wm_state
= 0;
269 /***********************************************************************
270 * make_window_embedded
272 void make_window_embedded( Display
*display
, struct x11drv_win_data
*data
)
276 /* the window cannot be mapped before being embedded */
277 unmap_window( display
, data
);
278 data
->embedded
= TRUE
;
279 map_window( display
, data
, 0 );
283 data
->embedded
= TRUE
;
284 set_xembed_flags( display
, data
, 0 );
289 /***********************************************************************
290 * SetWindowStyle (X11DRV.@)
292 * Update the X state of a window to reflect a style change
294 void X11DRV_SetWindowStyle( HWND hwnd
, DWORD old_style
)
296 Display
*display
= thread_display();
297 struct x11drv_win_data
*data
;
298 DWORD new_style
, changed
;
300 if (hwnd
== GetDesktopWindow()) return;
301 new_style
= GetWindowLongW( hwnd
, GWL_STYLE
);
302 changed
= new_style
^ old_style
;
304 if ((changed
& WS_VISIBLE
) && (new_style
& WS_VISIBLE
))
306 /* we don't unmap windows, that causes trouble with the window manager */
307 if (!(data
= X11DRV_get_win_data( hwnd
)) &&
308 !(data
= X11DRV_create_win_data( hwnd
))) return;
310 if (data
->whole_window
&& X11DRV_is_window_rect_mapped( &data
->window_rect
))
312 X11DRV_set_wm_hints( display
, data
);
313 if (!data
->mapped
) map_window( display
, data
, new_style
);
317 if (changed
& WS_DISABLED
)
319 data
= X11DRV_get_win_data( hwnd
);
320 if (data
&& data
->wm_hints
)
323 data
->wm_hints
->input
= !(new_style
& WS_DISABLED
);
324 XSetWMHints( display
, data
->whole_window
, data
->wm_hints
);
331 /***********************************************************************
334 * Move the window bits when a window is moved.
336 static void move_window_bits( struct x11drv_win_data
*data
, const RECT
*old_rect
, const RECT
*new_rect
,
337 const RECT
*old_client_rect
)
339 RECT src_rect
= *old_rect
;
340 RECT dst_rect
= *new_rect
;
341 HDC hdc_src
, hdc_dst
;
346 if (!data
->whole_window
)
348 OffsetRect( &dst_rect
, -data
->window_rect
.left
, -data
->window_rect
.top
);
349 parent
= GetAncestor( data
->hwnd
, GA_PARENT
);
350 hdc_src
= GetDCEx( parent
, 0, DCX_CACHE
);
351 hdc_dst
= GetDCEx( data
->hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
355 OffsetRect( &dst_rect
, -data
->client_rect
.left
, -data
->client_rect
.top
);
356 /* make src rect relative to the old position of the window */
357 OffsetRect( &src_rect
, -old_client_rect
->left
, -old_client_rect
->top
);
358 if (dst_rect
.left
== src_rect
.left
&& dst_rect
.top
== src_rect
.top
) return;
359 hdc_src
= hdc_dst
= GetDCEx( data
->hwnd
, 0, DCX_CACHE
);
362 code
= X11DRV_START_EXPOSURES
;
363 ExtEscape( hdc_dst
, X11DRV_ESCAPE
, sizeof(code
), (LPSTR
)&code
, 0, NULL
);
365 TRACE( "copying bits for win %p/%lx/%lx %s -> %s\n",
366 data
->hwnd
, data
->whole_window
, data
->client_window
,
367 wine_dbgstr_rect(&src_rect
), wine_dbgstr_rect(&dst_rect
) );
368 BitBlt( hdc_dst
, dst_rect
.left
, dst_rect
.top
,
369 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
,
370 hdc_src
, src_rect
.left
, src_rect
.top
, SRCCOPY
);
372 code
= X11DRV_END_EXPOSURES
;
373 ExtEscape( hdc_dst
, X11DRV_ESCAPE
, sizeof(code
), (LPSTR
)&code
, sizeof(rgn
), (LPSTR
)&rgn
);
375 ReleaseDC( data
->hwnd
, hdc_dst
);
376 if (hdc_src
!= hdc_dst
) ReleaseDC( parent
, hdc_src
);
380 if (!data
->whole_window
)
382 /* map region to client rect since we are using DCX_WINDOW */
383 OffsetRgn( rgn
, data
->window_rect
.left
- data
->client_rect
.left
,
384 data
->window_rect
.top
- data
->client_rect
.top
);
385 RedrawWindow( data
->hwnd
, NULL
, rgn
,
386 RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ALLCHILDREN
);
388 else RedrawWindow( data
->hwnd
, NULL
, rgn
, RDW_INVALIDATE
| RDW_ERASE
| RDW_ALLCHILDREN
);
393 /***********************************************************************
394 * SetWindowPos (X11DRV.@)
396 void X11DRV_SetWindowPos( HWND hwnd
, HWND insert_after
, UINT swp_flags
,
397 const RECT
*rectWindow
, const RECT
*rectClient
,
398 const RECT
*visible_rect
, const RECT
*valid_rects
)
400 struct x11drv_thread_data
*thread_data
= x11drv_thread_data();
401 Display
*display
= thread_data
->display
;
402 struct x11drv_win_data
*data
= X11DRV_get_win_data( hwnd
);
403 DWORD new_style
= GetWindowLongW( hwnd
, GWL_STYLE
);
404 RECT old_window_rect
, old_whole_rect
, old_client_rect
;
409 /* create the win data if the window is being made visible */
410 if (!(new_style
& WS_VISIBLE
)) return;
411 if (!(data
= X11DRV_create_win_data( hwnd
))) return;
414 /* check if we need to switch the window to managed */
415 if (!data
->managed
&& data
->whole_window
&& is_window_managed( hwnd
, swp_flags
, rectWindow
))
417 TRACE( "making win %p/%lx managed\n", hwnd
, data
->whole_window
);
418 if (data
->mapped
) unmap_window( display
, data
);
419 data
->managed
= TRUE
;
420 SetPropA( hwnd
, managed_prop
, (HANDLE
)1 );
423 old_window_rect
= data
->window_rect
;
424 old_whole_rect
= data
->whole_rect
;
425 old_client_rect
= data
->client_rect
;
426 data
->window_rect
= *rectWindow
;
427 data
->whole_rect
= *rectWindow
;
428 data
->client_rect
= *rectClient
;
429 X11DRV_window_to_X_rect( data
, &data
->whole_rect
);
430 if (memcmp( visible_rect
, &data
->whole_rect
, sizeof(RECT
) ))
432 TRACE( "%p: need to update visible rect %s -> %s\n", hwnd
,
433 wine_dbgstr_rect(visible_rect
), wine_dbgstr_rect(&data
->whole_rect
) );
434 SERVER_START_REQ( set_window_visible_rect
)
437 req
->flags
= swp_flags
;
438 req
->visible
.left
= data
->whole_rect
.left
;
439 req
->visible
.top
= data
->whole_rect
.top
;
440 req
->visible
.right
= data
->whole_rect
.right
;
441 req
->visible
.bottom
= data
->whole_rect
.bottom
;
442 wine_server_call( req
);
447 TRACE( "win %p window %s client %s style %08x flags %08x\n",
448 hwnd
, wine_dbgstr_rect(rectWindow
), wine_dbgstr_rect(rectClient
), new_style
, swp_flags
);
450 if (!IsRectEmpty( &valid_rects
[0] ))
452 int x_offset
= old_whole_rect
.left
- data
->whole_rect
.left
;
453 int y_offset
= old_whole_rect
.top
- data
->whole_rect
.top
;
455 /* if all that happened is that the whole window moved, copy everything */
456 if (!(swp_flags
& SWP_FRAMECHANGED
) &&
457 old_whole_rect
.right
- data
->whole_rect
.right
== x_offset
&&
458 old_whole_rect
.bottom
- data
->whole_rect
.bottom
== y_offset
&&
459 old_client_rect
.left
- data
->client_rect
.left
== x_offset
&&
460 old_client_rect
.right
- data
->client_rect
.right
== x_offset
&&
461 old_client_rect
.top
- data
->client_rect
.top
== y_offset
&&
462 old_client_rect
.bottom
- data
->client_rect
.bottom
== y_offset
&&
463 !memcmp( &valid_rects
[0], &data
->client_rect
, sizeof(RECT
) ))
465 /* if we have an X window the bits will be moved by the X server */
466 if (!data
->whole_window
)
467 move_window_bits( data
, &old_whole_rect
, &data
->whole_rect
, &old_client_rect
);
470 move_window_bits( data
, &valid_rects
[1], &valid_rects
[0], &old_client_rect
);
474 XFlush( gdi_display
); /* make sure painting is done before we move the window */
477 X11DRV_sync_client_position( display
, data
, swp_flags
, &old_client_rect
, &old_whole_rect
);
479 if (!data
->whole_window
) return;
481 /* check if we are currently processing an event relevant to this window */
483 if (thread_data
->current_event
&& thread_data
->current_event
->xany
.window
== data
->whole_window
)
484 event_type
= thread_data
->current_event
->type
;
486 if (event_type
!= ConfigureNotify
&& event_type
!= PropertyNotify
)
487 event_type
= 0; /* ignore other events */
489 if (data
->mapped
&& (!(new_style
& WS_VISIBLE
) ||
490 (!event_type
&& !X11DRV_is_window_rect_mapped( rectWindow
))))
491 unmap_window( display
, data
);
493 /* don't change position if we are about to minimize or maximize a managed window */
495 !(data
->managed
&& (swp_flags
& SWP_STATECHANGED
) && (new_style
& (WS_MINIMIZE
|WS_MAXIMIZE
))))
496 X11DRV_sync_window_position( display
, data
, swp_flags
, &old_client_rect
, &old_whole_rect
);
498 if ((new_style
& WS_VISIBLE
) &&
499 ((new_style
& WS_MINIMIZE
) || X11DRV_is_window_rect_mapped( rectWindow
)))
501 if (!data
->mapped
|| (swp_flags
& (SWP_FRAMECHANGED
|SWP_STATECHANGED
)))
502 X11DRV_set_wm_hints( display
, data
);
506 map_window( display
, data
, new_style
);
508 else if ((swp_flags
& SWP_STATECHANGED
) && (!data
->iconic
!= !(new_style
& WS_MINIMIZE
)))
510 data
->iconic
= (new_style
& WS_MINIMIZE
) != 0;
511 TRACE( "changing win %p iconic state to %u\n", data
->hwnd
, data
->iconic
);
514 XIconifyWindow( display
, data
->whole_window
, DefaultScreen(display
) );
515 else if (X11DRV_is_window_rect_mapped( rectWindow
))
516 XMapWindow( display
, data
->whole_window
);
518 update_net_wm_states( display
, data
);
520 else if (!event_type
)
522 update_net_wm_states( display
, data
);
527 XFlush( display
); /* make sure changes are done before we start painting again */
532 /**********************************************************************
535 void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
537 struct x11drv_win_data
*data
;
539 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
540 if (!data
->mapped
) return;
544 HWND hwndFocus
= GetFocus();
545 if (hwndFocus
&& IsChild( hwnd
, hwndFocus
)) X11DRV_SetFocus(hwndFocus
); /* FIXME */
550 struct desktop_resize_data
552 RECT old_screen_rect
;
553 RECT old_virtual_rect
;
556 static BOOL CALLBACK
update_windows_on_desktop_resize( HWND hwnd
, LPARAM lparam
)
558 struct x11drv_win_data
*data
;
559 Display
*display
= thread_display();
560 struct desktop_resize_data
*resize_data
= (struct desktop_resize_data
*)lparam
;
563 if (!(data
= X11DRV_get_win_data( hwnd
))) return TRUE
;
565 if (GetWindowLongW( hwnd
, GWL_STYLE
) & WS_VISIBLE
)
567 /* update the full screen state */
568 update_net_wm_states( display
, data
);
571 if (resize_data
->old_virtual_rect
.left
!= virtual_screen_rect
.left
) mask
|= CWX
;
572 if (resize_data
->old_virtual_rect
.top
!= virtual_screen_rect
.top
) mask
|= CWY
;
573 if (mask
&& data
->whole_window
)
575 XWindowChanges changes
;
578 changes
.x
= data
->whole_rect
.left
- virtual_screen_rect
.left
;
579 changes
.y
= data
->whole_rect
.top
- virtual_screen_rect
.top
;
580 XReconfigureWMWindow( display
, data
->whole_window
,
581 DefaultScreen(display
), mask
, &changes
);
588 /***********************************************************************
589 * X11DRV_resize_desktop
591 void X11DRV_resize_desktop( unsigned int width
, unsigned int height
)
593 HWND hwnd
= GetDesktopWindow();
594 struct desktop_resize_data resize_data
;
596 SetRect( &resize_data
.old_screen_rect
, 0, 0, screen_width
, screen_height
);
597 resize_data
.old_virtual_rect
= virtual_screen_rect
;
599 xinerama_init( width
, height
);
601 if (GetWindowThreadProcessId( hwnd
, NULL
) != GetCurrentThreadId())
603 SendMessageW( hwnd
, WM_X11DRV_RESIZE_DESKTOP
, 0, MAKELPARAM( width
, height
) );
607 TRACE( "desktop %p change to (%dx%d)\n", hwnd
, width
, height
);
608 SetWindowPos( hwnd
, 0, virtual_screen_rect
.left
, virtual_screen_rect
.top
,
609 virtual_screen_rect
.right
- virtual_screen_rect
.left
,
610 virtual_screen_rect
.bottom
- virtual_screen_rect
.top
,
611 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_DEFERERASE
);
612 SendMessageTimeoutW( HWND_BROADCAST
, WM_DISPLAYCHANGE
, screen_bpp
,
613 MAKELPARAM( width
, height
), SMTO_ABORTIFHUNG
, 2000, NULL
);
616 EnumWindows( update_windows_on_desktop_resize
, (LPARAM
)&resize_data
);
620 /***********************************************************************
621 * X11DRV_ConfigureNotify
623 void X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
625 XConfigureEvent
*event
= &xev
->xconfigure
;
626 struct x11drv_win_data
*data
;
629 int cx
, cy
, x
= event
->x
, y
= event
->y
;
632 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
633 if (!data
->mapped
|| data
->iconic
) return;
637 if (!event
->send_event
) /* normal event, need to map coordinates to the root */
641 XTranslateCoordinates( event
->display
, data
->whole_window
, root_window
,
642 0, 0, &x
, &y
, &child
);
647 rect
.right
= x
+ event
->width
;
648 rect
.bottom
= y
+ event
->height
;
649 OffsetRect( &rect
, virtual_screen_rect
.left
, virtual_screen_rect
.top
);
650 TRACE( "win %p new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
651 hwnd
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
652 event
->x
, event
->y
, event
->width
, event
->height
);
653 X11DRV_X_to_window_rect( data
, &rect
);
657 cx
= rect
.right
- rect
.left
;
658 cy
= rect
.bottom
- rect
.top
;
659 flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
661 /* Compare what has changed */
663 GetWindowRect( hwnd
, &rect
);
664 if (rect
.left
== x
&& rect
.top
== y
) flags
|= SWP_NOMOVE
;
666 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
667 hwnd
, rect
.left
, rect
.top
, x
, y
);
669 if ((rect
.right
- rect
.left
== cx
&& rect
.bottom
- rect
.top
== cy
) ||
670 (IsRectEmpty( &rect
) && event
->width
== 1 && event
->height
== 1))
672 if (flags
& SWP_NOMOVE
) return; /* if nothing changed, don't do anything */
676 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
677 hwnd
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, cx
, cy
);
679 SetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
683 /***********************************************************************
686 static BOOL
is_netwm_supported( Display
*display
, Atom atom
)
688 static Atom
*net_supported
;
689 static int net_supported_count
= -1;
693 if (net_supported_count
== -1)
697 unsigned long count
, remaining
;
699 if (!XGetWindowProperty( display
, DefaultRootWindow(display
), x11drv_atom(_NET_SUPPORTED
), 0,
700 ~0UL, False
, XA_ATOM
, &type
, &format
, &count
,
701 &remaining
, (unsigned char **)&net_supported
))
702 net_supported_count
= get_property_size( format
, count
) / sizeof(Atom
);
704 net_supported_count
= 0;
708 for (i
= 0; i
< net_supported_count
; i
++)
709 if (net_supported
[i
] == atom
) return TRUE
;
714 /***********************************************************************
715 * SysCommandSizeMove (X11DRV.@)
717 * Perform SC_MOVE and SC_SIZE commands.
719 BOOL
X11DRV_SysCommandSizeMove( HWND hwnd
, WPARAM wparam
)
721 WPARAM syscommand
= wparam
& 0xfff0;
722 WPARAM hittest
= wparam
& 0x0f;
726 Display
*display
= thread_display();
727 struct x11drv_win_data
*data
;
729 if (!(data
= X11DRV_get_win_data( hwnd
))) return FALSE
;
730 if (!data
->whole_window
|| !data
->managed
) return FALSE
;
732 if (!is_netwm_supported( display
, x11drv_atom(_NET_WM_MOVERESIZE
) ))
734 TRACE( "_NET_WM_MOVERESIZE not supported\n" );
738 if (syscommand
== SC_MOVE
)
740 if (!hittest
) dir
= _NET_WM_MOVERESIZE_MOVE_KEYBOARD
;
741 else dir
= _NET_WM_MOVERESIZE_MOVE
;
745 /* windows without WS_THICKFRAME are not resizable through the window manager */
746 if (!(GetWindowLongW( hwnd
, GWL_STYLE
) & WS_THICKFRAME
)) return FALSE
;
750 case WMSZ_LEFT
: dir
= _NET_WM_MOVERESIZE_SIZE_LEFT
; break;
751 case WMSZ_RIGHT
: dir
= _NET_WM_MOVERESIZE_SIZE_RIGHT
; break;
752 case WMSZ_TOP
: dir
= _NET_WM_MOVERESIZE_SIZE_TOP
; break;
753 case WMSZ_TOPLEFT
: dir
= _NET_WM_MOVERESIZE_SIZE_TOPLEFT
; break;
754 case WMSZ_TOPRIGHT
: dir
= _NET_WM_MOVERESIZE_SIZE_TOPRIGHT
; break;
755 case WMSZ_BOTTOM
: dir
= _NET_WM_MOVERESIZE_SIZE_BOTTOM
; break;
756 case WMSZ_BOTTOMLEFT
: dir
= _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
; break;
757 case WMSZ_BOTTOMRIGHT
: dir
= _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
; break;
758 default: dir
= _NET_WM_MOVERESIZE_SIZE_KEYBOARD
; break;
762 dwPoint
= GetMessagePos();
763 x
= (short)LOWORD(dwPoint
);
764 y
= (short)HIWORD(dwPoint
);
766 TRACE("hwnd %p, x %d, y %d, dir %d\n", hwnd
, x
, y
, dir
);
768 xev
.xclient
.type
= ClientMessage
;
769 xev
.xclient
.window
= X11DRV_get_whole_window(hwnd
);
770 xev
.xclient
.message_type
= x11drv_atom(_NET_WM_MOVERESIZE
);
771 xev
.xclient
.serial
= 0;
772 xev
.xclient
.display
= display
;
773 xev
.xclient
.send_event
= True
;
774 xev
.xclient
.format
= 32;
775 xev
.xclient
.data
.l
[0] = x
; /* x coord */
776 xev
.xclient
.data
.l
[1] = y
; /* y coord */
777 xev
.xclient
.data
.l
[2] = dir
; /* direction */
778 xev
.xclient
.data
.l
[3] = 1; /* button */
779 xev
.xclient
.data
.l
[4] = 0; /* unused */
781 /* need to ungrab the pointer that may have been automatically grabbed
782 * with a ButtonPress event */
784 XUngrabPointer( display
, CurrentTime
);
785 XSendEvent(display
, root_window
, False
, SubstructureNotifyMask
, &xev
);