char extra_bytes[1]; /* extra bytes storage */
};
-#define PAINT_INTERNAL 0x01 /* internal WM_PAINT pending */
-#define PAINT_ERASE 0x02 /* needs WM_ERASEBKGND */
-#define PAINT_NONCLIENT 0x04 /* needs WM_NCPAINT */
-#define PAINT_DELAYED_ERASE 0x08 /* still needs erase after WM_ERASEBKGND */
+/* flags that can be set by the client */
+#define PAINT_HAS_SURFACE SET_WINPOS_PAINT_SURFACE
+#define PAINT_HAS_PIXEL_FORMAT SET_WINPOS_PIXEL_FORMAT
+#define PAINT_CLIENT_FLAGS (PAINT_HAS_SURFACE | PAINT_HAS_PIXEL_FORMAT)
+/* flags only manipulated by the server */
+#define PAINT_INTERNAL 0x0010 /* internal WM_PAINT pending */
+#define PAINT_ERASE 0x0020 /* needs WM_ERASEBKGND */
+#define PAINT_NONCLIENT 0x0040 /* needs WM_NCPAINT */
+#define PAINT_DELAYED_ERASE 0x0080 /* still needs erase after WM_ERASEBKGND */
+#define PAINT_PIXEL_FORMAT_CHILD 0x0100 /* at least one child has a custom pixel format */
/* growable array of user handles */
struct user_handle_array
return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL;
}
+/* set the PAINT_PIXEL_FORMAT_CHILD flag on all the parents */
+/* note: we never reset the flag, it's just a heuristic */
+static inline void update_pixel_format_flags( struct window *win )
+{
+ for (win = win->parent; win && win->parent; win = win->parent)
+ win->paint_flags |= PAINT_PIXEL_FORMAT_CHILD;
+}
+
/* link a window at the right place in the siblings list */
static void link_window( struct window *win, struct window *previous )
{
/* top-level, attach the two threads */
if (parent->thread && parent->thread != win->thread && !is_desktop_window(parent))
attach_thread_input( win->thread, parent->thread );
+
+ if (win->paint_flags & (PAINT_HAS_PIXEL_FORMAT | PAINT_PIXEL_FORMAT_CHILD))
+ update_pixel_format_flags( win );
}
else /* move it to parent unlinked list */
{
return win->thread->process;
}
-/* attempt to close the desktop window when the last process using it is gone */
-void close_desktop_window( struct desktop *desktop )
+/* get the top window size of a given desktop */
+void get_top_window_rectangle( struct desktop *desktop, rectangle_t *rect )
{
struct window *win = desktop->top_window;
- if (win && win->thread) post_message( win->handle, WM_CLOSE, 0, 0 );
+ if (!win) rect->left = rect->top = rect->right = rect->bottom = 0;
+ else *rect = win->window_rect;
+}
+
+/* post a message to the desktop window */
+void post_desktop_message( struct desktop *desktop, unsigned int message,
+ lparam_t wparam, lparam_t lparam )
+{
+ struct window *win = desktop->top_window;
+ if (win && win->thread) post_message( win->handle, message, wparam, lparam );
}
/* create a new window structure (note: the window is not linked in the window tree) */
if (!win) return 0;
- /* set last active for window and its owner */
- win->last_active = win->handle;
- if ((owner = get_user_object( win->owner, USER_WINDOW ))) owner->last_active = win->handle;
+ /* set last active for window and its owners */
+ owner = win;
+ while (owner)
+ {
+ owner->last_active = win->handle;
+ owner = get_user_object( owner->owner, USER_WINDOW );
+ }
return 1;
}
}
-/* compute the intersection of two rectangles; return 0 if the result is empty */
-static inline int intersect_rect( rectangle_t *dst, const rectangle_t *src1, const rectangle_t *src2 )
-{
- dst->left = max( src1->left, src2->left );
- dst->top = max( src1->top, src2->top );
- dst->right = min( src1->right, src2->right );
- dst->bottom = min( src1->bottom, src2->bottom );
- return (dst->left < dst->right && dst->top < dst->bottom);
-}
-
-
/* offset the coordinates of a rectangle */
static inline void offset_rect( rectangle_t *rect, int offset_x, int offset_y )
{
/* get the top-level window to clip against for a given window */
static inline struct window *get_top_clipping_window( struct window *win )
{
- while (win->parent && !is_desktop_window(win->parent)) win = win->parent;
+ while (!(win->paint_flags & PAINT_HAS_SURFACE) && win->parent && !is_desktop_window(win->parent))
+ win = win->parent;
return win;
}
}
+/* clip all children with a custom pixel format out of the visible region */
+static struct region *clip_pixel_format_children( struct window *parent, struct region *parent_clip,
+ struct region *region, int offset_x, int offset_y )
+{
+ struct window *ptr;
+ struct region *clip = create_empty_region();
+
+ if (!clip) return NULL;
+
+ LIST_FOR_EACH_ENTRY_REV( ptr, &parent->children, struct window, entry )
+ {
+ if (!(ptr->style & WS_VISIBLE)) continue;
+ if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
+
+ /* add the visible rect */
+ set_region_rect( clip, &ptr->visible_rect );
+ if (ptr->win_region && !intersect_window_region( clip, ptr )) break;
+ offset_region( clip, offset_x, offset_y );
+ if (!intersect_region( clip, clip, parent_clip )) break;
+ if (!union_region( region, region, clip )) break;
+ if (!(ptr->paint_flags & (PAINT_HAS_PIXEL_FORMAT | PAINT_PIXEL_FORMAT_CHILD))) continue;
+
+ /* subtract the client rect if it uses a custom pixel format */
+ set_region_rect( clip, &ptr->client_rect );
+ if (ptr->win_region && !intersect_window_region( clip, ptr )) break;
+ offset_region( clip, offset_x, offset_y );
+ if (!intersect_region( clip, clip, parent_clip )) break;
+ if ((ptr->paint_flags & PAINT_HAS_PIXEL_FORMAT) && !subtract_region( region, region, clip ))
+ break;
+
+ if (!clip_pixel_format_children( ptr, clip, region, offset_x + ptr->client_rect.left,
+ offset_y + ptr->client_rect.top ))
+ break;
+ }
+ free_region( clip );
+ return region;
+}
+
+
+/* compute the visible surface region of a window, in parent coordinates */
+static struct region *get_surface_region( struct window *win )
+{
+ struct region *region, *clip;
+ int offset_x, offset_y;
+
+ /* create a region relative to the window itself */
+
+ if (!(region = create_empty_region())) return NULL;
+ if (!(clip = create_empty_region())) goto error;
+ set_region_rect( region, &win->visible_rect );
+ if (win->win_region && !intersect_window_region( region, win )) goto error;
+ set_region_rect( clip, &win->client_rect );
+ if (win->win_region && !intersect_window_region( clip, win )) goto error;
+
+ if ((win->paint_flags & PAINT_HAS_PIXEL_FORMAT) && !subtract_region( region, region, clip ))
+ goto error;
+
+ /* clip children */
+
+ if (!is_desktop_window(win))
+ {
+ offset_x = win->client_rect.left;
+ offset_y = win->client_rect.top;
+ }
+ else offset_x = offset_y = 0;
+
+ if (!clip_pixel_format_children( win, clip, region, offset_x, offset_y )) goto error;
+
+ free_region( clip );
+ return region;
+
+error:
+ if (clip) free_region( clip );
+ free_region( region );
+ return NULL;
+}
+
+
/* get the window class of a window */
struct window_class* get_window_class( user_handle_t window )
{
}
}
- if (win->parent)
+ if (win->parent && !is_desktop_window( win->parent ))
{
/* make it relative to the old window pos for subtracting */
offset_region( new_vis_rgn, win->window_rect.left - old_window_rect->left,
}
}
+ /* reset cursor clip rectangle when the desktop changes size */
+ if (win == win->desktop->top_window) win->desktop->cursor.clip = *window_rect;
+
/* if the window is not visible, everything is easy */
if (!visible) return;
if (tmp)
{
set_region_rect( tmp, &valid_rects[0] );
+ /* subtract update region since invalid parts of the valid rect won't be copied */
+ if (win->update_region)
+ {
+ offset_region( tmp, -window_rect->left, -window_rect->top );
+ subtract_region( tmp, tmp, win->update_region );
+ offset_region( tmp, window_rect->left, window_rect->top );
+ }
if (subtract_region( tmp, win_rgn, tmp )) win_rgn = tmp;
else free_region( tmp );
}
if (win == shell_listview) shell_listview = NULL;
if (win == progman_window) progman_window = NULL;
if (win == taskman_window) taskman_window = NULL;
+ free_hotkeys( win->desktop, win->handle );
free_user_handle( win->handle );
destroy_properties( win );
list_remove( &win->entry );
{
rectangle_t window_rect, client_rect, visible_rect;
struct window *previous = NULL;
- struct window *win = get_window( req->handle );
- unsigned int flags = req->flags;
+ struct window *top, *win = get_window( req->handle );
+ unsigned int flags = req->swp_flags;
if (!win) return;
if (!win->parent) flags |= SWP_NOZORDER; /* no Z order for the desktop */
if (previous == win) flags |= SWP_NOZORDER; /* nothing to do */
}
+ /* windows that use UpdateLayeredWindow don't trigger repaints */
+ if ((win->ex_style & WS_EX_LAYERED) && !win->is_layered) flags |= SWP_NOREDRAW;
+
/* window rectangle must be ordered properly */
if (req->window.right < req->window.left || req->window.bottom < req->window.top)
{
mirror_rect( &win->parent->client_rect, &client_rect );
}
+ win->paint_flags = (win->paint_flags & ~PAINT_CLIENT_FLAGS) | (req->paint_flags & PAINT_CLIENT_FLAGS);
+ if (win->paint_flags & PAINT_HAS_PIXEL_FORMAT) update_pixel_format_flags( win );
+
if (get_req_data_size() >= 3 * sizeof(rectangle_t))
{
rectangle_t valid_rects[2];
memcpy( valid_rects, (const rectangle_t *)get_req_data() + 1, 2 * sizeof(rectangle_t) );
- if (win->ex_style & WS_EX_LAYOUTRTL)
+ if (win->parent && win->parent->ex_style & WS_EX_LAYOUTRTL)
{
- mirror_rect( &win->client_rect, &valid_rects[0] );
- mirror_rect( &win->client_rect, &valid_rects[1] );
+ mirror_rect( &win->parent->client_rect, &valid_rects[0] );
+ mirror_rect( &win->parent->client_rect, &valid_rects[1] );
}
set_window_pos( win, previous, flags, &window_rect, &client_rect, &visible_rect, valid_rects );
}
reply->new_style = win->style;
reply->new_ex_style = win->ex_style;
+
+ top = get_top_clipping_window( win );
+ if (is_visible( top ) &&
+ (top->paint_flags & PAINT_HAS_SURFACE) &&
+ (top->paint_flags & (PAINT_HAS_PIXEL_FORMAT | PAINT_PIXEL_FORMAT_CHILD)))
+ reply->surface_win = top->handle;
}
if (data) set_reply_data_ptr( data, reply->total_size );
}
reply->top_win = top->handle;
- reply->top_rect = (top == win && (req->flags & DCX_WINDOW)) ? top->visible_rect : top->client_rect;
+ reply->top_rect = top->visible_rect;
if (!is_desktop_window(win))
{
reply->win_rect.right = win->client_rect.right - win->client_rect.left;
reply->win_rect.bottom = win->client_rect.bottom - win->client_rect.top;
}
+ reply->paint_flags = win->paint_flags & PAINT_CLIENT_FLAGS;
+}
+
+
+/* get the surface visible region of a window */
+DECL_HANDLER(get_surface_region)
+{
+ struct region *region;
+ struct window *win = get_window( req->window );
+
+ if (!win || !is_visible( win )) return;
+
+ if ((region = get_surface_region( win )))
+ {
+ rectangle_t *data;
+ if (win->parent) map_win_region_to_screen( win->parent, region );
+ data = get_region_data_and_free( region, get_reply_max_size(), &reply->total_size );
+ if (data) set_reply_data_ptr( data, reply->total_size );
+ }
+ reply->visible_rect = win->visible_rect;
+ if (win->parent) client_to_screen_rect( win->parent, &reply->visible_rect );
}
if (ptr == win) break;
if (!(ptr->style & WS_VISIBLE)) continue;
if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
+ if (ptr->is_layered && (ptr->layered_flags & LWA_COLORKEY)) continue;
if (!intersect_rect( &tmp, &ptr->visible_rect, &rect )) continue;
- if (ptr->win_region && !rect_in_region( ptr->win_region, &rect )) continue;
+ if (ptr->win_region)
+ {
+ tmp = rect;
+ offset_rect( &tmp, -ptr->window_rect.left, -ptr->window_rect.top );
+ if (!rect_in_region( ptr->win_region, &tmp )) continue;
+ }
/* found a window obscuring the rectangle, now move win above this one */
/* making sure to not violate the topmost rule */
if (!(ptr->ex_style & WS_EX_TOPMOST) || (win->ex_style & WS_EX_TOPMOST))