From a5ef549c6e4266d9a7e129b42ff49b109c6cadb8 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 6 Sep 2012 12:32:52 +0200 Subject: [PATCH] user32: Add support for managing a DIB surface for a window. --- dlls/user32/driver.c | 14 ++++---- dlls/user32/painting.c | 58 +++++++++++++++++++++++++++++-- dlls/user32/user_private.h | 10 ++++-- dlls/user32/win.c | 9 +++++ dlls/user32/win.h | 2 ++ dlls/user32/winpos.c | 38 ++++++++++++++++---- dlls/winex11.drv/window.c | 6 ++-- dlls/winex11.drv/winex11.drv.spec | 4 +-- 8 files changed, 121 insertions(+), 20 deletions(-) diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 6e21ca2937b..1d3d96afce4 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -420,13 +420,14 @@ static LRESULT CDECL nulldrv_WindowMessage( HWND hwnd, UINT msg, WPARAM wparam, static void CDECL nulldrv_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *window_rect, const RECT *client_rect, - RECT *visible_rect ) + RECT *visible_rect, struct window_surface **surface ) { } static void CDECL nulldrv_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *window_rect, const RECT *client_rect, - const RECT *visible_rect, const RECT *valid_rects ) + const RECT *visible_rect, const RECT *valid_rects, + struct window_surface *surface ) { } @@ -763,18 +764,19 @@ static LRESULT CDECL loaderdrv_WindowMessage( HWND hwnd, UINT msg, WPARAM wparam static void CDECL loaderdrv_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *window_rect, const RECT *client_rect, - RECT *visible_rect ) + RECT *visible_rect, struct window_surface **surface ) { load_driver()->pWindowPosChanging( hwnd, insert_after, swp_flags, - window_rect, client_rect, visible_rect ); + window_rect, client_rect, visible_rect, surface ); } static void CDECL loaderdrv_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *window_rect, const RECT *client_rect, - const RECT *visible_rect, const RECT *valid_rects ) + const RECT *visible_rect, const RECT *valid_rects, + struct window_surface *surface ) { load_driver()->pWindowPosChanged( hwnd, insert_after, swp_flags, window_rect, - client_rect, visible_rect, valid_rects ); + client_rect, visible_rect, valid_rects, surface ); } static USER_DRIVER lazy_load_driver = diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c index 4fd387f2708..3869b48cf2e 100644 --- a/dlls/user32/painting.c +++ b/dlls/user32/painting.c @@ -108,12 +108,14 @@ static void dump_rdw_flags(UINT flags) */ static void update_visible_region( struct dce *dce ) { + struct window_surface *surface = NULL; NTSTATUS status; HRGN vis_rgn = 0; HWND top_win = 0; DWORD flags = dce->flags; size_t size = 256; RECT win_rect, top_rect; + WND *win; /* don't clip siblings if using parent clip region */ if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS; @@ -161,8 +163,16 @@ static void update_visible_region( struct dce *dce ) if (dce->clip_rgn) CombineRgn( vis_rgn, vis_rgn, dce->clip_rgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF ); - top_rect = get_virtual_screen_rect(); - __wine_set_visible_region( dce->hdc, vis_rgn, &win_rect, &top_rect, NULL ); + if ((win = WIN_GetPtr( top_win )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS) + { + surface = win->surface; + if (surface) window_surface_add_ref( surface ); + WIN_ReleasePtr( win ); + } + + if (!surface) top_rect = get_virtual_screen_rect(); + __wine_set_visible_region( dce->hdc, vis_rgn, &win_rect, &top_rect, surface ); + if (surface) window_surface_release( surface ); } @@ -181,8 +191,12 @@ static void reset_dce_attrs( struct dce *dce ) */ static void release_dce( struct dce *dce ) { + RECT vis_rect; + if (!dce->hwnd) return; /* already released */ + vis_rect = get_virtual_screen_rect(); + __wine_set_visible_region( dce->hdc, 0, &vis_rect, &vis_rect, NULL ); USER_Driver->pReleaseDC( dce->hwnd, dce->hdc ); if (dce->clip_rgn) DeleteObject( dce->clip_rgn ); @@ -743,6 +757,46 @@ void erase_now( HWND hwnd, UINT rdw_flags ) } +/*********************************************************************** + * move_window_bits + * + * Move the window bits when a window is resized or its surface recreated. + */ +void move_window_bits( HWND hwnd, struct window_surface *old_surface, + struct window_surface *new_surface, + const RECT *visible_rect, const RECT *old_visible_rect, + const RECT *client_rect, const RECT *valid_rects ) +{ + RECT dst = valid_rects[0]; + RECT src = valid_rects[1]; + + if (new_surface != old_surface || + src.left - old_visible_rect->left != dst.left - visible_rect->left || + src.top - old_visible_rect->top != dst.top - visible_rect->top) + { + char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; + BITMAPINFO *info = (BITMAPINFO *)buffer; + void *bits; + UINT flags = UPDATE_NOCHILDREN; + HRGN rgn = get_update_region( hwnd, &flags, NULL ); + HDC hdc = GetDCEx( hwnd, rgn, DCX_CACHE | DCX_EXCLUDERGN ); + + OffsetRect( &dst, -client_rect->left, -client_rect->top ); + TRACE( "copying %s -> %s\n", wine_dbgstr_rect(&src), wine_dbgstr_rect(&dst) ); + bits = old_surface->funcs->get_info( old_surface, info ); + old_surface->funcs->lock( old_surface ); + SetDIBitsToDevice( hdc, dst.left, dst.top, dst.right - dst.left, dst.bottom - dst.top, + src.left - old_visible_rect->left - old_surface->rect.left, + old_surface->rect.bottom - (src.bottom - old_visible_rect->top), + 0, old_surface->rect.bottom - old_surface->rect.top, + bits, info, DIB_RGB_COLORS ); + old_surface->funcs->unlock( old_surface ); + ReleaseDC( hwnd, hdc ); + DeleteObject( rgn ); + } +} + + /*********************************************************************** * update_now * diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index a57751fb774..bc78d2d9647 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -35,6 +35,8 @@ #define WM_SYSTIMER 0x0118 #define WM_POPUPSYSTEMMENU 0x0313 +struct window_surface; + /* internal messages codes */ enum wine_internal_message { @@ -110,8 +112,8 @@ typedef struct tagUSER_DRIVER { UINT (CDECL *pShowWindow)(HWND,INT,RECT*,UINT); LRESULT (CDECL *pSysCommand)(HWND,WPARAM,LPARAM); LRESULT (CDECL *pWindowMessage)(HWND,UINT,WPARAM,LPARAM); - void (CDECL *pWindowPosChanging)(HWND,HWND,UINT,const RECT *,const RECT *,RECT *); - void (CDECL *pWindowPosChanged)(HWND,HWND,UINT,const RECT *,const RECT *,const RECT *,const RECT *); + void (CDECL *pWindowPosChanging)(HWND,HWND,UINT,const RECT *,const RECT *,RECT *,struct window_surface**); + void (CDECL *pWindowPosChanged)(HWND,HWND,UINT,const RECT *,const RECT *,const RECT *,const RECT *,struct window_surface*); } USER_DRIVER; extern const USER_DRIVER *USER_Driver DECLSPEC_HIDDEN; @@ -213,6 +215,10 @@ extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECL extern void free_dce( struct dce *dce, HWND hwnd ) DECLSPEC_HIDDEN; extern void invalidate_dce( struct tagWND *win, const RECT *rect ) DECLSPEC_HIDDEN; extern void erase_now( HWND hwnd, UINT rdw_flags ) DECLSPEC_HIDDEN; +extern void move_window_bits( HWND hwnd, struct window_surface *old_surface, + struct window_surface *new_surface, + const RECT *visible_rect, const RECT *old_visible_rect, + const RECT *client_rect, const RECT *valid_rects ) DECLSPEC_HIDDEN; extern void *get_hook_proc( void *proc, const WCHAR *module ) DECLSPEC_HIDDEN; extern RECT get_virtual_screen_rect(void) DECLSPEC_HIDDEN; extern LRESULT call_current_hook( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam ) DECLSPEC_HIDDEN; diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 82d62b16051..c03ff42f175 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -34,6 +34,7 @@ #include "user_private.h" #include "controls.h" #include "winerror.h" +#include "wine/gdi_driver.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(win); @@ -810,6 +811,7 @@ LRESULT WIN_DestroyWindow( HWND hwnd ) HWND *list; HMENU menu = 0, sys_menu; HWND icon_title; + struct window_surface *surface; TRACE("%p\n", hwnd ); @@ -854,11 +856,14 @@ LRESULT WIN_DestroyWindow( HWND hwnd ) wndPtr->text = NULL; HeapFree( GetProcessHeap(), 0, wndPtr->pScroll ); wndPtr->pScroll = NULL; + surface = wndPtr->surface; + wndPtr->surface = NULL; WIN_ReleasePtr( wndPtr ); if (icon_title) DestroyWindow( icon_title ); if (menu) DestroyMenu( menu ); if (sys_menu) DestroyMenu( sys_menu ); + if (surface) window_surface_release( surface ); USER_Driver->pDestroyWindow( hwnd ); @@ -877,6 +882,7 @@ static void destroy_thread_window( HWND hwnd ) WND *wndPtr; HWND *list; HMENU menu = 0, sys_menu = 0; + struct window_surface *surface = NULL; WORD index; /* free child windows */ @@ -902,6 +908,8 @@ static void destroy_thread_window( HWND hwnd ) if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu; sys_menu = wndPtr->hSysMenu; free_dce( wndPtr->dce, hwnd ); + surface = wndPtr->surface; + wndPtr->surface = NULL; InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr ); } USER_Unlock(); @@ -909,6 +917,7 @@ static void destroy_thread_window( HWND hwnd ) HeapFree( GetProcessHeap(), 0, wndPtr ); if (menu) DestroyMenu( menu ); if (sys_menu) DestroyMenu( sys_menu ); + if (surface) window_surface_release( surface ); } diff --git a/dlls/user32/win.h b/dlls/user32/win.h index 7c899ac0174..81e81b28f01 100644 --- a/dlls/user32/win.h +++ b/dlls/user32/win.h @@ -45,6 +45,7 @@ typedef struct tagWND HINSTANCE hInstance; /* Window hInstance (from CreateWindow) */ RECT rectClient; /* Client area rel. to parent client area */ RECT rectWindow; /* Whole window rel. to parent client area */ + RECT visible_rect; /* Visible part of the whole rect, rel. to parent client area */ RECT normal_rect; /* Normal window rect saved when maximized/minimized */ POINT min_pos; /* Position for minimized window */ POINT max_pos; /* Position for maximized window */ @@ -59,6 +60,7 @@ typedef struct tagWND HMENU hSysMenu; /* window's copy of System Menu */ HICON hIcon; /* window's icon */ HICON hIconSmall; /* window's small icon */ + struct window_surface *surface; /* Window surface if any */ struct tagDIALOGINFO *dlgInfo;/* Dialog additional info (dialogs only) */ int cbWndExtra; /* class cbWndExtra at window creation */ DWORD_PTR userdata; /* User private data */ diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index 27489fe1168..60a539b4f71 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -33,6 +33,7 @@ #include "wine/server.h" #include "controls.h" #include "user_private.h" +#include "wine/gdi_driver.h" #include "win.h" #include "wine/debug.h" @@ -1949,18 +1950,23 @@ BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, { WND *win; BOOL ret; - RECT visible_rect, old_window_rect; int old_width; + RECT visible_rect, old_visible_rect, old_window_rect; + struct window_surface *old_surface, *new_surface = NULL; visible_rect = *window_rect; USER_Driver->pWindowPosChanging( hwnd, insert_after, swp_flags, - window_rect, client_rect, &visible_rect ); + window_rect, client_rect, &visible_rect, &new_surface ); WIN_GetRectangles( hwnd, COORDS_SCREEN, &old_window_rect, NULL ); - if (!(win = WIN_GetPtr( hwnd ))) return FALSE; - if (win == WND_DESKTOP || win == WND_OTHER_PROCESS) return FALSE; + if (!(win = WIN_GetPtr( hwnd )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) + { + if (new_surface) window_surface_release( new_surface ); + return FALSE; + } old_width = win->rectClient.right - win->rectClient.left; + old_visible_rect = win->visible_rect; SERVER_START_REQ( set_window_pos ) { @@ -1987,12 +1993,16 @@ BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, win->dwExStyle = reply->new_ex_style; win->rectWindow = *window_rect; win->rectClient = *client_rect; + win->visible_rect = visible_rect; + old_surface = win->surface; + win->surface = new_surface; if (GetWindowLongW( win->parent, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) { RECT client; GetClientRect( win->parent, &client ); mirror_rect( &client, &win->rectWindow ); mirror_rect( &client, &win->rectClient ); + mirror_rect( &client, &win->visible_rect ); } /* if an RTL window is resized the children have moved */ if (win->dwExStyle & WS_EX_LAYOUTRTL && client_rect->right - client_rect->left != old_width) @@ -2007,8 +2017,24 @@ BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, WIN_ReleasePtr( win ); - if (ret) USER_Driver->pWindowPosChanged( hwnd, insert_after, swp_flags, window_rect, - client_rect, &visible_rect, valid_rects ); + if (ret) + { + TRACE( "win %p surface %p -> %p\n", hwnd, old_surface, new_surface ); + if (old_surface) + { + if (!IsRectEmpty( valid_rects )) + { + move_window_bits( hwnd, old_surface, new_surface, &visible_rect, + &old_visible_rect, client_rect, valid_rects ); + valid_rects = NULL; /* prevent the driver from trying to also move the bits */ + } + window_surface_release( old_surface ); + } + USER_Driver->pWindowPosChanged( hwnd, insert_after, swp_flags, window_rect, + client_rect, &visible_rect, valid_rects, new_surface ); + } + else if (new_surface) window_surface_release( new_surface ); + return ret; } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 3541ed422da..fcaf688ad50 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2010,7 +2010,8 @@ void CDECL X11DRV_SetFocus( HWND hwnd ) * WindowPosChanging (X11DRV.@) */ void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, - const RECT *window_rect, const RECT *client_rect, RECT *visible_rect ) + const RECT *window_rect, const RECT *client_rect, RECT *visible_rect, + struct window_surface **surface ) { struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); @@ -2035,7 +2036,8 @@ void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag */ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *rectWindow, const RECT *rectClient, - const RECT *visible_rect, const RECT *valid_rects ) + const RECT *visible_rect, const RECT *valid_rects, + struct window_surface *surface ) { struct x11drv_thread_data *thread_data; Display *display; diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index 5b64dd76c75..1e8d4d9d08e 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -52,8 +52,8 @@ @ cdecl ShowWindow(long long ptr long) X11DRV_ShowWindow @ cdecl SysCommand(long long long) X11DRV_SysCommand @ cdecl WindowMessage(long long long long) X11DRV_WindowMessage -@ cdecl WindowPosChanging(long long long ptr ptr ptr) X11DRV_WindowPosChanging -@ cdecl WindowPosChanged(long long long ptr ptr ptr ptr) X11DRV_WindowPosChanged +@ cdecl WindowPosChanging(long long long ptr ptr ptr ptr) X11DRV_WindowPosChanging +@ cdecl WindowPosChanged(long long long ptr ptr ptr ptr ptr) X11DRV_WindowPosChanged # WinTab32 @ cdecl AttachEventQueueToTablet(long) X11DRV_AttachEventQueueToTablet