Moved visible region calculation to the server.
This commit is contained in:
parent
00844ee036
commit
e8d86b7cd4
|
@ -121,79 +121,46 @@ static int clip_children( HWND parent, HWND last, HRGN hrgn, int whole_window )
|
|||
|
||||
|
||||
/***********************************************************************
|
||||
* get_visible_region
|
||||
*
|
||||
* Compute the visible region of a window
|
||||
* get_server_visible_region
|
||||
*/
|
||||
static HRGN get_visible_region( WND *win, HWND top, UINT flags, int mode )
|
||||
static HRGN get_server_visible_region( HWND hwnd, HWND top, UINT flags )
|
||||
{
|
||||
HRGN rgn;
|
||||
RECT rect;
|
||||
int xoffset, yoffset;
|
||||
X11DRV_WND_DATA *data = win->pDriverData;
|
||||
RGNDATA *data;
|
||||
HRGN ret = 0;
|
||||
size_t size = 256;
|
||||
BOOL retry = FALSE;
|
||||
|
||||
if (flags & DCX_WINDOW)
|
||||
do
|
||||
{
|
||||
xoffset = win->rectWindow.left;
|
||||
yoffset = win->rectWindow.top;
|
||||
}
|
||||
else
|
||||
{
|
||||
xoffset = win->rectClient.left;
|
||||
yoffset = win->rectClient.top;
|
||||
}
|
||||
|
||||
if (flags & DCX_PARENTCLIP)
|
||||
GetClientRect( win->parent, &rect );
|
||||
else if (flags & DCX_WINDOW)
|
||||
rect = data->whole_rect;
|
||||
else
|
||||
rect = win->rectClient;
|
||||
|
||||
/* vis region is relative to the start of the client/window area */
|
||||
OffsetRect( &rect, -xoffset, -yoffset );
|
||||
|
||||
if (!(rgn = CreateRectRgn( rect.left, rect.top, rect.right, rect.bottom ))) return 0;
|
||||
|
||||
if ((flags & DCX_CLIPCHILDREN) && (mode != ClipByChildren))
|
||||
{
|
||||
/* we need to clip children by hand */
|
||||
if (clip_children( win->hwndSelf, 0, rgn, (flags & DCX_WINDOW) ) == NULLREGION) return rgn;
|
||||
}
|
||||
|
||||
if (top && top != win->hwndSelf) /* need to clip siblings of ancestors */
|
||||
{
|
||||
WND *parent, *ptr = WIN_FindWndPtr( win->hwndSelf );
|
||||
HRGN tmp = 0;
|
||||
|
||||
OffsetRgn( rgn, xoffset, yoffset );
|
||||
for (;;)
|
||||
if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ))) return 0;
|
||||
SERVER_START_REQ( get_visible_region )
|
||||
{
|
||||
if (ptr->dwStyle & WS_CLIPSIBLINGS)
|
||||
req->window = hwnd;
|
||||
req->top_win = top;
|
||||
req->flags = flags;
|
||||
wine_server_set_reply( req, data->Buffer, size );
|
||||
if (!wine_server_call_err( req ))
|
||||
{
|
||||
if (clip_children( ptr->parent, ptr->hwndSelf, rgn, FALSE ) == NULLREGION) break;
|
||||
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;
|
||||
ret = ExtCreateRegion( NULL, size, data );
|
||||
}
|
||||
else
|
||||
{
|
||||
size = reply->total_size;
|
||||
retry = TRUE;
|
||||
}
|
||||
}
|
||||
if (ptr->hwndSelf == top) break;
|
||||
if (!(parent = WIN_FindWndPtr( ptr->parent ))) break;
|
||||
WIN_ReleaseWndPtr( ptr );
|
||||
ptr = parent;
|
||||
/* clip to parent client area */
|
||||
if (tmp) SetRectRgn( tmp, 0, 0, ptr->rectClient.right - ptr->rectClient.left,
|
||||
ptr->rectClient.bottom - ptr->rectClient.top );
|
||||
else tmp = CreateRectRgn( 0, 0, ptr->rectClient.right - ptr->rectClient.left,
|
||||
ptr->rectClient.bottom - ptr->rectClient.top );
|
||||
CombineRgn( rgn, rgn, tmp, RGN_AND );
|
||||
OffsetRgn( rgn, ptr->rectClient.left, ptr->rectClient.top );
|
||||
xoffset += ptr->rectClient.left;
|
||||
yoffset += ptr->rectClient.top;
|
||||
}
|
||||
WIN_ReleaseWndPtr( ptr );
|
||||
/* make it relative to the target window again */
|
||||
OffsetRgn( rgn, -xoffset, -yoffset );
|
||||
if (tmp) DeleteObject( tmp );
|
||||
}
|
||||
|
||||
return rgn;
|
||||
SERVER_END_REQ;
|
||||
HeapFree( GetProcessHeap(), 0, data );
|
||||
} while (retry);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -426,52 +393,24 @@ BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
|
|||
HWND top = 0;
|
||||
X11DRV_WND_DATA *data = win->pDriverData;
|
||||
struct x11drv_escape_set_drawable escape;
|
||||
BOOL visible;
|
||||
|
||||
escape.mode = IncludeInferiors;
|
||||
/* don't clip siblings if using parent clip region */
|
||||
if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS;
|
||||
|
||||
/* find the top parent in the hierarchy that isn't clipping siblings */
|
||||
visible = (win->dwStyle & WS_VISIBLE) != 0;
|
||||
|
||||
if (visible)
|
||||
top = GetAncestor( hwnd, GA_ROOT );
|
||||
if (top != hwnd)
|
||||
{
|
||||
HWND *list = WIN_ListParents( hwnd );
|
||||
if (list)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; list[i] != GetDesktopWindow(); i++)
|
||||
{
|
||||
LONG style = GetWindowLongW( list[i], GWL_STYLE );
|
||||
if (!(style & WS_VISIBLE))
|
||||
{
|
||||
visible = FALSE;
|
||||
top = 0;
|
||||
break;
|
||||
}
|
||||
if (!(style & WS_CLIPSIBLINGS)) top = list[i];
|
||||
}
|
||||
HeapFree( GetProcessHeap(), 0, list );
|
||||
}
|
||||
if (!top && visible && !(flags & DCX_CLIPSIBLINGS)) top = hwnd;
|
||||
}
|
||||
|
||||
if (top)
|
||||
{
|
||||
HWND parent = GetAncestor( top, GA_PARENT );
|
||||
escape.org.x = escape.org.y = 0;
|
||||
if (flags & DCX_WINDOW)
|
||||
{
|
||||
escape.org.x = win->rectWindow.left - win->rectClient.left;
|
||||
escape.org.y = win->rectWindow.top - win->rectClient.top;
|
||||
}
|
||||
MapWindowPoints( hwnd, parent, &escape.org, 1 );
|
||||
MapWindowPoints( hwnd, top, &escape.org, 1 );
|
||||
escape.drawable_org.x = escape.drawable_org.y = 0;
|
||||
MapWindowPoints( parent, 0, &escape.drawable_org, 1 );
|
||||
/* have to use the parent so that we include siblings */
|
||||
if (parent) escape.drawable = X11DRV_get_client_window( parent );
|
||||
else escape.drawable = root_window;
|
||||
MapWindowPoints( top, 0, &escape.drawable_org, 1 );
|
||||
escape.drawable = X11DRV_get_client_window( top );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -482,23 +421,22 @@ BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
|
|||
escape.org.y = 0;
|
||||
escape.drawable_org = escape.org;
|
||||
}
|
||||
else if (flags & DCX_WINDOW)
|
||||
{
|
||||
escape.drawable = data->whole_window;
|
||||
escape.org.x = win->rectWindow.left - data->whole_rect.left;
|
||||
escape.org.y = win->rectWindow.top - data->whole_rect.top;
|
||||
escape.drawable_org.x = data->whole_rect.left - win->rectClient.left;
|
||||
escape.drawable_org.y = data->whole_rect.top - win->rectClient.top;
|
||||
}
|
||||
else
|
||||
{
|
||||
escape.drawable = data->client_window;
|
||||
escape.org.x = 0;
|
||||
escape.org.y = 0;
|
||||
escape.drawable_org = escape.org;
|
||||
if (flags & DCX_CLIPCHILDREN) escape.mode = ClipByChildren; /* can use X11 clipping */
|
||||
escape.drawable = data->whole_window;
|
||||
escape.drawable_org.x = data->whole_rect.left;
|
||||
escape.drawable_org.y = data->whole_rect.top;
|
||||
if (flags & DCX_WINDOW)
|
||||
{
|
||||
escape.org.x = win->rectWindow.left - data->whole_rect.left;
|
||||
escape.org.y = win->rectWindow.top - data->whole_rect.top;
|
||||
}
|
||||
else
|
||||
{
|
||||
escape.org.x = win->rectClient.left - data->whole_rect.left;
|
||||
escape.org.y = win->rectClient.top - data->whole_rect.top;
|
||||
}
|
||||
}
|
||||
MapWindowPoints( hwnd, 0, &escape.drawable_org, 1 );
|
||||
}
|
||||
|
||||
escape.code = X11DRV_SET_DRAWABLE;
|
||||
|
@ -508,17 +446,10 @@ BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
|
|||
SetHookFlags16( HDC_16(hdc), DCHF_VALIDATEVISRGN )) /* DC was dirty */
|
||||
{
|
||||
/* need to recompute the visible region */
|
||||
HRGN visRgn;
|
||||
HRGN visRgn = get_server_visible_region( hwnd, top, flags );
|
||||
|
||||
if (visible)
|
||||
{
|
||||
visRgn = get_visible_region( win, top, flags, escape.mode );
|
||||
|
||||
if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
|
||||
CombineRgn( visRgn, visRgn, hrgn,
|
||||
(flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
|
||||
}
|
||||
else visRgn = CreateRectRgn( 0, 0, 0, 0 );
|
||||
if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
|
||||
CombineRgn( visRgn, visRgn, hrgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
|
||||
|
||||
SelectVisRgn16( HDC_16(hdc), HRGN_16(visRgn) );
|
||||
DeleteObject( visRgn );
|
||||
|
|
|
@ -2614,6 +2614,22 @@ struct get_windows_offset_reply
|
|||
|
||||
|
||||
|
||||
struct get_visible_region_request
|
||||
{
|
||||
struct request_header __header;
|
||||
user_handle_t window;
|
||||
user_handle_t top_win;
|
||||
unsigned int flags;
|
||||
};
|
||||
struct get_visible_region_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
size_t total_size;
|
||||
/* VARARG(region,rectangles); */
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct set_window_property_request
|
||||
{
|
||||
struct request_header __header;
|
||||
|
@ -3189,6 +3205,7 @@ enum request
|
|||
REQ_set_window_text,
|
||||
REQ_inc_window_paint_count,
|
||||
REQ_get_windows_offset,
|
||||
REQ_get_visible_region,
|
||||
REQ_set_window_property,
|
||||
REQ_remove_window_property,
|
||||
REQ_get_window_property,
|
||||
|
@ -3369,6 +3386,7 @@ union generic_request
|
|||
struct set_window_text_request set_window_text_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 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;
|
||||
|
@ -3547,6 +3565,7 @@ union generic_reply
|
|||
struct set_window_text_reply set_window_text_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 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;
|
||||
|
@ -3574,6 +3593,6 @@ union generic_reply
|
|||
struct set_global_windows_reply set_global_windows_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 143
|
||||
#define SERVER_PROTOCOL_VERSION 144
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -29,6 +29,7 @@ C_SRCS = \
|
|||
process.c \
|
||||
ptrace.c \
|
||||
queue.c \
|
||||
region.c \
|
||||
registry.c \
|
||||
request.c \
|
||||
semaphore.c \
|
||||
|
|
|
@ -1838,6 +1838,17 @@ enum message_type
|
|||
@END
|
||||
|
||||
|
||||
/* Get the visible region of a window */
|
||||
@REQ(get_visible_region)
|
||||
user_handle_t window; /* handle to the window */
|
||||
user_handle_t top_win; /* top window to clip against */
|
||||
unsigned int flags; /* DCX flags */
|
||||
@REPLY
|
||||
size_t total_size; /* total size of the resulting region */
|
||||
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 */
|
||||
|
|
|
@ -0,0 +1,737 @@
|
|||
/*
|
||||
* Server-side region objects. Based on the X11 implementation.
|
||||
*
|
||||
* Copyright 1993, 1994, 1995, 2004 Alexandre Julliard
|
||||
* Modifications and additions: Copyright 1998 Huw Davies
|
||||
* 1999 Alex Korobka
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Note:
|
||||
* This is a simplified version of the code, without all the explanations.
|
||||
* Check the equivalent GDI code to make sense of it.
|
||||
*/
|
||||
|
||||
/************************************************************************
|
||||
|
||||
Copyright (c) 1987, 1988 X Consortium
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of the X Consortium shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from the X Consortium.
|
||||
|
||||
|
||||
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
|
||||
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the name of Digital not be
|
||||
used in advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
||||
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
||||
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
||||
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
SOFTWARE.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "request.h"
|
||||
|
||||
struct region
|
||||
{
|
||||
int size;
|
||||
int num_rects;
|
||||
rectangle_t *rects;
|
||||
rectangle_t extents;
|
||||
};
|
||||
|
||||
|
||||
#define RGN_DEFAULT_RECTS 2
|
||||
|
||||
#define EXTENTCHECK(r1, r2) \
|
||||
((r1)->right > (r2)->left && \
|
||||
(r1)->left < (r2)->right && \
|
||||
(r1)->bottom > (r2)->top && \
|
||||
(r1)->top < (r2)->bottom)
|
||||
|
||||
typedef int (*overlap_func_t)( struct region *reg, const rectangle_t *r1, const rectangle_t *r1End,
|
||||
const rectangle_t *r2, const rectangle_t *r2End, int top, int bottom );
|
||||
typedef int (*non_overlap_func_t)( struct region *reg, const rectangle_t *r,
|
||||
const rectangle_t *rEnd, int top, int bottom );
|
||||
|
||||
/* add a rectangle to a region */
|
||||
static inline rectangle_t *add_rect( struct region *reg )
|
||||
{
|
||||
if (reg->num_rects >= reg->size - 1)
|
||||
{
|
||||
rectangle_t *new_rect = realloc( reg->rects, 2 * sizeof(rectangle_t) * reg->size );
|
||||
if (!new_rect)
|
||||
{
|
||||
set_error( STATUS_NO_MEMORY );
|
||||
return 0;
|
||||
}
|
||||
reg->rects = new_rect;
|
||||
reg->size *= 2;
|
||||
}
|
||||
return reg->rects + reg->num_rects++;
|
||||
}
|
||||
|
||||
/* make sure all the rectangles are valid and that the region is properly y-x-banded */
|
||||
static inline int validate_rectangles( const rectangle_t *rects, unsigned int nb_rects )
|
||||
{
|
||||
const rectangle_t *ptr, *end;
|
||||
|
||||
for (ptr = rects, end = rects + nb_rects; ptr < end; ptr++)
|
||||
{
|
||||
if (ptr->left >= ptr->right || ptr->top >= ptr->bottom) return 0; /* empty rectangle */
|
||||
if (ptr == end - 1) break;
|
||||
if (ptr[0].top == ptr[1].top) /* same band */
|
||||
{
|
||||
if (ptr[0].bottom != ptr[1].bottom) return 0; /* not same y extent */
|
||||
if (ptr[0].right >= ptr[1].left) return 0; /* not properly x ordered */
|
||||
}
|
||||
else /* new band */
|
||||
{
|
||||
if (ptr[0].bottom > ptr[1].top) return 0; /* not properly y ordered */
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* attempt to merge the rects in the current band with those in the */
|
||||
/* previous one. Used only by region_op. */
|
||||
static int coalesce_region( struct region *pReg, int prevStart, int curStart )
|
||||
{
|
||||
int curNumRects;
|
||||
rectangle_t *pRegEnd = &pReg->rects[pReg->num_rects];
|
||||
rectangle_t *pPrevRect = &pReg->rects[prevStart];
|
||||
rectangle_t *pCurRect = &pReg->rects[curStart];
|
||||
int prevNumRects = curStart - prevStart;
|
||||
int bandtop = pCurRect->top;
|
||||
|
||||
for (curNumRects = 0;
|
||||
(pCurRect != pRegEnd) && (pCurRect->top == bandtop);
|
||||
curNumRects++)
|
||||
{
|
||||
pCurRect++;
|
||||
}
|
||||
|
||||
if (pCurRect != pRegEnd)
|
||||
{
|
||||
pRegEnd--;
|
||||
while (pRegEnd[-1].top == pRegEnd->top) pRegEnd--;
|
||||
curStart = pRegEnd - pReg->rects;
|
||||
pRegEnd = pReg->rects + pReg->num_rects;
|
||||
}
|
||||
|
||||
if ((curNumRects == prevNumRects) && (curNumRects != 0))
|
||||
{
|
||||
pCurRect -= curNumRects;
|
||||
if (pPrevRect->bottom == pCurRect->top)
|
||||
{
|
||||
do
|
||||
{
|
||||
if ((pPrevRect->left != pCurRect->left) ||
|
||||
(pPrevRect->right != pCurRect->right)) return curStart;
|
||||
pPrevRect++;
|
||||
pCurRect++;
|
||||
prevNumRects -= 1;
|
||||
} while (prevNumRects != 0);
|
||||
|
||||
pReg->num_rects -= curNumRects;
|
||||
pCurRect -= curNumRects;
|
||||
pPrevRect -= curNumRects;
|
||||
|
||||
do
|
||||
{
|
||||
pPrevRect->bottom = pCurRect->bottom;
|
||||
pPrevRect++;
|
||||
pCurRect++;
|
||||
curNumRects -= 1;
|
||||
} while (curNumRects != 0);
|
||||
|
||||
if (pCurRect == pRegEnd) curStart = prevStart;
|
||||
else do { *pPrevRect++ = *pCurRect++; } while (pCurRect != pRegEnd);
|
||||
|
||||
}
|
||||
}
|
||||
return curStart;
|
||||
}
|
||||
|
||||
/* apply an operation to two regions */
|
||||
/* check the GDI version of the code for explanations */
|
||||
static int region_op( struct region *newReg, const struct region *reg1, const struct region *reg2,
|
||||
overlap_func_t overlap_func,
|
||||
non_overlap_func_t non_overlap1_func,
|
||||
non_overlap_func_t non_overlap2_func )
|
||||
{
|
||||
int ybot, ytop, top, bot, prevBand, curBand;
|
||||
const rectangle_t *r1BandEnd, *r2BandEnd;
|
||||
|
||||
const rectangle_t *r1 = reg1->rects;
|
||||
const rectangle_t *r2 = reg2->rects;
|
||||
const rectangle_t *r1End = r1 + reg1->num_rects;
|
||||
const rectangle_t *r2End = r2 + reg2->num_rects;
|
||||
|
||||
rectangle_t *new_rects, *old_rects = newReg->rects;
|
||||
int new_size, ret = 0;
|
||||
|
||||
new_size = max( reg1->num_rects, reg2->num_rects ) * 2;
|
||||
if (!(new_rects = mem_alloc( new_size * sizeof(*newReg->rects) ))) return 0;
|
||||
|
||||
newReg->size = new_size;
|
||||
newReg->rects = new_rects;
|
||||
newReg->num_rects = 0;
|
||||
|
||||
if (reg1->extents.top < reg2->extents.top)
|
||||
ybot = reg1->extents.top;
|
||||
else
|
||||
ybot = reg2->extents.top;
|
||||
|
||||
prevBand = 0;
|
||||
|
||||
do
|
||||
{
|
||||
curBand = newReg->num_rects;
|
||||
|
||||
r1BandEnd = r1;
|
||||
while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top)) r1BandEnd++;
|
||||
|
||||
r2BandEnd = r2;
|
||||
while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top)) r2BandEnd++;
|
||||
|
||||
if (r1->top < r2->top)
|
||||
{
|
||||
top = max(r1->top,ybot);
|
||||
bot = min(r1->bottom,r2->top);
|
||||
|
||||
if ((top != bot) && non_overlap1_func)
|
||||
{
|
||||
if (!non_overlap1_func( newReg, r1, r1BandEnd, top, bot )) goto done;
|
||||
}
|
||||
|
||||
ytop = r2->top;
|
||||
}
|
||||
else if (r2->top < r1->top)
|
||||
{
|
||||
top = max(r2->top,ybot);
|
||||
bot = min(r2->bottom,r1->top);
|
||||
|
||||
if ((top != bot) && non_overlap2_func)
|
||||
{
|
||||
if (!non_overlap2_func( newReg, r2, r2BandEnd, top, bot )) goto done;
|
||||
}
|
||||
|
||||
ytop = r1->top;
|
||||
}
|
||||
else
|
||||
{
|
||||
ytop = r1->top;
|
||||
}
|
||||
|
||||
if (newReg->num_rects != curBand)
|
||||
prevBand = coalesce_region(newReg, prevBand, curBand);
|
||||
|
||||
ybot = min(r1->bottom, r2->bottom);
|
||||
curBand = newReg->num_rects;
|
||||
if (ybot > ytop)
|
||||
{
|
||||
if (!overlap_func( newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot )) goto done;
|
||||
}
|
||||
|
||||
if (newReg->num_rects != curBand)
|
||||
prevBand = coalesce_region(newReg, prevBand, curBand);
|
||||
|
||||
if (r1->bottom == ybot) r1 = r1BandEnd;
|
||||
if (r2->bottom == ybot) r2 = r2BandEnd;
|
||||
} while ((r1 != r1End) && (r2 != r2End));
|
||||
|
||||
curBand = newReg->num_rects;
|
||||
if (r1 != r1End)
|
||||
{
|
||||
if (non_overlap1_func)
|
||||
{
|
||||
do
|
||||
{
|
||||
r1BandEnd = r1;
|
||||
while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top)) r1BandEnd++;
|
||||
if (!non_overlap1_func( newReg, r1, r1BandEnd, max(r1->top,ybot), r1->bottom ))
|
||||
goto done;
|
||||
r1 = r1BandEnd;
|
||||
} while (r1 != r1End);
|
||||
}
|
||||
}
|
||||
else if ((r2 != r2End) && non_overlap2_func)
|
||||
{
|
||||
do
|
||||
{
|
||||
r2BandEnd = r2;
|
||||
while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top)) r2BandEnd++;
|
||||
if (!non_overlap2_func( newReg, r2, r2BandEnd, max(r2->top,ybot), r2->bottom ))
|
||||
goto done;
|
||||
r2 = r2BandEnd;
|
||||
} while (r2 != r2End);
|
||||
}
|
||||
|
||||
if (newReg->num_rects != curBand) coalesce_region(newReg, prevBand, curBand);
|
||||
|
||||
if ((newReg->num_rects < (newReg->size / 2)) && (newReg->size > 2))
|
||||
{
|
||||
new_size = max( newReg->num_rects, RGN_DEFAULT_RECTS );
|
||||
if ((new_rects = realloc( newReg->rects, sizeof(*newReg->rects) * new_size )))
|
||||
{
|
||||
newReg->rects = new_rects;
|
||||
newReg->size = new_size;
|
||||
}
|
||||
}
|
||||
ret = 1;
|
||||
done:
|
||||
free( old_rects );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* recalculate the extents of a region */
|
||||
static void set_region_extents( struct region *region )
|
||||
{
|
||||
rectangle_t *pRect, *pRectEnd;
|
||||
|
||||
if (region->num_rects == 0)
|
||||
{
|
||||
region->extents.left = 0;
|
||||
region->extents.top = 0;
|
||||
region->extents.right = 0;
|
||||
region->extents.bottom = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
pRect = region->rects;
|
||||
pRectEnd = &pRect[region->num_rects - 1];
|
||||
|
||||
region->extents.left = pRect->left;
|
||||
region->extents.top = pRect->top;
|
||||
region->extents.right = pRectEnd->right;
|
||||
region->extents.bottom = pRectEnd->bottom;
|
||||
|
||||
while (pRect <= pRectEnd)
|
||||
{
|
||||
if (pRect->left < region->extents.left) region->extents.left = pRect->left;
|
||||
if (pRect->right > region->extents.right) region->extents.right = pRect->right;
|
||||
pRect++;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle an overlapping band for intersect_region */
|
||||
static int intersect_overlapping( struct region *pReg,
|
||||
const rectangle_t *r1, const rectangle_t *r1End,
|
||||
const rectangle_t *r2, const rectangle_t *r2End,
|
||||
int top, int bottom )
|
||||
|
||||
{
|
||||
int left, right;
|
||||
|
||||
while ((r1 != r1End) && (r2 != r2End))
|
||||
{
|
||||
left = max(r1->left, r2->left);
|
||||
right = min(r1->right, r2->right);
|
||||
|
||||
if (left < right)
|
||||
{
|
||||
rectangle_t *rect = add_rect( pReg );
|
||||
if (!rect) return 0;
|
||||
rect->left = left;
|
||||
rect->top = top;
|
||||
rect->right = right;
|
||||
rect->bottom = bottom;
|
||||
}
|
||||
|
||||
if (r1->right < r2->right) r1++;
|
||||
else if (r2->right < r1->right) r2++;
|
||||
else
|
||||
{
|
||||
r1++;
|
||||
r2++;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* handle a non-overlapping band for subtract_region */
|
||||
static int subtract_non_overlapping( struct region *pReg, const rectangle_t *r,
|
||||
const rectangle_t *rEnd, int top, int bottom )
|
||||
{
|
||||
while (r != rEnd)
|
||||
{
|
||||
rectangle_t *rect = add_rect( pReg );
|
||||
if (!rect) return 0;
|
||||
rect->left = r->left;
|
||||
rect->top = top;
|
||||
rect->right = r->right;
|
||||
rect->bottom = bottom;
|
||||
r++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* handle an overlapping band for subtract_region */
|
||||
static int subtract_overlapping( struct region *pReg,
|
||||
const rectangle_t *r1, const rectangle_t *r1End,
|
||||
const rectangle_t *r2, const rectangle_t *r2End,
|
||||
int top, int bottom )
|
||||
{
|
||||
int left = r1->left;
|
||||
|
||||
while ((r1 != r1End) && (r2 != r2End))
|
||||
{
|
||||
if (r2->right <= left) r2++;
|
||||
else if (r2->left <= left)
|
||||
{
|
||||
left = r2->right;
|
||||
if (left >= r1->right)
|
||||
{
|
||||
r1++;
|
||||
if (r1 != r1End)
|
||||
left = r1->left;
|
||||
}
|
||||
else r2++;
|
||||
}
|
||||
else if (r2->left < r1->right)
|
||||
{
|
||||
rectangle_t *rect = add_rect( pReg );
|
||||
if (!rect) return 0;
|
||||
rect->left = left;
|
||||
rect->top = top;
|
||||
rect->right = r2->left;
|
||||
rect->bottom = bottom;
|
||||
left = r2->right;
|
||||
if (left >= r1->right)
|
||||
{
|
||||
r1++;
|
||||
if (r1 != r1End)
|
||||
left = r1->left;
|
||||
}
|
||||
else r2++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r1->right > left)
|
||||
{
|
||||
rectangle_t *rect = add_rect( pReg );
|
||||
if (!rect) return 0;
|
||||
rect->left = left;
|
||||
rect->top = top;
|
||||
rect->right = r1->right;
|
||||
rect->bottom = bottom;
|
||||
}
|
||||
r1++;
|
||||
left = r1->left;
|
||||
}
|
||||
}
|
||||
|
||||
while (r1 != r1End)
|
||||
{
|
||||
rectangle_t *rect = add_rect( pReg );
|
||||
if (!rect) return 0;
|
||||
rect->left = left;
|
||||
rect->top = top;
|
||||
rect->right = r1->right;
|
||||
rect->bottom = bottom;
|
||||
r1++;
|
||||
if (r1 != r1End) left = r1->left;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* handle a non-overlapping band for union_region */
|
||||
static int union_non_overlapping( struct region *pReg, const rectangle_t *r,
|
||||
const rectangle_t *rEnd, int top, int bottom )
|
||||
{
|
||||
while (r != rEnd)
|
||||
{
|
||||
rectangle_t *rect = add_rect( pReg );
|
||||
if (!rect) return 0;
|
||||
rect->left = r->left;
|
||||
rect->top = top;
|
||||
rect->right = r->right;
|
||||
rect->bottom = bottom;
|
||||
r++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* handle an overlapping band for union_region */
|
||||
static int union_overlapping( struct region *pReg,
|
||||
const rectangle_t *r1, const rectangle_t *r1End,
|
||||
const rectangle_t *r2, const rectangle_t *r2End,
|
||||
int top, int bottom )
|
||||
{
|
||||
#define MERGERECT(r) \
|
||||
if ((pReg->num_rects != 0) && \
|
||||
(pReg->rects[pReg->num_rects-1].top == top) && \
|
||||
(pReg->rects[pReg->num_rects-1].bottom == bottom) && \
|
||||
(pReg->rects[pReg->num_rects-1].right >= r->left)) \
|
||||
{ \
|
||||
if (pReg->rects[pReg->num_rects-1].right < r->right) \
|
||||
{ \
|
||||
pReg->rects[pReg->num_rects-1].right = r->right; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
rectangle_t *rect = add_rect( pReg ); \
|
||||
if (!rect) return 0; \
|
||||
rect->top = top; \
|
||||
rect->bottom = bottom; \
|
||||
rect->left = r->left; \
|
||||
rect->right = r->right; \
|
||||
} \
|
||||
r++;
|
||||
|
||||
while ((r1 != r1End) && (r2 != r2End))
|
||||
{
|
||||
if (r1->left < r2->left)
|
||||
{
|
||||
MERGERECT(r1);
|
||||
}
|
||||
else
|
||||
{
|
||||
MERGERECT(r2);
|
||||
}
|
||||
}
|
||||
|
||||
if (r1 != r1End)
|
||||
{
|
||||
do
|
||||
{
|
||||
MERGERECT(r1);
|
||||
} while (r1 != r1End);
|
||||
}
|
||||
else while (r2 != r2End)
|
||||
{
|
||||
MERGERECT(r2);
|
||||
}
|
||||
return 1;
|
||||
#undef MERGERECT
|
||||
}
|
||||
|
||||
|
||||
/* create a region from an array of rectangles */
|
||||
struct region *create_region( const rectangle_t *rects, unsigned int nb_rects )
|
||||
{
|
||||
struct region *region;
|
||||
unsigned int size = max( nb_rects, RGN_DEFAULT_RECTS );
|
||||
|
||||
if (!validate_rectangles( rects, nb_rects ))
|
||||
{
|
||||
set_error( STATUS_INVALID_PARAMETER );
|
||||
return NULL;
|
||||
}
|
||||
if (!(region = mem_alloc( sizeof(*region) ))) return NULL;
|
||||
if (!(region->rects = mem_alloc( size * sizeof(*region->rects) )))
|
||||
{
|
||||
free( region );
|
||||
return NULL;
|
||||
}
|
||||
region->size = size;
|
||||
region->num_rects = nb_rects;
|
||||
memcpy( region->rects, rects, nb_rects * sizeof(*rects) );
|
||||
set_region_extents( region );
|
||||
return region;
|
||||
}
|
||||
|
||||
|
||||
/* free a region */
|
||||
void free_region( struct region *region )
|
||||
{
|
||||
free( region->rects );
|
||||
free( region );
|
||||
}
|
||||
|
||||
/* set region to a simple rectangle */
|
||||
void set_region_rect( struct region *region, const rectangle_t *rect )
|
||||
{
|
||||
if (rect->left < rect->right && rect->top < rect->bottom)
|
||||
{
|
||||
region->num_rects = 1;
|
||||
region->rects[0] = region->extents = *rect;
|
||||
}
|
||||
else
|
||||
{
|
||||
region->num_rects = 0;
|
||||
region->extents.left = 0;
|
||||
region->extents.top = 0;
|
||||
region->extents.right = 0;
|
||||
region->extents.bottom = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
return memdup( region->rects, *total_size );
|
||||
}
|
||||
|
||||
/* retrieve the region data for sending to the client and free the region at the same time */
|
||||
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);
|
||||
free( region );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check if a given region is empty */
|
||||
int is_region_empty( const struct region *region )
|
||||
{
|
||||
return region->num_rects == 0;
|
||||
}
|
||||
|
||||
|
||||
/* get the extents rect of a region */
|
||||
void get_region_extents( const struct region *region, rectangle_t *rect )
|
||||
{
|
||||
*rect = region->extents;
|
||||
}
|
||||
|
||||
/* add an offset to a region */
|
||||
void offset_region( struct region *region, int x, int y )
|
||||
{
|
||||
rectangle_t *rect, *end;
|
||||
|
||||
for (rect = region->rects, end = rect + region->num_rects; rect < end; rect++)
|
||||
{
|
||||
rect->left += x;
|
||||
rect->right += x;
|
||||
rect->top += y;
|
||||
rect->bottom += y;
|
||||
}
|
||||
region->extents.left += x;
|
||||
region->extents.right += x;
|
||||
region->extents.top += y;
|
||||
region->extents.bottom += y;
|
||||
}
|
||||
|
||||
/* make a copy of a region; returns dst or NULL on error */
|
||||
struct region *copy_region( struct region *dst, const struct region *src )
|
||||
{
|
||||
if (dst == src) return dst;
|
||||
|
||||
if (dst->size < src->num_rects)
|
||||
{
|
||||
rectangle_t *rect = realloc( dst->rects, src->num_rects * sizeof(*rect) );
|
||||
if (!rect)
|
||||
{
|
||||
set_error( STATUS_NO_MEMORY );
|
||||
return NULL;
|
||||
}
|
||||
dst->rects = rect;
|
||||
dst->size = src->num_rects;
|
||||
}
|
||||
dst->num_rects = src->num_rects;
|
||||
dst->extents = src->extents;
|
||||
memcpy( dst->rects, src->rects, src->num_rects * sizeof(*dst->rects) );
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* compute the intersection of two regions into dst, which can be one of the source regions */
|
||||
struct region *intersect_region( struct region *dst, const struct region *src1,
|
||||
const struct region *src2 )
|
||||
{
|
||||
if (!src1->num_rects || !src2->num_rects || !EXTENTCHECK(&src1->extents, &src2->extents))
|
||||
{
|
||||
dst->num_rects = 0;
|
||||
dst->extents.left = 0;
|
||||
dst->extents.top = 0;
|
||||
dst->extents.right = 0;
|
||||
dst->extents.bottom = 0;
|
||||
return dst;
|
||||
}
|
||||
if (!region_op( dst, src1, src2, intersect_overlapping, NULL, NULL )) return NULL;
|
||||
set_region_extents( dst );
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* compute the subtraction of two regions into dst, which can be one of the source regions */
|
||||
struct region *subtract_region( struct region *dst, const struct region *src1,
|
||||
const struct region *src2 )
|
||||
{
|
||||
if (!src1->num_rects || !src2->num_rects || !EXTENTCHECK(&src1->extents, &src2->extents))
|
||||
return copy_region( dst, src1 );
|
||||
|
||||
if (!region_op( dst, src1, src2, subtract_overlapping,
|
||||
subtract_non_overlapping, NULL )) return NULL;
|
||||
set_region_extents( dst );
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* compute the union of two regions into dst, which can be one of the source regions */
|
||||
struct region *union_region( struct region *dst, const struct region *src1,
|
||||
const struct region *src2 )
|
||||
{
|
||||
if (src1 == src2) return copy_region( dst, src1 );
|
||||
if (!src1->num_rects) return copy_region( dst, src2 );
|
||||
if (!src2->num_rects) return copy_region( dst, src1 );
|
||||
|
||||
if ((src1->num_rects == 1) &&
|
||||
(src1->extents.left <= src2->extents.left) &&
|
||||
(src1->extents.top <= src2->extents.top) &&
|
||||
(src1->extents.right >= src2->extents.right) &&
|
||||
(src1->extents.bottom >= src2->extents.bottom))
|
||||
return copy_region( dst, src1 );
|
||||
|
||||
if ((src2->num_rects == 1) &&
|
||||
(src2->extents.left <= src1->extents.left) &&
|
||||
(src2->extents.top <= src1->extents.top) &&
|
||||
(src2->extents.right >= src1->extents.right) &&
|
||||
(src2->extents.bottom >= src1->extents.bottom))
|
||||
return copy_region( dst, src2 );
|
||||
|
||||
if (!region_op( dst, src1, src2, union_overlapping,
|
||||
union_non_overlapping, union_non_overlapping )) return NULL;
|
||||
|
||||
dst->extents.left = min(src1->extents.left, src2->extents.left);
|
||||
dst->extents.top = min(src1->extents.top, src2->extents.top);
|
||||
dst->extents.right = max(src1->extents.right, src2->extents.right);
|
||||
dst->extents.bottom = max(src1->extents.bottom, src2->extents.bottom);
|
||||
return dst;
|
||||
}
|
|
@ -251,6 +251,7 @@ DECL_HANDLER(get_window_text);
|
|||
DECL_HANDLER(set_window_text);
|
||||
DECL_HANDLER(inc_window_paint_count);
|
||||
DECL_HANDLER(get_windows_offset);
|
||||
DECL_HANDLER(get_visible_region);
|
||||
DECL_HANDLER(set_window_property);
|
||||
DECL_HANDLER(remove_window_property);
|
||||
DECL_HANDLER(get_window_property);
|
||||
|
@ -430,6 +431,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_set_window_text,
|
||||
(req_handler)req_inc_window_paint_count,
|
||||
(req_handler)req_get_windows_offset,
|
||||
(req_handler)req_get_visible_region,
|
||||
(req_handler)req_set_window_property,
|
||||
(req_handler)req_remove_window_property,
|
||||
(req_handler)req_get_window_property,
|
||||
|
|
|
@ -375,6 +375,21 @@ static void dump_varargs_input_records( size_t size )
|
|||
remove_data( size );
|
||||
}
|
||||
|
||||
static void dump_varargs_rectangles( size_t size )
|
||||
{
|
||||
const rectangle_t *rect = cur_data;
|
||||
size_t len = size / sizeof(*rect);
|
||||
|
||||
fputc( '{', stderr );
|
||||
while (len > 0)
|
||||
{
|
||||
dump_rectangle( rect++ );
|
||||
if (--len) fputc( ',', stderr );
|
||||
}
|
||||
fputc( '}', stderr );
|
||||
remove_data( size );
|
||||
}
|
||||
|
||||
static void dump_varargs_properties( size_t size )
|
||||
{
|
||||
const property_data_t *prop = cur_data;
|
||||
|
@ -2161,6 +2176,20 @@ static void dump_get_windows_offset_reply( const struct get_windows_offset_reply
|
|||
fprintf( stderr, " y=%d", req->y );
|
||||
}
|
||||
|
||||
static void dump_get_visible_region_request( const struct get_visible_region_request *req )
|
||||
{
|
||||
fprintf( stderr, " window=%p,", req->window );
|
||||
fprintf( stderr, " top_win=%p,", req->top_win );
|
||||
fprintf( stderr, " flags=%08x", req->flags );
|
||||
}
|
||||
|
||||
static void dump_get_visible_region_reply( const struct get_visible_region_reply *req )
|
||||
{
|
||||
fprintf( stderr, " total_size=%d,", req->total_size );
|
||||
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 );
|
||||
|
@ -2630,6 +2659,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_set_window_text_request,
|
||||
(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_set_window_property_request,
|
||||
(dump_func)dump_remove_window_property_request,
|
||||
(dump_func)dump_get_window_property_request,
|
||||
|
@ -2806,6 +2836,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)0,
|
||||
(dump_func)0,
|
||||
(dump_func)dump_get_windows_offset_reply,
|
||||
(dump_func)dump_get_visible_region_reply,
|
||||
(dump_func)0,
|
||||
(dump_func)dump_remove_window_property_reply,
|
||||
(dump_func)dump_get_window_property_reply,
|
||||
|
@ -2982,6 +3013,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"set_window_text",
|
||||
"inc_window_paint_count",
|
||||
"get_windows_offset",
|
||||
"get_visible_region",
|
||||
"set_window_property",
|
||||
"remove_window_property",
|
||||
"get_window_property",
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "wine/server_protocol.h"
|
||||
|
||||
struct thread;
|
||||
struct region;
|
||||
struct window;
|
||||
struct msg_queue;
|
||||
struct hook_table;
|
||||
|
@ -64,6 +65,25 @@ extern int attach_thread_input( struct thread *thread_from, struct thread *threa
|
|||
extern void post_message( user_handle_t win, unsigned int message,
|
||||
unsigned int wparam, unsigned int lparam );
|
||||
|
||||
/* region functions */
|
||||
|
||||
extern struct region *create_region( const rectangle_t *rects, unsigned int nb_rects );
|
||||
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 );
|
||||
extern rectangle_t *get_region_data_and_free( struct region *region, size_t *total_size );
|
||||
extern int is_region_empty( const struct region *region );
|
||||
extern void get_region_extents( const struct region *region, rectangle_t *rect );
|
||||
extern void offset_region( struct region *region, int x, int y );
|
||||
extern struct region *copy_region( struct region *dst, const struct region *src );
|
||||
extern struct region *intersect_region( struct region *dst, const struct region *src1,
|
||||
const struct region *src2 );
|
||||
extern struct region *subtract_region( struct region *dst, const struct region *src1,
|
||||
const struct region *src2 );
|
||||
extern struct region *union_region( struct region *dst, const struct region *src1,
|
||||
const struct region *src2 );
|
||||
static inline struct region *create_empty_region(void) { return create_region( NULL, 0 ); }
|
||||
|
||||
/* window functions */
|
||||
|
||||
extern void destroy_thread_windows( struct thread *thread );
|
||||
|
|
126
server/window.c
126
server/window.c
|
@ -463,6 +463,114 @@ user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *threa
|
|||
}
|
||||
|
||||
|
||||
/* 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 )
|
||||
{
|
||||
struct window *ptr;
|
||||
struct region *tmp = create_empty_region();
|
||||
|
||||
if (!tmp) return NULL;
|
||||
for (ptr = parent->first_child; ptr && ptr != last; ptr = ptr->next)
|
||||
{
|
||||
if (!(ptr->style & WS_VISIBLE)) continue;
|
||||
if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
|
||||
set_region_rect( tmp, &ptr->window_rect );
|
||||
offset_region( tmp, offset_x, offset_y );
|
||||
if (!(region = subtract_region( region, region, tmp ))) break;
|
||||
if (is_region_empty( region )) break;
|
||||
}
|
||||
free_region( tmp );
|
||||
return region;
|
||||
}
|
||||
|
||||
|
||||
/* compute the visible region of a window */
|
||||
static struct region *get_visible_region( struct window *win, struct window *top,
|
||||
unsigned int flags )
|
||||
{
|
||||
struct region *tmp, *region;
|
||||
struct window *ptr;
|
||||
rectangle_t rect;
|
||||
int offset_x, offset_y;
|
||||
|
||||
if (!(region = create_empty_region())) return NULL;
|
||||
|
||||
/* first check if all ancestors are visible */
|
||||
|
||||
for (ptr = win; ptr != top_window; ptr = ptr->parent)
|
||||
if (!(ptr->style & WS_VISIBLE)) return region; /* empty region */
|
||||
|
||||
/* retrieve window rectangle in parent coordinates */
|
||||
|
||||
if ((flags & DCX_PARENTCLIP) && win->parent)
|
||||
{
|
||||
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;
|
||||
offset_x = win->client_rect.left;
|
||||
offset_y = win->client_rect.top;
|
||||
}
|
||||
else if (flags & DCX_WINDOW)
|
||||
{
|
||||
rect = win->window_rect;
|
||||
offset_x = win->window_rect.left;
|
||||
offset_y = win->window_rect.top;
|
||||
}
|
||||
else
|
||||
{
|
||||
rect = win->client_rect;
|
||||
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 */
|
||||
|
||||
if (flags & DCX_CLIPCHILDREN)
|
||||
{
|
||||
if (!clip_children( win, NULL, region,
|
||||
offset_x - win->client_rect.left,
|
||||
offset_y - win->client_rect.top )) goto error;
|
||||
}
|
||||
|
||||
/* clip siblings of ancestors */
|
||||
|
||||
if (top && top != win && (tmp = create_empty_region()) != NULL)
|
||||
{
|
||||
offset_region( region, offset_x, offset_y ); /* make it relative to parent */
|
||||
while (win->parent)
|
||||
{
|
||||
if (win->style & WS_CLIPSIBLINGS)
|
||||
{
|
||||
if (!clip_children( win->parent, win, region, 0, 0 )) goto error;
|
||||
if (is_region_empty( region )) break;
|
||||
}
|
||||
if (win == top) break;
|
||||
/* clip to parent client area */
|
||||
win = win->parent;
|
||||
offset_x += win->client_rect.left;
|
||||
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 (is_region_empty( region )) break;
|
||||
}
|
||||
offset_region( region, -offset_x, -offset_y ); /* make it relative to target window again */
|
||||
free_region( tmp );
|
||||
}
|
||||
return region;
|
||||
|
||||
error:
|
||||
free_region( region );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* get the window class of a window */
|
||||
struct window_class* get_window_class( user_handle_t window )
|
||||
{
|
||||
|
@ -825,6 +933,24 @@ DECL_HANDLER(get_windows_offset)
|
|||
}
|
||||
|
||||
|
||||
/* get the visible region of a window */
|
||||
DECL_HANDLER(get_visible_region)
|
||||
{
|
||||
struct region *region;
|
||||
struct window *win = get_window( req->window );
|
||||
struct window *top = NULL;
|
||||
|
||||
if (!win) return;
|
||||
if (req->top_win && !(top = get_window( req->top_win ))) return;
|
||||
|
||||
if ((region = get_visible_region( win, top, req->flags )))
|
||||
{
|
||||
rectangle_t *data = get_region_data_and_free( region, &reply->total_size );
|
||||
set_reply_data_ptr( data, min(reply->total_size,get_reply_max_size()) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* set a window property */
|
||||
DECL_HANDLER(set_window_property)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue