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 short 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
;
49 bool bMapMode
= pRenderContext
->IsMapModeEnabled();
50 pRenderContext
->EnableMapMode( false );
51 InvertFlags nInvertStyle
;
52 if ( pData
->mnStyle
& CURSOR_SHADOW
)
53 nInvertStyle
= InvertFlags::N50
;
55 nInvertStyle
= InvertFlags::NONE
;
57 tools::Rectangle
aRect( pData
->maPixPos
, pData
->maPixSize
);
58 if ( pData
->mnDirection
!= CursorDirection::NONE
|| pData
->mnOrientation
)
60 tools::Polygon
aPoly( aRect
);
61 if( aPoly
.GetSize() == 5 )
63 aPoly
[1].AdjustX(1 ); // include the right border
66 // apply direction flag after slant to use the correct shape
67 if ( pData
->mnDirection
!= CursorDirection::NONE
)
70 int delta
= 3*aRect
.getWidth()+1;
71 if( pData
->mnDirection
== CursorDirection::LTR
)
74 pAry
[0] = aPoly
.GetPoint( 0 );
75 pAry
[1] = aPoly
.GetPoint( 1 );
77 pAry
[2].AdjustX(delta
);
79 pAry
[3].AdjustY(delta
);
80 pAry
[4] = aPoly
.GetPoint( 2 );
81 pAry
[5] = aPoly
.GetPoint( 3 );
82 pAry
[6] = aPoly
.GetPoint( 4 );
84 else if( pData
->mnDirection
== CursorDirection::RTL
)
87 pAry
[0] = aPoly
.GetPoint( 0 );
88 pAry
[1] = aPoly
.GetPoint( 1 );
89 pAry
[2] = aPoly
.GetPoint( 2 );
90 pAry
[3] = aPoly
.GetPoint( 3 );
92 pAry
[4].AdjustY(delta
);
94 pAry
[5].AdjustX( -delta
);
95 pAry
[6] = aPoly
.GetPoint( 4 );
97 aPoly
= tools::Polygon( 7, pAry
);
100 if ( pData
->mnOrientation
)
101 aPoly
.Rotate( pData
->maPixRotOff
, pData
->mnOrientation
);
102 pRenderContext
->Invert( aPoly
, nInvertStyle
);
103 aPaintRect
= aPoly
.GetBoundRect();
108 pRenderContext
->Invert( aRect
, nInvertStyle
);
111 pRenderContext
->EnableMapMode( bMapMode
);
115 static void ImplCursorInvert(vcl::Window
* pWindow
, ImplCursorData
const * pData
)
117 std::unique_ptr
<vcl::PaintBufferGuard
> pGuard
;
118 const bool bDoubleBuffering
= pWindow
->SupportsDoubleBuffering();
119 if (bDoubleBuffering
)
120 pGuard
.reset(new vcl::PaintBufferGuard(pWindow
->ImplGetWindowImpl()->mpFrameData
, pWindow
));
122 vcl::RenderContext
* pRenderContext
= bDoubleBuffering
? pGuard
->GetRenderContext() : pWindow
;
124 tools::Rectangle aPaintRect
= ImplCursorInvert(pRenderContext
, pData
);
125 if (bDoubleBuffering
)
126 pGuard
->SetPaintRect(pRenderContext
->PixelToLogic(aPaintRect
));
129 bool vcl::Cursor::ImplPrepForDraw(const OutputDevice
* pDevice
, ImplCursorData
& rData
)
131 if (pDevice
&& !rData
.mbCurVisible
)
133 rData
.maPixPos
= pDevice
->LogicToPixel( maPos
);
134 rData
.maPixSize
= pDevice
->LogicToPixel( maSize
);
135 rData
.mnOrientation
= mnOrientation
;
136 rData
.mnDirection
= mnDirection
;
138 // correct the position with the offset
139 rData
.maPixRotOff
= rData
.maPixPos
;
141 // use width (as set in Settings) if size is 0,
142 if (!rData
.maPixSize
.Width())
143 rData
.maPixSize
.setWidth(pDevice
->GetSettings().GetStyleSettings().GetCursorSize());
149 void vcl::Cursor::ImplDraw()
151 if (mpData
&& mpData
->mpWindow
)
153 // calculate output area
154 if (ImplPrepForDraw(mpData
->mpWindow
, *mpData
))
157 ImplCursorInvert(mpData
->mpWindow
, mpData
.get());
158 mpData
->mbCurVisible
= true;
163 void vcl::Cursor::DrawToDevice(OutputDevice
& rRenderContext
)
165 ImplCursorData aData
;
167 aData
.mbCurVisible
= false;
168 // calculate output area
169 if (ImplPrepForDraw(&rRenderContext
, aData
))
172 ImplCursorInvert(&rRenderContext
, &aData
);
176 void vcl::Cursor::ImplRestore()
178 assert( mpData
&& mpData
->mbCurVisible
);
180 ImplCursorInvert(mpData
->mpWindow
, mpData
.get());
181 mpData
->mbCurVisible
= false;
184 void vcl::Cursor::ImplDoShow( bool bDrawDirect
, bool bRestore
)
188 vcl::Window
* pWindow
;
193 // show the cursor, if there is an active window and the cursor
194 // has been selected in this window
195 pWindow
= Application::GetFocusWindow();
196 if ( !pWindow
|| (pWindow
->mpWindowImpl
->mpCursor
!= this) || pWindow
->mpWindowImpl
->mbInPaint
197 || !pWindow
->mpWindowImpl
->mpFrameData
->mbHasFocus
)
205 mpData
.reset( new ImplCursorData
);
206 mpData
->mbCurVisible
= false;
207 mpData
->maTimer
.SetInvokeHandler( LINK( this, Cursor
, ImplTimerHdl
) );
208 mpData
->maTimer
.SetDebugName( "vcl ImplCursorData maTimer" );
211 mpData
->mpWindow
= pWindow
;
212 mpData
->mnStyle
= mnStyle
;
213 if ( bDrawDirect
|| bRestore
)
216 if ( !mpWindow
&& ! ( ! bDrawDirect
&& mpData
->maTimer
.IsActive()) )
218 mpData
->maTimer
.SetTimeout( pWindow
->GetSettings().GetStyleSettings().GetCursorBlinkTime() );
219 if ( mpData
->maTimer
.GetTimeout() != STYLE_CURSOR_NOBLINKTIME
)
220 mpData
->maTimer
.Start();
221 else if ( !mpData
->mbCurVisible
)
223 LOKNotify( pWindow
, "cursor_invalidate" );
224 LOKNotify( pWindow
, "cursor_visible" );
230 void vcl::Cursor::LOKNotify( vcl::Window
* pWindow
, const OUString
& rAction
)
232 if (VclPtr
<vcl::Window
> pParent
= pWindow
->GetParentWithLOKNotifier())
234 assert(pWindow
&& "Cannot notify without a window");
235 assert(mpData
&& "Require ImplCursorData");
236 assert(comphelper::LibreOfficeKit::isActive());
238 if (comphelper::LibreOfficeKit::isDialogPainting())
241 const vcl::ILibreOfficeKitNotifier
* pNotifier
= pParent
->GetLOKNotifier();
242 std::vector
<vcl::LOKPayloadItem
> aItems
;
243 if (rAction
== "cursor_visible")
244 aItems
.emplace_back("visible", mpData
->mbCurVisible
? "true" : "false");
245 else if (rAction
== "cursor_invalidate")
247 const long nX
= pWindow
->GetOutOffXPixel() + pWindow
->LogicToPixel(GetPos()).X();
248 const long nY
= pWindow
->GetOutOffYPixel() + pWindow
->LogicToPixel(GetPos()).Y();
249 Size aSize
= pWindow
->LogicToPixel(GetSize());
251 aSize
.setWidth( pWindow
->GetSettings().GetStyleSettings().GetCursorSize() );
253 const tools::Rectangle
aRect(Point(nX
, nY
), aSize
);
254 aItems
.emplace_back("rectangle", aRect
.toString());
257 pNotifier
->notifyWindow(pParent
->GetLOKWindowId(), rAction
, aItems
);
261 bool vcl::Cursor::ImplDoHide( bool bSuspend
)
263 bool bWasCurVisible
= false;
264 if ( mpData
&& mpData
->mpWindow
)
266 bWasCurVisible
= mpData
->mbCurVisible
;
267 if ( mpData
->mbCurVisible
)
272 LOKNotify( mpData
->mpWindow
, "cursor_visible" );
273 mpData
->maTimer
.Stop();
274 mpData
->mpWindow
= nullptr;
277 return bWasCurVisible
;
280 void vcl::Cursor::ImplShow()
282 ImplDoShow( true/*bDrawDirect*/, false );
285 void vcl::Cursor::ImplHide()
290 void vcl::Cursor::ImplResume( bool bRestore
)
292 ImplDoShow( false, bRestore
);
295 bool vcl::Cursor::ImplSuspend()
297 return ImplDoHide( true );
300 void vcl::Cursor::ImplNew()
302 if ( mbVisible
&& mpData
&& mpData
->mpWindow
)
304 if ( mpData
->mbCurVisible
)
310 LOKNotify( mpData
->mpWindow
, "cursor_invalidate" );
311 if ( mpData
->maTimer
.GetTimeout() != STYLE_CURSOR_NOBLINKTIME
)
312 mpData
->maTimer
.Start();
317 IMPL_LINK_NOARG(vcl::Cursor
, ImplTimerHdl
, Timer
*, void)
319 if ( mpData
->mbCurVisible
)
325 vcl::Cursor::Cursor()
330 mnDirection
= CursorDirection::NONE
;
335 vcl::Cursor::Cursor( const Cursor
& rCursor
) :
336 maSize( rCursor
.maSize
),
337 maPos( rCursor
.maPos
)
341 mnOrientation
= rCursor
.mnOrientation
;
342 mnDirection
= rCursor
.mnDirection
;
344 mbVisible
= rCursor
.mbVisible
;
347 vcl::Cursor::~Cursor()
349 if (mpData
&& mpData
->mbCurVisible
)
353 void vcl::Cursor::SetStyle( sal_uInt16 nStyle
)
355 if ( mnStyle
!= nStyle
)
362 void vcl::Cursor::Show()
371 void vcl::Cursor::Hide()
380 void vcl::Cursor::SetWindow( vcl::Window
* pWindow
)
382 if ( mpWindow
.get() != pWindow
)
389 void vcl::Cursor::SetPos( const Point
& rPoint
)
391 if ( maPos
!= rPoint
)
398 void vcl::Cursor::SetSize( const Size
& rSize
)
400 if ( maSize
!= rSize
)
407 void vcl::Cursor::SetWidth( long nNewWidth
)
409 if ( maSize
.Width() != nNewWidth
)
411 maSize
.setWidth( nNewWidth
);
416 void vcl::Cursor::SetOrientation( short nNewOrientation
)
418 if ( mnOrientation
!= nNewOrientation
)
420 mnOrientation
= nNewOrientation
;
425 void vcl::Cursor::SetDirection( CursorDirection nNewDirection
)
427 if ( mnDirection
!= nNewDirection
)
429 mnDirection
= nNewDirection
;
434 vcl::Cursor
& vcl::Cursor::operator=( const vcl::Cursor
& rCursor
)
436 maPos
= rCursor
.maPos
;
437 maSize
= rCursor
.maSize
;
438 mnOrientation
= rCursor
.mnOrientation
;
439 mnDirection
= rCursor
.mnDirection
;
440 mbVisible
= rCursor
.mbVisible
;
446 bool vcl::Cursor::operator==( const vcl::Cursor
& rCursor
) const
449 ((maPos
== rCursor
.maPos
) &&
450 (maSize
== rCursor
.maSize
) &&
451 (mnOrientation
== rCursor
.mnOrientation
) &&
452 (mnDirection
== rCursor
.mnDirection
) &&
453 (mbVisible
== rCursor
.mbVisible
))
457 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */