/* * X11 windows driver * * Copyright 1993, 1994, 1995, 1996 Alexandre Julliard * 1993 David Metcalfe * 1995, 1996 Alex Korobka */ #include "config.h" #include #include "ts_xlib.h" #include "ts_xutil.h" #include #include #include "bitmap.h" #include "color.h" #include "debugtools.h" #include "display.h" #include "dce.h" #include "options.h" #include "message.h" #include "heap.h" #include "win.h" #include "windef.h" #include "class.h" #include "x11drv.h" #include "wingdi.h" #include "wine/winuser16.h" DEFAULT_DEBUG_CHANNEL(win) /* Some useful macros */ #define HAS_DLGFRAME(style,exStyle) \ ((!((style) & WS_THICKFRAME)) && (((style) & WS_DLGFRAME) || ((exStyle) & WS_EX_DLGMODALFRAME))) /**********************************************************************/ extern Cursor X11DRV_MOUSE_XCursor; /* Current X cursor */ extern BOOL X11DRV_CreateBitmap( HBITMAP ); extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP ); /**********************************************************************/ /* X context to associate a hwnd to an X window */ XContext winContext = 0; Atom wmProtocols = None; Atom wmDeleteWindow = None; Atom dndProtocol = None; Atom dndSelection = None; Atom wmChangeState = None; Atom kwmDockWindow = None; /*********************************************************************** * X11DRV_WND_GetXWindow * * Return the X window associated to a window. */ Window X11DRV_WND_GetXWindow(WND *wndPtr) { return wndPtr && wndPtr->pDriverData ? ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0; } /*********************************************************************** * X11DRV_WND_FindXWindow * * Return the the first X window associated to a window chain. */ Window X11DRV_WND_FindXWindow(WND *wndPtr) { while (wndPtr && !((X11DRV_WND_DATA *) wndPtr->pDriverData)->window) wndPtr = wndPtr->parent; return wndPtr ? ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0; } /*********************************************************************** * X11DRV_WND_RegisterWindow * * Associate an X window to a HWND. */ static void X11DRV_WND_RegisterWindow(WND *wndPtr) { TSXSetWMProtocols( display, X11DRV_WND_GetXWindow(wndPtr), &wmDeleteWindow, 1 ); if (!winContext) winContext = TSXUniqueContext(); TSXSaveContext( display, X11DRV_WND_GetXWindow(wndPtr), winContext, (char *) wndPtr->hwndSelf ); } /********************************************************************** * X11DRV_WND_Initialize */ void X11DRV_WND_Initialize(WND *wndPtr) { X11DRV_WND_DATA *pWndDriverData = (X11DRV_WND_DATA *) HeapAlloc(SystemHeap, 0, sizeof(X11DRV_WND_DATA)); wndPtr->pDriverData = (void *) pWndDriverData; pWndDriverData->window = 0; } /********************************************************************** * X11DRV_WND_Finalize */ void X11DRV_WND_Finalize(WND *wndPtr) { X11DRV_WND_DATA *pWndDriverData = (X11DRV_WND_DATA *) wndPtr->pDriverData; if (!wndPtr->pDriverData) { ERR("Trying to destroy window again. Not good.\n"); return; } if(pWndDriverData->window) { ERR( "WND destroyed without destroying " "the associated X Window (%ld)\n", pWndDriverData->window ); } HeapFree(SystemHeap, 0, wndPtr->pDriverData); wndPtr->pDriverData = NULL; } /********************************************************************** * X11DRV_WND_CreateDesktopWindow */ BOOL X11DRV_WND_CreateDesktopWindow(WND *wndPtr, CLASS *classPtr, BOOL bUnicode) { if (wmProtocols == None) wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True ); if (wmDeleteWindow == None) wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True ); if( dndProtocol == None ) dndProtocol = TSXInternAtom( display, "DndProtocol" , False ); if( dndSelection == None ) dndSelection = TSXInternAtom( display, "DndSelection" , False ); if( wmChangeState == None ) wmChangeState = TSXInternAtom (display, "WM_CHANGE_STATE", False); if (kwmDockWindow == None) kwmDockWindow = TSXInternAtom( display, "KWM_DOCKWINDOW", False ); ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = X11DRV_GetXRootWindow(); X11DRV_WND_RegisterWindow( wndPtr ); return TRUE; } /********************************************************************** * X11DRV_WND_CreateWindow */ BOOL X11DRV_WND_CreateWindow(WND *wndPtr, CLASS *classPtr, CREATESTRUCTA *cs, BOOL bUnicode) { /* Create the X window (only for top-level windows, and then only */ /* when there's no desktop window) */ if (!(cs->style & WS_CHILD) && (X11DRV_GetXRootWindow() == DefaultRootWindow(display))) { Window wGroupLeader; XWMHints* wm_hints; XSetWindowAttributes win_attr; /* Create "managed" windows only if a title bar or resizable */ /* frame is required. */ if (WIN_WindowNeedsWMBorder(cs->style, cs->dwExStyle)) { win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask | StructureNotifyMask; win_attr.override_redirect = FALSE; wndPtr->flags |= WIN_MANAGED; } else { win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask; win_attr.override_redirect = TRUE; } wndPtr->flags |= WIN_NATIVE; win_attr.bit_gravity = (classPtr->style & (CS_VREDRAW | CS_HREDRAW)) ? BGForget : BGNorthWest; win_attr.colormap = X11DRV_PALETTE_PaletteXColormap; win_attr.backing_store = NotUseful; win_attr.save_under = ((classPtr->style & CS_SAVEBITS) != 0); win_attr.cursor = X11DRV_MOUSE_XCursor; ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0; ((X11DRV_WND_DATA *) wndPtr->pDriverData)->bit_gravity = win_attr.bit_gravity; ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = TSXCreateWindow( display, X11DRV_GetXRootWindow(), cs->x, cs->y, cs->cx, cs->cy, 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask | CWOverrideRedirect | CWColormap | CWCursor | CWSaveUnder | CWBackingStore | CWBitGravity, &win_attr ); if(!(wGroupLeader = X11DRV_WND_GetXWindow(wndPtr))) return FALSE; /* If we are the systray, we need to be managed to be noticed by KWM */ if (wndPtr->dwExStyle & WS_EX_TRAYWINDOW) X11DRV_WND_DockWindow(wndPtr); if (wndPtr->flags & WIN_MANAGED) { XClassHint *class_hints = TSXAllocClassHint(); XSizeHints* size_hints = TSXAllocSizeHints(); if (class_hints) { class_hints->res_name = "wineManaged"; class_hints->res_class = "Wine"; TSXSetClassHint( display, ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window, class_hints ); TSXFree (class_hints); } if (size_hints) { size_hints->win_gravity = StaticGravity; size_hints->flags = PWinGravity; if (HAS_DLGFRAME(cs->style,cs->dwExStyle)) { size_hints->min_width = size_hints->max_width = cs->cx; size_hints->min_height = size_hints->max_height = cs->cy; size_hints->flags |= PMinSize | PMaxSize; } TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(wndPtr), size_hints, XA_WM_NORMAL_HINTS ); TSXFree(size_hints); } } if (cs->hwndParent) /* Get window owner */ { Window w; WND *tmpWnd = WIN_FindWndPtr(cs->hwndParent); w = X11DRV_WND_FindXWindow( tmpWnd ); if (w != None) { TSXSetTransientForHint( display, X11DRV_WND_GetXWindow(wndPtr), w ); wGroupLeader = w; } WIN_ReleaseWndPtr(tmpWnd); } wm_hints = TSXAllocWMHints(); { wm_hints->flags = InputHint | StateHint | WindowGroupHint; wm_hints->input = True; if( wndPtr->flags & WIN_MANAGED ) { if( wndPtr->class->hIcon ) { CURSORICONINFO *ptr; if( (ptr = (CURSORICONINFO *)GlobalLock16( wndPtr->class->hIcon )) ) { /* This is not entirely correct, may need to create * an icon window and set the pixmap as a background */ HBITMAP hBitmap = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes, ptr->bBitsPerPixel, (char *)(ptr + 1) + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) ); if( hBitmap ) { ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = hBitmap; X11DRV_CreateBitmap( hBitmap ); wm_hints->flags |= IconPixmapHint; wm_hints->icon_pixmap = X11DRV_BITMAP_Pixmap( hBitmap ); } } } wm_hints->initial_state = (wndPtr->dwStyle & WS_MINIMIZE) ? IconicState : NormalState; } else wm_hints->initial_state = NormalState; wm_hints->window_group = wGroupLeader; TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints ); TSXFree(wm_hints); } X11DRV_WND_RegisterWindow( wndPtr ); } return TRUE; } /*********************************************************************** * X11DRV_WND_DestroyWindow */ BOOL X11DRV_WND_DestroyWindow(WND *wndPtr) { Window w; if ((w = X11DRV_WND_GetXWindow(wndPtr))) { XEvent xe; TSXDeleteContext( display, w, winContext ); TSXDestroyWindow( display, w ); while( TSXCheckWindowEvent(display, w, NoEventMask, &xe) ); ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None; if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap ) { DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap ); ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0; } } return TRUE; } /***************************************************************** * X11DRV_WND_SetParent */ WND *X11DRV_WND_SetParent(WND *wndPtr, WND *pWndParent) { WND *pDesktop = WIN_GetDesktop(); if( wndPtr && pWndParent && (wndPtr != pDesktop) ) { WND* pWndPrev = wndPtr->parent; if( pWndParent != pWndPrev ) { if ( X11DRV_WND_GetXWindow(wndPtr) ) { /* Toplevel window needs to be reparented. Used by Tk 8.0 */ TSXDestroyWindow( display, X11DRV_WND_GetXWindow(wndPtr) ); ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None; } WIN_UnlinkWindow(wndPtr->hwndSelf); wndPtr->parent = pWndParent; /* Create an X counterpart for reparented top-level windows * when not in the desktop mode. */ if( pWndParent == pDesktop ) { wndPtr->dwStyle &= ~WS_CHILD; wndPtr->wIDmenu = 0; if( X11DRV_GetXRootWindow() == DefaultRootWindow(display) ) { CREATESTRUCTA cs; cs.lpCreateParams = NULL; cs.hInstance = 0; /* not used in following call */ cs.hMenu = 0; /* not used in following call */ cs.hwndParent = pWndParent->hwndSelf; cs.cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top; if (!cs.cy) cs.cy = 1; cs.cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left; if (!cs.cx) cs.cx = 1; cs.y = wndPtr->rectWindow.top; cs.x = wndPtr->rectWindow.left; cs.style = wndPtr->dwStyle; cs.lpszName = 0; /* not used in following call */ cs.lpszClass = 0; /*not used in following call */ cs.dwExStyle = wndPtr->dwExStyle; X11DRV_WND_CreateWindow(wndPtr, wndPtr->class, &cs, FALSE); } } else /* a child window */ { if( !( wndPtr->dwStyle & WS_CHILD ) ) { wndPtr->dwStyle |= WS_CHILD; if( wndPtr->wIDmenu != 0) { DestroyMenu( (HMENU) wndPtr->wIDmenu ); wndPtr->wIDmenu = 0; } } } WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP); } WIN_ReleaseDesktop(); return pWndPrev; } /* failure */ WIN_ReleaseDesktop(); return 0; } /*********************************************************************** * X11DRV_WND_ForceWindowRaise * * Raise a window on top of the X stacking order, while preserving * the correct Windows Z order. */ void X11DRV_WND_ForceWindowRaise(WND *wndPtr) { XWindowChanges winChanges; WND *wndPrev,*pDesktop = WIN_GetDesktop(); if( !wndPtr || !X11DRV_WND_GetXWindow(wndPtr) || (wndPtr->flags & WIN_MANAGED) ) { WIN_ReleaseDesktop(); return; } /* Raise all windows up to wndPtr according to their Z order. * (it would be easier with sibling-related Below but it doesn't * work very well with SGI mwm for instance) */ winChanges.stack_mode = Above; while (wndPtr) { if (X11DRV_WND_GetXWindow(wndPtr)) TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(wndPtr), 0, CWStackMode, &winChanges ); wndPrev = pDesktop->child; if (wndPrev == wndPtr) break; while (wndPrev && (wndPrev->next != wndPtr)) wndPrev = wndPrev->next; wndPtr = wndPrev; } WIN_ReleaseDesktop(); } /*********************************************************************** * X11DRV_WND_FindDesktopXWindow [Internal] * * Find the actual X window which needs be restacked. * Used by X11DRV_WND_SetWindowPos(). */ static Window X11DRV_WND_FindDesktopXWindow( WND *wndPtr ) { if (!(wndPtr->flags & WIN_MANAGED)) return X11DRV_WND_GetXWindow(wndPtr); else { Window window, root, parent, *children; int nchildren; window = X11DRV_WND_GetXWindow(wndPtr); for (;;) { TSXQueryTree( display, window, &root, &parent, &children, &nchildren ); TSXFree( children ); if (parent == root) return window; window = parent; } } } /*********************************************************************** * WINPOS_SetXWindowPos * * SetWindowPos() for an X window. Used by the real SetWindowPos(). */ void X11DRV_WND_SetWindowPos(WND *wndPtr, const WINDOWPOS *winpos, BOOL bChangePos) { XWindowChanges winChanges; int changeMask = 0; WND *winposPtr = WIN_FindWndPtr( winpos->hwnd ); if ( !winposPtr ) return; if(!wndPtr->hwndSelf) wndPtr = NULL; /* FIXME: WND destroyed, shouldn't happen!!! */ if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW)) { if(X11DRV_WND_GetXWindow(wndPtr)) TSXUnmapWindow( display, X11DRV_WND_GetXWindow(wndPtr) ); } if(bChangePos) { if ( !(winpos->flags & SWP_NOSIZE)) { winChanges.width = (winpos->cx > 0 ) ? winpos->cx : 1; winChanges.height = (winpos->cy > 0 ) ? winpos->cy : 1; changeMask |= CWWidth | CWHeight; /* Tweak dialog window size hints */ if ((winposPtr->flags & WIN_MANAGED) && HAS_DLGFRAME(winposPtr->dwStyle,winposPtr->dwExStyle)) { XSizeHints *size_hints = TSXAllocSizeHints(); if (size_hints) { long supplied_return; TSXGetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints, &supplied_return, XA_WM_NORMAL_HINTS); size_hints->min_width = size_hints->max_width = winpos->cx; size_hints->min_height = size_hints->max_height = winpos->cy; TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints, XA_WM_NORMAL_HINTS ); TSXFree(size_hints); } } } if (!(winpos->flags & SWP_NOMOVE)) { winChanges.x = winpos->x; winChanges.y = winpos->y; changeMask |= CWX | CWY; } if (!(winpos->flags & SWP_NOZORDER)) { winChanges.stack_mode = Below; changeMask |= CWStackMode; if (winpos->hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above; else if (winpos->hwndInsertAfter != HWND_BOTTOM) { WND* insertPtr = WIN_FindWndPtr( winpos->hwndInsertAfter ); Window stack[2]; stack[0] = X11DRV_WND_FindDesktopXWindow( insertPtr ); stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr ); /* for stupid window managers (i.e. all of them) */ TSXRestackWindows(display, stack, 2); changeMask &= ~CWStackMode; WIN_ReleaseWndPtr(insertPtr); } } if (changeMask && X11DRV_WND_GetXWindow(winposPtr)) { TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(winposPtr), 0, changeMask, &winChanges ); if( winposPtr->class->style & (CS_VREDRAW | CS_HREDRAW) ) X11DRV_WND_SetHostAttr( winposPtr, HAK_BITGRAVITY, BGForget ); } } if ( winpos->flags & SWP_SHOWWINDOW ) { if(X11DRV_WND_GetXWindow(wndPtr)) TSXMapWindow( display, X11DRV_WND_GetXWindow(wndPtr) ); } WIN_ReleaseWndPtr(winposPtr); } /***************************************************************** * X11DRV_WND_SetText */ void X11DRV_WND_SetText(WND *wndPtr, LPCSTR text) { if (!X11DRV_WND_GetXWindow(wndPtr)) return; TSXStoreName( display, X11DRV_WND_GetXWindow(wndPtr), text ); TSXSetIconName( display, X11DRV_WND_GetXWindow(wndPtr), text ); } /***************************************************************** * X11DRV_WND_SetFocus * * Set the X focus. * Explicit colormap management seems to work only with OLVWM. */ void X11DRV_WND_SetFocus(WND *wndPtr) { HWND hwnd = wndPtr->hwndSelf; XWindowAttributes win_attr; Window win; /* Only mess with the X focus if there's */ /* no desktop window and if the window is not managed by the WM. */ if ((X11DRV_GetXRootWindow() != DefaultRootWindow(display)) || (wndPtr->flags & WIN_MANAGED)) return; if (!hwnd) /* If setting the focus to 0, uninstall the colormap */ { if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE) TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap ); return; } /* Set X focus and install colormap */ if (!(win = X11DRV_WND_FindXWindow(wndPtr))) return; if (!TSXGetWindowAttributes( display, win, &win_attr ) || (win_attr.map_state != IsViewable)) return; /* If window is not viewable, don't change anything */ TSXSetInputFocus( display, win, RevertToParent, CurrentTime ); if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE) TSXInstallColormap( display, X11DRV_PALETTE_PaletteXColormap ); EVENT_Synchronize(); } /***************************************************************** * X11DRV_WND_PreSizeMove */ void X11DRV_WND_PreSizeMove(WND *wndPtr) { if (!(wndPtr->dwStyle & WS_CHILD) && (X11DRV_GetXRootWindow() == DefaultRootWindow(display))) TSXGrabServer( display ); } /***************************************************************** * X11DRV_WND_PostSizeMove */ void X11DRV_WND_PostSizeMove(WND *wndPtr) { if (!(wndPtr->dwStyle & WS_CHILD) && (X11DRV_GetXRootWindow() == DefaultRootWindow(display))) TSXUngrabServer( display ); } /***************************************************************** * X11DRV_WND_SurfaceCopy * * Copies rect to (rect.left + dx, rect.top + dy). */ void X11DRV_WND_SurfaceCopy(WND* wndPtr, DC *dcPtr, INT dx, INT dy, const RECT *rect, BOOL bUpdate) { X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dcPtr->physDev; POINT dst, src; dst.x = (src.x = dcPtr->w.DCOrgX + rect->left) + dx; dst.y = (src.y = dcPtr->w.DCOrgY + rect->top) + dy; if (bUpdate) /* handles non-Wine windows hanging over the copied area */ TSXSetGraphicsExposures( display, physDev->gc, True ); TSXSetFunction( display, physDev->gc, GXcopy ); TSXCopyArea( display, physDev->drawable, physDev->drawable, physDev->gc, src.x, src.y, rect->right - rect->left, rect->bottom - rect->top, dst.x, dst.y ); if (bUpdate) TSXSetGraphicsExposures( display, physDev->gc, False ); if (bUpdate) /* Make sure exposure events have been processed */ EVENT_Synchronize(); } /*********************************************************************** * X11DRV_WND_SetDrawable * * Set the drawable, origin and dimensions for the DC associated to * a given window. */ void X11DRV_WND_SetDrawable(WND *wndPtr, DC *dc, WORD flags, BOOL bSetClipOrigin) { X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev; INT dcOrgXCopy = 0, dcOrgYCopy = 0; BOOL offsetClipRgn = FALSE; if (!wndPtr) /* Get a DC for the whole screen */ { dc->w.DCOrgX = 0; dc->w.DCOrgY = 0; physDev->drawable = X11DRV_GetXRootWindow(); TSXSetSubwindowMode( display, physDev->gc, IncludeInferiors ); } else { /* * This function change the coordinate system (DCOrgX,DCOrgY) * values. When it moves the origin, other data like the current clipping * region will not be moved to that new origin. In the case of DCs that are class * or window DCs that clipping region might be a valid value from a previous use * of the DC and changing the origin of the DC without moving the clip region * results in a clip region that is not placed properly in the DC. * This code will save the dc origin, let the SetDrawable * modify the origin and reset the clipping. When the clipping is set, * it is moved according to the new DC origin. */ if ( (wndPtr->class->style & (CS_OWNDC | CS_CLASSDC)) && (dc->w.hClipRgn > 0)) { dcOrgXCopy = dc->w.DCOrgX; dcOrgYCopy = dc->w.DCOrgY; offsetClipRgn = TRUE; } if (flags & DCX_WINDOW) { dc->w.DCOrgX = wndPtr->rectWindow.left; dc->w.DCOrgY = wndPtr->rectWindow.top; } else { dc->w.DCOrgX = wndPtr->rectClient.left; dc->w.DCOrgY = wndPtr->rectClient.top; } while (!X11DRV_WND_GetXWindow(wndPtr)) { wndPtr = wndPtr->parent; dc->w.DCOrgX += wndPtr->rectClient.left; dc->w.DCOrgY += wndPtr->rectClient.top; } dc->w.DCOrgX -= wndPtr->rectWindow.left; dc->w.DCOrgY -= wndPtr->rectWindow.top; /* reset the clip region, according to the new origin */ if ( offsetClipRgn ) { OffsetRgn(dc->w.hClipRgn, dc->w.DCOrgX - dcOrgXCopy,dc->w.DCOrgY - dcOrgYCopy); } physDev->drawable = X11DRV_WND_GetXWindow(wndPtr); #if 0 /* This is needed when we reuse a cached DC because * SetDCState() called by ReleaseDC() screws up DC * origins for child windows. */ if( bSetClipOrigin ) TSXSetClipOrigin( display, physDev->gc, dc->w.DCOrgX, dc->w.DCOrgY ); #endif } } /*********************************************************************** * X11DRV_SetWMHint */ static BOOL X11DRV_SetWMHint(Display* display, WND* wndPtr, int hint, int val) { XWMHints* wm_hints = TSXAllocWMHints(); { wm_hints->flags = hint; switch( hint ) { case InputHint: wm_hints->input = val; break; case StateHint: wm_hints->initial_state = val; break; case IconPixmapHint: wm_hints->icon_pixmap = (Pixmap)val; break; case IconWindowHint: wm_hints->icon_window = (Window)val; break; } TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints ); TSXFree(wm_hints); return TRUE; } return FALSE; } /*********************************************************************** * X11DRV_WND_SetHostAttr * * This function returns TRUE if the attribute is supported and the * action was successful. Otherwise it should return FALSE and Wine will try * to get by without the functionality provided by the host window system. */ BOOL X11DRV_WND_SetHostAttr(WND* wnd, INT ha, INT value) { Window w; if( (w = X11DRV_WND_GetXWindow(wnd)) ) { XSetWindowAttributes win_attr; switch( ha ) { case HAK_ICONICSTATE: /* called when a window is minimized/restored */ if( (wnd->flags & WIN_MANAGED) ) { if( value ) { if( wnd->dwStyle & WS_VISIBLE ) { XClientMessageEvent ev; /* FIXME: set proper icon */ ev.type = ClientMessage; ev.display = display; ev.message_type = wmChangeState; ev.format = 32; ev.data.l[0] = IconicState; ev.window = w; if( TSXSendEvent (display, RootWindow( display, XScreenNumberOfScreen(X11DRV_GetXScreen()) ), True, (SubstructureRedirectMask | SubstructureNotifyMask), (XEvent*)&ev)) { XEvent xe; TSXFlush (display); while( !TSXCheckTypedWindowEvent( display, w, UnmapNotify, &xe) ); } else break; } else X11DRV_SetWMHint( display, wnd, StateHint, IconicState ); } else { if( !(wnd->flags & WS_VISIBLE) ) X11DRV_SetWMHint( display, wnd, StateHint, NormalState ); else { XEvent xe; TSXMapWindow(display, w ); while( !TSXCheckTypedWindowEvent( display, w, MapNotify, &xe) ); } } return TRUE; } break; case HAK_BITGRAVITY: /* called when a window is resized */ if( ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity != value ) { win_attr.bit_gravity = value; ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity = value; TSXChangeWindowAttributes( display, w, CWBitGravity, &win_attr ); } return TRUE; case HAK_ACCEPTFOCUS: /* called when a window is disabled/enabled */ if( (wnd->flags & WIN_MANAGED) ) return X11DRV_SetWMHint( display, wnd, InputHint, value ); } } return FALSE; } /*********************************************************************** * X11DRV_WND_IsSelfClipping */ BOOL X11DRV_WND_IsSelfClipping(WND *wndPtr) { return X11DRV_WND_GetXWindow(wndPtr) != None; } /*********************************************************************** * X11DRV_WND_DockWindow * * Set the X Property of the window that tells the windowmanager we really * want to be in the systray * * KDE: set "KWM_DOCKWINDOW", type "KWM_DOCKWINDOW" to 1 before a window is * mapped. * * all others: to be added ;) */ void X11DRV_WND_DockWindow(WND *wndPtr) { int data = 1; Window win = X11DRV_WND_GetXWindow(wndPtr); if (kwmDockWindow == None) return; /* no KDE running */ TSXChangeProperty( display,win,kwmDockWindow,kwmDockWindow,32,PropModeReplace,(char*)&data,1 ); }