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 SWP_EX_NOCOPY 0x0001
46 #define SWP_EX_PAINTSELF 0x0002
47 #define SWP_EX_NONCLIENT 0x0004
49 #define HAS_THICKFRAME(style) \
50 (((style) & WS_THICKFRAME) && \
51 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
53 #define ON_LEFT_BORDER(hit) \
54 (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
55 #define ON_RIGHT_BORDER(hit) \
56 (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
57 #define ON_TOP_BORDER(hit) \
58 (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
59 #define ON_BOTTOM_BORDER(hit) \
60 (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
62 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
63 #define _NET_WM_MOVERESIZE_SIZE_TOP 1
64 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
65 #define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
66 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
67 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
68 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
69 #define _NET_WM_MOVERESIZE_SIZE_LEFT 7
70 #define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
71 #define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
72 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
74 #define _NET_WM_STATE_REMOVE 0
75 #define _NET_WM_STATE_ADD 1
76 #define _NET_WM_STATE_TOGGLE 2
78 static const char managed_prop
[] = "__wine_x11_managed";
80 /***********************************************************************
83 void X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
85 XExposeEvent
*event
= &xev
->xexpose
;
87 struct x11drv_win_data
*data
;
88 int flags
= RDW_INVALIDATE
| RDW_ERASE
| RDW_ALLCHILDREN
;
90 TRACE( "win %p (%lx) %d,%d %dx%d\n",
91 hwnd
, event
->window
, event
->x
, event
->y
, event
->width
, event
->height
);
93 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
95 if (event
->window
== data
->whole_window
)
97 rect
.left
= data
->whole_rect
.left
+ event
->x
;
98 rect
.top
= data
->whole_rect
.top
+ event
->y
;
103 rect
.left
= data
->client_rect
.left
+ event
->x
;
104 rect
.top
= data
->client_rect
.top
+ event
->y
;
106 rect
.right
= rect
.left
+ event
->width
;
107 rect
.bottom
= rect
.top
+ event
->height
;
109 if (event
->window
== root_window
)
110 OffsetRect( &rect
, virtual_screen_rect
.left
, virtual_screen_rect
.top
);
112 SERVER_START_REQ( update_window_zorder
)
115 req
->rect
.left
= rect
.left
;
116 req
->rect
.top
= rect
.top
;
117 req
->rect
.right
= rect
.right
;
118 req
->rect
.bottom
= rect
.bottom
;
119 wine_server_call( req
);
123 /* make position relative to client area instead of parent */
124 OffsetRect( &rect
, -data
->client_rect
.left
, -data
->client_rect
.top
);
125 RedrawWindow( hwnd
, &rect
, 0, flags
);
128 /***********************************************************************
129 * SetWindowStyle (X11DRV.@)
131 * Update the X state of a window to reflect a style change
133 void X11DRV_SetWindowStyle( HWND hwnd
, DWORD old_style
)
135 Display
*display
= thread_display();
136 struct x11drv_win_data
*data
;
137 DWORD new_style
, changed
;
139 if (hwnd
== GetDesktopWindow()) return;
140 new_style
= GetWindowLongW( hwnd
, GWL_STYLE
);
141 changed
= new_style
^ old_style
;
143 if ((changed
& WS_VISIBLE
) && (new_style
& WS_VISIBLE
))
145 /* we don't unmap windows, that causes trouble with the window manager */
146 if (!(data
= X11DRV_get_win_data( hwnd
)) &&
147 !(data
= X11DRV_create_win_data( hwnd
))) return;
149 if (data
->whole_window
&& X11DRV_is_window_rect_mapped( &data
->window_rect
))
151 X11DRV_set_wm_hints( display
, data
);
154 TRACE( "mapping win %p\n", hwnd
);
155 wait_for_withdrawn_state( display
, data
);
156 X11DRV_sync_window_style( display
, data
);
158 XMapWindow( display
, data
->whole_window
);
161 data
->iconic
= (new_style
& WS_MINIMIZE
) != 0;
166 if (changed
& WS_DISABLED
)
168 data
= X11DRV_get_win_data( hwnd
);
169 if (data
&& data
->wm_hints
)
172 data
->wm_hints
->input
= !(new_style
& WS_DISABLED
);
173 XSetWMHints( display
, data
->whole_window
, data
->wm_hints
);
180 /***********************************************************************
181 * update_net_wm_states
183 static void update_net_wm_states( Display
*display
, struct x11drv_win_data
*data
)
185 static const unsigned int state_atoms
[NB_NET_WM_STATES
] =
187 XATOM__NET_WM_STATE_FULLSCREEN
,
188 XATOM__NET_WM_STATE_ABOVE
,
189 XATOM__NET_WM_STATE_MAXIMIZED_VERT
,
190 XATOM__NET_WM_STATE_SKIP_PAGER
,
191 XATOM__NET_WM_STATE_SKIP_TASKBAR
194 DWORD i
, style
, ex_style
, new_state
= 0;
197 if (!data
->managed
) return;
198 if (!data
->mapped
) return;
200 if (data
->whole_rect
.left
<= 0 && data
->whole_rect
.right
>= screen_width
&&
201 data
->whole_rect
.top
<= 0 && data
->whole_rect
.bottom
>= screen_height
)
202 new_state
|= (1 << NET_WM_STATE_FULLSCREEN
);
204 style
= GetWindowLongW( data
->hwnd
, GWL_STYLE
);
205 if (style
& WS_MAXIMIZE
) new_state
|= (1 << NET_WM_STATE_MAXIMIZED
);
207 ex_style
= GetWindowLongW( data
->hwnd
, GWL_EXSTYLE
);
208 if (ex_style
& WS_EX_TOPMOST
)
209 new_state
|= (1 << NET_WM_STATE_ABOVE
);
210 if (ex_style
& WS_EX_TOOLWINDOW
)
211 new_state
|= (1 << NET_WM_STATE_SKIP_TASKBAR
) | (1 << NET_WM_STATE_SKIP_PAGER
);
213 xev
.xclient
.type
= ClientMessage
;
214 xev
.xclient
.window
= data
->whole_window
;
215 xev
.xclient
.message_type
= x11drv_atom(_NET_WM_STATE
);
216 xev
.xclient
.serial
= 0;
217 xev
.xclient
.display
= display
;
218 xev
.xclient
.send_event
= True
;
219 xev
.xclient
.format
= 32;
220 xev
.xclient
.data
.l
[3] = 1;
222 for (i
= 0; i
< NB_NET_WM_STATES
; i
++)
224 if (!((data
->net_wm_state
^ new_state
) & (1 << i
))) continue; /* unchanged */
226 TRACE( "setting wm state %u for window %p/%lx to %u prev %u\n",
227 i
, data
->hwnd
, data
->whole_window
,
228 (new_state
& (1 << i
)) != 0, (data
->net_wm_state
& (1 << i
)) != 0 );
230 xev
.xclient
.data
.l
[0] = (new_state
& (1 << i
)) ? _NET_WM_STATE_ADD
: _NET_WM_STATE_REMOVE
;
231 xev
.xclient
.data
.l
[1] = X11DRV_Atoms
[state_atoms
[i
] - FIRST_XATOM
];
232 xev
.xclient
.data
.l
[2] = ((state_atoms
[i
] == XATOM__NET_WM_STATE_MAXIMIZED_VERT
) ?
233 x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ
) : 0);
235 XSendEvent( display
, root_window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, &xev
);
238 data
->net_wm_state
= new_state
;
242 /***********************************************************************
245 * Move the window bits when a window is moved.
247 static void move_window_bits( struct x11drv_win_data
*data
, const RECT
*old_rect
, const RECT
*new_rect
,
248 const RECT
*old_client_rect
)
250 RECT src_rect
= *old_rect
;
251 RECT dst_rect
= *new_rect
;
252 HDC hdc_src
, hdc_dst
;
257 if (!data
->whole_window
)
259 OffsetRect( &dst_rect
, -data
->window_rect
.left
, -data
->window_rect
.top
);
260 parent
= GetAncestor( data
->hwnd
, GA_PARENT
);
261 hdc_src
= GetDCEx( parent
, 0, DCX_CACHE
);
262 hdc_dst
= GetDCEx( data
->hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
266 OffsetRect( &dst_rect
, -data
->client_rect
.left
, -data
->client_rect
.top
);
267 /* make src rect relative to the old position of the window */
268 OffsetRect( &src_rect
, -old_client_rect
->left
, -old_client_rect
->top
);
269 if (dst_rect
.left
== src_rect
.left
&& dst_rect
.top
== src_rect
.top
) return;
270 hdc_src
= hdc_dst
= GetDCEx( data
->hwnd
, 0, DCX_CACHE
);
273 code
= X11DRV_START_EXPOSURES
;
274 ExtEscape( hdc_dst
, X11DRV_ESCAPE
, sizeof(code
), (LPSTR
)&code
, 0, NULL
);
276 TRACE( "copying bits for win %p/%lx/%lx %s -> %s\n",
277 data
->hwnd
, data
->whole_window
, data
->client_window
,
278 wine_dbgstr_rect(&src_rect
), wine_dbgstr_rect(&dst_rect
) );
279 BitBlt( hdc_dst
, dst_rect
.left
, dst_rect
.top
,
280 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
,
281 hdc_src
, src_rect
.left
, src_rect
.top
, SRCCOPY
);
283 code
= X11DRV_END_EXPOSURES
;
284 ExtEscape( hdc_dst
, X11DRV_ESCAPE
, sizeof(code
), (LPSTR
)&code
, sizeof(rgn
), (LPSTR
)&rgn
);
286 ReleaseDC( data
->hwnd
, hdc_dst
);
287 if (hdc_src
!= hdc_dst
) ReleaseDC( parent
, hdc_src
);
291 if (!data
->whole_window
)
293 /* map region to client rect since we are using DCX_WINDOW */
294 OffsetRgn( rgn
, data
->window_rect
.left
- data
->client_rect
.left
,
295 data
->window_rect
.top
- data
->client_rect
.top
);
296 RedrawWindow( data
->hwnd
, NULL
, rgn
,
297 RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ALLCHILDREN
);
299 else RedrawWindow( data
->hwnd
, NULL
, rgn
, RDW_INVALIDATE
| RDW_ERASE
| RDW_ALLCHILDREN
);
304 /***********************************************************************
305 * SetWindowPos (X11DRV.@)
307 void X11DRV_SetWindowPos( HWND hwnd
, HWND insert_after
, UINT swp_flags
,
308 const RECT
*rectWindow
, const RECT
*rectClient
,
309 const RECT
*visible_rect
, const RECT
*valid_rects
)
311 Display
*display
= thread_display();
312 struct x11drv_win_data
*data
= X11DRV_get_win_data( hwnd
);
313 DWORD new_style
= GetWindowLongW( hwnd
, GWL_STYLE
);
314 RECT old_window_rect
, old_whole_rect
, old_client_rect
;
318 /* create the win data if the window is being made visible */
319 if (!(new_style
& WS_VISIBLE
)) return;
320 if (!(data
= X11DRV_create_win_data( hwnd
))) return;
323 /* check if we need to switch the window to managed */
324 if (!data
->managed
&& data
->whole_window
&& is_window_managed( hwnd
, swp_flags
, rectWindow
))
326 TRACE( "making win %p/%lx managed\n", hwnd
, data
->whole_window
);
327 data
->managed
= TRUE
;
328 SetPropA( hwnd
, managed_prop
, (HANDLE
)1 );
332 XUnmapWindow( display
, data
->whole_window
);
334 data
->mapped
= FALSE
;
338 old_window_rect
= data
->window_rect
;
339 old_whole_rect
= data
->whole_rect
;
340 old_client_rect
= data
->client_rect
;
341 data
->window_rect
= *rectWindow
;
342 data
->whole_rect
= *rectWindow
;
343 data
->client_rect
= *rectClient
;
344 X11DRV_window_to_X_rect( data
, &data
->whole_rect
);
345 if (memcmp( &visible_rect
, &data
->whole_rect
, sizeof(RECT
) ))
347 TRACE( "%p: need to update visible rect %s -> %s\n", hwnd
,
348 wine_dbgstr_rect(visible_rect
), wine_dbgstr_rect(&data
->whole_rect
) );
349 SERVER_START_REQ( set_window_visible_rect
)
352 req
->flags
= swp_flags
;
353 req
->visible
.left
= data
->whole_rect
.left
;
354 req
->visible
.top
= data
->whole_rect
.top
;
355 req
->visible
.right
= data
->whole_rect
.right
;
356 req
->visible
.bottom
= data
->whole_rect
.bottom
;
357 wine_server_call( req
);
362 TRACE( "win %p window %s client %s style %08x flags %08x\n",
363 hwnd
, wine_dbgstr_rect(rectWindow
), wine_dbgstr_rect(rectClient
), new_style
, swp_flags
);
365 if (!IsRectEmpty( &valid_rects
[0] ))
367 int x_offset
= old_whole_rect
.left
- data
->whole_rect
.left
;
368 int y_offset
= old_whole_rect
.top
- data
->whole_rect
.top
;
370 /* if all that happened is that the whole window moved, copy everything */
371 if (!(swp_flags
& SWP_FRAMECHANGED
) &&
372 old_whole_rect
.right
- data
->whole_rect
.right
== x_offset
&&
373 old_whole_rect
.bottom
- data
->whole_rect
.bottom
== y_offset
&&
374 old_client_rect
.left
- data
->client_rect
.left
== x_offset
&&
375 old_client_rect
.right
- data
->client_rect
.right
== x_offset
&&
376 old_client_rect
.top
- data
->client_rect
.top
== y_offset
&&
377 old_client_rect
.bottom
- data
->client_rect
.bottom
== y_offset
&&
378 !memcmp( &valid_rects
[0], &data
->client_rect
, sizeof(RECT
) ))
380 /* if we have an X window the bits will be moved by the X server */
381 if (!data
->whole_window
)
382 move_window_bits( data
, &old_whole_rect
, &data
->whole_rect
, &old_client_rect
);
385 move_window_bits( data
, &valid_rects
[1], &valid_rects
[0], &old_client_rect
);
388 X11DRV_sync_client_position( display
, data
, swp_flags
, &old_client_rect
, &old_whole_rect
);
390 if (!data
->whole_window
|| data
->lock_changes
) return; /* nothing more to do */
392 if (data
->mapped
&& (!(new_style
& WS_VISIBLE
) || !X11DRV_is_window_rect_mapped( rectWindow
)))
394 TRACE( "unmapping win %p/%lx\n", hwnd
, data
->whole_window
);
396 if (data
->managed
) XWithdrawWindow( display
, data
->whole_window
, DefaultScreen(display
) );
397 else XUnmapWindow( display
, data
->whole_window
);
399 data
->mapped
= FALSE
;
400 data
->net_wm_state
= 0;
403 /* don't change position if we are about to minimize or maximize a managed window */
404 if (!(data
->managed
&& (swp_flags
& SWP_STATECHANGED
) && (new_style
& (WS_MINIMIZE
|WS_MAXIMIZE
))))
405 X11DRV_sync_window_position( display
, data
, swp_flags
, &old_client_rect
, &old_whole_rect
);
407 if ((new_style
& WS_VISIBLE
) &&
408 ((new_style
& WS_MINIMIZE
) || X11DRV_is_window_rect_mapped( rectWindow
)))
410 if (!data
->mapped
|| (swp_flags
& (SWP_FRAMECHANGED
|SWP_STATECHANGED
)))
411 X11DRV_set_wm_hints( display
, data
);
415 TRACE( "mapping win %p/%lx\n", hwnd
, data
->whole_window
);
416 wait_for_withdrawn_state( display
, data
);
417 X11DRV_sync_window_style( display
, data
);
419 XMapWindow( display
, data
->whole_window
);
423 data
->iconic
= (new_style
& WS_MINIMIZE
) != 0;
425 else if ((swp_flags
& SWP_STATECHANGED
) && (!data
->iconic
!= !(new_style
& WS_MINIMIZE
)))
427 data
->iconic
= (new_style
& WS_MINIMIZE
) != 0;
428 TRACE( "changing win %p iconic state to %u\n", data
->hwnd
, data
->iconic
);
431 XIconifyWindow( display
, data
->whole_window
, DefaultScreen(display
) );
432 else if (X11DRV_is_window_rect_mapped( rectWindow
))
433 XMapWindow( display
, data
->whole_window
);
436 update_net_wm_states( display
, data
);
441 /**********************************************************************
444 void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
446 struct x11drv_win_data
*data
;
449 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
450 if (!data
->mapped
) return;
454 HWND hwndFocus
= GetFocus();
455 if (hwndFocus
&& IsChild( hwnd
, hwndFocus
)) X11DRV_SetFocus(hwndFocus
); /* FIXME */
458 if (!data
->iconic
) return;
460 state
= get_window_wm_state( event
->xmap
.display
, data
);
461 if (state
== NormalState
)
464 unsigned int width
, height
, border
, depth
;
471 XGetGeometry( event
->xmap
.display
, data
->whole_window
, &root
, &x
, &y
, &width
, &height
,
473 XTranslateCoordinates( event
->xmap
.display
, data
->whole_window
, root
, 0, 0, &x
, &y
, &top
);
477 rect
.right
= x
+ width
;
478 rect
.bottom
= y
+ height
;
479 OffsetRect( &rect
, virtual_screen_rect
.left
, virtual_screen_rect
.top
);
480 X11DRV_X_to_window_rect( data
, &rect
);
482 wp
.length
= sizeof(wp
);
483 GetWindowPlacement( hwnd
, &wp
);
485 wp
.showCmd
= SW_RESTORE
;
486 wp
.rcNormalPosition
= rect
;
488 TRACE( "restoring win %p/%lx\n", hwnd
, data
->whole_window
);
489 data
->iconic
= FALSE
;
490 data
->lock_changes
++;
491 SetWindowPlacement( hwnd
, &wp
);
492 data
->lock_changes
--;
494 else TRACE( "win %p/%lx ignoring since state=%d\n", hwnd
, data
->whole_window
, state
);
498 /**********************************************************************
501 void X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
)
503 struct x11drv_win_data
*data
;
506 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
507 if (!data
->managed
|| !data
->mapped
|| data
->iconic
) return;
509 state
= get_window_wm_state( event
->xunmap
.display
, data
);
510 if (state
== IconicState
)
512 TRACE( "minimizing win %p/%lx\n", hwnd
, data
->whole_window
);
514 data
->lock_changes
++;
515 ShowWindow( hwnd
, SW_MINIMIZE
);
516 data
->lock_changes
--;
518 else TRACE( "win %p/%lx ignoring since state=%d\n", hwnd
, data
->whole_window
, state
);
521 struct desktop_resize_data
523 RECT old_screen_rect
;
524 RECT old_virtual_rect
;
527 static BOOL CALLBACK
update_windows_on_desktop_resize( HWND hwnd
, LPARAM lparam
)
529 struct x11drv_win_data
*data
;
530 Display
*display
= thread_display();
531 struct desktop_resize_data
*resize_data
= (struct desktop_resize_data
*)lparam
;
534 if (!(data
= X11DRV_get_win_data( hwnd
))) return TRUE
;
536 if (GetWindowLongW( hwnd
, GWL_STYLE
) & WS_VISIBLE
)
538 /* update the full screen state */
539 update_net_wm_states( display
, data
);
542 if (resize_data
->old_virtual_rect
.left
!= virtual_screen_rect
.left
) mask
|= CWX
;
543 if (resize_data
->old_virtual_rect
.top
!= virtual_screen_rect
.top
) mask
|= CWY
;
544 if (mask
&& data
->whole_window
)
546 XWindowChanges changes
;
549 changes
.x
= data
->whole_rect
.left
- virtual_screen_rect
.left
;
550 changes
.y
= data
->whole_rect
.top
- virtual_screen_rect
.top
;
551 XReconfigureWMWindow( display
, data
->whole_window
,
552 DefaultScreen(display
), mask
, &changes
);
559 /***********************************************************************
560 * X11DRV_resize_desktop
562 void X11DRV_resize_desktop( unsigned int width
, unsigned int height
)
564 HWND hwnd
= GetDesktopWindow();
565 struct desktop_resize_data resize_data
;
567 SetRect( &resize_data
.old_screen_rect
, 0, 0, screen_width
, screen_height
);
568 resize_data
.old_virtual_rect
= virtual_screen_rect
;
570 xinerama_init( width
, height
);
572 if (GetWindowThreadProcessId( hwnd
, NULL
) != GetCurrentThreadId())
574 SendMessageW( hwnd
, WM_X11DRV_RESIZE_DESKTOP
, 0, MAKELPARAM( width
, height
) );
578 TRACE( "desktop %p change to (%dx%d)\n", hwnd
, width
, height
);
579 SetWindowPos( hwnd
, 0, virtual_screen_rect
.left
, virtual_screen_rect
.top
,
580 virtual_screen_rect
.right
- virtual_screen_rect
.left
,
581 virtual_screen_rect
.bottom
- virtual_screen_rect
.top
,
582 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_DEFERERASE
);
583 SendMessageTimeoutW( HWND_BROADCAST
, WM_DISPLAYCHANGE
, screen_bpp
,
584 MAKELPARAM( width
, height
), SMTO_ABORTIFHUNG
, 2000, NULL
);
587 EnumWindows( update_windows_on_desktop_resize
, (LPARAM
)&resize_data
);
591 /***********************************************************************
592 * X11DRV_ConfigureNotify
594 void X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
596 XConfigureEvent
*event
= &xev
->xconfigure
;
597 struct x11drv_win_data
*data
;
600 int cx
, cy
, x
= event
->x
, y
= event
->y
;
603 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
607 if (!event
->send_event
) /* normal event, need to map coordinates to the root */
611 XTranslateCoordinates( event
->display
, data
->whole_window
, root_window
,
612 0, 0, &x
, &y
, &child
);
617 rect
.right
= x
+ event
->width
;
618 rect
.bottom
= y
+ event
->height
;
619 OffsetRect( &rect
, virtual_screen_rect
.left
, virtual_screen_rect
.top
);
620 TRACE( "win %p new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
621 hwnd
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
622 event
->x
, event
->y
, event
->width
, event
->height
);
623 X11DRV_X_to_window_rect( data
, &rect
);
627 cx
= rect
.right
- rect
.left
;
628 cy
= rect
.bottom
- rect
.top
;
629 flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
631 /* Compare what has changed */
633 GetWindowRect( hwnd
, &rect
);
634 if (rect
.left
== x
&& rect
.top
== y
) flags
|= SWP_NOMOVE
;
636 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
637 hwnd
, rect
.left
, rect
.top
, x
, y
);
639 if ((rect
.right
- rect
.left
== cx
&& rect
.bottom
- rect
.top
== cy
) ||
641 (IsRectEmpty( &rect
) && event
->width
== 1 && event
->height
== 1))
643 if (flags
& SWP_NOMOVE
) return; /* if nothing changed, don't do anything */
647 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
648 hwnd
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, cx
, cy
);
650 data
->lock_changes
++;
651 SetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
652 data
->lock_changes
--;
656 /***********************************************************************
659 * Draw the frame used when moving or resizing window.
661 * FIXME: This causes problems in Win95 mode. (why?)
663 static void draw_moving_frame( HDC hdc
, RECT
*rect
, BOOL thickframe
)
667 const int width
= GetSystemMetrics(SM_CXFRAME
);
668 const int height
= GetSystemMetrics(SM_CYFRAME
);
670 HBRUSH hbrush
= SelectObject( hdc
, GetStockObject( GRAY_BRUSH
) );
671 PatBlt( hdc
, rect
->left
, rect
->top
,
672 rect
->right
- rect
->left
- width
, height
, PATINVERT
);
673 PatBlt( hdc
, rect
->left
, rect
->top
+ height
, width
,
674 rect
->bottom
- rect
->top
- height
, PATINVERT
);
675 PatBlt( hdc
, rect
->left
+ width
, rect
->bottom
- 1,
676 rect
->right
- rect
->left
- width
, -height
, PATINVERT
);
677 PatBlt( hdc
, rect
->right
- 1, rect
->top
, -width
,
678 rect
->bottom
- rect
->top
- height
, PATINVERT
);
679 SelectObject( hdc
, hbrush
);
681 else DrawFocusRect( hdc
, rect
);
685 /***********************************************************************
688 * Initialization of a move or resize, when initiated from a menu choice.
689 * Return hit test code for caption or sizing border.
691 static LONG
start_size_move( HWND hwnd
, WPARAM wParam
, POINT
*capturePoint
, LONG style
)
698 GetWindowRect( hwnd
, &rectWindow
);
700 if ((wParam
& 0xfff0) == SC_MOVE
)
702 /* Move pointer at the center of the caption */
703 RECT rect
= rectWindow
;
704 /* Note: to be exactly centered we should take the different types
705 * of border into account, but it shouldn't make more than a few pixels
706 * of difference so let's not bother with that */
707 rect
.top
+= GetSystemMetrics(SM_CYBORDER
);
708 if (style
& WS_SYSMENU
)
709 rect
.left
+= GetSystemMetrics(SM_CXSIZE
) + 1;
710 if (style
& WS_MINIMIZEBOX
)
711 rect
.right
-= GetSystemMetrics(SM_CXSIZE
) + 1;
712 if (style
& WS_MAXIMIZEBOX
)
713 rect
.right
-= GetSystemMetrics(SM_CXSIZE
) + 1;
714 pt
.x
= (rect
.right
+ rect
.left
) / 2;
715 pt
.y
= rect
.top
+ GetSystemMetrics(SM_CYSIZE
)/2;
724 GetMessageW( &msg
, 0, WM_KEYFIRST
, WM_MOUSELAST
);
725 if (CallMsgFilterW( &msg
, MSGF_SIZE
)) continue;
731 hittest
= SendMessageW( hwnd
, WM_NCHITTEST
, 0, MAKELONG( pt
.x
, pt
.y
) );
732 if ((hittest
< HTLEFT
) || (hittest
> HTBOTTOMRIGHT
)) hittest
= 0;
743 pt
.x
=(rectWindow
.left
+rectWindow
.right
)/2;
744 pt
.y
= rectWindow
.top
+ GetSystemMetrics(SM_CYFRAME
) / 2;
748 pt
.x
=(rectWindow
.left
+rectWindow
.right
)/2;
749 pt
.y
= rectWindow
.bottom
- GetSystemMetrics(SM_CYFRAME
) / 2;
753 pt
.x
= rectWindow
.left
+ GetSystemMetrics(SM_CXFRAME
) / 2;
754 pt
.y
=(rectWindow
.top
+rectWindow
.bottom
)/2;
758 pt
.x
= rectWindow
.right
- GetSystemMetrics(SM_CXFRAME
) / 2;
759 pt
.y
=(rectWindow
.top
+rectWindow
.bottom
)/2;
762 case VK_ESCAPE
: return 0;
768 SetCursorPos( pt
.x
, pt
.y
);
769 SendMessageW( hwnd
, WM_SETCURSOR
, (WPARAM
)hwnd
, MAKELONG( hittest
, WM_MOUSEMOVE
));
774 /***********************************************************************
775 * set_movesize_capture
777 static void set_movesize_capture( HWND hwnd
)
781 SERVER_START_REQ( set_capture_window
)
784 req
->flags
= CAPTURE_MOVESIZE
;
785 if (!wine_server_call_err( req
))
787 previous
= reply
->previous
;
788 hwnd
= reply
->full_handle
;
792 if (previous
&& previous
!= hwnd
)
793 SendMessageW( previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
796 /***********************************************************************
797 * X11DRV_WMMoveResizeWindow
799 * Tells the window manager to initiate a move or resize operation.
802 * http://freedesktop.org/Standards/wm-spec/1.3/ar01s04.html
803 * or search for "_NET_WM_MOVERESIZE"
805 static BOOL
X11DRV_WMMoveResizeWindow( HWND hwnd
, int x
, int y
, WPARAM wparam
)
807 WPARAM syscommand
= wparam
& 0xfff0;
808 WPARAM hittest
= wparam
& 0x0f;
811 Display
*display
= thread_display();
813 if (syscommand
== SC_MOVE
)
815 if (!hittest
) dir
= _NET_WM_MOVERESIZE_MOVE_KEYBOARD
;
816 else dir
= _NET_WM_MOVERESIZE_MOVE
;
820 /* windows without WS_THICKFRAME are not resizable through the window manager */
821 if (!(GetWindowLongW( hwnd
, GWL_STYLE
) & WS_THICKFRAME
)) return FALSE
;
825 case WMSZ_LEFT
: dir
= _NET_WM_MOVERESIZE_SIZE_LEFT
; break;
826 case WMSZ_RIGHT
: dir
= _NET_WM_MOVERESIZE_SIZE_RIGHT
; break;
827 case WMSZ_TOP
: dir
= _NET_WM_MOVERESIZE_SIZE_TOP
; break;
828 case WMSZ_TOPLEFT
: dir
= _NET_WM_MOVERESIZE_SIZE_TOPLEFT
; break;
829 case WMSZ_TOPRIGHT
: dir
= _NET_WM_MOVERESIZE_SIZE_TOPRIGHT
; break;
830 case WMSZ_BOTTOM
: dir
= _NET_WM_MOVERESIZE_SIZE_BOTTOM
; break;
831 case WMSZ_BOTTOMLEFT
: dir
= _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
; break;
832 case WMSZ_BOTTOMRIGHT
: dir
= _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
; break;
833 default: dir
= _NET_WM_MOVERESIZE_SIZE_KEYBOARD
; break;
837 TRACE("hwnd %p, x %d, y %d, dir %d\n", hwnd
, x
, y
, dir
);
839 xev
.xclient
.type
= ClientMessage
;
840 xev
.xclient
.window
= X11DRV_get_whole_window(hwnd
);
841 xev
.xclient
.message_type
= x11drv_atom(_NET_WM_MOVERESIZE
);
842 xev
.xclient
.serial
= 0;
843 xev
.xclient
.display
= display
;
844 xev
.xclient
.send_event
= True
;
845 xev
.xclient
.format
= 32;
846 xev
.xclient
.data
.l
[0] = x
; /* x coord */
847 xev
.xclient
.data
.l
[1] = y
; /* y coord */
848 xev
.xclient
.data
.l
[2] = dir
; /* direction */
849 xev
.xclient
.data
.l
[3] = 1; /* button */
850 xev
.xclient
.data
.l
[4] = 0; /* unused */
852 /* need to ungrab the pointer that may have been automatically grabbed
853 * with a ButtonPress event */
855 XUngrabPointer( display
, CurrentTime
);
856 XSendEvent(display
, root_window
, False
, SubstructureNotifyMask
, &xev
);
861 /***********************************************************************
862 * SysCommandSizeMove (X11DRV.@)
864 * Perform SC_MOVE and SC_SIZE commands.
866 void X11DRV_SysCommandSizeMove( HWND hwnd
, WPARAM wParam
)
869 RECT sizingRect
, mouseRect
, origRect
;
872 LONG hittest
= (LONG
)(wParam
& 0x0f);
873 WPARAM syscommand
= wParam
& 0xfff0;
874 HCURSOR hDragCursor
= 0, hOldCursor
= 0;
875 POINT minTrack
, maxTrack
;
876 POINT capturePoint
, pt
;
877 LONG style
= GetWindowLongA( hwnd
, GWL_STYLE
);
878 BOOL thickframe
= HAS_THICKFRAME( style
);
879 BOOL iconic
= style
& WS_MINIMIZE
;
881 DWORD dwPoint
= GetMessagePos ();
882 BOOL DragFullWindows
= TRUE
;
883 Window parent_win
, grab_win
;
884 struct x11drv_thread_data
*thread_data
= x11drv_thread_data();
885 struct x11drv_win_data
*data
;
887 pt
.x
= (short)LOWORD(dwPoint
);
888 pt
.y
= (short)HIWORD(dwPoint
);
891 if (IsZoomed(hwnd
) || !IsWindowVisible(hwnd
)) return;
893 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
895 TRACE("hwnd %p (%smanaged), command %04lx, hittest %d, pos %d,%d\n",
896 hwnd
, data
->managed
? "" : "NOT ", syscommand
, hittest
, pt
.x
, pt
.y
);
898 /* if we are managed then we let the WM do all the work */
899 if (data
->managed
&& X11DRV_WMMoveResizeWindow( hwnd
, pt
.x
, pt
.y
, wParam
)) return;
901 if (syscommand
== SC_MOVE
)
903 if (!hittest
) hittest
= start_size_move( hwnd
, wParam
, &capturePoint
, style
);
904 if (!hittest
) return;
908 if ( hittest
&& (syscommand
!= SC_MOUSEMENU
) )
909 hittest
+= (HTLEFT
- WMSZ_LEFT
);
912 set_movesize_capture( hwnd
);
913 hittest
= start_size_move( hwnd
, wParam
, &capturePoint
, style
);
916 set_movesize_capture(0);
922 /* Get min/max info */
924 WINPOS_GetMinMaxInfo( hwnd
, NULL
, NULL
, &minTrack
, &maxTrack
);
925 GetWindowRect( hwnd
, &sizingRect
);
926 if (style
& WS_CHILD
)
928 parent
= GetParent(hwnd
);
929 /* make sizing rect relative to parent */
930 MapWindowPoints( 0, parent
, (POINT
*)&sizingRect
, 2 );
931 GetClientRect( parent
, &mouseRect
);
936 mouseRect
= virtual_screen_rect
;
938 origRect
= sizingRect
;
940 if (ON_LEFT_BORDER(hittest
))
942 mouseRect
.left
= max( mouseRect
.left
, sizingRect
.right
-maxTrack
.x
);
943 mouseRect
.right
= min( mouseRect
.right
, sizingRect
.right
-minTrack
.x
);
945 else if (ON_RIGHT_BORDER(hittest
))
947 mouseRect
.left
= max( mouseRect
.left
, sizingRect
.left
+minTrack
.x
);
948 mouseRect
.right
= min( mouseRect
.right
, sizingRect
.left
+maxTrack
.x
);
950 if (ON_TOP_BORDER(hittest
))
952 mouseRect
.top
= max( mouseRect
.top
, sizingRect
.bottom
-maxTrack
.y
);
953 mouseRect
.bottom
= min( mouseRect
.bottom
,sizingRect
.bottom
-minTrack
.y
);
955 else if (ON_BOTTOM_BORDER(hittest
))
957 mouseRect
.top
= max( mouseRect
.top
, sizingRect
.top
+minTrack
.y
);
958 mouseRect
.bottom
= min( mouseRect
.bottom
, sizingRect
.top
+maxTrack
.y
);
960 if (parent
) MapWindowPoints( parent
, 0, (LPPOINT
)&mouseRect
, 2 );
962 /* Retrieve a default cache DC (without using the window style) */
963 hdc
= GetDCEx( parent
, 0, DCX_CACHE
);
965 if( iconic
) /* create a cursor for dragging */
967 hDragCursor
= (HCURSOR
)GetClassLongPtrW( hwnd
, GCLP_HICON
);
968 if( !hDragCursor
) hDragCursor
= (HCURSOR
)SendMessageW( hwnd
, WM_QUERYDRAGICON
, 0, 0L);
969 if( !hDragCursor
) iconic
= FALSE
;
972 /* repaint the window before moving it around */
973 RedrawWindow( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
975 SendMessageW( hwnd
, WM_ENTERSIZEMOVE
, 0, 0 );
976 set_movesize_capture( hwnd
);
978 /* we only allow disabling the full window drag for child windows, or in desktop mode */
979 /* otherwise we'd need to grab the server and we want to avoid that */
980 if (parent
|| (root_window
!= DefaultRootWindow(gdi_display
)))
981 SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS
, 0, &DragFullWindows
, 0);
983 grab_win
= X11DRV_get_client_window( GetAncestor(hwnd
,GA_ROOT
) );
984 parent_win
= parent
? X11DRV_get_client_window( GetAncestor(parent
,GA_ROOT
) ) : root_window
;
987 XGrabPointer( thread_data
->display
, grab_win
, False
,
988 PointerMotionMask
| ButtonPressMask
| ButtonReleaseMask
,
989 GrabModeAsync
, GrabModeAsync
, parent_win
, None
, CurrentTime
);
991 thread_data
->grab_window
= grab_win
;
997 if (!GetMessageW( &msg
, 0, 0, 0 )) break;
998 if (CallMsgFilterW( &msg
, MSGF_SIZE
)) continue;
1000 /* Exit on button-up, Return, or Esc */
1001 if ((msg
.message
== WM_LBUTTONUP
) ||
1002 ((msg
.message
== WM_KEYDOWN
) &&
1003 ((msg
.wParam
== VK_RETURN
) || (msg
.wParam
== VK_ESCAPE
)))) break;
1005 if ((msg
.message
!= WM_KEYDOWN
) && (msg
.message
!= WM_MOUSEMOVE
))
1007 TranslateMessage( &msg
);
1008 DispatchMessageW( &msg
);
1009 continue; /* We are not interested in other messages */
1014 if (msg
.message
== WM_KEYDOWN
) switch(msg
.wParam
)
1016 case VK_UP
: pt
.y
-= 8; break;
1017 case VK_DOWN
: pt
.y
+= 8; break;
1018 case VK_LEFT
: pt
.x
-= 8; break;
1019 case VK_RIGHT
: pt
.x
+= 8; break;
1022 pt
.x
= max( pt
.x
, mouseRect
.left
);
1023 pt
.x
= min( pt
.x
, mouseRect
.right
);
1024 pt
.y
= max( pt
.y
, mouseRect
.top
);
1025 pt
.y
= min( pt
.y
, mouseRect
.bottom
);
1027 dx
= pt
.x
- capturePoint
.x
;
1028 dy
= pt
.y
- capturePoint
.y
;
1036 if( iconic
) /* ok, no system popup tracking */
1038 hOldCursor
= SetCursor(hDragCursor
);
1040 WINPOS_ShowIconTitle( hwnd
, FALSE
);
1042 else if(!DragFullWindows
)
1043 draw_moving_frame( hdc
, &sizingRect
, thickframe
);
1046 if (msg
.message
== WM_KEYDOWN
) SetCursorPos( pt
.x
, pt
.y
);
1049 RECT newRect
= sizingRect
;
1050 WPARAM wpSizingHit
= 0;
1052 if (hittest
== HTCAPTION
) OffsetRect( &newRect
, dx
, dy
);
1053 if (ON_LEFT_BORDER(hittest
)) newRect
.left
+= dx
;
1054 else if (ON_RIGHT_BORDER(hittest
)) newRect
.right
+= dx
;
1055 if (ON_TOP_BORDER(hittest
)) newRect
.top
+= dy
;
1056 else if (ON_BOTTOM_BORDER(hittest
)) newRect
.bottom
+= dy
;
1057 if(!iconic
&& !DragFullWindows
) draw_moving_frame( hdc
, &sizingRect
, thickframe
);
1060 /* determine the hit location */
1061 if (hittest
>= HTLEFT
&& hittest
<= HTBOTTOMRIGHT
)
1062 wpSizingHit
= WMSZ_LEFT
+ (hittest
- HTLEFT
);
1063 SendMessageW( hwnd
, WM_SIZING
, wpSizingHit
, (LPARAM
)&newRect
);
1067 if(!DragFullWindows
)
1068 draw_moving_frame( hdc
, &newRect
, thickframe
);
1070 SetWindowPos( hwnd
, 0, newRect
.left
, newRect
.top
,
1071 newRect
.right
- newRect
.left
,
1072 newRect
.bottom
- newRect
.top
,
1073 ( hittest
== HTCAPTION
) ? SWP_NOSIZE
: 0 );
1075 sizingRect
= newRect
;
1080 set_movesize_capture(0);
1083 if( moved
) /* restore cursors, show icon title later on */
1085 ShowCursor( FALSE
);
1086 SetCursor( hOldCursor
);
1089 else if (moved
&& !DragFullWindows
)
1091 draw_moving_frame( hdc
, &sizingRect
, thickframe
);
1092 /* make sure the moving frame is erased before we move the window */
1094 XFlush( gdi_display
);
1095 wine_tsx11_unlock();
1098 ReleaseDC( parent
, hdc
);
1101 XUngrabPointer( thread_data
->display
, CurrentTime
);
1102 wine_tsx11_unlock();
1103 thread_data
->grab_window
= None
;
1105 if (HOOK_CallHooks( WH_CBT
, HCBT_MOVESIZE
, (WPARAM
)hwnd
, (LPARAM
)&sizingRect
, TRUE
))
1108 SendMessageW( hwnd
, WM_EXITSIZEMOVE
, 0, 0 );
1109 SendMessageW( hwnd
, WM_SETVISIBLE
, !IsIconic(hwnd
), 0L);
1111 /* window moved or resized */
1114 /* if the moving/resizing isn't canceled call SetWindowPos
1115 * with the new position or the new size of the window
1117 if (!((msg
.message
== WM_KEYDOWN
) && (msg
.wParam
== VK_ESCAPE
)) )
1119 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
1120 if(!DragFullWindows
)
1121 SetWindowPos( hwnd
, 0, sizingRect
.left
, sizingRect
.top
,
1122 sizingRect
.right
- sizingRect
.left
,
1123 sizingRect
.bottom
- sizingRect
.top
,
1124 ( hittest
== HTCAPTION
) ? SWP_NOSIZE
: 0 );
1127 { /* restore previous size/position */
1129 SetWindowPos( hwnd
, 0, origRect
.left
, origRect
.top
,
1130 origRect
.right
- origRect
.left
,
1131 origRect
.bottom
- origRect
.top
,
1132 ( hittest
== HTCAPTION
) ? SWP_NOSIZE
: 0 );
1138 /* Single click brings up the system menu when iconized */
1142 if(style
& WS_SYSMENU
)
1143 SendMessageW( hwnd
, WM_SYSCOMMAND
,
1144 SC_MOUSEMENU
+ HTSYSMENU
, MAKELONG(pt
.x
,pt
.y
));
1146 else WINPOS_ShowIconTitle( hwnd
, TRUE
);