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
const 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())
276 #if HAVE_FEATURE_OPENGL
277 VCL_GL_INFO("PaintHelper::DoPaint on " <<
278 typeid( *m_pWindow
).name() << " '" << m_pWindow
->GetText() << "' begin");
280 // double-buffering: setup the buffer if it does not exist
281 if (!pFrameData
->mbInBufferedPaint
&& m_pWindow
->SupportsDoubleBuffering())
282 StartBufferedPaint();
284 // double-buffering: if this window does not support double-buffering,
285 // but we are in the middle of double-buffered paint, we might be
286 // losing information
287 if (pFrameData
->mbInBufferedPaint
&& !m_pWindow
->SupportsDoubleBuffering())
288 SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow
.get()).name());
290 if (pFrameData
->mbInBufferedPaint
&& m_pWindow
->SupportsDoubleBuffering())
293 vcl::PaintBufferGuard
g(pFrameData
, m_pWindow
);
294 m_pWindow
->ApplySettings(*pFrameData
->mpBuffer
);
296 m_pWindow
->PushPaintHelper(this, *pFrameData
->mpBuffer
);
297 m_pWindow
->Paint(*pFrameData
->mpBuffer
, m_aPaintRect
);
298 pFrameData
->maBufferedRect
.Union(m_aPaintRect
);
303 Wallpaper aBackground
= m_pWindow
->GetBackground();
304 m_pWindow
->ApplySettings(*m_pWindow
);
305 // Restore lost bitmap background.
306 if (aBackground
.IsBitmap())
307 m_pWindow
->SetBackground(aBackground
);
308 m_pWindow
->PushPaintHelper(this, *m_pWindow
);
309 m_pWindow
->Paint(*m_pWindow
, m_aPaintRect
);
311 #if HAVE_FEATURE_OPENGL
312 VCL_GL_INFO("PaintHelper::DoPaint end on " <<
313 typeid( *m_pWindow
).name() << " '" << m_pWindow
->GetText() << "'");
321 void RenderTools::DrawSelectionBackground(vcl::RenderContext
& rRenderContext
, vcl::Window
const & rWindow
,
322 const tools::Rectangle
& rRect
, sal_uInt16 nHighlight
,
323 bool bChecked
, bool bDrawBorder
, bool bDrawExtBorderOnly
,
324 Color
* pSelectionTextColor
, long nCornerRadius
, Color
const * pPaintColor
)
329 bool bRoundEdges
= nCornerRadius
> 0;
331 const StyleSettings
& rStyles
= rRenderContext
.GetSettings().GetStyleSettings();
333 // colors used for item highlighting
334 Color
aSelectionBorderColor(pPaintColor
? *pPaintColor
: rStyles
.GetHighlightColor());
335 Color
aSelectionFillColor(aSelectionBorderColor
);
337 bool bDark
= rStyles
.GetFaceColor().IsDark();
338 bool bBright
= ( rStyles
.GetFaceColor() == COL_WHITE
);
340 int c1
= aSelectionBorderColor
.GetLuminance();
341 int c2
= rWindow
.GetBackgroundColor().GetLuminance();
343 if (!bDark
&& !bBright
&& std::abs(c2
- c1
) < (pPaintColor
? 40 : 75))
347 aSelectionFillColor
.RGBtoHSB( h
, s
, b
);
348 if( b
> 50 ) b
-= 40;
350 aSelectionFillColor
= Color::HSBtoRGB( h
, s
, b
);
351 aSelectionBorderColor
= aSelectionFillColor
;
356 if (aSelectionBorderColor
.IsDark())
357 aSelectionBorderColor
.IncreaseLuminance(128);
359 aSelectionBorderColor
.DecreaseLuminance(128);
362 tools::Rectangle
aRect(rRect
);
363 if (bDrawExtBorderOnly
)
365 aRect
.AdjustLeft( -1 );
366 aRect
.AdjustTop( -1 );
367 aRect
.AdjustRight(1 );
368 aRect
.AdjustBottom(1 );
370 rRenderContext
.Push(PushFlags::FILLCOLOR
| PushFlags::LINECOLOR
);
373 rRenderContext
.SetLineColor(bDark
? COL_WHITE
: (bBright
? COL_BLACK
: aSelectionBorderColor
));
375 rRenderContext
.SetLineColor();
377 sal_uInt16 nPercent
= 0;
381 aSelectionFillColor
= COL_BLACK
;
383 nPercent
= 80; // just checked (light)
387 if (bChecked
&& nHighlight
== 2)
390 aSelectionFillColor
= COL_LIGHTGRAY
;
393 aSelectionFillColor
= COL_BLACK
;
394 rRenderContext
.SetLineColor(COL_BLACK
);
398 nPercent
= bRoundEdges
? 40 : 20; // selected, pressed or checked ( very dark )
400 else if (bChecked
|| nHighlight
== 1)
403 aSelectionFillColor
= COL_GRAY
;
406 aSelectionFillColor
= COL_BLACK
;
407 rRenderContext
.SetLineColor(COL_BLACK
);
411 nPercent
= bRoundEdges
? 60 : 35; // selected, pressed or checked ( very dark )
416 aSelectionFillColor
= COL_LIGHTGRAY
;
419 aSelectionFillColor
= COL_BLACK
;
420 rRenderContext
.SetLineColor(COL_BLACK
);
427 nPercent
= 70; // selected ( dark )
431 if (bDark
&& bDrawExtBorderOnly
)
433 rRenderContext
.SetFillColor();
434 if (pSelectionTextColor
)
435 *pSelectionTextColor
= rStyles
.GetHighlightTextColor();
439 rRenderContext
.SetFillColor(aSelectionFillColor
);
440 if (pSelectionTextColor
)
442 Color aTextColor
= rWindow
.IsControlBackground() ? rWindow
.GetControlForeground() : rStyles
.GetButtonTextColor();
443 Color aHLTextColor
= rStyles
.GetHighlightTextColor();
444 int nTextDiff
= std::abs(aSelectionFillColor
.GetLuminance() - aTextColor
.GetLuminance());
445 int nHLDiff
= std::abs(aSelectionFillColor
.GetLuminance() - aHLTextColor
.GetLuminance());
446 *pSelectionTextColor
= (nHLDiff
>= nTextDiff
) ? aHLTextColor
: aTextColor
;
452 rRenderContext
.DrawRect(aRect
);
458 tools::Polygon
aPoly(aRect
, nCornerRadius
, nCornerRadius
);
459 tools::PolyPolygon
aPolyPoly(aPoly
);
460 rRenderContext
.DrawTransparent(aPolyPoly
, nPercent
);
464 tools::Polygon
aPoly(aRect
);
465 tools::PolyPolygon
aPolyPoly(aPoly
);
466 rRenderContext
.DrawTransparent(aPolyPoly
, nPercent
);
470 rRenderContext
.Pop(); // LINECOLOR | FILLCOLOR
473 void Window::PushPaintHelper(PaintHelper
*pHelper
, vcl::RenderContext
& rRenderContext
)
477 if ( mpWindowImpl
->mpCursor
)
478 pHelper
->SetRestoreCursor(mpWindowImpl
->mpCursor
->ImplSuspend());
480 mbInitClipRegion
= true;
481 mpWindowImpl
->mbInPaint
= true;
483 // restore Paint-Region
484 vcl::Region
&rPaintRegion
= pHelper
->GetPaintRegion();
485 rPaintRegion
= mpWindowImpl
->maInvalidateRegion
;
486 tools::Rectangle aPaintRect
= rPaintRegion
.GetBoundRect();
488 // RTL: re-mirror paint rect and region at this window
489 if (ImplIsAntiparallel())
491 rRenderContext
.ReMirror(aPaintRect
);
492 rRenderContext
.ReMirror(rPaintRegion
);
494 aPaintRect
= ImplDevicePixelToLogic(aPaintRect
);
495 mpWindowImpl
->mpPaintRegion
= &rPaintRegion
;
496 mpWindowImpl
->maInvalidateRegion
.SetEmpty();
498 if ((pHelper
->GetPaintFlags() & ImplPaintFlags::Erase
) && rRenderContext
.IsBackground())
500 if (rRenderContext
.IsClipRegion())
502 vcl::Region aOldRegion
= rRenderContext
.GetClipRegion();
503 rRenderContext
.SetClipRegion();
504 Erase(rRenderContext
);
505 rRenderContext
.SetClipRegion(aOldRegion
);
508 Erase(rRenderContext
);
511 // #98943# trigger drawing of toolbox selection after all children are painted
512 if (mpWindowImpl
->mbDrawSelectionBackground
)
513 pHelper
->SetSelectionRect(aPaintRect
);
514 pHelper
->SetPaintRect(aPaintRect
);
517 void Window::PopPaintHelper(PaintHelper
const *pHelper
)
519 if (mpWindowImpl
->mpWinData
)
521 if (mpWindowImpl
->mbFocusVisible
)
522 ImplInvertFocus(*mpWindowImpl
->mpWinData
->mpFocusRect
);
524 mpWindowImpl
->mbInPaint
= false;
525 mbInitClipRegion
= true;
526 mpWindowImpl
->mpPaintRegion
= nullptr;
527 if (mpWindowImpl
->mpCursor
)
528 mpWindowImpl
->mpCursor
->ImplResume(pHelper
->GetRestoreCursor());
531 } /* namespace vcl */
533 PaintHelper::~PaintHelper()
535 WindowImpl
* pWindowImpl
= m_pWindow
->ImplGetWindowImpl();
538 m_pWindow
->PopPaintHelper(this);
541 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
542 if ( m_nPaintFlags
& (ImplPaintFlags::PaintAllChildren
| ImplPaintFlags::PaintChildren
) )
544 // Paint from the bottom child window and frontward.
545 vcl::Window
* pTempWindow
= pWindowImpl
->mpLastChild
;
548 if (pTempWindow
->mpWindowImpl
->mbVisible
)
549 pTempWindow
->ImplCallPaint(m_pChildRegion
.get(), m_nPaintFlags
);
550 pTempWindow
= pTempWindow
->mpWindowImpl
->mpPrev
;
554 if ( pWindowImpl
->mpWinData
&& pWindowImpl
->mbTrackVisible
&& (pWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
555 /* #98602# need to invert the tracking rect AFTER
556 * the children have painted
558 m_pWindow
->InvertTracking( *pWindowImpl
->mpWinData
->mpTrackRect
, pWindowImpl
->mpWinData
->mnTrackFlags
);
560 // double-buffering: paint in case we created the buffer, the children are
561 // already painted inside
562 if (m_bStartedBufferedPaint
&& pFrameData
->mbInBufferedPaint
)
565 pFrameData
->mbInBufferedPaint
= false;
566 pFrameData
->maBufferedRect
= tools::Rectangle();
569 // #98943# draw toolbox selection
570 if( !m_aSelectionRect
.IsEmpty() )
571 m_pWindow
->DrawSelectionBackground( m_aSelectionRect
, 3, false, true );
576 void Window::ImplCallPaint(const vcl::Region
* pRegion
, ImplPaintFlags nPaintFlags
)
578 // call PrePaint. PrePaint may add to the invalidate region as well as
579 // other parameters used below.
582 mpWindowImpl
->mbPaintFrame
= false;
584 if (nPaintFlags
& ImplPaintFlags::PaintAllChildren
)
585 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Paint
| ImplPaintFlags::PaintAllChildren
| (nPaintFlags
& ImplPaintFlags::PaintAll
);
586 if (nPaintFlags
& ImplPaintFlags::PaintChildren
)
587 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintChildren
;
588 if (nPaintFlags
& ImplPaintFlags::Erase
)
589 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Erase
;
590 if (nPaintFlags
& ImplPaintFlags::CheckRtl
)
591 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::CheckRtl
;
592 if (!mpWindowImpl
->mpFirstChild
)
593 mpWindowImpl
->mnPaintFlags
&= ~ImplPaintFlags::PaintAllChildren
;
595 if (mpWindowImpl
->mbPaintDisabled
)
597 if (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
598 Invalidate(InvalidateFlags::NoChildren
| InvalidateFlags::NoErase
| InvalidateFlags::NoTransparent
| InvalidateFlags::NoClipChildren
);
600 Invalidate(*pRegion
, InvalidateFlags::NoChildren
| InvalidateFlags::NoErase
| InvalidateFlags::NoTransparent
| InvalidateFlags::NoClipChildren
);
602 // call PostPaint before returning
608 nPaintFlags
= mpWindowImpl
->mnPaintFlags
& ~ImplPaintFlags::Paint
;
610 PaintHelper
aHelper(this, nPaintFlags
);
612 if (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::Paint
)
613 aHelper
.DoPaint(pRegion
);
615 mpWindowImpl
->mnPaintFlags
= ImplPaintFlags::NONE
;
621 void Window::ImplCallOverlapPaint()
623 // emit overlapping windows first
624 vcl::Window
* pTempWindow
= mpWindowImpl
->mpFirstOverlap
;
625 while ( pTempWindow
)
627 if ( pTempWindow
->mpWindowImpl
->mbReallyVisible
)
628 pTempWindow
->ImplCallOverlapPaint();
629 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
633 if ( mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintChildren
) )
635 // RTL: notify ImplCallPaint to check for re-mirroring
636 // because we were called from the Sal layer
637 ImplCallPaint(nullptr, mpWindowImpl
->mnPaintFlags
/*| ImplPaintFlags::CheckRtl */);
641 IMPL_LINK_NOARG(Window
, ImplHandlePaintHdl
, Timer
*, void)
643 comphelper::ProfileZone
aZone("VCL idle re-paint");
645 // save paint events until layout is done
646 if (IsSystemWindow() && static_cast<const SystemWindow
*>(this)->hasPendingLayout())
648 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
652 // save paint events until resizing or initial sizing done
653 if (mpWindowImpl
->mbFrame
&&
654 mpWindowImpl
->mpFrameData
->maResizeIdle
.IsActive())
656 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
658 else if ( mpWindowImpl
->mbReallyVisible
)
660 ImplCallOverlapPaint();
661 if (comphelper::LibreOfficeKit::isActive() &&
662 mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive())
663 mpWindowImpl
->mpFrameData
->maPaintIdle
.Stop();
667 IMPL_LINK_NOARG(Window
, ImplHandleResizeTimerHdl
, Timer
*, void)
669 comphelper::ProfileZone
aZone("VCL idle resize");
671 if( mpWindowImpl
->mbReallyVisible
)
674 if( mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive() )
676 mpWindowImpl
->mpFrameData
->maPaintIdle
.Stop();
677 mpWindowImpl
->mpFrameData
->maPaintIdle
.Invoke( nullptr );
682 void Window::ImplInvalidateFrameRegion( const vcl::Region
* pRegion
, InvalidateFlags nFlags
)
684 // set PAINTCHILDREN for all parent windows till the first OverlapWindow
685 if ( !ImplIsOverlapWindow() )
687 vcl::Window
* pTempWindow
= this;
688 ImplPaintFlags nTranspPaint
= IsPaintTransparent() ? ImplPaintFlags::Paint
: ImplPaintFlags::NONE
;
691 pTempWindow
= pTempWindow
->ImplGetParent();
692 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintChildren
)
694 pTempWindow
->mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintChildren
| nTranspPaint
;
695 if( ! pTempWindow
->IsPaintTransparent() )
696 nTranspPaint
= ImplPaintFlags::NONE
;
698 while ( !pTempWindow
->ImplIsOverlapWindow() );
702 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Paint
;
703 if ( nFlags
& InvalidateFlags::Children
)
704 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintAllChildren
;
705 if ( !(nFlags
& InvalidateFlags::NoErase
) )
706 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::Erase
;
709 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::PaintAll
;
710 else if ( !(mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
) )
712 // if not everything has to be redrawn, add the region to it
713 mpWindowImpl
->maInvalidateRegion
.Union( *pRegion
);
716 // Handle transparent windows correctly: invalidate must be done on the first opaque parent
717 if( ((IsPaintTransparent() && !(nFlags
& InvalidateFlags::NoTransparent
)) || (nFlags
& InvalidateFlags::Transparent
) )
720 vcl::Window
*pParent
= ImplGetParent();
721 while( pParent
&& pParent
->IsPaintTransparent() )
722 pParent
= pParent
->ImplGetParent();
725 vcl::Region
*pChildRegion
;
726 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
727 // invalidate the whole child window region in the parent
728 pChildRegion
= ImplGetWinChildClipRegion();
730 // invalidate the same region in the parent that has to be repainted in the child
731 pChildRegion
= &mpWindowImpl
->maInvalidateRegion
;
733 nFlags
|= InvalidateFlags::Children
; // paint should also be done on all children
734 nFlags
&= ~InvalidateFlags::NoErase
; // parent should paint and erase to create proper background
735 pParent
->ImplInvalidateFrameRegion( pChildRegion
, nFlags
);
739 if ( !mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive() )
740 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
743 void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region
& rRegion
)
745 vcl::Region aRegion
= rRegion
;
747 ImplClipBoundaries( aRegion
, true, true );
748 if ( !aRegion
.IsEmpty() )
749 ImplInvalidateFrameRegion( &aRegion
, InvalidateFlags::Children
);
751 // now we invalidate the overlapping windows
752 vcl::Window
* pTempWindow
= mpWindowImpl
->mpFirstOverlap
;
753 while ( pTempWindow
)
755 if ( pTempWindow
->IsVisible() )
756 pTempWindow
->ImplInvalidateOverlapFrameRegion( rRegion
);
758 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
762 void Window::ImplInvalidateParentFrameRegion( vcl::Region
& rRegion
)
764 if ( mpWindowImpl
->mbOverlapWin
)
765 mpWindowImpl
->mpFrameWindow
->ImplInvalidateOverlapFrameRegion( rRegion
);
768 if( ImplGetParent() )
769 ImplGetParent()->ImplInvalidateFrameRegion( &rRegion
, InvalidateFlags::Children
);
773 void Window::ImplInvalidate( const vcl::Region
* pRegion
, InvalidateFlags nFlags
)
775 // check what has to be redrawn
776 bool bInvalidateAll
= !pRegion
;
778 // take Transparent-Invalidate into account
779 vcl::Window
* pOpaqueWindow
= this;
780 if ( (mpWindowImpl
->mbPaintTransparent
&& !(nFlags
& InvalidateFlags::NoTransparent
)) || (nFlags
& InvalidateFlags::Transparent
) )
782 vcl::Window
* pTempWindow
= pOpaqueWindow
->ImplGetParent();
783 while ( pTempWindow
)
785 if ( !pTempWindow
->IsPaintTransparent() )
787 pOpaqueWindow
= pTempWindow
;
788 nFlags
|= InvalidateFlags::Children
;
789 bInvalidateAll
= false;
793 if ( pTempWindow
->ImplIsOverlapWindow() )
796 pTempWindow
= pTempWindow
->ImplGetParent();
801 InvalidateFlags nOrgFlags
= nFlags
;
802 if ( !(nFlags
& (InvalidateFlags::Children
| InvalidateFlags::NoChildren
)) )
804 if ( GetStyle() & WB_CLIPCHILDREN
)
805 nFlags
|= InvalidateFlags::NoChildren
;
807 nFlags
|= InvalidateFlags::Children
;
809 if ( (nFlags
& InvalidateFlags::NoChildren
) && mpWindowImpl
->mpFirstChild
)
810 bInvalidateAll
= false;
811 if ( bInvalidateAll
)
812 ImplInvalidateFrameRegion( nullptr, nFlags
);
815 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
816 vcl::Region
aRegion( aRect
);
819 // RTL: remirror region before intersecting it
820 if ( ImplIsAntiparallel() )
822 const OutputDevice
*pOutDev
= GetOutDev();
824 vcl::Region
aRgn( *pRegion
);
825 pOutDev
->ReMirror( aRgn
);
826 aRegion
.Intersect( aRgn
);
829 aRegion
.Intersect( *pRegion
);
831 ImplClipBoundaries( aRegion
, true, true );
832 if ( nFlags
& InvalidateFlags::NoChildren
)
834 nFlags
&= ~InvalidateFlags::Children
;
835 if ( !(nFlags
& InvalidateFlags::NoClipChildren
) )
837 if ( nOrgFlags
& InvalidateFlags::NoChildren
)
838 ImplClipAllChildren( aRegion
);
841 if ( ImplClipChildren( aRegion
) )
842 nFlags
|= InvalidateFlags::Children
;
846 if ( !aRegion
.IsEmpty() )
847 ImplInvalidateFrameRegion( &aRegion
, nFlags
); // transparency is handled here, pOpaqueWindow not required
850 if ( nFlags
& InvalidateFlags::Update
)
851 pOpaqueWindow
->Update(); // start painting at the opaque parent
854 void Window::ImplMoveInvalidateRegion( const tools::Rectangle
& rRect
,
855 long nHorzScroll
, long nVertScroll
,
858 if ( (mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintAll
)) == ImplPaintFlags::Paint
)
860 vcl::Region aTempRegion
= mpWindowImpl
->maInvalidateRegion
;
861 aTempRegion
.Intersect( rRect
);
862 aTempRegion
.Move( nHorzScroll
, nVertScroll
);
863 mpWindowImpl
->maInvalidateRegion
.Union( aTempRegion
);
866 if ( bChildren
&& (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintChildren
) )
868 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstChild
;
871 pWindow
->ImplMoveInvalidateRegion( rRect
, nHorzScroll
, nVertScroll
, true );
872 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
877 void Window::ImplMoveAllInvalidateRegions( const tools::Rectangle
& rRect
,
878 long nHorzScroll
, long nVertScroll
,
881 // also shift Paint-Region when paints need processing
882 ImplMoveInvalidateRegion( rRect
, nHorzScroll
, nVertScroll
, bChildren
);
883 // Paint-Region should be shifted, as drawn by the parents
884 if ( !ImplIsOverlapWindow() )
886 vcl::Region aPaintAllRegion
;
887 vcl::Window
* pPaintAllWindow
= this;
890 pPaintAllWindow
= pPaintAllWindow
->ImplGetParent();
891 if ( pPaintAllWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
893 if ( pPaintAllWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
895 aPaintAllRegion
.SetEmpty();
899 aPaintAllRegion
.Union( pPaintAllWindow
->mpWindowImpl
->maInvalidateRegion
);
902 while ( !pPaintAllWindow
->ImplIsOverlapWindow() );
903 if ( !aPaintAllRegion
.IsEmpty() )
905 aPaintAllRegion
.Move( nHorzScroll
, nVertScroll
);
906 InvalidateFlags nPaintFlags
= InvalidateFlags::NONE
;
908 nPaintFlags
|= InvalidateFlags::Children
;
909 ImplInvalidateFrameRegion( &aPaintAllRegion
, nPaintFlags
);
914 void Window::ImplValidateFrameRegion( const vcl::Region
* pRegion
, ValidateFlags nFlags
)
917 mpWindowImpl
->maInvalidateRegion
.SetEmpty();
920 // when all child windows have to be drawn we need to invalidate them before doing so
921 if ( (mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
) && mpWindowImpl
->mpFirstChild
)
923 vcl::Region aChildRegion
= mpWindowImpl
->maInvalidateRegion
;
924 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
926 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
927 aChildRegion
= aRect
;
929 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
932 pChild
->Invalidate( aChildRegion
, InvalidateFlags::Children
| InvalidateFlags::NoTransparent
);
933 pChild
= pChild
->mpWindowImpl
->mpNext
;
936 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAll
)
938 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
939 mpWindowImpl
->maInvalidateRegion
= aRect
;
941 mpWindowImpl
->maInvalidateRegion
.Exclude( *pRegion
);
943 mpWindowImpl
->mnPaintFlags
&= ~ImplPaintFlags::PaintAll
;
945 if ( nFlags
& ValidateFlags::Children
)
947 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
950 pChild
->ImplValidateFrameRegion( pRegion
, nFlags
);
951 pChild
= pChild
->mpWindowImpl
->mpNext
;
956 void Window::ImplValidate()
959 bool bValidateAll
= true;
960 ValidateFlags nFlags
= ValidateFlags::NONE
;
961 if ( GetStyle() & WB_CLIPCHILDREN
)
962 nFlags
|= ValidateFlags::NoChildren
;
964 nFlags
|= ValidateFlags::Children
;
965 if ( (nFlags
& ValidateFlags::NoChildren
) && mpWindowImpl
->mpFirstChild
)
966 bValidateAll
= false;
968 ImplValidateFrameRegion( nullptr, nFlags
);
971 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
972 vcl::Region
aRegion( aRect
);
973 ImplClipBoundaries( aRegion
, true, true );
974 if ( nFlags
& ValidateFlags::NoChildren
)
976 nFlags
&= ~ValidateFlags::Children
;
977 if ( ImplClipChildren( aRegion
) )
978 nFlags
|= ValidateFlags::Children
;
980 if ( !aRegion
.IsEmpty() )
981 ImplValidateFrameRegion( &aRegion
, nFlags
);
985 void Window::ImplUpdateAll()
987 if ( !mpWindowImpl
->mbReallyVisible
)
991 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
993 Point
aPoint( 0, 0 );
994 vcl::Region
aRegion( tools::Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
995 ImplInvalidateOverlapFrameRegion( aRegion
);
996 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
1000 // an update changes the OverlapWindow, such that for later paints
1001 // not too much has to be drawn, if ALLCHILDREN etc. is set
1002 vcl::Window
* pWindow
= ImplGetFirstOverlapWindow();
1003 pWindow
->ImplCallOverlapPaint();
1009 void Window::PrePaint(vcl::RenderContext
& /*rRenderContext*/)
1013 void Window::PostPaint(vcl::RenderContext
& /*rRenderContext*/)
1017 void Window::Paint(vcl::RenderContext
& /*rRenderContext*/, const tools::Rectangle
& rRect
)
1019 CallEventListeners(VclEventId::WindowPaint
, const_cast<tools::Rectangle
*>(&rRect
));
1022 void Window::SetPaintTransparent( bool bTransparent
)
1024 // transparency is not useful for frames as the background would have to be provided by a different frame
1025 if( bTransparent
&& mpWindowImpl
->mbFrame
)
1028 if ( mpWindowImpl
->mpBorderWindow
)
1029 mpWindowImpl
->mpBorderWindow
->SetPaintTransparent( bTransparent
);
1031 mpWindowImpl
->mbPaintTransparent
= bTransparent
;
1034 void Window::SetWindowRegionPixel()
1037 if ( mpWindowImpl
->mpBorderWindow
)
1038 mpWindowImpl
->mpBorderWindow
->SetWindowRegionPixel();
1039 else if( mpWindowImpl
->mbFrame
)
1041 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1042 mpWindowImpl
->mbWinRegion
= false;
1043 mpWindowImpl
->mpFrame
->ResetClipRegion();
1047 if ( mpWindowImpl
->mbWinRegion
)
1049 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1050 mpWindowImpl
->mbWinRegion
= false;
1053 if ( IsReallyVisible() )
1055 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
1056 vcl::Region
aRegion( aRect
);
1057 ImplInvalidateParentFrameRegion( aRegion
);
1063 void Window::SetWindowRegionPixel( const vcl::Region
& rRegion
)
1066 if ( mpWindowImpl
->mpBorderWindow
)
1067 mpWindowImpl
->mpBorderWindow
->SetWindowRegionPixel( rRegion
);
1068 else if( mpWindowImpl
->mbFrame
)
1070 if( !rRegion
.IsNull() )
1072 mpWindowImpl
->maWinRegion
= rRegion
;
1073 mpWindowImpl
->mbWinRegion
= ! rRegion
.IsEmpty();
1075 if( mpWindowImpl
->mbWinRegion
)
1077 // set/update ClipRegion
1078 RectangleVector aRectangles
;
1079 mpWindowImpl
->maWinRegion
.GetRegionRectangles(aRectangles
);
1080 mpWindowImpl
->mpFrame
->BeginSetClipRegion(aRectangles
.size());
1082 for (auto const& rectangle
: aRectangles
)
1084 mpWindowImpl
->mpFrame
->UnionClipRegion(
1087 rectangle
.GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
1088 rectangle
.GetHeight()); // same for height
1091 mpWindowImpl
->mpFrame
->EndSetClipRegion();
1097 //sal_uLong nRectCount;
1098 //ImplRegionInfo aInfo;
1099 //sal_Bool bRegionRect;
1101 //nRectCount = mpWindowImpl->maWinRegion.GetRectCount();
1102 //mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount );
1103 //bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
1104 //while ( bRegionRect )
1106 // mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight );
1107 // bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
1109 //mpWindowImpl->mpFrame->EndSetClipRegion();
1112 SetWindowRegionPixel();
1115 SetWindowRegionPixel();
1119 if ( rRegion
.IsNull() )
1121 if ( mpWindowImpl
->mbWinRegion
)
1123 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1124 mpWindowImpl
->mbWinRegion
= false;
1130 mpWindowImpl
->maWinRegion
= rRegion
;
1131 mpWindowImpl
->mbWinRegion
= true;
1135 if ( IsReallyVisible() )
1137 tools::Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
1138 vcl::Region
aRegion( aRect
);
1139 ImplInvalidateParentFrameRegion( aRegion
);
1144 vcl::Region
Window::GetPaintRegion() const
1147 if ( mpWindowImpl
->mpPaintRegion
)
1149 vcl::Region aRegion
= *mpWindowImpl
->mpPaintRegion
;
1150 aRegion
.Move( -mnOutOffX
, -mnOutOffY
);
1151 return PixelToLogic( aRegion
);
1155 vcl::Region
aPaintRegion(true);
1156 return aPaintRegion
;
1160 void Window::Invalidate( InvalidateFlags nFlags
)
1162 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1165 ImplInvalidate( nullptr, nFlags
);
1166 LogicInvalidate(nullptr);
1169 void Window::Invalidate( const tools::Rectangle
& rRect
, InvalidateFlags nFlags
)
1171 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1174 OutputDevice
*pOutDev
= GetOutDev();
1175 tools::Rectangle aRect
= pOutDev
->ImplLogicToDevicePixel( rRect
);
1176 if ( !aRect
.IsEmpty() )
1178 vcl::Region
aRegion( aRect
);
1179 ImplInvalidate( &aRegion
, nFlags
);
1180 tools::Rectangle
aLogicRectangle(rRect
);
1181 LogicInvalidate(&aLogicRectangle
);
1185 void Window::Invalidate( const vcl::Region
& rRegion
, InvalidateFlags nFlags
)
1187 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1190 if ( rRegion
.IsNull() )
1192 ImplInvalidate( nullptr, nFlags
);
1193 LogicInvalidate(nullptr);
1197 vcl::Region aRegion
= ImplPixelToDevicePixel( LogicToPixel( rRegion
) );
1198 if ( !aRegion
.IsEmpty() )
1200 ImplInvalidate( &aRegion
, nFlags
);
1201 tools::Rectangle aLogicRectangle
= rRegion
.GetBoundRect();
1202 LogicInvalidate(&aLogicRectangle
);
1207 void Window::LogicInvalidate(const tools::Rectangle
* pRectangle
)
1211 tools::Rectangle aRect
= GetOutDev()->ImplLogicToDevicePixel( *pRectangle
);
1212 PixelInvalidate(&aRect
);
1215 PixelInvalidate(nullptr);
1218 void Window::PixelInvalidate(const tools::Rectangle
* pRectangle
)
1220 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1223 if (const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
1225 // In case we are routing the window, notify the client
1226 std::vector
<vcl::LOKPayloadItem
> aPayload
;
1228 aPayload
.push_back(std::make_pair(OString("rectangle"), pRectangle
->toString()));
1231 const tools::Rectangle
aRect(Point(0, 0), GetSizePixel());
1232 aPayload
.push_back(std::make_pair(OString("rectangle"), aRect
.toString()));
1235 pNotifier
->notifyWindow(GetLOKWindowId(), "invalidate", aPayload
);
1237 // Added for dialog items. Pass invalidation to the parent window.
1238 else if (VclPtr
<vcl::Window
> pParent
= GetParentWithLOKNotifier())
1240 const tools::Rectangle
aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1241 pParent
->PixelInvalidate(&aRect
);
1245 void Window::Validate()
1247 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1253 bool Window::HasPaintEvent() const
1256 if ( !mpWindowImpl
->mbReallyVisible
)
1259 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1262 if ( mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::Paint
)
1265 if ( !ImplIsOverlapWindow() )
1267 const vcl::Window
* pTempWindow
= this;
1270 pTempWindow
= pTempWindow
->ImplGetParent();
1271 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::PaintChildren
| ImplPaintFlags::PaintAllChildren
) )
1274 while ( !pTempWindow
->ImplIsOverlapWindow() );
1280 void Window::Update()
1282 if ( mpWindowImpl
->mpBorderWindow
)
1284 mpWindowImpl
->mpBorderWindow
->Update();
1288 if ( !mpWindowImpl
->mbReallyVisible
)
1291 bool bFlush
= false;
1292 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1294 Point
aPoint( 0, 0 );
1295 vcl::Region
aRegion( tools::Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
1296 ImplInvalidateOverlapFrameRegion( aRegion
);
1297 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
1301 // First we should skip all windows which are Paint-Transparent
1302 vcl::Window
* pUpdateWindow
= this;
1303 vcl::Window
* pWindow
= pUpdateWindow
;
1304 while ( !pWindow
->ImplIsOverlapWindow() )
1306 if ( !pWindow
->mpWindowImpl
->mbPaintTransparent
)
1308 pUpdateWindow
= pWindow
;
1311 pWindow
= pWindow
->ImplGetParent();
1313 // In order to limit drawing, an update only draws the window which
1314 // has PAINTALLCHILDREN set
1315 pWindow
= pUpdateWindow
;
1318 if ( pWindow
->mpWindowImpl
->mnPaintFlags
& ImplPaintFlags::PaintAllChildren
)
1319 pUpdateWindow
= pWindow
;
1320 if ( pWindow
->ImplIsOverlapWindow() )
1322 pWindow
= pWindow
->ImplGetParent();
1326 // if there is something to paint, trigger a Paint
1327 if ( pUpdateWindow
->mpWindowImpl
->mnPaintFlags
& (ImplPaintFlags::Paint
| ImplPaintFlags::PaintChildren
) )
1329 VclPtr
<vcl::Window
> xWindow(this);
1331 // trigger an update also for system windows on top of us,
1332 // otherwise holes would remain
1333 vcl::Window
* pUpdateOverlapWindow
= ImplGetFirstOverlapWindow()->mpWindowImpl
->mpFirstOverlap
;
1334 while ( pUpdateOverlapWindow
)
1336 pUpdateOverlapWindow
->Update();
1337 pUpdateOverlapWindow
= pUpdateOverlapWindow
->mpWindowImpl
->mpNext
;
1340 pUpdateWindow
->ImplCallPaint(nullptr, pUpdateWindow
->mpWindowImpl
->mnPaintFlags
);
1342 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow
->GetParentDialog())
1343 pUpdateWindow
->LogicInvalidate(nullptr);
1345 if (xWindow
->IsDisposed())
1355 void Window::ImplPaintToDevice( OutputDevice
* i_pTargetOutDev
, const Point
& i_rPos
)
1357 // Special drawing when called through LOKit
1358 // TODO: Move to its own method
1359 if (comphelper::LibreOfficeKit::isActive())
1361 VclPtrInstance
<VirtualDevice
> pDevice(*i_pTargetOutDev
);
1363 Size
aSize(GetOutputSizePixel());
1364 pDevice
->SetOutputSizePixel(aSize
);
1366 vcl::Font aCopyFont
= GetFont();
1367 pDevice
->SetFont(aCopyFont
);
1369 pDevice
->SetTextColor(GetTextColor());
1371 pDevice
->SetLineColor(GetLineColor());
1373 pDevice
->SetLineColor();
1376 pDevice
->SetFillColor(GetFillColor());
1378 pDevice
->SetFillColor();
1380 if (IsTextLineColor())
1381 pDevice
->SetTextLineColor(GetTextLineColor());
1383 pDevice
->SetTextLineColor();
1385 if (IsOverlineColor())
1386 pDevice
->SetOverlineColor(GetOverlineColor());
1388 pDevice
->SetOverlineColor();
1390 if (IsTextFillColor())
1391 pDevice
->SetTextFillColor(GetTextFillColor());
1393 pDevice
->SetTextFillColor();
1395 pDevice
->SetTextAlign(GetTextAlign());
1396 pDevice
->SetRasterOp(GetRasterOp());
1398 tools::Rectangle
aPaintRect(Point(), GetOutputSizePixel());
1400 vcl::Region
aClipRegion(GetClipRegion());
1401 pDevice
->SetClipRegion();
1402 aClipRegion
.Intersect(aPaintRect
);
1403 pDevice
->SetClipRegion(aClipRegion
);
1405 if (!IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip
))
1408 pDevice
->SetMapMode(GetMapMode());
1410 Paint(*pDevice
, tools::Rectangle(Point(), GetOutputSizePixel()));
1412 i_pTargetOutDev
->DrawOutDev(i_rPos
, aSize
, Point(), pDevice
->PixelToLogic(aSize
), *pDevice
);
1414 // get rid of virtual device now so they don't pile up during recursive calls
1415 pDevice
.disposeAndClear();
1418 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1420 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1422 long nDeltaX
= pChild
->mnOutOffX
- mnOutOffX
;
1423 long nDeltaY
= pChild
->mnOutOffY
- mnOutOffY
;
1425 Point
aPos( i_rPos
);
1426 aPos
+= Point(nDeltaX
, nDeltaY
);
1428 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1435 bool bRVisible
= mpWindowImpl
->mbReallyVisible
;
1436 mpWindowImpl
->mbReallyVisible
= mpWindowImpl
->mbVisible
;
1437 bool bDevOutput
= mbDevOutput
;
1440 const OutputDevice
*pOutDev
= GetOutDev();
1441 long nOldDPIX
= pOutDev
->GetDPIX();
1442 long nOldDPIY
= pOutDev
->GetDPIY();
1443 mnDPIX
= i_pTargetOutDev
->GetDPIX();
1444 mnDPIY
= i_pTargetOutDev
->GetDPIY();
1445 bool bOutput
= IsOutputEnabled();
1450 bool bNeedsScaling
= false;
1451 if(comphelper::LibreOfficeKit::isActive())
1453 if(GetMapMode().GetMapUnit() != MapUnit::MapPixel
&&
1454 // Some of the preview windows (SvxPreviewBase) uses different painting (drawinglayer primitives)
1455 // For these preview we don't need to scale even though the unit is not pixel.
1456 GetMapMode().GetMapUnit() != MapUnit::Map100thMM
)
1458 bNeedsScaling
= true;
1459 // 1000.0 is used to reduce rounding imprecision (Size uses integers)
1460 Size aLogicSize
= PixelToLogic(Size(1000.0, 1000.0));
1461 fScaleX
= aLogicSize
.Width() / 1000.0;
1462 fScaleY
= aLogicSize
.Height() / 1000.0;
1466 { // TODO: Above scaling was added for LOK only, would be good to check how it works in other use cases
1467 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel
, "vcl.window", "MapMode must be PIXEL based" );
1468 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel
)
1472 // preserve graphicsstate
1474 vcl::Region
aClipRegion( GetClipRegion() );
1477 GDIMetaFile
* pOldMtf
= GetConnectMetaFile();
1479 SetConnectMetaFile( &aMtf
);
1481 // put a push action to metafile
1483 // copy graphics state to metafile
1484 vcl::Font aCopyFont
= GetFont();
1485 if( nOldDPIX
!= mnDPIX
|| nOldDPIY
!= mnDPIY
)
1487 aCopyFont
.SetFontHeight( aCopyFont
.GetFontHeight() * mnDPIY
/ nOldDPIY
);
1488 aCopyFont
.SetAverageFontWidth( aCopyFont
.GetAverageFontWidth() * mnDPIX
/ nOldDPIX
);
1490 SetFont( aCopyFont
);
1491 SetTextColor( GetTextColor() );
1493 SetLineColor( GetLineColor() );
1497 SetFillColor( GetFillColor() );
1500 if( IsTextLineColor() )
1501 SetTextLineColor( GetTextLineColor() );
1504 if( IsOverlineColor() )
1505 SetOverlineColor( GetOverlineColor() );
1508 if( IsTextFillColor() )
1509 SetTextFillColor( GetTextFillColor() );
1512 SetTextAlign( GetTextAlign() );
1513 SetRasterOp( GetRasterOp() );
1515 SetRefPoint( GetRefPoint() );
1518 SetLayoutMode( GetLayoutMode() );
1519 SetDigitLanguage( GetDigitLanguage() );
1521 tools::Rectangle aPaintRect
;
1524 aPaintRect
= tools::Rectangle( Point( 0, 0 ),
1525 Size(GetOutputSizePixel().Width() * fScaleX
, GetOutputSizePixel().Height() * fScaleY
) );
1529 aPaintRect
= tools::Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
1531 aClipRegion
.Intersect( aPaintRect
);
1532 SetClipRegion( aClipRegion
);
1534 // do the actual paint
1537 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip
) )
1541 aMtf
.Scale(fScaleX
, fScaleY
);
1544 Paint(*this, aPaintRect
);
1545 // put a pop action to metafile
1548 SetConnectMetaFile( pOldMtf
);
1549 EnableOutput( bOutput
);
1550 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1552 // paint metafile to VDev
1553 VclPtrInstance
<VirtualDevice
> pMaskedDevice(*i_pTargetOutDev
,
1554 DeviceFormat::DEFAULT
,
1555 DeviceFormat::DEFAULT
);
1558 pMaskedDevice
->SetMapMode( GetMapMode() );
1559 pMaskedDevice
->SetOutputSizePixel( GetOutputSizePixel() );
1560 pMaskedDevice
->EnableRTL( IsRTLEnabled() );
1562 aMtf
.Play( pMaskedDevice
);
1563 BitmapEx
aBmpEx( pMaskedDevice
->GetBitmapEx( Point( 0, 0 ), aPaintRect
.GetSize() ) );
1564 i_pTargetOutDev
->DrawBitmapEx( i_rPos
, aBmpEx
);
1565 // get rid of virtual device now so they don't pile up during recursive calls
1566 pMaskedDevice
.disposeAndClear();
1568 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1570 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1572 long nDeltaX
= pChild
->mnOutOffX
- mnOutOffX
;
1574 if( pOutDev
->HasMirroredGraphics() )
1575 nDeltaX
= mnOutWidth
- nDeltaX
- pChild
->mnOutWidth
;
1576 long nDeltaY
= pChild
->GetOutOffYPixel() - GetOutOffYPixel();
1577 Point
aPos( i_rPos
);
1578 Point
aDelta( nDeltaX
, nDeltaY
);
1580 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1584 // restore graphics state
1587 EnableOutput( bOutput
);
1588 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1589 mbDevOutput
= bDevOutput
;
1594 void Window::PaintToDevice( OutputDevice
* pDev
, const Point
& rPos
, const Size
& /*rSize*/ )
1596 SAL_WARN_IF( pDev
->HasMirroredGraphics(), "vcl.window", "PaintToDevice to mirroring graphics" );
1597 SAL_WARN_IF( pDev
->IsRTLEnabled(), "vcl.window", "PaintToDevice to mirroring device" );
1599 vcl::Window
* pRealParent
= nullptr;
1600 if( ! mpWindowImpl
->mbVisible
)
1602 vcl::Window
* pTempParent
= ImplGetDefaultWindow();
1603 pTempParent
->EnableChildTransparentMode();
1604 pRealParent
= GetParent();
1605 SetParent( pTempParent
);
1606 // trigger correct visibility flags for children
1611 bool bVisible
= mpWindowImpl
->mbVisible
;
1612 mpWindowImpl
->mbVisible
= true;
1614 if( mpWindowImpl
->mpBorderWindow
)
1615 mpWindowImpl
->mpBorderWindow
->ImplPaintToDevice( pDev
, rPos
);
1617 ImplPaintToDevice( pDev
, rPos
);
1619 mpWindowImpl
->mbVisible
= bVisible
;
1622 SetParent( pRealParent
);
1625 void Window::Erase(vcl::RenderContext
& rRenderContext
)
1627 if (!IsDeviceOutputNecessary() || ImplIsRecordLayout())
1630 bool bNativeOK
= false;
1632 ControlPart aCtrlPart
= ImplGetWindowImpl()->mnNativeBackground
;
1633 if (aCtrlPart
!= ControlPart::NONE
&& ! IsControlBackground())
1635 tools::Rectangle
aCtrlRegion(Point(), GetOutputSizePixel());
1636 ControlState nState
= ControlState::NONE
;
1639 nState
|= ControlState::ENABLED
;
1641 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::WindowBackground
, aCtrlPart
, aCtrlRegion
,
1642 nState
, ImplControlValue(), OUString());
1645 if (mbBackground
&& !bNativeOK
)
1647 RasterOp eRasterOp
= GetRasterOp();
1648 if (eRasterOp
!= RasterOp::OverPaint
)
1649 SetRasterOp(RasterOp::OverPaint
);
1650 rRenderContext
.DrawWallpaper(0, 0, mnOutWidth
, mnOutHeight
, maBackground
);
1651 if (eRasterOp
!= RasterOp::OverPaint
)
1652 rRenderContext
.SetRasterOp(eRasterOp
);
1656 mpAlphaVDev
->Erase();
1659 void Window::ImplScroll( const tools::Rectangle
& rRect
,
1660 long nHorzScroll
, long nVertScroll
, ScrollFlags nFlags
)
1662 if ( !IsDeviceOutputNecessary() )
1665 nHorzScroll
= ImplLogicWidthToDevicePixel( nHorzScroll
);
1666 nVertScroll
= ImplLogicHeightToDevicePixel( nVertScroll
);
1668 if ( !nHorzScroll
&& !nVertScroll
)
1671 if ( mpWindowImpl
->mpCursor
)
1672 mpWindowImpl
->mpCursor
->ImplSuspend();
1674 ScrollFlags nOrgFlags
= nFlags
;
1675 if ( !(nFlags
& (ScrollFlags::Children
| ScrollFlags::NoChildren
)) )
1677 if ( GetStyle() & WB_CLIPCHILDREN
)
1678 nFlags
|= ScrollFlags::NoChildren
;
1680 nFlags
|= ScrollFlags::Children
;
1683 vcl::Region aInvalidateRegion
;
1684 bool bScrollChildren(nFlags
& ScrollFlags::Children
);
1686 if ( !mpWindowImpl
->mpFirstChild
)
1687 bScrollChildren
= false;
1689 OutputDevice
*pOutDev
= GetOutDev();
1691 // RTL: check if this window requires special action
1692 bool bReMirror
= ImplIsAntiparallel();
1694 tools::Rectangle
aRectMirror( rRect
);
1697 // make sure the invalidate region of this window is
1698 // computed in the same coordinate space as the one from the overlap windows
1699 pOutDev
->ReMirror( aRectMirror
);
1702 // adapt paint areas
1703 ImplMoveAllInvalidateRegions( aRectMirror
, nHorzScroll
, nVertScroll
, bScrollChildren
);
1705 ImplCalcOverlapRegion( aRectMirror
, aInvalidateRegion
, !bScrollChildren
, false );
1707 // if the scrolling on the device is performed in the opposite direction
1708 // then move the overlaps in that direction to compute the invalidate region
1709 // on the correct side, i.e., revert nHorzScroll
1710 if (!aInvalidateRegion
.IsEmpty())
1712 aInvalidateRegion
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1715 tools::Rectangle
aDestRect(aRectMirror
);
1716 aDestRect
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1717 vcl::Region
aWinInvalidateRegion(aRectMirror
);
1718 if (!SupportsDoubleBuffering())
1720 // There will be no CopyArea() call below, so invalidate the
1721 // whole visible area, not only the smaller one that was just
1723 aWinInvalidateRegion
.Exclude(aDestRect
);
1726 aInvalidateRegion
.Union(aWinInvalidateRegion
);
1728 Point
aPoint( mnOutOffX
, mnOutOffY
);
1729 vcl::Region
aRegion( tools::Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
1730 if ( nFlags
& ScrollFlags::Clip
)
1731 aRegion
.Intersect( rRect
);
1732 if ( mpWindowImpl
->mbWinRegion
)
1733 aRegion
.Intersect( ImplPixelToDevicePixel( mpWindowImpl
->maWinRegion
) );
1735 aRegion
.Exclude( aInvalidateRegion
);
1737 ImplClipBoundaries( aRegion
, false, true );
1738 if ( !bScrollChildren
)
1740 if ( nOrgFlags
& ScrollFlags::NoChildren
)
1741 ImplClipAllChildren( aRegion
);
1743 ImplClipChildren( aRegion
);
1745 if ( mbClipRegion
&& (nFlags
& ScrollFlags::UseClipRegion
) )
1746 aRegion
.Intersect( maRegion
);
1747 if ( !aRegion
.IsEmpty() )
1749 if ( mpWindowImpl
->mpWinData
)
1751 if ( mpWindowImpl
->mbFocusVisible
)
1752 ImplInvertFocus( *mpWindowImpl
->mpWinData
->mpFocusRect
);
1753 if ( mpWindowImpl
->mbTrackVisible
&& (mpWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
1754 InvertTracking( *mpWindowImpl
->mpWinData
->mpTrackRect
, mpWindowImpl
->mpWinData
->mnTrackFlags
);
1757 // This seems completely unnecessary with tiled rendering, and
1758 // causes the "AquaSalGraphics::copyArea() for non-layered
1759 // graphics" message. Presumably we should bypass this on all
1760 // platforms when dealing with a "window" that uses tiled
1761 // rendering at the moment. Unclear how to figure that out,
1762 // though. Also unclear whether we actually could just not
1763 // create a "frame window", whatever that exactly is, in the
1764 // tiled rendering case, or at least for platforms where tiles
1765 // rendering is all there is.
1767 SalGraphics
* pGraphics
= ImplGetFrameGraphics();
1768 // The invalidation area contains the area what would be copied here,
1769 // so avoid copying in case of double buffering.
1770 if (pGraphics
&& !SupportsDoubleBuffering())
1774 pOutDev
->ReMirror( aRegion
);
1777 pOutDev
->SelectClipRegion( aRegion
, pGraphics
);
1778 pGraphics
->CopyArea( rRect
.Left()+nHorzScroll
, rRect
.Top()+nVertScroll
,
1779 rRect
.Left(), rRect
.Top(),
1780 rRect
.GetWidth(), rRect
.GetHeight(),
1784 if ( mpWindowImpl
->mpWinData
)
1786 if ( mpWindowImpl
->mbFocusVisible
)
1787 ImplInvertFocus( *mpWindowImpl
->mpWinData
->mpFocusRect
);
1788 if ( mpWindowImpl
->mbTrackVisible
&& (mpWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
1789 InvertTracking( *mpWindowImpl
->mpWinData
->mpTrackRect
, mpWindowImpl
->mpWinData
->mnTrackFlags
);
1793 if ( !aInvalidateRegion
.IsEmpty() )
1795 // RTL: the invalidate region for this windows is already computed in frame coordinates
1796 // so it has to be re-mirrored before calling the Paint-handler
1797 mpWindowImpl
->mnPaintFlags
|= ImplPaintFlags::CheckRtl
;
1799 if ( !bScrollChildren
)
1801 if ( nOrgFlags
& ScrollFlags::NoChildren
)
1802 ImplClipAllChildren( aInvalidateRegion
);
1804 ImplClipChildren( aInvalidateRegion
);
1806 ImplInvalidateFrameRegion( &aInvalidateRegion
, InvalidateFlags::Children
);
1809 if ( bScrollChildren
)
1811 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstChild
;
1814 Point aPos
= pWindow
->GetPosPixel();
1815 aPos
+= Point( nHorzScroll
, nVertScroll
);
1816 pWindow
->SetPosPixel( aPos
);
1818 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
1822 if ( nFlags
& ScrollFlags::Update
)
1825 if ( mpWindowImpl
->mpCursor
)
1826 mpWindowImpl
->mpCursor
->ImplResume();
1829 } /* namespace vcl */
1832 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */