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 void Window::PixelInvalidate(const tools::Rectangle
* pRectangle
)
1203 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1206 Size aSize
= GetSizePixel();
1207 if (aSize
.IsEmpty())
1210 if (const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
1212 // In case we are routing the window, notify the client
1213 std::vector
<vcl::LOKPayloadItem
> aPayload
;
1214 tools::Rectangle
aRect(Point(0, 0), aSize
);
1216 aRect
= *pRectangle
;
1218 if (IsRTLEnabled() && GetOutDev() && !GetOutDev()->ImplIsAntiparallel())
1219 GetOutDev()->ReMirror(aRect
);
1221 aPayload
.emplace_back("rectangle", aRect
.toString());
1223 pNotifier
->notifyWindow(GetLOKWindowId(), "invalidate", aPayload
);
1225 // Added for dialog items. Pass invalidation to the parent window.
1226 else if (VclPtr
<vcl::Window
> pParent
= GetParentWithLOKNotifier())
1228 const tools::Rectangle
aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1229 pParent
->PixelInvalidate(&aRect
);
1233 void Window::Validate()
1235 if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth
|| !GetOutDev()->mnOutHeight
) )
1241 bool Window::HasPaintEvent() const
1244 if ( !mpWindowImpl
->mbReallyVisible
)
1247 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1250 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::Paint
)
1253 if ( !ImplIsOverlapWindow() )
1255 const vcl::Window
* pTempWindow
= this;
1258 pTempWindow
= pTempWindow
->ImplGetParent();
1259 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::PaintChildren
| ImplPaintFlags::PaintAllChildren
) )
1262 while ( !pTempWindow
->ImplIsOverlapWindow() );
1268 void Window::PaintImmediately()
1273 if ( mpWindowImpl
->mpBorderWindow
)
1275 mpWindowImpl
->mpBorderWindow
->PaintImmediately();
1279 if ( !mpWindowImpl
->mbReallyVisible
)
1282 bool bFlush
= false;
1283 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1285 Point
aPoint( 0, 0 );
1286 vcl::Region
aRegion( tools::Rectangle( aPoint
, GetOutputSizePixel() ) );
1287 ImplInvalidateOverlapFrameRegion( aRegion
);
1288 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
1292 // First we should skip all windows which are Paint-Transparent
1293 vcl::Window
* pUpdateWindow
= this;
1294 vcl::Window
* pWindow
= pUpdateWindow
;
1295 while ( !pWindow
->ImplIsOverlapWindow() )
1297 if ( !pWindow
->mpWindowImpl
->mbPaintTransparent
)
1299 pUpdateWindow
= pWindow
;
1302 pWindow
= pWindow
->ImplGetParent();
1304 // In order to limit drawing, an update only draws the window which
1305 // has PAINTALLCHILDREN set
1306 pWindow
= pUpdateWindow
;
1309 if ( pWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
1310 pUpdateWindow
= pWindow
;
1311 if ( pWindow
->ImplIsOverlapWindow() )
1313 pWindow
= pWindow
->ImplGetParent();
1317 // if there is something to paint, trigger a Paint
1318 if ( pUpdateWindow
->mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintChildren
) )
1320 VclPtr
<vcl::Window
> xWindow(this);
1322 // trigger an update also for system windows on top of us,
1323 // otherwise holes would remain
1324 vcl::Window
* pUpdateOverlapWindow
= ImplGetFirstOverlapWindow();
1325 if (pUpdateOverlapWindow
->mpWindowImpl
)
1326 pUpdateOverlapWindow
= pUpdateOverlapWindow
->mpWindowImpl
->mpFirstOverlap
;
1328 pUpdateOverlapWindow
= nullptr;
1329 while ( pUpdateOverlapWindow
)
1331 pUpdateOverlapWindow
->PaintImmediately();
1332 pUpdateOverlapWindow
= pUpdateOverlapWindow
->mpWindowImpl
->mpNext
;
1335 pUpdateWindow
->ImplCallPaint(nullptr, pUpdateWindow
->mpWindowImpl
->mnPaintFlags
);
1337 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow
->GetParentDialog())
1338 pUpdateWindow
->LogicInvalidate(nullptr);
1340 if (xWindow
->isDisposed())
1347 GetOutDev()->Flush();
1350 void Window::ImplPaintToDevice( OutputDevice
* i_pTargetOutDev
, const Point
& i_rPos
)
1352 // Special drawing when called through LOKit
1353 // TODO: Move to its own method
1354 if (comphelper::LibreOfficeKit::isActive())
1356 VclPtrInstance
<VirtualDevice
> pDevice(*i_pTargetOutDev
);
1357 pDevice
->EnableRTL(IsRTLEnabled());
1359 Size
aSize(GetOutputSizePixel());
1360 pDevice
->SetOutputSizePixel(aSize
);
1362 vcl::Font aCopyFont
= GetFont();
1363 pDevice
->SetFont(aCopyFont
);
1365 pDevice
->SetTextColor(GetTextColor());
1366 if (GetOutDev()->IsLineColor())
1367 pDevice
->SetLineColor(GetOutDev()->GetLineColor());
1369 pDevice
->SetLineColor();
1371 if (GetOutDev()->IsFillColor())
1372 pDevice
->SetFillColor(GetOutDev()->GetFillColor());
1374 pDevice
->SetFillColor();
1376 if (IsTextLineColor())
1377 pDevice
->SetTextLineColor(GetTextLineColor());
1379 pDevice
->SetTextLineColor();
1381 if (IsOverlineColor())
1382 pDevice
->SetOverlineColor(GetOverlineColor());
1384 pDevice
->SetOverlineColor();
1386 if (IsTextFillColor())
1387 pDevice
->SetTextFillColor(GetTextFillColor());
1389 pDevice
->SetTextFillColor();
1391 pDevice
->SetTextAlign(GetTextAlign());
1392 pDevice
->SetRasterOp(GetOutDev()->GetRasterOp());
1394 tools::Rectangle
aPaintRect(Point(), GetOutputSizePixel());
1396 vcl::Region
aClipRegion(GetOutDev()->GetClipRegion());
1397 pDevice
->SetClipRegion();
1398 aClipRegion
.Intersect(aPaintRect
);
1399 pDevice
->SetClipRegion(aClipRegion
);
1401 if (!IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip
))
1404 pDevice
->SetMapMode(GetMapMode());
1406 Paint(*pDevice
, tools::Rectangle(Point(), GetOutputSizePixel()));
1408 i_pTargetOutDev
->DrawOutDev(i_rPos
, aSize
, Point(), pDevice
->PixelToLogic(aSize
), *pDevice
);
1410 bool bHasMirroredGraphics
= pDevice
->HasMirroredGraphics();
1412 // get rid of virtual device now so they don't pile up during recursive calls
1413 pDevice
.disposeAndClear();
1416 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1418 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1420 tools::Long nDeltaX
= pChild
->GetOutDev()->mnOutOffX
- GetOutDev()->mnOutOffX
;
1421 if( bHasMirroredGraphics
)
1422 nDeltaX
= GetOutDev()->mnOutWidth
- nDeltaX
- pChild
->GetOutDev()->mnOutWidth
;
1424 tools::Long nDeltaY
= pChild
->GetOutOffYPixel() - GetOutOffYPixel();
1426 Point
aPos( i_rPos
);
1427 aPos
+= Point(nDeltaX
, nDeltaY
);
1429 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1436 bool bRVisible
= mpWindowImpl
->mbReallyVisible
;
1437 mpWindowImpl
->mbReallyVisible
= mpWindowImpl
->mbVisible
;
1438 bool bDevOutput
= GetOutDev()->mbDevOutput
;
1439 GetOutDev()->mbDevOutput
= true;
1441 const OutputDevice
*pOutDev
= GetOutDev();
1442 tools::Long nOldDPIX
= pOutDev
->GetDPIX();
1443 tools::Long nOldDPIY
= pOutDev
->GetDPIY();
1444 GetOutDev()->mnDPIX
= i_pTargetOutDev
->GetDPIX();
1445 GetOutDev()->mnDPIY
= i_pTargetOutDev
->GetDPIY();
1446 bool bOutput
= GetOutDev()->IsOutputEnabled();
1447 GetOutDev()->EnableOutput();
1449 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel
, "vcl.window", "MapMode must be PIXEL based" );
1450 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel
)
1453 // preserve graphicsstate
1454 GetOutDev()->Push();
1455 vcl::Region
aClipRegion( GetOutDev()->GetClipRegion() );
1456 GetOutDev()->SetClipRegion();
1458 GDIMetaFile
* pOldMtf
= GetOutDev()->GetConnectMetaFile();
1460 GetOutDev()->SetConnectMetaFile( &aMtf
);
1462 // put a push action to metafile
1463 GetOutDev()->Push();
1464 // copy graphics state to metafile
1465 vcl::Font aCopyFont
= GetFont();
1466 if( nOldDPIX
!= GetOutDev()->mnDPIX
|| nOldDPIY
!= GetOutDev()->mnDPIY
)
1468 aCopyFont
.SetFontHeight( aCopyFont
.GetFontHeight() * GetOutDev()->mnDPIY
/ nOldDPIY
);
1469 aCopyFont
.SetAverageFontWidth( aCopyFont
.GetAverageFontWidth() * GetOutDev()->mnDPIX
/ nOldDPIX
);
1471 SetFont( aCopyFont
);
1472 SetTextColor( GetTextColor() );
1473 if( GetOutDev()->IsLineColor() )
1474 GetOutDev()->SetLineColor( GetOutDev()->GetLineColor() );
1476 GetOutDev()->SetLineColor();
1477 if( GetOutDev()->IsFillColor() )
1478 GetOutDev()->SetFillColor( GetOutDev()->GetFillColor() );
1480 GetOutDev()->SetFillColor();
1481 if( IsTextLineColor() )
1482 SetTextLineColor( GetTextLineColor() );
1485 if( IsOverlineColor() )
1486 SetOverlineColor( GetOverlineColor() );
1489 if( IsTextFillColor() )
1490 SetTextFillColor( GetTextFillColor() );
1493 SetTextAlign( GetTextAlign() );
1494 GetOutDev()->SetRasterOp( GetOutDev()->GetRasterOp() );
1495 if( GetOutDev()->IsRefPoint() )
1496 GetOutDev()->SetRefPoint( GetOutDev()->GetRefPoint() );
1498 GetOutDev()->SetRefPoint();
1499 GetOutDev()->SetLayoutMode( GetOutDev()->GetLayoutMode() );
1501 GetOutDev()->SetDigitLanguage( GetOutDev()->GetDigitLanguage() );
1502 tools::Rectangle
aPaintRect(Point(0, 0), GetOutputSizePixel());
1503 aClipRegion
.Intersect( aPaintRect
);
1504 GetOutDev()->SetClipRegion( aClipRegion
);
1506 // do the actual paint
1509 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip
) )
1511 Erase(*GetOutDev());
1514 Paint(*GetOutDev(), aPaintRect
);
1515 // put a pop action to metafile
1518 GetOutDev()->SetConnectMetaFile( pOldMtf
);
1519 GetOutDev()->EnableOutput( bOutput
);
1520 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1522 // paint metafile to VDev
1523 VclPtrInstance
<VirtualDevice
> pMaskedDevice(*i_pTargetOutDev
,
1524 DeviceFormat::WITH_ALPHA
);
1526 pMaskedDevice
->SetOutputSizePixel( GetOutputSizePixel() );
1527 pMaskedDevice
->EnableRTL( IsRTLEnabled() );
1529 aMtf
.Play(*pMaskedDevice
);
1530 BitmapEx
aBmpEx( pMaskedDevice
->GetBitmapEx( Point( 0, 0 ), aPaintRect
.GetSize() ) );
1531 i_pTargetOutDev
->DrawBitmapEx( i_rPos
, aBmpEx
);
1532 // get rid of virtual device now so they don't pile up during recursive calls
1533 pMaskedDevice
.disposeAndClear();
1535 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1537 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1539 tools::Long nDeltaX
= pChild
->GetOutDev()->mnOutOffX
- GetOutDev()->mnOutOffX
;
1541 if( pOutDev
->HasMirroredGraphics() )
1542 nDeltaX
= GetOutDev()->mnOutWidth
- nDeltaX
- pChild
->GetOutDev()->mnOutWidth
;
1543 tools::Long nDeltaY
= pChild
->GetOutOffYPixel() - GetOutOffYPixel();
1544 Point
aPos( i_rPos
);
1545 Point
aDelta( nDeltaX
, nDeltaY
);
1547 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1551 // restore graphics state
1554 GetOutDev()->EnableOutput( bOutput
);
1555 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1556 GetOutDev()->mbDevOutput
= bDevOutput
;
1557 GetOutDev()->mnDPIX
= nOldDPIX
;
1558 GetOutDev()->mnDPIY
= nOldDPIY
;
1561 void Window::PaintToDevice(OutputDevice
* pDev
, const Point
& rPos
)
1566 SAL_WARN_IF( pDev
->HasMirroredGraphics(), "vcl.window", "PaintToDevice to mirroring graphics" );
1567 SAL_WARN_IF( pDev
->IsRTLEnabled(), "vcl.window", "PaintToDevice to mirroring device" );
1569 vcl::Window
* pRealParent
= nullptr;
1570 if( ! mpWindowImpl
->mbVisible
)
1572 vcl::Window
* pTempParent
= ImplGetDefaultWindow();
1573 pTempParent
->EnableChildTransparentMode();
1574 pRealParent
= GetParent();
1575 SetParent( pTempParent
);
1576 // trigger correct visibility flags for children
1581 bool bVisible
= mpWindowImpl
->mbVisible
;
1582 mpWindowImpl
->mbVisible
= true;
1584 if( mpWindowImpl
->mpBorderWindow
)
1585 mpWindowImpl
->mpBorderWindow
->ImplPaintToDevice( pDev
, rPos
);
1587 ImplPaintToDevice( pDev
, rPos
);
1589 mpWindowImpl
->mbVisible
= bVisible
;
1592 SetParent( pRealParent
);
1595 void Window::Erase(vcl::RenderContext
& rRenderContext
)
1597 if (!GetOutDev()->IsDeviceOutputNecessary() || GetOutDev()->ImplIsRecordLayout())
1600 bool bNativeOK
= false;
1602 ControlPart aCtrlPart
= ImplGetWindowImpl()->mnNativeBackground
;
1604 if (aCtrlPart
== ControlPart::Entire
&& IsControlBackground())
1606 // nothing to do here; background is drawn in corresponding drawNativeControl implementation
1609 else if (aCtrlPart
!= ControlPart::NONE
&& ! IsControlBackground())
1611 tools::Rectangle
aCtrlRegion(Point(), GetOutputSizePixel());
1612 ControlState nState
= ControlState::NONE
;
1615 nState
|= ControlState::ENABLED
;
1617 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::WindowBackground
, aCtrlPart
, aCtrlRegion
,
1618 nState
, ImplControlValue(), OUString());
1621 if (GetOutDev()->mbBackground
&& !bNativeOK
)
1623 RasterOp eRasterOp
= GetOutDev()->GetRasterOp();
1624 if (eRasterOp
!= RasterOp::OverPaint
)
1625 GetOutDev()->SetRasterOp(RasterOp::OverPaint
);
1626 rRenderContext
.DrawWallpaper(0, 0, GetOutDev()->mnOutWidth
, GetOutDev()->mnOutHeight
, GetOutDev()->maBackground
);
1627 if (eRasterOp
!= RasterOp::OverPaint
)
1628 rRenderContext
.SetRasterOp(eRasterOp
);
1631 if (GetOutDev()->mpAlphaVDev
)
1632 GetOutDev()->mpAlphaVDev
->Erase();
1635 void Window::ImplScroll( const tools::Rectangle
& rRect
,
1636 tools::Long nHorzScroll
, tools::Long nVertScroll
, ScrollFlags nFlags
)
1638 if ( !GetOutDev()->IsDeviceOutputNecessary() )
1641 nHorzScroll
= GetOutDev()->ImplLogicWidthToDevicePixel( nHorzScroll
);
1642 nVertScroll
= GetOutDev()->ImplLogicHeightToDevicePixel( nVertScroll
);
1644 if ( !nHorzScroll
&& !nVertScroll
)
1647 // There will be no CopyArea() call below, so invalidate the whole visible
1648 // area, not only the smaller one that was just scrolled in.
1649 // Do this when we have a double buffer anyway, or (tdf#152094) the device has a map mode enabled which
1650 // makes the conversion to pixel inaccurate
1651 const bool bCopyExistingAreaAndElideInvalidate
= !SupportsDoubleBuffering() && !GetOutDev()->IsMapModeEnabled();
1653 if ( mpWindowImpl
->mpCursor
)
1654 mpWindowImpl
->mpCursor
->ImplSuspend();
1656 ScrollFlags nOrgFlags
= nFlags
;
1657 if ( !(nFlags
& (ScrollFlags::Children
| ScrollFlags::NoChildren
)) )
1659 if ( GetStyle() & WB_CLIPCHILDREN
)
1660 nFlags
|= ScrollFlags::NoChildren
;
1662 nFlags
|= ScrollFlags::Children
;
1665 vcl::Region aInvalidateRegion
;
1666 bool bScrollChildren(nFlags
& ScrollFlags::Children
);
1668 if ( !mpWindowImpl
->mpFirstChild
)
1669 bScrollChildren
= false;
1671 OutputDevice
*pOutDev
= GetOutDev();
1673 // RTL: check if this window requires special action
1674 bool bReMirror
= GetOutDev()->ImplIsAntiparallel();
1676 tools::Rectangle
aRectMirror( rRect
);
1679 // make sure the invalidate region of this window is
1680 // computed in the same coordinate space as the one from the overlap windows
1681 pOutDev
->ReMirror( aRectMirror
);
1684 // adapt paint areas
1685 ImplMoveAllInvalidateRegions( aRectMirror
, nHorzScroll
, nVertScroll
, bScrollChildren
);
1687 ImplCalcOverlapRegion( aRectMirror
, aInvalidateRegion
, !bScrollChildren
, false );
1689 // if the scrolling on the device is performed in the opposite direction
1690 // then move the overlaps in that direction to compute the invalidate region
1691 // on the correct side, i.e., revert nHorzScroll
1692 if (!aInvalidateRegion
.IsEmpty())
1694 aInvalidateRegion
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1697 tools::Rectangle
aDestRect(aRectMirror
);
1698 aDestRect
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1699 vcl::Region
aWinInvalidateRegion(aRectMirror
);
1700 if (bCopyExistingAreaAndElideInvalidate
)
1701 aWinInvalidateRegion
.Exclude(aDestRect
);
1703 aInvalidateRegion
.Union(aWinInvalidateRegion
);
1705 vcl::Region
aRegion( GetOutputRectPixel() );
1706 if ( nFlags
& ScrollFlags::Clip
)
1707 aRegion
.Intersect( rRect
);
1708 if ( mpWindowImpl
->mbWinRegion
)
1709 aRegion
.Intersect( GetOutDev()->ImplPixelToDevicePixel( mpWindowImpl
->maWinRegion
) );
1711 aRegion
.Exclude( aInvalidateRegion
);
1713 ImplClipBoundaries( aRegion
, false, true );
1714 if ( !bScrollChildren
)
1716 if ( nOrgFlags
& ScrollFlags::NoChildren
)
1717 ImplClipAllChildren( aRegion
);
1719 ImplClipChildren( aRegion
);
1721 if ( GetOutDev()->mbClipRegion
&& (nFlags
& ScrollFlags::UseClipRegion
) )
1722 aRegion
.Intersect( GetOutDev()->maRegion
);
1723 if ( !aRegion
.IsEmpty() )
1725 if ( mpWindowImpl
->mpWinData
)
1727 if ( mpWindowImpl
->mbFocusVisible
)
1728 ImplInvertFocus( *mpWindowImpl
->mpWinData
->mpFocusRect
);
1729 if ( mpWindowImpl
->mbTrackVisible
&& (mpWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
1730 InvertTracking( *mpWindowImpl
->mpWinData
->mpTrackRect
, mpWindowImpl
->mpWinData
->mnTrackFlags
);
1733 // This seems completely unnecessary with tiled rendering, and
1734 // causes the "AquaSalGraphics::copyArea() for non-layered
1735 // graphics" message. Presumably we should bypass this on all
1736 // platforms when dealing with a "window" that uses tiled
1737 // rendering at the moment. Unclear how to figure that out,
1738 // though. Also unclear whether we actually could just not
1739 // create a "frame window", whatever that exactly is, in the
1740 // tiled rendering case, or at least for platforms where tiles
1741 // rendering is all there is.
1743 SalGraphics
* pGraphics
= ImplGetFrameGraphics();
1744 // The invalidation area contains the area what would be copied here,
1745 // so avoid copying in case of double buffering.
1746 if (pGraphics
&& bCopyExistingAreaAndElideInvalidate
)
1750 pOutDev
->ReMirror( aRegion
);
1753 pOutDev
->SelectClipRegion( aRegion
, pGraphics
);
1754 pGraphics
->CopyArea( rRect
.Left()+nHorzScroll
, rRect
.Top()+nVertScroll
,
1755 rRect
.Left(), rRect
.Top(),
1756 rRect
.GetWidth(), rRect
.GetHeight(),
1760 if ( mpWindowImpl
->mpWinData
)
1762 if ( mpWindowImpl
->mbFocusVisible
)
1763 ImplInvertFocus( *mpWindowImpl
->mpWinData
->mpFocusRect
);
1764 if ( mpWindowImpl
->mbTrackVisible
&& (mpWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
1765 InvertTracking( *mpWindowImpl
->mpWinData
->mpTrackRect
, mpWindowImpl
->mpWinData
->mnTrackFlags
);
1769 if ( !aInvalidateRegion
.IsEmpty() )
1771 // RTL: the invalidate region for this windows is already computed in frame coordinates
1772 // so it has to be re-mirrored before calling the Paint-handler
1773 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::CheckRtl
;
1775 if ( !bScrollChildren
)
1777 if ( nOrgFlags
& ScrollFlags::NoChildren
)
1778 ImplClipAllChildren( aInvalidateRegion
);
1780 ImplClipChildren( aInvalidateRegion
);
1782 ImplInvalidateFrameRegion( &aInvalidateRegion
, InvalidateFlags::Children
);
1785 if ( bScrollChildren
)
1787 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstChild
;
1790 Point aPos
= pWindow
->GetPosPixel();
1791 aPos
+= Point( nHorzScroll
, nVertScroll
);
1792 pWindow
->SetPosPixel( aPos
);
1794 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
1798 if ( nFlags
& ScrollFlags::Update
)
1801 if ( mpWindowImpl
->mpCursor
)
1802 mpWindowImpl
->mpCursor
->ImplResume();
1805 } /* namespace vcl */
1808 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */