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 .
22 #include <comphelper/lok.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/timer.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/window.hxx>
27 #include <vcl/cursor.hxx>
31 #include <tools/poly.hxx>
35 AutoTimer maTimer
{ "vcl ImplCursorData maTimer" }; // Timer
36 Point maPixPos
; // Pixel-Position
37 Point maPixRotOff
; // Pixel-Offset-Position
38 Size maPixSize
; // Pixel-Size
39 Degree10 mnOrientation
; // Pixel-Orientation
40 CursorDirection mnDirection
; // indicates writing direction
41 sal_uInt16 mnStyle
; // Cursor-Style
42 bool mbCurVisible
; // Is cursor currently visible
43 VclPtr
<vcl::Window
> mpWindow
; // assigned window
48 const char* pDisableCursorIndicator(getenv("SAL_DISABLE_CURSOR_INDICATOR"));
49 bool bDisableCursorIndicator(nullptr != pDisableCursorIndicator
);
52 static tools::Rectangle
ImplCursorInvert(vcl::RenderContext
* pRenderContext
, ImplCursorData
const * pData
)
54 tools::Rectangle aPaintRect
;
56 bool bMapMode
= pRenderContext
->IsMapModeEnabled();
57 pRenderContext
->EnableMapMode( false );
58 InvertFlags nInvertStyle
;
59 if ( pData
->mnStyle
& CURSOR_SHADOW
)
60 nInvertStyle
= InvertFlags::N50
;
62 nInvertStyle
= InvertFlags::NONE
;
64 tools::Rectangle
aRect( pData
->maPixPos
, pData
->maPixSize
);
65 if ( pData
->mnDirection
!= CursorDirection::NONE
|| pData
->mnOrientation
)
67 tools::Polygon
aPoly( aRect
);
68 if( aPoly
.GetSize() == 5 )
70 aPoly
[1].AdjustX(1 ); // include the right border
73 // apply direction flag after slant to use the correct shape
74 if (!bDisableCursorIndicator
&& pData
->mnDirection
!= CursorDirection::NONE
)
77 // Related system settings for "delta" could be:
78 // gtk cursor-aspect-ratio and windows SPI_GETCARETWIDTH
79 int delta
= (aRect
.getOpenHeight() * 4 / 100) + 1;
80 if( pData
->mnDirection
== CursorDirection::LTR
)
83 pAry
[0] = aPoly
.GetPoint( 0 );
84 pAry
[1] = aPoly
.GetPoint( 1 );
86 pAry
[2].AdjustX(delta
);
87 pAry
[2].AdjustY(delta
);
89 pAry
[3].AdjustY(delta
* 2);
90 pAry
[4] = aPoly
.GetPoint( 2 );
91 pAry
[5] = aPoly
.GetPoint( 3 );
92 pAry
[6] = aPoly
.GetPoint( 4 );
94 else if( pData
->mnDirection
== CursorDirection::RTL
)
97 pAry
[0] = aPoly
.GetPoint( 0 );
98 pAry
[1] = aPoly
.GetPoint( 1 );
99 pAry
[2] = aPoly
.GetPoint( 2 );
100 pAry
[3] = aPoly
.GetPoint( 3 );
102 pAry
[4].AdjustY(delta
*2);
104 pAry
[5].AdjustX(-delta
);
105 pAry
[5].AdjustY(delta
);
106 pAry
[6] = aPoly
.GetPoint( 4 );
108 aPoly
= tools::Polygon( 7, pAry
);
111 if ( pData
->mnOrientation
)
112 aPoly
.Rotate( pData
->maPixRotOff
, pData
->mnOrientation
);
113 pRenderContext
->Invert( aPoly
, nInvertStyle
);
114 aPaintRect
= aPoly
.GetBoundRect();
119 pRenderContext
->Invert( aRect
, nInvertStyle
);
122 pRenderContext
->EnableMapMode( bMapMode
);
126 static void ImplCursorInvert(vcl::Window
* pWindow
, ImplCursorData
const * pData
)
128 if (!pWindow
|| pWindow
->isDisposed())
131 vcl::PaintBufferGuardPtr pGuard
;
132 const bool bDoubleBuffering
= pWindow
->SupportsDoubleBuffering();
133 if (bDoubleBuffering
)
134 pGuard
.reset(new vcl::PaintBufferGuard(pWindow
->ImplGetWindowImpl()->mpFrameData
, pWindow
));
136 vcl::RenderContext
* pRenderContext
= bDoubleBuffering
? pGuard
->GetRenderContext() : pWindow
->GetOutDev();
138 tools::Rectangle aPaintRect
= ImplCursorInvert(pRenderContext
, pData
);
139 if (bDoubleBuffering
)
140 pGuard
->SetPaintRect(pRenderContext
->PixelToLogic(aPaintRect
));
143 bool vcl::Cursor::ImplPrepForDraw(const OutputDevice
* pDevice
, ImplCursorData
& rData
)
145 if (pDevice
&& !rData
.mbCurVisible
)
147 rData
.maPixPos
= pDevice
->LogicToPixel( maPos
);
148 rData
.maPixSize
= pDevice
->LogicToPixel( maSize
);
149 rData
.mnOrientation
= mnOrientation
;
150 rData
.mnDirection
= mnDirection
;
152 // correct the position with the offset
153 rData
.maPixRotOff
= rData
.maPixPos
;
155 // use width (as set in Settings) if size is 0,
156 if (!rData
.maPixSize
.Width())
157 rData
.maPixSize
.setWidth(pDevice
->GetSettings().GetStyleSettings().GetCursorSize());
163 void vcl::Cursor::ImplDraw()
165 if (mpData
&& mpData
->mpWindow
)
167 // calculate output area
168 if (ImplPrepForDraw(mpData
->mpWindow
->GetOutDev(), *mpData
))
171 ImplCursorInvert(mpData
->mpWindow
, mpData
.get());
172 mpData
->mbCurVisible
= true;
177 void vcl::Cursor::DrawToDevice(OutputDevice
& rRenderContext
)
179 ImplCursorData aData
;
181 aData
.mbCurVisible
= false;
182 // calculate output area
183 if (ImplPrepForDraw(&rRenderContext
, aData
))
186 ImplCursorInvert(&rRenderContext
, &aData
);
190 void vcl::Cursor::ImplRestore()
192 assert( mpData
&& mpData
->mbCurVisible
);
194 ImplCursorInvert(mpData
->mpWindow
, mpData
.get());
195 mpData
->mbCurVisible
= false;
198 void vcl::Cursor::ImplDoShow( bool bDrawDirect
, bool bRestore
)
203 vcl::Window
* pWindow
;
208 // show the cursor, if there is an active window and the cursor
209 // has been selected in this window
210 pWindow
= Application::GetFocusWindow();
211 if (!pWindow
|| !pWindow
->mpWindowImpl
|| (pWindow
->mpWindowImpl
->mpCursor
!= this)
212 || pWindow
->mpWindowImpl
->mbInPaint
213 || !pWindow
->mpWindowImpl
->mpFrameData
->mbHasFocus
)
222 mpData
.reset( new ImplCursorData
);
223 mpData
->mbCurVisible
= false;
224 mpData
->maTimer
.SetInvokeHandler( LINK( this, Cursor
, ImplTimerHdl
) );
227 mpData
->mpWindow
= pWindow
;
228 mpData
->mnStyle
= mnStyle
;
229 if ( bDrawDirect
|| bRestore
)
232 if ( !mpWindow
&& (bDrawDirect
|| !mpData
->maTimer
.IsActive()) )
234 mpData
->maTimer
.SetTimeout( pWindow
->GetSettings().GetStyleSettings().GetCursorBlinkTime() );
235 if ( mpData
->maTimer
.GetTimeout() != STYLE_CURSOR_NOBLINKTIME
)
236 mpData
->maTimer
.Start();
237 else if ( !mpData
->mbCurVisible
)
239 LOKNotify( pWindow
, "cursor_invalidate" );
240 LOKNotify( pWindow
, "cursor_visible" );
244 void vcl::Cursor::LOKNotify( vcl::Window
* pWindow
, const OUString
& rAction
)
246 VclPtr
<vcl::Window
> pParent
= pWindow
->GetParentWithLOKNotifier();
250 assert(pWindow
&& "Cannot notify without a window");
251 assert(mpData
&& "Require ImplCursorData");
252 assert(comphelper::LibreOfficeKit::isActive());
254 if (comphelper::LibreOfficeKit::isDialogPainting())
257 const vcl::ILibreOfficeKitNotifier
* pNotifier
= pParent
->GetLOKNotifier();
258 std::vector
<vcl::LOKPayloadItem
> aItems
;
259 if (rAction
== "cursor_visible")
260 aItems
.emplace_back("visible", mpData
->mbCurVisible
? "true" : "false");
261 else if (rAction
== "cursor_invalidate")
263 const tools::Long nX
= pWindow
->GetOutOffXPixel() + pWindow
->LogicToPixel(GetPos()).X() - pParent
->GetOutOffXPixel();
264 const tools::Long nY
= pWindow
->GetOutOffYPixel() + pWindow
->LogicToPixel(GetPos()).Y() - pParent
->GetOutOffYPixel();
265 Size aSize
= pWindow
->LogicToPixel(GetSize());
267 aSize
.setWidth( pWindow
->GetSettings().GetStyleSettings().GetCursorSize() );
271 if (pWindow
->IsRTLEnabled() && pWindow
->GetOutDev() && pParent
->GetOutDev()
272 && !pWindow
->GetOutDev()->ImplIsAntiparallel())
273 pParent
->GetOutDev()->ReMirror(aPos
);
275 if (!pWindow
->IsRTLEnabled() && pWindow
->GetOutDev() && pParent
->GetOutDev()
276 && pWindow
->GetOutDev()->ImplIsAntiparallel())
278 pWindow
->GetOutDev()->ReMirror(aPos
);
279 pParent
->GetOutDev()->ReMirror(aPos
);
282 const tools::Rectangle
aRect(aPos
, aSize
);
283 aItems
.emplace_back("rectangle", aRect
.toString());
286 pNotifier
->notifyWindow(pParent
->GetLOKWindowId(), rAction
, aItems
);
289 bool vcl::Cursor::ImplDoHide( bool bSuspend
)
291 bool bWasCurVisible
= false;
292 if ( mpData
&& mpData
->mpWindow
)
294 bWasCurVisible
= mpData
->mbCurVisible
;
295 if ( mpData
->mbCurVisible
)
300 LOKNotify( mpData
->mpWindow
, "cursor_visible" );
301 mpData
->maTimer
.Stop();
302 mpData
->mpWindow
= nullptr;
305 return bWasCurVisible
;
308 void vcl::Cursor::ImplShow()
310 ImplDoShow( true/*bDrawDirect*/, false );
313 void vcl::Cursor::ImplHide()
318 void vcl::Cursor::ImplResume( bool bRestore
)
320 ImplDoShow( false, bRestore
);
323 bool vcl::Cursor::ImplSuspend()
325 return ImplDoHide( true );
328 void vcl::Cursor::ImplNew()
330 if ( !(mbVisible
&& mpData
&& mpData
->mpWindow
) )
333 if ( mpData
->mbCurVisible
)
339 LOKNotify( mpData
->mpWindow
, "cursor_invalidate" );
340 if ( mpData
->maTimer
.GetTimeout() != STYLE_CURSOR_NOBLINKTIME
)
341 mpData
->maTimer
.Start();
345 IMPL_LINK_NOARG(vcl::Cursor
, ImplTimerHdl
, Timer
*, void)
347 if ( mpData
->mbCurVisible
)
353 vcl::Cursor::Cursor()
357 mnOrientation
= 0_deg10
;
358 mnDirection
= CursorDirection::NONE
;
363 vcl::Cursor::Cursor( const Cursor
& rCursor
) :
364 maSize( rCursor
.maSize
),
365 maPos( rCursor
.maPos
)
369 mnOrientation
= rCursor
.mnOrientation
;
370 mnDirection
= rCursor
.mnDirection
;
372 mbVisible
= rCursor
.mbVisible
;
375 vcl::Cursor::~Cursor()
377 if (mpData
&& mpData
->mbCurVisible
)
381 void vcl::Cursor::SetStyle( sal_uInt16 nStyle
)
383 if ( mnStyle
!= nStyle
)
390 void vcl::Cursor::Show()
399 void vcl::Cursor::Hide()
408 void vcl::Cursor::SetWindow( vcl::Window
* pWindow
)
410 if ( mpWindow
.get() != pWindow
)
417 void vcl::Cursor::SetPos( const Point
& rPoint
)
419 if ( maPos
!= rPoint
)
426 void vcl::Cursor::SetSize( const Size
& rSize
)
428 if ( maSize
!= rSize
)
435 void vcl::Cursor::SetWidth( tools::Long nNewWidth
)
437 if ( maSize
.Width() != nNewWidth
)
439 maSize
.setWidth( nNewWidth
);
444 void vcl::Cursor::SetOrientation( Degree10 nNewOrientation
)
446 if ( mnOrientation
!= nNewOrientation
)
448 mnOrientation
= nNewOrientation
;
453 void vcl::Cursor::SetDirection( CursorDirection nNewDirection
)
455 if ( mnDirection
!= nNewDirection
)
457 mnDirection
= nNewDirection
;
462 vcl::Cursor
& vcl::Cursor::operator=( const vcl::Cursor
& rCursor
)
464 maPos
= rCursor
.maPos
;
465 maSize
= rCursor
.maSize
;
466 mnOrientation
= rCursor
.mnOrientation
;
467 mnDirection
= rCursor
.mnDirection
;
468 mbVisible
= rCursor
.mbVisible
;
474 bool vcl::Cursor::operator==( const vcl::Cursor
& rCursor
) const
477 ((maPos
== rCursor
.maPos
) &&
478 (maSize
== rCursor
.maSize
) &&
479 (mnOrientation
== rCursor
.mnOrientation
) &&
480 (mnDirection
== rCursor
.mnDirection
) &&
481 (mbVisible
== rCursor
.mbVisible
))
485 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */