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>
22 #include <vcl/window.hxx>
23 #include <vcl/dialog.hxx>
24 #include <vcl/virdev.hxx>
25 #include <vcl/cursor.hxx>
26 #include <vcl/settings.hxx>
28 #include <sal/types.h>
32 #include <salframe.hxx>
34 #include <comphelper/lok.hxx>
35 #if HAVE_FEATURE_OPENGL
36 #include <vcl/opengl/OpenGLHelper.hxx>
39 #define IMPL_PAINT_PAINT ((sal_uInt16)0x0001)
40 #define IMPL_PAINT_PAINTALL ((sal_uInt16)0x0002)
41 #define IMPL_PAINT_PAINTALLCHILDREN ((sal_uInt16)0x0004)
42 #define IMPL_PAINT_PAINTCHILDREN ((sal_uInt16)0x0008)
43 #define IMPL_PAINT_ERASE ((sal_uInt16)0x0010)
44 #define IMPL_PAINT_CHECKRTL ((sal_uInt16)0x0020)
48 PaintBufferGuard::PaintBufferGuard(ImplFrameData
* pFrameData
, vcl::Window
* pWindow
)
49 : mpFrameData(pFrameData
),
55 if (!pFrameData
->mpBuffer
)
58 // transfer various settings
59 // FIXME: this must disappear as we move to RenderContext only,
60 // the painting must become state-less, so that no actual
61 // vcl::Window setting affects this
62 mbBackground
= pFrameData
->mpBuffer
->IsBackground();
63 if (pWindow
->IsBackground())
65 maBackground
= pFrameData
->mpBuffer
->GetBackground();
66 pFrameData
->mpBuffer
->SetBackground(pWindow
->GetBackground());
69 //SAL_WARN("vcl.window", "the root of the double-buffering hierarchy should not have a transparent background");
71 PushFlags nFlags
= PushFlags::NONE
;
72 nFlags
|= PushFlags::CLIPREGION
;
73 nFlags
|= PushFlags::FILLCOLOR
;
74 nFlags
|= PushFlags::FONT
;
75 nFlags
|= PushFlags::LINECOLOR
;
76 nFlags
|= PushFlags::MAPMODE
;
77 maSettings
= pFrameData
->mpBuffer
->GetSettings();
78 nFlags
|= PushFlags::REFPOINT
;
79 nFlags
|= PushFlags::TEXTCOLOR
;
80 nFlags
|= PushFlags::TEXTLINECOLOR
;
81 nFlags
|= PushFlags::OVERLINECOLOR
;
82 nFlags
|= PushFlags::TEXTFILLCOLOR
;
83 nFlags
|= PushFlags::TEXTALIGN
;
84 nFlags
|= PushFlags::RASTEROP
;
85 nFlags
|= PushFlags::TEXTLAYOUTMODE
;
86 nFlags
|= PushFlags::TEXTLANGUAGE
;
87 pFrameData
->mpBuffer
->Push(nFlags
);
88 pFrameData
->mpBuffer
->SetClipRegion(pWindow
->GetClipRegion());
89 pFrameData
->mpBuffer
->SetFillColor(pWindow
->GetFillColor());
90 pFrameData
->mpBuffer
->SetFont(pWindow
->GetFont());
91 pFrameData
->mpBuffer
->SetLineColor(pWindow
->GetLineColor());
92 pFrameData
->mpBuffer
->SetMapMode(pWindow
->GetMapMode());
93 pFrameData
->mpBuffer
->SetRefPoint(pWindow
->GetRefPoint());
94 pFrameData
->mpBuffer
->SetSettings(pWindow
->GetSettings());
95 pFrameData
->mpBuffer
->SetTextColor(pWindow
->GetTextColor());
96 pFrameData
->mpBuffer
->SetTextLineColor(pWindow
->GetTextLineColor());
97 pFrameData
->mpBuffer
->SetOverlineColor(pWindow
->GetOverlineColor());
98 pFrameData
->mpBuffer
->SetTextFillColor(pWindow
->GetTextFillColor());
99 pFrameData
->mpBuffer
->SetTextAlign(pWindow
->GetTextAlign());
100 pFrameData
->mpBuffer
->SetRasterOp(pWindow
->GetRasterOp());
101 pFrameData
->mpBuffer
->SetLayoutMode(pWindow
->GetLayoutMode());
102 pFrameData
->mpBuffer
->SetDigitLanguage(pWindow
->GetDigitLanguage());
104 mnOutOffX
= pFrameData
->mpBuffer
->GetOutOffXPixel();
105 mnOutOffY
= pFrameData
->mpBuffer
->GetOutOffYPixel();
106 pFrameData
->mpBuffer
->SetOutOffXPixel(pWindow
->GetOutOffXPixel());
107 pFrameData
->mpBuffer
->SetOutOffYPixel(pWindow
->GetOutOffYPixel());
110 PaintBufferGuard::~PaintBufferGuard()
112 if (!mpFrameData
->mpBuffer
)
115 if (!m_aPaintRect
.IsEmpty())
117 // copy the buffer content to the actual window
118 // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are
119 // painting directly instead of using Invalidate()
120 // [ie. everything you can see was painted directly to the
121 // window either above or in eg. an event handler]
122 if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT"))
124 // Make sure that the +1 value GetSize() adds to the size is in pixels.
126 if (m_pWindow
->GetMapMode().GetMapUnit() == MapUnit::MapPixel
)
128 aPaintRectSize
= m_aPaintRect
.GetSize();
132 Rectangle aRectanglePixel
= m_pWindow
->LogicToPixel(m_aPaintRect
);
133 aPaintRectSize
= m_pWindow
->PixelToLogic(aRectanglePixel
.GetSize());
136 m_pWindow
->DrawOutDev(m_aPaintRect
.TopLeft(), aPaintRectSize
, m_aPaintRect
.TopLeft(), aPaintRectSize
, *mpFrameData
->mpBuffer
.get());
140 // Restore buffer state.
141 mpFrameData
->mpBuffer
->SetOutOffXPixel(mnOutOffX
);
142 mpFrameData
->mpBuffer
->SetOutOffYPixel(mnOutOffY
);
144 mpFrameData
->mpBuffer
->Pop();
145 mpFrameData
->mpBuffer
->SetSettings(maSettings
);
147 mpFrameData
->mpBuffer
->SetBackground(maBackground
);
149 mpFrameData
->mpBuffer
->SetBackground();
152 void PaintBufferGuard::SetPaintRect(const Rectangle
& rRectangle
)
154 m_aPaintRect
= rRectangle
;
157 vcl::RenderContext
* PaintBufferGuard::GetRenderContext()
159 if (mpFrameData
->mpBuffer
)
160 return mpFrameData
->mpBuffer
;
168 VclPtr
<vcl::Window
> m_pWindow
;
169 vcl::Region
* m_pChildRegion
;
170 Rectangle m_aSelectionRect
;
171 Rectangle m_aPaintRect
;
172 vcl::Region m_aPaintRegion
;
173 sal_uInt16 m_nPaintFlags
;
175 bool m_bRestoreCursor
: 1;
176 bool m_bStartedBufferedPaint
: 1; ///< This PaintHelper started a buffered paint, and should paint it on the screen when being destructed.
178 PaintHelper(vcl::Window
* pWindow
, sal_uInt16 nPaintFlags
);
183 void SetPaintRect(const Rectangle
& rRect
)
185 m_aPaintRect
= rRect
;
187 void SetSelectionRect(const Rectangle
& rRect
)
189 m_aSelectionRect
= rRect
;
191 void SetRestoreCursor(bool bRestoreCursor
)
193 m_bRestoreCursor
= bRestoreCursor
;
195 bool GetRestoreCursor() const
197 return m_bRestoreCursor
;
199 sal_uInt16
GetPaintFlags() const
201 return m_nPaintFlags
;
203 vcl::Region
& GetPaintRegion()
205 return m_aPaintRegion
;
207 void DoPaint(const vcl::Region
* pRegion
);
209 /// Start buffered paint: set it up to have the same settings as m_pWindow.
210 void StartBufferedPaint();
212 /// Paint the content of the buffer to the current m_pWindow.
218 PaintHelper::PaintHelper(vcl::Window
*pWindow
, sal_uInt16 nPaintFlags
)
220 , m_pChildRegion(nullptr)
221 , m_nPaintFlags(nPaintFlags
)
223 , m_bRestoreCursor(false)
224 , m_bStartedBufferedPaint(false)
228 void PaintHelper::StartBufferedPaint()
230 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
231 assert(!pFrameData
->mbInBufferedPaint
);
233 pFrameData
->mbInBufferedPaint
= true;
234 pFrameData
->maBufferedRect
= Rectangle();
235 m_bStartedBufferedPaint
= true;
238 void PaintHelper::PaintBuffer()
240 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
241 assert(pFrameData
->mbInBufferedPaint
);
242 assert(m_bStartedBufferedPaint
);
244 PaintBufferGuard
aGuard(pFrameData
, m_pWindow
);
245 aGuard
.SetPaintRect(pFrameData
->maBufferedRect
);
248 void PaintHelper::DoPaint(const vcl::Region
* pRegion
)
250 WindowImpl
* pWindowImpl
= m_pWindow
->ImplGetWindowImpl();
252 vcl::Region
* pWinChildClipRegion
= m_pWindow
->ImplGetWinChildClipRegion();
253 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
254 if (pWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTALL
|| pFrameData
->mbInBufferedPaint
)
256 pWindowImpl
->maInvalidateRegion
= *pWinChildClipRegion
;
261 pWindowImpl
->maInvalidateRegion
.Union( *pRegion
);
263 if (pWindowImpl
->mpWinData
&& pWindowImpl
->mbTrackVisible
)
264 /* #98602# need to repaint all children within the
265 * tracking rectangle, so the following invert
266 * operation takes places without traces of the previous
269 pWindowImpl
->maInvalidateRegion
.Union(*pWindowImpl
->mpWinData
->mpTrackRect
);
271 if (pWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTALLCHILDREN
)
272 m_pChildRegion
= new vcl::Region(pWindowImpl
->maInvalidateRegion
);
273 pWindowImpl
->maInvalidateRegion
.Intersect(*pWinChildClipRegion
);
275 pWindowImpl
->mnPaintFlags
= 0;
276 if (!pWindowImpl
->maInvalidateRegion
.IsEmpty())
278 #if HAVE_FEATURE_OPENGL
279 VCL_GL_INFO("PaintHelper::DoPaint on " <<
280 typeid( *m_pWindow
).name() << " '" << m_pWindow
->GetText() << "' begin");
282 // double-buffering: setup the buffer if it does not exist
283 if (!pFrameData
->mbInBufferedPaint
&& m_pWindow
->SupportsDoubleBuffering())
284 StartBufferedPaint();
286 // double-buffering: if this window does not support double-buffering,
287 // but we are in the middle of double-buffered paint, we might be
288 // losing information
289 if (pFrameData
->mbInBufferedPaint
&& !m_pWindow
->SupportsDoubleBuffering())
290 SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow
.get()).name());
292 if (pFrameData
->mbInBufferedPaint
&& m_pWindow
->SupportsDoubleBuffering())
295 PaintBufferGuard
g(pFrameData
, m_pWindow
);
296 m_pWindow
->ApplySettings(*pFrameData
->mpBuffer
.get());
298 m_pWindow
->PushPaintHelper(this, *pFrameData
->mpBuffer
.get());
299 m_pWindow
->Paint(*pFrameData
->mpBuffer
.get(), m_aPaintRect
);
300 pFrameData
->maBufferedRect
.Union(m_aPaintRect
);
305 m_pWindow
->ApplySettings(*m_pWindow
);
306 m_pWindow
->PushPaintHelper(this, *m_pWindow
);
307 m_pWindow
->Paint(*m_pWindow
, m_aPaintRect
);
309 #if HAVE_FEATURE_OPENGL
310 VCL_GL_INFO("PaintHelper::DoPaint end on " <<
311 typeid( *m_pWindow
).name() << " '" << m_pWindow
->GetText() << "'");
319 void RenderTools::DrawSelectionBackground(vcl::RenderContext
& rRenderContext
, vcl::Window
& rWindow
,
320 const Rectangle
& rRect
, sal_uInt16 nHighlight
,
321 bool bChecked
, bool bDrawBorder
, bool bDrawExtBorderOnly
,
322 Color
* pSelectionTextColor
, long nCornerRadius
, Color
* pPaintColor
)
327 bool bRoundEdges
= nCornerRadius
> 0;
329 const StyleSettings
& rStyles
= rRenderContext
.GetSettings().GetStyleSettings();
331 // colors used for item highlighting
332 Color
aSelectionBorderColor(pPaintColor
? *pPaintColor
: rStyles
.GetHighlightColor());
333 Color
aSelectionFillColor(aSelectionBorderColor
);
335 bool bDark
= rStyles
.GetFaceColor().IsDark();
336 bool bBright
= ( rStyles
.GetFaceColor() == Color( COL_WHITE
) );
338 int c1
= aSelectionBorderColor
.GetLuminance();
339 int c2
= rWindow
.GetDisplayBackground().GetColor().GetLuminance();
341 if (!bDark
&& !bBright
&& std::abs(c2
- c1
) < (pPaintColor
? 40 : 75))
345 aSelectionFillColor
.RGBtoHSB( h
, s
, b
);
346 if( b
> 50 ) b
-= 40;
348 aSelectionFillColor
.SetColor( Color::HSBtoRGB( h
, s
, b
) );
349 aSelectionBorderColor
= aSelectionFillColor
;
354 if (aSelectionBorderColor
.IsDark())
355 aSelectionBorderColor
.IncreaseLuminance(128);
357 aSelectionBorderColor
.DecreaseLuminance(128);
360 Rectangle
aRect(rRect
);
361 if (bDrawExtBorderOnly
)
368 rRenderContext
.Push(PushFlags::FILLCOLOR
| PushFlags::LINECOLOR
);
371 rRenderContext
.SetLineColor(bDark
? Color(COL_WHITE
) : (bBright
? Color(COL_BLACK
) : aSelectionBorderColor
));
373 rRenderContext
.SetLineColor();
375 sal_uInt16 nPercent
= 0;
379 aSelectionFillColor
= COL_BLACK
;
381 nPercent
= 80; // just checked (light)
385 if (bChecked
&& nHighlight
== 2)
388 aSelectionFillColor
= COL_LIGHTGRAY
;
391 aSelectionFillColor
= COL_BLACK
;
392 rRenderContext
.SetLineColor(COL_BLACK
);
396 nPercent
= bRoundEdges
? 40 : 20; // selected, pressed or checked ( very dark )
398 else if (bChecked
|| nHighlight
== 1)
401 aSelectionFillColor
= COL_GRAY
;
404 aSelectionFillColor
= COL_BLACK
;
405 rRenderContext
.SetLineColor(COL_BLACK
);
409 nPercent
= bRoundEdges
? 60 : 35; // selected, pressed or checked ( very dark )
414 aSelectionFillColor
= COL_LIGHTGRAY
;
417 aSelectionFillColor
= COL_BLACK
;
418 rRenderContext
.SetLineColor(COL_BLACK
);
425 nPercent
= 70; // selected ( dark )
429 if (bDark
&& bDrawExtBorderOnly
)
431 rRenderContext
.SetFillColor();
432 if (pSelectionTextColor
)
433 *pSelectionTextColor
= rStyles
.GetHighlightTextColor();
437 rRenderContext
.SetFillColor(aSelectionFillColor
);
438 if (pSelectionTextColor
)
440 Color aTextColor
= rWindow
.IsControlBackground() ? rWindow
.GetControlForeground() : rStyles
.GetButtonTextColor();
441 Color aHLTextColor
= rStyles
.GetHighlightTextColor();
442 int nTextDiff
= std::abs(aSelectionFillColor
.GetLuminance() - aTextColor
.GetLuminance());
443 int nHLDiff
= std::abs(aSelectionFillColor
.GetLuminance() - aHLTextColor
.GetLuminance());
444 *pSelectionTextColor
= (nHLDiff
>= nTextDiff
) ? aHLTextColor
: aTextColor
;
450 rRenderContext
.DrawRect(aRect
);
456 tools::Polygon
aPoly(aRect
, nCornerRadius
, nCornerRadius
);
457 tools::PolyPolygon
aPolyPoly(aPoly
);
458 rRenderContext
.DrawTransparent(aPolyPoly
, nPercent
);
462 tools::Polygon
aPoly(aRect
);
463 tools::PolyPolygon
aPolyPoly(aPoly
);
464 rRenderContext
.DrawTransparent(aPolyPoly
, nPercent
);
468 rRenderContext
.Pop(); // LINECOLOR | FILLCOLOR
471 void Window::PushPaintHelper(PaintHelper
*pHelper
, vcl::RenderContext
& rRenderContext
)
475 if ( mpWindowImpl
->mpCursor
)
476 pHelper
->SetRestoreCursor(mpWindowImpl
->mpCursor
->ImplSuspend());
478 mbInitClipRegion
= true;
479 mpWindowImpl
->mbInPaint
= true;
481 // restore Paint-Region
482 vcl::Region
&rPaintRegion
= pHelper
->GetPaintRegion();
483 rPaintRegion
= mpWindowImpl
->maInvalidateRegion
;
484 Rectangle aPaintRect
= rPaintRegion
.GetBoundRect();
486 // - RTL - re-mirror paint rect and region at this window
487 if (ImplIsAntiparallel())
489 rRenderContext
.ReMirror(aPaintRect
);
490 rRenderContext
.ReMirror(rPaintRegion
);
492 aPaintRect
= ImplDevicePixelToLogic(aPaintRect
);
493 mpWindowImpl
->mpPaintRegion
= &rPaintRegion
;
494 mpWindowImpl
->maInvalidateRegion
.SetEmpty();
496 if ((pHelper
->GetPaintFlags() & IMPL_PAINT_ERASE
) && rRenderContext
.IsBackground())
498 if (rRenderContext
.IsClipRegion())
500 vcl::Region aOldRegion
= rRenderContext
.GetClipRegion();
501 rRenderContext
.SetClipRegion();
502 Erase(rRenderContext
);
503 rRenderContext
.SetClipRegion(aOldRegion
);
506 Erase(rRenderContext
);
509 // #98943# trigger drawing of toolbox selection after all children are painted
510 if (mpWindowImpl
->mbDrawSelectionBackground
)
511 pHelper
->SetSelectionRect(aPaintRect
);
512 pHelper
->SetPaintRect(aPaintRect
);
515 void Window::PopPaintHelper(PaintHelper
*pHelper
)
517 if (mpWindowImpl
->mpWinData
)
519 if (mpWindowImpl
->mbFocusVisible
)
520 ImplInvertFocus(*(mpWindowImpl
->mpWinData
->mpFocusRect
));
522 mpWindowImpl
->mbInPaint
= false;
523 mbInitClipRegion
= true;
524 mpWindowImpl
->mpPaintRegion
= nullptr;
525 if (mpWindowImpl
->mpCursor
)
526 mpWindowImpl
->mpCursor
->ImplResume(pHelper
->GetRestoreCursor());
529 } /* namespace vcl */
531 PaintHelper::~PaintHelper()
533 WindowImpl
* pWindowImpl
= m_pWindow
->ImplGetWindowImpl();
536 m_pWindow
->PopPaintHelper(this);
539 ImplFrameData
* pFrameData
= m_pWindow
->mpWindowImpl
->mpFrameData
;
540 if ( m_nPaintFlags
& (IMPL_PAINT_PAINTALLCHILDREN
| IMPL_PAINT_PAINTCHILDREN
) )
542 // Paint from the bottom child window and frontward.
543 vcl::Window
* pTempWindow
= pWindowImpl
->mpLastChild
;
546 if (pTempWindow
->mpWindowImpl
->mbVisible
)
547 pTempWindow
->ImplCallPaint(m_pChildRegion
, m_nPaintFlags
);
548 pTempWindow
= pTempWindow
->mpWindowImpl
->mpPrev
;
552 if ( pWindowImpl
->mpWinData
&& pWindowImpl
->mbTrackVisible
&& (pWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
553 /* #98602# need to invert the tracking rect AFTER
554 * the children have painted
556 m_pWindow
->InvertTracking( *(pWindowImpl
->mpWinData
->mpTrackRect
), pWindowImpl
->mpWinData
->mnTrackFlags
);
558 // double-buffering: paint in case we created the buffer, the children are
559 // already painted inside
560 if (m_bStartedBufferedPaint
&& pFrameData
->mbInBufferedPaint
)
563 pFrameData
->mbInBufferedPaint
= false;
564 pFrameData
->maBufferedRect
= Rectangle();
567 // #98943# draw toolbox selection
568 if( !m_aSelectionRect
.IsEmpty() )
569 m_pWindow
->DrawSelectionBackground( m_aSelectionRect
, 3, false, true );
571 delete m_pChildRegion
;
576 void Window::ImplCallPaint(const vcl::Region
* pRegion
, sal_uInt16 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
& IMPL_PAINT_PAINTALLCHILDREN
)
585 mpWindowImpl
->mnPaintFlags
|= IMPL_PAINT_PAINT
| IMPL_PAINT_PAINTALLCHILDREN
| (nPaintFlags
& IMPL_PAINT_PAINTALL
);
586 if (nPaintFlags
& IMPL_PAINT_PAINTCHILDREN
)
587 mpWindowImpl
->mnPaintFlags
|= IMPL_PAINT_PAINTCHILDREN
;
588 if (nPaintFlags
& IMPL_PAINT_ERASE
)
589 mpWindowImpl
->mnPaintFlags
|= IMPL_PAINT_ERASE
;
590 if (nPaintFlags
& IMPL_PAINT_CHECKRTL
)
591 mpWindowImpl
->mnPaintFlags
|= IMPL_PAINT_CHECKRTL
;
592 if (!mpWindowImpl
->mpFirstChild
)
593 mpWindowImpl
->mnPaintFlags
&= ~IMPL_PAINT_PAINTALLCHILDREN
;
595 if (mpWindowImpl
->mbPaintDisabled
)
597 if (mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_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
& ~(IMPL_PAINT_PAINT
);
610 PaintHelper
aHelper(this, nPaintFlags
);
612 if (mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINT
)
613 aHelper
.DoPaint(pRegion
);
615 mpWindowImpl
->mnPaintFlags
= 0;
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
& (IMPL_PAINT_PAINT
| IMPL_PAINT_PAINTCHILDREN
) )
635 // - RTL - notify ImplCallPaint to check for re-mirroring (CHECKRTL)
636 // because we were called from the Sal layer
637 ImplCallPaint(nullptr, mpWindowImpl
->mnPaintFlags
/*| IMPL_PAINT_CHECKRTL */);
641 IMPL_LINK_NOARG(Window
, ImplHandlePaintHdl
, Idle
*, void)
643 // save paint events until layout is done
644 if (IsSystemWindow() && static_cast<const SystemWindow
*>(this)->hasPendingLayout())
646 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
650 // save paint events until resizing or initial sizing done
651 if (mpWindowImpl
->mbFrame
&&
652 mpWindowImpl
->mpFrameData
->maResizeIdle
.IsActive())
654 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
656 else if ( mpWindowImpl
->mbReallyVisible
)
658 ImplCallOverlapPaint();
662 IMPL_LINK_NOARG(Window
, ImplHandleResizeTimerHdl
, Idle
*, void)
664 if( mpWindowImpl
->mbReallyVisible
)
667 if( mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive() )
669 mpWindowImpl
->mpFrameData
->maPaintIdle
.Stop();
670 mpWindowImpl
->mpFrameData
->maPaintIdle
.GetIdleHdl().Call( nullptr );
675 void Window::ImplInvalidateFrameRegion( const vcl::Region
* pRegion
, InvalidateFlags nFlags
)
677 // set PAINTCHILDREN for all parent windows till the first OverlapWindow
678 if ( !ImplIsOverlapWindow() )
680 vcl::Window
* pTempWindow
= this;
681 sal_uInt16 nTranspPaint
= IsPaintTransparent() ? IMPL_PAINT_PAINT
: 0;
684 pTempWindow
= pTempWindow
->ImplGetParent();
685 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTCHILDREN
)
687 pTempWindow
->mpWindowImpl
->mnPaintFlags
|= IMPL_PAINT_PAINTCHILDREN
| nTranspPaint
;
688 if( ! pTempWindow
->IsPaintTransparent() )
691 while ( !pTempWindow
->ImplIsOverlapWindow() );
695 mpWindowImpl
->mnPaintFlags
|= IMPL_PAINT_PAINT
;
696 if ( nFlags
& InvalidateFlags::Children
)
697 mpWindowImpl
->mnPaintFlags
|= IMPL_PAINT_PAINTALLCHILDREN
;
698 if ( !(nFlags
& InvalidateFlags::NoErase
) )
699 mpWindowImpl
->mnPaintFlags
|= IMPL_PAINT_ERASE
;
701 mpWindowImpl
->mnPaintFlags
|= IMPL_PAINT_PAINTALL
;
703 // if not everything has to be redrawn, add the region to it
704 if ( !(mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTALL
) )
705 mpWindowImpl
->maInvalidateRegion
.Union( *pRegion
);
707 // Handle transparent windows correctly: invalidate must be done on the first opaque parent
708 if( ((IsPaintTransparent() && !(nFlags
& InvalidateFlags::NoTransparent
)) || (nFlags
& InvalidateFlags::Transparent
) )
711 vcl::Window
*pParent
= ImplGetParent();
712 while( pParent
&& pParent
->IsPaintTransparent() )
713 pParent
= pParent
->ImplGetParent();
716 vcl::Region
*pChildRegion
;
717 if ( mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTALL
)
718 // invalidate the whole child window region in the parent
719 pChildRegion
= ImplGetWinChildClipRegion();
721 // invalidate the same region in the parent that has to be repainted in the child
722 pChildRegion
= &mpWindowImpl
->maInvalidateRegion
;
724 nFlags
|= InvalidateFlags::Children
; // paint should also be done on all children
725 nFlags
&= ~InvalidateFlags::NoErase
; // parent should paint and erase to create proper background
726 pParent
->ImplInvalidateFrameRegion( pChildRegion
, nFlags
);
730 if ( !mpWindowImpl
->mpFrameData
->maPaintIdle
.IsActive() )
731 mpWindowImpl
->mpFrameData
->maPaintIdle
.Start();
734 void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region
& rRegion
)
736 vcl::Region aRegion
= rRegion
;
738 ImplClipBoundaries( aRegion
, true, true );
739 if ( !aRegion
.IsEmpty() )
740 ImplInvalidateFrameRegion( &aRegion
, InvalidateFlags::Children
);
742 // now we invalidate the overlapping windows
743 vcl::Window
* pTempWindow
= mpWindowImpl
->mpFirstOverlap
;
744 while ( pTempWindow
)
746 if ( pTempWindow
->IsVisible() )
747 pTempWindow
->ImplInvalidateOverlapFrameRegion( rRegion
);
749 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
753 void Window::ImplInvalidateParentFrameRegion( vcl::Region
& rRegion
)
755 if ( mpWindowImpl
->mbOverlapWin
)
756 mpWindowImpl
->mpFrameWindow
->ImplInvalidateOverlapFrameRegion( rRegion
);
759 if( ImplGetParent() )
760 ImplGetParent()->ImplInvalidateFrameRegion( &rRegion
, InvalidateFlags::Children
);
764 void Window::ImplInvalidate( const vcl::Region
* pRegion
, InvalidateFlags nFlags
)
766 // check what has to be redrawn
767 bool bInvalidateAll
= !pRegion
;
769 // take Transparent-Invalidate into account
770 vcl::Window
* pOpaqueWindow
= this;
771 if ( (mpWindowImpl
->mbPaintTransparent
&& !(nFlags
& InvalidateFlags::NoTransparent
)) || (nFlags
& InvalidateFlags::Transparent
) )
773 vcl::Window
* pTempWindow
= pOpaqueWindow
->ImplGetParent();
774 while ( pTempWindow
)
776 if ( !pTempWindow
->IsPaintTransparent() )
778 pOpaqueWindow
= pTempWindow
;
779 nFlags
|= InvalidateFlags::Children
;
780 bInvalidateAll
= false;
784 if ( pTempWindow
->ImplIsOverlapWindow() )
787 pTempWindow
= pTempWindow
->ImplGetParent();
792 InvalidateFlags nOrgFlags
= nFlags
;
793 if ( !(nFlags
& (InvalidateFlags::Children
| InvalidateFlags::NoChildren
)) )
795 if ( GetStyle() & WB_CLIPCHILDREN
)
796 nFlags
|= InvalidateFlags::NoChildren
;
798 nFlags
|= InvalidateFlags::Children
;
800 if ( (nFlags
& InvalidateFlags::NoChildren
) && mpWindowImpl
->mpFirstChild
)
801 bInvalidateAll
= false;
802 if ( bInvalidateAll
)
803 ImplInvalidateFrameRegion( nullptr, nFlags
);
806 Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
807 vcl::Region
aRegion( aRect
);
810 // --- RTL --- remirror region before intersecting it
811 if ( ImplIsAntiparallel() )
813 const OutputDevice
*pOutDev
= GetOutDev();
815 vcl::Region
aRgn( *pRegion
);
816 pOutDev
->ReMirror( aRgn
);
817 aRegion
.Intersect( aRgn
);
820 aRegion
.Intersect( *pRegion
);
822 ImplClipBoundaries( aRegion
, true, true );
823 if ( nFlags
& InvalidateFlags::NoChildren
)
825 nFlags
&= ~InvalidateFlags::Children
;
826 if ( !(nFlags
& InvalidateFlags::NoClipChildren
) )
828 if ( nOrgFlags
& InvalidateFlags::NoChildren
)
829 ImplClipAllChildren( aRegion
);
832 if ( ImplClipChildren( aRegion
) )
833 nFlags
|= InvalidateFlags::Children
;
837 if ( !aRegion
.IsEmpty() )
838 ImplInvalidateFrameRegion( &aRegion
, nFlags
); // transparency is handled here, pOpaqueWindow not required
841 if ( nFlags
& InvalidateFlags::Update
)
842 pOpaqueWindow
->Update(); // start painting at the opaque parent
845 void Window::ImplMoveInvalidateRegion( const Rectangle
& rRect
,
846 long nHorzScroll
, long nVertScroll
,
849 if ( (mpWindowImpl
->mnPaintFlags
& (IMPL_PAINT_PAINT
| IMPL_PAINT_PAINTALL
)) == IMPL_PAINT_PAINT
)
851 vcl::Region aTempRegion
= mpWindowImpl
->maInvalidateRegion
;
852 aTempRegion
.Intersect( rRect
);
853 aTempRegion
.Move( nHorzScroll
, nVertScroll
);
854 mpWindowImpl
->maInvalidateRegion
.Union( aTempRegion
);
857 if ( bChildren
&& (mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTCHILDREN
) )
859 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstChild
;
862 pWindow
->ImplMoveInvalidateRegion( rRect
, nHorzScroll
, nVertScroll
, true );
863 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
868 void Window::ImplMoveAllInvalidateRegions( const Rectangle
& rRect
,
869 long nHorzScroll
, long nVertScroll
,
872 // also shift Paint-Region when paints need processing
873 ImplMoveInvalidateRegion( rRect
, nHorzScroll
, nVertScroll
, bChildren
);
874 // Paint-Region should be shifted, as drawn by the parents
875 if ( !ImplIsOverlapWindow() )
877 vcl::Region aPaintAllRegion
;
878 vcl::Window
* pPaintAllWindow
= this;
881 pPaintAllWindow
= pPaintAllWindow
->ImplGetParent();
882 if ( pPaintAllWindow
->mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTALLCHILDREN
)
884 if ( pPaintAllWindow
->mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTALL
)
886 aPaintAllRegion
.SetEmpty();
890 aPaintAllRegion
.Union( pPaintAllWindow
->mpWindowImpl
->maInvalidateRegion
);
893 while ( !pPaintAllWindow
->ImplIsOverlapWindow() );
894 if ( !aPaintAllRegion
.IsEmpty() )
896 aPaintAllRegion
.Move( nHorzScroll
, nVertScroll
);
897 InvalidateFlags nPaintFlags
= InvalidateFlags::NONE
;
899 nPaintFlags
|= InvalidateFlags::Children
;
900 ImplInvalidateFrameRegion( &aPaintAllRegion
, nPaintFlags
);
905 void Window::ImplValidateFrameRegion( const vcl::Region
* pRegion
, ValidateFlags nFlags
)
908 mpWindowImpl
->maInvalidateRegion
.SetEmpty();
911 // when all child windows have to be drawn we need to invalidate them before doing so
912 if ( (mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTALLCHILDREN
) && mpWindowImpl
->mpFirstChild
)
914 vcl::Region aChildRegion
= mpWindowImpl
->maInvalidateRegion
;
915 if ( mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTALL
)
917 Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
918 aChildRegion
= aRect
;
920 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
923 pChild
->Invalidate( aChildRegion
, InvalidateFlags::Children
| InvalidateFlags::NoTransparent
);
924 pChild
= pChild
->mpWindowImpl
->mpNext
;
927 if ( mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTALL
)
929 Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
930 mpWindowImpl
->maInvalidateRegion
= aRect
;
932 mpWindowImpl
->maInvalidateRegion
.Exclude( *pRegion
);
934 mpWindowImpl
->mnPaintFlags
&= ~IMPL_PAINT_PAINTALL
;
936 if ( nFlags
& ValidateFlags::Children
)
938 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
941 pChild
->ImplValidateFrameRegion( pRegion
, nFlags
);
942 pChild
= pChild
->mpWindowImpl
->mpNext
;
947 void Window::ImplValidate()
950 bool bValidateAll
= true;
951 ValidateFlags nFlags
= ValidateFlags::NONE
;
952 if ( GetStyle() & WB_CLIPCHILDREN
)
953 nFlags
|= ValidateFlags::NoChildren
;
955 nFlags
|= ValidateFlags::Children
;
956 if ( (nFlags
& ValidateFlags::NoChildren
) && mpWindowImpl
->mpFirstChild
)
957 bValidateAll
= false;
959 ImplValidateFrameRegion( nullptr, nFlags
);
962 Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
963 vcl::Region
aRegion( aRect
);
964 ImplClipBoundaries( aRegion
, true, true );
965 if ( nFlags
& ValidateFlags::NoChildren
)
967 nFlags
&= ~ValidateFlags::Children
;
968 if ( ImplClipChildren( aRegion
) )
969 nFlags
|= ValidateFlags::Children
;
971 if ( !aRegion
.IsEmpty() )
972 ImplValidateFrameRegion( &aRegion
, nFlags
);
976 void Window::ImplUpdateAll()
978 if ( !mpWindowImpl
->mbReallyVisible
)
982 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
984 Point
aPoint( 0, 0 );
985 vcl::Region
aRegion( Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
986 ImplInvalidateOverlapFrameRegion( aRegion
);
987 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
991 // an update changes the OverlapWindow, such that for later paints
992 // not too much has to be drawn, if ALLCHILDREN etc. is set
993 vcl::Window
* pWindow
= ImplGetFirstOverlapWindow();
994 pWindow
->ImplCallOverlapPaint();
1000 void Window::PrePaint(vcl::RenderContext
& /*rRenderContext*/)
1004 void Window::PostPaint(vcl::RenderContext
& /*rRenderContext*/)
1008 void Window::Paint(vcl::RenderContext
& /*rRenderContext*/, const Rectangle
& rRect
)
1010 CallEventListeners(VCLEVENT_WINDOW_PAINT
, const_cast<Rectangle
*>(&rRect
));
1013 void Window::SetPaintTransparent( bool bTransparent
)
1015 // transparency is not useful for frames as the background would have to be provided by a different frame
1016 if( bTransparent
&& mpWindowImpl
->mbFrame
)
1019 if ( mpWindowImpl
->mpBorderWindow
)
1020 mpWindowImpl
->mpBorderWindow
->SetPaintTransparent( bTransparent
);
1022 mpWindowImpl
->mbPaintTransparent
= bTransparent
;
1025 void Window::SetWindowRegionPixel()
1028 if ( mpWindowImpl
->mpBorderWindow
)
1029 mpWindowImpl
->mpBorderWindow
->SetWindowRegionPixel();
1030 else if( mpWindowImpl
->mbFrame
)
1032 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1033 mpWindowImpl
->mbWinRegion
= false;
1034 mpWindowImpl
->mpFrame
->ResetClipRegion();
1038 if ( mpWindowImpl
->mbWinRegion
)
1040 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1041 mpWindowImpl
->mbWinRegion
= false;
1044 if ( IsReallyVisible() )
1046 Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
1047 vcl::Region
aRegion( aRect
);
1048 ImplInvalidateParentFrameRegion( aRegion
);
1054 void Window::SetWindowRegionPixel( const vcl::Region
& rRegion
)
1057 if ( mpWindowImpl
->mpBorderWindow
)
1058 mpWindowImpl
->mpBorderWindow
->SetWindowRegionPixel( rRegion
);
1059 else if( mpWindowImpl
->mbFrame
)
1061 if( !rRegion
.IsNull() )
1063 mpWindowImpl
->maWinRegion
= rRegion
;
1064 mpWindowImpl
->mbWinRegion
= ! rRegion
.IsEmpty();
1066 if( mpWindowImpl
->mbWinRegion
)
1068 // set/update ClipRegion
1069 RectangleVector aRectangles
;
1070 mpWindowImpl
->maWinRegion
.GetRegionRectangles(aRectangles
);
1071 mpWindowImpl
->mpFrame
->BeginSetClipRegion(aRectangles
.size());
1073 for(RectangleVector::const_iterator
aRectIter(aRectangles
.begin()); aRectIter
!= aRectangles
.end(); ++aRectIter
)
1075 mpWindowImpl
->mpFrame
->UnionClipRegion(
1078 aRectIter
->GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
1079 aRectIter
->GetHeight()); // same for height
1082 mpWindowImpl
->mpFrame
->EndSetClipRegion();
1088 //sal_uLong nRectCount;
1089 //ImplRegionInfo aInfo;
1090 //sal_Bool bRegionRect;
1092 //nRectCount = mpWindowImpl->maWinRegion.GetRectCount();
1093 //mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount );
1094 //bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
1095 //while ( bRegionRect )
1097 // mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight );
1098 // bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
1100 //mpWindowImpl->mpFrame->EndSetClipRegion();
1103 SetWindowRegionPixel();
1106 SetWindowRegionPixel();
1110 if ( rRegion
.IsNull() )
1112 if ( mpWindowImpl
->mbWinRegion
)
1114 mpWindowImpl
->maWinRegion
= vcl::Region(true);
1115 mpWindowImpl
->mbWinRegion
= false;
1121 mpWindowImpl
->maWinRegion
= rRegion
;
1122 mpWindowImpl
->mbWinRegion
= true;
1126 if ( IsReallyVisible() )
1128 Rectangle
aRect( Point( mnOutOffX
, mnOutOffY
), Size( mnOutWidth
, mnOutHeight
) );
1129 vcl::Region
aRegion( aRect
);
1130 ImplInvalidateParentFrameRegion( aRegion
);
1135 const vcl::Region
& Window::GetWindowRegionPixel() const
1138 if ( mpWindowImpl
->mpBorderWindow
)
1139 return mpWindowImpl
->mpBorderWindow
->GetWindowRegionPixel();
1141 return mpWindowImpl
->maWinRegion
;
1144 bool Window::IsWindowRegionPixel() const
1147 if ( mpWindowImpl
->mpBorderWindow
)
1148 return mpWindowImpl
->mpBorderWindow
->IsWindowRegionPixel();
1150 return mpWindowImpl
->mbWinRegion
;
1153 vcl::Region
Window::GetPaintRegion() const
1156 if ( mpWindowImpl
->mpPaintRegion
)
1158 vcl::Region aRegion
= *mpWindowImpl
->mpPaintRegion
;
1159 aRegion
.Move( -mnOutOffX
, -mnOutOffY
);
1160 return PixelToLogic( aRegion
);
1164 vcl::Region
aPaintRegion(true);
1165 return aPaintRegion
;
1169 void Window::Invalidate( InvalidateFlags nFlags
)
1171 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1174 ImplInvalidate( nullptr, nFlags
);
1175 LogicInvalidate(nullptr);
1178 void Window::Invalidate( const Rectangle
& rRect
, InvalidateFlags nFlags
)
1180 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1183 OutputDevice
*pOutDev
= GetOutDev();
1184 Rectangle aRect
= pOutDev
->ImplLogicToDevicePixel( rRect
);
1185 if ( !aRect
.IsEmpty() )
1187 vcl::Region
aRegion( aRect
);
1188 ImplInvalidate( &aRegion
, nFlags
);
1189 Rectangle
aLogicRectangle(rRect
);
1190 LogicInvalidate(&aLogicRectangle
);
1194 void Window::Invalidate( const vcl::Region
& rRegion
, InvalidateFlags nFlags
)
1196 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1199 if ( rRegion
.IsNull() )
1201 ImplInvalidate( nullptr, nFlags
);
1202 LogicInvalidate(nullptr);
1206 vcl::Region aRegion
= ImplPixelToDevicePixel( LogicToPixel( rRegion
) );
1207 if ( !aRegion
.IsEmpty() )
1209 ImplInvalidate( &aRegion
, nFlags
);
1210 Rectangle aLogicRectangle
= rRegion
.GetBoundRect();
1211 LogicInvalidate(&aLogicRectangle
);
1216 void Window::LogicInvalidate(const Rectangle
* pRectangle
)
1218 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1221 if (const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
1223 // In case we are routing the window, notify the client
1224 std::vector
<vcl::LOKPayloadItem
> aPayload
;
1226 aPayload
.push_back(std::make_pair(OString("rectangle"), pRectangle
->toString()));
1228 pNotifier
->notifyWindow(GetLOKWindowId(), "invalidate", aPayload
);
1230 // Added for dialog items. Pass invalidation to the parent window.
1231 else if (VclPtr
<vcl::Window
> pParent
= GetParentWithLOKNotifier())
1233 const Rectangle
aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), Size(GetOutputWidthPixel(), GetOutputHeightPixel()));
1234 pParent
->LogicInvalidate(&aRect
);
1238 void Window::Validate()
1240 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth
|| !mnOutHeight
) )
1246 bool Window::HasPaintEvent() const
1249 if ( !mpWindowImpl
->mbReallyVisible
)
1252 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1255 if ( mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINT
)
1258 if ( !ImplIsOverlapWindow() )
1260 const vcl::Window
* pTempWindow
= this;
1263 pTempWindow
= pTempWindow
->ImplGetParent();
1264 if ( pTempWindow
->mpWindowImpl
->mnPaintFlags
& (IMPL_PAINT_PAINTCHILDREN
| IMPL_PAINT_PAINTALLCHILDREN
) )
1267 while ( !pTempWindow
->ImplIsOverlapWindow() );
1273 void Window::Update()
1275 if ( mpWindowImpl
->mpBorderWindow
)
1277 mpWindowImpl
->mpBorderWindow
->Update();
1281 if ( !mpWindowImpl
->mbReallyVisible
)
1284 bool bFlush
= false;
1285 if ( mpWindowImpl
->mpFrameWindow
->mpWindowImpl
->mbPaintFrame
)
1287 Point
aPoint( 0, 0 );
1288 vcl::Region
aRegion( Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
1289 ImplInvalidateOverlapFrameRegion( aRegion
);
1290 if ( mpWindowImpl
->mbFrame
|| (mpWindowImpl
->mpBorderWindow
&& mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
1294 // First we should skip all windows which are Paint-Transparent
1295 vcl::Window
* pUpdateWindow
= this;
1296 vcl::Window
* pWindow
= pUpdateWindow
;
1297 while ( !pWindow
->ImplIsOverlapWindow() )
1299 if ( !pWindow
->mpWindowImpl
->mbPaintTransparent
)
1301 pUpdateWindow
= pWindow
;
1304 pWindow
= pWindow
->ImplGetParent();
1306 // In order to limit drawing, an update only draws the window which
1307 // has PAINTALLCHILDREN set
1308 pWindow
= pUpdateWindow
;
1311 if ( pWindow
->mpWindowImpl
->mnPaintFlags
& IMPL_PAINT_PAINTALLCHILDREN
)
1312 pUpdateWindow
= pWindow
;
1313 if ( pWindow
->ImplIsOverlapWindow() )
1315 pWindow
= pWindow
->ImplGetParent();
1319 // if there is something to paint, trigger a Paint
1320 if ( pUpdateWindow
->mpWindowImpl
->mnPaintFlags
& (IMPL_PAINT_PAINT
| IMPL_PAINT_PAINTCHILDREN
) )
1322 VclPtr
<vcl::Window
> xWindow(this);
1324 // trigger an update also for system windows on top of us,
1325 // otherwise holes would remain
1326 vcl::Window
* pUpdateOverlapWindow
= ImplGetFirstOverlapWindow()->mpWindowImpl
->mpFirstOverlap
;
1327 while ( pUpdateOverlapWindow
)
1329 pUpdateOverlapWindow
->Update();
1330 pUpdateOverlapWindow
= pUpdateOverlapWindow
->mpWindowImpl
->mpNext
;
1333 pUpdateWindow
->ImplCallPaint(nullptr, pUpdateWindow
->mpWindowImpl
->mnPaintFlags
);
1335 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow
->GetParentDialog())
1336 pUpdateWindow
->LogicInvalidate(nullptr);
1338 if (xWindow
->IsDisposed())
1348 void Window::ImplPaintToDevice( OutputDevice
* i_pTargetOutDev
, const Point
& i_rPos
)
1350 bool bRVisible
= mpWindowImpl
->mbReallyVisible
;
1351 mpWindowImpl
->mbReallyVisible
= mpWindowImpl
->mbVisible
;
1352 bool bDevOutput
= mbDevOutput
;
1355 const OutputDevice
*pOutDev
= GetOutDev();
1356 long nOldDPIX
= pOutDev
->GetDPIX();
1357 long nOldDPIY
= pOutDev
->GetDPIY();
1358 mnDPIX
= i_pTargetOutDev
->GetDPIX();
1359 mnDPIY
= i_pTargetOutDev
->GetDPIY();
1360 bool bOutput
= IsOutputEnabled();
1365 bool bNeedsScaling
= false;
1366 if(comphelper::LibreOfficeKit::isActive())
1368 if(GetMapMode().GetMapUnit() != MapUnit::MapPixel
&&
1369 // Some of the preview windows (SvxPreviewBase) uses different painting (drawinglayer primitives)
1370 // For these preview we don't need to scale even tough the unit is not pixel.
1371 GetMapMode().GetMapUnit() != MapUnit::Map100thMM
)
1373 bNeedsScaling
= true;
1374 // 1000.0 is used to reduce rounding imprecision (Size uses integers)
1375 Size aLogicSize
= PixelToLogic(Size(1000.0, 1000.0));
1376 fScaleX
= aLogicSize
.Width() / 1000.0;
1377 fScaleY
= aLogicSize
.Height() / 1000.0;
1381 { // TODO: Above scaling was added for LOK only, would be good to check how it works in other use cases
1382 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel
, "vcl", "MapMode must be PIXEL based" );
1383 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel
)
1387 // preserve graphicsstate
1389 vcl::Region
aClipRegion( GetClipRegion() );
1392 GDIMetaFile
* pOldMtf
= GetConnectMetaFile();
1394 SetConnectMetaFile( &aMtf
);
1396 // put a push action to metafile
1398 // copy graphics state to metafile
1399 vcl::Font aCopyFont
= GetFont();
1400 if( nOldDPIX
!= mnDPIX
|| nOldDPIY
!= mnDPIY
)
1402 aCopyFont
.SetFontHeight( aCopyFont
.GetFontHeight() * mnDPIY
/ nOldDPIY
);
1403 aCopyFont
.SetAverageFontWidth( aCopyFont
.GetAverageFontWidth() * mnDPIX
/ nOldDPIX
);
1405 SetFont( aCopyFont
);
1406 SetTextColor( GetTextColor() );
1408 SetLineColor( GetLineColor() );
1412 SetFillColor( GetFillColor() );
1415 if( IsTextLineColor() )
1416 SetTextLineColor( GetTextLineColor() );
1419 if( IsOverlineColor() )
1420 SetOverlineColor( GetOverlineColor() );
1423 if( IsTextFillColor() )
1424 SetTextFillColor( GetTextFillColor() );
1427 SetTextAlign( GetTextAlign() );
1428 SetRasterOp( GetRasterOp() );
1430 SetRefPoint( GetRefPoint() );
1433 SetLayoutMode( GetLayoutMode() );
1434 SetDigitLanguage( GetDigitLanguage() );
1436 Rectangle aPaintRect
;
1439 aPaintRect
= Rectangle( Point( 0, 0 ),
1440 Size(GetOutputSizePixel().Width() * fScaleX
, GetOutputSizePixel().Height() * fScaleY
) );
1444 aPaintRect
= Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
1446 aClipRegion
.Intersect( aPaintRect
);
1447 SetClipRegion( aClipRegion
);
1449 // do the actual paint
1452 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip
) )
1456 aMtf
.Scale(fScaleX
, fScaleY
);
1459 Paint(*this, aPaintRect
);
1460 // put a pop action to metafile
1463 SetConnectMetaFile( pOldMtf
);
1464 EnableOutput( bOutput
);
1465 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1467 // paint metafile to VDev
1468 VclPtrInstance
<VirtualDevice
> pMaskedDevice(*i_pTargetOutDev
,
1469 DeviceFormat::DEFAULT
,
1470 DeviceFormat::DEFAULT
);
1473 pMaskedDevice
->SetMapMode( GetMapMode() );
1474 pMaskedDevice
->SetOutputSizePixel( GetOutputSizePixel() );
1475 pMaskedDevice
->EnableRTL( IsRTLEnabled() );
1477 aMtf
.Play( pMaskedDevice
);
1478 BitmapEx
aBmpEx( pMaskedDevice
->GetBitmapEx( Point( 0, 0 ), aPaintRect
.GetSize() ) );
1479 i_pTargetOutDev
->DrawBitmapEx( i_rPos
, aBmpEx
);
1480 // get rid of virtual device now so they don't pile up during recursive calls
1481 pMaskedDevice
.disposeAndClear();
1483 for( vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
; pChild
; pChild
= pChild
->mpWindowImpl
->mpNext
)
1485 if( pChild
->mpWindowImpl
->mpFrame
== mpWindowImpl
->mpFrame
&& pChild
->IsVisible() )
1487 long nDeltaX
= pChild
->mnOutOffX
- mnOutOffX
;
1489 if( pOutDev
->HasMirroredGraphics() )
1490 nDeltaX
= mnOutWidth
- nDeltaX
- pChild
->mnOutWidth
;
1491 long nDeltaY
= pChild
->GetOutOffYPixel() - GetOutOffYPixel();
1492 Point
aPos( i_rPos
);
1493 Point
aDelta( nDeltaX
, nDeltaY
);
1495 pChild
->ImplPaintToDevice( i_pTargetOutDev
, aPos
);
1499 // restore graphics state
1502 EnableOutput( bOutput
);
1503 mpWindowImpl
->mbReallyVisible
= bRVisible
;
1504 mbDevOutput
= bDevOutput
;
1509 void Window::PaintToDevice( OutputDevice
* pDev
, const Point
& rPos
, const Size
& /*rSize*/ )
1511 SAL_WARN_IF( pDev
->HasMirroredGraphics(), "vcl", "PaintToDevice to mirroring graphics" );
1512 SAL_WARN_IF( pDev
->IsRTLEnabled(), "vcl", "PaintToDevice to mirroring device" );
1514 vcl::Window
* pRealParent
= nullptr;
1515 if( ! mpWindowImpl
->mbVisible
)
1517 vcl::Window
* pTempParent
= ImplGetDefaultWindow();
1518 pTempParent
->EnableChildTransparentMode();
1519 pRealParent
= GetParent();
1520 SetParent( pTempParent
);
1521 // trigger correct visibility flags for children
1526 bool bVisible
= mpWindowImpl
->mbVisible
;
1527 mpWindowImpl
->mbVisible
= true;
1529 if( mpWindowImpl
->mpBorderWindow
)
1530 mpWindowImpl
->mpBorderWindow
->ImplPaintToDevice( pDev
, rPos
);
1532 ImplPaintToDevice( pDev
, rPos
);
1534 mpWindowImpl
->mbVisible
= bVisible
;
1537 SetParent( pRealParent
);
1540 void Window::Erase(vcl::RenderContext
& rRenderContext
)
1542 if (!IsDeviceOutputNecessary() || ImplIsRecordLayout())
1545 bool bNativeOK
= false;
1547 ControlPart aCtrlPart
= ImplGetWindowImpl()->mnNativeBackground
;
1548 if (aCtrlPart
!= ControlPart::NONE
&& ! IsControlBackground())
1550 Rectangle
aCtrlRegion(Point(), GetOutputSizePixel());
1551 ControlState nState
= ControlState::NONE
;
1554 nState
|= ControlState::ENABLED
;
1556 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::WindowBackground
, aCtrlPart
, aCtrlRegion
,
1557 nState
, ImplControlValue(), OUString());
1560 if (mbBackground
&& !bNativeOK
)
1562 RasterOp eRasterOp
= GetRasterOp();
1563 if (eRasterOp
!= RasterOp::OverPaint
)
1564 SetRasterOp(RasterOp::OverPaint
);
1565 rRenderContext
.DrawWallpaper(0, 0, mnOutWidth
, mnOutHeight
, maBackground
);
1566 if (eRasterOp
!= RasterOp::OverPaint
)
1567 rRenderContext
.SetRasterOp(eRasterOp
);
1571 mpAlphaVDev
->Erase();
1574 void Window::ImplScroll( const Rectangle
& rRect
,
1575 long nHorzScroll
, long nVertScroll
, ScrollFlags nFlags
)
1577 if ( !IsDeviceOutputNecessary() )
1580 nHorzScroll
= ImplLogicWidthToDevicePixel( nHorzScroll
);
1581 nVertScroll
= ImplLogicHeightToDevicePixel( nVertScroll
);
1583 if ( !nHorzScroll
&& !nVertScroll
)
1586 if ( mpWindowImpl
->mpCursor
)
1587 mpWindowImpl
->mpCursor
->ImplSuspend();
1589 ScrollFlags nOrgFlags
= nFlags
;
1590 if ( !(nFlags
& (ScrollFlags::Children
| ScrollFlags::NoChildren
)) )
1592 if ( GetStyle() & WB_CLIPCHILDREN
)
1593 nFlags
|= ScrollFlags::NoChildren
;
1595 nFlags
|= ScrollFlags::Children
;
1598 vcl::Region aInvalidateRegion
;
1599 bool bScrollChildren(nFlags
& ScrollFlags::Children
);
1601 if ( !mpWindowImpl
->mpFirstChild
)
1602 bScrollChildren
= false;
1604 OutputDevice
*pOutDev
= GetOutDev();
1606 // --- RTL --- check if this window requires special action
1607 bool bReMirror
= ( ImplIsAntiparallel() );
1609 Rectangle
aRectMirror( rRect
);
1612 // --- RTL --- make sure the invalidate region of this window is
1613 // computed in the same coordinate space as the one from the overlap windows
1614 pOutDev
->ReMirror( aRectMirror
);
1617 // adapt paint areas
1618 ImplMoveAllInvalidateRegions( aRectMirror
, nHorzScroll
, nVertScroll
, bScrollChildren
);
1620 ImplCalcOverlapRegion( aRectMirror
, aInvalidateRegion
, !bScrollChildren
, false );
1623 // if the scrolling on the device is performed in the opposite direction
1624 // then move the overlaps in that direction to compute the invalidate region
1625 // on the correct side, i.e., revert nHorzScroll
1626 if (!aInvalidateRegion
.IsEmpty())
1628 aInvalidateRegion
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1631 Rectangle
aDestRect(aRectMirror
);
1632 aDestRect
.Move(bReMirror
? -nHorzScroll
: nHorzScroll
, nVertScroll
);
1633 vcl::Region
aWinInvalidateRegion(aRectMirror
);
1634 if (!SupportsDoubleBuffering())
1636 // There will be no CopyArea() call below, so invalidate the
1637 // whole visible area, not only the smaller one that was just
1639 aWinInvalidateRegion
.Exclude(aDestRect
);
1642 aInvalidateRegion
.Union(aWinInvalidateRegion
);
1644 Point
aPoint( mnOutOffX
, mnOutOffY
);
1645 vcl::Region
aRegion( Rectangle( aPoint
, Size( mnOutWidth
, mnOutHeight
) ) );
1646 if ( nFlags
& ScrollFlags::Clip
)
1647 aRegion
.Intersect( rRect
);
1648 if ( mpWindowImpl
->mbWinRegion
)
1649 aRegion
.Intersect( ImplPixelToDevicePixel( mpWindowImpl
->maWinRegion
) );
1651 aRegion
.Exclude( aInvalidateRegion
);
1653 ImplClipBoundaries( aRegion
, false, true );
1654 if ( !bScrollChildren
)
1656 if ( nOrgFlags
& ScrollFlags::NoChildren
)
1657 ImplClipAllChildren( aRegion
);
1659 ImplClipChildren( aRegion
);
1661 if ( mbClipRegion
&& (nFlags
& ScrollFlags::UseClipRegion
) )
1662 aRegion
.Intersect( maRegion
);
1663 if ( !aRegion
.IsEmpty() )
1665 if ( mpWindowImpl
->mpWinData
)
1667 if ( mpWindowImpl
->mbFocusVisible
)
1668 ImplInvertFocus( *(mpWindowImpl
->mpWinData
->mpFocusRect
) );
1669 if ( mpWindowImpl
->mbTrackVisible
&& (mpWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
1670 InvertTracking( *(mpWindowImpl
->mpWinData
->mpTrackRect
), mpWindowImpl
->mpWinData
->mnTrackFlags
);
1673 // This seems completely unnecessary with tiled rendering, and
1674 // causes the "AquaSalGraphics::copyArea() for non-layered
1675 // graphics" message. Presumably we should bypass this on all
1676 // platforms when dealing with a "window" that uses tiled
1677 // rendering at the moment. Unclear how to figure that out,
1678 // though. Also unclear whether we actually could just not
1679 // create a "frame window", whatever that exactly is, in the
1680 // tiled rendering case, or at least for platforms where tiles
1681 // rendering is all there is.
1683 SalGraphics
* pGraphics
= ImplGetFrameGraphics();
1684 // The invalidation area contains the area what would be copied here,
1685 // so avoid copying in case of double buffering.
1686 if (pGraphics
&& !SupportsDoubleBuffering())
1690 // --- RTL --- frame coordinates require re-mirroring
1691 pOutDev
->ReMirror( aRegion
);
1694 pOutDev
->SelectClipRegion( aRegion
, pGraphics
);
1695 pGraphics
->CopyArea( rRect
.Left()+nHorzScroll
, rRect
.Top()+nVertScroll
,
1696 rRect
.Left(), rRect
.Top(),
1697 rRect
.GetWidth(), rRect
.GetHeight(),
1701 if ( mpWindowImpl
->mpWinData
)
1703 if ( mpWindowImpl
->mbFocusVisible
)
1704 ImplInvertFocus( *(mpWindowImpl
->mpWinData
->mpFocusRect
) );
1705 if ( mpWindowImpl
->mbTrackVisible
&& (mpWindowImpl
->mpWinData
->mnTrackFlags
& ShowTrackFlags::TrackWindow
) )
1706 InvertTracking( *(mpWindowImpl
->mpWinData
->mpTrackRect
), mpWindowImpl
->mpWinData
->mnTrackFlags
);
1710 if ( !aInvalidateRegion
.IsEmpty() )
1712 // --- RTL --- the invalidate region for this windows is already computed in frame coordinates
1713 // so it has to be re-mirrored before calling the Paint-handler
1714 mpWindowImpl
->mnPaintFlags
|= IMPL_PAINT_CHECKRTL
;
1716 InvalidateFlags nPaintFlags
= InvalidateFlags::Children
;
1717 if ( !bScrollChildren
)
1719 if ( nOrgFlags
& ScrollFlags::NoChildren
)
1720 ImplClipAllChildren( aInvalidateRegion
);
1722 ImplClipChildren( aInvalidateRegion
);
1724 ImplInvalidateFrameRegion( &aInvalidateRegion
, nPaintFlags
);
1727 if ( bScrollChildren
)
1729 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstChild
;
1732 Point aPos
= pWindow
->GetPosPixel();
1733 aPos
+= Point( nHorzScroll
, nVertScroll
);
1734 pWindow
->SetPosPixel( aPos
);
1736 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
1740 if ( nFlags
& ScrollFlags::Update
)
1743 if ( mpWindowImpl
->mpCursor
)
1744 mpWindowImpl
->mpCursor
->ImplResume();
1747 } /* namespace vcl */
1750 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */