diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 76c30b7dfe5..9b4680bbcc1 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -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" ); } diff --git a/server/class.c b/server/class.c index e1e180bd97c..3231f366b26 100644 --- a/server/class.c +++ b/server/class.c @@ -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; diff --git a/server/region.c b/server/region.c index 9f377ee05d3..d169f1ac2b4 100644 --- a/server/region.c +++ b/server/region.c @@ -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( ®ion1->extents, ®ion2->extents )) return 0; + for (i = 0; i < region1->num_rects; i++) + { + if (!is_rect_equal( ®ion1->rects[i], ®ion2->rects[i] )) return 0; + } + + return 1; +} + + /* get the extents rect of a region */ void get_region_extents( const struct region *region, rectangle_t *rect ) { diff --git a/server/user.h b/server/user.h index 55a0d35feff..280da454d07 100644 --- a/server/user.h +++ b/server/user.h @@ -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); diff --git a/server/window.c b/server/window.c index 7675cd1103d..a56333cc6a5 100644 --- a/server/window.c +++ b/server/window.c @@ -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 )) {