diff --git a/dlls/ttydrv/wnd.c b/dlls/ttydrv/wnd.c index 714fff3d6dc..eedb48d23f5 100644 --- a/dlls/ttydrv/wnd.c +++ b/dlls/ttydrv/wnd.c @@ -38,11 +38,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(ttydrv); (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW) /*********************************************************************** - * set_window_rectangles + * set_window_pos * - * Set the window and client rectangles. + * Set a window position and Z order. */ -static void set_window_rectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient ) +static void set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow, + const RECT *rectClient, UINT swp_flags, UINT wvr_flags ) { WND *win = WIN_GetPtr( hwnd ); BOOL ret; @@ -53,9 +54,13 @@ static void set_window_rectangles( HWND hwnd, const RECT *rectWindow, const RECT if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd ); return; } - SERVER_START_REQ( set_window_rectangles ) + SERVER_START_REQ( set_window_pos ) { req->handle = hwnd; + req->top_win = 0; + req->previous = insert_after; + req->flags = swp_flags; + req->redraw_flags = wvr_flags; req->window.left = rectWindow->left; req->window.top = rectWindow->top; req->window.right = rectWindow->right; @@ -95,7 +100,7 @@ BOOL TTYDRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) /* initialize the dimensions before sending WM_GETMINMAXINFO */ SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy ); - set_window_rectangles( hwnd, &rect, &rect ); + set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER, 0 ); if (!wndPtr->parent) /* desktop window */ { @@ -483,6 +488,7 @@ BOOL TTYDRV_SetWindowPos( WINDOWPOS *winpos ) { WND *wndPtr; RECT newWindowRect, newClientRect; + UINT wvrFlags = 0; BOOL retvalue; HWND hwndActive = GetForegroundWindow(); @@ -620,7 +626,7 @@ BOOL TTYDRV_SetWindowPos( WINDOWPOS *winpos ) params.lppos = &winposCopy; winposCopy = *winpos; - SendMessageW( winpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)¶ms ); + wvrFlags = SendMessageW( winpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)¶ms ); TRACE( "%ld,%ld-%ld,%ld\n", params.rgrc[0].left, params.rgrc[0].top, params.rgrc[0].right, params.rgrc[0].bottom ); @@ -643,15 +649,10 @@ BOOL TTYDRV_SetWindowPos( WINDOWPOS *winpos ) winpos->flags &= ~SWP_NOCLIENTSIZE; } - if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter) - { - HWND parent = GetAncestor( winpos->hwnd, GA_PARENT ); - if (parent) WIN_LinkWindow( winpos->hwnd, parent, winpos->hwndInsertAfter ); - } - /* FIXME: actually do something with WVR_VALIDRECTS */ - set_window_rectangles( winpos->hwnd, &newWindowRect, &newClientRect ); + set_window_pos( winpos->hwnd, winpos->hwndInsertAfter, + &newWindowRect, &newClientRect, winpos->flags, wvrFlags ); if( winpos->flags & SWP_SHOWWINDOW ) WIN_SetStyle( winpos->hwnd, wndPtr->dwStyle | WS_VISIBLE ); diff --git a/dlls/user/painting.c b/dlls/user/painting.c index 314aa1c3921..de22b6f5412 100644 --- a/dlls/user/painting.c +++ b/dlls/user/painting.c @@ -1,7 +1,7 @@ /* * Window painting functions * - * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard + * Copyright 1993, 1994, 1995, 2001, 2004 Alexandre Julliard * Copyright 1999 Alex Korobka * * This library is free software; you can redistribute it and/or @@ -28,7 +28,8 @@ #include "windef.h" #include "winbase.h" #include "wingdi.h" -#include "wine/winuser16.h" +#include "ntstatus.h" +#include "winuser.h" #include "wine/server.h" #include "win.h" #include "dce.h" @@ -36,37 +37,43 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); -/*********************************************************************** - * add_paint_count - * - * Add an increment (normally 1 or -1) to the current paint count of a window. - */ -static void add_paint_count( HWND hwnd, int incr ) -{ - SERVER_START_REQ( inc_window_paint_count ) - { - req->handle = hwnd; - req->incr = incr; - wine_server_call( req ); - } - SERVER_END_REQ; -} - /*********************************************************************** - * copy_rgn - * - * copy a region, doing the right thing if the source region is 0 or 1 + * dump_rdw_flags */ -static HRGN copy_rgn( HRGN hSrc ) +static void dump_rdw_flags(UINT flags) { - if (hSrc > (HRGN)1) - { - HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 ); - CombineRgn( hrgn, hSrc, 0, RGN_COPY ); - return hrgn; - } - return hSrc; + TRACE("flags:"); + if (flags & RDW_INVALIDATE) TRACE(" RDW_INVALIDATE"); + if (flags & RDW_INTERNALPAINT) TRACE(" RDW_INTERNALPAINT"); + if (flags & RDW_ERASE) TRACE(" RDW_ERASE"); + if (flags & RDW_VALIDATE) TRACE(" RDW_VALIDATE"); + if (flags & RDW_NOINTERNALPAINT) TRACE(" RDW_NOINTERNALPAINT"); + if (flags & RDW_NOERASE) TRACE(" RDW_NOERASE"); + if (flags & RDW_NOCHILDREN) TRACE(" RDW_NOCHILDREN"); + if (flags & RDW_ALLCHILDREN) TRACE(" RDW_ALLCHILDREN"); + if (flags & RDW_UPDATENOW) TRACE(" RDW_UPDATENOW"); + if (flags & RDW_ERASENOW) TRACE(" RDW_ERASENOW"); + if (flags & RDW_FRAME) TRACE(" RDW_FRAME"); + if (flags & RDW_NOFRAME) TRACE(" RDW_NOFRAME"); + +#define RDW_FLAGS \ + (RDW_INVALIDATE | \ + RDW_INTERNALPAINT | \ + RDW_ERASE | \ + RDW_VALIDATE | \ + RDW_NOINTERNALPAINT | \ + RDW_NOERASE | \ + RDW_NOCHILDREN | \ + RDW_ALLCHILDREN | \ + RDW_UPDATENOW | \ + RDW_ERASENOW | \ + RDW_FRAME | \ + RDW_NOFRAME) + + if (flags & ~RDW_FLAGS) TRACE(" %04x", flags & ~RDW_FLAGS); + TRACE("\n"); +#undef RDW_FLAGS } @@ -75,95 +82,267 @@ static HRGN copy_rgn( HRGN hSrc ) * * Return update region for a window. */ -static HRGN get_update_region( WND *win ) +static HRGN get_update_region( HWND hwnd, UINT *flags, HWND *child ) { - if (!win->hrgnUpdate) return CreateRectRgn( 0, 0, 0, 0 ); - if (win->hrgnUpdate > (HRGN)1) return copy_rgn( win->hrgnUpdate ); - return CreateRectRgn( 0, 0, win->rectWindow.right - win->rectWindow.left, - win->rectWindow.bottom - win->rectWindow.top ); + HRGN hrgn = 0; + NTSTATUS status; + RGNDATA *data; + size_t size = 256; + + do + { + if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ))) + { + SetLastError( ERROR_OUTOFMEMORY ); + return 0; + } + + SERVER_START_REQ( get_update_region ) + { + req->window = hwnd; + req->flags = *flags; + wine_server_set_reply( req, data->Buffer, size ); + if (!(status = wine_server_call( req ))) + { + 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; + hrgn = ExtCreateRegion( NULL, size, data ); + if (child) *child = reply->child; + *flags = reply->flags; + } + else size = reply->total_size; + } + SERVER_END_REQ; + HeapFree( GetProcessHeap(), 0, data ); + } while (status == STATUS_BUFFER_OVERFLOW); + + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return hrgn; } /*********************************************************************** - * get_update_regions + * get_update_flags * - * Return update regions for the whole window and for the client area. + * Get only the update flags, not the update region. */ -static void get_update_regions( WND *win, HRGN *whole_rgn, HRGN *client_rgn ) +static BOOL get_update_flags( HWND hwnd, HWND *child, UINT *flags ) { - if (win->hrgnUpdate > (HRGN)1) + BOOL ret; + + SERVER_START_REQ( get_update_region ) + { + req->window = hwnd; + req->flags = *flags | UPDATE_NOREGION; + if ((ret = !wine_server_call_err( req ))) + { + if (child) *child = reply->child; + *flags = reply->flags; + } + } + SERVER_END_REQ; + return ret; +} + + +/*********************************************************************** + * redraw_window_rects + * + * Redraw part of a window. + */ +static BOOL redraw_window_rects( HWND hwnd, UINT flags, const RECT *rects, UINT count ) +{ + BOOL ret; + + SERVER_START_REQ( redraw_window ) + { + req->window = hwnd; + req->flags = flags; + wine_server_add_data( req, rects, count * sizeof(RECT) ); + ret = !wine_server_call_err( req ); + } + SERVER_END_REQ; + return ret; +} + + +/*********************************************************************** + * send_ncpaint + * + * Send a WM_NCPAINT message if needed, and return the resulting update region. + * Helper for erase_now and BeginPaint. + */ +static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) +{ + HRGN whole_rgn = get_update_region( hwnd, flags, child ); + HRGN client_rgn = 0; + + if (child) hwnd = *child; + + if (whole_rgn) { RECT client, update; + INT type; + WND *win = WIN_GetPtr( hwnd ); + + if (!win || win == WND_OTHER_PROCESS) + { + DeleteObject( whole_rgn ); + return 0; + } /* check if update rgn overlaps with nonclient area */ - GetRgnBox( win->hrgnUpdate, &update ); + type = GetRgnBox( whole_rgn, &update ); client = win->rectClient; OffsetRect( &client, -win->rectWindow.left, -win->rectWindow.top ); - if (update.left < client.left || update.top < client.top || + if ((*flags & UPDATE_NONCLIENT) || + update.left < client.left || update.top < client.top || update.right > client.right || update.bottom > client.bottom) { - *whole_rgn = copy_rgn( win->hrgnUpdate ); - *client_rgn = CreateRectRgnIndirect( &client ); - if (CombineRgn( *client_rgn, *client_rgn, win->hrgnUpdate, RGN_AND ) == NULLREGION) + client_rgn = CreateRectRgnIndirect( &client ); + CombineRgn( client_rgn, client_rgn, whole_rgn, RGN_AND ); + + /* check if update rgn contains complete nonclient area */ + if (type == SIMPLEREGION && update.left == 0 && update.top == 0 && + update.right == win->rectWindow.right - win->rectWindow.left && + update.bottom == win->rectWindow.bottom - win->rectWindow.top) { - DeleteObject( *client_rgn ); - *client_rgn = 0; + DeleteObject( whole_rgn ); + whole_rgn = (HRGN)1; } } else { - *whole_rgn = 0; - *client_rgn = copy_rgn( win->hrgnUpdate ); + client_rgn = whole_rgn; + whole_rgn = 0; + } + /* map client region to client coordinates */ + OffsetRgn( client_rgn, win->rectWindow.left - win->rectClient.left, + win->rectWindow.top - win->rectClient.top ); + WIN_ReleasePtr( win ); + + if (whole_rgn) /* NOTE: WM_NCPAINT allows wParam to be 1 */ + { + if (*flags & UPDATE_NONCLIENT) SendMessageW( hwnd, WM_NCPAINT, (WPARAM)whole_rgn, 0 ); + if (whole_rgn > (HRGN)1) DeleteObject( whole_rgn ); } } - else + return client_rgn; +} + + +/*********************************************************************** + * send_erase + * + * Send a WM_ERASEBKGND message if needed, and optionally return the DC for painting. + * If a DC is requested, the region is selected into it. + * Helper for erase_now and BeginPaint. + */ +static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, + RECT *clip_rect, HDC *hdc_ret ) +{ + BOOL need_erase = FALSE; + HDC hdc; + + if (hdc_ret || (flags & UPDATE_ERASE)) { - *client_rgn = *whole_rgn = win->hrgnUpdate; /* 0 or 1 */ + UINT dcx_flags = DCX_INTERSECTRGN | DCX_WINDOWPAINT | DCX_USESTYLE; + if (IsIconic(hwnd)) dcx_flags |= DCX_WINDOW; + + if ((hdc = GetDCEx( hwnd, client_rgn, dcx_flags ))) + { + INT type = GetClipBox( hdc, clip_rect ); + + if (flags & UPDATE_ERASE) + { + /* don't erase if the clip box is empty */ + if (type != NULLREGION) + need_erase = !SendMessageW( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 ); + } + if (!hdc_ret) + { + if (need_erase) /* FIXME: mark it as needing erase again */ + RedrawWindow( hwnd, NULL, client_rgn, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN ); + ReleaseDC( hwnd, hdc ); + } + } + + if (hdc_ret) *hdc_ret = hdc; + } + return need_erase; +} + + +/*********************************************************************** + * erase_now + * + * Implementation of RDW_ERASENOW behavior. + */ +void erase_now( HWND hwnd, UINT rdw_flags ) +{ + HWND child; + HRGN hrgn; + + /* loop while we find a child to repaint */ + for (;;) + { + RECT rect; + UINT flags = UPDATE_NONCLIENT | UPDATE_ERASE; + + if (rdw_flags & RDW_NOCHILDREN) flags |= UPDATE_NOCHILDREN; + else if (rdw_flags & RDW_ALLCHILDREN) flags |= UPDATE_ALLCHILDREN; + + if (!(hrgn = send_ncpaint( hwnd, &child, &flags ))) break; + send_erase( child, flags, hrgn, &rect, NULL ); + DeleteObject( hrgn ); + + if (!flags) break; /* nothing more to do */ + if (rdw_flags & RDW_NOCHILDREN) break; } } /*********************************************************************** - * begin_ncpaint + * update_now + * + * Implementation of RDW_UPDATENOW behavior. + * + * FIXME: Windows uses WM_SYNCPAINT to cut down the number of intertask + * SendMessage() calls. This is a comment inside DefWindowProc() source + * from 16-bit SDK: + * + * This message avoids lots of inter-app message traffic + * by switching to the other task and continuing the + * recursion there. + * + * wParam = flags + * LOWORD(lParam) = hrgnClip + * HIWORD(lParam) = hwndSkip (not used; always NULL) * - * Send a WM_NCPAINT message from inside BeginPaint(). - * Returns update region cropped to client rectangle (and in client coords), - * and clears window update region and internal paint flag. */ -static HRGN begin_ncpaint( HWND hwnd ) +void update_now( HWND hwnd, UINT rdw_flags ) { - HRGN whole_rgn, client_rgn; - WND *wnd = WIN_GetPtr( hwnd ); + HWND child; - if (!wnd || wnd == WND_OTHER_PROCESS) return 0; - - TRACE("hwnd %p [%p] ncf %i\n", - hwnd, wnd->hrgnUpdate, wnd->flags & WIN_NEEDS_NCPAINT); - - get_update_regions( wnd, &whole_rgn, &client_rgn ); - - if (whole_rgn) /* NOTE: WM_NCPAINT allows wParam to be 1 */ + /* loop while we find a child to repaint */ + for (;;) { - WIN_ReleasePtr( wnd ); - SendMessageA( hwnd, WM_NCPAINT, (WPARAM)whole_rgn, 0 ); - if (whole_rgn > (HRGN)1) DeleteObject( whole_rgn ); - /* make sure the window still exists before continuing */ - if (!(wnd = WIN_GetPtr( hwnd )) || wnd == WND_OTHER_PROCESS) - { - if (client_rgn > (HRGN)1) DeleteObject( client_rgn ); - return 0; - } - } + UINT flags = UPDATE_PAINT | UPDATE_INTERNALPAINT; - if (wnd->hrgnUpdate || (wnd->flags & WIN_INTERNAL_PAINT)) add_paint_count( hwnd, -1 ); - if (wnd->hrgnUpdate > (HRGN)1) DeleteObject( wnd->hrgnUpdate ); - wnd->hrgnUpdate = 0; - wnd->flags &= ~(WIN_INTERNAL_PAINT | WIN_NEEDS_NCPAINT); - if (client_rgn > (HRGN)1) OffsetRgn( client_rgn, wnd->rectWindow.left - wnd->rectClient.left, - wnd->rectWindow.top - wnd->rectClient.top ); - WIN_ReleasePtr( wnd ); - return client_rgn; + if (rdw_flags & RDW_NOCHILDREN) flags |= UPDATE_NOCHILDREN; + else if (rdw_flags & RDW_ALLCHILDREN) flags |= UPDATE_ALLCHILDREN; + + if (!get_update_flags( hwnd, &child, &flags )) break; + if (!flags) break; /* nothing more to do */ + + SendMessageW( child, WM_PAINT, 0, 0 ); + + if (rdw_flags & RDW_NOCHILDREN) break; + } } @@ -172,12 +351,9 @@ static HRGN begin_ncpaint( HWND hwnd ) */ HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps ) { - INT dcx_flags; - BOOL bIcon; - HRGN hrgnUpdate; - RECT clipRect, clientRect; HWND full_handle; - WND *wndPtr; + HRGN hrgn; + UINT flags = UPDATE_NONCLIENT | UPDATE_ERASE | UPDATE_PAINT | UPDATE_INTERNALPAINT | UPDATE_NOCHILDREN; if (!lps) return 0; @@ -189,68 +365,12 @@ HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps ) } hwnd = full_handle; - /* send WM_NCPAINT and retrieve update region */ - hrgnUpdate = begin_ncpaint( hwnd ); - if (!hrgnUpdate && !IsWindow( hwnd )) return 0; - HideCaret( hwnd ); - bIcon = (IsIconic(hwnd) && GetClassLongA(hwnd, GCL_HICON)); + if (!(hrgn = send_ncpaint( hwnd, NULL, &flags ))) return 0; - dcx_flags = DCX_INTERSECTRGN | DCX_WINDOWPAINT | DCX_USESTYLE; - if (bIcon) dcx_flags |= DCX_WINDOW; - - if (GetClassLongA( hwnd, GCL_STYLE ) & CS_PARENTDC) - { - /* Don't clip the output to the update region for CS_PARENTDC window */ - if (hrgnUpdate > (HRGN)1) DeleteObject( hrgnUpdate ); - hrgnUpdate = 0; - dcx_flags &= ~DCX_INTERSECTRGN; - } - else - { - if (!hrgnUpdate) /* empty region, clip everything */ - { - hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 ); - } - else if (hrgnUpdate == (HRGN)1) /* whole client area, don't clip */ - { - hrgnUpdate = 0; - dcx_flags &= ~DCX_INTERSECTRGN; - } - } - lps->hdc = GetDCEx( hwnd, hrgnUpdate, dcx_flags ); - /* ReleaseDC() in EndPaint() will delete the region */ - - if (!lps->hdc) - { - WARN("GetDCEx() failed in BeginPaint(), hwnd=%p\n", hwnd); - DeleteObject( hrgnUpdate ); - return 0; - } - - /* It is possible that the clip box is bigger than the window itself, - if CS_PARENTDC flag is set. Windows never return a paint rect bigger - than the window itself, so we need to intersect the cliprect with - the window */ - GetClientRect( hwnd, &clientRect ); - - GetClipBox( lps->hdc, &clipRect ); - LPtoDP(lps->hdc, (LPPOINT)&clipRect, 2); /* GetClipBox returns LP */ - - IntersectRect(&lps->rcPaint, &clientRect, &clipRect); - DPtoLP(lps->hdc, (LPPOINT)&lps->rcPaint, 2); /* we must return LP */ - - TRACE("hdc = %p box = (%ld,%ld - %ld,%ld)\n", - lps->hdc, lps->rcPaint.left, lps->rcPaint.top, lps->rcPaint.right, lps->rcPaint.bottom ); - - if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0; - lps->fErase = (wndPtr->flags & WIN_NEEDS_ERASEBKGND) != 0; - wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND; - WIN_ReleasePtr( wndPtr ); - - if (lps->fErase) - lps->fErase = !SendMessageA( hwnd, WM_ERASEBKGND, (WPARAM)lps->hdc, 0 ); + lps->fErase = send_erase( hwnd, flags, hrgn, &lps->rcPaint, &lps->hdc ); + if (!lps->hdc) DeleteObject( hrgn ); TRACE("hdc = %p box = (%ld,%ld - %ld,%ld), fErase = %d\n", lps->hdc, lps->rcPaint.left, lps->rcPaint.top, lps->rcPaint.right, lps->rcPaint.bottom, @@ -273,37 +393,129 @@ BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps ) } +/*********************************************************************** + * RedrawWindow (USER32.@) + */ +BOOL WINAPI RedrawWindow( HWND hwnd, const RECT *rect, HRGN hrgn, UINT flags ) +{ + BOOL ret; + + if (!hwnd) hwnd = GetDesktopWindow(); + + /* check if the window or its parents are visible/not minimized */ + + if (!WIN_IsWindowDrawable( hwnd, !(flags & RDW_FRAME) )) return TRUE; + + /* process pending events and messages before painting */ + if (flags & RDW_UPDATENOW) + MsgWaitForMultipleObjects( 0, NULL, FALSE, 0, QS_ALLINPUT ); + + if (TRACE_ON(win)) + { + if (hrgn) + { + RECT r; + GetRgnBox( hrgn, &r ); + TRACE( "%p region %p box %s ", hwnd, hrgn, wine_dbgstr_rect(&r) ); + } + else if (rect) + TRACE( "%p rect %s ", hwnd, wine_dbgstr_rect(rect) ); + else + TRACE( "%p whole window ", hwnd ); + + dump_rdw_flags(flags); + } + + if (rect && !hrgn) + { + ret = redraw_window_rects( hwnd, flags, rect, 1 ); + } + else if (!hrgn) + { + ret = redraw_window_rects( hwnd, flags, NULL, 0 ); + } + else /* need to build a list of the region rectangles */ + { + DWORD size; + RGNDATA *data = NULL; + + if (!(size = GetRegionData( hrgn, 0, NULL ))) return FALSE; + if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE; + GetRegionData( hrgn, size, data ); + ret = redraw_window_rects( hwnd, flags, (RECT *)data->Buffer, data->rdh.nCount ); + HeapFree( GetProcessHeap(), 0, data ); + } + + if (flags & RDW_UPDATENOW) update_now( hwnd, flags ); + else if (flags & RDW_ERASENOW) erase_now( hwnd, flags ); + + return ret; +} + + +/*********************************************************************** + * UpdateWindow (USER32.@) + */ +BOOL WINAPI UpdateWindow( HWND hwnd ) +{ + return RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN ); +} + + +/*********************************************************************** + * InvalidateRgn (USER32.@) + */ +BOOL WINAPI InvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) +{ + return RedrawWindow(hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) ); +} + + +/*********************************************************************** + * InvalidateRect (USER32.@) + */ +BOOL WINAPI InvalidateRect( HWND hwnd, const RECT *rect, BOOL erase ) +{ + return RedrawWindow( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) ); +} + + +/*********************************************************************** + * ValidateRgn (USER32.@) + */ +BOOL WINAPI ValidateRgn( HWND hwnd, HRGN hrgn ) +{ + return RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN ); +} + + +/*********************************************************************** + * ValidateRect (USER32.@) + */ +BOOL WINAPI ValidateRect( HWND hwnd, const RECT *rect ) +{ + return RedrawWindow( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN ); +} + + /*********************************************************************** * GetUpdateRgn (USER32.@) */ INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) { - INT retval; + INT retval = ERROR; + UINT flags = UPDATE_NOCHILDREN; HRGN update_rgn; - WND *wndPtr = WIN_GetPtr( hwnd ); - if (!wndPtr) return ERROR; - if (wndPtr == WND_OTHER_PROCESS) - { - FIXME( "not supported on other process window %p\n", hwnd ); - return ERROR; - } + if (erase) flags |= UPDATE_NONCLIENT | UPDATE_ERASE; - if ((update_rgn = get_update_region( wndPtr ))) + if ((update_rgn = send_ncpaint( hwnd, NULL, &flags ))) { - /* map coordinates and clip to client area */ - OffsetRgn( update_rgn, wndPtr->rectWindow.left - wndPtr->rectClient.left, - wndPtr->rectWindow.top - wndPtr->rectClient.top ); - SetRectRgn( hrgn, 0, 0, wndPtr->rectClient.right - wndPtr->rectClient.left, - wndPtr->rectClient.bottom - wndPtr->rectClient.top ); - retval = CombineRgn( hrgn, hrgn, update_rgn, RGN_AND ); + RECT rect; + send_erase( hwnd, flags, update_rgn, &rect, NULL ); + retval = CombineRgn( hrgn, update_rgn, 0, RGN_COPY ); DeleteObject( update_rgn ); } - else retval = ERROR; - - WIN_ReleasePtr( wndPtr ); - - if (erase) RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN ); return retval; } @@ -313,38 +525,28 @@ INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) */ BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase ) { - WND *wndPtr; - BOOL ret = FALSE; - HRGN update_rgn = CreateRectRgn( 0, 0, 0, 0 ); + HDC hdc; + RECT dummy; + UINT flags = UPDATE_NOCHILDREN; + HRGN update_rgn; - if (GetUpdateRgn( hwnd, update_rgn, erase ) == ERROR) - { - DeleteObject( update_rgn ); - return FALSE; - } + if (erase) flags |= UPDATE_NONCLIENT | UPDATE_ERASE; - if (rect) - { - GetRgnBox( update_rgn, rect ); - if (GetClassLongA(hwnd, GCL_STYLE) & CS_OWNDC) - { - HDC hdc = GetDCEx( hwnd, 0, DCX_USESTYLE ); - if (hdc) - { - if (GetMapMode(hdc) != MM_TEXT) DPtoLP(hdc, (LPPOINT)rect, 2); - ReleaseDC( hwnd, hdc ); - } - } - } - DeleteObject( update_rgn ); + if (!(update_rgn = send_ncpaint( hwnd, NULL, &flags ))) return FALSE; - wndPtr = WIN_GetPtr( hwnd ); - if (wndPtr && wndPtr != WND_OTHER_PROCESS) + GetRgnBox( update_rgn, rect ); + + send_erase( hwnd, flags, update_rgn, &dummy, &hdc ); + if (hdc) { - ret = (wndPtr->hrgnUpdate != 0); - WIN_ReleasePtr( wndPtr ); + DPtoLP( hdc, (LPPOINT)rect, 2 ); + ReleaseDC( hwnd, hdc ); } - return ret; + else DeleteObject( update_rgn ); + + /* check if we still have an update region */ + flags = UPDATE_PAINT | UPDATE_NOCHILDREN; + return (get_update_flags( hwnd, NULL, &flags ) && (flags & UPDATE_PAINT)); } diff --git a/dlls/x11drv/window.c b/dlls/x11drv/window.c index 76d2c02b701..98059fae077 100644 --- a/dlls/x11drv/window.c +++ b/dlls/x11drv/window.c @@ -740,49 +740,6 @@ void X11DRV_register_window( Display *display, HWND hwnd, struct x11drv_win_data } -/*********************************************************************** - * X11DRV_set_window_rectangles - * - * Set the window and client rectangles. - */ -void X11DRV_set_window_rectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient ) -{ - WND *win = WIN_GetPtr( hwnd ); - BOOL ret; - - if (!win) return; - if (win == WND_OTHER_PROCESS) - { - if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd ); - return; - } - SERVER_START_REQ( set_window_rectangles ) - { - req->handle = hwnd; - req->window.left = rectWindow->left; - req->window.top = rectWindow->top; - req->window.right = rectWindow->right; - req->window.bottom = rectWindow->bottom; - req->client.left = rectClient->left; - req->client.top = rectClient->top; - req->client.right = rectClient->right; - req->client.bottom = rectClient->bottom; - ret = !wine_server_call( req ); - } - SERVER_END_REQ; - if (ret) - { - win->rectWindow = *rectWindow; - win->rectClient = *rectClient; - - TRACE( "win %p window (%ld,%ld)-(%ld,%ld) client (%ld,%ld)-(%ld,%ld)\n", hwnd, - rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom, - rectClient->left, rectClient->top, rectClient->right, rectClient->bottom ); - } - WIN_ReleasePtr( win ); -} - - /********************************************************************** * create_desktop */ @@ -1013,6 +970,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) Display *display = thread_display(); WND *wndPtr; struct x11drv_win_data *data; + HWND insert_after; RECT rect; CBT_CREATEWNDA cbtc; BOOL ret = FALSE; @@ -1041,7 +999,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) /* initialize the dimensions before sending WM_GETMINMAXINFO */ SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy ); - X11DRV_set_window_rectangles( hwnd, &rect, &rect ); + X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER, 0 ); if (!wndPtr->parent) { @@ -1082,8 +1040,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE; SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy ); - X11DRV_set_window_rectangles( hwnd, &rect, &rect ); - X11DRV_sync_whole_window_position( display, wndPtr, 0 ); + X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER, 0 ); } WIN_ReleasePtr( wndPtr ); @@ -1109,9 +1066,16 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect ); if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE; + if (rect.left < wndPtr->rectWindow.left) rect.left = wndPtr->rectWindow.left; + if (rect.right > wndPtr->rectWindow.right) rect.right = wndPtr->rectWindow.right; + if (rect.top < wndPtr->rectWindow.top) rect.top = wndPtr->rectWindow.top; + if (rect.bottom > wndPtr->rectWindow.bottom) rect.bottom = wndPtr->rectWindow.bottom; if (rect.left > rect.right || rect.top > rect.bottom) rect = wndPtr->rectWindow; - X11DRV_set_window_rectangles( hwnd, &wndPtr->rectWindow, &rect ); - X11DRV_sync_client_window_position( display, wndPtr ); + + /* yes, even if the CBT hook was called with HWND_TOP */ + insert_after = ((wndPtr->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) ? HWND_BOTTOM : HWND_TOP; + + X11DRV_set_window_pos( hwnd, insert_after, &wndPtr->rectWindow, &rect, 0, 0 ); X11DRV_register_window( display, hwnd, data ); TRACE( "win %p window %ld,%ld,%ld,%ld client %ld,%ld,%ld,%ld whole %ld,%ld,%ld,%ld X client %ld,%ld,%ld,%ld xwin %x/%x\n", @@ -1125,12 +1089,6 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) data->client_rect.right, data->client_rect.bottom, (unsigned int)data->whole_window, (unsigned int)data->client_window ); - /* yes, even if the CBT hook was called with HWND_TOP */ - if ((wndPtr->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) - WIN_LinkWindow( hwnd, wndPtr->parent, HWND_BOTTOM ); - else - WIN_LinkWindow( hwnd, wndPtr->parent, HWND_TOP ); - WIN_ReleasePtr( wndPtr ); if (unicode) diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c index b0dac93d7d3..4545cac2256 100644 --- a/dlls/x11drv/winpos.c +++ b/dlls/x11drv/winpos.c @@ -86,53 +86,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(x11drv); #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */ -/*********************************************************************** - * clip_children - * - * Clip all children of a given window out of the visible region - */ -static int clip_children( HWND parent, HWND last, HRGN hrgn, int whole_window ) -{ - HWND *list; - WND *ptr; - HRGN rectRgn; - int i, x, y, ret = SIMPLEREGION; - - /* first check if we have anything to do */ - if (!(list = WIN_ListChildren( parent ))) return ret; - - if (whole_window) - { - WND *win = WIN_FindWndPtr( parent ); - x = win->rectWindow.left - win->rectClient.left; - y = win->rectWindow.top - win->rectClient.top; - WIN_ReleaseWndPtr( win ); - } - else x = y = 0; - - rectRgn = CreateRectRgn( 0, 0, 0, 0 ); - - for (i = 0; list[i] && list[i] != last; i++) - { - if (!(ptr = WIN_FindWndPtr( list[i] ))) continue; - if ((ptr->dwStyle & WS_VISIBLE) && !(ptr->dwExStyle & WS_EX_TRANSPARENT)) - { - SetRectRgn( rectRgn, ptr->rectWindow.left + x, ptr->rectWindow.top + y, - ptr->rectWindow.right + x, ptr->rectWindow.bottom + y ); - if ((ret = CombineRgn( hrgn, hrgn, rectRgn, RGN_DIFF )) == NULLREGION) - { - WIN_ReleaseWndPtr( ptr ); - break; /* no need to go on, region is empty */ - } - } - WIN_ReleaseWndPtr( ptr ); - } - DeleteObject( rectRgn ); - HeapFree( GetProcessHeap(), 0, list ); - return ret; -} - - /*********************************************************************** * get_server_visible_region */ @@ -173,46 +126,17 @@ static HRGN get_server_visible_region( HWND hwnd, HWND top, UINT flags ) /*********************************************************************** - * get_covered_region + * get_top_clipping_window * - * 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'. + * Get the top window to clip against (i.e. the top parent that has + * an associated X window). */ -static int get_covered_region( WND *win, HRGN rgn ) +static HWND get_top_clipping_window( HWND hwnd ) { - HRGN tmp; - int ret; - WND *parent, *ptr = WIN_FindWndPtr( win->hwndSelf ); - int xoffset = 0, yoffset = 0; + HWND ret = 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->hwndSelf, tmp, FALSE ) == NULLREGION) break; - } - if (!(parent = WIN_FindWndPtr( ptr->parent ))) break; - WIN_ReleaseWndPtr( ptr ); - ptr = parent; - OffsetRgn( tmp, 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( tmp, -xoffset, -yoffset ); - - /* now subtract the computed region from the original one */ - ret = CombineRgn( rgn, rgn, tmp, RGN_DIFF ); - DeleteObject( tmp ); + if (!using_wine_desktop) ret = GetAncestor( hwnd, GA_ROOT ); + if (!ret) ret = GetDesktopWindow(); return ret; } @@ -278,84 +202,6 @@ static void expose_window( HWND hwnd, RECT *rect, HRGN rgn, int 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->hwndSelf, NULL, hrgn, - RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN ); - } - - DeleteObject( hrgn ); -} - - /*********************************************************************** * X11DRV_Expose */ @@ -397,8 +243,8 @@ void X11DRV_Expose( HWND hwnd, XExposeEvent *event ) */ BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags ) { + HWND top = get_top_clipping_window( hwnd ); WND *win = WIN_GetPtr( hwnd ); - HWND top = 0; X11DRV_WND_DATA *data = win->pDriverData; struct x11drv_escape_set_drawable escape; @@ -406,9 +252,6 @@ BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags ) /* don't clip siblings if using parent clip region */ if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS; - top = GetAncestor( hwnd, GA_ROOT ); - if (!top) top = GetDesktopWindow(); - if (top != hwnd) { /* find the top most parent that doesn't clip siblings */ @@ -543,6 +386,14 @@ static BOOL SWP_DoWinPosChanging( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT pWinpos->y - wndPtr->rectWindow.top ); } pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE; + + TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n", + pWinpos->hwnd, pWinpos->hwndInsertAfter, pWinpos->x, pWinpos->y, + pWinpos->cx, pWinpos->cy, pWinpos->flags ); + TRACE( "current %s style %08lx new %s\n", + wine_dbgstr_rect( &wndPtr->rectWindow ), wndPtr->dwStyle, + wine_dbgstr_rect( pNewWindowRect )); + WIN_ReleasePtr( wndPtr ); return TRUE; } @@ -550,7 +401,7 @@ static BOOL SWP_DoWinPosChanging( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT /*********************************************************************** * SWP_DoNCCalcSize */ -static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT* pNewClientRect ) +static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, const RECT* pNewWindowRect, RECT* pNewClientRect ) { UINT wvrFlags = 0; WND *wndPtr; @@ -580,8 +431,6 @@ static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT* pN params.rgrc[0].top <= params.rgrc[0].bottom) *pNewClientRect = params.rgrc[0]; - /* FIXME: WVR_ALIGNxxx */ - if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0; if( pNewClientRect->left != wndPtr->rectClient.left || @@ -756,56 +605,6 @@ static BOOL fixup_flags( WINDOWPOS *winpos ) } -/*********************************************************************** - * set_visible_style - * - * Set/clear the WS_VISIBLE style of a window and map/unmap the X window. - */ -static void set_visible_style( HWND hwnd, BOOL set ) -{ - WND *win; - - if (!(win = WIN_GetPtr( hwnd ))) return; - if (win == WND_OTHER_PROCESS) return; - - TRACE( "hwnd %p (%lx) set %d visible %d empty %d\n", - hwnd, get_whole_window(win), - set, (win->dwStyle & WS_VISIBLE) != 0, IsRectEmpty(&win->rectWindow) ); - - if (set) - { - if (win->dwStyle & WS_VISIBLE) goto done; - WIN_SetStyle( hwnd, win->dwStyle | WS_VISIBLE ); - if (X11DRV_is_window_rect_mapped( &win->rectWindow ) && - get_whole_window(win) && is_window_top_level(win)) - { - Display *display = thread_display(); - X11DRV_sync_window_style( display, win ); - X11DRV_set_wm_hints( display, win ); - TRACE( "mapping win %p\n", hwnd ); - wine_tsx11_lock(); - XMapWindow( display, get_whole_window(win) ); - wine_tsx11_unlock(); - } - } - else - { - if (!(win->dwStyle & WS_VISIBLE)) goto done; - WIN_SetStyle( hwnd, win->dwStyle & ~WS_VISIBLE ); - if (X11DRV_is_window_rect_mapped( &win->rectWindow ) && - get_whole_window(win) && is_window_top_level(win)) - { - TRACE( "unmapping win %p\n", hwnd ); - wine_tsx11_lock(); - XUnmapWindow( thread_display(), get_whole_window(win) ); - wine_tsx11_unlock(); - } - } - done: - WIN_ReleasePtr( win ); -} - - /*********************************************************************** * SetWindowStyle (X11DRV.@) * @@ -871,22 +670,146 @@ void X11DRV_SetWindowStyle( HWND hwnd, LONG oldStyle ) } +/*********************************************************************** + * X11DRV_set_window_pos + * + * Set a window position and Z order. + */ +BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow, + const RECT *rectClient, UINT swp_flags, UINT wvr_flags ) +{ + HWND top = get_top_clipping_window( hwnd ); + WND *win = WIN_GetPtr( hwnd ); + DWORD old_style, new_style; + BOOL ret; + + if (!win) return FALSE; + if (win == WND_OTHER_PROCESS) + { + if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd ); + return FALSE; + } + old_style = win->dwStyle; + SERVER_START_REQ( set_window_pos ) + { + req->handle = hwnd; + req->top_win = top; + req->previous = insert_after; + req->flags = swp_flags & ~SWP_WINE_NOHOSTMOVE; + req->redraw_flags = wvr_flags; + req->window.left = rectWindow->left; + req->window.top = rectWindow->top; + req->window.right = rectWindow->right; + req->window.bottom = rectWindow->bottom; + req->client.left = rectClient->left; + req->client.top = rectClient->top; + req->client.right = rectClient->right; + req->client.bottom = rectClient->bottom; + ret = !wine_server_call( req ); + new_style = reply->new_style; + } + SERVER_END_REQ; + + if (ret) + { + struct x11drv_win_data *data = win->pDriverData; + Display *display = thread_display(); + + /* invalidate DCEs */ + + if ((((swp_flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) && (new_style & WS_VISIBLE)) || + (swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW))) + { + RECT rect; + UnionRect( &rect, rectWindow, &win->rectWindow ); + DCE_InvalidateDCE( hwnd, &rect ); + } + + win->rectWindow = *rectWindow; + win->rectClient = *rectClient; + win->dwStyle = new_style; + + TRACE( "win %p window %s client %s style %08lx\n", + hwnd, wine_dbgstr_rect(rectWindow), wine_dbgstr_rect(rectClient), new_style ); + + /* FIXME: copy the valid bits */ + + if (swp_flags & SWP_WINE_NOHOSTMOVE) + { + data->whole_rect = *rectWindow; + X11DRV_window_to_X_rect( win, &data->whole_rect ); + if (data->client_window != data->whole_window) + X11DRV_sync_client_window_position( display, win ); + } + else if (data->whole_window) /* don't do anything if X window not created yet */ + { + if ((old_style & WS_VISIBLE) && !(new_style & WS_VISIBLE)) + { + /* window got hidden, unmap it */ + TRACE( "unmapping win %p\n", hwnd ); + wine_tsx11_lock(); + XUnmapWindow( thread_display(), data->whole_window ); + wine_tsx11_unlock(); + } + else if ((new_style & WS_VISIBLE) && !X11DRV_is_window_rect_mapped( rectWindow )) + { + /* resizing to zero size or off screen -> unmap */ + TRACE( "unmapping zero size or off-screen win %p\n", hwnd ); + wine_tsx11_lock(); + XUnmapWindow( display, data->whole_window ); + wine_tsx11_unlock(); + } + + X11DRV_sync_whole_window_position( display, win, !(swp_flags & SWP_NOZORDER) ); + X11DRV_sync_client_window_position( display, win ); + + if (!(old_style & WS_VISIBLE) && (new_style & WS_VISIBLE)) + { + /* window got shown, map it */ + if (X11DRV_is_window_rect_mapped( rectWindow )) + { + TRACE( "mapping win %p\n", hwnd ); + if (is_window_top_level(win)) + { + X11DRV_sync_window_style( display, win ); + X11DRV_set_wm_hints( display, win ); + } + wine_tsx11_lock(); + XMapWindow( display, data->whole_window ); + wine_tsx11_unlock(); + } + } + else if ((new_style & WS_VISIBLE) && X11DRV_is_window_rect_mapped( rectWindow )) + { + /* resizing from zero size to non-zero -> map */ + TRACE( "mapping non zero size or off-screen win %p\n", hwnd ); + wine_tsx11_lock(); + XMapWindow( display, data->whole_window ); + wine_tsx11_unlock(); + } + wine_tsx11_lock(); + XFlush( display ); /* FIXME: should not be necessary */ + wine_tsx11_unlock(); + } + } + WIN_ReleasePtr( win ); + return ret; +} + + /*********************************************************************** * SetWindowPos (X11DRV.@) */ BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos ) { - WND *wndPtr; RECT newWindowRect, newClientRect; - RECT oldWindowRect, oldClientRect; - UINT wvrFlags = 0; - BOOL bChangePos; + UINT wvr_flags, orig_flags; TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n", winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - bChangePos = !(winpos->flags & SWP_WINE_NOHOSTMOVE); + orig_flags = winpos->flags; winpos->flags &= ~SWP_WINE_NOHOSTMOVE; /* Check window handle */ @@ -913,12 +836,6 @@ BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos ) /* Fix redundant flags */ if (!fixup_flags( winpos )) return FALSE; - if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE; - - TRACE("\tcurrent (%ld,%ld)-(%ld,%ld), style %08x\n", - wndPtr->rectWindow.left, wndPtr->rectWindow.top, - wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle ); - if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER) { if (GetAncestor( winpos->hwnd, GA_PARENT ) == GetDesktopWindow()) @@ -927,117 +844,14 @@ BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos ) /* Common operations */ - wvrFlags = SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect ); - - if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter) - { - HWND parent = GetAncestor( winpos->hwnd, GA_PARENT ); - if (parent) WIN_LinkWindow( winpos->hwnd, parent, winpos->hwndInsertAfter ); - } - - /* Reset active DCEs */ - - if( (((winpos->flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) && - wndPtr->dwStyle & WS_VISIBLE) || - (winpos->flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) ) - { - RECT rect; - - UnionRect(&rect, &newWindowRect, &wndPtr->rectWindow); - DCE_InvalidateDCE(wndPtr->hwndSelf, &rect); - } - - oldWindowRect = wndPtr->rectWindow; - oldClientRect = wndPtr->rectClient; - - /* Find out if we have to redraw the whole client rect */ - - if( oldClientRect.bottom - oldClientRect.top == - newClientRect.bottom - newClientRect.top ) wvrFlags &= ~WVR_VREDRAW; - - if( oldClientRect.right - oldClientRect.left == - newClientRect.right - newClientRect.left ) wvrFlags &= ~WVR_HREDRAW; + wvr_flags = SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect ); /* FIXME: actually do something with WVR_VALIDRECTS */ - X11DRV_set_window_rectangles( winpos->hwnd, &newWindowRect, &newClientRect ); - - if (get_whole_window(wndPtr)) /* don't do anything if X window not created yet */ - { - Display *display = thread_display(); - - if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW)) - { - /* clear the update region */ - RedrawWindow( winpos->hwnd, NULL, 0, RDW_VALIDATE | RDW_NOFRAME | - RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN ); - set_visible_style( winpos->hwnd, FALSE ); - } - else if ((wndPtr->dwStyle & WS_VISIBLE) && bChangePos && - X11DRV_is_window_rect_mapped( &oldWindowRect ) && - !X11DRV_is_window_rect_mapped( &newWindowRect )) - { - /* resizing to zero size or off screen -> unmap */ - TRACE( "unmapping zero size or off-screen win %p\n", winpos->hwnd ); - wine_tsx11_lock(); - XUnmapWindow( display, get_whole_window(wndPtr) ); - wine_tsx11_unlock(); - } - - if (bChangePos) - X11DRV_sync_whole_window_position( display, wndPtr, !(winpos->flags & SWP_NOZORDER) ); - else - { - struct x11drv_win_data *data = wndPtr->pDriverData; - data->whole_rect = wndPtr->rectWindow; - X11DRV_window_to_X_rect( wndPtr, &data->whole_rect ); - } - - if (X11DRV_sync_client_window_position( display, wndPtr ) || - (winpos->flags & SWP_FRAMECHANGED)) - { - /* if we moved the client area, repaint the whole non-client window */ - wine_tsx11_lock(); - XClearArea( display, get_whole_window(wndPtr), 0, 0, 0, 0, True ); - wine_tsx11_unlock(); - } - if (winpos->flags & SWP_SHOWWINDOW) - { - set_visible_style( winpos->hwnd, TRUE ); - } - else if ((wndPtr->dwStyle & WS_VISIBLE) && bChangePos && - !X11DRV_is_window_rect_mapped( &oldWindowRect ) && - X11DRV_is_window_rect_mapped( &newWindowRect )) - { - /* resizing from zero size to non-zero -> map */ - TRACE( "mapping non zero size or off-screen win %p\n", winpos->hwnd ); - wine_tsx11_lock(); - XMapWindow( display, get_whole_window(wndPtr) ); - wine_tsx11_unlock(); - } - wine_tsx11_lock(); - XFlush( display ); /* FIXME: should not be necessary */ - wine_tsx11_unlock(); - } - else /* no X window, simply toggle the window style */ - { - if (winpos->flags & SWP_SHOWWINDOW) - set_visible_style( winpos->hwnd, TRUE ); - else if (winpos->flags & SWP_HIDEWINDOW) - set_visible_style( winpos->hwnd, FALSE ); - } - - /* 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 ); + if (!X11DRV_set_window_pos( winpos->hwnd, winpos->hwndInsertAfter, + &newWindowRect, &newClientRect, + orig_flags, wvr_flags )) + return FALSE; if( winpos->flags & SWP_HIDEWINDOW ) HideCaret(winpos->hwnd); @@ -1572,7 +1386,7 @@ void X11DRV_handle_desktop_resize( unsigned int width, unsigned int height ) screen_height = height; TRACE("desktop %p change to (%dx%d)\n", hwnd, width, height); SetRect( &rect, 0, 0, width, height ); - X11DRV_set_window_rectangles( hwnd, &rect, &rect ); + X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER|SWP_NOMOVE|SWP_WINE_NOHOSTMOVE, 0 ); SendMessageTimeoutW( HWND_BROADCAST, WM_DISPLAYCHANGE, screen_depth, MAKELPARAM( width, height ), SMTO_ABORTIFHUNG, 2000, NULL ); } diff --git a/dlls/x11drv/x11drv.h b/dlls/x11drv/x11drv.h index 0f7c7a7a05c..8ae74f24e71 100644 --- a/dlls/x11drv/x11drv.h +++ b/dlls/x11drv/x11drv.h @@ -563,7 +563,8 @@ extern Window X11DRV_create_desktop( XVisualInfo *desktop_vi, const char *geomet extern void X11DRV_sync_window_style( Display *display, WND *win ); extern int X11DRV_sync_whole_window_position( Display *display, WND *win, int zorder ); extern int X11DRV_sync_client_window_position( Display *display, WND *win ); -extern void X11DRV_set_window_rectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient ); +extern BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow, + const RECT *rectClient, UINT swp_flags, UINT wvr_flags ); extern void X11DRV_set_wm_hints( Display *display, WND *win ); extern void X11DRV_handle_desktop_resize(unsigned int width, unsigned int height); diff --git a/include/win.h b/include/win.h index bc29a0d6b47..f3ed6568d92 100644 --- a/include/win.h +++ b/include/win.h @@ -52,7 +52,6 @@ typedef struct tagWND void *pVScroll; /* Vertical scroll-bar info */ void *pHScroll; /* Horizontal scroll-bar info */ struct tagDCE *dce; /* Window DCE (if CS_OWNDC or CS_CLASSDC) */ - HRGN hrgnUpdate; /* Update region */ DWORD dwStyle; /* Window style (from CreateWindow) */ DWORD dwExStyle; /* Extended style (from CreateWindowEx) */ DWORD clsStyle; /* Class style at window creation */ @@ -78,17 +77,14 @@ typedef struct } INTERNALPOS, *LPINTERNALPOS; /* WND flags values */ -#define WIN_NEEDS_ERASEBKGND 0x0002 /* WM_ERASEBKGND must be sent to window*/ -#define WIN_NEEDS_NCPAINT 0x0004 /* WM_NCPAINT must be sent to window */ -#define WIN_RESTORE_MAX 0x0008 /* Maximize when restoring */ -#define WIN_INTERNAL_PAINT 0x0010 /* Internal WM_PAINT message pending */ -#define WIN_NEED_SIZE 0x0040 /* Internal WM_SIZE is needed */ -#define WIN_NCACTIVATED 0x0080 /* last WM_NCACTIVATE was positive */ -#define WIN_ISMDICLIENT 0x0100 /* Window is an MDIClient */ -#define WIN_ISDIALOG 0x0200 /* Window is a dialog */ -#define WIN_ISWIN32 0x0400 /* Understands Win32 messages */ -#define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0800 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */ -#define WIN_NEEDS_INTERNALSOP 0x1000 /* Window was hidden by WIN_InternalShowOwnedPopups */ +#define WIN_RESTORE_MAX 0x0001 /* Maximize when restoring */ +#define WIN_NEED_SIZE 0x0002 /* Internal WM_SIZE is needed */ +#define WIN_NCACTIVATED 0x0004 /* last WM_NCACTIVATE was positive */ +#define WIN_ISMDICLIENT 0x0008 /* Window is an MDIClient */ +#define WIN_ISDIALOG 0x0010 /* Window is a dialog */ +#define WIN_ISWIN32 0x0020 /* Understands Win32 messages */ +#define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0040 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */ +#define WIN_NEEDS_INTERNALSOP 0x0080 /* Window was hidden by WIN_InternalShowOwnedPopups */ /* Window functions */ extern WND *WIN_GetPtr( HWND hwnd ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 987dee1bc3b..17e78278257 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2551,16 +2551,21 @@ struct get_window_tree_reply }; -struct set_window_rectangles_request +struct set_window_pos_request { struct request_header __header; user_handle_t handle; + user_handle_t top_win; + user_handle_t previous; + unsigned int flags; + unsigned int redraw_flags; rectangle_t window; rectangle_t client; }; -struct set_window_rectangles_reply +struct set_window_pos_reply { struct reply_header __header; + unsigned int new_style; }; @@ -2605,19 +2610,6 @@ struct set_window_text_reply -struct inc_window_paint_count_request -{ - struct request_header __header; - user_handle_t handle; - int incr; -}; -struct inc_window_paint_count_reply -{ - struct reply_header __header; -}; - - - struct get_windows_offset_request { struct request_header __header; @@ -2676,6 +2668,44 @@ struct set_window_region_reply +struct get_update_region_request +{ + struct request_header __header; + user_handle_t window; + unsigned int flags; +}; +struct get_update_region_reply +{ + struct reply_header __header; + user_handle_t child; + unsigned int flags; + size_t total_size; + /* VARARG(region,rectangles); */ +}; +#define UPDATE_NONCLIENT 0x01 +#define UPDATE_ERASE 0x02 +#define UPDATE_PAINT 0x04 +#define UPDATE_INTERNALPAINT 0x08 +#define UPDATE_ALLCHILDREN 0x10 +#define UPDATE_NOCHILDREN 0x20 +#define UPDATE_NOREGION 0x40 + + + +struct redraw_window_request +{ + struct request_header __header; + user_handle_t window; + unsigned int flags; + /* VARARG(region,rectangles); */ +}; +struct redraw_window_reply +{ + struct reply_header __header; +}; + + + struct set_window_property_request { struct request_header __header; @@ -3246,15 +3276,16 @@ enum request REQ_get_window_children, REQ_get_window_children_from_point, REQ_get_window_tree, - REQ_set_window_rectangles, + REQ_set_window_pos, REQ_get_window_rectangles, REQ_get_window_text, REQ_set_window_text, - REQ_inc_window_paint_count, REQ_get_windows_offset, REQ_get_visible_region, REQ_get_window_region, REQ_set_window_region, + REQ_get_update_region, + REQ_redraw_window, REQ_set_window_property, REQ_remove_window_property, REQ_get_window_property, @@ -3430,15 +3461,16 @@ union generic_request struct get_window_children_request get_window_children_request; struct get_window_children_from_point_request get_window_children_from_point_request; struct get_window_tree_request get_window_tree_request; - struct set_window_rectangles_request set_window_rectangles_request; + struct set_window_pos_request set_window_pos_request; struct get_window_rectangles_request get_window_rectangles_request; struct get_window_text_request get_window_text_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 get_window_region_request get_window_region_request; struct set_window_region_request set_window_region_request; + struct get_update_region_request get_update_region_request; + struct redraw_window_request redraw_window_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; @@ -3612,15 +3644,16 @@ union generic_reply struct get_window_children_reply get_window_children_reply; struct get_window_children_from_point_reply get_window_children_from_point_reply; struct get_window_tree_reply get_window_tree_reply; - struct set_window_rectangles_reply set_window_rectangles_reply; + struct set_window_pos_reply set_window_pos_reply; struct get_window_rectangles_reply get_window_rectangles_reply; struct get_window_text_reply get_window_text_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 get_window_region_reply get_window_region_reply; struct set_window_region_reply set_window_region_reply; + struct get_update_region_reply get_update_region_reply; + struct redraw_window_reply redraw_window_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; @@ -3648,6 +3681,6 @@ union generic_reply struct set_global_windows_reply set_global_windows_reply; }; -#define SERVER_PROTOCOL_VERSION 151 +#define SERVER_PROTOCOL_VERSION 152 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 7f21d4bfb8d..5423b7c1ea9 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1805,11 +1805,17 @@ enum message_type user_handle_t last_child; /* last child */ @END -/* Set the window and client rectangles of a window */ -@REQ(set_window_rectangles) +/* Set the position and Z order of a window */ +@REQ(set_window_pos) user_handle_t handle; /* handle to the window */ + user_handle_t top_win; /* top window to clip against */ + user_handle_t previous; /* previous window in Z order */ + unsigned int flags; /* SWP_* flags */ + unsigned int redraw_flags; /* WVR_* flags */ rectangle_t window; /* window rectangle */ rectangle_t client; /* client rectangle */ +@REPLY + unsigned int new_style; /* new window style */ @END @@ -1837,13 +1843,6 @@ enum message_type @END -/* Increment the window paint count */ -@REQ(inc_window_paint_count) - user_handle_t handle; /* handle to the window */ - int incr; /* increment (can be negative) */ -@END - - /* Get the coordinates offset between two windows */ @REQ(get_windows_offset) user_handle_t from; /* handle to the first window */ @@ -1881,6 +1880,33 @@ enum message_type @END +/* Get the window update region */ +@REQ(get_update_region) + user_handle_t window; /* handle to the window */ + unsigned int flags; /* update flags (see below) */ +@REPLY + user_handle_t child; /* child to repaint (or window itself) */ + unsigned int flags; /* resulting update flags (see below) */ + size_t total_size; /* total size of the resulting region */ + VARARG(region,rectangles); /* list of rectangles for the region */ +@END +#define UPDATE_NONCLIENT 0x01 /* get region for repainting non-client area */ +#define UPDATE_ERASE 0x02 /* get region for erasing client area */ +#define UPDATE_PAINT 0x04 /* get region for painting client area */ +#define UPDATE_INTERNALPAINT 0x08 /* get region if internal paint is pending */ +#define UPDATE_ALLCHILDREN 0x10 /* force repaint of all children */ +#define UPDATE_NOCHILDREN 0x20 /* don't try to repaint any children */ +#define UPDATE_NOREGION 0x40 /* don't return a region, only the flags */ + + +/* Mark parts of a window as needing a redraw */ +@REQ(redraw_window) + user_handle_t window; /* handle to the window */ + unsigned int flags; /* RDW_* flags */ + 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 */ diff --git a/server/request.h b/server/request.h index 92e6d572329..d4ceb244688 100644 --- a/server/request.h +++ b/server/request.h @@ -246,15 +246,16 @@ DECL_HANDLER(get_window_parents); DECL_HANDLER(get_window_children); DECL_HANDLER(get_window_children_from_point); DECL_HANDLER(get_window_tree); -DECL_HANDLER(set_window_rectangles); +DECL_HANDLER(set_window_pos); DECL_HANDLER(get_window_rectangles); 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(get_window_region); DECL_HANDLER(set_window_region); +DECL_HANDLER(get_update_region); +DECL_HANDLER(redraw_window); DECL_HANDLER(set_window_property); DECL_HANDLER(remove_window_property); DECL_HANDLER(get_window_property); @@ -429,15 +430,16 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_get_window_children, (req_handler)req_get_window_children_from_point, (req_handler)req_get_window_tree, - (req_handler)req_set_window_rectangles, + (req_handler)req_set_window_pos, (req_handler)req_get_window_rectangles, (req_handler)req_get_window_text, (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_get_window_region, (req_handler)req_set_window_region, + (req_handler)req_get_update_region, + (req_handler)req_redraw_window, (req_handler)req_set_window_property, (req_handler)req_remove_window_property, (req_handler)req_get_window_property, diff --git a/server/trace.c b/server/trace.c index b7823fb0cd6..daafbf502dd 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2149,9 +2149,13 @@ static void dump_get_window_tree_reply( const struct get_window_tree_reply *req fprintf( stderr, " last_child=%p", req->last_child ); } -static void dump_set_window_rectangles_request( const struct set_window_rectangles_request *req ) +static void dump_set_window_pos_request( const struct set_window_pos_request *req ) { fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " top_win=%p,", req->top_win ); + fprintf( stderr, " previous=%p,", req->previous ); + fprintf( stderr, " flags=%08x,", req->flags ); + fprintf( stderr, " redraw_flags=%08x,", req->redraw_flags ); fprintf( stderr, " window=" ); dump_rectangle( &req->window ); fprintf( stderr, "," ); @@ -2159,6 +2163,11 @@ static void dump_set_window_rectangles_request( const struct set_window_rectangl dump_rectangle( &req->client ); } +static void dump_set_window_pos_reply( const struct set_window_pos_reply *req ) +{ + fprintf( stderr, " new_style=%08x", req->new_style ); +} + static void dump_get_window_rectangles_request( const struct get_window_rectangles_request *req ) { fprintf( stderr, " handle=%p", req->handle ); @@ -2191,12 +2200,6 @@ static void dump_set_window_text_request( const struct set_window_text_request * dump_varargs_unicode_str( cur_size ); } -static void dump_inc_window_paint_count_request( const struct inc_window_paint_count_request *req ) -{ - fprintf( stderr, " handle=%p,", req->handle ); - fprintf( stderr, " incr=%d", req->incr ); -} - static void dump_get_windows_offset_request( const struct get_windows_offset_request *req ) { fprintf( stderr, " from=%p,", req->from ); @@ -2242,6 +2245,29 @@ static void dump_set_window_region_request( const struct set_window_region_reque dump_varargs_rectangles( cur_size ); } +static void dump_get_update_region_request( const struct get_update_region_request *req ) +{ + fprintf( stderr, " window=%p,", req->window ); + fprintf( stderr, " flags=%08x", req->flags ); +} + +static void dump_get_update_region_reply( const struct get_update_region_reply *req ) +{ + fprintf( stderr, " child=%p,", req->child ); + fprintf( stderr, " flags=%08x,", req->flags ); + fprintf( stderr, " total_size=%d,", req->total_size ); + fprintf( stderr, " region=" ); + dump_varargs_rectangles( cur_size ); +} + +static void dump_redraw_window_request( const struct redraw_window_request *req ) +{ + fprintf( stderr, " window=%p,", req->window ); + fprintf( stderr, " flags=%08x,", req->flags ); + 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 ); @@ -2706,15 +2732,16 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_window_children_request, (dump_func)dump_get_window_children_from_point_request, (dump_func)dump_get_window_tree_request, - (dump_func)dump_set_window_rectangles_request, + (dump_func)dump_set_window_pos_request, (dump_func)dump_get_window_rectangles_request, (dump_func)dump_get_window_text_request, (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_get_window_region_request, (dump_func)dump_set_window_region_request, + (dump_func)dump_get_update_region_request, + (dump_func)dump_redraw_window_request, (dump_func)dump_set_window_property_request, (dump_func)dump_remove_window_property_request, (dump_func)dump_get_window_property_request, @@ -2886,15 +2913,16 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_window_children_reply, (dump_func)dump_get_window_children_from_point_reply, (dump_func)dump_get_window_tree_reply, - (dump_func)0, + (dump_func)dump_set_window_pos_reply, (dump_func)dump_get_window_rectangles_reply, (dump_func)dump_get_window_text_reply, (dump_func)0, - (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)dump_get_update_region_reply, + (dump_func)0, (dump_func)0, (dump_func)dump_remove_window_property_reply, (dump_func)dump_get_window_property_reply, @@ -3066,15 +3094,16 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "get_window_children", "get_window_children_from_point", "get_window_tree", - "set_window_rectangles", + "set_window_pos", "get_window_rectangles", "get_window_text", "set_window_text", - "inc_window_paint_count", "get_windows_offset", "get_visible_region", "get_window_region", "set_window_region", + "get_update_region", + "redraw_window", "set_window_property", "remove_window_property", "get_window_property", diff --git a/server/window.c b/server/window.c index 9a9229d637c..7a2b50f3f2e 100644 --- a/server/window.c +++ b/server/window.c @@ -69,13 +69,14 @@ struct window rectangle_t window_rect; /* window rectangle (relative to parent client area) */ rectangle_t client_rect; /* client rectangle (relative to parent client area) */ struct region *win_region; /* region for shaped windows (relative to window rect) */ + struct region *update_region; /* update region (relative to window rect) */ unsigned int style; /* window style */ unsigned int ex_style; /* window extended style */ unsigned int id; /* window id */ void* instance; /* creator instance */ void* user_data; /* user-specific data */ WCHAR *text; /* window caption text */ - int paint_count; /* count of pending paints for this window */ + unsigned int paint_flags; /* various painting flags */ int prop_inuse; /* number of in-use window properties */ int prop_alloc; /* number of allocated window properties */ struct property *properties; /* window properties array */ @@ -83,6 +84,10 @@ struct window 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 */ + /* growable array of user handles */ struct user_handle_array { @@ -279,7 +284,8 @@ static void destroy_window( struct window *win ) if (win->thread->queue) { - if (win->paint_count) inc_queue_paint_count( win->thread, -win->paint_count ); + if (win->update_region) inc_queue_paint_count( win->thread, -1 ); + if (win->paint_flags & PAINT_INTERNAL) inc_queue_paint_count( win->thread, -1 ); queue_cleanup_window( win->thread, win->handle ); } /* reset global window pointers, if the corresponding window is destroyed */ @@ -291,6 +297,7 @@ static void destroy_window( struct window *win ) destroy_properties( win ); unlink_window( win ); if (win->win_region) free_region( win->win_region ); + if (win->update_region) free_region( win->update_region ); release_class( win->class ); if (win->text) free( win->text ); memset( win, 0x55, sizeof(*win) ); @@ -330,13 +337,14 @@ static struct window *create_window( struct window *parent, struct window *owner win->atom = atom; win->last_active = win->handle; win->win_region = NULL; + win->update_region = NULL; win->style = 0; win->ex_style = 0; win->id = 0; win->instance = NULL; win->user_data = NULL; win->text = NULL; - win->paint_count = 0; + win->paint_flags = 0; win->prop_inuse = 0; win->prop_alloc = 0; win->properties = NULL; @@ -405,6 +413,12 @@ int make_window_active( user_handle_t window ) return 1; } +/* increment (or decrement) the window paint count */ +static inline void inc_window_paint_count( struct window *win, int incr ) +{ + if (win->thread) inc_queue_paint_count( win->thread, incr ); +} + /* check if window and all its ancestors are visible */ static int is_visible( const struct window *win ) { @@ -538,6 +552,14 @@ struct thread *get_window_thread( user_handle_t handle ) return (struct thread *)grab_object( win->thread ); } + +/* check if any area of a window needs repainting */ +static inline int win_needs_repaint( struct window *win ) +{ + return win->update_region || (win->paint_flags & PAINT_INTERNAL); +} + + /* find a child of the specified window that needs repainting */ static struct window *find_child_to_repaint( struct window *parent, struct thread *thread ) { @@ -546,9 +568,9 @@ static struct window *find_child_to_repaint( struct window *parent, struct threa for (ptr = parent->first_child; ptr && !ret; ptr = ptr->next) { if (!(ptr->style & WS_VISIBLE)) continue; - if (ptr->paint_count && ptr->thread == thread) + if (ptr->thread == thread && win_needs_repaint( ptr )) ret = ptr; - else /* explore its children */ + else if (!(ptr->style & WS_MINIMIZE)) /* explore its children */ ret = find_child_to_repaint( ptr, thread ); } @@ -559,22 +581,28 @@ static struct window *find_child_to_repaint( struct window *parent, struct threa { if (!(ptr->style & WS_VISIBLE)) continue; if (ptr->ex_style & WS_EX_TRANSPARENT) continue; - if (ptr->paint_count && ptr->thread == thread) return ptr; + if (ptr->thread != thread) continue; + if (win_needs_repaint( ptr )) return ptr; } } return ret; } -/* find a window that needs repainting */ +/* find a window that needs to receive a WM_PAINT */ user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread ) { - struct window *win = parent ? get_window( parent ) : top_window; + struct window *ptr, *win = find_child_to_repaint( top_window, thread ); - if (!win || !(win->style & WS_VISIBLE)) return 0; - if (!win->paint_count || win->thread != thread) - win = find_child_to_repaint( win, thread ); - return win ? win->handle : 0; + if (win) + { + if (!parent) return win->handle; + /* check that it is a child of the specified parent */ + for (ptr = win; ptr; ptr = ptr->parent) + if (ptr->handle == parent) return win->handle; + /* otherwise don't return any window, we don't repaint a child before its parent */ + } + return 0; } @@ -716,6 +744,419 @@ struct window_class* get_window_class( user_handle_t window ) return win->class; } +/* return a copy of the specified region cropped to the window client or frame rectangle, */ +/* and converted from client to window coordinates. Helper for (in)validate_window. */ +static struct region *crop_region_to_win_rect( struct window *win, struct region *region, int frame ) +{ + rectangle_t rect; + struct region *tmp = create_empty_region(); + + if (!tmp) return NULL; + + /* get bounding rect in client coords */ + if (frame) + { + rect.left = win->window_rect.left - win->client_rect.left; + rect.top = win->window_rect.top - win->client_rect.top; + rect.right = win->window_rect.right - win->client_rect.left; + rect.bottom = win->window_rect.bottom - win->client_rect.top; + } + else + { + rect.left = 0; + rect.top = 0; + rect.right = win->client_rect.right - win->client_rect.left; + rect.bottom = win->client_rect.bottom - win->client_rect.top; + } + set_region_rect( tmp, &rect ); + + /* intersect specified region with bounding rect */ + if (region && !intersect_region( tmp, region, tmp )) goto done; + if (is_region_empty( tmp )) goto done; + + /* map it to window coords */ + offset_region( tmp, win->client_rect.left - win->window_rect.left, + win->client_rect.top - win->window_rect.top ); + return tmp; + +done: + free_region( tmp ); + return NULL; +} + + +/* set a region as new update region for the window */ +static void set_update_region( struct window *win, struct region *region ) +{ + if (region && !is_region_empty( region )) + { + if (!win->update_region) inc_window_paint_count( win, 1 ); + else free_region( win->update_region ); + win->update_region = region; + } + else + { + if (win->update_region) inc_window_paint_count( win, -1 ); + win->paint_flags &= ~(PAINT_ERASE | PAINT_NONCLIENT); + win->update_region = NULL; + if (region) free_region( region ); + } +} + + +/* add a region to the update region; the passed region is freed or reused */ +static int add_update_region( struct window *win, struct region *region ) +{ + if (win->update_region && !union_region( region, win->update_region, region )) + { + free_region( region ); + return 0; + } + set_update_region( win, region ); + return 1; +} + + +/* validate the non client area of a window */ +static void validate_non_client( struct window *win ) +{ + struct region *tmp; + rectangle_t rect; + + if (!win->update_region) return; /* nothing to do */ + + /* get client rect in window coords */ + rect.left = win->client_rect.left - win->window_rect.left; + rect.top = win->client_rect.top - win->window_rect.top; + rect.right = win->client_rect.right - win->window_rect.left; + rect.bottom = win->client_rect.bottom - win->window_rect.top; + + if ((tmp = create_region( &rect, 1 ))) + { + if (intersect_region( tmp, win->update_region, tmp )) + set_update_region( win, tmp ); + else + free_region( tmp ); + } + win->paint_flags &= ~PAINT_NONCLIENT; +} + + +/* validate a window completely so that we don't get any further paint messages for it */ +static void validate_whole_window( struct window *win ) +{ + set_update_region( win, NULL ); + + if (win->paint_flags & PAINT_INTERNAL) + { + win->paint_flags &= ~PAINT_INTERNAL; + inc_window_paint_count( win, -1 ); + } +} + + +/* validate the update region of a window on all parents; helper for redraw_window */ +static void validate_parents( struct window *child ) +{ + int offset_x = 0, offset_y = 0; + struct window *win = child; + struct region *tmp = NULL; + + if (!child->update_region) return; + + while (win->parent && win->parent != top_window) + { + /* map to parent client coords */ + offset_x += win->window_rect.left; + offset_y += win->window_rect.top; + + win = win->parent; + + /* and now map to window coords */ + offset_x += win->client_rect.left - win->window_rect.left; + offset_y += win->client_rect.top - win->window_rect.top; + + if (win->update_region && !(win->style & WS_CLIPCHILDREN)) + { + if (!tmp && !(tmp = create_empty_region())) return; + offset_region( child->update_region, offset_x, offset_y ); + if (subtract_region( tmp, win->update_region, child->update_region )) + { + set_update_region( win, tmp ); + tmp = NULL; + } + /* restore child coords */ + offset_region( child->update_region, -offset_x, -offset_y ); + } + } + if (tmp) free_region( tmp ); +} + + +/* add/subtract a region (in client coordinates) to the update region of the window */ +static void redraw_window( struct window *win, struct region *region, int frame, unsigned int flags ) +{ + struct region *tmp; + struct window *child; + + if (flags & RDW_INVALIDATE) + { + if (!(tmp = crop_region_to_win_rect( win, region, frame ))) return; + + if (!add_update_region( win, tmp )) return; + + if (flags & RDW_FRAME) win->paint_flags |= PAINT_NONCLIENT; + if (flags & RDW_ERASE) win->paint_flags |= PAINT_ERASE; + } + else if (flags & RDW_VALIDATE) + { + if (!region && (flags & RDW_NOFRAME)) /* shortcut: validate everything */ + { + set_update_region( win, NULL ); + } + else if (win->update_region) + { + if ((tmp = crop_region_to_win_rect( win, region, frame ))) + { + if (!subtract_region( tmp, win->update_region, tmp )) + { + free_region( tmp ); + return; + } + set_update_region( win, tmp ); + } + if (flags & RDW_NOFRAME) validate_non_client( win ); + if (flags & RDW_NOERASE) win->paint_flags &= ~PAINT_ERASE; + } + } + + if ((flags & RDW_INTERNALPAINT) && !(win->paint_flags & PAINT_INTERNAL)) + { + win->paint_flags |= PAINT_INTERNAL; + inc_window_paint_count( win, 1 ); + } + else if ((flags & RDW_NOINTERNALPAINT) && (win->paint_flags & PAINT_INTERNAL)) + { + win->paint_flags &= ~PAINT_INTERNAL; + inc_window_paint_count( win, -1 ); + } + + if (flags & RDW_UPDATENOW) + { + validate_parents( win ); + flags &= ~RDW_UPDATENOW; + } + + /* now process children recursively */ + + if (flags & RDW_NOCHILDREN) return; + if (win->style & WS_MINIMIZE) return; + if ((win->style & WS_CLIPCHILDREN) && !(flags & RDW_ALLCHILDREN)) return; + + if (!(tmp = crop_region_to_win_rect( win, region, 0 ))) return; + + /* map to client coordinates */ + offset_region( tmp, win->window_rect.left - win->client_rect.left, + win->window_rect.top - win->client_rect.top ); + + if (flags & RDW_INVALIDATE) flags |= RDW_FRAME | RDW_ERASE; + + for (child = win->first_child; child; child = child->next) + { + if (!(child->style & WS_VISIBLE)) continue; + if (!rect_in_region( tmp, &child->window_rect )) continue; + offset_region( tmp, -child->client_rect.left, -child->client_rect.top ); + redraw_window( child, tmp, 1, flags ); + offset_region( tmp, child->client_rect.left, child->client_rect.top ); + } + free_region( tmp ); +} + + +/* retrieve the update flags for a window depending on the state of the update region */ +static unsigned int get_update_flags( struct window *win, unsigned int flags ) +{ + unsigned int ret = 0; + + if (flags & UPDATE_NONCLIENT) + { + if ((win->paint_flags & PAINT_NONCLIENT) && win->update_region) ret |= UPDATE_NONCLIENT; + } + if (flags & UPDATE_ERASE) + { + if ((win->paint_flags & PAINT_ERASE) && win->update_region) ret |= UPDATE_ERASE; + } + if (flags & UPDATE_PAINT) + { + if (win->update_region) ret |= UPDATE_PAINT; + } + if (flags & UPDATE_INTERNALPAINT) + { + if (win->paint_flags & PAINT_INTERNAL) ret |= UPDATE_INTERNALPAINT; + } + return ret; +} + + +/* iterate through the children of the given window until we find one with some update flags */ +static unsigned int get_child_update_flags( struct window *win, unsigned int flags, + struct window **child ) +{ + struct window *ptr; + unsigned int ret = 0; + + for (ptr = win->first_child; ptr && !ret; ptr = ptr->next) + { + if (!(ptr->style & WS_VISIBLE)) continue; + if ((ret = get_update_flags( ptr, flags )) != 0) + { + *child = ptr; + break; + } + if (ptr->style & WS_MINIMIZE) continue; + + /* Note: the WS_CLIPCHILDREN test is the opposite of the invalidation case, + * here we only want to repaint children of windows that clip them, others + * need to wait for WM_PAINT to be done in the parent first. + */ + if (!(flags & UPDATE_NOCHILDREN) && + ((flags & UPDATE_ALLCHILDREN) || (ptr->style & WS_CLIPCHILDREN))) + ret = get_child_update_flags( ptr, flags, child ); + } + return ret; +} + + +/* expose a region of a window, looking for the top most parent that needs to be exposed */ +/* the region is in window coordinates */ +static void expose_window( struct window *win, struct window *top, struct region *region ) +{ + struct window *parent, *ptr; + int offset_x, offset_y; + + /* find the top most parent that doesn't clip either siblings or children */ + for (parent = ptr = win; ptr != top; ptr = ptr->parent) + { + if (!(ptr->style & WS_CLIPCHILDREN)) parent = ptr; + if (!(ptr->style & WS_CLIPSIBLINGS)) parent = ptr->parent; + } + if (parent == win && parent != top && win->parent) + parent = win->parent; /* always go up at least one level if possible */ + + offset_x = win->window_rect.left - win->client_rect.left; + offset_y = win->window_rect.top - win->client_rect.top; + for (ptr = win; ptr != parent; ptr = ptr->parent) + { + offset_x += ptr->client_rect.left; + offset_y += ptr->client_rect.top; + } + offset_region( region, offset_x, offset_y ); + redraw_window( parent, region, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN ); + offset_region( region, -offset_x, -offset_y ); +} + + +/* validate that the specified window and client rects are valid */ +static int validate_window_rectangles( const rectangle_t *window_rect, const rectangle_t *client_rect ) +{ + /* rectangles must be ordered properly */ + if (window_rect->right < window_rect->left) return 0; + if (window_rect->bottom < window_rect->top) return 0; + if (client_rect->right < client_rect->left) return 0; + if (client_rect->bottom < client_rect->top) return 0; + /* client rect must be inside window rect */ + if (client_rect->left < window_rect->left) return 0; + if (client_rect->right > window_rect->right) return 0; + if (client_rect->top < window_rect->top) return 0; + if (client_rect->bottom > window_rect->bottom) return 0; + return 1; +} + + +/* set the window and client rectangles, updating the update region if necessary */ +static void set_window_pos( struct window *win, struct window *top, struct window *previous, + unsigned int swp_flags, unsigned int wvr_flags, + const rectangle_t *window_rect, const rectangle_t *client_rect ) +{ + struct region *old_vis_rgn, *new_vis_rgn; + const rectangle_t old_window_rect = win->window_rect; + const rectangle_t old_client_rect = win->client_rect; + + /* if the window is not visible, everything is easy */ + + if ((win->parent && !is_visible( win->parent )) || + (!(win->style & WS_VISIBLE) && !(swp_flags & SWP_SHOWWINDOW))) + { + win->window_rect = *window_rect; + win->client_rect = *client_rect; + if (!(swp_flags & SWP_NOZORDER)) link_window( win, win->parent, previous ); + if (swp_flags & SWP_SHOWWINDOW) win->style |= WS_VISIBLE; + else if (swp_flags & SWP_HIDEWINDOW) win->style &= ~WS_VISIBLE; + return; + } + + if (!(old_vis_rgn = get_visible_region( win, top, DCX_WINDOW ))) return; + + /* set the new window info before invalidating anything */ + + win->window_rect = *window_rect; + win->client_rect = *client_rect; + if (!(swp_flags & SWP_NOZORDER)) link_window( win, win->parent, previous ); + if (swp_flags & SWP_SHOWWINDOW) win->style |= WS_VISIBLE; + else if (swp_flags & SWP_HIDEWINDOW) win->style &= ~WS_VISIBLE; + + if (!(new_vis_rgn = get_visible_region( win, top, DCX_WINDOW ))) + { + free_region( old_vis_rgn ); + clear_error(); /* ignore error since the window info has been modified already */ + return; + } + + /* expose anything revealed by the change */ + + offset_region( old_vis_rgn, old_window_rect.left - window_rect->left, + old_window_rect.top - window_rect->top ); + if (xor_region( new_vis_rgn, old_vis_rgn, new_vis_rgn )) expose_window( win, top, new_vis_rgn ); + free_region( old_vis_rgn ); + + if (!(win->style & WS_VISIBLE)) + { + /* clear the update region since the window is no longer visible */ + validate_whole_window( win ); + goto done; + } + + /* expose the whole non-client area if it changed in any way */ + + if ((swp_flags & SWP_FRAMECHANGED) || + memcmp( window_rect, &old_window_rect, sizeof(old_window_rect) ) || + memcmp( client_rect, &old_client_rect, sizeof(old_client_rect) )) + { + struct region *tmp = create_region( client_rect, 1 ); + + if (tmp) + { + set_region_rect( new_vis_rgn, window_rect ); + if (subtract_region( tmp, new_vis_rgn, tmp )) + { + offset_region( tmp, -window_rect->left, -window_rect->top ); + add_update_region( win, tmp ); + } + else free_region( tmp ); + } + } + + /* expose/validate new client areas + children */ + + /* FIXME: expose everything for now */ + if (memcmp( client_rect, &old_client_rect, sizeof(old_client_rect) )) + redraw_window( win, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN ); + +done: + free_region( new_vis_rgn ); + clear_error(); /* we ignore out of memory errors once the new rects have been set */ +} + /* create a window */ DECL_HANDLER(create_window) @@ -881,6 +1322,9 @@ DECL_HANDLER(set_window_info) if (req->flags & SET_WIN_USERDATA) win->user_data = req->user_data; if (req->flags & SET_WIN_EXTRA) memcpy( win->extra_bytes + req->extra_offset, &req->extra_value, req->extra_size ); + + /* changing window style triggers a non-client paint */ + if (req->flags & SET_WIN_STYLE) win->paint_flags |= PAINT_NONCLIENT; } @@ -987,16 +1431,53 @@ DECL_HANDLER(get_window_tree) } -/* set the window and client rectangles of a window */ -DECL_HANDLER(set_window_rectangles) +/* set the position and Z order of a window */ +DECL_HANDLER(set_window_pos) { + struct window *previous = NULL; + struct window *top = top_window; struct window *win = get_window( req->handle ); + unsigned int flags = req->flags; - if (win) + if (!win) return; + if (!win->parent) flags |= SWP_NOZORDER; /* no Z order for the desktop */ + + if (req->top_win) { - win->window_rect = req->window; - win->client_rect = req->client; + if (!(top = get_window( req->top_win ))) return; } + + if (!(flags & SWP_NOZORDER)) + { + if (!req->previous) /* special case: HWND_TOP */ + { + if (win->parent->first_child == win) flags |= SWP_NOZORDER; + } + else if (req->previous == (user_handle_t)1) /* special case: HWND_BOTTOM */ + { + previous = win->parent->last_child; + } + else + { + if (!(previous = get_window( req->previous ))) return; + /* previous must be a sibling */ + if (previous->parent != win->parent) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + } + if (previous == win) flags |= SWP_NOZORDER; /* nothing to do */ + } + + if (!validate_window_rectangles( &req->window, &req->client )) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + set_window_pos( win, top, previous, flags, req->redraw_flags, &req->window, &req->client ); + reply->new_style = win->style; } @@ -1048,20 +1529,6 @@ DECL_HANDLER(set_window_text) } -/* increment the window paint count */ -DECL_HANDLER(inc_window_paint_count) -{ - struct window *win = get_window( req->handle ); - - if (win && win->thread) - { - int old = win->paint_count; - if ((win->paint_count += req->incr) < 0) win->paint_count = 0; - inc_queue_paint_count( win->thread, win->paint_count - old ); - } -} - - /* get the coordinates offset between two windows */ DECL_HANDLER(get_windows_offset) { @@ -1142,6 +1609,86 @@ DECL_HANDLER(set_window_region) } +/* get a window update region */ +DECL_HANDLER(get_update_region) +{ + rectangle_t *data; + unsigned int flags = req->flags; + struct window *win = get_window( req->window ); + + reply->flags = 0; + if (!win || !is_visible( win )) return; + + if ((flags & UPDATE_NONCLIENT) && !(flags & (UPDATE_PAINT|UPDATE_INTERNALPAINT))) + { + /* non-client painting must be delayed if one of the parents is going to + * be repainted and doesn't clip children */ + struct window *ptr; + + for (ptr = win->parent; ptr && ptr != top_window; ptr = ptr->parent) + { + if (!(ptr->style & WS_CLIPCHILDREN) && win_needs_repaint( ptr )) + return; + } + } + + if (!(reply->flags = get_update_flags( win, flags ))) + { + /* if window doesn't need any repaint, check the children */ + if (!(flags & UPDATE_NOCHILDREN) && + ((flags & UPDATE_ALLCHILDREN) || (win->style & WS_CLIPCHILDREN))) + { + reply->flags = get_child_update_flags( win, flags, &win ); + } + } + + reply->child = win->handle; + + if (flags & UPDATE_NOREGION) return; + + if (win->update_region) + { + if (!(data = get_region_data( win->update_region, get_reply_max_size(), + &reply->total_size ))) return; + set_reply_data_ptr( data, reply->total_size ); + } + + if (reply->flags & (UPDATE_PAINT|UPDATE_INTERNALPAINT)) /* validate everything */ + { + validate_whole_window( win ); + } + else + { + if (reply->flags & UPDATE_NONCLIENT) validate_non_client( win ); + if (reply->flags & UPDATE_ERASE) win->paint_flags &= ~PAINT_ERASE; + } +} + + +/* mark parts of a window as needing a redraw */ +DECL_HANDLER(redraw_window) +{ + struct region *region = NULL; + struct window *win = get_window( req->window ); + + if (!win) return; + if (!is_visible( win )) return; /* nothing to do */ + + if (req->flags & (RDW_VALIDATE|RDW_INVALIDATE)) + { + if (get_req_data_size()) /* no data means whole rectangle */ + { + if (!(region = create_region_from_req_data( get_req_data(), get_req_data_size() ))) + return; + } + } + + redraw_window( win, region, (req->flags & RDW_INVALIDATE) && (req->flags & RDW_FRAME), + req->flags ); + if (region) free_region( region ); +} + + /* set a window property */ DECL_HANDLER(set_window_property) { diff --git a/windows/painting.c b/windows/painting.c index 49de5136bef..dcf6bb1a750 100644 --- a/windows/painting.c +++ b/windows/painting.c @@ -40,904 +40,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); WINE_DECLARE_DEBUG_CHANNEL(nonclient); -/* client rect in window coordinates */ - -#define GETCLIENTRECTW( wnd, r ) (r).left = (wnd)->rectClient.left - (wnd)->rectWindow.left; \ - (r).top = (wnd)->rectClient.top - (wnd)->rectWindow.top; \ - (r).right = (wnd)->rectClient.right - (wnd)->rectWindow.left; \ - (r).bottom = (wnd)->rectClient.bottom - (wnd)->rectWindow.top - - /* PAINT_RedrawWindow() control flags */ -#define RDW_EX_DELAY_NCPAINT 0x0020 - - /* WIN_UpdateNCRgn() flags */ -#define UNC_CHECK 0x0001 -#define UNC_ENTIRE 0x0002 -#define UNC_REGION 0x0004 -#define UNC_UPDATE 0x0008 -#define UNC_DELAY_NCPAINT 0x0010 -#define UNC_IN_BEGINPAINT 0x0020 - HPALETTE (WINAPI *pfnGDISelectPalette)(HDC hdc, HPALETTE hpal, WORD bkgnd ) = NULL; UINT (WINAPI *pfnGDIRealizePalette)(HDC hdc) = NULL; -/*********************************************************************** - * add_paint_count - * - * Add an increment (normally 1 or -1) to the current paint count of a window. - */ -static void add_paint_count( HWND hwnd, int incr ) -{ - SERVER_START_REQ( inc_window_paint_count ) - { - req->handle = hwnd; - req->incr = incr; - wine_server_call( req ); - } - SERVER_END_REQ; -} - - -/*********************************************************************** - * crop_rgn - * - * hSrc: Region to crop. - * lpRect: Clipping rectangle. - * - * hDst: Region to hold the result (a new region is created if it's 0). - * Allowed to be the same region as hSrc in which case everything - * will be done in place, with no memory reallocations. - * - * Returns: hDst if success, 0 otherwise. - */ -static HRGN crop_rgn( HRGN hDst, HRGN hSrc, const RECT *rect ) -{ - HRGN h = CreateRectRgnIndirect( rect ); - if (hDst == 0) hDst = h; - CombineRgn( hDst, hSrc, h, RGN_AND ); - if (hDst != h) DeleteObject( h ); - return hDst; -} - - -/*********************************************************************** - * WIN_HaveToDelayNCPAINT - * - * Currently, in the Wine painting mechanism, the WM_NCPAINT message - * is generated as soon as a region intersecting the non-client area - * of a window is invalidated. - * - * This technique will work fine for all windows whose parents - * have the WS_CLIPCHILDREN style. When the parents have that style, - * they are not going to override the contents of their children. - * However, when the parent doesn't have that style, Windows relies - * on a "painter's algorithm" to display the contents of the windows. - * That is, windows are painted from back to front. This includes the - * non-client area. - * - * This method looks at the current state of a window to determine - * if the sending of the WM_NCPAINT message should be delayed until - * the BeginPaint call. - * - * PARAMS: - * wndPtr - A Locked window pointer to the window we're - * examining. - * uncFlags - This is the flag passed to the WIN_UpdateNCRgn - * function. This is a shortcut for the cases when - * we already know when to avoid scanning all the - * parents of a window. If you already know that this - * window's NCPAINT should be delayed, set the - * UNC_DELAY_NCPAINT flag for this parameter. - * - * This shortcut behavior is implemented in the - * RDW_Paint() method. - * - */ -static BOOL WIN_HaveToDelayNCPAINT( HWND hwnd, UINT uncFlags) -{ - /* - * Test the shortcut first. (duh) - */ - if (uncFlags & UNC_DELAY_NCPAINT) - return TRUE; - - /* - * The UNC_IN_BEGINPAINT flag is set in the BeginPaint - * method only. This is another shortcut to avoid going - * up the parent's chain of the window to finally - * figure-out that none of them has an invalid region. - */ - if (uncFlags & UNC_IN_BEGINPAINT) - return FALSE; - - /* - * Scan all the parents of this window to find a window - * that doesn't have the WS_CLIPCHILDREN style and that - * has an invalid region. - */ - while ((hwnd = GetAncestor( hwnd, GA_PARENT ))) - { - WND* parentWnd = WIN_FindWndPtr( hwnd ); - if (parentWnd && !(parentWnd->dwStyle & WS_CLIPCHILDREN) && parentWnd->hrgnUpdate) - { - WIN_ReleaseWndPtr( parentWnd ); - return TRUE; - } - WIN_ReleaseWndPtr( parentWnd ); - } - return FALSE; -} - -/*********************************************************************** - * WIN_UpdateNCRgn - * - * Things to do: - * Send WM_NCPAINT if required (when nonclient is invalid or UNC_ENTIRE flag is set) - * Crop hrgnUpdate to a client rect, especially if it 1. - * If UNC_REGION is set return update region for the client rect. - * - * NOTE: UNC_REGION is mainly for the RDW_Paint() chunk that sends WM_ERASEBKGND message. - * The trick is that when the returned region handle may be different from hRgn. - * In this case the old hRgn must be considered gone. BUT, if the returned value - * is 1 then the hRgn is preserved and RDW_Paint() will have to get - * a DC without extra clipping region. - */ -static HRGN WIN_UpdateNCRgn(WND* wnd, HRGN hRgn, UINT uncFlags ) -{ - RECT r; - HRGN hClip = 0; - HRGN hrgnRet = 0; - - TRACE_(nonclient)("hwnd %p [%p] hrgn %p, unc %04x, ncf %i\n", - wnd->hwndSelf, wnd->hrgnUpdate, hRgn, uncFlags, wnd->flags & WIN_NEEDS_NCPAINT); - - /* desktop window doesn't have a nonclient area */ - if(wnd->hwndSelf == GetDesktopWindow()) - { - wnd->flags &= ~WIN_NEEDS_NCPAINT; - if( wnd->hrgnUpdate > (HRGN)1 ) - { - if (!hRgn) hRgn = CreateRectRgn( 0, 0, 0, 0 ); - CombineRgn( hRgn, wnd->hrgnUpdate, 0, RGN_COPY ); - hrgnRet = hRgn; - } - else - { - hrgnRet = wnd->hrgnUpdate; - } - return hrgnRet; - } - - if ((wnd->hwndSelf == GetForegroundWindow()) && - !(wnd->flags & WIN_NCACTIVATED) ) - { - wnd->flags |= WIN_NCACTIVATED; - uncFlags |= UNC_ENTIRE; - } - - /* - * If the window's non-client area needs to be painted, - */ - if ( ( wnd->flags & WIN_NEEDS_NCPAINT ) && - !WIN_HaveToDelayNCPAINT(wnd->hwndSelf, uncFlags) ) - { - RECT r2, r3; - - wnd->flags &= ~WIN_NEEDS_NCPAINT; - GETCLIENTRECTW( wnd, r ); - - TRACE_(nonclient)( "\tclient box (%ld,%ld-%ld,%ld), hrgnUpdate %p\n", - r.left, r.top, r.right, r.bottom, wnd->hrgnUpdate ); - if( wnd->hrgnUpdate > (HRGN)1 ) - { - /* Check if update rgn overlaps with nonclient area */ - - GetRgnBox( wnd->hrgnUpdate, &r2 ); - UnionRect( &r3, &r2, &r ); - if( r3.left != r.left || r3.top != r.top || - r3.right != r.right || r3.bottom != r.bottom ) /* it does */ - { - /* crop hrgnUpdate, save old one in hClip - the only - * case that places a valid region handle in hClip */ - - hClip = wnd->hrgnUpdate; - wnd->hrgnUpdate = crop_rgn( hRgn, hClip, &r ); - if( uncFlags & UNC_REGION ) hrgnRet = hClip; - } - - if( uncFlags & UNC_CHECK ) - { - GetRgnBox( wnd->hrgnUpdate, &r3 ); - if( IsRectEmpty( &r3 ) ) - { - /* delete the update region since all invalid - * parts were in the nonclient area */ - - DeleteObject( wnd->hrgnUpdate ); - wnd->hrgnUpdate = 0; - if(!(wnd->flags & WIN_INTERNAL_PAINT)) - add_paint_count( wnd->hwndSelf, -1 ); - - wnd->flags &= ~WIN_NEEDS_ERASEBKGND; - } - } - - if(!hClip && wnd->hrgnUpdate ) goto copyrgn; - } - else - if( wnd->hrgnUpdate == (HRGN)1 )/* entire window */ - { - if( uncFlags & UNC_UPDATE ) wnd->hrgnUpdate = CreateRectRgnIndirect( &r ); - if( uncFlags & UNC_REGION ) hrgnRet = (HRGN)1; - uncFlags |= UNC_ENTIRE; - } - } - else /* no WM_NCPAINT unless forced */ - { - if( wnd->hrgnUpdate > (HRGN)1 ) - { -copyrgn: - if( uncFlags & UNC_REGION ) - { - if (!hRgn) hRgn = CreateRectRgn( 0, 0, 0, 0 ); - CombineRgn( hRgn, wnd->hrgnUpdate, 0, RGN_COPY ); - hrgnRet = hRgn; - } - } - else - if( wnd->hrgnUpdate == (HRGN)1 && (uncFlags & UNC_UPDATE) ) - { - GETCLIENTRECTW( wnd, r ); - wnd->hrgnUpdate = CreateRectRgnIndirect( &r ); - if( uncFlags & UNC_REGION ) hrgnRet = (HRGN)1; - } - } - - if(!hClip && (uncFlags & UNC_ENTIRE) ) - { - /* still don't do anything if there is no nonclient area */ - hClip = (HRGN)(memcmp( &wnd->rectWindow, &wnd->rectClient, sizeof(RECT) ) != 0); - } - - if( hClip ) /* NOTE: WM_NCPAINT allows wParam to be 1 */ - { - if ( hClip == hrgnRet && hrgnRet > (HRGN)1 ) { - hClip = CreateRectRgn( 0, 0, 0, 0 ); - CombineRgn( hClip, hrgnRet, 0, RGN_COPY ); - } - - SendMessageA( wnd->hwndSelf, WM_NCPAINT, (WPARAM)hClip, 0L ); - if( (hClip > (HRGN)1) && (hClip != hRgn) && (hClip != hrgnRet) ) - DeleteObject( hClip ); - /* - * Since all Window locks are suspended while processing the WM_NCPAINT - * we want to make sure the window still exists before continuing. - */ - if (!IsWindow(wnd->hwndSelf)) - { - DeleteObject(hrgnRet); - hrgnRet=0; - } - } - - TRACE_(nonclient)("returning %p (hClip = %p, hrgnUpdate = %p)\n", hrgnRet, hClip, wnd->hrgnUpdate ); - - return hrgnRet; -} - - -/*********************************************************************** - * RDW_ValidateParent [RDW_UpdateRgns() helper] - * - * Validate the portions of parents that are covered by a validated child - * wndPtr = child - */ -static void RDW_ValidateParent(WND *wndChild) -{ - HWND parent; - HRGN hrg; - - if (wndChild->hrgnUpdate == (HRGN)1 ) { - RECT r; - r.left = 0; - r.top = 0; - r.right = wndChild->rectWindow.right - wndChild->rectWindow.left; - r.bottom = wndChild->rectWindow.bottom - wndChild->rectWindow.top; - hrg = CreateRectRgnIndirect( &r ); - } else - hrg = wndChild->hrgnUpdate; - - parent = GetAncestor( wndChild->hwndSelf, GA_PARENT ); - while (parent && parent != GetDesktopWindow()) - { - WND *wndParent = WIN_FindWndPtr( parent ); - if (wndParent && !(wndParent->dwStyle & WS_CLIPCHILDREN)) - { - if (wndParent->hrgnUpdate != 0) - { - POINT ptOffset; - RECT rect, rectParent; - if( wndParent->hrgnUpdate == (HRGN)1 ) - { - RECT r; - - r.left = 0; - r.top = 0; - r.right = wndParent->rectWindow.right - wndParent->rectWindow.left; - r.bottom = wndParent->rectWindow.bottom - wndParent->rectWindow.top; - - wndParent->hrgnUpdate = CreateRectRgnIndirect( &r ); - } - /* we must offset the child region by the offset of the child rect in the parent */ - GetWindowRect(wndParent->hwndSelf, &rectParent); - GetWindowRect(wndChild->hwndSelf, &rect); - ptOffset.x = rect.left - rectParent.left; - ptOffset.y = rect.top - rectParent.top; - OffsetRgn( hrg, ptOffset.x, ptOffset.y ); - if (CombineRgn( wndParent->hrgnUpdate, wndParent->hrgnUpdate, hrg, RGN_DIFF ) == NULLREGION) - { - /* the update region has become empty */ - DeleteObject( wndParent->hrgnUpdate ); - wndParent->hrgnUpdate = 0; - wndParent->flags &= ~WIN_NEEDS_ERASEBKGND; - if( !(wndParent->flags & WIN_INTERNAL_PAINT) ) - add_paint_count( wndParent->hwndSelf, -1 ); - } - OffsetRgn( hrg, -ptOffset.x, -ptOffset.y ); - } - } - WIN_ReleaseWndPtr( wndParent ); - parent = GetAncestor( parent, GA_PARENT ); - } - if (hrg != wndChild->hrgnUpdate) DeleteObject( hrg ); -} - -/*********************************************************************** - * RDW_UpdateRgns [RedrawWindow() helper] - * - * Walks the window tree and adds/removes parts of the hRgn to/from update - * regions of windows that overlap it. Also, manages internal paint flags. - * - * NOTE: Walks the window tree so the caller must lock it. - * MUST preserve hRgn (can modify but then has to restore). - */ -static void RDW_UpdateRgns( WND* wndPtr, HRGN hRgn, UINT flags, BOOL firstRecursLevel ) -{ - /* - * Called only when one of the following is set: - * (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) - */ - - BOOL bHadOne = wndPtr->hrgnUpdate && hRgn; - BOOL bChildren = (!(flags & RDW_NOCHILDREN) && !(wndPtr->dwStyle & WS_MINIMIZE) && - ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) ); - RECT r; - - r.left = 0; - r.top = 0; - r.right = wndPtr->rectWindow.right - wndPtr->rectWindow.left; - r.bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top; - - TRACE("\thwnd %p [%p] -> hrgn [%p], flags [%04x]\n", wndPtr->hwndSelf, wndPtr->hrgnUpdate, hRgn, flags ); - - if( flags & RDW_INVALIDATE ) - { - if( hRgn > (HRGN)1 ) - { - switch ((UINT)wndPtr->hrgnUpdate) - { - default: - CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hRgn, RGN_OR ); - /* fall through */ - case 0: - wndPtr->hrgnUpdate = crop_rgn( wndPtr->hrgnUpdate, - wndPtr->hrgnUpdate ? wndPtr->hrgnUpdate : hRgn, - &r ); - if( !bHadOne ) - { - GetRgnBox( wndPtr->hrgnUpdate, &r ); - if( IsRectEmpty( &r ) ) - { - DeleteObject( wndPtr->hrgnUpdate ); - wndPtr->hrgnUpdate = 0; - goto end; - } - } - break; - case 1: /* already an entire window */ - break; - } - } - else if( hRgn == (HRGN)1 ) - { - if( wndPtr->hrgnUpdate > (HRGN)1 ) - DeleteObject( wndPtr->hrgnUpdate ); - wndPtr->hrgnUpdate = (HRGN)1; - } - else - { - /* hRgn is zero */ - if( wndPtr->hrgnUpdate > (HRGN)1) - { - GetRgnBox( wndPtr->hrgnUpdate, &r ); - if( IsRectEmpty( &r ) ) - { - DeleteObject( wndPtr->hrgnUpdate ); - wndPtr->hrgnUpdate = 0; - goto end; - } - } - hRgn = wndPtr->hrgnUpdate; /* this is a trick that depends - * on code in RDW_Paint() */ - } - - if( !bHadOne && !(wndPtr->flags & WIN_INTERNAL_PAINT) ) - add_paint_count( wndPtr->hwndSelf, 1 ); - - if (flags & RDW_FRAME) wndPtr->flags |= WIN_NEEDS_NCPAINT; - if (flags & RDW_ERASE) wndPtr->flags |= WIN_NEEDS_ERASEBKGND; - flags |= RDW_FRAME; - } - else if( flags & RDW_VALIDATE ) - { - if( wndPtr->hrgnUpdate ) - { - if( hRgn > (HRGN)1 ) - { - if( wndPtr->hrgnUpdate == (HRGN)1 ) - wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r ); - - if( CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hRgn, RGN_DIFF ) - == NULLREGION ) - { - DeleteObject( wndPtr->hrgnUpdate ); - wndPtr->hrgnUpdate = 0; - } - } - else /* validate everything */ - { - if( wndPtr->hrgnUpdate > (HRGN)1 ) DeleteObject( wndPtr->hrgnUpdate ); - wndPtr->hrgnUpdate = 0; - } - - if( !wndPtr->hrgnUpdate ) - { - wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND; - if( !(wndPtr->flags & WIN_INTERNAL_PAINT) ) - add_paint_count( wndPtr->hwndSelf, -1 ); - } - } - - if (flags & RDW_NOFRAME) wndPtr->flags &= ~WIN_NEEDS_NCPAINT; - if (flags & RDW_NOERASE) wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND; - - } - - if ((firstRecursLevel) && (wndPtr->hrgnUpdate != 0) && (flags & RDW_UPDATENOW)) - RDW_ValidateParent(wndPtr); /* validate parent covered by region */ - - /* in/validate child windows that intersect with the region if it - * is a valid handle. */ - - if( flags & (RDW_INVALIDATE | RDW_VALIDATE) ) - { - HWND *list; - if( hRgn > (HRGN)1 && bChildren && (list = WIN_ListChildren( wndPtr->hwndSelf ))) - { - POINT ptTotal, prevOrigin = {0,0}; - POINT ptClient; - INT i; - - ptClient.x = wndPtr->rectClient.left - wndPtr->rectWindow.left; - ptClient.y = wndPtr->rectClient.top - wndPtr->rectWindow.top; - - for(i = ptTotal.x = ptTotal.y = 0; list[i]; i++) - { - WND *wnd = WIN_FindWndPtr( list[i] ); - if (!wnd) continue; - if( wnd->dwStyle & WS_VISIBLE ) - { - POINT ptOffset; - - r.left = wnd->rectWindow.left + ptClient.x; - r.right = wnd->rectWindow.right + ptClient.x; - r.top = wnd->rectWindow.top + ptClient.y; - r.bottom = wnd->rectWindow.bottom + ptClient.y; - - ptOffset.x = r.left - prevOrigin.x; - ptOffset.y = r.top - prevOrigin.y; - OffsetRect( &r, -ptTotal.x, -ptTotal.y ); - - if( RectInRegion( hRgn, &r ) ) - { - OffsetRgn( hRgn, -ptOffset.x, -ptOffset.y ); - RDW_UpdateRgns( wnd, hRgn, flags, FALSE ); - prevOrigin.x = r.left + ptTotal.x; - prevOrigin.y = r.top + ptTotal.y; - ptTotal.x += ptOffset.x; - ptTotal.y += ptOffset.y; - } - } - WIN_ReleaseWndPtr( wnd ); - } - HeapFree( GetProcessHeap(), 0, list ); - OffsetRgn( hRgn, ptTotal.x, ptTotal.y ); - bChildren = 0; - } - } - - /* handle hRgn == 1 (alias for entire window) and/or internal paint recursion */ - - if( bChildren ) - { - HWND *list; - if ((list = WIN_ListChildren( wndPtr->hwndSelf ))) - { - INT i; - for (i = 0; list[i]; i++) - { - WND *wnd = WIN_FindWndPtr( list[i] ); - if (!wnd) continue; - if( wnd->dwStyle & WS_VISIBLE ) - RDW_UpdateRgns( wnd, hRgn, flags, FALSE ); - WIN_ReleaseWndPtr( wnd ); - } - HeapFree( GetProcessHeap(), 0, list ); - } - } - -end: - - /* Set/clear internal paint flag */ - - if (flags & RDW_INTERNALPAINT) - { - if ( !wndPtr->hrgnUpdate && !(wndPtr->flags & WIN_INTERNAL_PAINT)) - add_paint_count( wndPtr->hwndSelf, 1 ); - wndPtr->flags |= WIN_INTERNAL_PAINT; - } - else if (flags & RDW_NOINTERNALPAINT) - { - if ( !wndPtr->hrgnUpdate && (wndPtr->flags & WIN_INTERNAL_PAINT)) - add_paint_count( wndPtr->hwndSelf, -1 ); - wndPtr->flags &= ~WIN_INTERNAL_PAINT; - } -} - -/*********************************************************************** - * RDW_Paint [RedrawWindow() helper] - * - * Walks the window tree and paints/erases windows that have - * nonzero update regions according to redraw flags. hrgn is a scratch - * region passed down during recursion. Must not be 1. - * - */ -static HRGN RDW_Paint( WND* wndPtr, HRGN hrgn, UINT flags, UINT ex ) -{ -/* NOTE: wndPtr is locked by caller. - * - * FIXME: Windows uses WM_SYNCPAINT to cut down the number of intertask - * SendMessage() calls. This is a comment inside DefWindowProc() source - * from 16-bit SDK: - * - * This message avoids lots of inter-app message traffic - * by switching to the other task and continuing the - * recursion there. - * - * wParam = flags - * LOWORD(lParam) = hrgnClip - * HIWORD(lParam) = hwndSkip (not used; always NULL) - * - */ - HDC hDC; - HWND hWnd = wndPtr->hwndSelf; - BOOL bIcon = ((wndPtr->dwStyle & WS_MINIMIZE) && GetClassLongA(hWnd, GCL_HICON)); - - /* Erase/update the window itself ... */ - - TRACE("\thwnd %p [%p] -> hrgn [%p], flags [%04x]\n", hWnd, wndPtr->hrgnUpdate, hrgn, flags ); - - /* - * Check if this window should delay it's processing of WM_NCPAINT. - * See WIN_HaveToDelayNCPAINT for a description of the mechanism - */ - if ((ex & RDW_EX_DELAY_NCPAINT) || WIN_HaveToDelayNCPAINT(wndPtr->hwndSelf, 0) ) - ex |= RDW_EX_DELAY_NCPAINT; - - if (flags & RDW_UPDATENOW) - { - if (wndPtr->hrgnUpdate) SendMessageW( hWnd, WM_PAINT, 0, 0 ); - } - else if (flags & RDW_ERASENOW) - { - UINT dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN | DCX_WINDOWPAINT | DCX_CACHE; - HRGN hrgnRet; - - hrgnRet = WIN_UpdateNCRgn(wndPtr, - hrgn, - UNC_REGION | UNC_CHECK | - ((ex & RDW_EX_DELAY_NCPAINT) ? UNC_DELAY_NCPAINT : 0) ); - - if( hrgnRet ) - { - if( hrgnRet > (HRGN)1 ) hrgn = hrgnRet; else hrgnRet = 0; /* entire client */ - if( wndPtr->flags & WIN_NEEDS_ERASEBKGND ) - { - if( bIcon ) dcx |= DCX_WINDOW; - else - if( hrgnRet ) - OffsetRgn( hrgnRet, wndPtr->rectWindow.left - wndPtr->rectClient.left, - wndPtr->rectWindow.top - wndPtr->rectClient.top); - else - dcx &= ~DCX_INTERSECTRGN; - if (( hDC = GetDCEx( hWnd, hrgnRet, dcx )) ) - { - if (SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 )) - wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND; - ReleaseDC( hWnd, hDC ); - } - } - } - } - - if( !IsWindow(hWnd) ) return hrgn; - - /* ... and its child windows */ - - if(!(flags & RDW_NOCHILDREN) && !(wndPtr->dwStyle & WS_MINIMIZE) && - ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) ) - { - HWND *list, *phwnd; - - if( (list = WIN_ListChildren( wndPtr->hwndSelf )) ) - { - for (phwnd = list; *phwnd; phwnd++) - { - if (!(wndPtr = WIN_FindWndPtr( *phwnd ))) continue; - if ( (wndPtr->dwStyle & WS_VISIBLE) && - (wndPtr->hrgnUpdate || (wndPtr->flags & WIN_INTERNAL_PAINT)) ) - hrgn = RDW_Paint( wndPtr, hrgn, flags, ex ); - WIN_ReleaseWndPtr(wndPtr); - } - HeapFree( GetProcessHeap(), 0, list ); - } - } - - return hrgn; -} - - -/*********************************************************************** - * dump_rdw_flags - */ -static void dump_rdw_flags(UINT flags) -{ - TRACE("flags:"); - if (flags & RDW_INVALIDATE) TRACE(" RDW_INVALIDATE"); - if (flags & RDW_INTERNALPAINT) TRACE(" RDW_INTERNALPAINT"); - if (flags & RDW_ERASE) TRACE(" RDW_ERASE"); - if (flags & RDW_VALIDATE) TRACE(" RDW_VALIDATE"); - if (flags & RDW_NOINTERNALPAINT) TRACE(" RDW_NOINTERNALPAINT"); - if (flags & RDW_NOERASE) TRACE(" RDW_NOERASE"); - if (flags & RDW_NOCHILDREN) TRACE(" RDW_NOCHILDREN"); - if (flags & RDW_ALLCHILDREN) TRACE(" RDW_ALLCHILDREN"); - if (flags & RDW_UPDATENOW) TRACE(" RDW_UPDATENOW"); - if (flags & RDW_ERASENOW) TRACE(" RDW_ERASENOW"); - if (flags & RDW_FRAME) TRACE(" RDW_FRAME"); - if (flags & RDW_NOFRAME) TRACE(" RDW_NOFRAME"); - -#define RDW_FLAGS \ - (RDW_INVALIDATE | \ - RDW_INTERNALPAINT | \ - RDW_ERASE | \ - RDW_VALIDATE | \ - RDW_NOINTERNALPAINT | \ - RDW_NOERASE | \ - RDW_NOCHILDREN | \ - RDW_ALLCHILDREN | \ - RDW_UPDATENOW | \ - RDW_ERASENOW | \ - RDW_FRAME | \ - RDW_NOFRAME) - - if (flags & ~RDW_FLAGS) TRACE(" %04x", flags & ~RDW_FLAGS); - TRACE("\n"); -#undef RDW_FLAGS -} - - -/*********************************************************************** - * RedrawWindow (USER32.@) - */ -BOOL WINAPI RedrawWindow( HWND hwnd, const RECT *rectUpdate, - HRGN hrgnUpdate, UINT flags ) -{ - HRGN hRgn = 0; - RECT r, r2; - POINT pt; - WND* wndPtr; - - if (!hwnd) hwnd = GetDesktopWindow(); - - /* check if the window or its parents are visible/not minimized */ - - if (!WIN_IsWindowDrawable( hwnd, !(flags & RDW_FRAME) )) return TRUE; - - /* process pending events and messages before painting */ - if (flags & RDW_UPDATENOW) - MsgWaitForMultipleObjects( 0, NULL, FALSE, 0, QS_ALLINPUT ); - - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE; - if (TRACE_ON(win)) - { - if( hrgnUpdate ) - { - GetRgnBox( hrgnUpdate, &r ); - TRACE( "%p (%p) NULL %p box (%ld,%ld-%ld,%ld) flags=%04x\n", - hwnd, wndPtr->hrgnUpdate, hrgnUpdate, r.left, r.top, r.right, r.bottom, flags ); - } - else - { - if( rectUpdate ) - r = *rectUpdate; - else - SetRectEmpty( &r ); - TRACE( "%p (%p) %s %ld,%ld-%ld,%ld %p flags=%04x\n", - hwnd, wndPtr->hrgnUpdate, rectUpdate ? "rect" : "NULL", r.left, - r.top, r.right, r.bottom, hrgnUpdate, flags ); - } - dump_rdw_flags(flags); - } - - /* prepare an update region in window coordinates */ - - if (((flags & (RDW_INVALIDATE|RDW_FRAME)) == (RDW_INVALIDATE|RDW_FRAME)) || - ((flags & (RDW_VALIDATE|RDW_NOFRAME)) == (RDW_VALIDATE|RDW_NOFRAME))) - r = wndPtr->rectWindow; - else - r = wndPtr->rectClient; - - pt.x = wndPtr->rectClient.left - wndPtr->rectWindow.left; - pt.y = wndPtr->rectClient.top - wndPtr->rectWindow.top; - OffsetRect( &r, -wndPtr->rectClient.left, -wndPtr->rectClient.top ); - - if (flags & RDW_INVALIDATE) /* ------------------------- Invalidate */ - { - /* If the window doesn't have hrgnUpdate we leave hRgn zero - * and put a new region straight into wndPtr->hrgnUpdate - * so that RDW_UpdateRgns() won't have to do any extra work. - */ - - if( hrgnUpdate ) - { - if( wndPtr->hrgnUpdate ) - { - hRgn = CreateRectRgn( 0, 0, 0, 0 ); - CombineRgn( hRgn, hrgnUpdate, 0, RGN_COPY ); - OffsetRgn( hRgn, pt.x, pt.y ); - } - else - { - wndPtr->hrgnUpdate = crop_rgn( 0, hrgnUpdate, &r ); - OffsetRgn( wndPtr->hrgnUpdate, pt.x, pt.y ); - } - } - else if( rectUpdate ) - { - if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END; - OffsetRect( &r2, pt.x, pt.y ); - if( wndPtr->hrgnUpdate == 0 ) - wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r2 ); - else - hRgn = CreateRectRgnIndirect( &r2 ); - } - else /* entire window or client depending on RDW_FRAME */ - { - if( flags & RDW_FRAME ) - { - if (wndPtr->hrgnUpdate) hRgn = (HRGN)1; - else wndPtr->hrgnUpdate = (HRGN)1; - } - else - { - GETCLIENTRECTW( wndPtr, r2 ); - if( wndPtr->hrgnUpdate == 0 ) - wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r2 ); - else - hRgn = CreateRectRgnIndirect( &r2 ); - } - } - } - else if (flags & RDW_VALIDATE) /* ------------------------- Validate */ - { - /* In this we cannot leave with zero hRgn */ - if( hrgnUpdate ) - { - hRgn = crop_rgn( hRgn, hrgnUpdate, &r ); - OffsetRgn( hRgn, pt.x, pt.y ); - GetRgnBox( hRgn, &r2 ); - if( IsRectEmpty( &r2 ) ) goto END; - } - else if( rectUpdate ) - { - if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END; - OffsetRect( &r2, pt.x, pt.y ); - hRgn = CreateRectRgnIndirect( &r2 ); - } - else /* entire window or client depending on RDW_NOFRAME */ - { - if( flags & RDW_NOFRAME ) - hRgn = (HRGN)1; - else - { - GETCLIENTRECTW( wndPtr, r2 ); - hRgn = CreateRectRgnIndirect( &r2 ); - } - } - } - - /* At this point hRgn is either an update region in window coordinates or 1 or 0 */ - - RDW_UpdateRgns( wndPtr, hRgn, flags, TRUE ); - - /* Erase/update windows, from now on hRgn is a scratch region */ - - hRgn = RDW_Paint( wndPtr, (hRgn == (HRGN)1) ? 0 : hRgn, flags, 0 ); - -END: - if( hRgn > (HRGN)1 && (hRgn != hrgnUpdate) ) - DeleteObject(hRgn ); - WIN_ReleaseWndPtr(wndPtr); - return TRUE; -} - - -/*********************************************************************** - * UpdateWindow (USER32.@) - */ -BOOL WINAPI UpdateWindow( HWND hwnd ) -{ - return RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN ); -} - - -/*********************************************************************** - * InvalidateRgn (USER32.@) - */ -BOOL WINAPI InvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) -{ - return RedrawWindow(hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) ); -} - - -/*********************************************************************** - * InvalidateRect (USER32.@) - */ -BOOL WINAPI InvalidateRect( HWND hwnd, const RECT *rect, BOOL erase ) -{ - return RedrawWindow( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) ); -} - - -/*********************************************************************** - * ValidateRgn (USER32.@) - */ -BOOL WINAPI ValidateRgn( HWND hwnd, HRGN hrgn ) -{ - return RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN ); -} - - -/*********************************************************************** - * ValidateRect (USER32.@) - */ -BOOL WINAPI ValidateRect( HWND hwnd, const RECT *rect ) -{ - return RedrawWindow( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN ); -} - - /*********************************************************************** * SelectPalette (Not a Windows API) */ diff --git a/windows/win.c b/windows/win.c index 338a7488475..cb85c22485e 100644 --- a/windows/win.c +++ b/windows/win.c @@ -698,7 +698,6 @@ BOOL WIN_CreateDesktopWindow(void) pWndDesktop->parent = 0; pWndDesktop->owner = 0; pWndDesktop->text = NULL; - pWndDesktop->hrgnUpdate = 0; pWndDesktop->pVScroll = NULL; pWndDesktop->pHScroll = NULL; pWndDesktop->helpContext = 0; @@ -738,7 +737,6 @@ BOOL WIN_CreateDesktopWindow(void) return FALSE; } - pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND; WIN_ReleaseWndPtr( pWndDesktop ); return TRUE; } @@ -1110,7 +1108,6 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, wndPtr->parent = parent; wndPtr->hInstance = cs->hInstance; wndPtr->text = NULL; - wndPtr->hrgnUpdate = 0; wndPtr->dwStyle = cs->style & ~WS_VISIBLE; wndPtr->dwExStyle = cs->dwExStyle; wndPtr->wIDmenu = 0; @@ -3125,19 +3122,13 @@ BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert ) if (wndPtr->dwStyle & WS_MINIMIZE) { + RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME ); if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED)) { - HDC hDC = GetDC(hWnd); - - if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 )) - wndPtr->flags |= WIN_NEEDS_ERASEBKGND; - - ReleaseDC( hWnd, hDC ); wndPtr->flags |= WIN_NCACTIVATED; } else { - RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME ); wndPtr->flags &= ~WIN_NCACTIVATED; } WIN_ReleaseWndPtr(wndPtr);