1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
21 #include <vcl/gdimtf.hxx>
22 #include <vcl/window.hxx>
23 #include <vcl/virdev.hxx>
24 #include <vcl/cursor.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/syswin.hxx>
28 #include <sal/types.h>
29 #include <sal/log.hxx>
33 #include <salframe.hxx>
35 #include <comphelper/lok.hxx>
36 #include <comphelper/profilezone.hxx>
37 #if HAVE_FEATURE_OPENGL
38 #include <vcl/opengl/OpenGLHelper.hxx>
45 PaintBufferGuard::PaintBufferGuard(ImplFrameData
* pFrameData
, vcl::Window
* pWindow
)
46 : mpFrameData(pFrameData
),
52 if (!pFrameData
->mpBuffer
)
55 // transfer various settings
56 // FIXME: this must disappear as we move to RenderContext only,
57 // the painting must become state-less, so that no actual
58 // vcl::Window setting affects this
59 mbBackground
= pFrameData
->mpBuffer
->IsBackground();
60 if (pWindow
->IsBackground())
62 maBackground
= pFrameData
->mpBuffer
->GetBackground();
63 pFrameData
->mpBuffer
->SetBackground(pWindow
->GetBackground());
66 //SAL_WARN("vcl.window", "the root of the double-buffering hierarchy should not have a transparent background");
68 vcl::PushFlags nFlags
= vcl::PushFlags::NONE
;
69 nFlags
|= vcl::PushFlags::CLIPREGION
;
70 nFlags
|= vcl::PushFlags::FILLCOLOR
;
71 nFlags
|= vcl::PushFlags::FONT
;
72 nFlags
|= vcl::PushFlags::LINECOLOR
;
73 nFlags
|= vcl::PushFlags::MAPMODE
;
74 maSettings
= pFrameData
->mpBuffer
->GetSettings();
75 nFlags
|= vcl::PushFlags::REFPOINT
;
76 nFlags
|= vcl::PushFlags::TEXTCOLOR
;
77 nFlags
|= vcl::PushFlags::TEXTLINECOLOR
;
78 nFlags
|= vcl::PushFlags::OVERLINECOLOR
;
79 nFlags
|= vcl::PushFlags::TEXTFILLCOLOR
;
80 nFlags
|= vcl::PushFlags::TEXTALIGN
;
81 nFlags
|= vcl::PushFlags::RASTEROP
;
82 nFlags
|= vcl::PushFlags::TEXTLAYOUTMODE
;
83 nFlags
|= vcl::PushFlags::TEXTLANGUAGE
;
84 pFrameData
->mpBuffer
->Push(nFlags
);
85 auto& rDev
= *pWindow
->GetOutDev();
86 pFrameData
->mpBuffer
->SetClipRegion(rDev
.GetClipRegion());
87 pFrameData
->mpBuffer
->SetFillColor(rDev
.GetFillColor());
88 pFrameData
->mpBuffer
->SetFont(pWindow
->GetFont());
89 pFrameData
->mpBuffer
->SetLineColor(rDev
.GetLineColor());
90 pFrameData
->mpBuffer
->SetMapMode(pWindow
->GetMapMode());
91 pFrameData
->mpBuffer
->SetRefPoint(rDev
.GetRefPoint());
92 pFrameData
->mpBuffer
->SetSettings(pWindow
->GetSettings());
93 pFrameData
->mpBuffer
->SetTextColor(pWindow
->GetTextColor());
94 pFrameData
->mpBuffer
->SetTextLineColor(pWindow
->GetTextLineColor());
95 pFrameData
->mpBuffer
->SetOverlineColor(pWindow
->GetOverlineColor());
96 pFrameData
->mpBuffer
->SetTextFillColor(pWindow
->GetTextFillColor());
97 pFrameData
->mpBuffer
->SetTextAlign(pWindow
->GetTextAlign());
98 pFrameData
->mpBuffer
->SetRasterOp(rDev
.GetRasterOp());
99 pFrameData
->mpBuffer
->SetLayoutMode(rDev
.GetLayoutMode());
100 pFrameData
->mpBuffer
->SetDigitLanguage(rDev
.GetDigitLanguage());
102 mnOutOffX
= pFrameData
->mpBuffer
->GetOutOffXPixel();
103 mnOutOffY
= pFrameData
->mpBuffer
->GetOutOffYPixel();
104 pFrameData
->mpBuffer
->SetOutOffXPixel(pWindow
->GetOutOffXPixel());
105 pFrameData
->mpBuffer
->SetOutOffYPixel(pWindow
->GetOutOffYPixel());
106 pFrameData
->mpBuffer
->EnableRTL(pWindow
->IsRTLEnabled());
109 PaintBufferGuard::~PaintBufferGuard() COVERITY_NOEXCEPT_FALSE
111 if (!mpFrameData
->mpBuffer
)
114 if (!m_aPaintRect
.IsEmpty())
116 // copy the buffer content to the actual window
117 // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are
118 // painting directly instead of using Invalidate()
119 // [ie. everything you can see was painted directly to the
120 // window either above or in eg. an event handler]
121 if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT"))
123 // Make sure that the +1 value GetSize() adds to the size is in pixels.
125 if (m_pWindow
->GetMapMode().GetMapUnit() == MapUnit::MapPixel
)
127 aPaintRectSize
= m_aPaintRect
.GetSize();
131 tools::Rectangle aRectanglePixel
= m_pWindow
->LogicToPixel(m_aPaintRect
);
132 aPaintRectSize
= m_pWindow
->PixelToLogic(aRectanglePixel
.GetSize());
135 m_pWindow
->GetOutDev()->DrawOutDev(m_aPaintRect
.TopLeft(), aPaintRectSize
, m_aPaintRect
.TopLeft(), aPaintRectSize
, *mpFrameData
->mpBuffer
);
139 // Restore buffer state.
140 mpFrameData
->mpBuffer
->SetOutOffXPixel(mnOutOffX
);
141 mpFrameData
->mpBuffer
->SetOutOffYPixel(mnOutOffY
);
143 mpFrameData
->mpBuffer
->Pop();
144 mpFrameData
->mpBuffer
->SetSettings(maSettings
);
146 mpFrameData
->mpBuffer
->SetBackground(maBackground
);
148 mpFrameData
->mpBuffer
->SetBackground();
151 void PaintBufferGuard::SetPaintRect(const tools::Rectangle
& rRectangle
)
153 m_aPaintRect
= rRectangle
;
156 vcl::RenderContext
* PaintBufferGuard::GetRenderContext()
158 if (mpFrameData
->mpBuffer
)
159 return mpFrameData
->mpBuffer
;
161 return m_pWindow
->GetOutDev();
168 VclPtr
<vcl::Window
> m_pWindow
;
169 std::unique_ptr
<vcl::Region
> m_pChildRegion
;
170 tools::Rectangle m_aSelectionRect
;
171 tools::Rectangle m_aPaintRect
;
172 vcl::Region m_aPaintRegion
;
173 ImplPaintFlags m_nPaintFlags
;
175 bool m_bRestoreCursor
: 1;
176 bool m_bStartedBufferedPaint
: 1; ///< This PaintHelper started a buffered paint, and should paint it on the screen when being destructed.
178 PaintHelper(vcl::Window
* pWindow
, ImplPaintFlags nPaintFlags
);
183 void SetPaintRect(const tools::Rectangle
& rRect
)
185 m_aPaintRect
= rRect
;
187 void SetSelectionRect(const tools::Rectangle
& rRect
)
189 m_aSelectionRect
= rRect
;
191 void SetRestoreCursor(bool bRestoreCursor
)
193 m_bRestoreCursor
= bRestoreCursor
;
195 bool GetRestoreCursor() const
197 return m_bRestoreCursor
;
199 ImplPaintFlags
GetPaintFlags() const
201 return m_nPaintFlags
;
203 vcl::Region
& GetPaintRegion()
205 return m_aPaintRegion
;
207 void DoPaint(const vcl::Region
* pRegion
);
209 /// Start buffered paint: set it up to have the same settings as m_pWindow.
210 void StartBufferedPaint();
212 /// Paint the content of the buffer to the current m_pWindow.
218 PaintHelper::PaintHelper(vcl::Window
*pWindow
, ImplPaintFlags nPaintFlags
)
220 , m_nPaintFlags(nPaintFlags
)
222 , m_bRestoreCursor(false)
223 , m_bStartedBufferedPaint(false)
227 void PaintHelper::StartBufferedPaint()
229 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
230 assert(!pFrameData
->mbInBufferedPaint
);
232 pFrameData
->mbInBufferedPaint
= true;
233 pFrameData
->maBufferedRect
= tools::Rectangle();
234 m_bStartedBufferedPaint
= true;
237 void PaintHelper::PaintBuffer()
239 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
240 assert(pFrameData
->mbInBufferedPaint
);
241 assert(m_bStartedBufferedPaint
);
243 vcl::PaintBufferGuard
aGuard(pFrameData
, m_pWindow
);
244 aGuard
.SetPaintRect(pFrameData
->maBufferedRect
);
247 void PaintHelper::DoPaint(const vcl::Region
* pRegion
)
249 WindowImpl
* pWindowImpl
= m_pWindow
->ImplGetWindowImpl();
251 vcl::Region
& rWinChildClipRegion
= m_pWindow
->ImplGetWinChildClipRegion();
252 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
253 if (pWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
|| pFrameData
->mbInBufferedPaint
)
255 pWindowImpl
->maInvalidateRegion
= rWinChildClipRegion
;
260 pWindowImpl
->maInvalidateRegion
.Union( *pRegion
);
262 if (pWindowImpl
->mpWinData
&& pWindowImpl
->mbTrackVisible
)
263 /* #98602# need to repaint all children within the
264 * tracking rectangle, so the following invert
265 * operation takes places without traces of the previous
268 pWindowImpl
->maInvalidateRegion
.Union(*pWindowImpl
->mpWinData
->mpTrackRect
);
270 if (pWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
271 m_pChildRegion
.reset( new vcl::Region(pWindowImpl
->maInvalidateRegion
) );
272 pWindowImpl
->maInvalidateRegion
.Intersect(rWinChildClipRegion
);
274 pWindowImpl
->mnPaintFlags
= ImplPaintFlags::NONE
;
275 if (pWindowImpl
->maInvalidateRegion
.IsEmpty())
278 #if HAVE_FEATURE_OPENGL
279 VCL_GL_INFO("PaintHelper::DoPaint on " <<
280 typeid( *m_pWindow
).name() << " '" << m_pWindow
->GetText() << "' begin");
282 // double-buffering: setup the buffer if it does not exist
283 if (!pFrameData
->mbInBufferedPaint
&& m_pWindow
->SupportsDoubleBuffering())
284 StartBufferedPaint();
286 // double-buffering: if this window does not support double-buffering,
287 // but we are in the middle of double-buffered paint, we might be
288 // losing information
289 if (pFrameData
->mbInBufferedPaint
&& !m_pWindow
->SupportsDoubleBuffering())
290 SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow
.get()).name());
292 if (pFrameData
->mbInBufferedPaint
&& m_pWindow
->SupportsDoubleBuffering())
295 vcl::PaintBufferGuard
g(pFrameData
, m_pWindow
);
296 m_pWindow
->ApplySettings(*pFrameData
->mpBuffer
);
298 m_pWindow
->PushPaintHelper(this, *pFrameData
->mpBuffer
);
299 m_pWindow
->Paint(*pFrameData
->mpBuffer
, m_aPaintRect
);
300 pFrameData
->maBufferedRect
.Union(m_aPaintRect
);
305 Wallpaper aBackground
= m_pWindow
->GetBackground();
306 m_pWindow
->ApplySettings(*m_pWindow
->GetOutDev());
307 // Restore bitmap background if it was lost.
308 if (aBackground
.IsBitmap() && !m_pWindow
->GetBackground().IsBitmap())
310 m_pWindow
->SetBackground(aBackground
);
312 m_pWindow
->PushPaintHelper(this, *m_pWindow
->GetOutDev());
313 m_pWindow
->Paint(*m_pWindow
->GetOutDev(), m_aPaintRect
);
315 #if HAVE_FEATURE_OPENGL
316 VCL_GL_INFO("PaintHelper::DoPaint end on " <<
317 typeid( *m_pWindow
).name() << " '" << m_pWindow
->GetText() << "'");
324 void RenderTools::DrawSelectionBackground(vcl::RenderContext
& rRenderContext
, vcl::Window
const & rWindow
,
325 const tools::Rectangle
& rRect
, sal_uInt16 nHighlight
,
326 bool bChecked
, bool bDrawBorder
, bool bDrawExtBorderOnly
,
327 Color
* pSelectionTextColor
, tools::Long nCornerRadius
, Color
const * pPaintColor
)
332 bool bRoundEdges
= nCornerRadius
> 0;
334 const StyleSettings
& rStyles
= rRenderContext
.GetSettings().GetStyleSettings();
336 // colors used for item highlighting
337 Color
aSelectionBorderColor(pPaintColor
? *pPaintColor
: rStyles
.GetHighlightColor());
338 Color
aSelectionFillColor(aSelectionBorderColor
);
340 bool bDark
= rStyles
.GetFaceColor().IsDark();
341 bool bBright
= ( rStyles
.GetFaceColor() == COL_WHITE
);
343 int c1
= aSelectionBorderColor
.GetLuminance();
344 int c2
= rWindow
.GetBackgroundColor().GetLuminance();
346 if (!bDark
&& !bBright
&& std::abs(c2
- c1
) < (pPaintColor
? 40 : 75))
350 aSelectionFillColor
.RGBtoHSB( h
, s
, b
);
351 if( b
> 50 ) b
-= 40;
353 aSelectionFillColor
= Color::HSBtoRGB( h
, s
, b
);
354 aSelectionBorderColor
= aSelectionFillColor
;
359 if (aSelectionBorderColor
.IsDark())
360 aSelectionBorderColor
.IncreaseLuminance(128);
362 aSelectionBorderColor
.DecreaseLuminance(128);
365 tools::Rectangle
aRect(rRect
);
366 if (bDrawExtBorderOnly
)
368 aRect
.AdjustLeft( -1 );
369 aRect
.AdjustTop( -1 );
370 aRect
.AdjustRight(1 );
371 aRect
.AdjustBottom(1 );
373 rRenderContext
.Push(vcl::PushFlags::FILLCOLOR
| vcl::PushFlags::LINECOLOR
);
376 rRenderContext
.SetLineColor(bDark
? COL_WHITE
: (bBright
? COL_BLACK
: aSelectionBorderColor
));
378 rRenderContext
.SetLineColor();
380 sal_uInt16 nPercent
= 0;
384 aSelectionFillColor
= COL_BLACK
;
386 nPercent
= 80; // just checked (light)
390 if (bChecked
&& nHighlight
== 2)
393 aSelectionFillColor
= COL_LIGHTGRAY
;
396 aSelectionFillColor
= COL_BLACK
;
397 rRenderContext
.SetLineColor(COL_BLACK
);
401 nPercent
= bRoundEdges
? 40 : 20; // selected, pressed or checked ( very dark )
403 else if (bChecked
|| nHighlight
== 1)
406 aSelectionFillColor
= COL_GRAY
;
409 aSelectionFillColor
= COL_BLACK
;
410 rRenderContext
.SetLineColor(COL_BLACK
);
414 nPercent
= bRoundEdges
? 60 : 35; // selected, pressed or checked ( very dark )
419 aSelectionFillColor
= COL_LIGHTGRAY
;
422 aSelectionFillColor
= COL_BLACK
;
423 rRenderContext
.SetLineColor(COL_BLACK
);
430 nPercent
= 70; // selected ( dark )
434 if (bDark
&& bDrawExtBorderOnly
)
436 rRenderContext
.SetFillColor();
437 if (pSelectionTextColor
)
438 *pSelectionTextColor
= rStyles
.GetHighlightTextColor();
442 rRenderContext
.SetFillColor(aSelectionFillColor
);
443 if (pSelectionTextColor
)
445 Color aTextColor
= rWindow
.IsControlBackground() ? rWindow
.GetControlForeground() : rStyles
.GetButtonTextColor();
446 Color aHLTextColor
= rStyles
.GetHighlightTextColor();
447 int nTextDiff
= std::abs(aSelectionFillColor
.GetLuminance() - aTextColor
.GetLuminance());
448 int nHLDiff
= std::abs(aSelectionFillColor
.GetLuminance() - aHLTextColor
.GetLuminance());
449 *pSelectionTextColor
= (nHLDiff
>= nTextDiff
) ? aHLTextColor
: aTextColor
;
455 rRenderContext
.DrawRect(aRect
);
461 tools::Polygon
aPoly(aRect
, nCornerRadius
, nCornerRadius
);
462 tools::PolyPolygon
aPolyPoly(aPoly
);
463 rRenderContext
.DrawTransparent(aPolyPoly
, nPercent
);
467 tools::Polygon
aPoly(aRect
);
468 tools::PolyPolygon
aPolyPoly(aPoly
);
469 rRenderContext
.DrawTransparent(aPolyPoly
, nPercent
);
473 rRenderContext
.Pop(); // LINECOLOR | FILLCOLOR
476 void Window::PushPaintHelper(PaintHelper
*pHelper
, vcl::RenderContext
& rRenderContext
)
480 if ( mpWindowImpl
->mpCursor
)
481 pHelper
->SetRestoreCursor(mpWindowImpl
->mpCursor
->ImplSuspend());
483 GetOutDev()->mbInitClipRegion
= true;
484 mpWindowImpl
->mbInPaint
= true;
486 // restore Paint-Region
487 vcl::Region
&rPaintRegion
= pHelper
->GetPaintRegion();
488 rPaintRegion
= mpWindowImpl
->maInvalidateRegion
;
489 tools::Rectangle aPaintRect
= rPaintRegion
.GetBoundRect();
491 // RTL: re-mirror paint rect and region at this window
492 if (GetOutDev()->ImplIsAntiparallel())
494 rRenderContext
.ReMirror(aPaintRect
);
495 rRenderContext
.ReMirror(rPaintRegion
);
497 aPaintRect
= GetOutDev()->ImplDevicePixelToLogic(aPaintRect
);
498 mpWindowImpl
->mpPaintRegion
= &rPaintRegion
;
499 mpWindowImpl
->maInvalidateRegion
.SetEmpty();
501 if ((pHelper
->GetPaintFlags() & ImplPaintFlags::Erase
) && rRenderContext
.IsBackground())
503 if (rRenderContext
.IsClipRegion())
505 vcl::Region aOldRegion
= rRenderContext
.GetClipRegion();
506 rRenderContext
.SetClipRegion();
507 Erase(rRenderContext
);
508 rRenderContext
.SetClipRegion(aOldRegion
);
511 Erase(rRenderContext
);
514 // #98943# trigger drawing of toolbox selection after all children are painted
515 if (mpWindowImpl
->mbDrawSelectionBackground
)
516 pHelper
->SetSelectionRect(aPaintRect
);
517 pHelper
->SetPaintRect(aPaintRect
);
520 void Window::PopPaintHelper(PaintHelper
const *pHelper
)
522 if (mpWindowImpl
->mpWinData
)
524 if (mpWindowImpl
->mbFocusVisible
)
525 ImplInvertFocus(*mpWindowImpl
->mpWinData
->mpFocusRect
);
527 mpWindowImpl
->mbInPaint
= false;
528 GetOutDev()->mbInitClipRegion
= true;
529 mpWindowImpl
->mpPaintRegion
= nullptr;
530 if (mpWindowImpl
->mpCursor
)
531 mpWindowImpl
->mpCursor
->ImplResume(pHelper
->GetRestoreCursor());
534 } /* namespace vcl */
536 PaintHelper::~PaintHelper()
538 WindowImpl
* pWindowImpl
= m_pWindow
->ImplGetWindowImpl();
541 m_pWindow
->PopPaintHelper(this);
544 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
545 if ( m_nPaintFlags
& (ImplPaintFlags::PaintAllChildren
| ImplPaintFlags::PaintChildren
) )
547 // Paint from the bottom child window and frontward.
548 vcl::Window
* pTempWindow
= pWindowImpl
->mpLastChild
;
551 if (pTempWindow
->mpWindowImpl
->mbVisible
)
552 pTempWindow
->ImplCallPaint(m_pChildRegion
.get(), m_nPaintFlags
);
553 pTempWindow
= pTempWindow
->mpWindowImpl
->mpPrev
;
557 if ( pWindowImpl
->mpWinData
&& pWindowImpl
->mbTrackVisible
&& (pWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
558 /* #98602# need to invert the tracking rect AFTER
559 * the children have painted
561 m_pWindow
->InvertTracking( *pWindowImpl
->mpWinData
->mpTrackRect
, pWindowImpl
->mpWinData
->mnTrackFlags
);
563 // double-buffering: paint in case we created the buffer, the children are
564 // already painted inside
565 if (m_bStartedBufferedPaint
&& pFrameData
->mbInBufferedPaint
)
568 pFrameData
->mbInBufferedPaint
= false;
569 pFrameData
->maBufferedRect
= tools::Rectangle();
572 // #98943# draw toolbox selection
573 if( !m_aSelectionRect
.IsEmpty() )
574 m_pWindow
->DrawSelectionBackground( m_aSelectionRect
, 3, false, true );
579 void Window::ImplCallPaint(const vcl::Region
* pRegion
, ImplPaintFlags nPaintFlags
)
581 // call PrePaint. PrePaint may add to the invalidate region as well as
582 // other parameters used below.
583 PrePaint(*GetOutDev());
585 mpWindowImpl
->mbPaintFrame
= false;
587 if (nPaintFlags
& ImplPaintFlags::PaintAllChildren
)
588 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Paint
| ImplPaintFlags::PaintAllChildren
| (nPaintFlags
& ImplPaintFlags::PaintAll
);
589 if (nPaintFlags
& ImplPaintFlags::PaintChildren
)
590 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintChildren
;
591 if (nPaintFlags
& ImplPaintFlags::Erase
)
592 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Erase
;
593 if (nPaintFlags
& ImplPaintFlags::CheckRtl
)
594 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::CheckRtl
;
595 if (!mpWindowImpl
->mpFirstChild
)
596 mpWindowImpl
->mnPaintFlags
&= ~ImplPaintFlags::PaintAllChildren
;
598 // If tiled rendering is used, windows are only invalidated, never painted to.
599 if (mpWindowImpl
->mbPaintDisabled
|| comphelper::LibreOfficeKit::isActive())
601 if (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
602 Invalidate(InvalidateFlags::NoChildren
| InvalidateFlags::NoErase
| InvalidateFlags::NoTransparent
| InvalidateFlags::NoClipChildren
);
604 Invalidate(*pRegion
, InvalidateFlags::NoChildren
| InvalidateFlags::NoErase
| InvalidateFlags::NoTransparent
| InvalidateFlags::NoClipChildren
);
606 // call PostPaint before returning
607 PostPaint(*GetOutDev());
612 nPaintFlags
= mpWindowImpl
->mnPaintFlags
& ~ImplPaintFlags::Paint
;
614 PaintHelper
aHelper(this, nPaintFlags
);
616 if (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::Paint
)
617 aHelper
.DoPaint(pRegion
);
619 mpWindowImpl
->mnPaintFlags
= ImplPaintFlags::NONE
;
622 PostPaint(*GetOutDev());
625 void Window::ImplCallOverlapPaint()
630 // emit overlapping windows first
631 vcl::Window
* pTempWindow
= mpWindowImpl
->mpFirstOverlap
;
632 while ( pTempWindow
)
634 if ( pTempWindow
->mpWindowImpl
->mbReallyVisible
)
635 pTempWindow
->ImplCallOverlapPaint();
636 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
640 if ( mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintChildren
) )
642 // RTL: notify ImplCallPaint to check for re-mirroring
643 // because we were called from the Sal layer
644 ImplCallPaint(nullptr, mpWindowImpl
->mnPaintFlags
/*| ImplPaintFlags::CheckRtl */);
648 IMPL_LINK_NOARG(Window
, ImplHandlePaintHdl
, Timer
*, void)
650 comphelper::ProfileZone
aZone("VCL idle re-paint");
652 // save paint events until layout is done
653 if (IsSystemWindow() && static_cast<const SystemWindow
*>(this)->hasPendingLayout())
655 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
659 // save paint events until resizing or initial sizing done
660 if (mpWindowImpl
->mbFrame
&&
661 mpWindowImpl
->mpFrameData
->maResizeIdle
.IsActive())
663 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
665 else if ( mpWindowImpl
->mbReallyVisible
)
667 ImplCallOverlapPaint();
668 if (comphelper::LibreOfficeKit::isActive() &&
669 mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive())
670 mpWindowImpl
->mpFrameData
->maPaintIdle
.Stop();
674 IMPL_LINK_NOARG(Window
, ImplHandleResizeTimerHdl
, Timer
*, void)
676 comphelper::ProfileZone
aZone("VCL idle resize");
678 if( mpWindowImpl
->mbReallyVisible
)
681 if( mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive() )
683 mpWindowImpl
->mpFrameData
->maPaintIdle
.Stop();
684 mpWindowImpl
->mpFrameData
->maPaintIdle
.Invoke( nullptr );
689 void Window::ImplInvalidateFrameRegion( const vcl::Region
* pRegion
, InvalidateFlags nFlags
)
691 // set PAINTCHILDREN for all parent windows till the first OverlapWindow
692 if ( !ImplIsOverlapWindow() )
694 vcl::Window
* pTempWindow
= this;
695 ImplPaintFlags nTranspPaint
= IsPaintTransparent() ? ImplPaintFlags::Paint
: ImplPaintFlags::NONE
;
698 pTempWindow
= pTempWindow
->ImplGetParent();
699 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintChildren
)
701 pTempWindow
->mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintChildren
| nTranspPaint
;
702 if( ! pTempWindow
->IsPaintTransparent() )
703 nTranspPaint
= ImplPaintFlags::NONE
;
705 while ( !pTempWindow
->ImplIsOverlapWindow() );
709 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Paint
;
710 if ( nFlags
& InvalidateFlags::Children
)
711 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintAllChildren
;
712 if ( !(nFlags
& InvalidateFlags::NoErase
) )
713 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Erase
;
716 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintAll
;
717 else if ( !(mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
) )
719 // if not everything has to be redrawn, add the region to it
720 mpWindowImpl
->maInvalidateRegion
.Union( *pRegion
);
723 // Handle transparent windows correctly: invalidate must be done on the first opaque parent
724 if( ((IsPaintTransparent() && !(nFlags
& InvalidateFlags::NoTransparent
)) || (nFlags
& InvalidateFlags::Transparent
) )
727 vcl::Window
*pParent
= ImplGetParent();
728 while( pParent
&& pParent
->IsPaintTransparent() )
729 pParent
= pParent
->ImplGetParent();
732 vcl::Region
*pChildRegion
;
733 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
734 // invalidate the whole child window region in the parent
735 pChildRegion
= &ImplGetWinChildClipRegion();
737 // invalidate the same region in the parent that has to be repainted in the child
738 pChildRegion
= &mpWindowImpl
->maInvalidateRegion
;
740 nFlags
|= InvalidateFlags::Children
; // paint should also be done on all children
741 nFlags
&= ~InvalidateFlags::NoErase
; // parent should paint and erase to create proper background
742 pParent
->ImplInvalidateFrameRegion( pChildRegion
, nFlags
);
746 if ( !mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive() )
747 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
750 void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region
& rRegion
)
752 vcl::Region aRegion
= rRegion
;
754 ImplClipBoundaries( aRegion
, true, true );
755 if ( !aRegion
.IsEmpty() )
756 ImplInvalidateFrameRegion( &aRegion
, InvalidateFlags::Children
);
758 // now we invalidate the overlapping windows
759 vcl::Window
* pTempWindow
= mpWindowImpl
->mpFirstOverlap
;
760 while ( pTempWindow
)
762 if ( pTempWindow
->IsVisible() )
763 pTempWindow
->ImplInvalidateOverlapFrameRegion( rRegion
);
765 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
769 void Window::ImplInvalidateParentFrameRegion( const vcl::Region
& rRegion
)
771 if ( mpWindowImpl
->mbOverlapWin
)
772 mpWindowImpl
->mpFrameWindow
->ImplInvalidateOverlapFrameRegion( rRegion
);
775 if( ImplGetParent() )
776 ImplGetParent()->ImplInvalidateFrameRegion( &rRegion
, InvalidateFlags::Children
);
780 void Window::ImplInvalidate( const vcl::Region
* pRegion
, InvalidateFlags nFlags
)
782 // check what has to be redrawn
783 bool bInvalidateAll
= !pRegion
;
785 // take Transparent-Invalidate into account
786 vcl::Window
* pOpaqueWindow
= this;
787 if ( (mpWindowImpl
->mbPaintTransparent
&& !(nFlags
& InvalidateFlags::NoTransparent
)) || (nFlags
& InvalidateFlags::Transparent
) )
789 vcl::Window
* pTempWindow
= pOpaqueWindow
->ImplGetParent();
790 while ( pTempWindow
)
792 if ( !pTempWindow
->IsPaintTransparent() )
794 pOpaqueWindow
= pTempWindow
;
795 nFlags
|= InvalidateFlags::Children
;
796 bInvalidateAll
= false;
800 if ( pTempWindow
->ImplIsOverlapWindow() )
803 pTempWindow
= pTempWindow
->ImplGetParent();
808 InvalidateFlags nOrgFlags
= nFlags
;
809 if ( !(nFlags
& (InvalidateFlags::Children
| InvalidateFlags::NoChildren
)) )
811 if ( GetStyle() & WB_CLIPCHILDREN
)
812 nFlags
|= InvalidateFlags::NoChildren
;
814 nFlags
|= InvalidateFlags::Children
;
816 if ( (nFlags
& InvalidateFlags::NoChildren
) && mpWindowImpl
->mpFirstChild
)
817 bInvalidateAll
= false;
818 if ( bInvalidateAll
)
819 ImplInvalidateFrameRegion( nullptr, nFlags
);
822 vcl::Region
aRegion( GetOutputRectPixel() );
825 // RTL: remirror region before intersecting it
826 if ( GetOutDev()->ImplIsAntiparallel() )
828 const OutputDevice
*pOutDev
= GetOutDev();
830 vcl::Region
aRgn( *pRegion
);
831 pOutDev
->ReMirror( aRgn
);
832 aRegion
.Intersect( aRgn
);
835 aRegion
.Intersect( *pRegion
);
837 ImplClipBoundaries( aRegion
, true, true );
838 if ( nFlags
& InvalidateFlags::NoChildren
)
840 nFlags
&= ~InvalidateFlags::Children
;
841 if ( !(nFlags
& InvalidateFlags::NoClipChildren
) )
843 if ( nOrgFlags
& InvalidateFlags::NoChildren
)
844 ImplClipAllChildren( aRegion
);
847 if ( ImplClipChildren( aRegion
) )
848 nFlags
|= InvalidateFlags::Children
;
852 if ( !aRegion
.IsEmpty() )
853 ImplInvalidateFrameRegion( &aRegion
, nFlags
); // transparency is handled here, pOpaqueWindow not required
856 if ( nFlags
& InvalidateFlags::Update
)
857 pOpaqueWindow
->PaintImmediately(); // start painting at the opaque parent
860 void Window::ImplMoveInvalidateRegion( const tools::Rectangle
& rRect
,
861 tools::Long nHorzScroll
, tools::Long nVertScroll
,
864 if ( (mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintAll
)) == ImplPaintFlags::Paint
)
866 vcl::Region aTempRegion
= mpWindowImpl
->maInvalidateRegion
;
867 aTempRegion
.Intersect( rRect
);
868 aTempRegion
.Move( nHorzScroll
, nVertScroll
);
869 mpWindowImpl
->maInvalidateRegion
.Union( aTempRegion
);
872 if ( bChildren
&& (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintChildren
) )
874 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstChild
;
877 pWindow
->ImplMoveInvalidateRegion( rRect
, nHorzScroll
, nVertScroll
, true );
878 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
883 void Window::ImplMoveAllInvalidateRegions( const tools::Rectangle
& rRect
,
884 tools::Long nHorzScroll
, tools::Long nVertScroll
,
887 // also shift Paint-Region when paints need processing
888 ImplMoveInvalidateRegion( rRect
, nHorzScroll
, nVertScroll
, bChildren
);
889 // Paint-Region should be shifted, as drawn by the parents
890 if ( ImplIsOverlapWindow() )
893 vcl::Region aPaintAllRegion
;
894 vcl::Window
* pPaintAllWindow
= this;
897 pPaintAllWindow
= pPaintAllWindow
->ImplGetParent();
898 if ( pPaintAllWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
900 if ( pPaintAllWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
902 aPaintAllRegion
.SetEmpty();
906 aPaintAllRegion
.Union( pPaintAllWindow
->mpWindowImpl
->maInvalidateRegion
);
909 while ( !pPaintAllWindow
->ImplIsOverlapWindow() );
910 if ( !aPaintAllRegion
.IsEmpty() )
912 aPaintAllRegion
.Move( nHorzScroll
, nVertScroll
);
913 InvalidateFlags nPaintFlags
= InvalidateFlags::NONE
;
915 nPaintFlags
|= InvalidateFlags::Children
;
916 ImplInvalidateFrameRegion( &aPaintAllRegion
, nPaintFlags
);
920 void Window::ImplValidateFrameRegion( const vcl::Region
* pRegion
, ValidateFlags nFlags
)
923 mpWindowImpl
->maInvalidateRegion
.SetEmpty();
926 // when all child windows have to be drawn we need to invalidate them before doing so
927 if ( (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
) && mpWindowImpl
->mpFirstChild
)
929 vcl::Region aChildRegion
= mpWindowImpl
->maInvalidateRegion
;
930 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
932 aChildRegion
= GetOutputRectPixel();
934 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
937 pChild
->Invalidate( aChildRegion
, InvalidateFlags::Children
| InvalidateFlags::NoTransparent
);
938 pChild
= pChild
->mpWindowImpl
->mpNext
;
941 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
943 mpWindowImpl
->maInvalidateRegion
= GetOutputRectPixel();
945 mpWindowImpl
->maInvalidateRegion
.Exclude( *pRegion
);
947 mpWindowImpl
->mnPaintFlags
&= ~ImplPaintFlags::PaintAll
;
949 if ( nFlags
& ValidateFlags::Children
)
951 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
954 pChild
->ImplValidateFrameRegion( pRegion
, nFlags
);
955 pChild
= pChild
->mpWindowImpl
->mpNext
;
960 void Window::ImplValidate()
963 bool bValidateAll
= true;
964 ValidateFlags nFlags
= ValidateFlags::NONE
;
965 if ( GetStyle() & WB_CLIPCHILDREN
)
966 nFlags
|= ValidateFlags::NoChildren
;
968 nFlags
|= ValidateFlags::Children
;
969 if ( (nFlags
& ValidateFlags::NoChildren
) && mpWindowImpl
->mpFirstChild
)
970 bValidateAll
= false;
972 ImplValidateFrameRegion( nullptr, nFlags
);
975 vcl::Region
aRegion( GetOutputRectPixel() );
976 ImplClipBoundaries( aRegion
, true, true );
977 if ( nFlags
& ValidateFlags::NoChildren
)
979 nFlags
&= ~ValidateFlags::Children
;
980 if ( ImplClipChildren( aRegion
) )
981 nFlags
|= ValidateFlags::Children
;
983 if ( !aRegion
.IsEmpty() )
984 ImplValidateFrameRegion( &aRegion
, nFlags
);
988 void Window::ImplUpdateAll()
990 if ( !mpWindowImpl
|| !mpWindowImpl
->mbReallyVisible
)
994 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
996 Point
aPoint( 0, 0 );
997 vcl::Region
aRegion( tools::Rectangle( aPoint
, GetOutputSizePixel() ) );
998 ImplInvalidateOverlapFrameRegion( aRegion
);
999 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
1003 // an update changes the OverlapWindow, such that for later paints
1004 // not too much has to be drawn, if ALLCHILDREN etc. is set
1005 vcl::Window
* pWindow
= ImplGetFirstOverlapWindow();
1006 pWindow
->ImplCallOverlapPaint();
1009 GetOutDev()->Flush();
1012 void Window::PrePaint(vcl::RenderContext
& /*rRenderContext*/)
1016 void Window::PostPaint(vcl::RenderContext
& /*rRenderContext*/)
1020 void Window::Paint(vcl::RenderContext
& /*rRenderContext*/, const tools::Rectangle
& rRect
)
1022 CallEventListeners(VclEventId::WindowPaint
, const_cast<tools::Rectangle
*>(&rRect
));
1025 void Window::SetPaintTransparent( bool bTransparent
)
1027 // transparency is not useful for frames as the background would have to be provided by a different frame
1028 if( bTransparent
&& mpWindowImpl
->mbFrame
)
1031 if ( mpWindowImpl
->mpBorderWindow
)
1032 mpWindowImpl
->mpBorderWindow
->SetPaintTransparent( bTransparent
);
1034 mpWindowImpl
->mbPaintTransparent
= bTransparent
;
1037 void Window::SetWindowRegionPixel()
1040 if ( mpWindowImpl
->mpBorderWindow
)
1041 mpWindowImpl
->mpBorderWindow
->SetWindowRegionPixel();
1042 else if( mpWindowImpl
->mbFrame
)
1044 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1045 mpWindowImpl
->mbWinRegion
= false;
1046 mpWindowImpl
->mpFrame
->ResetClipRegion();
1050 if ( mpWindowImpl
->mbWinRegion
)
1052 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1053 mpWindowImpl
->mbWinRegion
= false;
1056 if ( IsReallyVisible() )
1058 vcl::Region
aRegion( GetOutputRectPixel() );
1059 ImplInvalidateParentFrameRegion( aRegion
);
1065 void Window::SetWindowRegionPixel( const vcl::Region
& rRegion
)
1068 if ( mpWindowImpl
->mpBorderWindow
)
1069 mpWindowImpl
->mpBorderWindow
->SetWindowRegionPixel( rRegion
);
1070 else if( mpWindowImpl
->mbFrame
)
1072 if( !rRegion
.IsNull() )
1074 mpWindowImpl
->maWinRegion
= rRegion
;
1075 mpWindowImpl
->mbWinRegion
= ! rRegion
.IsEmpty();
1077 if( mpWindowImpl
->mbWinRegion
)
1079 // set/update ClipRegion
1080 RectangleVector aRectangles
;
1081 mpWindowImpl
->maWinRegion
.GetRegionRectangles(aRectangles
);
1082 mpWindowImpl
->mpFrame
->BeginSetClipRegion(aRectangles
.size());
1084 for (auto const& rectangle
: aRectangles
)
1086 mpWindowImpl
->mpFrame
->UnionClipRegion(
1089 rectangle
.GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
1090 rectangle
.GetHeight()); // same for height
1093 mpWindowImpl
->mpFrame
->EndSetClipRegion();
1096 SetWindowRegionPixel();
1099 SetWindowRegionPixel();
1103 if ( rRegion
.IsNull() )
1105 if ( mpWindowImpl
->mbWinRegion
)
1107 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1108 mpWindowImpl
->mbWinRegion
= false;
1114 mpWindowImpl
->maWinRegion
= rRegion
;
1115 mpWindowImpl
->mbWinRegion
= true;
1119 if ( IsReallyVisible() )
1121 vcl::Region
aRegion( GetOutputRectPixel() );
1122 ImplInvalidateParentFrameRegion( aRegion
);
1127 vcl::Region
Window::GetPaintRegion() const
1130 if ( mpWindowImpl
->mpPaintRegion
)
1132 vcl::Region aRegion
= *mpWindowImpl
->mpPaintRegion
;
1133 aRegion
.Move( -GetOutDev()->mnOutOffX
, -GetOutDev()->mnOutOffY
);
1134 return PixelToLogic( aRegion
);
1138 vcl::Region
aPaintRegion(true);
1139 return aPaintRegion
;
1143 void Window::Invalidate( InvalidateFlags nFlags
)
1145 if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth
|| !GetOutDev()->mnOutHeight
) )
1148 ImplInvalidate( nullptr, nFlags
);
1149 LogicInvalidate(nullptr);
1152 void Window::Invalidate( const tools::Rectangle
& rRect
, InvalidateFlags nFlags
)
1154 if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth
|| !GetOutDev()->mnOutHeight
) )
1157 OutputDevice
*pOutDev
= GetOutDev();
1158 tools::Rectangle aRect
= pOutDev
->ImplLogicToDevicePixel( rRect
);
1159 if ( !aRect
.IsEmpty() )
1161 vcl::Region
aRegion( aRect
);
1162 ImplInvalidate( &aRegion
, nFlags
);
1163 tools::Rectangle
aLogicRectangle(rRect
);
1164 LogicInvalidate(&aLogicRectangle
);
1168 void Window::Invalidate( const vcl::Region
& rRegion
, InvalidateFlags nFlags
)
1170 if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth
|| !GetOutDev()->mnOutHeight
) )
1173 if ( rRegion
.IsNull() )
1175 ImplInvalidate( nullptr, nFlags
);
1176 LogicInvalidate(nullptr);
1180 vcl::Region aRegion
= GetOutDev()->ImplPixelToDevicePixel( LogicToPixel( rRegion
) );
1181 if ( !aRegion
.IsEmpty() )
1183 ImplInvalidate( &aRegion
, nFlags
);
1184 tools::Rectangle aLogicRectangle
= rRegion
.GetBoundRect();
1185 LogicInvalidate(&aLogicRectangle
);
1190 void Window::LogicInvalidate(const tools::Rectangle
* pRectangle
)
1194 tools::Rectangle aRect
= GetOutDev()->ImplLogicToDevicePixel( *pRectangle
);
1195 PixelInvalidate(&aRect
);
1198 PixelInvalidate(nullptr);
1201 bool Window::InvalidateByForeignEditView(EditView
* )
1206 void Window::PixelInvalidate(const tools::Rectangle
* pRectangle
)
1208 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1211 Size aSize
= GetSizePixel();
1212 if (aSize
.IsEmpty())
1215 if (const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
1217 // In case we are routing the window, notify the client
1218 std::vector
<vcl::LOKPayloadItem
> aPayload
;
1219 tools::Rectangle
aRect(Point(0, 0), aSize
);
1221 aRect
= *pRectangle
;
1223 if (IsRTLEnabled() && GetOutDev() && !GetOutDev()->ImplIsAntiparallel())
1224 GetOutDev()->ReMirror(aRect
);
1226 aPayload
.emplace_back("rectangle", aRect
.toString());
1228 pNotifier
->notifyWindow(GetLOKWindowId(), u
"invalidate"_ustr
, aPayload
);
1230 // Added for dialog items. Pass invalidation to the parent window.
1231 else if (VclPtr
<vcl::Window
> pParent
= GetParentWithLOKNotifier())
1233 const tools::Rectangle
aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1234 pParent
->PixelInvalidate(&aRect
);
1238 void Window::Validate()
1240 if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth
|| !GetOutDev()->mnOutHeight
) )
1246 bool Window::HasPaintEvent() const
1249 if ( !mpWindowImpl
->mbReallyVisible
)
1252 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1255 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::Paint
)
1258 if ( !ImplIsOverlapWindow() )
1260 const vcl::Window
* pTempWindow
= this;
1263 pTempWindow
= pTempWindow
->ImplGetParent();
1264 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::PaintChildren
| ImplPaintFlags::PaintAllChildren
) )
1267 while ( !pTempWindow
->ImplIsOverlapWindow() );
1273 void Window::PaintImmediately()
1278 if ( mpWindowImpl
->mpBorderWindow
)
1280 mpWindowImpl
->mpBorderWindow
->PaintImmediately();
1284 if ( !mpWindowImpl
->mbReallyVisible
)
1287 bool bFlush
= false;
1288 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1290 Point
aPoint( 0, 0 );
1291 vcl::Region
aRegion( tools::Rectangle( aPoint
, GetOutputSizePixel() ) );
1292 ImplInvalidateOverlapFrameRegion( aRegion
);
1293 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
1297 // First we should skip all windows which are Paint-Transparent
1298 vcl::Window
* pUpdateWindow
= this;
1299 vcl::Window
* pWindow
= pUpdateWindow
;
1300 while ( !pWindow
->ImplIsOverlapWindow() )
1302 if ( !pWindow
->mpWindowImpl
->mbPaintTransparent
)
1304 pUpdateWindow
= pWindow
;
1307 pWindow
= pWindow
->ImplGetParent();
1309 // In order to limit drawing, an update only draws the window which
1310 // has PAINTALLCHILDREN set
1311 pWindow
= pUpdateWindow
;
1314 if ( pWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
1315 pUpdateWindow
= pWindow
;
1316 if ( pWindow
->ImplIsOverlapWindow() )
1318 pWindow
= pWindow
->ImplGetParent();
1322 // if there is something to paint, trigger a Paint
1323 if ( pUpdateWindow
->mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintChildren
) )
1325 VclPtr
<vcl::Window
> xWindow(this);
1327 // trigger an update also for system windows on top of us,
1328 // otherwise holes would remain
1329 vcl::Window
* pUpdateOverlapWindow
= ImplGetFirstOverlapWindow();
1330 if (pUpdateOverlapWindow
->mpWindowImpl
)
1331 pUpdateOverlapWindow
= pUpdateOverlapWindow
->mpWindowImpl
->mpFirstOverlap
;
1333 pUpdateOverlapWindow
= nullptr;
1334 while ( pUpdateOverlapWindow
)
1336 pUpdateOverlapWindow
->PaintImmediately();
1337 pUpdateOverlapWindow
= pUpdateOverlapWindow
->mpWindowImpl
->mpNext
;
1340 pUpdateWindow
->ImplCallPaint(nullptr, pUpdateWindow
->mpWindowImpl
->mnPaintFlags
);
1342 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow
->GetParentDialog())
1343 pUpdateWindow
->LogicInvalidate(nullptr);
1345 if (xWindow
->isDisposed())
1352 GetOutDev()->Flush();
1355 void Window::ImplPaintToDevice( OutputDevice
* i_pTargetOutDev
, const Point
& i_rPos
)
1357 // Special drawing when called through LOKit
1358 // TODO: Move to its own method
1359 if (comphelper::LibreOfficeKit::isActive())
1361 VclPtrInstance
<VirtualDevice
> pDevice(*i_pTargetOutDev
);
1362 pDevice
->EnableRTL(IsRTLEnabled());
1364 Size
aSize(GetOutputSizePixel());
1365 pDevice
->SetOutputSizePixel(aSize
);
1367 vcl::Font aCopyFont
= GetFont();
1368 pDevice
->SetFont(aCopyFont
);
1370 pDevice
->SetTextColor(GetTextColor());
1371 if (GetOutDev()->IsLineColor())
1372 pDevice
->SetLineColor(GetOutDev()->GetLineColor());
1374 pDevice
->SetLineColor();
1376 if (GetOutDev()->IsFillColor())
1377 pDevice
->SetFillColor(GetOutDev()->GetFillColor());
1379 pDevice
->SetFillColor();
1381 if (IsTextLineColor())
1382 pDevice
->SetTextLineColor(GetTextLineColor());
1384 pDevice
->SetTextLineColor();
1386 if (IsOverlineColor())
1387 pDevice
->SetOverlineColor(GetOverlineColor());
1389 pDevice
->SetOverlineColor();
1391 if (IsTextFillColor())
1392 pDevice
->SetTextFillColor(GetTextFillColor());
1394 pDevice
->SetTextFillColor();
1396 pDevice
->SetTextAlign(GetTextAlign());
1397 pDevice
->SetRasterOp(GetOutDev()->GetRasterOp());
1399 tools::Rectangle
aPaintRect(Point(), GetOutputSizePixel());
1401 vcl::Region
aClipRegion(GetOutDev()->GetClipRegion());
1402 pDevice
->SetClipRegion();
1403 aClipRegion
.Intersect(aPaintRect
);
1404 pDevice
->SetClipRegion(aClipRegion
);
1406 if (!IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip
))
1409 pDevice
->SetMapMode(GetMapMode());
1411 Paint(*pDevice
, tools::Rectangle(Point(), GetOutputSizePixel()));
1413 i_pTargetOutDev
->DrawOutDev(i_rPos
, aSize
, Point(), pDevice
->PixelToLogic(aSize
), *pDevice
);
1415 bool bHasMirroredGraphics
= pDevice
->HasMirroredGraphics();
1417 // get rid of virtual device now so they don't pile up during recursive calls
1418 pDevice
.disposeAndClear();
1421 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1423 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1425 tools::Long nDeltaX
= pChild
->GetOutDev()->mnOutOffX
- GetOutDev()->mnOutOffX
;
1426 if( bHasMirroredGraphics
)
1427 nDeltaX
= GetOutDev()->mnOutWidth
- nDeltaX
- pChild
->GetOutDev()->mnOutWidth
;
1429 tools::Long nDeltaY
= pChild
->GetOutOffYPixel() - GetOutOffYPixel();
1431 Point
aPos( i_rPos
);
1432 aPos
+= Point(nDeltaX
, nDeltaY
);
1434 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1441 bool bRVisible
= mpWindowImpl
->mbReallyVisible
;
1442 mpWindowImpl
->mbReallyVisible
= mpWindowImpl
->mbVisible
;
1443 bool bDevOutput
= GetOutDev()->mbDevOutput
;
1444 GetOutDev()->mbDevOutput
= true;
1446 const OutputDevice
*pOutDev
= GetOutDev();
1447 tools::Long nOldDPIX
= pOutDev
->GetDPIX();
1448 tools::Long nOldDPIY
= pOutDev
->GetDPIY();
1449 GetOutDev()->mnDPIX
= i_pTargetOutDev
->GetDPIX();
1450 GetOutDev()->mnDPIY
= i_pTargetOutDev
->GetDPIY();
1451 bool bOutput
= GetOutDev()->IsOutputEnabled();
1452 GetOutDev()->EnableOutput();
1454 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel
, "vcl.window", "MapMode must be PIXEL based" );
1455 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel
)
1458 // preserve graphicsstate
1459 GetOutDev()->Push();
1460 vcl::Region
aClipRegion( GetOutDev()->GetClipRegion() );
1461 GetOutDev()->SetClipRegion();
1463 GDIMetaFile
* pOldMtf
= GetOutDev()->GetConnectMetaFile();
1465 GetOutDev()->SetConnectMetaFile( &aMtf
);
1467 // put a push action to metafile
1468 GetOutDev()->Push();
1469 // copy graphics state to metafile
1470 vcl::Font aCopyFont
= GetFont();
1471 if( nOldDPIX
!= GetOutDev()->mnDPIX
|| nOldDPIY
!= GetOutDev()->mnDPIY
)
1473 aCopyFont
.SetFontHeight( aCopyFont
.GetFontHeight() * GetOutDev()->mnDPIY
/ nOldDPIY
);
1474 aCopyFont
.SetAverageFontWidth( aCopyFont
.GetAverageFontWidth() * GetOutDev()->mnDPIX
/ nOldDPIX
);
1476 SetFont( aCopyFont
);
1477 SetTextColor( GetTextColor() );
1478 if( GetOutDev()->IsLineColor() )
1479 GetOutDev()->SetLineColor( GetOutDev()->GetLineColor() );
1481 GetOutDev()->SetLineColor();
1482 if( GetOutDev()->IsFillColor() )
1483 GetOutDev()->SetFillColor( GetOutDev()->GetFillColor() );
1485 GetOutDev()->SetFillColor();
1486 if( IsTextLineColor() )
1487 SetTextLineColor( GetTextLineColor() );
1490 if( IsOverlineColor() )
1491 SetOverlineColor( GetOverlineColor() );
1494 if( IsTextFillColor() )
1495 SetTextFillColor( GetTextFillColor() );
1498 SetTextAlign( GetTextAlign() );
1499 GetOutDev()->SetRasterOp( GetOutDev()->GetRasterOp() );
1500 if( GetOutDev()->IsRefPoint() )
1501 GetOutDev()->SetRefPoint( GetOutDev()->GetRefPoint() );
1503 GetOutDev()->SetRefPoint();
1504 GetOutDev()->SetLayoutMode( GetOutDev()->GetLayoutMode() );
1506 GetOutDev()->SetDigitLanguage( GetOutDev()->GetDigitLanguage() );
1507 tools::Rectangle
aPaintRect(Point(0, 0), GetOutputSizePixel());
1508 aClipRegion
.Intersect( aPaintRect
);
1509 GetOutDev()->SetClipRegion( aClipRegion
);
1511 // do the actual paint
1514 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip
) )
1516 Erase(*GetOutDev());
1519 Paint(*GetOutDev(), aPaintRect
);
1520 // put a pop action to metafile
1523 GetOutDev()->SetConnectMetaFile( pOldMtf
);
1524 GetOutDev()->EnableOutput( bOutput
);
1525 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1527 // paint metafile to VDev
1528 VclPtrInstance
<VirtualDevice
> pMaskedDevice(*i_pTargetOutDev
,
1529 DeviceFormat::WITH_ALPHA
);
1531 pMaskedDevice
->SetOutputSizePixel( GetOutputSizePixel(), true, true );
1532 pMaskedDevice
->EnableRTL( IsRTLEnabled() );
1534 aMtf
.Play(*pMaskedDevice
);
1535 BitmapEx
aBmpEx( pMaskedDevice
->GetBitmapEx( Point( 0, 0 ), aPaintRect
.GetSize() ) );
1536 i_pTargetOutDev
->DrawBitmapEx( i_rPos
, aBmpEx
);
1537 // get rid of virtual device now so they don't pile up during recursive calls
1538 pMaskedDevice
.disposeAndClear();
1540 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1542 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1544 tools::Long nDeltaX
= pChild
->GetOutDev()->mnOutOffX
- GetOutDev()->mnOutOffX
;
1546 if( pOutDev
->HasMirroredGraphics() )
1547 nDeltaX
= GetOutDev()->mnOutWidth
- nDeltaX
- pChild
->GetOutDev()->mnOutWidth
;
1548 tools::Long nDeltaY
= pChild
->GetOutOffYPixel() - GetOutOffYPixel();
1549 Point
aPos( i_rPos
);
1550 Point
aDelta( nDeltaX
, nDeltaY
);
1552 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1556 // restore graphics state
1559 GetOutDev()->EnableOutput( bOutput
);
1560 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1561 GetOutDev()->mbDevOutput
= bDevOutput
;
1562 GetOutDev()->mnDPIX
= nOldDPIX
;
1563 GetOutDev()->mnDPIY
= nOldDPIY
;
1566 void Window::PaintToDevice(OutputDevice
* pDev
, const Point
& rPos
)
1571 SAL_WARN_IF( pDev
->HasMirroredGraphics(), "vcl.window", "PaintToDevice to mirroring graphics" );
1572 SAL_WARN_IF( pDev
->IsRTLEnabled(), "vcl.window", "PaintToDevice to mirroring device" );
1574 vcl::Window
* pRealParent
= nullptr;
1575 if( ! mpWindowImpl
->mbVisible
)
1577 vcl::Window
* pTempParent
= ImplGetDefaultWindow();
1578 pTempParent
->EnableChildTransparentMode();
1579 pRealParent
= GetParent();
1580 SetParent( pTempParent
);
1581 // trigger correct visibility flags for children
1586 bool bVisible
= mpWindowImpl
->mbVisible
;
1587 mpWindowImpl
->mbVisible
= true;
1589 if( mpWindowImpl
->mpBorderWindow
)
1590 mpWindowImpl
->mpBorderWindow
->ImplPaintToDevice( pDev
, rPos
);
1592 ImplPaintToDevice( pDev
, rPos
);
1594 mpWindowImpl
->mbVisible
= bVisible
;
1597 SetParent( pRealParent
);
1600 void Window::Erase(vcl::RenderContext
& rRenderContext
)
1602 if (!GetOutDev()->IsDeviceOutputNecessary() || GetOutDev()->ImplIsRecordLayout())
1605 bool bNativeOK
= false;
1607 ControlPart aCtrlPart
= ImplGetWindowImpl()->mnNativeBackground
;
1609 if (aCtrlPart
== ControlPart::Entire
&& IsControlBackground())
1611 // nothing to do here; background is drawn in corresponding drawNativeControl implementation
1614 else if (aCtrlPart
!= ControlPart::NONE
&& ! IsControlBackground())
1616 tools::Rectangle
aCtrlRegion(Point(), GetOutputSizePixel());
1617 ControlState nState
= ControlState::NONE
;
1620 nState
|= ControlState::ENABLED
;
1622 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::WindowBackground
, aCtrlPart
, aCtrlRegion
,
1623 nState
, ImplControlValue(), OUString());
1626 if (GetOutDev()->mbBackground
&& !bNativeOK
)
1628 RasterOp eRasterOp
= GetOutDev()->GetRasterOp();
1629 if (eRasterOp
!= RasterOp::OverPaint
)
1630 GetOutDev()->SetRasterOp(RasterOp::OverPaint
);
1631 rRenderContext
.DrawWallpaper(0, 0, GetOutDev()->mnOutWidth
, GetOutDev()->mnOutHeight
, GetOutDev()->maBackground
);
1632 if (eRasterOp
!= RasterOp::OverPaint
)
1633 rRenderContext
.SetRasterOp(eRasterOp
);
1636 if (GetOutDev()->mpAlphaVDev
)
1637 GetOutDev()->mpAlphaVDev
->Erase();
1640 void Window::ImplScroll( const tools::Rectangle
& rRect
,
1641 tools::Long nHorzScroll
, tools::Long nVertScroll
, ScrollFlags nFlags
)
1643 if ( !GetOutDev()->IsDeviceOutputNecessary() )
1646 nHorzScroll
= GetOutDev()->ImplLogicWidthToDevicePixel( nHorzScroll
);
1647 nVertScroll
= GetOutDev()->ImplLogicHeightToDevicePixel( nVertScroll
);
1649 if ( !nHorzScroll
&& !nVertScroll
)
1652 // There will be no CopyArea() call below, so invalidate the whole visible
1653 // area, not only the smaller one that was just scrolled in.
1654 // Do this when we have a double buffer anyway, or (tdf#152094) the device has a map mode enabled which
1655 // makes the conversion to pixel inaccurate
1656 const bool bCopyExistingAreaAndElideInvalidate
= !SupportsDoubleBuffering() && !GetOutDev()->IsMapModeEnabled();
1658 if ( mpWindowImpl
->mpCursor
)
1659 mpWindowImpl
->mpCursor
->ImplSuspend();
1661 ScrollFlags nOrgFlags
= nFlags
;
1662 if ( !(nFlags
& (ScrollFlags::Children
| ScrollFlags::NoChildren
)) )
1664 if ( GetStyle() & WB_CLIPCHILDREN
)
1665 nFlags
|= ScrollFlags::NoChildren
;
1667 nFlags
|= ScrollFlags::Children
;
1670 vcl::Region aInvalidateRegion
;
1671 bool bScrollChildren(nFlags
& ScrollFlags::Children
);
1673 if ( !mpWindowImpl
->mpFirstChild
)
1674 bScrollChildren
= false;
1676 OutputDevice
*pOutDev
= GetOutDev();
1678 // RTL: check if this window requires special action
1679 bool bReMirror
= GetOutDev()->ImplIsAntiparallel();
1681 tools::Rectangle
aRectMirror( rRect
);
1684 // make sure the invalidate region of this window is
1685 // computed in the same coordinate space as the one from the overlap windows
1686 pOutDev
->ReMirror( aRectMirror
);
1689 // adapt paint areas
1690 ImplMoveAllInvalidateRegions( aRectMirror
, nHorzScroll
, nVertScroll
, bScrollChildren
);
1692 ImplCalcOverlapRegion( aRectMirror
, aInvalidateRegion
, !bScrollChildren
, false );
1694 // if the scrolling on the device is performed in the opposite direction
1695 // then move the overlaps in that direction to compute the invalidate region
1696 // on the correct side, i.e., revert nHorzScroll
1697 if (!aInvalidateRegion
.IsEmpty())
1699 aInvalidateRegion
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1702 tools::Rectangle
aDestRect(aRectMirror
);
1703 aDestRect
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1704 vcl::Region
aWinInvalidateRegion(aRectMirror
);
1705 if (bCopyExistingAreaAndElideInvalidate
)
1706 aWinInvalidateRegion
.Exclude(aDestRect
);
1708 aInvalidateRegion
.Union(aWinInvalidateRegion
);
1710 vcl::Region
aRegion( GetOutputRectPixel() );
1711 if ( nFlags
& ScrollFlags::Clip
)
1712 aRegion
.Intersect( rRect
);
1713 if ( mpWindowImpl
->mbWinRegion
)
1714 aRegion
.Intersect( GetOutDev()->ImplPixelToDevicePixel( mpWindowImpl
->maWinRegion
) );
1716 aRegion
.Exclude( aInvalidateRegion
);
1718 ImplClipBoundaries( aRegion
, false, true );
1719 if ( !bScrollChildren
)
1721 if ( nOrgFlags
& ScrollFlags::NoChildren
)
1722 ImplClipAllChildren( aRegion
);
1724 ImplClipChildren( aRegion
);
1726 if ( GetOutDev()->mbClipRegion
&& (nFlags
& ScrollFlags::UseClipRegion
) )
1727 aRegion
.Intersect( GetOutDev()->maRegion
);
1728 if ( !aRegion
.IsEmpty() )
1730 if ( mpWindowImpl
->mpWinData
)
1732 if ( mpWindowImpl
->mbFocusVisible
)
1733 ImplInvertFocus( *mpWindowImpl
->mpWinData
->mpFocusRect
);
1734 if ( mpWindowImpl
->mbTrackVisible
&& (mpWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
1735 InvertTracking( *mpWindowImpl
->mpWinData
->mpTrackRect
, mpWindowImpl
->mpWinData
->mnTrackFlags
);
1738 // This seems completely unnecessary with tiled rendering, and
1739 // causes the "AquaSalGraphics::copyArea() for non-layered
1740 // graphics" message. Presumably we should bypass this on all
1741 // platforms when dealing with a "window" that uses tiled
1742 // rendering at the moment. Unclear how to figure that out,
1743 // though. Also unclear whether we actually could just not
1744 // create a "frame window", whatever that exactly is, in the
1745 // tiled rendering case, or at least for platforms where tiles
1746 // rendering is all there is.
1748 SalGraphics
* pGraphics
= ImplGetFrameGraphics();
1749 // The invalidation area contains the area what would be copied here,
1750 // so avoid copying in case of double buffering.
1751 if (pGraphics
&& bCopyExistingAreaAndElideInvalidate
)
1755 pOutDev
->ReMirror( aRegion
);
1758 pOutDev
->SelectClipRegion( aRegion
, pGraphics
);
1759 pGraphics
->CopyArea( rRect
.Left()+nHorzScroll
, rRect
.Top()+nVertScroll
,
1760 rRect
.Left(), rRect
.Top(),
1761 rRect
.GetWidth(), rRect
.GetHeight(),
1765 if ( mpWindowImpl
->mpWinData
)
1767 if ( mpWindowImpl
->mbFocusVisible
)
1768 ImplInvertFocus( *mpWindowImpl
->mpWinData
->mpFocusRect
);
1769 if ( mpWindowImpl
->mbTrackVisible
&& (mpWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
1770 InvertTracking( *mpWindowImpl
->mpWinData
->mpTrackRect
, mpWindowImpl
->mpWinData
->mnTrackFlags
);
1774 if ( !aInvalidateRegion
.IsEmpty() )
1776 // RTL: the invalidate region for this windows is already computed in frame coordinates
1777 // so it has to be re-mirrored before calling the Paint-handler
1778 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::CheckRtl
;
1780 if ( !bScrollChildren
)
1782 if ( nOrgFlags
& ScrollFlags::NoChildren
)
1783 ImplClipAllChildren( aInvalidateRegion
);
1785 ImplClipChildren( aInvalidateRegion
);
1787 ImplInvalidateFrameRegion( &aInvalidateRegion
, InvalidateFlags::Children
);
1790 if ( bScrollChildren
)
1792 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstChild
;
1795 Point aPos
= pWindow
->GetPosPixel();
1796 aPos
+= Point( nHorzScroll
, nVertScroll
);
1797 pWindow
->SetPosPixel( aPos
);
1799 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
1803 if ( nFlags
& ScrollFlags::Update
)
1806 if ( mpWindowImpl
->mpCursor
)
1807 mpWindowImpl
->mpCursor
->ImplResume();
1810 } /* namespace vcl */
1813 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */