diff options
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r-- | src/plugins/platforms/xcb/qglxintegration.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbclipboard.cpp | 2 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 20 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 7 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbdrag.cpp | 2 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.cpp | 49 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbkeyboard.cpp | 190 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbkeyboard.h | 5 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbnativeinterface.cpp | 2 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp | 7 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 15 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwmsupport.cpp | 4 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbxsettings.cpp | 6 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbxsettings.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/xcb-plugin.pro | 2 |
16 files changed, 226 insertions, 88 deletions
diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h index 84910c4172..5777980093 100644 --- a/src/plugins/platforms/xcb/qglxintegration.h +++ b/src/plugins/platforms/xcb/qglxintegration.h @@ -75,7 +75,6 @@ private: void init(QXcbScreen *screen, QPlatformOpenGLContext *share); void init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle); - QXcbScreen *m_screen; Display *m_display; GLXFBConfig m_config; GLXContext m_context; diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index 45856f3e6c..8b3893ec2f 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -276,7 +276,7 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c) m_timestamp[QClipboard::Clipboard] = XCB_CURRENT_TIME; m_timestamp[QClipboard::Selection] = XCB_CURRENT_TIME; - m_screen = connection()->screens().at(connection()->primaryScreen()); + m_screen = connection()->primaryScreen(); int x = 0, y = 0, w = 3, h = 3; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 835c414d85..5510c3b1b4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -244,7 +244,7 @@ void QXcbConnection::updateScreens() // the first or an exact match. An exact match isn't // always available if primary->output is XCB_NONE // or currently disconnected output. - if (m_primaryScreen == xcbScreenNumber) { + if (m_primaryScreenNumber == xcbScreenNumber) { if (!primaryScreen || (primary && outputs[i] == primary->output)) { primaryScreen = screen; siblings.prepend(siblings.takeLast()); @@ -306,7 +306,7 @@ void QXcbConnection::updateScreens() QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName) : m_connection(0) , m_canGrabServer(canGrabServer) - , m_primaryScreen(0) + , m_primaryScreenNumber(0) , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY")) , m_nativeInterface(nativeInterface) , xfixes_first_event(0) @@ -331,7 +331,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra #ifdef XCB_USE_XLIB dpy = XOpenDisplay(m_displayName.constData()); if (dpy) { - m_primaryScreen = DefaultScreen(dpy); + m_primaryScreenNumber = DefaultScreen(dpy); m_connection = XGetXCBConnection(dpy); XSetEventQueueOwner(dpy, XCBOwnsEventQueue); XSetErrorHandler(nullErrorHandler); @@ -339,7 +339,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra m_xlib_display = dpy; } #else - m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreen); + m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreenNumber); #endif //XCB_USE_XLIB if (!m_connection || xcb_connection_has_error(m_connection)) @@ -449,6 +449,16 @@ QXcbConnection::~QXcbConnection() delete m_keyboard; } +QXcbScreen *QXcbConnection::primaryScreen() const +{ + if (!m_screens.isEmpty()) { + Q_ASSERT(m_screens.first()->screenNumber() == primaryScreenNumber()); + return m_screens.first(); + } + + return Q_NULLPTR; +} + void QXcbConnection::addWindowEventListener(xcb_window_t id, QXcbWindowEventListener *eventListener) { m_mapper.insert(id, eventListener); @@ -1219,7 +1229,7 @@ xcb_timestamp_t QXcbConnection::getTimestamp() xcb_window_t QXcbConnection::rootWindow() { - return screens().at(primaryScreen())->root(); + return primaryScreen()->root(); } void QXcbConnection::processXcbEvents() diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 4a16e116c6..7286b6b89b 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -324,6 +324,7 @@ private: class QXcbWindowEventListener { public: + virtual ~QXcbWindowEventListener() {} virtual bool handleGenericEvent(xcb_generic_event_t *, long *) { return false; } virtual void handleExposeEvent(const xcb_expose_event_t *) {} @@ -369,7 +370,8 @@ public: QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); } const QList<QXcbScreen *> &screens() const { return m_screens; } - int primaryScreen() const { return m_primaryScreen; } + int primaryScreenNumber() const { return m_primaryScreenNumber; } + QXcbScreen *primaryScreen() const; inline xcb_atom_t atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; } QXcbAtom::Atom qatom(xcb_atom_t atom) const; @@ -469,6 +471,7 @@ public: QXcbEventReader *eventReader() const { return m_reader; } + bool canGrab() const { return m_canGrabServer; } protected: bool event(QEvent *e) Q_DECL_OVERRIDE; @@ -550,7 +553,7 @@ private: bool m_canGrabServer; QList<QXcbScreen *> m_screens; - int m_primaryScreen; + int m_primaryScreenNumber; xcb_atom_t m_allAtoms[QXcbAtom::NAtoms]; diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 53437f24ae..7037e102e2 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -311,7 +311,7 @@ void QXcbDrag::move(const QMouseEvent *me) return; const QList<QXcbScreen *> &screens = connection()->screens(); - QXcbScreen *screen = screens.at(connection()->primaryScreen()); + QXcbScreen *screen = connection()->primaryScreen(); for (int i = 0; i < screens.size(); ++i) { if (screens.at(i)->geometry().contains(globalPos)) { screen = screens.at(i); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index d3533b8e44..3818494d99 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -92,11 +92,11 @@ QT_BEGIN_NAMESPACE -#if defined(QT_DEBUG) && defined(Q_OS_LINUX) // Find out if our parent process is gdb by looking at the 'exe' symlink under /proc,. // or, for older Linuxes, read out 'cmdline'. static bool runningUnderDebugger() { +#if defined(QT_DEBUG) && defined(Q_OS_LINUX) const QString parentProc = QLatin1String("/proc/") + QString::number(getppid()); const QFileInfo parentProcExe(parentProc + QLatin1String("/exe")); if (parentProcExe.isSymLink()) @@ -113,12 +113,15 @@ static bool runningUnderDebugger() s += c; } return s == "gdb"; -} +#else + return false; #endif +} QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char **argv) : m_services(new QGenericUnixServices) , m_instanceName(0) + , m_canGrab(true) { qRegisterMetaType<QXcbWindow*>(); #ifdef XCB_USE_XLIB @@ -126,16 +129,10 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char #endif m_nativeInterface.reset(new QXcbNativeInterface); - bool canGrab = true; - #if defined(QT_DEBUG) && defined(Q_OS_LINUX) - canGrab = !runningUnderDebugger(); - #endif - static bool canNotGrabEnv = qgetenv("QT_XCB_NO_GRAB_SERVER").length(); - if (canNotGrabEnv) - canGrab = false; - // Parse arguments const char *displayName = 0; + bool noGrabArg = false; + bool doGrabArg = false; if (argc) { int j = 1; for (int i = 1; i < argc; i++) { @@ -146,13 +143,35 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char displayName = argv[++i]; else if (arg == "-name" && i < argc - 1) m_instanceName = argv[++i]; + else if (arg == "-nograb") + noGrabArg = true; + else if (arg == "-dograb") + doGrabArg = true; else argv[j++] = argv[i]; } argc = j; } // argc - m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab, displayName); + bool underDebugger = runningUnderDebugger(); + if (noGrabArg && doGrabArg && underDebugger) { + qWarning() << "Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes prcedence"; + doGrabArg = false; + } + +#if defined(QT_DEBUG) + if (!noGrabArg && !doGrabArg && underDebugger) { + qDebug("Qt: gdb: -nograb added to command-line options.\n" + "\t Use the -dograb option to enforce grabbing."); + } +#endif + m_canGrab = (!underDebugger && noGrabArg) || (underDebugger && doGrabArg); + + static bool canNotGrabEnv = qEnvironmentVariableIsSet("QT_XCB_NO_GRAB_SERVER"); + if (canNotGrabEnv) + m_canGrab = false; + + m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, displayName); for (int i = 0; i < parameters.size() - 1; i += 2) { #ifdef Q_XCB_DEBUG @@ -408,19 +427,19 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const case QPlatformIntegration::StartDragTime: case QPlatformIntegration::KeyboardAutoRepeatRate: case QPlatformIntegration::PasswordMaskDelay: - case QPlatformIntegration::FontSmoothingGamma: case QPlatformIntegration::StartDragVelocity: case QPlatformIntegration::UseRtlExtensions: case QPlatformIntegration::PasswordMaskCharacter: // TODO using various xcb, gnome or KDE settings break; // Not implemented, use defaults + case QPlatformIntegration::FontSmoothingGamma: + // Match Qt 4.8 text rendering, and rendering of other X11 toolkits. + return qreal(1.0); case QPlatformIntegration::StartDragDistance: { // The default (in QPlatformTheme::defaultThemeHint) is 10 pixels, but // on a high-resolution screen it makes sense to increase it. - const QList<QXcbScreen *> &screens = defaultConnection()->screens(); qreal dpi = 100.0; - if (screens.length() > 0) { - const QXcbScreen *screen = screens.at(defaultConnection()->primaryScreen()); + if (const QXcbScreen *screen = defaultConnection()->primaryScreen()) { if (screen->logicalDpi().first > dpi) dpi = screen->logicalDpi().first; if (screen->logicalDpi().second > dpi) diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index ffb068ecb3..db6ad541ea 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -117,6 +117,7 @@ private: mutable QByteArray m_wmClass; const char *m_instanceName; + bool m_canGrab; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index dae3a79628..260fb46309 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -721,7 +721,7 @@ void QXcbKeyboard::updateKeymap() if (xkb_keymap) { new_state = xkb_state_new(xkb_keymap); } else { - printKeymapError("Failed to compile a keymap!"); + printKeymapError("Qt: Failed to compile a keymap!"); m_config = false; return; } @@ -737,6 +737,8 @@ void QXcbKeyboard::updateKeymap() xkb_state = new_state; if (!connection()->hasXKB()) updateXKBMods(); + + checkForLatinLayout(); } #ifndef QT_NO_XKB @@ -824,37 +826,137 @@ void QXcbKeyboard::updateXKBMods() xkb_mods.mod5 = xkb_keymap_mod_get_index(xkb_keymap, "Mod5"); } +static bool isLatin(xkb_keysym_t sym) +{ + return ((sym >= 'a' && sym <= 'z') || (sym >= 'A' && sym <= 'Z')); +} + +void QXcbKeyboard::checkForLatinLayout() +{ + m_hasLatinLayout = false; + const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(xkb_keymap); + const xcb_keycode_t minKeycode = connection()->setup()->min_keycode; + const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode; + struct xkb_state *kb_state = xkb_state_new(xkb_keymap); + for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) { + xkb_state_update_mask(kb_state, 0, 0, 0, 0, 0, layout); + for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) { + xkb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, code); + // if layout can produce any of these latin letters (chosen + // arbitrarily) then it must be a latin key based layout + if (sym == XK_q || sym == XK_a || sym == XK_e) { + m_hasLatinLayout = true; + xkb_state_unref(kb_state); + return; + } + } + } + xkb_state_unref(kb_state); +} + +xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const +{ + xkb_layout_index_t layout; + xkb_keysym_t sym = XKB_KEY_NoSymbol; + const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(xkb_keymap, keycode); + const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(xkb_state, keycode); + // Look at user layouts in the order in which they are defined in system + // settings to find a latin keysym. + for (layout = 0; layout < layoutCount; ++layout) { + if (layout == currentLayout) + continue; + const xkb_keysym_t *syms; + xkb_level_index_t level = xkb_state_key_get_level(xkb_state, keycode, layout); + if (xkb_keymap_key_get_syms_by_level(xkb_keymap, keycode, layout, level, &syms) != 1) + continue; + if (isLatin(syms[0])) { + sym = syms[0]; + break; + } + } + // If user layouts don't contain any layout that results in a latin key, we query a + // key from "US" layout, this allows for latin-key-based shorcuts to work even when + // users have only one (non-latin) layout set. + xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); + xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); + if (sym == XKB_KEY_NoSymbol && !m_hasLatinLayout) { + if (!latin_keymap) { + const struct xkb_rule_names names = { xkb_names.rules, xkb_names.model, "us", 0, 0 }; + latin_keymap = xkb_keymap_new_from_names(xkb_context, &names, (xkb_keymap_compile_flags)0); + static bool printFailure = true; + if (!latin_keymap && printFailure) { + // print message about failure to compile US keymap only once, + // no need to do this on every key press. + printFailure = false; + printKeymapError("Qt: Failed to compile US keymap, shortcut handling with " + "non-Latin keyboard layouts may not be fully functional!"); + } + } + if (latin_keymap) { + struct xkb_state *latin_state = xkb_state_new(latin_keymap); + if (latin_state) { + xkb_state_update_mask(latin_state, 0, latchedMods, lockedMods, 0, 0, 0); + sym = xkb_state_key_get_one_sym(latin_state, keycode); + xkb_state_unref(latin_state); + } else { + qWarning("QXcbKeyboard: failed to create a state for US keymap!"); + } + } + } + if (sym == XKB_KEY_NoSymbol) + return sym; + // Check for uniqueness, consider the following setup: + // setxkbmap -layout us,ru,us -variant dvorak,, -option 'grp:ctrl_alt_toggle' (set 'ru' as active). + // In this setup, the user would expect to trigger a ctrl+q shortcut by pressing ctrl+<physical x key>, + // because "US dvorak" is higher up in the layout settings list. This check verifies that an obtained + // 'sym' can not be acquired by any other layout higher up in the user's layout list. If it can be acquired + // then the obtained key is not unique. This prevents ctrl+<physical q key> from generating a ctrl+q + // shortcut in the above described setup. We don't want ctrl+<physical x key> and ctrl+<physical q key> to + // generate the same shortcut event in this case. + const xcb_keycode_t minKeycode = connection()->setup()->min_keycode; + const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode; + struct xkb_state *kb_state = xkb_state_new(xkb_keymap); + for (xkb_layout_index_t prevLayout = 0; prevLayout < layout; ++prevLayout) { + xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, 0, 0, prevLayout); + for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) { + xkb_keysym_t prevSym = xkb_state_key_get_one_sym(kb_state, code); + if (prevSym == sym) { + sym = XKB_KEY_NoSymbol; + break; + } + } + } + xkb_state_unref(kb_state); + return sym; +} + QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const { // turn off the modifier bits which doesn't participate in shortcuts Qt::KeyboardModifiers notNeeded = Qt::MetaModifier | Qt::KeypadModifier | Qt::GroupSwitchModifier; Qt::KeyboardModifiers modifiers = event->modifiers() &= ~notNeeded; // create a fresh kb state and test against the relevant modifier combinations - // NOTE: it should be possible to query the keymap directly, once it gets - // supported by libxkbcommon - struct xkb_state * kb_state = xkb_state_new(xkb_keymap); + struct xkb_state *kb_state = xkb_state_new(xkb_keymap); if (!kb_state) { - qWarning("QXcbKeyboard: failed to compile xkb keymap"); + qWarning("QXcbKeyboard: failed to compile xkb keymap!"); return QList<int>(); } // get kb state from the master xkb_state and update the temporary kb_state - xkb_layout_index_t baseLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_DEPRESSED); - xkb_layout_index_t latchedLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_LATCHED); xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_LOCKED); xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); - xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, - baseLayout, latchedLayout, lockedLayout); + xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, 0, 0, lockedLayout); - xkb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, event->nativeScanCode()); + quint32 keycode = event->nativeScanCode(); + xkb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, keycode); if (sym == XKB_KEY_NoSymbol) { xkb_state_unref(kb_state); return QList<int>(); } QList<int> result; - int baseQtKey = keysymToQtKey(sym, modifiers, lookupString(kb_state, event->nativeScanCode())); + int baseQtKey = keysymToQtKey(sym, modifiers, lookupString(kb_state, keycode)); result += (baseQtKey + modifiers); // The base key is _always_ valid, of course xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(xkb_keymap, "Shift"); @@ -866,48 +968,33 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const Q_ASSERT(controlMod < 32); xkb_mod_mask_t depressed; - struct xkb_keymap *fallback_keymap = 0; int qtKey = 0; - //obtain a list of possible shortcuts for the given key event + // obtain a list of possible shortcuts for the given key event for (uint i = 1; i < sizeof(ModsTbl) / sizeof(*ModsTbl) ; ++i) { Qt::KeyboardModifiers neededMods = ModsTbl[i]; if ((modifiers & neededMods) == neededMods) { - - depressed = 0; - if (neededMods & Qt::AltModifier) - depressed |= (1 << altMod); - if (neededMods & Qt::ShiftModifier) - depressed |= (1 << shiftMod); - if (neededMods & Qt::ControlModifier) - depressed |= (1 << controlMod); - - // update a keyboard state from a set of explicit masks if (i == 8) { - // Add a fall back key for layouts with non Latin-1 characters - if (baseQtKey > 255) { - struct xkb_rule_names names = { xkb_names.rules, xkb_names.model, "us", 0, 0 }; - fallback_keymap = xkb_keymap_new_from_names(xkb_context, &names, (xkb_keymap_compile_flags)0); - if (!fallback_keymap) - continue; - xkb_state_unref(kb_state); - kb_state = xkb_state_new(fallback_keymap); - if (!kb_state) - continue; - } else + if (isLatin(baseQtKey)) continue; + // add a latin key as a fall back key + sym = lookupLatinKeysym(keycode); } else { - xkb_state_update_mask(kb_state, depressed, latchedMods, lockedMods, - baseLayout, latchedLayout, lockedLayout); + depressed = 0; + if (neededMods & Qt::AltModifier) + depressed |= (1 << altMod); + if (neededMods & Qt::ShiftModifier) + depressed |= (1 << shiftMod); + if (neededMods & Qt::ControlModifier) + depressed |= (1 << controlMod); + xkb_state_update_mask(kb_state, depressed, latchedMods, lockedMods, 0, 0, lockedLayout); + sym = xkb_state_key_get_one_sym(kb_state, keycode); } - sym = xkb_state_key_get_one_sym(kb_state, event->nativeScanCode()); - if (sym == XKB_KEY_NoSymbol) continue; Qt::KeyboardModifiers mods = modifiers & ~neededMods; - qtKey = keysymToQtKey(sym, mods, lookupString(kb_state, event->nativeScanCode())); - - if (qtKey == baseQtKey || qtKey == 0) + qtKey = keysymToQtKey(sym, mods, lookupString(kb_state, keycode)); + if (!qtKey || qtKey == baseQtKey) continue; // catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +, @@ -926,8 +1013,6 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const } } xkb_state_unref(kb_state); - xkb_keymap_unref(fallback_keymap); - return result; } @@ -1002,6 +1087,8 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) , xkb_context(0) , xkb_keymap(0) , xkb_state(0) + , latin_keymap(0) + , m_hasLatinLayout(false) { memset(&xkb_names, 0, sizeof(xkb_names)); #ifndef QT_NO_XKB @@ -1029,6 +1116,7 @@ QXcbKeyboard::~QXcbKeyboard() xkb_state_unref(xkb_state); xkb_keymap_unref(xkb_keymap); xkb_context_unref(xkb_context); + xkb_keymap_unref(latin_keymap); if (!connection()->hasXKB()) xcb_key_symbols_free(m_key_symbols); clearXKBConfig(); @@ -1324,7 +1412,6 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, if (type == QEvent::KeyPress) targetWindow->updateNetWmUserTime(time); - // It is crucial the order of xkb_state_key_get_one_sym & xkb_state_update_key operations is not reversed! xcb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, code); QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); @@ -1348,15 +1435,22 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, return; } - Qt::KeyboardModifiers modifiers = translateModifiers(state); - QString string = lookupString(xkb_state, code); int count = string.size(); string.truncate(count); - int qtcode = keysymToQtKey(sym, modifiers, string); - bool isAutoRepeat = false; + // Ιf control modifier is set we should prefer latin character, this is + // used for standard shortcuts in checks like "key == QKeySequence::Copy", + // users can still see the actual X11 keysym with QKeyEvent::nativeVirtualKey + Qt::KeyboardModifiers modifiers = translateModifiers(state); + xcb_keysym_t translatedSym = XKB_KEY_NoSymbol; + if (modifiers & Qt::ControlModifier && !isLatin(sym)) + translatedSym = lookupLatinKeysym(code); + if (translatedSym == XKB_KEY_NoSymbol) + translatedSym = sym; + int qtcode = keysymToQtKey(translatedSym, modifiers, string); + bool isAutoRepeat = false; if (type == QEvent::KeyPress) { if (m_autorepeat_code == code) { isAutoRepeat = true; diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index e71165d824..9f1cf165cb 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -91,6 +91,9 @@ protected: void updateVModMapping(); void updateVModToRModMapping(); + xkb_keysym_t lookupLatinKeysym(xkb_keycode_t keycode) const; + void checkForLatinLayout(); + private: bool m_config; xcb_keycode_t m_autorepeat_code; @@ -99,6 +102,7 @@ private: struct xkb_keymap *xkb_keymap; struct xkb_state *xkb_state; struct xkb_rule_names xkb_names; + mutable struct xkb_keymap *latin_keymap; struct _mod_masks { uint alt; @@ -128,6 +132,7 @@ private: _mod_masks vmod_masks; int core_device_id; #endif + bool m_hasLatinLayout; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 0d75a7f032..3058b29f2d 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -367,7 +367,7 @@ void *QXcbNativeInterface::x11Screen() QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration()); QXcbConnection *defaultConnection = integration->defaultConnection(); if (defaultConnection) - return reinterpret_cast<void *>(defaultConnection->primaryScreen()); + return reinterpret_cast<void *>(defaultConnection->primaryScreenNumber()); return 0; } diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp index 9ec4ea80ec..40a50f61ab 100644 --- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp @@ -59,7 +59,7 @@ QXcbSystemTrayTracker *QXcbSystemTrayTracker::create(QXcbConnection *connection) const xcb_atom_t trayAtom = connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_OPCODE); if (!trayAtom) return 0; - const QByteArray netSysTray = QByteArrayLiteral("_NET_SYSTEM_TRAY_S") + QByteArray::number(connection->primaryScreen()); + const QByteArray netSysTray = QByteArrayLiteral("_NET_SYSTEM_TRAY_S") + QByteArray::number(connection->primaryScreenNumber()); const xcb_atom_t selection = connection->internAtom(netSysTray.constData()); if (!selection) return 0; @@ -145,11 +145,8 @@ QRect QXcbSystemTrayTracker::systemTrayWindowGlobalGeometry(xcb_window_t window) inline void QXcbSystemTrayTracker::emitSystemTrayWindowChanged() { - const int screen = m_connection->primaryScreen(); - if (screen >= 0 && screen < m_connection->screens().size()) { - const QPlatformScreen *ps = m_connection->screens().at(screen); + if (const QPlatformScreen *ps = m_connection->primaryScreen()) emit systemTrayWindowChanged(ps->screen()); - } } // Client messages with the "MANAGER" atom on the root window indicate creation of a new tray. diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 0c2e9d047c..85af8ee1d2 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2170,6 +2170,9 @@ void QXcbWindow::updateSyncRequestCounter() bool QXcbWindow::setKeyboardGrabEnabled(bool grab) { + if (grab && !connection()->canGrab()) + return false; + if (!grab) { xcb_ungrab_keyboard(xcb_connection(), XCB_TIME_CURRENT_TIME); return true; @@ -2185,6 +2188,9 @@ bool QXcbWindow::setKeyboardGrabEnabled(bool grab) bool QXcbWindow::setMouseGrabEnabled(bool grab) { + if (grab && !connection()->canGrab()) + return false; + if (!grab) { xcb_ungrab_pointer(xcb_connection(), XCB_TIME_CURRENT_TIME); return true; @@ -2380,13 +2386,10 @@ void QXcbWindow::setAlertState(bool enabled) { if (m_alertState == enabled) return; - const NetWmStates oldState = netWmStates(); + m_alertState = enabled; - if (enabled) { - setNetWmStates(oldState | NetWmStateDemandsAttention); - } else { - setNetWmStates(oldState & ~NetWmStateDemandsAttention); - } + + changeNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); } bool QXcbWindow::needsSync() const diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.cpp b/src/plugins/platforms/xcb/qxcbwmsupport.cpp index 0458be32f6..1be9ab3e05 100644 --- a/src/plugins/platforms/xcb/qxcbwmsupport.cpp +++ b/src/plugins/platforms/xcb/qxcbwmsupport.cpp @@ -56,7 +56,7 @@ void QXcbWMSupport::updateNetWMAtoms() { net_wm_atoms.clear(); - xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root(); + xcb_window_t root = connection()->primaryScreen()->root(); int offset = 0; int remaining = 0; do { @@ -90,7 +90,7 @@ void QXcbWMSupport::updateVirtualRoots() if (!isSupportedByWM(atom(QXcbAtom::_NET_VIRTUAL_ROOTS))) return; - xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root(); + xcb_window_t root = connection()->primaryScreen()->root(); int offset = 0; int remaining = 0; do { diff --git a/src/plugins/platforms/xcb/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp index 6f2e60c9be..13d42832db 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.cpp +++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp @@ -262,6 +262,12 @@ QXcbXSettings::QXcbXSettings(QXcbScreen *screen) d_ptr->initialized = true; } +QXcbXSettings::~QXcbXSettings() +{ + delete d_ptr; + d_ptr = 0; +} + bool QXcbXSettings::initialized() const { Q_D(const QXcbXSettings); diff --git a/src/plugins/platforms/xcb/qxcbxsettings.h b/src/plugins/platforms/xcb/qxcbxsettings.h index 717fe559c9..3496cedf36 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.h +++ b/src/plugins/platforms/xcb/qxcbxsettings.h @@ -45,6 +45,7 @@ class QXcbXSettings : public QXcbWindowEventListener Q_DECLARE_PRIVATE(QXcbXSettings) public: QXcbXSettings(QXcbScreen *screen); + ~QXcbXSettings(); bool initialized() const; QVariant setting(const QByteArray &property) const; diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index 9aaafadcad..f14fcde73f 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -60,7 +60,7 @@ contains(QT_CONFIG, xcb-xlib) { # to support custom cursors with depth > 1 contains(QT_CONFIG, xcb-render) { DEFINES += XCB_USE_RENDER - LIBS += -lxcb-render -lxcb-render-util -lXrender + LIBS += -lxcb-render -lxcb-render-util } # build with session management support |