File indexing completed on 2024-05-12 05:37:18

0001 /*
0002     SPDX-FileCopyrightText: 2007 Fredrik Höglund <fredrik@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #include "cursornotificationhandler.h"
0008 
0009 #include <private/qtx11extras_p.h>
0010 
0011 #include <X11/extensions/Xfixes.h>
0012 
0013 /*
0014  * This class is a QWidget because we need an X window to
0015  * be able to receive XFixes events. We don't actually map
0016  * the widget.
0017  */
0018 
0019 CursorNotificationHandler::CursorNotificationHandler()
0020     : QWidget()
0021     , currentName(0)
0022 {
0023     Display *dpy = QX11Info::display();
0024     int errorBase;
0025     haveXfixes = false;
0026 
0027     // Request cursor change notification events
0028     if (XFixesQueryExtension(dpy, &fixesEventBase, &errorBase)) {
0029         int major, minor;
0030         XFixesQueryVersion(dpy, &major, &minor);
0031 
0032         if (major >= 2) {
0033             XFixesSelectCursorInput(dpy, winId(), XFixesDisplayCursorNotifyMask);
0034             haveXfixes = true;
0035         }
0036     }
0037 }
0038 
0039 CursorNotificationHandler::~CursorNotificationHandler()
0040 {
0041 }
0042 
0043 QString CursorNotificationHandler::cursorName()
0044 {
0045     if (!haveXfixes)
0046         return QString();
0047 
0048     if (!currentName) {
0049         // Xfixes doesn't have a request for getting the current cursor name,
0050         // but it's included in the XFixesCursorImage struct.
0051         XFixesCursorImage *image = XFixesGetCursorImage(QX11Info::display());
0052         currentName = image->atom;
0053         XFree(image);
0054     }
0055 
0056     return cursorName(currentName);
0057 }
0058 
0059 QString CursorNotificationHandler::cursorName(Atom cursor)
0060 {
0061     QString name;
0062 
0063     // XGetAtomName() is a synchronous call, so we cache the name
0064     // in an atom<->string map the first time we see a name
0065     // to keep the X server round trips down.
0066     if (names.contains(cursor))
0067         name = names[cursor];
0068     else {
0069         char *data = XGetAtomName(QX11Info::display(), cursor);
0070         name = QString::fromUtf8(data);
0071         XFree(data);
0072 
0073         names.insert(cursor, name);
0074     }
0075 
0076     return name;
0077 }
0078 
0079 bool CursorNotificationHandler::x11Event(XEvent *event)
0080 {
0081     if (event->type != fixesEventBase + XFixesCursorNotify)
0082         return false;
0083 
0084     XFixesCursorNotifyEvent *xfe = reinterpret_cast<XFixesCursorNotifyEvent *>(event);
0085     currentName = xfe->cursor_name;
0086 
0087     Q_EMIT cursorNameChanged(cursorName(currentName));
0088 
0089     return false;
0090 }