blob: 366ebc992b2876ede49d2523c555af6db9255036 [file] [log] [blame]
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001/*
2 * Window related functions
3 *
4 * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
5 * Copyright 1993 David Metcalfe
6 * Copyright 1995, 1996 Alex Korobka
7 */
8
9#include "config.h"
10
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +000011#include <stdlib.h>
12
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000013#include "ts_xlib.h"
14#include "ts_xutil.h"
15
16#include "winbase.h"
17#include "wingdi.h"
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +000018#include "winreg.h"
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000019#include "winuser.h"
20
21#include "debugtools.h"
22#include "x11drv.h"
23#include "win.h"
Alexandre Julliarde3fe9f22001-05-10 03:23:59 +000024#include "dce.h"
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000025#include "options.h"
26
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000027DEFAULT_DEBUG_CHANNEL(x11drv);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000028
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000029extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
30
31#define HAS_DLGFRAME(style,exStyle) \
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000032 (((exStyle) & WS_EX_DLGMODALFRAME) || \
33 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
34
35#define HAS_THICKFRAME(style,exStyle) \
36 (((style) & WS_THICKFRAME) && \
37 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
38
39#define HAS_THINFRAME(style) \
40 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000041
42/* X context to associate a hwnd to an X window */
43XContext winContext = 0;
44
45Atom wmProtocols = None;
46Atom wmDeleteWindow = None;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000047Atom wmTakeFocus = None;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000048Atom dndProtocol = None;
49Atom dndSelection = None;
50Atom wmChangeState = None;
51Atom kwmDockWindow = None;
52Atom _kde_net_wm_system_tray_window_for = None; /* KDE 2 Final */
53
54
55/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000056 * is_window_managed
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000057 *
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000058 * Check if a given window should be managed
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000059 */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000060inline static BOOL is_window_managed( WND *win )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000061{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000062 if (!Options.managed) return FALSE;
63
64 /* tray window is always managed */
65 if (win->dwExStyle & WS_EX_TRAYWINDOW) return TRUE;
66 /* child windows are not managed */
67 if (win->dwStyle & WS_CHILD) return FALSE;
68 /* tool windows are not managed */
69 if (win->dwExStyle & WS_EX_TOOLWINDOW) return FALSE;
70 /* windows with caption or thick frame are managed */
71 if ((win->dwStyle & WS_CAPTION) == WS_CAPTION) return TRUE;
72 if (win->dwStyle & WS_THICKFRAME) return TRUE;
73 /* default: not managed */
74 return FALSE;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000075}
76
77
78/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000079 * is_window_top_level
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000080 *
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000081 * Check if a given window is a top level X11 window
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000082 */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000083inline static BOOL is_window_top_level( WND *win )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000084{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000085 return (root_window == DefaultRootWindow(gdi_display) &&
86 win->parent->hwndSelf == GetDesktopWindow());
87}
88
89
90/***********************************************************************
Alexandre Julliard883cff42001-06-12 04:02:10 +000091 * is_client_window_mapped
92 *
93 * Check if the X client window should be mapped
94 */
95inline static BOOL is_client_window_mapped( WND *win )
96{
97 struct x11drv_win_data *data = win->pDriverData;
Alexandre Julliard704d0352001-07-12 02:49:31 +000098 return !(win->dwStyle & WS_MINIMIZE) && !IsRectEmpty( &data->client_rect );
Alexandre Julliard883cff42001-06-12 04:02:10 +000099}
100
101
102/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000103 * get_window_attributes
104 *
Alexandre Julliard883cff42001-06-12 04:02:10 +0000105 * Fill the window attributes structure for an X window.
106 * Returned cursor must be freed by caller.
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000107 */
Alexandre Julliard883cff42001-06-12 04:02:10 +0000108static int get_window_attributes( Display *display, WND *win, XSetWindowAttributes *attr )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000109{
110 BOOL is_top_level = is_window_top_level( win );
111 BOOL managed = is_top_level && is_window_managed( win );
112
113 if (managed) win->dwExStyle |= WS_EX_MANAGED;
114 else win->dwExStyle &= ~WS_EX_MANAGED;
115
116 attr->override_redirect = !managed;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000117 attr->colormap = X11DRV_PALETTE_PaletteXColormap;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000118 attr->save_under = ((win->clsStyle & CS_SAVEBITS) != 0);
119 attr->cursor = None;
120 attr->event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
121 ButtonPressMask | ButtonReleaseMask);
Alexandre Julliard883cff42001-06-12 04:02:10 +0000122 if (is_window_top_level( win ))
123 {
124 attr->event_mask |= StructureNotifyMask | FocusChangeMask;
125 attr->cursor = X11DRV_GetCursor( display, GlobalLock16(GetCursor()) );
126 }
127 return (CWOverrideRedirect | CWSaveUnder | CWEventMask | CWColormap | CWCursor);
128}
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000129
Alexandre Julliard883cff42001-06-12 04:02:10 +0000130
131/***********************************************************************
132 * sync_window_style
133 *
134 * Change the X window attributes when the window style has changed.
135 */
136static void sync_window_style( Display *display, WND *win )
137{
138 XSetWindowAttributes attr;
139 int mask;
140
141 wine_tsx11_lock();
142 mask = get_window_attributes( display, win, &attr );
143 XChangeWindowAttributes( display, get_whole_window(win), mask, &attr );
144 if (attr.cursor) XFreeCursor( display, attr.cursor );
145 wine_tsx11_unlock();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000146}
147
148
149/***********************************************************************
150 * get_window_changes
151 *
152 * fill the window changes structure
153 */
154static int get_window_changes( XWindowChanges *changes, const RECT *old, const RECT *new )
155{
156 int mask = 0;
157
158 if (old->right - old->left != new->right - new->left )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000159 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000160 if (!(changes->width = new->right - new->left)) changes->width = 1;
161 mask |= CWWidth;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000162 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000163 if (old->bottom - old->top != new->bottom - new->top)
164 {
165 if (!(changes->height = new->bottom - new->top)) changes->height = 1;
166 mask |= CWHeight;
167 }
168 if (old->left != new->left)
169 {
170 changes->x = new->left;
171 mask |= CWX;
172 }
173 if (old->top != new->top)
174 {
175 changes->y = new->top;
176 mask |= CWY;
177 }
178 return mask;
179}
180
181
182/***********************************************************************
183 * create_icon_window
184 */
185static Window create_icon_window( Display *display, WND *win )
186{
187 struct x11drv_win_data *data = win->pDriverData;
188 XSetWindowAttributes attr;
189
190 attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
191 ButtonPressMask | ButtonReleaseMask);
192 attr.bit_gravity = NorthWestGravity;
193 attr.backing_store = NotUseful/*WhenMapped*/;
194
Alexandre Julliard649637f2001-06-26 21:10:11 +0000195 wine_tsx11_lock();
196 data->icon_window = XCreateWindow( display, root_window, 0, 0,
197 GetSystemMetrics( SM_CXICON ),
198 GetSystemMetrics( SM_CYICON ),
199 0, screen_depth,
200 InputOutput, visual,
201 CWEventMask | CWBitGravity | CWBackingStore, &attr );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000202 XSaveContext( display, data->icon_window, winContext, (char *)win->hwndSelf );
Alexandre Julliard649637f2001-06-26 21:10:11 +0000203 wine_tsx11_unlock();
204
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000205 TRACE( "created %lx\n", data->icon_window );
Alexandre Julliard649637f2001-06-26 21:10:11 +0000206 SetPropA( win->hwndSelf, "__wine_x11_icon_window", (HANDLE)data->icon_window );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000207 return data->icon_window;
208}
209
210
211
212/***********************************************************************
213 * destroy_icon_window
214 */
Alexandre Julliard649637f2001-06-26 21:10:11 +0000215inline static void destroy_icon_window( Display *display, WND *win )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000216{
Alexandre Julliard649637f2001-06-26 21:10:11 +0000217 struct x11drv_win_data *data = win->pDriverData;
218
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000219 if (!data->icon_window) return;
Alexandre Julliard704d0352001-07-12 02:49:31 +0000220 wine_tsx11_lock();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000221 XDeleteContext( display, data->icon_window, winContext );
222 XDestroyWindow( display, data->icon_window );
223 data->icon_window = 0;
Alexandre Julliard704d0352001-07-12 02:49:31 +0000224 wine_tsx11_unlock();
Alexandre Julliard649637f2001-06-26 21:10:11 +0000225 RemovePropA( win->hwndSelf, "__wine_x11_icon_window" );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000226}
227
228
229/***********************************************************************
230 * set_icon_hints
231 *
232 * Set the icon wm hints
233 */
Alexandre Julliard43230042001-05-16 19:52:29 +0000234static void set_icon_hints( Display *display, WND *wndPtr, XWMHints *hints )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000235{
236 X11DRV_WND_DATA *data = wndPtr->pDriverData;
237 HICON hIcon = GetClassLongA( wndPtr->hwndSelf, GCL_HICON );
238
239 if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
240 if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
Alexandre Julliard883cff42001-06-12 04:02:10 +0000241 data->hWMIconBitmap = 0;
242 data->hWMIconMask = 0;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000243
Alexandre Julliard883cff42001-06-12 04:02:10 +0000244 if (!(wndPtr->dwExStyle & WS_EX_MANAGED))
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000245 {
Alexandre Julliard649637f2001-06-26 21:10:11 +0000246 destroy_icon_window( display, wndPtr );
Alexandre Julliard883cff42001-06-12 04:02:10 +0000247 hints->flags &= ~(IconPixmapHint | IconMaskHint | IconWindowHint);
248 }
249 else if (!hIcon)
250 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000251 if (!data->icon_window) create_icon_window( display, wndPtr );
252 hints->icon_window = data->icon_window;
253 hints->flags = (hints->flags & ~(IconPixmapHint | IconMaskHint)) | IconWindowHint;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000254 }
255 else
256 {
257 HBITMAP hbmOrig;
258 RECT rcMask;
259 BITMAP bmMask;
260 ICONINFO ii;
261 HDC hDC;
262
263 GetIconInfo(hIcon, &ii);
264
265 X11DRV_CreateBitmap(ii.hbmMask);
266 X11DRV_CreateBitmap(ii.hbmColor);
267
268 GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
269 rcMask.top = 0;
270 rcMask.left = 0;
271 rcMask.right = bmMask.bmWidth;
272 rcMask.bottom = bmMask.bmHeight;
273
274 hDC = CreateCompatibleDC(0);
275 hbmOrig = SelectObject(hDC, ii.hbmMask);
276 InvertRect(hDC, &rcMask);
277 SelectObject(hDC, hbmOrig);
278 DeleteDC(hDC);
279
280 data->hWMIconBitmap = ii.hbmColor;
281 data->hWMIconMask = ii.hbmMask;
282
283 hints->icon_pixmap = X11DRV_BITMAP_Pixmap(data->hWMIconBitmap);
284 hints->icon_mask = X11DRV_BITMAP_Pixmap(data->hWMIconMask);
Alexandre Julliard649637f2001-06-26 21:10:11 +0000285 destroy_icon_window( display, wndPtr );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000286 hints->flags = (hints->flags & ~IconWindowHint) | IconPixmapHint | IconMaskHint;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000287 }
288}
289
290
291/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000292 * set_size_hints
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000293 *
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000294 * set the window size hints
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000295 */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000296static void set_size_hints( Display *display, WND *win )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000297{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000298 XSizeHints* size_hints;
299 struct x11drv_win_data *data = win->pDriverData;
300
301 if ((size_hints = XAllocSizeHints()))
302 {
303 size_hints->win_gravity = StaticGravity;
304 size_hints->x = data->whole_rect.left;
305 size_hints->y = data->whole_rect.top;
306 size_hints->flags = PWinGravity | PPosition;
307
308 if (HAS_DLGFRAME( win->dwStyle, win->dwExStyle ))
309 {
310 size_hints->max_width = data->whole_rect.right - data->whole_rect.left;
311 size_hints->max_height = data->whole_rect.bottom - data->whole_rect.top;
312 size_hints->min_width = size_hints->max_width;
313 size_hints->min_height = size_hints->max_height;
314 size_hints->flags |= PMinSize | PMaxSize;
315 }
316 XSetWMNormalHints( display, data->whole_window, size_hints );
317 XFree( size_hints );
318 }
319}
320
321
322/***********************************************************************
323 * set_wm_hints
324 *
325 * Set the window manager hints for a newly-created window
326 */
Alexandre Julliard883cff42001-06-12 04:02:10 +0000327static void set_wm_hints( Display *display, WND *win )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000328{
329 struct x11drv_win_data *data = win->pDriverData;
330 Window group_leader;
331 XClassHint *class_hints;
332 XWMHints* wm_hints;
333 Atom protocols[2];
334 int i;
335
336 wine_tsx11_lock();
337
338 /* wm protocols */
339 i = 0;
340 protocols[i++] = wmDeleteWindow;
341 if (wmTakeFocus) protocols[i++] = wmTakeFocus;
342 XSetWMProtocols( display, data->whole_window, protocols, i );
343
344 /* class hints */
345 if ((class_hints = XAllocClassHint()))
346 {
347 class_hints->res_name = "wine";
348 class_hints->res_class = "Wine";
349 XSetClassHint( display, data->whole_window, class_hints );
350 XFree( class_hints );
351 }
352
353 /* transient for hint */
354 if (win->owner)
355 {
356 struct x11drv_win_data *owner_data = win->owner->pDriverData;
357 XSetTransientForHint( display, data->whole_window, owner_data->whole_window );
358 group_leader = owner_data->whole_window;
359 }
360 else group_leader = data->whole_window;
361
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000362 /* size hints */
363 set_size_hints( display, win );
364
365 /* systray properties (KDE only for now) */
366 if (win->dwExStyle & WS_EX_TRAYWINDOW)
367 {
368 int val = 1;
369 if (kwmDockWindow != None)
370 TSXChangeProperty( display, data->whole_window, kwmDockWindow, kwmDockWindow,
371 32, PropModeReplace, (char*)&val, 1 );
372 if (_kde_net_wm_system_tray_window_for != None)
373 TSXChangeProperty( display, data->whole_window, _kde_net_wm_system_tray_window_for,
374 XA_WINDOW, 32, PropModeReplace, (char*)&data->whole_window, 1 );
375 }
376
377 wine_tsx11_unlock();
Alexandre Julliard704d0352001-07-12 02:49:31 +0000378
379 /* wm hints */
380 if ((wm_hints = TSXAllocWMHints()))
381 {
382 wm_hints->flags = InputHint | StateHint | WindowGroupHint;
383 /* use globally active model if take focus is supported,
384 * passive model otherwise (cf. ICCCM) */
385 wm_hints->input = !wmTakeFocus;
386
387 set_icon_hints( display, win, wm_hints );
388
389 wm_hints->initial_state = (win->dwStyle & WS_MINIMIZE) ? IconicState : NormalState;
390 wm_hints->window_group = group_leader;
391
392 wine_tsx11_lock();
393 XSetWMHints( display, data->whole_window, wm_hints );
394 XFree(wm_hints);
395 wine_tsx11_unlock();
396 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000397}
398
399
400/***********************************************************************
401 * X11DRV_set_iconic_state
402 *
403 * Set the X11 iconic state according to the window style.
404 */
405void X11DRV_set_iconic_state( WND *win )
406{
407 Display *display = thread_display();
408 struct x11drv_win_data *data = win->pDriverData;
409 XWMHints* wm_hints;
410 BOOL iconic = IsIconic( win->hwndSelf );
411
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000412 wine_tsx11_lock();
413
Alexandre Julliard704d0352001-07-12 02:49:31 +0000414 if (iconic) XUnmapWindow( display, data->client_window );
415 else if (is_client_window_mapped( win )) XMapWindow( display, data->client_window );
416
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000417 if (!(wm_hints = XGetWMHints( display, data->whole_window ))) wm_hints = XAllocWMHints();
418 wm_hints->flags |= StateHint | IconPositionHint;
419 wm_hints->initial_state = iconic ? IconicState : NormalState;
420 wm_hints->icon_x = win->rectWindow.left;
421 wm_hints->icon_y = win->rectWindow.top;
422 XSetWMHints( display, data->whole_window, wm_hints );
423
424 if (win->dwStyle & WS_VISIBLE)
425 {
426 if (iconic)
427 XIconifyWindow( display, data->whole_window, DefaultScreen(display) );
428 else
429 if (!IsRectEmpty( &win->rectWindow )) XMapWindow( display, data->whole_window );
430 }
431
432 XFree(wm_hints);
433 wine_tsx11_unlock();
434}
435
436
437/***********************************************************************
438 * X11DRV_window_to_X_rect
439 *
440 * Convert a rect from client to X window coordinates
441 */
442void X11DRV_window_to_X_rect( WND *win, RECT *rect )
443{
444 if (!(win->dwExStyle & WS_EX_MANAGED)) return;
445 if (win->dwStyle & WS_ICONIC) return;
446 if (IsRectEmpty( rect )) return;
447
448 if (HAS_THICKFRAME( win->dwStyle, win->dwExStyle ))
449 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
450 else if (HAS_DLGFRAME( win->dwStyle, win->dwExStyle ))
451 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME) );
452 else if (HAS_THINFRAME( win->dwStyle ))
453 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
454
455 if ((win->dwStyle & WS_CAPTION) == WS_CAPTION)
456 {
457 if (win->dwExStyle & WS_EX_TOOLWINDOW)
458 rect->top += GetSystemMetrics(SM_CYSMCAPTION);
459 else
460 rect->top += GetSystemMetrics(SM_CYCAPTION);
461 }
462
463 if (win->dwExStyle & WS_EX_CLIENTEDGE)
464 InflateRect( rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE) );
465 if (win->dwExStyle & WS_EX_STATICEDGE)
466 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
467
468 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
469 if (rect->left >= rect->right) rect->right = rect->left + 1;
470}
471
472
473/***********************************************************************
474 * X11DRV_X_to_window_rect
475 *
476 * Opposite of X11DRV_window_to_X_rect
477 */
478void X11DRV_X_to_window_rect( WND *win, RECT *rect )
479{
480 if (!(win->dwExStyle & WS_EX_MANAGED)) return;
481 if (win->dwStyle & WS_ICONIC) return;
482 if (IsRectEmpty( rect )) return;
483
484 if (HAS_THICKFRAME( win->dwStyle, win->dwExStyle ))
485 InflateRect( rect, GetSystemMetrics(SM_CXFRAME), GetSystemMetrics(SM_CYFRAME) );
486 else if (HAS_DLGFRAME( win->dwStyle, win->dwExStyle ))
487 InflateRect( rect, GetSystemMetrics(SM_CXDLGFRAME), GetSystemMetrics(SM_CYDLGFRAME) );
488 else if (HAS_THINFRAME( win->dwStyle ))
489 InflateRect( rect, GetSystemMetrics(SM_CXBORDER), GetSystemMetrics(SM_CYBORDER) );
490
491 if ((win->dwStyle & WS_CAPTION) == WS_CAPTION)
492 {
493 if (win->dwExStyle & WS_EX_TOOLWINDOW)
494 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
495 else
496 rect->top -= GetSystemMetrics(SM_CYCAPTION);
497 }
498
499 if (win->dwExStyle & WS_EX_CLIENTEDGE)
500 InflateRect( rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE) );
501 if (win->dwExStyle & WS_EX_STATICEDGE)
502 InflateRect( rect, GetSystemMetrics(SM_CXBORDER), GetSystemMetrics(SM_CYBORDER) );
503
504 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
505 if (rect->left >= rect->right) rect->right = rect->left + 1;
506}
507
508
509/***********************************************************************
510 * X11DRV_sync_whole_window_position
511 *
512 * Synchronize the X whole window position with the Windows one
513 */
514int X11DRV_sync_whole_window_position( Display *display, WND *win, int zorder )
515{
516 XWindowChanges changes;
517 int mask;
518 struct x11drv_win_data *data = win->pDriverData;
519 RECT whole_rect = win->rectWindow;
520
521 X11DRV_window_to_X_rect( win, &whole_rect );
522 mask = get_window_changes( &changes, &data->whole_rect, &whole_rect );
523
524 if (zorder)
525 {
526 /* find window that this one must be after */
527 WND *prev = win->parent->child;
528 if (prev == win) /* top child */
529 {
530 changes.stack_mode = Above;
531 mask |= CWStackMode;
532 }
533 else
534 {
535 while (prev && prev->next != win) prev = prev->next;
536 if (prev)
537 {
538 changes.stack_mode = Below;
539 changes.sibling = get_whole_window(prev);
540 mask |= CWStackMode | CWSibling;
541 }
542 else ERR( "previous window not found for %x, list corrupted?\n", win->hwndSelf );
543 }
544 }
545
546 data->whole_rect = whole_rect;
547
548 if (mask)
549 {
550 TRACE( "setting win %lx pos %d,%d,%dx%d after %lx changes=%x\n",
551 data->whole_window, whole_rect.left, whole_rect.top,
552 whole_rect.right - whole_rect.left, whole_rect.bottom - whole_rect.top,
553 changes.sibling, mask );
554 wine_tsx11_lock();
555 XSync( gdi_display, False ); /* flush graphics operations before moving the window */
556 if (is_window_top_level( win ))
557 {
558 if (mask & (CWWidth|CWHeight)) set_size_hints( display, win );
559 XReconfigureWMWindow( display, data->whole_window,
560 DefaultScreen(display), mask, &changes );
561 }
562 else XConfigureWindow( display, data->whole_window, mask, &changes );
563 wine_tsx11_unlock();
564 }
565 return mask;
566}
567
568
569/***********************************************************************
570 * X11DRV_sync_client_window_position
571 *
572 * Synchronize the X client window position with the Windows one
573 */
574int X11DRV_sync_client_window_position( Display *display, WND *win )
575{
576 XWindowChanges changes;
577 int mask;
578 struct x11drv_win_data *data = win->pDriverData;
579 RECT client_rect = win->rectClient;
580
581 OffsetRect( &client_rect, -data->whole_rect.left, -data->whole_rect.top );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000582
583 if ((mask = get_window_changes( &changes, &data->client_rect, &client_rect )))
584 {
Alexandre Julliard883cff42001-06-12 04:02:10 +0000585 BOOL was_mapped = is_client_window_mapped( win );
586
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000587 TRACE( "setting win %lx pos %d,%d,%dx%d (was %d,%d,%dx%d) after %lx changes=%x\n",
588 data->client_window, client_rect.left, client_rect.top,
589 client_rect.right - client_rect.left, client_rect.bottom - client_rect.top,
590 data->client_rect.left, data->client_rect.top,
591 data->client_rect.right - data->client_rect.left,
592 data->client_rect.bottom - data->client_rect.top,
593 changes.sibling, mask );
594 data->client_rect = client_rect;
595 wine_tsx11_lock();
596 XSync( gdi_display, False ); /* flush graphics operations before moving the window */
Alexandre Julliard883cff42001-06-12 04:02:10 +0000597 if (was_mapped && !is_client_window_mapped( win ))
598 XUnmapWindow( display, data->client_window );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000599 XConfigureWindow( display, data->client_window, mask, &changes );
Alexandre Julliard883cff42001-06-12 04:02:10 +0000600 if (!was_mapped && is_client_window_mapped( win ))
601 XMapWindow( display, data->client_window );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000602 wine_tsx11_unlock();
603 }
604 return mask;
605}
606
607
608/***********************************************************************
609 * X11DRV_register_window
610 *
611 * Associate an X window to a HWND.
612 */
613void X11DRV_register_window( Display *display, HWND hwnd, struct x11drv_win_data *data )
614{
615 wine_tsx11_lock();
616 XSaveContext( display, data->whole_window, winContext, (char *)hwnd );
617 XSaveContext( display, data->client_window, winContext, (char *)hwnd );
618 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000619}
620
621
622/**********************************************************************
623 * create_desktop
624 */
Alexandre Julliard43230042001-05-16 19:52:29 +0000625static void create_desktop( Display *display, WND *wndPtr )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000626{
627 X11DRV_WND_DATA *data = wndPtr->pDriverData;
628
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000629 wine_tsx11_lock();
630 winContext = XUniqueContext();
631 wmProtocols = XInternAtom( display, "WM_PROTOCOLS", False );
632 wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", False );
633/* wmTakeFocus = XInternAtom( display, "WM_TAKE_FOCUS", False );*/
634 wmTakeFocus = 0; /* not yet */
635 dndProtocol = XInternAtom( display, "DndProtocol" , False );
636 dndSelection = XInternAtom( display, "DndSelection" , False );
637 wmChangeState = XInternAtom (display, "WM_CHANGE_STATE", False);
638 kwmDockWindow = XInternAtom( display, "KWM_DOCKWINDOW", False );
639 _kde_net_wm_system_tray_window_for = XInternAtom( display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False );
640 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000641
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000642 data->whole_window = data->client_window = root_window;
Alexandre Julliard649637f2001-06-26 21:10:11 +0000643
644 SetPropA( wndPtr->hwndSelf, "__wine_x11_whole_window", (HANDLE)root_window );
645 SetPropA( wndPtr->hwndSelf, "__wine_x11_client_window", (HANDLE)root_window );
646 SetPropA( wndPtr->hwndSelf, "__wine_x11_visual_id", (HANDLE)XVisualIDFromVisual(visual) );
647
Alexandre Julliard0b164742001-06-08 19:00:56 +0000648 if (root_window != DefaultRootWindow(display)) X11DRV_create_desktop_thread();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000649}
650
651
652/**********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000653 * create_whole_window
654 *
655 * Create the whole X window for a given window
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000656 */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000657static Window create_whole_window( Display *display, WND *win )
658{
659 struct x11drv_win_data *data = win->pDriverData;
660 int cx, cy, mask;
661 XSetWindowAttributes attr;
662 Window parent;
663 RECT rect;
664 BOOL is_top_level = is_window_top_level( win );
665
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000666 rect = win->rectWindow;
667 X11DRV_window_to_X_rect( win, &rect );
668
669 if (!(cx = rect.right - rect.left)) cx = 1;
670 if (!(cy = rect.bottom - rect.top)) cy = 1;
671
672 parent = get_client_window( win->parent );
673
674 wine_tsx11_lock();
675
Alexandre Julliard883cff42001-06-12 04:02:10 +0000676 mask = get_window_attributes( display, win, &attr );
677
678 /* set the attributes that don't change over the lifetime of the window */
679 attr.bit_gravity = ForgetGravity;
680 attr.win_gravity = NorthWestGravity;
681 attr.backing_store = NotUseful/*WhenMapped*/;
682 mask |= CWBitGravity | CWWinGravity | CWBackingStore;
683
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000684 data->whole_rect = rect;
685 data->whole_window = XCreateWindow( display, parent, rect.left, rect.top, cx, cy,
686 0, screen_depth, InputOutput, visual,
687 mask, &attr );
688 if (attr.cursor) XFreeCursor( display, attr.cursor );
689
Alexandre Julliard704d0352001-07-12 02:49:31 +0000690 if (!data->whole_window)
691 {
692 wine_tsx11_unlock();
693 return 0;
694 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000695
696 /* non-maximized child must be at bottom of Z order */
697 if ((win->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
698 {
699 XWindowChanges changes;
700 changes.stack_mode = Below;
701 XConfigureWindow( display, data->whole_window, CWStackMode, &changes );
702 }
703
Alexandre Julliard704d0352001-07-12 02:49:31 +0000704 wine_tsx11_unlock();
705
Alexandre Julliard883cff42001-06-12 04:02:10 +0000706 if (is_top_level) set_wm_hints( display, win );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000707
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000708 return data->whole_window;
709}
710
711
712/**********************************************************************
713 * create_client_window
714 *
715 * Create the client window for a given window
716 */
717static Window create_client_window( Display *display, WND *win )
718{
719 struct x11drv_win_data *data = win->pDriverData;
Alexandre Julliard883cff42001-06-12 04:02:10 +0000720 RECT rect = data->whole_rect;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000721 XSetWindowAttributes attr;
722
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000723 OffsetRect( &rect, -data->whole_rect.left, -data->whole_rect.top );
724 data->client_rect = rect;
725
726 attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
727 ButtonPressMask | ButtonReleaseMask);
728 attr.bit_gravity = (win->clsStyle & (CS_VREDRAW | CS_HREDRAW)) ?
729 ForgetGravity : NorthWestGravity;
730 attr.backing_store = NotUseful/*WhenMapped*/;
731
Alexandre Julliard883cff42001-06-12 04:02:10 +0000732 wine_tsx11_lock();
733 data->client_window = XCreateWindow( display, data->whole_window, 0, 0,
734 max( rect.right - rect.left, 1 ),
735 max( rect.bottom - rect.top, 1 ),
736 0, screen_depth,
737 InputOutput, visual,
738 CWEventMask | CWBitGravity | CWBackingStore, &attr );
739 if (data->client_window && is_client_window_mapped( win ))
740 XMapWindow( display, data->client_window );
741 wine_tsx11_unlock();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000742 return data->client_window;
743}
744
745
746/*****************************************************************
747 * SetWindowText (X11DRV.@)
748 */
749BOOL X11DRV_SetWindowText( HWND hwnd, LPCWSTR text )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000750{
Alexandre Julliard43230042001-05-16 19:52:29 +0000751 Display *display = thread_display();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000752 UINT count;
753 char *buffer;
754 static UINT text_cp = (UINT)-1;
755 Window win;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000756 WND *wndPtr = WIN_FindWndPtr( hwnd );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000757
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000758 if (!wndPtr) return FALSE;
759 if ((win = get_whole_window(wndPtr)))
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000760 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000761 if (text_cp == (UINT)-1)
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000762 {
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +0000763 HKEY hkey;
764 /* default value */
765 text_cp = CP_ACP;
766 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
767 {
768 char buffer[20];
769 DWORD type, count = sizeof(buffer);
770 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buffer, &count))
771 text_cp = atoi(buffer);
772 RegCloseKey(hkey);
773 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000774 TRACE("text_cp = %u\n", text_cp);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000775 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000776
777 /* allocate new buffer for window text */
778 count = WideCharToMultiByte(text_cp, 0, text, -1, NULL, 0, NULL, NULL);
779 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WCHAR) )))
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000780 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000781 ERR("Not enough memory for window text\n");
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000782 WIN_ReleaseWndPtr( wndPtr );
783 return FALSE;
784 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000785 WideCharToMultiByte(text_cp, 0, text, -1, buffer, count, NULL, NULL);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000786
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000787 wine_tsx11_lock();
788 XStoreName( display, win, buffer );
789 XSetIconName( display, win, buffer );
790 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000791
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000792 HeapFree( GetProcessHeap(), 0, buffer );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000793 }
794 WIN_ReleaseWndPtr( wndPtr );
795 return TRUE;
796}
797
798
799/***********************************************************************
800 * DestroyWindow (X11DRV.@)
801 */
802BOOL X11DRV_DestroyWindow( HWND hwnd )
803{
Alexandre Julliard43230042001-05-16 19:52:29 +0000804 Display *display = thread_display();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000805 WND *wndPtr = WIN_FindWndPtr( hwnd );
806 X11DRV_WND_DATA *data = wndPtr->pDriverData;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000807
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000808 if (!data) goto done;
809
810 if (data->whole_window)
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000811 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000812 TRACE( "win %x xwin %lx/%lx\n", hwnd, data->whole_window, data->client_window );
Alexandre Julliard43230042001-05-16 19:52:29 +0000813 wine_tsx11_lock();
814 XSync( gdi_display, False ); /* flush any reference to this drawable in GDI queue */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000815 XDeleteContext( display, data->whole_window, winContext );
816 XDeleteContext( display, data->client_window, winContext );
817 XDestroyWindow( display, data->whole_window ); /* this destroys client too */
Alexandre Julliard649637f2001-06-26 21:10:11 +0000818 destroy_icon_window( display, wndPtr );
Alexandre Julliard43230042001-05-16 19:52:29 +0000819 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000820 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000821
822 if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
823 if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000824 HeapFree( GetProcessHeap(), 0, data );
825 wndPtr->pDriverData = NULL;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000826 done:
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000827 WIN_ReleaseWndPtr( wndPtr );
828 return TRUE;
829}
830
831
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000832/**********************************************************************
833 * CreateWindow (X11DRV.@)
834 */
Gerard Patelad363032001-06-06 21:26:50 +0000835BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000836{
837 Display *display = thread_display();
838 WND *wndPtr;
839 struct x11drv_win_data *data;
Alexandre Julliard883cff42001-06-12 04:02:10 +0000840 RECT rect;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000841 BOOL ret = FALSE;
842
843 if (!(data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data)))) return FALSE;
844 data->whole_window = 0;
845 data->client_window = 0;
846 data->icon_window = 0;
847 data->hWMIconBitmap = 0;
848 data->hWMIconMask = 0;
849
850 wndPtr = WIN_FindWndPtr( hwnd );
851 wndPtr->pDriverData = data;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000852
853 if (!wndPtr->parent)
854 {
Alexandre Julliard883cff42001-06-12 04:02:10 +0000855 SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000856 create_desktop( display, wndPtr );
857 WIN_ReleaseWndPtr( wndPtr );
858 return TRUE;
859 }
860
861 if (!create_whole_window( display, wndPtr )) goto failed;
862 if (!create_client_window( display, wndPtr )) goto failed;
863 TSXSync( display, False );
864
Alexandre Julliard883cff42001-06-12 04:02:10 +0000865 WIN_ReleaseWndPtr( wndPtr );
866
Alexandre Julliard649637f2001-06-26 21:10:11 +0000867 SetPropA( hwnd, "__wine_x11_whole_window", (HANDLE)data->whole_window );
868 SetPropA( hwnd, "__wine_x11_client_window", (HANDLE)data->client_window );
869
Alexandre Julliard883cff42001-06-12 04:02:10 +0000870 /* send WM_NCCREATE */
871 TRACE( "hwnd %x cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cs->cx, cs->cy );
872 if (unicode)
873 ret = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
874 else
875 ret = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
876 if (!ret)
877 {
878 X11DRV_DestroyWindow( hwnd );
879 return FALSE;
880 }
881
882 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
883
884 sync_window_style( display, wndPtr );
885
886 /* send WM_NCCALCSIZE */
887 rect = wndPtr->rectWindow;
888 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect );
889 if (rect.left > rect.right || rect.top > rect.bottom) rect = wndPtr->rectWindow;
890 wndPtr->rectClient = rect;
891 X11DRV_sync_client_window_position( display, wndPtr );
892 X11DRV_register_window( display, hwnd, data );
893
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000894 TRACE( "win %x window %d,%d,%d,%d client %d,%d,%d,%d whole %d,%d,%d,%d X client %d,%d,%d,%d xwin %x/%x\n",
895 hwnd, wndPtr->rectWindow.left, wndPtr->rectWindow.top,
896 wndPtr->rectWindow.right, wndPtr->rectWindow.bottom,
897 wndPtr->rectClient.left, wndPtr->rectClient.top,
898 wndPtr->rectClient.right, wndPtr->rectClient.bottom,
899 data->whole_rect.left, data->whole_rect.top,
900 data->whole_rect.right, data->whole_rect.bottom,
901 data->client_rect.left, data->client_rect.top,
902 data->client_rect.right, data->client_rect.bottom,
903 (unsigned int)data->whole_window, (unsigned int)data->client_window );
904
905 if ((wndPtr->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
906 WIN_LinkWindow( hwnd, HWND_BOTTOM );
907 else
908 WIN_LinkWindow( hwnd, HWND_TOP );
909
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000910 WIN_ReleaseWndPtr( wndPtr );
911
Gerard Patelad363032001-06-06 21:26:50 +0000912 if (unicode)
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000913 ret = (SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
914 else
915 ret = (SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
916
917 if (!ret)
918 {
919 WIN_UnlinkWindow( hwnd );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000920 X11DRV_DestroyWindow( hwnd );
921 return FALSE;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000922 }
923
924 /* Send the size messages */
925
Alexandre Julliard0b164742001-06-08 19:00:56 +0000926 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000927 if (!(wndPtr->flags & WIN_NEED_SIZE))
928 {
929 /* send it anyway */
930 if (((wndPtr->rectClient.right-wndPtr->rectClient.left) <0)
931 ||((wndPtr->rectClient.bottom-wndPtr->rectClient.top)<0))
932 WARN("sending bogus WM_SIZE message 0x%08lx\n",
933 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
934 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
935 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
936 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
937 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
938 SendMessageW( hwnd, WM_MOVE, 0,
939 MAKELONG( wndPtr->rectClient.left, wndPtr->rectClient.top ) );
940 }
941
942 /* Show the window, maximizing or minimizing if needed */
943
944 if (wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE))
945 {
946 extern UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect ); /*FIXME*/
947
948 RECT newPos;
949 UINT swFlag = (wndPtr->dwStyle & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
950 wndPtr->dwStyle &= ~(WS_MAXIMIZE | WS_MINIMIZE);
951 WINPOS_MinMaximize( hwnd, swFlag, &newPos );
952 swFlag = ((wndPtr->dwStyle & WS_CHILD) || GetActiveWindow())
953 ? SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED
954 : SWP_NOZORDER | SWP_FRAMECHANGED;
955 SetWindowPos( hwnd, 0, newPos.left, newPos.top,
956 newPos.right, newPos.bottom, swFlag );
957 }
958
Alexandre Julliard0b164742001-06-08 19:00:56 +0000959 WIN_ReleaseWndPtr( wndPtr );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000960 return TRUE;
961
962
963 failed:
964 X11DRV_DestroyWindow( wndPtr->hwndSelf );
965 WIN_ReleaseWndPtr( wndPtr );
966 return FALSE;
967}
968
969
970/***********************************************************************
971 * X11DRV_get_client_window
972 *
973 * Return the X window associated with the client area of a window
974 */
975Window X11DRV_get_client_window( HWND hwnd )
976{
977 Window ret = 0;
978 WND *win = WIN_FindWndPtr( hwnd );
979 if (win)
980 {
981 struct x11drv_win_data *data = win->pDriverData;
982 ret = data->client_window;
983 WIN_ReleaseWndPtr( win );
984 }
985 return ret;
986}
987
988
989/***********************************************************************
990 * X11DRV_get_whole_window
991 *
992 * Return the X window associated with the full area of a window
993 */
994Window X11DRV_get_whole_window( HWND hwnd )
995{
996 Window ret = 0;
997 WND *win = WIN_FindWndPtr( hwnd );
998 if (win)
999 {
1000 struct x11drv_win_data *data = win->pDriverData;
1001 ret = data->whole_window;
1002 WIN_ReleaseWndPtr( win );
1003 }
1004 return ret;
1005}
1006
1007
1008/***********************************************************************
1009 * X11DRV_get_top_window
1010 *
1011 * Return the X window associated with the top-level parent of a window
1012 */
1013Window X11DRV_get_top_window( HWND hwnd )
1014{
1015 Window ret = 0;
1016 WND *win = WIN_FindWndPtr( hwnd );
1017 while (win && win->parent->hwndSelf != GetDesktopWindow())
1018 WIN_UpdateWndPtr( &win, win->parent );
1019 if (win)
1020 {
1021 struct x11drv_win_data *data = win->pDriverData;
1022 ret = data->whole_window;
1023 WIN_ReleaseWndPtr( win );
1024 }
1025 return ret;
1026}
1027
1028
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001029/*****************************************************************
1030 * SetParent (X11DRV.@)
1031 */
1032HWND X11DRV_SetParent( HWND hwnd, HWND parent )
1033{
Alexandre Julliard43230042001-05-16 19:52:29 +00001034 Display *display = thread_display();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001035 WND *wndPtr;
1036 WND *pWndParent;
1037 DWORD dwStyle;
1038 HWND retvalue;
1039
1040 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
1041
1042 dwStyle = wndPtr->dwStyle;
1043
Alexandre Julliardb19c57c2001-05-10 21:06:56 +00001044 if (!parent) parent = GetDesktopWindow();
1045
1046 if (!(pWndParent = WIN_FindWndPtr(parent)))
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001047 {
1048 WIN_ReleaseWndPtr( wndPtr );
1049 return 0;
1050 }
1051
1052 /* Windows hides the window first, then shows it again
1053 * including the WM_SHOWWINDOW messages and all */
1054 if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE );
1055
1056 retvalue = wndPtr->parent->hwndSelf; /* old parent */
1057 if (pWndParent != wndPtr->parent)
1058 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001059 struct x11drv_win_data *data = wndPtr->pDriverData;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001060
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001061 WIN_UnlinkWindow(wndPtr->hwndSelf);
1062 wndPtr->parent = pWndParent;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001063 WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001064
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001065 if (parent != GetDesktopWindow()) /* a child window */
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001066 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001067 if (!(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001068 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001069 DestroyMenu( (HMENU)wndPtr->wIDmenu );
1070 wndPtr->wIDmenu = 0;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001071 }
1072 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001073
Alexandre Julliard704d0352001-07-12 02:49:31 +00001074 if (is_window_top_level( wndPtr )) set_wm_hints( display, wndPtr );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001075 wine_tsx11_lock();
Alexandre Julliard883cff42001-06-12 04:02:10 +00001076 sync_window_style( display, wndPtr );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001077 XReparentWindow( display, data->whole_window, get_client_window(pWndParent),
1078 data->whole_rect.left, data->whole_rect.top );
1079 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001080 }
1081 WIN_ReleaseWndPtr( pWndParent );
1082 WIN_ReleaseWndPtr( wndPtr );
1083
1084 /* SetParent additionally needs to make hwnd the topmost window
1085 in the x-order and send the expected WM_WINDOWPOSCHANGING and
1086 WM_WINDOWPOSCHANGED notification messages.
1087 */
1088 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
1089 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|
1090 ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
1091 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
1092 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
1093
1094 return retvalue;
1095}
1096
1097
1098/*******************************************************************
1099 * EnableWindow (X11DRV.@)
1100 */
1101BOOL X11DRV_EnableWindow( HWND hwnd, BOOL enable )
1102{
Alexandre Julliard43230042001-05-16 19:52:29 +00001103 Display *display = thread_display();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001104 XWMHints *wm_hints;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001105 WND *wndPtr;
1106 BOOL retvalue;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001107
1108 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1109
1110 retvalue = ((wndPtr->dwStyle & WS_DISABLED) != 0);
1111
1112 if (enable && (wndPtr->dwStyle & WS_DISABLED))
1113 {
1114 /* Enable window */
1115 wndPtr->dwStyle &= ~WS_DISABLED;
1116
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001117 if (wndPtr->dwExStyle & WS_EX_MANAGED)
1118 {
1119 wine_tsx11_lock();
1120 if (!(wm_hints = XGetWMHints( display, get_whole_window(wndPtr) )))
1121 wm_hints = XAllocWMHints();
1122 if (wm_hints)
1123 {
1124 wm_hints->flags |= InputHint;
1125 wm_hints->input = TRUE;
1126 XSetWMHints( display, get_whole_window(wndPtr), wm_hints );
1127 XFree(wm_hints);
1128 }
1129 wine_tsx11_unlock();
1130 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001131
1132 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1133 }
1134 else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
1135 {
1136 SendMessageA( wndPtr->hwndSelf, WM_CANCELMODE, 0, 0 );
1137
1138 /* Disable window */
1139 wndPtr->dwStyle |= WS_DISABLED;
1140
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001141 if (wndPtr->dwExStyle & WS_EX_MANAGED)
1142 {
1143 wine_tsx11_lock();
1144 if (!(wm_hints = XGetWMHints( display, get_whole_window(wndPtr) )))
1145 wm_hints = XAllocWMHints();
1146 if (wm_hints)
1147 {
1148 wm_hints->flags |= InputHint;
1149 wm_hints->input = FALSE;
1150 XSetWMHints( display, get_whole_window(wndPtr), wm_hints );
1151 XFree(wm_hints);
1152 }
1153 wine_tsx11_unlock();
1154 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001155
1156 if (hwnd == GetFocus())
1157 SetFocus( 0 ); /* A disabled window can't have the focus */
1158
1159 if (hwnd == GetCapture())
1160 ReleaseCapture(); /* A disabled window can't capture the mouse */
1161
1162 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1163 }
1164 WIN_ReleaseWndPtr(wndPtr);
1165 return retvalue;
1166}
1167
1168
1169/*****************************************************************
1170 * SetFocus (X11DRV.@)
1171 *
1172 * Set the X focus.
1173 * Explicit colormap management seems to work only with OLVWM.
1174 */
1175void X11DRV_SetFocus( HWND hwnd )
1176{
Alexandre Julliard43230042001-05-16 19:52:29 +00001177 Display *display = thread_display();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001178 XWindowAttributes win_attr;
1179 Window win;
1180 WND *wndPtr = WIN_FindWndPtr( hwnd );
1181 WND *w = wndPtr;
1182
1183 if (!wndPtr) return;
1184
1185 /* Only mess with the X focus if there's */
1186 /* no desktop window and if the window is not managed by the WM. */
1187 if (root_window != DefaultRootWindow(display)) goto done;
1188
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001189 while (w && !get_whole_window(w)) w = w->parent;
1190 if (!w) goto done;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001191 if (w->dwExStyle & WS_EX_MANAGED) goto done;
1192
1193 if (!hwnd) /* If setting the focus to 0, uninstall the colormap */
1194 {
1195 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
1196 TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
1197 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001198 else if ((win = get_whole_window(w)))
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001199 {
1200 /* Set X focus and install colormap */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001201 wine_tsx11_lock();
1202 if (XGetWindowAttributes( display, win, &win_attr ) &&
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001203 (win_attr.map_state == IsViewable))
1204 {
1205 /* If window is not viewable, don't change anything */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001206
1207 /* we must not use CurrentTime (ICCCM), so try to use last message time instead */
1208 /* FIXME: this is not entirely correct */
1209 XSetInputFocus( display, win, RevertToParent,
1210 /*CurrentTime*/ GetMessageTime() + X11DRV_server_startticks );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001211 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001212 XInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001213 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001214 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001215 }
1216
1217 done:
1218 WIN_ReleaseWndPtr( wndPtr );
1219}
1220
1221
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001222/**********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001223 * SetWindowIcon (X11DRV.@)
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001224 *
1225 * hIcon or hIconSm has changed (or is being initialised for the
1226 * first time). Complete the X11 driver-specific initialisation
1227 * and set the window hints.
1228 *
1229 * This is not entirely correct, may need to create
1230 * an icon window and set the pixmap as a background
1231 */
1232HICON X11DRV_SetWindowIcon( HWND hwnd, HICON icon, BOOL small )
1233{
Alexandre Julliard43230042001-05-16 19:52:29 +00001234 Display *display = thread_display();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001235 WND *wndPtr = WIN_FindWndPtr( hwnd );
1236 int index = small ? GCL_HICONSM : GCL_HICON;
1237 HICON old;
1238
1239 if (!wndPtr) return 0;
1240
1241 old = GetClassLongW( hwnd, index );
1242 SetClassLongW( hwnd, index, icon );
1243
1244 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE |
1245 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1246
1247 if (wndPtr->dwExStyle & WS_EX_MANAGED)
1248 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001249 Window win = get_whole_window(wndPtr);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001250 XWMHints* wm_hints = TSXGetWMHints( display, win );
1251
1252 if (!wm_hints) wm_hints = TSXAllocWMHints();
1253 if (wm_hints)
1254 {
Alexandre Julliard43230042001-05-16 19:52:29 +00001255 set_icon_hints( display, wndPtr, wm_hints );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001256 TSXSetWMHints( display, win, wm_hints );
1257 TSXFree( wm_hints );
1258 }
1259 }
1260
1261 WIN_ReleaseWndPtr( wndPtr );
1262 return old;
1263}