diff options
Diffstat (limited to 'src/platformsupport')
38 files changed, 739 insertions, 172 deletions
diff --git a/src/platformsupport/accessibility/accessibility.pri b/src/platformsupport/accessibility/accessibility.pri new file mode 100644 index 0000000000..d63cd9656b --- /dev/null +++ b/src/platformsupport/accessibility/accessibility.pri @@ -0,0 +1,7 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/qaccessiblebridgeutils_p.h + +SOURCES += \ + $$PWD/qaccessiblebridgeutils.cpp diff --git a/src/platformsupport/accessibility/qaccessiblebridgeutils.cpp b/src/platformsupport/accessibility/qaccessiblebridgeutils.cpp new file mode 100644 index 0000000000..7140bb6e2d --- /dev/null +++ b/src/platformsupport/accessibility/qaccessiblebridgeutils.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qaccessiblebridgeutils_p.h" +#include <QtCore/qmath.h> + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +namespace QAccessibleBridgeUtils { + +static bool performAction(QAccessibleInterface *iface, const QString &actionName) +{ + if (QAccessibleActionInterface *actionIface = iface->actionInterface()) { + if (actionIface->actionNames().contains(actionName)) { + actionIface->doAction(actionName); + return true; + } + } + return false; +} + +QStringList effectiveActionNames(QAccessibleInterface *iface) +{ + QStringList actions; + if (QAccessibleActionInterface *actionIface = iface->actionInterface()) + actions = actionIface->actionNames(); + + if (iface->valueInterface()) { + if (!actions.contains(QAccessibleActionInterface::increaseAction())) + actions << QAccessibleActionInterface::increaseAction(); + if (!actions.contains(QAccessibleActionInterface::decreaseAction())) + actions << QAccessibleActionInterface::decreaseAction(); + } + return actions; +} + +bool performEffectiveAction(QAccessibleInterface *iface, const QString &actionName) +{ + if (!iface) + return false; + if (performAction(iface, actionName)) + return true; + if (actionName != QAccessibleActionInterface::increaseAction() + && actionName != QAccessibleActionInterface::decreaseAction()) + return false; + + QAccessibleValueInterface *valueIface = iface->valueInterface(); + if (!valueIface) + return false; + bool success; + const QVariant currentVariant = valueIface->currentValue(); + double stepSize = valueIface->minimumStepSize().toDouble(&success); + if (!success || qFuzzyIsNull(stepSize)) { + const double min = valueIface->minimumValue().toDouble(&success); + if (!success) + return false; + const double max = valueIface->maximumValue().toDouble(&success); + if (!success) + return false; + stepSize = (max - min) / 10; // this is pretty arbitrary, we just need to provide something + const int typ = currentVariant.type(); + if (typ != QMetaType::Float && typ != QMetaType::Double) { + // currentValue is an integer. Round it up to ensure stepping in case it was below 1 + stepSize = qCeil(stepSize); + } + } + const double current = currentVariant.toDouble(&success); + if (!success) + return false; + if (actionName == QAccessibleActionInterface::decreaseAction()) + stepSize = -stepSize; + valueIface->setCurrentValue(current + stepSize); + return true; +} + +} //namespace + +QT_END_NAMESPACE + +#endif diff --git a/src/platformsupport/accessibility/qaccessiblebridgeutils_p.h b/src/platformsupport/accessibility/qaccessiblebridgeutils_p.h new file mode 100644 index 0000000000..d05934b844 --- /dev/null +++ b/src/platformsupport/accessibility/qaccessiblebridgeutils_p.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACCESSIBLEBRIDGEUTILS_H +#define QACCESSIBLEBRIDGEUTILS_H + +#ifndef QT_NO_ACCESSIBILITY + +#include <QtCore/qstringlist.h> +#include <QtGui/qaccessible.h> + +QT_BEGIN_NAMESPACE + +namespace QAccessibleBridgeUtils { + QStringList effectiveActionNames(QAccessibleInterface *iface); + bool performEffectiveAction(QAccessibleInterface *iface, const QString &actionName); +} + +QT_END_NAMESPACE + +#endif + +#endif //QACCESSIBLEBRIDGEUTILS_H diff --git a/src/platformsupport/eglconvenience/eglconvenience.pri b/src/platformsupport/eglconvenience/eglconvenience.pri index 7600cc952b..8ada53d2c1 100644 --- a/src/platformsupport/eglconvenience/eglconvenience.pri +++ b/src/platformsupport/eglconvenience/eglconvenience.pri @@ -40,15 +40,4 @@ contains(QT_CONFIG,egl) { $$PWD/qxlibeglintegration.cpp } CONFIG += egl - -} else: contains(QT_CONFIG,dynamicgl) { - HEADERS += \ - $$PWD/qeglconvenience_p.h \ - $$PWD/qeglplatformcontext_p.h \ - $$PWD/qeglpbuffer_p.h - - SOURCES += \ - $$PWD/qeglconvenience.cpp \ - $$PWD/qeglplatformcontext.cpp \ - $$PWD/qeglpbuffer.cpp } diff --git a/src/platformsupport/eglconvenience/qeglcompositor.cpp b/src/platformsupport/eglconvenience/qeglcompositor.cpp index 0e0a2d9375..028f92f3cf 100644 --- a/src/platformsupport/eglconvenience/qeglcompositor.cpp +++ b/src/platformsupport/eglconvenience/qeglcompositor.cpp @@ -105,6 +105,29 @@ void QEGLCompositor::renderAll() windows.at(i)->composited(); } +struct BlendStateBinder +{ + BlendStateBinder() : m_blend(false) { + glDisable(GL_BLEND); + } + void set(bool blend) { + if (blend != m_blend) { + if (blend) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable(GL_BLEND); + } + m_blend = blend; + } + } + ~BlendStateBinder() { + if (m_blend) + glDisable(GL_BLEND); + } + bool m_blend; +}; + void QEGLCompositor::render(QEGLPlatformWindow *window) { const QPlatformTextureList *textures = window->textures(); @@ -114,29 +137,37 @@ void QEGLCompositor::render(QEGLPlatformWindow *window) const QRect targetWindowRect(QPoint(0, 0), window->screen()->geometry().size()); glViewport(0, 0, targetWindowRect.width(), targetWindowRect.height()); + float currentOpacity = 1.0f; + BlendStateBinder blend; + for (int i = 0; i < textures->count(); ++i) { uint textureId = textures->textureId(i); glBindTexture(GL_TEXTURE_2D, textureId); QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect); + const float opacity = window->window()->opacity(); + if (opacity != currentOpacity) { + currentOpacity = opacity; + m_blitter->setOpacity(currentOpacity); + } if (textures->count() > 1 && i == textures->count() - 1) { // Backingstore for a widget with QOpenGLWidget subwidgets - m_blitter->setSwizzleRB(true); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + blend.set(true); m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); - glDisable(GL_BLEND); } else if (textures->count() == 1) { // A regular QWidget window - m_blitter->setSwizzleRB(true); + const bool translucent = window->window()->requestedFormat().alphaBufferSize() > 0; + blend.set(translucent); m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); } else { // Texture from an FBO belonging to a QOpenGLWidget - m_blitter->setSwizzleRB(false); + blend.set(false); m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft); } } + + m_blitter->setOpacity(1.0f); } QEGLCompositor *QEGLCompositor::instance() diff --git a/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp b/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp index ab92bac37d..8abfbf2763 100644 --- a/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp @@ -41,6 +41,7 @@ #include <QtGui/QOpenGLShaderProgram> #include <QtGui/QOpenGLContext> +#include <QtGui/QPainter> #include "qeglplatformbackingstore_p.h" #include "qeglcompositor_p.h" @@ -209,9 +210,16 @@ void QEGLPlatformBackingStore::composited() } } -void QEGLPlatformBackingStore::beginPaint(const QRegion &rgn) +void QEGLPlatformBackingStore::beginPaint(const QRegion ®ion) { - m_dirty |= rgn; + m_dirty |= region; + + if (m_image.hasAlphaChannel()) { + QPainter p(&m_image); + p.setCompositionMode(QPainter::CompositionMode_Source); + foreach (const QRect &r, region.rects()) + p.fillRect(r, Qt::transparent); + } } void QEGLPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents) @@ -223,7 +231,15 @@ void QEGLPlatformBackingStore::resize(const QSize &size, const QRegion &staticCo if (!dstWin || (!dstWin->isRaster() && dstWin->window()->surfaceType() != QSurface::RasterGLSurface)) return; - m_image = QImage(size, QImage::Format_RGB32); + // Child windows do not get real native surfaces and so share the same + // format as the parent, regardless of what has been requested. The + // exception is WA_TranslucentBackground that sets alphaBufferSize in the + // requested format, this has to be taken into account when compositing. + const bool translucent = m_window->window()->requestedFormat().alphaBufferSize() > 0; + const QImage::Format format = translucent ? QImage::Format_RGBA8888 : QImage::Format_RGBX8888; + + m_image = QImage(size, format); + m_window->create(); screen->compositingContext()->makeCurrent(dstWin->window()); diff --git a/src/platformsupport/eglconvenience/qeglplatformbackingstore_p.h b/src/platformsupport/eglconvenience/qeglplatformbackingstore_p.h index cb1e5999b0..8b0566afa6 100644 --- a/src/platformsupport/eglconvenience/qeglplatformbackingstore_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformbackingstore_p.h @@ -61,7 +61,7 @@ public: QPaintDevice *paintDevice() Q_DECL_OVERRIDE; - void beginPaint(const QRegion &) Q_DECL_OVERRIDE; + void beginPaint(const QRegion ®ion) Q_DECL_OVERRIDE; void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE; diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index eec6463c21..9691d12682 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -44,6 +44,7 @@ #include "qeglpbuffer_p.h" #include <qpa/qplatformwindow.h> #include <QOpenGLContext> +#include <QtPlatformHeaders/QEGLNativeContext> #include <QDebug> QT_BEGIN_NAMESPACE @@ -108,25 +109,21 @@ QT_BEGIN_NAMESPACE #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 #endif -QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display) - : m_eglDisplay(display) - , m_eglConfig(q_configFromGLFormat(display, format)) - , m_swapInterval(-1) - , m_swapIntervalEnvChecked(false) - , m_swapIntervalFromEnv(-1) -{ - init(format, share); -} - QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLConfig config) + EGLConfig *config, const QVariant &nativeHandle) : m_eglDisplay(display) - , m_eglConfig(config) , m_swapInterval(-1) , m_swapIntervalEnvChecked(false) , m_swapIntervalFromEnv(-1) { - init(format, share); + if (nativeHandle.isNull()) { + m_eglConfig = config ? *config : q_configFromGLFormat(display, format); + m_ownsContext = true; + init(format, share); + } else { + m_ownsContext = false; + adopt(nativeHandle, share); + } } void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLContext *share) @@ -198,6 +195,59 @@ void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLCont q_printEglConfig(m_eglDisplay, m_eglConfig); } + updateFormatFromGL(); +} + +void QEGLPlatformContext::adopt(const QVariant &nativeHandle, QPlatformOpenGLContext *share) +{ + if (!nativeHandle.canConvert<QEGLNativeContext>()) { + qWarning("QEGLPlatformContext: Requires a QEGLNativeContext"); + return; + } + QEGLNativeContext handle = nativeHandle.value<QEGLNativeContext>(); + EGLContext context = handle.context(); + if (!context) { + qWarning("QEGLPlatformContext: No EGLContext given"); + return; + } + + // A context belonging to a given EGLDisplay cannot be used with another one. + if (handle.display() != m_eglDisplay) { + qWarning("QEGLPlatformContext: Cannot adopt context from different display"); + return; + } + + // Figure out the EGLConfig. + EGLint value = 0; + eglQueryContext(m_eglDisplay, context, EGL_CONFIG_ID, &value); + EGLint n = 0; + EGLConfig cfg; + const EGLint attribs[] = { EGL_CONFIG_ID, value, EGL_NONE }; + if (eglChooseConfig(m_eglDisplay, attribs, &cfg, 1, &n) && n == 1) { + m_eglConfig = cfg; + m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig); + } else { + qWarning("QEGLPlatformContext: Failed to get framebuffer configuration for context"); + } + + // Fetch client API type. + value = 0; + eglQueryContext(m_eglDisplay, context, EGL_CONTEXT_CLIENT_TYPE, &value); + if (value == EGL_OPENGL_API || value == EGL_OPENGL_ES_API) { + m_api = value; + eglBindAPI(m_api); + } else { + qWarning("QEGLPlatformContext: Failed to get client API type"); + m_api = EGL_OPENGL_ES_API; + } + + m_eglContext = context; + m_shareContext = share ? static_cast<QEGLPlatformContext *>(share)->m_eglContext : 0; + updateFormatFromGL(); +} + +void QEGLPlatformContext::updateFormatFromGL() +{ #ifndef QT_NO_OPENGL // Make the context current to ensure the GL version query works. This needs a surface too. const EGLint pbufferAttributes[] = { @@ -296,10 +346,10 @@ bool QEGLPlatformContext::makeCurrent(QPlatformSurface *surface) QEGLPlatformContext::~QEGLPlatformContext() { - if (m_eglContext != EGL_NO_CONTEXT) { + if (m_ownsContext && m_eglContext != EGL_NO_CONTEXT) eglDestroyContext(m_eglDisplay, m_eglContext); - m_eglContext = EGL_NO_CONTEXT; - } + + m_eglContext = EGL_NO_CONTEXT; } void QEGLPlatformContext::doneCurrent() diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h index 714633c3bc..82f062c4a4 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h @@ -44,6 +44,7 @@ #include <qpa/qplatformwindow.h> #include <qpa/qplatformopenglcontext.h> +#include <QtCore/QVariant> #include <EGL/egl.h> QT_BEGIN_NAMESPACE @@ -51,9 +52,8 @@ QT_BEGIN_NAMESPACE class QEGLPlatformContext : public QPlatformOpenGLContext { public: - QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display); QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLConfig config); + EGLConfig *config = 0, const QVariant &nativeHandle = QVariant()); ~QEGLPlatformContext(); bool makeCurrent(QPlatformSurface *surface); @@ -74,6 +74,8 @@ protected: private: void init(const QSurfaceFormat &format, QPlatformOpenGLContext *share); + void adopt(const QVariant &nativeHandle, QPlatformOpenGLContext *share); + void updateFormatFromGL(); EGLContext m_eglContext; EGLContext m_shareContext; @@ -84,6 +86,7 @@ private: int m_swapInterval; bool m_swapIntervalEnvChecked; int m_swapIntervalFromEnv; + bool m_ownsContext; }; QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp index b48f993436..1b63d16195 100644 --- a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp @@ -43,6 +43,7 @@ #include <QtGui/QOpenGLContext> #include <QtGui/QOffscreenSurface> #include <QtGui/QGuiApplication> +#include <QtGui/private/qguiapplication_p.h> #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatforminputcontextfactory_p.h> @@ -57,6 +58,8 @@ #include <QtPlatformSupport/private/qevdevtouch_p.h> #endif +#include <QtPlatformHeaders/qeglfsfunctions.h> + #include "qeglplatformintegration_p.h" #include "qeglplatformcontext_p.h" #include "qeglplatformwindow_p.h" @@ -93,7 +96,8 @@ QEGLPlatformIntegration::QEGLPlatformIntegration() m_display(EGL_NO_DISPLAY), m_inputContext(0), m_fontDb(new QGenericUnixFontDatabase), - m_services(new QGenericUnixServices) + m_services(new QGenericUnixServices), + m_kbdMgr(0) { } @@ -158,9 +162,14 @@ QPlatformOpenGLContext *QEGLPlatformIntegration::createPlatformOpenGLContext(QOp // If there is a "root" window into which raster and QOpenGLWidget content is // composited, all other contexts must share with its context. QOpenGLContext *compositingContext = screen ? screen->compositingContext() : 0; - return createContext(context->format(), - compositingContext ? compositingContext->handle() : context->shareHandle(), - display()); + QPlatformOpenGLContext *share = compositingContext ? compositingContext->handle() : context->shareHandle(); + QVariant nativeHandle = context->nativeHandle(); + QPlatformOpenGLContext *platformContext = createContext(context->format(), + share, + display(), + &nativeHandle); + context->setNativeHandle(nativeHandle); + return platformContext; } QPlatformOffscreenSurface *QEGLPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const @@ -189,7 +198,10 @@ QPlatformNativeInterface *QEGLPlatformIntegration::nativeInterface() const enum ResourceType { EglDisplay, EglWindow, - EglContext + EglContext, + EglConfig, + NativeDisplay, + Display }; static int resourceType(const QByteArray &key) @@ -197,7 +209,10 @@ static int resourceType(const QByteArray &key) static const QByteArray names[] = { // match ResourceType QByteArrayLiteral("egldisplay"), QByteArrayLiteral("eglwindow"), - QByteArrayLiteral("eglcontext") + QByteArrayLiteral("eglcontext"), + QByteArrayLiteral("eglconfig"), + QByteArrayLiteral("nativedisplay"), + QByteArrayLiteral("display") }; const QByteArray *end = names + sizeof(names) / sizeof(names[0]); const QByteArray *result = std::find(names, end, key); @@ -214,6 +229,26 @@ void *QEGLPlatformIntegration::nativeResourceForIntegration(const QByteArray &re case EglDisplay: result = m_screen->display(); break; + case NativeDisplay: + result = reinterpret_cast<void*>(nativeDisplay()); + break; + default: + break; + } + + return result; +} + +void *QEGLPlatformIntegration::nativeResourceForScreen(const QByteArray &resource, QScreen *) +{ + void *result = 0; + + switch (resourceType(resource)) { + case Display: + // Play nice when using the x11 hooks: Be compatible with xcb that allows querying + // the X Display pointer, which is nothing but our native display. + result = reinterpret_cast<void*>(nativeDisplay()); + break; default: break; } @@ -252,6 +287,10 @@ void *QEGLPlatformIntegration::nativeResourceForContext(const QByteArray &resour if (context->handle()) result = static_cast<QEGLPlatformContext *>(context->handle())->eglContext(); break; + case EglConfig: + if (context->handle()) + result = static_cast<QEGLPlatformContext *>(context->handle())->eglConfig(); + break; default: break; } @@ -279,10 +318,35 @@ QPlatformNativeInterface::NativeResourceForContextFunction QEGLPlatformIntegrati return 0; } +QFunctionPointer QEGLPlatformIntegration::platformFunction(const QByteArray &function) const +{ +#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) + if (function == QEglFSFunctions::loadKeymapTypeIdentifier()) + return QFunctionPointer(loadKeymapStatic); +#else + Q_UNUSED(function) +#endif + + return 0; +} + +void QEGLPlatformIntegration::loadKeymapStatic(const QString &filename) +{ +#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) + QEGLPlatformIntegration *self = static_cast<QEGLPlatformIntegration *>(QGuiApplicationPrivate::platformIntegration()); + if (self->m_kbdMgr) + self->m_kbdMgr->loadKeymap(filename); + else + qWarning("QEGLPlatformIntegration: Cannot load keymap, no keyboard handler found"); +#else + Q_UNUSED(filename); +#endif +} + void QEGLPlatformIntegration::createInputHandlers() { #if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) - new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this); + m_kbdMgr = new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this); QEvdevMouseManager *mouseMgr = new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this); Q_FOREACH (QScreen *screen, QGuiApplication::screens()) { QEGLPlatformCursor *cursor = static_cast<QEGLPlatformCursor *>(screen->handle()->cursor()); diff --git a/src/platformsupport/eglconvenience/qeglplatformintegration_p.h b/src/platformsupport/eglconvenience/qeglplatformintegration_p.h index f665455383..36f79e2997 100644 --- a/src/platformsupport/eglconvenience/qeglplatformintegration_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformintegration_p.h @@ -44,6 +44,7 @@ #include <qpa/qplatformintegration.h> #include <qpa/qplatformnativeinterface.h> +#include <QtCore/QVariant> #include <EGL/egl.h> QT_BEGIN_NAMESPACE @@ -52,6 +53,7 @@ class QEGLPlatformScreen; class QEGLPlatformWindow; class QEGLPlatformContext; class QFbVtHandler; +class QEvdevKeyboardManager; class QEGLPlatformIntegration : public QPlatformIntegration, public QPlatformNativeInterface { @@ -79,16 +81,20 @@ public: QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; // QPlatformNativeInterface void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; + void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) Q_DECL_OVERRIDE; void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) Q_DECL_OVERRIDE; NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE; + QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + protected: virtual QEGLPlatformScreen *createScreen() const = 0; virtual QEGLPlatformWindow *createWindow(QWindow *window) const = 0; virtual QEGLPlatformContext *createContext(const QSurfaceFormat &format, QPlatformOpenGLContext *shareContext, - EGLDisplay display) const = 0; + EGLDisplay display, + QVariant *nativeHandle) const = 0; virtual QPlatformOffscreenSurface *createOffscreenSurface(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *surface) const = 0; @@ -98,12 +104,15 @@ protected: void createInputHandlers(); private: + static void loadKeymapStatic(const QString &filename); + QEGLPlatformScreen *m_screen; EGLDisplay m_display; QPlatformInputContext *m_inputContext; QScopedPointer<QPlatformFontDatabase> m_fontDb; QScopedPointer<QPlatformServices> m_services; QScopedPointer<QFbVtHandler> m_vtHandler; + QEvdevKeyboardManager *m_kbdMgr; }; QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglplatformwindow.cpp b/src/platformsupport/eglconvenience/qeglplatformwindow.cpp index e9b79512ba..a83dd80391 100644 --- a/src/platformsupport/eglconvenience/qeglplatformwindow.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformwindow.cpp @@ -127,4 +127,12 @@ WId QEGLPlatformWindow::winId() const return m_winId; } +void QEGLPlatformWindow::setOpacity(qreal) +{ + if (!isRaster()) + qWarning("eglfs: Cannot set opacity for non-raster windows"); + + // Nothing to do here. The opacity is stored in the QWindow. +} + QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglplatformwindow_p.h b/src/platformsupport/eglconvenience/qeglplatformwindow_p.h index 17a1d07a79..8c77d31fef 100644 --- a/src/platformsupport/eglconvenience/qeglplatformwindow_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformwindow_p.h @@ -64,6 +64,7 @@ public: bool isRaster() const; WId winId() const Q_DECL_OVERRIDE; + void setOpacity(qreal opacity) Q_DECL_OVERRIDE; virtual EGLNativeWindowType eglWindow() const = 0; diff --git a/src/platformsupport/fbconvenience/qfbscreen.cpp b/src/platformsupport/fbconvenience/qfbscreen.cpp index 37d16ddeb6..a962a5eb59 100644 --- a/src/platformsupport/fbconvenience/qfbscreen.cpp +++ b/src/platformsupport/fbconvenience/qfbscreen.cpp @@ -196,13 +196,13 @@ void QFbScreen::generateRects() remainingScreen -= localGeometry; QRegion windowRegion(localGeometry); windowRegion -= remainingScreen; - foreach (QRect rect, windowRegion.rects()) { + foreach (const QRect &rect, windowRegion.rects()) { mCachedRects += QPair<QRect, int>(rect, i); } } #endif } - foreach (QRect rect, remainingScreen.rects()) + foreach (const QRect &rect, remainingScreen.rects()) mCachedRects += QPair<QRect, int>(rect, -1); mIsUpToDate = true; return; @@ -242,7 +242,7 @@ QRegion QFbScreen::doRedraw() rectRegion -= intersect; // we only expect one rectangle, but defensive coding... - foreach (QRect rect, intersect.rects()) { + foreach (const QRect &rect, intersect.rects()) { bool firstLayer = true; if (layer == -1) { mCompositePainter->fillRect(rect, Qt::black); diff --git a/src/platformsupport/fbconvenience/qfbscreen_p.h b/src/platformsupport/fbconvenience/qfbscreen_p.h index dd940c4a1d..924b49afda 100644 --- a/src/platformsupport/fbconvenience/qfbscreen_p.h +++ b/src/platformsupport/fbconvenience/qfbscreen_p.h @@ -108,7 +108,7 @@ private: void generateRects(); QPainter *mCompositePainter; - QList<QPair<QRect, int> > mCachedRects; + QVector<QPair<QRect, int> > mCachedRects; QList <QFbBackingStore*> mBackingStores; friend class QFbWindow; diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index b8da9726d5..0d1f9455e1 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -51,7 +51,6 @@ #include <qpa/qplatformservices.h> #include <QtGui/private/qfontengine_ft_p.h> -#include <QtGui/private/qfontengine_qpa_p.h> #include <QtGui/private/qguiapplication_p.h> #include <QtGui/qguiapplication.h> diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp index fec489ba60..20cdab6de1 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE QFontEngineMultiFontConfig::QFontEngineMultiFontConfig(QFontEngine *fe, int script) - : QFontEngineMultiQPA(fe, script) + : QFontEngineMultiBasicImpl(fe, script) { } diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h index 2d93d236e5..9fb273f692 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h +++ b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h @@ -42,12 +42,12 @@ #ifndef QFONTENGINEMULTIFONTCONFIG_H #define QFONTENGINEMULTIFONTCONFIG_H -#include <QtGui/private/qfontengine_qpa_p.h> +#include <QtGui/private/qfontengine_p.h> #include <fontconfig/fontconfig.h> QT_BEGIN_NAMESPACE -class QFontEngineMultiFontConfig : public QFontEngineMultiQPA +class QFontEngineMultiFontConfig : public QFontEngineMultiBasicImpl { public: explicit QFontEngineMultiFontConfig(QFontEngine *fe, int script); diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 9248785696..c0643444e2 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -348,7 +348,7 @@ QFontEngine *QCoreTextFontDatabase::fontEngine(const QByteArray &fontData, qreal QFontEngine *fontEngine = NULL; if (cgFont == NULL) { - qWarning("QRawFont::platformLoadFromData: CGFontCreateWithDataProvider failed"); + qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed"); } else { QFontDef def; def.pixelSize = pixelSize; diff --git a/src/platformsupport/glxconvenience/qglxconvenience.cpp b/src/platformsupport/glxconvenience/qglxconvenience.cpp index 4630b12a57..851ad37a6a 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience.cpp +++ b/src/platformsupport/glxconvenience/qglxconvenience.cpp @@ -250,7 +250,7 @@ XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *f return visualInfo; } -void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config, GLXContext) +void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config) { int redSize = 0; int greenSize = 0; @@ -262,8 +262,6 @@ void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, int sampleCount = 0; int stereo = 0; - XVisualInfo *vi = glXGetVisualFromFBConfig(display,config); - XFree(vi); glXGetFBConfigAttrib(display, config, GLX_RED_SIZE, &redSize); glXGetFBConfigAttrib(display, config, GLX_GREEN_SIZE, &greenSize); glXGetFBConfigAttrib(display, config, GLX_BLUE_SIZE, &blueSize); @@ -287,6 +285,41 @@ void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, format->setStereo(stereo); } +void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo) +{ + int redSize = 0; + int greenSize = 0; + int blueSize = 0; + int alphaSize = 0; + int depthSize = 0; + int stencilSize = 0; + int sampleBuffers = 0; + int sampleCount = 0; + int stereo = 0; + + glXGetConfig(display, visualInfo, GLX_RED_SIZE, &redSize); + glXGetConfig(display, visualInfo, GLX_GREEN_SIZE, &greenSize); + glXGetConfig(display, visualInfo, GLX_BLUE_SIZE, &blueSize); + glXGetConfig(display, visualInfo, GLX_ALPHA_SIZE, &alphaSize); + glXGetConfig(display, visualInfo, GLX_DEPTH_SIZE, &depthSize); + glXGetConfig(display, visualInfo, GLX_STENCIL_SIZE, &stencilSize); + glXGetConfig(display, visualInfo, GLX_SAMPLES_ARB, &sampleBuffers); + glXGetConfig(display, visualInfo, GLX_STEREO, &stereo); + + format->setRedBufferSize(redSize); + format->setGreenBufferSize(greenSize); + format->setBlueBufferSize(blueSize); + format->setAlphaBufferSize(alphaSize); + format->setDepthBufferSize(depthSize); + format->setStencilBufferSize(stencilSize); + if (sampleBuffers) { + glXGetConfig(display, visualInfo, GLX_SAMPLES_ARB, &sampleCount); + format->setSamples(sampleCount); + } + + format->setStereo(stereo); +} + QSurfaceFormat qglx_reduceSurfaceFormat(const QSurfaceFormat &format, bool *reduced) { QSurfaceFormat retFormat = format; diff --git a/src/platformsupport/glxconvenience/qglxconvenience_p.h b/src/platformsupport/glxconvenience/qglxconvenience_p.h index 66548a3479..04fa8595ef 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience_p.h +++ b/src/platformsupport/glxconvenience/qglxconvenience_p.h @@ -50,7 +50,8 @@ XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format); GLXFBConfig qglx_findConfig(Display *display, int screen, const QSurfaceFormat &format, int drawableBit = GLX_WINDOW_BIT); -void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config, GLXContext context = 0); +void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config); +void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo); QVector<int> qglx_buildSpec(const QSurfaceFormat &format, int drawableBit = GLX_WINDOW_BIT); QSurfaceFormat qglx_reduceSurfaceFormat(const QSurfaceFormat &format, bool *reduced); diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp index 0841544208..72de73db7e 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp @@ -93,13 +93,15 @@ QEvdevKeyboardHandler::~QEvdevKeyboardHandler() qt_safe_close(m_fd); } -QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device, const QString &specification) +QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device, + const QString &specification, + const QString &defaultKeymapFile) { #ifdef QT_QPA_KEYMAP_DEBUG qWarning() << "Try to create keyboard handler for" << device << specification; #endif - QString keymapFile; + QString keymapFile = defaultKeymapFile; int repeatDelay = 400; int repeatRate = 80; bool disableZap = false; diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h index 1065b05d51..164b1c3863 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h @@ -145,7 +145,9 @@ public: SwitchConsoleMask = 0x0000007f }; - static QEvdevKeyboardHandler *create(const QString &device, const QString &specification); + static QEvdevKeyboardHandler *create(const QString &device, + const QString &specification, + const QString &defaultKeymapFile = QString()); static Qt::KeyboardModifiers toQtModifiers(quint8 mod) { @@ -161,13 +163,14 @@ public: return qtmod; } + bool loadKeymap(const QString &file); + void unloadKeymap(); + private slots: void readKeycode(); KeycodeAction processKeycode(quint16 keycode, bool pressed, bool autorepeat); private: - void unloadKeymap(); - bool loadKeymap(const QString &file); void processKeyEvent(int nativecode, int unicode, int qtcode, Qt::KeyboardModifiers modifiers, bool isPress, bool autoRepeat); void switchLed(int, bool); diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp index 4932087c5f..4ceaf98055 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp @@ -113,7 +113,7 @@ void QEvdevKeyboardManager::addKeyboard(const QString &deviceNode) #endif QEvdevKeyboardHandler *keyboard; - keyboard = QEvdevKeyboardHandler::create(deviceNode, m_spec); + keyboard = QEvdevKeyboardHandler::create(deviceNode, m_spec, m_defaultKeymapFile); if (keyboard) m_keyboards.insert(deviceNode, keyboard); else @@ -132,4 +132,28 @@ void QEvdevKeyboardManager::removeKeyboard(const QString &deviceNode) } } +void QEvdevKeyboardManager::loadKeymap(const QString &file) +{ + m_defaultKeymapFile = file; + + if (file.isEmpty()) { + // Restore the default, which is either the built-in keymap or + // the one given in the plugin spec. + QString keymapFromSpec; + foreach (const QString &arg, m_spec.split(QLatin1Char(':'))) { + if (arg.startsWith(QLatin1String("keymap="))) + keymapFromSpec = arg.mid(7); + } + foreach (QEvdevKeyboardHandler *handler, m_keyboards) { + if (keymapFromSpec.isEmpty()) + handler->unloadKeymap(); + else + handler->loadKeymap(keymapFromSpec); + } + } else { + foreach (QEvdevKeyboardHandler *handler, m_keyboards) + handler->loadKeymap(file); + } +} + QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h index 37c60c035c..e7a07f17a4 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager_p.h @@ -59,6 +59,8 @@ public: QEvdevKeyboardManager(const QString &key, const QString &specification, QObject *parent = 0); ~QEvdevKeyboardManager(); + void loadKeymap(const QString &file); + private slots: void addKeyboard(const QString &deviceNode = QString()); void removeKeyboard(const QString &deviceNode); @@ -67,6 +69,7 @@ private: QString m_spec; QHash<QString,QEvdevKeyboardHandler*> m_keyboards; QDeviceDiscovery *m_deviceDiscovery; + QString m_defaultKeymapFile; }; QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index 92f807095f..611a7f9d6d 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -60,6 +60,8 @@ //#define QT_QPA_MOUSE_HANDLER_DEBUG +#define TEST_BIT(array, bit) (array[bit/8] & (1<<(bit%8))) + QT_BEGIN_NAMESPACE QEvdevMouseHandler *QEvdevMouseHandler::create(const QString &device, const QString &specification) @@ -71,6 +73,7 @@ QEvdevMouseHandler *QEvdevMouseHandler::create(const QString &device, const QStr bool compression = true; int jitterLimit = 0; int grab = 0; + bool abs = false; QStringList args = specification.split(QLatin1Char(':')); foreach (const QString &arg, args) { @@ -80,27 +83,37 @@ QEvdevMouseHandler *QEvdevMouseHandler::create(const QString &device, const QStr jitterLimit = arg.mid(9).toInt(); else if (arg.startsWith(QLatin1String("grab="))) grab = arg.mid(5).toInt(); + else if (arg == QLatin1String("abs")) + abs = true; } int fd; fd = qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0); if (fd >= 0) { ::ioctl(fd, EVIOCGRAB, grab); - return new QEvdevMouseHandler(device, fd, compression, jitterLimit); + return new QEvdevMouseHandler(device, fd, abs, compression, jitterLimit); } else { qWarning("Cannot open mouse input device '%s': %s", qPrintable(device), strerror(errno)); return 0; } } -QEvdevMouseHandler::QEvdevMouseHandler(const QString &device, int fd, bool compression, int jitterLimit) +QEvdevMouseHandler::QEvdevMouseHandler(const QString &device, int fd, bool abs, bool compression, int jitterLimit) : m_device(device), m_fd(fd), m_notify(0), m_x(0), m_y(0), m_prevx(0), m_prevy(0), - m_compression(compression), m_buttons(0), m_prevInvalid(true) + m_abs(abs), m_compression(compression), m_buttons(0), m_prevInvalid(true) { setObjectName(QLatin1String("Evdev Mouse Handler")); m_jitterLimitSquared = jitterLimit * jitterLimit; + // Some touch screens present as mice with absolute coordinates. + // These can not be differentiated from touchpads, so supplying abs to QT_QPA_EVDEV_MOUSE_PARAMETERS + // will force qevdevmousehandler to treat the coordinates as absolute, scaled to the hardware maximums. + // Turning this on will not affect mice as these do not report in absolute coordinates + // but will make touchpads act like touch screens + if (m_abs) + m_abs = getHardwareMaximum(); + // socket notifier for events on the mouse device QSocketNotifier *notifier; notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); @@ -113,16 +126,66 @@ QEvdevMouseHandler::~QEvdevMouseHandler() qt_safe_close(m_fd); } +// Ask touch screen hardware for information on coordinate maximums +// If any ioctls fail, revert to non abs mode +bool QEvdevMouseHandler::getHardwareMaximum() +{ + unsigned char absFeatures[(ABS_MAX / 8) + 1]; + memset(absFeatures, '\0', sizeof (absFeatures)); + + // test if ABS_X, ABS_Y are available + if (ioctl(m_fd, EVIOCGBIT(EV_ABS, sizeof (absFeatures)), absFeatures) == -1) + return false; + + if ((!TEST_BIT(absFeatures, ABS_X)) || (!TEST_BIT(absFeatures, ABS_Y))) + return false; + + // ask hardware for minimum and maximum values + struct input_absinfo absInfo; + if (ioctl(m_fd, EVIOCGABS(ABS_X), &absInfo) == -1) + return false; + + m_hardwareWidth = absInfo.maximum - absInfo.minimum; + + if (ioctl(m_fd, EVIOCGABS(ABS_Y), &absInfo) == -1) + return false; + + m_hardwareHeight = absInfo.maximum - absInfo.minimum; + + QRect g = QGuiApplication::primaryScreen()->virtualGeometry(); + m_hardwareScalerX = static_cast<qreal>(m_hardwareWidth) / (g.right() - g.left()); + m_hardwareScalerY = static_cast<qreal>(m_hardwareHeight) / (g.bottom() - g.top()); + +#ifdef QT_QPA_MOUSE_HANDLER_DEBUG + qDebug() << "Absolute pointing device"; + qDebug() << "hardware max x" << m_hardwareWidth; + qDebug() << "hardware max y" << m_hardwareHeight; + qDebug() << "hardware scalers x" << m_hardwareScalerX << "y" << m_hardwareScalerY; +#endif + + return true; +} + void QEvdevMouseHandler::sendMouseEvent() { - int x = m_x - m_prevx; - int y = m_y - m_prevy; + int x; + int y; + + if (!m_abs) { + x = m_x - m_prevx; + y = m_y - m_prevy; + } + else { + x = m_x / m_hardwareScalerX; + y = m_y / m_hardwareScalerY; + } + if (m_prevInvalid) { x = y = 0; m_prevInvalid = false; } - emit handleMouseEvent(x, y, m_buttons); + emit handleMouseEvent(x, y, m_abs, m_buttons); m_prevx = m_x; m_prevy = m_y; diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h b/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h index d419a1913e..027d2862b0 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h @@ -57,26 +57,32 @@ public: ~QEvdevMouseHandler(); signals: - void handleMouseEvent(int x, int y, Qt::MouseButtons buttons); + void handleMouseEvent(int x, int y, bool abs, Qt::MouseButtons buttons); void handleWheelEvent(int delta, Qt::Orientation orientation); private slots: void readMouseData(); private: - QEvdevMouseHandler(const QString &device, int fd, bool compression, int jitterLimit); + QEvdevMouseHandler(const QString &device, int fd, bool abs, bool compression, int jitterLimit); void sendMouseEvent(); + bool getHardwareMaximum(); QString m_device; int m_fd; QSocketNotifier *m_notify; int m_x, m_y; int m_prevx, m_prevy; + bool m_abs; bool m_compression; Qt::MouseButtons m_buttons; int m_jitterLimitSquared; bool m_prevInvalid; + int m_hardwareWidth; + int m_hardwareHeight; + qreal m_hardwareScalerY; + qreal m_hardwareScalerX; }; QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp index 6c430091c1..87f3a4c9a0 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp @@ -111,11 +111,16 @@ QEvdevMouseManager::~QEvdevMouseManager() m_mice.clear(); } -void QEvdevMouseManager::handleMouseEvent(int x, int y, Qt::MouseButtons buttons) +void QEvdevMouseManager::handleMouseEvent(int x, int y, bool abs, Qt::MouseButtons buttons) { // update current absolute coordinates - m_x += x; - m_y += y; + if (!abs) { + m_x += x; + m_y += y; + } else { + m_x = x; + m_y = y; + } // clamp to screen geometry QRect g = QGuiApplication::primaryScreen()->virtualGeometry(); @@ -130,7 +135,9 @@ void QEvdevMouseManager::handleMouseEvent(int x, int y, Qt::MouseButtons buttons m_y = g.bottom() - m_yoffset; QPoint pos(m_x + m_xoffset, m_y + m_yoffset); - QWindowSystemInterface::handleMouseEvent(0, pos, pos, buttons); + // Cannot track the keyboard modifiers ourselves here. Instead, report the + // modifiers from the last key event that has been seen by QGuiApplication. + QWindowSystemInterface::handleMouseEvent(0, pos, pos, buttons, QGuiApplication::keyboardModifiers()); #ifdef QT_QPA_MOUSEMANAGER_DEBUG qDebug("mouse event %d %d %d", pos.x(), pos.y(), int(buttons)); @@ -140,7 +147,7 @@ void QEvdevMouseManager::handleMouseEvent(int x, int y, Qt::MouseButtons buttons void QEvdevMouseManager::handleWheelEvent(int delta, Qt::Orientation orientation) { QPoint pos(m_x + m_xoffset, m_y + m_yoffset); - QWindowSystemInterface::handleWheelEvent(0, pos, pos, delta, orientation); + QWindowSystemInterface::handleWheelEvent(0, pos, pos, delta, orientation, QGuiApplication::keyboardModifiers()); #ifdef QT_QPA_MOUSEMANAGER_DEBUG qDebug("mouse wheel event %dx%d %d %d", pos.x(), pos.y(), delta, int(orientation)); @@ -156,7 +163,7 @@ void QEvdevMouseManager::addMouse(const QString &deviceNode) QEvdevMouseHandler *handler; handler = QEvdevMouseHandler::create(deviceNode, m_spec); if (handler) { - connect(handler, SIGNAL(handleMouseEvent(int,int,Qt::MouseButtons)), this, SLOT(handleMouseEvent(int,int,Qt::MouseButtons))); + connect(handler, SIGNAL(handleMouseEvent(int,int,bool,Qt::MouseButtons)), this, SLOT(handleMouseEvent(int,int,bool,Qt::MouseButtons))); connect(handler, SIGNAL(handleWheelEvent(int,Qt::Orientation)), this, SLOT(handleWheelEvent(int,Qt::Orientation))); m_mice.insert(deviceNode, handler); } else { diff --git a/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h b/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h index d52a16ea75..5280b5efbd 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h +++ b/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h @@ -62,7 +62,7 @@ public: QDeviceDiscovery *deviceDiscovery() { return m_deviceDiscovery; } public slots: - void handleMouseEvent(int x, int y, Qt::MouseButtons buttons); + void handleMouseEvent(int x, int y, bool abs, Qt::MouseButtons buttons); void handleWheelEvent(int delta, Qt::Orientation orientation); private slots: diff --git a/src/platformsupport/input/evdevtouch/qevdevtouch.cpp b/src/platformsupport/input/evdevtouch/qevdevtouch.cpp index 563edf4fd7..6ed4abaeee 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouch.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouch.cpp @@ -184,6 +184,8 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &specification, QString dev; int rotationAngle = 0; + bool invertx = false; + bool inverty = false; for (int i = 0; i < args.count(); ++i) { if (args.at(i).startsWith(QLatin1String("/dev/")) && dev.isEmpty()) { dev = args.at(i); @@ -201,6 +203,10 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &specification, break; } } + } else if (args.at(i) == QLatin1String("invertx")) { + invertx = true; + } else if (args.at(i) == QLatin1String("inverty")) { + inverty = true; } } @@ -326,6 +332,12 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &specification, if (rotationAngle) d->m_rotate = QTransform::fromTranslate(0.5, 0.5).rotate(rotationAngle).translate(-0.5, -0.5); + if (invertx) + d->m_rotate *= QTransform::fromTranslate(0.5, 0.5).scale(-1.0, 1.0).translate(-0.5, -0.5); + + if (inverty) + d->m_rotate *= QTransform::fromTranslate(0.5, 0.5).scale(1.0, -1.0).translate(-0.5, -0.5); + d->registerDevice(); } diff --git a/src/platformsupport/linuxaccessibility/application.cpp b/src/platformsupport/linuxaccessibility/application.cpp index ae52ab3b57..2b932a816d 100644 --- a/src/platformsupport/linuxaccessibility/application.cpp +++ b/src/platformsupport/linuxaccessibility/application.cpp @@ -47,6 +47,7 @@ #include <qdebug.h> #include "deviceeventcontroller_adaptor.h" +#include "atspi/atspi-constants.h" //#define KEYBOARD_DEBUG @@ -62,7 +63,7 @@ QT_BEGIN_NAMESPACE */ QSpiApplicationAdaptor::QSpiApplicationAdaptor(const QDBusConnection &connection, QObject *parent) - : QObject(parent), dbusConnection(connection) + : QObject(parent), dbusConnection(connection), inCapsLock(false) { } @@ -107,13 +108,14 @@ bool QSpiApplicationAdaptor::eventFilter(QObject *target, QEvent *event) de.id = keyEvent->nativeVirtualKey(); de.hardwareCode = keyEvent->nativeScanCode(); - de.modifiers = keyEvent->nativeModifiers(); de.timestamp = QDateTime::currentMSecsSinceEpoch(); if (keyEvent->key() == Qt::Key_Tab) de.text = QStringLiteral("Tab"); else if (keyEvent->key() == Qt::Key_Backtab) de.text = QStringLiteral("Backtab"); + else if (keyEvent->key() == Qt::Key_Control) + de.text = QStringLiteral("Control_L"); else if (keyEvent->key() == Qt::Key_Left) de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Left") : QStringLiteral("Left"); else if (keyEvent->key() == Qt::Key_Right) @@ -142,9 +144,13 @@ bool QSpiApplicationAdaptor::eventFilter(QObject *target, QEvent *event) de.text = QStringLiteral("Escape"); else if (keyEvent->key() == Qt::Key_Space) de.text = QStringLiteral("space"); - else if (keyEvent->key() == Qt::Key_CapsLock) + else if (keyEvent->key() == Qt::Key_CapsLock) { de.text = QStringLiteral("Caps_Lock"); - else if (keyEvent->key() == Qt::Key_NumLock) + if (event->type() == QEvent::KeyPress) + inCapsLock = true; + else + inCapsLock = false; + } else if (keyEvent->key() == Qt::Key_NumLock) de.text = QStringLiteral("Num_Lock"); else if (keyEvent->key() == Qt::Key_Insert) de.text = QStringLiteral("Insert"); @@ -155,18 +161,28 @@ bool QSpiApplicationAdaptor::eventFilter(QObject *target, QEvent *event) // Long term the spec will hopefully change to just use keycodes. de.isText = !de.text.isEmpty(); + de.modifiers = 0; + if (!inCapsLock && keyEvent->modifiers() & Qt::ShiftModifier) + de.modifiers |= 1 << ATSPI_MODIFIER_SHIFT; + if (inCapsLock && (keyEvent->key() != Qt::Key_CapsLock)) + de.modifiers |= 1 << ATSPI_MODIFIER_SHIFTLOCK; + if ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->key() != Qt::Key_Control)) + de.modifiers |= 1 << ATSPI_MODIFIER_CONTROL; + if ((keyEvent->modifiers() & Qt::AltModifier) && (keyEvent->key() != Qt::Key_Alt)) + de.modifiers |= 1 << ATSPI_MODIFIER_ALT; + #ifdef KEYBOARD_DEBUG - qDebug() << QStringLiteral("Key event text: ") << event->type() << de.isText << QStringLiteral(" ") << de.text - << QStringLiteral(" hardware code: ") << de.hardwareCode - << QStringLiteral(" native sc: ") << keyEvent->nativeScanCode() - << QStringLiteral(" native mod: ") << keyEvent->nativeModifiers() - << QStringLiteral("native virt: ") << keyEvent->nativeVirtualKey(); + qDebug() << QStringLiteral("Key event text:") << event->type() << de.text + << QStringLiteral("native virtual key:") << de.id + << QStringLiteral("hardware code/scancode:") << de.hardwareCode + << QStringLiteral("modifiers:") << de.modifiers + << QStringLiteral("text:") << de.text; #endif QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.a11y.atspi.Registry"), QStringLiteral("/org/a11y/atspi/registry/deviceeventcontroller"), QStringLiteral("org.a11y.atspi.DeviceEventController"), QStringLiteral("NotifyListenersSync")); - m.setArguments(QVariantList() <<QVariant::fromValue(de)); + m.setArguments(QVariantList() << QVariant::fromValue(de)); // FIXME: this is critical, the timeout should probably be pretty low to allow normal processing int timeout = 100; @@ -175,9 +191,6 @@ bool QSpiApplicationAdaptor::eventFilter(QObject *target, QEvent *event) if (sent) { //queue the event and send it after callback keyEvents.enqueue(QPair<QPointer<QObject>, QKeyEvent*> (QPointer<QObject>(target), copyKeyEvent(keyEvent))); -#ifdef KEYBOARD_DEBUG - qDebug() << QStringLiteral("Sent key: ") << de.text; -#endif return true; } } diff --git a/src/platformsupport/linuxaccessibility/application_p.h b/src/platformsupport/linuxaccessibility/application_p.h index e8684ab2b5..4cdce4de9e 100644 --- a/src/platformsupport/linuxaccessibility/application_p.h +++ b/src/platformsupport/linuxaccessibility/application_p.h @@ -78,6 +78,7 @@ private: QQueue<QPair<QPointer<QObject>, QKeyEvent*> > keyEvents; QDBusConnection dbusConnection; + bool inCapsLock; }; QT_END_NAMESPACE diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp index 0fa1d96242..60972af70d 100644 --- a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp +++ b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp @@ -1078,16 +1078,14 @@ void AtSpiAdaptor::notify(QAccessibleEvent *event) QAccessibleInterface * iface = event->accessibleInterface(); if (!iface || !(iface->role() == QAccessible::Window && (sendWindow || sendWindow_activate))) return; + int isActive = iface->state().active; QString windowTitle = iface->text(QAccessible::Name); QDBusVariant data; data.setVariant(windowTitle); QVariantList args = packDBusSignalArguments(QString(), 0, 0, QVariant::fromValue(data)); - - QString status = iface->state().active ? QLatin1String("Activate") : QLatin1String("Deactivate"); + QString status = isActive ? QLatin1String("Activate") : QLatin1String("Deactivate"); QString path = pathForInterface(iface); sendDBusSignal(path, QLatin1String(ATSPI_DBUS_INTERFACE_EVENT_WINDOW), status, args); - - int isActive = iface->state().active; notifyStateChange(iface, QLatin1String("active"), isActive); } else if (stateChange.disabled) { QAccessibleInterface *iface = event->accessibleInterface(); @@ -1952,17 +1950,17 @@ QVariantList AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface, in return list; } -QRect AtSpiAdaptor::getCharacterExtents(QAccessibleInterface *interface, int offset, uint coordType) const +QList<QVariant> AtSpiAdaptor::getCharacterExtents(QAccessibleInterface *interface, int offset, uint coordType) const { QRect rect = interface->textInterface()->characterRect(offset); if (coordType == ATSPI_COORD_TYPE_WINDOW) rect = translateRectToWindowCoordinates(interface, rect); - return rect; + return QList<QVariant>() << rect.x() << rect.y() << rect.width() << rect.height(); } -QRect AtSpiAdaptor::getRangeExtents(QAccessibleInterface *interface, +QList<QVariant> AtSpiAdaptor::getRangeExtents(QAccessibleInterface *interface, int startOffset, int endOffset, uint coordType) const { if (endOffset == -1) @@ -1970,7 +1968,7 @@ QRect AtSpiAdaptor::getRangeExtents(QAccessibleInterface *interface, QAccessibleTextInterface *textInterface = interface->textInterface(); if (endOffset <= startOffset || !textInterface) - return QRect(); + return QList<QVariant>() << -1 << -1 << 0 << 0; QRect rect = textInterface->characterRect(startOffset); for (int i=startOffset + 1; i <= endOffset; i++) @@ -1980,7 +1978,7 @@ QRect AtSpiAdaptor::getRangeExtents(QAccessibleInterface *interface, if (coordType == ATSPI_COORD_TYPE_WINDOW) rect = translateRectToWindowCoordinates(interface, rect); - return rect; + return QList<QVariant>() << rect.x() << rect.y() << rect.width() << rect.height(); } QRect AtSpiAdaptor::translateRectToWindowCoordinates(QAccessibleInterface *interface, const QRect &rect) diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor_p.h b/src/platformsupport/linuxaccessibility/atspiadaptor_p.h index 8e905e4cca..2116a4e6a9 100644 --- a/src/platformsupport/linuxaccessibility/atspiadaptor_p.h +++ b/src/platformsupport/linuxaccessibility/atspiadaptor_p.h @@ -125,8 +125,8 @@ private: // text helper functions QVariantList getAttributes(QAccessibleInterface *, int offset, bool includeDefaults) const; QVariantList getAttributeValue(QAccessibleInterface *, int offset, const QString &attributeName) const; - QRect getCharacterExtents(QAccessibleInterface *, int offset, uint coordType) const; - QRect getRangeExtents(QAccessibleInterface *, int startOffset, int endOffset, uint coordType) const; + QList<QVariant> getCharacterExtents(QAccessibleInterface *, int offset, uint coordType) const; + QList<QVariant> getRangeExtents(QAccessibleInterface *, int startOffset, int endOffset, uint coordType) const; QAccessible::TextBoundaryType qAccessibleBoundaryType(int atspiTextBoundaryType) const; static bool inheritsQAction(QObject *object); diff --git a/src/platformsupport/linuxaccessibility/dbusconnection.cpp b/src/platformsupport/linuxaccessibility/dbusconnection.cpp index 18915f8e08..7bdd586a1f 100644 --- a/src/platformsupport/linuxaccessibility/dbusconnection.cpp +++ b/src/platformsupport/linuxaccessibility/dbusconnection.cpp @@ -84,8 +84,14 @@ void DBusConnection::serviceRegistered() QDBusConnection c = QDBusConnection::sessionBus(); OrgA11yStatusInterface *a11yStatus = new OrgA11yStatusInterface(A11Y_SERVICE, A11Y_PATH, c, this); + //The variable was introduced because on some embedded platforms there are custom accessibility + //clients which don't set Status.ScreenReaderEnabled to true. The variable is also useful for + //debugging. + static const bool a11yAlwaysOn = !qEnvironmentVariableIsSet("QT_LINUX_ACCESSIBILITY_ALWAYS_ON"); + // a11yStatus->isEnabled() returns always true (since Gnome 3.6) - bool enabled = a11yStatus->screenReaderEnabled(); + bool enabled = a11yAlwaysOn || a11yStatus->screenReaderEnabled(); + if (enabled != m_enabled) { m_enabled = enabled; if (m_a11yConnection.isConnected()) { diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 5b4d2b1fb3..32ce2e3887 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -18,6 +18,7 @@ include(input/input.pri) include(devicediscovery/devicediscovery.pri) include(services/services.pri) include(themes/themes.pri) +include(accessibility/accessibility.pri) include(linuxaccessibility/linuxaccessibility.pri) include(clipboard/clipboard.pri) diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp index 4a1d67f4b5..bf73d30871 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp @@ -51,6 +51,7 @@ #include <QtCore/QFileInfo> #include <QtCore/QFile> #include <QtCore/QDebug> +#include <QtCore/QHash> #include <QtCore/QSettings> #include <QtCore/QVariant> #include <QtCore/QStringList> @@ -171,26 +172,26 @@ QVariant QGenericUnixTheme::themeHint(ThemeHint hint) const class QKdeThemePrivate : public QPlatformThemePrivate { public: - QKdeThemePrivate(const QString &kdeHome, int kdeVersion) - : kdeHome(kdeHome) + QKdeThemePrivate(const QStringList &kdeDirs, int kdeVersion) + : kdeDirs(kdeDirs) , kdeVersion(kdeVersion) , toolButtonStyle(Qt::ToolButtonTextBesideIcon) , toolBarIconSize(0) , singleClick(true) { } - QString globalSettingsFile() const + static QString kdeGlobals(const QString &kdeDir) { - return kdeHome + QStringLiteral("/share/config/kdeglobals"); + return kdeDir + QStringLiteral("/share/config/kdeglobals"); } void refresh(); - static void readKdeSystemPalette(const QSettings &kdeSettings, QPalette *pal); - static QFont *readKdeFontSetting(const QSettings &settings, const QString &key); - static QStringList kdeIconThemeSearchPaths(const QString &kdeHome); + static QVariant readKdeSetting(const QString &key, const QStringList &kdeDirs, QHash<QString, QSettings*> &kdeSettings); + static void readKdeSystemPalette(const QStringList &kdeDirs, QHash<QString, QSettings*> &kdeSettings, QPalette *pal); + static QFont *kdeFont(const QVariant &fontValue); + static QStringList kdeIconThemeSearchPaths(const QStringList &kdeDirs); - - const QString kdeHome; + const QStringList kdeDirs; const int kdeVersion; ResourceHelper resources; @@ -212,36 +213,33 @@ void QKdeThemePrivate::refresh() styleNames << QStringLiteral("Oxygen") << QStringLiteral("fusion") << QStringLiteral("windows"); iconFallbackThemeName = iconThemeName = QStringLiteral("oxygen"); - // Read settings file. - const QString settingsFile = globalSettingsFile(); - if (!QFileInfo(settingsFile).isReadable()) - return; - - const QSettings kdeSettings(settingsFile, QSettings::IniFormat); + QHash<QString, QSettings*> kdeSettings; QPalette systemPalette = QPalette(); - readKdeSystemPalette(kdeSettings, &systemPalette); + readKdeSystemPalette(kdeDirs, kdeSettings, &systemPalette); resources.palettes[QPlatformTheme::SystemPalette] = new QPalette(systemPalette); //## TODO tooltip color - const QVariant styleValue = kdeSettings.value(QStringLiteral("widgetStyle")); + const QVariant styleValue = readKdeSetting(QStringLiteral("widgetStyle"), kdeDirs, kdeSettings); if (styleValue.isValid()) { const QString style = styleValue.toString(); if (style != styleNames.front()) styleNames.push_front(style); } - singleClick = kdeSettings.value(QStringLiteral("KDE/SingleClick"), true).toBool(); + const QVariant singleClickValue = readKdeSetting(QStringLiteral("KDE/SingleClick"), kdeDirs, kdeSettings); + if (singleClickValue.isValid()) + singleClick = singleClickValue.toBool(); - const QVariant themeValue = kdeSettings.value(QStringLiteral("Icons/Theme")); + const QVariant themeValue = readKdeSetting(QStringLiteral("Icons/Theme"), kdeDirs, kdeSettings); if (themeValue.isValid()) iconThemeName = themeValue.toString(); - const QVariant toolBarIconSizeValue = kdeSettings.value(QStringLiteral("ToolbarIcons/Size")); + const QVariant toolBarIconSizeValue = readKdeSetting(QStringLiteral("ToolbarIcons/Size"), kdeDirs, kdeSettings); if (toolBarIconSizeValue.isValid()) toolBarIconSize = toolBarIconSizeValue.toInt(); - const QVariant toolbarStyleValue = kdeSettings.value(QStringLiteral("ToolButtonStyle")); + const QVariant toolbarStyleValue = readKdeSetting(QStringLiteral("Toolbar style/ToolButtonStyle"), kdeDirs, kdeSettings); if (toolbarStyleValue.isValid()) { const QString toolBarStyle = toolbarStyleValue.toString(); if (toolBarStyle == QStringLiteral("TextBesideIcon")) @@ -253,26 +251,46 @@ void QKdeThemePrivate::refresh() } // Read system font, ignore 'smallestReadableFont' - if (QFont *systemFont = readKdeFontSetting(kdeSettings, QStringLiteral("font"))) + if (QFont *systemFont = kdeFont(readKdeSetting(QStringLiteral("font"), kdeDirs, kdeSettings))) resources.fonts[QPlatformTheme::SystemFont] = systemFont; else resources.fonts[QPlatformTheme::SystemFont] = new QFont(QLatin1String(defaultSystemFontNameC), defaultSystemFontSize); - if (QFont *fixedFont = readKdeFontSetting(kdeSettings, QStringLiteral("fixed"))) { + if (QFont *fixedFont = kdeFont(readKdeSetting(QStringLiteral("fixed"), kdeDirs, kdeSettings))) { resources.fonts[QPlatformTheme::FixedFont] = fixedFont; } else { fixedFont = new QFont(QLatin1String(defaultSystemFontNameC), defaultSystemFontSize); fixedFont->setStyleHint(QFont::TypeWriter); resources.fonts[QPlatformTheme::FixedFont] = fixedFont; } + + qDeleteAll(kdeSettings); +} + +QVariant QKdeThemePrivate::readKdeSetting(const QString &key, const QStringList &kdeDirs, QHash<QString, QSettings*> &kdeSettings) +{ + foreach (const QString &kdeDir, kdeDirs) { + QSettings *settings = kdeSettings.value(kdeDir); + if (!settings) { + const QString kdeGlobalsPath = kdeGlobals(kdeDir); + if (QFileInfo(kdeGlobalsPath).isReadable()) { + settings = new QSettings(kdeGlobalsPath, QSettings::IniFormat); + kdeSettings.insert(kdeDir, settings); + } + } + if (settings) { + const QVariant value = settings->value(key); + if (value.isValid()) + return value; + } + } + return QVariant(); } // Reads the color from the KDE configuration, and store it in the // palette with the given color role if found. -static inline bool kdeColor(QPalette *pal, QPalette::ColorRole role, - const QSettings &kdeSettings, const QString &key) +static inline bool kdeColor(QPalette *pal, QPalette::ColorRole role, const QVariant &value) { - const QVariant value = kdeSettings.value(key); if (!value.isValid()) return false; const QStringList values = value.toStringList(); @@ -282,9 +300,9 @@ static inline bool kdeColor(QPalette *pal, QPalette::ColorRole role, return true; } -void QKdeThemePrivate::readKdeSystemPalette(const QSettings &kdeSettings, QPalette *pal) +void QKdeThemePrivate::readKdeSystemPalette(const QStringList &kdeDirs, QHash<QString, QSettings*> &kdeSettings, QPalette *pal) { - if (!kdeSettings.contains(QStringLiteral("Colors:Button/BackgroundNormal"))) { + if (!kdeColor(pal, QPalette::Button, readKdeSetting(QStringLiteral("Colors:Button/BackgroundNormal"), kdeDirs, kdeSettings))) { // kcolorscheme.cpp: SetDefaultColors const QColor defaultWindowBackground(214, 210, 208); const QColor defaultButtonBackground(223, 220, 217); @@ -292,19 +310,18 @@ void QKdeThemePrivate::readKdeSystemPalette(const QSettings &kdeSettings, QPalet return; } - kdeColor(pal, QPalette::Button, kdeSettings, QStringLiteral("Colors:Button/BackgroundNormal")); - kdeColor(pal, QPalette::Window, kdeSettings, QStringLiteral("Colors:Window/BackgroundNormal")); - kdeColor(pal, QPalette::Text, kdeSettings, QStringLiteral("Colors:View/ForegroundNormal")); - kdeColor(pal, QPalette::WindowText, kdeSettings, QStringLiteral("Colors:Window/ForegroundNormal")); - kdeColor(pal, QPalette::Base, kdeSettings, QStringLiteral("Colors:View/BackgroundNormal")); - kdeColor(pal, QPalette::Highlight, kdeSettings, QStringLiteral("Colors:Selection/BackgroundNormal")); - kdeColor(pal, QPalette::HighlightedText, kdeSettings, QStringLiteral("Colors:Selection/ForegroundNormal")); - kdeColor(pal, QPalette::AlternateBase, kdeSettings, QStringLiteral("Colors:View/BackgroundAlternate")); - kdeColor(pal, QPalette::ButtonText, kdeSettings, QStringLiteral("Colors:Button/ForegroundNormal")); - kdeColor(pal, QPalette::Link, kdeSettings, QStringLiteral("Colors:View/ForegroundLink")); - kdeColor(pal, QPalette::LinkVisited, kdeSettings, QStringLiteral("Colors:View/ForegroundVisited")); - kdeColor(pal, QPalette::ToolTipBase, kdeSettings, QStringLiteral("Colors:Tooltip/BackgroundNormal")); - kdeColor(pal, QPalette::ToolTipText, kdeSettings, QStringLiteral("Colors:Tooltip/ForegroundNormal")); + kdeColor(pal, QPalette::Window, readKdeSetting(QStringLiteral("Colors:Window/BackgroundNormal"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::Text, readKdeSetting(QStringLiteral("Colors:View/ForegroundNormal"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::WindowText, readKdeSetting(QStringLiteral("Colors:Window/ForegroundNormal"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::Base, readKdeSetting(QStringLiteral("Colors:View/BackgroundNormal"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::Highlight, readKdeSetting(QStringLiteral("Colors:Selection/BackgroundNormal"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::HighlightedText, readKdeSetting(QStringLiteral("Colors:Selection/ForegroundNormal"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::AlternateBase, readKdeSetting(QStringLiteral("Colors:View/BackgroundAlternate"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::ButtonText, readKdeSetting(QStringLiteral("Colors:Button/ForegroundNormal"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::Link, readKdeSetting(QStringLiteral("Colors:View/ForegroundLink"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::LinkVisited, readKdeSetting(QStringLiteral("Colors:View/ForegroundVisited"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::ToolTipBase, readKdeSetting(QStringLiteral("Colors:Tooltip/BackgroundNormal"), kdeDirs, kdeSettings)); + kdeColor(pal, QPalette::ToolTipText, readKdeSetting(QStringLiteral("Colors:Tooltip/ForegroundNormal"), kdeDirs, kdeSettings)); // The above code sets _all_ color roles to "normal" colors. In KDE, the disabled // color roles are calculated by applying various effects described in kdeglobals. @@ -347,15 +364,14 @@ void QKdeThemePrivate::readKdeSystemPalette(const QSettings &kdeSettings, QPalet const char *QKdeTheme::name = "kde"; -QKdeTheme::QKdeTheme(const QString &kdeHome, int kdeVersion) - : QPlatformTheme(new QKdeThemePrivate(kdeHome,kdeVersion)) +QKdeTheme::QKdeTheme(const QStringList& kdeDirs, int kdeVersion) + : QPlatformTheme(new QKdeThemePrivate(kdeDirs,kdeVersion)) { d_func()->refresh(); } -QFont *QKdeThemePrivate::readKdeFontSetting(const QSettings &settings, const QString &key) +QFont *QKdeThemePrivate::kdeFont(const QVariant &fontValue) { - const QVariant fontValue = settings.value(key); if (fontValue.isValid()) { // Read font value: Might be a QStringList as KDE stores fonts without quotes. // Also retrieve the family for the constructor since we cannot use the @@ -382,16 +398,11 @@ QFont *QKdeThemePrivate::readKdeFontSetting(const QSettings &settings, const QSt } -QStringList QKdeThemePrivate::kdeIconThemeSearchPaths(const QString &kdeHome) +QStringList QKdeThemePrivate::kdeIconThemeSearchPaths(const QStringList &kdeDirs) { - QStringList candidates = QStringList(kdeHome); - const QString kdeDirs = QFile::decodeName(qgetenv("KDEDIRS")); - if (!kdeDirs.isEmpty()) - candidates.append(kdeDirs.split(QLatin1Char(':'))); - QStringList paths = QGenericUnixTheme::xdgIconThemePaths(); const QString iconPath = QStringLiteral("/share/icons"); - foreach (const QString &candidate, candidates) { + foreach (const QString &candidate, kdeDirs) { const QFileInfo fi(candidate + iconPath); if (fi.isDir()) paths.append(fi.absoluteFilePath()); @@ -418,7 +429,7 @@ QVariant QKdeTheme::themeHint(QPlatformTheme::ThemeHint hint) const case QPlatformTheme::SystemIconFallbackThemeName: return QVariant(d->iconFallbackThemeName); case QPlatformTheme::IconThemeSearchPaths: - return QVariant(d->kdeIconThemeSearchPaths(d->kdeHome)); + return QVariant(d->kdeIconThemeSearchPaths(d->kdeDirs)); case QPlatformTheme::StyleNames: return QVariant(d->styleNames); case QPlatformTheme::KeyboardScheme: @@ -445,26 +456,52 @@ const QFont *QKdeTheme::font(Font type) const QPlatformTheme *QKdeTheme::createKdeTheme() { - // Check for version >= 4 and determine home folder from environment, - // defaulting to ~/.kde<version>, ~/.kde const QByteArray kdeVersionBA = qgetenv("KDE_SESSION_VERSION"); const int kdeVersion = kdeVersionBA.toInt(); if (kdeVersion < 4) return 0; - const QString kdeHomePathVar = QString::fromLocal8Bit(qgetenv("KDEHOME")); + + // Determine KDE prefixes in the following priority order: + // - KDEHOME and KDEDIRS environment variables + // - ~/.kde(<version>) + // - read prefixes from /etc/kde<version>rc + // - fallback to /etc/kde<version> + + QStringList kdeDirs; + const QString kdeHomePathVar = QFile::decodeName(qgetenv("KDEHOME")); if (!kdeHomePathVar.isEmpty()) - return new QKdeTheme(kdeHomePathVar, kdeVersion); + kdeDirs += kdeHomePathVar; + + const QString kdeDirsVar = QFile::decodeName(qgetenv("KDEDIRS")); + if (!kdeDirsVar.isEmpty()) + kdeDirs += kdeDirsVar.split(QLatin1Char(':'), QString::SkipEmptyParts); + + const QString kdeVersionHomePath = QDir::homePath() + QStringLiteral("/.kde") + QLatin1String(kdeVersionBA); + if (QFileInfo(kdeVersionHomePath).isDir()) + kdeDirs += kdeVersionHomePath; - const QString kdeVersionHomePath = QDir::homePath() + QStringLiteral("/.kde") + QLatin1String(kdeVersionBA); - if (QFileInfo(kdeVersionHomePath).isDir()) - return new QKdeTheme(kdeVersionHomePath, kdeVersion); + const QString kdeHomePath = QDir::homePath() + QStringLiteral("/.kde"); + if (QFileInfo(kdeHomePath).isDir()) + kdeDirs += kdeHomePath; - const QString kdeHomePath = QDir::homePath() + QStringLiteral("/.kde"); - if (QFileInfo(kdeHomePath).isDir()) - return new QKdeTheme(kdeHomePath, kdeVersion); + const QString kdeRcPath = QStringLiteral("/etc/kde") + QLatin1String(kdeVersionBA) + QStringLiteral("rc"); + if (QFileInfo(kdeRcPath).isReadable()) { + QSettings kdeSettings(kdeRcPath, QSettings::IniFormat); + kdeSettings.beginGroup(QStringLiteral("Directories-default")); + kdeDirs += kdeSettings.value(QStringLiteral("prefixes")).toStringList(); + } + + const QString kdeVersionPrefix = QStringLiteral("/etc/kde") + QLatin1String(kdeVersionBA); + if (QFileInfo(kdeVersionPrefix).isDir()) + kdeDirs += kdeVersionPrefix; + + kdeDirs.removeDuplicates(); + if (kdeDirs.isEmpty()) { + qWarning("%s: Unable to determine KDE dirs", Q_FUNC_INFO); + return 0; + } - qWarning("%s: Unable to determine KDEHOME", Q_FUNC_INFO); - return 0; + return new QKdeTheme(kdeDirs, kdeVersion); } #endif // QT_NO_SETTINGS diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h index 36fcdd8dce..d01e6d485c 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h @@ -87,7 +87,7 @@ class QKdeTheme : public QPlatformTheme { Q_DECLARE_PRIVATE(QKdeTheme) public: - QKdeTheme(const QString &kdeHome, int kdeVersion); + QKdeTheme(const QStringList& kdeDirs, int kdeVersion); static QPlatformTheme *createKdeTheme(); virtual QVariant themeHint(ThemeHint hint) const; |