| /* |
| * Window related functions |
| * |
| * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard |
| * Copyright 1993 David Metcalfe |
| * Copyright 1995, 1996 Alex Korobka |
| */ |
| |
| #include "config.h" |
| |
| #include "ts_xlib.h" |
| #include "ts_xutil.h" |
| |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| |
| #include "debugtools.h" |
| #include "x11drv.h" |
| #include "win.h" |
| #include "dce.h" |
| #include "options.h" |
| |
| DEFAULT_DEBUG_CHANNEL(win); |
| |
| extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP ); |
| |
| #define HAS_DLGFRAME(style,exStyle) \ |
| ((!((style) & WS_THICKFRAME)) && (((style) & WS_DLGFRAME) || ((exStyle) & WS_EX_DLGMODALFRAME))) |
| |
| /* 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; |
| Atom _kde_net_wm_system_tray_window_for = None; /* KDE 2 Final */ |
| |
| |
| /*********************************************************************** |
| * X11DRV_register_window |
| * |
| * Associate an X window to a HWND. |
| */ |
| void X11DRV_register_window( Display *display, HWND hwnd, Window win ) |
| { |
| if (!winContext) winContext = TSXUniqueContext(); |
| TSXSaveContext( display, win, winContext, (char *)hwnd ); |
| TSXSetWMProtocols( display, win, &wmDeleteWindow, 1 ); |
| } |
| |
| |
| /*********************************************************************** |
| * set_wm_hint |
| * |
| * Set a window manager hint. |
| */ |
| static void set_wm_hint( Display *display, Window win, int hint, int val ) |
| { |
| XWMHints* wm_hints = TSXGetWMHints( display, win ); |
| if (!wm_hints) wm_hints = TSXAllocWMHints(); |
| if (wm_hints) |
| { |
| 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, win, wm_hints ); |
| TSXFree(wm_hints); |
| } |
| } |
| |
| |
| /*********************************************************************** |
| * set_icon_hints |
| * |
| * Set the icon wm hints |
| */ |
| static void set_icon_hints( Display *display, WND *wndPtr, XWMHints *hints ) |
| { |
| X11DRV_WND_DATA *data = wndPtr->pDriverData; |
| HICON hIcon = GetClassLongA( wndPtr->hwndSelf, GCL_HICON ); |
| |
| if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap ); |
| if (data->hWMIconMask) DeleteObject( data->hWMIconMask); |
| |
| if (!hIcon) |
| { |
| data->hWMIconBitmap = 0; |
| data->hWMIconMask = 0; |
| hints->flags &= ~(IconPixmapHint | IconMaskHint); |
| } |
| else |
| { |
| HBITMAP hbmOrig; |
| RECT rcMask; |
| BITMAP bmMask; |
| ICONINFO ii; |
| HDC hDC; |
| |
| GetIconInfo(hIcon, &ii); |
| |
| X11DRV_CreateBitmap(ii.hbmMask); |
| X11DRV_CreateBitmap(ii.hbmColor); |
| |
| GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask); |
| rcMask.top = 0; |
| rcMask.left = 0; |
| rcMask.right = bmMask.bmWidth; |
| rcMask.bottom = bmMask.bmHeight; |
| |
| hDC = CreateCompatibleDC(0); |
| hbmOrig = SelectObject(hDC, ii.hbmMask); |
| InvertRect(hDC, &rcMask); |
| SelectObject(hDC, hbmOrig); |
| DeleteDC(hDC); |
| |
| data->hWMIconBitmap = ii.hbmColor; |
| data->hWMIconMask = ii.hbmMask; |
| |
| hints->icon_pixmap = X11DRV_BITMAP_Pixmap(data->hWMIconBitmap); |
| hints->icon_mask = X11DRV_BITMAP_Pixmap(data->hWMIconMask); |
| hints->flags |= IconPixmapHint | IconMaskHint; |
| } |
| } |
| |
| |
| /*********************************************************************** |
| * dock_window |
| * |
| * 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 ;) |
| */ |
| inline static void dock_window( Display *display, Window win ) |
| { |
| int data = 1; |
| if (kwmDockWindow != None) |
| TSXChangeProperty( display, win, kwmDockWindow, kwmDockWindow, |
| 32, PropModeReplace, (char*)&data, 1 ); |
| if (_kde_net_wm_system_tray_window_for != None) |
| TSXChangeProperty( display, win, _kde_net_wm_system_tray_window_for, XA_WINDOW, |
| 32, PropModeReplace, (char*)&win, 1 ); |
| } |
| |
| |
| /********************************************************************** |
| * create_desktop |
| */ |
| static void create_desktop( Display *display, WND *wndPtr ) |
| { |
| X11DRV_WND_DATA *data = wndPtr->pDriverData; |
| |
| wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True ); |
| wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True ); |
| dndProtocol = TSXInternAtom( display, "DndProtocol" , False ); |
| dndSelection = TSXInternAtom( display, "DndSelection" , False ); |
| wmChangeState = TSXInternAtom (display, "WM_CHANGE_STATE", False); |
| kwmDockWindow = TSXInternAtom( display, "KWM_DOCKWINDOW", False ); |
| _kde_net_wm_system_tray_window_for = TSXInternAtom( display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False ); |
| |
| data->window = root_window; |
| if (root_window != DefaultRootWindow(display)) |
| { |
| wndPtr->flags |= WIN_NATIVE; |
| X11DRV_create_desktop_thread(); |
| } |
| } |
| |
| |
| /********************************************************************** |
| * CreateWindow (X11DRV.@) |
| */ |
| BOOL X11DRV_CreateWindow( HWND hwnd ) |
| { |
| Display *display = thread_display(); |
| X11DRV_WND_DATA *data; |
| WND *wndPtr = WIN_FindWndPtr( hwnd ); |
| int x = wndPtr->rectWindow.left; |
| int y = wndPtr->rectWindow.top; |
| int cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left; |
| int cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top; |
| |
| if (!(data = HeapAlloc(GetProcessHeap(), 0, sizeof(X11DRV_WND_DATA)))) |
| { |
| WIN_ReleaseWndPtr( wndPtr ); |
| return FALSE; |
| } |
| data->window = 0; |
| wndPtr->pDriverData = data; |
| |
| if (!wndPtr->parent) |
| { |
| create_desktop( display, wndPtr ); |
| WIN_ReleaseWndPtr( wndPtr ); |
| return TRUE; |
| } |
| |
| /* Create the X window (only for top-level windows, and then only */ |
| /* when there's no desktop window) */ |
| |
| if ((root_window == DefaultRootWindow(display)) |
| && (wndPtr->parent->hwndSelf == GetDesktopWindow())) |
| { |
| Window wGroupLeader; |
| XWMHints* wm_hints; |
| XSetWindowAttributes win_attr; |
| |
| /* Create "managed" windows only if a title bar or resizable */ |
| /* frame is required. */ |
| if (WIN_WindowNeedsWMBorder(wndPtr->dwStyle, wndPtr->dwExStyle)) |
| { |
| win_attr.event_mask = ExposureMask | KeyPressMask | |
| KeyReleaseMask | PointerMotionMask | |
| ButtonPressMask | ButtonReleaseMask | |
| FocusChangeMask | StructureNotifyMask; |
| win_attr.override_redirect = FALSE; |
| wndPtr->dwExStyle |= WS_EX_MANAGED; |
| } |
| else |
| { |
| win_attr.event_mask = ExposureMask | KeyPressMask | |
| KeyReleaseMask | PointerMotionMask | |
| ButtonPressMask | ButtonReleaseMask | |
| FocusChangeMask; |
| win_attr.override_redirect = TRUE; |
| } |
| wndPtr->flags |= WIN_NATIVE; |
| |
| wine_tsx11_lock(); |
| |
| win_attr.bit_gravity = (wndPtr->clsStyle & (CS_VREDRAW | CS_HREDRAW)) ? ForgetGravity : NorthWestGravity; |
| win_attr.colormap = X11DRV_PALETTE_PaletteXColormap; |
| win_attr.backing_store = NotUseful; |
| win_attr.save_under = ((wndPtr->clsStyle & CS_SAVEBITS) != 0); |
| win_attr.cursor = X11DRV_GetCursor( display, GlobalLock16(GetCursor()) ); |
| |
| data->hWMIconBitmap = 0; |
| data->hWMIconMask = 0; |
| data->bit_gravity = win_attr.bit_gravity; |
| |
| /* Zero-size X11 window hack. X doesn't like them, and will crash */ |
| /* with a BadValue unless we do something ugly like this. */ |
| /* Zero size window won't be mapped */ |
| if (cx <= 0) cx = 1; |
| if (cy <= 0) cy = 1; |
| |
| data->window = XCreateWindow( display, root_window, |
| x, y, cx, cy, |
| 0, screen_depth, |
| InputOutput, visual, |
| CWEventMask | CWOverrideRedirect | |
| CWColormap | CWCursor | CWSaveUnder | |
| CWBackingStore | CWBitGravity, |
| &win_attr ); |
| |
| if (win_attr.cursor) XFreeCursor( display, win_attr.cursor ); |
| wine_tsx11_unlock(); |
| |
| if(!(wGroupLeader = data->window)) |
| { |
| HeapFree( GetProcessHeap(), 0, data ); |
| WIN_ReleaseWndPtr( wndPtr ); |
| return FALSE; |
| } |
| |
| /* If we are the systray, we need to be managed to be noticed by KWM */ |
| if (wndPtr->dwExStyle & WS_EX_TRAYWINDOW) dock_window( display, data->window ); |
| |
| if (wndPtr->dwExStyle & WS_EX_MANAGED) |
| { |
| XClassHint *class_hints = TSXAllocClassHint(); |
| XSizeHints* size_hints = TSXAllocSizeHints(); |
| |
| if (class_hints) |
| { |
| class_hints->res_name = "wineManaged"; |
| class_hints->res_class = "Wine"; |
| TSXSetClassHint( display, data->window, class_hints ); |
| TSXFree (class_hints); |
| } |
| |
| if (size_hints) |
| { |
| size_hints->win_gravity = StaticGravity; |
| size_hints->x = x; |
| size_hints->y = y; |
| size_hints->flags = PWinGravity|PPosition; |
| |
| if (HAS_DLGFRAME(wndPtr->dwStyle,wndPtr->dwExStyle)) |
| { |
| size_hints->min_width = size_hints->max_width = cx; |
| size_hints->min_height = size_hints->max_height = cy; |
| size_hints->flags |= PMinSize | PMaxSize; |
| } |
| |
| TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(wndPtr), |
| size_hints, XA_WM_NORMAL_HINTS ); |
| TSXFree(size_hints); |
| } |
| } |
| |
| if (wndPtr->owner) /* Get window owner */ |
| { |
| Window w = X11DRV_WND_FindXWindow( wndPtr->owner ); |
| if (w != None) |
| { |
| TSXSetTransientForHint( display, X11DRV_WND_GetXWindow(wndPtr), w ); |
| wGroupLeader = w; |
| } |
| } |
| |
| if ((wm_hints = TSXAllocWMHints())) |
| { |
| wm_hints->flags = InputHint | StateHint | WindowGroupHint; |
| wm_hints->input = True; |
| |
| if (wndPtr->dwExStyle & WS_EX_MANAGED) |
| { |
| set_icon_hints( display, wndPtr, wm_hints ); |
| 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_register_window( display, hwnd, data->window ); |
| TSXFlush( display ); |
| } |
| WIN_ReleaseWndPtr( wndPtr ); |
| return TRUE; |
| } |
| |
| |
| /*********************************************************************** |
| * DestroyWindow (X11DRV.@) |
| */ |
| BOOL X11DRV_DestroyWindow( HWND hwnd ) |
| { |
| Display *display = thread_display(); |
| WND *wndPtr = WIN_FindWndPtr( hwnd ); |
| X11DRV_WND_DATA *data = wndPtr->pDriverData; |
| Window w; |
| |
| if (data && (w = data->window)) |
| { |
| XEvent xe; |
| wine_tsx11_lock(); |
| XSync( gdi_display, False ); /* flush any reference to this drawable in GDI queue */ |
| XDeleteContext( display, w, winContext ); |
| XDestroyWindow( display, w ); |
| while( XCheckWindowEvent(display, w, NoEventMask, &xe) ); |
| wine_tsx11_unlock(); |
| |
| data->window = None; |
| if( data->hWMIconBitmap ) |
| { |
| DeleteObject( data->hWMIconBitmap ); |
| data->hWMIconBitmap = 0; |
| } |
| if( data->hWMIconMask ) |
| { |
| DeleteObject( data->hWMIconMask); |
| data->hWMIconMask= 0; |
| } |
| } |
| HeapFree( GetProcessHeap(), 0, data ); |
| wndPtr->pDriverData = NULL; |
| WIN_ReleaseWndPtr( wndPtr ); |
| return TRUE; |
| } |
| |
| |
| /***************************************************************** |
| * SetParent (X11DRV.@) |
| */ |
| HWND X11DRV_SetParent( HWND hwnd, HWND parent ) |
| { |
| Display *display = thread_display(); |
| WND *wndPtr; |
| WND *pWndParent; |
| DWORD dwStyle; |
| HWND retvalue; |
| |
| if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0; |
| |
| dwStyle = wndPtr->dwStyle; |
| |
| if (!parent) parent = GetDesktopWindow(); |
| |
| if (!(pWndParent = WIN_FindWndPtr(parent))) |
| { |
| WIN_ReleaseWndPtr( wndPtr ); |
| return 0; |
| } |
| |
| /* Windows hides the window first, then shows it again |
| * including the WM_SHOWWINDOW messages and all */ |
| if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE ); |
| |
| retvalue = wndPtr->parent->hwndSelf; /* old parent */ |
| if (pWndParent != wndPtr->parent) |
| { |
| 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 (parent == GetDesktopWindow()) |
| { |
| if(root_window == DefaultRootWindow(display)) |
| X11DRV_CreateWindow(wndPtr->hwndSelf); |
| } |
| else /* a child window */ |
| { |
| if( !( wndPtr->dwStyle & WS_CHILD ) ) |
| { |
| if( wndPtr->wIDmenu != 0) |
| { |
| DestroyMenu( (HMENU) wndPtr->wIDmenu ); |
| wndPtr->wIDmenu = 0; |
| } |
| } |
| } |
| WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP); |
| } |
| WIN_ReleaseWndPtr( pWndParent ); |
| WIN_ReleaseWndPtr( wndPtr ); |
| |
| /* SetParent additionally needs to make hwnd the topmost window |
| in the x-order and send the expected WM_WINDOWPOSCHANGING and |
| WM_WINDOWPOSCHANGED notification messages. |
| */ |
| SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, |
| SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE| |
| ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0)); |
| /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler |
| * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */ |
| |
| return retvalue; |
| } |
| |
| |
| /******************************************************************* |
| * EnableWindow (X11DRV.@) |
| */ |
| BOOL X11DRV_EnableWindow( HWND hwnd, BOOL enable ) |
| { |
| Display *display = thread_display(); |
| WND *wndPtr; |
| BOOL retvalue; |
| Window w; |
| |
| if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE; |
| |
| retvalue = ((wndPtr->dwStyle & WS_DISABLED) != 0); |
| |
| if (enable && (wndPtr->dwStyle & WS_DISABLED)) |
| { |
| /* Enable window */ |
| wndPtr->dwStyle &= ~WS_DISABLED; |
| |
| if ((wndPtr->dwExStyle & WS_EX_MANAGED) && (w = X11DRV_WND_GetXWindow( wndPtr ))) |
| set_wm_hint( display, w, InputHint, TRUE ); |
| |
| SendMessageA( hwnd, WM_ENABLE, TRUE, 0 ); |
| } |
| else if (!enable && !(wndPtr->dwStyle & WS_DISABLED)) |
| { |
| SendMessageA( wndPtr->hwndSelf, WM_CANCELMODE, 0, 0 ); |
| |
| /* Disable window */ |
| wndPtr->dwStyle |= WS_DISABLED; |
| |
| if ((wndPtr->dwExStyle & WS_EX_MANAGED) && (w = X11DRV_WND_GetXWindow( wndPtr ))) |
| set_wm_hint( display, w, InputHint, FALSE ); |
| |
| if (hwnd == GetFocus()) |
| SetFocus( 0 ); /* A disabled window can't have the focus */ |
| |
| if (hwnd == GetCapture()) |
| ReleaseCapture(); /* A disabled window can't capture the mouse */ |
| |
| SendMessageA( hwnd, WM_ENABLE, FALSE, 0 ); |
| } |
| WIN_ReleaseWndPtr(wndPtr); |
| return retvalue; |
| } |
| |
| |
| /***************************************************************** |
| * SetFocus (X11DRV.@) |
| * |
| * Set the X focus. |
| * Explicit colormap management seems to work only with OLVWM. |
| */ |
| void X11DRV_SetFocus( HWND hwnd ) |
| { |
| Display *display = thread_display(); |
| XWindowAttributes win_attr; |
| Window win; |
| WND *wndPtr = WIN_FindWndPtr( hwnd ); |
| WND *w = wndPtr; |
| |
| if (!wndPtr) return; |
| |
| /* Only mess with the X focus if there's */ |
| /* no desktop window and if the window is not managed by the WM. */ |
| if (root_window != DefaultRootWindow(display)) goto done; |
| |
| while (w && !((X11DRV_WND_DATA *) w->pDriverData)->window) |
| w = w->parent; |
| if (!w) w = wndPtr; |
| if (w->dwExStyle & WS_EX_MANAGED) goto done; |
| |
| if (!hwnd) /* If setting the focus to 0, uninstall the colormap */ |
| { |
| if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE) |
| TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap ); |
| } |
| else if ((win = X11DRV_WND_FindXWindow(wndPtr))) |
| { |
| /* Set X focus and install colormap */ |
| if (TSXGetWindowAttributes( display, win, &win_attr ) && |
| (win_attr.map_state == IsViewable)) |
| { |
| /* 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 ); |
| X11DRV_Synchronize(); |
| } |
| } |
| |
| done: |
| WIN_ReleaseWndPtr( wndPtr ); |
| } |
| |
| |
| /***************************************************************** |
| * SetWindowText (X11DRV.@) |
| */ |
| BOOL X11DRV_SetWindowText( HWND hwnd, LPCWSTR text ) |
| { |
| Display *display = thread_display(); |
| UINT count; |
| char *buffer; |
| static UINT text_cp = (UINT)-1; |
| Window win; |
| WND *wndPtr = WIN_FindWndPtr( hwnd ); |
| |
| if (!wndPtr) return FALSE; |
| if ((win = X11DRV_WND_GetXWindow(wndPtr))) |
| { |
| if (text_cp == (UINT)-1) |
| { |
| text_cp = PROFILE_GetWineIniInt("x11drv", "TextCP", CP_ACP); |
| TRACE("text_cp = %u\n", text_cp); |
| } |
| |
| /* allocate new buffer for window text */ |
| count = WideCharToMultiByte(text_cp, 0, text, -1, NULL, 0, NULL, NULL); |
| if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WCHAR) ))) |
| { |
| ERR("Not enough memory for window text\n"); |
| WIN_ReleaseWndPtr( wndPtr ); |
| return FALSE; |
| } |
| WideCharToMultiByte(text_cp, 0, text, -1, buffer, count, NULL, NULL); |
| |
| TSXStoreName( display, win, buffer ); |
| TSXSetIconName( display, win, buffer ); |
| HeapFree( GetProcessHeap(), 0, buffer ); |
| } |
| WIN_ReleaseWndPtr( wndPtr ); |
| return TRUE; |
| } |
| |
| |
| /********************************************************************** |
| * X11DRV_SetWindowIcon |
| * |
| * hIcon or hIconSm has changed (or is being initialised for the |
| * first time). Complete the X11 driver-specific initialisation |
| * and set the window hints. |
| * |
| * This is not entirely correct, may need to create |
| * an icon window and set the pixmap as a background |
| */ |
| HICON X11DRV_SetWindowIcon( HWND hwnd, HICON icon, BOOL small ) |
| { |
| Display *display = thread_display(); |
| WND *wndPtr = WIN_FindWndPtr( hwnd ); |
| int index = small ? GCL_HICONSM : GCL_HICON; |
| HICON old; |
| |
| if (!wndPtr) return 0; |
| |
| old = GetClassLongW( hwnd, index ); |
| SetClassLongW( hwnd, index, icon ); |
| |
| SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | |
| SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER ); |
| |
| if (wndPtr->dwExStyle & WS_EX_MANAGED) |
| { |
| Window win = X11DRV_WND_GetXWindow(wndPtr); |
| XWMHints* wm_hints = TSXGetWMHints( display, win ); |
| |
| if (!wm_hints) wm_hints = TSXAllocWMHints(); |
| if (wm_hints) |
| { |
| set_icon_hints( display, wndPtr, wm_hints ); |
| TSXSetWMHints( display, win, wm_hints ); |
| TSXFree( wm_hints ); |
| } |
| } |
| |
| WIN_ReleaseWndPtr( wndPtr ); |
| return old; |
| } |
| |
| |
| /************************************************************************* |
| * fix_caret |
| */ |
| static BOOL fix_caret(HWND hWnd, LPRECT lprc, UINT flags) |
| { |
| HWND hCaret = CARET_GetHwnd(); |
| |
| if( hCaret ) |
| { |
| RECT rc; |
| CARET_GetRect( &rc ); |
| if( hCaret == hWnd || |
| (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) ) |
| { |
| POINT pt; |
| pt.x = rc.left; |
| pt.y = rc.top; |
| MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 ); |
| if( IntersectRect(lprc, lprc, &rc) ) |
| { |
| HideCaret(0); |
| lprc->left = pt.x; |
| lprc->top = pt.y; |
| return TRUE; |
| } |
| } |
| } |
| return FALSE; |
| } |
| |
| |
| /************************************************************************* |
| * ScrollWindowEx (X11DRV.@) |
| */ |
| INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy, |
| const RECT *rect, const RECT *clipRect, |
| HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags ) |
| { |
| INT retVal = NULLREGION; |
| BOOL bCaret = FALSE, bOwnRgn = TRUE; |
| RECT rc, cliprc; |
| WND* wnd = WIN_FindWndPtr( hwnd ); |
| |
| if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE )) |
| { |
| retVal = ERROR; |
| goto END; |
| } |
| |
| GetClientRect(hwnd, &rc); |
| if (rect) IntersectRect(&rc, &rc, rect); |
| |
| if (clipRect) IntersectRect(&cliprc,&rc,clipRect); |
| else cliprc = rc; |
| |
| if (!IsRectEmpty(&cliprc) && (dx || dy)) |
| { |
| HDC hDC; |
| BOOL bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE)); |
| HRGN hrgnClip = CreateRectRgnIndirect(&cliprc); |
| HRGN hrgnTemp = CreateRectRgnIndirect(&rc); |
| RECT caretrc; |
| |
| TRACE("%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p cliprc = (%d,%d-%d,%d), rc=(%d,%d-%d,%d) %04x\n", |
| (HWND16)hwnd, dx, dy, hrgnUpdate, rcUpdate, |
| clipRect?clipRect->left:0, clipRect?clipRect->top:0, |
| clipRect?clipRect->right:0, clipRect?clipRect->bottom:0, |
| rc.left, rc.top, rc.right, rc.bottom, (UINT16)flags ); |
| |
| caretrc = rc; |
| bCaret = fix_caret(hwnd, &caretrc, flags); |
| |
| if( hrgnUpdate ) bOwnRgn = FALSE; |
| else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 ); |
| |
| hDC = GetDCEx( hwnd, hrgnClip, DCX_CACHE | DCX_USESTYLE | |
| DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | |
| ((flags & SW_SCROLLCHILDREN) ? DCX_NOCLIPCHILDREN : 0) ); |
| if (hDC) |
| { |
| X11DRV_WND_SurfaceCopy(wnd,hDC,dx,dy,&rc,bUpdate); |
| if( bUpdate ) |
| { |
| DC* dc; |
| |
| if( (dc = DC_GetDCPtr(hDC)) ) |
| { |
| OffsetRgn( hrgnTemp, dc->DCOrgX, dc->DCOrgY ); |
| CombineRgn( hrgnTemp, hrgnTemp, dc->hVisRgn, |
| RGN_AND ); |
| OffsetRgn( hrgnTemp, -dc->DCOrgX, -dc->DCOrgY ); |
| CombineRgn( hrgnUpdate, hrgnTemp, hrgnClip, |
| RGN_AND ); |
| OffsetRgn( hrgnTemp, dx, dy ); |
| retVal = |
| CombineRgn( hrgnUpdate, hrgnUpdate, hrgnTemp, |
| RGN_DIFF ); |
| |
| if( rcUpdate ) GetRgnBox( hrgnUpdate, rcUpdate ); |
| GDI_ReleaseObj( hDC ); |
| } |
| } |
| ReleaseDC(hwnd, hDC); |
| } |
| |
| if( wnd->hrgnUpdate > 1 ) |
| { |
| /* Takes into account the fact that some damages may have |
| occured during the scroll. */ |
| CombineRgn( hrgnTemp, wnd->hrgnUpdate, 0, RGN_COPY ); |
| OffsetRgn( hrgnTemp, dx, dy ); |
| CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND ); |
| CombineRgn( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnTemp, RGN_OR ); |
| } |
| |
| if( flags & SW_SCROLLCHILDREN ) |
| { |
| RECT r; |
| WND *w; |
| for( w =WIN_LockWndPtr(wnd->child); w; WIN_UpdateWndPtr(&w, w->next)) |
| { |
| r = w->rectWindow; |
| if( !rect || IntersectRect(&r, &r, &rc) ) |
| SetWindowPos(w->hwndSelf, 0, w->rectWindow.left + dx, |
| w->rectWindow.top + dy, 0,0, SWP_NOZORDER | |
| SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW | |
| SWP_DEFERERASE ); |
| } |
| } |
| |
| if( flags & (SW_INVALIDATE | SW_ERASE) ) |
| RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE | |
| ((flags & SW_ERASE) ? RDW_ERASENOW : 0) | |
| ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) ); |
| |
| if( bCaret ) |
| { |
| SetCaretPos( caretrc.left + dx, caretrc.top + dy ); |
| ShowCaret(0); |
| } |
| |
| if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate ); |
| DeleteObject( hrgnClip ); |
| DeleteObject( hrgnTemp ); |
| } |
| END: |
| WIN_ReleaseWndPtr(wnd); |
| return retVal; |
| } |