2 * Window related functions
4 * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
5 * Copyright 1993 David Metcalfe
6 * Copyright 1995, 1996 Alex Korobka
18 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(win);
25 extern Cursor X11DRV_MOUSE_XCursor; /* current X cursor */
26 extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
28 #define HAS_DLGFRAME(style,exStyle) \
29 ((!((style) & WS_THICKFRAME)) && (((style) & WS_DLGFRAME) || ((exStyle) & WS_EX_DLGMODALFRAME)))
31 /* X context to associate a hwnd to an X window */
32 XContext winContext = 0;
34 Atom wmProtocols = None;
35 Atom wmDeleteWindow = None;
36 Atom dndProtocol = None;
37 Atom dndSelection = None;
38 Atom wmChangeState = None;
39 Atom kwmDockWindow = None;
40 Atom _kde_net_wm_system_tray_window_for = None; /* KDE 2 Final */
43 /***********************************************************************
46 * Associate an X window to a HWND.
48 static void register_window( HWND hwnd, Window win )
50 if (!winContext) winContext = TSXUniqueContext();
51 TSXSaveContext( display, win, winContext, (char *)hwnd );
52 TSXSetWMProtocols( display, win, &wmDeleteWindow, 1 );
56 /***********************************************************************
59 * Set a window manager hint.
61 static void set_wm_hint( Window win, int hint, int val )
63 XWMHints* wm_hints = TSXGetWMHints( display, win );
64 if (!wm_hints) wm_hints = TSXAllocWMHints();
67 wm_hints->flags = hint;
71 wm_hints->input = val;
75 wm_hints->initial_state = val;
79 wm_hints->icon_pixmap = (Pixmap)val;
83 wm_hints->icon_window = (Window)val;
86 TSXSetWMHints( display, win, wm_hints );
92 /***********************************************************************
95 * Set the icon wm hints
97 static void set_icon_hints( WND *wndPtr, XWMHints *hints )
99 X11DRV_WND_DATA *data = wndPtr->pDriverData;
100 HICON hIcon = GetClassLongA( wndPtr->hwndSelf, GCL_HICON );
102 if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
103 if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
107 data->hWMIconBitmap = 0;
108 data->hWMIconMask = 0;
109 hints->flags &= ~(IconPixmapHint | IconMaskHint);
119 GetIconInfo(hIcon, &ii);
121 X11DRV_CreateBitmap(ii.hbmMask);
122 X11DRV_CreateBitmap(ii.hbmColor);
124 GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
127 rcMask.right = bmMask.bmWidth;
128 rcMask.bottom = bmMask.bmHeight;
130 hDC = CreateCompatibleDC(0);
131 hbmOrig = SelectObject(hDC, ii.hbmMask);
132 InvertRect(hDC, &rcMask);
133 SelectObject(hDC, hbmOrig);
136 data->hWMIconBitmap = ii.hbmColor;
137 data->hWMIconMask = ii.hbmMask;
139 hints->icon_pixmap = X11DRV_BITMAP_Pixmap(data->hWMIconBitmap);
140 hints->icon_mask = X11DRV_BITMAP_Pixmap(data->hWMIconMask);
141 hints->flags |= IconPixmapHint | IconMaskHint;
146 /***********************************************************************
149 * Set the X Property of the window that tells the windowmanager we really
150 * want to be in the systray
152 * KDE: set "KWM_DOCKWINDOW", type "KWM_DOCKWINDOW" to 1 before a window is
155 * all others: to be added ;)
157 inline static void dock_window( Window win )
160 if (kwmDockWindow != None)
161 TSXChangeProperty( display, win, kwmDockWindow, kwmDockWindow,
162 32, PropModeReplace, (char*)&data, 1 );
163 if (_kde_net_wm_system_tray_window_for != None)
164 TSXChangeProperty( display, win, _kde_net_wm_system_tray_window_for, XA_WINDOW,
165 32, PropModeReplace, (char*)&win, 1 );
169 /**********************************************************************
172 static void create_desktop(WND *wndPtr)
174 X11DRV_WND_DATA *data = wndPtr->pDriverData;
176 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
177 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
178 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
179 dndSelection = TSXInternAtom( display, "DndSelection" , False );
180 wmChangeState = TSXInternAtom (display, "WM_CHANGE_STATE", False);
181 kwmDockWindow = TSXInternAtom( display, "KWM_DOCKWINDOW", False );
182 _kde_net_wm_system_tray_window_for = TSXInternAtom( display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False );
184 data->window = root_window;
185 if (root_window != DefaultRootWindow(display)) wndPtr->flags |= WIN_NATIVE;
186 register_window( wndPtr->hwndSelf, root_window );
190 /**********************************************************************
191 * CreateWindow (X11DRV.@)
193 BOOL X11DRV_CreateWindow( HWND hwnd )
195 X11DRV_WND_DATA *data;
196 WND *wndPtr = WIN_FindWndPtr( hwnd );
197 int x = wndPtr->rectWindow.left;
198 int y = wndPtr->rectWindow.top;
199 int cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
200 int cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
202 if (!(data = HeapAlloc(GetProcessHeap(), 0, sizeof(X11DRV_WND_DATA))))
204 WIN_ReleaseWndPtr( wndPtr );
208 wndPtr->pDriverData = data;
212 create_desktop( wndPtr );
213 WIN_ReleaseWndPtr( wndPtr );
217 /* Create the X window (only for top-level windows, and then only */
218 /* when there's no desktop window) */
220 if ((root_window == DefaultRootWindow(display))
221 && (wndPtr->parent->hwndSelf == GetDesktopWindow()))
225 XSetWindowAttributes win_attr;
227 /* Create "managed" windows only if a title bar or resizable */
228 /* frame is required. */
229 if (WIN_WindowNeedsWMBorder(wndPtr->dwStyle, wndPtr->dwExStyle))
231 win_attr.event_mask = ExposureMask | KeyPressMask |
232 KeyReleaseMask | PointerMotionMask |
233 ButtonPressMask | ButtonReleaseMask |
234 FocusChangeMask | StructureNotifyMask;
235 win_attr.override_redirect = FALSE;
236 wndPtr->dwExStyle |= WS_EX_MANAGED;
240 win_attr.event_mask = ExposureMask | KeyPressMask |
241 KeyReleaseMask | PointerMotionMask |
242 ButtonPressMask | ButtonReleaseMask |
244 win_attr.override_redirect = TRUE;
246 wndPtr->flags |= WIN_NATIVE;
248 win_attr.bit_gravity = (wndPtr->clsStyle & (CS_VREDRAW | CS_HREDRAW)) ? ForgetGravity : NorthWestGravity;
249 win_attr.colormap = X11DRV_PALETTE_PaletteXColormap;
250 win_attr.backing_store = NotUseful;
251 win_attr.save_under = ((wndPtr->clsStyle & CS_SAVEBITS) != 0);
252 win_attr.cursor = X11DRV_MOUSE_XCursor;
254 data->hWMIconBitmap = 0;
255 data->hWMIconMask = 0;
256 data->bit_gravity = win_attr.bit_gravity;
258 /* Zero-size X11 window hack. X doesn't like them, and will crash */
259 /* with a BadValue unless we do something ugly like this. */
260 /* Zero size window won't be mapped */
264 data->window = TSXCreateWindow( display, root_window,
268 CWEventMask | CWOverrideRedirect |
269 CWColormap | CWCursor | CWSaveUnder |
270 CWBackingStore | CWBitGravity,
273 if(!(wGroupLeader = X11DRV_WND_GetXWindow(wndPtr)))
275 HeapFree( GetProcessHeap(), 0, data );
276 WIN_ReleaseWndPtr( wndPtr );
280 /* If we are the systray, we need to be managed to be noticed by KWM */
281 if (wndPtr->dwExStyle & WS_EX_TRAYWINDOW) dock_window( data->window );
283 if (wndPtr->dwExStyle & WS_EX_MANAGED)
285 XClassHint *class_hints = TSXAllocClassHint();
286 XSizeHints* size_hints = TSXAllocSizeHints();
290 class_hints->res_name = "wineManaged";
291 class_hints->res_class = "Wine";
292 TSXSetClassHint( display, data->window, class_hints );
293 TSXFree (class_hints);
298 size_hints->win_gravity = StaticGravity;
301 size_hints->flags = PWinGravity|PPosition;
303 if (HAS_DLGFRAME(wndPtr->dwStyle,wndPtr->dwExStyle))
305 size_hints->min_width = size_hints->max_width = cx;
306 size_hints->min_height = size_hints->max_height = cy;
307 size_hints->flags |= PMinSize | PMaxSize;
310 TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(wndPtr),
311 size_hints, XA_WM_NORMAL_HINTS );
316 if (wndPtr->owner) /* Get window owner */
318 Window w = X11DRV_WND_FindXWindow( wndPtr->owner );
321 TSXSetTransientForHint( display, X11DRV_WND_GetXWindow(wndPtr), w );
326 if ((wm_hints = TSXAllocWMHints()))
328 wm_hints->flags = InputHint | StateHint | WindowGroupHint;
329 wm_hints->input = True;
331 if (wndPtr->dwExStyle & WS_EX_MANAGED)
333 set_icon_hints( wndPtr, wm_hints );
334 wm_hints->initial_state = (wndPtr->dwStyle & WS_MINIMIZE)
335 ? IconicState : NormalState;
338 wm_hints->initial_state = NormalState;
339 wm_hints->window_group = wGroupLeader;
341 TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
344 register_window( hwnd, data->window );
346 WIN_ReleaseWndPtr( wndPtr );
351 /***********************************************************************
352 * DestroyWindow (X11DRV.@)
354 BOOL X11DRV_DestroyWindow( HWND hwnd )
356 WND *wndPtr = WIN_FindWndPtr( hwnd );
357 X11DRV_WND_DATA *data = wndPtr->pDriverData;
360 if (data && (w = data->window))
363 TSXDeleteContext( display, w, winContext );
364 TSXDestroyWindow( display, w );
365 while( TSXCheckWindowEvent(display, w, NoEventMask, &xe) );
368 if( data->hWMIconBitmap )
370 DeleteObject( data->hWMIconBitmap );
371 data->hWMIconBitmap = 0;
373 if( data->hWMIconMask )
375 DeleteObject( data->hWMIconMask);
376 data->hWMIconMask= 0;
379 HeapFree( GetProcessHeap(), 0, data );
380 wndPtr->pDriverData = NULL;
381 WIN_ReleaseWndPtr( wndPtr );
386 /*****************************************************************
387 * SetParent (X11DRV.@)
389 HWND X11DRV_SetParent( HWND hwnd, HWND parent )
396 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
398 dwStyle = wndPtr->dwStyle;
400 pWndParent = parent ? WIN_FindWndPtr(parent) : WIN_GetDesktop();
403 WIN_ReleaseWndPtr( wndPtr );
407 /* Windows hides the window first, then shows it again
408 * including the WM_SHOWWINDOW messages and all */
409 if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE );
411 retvalue = wndPtr->parent->hwndSelf; /* old parent */
412 if (pWndParent != wndPtr->parent)
414 if ( X11DRV_WND_GetXWindow(wndPtr) )
416 /* Toplevel window needs to be reparented. Used by Tk 8.0 */
417 TSXDestroyWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
418 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
420 WIN_UnlinkWindow(wndPtr->hwndSelf);
421 wndPtr->parent = pWndParent;
423 /* Create an X counterpart for reparented top-level windows
424 * when not in the desktop mode. */
425 if (parent == GetDesktopWindow())
427 if(root_window == DefaultRootWindow(display))
428 X11DRV_CreateWindow(wndPtr->hwndSelf);
430 else /* a child window */
432 if( !( wndPtr->dwStyle & WS_CHILD ) )
434 if( wndPtr->wIDmenu != 0)
436 DestroyMenu( (HMENU) wndPtr->wIDmenu );
441 WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
443 WIN_ReleaseWndPtr( pWndParent );
444 WIN_ReleaseWndPtr( wndPtr );
446 /* SetParent additionally needs to make hwnd the topmost window
447 in the x-order and send the expected WM_WINDOWPOSCHANGING and
448 WM_WINDOWPOSCHANGED notification messages.
450 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
451 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|
452 ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
453 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
454 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
460 /*******************************************************************
461 * EnableWindow (X11DRV.@)
463 BOOL X11DRV_EnableWindow( HWND hwnd, BOOL enable )
469 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
471 retvalue = ((wndPtr->dwStyle & WS_DISABLED) != 0);
473 if (enable && (wndPtr->dwStyle & WS_DISABLED))
476 wndPtr->dwStyle &= ~WS_DISABLED;
478 if ((wndPtr->dwExStyle & WS_EX_MANAGED) && (w = X11DRV_WND_GetXWindow( wndPtr )))
479 set_wm_hint( w, InputHint, TRUE );
481 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
483 else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
485 SendMessageA( wndPtr->hwndSelf, WM_CANCELMODE, 0, 0 );
488 wndPtr->dwStyle |= WS_DISABLED;
490 if ((wndPtr->dwExStyle & WS_EX_MANAGED) && (w = X11DRV_WND_GetXWindow( wndPtr )))
491 set_wm_hint( w, InputHint, FALSE );
493 if (hwnd == GetFocus())
494 SetFocus( 0 ); /* A disabled window can't have the focus */
496 if (hwnd == GetCapture())
497 ReleaseCapture(); /* A disabled window can't capture the mouse */
499 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
501 WIN_ReleaseWndPtr(wndPtr);
506 /*****************************************************************
507 * SetFocus (X11DRV.@)
510 * Explicit colormap management seems to work only with OLVWM.
512 void X11DRV_SetFocus( HWND hwnd )
514 XWindowAttributes win_attr;
516 WND *wndPtr = WIN_FindWndPtr( hwnd );
521 /* Only mess with the X focus if there's */
522 /* no desktop window and if the window is not managed by the WM. */
523 if (root_window != DefaultRootWindow(display)) goto done;
525 while (w && !((X11DRV_WND_DATA *) w->pDriverData)->window)
528 if (w->dwExStyle & WS_EX_MANAGED) goto done;
530 if (!hwnd) /* If setting the focus to 0, uninstall the colormap */
532 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
533 TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
535 else if ((win = X11DRV_WND_FindXWindow(wndPtr)))
537 /* Set X focus and install colormap */
538 if (TSXGetWindowAttributes( display, win, &win_attr ) &&
539 (win_attr.map_state == IsViewable))
541 /* If window is not viewable, don't change anything */
542 TSXSetInputFocus( display, win, RevertToParent, CurrentTime );
543 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
544 TSXInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
545 X11DRV_Synchronize();
550 WIN_ReleaseWndPtr( wndPtr );
554 /*****************************************************************
555 * SetWindowText (X11DRV.@)
557 BOOL X11DRV_SetWindowText( HWND hwnd, LPCWSTR text )
561 static UINT text_cp = (UINT)-1;
563 WND *wndPtr = WIN_FindWndPtr( hwnd );
565 if (!wndPtr) return FALSE;
566 if ((win = X11DRV_WND_GetXWindow(wndPtr)))
568 if (text_cp == (UINT)-1)
570 text_cp = PROFILE_GetWineIniInt("x11drv", "TextCP", CP_ACP);
571 TRACE("text_cp = %u\n", text_cp);
574 /* allocate new buffer for window text */
575 count = WideCharToMultiByte(text_cp, 0, text, -1, NULL, 0, NULL, NULL);
576 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WCHAR) )))
578 ERR("Not enough memory for window text\n");
579 WIN_ReleaseWndPtr( wndPtr );
582 WideCharToMultiByte(text_cp, 0, text, -1, buffer, count, NULL, NULL);
584 TSXStoreName( display, win, buffer );
585 TSXSetIconName( display, win, buffer );
586 HeapFree( GetProcessHeap(), 0, buffer );
588 WIN_ReleaseWndPtr( wndPtr );
593 /**********************************************************************
594 * X11DRV_SetWindowIcon
596 * hIcon or hIconSm has changed (or is being initialised for the
597 * first time). Complete the X11 driver-specific initialisation
598 * and set the window hints.
600 * This is not entirely correct, may need to create
601 * an icon window and set the pixmap as a background
603 HICON X11DRV_SetWindowIcon( HWND hwnd, HICON icon, BOOL small )
605 WND *wndPtr = WIN_FindWndPtr( hwnd );
606 int index = small ? GCL_HICONSM : GCL_HICON;
609 if (!wndPtr) return 0;
611 old = GetClassLongW( hwnd, index );
612 SetClassLongW( hwnd, index, icon );
614 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE |
615 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
617 if (wndPtr->dwExStyle & WS_EX_MANAGED)
619 Window win = X11DRV_WND_GetXWindow(wndPtr);
620 XWMHints* wm_hints = TSXGetWMHints( display, win );
622 if (!wm_hints) wm_hints = TSXAllocWMHints();
625 set_icon_hints( wndPtr, wm_hints );
626 TSXSetWMHints( display, win, wm_hints );
631 WIN_ReleaseWndPtr( wndPtr );