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>
43 PaintBufferGuard::PaintBufferGuard(ImplFrameData
* pFrameData
, vcl::Window
* pWindow
)
44 : mpFrameData(pFrameData
),
50 if (!pFrameData
->mpBuffer
)
53 // transfer various settings
54 // FIXME: this must disappear as we move to RenderContext only,
55 // the painting must become state-less, so that no actual
56 // vcl::Window setting affects this
57 mbBackground
= pFrameData
->mpBuffer
->IsBackground();
58 if (pWindow
->IsBackground())
60 maBackground
= pFrameData
->mpBuffer
->GetBackground();
61 pFrameData
->mpBuffer
->SetBackground(pWindow
->GetBackground());
64 //SAL_WARN("vcl.window", "the root of the double-buffering hierarchy should not have a transparent background");
66 PushFlags nFlags
= PushFlags::NONE
;
67 nFlags
|= PushFlags::CLIPREGION
;
68 nFlags
|= PushFlags::FILLCOLOR
;
69 nFlags
|= PushFlags::FONT
;
70 nFlags
|= PushFlags::LINECOLOR
;
71 nFlags
|= PushFlags::MAPMODE
;
72 maSettings
= pFrameData
->mpBuffer
->GetSettings();
73 nFlags
|= PushFlags::REFPOINT
;
74 nFlags
|= PushFlags::TEXTCOLOR
;
75 nFlags
|= PushFlags::TEXTLINECOLOR
;
76 nFlags
|= PushFlags::OVERLINECOLOR
;
77 nFlags
|= PushFlags::TEXTFILLCOLOR
;
78 nFlags
|= PushFlags::TEXTALIGN
;
79 nFlags
|= PushFlags::RASTEROP
;
80 nFlags
|= PushFlags::TEXTLAYOUTMODE
;
81 nFlags
|= PushFlags::TEXTLANGUAGE
;
82 pFrameData
->mpBuffer
->Push(nFlags
);
83 pFrameData
->mpBuffer
->SetClipRegion(pWindow
->GetClipRegion());
84 pFrameData
->mpBuffer
->SetFillColor(pWindow
->GetFillColor());
85 pFrameData
->mpBuffer
->SetFont(pWindow
->GetFont());
86 pFrameData
->mpBuffer
->SetLineColor(pWindow
->GetLineColor());
87 pFrameData
->mpBuffer
->SetMapMode(pWindow
->GetMapMode());
88 pFrameData
->mpBuffer
->SetRefPoint(pWindow
->GetRefPoint());
89 pFrameData
->mpBuffer
->SetSettings(pWindow
->GetSettings());
90 pFrameData
->mpBuffer
->SetTextColor(pWindow
->GetTextColor());
91 pFrameData
->mpBuffer
->SetTextLineColor(pWindow
->GetTextLineColor());
92 pFrameData
->mpBuffer
->SetOverlineColor(pWindow
->GetOverlineColor());
93 pFrameData
->mpBuffer
->SetTextFillColor(pWindow
->GetTextFillColor());
94 pFrameData
->mpBuffer
->SetTextAlign(pWindow
->GetTextAlign());
95 pFrameData
->mpBuffer
->SetRasterOp(pWindow
->GetRasterOp());
96 pFrameData
->mpBuffer
->SetLayoutMode(pWindow
->GetLayoutMode());
97 pFrameData
->mpBuffer
->SetDigitLanguage(pWindow
->GetDigitLanguage());
99 mnOutOffX
= pFrameData
->mpBuffer
->GetOutOffXPixel();
100 mnOutOffY
= pFrameData
->mpBuffer
->GetOutOffYPixel();
101 pFrameData
->mpBuffer
->SetOutOffXPixel(pWindow
->GetOutOffXPixel());
102 pFrameData
->mpBuffer
->SetOutOffYPixel(pWindow
->GetOutOffYPixel());
105 PaintBufferGuard::~PaintBufferGuard()
107 if (!mpFrameData
->mpBuffer
)
110 if (!m_aPaintRect
.IsEmpty())
112 // copy the buffer content to the actual window
113 // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are
114 // painting directly instead of using Invalidate()
115 // [ie. everything you can see was painted directly to the
116 // window either above or in eg. an event handler]
117 if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT"))
119 // Make sure that the +1 value GetSize() adds to the size is in pixels.
121 if (m_pWindow
->GetMapMode().GetMapUnit() == MapUnit::MapPixel
)
123 aPaintRectSize
= m_aPaintRect
.GetSize();
127 tools::Rectangle aRectanglePixel
= m_pWindow
->LogicToPixel(m_aPaintRect
);
128 aPaintRectSize
= m_pWindow
->PixelToLogic(aRectanglePixel
.GetSize());
131 m_pWindow
->DrawOutDev(m_aPaintRect
.TopLeft(), aPaintRectSize
, m_aPaintRect
.TopLeft(), aPaintRectSize
, *mpFrameData
->mpBuffer
);
135 // Restore buffer state.
136 mpFrameData
->mpBuffer
->SetOutOffXPixel(mnOutOffX
);
137 mpFrameData
->mpBuffer
->SetOutOffYPixel(mnOutOffY
);
139 mpFrameData
->mpBuffer
->Pop();
140 mpFrameData
->mpBuffer
->SetSettings(maSettings
);
142 mpFrameData
->mpBuffer
->SetBackground(maBackground
);
144 mpFrameData
->mpBuffer
->SetBackground();
147 void PaintBufferGuard::SetPaintRect(const tools::Rectangle
& rRectangle
)
149 m_aPaintRect
= rRectangle
;
152 vcl::RenderContext
* PaintBufferGuard::GetRenderContext()
154 if (mpFrameData
->mpBuffer
)
155 return mpFrameData
->mpBuffer
;
163 VclPtr
<vcl::Window
> m_pWindow
;
164 std::unique_ptr
<vcl::Region
> m_pChildRegion
;
165 tools::Rectangle m_aSelectionRect
;
166 tools::Rectangle m_aPaintRect
;
167 vcl::Region m_aPaintRegion
;
168 ImplPaintFlags
const m_nPaintFlags
;
170 bool m_bRestoreCursor
: 1;
171 bool m_bStartedBufferedPaint
: 1; ///< This PaintHelper started a buffered paint, and should paint it on the screen when being destructed.
173 PaintHelper(vcl::Window
* pWindow
, ImplPaintFlags nPaintFlags
);
178 void SetPaintRect(const tools::Rectangle
& rRect
)
180 m_aPaintRect
= rRect
;
182 void SetSelectionRect(const tools::Rectangle
& rRect
)
184 m_aSelectionRect
= rRect
;
186 void SetRestoreCursor(bool bRestoreCursor
)
188 m_bRestoreCursor
= bRestoreCursor
;
190 bool GetRestoreCursor() const
192 return m_bRestoreCursor
;
194 ImplPaintFlags
GetPaintFlags() const
196 return m_nPaintFlags
;
198 vcl::Region
& GetPaintRegion()
200 return m_aPaintRegion
;
202 void DoPaint(const vcl::Region
* pRegion
);
204 /// Start buffered paint: set it up to have the same settings as m_pWindow.
205 void StartBufferedPaint();
207 /// Paint the content of the buffer to the current m_pWindow.
213 PaintHelper::PaintHelper(vcl::Window
*pWindow
, ImplPaintFlags nPaintFlags
)
215 , m_nPaintFlags(nPaintFlags
)
217 , m_bRestoreCursor(false)
218 , m_bStartedBufferedPaint(false)
222 void PaintHelper::StartBufferedPaint()
224 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
225 assert(!pFrameData
->mbInBufferedPaint
);
227 pFrameData
->mbInBufferedPaint
= true;
228 pFrameData
->maBufferedRect
= tools::Rectangle();
229 m_bStartedBufferedPaint
= true;
232 void PaintHelper::PaintBuffer()
234 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
235 assert(pFrameData
->mbInBufferedPaint
);
236 assert(m_bStartedBufferedPaint
);
238 PaintBufferGuard
aGuard(pFrameData
, m_pWindow
);
239 aGuard
.SetPaintRect(pFrameData
->maBufferedRect
);
242 void PaintHelper::DoPaint(const vcl::Region
* pRegion
)
244 WindowImpl
* pWindowImpl
= m_pWindow
->ImplGetWindowImpl();
246 vcl::Region
* pWinChildClipRegion
= m_pWindow
->ImplGetWinChildClipRegion();
247 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
248 if (pWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
|| pFrameData
->mbInBufferedPaint
)
250 pWindowImpl
->maInvalidateRegion
= *pWinChildClipRegion
;
255 pWindowImpl
->maInvalidateRegion
.Union( *pRegion
);
257 if (pWindowImpl
->mpWinData
&& pWindowImpl
->mbTrackVisible
)
258 /* #98602# need to repaint all children within the
259 * tracking rectangle, so the following invert
260 * operation takes places without traces of the previous
263 pWindowImpl
->maInvalidateRegion
.Union(*pWindowImpl
->mpWinData
->mpTrackRect
);
265 if (pWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
266 m_pChildRegion
.reset( new vcl::Region(pWindowImpl
->maInvalidateRegion
) );
267 pWindowImpl
->maInvalidateRegion
.Intersect(*pWinChildClipRegion
);
269 pWindowImpl
->mnPaintFlags
= ImplPaintFlags::NONE
;
270 if (!pWindowImpl
->maInvalidateRegion
.IsEmpty())
272 #if HAVE_FEATURE_OPENGL
273 VCL_GL_INFO("PaintHelper::DoPaint on " <<
274 typeid( *m_pWindow
).name() << " '" << m_pWindow
->GetText() << "' begin");
276 // double-buffering: setup the buffer if it does not exist
277 if (!pFrameData
->mbInBufferedPaint
&& m_pWindow
->SupportsDoubleBuffering())
278 StartBufferedPaint();
280 // double-buffering: if this window does not support double-buffering,
281 // but we are in the middle of double-buffered paint, we might be
282 // losing information
283 if (pFrameData
->mbInBufferedPaint
&& !m_pWindow
->SupportsDoubleBuffering())
284 SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow
.get()).name());
286 if (pFrameData
->mbInBufferedPaint
&& m_pWindow
->SupportsDoubleBuffering())
289 PaintBufferGuard
g(pFrameData
, m_pWindow
);
290 m_pWindow
->ApplySettings(*pFrameData
->mpBuffer
);
292 m_pWindow
->PushPaintHelper(this, *pFrameData
->mpBuffer
);
293 m_pWindow
->Paint(*pFrameData
->mpBuffer
, m_aPaintRect
);
294 pFrameData
->maBufferedRect
.Union(m_aPaintRect
);
299 Wallpaper aBackground
= m_pWindow
->GetBackground();
300 m_pWindow
->ApplySettings(*m_pWindow
);
301 // Restore lost bitmap background.
302 if (aBackground
.IsBitmap())
303 m_pWindow
->SetBackground(aBackground
);
304 m_pWindow
->PushPaintHelper(this, *m_pWindow
);
305 m_pWindow
->Paint(*m_pWindow
, m_aPaintRect
);
307 #if HAVE_FEATURE_OPENGL
308 VCL_GL_INFO("PaintHelper::DoPaint end on " <<
309 typeid( *m_pWindow
).name() << " '" << m_pWindow
->GetText() << "'");
317 void RenderTools::DrawSelectionBackground(vcl::RenderContext
& rRenderContext
, vcl::Window
const & rWindow
,
318 const tools::Rectangle
& rRect
, sal_uInt16 nHighlight
,
319 bool bChecked
, bool bDrawBorder
, bool bDrawExtBorderOnly
,
320 Color
* pSelectionTextColor
, long nCornerRadius
, Color
const * pPaintColor
)
325 bool bRoundEdges
= nCornerRadius
> 0;
327 const StyleSettings
& rStyles
= rRenderContext
.GetSettings().GetStyleSettings();
329 // colors used for item highlighting
330 Color
aSelectionBorderColor(pPaintColor
? *pPaintColor
: rStyles
.GetHighlightColor());
331 Color
aSelectionFillColor(aSelectionBorderColor
);
333 bool bDark
= rStyles
.GetFaceColor().IsDark();
334 bool bBright
= ( rStyles
.GetFaceColor() == COL_WHITE
);
336 int c1
= aSelectionBorderColor
.GetLuminance();
337 int c2
= rWindow
.GetBackgroundColor().GetLuminance();
339 if (!bDark
&& !bBright
&& std::abs(c2
- c1
) < (pPaintColor
? 40 : 75))
343 aSelectionFillColor
.RGBtoHSB( h
, s
, b
);
344 if( b
> 50 ) b
-= 40;
346 aSelectionFillColor
= Color::HSBtoRGB( h
, s
, b
);
347 aSelectionBorderColor
= aSelectionFillColor
;
352 if (aSelectionBorderColor
.IsDark())
353 aSelectionBorderColor
.IncreaseLuminance(128);
355 aSelectionBorderColor
.DecreaseLuminance(128);
358 tools::Rectangle
aRect(rRect
);
359 if (bDrawExtBorderOnly
)
361 aRect
.AdjustLeft( -1 );
362 aRect
.AdjustTop( -1 );
363 aRect
.AdjustRight(1 );
364 aRect
.AdjustBottom(1 );
366 rRenderContext
.Push(PushFlags::FILLCOLOR
| PushFlags::LINECOLOR
);
369 rRenderContext
.SetLineColor(bDark
? COL_WHITE
: (bBright
? COL_BLACK
: aSelectionBorderColor
));
371 rRenderContext
.SetLineColor();
373 sal_uInt16 nPercent
= 0;
377 aSelectionFillColor
= COL_BLACK
;
379 nPercent
= 80; // just checked (light)
383 if (bChecked
&& nHighlight
== 2)
386 aSelectionFillColor
= COL_LIGHTGRAY
;
389 aSelectionFillColor
= COL_BLACK
;
390 rRenderContext
.SetLineColor(COL_BLACK
);
394 nPercent
= bRoundEdges
? 40 : 20; // selected, pressed or checked ( very dark )
396 else if (bChecked
|| nHighlight
== 1)
399 aSelectionFillColor
= COL_GRAY
;
402 aSelectionFillColor
= COL_BLACK
;
403 rRenderContext
.SetLineColor(COL_BLACK
);
407 nPercent
= bRoundEdges
? 60 : 35; // selected, pressed or checked ( very dark )
412 aSelectionFillColor
= COL_LIGHTGRAY
;
415 aSelectionFillColor
= COL_BLACK
;
416 rRenderContext
.SetLineColor(COL_BLACK
);
423 nPercent
= 70; // selected ( dark )
427 if (bDark
&& bDrawExtBorderOnly
)
429 rRenderContext
.SetFillColor();
430 if (pSelectionTextColor
)
431 *pSelectionTextColor
= rStyles
.GetHighlightTextColor();
435 rRenderContext
.SetFillColor(aSelectionFillColor
);
436 if (pSelectionTextColor
)
438 Color aTextColor
= rWindow
.IsControlBackground() ? rWindow
.GetControlForeground() : rStyles
.GetButtonTextColor();
439 Color aHLTextColor
= rStyles
.GetHighlightTextColor();
440 int nTextDiff
= std::abs(aSelectionFillColor
.GetLuminance() - aTextColor
.GetLuminance());
441 int nHLDiff
= std::abs(aSelectionFillColor
.GetLuminance() - aHLTextColor
.GetLuminance());
442 *pSelectionTextColor
= (nHLDiff
>= nTextDiff
) ? aHLTextColor
: aTextColor
;
448 rRenderContext
.DrawRect(aRect
);
454 tools::Polygon
aPoly(aRect
, nCornerRadius
, nCornerRadius
);
455 tools::PolyPolygon
aPolyPoly(aPoly
);
456 rRenderContext
.DrawTransparent(aPolyPoly
, nPercent
);
460 tools::Polygon
aPoly(aRect
);
461 tools::PolyPolygon
aPolyPoly(aPoly
);
462 rRenderContext
.DrawTransparent(aPolyPoly
, nPercent
);
466 rRenderContext
.Pop(); // LINECOLOR | FILLCOLOR
469 void Window::PushPaintHelper(PaintHelper
*pHelper
, vcl::RenderContext
& rRenderContext
)
473 if ( mpWindowImpl
->mpCursor
)
474 pHelper
->SetRestoreCursor(mpWindowImpl
->mpCursor
->ImplSuspend());
476 mbInitClipRegion
= true;
477 mpWindowImpl
->mbInPaint
= true;
479 // restore Paint-Region
480 vcl::Region
&rPaintRegion
= pHelper
->GetPaintRegion();
481 rPaintRegion
= mpWindowImpl
->maInvalidateRegion
;
482 tools::Rectangle aPaintRect
= rPaintRegion
.GetBoundRect();
484 // RTL: re-mirror paint rect and region at this window
485 if (ImplIsAntiparallel())
487 rRenderContext
.ReMirror(aPaintRect
);
488 rRenderContext
.ReMirror(rPaintRegion
);
490 aPaintRect
= ImplDevicePixelToLogic(aPaintRect
);
491 mpWindowImpl
->mpPaintRegion
= &rPaintRegion
;
492 mpWindowImpl
->maInvalidateRegion
.SetEmpty();
494 if ((pHelper
->GetPaintFlags() & ImplPaintFlags::Erase
) && rRenderContext
.IsBackground())
496 if (rRenderContext
.IsClipRegion())
498 vcl::Region aOldRegion
= rRenderContext
.GetClipRegion();
499 rRenderContext
.SetClipRegion();
500 Erase(rRenderContext
);
501 rRenderContext
.SetClipRegion(aOldRegion
);
504 Erase(rRenderContext
);
507 // #98943# trigger drawing of toolbox selection after all children are painted
508 if (mpWindowImpl
->mbDrawSelectionBackground
)
509 pHelper
->SetSelectionRect(aPaintRect
);
510 pHelper
->SetPaintRect(aPaintRect
);
513 void Window::PopPaintHelper(PaintHelper
const *pHelper
)
515 if (mpWindowImpl
->mpWinData
)
517 if (mpWindowImpl
->mbFocusVisible
)
518 ImplInvertFocus(*mpWindowImpl
->mpWinData
->mpFocusRect
);
520 mpWindowImpl
->mbInPaint
= false;
521 mbInitClipRegion
= true;
522 mpWindowImpl
->mpPaintRegion
= nullptr;
523 if (mpWindowImpl
->mpCursor
)
524 mpWindowImpl
->mpCursor
->ImplResume(pHelper
->GetRestoreCursor());
527 } /* namespace vcl */
529 PaintHelper::~PaintHelper()
531 WindowImpl
* pWindowImpl
= m_pWindow
->ImplGetWindowImpl();
534 m_pWindow
->PopPaintHelper(this);
537 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
538 if ( m_nPaintFlags
& (ImplPaintFlags::PaintAllChildren
| ImplPaintFlags::PaintChildren
) )
540 // Paint from the bottom child window and frontward.
541 vcl::Window
* pTempWindow
= pWindowImpl
->mpLastChild
;
544 if (pTempWindow
->mpWindowImpl
->mbVisible
)
545 pTempWindow
->ImplCallPaint(m_pChildRegion
.get(), m_nPaintFlags
);
546 pTempWindow
= pTempWindow
->mpWindowImpl
->mpPrev
;
550 if ( pWindowImpl
->mpWinData
&& pWindowImpl
->mbTrackVisible
&& (pWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
551 /* #98602# need to invert the tracking rect AFTER
552 * the children have painted
554 m_pWindow
->InvertTracking( *pWindowImpl
->mpWinData
->mpTrackRect
, pWindowImpl
->mpWinData
->mnTrackFlags
);
556 // double-buffering: paint in case we created the buffer, the children are
557 // already painted inside
558 if (m_bStartedBufferedPaint
&& pFrameData
->mbInBufferedPaint
)
561 pFrameData
->mbInBufferedPaint
= false;
562 pFrameData
->maBufferedRect
= tools::Rectangle();
565 // #98943# draw toolbox selection
566 if( !m_aSelectionRect
.IsEmpty() )
567 m_pWindow
->DrawSelectionBackground( m_aSelectionRect
, 3, false, true );
572 void Window::ImplCallPaint(const vcl::Region
* pRegion
, ImplPaintFlags nPaintFlags
)
574 // call PrePaint. PrePaint may add to the invalidate region as well as
575 // other parameters used below.
578 mpWindowImpl
->mbPaintFrame
= false;
580 if (nPaintFlags
& ImplPaintFlags::PaintAllChildren
)
581 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Paint
| ImplPaintFlags::PaintAllChildren
| (nPaintFlags
& ImplPaintFlags::PaintAll
);
582 if (nPaintFlags
& ImplPaintFlags::PaintChildren
)
583 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintChildren
;
584 if (nPaintFlags
& ImplPaintFlags::Erase
)
585 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Erase
;
586 if (nPaintFlags
& ImplPaintFlags::CheckRtl
)
587 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::CheckRtl
;
588 if (!mpWindowImpl
->mpFirstChild
)
589 mpWindowImpl
->mnPaintFlags
&= ~ImplPaintFlags::PaintAllChildren
;
591 if (mpWindowImpl
->mbPaintDisabled
)
593 if (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
594 Invalidate(InvalidateFlags::NoChildren
| InvalidateFlags::NoErase
| InvalidateFlags::NoTransparent
| InvalidateFlags::NoClipChildren
);
596 Invalidate(*pRegion
, InvalidateFlags::NoChildren
| InvalidateFlags::NoErase
| InvalidateFlags::NoTransparent
| InvalidateFlags::NoClipChildren
);
598 // call PostPaint before returning
604 nPaintFlags
= mpWindowImpl
->mnPaintFlags
& ~ImplPaintFlags::Paint
;
606 PaintHelper
aHelper(this, nPaintFlags
);
608 if (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::Paint
)
609 aHelper
.DoPaint(pRegion
);
611 mpWindowImpl
->mnPaintFlags
= ImplPaintFlags::NONE
;
617 void Window::ImplCallOverlapPaint()
619 // emit overlapping windows first
620 vcl::Window
* pTempWindow
= mpWindowImpl
->mpFirstOverlap
;
621 while ( pTempWindow
)
623 if ( pTempWindow
->mpWindowImpl
->mbReallyVisible
)
624 pTempWindow
->ImplCallOverlapPaint();
625 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
629 if ( mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintChildren
) )
631 // RTL: notify ImplCallPaint to check for re-mirroring
632 // because we were called from the Sal layer
633 ImplCallPaint(nullptr, mpWindowImpl
->mnPaintFlags
/*| ImplPaintFlags::CheckRtl */);
637 IMPL_LINK_NOARG(Window
, ImplHandlePaintHdl
, Timer
*, void)
639 comphelper::ProfileZone
aZone("VCL idle re-paint");
641 // save paint events until layout is done
642 if (IsSystemWindow() && static_cast<const SystemWindow
*>(this)->hasPendingLayout())
644 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
648 // save paint events until resizing or initial sizing done
649 if (mpWindowImpl
->mbFrame
&&
650 mpWindowImpl
->mpFrameData
->maResizeIdle
.IsActive())
652 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
654 else if ( mpWindowImpl
->mbReallyVisible
)
656 ImplCallOverlapPaint();
657 if (comphelper::LibreOfficeKit::isActive() &&
658 mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive())
659 mpWindowImpl
->mpFrameData
->maPaintIdle
.Stop();
663 IMPL_LINK_NOARG(Window
, ImplHandleResizeTimerHdl
, Timer
*, void)
665 comphelper::ProfileZone
aZone("VCL idle resize");
667 if( mpWindowImpl
->mbReallyVisible
)
670 if( mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive() )
672 mpWindowImpl
->mpFrameData
->maPaintIdle
.Stop();
673 mpWindowImpl
->mpFrameData
->maPaintIdle
.Invoke( nullptr );
678 void Window::ImplInvalidateFrameRegion( const vcl::Region
* pRegion
, InvalidateFlags nFlags
)
680 // set PAINTCHILDREN for all parent windows till the first OverlapWindow
681 if ( !ImplIsOverlapWindow() )
683 vcl::Window
* pTempWindow
= this;
684 ImplPaintFlags nTranspPaint
= IsPaintTransparent() ? ImplPaintFlags::Paint
: ImplPaintFlags::NONE
;
687 pTempWindow
= pTempWindow
->ImplGetParent();
688 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintChildren
)
690 pTempWindow
->mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintChildren
| nTranspPaint
;
691 if( ! pTempWindow
->IsPaintTransparent() )
692 nTranspPaint
= ImplPaintFlags::NONE
;
694 while ( !pTempWindow
->ImplIsOverlapWindow() );
698 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Paint
;
699 if ( nFlags
& InvalidateFlags::Children
)
700 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintAllChildren
;
701 if ( !(nFlags
& InvalidateFlags::NoErase
) )
702 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Erase
;
705 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintAll
;
706 else if ( !(mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
) )
708 // if not everything has to be redrawn, add the region to it
709 mpWindowImpl
->maInvalidateRegion
.Union( *pRegion
);
712 // Handle transparent windows correctly: invalidate must be done on the first opaque parent
713 if( ((IsPaintTransparent() && !(nFlags
& InvalidateFlags::NoTransparent
)) || (nFlags
& InvalidateFlags::Transparent
) )
716 vcl::Window
*pParent
= ImplGetParent();
717 while( pParent
&& pParent
->IsPaintTransparent() )
718 pParent
= pParent
->ImplGetParent();
721 vcl::Region
*pChildRegion
;
722 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
723 // invalidate the whole child window region in the parent
724 pChildRegion
= ImplGetWinChildClipRegion();
726 // invalidate the same region in the parent that has to be repainted in the child
727 pChildRegion
= &mpWindowImpl
->maInvalidateRegion
;
729 nFlags
|= InvalidateFlags::Children
; // paint should also be done on all children
730 nFlags
&= ~InvalidateFlags::NoErase
; // parent should paint and erase to create proper background
731 pParent
->ImplInvalidateFrameRegion( pChildRegion
, nFlags
);
735 if ( !mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive() )
736 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
739 void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region
& rRegion
)
741 vcl::Region aRegion
= rRegion
;
743 ImplClipBoundaries( aRegion
, true, true );
744 if ( !aRegion
.IsEmpty() )
745 ImplInvalidateFrameRegion( &aRegion
, InvalidateFlags::Children
);
747 // now we invalidate the overlapping windows
748 vcl::Window
* pTempWindow
= mpWindowImpl
->mpFirstOverlap
;
749 while ( pTempWindow
)
751 if ( pTempWindow
->IsVisible() )
752 pTempWindow
->ImplInvalidateOverlapFrameRegion( rRegion
);
754 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
758 void Window::ImplInvalidateParentFrameRegion( vcl::Region
& rRegion
)
760 if ( mpWindowImpl
->mbOverlapWin
)
761 mpWindowImpl
->mpFrameWindow
->ImplInvalidateOverlapFrameRegion( rRegion
);
764 if( ImplGetParent() )
765 ImplGetParent()->ImplInvalidateFrameRegion( &rRegion
, InvalidateFlags::Children
);
769 void Window::ImplInvalidate( const vcl::Region
* pRegion
, InvalidateFlags nFlags
)
771 // check what has to be redrawn
772 bool bInvalidateAll
= !pRegion
;
774 // take Transparent-Invalidate into account
775 vcl::Window
* pOpaqueWindow
= this;
776 if ( (mpWindowImpl
->mbPaintTransparent
&& !(nFlags
& InvalidateFlags::NoTransparent
)) || (nFlags
& InvalidateFlags::Transparent
) )
778 vcl::Window
* pTempWindow
= pOpaqueWindow
->ImplGetParent();
779 while ( pTempWindow
)
781 if ( !pTempWindow
->IsPaintTransparent() )
783 pOpaqueWindow
= pTempWindow
;
784 nFlags
|= InvalidateFlags::Children
;
785 bInvalidateAll
= false;
789 if ( pTempWindow
->ImplIsOverlapWindow() )
792 pTempWindow
= pTempWindow
->ImplGetParent();
797 InvalidateFlags nOrgFlags
= nFlags
;
798 if ( !(nFlags
& (InvalidateFlags::Children
| InvalidateFlags::NoChildren
)) )
800 if ( GetStyle() & WB_CLIPCHILDREN
)
801 nFlags
|= InvalidateFlags::NoChildren
;
803 nFlags
|= InvalidateFlags::Children
;
805 if ( (nFlags
& InvalidateFlags::NoChildren
) && mpWindowImpl
->mpFirstChild
)
806 bInvalidateAll
= false;
807 if ( bInvalidateAll
)
808 ImplInvalidateFrameRegion( nullptr, nFlags
);
811 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
812 vcl::Region
aRegion( aRect
);
815 // RTL: remirror region before intersecting it
816 if ( ImplIsAntiparallel() )
818 const OutputDevice
*pOutDev
= GetOutDev();
820 vcl::Region
aRgn( *pRegion
);
821 pOutDev
->ReMirror( aRgn
);
822 aRegion
.Intersect( aRgn
);
825 aRegion
.Intersect( *pRegion
);
827 ImplClipBoundaries( aRegion
, true, true );
828 if ( nFlags
& InvalidateFlags::NoChildren
)
830 nFlags
&= ~InvalidateFlags::Children
;
831 if ( !(nFlags
& InvalidateFlags::NoClipChildren
) )
833 if ( nOrgFlags
& InvalidateFlags::NoChildren
)
834 ImplClipAllChildren( aRegion
);
837 if ( ImplClipChildren( aRegion
) )
838 nFlags
|= InvalidateFlags::Children
;
842 if ( !aRegion
.IsEmpty() )
843 ImplInvalidateFrameRegion( &aRegion
, nFlags
); // transparency is handled here, pOpaqueWindow not required
846 if ( nFlags
& InvalidateFlags::Update
)
847 pOpaqueWindow
->Update(); // start painting at the opaque parent
850 void Window::ImplMoveInvalidateRegion( const tools::Rectangle
& rRect
,
851 long nHorzScroll
, long nVertScroll
,
854 if ( (mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintAll
)) == ImplPaintFlags::Paint
)
856 vcl::Region aTempRegion
= mpWindowImpl
->maInvalidateRegion
;
857 aTempRegion
.Intersect( rRect
);
858 aTempRegion
.Move( nHorzScroll
, nVertScroll
);
859 mpWindowImpl
->maInvalidateRegion
.Union( aTempRegion
);
862 if ( bChildren
&& (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintChildren
) )
864 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstChild
;
867 pWindow
->ImplMoveInvalidateRegion( rRect
, nHorzScroll
, nVertScroll
, true );
868 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
873 void Window::ImplMoveAllInvalidateRegions( const tools::Rectangle
& rRect
,
874 long nHorzScroll
, long nVertScroll
,
877 // also shift Paint-Region when paints need processing
878 ImplMoveInvalidateRegion( rRect
, nHorzScroll
, nVertScroll
, bChildren
);
879 // Paint-Region should be shifted, as drawn by the parents
880 if ( !ImplIsOverlapWindow() )
882 vcl::Region aPaintAllRegion
;
883 vcl::Window
* pPaintAllWindow
= this;
886 pPaintAllWindow
= pPaintAllWindow
->ImplGetParent();
887 if ( pPaintAllWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
889 if ( pPaintAllWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
891 aPaintAllRegion
.SetEmpty();
895 aPaintAllRegion
.Union( pPaintAllWindow
->mpWindowImpl
->maInvalidateRegion
);
898 while ( !pPaintAllWindow
->ImplIsOverlapWindow() );
899 if ( !aPaintAllRegion
.IsEmpty() )
901 aPaintAllRegion
.Move( nHorzScroll
, nVertScroll
);
902 InvalidateFlags nPaintFlags
= InvalidateFlags::NONE
;
904 nPaintFlags
|= InvalidateFlags::Children
;
905 ImplInvalidateFrameRegion( &aPaintAllRegion
, nPaintFlags
);
910 void Window::ImplValidateFrameRegion( const vcl::Region
* pRegion
, ValidateFlags nFlags
)
913 mpWindowImpl
->maInvalidateRegion
.SetEmpty();
916 // when all child windows have to be drawn we need to invalidate them before doing so
917 if ( (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
) && mpWindowImpl
->mpFirstChild
)
919 vcl::Region aChildRegion
= mpWindowImpl
->maInvalidateRegion
;
920 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
922 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
923 aChildRegion
= aRect
;
925 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
928 pChild
->Invalidate( aChildRegion
, InvalidateFlags::Children
| InvalidateFlags::NoTransparent
);
929 pChild
= pChild
->mpWindowImpl
->mpNext
;
932 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
934 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
935 mpWindowImpl
->maInvalidateRegion
= aRect
;
937 mpWindowImpl
->maInvalidateRegion
.Exclude( *pRegion
);
939 mpWindowImpl
->mnPaintFlags
&= ~ImplPaintFlags::PaintAll
;
941 if ( nFlags
& ValidateFlags::Children
)
943 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
946 pChild
->ImplValidateFrameRegion( pRegion
, nFlags
);
947 pChild
= pChild
->mpWindowImpl
->mpNext
;
952 void Window::ImplValidate()
955 bool bValidateAll
= true;
956 ValidateFlags nFlags
= ValidateFlags::NONE
;
957 if ( GetStyle() & WB_CLIPCHILDREN
)
958 nFlags
|= ValidateFlags::NoChildren
;
960 nFlags
|= ValidateFlags::Children
;
961 if ( (nFlags
& ValidateFlags::NoChildren
) && mpWindowImpl
->mpFirstChild
)
962 bValidateAll
= false;
964 ImplValidateFrameRegion( nullptr, nFlags
);
967 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
968 vcl::Region
aRegion( aRect
);
969 ImplClipBoundaries( aRegion
, true, true );
970 if ( nFlags
& ValidateFlags::NoChildren
)
972 nFlags
&= ~ValidateFlags::Children
;
973 if ( ImplClipChildren( aRegion
) )
974 nFlags
|= ValidateFlags::Children
;
976 if ( !aRegion
.IsEmpty() )
977 ImplValidateFrameRegion( &aRegion
, nFlags
);
981 void Window::ImplUpdateAll()
983 if ( !mpWindowImpl
->mbReallyVisible
)
987 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
989 Point
aPoint( 0, 0 );
990 vcl::Region
aRegion( tools::Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
991 ImplInvalidateOverlapFrameRegion( aRegion
);
992 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
996 // an update changes the OverlapWindow, such that for later paints
997 // not too much has to be drawn, if ALLCHILDREN etc. is set
998 vcl::Window
* pWindow
= ImplGetFirstOverlapWindow();
999 pWindow
->ImplCallOverlapPaint();
1005 void Window::PrePaint(vcl::RenderContext
& /*rRenderContext*/)
1009 void Window::PostPaint(vcl::RenderContext
& /*rRenderContext*/)
1013 void Window::Paint(vcl::RenderContext
& /*rRenderContext*/, const tools::Rectangle
& rRect
)
1015 CallEventListeners(VclEventId::WindowPaint
, const_cast<tools::Rectangle
*>(&rRect
));
1018 void Window::SetPaintTransparent( bool bTransparent
)
1020 // transparency is not useful for frames as the background would have to be provided by a different frame
1021 if( bTransparent
&& mpWindowImpl
->mbFrame
)
1024 if ( mpWindowImpl
->mpBorderWindow
)
1025 mpWindowImpl
->mpBorderWindow
->SetPaintTransparent( bTransparent
);
1027 mpWindowImpl
->mbPaintTransparent
= bTransparent
;
1030 void Window::SetWindowRegionPixel()
1033 if ( mpWindowImpl
->mpBorderWindow
)
1034 mpWindowImpl
->mpBorderWindow
->SetWindowRegionPixel();
1035 else if( mpWindowImpl
->mbFrame
)
1037 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1038 mpWindowImpl
->mbWinRegion
= false;
1039 mpWindowImpl
->mpFrame
->ResetClipRegion();
1043 if ( mpWindowImpl
->mbWinRegion
)
1045 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1046 mpWindowImpl
->mbWinRegion
= false;
1049 if ( IsReallyVisible() )
1051 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
1052 vcl::Region
aRegion( aRect
);
1053 ImplInvalidateParentFrameRegion( aRegion
);
1059 void Window::SetWindowRegionPixel( const vcl::Region
& rRegion
)
1062 if ( mpWindowImpl
->mpBorderWindow
)
1063 mpWindowImpl
->mpBorderWindow
->SetWindowRegionPixel( rRegion
);
1064 else if( mpWindowImpl
->mbFrame
)
1066 if( !rRegion
.IsNull() )
1068 mpWindowImpl
->maWinRegion
= rRegion
;
1069 mpWindowImpl
->mbWinRegion
= ! rRegion
.IsEmpty();
1071 if( mpWindowImpl
->mbWinRegion
)
1073 // set/update ClipRegion
1074 RectangleVector aRectangles
;
1075 mpWindowImpl
->maWinRegion
.GetRegionRectangles(aRectangles
);
1076 mpWindowImpl
->mpFrame
->BeginSetClipRegion(aRectangles
.size());
1078 for (auto const& rectangle
: aRectangles
)
1080 mpWindowImpl
->mpFrame
->UnionClipRegion(
1083 rectangle
.GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
1084 rectangle
.GetHeight()); // same for height
1087 mpWindowImpl
->mpFrame
->EndSetClipRegion();
1093 //sal_uLong nRectCount;
1094 //ImplRegionInfo aInfo;
1095 //sal_Bool bRegionRect;
1097 //nRectCount = mpWindowImpl->maWinRegion.GetRectCount();
1098 //mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount );
1099 //bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
1100 //while ( bRegionRect )
1102 // mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight );
1103 // bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
1105 //mpWindowImpl->mpFrame->EndSetClipRegion();
1108 SetWindowRegionPixel();
1111 SetWindowRegionPixel();
1115 if ( rRegion
.IsNull() )
1117 if ( mpWindowImpl
->mbWinRegion
)
1119 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1120 mpWindowImpl
->mbWinRegion
= false;
1126 mpWindowImpl
->maWinRegion
= rRegion
;
1127 mpWindowImpl
->mbWinRegion
= true;
1131 if ( IsReallyVisible() )
1133 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
1134 vcl::Region
aRegion( aRect
);
1135 ImplInvalidateParentFrameRegion( aRegion
);
1140 vcl::Region
Window::GetPaintRegion() const
1143 if ( mpWindowImpl
->mpPaintRegion
)
1145 vcl::Region aRegion
= *mpWindowImpl
->mpPaintRegion
;
1146 aRegion
.Move( -mnOutOffX
, -mnOutOffY
);
1147 return PixelToLogic( aRegion
);
1151 vcl::Region
aPaintRegion(true);
1152 return aPaintRegion
;
1156 void Window::Invalidate( InvalidateFlags nFlags
)
1158 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1161 ImplInvalidate( nullptr, nFlags
);
1162 LogicInvalidate(nullptr);
1165 void Window::Invalidate( const tools::Rectangle
& rRect
, InvalidateFlags nFlags
)
1167 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1170 OutputDevice
*pOutDev
= GetOutDev();
1171 tools::Rectangle aRect
= pOutDev
->ImplLogicToDevicePixel( rRect
);
1172 if ( !aRect
.IsEmpty() )
1174 vcl::Region
aRegion( aRect
);
1175 ImplInvalidate( &aRegion
, nFlags
);
1176 tools::Rectangle
aLogicRectangle(rRect
);
1177 LogicInvalidate(&aLogicRectangle
);
1181 void Window::Invalidate( const vcl::Region
& rRegion
, InvalidateFlags nFlags
)
1183 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1186 if ( rRegion
.IsNull() )
1188 ImplInvalidate( nullptr, nFlags
);
1189 LogicInvalidate(nullptr);
1193 vcl::Region aRegion
= ImplPixelToDevicePixel( LogicToPixel( rRegion
) );
1194 if ( !aRegion
.IsEmpty() )
1196 ImplInvalidate( &aRegion
, nFlags
);
1197 tools::Rectangle aLogicRectangle
= rRegion
.GetBoundRect();
1198 LogicInvalidate(&aLogicRectangle
);
1203 void Window::LogicInvalidate(const tools::Rectangle
* pRectangle
)
1207 tools::Rectangle aRect
= GetOutDev()->ImplLogicToDevicePixel( *pRectangle
);
1208 PixelInvalidate(&aRect
);
1211 PixelInvalidate(nullptr);
1214 void Window::PixelInvalidate(const tools::Rectangle
* pRectangle
)
1216 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1219 if (const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
1221 // In case we are routing the window, notify the client
1222 std::vector
<vcl::LOKPayloadItem
> aPayload
;
1224 aPayload
.push_back(std::make_pair(OString("rectangle"), pRectangle
->toString()));
1227 const tools::Rectangle
aRect(Point(0, 0), GetSizePixel());
1228 aPayload
.push_back(std::make_pair(OString("rectangle"), aRect
.toString()));
1231 pNotifier
->notifyWindow(GetLOKWindowId(), "invalidate", aPayload
);
1233 // Added for dialog items. Pass invalidation to the parent window.
1234 else if (VclPtr
<vcl::Window
> pParent
= GetParentWithLOKNotifier())
1236 const tools::Rectangle
aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1237 pParent
->PixelInvalidate(&aRect
);
1241 void Window::Validate()
1243 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1249 bool Window::HasPaintEvent() const
1252 if ( !mpWindowImpl
->mbReallyVisible
)
1255 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1258 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::Paint
)
1261 if ( !ImplIsOverlapWindow() )
1263 const vcl::Window
* pTempWindow
= this;
1266 pTempWindow
= pTempWindow
->ImplGetParent();
1267 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::PaintChildren
| ImplPaintFlags::PaintAllChildren
) )
1270 while ( !pTempWindow
->ImplIsOverlapWindow() );
1276 void Window::Update()
1278 if ( mpWindowImpl
->mpBorderWindow
)
1280 mpWindowImpl
->mpBorderWindow
->Update();
1284 if ( !mpWindowImpl
->mbReallyVisible
)
1287 bool bFlush
= false;
1288 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1290 Point
aPoint( 0, 0 );
1291 vcl::Region
aRegion( tools::Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
1292 ImplInvalidateOverlapFrameRegion( aRegion
);
1293 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
1297 // First we should skip all windows which are Paint-Transparent
1298 vcl::Window
* pUpdateWindow
= this;
1299 vcl::Window
* pWindow
= pUpdateWindow
;
1300 while ( !pWindow
->ImplIsOverlapWindow() )
1302 if ( !pWindow
->mpWindowImpl
->mbPaintTransparent
)
1304 pUpdateWindow
= pWindow
;
1307 pWindow
= pWindow
->ImplGetParent();
1309 // In order to limit drawing, an update only draws the window which
1310 // has PAINTALLCHILDREN set
1311 pWindow
= pUpdateWindow
;
1314 if ( pWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
1315 pUpdateWindow
= pWindow
;
1316 if ( pWindow
->ImplIsOverlapWindow() )
1318 pWindow
= pWindow
->ImplGetParent();
1322 // if there is something to paint, trigger a Paint
1323 if ( pUpdateWindow
->mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintChildren
) )
1325 VclPtr
<vcl::Window
> xWindow(this);
1327 // trigger an update also for system windows on top of us,
1328 // otherwise holes would remain
1329 vcl::Window
* pUpdateOverlapWindow
= ImplGetFirstOverlapWindow()->mpWindowImpl
->mpFirstOverlap
;
1330 while ( pUpdateOverlapWindow
)
1332 pUpdateOverlapWindow
->Update();
1333 pUpdateOverlapWindow
= pUpdateOverlapWindow
->mpWindowImpl
->mpNext
;
1336 pUpdateWindow
->ImplCallPaint(nullptr, pUpdateWindow
->mpWindowImpl
->mnPaintFlags
);
1338 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow
->GetParentDialog())
1339 pUpdateWindow
->LogicInvalidate(nullptr);
1341 if (xWindow
->IsDisposed())
1351 void Window::ImplPaintToDevice( OutputDevice
* i_pTargetOutDev
, const Point
& i_rPos
)
1353 // Special drawing when called through LOKit
1354 // TODO: Move to its own method
1355 if (comphelper::LibreOfficeKit::isActive())
1357 VclPtrInstance
<VirtualDevice
> pDevice(*i_pTargetOutDev
);
1359 Size
aSize(GetOutputSizePixel());
1360 pDevice
->SetOutputSizePixel(aSize
);
1362 vcl::Font aCopyFont
= GetFont();
1363 pDevice
->SetFont(aCopyFont
);
1365 pDevice
->SetTextColor(GetTextColor());
1367 pDevice
->SetLineColor(GetLineColor());
1369 pDevice
->SetLineColor();
1372 pDevice
->SetFillColor(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(GetRasterOp());
1394 tools::Rectangle
aPaintRect(Point(), GetOutputSizePixel());
1396 vcl::Region
aClipRegion(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 // get rid of virtual device now so they don't pile up during recursive calls
1411 pDevice
.disposeAndClear();
1414 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1416 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1418 long nDeltaX
= pChild
->mnOutOffX
- mnOutOffX
;
1419 long nDeltaY
= pChild
->mnOutOffY
- mnOutOffY
;
1421 Point
aPos( i_rPos
);
1422 aPos
+= Point(nDeltaX
, nDeltaY
);
1424 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1431 bool bRVisible
= mpWindowImpl
->mbReallyVisible
;
1432 mpWindowImpl
->mbReallyVisible
= mpWindowImpl
->mbVisible
;
1433 bool bDevOutput
= mbDevOutput
;
1436 const OutputDevice
*pOutDev
= GetOutDev();
1437 long nOldDPIX
= pOutDev
->GetDPIX();
1438 long nOldDPIY
= pOutDev
->GetDPIY();
1439 mnDPIX
= i_pTargetOutDev
->GetDPIX();
1440 mnDPIY
= i_pTargetOutDev
->GetDPIY();
1441 bool bOutput
= IsOutputEnabled();
1446 bool bNeedsScaling
= false;
1447 if(comphelper::LibreOfficeKit::isActive())
1449 if(GetMapMode().GetMapUnit() != MapUnit::MapPixel
&&
1450 // Some of the preview windows (SvxPreviewBase) uses different painting (drawinglayer primitives)
1451 // For these preview we don't need to scale even though the unit is not pixel.
1452 GetMapMode().GetMapUnit() != MapUnit::Map100thMM
)
1454 bNeedsScaling
= true;
1455 // 1000.0 is used to reduce rounding imprecision (Size uses integers)
1456 Size aLogicSize
= PixelToLogic(Size(1000.0, 1000.0));
1457 fScaleX
= aLogicSize
.Width() / 1000.0;
1458 fScaleY
= aLogicSize
.Height() / 1000.0;
1462 { // TODO: Above scaling was added for LOK only, would be good to check how it works in other use cases
1463 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel
, "vcl.window", "MapMode must be PIXEL based" );
1464 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel
)
1468 // preserve graphicsstate
1470 vcl::Region
aClipRegion( GetClipRegion() );
1473 GDIMetaFile
* pOldMtf
= GetConnectMetaFile();
1475 SetConnectMetaFile( &aMtf
);
1477 // put a push action to metafile
1479 // copy graphics state to metafile
1480 vcl::Font aCopyFont
= GetFont();
1481 if( nOldDPIX
!= mnDPIX
|| nOldDPIY
!= mnDPIY
)
1483 aCopyFont
.SetFontHeight( aCopyFont
.GetFontHeight() * mnDPIY
/ nOldDPIY
);
1484 aCopyFont
.SetAverageFontWidth( aCopyFont
.GetAverageFontWidth() * mnDPIX
/ nOldDPIX
);
1486 SetFont( aCopyFont
);
1487 SetTextColor( GetTextColor() );
1489 SetLineColor( GetLineColor() );
1493 SetFillColor( GetFillColor() );
1496 if( IsTextLineColor() )
1497 SetTextLineColor( GetTextLineColor() );
1500 if( IsOverlineColor() )
1501 SetOverlineColor( GetOverlineColor() );
1504 if( IsTextFillColor() )
1505 SetTextFillColor( GetTextFillColor() );
1508 SetTextAlign( GetTextAlign() );
1509 SetRasterOp( GetRasterOp() );
1511 SetRefPoint( GetRefPoint() );
1514 SetLayoutMode( GetLayoutMode() );
1515 SetDigitLanguage( GetDigitLanguage() );
1517 tools::Rectangle aPaintRect
;
1520 aPaintRect
= tools::Rectangle( Point( 0, 0 ),
1521 Size(GetOutputSizePixel().Width() * fScaleX
, GetOutputSizePixel().Height() * fScaleY
) );
1525 aPaintRect
= tools::Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
1527 aClipRegion
.Intersect( aPaintRect
);
1528 SetClipRegion( aClipRegion
);
1530 // do the actual paint
1533 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip
) )
1537 aMtf
.Scale(fScaleX
, fScaleY
);
1540 Paint(*this, aPaintRect
);
1541 // put a pop action to metafile
1544 SetConnectMetaFile( pOldMtf
);
1545 EnableOutput( bOutput
);
1546 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1548 // paint metafile to VDev
1549 VclPtrInstance
<VirtualDevice
> pMaskedDevice(*i_pTargetOutDev
,
1550 DeviceFormat::DEFAULT
,
1551 DeviceFormat::DEFAULT
);
1554 pMaskedDevice
->SetMapMode( GetMapMode() );
1555 pMaskedDevice
->SetOutputSizePixel( GetOutputSizePixel() );
1556 pMaskedDevice
->EnableRTL( IsRTLEnabled() );
1558 aMtf
.Play( pMaskedDevice
);
1559 BitmapEx
aBmpEx( pMaskedDevice
->GetBitmapEx( Point( 0, 0 ), aPaintRect
.GetSize() ) );
1560 i_pTargetOutDev
->DrawBitmapEx( i_rPos
, aBmpEx
);
1561 // get rid of virtual device now so they don't pile up during recursive calls
1562 pMaskedDevice
.disposeAndClear();
1564 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1566 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1568 long nDeltaX
= pChild
->mnOutOffX
- mnOutOffX
;
1570 if( pOutDev
->HasMirroredGraphics() )
1571 nDeltaX
= mnOutWidth
- nDeltaX
- pChild
->mnOutWidth
;
1572 long nDeltaY
= pChild
->GetOutOffYPixel() - GetOutOffYPixel();
1573 Point
aPos( i_rPos
);
1574 Point
aDelta( nDeltaX
, nDeltaY
);
1576 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1580 // restore graphics state
1583 EnableOutput( bOutput
);
1584 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1585 mbDevOutput
= bDevOutput
;
1590 void Window::PaintToDevice( OutputDevice
* pDev
, const Point
& rPos
, const Size
& /*rSize*/ )
1592 SAL_WARN_IF( pDev
->HasMirroredGraphics(), "vcl.window", "PaintToDevice to mirroring graphics" );
1593 SAL_WARN_IF( pDev
->IsRTLEnabled(), "vcl.window", "PaintToDevice to mirroring device" );
1595 vcl::Window
* pRealParent
= nullptr;
1596 if( ! mpWindowImpl
->mbVisible
)
1598 vcl::Window
* pTempParent
= ImplGetDefaultWindow();
1599 pTempParent
->EnableChildTransparentMode();
1600 pRealParent
= GetParent();
1601 SetParent( pTempParent
);
1602 // trigger correct visibility flags for children
1607 bool bVisible
= mpWindowImpl
->mbVisible
;
1608 mpWindowImpl
->mbVisible
= true;
1610 if( mpWindowImpl
->mpBorderWindow
)
1611 mpWindowImpl
->mpBorderWindow
->ImplPaintToDevice( pDev
, rPos
);
1613 ImplPaintToDevice( pDev
, rPos
);
1615 mpWindowImpl
->mbVisible
= bVisible
;
1618 SetParent( pRealParent
);
1621 void Window::Erase(vcl::RenderContext
& rRenderContext
)
1623 if (!IsDeviceOutputNecessary() || ImplIsRecordLayout())
1626 bool bNativeOK
= false;
1628 ControlPart aCtrlPart
= ImplGetWindowImpl()->mnNativeBackground
;
1629 if (aCtrlPart
!= ControlPart::NONE
&& ! IsControlBackground())
1631 tools::Rectangle
aCtrlRegion(Point(), GetOutputSizePixel());
1632 ControlState nState
= ControlState::NONE
;
1635 nState
|= ControlState::ENABLED
;
1637 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::WindowBackground
, aCtrlPart
, aCtrlRegion
,
1638 nState
, ImplControlValue(), OUString());
1641 if (mbBackground
&& !bNativeOK
)
1643 RasterOp eRasterOp
= GetRasterOp();
1644 if (eRasterOp
!= RasterOp::OverPaint
)
1645 SetRasterOp(RasterOp::OverPaint
);
1646 rRenderContext
.DrawWallpaper(0, 0, mnOutWidth
, mnOutHeight
, maBackground
);
1647 if (eRasterOp
!= RasterOp::OverPaint
)
1648 rRenderContext
.SetRasterOp(eRasterOp
);
1652 mpAlphaVDev
->Erase();
1655 void Window::ImplScroll( const tools::Rectangle
& rRect
,
1656 long nHorzScroll
, long nVertScroll
, ScrollFlags nFlags
)
1658 if ( !IsDeviceOutputNecessary() )
1661 nHorzScroll
= ImplLogicWidthToDevicePixel( nHorzScroll
);
1662 nVertScroll
= ImplLogicHeightToDevicePixel( nVertScroll
);
1664 if ( !nHorzScroll
&& !nVertScroll
)
1667 if ( mpWindowImpl
->mpCursor
)
1668 mpWindowImpl
->mpCursor
->ImplSuspend();
1670 ScrollFlags nOrgFlags
= nFlags
;
1671 if ( !(nFlags
& (ScrollFlags::Children
| ScrollFlags::NoChildren
)) )
1673 if ( GetStyle() & WB_CLIPCHILDREN
)
1674 nFlags
|= ScrollFlags::NoChildren
;
1676 nFlags
|= ScrollFlags::Children
;
1679 vcl::Region aInvalidateRegion
;
1680 bool bScrollChildren(nFlags
& ScrollFlags::Children
);
1682 if ( !mpWindowImpl
->mpFirstChild
)
1683 bScrollChildren
= false;
1685 OutputDevice
*pOutDev
= GetOutDev();
1687 // RTL: check if this window requires special action
1688 bool bReMirror
= ImplIsAntiparallel();
1690 tools::Rectangle
aRectMirror( rRect
);
1693 // make sure the invalidate region of this window is
1694 // computed in the same coordinate space as the one from the overlap windows
1695 pOutDev
->ReMirror( aRectMirror
);
1698 // adapt paint areas
1699 ImplMoveAllInvalidateRegions( aRectMirror
, nHorzScroll
, nVertScroll
, bScrollChildren
);
1701 ImplCalcOverlapRegion( aRectMirror
, aInvalidateRegion
, !bScrollChildren
, false );
1703 // if the scrolling on the device is performed in the opposite direction
1704 // then move the overlaps in that direction to compute the invalidate region
1705 // on the correct side, i.e., revert nHorzScroll
1706 if (!aInvalidateRegion
.IsEmpty())
1708 aInvalidateRegion
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1711 tools::Rectangle
aDestRect(aRectMirror
);
1712 aDestRect
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1713 vcl::Region
aWinInvalidateRegion(aRectMirror
);
1714 if (!SupportsDoubleBuffering())
1716 // There will be no CopyArea() call below, so invalidate the
1717 // whole visible area, not only the smaller one that was just
1719 aWinInvalidateRegion
.Exclude(aDestRect
);
1722 aInvalidateRegion
.Union(aWinInvalidateRegion
);
1724 Point
aPoint( mnOutOffX
, mnOutOffY
);
1725 vcl::Region
aRegion( tools::Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
1726 if ( nFlags
& ScrollFlags::Clip
)
1727 aRegion
.Intersect( rRect
);
1728 if ( mpWindowImpl
->mbWinRegion
)
1729 aRegion
.Intersect( ImplPixelToDevicePixel( mpWindowImpl
->maWinRegion
) );
1731 aRegion
.Exclude( aInvalidateRegion
);
1733 ImplClipBoundaries( aRegion
, false, true );
1734 if ( !bScrollChildren
)
1736 if ( nOrgFlags
& ScrollFlags::NoChildren
)
1737 ImplClipAllChildren( aRegion
);
1739 ImplClipChildren( aRegion
);
1741 if ( mbClipRegion
&& (nFlags
& ScrollFlags::UseClipRegion
) )
1742 aRegion
.Intersect( maRegion
);
1743 if ( !aRegion
.IsEmpty() )
1745 if ( mpWindowImpl
->mpWinData
)
1747 if ( mpWindowImpl
->mbFocusVisible
)
1748 ImplInvertFocus( *mpWindowImpl
->mpWinData
->mpFocusRect
);
1749 if ( mpWindowImpl
->mbTrackVisible
&& (mpWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
1750 InvertTracking( *mpWindowImpl
->mpWinData
->mpTrackRect
, mpWindowImpl
->mpWinData
->mnTrackFlags
);
1753 // This seems completely unnecessary with tiled rendering, and
1754 // causes the "AquaSalGraphics::copyArea() for non-layered
1755 // graphics" message. Presumably we should bypass this on all
1756 // platforms when dealing with a "window" that uses tiled
1757 // rendering at the moment. Unclear how to figure that out,
1758 // though. Also unclear whether we actually could just not
1759 // create a "frame window", whatever that exactly is, in the
1760 // tiled rendering case, or at least for platforms where tiles
1761 // rendering is all there is.
1763 SalGraphics
* pGraphics
= ImplGetFrameGraphics();
1764 // The invalidation area contains the area what would be copied here,
1765 // so avoid copying in case of double buffering.
1766 if (pGraphics
&& !SupportsDoubleBuffering())
1770 pOutDev
->ReMirror( aRegion
);
1773 pOutDev
->SelectClipRegion( aRegion
, pGraphics
);
1774 pGraphics
->CopyArea( rRect
.Left()+nHorzScroll
, rRect
.Top()+nVertScroll
,
1775 rRect
.Left(), rRect
.Top(),
1776 rRect
.GetWidth(), rRect
.GetHeight(),
1780 if ( mpWindowImpl
->mpWinData
)
1782 if ( mpWindowImpl
->mbFocusVisible
)
1783 ImplInvertFocus( *mpWindowImpl
->mpWinData
->mpFocusRect
);
1784 if ( mpWindowImpl
->mbTrackVisible
&& (mpWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
1785 InvertTracking( *mpWindowImpl
->mpWinData
->mpTrackRect
, mpWindowImpl
->mpWinData
->mnTrackFlags
);
1789 if ( !aInvalidateRegion
.IsEmpty() )
1791 // RTL: the invalidate region for this windows is already computed in frame coordinates
1792 // so it has to be re-mirrored before calling the Paint-handler
1793 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::CheckRtl
;
1795 if ( !bScrollChildren
)
1797 if ( nOrgFlags
& ScrollFlags::NoChildren
)
1798 ImplClipAllChildren( aInvalidateRegion
);
1800 ImplClipChildren( aInvalidateRegion
);
1802 ImplInvalidateFrameRegion( &aInvalidateRegion
, InvalidateFlags::Children
);
1805 if ( bScrollChildren
)
1807 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstChild
;
1810 Point aPos
= pWindow
->GetPosPixel();
1811 aPos
+= Point( nHorzScroll
, nVertScroll
);
1812 pWindow
->SetPosPixel( aPos
);
1814 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
1818 if ( nFlags
& ScrollFlags::Update
)
1821 if ( mpWindowImpl
->mpCursor
)
1822 mpWindowImpl
->mpCursor
->ImplResume();
1825 } /* namespace vcl */
1828 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */