Added support for window regions in the server.

This commit is contained in:
Alexandre Julliard 2004-06-29 03:53:25 +00:00
parent 7e168ee798
commit 618a7e5813
9 changed files with 256 additions and 51 deletions

View File

@ -1657,20 +1657,6 @@ int X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
return FALSE;
}
if (wndPtr->hrgnWnd == hrgn)
{
WIN_ReleasePtr( wndPtr );
return TRUE;
}
if (wndPtr->hrgnWnd)
{
/* delete previous region */
DeleteObject(wndPtr->hrgnWnd);
wndPtr->hrgnWnd = 0;
}
wndPtr->hrgnWnd = hrgn;
#ifdef HAVE_LIBXSHAPE
{
Display *display = thread_display();
@ -1706,7 +1692,6 @@ int X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
#endif /* HAVE_LIBXSHAPE */
WIN_ReleasePtr( wndPtr );
if (redraw) RedrawWindow( hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ERASE );
return TRUE;
}

View File

@ -2630,6 +2630,33 @@ struct get_visible_region_reply
struct get_window_region_request
{
struct request_header __header;
user_handle_t window;
};
struct get_window_region_reply
{
struct reply_header __header;
size_t total_size;
/* VARARG(region,rectangles); */
};
struct set_window_region_request
{
struct request_header __header;
user_handle_t window;
/* VARARG(region,rectangles); */
};
struct set_window_region_reply
{
struct reply_header __header;
};
struct set_window_property_request
{
struct request_header __header;
@ -3206,6 +3233,8 @@ enum request
REQ_inc_window_paint_count,
REQ_get_windows_offset,
REQ_get_visible_region,
REQ_get_window_region,
REQ_set_window_region,
REQ_set_window_property,
REQ_remove_window_property,
REQ_get_window_property,
@ -3387,6 +3416,8 @@ union generic_request
struct inc_window_paint_count_request inc_window_paint_count_request;
struct get_windows_offset_request get_windows_offset_request;
struct get_visible_region_request get_visible_region_request;
struct get_window_region_request get_window_region_request;
struct set_window_region_request set_window_region_request;
struct set_window_property_request set_window_property_request;
struct remove_window_property_request remove_window_property_request;
struct get_window_property_request get_window_property_request;
@ -3566,6 +3597,8 @@ union generic_reply
struct inc_window_paint_count_reply inc_window_paint_count_reply;
struct get_windows_offset_reply get_windows_offset_reply;
struct get_visible_region_reply get_visible_region_reply;
struct get_window_region_reply get_window_region_reply;
struct set_window_region_reply set_window_region_reply;
struct set_window_property_reply set_window_property_reply;
struct remove_window_property_reply remove_window_property_reply;
struct get_window_property_reply get_window_property_reply;
@ -3593,6 +3626,6 @@ union generic_reply
struct set_global_windows_reply set_global_windows_reply;
};
#define SERVER_PROTOCOL_VERSION 144
#define SERVER_PROTOCOL_VERSION 145
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -1849,6 +1849,22 @@ enum message_type
@END
/* Get the window region */
@REQ(get_window_region)
user_handle_t window; /* handle to the window */
@REPLY
size_t total_size; /* total size of the resulting region */
VARARG(region,rectangles); /* list of rectangles for the region */
@END
/* Set the window region */
@REQ(set_window_region)
user_handle_t window; /* handle to the window */
VARARG(region,rectangles); /* list of rectangles for the region */
@END
/* Set a window property */
@REQ(set_window_property)
user_handle_t window; /* handle to the window */

View File

@ -99,6 +99,8 @@ typedef int (*overlap_func_t)( struct region *reg, const rectangle_t *r1, const
typedef int (*non_overlap_func_t)( struct region *reg, const rectangle_t *r,
const rectangle_t *rEnd, int top, int bottom );
static const rectangle_t empty_rect; /* all-zero rectangle for empty regions */
/* add a rectangle to a region */
static inline rectangle_t *add_rect( struct region *reg )
{
@ -578,6 +580,16 @@ struct region *create_region( const rectangle_t *rects, unsigned int nb_rects )
return region;
}
/* create a region from request data */
struct region *create_region_from_req_data( const void *data, size_t size )
{
const rectangle_t *rects = data;
int nb_rects = size / sizeof(rectangle_t);
/* special case: empty region can be specified by a single all-zero rectangle */
if (nb_rects == 1 && !memcmp( rects, &empty_rect, sizeof(empty_rect) )) nb_rects = 0;
return create_region( rects, nb_rects );
}
/* free a region */
void free_region( struct region *region )
@ -607,7 +619,12 @@ void set_region_rect( struct region *region, const rectangle_t *rect )
/* retrieve the region data for sending to the client */
rectangle_t *get_region_data( const struct region *region, size_t *total_size )
{
*total_size = region->num_rects * sizeof(rectangle_t);
if (!(*total_size = region->num_rects * sizeof(rectangle_t)))
{
/* return a single empty rect for empty regions */
*total_size = sizeof(empty_rect);
return memdup( &empty_rect, sizeof(empty_rect) );
}
return memdup( region->rects, *total_size );
}
@ -615,7 +632,13 @@ rectangle_t *get_region_data( const struct region *region, size_t *total_size )
rectangle_t *get_region_data_and_free( struct region *region, size_t *total_size )
{
rectangle_t *ret = region->rects;
*total_size = region->num_rects * sizeof(rectangle_t);
if (!(*total_size = region->num_rects * sizeof(rectangle_t)))
{
/* return a single empty rect for empty regions */
*total_size = sizeof(empty_rect);
ret = memdup( &empty_rect, sizeof(empty_rect) );
}
free( region );
return ret;
}

View File

@ -252,6 +252,8 @@ DECL_HANDLER(set_window_text);
DECL_HANDLER(inc_window_paint_count);
DECL_HANDLER(get_windows_offset);
DECL_HANDLER(get_visible_region);
DECL_HANDLER(get_window_region);
DECL_HANDLER(set_window_region);
DECL_HANDLER(set_window_property);
DECL_HANDLER(remove_window_property);
DECL_HANDLER(get_window_property);
@ -432,6 +434,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_inc_window_paint_count,
(req_handler)req_get_windows_offset,
(req_handler)req_get_visible_region,
(req_handler)req_get_window_region,
(req_handler)req_set_window_region,
(req_handler)req_set_window_property,
(req_handler)req_remove_window_property,
(req_handler)req_get_window_property,

View File

@ -2190,6 +2190,25 @@ static void dump_get_visible_region_reply( const struct get_visible_region_reply
dump_varargs_rectangles( cur_size );
}
static void dump_get_window_region_request( const struct get_window_region_request *req )
{
fprintf( stderr, " window=%p", req->window );
}
static void dump_get_window_region_reply( const struct get_window_region_reply *req )
{
fprintf( stderr, " total_size=%d,", req->total_size );
fprintf( stderr, " region=" );
dump_varargs_rectangles( cur_size );
}
static void dump_set_window_region_request( const struct set_window_region_request *req )
{
fprintf( stderr, " window=%p,", req->window );
fprintf( stderr, " region=" );
dump_varargs_rectangles( cur_size );
}
static void dump_set_window_property_request( const struct set_window_property_request *req )
{
fprintf( stderr, " window=%p,", req->window );
@ -2660,6 +2679,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_inc_window_paint_count_request,
(dump_func)dump_get_windows_offset_request,
(dump_func)dump_get_visible_region_request,
(dump_func)dump_get_window_region_request,
(dump_func)dump_set_window_region_request,
(dump_func)dump_set_window_property_request,
(dump_func)dump_remove_window_property_request,
(dump_func)dump_get_window_property_request,
@ -2837,6 +2858,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)0,
(dump_func)dump_get_windows_offset_reply,
(dump_func)dump_get_visible_region_reply,
(dump_func)dump_get_window_region_reply,
(dump_func)0,
(dump_func)0,
(dump_func)dump_remove_window_property_reply,
(dump_func)dump_get_window_property_reply,
@ -3014,6 +3037,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"inc_window_paint_count",
"get_windows_offset",
"get_visible_region",
"get_window_region",
"set_window_region",
"set_window_property",
"remove_window_property",
"get_window_property",

View File

@ -68,6 +68,7 @@ extern void post_message( user_handle_t win, unsigned int message,
/* region functions */
extern struct region *create_region( const rectangle_t *rects, unsigned int nb_rects );
extern struct region *create_region_from_req_data( const void *data, size_t size );
extern void free_region( struct region *region );
extern void set_region_rect( struct region *region, const rectangle_t *rect );
extern rectangle_t *get_region_data( const struct region *region, size_t *total_size );

View File

@ -68,6 +68,7 @@ struct window
user_handle_t last_active; /* last active popup */
rectangle_t window_rect; /* window rectangle */
rectangle_t client_rect; /* client rectangle */
struct region *win_region; /* window region (for shaped windows) */
unsigned int style; /* window style */
unsigned int ex_style; /* window extended style */
unsigned int id; /* window id */
@ -261,6 +262,7 @@ static void destroy_window( struct window *win )
free_user_handle( win->handle );
destroy_properties( win );
unlink_window( win );
if (win->win_region) free_region( win->win_region );
release_class( win->class );
if (win->text) free( win->text );
memset( win, 0x55, sizeof(*win) );
@ -299,6 +301,7 @@ static struct window *create_window( struct window *parent, struct window *owner
win->class = class;
win->atom = atom;
win->last_active = win->handle;
win->win_region = NULL;
win->style = 0;
win->ex_style = 0;
win->id = 0;
@ -463,6 +466,18 @@ user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *threa
}
/* intersect the window region with the specified region, relative to the window parent */
static struct region *intersect_window_region( struct region *region, struct window *win )
{
/* make region relative to window rect */
offset_region( region, -win->window_rect.left, -win->window_rect.top );
if (!intersect_region( region, region, win->win_region )) return NULL;
/* make region relative to parent again */
offset_region( region, win->window_rect.left, win->window_rect.top );
return region;
}
/* clip all children of a given window out of the visible region */
static struct region *clip_children( struct window *parent, struct window *last,
struct region *region, int offset_x, int offset_y )
@ -476,6 +491,11 @@ static struct region *clip_children( struct window *parent, struct window *last,
if (!(ptr->style & WS_VISIBLE)) continue;
if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
set_region_rect( tmp, &ptr->window_rect );
if (ptr->win_region && !intersect_window_region( tmp, ptr ))
{
free_region( tmp );
return NULL;
}
offset_region( tmp, offset_x, offset_y );
if (!(region = subtract_region( region, region, tmp ))) break;
if (is_region_empty( region )) break;
@ -491,7 +511,6 @@ static struct region *get_visible_region( struct window *win, struct window *top
{
struct region *tmp, *region;
struct window *ptr;
rectangle_t rect;
int offset_x, offset_y;
if (!(region = create_empty_region())) return NULL;
@ -501,32 +520,32 @@ static struct region *get_visible_region( struct window *win, struct window *top
for (ptr = win; ptr != top_window; ptr = ptr->parent)
if (!(ptr->style & WS_VISIBLE)) return region; /* empty region */
/* retrieve window rectangle in parent coordinates */
/* create a region relative to the window itself */
if ((flags & DCX_PARENTCLIP) && win->parent)
{
rectangle_t rect;
rect.left = rect.top = 0;
rect.right = win->parent->client_rect.right - win->parent->client_rect.left;
rect.bottom = win->parent->client_rect.bottom - win->parent->client_rect.top;
set_region_rect( region, &rect );
offset_x = win->client_rect.left;
offset_y = win->client_rect.top;
}
else if (flags & DCX_WINDOW)
{
rect = win->window_rect;
set_region_rect( region, &win->window_rect );
if (win->win_region && !intersect_window_region( region, win )) goto error;
offset_x = win->window_rect.left;
offset_y = win->window_rect.top;
}
else
{
rect = win->client_rect;
set_region_rect( region, &win->client_rect );
if (win->win_region && !intersect_window_region( region, win )) goto error;
offset_x = win->client_rect.left;
offset_y = win->client_rect.top;
}
/* create a region relative to the window itself */
set_region_rect( region, &rect );
offset_region( region, -offset_x, -offset_y );
/* clip children */
@ -557,7 +576,16 @@ static struct region *get_visible_region( struct window *win, struct window *top
offset_y += win->client_rect.top;
offset_region( region, win->client_rect.left, win->client_rect.top );
set_region_rect( tmp, &win->client_rect );
if (!intersect_region( region, region, tmp )) goto error;
if (win->win_region && !intersect_window_region( tmp, win ))
{
free_region( tmp );
goto error;
}
if (!intersect_region( region, region, tmp ))
{
free_region( tmp );
goto error;
}
if (is_region_empty( region )) break;
}
offset_region( region, -offset_x, -offset_y ); /* make it relative to target window again */
@ -951,6 +979,40 @@ DECL_HANDLER(get_visible_region)
}
/* get the window region */
DECL_HANDLER(get_window_region)
{
struct window *win = get_window( req->window );
if (!win) return;
reply->total_size = 0;
if (win->win_region)
{
rectangle_t *data = get_region_data( win->win_region, &reply->total_size );
set_reply_data_ptr( data, min( reply->total_size, get_reply_max_size() ) );
}
}
/* set the window region */
DECL_HANDLER(set_window_region)
{
struct region *region = NULL;
struct window *win = get_window( req->window );
if (!win) return;
if (get_req_data_size()) /* no data means remove the region completely */
{
if (!(region = create_region_from_req_data( get_req_data(), get_req_data_size() )))
return;
}
if (win->win_region) free_region( win->win_region );
win->win_region = region;
}
/* set a window property */
DECL_HANDLER(set_window_property)
{

View File

@ -172,21 +172,51 @@ BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect )
int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
{
int nRet = ERROR;
WND *wndPtr = WIN_GetPtr( hwnd );
HRGN win_rgn = 0;
RGNDATA *data;
size_t size = 256;
BOOL retry = FALSE;
if (wndPtr == WND_OTHER_PROCESS)
do
{
if (IsWindow( hwnd ))
FIXME( "not supported on other process window %p\n", hwnd );
wndPtr = NULL;
}
if (!wndPtr)
if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 )))
{
SetLastError( ERROR_OUTOFMEMORY );
return ERROR;
}
SERVER_START_REQ( get_window_region )
{
req->window = hwnd;
wine_server_set_reply( req, data->Buffer, size );
if (!wine_server_call_err( req ))
{
if (!reply->total_size) retry = FALSE; /* no region at all */
else if (reply->total_size <= size)
{
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;
win_rgn = ExtCreateRegion( NULL, size, data );
retry = FALSE;
}
else
{
size = reply->total_size;
retry = TRUE;
}
}
}
SERVER_END_REQ;
HeapFree( GetProcessHeap(), 0, data );
} while (retry);
if (win_rgn)
{
SetLastError( ERROR_INVALID_WINDOW_HANDLE );
return ERROR;
nRet = CombineRgn( hrgn, win_rgn, 0, RGN_COPY );
DeleteObject( win_rgn );
}
if (wndPtr->hrgnWnd) nRet = CombineRgn( hrgn, wndPtr->hrgnWnd, 0, RGN_COPY );
WIN_ReleasePtr( wndPtr );
return nRet;
}
@ -196,21 +226,49 @@ int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
*/
int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
{
RECT rect;
static const RECT empty_rect;
WND *wndPtr;
BOOL ret;
if (hrgn) /* verify that region really exists */
if (hrgn)
{
if (GetRgnBox( hrgn, &rect ) == ERROR) return FALSE;
RGNDATA *data;
DWORD size;
if (!(size = GetRegionData( hrgn, 0, NULL ))) return FALSE;
if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
if (!GetRegionData( hrgn, size, data ))
{
HeapFree( GetProcessHeap(), 0, data );
return FALSE;
}
SERVER_START_REQ( set_window_region )
{
req->window = hwnd;
if (data->rdh.nCount)
wine_server_add_data( req, data->Buffer, data->rdh.nCount * sizeof(RECT) );
else
wine_server_add_data( req, &empty_rect, sizeof(empty_rect) );
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
}
else /* clear existing region */
{
SERVER_START_REQ( set_window_region )
{
req->window = hwnd;
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
}
if (USER_Driver.pSetWindowRgn)
return USER_Driver.pSetWindowRgn( hwnd, hrgn, bRedraw );
if (!ret) return FALSE;
if ((wndPtr = WIN_GetPtr( hwnd )) == WND_OTHER_PROCESS)
{
if (IsWindow( hwnd ))
FIXME( "not supported on other process window %p\n", hwnd );
FIXME( "not properly supported on other process window %p\n", hwnd );
wndPtr = NULL;
}
if (!wndPtr)
@ -224,7 +282,6 @@ int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
WIN_ReleasePtr( wndPtr );
return TRUE;
}
if (wndPtr->hrgnWnd)
{
/* delete previous region */
@ -234,12 +291,11 @@ int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
wndPtr->hrgnWnd = hrgn;
WIN_ReleasePtr( wndPtr );
/* Size the window to the rectangle of the new region (if it isn't NULL) */
if (hrgn) SetWindowPos( hwnd, 0, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOACTIVATE |
SWP_NOZORDER | (bRedraw ? 0 : SWP_NOREDRAW) );
return TRUE;
if (USER_Driver.pSetWindowRgn)
ret = USER_Driver.pSetWindowRgn( hwnd, hrgn, bRedraw );
if (ret && bRedraw) RedrawWindow( hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ERASE );
return ret;
}