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
32 #include <X11/Xresource.h>
33 #include <X11/Xutil.h>
40 #include "wine/unicode.h"
42 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(x11drv
);
50 extern Pixmap
X11DRV_BITMAP_Pixmap( HBITMAP
);
52 #define HAS_DLGFRAME(style,exStyle) \
53 (((exStyle) & WS_EX_DLGMODALFRAME) || \
54 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
56 /* X context to associate a hwnd to an X window */
57 XContext winContext
= 0;
59 Atom X11DRV_Atoms
[NB_XATOMS
- FIRST_XATOM
];
61 static const char * const atom_names
[NB_XATOMS
- FIRST_XATOM
] =
80 "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
106 static LPCSTR whole_window_atom
;
107 static LPCSTR client_window_atom
;
108 static LPCSTR icon_window_atom
;
110 /***********************************************************************
113 * Check if a given window should be managed
115 inline static BOOL
is_window_managed( WND
*win
)
117 if (!managed_mode
) return FALSE
;
118 /* tray window is always managed */
119 if (win
->dwExStyle
& WS_EX_TRAYWINDOW
) return TRUE
;
120 /* child windows are not managed */
121 if (win
->dwStyle
& WS_CHILD
) return FALSE
;
122 /* tool windows are not managed */
123 if (win
->dwExStyle
& WS_EX_TOOLWINDOW
) return FALSE
;
124 /* windows with caption or thick frame are managed */
125 if ((win
->dwStyle
& WS_CAPTION
) == WS_CAPTION
) return TRUE
;
126 if (win
->dwStyle
& WS_THICKFRAME
) return TRUE
;
127 /* default: not managed */
132 /***********************************************************************
133 * is_client_window_mapped
135 * Check if the X client window should be mapped
137 inline static BOOL
is_client_window_mapped( WND
*win
)
139 struct x11drv_win_data
*data
= win
->pDriverData
;
140 return !(win
->dwStyle
& WS_MINIMIZE
) && !IsRectEmpty( &data
->client_rect
);
144 /***********************************************************************
145 * get_window_attributes
147 * Fill the window attributes structure for an X window.
149 static int get_window_attributes( Display
*display
, WND
*win
, XSetWindowAttributes
*attr
)
151 BOOL is_top_level
= is_window_top_level( win
);
152 BOOL managed
= is_top_level
&& is_window_managed( win
);
154 if (managed
) WIN_SetExStyle( win
->hwndSelf
, win
->dwExStyle
| WS_EX_MANAGED
);
155 else WIN_SetExStyle( win
->hwndSelf
, win
->dwExStyle
& ~WS_EX_MANAGED
);
157 attr
->override_redirect
= !managed
;
158 attr
->colormap
= X11DRV_PALETTE_PaletteXColormap
;
159 attr
->save_under
= ((win
->clsStyle
& CS_SAVEBITS
) != 0);
160 attr
->cursor
= x11drv_thread_data()->cursor
;
161 attr
->event_mask
= (ExposureMask
| PointerMotionMask
|
162 ButtonPressMask
| ButtonReleaseMask
| EnterWindowMask
);
164 if (is_window_top_level( win
))
165 attr
->event_mask
|= (KeyPressMask
| KeyReleaseMask
| StructureNotifyMask
|
166 FocusChangeMask
| KeymapStateMask
);
168 return (CWOverrideRedirect
| CWSaveUnder
| CWEventMask
| CWColormap
| CWCursor
);
172 /***********************************************************************
173 * X11DRV_sync_window_style
175 * Change the X window attributes when the window style has changed.
177 void X11DRV_sync_window_style( Display
*display
, WND
*win
)
179 XSetWindowAttributes attr
;
183 mask
= get_window_attributes( display
, win
, &attr
);
184 XChangeWindowAttributes( display
, get_whole_window(win
), mask
, &attr
);
189 /***********************************************************************
192 * fill the window changes structure
194 static int get_window_changes( XWindowChanges
*changes
, const RECT
*old
, const RECT
*new )
198 if (old
->right
- old
->left
!= new->right
- new->left
)
200 if (!(changes
->width
= new->right
- new->left
)) changes
->width
= 1;
203 if (old
->bottom
- old
->top
!= new->bottom
- new->top
)
205 if (!(changes
->height
= new->bottom
- new->top
)) changes
->height
= 1;
208 if (old
->left
!= new->left
)
210 changes
->x
= new->left
;
213 if (old
->top
!= new->top
)
215 changes
->y
= new->top
;
222 /***********************************************************************
225 static Window
create_icon_window( Display
*display
, WND
*win
)
227 struct x11drv_win_data
*data
= win
->pDriverData
;
228 XSetWindowAttributes attr
;
230 attr
.event_mask
= (ExposureMask
| KeyPressMask
| KeyReleaseMask
| PointerMotionMask
|
231 ButtonPressMask
| ButtonReleaseMask
| EnterWindowMask
);
232 attr
.bit_gravity
= NorthWestGravity
;
233 attr
.backing_store
= NotUseful
/*WhenMapped*/;
234 attr
.colormap
= X11DRV_PALETTE_PaletteXColormap
; /* Needed due to our visual */
237 data
->icon_window
= XCreateWindow( display
, root_window
, 0, 0,
238 GetSystemMetrics( SM_CXICON
),
239 GetSystemMetrics( SM_CYICON
),
242 CWEventMask
| CWBitGravity
| CWBackingStore
| CWColormap
, &attr
);
243 XSaveContext( display
, data
->icon_window
, winContext
, (char *)win
->hwndSelf
);
246 TRACE( "created %lx\n", data
->icon_window
);
247 SetPropA( win
->hwndSelf
, icon_window_atom
, (HANDLE
)data
->icon_window
);
248 return data
->icon_window
;
253 /***********************************************************************
254 * destroy_icon_window
256 inline static void destroy_icon_window( Display
*display
, WND
*win
)
258 struct x11drv_win_data
*data
= win
->pDriverData
;
260 if (!data
->icon_window
) return;
261 if (x11drv_thread_data()->cursor_window
== data
->icon_window
)
262 x11drv_thread_data()->cursor_window
= None
;
264 XDeleteContext( display
, data
->icon_window
, winContext
);
265 XDestroyWindow( display
, data
->icon_window
);
266 data
->icon_window
= 0;
268 RemovePropA( win
->hwndSelf
, icon_window_atom
);
272 /***********************************************************************
275 * Set the icon wm hints
277 static void set_icon_hints( Display
*display
, WND
*wndPtr
, XWMHints
*hints
)
279 X11DRV_WND_DATA
*data
= wndPtr
->pDriverData
;
280 HICON hIcon
= (HICON
)GetClassLongA( wndPtr
->hwndSelf
, GCL_HICON
);
282 if (data
->hWMIconBitmap
) DeleteObject( data
->hWMIconBitmap
);
283 if (data
->hWMIconMask
) DeleteObject( data
->hWMIconMask
);
284 data
->hWMIconBitmap
= 0;
285 data
->hWMIconMask
= 0;
287 if (!(wndPtr
->dwExStyle
& WS_EX_MANAGED
))
289 destroy_icon_window( display
, wndPtr
);
290 hints
->flags
&= ~(IconPixmapHint
| IconMaskHint
| IconWindowHint
);
294 if (!data
->icon_window
) create_icon_window( display
, wndPtr
);
295 hints
->icon_window
= data
->icon_window
;
296 hints
->flags
= (hints
->flags
& ~(IconPixmapHint
| IconMaskHint
)) | IconWindowHint
;
306 GetIconInfo(hIcon
, &ii
);
308 GetObjectA(ii
.hbmMask
, sizeof(bmMask
), &bmMask
);
311 rcMask
.right
= bmMask
.bmWidth
;
312 rcMask
.bottom
= bmMask
.bmHeight
;
314 hDC
= CreateCompatibleDC(0);
315 hbmOrig
= SelectObject(hDC
, ii
.hbmMask
);
316 InvertRect(hDC
, &rcMask
);
317 SelectObject(hDC
, ii
.hbmColor
); /* force the color bitmap to x11drv mode too */
318 SelectObject(hDC
, hbmOrig
);
321 data
->hWMIconBitmap
= ii
.hbmColor
;
322 data
->hWMIconMask
= ii
.hbmMask
;
324 hints
->icon_pixmap
= X11DRV_BITMAP_Pixmap(data
->hWMIconBitmap
);
325 hints
->icon_mask
= X11DRV_BITMAP_Pixmap(data
->hWMIconMask
);
326 destroy_icon_window( display
, wndPtr
);
327 hints
->flags
= (hints
->flags
& ~IconWindowHint
) | IconPixmapHint
| IconMaskHint
;
332 /***********************************************************************
335 * set the window size hints
337 static void set_size_hints( Display
*display
, WND
*win
)
339 XSizeHints
* size_hints
;
340 struct x11drv_win_data
*data
= win
->pDriverData
;
342 if ((size_hints
= XAllocSizeHints()))
344 size_hints
->win_gravity
= StaticGravity
;
345 size_hints
->x
= data
->whole_rect
.left
;
346 size_hints
->y
= data
->whole_rect
.top
;
347 size_hints
->flags
= PWinGravity
| PPosition
;
349 if (HAS_DLGFRAME( win
->dwStyle
, win
->dwExStyle
))
351 size_hints
->max_width
= data
->whole_rect
.right
- data
->whole_rect
.left
;
352 size_hints
->max_height
= data
->whole_rect
.bottom
- data
->whole_rect
.top
;
353 size_hints
->min_width
= size_hints
->max_width
;
354 size_hints
->min_height
= size_hints
->max_height
;
355 size_hints
->flags
|= PMinSize
| PMaxSize
;
357 XSetWMNormalHints( display
, data
->whole_window
, size_hints
);
363 /***********************************************************************
364 * X11DRV_set_wm_hints
366 * Set the window manager hints for a newly-created window
368 void X11DRV_set_wm_hints( Display
*display
, WND
*win
)
370 struct x11drv_win_data
*data
= win
->pDriverData
;
372 XClassHint
*class_hints
;
383 protocols
[i
++] = x11drv_atom(WM_DELETE_WINDOW
);
384 protocols
[i
++] = x11drv_atom(_NET_WM_PING
);
385 if (use_take_focus
) protocols
[i
++] = x11drv_atom(WM_TAKE_FOCUS
);
386 XChangeProperty( display
, data
->whole_window
, x11drv_atom(WM_PROTOCOLS
),
387 XA_ATOM
, 32, PropModeReplace
, (char *)protocols
, i
);
390 if ((class_hints
= XAllocClassHint()))
392 class_hints
->res_name
= "wine";
393 class_hints
->res_class
= "Wine";
394 XSetClassHint( display
, data
->whole_window
, class_hints
);
395 XFree( class_hints
);
398 /* transient for hint */
401 Window owner_win
= X11DRV_get_whole_window( win
->owner
);
402 XSetTransientForHint( display
, data
->whole_window
, owner_win
);
403 group_leader
= owner_win
;
405 else group_leader
= data
->whole_window
;
408 set_size_hints( display
, win
);
410 /* systray properties (KDE only for now) */
411 if (win
->dwExStyle
& WS_EX_TRAYWINDOW
)
414 XChangeProperty( display
, data
->whole_window
, x11drv_atom(KWM_DOCKWINDOW
),
415 x11drv_atom(KWM_DOCKWINDOW
), 32, PropModeReplace
, (char*)&val
, 1 );
416 XChangeProperty( display
, data
->whole_window
, x11drv_atom(_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR
),
417 XA_WINDOW
, 32, PropModeReplace
, (char*)&data
->whole_window
, 1 );
420 /* set the WM_CLIENT_MACHINE and WM_LOCALE_NAME properties */
421 XSetWMProperties(display
, data
->whole_window
, NULL
, NULL
, NULL
, 0, NULL
, NULL
, NULL
);
422 /* set the pid. together, these properties are needed so the window manager can kill us if we freeze */
424 XChangeProperty(display
, data
->whole_window
, x11drv_atom(_NET_WM_PID
),
425 XA_CARDINAL
, 32, PropModeReplace
, (char *)&i
, 1);
427 mwm_hints
.flags
= MWM_HINTS_FUNCTIONS
| MWM_HINTS_DECORATIONS
;
428 mwm_hints
.functions
= 0;
429 if ((win
->dwStyle
& WS_CAPTION
) == WS_CAPTION
) mwm_hints
.functions
|= MWM_FUNC_MOVE
;
430 if (win
->dwStyle
& WS_THICKFRAME
) mwm_hints
.functions
|= MWM_FUNC_MOVE
| MWM_FUNC_RESIZE
;
431 if (win
->dwStyle
& WS_MINIMIZEBOX
) mwm_hints
.functions
|= MWM_FUNC_MINIMIZE
;
432 if (win
->dwStyle
& WS_MAXIMIZEBOX
) mwm_hints
.functions
|= MWM_FUNC_MAXIMIZE
;
433 if (win
->dwStyle
& WS_SYSMENU
) mwm_hints
.functions
|= MWM_FUNC_CLOSE
;
434 mwm_hints
.decorations
= 0;
435 if ((win
->dwStyle
& WS_CAPTION
) == WS_CAPTION
) mwm_hints
.decorations
|= MWM_DECOR_TITLE
;
436 if (win
->dwExStyle
& WS_EX_DLGMODALFRAME
) mwm_hints
.decorations
|= MWM_DECOR_BORDER
;
437 else if (win
->dwStyle
& WS_THICKFRAME
) mwm_hints
.decorations
|= MWM_DECOR_BORDER
| MWM_DECOR_RESIZEH
;
438 else if ((win
->dwStyle
& (WS_DLGFRAME
|WS_BORDER
)) == WS_DLGFRAME
) mwm_hints
.decorations
|= MWM_DECOR_BORDER
;
439 else if (win
->dwStyle
& WS_BORDER
) mwm_hints
.decorations
|= MWM_DECOR_BORDER
;
440 else if (!(win
->dwStyle
& (WS_CHILD
|WS_POPUP
))) mwm_hints
.decorations
|= MWM_DECOR_BORDER
;
441 if (win
->dwStyle
& WS_SYSMENU
) mwm_hints
.decorations
|= MWM_DECOR_MENU
;
442 if (win
->dwStyle
& WS_MINIMIZEBOX
) mwm_hints
.decorations
|= MWM_DECOR_MINIMIZE
;
443 if (win
->dwStyle
& WS_MAXIMIZEBOX
) mwm_hints
.decorations
|= MWM_DECOR_MAXIMIZE
;
445 XChangeProperty( display
, data
->whole_window
, x11drv_atom(_MOTIF_WM_HINTS
),
446 x11drv_atom(_MOTIF_WM_HINTS
), 32, PropModeReplace
,
447 (char*)&mwm_hints
, sizeof(mwm_hints
)/sizeof(long) );
449 XChangeProperty( display
, data
->whole_window
, x11drv_atom(XdndAware
),
450 XA_ATOM
, 32, PropModeReplace
, (unsigned char*)&dndVersion
, 1 );
452 wm_hints
= XAllocWMHints();
458 wm_hints
->flags
= InputHint
| StateHint
| WindowGroupHint
;
459 wm_hints
->input
= !(win
->dwStyle
& WS_DISABLED
);
461 set_icon_hints( display
, win
, wm_hints
);
463 wm_hints
->initial_state
= (win
->dwStyle
& WS_MINIMIZE
) ? IconicState
: NormalState
;
464 wm_hints
->window_group
= group_leader
;
467 XSetWMHints( display
, data
->whole_window
, wm_hints
);
474 /***********************************************************************
475 * X11DRV_set_iconic_state
477 * Set the X11 iconic state according to the window style.
479 void X11DRV_set_iconic_state( WND
*win
)
481 Display
*display
= thread_display();
482 struct x11drv_win_data
*data
= win
->pDriverData
;
484 BOOL iconic
= IsIconic( win
->hwndSelf
);
488 if (iconic
) XUnmapWindow( display
, data
->client_window
);
489 else if (is_client_window_mapped( win
)) XMapWindow( display
, data
->client_window
);
491 if (!(wm_hints
= XGetWMHints( display
, data
->whole_window
))) wm_hints
= XAllocWMHints();
492 wm_hints
->flags
|= StateHint
| IconPositionHint
;
493 wm_hints
->initial_state
= iconic
? IconicState
: NormalState
;
494 wm_hints
->icon_x
= win
->rectWindow
.left
;
495 wm_hints
->icon_y
= win
->rectWindow
.top
;
496 XSetWMHints( display
, data
->whole_window
, wm_hints
);
498 if (win
->dwStyle
& WS_VISIBLE
)
501 XIconifyWindow( display
, data
->whole_window
, DefaultScreen(display
) );
503 if (!IsRectEmpty( &win
->rectWindow
)) XMapWindow( display
, data
->whole_window
);
511 /***********************************************************************
512 * X11DRV_window_to_X_rect
514 * Convert a rect from client to X window coordinates
516 void X11DRV_window_to_X_rect( WND
*win
, RECT
*rect
)
520 if (!(win
->dwExStyle
& WS_EX_MANAGED
)) return;
521 if (IsRectEmpty( rect
)) return;
523 rc
.top
= rc
.bottom
= rc
.left
= rc
.right
= 0;
525 AdjustWindowRectEx( &rc
, win
->dwStyle
& ~(WS_HSCROLL
|WS_VSCROLL
), FALSE
, win
->dwExStyle
);
527 rect
->left
-= rc
.left
;
528 rect
->right
-= rc
.right
;
530 rect
->bottom
-= rc
.bottom
;
531 if (rect
->top
>= rect
->bottom
) rect
->bottom
= rect
->top
+ 1;
532 if (rect
->left
>= rect
->right
) rect
->right
= rect
->left
+ 1;
536 /***********************************************************************
537 * X11DRV_X_to_window_rect
539 * Opposite of X11DRV_window_to_X_rect
541 void X11DRV_X_to_window_rect( WND
*win
, RECT
*rect
)
543 if (!(win
->dwExStyle
& WS_EX_MANAGED
)) return;
544 if (IsRectEmpty( rect
)) return;
546 AdjustWindowRectEx( rect
, win
->dwStyle
& ~(WS_HSCROLL
|WS_VSCROLL
), FALSE
, win
->dwExStyle
);
548 if (rect
->top
>= rect
->bottom
) rect
->bottom
= rect
->top
+ 1;
549 if (rect
->left
>= rect
->right
) rect
->right
= rect
->left
+ 1;
553 /***********************************************************************
554 * X11DRV_sync_whole_window_position
556 * Synchronize the X whole window position with the Windows one
558 int X11DRV_sync_whole_window_position( Display
*display
, WND
*win
, int zorder
)
560 XWindowChanges changes
;
562 struct x11drv_win_data
*data
= win
->pDriverData
;
563 RECT whole_rect
= win
->rectWindow
;
565 X11DRV_window_to_X_rect( win
, &whole_rect
);
566 mask
= get_window_changes( &changes
, &data
->whole_rect
, &whole_rect
);
570 if (is_window_top_level( win
))
572 /* find window that this one must be after */
573 HWND prev
= GetWindow( win
->hwndSelf
, GW_HWNDPREV
);
574 while (prev
&& !(GetWindowLongW( prev
, GWL_STYLE
) & WS_VISIBLE
))
575 prev
= GetWindow( prev
, GW_HWNDPREV
);
576 if (!prev
) /* top child */
578 changes
.stack_mode
= Above
;
583 /* should use stack_mode Below but most window managers don't get it right */
584 /* so move it above the next one in Z order */
585 HWND next
= GetWindow( win
->hwndSelf
, GW_HWNDNEXT
);
586 while (next
&& !(GetWindowLongW( next
, GWL_STYLE
) & WS_VISIBLE
))
587 next
= GetWindow( next
, GW_HWNDNEXT
);
590 changes
.stack_mode
= Above
;
591 changes
.sibling
= X11DRV_get_whole_window(next
);
592 mask
|= CWStackMode
| CWSibling
;
598 HWND next
= GetWindow( win
->hwndSelf
, GW_HWNDNEXT
);
600 if (win
->parent
== GetDesktopWindow() &&
601 root_window
!= DefaultRootWindow(display
))
603 /* in desktop mode we need the sibling to belong to the same process */
606 WND
*ptr
= WIN_GetPtr( next
);
607 if (ptr
!= WND_OTHER_PROCESS
)
609 WIN_ReleasePtr( ptr
);
612 next
= GetWindow( next
, GW_HWNDNEXT
);
616 if (!next
) /* bottom child */
618 changes
.stack_mode
= Below
;
623 changes
.stack_mode
= Above
;
624 changes
.sibling
= X11DRV_get_whole_window(next
);
625 mask
|= CWStackMode
| CWSibling
;
630 data
->whole_rect
= whole_rect
;
634 TRACE( "setting win %lx pos %ld,%ld,%ldx%ld after %lx changes=%x\n",
635 data
->whole_window
, whole_rect
.left
, whole_rect
.top
,
636 whole_rect
.right
- whole_rect
.left
, whole_rect
.bottom
- whole_rect
.top
,
637 changes
.sibling
, mask
);
639 XSync( gdi_display
, False
); /* flush graphics operations before moving the window */
640 if (is_window_top_level( win
))
642 if (mask
& (CWWidth
|CWHeight
)) set_size_hints( display
, win
);
643 XReconfigureWMWindow( display
, data
->whole_window
,
644 DefaultScreen(display
), mask
, &changes
);
646 else XConfigureWindow( display
, data
->whole_window
, mask
, &changes
);
653 /***********************************************************************
654 * X11DRV_sync_client_window_position
656 * Synchronize the X client window position with the Windows one
658 int X11DRV_sync_client_window_position( Display
*display
, WND
*win
)
660 XWindowChanges changes
;
662 struct x11drv_win_data
*data
= win
->pDriverData
;
663 RECT client_rect
= win
->rectClient
;
665 OffsetRect( &client_rect
, -data
->whole_rect
.left
, -data
->whole_rect
.top
);
667 if ((mask
= get_window_changes( &changes
, &data
->client_rect
, &client_rect
)))
669 BOOL was_mapped
= is_client_window_mapped( win
);
671 TRACE( "setting win %lx pos %ld,%ld,%ldx%ld (was %ld,%ld,%ldx%ld) after %lx changes=%x\n",
672 data
->client_window
, client_rect
.left
, client_rect
.top
,
673 client_rect
.right
- client_rect
.left
, client_rect
.bottom
- client_rect
.top
,
674 data
->client_rect
.left
, data
->client_rect
.top
,
675 data
->client_rect
.right
- data
->client_rect
.left
,
676 data
->client_rect
.bottom
- data
->client_rect
.top
,
677 changes
.sibling
, mask
);
678 data
->client_rect
= client_rect
;
680 XSync( gdi_display
, False
); /* flush graphics operations before moving the window */
681 if (was_mapped
&& !is_client_window_mapped( win
))
682 XUnmapWindow( display
, data
->client_window
);
683 XConfigureWindow( display
, data
->client_window
, mask
, &changes
);
684 if (!was_mapped
&& is_client_window_mapped( win
))
685 XMapWindow( display
, data
->client_window
);
692 /***********************************************************************
693 * X11DRV_register_window
695 * Associate an X window to a HWND.
697 void X11DRV_register_window( Display
*display
, HWND hwnd
, struct x11drv_win_data
*data
)
700 XSaveContext( display
, data
->whole_window
, winContext
, (char *)hwnd
);
701 XSaveContext( display
, data
->client_window
, winContext
, (char *)hwnd
);
706 /**********************************************************************
709 static void create_desktop( Display
*display
, WND
*wndPtr
)
711 X11DRV_WND_DATA
*data
= wndPtr
->pDriverData
;
714 winContext
= XUniqueContext();
715 XInternAtoms( display
, (char **)atom_names
, NB_XATOMS
- FIRST_XATOM
, False
, X11DRV_Atoms
);
718 whole_window_atom
= MAKEINTATOMA( GlobalAddAtomA( "__wine_x11_whole_window" ));
719 client_window_atom
= MAKEINTATOMA( GlobalAddAtomA( "__wine_x11_client_window" ));
720 icon_window_atom
= MAKEINTATOMA( GlobalAddAtomA( "__wine_x11_icon_window" ));
722 data
->whole_window
= data
->client_window
= root_window
;
723 data
->whole_rect
= data
->client_rect
= wndPtr
->rectWindow
;
725 SetPropA( wndPtr
->hwndSelf
, whole_window_atom
, (HANDLE
)root_window
);
726 SetPropA( wndPtr
->hwndSelf
, client_window_atom
, (HANDLE
)root_window
);
727 SetPropA( wndPtr
->hwndSelf
, "__wine_x11_visual_id", (HANDLE
)XVisualIDFromVisual(visual
) );
729 X11DRV_InitClipboard();
731 if (root_window
!= DefaultRootWindow(display
)) X11DRV_create_desktop_thread();
735 /**********************************************************************
736 * create_whole_window
738 * Create the whole X window for a given window
740 static Window
create_whole_window( Display
*display
, WND
*win
)
742 struct x11drv_win_data
*data
= win
->pDriverData
;
744 XSetWindowAttributes attr
;
747 BOOL is_top_level
= is_window_top_level( win
);
749 rect
= win
->rectWindow
;
750 X11DRV_window_to_X_rect( win
, &rect
);
752 if (!(cx
= rect
.right
- rect
.left
)) cx
= 1;
753 if (!(cy
= rect
.bottom
- rect
.top
)) cy
= 1;
755 parent
= X11DRV_get_client_window( win
->parent
);
759 mask
= get_window_attributes( display
, win
, &attr
);
761 /* set the attributes that don't change over the lifetime of the window */
762 attr
.bit_gravity
= ForgetGravity
;
763 attr
.win_gravity
= NorthWestGravity
;
764 attr
.backing_store
= NotUseful
/*WhenMapped*/;
765 mask
|= CWBitGravity
| CWWinGravity
| CWBackingStore
;
767 data
->whole_rect
= rect
;
768 data
->whole_window
= XCreateWindow( display
, parent
, rect
.left
, rect
.top
, cx
, cy
,
769 0, screen_depth
, InputOutput
, visual
,
772 if (!data
->whole_window
)
780 XIM xim
= x11drv_thread_data()->xim
;
781 if (xim
) data
->xic
= XCreateIC( xim
,
782 XNInputStyle
, XIMPreeditNothing
| XIMStatusNothing
,
783 XNClientWindow
, data
->whole_window
,
784 XNFocusWindow
, data
->whole_window
,
788 /* non-maximized child must be at bottom of Z order */
789 if ((win
->dwStyle
& (WS_CHILD
|WS_MAXIMIZE
)) == WS_CHILD
)
791 XWindowChanges changes
;
792 changes
.stack_mode
= Below
;
793 XConfigureWindow( display
, data
->whole_window
, CWStackMode
, &changes
);
798 if (is_top_level
) X11DRV_set_wm_hints( display
, win
);
800 return data
->whole_window
;
804 /**********************************************************************
805 * create_client_window
807 * Create the client window for a given window
809 static Window
create_client_window( Display
*display
, WND
*win
)
811 struct x11drv_win_data
*data
= win
->pDriverData
;
812 RECT rect
= data
->whole_rect
;
813 XSetWindowAttributes attr
;
815 OffsetRect( &rect
, -data
->whole_rect
.left
, -data
->whole_rect
.top
);
816 data
->client_rect
= rect
;
818 attr
.event_mask
= (ExposureMask
| PointerMotionMask
|
819 ButtonPressMask
| ButtonReleaseMask
| EnterWindowMask
);
820 attr
.bit_gravity
= (win
->clsStyle
& (CS_VREDRAW
| CS_HREDRAW
)) ?
821 ForgetGravity
: NorthWestGravity
;
822 attr
.backing_store
= NotUseful
/*WhenMapped*/;
825 data
->client_window
= XCreateWindow( display
, data
->whole_window
, 0, 0,
826 max( rect
.right
- rect
.left
, 1 ),
827 max( rect
.bottom
- rect
.top
, 1 ),
830 CWEventMask
| CWBitGravity
| CWBackingStore
, &attr
);
831 if (data
->client_window
&& is_client_window_mapped( win
))
832 XMapWindow( display
, data
->client_window
);
834 return data
->client_window
;
838 /*****************************************************************
839 * SetWindowText (X11DRV.@)
841 BOOL
X11DRV_SetWindowText( HWND hwnd
, LPCWSTR text
)
843 Display
*display
= thread_display();
850 if ((win
= X11DRV_get_whole_window( hwnd
)))
852 /* allocate new buffer for window text */
853 count
= WideCharToMultiByte(CP_UNIXCP
, 0, text
, -1, NULL
, 0, NULL
, NULL
);
854 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, count
)))
856 ERR("Not enough memory for window text\n");
859 WideCharToMultiByte(CP_UNIXCP
, 0, text
, -1, buffer
, count
, NULL
, NULL
);
861 count
= WideCharToMultiByte(CP_UTF8
, 0, text
, strlenW(text
), NULL
, 0, NULL
, NULL
);
862 if (!(utf8_buffer
= HeapAlloc( GetProcessHeap(), 0, count
)))
864 ERR("Not enough memory for window text in UTF-8\n");
867 WideCharToMultiByte(CP_UTF8
, 0, text
, strlenW(text
), utf8_buffer
, count
, NULL
, NULL
);
870 if (XmbTextListToTextProperty( display
, &buffer
, 1, XStdICCTextStyle
, &prop
) == Success
)
872 XSetWMName( display
, win
, &prop
);
873 XSetWMIconName( display
, win
, &prop
);
877 Implements a NET_WM UTF-8 title. It should be without a trailing \0,
878 according to the standard
879 ( http://www.pps.jussieu.fr/~jch/software/UTF8_STRING/UTF8_STRING.text ).
881 XChangeProperty( display
, win
, x11drv_atom(_NET_WM_NAME
), x11drv_atom(UTF8_STRING
),
882 8, PropModeReplace
, (unsigned char *) utf8_buffer
, count
);
885 HeapFree( GetProcessHeap(), 0, utf8_buffer
);
886 HeapFree( GetProcessHeap(), 0, buffer
);
892 /***********************************************************************
893 * DestroyWindow (X11DRV.@)
895 BOOL
X11DRV_DestroyWindow( HWND hwnd
)
897 struct x11drv_thread_data
*thread_data
= x11drv_thread_data();
898 Display
*display
= thread_data
->display
;
899 WND
*wndPtr
= WIN_GetPtr( hwnd
);
900 X11DRV_WND_DATA
*data
= wndPtr
->pDriverData
;
902 if (!data
) goto done
;
904 if (data
->whole_window
)
906 TRACE( "win %p xwin %lx/%lx\n", hwnd
, data
->whole_window
, data
->client_window
);
907 if (thread_data
->cursor_window
== data
->whole_window
) thread_data
->cursor_window
= None
;
908 if (thread_data
->last_focus
== hwnd
) thread_data
->last_focus
= 0;
910 XSync( gdi_display
, False
); /* flush any reference to this drawable in GDI queue */
911 XDeleteContext( display
, data
->whole_window
, winContext
);
912 XDeleteContext( display
, data
->client_window
, winContext
);
913 XDestroyWindow( display
, data
->whole_window
); /* this destroys client too */
916 XUnsetICFocus( data
->xic
);
917 XDestroyIC( data
->xic
);
919 destroy_icon_window( display
, wndPtr
);
923 if (data
->hWMIconBitmap
) DeleteObject( data
->hWMIconBitmap
);
924 if (data
->hWMIconMask
) DeleteObject( data
->hWMIconMask
);
925 HeapFree( GetProcessHeap(), 0, data
);
926 wndPtr
->pDriverData
= NULL
;
928 WIN_ReleasePtr( wndPtr
);
933 /**********************************************************************
934 * CreateWindow (X11DRV.@)
936 BOOL
X11DRV_CreateWindow( HWND hwnd
, CREATESTRUCTA
*cs
, BOOL unicode
)
938 Display
*display
= thread_display();
940 struct x11drv_win_data
*data
;
947 ERR( "invalid window width %d\n", cs
->cx
);
952 ERR( "invalid window height %d\n", cs
->cx
);
956 if (!(data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
)))) return FALSE
;
957 data
->whole_window
= 0;
958 data
->client_window
= 0;
959 data
->icon_window
= 0;
961 data
->hWMIconBitmap
= 0;
962 data
->hWMIconMask
= 0;
964 wndPtr
= WIN_GetPtr( hwnd
);
965 wndPtr
->pDriverData
= data
;
967 /* initialize the dimensions before sending WM_GETMINMAXINFO */
968 SetRect( &rect
, cs
->x
, cs
->y
, cs
->x
+ cs
->cx
, cs
->y
+ cs
->cy
);
969 WIN_SetRectangles( hwnd
, &rect
, &rect
);
973 create_desktop( display
, wndPtr
);
974 WIN_ReleasePtr( wndPtr
);
978 if (!create_whole_window( display
, wndPtr
)) goto failed
;
979 if (!create_client_window( display
, wndPtr
)) goto failed
;
980 TSXSync( display
, False
);
982 SetPropA( hwnd
, whole_window_atom
, (HANDLE
)data
->whole_window
);
983 SetPropA( hwnd
, client_window_atom
, (HANDLE
)data
->client_window
);
985 /* Call the WH_CBT hook */
987 cbtc
.hwndInsertAfter
= HWND_TOP
;
988 if (HOOK_CallHooks( WH_CBT
, HCBT_CREATEWND
, (WPARAM
)hwnd
, (LPARAM
)&cbtc
, unicode
))
990 TRACE("CBT-hook returned !0\n");
994 /* Send the WM_GETMINMAXINFO message and fix the size if needed */
995 if ((cs
->style
& WS_THICKFRAME
) || !(cs
->style
& (WS_POPUP
| WS_CHILD
)))
997 POINT maxSize
, maxPos
, minTrack
, maxTrack
;
999 WIN_ReleasePtr( wndPtr
);
1000 WINPOS_GetMinMaxInfo( hwnd
, &maxSize
, &maxPos
, &minTrack
, &maxTrack
);
1001 if (maxSize
.x
< cs
->cx
) cs
->cx
= maxSize
.x
;
1002 if (maxSize
.y
< cs
->cy
) cs
->cy
= maxSize
.y
;
1003 if (cs
->cx
< minTrack
.x
) cs
->cx
= minTrack
.x
;
1004 if (cs
->cy
< minTrack
.y
) cs
->cy
= minTrack
.y
;
1005 if (cs
->cx
< 0) cs
->cx
= 0;
1006 if (cs
->cy
< 0) cs
->cy
= 0;
1008 if (!(wndPtr
= WIN_GetPtr( hwnd
))) return FALSE
;
1009 SetRect( &rect
, cs
->x
, cs
->y
, cs
->x
+ cs
->cx
, cs
->y
+ cs
->cy
);
1010 WIN_SetRectangles( hwnd
, &rect
, &rect
);
1011 X11DRV_sync_whole_window_position( display
, wndPtr
, 0 );
1013 WIN_ReleasePtr( wndPtr
);
1015 /* send WM_NCCREATE */
1016 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd
, cs
->x
, cs
->y
, cs
->cx
, cs
->cy
);
1018 ret
= SendMessageW( hwnd
, WM_NCCREATE
, 0, (LPARAM
)cs
);
1020 ret
= SendMessageA( hwnd
, WM_NCCREATE
, 0, (LPARAM
)cs
);
1023 WARN("aborted by WM_xxCREATE!\n");
1027 if (!(wndPtr
= WIN_GetPtr(hwnd
))) return FALSE
;
1029 X11DRV_sync_window_style( display
, wndPtr
);
1031 /* send WM_NCCALCSIZE */
1032 rect
= wndPtr
->rectWindow
;
1033 WIN_ReleasePtr( wndPtr
);
1034 SendMessageW( hwnd
, WM_NCCALCSIZE
, FALSE
, (LPARAM
)&rect
);
1036 if (!(wndPtr
= WIN_GetPtr(hwnd
))) return FALSE
;
1037 if (rect
.left
> rect
.right
|| rect
.top
> rect
.bottom
) rect
= wndPtr
->rectWindow
;
1038 WIN_SetRectangles( hwnd
, &wndPtr
->rectWindow
, &rect
);
1039 X11DRV_sync_client_window_position( display
, wndPtr
);
1040 X11DRV_register_window( display
, hwnd
, data
);
1042 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/%x\n",
1043 hwnd
, wndPtr
->rectWindow
.left
, wndPtr
->rectWindow
.top
,
1044 wndPtr
->rectWindow
.right
, wndPtr
->rectWindow
.bottom
,
1045 wndPtr
->rectClient
.left
, wndPtr
->rectClient
.top
,
1046 wndPtr
->rectClient
.right
, wndPtr
->rectClient
.bottom
,
1047 data
->whole_rect
.left
, data
->whole_rect
.top
,
1048 data
->whole_rect
.right
, data
->whole_rect
.bottom
,
1049 data
->client_rect
.left
, data
->client_rect
.top
,
1050 data
->client_rect
.right
, data
->client_rect
.bottom
,
1051 (unsigned int)data
->whole_window
, (unsigned int)data
->client_window
);
1053 if ((wndPtr
->dwStyle
& (WS_CHILD
|WS_MAXIMIZE
)) == WS_CHILD
)
1054 WIN_LinkWindow( hwnd
, wndPtr
->parent
, HWND_BOTTOM
);
1056 WIN_LinkWindow( hwnd
, wndPtr
->parent
, HWND_TOP
);
1058 WIN_ReleasePtr( wndPtr
);
1061 ret
= (SendMessageW( hwnd
, WM_CREATE
, 0, (LPARAM
)cs
) != -1);
1063 ret
= (SendMessageA( hwnd
, WM_CREATE
, 0, (LPARAM
)cs
) != -1);
1067 WIN_UnlinkWindow( hwnd
);
1071 /* Send the size messages */
1073 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) return FALSE
;
1074 if (!(wndPtr
->flags
& WIN_NEED_SIZE
))
1076 /* send it anyway */
1077 if (((wndPtr
->rectClient
.right
-wndPtr
->rectClient
.left
) <0)
1078 ||((wndPtr
->rectClient
.bottom
-wndPtr
->rectClient
.top
)<0))
1079 WARN("sending bogus WM_SIZE message 0x%08lx\n",
1080 MAKELONG(wndPtr
->rectClient
.right
-wndPtr
->rectClient
.left
,
1081 wndPtr
->rectClient
.bottom
-wndPtr
->rectClient
.top
));
1082 SendMessageW( hwnd
, WM_SIZE
, SIZE_RESTORED
,
1083 MAKELONG(wndPtr
->rectClient
.right
-wndPtr
->rectClient
.left
,
1084 wndPtr
->rectClient
.bottom
-wndPtr
->rectClient
.top
));
1085 SendMessageW( hwnd
, WM_MOVE
, 0,
1086 MAKELONG( wndPtr
->rectClient
.left
, wndPtr
->rectClient
.top
) );
1089 /* Show the window, maximizing or minimizing if needed */
1091 if (wndPtr
->dwStyle
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1093 extern UINT
WINPOS_MinMaximize( HWND hwnd
, UINT cmd
, LPRECT rect
); /*FIXME*/
1096 UINT swFlag
= (wndPtr
->dwStyle
& WS_MINIMIZE
) ? SW_MINIMIZE
: SW_MAXIMIZE
;
1097 WIN_SetStyle( hwnd
, wndPtr
->dwStyle
& ~(WS_MAXIMIZE
| WS_MINIMIZE
) );
1098 WINPOS_MinMaximize( hwnd
, swFlag
, &newPos
);
1099 swFlag
= ((wndPtr
->dwStyle
& WS_CHILD
) || GetActiveWindow())
1100 ? SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
1101 : SWP_NOZORDER
| SWP_FRAMECHANGED
;
1102 SetWindowPos( hwnd
, 0, newPos
.left
, newPos
.top
,
1103 newPos
.right
, newPos
.bottom
, swFlag
);
1106 /* if the window was made visible set create struct flag so that
1107 * we do a proper ShowWindow later on */
1108 if (wndPtr
->dwStyle
& WS_VISIBLE
) cs
->style
|= WS_VISIBLE
;
1110 WIN_ReleaseWndPtr( wndPtr
);
1115 X11DRV_DestroyWindow( hwnd
);
1116 if (wndPtr
) WIN_ReleasePtr( wndPtr
);
1121 /***********************************************************************
1122 * X11DRV_get_client_window
1124 * Return the X window associated with the client area of a window
1126 Window
X11DRV_get_client_window( HWND hwnd
)
1129 WND
*win
= WIN_GetPtr( hwnd
);
1131 if (win
== WND_OTHER_PROCESS
)
1132 return (Window
)GetPropA( hwnd
, client_window_atom
);
1136 struct x11drv_win_data
*data
= win
->pDriverData
;
1137 ret
= data
->client_window
;
1138 WIN_ReleasePtr( win
);
1144 /***********************************************************************
1145 * X11DRV_get_whole_window
1147 * Return the X window associated with the full area of a window
1149 Window
X11DRV_get_whole_window( HWND hwnd
)
1152 WND
*win
= WIN_GetPtr( hwnd
);
1154 if (win
== WND_OTHER_PROCESS
)
1155 return (Window
)GetPropA( hwnd
, whole_window_atom
);
1159 struct x11drv_win_data
*data
= win
->pDriverData
;
1160 ret
= data
->whole_window
;
1161 WIN_ReleasePtr( win
);
1167 /***********************************************************************
1170 * Return the X input context associated with a window
1172 XIC
X11DRV_get_ic( HWND hwnd
)
1175 WND
*win
= WIN_GetPtr( hwnd
);
1177 if (win
&& win
!= WND_OTHER_PROCESS
)
1179 struct x11drv_win_data
*data
= win
->pDriverData
;
1181 WIN_ReleasePtr( win
);
1187 /*****************************************************************
1188 * SetParent (X11DRV.@)
1190 HWND
X11DRV_SetParent( HWND hwnd
, HWND parent
)
1192 Display
*display
= thread_display();
1196 /* Windows hides the window first, then shows it again
1197 * including the WM_SHOWWINDOW messages and all */
1198 BOOL was_visible
= ShowWindow( hwnd
, SW_HIDE
);
1200 if (!IsWindow( parent
)) return 0;
1201 if (!(wndPtr
= WIN_GetPtr(hwnd
)) || wndPtr
== WND_OTHER_PROCESS
) return 0;
1203 retvalue
= wndPtr
->parent
; /* old parent */
1204 if (parent
!= retvalue
)
1206 struct x11drv_win_data
*data
= wndPtr
->pDriverData
;
1208 WIN_LinkWindow( hwnd
, parent
, HWND_TOP
);
1210 if (parent
!= GetDesktopWindow()) /* a child window */
1212 if (!(wndPtr
->dwStyle
& WS_CHILD
))
1214 HMENU menu
= (HMENU
)SetWindowLongW( hwnd
, GWL_ID
, 0 );
1215 if (menu
) DestroyMenu( menu
);
1219 if (is_window_top_level( wndPtr
)) X11DRV_set_wm_hints( display
, wndPtr
);
1221 X11DRV_sync_window_style( display
, wndPtr
);
1222 XReparentWindow( display
, data
->whole_window
, X11DRV_get_client_window(parent
),
1223 data
->whole_rect
.left
, data
->whole_rect
.top
);
1224 wine_tsx11_unlock();
1226 WIN_ReleasePtr( wndPtr
);
1228 /* SetParent additionally needs to make hwnd the topmost window
1229 in the x-order and send the expected WM_WINDOWPOSCHANGING and
1230 WM_WINDOWPOSCHANGED notification messages.
1232 SetWindowPos( hwnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1233 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| (was_visible
? SWP_SHOWWINDOW
: 0) );
1234 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
1235 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
1241 /*****************************************************************
1242 * SetFocus (X11DRV.@)
1245 * Explicit colormap management seems to work only with OLVWM.
1247 void X11DRV_SetFocus( HWND hwnd
)
1249 Display
*display
= thread_display();
1250 XWindowAttributes win_attr
;
1253 /* Only mess with the X focus if there's */
1254 /* no desktop window and if the window is not managed by the WM. */
1255 if (root_window
!= DefaultRootWindow(display
)) return;
1257 if (!hwnd
) /* If setting the focus to 0, uninstall the colormap */
1260 if (X11DRV_PALETTE_PaletteFlags
& X11DRV_PALETTE_PRIVATE
)
1261 XUninstallColormap( display
, X11DRV_PALETTE_PaletteXColormap
);
1262 wine_tsx11_unlock();
1266 hwnd
= GetAncestor( hwnd
, GA_ROOT
);
1267 if (GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_MANAGED
) return;
1268 if (!(win
= X11DRV_get_whole_window( hwnd
))) return;
1270 /* Set X focus and install colormap */
1272 if (XGetWindowAttributes( display
, win
, &win_attr
) &&
1273 (win_attr
.map_state
== IsViewable
))
1275 /* If window is not viewable, don't change anything */
1277 /* we must not use CurrentTime (ICCCM), so try to use last message time instead */
1278 /* FIXME: this is not entirely correct */
1279 XSetInputFocus( display
, win
, RevertToParent
,
1280 /*CurrentTime*/ GetMessageTime() + X11DRV_server_startticks
);
1281 if (X11DRV_PALETTE_PaletteFlags
& X11DRV_PALETTE_PRIVATE
)
1282 XInstallColormap( display
, X11DRV_PALETTE_PaletteXColormap
);
1284 wine_tsx11_unlock();
1288 /**********************************************************************
1289 * SetWindowIcon (X11DRV.@)
1291 * hIcon or hIconSm has changed (or is being initialised for the
1292 * first time). Complete the X11 driver-specific initialisation
1293 * and set the window hints.
1295 * This is not entirely correct, may need to create
1296 * an icon window and set the pixmap as a background
1298 HICON
X11DRV_SetWindowIcon( HWND hwnd
, HICON icon
, BOOL small
)
1301 Display
*display
= thread_display();
1302 HICON old
= (HICON
)SetClassLongW(hwnd
, small
? GCL_HICONSM
: GCL_HICON
, (LONG
)icon
);
1304 SetWindowPos( hwnd
, 0, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOSIZE
|
1305 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1307 if (!(wndPtr
= WIN_GetPtr( hwnd
)) || wndPtr
== WND_OTHER_PROCESS
) return old
;
1309 if (wndPtr
->dwExStyle
& WS_EX_MANAGED
)
1311 Window win
= get_whole_window(wndPtr
);
1315 if (!(wm_hints
= XGetWMHints( display
, win
))) wm_hints
= XAllocWMHints();
1316 wine_tsx11_unlock();
1319 set_icon_hints( display
, wndPtr
, wm_hints
);
1321 XSetWMHints( display
, win
, wm_hints
);
1323 wine_tsx11_unlock();
1326 WIN_ReleasePtr( wndPtr
);