1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window painting function
5 * FILE: win32ss/user/ntuser/painting.c
6 * PROGRAMER: Filip Navara (xnavara@volny.cz)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserPainting);
11
12 BOOL UserExtTextOutW(HDC hdc, INT x, INT y, UINT flags, PRECTL lprc,
13 LPCWSTR lpString, UINT count);
14
15 /* PRIVATE FUNCTIONS **********************************************************/
16
17 /**
18 * @name IntIntersectWithParents
19 *
20 * Intersect window rectangle with all parent client rectangles.
21 *
22 * @param Child
23 * Pointer to child window to start intersecting from.
24 * @param WindowRect
25 * Pointer to rectangle that we want to intersect in screen
26 * coordinates on input and intersected rectangle on output (if TRUE
27 * is returned).
28 *
29 * @return
30 * If any parent is minimized or invisible or the resulting rectangle
31 * is empty then FALSE is returned. Otherwise TRUE is returned.
32 */
33
34 BOOL FASTCALL
IntIntersectWithParents(PWND Child,RECTL * WindowRect)35 IntIntersectWithParents(PWND Child, RECTL *WindowRect)
36 {
37 PWND ParentWnd;
38
39 if (Child->ExStyle & WS_EX_REDIRECTED)
40 return TRUE;
41
42 ParentWnd = Child->spwndParent;
43 while (ParentWnd != NULL)
44 {
45 if (!(ParentWnd->style & WS_VISIBLE) ||
46 (ParentWnd->style & WS_MINIMIZE) ||
47 !RECTL_bIntersectRect(WindowRect, WindowRect, &ParentWnd->rcClient) )
48 {
49 return FALSE;
50 }
51
52 if (ParentWnd->ExStyle & WS_EX_REDIRECTED)
53 return TRUE;
54
55 ParentWnd = ParentWnd->spwndParent;
56 }
57
58 return TRUE;
59 }
60
61 BOOL FASTCALL
IntValidateParents(PWND Child,BOOL Recurse)62 IntValidateParents(PWND Child, BOOL Recurse)
63 {
64 RECTL ParentRect, Rect;
65 BOOL Start, Ret = TRUE;
66 PWND ParentWnd = Child;
67 PREGION Rgn = NULL;
68
69 if (ParentWnd->style & WS_CHILD)
70 {
71 do
72 ParentWnd = ParentWnd->spwndParent;
73 while (ParentWnd->style & WS_CHILD);
74 }
75
76 // No pending nonclient paints.
77 if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE;
78
79 Start = TRUE;
80 ParentWnd = Child->spwndParent;
81 while (ParentWnd)
82 {
83 if (ParentWnd->style & WS_CLIPCHILDREN)
84 break;
85
86 if (ParentWnd->hrgnUpdate != 0)
87 {
88 if (Recurse)
89 {
90 Ret = FALSE;
91 break;
92 }
93 // Start with child clipping.
94 if (Start)
95 {
96 Start = FALSE;
97
98 Rect = Child->rcWindow;
99
100 if (!IntIntersectWithParents(Child, &Rect)) break;
101
102 Rgn = IntSysCreateRectpRgnIndirect(&Rect);
103
104 if (Child->hrgnClip)
105 {
106 PREGION RgnClip = REGION_LockRgn(Child->hrgnClip);
107 IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND);
108 REGION_UnlockRgn(RgnClip);
109 }
110 }
111
112 ParentRect = ParentWnd->rcWindow;
113
114 if (!IntIntersectWithParents(ParentWnd, &ParentRect)) break;
115
116 IntInvalidateWindows( ParentWnd,
117 Rgn,
118 RDW_VALIDATE | RDW_NOCHILDREN | RDW_NOUPDATEDIRTY);
119 }
120 ParentWnd = ParentWnd->spwndParent;
121 }
122
123 if (Rgn) REGION_Delete(Rgn);
124
125 return Ret;
126 }
127
128 /*
129 Synchronize painting to the top-level windows of other threads.
130 */
131 VOID FASTCALL
IntSendSyncPaint(PWND Wnd,ULONG Flags)132 IntSendSyncPaint(PWND Wnd, ULONG Flags)
133 {
134 PTHREADINFO ptiCur, ptiWnd;
135 PUSER_SENT_MESSAGE Message;
136 PLIST_ENTRY Entry;
137 BOOL bSend = TRUE;
138
139 ptiWnd = Wnd->head.pti;
140 ptiCur = PsGetCurrentThreadWin32Thread();
141 /*
142 Not the current thread, Wnd is in send Nonclient paint also in send erase background and it is visiable.
143 */
144 if ( Wnd->head.pti != ptiCur &&
145 Wnd->state & WNDS_SENDNCPAINT &&
146 Wnd->state & WNDS_SENDERASEBACKGROUND &&
147 Wnd->style & WS_VISIBLE)
148 {
149 // For testing, if you see this, break out the Champagne and have a party!
150 TRACE("SendSyncPaint Wnd in State!\n");
151 if (!IsListEmpty(&ptiWnd->SentMessagesListHead))
152 {
153 // Scan sent queue messages to see if we received sync paint messages.
154 Entry = ptiWnd->SentMessagesListHead.Flink;
155 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
156 do
157 {
158 TRACE("LOOP it\n");
159 if (Message->Msg.message == WM_SYNCPAINT &&
160 Message->Msg.hwnd == UserHMGetHandle(Wnd))
161 { // Already received so exit out.
162 ERR("SendSyncPaint Found one in the Sent Msg Queue!\n");
163 bSend = FALSE;
164 break;
165 }
166 Entry = Message->ListEntry.Flink;
167 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
168 }
169 while (Entry != &ptiWnd->SentMessagesListHead);
170 }
171 if (bSend)
172 {
173 TRACE("Sending WM_SYNCPAINT\n");
174 // This message has no parameters. But it does! Pass Flags along.
175 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SYNCPAINT, Flags, 0);
176 Wnd->state |= WNDS_SYNCPAINTPENDING;
177 }
178 }
179
180 // Send to all the children if this is the desktop window.
181 if (UserIsDesktopWindow(Wnd))
182 {
183 if ( Flags & RDW_ALLCHILDREN ||
184 ( !(Flags & RDW_NOCHILDREN) && Wnd->style & WS_CLIPCHILDREN))
185 {
186 PWND spwndChild = Wnd->spwndChild;
187 while(spwndChild)
188 {
189 if ( spwndChild->style & WS_CHILD &&
190 spwndChild->head.pti != ptiCur)
191 {
192 spwndChild = spwndChild->spwndNext;
193 continue;
194 }
195 IntSendSyncPaint( spwndChild, Flags );
196 spwndChild = spwndChild->spwndNext;
197 }
198 }
199 }
200 }
201
202 /*
203 * @name IntCalcWindowRgn
204 *
205 * Get a window or client region.
206 */
207
208 HRGN FASTCALL
IntCalcWindowRgn(PWND Wnd,BOOL Client)209 IntCalcWindowRgn(PWND Wnd, BOOL Client)
210 {
211 HRGN hRgnWindow;
212
213 if (Client)
214 {
215 hRgnWindow = NtGdiCreateRectRgn(
216 Wnd->rcClient.left,
217 Wnd->rcClient.top,
218 Wnd->rcClient.right,
219 Wnd->rcClient.bottom);
220 }
221 else
222 {
223 hRgnWindow = NtGdiCreateRectRgn(
224 Wnd->rcWindow.left,
225 Wnd->rcWindow.top,
226 Wnd->rcWindow.right,
227 Wnd->rcWindow.bottom);
228 }
229
230 if (Wnd->hrgnClip != NULL && !(Wnd->style & WS_MINIMIZE))
231 {
232 NtGdiOffsetRgn(hRgnWindow,
233 -Wnd->rcWindow.left,
234 -Wnd->rcWindow.top);
235 NtGdiCombineRgn(hRgnWindow, hRgnWindow, Wnd->hrgnClip, RGN_AND);
236 NtGdiOffsetRgn(hRgnWindow,
237 Wnd->rcWindow.left,
238 Wnd->rcWindow.top);
239 }
240
241 return hRgnWindow;
242 }
243
244 /*
245 * @name IntGetNCUpdateRgn
246 *
247 * Get non-client update region of a window and optionally validate it.
248 *
249 * @param Window
250 * Pointer to window to get the NC update region from.
251 * @param Validate
252 * Set to TRUE to force validating the NC update region.
253 *
254 * @return
255 * Handle to NC update region. The caller is responsible for deleting
256 * it.
257 */
258
259 HRGN FASTCALL
IntGetNCUpdateRgn(PWND Window,BOOL Validate)260 IntGetNCUpdateRgn(PWND Window, BOOL Validate)
261 {
262 HRGN hRgnNonClient;
263 HRGN hRgnWindow;
264 UINT RgnType, NcType;
265 RECT update;
266
267 if (Window->hrgnUpdate != NULL &&
268 Window->hrgnUpdate != HRGN_WINDOW)
269 {
270 hRgnNonClient = IntCalcWindowRgn(Window, FALSE);
271
272 /*
273 * If region creation fails it's safe to fallback to whole
274 * window region.
275 */
276 if (hRgnNonClient == NULL)
277 {
278 return HRGN_WINDOW;
279 }
280
281 hRgnWindow = IntCalcWindowRgn(Window, TRUE);
282 if (hRgnWindow == NULL)
283 {
284 GreDeleteObject(hRgnNonClient);
285 return HRGN_WINDOW;
286 }
287
288 NcType = IntGdiGetRgnBox(hRgnNonClient, &update);
289
290 RgnType = NtGdiCombineRgn(hRgnNonClient, hRgnNonClient, hRgnWindow, RGN_DIFF);
291
292 if (RgnType == ERROR)
293 {
294 GreDeleteObject(hRgnWindow);
295 GreDeleteObject(hRgnNonClient);
296 return HRGN_WINDOW;
297 }
298 else if (RgnType == NULLREGION)
299 {
300 GreDeleteObject(hRgnWindow);
301 GreDeleteObject(hRgnNonClient);
302 Window->state &= ~WNDS_UPDATEDIRTY;
303 return NULL;
304 }
305
306 /*
307 * Remove the nonclient region from the standard update region if
308 * we were asked for it.
309 */
310
311 if (Validate)
312 {
313 if (NtGdiCombineRgn(Window->hrgnUpdate, Window->hrgnUpdate, hRgnWindow, RGN_AND) == NULLREGION)
314 {
315 IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
316 GreDeleteObject(Window->hrgnUpdate);
317 Window->state &= ~WNDS_UPDATEDIRTY;
318 Window->hrgnUpdate = NULL;
319 if (!(Window->state & WNDS_INTERNALPAINT))
320 MsqDecPaintCountQueue(Window->head.pti);
321 }
322 }
323
324 /* check if update rgn contains complete nonclient area */
325 if (NcType == SIMPLEREGION)
326 {
327 RECT window;
328 IntGetWindowRect( Window, &window );
329
330 if (IntEqualRect( &window, &update ))
331 {
332 GreDeleteObject(hRgnNonClient);
333 hRgnNonClient = HRGN_WINDOW;
334 }
335 }
336
337 GreDeleteObject(hRgnWindow);
338
339 return hRgnNonClient;
340 }
341 else
342 {
343 return Window->hrgnUpdate;
344 }
345 }
346
347 VOID FASTCALL
IntSendNCPaint(PWND pWnd,HRGN hRgn)348 IntSendNCPaint(PWND pWnd, HRGN hRgn)
349 {
350 pWnd->state &= ~WNDS_SENDNCPAINT;
351
352 if ( pWnd == GetW32ThreadInfo()->MessageQueue->spwndActive &&
353 !(pWnd->state & WNDS_ACTIVEFRAME))
354 {
355 pWnd->state |= WNDS_ACTIVEFRAME;
356 pWnd->state &= ~WNDS_NONCPAINT;
357 hRgn = HRGN_WINDOW;
358 }
359
360 if (pWnd->state2 & WNDS2_FORCEFULLNCPAINTCLIPRGN)
361 {
362 pWnd->state2 &= ~WNDS2_FORCEFULLNCPAINTCLIPRGN;
363 hRgn = HRGN_WINDOW;
364 }
365
366 if (hRgn) co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCPAINT, (WPARAM)hRgn, 0);
367 }
368
369 VOID FASTCALL
IntSendChildNCPaint(PWND pWnd)370 IntSendChildNCPaint(PWND pWnd)
371 {
372 pWnd = pWnd->spwndChild;
373 while (pWnd)
374 {
375 if ((pWnd->hrgnUpdate == NULL) && (pWnd->state & WNDS_SENDNCPAINT))
376 {
377 PWND Next;
378 USER_REFERENCE_ENTRY Ref;
379
380 /* Reference, IntSendNCPaint leaves win32k */
381 UserRefObjectCo(pWnd, &Ref);
382 IntSendNCPaint(pWnd, HRGN_WINDOW);
383
384 /* Make sure to grab next one before dereferencing/freeing */
385 Next = pWnd->spwndNext;
386 UserDerefObjectCo(pWnd);
387 pWnd = Next;
388 }
389 else
390 {
391 pWnd = pWnd->spwndNext;
392 }
393 }
394 }
395
396 /*
397 * IntPaintWindows
398 *
399 * Internal function used by IntRedrawWindow.
400 */
401
402 VOID FASTCALL
co_IntPaintWindows(PWND Wnd,ULONG Flags,BOOL Recurse)403 co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
404 {
405 HDC hDC;
406 HWND hWnd = UserHMGetHandle(Wnd);
407 HRGN TempRegion = NULL;
408
409 Wnd->state &= ~WNDS_PAINTNOTPROCESSED;
410
411 if (Wnd->state & WNDS_SENDNCPAINT ||
412 Wnd->state & WNDS_SENDERASEBACKGROUND)
413 {
414 if (!(Wnd->style & WS_VISIBLE))
415 {
416 Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
417 return;
418 }
419 else
420 {
421 if (Wnd->hrgnUpdate == NULL)
422 {
423 Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
424 }
425
426 if (Wnd->head.pti == PsGetCurrentThreadWin32Thread())
427 {
428 if (Wnd->state & WNDS_SENDNCPAINT)
429 {
430 TempRegion = IntGetNCUpdateRgn(Wnd, TRUE);
431
432 IntSendNCPaint(Wnd, TempRegion);
433
434 if (TempRegion > HRGN_WINDOW && GreIsHandleValid(TempRegion))
435 {
436 /* NOTE: The region can already be deleted! */
437 GreDeleteObject(TempRegion);
438 }
439 }
440
441 if (Wnd->state & WNDS_SENDERASEBACKGROUND)
442 {
443 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
444 if (Wnd->hrgnUpdate)
445 {
446 hDC = UserGetDCEx( Wnd,
447 Wnd->hrgnUpdate,
448 DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN);
449
450 if (Wnd->head.pti->ppi != pti->ppi)
451 {
452 ERR("Sending DC to another Process!!!\n");
453 }
454
455 Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
456 // Kill the loop, so Clear before we send.
457 if (!co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
458 {
459 Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
460 }
461 UserReleaseDC(Wnd, hDC, FALSE);
462 }
463 }
464 }
465
466 }
467 }
468
469 /*
470 * Check that the window is still valid at this point
471 */
472 if (!IntIsWindow(hWnd))
473 {
474 return;
475 }
476
477 /*
478 * Paint child windows.
479 */
480
481 if (!(Flags & RDW_NOCHILDREN) &&
482 !(Wnd->style & WS_MINIMIZE) &&
483 ( Flags & RDW_ALLCHILDREN ||
484 (Flags & RDW_CLIPCHILDREN && Wnd->style & WS_CLIPCHILDREN) ) )
485 {
486 HWND *List, *phWnd;
487 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
488
489 if ((List = IntWinListChildren(Wnd)))
490 {
491 for (phWnd = List; *phWnd; ++phWnd)
492 {
493 if ((Wnd = UserGetWindowObject(*phWnd)) == NULL)
494 continue;
495
496 if (Wnd->head.pti != pti && Wnd->style & WS_CHILD)
497 continue;
498
499 if (Wnd->style & WS_VISIBLE)
500 {
501 USER_REFERENCE_ENTRY Ref;
502 UserRefObjectCo(Wnd, &Ref);
503 co_IntPaintWindows(Wnd, Flags, TRUE);
504 UserDerefObjectCo(Wnd);
505 }
506 }
507 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
508 }
509 }
510 }
511
512 /*
513 * IntUpdateWindows
514 *
515 * Internal function used by IntRedrawWindow, simplecall.
516 */
517
518 VOID FASTCALL
co_IntUpdateWindows(PWND Wnd,ULONG Flags,BOOL Recurse)519 co_IntUpdateWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
520 {
521 HWND hWnd = UserHMGetHandle(Wnd);
522 USER_REFERENCE_ENTRY Ref;
523
524 if ( Wnd->hrgnUpdate != NULL || Wnd->state & WNDS_INTERNALPAINT )
525 {
526 if (Wnd->hrgnUpdate)
527 {
528 if (!IntValidateParents(Wnd, Recurse))
529 {
530 return;
531 }
532 }
533
534 if (Wnd->state & WNDS_INTERNALPAINT)
535 {
536 Wnd->state &= ~WNDS_INTERNALPAINT;
537
538 if (Wnd->hrgnUpdate == NULL)
539 MsqDecPaintCountQueue(Wnd->head.pti);
540 }
541
542 Wnd->state |= WNDS_PAINTNOTPROCESSED;
543 Wnd->state &= ~WNDS_UPDATEDIRTY;
544
545 Wnd->state2 |= WNDS2_WMPAINTSENT;
546
547 UserRefObjectCo(Wnd, &Ref);
548 co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
549
550 if (Wnd->state & WNDS_PAINTNOTPROCESSED)
551 {
552 co_IntPaintWindows(Wnd, RDW_NOCHILDREN, FALSE);
553 }
554 UserDerefObjectCo(Wnd);
555 }
556
557 // Force flags as a toggle. Fixes msg:test_paint_messages:WmChildPaintNc.
558 Flags = (Flags & RDW_NOCHILDREN) ? RDW_NOCHILDREN : RDW_ALLCHILDREN; // All children is the default.
559
560 /*
561 * Update child windows.
562 */
563
564 if (!(Flags & RDW_NOCHILDREN) &&
565 (Flags & RDW_ALLCHILDREN) &&
566 !UserIsDesktopWindow(Wnd))
567 {
568 PWND Child;
569
570 for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext)
571 {
572 /* transparent window, check for non-transparent sibling to paint first, then skip it */
573 if ( Child->ExStyle & WS_EX_TRANSPARENT &&
574 ( Child->hrgnUpdate != NULL || Child->state & WNDS_INTERNALPAINT ) )
575 {
576 PWND Next = Child->spwndNext;
577 while (Next)
578 {
579 if ( Next->hrgnUpdate != NULL || Next->state & WNDS_INTERNALPAINT ) break;
580
581 Next = Next->spwndNext;
582 }
583
584 if (Next) continue;
585 }
586
587 if (Child->style & WS_VISIBLE)
588 {
589 USER_REFERENCE_ENTRY Ref;
590 UserRefObjectCo(Child, &Ref);
591 co_IntUpdateWindows(Child, Flags, TRUE);
592 UserDerefObjectCo(Child);
593 }
594 }
595 }
596 }
597
598 VOID FASTCALL
UserUpdateWindows(PWND pWnd,ULONG Flags)599 UserUpdateWindows(PWND pWnd, ULONG Flags)
600 {
601 // If transparent and any sibling windows below needs to be painted, leave.
602 if (pWnd->ExStyle & WS_EX_TRANSPARENT)
603 {
604 PWND Next = pWnd->spwndNext;
605
606 while(Next)
607 {
608 if ( Next->head.pti == pWnd->head.pti &&
609 ( Next->hrgnUpdate != NULL || Next->state & WNDS_INTERNALPAINT) )
610 {
611 return;
612 }
613
614 Next = Next->spwndNext;
615 }
616 }
617 co_IntUpdateWindows(pWnd, Flags, FALSE);
618 }
619
620 VOID FASTCALL
UserSyncAndPaintWindows(PWND pWnd,ULONG Flags)621 UserSyncAndPaintWindows(PWND pWnd, ULONG Flags)
622 {
623 PWND Parent = pWnd;
624 // Find parent, if it needs to be painted, leave.
625 while(TRUE)
626 {
627 if ((Parent = Parent->spwndParent) == NULL) break;
628 if ( Parent->style & WS_CLIPCHILDREN ) break;
629 if ( Parent->hrgnUpdate != NULL || Parent->state & WNDS_INTERNALPAINT ) return;
630 }
631
632 IntSendSyncPaint(pWnd, Flags);
633 co_IntPaintWindows(pWnd, Flags, FALSE);
634 }
635
636 /*
637 * IntInvalidateWindows
638 *
639 * Internal function used by IntRedrawWindow, UserRedrawDesktop,
640 * co_WinPosSetWindowPos, co_UserRedrawWindow.
641 */
642 VOID FASTCALL
IntInvalidateWindows(PWND Wnd,PREGION Rgn,ULONG Flags)643 IntInvalidateWindows(PWND Wnd, PREGION Rgn, ULONG Flags)
644 {
645 INT RgnType = NULLREGION;
646 BOOL HadPaintMessage;
647
648 TRACE("IntInvalidateWindows start Rgn %p\n",Rgn);
649
650 if ( Rgn > PRGN_WINDOW )
651 {
652 /*
653 * If the nonclient is not to be redrawn, clip the region to the client
654 * rect
655 */
656 if ((Flags & RDW_INVALIDATE) != 0 && (Flags & RDW_FRAME) == 0)
657 {
658 PREGION RgnClient;
659
660 RgnClient = IntSysCreateRectpRgnIndirect(&Wnd->rcClient);
661 if (RgnClient)
662 {
663 RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClient, RGN_AND);
664 REGION_Delete(RgnClient);
665 }
666 }
667
668 /*
669 * Clip the given region with window rectangle (or region)
670 */
671
672 if (!Wnd->hrgnClip || (Wnd->style & WS_MINIMIZE))
673 {
674 PREGION RgnWindow = IntSysCreateRectpRgnIndirect(&Wnd->rcWindow);
675 if (RgnWindow)
676 {
677 RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnWindow, RGN_AND);
678 REGION_Delete(RgnWindow);
679 }
680 }
681 else
682 {
683 PREGION RgnClip = REGION_LockRgn(Wnd->hrgnClip);
684 if (RgnClip)
685 {
686 REGION_bOffsetRgn(Rgn,
687 -Wnd->rcWindow.left,
688 -Wnd->rcWindow.top);
689 RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND);
690 REGION_bOffsetRgn(Rgn,
691 Wnd->rcWindow.left,
692 Wnd->rcWindow.top);
693 REGION_UnlockRgn(RgnClip);
694 }
695 }
696 }
697 else
698 {
699 RgnType = NULLREGION;
700 }
701
702 /* Nothing to paint, just return */
703 if ((RgnType == NULLREGION && (Flags & RDW_INVALIDATE)) || RgnType == ERROR)
704 {
705 return;
706 }
707
708 /*
709 * Save current state of pending updates
710 */
711
712 HadPaintMessage = IntIsWindowDirty(Wnd);
713
714 /*
715 * Update the region and flags
716 */
717
718 // The following flags are used to invalidate the window.
719 if (Flags & (RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_ERASE|RDW_FRAME))
720 {
721 if (Flags & RDW_INTERNALPAINT)
722 {
723 Wnd->state |= WNDS_INTERNALPAINT;
724 }
725
726 if (Flags & RDW_INVALIDATE )
727 {
728 PREGION RgnUpdate;
729
730 Wnd->state &= ~WNDS_NONCPAINT;
731
732 /* If not the same thread set it dirty. */
733 if (Wnd->head.pti != PsGetCurrentThreadWin32Thread())
734 {
735 Wnd->state |= WNDS_UPDATEDIRTY;
736 if (Wnd->state2 & WNDS2_WMPAINTSENT)
737 Wnd->state2 |= WNDS2_ENDPAINTINVALIDATE;
738 }
739
740 if (Flags & RDW_FRAME)
741 Wnd->state |= WNDS_SENDNCPAINT;
742
743 if (Flags & RDW_ERASE)
744 Wnd->state |= WNDS_SENDERASEBACKGROUND;
745
746 if (RgnType != NULLREGION && Rgn > PRGN_WINDOW)
747 {
748 if (Wnd->hrgnUpdate == NULL)
749 {
750 Wnd->hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0);
751 IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC);
752 }
753
754 if (Wnd->hrgnUpdate != HRGN_WINDOW)
755 {
756 RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate);
757 if (RgnUpdate)
758 {
759 RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_OR);
760 REGION_UnlockRgn(RgnUpdate);
761 if (RgnType == NULLREGION)
762 {
763 IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
764 GreDeleteObject(Wnd->hrgnUpdate);
765 Wnd->hrgnUpdate = NULL;
766 }
767 }
768 }
769 }
770
771 Flags |= RDW_ERASE|RDW_FRAME; // For children.
772
773 }
774
775 if (!HadPaintMessage && IntIsWindowDirty(Wnd))
776 {
777 MsqIncPaintCountQueue(Wnd->head.pti);
778 }
779
780 } // The following flags are used to validate the window.
781 else if (Flags & (RDW_VALIDATE|RDW_NOINTERNALPAINT|RDW_NOERASE|RDW_NOFRAME))
782 {
783 if (Wnd->state & WNDS_UPDATEDIRTY && !(Flags & RDW_NOUPDATEDIRTY))
784 return;
785
786 if (Flags & RDW_NOINTERNALPAINT)
787 {
788 Wnd->state &= ~WNDS_INTERNALPAINT;
789 }
790
791 if (Flags & RDW_VALIDATE)
792 {
793 if (Flags & RDW_NOFRAME)
794 Wnd->state &= ~WNDS_SENDNCPAINT;
795
796 if (Flags & RDW_NOERASE)
797 Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
798
799 if (Wnd->hrgnUpdate > HRGN_WINDOW && RgnType != NULLREGION && Rgn > PRGN_WINDOW)
800 {
801 PREGION RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate);
802
803 if (RgnUpdate)
804 {
805 RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_DIFF);
806 REGION_UnlockRgn(RgnUpdate);
807
808 if (RgnType == NULLREGION)
809 {
810 IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
811 GreDeleteObject(Wnd->hrgnUpdate);
812 Wnd->hrgnUpdate = NULL;
813 }
814 }
815 }
816 // If update is null, do not erase.
817 if (Wnd->hrgnUpdate == NULL)
818 {
819 Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
820 }
821 }
822
823 if (HadPaintMessage && !IntIsWindowDirty(Wnd))
824 {
825 MsqDecPaintCountQueue(Wnd->head.pti);
826 }
827 }
828
829 /*
830 * Process children if needed
831 */
832
833 if (!(Flags & RDW_NOCHILDREN) &&
834 !(Wnd->style & WS_MINIMIZE) &&
835 ((Flags & RDW_ALLCHILDREN) || !(Wnd->style & WS_CLIPCHILDREN)))
836 {
837 PWND Child;
838
839 for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext)
840 {
841 if (Child->style & WS_VISIBLE)
842 {
843 /*
844 * Recursive call to update children hrgnUpdate
845 */
846 PREGION RgnTemp = IntSysCreateRectpRgn(0, 0, 0, 0);
847 if (RgnTemp)
848 {
849 if (Rgn > PRGN_WINDOW) IntGdiCombineRgn(RgnTemp, Rgn, 0, RGN_COPY);
850 IntInvalidateWindows(Child, ((Rgn > PRGN_WINDOW)?RgnTemp:Rgn), Flags);
851 REGION_Delete(RgnTemp);
852 }
853 }
854 }
855 }
856 TRACE("IntInvalidateWindows exit\n");
857 }
858
859 /*
860 * IntIsWindowDrawable
861 *
862 * Remarks
863 * Window is drawable when it is visible and all parents are not
864 * minimized.
865 */
866
867 BOOL FASTCALL
IntIsWindowDrawable(PWND Wnd)868 IntIsWindowDrawable(PWND Wnd)
869 {
870 PWND WndObject;
871
872 for (WndObject = Wnd; WndObject != NULL; WndObject = WndObject->spwndParent)
873 {
874 if ( WndObject->state2 & WNDS2_INDESTROY ||
875 WndObject->state & WNDS_DESTROYED ||
876 !WndObject ||
877 !(WndObject->style & WS_VISIBLE) ||
878 ((WndObject->style & WS_MINIMIZE) && (WndObject != Wnd)))
879 {
880 return FALSE;
881 }
882 }
883
884 return TRUE;
885 }
886
887 /*
888 * IntRedrawWindow
889 *
890 * Internal version of NtUserRedrawWindow that takes WND as
891 * first parameter.
892 */
893
894 BOOL FASTCALL
co_UserRedrawWindow(PWND Window,const RECTL * UpdateRect,PREGION UpdateRgn,ULONG Flags)895 co_UserRedrawWindow(
896 PWND Window,
897 const RECTL* UpdateRect,
898 PREGION UpdateRgn,
899 ULONG Flags)
900 {
901 PREGION TmpRgn = NULL;
902 TRACE("co_UserRedrawWindow start Rgn %p\n",UpdateRgn);
903
904 /*
905 * Step 1.
906 * Validation of passed parameters.
907 */
908
909 if (!IntIsWindowDrawable(Window))
910 {
911 return TRUE; // Just do nothing!!!
912 }
913
914 if (Window == NULL)
915 {
916 Window = UserGetDesktopWindow();
917 }
918
919 /*
920 * Step 2.
921 * Transform the parameters UpdateRgn and UpdateRect into
922 * a region hRgn specified in screen coordinates.
923 */
924
925 if (Flags & (RDW_INVALIDATE | RDW_VALIDATE)) // Both are OKAY!
926 {
927 /* We can't hold lock on GDI objects while doing roundtrips to user mode,
928 * so use a copy instead */
929 if (UpdateRgn)
930 {
931 TmpRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
932
933 if (UpdateRgn > PRGN_WINDOW)
934 {
935 IntGdiCombineRgn(TmpRgn, UpdateRgn, NULL, RGN_COPY);
936 }
937
938 if (Window != UserGetDesktopWindow())
939 {
940 REGION_bOffsetRgn(TmpRgn, Window->rcClient.left, Window->rcClient.top);
941 }
942 }
943 else
944 {
945 if (UpdateRect != NULL)
946 {
947 if (Window == UserGetDesktopWindow())
948 {
949 TmpRgn = IntSysCreateRectpRgnIndirect(UpdateRect);
950 }
951 else
952 {
953 TmpRgn = IntSysCreateRectpRgn(Window->rcClient.left + UpdateRect->left,
954 Window->rcClient.top + UpdateRect->top,
955 Window->rcClient.left + UpdateRect->right,
956 Window->rcClient.top + UpdateRect->bottom);
957 }
958 }
959 else
960 {
961 if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
962 (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
963 {
964 if (!RECTL_bIsEmptyRect(&Window->rcWindow))
965 TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcWindow);
966 }
967 else
968 {
969 if (!RECTL_bIsEmptyRect(&Window->rcClient))
970 TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcClient);
971 }
972 }
973 }
974 }
975
976 /* Fixes test RDW_INTERNALPAINT behavior */
977 if (TmpRgn == NULL)
978 {
979 TmpRgn = PRGN_WINDOW; // Need a region so the bits can be set!!!
980 }
981
982 /*
983 * Step 3.
984 * Adjust the window update region depending on hRgn and flags.
985 */
986
987 if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) &&
988 TmpRgn != NULL)
989 {
990 IntInvalidateWindows(Window, TmpRgn, Flags);
991 }
992
993 /*
994 * Step 4.
995 * Repaint and erase windows if needed.
996 */
997
998 if (Flags & RDW_UPDATENOW)
999 {
1000 UserUpdateWindows(Window, Flags);
1001 }
1002 else if (Flags & RDW_ERASENOW)
1003 {
1004 if ((Flags & (RDW_NOCHILDREN|RDW_ALLCHILDREN)) == 0)
1005 Flags |= RDW_CLIPCHILDREN;
1006
1007 UserSyncAndPaintWindows(Window, Flags);
1008 }
1009
1010 /*
1011 * Step 5.
1012 * Cleanup ;-)
1013 */
1014
1015 if (TmpRgn > PRGN_WINDOW)
1016 {
1017 REGION_Delete(TmpRgn);
1018 }
1019 TRACE("co_UserRedrawWindow exit\n");
1020
1021 return TRUE;
1022 }
1023
1024 VOID FASTCALL
PaintSuspendedWindow(PWND pwnd,HRGN hrgnOrig)1025 PaintSuspendedWindow(PWND pwnd, HRGN hrgnOrig)
1026 {
1027 if (pwnd->hrgnUpdate)
1028 {
1029 HDC hDC;
1030 INT Flags = DC_NC|DC_NOSENDMSG;
1031 HRGN hrgnTemp;
1032 RECT Rect;
1033 INT type;
1034 PREGION prgn;
1035
1036 if (pwnd->hrgnUpdate > HRGN_WINDOW)
1037 {
1038 hrgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
1039 type = NtGdiCombineRgn( hrgnTemp, pwnd->hrgnUpdate, 0, RGN_COPY);
1040 if (type == ERROR)
1041 {
1042 GreDeleteObject(hrgnTemp);
1043 hrgnTemp = HRGN_WINDOW;
1044 }
1045 }
1046 else
1047 {
1048 hrgnTemp = GreCreateRectRgnIndirect(&pwnd->rcWindow);
1049 }
1050
1051 if ( hrgnOrig &&
1052 hrgnTemp > HRGN_WINDOW &&
1053 NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnOrig, RGN_AND) == NULLREGION)
1054 {
1055 GreDeleteObject(hrgnTemp);
1056 return;
1057 }
1058
1059 hDC = UserGetDCEx(pwnd, hrgnTemp, DCX_WINDOW|DCX_INTERSECTRGN|DCX_USESTYLE|DCX_KEEPCLIPRGN);
1060
1061 Rect = pwnd->rcWindow;
1062 RECTL_vOffsetRect(&Rect, -pwnd->rcWindow.left, -pwnd->rcWindow.top);
1063
1064 // Clear out client area!
1065 FillRect(hDC, &Rect, IntGetSysColorBrush(COLOR_WINDOW));
1066
1067 NC_DoNCPaint(pwnd, hDC, Flags); // Redraw without MENUs.
1068
1069 UserReleaseDC(pwnd, hDC, FALSE);
1070
1071 prgn = REGION_LockRgn(hrgnTemp);
1072 IntInvalidateWindows(pwnd, prgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN);
1073 REGION_UnlockRgn(prgn);
1074
1075 // Set updates for this window.
1076 pwnd->state |= WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_UPDATEDIRTY;
1077
1078 // DCX_KEEPCLIPRGN is set. Check it anyway.
1079 if (hrgnTemp > HRGN_WINDOW && GreIsHandleValid(hrgnTemp)) GreDeleteObject(hrgnTemp);
1080 }
1081 }
1082
1083 VOID FASTCALL
UpdateTheadChildren(PWND pWnd,HRGN hRgn)1084 UpdateTheadChildren(PWND pWnd, HRGN hRgn)
1085 {
1086 PaintSuspendedWindow( pWnd, hRgn );
1087
1088 if (!(pWnd->style & WS_CLIPCHILDREN))
1089 return;
1090
1091 pWnd = pWnd->spwndChild; // invalidate children if any.
1092 while (pWnd)
1093 {
1094 UpdateTheadChildren( pWnd, hRgn );
1095 pWnd = pWnd->spwndNext;
1096 }
1097 }
1098
1099 VOID FASTCALL
UpdateThreadWindows(PWND pWnd,PTHREADINFO pti,HRGN hRgn)1100 UpdateThreadWindows(PWND pWnd, PTHREADINFO pti, HRGN hRgn)
1101 {
1102 PWND pwndTemp;
1103
1104 for ( pwndTemp = pWnd;
1105 pwndTemp;
1106 pwndTemp = pwndTemp->spwndNext )
1107 {
1108 if (pwndTemp->head.pti == pti)
1109 {
1110 UserUpdateWindows(pwndTemp, RDW_ALLCHILDREN);
1111 }
1112 else
1113 {
1114 if (IsThreadSuspended(pwndTemp->head.pti) || MsqIsHung(pwndTemp->head.pti, MSQ_HUNG))
1115 {
1116 UpdateTheadChildren(pwndTemp, hRgn);
1117 }
1118 else
1119 UserUpdateWindows(pwndTemp, RDW_ALLCHILDREN);
1120 }
1121 }
1122 }
1123
1124 BOOL FASTCALL
IntIsWindowDirty(PWND Wnd)1125 IntIsWindowDirty(PWND Wnd)
1126 {
1127 return ( Wnd->style & WS_VISIBLE &&
1128 ( Wnd->hrgnUpdate != NULL ||
1129 Wnd->state & WNDS_INTERNALPAINT ) );
1130 }
1131
1132 /*
1133 Conditions to paint any window:
1134
1135 1. Update region is not null.
1136 2. Internal paint flag is set.
1137 3. Paint count is not zero.
1138
1139 */
1140 PWND FASTCALL
IntFindWindowToRepaint(PWND Window,PTHREADINFO Thread)1141 IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread)
1142 {
1143 PWND hChild;
1144 PWND TempWindow;
1145
1146 for (; Window != NULL; Window = Window->spwndNext)
1147 {
1148 if (IntWndBelongsToThread(Window, Thread))
1149 {
1150 if (IntIsWindowDirty(Window))
1151 {
1152 /* Make sure all non-transparent siblings are already drawn. */
1153 if (Window->ExStyle & WS_EX_TRANSPARENT)
1154 {
1155 for (TempWindow = Window->spwndNext; TempWindow != NULL;
1156 TempWindow = TempWindow->spwndNext)
1157 {
1158 if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) &&
1159 IntWndBelongsToThread(TempWindow, Thread) &&
1160 IntIsWindowDirty(TempWindow))
1161 {
1162 return TempWindow;
1163 }
1164 }
1165 }
1166 return Window;
1167 }
1168 }
1169 /* find a child of the specified window that needs repainting */
1170 if (Window->spwndChild)
1171 {
1172 hChild = IntFindWindowToRepaint(Window->spwndChild, Thread);
1173 if (hChild != NULL)
1174 return hChild;
1175 }
1176 }
1177 return Window;
1178 }
1179
1180 //
1181 // Internal painting of windows.
1182 //
1183 VOID FASTCALL
IntPaintWindow(PWND Window)1184 IntPaintWindow( PWND Window )
1185 {
1186 // Handle normal painting.
1187 co_IntPaintWindows( Window, RDW_NOCHILDREN, FALSE );
1188 }
1189
1190 BOOL FASTCALL
IntGetPaintMessage(PWND Window,UINT MsgFilterMin,UINT MsgFilterMax,PTHREADINFO Thread,MSG * Message,BOOL Remove)1191 IntGetPaintMessage(
1192 PWND Window,
1193 UINT MsgFilterMin,
1194 UINT MsgFilterMax,
1195 PTHREADINFO Thread,
1196 MSG *Message,
1197 BOOL Remove)
1198 {
1199 PWND PaintWnd, StartWnd;
1200
1201 if ((MsgFilterMin != 0 || MsgFilterMax != 0) &&
1202 (MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT))
1203 return FALSE;
1204
1205 if (Thread->TIF_flags & TIF_SYSTEMTHREAD )
1206 {
1207 ERR("WM_PAINT is in a System Thread!\n");
1208 }
1209
1210 StartWnd = UserGetDesktopWindow();
1211 PaintWnd = IntFindWindowToRepaint(StartWnd, Thread);
1212
1213 Message->hwnd = PaintWnd ? UserHMGetHandle(PaintWnd) : NULL;
1214
1215 if (Message->hwnd == NULL && Thread->cPaintsReady)
1216 {
1217 // Find note in window.c:"PAINTING BUG".
1218 ERR("WARNING SOMETHING HAS GONE WRONG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread->cPaintsReady);
1219 /* Hack to stop spamming the debug log ! */
1220 Thread->cPaintsReady = 0;
1221 return FALSE;
1222 }
1223
1224 if (Message->hwnd == NULL)
1225 return FALSE;
1226
1227 if (!(Window == NULL ||
1228 PaintWnd == Window ||
1229 IntIsChildWindow(Window, PaintWnd))) /* check that it is a child of the specified parent */
1230 return FALSE;
1231
1232 if (PaintWnd->state & WNDS_INTERNALPAINT)
1233 {
1234 PaintWnd->state &= ~WNDS_INTERNALPAINT;
1235 if (!PaintWnd->hrgnUpdate)
1236 MsqDecPaintCountQueue(Thread);
1237 }
1238 PaintWnd->state2 &= ~WNDS2_STARTPAINT;
1239 PaintWnd->state &= ~WNDS_UPDATEDIRTY;
1240
1241 Window = PaintWnd;
1242 while (Window && !UserIsDesktopWindow(Window))
1243 {
1244 // Role back and check for clip children, do not set if any.
1245 if (Window->spwndParent && !(Window->spwndParent->style & WS_CLIPCHILDREN))
1246 {
1247 PaintWnd->state2 |= WNDS2_WMPAINTSENT;
1248 }
1249 Window = Window->spwndParent;
1250 }
1251
1252 Message->wParam = Message->lParam = 0;
1253 Message->message = WM_PAINT;
1254 return TRUE;
1255 }
1256
1257 BOOL
1258 FASTCALL
IntPrintWindow(PWND pwnd,HDC hdcBlt,UINT nFlags)1259 IntPrintWindow(
1260 PWND pwnd,
1261 HDC hdcBlt,
1262 UINT nFlags)
1263 {
1264 HDC hdcSrc;
1265 INT cx, cy, xSrc, ySrc;
1266
1267 if ( nFlags & PW_CLIENTONLY)
1268 {
1269 cx = pwnd->rcClient.right - pwnd->rcClient.left;
1270 cy = pwnd->rcClient.bottom - pwnd->rcClient.top;
1271 xSrc = pwnd->rcClient.left - pwnd->rcWindow.left;
1272 ySrc = pwnd->rcClient.top - pwnd->rcWindow.top;
1273 }
1274 else
1275 {
1276 cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
1277 cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
1278 xSrc = 0;
1279 ySrc = 0;
1280 }
1281
1282 // TODO: Setup Redirection for Print.
1283 return FALSE;
1284
1285 /* Update the window just incase. */
1286 co_IntUpdateWindows( pwnd, RDW_ALLCHILDREN, FALSE);
1287
1288 hdcSrc = UserGetDCEx( pwnd, NULL, DCX_CACHE|DCX_WINDOW);
1289 /* Print window to printer context. */
1290 NtGdiBitBlt( hdcBlt,
1291 0,
1292 0,
1293 cx,
1294 cy,
1295 hdcSrc,
1296 xSrc,
1297 ySrc,
1298 SRCCOPY,
1299 0,
1300 0);
1301
1302 UserReleaseDC( pwnd, hdcSrc, FALSE);
1303
1304 // TODO: Release Redirection from Print.
1305
1306 return TRUE;
1307 }
1308
1309 BOOL
1310 FASTCALL
IntFlashWindowEx(PWND pWnd,PFLASHWINFO pfwi)1311 IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi)
1312 {
1313 DWORD_PTR FlashState;
1314 UINT uCount = pfwi->uCount;
1315 BOOL Activate = FALSE, Ret = FALSE;
1316
1317 ASSERT(pfwi);
1318
1319 FlashState = (DWORD_PTR)UserGetProp(pWnd, AtomFlashWndState, TRUE);
1320
1321 if (FlashState == FLASHW_FINISHED)
1322 {
1323 // Cycle has finished, kill timer and set this to Stop.
1324 FlashState |= FLASHW_KILLSYSTIMER;
1325 pfwi->dwFlags = FLASHW_STOP;
1326 }
1327 else
1328 {
1329 if (FlashState)
1330 {
1331 if (pfwi->dwFlags == FLASHW_SYSTIMER)
1332 {
1333 // Called from system timer, restore flags, counts and state.
1334 pfwi->dwFlags = LOWORD(FlashState);
1335 uCount = HIWORD(FlashState);
1336 FlashState = MAKELONG(LOWORD(FlashState),0);
1337 }
1338 else
1339 {
1340 // Clean out the trash! Fix SeaMonkey crash after restart.
1341 FlashState = 0;
1342 }
1343 }
1344
1345 if (FlashState == 0)
1346 { // First time in cycle, setup flash state.
1347 if ( pWnd->state & WNDS_ACTIVEFRAME ||
1348 (pfwi->dwFlags & FLASHW_CAPTION && pWnd->style & (WS_BORDER|WS_DLGFRAME)))
1349 {
1350 FlashState = FLASHW_STARTED|FLASHW_ACTIVE;
1351 }
1352 }
1353
1354 // Set previous window state.
1355 Ret = !!(FlashState & FLASHW_ACTIVE);
1356
1357 if ( (pfwi->dwFlags & FLASHW_TIMERNOFG) == FLASHW_TIMERNOFG &&
1358 gpqForeground == pWnd->head.pti->MessageQueue )
1359 {
1360 // Flashing until foreground, set this to Stop.
1361 pfwi->dwFlags = FLASHW_STOP;
1362 }
1363 }
1364
1365 // Toggle activate flag.
1366 if ( pfwi->dwFlags == FLASHW_STOP )
1367 {
1368 if (gpqForeground && gpqForeground->spwndActive == pWnd)
1369 Activate = TRUE;
1370 else
1371 Activate = FALSE;
1372 }
1373 else
1374 {
1375 Activate = (FlashState & FLASHW_ACTIVE) == 0;
1376 }
1377
1378 if ( pfwi->dwFlags == FLASHW_STOP || pfwi->dwFlags & FLASHW_CAPTION )
1379 {
1380 co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCACTIVATE, Activate, 0);
1381 }
1382
1383 // FIXME: Check for a Stop Sign here.
1384 if ( pfwi->dwFlags & FLASHW_TRAY )
1385 {
1386 // Need some shell work here too.
1387 TRACE("FIXME: Flash window no Tray support!\n");
1388 }
1389
1390 if ( pfwi->dwFlags == FLASHW_STOP )
1391 {
1392 if (FlashState & FLASHW_KILLSYSTIMER)
1393 {
1394 IntKillTimer(pWnd, ID_EVENT_SYSTIMER_FLASHWIN, TRUE);
1395 }
1396
1397 UserRemoveProp(pWnd, AtomFlashWndState, TRUE);
1398 }
1399 else
1400 { // Have a count and started, set timer.
1401 if ( uCount )
1402 {
1403 FlashState |= FLASHW_COUNT;
1404
1405 if (!(Activate ^ !!(FlashState & FLASHW_STARTED)))
1406 uCount--;
1407
1408 if (!(FlashState & FLASHW_KILLSYSTIMER))
1409 pfwi->dwFlags |= FLASHW_TIMER;
1410 }
1411
1412 if (pfwi->dwFlags & FLASHW_TIMER)
1413 {
1414 FlashState |= FLASHW_KILLSYSTIMER;
1415
1416 IntSetTimer( pWnd,
1417 ID_EVENT_SYSTIMER_FLASHWIN,
1418 pfwi->dwTimeout ? pfwi->dwTimeout : gpsi->dtCaretBlink,
1419 SystemTimerProc,
1420 TMRF_SYSTEM );
1421 }
1422
1423 if (FlashState & FLASHW_COUNT && uCount == 0)
1424 {
1425 // Keep spinning? Nothing else to do.
1426 FlashState = FLASHW_FINISHED;
1427 }
1428 else
1429 {
1430 // Save state and flags so this can be restored next time through.
1431 FlashState ^= (FlashState ^ -!!(Activate)) & FLASHW_ACTIVE;
1432 FlashState ^= (FlashState ^ pfwi->dwFlags) & (FLASHW_MASK & ~FLASHW_TIMER);
1433 }
1434 FlashState = MAKELONG(LOWORD(FlashState),uCount);
1435 UserSetProp(pWnd, AtomFlashWndState, (HANDLE)FlashState, TRUE);
1436 }
1437 return Ret;
1438 }
1439
1440 // Win: xxxBeginPaint
1441 HDC FASTCALL
IntBeginPaint(PWND Window,PPAINTSTRUCT Ps)1442 IntBeginPaint(PWND Window, PPAINTSTRUCT Ps)
1443 {
1444 RECT Rect;
1445 INT type;
1446 BOOL Erase = FALSE;
1447
1448 co_UserHideCaret(Window);
1449
1450 Window->state2 |= WNDS2_STARTPAINT;
1451 Window->state &= ~WNDS_PAINTNOTPROCESSED;
1452
1453 if (Window->state & WNDS_SENDNCPAINT)
1454 {
1455 HRGN hRgn;
1456 // Application can keep update dirty.
1457 do
1458 {
1459 Window->state &= ~WNDS_UPDATEDIRTY;
1460 hRgn = IntGetNCUpdateRgn(Window, FALSE);
1461 IntSendNCPaint(Window, hRgn);
1462 if (hRgn > HRGN_WINDOW && GreIsHandleValid(hRgn))
1463 {
1464 /* NOTE: The region can already be deleted! */
1465 GreDeleteObject(hRgn);
1466 }
1467 }
1468 while(Window->state & WNDS_UPDATEDIRTY);
1469 }
1470 else
1471 {
1472 Window->state &= ~WNDS_UPDATEDIRTY;
1473 }
1474
1475 RtlZeroMemory(Ps, sizeof(PAINTSTRUCT));
1476
1477 if (Window->state2 & WNDS2_ENDPAINTINVALIDATE)
1478 {
1479 ERR("BP: Another thread invalidated this window\n");
1480 }
1481
1482 Ps->hdc = UserGetDCEx( Window,
1483 Window->hrgnUpdate,
1484 DCX_INTERSECTRGN | DCX_USESTYLE);
1485 if (!Ps->hdc)
1486 {
1487 return NULL;
1488 }
1489
1490 // If set, always clear flags out due to the conditions later on for sending the message.
1491 if (Window->state & WNDS_SENDERASEBACKGROUND)
1492 {
1493 Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
1494 Erase = TRUE;
1495 }
1496
1497 if (Window->hrgnUpdate != NULL)
1498 {
1499 MsqDecPaintCountQueue(Window->head.pti);
1500 IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
1501 /* The region is part of the dc now and belongs to the process! */
1502 Window->hrgnUpdate = NULL;
1503 }
1504 else
1505 {
1506 if (Window->state & WNDS_INTERNALPAINT)
1507 MsqDecPaintCountQueue(Window->head.pti);
1508 }
1509
1510 type = GdiGetClipBox(Ps->hdc, &Ps->rcPaint);
1511
1512 IntGetClientRect(Window, &Rect);
1513
1514 Window->state &= ~WNDS_INTERNALPAINT;
1515
1516 if ( Erase && // Set to erase,
1517 type != NULLREGION && // don't erase if the clip box is empty,
1518 (!(Window->pcls->style & CS_PARENTDC) || // not parent dc or
1519 RECTL_bIntersectRect( &Rect, &Rect, &Ps->rcPaint) ) ) // intersecting.
1520 {
1521 Ps->fErase = !co_IntSendMessage(UserHMGetHandle(Window), WM_ERASEBKGND, (WPARAM)Ps->hdc, 0);
1522 if ( Ps->fErase )
1523 {
1524 Window->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
1525 }
1526 }
1527 else
1528 {
1529 Ps->fErase = FALSE;
1530 }
1531
1532 IntSendChildNCPaint(Window);
1533
1534 return Ps->hdc;
1535 }
1536
1537 // Win: xxxEndPaint
1538 BOOL FASTCALL
IntEndPaint(PWND Wnd,PPAINTSTRUCT Ps)1539 IntEndPaint(PWND Wnd, PPAINTSTRUCT Ps)
1540 {
1541 HDC hdc = NULL;
1542
1543 hdc = Ps->hdc;
1544
1545 UserReleaseDC(Wnd, hdc, TRUE);
1546
1547 if (Wnd->state2 & WNDS2_ENDPAINTINVALIDATE)
1548 {
1549 ERR("EP: Another thread invalidated this window\n");
1550 Wnd->state2 &= ~WNDS2_ENDPAINTINVALIDATE;
1551 }
1552
1553 Wnd->state2 &= ~(WNDS2_WMPAINTSENT|WNDS2_STARTPAINT);
1554
1555 co_UserShowCaret(Wnd);
1556
1557 return TRUE;
1558 }
1559
1560 // Win: xxxFillWindow
1561 BOOL FASTCALL
IntFillWindow(PWND pWndParent,PWND pWnd,HDC hDC,HBRUSH hBrush)1562 IntFillWindow(PWND pWndParent,
1563 PWND pWnd,
1564 HDC hDC,
1565 HBRUSH hBrush)
1566 {
1567 RECT Rect, Rect1;
1568 INT type;
1569
1570 if (!pWndParent)
1571 pWndParent = pWnd;
1572
1573 type = GdiGetClipBox(hDC, &Rect);
1574
1575 IntGetClientRect(pWnd, &Rect1);
1576
1577 if ( type != NULLREGION && // Clip box is not empty,
1578 (!(pWnd->pcls->style & CS_PARENTDC) || // not parent dc or
1579 RECTL_bIntersectRect( &Rect, &Rect, &Rect1) ) ) // intersecting.
1580 {
1581 POINT ppt;
1582 INT x = 0, y = 0;
1583
1584 if (!UserIsDesktopWindow(pWndParent))
1585 {
1586 x = pWndParent->rcClient.left - pWnd->rcClient.left;
1587 y = pWndParent->rcClient.top - pWnd->rcClient.top;
1588 }
1589
1590 GreSetBrushOrg(hDC, x, y, &ppt);
1591
1592 if ( hBrush < (HBRUSH)CTLCOLOR_MAX )
1593 hBrush = GetControlColor( pWndParent, pWnd, hDC, HandleToUlong(hBrush) + WM_CTLCOLORMSGBOX);
1594
1595 FillRect(hDC, &Rect, hBrush);
1596
1597 GreSetBrushOrg(hDC, ppt.x, ppt.y, NULL);
1598
1599 return TRUE;
1600 }
1601 else
1602 return FALSE;
1603 }
1604
1605 /* PUBLIC FUNCTIONS ***********************************************************/
1606
1607 /*
1608 * NtUserBeginPaint
1609 *
1610 * Status
1611 * @implemented
1612 */
1613
1614 HDC APIENTRY
NtUserBeginPaint(HWND hWnd,PAINTSTRUCT * UnsafePs)1615 NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
1616 {
1617 PWND Window;
1618 PAINTSTRUCT Ps;
1619 NTSTATUS Status;
1620 HDC hDC;
1621 USER_REFERENCE_ENTRY Ref;
1622 HDC Ret = NULL;
1623
1624 TRACE("Enter NtUserBeginPaint\n");
1625 UserEnterExclusive();
1626
1627 if (!(Window = UserGetWindowObject(hWnd)))
1628 {
1629 goto Cleanup; // Return NULL
1630 }
1631
1632 UserRefObjectCo(Window, &Ref);
1633
1634 hDC = IntBeginPaint(Window, &Ps);
1635
1636 Status = MmCopyToCaller(UnsafePs, &Ps, sizeof(PAINTSTRUCT));
1637 if (! NT_SUCCESS(Status))
1638 {
1639 SetLastNtError(Status);
1640 goto Cleanup; // Return NULL
1641 }
1642
1643 Ret = hDC;
1644
1645 Cleanup:
1646 if (Window) UserDerefObjectCo(Window);
1647
1648 TRACE("Leave NtUserBeginPaint, ret=%p\n", Ret);
1649 UserLeave();
1650 return Ret;
1651 }
1652
1653 /*
1654 * NtUserEndPaint
1655 *
1656 * Status
1657 * @implemented
1658 */
1659
1660 BOOL APIENTRY
NtUserEndPaint(HWND hWnd,CONST PAINTSTRUCT * pUnsafePs)1661 NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* pUnsafePs)
1662 {
1663 NTSTATUS Status = STATUS_SUCCESS;
1664 PWND Window;
1665 PAINTSTRUCT Ps;
1666 USER_REFERENCE_ENTRY Ref;
1667 BOOL Ret = FALSE;
1668
1669 TRACE("Enter NtUserEndPaint\n");
1670 UserEnterExclusive();
1671
1672 if (!(Window = UserGetWindowObject(hWnd)))
1673 {
1674 goto Cleanup; // Return FALSE
1675 }
1676
1677 UserRefObjectCo(Window, &Ref); // Here for the exception.
1678
1679 _SEH2_TRY
1680 {
1681 ProbeForRead(pUnsafePs, sizeof(*pUnsafePs), 1);
1682 RtlCopyMemory(&Ps, pUnsafePs, sizeof(PAINTSTRUCT));
1683 }
1684 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1685 {
1686 Status = _SEH2_GetExceptionCode();
1687 }
1688 _SEH2_END
1689 if (!NT_SUCCESS(Status))
1690 {
1691 goto Cleanup; // Return FALSE
1692 }
1693
1694 Ret = IntEndPaint(Window, &Ps);
1695
1696 Cleanup:
1697 if (Window) UserDerefObjectCo(Window);
1698
1699 TRACE("Leave NtUserEndPaint, ret=%i\n", Ret);
1700 UserLeave();
1701 return Ret;
1702 }
1703
1704 /*
1705 * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
1706 */
1707 /*
1708 * @implemented
1709 */
1710 BOOL APIENTRY
NtUserFillWindow(HWND hWndParent,HWND hWnd,HDC hDC,HBRUSH hBrush)1711 NtUserFillWindow(HWND hWndParent,
1712 HWND hWnd,
1713 HDC hDC,
1714 HBRUSH hBrush)
1715 {
1716 BOOL ret = FALSE;
1717 PWND pWnd, pWndParent = NULL;
1718 USER_REFERENCE_ENTRY Ref;
1719
1720 TRACE("Enter NtUserFillWindow\n");
1721 UserEnterExclusive();
1722
1723 if (!hDC)
1724 {
1725 goto Exit;
1726 }
1727
1728 if (!(pWnd = UserGetWindowObject(hWnd)))
1729 {
1730 goto Exit;
1731 }
1732
1733 if (hWndParent && !(pWndParent = UserGetWindowObject(hWndParent)))
1734 {
1735 goto Exit;
1736 }
1737
1738 UserRefObjectCo(pWnd, &Ref);
1739 ret = IntFillWindow( pWndParent, pWnd, hDC, hBrush );
1740 UserDerefObjectCo(pWnd);
1741
1742 Exit:
1743 TRACE("Leave NtUserFillWindow, ret=%i\n",ret);
1744 UserLeave();
1745 return ret;
1746 }
1747
1748 /*
1749 * @implemented
1750 */
1751 BOOL APIENTRY
NtUserFlashWindowEx(IN PFLASHWINFO pfwi)1752 NtUserFlashWindowEx(IN PFLASHWINFO pfwi)
1753 {
1754 PWND pWnd;
1755 FLASHWINFO finfo = {0};
1756 BOOL Ret = FALSE;
1757
1758 UserEnterExclusive();
1759
1760 _SEH2_TRY
1761 {
1762 ProbeForRead(pfwi, sizeof(FLASHWINFO), 1);
1763 RtlCopyMemory(&finfo, pfwi, sizeof(FLASHWINFO));
1764 }
1765 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1766 {
1767 SetLastNtError(_SEH2_GetExceptionCode());
1768 _SEH2_YIELD(goto Exit);
1769 }
1770 _SEH2_END
1771
1772 if (!( pWnd = ValidateHwndNoErr(finfo.hwnd)) ||
1773 finfo.cbSize != sizeof(FLASHWINFO) ||
1774 finfo.dwFlags & ~(FLASHW_ALL|FLASHW_TIMER|FLASHW_TIMERNOFG) )
1775 {
1776 EngSetLastError(ERROR_INVALID_PARAMETER);
1777 goto Exit;
1778 }
1779
1780 Ret = IntFlashWindowEx(pWnd, &finfo);
1781
1782 Exit:
1783 UserLeave();
1784 return Ret;
1785 }
1786
1787 /*
1788 GetUpdateRgn, this fails the same as the old one.
1789 */
1790 INT FASTCALL
co_UserGetUpdateRgn(PWND Window,HRGN hRgn,BOOL bErase)1791 co_UserGetUpdateRgn(PWND Window, HRGN hRgn, BOOL bErase)
1792 {
1793 int RegionType;
1794 BOOL Type;
1795 RECTL Rect;
1796
1797 ASSERT_REFS_CO(Window);
1798
1799 if (bErase)
1800 {
1801 USER_REFERENCE_ENTRY Ref;
1802 UserRefObjectCo(Window, &Ref);
1803 co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE);
1804 UserDerefObjectCo(Window);
1805 }
1806
1807 Window->state &= ~WNDS_UPDATEDIRTY;
1808
1809 if (Window->hrgnUpdate == NULL)
1810 {
1811 NtGdiSetRectRgn(hRgn, 0, 0, 0, 0);
1812 return NULLREGION;
1813 }
1814
1815 Rect = Window->rcClient;
1816 Type = IntIntersectWithParents(Window, &Rect);
1817
1818 if (Window->hrgnUpdate == HRGN_WINDOW)
1819 {
1820 // Trap it out.
1821 ERR("GURn: Caller is passing Window Region 1\n");
1822 if (!Type)
1823 {
1824 NtGdiSetRectRgn(hRgn, 0, 0, 0, 0);
1825 return NULLREGION;
1826 }
1827
1828 RegionType = SIMPLEREGION;
1829
1830 if (!UserIsDesktopWindow(Window))
1831 {
1832 RECTL_vOffsetRect(&Rect,
1833 -Window->rcClient.left,
1834 -Window->rcClient.top);
1835 }
1836 GreSetRectRgnIndirect(hRgn, &Rect);
1837 }
1838 else
1839 {
1840 HRGN hrgnTemp = GreCreateRectRgnIndirect(&Rect);
1841
1842 RegionType = NtGdiCombineRgn(hRgn, hrgnTemp, Window->hrgnUpdate, RGN_AND);
1843
1844 if (RegionType == ERROR || RegionType == NULLREGION)
1845 {
1846 if (hrgnTemp) GreDeleteObject(hrgnTemp);
1847 NtGdiSetRectRgn(hRgn, 0, 0, 0, 0);
1848 return RegionType;
1849 }
1850
1851 if (!UserIsDesktopWindow(Window))
1852 {
1853 NtGdiOffsetRgn(hRgn,
1854 -Window->rcClient.left,
1855 -Window->rcClient.top);
1856 }
1857 if (hrgnTemp) GreDeleteObject(hrgnTemp);
1858 }
1859 return RegionType;
1860 }
1861
1862 BOOL FASTCALL
co_UserGetUpdateRect(PWND Window,PRECT pRect,BOOL bErase)1863 co_UserGetUpdateRect(PWND Window, PRECT pRect, BOOL bErase)
1864 {
1865 INT RegionType;
1866 BOOL Ret = TRUE;
1867
1868 if (bErase)
1869 {
1870 USER_REFERENCE_ENTRY Ref;
1871 UserRefObjectCo(Window, &Ref);
1872 co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE);
1873 UserDerefObjectCo(Window);
1874 }
1875
1876 Window->state &= ~WNDS_UPDATEDIRTY;
1877
1878 if (Window->hrgnUpdate == NULL)
1879 {
1880 pRect->left = pRect->top = pRect->right = pRect->bottom = 0;
1881 Ret = FALSE;
1882 }
1883 else
1884 {
1885 /* Get the update region bounding box. */
1886 if (Window->hrgnUpdate == HRGN_WINDOW)
1887 {
1888 *pRect = Window->rcClient;
1889 ERR("GURt: Caller is retrieving Window Region 1\n");
1890 }
1891 else
1892 {
1893 RegionType = IntGdiGetRgnBox(Window->hrgnUpdate, pRect);
1894
1895 if (RegionType != ERROR && RegionType != NULLREGION)
1896 RECTL_bIntersectRect(pRect, pRect, &Window->rcClient);
1897 }
1898
1899 if (IntIntersectWithParents(Window, pRect))
1900 {
1901 if (!UserIsDesktopWindow(Window))
1902 {
1903 RECTL_vOffsetRect(pRect,
1904 -Window->rcClient.left,
1905 -Window->rcClient.top);
1906 }
1907 if (Window->pcls->style & CS_OWNDC)
1908 {
1909 HDC hdc;
1910 //DWORD layout;
1911 hdc = UserGetDCEx(Window, NULL, DCX_USESTYLE);
1912 //layout = NtGdiSetLayout(hdc, -1, 0);
1913 //IntMapWindowPoints( 0, Window, (LPPOINT)pRect, 2 );
1914 GreDPtoLP( hdc, (LPPOINT)pRect, 2 );
1915 //NtGdiSetLayout(hdc, -1, layout);
1916 UserReleaseDC(Window, hdc, FALSE);
1917 }
1918 }
1919 else
1920 {
1921 pRect->left = pRect->top = pRect->right = pRect->bottom = 0;
1922 }
1923 }
1924 return Ret;
1925 }
1926
1927 /*
1928 * NtUserGetUpdateRgn
1929 *
1930 * Status
1931 * @implemented
1932 */
1933
1934 INT APIENTRY
NtUserGetUpdateRgn(HWND hWnd,HRGN hRgn,BOOL bErase)1935 NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
1936 {
1937 PWND Window;
1938 INT ret = ERROR;
1939
1940 TRACE("Enter NtUserGetUpdateRgn\n");
1941 UserEnterExclusive();
1942
1943 Window = UserGetWindowObject(hWnd);
1944 if (Window)
1945 {
1946 ret = co_UserGetUpdateRgn(Window, hRgn, bErase);
1947 }
1948
1949 TRACE("Leave NtUserGetUpdateRgn, ret=%i\n", ret);
1950 UserLeave();
1951 return ret;
1952 }
1953
1954 /*
1955 * NtUserGetUpdateRect
1956 *
1957 * Status
1958 * @implemented
1959 */
1960
1961 BOOL APIENTRY
NtUserGetUpdateRect(HWND hWnd,LPRECT UnsafeRect,BOOL bErase)1962 NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
1963 {
1964 PWND Window;
1965 RECTL Rect;
1966 NTSTATUS Status;
1967 BOOL Ret = FALSE;
1968
1969 TRACE("Enter NtUserGetUpdateRect\n");
1970 UserEnterExclusive();
1971
1972 if (!(Window = UserGetWindowObject(hWnd)))
1973 {
1974 goto Exit; // Return FALSE
1975 }
1976
1977 Ret = co_UserGetUpdateRect(Window, &Rect, bErase);
1978
1979 if (UnsafeRect != NULL)
1980 {
1981 Status = MmCopyToCaller(UnsafeRect, &Rect, sizeof(RECTL));
1982 if (!NT_SUCCESS(Status))
1983 {
1984 EngSetLastError(ERROR_INVALID_PARAMETER);
1985 Ret = FALSE;
1986 }
1987 }
1988
1989 Exit:
1990 TRACE("Leave NtUserGetUpdateRect, ret=%i\n", Ret);
1991 UserLeave();
1992 return Ret;
1993 }
1994
1995 /*
1996 * NtUserRedrawWindow
1997 *
1998 * Status
1999 * @implemented
2000 */
2001
2002 BOOL APIENTRY
NtUserRedrawWindow(HWND hWnd,CONST RECT * lprcUpdate,HRGN hrgnUpdate,UINT flags)2003 NtUserRedrawWindow(
2004 HWND hWnd,
2005 CONST RECT *lprcUpdate,
2006 HRGN hrgnUpdate,
2007 UINT flags)
2008 {
2009 RECTL SafeUpdateRect;
2010 PWND Wnd;
2011 BOOL Ret = FALSE;
2012 USER_REFERENCE_ENTRY Ref;
2013 NTSTATUS Status = STATUS_SUCCESS;
2014 PREGION RgnUpdate = NULL;
2015
2016 TRACE("Enter NtUserRedrawWindow\n");
2017 UserEnterExclusive();
2018
2019 if (!(Wnd = UserGetWindowObject(hWnd ? hWnd : IntGetDesktopWindow())))
2020 {
2021 goto Exit; // Return FALSE
2022 }
2023
2024 if (lprcUpdate)
2025 {
2026 _SEH2_TRY
2027 {
2028 ProbeForRead(lprcUpdate, sizeof(RECTL), 1);
2029 RtlCopyMemory(&SafeUpdateRect, lprcUpdate, sizeof(RECTL));
2030 }
2031 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2032 {
2033 Status = _SEH2_GetExceptionCode();
2034 }
2035 _SEH2_END
2036 if (!NT_SUCCESS(Status))
2037 {
2038 EngSetLastError(RtlNtStatusToDosError(Status));
2039 goto Exit; // Return FALSE
2040 }
2041 }
2042
2043 if ( flags & ~(RDW_ERASE|RDW_FRAME|RDW_INTERNALPAINT|RDW_INVALIDATE|
2044 RDW_NOERASE|RDW_NOFRAME|RDW_NOINTERNALPAINT|RDW_VALIDATE|
2045 RDW_ERASENOW|RDW_UPDATENOW|RDW_ALLCHILDREN|RDW_NOCHILDREN) )
2046 {
2047 /* RedrawWindow fails only in case that flags are invalid */
2048 EngSetLastError(ERROR_INVALID_FLAGS);
2049 goto Exit; // Return FALSE
2050 }
2051
2052 /* We can't hold lock on GDI objects while doing roundtrips to user mode,
2053 * so it will be copied.
2054 */
2055 if (hrgnUpdate > HRGN_WINDOW)
2056 {
2057 RgnUpdate = REGION_LockRgn(hrgnUpdate);
2058 if (!RgnUpdate)
2059 {
2060 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2061 goto Exit; // Return FALSE
2062 }
2063 REGION_UnlockRgn(RgnUpdate);
2064 }
2065 else if (hrgnUpdate == HRGN_WINDOW) // Trap it out.
2066 {
2067 ERR("NTRW: Caller is passing Window Region 1\n");
2068 }
2069
2070 UserRefObjectCo(Wnd, &Ref);
2071
2072 Ret = co_UserRedrawWindow( Wnd,
2073 lprcUpdate ? &SafeUpdateRect : NULL,
2074 RgnUpdate,
2075 flags);
2076
2077 UserDerefObjectCo(Wnd);
2078
2079 Exit:
2080 TRACE("Leave NtUserRedrawWindow, ret=%i\n", Ret);
2081 UserLeave();
2082 return Ret;
2083 }
2084
2085 BOOL
UserDrawCaptionText(PWND pWnd,HDC hDc,const PUNICODE_STRING Text,const RECTL * lpRc,UINT uFlags,HFONT hFont)2086 UserDrawCaptionText(
2087 PWND pWnd,
2088 HDC hDc,
2089 const PUNICODE_STRING Text,
2090 const RECTL *lpRc,
2091 UINT uFlags,
2092 HFONT hFont)
2093 {
2094 HFONT hOldFont = NULL;
2095 COLORREF OldTextColor;
2096 NONCLIENTMETRICSW nclm;
2097 NTSTATUS Status;
2098 BOOLEAN bDeleteFont = FALSE;
2099 SIZE Size;
2100 BOOL Ret = TRUE;
2101 ULONG fit = 0, Length;
2102 RECTL r = *lpRc;
2103
2104 TRACE("UserDrawCaptionText: %wZ\n", Text);
2105
2106 nclm.cbSize = sizeof(nclm);
2107 if (!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS, nclm.cbSize, &nclm, 0))
2108 {
2109 ERR("UserSystemParametersInfo() failed!\n");
2110 return FALSE;
2111 }
2112
2113 if (!hFont)
2114 {
2115 if(uFlags & DC_SMALLCAP)
2116 Status = TextIntCreateFontIndirect(&nclm.lfSmCaptionFont, &hFont);
2117 else
2118 Status = TextIntCreateFontIndirect(&nclm.lfCaptionFont, &hFont);
2119
2120 if(!NT_SUCCESS(Status))
2121 {
2122 ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status);
2123 return FALSE;
2124 }
2125
2126 bDeleteFont = TRUE;
2127 }
2128
2129 IntGdiSetBkMode(hDc, TRANSPARENT);
2130
2131 hOldFont = NtGdiSelectFont(hDc, hFont);
2132
2133 if(uFlags & DC_INBUTTON)
2134 OldTextColor = IntGdiSetTextColor(hDc, IntGetSysColor(COLOR_BTNTEXT));
2135 else
2136 OldTextColor = IntGdiSetTextColor(hDc,
2137 IntGetSysColor(uFlags & DC_ACTIVE ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
2138
2139 // Adjust for system menu.
2140 if (pWnd && pWnd->style & WS_SYSMENU)
2141 {
2142 r.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
2143 if ((pWnd->style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW))
2144 {
2145 r.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
2146 r.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
2147 }
2148 }
2149
2150 GreGetTextExtentExW(hDc, Text->Buffer, Text->Length/sizeof(WCHAR), r.right - r.left, &fit, 0, &Size, 0);
2151
2152 Length = (Text->Length/sizeof(WCHAR) == fit ? fit : fit+1);
2153
2154 if (Text->Length/sizeof(WCHAR) > Length)
2155 {
2156 Ret = FALSE;
2157 }
2158
2159 if (Ret)
2160 { // Faster while in setup.
2161 UserExtTextOutW( hDc,
2162 lpRc->left,
2163 lpRc->top + (lpRc->bottom - lpRc->top - Size.cy) / 2, // DT_SINGLELINE && DT_VCENTER
2164 ETO_CLIPPED,
2165 (RECTL *)lpRc,
2166 Text->Buffer,
2167 Length);
2168 }
2169 else
2170 {
2171 DrawTextW( hDc,
2172 Text->Buffer,
2173 Text->Length/sizeof(WCHAR),
2174 (RECTL *)&r,
2175 DT_END_ELLIPSIS|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_LEFT);
2176 }
2177
2178 IntGdiSetTextColor(hDc, OldTextColor);
2179
2180 if (hOldFont)
2181 NtGdiSelectFont(hDc, hOldFont);
2182
2183 if (bDeleteFont)
2184 GreDeleteObject(hFont);
2185
2186 return Ret;
2187 }
2188
2189 //
2190 // This draws Buttons, Icons and Text...
2191 //
UserDrawCaption(PWND pWnd,HDC hDc,RECTL * lpRc,HFONT hFont,HICON hIcon,const PUNICODE_STRING Str,UINT uFlags)2192 BOOL UserDrawCaption(
2193 PWND pWnd,
2194 HDC hDc,
2195 RECTL *lpRc,
2196 HFONT hFont,
2197 HICON hIcon,
2198 const PUNICODE_STRING Str,
2199 UINT uFlags)
2200 {
2201 BOOL Ret = FALSE;
2202 HBRUSH hBgBrush, hOldBrush = NULL;
2203 RECTL Rect = *lpRc;
2204 BOOL HasIcon;
2205
2206 RECTL_vMakeWellOrdered(lpRc);
2207
2208 /* Determine whether the icon needs to be displayed */
2209 if (!hIcon && pWnd != NULL)
2210 {
2211 HasIcon = (uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP) &&
2212 (pWnd->style & WS_SYSMENU) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW);
2213 }
2214 else
2215 HasIcon = (hIcon != NULL);
2216
2217 // Draw the caption background
2218 if((uFlags & DC_GRADIENT) && !(uFlags & DC_INBUTTON))
2219 {
2220 static GRADIENT_RECT gcap = {0, 1};
2221 TRIVERTEX Vertices[2];
2222 COLORREF Colors[2];
2223
2224 Colors[0] = IntGetSysColor((uFlags & DC_ACTIVE) ?
2225 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
2226
2227 Colors[1] = IntGetSysColor((uFlags & DC_ACTIVE) ?
2228 COLOR_GRADIENTACTIVECAPTION : COLOR_GRADIENTINACTIVECAPTION);
2229
2230 Vertices[0].x = Rect.left;
2231 Vertices[0].y = Rect.top;
2232 Vertices[0].Red = (WORD)Colors[0]<<8;
2233 Vertices[0].Green = (WORD)Colors[0] & 0xFF00;
2234 Vertices[0].Blue = (WORD)(Colors[0]>>8) & 0xFF00;
2235 Vertices[0].Alpha = 0;
2236
2237 Vertices[1].x = Rect.right;
2238 Vertices[1].y = Rect.bottom;
2239 Vertices[1].Red = (WORD)Colors[1]<<8;
2240 Vertices[1].Green = (WORD)Colors[1] & 0xFF00;
2241 Vertices[1].Blue = (WORD)(Colors[1]>>8) & 0xFF00;
2242 Vertices[1].Alpha = 0;
2243
2244 if(!GreGradientFill(hDc, Vertices, 2, &gcap, 1, GRADIENT_FILL_RECT_H))
2245 {
2246 ERR("GreGradientFill() failed!\n");
2247 goto cleanup;
2248 }
2249 }
2250 else
2251 {
2252 if(uFlags & DC_INBUTTON)
2253 hBgBrush = IntGetSysColorBrush(COLOR_3DFACE);
2254 else if(uFlags & DC_ACTIVE)
2255 hBgBrush = IntGetSysColorBrush(COLOR_ACTIVECAPTION);
2256 else
2257 hBgBrush = IntGetSysColorBrush(COLOR_INACTIVECAPTION);
2258
2259 hOldBrush = NtGdiSelectBrush(hDc, hBgBrush);
2260
2261 if(!hOldBrush)
2262 {
2263 ERR("NtGdiSelectBrush() failed!\n");
2264 goto cleanup;
2265 }
2266
2267 if(!NtGdiPatBlt(hDc, Rect.left, Rect.top,
2268 Rect.right - Rect.left,
2269 Rect.bottom - Rect.top,
2270 PATCOPY))
2271 {
2272 ERR("NtGdiPatBlt() failed!\n");
2273 goto cleanup;
2274 }
2275 }
2276
2277 /* Draw icon */
2278 if (HasIcon)
2279 {
2280 PCURICON_OBJECT pIcon = NULL;
2281
2282 if (hIcon)
2283 {
2284 pIcon = UserGetCurIconObject(hIcon);
2285 }
2286 else if (pWnd)
2287 {
2288 pIcon = NC_IconForWindow(pWnd);
2289 // FIXME: NC_IconForWindow should reference it for us */
2290 if (pIcon)
2291 UserReferenceObject(pIcon);
2292 }
2293
2294 if (pIcon)
2295 {
2296 LONG cx = UserGetSystemMetrics(SM_CXSMICON);
2297 LONG cy = UserGetSystemMetrics(SM_CYSMICON);
2298 LONG x = Rect.left - cx/2 + 1 + (Rect.bottom - Rect.top)/2; // this is really what Window does
2299 LONG y = (Rect.top + Rect.bottom - cy)/2; // center
2300 UserDrawIconEx(hDc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL);
2301 UserDereferenceObject(pIcon);
2302 }
2303 else
2304 {
2305 HasIcon = FALSE;
2306 }
2307 }
2308
2309 if (HasIcon)
2310 Rect.left += Rect.bottom - Rect.top;
2311
2312 if((uFlags & DC_TEXT))
2313 {
2314 BOOL Set = FALSE;
2315 Rect.left += 2;
2316
2317 if (Str)
2318 Set = UserDrawCaptionText(pWnd, hDc, Str, &Rect, uFlags, hFont);
2319 else if (pWnd != NULL) // FIXME: Windows does not do that
2320 {
2321 UNICODE_STRING ustr;
2322 ustr.Buffer = pWnd->strName.Buffer; // FIXME: LARGE_STRING truncated!
2323 ustr.Length = (USHORT)min(pWnd->strName.Length, MAXUSHORT);
2324 ustr.MaximumLength = (USHORT)min(pWnd->strName.MaximumLength, MAXUSHORT);
2325 Set = UserDrawCaptionText(pWnd, hDc, &ustr, &Rect, uFlags, hFont);
2326 }
2327 if (pWnd)
2328 {
2329 if (Set)
2330 pWnd->state2 &= ~WNDS2_CAPTIONTEXTTRUNCATED;
2331 else
2332 pWnd->state2 |= WNDS2_CAPTIONTEXTTRUNCATED;
2333 }
2334 }
2335
2336 Ret = TRUE;
2337
2338 cleanup:
2339 if (hOldBrush) NtGdiSelectBrush(hDc, hOldBrush);
2340
2341 return Ret;
2342 }
2343
2344 INT
2345 FASTCALL
UserRealizePalette(HDC hdc)2346 UserRealizePalette(HDC hdc)
2347 {
2348 HWND hWnd, hWndDesktop;
2349 DWORD Ret;
2350
2351 Ret = IntGdiRealizePalette(hdc);
2352 if (Ret) // There was a change.
2353 {
2354 hWnd = IntWindowFromDC(hdc);
2355 if (hWnd) // Send broadcast if dc is associated with a window.
2356 { // FYI: Thread locked in CallOneParam.
2357 hWndDesktop = IntGetDesktopWindow();
2358 if ( hWndDesktop != hWnd )
2359 {
2360 PWND pWnd = UserGetWindowObject(hWndDesktop);
2361 ERR("RealizePalette Desktop.\n");
2362 hdc = UserGetWindowDC(pWnd);
2363 IntPaintDesktop(hdc);
2364 UserReleaseDC(pWnd,hdc,FALSE);
2365 }
2366 UserSendNotifyMessage((HWND)HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)hWnd, 0);
2367 }
2368 }
2369 return Ret;
2370 }
2371
2372 BOOL
2373 APIENTRY
NtUserDrawCaptionTemp(HWND hWnd,HDC hDC,LPCRECT lpRc,HFONT hFont,HICON hIcon,const PUNICODE_STRING str,UINT uFlags)2374 NtUserDrawCaptionTemp(
2375 HWND hWnd,
2376 HDC hDC,
2377 LPCRECT lpRc,
2378 HFONT hFont,
2379 HICON hIcon,
2380 const PUNICODE_STRING str,
2381 UINT uFlags)
2382 {
2383 PWND pWnd = NULL;
2384 UNICODE_STRING SafeStr = {0};
2385 NTSTATUS Status = STATUS_SUCCESS;
2386 RECTL SafeRect;
2387 BOOL Ret;
2388
2389 UserEnterExclusive();
2390
2391 if (hWnd != NULL)
2392 {
2393 if(!(pWnd = UserGetWindowObject(hWnd)))
2394 {
2395 UserLeave();
2396 return FALSE;
2397 }
2398 }
2399
2400 _SEH2_TRY
2401 {
2402 ProbeForRead(lpRc, sizeof(RECTL), sizeof(ULONG));
2403 RtlCopyMemory(&SafeRect, lpRc, sizeof(RECTL));
2404 if (str != NULL)
2405 {
2406 SafeStr = ProbeForReadUnicodeString(str);
2407 if (SafeStr.Length != 0)
2408 {
2409 ProbeForRead( SafeStr.Buffer,
2410 SafeStr.Length,
2411 sizeof(WCHAR));
2412 }
2413 }
2414 }
2415 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2416 {
2417 Status = _SEH2_GetExceptionCode();
2418 }
2419 _SEH2_END;
2420
2421 if (Status != STATUS_SUCCESS)
2422 {
2423 SetLastNtError(Status);
2424 UserLeave();
2425 return FALSE;
2426 }
2427
2428 if (str != NULL)
2429 Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, &SafeStr, uFlags);
2430 else
2431 {
2432 if ( RECTL_bIsEmptyRect(&SafeRect) && hFont == 0 && hIcon == 0 )
2433 {
2434 Ret = TRUE;
2435 if (uFlags & DC_DRAWCAPTIONMD)
2436 {
2437 ERR("NC Caption Mode\n");
2438 UserDrawCaptionBar(pWnd, hDC, uFlags);
2439 goto Exit;
2440 }
2441 else if (uFlags & DC_DRAWFRAMEMD)
2442 {
2443 ERR("NC Paint Mode\n");
2444 NC_DoNCPaint(pWnd, hDC, uFlags); // Update Menus too!
2445 goto Exit;
2446 }
2447 }
2448 Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, NULL, uFlags);
2449 }
2450 Exit:
2451 UserLeave();
2452 return Ret;
2453 }
2454
2455 BOOL
2456 APIENTRY
NtUserDrawCaption(HWND hWnd,HDC hDC,LPCRECT lpRc,UINT uFlags)2457 NtUserDrawCaption(HWND hWnd,
2458 HDC hDC,
2459 LPCRECT lpRc,
2460 UINT uFlags)
2461 {
2462 return NtUserDrawCaptionTemp(hWnd, hDC, lpRc, 0, 0, NULL, uFlags);
2463 }
2464
2465 INT FASTCALL
co_UserExcludeUpdateRgn(HDC hDC,PWND Window)2466 co_UserExcludeUpdateRgn(HDC hDC, PWND Window)
2467 {
2468 POINT pt;
2469 RECT rc;
2470
2471 if (Window->hrgnUpdate)
2472 {
2473 if (Window->hrgnUpdate == HRGN_WINDOW)
2474 {
2475 return NtGdiIntersectClipRect(hDC, 0, 0, 0, 0);
2476 }
2477 else
2478 {
2479 INT ret = ERROR;
2480 HRGN hrgn = NtGdiCreateRectRgn(0,0,0,0);
2481
2482 if ( hrgn && GreGetDCPoint( hDC, GdiGetDCOrg, &pt) )
2483 {
2484 if ( NtGdiGetRandomRgn( hDC, hrgn, CLIPRGN) == NULLREGION )
2485 {
2486 NtGdiOffsetRgn(hrgn, pt.x, pt.y);
2487 }
2488 else
2489 {
2490 HRGN hrgnScreen;
2491 PMONITOR pm = UserGetPrimaryMonitor();
2492 hrgnScreen = NtGdiCreateRectRgn(0,0,0,0);
2493 NtGdiCombineRgn(hrgnScreen, hrgnScreen, pm->hrgnMonitor, RGN_OR);
2494
2495 NtGdiCombineRgn(hrgn, hrgnScreen, NULL, RGN_COPY);
2496
2497 GreDeleteObject(hrgnScreen);
2498 }
2499
2500 NtGdiCombineRgn(hrgn, hrgn, Window->hrgnUpdate, RGN_DIFF);
2501
2502 NtGdiOffsetRgn(hrgn, -pt.x, -pt.y);
2503
2504 ret = NtGdiExtSelectClipRgn(hDC, hrgn, RGN_COPY);
2505
2506 GreDeleteObject(hrgn);
2507 }
2508 return ret;
2509 }
2510 }
2511 else
2512 {
2513 return GdiGetClipBox( hDC, &rc);
2514 }
2515 }
2516
2517 INT
2518 APIENTRY
NtUserExcludeUpdateRgn(HDC hDC,HWND hWnd)2519 NtUserExcludeUpdateRgn(
2520 HDC hDC,
2521 HWND hWnd)
2522 {
2523 INT ret = ERROR;
2524 PWND pWnd;
2525
2526 TRACE("Enter NtUserExcludeUpdateRgn\n");
2527 UserEnterExclusive();
2528
2529 pWnd = UserGetWindowObject(hWnd);
2530
2531 if (hDC && pWnd)
2532 ret = co_UserExcludeUpdateRgn(hDC, pWnd);
2533
2534 TRACE("Leave NtUserExcludeUpdateRgn, ret=%i\n", ret);
2535
2536 UserLeave();
2537 return ret;
2538 }
2539
2540 BOOL
2541 APIENTRY
NtUserInvalidateRect(HWND hWnd,CONST RECT * lpUnsafeRect,BOOL bErase)2542 NtUserInvalidateRect(
2543 HWND hWnd,
2544 CONST RECT *lpUnsafeRect,
2545 BOOL bErase)
2546 {
2547 UINT flags = RDW_INVALIDATE | (bErase ? RDW_ERASE : 0);
2548 if (!hWnd)
2549 {
2550 flags = RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW;
2551 lpUnsafeRect = NULL;
2552 }
2553 return NtUserRedrawWindow(hWnd, lpUnsafeRect, NULL, flags);
2554 }
2555
2556 BOOL
2557 APIENTRY
NtUserInvalidateRgn(HWND hWnd,HRGN hRgn,BOOL bErase)2558 NtUserInvalidateRgn(
2559 HWND hWnd,
2560 HRGN hRgn,
2561 BOOL bErase)
2562 {
2563 if (!hWnd)
2564 {
2565 EngSetLastError( ERROR_INVALID_WINDOW_HANDLE );
2566 return FALSE;
2567 }
2568 return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_INVALIDATE | (bErase? RDW_ERASE : 0));
2569 }
2570
2571 BOOL
2572 APIENTRY
NtUserPrintWindow(HWND hwnd,HDC hdcBlt,UINT nFlags)2573 NtUserPrintWindow(
2574 HWND hwnd,
2575 HDC hdcBlt,
2576 UINT nFlags)
2577 {
2578 PWND Window;
2579 BOOL Ret = FALSE;
2580
2581 UserEnterExclusive();
2582
2583 if (hwnd)
2584 {
2585 if (!(Window = UserGetWindowObject(hwnd)) ||
2586 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
2587 {
2588 goto Exit;
2589 }
2590
2591 if ( Window )
2592 {
2593 /* Validate flags and check it as a mask for 0 or 1. */
2594 if ( (nFlags & PW_CLIENTONLY) == nFlags)
2595 Ret = IntPrintWindow( Window, hdcBlt, nFlags);
2596 else
2597 EngSetLastError(ERROR_INVALID_PARAMETER);
2598 }
2599 }
2600 Exit:
2601 UserLeave();
2602 return Ret;
2603 }
2604
2605 /* ValidateRect gets redirected to NtUserValidateRect:
2606 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2607 BOOL
2608 APIENTRY
NtUserValidateRect(HWND hWnd,const RECT * lpRect)2609 NtUserValidateRect(
2610 HWND hWnd,
2611 const RECT *lpRect)
2612 {
2613 UINT flags = RDW_VALIDATE;
2614 if (!hWnd)
2615 {
2616 flags = RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW;
2617 lpRect = NULL;
2618 }
2619 return NtUserRedrawWindow(hWnd, lpRect, NULL, flags);
2620 }
2621
2622 /* EOF */
2623