LibreOffice Module vcl (master)  1
cursor.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
21 
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>
28 
29 #include <window.h>
30 
31 #include <tools/poly.hxx>
32 
34 {
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
44 };
45 
47 {
48  tools::Rectangle aPaintRect;
49 
50  bool bMapMode = pRenderContext->IsMapModeEnabled();
51  pRenderContext->EnableMapMode( false );
52  InvertFlags nInvertStyle;
53  if ( pData->mnStyle & CURSOR_SHADOW )
54  nInvertStyle = InvertFlags::N50;
55  else
56  nInvertStyle = InvertFlags::NONE;
57 
58  tools::Rectangle aRect( pData->maPixPos, pData->maPixSize );
59  if ( pData->mnDirection != CursorDirection::NONE || pData->mnOrientation )
60  {
61  tools::Polygon aPoly( aRect );
62  if( aPoly.GetSize() == 5 )
63  {
64  aPoly[1].AdjustX(1 ); // include the right border
65  aPoly[2].AdjustX(1 );
66 
67  // apply direction flag after slant to use the correct shape
68  if ( pData->mnDirection != CursorDirection::NONE)
69  {
70  Point pAry[7];
71  int delta = 3*aRect.getWidth()+1;
72  if( pData->mnDirection == CursorDirection::LTR )
73  {
74  // left-to-right
75  pAry[0] = aPoly.GetPoint( 0 );
76  pAry[1] = aPoly.GetPoint( 1 );
77  pAry[2] = pAry[1];
78  pAry[2].AdjustX(delta );
79  pAry[3] = pAry[1];
80  pAry[3].AdjustY(delta );
81  pAry[4] = aPoly.GetPoint( 2 );
82  pAry[5] = aPoly.GetPoint( 3 );
83  pAry[6] = aPoly.GetPoint( 4 );
84  }
85  else if( pData->mnDirection == CursorDirection::RTL )
86  {
87  // right-to-left
88  pAry[0] = aPoly.GetPoint( 0 );
89  pAry[1] = aPoly.GetPoint( 1 );
90  pAry[2] = aPoly.GetPoint( 2 );
91  pAry[3] = aPoly.GetPoint( 3 );
92  pAry[4] = pAry[0];
93  pAry[4].AdjustY(delta );
94  pAry[5] = pAry[0];
95  pAry[5].AdjustX( -delta );
96  pAry[6] = aPoly.GetPoint( 4 );
97  }
98  aPoly = tools::Polygon( 7, pAry);
99  }
100 
101  if ( pData->mnOrientation )
102  aPoly.Rotate( pData->maPixRotOff, pData->mnOrientation );
103  pRenderContext->Invert( aPoly, nInvertStyle );
104  aPaintRect = aPoly.GetBoundRect();
105  }
106  }
107  else
108  {
109  pRenderContext->Invert( aRect, nInvertStyle );
110  aPaintRect = aRect;
111  }
112  pRenderContext->EnableMapMode( bMapMode );
113  return aPaintRect;
114 }
115 
116 static void ImplCursorInvert(vcl::Window* pWindow, ImplCursorData const * pData)
117 {
118  if (!pWindow || pWindow->isDisposed())
119  return;
120 
122  const bool bDoubleBuffering = pWindow->SupportsDoubleBuffering();
123  if (bDoubleBuffering)
124  pGuard.reset(new vcl::PaintBufferGuard(pWindow->ImplGetWindowImpl()->mpFrameData, pWindow));
125 
126  vcl::RenderContext* pRenderContext = bDoubleBuffering ? pGuard->GetRenderContext() : pWindow->GetOutDev();
127 
128  tools::Rectangle aPaintRect = ImplCursorInvert(pRenderContext, pData);
129  if (bDoubleBuffering)
130  pGuard->SetPaintRect(pRenderContext->PixelToLogic(aPaintRect));
131 }
132 
134 {
135  if (pDevice && !rData.mbCurVisible)
136  {
137  rData.maPixPos = pDevice->LogicToPixel( maPos );
138  rData.maPixSize = pDevice->LogicToPixel( maSize );
140  rData.mnDirection = mnDirection;
141 
142  // correct the position with the offset
143  rData.maPixRotOff = rData.maPixPos;
144 
145  // use width (as set in Settings) if size is 0,
146  if (!rData.maPixSize.Width())
148  return true;
149  }
150  return false;
151 }
152 
154 {
155  if (mpData && mpData->mpWindow)
156  {
157  // calculate output area
158  if (ImplPrepForDraw(mpData->mpWindow->GetOutDev(), *mpData))
159  {
160  // display
161  ImplCursorInvert(mpData->mpWindow, mpData.get());
162  mpData->mbCurVisible = true;
163  }
164  }
165 }
166 
168 {
170  aData.mnStyle = 0;
171  aData.mbCurVisible = false;
172  // calculate output area
173  if (ImplPrepForDraw(&rRenderContext, aData))
174  {
175  // display
176  ImplCursorInvert(&rRenderContext, &aData);
177  }
178 }
179 
181 {
182  assert( mpData && mpData->mbCurVisible );
183 
184  ImplCursorInvert(mpData->mpWindow, mpData.get());
185  mpData->mbCurVisible = false;
186 }
187 
188 void vcl::Cursor::ImplDoShow( bool bDrawDirect, bool bRestore )
189 {
190  if ( !mbVisible )
191  return;
192 
193  vcl::Window* pWindow;
194  if ( mpWindow )
195  pWindow = mpWindow;
196  else
197  {
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)
204  pWindow = nullptr;
205  }
206 
207  if ( !pWindow )
208  return;
209 
210  if ( !mpData )
211  {
212  mpData.reset( new ImplCursorData );
213  mpData->mbCurVisible = false;
214  mpData->maTimer.SetInvokeHandler( LINK( this, Cursor, ImplTimerHdl ) );
215  }
216 
217  mpData->mpWindow = pWindow;
218  mpData->mnStyle = mnStyle;
219  if ( bDrawDirect || bRestore )
220  ImplDraw();
221 
222  if ( !mpWindow && (bDrawDirect || !mpData->maTimer.IsActive()) )
223  {
224  mpData->maTimer.SetTimeout( pWindow->GetSettings().GetStyleSettings().GetCursorBlinkTime() );
225  if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME )
226  mpData->maTimer.Start();
227  else if ( !mpData->mbCurVisible )
228  ImplDraw();
229  LOKNotify( pWindow, "cursor_invalidate" );
230  LOKNotify( pWindow, "cursor_visible" );
231  }
232 }
233 
234 void vcl::Cursor::LOKNotify( vcl::Window* pWindow, const OUString& rAction )
235 {
236  VclPtr<vcl::Window> pParent = pWindow->GetParentWithLOKNotifier();
237  if (!pParent)
238  return;
239 
240  assert(pWindow && "Cannot notify without a window");
241  assert(mpData && "Require ImplCursorData");
243 
245  return;
246 
247  const vcl::ILibreOfficeKitNotifier* pNotifier = pParent->GetLOKNotifier();
248  std::vector<vcl::LOKPayloadItem> aItems;
249  if (rAction == "cursor_visible")
250  aItems.emplace_back("visible", mpData->mbCurVisible ? "true" : "false");
251  else if (rAction == "cursor_invalidate")
252  {
253  const tools::Long nX = pWindow->GetOutOffXPixel() + pWindow->LogicToPixel(GetPos()).X() - pParent->GetOutOffXPixel();
254  const tools::Long nY = pWindow->GetOutOffYPixel() + pWindow->LogicToPixel(GetPos()).Y() - pParent->GetOutOffYPixel();
255  Size aSize = pWindow->LogicToPixel(GetSize());
256  if (!aSize.Width())
257  aSize.setWidth( pWindow->GetSettings().GetStyleSettings().GetCursorSize() );
258 
259  const tools::Rectangle aRect(Point(nX, nY), aSize);
260  aItems.emplace_back("rectangle", aRect.toString());
261  }
262 
263  pNotifier->notifyWindow(pParent->GetLOKWindowId(), rAction, aItems);
264 }
265 
266 bool vcl::Cursor::ImplDoHide( bool bSuspend )
267 {
268  bool bWasCurVisible = false;
269  if ( mpData && mpData->mpWindow )
270  {
271  bWasCurVisible = mpData->mbCurVisible;
272  if ( mpData->mbCurVisible )
273  ImplRestore();
274 
275  if ( !bSuspend )
276  {
277  LOKNotify( mpData->mpWindow, "cursor_visible" );
278  mpData->maTimer.Stop();
279  mpData->mpWindow = nullptr;
280  }
281  }
282  return bWasCurVisible;
283 }
284 
286 {
287  ImplDoShow( true/*bDrawDirect*/, false );
288 }
289 
291 {
292  ImplDoHide( false );
293 }
294 
295 void vcl::Cursor::ImplResume( bool bRestore )
296 {
297  ImplDoShow( false, bRestore );
298 }
299 
301 {
302  return ImplDoHide( true );
303 }
304 
306 {
307  if ( !(mbVisible && mpData && mpData->mpWindow) )
308  return;
309 
310  if ( mpData->mbCurVisible )
311  ImplRestore();
312 
313  ImplDraw();
314  if ( !mpWindow )
315  {
316  LOKNotify( mpData->mpWindow, "cursor_invalidate" );
317  if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME )
318  mpData->maTimer.Start();
319  }
320 }
321 
322 IMPL_LINK_NOARG(vcl::Cursor, ImplTimerHdl, Timer *, void)
323 {
324  if ( mpData->mbCurVisible )
325  ImplRestore();
326  else
327  ImplDraw();
328 }
329 
331 {
332  mpData = nullptr;
333  mpWindow = nullptr;
334  mnOrientation = 0_deg10;
335  mnDirection = CursorDirection::NONE;
336  mnStyle = 0;
337  mbVisible = false;
338 }
339 
340 vcl::Cursor::Cursor( const Cursor& rCursor ) :
341  maSize( rCursor.maSize ),
342  maPos( rCursor.maPos )
343 {
344  mpData = nullptr;
345  mpWindow = nullptr;
346  mnOrientation = rCursor.mnOrientation;
347  mnDirection = rCursor.mnDirection;
348  mnStyle = 0;
349  mbVisible = rCursor.mbVisible;
350 }
351 
353 {
354  if (mpData && mpData->mbCurVisible)
355  ImplRestore();
356 }
357 
358 void vcl::Cursor::SetStyle( sal_uInt16 nStyle )
359 {
360  if ( mnStyle != nStyle )
361  {
362  mnStyle = nStyle;
363  ImplNew();
364  }
365 }
366 
368 {
369  if ( !mbVisible )
370  {
371  mbVisible = true;
372  ImplShow();
373  }
374 }
375 
377 {
378  if ( mbVisible )
379  {
380  mbVisible = false;
381  ImplHide();
382  }
383 }
384 
386 {
387  if ( mpWindow.get() != pWindow )
388  {
389  mpWindow = pWindow;
390  ImplNew();
391  }
392 }
393 
394 void vcl::Cursor::SetPos( const Point& rPoint )
395 {
396  if ( maPos != rPoint )
397  {
398  maPos = rPoint;
399  ImplNew();
400  }
401 }
402 
403 void vcl::Cursor::SetSize( const Size& rSize )
404 {
405  if ( maSize != rSize )
406  {
407  maSize = rSize;
408  ImplNew();
409  }
410 }
411 
413 {
414  if ( maSize.Width() != nNewWidth )
415  {
416  maSize.setWidth( nNewWidth );
417  ImplNew();
418  }
419 }
420 
421 void vcl::Cursor::SetOrientation( Degree10 nNewOrientation )
422 {
423  if ( mnOrientation != nNewOrientation )
424  {
425  mnOrientation = nNewOrientation;
426  ImplNew();
427  }
428 }
429 
431 {
432  if ( mnDirection != nNewDirection )
433  {
434  mnDirection = nNewDirection;
435  ImplNew();
436  }
437 }
438 
440 {
441  maPos = rCursor.maPos;
442  maSize = rCursor.maSize;
443  mnOrientation = rCursor.mnOrientation;
444  mnDirection = rCursor.mnDirection;
445  mbVisible = rCursor.mbVisible;
446  ImplNew();
447 
448  return *this;
449 }
450 
451 bool vcl::Cursor::operator==( const vcl::Cursor& rCursor ) const
452 {
453  return
454  ((maPos == rCursor.maPos) &&
455  (maSize == rCursor.maSize) &&
456  (mnOrientation == rCursor.mnOrientation) &&
457  (mnDirection == rCursor.mnDirection) &&
458  (mbVisible == rCursor.mbVisible))
459  ;
460 }
461 
462 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
tools::Long GetOutOffYPixel() const
Definition: window3.cxx:124
vcl::LOKWindowId GetLOKWindowId() const
Definition: window.cxx:3253
void DrawToDevice(OutputDevice &rRenderContext)
Definition: cursor.cxx:167
CursorDirection mnDirection
Definition: cursor.cxx:40
std::unique_ptr< ImplCursorData > mpData
Definition: cursor.hxx:49
void SetOrientation(Degree10 nOrientation=0_deg10)
Definition: cursor.cxx:421
sal_uInt16 mnStyle
Definition: cursor.hxx:54
bool mbCurVisible
Definition: cursor.cxx:42
void SetPos(const Point &rNewPos)
Definition: cursor.cxx:394
void setWidth(tools::Long nWidth)
SAL_DLLPRIVATE bool ImplSuspend()
Definition: cursor.cxx:300
tools::Long getWidth() const
Degree10 mnOrientation
Definition: cursor.hxx:53
long Long
Point maPos
Definition: cursor.hxx:52
const StyleSettings & GetStyleSettings() const
bool IsMapModeEnabled() const
Definition: outdev.hxx:1561
SAL_DLLPRIVATE WindowImpl * ImplGetWindowImpl() const
Definition: window.hxx:527
AutoTimer maTimer vcl ImplCursorData maTimer
Definition: cursor.cxx:35
SAL_DLLPRIVATE void ImplNew()
Definition: cursor.cxx:305
void EnableMapMode(bool bEnable=true)
Definition: map.cxx:586
sal_uInt16 mnStyle
Definition: cursor.cxx:41
void LOKNotify(vcl::Window *pWindow, const OUString &rAction)
Definition: cursor.cxx:234
constexpr tools::Long Width() const
CursorDirection mnDirection
Definition: cursor.hxx:56
Point maPixRotOff
Definition: cursor.cxx:37
void Invert(const tools::Rectangle &rRect, InvertFlags nFlags=InvertFlags::NONE)
Definition: rect.cxx:149
Point maPixPos
Definition: cursor.cxx:36
VclPtr< vcl::Window > GetParentWithLOKNotifier()
Find the nearest parent with LOK Notifier; can be itself if this Window has LOK notifier set...
Definition: window.cxx:3258
#define CURSOR_SHADOW
Definition: cursor.hxx:36
void SetStyle(sal_uInt16 nStyle)
Definition: cursor.cxx:358
#define STYLE_CURSOR_NOBLINKTIME
Definition: settings.hxx:206
void Hide()
Definition: cursor.cxx:376
Degree10 mnOrientation
Definition: cursor.cxx:39
void Rotate(const Point &rCenter, double fSin, double fCos)
constexpr OUStringLiteral aData
SAL_DLLPRIVATE void ImplResume(bool bRestore=false)
Definition: cursor.cxx:295
SAL_DLLPRIVATE void ImplDraw()
Definition: cursor.cxx:153
An auto-timer is a multi-shot timer re-emitting itself at interval until destroyed or stopped...
Definition: timer.hxx:66
VclPtr< vcl::Window > mpWindow
Point LogicToPixel(const Point &rLogicPt) const
Definition: window3.cxx:131
bool ImplDoHide(bool bStop)
Definition: cursor.cxx:266
SAL_DLLPRIVATE void ImplHide()
Definition: cursor.cxx:290
bool operator==(const Cursor &rCursor) const
Definition: cursor.cxx:451
Size maSize
Definition: cursor.hxx:51
CursorDirection
Definition: cursor.hxx:38
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:175
const AllSettings & GetSettings() const
Definition: window3.cxx:129
void SetWindow(vcl::Window *pWindow)
Definition: cursor.cxx:385
bool mbVisible
Definition: cursor.hxx:55
std::unique_ptr< WindowImpl > mpWindowImpl
Definition: window.hxx:483
SAL_DLLPRIVATE void ImplShow()
Definition: cursor.cxx:285
void Show()
Definition: cursor.cxx:367
sal_uInt16 GetSize() const
void SetSize(const Size &rNewSize)
Definition: cursor.cxx:403
const AllSettings & GetSettings() const
Definition: outdev.hxx:294
Sets up the buffer to have settings matching the window, and restores the original state in the dtor...
Definition: window.h:396
VclPtr< vcl::Window > mpWindow
Definition: cursor.cxx:43
VclPtr< vcl::Window > mpWindow
Definition: cursor.hxx:50
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1109
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:878
const Point & GetPoint(sal_uInt16 nPos) const
void ImplRestore()
Definition: cursor.cxx:180
static vcl::Window * GetFocusWindow()
Get the currently focused window.
Definition: svapp.cxx:1064
std::unique_ptr< PaintBufferGuard, o3tl::default_delete< PaintBufferGuard > > PaintBufferGuardPtr
Definition: window.h:414
bool mbVisible
sal_uInt64 GetCursorBlinkTime() const
sal_Int32 GetCursorSize() const
::OutputDevice const * GetOutDev() const
Definition: window.cxx:568
Size maPixSize
Definition: cursor.cxx:38
Cursor & operator=(const Cursor &rCursor)
Definition: cursor.cxx:439
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
const vcl::ILibreOfficeKitNotifier * GetLOKNotifier() const
Definition: window.cxx:3248
bool ImplPrepForDraw(const OutputDevice *pDevice, ImplCursorData &rData)
Definition: cursor.cxx:133
Definition: timer.hxx:26
tools::Rectangle GetBoundRect() const
static tools::Rectangle ImplCursorInvert(vcl::RenderContext *pRenderContext, ImplCursorData const *pData)
Definition: cursor.cxx:46
void ImplDoShow(bool bDrawDirect, bool bRestore)
Definition: cursor.cxx:188
InvertFlags
Definition: InvertFlags.hxx:24
tools::Long GetOutOffXPixel() const
Definition: window3.cxx:123
rtl::OString toString() const
IMPL_LINK_NOARG(QuickSelectionEngine_Data, SearchStringTimeout, Timer *, void)
ImplFrameData * mpFrameData
Definition: window.h:222
void SetDirection(CursorDirection nDirection=CursorDirection::NONE)
Definition: cursor.cxx:430
bool SupportsDoubleBuffering() const
Can the widget derived from this Window do the double-buffering via RenderContext properly...
Definition: window.cxx:3853
bool isDisposed() const
void SetWidth(tools::Long nNewWidth)
Definition: cursor.cxx:412
::basegfx::B2IVector maSize