blob: 30ef89ba36dd9d86fc0b1889c1d7029d5751819e [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
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00007 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000021 */
22
23#include "config.h"
24
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000025#include <stdarg.h>
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +000026#include <stdlib.h>
James Liggett60a97502006-08-22 17:14:11 -070027#include <stdio.h>
Patrik Stridvallba78aac2003-08-08 21:07:23 +000028#ifdef HAVE_UNISTD_H
29# include <unistd.h>
30#endif
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +000031
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +000032#include <X11/Xlib.h>
Alexandre Julliarde9119c12002-09-24 18:36:51 +000033#include <X11/Xresource.h>
34#include <X11/Xutil.h>
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000035
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000036#include "windef.h"
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000037#include "winbase.h"
38#include "wingdi.h"
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +000039#include "winreg.h"
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000040#include "winuser.h"
Ilya Konstantinov560ca322001-10-02 18:44:56 +000041#include "wine/unicode.h"
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000042
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000043#include "x11drv.h"
Alexandre Julliard4d32a472005-03-25 10:38:56 +000044#include "wine/debug.h"
45#include "wine/server.h"
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000046#include "win.h"
Ove Kaaven77e7fd72002-01-21 18:41:27 +000047#include "mwm.h"
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000048
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000049WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000050
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000051/* X context to associate a hwnd to an X window */
52XContext winContext = 0;
53
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +000054/* X context to associate a struct x11drv_win_data to an hwnd */
55static XContext win_data_context;
56
Alexandre Julliardaf50ad62005-07-07 17:30:57 +000057static const char whole_window_prop[] = "__wine_x11_whole_window";
58static const char icon_window_prop[] = "__wine_x11_icon_window";
59static const char managed_prop[] = "__wine_x11_managed";
60static const char visual_id_prop[] = "__wine_x11_visual_id";
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000061
James Liggett60a97502006-08-22 17:14:11 -070062/* for XDG systray icons */
63#define SYSTEM_TRAY_REQUEST_DOCK 0
64
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000065/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000066 * is_window_managed
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000067 *
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000068 * Check if a given window should be managed
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000069 */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000070inline static BOOL is_window_managed( HWND hwnd )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000071{
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000072 DWORD style, ex_style;
73
Alexandre Julliard59546022002-05-23 16:32:32 +000074 if (!managed_mode) return FALSE;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000075 /* tray window is always managed */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000076 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
77 if (ex_style & WS_EX_TRAYWINDOW) return TRUE;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000078 /* child windows are not managed */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000079 style = GetWindowLongW( hwnd, GWL_STYLE );
80 if (style & WS_CHILD) return FALSE;
Mike Hearn27d972f2003-12-04 21:54:13 +000081 /* windows with caption are managed */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000082 if ((style & WS_CAPTION) == WS_CAPTION) return TRUE;
Mike Hearn27d972f2003-12-04 21:54:13 +000083 /* tool windows are not managed */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000084 if (ex_style & WS_EX_TOOLWINDOW) return FALSE;
Mike Hearn27d972f2003-12-04 21:54:13 +000085 /* windows with thick frame are managed */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000086 if (style & WS_THICKFRAME) return TRUE;
Jerry Jenkins4e6fab52003-12-13 00:05:53 +000087 /* application windows are managed */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000088 if (ex_style & WS_EX_APPWINDOW) return TRUE;
Alex Pasadynd18c8ca2004-02-06 05:17:55 +000089 /* full-screen popup windows are managed */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000090 if (style & WS_POPUP)
Alex Pasadynd18c8ca2004-02-06 05:17:55 +000091 {
Alexandre Julliardfc5ce142005-01-17 19:17:47 +000092 RECT rect;
93 GetWindowRect( hwnd, &rect );
94 if ((rect.right - rect.left) == screen_width && (rect.bottom - rect.top) == screen_height)
95 return TRUE;
Alex Pasadynd18c8ca2004-02-06 05:17:55 +000096 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +000097 /* default: not managed */
98 return FALSE;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000099}
100
101
102/***********************************************************************
Alexandre Julliard59b7d342004-04-27 23:32:01 +0000103 * X11DRV_is_window_rect_mapped
104 *
105 * Check if the X whole window should be mapped based on its rectangle
106 */
107BOOL X11DRV_is_window_rect_mapped( const RECT *rect )
108{
109 /* don't map if rect is empty */
110 if (IsRectEmpty( rect )) return FALSE;
111
112 /* don't map if rect is off-screen */
Alexandre Julliard7f8ad0a2004-04-28 00:31:21 +0000113 if (rect->left >= (int)screen_width || rect->top >= (int)screen_height) return FALSE;
Alexandre Julliard59b7d342004-04-27 23:32:01 +0000114 if (rect->right < 0 || rect->bottom < 0) return FALSE;
115
116 return TRUE;
117}
118
119
120/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000121 * get_window_attributes
122 *
Alexandre Julliard883cff42001-06-12 04:02:10 +0000123 * Fill the window attributes structure for an X window.
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000124 */
Alexandre Julliard6bb18e22006-03-27 15:33:43 +0200125static int get_window_attributes( Display *display, struct x11drv_win_data *data,
126 XSetWindowAttributes *attr )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000127{
Alexandre Julliardc44410d2006-03-28 12:21:37 +0200128 if (!data->managed &&
129 root_window == DefaultRootWindow( display ) &&
130 data->whole_window != root_window &&
131 is_window_managed( data->hwnd ))
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000132 {
133 data->managed = TRUE;
Alexandre Julliardaf50ad62005-07-07 17:30:57 +0000134 SetPropA( data->hwnd, managed_prop, (HANDLE)1 );
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000135 }
136 attr->override_redirect = !data->managed;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000137 attr->colormap = X11DRV_PALETTE_PaletteXColormap;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000138 attr->save_under = ((GetClassLongW( data->hwnd, GCL_STYLE ) & CS_SAVEBITS) != 0);
Alexandre Julliard9428f062002-06-14 00:08:40 +0000139 attr->cursor = x11drv_thread_data()->cursor;
Alexandre Julliard2431a642005-07-27 15:22:58 +0000140 return (CWOverrideRedirect | CWSaveUnder | CWColormap | CWCursor);
Alexandre Julliard883cff42001-06-12 04:02:10 +0000141}
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000142
Alexandre Julliard883cff42001-06-12 04:02:10 +0000143
144/***********************************************************************
Alexandre Julliard911a1772002-08-20 00:36:45 +0000145 * X11DRV_sync_window_style
Alexandre Julliard883cff42001-06-12 04:02:10 +0000146 *
147 * Change the X window attributes when the window style has changed.
148 */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000149void X11DRV_sync_window_style( Display *display, struct x11drv_win_data *data )
Alexandre Julliard883cff42001-06-12 04:02:10 +0000150{
151 XSetWindowAttributes attr;
Alexandre Julliard6bb18e22006-03-27 15:33:43 +0200152 int mask = get_window_attributes( display, data, &attr );
Alexandre Julliard883cff42001-06-12 04:02:10 +0000153
154 wine_tsx11_lock();
Alexandre Julliard6d5f5442006-03-06 21:02:59 +0100155 if (data->whole_window != DefaultRootWindow(display))
156 XChangeWindowAttributes( display, data->whole_window, mask, &attr );
Alexandre Julliard883cff42001-06-12 04:02:10 +0000157 wine_tsx11_unlock();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000158}
159
160
161/***********************************************************************
162 * get_window_changes
163 *
164 * fill the window changes structure
165 */
166static int get_window_changes( XWindowChanges *changes, const RECT *old, const RECT *new )
167{
168 int mask = 0;
169
170 if (old->right - old->left != new->right - new->left )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000171 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000172 if (!(changes->width = new->right - new->left)) changes->width = 1;
173 mask |= CWWidth;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000174 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000175 if (old->bottom - old->top != new->bottom - new->top)
176 {
177 if (!(changes->height = new->bottom - new->top)) changes->height = 1;
178 mask |= CWHeight;
179 }
180 if (old->left != new->left)
181 {
182 changes->x = new->left;
183 mask |= CWX;
184 }
185 if (old->top != new->top)
186 {
187 changes->y = new->top;
188 mask |= CWY;
189 }
190 return mask;
191}
192
193
194/***********************************************************************
195 * create_icon_window
196 */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000197static Window create_icon_window( Display *display, struct x11drv_win_data *data )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000198{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000199 XSetWindowAttributes attr;
200
201 attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
Alexandre Julliard9428f062002-06-14 00:08:40 +0000202 ButtonPressMask | ButtonReleaseMask | EnterWindowMask);
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000203 attr.bit_gravity = NorthWestGravity;
204 attr.backing_store = NotUseful/*WhenMapped*/;
Lionel Ulmer1fc39be2001-07-12 22:27:56 +0000205 attr.colormap = X11DRV_PALETTE_PaletteXColormap; /* Needed due to our visual */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000206
Alexandre Julliard649637f2001-06-26 21:10:11 +0000207 wine_tsx11_lock();
208 data->icon_window = XCreateWindow( display, root_window, 0, 0,
209 GetSystemMetrics( SM_CXICON ),
210 GetSystemMetrics( SM_CYICON ),
211 0, screen_depth,
212 InputOutput, visual,
Lionel Ulmer1fc39be2001-07-12 22:27:56 +0000213 CWEventMask | CWBitGravity | CWBackingStore | CWColormap, &attr );
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000214 XSaveContext( display, data->icon_window, winContext, (char *)data->hwnd );
Alexandre Julliard649637f2001-06-26 21:10:11 +0000215 wine_tsx11_unlock();
216
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000217 TRACE( "created %lx\n", data->icon_window );
Alexandre Julliardaf50ad62005-07-07 17:30:57 +0000218 SetPropA( data->hwnd, icon_window_prop, (HANDLE)data->icon_window );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000219 return data->icon_window;
220}
221
222
223
224/***********************************************************************
225 * destroy_icon_window
226 */
Alexandre Julliardf777d702005-01-31 16:34:07 +0000227static void destroy_icon_window( Display *display, struct x11drv_win_data *data )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000228{
229 if (!data->icon_window) return;
Alexandre Julliard9428f062002-06-14 00:08:40 +0000230 if (x11drv_thread_data()->cursor_window == data->icon_window)
231 x11drv_thread_data()->cursor_window = None;
Alexandre Julliard704d0352001-07-12 02:49:31 +0000232 wine_tsx11_lock();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000233 XDeleteContext( display, data->icon_window, winContext );
234 XDestroyWindow( display, data->icon_window );
235 data->icon_window = 0;
Alexandre Julliard704d0352001-07-12 02:49:31 +0000236 wine_tsx11_unlock();
Alexandre Julliardaf50ad62005-07-07 17:30:57 +0000237 RemovePropA( data->hwnd, icon_window_prop );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000238}
239
240
241/***********************************************************************
242 * set_icon_hints
243 *
244 * Set the icon wm hints
245 */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000246static void set_icon_hints( Display *display, struct x11drv_win_data *data,
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000247 XWMHints *hints, HICON hIcon )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000248{
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000249 if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
250 if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
Alexandre Julliard883cff42001-06-12 04:02:10 +0000251 data->hWMIconBitmap = 0;
252 data->hWMIconMask = 0;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000253
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000254 if (!data->managed)
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000255 {
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000256 destroy_icon_window( display, data );
Alexandre Julliard883cff42001-06-12 04:02:10 +0000257 hints->flags &= ~(IconPixmapHint | IconMaskHint | IconWindowHint);
258 }
259 else if (!hIcon)
260 {
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000261 if (!data->icon_window) create_icon_window( display, data );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000262 hints->icon_window = data->icon_window;
263 hints->flags = (hints->flags & ~(IconPixmapHint | IconMaskHint)) | IconWindowHint;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000264 }
265 else
266 {
267 HBITMAP hbmOrig;
268 RECT rcMask;
269 BITMAP bmMask;
270 ICONINFO ii;
271 HDC hDC;
272
273 GetIconInfo(hIcon, &ii);
274
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000275 GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
276 rcMask.top = 0;
277 rcMask.left = 0;
278 rcMask.right = bmMask.bmWidth;
279 rcMask.bottom = bmMask.bmHeight;
280
281 hDC = CreateCompatibleDC(0);
282 hbmOrig = SelectObject(hDC, ii.hbmMask);
283 InvertRect(hDC, &rcMask);
Alexandre Julliardd8a92442002-05-31 18:43:22 +0000284 SelectObject(hDC, ii.hbmColor); /* force the color bitmap to x11drv mode too */
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000285 SelectObject(hDC, hbmOrig);
286 DeleteDC(hDC);
287
288 data->hWMIconBitmap = ii.hbmColor;
289 data->hWMIconMask = ii.hbmMask;
290
Alexandre Julliard5fd13262005-03-27 18:30:51 +0000291 hints->icon_pixmap = X11DRV_get_pixmap(data->hWMIconBitmap);
292 hints->icon_mask = X11DRV_get_pixmap(data->hWMIconMask);
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000293 destroy_icon_window( display, data );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000294 hints->flags = (hints->flags & ~IconWindowHint) | IconPixmapHint | IconMaskHint;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000295 }
296}
297
James Liggett60a97502006-08-22 17:14:11 -0700298/***********************************************************************
299 * systray_dock_window
300 *
301 * Docks the given X window with the NETWM system tray.
302 */
303static void systray_dock_window( Display *display, struct x11drv_win_data *data )
304{
305 static Atom systray_atom;
306 Window systray_window;
307
308 wine_tsx11_lock();
309 if (!systray_atom)
310 {
311 if (DefaultScreen( display ) == 0)
312 systray_atom = x11drv_atom(_NET_SYSTEM_TRAY_S0);
313 else
314 {
315 char systray_buffer[29]; /* strlen(_NET_SYSTEM_TRAY_S4294967295)+1 */
316 sprintf( systray_buffer, "_NET_SYSTEM_TRAY_S%u", DefaultScreen( display ) );
317 systray_atom = XInternAtom( display, systray_buffer, False );
318 }
319 }
320 systray_window = XGetSelectionOwner( display, systray_atom );
321 wine_tsx11_unlock();
322
323 TRACE("Docking tray icon %p\n", data->hwnd);
324
325 if (systray_window != None)
326 {
327 XEvent ev;
328 unsigned long info[2];
329
330 /* Put the window offscreen so it isn't mapped. The window _cannot_ be
331 * mapped if we intend to dock with an XEMBED tray. If the window is
332 * mapped when we dock, it may become visible as a child of the root
333 * window after it docks, which isn't the proper behavior.
334 *
335 * For more information on this problem, see
336 * http://standards.freedesktop.org/xembed-spec/latest/ar01s04.html */
337
338 SetWindowPos( data->hwnd, NULL, screen_width + 1, screen_height + 1,
339 0, 0, SWP_NOZORDER | SWP_NOSIZE );
340
341 /* set XEMBED protocol data on the window */
342 info[0] = 0; /* protocol version */
343 info[1] = 1; /* mapped = true */
344
345 wine_tsx11_lock();
346 XChangeProperty( display, data->whole_window,
347 x11drv_atom(_XEMBED_INFO),
348 x11drv_atom(_XEMBED_INFO), 32, PropModeReplace,
349 (unsigned char*)info, 2 );
350 wine_tsx11_unlock();
351
352 /* send the docking request message */
353 ZeroMemory( &ev, sizeof(ev) );
354 ev.xclient.type = ClientMessage;
355 ev.xclient.window = systray_window;
356 ev.xclient.message_type = x11drv_atom( _NET_SYSTEM_TRAY_OPCODE );
357 ev.xclient.format = 32;
358 ev.xclient.data.l[0] = CurrentTime;
359 ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
360 ev.xclient.data.l[2] = data->whole_window;
361 ev.xclient.data.l[3] = 0;
362 ev.xclient.data.l[4] = 0;
363
364 wine_tsx11_lock();
365 XSendEvent( display, systray_window, False, NoEventMask, &ev );
366 wine_tsx11_unlock();
367
368 }
369 else
370 {
371 int val = 1;
372
373 /* fall back to he KDE hints if the WM doesn't support XEMBED'ed
374 * systrays */
375
376 wine_tsx11_lock();
377 XChangeProperty( display, data->whole_window,
378 x11drv_atom(KWM_DOCKWINDOW),
379 x11drv_atom(KWM_DOCKWINDOW), 32, PropModeReplace,
380 (unsigned char*)&val, 1 );
381 XChangeProperty( display, data->whole_window,
382 x11drv_atom(_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR),
383 XA_WINDOW, 32, PropModeReplace,
384 (unsigned char*)&data->whole_window, 1 );
385 wine_tsx11_unlock();
386 }
387}
388
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000389
390/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000391 * set_size_hints
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000392 *
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000393 * set the window size hints
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000394 */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000395static void set_size_hints( Display *display, struct x11drv_win_data *data, DWORD style )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000396{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000397 XSizeHints* size_hints;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000398
399 if ((size_hints = XAllocSizeHints()))
400 {
Alexandre Julliardba1517f2006-03-27 22:16:04 +0200401 size_hints->flags = 0;
402
403 if (data->hwnd != GetDesktopWindow()) /* don't force position of desktop */
404 {
405 size_hints->win_gravity = StaticGravity;
406 size_hints->x = data->whole_rect.left;
407 size_hints->y = data->whole_rect.top;
408 size_hints->flags |= PWinGravity | PPosition;
409 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000410
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000411 if ( !(style & WS_THICKFRAME) )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000412 {
413 size_hints->max_width = data->whole_rect.right - data->whole_rect.left;
414 size_hints->max_height = data->whole_rect.bottom - data->whole_rect.top;
415 size_hints->min_width = size_hints->max_width;
416 size_hints->min_height = size_hints->max_height;
417 size_hints->flags |= PMinSize | PMaxSize;
418 }
419 XSetWMNormalHints( display, data->whole_window, size_hints );
420 XFree( size_hints );
421 }
422}
423
424
425/***********************************************************************
Alexandre Julliardc7dbffc2005-07-01 16:16:00 +0000426 * get_process_name
427 *
428 * get the name of the current process for setting class hints
429 */
430static char *get_process_name(void)
431{
432 static char *name;
433
434 if (!name)
435 {
436 WCHAR module[MAX_PATH];
437 DWORD len = GetModuleFileNameW( 0, module, MAX_PATH );
438 if (len && len < MAX_PATH)
439 {
440 char *ptr;
441 WCHAR *p, *appname = module;
442
443 if ((p = strrchrW( appname, '/' ))) appname = p + 1;
444 if ((p = strrchrW( appname, '\\' ))) appname = p + 1;
445 len = WideCharToMultiByte( CP_UNIXCP, 0, appname, -1, NULL, 0, NULL, NULL );
446 if ((ptr = HeapAlloc( GetProcessHeap(), 0, len )))
447 {
448 WideCharToMultiByte( CP_UNIXCP, 0, appname, -1, ptr, len, NULL, NULL );
449 name = ptr;
450 }
451 }
452 }
453 return name;
454}
455
456
457/***********************************************************************
Alexandre Julliard911a1772002-08-20 00:36:45 +0000458 * X11DRV_set_wm_hints
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000459 *
460 * Set the window manager hints for a newly-created window
461 */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000462void X11DRV_set_wm_hints( Display *display, struct x11drv_win_data *data )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000463{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000464 Window group_leader;
465 XClassHint *class_hints;
466 XWMHints* wm_hints;
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000467 Atom protocols[3];
468 MwmHints mwm_hints;
Ulrich Czekalla032bdc92003-11-20 22:09:51 +0000469 Atom dndVersion = 4;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000470 int i;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000471 DWORD style = GetWindowLongW( data->hwnd, GWL_STYLE );
472 DWORD ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
473 HWND owner = GetWindow( data->hwnd, GW_OWNER );
Alexandre Julliardc7dbffc2005-07-01 16:16:00 +0000474 char *process_name = get_process_name();
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000475
Alexandre Julliardba1517f2006-03-27 22:16:04 +0200476 if (data->hwnd == GetDesktopWindow())
477 {
Alexandre Julliardc44410d2006-03-28 12:21:37 +0200478 if (data->whole_window == DefaultRootWindow(display)) return;
Alexandre Julliardba1517f2006-03-27 22:16:04 +0200479 /* force some styles for the desktop to get the correct decorations */
480 style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
481 owner = 0;
482 }
483
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000484 /* transient for hint */
485 if (owner)
486 {
487 Window owner_win = X11DRV_get_whole_window( owner );
488 wine_tsx11_lock();
489 XSetTransientForHint( display, data->whole_window, owner_win );
490 wine_tsx11_unlock();
491 group_leader = owner_win;
492 }
493 else group_leader = data->whole_window;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000494
495 wine_tsx11_lock();
496
497 /* wm protocols */
498 i = 0;
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000499 protocols[i++] = x11drv_atom(WM_DELETE_WINDOW);
500 protocols[i++] = x11drv_atom(_NET_WM_PING);
501 if (use_take_focus) protocols[i++] = x11drv_atom(WM_TAKE_FOCUS);
502 XChangeProperty( display, data->whole_window, x11drv_atom(WM_PROTOCOLS),
Hans Leidekkerac147fe2005-03-22 21:17:34 +0000503 XA_ATOM, 32, PropModeReplace, (unsigned char *)protocols, i );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000504
505 /* class hints */
506 if ((class_hints = XAllocClassHint()))
507 {
Andrew Talbot55e20a72006-06-26 20:56:16 +0100508 static char wine[] = "Wine";
509
Alexandre Julliardc7dbffc2005-07-01 16:16:00 +0000510 class_hints->res_name = process_name;
Andrew Talbot55e20a72006-06-26 20:56:16 +0100511 class_hints->res_class = wine;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000512 XSetClassHint( display, data->whole_window, class_hints );
513 XFree( class_hints );
514 }
515
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000516 /* size hints */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000517 set_size_hints( display, data, style );
James Liggett60a97502006-08-22 17:14:11 -0700518
519 /* Dock system tray windows. */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000520 if (ex_style & WS_EX_TRAYWINDOW)
James Liggett60a97502006-08-22 17:14:11 -0700521 systray_dock_window( display, data );
Ove Kaaven77e7fd72002-01-21 18:41:27 +0000522
Mike Hearn34dd4552003-05-04 02:27:20 +0000523 /* set the WM_CLIENT_MACHINE and WM_LOCALE_NAME properties */
524 XSetWMProperties(display, data->whole_window, NULL, NULL, NULL, 0, NULL, NULL, NULL);
525 /* set the pid. together, these properties are needed so the window manager can kill us if we freeze */
526 i = getpid();
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000527 XChangeProperty(display, data->whole_window, x11drv_atom(_NET_WM_PID),
Hans Leidekkerac147fe2005-03-22 21:17:34 +0000528 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&i, 1);
Ove Kaaven77e7fd72002-01-21 18:41:27 +0000529
Mike Hearn27d972f2003-12-04 21:54:13 +0000530 /* map WS_EX_TOOLWINDOW to _NET_WM_WINDOW_TYPE_UTILITY */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000531 if (ex_style & WS_EX_TOOLWINDOW)
Mike Hearn27d972f2003-12-04 21:54:13 +0000532 {
533 Atom a = x11drv_atom(_NET_WM_WINDOW_TYPE_UTILITY);
534 XChangeProperty(display, data->whole_window, x11drv_atom(_NET_WM_WINDOW_TYPE),
Hans Leidekkerac147fe2005-03-22 21:17:34 +0000535 XA_ATOM, 32, PropModeReplace, (unsigned char*)&a, 1);
Mike Hearn27d972f2003-12-04 21:54:13 +0000536 }
537
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000538 mwm_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
539 mwm_hints.functions = 0;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000540 if ((style & WS_CAPTION) == WS_CAPTION) mwm_hints.functions |= MWM_FUNC_MOVE;
541 if (style & WS_THICKFRAME) mwm_hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
542 if (style & WS_MINIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MINIMIZE;
543 if (style & WS_MAXIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MAXIMIZE;
544 if (style & WS_SYSMENU) mwm_hints.functions |= MWM_FUNC_CLOSE;
Maxime Bellengéca6cb6b2005-03-08 18:58:25 +0000545 if (ex_style & WS_EX_APPWINDOW) mwm_hints.functions |= MWM_FUNC_MOVE;
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000546 mwm_hints.decorations = 0;
Maxime Bellengéca6cb6b2005-03-08 18:58:25 +0000547 if ((style & WS_CAPTION) == WS_CAPTION)
548 {
549 mwm_hints.decorations |= MWM_DECOR_TITLE;
550 if (style & WS_SYSMENU) mwm_hints.decorations |= MWM_DECOR_MENU;
551 if (style & WS_MINIMIZEBOX) mwm_hints.decorations |= MWM_DECOR_MINIMIZE;
552 if (style & WS_MAXIMIZEBOX) mwm_hints.decorations |= MWM_DECOR_MAXIMIZE;
553 }
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000554 if (ex_style & WS_EX_DLGMODALFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER;
555 else if (style & WS_THICKFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH;
556 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER;
557 else if (style & WS_BORDER) mwm_hints.decorations |= MWM_DECOR_BORDER;
558 else if (!(style & (WS_CHILD|WS_POPUP))) mwm_hints.decorations |= MWM_DECOR_BORDER;
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000559
560 XChangeProperty( display, data->whole_window, x11drv_atom(_MOTIF_WM_HINTS),
561 x11drv_atom(_MOTIF_WM_HINTS), 32, PropModeReplace,
Hans Leidekkerac147fe2005-03-22 21:17:34 +0000562 (unsigned char*)&mwm_hints, sizeof(mwm_hints)/sizeof(long) );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000563
Ulrich Czekalla032bdc92003-11-20 22:09:51 +0000564 XChangeProperty( display, data->whole_window, x11drv_atom(XdndAware),
565 XA_ATOM, 32, PropModeReplace, (unsigned char*)&dndVersion, 1 );
566
Alexandre Julliarde9119c12002-09-24 18:36:51 +0000567 wm_hints = XAllocWMHints();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000568 wine_tsx11_unlock();
Alexandre Julliard704d0352001-07-12 02:49:31 +0000569
570 /* wm hints */
Alexandre Julliarde9119c12002-09-24 18:36:51 +0000571 if (wm_hints)
Alexandre Julliard704d0352001-07-12 02:49:31 +0000572 {
573 wm_hints->flags = InputHint | StateHint | WindowGroupHint;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000574 wm_hints->input = !(style & WS_DISABLED);
Alexandre Julliard704d0352001-07-12 02:49:31 +0000575
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000576 set_icon_hints( display, data, wm_hints,
Dmitry Timoshkov39f960b2005-02-15 21:51:06 +0000577 (HICON)GetClassLongPtrW( data->hwnd, GCLP_HICON ) );
Alexandre Julliard704d0352001-07-12 02:49:31 +0000578
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000579 wm_hints->initial_state = (style & WS_MINIMIZE) ? IconicState : NormalState;
Alexandre Julliard704d0352001-07-12 02:49:31 +0000580 wm_hints->window_group = group_leader;
581
582 wine_tsx11_lock();
583 XSetWMHints( display, data->whole_window, wm_hints );
584 XFree(wm_hints);
585 wine_tsx11_unlock();
586 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000587}
588
589
590/***********************************************************************
591 * X11DRV_set_iconic_state
592 *
593 * Set the X11 iconic state according to the window style.
594 */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000595void X11DRV_set_iconic_state( HWND hwnd )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000596{
597 Display *display = thread_display();
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000598 struct x11drv_win_data *data;
599 RECT rect;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000600 XWMHints* wm_hints;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000601 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
602 BOOL iconic = (style & WS_MINIMIZE) != 0;
603
604 if (!(data = X11DRV_get_win_data( hwnd ))) return;
Alexandre Julliardc44410d2006-03-28 12:21:37 +0200605 if (!data->whole_window || data->whole_window == DefaultRootWindow(display)) return;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000606
607 GetWindowRect( hwnd, &rect );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000608
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000609 wine_tsx11_lock();
610
611 if (!(wm_hints = XGetWMHints( display, data->whole_window ))) wm_hints = XAllocWMHints();
612 wm_hints->flags |= StateHint | IconPositionHint;
613 wm_hints->initial_state = iconic ? IconicState : NormalState;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000614 wm_hints->icon_x = rect.left;
615 wm_hints->icon_y = rect.top;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000616 XSetWMHints( display, data->whole_window, wm_hints );
617
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000618 if (style & WS_VISIBLE)
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000619 {
620 if (iconic)
621 XIconifyWindow( display, data->whole_window, DefaultScreen(display) );
622 else
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000623 if (X11DRV_is_window_rect_mapped( &rect ))
Alexandre Julliard59b7d342004-04-27 23:32:01 +0000624 XMapWindow( display, data->whole_window );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000625 }
626
627 XFree(wm_hints);
628 wine_tsx11_unlock();
629}
630
631
632/***********************************************************************
633 * X11DRV_window_to_X_rect
634 *
635 * Convert a rect from client to X window coordinates
636 */
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000637void X11DRV_window_to_X_rect( struct x11drv_win_data *data, RECT *rect )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000638{
Alexandre Julliard8cd1f712001-07-20 18:37:37 +0000639 RECT rc;
640
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000641 if (!data->managed) return;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000642 if (IsRectEmpty( rect )) return;
643
Alexandre Julliard8cd1f712001-07-20 18:37:37 +0000644 rc.top = rc.bottom = rc.left = rc.right = 0;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000645
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000646 AdjustWindowRectEx( &rc, GetWindowLongW( data->hwnd, GWL_STYLE ) & ~(WS_HSCROLL|WS_VSCROLL),
647 FALSE, GetWindowLongW( data->hwnd, GWL_EXSTYLE ) );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000648
Alexandre Julliard8cd1f712001-07-20 18:37:37 +0000649 rect->left -= rc.left;
650 rect->right -= rc.right;
651 rect->top -= rc.top;
652 rect->bottom -= rc.bottom;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000653 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
654 if (rect->left >= rect->right) rect->right = rect->left + 1;
655}
656
657
658/***********************************************************************
659 * X11DRV_X_to_window_rect
660 *
661 * Opposite of X11DRV_window_to_X_rect
662 */
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000663void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000664{
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000665 if (!data->managed) return;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000666 if (IsRectEmpty( rect )) return;
667
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000668 AdjustWindowRectEx( rect, GetWindowLongW( data->hwnd, GWL_STYLE ) & ~(WS_HSCROLL|WS_VSCROLL),
669 FALSE, GetWindowLongW( data->hwnd, GWL_EXSTYLE ));
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000670
671 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
672 if (rect->left >= rect->right) rect->right = rect->left + 1;
673}
674
675
676/***********************************************************************
Alexandre Julliardf777d702005-01-31 16:34:07 +0000677 * X11DRV_sync_window_position
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000678 *
Alexandre Julliardf777d702005-01-31 16:34:07 +0000679 * Synchronize the X window position with the Windows one
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000680 */
Alexandre Julliardf777d702005-01-31 16:34:07 +0000681void X11DRV_sync_window_position( Display *display, struct x11drv_win_data *data,
Alexandre Julliardae661da2005-02-03 13:40:12 +0000682 UINT swp_flags, const RECT *new_client_rect,
683 const RECT *new_whole_rect )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000684{
685 XWindowChanges changes;
686 int mask;
Alexandre Julliardf777d702005-01-31 16:34:07 +0000687 RECT old_whole_rect;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000688
Alexandre Julliardf777d702005-01-31 16:34:07 +0000689 old_whole_rect = data->whole_rect;
Alexandre Julliardae661da2005-02-03 13:40:12 +0000690 data->whole_rect = *new_whole_rect;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000691
Alexandre Julliardf777d702005-01-31 16:34:07 +0000692 data->client_rect = *new_client_rect;
693 OffsetRect( &data->client_rect, -data->whole_rect.left, -data->whole_rect.top );
Alexandre Julliardf777d702005-01-31 16:34:07 +0000694
Alexandre Julliard3217e532006-03-29 18:27:01 +0200695 if (!data->whole_window || data->lock_changes) return;
Alexandre Julliardf777d702005-01-31 16:34:07 +0000696
697 mask = get_window_changes( &changes, &old_whole_rect, &data->whole_rect );
698
699 if (!(swp_flags & SWP_NOZORDER))
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000700 {
Alexandre Julliardf777d702005-01-31 16:34:07 +0000701 /* find window that this one must be after */
702 HWND prev = GetWindow( data->hwnd, GW_HWNDPREV );
703 while (prev && !(GetWindowLongW( prev, GWL_STYLE ) & WS_VISIBLE))
704 prev = GetWindow( prev, GW_HWNDPREV );
705 if (!prev) /* top child */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000706 {
Alexandre Julliardf777d702005-01-31 16:34:07 +0000707 changes.stack_mode = Above;
708 mask |= CWStackMode;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000709 }
710 else
711 {
Alexandre Julliardf777d702005-01-31 16:34:07 +0000712 /* should use stack_mode Below but most window managers don't get it right */
713 /* so move it above the next one in Z order */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000714 HWND next = GetWindow( data->hwnd, GW_HWNDNEXT );
Alexandre Julliardf777d702005-01-31 16:34:07 +0000715 while (next && !(GetWindowLongW( next, GWL_STYLE ) & WS_VISIBLE))
716 next = GetWindow( next, GW_HWNDNEXT );
717 if (next)
Alexandre Julliard08eac702003-05-19 19:08:57 +0000718 {
719 changes.stack_mode = Above;
720 changes.sibling = X11DRV_get_whole_window(next);
721 mask |= CWStackMode | CWSibling;
722 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000723 }
724 }
725
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000726 if (mask)
727 {
Alexandre Julliardf777d702005-01-31 16:34:07 +0000728 DWORD style = GetWindowLongW( data->hwnd, GWL_STYLE );
729
Dan Kegel0fd521f2003-01-08 21:09:25 +0000730 TRACE( "setting win %lx pos %ld,%ld,%ldx%ld after %lx changes=%x\n",
Alexandre Julliardf777d702005-01-31 16:34:07 +0000731 data->whole_window, data->whole_rect.left, data->whole_rect.top,
732 data->whole_rect.right - data->whole_rect.left,
733 data->whole_rect.bottom - data->whole_rect.top, changes.sibling, mask );
734
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000735 wine_tsx11_lock();
Alexandre Julliardf777d702005-01-31 16:34:07 +0000736 if (mask & (CWWidth|CWHeight)) set_size_hints( display, data, style );
737 XReconfigureWMWindow( display, data->whole_window,
738 DefaultScreen(display), mask, &changes );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000739 wine_tsx11_unlock();
740 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000741}
742
743
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000744/**********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000745 * create_whole_window
746 *
747 * Create the whole X window for a given window
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000748 */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000749static Window create_whole_window( Display *display, struct x11drv_win_data *data, DWORD style )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000750{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000751 int cx, cy, mask;
752 XSetWindowAttributes attr;
Alexandre Julliardf777d702005-01-31 16:34:07 +0000753 XIM xim;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000754 RECT rect;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000755
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000756 rect = data->window_rect;
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000757 X11DRV_window_to_X_rect( data, &rect );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000758
759 if (!(cx = rect.right - rect.left)) cx = 1;
760 if (!(cy = rect.bottom - rect.top)) cy = 1;
761
Alexandre Julliard6bb18e22006-03-27 15:33:43 +0200762 mask = get_window_attributes( display, data, &attr );
Alexandre Julliard883cff42001-06-12 04:02:10 +0000763
764 /* set the attributes that don't change over the lifetime of the window */
Alexandre Julliardae661da2005-02-03 13:40:12 +0000765 attr.bit_gravity = NorthWestGravity;
Alexandre Julliardae661da2005-02-03 13:40:12 +0000766 attr.backing_store = NotUseful;
Alexandre Julliard2431a642005-07-27 15:22:58 +0000767 attr.event_mask = (ExposureMask | PointerMotionMask |
768 ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
769 KeyPressMask | KeyReleaseMask | StructureNotifyMask |
770 FocusChangeMask | KeymapStateMask);
771 mask |= CWBitGravity | CWBackingStore | CWEventMask;
Alexandre Julliard883cff42001-06-12 04:02:10 +0000772
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000773 wine_tsx11_lock();
774
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000775 data->whole_rect = rect;
Alexandre Julliardf777d702005-01-31 16:34:07 +0000776 data->whole_window = XCreateWindow( display, root_window, rect.left, rect.top, cx, cy,
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000777 0, screen_depth, InputOutput, visual,
778 mask, &attr );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000779
Alexandre Julliard704d0352001-07-12 02:49:31 +0000780 if (!data->whole_window)
781 {
782 wine_tsx11_unlock();
783 return 0;
784 }
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +0000785 XSaveContext( display, data->whole_window, winContext, (char *)data->hwnd );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000786
787 /* non-maximized child must be at bottom of Z order */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000788 if ((style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000789 {
790 XWindowChanges changes;
791 changes.stack_mode = Below;
792 XConfigureWindow( display, data->whole_window, CWStackMode, &changes );
793 }
Alexandre Julliard704d0352001-07-12 02:49:31 +0000794 wine_tsx11_unlock();
795
Alexandre Julliardf777d702005-01-31 16:34:07 +0000796 xim = x11drv_thread_data()->xim;
797 if (xim) data->xic = X11DRV_CreateIC( xim, display, data->whole_window );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000798
Alexandre Julliardf777d702005-01-31 16:34:07 +0000799 X11DRV_set_wm_hints( display, data );
800
Alexandre Julliardaf50ad62005-07-07 17:30:57 +0000801 SetPropA( data->hwnd, whole_window_prop, (HANDLE)data->whole_window );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000802 return data->whole_window;
803}
804
805
806/**********************************************************************
Alexandre Julliardf777d702005-01-31 16:34:07 +0000807 * destroy_whole_window
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000808 *
Alexandre Julliardf777d702005-01-31 16:34:07 +0000809 * Destroy the whole X window for a given window.
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000810 */
Alexandre Julliardf777d702005-01-31 16:34:07 +0000811static void destroy_whole_window( Display *display, struct x11drv_win_data *data )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000812{
Alexandre Julliardf777d702005-01-31 16:34:07 +0000813 struct x11drv_thread_data *thread_data = x11drv_thread_data();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000814
Alexandre Julliardf777d702005-01-31 16:34:07 +0000815 if (!data->whole_window) return;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000816
Alexandre Julliardf777d702005-01-31 16:34:07 +0000817 TRACE( "win %p xwin %lx\n", data->hwnd, data->whole_window );
818 if (thread_data->cursor_window == data->whole_window) thread_data->cursor_window = None;
Alexandre Julliard883cff42001-06-12 04:02:10 +0000819 wine_tsx11_lock();
Alexandre Julliardf777d702005-01-31 16:34:07 +0000820 XDeleteContext( display, data->whole_window, winContext );
Alexandre Julliard6d5f5442006-03-06 21:02:59 +0100821 if (data->whole_window != DefaultRootWindow(display))
822 XDestroyWindow( display, data->whole_window );
Alexandre Julliardf777d702005-01-31 16:34:07 +0000823 data->whole_window = 0;
824 if (data->xic)
825 {
826 XUnsetICFocus( data->xic );
827 XDestroyIC( data->xic );
828 }
Alexandre Julliard975f1b22006-05-09 17:32:40 +0200829 /* Outlook stops processing messages after destroying a dialog, so we need an explicit flush */
830 XFlush( display );
Alexandre Julliard883cff42001-06-12 04:02:10 +0000831 wine_tsx11_unlock();
Alexandre Julliardaf50ad62005-07-07 17:30:57 +0000832 RemovePropA( data->hwnd, whole_window_prop );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000833}
834
835
836/*****************************************************************
837 * SetWindowText (X11DRV.@)
838 */
Alexandre Julliard2997fc52005-07-18 13:20:18 +0000839void X11DRV_SetWindowText( HWND hwnd, LPCWSTR text )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000840{
Alexandre Julliard43230042001-05-16 19:52:29 +0000841 Display *display = thread_display();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000842 UINT count;
843 char *buffer;
Ilya Konstantinov560ca322001-10-02 18:44:56 +0000844 char *utf8_buffer;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000845 Window win;
Kusanagi Kouichi44dcf6a2003-06-20 23:29:06 +0000846 XTextProperty prop;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000847
Alexandre Julliardc44410d2006-03-28 12:21:37 +0200848 if ((win = X11DRV_get_whole_window( hwnd )) && win != DefaultRootWindow(display))
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000849 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000850 /* allocate new buffer for window text */
Dmitry Timoshkov8a8d1b92003-07-09 04:22:57 +0000851 count = WideCharToMultiByte(CP_UNIXCP, 0, text, -1, NULL, 0, NULL, NULL);
Dmitry Timoshkov4bc0b282001-08-22 18:04:00 +0000852 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count )))
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000853 {
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000854 ERR("Not enough memory for window text\n");
Alexandre Julliard2997fc52005-07-18 13:20:18 +0000855 return;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000856 }
Dmitry Timoshkov8a8d1b92003-07-09 04:22:57 +0000857 WideCharToMultiByte(CP_UNIXCP, 0, text, -1, buffer, count, NULL, NULL);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000858
Ilya Konstantinov560ca322001-10-02 18:44:56 +0000859 count = WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), NULL, 0, NULL, NULL);
860 if (!(utf8_buffer = HeapAlloc( GetProcessHeap(), 0, count )))
861 {
862 ERR("Not enough memory for window text in UTF-8\n");
Michael Stefaniuc14934332004-12-14 11:38:50 +0000863 HeapFree( GetProcessHeap(), 0, buffer );
Alexandre Julliard2997fc52005-07-18 13:20:18 +0000864 return;
Ilya Konstantinov560ca322001-10-02 18:44:56 +0000865 }
866 WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), utf8_buffer, count, NULL, NULL);
867
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000868 wine_tsx11_lock();
Kusanagi Kouichi44dcf6a2003-06-20 23:29:06 +0000869 if (XmbTextListToTextProperty( display, &buffer, 1, XStdICCTextStyle, &prop ) == Success)
870 {
871 XSetWMName( display, win, &prop );
872 XSetWMIconName( display, win, &prop );
873 XFree( prop.value );
874 }
Ilya Konstantinov560ca322001-10-02 18:44:56 +0000875 /*
876 Implements a NET_WM UTF-8 title. It should be without a trailing \0,
877 according to the standard
878 ( http://www.pps.jussieu.fr/~jch/software/UTF8_STRING/UTF8_STRING.text ).
879 */
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000880 XChangeProperty( display, win, x11drv_atom(_NET_WM_NAME), x11drv_atom(UTF8_STRING),
881 8, PropModeReplace, (unsigned char *) utf8_buffer, count);
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000882 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000883
Ilya Konstantinov560ca322001-10-02 18:44:56 +0000884 HeapFree( GetProcessHeap(), 0, utf8_buffer );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000885 HeapFree( GetProcessHeap(), 0, buffer );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000886 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000887}
888
889
890/***********************************************************************
891 * DestroyWindow (X11DRV.@)
892 */
Alexandre Julliard2997fc52005-07-18 13:20:18 +0000893void X11DRV_DestroyWindow( HWND hwnd )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000894{
Alexandre Julliard9428f062002-06-14 00:08:40 +0000895 struct x11drv_thread_data *thread_data = x11drv_thread_data();
896 Display *display = thread_data->display;
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +0000897 struct x11drv_win_data *data;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000898
Alexandre Julliard2997fc52005-07-18 13:20:18 +0000899 if (!(data = X11DRV_get_win_data( hwnd ))) return;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000900
Alexandre Julliard2fb7c872005-03-25 16:47:04 +0000901 free_window_dce( data );
Alexandre Julliardf777d702005-01-31 16:34:07 +0000902 destroy_whole_window( display, data );
903 destroy_icon_window( display, data );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000904
Alexandre Julliardf777d702005-01-31 16:34:07 +0000905 if (thread_data->last_focus == hwnd) thread_data->last_focus = 0;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000906 if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
907 if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +0000908 wine_tsx11_lock();
Alexandre Julliarde5515552005-02-09 14:01:40 +0000909 XDeleteContext( display, (XID)hwnd, win_data_context );
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +0000910 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000911 HeapFree( GetProcessHeap(), 0, data );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000912}
913
914
Alexandre Julliarde419cb82005-07-07 20:33:29 +0000915static struct x11drv_win_data *alloc_win_data( Display *display, HWND hwnd )
916{
917 struct x11drv_win_data *data;
918
919 if ((data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data))))
920 {
921 data->hwnd = hwnd;
922 data->whole_window = 0;
923 data->icon_window = 0;
924 data->xic = 0;
925 data->managed = FALSE;
926 data->dce = NULL;
Alexandre Julliard3217e532006-03-29 18:27:01 +0200927 data->lock_changes = 0;
Alexandre Julliarde419cb82005-07-07 20:33:29 +0000928 data->hWMIconBitmap = 0;
929 data->hWMIconMask = 0;
930
931 wine_tsx11_lock();
932 if (!winContext) winContext = XUniqueContext();
933 if (!win_data_context) win_data_context = XUniqueContext();
934 XSaveContext( display, (XID)hwnd, win_data_context, (char *)data );
935 wine_tsx11_unlock();
936 }
937 return data;
938}
939
940
Alexandre Julliarddb6608a2006-03-27 22:43:03 +0200941/* fill in the desktop X window id in the x11drv_win_data structure */
942static void get_desktop_xwin( Display *display, struct x11drv_win_data *data )
943{
944 RECT rect;
945 Window win = (Window)GetPropA( data->hwnd, whole_window_prop );
946
947 if (win)
948 {
Alexandre Julliardbec49902006-03-28 16:55:03 +0200949 unsigned int width, height;
950
Alexandre Julliarddb6608a2006-03-27 22:43:03 +0200951 /* retrieve the real size of the desktop */
952 SERVER_START_REQ( get_window_rectangles )
953 {
954 req->handle = data->hwnd;
Alexandre Julliardbec49902006-03-28 16:55:03 +0200955 wine_server_call( req );
956 width = reply->window.right - reply->window.left;
957 height = reply->window.bottom - reply->window.top;
Alexandre Julliarddb6608a2006-03-27 22:43:03 +0200958 }
959 SERVER_END_REQ;
Alexandre Julliardbec49902006-03-28 16:55:03 +0200960 data->whole_window = win;
961 if (win != root_window) X11DRV_init_desktop( win, width, height );
Alexandre Julliarddb6608a2006-03-27 22:43:03 +0200962 }
963 else
964 {
965 VisualID visualid;
966
967 wine_tsx11_lock();
968 visualid = XVisualIDFromVisual(visual);
969 wine_tsx11_unlock();
970 SetPropA( data->hwnd, whole_window_prop, (HANDLE)root_window );
971 SetPropA( data->hwnd, visual_id_prop, (HANDLE)visualid );
972 data->whole_window = root_window;
973 SetRect( &rect, 0, 0, screen_width, screen_height );
974 X11DRV_set_window_pos( data->hwnd, 0, &rect, &rect, SWP_NOZORDER, NULL );
975 if (root_window != DefaultRootWindow( display ))
976 {
977 data->managed = TRUE;
978 SetPropA( data->hwnd, managed_prop, (HANDLE)1 );
979 }
980 }
981}
982
Alexandre Julliarde419cb82005-07-07 20:33:29 +0000983/**********************************************************************
984 * CreateDesktopWindow (X11DRV.@)
985 */
986BOOL X11DRV_CreateDesktopWindow( HWND hwnd )
987{
988 Display *display = thread_display();
Alexandre Julliarde419cb82005-07-07 20:33:29 +0000989 struct x11drv_win_data *data;
Alexandre Julliarde419cb82005-07-07 20:33:29 +0000990
991 if (!(data = alloc_win_data( display, hwnd ))) return FALSE;
Alexandre Julliarde419cb82005-07-07 20:33:29 +0000992
Alexandre Julliarddb6608a2006-03-27 22:43:03 +0200993 get_desktop_xwin( display, data );
Alexandre Julliarde419cb82005-07-07 20:33:29 +0000994
995 return TRUE;
996}
997
998
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000999/**********************************************************************
1000 * CreateWindow (X11DRV.@)
1001 */
Gerard Patelad363032001-06-06 21:26:50 +00001002BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001003{
1004 Display *display = thread_display();
1005 WND *wndPtr;
1006 struct x11drv_win_data *data;
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001007 HWND insert_after;
Alexandre Julliard883cff42001-06-12 04:02:10 +00001008 RECT rect;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001009 DWORD style;
Alexandre Julliard02861352002-10-29 00:41:42 +00001010 CBT_CREATEWNDA cbtc;
Robert Shearmancaec6022005-03-23 10:26:15 +00001011 CREATESTRUCTA cbcs;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001012 BOOL ret = FALSE;
1013
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001014 if (!(data = alloc_win_data( display, hwnd ))) return FALSE;
1015
Michael Cardenasf0b6b9a2002-05-07 01:52:15 +00001016 if (cs->cx > 65535)
1017 {
1018 ERR( "invalid window width %d\n", cs->cx );
1019 cs->cx = 65535;
1020 }
1021 if (cs->cy > 65535)
1022 {
Evan Deaubl627423d2004-08-26 18:11:29 +00001023 ERR( "invalid window height %d\n", cs->cy );
Michael Cardenasf0b6b9a2002-05-07 01:52:15 +00001024 cs->cy = 65535;
1025 }
Alexandre Julliard25b64932004-12-09 16:58:00 +00001026 if (cs->cx < 0)
1027 {
1028 ERR( "invalid window width %d\n", cs->cx );
1029 cs->cx = 0;
1030 }
1031 if (cs->cy < 0)
1032 {
1033 ERR( "invalid window height %d\n", cs->cy );
1034 cs->cy = 0;
1035 }
Michael Cardenasf0b6b9a2002-05-07 01:52:15 +00001036
Alexandre Julliardddc33172001-10-22 19:08:33 +00001037 /* initialize the dimensions before sending WM_GETMINMAXINFO */
1038 SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
Alexandre Julliardae661da2005-02-03 13:40:12 +00001039 X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER, NULL );
Alexandre Julliardddc33172001-10-22 19:08:33 +00001040
Alexandre Julliardf777d702005-01-31 16:34:07 +00001041 /* create an X window if it's a top level window */
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001042 if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
Alexandre Julliardf777d702005-01-31 16:34:07 +00001043 {
1044 if (!create_whole_window( display, data, cs->style )) goto failed;
1045 }
Alexandre Julliarddb6608a2006-03-27 22:43:03 +02001046 else if (hwnd == GetDesktopWindow())
1047 {
1048 get_desktop_xwin( display, data );
1049 }
Alexandre Julliard649637f2001-06-26 21:10:11 +00001050
Alexandre Julliard2fb7c872005-03-25 16:47:04 +00001051 /* get class or window DC if needed */
1052 alloc_window_dce( data );
1053
Rein Klazes0f2f2b32002-01-09 19:09:06 +00001054 /* Call the WH_CBT hook */
Alexandre Julliard2fb7c872005-03-25 16:47:04 +00001055
Robert Shearmancaec6022005-03-23 10:26:15 +00001056 /* the window style passed to the hook must be the real window style,
1057 * rather than just the window style that the caller to CreateWindowEx
1058 * passed in, so we have to copy the original CREATESTRUCT and get the
1059 * the real style. */
1060 cbcs = *cs;
1061 cbcs.style = GetWindowLongW(hwnd, GWL_STYLE);
1062
1063 cbtc.lpcs = &cbcs;
Dmitry Timoshkovc99317a2003-10-24 04:21:46 +00001064 cbtc.hwndInsertAfter = HWND_TOP;
Alexandre Julliard02861352002-10-29 00:41:42 +00001065 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode ))
Rein Klazes0f2f2b32002-01-09 19:09:06 +00001066 {
Alexandre Julliard02861352002-10-29 00:41:42 +00001067 TRACE("CBT-hook returned !0\n");
1068 goto failed;
Rein Klazes0f2f2b32002-01-09 19:09:06 +00001069 }
1070
Alexandre Julliardddc33172001-10-22 19:08:33 +00001071 /* Send the WM_GETMINMAXINFO message and fix the size if needed */
1072 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1073 {
1074 POINT maxSize, maxPos, minTrack, maxTrack;
1075
Alexandre Julliardddc33172001-10-22 19:08:33 +00001076 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1077 if (maxSize.x < cs->cx) cs->cx = maxSize.x;
1078 if (maxSize.y < cs->cy) cs->cy = maxSize.y;
Alexandre Julliardddc33172001-10-22 19:08:33 +00001079 if (cs->cx < 0) cs->cx = 0;
1080 if (cs->cy < 0) cs->cy = 0;
1081
Alexandre Julliardddc33172001-10-22 19:08:33 +00001082 SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
Alexandre Julliardae661da2005-02-03 13:40:12 +00001083 if (!X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER, NULL )) return FALSE;
Alexandre Julliardddc33172001-10-22 19:08:33 +00001084 }
Alexandre Julliardddc33172001-10-22 19:08:33 +00001085
Alexandre Julliard883cff42001-06-12 04:02:10 +00001086 /* send WM_NCCREATE */
Alexandre Julliarde0315e42002-10-31 02:38:20 +00001087 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cs->cx, cs->cy );
Alexandre Julliard883cff42001-06-12 04:02:10 +00001088 if (unicode)
1089 ret = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1090 else
1091 ret = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1092 if (!ret)
1093 {
Alexandre Julliardddc33172001-10-22 19:08:33 +00001094 WARN("aborted by WM_xxCREATE!\n");
Alexandre Julliard883cff42001-06-12 04:02:10 +00001095 return FALSE;
1096 }
1097
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001098 /* make sure the window is still valid */
1099 if (!(data = X11DRV_get_win_data( hwnd ))) return FALSE;
Alexandre Julliardf777d702005-01-31 16:34:07 +00001100 if (data->whole_window) X11DRV_sync_window_style( display, data );
Alexandre Julliard883cff42001-06-12 04:02:10 +00001101
1102 /* send WM_NCCALCSIZE */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001103 rect = data->window_rect;
Alexandre Julliard883cff42001-06-12 04:02:10 +00001104 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect );
Alexandre Julliardddc33172001-10-22 19:08:33 +00001105
1106 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
Alexandre Julliard5defa492004-12-07 17:31:53 +00001107
1108 /* yes, even if the CBT hook was called with HWND_TOP */
1109 insert_after = ((wndPtr->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1110
Alexandre Julliardae661da2005-02-03 13:40:12 +00001111 X11DRV_set_window_pos( hwnd, insert_after, &wndPtr->rectWindow, &rect, 0, NULL );
Alexandre Julliard883cff42001-06-12 04:02:10 +00001112
Alexandre Julliardf777d702005-01-31 16:34:07 +00001113 TRACE( "win %p window %ld,%ld,%ld,%ld client %ld,%ld,%ld,%ld whole %ld,%ld,%ld,%ld X client %ld,%ld,%ld,%ld xwin %x\n",
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001114 hwnd, wndPtr->rectWindow.left, wndPtr->rectWindow.top,
1115 wndPtr->rectWindow.right, wndPtr->rectWindow.bottom,
1116 wndPtr->rectClient.left, wndPtr->rectClient.top,
1117 wndPtr->rectClient.right, wndPtr->rectClient.bottom,
1118 data->whole_rect.left, data->whole_rect.top,
1119 data->whole_rect.right, data->whole_rect.bottom,
1120 data->client_rect.left, data->client_rect.top,
1121 data->client_rect.right, data->client_rect.bottom,
Alexandre Julliardf777d702005-01-31 16:34:07 +00001122 (unsigned int)data->whole_window );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001123
Alexandre Julliardddc33172001-10-22 19:08:33 +00001124 WIN_ReleasePtr( wndPtr );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001125
Gerard Patelad363032001-06-06 21:26:50 +00001126 if (unicode)
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001127 ret = (SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
1128 else
1129 ret = (SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
1130
Alexandre Julliard4d32a472005-03-25 10:38:56 +00001131 if (!ret) return FALSE;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001132
Dmitry Timoshkov6dba0a72005-02-03 16:40:20 +00001133 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1134
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001135 /* Send the size messages */
1136
Alexandre Julliard6382ffa2005-01-20 20:07:42 +00001137 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return FALSE;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001138 if (!(wndPtr->flags & WIN_NEED_SIZE))
1139 {
Alexandre Julliard6382ffa2005-01-20 20:07:42 +00001140 RECT rect = wndPtr->rectClient;
1141 WIN_ReleasePtr( wndPtr );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001142 /* send it anyway */
Alexandre Julliard6382ffa2005-01-20 20:07:42 +00001143 if (((rect.right-rect.left) <0) ||((rect.bottom-rect.top)<0))
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001144 WARN("sending bogus WM_SIZE message 0x%08lx\n",
Alexandre Julliard6382ffa2005-01-20 20:07:42 +00001145 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001146 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
Alexandre Julliard6382ffa2005-01-20 20:07:42 +00001147 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1148 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001149 }
Alexandre Julliard6382ffa2005-01-20 20:07:42 +00001150 else WIN_ReleasePtr( wndPtr );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001151
1152 /* Show the window, maximizing or minimizing if needed */
1153
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001154 style = GetWindowLongW( hwnd, GWL_STYLE );
1155 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001156 {
1157 extern UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect ); /*FIXME*/
1158
1159 RECT newPos;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001160 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
Alexandre Julliardf9364282005-01-21 10:32:13 +00001161 WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001162 WINPOS_MinMaximize( hwnd, swFlag, &newPos );
Vitaliy Margolenaae76322005-11-30 12:32:22 +01001163
1164 swFlag = SWP_FRAMECHANGED | SWP_NOZORDER; /* Frame always gets changed */
1165 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1166
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001167 SetWindowPos( hwnd, 0, newPos.left, newPos.top,
1168 newPos.right, newPos.bottom, swFlag );
1169 }
1170
1171 return TRUE;
1172
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001173 failed:
Alexandre Julliardddc33172001-10-22 19:08:33 +00001174 X11DRV_DestroyWindow( hwnd );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001175 return FALSE;
1176}
1177
1178
1179/***********************************************************************
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001180 * X11DRV_get_win_data
1181 *
1182 * Return the X11 data structure associated with a window.
1183 */
1184struct x11drv_win_data *X11DRV_get_win_data( HWND hwnd )
1185{
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +00001186 char *data;
Alexandre Julliarde5515552005-02-09 14:01:40 +00001187
1188 if (!hwnd || XFindContext( thread_display(), (XID)hwnd, win_data_context, &data )) data = NULL;
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +00001189 return (struct x11drv_win_data *)data;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001190}
1191
1192
1193/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001194 * X11DRV_get_whole_window
1195 *
1196 * Return the X window associated with the full area of a window
1197 */
1198Window X11DRV_get_whole_window( HWND hwnd )
1199{
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001200 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
Alexandre Julliard8fd26b92001-10-15 17:56:45 +00001201
Alexandre Julliardaf50ad62005-07-07 17:30:57 +00001202 if (!data) return (Window)GetPropA( hwnd, whole_window_prop );
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001203 return data->whole_window;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001204}
1205
1206
Alexandre Julliard8b6a2192003-01-23 01:28:12 +00001207/***********************************************************************
1208 * X11DRV_get_ic
1209 *
1210 * Return the X input context associated with a window
1211 */
1212XIC X11DRV_get_ic( HWND hwnd )
1213{
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001214 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
Alexandre Julliard8b6a2192003-01-23 01:28:12 +00001215
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001216 if (!data) return 0;
1217 return data->xic;
Alexandre Julliard8b6a2192003-01-23 01:28:12 +00001218}
1219
1220
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001221/*****************************************************************
1222 * SetParent (X11DRV.@)
1223 */
1224HWND X11DRV_SetParent( HWND hwnd, HWND parent )
1225{
Alexandre Julliard43230042001-05-16 19:52:29 +00001226 Display *display = thread_display();
Alexandre Julliard4d32a472005-03-25 10:38:56 +00001227 WND *wndPtr;
1228 BOOL ret;
1229 HWND old_parent = 0;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001230
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001231 /* Windows hides the window first, then shows it again
1232 * including the WM_SHOWWINDOW messages and all */
Alexandre Julliardfb0ff052001-10-16 21:58:58 +00001233 BOOL was_visible = ShowWindow( hwnd, SW_HIDE );
1234
Alexandre Julliard4d32a472005-03-25 10:38:56 +00001235 wndPtr = WIN_GetPtr( hwnd );
1236 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001237
Alexandre Julliard4d32a472005-03-25 10:38:56 +00001238 SERVER_START_REQ( set_parent )
1239 {
1240 req->handle = hwnd;
1241 req->parent = parent;
1242 if ((ret = !wine_server_call( req )))
1243 {
1244 old_parent = reply->old_parent;
1245 wndPtr->parent = parent = reply->full_parent;
1246 }
1247
1248 }
1249 SERVER_END_REQ;
1250 WIN_ReleasePtr( wndPtr );
1251 if (!ret) return 0;
1252
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +00001253 if (parent != old_parent)
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001254 {
Alexandre Julliard4d32a472005-03-25 10:38:56 +00001255 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001256
Alexandre Julliard4d32a472005-03-25 10:38:56 +00001257 if (!data) return 0;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001258
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001259 if (parent != GetDesktopWindow()) /* a child window */
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001260 {
Alexandre Julliardf777d702005-01-31 16:34:07 +00001261 if (old_parent == GetDesktopWindow())
1262 {
1263 /* destroy the old X windows */
1264 destroy_whole_window( display, data );
1265 destroy_icon_window( display, data );
Dmitry Timoshkovd5e18042005-05-24 11:44:59 +00001266 if (data->managed)
1267 {
1268 data->managed = FALSE;
Alexandre Julliardaf50ad62005-07-07 17:30:57 +00001269 RemovePropA( data->hwnd, managed_prop );
Dmitry Timoshkovd5e18042005-05-24 11:44:59 +00001270 }
Alexandre Julliardf777d702005-01-31 16:34:07 +00001271 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001272 }
Alexandre Julliardf777d702005-01-31 16:34:07 +00001273 else /* new top level window */
1274 {
1275 /* FIXME: we ignore errors since we can't really recover anyway */
1276 create_whole_window( display, data, GetWindowLongW( hwnd, GWL_STYLE ) );
1277 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001278 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001279
1280 /* SetParent additionally needs to make hwnd the topmost window
1281 in the x-order and send the expected WM_WINDOWPOSCHANGING and
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00001282 WM_WINDOWPOSCHANGED notification messages.
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001283 */
1284 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
Alexandre Julliardfb0ff052001-10-16 21:58:58 +00001285 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001286 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
1287 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
1288
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +00001289 return old_parent;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001290}
1291
1292
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001293/*****************************************************************
1294 * SetFocus (X11DRV.@)
1295 *
1296 * Set the X focus.
1297 * Explicit colormap management seems to work only with OLVWM.
1298 */
1299void X11DRV_SetFocus( HWND hwnd )
1300{
Alexandre Julliard43230042001-05-16 19:52:29 +00001301 Display *display = thread_display();
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001302 struct x11drv_win_data *data;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001303 XWindowAttributes win_attr;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001304
1305 /* Only mess with the X focus if there's */
1306 /* no desktop window and if the window is not managed by the WM. */
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00001307 if (root_window != DefaultRootWindow(display)) return;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001308
1309 if (!hwnd) /* If setting the focus to 0, uninstall the colormap */
1310 {
Alexandre Julliard2496c082003-11-21 00:17:33 +00001311 wine_tsx11_lock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001312 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
Alexandre Julliard2496c082003-11-21 00:17:33 +00001313 XUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
1314 wine_tsx11_unlock();
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00001315 return;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001316 }
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00001317
1318 hwnd = GetAncestor( hwnd, GA_ROOT );
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001319
1320 if (!(data = X11DRV_get_win_data( hwnd ))) return;
Todd Mokros88ac4b92005-08-22 09:14:21 +00001321 if (data->managed || !data->whole_window) return;
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00001322
1323 /* Set X focus and install colormap */
1324 wine_tsx11_lock();
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001325 if (XGetWindowAttributes( display, data->whole_window, &win_attr ) &&
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00001326 (win_attr.map_state == IsViewable))
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001327 {
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00001328 /* If window is not viewable, don't change anything */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001329
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00001330 /* we must not use CurrentTime (ICCCM), so try to use last message time instead */
1331 /* FIXME: this is not entirely correct */
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001332 XSetInputFocus( display, data->whole_window, RevertToParent,
Jeremy White77502e72005-01-14 17:06:40 +00001333 /* CurrentTime */
1334 GetMessageTime() - EVENT_x11_time_to_win32_time(0));
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00001335 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
1336 XInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001337 }
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00001338 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001339}
1340
1341
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001342/**********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001343 * SetWindowIcon (X11DRV.@)
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001344 *
1345 * hIcon or hIconSm has changed (or is being initialised for the
1346 * first time). Complete the X11 driver-specific initialisation
1347 * and set the window hints.
1348 *
1349 * This is not entirely correct, may need to create
1350 * an icon window and set the pixmap as a background
1351 */
Alexandre Julliard446d8322003-12-31 23:51:52 +00001352void X11DRV_SetWindowIcon( HWND hwnd, UINT type, HICON icon )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001353{
Alexandre Julliard43230042001-05-16 19:52:29 +00001354 Display *display = thread_display();
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001355 struct x11drv_win_data *data;
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001356 XWMHints* wm_hints;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001357
Alexandre Julliard446d8322003-12-31 23:51:52 +00001358 if (type != ICON_BIG) return; /* nothing to do here */
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001359
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001360 if (!(data = X11DRV_get_win_data( hwnd ))) return;
Alexandre Julliardf777d702005-01-31 16:34:07 +00001361 if (!data->whole_window) return;
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001362 if (!data->managed) return;
Alexandre Julliard8fd26b92001-10-15 17:56:45 +00001363
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001364 wine_tsx11_lock();
1365 if (!(wm_hints = XGetWMHints( display, data->whole_window ))) wm_hints = XAllocWMHints();
1366 wine_tsx11_unlock();
1367 if (wm_hints)
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001368 {
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001369 set_icon_hints( display, data, wm_hints, icon );
Alexandre Julliarde9119c12002-09-24 18:36:51 +00001370 wine_tsx11_lock();
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001371 XSetWMHints( display, data->whole_window, wm_hints );
1372 XFree( wm_hints );
Alexandre Julliarde9119c12002-09-24 18:36:51 +00001373 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001374 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001375}