* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Window painting function
- * FILE: subsystems/win32/win32k/ntuser/painting.c
+ * FILE: win32ss/user/ntuser/painting.c
* PROGRAMER: Filip Navara (xnavara@volny.cz)
*/
#include <win32k.h>
DBG_DEFAULT_CHANNEL(UserPainting);
+BOOL UserExtTextOutW(HDC hdc, INT x, INT y, UINT flags, PRECTL lprc,
+ LPCWSTR lpString, UINT count);
+
/* PRIVATE FUNCTIONS **********************************************************/
/**
{
PWND ParentWnd;
+ if (Child->ExStyle & WS_EX_REDIRECTED)
+ return TRUE;
+
ParentWnd = Child->spwndParent;
while (ParentWnd != NULL)
{
- if (!(ParentWnd->style & WS_VISIBLE) ||
- (ParentWnd->style & WS_MINIMIZE))
- {
- return FALSE;
- }
-
- if (!RECTL_bIntersectRect(WindowRect, WindowRect, &ParentWnd->rcClient))
+ if (!(ParentWnd->style & WS_VISIBLE) ||
+ (ParentWnd->style & WS_MINIMIZE) ||
+ !RECTL_bIntersectRect(WindowRect, WindowRect, &ParentWnd->rcClient) )
{
return FALSE;
}
- /* FIXME: Layered windows. */
+ if (ParentWnd->ExStyle & WS_EX_REDIRECTED)
+ return TRUE;
ParentWnd = ParentWnd->spwndParent;
}
}
BOOL FASTCALL
-IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
+IntValidateParents(PWND Child, BOOL Recurse)
{
+ RECTL ParentRect, Rect;
+ BOOL Start, Ret = TRUE;
PWND ParentWnd = Child;
+ PREGION Rgn = NULL;
if (ParentWnd->style & WS_CHILD)
{
ParentWnd = ParentWnd->spwndParent;
while (ParentWnd->style & WS_CHILD);
}
-// Hax out for drawing issues.
-// if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE;
+ // No pending nonclient paints.
+ if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE;
+
+ Start = TRUE;
ParentWnd = Child->spwndParent;
while (ParentWnd)
{
if (ParentWnd->hrgnUpdate != 0)
{
if (Recurse)
- return FALSE;
+ {
+ Ret = FALSE;
+ break;
+ }
+ // Start with child clipping.
+ if (Start)
+ {
+ Start = FALSE;
+
+ Rect = Child->rcWindow;
+
+ if (!IntIntersectWithParents(Child, &Rect)) break;
+
+ Rgn = IntSysCreateRectpRgnIndirect(&Rect);
+
+ if (Child->hrgnClip)
+ {
+ PREGION RgnClip = REGION_LockRgn(Child->hrgnClip);
+ IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND);
+ REGION_UnlockRgn(RgnClip);
+ }
+ }
+
+ ParentRect = ParentWnd->rcWindow;
+
+ if (!IntIntersectWithParents(ParentWnd, &ParentRect)) break;
IntInvalidateWindows( ParentWnd,
- hValidateRgn,
- RDW_VALIDATE | RDW_NOCHILDREN);
+ Rgn,
+ RDW_VALIDATE | RDW_NOCHILDREN | RDW_NOUPDATEDIRTY);
}
-
ParentWnd = ParentWnd->spwndParent;
}
- return TRUE;
+ if (Rgn) REGION_Delete(Rgn);
+
+ return Ret;
}
/*
Wnd->style & WS_VISIBLE)
{
// For testing, if you see this, break out the Champagne and have a party!
- ERR("SendSyncPaint Wnd in State!\n");
+ TRACE("SendSyncPaint Wnd in State!\n");
if (!IsListEmpty(&ptiWnd->SentMessagesListHead))
{
// Scan sent queue messages to see if we received sync paint messages.
}
if (bSend)
{
- ERR("Sending WM_SYNCPAINT\n");
+ TRACE("Sending WM_SYNCPAINT\n");
// This message has no parameters. But it does! Pass Flags along.
co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SYNCPAINT, Flags, 0);
Wnd->state |= WNDS_SYNCPAINTPENDING;
}
// Send to all the children if this is the desktop window.
- if ( Wnd == UserGetDesktopWindow() )
+ if (UserIsDesktopWindow(Wnd))
{
if ( Flags & RDW_ALLCHILDREN ||
( !(Flags & RDW_NOCHILDREN) && Wnd->style & WS_CLIPCHILDREN))
}
}
-/**
+/*
* @name IntCalcWindowRgn
*
* Get a window or client region.
HRGN hRgnWindow;
if (Client)
- hRgnWindow = IntSysCreateRectRgnIndirect(&Wnd->rcClient);
+ {
+ hRgnWindow = NtGdiCreateRectRgn(
+ Wnd->rcClient.left,
+ Wnd->rcClient.top,
+ Wnd->rcClient.right,
+ Wnd->rcClient.bottom);
+ }
else
- hRgnWindow = IntSysCreateRectRgnIndirect(&Wnd->rcWindow);
+ {
+ hRgnWindow = NtGdiCreateRectRgn(
+ Wnd->rcWindow.left,
+ Wnd->rcWindow.top,
+ Wnd->rcWindow.right,
+ Wnd->rcWindow.bottom);
+ }
if (Wnd->hrgnClip != NULL && !(Wnd->style & WS_MINIMIZE))
{
return hRgnWindow;
}
-/**
+/*
* @name IntGetNCUpdateRgn
*
* Get non-client update region of a window and optionally validate it.
{
HRGN hRgnNonClient;
HRGN hRgnWindow;
- UINT RgnType;
+ UINT RgnType, NcType;
+ RECT update;
if (Window->hrgnUpdate != NULL &&
Window->hrgnUpdate != HRGN_WINDOW)
return HRGN_WINDOW;
}
- RgnType = NtGdiCombineRgn(hRgnNonClient, hRgnNonClient,
- hRgnWindow, RGN_DIFF);
+ NcType = IntGdiGetRgnBox(hRgnNonClient, &update);
+
+ RgnType = NtGdiCombineRgn(hRgnNonClient, hRgnNonClient, hRgnWindow, RGN_DIFF);
+
if (RgnType == ERROR)
{
GreDeleteObject(hRgnWindow);
if (Validate)
{
- if (NtGdiCombineRgn(Window->hrgnUpdate, Window->hrgnUpdate,
- hRgnWindow, RGN_AND) == NULLREGION)
+ if (NtGdiCombineRgn(Window->hrgnUpdate, Window->hrgnUpdate, hRgnWindow, RGN_AND) == NULLREGION)
{
IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
GreDeleteObject(Window->hrgnUpdate);
}
}
+ /* check if update rgn contains complete nonclient area */
+ if (NcType == SIMPLEREGION)
+ {
+ RECT window;
+ IntGetWindowRect( Window, &window );
+
+ if (IntEqualRect( &window, &update ))
+ {
+ GreDeleteObject(hRgnNonClient);
+ hRgnNonClient = HRGN_WINDOW;
+ }
+ }
+
GreDeleteObject(hRgnWindow);
return hRgnNonClient;
}
}
+VOID FASTCALL
+IntSendNCPaint(PWND pWnd, HRGN hRgn)
+{
+ pWnd->state &= ~WNDS_SENDNCPAINT;
+
+ if ( pWnd == GetW32ThreadInfo()->MessageQueue->spwndActive &&
+ !(pWnd->state & WNDS_ACTIVEFRAME))
+ {
+ pWnd->state |= WNDS_ACTIVEFRAME;
+ pWnd->state &= ~WNDS_NONCPAINT;
+ hRgn = HRGN_WINDOW;
+ }
+
+ if (pWnd->state2 & WNDS2_FORCEFULLNCPAINTCLIPRGN)
+ {
+ pWnd->state2 &= ~WNDS2_FORCEFULLNCPAINTCLIPRGN;
+ hRgn = HRGN_WINDOW;
+ }
+
+ if (hRgn) co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCPAINT, (WPARAM)hRgn, 0);
+}
+
+VOID FASTCALL
+IntSendChildNCPaint(PWND pWnd)
+{
+ for (pWnd = pWnd->spwndChild; pWnd; pWnd = pWnd->spwndNext)
+ {
+ if ((pWnd->hrgnUpdate == NULL) && (pWnd->state & WNDS_SENDNCPAINT))
+ {
+ USER_REFERENCE_ENTRY Ref;
+ UserRefObjectCo(pWnd, &Ref);
+ IntSendNCPaint(pWnd, HRGN_WINDOW);
+ UserDerefObjectCo(pWnd);
+ }
+ }
+}
+
/*
* IntPaintWindows
*
{
HDC hDC;
HWND hWnd = Wnd->head.h;
- HRGN TempRegion;
+ HRGN TempRegion = NULL;
Wnd->state &= ~WNDS_PAINTNOTPROCESSED;
- if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
+ if (Wnd->state & WNDS_SENDNCPAINT ||
+ Wnd->state & WNDS_SENDERASEBACKGROUND)
{
- if (Wnd->hrgnUpdate)
+ if (!(Wnd->style & WS_VISIBLE))
{
- if (!IntValidateParent(Wnd, Wnd->hrgnUpdate, Recurse))
- return;
+ Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ return;
}
-
- if (Flags & RDW_UPDATENOW)
+ else
{
- if ((Wnd->hrgnUpdate != NULL ||
- Wnd->state & WNDS_INTERNALPAINT))
+ if (Wnd->hrgnUpdate == NULL)
{
- Wnd->state2 |= WNDS2_WMPAINTSENT;
- co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
+ Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
}
- }
- else if (Wnd->head.pti == PsGetCurrentThreadWin32Thread())
- {
- if (Wnd->state & WNDS_SENDNCPAINT)
+
+ if (Wnd->head.pti == PsGetCurrentThreadWin32Thread())
{
- TempRegion = IntGetNCUpdateRgn(Wnd, TRUE);
- Wnd->state &= ~WNDS_SENDNCPAINT;
- if ( Wnd == GetW32ThreadInfo()->MessageQueue->spwndActive &&
- !(Wnd->state & WNDS_ACTIVEFRAME))
+ if (Wnd->state & WNDS_SENDNCPAINT)
{
- Wnd->state |= WNDS_ACTIVEFRAME;
- Wnd->state &= ~WNDS_NONCPAINT;
+ TempRegion = IntGetNCUpdateRgn(Wnd, TRUE);
+
+ IntSendNCPaint(Wnd, TempRegion);
+
+ if (TempRegion > HRGN_WINDOW && GreIsHandleValid(TempRegion))
+ {
+ /* NOTE: The region can already be deleted! */
+ GreDeleteObject(TempRegion);
+ }
}
- if (TempRegion) co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
- }
- if (Wnd->state & WNDS_SENDERASEBACKGROUND)
- {
- if (Wnd->hrgnUpdate)
+ if (Wnd->state & WNDS_SENDERASEBACKGROUND)
{
- hDC = UserGetDCEx( Wnd,
- Wnd->hrgnUpdate,
- DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN);
-
- Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
- // Kill the loop, so Clear before we send.
- if (!co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+ if (Wnd->hrgnUpdate)
{
- Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ hDC = UserGetDCEx( Wnd,
+ Wnd->hrgnUpdate,
+ DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN);
+
+ if (Wnd->head.pti->ppi != pti->ppi)
+ {
+ ERR("Sending DC to another Process!!!\n");
+ }
+
+ Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ // Kill the loop, so Clear before we send.
+ if (!co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
+ {
+ Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ }
+ UserReleaseDC(Wnd, hDC, FALSE);
}
- UserReleaseDC(Wnd, hDC, FALSE);
}
}
+
}
}
- else
- {
- Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
- }
/*
* Check that the window is still valid at this point
/*
* Paint child windows.
*/
+
if (!(Flags & RDW_NOCHILDREN) &&
!(Wnd->style & WS_MINIMIZE) &&
- ((Flags & RDW_ALLCHILDREN) || !(Wnd->style & WS_CLIPCHILDREN)) )
+ ( Flags & RDW_ALLCHILDREN ||
+ (Flags & RDW_CLIPCHILDREN && Wnd->style & WS_CLIPCHILDREN) ) )
{
HWND *List, *phWnd;
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
if ((List = IntWinListChildren(Wnd)))
{
- /* FIXME: Handle WS_EX_TRANSPARENT */
for (phWnd = List; *phWnd; ++phWnd)
{
- Wnd = UserGetWindowObject(*phWnd);
- if (Wnd && (Wnd->style & WS_VISIBLE))
+ if ((Wnd = UserGetWindowObject(*phWnd)) == NULL)
+ continue;
+
+ if (Wnd->head.pti != pti && Wnd->style & WS_CHILD)
+ continue;
+
+ if (Wnd->style & WS_VISIBLE)
{
USER_REFERENCE_ENTRY Ref;
UserRefObjectCo(Wnd, &Ref);
}
/*
- * IntInvalidateWindows
+ * IntUpdateWindows
*
- * Internal function used by IntRedrawWindow, UserRedrawDesktop,
- * co_WinPosSetWindowPos, IntValidateParent, co_UserRedrawWindow.
+ * Internal function used by IntRedrawWindow, simplecall.
*/
+
VOID FASTCALL
-IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
+co_IntUpdateWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
{
- INT RgnType;
- BOOL HadPaintMessage;
+ HWND hWnd = Wnd->head.h;
+
+ if ( Wnd->hrgnUpdate != NULL || Wnd->state & WNDS_INTERNALPAINT )
+ {
+ if (Wnd->hrgnUpdate)
+ {
+ if (!IntValidateParents(Wnd, Recurse))
+ {
+ return;
+ }
+ }
- TRACE("IntInvalidateWindows start\n");
+ if (Wnd->state & WNDS_INTERNALPAINT)
+ {
+ Wnd->state &= ~WNDS_INTERNALPAINT;
- Wnd->state |= WNDS_PAINTNOTPROCESSED;
+ if (Wnd->hrgnUpdate == NULL)
+ MsqDecPaintCountQueue(Wnd->head.pti);
+ }
- /*
- * If the nonclient is not to be redrawn, clip the region to the client
- * rect
- */
- if (0 != (Flags & RDW_INVALIDATE) && 0 == (Flags & RDW_FRAME))
+ Wnd->state |= WNDS_PAINTNOTPROCESSED;
+ Wnd->state &= ~WNDS_UPDATEDIRTY;
+
+ Wnd->state2 |= WNDS2_WMPAINTSENT;
+ co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
+
+ if (Wnd->state & WNDS_PAINTNOTPROCESSED)
+ {
+ USER_REFERENCE_ENTRY Ref;
+ UserRefObjectCo(Wnd, &Ref);
+ co_IntPaintWindows(Wnd, RDW_NOCHILDREN, FALSE);
+ UserDerefObjectCo(Wnd);
+ }
+ }
+
+ // Force flags as a toggle. Fixes msg:test_paint_messages:WmChildPaintNc.
+ Flags = (Flags & RDW_NOCHILDREN) ? RDW_NOCHILDREN : RDW_ALLCHILDREN; // All children is the default.
+
+ /*
+ * Update child windows.
+ */
+
+ if (!(Flags & RDW_NOCHILDREN) &&
+ (Flags & RDW_ALLCHILDREN) &&
+ !UserIsDesktopWindow(Wnd))
{
- HRGN hRgnClient;
+ PWND Child;
+
+ for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext)
+ {
+ /* transparent window, check for non-transparent sibling to paint first, then skip it */
+ if ( Child->ExStyle & WS_EX_TRANSPARENT &&
+ ( Child->hrgnUpdate != NULL || Child->state & WNDS_INTERNALPAINT ) )
+ {
+ PWND Next = Child->spwndNext;
+ while (Next)
+ {
+ if ( Next->hrgnUpdate != NULL || Next->state & WNDS_INTERNALPAINT ) break;
+
+ Next = Next->spwndNext;
+ }
+
+ if (Next) continue;
+ }
- hRgnClient = IntSysCreateRectRgnIndirect(&Wnd->rcClient);
- RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnClient, RGN_AND);
- GreDeleteObject(hRgnClient);
+ if (Child->style & WS_VISIBLE)
+ {
+ USER_REFERENCE_ENTRY Ref;
+ UserRefObjectCo(Child, &Ref);
+ co_IntUpdateWindows(Child, Flags, TRUE);
+ UserDerefObjectCo(Child);
+ }
+ }
}
+}
- /*
- * Clip the given region with window rectangle (or region)
- */
+VOID FASTCALL
+UserUpdateWindows(PWND pWnd, ULONG Flags)
+{
+ // If transparent and any sibling windows below needs to be painted, leave.
+ if (pWnd->ExStyle & WS_EX_TRANSPARENT)
+ {
+ PWND Next = pWnd->spwndNext;
+
+ while(Next)
+ {
+ if ( Next->head.pti == pWnd->head.pti &&
+ ( Next->hrgnUpdate != NULL || Next->state & WNDS_INTERNALPAINT) )
+ {
+ return;
+ }
+
+ Next = Next->spwndNext;
+ }
+ }
+ co_IntUpdateWindows(pWnd, Flags, FALSE);
+}
- if (!Wnd->hrgnClip || (Wnd->style & WS_MINIMIZE))
+VOID FASTCALL
+UserSyncAndPaintWindows(PWND pWnd, ULONG Flags)
+{
+ PWND Parent = pWnd;
+ // Find parent, if it needs to be painted, leave.
+ while(TRUE)
{
- HRGN hRgnWindow;
+ if ((Parent = Parent->spwndParent) == NULL) break;
+ if ( Parent->style & WS_CLIPCHILDREN ) break;
+ if ( Parent->hrgnUpdate != NULL || Parent->state & WNDS_INTERNALPAINT ) return;
+ }
- hRgnWindow = IntSysCreateRectRgnIndirect(&Wnd->rcWindow);
- RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnWindow, RGN_AND);
- GreDeleteObject(hRgnWindow);
+ IntSendSyncPaint(pWnd, Flags);
+ co_IntPaintWindows(pWnd, Flags, FALSE);
+}
+
+/*
+ * IntInvalidateWindows
+ *
+ * Internal function used by IntRedrawWindow, UserRedrawDesktop,
+ * co_WinPosSetWindowPos, co_UserRedrawWindow.
+ */
+VOID FASTCALL
+IntInvalidateWindows(PWND Wnd, PREGION Rgn, ULONG Flags)
+{
+ INT RgnType = NULLREGION;
+ BOOL HadPaintMessage;
+
+ TRACE("IntInvalidateWindows start Rgn %p\n",Rgn);
+
+ if ( Rgn > PRGN_WINDOW )
+ {
+ /*
+ * If the nonclient is not to be redrawn, clip the region to the client
+ * rect
+ */
+ if ((Flags & RDW_INVALIDATE) != 0 && (Flags & RDW_FRAME) == 0)
+ {
+ PREGION RgnClient;
+
+ RgnClient = IntSysCreateRectpRgnIndirect(&Wnd->rcClient);
+ if (RgnClient)
+ {
+ RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClient, RGN_AND);
+ REGION_Delete(RgnClient);
+ }
+ }
+
+ /*
+ * Clip the given region with window rectangle (or region)
+ */
+
+ if (!Wnd->hrgnClip || (Wnd->style & WS_MINIMIZE))
+ {
+ PREGION RgnWindow = IntSysCreateRectpRgnIndirect(&Wnd->rcWindow);
+ if (RgnWindow)
+ {
+ RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnWindow, RGN_AND);
+ REGION_Delete(RgnWindow);
+ }
+ }
+ else
+ {
+ PREGION RgnClip = REGION_LockRgn(Wnd->hrgnClip);
+ if (RgnClip)
+ {
+ REGION_bOffsetRgn(Rgn,
+ -Wnd->rcWindow.left,
+ -Wnd->rcWindow.top);
+ RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND);
+ REGION_bOffsetRgn(Rgn,
+ Wnd->rcWindow.left,
+ Wnd->rcWindow.top);
+ REGION_UnlockRgn(RgnClip);
+ }
+ }
}
else
{
- NtGdiOffsetRgn( hRgn,
- -Wnd->rcWindow.left,
- -Wnd->rcWindow.top);
- RgnType = NtGdiCombineRgn(hRgn, hRgn, Wnd->hrgnClip, RGN_AND);
- NtGdiOffsetRgn( hRgn,
- Wnd->rcWindow.left,
- Wnd->rcWindow.top);
+ RgnType = NULLREGION;
}
/*
Wnd->state |= WNDS_INTERNALPAINT;
}
- if (Flags & RDW_INVALIDATE && RgnType != NULLREGION)
+ if (Flags & RDW_INVALIDATE )
{
+ PREGION RgnUpdate;
+
Wnd->state &= ~WNDS_NONCPAINT;
/* If not the same thread set it dirty. */
if (Flags & RDW_FRAME)
Wnd->state |= WNDS_SENDNCPAINT;
+
if (Flags & RDW_ERASE)
Wnd->state |= WNDS_SENDERASEBACKGROUND;
- if (Wnd->hrgnUpdate == NULL)
+ if (RgnType != NULLREGION && Rgn > PRGN_WINDOW)
{
- Wnd->hrgnUpdate = IntSysCreateRectRgn(0, 0, 0, 0);
- IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC);
- }
+ if (Wnd->hrgnUpdate == NULL)
+ {
+ Wnd->hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0);
+ IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC);
+ }
- if (NtGdiCombineRgn(Wnd->hrgnUpdate, Wnd->hrgnUpdate,
- hRgn, RGN_OR) == NULLREGION)
- {
- IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(Wnd->hrgnUpdate);
- Wnd->hrgnUpdate = NULL;
+ if (Wnd->hrgnUpdate != HRGN_WINDOW)
+ {
+ RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate);
+ if (RgnUpdate)
+ {
+ RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_OR);
+ REGION_UnlockRgn(RgnUpdate);
+ if (RgnType == NULLREGION)
+ {
+ IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(Wnd->hrgnUpdate);
+ Wnd->hrgnUpdate = NULL;
+ }
+ }
+ }
}
- Flags |= RDW_FRAME; // For children.
+
+ Flags |= RDW_ERASE|RDW_FRAME; // For children.
+
+ }
+
+ if (!HadPaintMessage && IntIsWindowDirty(Wnd))
+ {
+ MsqIncPaintCountQueue(Wnd->head.pti);
}
+
} // The following flags are used to validate the window.
else if (Flags & (RDW_VALIDATE|RDW_NOINTERNALPAINT|RDW_NOERASE|RDW_NOFRAME))
{
- /* FIXME: Handle WNDS_UPDATEDIRTY */
+ if (Wnd->state & WNDS_UPDATEDIRTY && !(Flags & RDW_NOUPDATEDIRTY))
+ return;
if (Flags & RDW_NOINTERNALPAINT)
{
Wnd->state &= ~WNDS_INTERNALPAINT;
}
- if (Flags & RDW_VALIDATE && RgnType != NULLREGION)
+ if (Flags & RDW_VALIDATE)
{
if (Flags & RDW_NOFRAME)
Wnd->state &= ~WNDS_SENDNCPAINT;
+
if (Flags & RDW_NOERASE)
Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
- if (Wnd->hrgnUpdate != NULL)
+ if (Wnd->hrgnUpdate > HRGN_WINDOW && RgnType != NULLREGION && Rgn > PRGN_WINDOW)
{
- if (NtGdiCombineRgn(Wnd->hrgnUpdate, Wnd->hrgnUpdate,
- hRgn, RGN_DIFF) == NULLREGION)
- {
- IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(Wnd->hrgnUpdate);
- Wnd->hrgnUpdate = NULL;
- }
+ PREGION RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate);
+
+ if (RgnUpdate)
+ {
+ RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_DIFF);
+ REGION_UnlockRgn(RgnUpdate);
+
+ if (RgnType == NULLREGION)
+ {
+ IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(Wnd->hrgnUpdate);
+ Wnd->hrgnUpdate = NULL;
+ }
+ }
}
-
+ // If update is null, do not erase.
if (Wnd->hrgnUpdate == NULL)
+ {
Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ }
+ }
+
+ if (HadPaintMessage && !IntIsWindowDirty(Wnd))
+ {
+ MsqDecPaintCountQueue(Wnd->head.pti);
}
}
* Process children if needed
*/
- if (!(Flags & RDW_NOCHILDREN) && !(Wnd->style & WS_MINIMIZE) &&
+ if (!(Flags & RDW_NOCHILDREN) &&
+ !(Wnd->style & WS_MINIMIZE) &&
((Flags & RDW_ALLCHILDREN) || !(Wnd->style & WS_CLIPCHILDREN)))
- {
+ {
PWND Child;
for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext)
/*
* Recursive call to update children hrgnUpdate
*/
- HRGN hRgnTemp = IntSysCreateRectRgn(0, 0, 0, 0);
- NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
- IntInvalidateWindows(Child, hRgnTemp, Flags);
- GreDeleteObject(hRgnTemp);
+ PREGION RgnTemp = IntSysCreateRectpRgn(0, 0, 0, 0);
+ if (RgnTemp)
+ {
+ if (Rgn > PRGN_WINDOW) IntGdiCombineRgn(RgnTemp, Rgn, 0, RGN_COPY);
+ IntInvalidateWindows(Child, ((Rgn > PRGN_WINDOW)?RgnTemp:Rgn), Flags);
+ REGION_Delete(RgnTemp);
+ }
}
}
}
-
- /*
- * Fake post paint messages to window message queue if needed
- */
-
- if (HadPaintMessage != IntIsWindowDirty(Wnd))
- {
- if (HadPaintMessage)
- MsqDecPaintCountQueue(Wnd->head.pti);
- else
- MsqIncPaintCountQueue(Wnd->head.pti);
- }
TRACE("IntInvalidateWindows exit\n");
}
co_UserRedrawWindow(
PWND Window,
const RECTL* UpdateRect,
- HRGN UpdateRgn,
+ PREGION UpdateRgn,
ULONG Flags)
{
- HRGN hRgn = NULL;
- TRACE("co_UserRedrawWindow start\n");
+ PREGION TmpRgn = NULL;
+ TRACE("co_UserRedrawWindow start Rgn %p\n",UpdateRgn);
/*
* Step 1.
return TRUE; // Just do nothing!!!
}
+ if (Window == NULL)
+ {
+ Window = UserGetDesktopWindow();
+ }
+
/*
* Step 2.
* Transform the parameters UpdateRgn and UpdateRect into
if (Flags & (RDW_INVALIDATE | RDW_VALIDATE)) // Both are OKAY!
{
- if (UpdateRgn != NULL)
+ /* We can't hold lock on GDI objects while doing roundtrips to user mode,
+ * so use a copy instead */
+ if (UpdateRgn)
+ {
+ TmpRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
+
+ if (UpdateRgn > PRGN_WINDOW)
+ {
+ IntGdiCombineRgn(TmpRgn, UpdateRgn, NULL, RGN_COPY);
+ }
+
+ if (Window != UserGetDesktopWindow())
+ {
+ REGION_bOffsetRgn(TmpRgn, Window->rcClient.left, Window->rcClient.top);
+ }
+ }
+ else
{
- hRgn = IntSysCreateRectRgn(0, 0, 0, 0);
- if (NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION)
+ if (UpdateRect != NULL)
{
- GreDeleteObject(hRgn);
- hRgn = NULL;
+ if (Window == UserGetDesktopWindow())
+ {
+ TmpRgn = IntSysCreateRectpRgnIndirect(UpdateRect);
+ }
+ else
+ {
+ TmpRgn = IntSysCreateRectpRgn(Window->rcClient.left + UpdateRect->left,
+ Window->rcClient.top + UpdateRect->top,
+ Window->rcClient.left + UpdateRect->right,
+ Window->rcClient.top + UpdateRect->bottom);
+ }
}
else
- NtGdiOffsetRgn(hRgn, Window->rcClient.left, Window->rcClient.top);
- }
- else if (UpdateRect != NULL)
- {
- if (!RECTL_bIsEmptyRect(UpdateRect))
{
- hRgn = IntSysCreateRectRgnIndirect((RECTL *)UpdateRect);
- NtGdiOffsetRgn(hRgn, Window->rcClient.left, Window->rcClient.top);
+ if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
+ (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
+ {
+ if (!RECTL_bIsEmptyRect(&Window->rcWindow))
+ TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcWindow);
+ }
+ else
+ {
+ if (!RECTL_bIsEmptyRect(&Window->rcClient))
+ TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcClient);
+ }
}
}
- else if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
- (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
- {
- if (!RECTL_bIsEmptyRect(&Window->rcWindow))
- hRgn = IntSysCreateRectRgnIndirect(&Window->rcWindow);
- }
- else
- {
- if (!RECTL_bIsEmptyRect(&Window->rcClient))
- hRgn = IntSysCreateRectRgnIndirect(&Window->rcClient);
- }
+ }
+
+ /* Fixes test RDW_INTERNALPAINT behavior */
+ if (TmpRgn == NULL)
+ {
+ TmpRgn = PRGN_WINDOW; // Need a region so the bits can be set!!!
}
/*
*/
if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) &&
- hRgn != NULL)
+ TmpRgn != NULL)
{
- IntInvalidateWindows(Window, hRgn, Flags);
+ IntInvalidateWindows(Window, TmpRgn, Flags);
}
/*
* Repaint and erase windows if needed.
*/
- if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
+ if (Flags & RDW_UPDATENOW)
+ {
+ UserUpdateWindows(Window, Flags);
+ }
+ else if (Flags & RDW_ERASENOW)
{
- if (Flags & RDW_ERASENOW) IntSendSyncPaint(Window, Flags);
- co_IntPaintWindows(Window, Flags, FALSE);
+ if ((Flags & (RDW_NOCHILDREN|RDW_ALLCHILDREN)) == 0)
+ Flags |= RDW_CLIPCHILDREN;
+
+ UserSyncAndPaintWindows(Window, Flags);
}
/*
* Cleanup ;-)
*/
- if (hRgn != NULL)
+ if (TmpRgn > PRGN_WINDOW)
{
- GreDeleteObject(hRgn);
+ REGION_Delete(TmpRgn);
}
TRACE("co_UserRedrawWindow exit\n");
return TRUE;
}
-BOOL FASTCALL
-IntIsWindowDirty(PWND Wnd)
+VOID FASTCALL
+PaintSuspendedWindow(PWND pwnd, HRGN hrgnOrig)
{
- return ( Wnd->style & WS_VISIBLE &&
- ( Wnd->hrgnUpdate != NULL ||
- Wnd->state & WNDS_INTERNALPAINT ) );
-}
+ if (pwnd->hrgnUpdate)
+ {
+ HDC hDC;
+ INT Flags = DC_NC|DC_NOSENDMSG;
+ HRGN hrgnTemp;
+ RECT Rect;
+ INT type;
+ PREGION prgn;
-PWND FASTCALL
-IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread)
-{
- PWND hChild;
+ if (pwnd->hrgnUpdate > HRGN_WINDOW)
+ {
+ hrgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
+ type = NtGdiCombineRgn( hrgnTemp, pwnd->hrgnUpdate, 0, RGN_COPY);
+ if (type == ERROR)
+ {
+ GreDeleteObject(hrgnTemp);
+ hrgnTemp = HRGN_WINDOW;
+ }
+ }
+ else
+ {
+ hrgnTemp = GreCreateRectRgnIndirect(&pwnd->rcWindow);
+ }
+
+ if ( hrgnOrig &&
+ hrgnTemp > HRGN_WINDOW &&
+ NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnOrig, RGN_AND) == NULLREGION)
+ {
+ GreDeleteObject(hrgnTemp);
+ return;
+ }
+
+ hDC = UserGetDCEx(pwnd, hrgnTemp, DCX_WINDOW|DCX_INTERSECTRGN|DCX_USESTYLE|DCX_KEEPCLIPRGN);
+
+ Rect = pwnd->rcWindow;
+ RECTL_vOffsetRect(&Rect, -pwnd->rcWindow.left, -pwnd->rcWindow.top);
+
+ // Clear out client area!
+ FillRect(hDC, &Rect, IntGetSysColorBrush(COLOR_WINDOW));
+
+ NC_DoNCPaint(pwnd, hDC, Flags); // Redraw without MENUs.
+
+ UserReleaseDC(pwnd, hDC, FALSE);
+
+ prgn = REGION_LockRgn(hrgnTemp);
+ IntInvalidateWindows(pwnd, prgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN);
+ REGION_UnlockRgn(prgn);
+
+ // Set updates for this window.
+ pwnd->state |= WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_UPDATEDIRTY;
+
+ // DCX_KEEPCLIPRGN is set. Check it anyway.
+ if (hrgnTemp > HRGN_WINDOW && GreIsHandleValid(hrgnTemp)) GreDeleteObject(hrgnTemp);
+ }
+}
+
+VOID FASTCALL
+UpdateTheadChildren(PWND pWnd, HRGN hRgn)
+{
+ PaintSuspendedWindow( pWnd, hRgn );
+
+ if (!(pWnd->style & WS_CLIPCHILDREN))
+ return;
+
+ pWnd = pWnd->spwndChild; // invalidate children if any.
+ while (pWnd)
+ {
+ UpdateTheadChildren( pWnd, hRgn );
+ pWnd = pWnd->spwndNext;
+ }
+}
+
+VOID FASTCALL
+UpdateThreadWindows(PWND pWnd, PTHREADINFO pti, HRGN hRgn)
+{
+ PWND pwndTemp;
+
+ for ( pwndTemp = pWnd;
+ pwndTemp;
+ pwndTemp = pwndTemp->spwndNext )
+ {
+ if (pwndTemp->head.pti == pti)
+ {
+ UserUpdateWindows(pwndTemp, RDW_ALLCHILDREN);
+ }
+ else
+ {
+ if (IsThreadSuspended(pwndTemp->head.pti) || MsqIsHung(pwndTemp->head.pti))
+ {
+ UpdateTheadChildren(pwndTemp, hRgn);
+ }
+ else
+ UserUpdateWindows(pwndTemp, RDW_ALLCHILDREN);
+ }
+ }
+}
+
+BOOL FASTCALL
+IntIsWindowDirty(PWND Wnd)
+{
+ return ( Wnd->style & WS_VISIBLE &&
+ ( Wnd->hrgnUpdate != NULL ||
+ Wnd->state & WNDS_INTERNALPAINT ) );
+}
+
+/*
+ Conditions to paint any window:
+
+ 1. Update region is not null.
+ 2. Internal paint flag is set.
+ 3. Paint count is not zero.
+
+ */
+PWND FASTCALL
+IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread)
+{
+ PWND hChild;
PWND TempWindow;
for (; Window != NULL; Window = Window->spwndNext)
{
- if (IntWndBelongsToThread(Window, Thread) &&
- IntIsWindowDirty(Window))
+ if (IntWndBelongsToThread(Window, Thread))
{
- /* Make sure all non-transparent siblings are already drawn. */
- if (Window->ExStyle & WS_EX_TRANSPARENT)
+ if (IntIsWindowDirty(Window))
{
- for (TempWindow = Window->spwndNext; TempWindow != NULL;
- TempWindow = TempWindow->spwndNext)
+ /* Make sure all non-transparent siblings are already drawn. */
+ if (Window->ExStyle & WS_EX_TRANSPARENT)
{
- if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) &&
- IntWndBelongsToThread(TempWindow, Thread) &&
- IntIsWindowDirty(TempWindow))
+ for (TempWindow = Window->spwndNext; TempWindow != NULL;
+ TempWindow = TempWindow->spwndNext)
{
- return TempWindow;
+ if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) &&
+ IntWndBelongsToThread(TempWindow, Thread) &&
+ IntIsWindowDirty(TempWindow))
+ {
+ return TempWindow;
+ }
}
}
+ return Window;
}
-
- return Window;
}
-
+ /* find a child of the specified window that needs repainting */
if (Window->spwndChild)
{
hChild = IntFindWindowToRepaint(Window->spwndChild, Thread);
return Window;
}
+//
+// Internal painting of windows.
+//
+VOID FASTCALL
+IntPaintWindow( PWND Window )
+{
+ // Handle normal painting.
+ co_IntPaintWindows( Window, RDW_NOCHILDREN, FALSE );
+}
+
BOOL FASTCALL
IntGetPaintMessage(
PWND Window,
MSG *Message,
BOOL Remove)
{
- PWND PaintWnd;
+ PWND PaintWnd, StartWnd;
if ((MsgFilterMin != 0 || MsgFilterMax != 0) &&
(MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT))
ERR("WM_PAINT is in a System Thread!\n");
}
- PaintWnd = IntFindWindowToRepaint(UserGetDesktopWindow(), Thread);
+ StartWnd = UserGetDesktopWindow();
+ PaintWnd = IntFindWindowToRepaint(StartWnd, Thread);
Message->hwnd = PaintWnd ? UserHMGetHandle(PaintWnd) : NULL;
- if (Message->hwnd == NULL)
+ if (Message->hwnd == NULL && Thread->cPaintsReady)
{
- ERR("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread->cPaintsReady);
- /* Hack to stop spamming the debuglog ! */
+ // Find note in window.c:"PAINTING BUG".
+ ERR("WARNING SOMETHING HAS GONE WRONG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread->cPaintsReady);
+ /* Hack to stop spamming the debug log ! */
Thread->cPaintsReady = 0;
return FALSE;
}
- if (Window != NULL && PaintWnd != Window)
+ if (Message->hwnd == NULL)
+ return FALSE;
+
+ if (!(Window == NULL ||
+ PaintWnd == Window ||
+ IntIsChildWindow(Window, PaintWnd))) /* check that it is a child of the specified parent */
return FALSE;
if (PaintWnd->state & WNDS_INTERNALPAINT)
if (!PaintWnd->hrgnUpdate)
MsqDecPaintCountQueue(Thread);
}
- PaintWnd->state2 &= ~WNDS2_WMPAINTSENT;
+ PaintWnd->state2 &= ~WNDS2_STARTPAINT;
PaintWnd->state &= ~WNDS_UPDATEDIRTY;
- Message->wParam = Message->lParam = 0;
- Message->message = WM_PAINT;
- return TRUE;
-}
-
-static
-HWND FASTCALL
-co_IntFixCaret(PWND Window, RECTL *lprc, UINT flags)
-{
- PDESKTOP Desktop;
- PTHRDCARETINFO CaretInfo;
- PTHREADINFO pti;
- PUSER_MESSAGE_QUEUE ActiveMessageQueue;
- HWND hWndCaret;
- PWND WndCaret;
-
- ASSERT_REFS_CO(Window);
-
- pti = PsGetCurrentThreadWin32Thread();
- Desktop = pti->rpdesk;
- ActiveMessageQueue = Desktop->ActiveMessageQueue;
- if (!ActiveMessageQueue) return 0;
- CaretInfo = ActiveMessageQueue->CaretInfo;
- hWndCaret = CaretInfo->hWnd;
- WndCaret = ValidateHwndNoErr(hWndCaret);
-
- // FIXME: Check for WndCaret can be NULL
- if (WndCaret == Window ||
- ((flags & SW_SCROLLCHILDREN) && IntIsChildWindow(Window, WndCaret)))
+ Window = PaintWnd;
+ while (Window && !UserIsDesktopWindow(Window))
{
- POINT pt, FromOffset, ToOffset;
- RECTL rcCaret;
-
- pt.x = CaretInfo->Pos.x;
- pt.y = CaretInfo->Pos.y;
- IntGetClientOrigin(WndCaret, &FromOffset);
- IntGetClientOrigin(Window, &ToOffset);
- rcCaret.left = pt.x;
- rcCaret.top = pt.y;
- rcCaret.right = pt.x + CaretInfo->Size.cx;
- rcCaret.bottom = pt.y + CaretInfo->Size.cy;
- if (RECTL_bIntersectRect(lprc, lprc, &rcCaret))
+ // Role back and check for clip children, do not set if any.
+ if (Window->spwndParent && !(Window->spwndParent->style & WS_CLIPCHILDREN))
{
- co_UserHideCaret(0);
- lprc->left = pt.x;
- lprc->top = pt.y;
- return hWndCaret;
+ PaintWnd->state2 |= WNDS2_WMPAINTSENT;
}
+ Window = Window->spwndParent;
}
- return 0;
+ Message->wParam = Message->lParam = 0;
+ Message->message = WM_PAINT;
+ return TRUE;
}
BOOL
return FALSE;
/* Update the window just incase. */
- co_IntPaintWindows( pwnd, RDW_ERASENOW|RDW_UPDATENOW, FALSE);
+ co_IntUpdateWindows( pwnd, RDW_ALLCHILDREN, FALSE);
hdcSrc = UserGetDCEx( pwnd, NULL, DCX_CACHE|DCX_WINDOW);
/* Print window to printer context. */
FASTCALL
IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi)
{
- PPROPERTY pprop;
- DWORD FlashState;
- BOOL Ret = FALSE;
+ DWORD_PTR FlashState;
+ UINT uCount = pfwi->uCount;
+ BOOL Activate = FALSE, Ret = FALSE;
- pprop = IntGetProp(pWnd, AtomFlashWndState);
- if (!pprop)
+ ASSERT(pfwi);
+
+ FlashState = (DWORD_PTR)UserGetProp(pWnd, AtomFlashWndState, TRUE);
+
+ if (FlashState == FLASHW_FINISHED)
{
- FlashState = pfwi->dwFlags;
- IntSetProp(pWnd, AtomFlashWndState, (HANDLE) FlashState);
- return TRUE;
+ // Cycle has finished, kill timer and set this to Stop.
+ FlashState |= FLASHW_KILLSYSTIMER;
+ pfwi->dwFlags = FLASHW_STOP;
+ }
+ else
+ {
+ if (FlashState)
+ {
+ if (pfwi->dwFlags == FLASHW_SYSTIMER)
+ {
+ // Called from system timer, restore flags, counts and state.
+ pfwi->dwFlags = LOWORD(FlashState);
+ uCount = HIWORD(FlashState);
+ FlashState = MAKELONG(LOWORD(FlashState),0);
+ }
+ else
+ {
+ // Clean out the trash! Fix SeaMonkey crash after restart.
+ FlashState = 0;
+ }
+ }
+
+ if (FlashState == 0)
+ { // First time in cycle, setup flash state.
+ if ( pWnd->state & WNDS_ACTIVEFRAME ||
+ (pfwi->dwFlags & FLASHW_CAPTION && pWnd->style & (WS_BORDER|WS_DLGFRAME)))
+ {
+ FlashState = FLASHW_STARTED|FLASHW_ACTIVE;
+ }
+ }
+
+ // Set previous window state.
+ Ret = !!(FlashState & FLASHW_ACTIVE);
+
+ if ( (pfwi->dwFlags & FLASHW_TIMERNOFG) == FLASHW_TIMERNOFG &&
+ gpqForeground == pWnd->head.pti->MessageQueue )
+ {
+ // Flashing until foreground, set this to Stop.
+ pfwi->dwFlags = FLASHW_STOP;
+ }
+ }
+
+ // Toggle activate flag.
+ if ( pfwi->dwFlags == FLASHW_STOP )
+ {
+ if (gpqForeground && gpqForeground->spwndActive == pWnd)
+ Activate = TRUE;
+ else
+ Activate = FALSE;
+ }
+ else
+ {
+ Activate = (FlashState & FLASHW_ACTIVE) == 0;
+ }
+
+ if ( pfwi->dwFlags == FLASHW_STOP || pfwi->dwFlags & FLASHW_CAPTION )
+ {
+ co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCACTIVATE, Activate, 0);
+ }
+
+ // FIXME: Check for a Stop Sign here.
+ if ( pfwi->dwFlags & FLASHW_TRAY )
+ {
+ // Need some shell work here too.
+ TRACE("FIXME: Flash window no Tray support!\n");
}
- FlashState = (DWORD)pprop->Data;
if ( pfwi->dwFlags == FLASHW_STOP )
{
- IntRemoveProp(pWnd, AtomFlashWndState);
- Ret = TRUE;
+ if (FlashState & FLASHW_KILLSYSTIMER)
+ {
+ IntKillTimer(pWnd, ID_EVENT_SYSTIMER_FLASHWIN, TRUE);
+ }
+
+ UserRemoveProp(pWnd, AtomFlashWndState, TRUE);
+ }
+ else
+ { // Have a count and started, set timer.
+ if ( uCount )
+ {
+ FlashState |= FLASHW_COUNT;
+
+ if (!(Activate ^ !!(FlashState & FLASHW_STARTED)))
+ uCount--;
+
+ if (!(FlashState & FLASHW_KILLSYSTIMER))
+ pfwi->dwFlags |= FLASHW_TIMER;
+ }
+
+ if (pfwi->dwFlags & FLASHW_TIMER)
+ {
+ FlashState |= FLASHW_KILLSYSTIMER;
+
+ IntSetTimer( pWnd,
+ ID_EVENT_SYSTIMER_FLASHWIN,
+ pfwi->dwTimeout ? pfwi->dwTimeout : gpsi->dtCaretBlink,
+ SystemTimerProc,
+ TMRF_SYSTEM );
+ }
+
+ if (FlashState & FLASHW_COUNT && uCount == 0)
+ {
+ // Keep spinning? Nothing else to do.
+ FlashState = FLASHW_FINISHED;
+ }
+ else
+ {
+ // Save state and flags so this can be restored next time through.
+ FlashState ^= (FlashState ^ -!!(Activate)) & FLASHW_ACTIVE;
+ FlashState ^= (FlashState ^ pfwi->dwFlags) & (FLASHW_MASK & ~FLASHW_TIMER);
+ }
+ FlashState = MAKELONG(LOWORD(FlashState),uCount);
+ UserSetProp(pWnd, AtomFlashWndState, (HANDLE)FlashState, TRUE);
}
return Ret;
}
HDC FASTCALL
IntBeginPaint(PWND Window, PPAINTSTRUCT Ps)
{
+ RECT Rect;
+ INT type;
+ BOOL Erase = FALSE;
+
co_UserHideCaret(Window);
Window->state2 |= WNDS2_STARTPAINT;
if (Window->state & WNDS_SENDNCPAINT)
{
HRGN hRgn;
-
- Window->state &= ~WNDS_UPDATEDIRTY;
- hRgn = IntGetNCUpdateRgn(Window, FALSE);
- Window->state &= ~WNDS_SENDNCPAINT;
- co_IntSendMessage(UserHMGetHandle(Window), WM_NCPAINT, (WPARAM)hRgn, 0);
- if (hRgn != HRGN_WINDOW && hRgn != NULL && GreIsHandleValid(hRgn))
+ // Application can keep update dirty.
+ do
{
- /* NOTE: The region can already be deleted! */
- GreDeleteObject(hRgn);
+ Window->state &= ~WNDS_UPDATEDIRTY;
+ hRgn = IntGetNCUpdateRgn(Window, FALSE);
+ IntSendNCPaint(Window, hRgn);
+ if (hRgn > HRGN_WINDOW && GreIsHandleValid(hRgn))
+ {
+ /* NOTE: The region can already be deleted! */
+ GreDeleteObject(hRgn);
+ }
}
+ while(Window->state & WNDS_UPDATEDIRTY);
}
else
{
RtlZeroMemory(Ps, sizeof(PAINTSTRUCT));
+ if (Window->state2 & WNDS2_ENDPAINTINVALIDATE)
+ {
+ ERR("BP: Another thread invalidated this window\n");
+ }
+
Ps->hdc = UserGetDCEx( Window,
- Window->hrgnUpdate,
- DCX_INTERSECTRGN | DCX_USESTYLE);
+ Window->hrgnUpdate,
+ DCX_INTERSECTRGN | DCX_USESTYLE);
if (!Ps->hdc)
{
return NULL;
}
+ // If set, always clear flags out due to the conditions later on for sending the message.
+ if (Window->state & WNDS_SENDERASEBACKGROUND)
+ {
+ Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ Erase = TRUE;
+ }
+
if (Window->hrgnUpdate != NULL)
{
MsqDecPaintCountQueue(Window->head.pti);
- GdiGetClipBox(Ps->hdc, &Ps->rcPaint);
IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
/* The region is part of the dc now and belongs to the process! */
Window->hrgnUpdate = NULL;
{
if (Window->state & WNDS_INTERNALPAINT)
MsqDecPaintCountQueue(Window->head.pti);
-
- IntGetClientRect(Window, &Ps->rcPaint);
}
+ type = GdiGetClipBox(Ps->hdc, &Ps->rcPaint);
+
+ IntGetClientRect(Window, &Rect);
+
Window->state &= ~WNDS_INTERNALPAINT;
- if (Window->state & WNDS_SENDERASEBACKGROUND)
+ if ( Erase && // Set to erase,
+ type != NULLREGION && // don't erase if the clip box is empty,
+ (!(Window->pcls->style & CS_PARENTDC) || // not parent dc or
+ RECTL_bIntersectRect( &Rect, &Rect, &Ps->rcPaint) ) ) // intersecting.
{
- Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
Ps->fErase = !co_IntSendMessage(UserHMGetHandle(Window), WM_ERASEBKGND, (WPARAM)Ps->hdc, 0);
if ( Ps->fErase )
{
{
Ps->fErase = FALSE;
}
- if (Window->hrgnUpdate)
- {
- if (!(Window->style & WS_CLIPCHILDREN))
- {
- PWND Child;
- for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
- {
- if (Child->hrgnUpdate == NULL && Child->state & WNDS_SENDNCPAINT) // Helped fixing test_redrawnow.
- IntInvalidateWindows(Child, Window->hrgnUpdate, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
- }
- }
- }
+
+ IntSendChildNCPaint(Window);
+
return Ps->hdc;
}
UserReleaseDC(Wnd, hdc, TRUE);
+ if (Wnd->state2 & WNDS2_ENDPAINTINVALIDATE)
+ {
+ ERR("EP: Another thread invalidated this window\n");
+ Wnd->state2 &= ~WNDS2_ENDPAINTINVALIDATE;
+ }
+
Wnd->state2 &= ~(WNDS2_WMPAINTSENT|WNDS2_STARTPAINT);
co_UserShowCaret(Wnd);
return TRUE;
}
+BOOL FASTCALL
+IntFillWindow(PWND pWndParent,
+ PWND pWnd,
+ HDC hDC,
+ HBRUSH hBrush)
+{
+ RECT Rect, Rect1;
+ INT type;
+
+ if (!pWndParent)
+ pWndParent = pWnd;
+
+ type = GdiGetClipBox(hDC, &Rect);
+
+ IntGetClientRect(pWnd, &Rect1);
+
+ if ( type != NULLREGION && // Clip box is not empty,
+ (!(pWnd->pcls->style & CS_PARENTDC) || // not parent dc or
+ RECTL_bIntersectRect( &Rect, &Rect, &Rect1) ) ) // intersecting.
+ {
+ POINT ppt;
+ INT x = 0, y = 0;
+
+ if (!UserIsDesktopWindow(pWndParent))
+ {
+ x = pWndParent->rcClient.left - pWnd->rcClient.left;
+ y = pWndParent->rcClient.top - pWnd->rcClient.top;
+ }
+
+ GreSetBrushOrg(hDC, x, y, &ppt);
+
+ if ( hBrush < (HBRUSH)CTLCOLOR_MAX )
+ hBrush = GetControlColor( pWndParent, pWnd, hDC, HandleToUlong(hBrush) + WM_CTLCOLORMSGBOX);
+
+ FillRect(hDC, &Rect, hBrush);
+
+ GreSetBrushOrg(hDC, ppt.x, ppt.y, NULL);
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
/* PUBLIC FUNCTIONS ***********************************************************/
/*
END_CLEANUP;
}
+/*
+ * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
+ */
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserFillWindow(HWND hWndParent,
+ HWND hWnd,
+ HDC hDC,
+ HBRUSH hBrush)
+{
+ BOOL ret = FALSE;
+ PWND pWnd, pWndParent = NULL;
+ USER_REFERENCE_ENTRY Ref;
+
+ TRACE("Enter NtUserFillWindow\n");
+ UserEnterExclusive();
+
+ if (!hDC)
+ {
+ goto Exit;
+ }
+
+ if (!(pWnd = UserGetWindowObject(hWnd)))
+ {
+ goto Exit;
+ }
+
+ if (hWndParent && !(pWndParent = UserGetWindowObject(hWndParent)))
+ {
+ goto Exit;
+ }
+
+ UserRefObjectCo(pWnd, &Ref);
+ ret = IntFillWindow( pWndParent, pWnd, hDC, hBrush );
+ UserDerefObjectCo(pWnd);
+
+Exit:
+ TRACE("Leave NtUserFillWindow, ret=%i\n",ret);
+ UserLeave();
+ return ret;
+}
+
/*
* @implemented
*/
{
PWND pWnd;
FLASHWINFO finfo = {0};
- BOOL Ret = TRUE;
+ BOOL Ret = FALSE;
UserEnterExclusive();
_SEH2_TRY
{
- ProbeForRead(pfwi, sizeof(FLASHWINFO), sizeof(ULONG));
+ ProbeForRead(pfwi, sizeof(FLASHWINFO), 1);
RtlCopyMemory(&finfo, pfwi, sizeof(FLASHWINFO));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(_SEH2_GetExceptionCode());
- Ret = FALSE;
+ _SEH2_YIELD(goto Exit);
}
_SEH2_END
- if (!Ret) goto Exit;
-
- if (!( pWnd = (PWND)UserGetObject(gHandleTable, finfo.hwnd, TYPE_WINDOW)) ||
+ if (!( pWnd = ValidateHwndNoErr(finfo.hwnd)) ||
finfo.cbSize != sizeof(FLASHWINFO) ||
finfo.dwFlags & ~(FLASHW_ALL|FLASHW_TIMER|FLASHW_TIMERNOFG) )
{
EngSetLastError(ERROR_INVALID_PARAMETER);
- Ret = FALSE;
goto Exit;
}
return Ret;
}
+/*
+ GetUpdateRgn, this fails the same as the old one.
+ */
INT FASTCALL
co_UserGetUpdateRgn(PWND Window, HRGN hRgn, BOOL bErase)
{
int RegionType;
+ BOOL Type;
RECTL Rect;
ASSERT_REFS_CO(Window);
+ if (bErase)
+ {
+ USER_REFERENCE_ENTRY Ref;
+ UserRefObjectCo(Window, &Ref);
+ co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE);
+ UserDerefObjectCo(Window);
+ }
+
Window->state &= ~WNDS_UPDATEDIRTY;
if (Window->hrgnUpdate == NULL)
{
- RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
- }
- else
- {
- Rect = Window->rcClient;
- IntIntersectWithParents(Window, &Rect);
- NtGdiSetRectRgn(hRgn, Rect.left, Rect.top, Rect.right, Rect.bottom);
- RegionType = NtGdiCombineRgn(hRgn, hRgn, Window->hrgnUpdate, RGN_AND);
- NtGdiOffsetRgn(hRgn, -Window->rcClient.left, -Window->rcClient.top);
+ NtGdiSetRectRgn(hRgn, 0, 0, 0, 0);
+ return NULLREGION;
}
- if (bErase && RegionType != NULLREGION && RegionType != ERROR)
+ Rect = Window->rcClient;
+ Type = IntIntersectWithParents(Window, &Rect);
+
+ if (Window->hrgnUpdate == HRGN_WINDOW)
{
- co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
+ // Trap it out.
+ ERR("GURn: Caller is passing Window Region 1\n");
+ if (!Type)
+ {
+ NtGdiSetRectRgn(hRgn, 0, 0, 0, 0);
+ return NULLREGION;
+ }
+
+ RegionType = SIMPLEREGION;
+
+ if (!UserIsDesktopWindow(Window))
+ {
+ RECTL_vOffsetRect(&Rect,
+ -Window->rcClient.left,
+ -Window->rcClient.top);
+ }
+ GreSetRectRgnIndirect(hRgn, &Rect);
}
+ else
+ {
+ HRGN hrgnTemp = GreCreateRectRgnIndirect(&Rect);
+ RegionType = NtGdiCombineRgn(hRgn, hrgnTemp, Window->hrgnUpdate, RGN_AND);
+
+ if (RegionType == ERROR || RegionType == NULLREGION)
+ {
+ if (hrgnTemp) GreDeleteObject(hrgnTemp);
+ NtGdiSetRectRgn(hRgn, 0, 0, 0, 0);
+ return RegionType;
+ }
+
+ if (!UserIsDesktopWindow(Window))
+ {
+ NtGdiOffsetRgn(hRgn,
+ -Window->rcClient.left,
+ -Window->rcClient.top);
+ }
+ if (hrgnTemp) GreDeleteObject(hrgnTemp);
+ }
return RegionType;
}
-/*
+BOOL FASTCALL
+co_UserGetUpdateRect(PWND Window, PRECT pRect, BOOL bErase)
+{
+ INT RegionType;
+ BOOL Ret = TRUE;
+
+ if (bErase)
+ {
+ USER_REFERENCE_ENTRY Ref;
+ UserRefObjectCo(Window, &Ref);
+ co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE);
+ UserDerefObjectCo(Window);
+ }
+
+ Window->state &= ~WNDS_UPDATEDIRTY;
+
+ if (Window->hrgnUpdate == NULL)
+ {
+ pRect->left = pRect->top = pRect->right = pRect->bottom = 0;
+ Ret = FALSE;
+ }
+ else
+ {
+ /* Get the update region bounding box. */
+ if (Window->hrgnUpdate == HRGN_WINDOW)
+ {
+ *pRect = Window->rcClient;
+ ERR("GURt: Caller is retrieving Window Region 1\n");
+ }
+ else
+ {
+ RegionType = IntGdiGetRgnBox(Window->hrgnUpdate, pRect);
+
+ if (RegionType != ERROR && RegionType != NULLREGION)
+ RECTL_bIntersectRect(pRect, pRect, &Window->rcClient);
+ }
+
+ if (IntIntersectWithParents(Window, pRect))
+ {
+ if (!UserIsDesktopWindow(Window))
+ {
+ RECTL_vOffsetRect(pRect,
+ -Window->rcClient.left,
+ -Window->rcClient.top);
+ }
+ if (Window->pcls->style & CS_OWNDC)
+ {
+ HDC hdc;
+ //DWORD layout;
+ hdc = UserGetDCEx(Window, NULL, DCX_USESTYLE);
+ //layout = NtGdiSetLayout(hdc, -1, 0);
+ //IntMapWindowPoints( 0, Window, (LPPOINT)pRect, 2 );
+ GreDPtoLP( hdc, (LPPOINT)pRect, 2 );
+ //NtGdiSetLayout(hdc, -1, layout);
+ UserReleaseDC(Window, hdc, FALSE);
+ }
+ }
+ else
+ {
+ pRect->left = pRect->top = pRect->right = pRect->bottom = 0;
+ }
+ }
+ return Ret;
+}
+
+/*
* NtUserGetUpdateRgn
*
* Status
DECLARE_RETURN(INT);
PWND Window;
INT ret;
- USER_REFERENCE_ENTRY Ref;
TRACE("Enter NtUserGetUpdateRgn\n");
UserEnterExclusive();
RETURN(ERROR);
}
- UserRefObjectCo(Window, &Ref);
ret = co_UserGetUpdateRgn(Window, hRgn, bErase);
- UserDerefObjectCo(Window);
RETURN(ret);
{
PWND Window;
RECTL Rect;
- INT RegionType;
- PROSRGNDATA RgnData;
NTSTATUS Status;
+ BOOL Ret;
DECLARE_RETURN(BOOL);
TRACE("Enter NtUserGetUpdateRect\n");
RETURN(FALSE);
}
- Window->state &= ~WNDS_UPDATEDIRTY;
-
- if (Window->hrgnUpdate == NULL)
- {
- Rect.left = Rect.top = Rect.right = Rect.bottom = 0;
- }
- else
- {
- /* Get the update region bounding box. */
- if (Window->hrgnUpdate == HRGN_WINDOW)
- {
- Rect = Window->rcClient;
- }
- else
- {
- RgnData = RGNOBJAPI_Lock(Window->hrgnUpdate, NULL);
- ASSERT(RgnData != NULL);
- RegionType = REGION_GetRgnBox(RgnData, &Rect);
- RGNOBJAPI_Unlock(RgnData);
-
- if (RegionType != ERROR && RegionType != NULLREGION)
- RECTL_bIntersectRect(&Rect, &Rect, &Window->rcClient);
- }
-
- if (IntIntersectWithParents(Window, &Rect))
- {
- RECTL_vOffsetRect(&Rect,
- -Window->rcClient.left,
- -Window->rcClient.top);
- } else
- {
- Rect.left = Rect.top = Rect.right = Rect.bottom = 0;
- }
- }
-
- if (bErase && !RECTL_bIsEmptyRect(&Rect))
- {
- USER_REFERENCE_ENTRY Ref;
- UserRefObjectCo(Window, &Ref);
- co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
- UserDerefObjectCo(Window);
- }
+ Ret = co_UserGetUpdateRect(Window, &Rect, bErase);
if (UnsafeRect != NULL)
{
}
}
- RETURN(!RECTL_bIsEmptyRect(&Rect));
+ RETURN(Ret);
CLEANUP:
TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_);
BOOL Ret;
USER_REFERENCE_ENTRY Ref;
NTSTATUS Status = STATUS_SUCCESS;
+ PREGION RgnUpdate = NULL;
DECLARE_RETURN(BOOL);
TRACE("Enter NtUserRedrawWindow\n");
RETURN( FALSE);
}
+ /* We can't hold lock on GDI objects while doing roundtrips to user mode,
+ * so it will be copied.
+ */
+ if (hrgnUpdate > HRGN_WINDOW)
+ {
+ RgnUpdate = REGION_LockRgn(hrgnUpdate);
+ if (!RgnUpdate)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ RETURN(FALSE);
+ }
+ REGION_UnlockRgn(RgnUpdate);
+ }
+ else if (hrgnUpdate == HRGN_WINDOW) // Trap it out.
+ {
+ ERR("NTRW: Caller is passing Window Region 1\n");
+ }
+
UserRefObjectCo(Wnd, &Ref);
Ret = co_UserRedrawWindow( Wnd,
lprcUpdate ? &SafeUpdateRect : NULL,
- hrgnUpdate,
+ RgnUpdate,
flags);
UserDerefObjectCo(Wnd);
END_CLEANUP;
}
-static
-INT FASTCALL
-UserScrollDC(
- HDC hDC,
- INT dx,
- INT dy,
- const RECTL *prcScroll,
- const RECTL *prcClip,
- HRGN hrgnUpdate,
- RECTL *prcUpdate)
-{
- PDC pDC;
- RECTL rcScroll, rcClip, rcSrc, rcDst;
- INT Result;
-
- GdiGetClipBox(hDC, &rcClip);
- rcScroll = rcClip;
- if (prcClip)
- {
- RECTL_bIntersectRect(&rcClip, &rcClip, prcClip);
- }
-
- if (prcScroll)
- {
- rcScroll = *prcScroll;
- RECTL_bIntersectRect(&rcSrc, &rcClip, prcScroll);
- }
- else
- {
- rcSrc = rcClip;
- }
-
- rcDst = rcSrc;
- RECTL_vOffsetRect(&rcDst, dx, dy);
- RECTL_bIntersectRect(&rcDst, &rcDst, &rcClip);
-
- if (!NtGdiBitBlt( hDC,
- rcDst.left,
- rcDst.top,
- rcDst.right - rcDst.left,
- rcDst.bottom - rcDst.top,
- hDC,
- rcDst.left - dx,
- rcDst.top - dy,
- SRCCOPY,
- 0,
- 0))
- {
- return ERROR;
- }
-
- /* Calculate the region that was invalidated by moving or
- could not be copied, because it was not visible */
- if (hrgnUpdate || prcUpdate)
- {
- HRGN hrgnOwn, hrgnTmp;
- PREGION prgnTmp;
-
- pDC = DC_LockDc(hDC);
- if (!pDC)
- {
- return FALSE;
- }
-
- /* Begin with the shifted and then clipped scroll rect */
- rcDst = rcScroll;
- RECTL_vOffsetRect(&rcDst, dx, dy);
- RECTL_bIntersectRect(&rcDst, &rcDst, &rcClip);
- if (hrgnUpdate)
- {
- hrgnOwn = hrgnUpdate;
- if (!NtGdiSetRectRgn(hrgnOwn, rcDst.left, rcDst.top, rcDst.right, rcDst.bottom))
- {
- DC_UnlockDc(pDC);
- return ERROR;
- }
- }
- else
- {
- hrgnOwn = IntSysCreateRectRgnIndirect(&rcDst);
- }
-
- /* Add the source rect */
- hrgnTmp = IntSysCreateRectRgnIndirect(&rcSrc);
- NtGdiCombineRgn(hrgnOwn, hrgnOwn, hrgnTmp, RGN_OR);
-
- /* Substract the part of the dest that was visible in source */
- prgnTmp = RGNOBJAPI_Lock(hrgnTmp, NULL);
- IntGdiCombineRgn(prgnTmp, prgnTmp, pDC->prgnVis, RGN_AND);
- RGNOBJAPI_Unlock(prgnTmp);
- NtGdiOffsetRgn(hrgnTmp, dx, dy);
- Result = NtGdiCombineRgn(hrgnOwn, hrgnOwn, hrgnTmp, RGN_DIFF);
-
- /* DO NOT Unlock DC while messing with prgnVis! */
- DC_UnlockDc(pDC);
-
- GreDeleteObject(hrgnTmp);
-
- if (prcUpdate)
- {
- IntGdiGetRgnBox(hrgnOwn, prcUpdate);
- }
-
- if (!hrgnUpdate)
- {
- GreDeleteObject(hrgnOwn);
- }
- }
- else
- Result = NULLREGION;
-
- return Result;
-}
-
-/*
- * NtUserScrollDC
- *
- * Status
- * @implemented
- */
-BOOL APIENTRY
-NtUserScrollDC(
- HDC hDC,
- INT dx,
- INT dy,
- const RECT *prcUnsafeScroll,
- const RECT *prcUnsafeClip,
- HRGN hrgnUpdate,
- LPRECT prcUnsafeUpdate)
-{
- DECLARE_RETURN(DWORD);
- RECTL rcScroll, rcClip, rcUpdate;
- NTSTATUS Status = STATUS_SUCCESS;
- DWORD Result;
-
- TRACE("Enter NtUserScrollDC\n");
- UserEnterExclusive();
-
- _SEH2_TRY
- {
- if (prcUnsafeScroll)
- {
- ProbeForRead(prcUnsafeScroll, sizeof(*prcUnsafeScroll), 1);
- rcScroll = *prcUnsafeScroll;
- }
- if (prcUnsafeClip)
- {
- ProbeForRead(prcUnsafeClip, sizeof(*prcUnsafeClip), 1);
- rcClip = *prcUnsafeClip;
- }
- if (prcUnsafeUpdate)
- {
- ProbeForWrite(prcUnsafeUpdate, sizeof(*prcUnsafeUpdate), 1);
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- RETURN(FALSE);
- }
-
- Result = UserScrollDC( hDC,
- dx,
- dy,
- prcUnsafeScroll? &rcScroll : 0,
- prcUnsafeClip? &rcClip : 0,
- hrgnUpdate,
- prcUnsafeUpdate? &rcUpdate : NULL);
- if(Result == ERROR)
- {
- /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
- RETURN(FALSE);
- }
-
- if (prcUnsafeUpdate)
- {
- _SEH2_TRY
- {
- *prcUnsafeUpdate = rcUpdate;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END
- if (!NT_SUCCESS(Status))
- {
- /* FIXME: SetLastError? */
- /* FIXME: correct? We have already scrolled! */
- RETURN(FALSE);
- }
- }
-
- RETURN(TRUE);
-
-CLEANUP:
- TRACE("Leave NtUserScrollDC, ret=%lu\n",_ret_);
- UserLeave();
- END_CLEANUP;
-}
-
-/*
- * NtUserScrollWindowEx
- *
- * Status
- * @implemented
- */
-
-DWORD APIENTRY
-NtUserScrollWindowEx(
- HWND hWnd,
- INT dx,
- INT dy,
- const RECT *prcUnsafeScroll,
- const RECT *prcUnsafeClip,
- HRGN hrgnUpdate,
- LPRECT prcUnsafeUpdate,
- UINT flags)
-{
- RECTL rcScroll, rcClip, rcCaret, rcUpdate;
- INT Result;
- PWND Window = NULL, CaretWnd;
- HDC hDC;
- HRGN hrgnOwn = NULL, hrgnTemp, hrgnWinupd = NULL;
- HWND hwndCaret;
- DWORD dcxflags = 0;
- int rdw_flags;
- BOOL bOwnRgn = TRUE;
- NTSTATUS Status = STATUS_SUCCESS;
- DECLARE_RETURN(DWORD);
- USER_REFERENCE_ENTRY Ref, CaretRef;
-
- TRACE("Enter NtUserScrollWindowEx\n");
- UserEnterExclusive();
-
- Window = UserGetWindowObject(hWnd);
- if (!Window || !IntIsWindowDrawable(Window))
- {
- Window = NULL; /* prevent deref at cleanup */
- RETURN( ERROR);
- }
- UserRefObjectCo(Window, &Ref);
-
- IntGetClientRect(Window, &rcClip);
-
- _SEH2_TRY
- {
- if (prcUnsafeScroll)
- {
- ProbeForRead(prcUnsafeScroll, sizeof(*prcUnsafeScroll), 1);
- RECTL_bIntersectRect(&rcScroll, &rcClip, prcUnsafeScroll);
- }
- else
- rcScroll = rcClip;
-
- if (prcUnsafeClip)
- {
- ProbeForRead(prcUnsafeClip, sizeof(*prcUnsafeClip), 1);
- RECTL_bIntersectRect(&rcClip, &rcClip, prcUnsafeClip);
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END
-
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- RETURN(ERROR);
- }
-
- if (rcClip.right <= rcClip.left || rcClip.bottom <= rcClip.top ||
- (dx == 0 && dy == 0))
- {
- RETURN(NULLREGION);
- }
-
- if (hrgnUpdate)
- {
- hrgnOwn = hrgnUpdate;
- bOwnRgn = FALSE;
- }
- else
- hrgnOwn = IntSysCreateRectRgn(0, 0, 0, 0);
-
- /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
- if (flags & SW_SCROLLWNDDCE)
- {
- dcxflags = DCX_USESTYLE;
-
- if (!(Window->pcls->style & (CS_OWNDC|CS_CLASSDC)))
- dcxflags |= DCX_CACHE; // AH??? wine~ If not Powned or with Class go Cheap!
-
- if (flags & SW_SCROLLCHILDREN && Window->style & WS_CLIPCHILDREN)
- dcxflags |= DCX_CACHE|DCX_NOCLIPCHILDREN;
- }
- else
- {
- /* So in this case ScrollWindowEx uses Cache DC. */
- dcxflags = DCX_CACHE|DCX_USESTYLE;
- if (flags & SW_SCROLLCHILDREN) dcxflags |= DCX_NOCLIPCHILDREN;
- }
-
- hDC = UserGetDCEx(Window, 0, dcxflags);
- if (!hDC)
- {
- /* FIXME: SetLastError? */
- RETURN(ERROR);
- }
-
- rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE ;
-
- rcCaret = rcScroll;
- hwndCaret = co_IntFixCaret(Window, &rcCaret, flags);
-
- Result = UserScrollDC( hDC,
- dx,
- dy,
- &rcScroll,
- &rcClip,
- hrgnOwn,
- prcUnsafeUpdate? &rcUpdate : NULL);
-
- UserReleaseDC(Window, hDC, FALSE);
-
- /*
- * Take into account the fact that some damage may have occurred during
- * the scroll. Keep a copy in hrgnWinupd to be added to hrngUpdate at the end.
- */
-
- hrgnTemp = IntSysCreateRectRgn(0, 0, 0, 0);
- if (co_UserGetUpdateRgn(Window, hrgnTemp, FALSE) != NULLREGION)
- {
- HRGN hrgnClip = IntSysCreateRectRgnIndirect(&rcClip);
- if (!bOwnRgn)
- {
- hrgnWinupd = IntSysCreateRectRgn( 0, 0, 0, 0);
- NtGdiCombineRgn( hrgnWinupd, hrgnTemp, 0, RGN_COPY);
- }
- NtGdiOffsetRgn(hrgnTemp, dx, dy);
- NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnClip, RGN_AND);
- if (!bOwnRgn) NtGdiCombineRgn( hrgnWinupd, hrgnWinupd, hrgnTemp, RGN_OR );
- co_UserRedrawWindow(Window, NULL, hrgnTemp, rdw_flags );
- GreDeleteObject(hrgnClip);
- }
- GreDeleteObject(hrgnTemp);
-
- if (flags & SW_SCROLLCHILDREN)
- {
- PWND Child;
- RECTL rcChild;
- POINT ClientOrigin;
- USER_REFERENCE_ENTRY WndRef;
- RECTL rcDummy;
-
- IntGetClientOrigin(Window, &ClientOrigin);
- for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
- {
- rcChild = Child->rcWindow;
- rcChild.left -= ClientOrigin.x;
- rcChild.top -= ClientOrigin.y;
- rcChild.right -= ClientOrigin.x;
- rcChild.bottom -= ClientOrigin.y;
-
- if (! prcUnsafeScroll || RECTL_bIntersectRect(&rcDummy, &rcChild, &rcScroll))
- {
- UserRefObjectCo(Child, &WndRef);
- co_WinPosSetWindowPos(Child, 0, rcChild.left + dx, rcChild.top + dy, 0, 0,
- SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
- SWP_NOREDRAW | SWP_DEFERERASE);
- UserDerefObjectCo(Child);
- }
- }
- }
-
- if (flags & (SW_INVALIDATE | SW_ERASE))
- {
- co_UserRedrawWindow(Window, NULL, hrgnOwn, rdw_flags |
- ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
- ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0));
- }
-
- if (hwndCaret && (CaretWnd = UserGetWindowObject(hwndCaret)))
- {
- UserRefObjectCo(CaretWnd, &CaretRef);
-
- co_IntSetCaretPos(rcCaret.left + dx, rcCaret.top + dy);
- co_UserShowCaret(CaretWnd);
-
- UserDerefObjectCo(CaretWnd);
- }
-
- if (prcUnsafeUpdate)
- {
- _SEH2_TRY
- {
- /* Probe here, to not fail on invalid pointer before scrolling */
- ProbeForWrite(prcUnsafeUpdate, sizeof(*prcUnsafeUpdate), 1);
- *prcUnsafeUpdate = rcUpdate;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END
-
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- RETURN(ERROR);
- }
- }
-
- RETURN(Result);
-
-CLEANUP:
- if (hrgnWinupd && !bOwnRgn)
- {
- NtGdiCombineRgn( hrgnOwn, hrgnOwn, hrgnWinupd, RGN_OR);
- GreDeleteObject(hrgnWinupd);
- }
-
- if (hrgnOwn && !hrgnUpdate)
- {
- GreDeleteObject(hrgnOwn);
- }
-
- if (Window)
- UserDerefObjectCo(Window);
-
- TRACE("Leave NtUserScrollWindowEx, ret=%lu\n",_ret_);
- UserLeave();
- END_CLEANUP;
-}
-
BOOL
UserDrawCaptionText(
+ PWND pWnd,
HDC hDc,
const PUNICODE_STRING Text,
const RECTL *lpRc,
NTSTATUS Status;
BOOLEAN bDeleteFont = FALSE;
SIZE Size;
+ BOOL Ret = TRUE;
+ ULONG fit = 0, Length;
+ RECTL r = *lpRc;
TRACE("UserDrawCaptionText: %wZ\n", Text);
nclm.cbSize = sizeof(nclm);
- if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS,
- sizeof(NONCLIENTMETRICS), &nclm, 0))
+ if (!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS, nclm.cbSize, &nclm, 0))
{
ERR("UserSystemParametersInfo() failed!\n");
return FALSE;
IntGdiSetBkMode(hDc, TRANSPARENT);
hOldFont = NtGdiSelectFont(hDc, hFont);
- if(!hOldFont)
- {
- ERR("SelectFont() failed!\n");
- /* Don't fail */
- }
if(uFlags & DC_INBUTTON)
OldTextColor = IntGdiSetTextColor(hDc, IntGetSysColor(COLOR_BTNTEXT));
else
- OldTextColor = IntGdiSetTextColor(hDc, IntGetSysColor(uFlags & DC_ACTIVE
- ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
+ OldTextColor = IntGdiSetTextColor(hDc,
+ IntGetSysColor(uFlags & DC_ACTIVE ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
+
+ // Adjust for system menu.
+ if (pWnd && pWnd->style & WS_SYSMENU)
+ {
+ r.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
+ if ((pWnd->style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW))
+ {
+ r.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
+ r.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
+ }
+ }
- // FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
- GreGetTextExtentW(hDc, Text->Buffer, Text->Length/sizeof(WCHAR), &Size, 0);
- GreExtTextOutW(hDc,
- lpRc->left, (lpRc->top + lpRc->bottom)/2 - Size.cy/2,
- 0, NULL, Text->Buffer, Text->Length/sizeof(WCHAR), NULL, 0);
+ GreGetTextExtentExW(hDc, Text->Buffer, Text->Length/sizeof(WCHAR), r.right - r.left, &fit, 0, &Size, 0);
+ Length = (Text->Length/sizeof(WCHAR) == fit ? fit : fit+1);
+
+ if (Text->Length/sizeof(WCHAR) > Length)
+ {
+ Ret = FALSE;
+ }
+
+ if (Ret)
+ { // Faster while in setup.
+ UserExtTextOutW( hDc,
+ lpRc->left,
+ lpRc->top + (lpRc->bottom - lpRc->top - Size.cy) / 2, // DT_SINGLELINE && DT_VCENTER
+ ETO_CLIPPED,
+ (RECTL *)lpRc,
+ Text->Buffer,
+ Length);
+ }
+ else
+ {
+ DrawTextW( hDc,
+ Text->Buffer,
+ Text->Length/sizeof(WCHAR),
+ (RECTL *)&r,
+ DT_END_ELLIPSIS|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_LEFT);
+ }
+
IntGdiSetTextColor(hDc, OldTextColor);
+
if (hOldFont)
NtGdiSelectFont(hDc, hOldFont);
+
if (bDeleteFont)
GreDeleteObject(hFont);
- return TRUE;
+ return Ret;
}
+//
+// This draws Buttons, Icons and Text...
+//
BOOL UserDrawCaption(
PWND pWnd,
HDC hDc,
RECTL_vMakeWellOrdered(lpRc);
+ /* Determine whether the icon needs to be displayed */
if (!hIcon && pWnd != NULL)
{
- HasIcon = (uFlags & DC_ICON) && (pWnd->style & WS_SYSMENU)
- && !(uFlags & DC_SMALLCAP) && !(pWnd->ExStyle & WS_EX_DLGMODALFRAME)
- && !(pWnd->ExStyle & WS_EX_TOOLWINDOW);
+ HasIcon = (uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP) &&
+ (pWnd->style & WS_SYSMENU) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW);
}
else
- HasIcon = (hIcon != 0);
+ HasIcon = (hIcon != NULL);
// Draw the caption background
if((uFlags & DC_GRADIENT) && !(uFlags & DC_INBUTTON))
{
PCURICON_OBJECT pIcon = NULL;
- if (!hIcon && pWnd)
+ if (hIcon)
{
- hIcon = NC_IconForWindow( pWnd );
+ pIcon = UserGetCurIconObject(hIcon);
+ }
+ else if (pWnd)
+ {
+ pIcon = NC_IconForWindow(pWnd);
+ // FIXME: NC_IconForWindow should reference it for us */
+ if (pIcon)
+ UserReferenceObject(pIcon);
}
-
- if (hIcon)
- pIcon = UserGetCurIconObject(hIcon);
if (pIcon)
{
LONG cx = UserGetSystemMetrics(SM_CXSMICON);
LONG cy = UserGetSystemMetrics(SM_CYSMICON);
LONG x = Rect.left - cx/2 + 1 + (Rect.bottom - Rect.top)/2; // this is really what Window does
- LONG y = (Rect.top + Rect.bottom)/2 - cy/2; // center
+ LONG y = (Rect.top + Rect.bottom - cy)/2; // center
UserDrawIconEx(hDc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL);
UserDereferenceObject(pIcon);
}
+ else
+ {
+ HasIcon = FALSE;
+ }
}
- if (hIcon)
+ if (HasIcon)
Rect.left += Rect.bottom - Rect.top;
if((uFlags & DC_TEXT))
{
+ BOOL Set = FALSE;
Rect.left += 2;
if (Str)
- UserDrawCaptionText(hDc, Str, &Rect, uFlags, hFont);
+ Set = UserDrawCaptionText(pWnd, hDc, Str, &Rect, uFlags, hFont);
else if (pWnd != NULL) // FIXME: Windows does not do that
{
UNICODE_STRING ustr;
ustr.Buffer = pWnd->strName.Buffer; // FIXME: LARGE_STRING truncated!
ustr.Length = (USHORT)min(pWnd->strName.Length, MAXUSHORT);
ustr.MaximumLength = (USHORT)min(pWnd->strName.MaximumLength, MAXUSHORT);
- UserDrawCaptionText(hDc, &ustr, &Rect, uFlags, hFont);
+ Set = UserDrawCaptionText(pWnd, hDc, &ustr, &Rect, uFlags, hFont);
+ }
+ if (pWnd)
+ {
+ if (Set)
+ pWnd->state2 &= ~WNDS2_CAPTIONTEXTTRUNCATED;
+ else
+ pWnd->state2 |= WNDS2_CAPTIONTEXTTRUNCATED;
}
}
if (str != NULL)
Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, &SafeStr, uFlags);
else
+ {
+ if ( RECTL_bIsEmptyRect(&SafeRect) && hFont == 0 && hIcon == 0 )
+ {
+ Ret = TRUE;
+ if (uFlags & DC_DRAWCAPTIONMD)
+ {
+ ERR("NC Caption Mode\n");
+ UserDrawCaptionBar(pWnd, hDC, uFlags);
+ goto Exit;
+ }
+ else if (uFlags & DC_DRAWFRAMEMD)
+ {
+ ERR("NC Paint Mode\n");
+ NC_DoNCPaint(pWnd, hDC, uFlags); // Update Menus too!
+ goto Exit;
+ }
+ }
Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, NULL, uFlags);
-
+ }
+Exit:
UserLeave();
return Ret;
}
LPCRECT lpRc,
UINT uFlags)
{
- return NtUserDrawCaptionTemp(hWnd, hDC, lpRc, 0, 0, NULL, uFlags);
+ return NtUserDrawCaptionTemp(hWnd, hDC, lpRc, 0, 0, NULL, uFlags);
+}
+
+INT FASTCALL
+co_UserExcludeUpdateRgn(HDC hDC, PWND Window)
+{
+ POINT pt;
+ RECT rc;
+
+ if (Window->hrgnUpdate)
+ {
+ if (Window->hrgnUpdate == HRGN_WINDOW)
+ {
+ return NtGdiIntersectClipRect(hDC, 0, 0, 0, 0);
+ }
+ else
+ {
+ INT ret = ERROR;
+ HRGN hrgn = NtGdiCreateRectRgn(0,0,0,0);
+
+ if ( hrgn && GreGetDCPoint( hDC, GdiGetDCOrg, &pt) )
+ {
+ if ( NtGdiGetRandomRgn( hDC, hrgn, CLIPRGN) == NULLREGION )
+ {
+ NtGdiOffsetRgn(hrgn, pt.x, pt.y);
+ }
+ else
+ {
+ HRGN hrgnScreen;
+ PMONITOR pm = UserGetPrimaryMonitor();
+ hrgnScreen = NtGdiCreateRectRgn(0,0,0,0);
+ NtGdiCombineRgn(hrgnScreen, hrgnScreen, pm->hrgnMonitor, RGN_OR);
+
+ NtGdiCombineRgn(hrgn, hrgnScreen, NULL, RGN_COPY);
+
+ GreDeleteObject(hrgnScreen);
+ }
+
+ NtGdiCombineRgn(hrgn, hrgn, Window->hrgnUpdate, RGN_DIFF);
+
+ NtGdiOffsetRgn(hrgn, -pt.x, -pt.y);
+
+ ret = NtGdiExtSelectClipRgn(hDC, hrgn, RGN_COPY);
+
+ GreDeleteObject(hrgn);
+ }
+ return ret;
+ }
+ }
+ else
+ {
+ return GdiGetClipBox( hDC, &rc);
+ }
+}
+
+INT
+APIENTRY
+NtUserExcludeUpdateRgn(
+ HDC hDC,
+ HWND hWnd)
+{
+ INT ret = ERROR;
+ PWND pWnd;
+
+ TRACE("Enter NtUserExcludeUpdateRgn\n");
+ UserEnterExclusive();
+
+ pWnd = UserGetWindowObject(hWnd);
+
+ if (hDC && pWnd)
+ ret = co_UserExcludeUpdateRgn(hDC, pWnd);
+
+ TRACE("Leave NtUserExcludeUpdateRgn, ret=%i\n", ret);
+
+ UserLeave();
+ return ret;
}
BOOL
if (hwnd)
{
- if (!(Window = UserGetWindowObject(hwnd)) || // FIXME:
- Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
- Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ if (!(Window = UserGetWindowObject(hwnd)) ||
+ UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
{
goto Exit;
}