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
; // 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
46 static tools::Rectangle
ImplCursorInvert(vcl::RenderContext
* pRenderContext
, ImplCursorData
const * pData
)
48 tools::Rectangle aPaintRect
;
50 bool bMapMode
= pRenderContext
->IsMapModeEnabled();
51 pRenderContext
->EnableMapMode( false );
52 InvertFlags nInvertStyle
;
53 if ( pData
->mnStyle
& CURSOR_SHADOW
)
54 nInvertStyle
= InvertFlags::N50
;
56 nInvertStyle
= InvertFlags::NONE
;
58 tools::Rectangle
aRect( pData
->maPixPos
, pData
->maPixSize
);
59 if ( pData
->mnDirection
!= CursorDirection::NONE
|| pData
->mnOrientation
)
61 tools::Polygon
aPoly( aRect
);
62 if( aPoly
.GetSize() == 5 )
64 aPoly
[1].AdjustX(1 ); // include the right border
67 // apply direction flag after slant to use the correct shape
68 if ( pData
->mnDirection
!= CursorDirection::NONE
)
71 int delta
= 3*aRect
.getWidth()+1;
72 if( pData
->mnDirection
== CursorDirection::LTR
)
75 pAry
[0] = aPoly
.GetPoint( 0 );
76 pAry
[1] = aPoly
.GetPoint( 1 );
78 pAry
[2].AdjustX(delta
);
80 pAry
[3].AdjustY(delta
);
81 pAry
[4] = aPoly
.GetPoint( 2 );
82 pAry
[5] = aPoly
.GetPoint( 3 );
83 pAry
[6] = aPoly
.GetPoint( 4 );
85 else if( pData
->mnDirection
== CursorDirection::RTL
)
88 pAry
[0] = aPoly
.GetPoint( 0 );
89 pAry
[1] = aPoly
.GetPoint( 1 );
90 pAry
[2] = aPoly
.GetPoint( 2 );
91 pAry
[3] = aPoly
.GetPoint( 3 );
93 pAry
[4].AdjustY(delta
);
95 pAry
[5].AdjustX( -delta
);
96 pAry
[6] = aPoly
.GetPoint( 4 );
98 aPoly
= tools::Polygon( 7, pAry
);
101 if ( pData
->mnOrientation
)
102 aPoly
.Rotate( pData
->maPixRotOff
, pData
->mnOrientation
);
103 pRenderContext
->Invert( aPoly
, nInvertStyle
);
104 aPaintRect
= aPoly
.GetBoundRect();
109 pRenderContext
->Invert( aRect
, nInvertStyle
);
112 pRenderContext
->EnableMapMode( bMapMode
);
116 static void ImplCursorInvert(vcl::Window
* pWindow
, ImplCursorData
const * pData
)
118 if (!pWindow
|| pWindow
->IsDisposed())
121 std::unique_ptr
<vcl::PaintBufferGuard
> pGuard
;
122 const bool bDoubleBuffering
= pWindow
->SupportsDoubleBuffering();
123 if (bDoubleBuffering
)
124 pGuard
.reset(new vcl::PaintBufferGuard(pWindow
->ImplGetWindowImpl()->mpFrameData
, pWindow
));
126 vcl::RenderContext
* pRenderContext
= bDoubleBuffering
? pGuard
->GetRenderContext() : pWindow
;
128 tools::Rectangle aPaintRect
= ImplCursorInvert(pRenderContext
, pData
);
129 if (bDoubleBuffering
)
130 pGuard
->SetPaintRect(pRenderContext
->PixelToLogic(aPaintRect
));
133 bool vcl::Cursor::ImplPrepForDraw(const OutputDevice
* pDevice
, ImplCursorData
& rData
)
135 if (pDevice
&& !rData
.mbCurVisible
)
137 rData
.maPixPos
= pDevice
->LogicToPixel( maPos
);
138 rData
.maPixSize
= pDevice
->LogicToPixel( maSize
);
139 rData
.mnOrientation
= mnOrientation
;
140 rData
.mnDirection
= mnDirection
;
142 // correct the position with the offset
143 rData
.maPixRotOff
= rData
.maPixPos
;
145 // use width (as set in Settings) if size is 0,
146 if (!rData
.maPixSize
.Width())
147 rData
.maPixSize
.setWidth(pDevice
->GetSettings().GetStyleSettings().GetCursorSize());
153 void vcl::Cursor::ImplDraw()
155 if (mpData
&& mpData
->mpWindow
)
157 // calculate output area
158 if (ImplPrepForDraw(mpData
->mpWindow
, *mpData
))
161 ImplCursorInvert(mpData
->mpWindow
, mpData
.get());
162 mpData
->mbCurVisible
= true;
167 void vcl::Cursor::DrawToDevice(OutputDevice
& rRenderContext
)
169 ImplCursorData aData
;
171 aData
.mbCurVisible
= false;
172 // calculate output area
173 if (ImplPrepForDraw(&rRenderContext
, aData
))
176 ImplCursorInvert(&rRenderContext
, &aData
);
180 void vcl::Cursor::ImplRestore()
182 assert( mpData
&& mpData
->mbCurVisible
);
184 ImplCursorInvert(mpData
->mpWindow
, mpData
.get());
185 mpData
->mbCurVisible
= false;
188 void vcl::Cursor::ImplDoShow( bool bDrawDirect
, bool bRestore
)
193 vcl::Window
* pWindow
;
198 // show the cursor, if there is an active window and the cursor
199 // has been selected in this window
200 pWindow
= Application::GetFocusWindow();
201 if (!pWindow
|| !pWindow
->mpWindowImpl
|| (pWindow
->mpWindowImpl
->mpCursor
!= this)
202 || pWindow
->mpWindowImpl
->mbInPaint
203 || !pWindow
->mpWindowImpl
->mpFrameData
->mbHasFocus
)
212 mpData
.reset( new ImplCursorData
);
213 mpData
->mbCurVisible
= false;
214 mpData
->maTimer
.SetInvokeHandler( LINK( this, Cursor
, ImplTimerHdl
) );
215 mpData
->maTimer
.SetDebugName( "vcl ImplCursorData maTimer" );
218 mpData
->mpWindow
= pWindow
;
219 mpData
->mnStyle
= mnStyle
;
220 if ( bDrawDirect
|| bRestore
)
223 if ( !mpWindow
&& (bDrawDirect
|| !mpData
->maTimer
.IsActive()) )
225 mpData
->maTimer
.SetTimeout( pWindow
->GetSettings().GetStyleSettings().GetCursorBlinkTime() );
226 if ( mpData
->maTimer
.GetTimeout() != STYLE_CURSOR_NOBLINKTIME
)
227 mpData
->maTimer
.Start();
228 else if ( !mpData
->mbCurVisible
)
230 LOKNotify( pWindow
, "cursor_invalidate" );
231 LOKNotify( pWindow
, "cursor_visible" );
235 void vcl::Cursor::LOKNotify( vcl::Window
* pWindow
, const OUString
& rAction
)
237 VclPtr
<vcl::Window
> pParent
= pWindow
->GetParentWithLOKNotifier();
241 assert(pWindow
&& "Cannot notify without a window");
242 assert(mpData
&& "Require ImplCursorData");
243 assert(comphelper::LibreOfficeKit::isActive());
245 if (comphelper::LibreOfficeKit::isDialogPainting())
248 const vcl::ILibreOfficeKitNotifier
* pNotifier
= pParent
->GetLOKNotifier();
249 std::vector
<vcl::LOKPayloadItem
> aItems
;
250 if (rAction
== "cursor_visible")
251 aItems
.emplace_back("visible", mpData
->mbCurVisible
? "true" : "false");
252 else if (rAction
== "cursor_invalidate")
254 const tools::Long nX
= pWindow
->GetOutOffXPixel() + pWindow
->LogicToPixel(GetPos()).X() - pParent
->GetOutOffXPixel();
255 const tools::Long nY
= pWindow
->GetOutOffYPixel() + pWindow
->LogicToPixel(GetPos()).Y() - pParent
->GetOutOffYPixel();
256 Size aSize
= pWindow
->LogicToPixel(GetSize());
258 aSize
.setWidth( pWindow
->GetSettings().GetStyleSettings().GetCursorSize() );
260 const tools::Rectangle
aRect(Point(nX
, nY
), aSize
);
261 aItems
.emplace_back("rectangle", aRect
.toString());
264 pNotifier
->notifyWindow(pParent
->GetLOKWindowId(), rAction
, aItems
);
267 bool vcl::Cursor::ImplDoHide( bool bSuspend
)
269 bool bWasCurVisible
= false;
270 if ( mpData
&& mpData
->mpWindow
)
272 bWasCurVisible
= mpData
->mbCurVisible
;
273 if ( mpData
->mbCurVisible
)
278 LOKNotify( mpData
->mpWindow
, "cursor_visible" );
279 mpData
->maTimer
.Stop();
280 mpData
->mpWindow
= nullptr;
283 return bWasCurVisible
;
286 void vcl::Cursor::ImplShow()
288 ImplDoShow( true/*bDrawDirect*/, false );
291 void vcl::Cursor::ImplHide()
296 void vcl::Cursor::ImplResume( bool bRestore
)
298 ImplDoShow( false, bRestore
);
301 bool vcl::Cursor::ImplSuspend()
303 return ImplDoHide( true );
306 void vcl::Cursor::ImplNew()
308 if ( !(mbVisible
&& mpData
&& mpData
->mpWindow
) )
311 if ( mpData
->mbCurVisible
)
317 LOKNotify( mpData
->mpWindow
, "cursor_invalidate" );
318 if ( mpData
->maTimer
.GetTimeout() != STYLE_CURSOR_NOBLINKTIME
)
319 mpData
->maTimer
.Start();
323 IMPL_LINK_NOARG(vcl::Cursor
, ImplTimerHdl
, Timer
*, void)
325 if ( mpData
->mbCurVisible
)
331 vcl::Cursor::Cursor()
335 mnOrientation
= Degree10(0);
336 mnDirection
= CursorDirection::NONE
;
341 vcl::Cursor::Cursor( const Cursor
& rCursor
) :
342 maSize( rCursor
.maSize
),
343 maPos( rCursor
.maPos
)
347 mnOrientation
= rCursor
.mnOrientation
;
348 mnDirection
= rCursor
.mnDirection
;
350 mbVisible
= rCursor
.mbVisible
;
353 vcl::Cursor::~Cursor()
355 if (mpData
&& mpData
->mbCurVisible
)
359 void vcl::Cursor::SetStyle( sal_uInt16 nStyle
)
361 if ( mnStyle
!= nStyle
)
368 void vcl::Cursor::Show()
377 void vcl::Cursor::Hide()
386 void vcl::Cursor::SetWindow( vcl::Window
* pWindow
)
388 if ( mpWindow
.get() != pWindow
)
395 void vcl::Cursor::SetPos( const Point
& rPoint
)
397 if ( maPos
!= rPoint
)
404 void vcl::Cursor::SetSize( const Size
& rSize
)
406 if ( maSize
!= rSize
)
413 void vcl::Cursor::SetWidth( tools::Long nNewWidth
)
415 if ( maSize
.Width() != nNewWidth
)
417 maSize
.setWidth( nNewWidth
);
422 void vcl::Cursor::SetOrientation( Degree10 nNewOrientation
)
424 if ( mnOrientation
!= nNewOrientation
)
426 mnOrientation
= nNewOrientation
;
431 void vcl::Cursor::SetDirection( CursorDirection nNewDirection
)
433 if ( mnDirection
!= nNewDirection
)
435 mnDirection
= nNewDirection
;
440 vcl::Cursor
& vcl::Cursor::operator=( const vcl::Cursor
& rCursor
)
442 maPos
= rCursor
.maPos
;
443 maSize
= rCursor
.maSize
;
444 mnOrientation
= rCursor
.mnOrientation
;
445 mnDirection
= rCursor
.mnDirection
;
446 mbVisible
= rCursor
.mbVisible
;
452 bool vcl::Cursor::operator==( const vcl::Cursor
& rCursor
) const
455 ((maPos
== rCursor
.maPos
) &&
456 (maSize
== rCursor
.maSize
) &&
457 (mnOrientation
== rCursor
.mnOrientation
) &&
458 (mnDirection
== rCursor
.mnDirection
) &&
459 (mbVisible
== rCursor
.mbVisible
))
463 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */