KWin
Loading...
Searching...
No Matches
cursor.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "cursor.h"
11// kwin
12#include "compositor.h"
13#include "core/output.h"
14#include "cursorsource.h"
15#include "input.h"
16#include "keyboard_input.h"
17#include "main.h"
19#include "utils/common.h"
20#include "utils/xcbutils.h"
21// KDE
22#include <KConfig>
23#include <KConfigGroup>
24// Qt
25#include <QAbstractEventDispatcher>
26#include <QDBusConnection>
27#include <QScreen>
28#include <QTimer>
29
30#include <xcb/xcb_cursor.h>
31
32namespace KWin
33{
34Cursors *Cursors::s_self = nullptr;
36{
37 if (!s_self) {
38 s_self = new Cursors;
39 }
40 return s_self;
41}
42
44{
45 Q_ASSERT(!m_cursors.contains(cursor));
46 m_cursors += cursor;
47
48 connect(cursor, &Cursor::posChanged, this, [this, cursor](const QPointF &pos) {
49 setCurrentCursor(cursor);
50 Q_EMIT positionChanged(cursor, pos);
51 });
52}
53
55{
56 m_cursors.removeOne(cursor);
57 if (m_currentCursor == cursor) {
58 if (m_cursors.isEmpty()) {
59 m_currentCursor = nullptr;
60 } else {
61 setCurrentCursor(m_cursors.constFirst());
62 }
63 }
64 if (m_mouse == cursor) {
65 m_mouse = nullptr;
66 }
67}
68
70{
71 m_cursorHideCounter++;
72 if (m_cursorHideCounter == 1) {
73 Q_EMIT hiddenChanged();
74 }
75}
76
78{
79 m_cursorHideCounter--;
80 if (m_cursorHideCounter == 0) {
81 Q_EMIT hiddenChanged();
82 }
83}
84
86{
87 return m_cursorHideCounter > 0;
88}
89
90void Cursors::setCurrentCursor(Cursor *cursor)
91{
92 if (m_currentCursor == cursor) {
93 return;
94 }
95
96 Q_ASSERT(m_cursors.contains(cursor) || !cursor);
97
98 if (m_currentCursor) {
99 disconnect(m_currentCursor, &Cursor::cursorChanged, this, &Cursors::emitCurrentCursorChanged);
100 }
101 m_currentCursor = cursor;
102 connect(m_currentCursor, &Cursor::cursorChanged, this, &Cursors::emitCurrentCursorChanged);
103
104 Q_EMIT currentCursorChanged(m_currentCursor);
105}
106
107void Cursors::emitCurrentCursorChanged()
108{
109 Q_EMIT currentCursorChanged(m_currentCursor);
110}
111
113 : m_mousePollingCounter(0)
114 , m_cursorTrackingCounter(0)
115 , m_themeName(defaultThemeName())
116 , m_themeSize(defaultThemeSize())
117{
118 loadThemeSettings();
119 QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"),
120 QStringLiteral("notifyChange"), this, SLOT(slotKGlobalSettingsNotifyChange(int, int)));
121
122 if (kwinApp()->operationMode() != Application::OperationModeWaylandOnly) {
123 connect(kwinApp(), &Application::x11ConnectionChanged, this, [this]() {
124 m_cursors.clear();
125 });
126 }
127}
128
133
134void Cursor::loadThemeSettings()
135{
136 QString themeName = QString::fromUtf8(qgetenv("XCURSOR_THEME"));
137 bool ok = false;
138 // XCURSOR_SIZE might not be set (e.g. by startkde)
139 const uint themeSize = qEnvironmentVariableIntValue("XCURSOR_SIZE", &ok);
140 if (!themeName.isEmpty() && ok) {
141 updateTheme(themeName, themeSize);
142 return;
143 }
144 // didn't get from environment variables, read from config file
145 loadThemeFromKConfig();
146}
147
148void Cursor::loadThemeFromKConfig()
149{
150 KConfigGroup mousecfg(kwinApp()->inputConfig(), QStringLiteral("Mouse"));
151 const QString themeName = mousecfg.readEntry("cursorTheme", defaultThemeName());
152 const uint themeSize = mousecfg.readEntry("cursorSize", defaultThemeSize());
153 updateTheme(themeName, themeSize);
154}
155
156void Cursor::updateTheme(const QString &name, int size)
157{
158 if (m_themeName != name || m_themeSize != size) {
159 m_themeName = name;
160 m_themeSize = size;
161 m_cursors.clear();
162 Q_EMIT themeChanged();
163 }
164}
165
166void Cursor::slotKGlobalSettingsNotifyChange(int type, int arg)
167{
168 if (type == 5 /*CursorChanged*/) {
169 kwinApp()->inputConfig()->reparseConfiguration();
170 loadThemeFromKConfig();
171 }
172}
173
174bool Cursor::isOnOutput(Output *output) const
175{
176 if (Cursors::self()->isCursorHidden()) {
177 return false;
178 }
179 return geometry().intersects(output->geometry());
180}
181
182QPointF Cursor::hotspot() const
183{
184 if (Q_UNLIKELY(!m_source)) {
185 return QPointF();
186 }
187 return m_source->hotspot();
188}
189
190QRectF Cursor::geometry() const
191{
192 return rect().translated(m_pos - hotspot());
193}
194
195QRectF Cursor::rect() const
196{
197 if (Q_UNLIKELY(!m_source)) {
198 return QRectF();
199 } else {
200 return QRectF(QPointF(0, 0), m_source->size());
201 }
202}
203
204QPointF Cursor::pos()
205{
206 doGetPos();
207 return m_pos;
208}
209
210void Cursor::setPos(const QPointF &pos)
211{
212 // first query the current pos to not warp to the already existing pos
213 if (pos == m_pos) {
214 return;
215 }
216 m_pos = pos;
217 doSetPos();
218}
219
220void Cursor::markAsRendered(std::chrono::milliseconds timestamp)
221{
222 Q_EMIT rendered(timestamp);
223}
224
226{
227 return x11Cursor(shape.name());
228}
229
230xcb_cursor_t Cursor::x11Cursor(const QByteArray &name)
231{
232 Q_ASSERT(kwinApp()->x11Connection());
233 auto it = m_cursors.constFind(name);
234 if (it != m_cursors.constEnd()) {
235 return it.value();
236 }
237
238 if (name.isEmpty()) {
239 return XCB_CURSOR_NONE;
240 }
241
242 xcb_cursor_context_t *ctx;
243 if (xcb_cursor_context_new(kwinApp()->x11Connection(), Xcb::defaultScreen(), &ctx) < 0) {
244 return XCB_CURSOR_NONE;
245 }
246
247 xcb_cursor_t cursor = xcb_cursor_load_cursor(ctx, name.constData());
248 if (cursor == XCB_CURSOR_NONE) {
249 const auto &names = CursorShape::alternatives(name);
250 for (const QByteArray &cursorName : names) {
251 cursor = xcb_cursor_load_cursor(ctx, cursorName.constData());
252 if (cursor != XCB_CURSOR_NONE) {
253 break;
254 }
255 }
256 }
257 if (cursor != XCB_CURSOR_NONE) {
258 m_cursors.insert(name, cursor);
259 }
260
261 xcb_cursor_context_free(ctx);
262 return cursor;
263}
264
266{
267 Q_EMIT posChanged(m_pos);
268}
269
271{
272}
273
274void Cursor::updatePos(const QPointF &pos)
275{
276 if (m_pos == pos) {
277 return;
278 }
279 m_pos = pos;
280 Q_EMIT posChanged(m_pos);
281}
282
284{
285 ++m_mousePollingCounter;
286 if (m_mousePollingCounter == 1) {
288 }
289}
290
292{
293 Q_ASSERT(m_mousePollingCounter > 0);
294 --m_mousePollingCounter;
295 if (m_mousePollingCounter == 0) {
297 }
298}
299
303
307
309{
310 ++m_cursorTrackingCounter;
311 if (m_cursorTrackingCounter == 1) {
313 }
314}
315
317{
318 Q_ASSERT(m_cursorTrackingCounter > 0);
319 --m_cursorTrackingCounter;
320 if (m_cursorTrackingCounter == 0) {
322 }
323}
324
328
332
334{
335 return QStringLiteral("default");
336}
337
339{
340 return 24;
341}
342
343QList<QByteArray> CursorShape::alternatives(const QByteArray &name)
344{
345 static const QHash<QByteArray, QList<QByteArray>> alternatives = {
346 {
347 QByteArrayLiteral("crosshair"),
348 {
349 QByteArrayLiteral("cross"),
350 QByteArrayLiteral("diamond-cross"),
351 QByteArrayLiteral("cross-reverse"),
352 },
353 },
354 {
355 QByteArrayLiteral("default"),
356 {
357 QByteArrayLiteral("left_ptr"),
358 QByteArrayLiteral("arrow"),
359 QByteArrayLiteral("dnd-none"),
360 QByteArrayLiteral("op_left_arrow"),
361 },
362 },
363 {
364 QByteArrayLiteral("up-arrow"),
365 {
366 QByteArrayLiteral("up_arrow"),
367 QByteArrayLiteral("sb_up_arrow"),
368 QByteArrayLiteral("center_ptr"),
369 QByteArrayLiteral("centre_ptr"),
370 },
371 },
372 {
373 QByteArrayLiteral("wait"),
374 {
375 QByteArrayLiteral("watch"),
376 QByteArrayLiteral("progress"),
377 },
378 },
379 {
380 QByteArrayLiteral("text"),
381 {
382 QByteArrayLiteral("ibeam"),
383 QByteArrayLiteral("xterm"),
384 },
385 },
386 {
387 QByteArrayLiteral("all-scroll"),
388 {
389 QByteArrayLiteral("size_all"),
390 QByteArrayLiteral("fleur"),
391 },
392 },
393 {
394 QByteArrayLiteral("pointer"),
395 {
396 QByteArrayLiteral("pointing_hand"),
397 QByteArrayLiteral("hand2"),
398 QByteArrayLiteral("hand"),
399 QByteArrayLiteral("hand1"),
400 QByteArrayLiteral("e29285e634086352946a0e7090d73106"),
401 QByteArrayLiteral("9d800788f1b08800ae810202380a0822"),
402 },
403 },
404 {
405 QByteArrayLiteral("ns-resize"),
406 {
407 QByteArrayLiteral("size_ver"),
408 QByteArrayLiteral("00008160000006810000408080010102"),
409 QByteArrayLiteral("sb_v_double_arrow"),
410 QByteArrayLiteral("v_double_arrow"),
411 QByteArrayLiteral("n-resize"),
412 QByteArrayLiteral("s-resize"),
413 QByteArrayLiteral("col-resize"),
414 QByteArrayLiteral("top_side"),
415 QByteArrayLiteral("bottom_side"),
416 QByteArrayLiteral("base_arrow_up"),
417 QByteArrayLiteral("base_arrow_down"),
418 QByteArrayLiteral("based_arrow_down"),
419 QByteArrayLiteral("based_arrow_up"),
420 },
421 },
422 {
423 QByteArrayLiteral("ew-resize"),
424 {
425 QByteArrayLiteral("size_hor"),
426 QByteArrayLiteral("028006030e0e7ebffc7f7070c0600140"),
427 QByteArrayLiteral("sb_h_double_arrow"),
428 QByteArrayLiteral("h_double_arrow"),
429 QByteArrayLiteral("e-resize"),
430 QByteArrayLiteral("w-resize"),
431 QByteArrayLiteral("row-resize"),
432 QByteArrayLiteral("right_side"),
433 QByteArrayLiteral("left_side"),
434 },
435 },
436 {
437 QByteArrayLiteral("nesw-resize"),
438 {
439 QByteArrayLiteral("size_bdiag"),
440 QByteArrayLiteral("fcf1c3c7cd4491d801f1e1c78f100000"),
441 QByteArrayLiteral("fd_double_arrow"),
442 QByteArrayLiteral("bottom_left_corner"),
443 QByteArrayLiteral("top_right_corner"),
444 },
445 },
446 {
447 QByteArrayLiteral("nwse-resize"),
448 {
449 QByteArrayLiteral("size_fdiag"),
450 QByteArrayLiteral("c7088f0f3e6c8088236ef8e1e3e70000"),
451 QByteArrayLiteral("bd_double_arrow"),
452 QByteArrayLiteral("bottom_right_corner"),
453 QByteArrayLiteral("top_left_corner"),
454 },
455 },
456 {
457 QByteArrayLiteral("help"),
458 {
459 QByteArrayLiteral("whats_this"),
460 QByteArrayLiteral("d9ce0ab605698f320427677b458ad60b"),
461 QByteArrayLiteral("left_ptr_help"),
462 QByteArrayLiteral("question_arrow"),
463 QByteArrayLiteral("dnd-ask"),
464 QByteArrayLiteral("5c6cd98b3f3ebcb1f9c7f1c204630408"),
465 },
466 },
467 {
468 QByteArrayLiteral("col-resize"),
469 {
470 QByteArrayLiteral("split_h"),
471 QByteArrayLiteral("14fef782d02440884392942c11205230"),
472 QByteArrayLiteral("size_hor"),
473 },
474 },
475 {
476 QByteArrayLiteral("row-resize"),
477 {
478 QByteArrayLiteral("split_v"),
479 QByteArrayLiteral("2870a09082c103050810ffdffffe0204"),
480 QByteArrayLiteral("size_ver"),
481 },
482 },
483 {
484 QByteArrayLiteral("not-allowed"),
485 {
486 QByteArrayLiteral("forbidden"),
487 QByteArrayLiteral("03b6e0fcb3499374a867c041f52298f0"),
488 QByteArrayLiteral("circle"),
489 QByteArrayLiteral("dnd-no-drop"),
490 },
491 },
492 {
493 QByteArrayLiteral("progress"),
494 {
495 QByteArrayLiteral("left_ptr_watch"),
496 QByteArrayLiteral("3ecb610c1bf2410f44200f48c40d3599"),
497 QByteArrayLiteral("00000000000000020006000e7e9ffc3f"),
498 QByteArrayLiteral("08e8e1c95fe2fc01f976f1e063a24ccd"),
499 },
500 },
501 {
502 QByteArrayLiteral("grab"),
503 {
504 QByteArrayLiteral("openhand"),
505 QByteArrayLiteral("9141b49c8149039304290b508d208c40"),
506 QByteArrayLiteral("all_scroll"),
507 QByteArrayLiteral("all-scroll"),
508 },
509 },
510 {
511 QByteArrayLiteral("grabbing"),
512 {
513 QByteArrayLiteral("closedhand"),
514 QByteArrayLiteral("05e88622050804100c20044008402080"),
515 QByteArrayLiteral("4498f0e0c1937ffe01fd06f973665830"),
516 QByteArrayLiteral("9081237383d90e509aa00f00170e968f"),
517 QByteArrayLiteral("fcf21c00b30f7e3f83fe0dfd12e71cff"),
518 },
519 },
520 {
521 QByteArrayLiteral("alias"),
522 {
523 QByteArrayLiteral("link"),
524 QByteArrayLiteral("dnd-link"),
525 QByteArrayLiteral("3085a0e285430894940527032f8b26df"),
526 QByteArrayLiteral("640fb0e74195791501fd1ed57b41487f"),
527 QByteArrayLiteral("a2a266d0498c3104214a47bd64ab0fc8"),
528 },
529 },
530 {
531 QByteArrayLiteral("copy"),
532 {
533 QByteArrayLiteral("dnd-copy"),
534 QByteArrayLiteral("1081e37283d90000800003c07f3ef6bf"),
535 QByteArrayLiteral("6407b0e94181790501fd1e167b474872"),
536 QByteArrayLiteral("b66166c04f8c3109214a4fbd64a50fc8"),
537 },
538 },
539 {
540 QByteArrayLiteral("move"),
541 {
542 QByteArrayLiteral("dnd-move"),
543 },
544 },
545 {
546 QByteArrayLiteral("sw-resize"),
547 {
548 QByteArrayLiteral("size_bdiag"),
549 QByteArrayLiteral("fcf1c3c7cd4491d801f1e1c78f100000"),
550 QByteArrayLiteral("fd_double_arrow"),
551 QByteArrayLiteral("bottom_left_corner"),
552 },
553 },
554 {
555 QByteArrayLiteral("se-resize"),
556 {
557 QByteArrayLiteral("size_fdiag"),
558 QByteArrayLiteral("c7088f0f3e6c8088236ef8e1e3e70000"),
559 QByteArrayLiteral("bd_double_arrow"),
560 QByteArrayLiteral("bottom_right_corner"),
561 },
562 },
563 {
564 QByteArrayLiteral("ne-resize"),
565 {
566 QByteArrayLiteral("size_bdiag"),
567 QByteArrayLiteral("fcf1c3c7cd4491d801f1e1c78f100000"),
568 QByteArrayLiteral("fd_double_arrow"),
569 QByteArrayLiteral("top_right_corner"),
570 },
571 },
572 {
573 QByteArrayLiteral("nw-resize"),
574 {
575 QByteArrayLiteral("size_fdiag"),
576 QByteArrayLiteral("c7088f0f3e6c8088236ef8e1e3e70000"),
577 QByteArrayLiteral("bd_double_arrow"),
578 QByteArrayLiteral("top_left_corner"),
579 },
580 },
581 {
582 QByteArrayLiteral("n-resize"),
583 {
584 QByteArrayLiteral("size_ver"),
585 QByteArrayLiteral("00008160000006810000408080010102"),
586 QByteArrayLiteral("sb_v_double_arrow"),
587 QByteArrayLiteral("v_double_arrow"),
588 QByteArrayLiteral("col-resize"),
589 QByteArrayLiteral("top_side"),
590 },
591 },
592 {
593 QByteArrayLiteral("e-resize"),
594 {
595 QByteArrayLiteral("size_hor"),
596 QByteArrayLiteral("028006030e0e7ebffc7f7070c0600140"),
597 QByteArrayLiteral("sb_h_double_arrow"),
598 QByteArrayLiteral("h_double_arrow"),
599 QByteArrayLiteral("row-resize"),
600 QByteArrayLiteral("left_side"),
601 },
602 },
603 {
604 QByteArrayLiteral("s-resize"),
605 {
606 QByteArrayLiteral("size_ver"),
607 QByteArrayLiteral("00008160000006810000408080010102"),
608 QByteArrayLiteral("sb_v_double_arrow"),
609 QByteArrayLiteral("v_double_arrow"),
610 QByteArrayLiteral("col-resize"),
611 QByteArrayLiteral("bottom_side"),
612 },
613 },
614 {
615 QByteArrayLiteral("w-resize"),
616 {
617 QByteArrayLiteral("size_hor"),
618 QByteArrayLiteral("028006030e0e7ebffc7f7070c0600140"),
619 QByteArrayLiteral("sb_h_double_arrow"),
620 QByteArrayLiteral("h_double_arrow"),
621 QByteArrayLiteral("right_side"),
622 },
623 },
624 };
625 auto it = alternatives.find(name);
626 if (it != alternatives.end()) {
627 return it.value();
628 }
629 return QList<QByteArray>();
630}
631
632QByteArray CursorShape::name() const
633{
634 switch (m_shape) {
635 case Qt::ArrowCursor:
636 return QByteArrayLiteral("default");
637 case Qt::UpArrowCursor:
638 return QByteArrayLiteral("up-arrow");
639 case Qt::CrossCursor:
640 return QByteArrayLiteral("crosshair");
641 case Qt::WaitCursor:
642 return QByteArrayLiteral("wait");
643 case Qt::IBeamCursor:
644 return QByteArrayLiteral("text");
645 case Qt::SizeVerCursor:
646 return QByteArrayLiteral("ns-resize");
647 case Qt::SizeHorCursor:
648 return QByteArrayLiteral("ew-resize");
649 case Qt::SizeBDiagCursor:
650 return QByteArrayLiteral("nesw-resize");
651 case Qt::SizeFDiagCursor:
652 return QByteArrayLiteral("nwse-resize");
653 case Qt::SizeAllCursor:
654 return QByteArrayLiteral("all-scroll");
655 case Qt::SplitVCursor:
656 return QByteArrayLiteral("row-resize");
657 case Qt::SplitHCursor:
658 return QByteArrayLiteral("col-resize");
659 case Qt::PointingHandCursor:
660 return QByteArrayLiteral("pointer");
661 case Qt::ForbiddenCursor:
662 return QByteArrayLiteral("not-allowed");
663 case Qt::OpenHandCursor:
664 return QByteArrayLiteral("grab");
665 case Qt::ClosedHandCursor:
666 return QByteArrayLiteral("grabbing");
667 case Qt::WhatsThisCursor:
668 return QByteArrayLiteral("help");
669 case Qt::BusyCursor:
670 return QByteArrayLiteral("progress");
671 case Qt::DragMoveCursor:
672 return QByteArrayLiteral("move");
673 case Qt::DragCopyCursor:
674 return QByteArrayLiteral("copy");
675 case Qt::DragLinkCursor:
676 return QByteArrayLiteral("alias");
678 return QByteArrayLiteral("ne-resize");
680 return QByteArrayLiteral("n-resize");
682 return QByteArrayLiteral("nw-resize");
684 return QByteArrayLiteral("e-resize");
686 return QByteArrayLiteral("w-resize");
688 return QByteArrayLiteral("se-resize");
690 return QByteArrayLiteral("s-resize");
692 return QByteArrayLiteral("sw-resize");
693 default:
694 return QByteArray();
695 }
696}
697
699{
700 return m_source;
701}
702
704{
705 if (m_source == source) {
706 return;
707 }
708 if (m_source) {
709 disconnect(m_source, &CursorSource::changed, this, &Cursor::cursorChanged);
710 }
711 m_source = source;
712 if (m_source) {
713 connect(m_source, &CursorSource::changed, this, &Cursor::cursorChanged);
714 }
715 Q_EMIT cursorChanged();
716}
717
718} // namespace
719
720#include "moc_cursor.cpp"
void x11ConnectionChanged()
@ OperationModeWaylandOnly
KWin uses only Wayland.
Definition main.h:91
Replacement for QCursor.
Definition cursor.h:102
QPointF pos()
Definition cursor.cpp:204
virtual void doStopCursorTracking()
Definition cursor.cpp:329
xcb_cursor_t x11Cursor(CursorShape shape)
Definition cursor.cpp:225
static int defaultThemeSize()
Definition cursor.cpp:338
virtual void doStopMousePolling()
Definition cursor.cpp:304
void startMousePolling()
Definition cursor.cpp:283
void setSource(CursorSource *source)
Definition cursor.cpp:703
int themeSize() const
The size of the currently used Cursor theme.
Definition cursor.h:322
static QString defaultThemeName()
Definition cursor.cpp:333
void startCursorTracking()
Enables tracking changes of cursor images.
Definition cursor.cpp:308
void posChanged(const QPointF &pos)
QRectF rect() const
Definition cursor.cpp:195
const QString & themeName() const
The name of the currently used Cursor theme.
Definition cursor.h:317
void themeChanged()
void updatePos(const QPointF &pos)
Definition cursor.cpp:274
bool isOnOutput(Output *output) const
Definition cursor.cpp:174
QPointF hotspot() const
Definition cursor.cpp:182
virtual void doGetPos()
Definition cursor.cpp:270
QRectF geometry() const
Definition cursor.cpp:190
CursorSource * source() const
Definition cursor.cpp:698
virtual void doStartMousePolling()
Definition cursor.cpp:300
void cursorChanged()
Signal emitted when the cursor image changes.
~Cursor() override
Definition cursor.cpp:129
void markAsRendered(std::chrono::milliseconds timestamp)
Definition cursor.cpp:220
void stopCursorTracking()
Disables tracking changes of cursor images.
Definition cursor.cpp:316
void stopMousePolling()
Definition cursor.cpp:291
virtual void doSetPos()
Definition cursor.cpp:265
void setPos(const QPointF &pos)
Definition cursor.cpp:210
virtual void doStartCursorTracking()
Definition cursor.cpp:325
void rendered(std::chrono::milliseconds timestamp)
Wrapper round Qt::CursorShape with extensions enums into a single entity.
Definition cursor.h:50
static QList< QByteArray > alternatives(const QByteArray &name)
Definition cursor.cpp:343
QByteArray name() const
The name of a cursor shape in the theme.
Definition cursor.cpp:632
QSizeF size() const
QPointF hotspot() const
void hideCursor()
Definition cursor.cpp:69
void removeCursor(Cursor *cursor)
Definition cursor.cpp:54
void addCursor(Cursor *cursor)
Definition cursor.cpp:43
static Cursors * self()
Definition cursor.cpp:35
void positionChanged(Cursor *cursor, const QPointF &position)
void currentCursorChanged(Cursor *cursor)
bool isCursorHidden() const
Definition cursor.cpp:85
void showCursor()
Definition cursor.cpp:77
void hiddenChanged()
QRect geometry
Definition output.h:134
Session::Type type
Definition session.cpp:17