diff options
author | Jørgen Lind <jorgen.lind@nokia.com> | 2011-02-14 12:37:24 (GMT) |
---|---|---|
committer | Jørgen Lind <jorgen.lind@nokia.com> | 2011-02-14 13:39:17 (GMT) |
commit | 98f2392e7278aea52f46b7e20f93dea1831e5704 (patch) | |
tree | ed6b9b74df6b117e476633a4ff734d3b7531858a /src/plugins/platforms/xlib | |
parent | 7be3f2585676cb18821b51427527275fb441fa46 (diff) | |
download | Qt-98f2392e7278aea52f46b7e20f93dea1831e5704.zip Qt-98f2392e7278aea52f46b7e20f93dea1831e5704.tar.gz Qt-98f2392e7278aea52f46b7e20f93dea1831e5704.tar.bz2 |
Lighthouse Moving testlite plugin into xlib
Diffstat (limited to 'src/plugins/platforms/xlib')
24 files changed, 6275 insertions, 0 deletions
diff --git a/src/plugins/platforms/xlib/main.cpp b/src/plugins/platforms/xlib/main.cpp new file mode 100644 index 0000000..131d399 --- /dev/null +++ b/src/plugins/platforms/xlib/main.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/QPlatformIntegrationPlugin> +#include "qtestliteintegration.h" + +QT_BEGIN_NAMESPACE + +class QXlibIntegrationPlugin : public QPlatformIntegrationPlugin +{ +public: + QStringList keys() const; + QPlatformIntegration *create(const QString&, const QStringList&); +}; + +QStringList QXlibIntegrationPlugin::keys() const +{ + QStringList list; + list << "Xlib"; +#ifndef QT_NO_OPENGL + list << "XlibGL"; +#endif + return list; +} + +QPlatformIntegration* QXlibIntegrationPlugin::create(const QString& system, const QStringList& paramList) +{ + Q_UNUSED(paramList); + if (system.toLower() == "xlib") + return new QXlibIntegration; +#ifndef QT_NO_OPENGL + if (system.toLower() == "xlibgl") + return new QXlibIntegration(true); +#endif + + return 0; +} + +Q_EXPORT_PLUGIN2(xlib, QXlibIntegrationPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qglxintegration.cpp b/src/plugins/platforms/xlib/qglxintegration.cpp new file mode 100644 index 0000000..46dfef9 --- /dev/null +++ b/src/plugins/platforms/xlib/qglxintegration.cpp @@ -0,0 +1,376 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +#include <QLibrary> +#include <QGLFormat> + +#include "qtestlitewindow.h" +#include "qtestlitescreen.h" + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <GL/glx.h> + +#include "qglxintegration.h" + +#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) +#include <dlfcn.h> +#endif + +QT_BEGIN_NAMESPACE + +QMutex QGLXContext::m_defaultSharedContextMutex(QMutex::Recursive); + +QVector<int> QGLXContext::buildSpec(const QPlatformWindowFormat &format) +{ + QVector<int> spec(48); + int i = 0; + + spec[i++] = GLX_LEVEL; + spec[i++] = 0; + spec[i++] = GLX_DRAWABLE_TYPE; spec[i++] = GLX_WINDOW_BIT; + + if (format.rgba()) { + spec[i++] = GLX_RENDER_TYPE; spec[i++] = GLX_RGBA_BIT; + spec[i++] = GLX_RED_SIZE; spec[i++] = (format.redBufferSize() == -1) ? 1 : format.redBufferSize(); + spec[i++] = GLX_GREEN_SIZE; spec[i++] = (format.greenBufferSize() == -1) ? 1 : format.greenBufferSize(); + spec[i++] = GLX_BLUE_SIZE; spec[i++] = (format.blueBufferSize() == -1) ? 1 : format.blueBufferSize(); + if (format.alpha()) { + spec[i++] = GLX_ALPHA_SIZE; spec[i++] = (format.alphaBufferSize() == -1) ? 1 : format.alphaBufferSize(); + } + + spec[i++] = GLX_ACCUM_RED_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); + spec[i++] = GLX_ACCUM_GREEN_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); + spec[i++] = GLX_ACCUM_BLUE_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); + + if (format.alpha()) { + spec[i++] = GLX_ACCUM_ALPHA_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); + } + + } else { + spec[i++] = GLX_RENDER_TYPE; spec[i++] = GLX_COLOR_INDEX_BIT; //I'm really not sure if this works.... + spec[i++] = GLX_BUFFER_SIZE; spec[i++] = 8; + } + + spec[i++] = GLX_DOUBLEBUFFER; spec[i++] = format.doubleBuffer() ? True : False; + spec[i++] = GLX_STEREO; spec[i++] = format.stereo() ? True : False; + + if (format.depth()) { + spec[i++] = GLX_DEPTH_SIZE; spec[i++] = (format.depthBufferSize() == -1) ? 1 : format.depthBufferSize(); + } + + if (format.stencil()) { + spec[i++] = GLX_STENCIL_SIZE; spec[i++] = (format.stencilBufferSize() == -1) ? 1 : format.stencilBufferSize(); + } + if (format.sampleBuffers()) { + spec[i++] = GLX_SAMPLE_BUFFERS_ARB; + spec[i++] = 1; + spec[i++] = GLX_SAMPLES_ARB; + spec[i++] = format.samples() == -1 ? 4 : format.samples(); + } + + spec[i++] = XNone; + return spec; +} + +GLXFBConfig QGLXContext::findConfig(const QXlibScreen *screen, const QPlatformWindowFormat &format) +{ + bool reduced = true; + GLXFBConfig chosenConfig = 0; + QPlatformWindowFormat reducedFormat = format; + while (!chosenConfig && reduced) { + QVector<int> spec = buildSpec(reducedFormat); + int confcount = 0; + GLXFBConfig *configs; + configs = glXChooseFBConfig(screen->display(),screen->xScreenNumber(),spec.constData(),&confcount); + if (confcount) + { + for (int i = 0; i < confcount; i++) { + chosenConfig = configs[i]; + // Make sure we try to get an ARGB visual if the format asked for an alpha: + if (reducedFormat.alpha()) { + int alphaSize; + glXGetFBConfigAttrib(screen->display(),configs[i],GLX_ALPHA_SIZE,&alphaSize); + if (alphaSize > 0) + break; + } else { + break; // Just choose the first in the list if there's no alpha requested + } + } + + XFree(configs); + } + reducedFormat = reducePlatformWindowFormat(reducedFormat,&reduced); + } + + if (!chosenConfig) + qWarning("Warning no context created"); + + return chosenConfig; +} + +XVisualInfo *QGLXContext::findVisualInfo(const QXlibScreen *screen, const QPlatformWindowFormat &format) +{ + GLXFBConfig config = QGLXContext::findConfig(screen,format); + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(screen->display(),config); + return visualInfo; +} + +QPlatformWindowFormat QGLXContext::platformWindowFromGLXFBConfig(Display *display, GLXFBConfig config, GLXContext ctx) +{ + QPlatformWindowFormat format; + 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 level = 0; + int rgba = 0; + int stereo = 0; + int accumSizeA = 0; + int accumSizeR = 0; + int accumSizeG = 0; + int accumSizeB = 0; + + XVisualInfo *vi = glXGetVisualFromFBConfig(display,config); + glXGetConfig(display,vi,GLX_RGBA,&rgba); + XFree(vi); + glXGetFBConfigAttrib(display, config, GLX_RED_SIZE, &redSize); + glXGetFBConfigAttrib(display, config, GLX_GREEN_SIZE, &greenSize); + glXGetFBConfigAttrib(display, config, GLX_BLUE_SIZE, &blueSize); + glXGetFBConfigAttrib(display, config, GLX_ALPHA_SIZE, &alphaSize); + glXGetFBConfigAttrib(display, config, GLX_DEPTH_SIZE, &depthSize); + glXGetFBConfigAttrib(display, config, GLX_STENCIL_SIZE, &stencilSize); + glXGetFBConfigAttrib(display, config, GLX_SAMPLES, &sampleBuffers); + glXGetFBConfigAttrib(display, config, GLX_LEVEL, &level); + glXGetFBConfigAttrib(display, config, GLX_STEREO, &stereo); + glXGetFBConfigAttrib(display, config, GLX_ACCUM_ALPHA_SIZE, &accumSizeA); + glXGetFBConfigAttrib(display, config, GLX_ACCUM_RED_SIZE, &accumSizeR); + glXGetFBConfigAttrib(display, config, GLX_ACCUM_GREEN_SIZE, &accumSizeG); + glXGetFBConfigAttrib(display, config, GLX_ACCUM_BLUE_SIZE, &accumSizeB); + + format.setRedBufferSize(redSize); + format.setGreenBufferSize(greenSize); + format.setBlueBufferSize(blueSize); + format.setAlphaBufferSize(alphaSize); + format.setDepthBufferSize(depthSize); + format.setStencilBufferSize(stencilSize); + format.setSampleBuffers(sampleBuffers); + if (format.sampleBuffers()) { + glXGetFBConfigAttrib(display, config, GLX_SAMPLES_ARB, &sampleCount); + format.setSamples(sampleCount); + } + + format.setDirectRendering(glXIsDirect(display, ctx)); + format.setRgba(rgba); + format.setStereo(stereo); + format.setAccumBufferSize(accumSizeB); + + return format; +} + +QPlatformWindowFormat QGLXContext::reducePlatformWindowFormat(const QPlatformWindowFormat &format, bool *reduced) +{ + QPlatformWindowFormat retFormat = format; + *reduced = true; + + if (retFormat.sampleBuffers()) { + retFormat.setSampleBuffers(false); + } else if (retFormat.stereo()) { + retFormat.setStereo(false); + } else if (retFormat.accum()) { + retFormat.setAccum(false); + }else if (retFormat.stencil()) { + retFormat.setStencil(false); + }else if (retFormat.alpha()) { + retFormat.setAlpha(false); + }else if (retFormat.depth()) { + retFormat.setDepth(false); + }else if (retFormat.doubleBuffer()) { + retFormat.setDoubleBuffer(false); + }else{ + *reduced = false; + } + return retFormat; +} + +QGLXContext::QGLXContext(Window window, QXlibScreen *screen, const QPlatformWindowFormat &format) + : QPlatformGLContext() + , m_screen(screen) + , m_drawable((Drawable)window) + , m_context(0) +{ + + const QPlatformGLContext *sharePlatformContext; + if (format.useDefaultSharedContext()) { + if (!QPlatformGLContext::defaultSharedContext()) { + if (m_defaultSharedContextMutex.tryLock()){ + createDefaultSharedContex(screen); + m_defaultSharedContextMutex.unlock(); + } else { + m_defaultSharedContextMutex.lock(); //wait to the the shared context is created + m_defaultSharedContextMutex.unlock(); + } + } + sharePlatformContext = QPlatformGLContext::defaultSharedContext(); + } else { + sharePlatformContext = format.sharedGLContext(); + } + GLXContext shareGlxContext = 0; + if (sharePlatformContext) + shareGlxContext = static_cast<const QGLXContext*>(sharePlatformContext)->glxContext(); + + GLXFBConfig config = findConfig(screen,format); + m_context = glXCreateNewContext(screen->display(),config,GLX_RGBA_TYPE,shareGlxContext,TRUE); + m_windowFormat = QGLXContext::platformWindowFromGLXFBConfig(screen->display(),config,m_context); + +#ifdef MYX11_DEBUG + qDebug() << "QGLXGLContext::create context" << m_context; +#endif +} + +QGLXContext::QGLXContext(QXlibScreen *screen, Drawable drawable, GLXContext context) + : QPlatformGLContext(), m_screen(screen), m_drawable(drawable), m_context(context) +{ + +} + +QGLXContext::~QGLXContext() +{ + if (m_context) { + qDebug("Destroying GLX context 0x%p", m_context); + glXDestroyContext(m_screen->display(), m_context); + } +} + +void QGLXContext::createDefaultSharedContex(QXlibScreen *screen) +{ + int x = 0; + int y = 0; + int w = 3; + int h = 3; + + QPlatformWindowFormat format = QPlatformWindowFormat::defaultFormat(); + GLXContext context; + GLXFBConfig config = findConfig(screen,format); + if (config) { + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(screen->display(),config); + Colormap cmap = XCreateColormap(screen->display(),screen->rootWindow(),visualInfo->visual,AllocNone); + XSetWindowAttributes a; + a.colormap = cmap; + Window sharedWindow = XCreateWindow(screen->display(), screen->rootWindow(),x, y, w, h, + 0, visualInfo->depth, InputOutput, visualInfo->visual, + CWColormap, &a); + + context = glXCreateNewContext(screen->display(),config,GLX_RGBA_TYPE,0,TRUE); + QPlatformGLContext *sharedContext = new QGLXContext(screen,sharedWindow,context); + QPlatformGLContext::setDefaultSharedContext(sharedContext); + } else { + qWarning("Warning no shared context created"); + } +} + +void QGLXContext::makeCurrent() +{ + QPlatformGLContext::makeCurrent(); +#ifdef MYX11_DEBUG + qDebug("QGLXGLContext::makeCurrent(window=0x%x, ctx=0x%x)", m_drawable, m_context); +#endif + glXMakeCurrent(m_screen->display(), m_drawable, m_context); +} + +void QGLXContext::doneCurrent() +{ + QPlatformGLContext::doneCurrent(); + glXMakeCurrent(m_screen->display(), 0, 0); +} + +void QGLXContext::swapBuffers() +{ + glXSwapBuffers(m_screen->display(), m_drawable); +} + +void* QGLXContext::getProcAddress(const QString& procName) +{ + typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *); + static qt_glXGetProcAddressARB glXGetProcAddressARB = 0; + static bool resolved = false; + + if (resolved && !glXGetProcAddressARB) + return 0; + if (!glXGetProcAddressARB) { + QList<QByteArray> glxExt = QByteArray(glXGetClientString(m_screen->display(), GLX_EXTENSIONS)).split(' '); + if (glxExt.contains("GLX_ARB_get_proc_address")) { +#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) + void *handle = dlopen(NULL, RTLD_LAZY); + if (handle) { + glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB"); + dlclose(handle); + } + if (!glXGetProcAddressARB) +#endif + { + extern const QString qt_gl_library_name(); +// QLibrary lib(qt_gl_library_name()); + QLibrary lib(QLatin1String("GL")); + glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB"); + } + } + resolved = true; + } + if (!glXGetProcAddressARB) + return 0; + return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.toLatin1().data())); +} + +QPlatformWindowFormat QGLXContext::platformWindowFormat() const +{ + return m_windowFormat; +} + +QT_END_NAMESPACE + +#endif //!defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) diff --git a/src/plugins/platforms/xlib/qglxintegration.h b/src/plugins/platforms/xlib/qglxintegration.h new file mode 100644 index 0000000..f982708 --- /dev/null +++ b/src/plugins/platforms/xlib/qglxintegration.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q_GLX_CONTEXT_H +#define Q_GLX_CONTEXT_H + +#include "qtestlitewindow.h" + +#include <QtGui/QPlatformGLContext> +#include <QtGui/QPlatformWindowFormat> + +#include <QtCore/QMutex> + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) +#include <GL/glx.h> + +QT_BEGIN_NAMESPACE + +class QGLXContext : public QPlatformGLContext +{ +public: + QGLXContext(Window window, QXlibScreen *xd, const QPlatformWindowFormat &format); + ~QGLXContext(); + + virtual void makeCurrent(); + virtual void doneCurrent(); + virtual void swapBuffers(); + virtual void* getProcAddress(const QString& procName); + + GLXContext glxContext() const {return m_context;} + + QPlatformWindowFormat platformWindowFormat() const; + + static XVisualInfo *findVisualInfo(const QXlibScreen *xd, const QPlatformWindowFormat &format); +private: + static GLXFBConfig findConfig(const QXlibScreen *xd,const QPlatformWindowFormat &format); + static QVector<int> buildSpec(const QPlatformWindowFormat &format); + static QPlatformWindowFormat platformWindowFromGLXFBConfig(Display *display, GLXFBConfig config, GLXContext context); + static QPlatformWindowFormat reducePlatformWindowFormat(const QPlatformWindowFormat &format, bool *reduced); + + + QXlibScreen *m_screen; + Drawable m_drawable; + GLXContext m_context; + QPlatformWindowFormat m_windowFormat; + + QGLXContext (QXlibScreen *screen, Drawable drawable, GLXContext context); + static QMutex m_defaultSharedContextMutex; + static void createDefaultSharedContex(QXlibScreen *xd); +}; + +QT_END_NAMESPACE + +#endif //!defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) + +#endif diff --git a/src/plugins/platforms/xlib/qtestliteclipboard.cpp b/src/plugins/platforms/xlib/qtestliteclipboard.cpp new file mode 100644 index 0000000..1264b5a --- /dev/null +++ b/src/plugins/platforms/xlib/qtestliteclipboard.cpp @@ -0,0 +1,676 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestliteclipboard.h" + +#include "qtestlitescreen.h" +#include "qtestlitemime.h" + +#include <private/qapplication_p.h> + +#include <QtCore/QDebug> + +class QXlibClipboardMime : public QXlibMime +{ + Q_OBJECT +public: + QXlibClipboardMime(QClipboard::Mode mode, QXlibClipboard *clipboard) + : QXlibMime() + , m_clipboard(clipboard) + { + switch (mode) { + case QClipboard::Selection: + modeAtom = XA_PRIMARY; + break; + + case QClipboard::Clipboard: + modeAtom = QXlibStatic::atom(QXlibStatic::CLIPBOARD); + break; + + default: + qWarning("QTestLiteMime: Internal error: Unsupported clipboard mode"); + break; + } + } + +protected: + QStringList formats_sys() const + { + if (empty()) + return QStringList(); + + if (!formatList.count()) { + QXlibClipboardMime *that = const_cast<QXlibClipboardMime *>(this); + // get the list of targets from the current clipboard owner - we do this + // once so that multiple calls to this function don't require multiple + // server round trips... + that->format_atoms = m_clipboard->getDataInFormat(modeAtom,QXlibStatic::atom(QXlibStatic::TARGETS)); + + if (format_atoms.size() > 0) { + Atom *targets = (Atom *) format_atoms.data(); + int size = format_atoms.size() / sizeof(Atom); + + for (int i = 0; i < size; ++i) { + if (targets[i] == 0) + continue; + + QStringList formatsForAtom = mimeFormatsForAtom(m_clipboard->screen()->display(),targets[i]); + for (int j = 0; j < formatsForAtom.size(); ++j) { + if (!formatList.contains(formatsForAtom.at(j))) + that->formatList.append(formatsForAtom.at(j)); + } + } + } + } + + return formatList; + } + + bool hasFormat_sys(const QString &format) const + { + QStringList list = formats(); + return list.contains(format); + } + + QVariant retrieveData_sys(const QString &fmt, QVariant::Type requestedType) const + { + if (fmt.isEmpty() || empty()) + return QByteArray(); + + (void)formats(); // trigger update of format list + + QList<Atom> atoms; + Atom *targets = (Atom *) format_atoms.data(); + int size = format_atoms.size() / sizeof(Atom); + for (int i = 0; i < size; ++i) + atoms.append(targets[i]); + + QByteArray encoding; + Atom fmtatom = mimeAtomForFormat(m_clipboard->screen()->display(),fmt, requestedType, atoms, &encoding); + + if (fmtatom == 0) + return QVariant(); + + return mimeConvertToFormat(m_clipboard->screen()->display(),fmtatom, m_clipboard->getDataInFormat(modeAtom,fmtatom), fmt, requestedType, encoding); + } +private: + bool empty() const + { + Window win = XGetSelectionOwner(m_clipboard->screen()->display(), modeAtom); + + return win == XNone; + } + + + Atom modeAtom; + QXlibClipboard *m_clipboard; + QStringList formatList; + QByteArray format_atoms; +}; + +const int QXlibClipboard::clipboard_timeout = 5000; + +QXlibClipboard::QXlibClipboard(QXlibScreen *screen) + : QPlatformClipboard() + , m_screen(screen) + , m_xClipboard(0) + , m_clientClipboard(0) + , m_xSelection(0) + , m_clientSelection(0) + , m_requestor(XNone) + , m_owner(XNone) +{ +} + +const QMimeData * QXlibClipboard::mimeData(QClipboard::Mode mode) const +{ + if (mode == QClipboard::Clipboard) { + if (!m_xClipboard) { + QXlibClipboard *that = const_cast<QXlibClipboard *>(this); + that->m_xClipboard = new QXlibClipboardMime(mode,that); + } + Window clipboardOwner = XGetSelectionOwner(screen()->display(),QXlibStatic::atom(QXlibStatic::CLIPBOARD)); + if (clipboardOwner == owner()) { + return m_clientClipboard; + } else { + return m_xClipboard; + } + } else if (mode == QClipboard::Selection) { + if (!m_xSelection) { + QXlibClipboard *that = const_cast<QXlibClipboard *>(this); + that->m_xSelection = new QXlibClipboardMime(mode,that); + } + Window clipboardOwner = XGetSelectionOwner(screen()->display(),XA_PRIMARY); + if (clipboardOwner == owner()) { + return m_clientSelection; + } else { + return m_xSelection; + } + } + return 0; +} + +void QXlibClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) +{ + Atom modeAtom; + QMimeData **d; + switch (mode) { + case QClipboard::Selection: + modeAtom = XA_PRIMARY; + d = &m_clientSelection; + break; + + case QClipboard::Clipboard: + modeAtom = QXlibStatic::atom(QXlibStatic::CLIPBOARD); + d = &m_clientClipboard; + break; + + default: + qWarning("QClipboard::setMimeData: unsupported mode '%d'", mode); + return; + } + + Window newOwner; + + if (! data) { // no data, clear clipboard contents + newOwner = XNone; + } else { + newOwner = owner(); + + *d = data; + } + + XSetSelectionOwner(m_screen->display(), modeAtom, newOwner, CurrentTime); + + if (XGetSelectionOwner(m_screen->display(), modeAtom) != newOwner) { + qWarning("QClipboard::setData: Cannot set X11 selection owner"); + } + +} + +bool QXlibClipboard::supportsMode(QClipboard::Mode mode) const +{ + if (mode == QClipboard::Clipboard || mode == QClipboard::Selection) + return true; + return false; +} + + +QXlibScreen * QXlibClipboard::screen() const +{ + return m_screen; +} + +Window QXlibClipboard::requestor() const +{ + if (!m_requestor) { + int x = 0, y = 0, w = 3, h = 3; + QXlibClipboard *that = const_cast<QXlibClipboard *>(this); + Window window = XCreateSimpleWindow(m_screen->display(), m_screen->rootWindow(), + x, y, w, h, 0 /*border_width*/, + m_screen->blackPixel(), m_screen->whitePixel()); + that->setRequestor(window); + } + return m_requestor; +} + +void QXlibClipboard::setRequestor(Window window) +{ + if (m_requestor != XNone) { + XDestroyWindow(m_screen->display(),m_requestor); + } + m_requestor = window; +} + +Window QXlibClipboard::owner() const +{ + if (!m_owner) { + int x = 0, y = 0, w = 3, h = 3; + QXlibClipboard *that = const_cast<QXlibClipboard *>(this); + Window window = XCreateSimpleWindow(m_screen->display(), m_screen->rootWindow(), + x, y, w, h, 0 /*border_width*/, + m_screen->blackPixel(), m_screen->whitePixel()); + that->setOwner(window); + } + return m_owner; +} + +void QXlibClipboard::setOwner(Window window) +{ + if (m_owner != XNone){ + XDestroyWindow(m_screen->display(),m_owner); + } + m_owner = window; +} + +Atom QXlibClipboard::sendTargetsSelection(QMimeData *d, Window window, Atom property) +{ + QVector<Atom> types; + QStringList formats = QInternalMimeData::formatsHelper(d); + for (int i = 0; i < formats.size(); ++i) { + QList<Atom> atoms = QXlibMime::mimeAtomsForFormat(screen()->display(),formats.at(i)); + for (int j = 0; j < atoms.size(); ++j) { + if (!types.contains(atoms.at(j))) + types.append(atoms.at(j)); + } + } + types.append(QXlibStatic::atom(QXlibStatic::TARGETS)); + types.append(QXlibStatic::atom(QXlibStatic::MULTIPLE)); + types.append(QXlibStatic::atom(QXlibStatic::TIMESTAMP)); + types.append(QXlibStatic::atom(QXlibStatic::SAVE_TARGETS)); + + XChangeProperty(screen()->display(), window, property, XA_ATOM, 32, + PropModeReplace, (uchar *) types.data(), types.size()); + return property; +} + +Atom QXlibClipboard::sendSelection(QMimeData *d, Atom target, Window window, Atom property) +{ + Atom atomFormat = target; + int dataFormat = 0; + QByteArray data; + + QString fmt = QXlibMime::mimeAtomToString(screen()->display(), target); + if (fmt.isEmpty()) { // Not a MIME type we have + qDebug() << "QClipboard: send_selection(): converting to type '%s' is not supported" << fmt.data(); + return XNone; + } + qDebug() << "QClipboard: send_selection(): converting to type '%s'" << fmt.data(); + + if (QXlibMime::mimeDataForAtom(screen()->display(),target, d, &data, &atomFormat, &dataFormat)) { + + // don't allow INCR transfers when using MULTIPLE or to + // Motif clients (since Motif doesn't support INCR) + static Atom motif_clip_temporary = QXlibStatic::atom(QXlibStatic::CLIP_TEMPORARY); + bool allow_incr = property != motif_clip_temporary; + + // X_ChangeProperty protocol request is 24 bytes + const int increment = (XMaxRequestSize(screen()->display()) * 4) - 24; + if (data.size() > increment && allow_incr) { + long bytes = data.size(); + XChangeProperty(screen()->display(), window, property, + QXlibStatic::atom(QXlibStatic::INCR), 32, PropModeReplace, (uchar *) &bytes, 1); + +// (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment); + qDebug() << "not implemented INCRT just YET!"; + return property; + } + + // make sure we can perform the XChangeProperty in a single request + if (data.size() > increment) + return XNone; // ### perhaps use several XChangeProperty calls w/ PropModeAppend? + int dataSize = data.size() / (dataFormat / 8); + // use a single request to transfer data + XChangeProperty(screen()->display(), window, property, atomFormat, + dataFormat, PropModeReplace, (uchar *) data.data(), + dataSize); + } + return property; +} + +void QXlibClipboard::handleSelectionRequest(XEvent *xevent) +{ + XSelectionRequestEvent *req = &xevent->xselectionrequest; + + if (requestor() && req->requestor == requestor()) { + qDebug() << "This should be caught before"; + return; + } + + XEvent event; + event.xselection.type = SelectionNotify; + event.xselection.display = req->display; + event.xselection.requestor = req->requestor; + event.xselection.selection = req->selection; + event.xselection.target = req->target; + event.xselection.property = XNone; + event.xselection.time = req->time; + + QMimeData *d; + if (req->selection == XA_PRIMARY) { + d = m_clientSelection; + } else if (req->selection == QXlibStatic::atom(QXlibStatic::CLIPBOARD)) { + d = m_clientClipboard; + } else { + qWarning("QClipboard: Unknown selection '%lx'", req->selection); + XSendEvent(screen()->display(), req->requestor, False, NoEventMask, &event); + return; + } + + if (!d) { + qWarning("QClipboard: Cannot transfer data, no data available"); + XSendEvent(screen()->display(), req->requestor, False, NoEventMask, &event); + return; + } + + Atom xa_targets = QXlibStatic::atom(QXlibStatic::TARGETS); + Atom xa_multiple = QXlibStatic::atom(QXlibStatic::MULTIPLE); + Atom xa_timestamp = QXlibStatic::atom(QXlibStatic::TIMESTAMP); + + struct AtomPair { Atom target; Atom property; } *multi = 0; + Atom multi_type = XNone; + int multi_format = 0; + int nmulti = 0; + int imulti = -1; + bool multi_writeback = false; + + if (req->target == xa_multiple) { + QByteArray multi_data; + if (req->property == XNone + || !clipboardReadProperty(req->requestor, req->property, false, &multi_data, + 0, &multi_type, &multi_format) + || multi_format != 32) { + // MULTIPLE property not formatted correctly + XSendEvent(screen()->display(), req->requestor, False, NoEventMask, &event); + return; + } + nmulti = multi_data.size()/sizeof(*multi); + multi = new AtomPair[nmulti]; + memcpy(multi,multi_data.data(),multi_data.size()); + imulti = 0; + } + + for (; imulti < nmulti; ++imulti) { + Atom target; + Atom property; + + if (multi) { + target = multi[imulti].target; + property = multi[imulti].property; + } else { + target = req->target; + property = req->property; + if (property == XNone) // obsolete client + property = target; + } + + Atom ret = XNone; + if (target == XNone || property == XNone) { + ; + } else if (target == xa_timestamp) { +// if (d->timestamp != CurrentTime) { +// XChangeProperty(screen()->display(), req->requestor, property, XA_INTEGER, 32, +// PropModeReplace, CurrentTime, 1); +// ret = property; +// } else { +// qWarning("QClipboard: Invalid data timestamp"); +// } + } else if (target == xa_targets) { + ret = sendTargetsSelection(d, req->requestor, property); + } else { + ret = sendSelection(d, target, req->requestor, property); + } + + if (nmulti > 0) { + if (ret == XNone) { + multi[imulti].property = XNone; + multi_writeback = true; + } + } else { + event.xselection.property = ret; + break; + } + } + + if (nmulti > 0) { + if (multi_writeback) { + // according to ICCCM 2.6.2 says to put None back + // into the original property on the requestor window + XChangeProperty(screen()->display(), req->requestor, req->property, multi_type, 32, + PropModeReplace, (uchar *) multi, nmulti * 2); + } + + delete [] multi; + event.xselection.property = req->property; + } + + // send selection notify to requestor + XSendEvent(screen()->display(), req->requestor, False, NoEventMask, &event); +} + +static inline int maxSelectionIncr(Display *dpy) +{ return XMaxRequestSize(dpy) > 65536 ? 65536*4 : XMaxRequestSize(dpy)*4 - 100; } + +bool QXlibClipboard::clipboardReadProperty(Window win, Atom property, bool deleteProperty, QByteArray *buffer, int *size, Atom *type, int *format) const +{ + int maxsize = maxSelectionIncr(screen()->display()); + ulong bytes_left; // bytes_after + ulong length; // nitems + uchar *data; + Atom dummy_type; + int dummy_format; + int r; + + if (!type) // allow null args + type = &dummy_type; + if (!format) + format = &dummy_format; + + // Don't read anything, just get the size of the property data + r = XGetWindowProperty(screen()->display(), win, property, 0, 0, False, + AnyPropertyType, type, format, + &length, &bytes_left, &data); + if (r != Success || (type && *type == XNone)) { + buffer->resize(0); + return false; + } + XFree((char*)data); + + int offset = 0, buffer_offset = 0, format_inc = 1, proplen = bytes_left; + + switch (*format) { + case 8: + default: + format_inc = sizeof(char) / 1; + break; + + case 16: + format_inc = sizeof(short) / 2; + proplen *= sizeof(short) / 2; + break; + + case 32: + format_inc = sizeof(long) / 4; + proplen *= sizeof(long) / 4; + break; + } + + int newSize = proplen; + buffer->resize(newSize); + + bool ok = (buffer->size() == newSize); + + if (ok && newSize) { + // could allocate buffer + + while (bytes_left) { + // more to read... + + r = XGetWindowProperty(screen()->display(), win, property, offset, maxsize/4, + False, AnyPropertyType, type, format, + &length, &bytes_left, &data); + if (r != Success || (type && *type == XNone)) + break; + + offset += length / (32 / *format); + length *= format_inc * (*format) / 8; + + // Here we check if we get a buffer overflow and tries to + // recover -- this shouldn't normally happen, but it doesn't + // hurt to be defensive + if ((int)(buffer_offset + length) > buffer->size()) { + length = buffer->size() - buffer_offset; + + // escape loop + bytes_left = 0; + } + + memcpy(buffer->data() + buffer_offset, data, length); + buffer_offset += length; + + XFree((char*)data); + } + + if (*format == 8 && *type == QXlibStatic::atom(QXlibStatic::COMPOUND_TEXT)) { + // convert COMPOUND_TEXT to a multibyte string + XTextProperty textprop; + textprop.encoding = *type; + textprop.format = *format; + textprop.nitems = buffer_offset; + textprop.value = (unsigned char *) buffer->data(); + + char **list_ret = 0; + int count; + if (XmbTextPropertyToTextList(screen()->display(), &textprop, &list_ret, + &count) == Success && count && list_ret) { + offset = buffer_offset = strlen(list_ret[0]); + buffer->resize(offset); + memcpy(buffer->data(), list_ret[0], offset); + } + if (list_ret) XFreeStringList(list_ret); + } + } + + // correct size, not 0-term. + if (size) + *size = buffer_offset; + + if (deleteProperty) + XDeleteProperty(screen()->display(), win, property); + + XFlush(screen()->display()); + + return ok; +} + +QByteArray QXlibClipboard::clipboardReadIncrementalProperty(Window win, Atom property, int nbytes, bool nullterm) +{ + XEvent event; + + QByteArray buf; + QByteArray tmp_buf; + bool alloc_error = false; + int length; + int offset = 0; + + if (nbytes > 0) { + // Reserve buffer + zero-terminator (for text data) + // We want to complete the INCR transfer even if we cannot + // allocate more memory + buf.resize(nbytes+1); + alloc_error = buf.size() != nbytes+1; + } + + for (;;) { + XFlush(screen()->display()); + if (!screen()->waitForClipboardEvent(win,PropertyNotify,&event,clipboard_timeout)) + break; + if (event.xproperty.atom != property || + event.xproperty.state != PropertyNewValue) + continue; + if (clipboardReadProperty(win, property, true, &tmp_buf, &length, 0, 0)) { + if (length == 0) { // no more data, we're done + if (nullterm) { + buf.resize(offset+1); + buf[offset] = '\0'; + } else { + buf.resize(offset); + } + return buf; + } else if (!alloc_error) { + if (offset+length > (int)buf.size()) { + buf.resize(offset+length+65535); + if (buf.size() != offset+length+65535) { + alloc_error = true; + length = buf.size() - offset; + } + } + memcpy(buf.data()+offset, tmp_buf.constData(), length); + tmp_buf.resize(0); + offset += length; + } + } else { + break; + } + } + + // timed out ... create a new requestor window, otherwise the requestor + // could consider next request to be still part of this timed out request + setRequestor(0); + + return QByteArray(); +} + +QByteArray QXlibClipboard::getDataInFormat(Atom modeAtom, Atom fmtatom) +{ + QByteArray buf; + + Window win = requestor(); + + XSelectInput(screen()->display(), win, NoEventMask); // don't listen for any events + + XDeleteProperty(screen()->display(), win, QXlibStatic::atom(QXlibStatic::_QT_SELECTION)); + XConvertSelection(screen()->display(), modeAtom, fmtatom, QXlibStatic::atom(QXlibStatic::_QT_SELECTION), win, CurrentTime); + XSync(screen()->display(), false); + + XEvent xevent; + if (!screen()->waitForClipboardEvent(win,SelectionNotify,&xevent,clipboard_timeout) || + xevent.xselection.property == XNone) { + return buf; + } + + Atom type; + XSelectInput(screen()->display(), win, PropertyChangeMask); + + if (clipboardReadProperty(win, QXlibStatic::atom(QXlibStatic::_QT_SELECTION), true, &buf, 0, &type, 0)) { + if (type == QXlibStatic::atom(QXlibStatic::INCR)) { + int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0; + buf = clipboardReadIncrementalProperty(win, QXlibStatic::atom(QXlibStatic::_QT_SELECTION), nbytes, false); + } + } + + XSelectInput(screen()->display(), win, NoEventMask); + + + return buf; +} + +#include "qtestliteclipboard.moc" diff --git a/src/plugins/platforms/xlib/qtestliteclipboard.h b/src/plugins/platforms/xlib/qtestliteclipboard.h new file mode 100644 index 0000000..109714c --- /dev/null +++ b/src/plugins/platforms/xlib/qtestliteclipboard.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTESTLITECLIPBOARD_H +#define QTESTLITECLIPBOARD_H + +#include <QPlatformClipboard> +#include "qtestlitestaticinfo.h" + +class QXlibScreen; +class QXlibClipboard : public QPlatformClipboard +{ +public: + QXlibClipboard(QXlibScreen *screen); + + const QMimeData *mimeData(QClipboard::Mode mode) const; + void setMimeData(QMimeData *data, QClipboard::Mode mode); + + bool supportsMode(QClipboard::Mode mode) const; + + QXlibScreen *screen() const; + + Window requestor() const; + void setRequestor(Window window); + + Window owner() const; + + void handleSelectionRequest(XEvent *event); + + bool clipboardReadProperty(Window win, Atom property, bool deleteProperty, QByteArray *buffer, int *size, Atom *type, int *format) const; + QByteArray clipboardReadIncrementalProperty(Window win, Atom property, int nbytes, bool nullterm); + + QByteArray getDataInFormat(Atom modeAtom, Atom fmtatom); + +private: + void setOwner(Window window); + + Atom sendTargetsSelection(QMimeData *d, Window window, Atom property); + Atom sendSelection(QMimeData *d, Atom target, Window window, Atom property); + + QXlibScreen *m_screen; + + QMimeData *m_xClipboard; + QMimeData *m_clientClipboard; + + QMimeData *m_xSelection; + QMimeData *m_clientSelection; + + Window m_requestor; + Window m_owner; + + static const int clipboard_timeout; + +}; + +#endif // QTESTLITECLIPBOARD_H diff --git a/src/plugins/platforms/xlib/qtestlitecursor.cpp b/src/plugins/platforms/xlib/qtestlitecursor.cpp new file mode 100644 index 0000000..2f7cfbf --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitecursor.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestlitecursor.h" + +#include "qtestliteintegration.h" +#include "qtestlitescreen.h" +#include "qtestlitewindow.h" + +#include <QtGui/QBitmap> + +#include <X11/cursorfont.h> + +QT_BEGIN_NAMESPACE + +QXlibCursor::QXlibCursor(QXlibScreen *screen) + : QPlatformCursor(screen) +{ +} + +void QXlibCursor::changeCursor(QCursor *cursor, QWidget *widget) +{ + QXlibWindow *w = 0; + if (widget) { + QWidget *window = widget->window(); + w = static_cast<QXlibWindow*>(window->platformWindow()); + } else { + // No X11 cursor control when there is no widget under the cursor + return; + } + + if (!w) + return; + + int id = cursor->handle(); + + Cursor c; + if (!cursorMap.contains(id)) { + if (cursor->shape() == Qt::BitmapCursor) + c = createCursorBitmap(cursor); + else + c = createCursorShape(cursor->shape()); + if (!c) { + return; + } + cursorMap.insert(id, c); + } else { + c = cursorMap.value(id); + } + + w->setCursor(c); +} + +Cursor QXlibCursor::createCursorBitmap(QCursor * cursor) +{ + XColor bg, fg; + bg.red = 255 << 8; + bg.green = 255 << 8; + bg.blue = 255 << 8; + fg.red = 0; + fg.green = 0; + fg.blue = 0; + QPoint spot = cursor->hotSpot(); + Window rootwin = testLiteScreen()->rootWindow(); + + QImage mapImage = cursor->bitmap()->toImage().convertToFormat(QImage::Format_MonoLSB); + QImage maskImage = cursor->mask()->toImage().convertToFormat(QImage::Format_MonoLSB); + + int width = cursor->bitmap()->width(); + int height = cursor->bitmap()->height(); + int bytesPerLine = mapImage.bytesPerLine(); + int destLineSize = width / 8; + if (width % 8) + destLineSize++; + + const uchar * map = mapImage.bits(); + const uchar * mask = maskImage.bits(); + + char * mapBits = new char[height * destLineSize]; + char * maskBits = new char[height * destLineSize]; + for (int i = 0; i < height; i++) { + memcpy(mapBits + (destLineSize * i),map + (bytesPerLine * i), destLineSize); + memcpy(maskBits + (destLineSize * i),mask + (bytesPerLine * i), destLineSize); + } + + Pixmap cp = XCreateBitmapFromData(testLiteScreen()->display(), rootwin, mapBits, width, height); + Pixmap mp = XCreateBitmapFromData(testLiteScreen()->display(), rootwin, maskBits, width, height); + Cursor c = XCreatePixmapCursor(testLiteScreen()->display(), cp, mp, &fg, &bg, spot.x(), spot.y()); + XFreePixmap(testLiteScreen()->display(), cp); + XFreePixmap(testLiteScreen()->display(), mp); + delete[] mapBits; + delete[] maskBits; + + return c; +} + +Cursor QXlibCursor::createCursorShape(int cshape) +{ + Cursor cursor = 0; + + if (cshape < 0 || cshape > Qt::LastCursor) + return 0; + + switch (cshape) { + case Qt::ArrowCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_left_ptr); + break; + case Qt::UpArrowCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_center_ptr); + break; + case Qt::CrossCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_crosshair); + break; + case Qt::WaitCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_watch); + break; + case Qt::IBeamCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_xterm); + break; + case Qt::SizeAllCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_fleur); + break; + case Qt::PointingHandCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_hand2); + break; + case Qt::SizeBDiagCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_top_right_corner); + break; + case Qt::SizeFDiagCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_bottom_right_corner); + break; + case Qt::SizeVerCursor: + case Qt::SplitVCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_sb_v_double_arrow); + break; + case Qt::SizeHorCursor: + case Qt::SplitHCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_sb_h_double_arrow); + break; + case Qt::WhatsThisCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_question_arrow); + break; + case Qt::ForbiddenCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_circle); + break; + case Qt::BusyCursor: + cursor = XCreateFontCursor(testLiteScreen()->display(), XC_watch); + break; + + default: //default cursor for all the rest + break; + } + return cursor; +} + +QXlibScreen * QXlibCursor::testLiteScreen() const +{ + return static_cast<QXlibScreen *>(screen); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qtestlitecursor.h b/src/plugins/platforms/xlib/qtestlitecursor.h new file mode 100644 index 0000000..db9f9e2 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitecursor.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTESTLITECURSOR_H +#define QTESTLITECURSOR_H + +#include <QtGui/QPlatformCursor> + +#include "qtestliteintegration.h" + +QT_BEGIN_NAMESPACE + +class QXlibCursor : QPlatformCursor +{ +public: + QXlibCursor(QXlibScreen *screen); + + void changeCursor(QCursor * cursor, QWidget * widget); +private: + + Cursor createCursorBitmap(QCursor * cursor); + Cursor createCursorShape(int cshape); + + QXlibScreen *testLiteScreen() const; + QMap<int, Cursor> cursorMap; +}; + +QT_END_NAMESPACE + +#endif // QTESTLITECURSOR_H diff --git a/src/plugins/platforms/xlib/qtestliteeglintegration.cpp b/src/plugins/platforms/xlib/qtestliteeglintegration.cpp new file mode 100644 index 0000000..9bbe0ca --- /dev/null +++ b/src/plugins/platforms/xlib/qtestliteeglintegration.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestliteeglintegration.h" + +static int countBits(unsigned long mask) +{ + int count = 0; + while (mask != 0) { + if (mask & 1) + ++count; + mask >>= 1; + } + return count; +} + +VisualID QXlibEglIntegration::getCompatibleVisualId(Display *display, EGLConfig config) +{ + VisualID visualId = 0; + EGLint eglValue = 0; + + EGLDisplay eglDisplay = eglGetDisplay(display); + + EGLint configRedSize = 0; + eglGetConfigAttrib(eglDisplay, config, EGL_RED_SIZE, &configRedSize); + + EGLint configGreenSize = 0; + eglGetConfigAttrib(eglDisplay, config, EGL_GREEN_SIZE, &configGreenSize); + + EGLint configBlueSize = 0; + eglGetConfigAttrib(eglDisplay, config, EGL_BLUE_SIZE, &configBlueSize); + + EGLint configAlphaSize = 0; + eglGetConfigAttrib(eglDisplay, config, EGL_ALPHA_SIZE, &configAlphaSize); + + eglGetConfigAttrib(eglDisplay, config, EGL_CONFIG_ID, &eglValue); + int configId = eglValue; + + // See if EGL provided a valid VisualID: + eglGetConfigAttrib(eglDisplay, config, EGL_NATIVE_VISUAL_ID, &eglValue); + visualId = (VisualID)eglValue; + if (visualId) { + // EGL has suggested a visual id, so get the rest of the visual info for that id: + XVisualInfo visualInfoTemplate; + memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); + visualInfoTemplate.visualid = visualId; + + XVisualInfo *chosenVisualInfo; + int matchingCount = 0; + chosenVisualInfo = XGetVisualInfo(display, VisualIDMask, &visualInfoTemplate, &matchingCount); + if (chosenVisualInfo) { + // Skip size checks if implementation supports non-matching visual + // and config (http://bugreports.qt.nokia.com/browse/QTBUG-9444). + if (q_hasEglExtension(eglDisplay,"EGL_NV_post_convert_rounding")) { + XFree(chosenVisualInfo); + return visualId; + } + + int visualRedSize = countBits(chosenVisualInfo->red_mask); + int visualGreenSize = countBits(chosenVisualInfo->green_mask); + int visualBlueSize = countBits(chosenVisualInfo->blue_mask); + int visualAlphaSize = -1; // Need XRender to tell us the alpha channel size + + bool visualMatchesConfig = false; + if ( visualRedSize == configRedSize && + visualGreenSize == configGreenSize && + visualBlueSize == configBlueSize ) + { + // We need XRender to check the alpha channel size of the visual. If we don't have + // the alpha size, we don't check it against the EGL config's alpha size. + if (visualAlphaSize >= 0) + visualMatchesConfig = visualAlphaSize == configAlphaSize; + else + visualMatchesConfig = true; + } + + if (!visualMatchesConfig) { + if (visualAlphaSize >= 0) { + qWarning("Warning: EGL suggested using X Visual ID %d (ARGB%d%d%d%d) for EGL config %d (ARGB%d%d%d%d), but this is incompatable", + (int)visualId, visualAlphaSize, visualRedSize, visualGreenSize, visualBlueSize, + configId, configAlphaSize, configRedSize, configGreenSize, configBlueSize); + } else { + qWarning("Warning: EGL suggested using X Visual ID %d (RGB%d%d%d) for EGL config %d (RGB%d%d%d), but this is incompatable", + (int)visualId, visualRedSize, visualGreenSize, visualBlueSize, + configId, configRedSize, configGreenSize, configBlueSize); + } + visualId = 0; + } + } else { + qWarning("Warning: EGL suggested using X Visual ID %d for EGL config %d, but that isn't a valid ID", + (int)visualId, configId); + visualId = 0; + } + XFree(chosenVisualInfo); + } +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + else + qDebug("EGL did not suggest a VisualID (EGL_NATIVE_VISUAL_ID was zero) for EGLConfig %d", configId); +#endif + + if (visualId) { +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + if (configAlphaSize > 0) + qDebug("Using ARGB Visual ID %d provided by EGL for config %d", (int)visualId, configId); + else + qDebug("Using Opaque Visual ID %d provided by EGL for config %d", (int)visualId, configId); +#endif + return visualId; + } + + // Finally, try to + // use XGetVisualInfo and only use the bit depths to match on: + if (!visualId) { + XVisualInfo visualInfoTemplate; + memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); + XVisualInfo *matchingVisuals; + int matchingCount = 0; + + visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize + configAlphaSize; + matchingVisuals = XGetVisualInfo(display, + VisualDepthMask, + &visualInfoTemplate, + &matchingCount); + if (!matchingVisuals) { + // Try again without taking the alpha channel into account: + visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize; + matchingVisuals = XGetVisualInfo(display, + VisualDepthMask, + &visualInfoTemplate, + &matchingCount); + } + + if (matchingVisuals) { + visualId = matchingVisuals[0].visualid; + XFree(matchingVisuals); + } + } + + if (visualId) { +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("Using Visual ID %d provided by XGetVisualInfo for EGL config %d", (int)visualId, configId); +#endif + return visualId; + } + + qWarning("Unable to find an X11 visual which matches EGL config %d", configId); + return (VisualID)0; +} diff --git a/src/plugins/platforms/xlib/qtestliteeglintegration.h b/src/plugins/platforms/xlib/qtestliteeglintegration.h new file mode 100644 index 0000000..4c2e50d --- /dev/null +++ b/src/plugins/platforms/xlib/qtestliteeglintegration.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTESTLITEEGLINTEGRATION_H +#define QTESTLITEEGLINTEGRATION_H + +#include "qtestlitestaticinfo.h" +#include "../eglconvenience/qeglconvenience.h" + +class QXlibEglIntegration +{ +public: + static VisualID getCompatibleVisualId(Display *display, EGLConfig config); +}; + +#endif // QTESTLITEEGLINTEGRATION_H diff --git a/src/plugins/platforms/xlib/qtestliteintegration.cpp b/src/plugins/platforms/xlib/qtestliteintegration.cpp new file mode 100644 index 0000000..cdc5c29 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestliteintegration.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestliteintegration.h" +#include "qtestlitewindowsurface.h" +#include <QtGui/private/qpixmap_raster_p.h> +#include <QtCore/qdebug.h> + +#include "qtestlitewindow.h" +#include "qgenericunixfontdatabase.h" +#include "qtestlitescreen.h" +#include "qtestliteclipboard.h" + +#if !defined(QT_NO_OPENGL) +#if !defined(QT_OPENGL_ES_2) +#include <GL/glx.h> +#else +#include <EGL/egl.h> +#endif //!defined(QT_OPENGL_ES_2) +#include <private/qwindowsurface_gl_p.h> +#include <private/qpixmapdata_gl_p.h> +#endif //QT_NO_OPENGL + +QT_BEGIN_NAMESPACE + +QXlibIntegration::QXlibIntegration(bool useOpenGL) + : mUseOpenGL(useOpenGL) + , mFontDb(new QGenericUnixFontDatabase()) + , mClipboard(0) +{ + mPrimaryScreen = new QXlibScreen(); + mScreens.append(mPrimaryScreen); +} + +QPixmapData *QXlibIntegration::createPixmapData(QPixmapData::PixelType type) const +{ +#ifndef QT_NO_OPENGL + if (mUseOpenGL) + return new QGLPixmapData(type); +#endif + return new QRasterPixmapData(type); +} + +QWindowSurface *QXlibIntegration::createWindowSurface(QWidget *widget, WId) const +{ +#ifndef QT_NO_OPENGL + if (mUseOpenGL) + return new QGLWindowSurface(widget); +#endif + return new QXlibWindowSurface(widget); +} + + +QPlatformWindow *QXlibIntegration::createPlatformWindow(QWidget *widget, WId /*winId*/) const +{ + return new QXlibWindow(widget); +} + + + +QPixmap QXlibIntegration::grabWindow(WId window, int x, int y, int width, int height) const +{ + QImage image; + QWidget *widget = QWidget::find(window); + if (widget) { + QXlibScreen *screen = QXlibScreen::testLiteScreenForWidget(widget); + image = screen->grabWindow(window,x,y,width,height); + } else { + for (int i = 0; i < mScreens.size(); i++) { + QXlibScreen *screen = static_cast<QXlibScreen *>(mScreens[i]); + if (screen->rootWindow() == window) { + image = screen->grabWindow(window,x,y,width,height); + } + } + } + return QPixmap::fromImage(image); +} + +QPlatformFontDatabase *QXlibIntegration::fontDatabase() const +{ + return mFontDb; +} + +QPlatformClipboard * QXlibIntegration::clipboard() const +{ + //Use lazy init since clipboard needs QTestliteScreen + if (!mClipboard) { + QXlibIntegration *that = const_cast<QXlibIntegration *>(this); + that->mClipboard = new QXlibClipboard(mPrimaryScreen); + } + return mClipboard; +} + +bool QXlibIntegration::hasOpenGL() const +{ +#if !defined(QT_NO_OPENGL) +#if !defined(QT_OPENGL_ES_2) + QXlibScreen *screen = static_cast<const QXlibScreen *>(mScreens.at(0)); + return glXQueryExtension(screen->display(), 0, 0) != 0; +#else + static bool eglHasbeenInitialized = false; + static bool wasEglInitialized = false; + if (!eglHasbeenInitialized) { + eglHasbeenInitialized = true; + const QXlibScreen *screen = static_cast<const QXlibScreen *>(mScreens.at(0)); + EGLint major, minor; + eglBindAPI(EGL_OPENGL_ES_API); + EGLDisplay disp = eglGetDisplay(screen->display()); + wasEglInitialized = eglInitialize(disp,&major,&minor); + } + return wasEglInitialized; +#endif +#endif + return false; +} + + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qtestliteintegration.h b/src/plugins/platforms/xlib/qtestliteintegration.h new file mode 100644 index 0000000..c3125b8 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestliteintegration.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSSYSTEM_TESTLITE_H +#define QGRAPHICSSYSTEM_TESTLITE_H + +//make sure textstream is included before any X11 headers +#include <QtCore/QTextStream> + +#include <QtGui/QPlatformIntegration> +#include <QtGui/QPlatformScreen> + +#include "qtestlitestaticinfo.h" + +QT_BEGIN_NAMESPACE + +class QXlibScreen; + +class QXlibIntegration : public QPlatformIntegration +{ +public: + QXlibIntegration(bool useOpenGL = false); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; + QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; + + QPixmap grabWindow(WId window, int x, int y, int width, int height) const; + + QList<QPlatformScreen *> screens() const { return mScreens; } + + QPlatformFontDatabase *fontDatabase() const; + QPlatformClipboard *clipboard() const; + + bool hasOpenGL() const; + +private: + bool mUseOpenGL; + QXlibScreen *mPrimaryScreen; + QList<QPlatformScreen *> mScreens; + QPlatformFontDatabase *mFontDb; + QPlatformClipboard *mClipboard; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/xlib/qtestlitekeyboard.cpp b/src/plugins/platforms/xlib/qtestlitekeyboard.cpp new file mode 100644 index 0000000..fb0cf2e --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitekeyboard.cpp @@ -0,0 +1,1000 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestlitekeyboard.h" + +#include "qtestlitescreen.h" + +#include <QtGui/QWindowSystemInterface> + +#include <QtCore/QTextCodec> + +#ifndef XK_ISO_Left_Tab +#define XK_ISO_Left_Tab 0xFE20 +#endif + +#ifndef XK_dead_hook +#define XK_dead_hook 0xFE61 +#endif + +#ifndef XK_dead_horn +#define XK_dead_horn 0xFE62 +#endif + +#ifndef XK_Codeinput +#define XK_Codeinput 0xFF37 +#endif + +#ifndef XK_Kanji_Bangou +#define XK_Kanji_Bangou 0xFF37 /* same as codeinput */ +#endif + +// Fix old X libraries +#ifndef XK_KP_Home +#define XK_KP_Home 0xFF95 +#endif +#ifndef XK_KP_Left +#define XK_KP_Left 0xFF96 +#endif +#ifndef XK_KP_Up +#define XK_KP_Up 0xFF97 +#endif +#ifndef XK_KP_Right +#define XK_KP_Right 0xFF98 +#endif +#ifndef XK_KP_Down +#define XK_KP_Down 0xFF99 +#endif +#ifndef XK_KP_Prior +#define XK_KP_Prior 0xFF9A +#endif +#ifndef XK_KP_Next +#define XK_KP_Next 0xFF9B +#endif +#ifndef XK_KP_End +#define XK_KP_End 0xFF9C +#endif +#ifndef XK_KP_Insert +#define XK_KP_Insert 0xFF9E +#endif +#ifndef XK_KP_Delete +#define XK_KP_Delete 0xFF9F +#endif + +// the next lines are taken on 10/2009 from X.org (X11/XF86keysym.h), defining some special +// multimedia keys. They are included here as not every system has them. +#define XF86XK_MonBrightnessUp 0x1008FF02 +#define XF86XK_MonBrightnessDown 0x1008FF03 +#define XF86XK_KbdLightOnOff 0x1008FF04 +#define XF86XK_KbdBrightnessUp 0x1008FF05 +#define XF86XK_KbdBrightnessDown 0x1008FF06 +#define XF86XK_Standby 0x1008FF10 +#define XF86XK_AudioLowerVolume 0x1008FF11 +#define XF86XK_AudioMute 0x1008FF12 +#define XF86XK_AudioRaiseVolume 0x1008FF13 +#define XF86XK_AudioPlay 0x1008FF14 +#define XF86XK_AudioStop 0x1008FF15 +#define XF86XK_AudioPrev 0x1008FF16 +#define XF86XK_AudioNext 0x1008FF17 +#define XF86XK_HomePage 0x1008FF18 +#define XF86XK_Mail 0x1008FF19 +#define XF86XK_Start 0x1008FF1A +#define XF86XK_Search 0x1008FF1B +#define XF86XK_AudioRecord 0x1008FF1C +#define XF86XK_Calculator 0x1008FF1D +#define XF86XK_Memo 0x1008FF1E +#define XF86XK_ToDoList 0x1008FF1F +#define XF86XK_Calendar 0x1008FF20 +#define XF86XK_PowerDown 0x1008FF21 +#define XF86XK_ContrastAdjust 0x1008FF22 +#define XF86XK_Back 0x1008FF26 +#define XF86XK_Forward 0x1008FF27 +#define XF86XK_Stop 0x1008FF28 +#define XF86XK_Refresh 0x1008FF29 +#define XF86XK_PowerOff 0x1008FF2A +#define XF86XK_WakeUp 0x1008FF2B +#define XF86XK_Eject 0x1008FF2C +#define XF86XK_ScreenSaver 0x1008FF2D +#define XF86XK_WWW 0x1008FF2E +#define XF86XK_Sleep 0x1008FF2F +#define XF86XK_Favorites 0x1008FF30 +#define XF86XK_AudioPause 0x1008FF31 +#define XF86XK_AudioMedia 0x1008FF32 +#define XF86XK_MyComputer 0x1008FF33 +#define XF86XK_LightBulb 0x1008FF35 +#define XF86XK_Shop 0x1008FF36 +#define XF86XK_History 0x1008FF37 +#define XF86XK_OpenURL 0x1008FF38 +#define XF86XK_AddFavorite 0x1008FF39 +#define XF86XK_HotLinks 0x1008FF3A +#define XF86XK_BrightnessAdjust 0x1008FF3B +#define XF86XK_Finance 0x1008FF3C +#define XF86XK_Community 0x1008FF3D +#define XF86XK_AudioRewind 0x1008FF3E +#define XF86XK_BackForward 0x1008FF3F +#define XF86XK_Launch0 0x1008FF40 +#define XF86XK_Launch1 0x1008FF41 +#define XF86XK_Launch2 0x1008FF42 +#define XF86XK_Launch3 0x1008FF43 +#define XF86XK_Launch4 0x1008FF44 +#define XF86XK_Launch5 0x1008FF45 +#define XF86XK_Launch6 0x1008FF46 +#define XF86XK_Launch7 0x1008FF47 +#define XF86XK_Launch8 0x1008FF48 +#define XF86XK_Launch9 0x1008FF49 +#define XF86XK_LaunchA 0x1008FF4A +#define XF86XK_LaunchB 0x1008FF4B +#define XF86XK_LaunchC 0x1008FF4C +#define XF86XK_LaunchD 0x1008FF4D +#define XF86XK_LaunchE 0x1008FF4E +#define XF86XK_LaunchF 0x1008FF4F +#define XF86XK_ApplicationLeft 0x1008FF50 +#define XF86XK_ApplicationRight 0x1008FF51 +#define XF86XK_Book 0x1008FF52 +#define XF86XK_CD 0x1008FF53 +#define XF86XK_Calculater 0x1008FF54 +#define XF86XK_Clear 0x1008FF55 +#define XF86XK_ClearGrab 0x1008FE21 +#define XF86XK_Close 0x1008FF56 +#define XF86XK_Copy 0x1008FF57 +#define XF86XK_Cut 0x1008FF58 +#define XF86XK_Display 0x1008FF59 +#define XF86XK_DOS 0x1008FF5A +#define XF86XK_Documents 0x1008FF5B +#define XF86XK_Excel 0x1008FF5C +#define XF86XK_Explorer 0x1008FF5D +#define XF86XK_Game 0x1008FF5E +#define XF86XK_Go 0x1008FF5F +#define XF86XK_iTouch 0x1008FF60 +#define XF86XK_LogOff 0x1008FF61 +#define XF86XK_Market 0x1008FF62 +#define XF86XK_Meeting 0x1008FF63 +#define XF86XK_MenuKB 0x1008FF65 +#define XF86XK_MenuPB 0x1008FF66 +#define XF86XK_MySites 0x1008FF67 +#define XF86XK_News 0x1008FF69 +#define XF86XK_OfficeHome 0x1008FF6A +#define XF86XK_Option 0x1008FF6C +#define XF86XK_Paste 0x1008FF6D +#define XF86XK_Phone 0x1008FF6E +#define XF86XK_Reply 0x1008FF72 +#define XF86XK_Reload 0x1008FF73 +#define XF86XK_RotateWindows 0x1008FF74 +#define XF86XK_RotationPB 0x1008FF75 +#define XF86XK_RotationKB 0x1008FF76 +#define XF86XK_Save 0x1008FF77 +#define XF86XK_Send 0x1008FF7B +#define XF86XK_Spell 0x1008FF7C +#define XF86XK_SplitScreen 0x1008FF7D +#define XF86XK_Support 0x1008FF7E +#define XF86XK_TaskPane 0x1008FF7F +#define XF86XK_Terminal 0x1008FF80 +#define XF86XK_Tools 0x1008FF81 +#define XF86XK_Travel 0x1008FF82 +#define XF86XK_Video 0x1008FF87 +#define XF86XK_Word 0x1008FF89 +#define XF86XK_Xfer 0x1008FF8A +#define XF86XK_ZoomIn 0x1008FF8B +#define XF86XK_ZoomOut 0x1008FF8C +#define XF86XK_Away 0x1008FF8D +#define XF86XK_Messenger 0x1008FF8E +#define XF86XK_WebCam 0x1008FF8F +#define XF86XK_MailForward 0x1008FF90 +#define XF86XK_Pictures 0x1008FF91 +#define XF86XK_Music 0x1008FF92 +#define XF86XK_Battery 0x1008FF93 +#define XF86XK_Bluetooth 0x1008FF94 +#define XF86XK_WLAN 0x1008FF95 +#define XF86XK_UWB 0x1008FF96 +#define XF86XK_AudioForward 0x1008FF97 +#define XF86XK_AudioRepeat 0x1008FF98 +#define XF86XK_AudioRandomPlay 0x1008FF99 +#define XF86XK_Subtitle 0x1008FF9A +#define XF86XK_AudioCycleTrack 0x1008FF9B +#define XF86XK_Time 0x1008FF9F +#define XF86XK_Select 0x1008FFA0 +#define XF86XK_View 0x1008FFA1 +#define XF86XK_TopMenu 0x1008FFA2 +#define XF86XK_Suspend 0x1008FFA7 +#define XF86XK_Hibernate 0x1008FFA8 + + +// end of XF86keysyms.h + +// Special keys used by Qtopia, mapped into the X11 private keypad range. +#define QTOPIAXK_Select 0x11000601 +#define QTOPIAXK_Yes 0x11000602 +#define QTOPIAXK_No 0x11000603 +#define QTOPIAXK_Cancel 0x11000604 +#define QTOPIAXK_Printer 0x11000605 +#define QTOPIAXK_Execute 0x11000606 +#define QTOPIAXK_Sleep 0x11000607 +#define QTOPIAXK_Play 0x11000608 +#define QTOPIAXK_Zoom 0x11000609 +#define QTOPIAXK_Context1 0x1100060A +#define QTOPIAXK_Context2 0x1100060B +#define QTOPIAXK_Context3 0x1100060C +#define QTOPIAXK_Context4 0x1100060D +#define QTOPIAXK_Call 0x1100060E +#define QTOPIAXK_Hangup 0x1100060F +#define QTOPIAXK_Flip 0x11000610 + +// keyboard mapping table +static const unsigned int KeyTbl[] = { + + // misc keys + + XK_Escape, Qt::Key_Escape, + XK_Tab, Qt::Key_Tab, + XK_ISO_Left_Tab, Qt::Key_Backtab, + XK_BackSpace, Qt::Key_Backspace, + XK_Return, Qt::Key_Return, + XK_Insert, Qt::Key_Insert, + XK_Delete, Qt::Key_Delete, + XK_Clear, Qt::Key_Delete, + XK_Pause, Qt::Key_Pause, + XK_Print, Qt::Key_Print, + 0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq + 0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq + + // cursor movement + + XK_Home, Qt::Key_Home, + XK_End, Qt::Key_End, + XK_Left, Qt::Key_Left, + XK_Up, Qt::Key_Up, + XK_Right, Qt::Key_Right, + XK_Down, Qt::Key_Down, + XK_Prior, Qt::Key_PageUp, + XK_Next, Qt::Key_PageDown, + + // modifiers + + XK_Shift_L, Qt::Key_Shift, + XK_Shift_R, Qt::Key_Shift, + XK_Shift_Lock, Qt::Key_Shift, + XK_Control_L, Qt::Key_Control, + XK_Control_R, Qt::Key_Control, + XK_Meta_L, Qt::Key_Meta, + XK_Meta_R, Qt::Key_Meta, + XK_Alt_L, Qt::Key_Alt, + XK_Alt_R, Qt::Key_Alt, + XK_Caps_Lock, Qt::Key_CapsLock, + XK_Num_Lock, Qt::Key_NumLock, + XK_Scroll_Lock, Qt::Key_ScrollLock, + XK_Super_L, Qt::Key_Super_L, + XK_Super_R, Qt::Key_Super_R, + XK_Menu, Qt::Key_Menu, + XK_Hyper_L, Qt::Key_Hyper_L, + XK_Hyper_R, Qt::Key_Hyper_R, + XK_Help, Qt::Key_Help, + 0x1000FF74, Qt::Key_Backtab, // hardcoded HP backtab + 0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11) + 0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12) + + // numeric and function keypad keys + + XK_KP_Space, Qt::Key_Space, + XK_KP_Tab, Qt::Key_Tab, + XK_KP_Enter, Qt::Key_Enter, + //XK_KP_F1, Qt::Key_F1, + //XK_KP_F2, Qt::Key_F2, + //XK_KP_F3, Qt::Key_F3, + //XK_KP_F4, Qt::Key_F4, + XK_KP_Home, Qt::Key_Home, + XK_KP_Left, Qt::Key_Left, + XK_KP_Up, Qt::Key_Up, + XK_KP_Right, Qt::Key_Right, + XK_KP_Down, Qt::Key_Down, + XK_KP_Prior, Qt::Key_PageUp, + XK_KP_Next, Qt::Key_PageDown, + XK_KP_End, Qt::Key_End, + XK_KP_Begin, Qt::Key_Clear, + XK_KP_Insert, Qt::Key_Insert, + XK_KP_Delete, Qt::Key_Delete, + XK_KP_Equal, Qt::Key_Equal, + XK_KP_Multiply, Qt::Key_Asterisk, + XK_KP_Add, Qt::Key_Plus, + XK_KP_Separator, Qt::Key_Comma, + XK_KP_Subtract, Qt::Key_Minus, + XK_KP_Decimal, Qt::Key_Period, + XK_KP_Divide, Qt::Key_Slash, + + // International input method support keys + + // International & multi-key character composition + XK_ISO_Level3_Shift, Qt::Key_AltGr, + XK_Multi_key, Qt::Key_Multi_key, + XK_Codeinput, Qt::Key_Codeinput, + XK_SingleCandidate, Qt::Key_SingleCandidate, + XK_MultipleCandidate, Qt::Key_MultipleCandidate, + XK_PreviousCandidate, Qt::Key_PreviousCandidate, + + // Misc Functions + XK_Mode_switch, Qt::Key_Mode_switch, + XK_script_switch, Qt::Key_Mode_switch, + + // Japanese keyboard support + XK_Kanji, Qt::Key_Kanji, + XK_Muhenkan, Qt::Key_Muhenkan, + //XK_Henkan_Mode, Qt::Key_Henkan_Mode, + XK_Henkan_Mode, Qt::Key_Henkan, + XK_Henkan, Qt::Key_Henkan, + XK_Romaji, Qt::Key_Romaji, + XK_Hiragana, Qt::Key_Hiragana, + XK_Katakana, Qt::Key_Katakana, + XK_Hiragana_Katakana, Qt::Key_Hiragana_Katakana, + XK_Zenkaku, Qt::Key_Zenkaku, + XK_Hankaku, Qt::Key_Hankaku, + XK_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku, + XK_Touroku, Qt::Key_Touroku, + XK_Massyo, Qt::Key_Massyo, + XK_Kana_Lock, Qt::Key_Kana_Lock, + XK_Kana_Shift, Qt::Key_Kana_Shift, + XK_Eisu_Shift, Qt::Key_Eisu_Shift, + XK_Eisu_toggle, Qt::Key_Eisu_toggle, + //XK_Kanji_Bangou, Qt::Key_Kanji_Bangou, + //XK_Zen_Koho, Qt::Key_Zen_Koho, + //XK_Mae_Koho, Qt::Key_Mae_Koho, + XK_Kanji_Bangou, Qt::Key_Codeinput, + XK_Zen_Koho, Qt::Key_MultipleCandidate, + XK_Mae_Koho, Qt::Key_PreviousCandidate, + +#ifdef XK_KOREAN + // Korean keyboard support + XK_Hangul, Qt::Key_Hangul, + XK_Hangul_Start, Qt::Key_Hangul_Start, + XK_Hangul_End, Qt::Key_Hangul_End, + XK_Hangul_Hanja, Qt::Key_Hangul_Hanja, + XK_Hangul_Jamo, Qt::Key_Hangul_Jamo, + XK_Hangul_Romaja, Qt::Key_Hangul_Romaja, + //XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput, + XK_Hangul_Codeinput, Qt::Key_Codeinput, + XK_Hangul_Jeonja, Qt::Key_Hangul_Jeonja, + XK_Hangul_Banja, Qt::Key_Hangul_Banja, + XK_Hangul_PreHanja, Qt::Key_Hangul_PreHanja, + XK_Hangul_PostHanja, Qt::Key_Hangul_PostHanja, + //XK_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate, + //XK_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate, + //XK_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate, + XK_Hangul_SingleCandidate, Qt::Key_SingleCandidate, + XK_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate, + XK_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate, + XK_Hangul_Special, Qt::Key_Hangul_Special, + //XK_Hangul_switch, Qt::Key_Hangul_switch, + XK_Hangul_switch, Qt::Key_Mode_switch, +#endif // XK_KOREAN + + // dead keys + XK_dead_grave, Qt::Key_Dead_Grave, + XK_dead_acute, Qt::Key_Dead_Acute, + XK_dead_circumflex, Qt::Key_Dead_Circumflex, + XK_dead_tilde, Qt::Key_Dead_Tilde, + XK_dead_macron, Qt::Key_Dead_Macron, + XK_dead_breve, Qt::Key_Dead_Breve, + XK_dead_abovedot, Qt::Key_Dead_Abovedot, + XK_dead_diaeresis, Qt::Key_Dead_Diaeresis, + XK_dead_abovering, Qt::Key_Dead_Abovering, + XK_dead_doubleacute, Qt::Key_Dead_Doubleacute, + XK_dead_caron, Qt::Key_Dead_Caron, + XK_dead_cedilla, Qt::Key_Dead_Cedilla, + XK_dead_ogonek, Qt::Key_Dead_Ogonek, + XK_dead_iota, Qt::Key_Dead_Iota, + XK_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound, + XK_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound, + XK_dead_belowdot, Qt::Key_Dead_Belowdot, + XK_dead_hook, Qt::Key_Dead_Hook, + XK_dead_horn, Qt::Key_Dead_Horn, + + // Special keys from X.org - This include multimedia keys, + // wireless/bluetooth/uwb keys, special launcher keys, etc. + XF86XK_Back, Qt::Key_Back, + XF86XK_Forward, Qt::Key_Forward, + XF86XK_Stop, Qt::Key_Stop, + XF86XK_Refresh, Qt::Key_Refresh, + XF86XK_Favorites, Qt::Key_Favorites, + XF86XK_AudioMedia, Qt::Key_LaunchMedia, + XF86XK_OpenURL, Qt::Key_OpenUrl, + XF86XK_HomePage, Qt::Key_HomePage, + XF86XK_Search, Qt::Key_Search, + XF86XK_AudioLowerVolume, Qt::Key_VolumeDown, + XF86XK_AudioMute, Qt::Key_VolumeMute, + XF86XK_AudioRaiseVolume, Qt::Key_VolumeUp, + XF86XK_AudioPlay, Qt::Key_MediaPlay, + XF86XK_AudioStop, Qt::Key_MediaStop, + XF86XK_AudioPrev, Qt::Key_MediaPrevious, + XF86XK_AudioNext, Qt::Key_MediaNext, + XF86XK_AudioRecord, Qt::Key_MediaRecord, + XF86XK_Mail, Qt::Key_LaunchMail, + XF86XK_MyComputer, Qt::Key_Launch0, // ### Qt 5: remap properly + XF86XK_Calculator, Qt::Key_Launch1, + XF86XK_Memo, Qt::Key_Memo, + XF86XK_ToDoList, Qt::Key_ToDoList, + XF86XK_Calendar, Qt::Key_Calendar, + XF86XK_PowerDown, Qt::Key_PowerDown, + XF86XK_ContrastAdjust, Qt::Key_ContrastAdjust, + XF86XK_Standby, Qt::Key_Standby, + XF86XK_MonBrightnessUp, Qt::Key_MonBrightnessUp, + XF86XK_MonBrightnessDown, Qt::Key_MonBrightnessDown, + XF86XK_KbdLightOnOff, Qt::Key_KeyboardLightOnOff, + XF86XK_KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp, + XF86XK_KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown, + XF86XK_PowerOff, Qt::Key_PowerOff, + XF86XK_WakeUp, Qt::Key_WakeUp, + XF86XK_Eject, Qt::Key_Eject, + XF86XK_ScreenSaver, Qt::Key_ScreenSaver, + XF86XK_WWW, Qt::Key_WWW, + XF86XK_Sleep, Qt::Key_Sleep, + XF86XK_LightBulb, Qt::Key_LightBulb, + XF86XK_Shop, Qt::Key_Shop, + XF86XK_History, Qt::Key_History, + XF86XK_AddFavorite, Qt::Key_AddFavorite, + XF86XK_HotLinks, Qt::Key_HotLinks, + XF86XK_BrightnessAdjust, Qt::Key_BrightnessAdjust, + XF86XK_Finance, Qt::Key_Finance, + XF86XK_Community, Qt::Key_Community, + XF86XK_AudioRewind, Qt::Key_AudioRewind, + XF86XK_BackForward, Qt::Key_BackForward, + XF86XK_ApplicationLeft, Qt::Key_ApplicationLeft, + XF86XK_ApplicationRight, Qt::Key_ApplicationRight, + XF86XK_Book, Qt::Key_Book, + XF86XK_CD, Qt::Key_CD, + XF86XK_Calculater, Qt::Key_Calculator, + XF86XK_Clear, Qt::Key_Clear, + XF86XK_ClearGrab, Qt::Key_ClearGrab, + XF86XK_Close, Qt::Key_Close, + XF86XK_Copy, Qt::Key_Copy, + XF86XK_Cut, Qt::Key_Cut, + XF86XK_Display, Qt::Key_Display, + XF86XK_DOS, Qt::Key_DOS, + XF86XK_Documents, Qt::Key_Documents, + XF86XK_Excel, Qt::Key_Excel, + XF86XK_Explorer, Qt::Key_Explorer, + XF86XK_Game, Qt::Key_Game, + XF86XK_Go, Qt::Key_Go, + XF86XK_iTouch, Qt::Key_iTouch, + XF86XK_LogOff, Qt::Key_LogOff, + XF86XK_Market, Qt::Key_Market, + XF86XK_Meeting, Qt::Key_Meeting, + XF86XK_MenuKB, Qt::Key_MenuKB, + XF86XK_MenuPB, Qt::Key_MenuPB, + XF86XK_MySites, Qt::Key_MySites, + XF86XK_News, Qt::Key_News, + XF86XK_OfficeHome, Qt::Key_OfficeHome, + XF86XK_Option, Qt::Key_Option, + XF86XK_Paste, Qt::Key_Paste, + XF86XK_Phone, Qt::Key_Phone, + XF86XK_Reply, Qt::Key_Reply, + XF86XK_Reload, Qt::Key_Reload, + XF86XK_RotateWindows, Qt::Key_RotateWindows, + XF86XK_RotationPB, Qt::Key_RotationPB, + XF86XK_RotationKB, Qt::Key_RotationKB, + XF86XK_Save, Qt::Key_Save, + XF86XK_Send, Qt::Key_Send, + XF86XK_Spell, Qt::Key_Spell, + XF86XK_SplitScreen, Qt::Key_SplitScreen, + XF86XK_Support, Qt::Key_Support, + XF86XK_TaskPane, Qt::Key_TaskPane, + XF86XK_Terminal, Qt::Key_Terminal, + XF86XK_Tools, Qt::Key_Tools, + XF86XK_Travel, Qt::Key_Travel, + XF86XK_Video, Qt::Key_Video, + XF86XK_Word, Qt::Key_Word, + XF86XK_Xfer, Qt::Key_Xfer, + XF86XK_ZoomIn, Qt::Key_ZoomIn, + XF86XK_ZoomOut, Qt::Key_ZoomOut, + XF86XK_Away, Qt::Key_Away, + XF86XK_Messenger, Qt::Key_Messenger, + XF86XK_WebCam, Qt::Key_WebCam, + XF86XK_MailForward, Qt::Key_MailForward, + XF86XK_Pictures, Qt::Key_Pictures, + XF86XK_Music, Qt::Key_Music, + XF86XK_Battery, Qt::Key_Battery, + XF86XK_Bluetooth, Qt::Key_Bluetooth, + XF86XK_WLAN, Qt::Key_WLAN, + XF86XK_UWB, Qt::Key_UWB, + XF86XK_AudioForward, Qt::Key_AudioForward, + XF86XK_AudioRepeat, Qt::Key_AudioRepeat, + XF86XK_AudioRandomPlay, Qt::Key_AudioRandomPlay, + XF86XK_Subtitle, Qt::Key_Subtitle, + XF86XK_AudioCycleTrack, Qt::Key_AudioCycleTrack, + XF86XK_Time, Qt::Key_Time, + XF86XK_Select, Qt::Key_Select, + XF86XK_View, Qt::Key_View, + XF86XK_TopMenu, Qt::Key_TopMenu, + XF86XK_Bluetooth, Qt::Key_Bluetooth, + XF86XK_Suspend, Qt::Key_Suspend, + XF86XK_Hibernate, Qt::Key_Hibernate, + XF86XK_Launch0, Qt::Key_Launch2, // ### Qt 5: remap properly + XF86XK_Launch1, Qt::Key_Launch3, + XF86XK_Launch2, Qt::Key_Launch4, + XF86XK_Launch3, Qt::Key_Launch5, + XF86XK_Launch4, Qt::Key_Launch6, + XF86XK_Launch5, Qt::Key_Launch7, + XF86XK_Launch6, Qt::Key_Launch8, + XF86XK_Launch7, Qt::Key_Launch9, + XF86XK_Launch8, Qt::Key_LaunchA, + XF86XK_Launch9, Qt::Key_LaunchB, + XF86XK_LaunchA, Qt::Key_LaunchC, + XF86XK_LaunchB, Qt::Key_LaunchD, + XF86XK_LaunchC, Qt::Key_LaunchE, + XF86XK_LaunchD, Qt::Key_LaunchF, + XF86XK_LaunchE, Qt::Key_LaunchG, + XF86XK_LaunchF, Qt::Key_LaunchH, + + // Qtopia keys + QTOPIAXK_Select, Qt::Key_Select, + QTOPIAXK_Yes, Qt::Key_Yes, + QTOPIAXK_No, Qt::Key_No, + QTOPIAXK_Cancel, Qt::Key_Cancel, + QTOPIAXK_Printer, Qt::Key_Printer, + QTOPIAXK_Execute, Qt::Key_Execute, + QTOPIAXK_Sleep, Qt::Key_Sleep, + QTOPIAXK_Play, Qt::Key_Play, + QTOPIAXK_Zoom, Qt::Key_Zoom, + QTOPIAXK_Context1, Qt::Key_Context1, + QTOPIAXK_Context2, Qt::Key_Context2, + QTOPIAXK_Context3, Qt::Key_Context3, + QTOPIAXK_Context4, Qt::Key_Context4, + QTOPIAXK_Call, Qt::Key_Call, + QTOPIAXK_Hangup, Qt::Key_Hangup, + QTOPIAXK_Flip, Qt::Key_Flip, + + 0, 0 +}; + +static const unsigned short katakanaKeysymsToUnicode[] = { + 0x0000, 0x3002, 0x300C, 0x300D, 0x3001, 0x30FB, 0x30F2, 0x30A1, + 0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30E3, 0x30E5, 0x30E7, 0x30C3, + 0x30FC, 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD, + 0x30AF, 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, + 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, 0x30CB, 0x30CC, + 0x30CD, 0x30CE, 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, 0x30DE, + 0x30DF, 0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9, + 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F3, 0x309B, 0x309C +}; + +static const unsigned short cyrillicKeysymsToUnicode[] = { + 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0000, 0x045e, 0x045f, + 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0000, 0x040e, 0x040f, + 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, + 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a, + 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, + 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a +}; + +static const unsigned short greekKeysymsToUnicode[] = { + 0x0000, 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, + 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, + 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, + 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, + 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7, + 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static const unsigned short technicalKeysymsToUnicode[] = { + 0x0000, 0x23B7, 0x250C, 0x2500, 0x2320, 0x2321, 0x2502, 0x23A1, + 0x23A3, 0x23A4, 0x23A6, 0x239B, 0x239D, 0x239E, 0x23A0, 0x23A8, + 0x23AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222B, + 0x2234, 0x221D, 0x221E, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000, + 0x223C, 0x2243, 0x0000, 0x0000, 0x0000, 0x21D4, 0x21D2, 0x2261, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221A, 0x0000, + 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222A, 0x2227, 0x2228, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2202, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, + 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193, 0x0000 +}; + +static const unsigned short specialKeysymsToUnicode[] = { + 0x25C6, 0x2592, 0x2409, 0x240C, 0x240D, 0x240A, 0x0000, 0x0000, + 0x2424, 0x240B, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x23BA, + 0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251C, 0x2524, 0x2534, 0x252C, + 0x2502, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static const unsigned short publishingKeysymsToUnicode[] = { + 0x0000, 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, + 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, + 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, + 0x2105, 0x0000, 0x0000, 0x2012, 0x2329, 0x0000, 0x232a, 0x0000, + 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000, + 0x0000, 0x2122, 0x2613, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25af, + 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033, + 0x0000, 0x271d, 0x0000, 0x25ac, 0x25c0, 0x25b6, 0x25cf, 0x25ae, + 0x25e6, 0x25ab, 0x25ad, 0x25b3, 0x25bd, 0x2606, 0x2022, 0x25aa, + 0x25b2, 0x25bc, 0x261c, 0x261e, 0x2663, 0x2666, 0x2665, 0x0000, + 0x2720, 0x2020, 0x2021, 0x2713, 0x2717, 0x266f, 0x266d, 0x2642, + 0x2640, 0x260e, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e, 0x0000 +}; + +static const unsigned short aplKeysymsToUnicode[] = { + 0x0000, 0x0000, 0x0000, 0x003c, 0x0000, 0x0000, 0x003e, 0x0000, + 0x2228, 0x2227, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00af, 0x0000, 0x22a5, 0x2229, 0x230a, 0x0000, 0x005f, 0x0000, + 0x0000, 0x0000, 0x2218, 0x0000, 0x2395, 0x0000, 0x22a4, 0x25cb, + 0x0000, 0x0000, 0x0000, 0x2308, 0x0000, 0x0000, 0x222a, 0x0000, + 0x2283, 0x0000, 0x2282, 0x0000, 0x22a2, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x22a3, 0x0000, 0x0000, 0x0000 +}; + +static const unsigned short koreanKeysymsToUnicode[] = { + 0x0000, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, + 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f, + 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147, + 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x314f, + 0x3150, 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156, 0x3157, + 0x3158, 0x3159, 0x315a, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, + 0x3160, 0x3161, 0x3162, 0x3163, 0x11a8, 0x11a9, 0x11aa, 0x11ab, + 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3, + 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, + 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x316d, + 0x3171, 0x3178, 0x317f, 0x3181, 0x3184, 0x3186, 0x318d, 0x318e, + 0x11eb, 0x11f0, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9 +}; + +static QChar keysymToUnicode(unsigned char byte3, unsigned char byte4) +{ + switch (byte3) { + case 0x04: + // katakana + if (byte4 > 0xa0 && byte4 < 0xe0) + return QChar(katakanaKeysymsToUnicode[byte4 - 0xa0]); + else if (byte4 == 0x7e) + return QChar(0x203e); // Overline + break; + case 0x06: + // russian, use lookup table + if (byte4 > 0xa0) + return QChar(cyrillicKeysymsToUnicode[byte4 - 0xa0]); + break; + case 0x07: + // greek + if (byte4 > 0xa0) + return QChar(greekKeysymsToUnicode[byte4 - 0xa0]); + break; + case 0x08: + // technical + if (byte4 > 0xa0) + return QChar(technicalKeysymsToUnicode[byte4 - 0xa0]); + break; + case 0x09: + // special + if (byte4 >= 0xe0) + return QChar(specialKeysymsToUnicode[byte4 - 0xe0]); + break; + case 0x0a: + // publishing + if (byte4 > 0xa0) + return QChar(publishingKeysymsToUnicode[byte4 - 0xa0]); + break; + case 0x0b: + // APL + if (byte4 > 0xa0) + return QChar(aplKeysymsToUnicode[byte4 - 0xa0]); + break; + case 0x0e: + // Korean + if (byte4 > 0xa0) + return QChar(koreanKeysymsToUnicode[byte4 - 0xa0]); + break; + default: + break; + } + return QChar(0x0); +} + +Qt::KeyboardModifiers QXlibKeyboard::translateModifiers(int s) +{ + Qt::KeyboardModifiers ret = 0; + if (s & ShiftMask) + ret |= Qt::ShiftModifier; + if (s & ControlMask) + ret |= Qt::ControlModifier; + if (s & m_alt_mask) + ret |= Qt::AltModifier; + if (s & m_meta_mask) + ret |= Qt::MetaModifier; +// if (s & m_mode_switch_mask) //doesn't seem to work correctly +// ret |= Qt::GroupSwitchModifier; + return ret; +} + +void QXlibKeyboard::setMask(KeySym sym, uint mask) +{ + if (m_alt_mask == 0 + && m_meta_mask != mask + && m_super_mask != mask + && m_hyper_mask != mask + && (sym == XK_Alt_L || sym == XK_Alt_R)) { + m_alt_mask = mask; + } + if (m_meta_mask == 0 + && m_alt_mask != mask + && m_super_mask != mask + && m_hyper_mask != mask + && (sym == XK_Meta_L || sym == XK_Meta_R)) { + m_meta_mask = mask; + } + if (m_super_mask == 0 + && m_alt_mask != mask + && m_meta_mask != mask + && m_hyper_mask != mask + && (sym == XK_Super_L || sym == XK_Super_R)) { + m_super_mask = mask; + } + if (m_hyper_mask == 0 + && m_alt_mask != mask + && m_meta_mask != mask + && m_super_mask != mask + && (sym == XK_Hyper_L || sym == XK_Hyper_R)) { + m_hyper_mask = mask; + } + if (m_mode_switch_mask == 0 + && m_alt_mask != mask + && m_meta_mask != mask + && m_super_mask != mask + && m_hyper_mask != mask + && sym == XK_Mode_switch) { + m_mode_switch_mask = mask; + } + if (m_num_lock_mask == 0 + && sym == XK_Num_Lock) { + m_num_lock_mask = mask; + } +} + +int QXlibKeyboard::translateKeySym(uint key) const +{ + int code = -1; + int i = 0; // any other keys + while (KeyTbl[i]) { + if (key == KeyTbl[i]) { + code = (int)KeyTbl[i+1]; + break; + } + i += 2; + } + if (m_meta_mask) { + // translate Super/Hyper keys to Meta if we're using them as the MetaModifier + if (m_meta_mask == m_super_mask && (code == Qt::Key_Super_L || code == Qt::Key_Super_R)) { + code = Qt::Key_Meta; + } else if (m_meta_mask == m_hyper_mask && (code == Qt::Key_Hyper_L || code == Qt::Key_Hyper_R)) { + code = Qt::Key_Meta; + } + } + return code; +} + +QString QXlibKeyboard::translateKeySym(KeySym keysym, uint xmodifiers, + int &code, Qt::KeyboardModifiers &modifiers, + QByteArray &chars, int &count) +{ + // all keysyms smaller than 0xff00 are actally keys that can be mapped to unicode chars + + QTextCodec *mapper = QTextCodec::codecForLocale(); + QChar converted; + + if (/*count == 0 &&*/ keysym < 0xff00) { + unsigned char byte3 = (unsigned char)(keysym >> 8); + int mib = -1; + switch(byte3) { + case 0: // Latin 1 + case 1: // Latin 2 + case 2: //latin 3 + case 3: // latin4 + mib = byte3 + 4; break; + case 5: // arabic + mib = 82; break; + case 12: // Hebrew + mib = 85; break; + case 13: // Thai + mib = 2259; break; + case 4: // kana + case 6: // cyrillic + case 7: // greek + case 8: // technical, no mapping here at the moment + case 9: // Special + case 10: // Publishing + case 11: // APL + case 14: // Korean, no mapping + mib = -1; // manual conversion + mapper= 0; +#if !defined(QT_NO_XIM) + converted = keysymToUnicode(byte3, keysym & 0xff); +#endif + case 0x20: + // currency symbols + if (keysym >= 0x20a0 && keysym <= 0x20ac) { + mib = -1; // manual conversion + mapper = 0; + converted = (uint)keysym; + } + break; + default: + break; + } + if (mib != -1) { + mapper = QTextCodec::codecForMib(mib); + if (chars.isEmpty()) + chars.resize(1); + chars[0] = (unsigned char) (keysym & 0xff); // get only the fourth bit for conversion later + count = 1; + } + } else if (keysym >= 0x1000000 && keysym <= 0x100ffff) { + converted = (ushort) (keysym - 0x1000000); + mapper = 0; + } + if (count < (int)chars.size()-1) + chars[count] = '\0'; + + QString text; + if (!mapper && converted.unicode() != 0x0) { + text = converted; + } else if (!chars.isEmpty()) { + // convert chars (8bit) to text (unicode). + if (mapper) + text = mapper->toUnicode(chars.data(), count, 0); + if (text.isEmpty()) { + // no mapper, or codec couldn't convert to unicode (this + // can happen when running in the C locale or with no LANG + // set). try converting from latin-1 + text = QString::fromLatin1(chars); + } + } + + modifiers = translateModifiers(xmodifiers); + + // Commentary in X11/keysymdef says that X codes match ASCII, so it + // is safe to use the locale functions to process X codes in ISO8859-1. + // + // This is mainly for compatibility - applications should not use the + // Qt keycodes between 128 and 255, but should rather use the + // QKeyEvent::text(). + // + if (keysym < 128 || (keysym < 256 && (!mapper || mapper->mibEnum()==4))) { + // upper-case key, if known + code = isprint((int)keysym) ? toupper((int)keysym) : 0; + } else if (keysym >= XK_F1 && keysym <= XK_F35) { + // function keys + code = Qt::Key_F1 + ((int)keysym - XK_F1); + } else if (keysym >= XK_KP_Space && keysym <= XK_KP_9) { + if (keysym >= XK_KP_0) { + // numeric keypad keys + code = Qt::Key_0 + ((int)keysym - XK_KP_0); + } else { + code = translateKeySym(keysym); + } + modifiers |= Qt::KeypadModifier; + } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f && text.unicode()->unicode() != 0x7f && !(keysym >= XK_dead_grave && keysym <= XK_dead_horn)) { + code = text.unicode()->toUpper().unicode(); + } else { + // any other keys + code = translateKeySym(keysym); + + if (code == Qt::Key_Tab && (modifiers & Qt::ShiftModifier)) { + // map shift+tab to shift+backtab, QShortcutMap knows about it + // and will handle it. + code = Qt::Key_Backtab; + text = QString(); + } + } + + return text; +} + +QXlibKeyboard::QXlibKeyboard(QXlibScreen *screen) + : m_screen(screen) + , m_alt_mask(0) + , m_super_mask(0) + , m_hyper_mask(0) + , m_meta_mask(0) +{ + changeLayout(); +} + +void QXlibKeyboard::changeLayout() +{ + XkbDescPtr xkbDesc = XkbGetMap(m_screen->display(), XkbAllClientInfoMask, XkbUseCoreKbd); + for (int i = xkbDesc->min_key_code; i < xkbDesc->max_key_code; ++i) { + const uint mask = xkbDesc->map->modmap ? xkbDesc->map->modmap[i] : 0; + if (mask == 0) { + // key is not bound to a modifier + continue; + } + + for (int j = 0; j < XkbKeyGroupsWidth(xkbDesc, i); ++j) { + KeySym keySym = XkbKeySym(xkbDesc, i, j); + if (keySym == NoSymbol) + continue; + setMask(keySym, mask); + } + } + XkbFreeKeyboard(xkbDesc, XkbAllComponentsMask, true); + +} + +static Qt::KeyboardModifiers modifierFromKeyCode(int qtcode) +{ + switch (qtcode) { + case Qt::Key_Control: + return Qt::ControlModifier; + case Qt::Key_Alt: + return Qt::AltModifier; + case Qt::Key_Shift: + return Qt::ShiftModifier; + case Qt::Key_Meta: + return Qt::MetaModifier; + default: + return Qt::NoModifier; + } +} + +void QXlibKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, XKeyEvent *ev) +{ + int qtcode = 0; + Qt::KeyboardModifiers modifiers = translateModifiers(ev->state); + QByteArray chars; + chars.resize(513); + int count = 0; + KeySym keySym; + count = XLookupString(ev,chars.data(),chars.size(),&keySym,0); + QString text = translateKeySym(keySym,ev->state,qtcode,modifiers,chars,count); + QWindowSystemInterface::handleKeyEvent(widget,ev->time,type,qtcode,modifiers,text.left(count)); +} diff --git a/src/plugins/platforms/xlib/qtestlitekeyboard.h b/src/plugins/platforms/xlib/qtestlitekeyboard.h new file mode 100644 index 0000000..98df4e1 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitekeyboard.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTESTLITEKEYBOARD_H +#define QTESTLITEKEYBOARD_H + +#include "qtestliteintegration.h" + +class QXlibKeyboard +{ +public: + QXlibKeyboard(QXlibScreen *screen); + + void changeLayout(); + + void handleKeyEvent(QWidget *widget, QEvent::Type type, XKeyEvent *ev); + + Qt::KeyboardModifiers translateModifiers(int s); + +private: + + void setMask(KeySym sym, uint mask); + int translateKeySym(uint key) const; + QString translateKeySym(KeySym keysym, uint xmodifiers, + int &code, Qt::KeyboardModifiers &modifiers, + QByteArray &chars, int &count); + + QXlibScreen *m_screen; + + uint m_alt_mask; + uint m_super_mask; + uint m_hyper_mask; + uint m_meta_mask; + uint m_mode_switch_mask; + uint m_num_lock_mask; +}; + +#endif // QTESTLITEKEYBOARD_H diff --git a/src/plugins/platforms/xlib/qtestlitemime.cpp b/src/plugins/platforms/xlib/qtestlitemime.cpp new file mode 100644 index 0000000..5335ae9 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitemime.cpp @@ -0,0 +1,322 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestlitemime.h" + +#include "qtestlitestaticinfo.h" +#include "qtestlitescreen.h" + +#include <QtCore/QTextCodec> +#include <QtGui/QImageWriter> +#include <QtCore/QBuffer> + +QXlibMime::QXlibMime() + : QInternalMimeData() +{ } + +QXlibMime::~QXlibMime() +{} + + + + + +QString QXlibMime::mimeAtomToString(Display *display, Atom a) +{ + if (!a) return 0; + + if (a == XA_STRING || a == QXlibStatic::atom(QXlibStatic::UTF8_STRING)) { + return "text/plain"; // some Xdnd clients are dumb + } + char *atom = XGetAtomName(display, a); + QString result = QString::fromLatin1(atom); + XFree(atom); + return result; +} + +Atom QXlibMime::mimeStringToAtom(Display *display, const QString &mimeType) +{ + if (mimeType.isEmpty()) + return 0; + return XInternAtom(display, mimeType.toLatin1().constData(), False); +} + +QStringList QXlibMime::mimeFormatsForAtom(Display *display, Atom a) +{ + QStringList formats; + if (a) { + QString atomName = mimeAtomToString(display, a); + formats.append(atomName); + + // special cases for string type + if (a == QXlibStatic::atom(QXlibStatic::UTF8_STRING) + || a == XA_STRING + || a == QXlibStatic::atom(QXlibStatic::TEXT) + || a == QXlibStatic::atom(QXlibStatic::COMPOUND_TEXT)) + formats.append(QLatin1String("text/plain")); + + // special cases for uris + if (atomName == QLatin1String("text/x-moz-url")) + formats.append(QLatin1String("text/uri-list")); + + // special case for images + if (a == XA_PIXMAP) + formats.append(QLatin1String("image/ppm")); + } + return formats; +} + +bool QXlibMime::mimeDataForAtom(Display *display, Atom a, QMimeData *mimeData, QByteArray *data, Atom *atomFormat, int *dataFormat) +{ + bool ret = false; + *atomFormat = a; + *dataFormat = 8; + QString atomName = mimeAtomToString(display, a); + if (QInternalMimeData::hasFormatHelper(atomName, mimeData)) { + *data = QInternalMimeData::renderDataHelper(atomName, mimeData); + if (atomName == QLatin1String("application/x-color")) + *dataFormat = 16; + ret = true; + } else { + if ((a == QXlibStatic::atom(QXlibStatic::UTF8_STRING) + || a == XA_STRING + || a == QXlibStatic::atom(QXlibStatic::TEXT) + || a == QXlibStatic::atom(QXlibStatic::COMPOUND_TEXT)) + && QInternalMimeData::hasFormatHelper(QLatin1String("text/plain"), mimeData)) { + if (a == QXlibStatic::atom(QXlibStatic::UTF8_STRING)){ + *data = QInternalMimeData::renderDataHelper(QLatin1String("text/plain"), mimeData); + ret = true; + } else if (a == XA_STRING) { + *data = QString::fromUtf8(QInternalMimeData::renderDataHelper( + QLatin1String("text/plain"), mimeData)).toLocal8Bit(); + ret = true; + } else if (a == QXlibStatic::atom(QXlibStatic::TEXT) + || a == QXlibStatic::atom(QXlibStatic::COMPOUND_TEXT)) { + // the ICCCM states that TEXT and COMPOUND_TEXT are in the + // encoding of choice, so we choose the encoding of the locale + QByteArray strData = QString::fromUtf8(QInternalMimeData::renderDataHelper( + QLatin1String("text/plain"), mimeData)).toLocal8Bit(); + char *list[] = { strData.data(), NULL }; + + XICCEncodingStyle style = (a == QXlibStatic::atom(QXlibStatic::COMPOUND_TEXT)) + ? XCompoundTextStyle : XStdICCTextStyle; + XTextProperty textprop; + if (list[0] != NULL + && XmbTextListToTextProperty(display, list, 1, style, + &textprop) == Success) { + *atomFormat = textprop.encoding; + *dataFormat = textprop.format; + *data = QByteArray((const char *) textprop.value, textprop.nitems * textprop.format / 8); + ret = true; + + XFree(textprop.value); + } + } + } else if (atomName == QLatin1String("text/x-moz-url") && + QInternalMimeData::hasFormatHelper(QLatin1String("text/uri-list"), mimeData)) { + QByteArray uri = QInternalMimeData::renderDataHelper( + QLatin1String("text/uri-list"), mimeData).split('\n').first(); + QString mozUri = QString::fromLatin1(uri, uri.size()); + mozUri += QLatin1Char('\n'); + *data = QByteArray(reinterpret_cast<const char *>(mozUri.utf16()), mozUri.length() * 2); + ret = true; + } else if ((a == XA_PIXMAP || a == XA_BITMAP) && mimeData->hasImage()) { + ret = true; + } + } + return ret && data != 0; +} + +QList<Atom> QXlibMime::mimeAtomsForFormat(Display *display, const QString &format) +{ + QList<Atom> atoms; + atoms.append(mimeStringToAtom(display, format)); + + // special cases for strings + if (format == QLatin1String("text/plain")) { + atoms.append(QXlibStatic::atom(QXlibStatic::UTF8_STRING)); + atoms.append(XA_STRING); + atoms.append(QXlibStatic::atom(QXlibStatic::TEXT)); + atoms.append(QXlibStatic::atom(QXlibStatic::COMPOUND_TEXT)); + } + + // special cases for uris + if (format == QLatin1String("text/uri-list")) { + atoms.append(mimeStringToAtom(display,QLatin1String("text/x-moz-url"))); + } + + //special cases for images + if (format == QLatin1String("image/ppm")) + atoms.append(XA_PIXMAP); + if (format == QLatin1String("image/pbm")) + atoms.append(XA_BITMAP); + + return atoms; +} + +QVariant QXlibMime::mimeConvertToFormat(Display *display, Atom a, const QByteArray &data, const QString &format, QVariant::Type requestedType, const QByteArray &encoding) +{ + QString atomName = mimeAtomToString(display,a); + if (atomName == format) + return data; + + if (!encoding.isEmpty() + && atomName == format + QLatin1String(";charset=") + QString::fromLatin1(encoding)) { + + if (requestedType == QVariant::String) { + QTextCodec *codec = QTextCodec::codecForName(encoding); + if (codec) + return codec->toUnicode(data); + } + + return data; + } + + // special cases for string types + if (format == QLatin1String("text/plain")) { + if (a == QXlibStatic::atom(QXlibStatic::UTF8_STRING)) + return QString::fromUtf8(data); + if (a == XA_STRING) + return QString::fromLatin1(data); + if (a == QXlibStatic::atom(QXlibStatic::TEXT) + || a == QXlibStatic::atom(QXlibStatic::COMPOUND_TEXT)) + // #### might be wrong for COMPUND_TEXT + return QString::fromLocal8Bit(data, data.size()); + } + + // special case for uri types + if (format == QLatin1String("text/uri-list")) { + if (atomName == QLatin1String("text/x-moz-url")) { + // we expect this as utf16 <url><space><title> + // the first part is a url that should only contain ascci char + // so it should be safe to check that the second char is 0 + // to verify that it is utf16 + if (data.size() > 1 && data.at(1) == 0) + return QString::fromRawData((const QChar *)data.constData(), + data.size() / 2).split(QLatin1Char('\n')).first().toLatin1(); + } + } + + // special cas for images + if (format == QLatin1String("image/ppm")) { + if (a == XA_PIXMAP && data.size() == sizeof(Pixmap)) { + Pixmap xpm = *((Pixmap*)data.data()); + if (!xpm) + return QByteArray(); + Window root; + int x; + int y; + uint width; + uint height; + uint border_width; + uint depth; + + XGetGeometry(display, xpm, &root, &x, &y, &width, &height, &border_width, &depth); + XImage *ximg = XGetImage(display,xpm,x,y,width,height,AllPlanes,depth==1 ? XYPixmap : ZPixmap); + QImage qimg = QXlibStatic::qimageFromXImage(ximg); + XDestroyImage(ximg); + + QImageWriter imageWriter; + imageWriter.setFormat("PPMRAW"); + QBuffer buf; + buf.open(QIODevice::WriteOnly); + imageWriter.setDevice(&buf); + imageWriter.write(qimg); + return buf.buffer(); + } + } + return QVariant(); +} + +Atom QXlibMime::mimeAtomForFormat(Display *display, const QString &format, QVariant::Type requestedType, const QList<Atom> &atoms, QByteArray *requestedEncoding) +{ + requestedEncoding->clear(); + + // find matches for string types + if (format == QLatin1String("text/plain")) { + if (atoms.contains(QXlibStatic::atom(QXlibStatic::UTF8_STRING))) + return QXlibStatic::atom(QXlibStatic::UTF8_STRING); + if (atoms.contains(QXlibStatic::atom(QXlibStatic::COMPOUND_TEXT))) + return QXlibStatic::atom(QXlibStatic::COMPOUND_TEXT); + if (atoms.contains(QXlibStatic::atom(QXlibStatic::TEXT))) + return QXlibStatic::atom(QXlibStatic::TEXT); + if (atoms.contains(XA_STRING)) + return XA_STRING; + } + + // find matches for uri types + if (format == QLatin1String("text/uri-list")) { + Atom a = mimeStringToAtom(display,format); + if (a && atoms.contains(a)) + return a; + a = mimeStringToAtom(display,QLatin1String("text/x-moz-url")); + if (a && atoms.contains(a)) + return a; + } + + // find match for image + if (format == QLatin1String("image/ppm")) { + if (atoms.contains(XA_PIXMAP)) + return XA_PIXMAP; + } + + // for string/text requests try to use a format with a well-defined charset + // first to avoid encoding problems + if (requestedType == QVariant::String + && format.startsWith(QLatin1String("text/")) + && !format.contains(QLatin1String("charset="))) { + + QString formatWithCharset = format; + formatWithCharset.append(QLatin1String(";charset=utf-8")); + + Atom a = mimeStringToAtom(display,formatWithCharset); + if (a && atoms.contains(a)) { + *requestedEncoding = "utf-8"; + return a; + } + } + + Atom a = mimeStringToAtom(display,format); + if (a && atoms.contains(a)) + return a; + + return 0; +} diff --git a/src/plugins/platforms/xlib/qtestlitemime.h b/src/plugins/platforms/xlib/qtestlitemime.h new file mode 100644 index 0000000..6a70ea4 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitemime.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTESTLITEMIME_H +#define QTESTLITEMIME_H + +#include <private/qdnd_p.h> + +#include <QtGui/QClipboard> + +#include "qtestliteintegration.h" +#include "qtestliteclipboard.h" + +class QXlibMime : public QInternalMimeData { + Q_OBJECT +public: + QXlibMime(); + ~QXlibMime(); + + static QList<Atom> mimeAtomsForFormat(Display *display, const QString &format); + static QString mimeAtomToString(Display *display, Atom a); + static bool mimeDataForAtom(Display *display, Atom a, QMimeData *mimeData, QByteArray *data, Atom *atomFormat, int *dataFormat); + static QStringList mimeFormatsForAtom(Display *display, Atom a); + static Atom mimeStringToAtom(Display *display, const QString &mimeType); + static QVariant mimeConvertToFormat(Display *display, Atom a, const QByteArray &data, const QString &format, QVariant::Type requestedType, const QByteArray &encoding); + static Atom mimeAtomForFormat(Display *display, const QString &format, QVariant::Type requestedType, const QList<Atom> &atoms, QByteArray *requestedEncoding); +}; + +#endif // QTESTLITEMIME_H diff --git a/src/plugins/platforms/xlib/qtestlitescreen.cpp b/src/plugins/platforms/xlib/qtestlitescreen.cpp new file mode 100644 index 0000000..714c17b --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitescreen.cpp @@ -0,0 +1,468 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestlitescreen.h" + +#include "qtestlitecursor.h" +#include "qtestlitewindow.h" +#include "qtestlitekeyboard.h" +#include "qtestlitestaticinfo.h" +#include "qtestliteclipboard.h" + +#include <QtCore/QDebug> +#include <QtCore/QSocketNotifier> +#include <QtCore/QElapsedTimer> + +#include <private/qapplication_p.h> + +#include <X11/extensions/Xfixes.h> + +QT_BEGIN_NAMESPACE + +static int (*original_x_errhandler)(Display *dpy, XErrorEvent *); +static bool seen_badwindow; + +static int qt_x_errhandler(Display *dpy, XErrorEvent *err) +{ + +qDebug() << "qt_x_errhandler" << err->error_code; + + switch (err->error_code) { + case BadAtom: +#if 0 + if (err->request_code == 20 /* X_GetProperty */ + && (err->resourceid == XA_RESOURCE_MANAGER + || err->resourceid == XA_RGB_DEFAULT_MAP + || err->resourceid == ATOM(_NET_SUPPORTED) + || err->resourceid == ATOM(_NET_SUPPORTING_WM_CHECK) + || err->resourceid == ATOM(KDE_FULL_SESSION) + || err->resourceid == ATOM(KWIN_RUNNING) + || err->resourceid == ATOM(XdndProxy) + || err->resourceid == ATOM(XdndAware)) + + + ) { + // Perhaps we're running under SECURITY reduction? :/ + return 0; + } +#endif + qDebug() << "BadAtom"; + break; + + case BadWindow: + if (err->request_code == 2 /* X_ChangeWindowAttributes */ + || err->request_code == 38 /* X_QueryPointer */) { + for (int i = 0; i < ScreenCount(dpy); ++i) { + if (err->resourceid == RootWindow(dpy, i)) { + // Perhaps we're running under SECURITY reduction? :/ + return 0; + } + } + } + seen_badwindow = true; + if (err->request_code == 25 /* X_SendEvent */) { + for (int i = 0; i < ScreenCount(dpy); ++i) { + if (err->resourceid == RootWindow(dpy, i)) { + // Perhaps we're running under SECURITY reduction? :/ + return 0; + } + } +#if 0 + if (X11->xdndHandleBadwindow()) { + qDebug("xdndHandleBadwindow returned true"); + return 0; + } +#endif + } +#if 0 + if (X11->ignore_badwindow) + return 0; +#endif + break; + + case BadMatch: + if (err->request_code == 42 /* X_SetInputFocus */) + return 0; + break; + + default: +#if 0 //!defined(QT_NO_XINPUT) + if (err->request_code == X11->xinput_major + && err->error_code == (X11->xinput_errorbase + XI_BadDevice) + && err->minor_code == 3 /* X_OpenDevice */) { + return 0; + } +#endif + break; + } + + char errstr[256]; + XGetErrorText( dpy, err->error_code, errstr, 256 ); + char buffer[256]; + char request_str[256]; + qsnprintf(buffer, 256, "%d", err->request_code); + XGetErrorDatabaseText(dpy, "XRequest", buffer, "", request_str, 256); + if (err->request_code < 128) { + // X error for a normal protocol request + qWarning( "X Error: %s %d\n" + " Major opcode: %d (%s)\n" + " Resource id: 0x%lx", + errstr, err->error_code, + err->request_code, + request_str, + err->resourceid ); + } else { + // X error for an extension request + const char *extensionName = 0; +#if 0 + if (err->request_code == X11->xrender_major) + extensionName = "RENDER"; + else if (err->request_code == X11->xrandr_major) + extensionName = "RANDR"; + else if (err->request_code == X11->xinput_major) + extensionName = "XInputExtension"; + else if (err->request_code == X11->mitshm_major) + extensionName = "MIT-SHM"; +#endif + char minor_str[256]; + if (extensionName) { + qsnprintf(buffer, 256, "%s.%d", extensionName, err->minor_code); + XGetErrorDatabaseText(dpy, "XRequest", buffer, "", minor_str, 256); + } else { + extensionName = "Uknown extension"; + qsnprintf(minor_str, 256, "Unknown request"); + } + qWarning( "X Error: %s %d\n" + " Extension: %d (%s)\n" + " Minor opcode: %d (%s)\n" + " Resource id: 0x%lx", + errstr, err->error_code, + err->request_code, + extensionName, + err->minor_code, + minor_str, + err->resourceid ); + } + + // ### we really should distinguish between severe, non-severe and + // ### application specific errors + + return 0; +} + +QXlibScreen::QXlibScreen() + : mFormat(QImage::Format_RGB32) +{ + char *display_name = getenv("DISPLAY"); + mDisplay = XOpenDisplay(display_name); + mDisplayName = QString::fromLocal8Bit(display_name); + if (!mDisplay) { + fprintf(stderr, "Cannot connect to X server: %s\n", + display_name); + exit(1); + } + +#ifndef DONT_USE_MIT_SHM + Status MIT_SHM_extension_supported = XShmQueryExtension (mDisplay); + Q_ASSERT(MIT_SHM_extension_supported == True); +#endif + original_x_errhandler = XSetErrorHandler(qt_x_errhandler); + + if (qgetenv("DO_X_SYNCHRONIZE").toInt()) + XSynchronize(mDisplay, true); + + mScreen = DefaultScreen(mDisplay); + XSelectInput(mDisplay,rootWindow(), KeymapStateMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask); + int width = DisplayWidth(mDisplay, mScreen); + int height = DisplayHeight(mDisplay, mScreen); + mGeometry = QRect(0,0,width,height); + + int physicalWidth = DisplayWidthMM(mDisplay, mScreen); + int physicalHeight = DisplayHeightMM(mDisplay, mScreen); + mPhysicalSize = QSize(physicalWidth,physicalHeight); + + int xSocketNumber = XConnectionNumber(mDisplay); + + mDepth = DefaultDepth(mDisplay,mScreen); +#ifdef MYX11_DEBUG + qDebug() << "X socket:"<< xSocketNumber; +#endif + QSocketNotifier *sock = new QSocketNotifier(xSocketNumber, QSocketNotifier::Read, this); + connect(sock, SIGNAL(activated(int)), this, SLOT(eventDispatcher())); + + mCursor = new QXlibCursor(this); + mKeyboard = new QXlibKeyboard(this); +} + +QXlibScreen::~QXlibScreen() +{ + delete mCursor; + XCloseDisplay(mDisplay); +} + +#ifdef KeyPress +#undef KeyPress +#endif +#ifdef KeyRelease +#undef KeyRelease +#endif + +bool QXlibScreen::handleEvent(XEvent *xe) +{ + int quit = false; + QXlibWindow *platformWindow = 0; + QWidget *widget = QWidget::find(xe->xany.window); + if (widget) { + platformWindow = static_cast<QXlibWindow *>(widget->platformWindow()); + } + + Atom wmProtocolsAtom = QXlibStatic::atom(QXlibStatic::WM_PROTOCOLS); + Atom wmDeleteWindowAtom = QXlibStatic::atom(QXlibStatic::WM_DELETE_WINDOW); + switch (xe->type) { + + case ClientMessage: + if (xe->xclient.format == 32 && xe->xclient.message_type == wmProtocolsAtom) { + Atom a = xe->xclient.data.l[0]; + if (a == wmDeleteWindowAtom) + platformWindow->handleCloseEvent(); + } + break; + + case Expose: + if (platformWindow) + if (xe->xexpose.count == 0) + platformWindow->paintEvent(); + break; + case ConfigureNotify: + if (platformWindow) + platformWindow->resizeEvent(&xe->xconfigure); + break; + + case ButtonPress: + if (platformWindow) + platformWindow->mousePressEvent(&xe->xbutton); + break; + + case ButtonRelease: + if (platformWindow) + platformWindow->handleMouseEvent(QEvent::MouseButtonRelease, &xe->xbutton); + break; + + case MotionNotify: + if (platformWindow) + platformWindow->handleMouseEvent(QEvent::MouseMove, &xe->xbutton); + break; + + case XKeyPress: + mKeyboard->handleKeyEvent(widget,QEvent::KeyPress, &xe->xkey); + break; + + case XKeyRelease: + mKeyboard->handleKeyEvent(widget,QEvent::KeyRelease, &xe->xkey); + break; + + case EnterNotify: + if (platformWindow) + platformWindow->handleEnterEvent(); + break; + + case LeaveNotify: + if (platformWindow) + platformWindow->handleLeaveEvent(); + break; + + case XFocusIn: + if (platformWindow) + platformWindow->handleFocusInEvent(); + break; + + case XFocusOut: + if (platformWindow) + platformWindow->handleFocusOutEvent(); + break; + + case PropertyNotify: + break; + + case SelectionClear: + qDebug() << "Selection Clear!!!"; + break; + case SelectionRequest: + handleSelectionRequest(xe); + break; + case SelectionNotify: + qDebug() << "Selection Notify!!!!"; + + break; + + + default: +#ifdef MYX11_DEBUG + qDebug() << hex << xe->xany.window << "Other X event" << xe->type; +#endif + break; + } + + return quit; +} + +static Bool checkForClipboardEvents(Display *, XEvent *e, XPointer) +{ + Atom clipboard = QXlibStatic::atom(QXlibStatic::CLIPBOARD); + return ((e->type == SelectionRequest && (e->xselectionrequest.selection == XA_PRIMARY + || e->xselectionrequest.selection == clipboard)) + || (e->type == SelectionClear && (e->xselectionclear.selection == XA_PRIMARY + || e->xselectionclear.selection == clipboard))); +} + +bool QXlibScreen::waitForClipboardEvent(Window win, int type, XEvent *event, int timeout) +{ + QElapsedTimer timer; + timer.start(); + do { + if (XCheckTypedWindowEvent(mDisplay,win,type,event)) + return true; + + // process other clipboard events, since someone is probably requesting data from us + XEvent e; + if (XCheckIfEvent(mDisplay, &e, checkForClipboardEvents, 0)) + handleEvent(&e); + + XFlush(mDisplay); + + // sleep 50 ms, so we don't use up CPU cycles all the time. + struct timeval usleep_tv; + usleep_tv.tv_sec = 0; + usleep_tv.tv_usec = 50000; + select(0, 0, 0, 0, &usleep_tv); + } while (timer.elapsed() < timeout); + return false; +} + +void QXlibScreen::eventDispatcher() +{ + ulong marker = XNextRequest(mDisplay); + // int i = 0; + while (XPending(mDisplay)) { + XEvent event; + XNextEvent(mDisplay, &event); + /* done = */ + handleEvent(&event); + + if (event.xany.serial >= marker) { + #ifdef MYX11_DEBUG + qDebug() << "potential livelock averted"; + #endif + #if 0 + if (XEventsQueued(mDisplay, QueuedAfterFlush)) { + qDebug() << " with events queued"; + QTimer::singleShot(0, this, SLOT(eventDispatcher())); + } + #endif + break; + } + } +} + +QImage QXlibScreen::grabWindow(Window window, int x, int y, int w, int h) +{ + if (w == 0 || h ==0) + return QImage(); + + //WinId 0 means the desktop widget + if (!window) + window = rootWindow(); + + XWindowAttributes window_attr; + if (!XGetWindowAttributes(mDisplay, window, &window_attr)) + return QImage(); + + if (w < 0) + w = window_attr.width - x; + if (h < 0) + h = window_attr.height - y; + + // Ideally, we should also limit ourselves to the screen area, but the Qt docs say + // that it's "unsafe" to go outside the screen, so we can ignore that problem. + + //We're definitely not optimizing for speed... + XImage *xi = XGetImage(mDisplay, window, x, y, w, h, AllPlanes, ZPixmap); + + if (!xi) + return QImage(); + + //taking a copy to make sure we have ownership -- not fast + QImage result = QImage( (uchar*) xi->data, xi->width, xi->height, xi->bytes_per_line, QImage::Format_RGB32 ).copy(); + + XDestroyImage(xi); + + return result; +} + +QXlibScreen * QXlibScreen::testLiteScreenForWidget(QWidget *widget) +{ + QPlatformScreen *platformScreen = platformScreenForWidget(widget); + return static_cast<QXlibScreen *>(platformScreen); +} + +Display * QXlibScreen::display() const +{ + return mDisplay; +} + +int QXlibScreen::xScreenNumber() const +{ + return mScreen; +} + +QXlibKeyboard * QXlibScreen::keyboard() const +{ + return mKeyboard; +} + +void QXlibScreen::handleSelectionRequest(XEvent *event) +{ + QPlatformIntegration *integration = QApplicationPrivate::platformIntegration(); + QXlibClipboard *clipboard = static_cast<QXlibClipboard *>(integration->clipboard()); + clipboard->handleSelectionRequest(event); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qtestlitescreen.h b/src/plugins/platforms/xlib/qtestlitescreen.h new file mode 100644 index 0000000..7e59a59 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitescreen.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTESTLITESCREEN_H +#define QTESTLITESCREEN_H + +#include <QtGui/QPlatformScreen> +#include "qtestliteintegration.h" + +QT_BEGIN_NAMESPACE + +class QXlibCursor; +class QXlibKeyboard; + +class QXlibScreen : public QPlatformScreen +{ + Q_OBJECT +public: + QXlibScreen(); + + ~QXlibScreen(); + + QString displayName() const { return mDisplayName; } + + QRect geometry() const { return mGeometry; } + int depth() const { return mDepth; } + QImage::Format format() const { return mFormat; } + QSize physicalSize() const { return mPhysicalSize; } + + Window rootWindow() { return RootWindow(mDisplay, mScreen); } + unsigned long blackPixel() { return BlackPixel(mDisplay, mScreen); } + unsigned long whitePixel() { return WhitePixel(mDisplay, mScreen); } + + bool handleEvent(XEvent *xe); + bool waitForClipboardEvent(Window win, int type, XEvent *event, int timeout); + + QImage grabWindow(Window window, int x, int y, int w, int h); + + static QXlibScreen *testLiteScreenForWidget(QWidget *widget); + + Display *display() const; + int xScreenNumber() const; + + QXlibKeyboard *keyboard() const; + +public slots: + void eventDispatcher(); + +private: + + void handleSelectionRequest(XEvent *event); + QString mDisplayName; + QRect mGeometry; + QSize mPhysicalSize; + int mDepth; + QImage::Format mFormat; + QXlibCursor *mCursor; + QXlibKeyboard *mKeyboard; + + Display * mDisplay; + int mScreen; +}; + +QT_END_NAMESPACE + +#endif // QTESTLITESCREEN_H diff --git a/src/plugins/platforms/xlib/qtestlitestaticinfo.cpp b/src/plugins/platforms/xlib/qtestlitestaticinfo.cpp new file mode 100644 index 0000000..837636c --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitestaticinfo.cpp @@ -0,0 +1,511 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestlitestaticinfo.h" +#include "qtestlitescreen.h" + +#include <qplatformdefs.h> + +#include <QtGui/private/qapplication_p.h> +#include <QtCore/QBuffer> +#include <QtCore/QLibrary> + +#include <QDebug> + +#ifndef QT_NO_XFIXES +#include <X11/extensions/Xfixes.h> +#endif // QT_NO_XFIXES + +static const char * x11_atomnames = { + // window-manager <-> client protocols + "WM_PROTOCOLS\0" + "WM_DELETE_WINDOW\0" + "WM_TAKE_FOCUS\0" + "_NET_WM_PING\0" + "_NET_WM_CONTEXT_HELP\0" + "_NET_WM_SYNC_REQUEST\0" + "_NET_WM_SYNC_REQUEST_COUNTER\0" + + // ICCCM window state + "WM_STATE\0" + "WM_CHANGE_STATE\0" + + // Session management + "WM_CLIENT_LEADER\0" + "WM_WINDOW_ROLE\0" + "SM_CLIENT_ID\0" + + // Clipboard + "CLIPBOARD\0" + "INCR\0" + "TARGETS\0" + "MULTIPLE\0" + "TIMESTAMP\0" + "SAVE_TARGETS\0" + "CLIP_TEMPORARY\0" + "_QT_SELECTION\0" + "_QT_CLIPBOARD_SENTINEL\0" + "_QT_SELECTION_SENTINEL\0" + "CLIPBOARD_MANAGER\0" + + "RESOURCE_MANAGER\0" + + "_XSETROOT_ID\0" + + "_QT_SCROLL_DONE\0" + "_QT_INPUT_ENCODING\0" + + "_MOTIF_WM_HINTS\0" + + "DTWM_IS_RUNNING\0" + "ENLIGHTENMENT_DESKTOP\0" + "_DT_SAVE_MODE\0" + "_SGI_DESKS_MANAGER\0" + + // EWMH (aka NETWM) + "_NET_SUPPORTED\0" + "_NET_VIRTUAL_ROOTS\0" + "_NET_WORKAREA\0" + + "_NET_MOVERESIZE_WINDOW\0" + "_NET_WM_MOVERESIZE\0" + + "_NET_WM_NAME\0" + "_NET_WM_ICON_NAME\0" + "_NET_WM_ICON\0" + + "_NET_WM_PID\0" + + "_NET_WM_WINDOW_OPACITY\0" + + "_NET_WM_STATE\0" + "_NET_WM_STATE_ABOVE\0" + "_NET_WM_STATE_BELOW\0" + "_NET_WM_STATE_FULLSCREEN\0" + "_NET_WM_STATE_MAXIMIZED_HORZ\0" + "_NET_WM_STATE_MAXIMIZED_VERT\0" + "_NET_WM_STATE_MODAL\0" + "_NET_WM_STATE_STAYS_ON_TOP\0" + "_NET_WM_STATE_DEMANDS_ATTENTION\0" + + "_NET_WM_USER_TIME\0" + "_NET_WM_USER_TIME_WINDOW\0" + "_NET_WM_FULL_PLACEMENT\0" + + "_NET_WM_WINDOW_TYPE\0" + "_NET_WM_WINDOW_TYPE_DESKTOP\0" + "_NET_WM_WINDOW_TYPE_DOCK\0" + "_NET_WM_WINDOW_TYPE_TOOLBAR\0" + "_NET_WM_WINDOW_TYPE_MENU\0" + "_NET_WM_WINDOW_TYPE_UTILITY\0" + "_NET_WM_WINDOW_TYPE_SPLASH\0" + "_NET_WM_WINDOW_TYPE_DIALOG\0" + "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0" + "_NET_WM_WINDOW_TYPE_POPUP_MENU\0" + "_NET_WM_WINDOW_TYPE_TOOLTIP\0" + "_NET_WM_WINDOW_TYPE_NOTIFICATION\0" + "_NET_WM_WINDOW_TYPE_COMBO\0" + "_NET_WM_WINDOW_TYPE_DND\0" + "_NET_WM_WINDOW_TYPE_NORMAL\0" + "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0" + + "_KDE_NET_WM_FRAME_STRUT\0" + + "_NET_STARTUP_INFO\0" + "_NET_STARTUP_INFO_BEGIN\0" + + "_NET_SUPPORTING_WM_CHECK\0" + + "_NET_WM_CM_S0\0" + + "_NET_SYSTEM_TRAY_VISUAL\0" + + "_NET_ACTIVE_WINDOW\0" + + // Property formats + "COMPOUND_TEXT\0" + "TEXT\0" + "UTF8_STRING\0" + + // xdnd + "XdndEnter\0" + "XdndPosition\0" + "XdndStatus\0" + "XdndLeave\0" + "XdndDrop\0" + "XdndFinished\0" + "XdndTypeList\0" + "XdndActionList\0" + + "XdndSelection\0" + + "XdndAware\0" + "XdndProxy\0" + + "XdndActionCopy\0" + "XdndActionLink\0" + "XdndActionMove\0" + "XdndActionPrivate\0" + + // Motif DND + "_MOTIF_DRAG_AND_DROP_MESSAGE\0" + "_MOTIF_DRAG_INITIATOR_INFO\0" + "_MOTIF_DRAG_RECEIVER_INFO\0" + "_MOTIF_DRAG_WINDOW\0" + "_MOTIF_DRAG_TARGETS\0" + + "XmTRANSFER_SUCCESS\0" + "XmTRANSFER_FAILURE\0" + + // Xkb + "_XKB_RULES_NAMES\0" + + // XEMBED + "_XEMBED\0" + "_XEMBED_INFO\0" + + // Wacom old. (before version 0.10) + "Wacom Stylus\0" + "Wacom Cursor\0" + "Wacom Eraser\0" + + // Tablet + "STYLUS\0" + "ERASER\0" +}; + +/*! + \internal + Try to resolve a \a symbol from \a library with the version specified + by \a vernum. + + Note that, in the case of the Xfixes library, \a vernum is not the same as + \c XFIXES_MAJOR - it is a part of soname and may differ from the Xfixes + version. +*/ +static void* qt_load_library_runtime(const char *library, int vernum, + int highestVernum, const char *symbol) +{ + QList<int> versions; + // we try to load in the following order: + // explicit version -> the default one -> (from the highest (highestVernum) to the lowest (vernum) ) + if (vernum != -1) + versions << vernum; + versions << -1; + if (vernum != -1) { + for(int i = highestVernum; i > vernum; --i) + versions << i; + } + Q_FOREACH(int version, versions) { + QLatin1String libName(library); + QLibrary xfixesLib(libName, version); + void *ptr = xfixesLib.resolve(symbol); + if (ptr) + return ptr; + } + return 0; +} + +# define XFIXES_LOAD_RUNTIME(vernum, symbol, symbol_type) \ + (symbol_type)qt_load_library_runtime("libXfixes", vernum, 4, #symbol); +# define XFIXES_LOAD_V1(symbol) \ + XFIXES_LOAD_RUNTIME(1, symbol, Ptr##symbol) +# define XFIXES_LOAD_V2(symbol) \ + XFIXES_LOAD_RUNTIME(2, symbol, Ptr##symbol) + + +class QTestLiteStaticInfoPrivate +{ +public: + QTestLiteStaticInfoPrivate() + : use_xfixes(false) + , xfixes_major(0) + , xfixes_eventbase(0) + , xfixes_errorbase(0) + { + QXlibScreen *screen = qobject_cast<QXlibScreen *> (QApplicationPrivate::platformIntegration()->screens().at(0)); + Q_ASSERT(screen); + + initializeAllAtoms(screen); + initializeSupportedAtoms(screen); + + resolveXFixes(screen); + } + + bool isSupportedByWM(Atom atom) + { + if (!m_supportedAtoms) + return false; + + bool supported = false; + int i = 0; + while (m_supportedAtoms[i] != 0) { + if (m_supportedAtoms[i++] == atom) { + supported = true; + break; + } + } + + return supported; + } + + Atom atom(QXlibStatic::X11Atom atom) + { + return m_allAtoms[atom]; + } + + bool useXFixes() const { return use_xfixes; } + + int xFixesEventBase() const {return xfixes_eventbase; } + + PtrXFixesSelectSelectionInput xFixesSelectSelectionInput() const + { + return ptrXFixesSelectSelectionInput; + } + + QImage qimageFromXImage(XImage *xi) + { + QImage::Format format = QImage::Format_ARGB32_Premultiplied; + if (xi->depth == 24) + format = QImage::Format_RGB32; + else if (xi->depth == 16) + format = QImage::Format_RGB16; + + QImage image = QImage((uchar *)xi->data, xi->width, xi->height, xi->bytes_per_line, format).copy(); + + // we may have to swap the byte order + if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst) + || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst)) + { + for (int i=0; i < image.height(); i++) { + if (xi->depth == 16) { + ushort *p = (ushort*)image.scanLine(i); + ushort *end = p + image.width(); + while (p < end) { + *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff); + p++; + } + } else { + uint *p = (uint*)image.scanLine(i); + uint *end = p + image.width(); + while (p < end) { + *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000) + | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff); + p++; + } + } + } + } + + // fix-up alpha channel + if (format == QImage::Format_RGB32) { + QRgb *p = (QRgb *)image.bits(); + for (int y = 0; y < xi->height; ++y) { + for (int x = 0; x < xi->width; ++x) + p[x] |= 0xff000000; + p += xi->bytes_per_line / 4; + } + } + + return image; + } + + +private: + + void initializeAllAtoms(QXlibScreen *screen) { + const char *names[QXlibStatic::NAtoms]; + const char *ptr = x11_atomnames; + + int i = 0; + while (*ptr) { + names[i++] = ptr; + while (*ptr) + ++ptr; + ++ptr; + } + + Q_ASSERT(i == QXlibStatic::NPredefinedAtoms); + + QByteArray settings_atom_name("_QT_SETTINGS_TIMESTAMP_"); + settings_atom_name += XDisplayName(qPrintable(screen->displayName())); + names[i++] = settings_atom_name; + + Q_ASSERT(i == QXlibStatic::NAtoms); + #if 0//defined(XlibSpecificationRelease) && (XlibSpecificationRelease >= 6) + XInternAtoms(screen->display(), (char **)names, i, False, m_allAtoms); + #else + for (i = 0; i < QXlibStatic::NAtoms; ++i) + m_allAtoms[i] = XInternAtom(screen->display(), (char *)names[i], False); + #endif + } + + void initializeSupportedAtoms(QXlibScreen *screen) + { + Atom type; + int format; + long offset = 0; + unsigned long nitems, after; + unsigned char *data = 0; + + int e = XGetWindowProperty(screen->display(), screen->rootWindow(), + this->atom(QXlibStatic::_NET_SUPPORTED), 0, 0, + False, XA_ATOM, &type, &format, &nitems, &after, &data); + if (data) + XFree(data); + + if (e == Success && type == XA_ATOM && format == 32) { + QBuffer ts; + ts.open(QIODevice::WriteOnly); + + while (after > 0) { + XGetWindowProperty(screen->display(), screen->rootWindow(), + this->atom(QXlibStatic::_NET_SUPPORTED), offset, 1024, + False, XA_ATOM, &type, &format, &nitems, &after, &data); + + if (type == XA_ATOM && format == 32) { + ts.write(reinterpret_cast<char *>(data), nitems * sizeof(long)); + offset += nitems; + } else + after = 0; + if (data) + XFree(data); + } + + // compute nitems + QByteArray buffer(ts.buffer()); + nitems = buffer.size() / sizeof(Atom); + m_supportedAtoms = new Atom[nitems + 1]; + Atom *a = (Atom *) buffer.data(); + uint i; + for (i = 0; i < nitems; i++) + m_supportedAtoms[i] = a[i]; + m_supportedAtoms[nitems] = 0; + + } + } + + void resolveXFixes(QXlibScreen *screen) + { +#ifndef QT_NO_XFIXES + // See if Xfixes is supported on the connected display + if (XQueryExtension(screen->display(), "XFIXES", &xfixes_major, + &xfixes_eventbase, &xfixes_errorbase)) { + ptrXFixesQueryExtension = XFIXES_LOAD_V1(XFixesQueryExtension); + ptrXFixesQueryVersion = XFIXES_LOAD_V1(XFixesQueryVersion); + ptrXFixesSetCursorName = XFIXES_LOAD_V2(XFixesSetCursorName); + ptrXFixesSelectSelectionInput = XFIXES_LOAD_V2(XFixesSelectSelectionInput); + + if(ptrXFixesQueryExtension && ptrXFixesQueryVersion + && ptrXFixesQueryExtension(screen->display(), &xfixes_eventbase, + &xfixes_errorbase)) { + // Xfixes is supported. + // Note: the XFixes protocol version is negotiated using QueryVersion. + // We supply the highest version we support, the X server replies with + // the highest version it supports, but no higher than the version we + // asked for. The version sent back is the protocol version the X server + // will use to talk us. If this call is removed, the behavior of the + // X server when it receives an XFixes request is undefined. + int major = 3; + int minor = 0; + ptrXFixesQueryVersion(screen->display(), &major, &minor); + use_xfixes = (major >= 1); + xfixes_major = major; + } + } +#endif // QT_NO_XFIXES + + } + + Atom *m_supportedAtoms; + Atom m_allAtoms[QXlibStatic::NAtoms]; + +#ifndef QT_NO_XFIXES + PtrXFixesQueryExtension ptrXFixesQueryExtension; + PtrXFixesQueryVersion ptrXFixesQueryVersion; + PtrXFixesSetCursorName ptrXFixesSetCursorName; + PtrXFixesSelectSelectionInput ptrXFixesSelectSelectionInput; +#endif + + bool use_xfixes; + int xfixes_major; + int xfixes_eventbase; + int xfixes_errorbase; + +}; +Q_GLOBAL_STATIC(QTestLiteStaticInfoPrivate, qTestLiteStaticInfoPrivate); + + +Atom QXlibStatic::atom(QXlibStatic::X11Atom atom) +{ + return qTestLiteStaticInfoPrivate()->atom(atom); +} + +bool QXlibStatic::isSupportedByWM(Atom atom) +{ + return qTestLiteStaticInfoPrivate()->isSupportedByWM(atom); +} + +bool QXlibStatic::useXFixes() +{ + return qTestLiteStaticInfoPrivate()->useXFixes(); +} + +int QXlibStatic::xFixesEventBase() +{ + return qTestLiteStaticInfoPrivate()->xFixesEventBase(); +} + +#ifndef QT_NO_XFIXES +PtrXFixesSelectSelectionInput QXlibStatic::xFixesSelectSelectionInput() +{ + qDebug() << qTestLiteStaticInfoPrivate()->useXFixes(); + if (!qTestLiteStaticInfoPrivate()->useXFixes()) + return 0; + + return qTestLiteStaticInfoPrivate()->xFixesSelectSelectionInput(); +} + +QImage QXlibStatic::qimageFromXImage(XImage *xi) +{ + return qTestLiteStaticInfoPrivate()->qimageFromXImage(xi); +} +#endif //QT_NO_XFIXES diff --git a/src/plugins/platforms/xlib/qtestlitestaticinfo.h b/src/plugins/platforms/xlib/qtestlitestaticinfo.h new file mode 100644 index 0000000..8473ee9 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitestaticinfo.h @@ -0,0 +1,413 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTESTLITESTATICINFO_H +#define QTESTLITESTATICINFO_H + +#include <QtCore/QTextStream> +#include <QtCore/QDataStream> +#include <QtCore/QMetaType> +#include <QtCore/QVariant> + +#if defined(_XLIB_H_) // crude hack, but... +#error "cannot include <X11/Xlib.h> before this file" +#endif +#define XRegisterIMInstantiateCallback qt_XRegisterIMInstantiateCallback +#define XUnregisterIMInstantiateCallback qt_XUnregisterIMInstantiateCallback +#define XSetIMValues qt_XSetIMValues +#include <X11/Xlib.h> +#undef XRegisterIMInstantiateCallback +#undef XUnregisterIMInstantiateCallback +#undef XSetIMValues + +#include <X11/Xutil.h> +#include <X11/Xos.h> +#ifdef index +# undef index +#endif +#ifdef rindex +# undef rindex +#endif +#ifdef Q_OS_VXWORS +# ifdef open +# undef open +# endif +# ifdef getpid +# undef getpid +# endif +#endif // Q_OS_VXWORKS +#include <X11/Xatom.h> + +//#define QT_NO_SHAPE +#ifdef QT_NO_SHAPE +# define XShapeCombineRegion(a,b,c,d,e,f,g) +# define XShapeCombineMask(a,b,c,d,e,f,g) +#else +# include <X11/extensions/shape.h> +#endif // QT_NO_SHAPE + + +#if !defined (QT_NO_TABLET) +# include <X11/extensions/XInput.h> +#if defined (Q_OS_IRIX) +# include <X11/extensions/SGIMisc.h> +# include <wacom.h> +#endif +#endif // QT_NO_TABLET + + +// #define QT_NO_XINERAMA +#ifndef QT_NO_XINERAMA +// XFree86 does not C++ify Xinerama (at least up to XFree86 4.0.3). +extern "C" { +# include <X11/extensions/Xinerama.h> +} +#endif // QT_NO_XINERAMA + +// #define QT_NO_XRANDR +#ifndef QT_NO_XRANDR +# include <X11/extensions/Xrandr.h> +#endif // QT_NO_XRANDR + +// #define QT_NO_XRENDER +#ifndef QT_NO_XRENDER +# include <X11/extensions/Xrender.h> +#endif // QT_NO_XRENDER + +#ifndef QT_NO_XSYNC +extern "C" { +# include "X11/extensions/sync.h" +} +#endif + +// #define QT_NO_XKB +#ifndef QT_NO_XKB +# include <X11/XKBlib.h> +#endif // QT_NO_XKB + + +#if !defined(XlibSpecificationRelease) +# define X11R4 +typedef char *XPointer; +#else +# undef X11R4 +#endif + +#ifndef QT_NO_XFIXES +typedef Bool (*PtrXFixesQueryExtension)(Display *, int *, int *); +typedef Status (*PtrXFixesQueryVersion)(Display *, int *, int *); +typedef void (*PtrXFixesSetCursorName)(Display *dpy, Cursor cursor, const char *name); +typedef void (*PtrXFixesSelectSelectionInput)(Display *dpy, Window win, Atom selection, unsigned long eventMask); +#endif // QT_NO_XFIXES + +#ifndef QT_NO_XCURSOR +#include <X11/Xcursor/Xcursor.h> +typedef Cursor (*PtrXcursorLibraryLoadCursor)(Display *, const char *); +#endif // QT_NO_XCURSOR + +#ifndef QT_NO_XINERAMA +typedef Bool (*PtrXineramaQueryExtension)(Display *dpy, int *event_base, int *error_base); +typedef Bool (*PtrXineramaIsActive)(Display *dpy); +typedef XineramaScreenInfo *(*PtrXineramaQueryScreens)(Display *dpy, int *number); +#endif // QT_NO_XINERAMA + +#ifndef QT_NO_XRANDR +typedef void (*PtrXRRSelectInput)(Display *, Window, int); +typedef int (*PtrXRRUpdateConfiguration)(XEvent *); +typedef int (*PtrXRRRootToScreen)(Display *, Window); +typedef Bool (*PtrXRRQueryExtension)(Display *, int *, int *); +#endif // QT_NO_XRANDR + +#ifndef QT_NO_XINPUT +typedef int (*PtrXCloseDevice)(Display *, XDevice *); +typedef XDeviceInfo* (*PtrXListInputDevices)(Display *, int *); +typedef XDevice* (*PtrXOpenDevice)(Display *, XID); +typedef void (*PtrXFreeDeviceList)(XDeviceInfo *); +typedef int (*PtrXSelectExtensionEvent)(Display *, Window, XEventClass *, int); +#endif // QT_NO_XINPUT + +/* + * Solaris patch 108652-47 and higher fixes crases in + * XRegisterIMInstantiateCallback, but the function doesn't seem to + * work. + * + * Instead, we disabled R6 input, and open the input method + * immediately at application start. + */ + +//######### XFree86 has wrong declarations for XRegisterIMInstantiateCallback +//######### and XUnregisterIMInstantiateCallback in at least version 3.3.2. +//######### Many old X11R6 header files lack XSetIMValues. +//######### Therefore, we have to declare these functions ourselves. + +extern "C" Bool XRegisterIMInstantiateCallback( + Display*, + struct _XrmHashBucketRec*, + char*, + char*, + XIMProc, //XFree86 has XIDProc, which has to be wrong + XPointer +); + +extern "C" Bool XUnregisterIMInstantiateCallback( + Display*, + struct _XrmHashBucketRec*, + char*, + char*, + XIMProc, //XFree86 has XIDProc, which has to be wrong + XPointer +); + +#ifndef X11R4 +# include <X11/Xlocale.h> +#endif // X11R4 + + +#ifndef QT_NO_MITSHM +# include <X11/extensions/XShm.h> +#endif // QT_NO_MITSHM + +// rename a couple of X defines to get rid of name clashes +// resolve the conflict between X11's FocusIn and QEvent::FocusIn +enum { + XFocusOut = FocusOut, + XFocusIn = FocusIn, + XKeyPress = KeyPress, + XKeyRelease = KeyRelease, + XNone = None, + XRevertToParent = RevertToParent, + XGrayScale = GrayScale, + XCursorShape = CursorShape +}; +#undef FocusOut +#undef FocusIn +#undef KeyPress +#undef KeyRelease +#undef None +#undef RevertToParent +#undef GrayScale +#undef CursorShape + +#ifdef FontChange +#undef FontChange +#endif + + +class QXlibStatic +{ +public: + enum X11Atom { + // window-manager <-> client protocols + WM_PROTOCOLS, + WM_DELETE_WINDOW, + WM_TAKE_FOCUS, + _NET_WM_PING, + _NET_WM_CONTEXT_HELP, + _NET_WM_SYNC_REQUEST, + _NET_WM_SYNC_REQUEST_COUNTER, + + // ICCCM window state + WM_STATE, + WM_CHANGE_STATE, + + // Session management + WM_CLIENT_LEADER, + WM_WINDOW_ROLE, + SM_CLIENT_ID, + + // Clipboard + CLIPBOARD, + INCR, + TARGETS, + MULTIPLE, + TIMESTAMP, + SAVE_TARGETS, + CLIP_TEMPORARY, + _QT_SELECTION, + _QT_CLIPBOARD_SENTINEL, + _QT_SELECTION_SENTINEL, + CLIPBOARD_MANAGER, + + RESOURCE_MANAGER, + + _XSETROOT_ID, + + _QT_SCROLL_DONE, + _QT_INPUT_ENCODING, + + _MOTIF_WM_HINTS, + + DTWM_IS_RUNNING, + ENLIGHTENMENT_DESKTOP, + _DT_SAVE_MODE, + _SGI_DESKS_MANAGER, + + // EWMH (aka NETWM) + _NET_SUPPORTED, + _NET_VIRTUAL_ROOTS, + _NET_WORKAREA, + + _NET_MOVERESIZE_WINDOW, + _NET_WM_MOVERESIZE, + + _NET_WM_NAME, + _NET_WM_ICON_NAME, + _NET_WM_ICON, + + _NET_WM_PID, + + _NET_WM_WINDOW_OPACITY, + + _NET_WM_STATE, + _NET_WM_STATE_ABOVE, + _NET_WM_STATE_BELOW, + _NET_WM_STATE_FULLSCREEN, + _NET_WM_STATE_MAXIMIZED_HORZ, + _NET_WM_STATE_MAXIMIZED_VERT, + _NET_WM_STATE_MODAL, + _NET_WM_STATE_STAYS_ON_TOP, + _NET_WM_STATE_DEMANDS_ATTENTION, + + _NET_WM_USER_TIME, + _NET_WM_USER_TIME_WINDOW, + _NET_WM_FULL_PLACEMENT, + + _NET_WM_WINDOW_TYPE, + _NET_WM_WINDOW_TYPE_DESKTOP, + _NET_WM_WINDOW_TYPE_DOCK, + _NET_WM_WINDOW_TYPE_TOOLBAR, + _NET_WM_WINDOW_TYPE_MENU, + _NET_WM_WINDOW_TYPE_UTILITY, + _NET_WM_WINDOW_TYPE_SPLASH, + _NET_WM_WINDOW_TYPE_DIALOG, + _NET_WM_WINDOW_TYPE_DROPDOWN_MENU, + _NET_WM_WINDOW_TYPE_POPUP_MENU, + _NET_WM_WINDOW_TYPE_TOOLTIP, + _NET_WM_WINDOW_TYPE_NOTIFICATION, + _NET_WM_WINDOW_TYPE_COMBO, + _NET_WM_WINDOW_TYPE_DND, + _NET_WM_WINDOW_TYPE_NORMAL, + _KDE_NET_WM_WINDOW_TYPE_OVERRIDE, + + _KDE_NET_WM_FRAME_STRUT, + + _NET_STARTUP_INFO, + _NET_STARTUP_INFO_BEGIN, + + _NET_SUPPORTING_WM_CHECK, + + _NET_WM_CM_S0, + + _NET_SYSTEM_TRAY_VISUAL, + + _NET_ACTIVE_WINDOW, + + // Property formats + COMPOUND_TEXT, + TEXT, + UTF8_STRING, + + // Xdnd + XdndEnter, + XdndPosition, + XdndStatus, + XdndLeave, + XdndDrop, + XdndFinished, + XdndTypelist, + XdndActionList, + + XdndSelection, + + XdndAware, + XdndProxy, + + XdndActionCopy, + XdndActionLink, + XdndActionMove, + XdndActionPrivate, + + // Motif DND + _MOTIF_DRAG_AND_DROP_MESSAGE, + _MOTIF_DRAG_INITIATOR_INFO, + _MOTIF_DRAG_RECEIVER_INFO, + _MOTIF_DRAG_WINDOW, + _MOTIF_DRAG_TARGETS, + + XmTRANSFER_SUCCESS, + XmTRANSFER_FAILURE, + + // Xkb + _XKB_RULES_NAMES, + + // XEMBED + _XEMBED, + _XEMBED_INFO, + + XWacomStylus, + XWacomCursor, + XWacomEraser, + + XTabletStylus, + XTabletEraser, + + NPredefinedAtoms, + + _QT_SETTINGS_TIMESTAMP = NPredefinedAtoms, + NAtoms + }; + + static Atom atom(X11Atom atom); + static bool isSupportedByWM(Atom atom); + + static bool useXFixes(); + static int xFixesEventBase(); + + #ifndef QT_NO_XFIXES + static PtrXFixesSelectSelectionInput xFixesSelectSelectionInput(); + #endif //QT_NO_XFIXES + + static QImage qimageFromXImage(XImage *xi); + + +}; + +#endif // QTESTLITESTATICINFO_H diff --git a/src/plugins/platforms/xlib/qtestlitewindow.cpp b/src/plugins/platforms/xlib/qtestlitewindow.cpp new file mode 100644 index 0000000..0f11a81 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitewindow.cpp @@ -0,0 +1,735 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestlitewindow.h" + +#include "qtestliteintegration.h" +#include "qtestlitescreen.h" +#include "qtestlitekeyboard.h" +#include "qtestlitestaticinfo.h" + +#include <QtGui/QWindowSystemInterface> +#include <QSocketNotifier> +#include <QApplication> +#include <QDebug> + +#include <QtGui/private/qwindowsurface_p.h> +#include <QtGui/private/qapplication_p.h> + +#if !defined(QT_NO_OPENGL) +#if !defined(QT_OPENGL_ES_2) +#include "qglxintegration.h" +#else +#include "../eglconvenience/qeglconvenience.h" +#include "../eglconvenience/qeglplatformcontext.h" +#include "qtestliteeglintegration.h" +#endif //QT_OPENGL_ES_2 +#endif //QT_NO_OPENGL + +//#define MYX11_DEBUG + +QT_BEGIN_NAMESPACE + +QXlibWindow::QXlibWindow(QWidget *window) + : QPlatformWindow(window) + , mGLContext(0) + , mScreen(QXlibScreen::testLiteScreenForWidget(window)) +{ + int x = window->x(); + int y = window->y(); + int w = window->width(); + int h = window->height(); + + if(window->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL + && QApplicationPrivate::platformIntegration()->hasOpenGL() ) { +#if !defined(QT_NO_OPENGL) +#if !defined(QT_OPENGL_ES_2) + XVisualInfo *visualInfo = QGLXContext::findVisualInfo(mScreen,window->platformWindowFormat()); +#else + QPlatformWindowFormat windowFormat = correctColorBuffers(window->platformWindowFormat()); + + EGLDisplay eglDisplay = eglGetDisplay(mScreen->display()); + EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,windowFormat); + VisualID id = QXlibEglIntegration::getCompatibleVisualId(mScreen->display(),eglConfig); + + XVisualInfo visualInfoTemplate; + memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); + visualInfoTemplate.visualid = id; + + XVisualInfo *visualInfo; + int matchingCount = 0; + visualInfo = XGetVisualInfo(mScreen->display(), VisualIDMask, &visualInfoTemplate, &matchingCount); +#endif //!defined(QT_OPENGL_ES_2) + if (visualInfo) { + Colormap cmap = XCreateColormap(mScreen->display(),mScreen->rootWindow(),visualInfo->visual,AllocNone); + + XSetWindowAttributes a; + a.colormap = cmap; + x_window = XCreateWindow(mScreen->display(), mScreen->rootWindow(),x, y, w, h, + 0, visualInfo->depth, InputOutput, visualInfo->visual, + CWColormap, &a); + } else { + qFatal("no window!"); + } +#endif //!defined(QT_NO_OPENGL) + } else { + x_window = XCreateSimpleWindow(mScreen->display(), mScreen->rootWindow(), + x, y, w, h, 0 /*border_width*/, + mScreen->blackPixel(), mScreen->whitePixel()); + } + +#ifdef MYX11_DEBUG + qDebug() << "QTestLiteWindow::QTestLiteWindow creating" << hex << x_window << window; +#endif + + XSetWindowBackgroundPixmap(mScreen->display(), x_window, XNone); + + XSelectInput(mScreen->display(), x_window, + ExposureMask | KeyPressMask | KeyReleaseMask | + EnterWindowMask | LeaveWindowMask | FocusChangeMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | PropertyChangeMask | + StructureNotifyMask); + + gc = createGC(); + + Atom protocols[5]; + int n = 0; + protocols[n++] = QXlibStatic::atom(QXlibStatic::WM_DELETE_WINDOW); // support del window protocol + protocols[n++] = QXlibStatic::atom(QXlibStatic::WM_TAKE_FOCUS); // support take focus window protocol + protocols[n++] = QXlibStatic::atom(QXlibStatic::_NET_WM_PING); // support _NET_WM_PING protocol +#ifndef QT_NO_XSYNC + protocols[n++] = QXlibStatic::atom(QXlibStatic::_NET_WM_SYNC_REQUEST); // support _NET_WM_SYNC_REQUEST protocol +#endif // QT_NO_XSYNC + if (window->windowFlags() & Qt::WindowContextHelpButtonHint) + protocols[n++] = QXlibStatic::atom(QXlibStatic::_NET_WM_CONTEXT_HELP); + XSetWMProtocols(mScreen->display(), x_window, protocols, n); +} + + + +QXlibWindow::~QXlibWindow() +{ +#ifdef MYX11_DEBUG + qDebug() << "~QTestLiteWindow" << hex << x_window; +#endif + delete mGLContext; + XFreeGC(mScreen->display(), gc); + XDestroyWindow(mScreen->display(), x_window); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Mouse event stuff +static Qt::MouseButtons translateMouseButtons(int s) +{ + Qt::MouseButtons ret = 0; + if (s & Button1Mask) + ret |= Qt::LeftButton; + if (s & Button2Mask) + ret |= Qt::MidButton; + if (s & Button3Mask) + ret |= Qt::RightButton; + return ret; +} + + + +void QXlibWindow::handleMouseEvent(QEvent::Type type, XButtonEvent *e) +{ + static QPoint mousePoint; + + Qt::MouseButton button = Qt::NoButton; + Qt::MouseButtons buttons = translateMouseButtons(e->state); + Qt::KeyboardModifiers modifiers = mScreen->keyboard()->translateModifiers(e->state); + if (type != QEvent::MouseMove) { + switch (e->button) { + case Button1: button = Qt::LeftButton; break; + case Button2: button = Qt::MidButton; break; + case Button3: button = Qt::RightButton; break; + case Button4: + case Button5: + case 6: + case 7: { + //mouse wheel + if (type == QEvent::MouseButtonPress) { + //logic borrowed from qapplication_x11.cpp + int delta = 120 * ((e->button == Button4 || e->button == 6) ? 1 : -1); + bool hor = (((e->button == Button4 || e->button == Button5) + && (modifiers & Qt::AltModifier)) + || (e->button == 6 || e->button == 7)); + QWindowSystemInterface::handleWheelEvent(widget(), e->time, + QPoint(e->x, e->y), + QPoint(e->x_root, e->y_root), + delta, hor ? Qt::Horizontal : Qt::Vertical); + } + return; + } + default: break; + } + } + + buttons ^= button; // X event uses state *before*, Qt uses state *after* + + QWindowSystemInterface::handleMouseEvent(widget(), e->time, QPoint(e->x, e->y), + QPoint(e->x_root, e->y_root), + buttons); + + mousePoint = QPoint(e->x_root, e->y_root); +} + +void QXlibWindow::handleCloseEvent() +{ + QWindowSystemInterface::handleCloseEvent(widget()); +} + + +void QXlibWindow::handleEnterEvent() +{ + QWindowSystemInterface::handleEnterEvent(widget()); +} + +void QXlibWindow::handleLeaveEvent() +{ + QWindowSystemInterface::handleLeaveEvent(widget()); +} + +void QXlibWindow::handleFocusInEvent() +{ + QWindowSystemInterface::handleWindowActivated(widget()); +} + +void QXlibWindow::handleFocusOutEvent() +{ + QWindowSystemInterface::handleWindowActivated(0); +} + + + +void QXlibWindow::setGeometry(const QRect &rect) +{ + XMoveResizeWindow(mScreen->display(), x_window, rect.x(), rect.y(), rect.width(), rect.height()); + QPlatformWindow::setGeometry(rect); +} + + +Qt::WindowFlags QXlibWindow::windowFlags() const +{ + return mWindowFlags; +} + +WId QXlibWindow::winId() const +{ + return x_window; +} + +void QXlibWindow::setParent(const QPlatformWindow *window) +{ + QPoint topLeft = geometry().topLeft(); + XReparentWindow(mScreen->display(),x_window,window->winId(),topLeft.x(),topLeft.y()); +} + +void QXlibWindow::raise() +{ + XRaiseWindow(mScreen->display(), x_window); +} + +void QXlibWindow::lower() +{ + XLowerWindow(mScreen->display(), x_window); +} + +void QXlibWindow::setWindowTitle(const QString &title) +{ + QByteArray ba = title.toLatin1(); //We're not making a general solution here... + XTextProperty windowName; + windowName.value = (unsigned char *)ba.constData(); + windowName.encoding = XA_STRING; + windowName.format = 8; + windowName.nitems = ba.length(); + + XSetWMName(mScreen->display(), x_window, &windowName); +} + +GC QXlibWindow::createGC() +{ + GC gc; + + gc = XCreateGC(mScreen->display(), x_window, 0, 0); + if (gc < 0) { + qWarning("QTestLiteWindow::createGC() could not create GC"); + } + return gc; +} + +void QXlibWindow::paintEvent() +{ +#ifdef MYX11_DEBUG +// qDebug() << "QTestLiteWindow::paintEvent" << shm_img.size() << painted; +#endif + + if (QWindowSurface *surface = widget()->windowSurface()) + surface->flush(widget(), widget()->geometry(), QPoint()); +} + +void QXlibWindow::requestActivateWindow() +{ + XSetInputFocus(mScreen->display(), x_window, XRevertToParent, CurrentTime); +} + +void QXlibWindow::resizeEvent(XConfigureEvent *e) +{ + int xpos = geometry().x(); + int ypos = geometry().y(); + if ((e->width != geometry().width() || e->height != geometry().height()) && e->x == 0 && e->y == 0) { + //qDebug() << "resize with bogus pos" << e->x << e->y << e->width << e->height << "window"<< hex << window; + } else { + //qDebug() << "geometry change" << e->x << e->y << e->width << e->height << "window"<< hex << window; + xpos = e->x; + ypos = e->y; + } +#ifdef MYX11_DEBUG + qDebug() << hex << x_window << dec << "ConfigureNotify" << e->x << e->y << e->width << e->height << "geometry" << xpos << ypos << width << height; +#endif + + QRect newRect(xpos, ypos, e->width, e->height); + QWindowSystemInterface::handleGeometryChange(widget(), newRect); +} + +void QXlibWindow::mousePressEvent(XButtonEvent *e) +{ + static long prevTime = 0; + static Window prevWindow; + static int prevX = -999; + static int prevY = -999; + + QEvent::Type type = QEvent::MouseButtonPress; + + if (e->window == prevWindow && long(e->time) - prevTime < QApplication::doubleClickInterval() + && qAbs(e->x - prevX) < 5 && qAbs(e->y - prevY) < 5) { + type = QEvent::MouseButtonDblClick; + prevTime = e->time - QApplication::doubleClickInterval(); //no double click next time + } else { + prevTime = e->time; + } + prevWindow = e->window; + prevX = e->x; + prevY = e->y; + + handleMouseEvent(type, e); +} + +QXlibMWMHints QXlibWindow::getMWMHints() const +{ + QXlibMWMHints mwmhints; + + Atom type; + int format; + ulong nitems, bytesLeft; + uchar *data = 0; + Atom atomForMotifWmHints = QXlibStatic::atom(QXlibStatic::_MOTIF_WM_HINTS); + if ((XGetWindowProperty(mScreen->display(), x_window, atomForMotifWmHints, 0, 5, false, + atomForMotifWmHints, &type, &format, &nitems, &bytesLeft, + &data) == Success) + && (type == atomForMotifWmHints + && format == 32 + && nitems >= 5)) { + mwmhints = *(reinterpret_cast<QXlibMWMHints *>(data)); + } else { + mwmhints.flags = 0L; + mwmhints.functions = MWM_FUNC_ALL; + mwmhints.decorations = MWM_DECOR_ALL; + mwmhints.input_mode = 0L; + mwmhints.status = 0L; + } + + if (data) + XFree(data); + + return mwmhints; +} + +void QXlibWindow::setMWMHints(const QXlibMWMHints &mwmhints) +{ + Atom atomForMotifWmHints = QXlibStatic::atom(QXlibStatic::_MOTIF_WM_HINTS); + if (mwmhints.flags != 0l) { + XChangeProperty(mScreen->display(), x_window, + atomForMotifWmHints, atomForMotifWmHints, 32, + PropModeReplace, (unsigned char *) &mwmhints, 5); + } else { + XDeleteProperty(mScreen->display(), x_window, atomForMotifWmHints); + } +} + +// Returns true if we should set WM_TRANSIENT_FOR on \a w +static inline bool isTransient(const QWidget *w) +{ + return ((w->windowType() == Qt::Dialog + || w->windowType() == Qt::Sheet + || w->windowType() == Qt::Tool + || w->windowType() == Qt::SplashScreen + || w->windowType() == Qt::ToolTip + || w->windowType() == Qt::Drawer + || w->windowType() == Qt::Popup) + && !w->testAttribute(Qt::WA_X11BypassTransientForHint)); +} + +QVector<Atom> QXlibWindow::getNetWmState() const +{ + QVector<Atom> returnValue; + + // Don't read anything, just get the size of the property data + Atom actualType; + int actualFormat; + ulong propertyLength; + ulong bytesLeft; + uchar *propertyData = 0; + if (XGetWindowProperty(mScreen->display(), x_window, QXlibStatic::atom(QXlibStatic::_NET_WM_STATE), 0, 0, + False, XA_ATOM, &actualType, &actualFormat, + &propertyLength, &bytesLeft, &propertyData) == Success + && actualType == XA_ATOM && actualFormat == 32) { + returnValue.resize(bytesLeft / 4); + XFree((char*) propertyData); + + // fetch all data + if (XGetWindowProperty(mScreen->display(), x_window, QXlibStatic::atom(QXlibStatic::_NET_WM_STATE), 0, + returnValue.size(), False, XA_ATOM, &actualType, &actualFormat, + &propertyLength, &bytesLeft, &propertyData) != Success) { + returnValue.clear(); + } else if (propertyLength != (ulong)returnValue.size()) { + returnValue.resize(propertyLength); + } + + // put it into netWmState + if (!returnValue.isEmpty()) { + memcpy(returnValue.data(), propertyData, returnValue.size() * sizeof(Atom)); + } + XFree((char*) propertyData); + } + + return returnValue; +} + +Qt::WindowFlags QXlibWindow::setWindowFlags(Qt::WindowFlags flags) +{ +// Q_ASSERT(flags & Qt::Window); + mWindowFlags = flags; + +#ifdef MYX11_DEBUG + qDebug() << "QTestLiteWindow::setWindowFlags" << hex << x_window << "flags" << flags; +#endif + Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); + + if (type == Qt::ToolTip) + flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint; + if (type == Qt::Popup) + flags |= Qt::X11BypassWindowManagerHint; + + bool topLevel = (flags & Qt::Window); + bool popup = (type == Qt::Popup); + bool dialog = (type == Qt::Dialog + || type == Qt::Sheet); + bool desktop = (type == Qt::Desktop); + bool tool = (type == Qt::Tool || type == Qt::SplashScreen + || type == Qt::ToolTip || type == Qt::Drawer); + + Q_UNUSED(topLevel); + Q_UNUSED(dialog); + Q_UNUSED(desktop); + + bool tooltip = (type == Qt::ToolTip); + + XSetWindowAttributes wsa; + + QXlibMWMHints mwmhints; + mwmhints.flags = 0L; + mwmhints.functions = 0L; + mwmhints.decorations = 0; + mwmhints.input_mode = 0L; + mwmhints.status = 0L; + + + ulong wsa_mask = 0; + if (type != Qt::SplashScreen) { // && customize) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + + bool customize = flags & Qt::CustomizeWindowHint; + if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) { + mwmhints.decorations |= MWM_DECOR_BORDER; + mwmhints.decorations |= MWM_DECOR_RESIZEH; + + if (flags & Qt::WindowTitleHint) + mwmhints.decorations |= MWM_DECOR_TITLE; + + if (flags & Qt::WindowSystemMenuHint) + mwmhints.decorations |= MWM_DECOR_MENU; + + if (flags & Qt::WindowMinimizeButtonHint) { + mwmhints.decorations |= MWM_DECOR_MINIMIZE; + mwmhints.functions |= MWM_FUNC_MINIMIZE; + } + + if (flags & Qt::WindowMaximizeButtonHint) { + mwmhints.decorations |= MWM_DECOR_MAXIMIZE; + mwmhints.functions |= MWM_FUNC_MAXIMIZE; + } + + if (flags & Qt::WindowCloseButtonHint) + mwmhints.functions |= MWM_FUNC_CLOSE; + } + } else { + // if type == Qt::SplashScreen + mwmhints.decorations = MWM_DECOR_ALL; + } + + if (tool) { + wsa.save_under = True; + wsa_mask |= CWSaveUnder; + } + + if (flags & Qt::X11BypassWindowManagerHint) { + wsa.override_redirect = True; + wsa_mask |= CWOverrideRedirect; + } +#if 0 + if (wsa_mask && initializeWindow) { + Q_ASSERT(id); + XChangeWindowAttributes(dpy, id, wsa_mask, &wsa); + } +#endif + if (mwmhints.functions != 0) { + mwmhints.flags |= MWM_HINTS_FUNCTIONS; + mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE; + } else { + mwmhints.functions = MWM_FUNC_ALL; + } + + if (!(flags & Qt::FramelessWindowHint) + && flags & Qt::CustomizeWindowHint + && flags & Qt::WindowTitleHint + && !(flags & + (Qt::WindowMinimizeButtonHint + | Qt::WindowMaximizeButtonHint + | Qt::WindowCloseButtonHint))) { + // a special case - only the titlebar without any button + mwmhints.flags = MWM_HINTS_FUNCTIONS; + mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE; + mwmhints.decorations = 0; + } + + if (widget()->windowModality() == Qt::WindowModal) { + mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL; + } else if (widget()->windowModality() == Qt::ApplicationModal) { + mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL; + } + + setMWMHints(mwmhints); + + QVector<Atom> netWmState = getNetWmState(); + + if (flags & Qt::WindowStaysOnTopHint) { + if (flags & Qt::WindowStaysOnBottomHint) + qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time"; + if (!netWmState.contains(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_ABOVE))) + netWmState.append(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_ABOVE)); + if (!netWmState.contains(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_STAYS_ON_TOP))) + netWmState.append(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_STAYS_ON_TOP)); + } else if (flags & Qt::WindowStaysOnBottomHint) { + if (!netWmState.contains(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_BELOW))) + netWmState.append(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_BELOW)); + } + if (widget()->isFullScreen()) { + if (!netWmState.contains(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_FULLSCREEN))) + netWmState.append(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_FULLSCREEN)); + } + if (widget()->isMaximized()) { + if (!netWmState.contains(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_MAXIMIZED_HORZ))) + netWmState.append(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_MAXIMIZED_HORZ)); + if (!netWmState.contains(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_MAXIMIZED_VERT))) + netWmState.append(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_MAXIMIZED_VERT)); + } + if (widget()->windowModality() != Qt::NonModal) { + if (!netWmState.contains(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_MODAL))) + netWmState.append(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_MODAL)); + } + + if (!netWmState.isEmpty()) { + XChangeProperty(mScreen->display(), x_window, + QXlibStatic::atom(QXlibStatic::_NET_WM_STATE), XA_ATOM, 32, PropModeReplace, + (unsigned char *) netWmState.data(), netWmState.size()); + } else { + XDeleteProperty(mScreen->display(), x_window, QXlibStatic::atom(QXlibStatic::_NET_WM_STATE)); + } + +//##### only if initializeWindow??? + + if (popup || tooltip) { // popup widget +#ifdef MYX11_DEBUG + qDebug() << "Doing XChangeWindowAttributes for popup" << wsa.override_redirect; +#endif + // set EWMH window types + // setNetWmWindowTypes(); + + wsa.override_redirect = True; + wsa.save_under = True; + XChangeWindowAttributes(mScreen->display(), x_window, CWOverrideRedirect | CWSaveUnder, + &wsa); + } else { +#ifdef MYX11_DEBUG + qDebug() << "Doing XChangeWindowAttributes for non-popup"; +#endif + } + + return flags; +} + +void QXlibWindow::setVisible(bool visible) +{ +#ifdef MYX11_DEBUG + qDebug() << "QTestLiteWindow::setVisible" << visible << hex << x_window; +#endif + if (isTransient(widget())) { + Window parentXWindow = x_window; + if (widget()->parentWidget()) { + QWidget *widgetParent = widget()->parentWidget()->window(); + if (widgetParent && widgetParent->platformWindow()) { + QXlibWindow *parentWidnow = static_cast<QXlibWindow *>(widgetParent->platformWindow()); + parentXWindow = parentWidnow->x_window; + } + } + XSetTransientForHint(mScreen->display(),x_window,parentXWindow); + } + + if (visible) { + //ensure that the window is viewed in correct position. + doSizeHints(); + XMapWindow(mScreen->display(), x_window); + } else { + XUnmapWindow(mScreen->display(), x_window); + } +} + +void QXlibWindow::setCursor(const Cursor &cursor) +{ + XDefineCursor(mScreen->display(), x_window, cursor); + XFlush(mScreen->display()); +} + +QPlatformGLContext *QXlibWindow::glContext() const +{ + if (!QApplicationPrivate::platformIntegration()->hasOpenGL()) + return 0; + if (!mGLContext) { + QXlibWindow *that = const_cast<QXlibWindow *>(this); +#if !defined(QT_NO_OPENGL) +#if !defined(QT_OPENGL_ES_2) + that->mGLContext = new QGLXContext(x_window, mScreen,widget()->platformWindowFormat()); +#else + EGLDisplay display = eglGetDisplay(mScreen->display()); + + QPlatformWindowFormat windowFormat = correctColorBuffers(widget()->platformWindowFormat()); + + EGLConfig config = q_configFromQPlatformWindowFormat(display,windowFormat); + QVector<EGLint> eglContextAttrs; + eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); + eglContextAttrs.append(2); + eglContextAttrs.append(EGL_NONE); + + EGLSurface eglSurface = eglCreateWindowSurface(display,config,(EGLNativeWindowType)x_window,0); + that->mGLContext = new QEGLPlatformContext(display, config, eglContextAttrs.data(), eglSurface, EGL_OPENGL_ES_API); +#endif +#endif + } + return mGLContext; +} + +Window QXlibWindow::xWindow() const +{ + return x_window; +} + +GC QXlibWindow::graphicsContext() const +{ + return gc; +} + +void QXlibWindow::doSizeHints() +{ + Q_ASSERT(widget()->testAttribute(Qt::WA_WState_Created)); + XSizeHints s; + s.flags = 0; + QRect g = geometry(); + s.x = g.x(); + s.y = g.y(); + s.width = g.width(); + s.height = g.height(); + s.flags |= USPosition; + s.flags |= PPosition; + s.flags |= USSize; + s.flags |= PSize; + s.flags |= PWinGravity; + s.win_gravity = QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity; + XSetWMNormalHints(mScreen->display(), x_window, &s); +} + +QPlatformWindowFormat QXlibWindow::correctColorBuffers(const QPlatformWindowFormat &platformWindowFormat) const +{ + // I have only tested this setup on a dodgy intel setup, where I didn't use standard libs, + // so this might be not what we want to do :) + if ( !(platformWindowFormat.redBufferSize() == -1 && + platformWindowFormat.greenBufferSize() == -1 && + platformWindowFormat.blueBufferSize() == -1)) + return platformWindowFormat; + + QPlatformWindowFormat windowFormat = platformWindowFormat; + if (mScreen->depth() == 16) { + windowFormat.setRedBufferSize(5); + windowFormat.setGreenBufferSize(6); + windowFormat.setBlueBufferSize(5); + } else { + windowFormat.setRedBufferSize(8); + windowFormat.setGreenBufferSize(8); + windowFormat.setBlueBufferSize(8); + } + + return windowFormat; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qtestlitewindow.h b/src/plugins/platforms/xlib/qtestlitewindow.h new file mode 100644 index 0000000..ccf6867 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitewindow.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTESTLITEWINDOW_H +#define QTESTLITEWINDOW_H + +#include "qtestliteintegration.h" + +#include <QPlatformWindow> +#include <QEvent> + +#include <QObject> +#include <QImage> + +struct QXlibMWMHints { + ulong flags, functions, decorations; + long input_mode; + ulong status; +}; + +enum { + MWM_HINTS_FUNCTIONS = (1L << 0), + + MWM_FUNC_ALL = (1L << 0), + MWM_FUNC_RESIZE = (1L << 1), + MWM_FUNC_MOVE = (1L << 2), + MWM_FUNC_MINIMIZE = (1L << 3), + MWM_FUNC_MAXIMIZE = (1L << 4), + MWM_FUNC_CLOSE = (1L << 5), + + MWM_HINTS_DECORATIONS = (1L << 1), + + MWM_DECOR_ALL = (1L << 0), + MWM_DECOR_BORDER = (1L << 1), + MWM_DECOR_RESIZEH = (1L << 2), + MWM_DECOR_TITLE = (1L << 3), + MWM_DECOR_MENU = (1L << 4), + MWM_DECOR_MINIMIZE = (1L << 5), + MWM_DECOR_MAXIMIZE = (1L << 6), + + MWM_HINTS_INPUT_MODE = (1L << 2), + + MWM_INPUT_MODELESS = 0L, + MWM_INPUT_PRIMARY_APPLICATION_MODAL = 1L, + MWM_INPUT_FULL_APPLICATION_MODAL = 3L +}; + +class QXlibWindow : public QPlatformWindow +{ +public: + QXlibWindow(QWidget *window); + ~QXlibWindow(); + + + void mousePressEvent(XButtonEvent*); + void handleMouseEvent(QEvent::Type, XButtonEvent *ev); + + void handleCloseEvent(); + void handleEnterEvent(); + void handleLeaveEvent(); + void handleFocusInEvent(); + void handleFocusOutEvent(); + + void resizeEvent(XConfigureEvent *configure_event); + void paintEvent(); + + void requestActivateWindow(); + + void setGeometry(const QRect &rect); + + Qt::WindowFlags setWindowFlags(Qt::WindowFlags type); + Qt::WindowFlags windowFlags() const; + void setVisible(bool visible); + WId winId() const; + void setParent(const QPlatformWindow *window); + void raise(); + void lower(); + void setWindowTitle(const QString &title); + + void setCursor(const Cursor &cursor); + + QPlatformGLContext *glContext() const; + + Window xWindow() const; + GC graphicsContext() const; + +protected: + QVector<Atom> getNetWmState() const; + void setMWMHints(const QXlibMWMHints &mwmhints); + QXlibMWMHints getMWMHints() const; + + void doSizeHints(); + +private: + QPlatformWindowFormat correctColorBuffers(const QPlatformWindowFormat &windowFormat)const; + + Window x_window; + GC gc; + + GC createGC(); + + QPlatformGLContext *mGLContext; + QXlibScreen *mScreen; + Qt::WindowFlags mWindowFlags; +}; + +#endif diff --git a/src/plugins/platforms/xlib/qtestlitewindowsurface.cpp b/src/plugins/platforms/xlib/qtestlitewindowsurface.cpp new file mode 100644 index 0000000..088730d --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitewindowsurface.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtestlitewindowsurface.h" +#include "qtestliteintegration.h" + +#include <QtCore/qdebug.h> +#include <QWindowSystemInterface> + +#include "qtestlitewindow.h" +#include "qtestlitescreen.h" + +# include <sys/ipc.h> +# include <sys/shm.h> +# include <X11/extensions/XShm.h> + +QT_BEGIN_NAMESPACE + + +struct QXlibShmImageInfo { + QXlibShmImageInfo(Display *xdisplay) : image(0), display(xdisplay) {} + ~QXlibShmImageInfo() { destroy(); } + + void destroy(); + + XShmSegmentInfo shminfo; + XImage *image; + Display *display; +}; + + +#ifndef DONT_USE_MIT_SHM +void QXlibShmImageInfo::destroy() +{ + XShmDetach (display, &shminfo); + XDestroyImage (image); + shmdt (shminfo.shmaddr); + shmctl (shminfo.shmid, IPC_RMID, 0); +} +#endif + +void QXlibWindowSurface::resizeShmImage(int width, int height) +{ + +#ifdef DONT_USE_MIT_SHM + shm_img = QImage(width, height, QImage::Format_RGB32); +#else + + QXlibScreen *screen = QXlibScreen::testLiteScreenForWidget(window()); + if (image_info) + image_info->destroy(); + else + image_info = new QXlibShmImageInfo(screen->display()); + + Visual *visual = DefaultVisual(screen->display(), screen->xScreenNumber()); + + + XImage *image = XShmCreateImage (screen->display(), visual, 24, ZPixmap, 0, + &image_info->shminfo, width, height); + + + image_info->shminfo.shmid = shmget (IPC_PRIVATE, + image->bytes_per_line * image->height, IPC_CREAT|0777); + + image_info->shminfo.shmaddr = image->data = (char*)shmat (image_info->shminfo.shmid, 0, 0); + image_info->shminfo.readOnly = False; + + image_info->image = image; + + Status shm_attach_status = XShmAttach(screen->display(), &image_info->shminfo); + + Q_ASSERT(shm_attach_status == True); + + shm_img = QImage( (uchar*) image->data, image->width, image->height, image->bytes_per_line, QImage::Format_RGB32 ); +#endif + painted = false; +} + + +void QXlibWindowSurface::resizeBuffer(QSize s) +{ + if (shm_img.size() != s) + resizeShmImage(s.width(), s.height()); +} + +QSize QXlibWindowSurface::bufferSize() const +{ + return shm_img.size(); +} + +QXlibWindowSurface::QXlibWindowSurface (QWidget *window) + : QWindowSurface(window), + painted(false), image_info(0) +{ + xw = static_cast<QXlibWindow*>(window->platformWindow()); +// qDebug() << "QTestLiteWindowSurface::QTestLiteWindowSurface:" << xw->window; +} + +QXlibWindowSurface::~QXlibWindowSurface() +{ + delete image_info; +} + +QPaintDevice *QXlibWindowSurface::paintDevice() +{ + return &shm_img; +} + + +void QXlibWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(widget); + Q_UNUSED(region); + Q_UNUSED(offset); + + if (!painted) + return; + + QXlibScreen *screen = QXlibScreen::testLiteScreenForWidget(widget); + GC gc = xw->graphicsContext(); + Window window = xw->xWindow(); +#ifdef DONT_USE_MIT_SHM + // just convert the image every time... + if (!shm_img.isNull()) { + Visual *visual = DefaultVisual(screen->display(), screen->xScreenNumber()); + + QImage image = shm_img; + //img.convertToFormat( + XImage *xi = XCreateImage(screen->display(), visual, 24, ZPixmap, + 0, (char *) image.scanLine(0), image.width(), image.height(), + 32, image.bytesPerLine()); + + int x = 0; + int y = 0; + + /*int r =*/ XPutImage(screen->display(), window, gc, xi, 0, 0, x, y, image.width(), image.height()); + + xi->data = 0; // QImage owns these bits + XDestroyImage(xi); + } +#else + // Use MIT_SHM + if (image_info && image_info->image) { + //qDebug() << "Here we go" << image_info->image->width << image_info->image->height; + int x = 0; + int y = 0; + + // We could set send_event to true, and then use the ShmCompletion to synchronize, + // but let's do like Qt/11 and just use XSync + XShmPutImage (screen->display(), window, gc, image_info->image, 0, 0, + x, y, image_info->image->width, image_info->image->height, + /*send_event*/ False); + + XSync(screen->display(), False); + } +#endif +} + +// from qwindowsurface.cpp +extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); + +bool QXlibWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + if (shm_img.isNull()) + return false; + + const QVector<QRect> rects = area.rects(); + for (int i = 0; i < rects.size(); ++i) + qt_scrollRectInImage(shm_img, rects.at(i), QPoint(dx, dy)); + + return true; +} + + +void QXlibWindowSurface::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); + resizeBuffer(size()); +} + +void QXlibWindowSurface::endPaint(const QRegion ®ion) +{ + Q_UNUSED(region); + painted = true; //there is content in the buffer +} +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qtestlitewindowsurface.h b/src/plugins/platforms/xlib/qtestlitewindowsurface.h new file mode 100644 index 0000000..12b4c60 --- /dev/null +++ b/src/plugins/platforms/xlib/qtestlitewindowsurface.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSURFACE_TESTLITE_H +#define QWINDOWSURFACE_TESTLITE_H + +#include <QtGui/private/qwindowsurface_p.h> + + +QT_BEGIN_NAMESPACE + +class QXlibWindow; +class QXlibIntegration; +class QXlibScreen; +class QXlibShmImageInfo; + +class QXlibWindowSurface : public QWindowSurface +{ +public: + QXlibWindowSurface (QWidget *window); + ~QXlibWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion ®ion); + void endPaint(const QRegion ®ion); + +private: + bool painted; + void resizeBuffer(QSize); + QSize bufferSize() const; + + + void resizeShmImage(int width, int height); + + QImage shm_img; + QXlibShmImageInfo *image_info; + + QXlibWindow *xw; + +}; + + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/xlib/testlite.pro b/src/plugins/platforms/xlib/testlite.pro new file mode 100644 index 0000000..7fb3304 --- /dev/null +++ b/src/plugins/platforms/xlib/testlite.pro @@ -0,0 +1,57 @@ +TARGET = qtestlite + +include(../../qpluginbase.pri) +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms + +SOURCES = \ + main.cpp \ + qtestliteintegration.cpp \ + qtestlitewindowsurface.cpp \ + qtestlitewindow.cpp \ + qtestlitecursor.cpp \ + qtestlitescreen.cpp \ + qtestlitekeyboard.cpp \ + qtestliteclipboard.cpp \ + qtestlitemime.cpp \ + qtestlitestaticinfo.cpp + +HEADERS = \ + qtestliteintegration.h \ + qtestlitewindowsurface.h \ + qtestlitewindow.h \ + qtestlitecursor.h \ + qtestlitescreen.h \ + qtestlitekeyboard.h \ + qtestliteclipboard.h \ + qtestlitemime.h \ + qtestlitestaticinfo.h + +LIBS += -lX11 -lXext + +mac { + LIBS += -L/usr/X11/lib -lz -framework Carbon +} + +include (../fontdatabases/genericunix/genericunix.pri) + +contains(QT_CONFIG, opengl) { + QT += opengl + !contains(QT_CONFIG, opengles2) { + HEADERS += qglxintegration.h + SOURCES += qglxintegration.cpp + } else { # There is no easy way to detect if we'r suppose to use glx or not + HEADERS += \ + ../eglconvenience/qeglplatformcontext.h \ + ../eglconvenience/qeglconvenience.h \ + qtestliteeglintegration.h + + SOURCES += \ + ../eglconvenience/qeglplatformcontext.cpp \ + ../eglconvenience/qeglconvenience.cpp \ + qtestliteeglintegration.cpp + LIBS += -lEGL + } +} + +target.path += $$[QT_INSTALL_PLUGINS]/platforms +INSTALLS += target |