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 long mnPixSlant
; // Pixel-Slant
40 short mnOrientation
; // Pixel-Orientation
41 CursorDirection mnDirection
; // indicates writing direction
42 sal_uInt16 mnStyle
; // Cursor-Style
43 bool mbCurVisible
; // Ist Cursor aktuell sichtbar
44 VclPtr
<vcl::Window
> mpWindow
; // Zugeordnetes Windows
47 static void ImplCursorInvert( ImplCursorData
* pData
)
49 vcl::Window
* pWindow
= pData
->mpWindow
;
50 std::unique_ptr
<PaintBufferGuard
> pGuard
;
51 const bool bDoubleBuffering
= pWindow
->SupportsDoubleBuffering();
53 pGuard
.reset(new PaintBufferGuard(pWindow
->ImplGetWindowImpl()->mpFrameData
, pWindow
));
54 vcl::RenderContext
* pRenderContext
= bDoubleBuffering
? pGuard
->GetRenderContext() : pWindow
;
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 Rectangle
aRect( pData
->maPixPos
, pData
->maPixSize
);
65 if ( pData
->mnDirection
!= CursorDirection::NONE
|| pData
->mnOrientation
|| pData
->mnPixSlant
)
67 tools::Polygon
aPoly( aRect
);
68 if( aPoly
.GetSize() == 5 )
70 aPoly
[1].X() += 1; // include the right border
72 if ( pData
->mnPixSlant
)
74 Point aPoint
= aPoly
.GetPoint( 0 );
75 aPoint
.X() += pData
->mnPixSlant
;
76 aPoly
.SetPoint( aPoint
, 0 );
77 aPoly
.SetPoint( aPoint
, 4 );
78 aPoint
= aPoly
.GetPoint( 1 );
79 aPoint
.X() += pData
->mnPixSlant
;
80 aPoly
.SetPoint( aPoint
, 1 );
83 // apply direction flag after slant to use the correct shape
84 if ( pData
->mnDirection
!= CursorDirection::NONE
)
87 int delta
= 3*aRect
.getWidth()+1;
88 if( pData
->mnDirection
== CursorDirection::LTR
)
91 pAry
[0] = aPoly
.GetPoint( 0 );
92 pAry
[1] = aPoly
.GetPoint( 1 );
97 pAry
[4] = aPoly
.GetPoint( 2 );
98 pAry
[5] = aPoly
.GetPoint( 3 );
99 pAry
[6] = aPoly
.GetPoint( 4 );
101 else if( pData
->mnDirection
== CursorDirection::RTL
)
104 pAry
[0] = aPoly
.GetPoint( 0 );
105 pAry
[1] = aPoly
.GetPoint( 1 );
106 pAry
[2] = aPoly
.GetPoint( 2 );
107 pAry
[3] = aPoly
.GetPoint( 3 );
109 pAry
[4].Y() += delta
;
111 pAry
[5].X() -= delta
;
112 pAry
[6] = aPoly
.GetPoint( 4 );
114 aPoly
= tools::Polygon( 7, pAry
);
117 if ( pData
->mnOrientation
)
118 aPoly
.Rotate( pData
->maPixRotOff
, pData
->mnOrientation
);
119 pRenderContext
->Invert( aPoly
, nInvertStyle
);
120 if (bDoubleBuffering
)
121 aPaintRect
= aPoly
.GetBoundRect();
126 pRenderContext
->Invert( aRect
, nInvertStyle
);
127 if (bDoubleBuffering
)
130 pRenderContext
->EnableMapMode( bMapMode
);
131 if (bDoubleBuffering
)
132 pGuard
->SetPaintRect(pRenderContext
->PixelToLogic(aPaintRect
));
135 void vcl::Cursor::ImplDraw()
137 if ( mpData
&& mpData
->mpWindow
&& !mpData
->mbCurVisible
)
139 vcl::Window
* pWindow
= mpData
->mpWindow
;
140 mpData
->maPixPos
= pWindow
->LogicToPixel( maPos
);
141 mpData
->maPixSize
= pWindow
->LogicToPixel( maSize
);
142 mpData
->mnPixSlant
= pWindow
->LogicToPixel( Size( mnSlant
, 0 ) ).Width();
143 mpData
->mnOrientation
= mnOrientation
;
144 mpData
->mnDirection
= mnDirection
;
146 // correct the position with the offset
147 mpData
->maPixRotOff
= mpData
->maPixPos
;
149 // use width (as set in Settings) if size is 0,
150 if ( !mpData
->maPixSize
.Width() )
151 mpData
->maPixSize
.Width() = pWindow
->GetSettings().GetStyleSettings().GetCursorSize();
153 // calculate output area and display
154 ImplCursorInvert( mpData
);
155 mpData
->mbCurVisible
= true;
159 void vcl::Cursor::ImplRestore()
161 assert( mpData
&& mpData
->mbCurVisible
);
163 ImplCursorInvert( mpData
);
164 mpData
->mbCurVisible
= false;
167 void vcl::Cursor::ImplDoShow( bool bDrawDirect
, bool bRestore
)
171 vcl::Window
* pWindow
;
176 // show the cursor, if there is an active window and the cursor
177 // has been selected in this window
178 pWindow
= Application::GetFocusWindow();
179 if ( !pWindow
|| (pWindow
->mpWindowImpl
->mpCursor
!= this) || pWindow
->mpWindowImpl
->mbInPaint
180 || !pWindow
->mpWindowImpl
->mpFrameData
->mbHasFocus
)
188 mpData
= new ImplCursorData
;
189 mpData
->mbCurVisible
= false;
190 mpData
->maTimer
.SetTimeoutHdl( LINK( this, Cursor
, ImplTimerHdl
) );
191 mpData
->maTimer
.SetDebugName( "vcl ImplCursorData maTimer" );
194 mpData
->mpWindow
= pWindow
;
195 mpData
->mnStyle
= mnStyle
;
196 if ( bDrawDirect
|| bRestore
)
199 if ( !mpWindow
&& ! ( ! bDrawDirect
&& mpData
->maTimer
.IsActive()) )
201 mpData
->maTimer
.SetTimeout( pWindow
->GetSettings().GetStyleSettings().GetCursorBlinkTime() );
202 if ( mpData
->maTimer
.GetTimeout() != STYLE_CURSOR_NOBLINKTIME
)
203 mpData
->maTimer
.Start();
204 else if ( !mpData
->mbCurVisible
)
206 LOKNotify( pWindow
, "cursor_invalidate" );
207 LOKNotify( pWindow
, "cursor_visible" );
213 void vcl::Cursor::LOKNotify( vcl::Window
* pWindow
, const OUString
& rAction
)
215 if (VclPtr
<vcl::Window
> pParent
= pWindow
->GetParentWithLOKNotifier())
217 assert(pWindow
&& "Cannot notify without a window");
218 assert(mpData
&& "Require ImplCursorData");
219 assert(comphelper::LibreOfficeKit::isActive());
221 if (comphelper::LibreOfficeKit::isDialogPainting())
224 const vcl::ILibreOfficeKitNotifier
* pNotifier
= pParent
->GetLOKNotifier();
225 std::vector
<vcl::LOKPayloadItem
> aItems
;
226 if (rAction
== "cursor_visible")
227 aItems
.emplace_back("visible", mpData
->mbCurVisible
? "true" : "false");
228 else if (rAction
== "cursor_invalidate")
230 const long nX
= pWindow
->GetOutOffXPixel() + pWindow
->LogicToPixel(GetPos()).X();
231 const long nY
= pWindow
->GetOutOffYPixel() + pWindow
->LogicToPixel(GetPos()).Y();
232 Size aSize
= pWindow
->LogicToPixel(GetSize());
234 aSize
.Width() = pWindow
->GetSettings().GetStyleSettings().GetCursorSize();
236 const Rectangle
aRect(Point(nX
, nY
), aSize
);
237 aItems
.emplace_back("rectangle", aRect
.toString());
240 pNotifier
->notifyWindow(pParent
->GetLOKWindowId(), rAction
, aItems
);
244 bool vcl::Cursor::ImplDoHide( bool bSuspend
)
246 bool bWasCurVisible
= false;
247 if ( mpData
&& mpData
->mpWindow
)
249 bWasCurVisible
= mpData
->mbCurVisible
;
250 if ( mpData
->mbCurVisible
)
255 LOKNotify( mpData
->mpWindow
, "cursor_visible" );
256 mpData
->maTimer
.Stop();
257 mpData
->mpWindow
= nullptr;
260 return bWasCurVisible
;
263 void vcl::Cursor::ImplShow()
265 ImplDoShow( true/*bDrawDirect*/, false );
268 void vcl::Cursor::ImplHide()
273 void vcl::Cursor::ImplResume( bool bRestore
)
275 ImplDoShow( false, bRestore
);
278 bool vcl::Cursor::ImplSuspend()
280 return ImplDoHide( true );
283 void vcl::Cursor::ImplNew()
285 if ( mbVisible
&& mpData
&& mpData
->mpWindow
)
287 if ( mpData
->mbCurVisible
)
293 LOKNotify( mpData
->mpWindow
, "cursor_invalidate" );
294 if ( mpData
->maTimer
.GetTimeout() != STYLE_CURSOR_NOBLINKTIME
)
295 mpData
->maTimer
.Start();
300 IMPL_LINK_NOARG(vcl::Cursor
, ImplTimerHdl
, Timer
*, void)
302 if ( mpData
->mbCurVisible
)
308 vcl::Cursor::Cursor()
314 mnDirection
= CursorDirection::NONE
;
319 vcl::Cursor::Cursor( const Cursor
& rCursor
) :
320 maSize( rCursor
.maSize
),
321 maPos( rCursor
.maPos
)
325 mnSlant
= rCursor
.mnSlant
;
326 mnOrientation
= rCursor
.mnOrientation
;
327 mnDirection
= rCursor
.mnDirection
;
329 mbVisible
= rCursor
.mbVisible
;
332 vcl::Cursor::~Cursor()
336 if ( mpData
->mbCurVisible
)
343 void vcl::Cursor::SetStyle( sal_uInt16 nStyle
)
345 if ( mnStyle
!= nStyle
)
352 void vcl::Cursor::Show()
361 void vcl::Cursor::Hide()
370 void vcl::Cursor::SetWindow( vcl::Window
* pWindow
)
372 if ( mpWindow
.get() != pWindow
)
379 void vcl::Cursor::SetPos( const Point
& rPoint
)
381 if ( maPos
!= rPoint
)
388 void vcl::Cursor::SetSize( const Size
& rSize
)
390 if ( maSize
!= rSize
)
397 void vcl::Cursor::SetWidth( long nNewWidth
)
399 if ( maSize
.Width() != nNewWidth
)
401 maSize
.Width() = nNewWidth
;
406 void vcl::Cursor::SetOrientation( short nNewOrientation
)
408 if ( mnOrientation
!= nNewOrientation
)
410 mnOrientation
= nNewOrientation
;
415 void vcl::Cursor::SetDirection( CursorDirection nNewDirection
)
417 if ( mnDirection
!= nNewDirection
)
419 mnDirection
= nNewDirection
;
424 vcl::Cursor
& vcl::Cursor::operator=( const vcl::Cursor
& rCursor
)
426 maPos
= rCursor
.maPos
;
427 maSize
= rCursor
.maSize
;
428 mnSlant
= rCursor
.mnSlant
;
429 mnOrientation
= rCursor
.mnOrientation
;
430 mnDirection
= rCursor
.mnDirection
;
431 mbVisible
= rCursor
.mbVisible
;
437 bool vcl::Cursor::operator==( const vcl::Cursor
& rCursor
) const
440 ((maPos
== rCursor
.maPos
) &&
441 (maSize
== rCursor
.maSize
) &&
442 (mnSlant
== rCursor
.mnSlant
) &&
443 (mnOrientation
== rCursor
.mnOrientation
) &&
444 (mnDirection
== rCursor
.mnDirection
) &&
445 (mbVisible
== rCursor
.mbVisible
))
449 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */