Added function table to GDI objects for better encapsulation.
[wine.git] / dlls / x11drv / window.c
blobb90bce9648b661b4c27f0fa9b56710b6f0c43cfa
1 /*
2 * Window related functions
4 * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
5 * Copyright 1993 David Metcalfe
6 * Copyright 1995, 1996 Alex Korobka
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.
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.
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
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
25 #include <stdlib.h>
27 #include "ts_xlib.h"
28 #include "ts_xutil.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winreg.h"
33 #include "winuser.h"
34 #include "wine/unicode.h"
36 #include "wine/debug.h"
37 #include "x11drv.h"
38 #include "win.h"
39 #include "winpos.h"
40 #include "dce.h"
41 #include "hook.h"
42 #include "mwm.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
46 extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
48 #define HAS_DLGFRAME(style,exStyle) \
49 (((exStyle) & WS_EX_DLGMODALFRAME) || \
50 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
52 /* X context to associate a hwnd to an X window */
53 XContext winContext = 0;
55 Atom wmProtocols = None;
56 Atom wmDeleteWindow = None;
57 Atom wmTakeFocus = None;
58 Atom dndProtocol = None;
59 Atom dndSelection = None;
60 Atom wmChangeState = None;
61 Atom mwmHints = None;
62 Atom kwmDockWindow = None;
63 Atom _kde_net_wm_system_tray_window_for = None; /* KDE 2 Final */
65 static LPCSTR whole_window_atom;
66 static LPCSTR client_window_atom;
67 static LPCSTR icon_window_atom;
69 /***********************************************************************
70 * is_window_managed
72 * Check if a given window should be managed
74 inline static BOOL is_window_managed( WND *win )
76 if (!managed_mode) return FALSE;
77 /* tray window is always managed */
78 if (win->dwExStyle & WS_EX_TRAYWINDOW) return TRUE;
79 /* child windows are not managed */
80 if (win->dwStyle & WS_CHILD) return FALSE;
81 /* tool windows are not managed */
82 if (win->dwExStyle & WS_EX_TOOLWINDOW) return FALSE;
83 /* windows with caption or thick frame are managed */
84 if ((win->dwStyle & WS_CAPTION) == WS_CAPTION) return TRUE;
85 if (win->dwStyle & WS_THICKFRAME) return TRUE;
86 /* default: not managed */
87 return FALSE;
91 /***********************************************************************
92 * is_window_top_level
94 * Check if a given window is a top level X11 window
96 inline static BOOL is_window_top_level( WND *win )
98 return (root_window == DefaultRootWindow(gdi_display) && win->parent == GetDesktopWindow());
102 /***********************************************************************
103 * is_client_window_mapped
105 * Check if the X client window should be mapped
107 inline static BOOL is_client_window_mapped( WND *win )
109 struct x11drv_win_data *data = win->pDriverData;
110 return !(win->dwStyle & WS_MINIMIZE) && !IsRectEmpty( &data->client_rect );
114 /***********************************************************************
115 * get_window_attributes
117 * Fill the window attributes structure for an X window.
118 * Returned cursor must be freed by caller.
120 static int get_window_attributes( Display *display, WND *win, XSetWindowAttributes *attr )
122 BOOL is_top_level = is_window_top_level( win );
123 BOOL managed = is_top_level && is_window_managed( win );
125 if (managed) WIN_SetExStyle( win->hwndSelf, win->dwExStyle | WS_EX_MANAGED );
126 else WIN_SetExStyle( win->hwndSelf, win->dwExStyle & ~WS_EX_MANAGED );
128 attr->override_redirect = !managed;
129 attr->colormap = X11DRV_PALETTE_PaletteXColormap;
130 attr->save_under = ((win->clsStyle & CS_SAVEBITS) != 0);
131 attr->cursor = None;
132 attr->event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
133 ButtonPressMask | ButtonReleaseMask);
134 if (is_window_top_level( win ))
136 attr->event_mask |= StructureNotifyMask | FocusChangeMask | KeymapStateMask;
137 attr->cursor = X11DRV_GetCursor( display, GlobalLock16(GetCursor()) );
139 return (CWOverrideRedirect | CWSaveUnder | CWEventMask | CWColormap | CWCursor);
143 /***********************************************************************
144 * sync_window_style
146 * Change the X window attributes when the window style has changed.
148 static void sync_window_style( Display *display, WND *win )
150 XSetWindowAttributes attr;
151 int mask;
153 wine_tsx11_lock();
154 mask = get_window_attributes( display, win, &attr );
155 XChangeWindowAttributes( display, get_whole_window(win), mask, &attr );
156 if (attr.cursor) XFreeCursor( display, attr.cursor );
157 wine_tsx11_unlock();
161 /***********************************************************************
162 * get_window_changes
164 * fill the window changes structure
166 static int get_window_changes( XWindowChanges *changes, const RECT *old, const RECT *new )
168 int mask = 0;
170 if (old->right - old->left != new->right - new->left )
172 if (!(changes->width = new->right - new->left)) changes->width = 1;
173 mask |= CWWidth;
175 if (old->bottom - old->top != new->bottom - new->top)
177 if (!(changes->height = new->bottom - new->top)) changes->height = 1;
178 mask |= CWHeight;
180 if (old->left != new->left)
182 changes->x = new->left;
183 mask |= CWX;
185 if (old->top != new->top)
187 changes->y = new->top;
188 mask |= CWY;
190 return mask;
194 /***********************************************************************
195 * create_icon_window
197 static Window create_icon_window( Display *display, WND *win )
199 struct x11drv_win_data *data = win->pDriverData;
200 XSetWindowAttributes attr;
202 attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
203 ButtonPressMask | ButtonReleaseMask);
204 attr.bit_gravity = NorthWestGravity;
205 attr.backing_store = NotUseful/*WhenMapped*/;
206 attr.colormap = X11DRV_PALETTE_PaletteXColormap; /* Needed due to our visual */
208 wine_tsx11_lock();
209 data->icon_window = XCreateWindow( display, root_window, 0, 0,
210 GetSystemMetrics( SM_CXICON ),
211 GetSystemMetrics( SM_CYICON ),
212 0, screen_depth,
213 InputOutput, visual,
214 CWEventMask | CWBitGravity | CWBackingStore | CWColormap, &attr );
215 XSaveContext( display, data->icon_window, winContext, (char *)win->hwndSelf );
216 wine_tsx11_unlock();
218 TRACE( "created %lx\n", data->icon_window );
219 SetPropA( win->hwndSelf, icon_window_atom, (HANDLE)data->icon_window );
220 return data->icon_window;
225 /***********************************************************************
226 * destroy_icon_window
228 inline static void destroy_icon_window( Display *display, WND *win )
230 struct x11drv_win_data *data = win->pDriverData;
232 if (!data->icon_window) return;
233 wine_tsx11_lock();
234 XDeleteContext( display, data->icon_window, winContext );
235 XDestroyWindow( display, data->icon_window );
236 data->icon_window = 0;
237 wine_tsx11_unlock();
238 RemovePropA( win->hwndSelf, icon_window_atom );
242 /***********************************************************************
243 * set_icon_hints
245 * Set the icon wm hints
247 static void set_icon_hints( Display *display, WND *wndPtr, XWMHints *hints )
249 X11DRV_WND_DATA *data = wndPtr->pDriverData;
250 HICON hIcon = GetClassLongA( wndPtr->hwndSelf, GCL_HICON );
252 if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
253 if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
254 data->hWMIconBitmap = 0;
255 data->hWMIconMask = 0;
257 if (!(wndPtr->dwExStyle & WS_EX_MANAGED))
259 destroy_icon_window( display, wndPtr );
260 hints->flags &= ~(IconPixmapHint | IconMaskHint | IconWindowHint);
262 else if (!hIcon)
264 if (!data->icon_window) create_icon_window( display, wndPtr );
265 hints->icon_window = data->icon_window;
266 hints->flags = (hints->flags & ~(IconPixmapHint | IconMaskHint)) | IconWindowHint;
268 else
270 HBITMAP hbmOrig;
271 RECT rcMask;
272 BITMAP bmMask;
273 ICONINFO ii;
274 HDC hDC;
276 GetIconInfo(hIcon, &ii);
278 GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
279 rcMask.top = 0;
280 rcMask.left = 0;
281 rcMask.right = bmMask.bmWidth;
282 rcMask.bottom = bmMask.bmHeight;
284 hDC = CreateCompatibleDC(0);
285 hbmOrig = SelectObject(hDC, ii.hbmMask);
286 InvertRect(hDC, &rcMask);
287 SelectObject(hDC, ii.hbmColor); /* force the color bitmap to x11drv mode too */
288 SelectObject(hDC, hbmOrig);
289 DeleteDC(hDC);
291 data->hWMIconBitmap = ii.hbmColor;
292 data->hWMIconMask = ii.hbmMask;
294 hints->icon_pixmap = X11DRV_BITMAP_Pixmap(data->hWMIconBitmap);
295 hints->icon_mask = X11DRV_BITMAP_Pixmap(data->hWMIconMask);
296 destroy_icon_window( display, wndPtr );
297 hints->flags = (hints->flags & ~IconWindowHint) | IconPixmapHint | IconMaskHint;
302 /***********************************************************************
303 * set_size_hints
305 * set the window size hints
307 static void set_size_hints( Display *display, WND *win )
309 XSizeHints* size_hints;
310 struct x11drv_win_data *data = win->pDriverData;
312 if ((size_hints = XAllocSizeHints()))
314 size_hints->win_gravity = StaticGravity;
315 size_hints->x = data->whole_rect.left;
316 size_hints->y = data->whole_rect.top;
317 size_hints->flags = PWinGravity | PPosition;
319 if (HAS_DLGFRAME( win->dwStyle, win->dwExStyle ))
321 size_hints->max_width = data->whole_rect.right - data->whole_rect.left;
322 size_hints->max_height = data->whole_rect.bottom - data->whole_rect.top;
323 size_hints->min_width = size_hints->max_width;
324 size_hints->min_height = size_hints->max_height;
325 size_hints->flags |= PMinSize | PMaxSize;
327 XSetWMNormalHints( display, data->whole_window, size_hints );
328 XFree( size_hints );
333 /***********************************************************************
334 * set_wm_hints
336 * Set the window manager hints for a newly-created window
338 static void set_wm_hints( Display *display, WND *win )
340 struct x11drv_win_data *data = win->pDriverData;
341 Window group_leader;
342 XClassHint *class_hints;
343 XWMHints* wm_hints;
344 Atom protocols[2];
345 int i;
347 wine_tsx11_lock();
349 /* wm protocols */
350 i = 0;
351 protocols[i++] = wmDeleteWindow;
352 if (wmTakeFocus) protocols[i++] = wmTakeFocus;
353 XSetWMProtocols( display, data->whole_window, protocols, i );
355 /* class hints */
356 if ((class_hints = XAllocClassHint()))
358 class_hints->res_name = "wine";
359 class_hints->res_class = "Wine";
360 XSetClassHint( display, data->whole_window, class_hints );
361 XFree( class_hints );
364 /* transient for hint */
365 if (win->owner)
367 Window owner_win = X11DRV_get_whole_window( win->owner );
368 XSetTransientForHint( display, data->whole_window, owner_win );
369 group_leader = owner_win;
371 else group_leader = data->whole_window;
373 /* size hints */
374 set_size_hints( display, win );
376 /* systray properties (KDE only for now) */
377 if (win->dwExStyle & WS_EX_TRAYWINDOW)
379 int val = 1;
380 if (kwmDockWindow != None)
381 XChangeProperty( display, data->whole_window, kwmDockWindow, kwmDockWindow,
382 32, PropModeReplace, (char*)&val, 1 );
383 if (_kde_net_wm_system_tray_window_for != None)
384 XChangeProperty( display, data->whole_window, _kde_net_wm_system_tray_window_for,
385 XA_WINDOW, 32, PropModeReplace, (char*)&data->whole_window, 1 );
388 if (mwmHints != None)
390 MwmHints mwm_hints;
391 mwm_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
392 mwm_hints.functions = 0;
393 if ((win->dwStyle & WS_CAPTION) == WS_CAPTION) mwm_hints.functions |= MWM_FUNC_MOVE;
394 if (win->dwStyle & WS_THICKFRAME) mwm_hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
395 if (win->dwStyle & WS_MINIMIZE) mwm_hints.functions |= MWM_FUNC_MINIMIZE;
396 if (win->dwStyle & WS_MAXIMIZE) mwm_hints.functions |= MWM_FUNC_MAXIMIZE;
397 if (win->dwStyle & WS_SYSMENU) mwm_hints.functions |= MWM_FUNC_CLOSE;
398 mwm_hints.decorations = 0;
399 if ((win->dwStyle & WS_CAPTION) == WS_CAPTION) mwm_hints.decorations |= MWM_DECOR_TITLE;
400 if (win->dwExStyle & WS_EX_DLGMODALFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER;
401 else if (win->dwStyle & WS_THICKFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH;
402 else if ((win->dwStyle & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER;
403 else if (win->dwStyle & WS_BORDER) mwm_hints.decorations |= MWM_DECOR_BORDER;
404 else if (!(win->dwStyle & (WS_CHILD|WS_POPUP))) mwm_hints.decorations |= MWM_DECOR_BORDER;
405 if (win->dwStyle & WS_SYSMENU) mwm_hints.decorations |= MWM_DECOR_MENU;
406 if (win->dwStyle & WS_MINIMIZE) mwm_hints.decorations |= MWM_DECOR_MINIMIZE;
407 if (win->dwStyle & WS_MAXIMIZE) mwm_hints.decorations |= MWM_DECOR_MAXIMIZE;
409 XChangeProperty( display, data->whole_window, mwmHints, mwmHints, 32,
410 PropModeReplace, (char*)&mwm_hints, sizeof(mwm_hints)/sizeof(long) );
413 wine_tsx11_unlock();
415 /* wm hints */
416 if ((wm_hints = TSXAllocWMHints()))
418 wm_hints->flags = InputHint | StateHint | WindowGroupHint;
419 /* use globally active model if take focus is supported,
420 * passive model otherwise (cf. ICCCM) */
421 wm_hints->input = !wmTakeFocus;
423 set_icon_hints( display, win, wm_hints );
425 wm_hints->initial_state = (win->dwStyle & WS_MINIMIZE) ? IconicState : NormalState;
426 wm_hints->window_group = group_leader;
428 wine_tsx11_lock();
429 XSetWMHints( display, data->whole_window, wm_hints );
430 XFree(wm_hints);
431 wine_tsx11_unlock();
436 /***********************************************************************
437 * X11DRV_set_iconic_state
439 * Set the X11 iconic state according to the window style.
441 void X11DRV_set_iconic_state( WND *win )
443 Display *display = thread_display();
444 struct x11drv_win_data *data = win->pDriverData;
445 XWMHints* wm_hints;
446 BOOL iconic = IsIconic( win->hwndSelf );
448 wine_tsx11_lock();
450 if (iconic) XUnmapWindow( display, data->client_window );
451 else if (is_client_window_mapped( win )) XMapWindow( display, data->client_window );
453 if (!(wm_hints = XGetWMHints( display, data->whole_window ))) wm_hints = XAllocWMHints();
454 wm_hints->flags |= StateHint | IconPositionHint;
455 wm_hints->initial_state = iconic ? IconicState : NormalState;
456 wm_hints->icon_x = win->rectWindow.left;
457 wm_hints->icon_y = win->rectWindow.top;
458 XSetWMHints( display, data->whole_window, wm_hints );
460 if (win->dwStyle & WS_VISIBLE)
462 if (iconic)
463 XIconifyWindow( display, data->whole_window, DefaultScreen(display) );
464 else
465 if (!IsRectEmpty( &win->rectWindow )) XMapWindow( display, data->whole_window );
468 XFree(wm_hints);
469 wine_tsx11_unlock();
473 /***********************************************************************
474 * X11DRV_window_to_X_rect
476 * Convert a rect from client to X window coordinates
478 void X11DRV_window_to_X_rect( WND *win, RECT *rect )
480 RECT rc;
482 if (!(win->dwExStyle & WS_EX_MANAGED)) return;
483 if (IsRectEmpty( rect )) return;
485 rc.top = rc.bottom = rc.left = rc.right = 0;
487 AdjustWindowRectEx( &rc, win->dwStyle & ~(WS_HSCROLL|WS_VSCROLL), FALSE, win->dwExStyle );
489 rect->left -= rc.left;
490 rect->right -= rc.right;
491 rect->top -= rc.top;
492 rect->bottom -= rc.bottom;
493 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
494 if (rect->left >= rect->right) rect->right = rect->left + 1;
498 /***********************************************************************
499 * X11DRV_X_to_window_rect
501 * Opposite of X11DRV_window_to_X_rect
503 void X11DRV_X_to_window_rect( WND *win, RECT *rect )
505 if (!(win->dwExStyle & WS_EX_MANAGED)) return;
506 if (IsRectEmpty( rect )) return;
508 AdjustWindowRectEx( rect, win->dwStyle & ~(WS_HSCROLL|WS_VSCROLL), FALSE, win->dwExStyle );
510 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
511 if (rect->left >= rect->right) rect->right = rect->left + 1;
515 /***********************************************************************
516 * X11DRV_sync_whole_window_position
518 * Synchronize the X whole window position with the Windows one
520 int X11DRV_sync_whole_window_position( Display *display, WND *win, int zorder )
522 XWindowChanges changes;
523 int mask;
524 struct x11drv_win_data *data = win->pDriverData;
525 RECT whole_rect = win->rectWindow;
527 X11DRV_window_to_X_rect( win, &whole_rect );
528 mask = get_window_changes( &changes, &data->whole_rect, &whole_rect );
530 if (zorder)
532 /* find window that this one must be after */
533 HWND prev = GetWindow( win->hwndSelf, GW_HWNDPREV );
534 while (prev && !(GetWindowLongW( prev, GWL_STYLE ) & WS_VISIBLE))
535 prev = GetWindow( prev, GW_HWNDPREV );
536 if (!prev) /* top child */
538 changes.stack_mode = Above;
539 mask |= CWStackMode;
541 else
543 changes.stack_mode = Below;
544 changes.sibling = X11DRV_get_whole_window(prev);
545 mask |= CWStackMode | CWSibling;
549 data->whole_rect = whole_rect;
551 if (mask)
553 TRACE( "setting win %lx pos %d,%d,%dx%d after %lx changes=%x\n",
554 data->whole_window, whole_rect.left, whole_rect.top,
555 whole_rect.right - whole_rect.left, whole_rect.bottom - whole_rect.top,
556 changes.sibling, mask );
557 wine_tsx11_lock();
558 XSync( gdi_display, False ); /* flush graphics operations before moving the window */
559 if (is_window_top_level( win ))
561 if (mask & (CWWidth|CWHeight)) set_size_hints( display, win );
562 XReconfigureWMWindow( display, data->whole_window,
563 DefaultScreen(display), mask, &changes );
565 else XConfigureWindow( display, data->whole_window, mask, &changes );
566 wine_tsx11_unlock();
568 return mask;
572 /***********************************************************************
573 * X11DRV_sync_client_window_position
575 * Synchronize the X client window position with the Windows one
577 int X11DRV_sync_client_window_position( Display *display, WND *win )
579 XWindowChanges changes;
580 int mask;
581 struct x11drv_win_data *data = win->pDriverData;
582 RECT client_rect = win->rectClient;
584 OffsetRect( &client_rect, -data->whole_rect.left, -data->whole_rect.top );
586 if ((mask = get_window_changes( &changes, &data->client_rect, &client_rect )))
588 BOOL was_mapped = is_client_window_mapped( win );
590 TRACE( "setting win %lx pos %d,%d,%dx%d (was %d,%d,%dx%d) after %lx changes=%x\n",
591 data->client_window, client_rect.left, client_rect.top,
592 client_rect.right - client_rect.left, client_rect.bottom - client_rect.top,
593 data->client_rect.left, data->client_rect.top,
594 data->client_rect.right - data->client_rect.left,
595 data->client_rect.bottom - data->client_rect.top,
596 changes.sibling, mask );
597 data->client_rect = client_rect;
598 wine_tsx11_lock();
599 XSync( gdi_display, False ); /* flush graphics operations before moving the window */
600 if (was_mapped && !is_client_window_mapped( win ))
601 XUnmapWindow( display, data->client_window );
602 XConfigureWindow( display, data->client_window, mask, &changes );
603 if (!was_mapped && is_client_window_mapped( win ))
604 XMapWindow( display, data->client_window );
605 wine_tsx11_unlock();
607 return mask;
611 /***********************************************************************
612 * X11DRV_register_window
614 * Associate an X window to a HWND.
616 void X11DRV_register_window( Display *display, HWND hwnd, struct x11drv_win_data *data )
618 wine_tsx11_lock();
619 XSaveContext( display, data->whole_window, winContext, (char *)hwnd );
620 XSaveContext( display, data->client_window, winContext, (char *)hwnd );
621 wine_tsx11_unlock();
625 /**********************************************************************
626 * create_desktop
628 static void create_desktop( Display *display, WND *wndPtr, CREATESTRUCTA *cs )
630 X11DRV_WND_DATA *data = wndPtr->pDriverData;
632 wine_tsx11_lock();
633 winContext = XUniqueContext();
634 wmProtocols = XInternAtom( display, "WM_PROTOCOLS", False );
635 wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", False );
636 /* wmTakeFocus = XInternAtom( display, "WM_TAKE_FOCUS", False );*/
637 wmTakeFocus = 0; /* not yet */
638 dndProtocol = XInternAtom( display, "DndProtocol" , False );
639 dndSelection = XInternAtom( display, "DndSelection" , False );
640 wmChangeState = XInternAtom( display, "WM_CHANGE_STATE", False );
641 mwmHints = XInternAtom( display, _XA_MWM_HINTS, False );
642 kwmDockWindow = XInternAtom( display, "KWM_DOCKWINDOW", False );
643 _kde_net_wm_system_tray_window_for = XInternAtom( display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False );
644 wine_tsx11_unlock();
646 whole_window_atom = MAKEINTATOMA( GlobalAddAtomA( "__wine_x11_whole_window" ));
647 client_window_atom = MAKEINTATOMA( GlobalAddAtomA( "__wine_x11_client_window" ));
648 icon_window_atom = MAKEINTATOMA( GlobalAddAtomA( "__wine_x11_icon_window" ));
650 data->whole_window = data->client_window = root_window;
651 data->whole_rect = data->client_rect = wndPtr->rectWindow;
653 SetPropA( wndPtr->hwndSelf, whole_window_atom, (HANDLE)root_window );
654 SetPropA( wndPtr->hwndSelf, client_window_atom, (HANDLE)root_window );
655 SetPropA( wndPtr->hwndSelf, "__wine_x11_visual_id", (HANDLE)XVisualIDFromVisual(visual) );
657 SendMessageW( wndPtr->hwndSelf, WM_NCCREATE, 0, (LPARAM)cs );
658 if (root_window != DefaultRootWindow(display)) X11DRV_create_desktop_thread();
662 /**********************************************************************
663 * create_whole_window
665 * Create the whole X window for a given window
667 static Window create_whole_window( Display *display, WND *win )
669 struct x11drv_win_data *data = win->pDriverData;
670 int cx, cy, mask;
671 XSetWindowAttributes attr;
672 Window parent;
673 RECT rect;
674 BOOL is_top_level = is_window_top_level( win );
676 rect = win->rectWindow;
677 X11DRV_window_to_X_rect( win, &rect );
679 if (!(cx = rect.right - rect.left)) cx = 1;
680 if (!(cy = rect.bottom - rect.top)) cy = 1;
682 parent = X11DRV_get_client_window( win->parent );
684 wine_tsx11_lock();
686 mask = get_window_attributes( display, win, &attr );
688 /* set the attributes that don't change over the lifetime of the window */
689 attr.bit_gravity = ForgetGravity;
690 attr.win_gravity = NorthWestGravity;
691 attr.backing_store = NotUseful/*WhenMapped*/;
692 mask |= CWBitGravity | CWWinGravity | CWBackingStore;
694 data->whole_rect = rect;
695 data->whole_window = XCreateWindow( display, parent, rect.left, rect.top, cx, cy,
696 0, screen_depth, InputOutput, visual,
697 mask, &attr );
698 if (attr.cursor) XFreeCursor( display, attr.cursor );
700 if (!data->whole_window)
702 wine_tsx11_unlock();
703 return 0;
706 /* non-maximized child must be at bottom of Z order */
707 if ((win->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
709 XWindowChanges changes;
710 changes.stack_mode = Below;
711 XConfigureWindow( display, data->whole_window, CWStackMode, &changes );
714 wine_tsx11_unlock();
716 if (is_top_level) set_wm_hints( display, win );
718 return data->whole_window;
722 /**********************************************************************
723 * create_client_window
725 * Create the client window for a given window
727 static Window create_client_window( Display *display, WND *win )
729 struct x11drv_win_data *data = win->pDriverData;
730 RECT rect = data->whole_rect;
731 XSetWindowAttributes attr;
733 OffsetRect( &rect, -data->whole_rect.left, -data->whole_rect.top );
734 data->client_rect = rect;
736 attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
737 ButtonPressMask | ButtonReleaseMask);
738 attr.bit_gravity = (win->clsStyle & (CS_VREDRAW | CS_HREDRAW)) ?
739 ForgetGravity : NorthWestGravity;
740 attr.backing_store = NotUseful/*WhenMapped*/;
742 wine_tsx11_lock();
743 data->client_window = XCreateWindow( display, data->whole_window, 0, 0,
744 max( rect.right - rect.left, 1 ),
745 max( rect.bottom - rect.top, 1 ),
746 0, screen_depth,
747 InputOutput, visual,
748 CWEventMask | CWBitGravity | CWBackingStore, &attr );
749 if (data->client_window && is_client_window_mapped( win ))
750 XMapWindow( display, data->client_window );
751 wine_tsx11_unlock();
752 return data->client_window;
756 /*****************************************************************
757 * SetWindowText (X11DRV.@)
759 BOOL X11DRV_SetWindowText( HWND hwnd, LPCWSTR text )
761 Display *display = thread_display();
762 UINT count;
763 char *buffer;
764 char *utf8_buffer;
765 static UINT text_cp = (UINT)-1;
766 Window win;
768 if ((win = X11DRV_get_whole_window( hwnd )))
770 if (text_cp == (UINT)-1)
772 HKEY hkey;
773 /* default value */
774 text_cp = CP_ACP;
775 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
777 char buffer[20];
778 DWORD type, count = sizeof(buffer);
779 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buffer, &count))
780 text_cp = atoi(buffer);
781 RegCloseKey(hkey);
783 TRACE("text_cp = %u\n", text_cp);
786 /* allocate new buffer for window text */
787 count = WideCharToMultiByte(text_cp, 0, text, -1, NULL, 0, NULL, NULL);
788 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count )))
790 ERR("Not enough memory for window text\n");
791 return FALSE;
793 WideCharToMultiByte(text_cp, 0, text, -1, buffer, count, NULL, NULL);
795 count = WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), NULL, 0, NULL, NULL);
796 if (!(utf8_buffer = HeapAlloc( GetProcessHeap(), 0, count )))
798 ERR("Not enough memory for window text in UTF-8\n");
799 return FALSE;
801 WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), utf8_buffer, count, NULL, NULL);
803 wine_tsx11_lock();
804 XStoreName( display, win, buffer );
805 XSetIconName( display, win, buffer );
807 Implements a NET_WM UTF-8 title. It should be without a trailing \0,
808 according to the standard
809 ( http://www.pps.jussieu.fr/~jch/software/UTF8_STRING/UTF8_STRING.text ).
811 XChangeProperty( display, win,
812 XInternAtom(display, "_NET_WM_NAME", False),
813 XInternAtom(display, "UTF8_STRING", False),
814 8, PropModeReplace, (unsigned char *) utf8_buffer,
815 count);
816 wine_tsx11_unlock();
818 HeapFree( GetProcessHeap(), 0, utf8_buffer );
819 HeapFree( GetProcessHeap(), 0, buffer );
821 return TRUE;
825 /***********************************************************************
826 * DestroyWindow (X11DRV.@)
828 BOOL X11DRV_DestroyWindow( HWND hwnd )
830 Display *display = thread_display();
831 WND *wndPtr = WIN_GetPtr( hwnd );
832 X11DRV_WND_DATA *data = wndPtr->pDriverData;
834 if (!data) goto done;
836 if (data->whole_window)
838 TRACE( "win %x xwin %lx/%lx\n", hwnd, data->whole_window, data->client_window );
839 wine_tsx11_lock();
840 XSync( gdi_display, False ); /* flush any reference to this drawable in GDI queue */
841 XDeleteContext( display, data->whole_window, winContext );
842 XDeleteContext( display, data->client_window, winContext );
843 XDestroyWindow( display, data->whole_window ); /* this destroys client too */
844 destroy_icon_window( display, wndPtr );
845 wine_tsx11_unlock();
848 if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
849 if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
850 HeapFree( GetProcessHeap(), 0, data );
851 wndPtr->pDriverData = NULL;
852 done:
853 WIN_ReleasePtr( wndPtr );
854 return TRUE;
858 /**********************************************************************
859 * CreateWindow (X11DRV.@)
861 BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
863 HWND hwndLinkAfter;
864 Display *display = thread_display();
865 WND *wndPtr;
866 struct x11drv_win_data *data;
867 RECT rect;
868 BOOL ret = FALSE;
870 if (cs->cx > 65535)
872 ERR( "invalid window width %d\n", cs->cx );
873 cs->cx = 65535;
875 if (cs->cy > 65535)
877 ERR( "invalid window height %d\n", cs->cx );
878 cs->cy = 65535;
881 if (!(data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data)))) return FALSE;
882 data->whole_window = 0;
883 data->client_window = 0;
884 data->icon_window = 0;
885 data->hWMIconBitmap = 0;
886 data->hWMIconMask = 0;
888 wndPtr = WIN_GetPtr( hwnd );
889 wndPtr->pDriverData = data;
891 /* initialize the dimensions before sending WM_GETMINMAXINFO */
892 SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
893 WIN_SetRectangles( hwnd, &rect, &rect );
895 if (!wndPtr->parent)
897 create_desktop( display, wndPtr, cs );
898 WIN_ReleasePtr( wndPtr );
899 return TRUE;
902 if (!create_whole_window( display, wndPtr )) goto failed;
903 if (!create_client_window( display, wndPtr )) goto failed;
904 TSXSync( display, False );
906 SetPropA( hwnd, whole_window_atom, (HANDLE)data->whole_window );
907 SetPropA( hwnd, client_window_atom, (HANDLE)data->client_window );
909 /* Call the WH_CBT hook */
911 hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
912 ? HWND_BOTTOM : HWND_TOP;
914 if (HOOK_IsHooked( WH_CBT ))
916 CBT_CREATEWNDA cbtc;
917 LRESULT lret;
919 cbtc.lpcs = cs;
920 cbtc.hwndInsertAfter = hwndLinkAfter;
921 lret = (unicode) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND,
922 (WPARAM)hwnd, (LPARAM)&cbtc)
923 : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND,
924 (WPARAM)hwnd, (LPARAM)&cbtc);
925 if (lret)
927 TRACE("CBT-hook returned !0\n");
928 goto failed;
934 /* Send the WM_GETMINMAXINFO message and fix the size if needed */
935 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
937 POINT maxSize, maxPos, minTrack, maxTrack;
939 WIN_ReleasePtr( wndPtr );
940 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
941 if (maxSize.x < cs->cx) cs->cx = maxSize.x;
942 if (maxSize.y < cs->cy) cs->cy = maxSize.y;
943 if (cs->cx < minTrack.x ) cs->cx = minTrack.x;
944 if (cs->cy < minTrack.y ) cs->cy = minTrack.y;
945 if (cs->cx < 0) cs->cx = 0;
946 if (cs->cy < 0) cs->cy = 0;
948 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
949 SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
950 WIN_SetRectangles( hwnd, &rect, &rect );
951 X11DRV_sync_whole_window_position( display, wndPtr, 0 );
953 WIN_ReleasePtr( wndPtr );
955 /* send WM_NCCREATE */
956 TRACE( "hwnd %x cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cs->cx, cs->cy );
957 if (unicode)
958 ret = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
959 else
960 ret = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
961 if (!ret)
963 WARN("aborted by WM_xxCREATE!\n");
964 return FALSE;
967 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
969 sync_window_style( display, wndPtr );
971 /* send WM_NCCALCSIZE */
972 rect = wndPtr->rectWindow;
973 WIN_ReleasePtr( wndPtr );
974 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect );
976 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
977 if (rect.left > rect.right || rect.top > rect.bottom) rect = wndPtr->rectWindow;
978 WIN_SetRectangles( hwnd, &wndPtr->rectWindow, &rect );
979 X11DRV_sync_client_window_position( display, wndPtr );
980 X11DRV_register_window( display, hwnd, data );
982 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",
983 hwnd, wndPtr->rectWindow.left, wndPtr->rectWindow.top,
984 wndPtr->rectWindow.right, wndPtr->rectWindow.bottom,
985 wndPtr->rectClient.left, wndPtr->rectClient.top,
986 wndPtr->rectClient.right, wndPtr->rectClient.bottom,
987 data->whole_rect.left, data->whole_rect.top,
988 data->whole_rect.right, data->whole_rect.bottom,
989 data->client_rect.left, data->client_rect.top,
990 data->client_rect.right, data->client_rect.bottom,
991 (unsigned int)data->whole_window, (unsigned int)data->client_window );
993 if ((wndPtr->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
994 WIN_LinkWindow( hwnd, wndPtr->parent, HWND_BOTTOM );
995 else
996 WIN_LinkWindow( hwnd, wndPtr->parent, HWND_TOP );
998 WIN_ReleasePtr( wndPtr );
1000 if (unicode)
1001 ret = (SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
1002 else
1003 ret = (SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
1005 if (!ret)
1007 WIN_UnlinkWindow( hwnd );
1008 return FALSE;
1011 /* Send the size messages */
1013 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1014 if (!(wndPtr->flags & WIN_NEED_SIZE))
1016 /* send it anyway */
1017 if (((wndPtr->rectClient.right-wndPtr->rectClient.left) <0)
1018 ||((wndPtr->rectClient.bottom-wndPtr->rectClient.top)<0))
1019 WARN("sending bogus WM_SIZE message 0x%08lx\n",
1020 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
1021 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
1022 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1023 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
1024 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
1025 SendMessageW( hwnd, WM_MOVE, 0,
1026 MAKELONG( wndPtr->rectClient.left, wndPtr->rectClient.top ) );
1029 /* Show the window, maximizing or minimizing if needed */
1031 if (wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE))
1033 extern UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect ); /*FIXME*/
1035 RECT newPos;
1036 UINT swFlag = (wndPtr->dwStyle & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1037 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~(WS_MAXIMIZE | WS_MINIMIZE) );
1038 WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1039 swFlag = ((wndPtr->dwStyle & WS_CHILD) || GetActiveWindow())
1040 ? SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED
1041 : SWP_NOZORDER | SWP_FRAMECHANGED;
1042 SetWindowPos( hwnd, 0, newPos.left, newPos.top,
1043 newPos.right, newPos.bottom, swFlag );
1046 WIN_ReleaseWndPtr( wndPtr );
1047 return TRUE;
1050 failed:
1051 X11DRV_DestroyWindow( hwnd );
1052 if (wndPtr) WIN_ReleasePtr( wndPtr );
1053 return FALSE;
1057 /***********************************************************************
1058 * X11DRV_get_client_window
1060 * Return the X window associated with the client area of a window
1062 Window X11DRV_get_client_window( HWND hwnd )
1064 Window ret = 0;
1065 WND *win = WIN_GetPtr( hwnd );
1067 if (win == WND_OTHER_PROCESS)
1068 return GetPropA( hwnd, client_window_atom );
1070 if (win)
1072 struct x11drv_win_data *data = win->pDriverData;
1073 ret = data->client_window;
1074 WIN_ReleasePtr( win );
1076 return ret;
1080 /***********************************************************************
1081 * X11DRV_get_whole_window
1083 * Return the X window associated with the full area of a window
1085 Window X11DRV_get_whole_window( HWND hwnd )
1087 Window ret = 0;
1088 WND *win = WIN_GetPtr( hwnd );
1090 if (win == WND_OTHER_PROCESS)
1091 return GetPropA( hwnd, whole_window_atom );
1093 if (win)
1095 struct x11drv_win_data *data = win->pDriverData;
1096 ret = data->whole_window;
1097 WIN_ReleasePtr( win );
1099 return ret;
1103 /*****************************************************************
1104 * SetParent (X11DRV.@)
1106 HWND X11DRV_SetParent( HWND hwnd, HWND parent )
1108 Display *display = thread_display();
1109 WND *wndPtr;
1110 HWND retvalue;
1112 /* Windows hides the window first, then shows it again
1113 * including the WM_SHOWWINDOW messages and all */
1114 BOOL was_visible = ShowWindow( hwnd, SW_HIDE );
1116 if (!IsWindow( parent )) return 0;
1117 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
1119 retvalue = wndPtr->parent; /* old parent */
1120 if (parent != retvalue)
1122 struct x11drv_win_data *data = wndPtr->pDriverData;
1124 WIN_LinkWindow( hwnd, parent, HWND_TOP );
1126 if (parent != GetDesktopWindow()) /* a child window */
1128 if (!(wndPtr->dwStyle & WS_CHILD))
1130 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
1131 if (menu) DestroyMenu( menu );
1135 if (is_window_top_level( wndPtr )) set_wm_hints( display, wndPtr );
1136 wine_tsx11_lock();
1137 sync_window_style( display, wndPtr );
1138 XReparentWindow( display, data->whole_window, X11DRV_get_client_window(parent),
1139 data->whole_rect.left, data->whole_rect.top );
1140 wine_tsx11_unlock();
1142 WIN_ReleasePtr( wndPtr );
1144 /* SetParent additionally needs to make hwnd the topmost window
1145 in the x-order and send the expected WM_WINDOWPOSCHANGING and
1146 WM_WINDOWPOSCHANGED notification messages.
1148 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
1149 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
1150 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
1151 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
1153 return retvalue;
1157 /*****************************************************************
1158 * SetFocus (X11DRV.@)
1160 * Set the X focus.
1161 * Explicit colormap management seems to work only with OLVWM.
1163 void X11DRV_SetFocus( HWND hwnd )
1165 Display *display = thread_display();
1166 XWindowAttributes win_attr;
1167 Window win;
1169 /* Only mess with the X focus if there's */
1170 /* no desktop window and if the window is not managed by the WM. */
1171 if (root_window != DefaultRootWindow(display)) return;
1173 if (!hwnd) /* If setting the focus to 0, uninstall the colormap */
1175 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
1176 TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
1177 return;
1180 hwnd = GetAncestor( hwnd, GA_ROOT );
1181 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MANAGED) return;
1182 if (!(win = X11DRV_get_whole_window( hwnd ))) return;
1184 /* Set X focus and install colormap */
1185 wine_tsx11_lock();
1186 if (XGetWindowAttributes( display, win, &win_attr ) &&
1187 (win_attr.map_state == IsViewable))
1189 /* If window is not viewable, don't change anything */
1191 /* we must not use CurrentTime (ICCCM), so try to use last message time instead */
1192 /* FIXME: this is not entirely correct */
1193 XSetInputFocus( display, win, RevertToParent,
1194 /*CurrentTime*/ GetMessageTime() + X11DRV_server_startticks );
1195 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
1196 XInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
1198 wine_tsx11_unlock();
1202 /**********************************************************************
1203 * SetWindowIcon (X11DRV.@)
1205 * hIcon or hIconSm has changed (or is being initialised for the
1206 * first time). Complete the X11 driver-specific initialisation
1207 * and set the window hints.
1209 * This is not entirely correct, may need to create
1210 * an icon window and set the pixmap as a background
1212 HICON X11DRV_SetWindowIcon( HWND hwnd, HICON icon, BOOL small )
1214 WND *wndPtr;
1215 Display *display = thread_display();
1216 HICON old = SetClassLongW( hwnd, small ? GCL_HICONSM : GCL_HICON, icon );
1218 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE |
1219 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1221 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return old;
1223 if (wndPtr->dwExStyle & WS_EX_MANAGED)
1225 Window win = get_whole_window(wndPtr);
1226 XWMHints* wm_hints = TSXGetWMHints( display, win );
1228 if (!wm_hints) wm_hints = TSXAllocWMHints();
1229 if (wm_hints)
1231 set_icon_hints( display, wndPtr, wm_hints );
1232 TSXSetWMHints( display, win, wm_hints );
1233 TSXFree( wm_hints );
1236 WIN_ReleasePtr( wndPtr );
1237 return old;