server: Correctly expose composited parent window and its child on position change.

Skip redrawing the composited child window when the window rect and
visible region stays the same, since we're taking the union of the old
and new visible regions.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53153
Signed-off-by: Jinoh Kang <jinoh.kang.kr@gmail.com>
This commit is contained in:
Jinoh Kang 2022-10-31 22:29:52 +09:00 committed by Alexandre Julliard
parent 04576c156e
commit 17e6ef6d7e
Notes: Alexandre Julliard 2022-11-04 22:59:31 +01:00
Approved-by: Jacek Caban (@jacek)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/wine/-/merge_requests/231
5 changed files with 62 additions and 4 deletions

View file

@ -9303,7 +9303,7 @@ static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR pare
else
{
todo_wine_if( EqualRect( &rect_old, &rect_new ) ? is_zorder_redraw :
((extest->style & WS_CLIPCHILDREN) == 0 || is_composited) )
((extest->style & WS_CLIPCHILDREN) == 0 && !is_composited) )
ok( !!rgn_ok, "Parent update region shall match expected region\n" );
}
@ -9366,7 +9366,7 @@ static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR pare
else
{
todo_wine_if( EqualRect( &rect_old, &rect_new ) ? is_zorder_redraw :
((extest->style & WS_CLIPCHILDREN) == 0 || is_composited) )
((extest->style & WS_CLIPCHILDREN) == 0 && !is_composited) )
ok( !!rgn_ok, "Child update region shall match expected region\n" );
}

View file

@ -141,6 +141,11 @@ int is_hwnd_message_class( struct window_class *class )
return (!class->local && class->atom == find_global_atom( NULL, &name ));
}
int get_class_style( struct window_class *class )
{
return class->style;
}
atom_t get_class_atom( struct window_class *class )
{
return class->base_atom;

View file

@ -684,6 +684,23 @@ int is_region_empty( const struct region *region )
}
/* checks if two regions are identical */
int is_region_equal( const struct region *region1, const struct region *region2 )
{
int i;
if (region1->num_rects != region2->num_rects) return 0;
if (region1->num_rects == 0) return 1;
if (!is_rect_equal( &region1->extents, &region2->extents )) return 0;
for (i = 0; i < region1->num_rects; i++)
{
if (!is_rect_equal( &region1->rects[i], &region2->rects[i] )) return 0;
}
return 1;
}
/* get the extents rect of a region */
void get_region_extents( const struct region *region, rectangle_t *rect )
{

View file

@ -132,6 +132,7 @@ extern rectangle_t *get_region_data( const struct region *region, data_size_t ma
extern rectangle_t *get_region_data_and_free( struct region *region, data_size_t max_size,
data_size_t *total_size );
extern int is_region_empty( const struct region *region );
extern int is_region_equal( const struct region *region1, const struct region *region2 );
extern void get_region_extents( const struct region *region, rectangle_t *rect );
extern void offset_region( struct region *region, int x, int y );
extern void mirror_region( const rectangle_t *client_rect, struct region *region );
@ -175,6 +176,7 @@ extern struct window_class *grab_class( struct process *process, atom_t atom,
extern void release_class( struct window_class *class );
extern int is_desktop_class( struct window_class *class );
extern int is_hwnd_message_class( struct window_class *class );
extern int get_class_style( struct window_class *class );
extern atom_t get_class_atom( struct window_class *class );
extern client_ptr_t get_class_client_ptr( struct window_class *class );
@ -191,6 +193,13 @@ extern void close_process_desktop( struct process *process );
extern void set_thread_default_desktop( struct thread *thread, struct desktop *desktop, obj_handle_t handle );
extern void release_thread_desktop( struct thread *thread, int close );
/* checks if two rectangles are identical */
static inline int is_rect_equal( const rectangle_t *rect1, const rectangle_t *rect2 )
{
return (rect1->left == rect2->left && rect1->right == rect2->right &&
rect1->top == rect2->top && rect1->bottom == rect2->bottom);
}
static inline int is_rect_empty( const rectangle_t *rect )
{
return (rect->left >= rect->right || rect->top >= rect->bottom);

View file

@ -789,6 +789,21 @@ int is_window_transparent( user_handle_t window )
return (win->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT);
}
static int is_window_using_parent_dc( struct window *win )
{
return (win->style & (WS_POPUP|WS_CHILD)) == WS_CHILD && (get_class_style( win->class ) & CS_PARENTDC) != 0;
}
static int is_window_composited( struct window *win )
{
return (win->ex_style & WS_EX_COMPOSITED) != 0 && !is_window_using_parent_dc(win);
}
static int is_parent_composited( struct window *win )
{
return win->parent && is_window_composited( win->parent );
}
/* check if point is inside the window, and map to window dpi */
static int is_point_in_window( struct window *win, int *x, int *y, unsigned int dpi )
{
@ -1712,12 +1727,23 @@ static struct region *expose_window( struct window *win, const rectangle_t *old_
struct region *old_vis_rgn )
{
struct region *new_vis_rgn, *exposed_rgn;
int is_composited = is_parent_composited( win );
if (!(new_vis_rgn = get_visible_region( win, DCX_WINDOW ))) return NULL;
if (is_composited &&
is_rect_equal( old_window_rect, &win->window_rect ) &&
is_region_equal( old_vis_rgn, new_vis_rgn ))
{
free_region( new_vis_rgn );
return NULL;
}
if ((exposed_rgn = create_empty_region()))
{
if (subtract_region( exposed_rgn, new_vis_rgn, old_vis_rgn ) && !is_region_empty( exposed_rgn ))
if ((is_composited ? union_region( exposed_rgn, new_vis_rgn, old_vis_rgn )
: subtract_region( exposed_rgn, new_vis_rgn, old_vis_rgn )) &&
!is_region_empty( exposed_rgn ))
{
/* make it relative to the new client area */
offset_region( exposed_rgn, win->window_rect.left - win->client_rect.left,
@ -1736,7 +1762,8 @@ static struct region *expose_window( struct window *win, const rectangle_t *old_
offset_region( new_vis_rgn, win->window_rect.left - old_window_rect->left,
win->window_rect.top - old_window_rect->top );
if ((win->parent->style & WS_CLIPCHILDREN) ?
if (is_composited ? union_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ) :
(win->parent->style & WS_CLIPCHILDREN) ?
subtract_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ) :
xor_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ))
{