Commit 44f667fa authored by Jacek Caban's avatar Jacek Caban Committed by Alexandre Julliard

win32u: Move apply_window_pos implementation from user32.

parent d765edc4
......@@ -95,20 +95,6 @@ static LRESULT CDECL nulldrv_SysCommand( HWND hwnd, WPARAM wparam, LPARAM lparam
return -1;
}
static BOOL CDECL nulldrv_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
const RECT *window_rect, const RECT *client_rect,
RECT *visible_rect, struct window_surface **surface )
{
return FALSE;
}
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,
struct window_surface *surface )
{
}
/**********************************************************************
* Lazy loading user driver
......@@ -173,8 +159,8 @@ static struct user_driver_funcs lazy_load_driver =
nulldrv_SysCommand,
NULL,
NULL,
nulldrv_WindowPosChanging,
nulldrv_WindowPosChanged,
NULL,
NULL,
/* system parameters */
NULL,
/* vulkan support */
......@@ -207,8 +193,6 @@ void CDECL __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT v
SET_USER_FUNC(SetWindowIcon);
SET_USER_FUNC(SetWindowText);
SET_USER_FUNC(SysCommand);
SET_USER_FUNC(WindowPosChanging);
SET_USER_FUNC(WindowPosChanged);
#undef SET_USER_FUNC
prev = InterlockedCompareExchangePointer( (void **)&USER_Driver, driver, &lazy_load_driver );
......
......@@ -35,156 +35,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(win);
/***********************************************************************
* invalidate_dce
*
* It is called from SetWindowPos() - we have to
* mark as dirty all busy DCEs for windows that have pWnd->parent as
* an ancestor and whose client rect intersects with specified update
* rectangle. In addition, pWnd->parent DCEs may need to be updated if
* DCX_CLIPCHILDREN flag is set.
*/
void invalidate_dce( WND *win, const RECT *extra_rect )
{
/* FIXME: move callers to win32u */
NtUserCallTwoParam( (UINT_PTR)win, (UINT_PTR)extra_rect, NtUserInvalidateDCE );
}
/***********************************************************************
* get_update_region
*
* Return update region (in screen coordinates) for a window.
*/
static HRGN get_update_region( HWND hwnd, UINT *flags, HWND *child )
{
HRGN hrgn = 0;
NTSTATUS status;
RGNDATA *data;
size_t size = 256;
do
{
if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 )))
{
SetLastError( ERROR_OUTOFMEMORY );
return 0;
}
SERVER_START_REQ( get_update_region )
{
req->window = wine_server_user_handle( hwnd );
req->from_child = wine_server_user_handle( child ? *child : 0 );
req->flags = *flags;
wine_server_set_reply( req, data->Buffer, size );
if (!(status = wine_server_call( req )))
{
size_t reply_size = wine_server_reply_size( reply );
data->rdh.dwSize = sizeof(data->rdh);
data->rdh.iType = RDH_RECTANGLES;
data->rdh.nCount = reply_size / sizeof(RECT);
data->rdh.nRgnSize = reply_size;
hrgn = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
if (child) *child = wine_server_ptr_handle( reply->child );
*flags = reply->flags;
}
else size = reply->total_size;
}
SERVER_END_REQ;
HeapFree( GetProcessHeap(), 0, data );
} while (status == STATUS_BUFFER_OVERFLOW);
if (status) SetLastError( RtlNtStatusToDosError(status) );
return hrgn;
}
/***********************************************************************
* copy_bits_from_surface
*
* Copy bits from a window surface; helper for move_window_bits and move_window_bits_parent.
*/
static void copy_bits_from_surface( HWND hwnd, struct window_surface *surface,
const RECT *dst, const RECT *src )
{
char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
BITMAPINFO *info = (BITMAPINFO *)buffer;
void *bits;
UINT flags = UPDATE_NOCHILDREN | UPDATE_CLIPCHILDREN;
HRGN rgn = get_update_region( hwnd, &flags, NULL );
HDC hdc = NtUserGetDCEx( hwnd, rgn, DCX_CACHE | DCX_WINDOW | DCX_EXCLUDERGN );
bits = surface->funcs->get_info( surface, info );
surface->funcs->lock( surface );
SetDIBitsToDevice( hdc, dst->left, dst->top, dst->right - dst->left, dst->bottom - dst->top,
src->left - surface->rect.left, surface->rect.bottom - src->bottom,
0, surface->rect.bottom - surface->rect.top,
bits, info, DIB_RGB_COLORS );
surface->funcs->unlock( surface );
NtUserReleaseDC( hwnd, hdc );
}
/***********************************************************************
* 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 *window_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)
{
TRACE( "copying %s -> %s\n", wine_dbgstr_rect( &src ), wine_dbgstr_rect( &dst ));
OffsetRect( &src, -old_visible_rect->left, -old_visible_rect->top );
OffsetRect( &dst, -window_rect->left, -window_rect->top );
copy_bits_from_surface( hwnd, old_surface, &dst, &src );
}
}
/***********************************************************************
* move_window_bits_parent
*
* Move the window bits in the parent surface when a child is moved.
*/
void move_window_bits_parent( HWND hwnd, HWND parent, const RECT *window_rect, const RECT *valid_rects )
{
struct window_surface *surface;
RECT dst = valid_rects[0];
RECT src = valid_rects[1];
WND *win;
if (src.left == dst.left && src.top == dst.top) return;
if (!(win = WIN_GetPtr( parent ))) return;
if (win == WND_DESKTOP || win == WND_OTHER_PROCESS) return;
if (!(surface = win->surface))
{
WIN_ReleasePtr( win );
return;
}
TRACE( "copying %s -> %s\n", wine_dbgstr_rect( &src ), wine_dbgstr_rect( &dst ));
MapWindowPoints( NtUserGetAncestor( hwnd, GA_PARENT ), parent, (POINT *)&src, 2 );
OffsetRect( &src, win->client_rect.left - win->visible_rect.left,
win->client_rect.top - win->visible_rect.top );
OffsetRect( &dst, -window_rect->left, -window_rect->top );
window_surface_add_ref( surface );
WIN_ReleasePtr( win );
copy_bits_from_surface( hwnd, surface, &dst, &src );
window_surface_release( surface );
}
/*************************************************************************
* fix_caret
*
......
......@@ -181,7 +181,6 @@ static const struct user_callbacks user_funcs =
MENU_SetMenu,
SCROLL_SetStandardScrollPainted,
(void *)__wine_set_user_driver,
set_window_pos,
register_imm,
unregister_imm,
};
......
......@@ -103,12 +103,6 @@ extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN;
extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN;
extern HDC get_display_dc(void) DECLSPEC_HIDDEN;
extern void release_display_dc( HDC hdc ) 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 *window_rect, const RECT *valid_rects ) DECLSPEC_HIDDEN;
extern void move_window_bits_parent( HWND hwnd, HWND parent, const RECT *window_rect,
const RECT *valid_rects ) DECLSPEC_HIDDEN;
extern void wait_graphics_driver_ready(void) DECLSPEC_HIDDEN;
extern void *get_hook_proc( void *proc, const WCHAR *module, HMODULE *free_module ) DECLSPEC_HIDDEN;
extern RECT get_virtual_screen_rect(void) DECLSPEC_HIDDEN;
......
......@@ -161,148 +161,6 @@ BOOL is_desktop_window( HWND hwnd )
/*******************************************************************
* Off-screen window surface.
*/
struct offscreen_window_surface
{
struct window_surface header;
CRITICAL_SECTION cs;
RECT bounds;
char *bits;
BITMAPINFO info;
};
static const struct window_surface_funcs offscreen_window_surface_funcs;
static inline void reset_bounds( RECT *bounds )
{
bounds->left = bounds->top = INT_MAX;
bounds->right = bounds->bottom = INT_MIN;
}
static struct offscreen_window_surface *impl_from_window_surface( struct window_surface *base )
{
if (!base || base->funcs != &offscreen_window_surface_funcs) return NULL;
return CONTAINING_RECORD( base, struct offscreen_window_surface, header );
}
static void CDECL offscreen_window_surface_lock( struct window_surface *base )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
EnterCriticalSection( &impl->cs );
}
static void CDECL offscreen_window_surface_unlock( struct window_surface *base )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
LeaveCriticalSection( &impl->cs );
}
static RECT *CDECL offscreen_window_surface_get_bounds( struct window_surface *base )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
return &impl->bounds;
}
static void *CDECL offscreen_window_surface_get_bitmap_info( struct window_surface *base, BITMAPINFO *info )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
memcpy( info, &impl->info, offsetof( BITMAPINFO, bmiColors[0] ) );
return impl->bits;
}
static void CDECL offscreen_window_surface_set_region( struct window_surface *base, HRGN region )
{
}
static void CDECL offscreen_window_surface_flush( struct window_surface *base )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
base->funcs->lock( base );
reset_bounds( &impl->bounds );
base->funcs->unlock( base );
}
static void CDECL offscreen_window_surface_destroy( struct window_surface *base )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
impl->cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection( &impl->cs );
free( impl );
}
static const struct window_surface_funcs offscreen_window_surface_funcs =
{
offscreen_window_surface_lock,
offscreen_window_surface_unlock,
offscreen_window_surface_get_bitmap_info,
offscreen_window_surface_get_bounds,
offscreen_window_surface_set_region,
offscreen_window_surface_flush,
offscreen_window_surface_destroy
};
void create_offscreen_window_surface( const RECT *visible_rect, struct window_surface **surface )
{
struct offscreen_window_surface *impl;
SIZE_T size;
RECT surface_rect = *visible_rect;
TRACE( "visible_rect %s, surface %p.\n", wine_dbgstr_rect( visible_rect ), surface );
OffsetRect( &surface_rect, -surface_rect.left, -surface_rect.top );
surface_rect.right = (surface_rect.right + 0x1f) & ~0x1f;
surface_rect.bottom = (surface_rect.bottom + 0x1f) & ~0x1f;
/* check that old surface is an offscreen_window_surface, or release it */
if ((impl = impl_from_window_surface( *surface )))
{
/* if the rect didn't change, keep the same surface */
if (EqualRect( &surface_rect, &impl->header.rect )) return;
window_surface_release( &impl->header );
}
else if (*surface) window_surface_release( *surface );
/* create a new window surface */
*surface = NULL;
size = surface_rect.right * surface_rect.bottom * 4;
if (!(impl = calloc(1, offsetof( struct offscreen_window_surface, info.bmiColors[0] ) + size))) return;
impl->header.funcs = &offscreen_window_surface_funcs;
impl->header.ref = 1;
impl->header.rect = surface_rect;
InitializeCriticalSection( &impl->cs );
impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
reset_bounds( &impl->bounds );
impl->bits = (char *)&impl->info.bmiColors[0];
impl->info.bmiHeader.biSize = sizeof( impl->info );
impl->info.bmiHeader.biWidth = surface_rect.right;
impl->info.bmiHeader.biHeight = surface_rect.bottom;
impl->info.bmiHeader.biPlanes = 1;
impl->info.bmiHeader.biBitCount = 32;
impl->info.bmiHeader.biCompression = BI_RGB;
impl->info.bmiHeader.biSizeImage = size;
TRACE( "created window surface %p\n", &impl->header );
*surface = &impl->header;
}
/*******************************************************************
* register_window_surface
*
* Register a window surface in the global list, possibly replacing another one.
*/
void register_window_surface( struct window_surface *old, struct window_surface *new )
{
NtUserCallTwoParam( (UINT_PTR)old, (UINT_PTR)new, NtUserRegisterWindowSurface );
}
/*******************************************************************
* flush_window_surfaces
*
* Flush pending output from all window surfaces.
......
......@@ -36,7 +36,6 @@ struct tagDIALOGINFO;
/* Window functions */
extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN;
extern BOOL is_desktop_window( HWND hwnd ) DECLSPEC_HIDDEN;
extern void register_window_surface( struct window_surface *old, struct window_surface *new ) DECLSPEC_HIDDEN;
extern void flush_window_surfaces( BOOL idle ) DECLSPEC_HIDDEN;
extern WND *WIN_GetPtr( HWND hwnd ) DECLSPEC_HIDDEN;
extern HWND WIN_GetFullHandle( HWND hwnd ) DECLSPEC_HIDDEN;
......@@ -80,10 +79,6 @@ extern RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ) DECLSPEC_HIDDE
extern RECT rect_win_to_thread_dpi( HWND hwnd, RECT rect ) DECLSPEC_HIDDEN;
extern RECT rect_thread_to_win_dpi( HWND hwnd, RECT rect ) DECLSPEC_HIDDEN;
extern BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags,
const RECT *window_rect, const RECT *client_rect,
const RECT *valid_rects ) DECLSPEC_HIDDEN;
static inline void mirror_rect( const RECT *window_rect, RECT *rect )
{
int width = window_rect->right - window_rect->left;
......
......@@ -960,233 +960,6 @@ LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos )
/***********************************************************************
* update_surface_region
*/
static void update_surface_region( HWND hwnd )
{
NTSTATUS status;
HRGN region = 0;
RGNDATA *data;
size_t size = 256;
WND *win = WIN_GetPtr( hwnd );
if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS) return;
if (!win->surface) goto done;
do
{
if (!(data = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( RGNDATA, Buffer[size] )))) goto done;
SERVER_START_REQ( get_surface_region )
{
req->window = wine_server_user_handle( hwnd );
wine_server_set_reply( req, data->Buffer, size );
if (!(status = wine_server_call( req )))
{
size_t reply_size = wine_server_reply_size( reply );
if (reply_size)
{
data->rdh.dwSize = sizeof(data->rdh);
data->rdh.iType = RDH_RECTANGLES;
data->rdh.nCount = reply_size / sizeof(RECT);
data->rdh.nRgnSize = reply_size;
region = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
OffsetRgn( region, -reply->visible_rect.left, -reply->visible_rect.top );
}
}
else size = reply->total_size;
}
SERVER_END_REQ;
HeapFree( GetProcessHeap(), 0, data );
} while (status == STATUS_BUFFER_OVERFLOW);
if (status) goto done;
win->surface->funcs->set_region( win->surface, region );
if (region) DeleteObject( region );
done:
WIN_ReleasePtr( win );
}
/***********************************************************************
* set_window_pos
*
* Backend implementation of SetWindowPos.
*/
BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags,
const RECT *window_rect, const RECT *client_rect, const RECT *valid_rects )
{
WND *win;
HWND surface_win = 0, parent = NtUserGetAncestor( hwnd, GA_PARENT );
BOOL ret, needs_update = FALSE;
RECT visible_rect, old_visible_rect, old_window_rect, old_client_rect, extra_rects[3];
struct window_surface *old_surface, *new_surface = NULL;
struct window_surface *dummy_surface = (struct window_surface *)NtUserCallHwnd( 0, NtUserGetDummySurface );
if (!parent || parent == GetDesktopWindow())
{
new_surface = dummy_surface; /* provide a default surface for top-level windows */
window_surface_add_ref( new_surface );
}
visible_rect = *window_rect;
if (!(ret = USER_Driver->pWindowPosChanging( hwnd, insert_after, swp_flags,
window_rect, client_rect, &visible_rect, &new_surface )))
{
if (IsRectEmpty( window_rect )) visible_rect = *window_rect;
else
{
visible_rect = get_virtual_screen_rect();
IntersectRect( &visible_rect, &visible_rect, window_rect );
}
}
WIN_GetRectangles( hwnd, COORDS_SCREEN, &old_window_rect, NULL );
if (IsRectEmpty( &valid_rects[0] )) valid_rects = NULL;
if (!(win = WIN_GetPtr( hwnd )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
{
if (new_surface) window_surface_release( new_surface );
return FALSE;
}
/* create or update window surface for top-level windows if the driver doesn't implement WindowPosChanging */
if (!ret && new_surface && !IsRectEmpty( &visible_rect ) &&
(!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
NtUserGetLayeredWindowAttributes( hwnd, NULL, NULL, NULL )))
{
window_surface_release( new_surface );
if ((new_surface = win->surface)) window_surface_add_ref( new_surface );
create_offscreen_window_surface( &visible_rect, &new_surface );
}
old_visible_rect = win->visible_rect;
old_client_rect = win->client_rect;
old_surface = win->surface;
if (old_surface != new_surface) swp_flags |= SWP_FRAMECHANGED; /* force refreshing non-client area */
if (new_surface == dummy_surface) swp_flags |= SWP_NOREDRAW;
else if (old_surface == dummy_surface)
{
swp_flags |= SWP_NOCOPYBITS;
valid_rects = NULL;
}
SERVER_START_REQ( set_window_pos )
{
req->handle = wine_server_user_handle( hwnd );
req->previous = wine_server_user_handle( insert_after );
req->swp_flags = swp_flags;
req->window.left = window_rect->left;
req->window.top = window_rect->top;
req->window.right = window_rect->right;
req->window.bottom = window_rect->bottom;
req->client.left = client_rect->left;
req->client.top = client_rect->top;
req->client.right = client_rect->right;
req->client.bottom = client_rect->bottom;
if (!EqualRect( window_rect, &visible_rect ) || new_surface || valid_rects)
{
extra_rects[0] = extra_rects[1] = visible_rect;
if (new_surface)
{
extra_rects[1] = new_surface->rect;
OffsetRect( &extra_rects[1], visible_rect.left, visible_rect.top );
}
if (valid_rects) extra_rects[2] = valid_rects[0];
else SetRectEmpty( &extra_rects[2] );
wine_server_add_data( req, extra_rects, sizeof(extra_rects) );
}
if (new_surface) req->paint_flags |= SET_WINPOS_PAINT_SURFACE;
if (win->pixel_format) req->paint_flags |= SET_WINPOS_PIXEL_FORMAT;
if ((ret = !wine_server_call( req )))
{
win->dwStyle = reply->new_style;
win->dwExStyle = reply->new_ex_style;
win->window_rect = *window_rect;
win->client_rect = *client_rect;
win->visible_rect = visible_rect;
win->surface = new_surface;
surface_win = wine_server_ptr_handle( reply->surface_win );
needs_update = reply->needs_update;
if (GetWindowLongW( win->parent, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
{
RECT client;
GetClientRect( win->parent, &client );
mirror_rect( &client, &win->window_rect );
mirror_rect( &client, &win->client_rect );
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_client_rect.right - old_client_rect.left)
win->flags |= WIN_CHILDREN_MOVED;
}
}
SERVER_END_REQ;
if (ret)
{
if (needs_update) update_surface_region( surface_win );
if (((swp_flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) ||
(swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_STATECHANGED | SWP_FRAMECHANGED)))
invalidate_dce( win, &old_window_rect );
}
WIN_ReleasePtr( win );
if (ret)
{
TRACE( "win %p surface %p -> %p\n", hwnd, old_surface, new_surface );
register_window_surface( old_surface, new_surface );
if (old_surface)
{
if (valid_rects)
{
move_window_bits( hwnd, old_surface, new_surface, &visible_rect,
&old_visible_rect, window_rect, valid_rects );
valid_rects = NULL; /* prevent the driver from trying to also move the bits */
}
window_surface_release( old_surface );
}
else if (surface_win && surface_win != hwnd)
{
if (valid_rects)
{
RECT rects[2];
int x_offset = old_visible_rect.left - visible_rect.left;
int y_offset = old_visible_rect.top - visible_rect.top;
/* if all that happened is that the whole window moved, copy everything */
if (!(swp_flags & SWP_FRAMECHANGED) &&
old_visible_rect.right - visible_rect.right == x_offset &&
old_visible_rect.bottom - visible_rect.bottom == y_offset &&
old_client_rect.left - client_rect->left == x_offset &&
old_client_rect.right - client_rect->right == x_offset &&
old_client_rect.top - client_rect->top == y_offset &&
old_client_rect.bottom - client_rect->bottom == y_offset &&
EqualRect( &valid_rects[0], client_rect ))
{
rects[0] = visible_rect;
rects[1] = old_visible_rect;
valid_rects = rects;
}
move_window_bits_parent( hwnd, surface_win, window_rect, valid_rects );
valid_rects = NULL; /* prevent the driver from trying to also move the bits */
}
}
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;
}
/***********************************************************************
* BeginDeferWindowPos (USER32.@)
*/
HDWP WINAPI BeginDeferWindowPos( INT count )
......
......@@ -119,6 +119,133 @@ static const struct window_surface_funcs dummy_surface_funcs =
struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } };
/*******************************************************************
* Off-screen window surface.
*/
struct offscreen_window_surface
{
struct window_surface header;
pthread_mutex_t mutex;
RECT bounds;
char *bits;
BITMAPINFO info;
};
static const struct window_surface_funcs offscreen_window_surface_funcs;
static struct offscreen_window_surface *impl_from_window_surface( struct window_surface *base )
{
if (!base || base->funcs != &offscreen_window_surface_funcs) return NULL;
return CONTAINING_RECORD( base, struct offscreen_window_surface, header );
}
static void CDECL offscreen_window_surface_lock( struct window_surface *base )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
pthread_mutex_lock( &impl->mutex );
}
static void CDECL offscreen_window_surface_unlock( struct window_surface *base )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
pthread_mutex_unlock( &impl->mutex );
}
static RECT *CDECL offscreen_window_surface_get_bounds( struct window_surface *base )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
return &impl->bounds;
}
static void *CDECL offscreen_window_surface_get_bitmap_info( struct window_surface *base, BITMAPINFO *info )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
info->bmiHeader = impl->info.bmiHeader;
return impl->bits;
}
static void CDECL offscreen_window_surface_set_region( struct window_surface *base, HRGN region )
{
}
static void CDECL offscreen_window_surface_flush( struct window_surface *base )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
base->funcs->lock( base );
reset_bounds( &impl->bounds );
base->funcs->unlock( base );
}
static void CDECL offscreen_window_surface_destroy( struct window_surface *base )
{
struct offscreen_window_surface *impl = impl_from_window_surface( base );
free( impl );
}
static const struct window_surface_funcs offscreen_window_surface_funcs =
{
offscreen_window_surface_lock,
offscreen_window_surface_unlock,
offscreen_window_surface_get_bitmap_info,
offscreen_window_surface_get_bounds,
offscreen_window_surface_set_region,
offscreen_window_surface_flush,
offscreen_window_surface_destroy
};
void create_offscreen_window_surface( const RECT *visible_rect, struct window_surface **surface )
{
struct offscreen_window_surface *impl;
SIZE_T size;
RECT surface_rect = *visible_rect;
pthread_mutexattr_t attr;
TRACE( "visible_rect %s, surface %p.\n", wine_dbgstr_rect( visible_rect ), surface );
offset_rect( &surface_rect, -surface_rect.left, -surface_rect.top );
surface_rect.right = (surface_rect.right + 0x1f) & ~0x1f;
surface_rect.bottom = (surface_rect.bottom + 0x1f) & ~0x1f;
/* check that old surface is an offscreen_window_surface, or release it */
if ((impl = impl_from_window_surface( *surface )))
{
/* if the rect didn't change, keep the same surface */
if (EqualRect( &surface_rect, &impl->header.rect )) return;
window_surface_release( &impl->header );
}
else if (*surface) window_surface_release( *surface );
/* create a new window surface */
*surface = NULL;
size = surface_rect.right * surface_rect.bottom * 4;
if (!(impl = calloc(1, offsetof( struct offscreen_window_surface, info.bmiColors[0] ) + size))) return;
impl->header.funcs = &offscreen_window_surface_funcs;
impl->header.ref = 1;
impl->header.rect = surface_rect;
pthread_mutexattr_init( &attr );
pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
pthread_mutex_init( &impl->mutex, &attr );
pthread_mutexattr_destroy( &attr );
reset_bounds( &impl->bounds );
impl->bits = (char *)&impl->info.bmiColors[0];
impl->info.bmiHeader.biSize = sizeof( impl->info );
impl->info.bmiHeader.biWidth = surface_rect.right;
impl->info.bmiHeader.biHeight = surface_rect.bottom;
impl->info.bmiHeader.biPlanes = 1;
impl->info.bmiHeader.biBitCount = 32;
impl->info.bmiHeader.biCompression = BI_RGB;
impl->info.bmiHeader.biSizeImage = size;
TRACE( "created window surface %p\n", &impl->header );
*surface = &impl->header;
}
/*******************************************************************
* register_window_surface
*
* Register a window surface in the global list, possibly replacing another one.
......@@ -991,6 +1118,90 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn,
}
/***********************************************************************
* copy_bits_from_surface
*
* Copy bits from a window surface; helper for move_window_bits and move_window_bits_parent.
*/
static void copy_bits_from_surface( HWND hwnd, struct window_surface *surface,
const RECT *dst, const RECT *src )
{
char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
BITMAPINFO *info = (BITMAPINFO *)buffer;
void *bits;
UINT flags = UPDATE_NOCHILDREN | UPDATE_CLIPCHILDREN;
HRGN rgn = get_update_region( hwnd, &flags, NULL );
HDC hdc = NtUserGetDCEx( hwnd, rgn, DCX_CACHE | DCX_WINDOW | DCX_EXCLUDERGN );
bits = surface->funcs->get_info( surface, info );
surface->funcs->lock( surface );
NtGdiSetDIBitsToDeviceInternal( hdc, dst->left, dst->top, dst->right - dst->left, dst->bottom - dst->top,
src->left - surface->rect.left, surface->rect.bottom - src->bottom,
0, surface->rect.bottom - surface->rect.top,
bits, info, DIB_RGB_COLORS, 0, 0, FALSE, NULL );
surface->funcs->unlock( surface );
NtUserReleaseDC( hwnd, hdc );
}
/***********************************************************************
* 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 *window_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)
{
TRACE( "copying %s -> %s\n", wine_dbgstr_rect( &src ), wine_dbgstr_rect( &dst ));
OffsetRect( &src, -old_visible_rect->left, -old_visible_rect->top );
OffsetRect( &dst, -window_rect->left, -window_rect->top );
copy_bits_from_surface( hwnd, old_surface, &dst, &src );
}
}
/***********************************************************************
* move_window_bits_parent
*
* Move the window bits in the parent surface when a child is moved.
*/
void move_window_bits_parent( HWND hwnd, HWND parent, const RECT *window_rect, const RECT *valid_rects )
{
struct window_surface *surface;
RECT dst = valid_rects[0];
RECT src = valid_rects[1];
WND *win;
if (src.left == dst.left && src.top == dst.top) return;
if (!(win = get_win_ptr( parent ))) return;
if (win == WND_DESKTOP || win == WND_OTHER_PROCESS) return;
if (!(surface = win->surface))
{
release_win_ptr( win );
return;
}
TRACE( "copying %s -> %s\n", wine_dbgstr_rect( &src ), wine_dbgstr_rect( &dst ));
map_window_points( NtUserGetAncestor( hwnd, GA_PARENT ), parent, (POINT *)&src, 2, get_thread_dpi() );
offset_rect( &src, win->client_rect.left - win->visible_rect.left,
win->client_rect.top - win->visible_rect.top );
offset_rect( &dst, -window_rect->left, -window_rect->top );
window_surface_add_ref( surface );
release_win_ptr( win );
copy_bits_from_surface( hwnd, surface, &dst, &src );
window_surface_release( surface );
}
/***********************************************************************
* NtUserBeginPaint (win32u.@)
*/
HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps )
......
......@@ -1211,6 +1211,8 @@ static const struct user_driver_funcs lazy_load_driver =
.pShowWindow = nulldrv_ShowWindow,
.pUpdateLayeredWindow = loaderdrv_UpdateLayeredWindow,
.pWindowMessage = nulldrv_WindowMessage,
.pWindowPosChanging = nulldrv_WindowPosChanging,
.pWindowPosChanged = nulldrv_WindowPosChanged,
/* system parameters */
.pSystemParametersInfo = nulldrv_SystemParametersInfo,
/* vulkan support */
......
......@@ -53,9 +53,6 @@ struct user_callbacks
BOOL (CDECL *set_menu)( HWND hwnd, HMENU menu );
void (WINAPI *set_standard_scroll_painted)( HWND hwnd, INT bar, BOOL visible );
void (CDECL *set_user_driver)( void *, UINT );
BOOL (CDECL *set_window_pos)( HWND hwnd, HWND insert_after, UINT swp_flags,
const RECT *window_rect, const RECT *client_rect,
const RECT *valid_rects );
BOOL (WINAPI *register_imm)( HWND hwnd );
void (WINAPI *unregister_imm)( HWND hwnd );
};
......
......@@ -4743,12 +4743,6 @@ ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code
return (UINT_PTR)free_user_handle( UlongToHandle(arg1), arg2 );
case NtUserGetHandlePtr:
return (UINT_PTR)get_user_handle_ptr( UlongToHandle(arg1), arg2 );
case NtUserInvalidateDCE:
invalidate_dce( (void *)arg1, (const RECT *)arg2 );
return 0;
case NtUserRegisterWindowSurface:
register_window_surface( (struct window_surface *)arg1, (struct window_surface *)arg2 );
return 0;
default:
FIXME( "invalid code %u\n", code );
return 0;
......
......@@ -305,8 +305,16 @@ extern ULONG_PTR set_icon_param( HICON handle, ULONG_PTR param ) DECLSPEC_HIDDEN
/* dce.c */
extern struct window_surface dummy_surface DECLSPEC_HIDDEN;
extern void create_offscreen_window_surface( const RECT *visible_rect,
struct window_surface **surface ) DECLSPEC_HIDDEN;
extern void erase_now( HWND hwnd, UINT rdw_flags ) DECLSPEC_HIDDEN;
extern void flush_window_surfaces( BOOL idle ) 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 *window_rect, const RECT *valid_rects ) DECLSPEC_HIDDEN;
extern void move_window_bits_parent( HWND hwnd, HWND parent, const RECT *window_rect,
const RECT *valid_rects ) DECLSPEC_HIDDEN;
extern void register_window_surface( struct window_surface *old,
struct window_surface *new ) DECLSPEC_HIDDEN;
......
......@@ -137,8 +137,6 @@ enum
NtUserAllocWinProc,
NtUserFreeHandle,
NtUserGetHandlePtr,
NtUserInvalidateDCE,
NtUserRegisterWindowSurface,
};
/* NtUserCallHwnd codes, not compatible with Windows */
......@@ -152,8 +150,6 @@ enum
NtUserIsWindow,
NtUserIsWindowUnicode,
NtUserIsWindowVisible,
/* temporary exports */
NtUserGetDummySurface,
};
/* NtUserCallHwndParam codes, not compatible with Windows */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment