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