File indexing completed on 2024-05-12 17:07:16
0001 /* 0002 SPDX-FileCopyrightText: 2010 Andriy Rysin <rysin@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <QAbstractNativeEventFilter> 0010 #include <QKeySequence> 0011 #include <QString> 0012 #include <QStringList> 0013 #include <QWidget> 0014 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0015 #include <QX11Info> 0016 #else 0017 #include <QtGui/private/qtx11extras_p.h> 0018 #endif 0019 0020 #define explicit explicit_is_keyword_in_cpp 0021 #include <xcb/xcb.h> 0022 #include <xcb/xkb.h> 0023 #undef explicit 0024 0025 namespace 0026 { 0027 typedef union { 0028 /* All XKB events share these fields. */ 0029 struct { 0030 uint8_t response_type; 0031 uint8_t xkbType; 0032 uint16_t sequence; 0033 xcb_timestamp_t time; 0034 uint8_t deviceID; 0035 } any; 0036 xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify; 0037 xcb_xkb_map_notify_event_t map_notify; 0038 xcb_xkb_state_notify_event_t state_notify; 0039 } _xkb_event; 0040 } 0041 0042 class XEventNotifier : public QObject, public QAbstractNativeEventFilter 0043 { 0044 Q_OBJECT 0045 0046 Q_SIGNALS: 0047 void layoutChanged(); 0048 void layoutMapChanged(); 0049 0050 public: 0051 XEventNotifier(); 0052 ~XEventNotifier() override 0053 { 0054 } 0055 0056 virtual void start(); 0057 virtual void stop(); 0058 0059 protected: 0060 virtual bool processOtherEvents(xcb_generic_event_t *e); 0061 virtual bool processXkbEvents(xcb_generic_event_t *e); 0062 0063 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0064 bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override; 0065 #else 0066 bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override; 0067 #endif 0068 0069 private: 0070 int registerForXkbEvents(Display *display); 0071 bool isXkbEvent(xcb_generic_event_t *event); 0072 bool isGroupSwitchEvent(_xkb_event *event); 0073 bool isLayoutSwitchEvent(_xkb_event *event); 0074 0075 int xkbOpcode; 0076 }; 0077 0078 struct XkbConfig { 0079 QString keyboardModel; 0080 QStringList layouts; 0081 QStringList variants; 0082 QStringList options; 0083 0084 bool isValid() 0085 { 0086 return !layouts.empty(); 0087 } 0088 }; 0089 0090 class LayoutUnit 0091 { 0092 public: 0093 static const int MAX_LABEL_LENGTH; 0094 0095 LayoutUnit() 0096 { 0097 } 0098 explicit LayoutUnit(const QString &fullLayoutName); 0099 LayoutUnit(const QString &layout, const QString &variant) 0100 : m_layout(layout) 0101 , m_variant(variant) 0102 { 0103 } 0104 /*explicit*/ LayoutUnit(const LayoutUnit &other) 0105 { 0106 operator=(other); 0107 } 0108 0109 LayoutUnit &operator=(const LayoutUnit &other) 0110 { 0111 if (this != &other) { 0112 m_layout = other.m_layout; 0113 m_variant = other.m_variant; 0114 displayName = other.displayName; 0115 shortcut = other.shortcut; 0116 } 0117 return *this; 0118 } 0119 0120 QString getRawDisplayName() const 0121 { 0122 return displayName; 0123 } 0124 QString getDisplayName() const 0125 { 0126 return !displayName.isEmpty() ? displayName : m_layout; 0127 } 0128 void setDisplayName(const QString &name) 0129 { 0130 displayName = name; 0131 } 0132 0133 void setShortcut(const QKeySequence &shortcut) 0134 { 0135 this->shortcut = shortcut; 0136 } 0137 QKeySequence getShortcut() const 0138 { 0139 return shortcut; 0140 } 0141 QString layout() const 0142 { 0143 return m_layout; 0144 } 0145 void setLayout(const QString &layout) 0146 { 0147 m_layout = layout; 0148 } 0149 QString variant() const 0150 { 0151 return m_variant; 0152 } 0153 void setVariant(const QString &variant) 0154 { 0155 m_variant = variant; 0156 } 0157 0158 bool isEmpty() const 0159 { 0160 return m_layout.isEmpty(); 0161 } 0162 bool isValid() const 0163 { 0164 return !isEmpty(); 0165 } 0166 bool operator==(const LayoutUnit &layoutItem) const 0167 { 0168 // FIXME: why not compare the other properties? 0169 return m_layout == layoutItem.m_layout && m_variant == layoutItem.m_variant; 0170 } 0171 bool operator!=(const LayoutUnit &layoutItem) const 0172 { 0173 return !(*this == layoutItem); 0174 } 0175 QString toString() const; 0176 0177 private: 0178 QString displayName; 0179 QKeySequence shortcut; 0180 QString m_layout; 0181 QString m_variant; 0182 }; 0183 0184 struct LayoutSet { 0185 QList<LayoutUnit> layouts; 0186 LayoutUnit currentLayout; 0187 0188 LayoutSet() 0189 { 0190 } 0191 0192 LayoutSet(const LayoutSet &other) 0193 { 0194 operator=(other); 0195 } 0196 0197 bool isValid() const 0198 { 0199 return currentLayout.isValid() && layouts.contains(currentLayout); 0200 } 0201 0202 bool operator==(const LayoutSet ¤tLayouts) const 0203 { 0204 return this->layouts == currentLayouts.layouts && this->currentLayout == currentLayouts.currentLayout; 0205 } 0206 0207 LayoutSet &operator=(const LayoutSet ¤tLayouts) 0208 { 0209 this->layouts = currentLayouts.layouts; 0210 this->currentLayout = currentLayouts.currentLayout; 0211 return *this; 0212 } 0213 0214 QString toString() const 0215 { 0216 QString str(currentLayout.toString()); 0217 str += QLatin1String(": "); 0218 for (const auto &layoutUnit : qAsConst(layouts)) { 0219 str += layoutUnit.toString() + QLatin1Char(' '); 0220 } 0221 return str; 0222 } 0223 0224 static QString toString(const QList<LayoutUnit> &layoutUnits) 0225 { 0226 QString str; 0227 for (const auto &layoutUnit : layoutUnits) { 0228 str += layoutUnit.toString() + QLatin1Char(','); 0229 } 0230 return str; 0231 } 0232 }; 0233 0234 class X11Helper 0235 { 0236 public: 0237 static const int MAX_GROUP_COUNT; 0238 0239 static const char LEFT_VARIANT_STR[]; 0240 static const char RIGHT_VARIANT_STR[]; 0241 0242 static bool xkbSupported(int *xkbOpcode); 0243 0244 static void switchToNextLayout(); 0245 static void scrollLayouts(int delta); 0246 static bool isDefaultLayout(); 0247 static bool setDefaultLayout(); 0248 static bool setLayout(const LayoutUnit &layout); 0249 static LayoutUnit getCurrentLayout(); 0250 static LayoutSet getCurrentLayouts(); 0251 static QList<LayoutUnit> getLayoutsList(); 0252 static QStringList getLayoutsListAsString(const QList<LayoutUnit> &layoutsList); 0253 0254 enum FetchType { ALL, LAYOUTS_ONLY, MODEL_ONLY }; 0255 static bool getGroupNames(Display *dpy, XkbConfig *xkbConfig, FetchType fetchType); 0256 0257 static unsigned int getGroup(); 0258 static bool setGroup(unsigned int group); 0259 };