diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in index d3c4984f5e6..8007d2fe0ff 100644 --- a/dlls/user/Makefile.in +++ b/dlls/user/Makefile.in @@ -23,6 +23,7 @@ C_SRCS = \ mouse.c \ msg16.c \ network.c \ + painting.c \ property.c \ resource.c \ text.c \ diff --git a/dlls/user/painting.c b/dlls/user/painting.c new file mode 100644 index 00000000000..19fe3f9d1ac --- /dev/null +++ b/dlls/user/painting.c @@ -0,0 +1,231 @@ +/* + * Window painting functions + * + * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard + * Copyright 1999 Alex Korobka + */ +#include + +#include "windef.h" +#include "wingdi.h" +#include "wine/winuser16.h" +#include "wine/server.h" +#include "win.h" +#include "dce.h" +#include "debugtools.h" + +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 + */ +static HRGN copy_rgn( HRGN hSrc ) +{ + if (hSrc > 1) + { + HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 ); + CombineRgn( hrgn, hSrc, 0, RGN_COPY ); + return hrgn; + } + return hSrc; +} + + +/*********************************************************************** + * get_update_regions + * + * Return update regions for the whole window and for the client area. + */ +static void get_update_regions( WND *win, HRGN *whole_rgn, HRGN *client_rgn ) +{ + if (win->hrgnUpdate > 1) + { + RECT client, update; + + /* check if update rgn overlaps with nonclient area */ + GetRgnBox( win->hrgnUpdate, &update ); + client = win->rectClient; + OffsetRect( &client, -win->rectWindow.left, -win->rectWindow.top ); + + if (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) + { + DeleteObject( *client_rgn ); + *client_rgn = 0; + } + } + else + { + *whole_rgn = 0; + *client_rgn = copy_rgn( win->hrgnUpdate ); + } + } + else + { + *client_rgn = *whole_rgn = win->hrgnUpdate; /* 0 or 1 */ + } +} + + +/*********************************************************************** + * begin_ncpaint + * + * 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 ) +{ + HRGN whole_rgn, client_rgn; + WND *wnd = WIN_GetPtr( hwnd ); + + if (!wnd || wnd == WND_OTHER_PROCESS) return 0; + + TRACE("hwnd %04x [%04x] 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 */ + { + WIN_ReleasePtr( wnd ); + SendMessageA( hwnd, WM_NCPAINT, whole_rgn, 0 ); + if (whole_rgn > 1) DeleteObject( whole_rgn ); + /* make sure the window still exists before continuing */ + if (!(wnd = WIN_GetPtr( hwnd )) || wnd == WND_OTHER_PROCESS) + { + if (client_rgn > 1) DeleteObject( client_rgn ); + return 0; + } + } + + if (wnd->hrgnUpdate || (wnd->flags & WIN_INTERNAL_PAINT)) add_paint_count( hwnd, -1 ); + if (wnd->hrgnUpdate > 1) DeleteObject( wnd->hrgnUpdate ); + wnd->hrgnUpdate = 0; + wnd->flags &= ~(WIN_INTERNAL_PAINT | WIN_NEEDS_NCPAINT | WIN_NEEDS_BEGINPAINT); + if (client_rgn > 1) OffsetRgn( client_rgn, wnd->rectWindow.left - wnd->rectClient.left, + wnd->rectWindow.top - wnd->rectClient.top ); + WIN_ReleasePtr( wnd ); + return client_rgn; +} + + +/*********************************************************************** + * BeginPaint (USER32.@) + */ +HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps ) +{ + INT dcx_flags; + BOOL bIcon; + HRGN hrgnUpdate; + RECT clipRect, clientRect; + HWND full_handle; + WND *wndPtr; + + if (!(full_handle = WIN_IsCurrentThread( hwnd ))) + { + if (IsWindow(hwnd)) + FIXME( "window %x belongs to other thread\n", hwnd ); + return 0; + } + 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)); + + 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 > 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 == 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=%04x\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 = %x box = (%i,%i - %i,%i)\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); + wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND; + WIN_ReleasePtr( wndPtr ); + + if (!lps->fErase) + lps->fErase = !SendMessageA( hwnd, bIcon ? WM_ICONERASEBKGND : WM_ERASEBKGND, + (WPARAM)lps->hdc, 0 ); + return lps->hdc; +} + + +/*********************************************************************** + * EndPaint (USER32.@) + */ +BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps ) +{ + ReleaseDC( hwnd, lps->hdc ); + ShowCaret( hwnd ); + return TRUE; +} diff --git a/dlls/user/wnd16.c b/dlls/user/wnd16.c index 254ac22dbf9..96b4fcd7206 100644 --- a/dlls/user/wnd16.c +++ b/dlls/user/wnd16.c @@ -214,6 +214,38 @@ INT16 WINAPI GetWindowTextLength16( HWND16 hwnd ) } +/*********************************************************************** + * BeginPaint (USER.39) + */ +HDC16 WINAPI BeginPaint16( HWND16 hwnd, LPPAINTSTRUCT16 lps ) +{ + PAINTSTRUCT ps; + + BeginPaint( WIN_Handle32(hwnd), &ps ); + lps->hdc = ps.hdc; + lps->fErase = ps.fErase; + lps->rcPaint.top = ps.rcPaint.top; + lps->rcPaint.left = ps.rcPaint.left; + lps->rcPaint.right = ps.rcPaint.right; + lps->rcPaint.bottom = ps.rcPaint.bottom; + lps->fRestore = ps.fRestore; + lps->fIncUpdate = ps.fIncUpdate; + return lps->hdc; +} + + +/*********************************************************************** + * EndPaint (USER.40) + */ +BOOL16 WINAPI EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps ) +{ + PAINTSTRUCT ps; + + ps.hdc = lps->hdc; + return EndPaint( WIN_Handle32(hwnd), &ps ); +} + + /************************************************************************** * ShowWindow (USER.42) */ diff --git a/windows/painting.c b/windows/painting.c index b6f4754d4c6..5eda6dba5dd 100644 --- a/windows/painting.c +++ b/windows/painting.c @@ -278,153 +278,6 @@ copyrgn: } -/*********************************************************************** - * BeginPaint (USER.39) - */ -HDC16 WINAPI BeginPaint16( HWND16 hwnd, LPPAINTSTRUCT16 lps ) -{ - PAINTSTRUCT ps; - - BeginPaint( WIN_Handle32(hwnd), &ps ); - lps->hdc = ps.hdc; - lps->fErase = ps.fErase; - lps->rcPaint.top = ps.rcPaint.top; - lps->rcPaint.left = ps.rcPaint.left; - lps->rcPaint.right = ps.rcPaint.right; - lps->rcPaint.bottom = ps.rcPaint.bottom; - lps->fRestore = ps.fRestore; - lps->fIncUpdate = ps.fIncUpdate; - return lps->hdc; -} - - -/*********************************************************************** - * BeginPaint (USER32.@) - */ -HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps ) -{ - BOOL bIcon; - HRGN hrgnUpdate; - RECT clipRect, clientRect; - HWND full_handle; - WND *wndPtr; - - if (!(full_handle = WIN_IsCurrentThread( hwnd ))) - { - if (IsWindow(hwnd)) - FIXME( "window %x belongs to other thread\n", hwnd ); - return 0; - } - hwnd = full_handle; - - bIcon = (IsIconic(hwnd) && GetClassLongA(hwnd, GCL_HICON)); - - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0; - wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT; - - /* send WM_NCPAINT and make sure hrgnUpdate is a valid rgn handle */ - WIN_UpdateNCRgn( wndPtr, 0, UNC_UPDATE | UNC_IN_BEGINPAINT); - - /* - * Make sure the window is still a window. All window locks are suspended - * when the WM_NCPAINT is sent. - */ - if (!IsWindow( hwnd )) - { - WIN_ReleaseWndPtr(wndPtr); - return 0; - } - - if( ((hrgnUpdate = wndPtr->hrgnUpdate) != 0) || (wndPtr->flags & WIN_INTERNAL_PAINT)) - add_paint_count( hwnd, -1 ); - - wndPtr->hrgnUpdate = 0; - wndPtr->flags &= ~WIN_INTERNAL_PAINT; - - WIN_ReleaseWndPtr(wndPtr); - - HideCaret( hwnd ); - - TRACE("hrgnUpdate = %04x, \n", hrgnUpdate); - - if (GetClassLongA( hwnd, GCL_STYLE ) & CS_PARENTDC) - { - /* Don't clip the output to the update region for CS_PARENTDC window */ - if( hrgnUpdate ) - DeleteObject(hrgnUpdate); - lps->hdc = GetDCEx( hwnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE | - (bIcon ? DCX_WINDOW : 0) ); - } - else - { - if( hrgnUpdate ) /* convert to client coordinates */ - OffsetRgn( hrgnUpdate, wndPtr->rectWindow.left - wndPtr->rectClient.left, - wndPtr->rectWindow.top - wndPtr->rectClient.top ); - lps->hdc = GetDCEx(hwnd, hrgnUpdate, DCX_INTERSECTRGN | - DCX_WINDOWPAINT | DCX_USESTYLE | (bIcon ? DCX_WINDOW : 0) ); - /* ReleaseDC() in EndPaint() will delete the region */ - } - - TRACE("hdc = %04x\n", lps->hdc); - - if (!lps->hdc) - { - WARN("GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd); - 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("box = (%i,%i - %i,%i)\n", lps->rcPaint.left, lps->rcPaint.top, - lps->rcPaint.right, lps->rcPaint.bottom ); - - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0; - if (wndPtr->flags & WIN_NEEDS_ERASEBKGND) - { - wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND; - lps->fErase = !SendMessageA(hwnd, (bIcon) ? WM_ICONERASEBKGND : WM_ERASEBKGND, - (WPARAM16)lps->hdc, 0 ); - } - else lps->fErase = TRUE; - - WIN_ReleaseWndPtr(wndPtr); - return lps->hdc; -} - - -/*********************************************************************** - * EndPaint (USER.40) - */ -BOOL16 WINAPI EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps ) -{ - ReleaseDC16( hwnd, lps->hdc ); - ShowCaret16( hwnd ); - return TRUE; -} - - -/*********************************************************************** - * EndPaint (USER32.@) - */ -BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps ) -{ - ReleaseDC( hwnd, lps->hdc ); - ShowCaret( hwnd ); - return TRUE; -} - - /*********************************************************************** * RDW_ValidateParent [RDW_UpdateRgns() helper] * @@ -858,8 +711,6 @@ BOOL WINAPI RedrawWindow( HWND hwnd, const RECT *rectUpdate, { if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END; OffsetRect( &r2, pt.x, pt.y ); - -rect2i: if( wndPtr->hrgnUpdate == 0 ) wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r2 ); else @@ -869,14 +720,16 @@ rect2i: { if( flags & RDW_FRAME ) { - if( wndPtr->hrgnUpdate ) - DeleteObject( wndPtr->hrgnUpdate ); - wndPtr->hrgnUpdate = 1; + if (wndPtr->hrgnUpdate) hRgn = 1; + else wndPtr->hrgnUpdate = 1; } else { GETCLIENTRECTW( wndPtr, r2 ); - goto rect2i; + if( wndPtr->hrgnUpdate == 0 ) + wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r2 ); + else + hRgn = CreateRectRgnIndirect( &r2 ); } } }