Don't rely on X to expose windows covered by a sibling, do it

manually.
This commit is contained in:
Alexandre Julliard 2001-06-22 03:42:27 +00:00
parent 624f14e776
commit f4b14106f7
2 changed files with 211 additions and 46 deletions

View File

@ -168,6 +168,206 @@ static HRGN get_visible_region( WND *win, WND *top, UINT flags, int mode )
}
/***********************************************************************
* get_covered_region
*
* Compute the portion of 'rgn' that is covered by non-clipped siblings.
* This is the area that is covered from X point of view, but may still need
* to be exposed.
* 'rgn' must be relative to the client area of the parent of 'win'.
*/
static int get_covered_region( WND *win, HRGN rgn )
{
HRGN tmp;
int ret;
WND *ptr = win;
int xoffset = 0, yoffset = 0;
tmp = CreateRectRgn( 0, 0, 0, 0 );
CombineRgn( tmp, rgn, 0, RGN_COPY );
/* to make things easier we actually build the uncovered
* area by removing all siblings and then we subtract that
* from the total region to get the covered area */
for (;;)
{
if (!(ptr->dwStyle & WS_CLIPSIBLINGS))
{
if (clip_children( ptr->parent, ptr, tmp, FALSE ) == NULLREGION) break;
}
if (!(ptr = ptr->parent)) break;
OffsetRgn( tmp, ptr->rectClient.left, ptr->rectClient.top );
xoffset += ptr->rectClient.left;
yoffset += ptr->rectClient.top;
}
/* make it relative to the target window again */
OffsetRgn( tmp, -xoffset, -yoffset );
/* now subtract the computed region from the original one */
ret = CombineRgn( rgn, rgn, tmp, RGN_DIFF );
DeleteObject( tmp );
return ret;
}
/***********************************************************************
* expose_window
*
* Expose a region of a given window.
*/
static void expose_window( WND *win, RECT *rect, HRGN rgn, int flags )
{
WND *ptr, *top;
int xoffset = 0, yoffset = 0;
/* find the top most parent that doesn't clip children or siblings and
* invalidate the area on its parent, including all children */
top = NULL;
for (ptr = win; ptr && ptr->parent; ptr = ptr->parent)
{
if (!(ptr->dwStyle & WS_CLIPSIBLINGS)) top = ptr;
if (!(ptr->parent->dwStyle & WS_CLIPCHILDREN)) top = ptr;
}
if (top)
{
if (top->parent && top->parent->hwndSelf != GetDesktopWindow()) top = top->parent;
flags &= ~RDW_FRAME; /* parent will invalidate children frame anyway */
flags |= RDW_ALLCHILDREN;
}
else top = win;
/* make coords relative to top */
for (ptr = win; ptr != top; ptr = ptr->parent)
{
xoffset += ptr->rectClient.left;
yoffset += ptr->rectClient.top;
}
if (rect)
{
OffsetRect( rect, xoffset, yoffset );
RedrawWindow( top->hwndSelf, rect, 0, flags );
}
else
{
OffsetRgn( rgn, xoffset, yoffset );
RedrawWindow( top->hwndSelf, NULL, rgn, flags );
}
}
/***********************************************************************
* expose_covered_parent_area
*
* Expose the parent area that has been uncovered by moving/hiding a
* given window, but that is still covered by other siblings (the area
* not covered by siblings will be exposed automatically by X).
*/
static void expose_covered_parent_area( WND *win, const RECT *old_rect )
{
int ret = SIMPLEREGION;
HRGN hrgn = CreateRectRgnIndirect( old_rect );
if (win->dwStyle & WS_VISIBLE)
{
HRGN tmp = CreateRectRgnIndirect( &win->rectWindow );
ret = CombineRgn( hrgn, hrgn, tmp, RGN_DIFF );
DeleteObject( tmp );
}
if (ret != NULLREGION)
{
if (get_covered_region( win, hrgn ) != NULLREGION)
expose_window( win->parent, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
}
DeleteObject( hrgn );
}
/***********************************************************************
* expose_covered_window_area
*
* Expose the area of a window that is covered by other siblings.
*/
static void expose_covered_window_area( WND *win, const RECT *old_client_rect, BOOL frame )
{
HRGN hrgn;
int ret = SIMPLEREGION;
if (frame)
hrgn = CreateRectRgn( win->rectWindow.left - win->rectClient.left,
win->rectWindow.top - win->rectClient.top,
win->rectWindow.right - win->rectWindow.left,
win->rectWindow.bottom - win->rectWindow.top );
else
hrgn = CreateRectRgn( 0, 0,
win->rectClient.right - win->rectClient.left,
win->rectClient.bottom - win->rectClient.top );
/* if the client rect didn't move we don't need to repaint it all */
if (old_client_rect->left == win->rectClient.left &&
old_client_rect->top == win->rectClient.top)
{
RECT rc;
if (IntersectRect( &rc, old_client_rect, &win->rectClient ))
{
HRGN tmp;
/* subtract the unchanged client area from the region to expose */
OffsetRect( &rc, -win->rectClient.left, -win->rectClient.top );
if ((tmp = CreateRectRgnIndirect( &rc )))
{
ret = CombineRgn( hrgn, hrgn, tmp, RGN_DIFF );
DeleteObject( tmp );
}
}
}
if (ret != NULLREGION)
{
if (get_covered_region( win, hrgn ) != NULLREGION)
expose_window( win, NULL, hrgn,
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
}
DeleteObject( hrgn );
}
/***********************************************************************
* X11DRV_Expose
*/
void X11DRV_Expose( HWND hwnd, XExposeEvent *event )
{
RECT rect;
struct x11drv_win_data *data;
int flags = RDW_INVALIDATE | RDW_ERASE;
WND *win;
TRACE( "win %x (%lx) %d,%d %dx%d\n",
hwnd, event->window, event->x, event->y, event->width, event->height );
rect.left = event->x;
rect.top = event->y;
rect.right = rect.left + event->width;
rect.bottom = rect.top + event->height;
if (!(win = WIN_FindWndPtr(hwnd))) return;
data = win->pDriverData;
if (event->window != data->client_window) /* whole window or icon window */
{
flags |= RDW_FRAME;
/* make position relative to client area instead of window */
OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top );
}
expose_window( win, &rect, 0, flags );
WIN_ReleaseWndPtr( win );
}
/***********************************************************************
* X11DRV_GetDC (X11DRV.@)
*
@ -572,6 +772,7 @@ BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
{
/* if we moved the client area, repaint the whole non-client window */
XClearArea( display, get_whole_window(wndPtr), 0, 0, 0, 0, True );
winpos->flags |= SWP_FRAMECHANGED;
}
if (winpos->flags & SWP_SHOWWINDOW)
{
@ -593,6 +794,14 @@ BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
wine_tsx11_unlock();
}
/* manually expose the areas that X won't expose because they are still covered by something */
if (!(winpos->flags & SWP_SHOWWINDOW))
expose_covered_parent_area( wndPtr, &oldWindowRect );
if (wndPtr->dwStyle & WS_VISIBLE)
expose_covered_window_area( wndPtr, &oldClientRect, winpos->flags & SWP_FRAMECHANGED );
WIN_ReleaseWndPtr(wndPtr);
if (wvrFlags & WVR_REDRAW) RedrawWindow( winpos->hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE );

View File

@ -96,13 +96,13 @@ static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event );
static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event );
static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
static void EVENT_Expose( HWND hWnd, XExposeEvent *event );
static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
static void EVENT_PropertyNotify( XPropertyEvent *event );
static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
static void EVENT_MappingNotify( XMappingEvent *event );
extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
@ -319,7 +319,7 @@ static void EVENT_ProcessEvent( XEvent *event )
break;
case Expose:
EVENT_Expose( hWnd, &event->xexpose );
X11DRV_Expose( hWnd, &event->xexpose );
break;
case ConfigureNotify:
@ -388,50 +388,6 @@ WORD X11DRV_EVENT_XStateToKeyState( int state )
}
/***********************************************************************
* EVENT_Expose
*/
static void EVENT_Expose( HWND hwnd, XExposeEvent *event )
{
RECT rect;
struct x11drv_win_data *data;
int flags = RDW_INVALIDATE | RDW_ERASE;
WND *win;
TRACE( "win %x (%lx) %d,%d %dx%d\n",
hwnd, event->window, event->x, event->y, event->width, event->height );
rect.left = event->x;
rect.top = event->y;
rect.right = rect.left + event->width;
rect.bottom = rect.top + event->height;
if (!(win = WIN_FindWndPtr(hwnd))) return;
data = win->pDriverData;
if (event->window != data->client_window) /* whole window or icon window */
{
flags |= RDW_FRAME;
/* make position relative to client area instead of window */
OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top );
}
/* find the top level parent that doesn't clip children and invalidate the area */
/* on the parent (which will invalidate all the children too) */
while (win->parent && win->parent->hwndSelf != GetDesktopWindow() &&
!(win->parent->dwStyle & WS_CLIPCHILDREN))
{
OffsetRect( &rect, win->rectClient.left, win->rectClient.top );
WIN_UpdateWndPtr( &win, win->parent );
flags &= ~RDW_FRAME; /* parent will invalidate children frame anyway */
flags |= RDW_ALLCHILDREN; /* force invalidating all children of siblings */
}
hwnd = win->hwndSelf;
WIN_ReleaseWndPtr(win);
RedrawWindow( hwnd, &rect, 0, flags );
}
/* get the coordinates of a mouse event */
static void get_coords( HWND *hwnd, Window window, int x, int y, POINT *pt )
{