File indexing completed on 2025-01-26 05:06:34

0001 /*
0002     SPDX-FileCopyrightText: 2017 Xuetian Weng <wengxt@gmail.com>
0003     SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "x11_backend.h"
0009 #include "x11_libinput_backend.h"
0010 
0011 #include "logging.h"
0012 
0013 #include <config-X11.h>
0014 
0015 #include <libinput-properties.h>
0016 
0017 #include <KConfig>
0018 #include <KConfigGroup>
0019 #include <KLocalizedString>
0020 #include <KSharedConfig>
0021 #include <QFile>
0022 
0023 #include <X11/X.h>
0024 #include <X11/Xatom.h>
0025 #include <X11/Xlib.h>
0026 #include <X11/Xutil.h>
0027 #include <X11/extensions/XI.h>
0028 #include <X11/extensions/XInput2.h>
0029 #if HAVE_XCURSOR
0030 #include <X11/Xcursor/Xcursor.h>
0031 #include <X11/extensions/XInput.h>
0032 #endif
0033 
0034 X11Backend *X11Backend::implementation(QObject *parent)
0035 {
0036     auto dpy = QX11Info::display();
0037     Atom testAtom = XInternAtom(dpy, LIBINPUT_PROP_ACCEL, True);
0038 
0039     if (testAtom) {
0040         qCDebug(KCM_MOUSE) << "Using libinput driver on X11.";
0041         return new X11LibinputBackend(parent);
0042     }
0043 
0044     return nullptr;
0045 }
0046 
0047 X11Backend::X11Backend(QObject *parent)
0048     : InputBackend(parent)
0049 {
0050     m_platformX11 = QX11Info::isPlatformX11();
0051     if (m_platformX11) {
0052         m_dpy = QX11Info::display();
0053     } else {
0054         // TODO: remove this - not needed anymore with Wayland backend!
0055         // let's hope we have a compatibility system like Xwayland ready
0056         m_dpy = XOpenDisplay(nullptr);
0057     }
0058 }
0059 
0060 X11Backend::~X11Backend()
0061 {
0062     if (!m_platformX11 && m_dpy) {
0063         XCloseDisplay(m_dpy);
0064     }
0065 }
0066 
0067 QString X11Backend::currentCursorTheme()
0068 {
0069     if (!m_dpy) {
0070         return QString();
0071     }
0072 
0073     QByteArray name = XGetDefault(m_dpy, "Xcursor", "theme");
0074 #if HAVE_XCURSOR
0075     if (name.isEmpty()) {
0076         name = QByteArray(XcursorGetTheme(m_dpy));
0077     }
0078 #endif
0079     return QFile::decodeName(name);
0080 }
0081 
0082 void X11Backend::applyCursorTheme(const QString &theme, int size)
0083 {
0084 #if HAVE_XCURSOR
0085 
0086     // Apply the KDE cursor theme to ourselves
0087     if (!m_dpy) {
0088         return;
0089     }
0090     if (!theme.isEmpty()) {
0091         XcursorSetTheme(m_dpy, QFile::encodeName(theme));
0092     }
0093 
0094     if (size >= 0) {
0095         XcursorSetDefaultSize(m_dpy, size);
0096     }
0097 
0098     // Load the default cursor from the theme and apply it to the root window.
0099     Cursor handle = XcursorLibraryLoadCursor(m_dpy, "left_ptr");
0100     XDefineCursor(m_dpy, DefaultRootWindow(m_dpy), handle);
0101     XFreeCursor(m_dpy, handle); // Don't leak the cursor
0102     XFlush(m_dpy);
0103 #endif
0104 }
0105 
0106 void X11Backend::kcmInit()
0107 {
0108     auto config = KSharedConfig::openConfig("kcminputrc", KConfig::NoGlobals);
0109     KConfigGroup group = config->group(QStringLiteral("Mouse"));
0110     const QString theme = group.readEntry("cursorTheme", QStringLiteral("breeze_cursors"));
0111     const int size = group.readEntry("cursorSize", 24);
0112 
0113     // Note: If you update this code, update kapplymousetheme as well.
0114 
0115     applyCursorTheme(theme, size);
0116 }