1 /* 2 * SPDX-FileCopyrightText: 2010 Andriy Rysin (rysin@kde.org) 3 * 4 * SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 7 8 #ifndef X11_HELPER_H_ 9 #define X11_HELPER_H_ 10 11 #include <QKeySequence> 12 #include <QString> 13 #include <QStringList> 14 #include <QWidget> 15 #include <QX11Info> 16 #include <QAbstractNativeEventFilter> 17 18 #include <xcb/xcb.h> 19 20 namespace 21 { 22 typedef struct _xcb_xkb_map_notify_event_t { 23 uint8_t response_type; 24 uint8_t xkbType; 25 uint16_t sequence; 26 xcb_timestamp_t time; 27 uint8_t deviceID; 28 uint8_t ptrBtnActions; 29 uint16_t changed; 30 xcb_keycode_t minKeyCode; 31 xcb_keycode_t maxKeyCode; 32 uint8_t firstType; 33 uint8_t nTypes; 34 xcb_keycode_t firstKeySym; 35 uint8_t nKeySyms; 36 xcb_keycode_t firstKeyAct; 37 uint8_t nKeyActs; 38 xcb_keycode_t firstKeyBehavior; 39 uint8_t nKeyBehavior; 40 xcb_keycode_t firstKeyExplicit; 41 uint8_t nKeyExplicit; 42 xcb_keycode_t firstModMapKey; 43 uint8_t nModMapKeys; 44 xcb_keycode_t firstVModMapKey; 45 uint8_t nVModMapKeys; 46 uint16_t virtualMods; 47 uint8_t pad0[2]; 48 } _xcb_xkb_map_notify_event_t; 49 typedef struct _xcb_xkb_state_notify_event_t { 50 uint8_t response_type; 51 uint8_t xkbType; 52 uint16_t sequence; 53 xcb_timestamp_t time; 54 uint8_t deviceID; 55 uint8_t mods; 56 uint8_t baseMods; 57 uint8_t latchedMods; 58 uint8_t lockedMods; 59 uint8_t group; 60 int16_t baseGroup; 61 int16_t latchedGroup; 62 uint8_t lockedGroup; 63 uint8_t compatState; 64 uint8_t grabMods; 65 uint8_t compatGrabMods; 66 uint8_t lookupMods; 67 uint8_t compatLoockupMods; 68 uint16_t ptrBtnState; 69 uint16_t changed; 70 xcb_keycode_t keycode; 71 uint8_t eventType; 72 uint8_t requestMajor; 73 uint8_t requestMinor; 74 } _xcb_xkb_state_notify_event_t; 75 typedef union { 76 /* All XKB events share these fields. */ 77 struct { 78 uint8_t response_type; 79 uint8_t xkbType; 80 uint16_t sequence; 81 xcb_timestamp_t time; 82 uint8_t deviceID; 83 } any; 84 _xcb_xkb_map_notify_event_t map_notify; 85 _xcb_xkb_state_notify_event_t state_notify; 86 } _xkb_event; 87 } 88 89 class XEventNotifier : public QObject, public QAbstractNativeEventFilter { 90 Q_OBJECT 91 92 Q_SIGNALS: 93 void layoutChanged(); 94 void layoutMapChanged(); 95 96 public: 97 XEventNotifier(); ~XEventNotifier()98 ~XEventNotifier() override {} 99 100 virtual void start(); 101 virtual void stop(); 102 103 protected: 104 // bool x11Event(XEvent * e); 105 virtual bool processOtherEvents(xcb_generic_event_t* e); 106 virtual bool processXkbEvents(xcb_generic_event_t* e); 107 virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE; 108 109 private: 110 int registerForXkbEvents(Display* display); 111 bool isXkbEvent(xcb_generic_event_t* event); 112 bool isGroupSwitchEvent(_xkb_event* event); 113 bool isLayoutSwitchEvent(_xkb_event* event); 114 115 int xkbOpcode; 116 }; 117 118 struct XkbConfig { 119 QString keyboardModel; 120 QStringList layouts; 121 QStringList variants; 122 QStringList options; 123 isValidXkbConfig124 bool isValid() { return ! layouts.empty(); } 125 }; 126 127 128 struct LayoutUnit { 129 static const int MAX_LABEL_LENGTH; 130 131 //TODO: move these to private? 132 QString layout; 133 QString variant; 134 LayoutUnitLayoutUnit135 LayoutUnit() {} 136 explicit LayoutUnit(const QString& fullLayoutName); LayoutUnitLayoutUnit137 LayoutUnit(const QString& layout_, const QString& variant_) { 138 layout = layout_; 139 variant = variant_; 140 } 141 getRawDisplayNameLayoutUnit142 QString getRawDisplayName() const { return displayName; } getDisplayNameLayoutUnit143 QString getDisplayName() const { return !displayName.isEmpty() ? displayName : layout; } setDisplayNameLayoutUnit144 void setDisplayName(const QString& name) { displayName = name; } 145 setShortcutLayoutUnit146 void setShortcut(const QKeySequence& shortcut) { this->shortcut = shortcut; } getShortcutLayoutUnit147 QKeySequence getShortcut() const { return shortcut; } 148 isEmptyLayoutUnit149 bool isEmpty() const { return layout.isEmpty(); } isValidLayoutUnit150 bool isValid() const { return ! isEmpty(); } 151 bool operator==(const LayoutUnit& layoutItem) const { 152 return layout==layoutItem.layout && variant==layoutItem.variant; 153 } 154 bool operator!=(const LayoutUnit& layoutItem) const { 155 return ! (*this == layoutItem); 156 } 157 QString toString() const; 158 159 private: 160 QString displayName; 161 QKeySequence shortcut; 162 }; 163 164 struct LayoutSet { 165 QList<LayoutUnit> layouts; 166 LayoutUnit currentLayout; 167 LayoutSetLayoutSet168 LayoutSet() {} 169 LayoutSetLayoutSet170 LayoutSet(const LayoutSet& currentLayouts) { 171 this->layouts = currentLayouts.layouts; 172 this->currentLayout = currentLayouts.currentLayout; 173 } 174 isValidLayoutSet175 bool isValid() const { 176 return currentLayout.isValid() && layouts.contains(currentLayout); 177 } 178 179 bool operator == (const LayoutSet& currentLayouts) const { 180 return this->layouts == currentLayouts.layouts 181 && this->currentLayout == currentLayouts.currentLayout; 182 } 183 184 LayoutSet& operator = (const LayoutSet& currentLayouts) { 185 this->layouts = currentLayouts.layouts; 186 this->currentLayout = currentLayouts.currentLayout; 187 return *this; 188 } 189 toStringLayoutSet190 QString toString() const { 191 QString str(currentLayout.toString()); 192 str += QLatin1String(": "); 193 foreach(const LayoutUnit& layoutUnit, layouts) { 194 str += layoutUnit.toString() + QLatin1Char(' '); 195 } 196 return str; 197 } 198 toStringLayoutSet199 static QString toString(const QList<LayoutUnit>& layoutUnits) { 200 QString str; 201 foreach(const LayoutUnit& layoutUnit, layoutUnits) { 202 str += layoutUnit.toString() + QLatin1Char(','); 203 } 204 return str; 205 } 206 }; 207 208 class X11Helper 209 { 210 public: 211 static const int MAX_GROUP_COUNT; 212 static const int ARTIFICIAL_GROUP_LIMIT_COUNT; 213 214 static const char LEFT_VARIANT_STR[]; 215 static const char RIGHT_VARIANT_STR[]; 216 217 static bool xkbSupported(int* xkbOpcode); 218 219 static void switchToNextLayout(); 220 static void scrollLayouts(int delta); 221 static bool isDefaultLayout(); 222 static bool setDefaultLayout(); 223 static bool setLayout(const LayoutUnit& layout); 224 static LayoutUnit getCurrentLayout(); 225 static LayoutSet getCurrentLayouts(); 226 static QList<LayoutUnit> getLayoutsList(); 227 static QStringList getLayoutsListAsString(const QList<LayoutUnit>& layoutsList); 228 229 enum FetchType { ALL, LAYOUTS_ONLY, MODEL_ONLY }; 230 static bool getGroupNames(Display* dpy, XkbConfig* xkbConfig, FetchType fetchType); 231 232 private: 233 static unsigned int getGroup(); 234 static bool setGroup(unsigned int group); 235 }; 236 237 #endif /* X11_HELPER_H_ */ 238