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 PushFlags nFlags
= PushFlags::NONE
;
69 nFlags
|= PushFlags::CLIPREGION
;
70 nFlags
|= PushFlags::FILLCOLOR
;
71 nFlags
|= PushFlags::FONT
;
72 nFlags
|= PushFlags::LINECOLOR
;
73 nFlags
|= PushFlags::MAPMODE
;
74 maSettings
= pFrameData
->mpBuffer
->GetSettings();
75 nFlags
|= PushFlags::REFPOINT
;
76 nFlags
|= PushFlags::TEXTCOLOR
;
77 nFlags
|= PushFlags::TEXTLINECOLOR
;
78 nFlags
|= PushFlags::OVERLINECOLOR
;
79 nFlags
|= PushFlags::TEXTFILLCOLOR
;
80 nFlags
|= PushFlags::TEXTALIGN
;
81 nFlags
|= PushFlags::RASTEROP
;
82 nFlags
|= PushFlags::TEXTLAYOUTMODE
;
83 nFlags
|= PushFlags::TEXTLANGUAGE
;
84 pFrameData
->mpBuffer
->Push(nFlags
);
85 pFrameData
->mpBuffer
->SetClipRegion(pWindow
->GetClipRegion());
86 pFrameData
->mpBuffer
->SetFillColor(pWindow
->GetFillColor());
87 pFrameData
->mpBuffer
->SetFont(pWindow
->GetFont());
88 pFrameData
->mpBuffer
->SetLineColor(pWindow
->GetLineColor());
89 pFrameData
->mpBuffer
->SetMapMode(pWindow
->GetMapMode());
90 pFrameData
->mpBuffer
->SetRefPoint(pWindow
->GetRefPoint());
91 pFrameData
->mpBuffer
->SetSettings(pWindow
->GetSettings());
92 pFrameData
->mpBuffer
->SetTextColor(pWindow
->GetTextColor());
93 pFrameData
->mpBuffer
->SetTextLineColor(pWindow
->GetTextLineColor());
94 pFrameData
->mpBuffer
->SetOverlineColor(pWindow
->GetOverlineColor());
95 pFrameData
->mpBuffer
->SetTextFillColor(pWindow
->GetTextFillColor());
96 pFrameData
->mpBuffer
->SetTextAlign(pWindow
->GetTextAlign());
97 pFrameData
->mpBuffer
->SetRasterOp(pWindow
->GetRasterOp());
98 pFrameData
->mpBuffer
->SetLayoutMode(pWindow
->GetLayoutMode());
99 pFrameData
->mpBuffer
->SetDigitLanguage(pWindow
->GetDigitLanguage());
101 mnOutOffX
= pFrameData
->mpBuffer
->GetOutOffXPixel();
102 mnOutOffY
= pFrameData
->mpBuffer
->GetOutOffYPixel();
103 pFrameData
->mpBuffer
->SetOutOffXPixel(pWindow
->GetOutOffXPixel());
104 pFrameData
->mpBuffer
->SetOutOffYPixel(pWindow
->GetOutOffYPixel());
105 pFrameData
->mpBuffer
->EnableRTL(pWindow
->IsRTLEnabled());
108 PaintBufferGuard::~PaintBufferGuard()
110 if (!mpFrameData
->mpBuffer
)
113 if (!m_aPaintRect
.IsEmpty())
115 // copy the buffer content to the actual window
116 // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are
117 // painting directly instead of using Invalidate()
118 // [ie. everything you can see was painted directly to the
119 // window either above or in eg. an event handler]
120 if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT"))
122 // Make sure that the +1 value GetSize() adds to the size is in pixels.
124 if (m_pWindow
->GetMapMode().GetMapUnit() == MapUnit::MapPixel
)
126 aPaintRectSize
= m_aPaintRect
.GetSize();
130 tools::Rectangle aRectanglePixel
= m_pWindow
->LogicToPixel(m_aPaintRect
);
131 aPaintRectSize
= m_pWindow
->PixelToLogic(aRectanglePixel
.GetSize());
134 m_pWindow
->DrawOutDev(m_aPaintRect
.TopLeft(), aPaintRectSize
, m_aPaintRect
.TopLeft(), aPaintRectSize
, *mpFrameData
->mpBuffer
);
138 // Restore buffer state.
139 mpFrameData
->mpBuffer
->SetOutOffXPixel(mnOutOffX
);
140 mpFrameData
->mpBuffer
->SetOutOffYPixel(mnOutOffY
);
142 mpFrameData
->mpBuffer
->Pop();
143 mpFrameData
->mpBuffer
->SetSettings(maSettings
);
145 mpFrameData
->mpBuffer
->SetBackground(maBackground
);
147 mpFrameData
->mpBuffer
->SetBackground();
150 void PaintBufferGuard::SetPaintRect(const tools::Rectangle
& rRectangle
)
152 m_aPaintRect
= rRectangle
;
155 vcl::RenderContext
* PaintBufferGuard::GetRenderContext()
157 if (mpFrameData
->mpBuffer
)
158 return mpFrameData
->mpBuffer
;
167 VclPtr
<vcl::Window
> m_pWindow
;
168 std::unique_ptr
<vcl::Region
> m_pChildRegion
;
169 tools::Rectangle m_aSelectionRect
;
170 tools::Rectangle m_aPaintRect
;
171 vcl::Region m_aPaintRegion
;
172 ImplPaintFlags m_nPaintFlags
;
174 bool m_bRestoreCursor
: 1;
175 bool m_bStartedBufferedPaint
: 1; ///< This PaintHelper started a buffered paint, and should paint it on the screen when being destructed.
177 PaintHelper(vcl::Window
* pWindow
, ImplPaintFlags nPaintFlags
);
182 void SetPaintRect(const tools::Rectangle
& rRect
)
184 m_aPaintRect
= rRect
;
186 void SetSelectionRect(const tools::Rectangle
& rRect
)
188 m_aSelectionRect
= rRect
;
190 void SetRestoreCursor(bool bRestoreCursor
)
192 m_bRestoreCursor
= bRestoreCursor
;
194 bool GetRestoreCursor() const
196 return m_bRestoreCursor
;
198 ImplPaintFlags
GetPaintFlags() const
200 return m_nPaintFlags
;
202 vcl::Region
& GetPaintRegion()
204 return m_aPaintRegion
;
206 void DoPaint(const vcl::Region
* pRegion
);
208 /// Start buffered paint: set it up to have the same settings as m_pWindow.
209 void StartBufferedPaint();
211 /// Paint the content of the buffer to the current m_pWindow.
217 PaintHelper::PaintHelper(vcl::Window
*pWindow
, ImplPaintFlags nPaintFlags
)
219 , m_nPaintFlags(nPaintFlags
)
221 , m_bRestoreCursor(false)
222 , m_bStartedBufferedPaint(false)
226 void PaintHelper::StartBufferedPaint()
228 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
229 assert(!pFrameData
->mbInBufferedPaint
);
231 pFrameData
->mbInBufferedPaint
= true;
232 pFrameData
->maBufferedRect
= tools::Rectangle();
233 m_bStartedBufferedPaint
= true;
236 void PaintHelper::PaintBuffer()
238 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
239 assert(pFrameData
->mbInBufferedPaint
);
240 assert(m_bStartedBufferedPaint
);
242 vcl::PaintBufferGuard
aGuard(pFrameData
, m_pWindow
);
243 aGuard
.SetPaintRect(pFrameData
->maBufferedRect
);
246 void PaintHelper::DoPaint(const vcl::Region
* pRegion
)
248 WindowImpl
* pWindowImpl
= m_pWindow
->ImplGetWindowImpl();
250 vcl::Region
* pWinChildClipRegion
= m_pWindow
->ImplGetWinChildClipRegion();
251 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
252 if (pWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
|| pFrameData
->mbInBufferedPaint
)
254 pWindowImpl
->maInvalidateRegion
= *pWinChildClipRegion
;
259 pWindowImpl
->maInvalidateRegion
.Union( *pRegion
);
261 if (pWindowImpl
->mpWinData
&& pWindowImpl
->mbTrackVisible
)
262 /* #98602# need to repaint all children within the
263 * tracking rectangle, so the following invert
264 * operation takes places without traces of the previous
267 pWindowImpl
->maInvalidateRegion
.Union(*pWindowImpl
->mpWinData
->mpTrackRect
);
269 if (pWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
270 m_pChildRegion
.reset( new vcl::Region(pWindowImpl
->maInvalidateRegion
) );
271 pWindowImpl
->maInvalidateRegion
.Intersect(*pWinChildClipRegion
);
273 pWindowImpl
->mnPaintFlags
= ImplPaintFlags::NONE
;
274 if (pWindowImpl
->maInvalidateRegion
.IsEmpty())
277 #if HAVE_FEATURE_OPENGL
278 VCL_GL_INFO("PaintHelper::DoPaint on " <<
279 typeid( *m_pWindow
).name() << " '" << m_pWindow
->GetText() << "' begin");
281 // double-buffering: setup the buffer if it does not exist
282 if (!pFrameData
->mbInBufferedPaint
&& m_pWindow
->SupportsDoubleBuffering())
283 StartBufferedPaint();
285 // double-buffering: if this window does not support double-buffering,
286 // but we are in the middle of double-buffered paint, we might be
287 // losing information
288 if (pFrameData
->mbInBufferedPaint
&& !m_pWindow
->SupportsDoubleBuffering())
289 SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow
.get()).name());
291 if (pFrameData
->mbInBufferedPaint
&& m_pWindow
->SupportsDoubleBuffering())
294 vcl::PaintBufferGuard
g(pFrameData
, m_pWindow
);
295 m_pWindow
->ApplySettings(*pFrameData
->mpBuffer
);
297 m_pWindow
->PushPaintHelper(this, *pFrameData
->mpBuffer
);
298 m_pWindow
->Paint(*pFrameData
->mpBuffer
, m_aPaintRect
);
299 pFrameData
->maBufferedRect
.Union(m_aPaintRect
);
304 Wallpaper aBackground
= m_pWindow
->GetBackground();
305 m_pWindow
->ApplySettings(*m_pWindow
);
306 // Restore bitmap background if it was lost.
307 if (aBackground
.IsBitmap() && !m_pWindow
->GetBackground().IsBitmap())
309 m_pWindow
->SetBackground(aBackground
);
311 m_pWindow
->PushPaintHelper(this, *m_pWindow
);
312 m_pWindow
->Paint(*m_pWindow
, m_aPaintRect
);
314 #if HAVE_FEATURE_OPENGL
315 VCL_GL_INFO("PaintHelper::DoPaint end on " <<
316 typeid( *m_pWindow
).name() << " '" << m_pWindow
->GetText() << "'");
323 void RenderTools::DrawSelectionBackground(vcl::RenderContext
& rRenderContext
, vcl::Window
const & rWindow
,
324 const tools::Rectangle
& rRect
, sal_uInt16 nHighlight
,
325 bool bChecked
, bool bDrawBorder
, bool bDrawExtBorderOnly
,
326 Color
* pSelectionTextColor
, tools::Long nCornerRadius
, Color
const * pPaintColor
)
331 bool bRoundEdges
= nCornerRadius
> 0;
333 const StyleSettings
& rStyles
= rRenderContext
.GetSettings().GetStyleSettings();
335 // colors used for item highlighting
336 Color
aSelectionBorderColor(pPaintColor
? *pPaintColor
: rStyles
.GetHighlightColor());
337 Color
aSelectionFillColor(aSelectionBorderColor
);
339 bool bDark
= rStyles
.GetFaceColor().IsDark();
340 bool bBright
= ( rStyles
.GetFaceColor() == COL_WHITE
);
342 int c1
= aSelectionBorderColor
.GetLuminance();
343 int c2
= rWindow
.GetBackgroundColor().GetLuminance();
345 if (!bDark
&& !bBright
&& std::abs(c2
- c1
) < (pPaintColor
? 40 : 75))
349 aSelectionFillColor
.RGBtoHSB( h
, s
, b
);
350 if( b
> 50 ) b
-= 40;
352 aSelectionFillColor
= Color::HSBtoRGB( h
, s
, b
);
353 aSelectionBorderColor
= aSelectionFillColor
;
358 if (aSelectionBorderColor
.IsDark())
359 aSelectionBorderColor
.IncreaseLuminance(128);
361 aSelectionBorderColor
.DecreaseLuminance(128);
364 tools::Rectangle
aRect(rRect
);
365 if (bDrawExtBorderOnly
)
367 aRect
.AdjustLeft( -1 );
368 aRect
.AdjustTop( -1 );
369 aRect
.AdjustRight(1 );
370 aRect
.AdjustBottom(1 );
372 rRenderContext
.Push(PushFlags::FILLCOLOR
| PushFlags::LINECOLOR
);
375 rRenderContext
.SetLineColor(bDark
? COL_WHITE
: (bBright
? COL_BLACK
: aSelectionBorderColor
));
377 rRenderContext
.SetLineColor();
379 sal_uInt16 nPercent
= 0;
383 aSelectionFillColor
= COL_BLACK
;
385 nPercent
= 80; // just checked (light)
389 if (bChecked
&& nHighlight
== 2)
392 aSelectionFillColor
= COL_LIGHTGRAY
;
395 aSelectionFillColor
= COL_BLACK
;
396 rRenderContext
.SetLineColor(COL_BLACK
);
400 nPercent
= bRoundEdges
? 40 : 20; // selected, pressed or checked ( very dark )
402 else if (bChecked
|| nHighlight
== 1)
405 aSelectionFillColor
= COL_GRAY
;
408 aSelectionFillColor
= COL_BLACK
;
409 rRenderContext
.SetLineColor(COL_BLACK
);
413 nPercent
= bRoundEdges
? 60 : 35; // selected, pressed or checked ( very dark )
418 aSelectionFillColor
= COL_LIGHTGRAY
;
421 aSelectionFillColor
= COL_BLACK
;
422 rRenderContext
.SetLineColor(COL_BLACK
);
429 nPercent
= 70; // selected ( dark )
433 if (bDark
&& bDrawExtBorderOnly
)
435 rRenderContext
.SetFillColor();
436 if (pSelectionTextColor
)
437 *pSelectionTextColor
= rStyles
.GetHighlightTextColor();
441 rRenderContext
.SetFillColor(aSelectionFillColor
);
442 if (pSelectionTextColor
)
444 Color aTextColor
= rWindow
.IsControlBackground() ? rWindow
.GetControlForeground() : rStyles
.GetButtonTextColor();
445 Color aHLTextColor
= rStyles
.GetHighlightTextColor();
446 int nTextDiff
= std::abs(aSelectionFillColor
.GetLuminance() - aTextColor
.GetLuminance());
447 int nHLDiff
= std::abs(aSelectionFillColor
.GetLuminance() - aHLTextColor
.GetLuminance());
448 *pSelectionTextColor
= (nHLDiff
>= nTextDiff
) ? aHLTextColor
: aTextColor
;
454 rRenderContext
.DrawRect(aRect
);
460 tools::Polygon
aPoly(aRect
, nCornerRadius
, nCornerRadius
);
461 tools::PolyPolygon
aPolyPoly(aPoly
);
462 rRenderContext
.DrawTransparent(aPolyPoly
, nPercent
);
466 tools::Polygon
aPoly(aRect
);
467 tools::PolyPolygon
aPolyPoly(aPoly
);
468 rRenderContext
.DrawTransparent(aPolyPoly
, nPercent
);
472 rRenderContext
.Pop(); // LINECOLOR | FILLCOLOR
475 void Window::PushPaintHelper(PaintHelper
*pHelper
, vcl::RenderContext
& rRenderContext
)
479 if ( mpWindowImpl
->mpCursor
)
480 pHelper
->SetRestoreCursor(mpWindowImpl
->mpCursor
->ImplSuspend());
482 mbInitClipRegion
= true;
483 mpWindowImpl
->mbInPaint
= true;
485 // restore Paint-Region
486 vcl::Region
&rPaintRegion
= pHelper
->GetPaintRegion();
487 rPaintRegion
= mpWindowImpl
->maInvalidateRegion
;
488 tools::Rectangle aPaintRect
= rPaintRegion
.GetBoundRect();
490 // RTL: re-mirror paint rect and region at this window
491 if (ImplIsAntiparallel())
493 rRenderContext
.ReMirror(aPaintRect
);
494 rRenderContext
.ReMirror(rPaintRegion
);
496 aPaintRect
= ImplDevicePixelToLogic(aPaintRect
);
497 mpWindowImpl
->mpPaintRegion
= &rPaintRegion
;
498 mpWindowImpl
->maInvalidateRegion
.SetEmpty();
500 if ((pHelper
->GetPaintFlags() & ImplPaintFlags::Erase
) && rRenderContext
.IsBackground())
502 if (rRenderContext
.IsClipRegion())
504 vcl::Region aOldRegion
= rRenderContext
.GetClipRegion();
505 rRenderContext
.SetClipRegion();
506 Erase(rRenderContext
);
507 rRenderContext
.SetClipRegion(aOldRegion
);
510 Erase(rRenderContext
);
513 // #98943# trigger drawing of toolbox selection after all children are painted
514 if (mpWindowImpl
->mbDrawSelectionBackground
)
515 pHelper
->SetSelectionRect(aPaintRect
);
516 pHelper
->SetPaintRect(aPaintRect
);
519 void Window::PopPaintHelper(PaintHelper
const *pHelper
)
521 if (mpWindowImpl
->mpWinData
)
523 if (mpWindowImpl
->mbFocusVisible
)
524 ImplInvertFocus(*mpWindowImpl
->mpWinData
->mpFocusRect
);
526 mpWindowImpl
->mbInPaint
= false;
527 mbInitClipRegion
= true;
528 mpWindowImpl
->mpPaintRegion
= nullptr;
529 if (mpWindowImpl
->mpCursor
)
530 mpWindowImpl
->mpCursor
->ImplResume(pHelper
->GetRestoreCursor());
533 } /* namespace vcl */
535 PaintHelper::~PaintHelper()
537 WindowImpl
* pWindowImpl
= m_pWindow
->ImplGetWindowImpl();
540 m_pWindow
->PopPaintHelper(this);
543 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
544 if ( m_nPaintFlags
& (ImplPaintFlags::PaintAllChildren
| ImplPaintFlags::PaintChildren
) )
546 // Paint from the bottom child window and frontward.
547 vcl::Window
* pTempWindow
= pWindowImpl
->mpLastChild
;
550 if (pTempWindow
->mpWindowImpl
->mbVisible
)
551 pTempWindow
->ImplCallPaint(m_pChildRegion
.get(), m_nPaintFlags
);
552 pTempWindow
= pTempWindow
->mpWindowImpl
->mpPrev
;
556 if ( pWindowImpl
->mpWinData
&& pWindowImpl
->mbTrackVisible
&& (pWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
557 /* #98602# need to invert the tracking rect AFTER
558 * the children have painted
560 m_pWindow
->InvertTracking( *pWindowImpl
->mpWinData
->mpTrackRect
, pWindowImpl
->mpWinData
->mnTrackFlags
);
562 // double-buffering: paint in case we created the buffer, the children are
563 // already painted inside
564 if (m_bStartedBufferedPaint
&& pFrameData
->mbInBufferedPaint
)
567 pFrameData
->mbInBufferedPaint
= false;
568 pFrameData
->maBufferedRect
= tools::Rectangle();
571 // #98943# draw toolbox selection
572 if( !m_aSelectionRect
.IsEmpty() )
573 m_pWindow
->DrawSelectionBackground( m_aSelectionRect
, 3, false, true );
578 void Window::ImplCallPaint(const vcl::Region
* pRegion
, ImplPaintFlags nPaintFlags
)
580 // call PrePaint. PrePaint may add to the invalidate region as well as
581 // other parameters used below.
584 mpWindowImpl
->mbPaintFrame
= false;
586 if (nPaintFlags
& ImplPaintFlags::PaintAllChildren
)
587 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Paint
| ImplPaintFlags::PaintAllChildren
| (nPaintFlags
& ImplPaintFlags::PaintAll
);
588 if (nPaintFlags
& ImplPaintFlags::PaintChildren
)
589 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintChildren
;
590 if (nPaintFlags
& ImplPaintFlags::Erase
)
591 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Erase
;
592 if (nPaintFlags
& ImplPaintFlags::CheckRtl
)
593 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::CheckRtl
;
594 if (!mpWindowImpl
->mpFirstChild
)
595 mpWindowImpl
->mnPaintFlags
&= ~ImplPaintFlags::PaintAllChildren
;
597 if (mpWindowImpl
->mbPaintDisabled
)
599 if (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
600 Invalidate(InvalidateFlags::NoChildren
| InvalidateFlags::NoErase
| InvalidateFlags::NoTransparent
| InvalidateFlags::NoClipChildren
);
602 Invalidate(*pRegion
, InvalidateFlags::NoChildren
| InvalidateFlags::NoErase
| InvalidateFlags::NoTransparent
| InvalidateFlags::NoClipChildren
);
604 // call PostPaint before returning
610 nPaintFlags
= mpWindowImpl
->mnPaintFlags
& ~ImplPaintFlags::Paint
;
612 PaintHelper
aHelper(this, nPaintFlags
);
614 if (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::Paint
)
615 aHelper
.DoPaint(pRegion
);
617 mpWindowImpl
->mnPaintFlags
= ImplPaintFlags::NONE
;
623 void Window::ImplCallOverlapPaint()
625 // emit overlapping windows first
626 vcl::Window
* pTempWindow
= mpWindowImpl
->mpFirstOverlap
;
627 while ( pTempWindow
)
629 if ( pTempWindow
->mpWindowImpl
->mbReallyVisible
)
630 pTempWindow
->ImplCallOverlapPaint();
631 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
635 if ( mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintChildren
) )
637 // RTL: notify ImplCallPaint to check for re-mirroring
638 // because we were called from the Sal layer
639 ImplCallPaint(nullptr, mpWindowImpl
->mnPaintFlags
/*| ImplPaintFlags::CheckRtl */);
643 IMPL_LINK_NOARG(Window
, ImplHandlePaintHdl
, Timer
*, void)
646 comphelper::ProfileZone
aZone("VCL idle re-paint");
648 // save paint events until layout is done
649 if (IsSystemWindow() && static_cast<const SystemWindow
*>(this)->hasPendingLayout())
651 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
655 // save paint events until resizing or initial sizing done
656 if (mpWindowImpl
->mbFrame
&&
657 mpWindowImpl
->mpFrameData
->maResizeIdle
.IsActive())
659 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
661 else if ( mpWindowImpl
->mbReallyVisible
)
663 ImplCallOverlapPaint();
664 if (comphelper::LibreOfficeKit::isActive() &&
665 mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive())
666 mpWindowImpl
->mpFrameData
->maPaintIdle
.Stop();
671 IMPL_LINK_NOARG(Window
, ImplHandleResizeTimerHdl
, Timer
*, void)
673 comphelper::ProfileZone
aZone("VCL idle resize");
675 if( mpWindowImpl
->mbReallyVisible
)
678 if( mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive() )
680 mpWindowImpl
->mpFrameData
->maPaintIdle
.Stop();
681 mpWindowImpl
->mpFrameData
->maPaintIdle
.Invoke( nullptr );
686 void Window::ImplInvalidateFrameRegion( const vcl::Region
* pRegion
, InvalidateFlags nFlags
)
688 // set PAINTCHILDREN for all parent windows till the first OverlapWindow
689 if ( !ImplIsOverlapWindow() )
691 vcl::Window
* pTempWindow
= this;
692 ImplPaintFlags nTranspPaint
= IsPaintTransparent() ? ImplPaintFlags::Paint
: ImplPaintFlags::NONE
;
695 pTempWindow
= pTempWindow
->ImplGetParent();
696 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintChildren
)
698 pTempWindow
->mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintChildren
| nTranspPaint
;
699 if( ! pTempWindow
->IsPaintTransparent() )
700 nTranspPaint
= ImplPaintFlags::NONE
;
702 while ( !pTempWindow
->ImplIsOverlapWindow() );
706 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Paint
;
707 if ( nFlags
& InvalidateFlags::Children
)
708 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintAllChildren
;
709 if ( !(nFlags
& InvalidateFlags::NoErase
) )
710 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Erase
;
713 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintAll
;
714 else if ( !(mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
) )
716 // if not everything has to be redrawn, add the region to it
717 mpWindowImpl
->maInvalidateRegion
.Union( *pRegion
);
720 // Handle transparent windows correctly: invalidate must be done on the first opaque parent
721 if( ((IsPaintTransparent() && !(nFlags
& InvalidateFlags::NoTransparent
)) || (nFlags
& InvalidateFlags::Transparent
) )
724 vcl::Window
*pParent
= ImplGetParent();
725 while( pParent
&& pParent
->IsPaintTransparent() )
726 pParent
= pParent
->ImplGetParent();
729 vcl::Region
*pChildRegion
;
730 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
731 // invalidate the whole child window region in the parent
732 pChildRegion
= ImplGetWinChildClipRegion();
734 // invalidate the same region in the parent that has to be repainted in the child
735 pChildRegion
= &mpWindowImpl
->maInvalidateRegion
;
737 nFlags
|= InvalidateFlags::Children
; // paint should also be done on all children
738 nFlags
&= ~InvalidateFlags::NoErase
; // parent should paint and erase to create proper background
739 pParent
->ImplInvalidateFrameRegion( pChildRegion
, nFlags
);
743 if ( !mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive() )
744 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
747 void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region
& rRegion
)
749 vcl::Region aRegion
= rRegion
;
751 ImplClipBoundaries( aRegion
, true, true );
752 if ( !aRegion
.IsEmpty() )
753 ImplInvalidateFrameRegion( &aRegion
, InvalidateFlags::Children
);
755 // now we invalidate the overlapping windows
756 vcl::Window
* pTempWindow
= mpWindowImpl
->mpFirstOverlap
;
757 while ( pTempWindow
)
759 if ( pTempWindow
->IsVisible() )
760 pTempWindow
->ImplInvalidateOverlapFrameRegion( rRegion
);
762 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
766 void Window::ImplInvalidateParentFrameRegion( vcl::Region
& rRegion
)
768 if ( mpWindowImpl
->mbOverlapWin
)
769 mpWindowImpl
->mpFrameWindow
->ImplInvalidateOverlapFrameRegion( rRegion
);
772 if( ImplGetParent() )
773 ImplGetParent()->ImplInvalidateFrameRegion( &rRegion
, InvalidateFlags::Children
);
777 void Window::ImplInvalidate( const vcl::Region
* pRegion
, InvalidateFlags nFlags
)
779 // check what has to be redrawn
780 bool bInvalidateAll
= !pRegion
;
782 // take Transparent-Invalidate into account
783 vcl::Window
* pOpaqueWindow
= this;
784 if ( (mpWindowImpl
->mbPaintTransparent
&& !(nFlags
& InvalidateFlags::NoTransparent
)) || (nFlags
& InvalidateFlags::Transparent
) )
786 vcl::Window
* pTempWindow
= pOpaqueWindow
->ImplGetParent();
787 while ( pTempWindow
)
789 if ( !pTempWindow
->IsPaintTransparent() )
791 pOpaqueWindow
= pTempWindow
;
792 nFlags
|= InvalidateFlags::Children
;
793 bInvalidateAll
= false;
797 if ( pTempWindow
->ImplIsOverlapWindow() )
800 pTempWindow
= pTempWindow
->ImplGetParent();
805 InvalidateFlags nOrgFlags
= nFlags
;
806 if ( !(nFlags
& (InvalidateFlags::Children
| InvalidateFlags::NoChildren
)) )
808 if ( GetStyle() & WB_CLIPCHILDREN
)
809 nFlags
|= InvalidateFlags::NoChildren
;
811 nFlags
|= InvalidateFlags::Children
;
813 if ( (nFlags
& InvalidateFlags::NoChildren
) && mpWindowImpl
->mpFirstChild
)
814 bInvalidateAll
= false;
815 if ( bInvalidateAll
)
816 ImplInvalidateFrameRegion( nullptr, nFlags
);
819 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
820 vcl::Region
aRegion( aRect
);
823 // RTL: remirror region before intersecting it
824 if ( ImplIsAntiparallel() )
826 const OutputDevice
*pOutDev
= GetOutDev();
828 vcl::Region
aRgn( *pRegion
);
829 pOutDev
->ReMirror( aRgn
);
830 aRegion
.Intersect( aRgn
);
833 aRegion
.Intersect( *pRegion
);
835 ImplClipBoundaries( aRegion
, true, true );
836 if ( nFlags
& InvalidateFlags::NoChildren
)
838 nFlags
&= ~InvalidateFlags::Children
;
839 if ( !(nFlags
& InvalidateFlags::NoClipChildren
) )
841 if ( nOrgFlags
& InvalidateFlags::NoChildren
)
842 ImplClipAllChildren( aRegion
);
845 if ( ImplClipChildren( aRegion
) )
846 nFlags
|= InvalidateFlags::Children
;
850 if ( !aRegion
.IsEmpty() )
851 ImplInvalidateFrameRegion( &aRegion
, nFlags
); // transparency is handled here, pOpaqueWindow not required
854 if ( nFlags
& InvalidateFlags::Update
)
855 pOpaqueWindow
->PaintImmediately(); // start painting at the opaque parent
858 void Window::ImplMoveInvalidateRegion( const tools::Rectangle
& rRect
,
859 tools::Long nHorzScroll
, tools::Long nVertScroll
,
862 if ( (mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintAll
)) == ImplPaintFlags::Paint
)
864 vcl::Region aTempRegion
= mpWindowImpl
->maInvalidateRegion
;
865 aTempRegion
.Intersect( rRect
);
866 aTempRegion
.Move( nHorzScroll
, nVertScroll
);
867 mpWindowImpl
->maInvalidateRegion
.Union( aTempRegion
);
870 if ( bChildren
&& (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintChildren
) )
872 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstChild
;
875 pWindow
->ImplMoveInvalidateRegion( rRect
, nHorzScroll
, nVertScroll
, true );
876 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
881 void Window::ImplMoveAllInvalidateRegions( const tools::Rectangle
& rRect
,
882 tools::Long nHorzScroll
, tools::Long nVertScroll
,
885 // also shift Paint-Region when paints need processing
886 ImplMoveInvalidateRegion( rRect
, nHorzScroll
, nVertScroll
, bChildren
);
887 // Paint-Region should be shifted, as drawn by the parents
888 if ( ImplIsOverlapWindow() )
891 vcl::Region aPaintAllRegion
;
892 vcl::Window
* pPaintAllWindow
= this;
895 pPaintAllWindow
= pPaintAllWindow
->ImplGetParent();
896 if ( pPaintAllWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
898 if ( pPaintAllWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
900 aPaintAllRegion
.SetEmpty();
904 aPaintAllRegion
.Union( pPaintAllWindow
->mpWindowImpl
->maInvalidateRegion
);
907 while ( !pPaintAllWindow
->ImplIsOverlapWindow() );
908 if ( !aPaintAllRegion
.IsEmpty() )
910 aPaintAllRegion
.Move( nHorzScroll
, nVertScroll
);
911 InvalidateFlags nPaintFlags
= InvalidateFlags::NONE
;
913 nPaintFlags
|= InvalidateFlags::Children
;
914 ImplInvalidateFrameRegion( &aPaintAllRegion
, nPaintFlags
);
918 void Window::ImplValidateFrameRegion( const vcl::Region
* pRegion
, ValidateFlags nFlags
)
921 mpWindowImpl
->maInvalidateRegion
.SetEmpty();
924 // when all child windows have to be drawn we need to invalidate them before doing so
925 if ( (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
) && mpWindowImpl
->mpFirstChild
)
927 vcl::Region aChildRegion
= mpWindowImpl
->maInvalidateRegion
;
928 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
930 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
931 aChildRegion
= aRect
;
933 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
936 pChild
->Invalidate( aChildRegion
, InvalidateFlags::Children
| InvalidateFlags::NoTransparent
);
937 pChild
= pChild
->mpWindowImpl
->mpNext
;
940 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
942 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
943 mpWindowImpl
->maInvalidateRegion
= aRect
;
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 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
976 vcl::Region
aRegion( aRect
);
977 ImplClipBoundaries( aRegion
, true, true );
978 if ( nFlags
& ValidateFlags::NoChildren
)
980 nFlags
&= ~ValidateFlags::Children
;
981 if ( ImplClipChildren( aRegion
) )
982 nFlags
|= ValidateFlags::Children
;
984 if ( !aRegion
.IsEmpty() )
985 ImplValidateFrameRegion( &aRegion
, nFlags
);
989 void Window::ImplUpdateAll()
991 if ( !mpWindowImpl
->mbReallyVisible
)
995 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
997 Point
aPoint( 0, 0 );
998 vcl::Region
aRegion( tools::Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
999 ImplInvalidateOverlapFrameRegion( aRegion
);
1000 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
1004 // an update changes the OverlapWindow, such that for later paints
1005 // not too much has to be drawn, if ALLCHILDREN etc. is set
1006 vcl::Window
* pWindow
= ImplGetFirstOverlapWindow();
1007 pWindow
->ImplCallOverlapPaint();
1013 void Window::PrePaint(vcl::RenderContext
& /*rRenderContext*/)
1017 void Window::PostPaint(vcl::RenderContext
& /*rRenderContext*/)
1021 void Window::Paint(vcl::RenderContext
& /*rRenderContext*/, const tools::Rectangle
& rRect
)
1023 CallEventListeners(VclEventId::WindowPaint
, const_cast<tools::Rectangle
*>(&rRect
));
1026 void Window::SetPaintTransparent( bool bTransparent
)
1028 // transparency is not useful for frames as the background would have to be provided by a different frame
1029 if( bTransparent
&& mpWindowImpl
->mbFrame
)
1032 if ( mpWindowImpl
->mpBorderWindow
)
1033 mpWindowImpl
->mpBorderWindow
->SetPaintTransparent( bTransparent
);
1035 mpWindowImpl
->mbPaintTransparent
= bTransparent
;
1038 void Window::SetWindowRegionPixel()
1041 if ( mpWindowImpl
->mpBorderWindow
)
1042 mpWindowImpl
->mpBorderWindow
->SetWindowRegionPixel();
1043 else if( mpWindowImpl
->mbFrame
)
1045 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1046 mpWindowImpl
->mbWinRegion
= false;
1047 mpWindowImpl
->mpFrame
->ResetClipRegion();
1051 if ( mpWindowImpl
->mbWinRegion
)
1053 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1054 mpWindowImpl
->mbWinRegion
= false;
1057 if ( IsReallyVisible() )
1059 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
1060 vcl::Region
aRegion( aRect
);
1061 ImplInvalidateParentFrameRegion( aRegion
);
1067 void Window::SetWindowRegionPixel( const vcl::Region
& rRegion
)
1070 if ( mpWindowImpl
->mpBorderWindow
)
1071 mpWindowImpl
->mpBorderWindow
->SetWindowRegionPixel( rRegion
);
1072 else if( mpWindowImpl
->mbFrame
)
1074 if( !rRegion
.IsNull() )
1076 mpWindowImpl
->maWinRegion
= rRegion
;
1077 mpWindowImpl
->mbWinRegion
= ! rRegion
.IsEmpty();
1079 if( mpWindowImpl
->mbWinRegion
)
1081 // set/update ClipRegion
1082 RectangleVector aRectangles
;
1083 mpWindowImpl
->maWinRegion
.GetRegionRectangles(aRectangles
);
1084 mpWindowImpl
->mpFrame
->BeginSetClipRegion(aRectangles
.size());
1086 for (auto const& rectangle
: aRectangles
)
1088 mpWindowImpl
->mpFrame
->UnionClipRegion(
1091 rectangle
.GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
1092 rectangle
.GetHeight()); // same for height
1095 mpWindowImpl
->mpFrame
->EndSetClipRegion();
1101 //sal_uLong nRectCount;
1102 //ImplRegionInfo aInfo;
1103 //sal_Bool bRegionRect;
1105 //nRectCount = mpWindowImpl->maWinRegion.GetRectCount();
1106 //mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount );
1107 //bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
1108 //while ( bRegionRect )
1110 // mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight );
1111 // bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
1113 //mpWindowImpl->mpFrame->EndSetClipRegion();
1116 SetWindowRegionPixel();
1119 SetWindowRegionPixel();
1123 if ( rRegion
.IsNull() )
1125 if ( mpWindowImpl
->mbWinRegion
)
1127 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1128 mpWindowImpl
->mbWinRegion
= false;
1134 mpWindowImpl
->maWinRegion
= rRegion
;
1135 mpWindowImpl
->mbWinRegion
= true;
1139 if ( IsReallyVisible() )
1141 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
1142 vcl::Region
aRegion( aRect
);
1143 ImplInvalidateParentFrameRegion( aRegion
);
1148 vcl::Region
Window::GetPaintRegion() const
1151 if ( mpWindowImpl
->mpPaintRegion
)
1153 vcl::Region aRegion
= *mpWindowImpl
->mpPaintRegion
;
1154 aRegion
.Move( -mnOutOffX
, -mnOutOffY
);
1155 return PixelToLogic( aRegion
);
1159 vcl::Region
aPaintRegion(true);
1160 return aPaintRegion
;
1164 void Window::Invalidate( InvalidateFlags nFlags
)
1166 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1169 ImplInvalidate( nullptr, nFlags
);
1170 LogicInvalidate(nullptr);
1173 void Window::Invalidate( const tools::Rectangle
& rRect
, InvalidateFlags nFlags
)
1175 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1178 OutputDevice
*pOutDev
= GetOutDev();
1179 tools::Rectangle aRect
= pOutDev
->ImplLogicToDevicePixel( rRect
);
1180 if ( !aRect
.IsEmpty() )
1182 vcl::Region
aRegion( aRect
);
1183 ImplInvalidate( &aRegion
, nFlags
);
1184 tools::Rectangle
aLogicRectangle(rRect
);
1185 LogicInvalidate(&aLogicRectangle
);
1189 void Window::Invalidate( const vcl::Region
& rRegion
, InvalidateFlags nFlags
)
1191 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1194 if ( rRegion
.IsNull() )
1196 ImplInvalidate( nullptr, nFlags
);
1197 LogicInvalidate(nullptr);
1201 vcl::Region aRegion
= ImplPixelToDevicePixel( LogicToPixel( rRegion
) );
1202 if ( !aRegion
.IsEmpty() )
1204 ImplInvalidate( &aRegion
, nFlags
);
1205 tools::Rectangle aLogicRectangle
= rRegion
.GetBoundRect();
1206 LogicInvalidate(&aLogicRectangle
);
1211 void Window::LogicInvalidate(const tools::Rectangle
* pRectangle
)
1215 tools::Rectangle aRect
= GetOutDev()->ImplLogicToDevicePixel( *pRectangle
);
1216 PixelInvalidate(&aRect
);
1219 PixelInvalidate(nullptr);
1222 void Window::PixelInvalidate(const tools::Rectangle
* pRectangle
)
1224 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1227 Size aSize
= GetSizePixel();
1228 if (aSize
.IsEmpty())
1231 if (const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
1233 // In case we are routing the window, notify the client
1234 std::vector
<vcl::LOKPayloadItem
> aPayload
;
1236 aPayload
.emplace_back("rectangle", pRectangle
->toString());
1239 const tools::Rectangle
aRect(Point(0, 0), aSize
);
1240 aPayload
.emplace_back("rectangle", aRect
.toString());
1243 pNotifier
->notifyWindow(GetLOKWindowId(), "invalidate", aPayload
);
1245 // Added for dialog items. Pass invalidation to the parent window.
1246 else if (VclPtr
<vcl::Window
> pParent
= GetParentWithLOKNotifier())
1248 const tools::Rectangle
aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1249 pParent
->PixelInvalidate(&aRect
);
1253 void Window::Validate()
1255 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1261 bool Window::HasPaintEvent() const
1264 if ( !mpWindowImpl
->mbReallyVisible
)
1267 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1270 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::Paint
)
1273 if ( !ImplIsOverlapWindow() )
1275 const vcl::Window
* pTempWindow
= this;
1278 pTempWindow
= pTempWindow
->ImplGetParent();
1279 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::PaintChildren
| ImplPaintFlags::PaintAllChildren
) )
1282 while ( !pTempWindow
->ImplIsOverlapWindow() );
1288 void Window::PaintImmediately()
1290 if ( mpWindowImpl
->mpBorderWindow
)
1292 mpWindowImpl
->mpBorderWindow
->PaintImmediately();
1296 if ( !mpWindowImpl
->mbReallyVisible
)
1299 bool bFlush
= false;
1300 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1302 Point
aPoint( 0, 0 );
1303 vcl::Region
aRegion( tools::Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
1304 ImplInvalidateOverlapFrameRegion( aRegion
);
1305 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
1309 // First we should skip all windows which are Paint-Transparent
1310 vcl::Window
* pUpdateWindow
= this;
1311 vcl::Window
* pWindow
= pUpdateWindow
;
1312 while ( !pWindow
->ImplIsOverlapWindow() )
1314 if ( !pWindow
->mpWindowImpl
->mbPaintTransparent
)
1316 pUpdateWindow
= pWindow
;
1319 pWindow
= pWindow
->ImplGetParent();
1321 // In order to limit drawing, an update only draws the window which
1322 // has PAINTALLCHILDREN set
1323 pWindow
= pUpdateWindow
;
1326 if ( pWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
1327 pUpdateWindow
= pWindow
;
1328 if ( pWindow
->ImplIsOverlapWindow() )
1330 pWindow
= pWindow
->ImplGetParent();
1334 // if there is something to paint, trigger a Paint
1335 if ( pUpdateWindow
->mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintChildren
) )
1337 VclPtr
<vcl::Window
> xWindow(this);
1339 // trigger an update also for system windows on top of us,
1340 // otherwise holes would remain
1341 vcl::Window
* pUpdateOverlapWindow
= ImplGetFirstOverlapWindow()->mpWindowImpl
->mpFirstOverlap
;
1342 while ( pUpdateOverlapWindow
)
1344 pUpdateOverlapWindow
->PaintImmediately();
1345 pUpdateOverlapWindow
= pUpdateOverlapWindow
->mpWindowImpl
->mpNext
;
1348 pUpdateWindow
->ImplCallPaint(nullptr, pUpdateWindow
->mpWindowImpl
->mnPaintFlags
);
1350 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow
->GetParentDialog())
1351 pUpdateWindow
->LogicInvalidate(nullptr);
1353 if (xWindow
->IsDisposed())
1363 void Window::ImplPaintToDevice( OutputDevice
* i_pTargetOutDev
, const Point
& i_rPos
)
1365 // Special drawing when called through LOKit
1366 // TODO: Move to its own method
1367 if (comphelper::LibreOfficeKit::isActive())
1369 VclPtrInstance
<VirtualDevice
> pDevice(*i_pTargetOutDev
);
1371 Size
aSize(GetOutputSizePixel());
1372 pDevice
->SetOutputSizePixel(aSize
);
1374 vcl::Font aCopyFont
= GetFont();
1375 pDevice
->SetFont(aCopyFont
);
1377 pDevice
->SetTextColor(GetTextColor());
1379 pDevice
->SetLineColor(GetLineColor());
1381 pDevice
->SetLineColor();
1384 pDevice
->SetFillColor(GetFillColor());
1386 pDevice
->SetFillColor();
1388 if (IsTextLineColor())
1389 pDevice
->SetTextLineColor(GetTextLineColor());
1391 pDevice
->SetTextLineColor();
1393 if (IsOverlineColor())
1394 pDevice
->SetOverlineColor(GetOverlineColor());
1396 pDevice
->SetOverlineColor();
1398 if (IsTextFillColor())
1399 pDevice
->SetTextFillColor(GetTextFillColor());
1401 pDevice
->SetTextFillColor();
1403 pDevice
->SetTextAlign(GetTextAlign());
1404 pDevice
->SetRasterOp(GetRasterOp());
1406 tools::Rectangle
aPaintRect(Point(), GetOutputSizePixel());
1408 vcl::Region
aClipRegion(GetClipRegion());
1409 pDevice
->SetClipRegion();
1410 aClipRegion
.Intersect(aPaintRect
);
1411 pDevice
->SetClipRegion(aClipRegion
);
1413 if (!IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip
))
1416 pDevice
->SetMapMode(GetMapMode());
1418 Paint(*pDevice
, tools::Rectangle(Point(), GetOutputSizePixel()));
1420 i_pTargetOutDev
->DrawOutDev(i_rPos
, aSize
, Point(), pDevice
->PixelToLogic(aSize
), *pDevice
);
1422 // get rid of virtual device now so they don't pile up during recursive calls
1423 pDevice
.disposeAndClear();
1426 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1428 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1430 tools::Long nDeltaX
= pChild
->mnOutOffX
- mnOutOffX
;
1431 tools::Long nDeltaY
= pChild
->mnOutOffY
- mnOutOffY
;
1433 Point
aPos( i_rPos
);
1434 aPos
+= Point(nDeltaX
, nDeltaY
);
1436 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1443 bool bRVisible
= mpWindowImpl
->mbReallyVisible
;
1444 mpWindowImpl
->mbReallyVisible
= mpWindowImpl
->mbVisible
;
1445 bool bDevOutput
= mbDevOutput
;
1448 const OutputDevice
*pOutDev
= GetOutDev();
1449 tools::Long nOldDPIX
= pOutDev
->GetDPIX();
1450 tools::Long nOldDPIY
= pOutDev
->GetDPIY();
1451 mnDPIX
= i_pTargetOutDev
->GetDPIX();
1452 mnDPIY
= i_pTargetOutDev
->GetDPIY();
1453 bool bOutput
= IsOutputEnabled();
1456 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel
, "vcl.window", "MapMode must be PIXEL based" );
1457 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel
)
1460 // preserve graphicsstate
1462 vcl::Region
aClipRegion( GetClipRegion() );
1465 GDIMetaFile
* pOldMtf
= GetConnectMetaFile();
1467 SetConnectMetaFile( &aMtf
);
1469 // put a push action to metafile
1471 // copy graphics state to metafile
1472 vcl::Font aCopyFont
= GetFont();
1473 if( nOldDPIX
!= mnDPIX
|| nOldDPIY
!= mnDPIY
)
1475 aCopyFont
.SetFontHeight( aCopyFont
.GetFontHeight() * mnDPIY
/ nOldDPIY
);
1476 aCopyFont
.SetAverageFontWidth( aCopyFont
.GetAverageFontWidth() * mnDPIX
/ nOldDPIX
);
1478 SetFont( aCopyFont
);
1479 SetTextColor( GetTextColor() );
1481 SetLineColor( GetLineColor() );
1485 SetFillColor( GetFillColor() );
1488 if( IsTextLineColor() )
1489 SetTextLineColor( GetTextLineColor() );
1492 if( IsOverlineColor() )
1493 SetOverlineColor( GetOverlineColor() );
1496 if( IsTextFillColor() )
1497 SetTextFillColor( GetTextFillColor() );
1500 SetTextAlign( GetTextAlign() );
1501 SetRasterOp( GetRasterOp() );
1503 SetRefPoint( GetRefPoint() );
1506 SetLayoutMode( GetLayoutMode() );
1508 SetDigitLanguage( GetDigitLanguage() );
1509 tools::Rectangle
aPaintRect(Point(0, 0), GetOutputSizePixel());
1510 aClipRegion
.Intersect( aPaintRect
);
1511 SetClipRegion( aClipRegion
);
1513 // do the actual paint
1516 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip
) )
1521 Paint(*this, aPaintRect
);
1522 // put a pop action to metafile
1525 SetConnectMetaFile( pOldMtf
);
1526 EnableOutput( bOutput
);
1527 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1529 // paint metafile to VDev
1530 VclPtrInstance
<VirtualDevice
> pMaskedDevice(*i_pTargetOutDev
,
1531 DeviceFormat::DEFAULT
,
1532 DeviceFormat::DEFAULT
);
1534 pMaskedDevice
->SetOutputSizePixel( GetOutputSizePixel() );
1535 pMaskedDevice
->EnableRTL( IsRTLEnabled() );
1537 aMtf
.Play( pMaskedDevice
);
1538 BitmapEx
aBmpEx( pMaskedDevice
->GetBitmapEx( Point( 0, 0 ), aPaintRect
.GetSize() ) );
1539 i_pTargetOutDev
->DrawBitmapEx( i_rPos
, aBmpEx
);
1540 // get rid of virtual device now so they don't pile up during recursive calls
1541 pMaskedDevice
.disposeAndClear();
1543 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1545 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1547 tools::Long nDeltaX
= pChild
->mnOutOffX
- mnOutOffX
;
1549 if( pOutDev
->HasMirroredGraphics() )
1550 nDeltaX
= mnOutWidth
- nDeltaX
- pChild
->mnOutWidth
;
1551 tools::Long nDeltaY
= pChild
->GetOutOffYPixel() - GetOutOffYPixel();
1552 Point
aPos( i_rPos
);
1553 Point
aDelta( nDeltaX
, nDeltaY
);
1555 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1559 // restore graphics state
1562 EnableOutput( bOutput
);
1563 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1564 mbDevOutput
= bDevOutput
;
1569 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 (!IsDeviceOutputNecessary() || 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 (mbBackground
&& !bNativeOK
)
1628 RasterOp eRasterOp
= GetRasterOp();
1629 if (eRasterOp
!= RasterOp::OverPaint
)
1630 SetRasterOp(RasterOp::OverPaint
);
1631 rRenderContext
.DrawWallpaper(0, 0, mnOutWidth
, mnOutHeight
, maBackground
);
1632 if (eRasterOp
!= RasterOp::OverPaint
)
1633 rRenderContext
.SetRasterOp(eRasterOp
);
1637 mpAlphaVDev
->Erase();
1640 void Window::ImplScroll( const tools::Rectangle
& rRect
,
1641 tools::Long nHorzScroll
, tools::Long nVertScroll
, ScrollFlags nFlags
)
1643 if ( !IsDeviceOutputNecessary() )
1646 nHorzScroll
= ImplLogicWidthToDevicePixel( nHorzScroll
);
1647 nVertScroll
= ImplLogicHeightToDevicePixel( nVertScroll
);
1649 if ( !nHorzScroll
&& !nVertScroll
)
1652 if ( mpWindowImpl
->mpCursor
)
1653 mpWindowImpl
->mpCursor
->ImplSuspend();
1655 ScrollFlags nOrgFlags
= nFlags
;
1656 if ( !(nFlags
& (ScrollFlags::Children
| ScrollFlags::NoChildren
)) )
1658 if ( GetStyle() & WB_CLIPCHILDREN
)
1659 nFlags
|= ScrollFlags::NoChildren
;
1661 nFlags
|= ScrollFlags::Children
;
1664 vcl::Region aInvalidateRegion
;
1665 bool bScrollChildren(nFlags
& ScrollFlags::Children
);
1667 if ( !mpWindowImpl
->mpFirstChild
)
1668 bScrollChildren
= false;
1670 OutputDevice
*pOutDev
= GetOutDev();
1672 // RTL: check if this window requires special action
1673 bool bReMirror
= ImplIsAntiparallel();
1675 tools::Rectangle
aRectMirror( rRect
);
1678 // make sure the invalidate region of this window is
1679 // computed in the same coordinate space as the one from the overlap windows
1680 pOutDev
->ReMirror( aRectMirror
);
1683 // adapt paint areas
1684 ImplMoveAllInvalidateRegions( aRectMirror
, nHorzScroll
, nVertScroll
, bScrollChildren
);
1686 ImplCalcOverlapRegion( aRectMirror
, aInvalidateRegion
, !bScrollChildren
, false );
1688 // if the scrolling on the device is performed in the opposite direction
1689 // then move the overlaps in that direction to compute the invalidate region
1690 // on the correct side, i.e., revert nHorzScroll
1691 if (!aInvalidateRegion
.IsEmpty())
1693 aInvalidateRegion
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1696 tools::Rectangle
aDestRect(aRectMirror
);
1697 aDestRect
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1698 vcl::Region
aWinInvalidateRegion(aRectMirror
);
1699 if (!SupportsDoubleBuffering())
1701 // There will be no CopyArea() call below, so invalidate the
1702 // whole visible area, not only the smaller one that was just
1704 aWinInvalidateRegion
.Exclude(aDestRect
);
1707 aInvalidateRegion
.Union(aWinInvalidateRegion
);
1709 Point
aPoint( mnOutOffX
, mnOutOffY
);
1710 vcl::Region
aRegion( tools::Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
1711 if ( nFlags
& ScrollFlags::Clip
)
1712 aRegion
.Intersect( rRect
);
1713 if ( mpWindowImpl
->mbWinRegion
)
1714 aRegion
.Intersect( 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 ( mbClipRegion
&& (nFlags
& ScrollFlags::UseClipRegion
) )
1727 aRegion
.Intersect( 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
&& !SupportsDoubleBuffering())
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: */