diff options
Diffstat (limited to 'src/plugins')
439 files changed, 34097 insertions, 22583 deletions
diff --git a/src/plugins/accessible/widgets/complexwidgets.h b/src/plugins/accessible/widgets/complexwidgets.h index c6453f19c4..3c01445091 100644 --- a/src/plugins/accessible/widgets/complexwidgets.h +++ b/src/plugins/accessible/widgets/complexwidgets.h @@ -43,9 +43,9 @@ #define COMPLEXWIDGETS_H #include <QtCore/qpointer.h> -#include <QtGui/qaccessiblewidget.h> -#include <QtGui/qabstractitemview.h> -#include <QtGui/qaccessible2.h> +#include <QtWidgets/qaccessiblewidget.h> +#include <QtWidgets/qabstractitemview.h> +#include <QtWidgets/qaccessible2.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/accessible/widgets/itemviews.h b/src/plugins/accessible/widgets/itemviews.h index c8492e3c89..2c981ef0e8 100644 --- a/src/plugins/accessible/widgets/itemviews.h +++ b/src/plugins/accessible/widgets/itemviews.h @@ -42,11 +42,11 @@ #ifndef ACCESSIBLE_ITEMVIEWS_H #define ACCESSIBLE_ITEMVIEWS_H -#include <QtGui/qabstractitemview.h> -#include <QtGui/qheaderview.h> -#include <QtGui/qaccessible.h> -#include <QtGui/qaccessible2.h> -#include <QtGui/qaccessiblewidget.h> +#include <QtWidgets/qabstractitemview.h> +#include <QtWidgets/qheaderview.h> +#include <QtWidgets/qaccessible.h> +#include <QtWidgets/qaccessible2.h> +#include <QtWidgets/qaccessiblewidget.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.cpp b/src/plugins/accessible/widgets/qaccessiblemenu.cpp index 1454c7c80b..8e72910b45 100644 --- a/src/plugins/accessible/widgets/qaccessiblemenu.cpp +++ b/src/plugins/accessible/widgets/qaccessiblemenu.cpp @@ -43,7 +43,7 @@ #include <qmenu.h> #include <qmenubar.h> -#include <QtGui/QAction> +#include <QtWidgets/QAction> #include <qstyle.h> #ifndef QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.h b/src/plugins/accessible/widgets/qaccessiblemenu.h index 680594d667..1ee6d5436f 100644 --- a/src/plugins/accessible/widgets/qaccessiblemenu.h +++ b/src/plugins/accessible/widgets/qaccessiblemenu.h @@ -42,7 +42,7 @@ #ifndef QACCESSIBLEMENU_H #define QACCESSIBLEMENU_H -#include <QtGui/qaccessiblewidget.h> +#include <QtWidgets/qaccessiblewidget.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp index a0dde37ed6..a8f38b61a3 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp @@ -65,7 +65,7 @@ #include <QMainWindow> #include <QAbstractButton> #include <private/qdockwidget_p.h> -#include <QtGui/QFocusFrame> +#include <QFocusFrame> #ifndef QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.h b/src/plugins/accessible/widgets/qaccessiblewidgets.h index 242f8c1610..942012896b 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.h +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.h @@ -42,8 +42,8 @@ #ifndef QACCESSIBLEWIDGETS_H #define QACCESSIBLEWIDGETS_H -#include <QtGui/qaccessible2.h> -#include <QtGui/qaccessiblewidget.h> +#include <QtWidgets/qaccessible2.h> +#include <QtWidgets/qaccessiblewidget.h> #ifndef QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/rangecontrols.h b/src/plugins/accessible/widgets/rangecontrols.h index 0f21a5a119..529a331c94 100644 --- a/src/plugins/accessible/widgets/rangecontrols.h +++ b/src/plugins/accessible/widgets/rangecontrols.h @@ -42,8 +42,8 @@ #ifndef RANGECONTROLS_H #define RANGECONTROLS_H -#include <QtGui/qaccessiblewidget.h> -#include <QtGui/qaccessible2.h> +#include <QtWidgets/qaccessiblewidget.h> +#include <QtWidgets/qaccessible2.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h index d5144caebd..7cc14410cf 100644 --- a/src/plugins/accessible/widgets/simplewidgets.h +++ b/src/plugins/accessible/widgets/simplewidgets.h @@ -43,8 +43,8 @@ #define SIMPLEWIDGETS_H #include <QtCore/qcoreapplication.h> -#include <QtGui/qaccessible2.h> -#include <QtGui/qaccessiblewidget.h> +#include <QtWidgets/qaccessible2.h> +#include <QtWidgets/qaccessiblewidget.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/accessible/widgets/widgets.pro b/src/plugins/accessible/widgets/widgets.pro index d1a121ec94..3bf7dede56 100644 --- a/src/plugins/accessible/widgets/widgets.pro +++ b/src/plugins/accessible/widgets/widgets.pro @@ -2,7 +2,7 @@ TARGET = qtaccessiblewidgets load(qt_plugin) include (../qaccessiblebase.pri) -QT += core-private gui-private +QT += core-private gui-private widgets-private DESTDIR = $$QT.gui.plugins/accessible QTDIR_build:REQUIRES += "contains(QT_CONFIG, accessibility)" diff --git a/src/plugins/decorations/decorations.pro b/src/plugins/decorations/decorations.pro deleted file mode 100644 index 3d6912e77c..0000000000 --- a/src/plugins/decorations/decorations.pro +++ /dev/null @@ -1,4 +0,0 @@ -TEMPLATE = subdirs -contains(decoration-plugins, default) :SUBDIRS += default -contains(decoration-plugins, styled) :SUBDIRS += styled -contains(decoration-plugins, windows) :SUBDIRS += windows diff --git a/src/plugins/decorations/default/default.pro b/src/plugins/decorations/default/default.pro deleted file mode 100644 index c323d10930..0000000000 --- a/src/plugins/decorations/default/default.pro +++ /dev/null @@ -1,10 +0,0 @@ -TARGET = qdecorationdefault -load(qt_plugin) - -HEADERS = $$QT_SOURCE_TREE/src/gui/embedded/qdecorationdefault_qws.h -SOURCES = main.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qdecorationdefault_qws.cpp - -DESTDIR = $$QT.gui.plugins/decorations -target.path += $$[QT_INSTALL_PLUGINS]/decorations -INSTALLS += target diff --git a/src/plugins/decorations/styled/styled.pro b/src/plugins/decorations/styled/styled.pro deleted file mode 100644 index c5329aea29..0000000000 --- a/src/plugins/decorations/styled/styled.pro +++ /dev/null @@ -1,13 +0,0 @@ -TARGET = qdecorationstyled -load(qt_plugin) - -DESTDIR = $$QT.gui.plugins/decorations -target.path += $$[QT_INSTALL_PLUGINS]/decorations -INSTALLS += target - -DEFINES += QT_QWS_DECORATION_STYLED - -HEADERS = $$QT_SOURCE_TREE/src/gui/embedded/qdecorationstyled_qws.h -SOURCES = main.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qdecorationstyled_qws.cpp - diff --git a/src/plugins/decorations/windows/windows.pro b/src/plugins/decorations/windows/windows.pro deleted file mode 100644 index f27adb908b..0000000000 --- a/src/plugins/decorations/windows/windows.pro +++ /dev/null @@ -1,10 +0,0 @@ -TARGET = qdecorationwindows -load(qt_plugin) - -HEADERS = $$QT_SOURCE_TREE/src/gui/embedded/qdecorationwindows_qws.h -SOURCES = main.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qdecorationwindows_qws.cpp - -DESTDIR = $$QT.gui.plugins/decorations -target.path += $$[QT_INSTALL_PLUGINS]/decorations -INSTALLS += target diff --git a/src/plugins/generic/linuxinput/linuxinput.pro b/src/plugins/generic/linuxinput/linuxinput.pro index 18cb04e973..6ef5f0fb3a 100644 --- a/src/plugins/generic/linuxinput/linuxinput.pro +++ b/src/plugins/generic/linuxinput/linuxinput.pro @@ -5,8 +5,6 @@ DESTDIR = $$QT.gui.plugins/generic target.path = $$[QT_INSTALL_PLUGINS]/generic INSTALLS += target -DEFINES += QT_QWS_KBD_LINUXINPUT - HEADERS = qlinuxinput.h QT += core-private @@ -14,7 +12,3 @@ QT += core-private SOURCES = main.cpp \ qlinuxinput.cpp -HEADERS += $$QT_SOURCE_TREE/src/gui/embedded/qkbd_qws.h \ - $$QT_SOURCE_TREE/src/gui/embedded/qkbd_qws_p.h - -SOURCES += $$QT_SOURCE_TREE/src/gui/embedded/qkbd_qws.cpp diff --git a/src/plugins/generic/linuxinput/main.cpp b/src/plugins/generic/linuxinput/main.cpp index 9c38dba199..20391901bf 100644 --- a/src/plugins/generic/linuxinput/main.cpp +++ b/src/plugins/generic/linuxinput/main.cpp @@ -61,8 +61,7 @@ QLinuxInputPlugin::QLinuxInputPlugin() QStringList QLinuxInputPlugin::keys() const { return (QStringList() - << QLatin1String("LinuxInputMouse") - << QLatin1String("LinuxInputKeyboard")); + << QLatin1String("LinuxInputMouse")); } QObject* QLinuxInputPlugin::create(const QString &key, @@ -70,8 +69,6 @@ QObject* QLinuxInputPlugin::create(const QString &key, { if (!key.compare(QLatin1String("LinuxInputMouse"), Qt::CaseInsensitive)) return new QLinuxInputMouseHandler(key, specification); - if (!key.compare(QLatin1String("LinuxInputKeyboard"), Qt::CaseInsensitive)) - return new QLinuxInputKeyboardHandler(key, specification); return 0; } diff --git a/src/plugins/generic/linuxinput/qlinuxinput.cpp b/src/plugins/generic/linuxinput/qlinuxinput.cpp index 2316f089cc..943b213ce0 100644 --- a/src/plugins/generic/linuxinput/qlinuxinput.cpp +++ b/src/plugins/generic/linuxinput/qlinuxinput.cpp @@ -48,9 +48,6 @@ #include <QPoint> #include <QWindowSystemInterface> -#include <qkbd_qws.h> - - #include <qplatformdefs.h> #include <private/qcore_unix_p.h> // overrides QT_OPEN @@ -361,195 +358,6 @@ void QLinuxInputMouseHandler::readMouseData() -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//Keyboard handler - - - - -class QWSLinuxInputKeyboardHandler : public QWSKeyboardHandler -{ -public: - QWSLinuxInputKeyboardHandler(const QString&); - ~QWSLinuxInputKeyboardHandler(); - - virtual bool filterInputEvent(quint16 &input_code, qint32 &input_value); - -//private: -// QWSLinuxInputKbPrivate *d; -}; - - -QWSLinuxInputKeyboardHandler::QWSLinuxInputKeyboardHandler(const QString &device) - : QWSKeyboardHandler(device) -{ -} - -QWSLinuxInputKeyboardHandler::~QWSLinuxInputKeyboardHandler() -{ -} - -bool QWSLinuxInputKeyboardHandler::filterInputEvent(quint16 &, qint32 &) -{ - return false; -} - - -QLinuxInputKeyboardHandler::QLinuxInputKeyboardHandler(const QString &key, const QString &specification) - : m_handler(0), m_fd(-1), m_tty_fd(-1), m_orig_kbmode(K_XLATE) -{ - setObjectName(QLatin1String("LinuxInputSubsystem Keyboard Handler")); - - QString dev = QLatin1String("/dev/input/event1"); - int repeat_delay = -1; - int repeat_rate = -1; - - bool ttymode = false; - - QStringList args = specification.split(QLatin1Char(':')); - foreach (const QString &arg, args) { - if (arg.startsWith(QLatin1String("repeat-delay="))) - repeat_delay = arg.mid(13).toInt(); - else if (arg.startsWith(QLatin1String("repeat-rate="))) - repeat_rate = arg.mid(12).toInt(); - else if (arg.startsWith(QLatin1String("ttymode"))) - ttymode = true; - else if (arg.startsWith(QLatin1String("/dev/"))) - dev = arg; - } - - m_handler = new QWSLinuxInputKeyboardHandler(dev); //This is a hack to avoid copying all the QWS code - - m_fd = QT_OPEN(dev.toLocal8Bit().constData(), O_RDWR, 0); - if (m_fd >= 0) { - if (repeat_delay > 0 && repeat_rate > 0) { - int kbdrep[2] = { repeat_delay, repeat_rate }; - ::ioctl(m_fd, EVIOCSREP, kbdrep); - } - - QSocketNotifier *notifier; - notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); - connect(notifier, SIGNAL(activated(int)), this, SLOT(readKeycode())); - - if (ttymode) { - // play nice in case we are started from a shell (e.g. for debugging) - m_tty_fd = isatty(0) ? 0 : -1; - - if (m_tty_fd >= 0) { - // save tty config for restore. - tcgetattr(m_tty_fd, &m_tty_attr); - - struct ::termios termdata; - tcgetattr(m_tty_fd, &termdata); - - // record the original mode so we can restore it again in the destructor. - ::ioctl(m_tty_fd, KDGKBMODE, &m_orig_kbmode); - - // setting this translation mode is even needed in INPUT mode to prevent - // the shell from also interpreting codes, if the process has a tty - // attached: e.g. Ctrl+C wouldn't copy, but kill the application. - ::ioctl(m_tty_fd, KDSKBMODE, K_MEDIUMRAW); - - // set the tty layer to pass-through - termdata.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); - termdata.c_oflag = 0; - termdata.c_cflag = CREAD | CS8; - termdata.c_lflag = 0; - termdata.c_cc[VTIME]=0; - termdata.c_cc[VMIN]=1; - cfsetispeed(&termdata, 9600); - cfsetospeed(&termdata, 9600); - tcsetattr(m_tty_fd, TCSANOW, &termdata); - } - } - } else { - qWarning("Cannot open keyboard input device '%s': %s", qPrintable(dev), strerror(errno)); - return; - } -} - -QLinuxInputKeyboardHandler::~QLinuxInputKeyboardHandler() -{ - if (m_tty_fd >= 0) { - ::ioctl(m_tty_fd, KDSKBMODE, m_orig_kbmode); - tcsetattr(m_tty_fd, TCSANOW, &m_tty_attr); - } - if (m_fd >= 0) - QT_CLOSE(m_fd); - delete m_handler; -} - -void QLinuxInputKeyboardHandler::switchLed(int led, bool state) -{ - struct ::input_event led_ie; - ::gettimeofday(&led_ie.time, 0); - led_ie.type = EV_LED; - led_ie.code = led; - led_ie.value = state; - - QT_WRITE(m_fd, &led_ie, sizeof(led_ie)); -} - - - -void QLinuxInputKeyboardHandler::readKeycode() -{ - struct ::input_event buffer[32]; - int n = 0; - - forever { - n = QT_READ(m_fd, reinterpret_cast<char *>(buffer) + n, sizeof(buffer) - n); - - if (n == 0) { - qWarning("Got EOF from the input device."); - return; - } else if (n < 0 && (errno != EINTR && errno != EAGAIN)) { - qWarning("Could not read from input device: %s", strerror(errno)); - return; - } else if (n % sizeof(buffer[0]) == 0) { - break; - } - } - - n /= sizeof(buffer[0]); - - for (int i = 0; i < n; ++i) { - if (buffer[i].type != EV_KEY) - continue; - - quint16 code = buffer[i].code; - qint32 value = buffer[i].value; - - if (m_handler->filterInputEvent(code, value)) - continue; - - QWSKeyboardHandler::KeycodeAction ka; - ka = m_handler->processKeycode(code, value != 0, value == 2); - - switch (ka) { - case QWSKeyboardHandler::CapsLockOn: - case QWSKeyboardHandler::CapsLockOff: - switchLed(LED_CAPSL, ka == QWSKeyboardHandler::CapsLockOn); - break; - - case QWSKeyboardHandler::NumLockOn: - case QWSKeyboardHandler::NumLockOff: - switchLed(LED_NUML, ka == QWSKeyboardHandler::NumLockOn); - break; - - case QWSKeyboardHandler::ScrollLockOn: - case QWSKeyboardHandler::ScrollLockOff: - switchLed(LED_SCROLLL, ka == QWSKeyboardHandler::ScrollLockOn); - break; - - default: - // ignore console switching and reboot - break; - } - } -} - - diff --git a/src/plugins/generic/linuxinput/qlinuxinput.h b/src/plugins/generic/linuxinput/qlinuxinput.h index 83b91d095d..b9475a1bf5 100644 --- a/src/plugins/generic/linuxinput/qlinuxinput.h +++ b/src/plugins/generic/linuxinput/qlinuxinput.h @@ -79,31 +79,6 @@ private: QLinuxInputMouseHandlerData *d; }; - -class QWSLinuxInputKeyboardHandler; - -class QLinuxInputKeyboardHandler : public QObject -{ - Q_OBJECT -public: - QLinuxInputKeyboardHandler(const QString &key, const QString &specification); - ~QLinuxInputKeyboardHandler(); - - -private: - void switchLed(int, bool); - -private slots: - void readKeycode(); - -private: - QWSLinuxInputKeyboardHandler *m_handler; - int m_fd; - int m_tty_fd; - struct termios m_tty_attr; - int m_orig_kbmode; -}; - QT_END_NAMESPACE QT_END_HEADER diff --git a/src/plugins/gfxdrivers/ahi/ahi.pro b/src/plugins/gfxdrivers/ahi/ahi.pro deleted file mode 100644 index fd078421f9..0000000000 --- a/src/plugins/gfxdrivers/ahi/ahi.pro +++ /dev/null @@ -1,14 +0,0 @@ -TARGET = qahiscreen -load(qt_plugin) - -DESTDIR = $$QT.gui.plugins/gfxdrivers - -target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers -INSTALLS += target - -HEADERS = qscreenahi_qws.h - -SOURCES = qscreenahi_qws.cpp \ - qscreenahiplugin.cpp - -LIBS += -lahi diff --git a/src/plugins/gfxdrivers/ahi/qscreenahi_qws.cpp b/src/plugins/gfxdrivers/ahi/qscreenahi_qws.cpp deleted file mode 100644 index 320aff9811..0000000000 --- a/src/plugins/gfxdrivers/ahi/qscreenahi_qws.cpp +++ /dev/null @@ -1,598 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qscreenahi_qws.h" - -#ifndef QT_NO_QWS_AHI - -#include <QtGui/qcolor.h> -#include <QtGui/qapplication.h> -#include <QtCore/qvector.h> -#include <QtCore/qvarlengtharray.h> -#include <private/qwssignalhandler_p.h> - -#include <ahi.h> - -//#define QAHISCREEN_DEBUG - -static int depthForPixelFormat(const AhiPixelFormat_t format) -{ - switch (format) { - case AhiPix1bpp: - return 1; - case AhiPix2bpp: - return 2; - case AhiPix4bpp: - return 4; - case AhiPix8bpp_332RGB: - case AhiPix8bpp: - return 8; - case AhiPix16bpp_444RGB: - return 12; - case AhiPix16bpp_555RGB: - return 15; - case AhiPix16bpp_565RGB: - return 16; - case AhiPix32bpp_8888ARGB: - case AhiPix32bpp_8888BGRA: - return 32; - default: - return 0; - } -} - -static AhiPixelFormat_t pixelFormatForImageFormat(const QImage::Format format) -{ - switch (format) { - case QImage::Format_Mono: - case QImage::Format_MonoLSB: - return AhiPix1bpp; - case QImage::Format_Indexed8: - return AhiPix8bpp; - case QImage::Format_RGB32: - case QImage::Format_ARGB32: - case QImage::Format_ARGB32_Premultiplied: - return AhiPix32bpp_8888ARGB; - case QImage::Format_RGB16: - return AhiPix16bpp_565RGB; - case QImage::Format_RGB555: - return AhiPix16bpp_555RGB; - case QImage::Format_ARGB4444_Premultiplied: - case QImage::Format_RGB444: - return AhiPix16bpp_444RGB; - default: - return AhiPixelFormatMax; - } -} - -class QAhiScreenCursor : public QScreenCursor -{ -public: - QAhiScreenCursor(QScreen *screen, AhiDevCtx_t context); - - void set(const QImage &image, int hotx, int hoty); - void move(int x, int y); - void show(); - void hide(); - -private: - QScreen *screen; - AhiDevCtx_t context; -}; - -QAhiScreenCursor::QAhiScreenCursor(QScreen *s, AhiDevCtx_t c) - : QScreenCursor(), screen(s), context(c) -{ - hwaccel = true; - supportsAlpha = true; - - if (enable) - show(); - else - hide(); -} - -void QAhiScreenCursor::set(const QImage &image, int hotx, int hoty) -{ - if (image.isNull()) { - QScreenCursor::set(image, hotx, hoty); - return; - } - - if (image.format() != QImage::Format_MonoLSB) { - set(image.convertToFormat(QImage::Format_MonoLSB), hotx, hoty); - return; - } - - AhiPixelFormat_t pixFmt = pixelFormatForImageFormat(image.format()); - - if (pixFmt >= AhiPixelFormatMax) { // generic fallback - QImage::Format toFormat = screen->pixelFormat(); - if (toFormat == QImage::Format_Invalid) - toFormat = QImage::Format_ARGB32; - set(image.convertToFormat(toFormat), hotx, hoty); - return; - } - - AhiPoint_t hotSpot = { hotx, hoty }; - AhiSize_t bitmapSize = { image.width(), image.height() }; - AhiBitmap_t bitmap = { bitmapSize, (void*)(image.bits()), - image.bytesPerLine(), pixFmt }; - - AhiSts_t status; - status = AhiDispCursorSet(context, AhiCursor1, &bitmap, &hotSpot, - image.serialNumber(), 0); - if (status != AhiStsOk) - qWarning("QAhiScreenCursor::set(): AhiDispCursorSet failed: %x", - status); - - QScreenCursor::set(image, hotx, hoty); -} - -void QAhiScreenCursor::move(int x, int y) -{ - AhiPoint_t pos = { x, y }; - AhiSts_t status = AhiDispCursorPos(context, AhiCursor1, &pos, 0); - if (status != AhiStsOk) - qWarning("QAhiScreenCursor::move(): error setting mouse position: %x", - status); - QScreenCursor::move(x, y); -} - -void QAhiScreenCursor::show() -{ - AhiSts_t status; - status = AhiDispCursorState(context, AhiCursor1, AhiCursorStateOn, 0); - if (status != AhiStsOk) - qWarning("QAhiScreenCursor::show(): error setting state: %x", status); - QScreenCursor::show(); -} - -void QAhiScreenCursor::hide() -{ - AhiDispCursorState(context, AhiCursor1, AhiCursorStateOff, 0); - QScreenCursor::hide(); -} - -class QAhiScreenPrivate : public QObject -{ -public: - QAhiScreenPrivate(); - ~QAhiScreenPrivate(); - - bool setMode(AhiDispMode_t mode); - - AhiDevCtx_t context; - AhiSurf_t surface; - QAhiScreenCursor *cursor; -}; - -QT_BEGIN_NAMESPACE - -QAhiScreenPrivate::QAhiScreenPrivate() - : context(0), surface(0), cursor(0) -{ -#ifndef QT_NO_QWS_SIGNALHANDLER - QWSSignalHandler::instance()->addObject(this); -#endif -} - -QAhiScreenPrivate::~QAhiScreenPrivate() -{ - delete cursor; - - if (surface) { - AhiSurfFree(context, surface); - surface = 0; - } - if (context) { - AhiDevClose(context); - context = 0; - } - AhiTerm(); -} - -bool QAhiScreenPrivate::setMode(AhiDispMode_t mode) -{ - AhiSts_t status; - - status = AhiDispModeSet(context, &mode, 0); - if (status != AhiStsOk) { - qCritical("QAhiScreenPrivate::setMode(): AhiDispModeSet failed: %x", - status); - return false; - } - - if (surface) { - AhiSurfFree(context, surface); - surface = 0; - } - status = AhiSurfAlloc(context, &surface, &mode.size, mode.pixFmt, - AHIFLAG_SURFFIXED); - if (status != AhiStsOk) { - qCritical("QAhiScreenPrivate::setMode(): AhisurfAlloc failed: %x", - status); - return false; - } - - status = AhiDispSurfSet(context, surface, 0); - if (status != AhiStsOk) { - qCritical("QAhiScreenPrivate::setMode(): AhiDispSurfSet failed: %x", - status); - return false; - } - - return true; -} - -QAhiScreen::QAhiScreen(int displayId) - : QScreen(displayId), d_ptr(new QAhiScreenPrivate) -{ -} - -QAhiScreen::~QAhiScreen() -{ - delete d_ptr; -} - -bool QAhiScreen::configure() -{ - AhiSurfInfo_t surfaceInfo; - AhiSts_t status; - - status = AhiSurfInfo(d_ptr->context, d_ptr->surface, &surfaceInfo); - if (status != AhiStsOk) { - qCritical("QAhiScreen::configure(): AhiSurfInfo failed: %x", status); - return false; - } - - QScreen::data = 0; - QScreen::w = QScreen::dw = surfaceInfo.size.cx; - QScreen::h = QScreen::dh = surfaceInfo.size.cy; - QScreen::lstep = surfaceInfo.stride; - QScreen::size = surfaceInfo.sizeInBytes; - - switch (surfaceInfo.pixFmt) { - case AhiPix1bpp: - setPixelFormat(QImage::Format_Mono); - QScreen::d = 1; - break; - case AhiPix4bpp: - QScreen::d = 4; - break; - case AhiPix8bpp_332RGB: - case AhiPix8bpp: - QScreen::d = 8; - break; - case AhiPix16bpp_444RGB: - setPixelFormat(QImage::Format_RGB444); - QScreen::d = 12; - break; - case AhiPix16bpp_555RGB: - setPixelFormat(QImage::Format_RGB555); - QScreen::d = 15; - break; - case AhiPix16bpp_565RGB: - setPixelFormat(QImage::Format_RGB16); - QScreen::d = 16; - break; - case AhiPix2bpp: - QScreen::d = 2; - break; - case AhiPix32bpp_8888ARGB: - setPixelFormat(QImage::Format_ARGB32); - // fallthrough - case AhiPix32bpp_8888BGRA: - QScreen::d = 32; - break; - default: - qCritical("QAhiScreen::configure(): Unknown pixel format: %x", - surfaceInfo.pixFmt); - return false; - } - - const int dpi = 72; - QScreen::physWidth = qRound(QScreen::dw * 25.4 / dpi); - QScreen::physHeight = qRound(QScreen::dh * 25.4 / dpi); - - return true; -} - -bool QAhiScreen::connect(const QString &displaySpec) -{ - Q_UNUSED(displaySpec); - - AhiSts_t status; - - status = AhiInit(0); - if (status != AhiStsOk) { - qCritical("QAhiScreen::connect(): AhiInit failed: %x", status); - return false; - } - - AhiDev_t device; - AhiDevInfo_t info; - - status = AhiDevEnum(&device, &info, 0); - if (status != AhiStsOk) { - qCritical("QAhiScreen::connect(): AhiDevEnum failed: %x", status); - return false; - } -#ifdef QAHISCREEN_DEBUG - { - int displayNo = 0; - AhiDevInfo_t dispInfo = info; - qDebug("AHI supported devices:"); - do { - qDebug(" %2i: %s, sw version: %s (rev %u)\n" - " chip: 0x%x (rev %u), mem: %i (%i/%i), bus: 0x%x", - displayNo, dispInfo.name, - dispInfo.swVersion, uint(dispInfo.swRevision), - uint(dispInfo.chipId), uint(dispInfo.revisionId), - uint(dispInfo.totalMemory), - uint(dispInfo.internalMemSize), - uint(dispInfo.externalMemSize), - uint(dispInfo.cpuBusInterfaceMode)); - status = AhiDevEnum(&device, &info, ++displayNo); - } while (status == AhiStsOk); - } -#endif - - status = AhiDevOpen(&d_ptr->context, device, "qscreenahi", - AHIFLAG_USERLEVEL); - if (status != AhiStsOk) { - qCritical("QAhiScreen::connect(): AhiDevOpen failed: %x", status); - return false; - } - - AhiDispMode_t mode; - - status = AhiDispModeEnum(d_ptr->context, &mode, 0); - if (status != AhiStsOk) { - qCritical("QAhiScreen::connect(): AhiDispModeEnum failed: %x", status); - return false; - } - -#ifdef QAHISCREEN_DEBUG - { - int modeNo = 0; - AhiDispMode_t modeInfo = mode; - qDebug("AHI supported modes:"); - do { - qDebug(" %2i: %ux%u, fmt: %i, %u Hz, rot: %i, mirror: %i", - modeNo, uint(modeInfo.size.cx), uint(modeInfo.size.cy), - modeInfo.pixFmt, uint(modeInfo.frequency), - modeInfo.rotation, modeInfo.mirror); - status = AhiDispModeEnum(d_ptr->context, &modeInfo, ++modeNo); - } while (status == AhiStsOk); - } -#endif - - if (QApplication::type() == QApplication::GuiServer) { - if (!d_ptr->setMode(mode)) - return false; - } else { - status = AhiDispSurfGet(d_ptr->context, &d_ptr->surface); - if (status != AhiStsOk) { - qCritical("QAhiScreen::connect(): AhiDispSurfGet failed: %x", - status); - return false; - } - - status = AhiDispModeGet(d_ptr->context, &mode); - if (status != AhiStsOk) { - qCritical("QAhiScreen::context(): AhiDispModeGet failed: %x", - status); - return false; - } - } - - return configure(); -} - -void QAhiScreen::disconnect() -{ - AhiSurfFree(d_ptr->context, d_ptr->surface); - d_ptr->surface = 0; - AhiDevClose(d_ptr->context); - d_ptr->context = 0; - AhiTerm(); -} - -bool QAhiScreen::initDevice() -{ - QScreenCursor::initSoftwareCursor(); - - AhiSts_t status = AhiDispState(d_ptr->context, AhiDispStateOn, 0); - if (status != AhiStsOk) { - qCritical("QAhiScreen::connect(): AhiDispState failed: %x", status); - return false; - } - - return true; -} - -void QAhiScreen::shutdownDevice() -{ - AhiDispState(d_ptr->context, AhiDispStateOff, 0); -} - -void QAhiScreen::setMode(int width, int height, int depth) -{ - int modeNo = 0; - AhiDispMode_t mode; - AhiSts_t status = AhiStsOk; - - while (status == AhiStsOk) { - status = AhiDispModeEnum(d_ptr->context, &mode, modeNo); - if (mode.size.cx == uint(width) && - mode.size.cy == uint(height) && - depthForPixelFormat(mode.pixFmt) == depth) - { - d_ptr->setMode(mode); - configure(); - return; - } - } -} - -void QAhiScreen::blit(const QImage &image, const QPoint &topLeft, - const QRegion ®) -{ - AhiPixelFormat_t pixFmt = pixelFormatForImageFormat(image.format()); - - if (pixFmt >= AhiPixelFormatMax) { // generic fallback - QImage::Format toFormat = pixelFormat(); - if (toFormat == QImage::Format_Invalid) - toFormat = QImage::Format_ARGB32; - blit(image.convertToFormat(toFormat), topLeft, reg); - return; - } - - AhiSts_t status; - - status = AhiDrawSurfDstSet(d_ptr->context, d_ptr->surface, 0); - if (status != AhiStsOk) { - qWarning("QAhiScreen::blit(): AhiDrawSurfDstSet failed: %x", status); - return; - } - - const QVector<QRect> rects = (reg & region()).rects(); - const int numRects = rects.size(); - QVarLengthArray<AhiPoint_t, 8> src(numRects); - QVarLengthArray<AhiRect_t, 8> dest(numRects); - - for (int i = 0; i < numRects; ++i) { - const QRect rect = rects.at(i); - - src[i].x = rect.x() - topLeft.x(); - src[i].y = rect.y() - topLeft.y(); - dest[i].left = rect.left(); - dest[i].top = rect.top(); - dest[i].right = rect.x() + rect.width(); - dest[i].bottom = rect.y() + rect.height(); - } - - AhiSize_t bitmapSize = { image.width(), image.height() }; - AhiBitmap_t bitmap = { bitmapSize, (void*)(image.bits()), - image.bytesPerLine(), pixFmt }; - - status = AhiDrawRopSet(d_ptr->context, AHIMAKEROP3(AHIROPSRCCOPY)); - if (status != AhiStsOk) { - qWarning("QAhiScreen::blit(): AhiDrawRopSet failed: %x", status); - return; - } - - for (int i = 0; i < numRects; ++i) { - status = AhiDrawBitmapBlt(d_ptr->context, &dest[i], &src[i], - &bitmap, 0, 0); - if (status != AhiStsOk) { - qWarning("QAhiScreen::blit(): AhiDrawBitmapBlt failed: %x", - status); - break; - } - } -} - -void QAhiScreen::solidFill(const QColor &color, const QRegion ®) -{ - AhiSts_t status = AhiStsOk; - - switch (pixelFormat()) { - case QImage::Format_ARGB32_Premultiplied: - case QImage::Format_ARGB32: - case QImage::Format_RGB32: - status = AhiDrawBrushFgColorSet(d_ptr->context, color.rgba()); - break; - case QImage::Format_RGB16: - status = AhiDrawBrushFgColorSet(d_ptr->context, qt_convRgbTo16(color.rgb())); - break; - default: - qFatal("QAhiScreen::solidFill(): Not implemented for pixel format %d", - int(pixelFormat())); - break; - } - - if (status != AhiStsOk) { - qWarning("QAhiScreen::solidFill(): AhiDrawBrushFgColorSet failed: %x", - status); - return; - } - - status = AhiDrawBrushSet(d_ptr->context, 0, 0, 0, AHIFLAG_BRUSHSOLID); - if (status != AhiStsOk) { - qWarning("QAhiScreen::solidFill(): AhiDrawBrushSet failed: %x", - status); - return; - } - - status = AhiDrawRopSet(d_ptr->context, AHIMAKEROP3(AHIROPPATCOPY)); - if (status != AhiStsOk) { - qWarning("QAhiScreen::solidFill(): AhiDrawRopSet failed: %x", status); - return; - } - - status = AhiDrawSurfDstSet(d_ptr->context, d_ptr->surface, 0); - if (status != AhiStsOk) { - qWarning("QAhiScreen::solidFill(): AhiDrawSurfDst failed: %x", status); - return; - } - - const QVector<QRect> rects = (reg & region()).rects(); - QVarLengthArray<AhiRect_t> ahiRects(rects.size()); - - for (int i = 0; i < rects.size(); ++i) { - const QRect rect = rects.at(i); - ahiRects[i].left = rect.left(); - ahiRects[i].top = rect.top(); - ahiRects[i].right = rect.x() + rect.width(); - ahiRects[i].bottom = rect.y() + rect.height(); - } - - status = AhiDrawBitBltMulti(d_ptr->context, ahiRects.data(), - 0, ahiRects.size()); - if (status != AhiStsOk) - qWarning("QAhiScreen::solidFill(): AhiDrawBitBlt failed: %x", status); -} - -QT_END_NAMESPACE - -#endif // QT_NO_QWS_AHI diff --git a/src/plugins/gfxdrivers/directfb/directfb.pro b/src/plugins/gfxdrivers/directfb/directfb.pro deleted file mode 100644 index 6fb2a0f9aa..0000000000 --- a/src/plugins/gfxdrivers/directfb/directfb.pro +++ /dev/null @@ -1,15 +0,0 @@ -TARGET = qdirectfbscreen -load(qt_plugin) -include($$QT_SOURCE_TREE/src/gui/embedded/directfb.pri) - -DESTDIR = $$QT.gui.plugins/gfxdrivers - -target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers -INSTALLS += target - -SOURCES += qdirectfbscreenplugin.cpp - -QMAKE_CXXFLAGS += $$QT_CFLAGS_DIRECTFB -LIBS += $$QT_LIBS_DIRECTFB -DEFINES += $$QT_DEFINES_DIRECTFB -contains(gfx-plugins, directfb):DEFINES += QT_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp deleted file mode 100644 index 9ec3f71c7c..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp +++ /dev/null @@ -1,436 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdirectfbkeyboard.h" - -#ifndef QT_NO_QWS_DIRECTFB - -#include "qdirectfbscreen.h" -#include <qobject.h> -#include <qsocketnotifier.h> -#include <qhash.h> - -#include <directfb.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> - -QT_BEGIN_NAMESPACE - -class KeyMap : public QHash<DFBInputDeviceKeySymbol, Qt::Key> -{ -public: - KeyMap(); -}; - -Q_GLOBAL_STATIC(KeyMap, keymap); - -class QDirectFBKeyboardHandlerPrivate : public QObject -{ - Q_OBJECT -public: - QDirectFBKeyboardHandlerPrivate(QDirectFBKeyboardHandler *handler); - ~QDirectFBKeyboardHandlerPrivate(); - - void suspend(); - void resume(); - -private: - QDirectFBKeyboardHandler *handler; - IDirectFBEventBuffer *eventBuffer; - QSocketNotifier *keyboardNotifier; - DFBEvent event; - int bytesRead; - int lastUnicode, lastKeycode; - Qt::KeyboardModifiers lastModifiers; -private Q_SLOTS: - void readKeyboardData(); -}; - -QDirectFBKeyboardHandlerPrivate::QDirectFBKeyboardHandlerPrivate(QDirectFBKeyboardHandler *h) - : handler(h), eventBuffer(0), keyboardNotifier(0), bytesRead(0), - lastUnicode(0), lastKeycode(0), lastModifiers(0) -{ - Q_ASSERT(qt_screen); - - IDirectFB *fb = QDirectFBScreen::instance()->dfb(); - if (!fb) { - qCritical("QDirectFBKeyboardHandler: DirectFB not initialized"); - return; - } - - DFBResult result; - result = fb->CreateInputEventBuffer(fb, DICAPS_KEYS, DFB_TRUE, - &eventBuffer); - if (result != DFB_OK) { - DirectFBError("QDirectFBKeyboardHandler: " - "Unable to create input event buffer", result); - return; - } - - int fd; - result = eventBuffer->CreateFileDescriptor(eventBuffer, &fd); - if (result != DFB_OK) { - DirectFBError("QDirectFBKeyboardHandler: " - "Unable to create file descriptor", result); - return; - } - - int flags = ::fcntl(fd, F_GETFL, 0); - ::fcntl(fd, F_SETFL, flags | O_NONBLOCK); - - memset(&event, 0, sizeof(event)); - - keyboardNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); - connect(keyboardNotifier, SIGNAL(activated(int)), - this, SLOT(readKeyboardData())); - resume(); -} - -void QDirectFBKeyboardHandlerPrivate::suspend() -{ - keyboardNotifier->setEnabled(false); -} - -void QDirectFBKeyboardHandlerPrivate::resume() -{ - eventBuffer->Reset(eventBuffer); - keyboardNotifier->setEnabled(true); -} - -QDirectFBKeyboardHandlerPrivate::~QDirectFBKeyboardHandlerPrivate() -{ - if (eventBuffer) - eventBuffer->Release(eventBuffer); -} - -void QDirectFBKeyboardHandlerPrivate::readKeyboardData() -{ - if(!qt_screen) - return; - - for (;;) { - // GetEvent returns DFB_UNSUPPORTED after CreateFileDescriptor(). - // This seems stupid and I really hope it's a bug which will be fixed. - - // DFBResult ret = eventBuffer->GetEvent(eventBuffer, &event); - - char *buf = reinterpret_cast<char*>(&event); - int ret = ::read(keyboardNotifier->socket(), - buf + bytesRead, sizeof(DFBEvent) - bytesRead); - if (ret == -1) { - if (errno != EAGAIN) - qWarning("QDirectFBKeyboardHandlerPrivate::readKeyboardData(): %s", - strerror(errno)); - return; - } - - Q_ASSERT(ret >= 0); - bytesRead += ret; - if (bytesRead < int(sizeof(DFBEvent))) - break; - bytesRead = 0; - - Q_ASSERT(event.clazz == DFEC_INPUT); - - const DFBInputEvent input = event.input; - - Qt::KeyboardModifiers modifiers = Qt::NoModifier; - - // Not implemented: - // if (input.modifiers & DIMM_SUPER) - // if (input.modifiers & DIMM_HYPER) - - if (!(input.flags & DIEF_KEYSYMBOL) || - !(input.flags & DIEF_KEYID) || - !(input.type & (DIET_KEYPRESS|DIET_KEYRELEASE))) - { - static bool first = true; - if (first) { - qWarning("QDirectFBKeyboardHandler - Getting unexpected non-keyboard related events"); - first = false; - } - break; - } - - if (input.flags & DIEF_MODIFIERS) { - if (input.modifiers & DIMM_SHIFT) - modifiers |= Qt::ShiftModifier; - if (input.modifiers & DIMM_CONTROL) - modifiers |= Qt::ControlModifier; - if (input.modifiers & DIMM_ALT) - modifiers |= Qt::AltModifier; - if (input.modifiers & DIMM_ALTGR) - modifiers |= Qt::AltModifier; - if (input.modifiers & DIMM_META) - modifiers |= Qt::MetaModifier; - } - - - const bool press = input.type & DIET_KEYPRESS; - DFBInputDeviceKeySymbol symbol = input.key_symbol; - int unicode = -1; - int keycode = 0; - - keycode = keymap()->value(symbol); - if (DFB_KEY_TYPE(symbol) == DIKT_UNICODE) - unicode = symbol; - - if (unicode != -1 || keycode != 0) { - bool autoRepeat = false; - if (press) { - if (unicode == lastUnicode && keycode == lastKeycode && modifiers == lastModifiers) { - autoRepeat = true; - } else { - lastUnicode = unicode; - lastKeycode = keycode; - lastModifiers = modifiers; - } - } else { - lastUnicode = lastKeycode = -1; - lastModifiers = 0; - } - if (autoRepeat) { - handler->processKeyEvent(unicode, keycode, - modifiers, false, autoRepeat); - - } - - handler->processKeyEvent(unicode, keycode, - modifiers, press, autoRepeat); - } - } -} - -QDirectFBKeyboardHandler::QDirectFBKeyboardHandler(const QString &device) - : QWSKeyboardHandler() -{ - Q_UNUSED(device); - d = new QDirectFBKeyboardHandlerPrivate(this); -} - -QDirectFBKeyboardHandler::~QDirectFBKeyboardHandler() -{ - delete d; -} - -KeyMap::KeyMap() -{ - insert(DIKS_BACKSPACE , Qt::Key_Backspace); - insert(DIKS_TAB , Qt::Key_Tab); - insert(DIKS_RETURN , Qt::Key_Return); - insert(DIKS_ESCAPE , Qt::Key_Escape); - insert(DIKS_DELETE , Qt::Key_Delete); - - insert(DIKS_CURSOR_LEFT , Qt::Key_Left); - insert(DIKS_CURSOR_RIGHT , Qt::Key_Right); - insert(DIKS_CURSOR_UP , Qt::Key_Up); - insert(DIKS_CURSOR_DOWN , Qt::Key_Down); - insert(DIKS_INSERT , Qt::Key_Insert); - insert(DIKS_HOME , Qt::Key_Home); - insert(DIKS_END , Qt::Key_End); - insert(DIKS_PAGE_UP , Qt::Key_PageUp); - insert(DIKS_PAGE_DOWN , Qt::Key_PageDown); - insert(DIKS_PRINT , Qt::Key_Print); - insert(DIKS_PAUSE , Qt::Key_Pause); - insert(DIKS_SELECT , Qt::Key_Select); - insert(DIKS_GOTO , Qt::Key_OpenUrl); - insert(DIKS_CLEAR , Qt::Key_Clear); - insert(DIKS_MENU , Qt::Key_Menu); - insert(DIKS_HELP , Qt::Key_Help); - - insert(DIKS_INTERNET , Qt::Key_HomePage); - insert(DIKS_MAIL , Qt::Key_LaunchMail); - insert(DIKS_FAVORITES , Qt::Key_Favorites); - - insert(DIKS_BACK , Qt::Key_Back); - insert(DIKS_FORWARD , Qt::Key_Forward); - insert(DIKS_VOLUME_UP , Qt::Key_VolumeUp); - insert(DIKS_VOLUME_DOWN , Qt::Key_VolumeDown); - insert(DIKS_MUTE , Qt::Key_VolumeMute); - insert(DIKS_PLAYPAUSE , Qt::Key_Pause); - insert(DIKS_PLAY , Qt::Key_MediaPlay); - insert(DIKS_STOP , Qt::Key_MediaStop); - insert(DIKS_RECORD , Qt::Key_MediaRecord); - insert(DIKS_PREVIOUS , Qt::Key_MediaPrevious); - insert(DIKS_NEXT , Qt::Key_MediaNext); - - insert(DIKS_F1 , Qt::Key_F1); - insert(DIKS_F2 , Qt::Key_F2); - insert(DIKS_F3 , Qt::Key_F3); - insert(DIKS_F4 , Qt::Key_F4); - insert(DIKS_F5 , Qt::Key_F5); - insert(DIKS_F6 , Qt::Key_F6); - insert(DIKS_F7 , Qt::Key_F7); - insert(DIKS_F8 , Qt::Key_F8); - insert(DIKS_F9 , Qt::Key_F9); - insert(DIKS_F10 , Qt::Key_F10); - insert(DIKS_F11 , Qt::Key_F11); - insert(DIKS_F12 , Qt::Key_F12); - - insert(DIKS_SHIFT , Qt::Key_Shift); - insert(DIKS_CONTROL , Qt::Key_Control); - insert(DIKS_ALT , Qt::Key_Alt); - insert(DIKS_ALTGR , Qt::Key_AltGr); - - insert(DIKS_META , Qt::Key_Meta); - insert(DIKS_SUPER , Qt::Key_Super_L); // ??? - insert(DIKS_HYPER , Qt::Key_Hyper_L); // ??? - - insert(DIKS_CAPS_LOCK , Qt::Key_CapsLock); - insert(DIKS_NUM_LOCK , Qt::Key_NumLock); - insert(DIKS_SCROLL_LOCK , Qt::Key_ScrollLock); - - insert(DIKS_DEAD_ABOVEDOT , Qt::Key_Dead_Abovedot); - insert(DIKS_DEAD_ABOVERING , Qt::Key_Dead_Abovering); - insert(DIKS_DEAD_ACUTE , Qt::Key_Dead_Acute); - insert(DIKS_DEAD_BREVE , Qt::Key_Dead_Breve); - insert(DIKS_DEAD_CARON , Qt::Key_Dead_Caron); - insert(DIKS_DEAD_CEDILLA , Qt::Key_Dead_Cedilla); - insert(DIKS_DEAD_CIRCUMFLEX , Qt::Key_Dead_Circumflex); - insert(DIKS_DEAD_DIAERESIS , Qt::Key_Dead_Diaeresis); - insert(DIKS_DEAD_DOUBLEACUTE , Qt::Key_Dead_Doubleacute); - insert(DIKS_DEAD_GRAVE , Qt::Key_Dead_Grave); - insert(DIKS_DEAD_IOTA , Qt::Key_Dead_Iota); - insert(DIKS_DEAD_MACRON , Qt::Key_Dead_Macron); - insert(DIKS_DEAD_OGONEK , Qt::Key_Dead_Ogonek); - insert(DIKS_DEAD_SEMIVOICED_SOUND , Qt::Key_Dead_Semivoiced_Sound); - insert(DIKS_DEAD_TILDE , Qt::Key_Dead_Tilde); - insert(DIKS_DEAD_VOICED_SOUND , Qt::Key_Dead_Voiced_Sound); - insert(DIKS_SPACE , Qt::Key_Space); - insert(DIKS_EXCLAMATION_MARK , Qt::Key_Exclam); - insert(DIKS_QUOTATION , Qt::Key_QuoteDbl); - insert(DIKS_NUMBER_SIGN , Qt::Key_NumberSign); - insert(DIKS_DOLLAR_SIGN , Qt::Key_Dollar); - insert(DIKS_PERCENT_SIGN , Qt::Key_Percent); - insert(DIKS_AMPERSAND , Qt::Key_Ampersand); - insert(DIKS_APOSTROPHE , Qt::Key_Apostrophe); - insert(DIKS_PARENTHESIS_LEFT , Qt::Key_ParenLeft); - insert(DIKS_PARENTHESIS_RIGHT , Qt::Key_ParenRight); - insert(DIKS_ASTERISK , Qt::Key_Asterisk); - insert(DIKS_PLUS_SIGN , Qt::Key_Plus); - insert(DIKS_COMMA , Qt::Key_Comma); - insert(DIKS_MINUS_SIGN , Qt::Key_Minus); - insert(DIKS_PERIOD , Qt::Key_Period); - insert(DIKS_SLASH , Qt::Key_Slash); - insert(DIKS_0 , Qt::Key_0); - insert(DIKS_1 , Qt::Key_1); - insert(DIKS_2 , Qt::Key_2); - insert(DIKS_3 , Qt::Key_3); - insert(DIKS_4 , Qt::Key_4); - insert(DIKS_5 , Qt::Key_5); - insert(DIKS_6 , Qt::Key_6); - insert(DIKS_7 , Qt::Key_7); - insert(DIKS_8 , Qt::Key_8); - insert(DIKS_9 , Qt::Key_9); - insert(DIKS_COLON , Qt::Key_Colon); - insert(DIKS_SEMICOLON , Qt::Key_Semicolon); - insert(DIKS_LESS_THAN_SIGN , Qt::Key_Less); - insert(DIKS_EQUALS_SIGN , Qt::Key_Equal); - insert(DIKS_GREATER_THAN_SIGN , Qt::Key_Greater); - insert(DIKS_QUESTION_MARK , Qt::Key_Question); - insert(DIKS_AT , Qt::Key_At); - insert(DIKS_CAPITAL_A , Qt::Key_A); - insert(DIKS_CAPITAL_B , Qt::Key_B); - insert(DIKS_CAPITAL_C , Qt::Key_C); - insert(DIKS_CAPITAL_D , Qt::Key_D); - insert(DIKS_CAPITAL_E , Qt::Key_E); - insert(DIKS_CAPITAL_F , Qt::Key_F); - insert(DIKS_CAPITAL_G , Qt::Key_G); - insert(DIKS_CAPITAL_H , Qt::Key_H); - insert(DIKS_CAPITAL_I , Qt::Key_I); - insert(DIKS_CAPITAL_J , Qt::Key_J); - insert(DIKS_CAPITAL_K , Qt::Key_K); - insert(DIKS_CAPITAL_L , Qt::Key_L); - insert(DIKS_CAPITAL_M , Qt::Key_M); - insert(DIKS_CAPITAL_N , Qt::Key_N); - insert(DIKS_CAPITAL_O , Qt::Key_O); - insert(DIKS_CAPITAL_P , Qt::Key_P); - insert(DIKS_CAPITAL_Q , Qt::Key_Q); - insert(DIKS_CAPITAL_R , Qt::Key_R); - insert(DIKS_CAPITAL_S , Qt::Key_S); - insert(DIKS_CAPITAL_T , Qt::Key_T); - insert(DIKS_CAPITAL_U , Qt::Key_U); - insert(DIKS_CAPITAL_V , Qt::Key_V); - insert(DIKS_CAPITAL_W , Qt::Key_W); - insert(DIKS_CAPITAL_X , Qt::Key_X); - insert(DIKS_CAPITAL_Y , Qt::Key_Y); - insert(DIKS_CAPITAL_Z , Qt::Key_Z); - insert(DIKS_SQUARE_BRACKET_LEFT , Qt::Key_BracketLeft); - insert(DIKS_BACKSLASH , Qt::Key_Backslash); - insert(DIKS_SQUARE_BRACKET_RIGHT , Qt::Key_BracketRight); - insert(DIKS_CIRCUMFLEX_ACCENT , Qt::Key_AsciiCircum); - insert(DIKS_UNDERSCORE , Qt::Key_Underscore); - insert(DIKS_SMALL_A , Qt::Key_A); - insert(DIKS_SMALL_B , Qt::Key_B); - insert(DIKS_SMALL_C , Qt::Key_C); - insert(DIKS_SMALL_D , Qt::Key_D); - insert(DIKS_SMALL_E , Qt::Key_E); - insert(DIKS_SMALL_F , Qt::Key_F); - insert(DIKS_SMALL_G , Qt::Key_G); - insert(DIKS_SMALL_H , Qt::Key_H); - insert(DIKS_SMALL_I , Qt::Key_I); - insert(DIKS_SMALL_J , Qt::Key_J); - insert(DIKS_SMALL_K , Qt::Key_K); - insert(DIKS_SMALL_L , Qt::Key_L); - insert(DIKS_SMALL_M , Qt::Key_M); - insert(DIKS_SMALL_N , Qt::Key_N); - insert(DIKS_SMALL_O , Qt::Key_O); - insert(DIKS_SMALL_P , Qt::Key_P); - insert(DIKS_SMALL_Q , Qt::Key_Q); - insert(DIKS_SMALL_R , Qt::Key_R); - insert(DIKS_SMALL_S , Qt::Key_S); - insert(DIKS_SMALL_T , Qt::Key_T); - insert(DIKS_SMALL_U , Qt::Key_U); - insert(DIKS_SMALL_V , Qt::Key_V); - insert(DIKS_SMALL_W , Qt::Key_W); - insert(DIKS_SMALL_X , Qt::Key_X); - insert(DIKS_SMALL_Y , Qt::Key_Y); - insert(DIKS_SMALL_Z , Qt::Key_Z); - insert(DIKS_CURLY_BRACKET_LEFT , Qt::Key_BraceLeft); - insert(DIKS_VERTICAL_BAR , Qt::Key_Bar); - insert(DIKS_CURLY_BRACKET_RIGHT , Qt::Key_BraceRight); - insert(DIKS_TILDE , Qt::Key_AsciiTilde); -} - -QT_END_NAMESPACE -#include "qdirectfbkeyboard.moc" -#endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp deleted file mode 100644 index f5f03e72eb..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdirectfbmouse.h" - -#ifndef QT_NO_QWS_DIRECTFB - -#include "qdirectfbscreen.h" -#include <qsocketnotifier.h> - -#include <directfb.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> - -QT_BEGIN_NAMESPACE - -class QDirectFBMouseHandlerPrivate : public QObject -{ - Q_OBJECT -public: - QDirectFBMouseHandlerPrivate(QDirectFBMouseHandler *h); - ~QDirectFBMouseHandlerPrivate(); - - void setEnabled(bool on); -private: - QDirectFBMouseHandler *handler; - IDirectFBEventBuffer *eventBuffer; -#ifndef QT_NO_DIRECTFB_LAYER - IDirectFBDisplayLayer *layer; -#endif - QSocketNotifier *mouseNotifier; - - QPoint prevPoint; - Qt::MouseButtons prevbuttons; - - DFBEvent event; - uint bytesRead; - -private Q_SLOTS: - void readMouseData(); -}; - -QDirectFBMouseHandlerPrivate::QDirectFBMouseHandlerPrivate(QDirectFBMouseHandler *h) - : handler(h), eventBuffer(0) -{ - DFBResult result; - - QScreen *screen = QScreen::instance(); - if (!screen) { - qCritical("QDirectFBMouseHandler: no screen instance found"); - return; - } - - IDirectFB *fb = QDirectFBScreen::instance()->dfb(); - if (!fb) { - qCritical("QDirectFBMouseHandler: DirectFB not initialized"); - return; - } - -#ifndef QT_NO_DIRECTFB_LAYER - layer = QDirectFBScreen::instance()->dfbDisplayLayer(); - if (!layer) { - qCritical("QDirectFBMouseHandler: Unable to get primary display layer"); - return; - } -#endif - - DFBInputDeviceCapabilities caps; - caps = DICAPS_BUTTONS | DICAPS_AXES; - result = fb->CreateInputEventBuffer(fb, caps, DFB_TRUE, &eventBuffer); - if (result != DFB_OK) { - DirectFBError("QDirectFBMouseHandler: " - "Unable to create input event buffer", result); - return; - } - - int fd; - result = eventBuffer->CreateFileDescriptor(eventBuffer, &fd); - if (result != DFB_OK) { - DirectFBError("QDirectFBMouseHandler: " - "Unable to create file descriptor", result); - return; - } - - int flags = fcntl(fd, F_GETFL, 0); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); - - // DirectFB seems to assume that the mouse always starts centered - prevPoint = QPoint(screen->deviceWidth() / 2, screen->deviceHeight() / 2); - prevbuttons = Qt::NoButton; - memset(&event, 0, sizeof(event)); - bytesRead = 0; - - mouseNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); - connect(mouseNotifier, SIGNAL(activated(int)),this, SLOT(readMouseData())); - setEnabled(true); -} - -QDirectFBMouseHandlerPrivate::~QDirectFBMouseHandlerPrivate() -{ - if (eventBuffer) - eventBuffer->Release(eventBuffer); -} - -void QDirectFBMouseHandlerPrivate::setEnabled(bool on) -{ - if (mouseNotifier->isEnabled() != on) { -#ifndef QT_NO_DIRECTFB_LAYER - DFBResult result; - result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::QDirectFBScreenCursor: " - "Unable to set cooperative level", result); - } - result = layer->EnableCursor(layer, on ? 1 : 0); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::QDirectFBScreenCursor: " - "Unable to enable cursor", result); - } - - result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::show: " - "Unable to set cooperative level", result); - } - - layer->SetCooperativeLevel(layer, DLSCL_SHARED); -#endif - mouseNotifier->setEnabled(on); - } -} - -void QDirectFBMouseHandlerPrivate::readMouseData() -{ - if (!QScreen::instance()) - return; - - for (;;) { - // GetEvent returns DFB_UNSUPPORTED after CreateFileDescriptor(). - // This seems stupid and I really hope it's a bug which will be fixed. - - // DFBResult ret = eventBuffer->GetEvent(eventBuffer, &event); - - char *buf = reinterpret_cast<char*>(&event); - int ret = ::read(mouseNotifier->socket(), - buf + bytesRead, sizeof(DFBEvent) - bytesRead); - if (ret == -1) { - if (errno == EINTR) - continue; - if (errno == EAGAIN) - return; - qWarning("QDirectFBMouseHandlerPrivate::readMouseData(): %s", - strerror(errno)); - return; - } - - Q_ASSERT(ret >= 0); - bytesRead += ret; - if (bytesRead < sizeof(DFBEvent)) - break; - bytesRead = 0; - - Q_ASSERT(event.clazz == DFEC_INPUT); - - const DFBInputEvent input = event.input; - int x = prevPoint.x(); - int y = prevPoint.y(); - int wheel = 0; - - if (input.type == DIET_AXISMOTION) { -#if defined(QT_NO_DIRECTFB_LAYER) || defined(QT_DIRECTFB_WINDOW_AS_CURSOR) - if (input.flags & DIEF_AXISABS) { - switch (input.axis) { - case DIAI_X: x = input.axisabs; break; - case DIAI_Y: y = input.axisabs; break; - default: - qWarning("QDirectFBMouseHandlerPrivate::readMouseData: " - "unknown axis (absolute) %d", input.axis); - break; - } - } else if (input.flags & DIEF_AXISREL) { - switch (input.axis) { - case DIAI_X: x += input.axisrel; break; - case DIAI_Y: y += input.axisrel; break; - case DIAI_Z: wheel = -120 * input.axisrel; break; - default: - qWarning("QDirectFBMouseHandlerPrivate::readMouseData: " - "unknown axis (releative) %d", input.axis); - } - } -#else - if (input.axis == DIAI_X || input.axis == DIAI_Y) { - DFBResult result = layer->GetCursorPosition(layer, &x, &y); - if (result != DFB_OK) { - DirectFBError("QDirectFBMouseHandler::readMouseData", - result); - } - } else if (input.axis == DIAI_Z) { - Q_ASSERT(input.flags & DIEF_AXISREL); - wheel = input.axisrel; - wheel *= -120; - } -#endif - } - - Qt::MouseButtons buttons = Qt::NoButton; - if (input.flags & DIEF_BUTTONS) { - if (input.buttons & DIBM_LEFT) - buttons |= Qt::LeftButton; - if (input.buttons & DIBM_MIDDLE) - buttons |= Qt::MidButton; - if (input.buttons & DIBM_RIGHT) - buttons |= Qt::RightButton; - } - - QPoint p = QPoint(x, y); - handler->limitToScreen(p); - - if (p == prevPoint && wheel == 0 && buttons == prevbuttons) - continue; - - prevPoint = p; - prevbuttons = buttons; - - handler->mouseChanged(p, buttons, wheel); - } -} - -QDirectFBMouseHandler::QDirectFBMouseHandler(const QString &driver, - const QString &device) - : QWSMouseHandler(driver, device) -{ - d = new QDirectFBMouseHandlerPrivate(this); -} - -QDirectFBMouseHandler::~QDirectFBMouseHandler() -{ - delete d; -} - -void QDirectFBMouseHandler::suspend() -{ - d->setEnabled(false); -} - -void QDirectFBMouseHandler::resume() -{ - d->setEnabled(true); -} - -QT_END_NAMESPACE -#include "qdirectfbmouse.moc" -#endif // QT_NO_QWS_DIRECTFB - - diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp deleted file mode 100644 index 90d0090790..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdirectfbscreen.h" -#include "qdirectfbpaintdevice.h" -#include "qdirectfbpaintengine.h" - -#ifndef QT_NO_QWS_DIRECTFB - -QT_BEGIN_NAMESPACE - -QDirectFBPaintDevice::QDirectFBPaintDevice(QDirectFBScreen *scr) - : QCustomRasterPaintDevice(0), dfbSurface(0), screen(scr), - bpl(-1), lockFlgs(DFBSurfaceLockFlags(0)), mem(0), engine(0), imageFormat(QImage::Format_Invalid) -{ -#ifdef QT_DIRECTFB_SUBSURFACE - subSurface = 0; - syncPending = false; -#endif -} - -QDirectFBPaintDevice::~QDirectFBPaintDevice() -{ - if (QDirectFBScreen::instance()) { - unlockSurface(); -#ifdef QT_DIRECTFB_SUBSURFACE - releaseSubSurface(); -#endif - if (dfbSurface) { - screen->releaseDFBSurface(dfbSurface); - } - } - delete engine; -} - -IDirectFBSurface *QDirectFBPaintDevice::directFBSurface() const -{ - return dfbSurface; -} - -bool QDirectFBPaintDevice::lockSurface(DFBSurfaceLockFlags lockFlags) -{ - if (lockFlgs && (lockFlags & ~lockFlgs)) - unlockSurface(); - if (!mem) { - Q_ASSERT(dfbSurface); -#ifdef QT_DIRECTFB_SUBSURFACE - if (!subSurface) { - DFBResult result; - subSurface = screen->getSubSurface(dfbSurface, QRect(), QDirectFBScreen::TrackSurface, &result); - if (result != DFB_OK || !subSurface) { - DirectFBError("Couldn't create sub surface", result); - return false; - } - } - IDirectFBSurface *surface = subSurface; -#else - IDirectFBSurface *surface = dfbSurface; -#endif - Q_ASSERT(surface); - mem = QDirectFBScreen::lockSurface(surface, lockFlags, &bpl); - lockFlgs = lockFlags; - Q_ASSERT(mem); - Q_ASSERT(bpl > 0); - const QSize s = size(); - lockedImage = QImage(mem, s.width(), s.height(), bpl, - QDirectFBScreen::getImageFormat(dfbSurface)); - return true; - } -#ifdef QT_DIRECTFB_SUBSURFACE - if (syncPending) { - syncPending = false; - screen->waitIdle(); - } -#endif - return false; -} - -void QDirectFBPaintDevice::unlockSurface() -{ - if (QDirectFBScreen::instance() && lockFlgs) { -#ifdef QT_DIRECTFB_SUBSURFACE - IDirectFBSurface *surface = subSurface; -#else - IDirectFBSurface *surface = dfbSurface; -#endif - if (surface) { - surface->Unlock(surface); - lockFlgs = static_cast<DFBSurfaceLockFlags>(0); - mem = 0; - } - } -} - -void *QDirectFBPaintDevice::memory() const -{ - return mem; -} - -QImage::Format QDirectFBPaintDevice::format() const -{ - return imageFormat; -} - -int QDirectFBPaintDevice::bytesPerLine() const -{ - Q_ASSERT(!mem || bpl != -1); - return bpl; -} - -QSize QDirectFBPaintDevice::size() const -{ - int w, h; - dfbSurface->GetSize(dfbSurface, &w, &h); - return QSize(w, h); -} - -int QDirectFBPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const -{ - if (!dfbSurface) - return 0; - - switch (metric) { - case QPaintDevice::PdmWidth: - case QPaintDevice::PdmHeight: - return (metric == PdmWidth ? size().width() : size().height()); - case QPaintDevice::PdmWidthMM: - return (size().width() * 1000) / dotsPerMeterX(); - case QPaintDevice::PdmHeightMM: - return (size().height() * 1000) / dotsPerMeterY(); - case QPaintDevice::PdmPhysicalDpiX: - case QPaintDevice::PdmDpiX: - return (dotsPerMeterX() * 254) / 10000; // 0.0254 meters-per-inch - case QPaintDevice::PdmPhysicalDpiY: - case QPaintDevice::PdmDpiY: - return (dotsPerMeterY() * 254) / 10000; // 0.0254 meters-per-inch - case QPaintDevice::PdmDepth: - return QDirectFBScreen::depth(imageFormat); - case QPaintDevice::PdmNumColors: { - if (!lockedImage.isNull()) - return lockedImage.colorCount(); - - DFBResult result; - IDirectFBPalette *palette = 0; - unsigned int numColors = 0; - - result = dfbSurface->GetPalette(dfbSurface, &palette); - if ((result != DFB_OK) || !palette) - return 0; - - result = palette->GetSize(palette, &numColors); - palette->Release(palette); - if (result != DFB_OK) - return 0; - - return numColors; - } - default: - qCritical("QDirectFBPaintDevice::metric(): Unhandled metric!"); - return 0; - } -} - -QPaintEngine *QDirectFBPaintDevice::paintEngine() const -{ - return engine; -} - -#ifdef QT_DIRECTFB_SUBSURFACE -void QDirectFBPaintDevice::releaseSubSurface() -{ - Q_ASSERT(QDirectFBScreen::instance()); - if (subSurface) { - unlockSurface(); - screen->releaseDFBSurface(subSurface); - subSurface = 0; - } -} -#endif - -QT_END_NAMESPACE - -#endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h deleted file mode 100644 index 975954a496..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h +++ /dev/null @@ -1,108 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDIRECTFBPAINTDEVICE_H -#define QDIRECTFBPAINTDEVICE_H - -#include <private/qpaintengine_raster_p.h> -#include "qdirectfbscreen.h" - -#ifndef QT_NO_QWS_DIRECTFB - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) - -// Inherited by both window surface and pixmap -class QDirectFBPaintEngine; -class QDirectFBPaintDevice : public QCustomRasterPaintDevice -{ -public: - ~QDirectFBPaintDevice(); - - virtual IDirectFBSurface *directFBSurface() const; - - bool lockSurface(DFBSurfaceLockFlags lockFlags); - void unlockSurface(); - - // Reimplemented from QCustomRasterPaintDevice: - void *memory() const; - QImage::Format format() const; - int bytesPerLine() const; - QSize size() const; - int metric(QPaintDevice::PaintDeviceMetric metric) const; - DFBSurfaceLockFlags lockFlags() const { return lockFlgs; } - QPaintEngine *paintEngine() const; -protected: - QDirectFBPaintDevice(QDirectFBScreen *scr); - inline int dotsPerMeterX() const - { - return (screen->deviceWidth() * 1000) / screen->physicalWidth(); - } - inline int dotsPerMeterY() const - { - return (screen->deviceHeight() * 1000) / screen->physicalHeight(); - } - - IDirectFBSurface *dfbSurface; -#ifdef QT_DIRECTFB_SUBSURFACE - void releaseSubSurface(); - IDirectFBSurface *subSurface; - friend class QDirectFBPaintEnginePrivate; - bool syncPending; -#endif - QImage lockedImage; - QDirectFBScreen *screen; - int bpl; - DFBSurfaceLockFlags lockFlgs; - uchar *mem; - QDirectFBPaintEngine *engine; - QImage::Format imageFormat; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QT_NO_QWS_DIRECTFB -#endif //QDIRECTFBPAINTDEVICE_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp deleted file mode 100644 index 18861cfac1..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ /dev/null @@ -1,1430 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdirectfbpaintengine.h" - -#ifndef QT_NO_QWS_DIRECTFB - -#include "qdirectfbwindowsurface.h" -#include "qdirectfbscreen.h" -#include "qdirectfbpixmap.h" -#include <directfb.h> -#include <qtransform.h> -#include <qvarlengtharray.h> -#include <qcache.h> -#include <qmath.h> -#include <private/qpixmapdata_p.h> -#include <private/qpixmap_raster_p.h> -#include <private/qimagepixmapcleanuphooks_p.h> - - -QT_BEGIN_NAMESPACE - -class SurfaceCache; -class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate -{ -public: - enum TransformationTypeFlags { - Matrix_NegativeScale = 0x100, - Matrix_RectsUnsupported = (QTransform::TxRotate|QTransform::TxShear|QTransform::TxProject), - Matrix_BlitsUnsupported = (Matrix_NegativeScale|Matrix_RectsUnsupported) - }; - - inline static uint getTransformationType(const QTransform &transform) - { - int ret = transform.type(); - if (qMin(transform.m11(), transform.m22()) < 0) { - ret |= QDirectFBPaintEnginePrivate::Matrix_NegativeScale; - } - return ret; - } - - enum CompositionModeStatus { - PorterDuff_None = 0x0, - PorterDuff_Supported = 0x1, - PorterDuff_PremultiplyColors = 0x2, - PorterDuff_AlwaysBlend = 0x4 - }; - - enum ClipType { - ClipUnset, - NoClip, - RectClip, - RegionClip, - ComplexClip - }; - - QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p); - ~QDirectFBPaintEnginePrivate(); - - inline void setTransform(const QTransform &transforma); - inline void setPen(const QPen &pen); - inline void setCompositionMode(QPainter::CompositionMode mode); - inline void setRenderHints(QPainter::RenderHints hints); - - inline void setDFBColor(const QColor &color); - - inline void lock(); - inline void unlock(); - static inline void unlock(QDirectFBPaintDevice *device); - - inline bool isSimpleBrush(const QBrush &brush) const; - - void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos, const QTransform &pixmapTransform); - void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src); - - inline bool supportsStretchBlit() const; - - inline void updateClip(); - virtual void systemStateChanged(); - - static IDirectFBSurface *getSurface(const QImage &img, bool *release); - -#ifdef QT_DIRECTFB_IMAGECACHE - static inline int cacheCost(const QImage &img) { return img.width() * img.height() * img.depth() / 8; } -#endif - - enum BlitFlag { - HasAlpha = 0x1, - Premultiplied = 0x2 - }; - void prepareForBlit(uint blitFlags); - - IDirectFBSurface *surface; - - bool antialiased; - bool simplePen; - - uint transformationType; // this is QTransform::type() + Matrix_NegativeScale if qMin(transform.m11(), transform.m22()) < 0 - - SurfaceCache *surfaceCache; - IDirectFB *fb; - quint8 opacity; - - ClipType clipType; - QDirectFBPaintDevice *dfbDevice; - uint compositionModeStatus; - bool isPremultiplied; - - bool inClip; - QRect currentClip; - - QDirectFBPaintEngine *q; -}; - -class SurfaceCache -{ -public: - SurfaceCache() : surface(0), buffer(0), bufsize(0) {} - ~SurfaceCache() { clear(); } - IDirectFBSurface *getSurface(const uint *buf, int size); - void clear(); -private: - IDirectFBSurface *surface; - uint *buffer; - int bufsize; -}; - - -#ifdef QT_DIRECTFB_IMAGECACHE -QT_BEGIN_INCLUDE_NAMESPACE -#include <private/qimage_p.h> -QT_END_INCLUDE_NAMESPACE -struct CachedImage -{ - IDirectFBSurface *surface; - ~CachedImage() - { - if (surface && QDirectFBScreen::instance()) { - QDirectFBScreen::instance()->releaseDFBSurface(surface); - } - } -}; -static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB -#endif - -#define VOID_ARG() static_cast<bool>(false) -enum PaintOperation { - DRAW_RECTS = 0x0001, DRAW_LINES = 0x0002, DRAW_IMAGE = 0x0004, - DRAW_PIXMAP = 0x0008, DRAW_TILED_PIXMAP = 0x0010, STROKE_PATH = 0x0020, - DRAW_PATH = 0x0040, DRAW_POINTS = 0x0080, DRAW_ELLIPSE = 0x0100, - DRAW_POLYGON = 0x0200, DRAW_TEXT = 0x0400, FILL_PATH = 0x0800, - FILL_RECT = 0x1000, DRAW_COLORSPANS = 0x2000, DRAW_ROUNDED_RECT = 0x4000, - DRAW_STATICTEXT = 0x8000, ALL = 0xffff -}; - -enum { RasterWarn = 1, RasterDisable = 2 }; -static inline uint rasterFallbacksMask(PaintOperation op) -{ - uint ret = 0; -#ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS - if (op & QT_DIRECTFB_WARN_ON_RASTERFALLBACKS) - ret |= RasterWarn; -#endif -#ifdef QT_DIRECTFB_DISABLE_RASTERFALLBACKS - if (op & QT_DIRECTFB_DISABLE_RASTERFALLBACKS) - ret |= RasterDisable; -#endif - static int warningMask = -1; - static int disableMask = -1; - if (warningMask < 0) { - struct { - const char *name; - PaintOperation operation; - } const operations[] = { - { "DRAW_RECTS", DRAW_RECTS }, - { "DRAW_LINES", DRAW_LINES }, - { "DRAW_IMAGE", DRAW_IMAGE }, - { "DRAW_PIXMAP", DRAW_PIXMAP }, - { "DRAW_TILED_PIXMAP", DRAW_TILED_PIXMAP }, - { "STROKE_PATH", STROKE_PATH }, - { "DRAW_PATH", DRAW_PATH }, - { "DRAW_POINTS", DRAW_POINTS }, - { "DRAW_ELLIPSE", DRAW_ELLIPSE }, - { "DRAW_POLYGON", DRAW_POLYGON }, - { "DRAW_TEXT", DRAW_TEXT }, - { "FILL_PATH", FILL_PATH }, - { "FILL_RECT", FILL_RECT }, - { "DRAW_COLORSPANS", DRAW_COLORSPANS }, - { "DRAW_ROUNDED_RECT", DRAW_ROUNDED_RECT }, - { "ALL", ALL }, - { 0, ALL } - }; - - QStringList warning = QString::fromLatin1(qgetenv("QT_DIRECTFB_WARN_ON_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'), - QString::SkipEmptyParts); - QStringList disable = QString::fromLatin1(qgetenv("QT_DIRECTFB_DISABLE_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'), - QString::SkipEmptyParts); - warningMask = 0; - disableMask = 0; - if (!warning.isEmpty() || !disable.isEmpty()) { - for (int i=0; operations[i].name; ++i) { - const QString name = QString::fromLatin1(operations[i].name); - int idx = warning.indexOf(name); - if (idx != -1) { - warningMask |= operations[i].operation; - warning.erase(warning.begin() + idx); - } - idx = disable.indexOf(name); - if (idx != -1) { - disableMask |= operations[i].operation; - disable.erase(disable.begin() + idx); - } - } - } - if (!warning.isEmpty()) { - qWarning("QDirectFBPaintEngine QT_DIRECTFB_WARN_ON_RASTERFALLBACKS Unknown operation(s): %s", - qPrintable(warning.join(QLatin1String("|")))); - } - if (!disable.isEmpty()) { - qWarning("QDirectFBPaintEngine QT_DIRECTFB_DISABLE_RASTERFALLBACKS Unknown operation(s): %s", - qPrintable(disable.join(QLatin1String("|")))); - } - } - if (op & warningMask) - ret |= RasterWarn; - if (op & disableMask) - ret |= RasterDisable; - return ret; -} - -template <typename device, typename T1, typename T2, typename T3> -static void rasterFallbackWarn(const char *msg, const char *func, const device *dev, - uint transformationType, bool simplePen, - uint clipType, uint compositionModeStatus, - const char *nameOne, const T1 &one, - const char *nameTwo, const T2 &two, - const char *nameThree, const T3 &three); - -#define RASTERFALLBACK(op, one, two, three) \ - { \ - static const uint rasterFallbacks = rasterFallbacksMask(op); \ - switch (rasterFallbacks) { \ - case 0: break; \ - case RasterWarn: \ - rasterFallbackWarn("Falling back to raster engine for", \ - __FUNCTION__, \ - state()->painter->device(), \ - d_func()->transformationType, \ - d_func()->simplePen, \ - d_func()->clipType, \ - d_func()->compositionModeStatus, \ - #one, one, #two, two, #three, three); \ - break; \ - case RasterDisable|RasterWarn: \ - rasterFallbackWarn("Disabled raster engine operation", \ - __FUNCTION__, \ - state()->painter->device(), \ - d_func()->transformationType, \ - d_func()->simplePen, \ - d_func()->clipType, \ - d_func()->compositionModeStatus, \ - #one, one, #two, two, #three, three); \ - case RasterDisable: \ - return; \ - } \ - } - -template <class T> -static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface); -template <class T> -static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface); -template <class T> -static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface); - -#define CLIPPED_PAINT(operation) { \ - d->unlock(); \ - DFBRegion clipRegion; \ - switch (d->clipType) { \ - case QDirectFBPaintEnginePrivate::NoClip: \ - case QDirectFBPaintEnginePrivate::RectClip: \ - operation; \ - break; \ - case QDirectFBPaintEnginePrivate::RegionClip: { \ - Q_ASSERT(d->clip()); \ - const QVector<QRect> cr = d->clip()->clipRegion.rects(); \ - const int size = cr.size(); \ - for (int i=0; i<size; ++i) { \ - d->currentClip = cr.at(i); \ - clipRegion.x1 = d->currentClip.x(); \ - clipRegion.y1 = d->currentClip.y(); \ - clipRegion.x2 = d->currentClip.right(); \ - clipRegion.y2 = d->currentClip.bottom(); \ - d->surface->SetClip(d->surface, &clipRegion); \ - operation; \ - } \ - d->updateClip(); \ - break; } \ - case QDirectFBPaintEnginePrivate::ComplexClip: \ - case QDirectFBPaintEnginePrivate::ClipUnset: \ - qFatal("CLIPPED_PAINT internal error %d", d->clipType); \ - break; \ - } \ - } - - -QDirectFBPaintEngine::QDirectFBPaintEngine(QPaintDevice *device) - : QRasterPaintEngine(*(new QDirectFBPaintEnginePrivate(this)), device) -{ -} - -QDirectFBPaintEngine::~QDirectFBPaintEngine() -{ -} - -bool QDirectFBPaintEngine::begin(QPaintDevice *device) -{ - Q_D(QDirectFBPaintEngine); - if (device->devType() == QInternal::CustomRaster) { - d->dfbDevice = static_cast<QDirectFBPaintDevice*>(device); - } else if (device->devType() == QInternal::Pixmap) { - QPixmapData *data = static_cast<QPixmap*>(device)->pixmapData(); - Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); - QDirectFBPixmapData *dfbPixmapData = static_cast<QDirectFBPixmapData*>(data); - QDirectFBPaintEnginePrivate::unlock(dfbPixmapData); - d->dfbDevice = static_cast<QDirectFBPaintDevice*>(dfbPixmapData); - } - - if (d->dfbDevice) - d->surface = d->dfbDevice->directFBSurface(); - - if (!d->surface) { - qFatal("QDirectFBPaintEngine used on an invalid device: 0x%x", - device->devType()); - } - d->isPremultiplied = QDirectFBScreen::isPremultiplied(d->dfbDevice->format()); - - d->prepare(d->dfbDevice); - gccaps = AllFeatures; - d->setCompositionMode(state()->composition_mode); - - return QRasterPaintEngine::begin(device); -} - -bool QDirectFBPaintEngine::end() -{ - Q_D(QDirectFBPaintEngine); - d->unlock(); - d->dfbDevice = 0; -#if (Q_DIRECTFB_VERSION >= 0x010000) - d->surface->ReleaseSource(d->surface); -#endif - d->currentClip = QRect(); - d->surface->SetClip(d->surface, NULL); - d->surface = 0; - return QRasterPaintEngine::end(); -} - -void QDirectFBPaintEngine::clipEnabledChanged() -{ - Q_D(QDirectFBPaintEngine); - QRasterPaintEngine::clipEnabledChanged(); - d->updateClip(); -} - -void QDirectFBPaintEngine::penChanged() -{ - Q_D(QDirectFBPaintEngine); - d->setPen(state()->pen); - - QRasterPaintEngine::penChanged(); -} - -void QDirectFBPaintEngine::opacityChanged() -{ - Q_D(QDirectFBPaintEngine); - d->opacity = quint8(state()->opacity * 255); - QRasterPaintEngine::opacityChanged(); -} - -void QDirectFBPaintEngine::compositionModeChanged() -{ - Q_D(QDirectFBPaintEngine); - d->setCompositionMode(state()->compositionMode()); - QRasterPaintEngine::compositionModeChanged(); -} - -void QDirectFBPaintEngine::renderHintsChanged() -{ - Q_D(QDirectFBPaintEngine); - d->setRenderHints(state()->renderHints); - QRasterPaintEngine::renderHintsChanged(); -} - -void QDirectFBPaintEngine::transformChanged() -{ - Q_D(QDirectFBPaintEngine); - d->setTransform(state()->matrix); - QRasterPaintEngine::transformChanged(); -} - -void QDirectFBPaintEngine::setState(QPainterState *state) -{ - Q_D(QDirectFBPaintEngine); - QRasterPaintEngine::setState(state); - d->setPen(state->pen); - d->opacity = quint8(state->opacity * 255); - d->setCompositionMode(state->compositionMode()); - d->setTransform(state->transform()); - d->setRenderHints(state->renderHints); - if (d->surface) - d->updateClip(); -} - -void QDirectFBPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) -{ - Q_D(QDirectFBPaintEngine); - const bool wasInClip = d->inClip; - d->inClip = true; - QRasterPaintEngine::clip(path, op); - if (!wasInClip) { - d->inClip = false; - d->updateClip(); - } -} - -void QDirectFBPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) -{ - Q_D(QDirectFBPaintEngine); - const bool wasInClip = d->inClip; - d->inClip = true; - QRasterPaintEngine::clip(region, op); - if (!wasInClip) { - d->inClip = false; - d->updateClip(); - } -} - -void QDirectFBPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) -{ - Q_D(QDirectFBPaintEngine); - const bool wasInClip = d->inClip; - d->inClip = true; - QRasterPaintEngine::clip(rect, op); - if (!wasInClip) { - d->inClip = false; - d->updateClip(); - } -} - -void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount) -{ - Q_D(QDirectFBPaintEngine); - const QPen &pen = state()->pen; - const QBrush &brush = state()->brush; - if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen) - return; - - if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) - || !d->simplePen - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip - || !d->isSimpleBrush(brush) - || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { - RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG()); - d->lock(); - QRasterPaintEngine::drawRects(rects, rectCount); - return; - } - - if (brush.style() != Qt::NoBrush) { - d->setDFBColor(brush.color()); - CLIPPED_PAINT(QT_PREPEND_NAMESPACE(fillRects<QRect>)(rects, rectCount, state()->matrix, d->surface)); - } - - if (pen.style() != Qt::NoPen) { - d->setDFBColor(pen.color()); - CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawRects<QRect>)(rects, rectCount, state()->matrix, d->surface)); - } -} - -void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount) -{ - Q_D(QDirectFBPaintEngine); - const QPen &pen = state()->pen; - const QBrush &brush = state()->brush; - if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen) - return; - - if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) - || !d->simplePen - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip - || !d->isSimpleBrush(brush) - || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { - RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG()); - d->lock(); - QRasterPaintEngine::drawRects(rects, rectCount); - return; - } - - if (brush.style() != Qt::NoBrush) { - d->setDFBColor(brush.color()); - CLIPPED_PAINT(fillRects<QRectF>(rects, rectCount, state()->matrix, d->surface)); - } - - if (pen.style() != Qt::NoPen) { - d->setDFBColor(pen.color()); - CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawRects<QRectF>)(rects, rectCount, state()->matrix, d->surface)); - } -} - -void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount) -{ - Q_D(QDirectFBPaintEngine); - - const QPen &pen = state()->pen; - if (!d->simplePen - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip - || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { - RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG()); - d->lock(); - QRasterPaintEngine::drawLines(lines, lineCount); - return; - } - - if (pen.style() != Qt::NoPen) { - d->setDFBColor(pen.color()); - CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLine>)(lines, lineCount, state()->matrix, d->surface)); - } -} - -void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount) -{ - Q_D(QDirectFBPaintEngine); - - const QPen &pen = state()->pen; - if (!d->simplePen - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip - || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { - RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG()); - d->lock(); - QRasterPaintEngine::drawLines(lines, lineCount); - return; - } - - if (pen.style() != Qt::NoPen) { - d->setDFBColor(pen.color()); - CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLineF>)(lines, lineCount, state()->matrix, d->surface)); - } -} - -void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, - const QRectF &sr, - Qt::ImageConversionFlags flags) -{ - Q_D(QDirectFBPaintEngine); - Q_UNUSED(flags); - - /* This is hard to read. The way it works is like this: - - - If you do not have support for preallocated surfaces and do not use an - image cache we always fall back to raster engine. - - - If it's rotated/sheared/mirrored (negative scale) or we can't - clip it we fall back to raster engine. - - - If we don't cache the image, but we do have support for - preallocated surfaces we fall back to the raster engine if the - image is in a format DirectFB can't handle. - - - If we do cache the image but don't have support for preallocated - images and the cost of caching the image (bytes used) is higher - than the max image cache size we fall back to raster engine. - */ - -#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE - if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported) - || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) - || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) - || (!d->supportsStretchBlit() && state()->matrix.mapRect(r).size() != sr.size()) -#ifndef QT_DIRECTFB_IMAGECACHE - || (QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN) -#elif defined QT_NO_DIRECTFB_PREALLOCATED - || (QDirectFBPaintEnginePrivate::cacheCost(image) > imageCache.maxCost()) -#endif - ) -#endif - { - RASTERFALLBACK(DRAW_IMAGE, r, image.size(), sr); - d->lock(); - QRasterPaintEngine::drawImage(r, image, sr, flags); - return; - } -#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE - bool release; - IDirectFBSurface *imgSurface = d->getSurface(image, &release); - uint blitFlags = 0; - if (image.hasAlphaChannel()) - blitFlags |= QDirectFBPaintEnginePrivate::HasAlpha; - if (QDirectFBScreen::isPremultiplied(image.format())) - blitFlags |= QDirectFBPaintEnginePrivate::Premultiplied; - d->prepareForBlit(blitFlags); - CLIPPED_PAINT(d->blit(r, imgSurface, sr)); - if (release) { -#if (Q_DIRECTFB_VERSION >= 0x010000) - d->surface->ReleaseSource(d->surface); -#endif - imgSurface->Release(imgSurface); - } -#endif -} - -void QDirectFBPaintEngine::drawImage(const QPointF &p, const QImage &img) -{ - drawImage(QRectF(p, img.size()), img, img.rect()); -} - -void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, - const QRectF &sr) -{ - Q_D(QDirectFBPaintEngine); - - if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) { - RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); - d->lock(); - QRasterPaintEngine::drawPixmap(r, pixmap, sr); - } else { - QPixmapData *data = pixmap.pixmapData(); - Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); - QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); - if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported) - || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) - || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) - || (!d->supportsStretchBlit() && state()->matrix.mapRect(r).size() != sr.size())) { - RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); - const QImage *img = dfbData->buffer(); - d->lock(); - QRasterPaintEngine::drawImage(r, *img, sr); - } else { - QDirectFBPaintEnginePrivate::unlock(dfbData); - IDirectFBSurface *s = dfbData->directFBSurface(); - uint blitFlags = 0; - if (pixmap.hasAlphaChannel()) - blitFlags |= QDirectFBPaintEnginePrivate::HasAlpha; - if (QDirectFBScreen::isPremultiplied(dfbData->pixelFormat())) - blitFlags |= QDirectFBPaintEnginePrivate::Premultiplied; - - d->prepareForBlit(blitFlags); - CLIPPED_PAINT(d->blit(r, s, sr)); - } - } -} - -void QDirectFBPaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm) -{ - drawPixmap(QRectF(p, pm.size()), pm, pm.rect()); -} - -void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r, - const QPixmap &pixmap, - const QPointF &offset) -{ - Q_D(QDirectFBPaintEngine); - if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) { - RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset); - d->lock(); - QRasterPaintEngine::drawTiledPixmap(r, pixmap, offset); - } else if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported) - || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) - || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) - || (!d->supportsStretchBlit() && state()->matrix.isScaling())) { - RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset); - QPixmapData *pixmapData = pixmap.pixmapData(); - Q_ASSERT(pixmapData->classId() == QPixmapData::DirectFBClass); - QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(pixmapData); - const QImage *img = dfbData->buffer(); - d->lock(); - QRasterPixmapData *data = new QRasterPixmapData(QPixmapData::PixmapType); - data->fromImage(*img, Qt::AutoColor); - const QPixmap pix(data); - QRasterPaintEngine::drawTiledPixmap(r, pix, offset); - } else { - QTransform transform(state()->matrix); - CLIPPED_PAINT(d->drawTiledPixmap(r, pixmap, offset, transform)); - } -} - - -void QDirectFBPaintEngine::stroke(const QVectorPath &path, const QPen &pen) -{ - RASTERFALLBACK(STROKE_PATH, path, VOID_ARG(), VOID_ARG()); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::stroke(path, pen); -} - -void QDirectFBPaintEngine::drawPath(const QPainterPath &path) -{ - RASTERFALLBACK(DRAW_PATH, path, VOID_ARG(), VOID_ARG()); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::drawPath(path); -} - -void QDirectFBPaintEngine::drawPoints(const QPointF *points, int pointCount) -{ - RASTERFALLBACK(DRAW_POINTS, pointCount, VOID_ARG(), VOID_ARG()); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::drawPoints(points, pointCount); -} - -void QDirectFBPaintEngine::drawPoints(const QPoint *points, int pointCount) -{ - RASTERFALLBACK(DRAW_POINTS, pointCount, VOID_ARG(), VOID_ARG()); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::drawPoints(points, pointCount); -} - -void QDirectFBPaintEngine::drawEllipse(const QRectF &rect) -{ - RASTERFALLBACK(DRAW_ELLIPSE, rect, VOID_ARG(), VOID_ARG()); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::drawEllipse(rect); -} - -void QDirectFBPaintEngine::drawPolygon(const QPointF *points, int pointCount, - PolygonDrawMode mode) -{ - RASTERFALLBACK(DRAW_POLYGON, pointCount, mode, VOID_ARG()); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::drawPolygon(points, pointCount, mode); -} - -void QDirectFBPaintEngine::drawPolygon(const QPoint *points, int pointCount, - PolygonDrawMode mode) -{ - RASTERFALLBACK(DRAW_POLYGON, pointCount, mode, VOID_ARG()); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::drawPolygon(points, pointCount, mode); -} - -void QDirectFBPaintEngine::drawTextItem(const QPointF &p, - const QTextItem &textItem) -{ - RASTERFALLBACK(DRAW_TEXT, p, textItem.text(), VOID_ARG()); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::drawTextItem(p, textItem); -} - -void QDirectFBPaintEngine::fill(const QVectorPath &path, const QBrush &brush) -{ - if (brush.style() == Qt::NoBrush) - return; - RASTERFALLBACK(FILL_PATH, path, brush, VOID_ARG()); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::fill(path, brush); -} - -void QDirectFBPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode) -{ - RASTERFALLBACK(DRAW_ROUNDED_RECT, rect, xrad, yrad); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::drawRoundedRect(rect, xrad, yrad, mode); -} - -void QDirectFBPaintEngine::drawStaticTextItem(QStaticTextItem *item) -{ - RASTERFALLBACK(DRAW_STATICTEXT, item, VOID_ARG(), VOID_ARG()); - Q_D(QDirectFBPaintEngine); - d->lock(); - QRasterPaintEngine::drawStaticTextItem(item); -} - -void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) -{ - Q_D(QDirectFBPaintEngine); - if (brush.style() == Qt::NoBrush) - return; - if (d->clipType != QDirectFBPaintEnginePrivate::ComplexClip) { - switch (brush.style()) { - case Qt::SolidPattern: { - const QColor color = brush.color(); - if (!color.isValid()) - return; - - if (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported - || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { - break; - } - d->setDFBColor(color); - const QRect r = state()->matrix.mapRect(rect).toRect(); - CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height())); - return; } - - case Qt::TexturePattern: { - const QPointF &brushOrigin = state()->brushOrigin; - const QTransform stateTransform = state()->matrix; - QTransform transform(stateTransform); - transform.translate(brushOrigin.x(), brushOrigin.y()); - transform = brush.transform() * transform; - if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported) - || (QDirectFBPaintEnginePrivate::getTransformationType(transform) & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) - || (!d->supportsStretchBlit() && transform.isScaling())) { - break; - } - - const QPixmap texture = brush.texture(); - if (texture.pixmapData()->classId() != QPixmapData::DirectFBClass) - break; - - CLIPPED_PAINT(d->drawTiledPixmap(stateTransform.mapRect(rect), texture, rect.topLeft() - brushOrigin, transform)); - return; } - default: - break; - } - } - RASTERFALLBACK(FILL_RECT, rect, brush, VOID_ARG()); - d->lock(); - QRasterPaintEngine::fillRect(rect, brush); -} - -void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color) -{ - if (!color.isValid()) - return; - Q_D(QDirectFBPaintEngine); - if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) - || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) - || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { - RASTERFALLBACK(FILL_RECT, rect, color, VOID_ARG()); - d->lock(); - QRasterPaintEngine::fillRect(rect, color); - } else { - d->setDFBColor(color); - const QRect r = state()->matrix.mapRect(rect).toRect(); - CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height())); - } -} - -void QDirectFBPaintEngine::drawBufferSpan(const uint *buffer, int bufsize, - int x, int y, int length, - uint const_alpha) -{ - Q_D(QDirectFBPaintEngine); - IDirectFBSurface *src = d->surfaceCache->getSurface(buffer, bufsize); - // ### how does this play with setDFBColor - src->SetColor(src, 0, 0, 0, const_alpha); - const DFBRectangle rect = { 0, 0, length, 1 }; - d->surface->Blit(d->surface, src, &rect, x, y); -} - -#ifdef QT_DIRECTFB_IMAGECACHE -static void cachedImageCleanupHook(qint64 key) -{ - delete imageCache.take(key); -} -void QDirectFBPaintEngine::initImageCache(int size) -{ - Q_ASSERT(size >= 0); - imageCache.setMaxCost(size); - QImagePixmapCleanupHooks::instance()->addImageHook(cachedImageCleanupHook); -} - -#endif // QT_DIRECTFB_IMAGECACHE - -// ---- QDirectFBPaintEnginePrivate ---- - - -QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p) - : surface(0), antialiased(false), simplePen(false), - transformationType(0), opacity(255), - clipType(ClipUnset), dfbDevice(0), - compositionModeStatus(0), isPremultiplied(false), inClip(false), q(p) -{ - fb = QDirectFBScreen::instance()->dfb(); - surfaceCache = new SurfaceCache; -} - -QDirectFBPaintEnginePrivate::~QDirectFBPaintEnginePrivate() -{ - delete surfaceCache; -} - -bool QDirectFBPaintEnginePrivate::isSimpleBrush(const QBrush &brush) const -{ - return (brush.style() == Qt::NoBrush) || (brush.style() == Qt::SolidPattern && !antialiased); -} - -void QDirectFBPaintEnginePrivate::lock() -{ - // We will potentially get a new pointer to the buffer after a - // lock so we need to call the base implementation of prepare so - // it updates its rasterBuffer to point to the new buffer address. - Q_ASSERT(dfbDevice); - if (dfbDevice->lockSurface(DSLF_READ|DSLF_WRITE)) { - prepare(dfbDevice); - } -} - -void QDirectFBPaintEnginePrivate::unlock() -{ - Q_ASSERT(dfbDevice); -#ifdef QT_DIRECTFB_SUBSURFACE - dfbDevice->syncPending = true; -#else - QDirectFBPaintEnginePrivate::unlock(dfbDevice); -#endif -} - -void QDirectFBPaintEnginePrivate::unlock(QDirectFBPaintDevice *device) -{ -#ifdef QT_NO_DIRECTFB_SUBSURFACE - Q_ASSERT(device); - device->unlockSurface(); -#else - Q_UNUSED(device); -#endif -} - -void QDirectFBPaintEnginePrivate::setTransform(const QTransform &transform) -{ - transformationType = getTransformationType(transform); - setPen(q->state()->pen); -} - -void QDirectFBPaintEnginePrivate::setPen(const QPen &pen) -{ - if (pen.style() == Qt::NoPen) { - simplePen = true; - } else if (pen.style() == Qt::SolidLine - && !antialiased - && pen.brush().style() == Qt::SolidPattern - && pen.widthF() <= 1.0 - && (transformationType < QTransform::TxScale || pen.isCosmetic())) { - simplePen = true; - } else { - simplePen = false; - } -} - -void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode mode) -{ - if (!surface) - return; - - static const bool forceRasterFallBack = qgetenv("QT_DIRECTFB_FORCE_RASTER").toInt() > 0; - if (forceRasterFallBack) { - compositionModeStatus = PorterDuff_None; - return; - } - - compositionModeStatus = PorterDuff_Supported|PorterDuff_PremultiplyColors|PorterDuff_AlwaysBlend; - switch (mode) { - case QPainter::CompositionMode_Clear: - surface->SetPorterDuff(surface, DSPD_CLEAR); - break; - case QPainter::CompositionMode_Source: - surface->SetPorterDuff(surface, DSPD_SRC); - compositionModeStatus &= ~PorterDuff_AlwaysBlend; - if (!isPremultiplied) - compositionModeStatus &= ~PorterDuff_PremultiplyColors; - break; - case QPainter::CompositionMode_SourceOver: - compositionModeStatus &= ~PorterDuff_AlwaysBlend; - surface->SetPorterDuff(surface, DSPD_SRC_OVER); - break; - case QPainter::CompositionMode_DestinationOver: - surface->SetPorterDuff(surface, DSPD_DST_OVER); - break; - case QPainter::CompositionMode_SourceIn: - surface->SetPorterDuff(surface, DSPD_SRC_IN); - if (!isPremultiplied) - compositionModeStatus &= ~PorterDuff_PremultiplyColors; - break; - case QPainter::CompositionMode_DestinationIn: - surface->SetPorterDuff(surface, DSPD_DST_IN); - break; - case QPainter::CompositionMode_SourceOut: - surface->SetPorterDuff(surface, DSPD_SRC_OUT); - break; - case QPainter::CompositionMode_DestinationOut: - surface->SetPorterDuff(surface, DSPD_DST_OUT); - break; - case QPainter::CompositionMode_Destination: - surface->SetSrcBlendFunction(surface, DSBF_ZERO); - surface->SetDstBlendFunction(surface, DSBF_ONE); - break; -#if (Q_DIRECTFB_VERSION >= 0x010000) - case QPainter::CompositionMode_SourceAtop: - surface->SetPorterDuff(surface, DSPD_SRC_ATOP); - break; - case QPainter::CompositionMode_DestinationAtop: - surface->SetPorterDuff(surface, DSPD_DST_ATOP); - break; - case QPainter::CompositionMode_Plus: - surface->SetPorterDuff(surface, DSPD_ADD); - break; - case QPainter::CompositionMode_Xor: - surface->SetPorterDuff(surface, DSPD_XOR); - break; -#endif - default: - compositionModeStatus = PorterDuff_None; - break; - } -} - -void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints) -{ - const bool old = antialiased; - antialiased = bool(hints & QPainter::Antialiasing); - if (old != antialiased) { - setPen(q->state()->pen); - } -} - -void QDirectFBPaintEnginePrivate::prepareForBlit(uint flags) -{ - DFBSurfaceBlittingFlags blittingFlags = DSBLIT_NOFX; - if (flags & Premultiplied) - blittingFlags |= DSBLIT_SRC_PREMULTIPLY; - if (flags & HasAlpha) - blittingFlags |= DSBLIT_BLEND_ALPHACHANNEL; - if (opacity != 255) { - blittingFlags |= DSBLIT_BLEND_COLORALPHA; - surface->SetColor(surface, 0xff, 0xff, 0xff, opacity); - } - - surface->SetBlittingFlags(surface, blittingFlags); -} - -static inline uint ALPHA_MUL(uint x, uint a) -{ - uint t = x * a; - t = ((t + (t >> 8) + 0x80) >> 8) & 0xff; - return t; -} - -void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color) -{ - Q_ASSERT(surface); - Q_ASSERT(compositionModeStatus & PorterDuff_Supported); - const quint8 alpha = (opacity == 255 ? - color.alpha() : ALPHA_MUL(color.alpha(), opacity)); - QColor col; - if (compositionModeStatus & PorterDuff_PremultiplyColors) { - col = QColor(ALPHA_MUL(color.red(), alpha), - ALPHA_MUL(color.green(), alpha), - ALPHA_MUL(color.blue(), alpha), - alpha); - } else { - col = QColor(color.red(), color.green(), color.blue(), alpha); - } - surface->SetColor(surface, col.red(), col.green(), col.blue(), col.alpha()); - surface->SetDrawingFlags(surface, alpha == 255 && !(compositionModeStatus & PorterDuff_AlwaysBlend) ? DSDRAW_NOFX : DSDRAW_BLEND); -} - -IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, bool *release) -{ -#ifdef QT_NO_DIRECTFB_IMAGECACHE - *release = true; - return QDirectFBScreen::instance()->createDFBSurface(img, img.format(), QDirectFBScreen::DontTrackSurface); -#else - const qint64 key = img.cacheKey(); - *release = false; - if (imageCache.contains(key)) { - return imageCache[key]->surface; - } - - const int cost = cacheCost(img); - const bool cache = cost <= imageCache.maxCost(); - QDirectFBScreen *screen = QDirectFBScreen::instance(); - const QImage::Format format = (img.format() == screen->alphaPixmapFormat() || QDirectFBPixmapData::hasAlphaChannel(img) - ? screen->alphaPixmapFormat() : screen->pixelFormat()); - - IDirectFBSurface *surface = screen->createDFBSurface(img, format, - cache - ? QDirectFBScreen::TrackSurface - : QDirectFBScreen::DontTrackSurface); - if (cache) { - CachedImage *cachedImage = new CachedImage; - const_cast<QImage&>(img).data_ptr()->is_cached = true; - cachedImage->surface = surface; - imageCache.insert(key, cachedImage, cost); - } else { - *release = true; - } - return surface; -#endif -} - - -void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, const QRectF &src) -{ - const QRect sr = src.toRect(); - const QRect dr = q->state()->matrix.mapRect(dest).toRect(); - if (dr.isEmpty()) - return; - const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() }; - DFBResult result; - - if (dr.size() == sr.size()) { - result = surface->Blit(surface, s, &sRect, dr.x(), dr.y()); - } else { - Q_ASSERT(supportsStretchBlit()); - const DFBRectangle dRect = { dr.x(), dr.y(), dr.width(), dr.height() }; - result = surface->StretchBlit(surface, s, &sRect, &dRect); - } - if (result != DFB_OK) - DirectFBError("QDirectFBPaintEngine::drawPixmap()", result); -} - -static inline qreal fixCoord(qreal rect_pos, qreal pixmapSize, qreal offset) -{ - qreal pos = rect_pos - offset; - while (pos > rect_pos) - pos -= pixmapSize; - while (pos + pixmapSize < rect_pos) - pos += pixmapSize; - return pos; -} - -void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, - const QPointF &off, const QTransform &pixmapTransform) -{ - const QTransform &transform = q->state()->matrix; - Q_ASSERT(!(getTransformationType(transform) & Matrix_BlitsUnsupported) && - !(getTransformationType(pixmapTransform) & Matrix_BlitsUnsupported)); - const QRect destinationRect = transform.mapRect(dest).toRect().normalized(); - QRect newClip = destinationRect; - if (!currentClip.isEmpty()) - newClip &= currentClip; - - if (newClip.isNull()) - return; - - const DFBRegion clip = { - newClip.x(), - newClip.y(), - newClip.right(), - newClip.bottom() - }; - surface->SetClip(surface, &clip); - - QPointF offset = pixmapTransform.inverted().map(off); - Q_ASSERT(transform.type() <= QTransform::TxScale); - QPixmapData *data = pixmap.pixmapData(); - Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); - QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); - IDirectFBSurface *sourceSurface = dfbData->directFBSurface(); - uint blitFlags = 0; - if (dfbData->hasAlphaChannel()) - blitFlags |= HasAlpha; - if (QDirectFBScreen::isPremultiplied(dfbData->pixelFormat())) - blitFlags |= Premultiplied; - prepareForBlit(blitFlags); - QDirectFBPaintEnginePrivate::unlock(dfbData); - const QSize pixmapSize = dfbData->size(); - if (transform.isScaling() || pixmapTransform.isScaling()) { - Q_ASSERT(supportsStretchBlit()); - Q_ASSERT(qMin(transform.m11(), transform.m22()) >= 0); - offset.rx() *= transform.m11(); - offset.ry() *= transform.m22(); - - const QSizeF mappedSize(pixmapSize.width() * pixmapTransform.m11(), pixmapSize.height() * pixmapTransform.m22()); - qreal y = fixCoord(destinationRect.y(), mappedSize.height(), offset.y()); - const qreal startX = fixCoord(destinationRect.x(), mappedSize.width(), offset.x()); - while (y <= destinationRect.bottom()) { - qreal x = startX; - while (x <= destinationRect.right()) { - const DFBRectangle destination = { qRound(x), qRound(y), mappedSize.width(), mappedSize.height() }; - surface->StretchBlit(surface, sourceSurface, 0, &destination); - x += mappedSize.width(); - } - y += mappedSize.height(); - } - } else { - qreal y = fixCoord(destinationRect.y(), pixmapSize.height(), offset.y()); - const qreal startX = fixCoord(destinationRect.x(), pixmapSize.width(), offset.x()); - int horizontal = qMax(1, destinationRect.width() / pixmapSize.width()) + 1; - if (startX != destinationRect.x()) - ++horizontal; - int vertical = qMax(1, destinationRect.height() / pixmapSize.height()) + 1; - if (y != destinationRect.y()) - ++vertical; - - const int maxCount = (vertical * horizontal); - QVarLengthArray<DFBRectangle, 16> sourceRects(maxCount); - QVarLengthArray<DFBPoint, 16> points(maxCount); - - int i = 0; - while (y <= destinationRect.bottom()) { - Q_ASSERT(i < maxCount); - qreal x = startX; - while (x <= destinationRect.right()) { - points[i].x = qRound(x); - points[i].y = qRound(y); - sourceRects[i].x = 0; - sourceRects[i].y = 0; - sourceRects[i].w = int(pixmapSize.width()); - sourceRects[i].h = int(pixmapSize.height()); - x += pixmapSize.width(); - ++i; - } - y += pixmapSize.height(); - } - surface->BatchBlit(surface, sourceSurface, sourceRects.constData(), points.constData(), i); - } - - if (currentClip.isEmpty()) { - surface->SetClip(surface, 0); - } else { - const DFBRegion clip = { - currentClip.x(), - currentClip.y(), - currentClip.right(), - currentClip.bottom() - }; - surface->SetClip(surface, &clip); - } -} - -void QDirectFBPaintEnginePrivate::updateClip() -{ - Q_ASSERT(surface); - currentClip = QRect(); - const QClipData *clipData = clip(); - if (!clipData || !clipData->enabled) { - surface->SetClip(surface, NULL); - clipType = NoClip; - } else if (clipData->hasRectClip) { - const DFBRegion r = { - clipData->clipRect.x(), - clipData->clipRect.y(), - clipData->clipRect.right(), - clipData->clipRect.bottom() - }; - surface->SetClip(surface, &r); - currentClip = clipData->clipRect.normalized(); - // ### is this guaranteed to always be normalized? - clipType = RectClip; - } else if (clipData->hasRegionClip) { - clipType = RegionClip; - } else { - clipType = ComplexClip; - } -} - -bool QDirectFBPaintEnginePrivate::supportsStretchBlit() const -{ -#ifdef QT_DIRECTFB_STRETCHBLIT - return !(q->state()->renderHints & QPainter::SmoothPixmapTransform); -#else - return false; -#endif -} - - -void QDirectFBPaintEnginePrivate::systemStateChanged() -{ - QRasterPaintEnginePrivate::systemStateChanged(); - updateClip(); -} - -IDirectFBSurface *SurfaceCache::getSurface(const uint *buf, int size) -{ - if (buffer == buf && bufsize == size) - return surface; - - clear(); - - const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size); - surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface, 0); - if (!surface) - qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface"); - - buffer = const_cast<uint*>(buf); - bufsize = size; - - return surface; -} - -void SurfaceCache::clear() -{ - if (surface && QDirectFBScreen::instance()) - QDirectFBScreen::instance()->releaseDFBSurface(surface); - surface = 0; - buffer = 0; - bufsize = 0; -} - - -static inline QRect mapRect(const QTransform &transform, const QRect &rect) { return transform.mapRect(rect); } -static inline QRect mapRect(const QTransform &transform, const QRectF &rect) { return transform.mapRect(rect).toRect(); } -static inline QLine map(const QTransform &transform, const QLine &line) { return transform.map(line); } -static inline QLine map(const QTransform &transform, const QLineF &line) { return transform.map(line).toLine(); } -template <class T> -static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface) -{ - if (n == 1) { - const QLine l = map(transform, lines[0]); - surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); - } else { - QVarLengthArray<DFBRegion, 32> lineArray(n); - for (int i=0; i<n; ++i) { - const QLine l = map(transform, lines[i]); - lineArray[i].x1 = l.x1(); - lineArray[i].y1 = l.y1(); - lineArray[i].x2 = l.x2(); - lineArray[i].y2 = l.y2(); - } - surface->DrawLines(surface, lineArray.constData(), n); - } -} - -template <class T> -static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface) -{ - if (n == 1) { - const QRect r = mapRect(transform, rects[0]); - surface->FillRectangle(surface, r.x(), r.y(), r.width(), r.height()); - } else { - QVarLengthArray<DFBRectangle, 32> rectArray(n); - for (int i=0; i<n; ++i) { - const QRect r = mapRect(transform, rects[i]); - rectArray[i].x = r.x(); - rectArray[i].y = r.y(); - rectArray[i].w = r.width(); - rectArray[i].h = r.height(); - } - surface->FillRectangles(surface, rectArray.constData(), n); - } -} - -template <class T> -static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface) -{ - for (int i=0; i<n; ++i) { - const QRect r = mapRect(transform, rects[i]); - surface->DrawRectangle(surface, r.x(), r.y(), r.width(), r.height()); - } -} - -template <typename T> inline const T *ptr(const T &t) { return &t; } -template <> inline const bool* ptr<bool>(const bool &) { return 0; } -template <typename device, typename T1, typename T2, typename T3> -static void rasterFallbackWarn(const char *msg, const char *func, const device *dev, - uint transformationType, bool simplePen, - uint clipType, uint compositionModeStatus, - const char *nameOne, const T1 &one, - const char *nameTwo, const T2 &two, - const char *nameThree, const T3 &three) -{ - QString out; - QDebug dbg(&out); - dbg << msg << (QByteArray(func) + "()") << "painting on"; - if (dev->devType() == QInternal::Widget) { - dbg << static_cast<const QWidget*>(dev); - } else { - dbg << dev << "of type" << dev->devType(); - } - - dbg << QString::fromLatin1("transformationType 0x%1").arg(transformationType, 3, 16, QLatin1Char('0')) - << "simplePen" << simplePen - << "clipType" << clipType - << "compositionModeStatus" << compositionModeStatus; - - const T1 *t1 = ptr(one); - const T2 *t2 = ptr(two); - const T3 *t3 = ptr(three); - - if (t1) { - dbg << nameOne << *t1; - if (t2) { - dbg << nameTwo << *t2; - if (t3) { - dbg << nameThree << *t3; - } - } - } - qWarning("%s", qPrintable(out)); -} - -QT_END_NAMESPACE - -#endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h deleted file mode 100644 index a3217d0f32..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPAINTENGINE_DIRECTFB_P_H -#define QPAINTENGINE_DIRECTFB_P_H - -#include <QtGui/qpaintengine.h> -#include <private/qpaintengine_raster_p.h> - -#ifndef QT_NO_QWS_DIRECTFB - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) - -class QDirectFBPaintEnginePrivate; - -class QDirectFBPaintEngine : public QRasterPaintEngine -{ - Q_DECLARE_PRIVATE(QDirectFBPaintEngine) -public: - QDirectFBPaintEngine(QPaintDevice *device); - virtual ~QDirectFBPaintEngine(); - - virtual bool begin(QPaintDevice *device); - virtual bool end(); - - virtual void drawRects(const QRect *rects, int rectCount); - virtual void drawRects(const QRectF *rects, int rectCount); - - virtual void fillRect(const QRectF &r, const QBrush &brush); - virtual void fillRect(const QRectF &r, const QColor &color); - - virtual void drawLines(const QLine *line, int lineCount); - virtual void drawLines(const QLineF *line, int lineCount); - - virtual void drawImage(const QPointF &p, const QImage &img); - virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, - Qt::ImageConversionFlags falgs = Qt::AutoColor); - - virtual void drawPixmap(const QPointF &p, const QPixmap &pm); - virtual void drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr); - virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr); - - virtual void drawBufferSpan(const uint *buffer, int bufsize, - int x, int y, int length, uint const_alpha); - - virtual void stroke(const QVectorPath &path, const QPen &pen); - virtual void drawPath(const QPainterPath &path); - virtual void drawPoints(const QPointF *points, int pointCount); - virtual void drawPoints(const QPoint *points, int pointCount); - virtual void drawEllipse(const QRectF &rect); - virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); - virtual void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode); - virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); - virtual void fill(const QVectorPath &path, const QBrush &brush); - virtual void drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode); - - virtual void clipEnabledChanged(); - virtual void penChanged(); - virtual void opacityChanged(); - virtual void compositionModeChanged(); - virtual void renderHintsChanged(); - virtual void transformChanged(); - - virtual void setState(QPainterState *state); - - virtual void clip(const QVectorPath &path, Qt::ClipOperation op); - virtual void clip(const QRegion ®ion, Qt::ClipOperation op); - virtual void clip(const QRect &rect, Qt::ClipOperation op); - - virtual void drawStaticTextItem(QStaticTextItem *item); - - static void initImageCache(int size); -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QT_NO_QWS_DIRECTFB - -#endif // QPAINTENGINE_DIRECTFB_P_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp deleted file mode 100644 index 5259a93698..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ /dev/null @@ -1,588 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdirectfbpixmap.h" - -#ifndef QT_NO_QWS_DIRECTFB - -#include "qdirectfbscreen.h" -#include "qdirectfbpaintengine.h" - -#include <QtGui/qbitmap.h> -#include <QtCore/qfile.h> -#include <directfb.h> - - -QT_BEGIN_NAMESPACE - -static int global_ser_no = 0; - -QDirectFBPixmapData::QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType) - : QPixmapData(pixelType, DirectFBClass), QDirectFBPaintDevice(screen), - alpha(false) -{ - setSerialNumber(0); -} - -QDirectFBPixmapData::~QDirectFBPixmapData() -{ -} - -void QDirectFBPixmapData::resize(int width, int height) -{ - if (width <= 0 || height <= 0) { - invalidate(); - return; - } - - imageFormat = screen->pixelFormat(); - dfbSurface = screen->createDFBSurface(QSize(width, height), - imageFormat, - QDirectFBScreen::TrackSurface); - d = QDirectFBScreen::depth(imageFormat); - alpha = false; - if (!dfbSurface) { - invalidate(); - qWarning("QDirectFBPixmapData::resize(): Unable to allocate surface"); - return; - } - - w = width; - h = height; - is_null = (w <= 0 || h <= 0); - setSerialNumber(++global_ser_no); -} - -#ifdef QT_DIRECTFB_OPAQUE_DETECTION -// mostly duplicated from qimage.cpp (QImageData::checkForAlphaPixels) -static bool checkForAlphaPixels(const QImage &img) -{ - const uchar *bits = img.bits(); - const int bytes_per_line = img.bytesPerLine(); - const uchar *end_bits = bits + bytes_per_line; - const int width = img.width(); - const int height = img.height(); - switch (img.format()) { - case QImage::Format_Indexed8: - return img.hasAlphaChannel(); - case QImage::Format_ARGB32: - case QImage::Format_ARGB32_Premultiplied: - for (int y=0; y<height; ++y) { - for (int x=0; x<width; ++x) { - if ((((uint *)bits)[x] & 0xff000000) != 0xff000000) { - return true; - } - } - bits += bytes_per_line; - } - break; - - case QImage::Format_ARGB8555_Premultiplied: - case QImage::Format_ARGB8565_Premultiplied: - for (int y=0; y<height; ++y) { - while (bits < end_bits) { - if (bits[0] != 0) { - return true; - } - bits += 3; - } - bits = end_bits; - end_bits += bytes_per_line; - } - break; - - case QImage::Format_ARGB6666_Premultiplied: - for (int y=0; y<height; ++y) { - while (bits < end_bits) { - if ((bits[0] & 0xfc) != 0) { - return true; - } - bits += 3; - } - bits = end_bits; - end_bits += bytes_per_line; - } - break; - - case QImage::Format_ARGB4444_Premultiplied: - for (int y=0; y<height; ++y) { - while (bits < end_bits) { - if ((bits[0] & 0xf0) != 0) { - return true; - } - bits += 2; - } - bits = end_bits; - end_bits += bytes_per_line; - } - break; - - default: - break; - } - - return false; -} -#endif // QT_DIRECTFB_OPAQUE_DETECTION - -bool QDirectFBPixmapData::hasAlphaChannel(const QImage &img, Qt::ImageConversionFlags flags) -{ - if (img.depth() == 1) - return true; -#ifdef QT_DIRECTFB_OPAQUE_DETECTION - return ((flags & Qt::NoOpaqueDetection) ? img.hasAlphaChannel() : checkForAlphaPixels(img)); -#else - Q_UNUSED(flags); - return img.hasAlphaChannel(); -#endif -} - -#ifdef QT_DIRECTFB_IMAGEPROVIDER -bool QDirectFBPixmapData::fromFile(const QString &filename, const char *format, - Qt::ImageConversionFlags flags) -{ - if (!QFile::exists(filename)) - return false; - if (flags == Qt::AutoColor) { - if (filename.startsWith(QLatin1Char(':'))) { // resource - QFile file(filename); - if (!file.open(QIODevice::ReadOnly)) - return false; - const QByteArray data = file.readAll(); - file.close(); - return fromData(reinterpret_cast<const uchar*>(data.constData()), data.size(), format, flags); - } else { - DFBDataBufferDescription description; - description.flags = DBDESC_FILE; - const QByteArray fileNameData = filename.toLocal8Bit(); - description.file = fileNameData.constData(); - if (fromDataBufferDescription(description)) { - return true; - } - // fall back to Qt - } - } - return QPixmapData::fromFile(filename, format, flags); -} - -bool QDirectFBPixmapData::fromData(const uchar *buffer, uint len, const char *format, - Qt::ImageConversionFlags flags) -{ - if (flags == Qt::AutoColor) { - DFBDataBufferDescription description; - description.flags = DBDESC_MEMORY; - description.memory.data = buffer; - description.memory.length = len; - if (fromDataBufferDescription(description)) - return true; - // fall back to Qt - } - return QPixmapData::fromData(buffer, len, format, flags); -} - -template <typename T> struct QDirectFBInterfaceCleanupHandler -{ - static void cleanup(T *t) { if (t) t->Release(t); } -}; - -template <typename T> -class QDirectFBPointer : public QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> > -{ -public: - QDirectFBPointer(T *t = 0) - : QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> >(t) - {} -}; - -bool QDirectFBPixmapData::fromDataBufferDescription(const DFBDataBufferDescription &dataBufferDescription) -{ - IDirectFB *dfb = screen->dfb(); - Q_ASSERT(dfb); - DFBResult result = DFB_OK; - IDirectFBDataBuffer *dataBufferPtr; - if ((result = dfb->CreateDataBuffer(dfb, &dataBufferDescription, &dataBufferPtr)) != DFB_OK) { - DirectFBError("QDirectFBPixmapData::fromDataBufferDescription()", result); - return false; - } - QDirectFBPointer<IDirectFBDataBuffer> dataBuffer(dataBufferPtr); - - IDirectFBImageProvider *providerPtr; - if ((result = dataBuffer->CreateImageProvider(dataBuffer.data(), &providerPtr)) != DFB_OK) - return false; - - QDirectFBPointer<IDirectFBImageProvider> provider(providerPtr); - - DFBImageDescription imageDescription; - result = provider->GetImageDescription(provider.data(), &imageDescription); - if (result != DFB_OK) { - DirectFBError("QDirectFBPixmapData::fromSurfaceDescription(): Can't get image description", result); - return false; - } - - if (imageDescription.caps & DICAPS_COLORKEY) { - return false; - } - - DFBSurfaceDescription surfaceDescription; - if ((result = provider->GetSurfaceDescription(provider.data(), &surfaceDescription)) != DFB_OK) { - DirectFBError("QDirectFBPixmapData::fromDataBufferDescription(): Can't get surface description", result); - return false; - } - - alpha = imageDescription.caps & DICAPS_ALPHACHANNEL; - imageFormat = alpha ? screen->alphaPixmapFormat() : screen->pixelFormat(); - - dfbSurface = screen->createDFBSurface(QSize(surfaceDescription.width, surfaceDescription.height), - imageFormat, QDirectFBScreen::TrackSurface); - - result = provider->RenderTo(provider.data(), dfbSurface, 0); - if (result != DFB_OK) { - DirectFBError("QDirectFBPixmapData::fromSurfaceDescription(): Can't render to surface", result); - return false; - } - - w = surfaceDescription.width; - h = surfaceDescription.height; - is_null = (w <= 0 || h <= 0); - d = QDirectFBScreen::depth(imageFormat); - setSerialNumber(++global_ser_no); - -#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE - screen->setDirectFBImageProvider(providerPtr); - provider.take(); -#endif - - return true; -} - -#endif - -void QDirectFBPixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) -{ - alpha = QDirectFBPixmapData::hasAlphaChannel(img, flags); - imageFormat = alpha ? screen->alphaPixmapFormat() : screen->pixelFormat(); - - QImage image; - if ((flags & ~Qt::NoOpaqueDetection) != Qt::AutoColor) { - image = img.convertToFormat(imageFormat, flags); - flags = Qt::AutoColor; - } else if (img.format() == QImage::Format_RGB32 || img.depth() == 1) { - image = img.convertToFormat(imageFormat, flags); - } else if (img.format() != imageFormat) { - image = img.convertToFormat(imageFormat, flags); - } else { - image = img; - } - - dfbSurface = screen->createDFBSurface(image, image.format(), QDirectFBScreen::NoPreallocated | QDirectFBScreen::TrackSurface); - if (!dfbSurface) { - qWarning("QDirectFBPixmapData::fromImage()"); - invalidate(); - return; - } - - w = image.width(); - h = image.height(); - is_null = (w <= 0 || h <= 0); - d = QDirectFBScreen::depth(imageFormat); - setSerialNumber(++global_ser_no); -#ifdef QT_NO_DIRECTFB_OPAQUE_DETECTION - Q_UNUSED(flags); -#endif -} - -void QDirectFBPixmapData::copy(const QPixmapData *data, const QRect &rect) -{ - if (data->classId() != DirectFBClass) { - QPixmapData::copy(data, rect); - return; - } - - const QDirectFBPixmapData *otherData = static_cast<const QDirectFBPixmapData*>(data); -#ifdef QT_NO_DIRECTFB_SUBSURFACE - if (otherData->lockFlags()) { - const_cast<QDirectFBPixmapData*>(otherData)->unlockSurface(); - } -#endif - IDirectFBSurface *src = otherData->directFBSurface(); - alpha = data->hasAlphaChannel(); - imageFormat = (alpha - ? QDirectFBScreen::instance()->alphaPixmapFormat() - : QDirectFBScreen::instance()->pixelFormat()); - - - dfbSurface = screen->createDFBSurface(rect.size(), imageFormat, - QDirectFBScreen::TrackSurface); - if (!dfbSurface) { - qWarning("QDirectFBPixmapData::copy()"); - invalidate(); - return; - } - - if (alpha) { - dfbSurface->Clear(dfbSurface, 0, 0, 0, 0); - dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_BLEND_ALPHACHANNEL); - } else { - dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); - } - const DFBRectangle blitRect = { rect.x(), rect.y(), - rect.width(), rect.height() }; - w = rect.width(); - h = rect.height(); - d = otherData->d; - is_null = (w <= 0 || h <= 0); - unlockSurface(); - DFBResult result = dfbSurface->Blit(dfbSurface, src, &blitRect, 0, 0); -#if (Q_DIRECTFB_VERSION >= 0x010000) - dfbSurface->ReleaseSource(dfbSurface); -#endif - if (result != DFB_OK) { - DirectFBError("QDirectFBPixmapData::copy()", result); - invalidate(); - return; - } - - setSerialNumber(++global_ser_no); -} - -static inline bool isOpaqueFormat(QImage::Format format) -{ - switch (format) { - case QImage::Format_RGB32: - case QImage::Format_RGB16: - case QImage::Format_RGB666: - case QImage::Format_RGB555: - case QImage::Format_RGB888: - case QImage::Format_RGB444: - return true; - default: - break; - } - return false; -} - -void QDirectFBPixmapData::fill(const QColor &color) -{ - if (!serialNumber()) - return; - - Q_ASSERT(dfbSurface); - - alpha |= (color.alpha() < 255); - - if (alpha && isOpaqueFormat(imageFormat)) { - QSize size; - dfbSurface->GetSize(dfbSurface, &size.rwidth(), &size.rheight()); - screen->releaseDFBSurface(dfbSurface); - imageFormat = screen->alphaPixmapFormat(); - d = QDirectFBScreen::depth(imageFormat); - dfbSurface = screen->createDFBSurface(size, screen->alphaPixmapFormat(), QDirectFBScreen::TrackSurface); - setSerialNumber(++global_ser_no); - if (!dfbSurface) { - qWarning("QDirectFBPixmapData::fill()"); - invalidate(); - return; - } - } - - dfbSurface->Clear(dfbSurface, color.red(), color.green(), color.blue(), color.alpha()); -} - -QPixmap QDirectFBPixmapData::transformed(const QTransform &transform, - Qt::TransformationMode mode) const -{ - QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); -#ifdef QT_NO_DIRECTFB_SUBSURFACE - if (lockFlags()) - that->unlockSurface(); -#endif - - if (!dfbSurface || transform.type() != QTransform::TxScale - || mode != Qt::FastTransformation) - { - const QImage *image = that->buffer(); - Q_ASSERT(image); - const QImage transformed = image->transformed(transform, mode); - QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType); - data->fromImage(transformed, Qt::AutoColor); - return QPixmap(data); - } - - const QSize size = transform.mapRect(QRect(0, 0, w, h)).size(); - if (size.isEmpty()) - return QPixmap(); - - QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType); - data->setSerialNumber(++global_ser_no); - DFBSurfaceBlittingFlags flags = DSBLIT_NOFX; - data->alpha = alpha; - if (alpha) { - flags = DSBLIT_BLEND_ALPHACHANNEL; - } - data->dfbSurface = screen->createDFBSurface(size, - imageFormat, - QDirectFBScreen::TrackSurface); - if (flags & DSBLIT_BLEND_ALPHACHANNEL) { - data->dfbSurface->Clear(data->dfbSurface, 0, 0, 0, 0); - } - data->dfbSurface->SetBlittingFlags(data->dfbSurface, flags); - - const DFBRectangle destRect = { 0, 0, size.width(), size.height() }; - data->dfbSurface->StretchBlit(data->dfbSurface, dfbSurface, 0, &destRect); - data->w = size.width(); - data->h = size.height(); - data->is_null = (data->w <= 0 || data->h <= 0); - -#if (Q_DIRECTFB_VERSION >= 0x010000) - data->dfbSurface->ReleaseSource(data->dfbSurface); -#endif - return QPixmap(data); -} - -QImage QDirectFBPixmapData::toImage() const -{ - if (!dfbSurface) - return QImage(); - -#if 0 - // In later versions of DirectFB one can set a flag to tell - // DirectFB not to move the surface to videomemory. When that - // happens we can use this (hopefully faster) codepath -#ifndef QT_NO_DIRECTFB_PREALLOCATED - QImage ret(w, h, QDirectFBScreen::getImageFormat(dfbSurface)); - if (IDirectFBSurface *imgSurface = screen->createDFBSurface(ret, QDirectFBScreen::DontTrackSurface)) { - if (hasAlphaChannel()) { - imgSurface->SetBlittingFlags(imgSurface, DSBLIT_BLEND_ALPHACHANNEL); - imgSurface->Clear(imgSurface, 0, 0, 0, 0); - } else { - imgSurface->SetBlittingFlags(imgSurface, DSBLIT_NOFX); - } - imgSurface->Blit(imgSurface, dfbSurface, 0, 0, 0); -#if (Q_DIRECTFB_VERSION >= 0x010000) - imgSurface->ReleaseSource(imgSurface); -#endif - imgSurface->Release(imgSurface); - return ret; - } -#endif -#endif - - QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); - const QImage *img = that->buffer(); - return img->copy(); -} - -/* This is QPixmapData::paintEngine(), not QPaintDevice::paintEngine() */ - -QPaintEngine *QDirectFBPixmapData::paintEngine() const -{ - if (!engine) { - // QDirectFBPixmapData is also a QCustomRasterPaintDevice, so pass - // that to the paint engine: - QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); - that->engine = new QDirectFBPaintEngine(that); - } - return engine; -} - -QImage *QDirectFBPixmapData::buffer() -{ - if (!lockFlgs) { - lockSurface(DSLF_READ|DSLF_WRITE); - } - Q_ASSERT(lockFlgs); - Q_ASSERT(!lockedImage.isNull()); - return &lockedImage; -} - - -bool QDirectFBPixmapData::scroll(int dx, int dy, const QRect &rect) -{ - if (!dfbSurface) { - return false; - } - unlockSurface(); - DFBResult result = dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); - if (result != DFB_OK) { - DirectFBError("QDirectFBPixmapData::scroll", result); - return false; - } - result = dfbSurface->SetPorterDuff(dfbSurface, DSPD_NONE); - if (result != DFB_OK) { - DirectFBError("QDirectFBPixmapData::scroll", result); - return false; - } - - const DFBRectangle source = { rect.x(), rect.y(), rect.width(), rect.height() }; - result = dfbSurface->Blit(dfbSurface, dfbSurface, &source, source.x + dx, source.y + dy); - if (result != DFB_OK) { - DirectFBError("QDirectFBPixmapData::scroll", result); - return false; - } - - return true; -} - -void QDirectFBPixmapData::invalidate() -{ - if (dfbSurface) { - screen->releaseDFBSurface(dfbSurface); - dfbSurface = 0; - } - setSerialNumber(0); - alpha = false; - d = w = h = 0; - is_null = true; - imageFormat = QImage::Format_Invalid; -} - -Q_GUI_EXPORT IDirectFBSurface *qt_directfb_surface_for_pixmap(const QPixmap &pixmap) -{ - const QPixmapData *data = pixmap.pixmapData(); - if (!data || data->classId() != QPixmapData::DirectFBClass) - return 0; - const QDirectFBPixmapData *dfbData = static_cast<const QDirectFBPixmapData*>(data); - return dfbData->directFBSurface(); -} - -QT_END_NAMESPACE - -#endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h deleted file mode 100644 index bc94b42638..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDIRECTFBPIXMAP_H -#define QDIRECTFBPIXMAP_H - -#include <qglobal.h> - -#ifndef QT_NO_QWS_DIRECTFB - -#include <QtGui/private/qpixmapdata_p.h> -#include <QtGui/private/qpaintengine_raster_p.h> -#include "qdirectfbpaintdevice.h" -#include <directfb.h> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) - -class QDirectFBPaintEngine; - -class QDirectFBPixmapData : public QPixmapData, public QDirectFBPaintDevice -{ -public: - QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType); - ~QDirectFBPixmapData(); - - // Re-implemented from QPixmapData: - virtual void resize(int width, int height); - virtual void fromImage(const QImage &image, Qt::ImageConversionFlags flags); -#ifdef QT_DIRECTFB_IMAGEPROVIDER - virtual bool fromFile(const QString &filename, const char *format, - Qt::ImageConversionFlags flags); - virtual bool fromData(const uchar *buffer, uint len, const char *format, - Qt::ImageConversionFlags flags); -#endif - virtual void copy(const QPixmapData *data, const QRect &rect); - virtual void fill(const QColor &color); - virtual QPixmap transformed(const QTransform &matrix, - Qt::TransformationMode mode) const; - virtual QImage toImage() const; - virtual QPaintEngine *paintEngine() const; - virtual QImage *buffer(); - virtual bool scroll(int dx, int dy, const QRect &rect); - // Pure virtual in QPixmapData, so re-implement here and delegate to QDirectFBPaintDevice - virtual int metric(QPaintDevice::PaintDeviceMetric m) const { return QDirectFBPaintDevice::metric(m); } - - inline QImage::Format pixelFormat() const { return imageFormat; } - inline bool hasAlphaChannel() const { return alpha; } - static bool hasAlphaChannel(const QImage &img, Qt::ImageConversionFlags flags = Qt::AutoColor); -private: -#ifdef QT_DIRECTFB_IMAGEPROVIDER - bool fromDataBufferDescription(const DFBDataBufferDescription &dataBuffer); -#endif - void invalidate(); - bool alpha; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QT_NO_QWS_DIRECTFB - -#endif // QDIRECTFBPIXMAP_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp deleted file mode 100644 index 7b1538bb49..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp +++ /dev/null @@ -1,1819 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdirectfbscreen.h" -#include "qdirectfbwindowsurface.h" -#include "qdirectfbpixmap.h" -#include "qdirectfbmouse.h" -#include "qdirectfbkeyboard.h" -#include <QtGui/qwsdisplay_qws.h> -#include <QtGui/qcolor.h> -#include <QtGui/qapplication.h> -#include <QtGui/qwindowsystem_qws.h> -#include <QtGui/private/qgraphicssystem_qws_p.h> -#include <QtGui/private/qwssignalhandler_p.h> -#include <QtCore/qvarlengtharray.h> -#include <QtCore/qvector.h> -#include <QtCore/qrect.h> - -#ifndef QT_NO_QWS_DIRECTFB - -QT_BEGIN_NAMESPACE - -class QDirectFBScreenPrivate : public QObject, public QWSGraphicsSystem -{ - Q_OBJECT -public: - QDirectFBScreenPrivate(QDirectFBScreen *qptr); - ~QDirectFBScreenPrivate(); - - void setFlipFlags(const QStringList &args); - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; -public slots: -#ifdef QT_DIRECTFB_WM - void onWindowEvent(QWSWindow *window, QWSServer::WindowEvent event); -#endif -public: - IDirectFB *dfb; - DFBSurfaceFlipFlags flipFlags; - QDirectFBScreen::DirectFBFlags directFBFlags; - QImage::Format alphaPixmapFormat; - IDirectFBScreen *dfbScreen; -#ifdef QT_NO_DIRECTFB_WM - IDirectFBSurface *primarySurface; - QColor backgroundColor; -#endif -#ifndef QT_NO_DIRECTFB_LAYER - IDirectFBDisplayLayer *dfbLayer; -#endif - QSet<IDirectFBSurface*> allocatedSurfaces; - -#ifndef QT_NO_DIRECTFB_MOUSE - QDirectFBMouseHandler *mouse; -#endif -#ifndef QT_NO_DIRECTFB_KEYBOARD - QDirectFBKeyboardHandler *keyboard; -#endif -#if defined QT_DIRECTFB_IMAGEPROVIDER && defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE - IDirectFBImageProvider *imageProvider; -#endif - IDirectFBSurface *cursorSurface; - qint64 cursorImageKey; - - QDirectFBScreen *q; - static QDirectFBScreen *instance; -}; - -QDirectFBScreen *QDirectFBScreenPrivate::instance = 0; - -QDirectFBScreenPrivate::QDirectFBScreenPrivate(QDirectFBScreen *qptr) - : QWSGraphicsSystem(qptr), dfb(0), flipFlags(DSFLIP_NONE), - directFBFlags(QDirectFBScreen::NoFlags), alphaPixmapFormat(QImage::Format_Invalid), - dfbScreen(0) -#ifdef QT_NO_DIRECTFB_WM - , primarySurface(0) -#endif -#ifndef QT_NO_DIRECTFB_LAYER - , dfbLayer(0) -#endif -#ifndef QT_NO_DIRECTFB_MOUSE - , mouse(0) -#endif -#ifndef QT_NO_DIRECTFB_KEYBOARD - , keyboard(0) -#endif -#if defined QT_DIRECTFB_IMAGEPROVIDER && defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE - , imageProvider(0) -#endif - , cursorSurface(0) - , cursorImageKey(0) - , q(qptr) -{ -#ifndef QT_NO_QWS_SIGNALHANDLER - QWSSignalHandler::instance()->addObject(this); -#endif -#ifdef QT_DIRECTFB_WM - connect(QWSServer::instance(), SIGNAL(windowEvent(QWSWindow*,QWSServer::WindowEvent)), - this, SLOT(onWindowEvent(QWSWindow*,QWSServer::WindowEvent))); -#endif -} - -QDirectFBScreenPrivate::~QDirectFBScreenPrivate() -{ -#ifndef QT_NO_DIRECTFB_MOUSE - delete mouse; -#endif -#ifndef QT_NO_DIRECTFB_KEYBOARD - delete keyboard; -#endif -#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE - if (imageProvider) - imageProvider->Release(imageProvider); -#endif - - for (QSet<IDirectFBSurface*>::const_iterator it = allocatedSurfaces.begin(); it != allocatedSurfaces.end(); ++it) { - (*it)->Release(*it); - } - -#ifdef QT_NO_DIRECTFB_WM - if (primarySurface) - primarySurface->Release(primarySurface); -#endif - -#ifndef QT_NO_DIRECTFB_LAYER - if (dfbLayer) - dfbLayer->Release(dfbLayer); -#endif - - if (dfbScreen) - dfbScreen->Release(dfbScreen); - - if (dfb) - dfb->Release(dfb); -} - -IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QImage &image, QImage::Format format, SurfaceCreationOptions options, DFBResult *resultPtr) -{ - if (image.isNull()) // assert? - return 0; - - if (QDirectFBScreen::getSurfacePixelFormat(format) == DSPF_UNKNOWN) { - format = QDirectFBPixmapData::hasAlphaChannel(image) ? d_ptr->alphaPixmapFormat : pixelFormat(); - } - if (image.format() != format) { - return createDFBSurface(image.convertToFormat(format), format, options | NoPreallocated, resultPtr); - } - - DFBSurfaceDescription description; - memset(&description, 0, sizeof(DFBSurfaceDescription)); - description.width = image.width(); - description.height = image.height(); - description.flags = DSDESC_WIDTH|DSDESC_HEIGHT|DSDESC_PIXELFORMAT; - initSurfaceDescriptionPixelFormat(&description, format); - bool doMemCopy = true; -#ifdef QT_DIRECTFB_PREALLOCATED - if (!(options & NoPreallocated)) { - doMemCopy = false; - description.flags |= DSDESC_PREALLOCATED; - description.preallocated[0].data = const_cast<uchar*>(image.bits()); - description.preallocated[0].pitch = image.bytesPerLine(); - description.preallocated[1].data = 0; - description.preallocated[1].pitch = 0; - } -#endif - DFBResult result; - IDirectFBSurface *surface = createDFBSurface(description, options, &result); - if (resultPtr) - *resultPtr = result; - if (!surface) { - DirectFBError("Couldn't create surface createDFBSurface(QImage, QImage::Format, SurfaceCreationOptions)", result); - return 0; - } - if (doMemCopy) { - int bplDFB; - uchar *mem = QDirectFBScreen::lockSurface(surface, DSLF_WRITE, &bplDFB); - if (mem) { - const int height = image.height(); - const int bplQt = image.bytesPerLine(); - if (bplQt == bplDFB && bplQt == (image.width() * image.depth() / 8)) { - memcpy(mem, image.bits(), image.byteCount()); - } else { - for (int i=0; i<height; ++i) { - memcpy(mem, image.scanLine(i), bplQt); - mem += bplDFB; - } - } - surface->Unlock(surface); - } - } -#ifdef QT_DIRECTFB_PALETTE - if (image.colorCount() != 0 && surface) - QDirectFBScreen::setSurfaceColorTable(surface, image); -#endif - return surface; -} - -IDirectFBSurface *QDirectFBScreen::copyDFBSurface(IDirectFBSurface *src, - QImage::Format format, - SurfaceCreationOptions options, - DFBResult *result) -{ - Q_ASSERT(src); - QSize size; - src->GetSize(src, &size.rwidth(), &size.rheight()); - IDirectFBSurface *surface = createDFBSurface(size, format, options, result); - DFBSurfaceBlittingFlags flags = QDirectFBScreen::hasAlphaChannel(surface) - ? DSBLIT_BLEND_ALPHACHANNEL - : DSBLIT_NOFX; - if (flags & DSBLIT_BLEND_ALPHACHANNEL) - surface->Clear(surface, 0, 0, 0, 0); - - surface->SetBlittingFlags(surface, flags); - surface->Blit(surface, src, 0, 0, 0); -#if (Q_DIRECTFB_VERSION >= 0x010000) - surface->ReleaseSource(surface); -#endif - return surface; -} - -IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QSize &size, - QImage::Format format, - SurfaceCreationOptions options, - DFBResult *result) -{ - DFBSurfaceDescription desc; - memset(&desc, 0, sizeof(DFBSurfaceDescription)); - desc.flags |= DSDESC_WIDTH|DSDESC_HEIGHT; - if (!QDirectFBScreen::initSurfaceDescriptionPixelFormat(&desc, format)) - return 0; - desc.width = size.width(); - desc.height = size.height(); - return createDFBSurface(desc, options, result); -} - -IDirectFBSurface *QDirectFBScreen::createDFBSurface(DFBSurfaceDescription desc, SurfaceCreationOptions options, DFBResult *resultPtr) -{ - DFBResult tmp; - DFBResult &result = (resultPtr ? *resultPtr : tmp); - result = DFB_OK; - IDirectFBSurface *newSurface = 0; - - if (!d_ptr->dfb) { - qWarning("QDirectFBScreen::createDFBSurface() - not connected"); - return 0; - } - - if (d_ptr->directFBFlags & VideoOnly - && !(desc.flags & DSDESC_PREALLOCATED) - && (!(desc.flags & DSDESC_CAPS) || !(desc.caps & DSCAPS_SYSTEMONLY))) { - // Add the video only capability. This means the surface will be created in video ram - if (!(desc.flags & DSDESC_CAPS)) { - desc.caps = DSCAPS_VIDEOONLY; - desc.flags |= DSDESC_CAPS; - } else { - desc.caps |= DSCAPS_VIDEOONLY; - } - result = d_ptr->dfb->CreateSurface(d_ptr->dfb, &desc, &newSurface); - if (result != DFB_OK -#ifdef QT_NO_DEBUG - && (desc.flags & DSDESC_CAPS) && (desc.caps & DSCAPS_PRIMARY) -#endif - ) { - qWarning("QDirectFBScreen::createDFBSurface() Failed to create surface in video memory!\n" - " Flags %0x Caps %0x width %d height %d pixelformat %0x %d preallocated %p %d\n%s", - desc.flags, desc.caps, desc.width, desc.height, - desc.pixelformat, DFB_PIXELFORMAT_INDEX(desc.pixelformat), - desc.preallocated[0].data, desc.preallocated[0].pitch, - DirectFBErrorString(result)); - } - desc.caps &= ~DSCAPS_VIDEOONLY; - } - - if (d_ptr->directFBFlags & SystemOnly) - desc.caps |= DSCAPS_SYSTEMONLY; - - if (!newSurface) - result = d_ptr->dfb->CreateSurface(d_ptr->dfb, &desc, &newSurface); - - if (result != DFB_OK) { - qWarning("QDirectFBScreen::createDFBSurface() Failed!\n" - " Flags %0x Caps %0x width %d height %d pixelformat %0x %d preallocated %p %d\n%s", - desc.flags, desc.caps, desc.width, desc.height, - desc.pixelformat, DFB_PIXELFORMAT_INDEX(desc.pixelformat), - desc.preallocated[0].data, desc.preallocated[0].pitch, - DirectFBErrorString(result)); - return 0; - } - - Q_ASSERT(newSurface); - - if (options & TrackSurface) { - d_ptr->allocatedSurfaces.insert(newSurface); - } - - return newSurface; -} - -#ifdef QT_DIRECTFB_SUBSURFACE -IDirectFBSurface *QDirectFBScreen::getSubSurface(IDirectFBSurface *surface, - const QRect &rect, - SurfaceCreationOptions options, - DFBResult *resultPtr) -{ - Q_ASSERT(!(options & NoPreallocated)); - Q_ASSERT(surface); - DFBResult res; - DFBResult &result = (resultPtr ? *resultPtr : res); - IDirectFBSurface *subSurface = 0; - if (rect.isNull()) { - result = surface->GetSubSurface(surface, 0, &subSurface); - } else { - const DFBRectangle subRect = { rect.x(), rect.y(), rect.width(), rect.height() }; - result = surface->GetSubSurface(surface, &subRect, &subSurface); - } - if (result != DFB_OK) { - DirectFBError("Can't get sub surface", result); - } else if (options & TrackSurface) { - d_ptr->allocatedSurfaces.insert(subSurface); - } - return subSurface; -} -#endif - - -void QDirectFBScreen::releaseDFBSurface(IDirectFBSurface *surface) -{ - Q_ASSERT(QDirectFBScreen::instance()); - Q_ASSERT(surface); - surface->Release(surface); - if (!d_ptr->allocatedSurfaces.remove(surface)) - qWarning("QDirectFBScreen::releaseDFBSurface() - %p not in list", surface); - - //qDebug("Released surface at %p. New count = %d", surface, d_ptr->allocatedSurfaces.count()); -} - -QDirectFBScreen::DirectFBFlags QDirectFBScreen::directFBFlags() const -{ - return d_ptr->directFBFlags; -} - -IDirectFB *QDirectFBScreen::dfb() -{ - return d_ptr->dfb; -} - -#ifdef QT_NO_DIRECTFB_WM -IDirectFBSurface *QDirectFBScreen::primarySurface() -{ - return d_ptr->primarySurface; -} -#endif - -#ifndef QT_NO_DIRECTFB_LAYER -IDirectFBDisplayLayer *QDirectFBScreen::dfbDisplayLayer() -{ - return d_ptr->dfbLayer; -} -#endif - -DFBSurfacePixelFormat QDirectFBScreen::getSurfacePixelFormat(QImage::Format format) -{ - switch (format) { -#ifndef QT_NO_DIRECTFB_PALETTE - case QImage::Format_Indexed8: - return DSPF_LUT8; -#endif - case QImage::Format_RGB888: - return DSPF_RGB24; - case QImage::Format_ARGB4444_Premultiplied: - return DSPF_ARGB4444; -#if (Q_DIRECTFB_VERSION >= 0x010100) - case QImage::Format_RGB444: - return DSPF_RGB444; - case QImage::Format_RGB555: - return DSPF_RGB555; -#endif - case QImage::Format_RGB16: - return DSPF_RGB16; -#if (Q_DIRECTFB_VERSION >= 0x010000) - case QImage::Format_ARGB6666_Premultiplied: - return DSPF_ARGB6666; - case QImage::Format_RGB666: - return DSPF_RGB18; -#endif - case QImage::Format_RGB32: - return DSPF_RGB32; - case QImage::Format_ARGB32_Premultiplied: - case QImage::Format_ARGB32: - return DSPF_ARGB; - default: - return DSPF_UNKNOWN; - }; -} - -QImage::Format QDirectFBScreen::getImageFormat(IDirectFBSurface *surface) -{ - DFBSurfacePixelFormat format; - surface->GetPixelFormat(surface, &format); - - switch (format) { - case DSPF_LUT8: - return QImage::Format_Indexed8; - case DSPF_RGB24: - return QImage::Format_RGB888; - case DSPF_ARGB4444: - return QImage::Format_ARGB4444_Premultiplied; -#if (Q_DIRECTFB_VERSION >= 0x010100) - case DSPF_RGB444: - return QImage::Format_RGB444; - case DSPF_RGB555: -#endif - case DSPF_ARGB1555: - return QImage::Format_RGB555; - case DSPF_RGB16: - return QImage::Format_RGB16; -#if (Q_DIRECTFB_VERSION >= 0x010000) - case DSPF_ARGB6666: - return QImage::Format_ARGB6666_Premultiplied; - case DSPF_RGB18: - return QImage::Format_RGB666; -#endif - case DSPF_RGB32: - return QImage::Format_RGB32; - case DSPF_ARGB: { - DFBSurfaceCapabilities caps; - const DFBResult result = surface->GetCapabilities(surface, &caps); - Q_ASSERT(result == DFB_OK); - Q_UNUSED(result); - return (caps & DSCAPS_PREMULTIPLIED - ? QImage::Format_ARGB32_Premultiplied - : QImage::Format_ARGB32); } - default: - break; - } - return QImage::Format_Invalid; -} - -DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const uint *buffer, - int length) -{ - DFBSurfaceDescription description; - memset(&description, 0, sizeof(DFBSurfaceDescription)); - - description.flags = DSDESC_CAPS|DSDESC_WIDTH|DSDESC_HEIGHT|DSDESC_PIXELFORMAT|DSDESC_PREALLOCATED; - description.caps = DSCAPS_PREMULTIPLIED; - description.width = length; - description.height = 1; - description.pixelformat = DSPF_ARGB; - description.preallocated[0].data = (void*)buffer; - description.preallocated[0].pitch = length * sizeof(uint); - description.preallocated[1].data = 0; - description.preallocated[1].pitch = 0; - return description; -} - -#ifndef QT_NO_DIRECTFB_PALETTE -void QDirectFBScreen::setSurfaceColorTable(IDirectFBSurface *surface, - const QImage &image) -{ - if (!surface) - return; - - const int numColors = image.colorCount(); - if (numColors == 0) - return; - - QVarLengthArray<DFBColor, 256> colors(numColors); - for (int i = 0; i < numColors; ++i) { - QRgb c = image.color(i); - colors[i].a = qAlpha(c); - colors[i].r = qRed(c); - colors[i].g = qGreen(c); - colors[i].b = qBlue(c); - } - - IDirectFBPalette *palette; - DFBResult result; - result = surface->GetPalette(surface, &palette); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::setSurfaceColorTable GetPalette", - result); - return; - } - result = palette->SetEntries(palette, colors.data(), numColors, 0); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::setSurfaceColorTable SetEntries", - result); - } - palette->Release(palette); -} - -#endif // QT_NO_DIRECTFB_PALETTE - -#if defined QT_DIRECTFB_CURSOR -class Q_GUI_EXPORT QDirectFBScreenCursor : public QScreenCursor -{ -public: - QDirectFBScreenCursor(); - virtual void set(const QImage &image, int hotx, int hoty); - virtual void move(int x, int y); - virtual void show(); - virtual void hide(); -private: -#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR - ~QDirectFBScreenCursor(); - bool createWindow(); - IDirectFBWindow *window; -#endif - IDirectFBDisplayLayer *layer; -}; - -QDirectFBScreenCursor::QDirectFBScreenCursor() -{ - IDirectFB *fb = QDirectFBScreen::instance()->dfb(); - if (!fb) - qFatal("QDirectFBScreenCursor: DirectFB not initialized"); - - layer = QDirectFBScreen::instance()->dfbDisplayLayer(); - Q_ASSERT(layer); - - enable = false; - hwaccel = true; - supportsAlpha = true; -#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR - window = 0; - DFBResult result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::hide: " - "Unable to set cooperative level", result); - } - result = layer->SetCursorOpacity(layer, 0); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::hide: " - "Unable to set cursor opacity", result); - } - - result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::hide: " - "Unable to set cooperative level", result); - } -#endif -} - -#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR -QDirectFBScreenCursor::~QDirectFBScreenCursor() -{ - if (window) { - window->Release(window); - window = 0; - } -} - -bool QDirectFBScreenCursor::createWindow() -{ - Q_ASSERT(!window); - Q_ASSERT(!cursor.isNull()); - DFBWindowDescription description; - memset(&description, 0, sizeof(DFBWindowDescription)); - description.flags = DWDESC_POSX|DWDESC_POSY|DWDESC_WIDTH|DWDESC_HEIGHT|DWDESC_CAPS|DWDESC_PIXELFORMAT|DWDESC_SURFACE_CAPS; - description.width = cursor.width(); - description.height = cursor.height(); - description.posx = pos.x() - hotspot.x(); - description.posy = pos.y() - hotspot.y(); -#if (Q_DIRECTFB_VERSION >= 0x010100) - description.flags |= DWDESC_OPTIONS; - description.options = DWOP_GHOST|DWOP_ALPHACHANNEL; -#endif - description.caps = DWCAPS_NODECORATION|DWCAPS_DOUBLEBUFFER; - const QImage::Format format = QDirectFBScreen::instance()->alphaPixmapFormat(); - description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(format); - if (QDirectFBScreen::isPremultiplied(format)) - description.surface_caps = DSCAPS_PREMULTIPLIED; - - DFBResult result = layer->CreateWindow(layer, &description, &window); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::createWindow: Unable to create window", result); - return false; - } - result = window->SetOpacity(window, 255); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::createWindow: Unable to set opacity ", result); - return false; - } - - result = window->SetStackingClass(window, DWSC_UPPER); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::createWindow: Unable to set stacking class ", result); - return false; - } - - result = window->RaiseToTop(window); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::createWindow: Unable to raise window ", result); - return false; - } - - return true; -} -#endif - -void QDirectFBScreenCursor::move(int x, int y) -{ - pos = QPoint(x, y); -#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR - if (window) { - const QPoint p = pos - hotspot; - DFBResult result = window->MoveTo(window, p.x(), p.y()); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::move: Unable to move window", result); - } - } -#else - layer->WarpCursor(layer, x, y); -#endif -} - -void QDirectFBScreenCursor::hide() -{ - if (enable) { - enable = false; - DFBResult result; -#ifndef QT_DIRECTFB_WINDOW_AS_CURSOR - result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::hide: " - "Unable to set cooperative level", result); - } - result = layer->SetCursorOpacity(layer, 0); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::hide: " - "Unable to set cursor opacity", result); - } - result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::hide: " - "Unable to set cooperative level", result); - } -#else - if (window) { - result = window->SetOpacity(window, 0); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::hide: " - "Unable to set window opacity", result); - } - } -#endif - } -} - -void QDirectFBScreenCursor::show() -{ - if (!enable) { - enable = true; - DFBResult result; - result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::show: " - "Unable to set cooperative level", result); - } - result = layer->SetCursorOpacity(layer, -#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR - 0 -#else - 255 -#endif - ); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::show: " - "Unable to set cursor shape", result); - } - result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::show: " - "Unable to set cooperative level", result); - } -#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR - if (window) { - DFBResult result = window->SetOpacity(window, 255); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::show: " - "Unable to set window opacity", result); - } - } -#endif - } -} - -void QDirectFBScreenCursor::set(const QImage &image, int hotx, int hoty) -{ - QDirectFBScreen *screen = QDirectFBScreen::instance(); - if (!screen) - return; - - if (image.isNull()) { - cursor = QImage(); - hide(); - } else { - cursor = image.convertToFormat(screen->alphaPixmapFormat()); - size = cursor.size(); - hotspot = QPoint(hotx, hoty); - DFBResult result = DFB_OK; - IDirectFBSurface *surface = screen->createDFBSurface(cursor, screen->alphaPixmapFormat(), - QDirectFBScreen::DontTrackSurface, &result); - if (!surface) { - DirectFBError("QDirectFBScreenCursor::set: Unable to create surface", result); - return; - } -#ifndef QT_DIRECTFB_WINDOW_AS_CURSOR - result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::show: " - "Unable to set cooperative level", result); - } - result = layer->SetCursorShape(layer, surface, hotx, hoty); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::show: " - "Unable to set cursor shape", result); - } - result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::show: " - "Unable to set cooperative level", result); - } -#else - if (window || createWindow()) { - QSize windowSize; - result = window->GetSize(window, &windowSize.rwidth(), &windowSize.rheight()); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::set: " - "Unable to get window size", result); - } - result = window->Resize(window, size.width(), size.height()); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::set: Unable to resize window", result); - } - - IDirectFBSurface *windowSurface; - result = window->GetSurface(window, &windowSurface); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::set: Unable to get window surface", result); - } else { - result = windowSurface->Clear(windowSurface, 0, 0, 0, 0); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::set: Unable to clear surface", result); - } - - result = windowSurface->Blit(windowSurface, surface, 0, 0, 0); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::set: Unable to blit to surface", result); - } - } - result = windowSurface->Flip(windowSurface, 0, DSFLIP_NONE); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::set: Unable to flip window", result); - } - - windowSurface->Release(windowSurface); - } -#endif - surface->Release(surface); - show(); - } - -} -#endif // QT_DIRECTFB_CURSOR - -QDirectFBScreen::QDirectFBScreen(int display_id) - : QScreen(display_id, DirectFBClass), d_ptr(new QDirectFBScreenPrivate(this)) -{ - QDirectFBScreenPrivate::instance = this; -} - -QDirectFBScreen::~QDirectFBScreen() -{ - if (QDirectFBScreenPrivate::instance == this) - QDirectFBScreenPrivate::instance = 0; - delete d_ptr; -} - -QDirectFBScreen *QDirectFBScreen::instance() -{ - return QDirectFBScreenPrivate::instance; -} - -int QDirectFBScreen::depth(DFBSurfacePixelFormat format) -{ - switch (format) { - case DSPF_A1: - return 1; - case DSPF_A8: - case DSPF_RGB332: - case DSPF_LUT8: - case DSPF_ALUT44: - return 8; - case DSPF_I420: - case DSPF_YV12: - case DSPF_NV12: - case DSPF_NV21: -#if (Q_DIRECTFB_VERSION >= 0x010100) - case DSPF_RGB444: -#endif - return 12; -#if (Q_DIRECTFB_VERSION >= 0x010100) - case DSPF_RGB555: - return 15; -#endif - case DSPF_ARGB1555: - case DSPF_RGB16: - case DSPF_YUY2: - case DSPF_UYVY: - case DSPF_NV16: - case DSPF_ARGB2554: - case DSPF_ARGB4444: - return 16; - case DSPF_RGB24: - return 24; - case DSPF_RGB32: - case DSPF_ARGB: - case DSPF_AiRGB: - return 32; - case DSPF_UNKNOWN: - default: - return 0; - }; - return 0; -} - -int QDirectFBScreen::depth(QImage::Format format) -{ - int depth = 0; - switch(format) { - case QImage::Format_Invalid: - case QImage::NImageFormats: - Q_ASSERT(false); - case QImage::Format_Mono: - case QImage::Format_MonoLSB: - depth = 1; - break; - case QImage::Format_Indexed8: - depth = 8; - break; - case QImage::Format_RGB32: - case QImage::Format_ARGB32: - case QImage::Format_ARGB32_Premultiplied: - depth = 32; - break; - case QImage::Format_RGB555: - case QImage::Format_RGB16: - case QImage::Format_RGB444: - case QImage::Format_ARGB4444_Premultiplied: - depth = 16; - break; - case QImage::Format_RGB666: - case QImage::Format_ARGB6666_Premultiplied: - case QImage::Format_ARGB8565_Premultiplied: - case QImage::Format_ARGB8555_Premultiplied: - case QImage::Format_RGB888: - depth = 24; - break; - } - return depth; -} - -void QDirectFBScreenPrivate::setFlipFlags(const QStringList &args) -{ - QRegExp flipRegexp(QLatin1String("^flip=([\\w,]*)$")); - int index = args.indexOf(flipRegexp); - if (index >= 0) { - const QStringList flips = flipRegexp.cap(1).split(QLatin1Char(','), - QString::SkipEmptyParts); - flipFlags = DSFLIP_NONE; - foreach(const QString &flip, flips) { - if (flip == QLatin1String("wait")) - flipFlags |= DSFLIP_WAIT; - else if (flip == QLatin1String("blit")) - flipFlags |= DSFLIP_BLIT; - else if (flip == QLatin1String("onsync")) - flipFlags |= DSFLIP_ONSYNC; - else if (flip == QLatin1String("pipeline")) - flipFlags |= DSFLIP_PIPELINE; - else - qWarning("QDirectFBScreen: Unknown flip argument: %s", - qPrintable(flip)); - } - } else { - flipFlags = DSFLIP_BLIT|DSFLIP_ONSYNC; - } -} - -#ifdef QT_DIRECTFB_WM -void QDirectFBScreenPrivate::onWindowEvent(QWSWindow *window, QWSServer::WindowEvent event) -{ - if (event == QWSServer::Raise) { - QWSWindowSurface *windowSurface = window->windowSurface(); - if (windowSurface && windowSurface->key() == QLatin1String("directfb")) { - static_cast<QDirectFBWindowSurface*>(windowSurface)->raise(); - } - } -} -#endif - -QPixmapData *QDirectFBScreenPrivate::createPixmapData(QPixmapData::PixelType type) const -{ - if (type == QPixmapData::BitmapType) - return QWSGraphicsSystem::createPixmapData(type); - - return new QDirectFBPixmapData(q, type); -} - -#if (Q_DIRECTFB_VERSION >= 0x000923) -#ifdef QT_NO_DEBUG -struct FlagDescription; -static const FlagDescription *accelerationDescriptions = 0; -static const FlagDescription *blitDescriptions = 0; -static const FlagDescription *drawDescriptions = 0; -#else -struct FlagDescription { - const char *name; - uint flag; -}; - -static const FlagDescription accelerationDescriptions[] = { - { "DFXL_NONE", DFXL_NONE }, - { "DFXL_FILLRECTANGLE", DFXL_FILLRECTANGLE }, - { "DFXL_DRAWRECTANGLE", DFXL_DRAWRECTANGLE }, - { "DFXL_DRAWLINE", DFXL_DRAWLINE }, - { "DFXL_FILLTRIANGLE", DFXL_FILLTRIANGLE }, - { "DFXL_BLIT", DFXL_BLIT }, - { "DFXL_STRETCHBLIT", DFXL_STRETCHBLIT }, - { "DFXL_TEXTRIANGLES", DFXL_TEXTRIANGLES }, - { "DFXL_DRAWSTRING", DFXL_DRAWSTRING }, - { 0, 0 } -}; - -static const FlagDescription blitDescriptions[] = { - { "DSBLIT_NOFX", DSBLIT_NOFX }, - { "DSBLIT_BLEND_ALPHACHANNEL", DSBLIT_BLEND_ALPHACHANNEL }, - { "DSBLIT_BLEND_COLORALPHA", DSBLIT_BLEND_COLORALPHA }, - { "DSBLIT_COLORIZE", DSBLIT_COLORIZE }, - { "DSBLIT_SRC_COLORKEY", DSBLIT_SRC_COLORKEY }, - { "DSBLIT_DST_COLORKEY", DSBLIT_DST_COLORKEY }, - { "DSBLIT_SRC_PREMULTIPLY", DSBLIT_SRC_PREMULTIPLY }, - { "DSBLIT_DST_PREMULTIPLY", DSBLIT_DST_PREMULTIPLY }, - { "DSBLIT_DEMULTIPLY", DSBLIT_DEMULTIPLY }, - { "DSBLIT_DEINTERLACE", DSBLIT_DEINTERLACE }, -#if (Q_DIRECTFB_VERSION >= 0x000923) - { "DSBLIT_SRC_PREMULTCOLOR", DSBLIT_SRC_PREMULTCOLOR }, - { "DSBLIT_XOR", DSBLIT_XOR }, -#endif -#if (Q_DIRECTFB_VERSION >= 0x010000) - { "DSBLIT_INDEX_TRANSLATION", DSBLIT_INDEX_TRANSLATION }, -#endif - { 0, 0 } -}; - -static const FlagDescription drawDescriptions[] = { - { "DSDRAW_NOFX", DSDRAW_NOFX }, - { "DSDRAW_BLEND", DSDRAW_BLEND }, - { "DSDRAW_DST_COLORKEY", DSDRAW_DST_COLORKEY }, - { "DSDRAW_SRC_PREMULTIPLY", DSDRAW_SRC_PREMULTIPLY }, - { "DSDRAW_DST_PREMULTIPLY", DSDRAW_DST_PREMULTIPLY }, - { "DSDRAW_DEMULTIPLY", DSDRAW_DEMULTIPLY }, - { "DSDRAW_XOR", DSDRAW_XOR }, - { 0, 0 } -}; -#endif - -static const QByteArray flagDescriptions(uint mask, const FlagDescription *flags) -{ -#ifdef QT_NO_DEBUG - Q_UNUSED(mask); - Q_UNUSED(flags); - return QByteArray(""); -#else - if (!mask) - return flags[0].name; - - QStringList list; - for (int i=1; flags[i].name; ++i) { - if (mask & flags[i].flag) { - list.append(QString::fromLatin1(flags[i].name)); - } - } - Q_ASSERT(!list.isEmpty()); - return (QLatin1Char(' ') + list.join(QLatin1String("|"))).toLatin1(); -#endif -} -static void printDirectFBInfo(IDirectFB *fb, IDirectFBSurface *primarySurface) -{ - DFBResult result; - DFBGraphicsDeviceDescription dev; - - result = fb->GetDeviceDescription(fb, &dev); - if (result != DFB_OK) { - DirectFBError("Error reading graphics device description", result); - return; - } - - DFBSurfacePixelFormat pixelFormat; - primarySurface->GetPixelFormat(primarySurface, &pixelFormat); - - qDebug("Device: %s (%s), Driver: %s v%i.%i (%s) Pixelformat: %d (%d)\n" - "acceleration: 0x%x%s\nblit: 0x%x%s\ndraw: 0x%0x%s\nvideo: %iKB\n", - dev.name, dev.vendor, dev.driver.name, dev.driver.major, - dev.driver.minor, dev.driver.vendor, DFB_PIXELFORMAT_INDEX(pixelFormat), - QDirectFBScreen::getImageFormat(primarySurface), dev.acceleration_mask, - flagDescriptions(dev.acceleration_mask, accelerationDescriptions).constData(), - dev.blitting_flags, flagDescriptions(dev.blitting_flags, blitDescriptions).constData(), - dev.drawing_flags, flagDescriptions(dev.drawing_flags, drawDescriptions).constData(), - (dev.video_memory >> 10)); -} -#endif - -static inline bool setIntOption(const QStringList &arguments, const QString &variable, int *value) -{ - Q_ASSERT(value); - QRegExp rx(QString::fromLatin1("%1=?(\\d+)").arg(variable)); - rx.setCaseSensitivity(Qt::CaseInsensitive); - if (arguments.indexOf(rx) != -1) { - *value = rx.cap(1).toInt(); - return true; - } - return false; -} - -static inline QColor colorFromName(const QString &name) -{ - QRegExp rx(QLatin1String("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])")); - rx.setCaseSensitivity(Qt::CaseInsensitive); - if (rx.exactMatch(name)) { - Q_ASSERT(rx.captureCount() == 4); - int ints[4]; - int i; - for (i=0; i<4; ++i) { - bool ok; - ints[i] = rx.cap(i + 1).toUInt(&ok, 16); - if (!ok || ints[i] > 255) - break; - } - if (i == 4) - return QColor(ints[0], ints[1], ints[2], ints[3]); - } - return QColor(name); -} - -bool QDirectFBScreen::connect(const QString &displaySpec) -{ - DFBResult result = DFB_OK; - - { // pass command line arguments to DirectFB - const QStringList args = QCoreApplication::arguments(); - int argc = args.size(); - char **argv = new char*[argc]; - - for (int i = 0; i < argc; ++i) - argv[i] = qstrdup(args.at(i).toLocal8Bit().constData()); - - result = DirectFBInit(&argc, &argv); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen: error initializing DirectFB", - result); - } - delete[] argv; - } - - const QStringList displayArgs = displaySpec.split(QLatin1Char(':'), - QString::SkipEmptyParts); - - d_ptr->setFlipFlags(displayArgs); - - result = DirectFBCreate(&d_ptr->dfb); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen: error creating DirectFB interface", - result); - return false; - } - - if (displayArgs.contains(QLatin1String("videoonly"), Qt::CaseInsensitive)) - d_ptr->directFBFlags |= VideoOnly; - - if (displayArgs.contains(QLatin1String("systemonly"), Qt::CaseInsensitive)) { - if (d_ptr->directFBFlags & VideoOnly) { - qWarning("QDirectFBScreen: error. videoonly and systemonly are mutually exclusive"); - } else { - d_ptr->directFBFlags |= SystemOnly; - } - } - - if (displayArgs.contains(QLatin1String("boundingrectflip"), Qt::CaseInsensitive)) { - d_ptr->directFBFlags |= BoundingRectFlip; - } else if (displayArgs.contains(QLatin1String("nopartialflip"), Qt::CaseInsensitive)) { - d_ptr->directFBFlags |= NoPartialFlip; - } - -#ifdef QT_DIRECTFB_IMAGECACHE - int imageCacheSize = 4 * 1024 * 1024; // 4 MB - setIntOption(displayArgs, QLatin1String("imagecachesize"), &imageCacheSize); - QDirectFBPaintEngine::initImageCache(imageCacheSize); -#endif - -#ifndef QT_NO_DIRECTFB_WM - if (displayArgs.contains(QLatin1String("fullscreen"))) -#endif - d_ptr->dfb->SetCooperativeLevel(d_ptr->dfb, DFSCL_FULLSCREEN); - - const bool forcePremultiplied = displayArgs.contains(QLatin1String("forcepremultiplied"), Qt::CaseInsensitive); - - DFBSurfaceDescription description; - memset(&description, 0, sizeof(DFBSurfaceDescription)); - IDirectFBSurface *surface; - -#ifdef QT_NO_DIRECTFB_WM - description.flags = DSDESC_CAPS; - if (::setIntOption(displayArgs, QLatin1String("width"), &description.width)) - description.flags |= DSDESC_WIDTH; - if (::setIntOption(displayArgs, QLatin1String("height"), &description.height)) - description.flags |= DSDESC_HEIGHT; - - description.caps = DSCAPS_PRIMARY|DSCAPS_DOUBLE; - struct { - const char *name; - const DFBSurfaceCapabilities cap; - } const capabilities[] = { - { "static_alloc", DSCAPS_STATIC_ALLOC }, - { "triplebuffer", DSCAPS_TRIPLE }, - { "interlaced", DSCAPS_INTERLACED }, - { "separated", DSCAPS_SEPARATED }, -// { "depthbuffer", DSCAPS_DEPTH }, // only makes sense with TextureTriangles which are not supported - { 0, DSCAPS_NONE } - }; - for (int i=0; capabilities[i].name; ++i) { - if (displayArgs.contains(QString::fromLatin1(capabilities[i].name), Qt::CaseInsensitive)) - description.caps |= capabilities[i].cap; - } - - if (forcePremultiplied) { - description.caps |= DSCAPS_PREMULTIPLIED; - } - - // We don't track the primary surface as it's released in disconnect - d_ptr->primarySurface = createDFBSurface(description, DontTrackSurface, &result); - if (!d_ptr->primarySurface) { - DirectFBError("QDirectFBScreen: error creating primary surface", - result); - return false; - } - - surface = d_ptr->primarySurface; -#else - description.flags = DSDESC_WIDTH|DSDESC_HEIGHT; - description.width = description.height = 1; - surface = createDFBSurface(description, DontTrackSurface, &result); - if (!surface) { - DirectFBError("QDirectFBScreen: error creating surface", result); - return false; - } -#endif - // Work out what format we're going to use for surfaces with an alpha channel - QImage::Format pixelFormat = QDirectFBScreen::getImageFormat(surface); - d_ptr->alphaPixmapFormat = pixelFormat; - - switch (pixelFormat) { - case QImage::Format_RGB666: - d_ptr->alphaPixmapFormat = QImage::Format_ARGB6666_Premultiplied; - break; - case QImage::Format_RGB444: - d_ptr->alphaPixmapFormat = QImage::Format_ARGB4444_Premultiplied; - break; - case QImage::Format_RGB32: - pixelFormat = d_ptr->alphaPixmapFormat = QImage::Format_ARGB32_Premultiplied; - // ### Format_RGB32 doesn't work so well with Qt. Force ARGB32 for windows/pixmaps - break; - case QImage::Format_Indexed8: - qWarning("QDirectFBScreen::connect(). Qt/DirectFB does not work with the LUT8 pixelformat."); - return false; - case QImage::NImageFormats: - case QImage::Format_Invalid: - case QImage::Format_Mono: - case QImage::Format_MonoLSB: - case QImage::Format_RGB888: - case QImage::Format_RGB16: - case QImage::Format_RGB555: - d_ptr->alphaPixmapFormat = QImage::Format_ARGB32_Premultiplied; - break; - case QImage::Format_ARGB32: - if (forcePremultiplied) - d_ptr->alphaPixmapFormat = pixelFormat = QImage::Format_ARGB32_Premultiplied; - case QImage::Format_ARGB32_Premultiplied: - case QImage::Format_ARGB4444_Premultiplied: - case QImage::Format_ARGB8555_Premultiplied: - case QImage::Format_ARGB8565_Premultiplied: - case QImage::Format_ARGB6666_Premultiplied: - // works already - break; - } - setPixelFormat(pixelFormat); - QScreen::d = QDirectFBScreen::depth(pixelFormat); - data = 0; - lstep = 0; - size = 0; - - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::connect: " - "Unable to get screen!", result); - return false; - } - const QString qws_size = QString::fromLatin1(qgetenv("QWS_SIZE")); - if (!qws_size.isEmpty()) { - QRegExp rx(QLatin1String("(\\d+)x(\\d+)")); - if (!rx.exactMatch(qws_size)) { - qWarning("QDirectFBScreen::connect: Can't parse QWS_SIZE=\"%s\"", qPrintable(qws_size)); - } else { - int *ints[2] = { &w, &h }; - for (int i=0; i<2; ++i) { - *ints[i] = rx.cap(i + 1).toInt(); - if (*ints[i] <= 0) { - qWarning("QDirectFBScreen::connect: %s is not a positive integer", - qPrintable(rx.cap(i + 1))); - w = h = 0; - break; - } - } - } - } - - setIntOption(displayArgs, QLatin1String("width"), &w); - setIntOption(displayArgs, QLatin1String("height"), &h); - -#ifndef QT_NO_DIRECTFB_LAYER - int layerId = DLID_PRIMARY; - setIntOption(displayArgs, QLatin1String("layerid"), &layerId); - - result = d_ptr->dfb->GetDisplayLayer(d_ptr->dfb, static_cast<DFBDisplayLayerID>(layerId), - &d_ptr->dfbLayer); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::connect: " - "Unable to get display layer!", result); - return false; - } - result = d_ptr->dfbLayer->GetScreen(d_ptr->dfbLayer, &d_ptr->dfbScreen); -#else - result = d_ptr->dfb->GetScreen(d_ptr->dfb, 0, &d_ptr->dfbScreen); -#endif - - if (w <= 0 || h <= 0) { -#ifdef QT_NO_DIRECTFB_WM - result = d_ptr->primarySurface->GetSize(d_ptr->primarySurface, &w, &h); -#elif (Q_DIRECTFB_VERSION >= 0x010000) - IDirectFBSurface *layerSurface; - if (d_ptr->dfbLayer->GetSurface(d_ptr->dfbLayer, &layerSurface) == DFB_OK) { - result = layerSurface->GetSize(layerSurface, &w, &h); - layerSurface->Release(layerSurface); - } - if (w <= 0 || h <= 0) { - result = d_ptr->dfbScreen->GetSize(d_ptr->dfbScreen, &w, &h); - } -#else - qWarning("QDirectFBScreen::connect: DirectFB versions prior to 1.0 do not offer a way\n" - "query the size of the primary surface in windowed mode. You have to specify\n" - "the size of the display using QWS_SIZE=[0-9]x[0-9] or\n" - "QWS_DISPLAY=directfb:width=[0-9]:height=[0-9]"); - return false; -#endif - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::connect: " - "Unable to get screen size!", result); - return false; - } - } - - - dw = w; - dh = h; - - Q_ASSERT(dw != 0 && dh != 0); - - physWidth = physHeight = -1; - setIntOption(displayArgs, QLatin1String("mmWidth"), &physWidth); - setIntOption(displayArgs, QLatin1String("mmHeight"), &physHeight); - const int dpi = 72; - if (physWidth < 0) - physWidth = qRound(dw * 25.4 / dpi); - if (physHeight < 0) - physHeight = qRound(dh * 25.4 / dpi); - - setGraphicsSystem(d_ptr); - -#if (Q_DIRECTFB_VERSION >= 0x000923) - if (displayArgs.contains(QLatin1String("debug"), Qt::CaseInsensitive)) - printDirectFBInfo(d_ptr->dfb, surface); -#endif -#ifdef QT_DIRECTFB_WM - surface->Release(surface); - QColor backgroundColor; -#else - QColor &backgroundColor = d_ptr->backgroundColor; -#endif - - QRegExp backgroundColorRegExp(QLatin1String("bgcolor=(.+)")); - backgroundColorRegExp.setCaseSensitivity(Qt::CaseInsensitive); - if (displayArgs.indexOf(backgroundColorRegExp) != -1) { - backgroundColor = colorFromName(backgroundColorRegExp.cap(1)); - } -#ifdef QT_NO_DIRECTFB_WM - if (!backgroundColor.isValid()) - backgroundColor = Qt::green; - d_ptr->primarySurface->Clear(d_ptr->primarySurface, backgroundColor.red(), - backgroundColor.green(), backgroundColor.blue(), - backgroundColor.alpha()); - d_ptr->primarySurface->Flip(d_ptr->primarySurface, 0, d_ptr->flipFlags); -#else - if (backgroundColor.isValid()) { - DFBResult result = d_ptr->dfbLayer->SetCooperativeLevel(d_ptr->dfbLayer, DLSCL_ADMINISTRATIVE); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::connect " - "Unable to set cooperative level", result); - } - result = d_ptr->dfbLayer->SetBackgroundColor(d_ptr->dfbLayer, backgroundColor.red(), backgroundColor.green(), - backgroundColor.blue(), backgroundColor.alpha()); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::connect: " - "Unable to set background color", result); - } - - result = d_ptr->dfbLayer->SetBackgroundMode(d_ptr->dfbLayer, DLBM_COLOR); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreenCursor::connect: " - "Unable to set background mode", result); - } - - result = d_ptr->dfbLayer->SetCooperativeLevel(d_ptr->dfbLayer, DLSCL_SHARED); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::connect " - "Unable to set cooperative level", result); - } - - } -#endif - - return true; -} - -void QDirectFBScreen::disconnect() -{ -#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE - if (d_ptr->imageProvider) - d_ptr->imageProvider->Release(d_ptr->imageProvider); -#endif -#ifdef QT_NO_DIRECTFB_WM - d_ptr->primarySurface->Release(d_ptr->primarySurface); - d_ptr->primarySurface = 0; -#endif - - foreach (IDirectFBSurface *surf, d_ptr->allocatedSurfaces) - surf->Release(surf); - d_ptr->allocatedSurfaces.clear(); - -#ifndef QT_NO_DIRECTFB_LAYER - d_ptr->dfbLayer->Release(d_ptr->dfbLayer); - d_ptr->dfbLayer = 0; -#endif - - d_ptr->dfbScreen->Release(d_ptr->dfbScreen); - d_ptr->dfbScreen = 0; - - d_ptr->dfb->Release(d_ptr->dfb); - d_ptr->dfb = 0; -} - -bool QDirectFBScreen::initDevice() -{ -#ifndef QT_NO_DIRECTFB_MOUSE - if (qgetenv("QWS_MOUSE_PROTO").isEmpty()) { - QWSServer::instance()->setDefaultMouse("None"); - d_ptr->mouse = new QDirectFBMouseHandler; - } -#endif -#ifndef QT_NO_DIRECTFB_KEYBOARD - if (qgetenv("QWS_KEYBOARD").isEmpty()) { - QWSServer::instance()->setDefaultKeyboard("None"); - d_ptr->keyboard = new QDirectFBKeyboardHandler(QString()); - } -#endif - -#ifdef QT_DIRECTFB_CURSOR - qt_screencursor = new QDirectFBScreenCursor; -#elif !defined QT_NO_QWS_CURSOR - QScreenCursor::initSoftwareCursor(); -#endif - return true; -} - -void QDirectFBScreen::shutdownDevice() -{ -#ifndef QT_NO_DIRECTFB_MOUSE - delete d_ptr->mouse; - d_ptr->mouse = 0; -#endif -#ifndef QT_NO_DIRECTFB_KEYBOARD - delete d_ptr->keyboard; - d_ptr->keyboard = 0; -#endif - -#ifndef QT_NO_QWS_CURSOR - delete qt_screencursor; - qt_screencursor = 0; -#endif -} - -void QDirectFBScreen::setMode(int width, int height, int depth) -{ - d_ptr->dfb->SetVideoMode(d_ptr->dfb, width, height, depth); -} - -void QDirectFBScreen::blank(bool on) -{ - d_ptr->dfbScreen->SetPowerMode(d_ptr->dfbScreen, - (on ? DSPM_ON : DSPM_SUSPEND)); -} - -QWSWindowSurface *QDirectFBScreen::createSurface(QWidget *widget) const -{ -#ifdef QT_NO_DIRECTFB_WM - if (QApplication::type() == QApplication::GuiServer) { - return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this), widget); - } else { - return QScreen::createSurface(widget); - } -#else - return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this), widget); -#endif -} - -QWSWindowSurface *QDirectFBScreen::createSurface(const QString &key) const -{ - if (key == QLatin1String("directfb")) { - return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this)); - } - return QScreen::createSurface(key); -} - -#if defined QT_NO_DIRECTFB_WM -struct PaintCommand { - PaintCommand() : dfbSurface(0), windowOpacity(255), blittingFlags(DSBLIT_NOFX) {} - IDirectFBSurface *dfbSurface; - QImage image; - QPoint windowPosition; - QRegion source; - quint8 windowOpacity; - DFBSurfaceBlittingFlags blittingFlags; -}; - -static inline void initParameters(DFBRectangle &source, const QRect &sourceGlobal, const QPoint &pos) -{ - source.x = sourceGlobal.x() - pos.x(); - source.y = sourceGlobal.y() - pos.y(); - source.w = sourceGlobal.width(); - source.h = sourceGlobal.height(); -} -#endif - -void QDirectFBScreen::exposeRegion(QRegion r, int) -{ - Q_UNUSED(r); -#if defined QT_NO_DIRECTFB_WM - - r &= region(); - if (r.isEmpty()) { - return; - } - r = r.boundingRect(); - - IDirectFBSurface *primary = d_ptr->primarySurface; - const QList<QWSWindow*> windows = QWSServer::instance()->clientWindows(); - QVarLengthArray<PaintCommand, 4> commands(windows.size()); - QRegion region = r; - int idx = 0; - for (int i=0; i<windows.size(); ++i) { - QWSWindowSurface *surface = windows.at(i)->windowSurface(); - if (!surface) - continue; - - const QRect windowGeometry = surface->geometry(); - const QRegion intersection = region & windowGeometry; - if (intersection.isEmpty()) { - continue; - } - - PaintCommand &cmd = commands[idx]; - - if (surface->key() == QLatin1String("directfb")) { - const QDirectFBWindowSurface *ws = static_cast<QDirectFBWindowSurface*>(surface); - cmd.dfbSurface = ws->directFBSurface(); - - if (!cmd.dfbSurface) { - continue; - } - } else { - cmd.image = surface->image(); - if (cmd.image.isNull()) { - continue; - } - } - ++idx; - - cmd.windowPosition = windowGeometry.topLeft(); - cmd.source = intersection; - if (windows.at(i)->isOpaque()) { - region -= intersection; - if (region.isEmpty()) - break; - } else { - cmd.windowOpacity = windows.at(i)->opacity(); - cmd.blittingFlags = cmd.windowOpacity == 255 - ? DSBLIT_BLEND_ALPHACHANNEL - : (DSBLIT_BLEND_ALPHACHANNEL|DSBLIT_BLEND_COLORALPHA); - } - } - - solidFill(d_ptr->backgroundColor, region); - - while (idx > 0) { - const PaintCommand &cmd = commands[--idx]; - Q_ASSERT(cmd.dfbSurface || !cmd.image.isNull()); - IDirectFBSurface *surface; - if (cmd.dfbSurface) { - surface = cmd.dfbSurface; - } else { - Q_ASSERT(!cmd.image.isNull()); - DFBResult result; - surface = createDFBSurface(cmd.image, cmd.image.format(), DontTrackSurface, &result); - Q_ASSERT((result != DFB_OK) == !surface); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::exposeRegion: Can't create surface from image", result); - continue; - } - } - - primary->SetBlittingFlags(primary, cmd.blittingFlags); - if (cmd.blittingFlags & DSBLIT_BLEND_COLORALPHA) { - primary->SetColor(primary, 0xff, 0xff, 0xff, cmd.windowOpacity); - } - const QRegion ®ion = cmd.source; - const int rectCount = region.rectCount(); - DFBRectangle source; - if (rectCount == 1) { - ::initParameters(source, region.boundingRect(), cmd.windowPosition); - primary->Blit(primary, surface, &source, cmd.windowPosition.x() + source.x, cmd.windowPosition.y() + source.y); - } else { - const QVector<QRect> rects = region.rects(); - for (int i=0; i<rectCount; ++i) { - ::initParameters(source, rects.at(i), cmd.windowPosition); - primary->Blit(primary, surface, &source, cmd.windowPosition.x() + source.x, cmd.windowPosition.y() + source.y); - } - } - if (surface != cmd.dfbSurface) { - surface->Release(surface); - } - } - - primary->SetColor(primary, 0xff, 0xff, 0xff, 0xff); - -#if defined QT_NO_DIRECTFB_CURSOR and !defined QT_NO_QWS_CURSOR - if (QScreenCursor *cursor = QScreenCursor::instance()) { - const QRect cursorRectangle = cursor->boundingRect(); - if (cursor->isVisible() && !cursor->isAccelerated() && r.intersects(cursorRectangle)) { - const QImage image = cursor->image(); - if (image.cacheKey() != d_ptr->cursorImageKey) { - if (d_ptr->cursorSurface) { - releaseDFBSurface(d_ptr->cursorSurface); - } - d_ptr->cursorSurface = createDFBSurface(image, image.format(), QDirectFBScreen::TrackSurface); - d_ptr->cursorImageKey = image.cacheKey(); - } - - Q_ASSERT(d_ptr->cursorSurface); - primary->SetBlittingFlags(primary, DSBLIT_BLEND_ALPHACHANNEL); - primary->Blit(primary, d_ptr->cursorSurface, 0, cursorRectangle.x(), cursorRectangle.y()); - } - } -#endif - flipSurface(primary, d_ptr->flipFlags, r, QPoint()); - primary->SetBlittingFlags(primary, DSBLIT_NOFX); -#endif -} - -void QDirectFBScreen::solidFill(const QColor &color, const QRegion ®ion) -{ -#ifdef QT_DIRECTFB_WM - Q_UNUSED(color); - Q_UNUSED(region); -#else - QDirectFBScreen::solidFill(d_ptr->primarySurface, color, region); -#endif -} - -static inline void clearRect(IDirectFBSurface *surface, const QColor &color, const QRect &rect) -{ - Q_ASSERT(surface); - const DFBRegion region = { rect.left(), rect.top(), rect.right(), rect.bottom() }; - // could just reinterpret_cast this to a DFBRegion - surface->SetClip(surface, ®ion); - surface->Clear(surface, color.red(), color.green(), color.blue(), color.alpha()); -} - -void QDirectFBScreen::solidFill(IDirectFBSurface *surface, const QColor &color, const QRegion ®ion) -{ - if (region.isEmpty()) - return; - - const int n = region.rectCount(); - if (n == 1) { - clearRect(surface, color, region.boundingRect()); - } else { - const QVector<QRect> rects = region.rects(); - for (int i=0; i<n; ++i) { - clearRect(surface, color, rects.at(i)); - } - } - surface->SetClip(surface, 0); -} - -QImage::Format QDirectFBScreen::alphaPixmapFormat() const -{ - return d_ptr->alphaPixmapFormat; -} - -bool QDirectFBScreen::initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *description, - QImage::Format format) -{ - const DFBSurfacePixelFormat pixelformat = QDirectFBScreen::getSurfacePixelFormat(format); - if (pixelformat == DSPF_UNKNOWN) - return false; - description->flags |= DSDESC_PIXELFORMAT; - description->pixelformat = pixelformat; - if (QDirectFBScreen::isPremultiplied(format)) { - if (!(description->flags & DSDESC_CAPS)) { - description->caps = DSCAPS_PREMULTIPLIED; - description->flags |= DSDESC_CAPS; - } else { - description->caps |= DSCAPS_PREMULTIPLIED; - } - } - return true; -} - -uchar *QDirectFBScreen::lockSurface(IDirectFBSurface *surface, DFBSurfaceLockFlags flags, int *bpl) -{ - void *mem = 0; - const DFBResult result = surface->Lock(surface, flags, &mem, bpl); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::lockSurface()", result); - } - - return reinterpret_cast<uchar*>(mem); -} - -static inline bool isFullUpdate(IDirectFBSurface *surface, const QRegion ®ion, const QPoint &offset) -{ - if (offset == QPoint(0, 0) && region.rectCount() == 1) { - QSize size; - surface->GetSize(surface, &size.rwidth(), &size.rheight()); - if (region.boundingRect().size() == size) - return true; - } - return false; -} - -void QDirectFBScreen::flipSurface(IDirectFBSurface *surface, DFBSurfaceFlipFlags flipFlags, - const QRegion ®ion, const QPoint &offset) -{ - if (d_ptr->directFBFlags & NoPartialFlip - || (!(flipFlags & DSFLIP_BLIT) && QT_PREPEND_NAMESPACE(isFullUpdate(surface, region, offset)))) { - surface->Flip(surface, 0, flipFlags); - } else { - if (!(d_ptr->directFBFlags & BoundingRectFlip) && region.rectCount() > 1) { - const QVector<QRect> rects = region.rects(); - const DFBSurfaceFlipFlags nonWaitFlags = flipFlags & ~DSFLIP_WAIT; - for (int i=0; i<rects.size(); ++i) { - const QRect &r = rects.at(i); - const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(), - r.right() + offset.x(), - r.bottom() + offset.y() }; - surface->Flip(surface, &dfbReg, i + 1 < rects.size() ? nonWaitFlags : flipFlags); - } - } else { - const QRect r = region.boundingRect(); - const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(), - r.right() + offset.x(), - r.bottom() + offset.y() }; - surface->Flip(surface, &dfbReg, flipFlags); - } - } -} - -#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE -void QDirectFBScreen::setDirectFBImageProvider(IDirectFBImageProvider *provider) -{ - Q_ASSERT(provider); - if (d_ptr->imageProvider) - d_ptr->imageProvider->Release(d_ptr->imageProvider); - d_ptr->imageProvider = provider; -} -#endif - -void QDirectFBScreen::waitIdle() -{ - d_ptr->dfb->WaitIdle(d_ptr->dfb); -} - -#ifdef QT_DIRECTFB_WM -IDirectFBWindow *QDirectFBScreen::windowForWidget(const QWidget *widget) const -{ - if (widget) { - const QWSWindowSurface *surface = static_cast<const QWSWindowSurface*>(widget->windowSurface()); - if (surface && surface->key() == QLatin1String("directfb")) { - return static_cast<const QDirectFBWindowSurface*>(surface)->directFBWindow(); - } - } - return 0; -} -#endif - -IDirectFBSurface * QDirectFBScreen::surfaceForWidget(const QWidget *widget, QRect *rect) const -{ - Q_ASSERT(widget); - if (!widget->isVisible() || widget->size().isNull()) - return 0; - - const QWSWindowSurface *surface = static_cast<const QWSWindowSurface*>(widget->windowSurface()); - if (surface && surface->key() == QLatin1String("directfb")) { - return static_cast<const QDirectFBWindowSurface*>(surface)->surfaceForWidget(widget, rect); - } - return 0; -} - -#ifdef QT_DIRECTFB_SUBSURFACE -IDirectFBSurface *QDirectFBScreen::subSurfaceForWidget(const QWidget *widget, const QRect &area) const -{ - Q_ASSERT(widget); - QRect rect; - IDirectFBSurface *surface = surfaceForWidget(widget, &rect); - IDirectFBSurface *subSurface = 0; - if (surface) { - if (!area.isNull()) - rect &= area.translated(widget->mapTo(widget->window(), QPoint(0, 0))); - if (!rect.isNull()) { - const DFBRectangle subRect = { rect.x(), rect.y(), rect.width(), rect.height() }; - const DFBResult result = surface->GetSubSurface(surface, &subRect, &subSurface); - if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::subSurface(): Can't get sub surface", result); - } - } - } - return subSurface; -} -#endif - -Q_GUI_EXPORT IDirectFBSurface *qt_directfb_surface_for_widget(const QWidget *widget, QRect *rect) -{ - return QDirectFBScreen::instance() ? QDirectFBScreen::instance()->surfaceForWidget(widget, rect) : 0; -} -#ifdef QT_DIRECTFB_SUBSURFACE -Q_GUI_EXPORT IDirectFBSurface *qt_directfb_subsurface_for_widget(const QWidget *widget, const QRect &area) -{ - return QDirectFBScreen::instance() ? QDirectFBScreen::instance()->subSurfaceForWidget(widget, area) : 0; -} -#endif -#ifdef QT_DIRECTFB_WM -Q_GUI_EXPORT IDirectFBWindow *qt_directfb_window_for_widget(const QWidget *widget) -{ - return QDirectFBScreen::instance() ? QDirectFBScreen::instance()->windowForWidget(widget) : 0; -} - -#endif - -QT_END_NAMESPACE - -#include "qdirectfbscreen.moc" -#endif // QT_NO_QWS_DIRECTFB - diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h deleted file mode 100644 index afc153bab2..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h +++ /dev/null @@ -1,303 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDIRECTFBSCREEN_H -#define QDIRECTFBSCREEN_H - -#include <qglobal.h> -#ifndef QT_NO_QWS_DIRECTFB -#include <QtGui/qscreen_qws.h> -#include <directfb.h> -#include <directfb_version.h> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) - -#if !defined QT_DIRECTFB_SUBSURFACE && !defined QT_NO_DIRECTFB_SUBSURFACE -#define QT_NO_DIRECTFB_SUBSURFACE -#endif -#if !defined QT_NO_DIRECTFB_LAYER && !defined QT_DIRECTFB_LAYER -#define QT_DIRECTFB_LAYER -#endif -#if !defined QT_NO_DIRECTFB_WM && !defined QT_DIRECTFB_WM -#define QT_DIRECTFB_WM -#endif -#if !defined QT_DIRECTFB_IMAGECACHE && !defined QT_NO_DIRECTFB_IMAGECACHE -#define QT_NO_DIRECTFB_IMAGECACHE -#endif -#if !defined QT_NO_DIRECTFB_IMAGEPROVIDER && !defined QT_DIRECTFB_IMAGEPROVIDER -#define QT_DIRECTFB_IMAGEPROVIDER -#endif -#if !defined QT_NO_DIRECTFB_STRETCHBLIT && !defined QT_DIRECTFB_STRETCHBLIT -#define QT_DIRECTFB_STRETCHBLIT -#endif -#if !defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE && !defined QT_NO_DIRECTFB_IMAGEPROVIDER_KEEPALIVE -#define QT_NO_DIRECTFB_IMAGEPROVIDER_KEEPALIVE -#endif -#if !defined QT_DIRECTFB_WINDOW_AS_CURSOR && !defined QT_NO_DIRECTFB_WINDOW_AS_CURSOR -#define QT_NO_DIRECTFB_WINDOW_AS_CURSOR -#endif -#if !defined QT_DIRECTFB_PALETTE && !defined QT_NO_DIRECTFB_PALETTE -#define QT_NO_DIRECTFB_PALETTE -#endif -#if !defined QT_NO_DIRECTFB_PREALLOCATED && !defined QT_DIRECTFB_PREALLOCATED -#define QT_DIRECTFB_PREALLOCATED -#endif -#if !defined QT_NO_DIRECTFB_MOUSE && !defined QT_DIRECTFB_MOUSE -#define QT_DIRECTFB_MOUSE -#endif -#if !defined QT_NO_DIRECTFB_KEYBOARD && !defined QT_DIRECTFB_KEYBOARD -#define QT_DIRECTFB_KEYBOARD -#endif -#if !defined QT_NO_DIRECTFB_OPAQUE_DETECTION && !defined QT_DIRECTFB_OPAQUE_DETECTION -#define QT_DIRECTFB_OPAQUE_DETECTION -#endif -#ifndef QT_NO_QWS_CURSOR -#if defined QT_DIRECTFB_WM && defined QT_DIRECTFB_WINDOW_AS_CURSOR -#define QT_DIRECTFB_CURSOR -#elif defined QT_DIRECTFB_LAYER -#define QT_DIRECTFB_CURSOR -#endif -#endif -#ifndef QT_DIRECTFB_CURSOR -#define QT_NO_DIRECTFB_CURSOR -#endif -#if defined QT_NO_DIRECTFB_LAYER && defined QT_DIRECTFB_WM -#error QT_NO_DIRECTFB_LAYER requires QT_NO_DIRECTFB_WM -#endif -#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE && defined QT_NO_DIRECTFB_IMAGEPROVIDER -#error QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE requires QT_DIRECTFB_IMAGEPROVIDER to be defined -#endif -#if defined QT_DIRECTFB_WINDOW_AS_CURSOR && defined QT_NO_DIRECTFB_WM -#error QT_DIRECTFB_WINDOW_AS_CURSOR requires QT_DIRECTFB_WM to be defined -#endif - -#define Q_DIRECTFB_VERSION ((DIRECTFB_MAJOR_VERSION << 16) | (DIRECTFB_MINOR_VERSION << 8) | DIRECTFB_MICRO_VERSION) - -#define DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(F) \ - static inline F operator~(F f) { return F(~int(f)); } \ - static inline F operator&(F left, F right) { return F(int(left) & int(right)); } \ - static inline F operator|(F left, F right) { return F(int(left) | int(right)); } \ - static inline F &operator|=(F &left, F right) { left = (left | right); return left; } \ - static inline F &operator&=(F &left, F right) { left = (left & right); return left; } - -DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBInputDeviceCapabilities); -DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBWindowDescriptionFlags); -DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBWindowCapabilities); -DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBWindowOptions); -DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceDescriptionFlags); -DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceCapabilities); -DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceLockFlags); -DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceBlittingFlags); -DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceDrawingFlags); -DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceFlipFlags); - -class QDirectFBScreenPrivate; -class Q_GUI_EXPORT QDirectFBScreen : public QScreen -{ -public: - QDirectFBScreen(int display_id); - ~QDirectFBScreen(); - - enum DirectFBFlag { - NoFlags = 0x00, - VideoOnly = 0x01, - SystemOnly = 0x02, - BoundingRectFlip = 0x04, - NoPartialFlip = 0x08 - }; - - Q_DECLARE_FLAGS(DirectFBFlags, DirectFBFlag); - - DirectFBFlags directFBFlags() const; - - bool connect(const QString &displaySpec); - void disconnect(); - bool initDevice(); - void shutdownDevice(); - - void exposeRegion(QRegion r, int changing); - void solidFill(const QColor &color, const QRegion ®ion); - static void solidFill(IDirectFBSurface *surface, const QColor &color, const QRegion ®ion); - - void setMode(int width, int height, int depth); - void blank(bool on); - - QWSWindowSurface *createSurface(QWidget *widget) const; - QWSWindowSurface *createSurface(const QString &key) const; - - static QDirectFBScreen *instance(); - void waitIdle(); - IDirectFBSurface *surfaceForWidget(const QWidget *widget, QRect *rect) const; -#ifdef QT_DIRECTFB_SUBSURFACE - IDirectFBSurface *subSurfaceForWidget(const QWidget *widget, const QRect &area = QRect()) const; -#endif - IDirectFB *dfb(); -#ifdef QT_DIRECTFB_WM - IDirectFBWindow *windowForWidget(const QWidget *widget) const; -#else - IDirectFBSurface *primarySurface(); -#endif -#ifndef QT_NO_DIRECTFB_LAYER - IDirectFBDisplayLayer *dfbDisplayLayer(); -#endif - - // Track surface creation/release so we can release all on exit - enum SurfaceCreationOption { - DontTrackSurface = 0x1, - TrackSurface = 0x2, - NoPreallocated = 0x4 - }; - Q_DECLARE_FLAGS(SurfaceCreationOptions, SurfaceCreationOption); - IDirectFBSurface *createDFBSurface(const QImage &image, - QImage::Format format, - SurfaceCreationOptions options, - DFBResult *result = 0); - IDirectFBSurface *createDFBSurface(const QSize &size, - QImage::Format format, - SurfaceCreationOptions options, - DFBResult *result = 0); - IDirectFBSurface *copyDFBSurface(IDirectFBSurface *src, - QImage::Format format, - SurfaceCreationOptions options, - DFBResult *result = 0); - IDirectFBSurface *createDFBSurface(DFBSurfaceDescription desc, - SurfaceCreationOptions options, - DFBResult *result); -#ifdef QT_DIRECTFB_SUBSURFACE - IDirectFBSurface *getSubSurface(IDirectFBSurface *surface, - const QRect &rect, - SurfaceCreationOptions options, - DFBResult *result); -#endif - - void flipSurface(IDirectFBSurface *surface, DFBSurfaceFlipFlags flipFlags, - const QRegion ®ion, const QPoint &offset); - void releaseDFBSurface(IDirectFBSurface *surface); - - using QScreen::depth; - static int depth(DFBSurfacePixelFormat format); - static int depth(QImage::Format format); - - static DFBSurfacePixelFormat getSurfacePixelFormat(QImage::Format format); - static DFBSurfaceDescription getSurfaceDescription(const uint *buffer, - int length); - static QImage::Format getImageFormat(IDirectFBSurface *surface); - static bool initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *description, QImage::Format format); - static inline bool isPremultiplied(QImage::Format format); - static inline bool hasAlphaChannel(DFBSurfacePixelFormat format); - static inline bool hasAlphaChannel(IDirectFBSurface *surface); - QImage::Format alphaPixmapFormat() const; - -#ifndef QT_NO_DIRECTFB_PALETTE - static void setSurfaceColorTable(IDirectFBSurface *surface, - const QImage &image); -#endif - - static uchar *lockSurface(IDirectFBSurface *surface, DFBSurfaceLockFlags flags, int *bpl = 0); -#if defined QT_DIRECTFB_IMAGEPROVIDER && defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE - void setDirectFBImageProvider(IDirectFBImageProvider *provider); -#endif -private: - QDirectFBScreenPrivate *d_ptr; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QDirectFBScreen::SurfaceCreationOptions); -Q_DECLARE_OPERATORS_FOR_FLAGS(QDirectFBScreen::DirectFBFlags); - -inline bool QDirectFBScreen::isPremultiplied(QImage::Format format) -{ - switch (format) { - case QImage::Format_ARGB32_Premultiplied: - case QImage::Format_ARGB8565_Premultiplied: - case QImage::Format_ARGB6666_Premultiplied: - case QImage::Format_ARGB8555_Premultiplied: - case QImage::Format_ARGB4444_Premultiplied: - return true; - default: - break; - } - return false; -} - -inline bool QDirectFBScreen::hasAlphaChannel(DFBSurfacePixelFormat format) -{ - switch (format) { - case DSPF_ARGB1555: - case DSPF_ARGB: - case DSPF_LUT8: - case DSPF_AiRGB: - case DSPF_A1: - case DSPF_ARGB2554: - case DSPF_ARGB4444: -#if (Q_DIRECTFB_VERSION >= 0x000923) - case DSPF_AYUV: -#endif -#if (Q_DIRECTFB_VERSION >= 0x010000) - case DSPF_A4: - case DSPF_ARGB1666: - case DSPF_ARGB6666: - case DSPF_LUT2: -#endif - return true; - default: - return false; - } -} - -inline bool QDirectFBScreen::hasAlphaChannel(IDirectFBSurface *surface) -{ - Q_ASSERT(surface); - DFBSurfacePixelFormat format; - surface->GetPixelFormat(surface, &format); - return QDirectFBScreen::hasAlphaChannel(format); -} - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QT_NO_QWS_DIRECTFB -#endif // QDIRECTFBSCREEN_H - diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp deleted file mode 100644 index b8fc811e4d..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp +++ /dev/null @@ -1,506 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdirectfbwindowsurface.h" -#include "qdirectfbscreen.h" -#include "qdirectfbpaintengine.h" - -#include <private/qwidget_p.h> -#include <qwidget.h> -#include <qwindowsystem_qws.h> -#include <qpaintdevice.h> -#include <qvarlengtharray.h> - -#ifndef QT_NO_QWS_DIRECTFB - -QT_BEGIN_NAMESPACE - -QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr) - : QDirectFBPaintDevice(scr) -#ifndef QT_NO_DIRECTFB_WM - , dfbWindow(0) -#endif - , flipFlags(flip) - , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip) - , flushPending(false) -{ -#ifdef QT_NO_DIRECTFB_WM - mode = Offscreen; -#endif - setSurfaceFlags(Opaque | Buffered); -#ifdef QT_DIRECTFB_TIMING - frames = 0; - timer.start(); -#endif -} - -QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr, QWidget *widget) - : QWSWindowSurface(widget), QDirectFBPaintDevice(scr) -#ifndef QT_NO_DIRECTFB_WM - , dfbWindow(0) -#endif - , flipFlags(flip) - , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip) - , flushPending(false) -{ - SurfaceFlags flags = 0; - if (!widget || widget->window()->windowOpacity() == 0xff) - flags |= Opaque; -#ifdef QT_NO_DIRECTFB_WM - if (widget && widget->testAttribute(Qt::WA_PaintOnScreen)) { - flags = RegionReserved; - mode = Primary; - } else { - mode = Offscreen; - flags = Buffered; - } -#endif - setSurfaceFlags(flags); -#ifdef QT_DIRECTFB_TIMING - frames = 0; - timer.start(); -#endif -} - -QDirectFBWindowSurface::~QDirectFBWindowSurface() -{ - releaseSurface(); - // these are not tracked by QDirectFBScreen so we don't want QDirectFBPaintDevice to release it -} - -bool QDirectFBWindowSurface::isValid() const -{ - return true; -} - -#ifdef QT_DIRECTFB_WM -void QDirectFBWindowSurface::raise() -{ - if (IDirectFBWindow *window = directFBWindow()) { - window->RaiseToTop(window); - } -} - -IDirectFBWindow *QDirectFBWindowSurface::directFBWindow() const -{ - return dfbWindow; -} - -void QDirectFBWindowSurface::createWindow(const QRect &rect) -{ - IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer(); - if (!layer) - qFatal("QDirectFBWindowSurface: Unable to get primary display layer!"); - - updateIsOpaque(); - - DFBWindowDescription description; - memset(&description, 0, sizeof(DFBWindowDescription)); - - description.flags = DWDESC_CAPS|DWDESC_HEIGHT|DWDESC_WIDTH|DWDESC_POSX|DWDESC_POSY|DWDESC_SURFACE_CAPS|DWDESC_PIXELFORMAT; - description.caps = DWCAPS_NODECORATION; - description.surface_caps = DSCAPS_NONE; - imageFormat = screen->pixelFormat(); - - if (!(surfaceFlags() & Opaque)) { - imageFormat = screen->alphaPixmapFormat(); - description.caps |= DWCAPS_ALPHACHANNEL; -#if (Q_DIRECTFB_VERSION >= 0x010200) - description.flags |= DWDESC_OPTIONS; - description.options |= DWOP_ALPHACHANNEL; -#endif - } - description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(imageFormat); - description.posx = rect.x(); - description.posy = rect.y(); - description.width = rect.width(); - description.height = rect.height(); - - if (QDirectFBScreen::isPremultiplied(imageFormat)) - description.surface_caps = DSCAPS_PREMULTIPLIED; - - if (screen->directFBFlags() & QDirectFBScreen::VideoOnly) - description.surface_caps |= DSCAPS_VIDEOONLY; - - DFBResult result = layer->CreateWindow(layer, &description, &dfbWindow); - - if (result != DFB_OK) - DirectFBErrorFatal("QDirectFBWindowSurface::createWindow", result); - - if (window()) { - if (window()->windowFlags() & Qt::WindowStaysOnTopHint) { - dfbWindow->SetStackingClass(dfbWindow, DWSC_UPPER); - } - DFBWindowID winid; - result = dfbWindow->GetID(dfbWindow, &winid); - if (result != DFB_OK) { - DirectFBError("QDirectFBWindowSurface::createWindow. Can't get ID", result); - } else { - window()->setProperty("_q_DirectFBWindowID", winid); - } - } - - Q_ASSERT(!dfbSurface); - dfbWindow->GetSurface(dfbWindow, &dfbSurface); -} - -static DFBResult setWindowGeometry(IDirectFBWindow *dfbWindow, const QRect &old, const QRect &rect) -{ - DFBResult result = DFB_OK; - const bool isMove = old.isEmpty() || rect.topLeft() != old.topLeft(); - const bool isResize = rect.size() != old.size(); - -#if (Q_DIRECTFB_VERSION >= 0x010000) - if (isResize && isMove) { - result = dfbWindow->SetBounds(dfbWindow, rect.x(), rect.y(), - rect.width(), rect.height()); - } else if (isResize) { - result = dfbWindow->Resize(dfbWindow, - rect.width(), rect.height()); - } else if (isMove) { - result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y()); - } -#else - if (isResize) { - result = dfbWindow->Resize(dfbWindow, - rect.width(), rect.height()); - } - if (isMove) { - result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y()); - } -#endif - return result; -} -#endif // QT_NO_DIRECTFB_WM - -void QDirectFBWindowSurface::setGeometry(const QRect &rect) -{ - const QRect oldRect = geometry(); - if (oldRect == rect) - return; - - IDirectFBSurface *oldSurface = dfbSurface; - const bool sizeChanged = oldRect.size() != rect.size(); - if (sizeChanged) { - delete engine; - engine = 0; - releaseSurface(); - Q_ASSERT(!dfbSurface); - } - - if (rect.isNull()) { -#ifndef QT_NO_DIRECTFB_WM - if (dfbWindow) { - if (window()) - window()->setProperty("_q_DirectFBWindowID", QVariant()); - - dfbWindow->Release(dfbWindow); - dfbWindow = 0; - } -#endif - Q_ASSERT(!dfbSurface); -#ifdef QT_DIRECTFB_SUBSURFACE - Q_ASSERT(!subSurface); -#endif - } else { -#ifdef QT_DIRECTFB_WM - if (!dfbWindow) { - createWindow(rect); - } else { - setWindowGeometry(dfbWindow, oldRect, rect); - Q_ASSERT(!sizeChanged || !dfbSurface); - if (sizeChanged) - dfbWindow->GetSurface(dfbWindow, &dfbSurface); - } -#else - IDirectFBSurface *primarySurface = screen->primarySurface(); - DFBResult result = DFB_OK; - if (mode == Primary) { - Q_ASSERT(primarySurface); - if (rect == screen->region().boundingRect()) { - dfbSurface = primarySurface; - } else { - const DFBRectangle r = { rect.x(), rect.y(), - rect.width(), rect.height() }; - result = primarySurface->GetSubSurface(primarySurface, &r, &dfbSurface); - } - } else { // mode == Offscreen - if (!dfbSurface) { - dfbSurface = screen->createDFBSurface(rect.size(), surfaceFlags() & Opaque ? screen->pixelFormat() : screen->alphaPixmapFormat(), - QDirectFBScreen::DontTrackSurface); - } - } - if (result != DFB_OK) - DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result); -#endif - } - if (oldSurface != dfbSurface) { - imageFormat = dfbSurface ? QDirectFBScreen::getImageFormat(dfbSurface) : QImage::Format_Invalid; - } - - if (oldRect.size() != rect.size()) { - QWSWindowSurface::setGeometry(rect); - } else { - QWindowSurface::setGeometry(rect); - } -} - -QByteArray QDirectFBWindowSurface::permanentState() const -{ - QByteArray state(sizeof(SurfaceFlags) + sizeof(DFBWindowID), 0); - char *ptr = state.data(); - SurfaceFlags flags = surfaceFlags(); - memcpy(ptr, &flags, sizeof(SurfaceFlags)); - ptr += sizeof(SurfaceFlags); - DFBWindowID did = (DFBWindowID)(-1); - if (dfbWindow) - dfbWindow->GetID(dfbWindow, &did); - memcpy(ptr, &did, sizeof(DFBWindowID)); - return state; -} - -void QDirectFBWindowSurface::setPermanentState(const QByteArray &state) -{ - const char *ptr = state.constData(); - IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer(); - SurfaceFlags flags; - memcpy(&flags, ptr, sizeof(SurfaceFlags)); - - setSurfaceFlags(flags); - ptr += sizeof(SurfaceFlags); - DFBWindowID id; - memcpy(&id, ptr, sizeof(DFBWindowID)); - if (dfbSurface) - dfbSurface->Release(dfbSurface); - if (id != (DFBWindowID)-1) { - IDirectFBWindow *dw; - layer->GetWindow(layer, id, &dw); - if (dw->GetSurface(dw, &dfbSurface) != DFB_OK) - dfbSurface = 0; - dw->Release(dw); - } - else { - dfbSurface = 0; - } -} - -bool QDirectFBWindowSurface::scroll(const QRegion ®ion, int dx, int dy) -{ - if (!dfbSurface || !(flipFlags & DSFLIP_BLIT) || region.rectCount() != 1) - return false; - if (flushPending) { - dfbSurface->Flip(dfbSurface, 0, DSFLIP_BLIT); - } else { - flushPending = true; - } - dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); - const QRect r = region.boundingRect(); - const DFBRectangle rect = { r.x(), r.y(), r.width(), r.height() }; - dfbSurface->Blit(dfbSurface, dfbSurface, &rect, r.x() + dx, r.y() + dy); - return true; -} - -bool QDirectFBWindowSurface::move(const QPoint &moveBy) -{ - setGeometry(geometry().translated(moveBy)); - return true; -} - -void QDirectFBWindowSurface::setOpaque(bool opaque) -{ - SurfaceFlags flags = surfaceFlags(); - if (opaque != (flags & Opaque)) { - if (opaque) { - flags |= Opaque; - } else { - flags &= ~Opaque; - } - setSurfaceFlags(flags); - } -} - - -void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion ®ion, - const QPoint &offset) -{ - QWidget *win = window(); - if (!win) - return; - -#if !defined(QT_NO_QWS_PROXYSCREEN) && !defined(QT_NO_GRAPHICSVIEW) - QWExtra *extra = qt_widget_private(widget)->extraData(); - if (extra && extra->proxyWidget) - return; -#else - Q_UNUSED(widget); -#endif - - const quint8 windowOpacity = quint8(win->windowOpacity() * 0xff); - const QRect windowGeometry = geometry(); -#ifdef QT_DIRECTFB_WM - quint8 currentOpacity; - Q_ASSERT(dfbWindow); - dfbWindow->GetOpacity(dfbWindow, ¤tOpacity); - if (currentOpacity != windowOpacity) { - dfbWindow->SetOpacity(dfbWindow, windowOpacity); - } - - screen->flipSurface(dfbSurface, flipFlags, region, offset); -#else - setOpaque(windowOpacity == 0xff); - if (mode == Offscreen) { - screen->exposeRegion(region.translated(offset + geometry().topLeft()), 0); - } else { - screen->flipSurface(dfbSurface, flipFlags, region, offset); - } -#endif - -#ifdef QT_DIRECTFB_TIMING - enum { Secs = 3 }; - ++frames; - if (timer.elapsed() >= Secs * 1000) { - qDebug("%d fps", int(double(frames) / double(Secs))); - frames = 0; - timer.restart(); - } -#endif - flushPending = false; -} - -void QDirectFBWindowSurface::beginPaint(const QRegion ®ion) -{ - if (!engine) { - engine = new QDirectFBPaintEngine(this); - } - - if (dfbSurface) { - const QWidget *win = window(); - if (win && win->testAttribute(Qt::WA_NoSystemBackground)) { - QDirectFBScreen::solidFill(dfbSurface, Qt::transparent, region); - } - } - flushPending = true; -} - -void QDirectFBWindowSurface::endPaint(const QRegion &) -{ -#ifdef QT_NO_DIRECTFB_SUBSURFACE - unlockSurface(); -#endif -} - -IDirectFBSurface *QDirectFBWindowSurface::directFBSurface() const -{ - return dfbSurface; -} - - -IDirectFBSurface *QDirectFBWindowSurface::surfaceForWidget(const QWidget *widget, QRect *rect) const -{ - Q_ASSERT(widget); - if (!dfbSurface) - return 0; - QWidget *win = window(); - Q_ASSERT(win); - if (rect) { - if (win == widget) { - *rect = widget->rect(); - } else { - *rect = QRect(widget->mapTo(win, QPoint(0, 0)), widget->size()); - } - } - - Q_ASSERT(win == widget || win->isAncestorOf(widget)); - return dfbSurface; -} - -void QDirectFBWindowSurface::releaseSurface() -{ - if (dfbSurface) { -#ifdef QT_DIRECTFB_SUBSURFACE - releaseSubSurface(); -#else - unlockSurface(); -#endif -#ifdef QT_NO_DIRECTFB_WM - Q_ASSERT(screen->primarySurface()); - if (dfbSurface != screen->primarySurface()) -#endif - - dfbSurface->Release(dfbSurface); - dfbSurface = 0; - } -} - -void QDirectFBWindowSurface::updateIsOpaque() -{ - const QWidget *win = window(); - Q_ASSERT(win); - if (win->testAttribute(Qt::WA_OpaquePaintEvent) || win->testAttribute(Qt::WA_PaintOnScreen)) { - setOpaque(true); - return; - } - - if (qFuzzyCompare(static_cast<float>(win->windowOpacity()), 1.0f)) { - const QPalette &pal = win->palette(); - - if (win->autoFillBackground()) { - const QBrush &autoFillBrush = pal.brush(win->backgroundRole()); - if (autoFillBrush.style() != Qt::NoBrush && autoFillBrush.isOpaque()) { - setOpaque(true); - return; - } - } - - if (win->isWindow() && !win->testAttribute(Qt::WA_NoSystemBackground)) { - const QBrush &windowBrush = win->palette().brush(QPalette::Window); - if (windowBrush.style() != Qt::NoBrush && windowBrush.isOpaque()) { - setOpaque(true); - return; - } - } - } - setOpaque(false); -} - -QT_END_NAMESPACE - -#endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h deleted file mode 100644 index df9baa1ff2..0000000000 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h +++ /dev/null @@ -1,129 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDIRECFBWINDOWSURFACE_H -#define QDIRECFBWINDOWSURFACE_H - -#include "qdirectfbpaintengine.h" -#include "qdirectfbpaintdevice.h" -#include "qdirectfbscreen.h" - -#ifndef QT_NO_QWS_DIRECTFB - -#include <private/qpaintengine_raster_p.h> -#include <private/qwindowsurface_qws_p.h> - -#ifdef QT_DIRECTFB_TIMING -#include <qdatetime.h> -#endif - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) - -class QDirectFBWindowSurface : public QWSWindowSurface, public QDirectFBPaintDevice -{ -public: - QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen *scr); - QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen *scr, QWidget *widget); - ~QDirectFBWindowSurface(); - -#ifdef QT_DIRECTFB_WM - void raise(); -#endif - bool isValid() const; - - void setGeometry(const QRect &rect); - - QString key() const { return QLatin1String("directfb"); } - QByteArray permanentState() const; - void setPermanentState(const QByteArray &state); - - bool scroll(const QRegion &area, int dx, int dy); - - bool move(const QPoint &offset); - - QImage image() const { return QImage(); } - QPaintDevice *paintDevice() { return this; } - - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - - void beginPaint(const QRegion &); - void endPaint(const QRegion &); - - IDirectFBSurface *surfaceForWidget(const QWidget *widget, QRect *rect) const; - IDirectFBSurface *directFBSurface() const; -#ifdef QT_DIRECTFB_WM - IDirectFBWindow *directFBWindow() const; -#endif -private: - void updateIsOpaque(); - void setOpaque(bool opaque); - void releaseSurface(); - -#ifdef QT_DIRECTFB_WM - void createWindow(const QRect &rect); - IDirectFBWindow *dfbWindow; -#else - enum Mode { - Primary, - Offscreen - } mode; -#endif - - DFBSurfaceFlipFlags flipFlags; - bool boundingRectFlip; - bool flushPending; -#ifdef QT_DIRECTFB_TIMING - int frames; - QTime timer; -#endif -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QT_NO_QWS_DIRECTFB - -#endif // QDIRECFBWINDOWSURFACE_H diff --git a/src/plugins/gfxdrivers/eglnullws/README b/src/plugins/gfxdrivers/eglnullws/README deleted file mode 100644 index 80b88c7e01..0000000000 --- a/src/plugins/gfxdrivers/eglnullws/README +++ /dev/null @@ -1,48 +0,0 @@ -EGL NullWS QScreen Driver -========================= - -If your application draws everything within a single full-screen QGLWidget then -you may wish to use this QScreen plugin driver. This driver simply returns 0 -(as a EGLNativeWindowType value) when asked by the QtOpenGl module to create a -native window. Some OpenGL ES implementations (including PowerVR) interpret this -to mean that a full-screen OpenGL context is desired without any windowing -support (NullWS). - -To tell a Qt/Embedded application to use this driver use the -display command -line option or the QWS_DISPLAY environment variable. The following driver -options are supported: - -size=WIDTHxHEIGHT Screen size reported by the driver -format=FORMAT Screen format - -Run with '-display eglnullws:help' to get a full list of options (including a -list of supported format strings). - -If you choose a screen format that is not supported by the hardware then the -QtOpenGl module will write out a list of supported EGL configurations. Use -one of the supported screen formats from this list. - -Using this driver with PowerVR hardware ---------------------------------------- - -Using this plugin with PowerVR hardware should give a significant speedup -compared to running with the Qt powervr driver (with a full-screen QGLWidget). -This is because sacrificing the window system allows less work to be done in -order to get graphics on the screen. Using this driver also avoids the memory -fragmentation issues present in the powervr driver and avoids any direct -dependencies on the deprecated PVR2D API from Imagination Technologies. - -To use this driver ensure you have /etc/powervr.ini with contents similar to -this: - -[default] -WindowSystem=libpvrPVR2D_FLIPWSEGL.so - -This driver will also function with libpvrPVR2D_FRONTWSEGL.so, but that draws -straight into the framebuffer and will therefore cause flickering (it can be -useful for performance testing though). The flip plugin uses triple buffering, -so you will need to set the virtual vertical resolution of your framebuffer to -be three times the physical vertical resolution of your screen. This can be -done with 'fbset -vyres'. Failure to do this can cause system crashes. You -should also ensure that the plugin you choose in powervr.ini is in your library -path (it may just silently default to the flip plugin if not). diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullws.pro b/src/plugins/gfxdrivers/eglnullws/eglnullws.pro deleted file mode 100644 index cb65c2b627..0000000000 --- a/src/plugins/gfxdrivers/eglnullws/eglnullws.pro +++ /dev/null @@ -1,18 +0,0 @@ -TARGET = qeglnullws -load(qt_plugin) - -CONFIG += warn_on -QT += opengl - -DESTDIR = $$QT.gui.plugins/gfxdrivers - -target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers -INSTALLS += target - -HEADERS = eglnullwsscreen.h \ - eglnullwsscreenplugin.h \ - eglnullwswindowsurface.h - -SOURCES = eglnullwsscreen.cpp \ - eglnullwsscreenplugin.cpp \ - eglnullwswindowsurface.cpp diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp deleted file mode 100644 index e8c73cf31d..0000000000 --- a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "eglnullwsscreen.h" -#include "eglnullwswindowsurface.h" -#include "eglnullwsscreenplugin.h" - -#include <QHash> -#include <QDebug> - -namespace -{ - class EGLNullWSScreenSurfaceFunctions : public QGLScreenSurfaceFunctions - { - public: - virtual bool createNativeWindow(QWidget *, EGLNativeWindowType *native) - { *native = 0; return true; } - }; -} - -EGLNullWSScreen::EGLNullWSScreen(int displayId) : QGLScreen(displayId) {} - -EGLNullWSScreen::~EGLNullWSScreen() {} - -bool EGLNullWSScreen::initDevice() -{ - setSurfaceFunctions(new EGLNullWSScreenSurfaceFunctions); - return true; -} - -static const QHash<QString, QImage::Format> formatDictionary() -{ - QHash<QString, QImage::Format> dictionary; - dictionary["rgb32"] = QImage::Format_RGB32; - dictionary["argb32"] = QImage::Format_ARGB32; - dictionary["rgb16"] = QImage::Format_RGB16; - dictionary["rgb666"] = QImage::Format_RGB666; - dictionary["rgb555"] = QImage::Format_RGB555; - dictionary["rgb888"] = QImage::Format_RGB888; - dictionary["rgb444"] = QImage::Format_RGB444; - return dictionary; -} - -static int depthForFormat(QImage::Format format) -{ - switch (format) { - case QImage::Format_RGB32: return 32; - case QImage::Format_ARGB32: return 32; - case QImage::Format_RGB16: return 16; - case QImage::Format_RGB666: return 24; - case QImage::Format_RGB555: return 16; - case QImage::Format_RGB888: return 24; - case QImage::Format_RGB444: return 16; - default: - Q_ASSERT_X(false, "EGLNullWSScreen", "Unknown format"); - return -1; - } -} - -static void printHelp(const QHash<QString, QImage::Format> &formatDictionary) -{ - QByteArray formatsBuf; - QTextStream(&formatsBuf) << QStringList(formatDictionary.keys()).join(", "); - qWarning( - "%s: Valid options are:\n" - "size=WIDTHxHEIGHT Screen size reported by this driver\n" - "format=FORMAT Screen format, where FORMAT is one of the following:\n" - " %s\n", - PluginName, - formatsBuf.constData()); -} - -bool EGLNullWSScreen::connect(const QString &displaySpec) -{ - const QStringList args = displaySpec.section(':', 1).split(':', QString::SkipEmptyParts); - const QHash<QString, QImage::Format> formatDict = formatDictionary(); - Q_FOREACH(const QString arg, args) { - const QString optionName = arg.section('=', 0, 0); - const QString optionArg = arg.section('=', 1); - if (optionName == QLatin1String("size")) { - w = optionArg.section('x', 0, 0).toInt(); - h = optionArg.section('x', 1, 1).toInt(); - } else if (optionName == QLatin1String("format")) { - if (formatDict.contains(optionArg)) - setPixelFormat(formatDict.value(optionArg)); - else - printHelp(formatDict); - } else { - printHelp(formatDict); - } - } - - if (w == 0 || h == 0) { - w = 640; - h = 480; - qWarning("%s: Using default screen size %dx%d", PluginName, w, h); - } - dw = w; - dh = h; - - if (pixelFormat() == QImage::Format_Invalid) { - qWarning("%s: Using default screen format argb32", PluginName); - setPixelFormat(QImage::Format_ARGB32); - } - d = depthForFormat(pixelFormat()); - - static const int Dpi = 120; - static const qreal ScalingFactor = static_cast<qreal>(25.4) / Dpi; - physWidth = qRound(dw * ScalingFactor); - physHeight = qRound(dh * ScalingFactor); - - return true; -} - -void EGLNullWSScreen::disconnect() {} - -void EGLNullWSScreen::shutdownDevice() {} - -void EGLNullWSScreen::setMode(int /*width*/, int /*height*/, int /*depth*/) {} - -void EGLNullWSScreen::blank(bool /*on*/) {} - -void EGLNullWSScreen::exposeRegion(QRegion /*r*/, int /*changing*/) {} - -QWSWindowSurface* EGLNullWSScreen::createSurface(QWidget *widget) const -{ - if (qobject_cast<QGLWidget*>(widget)) { - return new EGLNullWSWindowSurface(widget); - } else { - qWarning("%s: Creating non-GL surface", PluginName); - return QScreen::createSurface(widget); - } -} - -QWSWindowSurface* EGLNullWSScreen::createSurface(const QString &key) const -{ - if (key == QLatin1String("eglnullws")) { - return new EGLNullWSWindowSurface; - } else { - qWarning("%s: Creating non-GL surface", PluginName); - return QScreen::createSurface(key); - } -} diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h deleted file mode 100644 index 8295e5daaa..0000000000 --- a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef EGLNULLWSSCREEN -#define EGLNULLWSSCREEN - -#include <QGLScreen> - -class EGLNullWSScreen : public QGLScreen -{ -public: - EGLNullWSScreen(int displayId); - ~EGLNullWSScreen(); - - bool initDevice(); - bool connect(const QString &displaySpec); - void disconnect(); - void shutdownDevice(); - - void setMode(int width, int height, int depth); - void blank(bool on); - - void exposeRegion(QRegion r, int changing); - - QWSWindowSurface* createSurface(QWidget *widget) const; - QWSWindowSurface* createSurface(const QString &key) const; - - bool hasOpenGL() { return true; } -}; - -#endif // EGLNULLWSSCREEN diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp deleted file mode 100644 index ebae53d8c4..0000000000 --- a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "eglnullwsscreenplugin.h" -#include "eglnullwsscreen.h" - -#include <QScreenDriverPlugin> -#include <QStringList> - -class EGLNullWSScreenPlugin : public QScreenDriverPlugin -{ -public: - virtual QStringList keys() const; - virtual QScreen *create(const QString& driver, int displayId); -}; - -QStringList EGLNullWSScreenPlugin::keys() const -{ - return QStringList() << QLatin1String(PluginName); -} - -QScreen *EGLNullWSScreenPlugin::create(const QString& driver, int displayId) -{ - return (driver.toLower() == QLatin1String(PluginName) ? - new EGLNullWSScreen(displayId) : 0); -} - -Q_EXPORT_PLUGIN2(qeglnullws, EGLNullWSScreenPlugin) diff --git a/src/plugins/gfxdrivers/gfxdrivers.pro b/src/plugins/gfxdrivers/gfxdrivers.pro deleted file mode 100644 index 1f38942a50..0000000000 --- a/src/plugins/gfxdrivers/gfxdrivers.pro +++ /dev/null @@ -1,10 +0,0 @@ -TEMPLATE = subdirs -contains(gfx-plugins, ahi) :SUBDIRS += ahi -contains(gfx-plugins, directfb) :SUBDIRS += directfb -contains(gfx-plugins, linuxfb) :SUBDIRS += linuxfb -contains(gfx-plugins, qvfb) :SUBDIRS += qvfb -contains(gfx-plugins, vnc) :SUBDIRS += vnc -contains(gfx-plugins, transformed) :SUBDIRS += transformed -contains(gfx-plugins, svgalib) :SUBDIRS += svgalib -contains(gfx-plugins, powervr) :SUBDIRS += powervr -contains(gfx-plugins, eglnullws) :SUBDIRS += eglnullws diff --git a/src/plugins/gfxdrivers/linuxfb/linuxfb.pro b/src/plugins/gfxdrivers/linuxfb/linuxfb.pro deleted file mode 100644 index 2bbe910e63..0000000000 --- a/src/plugins/gfxdrivers/linuxfb/linuxfb.pro +++ /dev/null @@ -1,14 +0,0 @@ -TARGET = qscreenlinuxfb -load(qt_plugin) - -DESTDIR = $$QT.gui.plugins/gfxdrivers - -target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers -INSTALLS += target - -DEFINES += QT_QWS_LINUXFB - -HEADERS = $$QT_SOURCE_TREE/src/gui/embedded/qscreenlinuxfb_qws.h - -SOURCES = main.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qscreenlinuxfb_qws.cpp diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro b/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro deleted file mode 100644 index 595cf45301..0000000000 --- a/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro +++ /dev/null @@ -1,26 +0,0 @@ -TEMPLATE = lib -TARGET = pvrQWSWSEGL -CONFIG += dll warn_on -CONFIG -= qt - -HEADERS+=\ - pvrqwsdrawable.h \ - pvrqwsdrawable_p.h - -SOURCES+=\ - pvrqwsdrawable.c \ - pvrqwswsegl.c - -INCLUDEPATH += $$QMAKE_INCDIR_EGL - -for(p, QMAKE_LIBDIR_EGL) { - exists($$p):LIBS += -L$$p -} - -LIBS += -lpvr2d - -DESTDIR = $$QMAKE_LIBDIR_QT -target.path = $$[QT_INSTALL_LIBS] -INSTALLS += target - -include(../powervr.pri)
\ No newline at end of file diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c deleted file mode 100644 index c453279155..0000000000 --- a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c +++ /dev/null @@ -1,830 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "pvrqwsdrawable_p.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/ioctl.h> -#include <linux/fb.h> -#include <fcntl.h> -#include <unistd.h> - -PvrQwsDisplay pvrQwsDisplay; - -static void pvrQwsDestroyDrawableForced(PvrQwsDrawable *drawable); - -/* Initialize the /dev/fbN device for a specific screen */ -static int pvrQwsInitFbScreen(int screen) -{ - struct fb_var_screeninfo var; - struct fb_fix_screeninfo fix; - unsigned long start; - unsigned long length; - int width, height, stride; - PVR2DFORMAT format; - void *mapped; - int fd, bytesPerPixel; - char name[64]; - PVR2DMEMINFO *memInfo; - unsigned long pageAddresses[2]; - - /* Bail out if already initialized, or the number is incorrect */ - if (screen < 0 || screen >= PVRQWS_MAX_SCREENS) - return 0; - if (pvrQwsDisplay.screens[screen].initialized) - return 1; - - /* Open the framebuffer and fetch its properties */ - sprintf(name, "/dev/fb%d", screen); - fd = open(name, O_RDWR, 0); - if (fd < 0) { - perror(name); - return 0; - } - if (ioctl(fd, FBIOGET_VSCREENINFO, &var) < 0) { - perror("FBIOGET_VSCREENINFO"); - close(fd); - return 0; - } - if (ioctl(fd, FBIOGET_FSCREENINFO, &fix) < 0) { - perror("FBIOGET_FSCREENINFO"); - close(fd); - return 0; - } - width = var.xres; - height = var.yres; - bytesPerPixel = var.bits_per_pixel / 8; - stride = fix.line_length; - format = PVR2D_1BPP; - if (var.bits_per_pixel == 16) { - if (var.red.length == 5 && var.green.length == 6 && - var.blue.length == 5 && var.red.offset == 11 && - var.green.offset == 5 && var.blue.offset == 0) { - format = PVR2D_RGB565; - } - if (var.red.length == 4 && var.green.length == 4 && - var.blue.length == 4 && var.transp.length == 4 && - var.red.offset == 8 && var.green.offset == 4 && - var.blue.offset == 0 && var.transp.offset == 12) { - format = PVR2D_ARGB4444; - } - } else if (var.bits_per_pixel == 32) { - if (var.red.length == 8 && var.green.length == 8 && - var.blue.length == 8 && var.transp.length == 8 && - var.red.offset == 16 && var.green.offset == 8 && - var.blue.offset == 0 && var.transp.offset == 24) { - format = PVR2D_ARGB8888; - } - } - if (format == PVR2D_1BPP) { - fprintf(stderr, "%s: could not find a suitable PVR2D pixel format\n", name); - close(fd); - return 0; - } - start = fix.smem_start; - length = var.xres_virtual * var.yres_virtual * bytesPerPixel; - - if (screen == 0) { - /* We use PVR2DGetFrameBuffer to map the first screen. - On some chipsets it is more reliable than using PVR2DMemWrap */ - mapped = 0; - memInfo = 0; - } else { - /* Other screens: map the framebuffer region into memory */ - mapped = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (!mapped || mapped == (void *)(-1)) { - perror("mmap"); - close(fd); - return 0; - } - - /* Allocate a PVR2D memory region for the framebuffer */ - memInfo = 0; - if (pvrQwsDisplay.context) { - pageAddresses[0] = start & 0xFFFFF000; - pageAddresses[1] = 0; - if (PVR2DMemWrap - (pvrQwsDisplay.context, mapped, PVR2D_WRAPFLAG_CONTIGUOUS, - length, pageAddresses, &memInfo) != PVR2D_OK) { - munmap(mapped, length); - close(fd); - return 0; - } - } - } - - /* We don't need the file descriptor any more */ - close(fd); - - /* The framebuffer is ready, so initialize the PvrQwsScreenInfo */ - pvrQwsDisplay.screens[screen].screenRect.x = 0; - pvrQwsDisplay.screens[screen].screenRect.y = 0; - pvrQwsDisplay.screens[screen].screenRect.width = width; - pvrQwsDisplay.screens[screen].screenRect.height = height; - pvrQwsDisplay.screens[screen].screenStride = stride; - pvrQwsDisplay.screens[screen].pixelFormat = format; - pvrQwsDisplay.screens[screen].bytesPerPixel = bytesPerPixel; - pvrQwsDisplay.screens[screen].screenDrawable = 0; - if (mapped) { - /* Don't set these fields if mapped is 0, because PVR2DGetFrameBuffer - may have already been called and set them */ - pvrQwsDisplay.screens[screen].frameBuffer = memInfo; - pvrQwsDisplay.screens[screen].mapped = mapped; - } - pvrQwsDisplay.screens[screen].mappedLength = length; - pvrQwsDisplay.screens[screen].screenStart = start; - pvrQwsDisplay.screens[screen].needsUnmap = (mapped != 0); - pvrQwsDisplay.screens[screen].initialized = 1; - return 1; -} - -/* Called when a new drawable is added to ensure that we have a - PVR2D context and framebuffer PVR2DMEMINFO blocks */ -static int pvrQwsAddDrawable(void) -{ - int numDevs, screen; - PVR2DDEVICEINFO *devs; - unsigned long devId; - unsigned long pageAddresses[2]; - PVR2DMEMINFO *memInfo; - PVR2DDISPLAYINFO displayInfo; - - /* Bail out early if this is not the first drawable */ - if (pvrQwsDisplay.numDrawables > 0) { - ++(pvrQwsDisplay.numDrawables); - return 1; - } - - /* Find the first PVR2D device in the system and open it */ - numDevs = PVR2DEnumerateDevices(0); - if (numDevs <= 0) - return 0; - devs = (PVR2DDEVICEINFO *)malloc(sizeof(PVR2DDEVICEINFO) * numDevs); - if (!devs) - return 0; - if (PVR2DEnumerateDevices(devs) != PVR2D_OK) { - free(devs); - return 0; - } - devId = devs[0].ulDevID; - free(devs); - if (PVR2DCreateDeviceContext(devId, &pvrQwsDisplay.context, 0) != PVR2D_OK) - return 0; - pvrQwsDisplay.numFlipBuffers = 0; - pvrQwsDisplay.flipChain = 0; - if (PVR2DGetDeviceInfo(pvrQwsDisplay.context, &displayInfo) == PVR2D_OK) { - if (displayInfo.ulMaxFlipChains > 0 && displayInfo.ulMaxBuffersInChain > 0) - pvrQwsDisplay.numFlipBuffers = displayInfo.ulMaxBuffersInChain; - if (pvrQwsDisplay.numFlipBuffers > PVRQWS_MAX_FLIP_BUFFERS) - pvrQwsDisplay.numFlipBuffers = PVRQWS_MAX_FLIP_BUFFERS; - } - - /* Create the PVR2DMEMINFO blocks for the active framebuffers */ - for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) { - if (screen != 0 && pvrQwsDisplay.screens[screen].mapped) { - pageAddresses[0] - = pvrQwsDisplay.screens[screen].screenStart & 0xFFFFF000; - pageAddresses[1] = 0; - if (PVR2DMemWrap - (pvrQwsDisplay.context, - pvrQwsDisplay.screens[screen].mapped, - PVR2D_WRAPFLAG_CONTIGUOUS, - pvrQwsDisplay.screens[screen].mappedLength, - pageAddresses, &memInfo) != PVR2D_OK) { - PVR2DDestroyDeviceContext(pvrQwsDisplay.context); - pvrQwsDisplay.context = 0; - return 0; - } - pvrQwsDisplay.screens[screen].frameBuffer = memInfo; - } else if (screen == 0) { - if (PVR2DGetFrameBuffer - (pvrQwsDisplay.context, - PVR2D_FB_PRIMARY_SURFACE, &memInfo) != PVR2D_OK) { - fprintf(stderr, "QWSWSEGL: could not get the primary framebuffer surface\n"); - PVR2DDestroyDeviceContext(pvrQwsDisplay.context); - pvrQwsDisplay.context = 0; - return 0; - } - pvrQwsDisplay.screens[screen].frameBuffer = memInfo; - pvrQwsDisplay.screens[screen].mapped = memInfo->pBase; - } - } - - /* Create a flip chain for the screen if supported by the hardware */ - pvrQwsDisplay.usePresentBlit = 0; - if (pvrQwsDisplay.numFlipBuffers > 0) { - long stride = 0; - unsigned long flipId = 0; - unsigned long numBuffers; - if (PVR2DCreateFlipChain(pvrQwsDisplay.context, 0, - //PVR2D_CREATE_FLIPCHAIN_SHARED | - //PVR2D_CREATE_FLIPCHAIN_QUERY, - pvrQwsDisplay.numFlipBuffers, - pvrQwsDisplay.screens[0].screenRect.width, - pvrQwsDisplay.screens[0].screenRect.height, - pvrQwsDisplay.screens[0].pixelFormat, - &stride, &flipId, &(pvrQwsDisplay.flipChain)) - == PVR2D_OK) { - pvrQwsDisplay.screens[0].screenStride = stride; - PVR2DGetFlipChainBuffers(pvrQwsDisplay.context, - pvrQwsDisplay.flipChain, - &numBuffers, - pvrQwsDisplay.flipBuffers); - } else { - pvrQwsDisplay.flipChain = 0; - pvrQwsDisplay.numFlipBuffers = 0; - } - - /* PVR2DPresentBlt is a little more reliable than PVR2DBlt - when flip chains are present, even if we cannot create a - flip chain at the moment */ - pvrQwsDisplay.usePresentBlit = 1; - } - - /* The context is ready to go */ - ++(pvrQwsDisplay.numDrawables); - return 1; -} - -/* Called when the last drawable is destroyed. The PVR2D context - will be destroyed but the raw framebuffer memory will stay mapped */ -static void pvrQwsDestroyContext(void) -{ - int screen; - for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) { - if (pvrQwsDisplay.screens[screen].frameBuffer) { - PVR2DMemFree - (pvrQwsDisplay.context, - pvrQwsDisplay.screens[screen].frameBuffer); - pvrQwsDisplay.screens[screen].frameBuffer = 0; - } - } - - if (pvrQwsDisplay.numFlipBuffers > 0) - PVR2DDestroyFlipChain(pvrQwsDisplay.context, pvrQwsDisplay.flipChain); - PVR2DDestroyDeviceContext(pvrQwsDisplay.context); - pvrQwsDisplay.context = 0; - pvrQwsDisplay.flipChain = 0; - pvrQwsDisplay.numFlipBuffers = 0; - pvrQwsDisplay.usePresentBlit = 0; -} - -int pvrQwsDisplayOpen(void) -{ - int screen; - - /* If the display is already open, increase reference count and return */ - if (pvrQwsDisplay.refCount > 0) { - ++(pvrQwsDisplay.refCount); - return 1; - } - - /* Open the framebuffer and map it directly */ - if (!pvrQwsInitFbScreen(0)) { - --(pvrQwsDisplay.refCount); - return 0; - } - - /* Clear the other screens. We will create them if they are referenced */ - for (screen = 1; screen < PVRQWS_MAX_SCREENS; ++screen) - memset(&(pvrQwsDisplay.screens[screen]), 0, sizeof(PvrQwsScreenInfo)); - - /* The display is open and ready */ - ++(pvrQwsDisplay.refCount); - return 1; -} - -void pvrQwsDisplayClose(void) -{ - int screen; - - if (pvrQwsDisplay.refCount == 0) - return; - if (--(pvrQwsDisplay.refCount) > 0) - return; - - /* Prevent pvrQwsDestroyContext from being called for the time being */ - ++pvrQwsDisplay.numDrawables; - - /* Free the screens */ - for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) { - PvrQwsScreenInfo *info = &(pvrQwsDisplay.screens[screen]); - if (info->screenDrawable) - pvrQwsDestroyDrawableForced(info->screenDrawable); - if (info->frameBuffer) - PVR2DMemFree(pvrQwsDisplay.context, info->frameBuffer); - if (info->mapped && info->needsUnmap) - munmap(info->mapped, info->mappedLength); - } - - /* Now it is safe to destroy the PVR2D context */ - --pvrQwsDisplay.numDrawables; - if (pvrQwsDisplay.context) - PVR2DDestroyDeviceContext(pvrQwsDisplay.context); - - memset(&pvrQwsDisplay, 0, sizeof(pvrQwsDisplay)); -} - -int pvrQwsDisplayIsOpen(void) -{ - return (pvrQwsDisplay.refCount > 0); -} - -/* Ensure that a specific screen has been initialized */ -static int pvrQwsEnsureScreen(int screen) -{ - if (screen < 0 || screen >= PVRQWS_MAX_SCREENS) - return 0; - if (!screen) - return 1; - return pvrQwsInitFbScreen(screen); -} - -PvrQwsDrawable *pvrQwsScreenWindow(int screen) -{ - PvrQwsDrawable *drawable; - - if (!pvrQwsEnsureScreen(screen)) - return 0; - - drawable = pvrQwsDisplay.screens[screen].screenDrawable; - if (drawable) - return drawable; - - drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable)); - if (!drawable) - return 0; - - drawable->type = PvrQwsScreen; - drawable->screen = screen; - drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat; - drawable->rect = pvrQwsDisplay.screens[screen].screenRect; - drawable->visibleRects[0] = drawable->rect; - drawable->numVisibleRects = 1; - drawable->isFullScreen = 1; - - if (!pvrQwsAddDrawable()) { - free(drawable); - return 0; - } - - pvrQwsDisplay.screens[screen].screenDrawable = drawable; - - return drawable; -} - -PvrQwsDrawable *pvrQwsCreateWindow(int screen, long winId, const PvrQwsRect *rect) -{ - PvrQwsDrawable *drawable; - - if (!pvrQwsEnsureScreen(screen)) - return 0; - - drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable)); - if (!drawable) - return 0; - - drawable->type = PvrQwsWindow; - drawable->winId = winId; - drawable->refCount = 1; - drawable->screen = screen; - drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat; - drawable->rect = *rect; - - if (!pvrQwsAddDrawable()) { - free(drawable); - return 0; - } - - drawable->nextWinId = pvrQwsDisplay.firstWinId; - pvrQwsDisplay.firstWinId = drawable; - - return drawable; -} - -PvrQwsDrawable *pvrQwsFetchWindow(long winId) -{ - PvrQwsDrawable *drawable = pvrQwsDisplay.firstWinId; - while (drawable != 0 && drawable->winId != winId) - drawable = drawable->nextWinId; - - if (drawable) - ++(drawable->refCount); - return drawable; -} - -int pvrQwsReleaseWindow(PvrQwsDrawable *drawable) -{ - if (drawable->type == PvrQwsWindow) - return (--(drawable->refCount) <= 0); - else - return 0; -} - -PvrQwsDrawable *pvrQwsCreatePixmap(int width, int height, int screen) -{ - PvrQwsDrawable *drawable; - - if (!pvrQwsEnsureScreen(screen)) - return 0; - - drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable)); - if (!drawable) - return 0; - - drawable->type = PvrQwsPixmap; - drawable->screen = screen; - drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat; - drawable->rect.x = 0; - drawable->rect.y = 0; - drawable->rect.width = width; - drawable->rect.height = height; - - if (!pvrQwsAddDrawable()) { - free(drawable); - return 0; - } - - return drawable; -} - -static void pvrQwsDestroyDrawableForced(PvrQwsDrawable *drawable) -{ - /* Remove the drawable from the display's winId list */ - PvrQwsDrawable *current = pvrQwsDisplay.firstWinId; - PvrQwsDrawable *prev = 0; - while (current != 0 && current != drawable) { - prev = current; - current = current->nextWinId; - } - if (current != 0) { - if (prev) - prev->nextWinId = current->nextWinId; - else - pvrQwsDisplay.firstWinId = current->nextWinId; - } - - pvrQwsFreeBuffers(drawable); - free(drawable); - - --pvrQwsDisplay.numDrawables; - if (pvrQwsDisplay.numDrawables == 0) - pvrQwsDestroyContext(); -} - -void pvrQwsDestroyDrawable(PvrQwsDrawable *drawable) -{ - if (drawable && drawable->type != PvrQwsScreen) - pvrQwsDestroyDrawableForced(drawable); -} - -PvrQwsDrawableType pvrQwsGetDrawableType(PvrQwsDrawable *drawable) -{ - return drawable->type; -} - -void pvrQwsSetVisibleRegion - (PvrQwsDrawable *drawable, const PvrQwsRect *rects, int numRects) -{ - int index, indexOut; - PvrQwsRect *rect; - PvrQwsRect *screenRect; - - /* Visible regions don't make sense for pixmaps */ - if (drawable->type == PvrQwsPixmap) - return; - - /* Restrict the number of rectangles to prevent buffer overflow */ - if (numRects > PVRQWS_MAX_VISIBLE_RECTS) - numRects = PVRQWS_MAX_VISIBLE_RECTS; - if (numRects > 0) - memcpy(drawable->visibleRects, rects, numRects * sizeof(PvrQwsRect)); - - /* Convert the rectangles into screen-relative co-ordinates and - then clamp them to the screen boundaries. If any of the - clamped rectangles are empty, remove them from the list */ - screenRect = &(pvrQwsDisplay.screens[drawable->screen].screenRect); - indexOut = 0; - for (index = 0, rect = drawable->visibleRects; index < numRects; ++index, ++rect) { - if (rect->x < 0) { - rect->width += rect->x; - rect->x = 0; - if (rect->width < 0) - rect->width = 0; - } else if (rect->x >= screenRect->width) { - rect->x = screenRect->width; - rect->width = 0; - } - if ((rect->x + rect->width) > screenRect->width) { - rect->width = screenRect->width - rect->x; - } - if (rect->y < 0) { - rect->height += rect->y; - rect->y = 0; - if (rect->height < 0) - rect->height = 0; - } else if (rect->y >= screenRect->height) { - rect->y = screenRect->height; - rect->height = 0; - } - if ((rect->y + rect->height) > screenRect->height) { - rect->height = screenRect->height - rect->y; - } - if (rect->width > 0 && rect->height > 0) { - if (index != indexOut) - drawable->visibleRects[indexOut] = *rect; - ++indexOut; - } - } - drawable->numVisibleRects = indexOut; -} - -void pvrQwsClearVisibleRegion(PvrQwsDrawable *drawable) -{ - if (drawable->type != PvrQwsPixmap) - drawable->numVisibleRects = 0; -} - -void pvrQwsSetGeometry(PvrQwsDrawable *drawable, const PvrQwsRect *rect) -{ - /* We can only change the geometry of window drawables */ - if (drawable->type != PvrQwsWindow) - return; - - /* If the position has changed, then clear the visible region */ - if (drawable->rect.x != rect->x || drawable->rect.y != rect->y) { - drawable->rect.x = rect->x; - drawable->rect.y = rect->y; - drawable->numVisibleRects = 0; - } - - /* If the size has changed, then clear the visible region and - invalidate the drawable's buffers. Invalidating the buffers - will force EGL to recreate the drawable, which will then - allocate new buffers for the new size */ - if (drawable->rect.width != rect->width || - drawable->rect.height != rect->height) { - drawable->rect.width = rect->width; - drawable->rect.height = rect->height; - drawable->numVisibleRects = 0; - pvrQwsInvalidateBuffers(drawable); - } -} - -void pvrQwsGetGeometry(PvrQwsDrawable *drawable, PvrQwsRect *rect) -{ - *rect = drawable->rect; -} - -void pvrQwsSetRotation(PvrQwsDrawable *drawable, int angle) -{ - if (drawable->rotationAngle != angle) { - drawable->rotationAngle = angle; - - /* Force the buffers to be recreated if the rotation angle changes */ - pvrQwsInvalidateBuffers(drawable); - } -} - -int pvrQwsGetStride(PvrQwsDrawable *drawable) -{ - if (drawable->backBuffersValid) - return drawable->strideBytes; - else - return 0; -} - -PvrQwsPixelFormat pvrQwsGetPixelFormat(PvrQwsDrawable *drawable) -{ - return (PvrQwsPixelFormat)(drawable->pixelFormat); -} - -void *pvrQwsGetRenderBuffer(PvrQwsDrawable *drawable) -{ - if (drawable->backBuffersValid) - return drawable->backBuffers[drawable->currentBackBuffer]->pBase; - else - return 0; -} - -int pvrQwsAllocBuffers(PvrQwsDrawable *drawable) -{ - int index; - int numBuffers = PVRQWS_MAX_BACK_BUFFERS; - if (drawable->type == PvrQwsPixmap) - numBuffers = 1; - if (drawable->backBuffers[0]) { - if (drawable->backBuffersValid) - return 1; - if (!drawable->usingFlipBuffers) { - for (index = 0; index < numBuffers; ++index) - PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]); - } - } - drawable->stridePixels = (drawable->rect.width + 31) & ~31; - drawable->strideBytes = - drawable->stridePixels * - pvrQwsDisplay.screens[drawable->screen].bytesPerPixel; - drawable->usingFlipBuffers = - (pvrQwsDisplay.numFlipBuffers > 0 && drawable->isFullScreen); - if (drawable->usingFlipBuffers) { - if (numBuffers > (int)(pvrQwsDisplay.numFlipBuffers)) - numBuffers = pvrQwsDisplay.numFlipBuffers; - for (index = 0; index < numBuffers; ++index) - drawable->backBuffers[index] = pvrQwsDisplay.flipBuffers[index]; - } else { - for (index = 0; index < numBuffers; ++index) { - if (PVR2DMemAlloc(pvrQwsDisplay.context, - drawable->strideBytes * drawable->rect.height, - 128, 0, - &(drawable->backBuffers[index])) != PVR2D_OK) { - while (--index >= 0) - PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]); - memset(drawable->backBuffers, 0, sizeof(drawable->backBuffers)); - drawable->backBuffersValid = 0; - return 0; - } - } - } - for (index = numBuffers; index < PVRQWS_MAX_BACK_BUFFERS; ++index) { - drawable->backBuffers[index] = drawable->backBuffers[0]; - } - drawable->backBuffersValid = 1; - drawable->currentBackBuffer = 0; - return 1; -} - -void pvrQwsFreeBuffers(PvrQwsDrawable *drawable) -{ - int index; - int numBuffers = PVRQWS_MAX_BACK_BUFFERS; - if (drawable->type == PvrQwsPixmap) - numBuffers = 1; - if (!drawable->usingFlipBuffers) { - for (index = 0; index < numBuffers; ++index) { - if (drawable->backBuffers[index]) - PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]); - } - } - memset(drawable->backBuffers, 0, sizeof(drawable->backBuffers)); - drawable->backBuffersValid = 0; - drawable->usingFlipBuffers = 0; -} - -void pvrQwsInvalidateBuffers(PvrQwsDrawable *drawable) -{ - drawable->backBuffersValid = 0; -} - -int pvrQwsGetBuffers - (PvrQwsDrawable *drawable, PVR2DMEMINFO **source, PVR2DMEMINFO **render) -{ - if (!drawable->backBuffersValid) - return 0; - *render = drawable->backBuffers[drawable->currentBackBuffer]; - *source = drawable->backBuffers - [(drawable->currentBackBuffer + PVRQWS_MAX_BACK_BUFFERS - 1) % - PVRQWS_MAX_BACK_BUFFERS]; - return 1; -} - -int pvrQwsSwapBuffers(PvrQwsDrawable *drawable, int repaintOnly) -{ - PVR2DMEMINFO *buffer; - PvrQwsRect *rect; - int index; - - /* Bail out if the back buffers have been invalidated */ - if (!drawable->backBuffersValid) - return 0; - - /* If there is a swap function, then use that instead */ - if (drawable->swapFunction) { - (*(drawable->swapFunction))(drawable, drawable->userData, repaintOnly); - if (!repaintOnly) { - drawable->currentBackBuffer - = (drawable->currentBackBuffer + 1) % PVRQWS_MAX_BACK_BUFFERS; - } - return 1; - } - - /* Iterate through the visible rectangles and blit them to the screen */ - if (!repaintOnly) { - index = drawable->currentBackBuffer; - } else { - index = (drawable->currentBackBuffer + PVRQWS_MAX_BACK_BUFFERS - 1) - % PVRQWS_MAX_BACK_BUFFERS; - } - buffer = drawable->backBuffers[index]; - rect = drawable->visibleRects; - if (drawable->usingFlipBuffers) { - PVR2DPresentFlip(pvrQwsDisplay.context, pvrQwsDisplay.flipChain, buffer, 0); - } else if (pvrQwsDisplay.usePresentBlit && drawable->numVisibleRects > 0) { - PVR2DRECT pvrRects[PVRQWS_MAX_VISIBLE_RECTS]; - for (index = 0; index < drawable->numVisibleRects; ++index, ++rect) { - pvrRects[index].left = rect->x; - pvrRects[index].top = rect->y; - pvrRects[index].right = rect->x + rect->width; - pvrRects[index].bottom = rect->y + rect->height; - } - for (index = 0; index < drawable->numVisibleRects; index += 4) { - int numClip = drawable->numVisibleRects - index; - if (numClip > 4) /* No more than 4 clip rects at a time */ - numClip = 4; - PVR2DSetPresentBltProperties - (pvrQwsDisplay.context, - PVR2D_PRESENT_PROPERTY_SRCSTRIDE | - PVR2D_PRESENT_PROPERTY_DSTSIZE | - PVR2D_PRESENT_PROPERTY_DSTPOS | - PVR2D_PRESENT_PROPERTY_CLIPRECTS, - drawable->strideBytes, - drawable->rect.width, drawable->rect.height, - drawable->rect.x, drawable->rect.y, - numClip, pvrRects + index, 0); - PVR2DPresentBlt(pvrQwsDisplay.context, buffer, 0); - } - PVR2DQueryBlitsComplete(pvrQwsDisplay.context, buffer, 1); - } else { - /* TODO: use PVR2DBltClipped for faster transfers of clipped windows */ - PVR2DBLTINFO blit; - for (index = 0; index < drawable->numVisibleRects; ++index, ++rect) { - memset(&blit, 0, sizeof(blit)); - - blit.CopyCode = PVR2DROPcopy; - blit.BlitFlags = PVR2D_BLIT_DISABLE_ALL; - - blit.pSrcMemInfo = buffer; - blit.SrcStride = drawable->strideBytes; - blit.SrcX = rect->x - drawable->rect.x; - blit.SrcY = rect->y - drawable->rect.y; - blit.SizeX = rect->width; - blit.SizeY = rect->height; - blit.SrcFormat = drawable->pixelFormat; - - blit.pDstMemInfo = pvrQwsDisplay.screens[drawable->screen].frameBuffer; - blit.DstStride = pvrQwsDisplay.screens[drawable->screen].screenStride; - blit.DstX = rect->x; - blit.DstY = rect->y; - blit.DSizeX = rect->width; - blit.DSizeY = rect->height; - blit.DstFormat = pvrQwsDisplay.screens[drawable->screen].pixelFormat; - - PVR2DBlt(pvrQwsDisplay.context, &blit); - } - } - - /* Swap the buffers */ - if (!repaintOnly) { - drawable->currentBackBuffer - = (drawable->currentBackBuffer + 1) % PVRQWS_MAX_BACK_BUFFERS; - } - return 1; -} - -void pvrQwsSetSwapFunction - (PvrQwsDrawable *drawable, PvrQwsSwapFunction func, void *userData) -{ - drawable->swapFunction = func; - drawable->userData = userData; -} diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h deleted file mode 100644 index 40119b0a41..0000000000 --- a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h +++ /dev/null @@ -1,169 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef PVRQWSDRAWABLE_H -#define PVRQWSDRAWABLE_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - int x, y, width, height; -} PvrQwsRect; - -typedef enum -{ - PvrQwsScreen, - PvrQwsWindow, - PvrQwsPixmap - -} PvrQwsDrawableType; - -typedef enum -{ - PvrQws_1BPP = 0, - PvrQws_RGB565, - PvrQws_ARGB4444, - PvrQws_RGB888, - PvrQws_ARGB8888, - PvrQws_VGAEMU - -} PvrQwsPixelFormat; - -typedef struct _PvrQwsDrawable PvrQwsDrawable; - -typedef void (*PvrQwsSwapFunction) - (PvrQwsDrawable *drawable, void *userData, int repaintOnly); - -/* Open the display and prepare for window operations. The display - can be opened multiple times and each time is reference counted. - The display will be finally closed when the same number of - calls to pvrQwsDisplayClose() have been encountered */ -int pvrQwsDisplayOpen(void); - -/* Close the display */ -void pvrQwsDisplayClose(void); - -/* Determine if the display is already open */ -int pvrQwsDisplayIsOpen(void); - -/* Create a window that represents a particular framebuffer screen. - Initially the visible region will be the whole screen. If the screen - window has already been created, then will return the same value */ -PvrQwsDrawable *pvrQwsScreenWindow(int screen); - -/* Create a top-level window on a particular framebuffer screen. - Initially the window will not have a visible region */ -PvrQwsDrawable *pvrQwsCreateWindow(int screen, long winId, const PvrQwsRect *rect); - -/* Fetch an existing window for a window id and increase its refcount */ -PvrQwsDrawable *pvrQwsFetchWindow(long winId); - -/* Release the refcount on a window. Returns 1 if refcount is zero */ -int pvrQwsReleaseWindow(PvrQwsDrawable *drawable); - -/* Create an off-screen pixmap */ -PvrQwsDrawable *pvrQwsCreatePixmap(int width, int height, int screen); - -/* Destroy a previously-created drawable. Will not destroy screens. */ -void pvrQwsDestroyDrawable(PvrQwsDrawable *drawable); - -/* Get a drawable's type */ -PvrQwsDrawableType pvrQwsGetDrawableType(PvrQwsDrawable *drawable); - -/* Sets the visible region for a window or screen drawable. Pixels within - the specified rectangles will be copied to the framebuffer when the window - or screen is swapped. The rectangles should be in global co-ordinates */ -void pvrQwsSetVisibleRegion - (PvrQwsDrawable *drawable, const PvrQwsRect *rects, int numRects); - -/* Clear the visible region for a window or screen drawable, - effectively removing it from the screen */ -void pvrQwsClearVisibleRegion(PvrQwsDrawable *drawable); - -/* Set the geometry for a drawable. This can only be used on windows */ -void pvrQwsSetGeometry(PvrQwsDrawable *drawable, const PvrQwsRect *rect); - -/* Get the current geometry for a drawable */ -void pvrQwsGetGeometry(PvrQwsDrawable *drawable, PvrQwsRect *rect); - -/* Set the rotation angle in degrees */ -void pvrQwsSetRotation(PvrQwsDrawable *drawable, int angle); - -/* Get the line stride for a drawable. Returns zero if the buffers - are not allocated or have been invalidated */ -int pvrQwsGetStride(PvrQwsDrawable *drawable); - -/* Get the pixel format for a drawable */ -PvrQwsPixelFormat pvrQwsGetPixelFormat(PvrQwsDrawable *drawable); - -/* Get a pointer to the beginning of a drawable's current render buffer. - Returns null if the buffers are not allocated or have been invalidated */ -void *pvrQwsGetRenderBuffer(PvrQwsDrawable *drawable); - -/* Allocate the buffers associated with a drawable. We allocate one buffer - for pixmaps, and several for windows and screens */ -int pvrQwsAllocBuffers(PvrQwsDrawable *drawable); - -/* Free the buffers associated with a drawable */ -void pvrQwsFreeBuffers(PvrQwsDrawable *drawable); - -/* Invalidate the buffers associated with a drawable. The buffers will - still be allocated but the next attempt to swap the buffers will fail */ -void pvrQwsInvalidateBuffers(PvrQwsDrawable *drawable); - -/* Swap the back buffers for a window or screen and copy to the framebuffer */ -int pvrQwsSwapBuffers(PvrQwsDrawable *drawable, int repaintOnly); - -/* Set the swap function for a drawable. When pvrQwsSwapBuffers() - is called on the drawable, the supplied function will be called - instead of copying the drawable contents to the screen. This allows - higher-level compositors to know when a drawable has changed. - The swap function can be set to null to return to normal processing */ -void pvrQwsSetSwapFunction - (PvrQwsDrawable *drawable, PvrQwsSwapFunction func, void *userData); - -#ifdef __cplusplus -}; -#endif - -#endif diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h deleted file mode 100644 index b20dc023d6..0000000000 --- a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h +++ /dev/null @@ -1,132 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef PVRQWSDRAWABLE_P_H -#define PVRQWSDRAWABLE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// reasons. This header file may change from version to version -// without notice, or even be removed. -// -// We mean it. -// - -#include <pvr2d.h> -#include "pvrqwsdrawable.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define PVRQWS_MAX_VISIBLE_RECTS 32 -#define PVRQWS_MAX_SCREENS 1 -#define PVRQWS_MAX_BACK_BUFFERS 2 -#define PVRQWS_MAX_FLIP_BUFFERS 2 - -typedef struct { - - PvrQwsRect screenRect; - int screenStride; - PVR2DFORMAT pixelFormat; - int bytesPerPixel; - PVR2DMEMINFO *frameBuffer; - PvrQwsDrawable *screenDrawable; - void *mapped; - int mappedLength; - unsigned long screenStart; - int needsUnmap; - int initialized; - -} PvrQwsScreenInfo; - -typedef struct { - - int refCount; - PvrQwsScreenInfo screens[PVRQWS_MAX_SCREENS]; - PVR2DCONTEXTHANDLE context; - int numDrawables; - unsigned long numFlipBuffers; - PVR2DFLIPCHAINHANDLE flipChain; - PVR2DMEMINFO *flipBuffers[PVRQWS_MAX_FLIP_BUFFERS]; - int usePresentBlit; - PvrQwsDrawable *firstWinId; - -} PvrQwsDisplay; - -extern PvrQwsDisplay pvrQwsDisplay; - -struct _PvrQwsDrawable -{ - PvrQwsDrawableType type; - long winId; - int refCount; - PvrQwsRect rect; - int screen; - PVR2DFORMAT pixelFormat; - PvrQwsRect visibleRects[PVRQWS_MAX_VISIBLE_RECTS]; - int numVisibleRects; - PVR2DMEMINFO *backBuffers[PVRQWS_MAX_BACK_BUFFERS]; - int currentBackBuffer; - int backBuffersValid; - int usingFlipBuffers; - int isFullScreen; - int strideBytes; - int stridePixels; - int rotationAngle; - PvrQwsSwapFunction swapFunction; - void *userData; - PvrQwsDrawable *nextWinId; - -}; - -/* Get the current source and render buffers for a drawable */ -int pvrQwsGetBuffers - (PvrQwsDrawable *drawable, PVR2DMEMINFO **source, PVR2DMEMINFO **render); - -#ifdef __cplusplus -}; -#endif - -#endif diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c deleted file mode 100644 index ce99e607f2..0000000000 --- a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c +++ /dev/null @@ -1,402 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <GLES/eglplatform.h> -#include <wsegl.h> -#include <pvr2d.h> -#include <string.h> -#include <sys/mman.h> -#include "pvrqwsdrawable_p.h" - -#define WSEGL_UNUSED(x) (void)x; - -// If the PVR2D version is not specified, then assume MBX-style headers. -// If the version is defined, then we assume that we have SGX-style headers. -#if !defined(PVR2D_REV_MAJOR) -#define WSEGL_CAP_WINDOWS_USE_HW_SYNC WSEGL_CAP_WINDOWS_USE_MBX_SYNC -#define WSEGL_CAP_PIXMAPS_USE_HW_SYNC WSEGL_CAP_PIXMAPS_USE_MBX_SYNC -#endif - -/* Capability information for the display */ -static WSEGLCaps const wseglDisplayCaps[] = { - {WSEGL_CAP_WINDOWS_USE_HW_SYNC, 1}, - {WSEGL_CAP_PIXMAPS_USE_HW_SYNC, 1}, - {WSEGL_NO_CAPS, 0} -}; - -/* Configuration information for the display */ -static WSEGLConfig wseglDisplayConfigs[] = { - {WSEGL_DRAWABLE_WINDOW, WSEGL_PIXELFORMAT_565, WSEGL_FALSE, - 0, 0, 0, WSEGL_OPAQUE, 0}, - {WSEGL_DRAWABLE_PIXMAP, WSEGL_PIXELFORMAT_565, WSEGL_FALSE, - 0, 0, 0, WSEGL_OPAQUE, 0}, - {WSEGL_NO_DRAWABLE, 0, 0, 0, 0, 0, 0, 0} -}; - -/* Determine if nativeDisplay is a valid display handle */ -static WSEGLError wseglIsDisplayValid(NativeDisplayType nativeDisplay) -{ - /* We only have the default display in this system */ - if (nativeDisplay == WSEGL_DEFAULT_DISPLAY) - return WSEGL_SUCCESS; - else - return WSEGL_BAD_NATIVE_DISPLAY; -} - -/* Initialize a native display for use with WSEGL */ -static WSEGLError wseglInitializeDisplay - (NativeDisplayType nativeDisplay, WSEGLDisplayHandle *display, - const WSEGLCaps **caps, WSEGLConfig **configs) -{ - WSEGLPixelFormat pixelFormat; - - /* Bail out if the native display is incorrect */ - if (nativeDisplay != WSEGL_DEFAULT_DISPLAY) - return WSEGL_CANNOT_INITIALISE; - - /* Open the PVR/QWS display, which will initialize the framebuffer */ - if (!pvrQwsDisplayOpen()) - return WSEGL_CANNOT_INITIALISE; - - /* Convert the PVR2D pixel format into a WSEGL pixel format */ - switch (pvrQwsDisplay.screens[0].pixelFormat) { - case PVR2D_RGB565: - pixelFormat = WSEGL_PIXELFORMAT_565; - break; - - case PVR2D_ARGB4444: - pixelFormat = WSEGL_PIXELFORMAT_4444; - break; - - case PVR2D_ARGB8888: - pixelFormat = WSEGL_PIXELFORMAT_8888; - break; - - default: - pvrQwsDisplayClose(); - return WSEGL_CANNOT_INITIALISE; - } - wseglDisplayConfigs[0].ePixelFormat = pixelFormat; - wseglDisplayConfigs[1].ePixelFormat = pixelFormat; - - /* The display has been initialized */ - *display = (WSEGLDisplayHandle)&pvrQwsDisplay; - *caps = wseglDisplayCaps; - *configs = wseglDisplayConfigs; - return WSEGL_SUCCESS; -} - -/* Close the WSEGL display */ -static WSEGLError wseglCloseDisplay(WSEGLDisplayHandle display) -{ - if (display == (WSEGLDisplayHandle)&pvrQwsDisplay) - pvrQwsDisplayClose(); - return WSEGL_SUCCESS; -} - -static WSEGLRotationAngle wseglRotationValue(int degrees) -{ - switch (degrees) { - case 90: return WSEGL_ROTATE_90; - case 180: return WSEGL_ROTATE_180; - case 270: return WSEGL_ROTATE_270; - default: return WSEGL_ROTATE_0; - } -} - -/* Create the WSEGL drawable version of a native window */ -static WSEGLError wseglCreateWindowDrawable - (WSEGLDisplayHandle display, WSEGLConfig *config, - WSEGLDrawableHandle *drawable, NativeWindowType nativeWindow, - WSEGLRotationAngle *rotationAngle) -{ - PvrQwsDrawable *draw; - - WSEGL_UNUSED(display); - WSEGL_UNUSED(config); - - /* Check for special handles that indicate framebuffer screens */ - if (nativeWindow >= (NativeWindowType)0 && - nativeWindow < (NativeWindowType)PVRQWS_MAX_SCREENS) { - PvrQwsDrawable *screen = pvrQwsScreenWindow((int)nativeWindow); - if (!screen) - return WSEGL_OUT_OF_MEMORY; - *drawable = (WSEGLDrawableHandle)screen; - if (!pvrQwsAllocBuffers(screen)) - return WSEGL_OUT_OF_MEMORY; - *rotationAngle = wseglRotationValue(screen->rotationAngle); - return WSEGL_SUCCESS; - } - - /* The native window is the winId - fetch the underlying drawable */ - draw = pvrQwsFetchWindow((long)nativeWindow); - if (!draw) - return WSEGL_BAD_DRAWABLE; - - /* The drawable is ready to go */ - *drawable = (WSEGLDrawableHandle)draw; - *rotationAngle = wseglRotationValue(draw->rotationAngle); - if (!pvrQwsAllocBuffers(draw)) - return WSEGL_OUT_OF_MEMORY; - return WSEGL_SUCCESS; -} - -/* Create the WSEGL drawable version of a native pixmap */ -static WSEGLError wseglCreatePixmapDrawable - (WSEGLDisplayHandle display, WSEGLConfig *config, - WSEGLDrawableHandle *drawable, NativePixmapType nativePixmap, - WSEGLRotationAngle *rotationAngle) -{ - WSEGL_UNUSED(display); - WSEGL_UNUSED(config); - if (!nativePixmap) - return WSEGL_BAD_NATIVE_PIXMAP; - if (!pvrQwsAllocBuffers((PvrQwsDrawable *)nativePixmap)) - return WSEGL_OUT_OF_MEMORY; - *drawable = (WSEGLDrawableHandle)nativePixmap; - *rotationAngle = WSEGL_ROTATE_0; - return WSEGL_SUCCESS; -} - -/* Delete a specific drawable */ -static WSEGLError wseglDeleteDrawable(WSEGLDrawableHandle _drawable) -{ - PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable; - if (!drawable || drawable->type == PvrQwsScreen) - return WSEGL_SUCCESS; - if (pvrQwsDisplay.numFlipBuffers == 0) - pvrQwsFreeBuffers(drawable); - if (pvrQwsReleaseWindow(drawable)) - pvrQwsDestroyDrawable(drawable); - return WSEGL_SUCCESS; -} - -/* Swap the contents of a drawable to the screen */ -static WSEGLError wseglSwapDrawable - (WSEGLDrawableHandle _drawable, unsigned long data) -{ - WSEGL_UNUSED(data); - PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable; - if (drawable->type != PvrQwsPixmap && !pvrQwsSwapBuffers(drawable, 0)) - return WSEGL_BAD_DRAWABLE; - else - return WSEGL_SUCCESS; -} - -/* Set the swap interval of a window drawable */ -static WSEGLError wseglSwapControlInterval - (WSEGLDrawableHandle drawable, unsigned long interval) -{ - WSEGL_UNUSED(drawable); - if (pvrQwsDisplay.flipChain) { - PVR2DSetPresentFlipProperties - (pvrQwsDisplay.context, pvrQwsDisplay.flipChain, - PVR2D_PRESENT_PROPERTY_INTERVAL, 0, 0, 0, NULL, interval); - } - return WSEGL_SUCCESS; -} - -/* Flush native rendering requests on a drawable */ -static WSEGLError wseglWaitNative - (WSEGLDrawableHandle drawable, unsigned long engine) -{ - WSEGL_UNUSED(drawable); - if (engine == WSEGL_DEFAULT_NATIVE_ENGINE) - return WSEGL_SUCCESS; - else - return WSEGL_BAD_NATIVE_ENGINE; -} - -/* Copy color data from a drawable to a native pixmap */ -static WSEGLError wseglCopyFromDrawable - (WSEGLDrawableHandle _drawable, NativePixmapType nativePixmap) -{ - PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable; - PvrQwsDrawable *pixmap = (PvrQwsDrawable *)nativePixmap; - PVR2DBLTINFO blit; - - if (!drawable || !drawable->backBuffersValid) - return WSEGL_BAD_NATIVE_WINDOW; - if (!pixmap || !pixmap->backBuffersValid) - return WSEGL_BAD_NATIVE_PIXMAP; - - memset(&blit, 0, sizeof(blit)); - - blit.CopyCode = PVR2DROPcopy; - blit.BlitFlags = PVR2D_BLIT_DISABLE_ALL; - - blit.pSrcMemInfo = drawable->backBuffers[drawable->currentBackBuffer]; - blit.SrcStride = drawable->strideBytes; - blit.SrcX = 0; - blit.SrcY = 0; - blit.SizeX = drawable->rect.width; - blit.SizeY = drawable->rect.height; - blit.SrcFormat = drawable->pixelFormat; - - blit.pDstMemInfo = pixmap->backBuffers[pixmap->currentBackBuffer]; - blit.DstStride = pixmap->strideBytes; - blit.DstX = 0; - blit.DstY = 0; - blit.DSizeX = pixmap->rect.width; - blit.DSizeY = pixmap->rect.height; - blit.DstFormat = pixmap->pixelFormat; - - PVR2DBlt(pvrQwsDisplay.context, &blit); - PVR2DQueryBlitsComplete - (pvrQwsDisplay.context, pixmap->backBuffers[pixmap->currentBackBuffer], 1); - - return WSEGL_SUCCESS; -} - -/* Copy color data from a PBuffer to a native pixmap */ -static WSEGLError wseglCopyFromPBuffer - (void *address, unsigned long width, unsigned long height, - unsigned long stride, WSEGLPixelFormat format, - NativePixmapType nativePixmap) -{ - PvrQwsDrawable *pixmap = (PvrQwsDrawable *)nativePixmap; - PVR2DFORMAT pixelFormat; - - if (!pixmap) - return WSEGL_BAD_NATIVE_PIXMAP; - - /* We can only copy under certain conditions */ - switch (format) { - case WSEGL_PIXELFORMAT_565: - pixelFormat = PVR2D_RGB565; break; - case WSEGL_PIXELFORMAT_4444: - pixelFormat = PVR2D_ARGB4444; break; - case WSEGL_PIXELFORMAT_8888: - pixelFormat = PVR2D_ARGB8888; break; - default: - return WSEGL_BAD_CONFIG; - } - if (width > (unsigned long)(pixmap->rect.width) || - height > (unsigned long)(pixmap->rect.height) || - pixelFormat != pixmap->pixelFormat) { - return WSEGL_BAD_CONFIG; - } - - /* We'd like to use PVR2DBlt to do this, but there is no easy way - to map the virtual "address" into physical space to be able - to use the hardware assist. Use memcpy to do the work instead. - Note: PBuffer's are upside down, so we copy from the bottom up */ - char *srcaddr = (char *)address; - char *dstaddr = (char *)(pixmap->backBuffers[pixmap->currentBackBuffer]->pBase); - int dststride = pixmap->strideBytes; - int srcwidth = ((int)width) * pvrQwsDisplay.screens[0].bytesPerPixel; - srcaddr += height * stride; - while (height > 0) { - srcaddr -= (int)stride; - memcpy(dstaddr, srcaddr, srcwidth); - dstaddr += dststride; - --height; - } - return WSEGL_SUCCESS; -} - -/* Return the parameters of a drawable that are needed by the EGL layer */ -static WSEGLError wseglGetDrawableParameters - (WSEGLDrawableHandle _drawable, WSEGLDrawableParams *sourceParams, - WSEGLDrawableParams *renderParams) -{ - PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable; - PVR2DMEMINFO *source, *render; - WSEGLPixelFormat pixelFormat; - - if (!pvrQwsGetBuffers(drawable, &source, &render)) - return WSEGL_BAD_DRAWABLE; - - switch (drawable->pixelFormat) { - case PVR2D_RGB565: - default: - pixelFormat = WSEGL_PIXELFORMAT_565; - break; - - case PVR2D_ARGB4444: - pixelFormat = WSEGL_PIXELFORMAT_4444; - break; - - case PVR2D_ARGB8888: - pixelFormat = WSEGL_PIXELFORMAT_8888; - break; - } - - sourceParams->ui32Width = drawable->rect.width; - sourceParams->ui32Height = drawable->rect.height; - sourceParams->ui32Stride = drawable->stridePixels; - sourceParams->ePixelFormat = pixelFormat; - sourceParams->pvLinearAddress = source->pBase; - sourceParams->ui32HWAddress = source->ui32DevAddr; - sourceParams->hPrivateData = source->hPrivateData; - - renderParams->ui32Width = drawable->rect.width; - renderParams->ui32Height = drawable->rect.height; - renderParams->ui32Stride = drawable->stridePixels; - renderParams->ePixelFormat = pixelFormat; - renderParams->pvLinearAddress = render->pBase; - renderParams->ui32HWAddress = render->ui32DevAddr; - renderParams->hPrivateData = render->hPrivateData; - - return WSEGL_SUCCESS; -} - -static WSEGL_FunctionTable const wseglFunctions = { - WSEGL_VERSION, - wseglIsDisplayValid, - wseglInitializeDisplay, - wseglCloseDisplay, - wseglCreateWindowDrawable, - wseglCreatePixmapDrawable, - wseglDeleteDrawable, - wseglSwapDrawable, - wseglSwapControlInterval, - wseglWaitNative, - wseglCopyFromDrawable, - wseglCopyFromPBuffer, - wseglGetDrawableParameters -}; - -/* Return the table of WSEGL functions to the EGL implementation */ -const WSEGL_FunctionTable *WSEGL_GetFunctionTablePointer(void) -{ - return &wseglFunctions; -} diff --git a/src/plugins/gfxdrivers/powervr/README b/src/plugins/gfxdrivers/powervr/README deleted file mode 100644 index 513e7f5e9e..0000000000 --- a/src/plugins/gfxdrivers/powervr/README +++ /dev/null @@ -1,66 +0,0 @@ -PowerVR QScreen Driver -====================== - -This QScreen plugin driver allows the QtOpenGl module to integrate with PowerVR -hardware from Imagination Technologies. Using this plugin, applications may use -QGLWidget & QGLPixelBuffer with OpenGL ES. The integration with PowerVR drivers -is built as two libraries: The actual QScreen plugin used by Qt (in the -pvreglscreen directory) and a WSEGL plugin for the PowerVR drivers (in the -QWSWSEGL directory). - -Qt/Embedded needs to be configured with the QT_QWS_CLIENTBLIT and -QT_NO_QWS_CURSOR defines. - -The PowerVR drivers provide the WSEGL plugin API to allow window systems such as -QWS to integrate correctly. In order to use the integration, the WSEGL plugin -(libpvrQWSWSEGL.so, usually installed into the Qt library directory) must be in -the LD library path. The PowerVR driver also needs to be told which WSEGL library -to use. This is done by creating/modifying /etc/powervr.ini: - -[default] -WindowSystem=libpvrQWSWSEGL.so - -Note: It is important that the /etc/powervr.ini file not contain ^M (Ctrl-M) DOS -end of line markers at the end of its lines. If ^M markers are present, then the -libpvrQWSWSEGL.so driver will not be loaded and the default null Linux driver -will be loaded silently instead. Make sure that the end of line markers are -strictly Unix-style markers. - - -*************************************************************************** -* IMPORTANT: To build the QScreen plugin and the WSEGL library it depends * -* on, the pvr2d.h, wsegl.h headers for your platform are required. You * -* can find a copy of these headers in src/3rdparty/powervr for SGX based * -* platforms like the TI OMAP3xxx. They probably will not work on MBX * -* because of differences in the layout of certain PVR2D structures. * -* You can tell Qt where to find the actual headers for your system by * -* setting QMAKE_INCDIR_POWERVR in the mkspec. * -*************************************************************************** - -When you start a Qt/Embedded application, you should modify the QWS_DISPLAY -environment variable to use the "powervr" driver instead of "LinuxFb". For -example, if your original QWS_DISPLAY variable was: - - LinuxFb:mmWidth40:mmHeight54:0 - -then it should be changed to: - - powervr:mmWidth40:mmHeight54:0 - -To test the OpenGL ES integration, you can use the hellogl_es example and run it -on the device with: - - hellogl_es -qws - -The driver also supports screen rotation if Qt is configured with the --qt-gfx-transformed option and the QWS_DISPLAY variable is wrapped in a -"Transformed" declaration: - - Transformed:powervr:mmWidth40:mmHeight54:Rot90:0 - -Know Issues: - * A QGLWidget may not have window decorations if it is a top-level window. - * On some platforms, starting a QWS application after the system has been up - for a long time may cause the driver to fail. This is due to fragmentation - of main memory prevening older PowerVR drivers from allocating a contiguous - region of phyical RAM for the GL surface. diff --git a/src/plugins/gfxdrivers/powervr/powervr.pri b/src/plugins/gfxdrivers/powervr/powervr.pri deleted file mode 100644 index 9df8c0ed5b..0000000000 --- a/src/plugins/gfxdrivers/powervr/powervr.pri +++ /dev/null @@ -1,2 +0,0 @@ - -INCLUDEPATH += $$QMAKE_INCDIR_POWERVR diff --git a/src/plugins/gfxdrivers/powervr/powervr.pro b/src/plugins/gfxdrivers/powervr/powervr.pro deleted file mode 100644 index f31ad042d8..0000000000 --- a/src/plugins/gfxdrivers/powervr/powervr.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = QWSWSEGL pvreglscreen -CONFIG += ordered diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp deleted file mode 100644 index 0171de6797..0000000000 --- a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "pvreglscreen.h" -#include "pvreglwindowsurface.h" -#include "pvrqwsdrawable_p.h" -#include <QRegExp> -#include <qwindowsystem_qws.h> -#ifndef QT_NO_QWS_TRANSFORMED -#include <qscreentransformed_qws.h> -#endif -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/kd.h> -#include <fcntl.h> -#include <unistd.h> - -//![0] -PvrEglScreen::PvrEglScreen(int displayId) - : QGLScreen(displayId) -{ - setOptions(NativeWindows); - setSupportsBlitInClients(true); - setSurfaceFunctions(new PvrEglScreenSurfaceFunctions(this, displayId)); -//![0] - fd = -1; - ttyfd = -1; - doGraphicsMode = true; - oldKdMode = KD_TEXT; - parent = 0; - - // Make sure that the EGL layer is initialized and the drivers loaded. - EGLDisplay dpy = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY); - if (!eglInitialize(dpy, 0, 0)) - qWarning("Could not initialize EGL display - are the drivers loaded?"); - - // Make sure that screen 0 is initialized. - pvrQwsScreenWindow(0); -} - -PvrEglScreen::~PvrEglScreen() -{ - if (fd >= 0) - ::close(fd); -} - -bool PvrEglScreen::initDevice() -{ - openTty(); - return true; -} - -bool PvrEglScreen::connect(const QString &displaySpec) -{ - if (!pvrQwsDisplayOpen()) - return false; - - // Initialize the QScreen properties. - data = (uchar *)(pvrQwsDisplay.screens[0].mapped); - w = pvrQwsDisplay.screens[0].screenRect.width; - h = pvrQwsDisplay.screens[0].screenRect.height; - lstep = pvrQwsDisplay.screens[0].screenStride; - dw = w; - dh = h; - size = h * lstep; - mapsize = size; - switch (pvrQwsDisplay.screens[0].pixelFormat) { - case PVR2D_RGB565: - d = 16; - setPixelFormat(QImage::Format_RGB16); - break; - case PVR2D_ARGB4444: - d = 16; - setPixelFormat(QImage::Format_ARGB4444_Premultiplied); - break; - case PVR2D_ARGB8888: - d = 32; - setPixelFormat(QImage::Format_ARGB32_Premultiplied); - break; - default: - pvrQwsDisplayClose(); - qWarning("PvrEglScreen::connect: unsupported pixel format %d", (int)(pvrQwsDisplay.screens[0].pixelFormat)); - return false; - } - - // Handle display physical size spec. - QStringList displayArgs = displaySpec.split(QLatin1Char(':')); - QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)")); - int dimIdxW = displayArgs.indexOf(mmWidthRx); - QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)")); - int dimIdxH = displayArgs.indexOf(mmHeightRx); - if (dimIdxW >= 0) { - mmWidthRx.exactMatch(displayArgs.at(dimIdxW)); - physWidth = mmWidthRx.cap(1).toInt(); - if (dimIdxH < 0) - physHeight = dh*physWidth/dw; - } - if (dimIdxH >= 0) { - mmHeightRx.exactMatch(displayArgs.at(dimIdxH)); - physHeight = mmHeightRx.cap(1).toInt(); - if (dimIdxW < 0) - physWidth = dw*physHeight/dh; - } - if (dimIdxW < 0 && dimIdxH < 0) { - const int dpi = 72; - physWidth = qRound(dw * 25.4 / dpi); - physHeight = qRound(dh * 25.4 / dpi); - } - - // Find the name of the tty device to use. - QRegExp ttyRegExp(QLatin1String("tty=(.*)")); - if (displayArgs.indexOf(ttyRegExp) != -1) - ttyDevice = ttyRegExp.cap(1); - if (displayArgs.contains(QLatin1String("nographicsmodeswitch"))) - doGraphicsMode = false; - - // The screen is ready. - return true; -} - -void PvrEglScreen::disconnect() -{ - pvrQwsDisplayClose(); -} - -void PvrEglScreen::shutdownDevice() -{ - closeTty(); -} - -void PvrEglScreen::blit(const QImage &img, const QPoint &topLeft, const QRegion ®ion) -{ - QGLScreen::blit(img, topLeft, region); - sync(); -} - -void PvrEglScreen::solidFill(const QColor &color, const QRegion ®ion) -{ - QGLScreen::solidFill(color, region); - sync(); -} - -bool PvrEglScreen::chooseContext - (QGLContext *context, const QGLContext *shareContext) -{ - // We use PvrEglScreenSurfaceFunctions instead. - Q_UNUSED(context); - Q_UNUSED(shareContext); - return false; -} - -bool PvrEglScreen::hasOpenGL() -{ - return true; -} - -//![1] -QWSWindowSurface* PvrEglScreen::createSurface(QWidget *widget) const -{ - if (qobject_cast<QGLWidget*>(widget)) - return new PvrEglWindowSurface(widget, (PvrEglScreen *)this, displayId); - - return QScreen::createSurface(widget); -} - -QWSWindowSurface* PvrEglScreen::createSurface(const QString &key) const -{ - if (key == QLatin1String("PvrEgl")) - return new PvrEglWindowSurface(); - - return QScreen::createSurface(key); -} -//![1] - -#ifndef QT_NO_QWS_TRANSFORMED - -static const QScreen *parentScreen - (const QScreen *current, const QScreen *lookingFor) -{ - if (!current) - return 0; - switch (current->classId()) { - case QScreen::ProxyClass: - case QScreen::TransformedClass: { - const QScreen *child = - static_cast<const QProxyScreen *>(current)->screen(); - if (child == lookingFor) - return current; - else - return parentScreen(child, lookingFor); - } - // Not reached. - - case QScreen::MultiClass: { - QList<QScreen *> screens = current->subScreens(); - foreach (QScreen *screen, screens) { - if (screen == lookingFor) - return current; - const QScreen *parent = parentScreen(screen, lookingFor); - if (parent) - return parent; - } - } - break; - - default: break; - } - return 0; -} - -int PvrEglScreen::transformation() const -{ - // We need to search for our parent screen, which is assumed to be - // "Transformed". If it isn't, then there is no transformation. - // There is no direct method to get the parent screen so we need - // to search every screen until we find ourselves. - if (!parent && qt_screen != this) - parent = parentScreen(qt_screen, this); - if (!parent) - return 0; - if (parent->classId() != QScreen::TransformedClass) - return 0; - return 90 * static_cast<const QTransformedScreen *>(parent) - ->transformOrientation(); -} - -#else - -int PvrEglScreen::transformation() const -{ - return 0; -} - -#endif - -void PvrEglScreen::sync() -{ - // Put code here to synchronize 2D and 3D operations if necessary. -} - -void PvrEglScreen::openTty() -{ - const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0}; - - if (ttyDevice.isEmpty()) { - for (const char * const *dev = devs; *dev; ++dev) { - ttyfd = ::open(*dev, O_RDWR); - if (ttyfd != -1) - break; - } - } else { - ttyfd = ::open(ttyDevice.toAscii().constData(), O_RDWR); - } - - if (ttyfd == -1) - return; - - ::fcntl(ttyfd, F_SETFD, FD_CLOEXEC); - - if (doGraphicsMode) { - ioctl(ttyfd, KDGETMODE, &oldKdMode); - if (oldKdMode != KD_GRAPHICS) { - int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS); - if (ret == -1) - doGraphicsMode = false; - } - } - - // No blankin' screen, no blinkin' cursor!, no cursor! - const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c"; - ::write(ttyfd, termctl, sizeof(termctl)); -} - -void PvrEglScreen::closeTty() -{ - if (ttyfd == -1) - return; - - if (doGraphicsMode) - ioctl(ttyfd, KDSETMODE, oldKdMode); - - // Blankin' screen, blinkin' cursor! - const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c"; - ::write(ttyfd, termctl, sizeof(termctl)); - - ::close(ttyfd); - ttyfd = -1; -} - -//![2] -bool PvrEglScreenSurfaceFunctions::createNativeWindow(QWidget *widget, EGLNativeWindowType *native) -{ -//![2] - QWSWindowSurface *surface = - static_cast<QWSWindowSurface *>(widget->windowSurface()); - if (!surface) { - // The widget does not have a surface yet, so give it one. - surface = new PvrEglWindowSurface(widget, screen, displayId); - widget->setWindowSurface(surface); - } else if (surface->key() != QLatin1String("PvrEgl")) { - // The application has attached a QGLContext to an ordinary QWidget. - // Replace the widget's window surface with a new one that can do GL. - QRect geometry = widget->frameGeometry(); - geometry.moveTo(widget->mapToGlobal(QPoint(0, 0))); - surface = new PvrEglWindowSurface(widget, screen, displayId); - surface->setGeometry(geometry); - widget->setWindowSurface(surface); - widget->setAttribute(Qt::WA_NoSystemBackground, true); - } - PvrEglWindowSurface *nsurface = static_cast<PvrEglWindowSurface*>(surface); - *native = (EGLNativeWindowType)(nsurface->nativeDrawable()); - return true; -} diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro deleted file mode 100644 index 2b5212a6b3..0000000000 --- a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro +++ /dev/null @@ -1,27 +0,0 @@ -TEMPLATE = lib -TARGET = qgfxpvregl -CONFIG += qt plugin warn_on -QT += opengl - -LIBS += -lpvrQWSWSEGL - -DEFINES += QT_QWS_CLIENTBLIT - -INCLUDEPATH += ../QWSWSEGL - - -HEADERS = \ - pvreglscreen.h \ - pvreglwindowsurface.h - -SOURCES = \ - pvreglscreenplugin.cpp \ - pvreglscreen.cpp \ - pvreglwindowsurface.cpp - -DESTDIR = $$QT.gui.plugins/gfxdrivers - -target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers -INSTALLS += target - -include(../powervr.pri)
\ No newline at end of file diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp deleted file mode 100644 index 943bf9473c..0000000000 --- a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "pvreglscreen.h" - -#include <QScreenDriverPlugin> -#include <QStringList> - -class PvrEglScreenPlugin : public QScreenDriverPlugin -{ -public: - PvrEglScreenPlugin(); - - QStringList keys() const; - QScreen *create(const QString&, int displayId); -}; - -PvrEglScreenPlugin::PvrEglScreenPlugin() - : QScreenDriverPlugin() -{ -} - -QStringList PvrEglScreenPlugin::keys() const -{ - return (QStringList() << "powervr"); -} - -QScreen* PvrEglScreenPlugin::create(const QString& driver, int displayId) -{ - if (driver.toLower() != "powervr") - return 0; - - return new PvrEglScreen(displayId); -} - -Q_EXPORT_PLUGIN2(qgfxpvregl, PvrEglScreenPlugin) diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp deleted file mode 100644 index f23f5c1cc4..0000000000 --- a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "pvreglwindowsurface.h" -#include "pvreglscreen.h" -#include <QScreen> -#include <QDebug> -#include <QWSDisplay> - -PvrEglWindowSurface::PvrEglWindowSurface - (QWidget *widget, PvrEglScreen *screen, int screenNum) - : QWSGLWindowSurface(widget) -{ - setSurfaceFlags(QWSWindowSurface::Opaque); - - this->widget = widget; - this->screen = screen; - this->pdevice = 0; - - QPoint pos = offset(widget); - QSize size = widget->size(); - - PvrQwsRect pvrRect; - pvrRect.x = pos.x(); - pvrRect.y = pos.y(); - pvrRect.width = size.width(); - pvrRect.height = size.height(); - transformRects(&pvrRect, 1); - - // Try to recover a previous PvrQwsDrawable object for the widget - // if there is one. This can happen when a PvrEglWindowSurface - // is created for a widget, bound to a EGLSurface, and then destroyed. - // When a new PvrEglWindowSurface is created for the widget, it will - // pick up the previous PvrQwsDrawable if the EGLSurface has not been - // destroyed in the meantime. - drawable = pvrQwsFetchWindow((long)widget); - if (drawable) - pvrQwsSetGeometry(drawable, &pvrRect); - else - drawable = pvrQwsCreateWindow(screenNum, (long)widget, &pvrRect); - pvrQwsSetRotation(drawable, screen->transformation()); -} - -PvrEglWindowSurface::PvrEglWindowSurface() - : QWSGLWindowSurface() -{ - setSurfaceFlags(QWSWindowSurface::Opaque); - drawable = 0; - widget = 0; - screen = 0; - pdevice = 0; -} - -PvrEglWindowSurface::~PvrEglWindowSurface() -{ - // Release the PvrQwsDrawable. If it is bound to an EGLSurface, - // then it will stay around until a new PvrEglWindowSurface is - // created for the widget. If it is not bound to an EGLSurface, - // it will be destroyed immediately. - if (drawable && pvrQwsReleaseWindow(drawable)) - pvrQwsDestroyDrawable(drawable); - - delete pdevice; -} - -bool PvrEglWindowSurface::isValid() const -{ - return (widget != 0); -} - -void PvrEglWindowSurface::setGeometry(const QRect &rect) -{ - if (drawable) { - // XXX: adjust for the screen offset. - PvrQwsRect pvrRect; - pvrRect.x = rect.x(); - pvrRect.y = rect.y(); - pvrRect.width = rect.width(); - pvrRect.height = rect.height(); - transformRects(&pvrRect, 1); - pvrQwsSetGeometry(drawable, &pvrRect); - pvrQwsSetRotation(drawable, screen->transformation()); - } - QWSGLWindowSurface::setGeometry(rect); -} - -bool PvrEglWindowSurface::move(const QPoint &offset) -{ - QRect rect = geometry().translated(offset); - if (drawable) { - PvrQwsRect pvrRect; - pvrRect.x = rect.x(); - pvrRect.y = rect.y(); - pvrRect.width = rect.width(); - pvrRect.height = rect.height(); - transformRects(&pvrRect, 1); - pvrQwsSetGeometry(drawable, &pvrRect); - pvrQwsSetRotation(drawable, screen->transformation()); - } - return QWSGLWindowSurface::move(offset); -} - -QByteArray PvrEglWindowSurface::permanentState() const -{ - // Nothing interesting to pass to the server just yet. - return QByteArray(); -} - -void PvrEglWindowSurface::setPermanentState(const QByteArray &state) -{ - Q_UNUSED(state); -} - -void PvrEglWindowSurface::flush - (QWidget *widget, const QRegion ®ion, const QPoint &offset) -{ - // The GL paint engine is responsible for the swapBuffers() call. - // If we were to call the base class's implementation of flush() - // then it would fetch the image() and manually blit it to the - // screeen instead of using the fast PVR2D blit. - Q_UNUSED(widget); - Q_UNUSED(region); - Q_UNUSED(offset); -} - -QImage PvrEglWindowSurface::image() const -{ - if (drawable) { - PvrQwsRect pvrRect; - pvrQwsGetGeometry(drawable, &pvrRect); - void *data = pvrQwsGetRenderBuffer(drawable); - if (data) { - return QImage((uchar *)data, pvrRect.width, pvrRect.height, - pvrQwsGetStride(drawable), screen->pixelFormat()); - } - } - return QImage(16, 16, screen->pixelFormat()); -} - -QPaintDevice *PvrEglWindowSurface::paintDevice() -{ - return widget; -} - -void PvrEglWindowSurface::setDirectRegion(const QRegion &r, int id) -{ - QWSGLWindowSurface::setDirectRegion(r, id); - - if (!drawable) - return; - - // Clip the region to the window boundaries in case the child - // is partially outside the geometry of the parent. - QWidget *window = widget->window(); - QRegion region = r; - if (widget != window) { - QRect rect = window->geometry(); - rect.moveTo(window->mapToGlobal(QPoint(0, 0))); - region = region.intersect(rect); - } - - if (region.isEmpty()) { - pvrQwsClearVisibleRegion(drawable); - } else if (region.rectCount() == 1) { - QRect rect = region.boundingRect(); - PvrQwsRect pvrRect; - pvrRect.x = rect.x(); - pvrRect.y = rect.y(); - pvrRect.width = rect.width(); - pvrRect.height = rect.height(); - transformRects(&pvrRect, 1); - pvrQwsSetVisibleRegion(drawable, &pvrRect, 1); - pvrQwsSetRotation(drawable, screen->transformation()); - if (!pvrQwsSwapBuffers(drawable, 1)) - screen->solidFill(QColor(0, 0, 0), region); - } else { - QVector<QRect> rects = region.rects(); - PvrQwsRect *pvrRects = new PvrQwsRect [rects.size()]; - for (int index = 0; index < rects.size(); ++index) { - QRect rect = rects[index]; - pvrRects[index].x = rect.x(); - pvrRects[index].y = rect.y(); - pvrRects[index].width = rect.width(); - pvrRects[index].height = rect.height(); - } - transformRects(pvrRects, rects.size()); - pvrQwsSetVisibleRegion(drawable, pvrRects, rects.size()); - pvrQwsSetRotation(drawable, screen->transformation()); - if (!pvrQwsSwapBuffers(drawable, 1)) - screen->solidFill(QColor(0, 0, 0), region); - delete [] pvrRects; - } -} - -void PvrEglWindowSurface::transformRects(PvrQwsRect *rects, int count) const -{ - switch (screen->transformation()) { - case 0: break; - - case 90: - { - for (int index = 0; index < count; ++index) { - int x = rects[index].y; - int y = screen->height() - (rects[index].x + rects[index].width); - rects[index].x = x; - rects[index].y = y; - qSwap(rects[index].width, rects[index].height); - } - } - break; - - case 180: - { - for (int index = 0; index < count; ++index) { - int x = screen->width() - (rects[index].x + rects[index].width); - int y = screen->height() - (rects[index].y + rects[index].height); - rects[index].x = x; - rects[index].y = y; - } - } - break; - - case 270: - { - for (int index = 0; index < count; ++index) { - int x = screen->width() - (rects[index].y + rects[index].height); - int y = rects[index].x; - rects[index].x = x; - rects[index].y = y; - qSwap(rects[index].width, rects[index].height); - } - } - break; - } -} diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h deleted file mode 100644 index 365fed9170..0000000000 --- a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef PVREGLWINDOWSURFACE_H -#define PVREGLWINDOWSURFACE_H - -#include <private/qglwindowsurface_qws_p.h> -#include "pvrqwsdrawable.h" - -class PvrEglScreen; - -class PvrEglWindowSurface : public QWSGLWindowSurface -{ -public: - PvrEglWindowSurface(QWidget *widget, PvrEglScreen *screen, int screenNum); - PvrEglWindowSurface(); - ~PvrEglWindowSurface(); - - QString key() const { return QLatin1String("PvrEgl"); } - - bool isValid() const; - - void setGeometry(const QRect &rect); - bool move(const QPoint &offset); - - QByteArray permanentState() const; - void setPermanentState(const QByteArray &state); - - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - - QImage image() const; - QPaintDevice *paintDevice(); - - void setDirectRegion(const QRegion ®ion, int id); - - long nativeDrawable() const { return (long)widget; } - -private: - QWidget *widget; - PvrQwsDrawable *drawable; - PvrEglScreen *screen; - QPaintDevice *pdevice; - - void transformRects(PvrQwsRect *rects, int count) const; -}; - -#endif diff --git a/src/plugins/gfxdrivers/qvfb/main.cpp b/src/plugins/gfxdrivers/qvfb/main.cpp deleted file mode 100644 index 98661b61b9..0000000000 --- a/src/plugins/gfxdrivers/qvfb/main.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qscreendriverplugin_qws.h> -#include <qscreenvfb_qws.h> -#include <qstringlist.h> - -#ifndef QT_NO_LIBRARY -QT_BEGIN_NAMESPACE - -class ScreenVfbDriver : public QScreenDriverPlugin -{ -public: - ScreenVfbDriver(); - - QStringList keys() const; - QScreen *create(const QString&, int displayId); -}; - -ScreenVfbDriver::ScreenVfbDriver() -: QScreenDriverPlugin() -{ -} - -QStringList ScreenVfbDriver::keys() const -{ - QStringList list; - list << "QVFb"; - return list; -} - -QScreen* ScreenVfbDriver::create(const QString& driver, int displayId) -{ - if (driver.toLower() == "qvfb") - return new QVFbScreen(displayId); - - return 0; -} - -Q_EXPORT_STATIC_PLUGIN(ScreenVfbDriver) -Q_EXPORT_PLUGIN2(qscreenvfb, ScreenVfbDriver) - -QT_END_NAMESPACE -#endif //QT_NO_LIBRARY diff --git a/src/plugins/gfxdrivers/qvfb/qvfb.pro b/src/plugins/gfxdrivers/qvfb/qvfb.pro deleted file mode 100644 index 99376be81c..0000000000 --- a/src/plugins/gfxdrivers/qvfb/qvfb.pro +++ /dev/null @@ -1,19 +0,0 @@ -TARGET = qscreenvfb -load(qt_plugin) - -DEFINES += QT_QWS_QVFB QT_QWS_MOUSE_QVFB QT_QWS_KBD_QVFB - -DESTDIR = $$QT.gui.plugins/gfxdrivers - -HEADERS = \ - $$QT_SOURCE_TREE/src/gui/embedded/qscreenvfb_qws.h \ - $$QT_SOURCE_TREE/src/gui/embedded/qkbdvfb_qws.h \ - $$QT_SOURCE_TREE/src/gui/embedded/qmousevfb_qws.h - -SOURCES = main.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qscreenvfb_qws.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qkbdvfb_qws.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qmousevfb_qws.cpp - -target.path += $$[QT_INSTALL_PLUGINS]/gfxdrivers -INSTALLS += target diff --git a/src/plugins/gfxdrivers/transformed/main.cpp b/src/plugins/gfxdrivers/transformed/main.cpp deleted file mode 100644 index 612068e3a6..0000000000 --- a/src/plugins/gfxdrivers/transformed/main.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qscreendriverplugin_qws.h> -#include <qscreentransformed_qws.h> -#include <qstringlist.h> -#ifndef QT_NO_LIBRARY -QT_BEGIN_NAMESPACE - -class GfxTransformedDriver : public QScreenDriverPlugin -{ -public: - GfxTransformedDriver(); - - QStringList keys() const; - QScreen *create(const QString&, int displayId); -}; - -GfxTransformedDriver::GfxTransformedDriver() -: QScreenDriverPlugin() -{ -} - -QStringList GfxTransformedDriver::keys() const -{ - QStringList list; - list << "Transformed"; - return list; -} - -QScreen* GfxTransformedDriver::create(const QString& driver, int displayId) -{ -#ifndef QT_NO_QWS_TRANSFORMED - if (driver.toLower() == "transformed") - return new QTransformedScreen(displayId); -#else //QT_NO_QWS_TRANSFORMED - printf("QT buildt with QT_NO_QWS_TRANSFORMED. No screen driver returned\n"); -#endif //QT_NO_QWS_TRANSFORMED - return 0; -} - -Q_EXPORT_STATIC_PLUGIN(GfxTransformedDriver) -Q_EXPORT_PLUGIN2(qgfxtransformed, GfxTransformedDriver) - -QT_END_NAMESPACE -#endif //QT_NO_LIBRARY diff --git a/src/plugins/gfxdrivers/transformed/transformed.pro b/src/plugins/gfxdrivers/transformed/transformed.pro deleted file mode 100644 index f97713fc38..0000000000 --- a/src/plugins/gfxdrivers/transformed/transformed.pro +++ /dev/null @@ -1,13 +0,0 @@ -TARGET = qgfxtransformed -load(qt_plugin) - -DEFINES += QT_QWS_TRANSFORMED - -DESTDIR = $$QT.gui.plugins/gfxdrivers - -HEADERS = $$QT_SOURCE_TREE/src/gui/embedded/qscreentransformed_qws.h -SOURCES = main.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qscreentransformed_qws.cpp - -target.path=$$[QT_INSTALL_PLUGINS]/gfxdrivers -INSTALLS += target diff --git a/src/plugins/gfxdrivers/vnc/main.cpp b/src/plugins/gfxdrivers/vnc/main.cpp deleted file mode 100644 index 0a7ae592e0..0000000000 --- a/src/plugins/gfxdrivers/vnc/main.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qscreendriverplugin_qws.h> -#include <qscreenvnc_qws.h> -#include <qstringlist.h> - -#ifndef QT_NO_LIBRARY -QT_BEGIN_NAMESPACE - -class GfxVncDriver : public QScreenDriverPlugin -{ -public: - GfxVncDriver(); - - QStringList keys() const; - QScreen *create(const QString&, int displayId); -}; - -GfxVncDriver::GfxVncDriver() -: QScreenDriverPlugin() -{ -} - -QStringList GfxVncDriver::keys() const -{ - QStringList list; - list << "VNC"; - return list; -} - -QScreen* GfxVncDriver::create(const QString& driver, int displayId) -{ -#ifndef QT_NO_QWS_VNC - if (driver.toLower() == "vnc") - return new QVNCScreen(displayId); -#else //QT_NO_QWS_VNC - printf("QT buildt with QT_NO_QWS_VNC. No screen driver returned\n"); -#endif //QT_NO_QWS_VNC - return 0; -} - -Q_EXPORT_STATIC_PLUGIN(GfxVncDriver) -Q_EXPORT_PLUGIN2(qgfxvnc, GfxVncDriver) - -QT_END_NAMESPACE - -#endif //QT_NO_LIBRARY diff --git a/src/plugins/gfxdrivers/vnc/qscreenvnc_p.h b/src/plugins/gfxdrivers/vnc/qscreenvnc_p.h deleted file mode 100644 index e64393a8c9..0000000000 --- a/src/plugins/gfxdrivers/vnc/qscreenvnc_p.h +++ /dev/null @@ -1,524 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSCREENVNC_P_H -#define QSCREENVNC_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the QLibrary class. This header file may change from version to version -// without notice, or even be removed. -// -// We mean it. -// - -#include "qscreenvnc_qws.h" - -#ifndef QT_NO_QWS_VNC - -#include <QtCore/qvarlengtharray.h> -#include <QtCore/qsharedmemory.h> -#include <QtNetwork/qtcpsocket.h> -#include <QtNetwork/qtcpserver.h> - -QT_BEGIN_NAMESPACE - -class QVNCServer; - -#ifndef QT_NO_QWS_CURSOR -class QVNCCursor : public QProxyScreenCursor -{ -public: - QVNCCursor(QVNCScreen *s); - ~QVNCCursor(); - - void hide(); - void show(); - void set(const QImage &image, int hotx, int hoty); - void move(int x, int y); - -private: - void setDirty(const QRect &r) const; - QVNCScreen *screen; -}; - -class QVNCClientCursor : public QProxyScreenCursor -{ -public: - QVNCClientCursor(QVNCServer *s); - ~QVNCClientCursor(); - - void set(const QImage &image, int hotx, int hoty); - void write() const; - -private: - QVNCServer *server; -}; -#endif // QT_NO_QWS_CURSOR - -#define MAP_TILE_SIZE 16 -#define MAP_WIDTH 1280 / MAP_TILE_SIZE -#define MAP_HEIGHT 1024 / MAP_TILE_SIZE - -class QVNCDirtyMap -{ -public: - QVNCDirtyMap(QScreen *screen); - virtual ~QVNCDirtyMap(); - - void reset(); - bool dirty(int x, int y) const; - virtual void setDirty(int x, int y, bool force = false) = 0; - void setClean(int x, int y); - - int bytesPerPixel; - - int numDirty; - int mapWidth; - int mapHeight; - -protected: - uchar *map; - QScreen *screen; - uchar *buffer; - int bufferWidth; - int bufferHeight; - int bufferStride; - int numTiles; -}; - -template <class T> -class QVNCDirtyMapOptimized : public QVNCDirtyMap -{ -public: - QVNCDirtyMapOptimized(QScreen *screen) : QVNCDirtyMap(screen) {} - ~QVNCDirtyMapOptimized() {} - - void setDirty(int x, int y, bool force = false); -}; - -class QRfbRect -{ -public: - QRfbRect() {} - QRfbRect(quint16 _x, quint16 _y, quint16 _w, quint16 _h) { - x = _x; y = _y; w = _w; h = _h; - } - - void read(QTcpSocket *s); - void write(QTcpSocket *s) const; - - quint16 x; - quint16 y; - quint16 w; - quint16 h; -}; - -class QRfbPixelFormat -{ -public: - static int size() { return 16; } - - void read(QTcpSocket *s); - void write(QTcpSocket *s); - - int bitsPerPixel; - int depth; - bool bigEndian; - bool trueColor; - int redBits; - int greenBits; - int blueBits; - int redShift; - int greenShift; - int blueShift; -}; - -class QRfbServerInit -{ -public: - QRfbServerInit() { name = 0; } - ~QRfbServerInit() { delete[] name; } - - int size() const { return QRfbPixelFormat::size() + 8 + strlen(name); } - void setName(const char *n); - - void read(QTcpSocket *s); - void write(QTcpSocket *s); - - quint16 width; - quint16 height; - QRfbPixelFormat format; - char *name; -}; - -class QRfbSetEncodings -{ -public: - bool read(QTcpSocket *s); - - quint16 count; -}; - -class QRfbFrameBufferUpdateRequest -{ -public: - bool read(QTcpSocket *s); - - char incremental; - QRfbRect rect; -}; - -class QRfbKeyEvent -{ -public: - bool read(QTcpSocket *s); - - char down; - int keycode; - int unicode; -}; - -class QRfbPointerEvent -{ -public: - bool read(QTcpSocket *s); - - uint buttons; - quint16 x; - quint16 y; -}; - -class QRfbClientCutText -{ -public: - bool read(QTcpSocket *s); - - quint32 length; -}; - -class QVNCScreenPrivate : public QObject -{ -public: - QVNCScreenPrivate(QVNCScreen *parent); - ~QVNCScreenPrivate(); - - void setDirty(const QRect &rect, bool force = false); - void configure(); - - qreal dpiX; - qreal dpiY; - bool doOnScreenSurface; - QVNCDirtyMap *dirty; - int refreshRate; - QVNCServer *vncServer; - -#if !defined(QT_NO_QWS_MULTIPROCESS) && !defined(QT_NO_SHAREDMEMORY) - QSharedMemory shm; -#endif - - QVNCScreen *q_ptr; - - bool noDisablePainting; -}; - -class QRfbEncoder -{ -public: - QRfbEncoder(QVNCServer *s) : server(s) {} - virtual ~QRfbEncoder() {} - - virtual void write() = 0; - -protected: - QVNCServer *server; -}; - -class QRfbRawEncoder : public QRfbEncoder -{ -public: - QRfbRawEncoder(QVNCServer *s) : QRfbEncoder(s) {} - - void write(); - -private: - QByteArray buffer; -}; - -template <class SRC> class QRfbHextileEncoder; - -template <class SRC> -class QRfbSingleColorHextile -{ -public: - QRfbSingleColorHextile(QRfbHextileEncoder<SRC> *e) : encoder(e) {} - bool read(const uchar *data, int width, int height, int stride); - void write(QTcpSocket *socket) const; - -private: - QRfbHextileEncoder<SRC> *encoder; -}; - -template <class SRC> -class QRfbDualColorHextile -{ -public: - QRfbDualColorHextile(QRfbHextileEncoder<SRC> *e) : encoder(e) {} - bool read(const uchar *data, int width, int height, int stride); - void write(QTcpSocket *socket) const; - -private: - struct Rect { - quint8 xy; - quint8 wh; - } Q_PACKED rects[8 * 16]; - - quint8 numRects; - QRfbHextileEncoder<SRC> *encoder; - -private: - inline int lastx() const { return rectx(numRects); } - inline int lasty() const { return recty(numRects); } - inline int rectx(int r) const { return rects[r].xy >> 4; } - inline int recty(int r) const { return rects[r].xy & 0x0f; } - inline int width(int r) const { return (rects[r].wh >> 4) + 1; } - inline int height(int r) const { return (rects[r].wh & 0x0f) + 1; } - - inline void setX(int r, int x) { - rects[r].xy = (x << 4) | (rects[r].xy & 0x0f); - } - inline void setY(int r, int y) { - rects[r].xy = (rects[r].xy & 0xf0) | y; - } - inline void setWidth(int r, int width) { - rects[r].wh = ((width - 1) << 4) | (rects[r].wh & 0x0f); - } - inline void setHeight(int r, int height) { - rects[r].wh = (rects[r].wh & 0xf0) | (height - 1); - } - - inline void setWidth(int width) { setWidth(numRects, width); } - inline void setHeight(int height) { setHeight(numRects, height); } - inline void setX(int x) { setX(numRects, x); } - inline void setY(int y) { setY(numRects, y); } - void next(); -}; - -template <class SRC> -class QRfbMultiColorHextile -{ -public: - QRfbMultiColorHextile(QRfbHextileEncoder<SRC> *e) : encoder(e) {} - bool read(const uchar *data, int width, int height, int stride); - void write(QTcpSocket *socket) const; - -private: - inline quint8* rect(int r) { - return rects.data() + r * (bpp + 2); - } - inline const quint8* rect(int r) const { - return rects.constData() + r * (bpp + 2); - } - inline void setX(int r, int x) { - quint8 *ptr = rect(r) + bpp; - *ptr = (x << 4) | (*ptr & 0x0f); - } - inline void setY(int r, int y) { - quint8 *ptr = rect(r) + bpp; - *ptr = (*ptr & 0xf0) | y; - } - void setColor(SRC color); - inline int rectx(int r) const { - const quint8 *ptr = rect(r) + bpp; - return *ptr >> 4; - } - inline int recty(int r) const { - const quint8 *ptr = rect(r) + bpp; - return *ptr & 0x0f; - } - inline void setWidth(int r, int width) { - quint8 *ptr = rect(r) + bpp + 1; - *ptr = ((width - 1) << 4) | (*ptr & 0x0f); - } - inline void setHeight(int r, int height) { - quint8 *ptr = rect(r) + bpp + 1; - *ptr = (*ptr & 0xf0) | (height - 1); - } - - bool beginRect(); - void endRect(); - - static const int maxRectsSize = 16 * 16; - QVarLengthArray<quint8, maxRectsSize> rects; - - quint8 bpp; - quint8 numRects; - QRfbHextileEncoder<SRC> *encoder; -}; - -template <class SRC> -class QRfbHextileEncoder : public QRfbEncoder -{ -public: - QRfbHextileEncoder(QVNCServer *s); - void write(); - -private: - enum SubEncoding { - Raw = 1, - BackgroundSpecified = 2, - ForegroundSpecified = 4, - AnySubrects = 8, - SubrectsColoured = 16 - }; - - QByteArray buffer; - QRfbSingleColorHextile<SRC> singleColorHextile; - QRfbDualColorHextile<SRC> dualColorHextile; - QRfbMultiColorHextile<SRC> multiColorHextile; - - SRC bg; - SRC fg; - bool newBg; - bool newFg; - - friend class QRfbSingleColorHextile<SRC>; - friend class QRfbDualColorHextile<SRC>; - friend class QRfbMultiColorHextile<SRC>; -}; - -class QVNCServer : public QObject -{ - Q_OBJECT -public: - QVNCServer(QVNCScreen *screen); - QVNCServer(QVNCScreen *screen, int id); - ~QVNCServer(); - - void setDirty(); - void setDirtyCursor() { dirtyCursor = true; setDirty(); } - inline bool isConnected() const { return state == Connected; } - inline void setRefreshRate(int rate) { refreshRate = rate; } - - enum ClientMsg { SetPixelFormat = 0, - FixColourMapEntries = 1, - SetEncodings = 2, - FramebufferUpdateRequest = 3, - KeyEvent = 4, - PointerEvent = 5, - ClientCutText = 6 }; - - enum ServerMsg { FramebufferUpdate = 0, - SetColourMapEntries = 1 }; - - void convertPixels(char *dst, const char *src, int count) const; - - inline int clientBytesPerPixel() const { - return pixelFormat.bitsPerPixel / 8; - } - - inline QVNCScreen* screen() const { return qvnc_screen; } - inline QVNCDirtyMap* dirtyMap() const { return qvnc_screen->d_ptr->dirty; } - inline QTcpSocket* clientSocket() const { return client; } - QImage screenImage() const; - inline bool doPixelConversion() const { return needConversion; } -#ifndef QT_NO_QWS_CURSOR - inline bool hasClientCursor() const { return qvnc_cursor != 0; } -#endif - -private: - void setPixelFormat(); - void setEncodings(); - void frameBufferUpdateRequest(); - void pointerEvent(); - void keyEvent(); - void clientCutText(); - bool pixelConversionNeeded() const; - -private slots: - void newConnection(); - void readClient(); - void checkUpdate(); - void discardClient(); - -private: - void init(uint port); - enum ClientState { Unconnected, Protocol, Init, Connected }; - QTimer *timer; - QTcpServer *serverSocket; - QTcpSocket *client; - ClientState state; - quint8 msgType; - bool handleMsg; - QRfbPixelFormat pixelFormat; - Qt::KeyboardModifiers keymod; - int encodingsPending; - int cutTextPending; - uint supportCopyRect : 1; - uint supportRRE : 1; - uint supportCoRRE : 1; - uint supportHextile : 1; - uint supportZRLE : 1; - uint supportCursor : 1; - uint supportDesktopSize : 1; - bool wantUpdate; - bool sameEndian; - bool needConversion; -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - bool swapBytes; -#endif - bool dirtyCursor; - int refreshRate; - QVNCScreen *qvnc_screen; -#ifndef QT_NO_QWS_CURSOR - QVNCClientCursor *qvnc_cursor; -#endif - - QRfbEncoder *encoder; -}; - - -QT_END_NAMESPACE -#endif // QT_NO_QWS_VNC -#endif // QSCREENVNC_P_H diff --git a/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp b/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp deleted file mode 100644 index 3ddedc63ea..0000000000 --- a/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp +++ /dev/null @@ -1,2338 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qscreenvnc_qws.h" - -#ifndef QT_NO_QWS_VNC - -#include "qscreenvnc_p.h" -#include "qwindowsystem_qws.h" -#include "qwsdisplay_qws.h" -#include "qscreendriverfactory_qws.h" -#include <QtCore/qtimer.h> -#include <QtCore/qregexp.h> -#include <QtGui/qwidget.h> -#include <QtGui/qpolygon.h> -#include <QtGui/qpainter.h> -#include <qdebug.h> -#include <private/qwindowsurface_qws_p.h> -#include <private/qwssignalhandler_p.h> -#include <private/qwidget_p.h> -#include <private/qdrawhelper_p.h> - -#include <stdlib.h> - -QT_BEGIN_NAMESPACE - -//#define QT_QWS_VNC_DEBUG - -extern QString qws_qtePipeFilename(); - -#ifndef QT_NO_QWS_CURSOR - -QVNCCursor::QVNCCursor(QVNCScreen *s) - : screen(s) -{ - if (qt_screencursor) - setScreenCursor(qt_screencursor); - else - hwaccel = true; -} - -QVNCCursor::~QVNCCursor() -{ - if (screenCursor()) - qt_screencursor = screenCursor(); -} - -void QVNCCursor::setDirty(const QRect &r) const -{ - screen->d_ptr->setDirty(r, true); -} - -void QVNCCursor::hide() -{ - QProxyScreenCursor::hide(); - if (enable) - setDirty(boundingRect()); -} - -void QVNCCursor::show() -{ - QProxyScreenCursor::show(); - if (enable) - setDirty(boundingRect()); -} - -void QVNCCursor::set(const QImage &image, int hotx, int hoty) -{ - QRegion dirty = boundingRect(); - QProxyScreenCursor::set(image, hotx, hoty); - dirty |= boundingRect(); - if (enable && hwaccel && !screen->d_ptr->vncServer->hasClientCursor()) { - const QVector<QRect> rects = dirty.rects(); - for (int i = 0; i < rects.size(); ++i) - setDirty(rects.at(i)); - } -} - -void QVNCCursor::move(int x, int y) -{ - if (enable && hwaccel && !screen->d_ptr->vncServer->hasClientCursor()) { - QRegion dirty = boundingRect(); - QProxyScreenCursor::move(x, y); - dirty |= boundingRect(); - if (enable) { - const QVector<QRect> rects = dirty.rects(); - for (int i = 0; i < rects.size(); ++i) - setDirty(rects.at(i)); - } - } else { - QProxyScreenCursor::move(x, y); - } -} - -QVNCClientCursor::QVNCClientCursor(QVNCServer *s) - : server(s) -{ - setScreenCursor(qt_screencursor); - Q_ASSERT(hwaccel); - qt_screencursor = this; // hw: XXX - - set(image(), hotspot.x(), hotspot.y()); -} - -QVNCClientCursor::~QVNCClientCursor() -{ - qt_screencursor = screenCursor(); -} - -void QVNCClientCursor::set(const QImage &image, int hotx, int hoty) -{ - QScreenCursor::set(image, hotx, hoty); - server->setDirtyCursor(); -} - -void QVNCClientCursor::write() const -{ - QTcpSocket *socket = server->clientSocket(); - - // FramebufferUpdate header - { - const quint16 tmp[6] = { htons(0), - htons(1), - htons(hotspot.x()), htons(hotspot.y()), - htons(cursor.width()), - htons(cursor.height()) }; - socket->write((char*)tmp, sizeof(tmp)); - - const quint32 encoding = htonl(-239); - socket->write((char*)(&encoding), sizeof(encoding)); - } - - if (cursor.isNull()) - return; - - // write pixels - Q_ASSERT(cursor.hasAlphaChannel()); - const QImage img = cursor.convertToFormat(server->screen()->pixelFormat()); - const int n = server->clientBytesPerPixel() * img.width(); - char *buffer = new char[n]; - for (int i = 0; i < img.height(); ++i) { - server->convertPixels(buffer, (const char*)img.scanLine(i), img.width()); - socket->write(buffer, n); - } - delete[] buffer; - - // write mask - const QImage bitmap = cursor.createAlphaMask().convertToFormat(QImage::Format_Mono); - Q_ASSERT(bitmap.depth() == 1); - Q_ASSERT(bitmap.size() == img.size()); - const int width = (bitmap.width() + 7) / 8; - for (int i = 0; i < bitmap.height(); ++i) - socket->write((const char*)bitmap.scanLine(i), width); -} - -#endif // QT_NO_QWS_CURSOR - -QVNCScreenPrivate::QVNCScreenPrivate(QVNCScreen *parent) - : dpiX(72), dpiY(72), doOnScreenSurface(false), refreshRate(25), - vncServer(0), q_ptr(parent), noDisablePainting(false) -{ -#ifdef QT_BUILD_INTERNAL - noDisablePainting = (qgetenv("QT_VNC_NO_DISABLEPAINTING").toInt() > 0); -#endif -#ifndef QT_NO_QWS_SIGNALHANDLER - QWSSignalHandler::instance()->addObject(this); -#endif -} - -QVNCScreenPrivate::~QVNCScreenPrivate() -{ -#if defined(QT_NO_QWS_MULTIPROCESS) || defined(QT_NO_SHAREDMEMORY) - if (q_ptr->screen()) - return; - - delete[] q_ptr->data; - q_ptr->data = 0; -#else - shm.detach(); -#endif -} - -void QVNCScreenPrivate::configure() -{ - if (q_ptr->screen()) - return; - - q_ptr->lstep = q_ptr->dw * ((q_ptr->d + 7) / 8); - q_ptr->size = q_ptr->h * q_ptr->lstep; - q_ptr->mapsize = q_ptr->size; - q_ptr->physWidth = qRound(q_ptr->dw * qreal(25.4) / dpiX); - q_ptr->physHeight = qRound(q_ptr->dh * qreal(25.4) / dpiY); - - switch (q_ptr->d) { - case 1: - q_ptr->setPixelFormat(QImage::Format_Mono); //### LSB??? - break; - case 8: - q_ptr->setPixelFormat(QImage::Format_Indexed8); - break; - case 12: - q_ptr->setPixelFormat(QImage::Format_RGB444); - break; - case 15: - q_ptr->setPixelFormat(QImage::Format_RGB555); - break; - case 16: - q_ptr->setPixelFormat(QImage::Format_RGB16); - break; - case 18: - q_ptr->setPixelFormat(QImage::Format_RGB666); - break; - case 24: - q_ptr->setPixelFormat(QImage::Format_RGB888); - break; - case 32: - q_ptr->setPixelFormat(QImage::Format_ARGB32_Premultiplied); - break; - } - -#if !defined(QT_NO_QWS_MULTIPROCESS) && !defined(QT_NO_SHAREDMEMORY) - if (q_ptr->size != shm.size()) { - shm.detach(); - const QString key = qws_qtePipeFilename() + - QString().sprintf("_vnc_%d_%d", - q_ptr->displayId, q_ptr->size); - shm.setKey(key); - if (QApplication::type() == QApplication::GuiServer) { - if (!shm.create(q_ptr->size)) { - qWarning() << "QVNCScreen could not create shared memory:" - << shm.errorString(); - if (!shm.attach()) { - qWarning() << "QVNCScreen could not attach to shared memory:" - << shm.errorString(); - } - } - } else if (!shm.attach()) { - qWarning() << "QVNCScreen could not attach to shared memory:" - << shm.errorString(); - } - q_ptr->data = reinterpret_cast<uchar*>(shm.data()); - } -#else - if (q_ptr->data) - delete[] q_ptr->data; - q_ptr->data = new uchar[q_ptr->size]; -#endif -} - -//=========================================================================== - -static const struct { - int keysym; - int keycode; -} keyMap[] = { - { 0xff08, Qt::Key_Backspace }, - { 0xff09, Qt::Key_Tab }, - { 0xff0d, Qt::Key_Return }, - { 0xff1b, Qt::Key_Escape }, - { 0xff63, Qt::Key_Insert }, - { 0xffff, Qt::Key_Delete }, - { 0xff50, Qt::Key_Home }, - { 0xff57, Qt::Key_End }, - { 0xff55, Qt::Key_PageUp }, - { 0xff56, Qt::Key_PageDown }, - { 0xff51, Qt::Key_Left }, - { 0xff52, Qt::Key_Up }, - { 0xff53, Qt::Key_Right }, - { 0xff54, Qt::Key_Down }, - { 0xffbe, Qt::Key_F1 }, - { 0xffbf, Qt::Key_F2 }, - { 0xffc0, Qt::Key_F3 }, - { 0xffc1, Qt::Key_F4 }, - { 0xffc2, Qt::Key_F5 }, - { 0xffc3, Qt::Key_F6 }, - { 0xffc4, Qt::Key_F7 }, - { 0xffc5, Qt::Key_F8 }, - { 0xffc6, Qt::Key_F9 }, - { 0xffc7, Qt::Key_F10 }, - { 0xffc8, Qt::Key_F11 }, - { 0xffc9, Qt::Key_F12 }, - { 0xffe1, Qt::Key_Shift }, - { 0xffe2, Qt::Key_Shift }, - { 0xffe3, Qt::Key_Control }, - { 0xffe4, Qt::Key_Control }, - { 0xffe7, Qt::Key_Meta }, - { 0xffe8, Qt::Key_Meta }, - { 0xffe9, Qt::Key_Alt }, - { 0xffea, Qt::Key_Alt }, - - { 0xffb0, Qt::Key_0 }, - { 0xffb1, Qt::Key_1 }, - { 0xffb2, Qt::Key_2 }, - { 0xffb3, Qt::Key_3 }, - { 0xffb4, Qt::Key_4 }, - { 0xffb5, Qt::Key_5 }, - { 0xffb6, Qt::Key_6 }, - { 0xffb7, Qt::Key_7 }, - { 0xffb8, Qt::Key_8 }, - { 0xffb9, Qt::Key_9 }, - - { 0xff8d, Qt::Key_Return }, - { 0xffaa, Qt::Key_Asterisk }, - { 0xffab, Qt::Key_Plus }, - { 0xffad, Qt::Key_Minus }, - { 0xffae, Qt::Key_Period }, - { 0xffaf, Qt::Key_Slash }, - - { 0xff95, Qt::Key_Home }, - { 0xff96, Qt::Key_Left }, - { 0xff97, Qt::Key_Up }, - { 0xff98, Qt::Key_Right }, - { 0xff99, Qt::Key_Down }, - { 0xff9a, Qt::Key_PageUp }, - { 0xff9b, Qt::Key_PageDown }, - { 0xff9c, Qt::Key_End }, - { 0xff9e, Qt::Key_Insert }, - { 0xff9f, Qt::Key_Delete }, - - { 0, 0 } -}; - -void QRfbRect::read(QTcpSocket *s) -{ - quint16 buf[4]; - s->read((char*)buf, 8); - x = ntohs(buf[0]); - y = ntohs(buf[1]); - w = ntohs(buf[2]); - h = ntohs(buf[3]); -} - -void QRfbRect::write(QTcpSocket *s) const -{ - quint16 buf[4]; - buf[0] = htons(x); - buf[1] = htons(y); - buf[2] = htons(w); - buf[3] = htons(h); - s->write((char*)buf, 8); -} - -void QRfbPixelFormat::read(QTcpSocket *s) -{ - char buf[16]; - s->read(buf, 16); - bitsPerPixel = buf[0]; - depth = buf[1]; - bigEndian = buf[2]; - trueColor = buf[3]; - - quint16 a = ntohs(*(quint16 *)(buf + 4)); - redBits = 0; - while (a) { a >>= 1; redBits++; } - - a = ntohs(*(quint16 *)(buf + 6)); - greenBits = 0; - while (a) { a >>= 1; greenBits++; } - - a = ntohs(*(quint16 *)(buf + 8)); - blueBits = 0; - while (a) { a >>= 1; blueBits++; } - - redShift = buf[10]; - greenShift = buf[11]; - blueShift = buf[12]; -} - -void QRfbPixelFormat::write(QTcpSocket *s) -{ - char buf[16]; - buf[0] = bitsPerPixel; - buf[1] = depth; - buf[2] = bigEndian; - buf[3] = trueColor; - - quint16 a = 0; - for (int i = 0; i < redBits; i++) a = (a << 1) | 1; - *(quint16 *)(buf + 4) = htons(a); - - a = 0; - for (int i = 0; i < greenBits; i++) a = (a << 1) | 1; - *(quint16 *)(buf + 6) = htons(a); - - a = 0; - for (int i = 0; i < blueBits; i++) a = (a << 1) | 1; - *(quint16 *)(buf + 8) = htons(a); - - buf[10] = redShift; - buf[11] = greenShift; - buf[12] = blueShift; - s->write(buf, 16); -} - - -void QRfbServerInit::setName(const char *n) -{ - delete[] name; - name = new char [strlen(n) + 1]; - strcpy(name, n); -} - -void QRfbServerInit::read(QTcpSocket *s) -{ - s->read((char *)&width, 2); - width = ntohs(width); - s->read((char *)&height, 2); - height = ntohs(height); - format.read(s); - - quint32 len; - s->read((char *)&len, 4); - len = ntohl(len); - - name = new char [len + 1]; - s->read(name, len); - name[len] = '\0'; -} - -void QRfbServerInit::write(QTcpSocket *s) -{ - quint16 t = htons(width); - s->write((char *)&t, 2); - t = htons(height); - s->write((char *)&t, 2); - format.write(s); - quint32 len = strlen(name); - len = htonl(len); - s->write((char *)&len, 4); - s->write(name, strlen(name)); -} - -bool QRfbSetEncodings::read(QTcpSocket *s) -{ - if (s->bytesAvailable() < 3) - return false; - - char tmp; - s->read(&tmp, 1); // padding - s->read((char *)&count, 2); - count = ntohs(count); - - return true; -} - -bool QRfbFrameBufferUpdateRequest::read(QTcpSocket *s) -{ - if (s->bytesAvailable() < 9) - return false; - - s->read(&incremental, 1); - rect.read(s); - - return true; -} - -bool QRfbKeyEvent::read(QTcpSocket *s) -{ - if (s->bytesAvailable() < 7) - return false; - - s->read(&down, 1); - quint16 tmp; - s->read((char *)&tmp, 2); // padding - - quint32 key; - s->read((char *)&key, 4); - key = ntohl(key); - - unicode = 0; - keycode = 0; - int i = 0; - while (keyMap[i].keysym && !keycode) { - if (keyMap[i].keysym == (int)key) - keycode = keyMap[i].keycode; - i++; - } - - if (keycode >= ' ' && keycode <= '~') - unicode = keycode; - - if (!keycode) { - if (key <= 0xff) { - unicode = key; - if (key >= 'a' && key <= 'z') - keycode = Qt::Key_A + key - 'a'; - else if (key >= ' ' && key <= '~') - keycode = Qt::Key_Space + key - ' '; - } - } - - return true; -} - -bool QRfbPointerEvent::read(QTcpSocket *s) -{ - if (s->bytesAvailable() < 5) - return false; - - char buttonMask; - s->read(&buttonMask, 1); - buttons = 0; - if (buttonMask & 1) - buttons |= Qt::LeftButton; - if (buttonMask & 2) - buttons |= Qt::MidButton; - if (buttonMask & 4) - buttons |= Qt::RightButton; - - quint16 tmp; - s->read((char *)&tmp, 2); - x = ntohs(tmp); - s->read((char *)&tmp, 2); - y = ntohs(tmp); - - return true; -} - -bool QRfbClientCutText::read(QTcpSocket *s) -{ - if (s->bytesAvailable() < 7) - return false; - - char tmp[3]; - s->read(tmp, 3); // padding - s->read((char *)&length, 4); - length = ntohl(length); - - return true; -} - -//=========================================================================== - -QVNCServer::QVNCServer(QVNCScreen *screen) - : qvnc_screen(screen) -{ - init(5900); -} - -QVNCServer::QVNCServer(QVNCScreen *screen, int id) - : qvnc_screen(screen) -{ - init(5900 + id); -} - -void QVNCServer::init(uint port) -{ - handleMsg = false; - client = 0; - encodingsPending = 0; - cutTextPending = 0; - keymod = 0; - state = Unconnected; - dirtyCursor = false; - - refreshRate = 25; - timer = new QTimer(this); - timer->setSingleShot(true); - connect(timer, SIGNAL(timeout()), this, SLOT(checkUpdate())); - - serverSocket = new QTcpServer(this); - if (!serverSocket->listen(QHostAddress::Any, port)) - qDebug() << "QVNCServer could not connect:" << serverSocket->errorString(); - else - qDebug("QVNCServer created on port %d", port); - - connect(serverSocket, SIGNAL(newConnection()), this, SLOT(newConnection())); - -#ifndef QT_NO_QWS_CURSOR - qvnc_cursor = 0; -#endif - encoder = 0; -} - -QVNCServer::~QVNCServer() -{ - delete encoder; - encoder = 0; - delete client; - client = 0; -#ifndef QT_NO_QWS_CURSOR - delete qvnc_cursor; - qvnc_cursor = 0; -#endif -} - -void QVNCServer::setDirty() -{ - if (state == Connected && !timer->isActive() && - ((dirtyMap()->numDirty > 0) || dirtyCursor)) { - timer->start(); - } -} - -void QVNCServer::newConnection() -{ - if (client) - delete client; - - client = serverSocket->nextPendingConnection(); - connect(client,SIGNAL(readyRead()),this,SLOT(readClient())); - connect(client,SIGNAL(disconnected()),this,SLOT(discardClient())); - handleMsg = false; - encodingsPending = 0; - cutTextPending = 0; - supportHextile = false; - wantUpdate = false; - - timer->start(1000 / refreshRate); - dirtyMap()->reset(); - - // send protocol version - const char *proto = "RFB 003.003\n"; - client->write(proto, 12); - state = Protocol; - - if (!qvnc_screen->screen() && !qvnc_screen->d_ptr->noDisablePainting) - QWSServer::instance()->enablePainting(true); -} - -void QVNCServer::readClient() -{ - switch (state) { - case Protocol: - if (client->bytesAvailable() >= 12) { - char proto[13]; - client->read(proto, 12); - proto[12] = '\0'; - qDebug("Client protocol version %s", proto); - // No authentication - quint32 auth = htonl(1); - client->write((char *) &auth, sizeof(auth)); - state = Init; - } - break; - - case Init: - if (client->bytesAvailable() >= 1) { - quint8 shared; - client->read((char *) &shared, 1); - - // Server Init msg - QRfbServerInit sim; - QRfbPixelFormat &format = sim.format; - switch (qvnc_screen->depth()) { - case 32: - format.bitsPerPixel = 32; - format.depth = 32; - format.bigEndian = 0; - format.trueColor = true; - format.redBits = 8; - format.greenBits = 8; - format.blueBits = 8; - format.redShift = 16; - format.greenShift = 8; - format.blueShift = 0; - break; - - case 24: - format.bitsPerPixel = 24; - format.depth = 24; - format.bigEndian = 0; - format.trueColor = true; - format.redBits = 8; - format.greenBits = 8; - format.blueBits = 8; - format.redShift = 16; - format.greenShift = 8; - format.blueShift = 0; - break; - - case 18: - format.bitsPerPixel = 24; - format.depth = 18; - format.bigEndian = 0; - format.trueColor = true; - format.redBits = 6; - format.greenBits = 6; - format.blueBits = 6; - format.redShift = 12; - format.greenShift = 6; - format.blueShift = 0; - break; - - case 16: - format.bitsPerPixel = 16; - format.depth = 16; - format.bigEndian = 0; - format.trueColor = true; - format.redBits = 5; - format.greenBits = 6; - format.blueBits = 5; - format.redShift = 11; - format.greenShift = 5; - format.blueShift = 0; - break; - - case 15: - format.bitsPerPixel = 16; - format.depth = 15; - format.bigEndian = 0; - format.trueColor = true; - format.redBits = 5; - format.greenBits = 5; - format.blueBits = 5; - format.redShift = 10; - format.greenShift = 5; - format.blueShift = 0; - break; - - case 12: - format.bitsPerPixel = 16; - format.depth = 12; - format.bigEndian = 0; - format.trueColor = true; - format.redBits = 4; - format.greenBits = 4; - format.blueBits = 4; - format.redShift = 8; - format.greenShift = 4; - format.blueShift = 0; - break; - - case 8: - case 4: - format.bitsPerPixel = 8; - format.depth = 8; - format.bigEndian = 0; - format.trueColor = false; - format.redBits = 0; - format.greenBits = 0; - format.blueBits = 0; - format.redShift = 0; - format.greenShift = 0; - format.blueShift = 0; - break; - - default: - qDebug("QVNC cannot drive depth %d", qvnc_screen->depth()); - discardClient(); - return; - } - sim.width = qvnc_screen->deviceWidth(); - sim.height = qvnc_screen->deviceHeight(); - sim.setName("Qt for Embedded Linux VNC Server"); - sim.write(client); - state = Connected; - } - break; - - case Connected: - do { - if (!handleMsg) { - client->read((char *)&msgType, 1); - handleMsg = true; - } - if (handleMsg) { - switch (msgType ) { - case SetPixelFormat: - setPixelFormat(); - break; - case FixColourMapEntries: - qDebug("Not supported: FixColourMapEntries"); - handleMsg = false; - break; - case SetEncodings: - setEncodings(); - break; - case FramebufferUpdateRequest: - frameBufferUpdateRequest(); - break; - case KeyEvent: - keyEvent(); - break; - case PointerEvent: - pointerEvent(); - break; - case ClientCutText: - clientCutText(); - break; - default: - qDebug("Unknown message type: %d", (int)msgType); - handleMsg = false; - } - } - } while (!handleMsg && client->bytesAvailable()); - break; - default: - break; - } -} - -#if Q_BYTE_ORDER == Q_BIG_ENDIAN -bool QVNCScreen::swapBytes() const -{ - if (depth() != 16) - return false; - - if (screen()) - return screen()->frameBufferLittleEndian(); - return frameBufferLittleEndian(); -} -#endif - -void QVNCServer::setPixelFormat() -{ - if (client->bytesAvailable() >= 19) { - char buf[3]; - client->read(buf, 3); // just padding - pixelFormat.read(client); -#ifdef QT_QWS_VNC_DEBUG - qDebug("Want format: %d %d %d %d %d %d %d %d %d %d", - int(pixelFormat.bitsPerPixel), - int(pixelFormat.depth), - int(pixelFormat.bigEndian), - int(pixelFormat.trueColor), - int(pixelFormat.redBits), - int(pixelFormat.greenBits), - int(pixelFormat.blueBits), - int(pixelFormat.redShift), - int(pixelFormat.greenShift), - int(pixelFormat.blueShift)); -#endif - if (!pixelFormat.trueColor) { - qDebug("Can only handle true color clients"); - discardClient(); - } - handleMsg = false; - sameEndian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) == !!pixelFormat.bigEndian; - needConversion = pixelConversionNeeded(); -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - swapBytes = qvnc_screen->swapBytes(); -#endif - } -} - -void QVNCServer::setEncodings() -{ - QRfbSetEncodings enc; - - if (!encodingsPending && enc.read(client)) { - encodingsPending = enc.count; - if (!encodingsPending) - handleMsg = false; - } - - if (encoder) { - delete encoder; - encoder = 0; - } - - enum Encodings { - Raw = 0, - CopyRect = 1, - RRE = 2, - CoRRE = 4, - Hextile = 5, - ZRLE = 16, - Cursor = -239, - DesktopSize = -223 - }; - - if (encodingsPending && (unsigned)client->bytesAvailable() >= - encodingsPending * sizeof(quint32)) { - for (int i = 0; i < encodingsPending; ++i) { - qint32 enc; - client->read((char *)&enc, sizeof(qint32)); - enc = ntohl(enc); -#ifdef QT_QWS_VNC_DEBUG - qDebug("QVNCServer::setEncodings: %d", enc); -#endif - switch (enc) { - case Raw: - if (!encoder) { - encoder = new QRfbRawEncoder(this); -#ifdef QT_QWS_VNC_DEBUG - qDebug("QVNCServer::setEncodings: using raw"); -#endif - } - break; - case CopyRect: - supportCopyRect = true; - break; - case RRE: - supportRRE = true; - break; - case CoRRE: - supportCoRRE = true; - break; - case Hextile: - supportHextile = true; - if (encoder) - break; - switch (qvnc_screen->depth()) { -#ifdef QT_QWS_DEPTH_8 - case 8: - encoder = new QRfbHextileEncoder<quint8>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_12 - case 12: - encoder = new QRfbHextileEncoder<qrgb444>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_15 - case 15: - encoder = new QRfbHextileEncoder<qrgb555>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_16 - case 16: - encoder = new QRfbHextileEncoder<quint16>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_18 - case 18: - encoder = new QRfbHextileEncoder<qrgb666>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_24 - case 24: - encoder = new QRfbHextileEncoder<qrgb888>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_32 - case 32: - encoder = new QRfbHextileEncoder<quint32>(this); - break; -#endif - default: - break; - } -#ifdef QT_QWS_VNC_DEBUG - qDebug("QVNCServer::setEncodings: using hextile"); -#endif - break; - case ZRLE: - supportZRLE = true; - break; - case Cursor: - supportCursor = true; -#ifndef QT_NO_QWS_CURSOR - if (!qvnc_screen->screen() || qt_screencursor->isAccelerated()) { - delete qvnc_cursor; - qvnc_cursor = new QVNCClientCursor(this); - } -#endif - break; - case DesktopSize: - supportDesktopSize = true; - break; - default: - break; - } - } - handleMsg = false; - encodingsPending = 0; - } - - if (!encoder) { - encoder = new QRfbRawEncoder(this); -#ifdef QT_QWS_VNC_DEBUG - qDebug("QVNCServer::setEncodings: fallback using raw"); -#endif - } -} - -void QVNCServer::frameBufferUpdateRequest() -{ - QRfbFrameBufferUpdateRequest ev; - - if (ev.read(client)) { - if (!ev.incremental) { - QRect r(ev.rect.x, ev.rect.y, ev.rect.w, ev.rect.h); - r.translate(qvnc_screen->offset()); - qvnc_screen->d_ptr->setDirty(r, true); - } - wantUpdate = true; - checkUpdate(); - handleMsg = false; - } -} - -void QVNCServer::pointerEvent() -{ - QRfbPointerEvent ev; - if (ev.read(client)) { - const QPoint offset = qvnc_screen->offset(); - QWSServer::sendMouseEvent(offset + QPoint(ev.x, ev.y), ev.buttons); - handleMsg = false; - } -} - -void QVNCServer::keyEvent() -{ - QRfbKeyEvent ev; - - if (ev.read(client)) { - if (ev.keycode == Qt::Key_Shift) - keymod = ev.down ? keymod | Qt::ShiftModifier : - keymod & ~Qt::ShiftModifier; - else if (ev.keycode == Qt::Key_Control) - keymod = ev.down ? keymod | Qt::ControlModifier : - keymod & ~Qt::ControlModifier; - else if (ev.keycode == Qt::Key_Alt) - keymod = ev.down ? keymod | Qt::AltModifier : - keymod & ~Qt::AltModifier; - if (ev.unicode || ev.keycode) - QWSServer::sendKeyEvent(ev.unicode, ev.keycode, keymod, ev.down, false); - handleMsg = false; - } -} - -void QVNCServer::clientCutText() -{ - QRfbClientCutText ev; - - if (cutTextPending == 0 && ev.read(client)) { - cutTextPending = ev.length; - if (!cutTextPending) - handleMsg = false; - } - - if (cutTextPending && client->bytesAvailable() >= cutTextPending) { - char *text = new char [cutTextPending+1]; - client->read(text, cutTextPending); - delete [] text; - cutTextPending = 0; - handleMsg = false; - } -} - -// stride in bytes -template <class SRC> -bool QRfbSingleColorHextile<SRC>::read(const uchar *data, - int width, int height, int stride) -{ - const int depth = encoder->server->screen()->depth(); - if (width % (depth / 8)) // hw: should rather fallback to simple loop - return false; - - static int alwaysFalse = qgetenv("QT_VNC_NOCHECKFILL").toInt(); - if (alwaysFalse) - return false; - - switch (depth) { - case 4: { - const quint8 *data8 = reinterpret_cast<const quint8*>(data); - if ((data8[0] & 0xf) != (data8[0] >> 4)) - return false; - width /= 2; - } // fallthrough - case 8: { - const quint8 *data8 = reinterpret_cast<const quint8*>(data); - if (data8[0] != data8[1]) - return false; - width /= 2; - } // fallthrough - case 12: - case 15: - case 16: { - const quint16 *data16 = reinterpret_cast<const quint16*>(data); - if (data16[0] != data16[1]) - return false; - width /= 2; - } // fallthrough - case 18: - case 24: - case 32: { - const quint32 *data32 = reinterpret_cast<const quint32*>(data); - const quint32 first = data32[0]; - const int linestep = (stride / sizeof(quint32)) - width; - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - if (*(data32++) != first) - return false; - } - data32 += linestep; - } - break; - } - default: - return false; - } - - SRC color = reinterpret_cast<const SRC*>(data)[0]; - encoder->newBg |= (color != encoder->bg); - encoder->bg = color; - return true; -} - -template <class SRC> -void QRfbSingleColorHextile<SRC>::write(QTcpSocket *socket) const -{ - if (true || encoder->newBg) { - const int bpp = encoder->server->clientBytesPerPixel(); - const int padding = 3; - QVarLengthArray<char> buffer(padding + 1 + bpp); - buffer[padding] = 2; // BackgroundSpecified - encoder->server->convertPixels(buffer.data() + padding + 1, - reinterpret_cast<char*>(&encoder->bg), - 1); - socket->write(buffer.data() + padding, bpp + 1); -// encoder->newBg = false; - } else { - char subenc = 0; - socket->write(&subenc, 1); - } -} - -template <class SRC> -bool QRfbDualColorHextile<SRC>::read(const uchar *data, - int width, int height, int stride) -{ - const SRC *ptr = reinterpret_cast<const SRC*>(data); - const int linestep = (stride / sizeof(SRC)) - width; - - SRC c1; - SRC c2 = 0; - int n1 = 0; - int n2 = 0; - int x = 0; - int y = 0; - - c1 = *ptr; - - // find second color - while (y < height) { - while (x < width) { - if (*ptr == c1) { - ++n1; - } else { - c2 = *ptr; - goto found_second_color; - } - ++ptr; - ++x; - } - x = 0; - ptr += linestep; - ++y; - } - -found_second_color: - // finish counting - while (y < height) { - while (x < width) { - if (*ptr == c1) { - ++n1; - } else if (*ptr == c2) { - ++n2; - } else { - return false; - } - ++ptr; - ++x; - } - x = 0; - ptr += linestep; - ++y; - } - - if (n2 > n1) { - const quint32 tmpC = c1; - c1 = c2; - c2 = tmpC; - } - - encoder->newBg |= (c1 != encoder->bg); - encoder->newFg |= (c2 != encoder->fg); - - encoder->bg = c1; - encoder->fg = c2; - - // create map - bool inRect = false; - numRects = 0; - ptr = reinterpret_cast<const SRC*>(data); - for (y = 0; y < height; ++y) { - for (x = 0; x < width; ++x) { - if (inRect && *ptr == encoder->bg) { - // rect finished - setWidth(x - lastx()); - next(); - inRect = false; - } else if (!inRect && *ptr == encoder->fg) { - // rect start - setX(x); - setY(y); - setHeight(1); - inRect = true; - } - ++ptr; - } - if (inRect) { - // finish rect - setWidth(width - lastx()); - next(); - inRect = false; - } - ptr += linestep; - } - - return true; -} - -template <class SRC> -void QRfbDualColorHextile<SRC>::write(QTcpSocket *socket) const -{ - const int bpp = encoder->server->clientBytesPerPixel(); - const int padding = 3; - QVarLengthArray<char> buffer(padding + 2 * bpp + sizeof(char) + sizeof(numRects)); - char &subenc = buffer[padding]; - int n = padding + sizeof(subenc); - - subenc = 0x8; // AnySubrects - - if (encoder->newBg) { - subenc |= 0x2; // Background - encoder->server->convertPixels(buffer.data() + n, (char*)&encoder->bg, 1); - n += bpp; -// encoder->newBg = false; - } - - if (encoder->newFg) { - subenc |= 0x4; // Foreground - encoder->server->convertPixels(buffer.data() + n, (char*)&encoder->fg, 1); - n += bpp; -// encoder->newFg = false; - } - buffer[n] = numRects; - n += sizeof(numRects); - - socket->write(buffer.data() + padding, n - padding); - socket->write((char*)rects, numRects * sizeof(Rect)); -} - -template <class SRC> -void QRfbDualColorHextile<SRC>::next() -{ - for (int r = numRects - 1; r >= 0; --r) { - if (recty(r) == lasty()) - continue; - if (recty(r) < lasty() - 1) // only search previous scanline - break; - if (rectx(r) == lastx() && width(r) == width(numRects)) { - ++rects[r].wh; - return; - } - } - ++numRects; -} - -template <class SRC> -inline void QRfbMultiColorHextile<SRC>::setColor(SRC color) -{ - encoder->server->convertPixels(reinterpret_cast<char*>(rect(numRects)), - (const char*)&color, 1); -} - -template <class SRC> -inline bool QRfbMultiColorHextile<SRC>::beginRect() -{ - if ((rects.size() + bpp + 2) > maxRectsSize) - return false; - rects.resize(rects.size() + bpp + 2); - return true; -} - -template <class SRC> -inline void QRfbMultiColorHextile<SRC>::endRect() -{ - setHeight(numRects, 1); - ++numRects; -} - -template <class SRC> -bool QRfbMultiColorHextile<SRC>::read(const uchar *data, - int width, int height, int stride) -{ - const SRC *ptr = reinterpret_cast<const SRC*>(data); - const int linestep = (stride / sizeof(SRC)) - width; - - bpp = encoder->server->clientBytesPerPixel(); - - if (encoder->newBg) - encoder->bg = ptr[0]; - - const SRC bg = encoder->bg; - SRC color = bg; - bool inRect = false; - - numRects = 0; - rects.clear(); - - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - if (inRect && *ptr != color) { // end rect - setWidth(numRects, x - rectx(numRects)); - endRect(); - inRect = false; - } - - if (!inRect && *ptr != bg) { // begin rect - if (!beginRect()) - return false; - inRect = true; - color = *ptr; - setColor(color); - setX(numRects, x); - setY(numRects, y); - } - ++ptr; - } - if (inRect) { // end rect - setWidth(numRects, width - rectx(numRects)); - endRect(); - inRect = false; - } - ptr += linestep; - } - - return true; -} - -template <class SRC> -void QRfbMultiColorHextile<SRC>::write(QTcpSocket *socket) const -{ - const int padding = 3; - QVarLengthArray<quint8> buffer(bpp + padding + sizeof(quint8) + sizeof(numRects)); - - quint8 &subenc = buffer[padding]; - int n = padding + sizeof(quint8); - - subenc = 8 | 16; // AnySubrects | SubrectsColoured - - if (encoder->newBg) { - subenc |= 0x2; // Background - encoder->server->convertPixels(reinterpret_cast<char*>(buffer.data() + n), - reinterpret_cast<const char*>(&encoder->bg), - 1); - n += bpp; -// encoder->newBg = false; - } - - buffer[n] = numRects; - n += sizeof(numRects); - - socket->write(reinterpret_cast<const char*>(buffer.data() + padding), - n - padding); - socket->write(reinterpret_cast<const char*>(rects.constData()), - rects.size()); -} - -bool QVNCServer::pixelConversionNeeded() const -{ - if (!sameEndian) - return true; - -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - if (qvnc_screen->swapBytes()) - return true; -#endif - - const int screendepth = qvnc_screen->depth(); - if (screendepth != pixelFormat.bitsPerPixel) - return true; - - switch (screendepth) { - case 32: - case 24: - return false; - case 18: - return (pixelFormat.redBits == 6 - && pixelFormat.greenBits == 6 - && pixelFormat.blueBits == 6); - case 16: - return (pixelFormat.redBits == 5 - && pixelFormat.greenBits == 6 - && pixelFormat.blueBits == 5); - case 15: - return (pixelFormat.redBits == 5 - && pixelFormat.greenBits == 5 - && pixelFormat.blueBits == 5); - case 12: - return (pixelFormat.redBits == 4 - && pixelFormat.greenBits == 4 - && pixelFormat.blueBits == 4); - } - return true; -} - -// count: number of pixels -void QVNCServer::convertPixels(char *dst, const char *src, int count) const -{ - const int screendepth = qvnc_screen->depth(); - const bool isBgr = qvnc_screen->pixelType() == QScreen::BGRPixel; - - // cutoffs -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - if (!swapBytes) -#endif - if (sameEndian) { - if (screendepth == pixelFormat.bitsPerPixel) { // memcpy cutoffs - - switch (screendepth) { - case 32: - memcpy(dst, src, count * sizeof(quint32)); - return; - case 16: - if (pixelFormat.redBits == 5 - && pixelFormat.greenBits == 6 - && pixelFormat.blueBits == 5) - { - memcpy(dst, src, count * sizeof(quint16)); - return; - } - } - } else if (screendepth == 16 && pixelFormat.bitsPerPixel == 32) { -#if defined(__i386__) // Currently fails on ARM if dst is not 4 byte aligned - const quint32 *src32 = reinterpret_cast<const quint32*>(src); - quint32 *dst32 = reinterpret_cast<quint32*>(dst); - int count32 = count * sizeof(quint16) / sizeof(quint32); - while (count32--) { - const quint32 s = *src32++; - quint32 result1; - quint32 result2; - - // red - result1 = ((s & 0xf8000000) | ((s & 0xe0000000) >> 5)) >> 8; - result2 = ((s & 0x0000f800) | ((s & 0x0000e000) >> 5)) << 8; - - // green - result1 |= ((s & 0x07e00000) | ((s & 0x06000000) >> 6)) >> 11; - result2 |= ((s & 0x000007e0) | ((s & 0x00000600) >> 6)) << 5; - - // blue - result1 |= ((s & 0x001f0000) | ((s & 0x001c0000) >> 5)) >> 13; - result2 |= ((s & 0x0000001f) | ((s & 0x0000001c) >> 5)) << 3; - - *dst32++ = result2; - *dst32++ = result1; - } - if (count & 0x1) { - const quint16 *src16 = reinterpret_cast<const quint16*>(src); - *dst32 = qt_conv16ToRgb(src16[count - 1]); - } - return; -#endif - } - } - - const int bytesPerPixel = (pixelFormat.bitsPerPixel + 7) / 8; - -// nibble = 0; - - for (int i = 0; i < count; ++i) { - int r, g, b; - - switch (screendepth) { -#if 0 - case 4: { - if (!nibble) { - r = ((*src) & 0x0f) << 4; - } else { - r = (*src) & 0xf0; - src++; - } - nibble = !nibble; - g = b = r; - break; - } -#endif - case 8: { - QRgb rgb = qvnc_screen->clut()[int(*src)]; - r = qRed(rgb); - g = qGreen(rgb); - b = qBlue(rgb); - src++; - break; - } -#ifdef QT_QWS_DEPTH_12 - case 12: { - quint32 p = quint32(*reinterpret_cast<const qrgb444*>(src)); - r = qRed(p); - g = qGreen(p); - b = qBlue(p); - src += sizeof(qrgb444); - break; - } -#endif -#ifdef QT_QWS_DEPTH_15 - case 15: { - quint32 p = quint32(*reinterpret_cast<const qrgb555*>(src)); - r = qRed(p); - g = qGreen(p); - b = qBlue(p); - src += sizeof(qrgb555); - break; - } -#endif - case 16: { - quint16 p = *reinterpret_cast<const quint16*>(src); -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - if (swapBytes) - p = ((p & 0xff) << 8) | ((p & 0xff00) >> 8); -#endif - r = (p >> 11) & 0x1f; - g = (p >> 5) & 0x3f; - b = p & 0x1f; - r <<= 3; - g <<= 2; - b <<= 3; - src += sizeof(quint16); - break; - } -#ifdef QT_QWS_DEPTH_18 - case 18: { - quint32 p = quint32(*reinterpret_cast<const qrgb666*>(src)); - r = qRed(p); - g = qGreen(p); - b = qBlue(p); - src += sizeof(qrgb666); - break; - } -#endif -#ifdef QT_QWS_DEPTH_24 - case 24: { - quint32 p = quint32(*reinterpret_cast<const qrgb888*>(src)); - r = qRed(p); - g = qGreen(p); - b = qBlue(p); - src += sizeof(qrgb888); - break; - } -#endif - case 32: { - quint32 p = *reinterpret_cast<const quint32*>(src); - r = (p >> 16) & 0xff; - g = (p >> 8) & 0xff; - b = p & 0xff; - src += sizeof(quint32); - break; - } - default: { - r = g = b = 0; - qDebug("QVNCServer: don't support %dbpp display", screendepth); - return; - } - } - -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - if (swapBytes ^ isBgr) -#else - if (isBgr) -#endif - qSwap(r, b); - - r >>= (8 - pixelFormat.redBits); - g >>= (8 - pixelFormat.greenBits); - b >>= (8 - pixelFormat.blueBits); - - int pixel = (r << pixelFormat.redShift) | - (g << pixelFormat.greenShift) | - (b << pixelFormat.blueShift); - - if (sameEndian || pixelFormat.bitsPerPixel == 8) { - memcpy(dst, &pixel, bytesPerPixel); // XXX: do a simple for-loop instead? - dst += bytesPerPixel; - continue; - } - - - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - switch (pixelFormat.bitsPerPixel) { - case 16: - pixel = (((pixel & 0x0000ff00) << 8) | - ((pixel & 0x000000ff) << 24)); - break; - case 32: - pixel = (((pixel & 0xff000000) >> 24) | - ((pixel & 0x00ff0000) >> 8) | - ((pixel & 0x0000ff00) << 8) | - ((pixel & 0x000000ff) << 24)); - break; - default: - qDebug("Cannot handle %d bpp client", pixelFormat.bitsPerPixel); - } - } else { // QSysInfo::ByteOrder == QSysInfo::LittleEndian - switch (pixelFormat.bitsPerPixel) { - case 16: - pixel = (((pixel & 0xff000000) >> 8) | - ((pixel & 0x00ff0000) << 8)); - break; - case 32: - pixel = (((pixel & 0xff000000) >> 24) | - ((pixel & 0x00ff0000) >> 8) | - ((pixel & 0x0000ff00) << 8) | - ((pixel & 0x000000ff) << 24)); - break; - default: - qDebug("Cannot handle %d bpp client", - pixelFormat.bitsPerPixel); - break; - } - } - memcpy(dst, &pixel, bytesPerPixel); // XXX: simple for-loop instead? - dst += bytesPerPixel; - } -} - -#ifndef QT_NO_QWS_CURSOR -static void blendCursor(QImage &image, const QRect &imageRect) -{ - const QRect cursorRect = qt_screencursor->boundingRect(); - const QRect intersection = (cursorRect & imageRect); - const QRect destRect = intersection.translated(-imageRect.topLeft()); - const QRect srcRect = intersection.translated(-cursorRect.topLeft()); - - QPainter painter(&image); - painter.drawImage(destRect, qt_screencursor->image(), srcRect); - painter.end(); -} -#endif // QT_NO_QWS_CURSOR - -QVNCDirtyMap::QVNCDirtyMap(QScreen *s) - : bytesPerPixel(0), numDirty(0), screen(s) -{ - bytesPerPixel = (screen->depth() + 7) / 8; - bufferWidth = screen->deviceWidth(); - bufferHeight = screen->deviceHeight(); - bufferStride = bufferWidth * bytesPerPixel; - buffer = new uchar[bufferHeight * bufferStride]; - - mapWidth = (bufferWidth + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE; - mapHeight = (bufferHeight + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE; - numTiles = mapWidth * mapHeight; - map = new uchar[numTiles]; -} - -QVNCDirtyMap::~QVNCDirtyMap() -{ - delete[] map; - delete[] buffer; -} - -void QVNCDirtyMap::reset() -{ - memset(map, 1, numTiles); - memset(buffer, 0, bufferHeight * bufferStride); - numDirty = numTiles; -} - -inline bool QVNCDirtyMap::dirty(int x, int y) const -{ - return map[y * mapWidth + x]; -} - -inline void QVNCDirtyMap::setClean(int x, int y) -{ - map[y * mapWidth + x] = 0; - --numDirty; -} - -template <class T> -void QVNCDirtyMapOptimized<T>::setDirty(int tileX, int tileY, bool force) -{ - static bool alwaysForce = qgetenv("QT_VNC_NO_COMPAREBUFFER").toInt(); - if (alwaysForce) - force = true; - - bool changed = false; - - if (!force) { - const int lstep = screen->linestep(); - const int startX = tileX * MAP_TILE_SIZE; - const int startY = tileY * MAP_TILE_SIZE; - const uchar *scrn = screen->base() - + startY * lstep + startX * bytesPerPixel; - uchar *old = buffer + startY * bufferStride + startX * sizeof(T); - - const int tileHeight = (startY + MAP_TILE_SIZE > bufferHeight ? - bufferHeight - startY : MAP_TILE_SIZE); - const int tileWidth = (startX + MAP_TILE_SIZE > bufferWidth ? - bufferWidth - startX : MAP_TILE_SIZE); - const bool doInlines = (tileWidth == MAP_TILE_SIZE); - - int y = tileHeight; - - if (doInlines) { // hw: memcmp/memcpy is inlined when using constants - while (y) { - if (memcmp(old, scrn, sizeof(T) * MAP_TILE_SIZE)) { - changed = true; - break; - } - scrn += lstep; - old += bufferStride; - --y; - } - - while (y) { - memcpy(old, scrn, sizeof(T) * MAP_TILE_SIZE); - scrn += lstep; - old += bufferStride; - --y; - } - } else { - while (y) { - if (memcmp(old, scrn, sizeof(T) * tileWidth)) { - changed = true; - break; - } - scrn += lstep; - old += bufferStride; - --y; - } - - while (y) { - memcpy(old, scrn, sizeof(T) * tileWidth); - scrn += lstep; - old += bufferStride; - --y; - } - } - } - - const int mapIndex = tileY * mapWidth + tileX; - if ((force || changed) && !map[mapIndex]) { - map[mapIndex] = 1; - ++numDirty; - } -} - -template <class SRC> -QRfbHextileEncoder<SRC>::QRfbHextileEncoder(QVNCServer *s) - : QRfbEncoder(s), - singleColorHextile(this), dualColorHextile(this), multiColorHextile(this) -{ -} - -/* - \internal - Send dirty rects using hextile encoding. -*/ -template <class SRC> -void QRfbHextileEncoder<SRC>::write() -{ - QWSDisplay::grab(true); - - QVNCDirtyMap *map = server->dirtyMap(); - QTcpSocket *socket = server->clientSocket(); - - const quint32 encoding = htonl(5); // hextile encoding - const int bytesPerPixel = server->clientBytesPerPixel(); - - { - const char tmp[2] = { 0, 0 }; // msg type, padding - socket->write(tmp, sizeof(tmp)); - } - { - const quint16 count = htons(map->numDirty); - socket->write((char *)&count, sizeof(count)); - } - - if (map->numDirty <= 0) { - QWSDisplay::ungrab(); - return; - } - - newBg = true; - newFg = true; - - const QImage screenImage = server->screenImage(); - QRfbRect rect(0, 0, MAP_TILE_SIZE, MAP_TILE_SIZE); - - for (int y = 0; y < map->mapHeight; ++y) { - if (rect.y + MAP_TILE_SIZE > server->screen()->height()) - rect.h = server->screen()->height() - rect.y; - rect.w = MAP_TILE_SIZE; - for (int x = 0; x < map->mapWidth; ++x) { - if (!map->dirty(x, y)) - continue; - map->setClean(x, y); - - rect.x = x * MAP_TILE_SIZE; - if (rect.x + MAP_TILE_SIZE > server->screen()->deviceWidth()) - rect.w = server->screen()->deviceWidth() - rect.x; - rect.write(socket); - - socket->write((char *)&encoding, sizeof(encoding)); - - const uchar *screendata = screenImage.scanLine(rect.y) - + rect.x * screenImage.depth() / 8; - int linestep = screenImage.bytesPerLine(); - -#ifndef QT_NO_QWS_CURSOR - // hardware cursors must be blended with the screen memory - const bool doBlendCursor = qt_screencursor - && !server->hasClientCursor() - && qt_screencursor->isAccelerated(); - QImage tileImage; - if (doBlendCursor) { - const QRect tileRect(rect.x, rect.y, rect.w, rect.h); - const QRect cursorRect = qt_screencursor->boundingRect() - .translated(-server->screen()->offset()); - if (tileRect.intersects(cursorRect)) { - tileImage = screenImage.copy(tileRect); - blendCursor(tileImage, - tileRect.translated(server->screen()->offset())); - screendata = tileImage.bits(); - linestep = tileImage.bytesPerLine(); - } - } -#endif // QT_NO_QWS_CURSOR - - if (singleColorHextile.read(screendata, rect.w, rect.h, linestep)) { - singleColorHextile.write(socket); - } else if (dualColorHextile.read(screendata, rect.w, rect.h, linestep)) { - dualColorHextile.write(socket); - } else if (multiColorHextile.read(screendata, rect.w, rect.h, linestep)) { - multiColorHextile.write(socket); - } else if (server->doPixelConversion()) { - const int bufferSize = rect.w * rect.h * bytesPerPixel + 1; - const int padding = sizeof(quint32) - sizeof(char); - buffer.resize(bufferSize + padding); - - buffer[padding] = 1; // Raw subencoding - - // convert pixels - char *b = buffer.data() + padding + 1; - const int bstep = rect.w * bytesPerPixel; - for (int i = 0; i < rect.h; ++i) { - server->convertPixels(b, (const char*)screendata, rect.w); - screendata += linestep; - b += bstep; - } - socket->write(buffer.constData() + padding, bufferSize); - } else { - quint8 subenc = 1; // Raw subencoding - socket->write((char *)&subenc, 1); - - // send pixels - for (int i = 0; i < rect.h; ++i) { - socket->write((const char*)screendata, - rect.w * bytesPerPixel); - screendata += linestep; - } - } - } - if (socket->state() == QAbstractSocket::UnconnectedState) - break; - rect.y += MAP_TILE_SIZE; - } - socket->flush(); - Q_ASSERT(map->numDirty == 0); - - QWSDisplay::ungrab(); -} - -void QRfbRawEncoder::write() -{ - QWSDisplay::grab(false); - - QVNCDirtyMap *map = server->dirtyMap(); - QTcpSocket *socket = server->clientSocket(); - - const int bytesPerPixel = server->clientBytesPerPixel(); - - // create a region from the dirty rects and send the region's merged rects. - QRegion rgn; - if (map) { - for (int y = 0; y < map->mapHeight; ++y) { - for (int x = 0; x < map->mapWidth; ++x) { - if (!map->dirty(x, y)) - continue; - rgn += QRect(x * MAP_TILE_SIZE, y * MAP_TILE_SIZE, - MAP_TILE_SIZE, MAP_TILE_SIZE); - map->setClean(x, y); - } - } - - rgn &= QRect(0, 0, server->screen()->deviceWidth(), - server->screen()->deviceHeight()); - } - const QVector<QRect> rects = rgn.rects(); - - { - const char tmp[2] = { 0, 0 }; // msg type, padding - socket->write(tmp, sizeof(tmp)); - } - - { - const quint16 count = htons(rects.size()); - socket->write((char *)&count, sizeof(count)); - } - - if (rects.size() <= 0) { - QWSDisplay::ungrab(); - return; - } - - const QImage screenImage = server->screenImage(); - - for (int i = 0; i < rects.size(); ++i) { - const QRect tileRect = rects.at(i); - const QRfbRect rect(tileRect.x(), tileRect.y(), - tileRect.width(), tileRect.height()); - rect.write(socket); - - const quint32 encoding = htonl(0); // raw encoding - socket->write((char *)&encoding, sizeof(encoding)); - - int linestep = screenImage.bytesPerLine(); - const uchar *screendata = screenImage.scanLine(rect.y) - + rect.x * screenImage.depth() / 8; - -#ifndef QT_NO_QWS_CURSOR - // hardware cursors must be blended with the screen memory - const bool doBlendCursor = qt_screencursor - && !server->hasClientCursor() - && qt_screencursor->isAccelerated(); - QImage tileImage; - if (doBlendCursor) { - const QRect cursorRect = qt_screencursor->boundingRect() - .translated(-server->screen()->offset()); - if (tileRect.intersects(cursorRect)) { - tileImage = screenImage.copy(tileRect); - blendCursor(tileImage, - tileRect.translated(server->screen()->offset())); - screendata = tileImage.bits(); - linestep = tileImage.bytesPerLine(); - } - } -#endif // QT_NO_QWS_CURSOR - - if (server->doPixelConversion()) { - const int bufferSize = rect.w * rect.h * bytesPerPixel; - if (bufferSize > buffer.size()) - buffer.resize(bufferSize); - - // convert pixels - char *b = buffer.data(); - const int bstep = rect.w * bytesPerPixel; - for (int i = 0; i < rect.h; ++i) { - server->convertPixels(b, (const char*)screendata, rect.w); - screendata += linestep; - b += bstep; - } - socket->write(buffer.constData(), bufferSize); - } else { - for (int i = 0; i < rect.h; ++i) { - socket->write((const char*)screendata, rect.w * bytesPerPixel); - screendata += linestep; - } - } - if (socket->state() == QAbstractSocket::UnconnectedState) - break; - } - socket->flush(); - - QWSDisplay::ungrab(); -} - -inline QImage QVNCServer::screenImage() const -{ - return QImage(qvnc_screen->base(), qvnc_screen->deviceWidth(), - qvnc_screen->deviceHeight(), qvnc_screen->linestep(), - qvnc_screen->pixelFormat()); -} - -void QVNCServer::checkUpdate() -{ - if (!wantUpdate) - return; - - if (dirtyCursor) { -#ifndef QT_NO_QWS_CURSOR - Q_ASSERT(qvnc_cursor); - qvnc_cursor->write(); -#endif - dirtyCursor = false; - wantUpdate = false; - return; - } - - if (dirtyMap()->numDirty > 0) { - if (encoder) - encoder->write(); - wantUpdate = false; - } -} - -void QVNCServer::discardClient() -{ - timer->stop(); - state = Unconnected; - delete encoder; - encoder = 0; -#ifndef QT_NO_QWS_CURSOR - delete qvnc_cursor; - qvnc_cursor = 0; -#endif - if (!qvnc_screen->screen() && !qvnc_screen->d_ptr->noDisablePainting && QWSServer::instance()) - QWSServer::instance()->enablePainting(false); -} - - -//=========================================================================== - -/*! - \class QVNCScreen - \internal - \ingroup qws - - \brief The QVNCScreen class implements a screen driver for VNC - servers. - - Note that this class is only available in \l{Qt for Embedded Linux}. - Custom screen drivers can be added by subclassing the QScreen - class, using the QScreenDriverFactory class to dynamically load - the driver into the application. - - The VNC protocol allows you to view and interact with the - computer's display from anywhere on the network. See the - \l{The VNC Protocol and Qt for Embedded Linux}{VNC protocol} - documentation for more details. - - The default implementation of QVNCScreen inherits QLinuxFbScreen, - but any QScreen subclass, or QScreen itself, can serve as its base - class. This is easily achieved by manipulating the \c - VNCSCREEN_BASE definition in the header file. - - \sa QScreen, {Running Applications} -*/ - -/*! - \fn QVNCScreen::QVNCScreen(int displayId) - - Constructs a QVNCScreen object. The \a displayId argument - identifies the Qt for Embedded Linux server to connect to. -*/ -QVNCScreen::QVNCScreen(int display_id) - : QProxyScreen(display_id, VNCClass) -{ - d_ptr = new QVNCScreenPrivate(this); -} - -/*! - Destroys this QVNCScreen object. -*/ -QVNCScreen::~QVNCScreen() -{ - delete d_ptr; -} - -/*! - \reimp -*/ -void QVNCScreen::setDirty(const QRect &rect) -{ - d_ptr->setDirty(rect); -} - -void QVNCScreenPrivate::setDirty(const QRect& rect, bool force) -{ - if (rect.isEmpty()) - return; - - if (q_ptr->screen()) - q_ptr->screen()->setDirty(rect); - - if (!vncServer || !vncServer->isConnected()) - return; - - const QRect r = rect.translated(-q_ptr->offset()); - const int x1 = r.x() / MAP_TILE_SIZE; - int y = r.y() / MAP_TILE_SIZE; - for (; (y <= r.bottom() / MAP_TILE_SIZE) && y < dirty->mapHeight; y++) - for (int x = x1; (x <= r.right() / MAP_TILE_SIZE) && x < dirty->mapWidth; x++) - dirty->setDirty(x, y, force); - - vncServer->setDirty(); -} - -static int getDisplayId(const QString &spec) -{ - QRegExp regexp(QLatin1String(":(\\d+)\\b")); - if (regexp.lastIndexIn(spec) != -1) { - const QString capture = regexp.cap(1); - return capture.toInt(); - } - return 0; -} - -/*! - \reimp -*/ -bool QVNCScreen::connect(const QString &displaySpec) -{ - QString dspec = displaySpec; - if (dspec.startsWith(QLatin1String("vnc:"), Qt::CaseInsensitive)) - dspec = dspec.mid(QString::fromLatin1("vnc:").size()); - else if (dspec.compare(QLatin1String("vnc"), Qt::CaseInsensitive) == 0) - dspec = QString(); - - const QString displayIdSpec = QString::fromLatin1(" :%1").arg(displayId); - if (dspec.endsWith(displayIdSpec)) - dspec = dspec.left(dspec.size() - displayIdSpec.size()); - - QStringList args = dspec.split(QLatin1Char(':'), - QString::SkipEmptyParts); - QRegExp refreshRegexp(QLatin1String("^refreshrate=(\\d+)$")); - int index = args.indexOf(refreshRegexp); - if (index >= 0) { - d_ptr->refreshRate = refreshRegexp.cap(1).toInt(); - args.removeAt(index); - dspec = args.join(QLatin1String(":")); - } - - QString driver = dspec; - int colon = driver.indexOf(QLatin1Char(':')); - if (colon >= 0) - driver.truncate(colon); - - if (QScreenDriverFactory::keys().contains(driver, Qt::CaseInsensitive)) { - const int id = getDisplayId(dspec); - QScreen *s = qt_get_screen(id, dspec.toLatin1().constData()); - if (s->pixelFormat() == QImage::Format_Indexed8 - || s->pixelFormat() == QImage::Format_Invalid && s->depth() == 8) - qFatal("QVNCScreen: unsupported screen format"); - setScreen(s); - } else { // create virtual screen -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - QScreen::setFrameBufferLittleEndian(false); -#endif - - d = qgetenv("QWS_DEPTH").toInt(); - if (!d) - d = 16; - - QByteArray str = qgetenv("QWS_SIZE"); - if(!str.isEmpty()) { - sscanf(str.constData(), "%dx%d", &w, &h); - dw = w; - dh = h; - } else { - dw = w = 640; - dh = h = 480; - } - - const QStringList args = displaySpec.split(QLatin1Char(':'), - QString::SkipEmptyParts); - - if (args.contains(QLatin1String("paintonscreen"), Qt::CaseInsensitive)) - d_ptr->doOnScreenSurface = true; - - QRegExp depthRegexp(QLatin1String("^depth=(\\d+)$")); - if (args.indexOf(depthRegexp) != -1) - d = depthRegexp.cap(1).toInt(); - - QRegExp sizeRegexp(QLatin1String("^size=(\\d+)x(\\d+)$")); - if (args.indexOf(sizeRegexp) != -1) { - dw = w = sizeRegexp.cap(1).toInt(); - dh = h = sizeRegexp.cap(2).toInt(); - } - - // Handle display physical size spec. - QRegExp mmWidthRegexp(QLatin1String("^mmWidth=?(\\d+)$")); - if (args.indexOf(mmWidthRegexp) != -1) { - const int mmWidth = mmWidthRegexp.cap(1).toInt(); - if (mmWidth > 0) - d_ptr->dpiX = dw * 25.4 / mmWidth; - } - QRegExp mmHeightRegexp(QLatin1String("^mmHeight=?(\\d+)$")); - if (args.indexOf(mmHeightRegexp) != -1) { - const int mmHeight = mmHeightRegexp.cap(1).toInt(); - if (mmHeight > 0) - d_ptr->dpiY = dh * 25.4 / mmHeight; - } - QRegExp dpiRegexp(QLatin1String("^dpi=(\\d+)(?:,(\\d+))?$")); - if (args.indexOf(dpiRegexp) != -1) { - const qreal dpiX = dpiRegexp.cap(1).toFloat(); - const qreal dpiY = dpiRegexp.cap(2).toFloat(); - if (dpiX > 0) - d_ptr->dpiX = dpiX; - d_ptr->dpiY = (dpiY > 0 ? dpiY : dpiX); - } - - if (args.contains(QLatin1String("noDisablePainting"))) - d_ptr->noDisablePainting = true; - - QWSServer::setDefaultMouse("None"); - QWSServer::setDefaultKeyboard("None"); - - d_ptr->configure(); - } - - // XXX - qt_screen = this; - - return true; -} - -/*! - \reimp -*/ -void QVNCScreen::disconnect() -{ - QProxyScreen::disconnect(); -#if !defined(QT_NO_QWS_MULTIPROCESS) && !defined(QT_NO_SHAREDMEMORY) - d_ptr->shm.detach(); -#endif -} - -/*! - \reimp -*/ -bool QVNCScreen::initDevice() -{ - if (!QProxyScreen::screen() && d == 4) { - screencols = 16; - int val = 0; - for (int idx = 0; idx < 16; idx++, val += 17) { - screenclut[idx] = qRgb(val, val, val); - } - } - d_ptr->vncServer = new QVNCServer(this, displayId); - d_ptr->vncServer->setRefreshRate(d_ptr->refreshRate); - - switch (depth()) { -#ifdef QT_QWS_DEPTH_32 - case 32: - d_ptr->dirty = new QVNCDirtyMapOptimized<quint32>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_24 - case 24: - d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb888>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_18 - case 18: - d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb666>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_16 - case 16: - d_ptr->dirty = new QVNCDirtyMapOptimized<quint16>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_15 - case 15: - d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb555>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_12 - case 12: - d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb444>(this); - break; -#endif -#ifdef QT_QWS_DEPTH_8 - case 8: - d_ptr->dirty = new QVNCDirtyMapOptimized<quint8>(this); - break; -#endif - default: - qWarning("QVNCScreen::initDevice: No support for screen depth %d", - depth()); - d_ptr->dirty = 0; - return false; - } - - - const bool ok = QProxyScreen::initDevice(); -#ifndef QT_NO_QWS_CURSOR - qt_screencursor = new QVNCCursor(this); -#endif - if (QProxyScreen::screen()) - return ok; - - // Disable painting if there is only 1 display and nothing is attached to the VNC server - if (!d_ptr->noDisablePainting) - QWSServer::instance()->enablePainting(false); - - return true; -} - -/*! - \reimp -*/ -void QVNCScreen::shutdownDevice() -{ - QProxyScreen::shutdownDevice(); - delete d_ptr->vncServer; - delete d_ptr->dirty; -} - -QT_END_NAMESPACE - -#endif // QT_NO_QWS_VNC diff --git a/src/plugins/gfxdrivers/vnc/vnc.pro b/src/plugins/gfxdrivers/vnc/vnc.pro deleted file mode 100644 index 95e2ba7cf8..0000000000 --- a/src/plugins/gfxdrivers/vnc/vnc.pro +++ /dev/null @@ -1,16 +0,0 @@ -TARGET = qgfxvnc -load(qt_plugin) - -DEFINES += QT_QWS_VNC - -DESTDIR = $$QT.gui.plugins/gfxdrivers - -HEADERS = \ - qscreenvnc_qws.h \ - qscreenvnc_p.h - -SOURCES = main.cpp \ - qscreenvnc_qws.cpp - -target.path += $$[QT_INSTALL_PLUGINS]/gfxdrivers -INSTALLS += target diff --git a/src/plugins/graphicssystems/graphicssystems.pro b/src/plugins/graphicssystems/graphicssystems.pro deleted file mode 100644 index 5c99291047..0000000000 --- a/src/plugins/graphicssystems/graphicssystems.pro +++ /dev/null @@ -1,15 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += trace -!wince*:contains(QT_CONFIG, opengl):SUBDIRS += opengl -contains(QT_CONFIG, openvg):contains(QT_CONFIG, egl) { - SUBDIRS += openvg -} - -contains(QT_CONFIG, shivavg) { - # Only works under X11 at present - !win32:!embedded:!mac:SUBDIRS += shivavg -} - -!win32:!embedded:!mac:!symbian:CONFIG += x11 - -x11:contains(QT_CONFIG, opengles2):contains(QT_CONFIG, egl):SUBDIRS += meego diff --git a/src/plugins/graphicssystems/meego/dithering.cpp b/src/plugins/graphicssystems/meego/dithering.cpp deleted file mode 100644 index 6e4b61c754..0000000000 --- a/src/plugins/graphicssystems/meego/dithering.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// Implements two dithering methods: -// -// * convertRGBA32_to_RGB565 -// -// This is implemented using Ordered Bayer Dithering. The code has been adapted -// from QX11PixmapData::fromImage. This method was originally implemented using -// Floyd-Steinberg dithering but was later changed to Ordered Dithering because -// of the better quality of the results. -// -// * convertRGBA32_to_RGBA4444 -// -// This is implemented using Floyd-Steinberg dithering. -// -// The alghorithm used here is not the fastest possible but it's prolly fast enough: -// uses look-up tables, integer-only arthmetics and works in one pass on two lines -// at a time. It's a high-quality dithering using 1/8 diffusion precission. -// Each channel (RGBA) is diffused independently and alpha is dithered too. - -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <QVarLengthArray> - -// Gets a component (red = 1, green = 2...) from a RGBA data structure. -// data is unsigned char. stride is the number of bytes per line. -#define GET_RGBA_COMPONENT(data, x, y, stride, c) (data[(y * stride) + (x << 2) + c]) - -// Writes a new pixel with r, g, b to data in 565 16bit format. Data is a short. -#define PUT_565(data, x, y, width, r, g, b) (data[(y * width) + x] = (r << 11) | (g << 5) | b) - -// Writes a new pixel with r, g, b, a to data in 4444 RGBA 16bit format. Data is a short. -#define PUT_4444(data, x, y, width, r, g, b, a) (data[(y * width) + x] = (r << 12) | (g << 8) | (b << 4) | a) - -// Writes(ads) a new value to the diffusion accumulator. accumulator is a short. -// x, y is a position in the accumulation buffer. y can be 0 or 1 -- we operate on two lines at time. -#define ACCUMULATE(accumulator, x, y, width, v) if (x < width && x >= 0) accumulator[(y * width) + x] += v - -// Clamps a value to be in 0..255 range. -#define CLAMP_256(v) if (v > 255) v = 255; if (v < 0) v = 0; - -// Converts incoming RGB32 (QImage::Format_RGB32) to RGB565. Returns the newly allocated data. -unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int height, int stride) -{ - static bool thresholdMapInitialized = false; - static int thresholdMap[16][16]; - - if (!thresholdMapInitialized) { - int i; - int j; - int n; - - thresholdMap[0][0] = 0; - thresholdMap[1][0] = 2; - thresholdMap[0][1] = 3; - thresholdMap[1][1] = 1; - - for (n=2; n<16; n*=2) { - for (i=0; i<n; i++) { - for (j=0; j<n; j++) { - thresholdMap[i][j] *= 4; - thresholdMap[i+n][j] = thresholdMap[i][j] + 2; - thresholdMap[i][j+n] = thresholdMap[i][j] + 3; - thresholdMap[i+n][j+n] = thresholdMap[i][j] + 1; - } - } - } - - thresholdMapInitialized = true; - } - - // Output line stride. Aligned to 4 bytes. - int alignedWidth = width; - if (alignedWidth % 2 > 0) - alignedWidth++; - - // Will store output - unsigned short *out = (unsigned short *)malloc (alignedWidth * height * 2); - - int x; - int y; - int threshold; - - // For each line... - for (y = 0; y < height; y++) { - - // For each column.... - for (x = 0; x < width; x++) { - - int r = GET_RGBA_COMPONENT(in, x, y, stride, 0); - int g = GET_RGBA_COMPONENT(in, x, y, stride, 1); - int b = GET_RGBA_COMPONENT(in, x, y, stride, 2); - - threshold = thresholdMap[x%16][y%16]; - - if (r <= (255-(1<<3)) && ((r<<5) & 255) > threshold) r += (1<<3); - if (g <= (255-(1<<2)) && ((g<<6) & 255) > threshold) g += (1<<2); - if (b <= (255-(1<<3)) && ((b<<5) & 255) > threshold) b += (1<<3); - - // Write the newly produced pixel - PUT_565(out, x, y, alignedWidth, ((b >> 3) & 0x1f), ((g >> 2) & 0x3f), ((r >> 3) & 0x1f)); - } - } - - return out; -} - -// Converts incoming RGBA32 (QImage::Format_ARGB32_Premultiplied) to RGB565. Returns the newly allocated data. -// This function is similar (yet different) to the _565 variant but it makes sense to duplicate it here for simplicity. -// The output has each scan line aligned to 4 bytes (as expected by GL by default). -unsigned short* convertARGB32_to_RGBA4444(const unsigned char *in, int width, int height, int stride) -{ - // Output line stride. Aligned to 4 bytes. - int alignedWidth = width; - if (alignedWidth % 2 > 0) - alignedWidth++; - - // Will store output - unsigned short *out = (unsigned short *) malloc(alignedWidth * 2 * height); - - // Lookup tables for the 8bit => 4bit conversion - unsigned char lookup_8bit_to_4bit[256]; - short lookup_8bit_to_4bit_diff[256]; - - // Macros for the conversion using the lookup table. - #define CONVERT_8BIT_TO_4BIT(v) (lookup_8bit_to_4bit[v]) - #define DIFF_8BIT_TO_4BIT(v) (lookup_8bit_to_4bit_diff[v]) - - int i; - int x, y, c; // Pixel we're processing. c is component number (0, 1, 2, 3 for r, b, b, a) - short component[4]; // Stores the new components (r, g, b, a) for pixel produced during conversion - short diff; // The difference between the converted value and the original one. To be accumulated. - QVarLengthArray <short> accumulatorData(4 * width * 2); // Data for three acumulators for r, g, b. Each accumulator is two lines. - short *accumulator[4]; // Helper for accessing the accumulator on a per-channel basis more easily. - accumulator[0] = accumulatorData.data(); - accumulator[1] = accumulatorData.data() + width; - accumulator[2] = accumulatorData.data() + (width * 2); - accumulator[3] = accumulatorData.data() + (width * 3); - - // Produce the conversion lookup tables. - for (i = 0; i < 256; i++) { - lookup_8bit_to_4bit[i] = round(i / 16.0); - // Before bitshifts: (i * 8) - (... * 16 * 8) - lookup_8bit_to_4bit_diff[i] = (i << 3) - (lookup_8bit_to_4bit[i] << 7); - - if (lookup_8bit_to_4bit[i] > 15) - lookup_8bit_to_4bit[i] = 15; - } - - // Clear the accumulators - memset(accumulator[0], 0, width * 4); - memset(accumulator[1], 0, width * 4); - memset(accumulator[2], 0, width * 4); - memset(accumulator[3], 0, width * 4); - - // For each line... - for (y = 0; y < height; y++) { - - // For each component (r, g, b, a)... - memcpy(accumulator[0], accumulator[0] + width, width * 2); - memset(accumulator[0] + width, 0, width * 2); - - memcpy(accumulator[1], accumulator[1] + width, width * 2); - memset(accumulator[1] + width, 0, width * 2); - - memcpy(accumulator[2], accumulator[2] + width, width * 2); - memset(accumulator[2] + width, 0, width * 2); - - memcpy(accumulator[3], accumulator[3] + width, width * 2); - memset(accumulator[3] + width, 0, width * 2); - - // For each column.... - for (x = 0; x < width; x++) { - - // For each component (r, g, b, a)... - for (c = 0; c < 4; c++) { - - // Get the 8bit value from the original image - component[c] = GET_RGBA_COMPONENT(in, x, y, stride, c); - - // Add the diffusion for this pixel we stored in the accumulator. - // >> 7 because the values in accumulator are stored * 128 - component[c] += accumulator[c][x] >> 7; - - // Make sure we're not over the boundaries. - CLAMP_256(component[c]); - - // Store the difference from converting 8bit => 4bit and the orig pixel. - // Convert 8bit => 4bit. - diff = DIFF_8BIT_TO_4BIT(component[c]); - component[c] = CONVERT_8BIT_TO_4BIT(component[c]); - - // Distribute the difference according to the matrix in the - // accumulation bufffer. - ACCUMULATE(accumulator[c], x + 1, 0, width, diff * 7); - ACCUMULATE(accumulator[c], x - 1, 1, width, diff * 3); - ACCUMULATE(accumulator[c], x, 1, width, diff * 5); - ACCUMULATE(accumulator[c], x + 1, 1, width, diff * 1); - } - - // Write the newly produced pixel - PUT_4444(out, x, y, alignedWidth, component[0], component[1], component[2], component[3]); - } - } - - return out; -} - -unsigned char* convertBGRA32_to_RGBA32(const unsigned char *in, int width, int height, int stride) -{ - unsigned char *out = (unsigned char *) malloc(stride * height); - - // For each line... - for (int y = 0; y < height; y++) { - // For each column - for (int x = 0; x < width; x++) { - out[(stride * y) + (x * 4) + 0] = in[(stride * y) + (x * 4) + 2]; - out[(stride * y) + (x * 4) + 1] = in[(stride * y) + (x * 4) + 1]; - out[(stride * y) + (x * 4) + 2] = in[(stride * y) + (x * 4) + 0]; - out[(stride * y) + (x * 4) + 3] = in[(stride * y) + (x * 4) + 3]; - } - } - - return out; -} diff --git a/src/plugins/graphicssystems/meego/meego.pro b/src/plugins/graphicssystems/meego/meego.pro deleted file mode 100644 index 6432825888..0000000000 --- a/src/plugins/graphicssystems/meego/meego.pro +++ /dev/null @@ -1,13 +0,0 @@ -TARGET = qmeegographicssystem -load(qt_plugin) - -QT += core-private gui-private opengl-private - -DESTDIR = $$QT.gui.plugins/graphicssystems - -HEADERS = qmeegographicssystem.h qmeegopixmapdata.h qmeegoextensions.h qmeegorasterpixmapdata.h qmeegolivepixmapdata.h -SOURCES = qmeegographicssystem.cpp qmeegographicssystem.h qmeegographicssystemplugin.h qmeegographicssystemplugin.cpp qmeegopixmapdata.h qmeegopixmapdata.cpp qmeegoextensions.h qmeegoextensions.cpp qmeegorasterpixmapdata.h qmeegorasterpixmapdata.cpp qmeegolivepixmapdata.cpp qmeegolivepixmapdata.h dithering.cpp - -target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems -INSTALLS += target - diff --git a/src/plugins/graphicssystems/meego/qmeegoextensions.cpp b/src/plugins/graphicssystems/meego/qmeegoextensions.cpp deleted file mode 100644 index c1a8eb7028..0000000000 --- a/src/plugins/graphicssystems/meego/qmeegoextensions.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qmeegoextensions.h" -#include <private/qeglcontext_p.h> -#include <private/qpixmapdata_gl_p.h> - -bool QMeeGoExtensions::initialized = false; -bool QMeeGoExtensions::hasImageShared = false; -bool QMeeGoExtensions::hasSurfaceScaling = false; -bool QMeeGoExtensions::hasLockSurface = false; -bool QMeeGoExtensions::hasFenceSync = false; - -/* Extension funcs */ - -typedef EGLBoolean (EGLAPIENTRY *eglQueryImageNOKFunc)(EGLDisplay, EGLImageKHR, EGLint, EGLint*); -typedef EGLNativeSharedImageTypeNOK (EGLAPIENTRY *eglCreateSharedImageNOKFunc)(EGLDisplay, EGLImageKHR, EGLint*); -typedef EGLBoolean (EGLAPIENTRY *eglDestroySharedImageNOKFunc)(EGLDisplay, EGLNativeSharedImageTypeNOK); -typedef EGLBoolean (EGLAPIENTRY *eglSetSurfaceScalingNOKFunc)(EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint); -typedef EGLBoolean (EGLAPIENTRY *eglLockSurfaceKHRFunc)(EGLDisplay, EGLSurface, const EGLint*); -typedef EGLBoolean (EGLAPIENTRY *eglUnlockSurfaceKHRFunc)(EGLDisplay, EGLSurface); -typedef EGLSyncKHR (EGLAPIENTRY *eglCreateSyncKHRFunc)(EGLDisplay, EGLenum, const EGLint*); -typedef EGLBoolean (EGLAPIENTRY *eglDestroySyncKHRFunc)(EGLDisplay, EGLSyncKHR); -typedef EGLint (EGLAPIENTRY *eglClientWaitSyncKHRFunc)(EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR); -typedef EGLBoolean (EGLAPIENTRY *eglGetSyncAttribKHRFunc)(EGLDisplay, EGLSyncKHR, EGLint, EGLint*); - -static eglQueryImageNOKFunc _eglQueryImageNOK = 0; -static eglCreateSharedImageNOKFunc _eglCreateSharedImageNOK = 0; -static eglDestroySharedImageNOKFunc _eglDestroySharedImageNOK = 0; -static eglSetSurfaceScalingNOKFunc _eglSetSurfaceScalingNOK = 0; -static eglLockSurfaceKHRFunc _eglLockSurfaceKHR = 0; -static eglUnlockSurfaceKHRFunc _eglUnlockSurfaceKHR = 0; -static eglCreateSyncKHRFunc _eglCreateSyncKHR = 0; -static eglDestroySyncKHRFunc _eglDestroySyncKHR = 0; -static eglClientWaitSyncKHRFunc _eglClientWaitSyncKHR = 0; -static eglGetSyncAttribKHRFunc _eglGetSyncAttribKHR = 0; - -/* Public */ - -void QMeeGoExtensions::ensureInitialized() -{ - if (!initialized) - initialize(); - - initialized = true; -} - -EGLNativeSharedImageTypeNOK QMeeGoExtensions::eglCreateSharedImageNOK(EGLDisplay dpy, EGLImageKHR image, EGLint *props) -{ - if (!hasImageShared) - qFatal("EGL_NOK_image_shared not found but trying to use capability!"); - - return _eglCreateSharedImageNOK(dpy, image, props); -} - -bool QMeeGoExtensions::eglQueryImageNOK(EGLDisplay dpy, EGLImageKHR image, EGLint prop, EGLint *v) -{ - if (!hasImageShared) - qFatal("EGL_NOK_image_shared not found but trying to use capability!"); - - return _eglQueryImageNOK(dpy, image, prop, v); -} - -bool QMeeGoExtensions::eglDestroySharedImageNOK(EGLDisplay dpy, EGLNativeSharedImageTypeNOK img) -{ - if (!hasImageShared) - qFatal("EGL_NOK_image_shared not found but trying to use capability!"); - - return _eglDestroySharedImageNOK(dpy, img); -} - -bool QMeeGoExtensions::eglSetSurfaceScalingNOK(EGLDisplay dpy, EGLSurface surface, int x, int y, int width, int height) -{ - if (!hasSurfaceScaling) - qFatal("EGL_NOK_surface_scaling not found but trying to use capability!"); - - return _eglSetSurfaceScalingNOK(dpy, surface, x, y, width, height); -} - -bool QMeeGoExtensions::eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list) -{ - if (!hasLockSurface) - qFatal("EGL_KHR_lock_surface2 not found but trying to use capability!"); - - return _eglLockSurfaceKHR(display, surface, attrib_list); -} - -bool QMeeGoExtensions::eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface) -{ - if (!hasLockSurface) - qFatal("EGL_KHR_lock_surface2 not found but trying to use capability!"); - - return _eglUnlockSurfaceKHR(display, surface); -} - -EGLSyncKHR QMeeGoExtensions::eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) -{ - if (!hasFenceSync) - qFatal("EGL_KHR_fence_sync not found but trying to use capability!"); - - return _eglCreateSyncKHR(dpy, type, attrib_list); -} - -bool QMeeGoExtensions::eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) -{ - if (!hasFenceSync) - qFatal("EGL_KHR_fence_sync not found but trying to use capability!"); - - return _eglDestroySyncKHR(dpy, sync); -} - -EGLint QMeeGoExtensions::eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) -{ - if (!hasFenceSync) - qFatal("EGL_KHR_fence_sync not found but trying to use capability!"); - - return _eglClientWaitSyncKHR(dpy, sync, flags, timeout); -} - -EGLBoolean QMeeGoExtensions::eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) -{ - if (!hasFenceSync) - qFatal("EGL_KHR_fence_sync not found but trying to use capability!"); - - return _eglGetSyncAttribKHR(dpy, sync, attribute, value); -} - -/* Private */ - -void QMeeGoExtensions::initialize() -{ - QGLContext *ctx = (QGLContext *) QGLContext::currentContext(); - qt_resolve_eglimage_gl_extensions(ctx); - - if (QEgl::hasExtension("EGL_NOK_image_shared")) { - qDebug("MeegoGraphics: found EGL_NOK_image_shared"); - _eglQueryImageNOK = (eglQueryImageNOKFunc) eglGetProcAddress("eglQueryImageNOK"); - _eglCreateSharedImageNOK = (eglCreateSharedImageNOKFunc) eglGetProcAddress("eglCreateSharedImageNOK"); - _eglDestroySharedImageNOK = (eglDestroySharedImageNOKFunc) eglGetProcAddress("eglDestroySharedImageNOK"); - _eglLockSurfaceKHR = (eglLockSurfaceKHRFunc) eglGetProcAddress("eglLockSurfaceKHR"); - _eglUnlockSurfaceKHR = (eglUnlockSurfaceKHRFunc) eglGetProcAddress("eglUnlockSurfaceKHR"); - - Q_ASSERT(_eglQueryImageNOK && _eglCreateSharedImageNOK && _eglDestroySharedImageNOK); - hasImageShared = true; - } - - if (QEgl::hasExtension("EGL_NOK_surface_scaling")) { - qDebug("MeegoGraphics: found EGL_NOK_surface_scaling"); - _eglSetSurfaceScalingNOK = (eglSetSurfaceScalingNOKFunc) eglGetProcAddress("eglSetSurfaceScalingNOK"); - - Q_ASSERT(_eglSetSurfaceScalingNOK); - hasSurfaceScaling = true; - } - - if (QEgl::hasExtension("EGL_KHR_lock_surface2")) { - qDebug("MeegoGraphics: found EGL_KHR_lock_surface2"); - _eglLockSurfaceKHR = (eglLockSurfaceKHRFunc) eglGetProcAddress("eglLockSurfaceKHR"); - _eglUnlockSurfaceKHR = (eglUnlockSurfaceKHRFunc) eglGetProcAddress("eglUnlockSurfaceKHR"); - - Q_ASSERT(_eglLockSurfaceKHR && _eglUnlockSurfaceKHR); - hasLockSurface = true; - } - - if (QEgl::hasExtension("EGL_KHR_fence_sync")) { - qDebug("MeegoGraphics: found EGL_KHR_fence_sync"); - _eglCreateSyncKHR = (eglCreateSyncKHRFunc) eglGetProcAddress("eglCreateSyncKHR"); - _eglDestroySyncKHR = (eglDestroySyncKHRFunc) eglGetProcAddress("eglDestroySyncKHR"); - _eglClientWaitSyncKHR = (eglClientWaitSyncKHRFunc) eglGetProcAddress("eglClientWaitSyncKHR"); - _eglGetSyncAttribKHR = (eglGetSyncAttribKHRFunc) eglGetProcAddress("eglGetSyncAttribKHR"); - - Q_ASSERT(_eglCreateSyncKHR && _eglDestroySyncKHR && _eglClientWaitSyncKHR && _eglGetSyncAttribKHR); - hasFenceSync = true; - } -} - diff --git a/src/plugins/graphicssystems/meego/qmeegoextensions.h b/src/plugins/graphicssystems/meego/qmeegoextensions.h deleted file mode 100644 index e4ceed3a31..0000000000 --- a/src/plugins/graphicssystems/meego/qmeegoextensions.h +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MEXTENSIONS_H -#define MEXTENSIONS_H - -#include <private/qgl_p.h> -#include <private/qeglcontext_p.h> -#include <private/qpixmapdata_gl_p.h> -#include <EGL/egl.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - -/* Extensions decls */ - -#ifndef EGL_SHARED_IMAGE_NOK -#define EGL_SHARED_IMAGE_NOK 0x30DA -typedef void* EGLNativeSharedImageTypeNOK; -#endif - -#ifndef EGL_GL_TEXTURE_2D_KHR -#define EGL_GL_TEXTURE_2D_KHR 0x30B1 -#endif - -#ifndef EGL_FIXED_WIDTH_NOK -#define EGL_FIXED_WIDTH_NOK 0x30DB -#define EGL_FIXED_HEIGHT_NOK 0x30DC -#endif - -#ifndef EGL_BITMAP_POINTER_KHR -#define EGL_BITMAP_POINTER_KHR 0x30C6 -#define EGL_BITMAP_PITCH_KHR 0x30C7 -#endif - -#ifndef EGL_MAP_PRESERVE_PIXELS_KHR -#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 -#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 -#define EGL_READ_SURFACE_BIT_KHR 0x0001 -#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 -#endif - -#ifndef EGL_SYNC_FENCE_KHR -#define EGL_SYNC_FENCE_KHR 0x30F9 -#define EGL_SYNC_TYPE_KHR 0x30F7 -#define EGL_SYNC_STATUS_KHR 0x30F1 -#define EGL_SYNC_CONDITION_KHR 0x30F8 -#define EGL_SIGNALED_KHR 0x30F2 -#define EGL_UNSIGNALED_KHR 0x30F3 -#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0 -#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 -#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull -#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5 -#define EGL_CONDITION_SATISFIED_KHR 0x30F6 -#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0) -typedef void* EGLSyncKHR; -typedef khronos_utime_nanoseconds_t EGLTimeKHR; -#endif - -/* Class */ - -class QMeeGoExtensions -{ -public: - static void ensureInitialized(); - - static EGLNativeSharedImageTypeNOK eglCreateSharedImageNOK(EGLDisplay dpy, EGLImageKHR image, EGLint *props); - static bool eglQueryImageNOK(EGLDisplay dpy, EGLImageKHR image, EGLint prop, EGLint *v); - static bool eglDestroySharedImageNOK(EGLDisplay dpy, EGLNativeSharedImageTypeNOK img); - static bool eglSetSurfaceScalingNOK(EGLDisplay dpy, EGLSurface surface, int x, int y, int width, int height); - static bool eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); - static bool eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface); - static EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); - static bool eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync); - static EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); - static EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); - -private: - static void initialize(); - - static bool initialized; - static bool hasImageShared; - static bool hasSurfaceScaling; - static bool hasLockSurface; - static bool hasFenceSync; -}; - -#endif diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp b/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp deleted file mode 100644 index ab403797df..0000000000 --- a/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp +++ /dev/null @@ -1,534 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QDebug> -#include <private/qpixmap_raster_p.h> -#include <private/qwindowsurface_gl_p.h> -#include <private/qwindowsurface_raster_p.h> -#include <private/qegl_p.h> -#include <private/qglextensions_p.h> -#include <private/qgl_p.h> -#include <private/qimagepixmapcleanuphooks_p.h> -#include <private/qapplication_p.h> -#include <private/qgraphicssystem_runtime_p.h> -#include <private/qimage_p.h> -#include <private/qeglproperties_p.h> -#include <private/qeglcontext_p.h> -#include <private/qpixmap_x11_p.h> - -#include "qmeegopixmapdata.h" -#include "qmeegolivepixmapdata.h" -#include "qmeegographicssystem.h" -#include "qmeegoextensions.h" - -#include <QTimer> - -bool QMeeGoGraphicsSystem::surfaceWasCreated = false; - -QHash <Qt::HANDLE, QPixmap*> QMeeGoGraphicsSystem::liveTexturePixmaps; - -QList<QMeeGoSwitchCallback> QMeeGoGraphicsSystem::switchCallbacks; - -QMeeGoGraphicsSystem::SwitchPolicy QMeeGoGraphicsSystem::switchPolicy = QMeeGoGraphicsSystem::AutomaticSwitch; - -QMeeGoGraphicsSystem::QMeeGoGraphicsSystem() -{ - qDebug("Using the meego graphics system"); -} - -QMeeGoGraphicsSystem::~QMeeGoGraphicsSystem() -{ - qDebug("Meego graphics system destroyed"); - qt_destroy_gl_share_widget(); -} - -class QMeeGoGraphicsSystemSwitchHandler : public QObject -{ - Q_OBJECT -public: - QMeeGoGraphicsSystemSwitchHandler(); - - void addWidget(QWidget *widget); - bool eventFilter(QObject *, QEvent *); - - void handleMapNotify(); - -private slots: - void removeWidget(QObject *object); - void switchToRaster(); - void switchToMeeGo(); - -private: - int visibleWidgets() const; - -private: - QList<QWidget *> m_widgets; -}; - -typedef bool(*QX11FilterFunction)(XEvent *event); -Q_GUI_EXPORT void qt_installX11EventFilter(QX11FilterFunction func); - -static bool x11EventFilter(XEvent *event); - -QMeeGoGraphicsSystemSwitchHandler::QMeeGoGraphicsSystemSwitchHandler() -{ - qt_installX11EventFilter(x11EventFilter); -} - -void QMeeGoGraphicsSystemSwitchHandler::addWidget(QWidget *widget) -{ - if (widget != qt_gl_share_widget() && !m_widgets.contains(widget)) { - widget->installEventFilter(this); - connect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(removeWidget(QObject *))); - m_widgets << widget; - } -} - -void QMeeGoGraphicsSystemSwitchHandler::handleMapNotify() -{ - if (m_widgets.isEmpty() && QMeeGoGraphicsSystem::switchPolicy == QMeeGoGraphicsSystem::AutomaticSwitch) - QTimer::singleShot(0, this, SLOT(switchToMeeGo())); -} - -void QMeeGoGraphicsSystemSwitchHandler::removeWidget(QObject *object) -{ - m_widgets.removeOne(static_cast<QWidget *>(object)); - if (m_widgets.isEmpty() && QMeeGoGraphicsSystem::switchPolicy == QMeeGoGraphicsSystem::AutomaticSwitch) - QTimer::singleShot(0, this, SLOT(switchToRaster())); -} - -void QMeeGoGraphicsSystemSwitchHandler::switchToRaster() -{ - QMeeGoGraphicsSystem::switchToRaster(); -} - -void QMeeGoGraphicsSystemSwitchHandler::switchToMeeGo() -{ - QMeeGoGraphicsSystem::switchToMeeGo(); -} - -int QMeeGoGraphicsSystemSwitchHandler::visibleWidgets() const -{ - int count = 0; - for (int i = 0; i < m_widgets.size(); ++i) - count += m_widgets.at(i)->isVisible() && !(m_widgets.at(i)->windowState() & Qt::WindowMinimized); - return count; -} - -bool QMeeGoGraphicsSystemSwitchHandler::eventFilter(QObject *object, QEvent *event) -{ - if (event->type() == QEvent::WindowStateChange - && QMeeGoGraphicsSystem::switchPolicy == QMeeGoGraphicsSystem::AutomaticSwitch) - { - QWindowStateChangeEvent *change = static_cast<QWindowStateChangeEvent *>(event); - QWidget *widget = static_cast<QWidget *>(object); - - Qt::WindowStates current = widget->windowState(); - Qt::WindowStates old = change->oldState(); - - // did minimized flag change? - if ((current ^ old) & Qt::WindowMinimized) { - if (current & Qt::WindowMinimized) { - if (visibleWidgets() == 0) - QMeeGoGraphicsSystem::switchToRaster(); - } else { - if (visibleWidgets() > 0) - QMeeGoGraphicsSystem::switchToMeeGo(); - } - } - } - - // resume processing of event - return false; -} - -Q_GLOBAL_STATIC(QMeeGoGraphicsSystemSwitchHandler, switch_handler) - -bool x11EventFilter(XEvent *event) -{ - if (event->type == MapNotify) - switch_handler()->handleMapNotify(); - return false; -} - -QWindowSurface* QMeeGoGraphicsSystem::createWindowSurface(QWidget *widget) const -{ - QGLWidget *shareWidget = qt_gl_share_widget(); - - if (!shareWidget) - return new QRasterWindowSurface(widget); - - QGLShareContextScope ctx(shareWidget->context()); - - if (QApplicationPrivate::instance()->graphics_system_name == QLatin1String("runtime")) - switch_handler()->addWidget(widget); - - QMeeGoGraphicsSystem::surfaceWasCreated = true; - QWindowSurface *surface = new QGLWindowSurface(widget); - return surface; -} - -QPixmapData *QMeeGoGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const -{ - return new QRasterPixmapData(type); -} - -QPixmapData *QMeeGoGraphicsSystem::createPixmapData(QPixmapData *origin) -{ - // If the pixmap is a raster type... - // and if the pixmap pointer matches our mapping... - // create a shared image instead with the given handle. - - if (!origin->isNull() && origin->classId() == QPixmapData::RasterClass) { - QRasterPixmapData *rasterClass = static_cast <QRasterPixmapData *> (origin); - void *rawResource = static_cast <void *> (rasterClass->buffer()->data_ptr()->data); - - if (QMeeGoPixmapData::sharedImagesMap.contains(rawResource)) - return new QMeeGoPixmapData(); - } - - return new QRasterPixmapData(origin->pixelType()); -} - -QPixmapData* QMeeGoGraphicsSystem::wrapPixmapData(QPixmapData *pmd) -{ - QString name = QApplicationPrivate::instance()->graphics_system_name; - if (name == "runtime") { - QRuntimeGraphicsSystem *rsystem = (QRuntimeGraphicsSystem *) QApplicationPrivate::instance()->graphics_system; - QRuntimePixmapData *rt = new QRuntimePixmapData(rsystem, pmd->pixelType());; - rt->m_data = pmd; - rt->readBackInfo(); - rsystem->m_pixmapDatas << rt; - return rt; - } else - return pmd; -} - -void QMeeGoGraphicsSystem::setSurfaceFixedSize(int /*width*/, int /*height*/) -{ - if (QMeeGoGraphicsSystem::surfaceWasCreated) { - qWarning("Trying to set surface fixed size but surface already created!"); - return; - } - -#ifdef QT_WAS_PATCHED - QEglProperties *properties = new QEglProperties(); - properties->setValue(EGL_FIXED_WIDTH_NOK, width); - properties->setValue(EGL_FIXED_HEIGHT_NOK, height); - QGLContextPrivate::setExtraWindowSurfaceCreationProps(properties); -#endif -} - -void QMeeGoGraphicsSystem::setSurfaceScaling(int x, int y, int width, int height) -{ - QMeeGoExtensions::ensureInitialized(); - QMeeGoExtensions::eglSetSurfaceScalingNOK(QEgl::display(), QEglContext::currentContext(QEgl::OpenGL)->currentSurface, x, y, width, height); -} - -void QMeeGoGraphicsSystem::setTranslucent(bool translucent) -{ - if (QMeeGoGraphicsSystem::surfaceWasCreated) { - qWarning("Trying to set translucency but surface already created!"); - return; - } - - QGLWindowSurface::surfaceFormat.setSampleBuffers(false); - QGLWindowSurface::surfaceFormat.setSamples(0); - QGLWindowSurface::surfaceFormat.setAlpha(translucent); -} - -QPixmapData *QMeeGoGraphicsSystem::pixmapDataFromEGLSharedImage(Qt::HANDLE handle, const QImage &softImage) -{ - if (softImage.format() != QImage::Format_ARGB32_Premultiplied && - softImage.format() != QImage::Format_RGB32) { - qFatal("For egl shared images, the soft image has to be ARGB32_Premultiplied or RGB32"); - return NULL; - } - - if (QMeeGoGraphicsSystem::meeGoRunning()) { - QMeeGoPixmapData *pmd = new QMeeGoPixmapData; - pmd->fromEGLSharedImage(handle, softImage); - return QMeeGoGraphicsSystem::wrapPixmapData(pmd); - } else { - QRasterPixmapData *pmd = new QRasterPixmapData(QPixmapData::PixmapType); - pmd->fromImage(softImage, Qt::NoFormatConversion); - - // Make sure that the image was not converted in any way - if (pmd->buffer()->data_ptr()->data != - const_cast<QImage &>(softImage).data_ptr()->data) - qFatal("Iternal misalignment of raster data detected. Prolly a QImage copy fail."); - - QMeeGoPixmapData::registerSharedImage(handle, softImage); - return QMeeGoGraphicsSystem::wrapPixmapData(pmd); - } -} - -void QMeeGoGraphicsSystem::updateEGLSharedImagePixmap(QPixmap *pixmap) -{ - QMeeGoPixmapData *pmd = (QMeeGoPixmapData *) pixmap->pixmapData(); - - // Basic sanity check to make sure this is really a QMeeGoPixmapData... - if (pmd->classId() != QPixmapData::OpenGLClass) - qFatal("Trying to updated EGLSharedImage pixmap but it's not really a shared image pixmap!"); - - pmd->updateFromSoftImage(); -} - -QPixmapData *QMeeGoGraphicsSystem::pixmapDataWithGLTexture(int w, int h) -{ - QGLPixmapData *pmd = new QGLPixmapData(QPixmapData::PixmapType); - pmd->resize(w, h); - return QMeeGoGraphicsSystem::wrapPixmapData(pmd); -} - -bool QMeeGoGraphicsSystem::meeGoRunning() -{ - return runningGraphicsSystemName() == "meego"; -} - -QPixmapData* QMeeGoGraphicsSystem::pixmapDataWithNewLiveTexture(int w, int h, QImage::Format format) -{ - return new QMeeGoLivePixmapData(w, h, format); -} - -QPixmapData* QMeeGoGraphicsSystem::pixmapDataFromLiveTextureHandle(Qt::HANDLE handle) -{ - return new QMeeGoLivePixmapData(handle); -} - -QImage* QMeeGoGraphicsSystem::lockLiveTexture(QPixmap* pixmap, void* fenceSync) -{ - QMeeGoLivePixmapData *pixmapData = static_cast<QMeeGoLivePixmapData*>(pixmap->data_ptr().data()); - return pixmapData->lock(fenceSync); -} - -bool QMeeGoGraphicsSystem::releaseLiveTexture(QPixmap *pixmap, QImage *image) -{ - QMeeGoLivePixmapData *pixmapData = static_cast<QMeeGoLivePixmapData*>(pixmap->data_ptr().data()); - return pixmapData->release(image); -} - -Qt::HANDLE QMeeGoGraphicsSystem::getLiveTextureHandle(QPixmap *pixmap) -{ - QMeeGoLivePixmapData *pixmapData = static_cast<QMeeGoLivePixmapData*>(pixmap->data_ptr().data()); - return pixmapData->handle(); -} - -void* QMeeGoGraphicsSystem::createFenceSync() -{ - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - QMeeGoExtensions::ensureInitialized(); - return QMeeGoExtensions::eglCreateSyncKHR(QEgl::display(), EGL_SYNC_FENCE_KHR, NULL); -} - -void QMeeGoGraphicsSystem::destroyFenceSync(void *fenceSync) -{ - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - QMeeGoExtensions::ensureInitialized(); - QMeeGoExtensions::eglDestroySyncKHR(QEgl::display(), fenceSync); -} - -QString QMeeGoGraphicsSystem::runningGraphicsSystemName() -{ - if (!QApplicationPrivate::instance()) { - qWarning("Querying graphics system but application not running yet!"); - return QString(); - } - - QString name = QApplicationPrivate::instance()->graphics_system_name; - if (name == QLatin1String("runtime")) { - QRuntimeGraphicsSystem *rsystem = (QRuntimeGraphicsSystem *) QApplicationPrivate::instance()->graphics_system; - name = rsystem->graphicsSystemName(); - } - - return name; -} - -void QMeeGoGraphicsSystem::switchToMeeGo() -{ - if (switchPolicy == NoSwitch || meeGoRunning()) - return; - - if (QApplicationPrivate::instance()->graphics_system_name != QLatin1String("runtime")) - qWarning("Can't switch to meego - switching only supported with 'runtime' graphics system."); - else { - triggerSwitchCallbacks(0, "meego"); - - QApplication *app = static_cast<QApplication *>(QCoreApplication::instance()); - app->setGraphicsSystem(QLatin1String("meego")); - - triggerSwitchCallbacks(1, "meego"); - } -} - -void QMeeGoGraphicsSystem::switchToRaster() -{ - if (switchPolicy == NoSwitch || runningGraphicsSystemName() == QLatin1String("raster")) - return; - - if (QApplicationPrivate::instance()->graphics_system_name != QLatin1String("runtime")) - qWarning("Can't switch to raster - switching only supported with 'runtime' graphics system."); - else { - triggerSwitchCallbacks(0, "raster"); - - QApplication *app = static_cast<QApplication *>(QCoreApplication::instance()); - app->setGraphicsSystem(QLatin1String("raster")); - - QMeeGoLivePixmapData::invalidateSurfaces(); - - triggerSwitchCallbacks(1, "raster"); - } -} - -void QMeeGoGraphicsSystem::registerSwitchCallback(QMeeGoSwitchCallback callback) -{ - switchCallbacks << callback; -} - -void QMeeGoGraphicsSystem::triggerSwitchCallbacks(int type, const char *name) -{ - for (int i = 0; i < switchCallbacks.size(); ++i) - switchCallbacks.at(i)(type, name); -} - -/* C API */ - -int qt_meego_image_to_egl_shared_image(const QImage &image) -{ - return QMeeGoPixmapData::imageToEGLSharedImage(image); -} - -QPixmapData* qt_meego_pixmapdata_from_egl_shared_image(Qt::HANDLE handle, const QImage &softImage) -{ - return QMeeGoGraphicsSystem::pixmapDataFromEGLSharedImage(handle, softImage); -} - -QPixmapData* qt_meego_pixmapdata_with_gl_texture(int w, int h) -{ - return QMeeGoGraphicsSystem::pixmapDataWithGLTexture(w, h); -} - -bool qt_meego_destroy_egl_shared_image(Qt::HANDLE handle) -{ - return QMeeGoPixmapData::destroyEGLSharedImage(handle); -} - -void qt_meego_set_surface_fixed_size(int width, int height) -{ - QMeeGoGraphicsSystem::setSurfaceFixedSize(width, height); -} - -void qt_meego_set_surface_scaling(int x, int y, int width, int height) -{ - QMeeGoGraphicsSystem::setSurfaceScaling(x, y, width, height); -} - -void qt_meego_set_translucent(bool translucent) -{ - QMeeGoGraphicsSystem::setTranslucent(translucent); -} - -void qt_meego_update_egl_shared_image_pixmap(QPixmap *pixmap) -{ - QMeeGoGraphicsSystem::updateEGLSharedImagePixmap(pixmap); -} - -QPixmapData* qt_meego_pixmapdata_with_new_live_texture(int w, int h, QImage::Format format) -{ - return QMeeGoGraphicsSystem::pixmapDataWithNewLiveTexture(w, h, format); -} - -QPixmapData* qt_meego_pixmapdata_from_live_texture_handle(Qt::HANDLE handle) -{ - return QMeeGoGraphicsSystem::pixmapDataFromLiveTextureHandle(handle); -} - -QImage* qt_meego_live_texture_lock(QPixmap *pixmap, void *fenceSync) -{ - return QMeeGoGraphicsSystem::lockLiveTexture(pixmap, fenceSync); -} - -bool qt_meego_live_texture_release(QPixmap *pixmap, QImage *image) -{ - return QMeeGoGraphicsSystem::releaseLiveTexture(pixmap, image); -} - -Qt::HANDLE qt_meego_live_texture_get_handle(QPixmap *pixmap) -{ - return QMeeGoGraphicsSystem::getLiveTextureHandle(pixmap); -} - -void* qt_meego_create_fence_sync(void) -{ - return QMeeGoGraphicsSystem::createFenceSync(); -} - -void qt_meego_destroy_fence_sync(void* fs) -{ - return QMeeGoGraphicsSystem::destroyFenceSync(fs); -} - -void qt_meego_invalidate_live_surfaces(void) -{ - return QMeeGoLivePixmapData::invalidateSurfaces(); -} - -void qt_meego_switch_to_raster(void) -{ - QMeeGoGraphicsSystem::switchToRaster(); -} - -void qt_meego_switch_to_meego(void) -{ - QMeeGoGraphicsSystem::switchToMeeGo(); -} - -void qt_meego_register_switch_callback(QMeeGoSwitchCallback callback) -{ - QMeeGoGraphicsSystem::registerSwitchCallback(callback); -} - -void qt_meego_set_switch_policy(int policy) -{ - QMeeGoGraphicsSystem::switchPolicy = QMeeGoGraphicsSystem::SwitchPolicy(policy); -} - -#include "qmeegographicssystem.moc" diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystem.h b/src/plugins/graphicssystems/meego/qmeegographicssystem.h deleted file mode 100644 index 7299af56be..0000000000 --- a/src/plugins/graphicssystems/meego/qmeegographicssystem.h +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MGRAPHICSSYSTEM_H -#define MGRAPHICSSYSTEM_H - -#include <private/qgraphicssystem_p.h> -#include <EGL/egl.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - -extern "C" typedef void (*QMeeGoSwitchCallback)(int type, const char *name); - -class QMeeGoGraphicsSystem : public QGraphicsSystem -{ -public: - enum SwitchPolicy { AutomaticSwitch, ManualSwitch, NoSwitch }; - - QMeeGoGraphicsSystem(); - ~QMeeGoGraphicsSystem(); - - virtual QWindowSurface *createWindowSurface(QWidget *widget) const; - virtual QPixmapData *createPixmapData(QPixmapData::PixelType) const; - virtual QPixmapData *createPixmapData(QPixmapData *origin); - - static QPixmapData *wrapPixmapData(QPixmapData *pmd); - static void setSurfaceFixedSize(int width, int height); - static void setSurfaceScaling(int x, int y, int width, int height); - static void setTranslucent(bool translucent); - - static QPixmapData *pixmapDataFromEGLSharedImage(Qt::HANDLE handle, const QImage &softImage); - static QPixmapData *pixmapDataFromEGLImage(Qt::HANDLE handle); - static QPixmapData *pixmapDataWithGLTexture(int w, int h); - static void updateEGLSharedImagePixmap(QPixmap *pixmap); - - static QPixmapData *pixmapDataWithNewLiveTexture(int w, int h, QImage::Format format); - static QPixmapData *pixmapDataFromLiveTextureHandle(Qt::HANDLE handle); - static QImage *lockLiveTexture(QPixmap* pixmap, void* fenceSync); - static bool releaseLiveTexture(QPixmap *pixmap, QImage *image); - static Qt::HANDLE getLiveTextureHandle(QPixmap *pixmap); - - static void* createFenceSync(); - static void destroyFenceSync(void* fenceSync); - - static void switchToRaster(); - static void switchToMeeGo(); - static QString runningGraphicsSystemName(); - - static void registerSwitchCallback(QMeeGoSwitchCallback callback); - - static SwitchPolicy switchPolicy; - -private: - static bool meeGoRunning(); - static EGLSurface getSurfaceForLiveTexturePixmap(QPixmap *pixmap); - static void destroySurfaceForLiveTexturePixmap(QPixmapData* pmd); - static void triggerSwitchCallbacks(int type, const char *name); - - static bool surfaceWasCreated; - static QHash<Qt::HANDLE, QPixmap*> liveTexturePixmaps; - static QList<QMeeGoSwitchCallback> switchCallbacks; -}; - -/* C api */ - -extern "C" { - Q_DECL_EXPORT int qt_meego_image_to_egl_shared_image(const QImage &image); - Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_from_egl_shared_image(Qt::HANDLE handle, const QImage &softImage); - Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_with_gl_texture(int w, int h); - Q_DECL_EXPORT void qt_meego_update_egl_shared_image_pixmap(QPixmap *pixmap); - Q_DECL_EXPORT bool qt_meego_destroy_egl_shared_image(Qt::HANDLE handle); - Q_DECL_EXPORT void qt_meego_set_surface_fixed_size(int width, int height); - Q_DECL_EXPORT void qt_meego_set_surface_scaling(int x, int y, int width, int height); - Q_DECL_EXPORT void qt_meego_set_translucent(bool translucent); - Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_with_new_live_texture(int w, int h, QImage::Format format); - Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_from_live_texture_handle(Qt::HANDLE handle); - Q_DECL_EXPORT QImage* qt_meego_live_texture_lock(QPixmap *pixmap, void *fenceSync); - Q_DECL_EXPORT bool qt_meego_live_texture_release(QPixmap *pixmap, QImage *image); - Q_DECL_EXPORT Qt::HANDLE qt_meego_live_texture_get_handle(QPixmap *pixmap); - Q_DECL_EXPORT void* qt_meego_create_fence_sync(void); - Q_DECL_EXPORT void qt_meego_destroy_fence_sync(void* fs); - Q_DECL_EXPORT void qt_meego_invalidate_live_surfaces(void); - Q_DECL_EXPORT void qt_meego_switch_to_raster(void); - Q_DECL_EXPORT void qt_meego_switch_to_meego(void); - Q_DECL_EXPORT void qt_meego_register_switch_callback(QMeeGoSwitchCallback callback); - Q_DECL_EXPORT void qt_meego_set_switch_policy(int policy); -} - -#endif diff --git a/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp b/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp deleted file mode 100644 index 40421bc8f0..0000000000 --- a/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp +++ /dev/null @@ -1,323 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qmeegolivepixmapdata.h" -#include "qmeegorasterpixmapdata.h" -#include <private/qimage_p.h> -#include <private/qwindowsurface_gl_p.h> -#include <private/qeglcontext_p.h> -#include <private/qapplication_p.h> -#include <private/qgraphicssystem_runtime_p.h> -#include <private/qpixmap_x11_p.h> -#include <stdio.h> - -static QMeeGoLivePixmapDataList all_live_pixmaps; - -static EGLint lock_attribs[] = { - EGL_MAP_PRESERVE_PIXELS_KHR, EGL_TRUE, - EGL_LOCK_USAGE_HINT_KHR, EGL_READ_SURFACE_BIT_KHR | EGL_WRITE_SURFACE_BIT_KHR, - EGL_NONE -}; - -static EGLint preserved_attribs[] = { - EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, - EGL_NONE -}; - -// as copied from qwindowsurface.cpp -void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset) -{ - // make sure we don't detach - uchar *mem = const_cast<uchar*>(const_cast<const QImage &>(img).bits()); - - int lineskip = img.bytesPerLine(); - int depth = img.depth() >> 3; - - const QRect imageRect(0, 0, img.width(), img.height()); - const QRect r = rect & imageRect & imageRect.translated(-offset); - const QPoint p = rect.topLeft() + offset; - - if (r.isEmpty()) - return; - - const uchar *src; - uchar *dest; - - if (r.top() < p.y()) { - src = mem + r.bottom() * lineskip + r.left() * depth; - dest = mem + (p.y() + r.height() - 1) * lineskip + p.x() * depth; - lineskip = -lineskip; - } else { - src = mem + r.top() * lineskip + r.left() * depth; - dest = mem + p.y() * lineskip + p.x() * depth; - } - - const int w = r.width(); - int h = r.height(); - const int bytes = w * depth; - - // overlapping segments? - if (offset.y() == 0 && qAbs(offset.x()) < w) { - do { - ::memmove(dest, src, bytes); - dest += lineskip; - src += lineskip; - } while (--h); - } else { - do { - ::memcpy(dest, src, bytes); - dest += lineskip; - src += lineskip; - } while (--h); - } -} - -/* Public */ - -QMeeGoLivePixmapData::QMeeGoLivePixmapData(int w, int h, QImage::Format format) : QGLPixmapData(QPixmapData::PixmapType) -{ - QImage image(w, h, format); - QX11PixmapData *pmd = new QX11PixmapData(QPixmapData::PixmapType); - pmd->fromImage(image, Qt::NoOpaqueDetection); - backingX11Pixmap = new QPixmap(pmd); - - initializeThroughEGLImage(); - - pos = all_live_pixmaps.insert(all_live_pixmaps.begin(), this); -} - -QMeeGoLivePixmapData::QMeeGoLivePixmapData(Qt::HANDLE h) : QGLPixmapData(QPixmapData::PixmapType) -{ - backingX11Pixmap = new QPixmap(QPixmap::fromX11Pixmap(h)); - initializeThroughEGLImage(); - - pos = all_live_pixmaps.insert(all_live_pixmaps.begin(), this); -} - -QMeeGoLivePixmapData::~QMeeGoLivePixmapData() -{ - delete backingX11Pixmap; - all_live_pixmaps.erase(pos); -} - -void QMeeGoLivePixmapData::initializeThroughEGLImage() -{ - if (texture()->id != 0) - return; - - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - QMeeGoExtensions::ensureInitialized(); - - EGLImageKHR eglImage = EGL_NO_IMAGE_KHR; - GLuint newTextureId = 0; - - eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, - (EGLClientBuffer) backingX11Pixmap->handle(), preserved_attribs); - - if (eglImage == EGL_NO_IMAGE_KHR) { - qWarning("eglCreateImageKHR failed (live texture)!"); - return; - } - - glGenTextures(1, &newTextureId); - glBindTexture(GL_TEXTURE_2D, newTextureId); - - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (EGLImageKHR) eglImage); - if (glGetError() == GL_NO_ERROR) { - resize(backingX11Pixmap->width(), backingX11Pixmap->height()); - texture()->id = newTextureId; - texture()->options &= ~QGLContext::InvertedYBindOption; - m_hasAlpha = backingX11Pixmap->hasAlphaChannel(); - } else { - qWarning("Failed to create a texture from an egl image (live texture)!"); - glDeleteTextures(1, &newTextureId); - } - - QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); -} - -QPixmapData *QMeeGoLivePixmapData::createCompatiblePixmapData() const -{ - qWarning("Create compatible called on live pixmap! Expect fail soon..."); - return new QMeeGoRasterPixmapData(pixelType()); -} - -QImage* QMeeGoLivePixmapData::lock(EGLSyncKHR fenceSync) -{ - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - QMeeGoExtensions::ensureInitialized(); - - if (fenceSync) { - QMeeGoExtensions::eglClientWaitSyncKHR(QEgl::display(), - fenceSync, - EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, - EGL_FOREVER_KHR); - } - - void *data = 0; - int pitch = 0; - int surfaceWidth = 0; - int surfaceHeight = 0; - EGLSurface surface = 0; - QImage::Format format; - lockedImage = QImage(); - - surface = getSurfaceForBackingPixmap(); - if (! QMeeGoExtensions::eglLockSurfaceKHR(QEgl::display(), surface, lock_attribs)) { - qWarning("Failed to lock surface (live texture)!"); - return &lockedImage; - } - - eglQuerySurface(QEgl::display(), surface, EGL_BITMAP_POINTER_KHR, (EGLint*) &data); - eglQuerySurface(QEgl::display(), surface, EGL_BITMAP_PITCH_KHR, (EGLint*) &pitch); - eglQuerySurface(QEgl::display(), surface, EGL_WIDTH, (EGLint*) &surfaceWidth); - eglQuerySurface(QEgl::display(), surface, EGL_HEIGHT, (EGLint*) &surfaceHeight); - - // Ok, here we know we just support those two formats. Real solution would be: - // query also the format. - if (backingX11Pixmap->depth() > 16) - format = QImage::Format_ARGB32_Premultiplied; - else - format = QImage::Format_RGB16; - - if (data == NULL || pitch == 0) { - qWarning("Failed to query the live texture!"); - return &lockedImage; - } - - if (width() != surfaceWidth || height() != surfaceHeight) { - qWarning("Live texture dimensions don't match!"); - QMeeGoExtensions::eglUnlockSurfaceKHR(QEgl::display(), surface); - return &lockedImage; - } - - lockedImage = QImage((uchar *) data, width(), height(), pitch, format); - return &lockedImage; -} - -bool QMeeGoLivePixmapData::release(QImage* /*img*/) -{ - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - QMeeGoExtensions::ensureInitialized(); - - if (QMeeGoExtensions::eglUnlockSurfaceKHR(QEgl::display(), getSurfaceForBackingPixmap())) { - lockedImage = QImage(); - return true; - } else { - lockedImage = QImage(); - return false; - } -} - -Qt::HANDLE QMeeGoLivePixmapData::handle() -{ - return backingX11Pixmap->handle(); -} - -bool QMeeGoLivePixmapData::scroll(int dx, int dy, const QRect &rect) -{ - lock(NULL); - - if (!lockedImage.isNull()) - qt_scrollRectInImage(lockedImage, rect, QPoint(dx, dy)); - - release(&lockedImage); - return true; -} - -EGLSurface QMeeGoLivePixmapData::getSurfaceForBackingPixmap() -{ - initializeThroughEGLImage(); - - // This code is a crative remix of the stuff that can be found in the - // Qt's TFP implementation in /src/opengl/qgl_x11egl.cpp ::bindiTextureFromNativePixmap - QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(backingX11Pixmap->data_ptr().data()); - Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class); - bool hasAlpha = pixmapData->hasAlphaChannel(); - - if (pixmapData->gl_surface && - hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) - return pixmapData->gl_surface; - - // Check to see if the surface is still valid - if (pixmapData->gl_surface && - hasAlpha != ((pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha) > 0)) { - // Surface is invalid! - destroySurfaceForPixmapData(pixmapData); - } - - if (pixmapData->gl_surface == 0) { - EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap, - QEgl::OpenGL, - hasAlpha ? QEgl::Translucent : QEgl::NoOptions); - - pixmapData->gl_surface = (void*)QEgl::createSurface(backingX11Pixmap, config); - - if (hasAlpha) - pixmapData->flags |= QX11PixmapData::GlSurfaceCreatedWithAlpha; - else - pixmapData->flags &= ~QX11PixmapData::GlSurfaceCreatedWithAlpha; - - if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE) - return NULL; - } - - return pixmapData->gl_surface; -} - -void QMeeGoLivePixmapData::destroySurfaceForPixmapData(QPixmapData* pmd) -{ - Q_ASSERT(pmd->classId() == QPixmapData::X11Class); - QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd); - if (pixmapData->gl_surface) { - eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); - pixmapData->gl_surface = 0; - } -} - -void QMeeGoLivePixmapData::invalidateSurfaces() -{ - foreach (QMeeGoLivePixmapData *data, all_live_pixmaps) { - QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(data->backingX11Pixmap->data_ptr().data()); - *data->texture() = QGLTexture(); - pixmapData->gl_surface = 0; - } -} diff --git a/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.h b/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.h deleted file mode 100644 index 73f75143e3..0000000000 --- a/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MLIVEPIXMAPDATA_H -#define MLIVEPIXMAPDATA_H - -#include <QLinkedList> -#include <private/qpixmapdata_gl_p.h> -#include "qmeegoextensions.h" - -class QMeeGoLivePixmapData; -typedef QLinkedList<QMeeGoLivePixmapData *> QMeeGoLivePixmapDataList; - -class QMeeGoLivePixmapData : public QGLPixmapData -{ -public: - QMeeGoLivePixmapData(int w, int h, QImage::Format format); - QMeeGoLivePixmapData(Qt::HANDLE h); - ~QMeeGoLivePixmapData(); - - QPixmapData *createCompatiblePixmapData() const; - bool scroll(int dx, int dy, const QRect &rect); - - void initializeThroughEGLImage(); - - QImage* lock(EGLSyncKHR fenceSync); - bool release(QImage *img); - Qt::HANDLE handle(); - - EGLSurface getSurfaceForBackingPixmap(); - void destroySurfaceForPixmapData(QPixmapData* pmd); - - QPixmap *backingX11Pixmap; - QImage lockedImage; - QMeeGoLivePixmapDataList::Iterator pos; - - static void invalidateSurfaces(); -}; - -#endif diff --git a/src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp b/src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp deleted file mode 100644 index ec6c33fa07..0000000000 --- a/src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qmeegopixmapdata.h" -#include "qmeegoextensions.h" -#include "qmeegorasterpixmapdata.h" -#include <private/qimage_p.h> -#include <private/qwindowsurface_gl_p.h> -#include <private/qeglcontext_p.h> -#include <private/qapplication_p.h> -#include <private/qgraphicssystem_runtime_p.h> - -// from dithering.cpp -extern unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int height, int stride); -extern unsigned short* convertARGB32_to_RGBA4444(const unsigned char *in, int width, int height, int stride); -extern unsigned char* convertBGRA32_to_RGBA32(const unsigned char *in, int width, int height, int stride); - -static EGLint preserved_image_attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; - -QHash <void*, QMeeGoImageInfo*> QMeeGoPixmapData::sharedImagesMap; - -/* Public */ - -QMeeGoPixmapData::QMeeGoPixmapData() : QGLPixmapData(QPixmapData::PixmapType) -{ -} - -void QMeeGoPixmapData::fromTexture(GLuint textureId, int w, int h, bool alpha) -{ - resize(w, h); - texture()->id = textureId; - m_hasAlpha = alpha; - softImage = QImage(); -} - -QImage QMeeGoPixmapData::toImage() const -{ - return softImage; -} - -void QMeeGoPixmapData::fromImage(const QImage &image, - Qt::ImageConversionFlags flags) -{ - void *rawResource = static_cast <void *> (((QImage &) image).data_ptr()->data); - - if (sharedImagesMap.contains(rawResource)) { - QMeeGoImageInfo *info = sharedImagesMap.value(rawResource); - fromEGLSharedImage(info->handle, image); - } else { - // This should *never* happen since the graphics system should never - // create a QMeeGoPixmapData for an origin that doesn't contain a raster - // image we know about. But... - qWarning("QMeeGoPixmapData::fromImage called on non-know resource. Falling back..."); - QGLPixmapData::fromImage(image, flags); - } -} - -void QMeeGoPixmapData::fromEGLSharedImage(Qt::HANDLE handle, const QImage &si) -{ - if (si.isNull()) - qFatal("Trying to build pixmap with an empty/null softimage!"); - - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - - QMeeGoExtensions::ensureInitialized(); - - bool textureIsBound = false; - GLuint newTextureId; - GLint newWidth, newHeight; - - glGenTextures(1, &newTextureId); - glBindTexture(GL_TEXTURE_2D, newTextureId); - - EGLImageKHR image = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_SHARED_IMAGE_NOK, - (EGLClientBuffer)handle, preserved_image_attribs); - - if (image != EGL_NO_IMAGE_KHR) { - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); - GLint err = glGetError(); - if (err == GL_NO_ERROR) - textureIsBound = true; - - QMeeGoExtensions::eglQueryImageNOK(QEgl::display(), image, EGL_WIDTH, &newWidth); - QMeeGoExtensions::eglQueryImageNOK(QEgl::display(), image, EGL_HEIGHT, &newHeight); - - QEgl::eglDestroyImageKHR(QEgl::display(), image); - } - - if (textureIsBound) { - fromTexture(newTextureId, newWidth, newHeight, - (si.hasAlphaChannel() && const_cast<QImage &>(si).data_ptr()->checkForAlphaPixels())); - texture()->options &= ~QGLContext::InvertedYBindOption; - softImage = si; - QMeeGoPixmapData::registerSharedImage(handle, softImage); - } else { - qWarning("Failed to create a texture from a shared image!"); - glDeleteTextures(1, &newTextureId); - } -} - -Qt::HANDLE QMeeGoPixmapData::imageToEGLSharedImage(const QImage &image) -{ - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - - QMeeGoExtensions::ensureInitialized(); - - GLuint textureId; - - glGenTextures(1, &textureId); - glBindTexture(GL_TEXTURE_2D, textureId); - if (image.hasAlphaChannel() && const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels()) { - void *converted = convertBGRA32_to_RGBA32(image.bits(), image.width(), image.height(), image.bytesPerLine()); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, converted); - free(converted); - } else { - void *converted = convertRGB32_to_RGB565(image.bits(), image.width(), image.height(), image.bytesPerLine()); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, converted); - free(converted); - } - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glBindTexture(GL_TEXTURE_2D, textureId); - EGLImageKHR eglimage = QEgl::eglCreateImageKHR(QEgl::display(), QEglContext::currentContext(QEgl::OpenGL)->context(), - EGL_GL_TEXTURE_2D_KHR, - (EGLClientBuffer) textureId, - preserved_image_attribs); - glDeleteTextures(1, &textureId); - if (eglimage) { - EGLNativeSharedImageTypeNOK handle = QMeeGoExtensions::eglCreateSharedImageNOK(QEgl::display(), eglimage, NULL); - QEgl::eglDestroyImageKHR(QEgl::display(), eglimage); - return (Qt::HANDLE) handle; - } else { - qWarning("Failed to create shared image from pixmap/texture!"); - return 0; - } -} - -void QMeeGoPixmapData::updateFromSoftImage() -{ - // FIXME That's broken with recent 16bit textures changes. - m_dirty = true; - m_source = softImage; - ensureCreated(); - - if (softImage.width() != w || softImage.height() != h) - qWarning("Ooops, looks like softImage changed dimensions since last updated! Corruption ahead?!"); -} - -bool QMeeGoPixmapData::destroyEGLSharedImage(Qt::HANDLE h) -{ - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - QMeeGoExtensions::ensureInitialized(); - - QMutableHashIterator <void*, QMeeGoImageInfo*> i(sharedImagesMap); - while (i.hasNext()) { - i.next(); - if (i.value()->handle == h) - i.remove(); - } - - return QMeeGoExtensions::eglDestroySharedImageNOK(QEgl::display(), (EGLNativeSharedImageTypeNOK) h); -} - -void QMeeGoPixmapData::registerSharedImage(Qt::HANDLE handle, const QImage &si) -{ - void *raw = static_cast <void *> (((QImage) si).data_ptr()->data); - QMeeGoImageInfo *info; - - if (! sharedImagesMap.contains(raw)) { - info = new QMeeGoImageInfo; - info->handle = handle; - info->rawFormat = si.format(); - sharedImagesMap.insert(raw, info); - } else { - info = sharedImagesMap.value(raw); - if (info->handle != handle || info->rawFormat != si.format()) - qWarning("Inconsistency detected: overwriting entry in sharedImagesMap but handle/format different"); - } -} - -QPixmapData *QMeeGoPixmapData::createCompatiblePixmapData() const -{ - return new QMeeGoRasterPixmapData(pixelType()); -} diff --git a/src/plugins/graphicssystems/meego/qmeegopixmapdata.h b/src/plugins/graphicssystems/meego/qmeegopixmapdata.h deleted file mode 100644 index f1ff255b08..0000000000 --- a/src/plugins/graphicssystems/meego/qmeegopixmapdata.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MPIXMAPDATA_H -#define MPIXMAPDATA_H - -#include <private/qpixmapdata_gl_p.h> - -struct QMeeGoImageInfo -{ - Qt::HANDLE handle; - QImage::Format rawFormat; -}; - -class QMeeGoPixmapData : public QGLPixmapData -{ -public: - QMeeGoPixmapData(); - void fromTexture(GLuint textureId, int w, int h, bool alpha); - QPixmapData *createCompatiblePixmapData() const; - - virtual void fromEGLSharedImage(Qt::HANDLE handle, const QImage &softImage); - virtual void fromImage (const QImage &image, Qt::ImageConversionFlags flags); - virtual QImage toImage() const; - virtual void updateFromSoftImage(); - - QImage softImage; - - static QHash <void*, QMeeGoImageInfo*> sharedImagesMap; - - static Qt::HANDLE imageToEGLSharedImage(const QImage &image); - static bool destroyEGLSharedImage(Qt::HANDLE h); - static void registerSharedImage(Qt::HANDLE handle, const QImage &si); -}; - -#endif diff --git a/src/plugins/graphicssystems/opengl/opengl.pro b/src/plugins/graphicssystems/opengl/opengl.pro deleted file mode 100644 index fd3542ecf0..0000000000 --- a/src/plugins/graphicssystems/opengl/opengl.pro +++ /dev/null @@ -1,13 +0,0 @@ -TARGET = qglgraphicssystem -load(qt_plugin) - -QT += core-private gui-private opengl-private - -DESTDIR = $$QT.gui.plugins/graphicssystems - -SOURCES = main.cpp - -target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems -INSTALLS += target - -symbian: TARGET.UID3 = 0x2002131B diff --git a/src/plugins/graphicssystems/openvg/openvg.pro b/src/plugins/graphicssystems/openvg/openvg.pro deleted file mode 100644 index 6a737790a2..0000000000 --- a/src/plugins/graphicssystems/openvg/openvg.pro +++ /dev/null @@ -1,14 +0,0 @@ -TARGET = qvggraphicssystem -load(qt_plugin) - -QT += openvg - -DESTDIR = $$QT.gui.plugins/graphicssystems - -SOURCES = main.cpp qgraphicssystem_vg.cpp -HEADERS = qgraphicssystem_vg_p.h - -target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems -INSTALLS += target - -symbian: TARGET.UID3 = 0x2001E62C diff --git a/src/plugins/graphicssystems/shivavg/README b/src/plugins/graphicssystems/shivavg/README deleted file mode 100644 index 15ee7101e8..0000000000 --- a/src/plugins/graphicssystems/shivavg/README +++ /dev/null @@ -1,8 +0,0 @@ - -This graphics system uses ShivaVG (http://sourceforge.net/projects/shivavg) -to perform OpenVG rendering on X11 systems. The graphics system name for -the "-graphicssystem" command-line option is "ShivaVG". - -ShivaVG support is experimental, mostly to demonstrate how to integrate -non-EGL OpenVG engines into the system. It will probably not produce -good output. diff --git a/src/plugins/graphicssystems/shivavg/shivavg.pro b/src/plugins/graphicssystems/shivavg/shivavg.pro deleted file mode 100644 index 1d934cd685..0000000000 --- a/src/plugins/graphicssystems/shivavg/shivavg.pro +++ /dev/null @@ -1,12 +0,0 @@ -TARGET = qshivavggraphicssystem -load(qt_plugin) - -QT += openvg - -DESTDIR = $$QT.gui.plugins/graphicssystems - -SOURCES = main.cpp shivavggraphicssystem.cpp shivavgwindowsurface.cpp -HEADERS = shivavggraphicssystem.h shivavgwindowsurface.h - -target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems -INSTALLS += target diff --git a/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp b/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp deleted file mode 100644 index 448532ae92..0000000000 --- a/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#define GL_GLEXT_PROTOTYPES -#include "shivavgwindowsurface.h" -#include <QtOpenVG/private/qpaintengine_vg_p.h> -#if defined(Q_WS_X11) -#include "private/qt_x11_p.h" -#include "qx11info_x11.h" -#include <GL/glx.h> - -extern QX11Info *qt_x11Info(const QPaintDevice *pd); -#endif - -// Define this to use framebuffer objects. -//#define QVG_USE_FBO 1 - -#include <vg/openvg.h> - -QT_BEGIN_NAMESPACE - -class QShivaContext -{ -public: - QShivaContext(); - ~QShivaContext(); - - bool makeCurrent(ShivaVGWindowSurfacePrivate *surface); - void doneCurrent(); - - bool initialized; - QSize currentSize; - ShivaVGWindowSurfacePrivate *currentSurface; -}; - -Q_GLOBAL_STATIC(QShivaContext, shivaContext); - -class ShivaVGWindowSurfacePrivate -{ -public: - ShivaVGWindowSurfacePrivate() - : isCurrent(false) - , needsResize(true) - , engine(0) -#if defined(QVG_USE_FBO) - , fbo(0) - , texture(0) -#endif -#if defined(Q_WS_X11) - , drawable(0) - , context(0) -#endif - { - } - ~ShivaVGWindowSurfacePrivate(); - - void ensureContext(QWidget *widget); - - QSize size; - bool isCurrent; - bool needsResize; - QVGPaintEngine *engine; -#if defined(QVG_USE_FBO) - GLuint fbo; - GLuint texture; -#endif -#if defined(Q_WS_X11) - GLXDrawable drawable; - GLXContext context; -#endif -}; - -QShivaContext::QShivaContext() - : initialized(false) - , currentSurface(0) -{ -} - -QShivaContext::~QShivaContext() -{ - if (initialized) - vgDestroyContextSH(); -} - -bool QShivaContext::makeCurrent(ShivaVGWindowSurfacePrivate *surface) -{ - if (currentSurface) - currentSurface->isCurrent = false; - surface->isCurrent = true; - currentSurface = surface; - currentSize = surface->size; -#if defined(Q_WS_X11) - glXMakeCurrent(X11->display, surface->drawable, surface->context); -#endif - if (!initialized) { - if (!vgCreateContextSH(currentSize.width(), currentSize.height())) { - qWarning("vgCreateContextSH(%d, %d): could not create context", currentSize.width(), currentSize.height()); - return false; - } - initialized = true; - } else { - vgResizeSurfaceSH(currentSize.width(), currentSize.height()); - } -#if defined(QVG_USE_FBO) - if (surface->fbo) - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, surface->fbo); - else - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); -#endif - return true; -} - -void QShivaContext::doneCurrent() -{ - if (currentSurface) { - currentSurface->isCurrent = false; - currentSurface = 0; - } -#if defined(Q_WS_X11) - glXMakeCurrent(X11->display, 0, 0); -#endif -} - -ShivaVGWindowSurfacePrivate::~ShivaVGWindowSurfacePrivate() -{ -#if defined(QVG_USE_FBO) - if (fbo) { - glDeleteTextures(1, &texture); - glDeleteFramebuffersEXT(1, &fbo); - } -#endif -} - -void ShivaVGWindowSurfacePrivate::ensureContext(QWidget *widget) -{ -#if defined(Q_WS_X11) - Window win = widget->winId(); - if (win != drawable) { - if (context) - glXDestroyContext(X11->display, context); - drawable = win; - } - if (context == 0) { - const QX11Info *xinfo = qt_x11Info(widget); - int spec[64]; - int i = 0; - spec[i++] = GLX_DOUBLEBUFFER; - spec[i++] = GLX_DEPTH_SIZE; - spec[i++] = 1; - spec[i++] = GLX_STENCIL_SIZE; - spec[i++] = 1; - spec[i++] = GLX_RGBA; - spec[i++] = GLX_RED_SIZE; - spec[i++] = 1; - spec[i++] = GLX_GREEN_SIZE; - spec[i++] = 1; - spec[i++] = GLX_BLUE_SIZE; - spec[i++] = 1; - spec[i++] = GLX_SAMPLE_BUFFERS_ARB; - spec[i++] = 1; - spec[i++] = GLX_SAMPLES_ARB; - spec[i++] = 4; - spec[i] = XNone; - XVisualInfo *visual = glXChooseVisual - (xinfo->display(), xinfo->screen(), spec); - context = glXCreateContext(X11->display, visual, 0, True); - if (!context) - qWarning("glXCreateContext: could not create GL context for VG rendering"); - } -#else - Q_UNUSED(widget); -#endif -#if defined(QVG_USE_FBO) - if (needsResize && fbo) { -#if defined(Q_WS_X11) - glXMakeCurrent(X11->display, drawable, context); -#endif - glDeleteTextures(1, &texture); - glDeleteFramebuffersEXT(1, &fbo); -#if defined(Q_WS_X11) - glXMakeCurrent(X11->display, 0, 0); -#endif - fbo = 0; - texture = 0; - } - if (!fbo) { -#if defined(Q_WS_X11) - glXMakeCurrent(X11->display, drawable, context); -#endif - glGenFramebuffersEXT(1, &fbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size.width(), size.height(), 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2DEXT - (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, - texture, 0); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); -#if defined(Q_WS_X11) - glXMakeCurrent(X11->display, 0, 0); -#endif - } -#endif - needsResize = false; -} - -ShivaVGWindowSurface::ShivaVGWindowSurface(QWidget *window) - : QWindowSurface(window), d_ptr(new ShivaVGWindowSurfacePrivate) -{ -} - -ShivaVGWindowSurface::~ShivaVGWindowSurface() -{ - if (d_ptr->isCurrent) { - shivaContext()->doneCurrent(); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - } -#if defined(Q_WS_X11) - if (d_ptr->context) - glXDestroyContext(X11->display, d_ptr->context); -#endif - delete d_ptr; -} - -QPaintDevice *ShivaVGWindowSurface::paintDevice() -{ - d_ptr->ensureContext(window()); - shivaContext()->makeCurrent(d_ptr); - glClearDepth(0.0f); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - return this; -} - -void ShivaVGWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) -{ - Q_UNUSED(region); - Q_UNUSED(offset); - QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget(); - d_ptr->ensureContext(parent); - QShivaContext *context = shivaContext(); - if (!d_ptr->isCurrent) - context->makeCurrent(d_ptr); -#if defined(QVG_USE_FBO) - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - if (d_ptr->fbo) { - static GLfloat const vertices[][2] = { - {-1, -1}, {1, -1}, {1, 1}, {-1, 1} - }; - static GLfloat const texCoords[][2] = { - {0, 0}, {1, 0}, {1, 1}, {0, 1} - }; - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glVertexPointer(2, GL_FLOAT, 0, vertices); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - glBindTexture(GL_TEXTURE_2D, d_ptr->texture); - glEnable(GL_TEXTURE_2D); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - } -#endif -#if defined(Q_WS_X11) - glXSwapBuffers(X11->display, d_ptr->drawable); -#endif - context->doneCurrent(); -} - -void ShivaVGWindowSurface::setGeometry(const QRect &rect) -{ - QWindowSurface::setGeometry(rect); - d_ptr->needsResize = true; - d_ptr->size = rect.size(); -} - -bool ShivaVGWindowSurface::scroll(const QRegion &area, int dx, int dy) -{ - return QWindowSurface::scroll(area, dx, dy); -} - -void ShivaVGWindowSurface::beginPaint(const QRegion ®ion) -{ - // Nothing to do here. - Q_UNUSED(region); -} - -void ShivaVGWindowSurface::endPaint(const QRegion ®ion) -{ - // Nothing to do here. - Q_UNUSED(region); -} - -Q_GLOBAL_STATIC(QVGPaintEngine, sharedPaintEngine); - -QPaintEngine *ShivaVGWindowSurface::paintEngine() const -{ - if (!d_ptr->engine) - d_ptr->engine = sharedPaintEngine(); - return d_ptr->engine; -} - -int ShivaVGWindowSurface::metric(PaintDeviceMetric met) const -{ - return qt_paint_device_metric(window(), met); -} - -QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/trace/main.cpp b/src/plugins/graphicssystems/trace/main.cpp deleted file mode 100644 index c0043a2cdd..0000000000 --- a/src/plugins/graphicssystems/trace/main.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <private/qgraphicssystemplugin_p.h> -#include "qgraphicssystem_trace_p.h" - -QT_BEGIN_NAMESPACE - -class QTraceGraphicsSystemPlugin : public QGraphicsSystemPlugin -{ -public: - QStringList keys() const; - QGraphicsSystem *create(const QString&); -}; - -QStringList QTraceGraphicsSystemPlugin::keys() const -{ - return QStringList(QLatin1String("Trace")); -} - -QGraphicsSystem* QTraceGraphicsSystemPlugin::create(const QString& system) -{ - if (system.toLower() == QLatin1String("trace")) - return new QTraceGraphicsSystem; - - return 0; -} - -Q_EXPORT_PLUGIN2(trace, QTraceGraphicsSystemPlugin) - -QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp b/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp deleted file mode 100644 index 502a198099..0000000000 --- a/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgraphicssystem_trace_p.h" -#include <private/qpixmap_raster_p.h> -#include <private/qpaintbuffer_p.h> -#include <private/qwindowsurface_raster_p.h> - -#include <QFile> -#include <QPainter> -#include <QtDebug> - -QT_BEGIN_NAMESPACE - -class QTraceWindowSurface : public QRasterWindowSurface -{ -public: - QTraceWindowSurface(QWidget *widget); - ~QTraceWindowSurface(); - - QPaintDevice *paintDevice(); - void beginPaint(const QRegion &rgn); - void endPaint(const QRegion &rgn); - - bool scroll(const QRegion &area, int dx, int dy); - -private: - QPaintBuffer *buffer; - QList<QRegion> updates; - - qulonglong winId; -}; - -QTraceWindowSurface::QTraceWindowSurface(QWidget *widget) - : QRasterWindowSurface(widget) - , buffer(0) - , winId(0) -{ -} - -QTraceWindowSurface::~QTraceWindowSurface() -{ - if (buffer) { - QFile outputFile(QString(QLatin1String("qtgraphics-%0.trace")).arg(winId)); - if (outputFile.open(QIODevice::WriteOnly)) { - QDataStream out(&outputFile); - out.setFloatingPointPrecision(QDataStream::SinglePrecision); - - out.writeBytes("qttraceV2", 9); - - uint version = 1; - - out << version << *buffer << updates; - } - delete buffer; - } -} - -QPaintDevice *QTraceWindowSurface::paintDevice() -{ - if (!buffer) { - buffer = new QPaintBuffer; -#ifdef Q_WS_QPA - buffer->setBoundingRect(QRect(QPoint(), size())); -#else - buffer->setBoundingRect(geometry()); -#endif - } - return buffer; -} - -void QTraceWindowSurface::beginPaint(const QRegion &rgn) -{ - // ensure paint buffer is created - paintDevice(); - buffer->beginNewFrame(); - - QRasterWindowSurface::beginPaint(rgn); -} - -void QTraceWindowSurface::endPaint(const QRegion &rgn) -{ - QPainter p(QRasterWindowSurface::paintDevice()); - buffer->draw(&p, buffer->numFrames()-1); - p.end(); - - winId = (qulonglong)window()->winId(); - - updates << rgn; - - QRasterWindowSurface::endPaint(rgn); -} - -bool QTraceWindowSurface::scroll(const QRegion &, int, int) -{ - // TODO: scrolling should also be streamed and replayed - // to test scrolling performance - return false; -} - -QTraceGraphicsSystem::QTraceGraphicsSystem() -{ -} - -QPixmapData *QTraceGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const -{ - return new QRasterPixmapData(type); -} - -QWindowSurface *QTraceGraphicsSystem::createWindowSurface(QWidget *widget) const -{ - return new QTraceWindowSurface(widget); -} - -QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/trace/trace.pro b/src/plugins/graphicssystems/trace/trace.pro deleted file mode 100644 index f44bb3211e..0000000000 --- a/src/plugins/graphicssystems/trace/trace.pro +++ /dev/null @@ -1,13 +0,0 @@ -TARGET = qtracegraphicssystem -load(qt_plugin) - -QT += core-private gui-private network - -DESTDIR = $$QT.gui.plugins/graphicssystems -symbian:TARGET.UID3 = 0x2002130E - -SOURCES = main.cpp qgraphicssystem_trace.cpp - -target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems -INSTALLS += target -INCLUDEPATH += ../../../3rdparty/harfbuzz/src diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index 5e1f16bad4..da6b8a75bc 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -589,7 +589,6 @@ QImage ICOReader::iconAt(int index) mask.setColor(1, qRgba(0 ,0 ,0 ,0xff)); read1BitBMP(mask); if (!mask.isNull()) { - img = QImage(image.width(), image.height(), QImage::Format_ARGB32 ); img = image; img.setAlphaChannel(mask); // (Luckily, it seems that setAlphaChannel() does not ruin the alpha values diff --git a/src/plugins/inputmethods/imsw-multi/imsw-multi.pro b/src/plugins/inputmethods/imsw-multi/imsw-multi.pro deleted file mode 100644 index 4c7b9b96d8..0000000000 --- a/src/plugins/inputmethods/imsw-multi/imsw-multi.pro +++ /dev/null @@ -1,13 +0,0 @@ -TARGET = qimsw-multi -load(qt_plugin) -CONFIG += warn_on - -DESTDIR = $$QT.gui.plugins/inputmethods - -HEADERS += qmultiinputcontext.h \ - qmultiinputcontextplugin.h -SOURCES += qmultiinputcontext.cpp \ - qmultiinputcontextplugin.cpp - -target.path += $$[QT_INSTALL_PLUGINS]/inputmethods -INSTALLS += target diff --git a/src/plugins/inputmethods/imsw-multi/qmultiinputcontext.cpp b/src/plugins/inputmethods/imsw-multi/qmultiinputcontext.cpp deleted file mode 100644 index 258d586564..0000000000 --- a/src/plugins/inputmethods/imsw-multi/qmultiinputcontext.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/**************************************************************************** -** -** Implementation of QMultiInputContext class -** -** Copyright (C) 2004 immodule for Qt Project. All rights reserved. -** -** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own -** licence. You may use this file under your Qt license. Following -** description is copied from their original file headers. Contact -** immodule-qt@freedesktop.org if any conditions of this licensing are -** not clear to you. -** -****************************************************************************/ - -#ifndef QT_NO_IM -#include "qmultiinputcontext.h" -#include <qinputcontextfactory.h> -#include <qstringlist.h> -#include <qaction.h> -#include <qsettings.h> -#include <qmenu.h> - -#include <stdlib.h> - -QT_BEGIN_NAMESPACE - -QMultiInputContext::QMultiInputContext() - : QInputContext(), current(-1) -{ - keys = QInputContextFactory::keys(); - for (int i = keys.size()-1; i >= 0; --i) - if (keys.at(i).contains(QLatin1String("imsw"))) - keys.removeAt(i); - - QString def = QLatin1String(getenv("QT4_IM_MODULE")); - if (def.isEmpty()) - def = QLatin1String(getenv("QT_IM_MODULE")); - if (def.isEmpty()) { - QSettings settings(QSettings::UserScope, QLatin1String("Trolltech")); - settings.beginGroup(QLatin1String("Qt")); - def = settings.value(QLatin1String("DefaultInputMethod"), QLatin1String("xim")).toString(); - } - current = keys.indexOf(def); - if (current < 0) - current = 0; - - menu = new QMenu(tr("Select IM")); - separator = new QAction(this); - separator->setSeparator(true); - - QActionGroup *group = new QActionGroup(this); - for (int i = 0; i < keys.size(); ++i) { - slaves.append(0); - const QString key = keys.at(i); - QAction *a = menu->addAction(QInputContextFactory::displayName(key)); - a->setData(key); - a->setCheckable(true); - group->addAction(a); - if (i == current) { - slaves.replace(current, QInputContextFactory::create(key, this)); - a->setChecked(true); - } - } - connect(group, SIGNAL(triggered(QAction*)), this, SLOT(changeSlave(QAction*))); -} - -QMultiInputContext::~QMultiInputContext() -{ - delete menu; -} - - -QString QMultiInputContext::identifierName() -{ - return (slave()) ? slave()->identifierName() : QLatin1String(""); -} - -QString QMultiInputContext::language() -{ - return (slave()) ? slave()->language() : QLatin1String(""); -} - - -#if defined(Q_WS_X11) -bool QMultiInputContext::x11FilterEvent(QWidget *keywidget, XEvent *event) -{ - return (slave()) ? slave()->x11FilterEvent(keywidget, event) : false; -} -#endif // Q_WS_X11 - - -bool QMultiInputContext::filterEvent(const QEvent *event) -{ - return (slave()) ? slave()->filterEvent(event) : false; -} - -void QMultiInputContext::reset() -{ - if (slave()) - slave()->reset(); -} - -void QMultiInputContext::update() -{ - if (slave()) - slave()->update(); -} - -void QMultiInputContext::mouseHandler(int x, QMouseEvent *event) -{ - if (slave()) - slave()->mouseHandler(x, event); -} - -QFont QMultiInputContext::font() const -{ - return (slave()) ? slave()->font() : QInputContext::font(); -} - -void QMultiInputContext::setFocusWidget(QWidget *w) -{ - QInputContext::setFocusWidget(w); - if (slave()) - slave()->setFocusWidget(w); -} - -QWidget *QMultiInputContext::focusWidget() const -{ - return QInputContext::focusWidget(); -} - -void QMultiInputContext::widgetDestroyed(QWidget *w) -{ - if (slave()) - slave()->widgetDestroyed(w); -} - -bool QMultiInputContext::isComposing() const -{ - return (slave()) ? slave()->isComposing() : false; -} - -QList<QAction *> QMultiInputContext::actions() -{ - QList<QAction *> a = slave()->actions(); - a.append(separator); - a.append(menu->menuAction()); - return a; -} - -void QMultiInputContext::changeSlave(QAction *a) -{ - for (int i = 0; i < slaves.size(); ++i) { - if (keys.at(i) == a->data().toString()) { - if (slaves.at(i) == 0) - slaves.replace(i, QInputContextFactory::create(keys.at(i), this)); - QInputContext *qic = slaves.at(current); - QWidget *oldWidget = qic->focusWidget(); - qic->reset(); - qic->setFocusWidget(0); - current = i; - qic = slaves.at(current); - qic->setFocusWidget(oldWidget); - return; - } - } -} - -QT_END_NAMESPACE - -#endif // QT_NO_IM diff --git a/src/plugins/inputmethods/imsw-multi/qmultiinputcontext.h b/src/plugins/inputmethods/imsw-multi/qmultiinputcontext.h deleted file mode 100644 index 5d311b3f4b..0000000000 --- a/src/plugins/inputmethods/imsw-multi/qmultiinputcontext.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/**************************************************************************** -** -** Definition of QMultiInputContext class -** -** Copyright (C) 2004 immodule for Qt Project. All rights reserved. -** -** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own -** licence. You may use this file under your Qt license. Following -** description is copied from their original file headers. Contact -** immodule-qt@freedesktop.org if any conditions of this licensing are -** not clear to you. -** -****************************************************************************/ - -#ifndef QMULTIINPUTCONTEXT_H -#define QMULTIINPUTCONTEXT_H - -#ifndef QT_NO_IM - -#include <QtGui/qwidget.h> -#include <QtGui/qinputcontext.h> -#include <QtCore/qstring.h> -#include <QtCore/qnamespace.h> -#include <QtCore/qmap.h> -#include <QtCore/qpointer.h> -#include <QtCore/qlist.h> - -QT_BEGIN_NAMESPACE - -class QMultiInputContext : public QInputContext -{ - Q_OBJECT -public: - QMultiInputContext(); - ~QMultiInputContext(); - - QString identifierName(); - QString language(); - -#if defined(Q_WS_X11) - bool x11FilterEvent( QWidget *keywidget, XEvent *event ); -#endif // Q_WS_X11 - bool filterEvent( const QEvent *event ); - - void reset(); - void update(); - void mouseHandler( int x, QMouseEvent *event ); - QFont font() const; - bool isComposing() const; - - QList<QAction *> actions(); - - QWidget *focusWidget() const; - void setFocusWidget(QWidget *w); - - void widgetDestroyed( QWidget *w ); - - QInputContext *slave() { return slaves.at(current); } - const QInputContext *slave() const { return slaves.at(current); } - -protected Q_SLOTS: - void changeSlave(QAction *); -private: - void *unused; - int current; - QList<QInputContext *> slaves; - QMenu *menu; - QAction *separator; - QStringList keys; -}; - -#endif // Q_NO_IM - -QT_END_NAMESPACE - -#endif // QMULTIINPUTCONTEXT_H diff --git a/src/plugins/inputmethods/imsw-multi/qmultiinputcontextplugin.cpp b/src/plugins/inputmethods/imsw-multi/qmultiinputcontextplugin.cpp deleted file mode 100644 index 1f56e2350b..0000000000 --- a/src/plugins/inputmethods/imsw-multi/qmultiinputcontextplugin.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/**************************************************************************** -** -** Implementation of QMultiInputContextPlugin class -** -** Copyright (C) 2004 immodule for Qt Project. All rights reserved. -** -** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own -** license. You may use this file under your Qt license. Following -** description is copied from their original file headers. Contact -** immodule-qt@freedesktop.org if any conditions of this licensing are -** not clear to you. -** -****************************************************************************/ - -#ifndef QT_NO_IM -#include "qmultiinputcontext.h" -#include "qmultiinputcontextplugin.h" -#include <qinputcontextplugin.h> -#include <qstringlist.h> - -QT_BEGIN_NAMESPACE - -QMultiInputContextPlugin::QMultiInputContextPlugin() -{ -} - -QMultiInputContextPlugin::~QMultiInputContextPlugin() -{ -} - -QStringList QMultiInputContextPlugin::keys() const -{ - // input method switcher should named with "imsw-" prefix to - // prevent to be listed in ordinary input method list. - return QStringList( QLatin1String("imsw-multi") ); -} - -QInputContext *QMultiInputContextPlugin::create( const QString &key ) -{ - if (key != QLatin1String("imsw-multi")) - return 0; - return new QMultiInputContext; -} - -QStringList QMultiInputContextPlugin::languages( const QString & ) -{ - return QStringList(); -} - -QString QMultiInputContextPlugin::displayName( const QString &key ) -{ - if (key != QLatin1String("imsw-multi")) - return QString(); - return tr( "Multiple input method switcher" ); -} - -QString QMultiInputContextPlugin::description( const QString &key ) -{ - if (key != QLatin1String("imsw-multi")) - return QString(); - return tr( "Multiple input method switcher that uses the context menu of the text widgets" ); -} - - -Q_EXPORT_STATIC_PLUGIN(QMultiInputContextPlugin) -Q_EXPORT_PLUGIN2(qimsw_multi, QMultiInputContextPlugin) - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/inputmethods/imsw-multi/qmultiinputcontextplugin.h b/src/plugins/inputmethods/imsw-multi/qmultiinputcontextplugin.h deleted file mode 100644 index c18112ff8b..0000000000 --- a/src/plugins/inputmethods/imsw-multi/qmultiinputcontextplugin.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/**************************************************************************** -** -** Definition of QMultiInputContextPlugin class -** -** Copyright (C) 2004 immodule for Qt Project. All rights reserved. -** -** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own -** license. You may use this file under your Qt license. Following -** description is copied from their original file headers. Contact -** immodule-qt@freedesktop.org if any conditions of this licensing are -** not clear to you. -** -****************************************************************************/ - -#ifndef QMULTIINPUTCONTEXTPLUGIN_H -#define QMULTIINPUTCONTEXTPLUGIN_H - -#ifndef QT_NO_IM - -#include "qmultiinputcontext.h" -#include <QtGui/qinputcontextplugin.h> -#include <QtCore/qstringlist.h> - -QT_BEGIN_NAMESPACE - -class QMultiInputContextPlugin : public QInputContextPlugin -{ - Q_OBJECT -public: - QMultiInputContextPlugin(); - ~QMultiInputContextPlugin(); - - QStringList keys() const; - QInputContext *create( const QString &key ); - QStringList languages( const QString &key ); - QString displayName( const QString &key ); - QString description( const QString &key ); -}; - -#endif // QT_NO_IM - -QT_END_NAMESPACE - -#endif // QMULTIINPUTCONTEXTPLUGIN_H diff --git a/src/plugins/inputmethods/inputmethods.pro b/src/plugins/inputmethods/inputmethods.pro deleted file mode 100644 index e1ca847519..0000000000 --- a/src/plugins/inputmethods/inputmethods.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS = imsw-multi diff --git a/src/plugins/kbddrivers/kbddrivers.pro b/src/plugins/kbddrivers/kbddrivers.pro deleted file mode 100644 index dbab47b366..0000000000 --- a/src/plugins/kbddrivers/kbddrivers.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -contains(kbd-plugins, linuxinput): SUBDIRS += linuxinput diff --git a/src/plugins/kbddrivers/linuxinput/linuxinput.pro b/src/plugins/kbddrivers/linuxinput/linuxinput.pro deleted file mode 100644 index 8eaa786ce0..0000000000 --- a/src/plugins/kbddrivers/linuxinput/linuxinput.pro +++ /dev/null @@ -1,14 +0,0 @@ -TARGET = qlinuxinputkbddriver -load(qt_plugin) - -DESTDIR = $$QT.gui.plugins/kbddrivers -target.path = $$[QT_INSTALL_PLUGINS]/kbddrivers -INSTALLS += target - -DEFINES += QT_QWS_KBD_LINUXINPUT - -HEADERS = $$QT_SOURCE_TREE/src/gui/embedded/qkbdlinuxinput_qws.h - -SOURCES = main.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qkbdlinuxinput_qws.cpp - diff --git a/src/plugins/kbddrivers/linuxinput/main.cpp b/src/plugins/kbddrivers/linuxinput/main.cpp deleted file mode 100644 index 9affaa67ea..0000000000 --- a/src/plugins/kbddrivers/linuxinput/main.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qkbddriverplugin_qws.h> -#include <qkbdlinuxinput_qws.h> - -QT_BEGIN_NAMESPACE - -class QLinuxInputKbdDriver : public QKbdDriverPlugin -{ -public: - QLinuxInputKbdDriver(); - - QStringList keys() const; - QWSKeyboardHandler* create(const QString &driver, const QString &device); -}; - -QLinuxInputKbdDriver::QLinuxInputKbdDriver() - : QKbdDriverPlugin() -{ -} - -QStringList QLinuxInputKbdDriver::keys() const -{ - return (QStringList() << QLatin1String("LinuxInput")); -} - -QWSKeyboardHandler* QLinuxInputKbdDriver::create(const QString &driver, - const QString &device) -{ - Q_UNUSED(device); - if (driver.compare(QLatin1String("LinuxInput"), Qt::CaseInsensitive)) - return 0; - return new QWSLinuxInputKeyboardHandler(device); -} - -Q_EXPORT_PLUGIN2(qwslinuxinputkbddriver, QLinuxInputKbdDriver) - -QT_END_NAMESPACE diff --git a/src/plugins/mousedrivers/linuxtp/linuxtp.pro b/src/plugins/mousedrivers/linuxtp/linuxtp.pro deleted file mode 100644 index e5d274a0b7..0000000000 --- a/src/plugins/mousedrivers/linuxtp/linuxtp.pro +++ /dev/null @@ -1,14 +0,0 @@ -TARGET = qlinuxtpmousedriver -load(qt_plugin) - -DESTDIR = $$QT.gui.plugins/mousedrivers -target.path = $$[QT_INSTALL_PLUGINS]/mousedrivers -INSTALLS += target - -DEFINES += QT_QWS_MOUSE_LINUXTP - -HEADERS = $$QT_SOURCE_TREE/src/gui/embedded/qmouselinuxtp_qws.h - -SOURCES = main.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qmouselinuxtp_qws.cpp - diff --git a/src/plugins/mousedrivers/linuxtp/main.cpp b/src/plugins/mousedrivers/linuxtp/main.cpp deleted file mode 100644 index 64a69ef7f1..0000000000 --- a/src/plugins/mousedrivers/linuxtp/main.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qmousedriverplugin_qws.h> -#include <qmouselinuxtp_qws.h> - -QT_BEGIN_NAMESPACE - -class QLinuxTPMouseDriver : public QMouseDriverPlugin -{ -public: - QLinuxTPMouseDriver(); - - QStringList keys() const; - QWSMouseHandler* create(const QString &driver, const QString &device); -}; - -QLinuxTPMouseDriver::QLinuxTPMouseDriver() - : QMouseDriverPlugin() -{ -} - -QStringList QLinuxTPMouseDriver::keys() const -{ - return (QStringList() << "LinuxTP"); -} - -QWSMouseHandler* QLinuxTPMouseDriver::create(const QString &driver, - const QString &device) -{ - if (driver.compare(QLatin1String("LinuxTP"), Qt::CaseInsensitive)) - return 0; - return new QWSLinuxTPMouseHandler(driver, device); -} - -Q_EXPORT_PLUGIN2(qwslinuxtpmousehandler, QLinuxTPMouseDriver) - -QT_END_NAMESPACE diff --git a/src/plugins/mousedrivers/mousedrivers.pro b/src/plugins/mousedrivers/mousedrivers.pro deleted file mode 100644 index f89682b880..0000000000 --- a/src/plugins/mousedrivers/mousedrivers.pro +++ /dev/null @@ -1,5 +0,0 @@ -TEMPLATE = subdirs -contains(mouse-plugins, linuxtp): SUBDIRS += linuxtp -contains(mouse-plugins, pc): SUBDIRS += pc -contains(mouse-plugins, tslib): SUBDIRS += tslib -contains(mouse-plugins, linuxinput): SUBDIRS += linuxinput diff --git a/src/plugins/mousedrivers/pc/main.cpp b/src/plugins/mousedrivers/pc/main.cpp deleted file mode 100644 index fbd23dab0f..0000000000 --- a/src/plugins/mousedrivers/pc/main.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qmousedriverplugin_qws.h> -#include <qmousepc_qws.h> - -QT_BEGIN_NAMESPACE - -class QPcMouseDriver : public QMouseDriverPlugin -{ -public: - QPcMouseDriver(); - - QStringList keys() const; - QWSMouseHandler* create(const QString &driver, const QString &device); -}; - -QPcMouseDriver::QPcMouseDriver() - : QMouseDriverPlugin() -{ -} - -QStringList QPcMouseDriver::keys() const -{ - return (QStringList() - << QLatin1String("Auto") - << QLatin1String("IntelliMouse") - << QLatin1String("Microsoft") - << QLatin1String("MouseSystems") - << QLatin1String("MouseMan")); -} - -QWSMouseHandler* QPcMouseDriver::create(const QString &driver, - const QString &device) -{ - if (!keys().contains(driver, Qt::CaseInsensitive)) - return 0; - return new QWSPcMouseHandler(driver, device); -} - -Q_EXPORT_PLUGIN2(qwspcmousehandler, QPcMouseDriver) - -QT_END_NAMESPACE diff --git a/src/plugins/mousedrivers/pc/pc.pro b/src/plugins/mousedrivers/pc/pc.pro deleted file mode 100644 index 04d7b0f06f..0000000000 --- a/src/plugins/mousedrivers/pc/pc.pro +++ /dev/null @@ -1,14 +0,0 @@ -TARGET = qpcmousedriver -load(qt_plugin) - -DESTDIR = $$QT.gui.plugins/mousedrivers -target.path = $$[QT_INSTALL_PLUGINS]/mousedrivers -INSTALLS += target - -DEFINES += QT_QWS_MOUSE_PC - -HEADERS = $$QT_SOURCE_TREE/src/gui/embedded/qmousepc_qws.h - -SOURCES = main.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qmousepc_qws.cpp - diff --git a/src/plugins/mousedrivers/tslib/main.cpp b/src/plugins/mousedrivers/tslib/main.cpp deleted file mode 100644 index 1d6f8535ba..0000000000 --- a/src/plugins/mousedrivers/tslib/main.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qmousedriverplugin_qws.h> -#include <qmousetslib_qws.h> - -QT_BEGIN_NAMESPACE - -class TslibMouseDriver : public QMouseDriverPlugin -{ -public: - TslibMouseDriver(); - - QStringList keys() const; - QWSMouseHandler* create(const QString &driver, const QString &device); -}; - -TslibMouseDriver::TslibMouseDriver() - : QMouseDriverPlugin() -{ -} - -QStringList TslibMouseDriver::keys() const -{ - return (QStringList() << "tslib"); -} - -QWSMouseHandler* TslibMouseDriver::create(const QString &driver, - const QString &device) -{ - if (driver.toLower() != "tslib") - return 0; - return new QWSTslibMouseHandler(driver, device); -} - -Q_EXPORT_STATIC_PLUGIN(TslibMouseDriver) -Q_EXPORT_PLUGIN2(qwstslibmousehandler, TslibMouseDriver) - -QT_END_NAMESPACE diff --git a/src/plugins/mousedrivers/tslib/tslib.pro b/src/plugins/mousedrivers/tslib/tslib.pro deleted file mode 100644 index 552a2e7173..0000000000 --- a/src/plugins/mousedrivers/tslib/tslib.pro +++ /dev/null @@ -1,16 +0,0 @@ -TARGET = qtslibmousedriver -load(qt_plugin) - -DESTDIR = $$QT.gui.plugins/mousedrivers - -HEADERS = \ - $$QT_SOURCE_TREE/src/gui/embedded/qmousedriverplugin_qws.h \ - $$QT_SOURCE_TREE/src/gui/embedded/qmousetslib_qws.h -SOURCES = main.cpp \ - $$QT_SOURCE_TREE/src/gui/embedded/qmousetslib_qws.cpp - -LIBS += -lts - -target.path += $$[QT_INSTALL_PLUGINS]/mousedrivers -INSTALLS += target - diff --git a/src/plugins/platforminputcontexts/ibus/ibus.pro b/src/plugins/platforminputcontexts/ibus/ibus.pro new file mode 100644 index 0000000000..193dad0018 --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/ibus.pro @@ -0,0 +1,19 @@ +TARGET = ibusplatforminputcontextplugin +load(qt_plugin) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforminputcontexts + +QT += dbus platformsupport-private +SOURCES += $$PWD/qibusplatforminputcontext.cpp \ + $$PWD/qibusproxy.cpp \ + $$PWD/qibusinputcontextproxy.cpp \ + $$PWD/qibustypes.cpp \ + $$PWD/main.cpp + +HEADERS += $$PWD/qibusplatforminputcontext.h \ + $$PWD/qibusproxy.h \ + $$PWD/qibusinputcontextproxy.h \ + $$PWD/qibustypes.h + +target.path += $$[QT_INSTALL_PLUGINS]/platforminputcontexts +INSTALLS += target diff --git a/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml new file mode 100644 index 0000000000..dbc79c178b --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml @@ -0,0 +1,80 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.freedesktop.IBus.InputContext"> + <method name="ProcessKeyEvent"> + <arg name="keyval" direction="in" type="u"/> + <arg name="keycode" direction="in" type="u"/> + <arg name="state" direction="in" type="u"/> + <arg name="handled" direction="out" type="b"/> + </method> + <method name="SetCursorLocation"> + <arg name="x" direction="in" type="i"/> + <arg name="y" direction="in" type="i"/> + <arg name="w" direction="in" type="i"/> + <arg name="h" direction="in" type="i"/> + </method> + <method name="FocusIn"/> + <method name="FocusOut"/> + <method name="Reset"/> + <method name="Enable"/> + <method name="Disable"/> + <method name="IsEnabled"> + <arg name="enable" direction="out" type="b"/> + </method> + <method name="SetCapabilities"> + <arg name="caps" direction="in" type="u"/> + </method> + <method name="PropertyActivate"> + <arg name="name" direction="in" type="s"/> + <arg name="state" direction="in" type="i"/> + </method> + <method name="SetEngine"> + <arg name="name" direction="in" type="s"/> + </method> + <method name="GetEngine"> + <arg name="desc" direction="out" type="v"/> + </method> + <method name="Destroy"/> + <signal name="CommitText"> + <arg name="text" type="v"/> + </signal> + <signal name="Enabled"/> + <signal name="Disabled"/> + <signal name="ForwardKeyEvent"> + <arg name="keyval" type="u"/> + <arg name="keycode" type="u"/> + <arg name="state" type="u"/> + </signal> + <signal name="UpdatePreeditText"> + <arg name="text" type="v"/> + <arg name="cursor_pos" type="u"/> + <arg name="visible" type="b"/> + </signal> + <signal name="ShowPreeditText"/> + <signal name="HidePreeditText"/> + <signal name="UpdateAuxiliaryText"> + <arg name="text" type="v"/> + <arg name="visible" type="b"/> + </signal> + <signal name="ShowAuxiliaryText"/> + <signal name="HideAuxiliaryText"/> + <signal name="UpdateLookupTable"> + <arg name="table" type="v"/> + <arg name="visible" type="b"/> + </signal> + <signal name="ShowLookupTable"/> + <signal name="HideLookupTable"/> + <signal name="PageUpLookupTable"/> + <signal name="PageDownLookupTable"/> + <signal name="CursorUpLookupTable"/> + <signal name="CursorDownLookupTable"/> + <signal name="RegisterProperties"> + <arg name="props" type="v"/> + </signal> + <signal name="UpdateProperty"> + <arg name="prop" type="v"/> + </signal> + </interface> +</node> + diff --git a/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.xml b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.xml new file mode 100644 index 0000000000..6ac4891771 --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.xml @@ -0,0 +1,30 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.freedesktop.IBus"> + <method name="GetAddress"> + <arg name="address" direction="out" type="s"/> + </method> + <method name="CreateInputContext"> + <arg name="name" direction="in" type="s"/> + <arg name="context" direction="out" type="o"/> + </method> + <method name="RegisterComponent"> + <arg name="components" direction="in" type="v"/> + </method> + <method name="ListEngines"> + <arg name="engines" direction="out" type="av"/> + </method> + <method name="ListActiveEngines"> + <arg name="engines" direction="out" type="av"/> + </method> + <method name="Exit"> + <arg name="restart" direction="in" type="b"/> + </method> + <method name="Ping"> + <arg name="data" direction="in" type="v"/> + <arg name="data" direction="out" type="v"/> + </method> + </interface> +</node> + diff --git a/src/plugins/gfxdrivers/linuxfb/main.cpp b/src/plugins/platforminputcontexts/ibus/main.cpp index 187237f042..eb773c8856 100644 --- a/src/plugins/gfxdrivers/linuxfb/main.cpp +++ b/src/plugins/platforminputcontexts/ibus/main.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Contact: Nokia Corporation (info@qt.nokia.com) ** ** This file is part of the plugins of the Qt Toolkit. ** @@ -39,41 +39,33 @@ ** ****************************************************************************/ -#include <qscreendriverplugin_qws.h> -#include <qscreenlinuxfb_qws.h> -#include <qstringlist.h> +#include <private/qplatforminputcontextplugin_qpa_p.h> +#include <QtCore/QStringList> +#include "qibusplatforminputcontext.h" QT_BEGIN_NAMESPACE -class QScreenLinuxFbPlugin : public QScreenDriverPlugin +class QIbusPlatformInputContextPlugin : public QPlatformInputContextPlugin { public: - QScreenLinuxFbPlugin(); - QStringList keys() const; - QScreen *create(const QString&, int displayId); + QIBusPlatformInputContext *create(const QString&, const QStringList&); }; -QScreenLinuxFbPlugin::QScreenLinuxFbPlugin() - : QScreenDriverPlugin() -{ -} - -QStringList QScreenLinuxFbPlugin::keys() const +QStringList QIbusPlatformInputContextPlugin::keys() const { - QStringList list; - list << QLatin1String("LinuxFb"); - return list; + return QStringList(QStringLiteral("ibus")); } -QScreen* QScreenLinuxFbPlugin::create(const QString& driver, int displayId) +QIBusPlatformInputContext *QIbusPlatformInputContextPlugin::create(const QString& system, const QStringList& paramList) { - if (driver.toLower() == QLatin1String("linuxfb")) - return new QLinuxFbScreen(displayId); + Q_UNUSED(paramList); + if (system.compare(system, QStringLiteral("ibus"), Qt::CaseInsensitive) == 0) + return new QIBusPlatformInputContext; return 0; } -Q_EXPORT_PLUGIN2(qscreenlinuxfb, QScreenLinuxFbPlugin) +Q_EXPORT_PLUGIN2(ibusplatforminputcontextplugin, QIbusPlatformInputContextPlugin) QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp new file mode 100644 index 0000000000..7adffbc2e2 --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp @@ -0,0 +1,26 @@ +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -N -p qibusinputcontextproxy -c QIBusInputContextProxy interfaces/org.freedesktop.IBus.InputContext.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "qibusinputcontextproxy.h" + +/* + * Implementation of interface class QIBusInputContextProxy + */ + +QIBusInputContextProxy::QIBusInputContextProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +QIBusInputContextProxy::~QIBusInputContextProxy() +{ +} + diff --git a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h new file mode 100644 index 0000000000..9a91c4e484 --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h @@ -0,0 +1,144 @@ +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -N -p qibusinputcontextproxy -c QIBusInputContextProxy interfaces/org.freedesktop.IBus.InputContext.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef QIBUSINPUTCONTEXTPROXY_H_1308831153 +#define QIBUSINPUTCONTEXTPROXY_H_1308831153 + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface org.freedesktop.IBus.InputContext + */ +class QIBusInputContextProxy: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.freedesktop.IBus.InputContext"; } + +public: + QIBusInputContextProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~QIBusInputContextProxy(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<> Destroy() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("Destroy"), argumentList); + } + + inline QDBusPendingReply<> Disable() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("Disable"), argumentList); + } + + inline QDBusPendingReply<> Enable() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("Enable"), argumentList); + } + + inline QDBusPendingReply<> FocusIn() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("FocusIn"), argumentList); + } + + inline QDBusPendingReply<> FocusOut() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("FocusOut"), argumentList); + } + + inline QDBusPendingReply<QDBusVariant> GetEngine() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("GetEngine"), argumentList); + } + + inline QDBusPendingReply<bool> IsEnabled() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("IsEnabled"), argumentList); + } + + inline QDBusPendingReply<bool> ProcessKeyEvent(uint keyval, uint keycode, uint state) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(keyval) << QVariant::fromValue(keycode) << QVariant::fromValue(state); + return asyncCallWithArgumentList(QLatin1String("ProcessKeyEvent"), argumentList); + } + + inline QDBusPendingReply<> PropertyActivate(const QString &name, int state) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(name) << QVariant::fromValue(state); + return asyncCallWithArgumentList(QLatin1String("PropertyActivate"), argumentList); + } + + inline QDBusPendingReply<> Reset() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("Reset"), argumentList); + } + + inline QDBusPendingReply<> SetCapabilities(uint caps) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(caps); + return asyncCallWithArgumentList(QLatin1String("SetCapabilities"), argumentList); + } + + inline QDBusPendingReply<> SetCursorLocation(int x, int y, int w, int h) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h); + return asyncCallWithArgumentList(QLatin1String("SetCursorLocation"), argumentList); + } + + inline QDBusPendingReply<> SetEngine(const QString &name) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(name); + return asyncCallWithArgumentList(QLatin1String("SetEngine"), argumentList); + } + +Q_SIGNALS: // SIGNALS + void CommitText(const QDBusVariant &text); + void CursorDownLookupTable(); + void CursorUpLookupTable(); + void Disabled(); + void Enabled(); + void ForwardKeyEvent(uint keyval, uint keycode, uint state); + void HideAuxiliaryText(); + void HideLookupTable(); + void HidePreeditText(); + void PageDownLookupTable(); + void PageUpLookupTable(); + void RegisterProperties(const QDBusVariant &props); + void ShowAuxiliaryText(); + void ShowLookupTable(); + void ShowPreeditText(); + void UpdateAuxiliaryText(const QDBusVariant &text, bool visible); + void UpdateLookupTable(const QDBusVariant &table, bool visible); + void UpdatePreeditText(const QDBusVariant &text, uint cursor_pos, bool visible); + void UpdateProperty(const QDBusVariant &prop); +}; + +#endif diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp new file mode 100644 index 0000000000..af8fd5a1f1 --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -0,0 +1,329 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qibusplatforminputcontext.h" + +#include <QtDebug> +#include <QTextCharFormat> +#include <QGuiApplication> +#include <qwindow.h> +#include <qevent.h> + +#include "qibusproxy.h" +#include "qibusinputcontextproxy.h" +#include "qibustypes.h" + +#include <sys/types.h> +#include <signal.h> + +#include <QtDBus> + +enum { debug = 0 }; + +class QIBusPlatformInputContextPrivate +{ +public: + QIBusPlatformInputContextPrivate(); + ~QIBusPlatformInputContextPrivate() + { + delete context; + delete bus; + delete connection; + } + + static QDBusConnection *createConnection(); + + QDBusConnection *connection; + QIBusProxy *bus; + QIBusInputContextProxy *context; + + bool valid; +}; + + +QIBusPlatformInputContext::QIBusPlatformInputContext () + : d(new QIBusPlatformInputContextPrivate()) +{ + if (d->context) { + connect(d->context, SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant))); + connect(d->context, SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool))); + } + QInputPanel *p = qApp->inputPanel(); + connect(p, SIGNAL(inputItemChanged()), this, SLOT(inputItemChanged())); + connect(p, SIGNAL(cursorRectangleChanged()), this, SLOT(cursorRectChanged())); +} + +QIBusPlatformInputContext::~QIBusPlatformInputContext (void) +{ + delete d; +} + +bool QIBusPlatformInputContext::isValid() const +{ + return d->valid; +} + +void QIBusPlatformInputContext::invokeAction(QInputPanel::Action a, int x) +{ + QPlatformInputContext::invokeAction(a, x); + + if (!d->valid) + return; +} + +void QIBusPlatformInputContext::reset() +{ + QPlatformInputContext::reset(); + + if (!d->valid) + return; + + d->context->Reset(); +} + +void QIBusPlatformInputContext::update(Qt::InputMethodQueries q) +{ + QPlatformInputContext::update(q); +} + +void QIBusPlatformInputContext::cursorRectChanged() +{ + if (!d->valid) + return; + + QRect r = qApp->inputPanel()->cursorRectangle().toRect(); + if(!r.isValid()) + return; + + QWindow *inputWindow = qApp->inputPanel()->inputWindow(); + r.moveTopLeft(inputWindow->mapToGlobal(r.topLeft())); + if (debug) + qDebug() << "microFocus" << r; + d->context->SetCursorLocation(r.x(), r.y(), r.width(), r.height()); +} + +void QIBusPlatformInputContext::inputItemChanged() +{ + if (!d->valid) + return; + + QObject *input = qApp->inputPanel()->inputItem(); + if (debug) + qDebug() << "setFocusObject" << input; + if (input) + d->context->FocusIn(); + else + d->context->FocusOut(); +} + + +void QIBusPlatformInputContext::commitText(const QDBusVariant &text) +{ + QObject *input = qApp->inputPanel()->inputItem(); + if (!input) + return; + + const QDBusArgument arg = text.variant().value<QDBusArgument>(); + + QIBusText t; + if (debug) + qDebug() << arg.currentSignature(); + t.fromDBusArgument(arg); + if (debug) + qDebug() << "commit text:" << t.text; + + QInputMethodEvent event; + event.setCommitString(t.text); + QCoreApplication::sendEvent(input, &event); +} + +void QIBusPlatformInputContext::updatePreeditText(const QDBusVariant &text, uint cursorPos, bool visible) +{ + QObject *input = qApp->inputPanel()->inputItem(); + if (!input) + return; + + const QDBusArgument arg = text.variant().value<QDBusArgument>(); + + QIBusText t; + t.fromDBusArgument(arg); + if (debug) + qDebug() << "preedit text:" << t.text; + + QList<QInputMethodEvent::Attribute> attributes = t.attributes.imAttributes(); + attributes += QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursorPos, visible ? 1 : 0, QVariant()); + + QInputMethodEvent event(t.text, attributes); + QCoreApplication::sendEvent(input, &event); +} + + +/* Kernel keycode -> X keycode table */ +static const unsigned int keycode_table[256] = { + 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 111, 221, 94, 95, 96, 211, 128, 127, 129, 208, 131, 126, + 108, 109, 112, 111, 113, 181, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107, + 239, 160, 174, 176, 222, 157, 123, 110, 139, 134, 209, 210, 133, 115, 116, 117, + 232, 133, 134, 135, 140, 248, 191, 192, 122, 188, 245, 158, 161, 193, 223, 227, + 198, 199, 200, 147, 159, 151, 178, 201, 146, 203, 166, 236, 230, 235, 234, 233, + 163, 204, 253, 153, 162, 144, 164, 177, 152, 190, 208, 129, 130, 231, 209, 210, + 136, 220, 143, 246, 251, 137, 138, 182, 183, 184, 93, 184, 247, 132, 170, 219, + 249, 205, 207, 149, 150, 154, 155, 167, 168, 169, 171, 172, 173, 165, 175, 179, + 180, 0, 185, 186, 187, 118, 119, 120, 121, 229, 194, 195, 196, 197, 148, 202, + 101, 212, 237, 214, 215, 216, 217, 218, 228, 142, 213, 240, 241, 242, 243, 244, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +bool +QIBusPlatformInputContext::x11FilterEvent(uint keyval, uint keycode, uint state, bool press) +{ + if (!d->valid) + return false; + + if (!press) + return false; + + keycode -= 8; // ### + QDBusReply<bool> reply = d->context->ProcessKeyEvent(keyval, keycode, state); + +// qDebug() << "x11FilterEvent return" << reply.value(); + + return reply.value(); +} + +QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate() + : connection(createConnection()), + bus(0), + context(0), + valid(false) +{ + if (!connection || !connection->isConnected()) { + qDebug("QIBusPlatformInputContext: not connected."); + return; + } + + bus = new QIBusProxy(QLatin1String("org.freedesktop.IBus"), + QLatin1String("/org/freedesktop/IBus"), + *connection); + if (!bus->isValid()) { + qWarning("QIBusPlatformInputContext: invalid bus."); + return; + } + + QDBusReply<QDBusObjectPath> ic = bus->CreateInputContext(QLatin1String("QIBusInputContext")); + if (!ic.isValid()) { + qWarning("QIBusPlatformInputContext: CreateInputContext failed."); + return; + } + + context = new QIBusInputContextProxy(QLatin1String("org.freedesktop.IBus"), ic.value().path(), *connection); + + if (!context->isValid()) { + qWarning("QIBusPlatformInputContext: invalid input context."); + return; + } + + enum Capabilities { + IBUS_CAP_PREEDIT_TEXT = 1 << 0, + IBUS_CAP_AUXILIARY_TEXT = 1 << 1, + IBUS_CAP_LOOKUP_TABLE = 1 << 2, + IBUS_CAP_FOCUS = 1 << 3, + IBUS_CAP_PROPERTY = 1 << 4, + IBUS_CAP_SURROUNDING_TEXT = 1 << 5 + }; + context->SetCapabilities(IBUS_CAP_PREEDIT_TEXT|IBUS_CAP_FOCUS); + + if (debug) + qDebug(">>>> valid!"); + valid = true; +} + +QDBusConnection *QIBusPlatformInputContextPrivate::createConnection() +{ + QByteArray display(getenv("DISPLAY")); + QByteArray host = "unix"; + QByteArray displayNumber = "0"; + + int pos = display.indexOf(':'); + if (pos > 0) + host = display.left(pos); + ++pos; + int pos2 = display.indexOf('.', pos); + if (pos2 > 0) + displayNumber = display.mid(pos, pos2 - pos); + if (debug) + qDebug() << "host=" << host << "displayNumber" << displayNumber; + + QFile file(QDir::homePath() + QLatin1String("/.config/ibus/bus/") + + QLatin1String(QDBusConnection::localMachineId()) + + QLatin1Char('-') + QString::fromLocal8Bit(host) + QLatin1Char('-') + QString::fromLocal8Bit(displayNumber)); + + if (!file.exists()) { + qWarning("QIBusPlatformInputContext: ibus config file '%s' does not exist.", qPrintable(file.fileName())); + return 0; + } + + file.open(QFile::ReadOnly); + + QByteArray address; + int pid = -1; + + while (!file.atEnd()) { + QByteArray line = file.readLine().trimmed(); + if (line.startsWith('#')) + continue; + + if (line.startsWith("IBUS_ADDRESS=")) + address = line.mid(sizeof("IBUS_ADDRESS=") - 1); + if (line.startsWith("IBUS_DAEMON_PID=")) + pid = line.mid(sizeof("IBUS_DAEMON_PID=") - 1).toInt(); + } + + if (debug) + qDebug() << "IBUS_ADDRESS=" << address << "PID=" << pid; + if (address.isEmpty() || pid < 0 || kill(pid, 0) != 0) + return 0; + + return new QDBusConnection(QDBusConnection::connectToBus(QString::fromLatin1(address), QLatin1String("QIBusProxy"))); +} diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h new file mode 100644 index 0000000000..84b578db16 --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QIBUSPLATFORMINPUTCONTEXT_H +#define QIBUSPLATFORMINPUTCONTEXT_H + +#include <QPlatformInputContext> + +class QIBusPlatformInputContextPrivate; +class QDBusVariant; + +class QIBusPlatformInputContext : public QPlatformInputContext +{ + Q_OBJECT +public: + QIBusPlatformInputContext(); + ~QIBusPlatformInputContext(); + + bool isValid() const; + + void invokeAction(QInputPanel::Action a, int x); + void reset(void); + void update(Qt::InputMethodQueries); + + Q_INVOKABLE bool x11FilterEvent(uint keyval, uint keycode, uint state, bool press); + +public Q_SLOTS: + void commitText(const QDBusVariant &text); + void updatePreeditText(const QDBusVariant &text, uint cursor_pos, bool visible); + void inputItemChanged(); + void cursorRectChanged(); + +private: + QIBusPlatformInputContextPrivate *d; +}; + +#endif diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp b/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp new file mode 100644 index 0000000000..9d64b603f3 --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp @@ -0,0 +1,26 @@ +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -N -p qibusproxy -c QIBusProxy interfaces/org.freedesktop.IBus.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "qibusproxy.h" + +/* + * Implementation of interface class QIBusProxy + */ + +QIBusProxy::QIBusProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +QIBusProxy::~QIBusProxy() +{ +} + diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxy.h b/src/plugins/platforminputcontexts/ibus/qibusproxy.h new file mode 100644 index 0000000000..389eec3175 --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/qibusproxy.h @@ -0,0 +1,88 @@ +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -N -p qibusproxy -c QIBusProxy interfaces/org.freedesktop.IBus.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef QIBUSPROXY_H_1308831142 +#define QIBUSPROXY_H_1308831142 + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface org.freedesktop.IBus + */ +class QIBusProxy: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.freedesktop.IBus"; } + +public: + QIBusProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~QIBusProxy(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<QDBusObjectPath> CreateInputContext(const QString &name) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(name); + return asyncCallWithArgumentList(QLatin1String("CreateInputContext"), argumentList); + } + + inline QDBusPendingReply<> Exit(bool restart) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(restart); + return asyncCallWithArgumentList(QLatin1String("Exit"), argumentList); + } + + inline QDBusPendingReply<QString> GetAddress() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("GetAddress"), argumentList); + } + + inline QDBusPendingReply<QVariantList> ListActiveEngines() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("ListActiveEngines"), argumentList); + } + + inline QDBusPendingReply<QVariantList> ListEngines() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("ListEngines"), argumentList); + } + + inline QDBusPendingReply<QDBusVariant> Ping(const QDBusVariant &data) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(data); + return asyncCallWithArgumentList(QLatin1String("Ping"), argumentList); + } + + inline QDBusPendingReply<> RegisterComponent(const QDBusVariant &components) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(components); + return asyncCallWithArgumentList(QLatin1String("RegisterComponent"), argumentList); + } + +Q_SIGNALS: // SIGNALS +}; + +#endif diff --git a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp new file mode 100644 index 0000000000..8d8c61afb7 --- /dev/null +++ b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qibustypes.h" +#include <qtextformat.h> +#include <QtDBus> + +QIBusSerializable::QIBusSerializable() +{ +} + +QIBusSerializable::~QIBusSerializable() +{ +} + +void QIBusSerializable::fromDBusArgument(const QDBusArgument &arg) +{ + arg >> name; + arg.beginMap(); + while (!arg.atEnd()) { + arg.beginMapEntry(); + QString key; + QDBusVariant value; + arg >> key; + arg >> value; + arg.endMapEntry(); + attachments[key] = value.variant().value<QDBusArgument>(); + } + arg.endMap(); +} + + + +QIBusAttribute::QIBusAttribute() + : type(Invalid), + value(0), + start(0), + end(0) +{ +} + +QIBusAttribute::~QIBusAttribute() +{ + +} + +void QIBusAttribute::fromDBusArgument(const QDBusArgument &arg) +{ +// qDebug() << "QIBusAttribute::fromDBusArgument()" << arg.currentSignature(); + arg.beginStructure(); + + QIBusSerializable::fromDBusArgument(arg); + + quint32 t; + arg >> t; + type = (Type)t; + arg >> value; + arg >> start; + arg >> end; + + arg.endStructure(); +} + +QTextFormat QIBusAttribute::format() const +{ + QTextCharFormat fmt; + switch (type) { + case Invalid: + break; + case Underline: { + QTextCharFormat::UnderlineStyle style = QTextCharFormat::NoUnderline; + + switch (value) { + case UnderlineNone: + break; + case UnderlineSingle: + style = QTextCharFormat::SingleUnderline; + break; + case UnderlineDouble: + style = QTextCharFormat::DashUnderline; + break; + case UnderlineLow: + style = QTextCharFormat::DashDotLine; + break; + case UnderlineError: + style = QTextCharFormat::WaveUnderline; + fmt.setUnderlineColor(Qt::red); + break; + } + + fmt.setUnderlineStyle(style); + break; + } + case Foreground: + fmt.setForeground(QColor(value)); + break; + case Background: + fmt.setBackground(QColor(value)); + break; + } + return fmt; +} + + +QIBusAttributeList::QIBusAttributeList() +{ + +} + +QIBusAttributeList::~QIBusAttributeList() +{ + +} + +void QIBusAttributeList::fromDBusArgument(const QDBusArgument &arg) +{ +// qDebug() << "QIBusAttributeList::fromDBusArgument()" << arg.currentSignature(); + arg.beginStructure(); + + QIBusSerializable::fromDBusArgument(arg); + + arg.beginArray(); + while(!arg.atEnd()) { + QDBusVariant var; + arg >> var; + + QIBusAttribute attr; + attr.fromDBusArgument(var.variant().value<QDBusArgument>()); + attributes.append(attr); + } + arg.endArray(); + + arg.endStructure(); +} + +QList<QInputMethodEvent::Attribute> QIBusAttributeList::imAttributes() const +{ + QList<QInputMethodEvent::Attribute> imAttrs; + for (int i = 0; i < attributes.size(); ++i) { + const QIBusAttribute &attr = attributes.at(i); + imAttrs += QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, attr.start, attr.end - attr.start, attr.format()); + } + return imAttrs; +} + + +QIBusText::QIBusText() +{ + +} + +QIBusText::~QIBusText() +{ + +} + +void QIBusText::fromDBusArgument(const QDBusArgument &arg) +{ +// qDebug() << "QIBusText::fromDBusArgument()" << arg.currentSignature(); + arg.beginStructure(); + + QIBusSerializable::fromDBusArgument(arg); + + arg >> text; + QDBusVariant variant; + arg >> variant; + attributes.fromDBusArgument(variant.variant().value<QDBusArgument>()); + + arg.endStructure(); +} + diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h b/src/plugins/platforminputcontexts/ibus/qibustypes.h index f1893e3e96..c426ff7eda 100644 --- a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h +++ b/src/plugins/platforminputcontexts/ibus/qibustypes.h @@ -38,62 +38,79 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#ifndef QIBUSTYPES_H +#define QIBUSTYPES_H -#ifndef PVREGLSCREEN_H -#define PVREGLSCREEN_H +#include <qvector.h> +#include <qevent.h> -#include <QScreen> -#include <QGLScreen> -#include "pvrqwsdrawable.h" +class QDBusArgument; -class PvrEglScreen; - -class PvrEglScreenSurfaceFunctions : public QGLScreenSurfaceFunctions +class QIBusSerializable { public: - PvrEglScreenSurfaceFunctions(PvrEglScreen *s, int screenNum) - : screen(s), displayId(screenNum) {} + QIBusSerializable(); + virtual ~QIBusSerializable(); - bool createNativeWindow(QWidget *widget, EGLNativeWindowType *native); + virtual void fromDBusArgument(const QDBusArgument &arg); -private: - PvrEglScreen *screen; - int displayId; + QString name; + QHash<QString, QDBusArgument> attachments; }; -class PvrEglScreen : public QGLScreen +class QIBusAttribute : public QIBusSerializable { public: - PvrEglScreen(int displayId); - ~PvrEglScreen(); + enum Type { + Invalid = 0, + Underline = 1, + Foreground = 2, + Background = 3, + }; + + enum Underline { + UnderlineNone = 0, + UnderlineSingle = 1, + UnderlineDouble = 2, + UnderlineLow = 3, + UnderlineError = 4, + }; + + QIBusAttribute(); + ~QIBusAttribute(); - bool initDevice(); - bool connect(const QString &displaySpec); - void disconnect(); - void shutdownDevice(); - void setMode(int, int, int) {} + void fromDBusArgument(const QDBusArgument &arg); + QTextFormat format() const; - void blit(const QImage &img, const QPoint &topLeft, const QRegion ®ion); - void solidFill(const QColor &color, const QRegion ®ion); + Type type; + quint32 value; + quint32 start; + quint32 end; +}; - bool chooseContext(QGLContext *context, const QGLContext *shareContext); - bool hasOpenGL(); +class QIBusAttributeList : public QIBusSerializable +{ +public: + QIBusAttributeList(); + ~QIBusAttributeList(); - QWSWindowSurface* createSurface(QWidget *widget) const; - QWSWindowSurface* createSurface(const QString &key) const; + void fromDBusArgument(const QDBusArgument &arg); - int transformation() const; + QList<QInputMethodEvent::Attribute> imAttributes() const; + + QVector<QIBusAttribute> attributes; +}; + +class QIBusText : public QIBusSerializable +{ +public: + QIBusText(); + ~QIBusText(); -private: - void sync(); - void openTty(); - void closeTty(); + void fromDBusArgument(const QDBusArgument &arg); - int fd; - int ttyfd, oldKdMode; - QString ttyDevice; - bool doGraphicsMode; - mutable const QScreen *parent; + QString text; + QIBusAttributeList attributes; }; #endif diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro new file mode 100644 index 0000000000..b6e2b6e775 --- /dev/null +++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs + +!macx:!win:SUBDIRS += ibus + diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index bfa147f948..d6801e0bed 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -2,28 +2,46 @@ TARGET = qcocoa load(qt_plugin) DESTDIR = $$QT.gui.plugins/platforms -OBJECTIVE_SOURCES = main.mm \ +OBJECTIVE_SOURCES += main.mm \ qcocoaintegration.mm \ - qcocoawindowsurface.mm \ + qcocoabackingstore.mm \ qcocoawindow.mm \ qnsview.mm \ - qcocoaeventloopintegration.mm \ qcocoaautoreleasepool.mm \ - qnswindowdelegate.mm + qnswindowdelegate.mm \ + qcocoaglcontext.mm \ + qcocoanativeinterface.mm \ + qcocoaeventdispatcher.mm \ + qcocoamenuloader.mm \ + qcocoaapplicationdelegate.mm \ + qcocoaapplication.mm \ + qcocoamenu.mm \ + qmenu_mac.mm \ + qcocoahelpers.mm \ -OBJECTIVE_HEADERS = qcocoaintegration.h \ - qcocoawindowsurface.h \ +HEADERS += qcocoaintegration.h \ + qcocoabackingstore.h \ qcocoawindow.h \ qnsview.h \ - qcocoaeventloopintegration.h \ qcocoaautoreleasepool.h \ - qnswindowdelegate.h + qnswindowdelegate.h \ + qcocoaglcontext.h \ + qcocoanativeinterface.h \ + qcocoaeventdispatcher.h \ + qcocoamenuloader.h \ + qcocoaapplicationdelegate.h \ + qcocoaapplication.h \ + qcocoamenu.h \ + qmenu_mac.h \ + qcocoahelpers.h \ + +RESOURCES += qcocoaresources.qrc #add libz for freetype. -LIBS += -lz -LIBS += -framework cocoa +LIBS += -lz -framework Cocoa + +QT += core-private gui-private widgets-private platformsupport-private -include(../fontdatabases/coretext/coretext.pri) +CONFIG += qpa/basicunixfontdatabase target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target - diff --git a/src/plugins/platforms/cocoa/images/copyarrowcursor.png b/src/plugins/platforms/cocoa/images/copyarrowcursor.png Binary files differnew file mode 100644 index 0000000000..13dfca95bc --- /dev/null +++ b/src/plugins/platforms/cocoa/images/copyarrowcursor.png diff --git a/src/plugins/platforms/cocoa/images/forbiddencursor.png b/src/plugins/platforms/cocoa/images/forbiddencursor.png Binary files differnew file mode 100644 index 0000000000..a9f21b4a5e --- /dev/null +++ b/src/plugins/platforms/cocoa/images/forbiddencursor.png diff --git a/src/plugins/platforms/cocoa/images/leopard-unified-toolbar-on.png b/src/plugins/platforms/cocoa/images/leopard-unified-toolbar-on.png Binary files differnew file mode 100644 index 0000000000..6716597046 --- /dev/null +++ b/src/plugins/platforms/cocoa/images/leopard-unified-toolbar-on.png diff --git a/src/plugins/platforms/cocoa/images/pluscursor.png b/src/plugins/platforms/cocoa/images/pluscursor.png Binary files differnew file mode 100644 index 0000000000..c583c088c9 --- /dev/null +++ b/src/plugins/platforms/cocoa/images/pluscursor.png diff --git a/src/plugins/platforms/cocoa/images/spincursor.png b/src/plugins/platforms/cocoa/images/spincursor.png Binary files differnew file mode 100644 index 0000000000..ca44ab50fd --- /dev/null +++ b/src/plugins/platforms/cocoa/images/spincursor.png diff --git a/src/plugins/platforms/cocoa/images/waitcursor.png b/src/plugins/platforms/cocoa/images/waitcursor.png Binary files differnew file mode 100644 index 0000000000..a9abe61320 --- /dev/null +++ b/src/plugins/platforms/cocoa/images/waitcursor.png diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.h b/src/plugins/platforms/cocoa/qcocoaapplication.h new file mode 100644 index 0000000000..5b6b2f48f2 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaapplication.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** Copyright (c) 2007-2008, Apple, Inc. +** +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * Neither the name of Apple, Inc. nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp, qcolor_x11.cpp, qfiledialog.cpp +// and many other. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +/* + Cocoa Application Categories +*/ +#include "qglobal.h" + +#import <AppKit/AppKit.h> +QT_FORWARD_DECLARE_CLASS(QApplicationPrivate) +@class QT_MANGLE_NAMESPACE(QCocoaMenuLoader); + +@interface NSApplication (QT_MANGLE_NAMESPACE(QApplicationIntegration)) +- (void)QT_MANGLE_NAMESPACE(qt_setDockMenu):(NSMenu *)newMenu; +- (QApplicationPrivate *)QT_MANGLE_NAMESPACE(qt_qappPrivate); +- (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader); +- (int)QT_MANGLE_NAMESPACE(qt_validModesForFontPanel):(NSFontPanel *)fontPanel; + +- (void)qt_sendPostedMessage:(NSEvent *)event; +- (BOOL)qt_filterEvent:(NSEvent *)event; +@end + +@interface QNSApplication : NSApplication { +} +@end + +QT_BEGIN_NAMESPACE + +void qt_redirectNSApplicationSendEvent(); + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm new file mode 100644 index 0000000000..2adf6a57f0 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** Copyright (c) 2007-2008, Apple, Inc. +** +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * Neither the name of Apple, Inc. nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +****************************************************************************/ + +#include <qcocoaapplication.h> + +#include <qcocoaapplicationdelegate.h> +#include <qcocoahelpers.h> +#include <qguiapplication.h> +#include <qdebug.h> + +QT_USE_NAMESPACE + +@implementation NSApplication (QT_MANGLE_NAMESPACE(QApplicationIntegration)) + +- (void)QT_MANGLE_NAMESPACE(qt_setDockMenu):(NSMenu *)newMenu +{ + [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] setDockMenu:newMenu]; +} + +- (QApplicationPrivate *)QT_MANGLE_NAMESPACE(qt_qappPrivate) +{ + return [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] qAppPrivate]; +} + +- (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader) +{ + return [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] menuLoader]; +} + +- (int)QT_MANGLE_NAMESPACE(qt_validModesForFontPanel):(NSFontPanel *)fontPanel +{ + Q_UNUSED(fontPanel); + // only display those things that QFont can handle + return NSFontPanelFaceModeMask + | NSFontPanelSizeModeMask + | NSFontPanelCollectionModeMask + | NSFontPanelUnderlineEffectModeMask + | NSFontPanelStrikethroughEffectModeMask; +} + +- (void)qt_sendPostedMessage:(NSEvent *)event +{ +/* + // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5! + // That is why we need to split the address in two parts: + quint64 lower = [event data1]; + quint64 upper = [event data2]; + QCocoaPostMessageArgs *args = reinterpret_cast<QCocoaPostMessageArgs *>(lower | (upper << 32)); + // Special case for convenience: if the argument is an NSNumber, we unbox it directly. + // Use NSValue instead if this behaviour is unwanted. + id a1 = ([args->arg1 isKindOfClass:[NSNumber class]]) ? (id)[args->arg1 intValue] : args->arg1; + id a2 = ([args->arg2 isKindOfClass:[NSNumber class]]) ? (id)[args->arg2 intValue] : args->arg2; + switch (args->argCount) { + case 0: + [args->target performSelector:args->selector]; + break; + case 1: + [args->target performSelector:args->selector withObject:a1]; + break; + case 3: + [args->target performSelector:args->selector withObject:a1 withObject:a2]; + break; + } + + delete args; +*/ +} + +- (BOOL)qt_filterEvent:(NSEvent *)event +{ +/* + if (qApp->macEventFilter(0, reinterpret_cast<EventRef>(event))) + return true; + + if ([event type] == NSApplicationDefined) { + switch ([event subtype]) { + case QtCocoaEventSubTypePostMessage: + [NSApp qt_sendPostedMessage:event]; + return true; + default: + break; + } + } +*/ + return false; +} + +@end + +@implementation QNSApplication + +- (void)qt_sendEvent_original:(NSEvent *)event +{ + Q_UNUSED(event); + // This method will only be used as a signature + // template for the method we add into NSApplication + // containing the original [NSApplication sendEvent:] implementation +} + +- (void)qt_sendEvent_replacement:(NSEvent *)event +{ + // This method (or its implementation to be precise) will + // be called instead of sendEvent if redirection occurs. + // 'self' will then be an instance of NSApplication + // (and not QNSApplication) + if (![NSApp qt_filterEvent:event]) + [self qt_sendEvent_original:event]; +} + +- (void)sendEvent:(NSEvent *)event +{ + // This method will be called if + // no redirection occurs + if (![NSApp qt_filterEvent:event]) + [super sendEvent:event]; +} + +- (void)qtDispatcherToQAction:(id)sender +{ + // Forward actions sendt from the menu bar (e.g. quit) to the menu loader. + // Having this method here means that we are the last stop in the responder + // chain, and that we are able to handle menu actions even when no window is + // visible on screen. Note: If Qt is used as a plugin, Qt will not use a + // native menu bar. Hence, we will also not need to do any redirection etc. as + // we do with sendEvent. + [[NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)] qtDispatcherToQAction:sender]; +} + +@end + +QT_BEGIN_NAMESPACE + +void qt_redirectNSApplicationSendEvent() +{ +/* + if ([NSApp isMemberOfClass:[QNSApplication class]]) { + // No need to change implementation since Qt + // already controls a subclass of NSApplication + return; + } + + // Change the implementation of [NSApplication sendEvent] to the + // implementation of qt_sendEvent_replacement found in QNSApplication. + // And keep the old implementation that gets overwritten inside a new + // method 'qt_sendEvent_original' that we add to NSApplication + qt_cocoa_change_implementation( + [NSApplication class], + @selector(sendEvent:), + [QNSApplication class], + @selector(qt_sendEvent_replacement:), + @selector(qt_sendEvent_original:)); + */ + } + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h new file mode 100644 index 0000000000..7f8d1dfacd --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +/**************************************************************************** + ** + ** Copyright (c) 2007-2008, Apple, Inc. + ** + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions are met: + ** + ** * Redistributions of source code must retain the above copyright notice, + ** this list of conditions and the following disclaimer. + ** + ** * Redistributions in binary form must reproduce the above copyright notice, + ** this list of conditions and the following disclaimer in the documentation + ** and/or other materials provided with the distribution. + ** + ** * Neither the name of Apple, Inc. nor the names of its contributors + ** may be used to endorse or promote products derived from this software + ** without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ** + ****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp, qcolor_x11.cpp, qfiledialog.cpp +// and many other. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + + +#import <Cocoa/Cocoa.h> + +#include <qglobal.h> + +QT_FORWARD_DECLARE_CLASS(QApplicationPrivate); + +@class QT_MANGLE_NAMESPACE(QCocoaMenuLoader); + +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 + +@protocol NSApplicationDelegate <NSObject> +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification; +- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames; +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender; +- (void)applicationDidBecomeActive:(NSNotification *)notification; +- (void)applicationDidResignActive:(NSNotification *)notification; +@end + +#endif + +@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) : NSObject <NSApplicationDelegate> { + bool startedQuit; + QApplicationPrivate *qtPrivate; + NSMenu *dockMenu; + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader; + NSObject <NSApplicationDelegate> *reflectionDelegate; + bool inLaunch; +} ++ (QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)*)sharedDelegate; +- (void)setDockMenu:(NSMenu *)newMenu; +- (void)setQtPrivate:(QApplicationPrivate *)value; +- (QApplicationPrivate *)qAppPrivate; +- (void)setMenuLoader:(QT_MANGLE_NAMESPACE(QCocoaMenuLoader)*)menuLoader; +- (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader; +- (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate; +- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; +@end diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm new file mode 100644 index 0000000000..6a2508359b --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -0,0 +1,354 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** + ** + ** Copyright (c) 2007-2008, Apple, Inc. + ** + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions are met: + ** + ** * Redistributions of source code must retain the above copyright notice, + ** this list of conditions and the following disclaimer. + ** + ** * Redistributions in binary form must reproduce the above copyright notice, + ** this list of conditions and the following disclaimer in the documentation + ** and/or other materials provided with the distribution. + ** + ** * Neither the name of Apple, Inc. nor the names of its contributors + ** may be used to endorse or promote products derived from this software + ** without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ** + ****************************************************************************/ + + +#import "qcocoaapplicationdelegate.h" +#import "qnswindowdelegate.h" +#include <qevent.h> +#include <qurl.h> +#include <qdebug.h> +#include <qguiapplication.h> + +QT_USE_NAMESPACE + +static QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *sharedCocoaApplicationDelegate = nil; + +static void cleanupCocoaApplicationDelegate() +{ + [sharedCocoaApplicationDelegate release]; +} + +@implementation QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) + +- (id)init +{ + self = [super init]; + if (self) + inLaunch = true; + return self; +} + +- (void)dealloc +{ + sharedCocoaApplicationDelegate = nil; + [dockMenu release]; + [qtMenuLoader release]; + if (reflectionDelegate) { + [NSApp setDelegate:reflectionDelegate]; + [reflectionDelegate release]; + } + [super dealloc]; +} + ++ (id)allocWithZone:(NSZone *)zone +{ + @synchronized(self) { + if (sharedCocoaApplicationDelegate == nil) { + sharedCocoaApplicationDelegate = [super allocWithZone:zone]; + return sharedCocoaApplicationDelegate; + qAddPostRoutine(cleanupCocoaApplicationDelegate); + } + } + return nil; +} + ++ (QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)*)sharedDelegate +{ + @synchronized(self) { + if (sharedCocoaApplicationDelegate == nil) + [[self alloc] init]; + } + return [[sharedCocoaApplicationDelegate retain] autorelease]; +} + +- (void)setDockMenu:(NSMenu*)newMenu +{ + [newMenu retain]; + [dockMenu release]; + dockMenu = newMenu; +} + +- (NSMenu *)applicationDockMenu +{ + return [[dockMenu retain] autorelease]; +} + +- (QApplicationPrivate *)qAppPrivate +{ + return qtPrivate; +} + +- (void)setQtPrivate:(QApplicationPrivate *)value +{ + qtPrivate = value; +} + +- (void)setMenuLoader:(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader +{ + [menuLoader retain]; + [qtMenuLoader release]; + qtMenuLoader = menuLoader; +} + +- (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader +{ + return [[qtMenuLoader retain] autorelease]; +} + +// This function will only be called when NSApp is actually running. Before +// that, the kAEQuitApplication Apple event will be sent to +// QApplicationPrivate::globalAppleEventProcessor in qapplication_mac.mm +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ +/* + Q_UNUSED(sender); + // The reflection delegate gets precedence + if (reflectionDelegate + && [reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)]) { + return [reflectionDelegate applicationShouldTerminate:sender]; + } + + if (qtPrivate->canQuit()) { + if (!startedQuit) { + startedQuit = true; + qAppInstance()->quit(); + startedQuit = false; + } + } + + if (qtPrivate->threadData->eventLoops.size() == 0) { + // INVARIANT: No event loop is executing. This probably + // means that Qt is used as a plugin, or as a part of a native + // Cocoa application. In any case it should be fine to + // terminate now: + return NSTerminateNow; + } + + return NSTerminateCancel; +*/ + return NSTerminateNow; +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + Q_UNUSED(aNotification); + inLaunch = false; + // qt_release_apple_event_handler(); + + + // Insert code here to initialize your application +} + + + +- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames +{ +/* + for (NSString *fileName in filenames) { + QString qtFileName = qt_mac_NSStringToQString(fileName); + if (inLaunch) { + // We need to be careful because Cocoa will be nice enough to take + // command line arguments and send them to us as events. Given the history + // of Qt Applications, this will result in behavior people don't want, as + // they might be doing the opening themselves with the command line parsing. + if (qApp->arguments().contains(qtFileName)) + continue; + } + QFileOpenEvent foe(qtFileName); + qt_sendSpontaneousEvent(qAppInstance(), &foe); + } + + if (reflectionDelegate && + [reflectionDelegate respondsToSelector:@selector(application:openFiles:)]) + [reflectionDelegate application:sender openFiles:filenames]; +*/ +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender +{ + // If we have a reflection delegate, that will get to call the shots. + if (reflectionDelegate + && [reflectionDelegate respondsToSelector: + @selector(applicationShouldTerminateAfterLastWindowClosed:)]) + return [reflectionDelegate applicationShouldTerminateAfterLastWindowClosed:sender]; + return NO; // Someday qApp->quitOnLastWindowClosed(); when QApp and NSApp work closer together. +} + + +- (void)applicationDidBecomeActive:(NSNotification *)notification +{ +/* + if (reflectionDelegate + && [reflectionDelegate respondsToSelector:@selector(applicationDidBecomeActive:)]) + [reflectionDelegate applicationDidBecomeActive:notification]; + + onApplicationChangedActivation(true); + + if (!QWidget::mouseGrabber()){ + // Update enter/leave immidiatly, don't wait for a move event. But only + // if no grab exists (even if the grab points to this widget, it seems, ref X11) + QPoint qlocal, qglobal; + QWidget *widgetUnderMouse = 0; + qt_mac_getTargetForMouseEvent(0, QEvent::Enter, qlocal, qglobal, 0, &widgetUnderMouse); + QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, 0); + qt_last_mouse_receiver = widgetUnderMouse; + qt_last_native_mouse_receiver = widgetUnderMouse ? + (widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget()) : 0; + } +*/ +} + +- (void)applicationDidResignActive:(NSNotification *)notification +{ +/* + if (reflectionDelegate + && [reflectionDelegate respondsToSelector:@selector(applicationDidResignActive:)]) + [reflectionDelegate applicationDidResignActive:notification]; + + onApplicationChangedActivation(false); + + if (!QWidget::mouseGrabber()) + QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver); + qt_last_mouse_receiver = 0; + qt_last_native_mouse_receiver = 0; + qt_button_down = 0; +*/ +} + +- (void)applicationDidChangeScreenParameters:(NSNotification *)notification +{ + Q_UNUSED(notification); + //QDesktopWidgetImplementation::instance()->onResize(); +} + +- (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate +{ + [oldDelegate retain]; + [reflectionDelegate release]; + reflectionDelegate = oldDelegate; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector +{ + NSMethodSignature *result = [super methodSignatureForSelector:aSelector]; + if (!result && reflectionDelegate) { + result = [reflectionDelegate methodSignatureForSelector:aSelector]; + } + return result; +} + +- (BOOL)respondsToSelector:(SEL)aSelector +{ + BOOL result = [super respondsToSelector:aSelector]; + if (!result && reflectionDelegate) + result = [reflectionDelegate respondsToSelector:aSelector]; + return result; +} + +- (void)forwardInvocation:(NSInvocation *)invocation +{ + SEL invocationSelector = [invocation selector]; + if (reflectionDelegate && [reflectionDelegate respondsToSelector:invocationSelector]) + [invocation invokeWithTarget:reflectionDelegate]; + else + [self doesNotRecognizeSelector:invocationSelector]; +} + +- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent +{ + Q_UNUSED(replyEvent); +/* + NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + QUrl url(qt_mac_NSStringToQString(urlString)); + QFileOpenEvent qtEvent(url); + qt_sendSpontaneousEvent(qAppInstance(), &qtEvent); +*/ +} + +- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent +{ + Q_UNUSED(event); + Q_UNUSED(replyEvent); + qDebug() << "appleEventQuit"; + + [NSApp terminate:self]; +} + +- (void)qtDispatcherToQAction:(id)sender +{ + //[[NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)] qtDispatcherToQAction:sender]; +} + +@end diff --git a/src/plugins/platforms/cocoa/qcocoaautoreleasepool.h b/src/plugins/platforms/cocoa/qcocoaautoreleasepool.h index 862bc27f9d..359b5d34d0 100644 --- a/src/plugins/platforms/cocoa/qcocoaautoreleasepool.h +++ b/src/plugins/platforms/cocoa/qcocoaautoreleasepool.h @@ -42,6 +42,8 @@ #ifndef QCOCOAAUTORELEASEPOOL_H #define QCOCOAAUTORELEASEPOOL_H +#undef slots + #include <Cocoa/Cocoa.h> class QCocoaAutoReleasePool diff --git a/src/plugins/platforms/cocoa/qcocoawindowsurface.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 95eea2b7ea..938e27347c 100644 --- a/src/plugins/platforms/cocoa/qcocoawindowsurface.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -39,33 +39,31 @@ ** ****************************************************************************/ -#ifndef QWINDOWSURFACE_COCOA_H -#define QWINDOWSURFACE_COCOA_H +#ifndef QBACKINGSTORE_COCOA_H +#define QBACKINGSTORE_COCOA_H #include <Cocoa/Cocoa.h> #include "qcocoawindow.h" #include "qnsview.h" -#include <QtGui/private/qwindowsurface_p.h> +#include <QPlatformBackingStore> QT_BEGIN_NAMESPACE -class QCocoaWindowSurface : public QWindowSurface +class QCocoaBackingStore : public QPlatformBackingStore { public: - QCocoaWindowSurface(QWidget *window, WId wid); - ~QCocoaWindowSurface(); + QCocoaBackingStore(QWindow *window); + ~QCocoaBackingStore(); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - void resize (const QSize &size); + void flush(QWindow *widget, const QRegion ®ion, const QPoint &offset); + void resize (const QSize &size, const QRegion &); private: - QCocoaWindow *m_cocoaWindow; QImage *m_image; - QNSView *m_contentView; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindowsurface.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 16bb327196..5a59fb5c49 100644 --- a/src/plugins/platforms/cocoa/qcocoawindowsurface.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -39,10 +39,9 @@ ** ****************************************************************************/ -#include "qcocoawindowsurface.h" +#include "qcocoabackingstore.h" #include <QtCore/qdebug.h> - #include <QtGui/QPainter> QT_BEGIN_NAMESPACE @@ -56,30 +55,28 @@ QRect flipedRect(const QRect &sourceRect,int height) return flippedRect; } -QCocoaWindowSurface::QCocoaWindowSurface(QWidget *window, WId wId) - : QWindowSurface(window) +QCocoaBackingStore::QCocoaBackingStore(QWindow *window) + : QPlatformBackingStore(window) { - m_cocoaWindow = static_cast<QCocoaWindow *>(window->platformWindow()); + m_cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); const QRect geo = window->geometry(); NSRect rect = NSMakeRect(geo.x(),geo.y(),geo.width(),geo.height()); - m_contentView = [[QNSView alloc] initWithWidget:window]; - m_cocoaWindow->setContentView(m_contentView); - m_image = new QImage(window->size(),QImage::Format_ARGB32); + m_image = new QImage(window->geometry().size(),QImage::Format_ARGB32); } -QCocoaWindowSurface::~QCocoaWindowSurface() +QCocoaBackingStore::~QCocoaBackingStore() { delete m_image; } -QPaintDevice *QCocoaWindowSurface::paintDevice() +QPaintDevice *QCocoaBackingStore::paintDevice() { return m_image; } -void QCocoaWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QCocoaBackingStore::flush(QWindow *widget, const QRegion ®ion, const QPoint &offset) { Q_UNUSED(widget); Q_UNUSED(offset); @@ -87,17 +84,15 @@ void QCocoaWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QP QRect geo = region.boundingRect(); NSRect rect = NSMakeRect(geo.x(), geo.y(), geo.width(), geo.height()); - [m_contentView displayRect:rect]; + [m_cocoaWindow->m_contentView displayRect:rect]; } -void QCocoaWindowSurface::resize(const QSize &size) +void QCocoaBackingStore::resize(const QSize &size, const QRegion &) { - QWindowSurface::resize(size); delete m_image; m_image = new QImage(size,QImage::Format_ARGB32_Premultiplied); NSSize newSize = NSMakeSize(size.width(),size.height()); - [m_contentView setImage:m_image]; - + [static_cast<QNSView *>(m_cocoaWindow->m_contentView) setImage:m_image]; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h new file mode 100644 index 0000000000..7184db84fa --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** Copyright (c) 2007-2008, Apple, Inc. +** +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * Neither the name of Apple, Inc. nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +****************************************************************************/ + +#ifndef QEVENTDISPATCHER_MAC_P_H +#define QEVENTDISPATCHER_MAC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qhash.h> +#include <QtCore/qstack.h> +#include <QtGui/qwindowdefs.h> +#include <QtCore/private/qeventdispatcher_unix_p.h> + +#include <CoreFoundation/CoreFoundation.h> + +QT_BEGIN_NAMESPACE + +typedef struct _NSModalSession *NSModalSession; +typedef struct _QCocoaModalSessionInfo { + QPointer<QWindow> window; + NSModalSession session; + void *nswindow; +} QCocoaModalSessionInfo; + +class QCocoaEventDispatcherPrivate; +class QCocoaEventDispatcher : public QEventDispatcherUNIX +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QCocoaEventDispatcher) + +public: + QCocoaEventDispatcher(QAbstractEventDispatcherPrivate &priv, QObject *parent = 0); + explicit QCocoaEventDispatcher(QObject *parent = 0); + ~QCocoaEventDispatcher(); + + + bool processEvents(QEventLoop::ProcessEventsFlags flags); + bool hasPendingEvents(); + + void registerSocketNotifier(QSocketNotifier *notifier); + void unregisterSocketNotifier(QSocketNotifier *notifier); + + void registerTimer(int timerId, int interval, QObject *object); + bool unregisterTimer(int timerId); + bool unregisterTimers(QObject *object); + QList<TimerInfo> registeredTimers(QObject *object) const; + + void wakeUp(); + void interrupt(); + +private: + //friend void qt_mac_select_timer_callbk(__EventLoopTimer*, void*); + friend class QApplicationPrivate; +}; + +struct MacTimerInfo { + int id; + int interval; + QObject *obj; + bool pending; + CFRunLoopTimerRef runLoopTimer; + bool operator==(const MacTimerInfo &other) + { + return (id == other.id); + } +}; +typedef QHash<int, MacTimerInfo *> MacTimerHash; + +struct MacSocketInfo { + MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0) {} + CFSocketRef socket; + CFRunLoopSourceRef runloop; + QObject *readNotifier; + QObject *writeNotifier; +}; +typedef QHash<int, MacSocketInfo *> MacSocketHash; + +class QCocoaEventDispatcherPrivate : public QEventDispatcherUNIXPrivate +{ + Q_DECLARE_PUBLIC(QCocoaEventDispatcher) + +public: + QCocoaEventDispatcherPrivate(); + + static MacTimerHash macTimerHash; + // Set 'blockSendPostedEvents' to true if you _really_ need + // to make sure that qt events are not posted while calling + // low-level cocoa functions (like beginModalForWindow). And + // use a QBoolBlocker to be safe: + static bool blockSendPostedEvents; + // The following variables help organizing modal sessions: + static QStack<QCocoaModalSessionInfo> cocoaModalSessionStack; + static bool currentExecIsNSAppRun; + static bool nsAppRunCalledByQt; + static bool cleanupModalSessionsNeeded; + static NSModalSession currentModalSessionCached; + static NSModalSession currentModalSession(); + static void updateChildrenWorksWhenModal(); + static void temporarilyStopAllModalSessions(); + static void beginModalSession(QWindow *widget); + static void endModalSession(QWindow *widget); + static void cancelWaitForMoreEvents(); + static void cleanupModalSessions(); + static void ensureNSAppInitialized(); + + MacSocketHash macSockets; + QList<void *> queuedUserInputEvents; // NSEvent * + CFRunLoopSourceRef postedEventsSource; + CFRunLoopObserverRef waitingObserver; + CFRunLoopObserverRef firstTimeObserver; + QAtomicInt serialNumber; + int lastSerial; + static bool interrupt; +private: + static Boolean postedEventSourceEqualCallback(const void *info1, const void *info2); + static void postedEventsSourcePerformCallback(void *info); + static void activateTimer(CFRunLoopTimerRef, void *info); + static void waitingObserverCallback(CFRunLoopObserverRef observer, + CFRunLoopActivity activity, void *info); + static void firstLoopEntry(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info); + friend void processPostedEvents(QCocoaEventDispatcherPrivate *const d, const bool blockSendPostedEvents); +}; + +class QtCocoaInterruptDispatcher : public QObject +{ + static QtCocoaInterruptDispatcher *instance; + bool cancelled; + + QtCocoaInterruptDispatcher(); + ~QtCocoaInterruptDispatcher(); + + public: + static void interruptLater(); + static void cancelInterruptLater(); +}; + +QT_END_NAMESPACE + +#endif // QEVENTDISPATCHER_MAC_P_H diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm new file mode 100644 index 0000000000..9525b47c65 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -0,0 +1,1123 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** Copyright (c) 2007-2008, Apple, Inc. +** +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** +** * Neither the name of Apple, Inc. nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +****************************************************************************/ + +#include "qcocoaeventdispatcher.h" +#include "qcocoaautoreleasepool.h" + +#include "qguiapplication.h" +#include "qevent.h" +#include "qhash.h" +#include "qmutex.h" +#include "qsocketnotifier.h" +#include <qplatformwindow_qpa.h> +#include "private/qthread_p.h" +#include "private/qguiapplication_p.h" +#include <qdebug.h> + +#undef slots +#include <Cocoa/Cocoa.h> +#include <Carbon/Carbon.h> + +QT_BEGIN_NAMESPACE + +QT_USE_NAMESPACE + +enum { + QtCocoaEventSubTypeWakeup = SHRT_MAX, + QtCocoaEventSubTypePostMessage = SHRT_MAX-1 +}; + +static inline CFRunLoopRef mainRunLoop() +{ + return CFRunLoopGetMain(); +} + +/***************************************************************************** + Timers stuff + *****************************************************************************/ + +/* timer call back */ +void QCocoaEventDispatcherPrivate::activateTimer(CFRunLoopTimerRef, void *info) +{ + int timerID = +#ifdef Q_OS_MAC64 + qint64(info); +#else + int(info); +#endif + + MacTimerInfo *tmr; + tmr = macTimerHash.value(timerID); + if (tmr == 0 || tmr->pending == true) + return; // Can't send another timer event if it's pending. + + + if (blockSendPostedEvents) { + QCoreApplication::postEvent(tmr->obj, new QTimerEvent(tmr->id)); + } else { + tmr->pending = true; + QTimerEvent e(tmr->id); + + QCoreApplication::sendSpontaneousEvent(tmr->obj, &e); + // Get the value again in case the timer gets unregistered during the sendEvent. + tmr = macTimerHash.value(timerID); + if (tmr != 0) + tmr->pending = false; + } + +} + +void QCocoaEventDispatcher::registerTimer(int timerId, int interval, QObject *obj) +{ +#ifndef QT_NO_DEBUG + if (timerId < 1 || interval < 0 || !obj) { + qWarning("QEventDispatcherMac::registerTimer: invalid arguments"); + return; + } else if (obj->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QObject::startTimer: timers cannot be started from another thread"); + return; + } +#endif + + MacTimerInfo *t = new MacTimerInfo(); + t->id = timerId; + t->interval = interval; + t->obj = obj; + t->runLoopTimer = 0; + t->pending = false; + + CFAbsoluteTime fireDate = CFAbsoluteTimeGetCurrent(); + CFTimeInterval cfinterval = qMax(CFTimeInterval(interval) / 1000, 0.0000001); + fireDate += cfinterval; + QCocoaEventDispatcherPrivate::macTimerHash.insert(timerId, t); + CFRunLoopTimerContext info = { 0, (void *)timerId, 0, 0, 0 }; + t->runLoopTimer = CFRunLoopTimerCreate(0, fireDate, cfinterval, 0, 0, + QCocoaEventDispatcherPrivate::activateTimer, &info); + if (t->runLoopTimer == 0) { + qFatal("QEventDispatcherMac::registerTimer: Cannot create timer"); + } + CFRunLoopAddTimer(mainRunLoop(), t->runLoopTimer, kCFRunLoopCommonModes); +} + +bool QCocoaEventDispatcher::unregisterTimer(int identifier) +{ +#ifndef QT_NO_DEBUG + if (identifier < 1) { + qWarning("QEventDispatcherMac::unregisterTimer: invalid argument"); + return false; + } else if (thread() != QThread::currentThread()) { + qWarning("QObject::killTimer: timers cannot be stopped from another thread"); + return false; + } +#endif + if (identifier <= 0) + return false; // not init'd or invalid timer + + MacTimerInfo *timerInfo = QCocoaEventDispatcherPrivate::macTimerHash.take(identifier); + if (timerInfo == 0) + return false; + + if (!QObjectPrivate::get(timerInfo->obj)->inThreadChangeEvent) + QAbstractEventDispatcherPrivate::releaseTimerId(identifier); + CFRunLoopTimerInvalidate(timerInfo->runLoopTimer); + CFRelease(timerInfo->runLoopTimer); + delete timerInfo; + + return true; +} + +bool QCocoaEventDispatcher::unregisterTimers(QObject *obj) +{ +#ifndef QT_NO_DEBUG + if (!obj) { + qWarning("QEventDispatcherMac::unregisterTimers: invalid argument"); + return false; + } else if (obj->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QObject::killTimers: timers cannot be stopped from another thread"); + return false; + } +#endif + + MacTimerHash::iterator it = QCocoaEventDispatcherPrivate::macTimerHash.begin(); + while (it != QCocoaEventDispatcherPrivate::macTimerHash.end()) { + MacTimerInfo *timerInfo = it.value(); + if (timerInfo->obj != obj) { + ++it; + } else { + if (!QObjectPrivate::get(timerInfo->obj)->inThreadChangeEvent) + QAbstractEventDispatcherPrivate::releaseTimerId(timerInfo->id); + CFRunLoopTimerInvalidate(timerInfo->runLoopTimer); + CFRelease(timerInfo->runLoopTimer); + delete timerInfo; + it = QCocoaEventDispatcherPrivate::macTimerHash.erase(it); + } + } + return true; +} + +QList<QCocoaEventDispatcher::TimerInfo> +QCocoaEventDispatcher::registeredTimers(QObject *object) const +{ + if (!object) { + qWarning("QEventDispatcherMac:registeredTimers: invalid argument"); + return QList<TimerInfo>(); + } + + QList<TimerInfo> list; + + MacTimerHash::const_iterator it = QCocoaEventDispatcherPrivate::macTimerHash.constBegin(); + while (it != QCocoaEventDispatcherPrivate::macTimerHash.constEnd()) { + MacTimerInfo *t = it.value(); + if (t->obj == object) + list << TimerInfo(t->id, t->interval); + ++it; + } + return list; +} + +/************************************************************************** + Socket Notifiers + *************************************************************************/ +void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef, + const void *, void *info) { + QCocoaEventDispatcherPrivate *const eventDispatcher + = static_cast<QCocoaEventDispatcherPrivate *>(info); + int nativeSocket = CFSocketGetNative(s); + MacSocketInfo *socketInfo = eventDispatcher->macSockets.value(nativeSocket); + QEvent notifierEvent(QEvent::SockAct); + + // There is a race condition that happen where we disable the notifier and + // the kernel still has a notification to pass on. We then get this + // notification after we've successfully disabled the CFSocket, but our Qt + // notifier is now gone. The upshot is we have to check the notifier + // everytime. + if (callbackType == kCFSocketReadCallBack) { + if (socketInfo->readNotifier) + QGuiApplication::sendEvent(socketInfo->readNotifier, ¬ifierEvent); + } else if (callbackType == kCFSocketWriteCallBack) { + if (socketInfo->writeNotifier) + QGuiApplication::sendEvent(socketInfo->writeNotifier, ¬ifierEvent); + } +} + +/* + Adds a loop source for the given socket to the current run loop. +*/ +CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket) +{ + CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0); + if (!loopSource) + return 0; + + CFRunLoopAddSource(mainRunLoop(), loopSource, kCFRunLoopCommonModes); + return loopSource; +} + +/* + Removes the loop source for the given socket from the current run loop. +*/ +void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop) +{ + Q_ASSERT(runloop); + CFRunLoopRemoveSource(mainRunLoop(), runloop, kCFRunLoopCommonModes); + CFSocketDisableCallBacks(socket, kCFSocketReadCallBack); + CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack); + CFRunLoopSourceInvalidate(runloop); +} + +/* + Register a QSocketNotifier with the mac event system by creating a CFSocket with + with a read/write callback. + + Qt has separate socket notifiers for reading and writing, but on the mac there is + a limitation of one CFSocket object for each native socket. +*/ +void QCocoaEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int nativeSocket = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != thread() + || thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); + return; + } +#endif + + Q_D(QCocoaEventDispatcher); + + if (type == QSocketNotifier::Exception) { + qWarning("QSocketNotifier::Exception is not supported on Mac OS X"); + return; + } + + // Check if we have a CFSocket for the native socket, create one if not. + MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket); + if (!socketInfo) { + socketInfo = new MacSocketInfo(); + + // Create CFSocket, specify that we want both read and write callbacks (the callbacks + // are enabled/disabled later on). + const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack; + CFSocketContext context = {0, d, 0, 0, 0}; + socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context); + if (CFSocketIsValid(socketInfo->socket) == false) { + qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket"); + return; + } + + CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket); + flags |= kCFSocketAutomaticallyReenableWriteCallBack; //QSocketNotifier stays enabled after a write + flags &= ~kCFSocketCloseOnInvalidate; //QSocketNotifier doesn't close the socket upon destruction/invalidation + CFSocketSetSocketFlags(socketInfo->socket, flags); + + // Add CFSocket to runloop. + if(!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) { + qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop"); + CFSocketInvalidate(socketInfo->socket); + CFRelease(socketInfo->socket); + return; + } + + // Disable both callback types by default. This must be done after + // we add the CFSocket to the runloop, or else these calls will have + // no effect. + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + + d->macSockets.insert(nativeSocket, socketInfo); + } + + // Increment read/write counters and select enable callbacks if necessary. + if (type == QSocketNotifier::Read) { + Q_ASSERT(socketInfo->readNotifier == 0); + socketInfo->readNotifier = notifier; + CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack); + } else if (type == QSocketNotifier::Write) { + Q_ASSERT(socketInfo->writeNotifier == 0); + socketInfo->writeNotifier = notifier; + CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + } +} + +/* + Unregister QSocketNotifer. The CFSocket correspoding to this notifier is + removed from the runloop of this is the last notifier that users + that CFSocket. +*/ +void QCocoaEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int nativeSocket = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); + return; + } +#endif + + Q_D(QCocoaEventDispatcher); + + if (type == QSocketNotifier::Exception) { + qWarning("QSocketNotifier::Exception is not supported on Mac OS X"); + return; + } + MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket); + if (!socketInfo) { + qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier"); + return; + } + + // Decrement read/write counters and disable callbacks if necessary. + if (type == QSocketNotifier::Read) { + Q_ASSERT(notifier == socketInfo->readNotifier); + socketInfo->readNotifier = 0; + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); + } else if (type == QSocketNotifier::Write) { + Q_ASSERT(notifier == socketInfo->writeNotifier); + socketInfo->writeNotifier = 0; + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + } + + // Remove CFSocket from runloop if this was the last QSocketNotifier. + if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) { + if (CFSocketIsValid(socketInfo->socket)) + qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); + CFRunLoopSourceInvalidate(socketInfo->runloop); + CFRelease(socketInfo->runloop); + CFSocketInvalidate(socketInfo->socket); + CFRelease(socketInfo->socket); + delete socketInfo; + d->macSockets.remove(nativeSocket); + } +} + +bool QCocoaEventDispatcher::hasPendingEvents() +{ + extern uint qGlobalPostedEventsCount(); + extern bool qt_is_gui_used; //qapplication.cpp + return qGlobalPostedEventsCount() || (qt_is_gui_used && GetNumEventsInQueue(GetMainEventQueue())); +} + +static bool IsMouseOrKeyEvent( NSEvent* event ) +{ + bool result = false; + + switch( [event type] ) + { + case NSLeftMouseDown: + case NSLeftMouseUp: + case NSRightMouseDown: + case NSRightMouseUp: + case NSMouseMoved: // ?? + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSMouseEntered: + case NSMouseExited: + case NSKeyDown: + case NSKeyUp: + case NSFlagsChanged: // key modifiers changed? + case NSCursorUpdate: // ?? + case NSScrollWheel: + case NSTabletPoint: + case NSTabletProximity: + case NSOtherMouseDown: + case NSOtherMouseUp: + case NSOtherMouseDragged: +#ifndef QT_NO_GESTURES +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + case NSEventTypeGesture: // touch events + case NSEventTypeMagnify: + case NSEventTypeSwipe: + case NSEventTypeRotate: + case NSEventTypeBeginGesture: + case NSEventTypeEndGesture: +#endif +#endif // QT_NO_GESTURES + result = true; + break; + + default: + break; + } + return result; +} + +static inline void qt_mac_waitForMoreEvents() +{ + // If no event exist in the cocoa event que, wait + // (and free up cpu time) until at least one event occur. + // This implementation is a bit on the edge, but seems to + // work fine: + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantFuture] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event) + [NSApp postEvent:event atStart:YES]; +} + +static inline void qt_mac_waitForMoreModalSessionEvents() +{ + // If no event exist in the cocoa event que, wait + // (and free up cpu time) until at least one event occur. + // This implementation is a bit on the edge, but seems to + // work fine: + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantFuture] + inMode:NSModalPanelRunLoopMode + dequeue:YES]; + if (event) + [NSApp postEvent:event atStart:YES]; +} + +bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + Q_D(QCocoaEventDispatcher); + d->interrupt = false; + + bool interruptLater = false; + QtCocoaInterruptDispatcher::cancelInterruptLater(); + + // In case we end up recursing while we now process events, make sure + // that we send remaining posted Qt events before this call returns: + wakeUp(); + emit awake(); + + bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents; + bool retVal = false; + forever { + if (d->interrupt) + break; + + QCocoaAutoReleasePool pool; + NSEvent* event = 0; + + // First, send all previously excluded input events, if any: + if (!excludeUserEvents) { + while (!d->queuedUserInputEvents.isEmpty()) { + event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst()); + if (!filterEvent(event)) { + [NSApp sendEvent:event]; + retVal = true; + } + [event release]; + } + } + + // If Qt is used as a plugin, or as an extension in a native cocoa + // application, we should not run or stop NSApplication; This will be + // done from the application itself. And if processEvents is called + // manually (rather than from a QEventLoop), we cannot enter a tight + // loop and block this call, but instead we need to return after one flush. + // Finally, if we are to exclude user input events, we cannot call [NSApp run] + // as we then loose control over which events gets dispatched: + const bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning]; + const bool canExec_Qt = !excludeUserEvents && + (flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec) ; + + if (canExec_Qt && canExec_3rdParty) { + // We can use exec-mode, meaning that we can stay in a tight loop until + // interrupted. This is mostly an optimization, but it allow us to use + // [NSApp run], which is the normal code path for cocoa applications. + if (NSModalSession session = d->currentModalSession()) { + QBoolBlocker execGuard(d->currentExecIsNSAppRun, false); + while ([NSApp runModalSession:session] == NSRunContinuesResponse && !d->interrupt) + qt_mac_waitForMoreModalSessionEvents(); + + if (!d->interrupt && session == d->currentModalSessionCached) { + // Someone called [NSApp stopModal:] from outside the event + // dispatcher (e.g to stop a native dialog). But that call wrongly stopped + // 'session' as well. As a result, we need to restart all internal sessions: + d->temporarilyStopAllModalSessions(); + } + } else { + d->nsAppRunCalledByQt = true; + QBoolBlocker execGuard(d->currentExecIsNSAppRun, true); + [NSApp run]; + } + retVal = true; + } else { + // We cannot block the thread (and run in a tight loop). + // Instead we will process all current pending events and return. + d->ensureNSAppInitialized(); + if (NSModalSession session = d->currentModalSession()) { + // INVARIANT: a modal window is executing. + if (!excludeUserEvents) { + // Since we can dispatch all kinds of events, we choose + // to use cocoa's native way of running modal sessions: + if (flags & QEventLoop::WaitForMoreEvents) + qt_mac_waitForMoreModalSessionEvents(); + NSInteger status = [NSApp runModalSession:session]; + if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) { + // INVARIANT: Someone called [NSApp stopModal:] from outside the event + // dispatcher (e.g to stop a native dialog). But that call wrongly stopped + // 'session' as well. As a result, we need to restart all internal sessions: + d->temporarilyStopAllModalSessions(); + } + retVal = true; + } else do { + // Dispatch all non-user events (but que non-user events up for later). In + // this case, we need more control over which events gets dispatched, and + // cannot use [NSApp runModalSession:session]: + event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSModalPanelRunLoopMode + dequeue: YES]; + + if (event) { + if (IsMouseOrKeyEvent(event)) { + [event retain]; + d->queuedUserInputEvents.append(event); + continue; + } + if (!filterEvent(event)) { + [NSApp sendEvent:event]; + retVal = true; + } + } + } while (!d->interrupt && event != nil); + } else do { + // INVARIANT: No modal window is executing. + event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue: YES]; + + if (event) { + if (flags & QEventLoop::ExcludeUserInputEvents) { + if (IsMouseOrKeyEvent(event)) { + [event retain]; + d->queuedUserInputEvents.append(event); + continue; + } + } + if (!filterEvent(event)) { + [NSApp sendEvent:event]; + retVal = true; + } + } + } while (!d->interrupt && event != nil); + + // Be sure to flush the Qt posted events when not using exec mode + // (exec mode will always do this call from the event loop source): + if (!d->interrupt) + QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); + + // Since the window that holds modality might have changed while processing + // events, we we need to interrupt when we return back the previous process + // event recursion to ensure that we spin the correct modal session. + // We do the interruptLater at the end of the function to ensure that we don't + // disturb the 'wait for more events' below (as deleteLater will post an event): + interruptLater = true; + } + bool canWait = (d->threadData->canWait + && !retVal + && !d->interrupt + && (flags & QEventLoop::WaitForMoreEvents)); + if (canWait) { + // INVARIANT: We haven't processed any events yet. And we're told + // to stay inside this function until at least one event is processed. + qt_mac_waitForMoreEvents(); + flags &= ~QEventLoop::WaitForMoreEvents; + } else { + // Done with event processing for now. + // Leave the function: + break; + } + } + + // If we're interrupted, we need to interrupt the _current_ + // recursion as well to check if it is still supposed to be + // executing. This way we wind down the stack until we land + // on a recursion that again calls processEvents (typically + // from QEventLoop), and set interrupt to false: + if (d->interrupt) + interrupt(); + + if (interruptLater) + QtCocoaInterruptDispatcher::interruptLater(); + + return retVal; +} + +void QCocoaEventDispatcher::wakeUp() +{ + Q_D(QCocoaEventDispatcher); + d->serialNumber.ref(); + CFRunLoopSourceSignal(d->postedEventsSource); + CFRunLoopWakeUp(mainRunLoop()); +} + +/***************************************************************************** + QEventDispatcherMac Implementation + *****************************************************************************/ +MacTimerHash QCocoaEventDispatcherPrivate::macTimerHash; +bool QCocoaEventDispatcherPrivate::blockSendPostedEvents = false; +bool QCocoaEventDispatcherPrivate::interrupt = false; + + +QStack<QCocoaModalSessionInfo> QCocoaEventDispatcherPrivate::cocoaModalSessionStack; +bool QCocoaEventDispatcherPrivate::currentExecIsNSAppRun = false; +bool QCocoaEventDispatcherPrivate::nsAppRunCalledByQt = false; +bool QCocoaEventDispatcherPrivate::cleanupModalSessionsNeeded = false; +NSModalSession QCocoaEventDispatcherPrivate::currentModalSessionCached = 0; + +void QCocoaEventDispatcherPrivate::ensureNSAppInitialized() +{ + // Some elements in Cocoa require NSApplication to be running before + // they get fully initialized, in particular the menu bar. This + // function is intended for cases where a dialog is told to execute before + // QGuiApplication::exec is called, or the application spins the events loop + // manually rather than calling QGuiApplication:exec. + // The function makes sure that NSApplication starts running, but stops + // it again as soon as the send posted events callback is called. That way + // we let Cocoa finish the initialization it seems to need. We'll only + // apply this trick at most once for any application, and we avoid doing it + // for the common case where main just starts QGuiApplication::exec. + if (nsAppRunCalledByQt || [NSApp isRunning]) + return; + nsAppRunCalledByQt = true; + QBoolBlocker block1(interrupt, true); + QBoolBlocker block2(currentExecIsNSAppRun, true); + [NSApp run]; +} + +void QCocoaEventDispatcherPrivate::temporarilyStopAllModalSessions() +{ + // Flush, and Stop, all created modal session, and as + // such, make them pending again. The next call to + // currentModalSession will recreate them again. The + // reason to stop all session like this is that otherwise + // a call [NSApp stop] would not stop NSApp, but rather + // the current modal session. So if we need to stop NSApp + // we need to stop all the modal session first. To avoid changing + // the stacking order of the windows while doing so, we put + // up a block that is used in QCocoaWindow and QCocoaPanel: + int stackSize = cocoaModalSessionStack.size(); + for (int i=0; i<stackSize; ++i) { + QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; + if (info.session) { + [NSApp endModalSession:info.session]; + info.session = 0; + } + } + currentModalSessionCached = 0; +} + +NSModalSession QCocoaEventDispatcherPrivate::currentModalSession() +{ + // If we have one or more modal windows, this function will create + // a session for each of those, and return the one for the top. + if (currentModalSessionCached) + return currentModalSessionCached; + + if (cocoaModalSessionStack.isEmpty()) + return 0; + + int sessionCount = cocoaModalSessionStack.size(); + for (int i=0; i<sessionCount; ++i) { + QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; + if (!info.window) + continue; +// ### port +// if (info.window->testAttribute(Qt::WA_DontShowOnScreen)) +// continue; + + if (!info.session) { + QCocoaAutoReleasePool pool; + NSWindow *window = reinterpret_cast<NSWindow *>(info.window->handle()->winId()); + if (!window) + continue; + + ensureNSAppInitialized(); + QBoolBlocker block1(blockSendPostedEvents, true); + info.nswindow = window; + [(NSWindow*) info.nswindow retain]; + int levelBeforeEnterModal = [window level]; + info.session = [NSApp beginModalSessionForWindow:window]; + // Make sure we don't stack the window lower that it was before + // entering modal, in case it e.g. had the stays-on-top flag set: + if (levelBeforeEnterModal > [window level]) + [window setLevel:levelBeforeEnterModal]; + } + currentModalSessionCached = info.session; + cleanupModalSessionsNeeded = false; + } + return currentModalSessionCached; +} + +static void setChildrenWorksWhenModal(QWindow *window, bool worksWhenModal) +{ + // For NSPanels (but not NSWindows, sadly), we can set the flag + // worksWhenModal, so that they are active even when they are not modal. +/* + ### not ported + QList<QDialog *> dialogs = window->findChildren<QDialog *>(); + for (int i=0; i<dialogs.size(); ++i){ + NSWindow *window = qt_mac_window_for(dialogs[i]); + if (window && [window isKindOfClass:[NSPanel class]]) { + [static_cast<NSPanel *>(window) setWorksWhenModal:worksWhenModal]; + if (worksWhenModal && [window isVisible]){ + [window orderFront:window]; + } + } + } +*/ +} + +void QCocoaEventDispatcherPrivate::updateChildrenWorksWhenModal() +{ + // Make the dialog children of the window + // active. And make the dialog children of + // the previous modal dialog unactive again: + QCocoaAutoReleasePool pool; + int size = cocoaModalSessionStack.size(); + if (size > 0){ + if (QWindow *prevModal = cocoaModalSessionStack[size-1].window) + setChildrenWorksWhenModal(prevModal, true); + if (size > 1){ + if (QWindow *prevModal = cocoaModalSessionStack[size-2].window) + setChildrenWorksWhenModal(prevModal, false); + } + } +} + +void QCocoaEventDispatcherPrivate::cleanupModalSessions() +{ + // Go through the list of modal sessions, and end those + // that no longer has a window assosiated; no window means + // the the session has logically ended. The reason we wait like + // this to actually end the sessions for real (rather than at the + // point they were marked as stopped), is that ending a session + // when no other session runs below it on the stack will make cocoa + // drop some events on the floor. + QCocoaAutoReleasePool pool; + int stackSize = cocoaModalSessionStack.size(); + + for (int i=stackSize-1; i>=0; --i) { + QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; + if (info.window) { + // This session has a window, and is therefore not marked + // as stopped. So just make it current. There might still be other + // stopped sessions on the stack, but those will be stopped on + // a later "cleanup" call. + currentModalSessionCached = info.session; + break; + } + cocoaModalSessionStack.remove(i); + currentModalSessionCached = 0; + if (info.session) { + [NSApp endModalSession:info.session]; + [(NSWindow *)info.nswindow release]; + } + } + + updateChildrenWorksWhenModal(); + cleanupModalSessionsNeeded = false; +} + +void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window) +{ + // Add a new, empty (null), NSModalSession to the stack. + // It will become active the next time QEventDispatcher::processEvents is called. + // A QCocoaModalSessionInfo is considered pending to become active if the window pointer + // is non-zero, and the session pointer is zero (it will become active upon a call to + // currentModalSession). A QCocoaModalSessionInfo is considered pending to be stopped if + // the window pointer is zero, and the session pointer is non-zero (it will be fully + // stopped in cleanupModalSessions()). + QCocoaModalSessionInfo info = {window, 0, 0}; + cocoaModalSessionStack.push(info); + updateChildrenWorksWhenModal(); + currentModalSessionCached = 0; +} + +void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window) +{ + // Mark all sessions attached to window as pending to be stopped. We do this + // by setting the window pointer to zero, but leave the session pointer. + // We don't tell cocoa to stop any sessions just yet, because cocoa only understands + // when we stop the _current_ modal session (which is the session on top of + // the stack, and might not belong to 'window'). + int stackSize = cocoaModalSessionStack.size(); + for (int i=stackSize-1; i>=0; --i) { + QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; + if (info.window == window) { + info.window = 0; + if (i == stackSize-1) { + // The top sessions ended. Interrupt the event dispatcher + // to start spinning the correct session immidiatly: + currentModalSessionCached = 0; + cleanupModalSessionsNeeded = true; + QCocoaEventDispatcher::instance()->interrupt(); + } + } + } +} + +QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate() +{ +} + +QCocoaEventDispatcher::QCocoaEventDispatcher(QObject *parent) + : QEventDispatcherUNIX(*new QCocoaEventDispatcherPrivate, parent) +{ + Q_D(QCocoaEventDispatcher); + CFRunLoopSourceContext context; + bzero(&context, sizeof(CFRunLoopSourceContext)); + context.info = d; + context.equal = QCocoaEventDispatcherPrivate::postedEventSourceEqualCallback; + context.perform = QCocoaEventDispatcherPrivate::postedEventsSourcePerformCallback; + d->postedEventsSource = CFRunLoopSourceCreate(0, 0, &context); + Q_ASSERT(d->postedEventsSource); + CFRunLoopAddSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes); + + CFRunLoopObserverContext observerContext; + bzero(&observerContext, sizeof(CFRunLoopObserverContext)); + observerContext.info = this; + d->waitingObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, + kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting, + true, 0, + QCocoaEventDispatcherPrivate::waitingObserverCallback, + &observerContext); + CFRunLoopAddObserver(mainRunLoop(), d->waitingObserver, kCFRunLoopCommonModes); + + /* The first cycle in the loop adds the source and the events of the source + are not processed. + We use an observer to process the posted events for the first + execution of the loop. */ + CFRunLoopObserverContext firstTimeObserverContext; + bzero(&firstTimeObserverContext, sizeof(CFRunLoopObserverContext)); + firstTimeObserverContext.info = d; + d->firstTimeObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, + kCFRunLoopEntry, + /* repeats = */ false, + 0, + QCocoaEventDispatcherPrivate::firstLoopEntry, + &firstTimeObserverContext); + CFRunLoopAddObserver(mainRunLoop(), d->firstTimeObserver, kCFRunLoopCommonModes); +} + +void QCocoaEventDispatcherPrivate::waitingObserverCallback(CFRunLoopObserverRef, + CFRunLoopActivity activity, void *info) +{ + if (activity == kCFRunLoopBeforeWaiting) + emit static_cast<QCocoaEventDispatcher*>(info)->aboutToBlock(); + else + emit static_cast<QCocoaEventDispatcher*>(info)->awake(); +} + +Boolean QCocoaEventDispatcherPrivate::postedEventSourceEqualCallback(const void *info1, const void *info2) +{ + return info1 == info2; +} + +void processPostedEvents(QCocoaEventDispatcherPrivate *const d, const bool blockSendPostedEvents) +{ + if (blockSendPostedEvents) { + // We're told to not send posted events (because the event dispatcher + // is currently working on setting up the correct session to run). But + // we still need to make sure that we don't fall asleep until pending events + // are sendt, so we just signal this need, and return: + CFRunLoopSourceSignal(d->postedEventsSource); + return; + } + + if (d->cleanupModalSessionsNeeded) + d->cleanupModalSessions(); + + if (d->interrupt) { + if (d->currentExecIsNSAppRun) { + // The event dispatcher has been interrupted. But since + // [NSApplication run] is running the event loop, we + // delayed stopping it until now (to let cocoa process + // pending cocoa events first). + if (d->currentModalSessionCached) + d->temporarilyStopAllModalSessions(); + [NSApp stop:NSApp]; + d->cancelWaitForMoreEvents(); + } + return; + } + + if (!d->threadData->canWait || (d->serialNumber != d->lastSerial)) { + d->lastSerial = d->serialNumber; + QWindowSystemInterface::sendWindowSystemEvents(d->q_func(), QEventLoop::AllEvents); + } +} + +void QCocoaEventDispatcherPrivate::firstLoopEntry(CFRunLoopObserverRef ref, + CFRunLoopActivity activity, + void *info) +{ + Q_UNUSED(ref); + Q_UNUSED(activity); +/* + // This function is called when NSApplication has finished initialization, + // which appears to be just after [NSApplication run] has started to execute. + // By setting up our apple events handlers this late, we override the ones + // set up by NSApplication. + + // If Qt is used as a plugin, we let the 3rd party application handle events + // like quit and open file events. Otherwise, if we install our own handlers, we + // easily end up breaking functionallity the 3rd party application depend on: + if (QGuiApplication::testAttribute(Qt::AA_MacPluginApplication)) + return; + + QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; + NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager]; + [eventManager setEventHandler:newDelegate andSelector:@selector(appleEventQuit:withReplyEvent:) + forEventClass:kCoreEventClass andEventID:kAEQuitApplication]; + [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:) + forEventClass:kInternetEventClass andEventID:kAEGetURL]; +*/ + + processPostedEvents(static_cast<QCocoaEventDispatcherPrivate *>(info), blockSendPostedEvents); +} + +void QCocoaEventDispatcherPrivate::postedEventsSourcePerformCallback(void *info) +{ + processPostedEvents(static_cast<QCocoaEventDispatcherPrivate *>(info), blockSendPostedEvents); +} + +void QCocoaEventDispatcherPrivate::cancelWaitForMoreEvents() +{ + // In case the event dispatcher is waiting for more + // events somewhere, we post a dummy event to wake it up: + QCocoaAutoReleasePool pool; + [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint + modifierFlags:0 timestamp:0. windowNumber:0 context:0 + subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO]; +} + +void QCocoaEventDispatcher::interrupt() +{ + Q_D(QCocoaEventDispatcher); + d->interrupt = true; + wakeUp(); + + // We do nothing more here than setting d->interrupt = true, and + // poke the event loop if it is sleeping. Actually stopping + // NSApp, or the current modal session, is done inside the send + // posted events callback. We do this to ensure that all current pending + // cocoa events gets delivered before we stop. Otherwise, if we now stop + // the last event loop recursion, cocoa will just drop pending posted + // events on the floor before we get a chance to reestablish a new session. + d->cancelWaitForMoreEvents(); +} + +QCocoaEventDispatcher::~QCocoaEventDispatcher() +{ + Q_D(QCocoaEventDispatcher); + //timer cleanup + MacTimerHash::iterator it = QCocoaEventDispatcherPrivate::macTimerHash.begin(); + while (it != QCocoaEventDispatcherPrivate::macTimerHash.end()) { + MacTimerInfo *t = it.value(); + if (t->runLoopTimer) { + CFRunLoopTimerInvalidate(t->runLoopTimer); + CFRelease(t->runLoopTimer); + } + delete t; + ++it; + } + QCocoaEventDispatcherPrivate::macTimerHash.clear(); + + // Remove CFSockets from the runloop. + for (MacSocketHash::ConstIterator it = d->macSockets.constBegin(); it != d->macSockets.constEnd(); ++it) { + MacSocketInfo *socketInfo = (*it); + if (CFSocketIsValid(socketInfo->socket)) { + qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); + CFRunLoopSourceInvalidate(socketInfo->runloop); + CFRelease(socketInfo->runloop); + CFSocketInvalidate(socketInfo->socket); + CFRelease(socketInfo->socket); + } + } + CFRunLoopRemoveSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes); + CFRelease(d->postedEventsSource); + + CFRunLoopObserverInvalidate(d->waitingObserver); + CFRelease(d->waitingObserver); + + CFRunLoopObserverInvalidate(d->firstTimeObserver); + CFRelease(d->firstTimeObserver); +} + +QtCocoaInterruptDispatcher* QtCocoaInterruptDispatcher::instance = 0; + +QtCocoaInterruptDispatcher::QtCocoaInterruptDispatcher() : cancelled(false) +{ + // The whole point of this class is that we enable a way to interrupt + // the event dispatcher when returning back to a lower recursion level + // than where interruptLater was called. This is needed to detect if + // [NSApp run] should still be running at the recursion level it is at. + // Since the interrupt is canceled if processEvents is called before + // this object gets deleted, we also avoid interrupting unnecessary. + deleteLater(); +} + +QtCocoaInterruptDispatcher::~QtCocoaInterruptDispatcher() +{ + if (cancelled) + return; + instance = 0; + QCocoaEventDispatcher::instance()->interrupt(); +} + +void QtCocoaInterruptDispatcher::cancelInterruptLater() +{ + if (!instance) + return; + instance->cancelled = true; + delete instance; + instance = 0; +} + +void QtCocoaInterruptDispatcher::interruptLater() +{ + cancelInterruptLater(); + instance = new QtCocoaInterruptDispatcher; +} + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/cocoa/qcocoaeventloopintegration.mm b/src/plugins/platforms/cocoa/qcocoaeventloopintegration.mm deleted file mode 100644 index ac0b75e9ea..0000000000 --- a/src/plugins/platforms/cocoa/qcocoaeventloopintegration.mm +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qcocoaeventloopintegration.h" - -#import <Cocoa/Cocoa.h> - -#include "qcocoaautoreleasepool.h" - -#include <QtCore/QElapsedTimer> - -#include <QDebug> -#include <QApplication> - -void wakeupCallback ( void * ) { - QPlatformEventLoopIntegration::processEvents(); -} - -void timerCallback( CFRunLoopTimerRef timer, void *info) -{ - QPlatformEventLoopIntegration::processEvents(); - QCocoaEventLoopIntegration *eventLoopIntegration = - static_cast<QCocoaEventLoopIntegration *>(info); - qint64 nextTime = eventLoopIntegration->nextTimerEvent(); - CFAbsoluteTime nexttime = CFAbsoluteTimeGetCurrent(); - nexttime = nexttime + (double(nextTime)/1000); - CFRunLoopTimerSetNextFireDate(timer,nexttime); -} - -QCocoaEventLoopIntegration::QCocoaEventLoopIntegration() : - QPlatformEventLoopIntegration() -{ - [NSApplication sharedApplication]; - m_sourceContext.version = 0; - m_sourceContext.info = this; - m_sourceContext.retain = 0; - m_sourceContext.release = 0; - m_sourceContext.copyDescription = 0; - m_sourceContext.equal = 0; - m_sourceContext.hash = 0; - m_sourceContext.schedule = 0; - m_sourceContext.cancel = 0; - m_sourceContext.perform = wakeupCallback; - - m_source = CFRunLoopSourceCreate(0,0,&m_sourceContext); - CFRunLoopAddSource(CFRunLoopGetMain(),m_source,kCFRunLoopCommonModes); - - m_timerContext.version = 0; - m_timerContext.info = this; - m_timerContext.retain = 0; - m_timerContext.release = 0; - m_timerContext.copyDescription = 0; - CFAbsoluteTime fireDate = CFAbsoluteTimeGetCurrent (); - CFTimeInterval interval = 30; - - CFRunLoopTimerRef m_timerSource = CFRunLoopTimerCreate(0,fireDate,interval,0,0,timerCallback,&m_timerContext); - CFRunLoopAddTimer(CFRunLoopGetMain(),m_timerSource,kCFRunLoopCommonModes); -} - -void QCocoaEventLoopIntegration::startEventLoop() -{ - [[NSApplication sharedApplication] run]; -} - -void QCocoaEventLoopIntegration::quitEventLoop() -{ - [[NSApplication sharedApplication] terminate:nil]; -} - -void QCocoaEventLoopIntegration::qtNeedsToProcessEvents() -{ - CFRunLoopSourceSignal(m_source); -} - diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h new file mode 100644 index 0000000000..1b84e7b305 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -0,0 +1,43 @@ +#ifndef QCOCOAGLCONTEXT_H +#define QCOCOAGLCONTEXT_H + +#include <QtCore/QWeakPointer> +#include <QtGui/QPlatformOpenGLContext> +#include <QtGui/QOpenGLContext> +#include <QtGui/QWindow> + +#undef slots +#include <Cocoa/Cocoa.h> + +QT_BEGIN_NAMESPACE + +class QCocoaGLContext : public QPlatformOpenGLContext +{ +public: + QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share); + + QSurfaceFormat format() const; + + void swapBuffers(QPlatformSurface *surface); + + bool makeCurrent(QPlatformSurface *surface); + void doneCurrent(); + + void (*getProcAddress(const QByteArray &procName)) (); + + void update(); + + static NSOpenGLPixelFormat *createNSOpenGLPixelFormat(); + NSOpenGLContext *nsOpenGLContext() const; + +private: + void setActiveWindow(QWindow *window); + + NSOpenGLContext *m_context; + QSurfaceFormat m_format; + QWeakPointer<QWindow> m_currentWindow; +}; + +QT_END_NAMESPACE + +#endif // QCOCOAGLCONTEXT_H diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm new file mode 100644 index 0000000000..8b07315378 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -0,0 +1,99 @@ +#include "qcocoaglcontext.h" +#include "qcocoawindow.h" +#include "qcocoaautoreleasepool.h" +#include <qdebug.h> +#include <QtCore/private/qcore_mac_p.h> +#include <QtPlatformSupport/private/cglconvenience_p.h> + +#import <Cocoa/Cocoa.h> + +QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share) + : m_format(format) +{ + QCocoaAutoReleasePool pool; // For the SG Canvas render thread. + + NSOpenGLPixelFormat *pixelFormat = static_cast <NSOpenGLPixelFormat *>(qcgl_createNSOpenGLPixelFormat()); + NSOpenGLContext *actualShare = share ? static_cast<QCocoaGLContext *>(share)->m_context : 0; + + m_context = [NSOpenGLContext alloc]; + [m_context initWithFormat:pixelFormat shareContext:actualShare]; + + const GLint interval = 1; + [m_context setValues:&interval forParameter:NSOpenGLCPSwapInterval]; + +} + +// Match up with createNSOpenGLPixelFormat! +QSurfaceFormat QCocoaGLContext::format() const +{ + return m_format; +} + +void QCocoaGLContext::swapBuffers(QPlatformSurface *surface) +{ + QWindow *window = static_cast<QCocoaWindow *>(surface)->window(); + setActiveWindow(window); + + [m_context flushBuffer]; +} + +bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) +{ + QCocoaAutoReleasePool pool; + + QWindow *window = static_cast<QCocoaWindow *>(surface)->window(); + setActiveWindow(window); + + [m_context makeCurrentContext]; + return true; +} + +void QCocoaGLContext::setActiveWindow(QWindow *window) +{ + if (window == m_currentWindow.data()) + return; + + if (m_currentWindow) + static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0); + + Q_ASSERT(window->handle()); + + m_currentWindow = window; + + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); + cocoaWindow->setCurrentContext(this); + + NSView *view = cocoaWindow->contentView(); + [m_context setView:view]; +} + +void QCocoaGLContext::doneCurrent() +{ + if (m_currentWindow) + static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0); + + m_currentWindow.clear(); + + [NSOpenGLContext clearCurrentContext]; +} + +void (*QCocoaGLContext::getProcAddress(const QByteArray &procName))() +{ + return qcgl_getProcAddress(procName); +} + +void QCocoaGLContext::update() +{ + [m_context update]; +} + +NSOpenGLPixelFormat *QCocoaGLContext::createNSOpenGLPixelFormat() +{ + return static_cast<NSOpenGLPixelFormat *>(qcgl_createNSOpenGLPixelFormat()); +} + +NSOpenGLContext *QCocoaGLContext::nsOpenGLContext() const +{ + return m_context; +} + diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h new file mode 100644 index 0000000000..8e807cc288 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -0,0 +1,90 @@ +/**************************************************************************** + ** + ** 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 plugins of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** GNU Lesser General Public License Usage + ** 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. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU General + ** Public License version 3.0 as published by the Free Software Foundation + ** and appearing in the file LICENSE.GPL included in the packaging of this + ** file. Please review the following information to ensure the GNU General + ** Public License version 3.0 requirements will be met: + ** http://www.gnu.org/copyleft/gpl.html. + ** + ** Other Usage + ** Alternatively, this file may be used in accordance with the terms and + ** conditions contained in a signed written agreement between you and Nokia. + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef QCOCOAHELPERS_H +#define QCOCOAHELPERS_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It provides helper functions +// for the Cocoa lighthouse plugin. This header file may +// change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qt_mac_p.h> + +class QPixmap; +class QString; + +// Conversion functions +QStringList qt_mac_NSArrayToQStringList(void *nsarray); +void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list); + +inline NSMutableArray *qt_mac_QStringListToNSMutableArray(const QStringList &qstrlist) +{ return reinterpret_cast<NSMutableArray *>(qt_mac_QStringListToNSMutableArrayVoid(qstrlist)); } + +inline QString qt_mac_NSStringToQString(const NSString *nsstr) +{ return QCFString::toQString(reinterpret_cast<const CFStringRef>(nsstr)); } + +inline NSString *qt_mac_QStringToNSString(const QString &qstr) +{ return [const_cast<NSString *>(reinterpret_cast<const NSString *>(QCFString::toCFStringRef(qstr))) autorelease]; } + +CGImageRef qt_mac_image_to_cgimage(const QImage &image); +NSImage *qt_mac_cgimage_to_nsimage(CGImageRef iamge); +NSImage *qt_mac_create_nsimage(const QPixmap &pm); + +QChar qt_mac_qtKey2CocoaKey(Qt::Key key); +Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode); + +// Misc +void qt_mac_transformProccessToForegroundApplication(); +QString qt_mac_removeMnemonics(const QString &original); +CGColorSpaceRef qt_mac_genericColorSpace(); +CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget); +QString qt_mac_applicationName(); + + +#endif //QCOCOAHELPERS_H + diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm new file mode 100644 index 0000000000..03e83f1130 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -0,0 +1,448 @@ +/**************************************************************************** + ** + ** 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 plugins of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** GNU Lesser General Public License Usage + ** 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. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU General + ** Public License version 3.0 as published by the Free Software Foundation + ** and appearing in the file LICENSE.GPL included in the packaging of this + ** file. Please review the following information to ensure the GNU General + ** Public License version 3.0 requirements will be met: + ** http://www.gnu.org/copyleft/gpl.html. + ** + ** Other Usage + ** Alternatively, this file may be used in accordance with the terms and + ** conditions contained in a signed written agreement between you and Nokia. + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#include "qcocoahelpers.h" + +#include "qcocoaautoreleasepool.h" + +#include <QtCore> +#include <QtGui> + +// +// Conversion Functions +// + +QStringList qt_mac_NSArrayToQStringList(void *nsarray) +{ + QStringList result; + NSArray *array = static_cast<NSArray *>(nsarray); + for (NSUInteger i=0; i<[array count]; ++i) + result << qt_mac_NSStringToQString([array objectAtIndex:i]); + return result; +} + +void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list) +{ + NSMutableArray *result = [NSMutableArray arrayWithCapacity:list.size()]; + for (int i=0; i<list.size(); ++i){ + [result addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(list[i]))]; + } + return result; +} + +static void drawImageReleaseData (void *info, const void *, size_t) +{ + delete static_cast<QImage *>(info); +} + +CGImageRef qt_mac_image_to_cgimage(const QImage &img) +{ + QImage *image; + if (img.depth() != 32) + image = new QImage(img.convertToFormat(QImage::Format_ARGB32_Premultiplied)); + else + image = new QImage(img); + + uint cgflags = kCGImageAlphaNone; + switch (image->format()) { + case QImage::Format_ARGB32_Premultiplied: + cgflags = kCGImageAlphaPremultipliedFirst; + break; + case QImage::Format_ARGB32: + cgflags = kCGImageAlphaFirst; + break; + case QImage::Format_RGB32: + cgflags = kCGImageAlphaNoneSkipFirst; + default: + break; + } + cgflags |= kCGBitmapByteOrder32Host; + QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(image, + static_cast<const QImage *>(image)->bits(), + image->byteCount(), + drawImageReleaseData); + + return CGImageCreate(image->width(), image->height(), 8, 32, + image->bytesPerLine(), + qt_mac_genericColorSpace(), + cgflags, dataProvider, 0, false, kCGRenderingIntentDefault); + +} + +NSImage *qt_mac_cgimage_to_nsimage(CGImageRef image) +{ + QCocoaAutoReleasePool pool; + NSImage *newImage = 0; + NSRect imageRect = NSMakeRect(0.0, 0.0, CGImageGetWidth(image), CGImageGetHeight(image)); + newImage = [[NSImage alloc] initWithSize:imageRect.size]; + [newImage lockFocus]; + { + CGContextRef imageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; + CGContextDrawImage(imageContext, *(CGRect*)&imageRect, image); + } + [newImage unlockFocus]; + return newImage; +} + +NSImage *qt_mac_create_nsimage(const QPixmap &pm) +{ + QImage image = pm.toImage(); + return qt_mac_cgimage_to_nsimage(qt_mac_image_to_cgimage(image)); +} + + +// Use this method to keep all the information in the TextSegment. As long as it is ordered +// we are in OK shape, and we can influence that ourselves. +struct KeyPair +{ + QChar cocoaKey; + Qt::Key qtKey; +}; + +bool operator==(const KeyPair &entry, QChar qchar) +{ + return entry.cocoaKey == qchar; +} + +bool operator<(const KeyPair &entry, QChar qchar) +{ + return entry.cocoaKey < qchar; +} + +bool operator<(QChar qchar, const KeyPair &entry) +{ + return qchar < entry.cocoaKey; +} + +bool operator<(const Qt::Key &key, const KeyPair &entry) +{ + return key < entry.qtKey; +} + +bool operator<(const KeyPair &entry, const Qt::Key &key) +{ + return entry.qtKey < key; +} + +static bool qtKey2CocoaKeySortLessThan(const KeyPair &entry1, const KeyPair &entry2) +{ + return entry1.qtKey < entry2.qtKey; +} + +static const int NumEntries = 59; +static const KeyPair entries[NumEntries] = { + { NSEnterCharacter, Qt::Key_Enter }, + { NSBackspaceCharacter, Qt::Key_Backspace }, + { NSTabCharacter, Qt::Key_Tab }, + { NSNewlineCharacter, Qt::Key_Return }, + { NSCarriageReturnCharacter, Qt::Key_Return }, + { NSBackTabCharacter, Qt::Key_Backtab }, + { kEscapeCharCode, Qt::Key_Escape }, + // Cocoa sends us delete when pressing backspace! + // (NB when we reverse this list in qtKey2CocoaKey, there + // will be two indices of Qt::Key_Backspace. But is seems to work + // ok for menu shortcuts (which uses that function): + { NSDeleteCharacter, Qt::Key_Backspace }, + { NSUpArrowFunctionKey, Qt::Key_Up }, + { NSDownArrowFunctionKey, Qt::Key_Down }, + { NSLeftArrowFunctionKey, Qt::Key_Left }, + { NSRightArrowFunctionKey, Qt::Key_Right }, + { NSF1FunctionKey, Qt::Key_F1 }, + { NSF2FunctionKey, Qt::Key_F2 }, + { NSF3FunctionKey, Qt::Key_F3 }, + { NSF4FunctionKey, Qt::Key_F4 }, + { NSF5FunctionKey, Qt::Key_F5 }, + { NSF6FunctionKey, Qt::Key_F6 }, + { NSF7FunctionKey, Qt::Key_F7 }, + { NSF8FunctionKey, Qt::Key_F8 }, + { NSF9FunctionKey, Qt::Key_F8 }, + { NSF10FunctionKey, Qt::Key_F10 }, + { NSF11FunctionKey, Qt::Key_F11 }, + { NSF12FunctionKey, Qt::Key_F12 }, + { NSF13FunctionKey, Qt::Key_F13 }, + { NSF14FunctionKey, Qt::Key_F14 }, + { NSF15FunctionKey, Qt::Key_F15 }, + { NSF16FunctionKey, Qt::Key_F16 }, + { NSF17FunctionKey, Qt::Key_F17 }, + { NSF18FunctionKey, Qt::Key_F18 }, + { NSF19FunctionKey, Qt::Key_F19 }, + { NSF20FunctionKey, Qt::Key_F20 }, + { NSF21FunctionKey, Qt::Key_F21 }, + { NSF22FunctionKey, Qt::Key_F22 }, + { NSF23FunctionKey, Qt::Key_F23 }, + { NSF24FunctionKey, Qt::Key_F24 }, + { NSF25FunctionKey, Qt::Key_F25 }, + { NSF26FunctionKey, Qt::Key_F26 }, + { NSF27FunctionKey, Qt::Key_F27 }, + { NSF28FunctionKey, Qt::Key_F28 }, + { NSF29FunctionKey, Qt::Key_F29 }, + { NSF30FunctionKey, Qt::Key_F30 }, + { NSF31FunctionKey, Qt::Key_F31 }, + { NSF32FunctionKey, Qt::Key_F32 }, + { NSF33FunctionKey, Qt::Key_F33 }, + { NSF34FunctionKey, Qt::Key_F34 }, + { NSF35FunctionKey, Qt::Key_F35 }, + { NSInsertFunctionKey, Qt::Key_Insert }, + { NSDeleteFunctionKey, Qt::Key_Delete }, + { NSHomeFunctionKey, Qt::Key_Home }, + { NSEndFunctionKey, Qt::Key_End }, + { NSPageUpFunctionKey, Qt::Key_PageUp }, + { NSPageDownFunctionKey, Qt::Key_PageDown }, + { NSPrintScreenFunctionKey, Qt::Key_Print }, + { NSScrollLockFunctionKey, Qt::Key_ScrollLock }, + { NSPauseFunctionKey, Qt::Key_Pause }, + { NSSysReqFunctionKey, Qt::Key_SysReq }, + { NSMenuFunctionKey, Qt::Key_Menu }, + { NSHelpFunctionKey, Qt::Key_Help }, +}; +static const KeyPair * const end = entries + NumEntries; + +QChar qt_mac_qtKey2CocoaKey(Qt::Key key) +{ + // The first time this function is called, create a reverse + // looup table sorted on Qt Key rather than Cocoa key: + static QVector<KeyPair> rev_entries(NumEntries); + static bool mustInit = true; + if (mustInit){ + mustInit = false; + for (int i=0; i<NumEntries; ++i) + rev_entries[i] = entries[i]; + qSort(rev_entries.begin(), rev_entries.end(), qtKey2CocoaKeySortLessThan); + } + const QVector<KeyPair>::iterator i + = qBinaryFind(rev_entries.begin(), rev_entries.end(), key); + if (i == rev_entries.end()) + return QChar(); + return i->cocoaKey; +} + +Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode) +{ + const KeyPair *i = qBinaryFind(entries, end, keyCode); + if (i == end) + return Qt::Key(keyCode.unicode()); + return i->qtKey; +} + +// +// Misc +// + +// Changes the process type for this process to kProcessTransformToForegroundApplication, +// unless either LSUIElement or LSBackgroundOnly is set in the Info.plist. +void qt_mac_transformProccessToForegroundApplication() +{ + ProcessSerialNumber psn; + if (GetCurrentProcess(&psn) == noErr) { + bool forceTransform = true; + CFTypeRef value = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), + CFSTR("LSUIElement")); + if (value) { + CFTypeID valueType = CFGetTypeID(value); + // Officially it's supposed to be a string, a boolean makes sense, so we'll check. + // A number less so, but OK. + if (valueType == CFStringGetTypeID()) + forceTransform = !(QCFString::toQString(static_cast<CFStringRef>(value)).toInt()); + else if (valueType == CFBooleanGetTypeID()) + forceTransform = !CFBooleanGetValue(static_cast<CFBooleanRef>(value)); + else if (valueType == CFNumberGetTypeID()) { + int valueAsInt; + CFNumberGetValue(static_cast<CFNumberRef>(value), kCFNumberIntType, &valueAsInt); + forceTransform = !valueAsInt; + } + } + + if (forceTransform) { + value = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), + CFSTR("LSBackgroundOnly")); + if (value) { + CFTypeID valueType = CFGetTypeID(value); + if (valueType == CFBooleanGetTypeID()) + forceTransform = !CFBooleanGetValue(static_cast<CFBooleanRef>(value)); + else if (valueType == CFStringGetTypeID()) + forceTransform = !(QCFString::toQString(static_cast<CFStringRef>(value)).toInt()); + else if (valueType == CFNumberGetTypeID()) { + int valueAsInt; + CFNumberGetValue(static_cast<CFNumberRef>(value), kCFNumberIntType, &valueAsInt); + forceTransform = !valueAsInt; + } + } + } + + if (forceTransform) { + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + } + } +} + +QString qt_mac_removeMnemonics(const QString &original) +{ + QString returnText(original.size(), 0); + int finalDest = 0; + int currPos = 0; + int l = original.length(); + while (l) { + if (original.at(currPos) == QLatin1Char('&') + && (l == 1 || original.at(currPos + 1) != QLatin1Char('&'))) { + ++currPos; + --l; + if (l == 0) + break; + } + returnText[finalDest] = original.at(currPos); + ++currPos; + ++finalDest; + --l; + } + returnText.truncate(finalDest); + return returnText; +} + + +CGColorSpaceRef m_genericColorSpace = 0; +QHash<CGDirectDisplayID, CGColorSpaceRef> m_displayColorSpaceHash; +bool m_postRoutineRegistered = false; + +CGColorSpaceRef qt_mac_genericColorSpace() +{ +#if 0 + if (!m_genericColorSpace) { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { + m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + } else +#endif + { + m_genericColorSpace = CGColorSpaceCreateDeviceRGB(); + } + if (!m_postRoutineRegistered) { + m_postRoutineRegistered = true; + qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces); + } + } + return m_genericColorSpace; +#else + // Just return the main display colorspace for the moment. + return qt_mac_displayColorSpace(0); +#endif +} + +/* + Ideally, we should pass the widget in here, and use CGGetDisplaysWithRect() etc. + to support multiple displays correctly. +*/ +CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget) +{ + CGColorSpaceRef colorSpace; + + CGDirectDisplayID displayID; + CMProfileRef displayProfile = 0; + if (widget == 0) { + displayID = CGMainDisplayID(); + } else { + displayID = CGMainDisplayID(); + /* + ### get correct display + const QRect &qrect = widget->window()->geometry(); + CGRect rect = CGRectMake(qrect.x(), qrect.y(), qrect.width(), qrect.height()); + CGDisplayCount throwAway; + CGDisplayErr dErr = CGGetDisplaysWithRect(rect, 1, &displayID, &throwAway); + if (dErr != kCGErrorSuccess) + return macDisplayColorSpace(0); // fall back on main display + */ + } + if ((colorSpace = m_displayColorSpaceHash.value(displayID))) + return colorSpace; + + CMError err = CMGetProfileByAVID((CMDisplayIDType)displayID, &displayProfile); + if (err == noErr) { + colorSpace = CGColorSpaceCreateWithPlatformColorSpace(displayProfile); + } else if (widget) { + return qt_mac_displayColorSpace(0); // fall back on main display + } + + if (colorSpace == 0) + colorSpace = CGColorSpaceCreateDeviceRGB(); + + m_displayColorSpaceHash.insert(displayID, colorSpace); + CMCloseProfile(displayProfile); + if (!m_postRoutineRegistered) { + m_postRoutineRegistered = true; + void qt_mac_cleanUpMacColorSpaces(); + qAddPostRoutine(qt_mac_cleanUpMacColorSpaces); + } + return colorSpace; +} + +void qt_mac_cleanUpMacColorSpaces() +{ + if (m_genericColorSpace) { + CFRelease(m_genericColorSpace); + m_genericColorSpace = 0; + } + QHash<CGDirectDisplayID, CGColorSpaceRef>::const_iterator it = m_displayColorSpaceHash.constBegin(); + while (it != m_displayColorSpaceHash.constEnd()) { + if (it.value()) + CFRelease(it.value()); + ++it; + } + m_displayColorSpaceHash.clear(); +} + +QString qt_mac_applicationName() +{ + QString appName; + CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("CFBundleName")); + if (string) + appName = QCFString::toQString(static_cast<CFStringRef>(string)); + + if (appName.isEmpty()) { + QString arg0 = qApp->arguments().at(0); + if (arg0.contains("/")) { + QStringList parts = arg0.split("/"); + appName = parts.at(parts.count() - 1); + } else { + appName = arg0; + } + } + return appName; +} + diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 120bee46b7..a253a6bea3 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -76,19 +76,19 @@ public: ~QCocoaIntegration(); bool hasCapability(QPlatformIntegration::Capability cap) const; - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId = 0) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; - - QList<QPlatformScreen *> screens() const { return mScreens; } + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const; + QAbstractEventDispatcher *guiThreadEventDispatcher() const; QPlatformFontDatabase *fontDatabase() const; + QPlatformMenu *createPlatformMenu(QMenu *menu = 0) const; + QPlatformMenuBar *createPlatformMenuBar(QMenuBar *menuBar = 0) const; - QPlatformEventLoopIntegration *createEventLoopIntegration() const; - + QPlatformNativeInterface *nativeInterface() const; private: - QList<QPlatformScreen *> mScreens; QPlatformFontDatabase *mFontDb; + QAbstractEventDispatcher *mEventDispatcher; QCocoaAutoReleasePool *mPool; }; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 086f7b62e9..e3e204226f 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -42,14 +42,18 @@ #include "qcocoaintegration.h" #include "qcocoawindow.h" -#include "qcocoawindowsurface.h" -#include "qcocoaeventloopintegration.h" +#include "qcocoabackingstore.h" +#include "qcocoanativeinterface.h" +#include "qcocoamenuloader.h" +#include "qcocoaeventdispatcher.h" +#include "qcocoahelpers.h" +#include "qcocoaapplication.h" +#include "qcocoaapplicationdelegate.h" +#include "qmenu_mac.h" -#include "qcoretextfontdatabase.h" +#include <QtCore/qcoreapplication.h> -#include <QtGui/QApplication> - -#include <private/qpixmap_raster_p.h> +#include <QtPlatformSupport/private/qbasicunixfontdatabase_p.h> QT_BEGIN_NAMESPACE @@ -74,18 +78,47 @@ QCocoaScreen::~QCocoaScreen() } QCocoaIntegration::QCocoaIntegration() - : mFontDb(new QCoreTextFontDatabase()) + : mFontDb(new QBasicUnixFontDatabase()) + , mEventDispatcher(new QCocoaEventDispatcher()) { mPool = new QCocoaAutoReleasePool; - //Make sure we have a nsapplication :) - [NSApplication sharedApplication]; -// [[OurApplication alloc] init]; + QNSApplication *cocoaApplication = [QNSApplication sharedApplication]; + + // Applications launched from plain executables (without an app + // bundle) are "background" applications that does not take keybaord + // focus or have a dock icon or task switcher entry. Qt Gui apps generally + // wants to be foreground applications so change the process type. (But + // see the function implementation for exceptions.) + qt_mac_transformProccessToForegroundApplication(); + + // Move the application window to front to avoid launching behind the terminal. + // Ignoring other apps is neccessary (we must ignore the terminal), but makes + // Qt apps play slightly less nice with other apps when lanching from Finder + // (See the activateIgnoringOtherApps docs.) + [cocoaApplication activateIgnoringOtherApps : YES]; + + // ### For AA_MacPluginApplication we don't want to load the menu nib. + // Qt 4 also does not set the application delegate, so that behavior + // is matched here. + if (!QCoreApplication::testAttribute(Qt::AA_MacPluginApplication)) { + + // Set app delegate, link to the current delegate (if any) + QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; + [newDelegate setReflectionDelegate:[cocoaApplication delegate]]; + [cocoaApplication setDelegate:newDelegate]; + + // Load the application menu. This menu contains Preferences, Hide, Quit. + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader = [[QT_MANGLE_NAMESPACE(QCocoaMenuLoader) alloc] init]; + qt_mac_loadMenuNib(qtMenuLoader); + [cocoaApplication setMenu:[qtMenuLoader menu]]; + [newDelegate setMenuLoader:qtMenuLoader]; + } NSArray *screens = [NSScreen screens]; for (uint i = 0; i < [screens count]; i++) { QCocoaScreen *screen = new QCocoaScreen(i); - mScreens.append(screen); + screenAdded(screen); } } @@ -98,26 +131,32 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons { switch (cap) { case ThreadedPixmaps: return true; + case OpenGL : return true; + case ThreadedOpenGL : return true; default: return QPlatformIntegration::hasCapability(cap); } } -QPixmapData *QCocoaIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWindow *window) const +{ + return new QCocoaWindow(window); +} + +QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - return new QRasterPixmapData(type); + return new QCocoaGLContext(context->format(), context->shareHandle()); } -QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWidget *widget, WId winId) const +QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *window) const { - Q_UNUSED(winId); - return new QCocoaWindow(widget); + return new QCocoaBackingStore(window); } -QWindowSurface *QCocoaIntegration::createWindowSurface(QWidget *widget, WId winId) const +QAbstractEventDispatcher *QCocoaIntegration::guiThreadEventDispatcher() const { - return new QCocoaWindowSurface(widget,winId); + return mEventDispatcher; } QPlatformFontDatabase *QCocoaIntegration::fontDatabase() const @@ -125,8 +164,21 @@ QPlatformFontDatabase *QCocoaIntegration::fontDatabase() const return mFontDb; } -QPlatformEventLoopIntegration *QCocoaIntegration::createEventLoopIntegration() const +QPlatformMenu *QCocoaIntegration::createPlatformMenu(QMenu *menu) const +{ + // return new QCocoaMenu(menu); + return 0; +} + +QPlatformMenuBar *QCocoaIntegration::createPlatformMenuBar(QMenuBar *menuBar) const +{ + //return new QCocoaMenuBar(menuBar); + return 0; +} + +QPlatformNativeInterface *QCocoaIntegration::nativeInterface() const { - return new QCocoaEventLoopIntegration(); + return new QCocoaNativeInterface(); } + QT_END_NAMESPACE diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp b/src/plugins/platforms/cocoa/qcocoamenu.h index 228e7b8dea..4e8ce20580 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the plugins of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -39,40 +39,42 @@ ** ****************************************************************************/ -#include "qdirectfbscreen.h" +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// -#include <QtGui/qscreendriverplugin_qws.h> -#include <QtCore/qstringlist.h> -#ifndef QT_NO_QWS_DIRECTFB +#include "qmacdefines_mac.h" +#import <Cocoa/Cocoa.h> -class DirectFBScreenDriverPlugin : public QScreenDriverPlugin -{ -public: - DirectFBScreenDriverPlugin(); +QT_FORWARD_DECLARE_CLASS(QMenu) +QT_FORWARD_DECLARE_CLASS(QAction) - QStringList keys() const; - QScreen *create(const QString&, int displayId); -}; +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 -DirectFBScreenDriverPlugin::DirectFBScreenDriverPlugin() - : QScreenDriverPlugin() -{ -} +@protocol NSMenuDelegate <NSObject> +- (void)menu:(NSMenu*)menu willHighlightItem:(NSMenuItem*)item; +- (void)menuWillOpen:(NSMenu*)menu; +- (void)menuDidClose:(NSMenu*)menu; +- (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier + whichItem:(NSMenuItem**)outItem; +@end -QStringList DirectFBScreenDriverPlugin::keys() const -{ - return (QStringList() << "directfb"); -} +#endif -QScreen* DirectFBScreenDriverPlugin::create(const QString& driver, - int displayId) +@interface QT_MANGLE_NAMESPACE(QNativeCocoaMenu) : NSMenu <NSMenuDelegate> { - if (driver.toLower() != "directfb") - return 0; - - return new QDirectFBScreen(displayId); + QMenu *qmenu; + QAction *previousAction; } +- (id)initWithQMenu:(QMenu*)menu; +- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action; +- (NSInteger)indexOfItemWithTarget:(id)anObject andAction:(SEL)actionSelector; +@end -Q_EXPORT_PLUGIN2(qdirectfbscreen, DirectFBScreenDriverPlugin) - -#endif diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm new file mode 100644 index 0000000000..1bb5f45a94 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** 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 QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication.h" +#include "qvarlengtharray.h" +#import "qcocoamenu.h" +#import "qcocoamenuloader.h" +#import "qcocoaapplication.h" +#include "qcocoahelpers.h" +#include <private/qapplication_p.h> +#include <private/qaction_p.h> + +QT_FORWARD_DECLARE_CLASS(QAction) +QT_FORWARD_DECLARE_CLASS(QWidget) +QT_FORWARD_DECLARE_CLASS(QApplication) +QT_FORWARD_DECLARE_CLASS(QCoreApplication) +QT_FORWARD_DECLARE_CLASS(QApplicationPrivate) +QT_FORWARD_DECLARE_CLASS(QKeyEvent) +QT_FORWARD_DECLARE_CLASS(QEvent) + +QT_BEGIN_NAMESPACE +extern void qt_mac_menu_collapseSeparators(NSMenu *menu, bool collapse); +void qt_mac_clear_status_text(QAction *action); +extern void qt_mac_emit_menuSignals(QMenu *menu, bool show); +extern void qt_mac_menu_emit_hovered(QMenu *menu, QAction *action); +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +@implementation QT_MANGLE_NAMESPACE(QNativeCocoaMenu) + +- (id)initWithQMenu:(QMenu*)menu +{ + self = [super init]; + if (self) { + qmenu = menu; + previousAction = 0; + [self setAutoenablesItems:NO]; + [self setDelegate:self]; + } + return self; +} + +- (void)menu:(NSMenu*)menu willHighlightItem:(NSMenuItem*)item +{ + Q_UNUSED(menu); + + if (!item) { + if (previousAction) { + qt_mac_clear_status_text(previousAction); + previousAction = 0; + } + return; + } + + if (QAction *action = reinterpret_cast<QAction *>([item tag])) { + QMenu *qtmenu = static_cast<QT_MANGLE_NAMESPACE(QNativeCocoaMenu) *>(menu)->qmenu; + previousAction = action; + action->activate(QAction::Hover); + qt_mac_menu_emit_hovered(qtmenu, action); + action->showStatusText(0); // 0 widget -> action's parent + } +} + +- (void)menuWillOpen:(NSMenu*)menu +{ + while (QWidget *popup + = QApplication::activePopupWidget()) + popup->close(); + QMenu *qtmenu = static_cast<QT_MANGLE_NAMESPACE(QNativeCocoaMenu) *>(menu)->qmenu; + qt_mac_emit_menuSignals(qtmenu, true); + qt_mac_menu_collapseSeparators(menu, qtmenu->separatorsCollapsible()); +} + +- (void)menuDidClose:(NSMenu*)menu +{ + qt_mac_emit_menuSignals(((QT_MANGLE_NAMESPACE(QNativeCocoaMenu) *)menu)->qmenu, false); + if (previousAction) { + qt_mac_clear_status_text(previousAction); + previousAction = 0; + } +} + +- (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier + whichItem:(NSMenuItem**)outItem +{ + for (NSMenuItem *item in [menu itemArray]) { + if (![item isEnabled] || [item isHidden] || [item isSeparatorItem]) + continue; + if ([item hasSubmenu]) { + if ([self hasShortcut:[item submenu] + forKey:key + forModifiers:modifier whichItem:outItem]) { + if (outItem) + *outItem = item; + return YES; + } + } + NSString *menuKey = [item keyEquivalent]; + if (menuKey && NSOrderedSame == [menuKey compare:key] + && (modifier == [item keyEquivalentModifierMask])) { + if (outItem) + *outItem = item; + return YES; + } + } + if (outItem) + *outItem = 0; + return NO; +} + +NSString *qt_mac_removePrivateUnicode(NSString* string) +{ + int len = [string length]; + if (len) { + QVarLengthArray <unichar, 10> characters(len); + bool changed = false; + for (int i = 0; i<len; i++) { + characters[i] = [string characterAtIndex:i]; + // check if they belong to key codes in private unicode range + // currently we need to handle only the NSDeleteFunctionKey + if (characters[i] == NSDeleteFunctionKey) { + characters[i] = NSDeleteCharacter; + changed = true; + } + } + if (changed) + return [NSString stringWithCharacters:characters.data() length:len]; + } + return string; +} + +- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action +{ + // Check if the menu actually has a keysequence defined for this key event. + // If it does, then we will first send the key sequence to the QWidget that has focus + // since (in Qt's eyes) it needs to a chance at the key event first. If the widget + // accepts the key event, we then return YES, but set the target and action to be nil, + // which means that the action should not be triggered, and instead dispatch the event ourselves. + // In every other case we return NO, which means that Cocoa can do as it pleases + // (i.e., fire the menu action). + NSMenuItem *whichItem; + // Change the private unicode keys to the ones used in setting the "Key Equivalents" + NSString *characters = qt_mac_removePrivateUnicode([event characters]); + if ([self hasShortcut:menu + forKey:characters + // Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ... + forModifiers:([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask)) + whichItem:&whichItem]) { + QWidget *widget = 0; + QAction *qaction = 0; + if (whichItem && [whichItem tag]) { + qaction = reinterpret_cast<QAction *>([whichItem tag]); + } + if (qApp->activePopupWidget()) + widget = (qApp->activePopupWidget()->focusWidget() ? + qApp->activePopupWidget()->focusWidget() : qApp->activePopupWidget()); + else if (QApplicationPrivate::focus_widget) + widget = QApplicationPrivate::focus_widget; + // If we could not find any receivers, pass it to the active window + if (!widget) + widget = qApp->activeWindow(); + if (qaction && widget) { + int key = qaction->shortcut(); + QKeyEvent accel_ev(QEvent::ShortcutOverride, (key & (~Qt::KeyboardModifierMask)), + Qt::KeyboardModifiers(key & Qt::KeyboardModifierMask)); + accel_ev.ignore(); + +// ### qt_sendSpontaneousEvent(widget, &accel_ev); + + if (accel_ev.isAccepted()) { + qWarning("Unimplemented: qt_dispatchKeyEvent"); +#if 0 + qt_dispatchKeyEvent(event, widget); +#endif + *target = nil; + *action = nil; + return YES; + } + } + } + return NO; +} + +- (NSInteger)indexOfItemWithTarget:(id)anObject andAction:(SEL)actionSelector +{ + NSInteger index = [super indexOfItemWithTarget:anObject andAction:actionSelector]; + static SEL selForOFCP = NSSelectorFromString(@"orderFrontCharacterPalette:"); + if (index == -1 && selForOFCP == actionSelector) { + // Check if the 'orderFrontCharacterPalette' SEL exists for QNativeCocoaMenuLoader object + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; + return [super indexOfItemWithTarget:loader andAction:actionSelector]; + } + return index; +} + +@end + +QT_BEGIN_NAMESPACE +extern int qt_mac_menus_open_count; // qmenu_mac.mm + +void qt_mac_emit_menuSignals(QMenu *menu, bool show) +{ + if (!menu) + return; + int delta; + if (show) { + emit menu->aboutToShow(); + delta = 1; + } else { + emit menu->aboutToHide(); + delta = -1; + } + qt_mac_menus_open_count += delta; +} + +void qt_mac_clear_status_text(QAction *action) +{ + action->d_func()->showStatusText(0, QString()); +} + +void qt_mac_menu_emit_hovered(QMenu *menu, QAction *action) +{ + emit menu->hovered(action); +} + + +QT_END_NAMESPACE + diff --git a/src/plugins/decorations/styled/main.cpp b/src/plugins/platforms/cocoa/qcocoamenuloader.h index 69c339843a..2fcda512f0 100644 --- a/src/plugins/decorations/styled/main.cpp +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.h @@ -39,39 +39,57 @@ ** ****************************************************************************/ -#include <qdecorationplugin_qws.h> -#include <qdecorationstyled_qws.h> +#ifndef QCOCOAMENULOADER_P_H +#define QCOCOAMENULOADER_P_H -QT_BEGIN_NAMESPACE +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// -class DecorationStyled : public QDecorationPlugin -{ -public: - DecorationStyled(); - - QStringList keys() const; - QDecoration *create(const QString&); -}; - -DecorationStyled::DecorationStyled() : QDecorationPlugin() -{ -} +#import <Cocoa/Cocoa.h> +#include <QtCore/private/qcore_mac_p.h> -QStringList DecorationStyled::keys() const +@interface QT_MANGLE_NAMESPACE(QCocoaMenuLoader) : NSResponder { - return (QStringList() << QLatin1String("Styled")); -} - -QDecoration* DecorationStyled::create(const QString& s) -{ - if (s.toLower() != QLatin1String("styled")) - return 0; - - qDebug("creatign styled decoration"); - - return new QDecorationStyled; + IBOutlet NSMenu *theMenu; + IBOutlet NSMenu *appMenu; + IBOutlet NSMenuItem *quitItem; + IBOutlet NSMenuItem *preferencesItem; + IBOutlet NSMenuItem *aboutItem; + IBOutlet NSMenuItem *aboutQtItem; + IBOutlet NSMenuItem *hideItem; + NSMenuItem *lastAppSpecificItem; + NSMenuItem *servicesItem; + NSMenuItem *hideAllOthersItem; + NSMenuItem *showAllItem; } +- (void)ensureAppMenuInMenu:(NSMenu *)menu; +- (void)removeActionsFromAppMenu; +- (NSMenu *)applicationMenu; +- (NSMenu *)menu; +- (NSMenuItem *)quitMenuItem; +- (NSMenuItem *)preferencesMenuItem; +- (NSMenuItem *)aboutMenuItem; +- (NSMenuItem *)aboutQtMenuItem; +- (NSMenuItem *)hideMenuItem; +- (NSMenuItem *)appSpecificMenuItem; +- (IBAction)terminate:(id)sender; +- (IBAction)orderFrontStandardAboutPanel:(id)sender; +- (IBAction)hideOtherApplications:(id)sender; +- (IBAction)unhideAllApplications:(id)sender; +- (IBAction)hide:(id)sender; +- (IBAction)qtDispatcherToQAction:(id)sender; +- (void)qtUpdateMenubar; +- (void)orderFrontCharacterPalette:(id)sender; +@end -Q_EXPORT_PLUGIN2(qdecorationstyled, DecorationStyled) +void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader); -QT_END_NAMESPACE +#endif // QCOCOAMENULOADER_P_H diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm new file mode 100644 index 0000000000..353808655f --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -0,0 +1,314 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcocoamenuloader.h" + +#include "qmenu_mac.h" +#include "qcocoahelpers.h" + +#include <QtCore/private/qcore_mac_p.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdir.h> +#include <QtCore/qstring.h> +#include <QtCore/qdebug.h> + +QT_FORWARD_DECLARE_CLASS(QCFString) +QT_FORWARD_DECLARE_CLASS(QString) + +#ifndef QT_NO_TRANSLATION + QT_BEGIN_NAMESPACE + extern QString qt_mac_applicationmenu_string(int type); + QT_END_NAMESPACE +#endif + +QT_USE_NAMESPACE + +/* + Loads and instantiates the main app menu from the menu nib file(s). + + The main app menu contains the Quit, Hide About, Preferences entries, and + The reason for having the nib file is that those can not be created + programmatically. To ease deployment the nib files are stored in Qt resources + and written to QDir::temp() before loading. (Earlier Qt versions used + to require having the nib file in the QtGui framework.) +*/ +void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader) +{ + // Create qt_menu.nib dir in temp. + QDir temp = QDir::temp(); + temp.mkdir("qt_menu.nib"); + QString nibDir = temp.canonicalPath() + QLatin1String("/") + QLatin1String("qt_menu.nib/"); + if (!QDir(nibDir).exists()) { + qWarning("qt_mac_loadMenuNib: could not create nib directory in temp"); + return; + } + + // Copy nib files from resources to temp. + QDir nibResource(":/trolltech/mac/qt_menu.nib/"); + if (!nibResource.exists()) { + qWarning("qt_mac_loadMenuNib: could not load nib from resources"); + return; + } + foreach (const QFileInfo &file, nibResource.entryInfoList()) { + QFile::copy(file.absoluteFilePath(), nibDir + QLatin1String("/") + file.fileName()); + } + + // Load and instantiate nib file from temp + NSURL *nibUrl = [NSURL fileURLWithPath : const_cast<NSString *>(reinterpret_cast<const NSString *>(QCFString::toCFStringRef(nibDir)))]; + [nibUrl autorelease]; + NSNib *nib = [[NSNib alloc] initWithContentsOfURL : nibUrl]; + [nib autorelease]; + if(!nib) { + qWarning("qt_mac_loadMenuNib: could not load nib from temp"); + return; + } + bool ok = [nib instantiateNibWithOwner : qtMenuLoader topLevelObjects : nil]; + if (!ok) { + qWarning("qt_mac_loadMenuNib: could not instantiate nib"); + } +} + + + +@implementation QT_MANGLE_NAMESPACE(QCocoaMenuLoader) + +- (void)awakeFromNib +{ + servicesItem = [[appMenu itemWithTitle:@"Services"] retain]; + hideAllOthersItem = [[appMenu itemWithTitle:@"Hide Others"] retain]; + showAllItem = [[appMenu itemWithTitle:@"Show All"] retain]; + + // Get the names in the nib to match the app name set by Qt. + const NSString *appName = reinterpret_cast<const NSString*>(QCFString::toCFStringRef(qt_mac_applicationName())); + [quitItem setTitle:[[quitItem title] stringByReplacingOccurrencesOfString:@"NewApplication" + withString:const_cast<NSString *>(appName)]]; + [hideItem setTitle:[[hideItem title] stringByReplacingOccurrencesOfString:@"NewApplication" + withString:const_cast<NSString *>(appName)]]; + [aboutItem setTitle:[[aboutItem title] stringByReplacingOccurrencesOfString:@"NewApplication" + withString:const_cast<NSString *>(appName)]]; + [appName release]; + // Disable the items that don't do anything. If someone associates a QAction with them + // They should get synced back in. + [preferencesItem setEnabled:NO]; + [preferencesItem setHidden:YES]; + [aboutItem setEnabled:NO]; + [aboutItem setHidden:YES]; +} + +- (void)ensureAppMenuInMenu:(NSMenu *)menu +{ + // The application menu is the menu in the menu bar that contains the + // 'Quit' item. When changing menu bar (e.g when switching between + // windows with different menu bars), we never recreate this menu, but + // instead pull it out the current menu bar and place into the new one: + NSMenu *mainMenu = [NSApp mainMenu]; + if ([NSApp mainMenu] == menu) + return; // nothing to do (menu is the current menu bar)! + +#ifndef QT_NAMESPACE + Q_ASSERT(mainMenu); +#endif + // Grab the app menu out of the current menu. + int numItems = [mainMenu numberOfItems]; + NSMenuItem *oldAppMenuItem = 0; + for (int i = 0; i < numItems; ++i) { + NSMenuItem *item = [mainMenu itemAtIndex:i]; + if ([item submenu] == appMenu) { + oldAppMenuItem = item; + [oldAppMenuItem retain]; + [mainMenu removeItemAtIndex:i]; + break; + } + } + + if (oldAppMenuItem) { + [oldAppMenuItem setSubmenu:nil]; + [oldAppMenuItem release]; + NSMenuItem *appMenuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" + action:nil keyEquivalent:@""]; + [appMenuItem setSubmenu:appMenu]; + [menu insertItem:appMenuItem atIndex:0]; + } +} + +- (void)removeActionsFromAppMenu +{ + for (NSMenuItem *item in [appMenu itemArray]) + [item setTag:nil]; +} + +- (void)dealloc +{ + [servicesItem release]; + [hideAllOthersItem release]; + [showAllItem release]; + + [lastAppSpecificItem release]; + [theMenu release]; + [appMenu release]; + [super dealloc]; +} + +- (NSMenu *)menu +{ + return [[theMenu retain] autorelease]; +} + +- (NSMenu *)applicationMenu +{ + return [[appMenu retain] autorelease]; +} + +- (NSMenuItem *)quitMenuItem +{ + return [[quitItem retain] autorelease]; +} + +- (NSMenuItem *)preferencesMenuItem +{ + return [[preferencesItem retain] autorelease]; +} + +- (NSMenuItem *)aboutMenuItem +{ + return [[aboutItem retain] autorelease]; +} + +- (NSMenuItem *)aboutQtMenuItem +{ + return [[aboutQtItem retain] autorelease]; +} + +- (NSMenuItem *)hideMenuItem +{ + return [[hideItem retain] autorelease]; +} + +- (NSMenuItem *)appSpecificMenuItem +{ + // Create an App-Specific menu item, insert it into the menu and return + // it as an autorelease item. + NSMenuItem *item = [[NSMenuItem alloc] init]; + + NSInteger location; + if (lastAppSpecificItem == nil) { + location = [appMenu indexOfItem:aboutQtItem]; + } else { + location = [appMenu indexOfItem:lastAppSpecificItem]; + [lastAppSpecificItem release]; + } + lastAppSpecificItem = item; // Keep track of this for later (i.e., don't release it) + [appMenu insertItem:item atIndex:location + 1]; + + return [[item retain] autorelease]; +} + +- (BOOL) acceptsFirstResponder +{ + return YES; +} + +- (void)terminate:(id)sender +{ + [NSApp terminate:sender]; +} + +- (void)orderFrontStandardAboutPanel:(id)sender +{ + [NSApp orderFrontStandardAboutPanel:sender]; +} + +- (void)hideOtherApplications:(id)sender +{ + [NSApp hideOtherApplications:sender]; +} + +- (void)unhideAllApplications:(id)sender +{ + [NSApp unhideAllApplications:sender]; +} + +- (void)hide:(id)sender +{ + [NSApp hide:sender]; +} + +- (void)qtUpdateMenubar +{ + QCocoaMenuBar::macUpdateMenuBarImmediatly(); +} + +- (void)qtTranslateApplicationMenu +{ + + qDebug() << "qtTranslateApplicationMenu"; + +#ifndef QT_NO_TRANSLATION + [servicesItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(0))]; + [hideItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(1).arg(qt_mac_applicationName()))]; + [hideAllOthersItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(2))]; + [showAllItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(3))]; + [preferencesItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(4))]; + [quitItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(5).arg(qt_mac_applicationName()))]; + [aboutItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(6).arg(qt_mac_applicationName()))]; +#endif +} + +- (IBAction)qtDispatcherToQAction:(id)sender +{ + // + //QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData); + NSMenuItem *item = static_cast<NSMenuItem *>(sender); + if (QAction *action = reinterpret_cast<QAction *>([item tag])) { + action->trigger(); + } else if (item == quitItem) { + // We got here because someone was once the quitItem, but it has been + // abandoned (e.g., the menubar was deleted). In the meantime, just do + // normal QApplication::quit(). + qApp->quit(); + } +} + + - (void)orderFrontCharacterPalette:(id)sender + { + [NSApp orderFrontCharacterPalette:sender]; + } +@end diff --git a/src/plugins/graphicssystems/meego/qmeegorasterpixmapdata.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index 10fa61c972..f8216d8e61 100644 --- a/src/plugins/graphicssystems/meego/qmeegorasterpixmapdata.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -39,17 +39,17 @@ ** ****************************************************************************/ -#ifndef MRASTERPIXMAPDATA_H -#define MRASTERPIXMAPDATA_H +#ifndef QCOCOANATIVEINTERFACE_H +#define QCOCOANATIVEINTERFACE_H -#include <private/qpixmap_raster_p.h> +#include <QtGui/QPlatformNativeInterface> -class QMeeGoRasterPixmapData : public QRasterPixmapData +class QWidget; + +class QCocoaNativeInterface : public QPlatformNativeInterface { public: - QMeeGoRasterPixmapData(); - QMeeGoRasterPixmapData(QPixmapData::PixelType t); - void copy(const QPixmapData *data, const QRect &rect); + void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); }; -#endif +#endif // QCOCOANATIVEINTERFACE_H diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystemplugin.cpp b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 493d14e962..c6aa0d39e6 100644 --- a/src/plugins/graphicssystems/meego/qmeegographicssystemplugin.cpp +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -39,20 +39,21 @@ ** ****************************************************************************/ -#include <QDebug> -#include "qmeegographicssystemplugin.h" -#include "qmeegographicssystem.h" +#include "qcocoanativeinterface.h" +#include "qcocoaglcontext.h" +#include "qcocoawindow.h" +#include <qbytearray.h> +#include <qwindow.h> +#include "qplatformwindow_qpa.h" +#include "qsurfaceformat.h" +#include "qplatformopenglcontext_qpa.h" +#include "qopenglcontext.h" +#include <qdebug.h> -QStringList QMeeGoGraphicsSystemPlugin::keys() const +void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { - QStringList list; - list << "meego"; - return list; + if (resourceString == "nsopenglcontext") { + return static_cast<QCocoaWindow *>(window->handle())->currentContext()->nsOpenGLContext(); + } + return 0; } - -QGraphicsSystem *QMeeGoGraphicsSystemPlugin::create(const QString&) -{ - return new QMeeGoGraphicsSystem; -} - -Q_EXPORT_PLUGIN2(meego, QMeeGoGraphicsSystemPlugin) diff --git a/src/plugins/platforms/cocoa/qcocoaresources.qrc b/src/plugins/platforms/cocoa/qcocoaresources.qrc new file mode 100644 index 0000000000..de50d397c6 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaresources.qrc @@ -0,0 +1,17 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/trolltech/mac/cursors"> +<file>images/copyarrowcursor.png</file> +<file>images/forbiddencursor.png</file> +<file>images/spincursor.png</file> +<file>images/waitcursor.png</file> +<file>images/pluscursor.png</file> +</qresource> +<qresource prefix="/trolltech/mac/style"> +<file>images/leopard-unified-toolbar-on.png</file> +</qresource> +<qresource prefix="/trolltech/mac/"> +<file>qt_menu.nib/classes.nib</file> +<file>qt_menu.nib/info.nib</file> +<file>qt_menu.nib/keyedobjects.nib</file> +</qresource> +</RCC> diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 9e7e68b7d2..ce79d3967f 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -45,28 +45,55 @@ #include <Cocoa/Cocoa.h> #include <QPlatformWindow> +#include <QRect> + +#include "qcocoaglcontext.h" +#include "qnsview.h" QT_BEGIN_NAMESPACE +@interface QNSWindow : NSWindow { + +} + +@end + class QCocoaWindow : public QPlatformWindow { public: - QCocoaWindow(QWidget *tlw); + QCocoaWindow(QWindow *tlw); ~QCocoaWindow(); void setGeometry(const QRect &rect); - void setVisible(bool visible); + void setWindowTitle(const QString &title); + void raise(); + void lower(); WId winId() const; - NSView *contentView() const; - void setContentView(NSView *contentView); + void windowDidMove(); void windowDidResize(); + void windowWillClose(); + + void setCurrentContext(QCocoaGLContext *context); + QCocoaGLContext *currentContext() const; + +protected: + void determineWindowClass(); + QNSWindow *createWindow(); + NSRect globalGeometry(const QRect localWindowGeometry) const; + QRect windowGeometry() const; + QCocoaWindow *parentCocoaWindow() const; private: - NSWindow *m_nsWindow; + friend class QCocoaBackingStore; + QNSWindow *m_nsWindow; + QNSView *m_contentView; + quint32 m_windowAttributes; + quint32 m_windowClass; + QCocoaGLContext *m_glContext; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index a2fdce3520..7e4d4217ef 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -41,54 +41,116 @@ #include "qcocoawindow.h" #include "qnswindowdelegate.h" #include "qcocoaautoreleasepool.h" +#include "qcocoaglcontext.h" +#include "qnsview.h" +#include <QtCore/private/qcore_mac_p.h> +#include <qwindow.h> +#include <QWindowSystemInterface> +#include <QPlatformScreen> -#include <QWidget> +#include <Cocoa/Cocoa.h> +#include <Carbon/Carbon.h> -#include <QtGui/QApplication> +#include <QDebug> -#include <QWindowSystemInterface> +@implementation QNSWindow -#include <QDebug> +- (BOOL)canBecomeKeyWindow +{ + return YES; +} + +- (BOOL)canBecomeMainWindow +{ + return YES; +} + +@end -QCocoaWindow::QCocoaWindow(QWidget *tlw) +QCocoaWindow::QCocoaWindow(QWindow *tlw) : QPlatformWindow(tlw) + , m_windowAttributes(0) + , m_windowClass(0) + , m_glContext(0) { QCocoaAutoReleasePool pool; - const QRect geo = tlw->geometry(); - NSRect frame = NSMakeRect(geo.x(), geo.y(), geo.width(), geo.height()); - m_nsWindow = [[NSWindow alloc] initWithContentRect:frame - styleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask - backing:NSBackingStoreBuffered - defer:YES]; + determineWindowClass(); + m_nsWindow = createWindow(); QNSWindowDelegate *delegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this]; [m_nsWindow setDelegate:delegate]; - - [m_nsWindow makeKeyAndOrderFront:nil]; [m_nsWindow setAcceptsMouseMovedEvents:YES]; + + // Prevent Cocoa from releasing the window on close. Qt + // handles the close event asynchronously and we want to + // make sure that m_nsWindow stays valid until the + // QCocoaWindow is deleted by Qt. + [m_nsWindow setReleasedWhenClosed : NO]; + + m_contentView = [[QNSView alloc] initWithQWindow:tlw]; + + setGeometry(tlw->geometry()); + + [m_nsWindow setContentView:m_contentView]; } QCocoaWindow::~QCocoaWindow() { + [m_nsWindow release]; } void QCocoaWindow::setGeometry(const QRect &rect) { QPlatformWindow::setGeometry(rect); - NSRect bounds = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); + NSRect bounds = globalGeometry(rect); [[m_nsWindow contentView]setFrameSize:bounds.size]; + [m_nsWindow setContentSize : bounds.size]; + [m_nsWindow setFrameOrigin : bounds.origin]; + + if (m_glContext) + m_glContext->update(); } void QCocoaWindow::setVisible(bool visible) { - Q_UNUSED(visible); + if (visible) { + // The parent window might have moved while this window was hidden, + // update the window geometry if there is a parent. + if (window()->transientParent()) + setGeometry(window()->geometry()); + + // Make sure the QWindow has a frame ready before we show the NSWindow. + QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRect(QPoint(), geometry().size())); + + [m_nsWindow makeKeyAndOrderFront:nil]; + } else { + [m_nsWindow orderOut:nil]; + } +} + +void QCocoaWindow::setWindowTitle(const QString &title) +{ + CFStringRef windowTitle = QCFString::toCFStringRef(title); + [m_nsWindow setTitle: const_cast<NSString *>(reinterpret_cast<const NSString *>(windowTitle))]; + CFRelease(windowTitle); +} + +void QCocoaWindow::raise() +{ + // ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm) + [m_nsWindow orderFront: m_nsWindow]; +} + +void QCocoaWindow::lower() +{ + [m_nsWindow orderFront: m_nsWindow]; } WId QCocoaWindow::winId() const { - return WId([m_nsWindow windowNumber]); + return WId(m_nsWindow); } NSView *QCocoaWindow::contentView() const @@ -96,15 +158,231 @@ NSView *QCocoaWindow::contentView() const return [m_nsWindow contentView]; } -void QCocoaWindow::setContentView(NSView *contentView) +void QCocoaWindow::windowDidMove() { - [m_nsWindow setContentView:contentView]; + if (m_glContext) + m_glContext->update(); } void QCocoaWindow::windowDidResize() { - //jlind: XXX This isn't ideal. Eventdispatcher does not run when resizing... + if (m_glContext) + m_glContext->update(); + NSRect rect = [[m_nsWindow contentView]frame]; QRect geo(rect.origin.x,rect.origin.y,rect.size.width,rect.size.height); - QWindowSystemInterface::handleGeometryChange(widget(),geo); + QWindowSystemInterface::handleSynchronousGeometryChange(window(), geo); +} + + +void QCocoaWindow::windowWillClose() +{ + QWindowSystemInterface::handleCloseEvent(window()); +} + +void QCocoaWindow::setCurrentContext(QCocoaGLContext *context) +{ + m_glContext = context; +} + +QCocoaGLContext *QCocoaWindow::currentContext() const +{ + return m_glContext; } + +/* + Determine the window class based on the window type and + window flags, and widget attr Sets m_windowAttributes + and m_windowClass. +*/ +void QCocoaWindow::determineWindowClass() +{ + Qt::WindowType type = window()->windowType(); + Qt::WindowFlags flags = window()->windowFlags(); + + const bool popup = (type == Qt::Popup); + + if (type == Qt::ToolTip || type == Qt::SplashScreen || popup) + flags |= Qt::FramelessWindowHint; + + m_windowClass = kSheetWindowClass; + + if (popup || type == Qt::SplashScreen) + m_windowClass = kModalWindowClass; + else if (type == Qt::ToolTip) + m_windowClass = kHelpWindowClass; + else if (type == Qt::Tool) + m_windowClass = kFloatingWindowClass; + else + m_windowClass = kDocumentWindowClass; + + m_windowAttributes = (kWindowCompositingAttribute | kWindowStandardHandlerAttribute); + +// if(qt_mac_is_macsheet(window())) { +// m_windowClass = kSheetWindowClass; +// } else + + { + // Shift things around a bit to get the correct window class based on the presence + // (or lack) of the border. + + bool customize = flags & Qt::CustomizeWindowHint; + bool framelessWindow = (flags & Qt::FramelessWindowHint || (customize && !(flags & Qt::WindowTitleHint))); + if (framelessWindow) { + if (m_windowClass == kDocumentWindowClass) { + m_windowAttributes |= kWindowNoTitleBarAttribute; + } else if (m_windowClass == kFloatingWindowClass) { + m_windowAttributes |= kWindowNoTitleBarAttribute; + } else if (m_windowClass == kMovableModalWindowClass) { + m_windowClass = kModalWindowClass; + } + } else { + m_windowAttributes |= NSTitledWindowMask; + if (m_windowClass != kModalWindowClass) + m_windowAttributes |= NSResizableWindowMask; + } + + // Only add extra decorations (well, buttons) for widgets that can have them + // and have an actual border we can put them on. + + if(m_windowClass != kModalWindowClass && m_windowClass != kMovableModalWindowClass + && m_windowClass != kSheetWindowClass && m_windowClass != kPlainWindowClass + && !framelessWindow && m_windowClass != kDrawerWindowClass + && m_windowClass != kHelpWindowClass) { + if (flags & Qt::WindowMinimizeButtonHint) + m_windowAttributes |= NSMiniaturizableWindowMask; + if (flags & Qt::WindowSystemMenuHint || flags & Qt::WindowCloseButtonHint) + m_windowAttributes |= NSClosableWindowMask; + } else { + // Clear these hints so that we aren't call them on invalid windows + flags &= ~(Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint + | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint); + } + + } + + if((popup || type == Qt::Tool) && !window()->isModal()) + m_windowAttributes |= kWindowHideOnSuspendAttribute; + m_windowAttributes |= kWindowLiveResizeAttribute; +} + +/* + +*/ +QNSWindow * QCocoaWindow::createWindow() +{ + // Determine if we need to add in our "custom window" attribute. Cocoa is rather clever + // in deciding if we need the maximize button or not (i.e., it's resizeable, so you + // must need a maximize button). So, the only buttons we have control over are the + // close and minimize buttons. If someone wants to customize and NOT have the maximize + // button, then we have to do our hack. We only do it for these cases because otherwise + // the window looks different when activated. This "QtMacCustomizeWindow" attribute is + // intruding on a public space and WILL BREAK in the future. + // One can hope that there is a more public API available by that time. +/* + Qt::WindowFlags flags = widget ? widget->windowFlags() : Qt::WindowFlags(0); + if ((flags & Qt::CustomizeWindowHint)) { + if ((flags & (Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint + | Qt::WindowMinimizeButtonHint | Qt::WindowTitleHint)) + && !(flags & Qt::WindowMaximizeButtonHint)) + wattr |= QtMacCustomizeWindow; + } +*/ + NSRect frame = globalGeometry(window()->geometry()); + QCocoaAutoReleasePool pool; + QNSWindow *window; + + switch (m_windowClass) { + case kMovableModalWindowClass: + case kModalWindowClass: + case kSheetWindowClass: + case kFloatingWindowClass: + case kOverlayWindowClass: + case kHelpWindowClass: { + NSPanel *panel; + + BOOL needFloating = NO; + BOOL worksWhenModal = (this->window()->windowType() == Qt::Popup); + + // Add in the extra flags if necessary. + switch (m_windowClass) { + case kSheetWindowClass: + m_windowAttributes |= NSDocModalWindowMask; + break; + case kFloatingWindowClass: + case kHelpWindowClass: + needFloating = YES; + m_windowAttributes |= NSUtilityWindowMask; + break; + default: + break; + } + + panel = [[NSPanel alloc] initWithContentRect:frame + styleMask:m_windowAttributes + backing:NSBackingStoreBuffered + defer:NO]; // see window case below +// ### crashes +// [panel setFloatingPanel:needFloating]; +// [panel setWorksWhenModal:worksWhenModal]; + window = static_cast<NSWindow *>(panel); + break; + } + default: + window = [[QNSWindow alloc] initWithContentRect:frame + styleMask:(NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask) + backing:NSBackingStoreBuffered + defer:NO]; // Deferring window creation breaks OpenGL (the GL context is set up + // before the window is shown and needs a proper window.). + break; + } + + //qt_syncCocoaTitleBarButtons(window, widget); + return window; +} + +// Calculate the global screen geometry for the given local geometry, which +// might be in the parent window coordinate system. +NSRect QCocoaWindow::globalGeometry(const QRect localGeometry) const +{ + QRect finalGeometry = localGeometry; + + if (QCocoaWindow *parent = parentCocoaWindow()) { + QRect parentGeometry = parent->windowGeometry(); + finalGeometry.adjust(parentGeometry.x(), parentGeometry.y(), parentGeometry.x(), parentGeometry.y()); + + // Qt child window geometry assumes that the origin is at the + // top-left of the content area of the parent window. The title + // bar is not a part of this contet area, but is still included + // in the NSWindow height. Move the child window down to acccount + // for this if the parent window has a title bar. + const int titlebarHeight = 22; + if (!(window()->windowFlags() & Qt::FramelessWindowHint)) + finalGeometry.adjust(0, titlebarHeight, 0, titlebarHeight); + } + + // The final "y invert" to get OS X global geometry: + QPlatformScreen *onScreen = QPlatformScreen::platformScreenForWindow(window()); + int flippedY = onScreen->geometry().height() - finalGeometry.y() - finalGeometry.height(); + return NSMakeRect(finalGeometry.x(), flippedY, finalGeometry.width(), finalGeometry.height()); +} + +// Returns the current global screen geometry for the nswindow accociated with this window. +QRect QCocoaWindow::windowGeometry() const +{ + NSRect rect = [m_nsWindow frame]; + QPlatformScreen *onScreen = QPlatformScreen::platformScreenForWindow(window()); + int flippedY = onScreen->geometry().height() - rect.origin.y - rect.size.height; // account for nswindow inverted y. + QRect qRect = QRect(rect.origin.x, flippedY, rect.size.width, rect.size.height); + return qRect; +} + +// Returns a pointer to the parent QCocoaWindow for this window, or 0 if there is none. +QCocoaWindow *QCocoaWindow::parentCocoaWindow() const +{ + if (window() && window()->transientParent()) { + return static_cast<QCocoaWindow*>(window()->transientParent()->handle()); + } + return 0; +} + diff --git a/src/plugins/platforms/cocoa/qmenu_mac.h b/src/plugins/platforms/cocoa/qmenu_mac.h new file mode 100644 index 0000000000..f20f82c761 --- /dev/null +++ b/src/plugins/platforms/cocoa/qmenu_mac.h @@ -0,0 +1,85 @@ + +#include <private/qt_mac_p.h> +#include <QtCore/qpointer.h> +#include <QtWidgets/qmenu.h> +#include <QtWidgets/qmenubar.h> +#include <QtWidgets/qplatformmenu_qpa.h> + +@class NSMenuItem; +class QCocoaMenuAction : public QPlatformMenuAction +{ +public: + QCocoaMenuAction(); + ~QCocoaMenuAction(); + + NSMenuItem *menuItem; + uchar ignore_accel : 1; + uchar merged : 1; + OSMenuRef menu; + QPointer<QMenu> qtMenu; +}; + +struct QMenuMergeItem +{ + inline QMenuMergeItem(NSMenuItem *c, QCocoaMenuAction *a) : menuItem(c), action(a) { } + NSMenuItem *menuItem; + QCocoaMenuAction *action; +}; +typedef QList<QMenuMergeItem> QMenuMergeList; + +class QCocoaMenu : public QPlatformMenu +{ +public: + QCocoaMenu(QMenu *qtMenu); + ~QCocoaMenu(); + + OSMenuRef macMenu(OSMenuRef merge = 0); + void syncSeparatorsCollapsible(bool collapse); + void setMenuEnabled(bool enable); + + void addAction(QAction *action, QAction *before); + void syncAction(QAction *action); + void removeAction(QAction *action); + + void addAction(QCocoaMenuAction *action, QCocoaMenuAction *before); + void syncAction(QCocoaMenuAction *action); + void removeAction(QCocoaMenuAction *action); + bool merged(const QAction *action) const; + QCocoaMenuAction *findAction(QAction *action) const; + + OSMenuRef menu; + static QHash<OSMenuRef, OSMenuRef> mergeMenuHash; + static QHash<OSMenuRef, QMenuMergeList*> mergeMenuItemsHash; + QList<QCocoaMenuAction*> actionItems; + QMenu *qtMenu; +}; + +class QCocoaMenuBar : public QPlatformMenuBar +{ +public: + QCocoaMenuBar(QMenuBar *qtMenuBar); + ~QCocoaMenuBar(); + + void handleReparent(QWidget *newParent); + + void addAction(QAction *action, QAction *before); + void syncAction(QAction *action); + void removeAction(QAction *action); + + void addAction(QCocoaMenuAction *action, QCocoaMenuAction *before); + void syncAction(QCocoaMenuAction *action); + void removeAction(QCocoaMenuAction *action); + + bool macWidgetHasNativeMenubar(QWidget *widget); + void macCreateMenuBar(QWidget *parent); + void macDestroyMenuBar(); + OSMenuRef macMenu(); + static bool macUpdateMenuBarImmediatly(); + static void macUpdateMenuBar(); + QCocoaMenuAction *findAction(QAction *action) const; + + OSMenuRef menu; + OSMenuRef apple_menu; + QList<QCocoaMenuAction*> actionItems; + QMenuBar *qtMenuBar; +}; diff --git a/src/plugins/platforms/cocoa/qmenu_mac.mm b/src/plugins/platforms/cocoa/qmenu_mac.mm new file mode 100644 index 0000000000..7ca546dd79 --- /dev/null +++ b/src/plugins/platforms/cocoa/qmenu_mac.mm @@ -0,0 +1,1274 @@ +/**************************************************************************** +** +** 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 QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmenu_mac.h" + +#include <Cocoa/Cocoa.h> + +#include "qmenu.h" +#include "qhash.h" +#include <qdebug.h> +#include "qapplication.h" +#include "qregexp.h" +#include "qtoolbar.h" +#include "qevent.h" +#include "qstyle.h" +#include "qwidgetaction.h" + +#include <private/qmenu_p.h> +#include <private/qmenubar_p.h> +#include <private/qguiapplication_p.h> + +#include "qcocoahelpers.h" +#include "qcocoaapplication.h" +#include "qcocoamenuloader.h" +#include "qcocoamenu.h" +#include "qcocoahelpers.h" +#include "qcocoaautoreleasepool.h" + +QT_BEGIN_NAMESPACE + +/***************************************************************************** + QMenu debug facilities + *****************************************************************************/ + +/***************************************************************************** + QMenu globals + *****************************************************************************/ +bool qt_mac_no_menubar_merge = false; +bool qt_mac_quit_menu_item_enabled = true; +int qt_mac_menus_open_count = 0; + +static OSMenuRef qt_mac_create_menu(QWidget *w); + +static struct { + QPointer<QMenuBar> qmenubar; + bool modal; +} qt_mac_current_menubar = { 0, false }; + + + + +/***************************************************************************** + Externals + *****************************************************************************/ +extern OSViewRef qt_mac_hiview_for(const QWidget *w); //qwidget_mac.cpp +extern IconRef qt_mac_create_iconref(const QPixmap &px); //qpixmap_mac.cpp +extern QWidget * mac_keyboard_grabber; //qwidget_mac.cpp +extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); //qapplication_xxx.cpp +RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp +void qt_mac_dispose_rgn(RgnHandle r); //qregion_mac.cpp + +/***************************************************************************** + QMenu utility functions + *****************************************************************************/ +bool qt_mac_watchingAboutToShow(QMenu *menu) +{ + return menu; /* && menu->receivers(SIGNAL(aboutToShow()));*/ +} + +static int qt_mac_CountMenuItems(OSMenuRef menu) +{ + if (menu) { + return [menu numberOfItems]; + } + return 0; +} + +void qt_mac_menu_collapseSeparators(NSMenu * theMenu, bool collapse) +{ + QCocoaAutoReleasePool pool; + OSMenuRef menu = static_cast<OSMenuRef>(theMenu); + if (collapse) { + bool previousIsSeparator = true; // setting to true kills all the separators placed at the top. + NSMenuItem *previousItem = nil; + + NSArray *itemArray = [menu itemArray]; + for (unsigned int i = 0; i < [itemArray count]; ++i) { + NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]); + if ([item isSeparatorItem]) { + [item setHidden:previousIsSeparator]; + } + + if (![item isHidden]) { + previousItem = item; + previousIsSeparator = ([previousItem isSeparatorItem]); + } + } + + // We now need to check the final item since we don't want any separators at the end of the list. + if (previousItem && previousIsSeparator) + [previousItem setHidden:YES]; + } else { + NSArray *itemArray = [menu itemArray]; + for (unsigned int i = 0; i < [itemArray count]; ++i) { + NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]); + if (QAction *action = reinterpret_cast<QAction *>([item tag])) + [item setHidden:!action->isVisible()]; + } + } +} + +#ifndef QT_NO_TRANSLATION +static const char *application_menu_strings[] = { + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Services"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide %1"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide Others"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Show All"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1") + }; + +QString qt_mac_applicationmenu_string(int type) +{ + QString menuString = QString::fromLatin1(application_menu_strings[type]); + QString translated = qApp->translate("QMenuBar", application_menu_strings[type]); + if (translated != menuString) + return translated; + else + return qApp->translate("MAC_APPLICATION_MENU", + application_menu_strings[type]); +} +#endif + + +static quint32 constructModifierMask(quint32 accel_key) +{ + quint32 ret = 0; + const bool dontSwap = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta); + if ((accel_key & Qt::CTRL) == Qt::CTRL) + ret |= (dontSwap ? NSControlKeyMask : NSCommandKeyMask); + if ((accel_key & Qt::META) == Qt::META) + ret |= (dontSwap ? NSCommandKeyMask : NSControlKeyMask); + if ((accel_key & Qt::ALT) == Qt::ALT) + ret |= NSAlternateKeyMask; + if ((accel_key & Qt::SHIFT) == Qt::SHIFT) + ret |= NSShiftKeyMask; + return ret; +} + +static void cancelAllMenuTracking() +{ + QCocoaAutoReleasePool pool; + NSMenu *mainMenu = [NSApp mainMenu]; + [mainMenu cancelTracking]; + for (NSMenuItem *item in [mainMenu itemArray]) { + if ([item submenu]) { + [[item submenu] cancelTracking]; + } + } +} + +static bool actualMenuItemVisibility(const QCocoaMenuBar *mbp, + const QCocoaMenuAction *action) +{ + bool visible = action->action->isVisible(); + if (visible && action->action->text() == QString(QChar(0x14))) + return false; + + if (visible && action->action->menu() && !action->action->menu()->actions().isEmpty() && +/* ### !qt_mac_CountMenuItems(cocoaMenu->macMenu(mbp->apple_menu)) &&*/ + !qt_mac_watchingAboutToShow(action->action->menu())) { + return false; + } + return visible; +} + +static inline void syncNSMenuItemVisiblity(NSMenuItem *menuItem, bool actionVisibility) +{ + [menuItem setHidden:NO]; + [menuItem setHidden:YES]; + [menuItem setHidden:!actionVisibility]; +} + +static inline void syncNSMenuItemEnabled(NSMenuItem *menuItem, bool enabled) +{ + [menuItem setEnabled:NO]; + [menuItem setEnabled:YES]; + [menuItem setEnabled:enabled]; +} + +static inline void syncMenuBarItemsVisiblity(const QCocoaMenuBar *mac_menubar) +{ + const QList<QCocoaMenuAction *> &menubarActions = mac_menubar->actionItems; + for (int i = 0; i < menubarActions.size(); ++i) { + const QCocoaMenuAction *action = menubarActions.at(i); + syncNSMenuItemVisiblity(action->menuItem, actualMenuItemVisibility(mac_menubar, action)); + } +} + +static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() +{ + return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; +} + +static NSMenuItem *createNSMenuItem(const QString &title) +{ + NSMenuItem *item = [[NSMenuItem alloc] + initWithTitle:qt_mac_QStringToNSString(title) + action:@selector(qtDispatcherToQAction:) keyEquivalent:@""]; + [item setTarget:nil]; + return item; +} + +// helper that recurses into a menu structure and en/dis-ables them +void qt_mac_set_modal_state_helper_recursive(OSMenuRef menu, OSMenuRef merge, bool on) +{ + bool modalWindowOnScreen = qApp->activeModalWidget() != 0; + for (NSMenuItem *item in [menu itemArray]) { + OSMenuRef submenu = [item submenu]; + if (submenu != merge) { + if (submenu) + qt_mac_set_modal_state_helper_recursive(submenu, merge, on); + if (!on) { + // The item should follow what the QAction has. + if ([item tag]) { + QAction *action = reinterpret_cast<QAction *>([item tag]); + syncNSMenuItemEnabled(item, action->isEnabled()); + } else { + syncNSMenuItemEnabled(item, YES); + } + // We sneak in some extra code here to handle a menu problem: + // If there is no window on screen, we cannot set 'nil' as + // menu item target, because then cocoa will disable the item + // (guess it assumes that there will be no first responder to + // catch the trigger anyway?) OTOH, If we have a modal window, + // then setting the menu loader as target will make cocoa not + // deliver the trigger because the loader is then seen as modally + // shaddowed). So either way there are shortcomings. Instead, we + // decide the target as late as possible: + [item setTarget:modalWindowOnScreen ? nil : getMenuLoader()]; + } else { + syncNSMenuItemEnabled(item, NO); + } + } + } +} + +//toggling of modal state +static void qt_mac_set_modal_state(OSMenuRef menu, bool on) +{ + OSMenuRef merge = QCocoaMenu::mergeMenuHash.value(menu); + qt_mac_set_modal_state_helper_recursive(menu, merge, on); + // I'm ignoring the special items now, since they should get handled via a syncAction() +} + +bool qt_mac_menubar_is_open() +{ + return qt_mac_menus_open_count > 0; +} + +QCocoaMenuAction::~QCocoaMenuAction() +{ + [menu release]; + // Update the menu item if this action still owns it. For some items + // (like 'Quit') ownership will be transferred between all menu bars... + if (action && action.data() == reinterpret_cast<QAction *>([menuItem tag])) { + QAction::MenuRole role = action->menuRole(); + // Check if the item is owned by Qt, and should be hidden to keep it from causing + // problems. Do it for everything but the quit menu item since that should always + // be visible. + if (role > QAction::ApplicationSpecificRole && role < QAction::QuitRole) { + [menuItem setHidden:YES]; + } else if (role == QAction::TextHeuristicRole + && menuItem != [getMenuLoader() quitMenuItem]) { + [menuItem setHidden:YES]; + } + [menuItem setTag:nil]; + } + [menuItem release]; +} + +static NSMenuItem *qt_mac_menu_merge_action(OSMenuRef merge, QCocoaMenuAction *action) +{ + if (qt_mac_no_menubar_merge || action->action->menu() || action->action->isSeparator() + || action->action->menuRole() == QAction::NoRole) + return 0; + + QString t = qt_mac_removeMnemonics(action->action->text().toLower()); + int st = t.lastIndexOf(QLatin1Char('\t')); + if (st != -1) + t.remove(st, t.length()-st); + t.replace(QRegExp(QString::fromLatin1("\\.*$")), QLatin1String("")); //no ellipses + //now the fun part + NSMenuItem *ret = 0; + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + + switch (action->action->menuRole()) { + case QAction::NoRole: + ret = 0; + break; + case QAction::ApplicationSpecificRole: + ret = [loader appSpecificMenuItem]; + break; + case QAction::AboutRole: + ret = [loader aboutMenuItem]; + break; + case QAction::AboutQtRole: + ret = [loader aboutQtMenuItem]; + break; + case QAction::QuitRole: + ret = [loader quitMenuItem]; + break; + case QAction::PreferencesRole: + ret = [loader preferencesMenuItem]; + break; + case QAction::TextHeuristicRole: { + QString aboutString = QMenuBar::tr("About").toLower(); + if (t.startsWith(aboutString) || t.endsWith(aboutString)) { + if (t.indexOf(QRegExp(QString::fromLatin1("qt$"), Qt::CaseInsensitive)) == -1) { + ret = [loader aboutMenuItem]; + } else { + ret = [loader aboutQtMenuItem]; + } + } else if (t.startsWith(QMenuBar::tr("Config").toLower()) + || t.startsWith(QMenuBar::tr("Preference").toLower()) + || t.startsWith(QMenuBar::tr("Options").toLower()) + || t.startsWith(QMenuBar::tr("Setting").toLower()) + || t.startsWith(QMenuBar::tr("Setup").toLower())) { + ret = [loader preferencesMenuItem]; + } else if (t.startsWith(QMenuBar::tr("Quit").toLower()) + || t.startsWith(QMenuBar::tr("Exit").toLower())) { + ret = [loader quitMenuItem]; + } + } + break; + } + + if (QMenuMergeList *list = QCocoaMenu::mergeMenuItemsHash.value(merge)) { + for(int i = 0; i < list->size(); ++i) { + const QMenuMergeItem &item = list->at(i); + if (item.menuItem == ret && item.action) + return 0; + } + } + + return ret; +} + +static QString qt_mac_menu_merge_text(QCocoaMenuAction *action) +{ + QString ret; + extern QString qt_mac_applicationmenu_string(int type); + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + if (action->action->menuRole() == QAction::ApplicationSpecificRole) + ret = action->action->text(); + else if (action->menuItem == [loader aboutMenuItem]) { + ret = qt_mac_applicationmenu_string(6).arg(qt_mac_applicationName()); + } else if (action->menuItem == [loader aboutQtMenuItem]) { + if (action->action->text() == QString("About Qt")) + ret = QMenuBar::tr("About Qt"); + else + ret = action->action->text(); + } else if (action->menuItem == [loader preferencesMenuItem]) { + ret = qt_mac_applicationmenu_string(4); + } else if (action->menuItem == [loader quitMenuItem]) { + ret = qt_mac_applicationmenu_string(5).arg(qt_mac_applicationName()); + } + return ret; +} + +static QKeySequence qt_mac_menu_merge_accel(QCocoaMenuAction *action) +{ + QKeySequence ret; + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + if (action->action->menuRole() == QAction::ApplicationSpecificRole) + ret = action->action->shortcut(); + else if (action->menuItem == [loader preferencesMenuItem]) + ret = QKeySequence(QKeySequence::Preferences); + else if (action->menuItem == [loader quitMenuItem]) + ret = QKeySequence(QKeySequence::Quit); + return ret; +} + +void Q_WIDGETS_EXPORT qt_mac_set_menubar_icons(bool b) +{ QApplication::instance()->setAttribute(Qt::AA_DontShowIconsInMenus, !b); } +void Q_WIDGETS_EXPORT qt_mac_set_native_menubar(bool b) +{ QApplication::instance()->setAttribute(Qt::AA_DontUseNativeMenuBar, !b); } +void Q_WIDGETS_EXPORT qt_mac_set_menubar_merge(bool b) { qt_mac_no_menubar_merge = !b; } + +/***************************************************************************** + QMenu bindings + *****************************************************************************/ + +QCocoaMenuAction::QCocoaMenuAction() + : menuItem(0) + , ignore_accel(0), merged(0), menu(0) +{ + +} + +QCocoaMenu::QCocoaMenu(QMenu *a_qtMenu) : menu(0), qtMenu(a_qtMenu) +{ +} + +QCocoaMenu::~QCocoaMenu() +{ + QCocoaAutoReleasePool pool; + while (actionItems.size()) { + QCocoaMenuAction *action = static_cast<QCocoaMenuAction *>(actionItems.takeFirst()); + if (QMenuMergeList *list = mergeMenuItemsHash.value(action->menu)) { + int i = 0; + while (i < list->size()) { + const QMenuMergeItem &item = list->at(i); + if (item.action == action) + list->removeAt(i); + else + ++i; + } + } + delete action; + } + mergeMenuHash.remove(menu); + mergeMenuItemsHash.remove(menu); + [menu release]; +} + + +void QCocoaMenu::addAction(QAction *a, QAction *before) +{ + QCocoaMenuAction *action = new QCocoaMenuAction; + action->action = a; + action->ignore_accel = 0; + action->merged = 0; + action->menu = 0; + + QCocoaMenuAction *cocoaBefore = findAction(before); + addAction(action, cocoaBefore); +} + + +void QCocoaMenu::addAction(QCocoaMenuAction *action, QCocoaMenuAction *before) +{ + QCocoaAutoReleasePool pool; + if (!action) + return; + int before_index = actionItems.indexOf(before); + if (before_index < 0) { + before = 0; + before_index = actionItems.size(); + } + actionItems.insert(before_index, action); + + [menu retain]; + [action->menu release]; + action->menu = menu; + + /* When the action is considered a mergable action it + will stay that way, until removed.. */ + if (!qt_mac_no_menubar_merge) { + OSMenuRef merge = QCocoaMenu::mergeMenuHash.value(menu); + if (merge) { + if (NSMenuItem *cmd = qt_mac_menu_merge_action(merge, action)) { + action->merged = 1; + [merge retain]; + [action->menu release]; + action->menu = merge; + [cmd retain]; + [cmd setAction:@selector(qtDispatcherToQAction:)]; + [cmd setTarget:nil]; + [action->menuItem release]; + action->menuItem = cmd; + QMenuMergeList *list = QCocoaMenu::mergeMenuItemsHash.value(merge); + if (!list) { + list = new QMenuMergeList; + QCocoaMenu::mergeMenuItemsHash.insert(merge, list); + } + list->append(QMenuMergeItem(cmd, action)); + } + } + } + + NSMenuItem *newItem = action->menuItem; + if (newItem == 0) { + newItem = createNSMenuItem(action->action->text()); + action->menuItem = newItem; + if (before) { + [menu insertItem:newItem atIndex:qMax(before_index, 0)]; + } else { + [menu addItem:newItem]; + } + } else { + [newItem setEnabled:YES]; + // ### + //[newItem setEnabled:!QApplicationPrivate::modalState()]; + + } + [newItem setTag:long(static_cast<QAction *>(action->action))]; + syncAction(action); +} + +void QCocoaMenu::syncAction(QAction *a) +{ + syncAction(findAction(a)); +} + +void QCocoaMenu::removeAction(QAction *a) +{ + removeAction(findAction(a)); +} + +QCocoaMenuAction *QCocoaMenu::findAction(QAction *action) const +{ + for (int i = 0; i < actionItems.size(); i++) { + QCocoaMenuAction *act = actionItems[i]; + if (action == act->action) + return act; + } + return 0; +} + + +// return an autoreleased string given a QKeySequence (currently only looks at the first one). +NSString *keySequenceToKeyEqivalent(const QKeySequence &accel) +{ + quint32 accel_key = (accel[0] & ~(Qt::MODIFIER_MASK | Qt::UNICODE_ACCEL)); + QChar cocoa_key = qt_mac_qtKey2CocoaKey(Qt::Key(accel_key)); + if (cocoa_key.isNull()) + cocoa_key = QChar(accel_key).toLower().unicode(); + return [NSString stringWithCharacters:&cocoa_key.unicode() length:1]; +} + +// return the cocoa modifier mask for the QKeySequence (currently only looks at the first one). +NSUInteger keySequenceModifierMask(const QKeySequence &accel) +{ + return constructModifierMask(accel[0]); +} + +void QCocoaMenu::syncAction(QCocoaMenuAction *action) +{ + if (!action) + return; + + NSMenuItem *item = action->menuItem; + if (!item) + return; + + QCocoaAutoReleasePool pool; + NSMenu *menu = [item menu]; + bool actionVisible = action->action->isVisible(); + [item setHidden:!actionVisible]; + if (!actionVisible) + return; + + int itemIndex = [menu indexOfItem:item]; + Q_ASSERT(itemIndex != -1); + if (action->action->isSeparator()) { + action->menuItem = [NSMenuItem separatorItem]; + [action->menuItem retain]; + [menu insertItem: action->menuItem atIndex:itemIndex]; + [menu removeItem:item]; + [item release]; + item = action->menuItem; + return; + } else if ([item isSeparatorItem]) { + // I'm no longer a separator... + action->menuItem = createNSMenuItem(action->action->text()); + [menu insertItem:action->menuItem atIndex:itemIndex]; + [menu removeItem:item]; + [item release]; + item = action->menuItem; + } + + //find text (and accel) + action->ignore_accel = 0; + QString text = action->action->text(); + QKeySequence accel = action->action->shortcut(); + { + int st = text.lastIndexOf(QLatin1Char('\t')); + if (st != -1) { + action->ignore_accel = 1; + accel = QKeySequence(text.right(text.length()-(st+1))); + text.remove(st, text.length()-st); + } + } + { + QString cmd_text = qt_mac_menu_merge_text(action); + if (!cmd_text.isEmpty()) { + text = cmd_text; + accel = qt_mac_menu_merge_accel(action); + } + } + // Show multiple key sequences as part of the menu text. + if (accel.count() > 1) + text += QLatin1String(" (") + accel.toString(QKeySequence::NativeText) + QLatin1String(")"); + +#if 0 + QString finalString = qt_mac_removeMnemonics(text); +#else + QString finalString = qt_mac_removeMnemonics(text); +#endif + // Cocoa Font and title + if (action->action->font().resolve()) { + const QFont &actionFont = action->action->font(); + NSFont *customMenuFont = [NSFont fontWithName:qt_mac_QStringToNSString(actionFont.family()) + size:actionFont.pointSize()]; + NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil]; + NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil]; + NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; + NSAttributedString *str = [[[NSAttributedString alloc] initWithString:qt_mac_QStringToNSString(finalString) + attributes:attributes] autorelease]; + [item setAttributedTitle: str]; + } else { + [item setTitle: qt_mac_QStringToNSString(finalString)]; + } + + if (action->action->menuRole() == QAction::AboutRole || action->action->menuRole() == QAction::QuitRole) + [item setTitle:qt_mac_QStringToNSString(text)]; + else + [item setTitle:qt_mac_QStringToNSString(qt_mac_removeMnemonics(text))]; + + // Cocoa Enabled + [item setEnabled: action->action->isEnabled()]; + + // Cocoa icon + NSImage *nsimage = 0; + if (!action->action->icon().isNull() && action->action->isIconVisibleInMenu()) { + nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(action->action->icon().pixmap(16, QIcon::Normal))); + } + [item setImage:nsimage]; + [nsimage release]; + + if (action->action->menu()) { //submenu + QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(action->action->menu()->platformMenu()); + NSMenu *subMenu = cocoaMenu->macMenu(); + if ([subMenu supermenu] && [subMenu supermenu] != [item menu]) { + // The menu is already a sub-menu of another one. Cocoa will throw an exception, + // in such cases. For the time being, a new QMenu with same set of actions is the + // only workaround. + action->action->setEnabled(false); + } else { + [item setSubmenu:subMenu]; + } + } else { //respect some other items + [item setSubmenu:0]; + // No key equivalent set for multiple key QKeySequence. + if (accel.count() == 1) { + [item setKeyEquivalent:keySequenceToKeyEqivalent(accel)]; + [item setKeyEquivalentModifierMask:keySequenceModifierMask(accel)]; + } else { + [item setKeyEquivalent:@""]; + [item setKeyEquivalentModifierMask:NSCommandKeyMask]; + } + } + //mark glyph + [item setState:action->action->isChecked() ? NSOnState : NSOffState]; +} + +void QCocoaMenu::removeAction(QCocoaMenuAction *action) +{ + if (!action) + return; + QCocoaAutoReleasePool pool; + if (action->merged) { + if (reinterpret_cast<QAction *>([action->menuItem tag]) == action->action) { + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + [action->menuItem setEnabled:false]; + if (action->menuItem != [loader quitMenuItem] + && action->menuItem != [loader preferencesMenuItem]) { + [[action->menuItem menu] removeItem:action->menuItem]; + } + } + } else { + [[action->menuItem menu] removeItem:action->menuItem]; + } + actionItems.removeAll(action); +} + +OSMenuRef QCocoaMenu::macMenu(OSMenuRef merge) +{ + if (menu) + return menu; + menu = qt_mac_create_menu(qtMenu); + if (merge) { + mergeMenuHash.insert(menu, merge); + } + QList<QAction*> items = qtMenu->actions(); + for(int i = 0; i < items.count(); i++) + addAction(items[i], 0); + syncSeparatorsCollapsible(qtMenu->separatorsCollapsible()); + return menu; +} + +/*! + \internal +*/ +void +QCocoaMenu::syncSeparatorsCollapsible(bool collapse) +{ + qt_mac_menu_collapseSeparators(menu, collapse); +} + +/*! + \internal +*/ +void QCocoaMenu::setMenuEnabled(bool enable) +{ + QCocoaAutoReleasePool pool; + if (enable) { + for (int i = 0; i < actionItems.count(); ++i) { + QCocoaMenuAction *menuItem = static_cast<QCocoaMenuAction *>(actionItems.at(i)); + if (menuItem && menuItem->action && menuItem->action->isEnabled()) { + [menuItem->menuItem setEnabled:true]; + } + } + } else { + NSMenu *menu = menu; + for (NSMenuItem *item in [menu itemArray]) { + [item setEnabled:false]; + } + } +} + +/*! + \internal + + This function will return the OSMenuRef used to create the native menu bar + bindings. + + If Qt is built against Carbon, the OSMenuRef is a MenuRef that can be used + with Carbon's Menu Manager API. + + If Qt is built against Cocoa, the OSMenuRef is a NSMenu pointer. + + \warning This function is not portable. + + \sa QMenuBar::macMenu() +*/ +/// OSMenuRef QMenu::macMenu(OSMenuRef merge) { return d_func()->macMenu(merge); } + +/***************************************************************************** + QMenuBar bindings + *****************************************************************************/ +typedef QHash<QWidget *, QMenuBar *> MenuBarHash; +Q_GLOBAL_STATIC(MenuBarHash, menubars) +static QMenuBar *fallback = 0; + +QCocoaMenuBar::QCocoaMenuBar(QMenuBar *a_qtMenuBar) : menu(0), apple_menu(0), qtMenuBar(a_qtMenuBar) +{ + macCreateMenuBar(qtMenuBar->parentWidget()); +} + +QCocoaMenuBar::~QCocoaMenuBar() +{ + for(QList<QCocoaMenuAction*>::Iterator it = actionItems.begin(); it != actionItems.end(); ++it) + delete (*it); + [apple_menu release]; + [menu release]; +} +void QCocoaMenuBar::handleReparent(QWidget *newParent) +{ + if (macWidgetHasNativeMenubar(newParent)) { + // If the new parent got a native menubar from before, keep that + // menubar rather than replace it with this one (because a parents + // menubar has precedence over children menubars). + macDestroyMenuBar(); + macCreateMenuBar(newParent); + } + +} + +void QCocoaMenuBar::addAction(QAction *action, QAction *beforeAction) +{ + if (action->isSeparator() || !menu) + return; + QCocoaMenuAction *cocoaAction = new QCocoaMenuAction; + cocoaAction->action = action; + cocoaAction->ignore_accel = 1; + QCocoaMenuAction *cocoaBeforeAction = findAction(beforeAction); + addAction(cocoaAction, cocoaBeforeAction); +} + +void QCocoaMenuBar::addAction(QCocoaMenuAction *action, QCocoaMenuAction *before) +{ + if (!action || !menu) + return; + + int before_index = actionItems.indexOf(before); + if (before_index < 0) { + before = 0; + before_index = actionItems.size(); + } + actionItems.insert(before_index, action); + + MenuItemIndex index = actionItems.size()-1; + + action->menu = menu; + QCocoaAutoReleasePool pool; + [action->menu retain]; + NSMenuItem *newItem = createNSMenuItem(action->action->text()); + action->menuItem = newItem; + + if (before) { + [menu insertItem:newItem atIndex:qMax(1, before_index + 1)]; + index = before_index; + } else { + [menu addItem:newItem]; + } + [newItem setTag:long(static_cast<QAction *>(action->action))]; + syncAction(action); +} + + +void QCocoaMenuBar::syncAction(QCocoaMenuAction *action) +{ + if (!action || !menu) + return; + + QCocoaAutoReleasePool pool; + NSMenuItem *item = action->menuItem; + + OSMenuRef submenu = 0; + bool release_submenu = false; + if (action->action->menu()) { + QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(action->action->menu()->platformMenu()); + if (!cocoaMenu) { + + } + + if ((submenu = cocoaMenu->macMenu(apple_menu))) { + if ([submenu supermenu] && [submenu supermenu] != [item menu]) + return; + else + [item setSubmenu:submenu]; + } + } + + if (submenu) { + bool visible = actualMenuItemVisibility(this, action); + [item setSubmenu: submenu]; + [submenu setTitle:qt_mac_QStringToNSString(qt_mac_removeMnemonics(action->action->text()))]; + syncNSMenuItemVisiblity(item, visible); + if (release_submenu) { //no pointers to it + [submenu release]; + } + } else { + qWarning("QMenu: No OSMenuRef created for popup menu"); + } +} + + +void QCocoaMenuBar::removeAction(QCocoaMenuAction *action) +{ + if (!action || !menu) + return; + QCocoaAutoReleasePool pool; + [action->menu removeItem:action->menuItem]; + actionItems.removeAll(action); +} + +void QCocoaMenuBar::syncAction(QAction *a) +{ + syncAction(findAction(a)); +} + +void QCocoaMenuBar::removeAction(QAction *a) +{ + removeAction(findAction(a)); +} + +QCocoaMenuAction *QCocoaMenuBar::findAction(QAction *action) const +{ + for (int i = 0; i < actionItems.size(); i++) { + QCocoaMenuAction *act = actionItems[i]; + if (action == act->action) + return act; + } + return 0; +} + +bool QCocoaMenuBar::macWidgetHasNativeMenubar(QWidget *widget) +{ + // This function is different from q->isNativeMenuBar(), as + // it returns true only if a native menu bar is actually + // _created_. + if (!widget) + return false; + return menubars()->contains(widget->window()); +} + +void QCocoaMenuBar::macCreateMenuBar(QWidget *parent) +{ + static int dontUseNativeMenuBar = -1; + // We call the isNativeMenuBar function here + // because that will make sure that local overrides + // are dealt with correctly. q->isNativeMenuBar() will, if not + // overridden, depend on the attribute Qt::AA_DontUseNativeMenuBar: + bool qt_mac_no_native_menubar = !qtMenuBar->isNativeMenuBar(); + if (qt_mac_no_native_menubar == false && dontUseNativeMenuBar < 0) { + // The menubar is set to be native. Let's check (one time only + // for all menubars) if this is OK with the rest of the environment. + // As a result, Qt::AA_DontUseNativeMenuBar is set. NB: the application + // might still choose to not respect, or change, this flag. + bool isPlugin = QApplication::testAttribute(Qt::AA_MacPluginApplication); + bool environmentSaysNo = !qgetenv("QT_MAC_NO_NATIVE_MENUBAR").isEmpty(); + dontUseNativeMenuBar = isPlugin || environmentSaysNo; + QApplication::instance()->setAttribute(Qt::AA_DontUseNativeMenuBar, dontUseNativeMenuBar); + qt_mac_no_native_menubar = !qtMenuBar->isNativeMenuBar(); + } + if (qt_mac_no_native_menubar == false) { + // INVARIANT: Use native menubar. + macUpdateMenuBar(); + if (!parent && !fallback) { + fallback = qtMenuBar; + } else if (parent && parent->isWindow()) { + menubars()->insert(qtMenuBar->window(), qtMenuBar); + } + } +} + +void QCocoaMenuBar::macDestroyMenuBar() +{ + QCocoaAutoReleasePool pool; + if (fallback == qtMenuBar) + fallback = 0; + QWidget *tlw = qtMenuBar->window(); + menubars()->remove(tlw); + + if (!qt_mac_current_menubar.qmenubar || qt_mac_current_menubar.qmenubar == qtMenuBar) { + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + [loader removeActionsFromAppMenu]; + QCocoaMenuBar::macUpdateMenuBar(); + } +} + +OSMenuRef QCocoaMenuBar::macMenu() +{ + if (!qtMenuBar->isNativeMenuBar()) { + return 0; + } else if (!menu) { + menu = qt_mac_create_menu(qtMenuBar); + ProcessSerialNumber mine, front; + if (GetCurrentProcess(&mine) == noErr && GetFrontProcess(&front) == noErr) { + if (!qt_mac_no_menubar_merge && !apple_menu) { + apple_menu = qt_mac_create_menu(qtMenuBar); + [apple_menu setTitle:qt_mac_QStringToNSString(QString(QChar(0x14)))]; + NSMenuItem *apple_menuItem = [[NSMenuItem alloc] init]; + [apple_menuItem setSubmenu:menu]; + [apple_menu addItem:apple_menuItem]; + [apple_menuItem release]; + } + if (apple_menu) { + QCocoaMenu::mergeMenuHash.insert(menu, apple_menu); + } + QList<QAction*> items = qtMenuBar->actions(); + for(int i = 0; i < items.count(); i++) + addAction(items[i], 0); + } + } + return menu; +} + +/*! + \internal + + This function will return the OSMenuRef used to create the native menu bar + bindings. This OSMenuRef is then set as the root menu for the Menu + Manager. + + \warning This function is not portable. + + \sa QMenu::macMenu() +*/ +//OSMenuRef QMenuBar::macMenu() { return d_func()->macMenu(); } + +/* ! + \internal + Ancestor function that crosses windows (QWidget::isAncestorOf + only considers widgets within the same window). +*/ +static bool qt_mac_is_ancestor(QWidget* possibleAncestor, QWidget *child) +{ + if (!possibleAncestor) + return false; + + QWidget * current = child->parentWidget(); + while (current != 0) { + if (current == possibleAncestor) + return true; + current = current->parentWidget(); + } + return false; +} + +/* ! + \internal + Returns true if the entries of menuBar should be disabled, + based on the modality type of modalWidget. +*/ +static bool qt_mac_should_disable_menu(QMenuBar *menuBar) +{ + QWidget *modalWidget = qApp->activeModalWidget(); + if (!modalWidget) + return false; + + if (menuBar && menuBar == menubars()->value(modalWidget)) + // The menu bar is owned by the modal widget. + // In that case we should enable it: + return false; + + // When there is an application modal window on screen, the entries of + // the menubar should be disabled. The exception in Qt is that if the + // modal window is the only window on screen, then we enable the menu bar. + QWidget *w = modalWidget; + QWidgetList topLevelWidgets = QApplication::topLevelWidgets(); + while (w) { + if (w->isVisible() && w->windowModality() == Qt::ApplicationModal) { + for (int i=0; i<topLevelWidgets.size(); ++i) { + QWidget *top = topLevelWidgets.at(i); + if (w != top && top->isVisible()) { + // INVARIANT: we found another visible window + // on screen other than our modalWidget. We therefore + // disable the menu bar to follow normal modality logic: + return true; + } + } + // INVARIANT: We have only one window on screen that happends + // to be application modal. We choose to enable the menu bar + // in that case to e.g. enable the quit menu item. + return false; + } + w = w->parentWidget(); + } + + // INVARIANT: modalWidget is window modal. Disable menu entries + // if the menu bar belongs to an ancestor of modalWidget. If menuBar + // is nil, we understand it as the default menu bar set by the nib: + return menuBar ? qt_mac_is_ancestor(menuBar->parentWidget(), modalWidget) : false; +} + +static QWidget *findWindowThatShouldDisplayMenubar() +{ + QWidget *w = qApp->activeWindow(); + + if (!w) { + // We have no active window on screen. Try to + // find a window from the list of top levels: + QWidgetList tlws = QApplication::topLevelWidgets(); + for(int i = 0; i < tlws.size(); ++i) { + QWidget *tlw = tlws.at(i); + if ((tlw->isVisible() && tlw->windowType() != Qt::Tool && + tlw->windowType() != Qt::Popup)) { + w = tlw; + break; + } + } + } + + return w; +} + +static QMenuBar *findMenubarForWindow(QWidget *w) +{ + QMenuBar *mb = 0; + if (w) { + mb = menubars()->value(w); + +#if 0 +// ### +//#ifndef QT_NO_MAINWINDOW + QDockWidget *dw = qobject_cast<QDockWidget *>(w); + if (!mb && dw) { + QMainWindow *mw = qobject_cast<QMainWindow *>(dw->parentWidget()); + if (mw && (mb = menubars()->value(mw))) + w = mw; + } +#endif + while(w && !mb) + mb = menubars()->value((w = w->parentWidget())); + } + + if (!mb) { + // We could not find a menu bar for the window. Lets + // check if we have a global (parentless) menu bar instead: + mb = fallback; + } + + return mb; +} + +void qt_mac_clear_menubar() +{ + if (QApplication::testAttribute(Qt::AA_MacPluginApplication)) + return; + + QCocoaAutoReleasePool pool; + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + NSMenu *menu = [loader menu]; + [loader ensureAppMenuInMenu:menu]; + [NSApp setMainMenu:menu]; + const bool modal = qt_mac_should_disable_menu(0); + if (qt_mac_current_menubar.qmenubar || modal != qt_mac_current_menubar.modal) + qt_mac_set_modal_state(menu, modal); + qt_mac_current_menubar.qmenubar = 0; + qt_mac_current_menubar.modal = modal; +} + +/*! + \internal + + This function will update the current menu bar and set it as the + active menu bar in the Menu Manager. + + \warning This function is not portable. +*/ +void QCocoaMenuBar::macUpdateMenuBar() +{ + [getMenuLoader() performSelectorOnMainThread: @selector(qtUpdateMenubar) withObject: nil waitUntilDone: NO]; +} + +bool QCocoaMenuBar::macUpdateMenuBarImmediatly() +{ + bool ret = false; + cancelAllMenuTracking(); + QWidget *w = findWindowThatShouldDisplayMenubar(); + QMenuBar *mb = findMenubarForWindow(w); + + // ### extern bool qt_mac_app_fullscreen; //qapplication_mac.mm + bool qt_mac_app_fullscreen = false; + // We need to see if we are in full screen mode, if so we need to + // switch the full screen mode to be able to show or hide the menubar. + if(w && mb) { + // This case means we are creating a menubar, check if full screen + if(w->isFullScreen()) { + // Ok, switch to showing the menubar when hovering over it. + SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar); + qt_mac_app_fullscreen = true; + } + } else if(w) { + // Removing a menubar + if(w->isFullScreen()) { + // Ok, switch to not showing the menubar when hovering on it + SetSystemUIMode(kUIModeAllHidden, 0); + qt_mac_app_fullscreen = true; + } + } + + if (mb && mb->isNativeMenuBar()) { + + // ### + bool modal = false; + //bool modal = QGuiApplicationPrivate::modalState(); + QCocoaAutoReleasePool pool; + if (OSMenuRef menu = reinterpret_cast<QCocoaMenuBar *>(mb->platformMenuBar())->macMenu()) { + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + [loader ensureAppMenuInMenu:menu]; + [NSApp setMainMenu:menu]; + syncMenuBarItemsVisiblity(reinterpret_cast<QCocoaMenuBar *>(mb->platformMenuBar())); + + if (OSMenuRef tmpMerge = QCocoaMenu::mergeMenuHash.value(menu)) { + if (QMenuMergeList *mergeList + = QCocoaMenu::mergeMenuItemsHash.value(tmpMerge)) { + const int mergeListSize = mergeList->size(); + + for (int i = 0; i < mergeListSize; ++i) { + const QMenuMergeItem &mergeItem = mergeList->at(i); + // Ideally we would call QCocoaMenu::syncAction, but that requires finding + // the original QMen and likely doing more work than we need. + // For example, enabled is handled below. + [mergeItem.menuItem setTag:reinterpret_cast<long>( + static_cast<QAction *>(mergeItem.action->action))]; + [mergeItem.menuItem setHidden:!(mergeItem.action->action->isVisible())]; + } + } + } + // Check if menu is modally shaddowed and should be disabled: + modal = qt_mac_should_disable_menu(mb); + if (mb != qt_mac_current_menubar.qmenubar || modal != qt_mac_current_menubar.modal) + qt_mac_set_modal_state(menu, modal); + } + qt_mac_current_menubar.qmenubar = mb; + qt_mac_current_menubar.modal = modal; + ret = true; + } else if (qt_mac_current_menubar.qmenubar && qt_mac_current_menubar.qmenubar->isNativeMenuBar()) { + // INVARIANT: The currently active menu bar (if any) is not native. But we do have a + // native menu bar from before. So we need to decide whether or not is should be enabled: + const bool modal = qt_mac_should_disable_menu(qt_mac_current_menubar.qmenubar); + if (modal != qt_mac_current_menubar.modal) { + ret = true; + if (OSMenuRef menu = reinterpret_cast<QCocoaMenuBar *>(qt_mac_current_menubar.qmenubar->platformMenuBar())->macMenu()) { + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + [loader ensureAppMenuInMenu:menu]; + [NSApp setMainMenu:menu]; + syncMenuBarItemsVisiblity(reinterpret_cast<QCocoaMenuBar *>(qt_mac_current_menubar.qmenubar->platformMenuBar())); + qt_mac_set_modal_state(menu, modal); + } + qt_mac_current_menubar.modal = modal; + } + } + + if (!ret) { + qt_mac_clear_menubar(); + } + return ret; +} + +QHash<OSMenuRef, OSMenuRef> QCocoaMenu::mergeMenuHash; +QHash<OSMenuRef, QMenuMergeList*> QCocoaMenu::mergeMenuItemsHash; + +bool QCocoaMenu::merged(const QAction *action) const +{ + if (OSMenuRef merge = mergeMenuHash.value(menu)) { + if (QMenuMergeList *list = mergeMenuItemsHash.value(merge)) { + for(int i = 0; i < list->size(); ++i) { + const QMenuMergeItem &item = list->at(i); + if (item.action->action == action) + return true; + } + } + } + return false; +} + +//creation of the OSMenuRef +static OSMenuRef qt_mac_create_menu(QWidget *w) +{ + OSMenuRef ret; + if (QMenu *qmenu = qobject_cast<QMenu *>(w)){ + ret = [[QT_MANGLE_NAMESPACE(QNativeCocoaMenu) alloc] initWithQMenu:qmenu]; + } else { + ret = [[NSMenu alloc] init]; + } + return ret; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 69a11134bd..0b96928d5b 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -48,17 +48,18 @@ @interface QNSView : NSView { CGImageRef m_cgImage; - QWidget *m_widget; + QWindow *m_window; Qt::MouseButtons m_buttons; } - (id)init; -- (id)initWithWidget:(QWidget *)widget; +- (id)initWithQWindow:(QWindow *)window; - (void)setImage:(QImage *)image; - (void)drawRect:(NSRect)dirtyRect; - (BOOL)isFlipped; +- (BOOL)acceptsFirstResponder; - (void)handleMouseEvent:(NSEvent *)theEvent; - (void)mouseDown:(NSEvent *)theEvent; @@ -74,6 +75,12 @@ - (void)otherMouseDragged:(NSEvent *)theEvent; - (void)otherMouseUp:(NSEvent *)theEvent; +- (int) convertKeyCode : (QChar)keyCode; +- (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags; +- (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType; +- (void)keyDown:(NSEvent *)theEvent; +- (void)keyUp:(NSEvent *)theEvent; + @end #endif //QNSVIEW_H diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 037cbdb5d6..f3c71d9eed 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -39,12 +39,20 @@ ** ****************************************************************************/ +#include <Carbon/Carbon.h> + #include "qnsview.h" +#include "qcocoahelpers.h" #include <QtGui/QWindowSystemInterface> - #include <QtCore/QDebug> +@interface NSEvent (Qt_Compile_Leopard_DeviceDelta) + - (CGFloat)deviceDeltaX; + - (CGFloat)deviceDeltaY; + - (CGFloat)deviceDeltaZ; +@end + @implementation QNSView - (id) init @@ -52,16 +60,16 @@ self = [super init]; if (self) { m_cgImage = 0; - m_widget = 0; + m_window = 0; m_buttons = Qt::NoButton; } return self; } -- (id)initWithWidget:(QWidget *)widget { +- (id)initWithQWindow:(QWindow *)widget { self = [self init]; if (self) { - m_widget = widget; + m_window = widget; } return self; } @@ -91,7 +99,7 @@ bitDepth, bytesPrLine, cgColourSpaceRef, - kCGImageAlphaNone, + kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst, cgDataProviderRef, NULL, false, @@ -130,82 +138,185 @@ return YES; } +- (BOOL)acceptsFirstResponder +{ + return YES; +} + - (void)handleMouseEvent:(NSEvent *)theEvent; { - NSPoint point = [self convertPoint: [theEvent locationInWindow] fromView: nil]; - QPoint qt_localPoint(point.x,point.y); + NSPoint windowPoint = [self convertPoint: [theEvent locationInWindow] fromView: nil]; + QPoint qt_windowPoint(windowPoint.x, windowPoint.y); NSTimeInterval timestamp = [theEvent timestamp]; ulong qt_timestamp = timestamp * 1000; - QWindowSystemInterface::handleMouseEvent(m_widget,qt_timestamp,qt_localPoint,QPoint(),m_buttons); + // ### Should the points be windowPoint and screenPoint? + QWindowSystemInterface::handleMouseEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, m_buttons); +} +- (void)mouseDown:(NSEvent *)theEvent +{ + m_buttons |= Qt::LeftButton; + [self handleMouseEvent:theEvent]; +} + +- (void)mouseDragged:(NSEvent *)theEvent +{ + if (!(m_buttons & Qt::LeftButton)) + qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton"); + [self handleMouseEvent:theEvent]; +} + +- (void)mouseUp:(NSEvent *)theEvent +{ + m_buttons &= QFlag(~int(Qt::LeftButton)); + [self handleMouseEvent:theEvent]; } - - (void)mouseDown:(NSEvent *)theEvent - { - m_buttons |= Qt::LeftButton; - [self handleMouseEvent:theEvent]; - } - - (void)mouseDragged:(NSEvent *)theEvent - { - if (!(m_buttons & Qt::LeftButton)) - qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton"); - [self handleMouseEvent:theEvent]; - } - - (void)mouseUp:(NSEvent *)theEvent - { - m_buttons &= QFlag(~int(Qt::LeftButton)); - [self handleMouseEvent:theEvent]; - } - (void)mouseMoved:(NSEvent *)theEvent { - qDebug() << "mouseMove"; [self handleMouseEvent:theEvent]; } + - (void)mouseEntered:(NSEvent *)theEvent { - Q_UNUSED(theEvent); - QWindowSystemInterface::handleEnterEvent(m_widget); + Q_UNUSED(theEvent); + QWindowSystemInterface::handleEnterEvent(m_window); } + - (void)mouseExited:(NSEvent *)theEvent { - Q_UNUSED(theEvent); - QWindowSystemInterface::handleLeaveEvent(m_widget); + Q_UNUSED(theEvent); + QWindowSystemInterface::handleLeaveEvent(m_window); } + - (void)rightMouseDown:(NSEvent *)theEvent { - m_buttons |= Qt::RightButton; + m_buttons |= Qt::RightButton; [self handleMouseEvent:theEvent]; } + - (void)rightMouseDragged:(NSEvent *)theEvent { - if (!(m_buttons & Qt::LeftButton)) - qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton"); - [self handleMouseEvent:theEvent]; + if (!(m_buttons & Qt::LeftButton)) + qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton"); + [self handleMouseEvent:theEvent]; } + - (void)rightMouseUp:(NSEvent *)theEvent { - m_buttons &= QFlag(~int(Qt::RightButton)); - [self handleMouseEvent:theEvent]; + m_buttons &= QFlag(~int(Qt::RightButton)); + [self handleMouseEvent:theEvent]; } + - (void)otherMouseDown:(NSEvent *)theEvent { - m_buttons |= Qt::RightButton; + m_buttons |= Qt::RightButton; [self handleMouseEvent:theEvent]; } + - (void)otherMouseDragged:(NSEvent *)theEvent { - if (!(m_buttons & Qt::LeftButton)) - qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton"); - [self handleMouseEvent:theEvent]; + if (!(m_buttons & Qt::LeftButton)) + qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton"); + [self handleMouseEvent:theEvent]; } + - (void)otherMouseUp:(NSEvent *)theEvent { - m_buttons &= QFlag(~int(Qt::MiddleButton)); - [self handleMouseEvent:theEvent]; + m_buttons &= QFlag(~int(Qt::MiddleButton)); + [self handleMouseEvent:theEvent]; } +#ifndef QT_NO_WHEELEVENT +- (void)scrollWheel:(NSEvent *)theEvent +{ + int deltaX = 0; + int deltaY = 0; + int deltaZ = 0; + + const EventRef carbonEvent = (EventRef)[theEvent eventRef]; + const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0; + const bool scrollEvent = carbonEventKind == kEventMouseScroll; + + if (scrollEvent) { + // The mouse device containts pixel scroll wheel support (Mighty Mouse, Trackpad). + // Since deviceDelta is delivered as pixels rather than degrees, we need to + // convert from pixels to degrees in a sensible manner. + // It looks like 1/4 degrees per pixel behaves most native. + // (NB: Qt expects the unit for delta to be 8 per degree): + const int pixelsToDegrees = 2; // 8 * 1/4 + deltaX = [theEvent deviceDeltaX] * pixelsToDegrees; + deltaY = [theEvent deviceDeltaY] * pixelsToDegrees; + deltaZ = [theEvent deviceDeltaZ] * pixelsToDegrees; + } else { + // carbonEventKind == kEventMouseWheelMoved + // Remove acceleration, and use either -120 or 120 as delta: + deltaX = qBound(-120, int([theEvent deltaX] * 10000), 120); + deltaY = qBound(-120, int([theEvent deltaY] * 10000), 120); + deltaZ = qBound(-120, int([theEvent deltaZ] * 10000), 120); + } + + NSPoint windowPoint = [self convertPoint: [theEvent locationInWindow] fromView: nil]; + QPoint qt_windowPoint(windowPoint.x, windowPoint.y); + NSTimeInterval timestamp = [theEvent timestamp]; + ulong qt_timestamp = timestamp * 1000; + + if (deltaX != 0) + QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, deltaX, Qt::Horizontal); + + if (deltaY != 0) + QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, deltaY, Qt::Vertical); + if (deltaZ != 0) + // Qt doesn't explicitly support wheels with a Z component. In a misguided attempt to + // try to be ahead of the pack, I'm adding this extra value. + QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, deltaY, (Qt::Orientation)3); +} +#endif //QT_NO_WHEELEVENT + +- (int) convertKeyCode : (QChar)keyChar +{ + return qt_mac_cocoaKey2QtKey(keyChar); +} + +- (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags +{ + Qt::KeyboardModifiers qtMods =Qt::NoModifier; + if (modifierFlags & NSShiftKeyMask) + qtMods |= Qt::ShiftModifier; + if (modifierFlags & NSControlKeyMask) + qtMods |= Qt::MetaModifier; + if (modifierFlags & NSAlternateKeyMask) + qtMods |= Qt::AltModifier; + if (modifierFlags & NSCommandKeyMask) + qtMods |= Qt::ControlModifier; + if (modifierFlags & NSNumericPadKeyMask) + qtMods |= Qt::KeypadModifier; + return qtMods; +} + +- (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType +{ + NSTimeInterval timestamp = [theEvent timestamp]; + ulong qt_timestamp = timestamp * 1000; + QString characters = QString::fromUtf8([[theEvent characters] UTF8String]); + Qt::KeyboardModifiers modifiers = [self convertKeyModifiers : [theEvent modifierFlags]]; + QChar ch([[theEvent charactersIgnoringModifiers] characterAtIndex:0]); + int keyCode = [self convertKeyCode : ch]; + + QWindowSystemInterface::handleKeyEvent(m_window, qt_timestamp, QEvent::Type(eventType), keyCode, modifiers, characters); +} + +- (void)keyDown:(NSEvent *)theEvent +{ + [self handleKeyEvent : theEvent eventType :int(QEvent::KeyPress)]; +} + +- (void)keyUp:(NSEvent *)theEvent +{ + [self handleKeyEvent : theEvent eventType :int(QEvent::KeyRelease)]; +} @end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h index cf296c4a8b..5cd226a71d 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.h +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h @@ -46,6 +46,26 @@ #include "qcocoawindow.h" +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 +@protocol NSWindowDelegate <NSObject> +//- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize; +//- (void)windowDidMiniaturize:(NSNotification*)notification; +- (void)windowDidResize:(NSNotification *)notification; +- (void)windowWillClose:(NSNotification *)notification; +//- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)defaultFrame; +- (void)windowDidMove:(NSNotification *)notification; +//- (BOOL)windowShouldClose:(id)window; +//- (void)windowDidDeminiaturize:(NSNotification *)notification; +//- (void)windowDidBecomeMain:(NSNotification*)notification; +//- (void)windowDidResignMain:(NSNotification*)notification; +//- (void)windowDidBecomeKey:(NSNotification*)notification; +//- (void)windowDidResignKey:(NSNotification*)notification; +//- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu; +//- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard; +//- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame; +@end +#endif + @interface QNSWindowDelegate : NSObject <NSWindowDelegate> { QCocoaWindow *m_cocoaWindow; @@ -54,6 +74,7 @@ - (id)initWithQCocoaWindow: (QCocoaWindow *) cocoaWindow; - (void)windowDidResize:(NSNotification *)notification; +- (void)windowDidMove:(NSNotification *)notification; - (void)windowWillClose:(NSNotification *)notification; @end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 887b08f6d2..869ef7840b 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -64,10 +64,20 @@ } } +- (void)windowDidMove:(NSNotification *)notification +{ + Q_UNUSED(notification); + if (m_cocoaWindow) { + m_cocoaWindow->windowDidMove(); + } +} + - (void)windowWillClose:(NSNotification *)notification { Q_UNUSED(notification); - QWindowSystemInterface::handleCloseEvent(m_cocoaWindow->widget()); + if (m_cocoaWindow) { + m_cocoaWindow->windowWillClose(); + } } @end diff --git a/src/plugins/platforms/cocoa/qt_menu.nib/classes.nib b/src/plugins/platforms/cocoa/qt_menu.nib/classes.nib new file mode 100644 index 0000000000..0031e0e4e5 --- /dev/null +++ b/src/plugins/platforms/cocoa/qt_menu.nib/classes.nib @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>IBClasses</key> + <array> + <dict> + <key>ACTIONS</key> + <dict> + <key>hide</key> + <string>id</string> + <key>hideOtherApplications</key> + <string>id</string> + <key>orderFrontStandardAboutPanel</key> + <string>id</string> + <key>qtDispatcherToQAction</key> + <string>id</string> + <key>terminate</key> + <string>id</string> + <key>unhideAllApplications</key> + <string>id</string> + </dict> + <key>CLASS</key> + <string>QCocoaMenuLoader</string> + <key>LANGUAGE</key> + <string>ObjC</string> + <key>OUTLETS</key> + <dict> + <key>aboutItem</key> + <string>NSMenuItem</string> + <key>aboutQtItem</key> + <string>NSMenuItem</string> + <key>appMenu</key> + <string>NSMenu</string> + <key>hideItem</key> + <string>NSMenuItem</string> + <key>preferencesItem</key> + <string>NSMenuItem</string> + <key>quitItem</key> + <string>NSMenuItem</string> + <key>theMenu</key> + <string>NSMenu</string> + </dict> + <key>SUPERCLASS</key> + <string>NSResponder</string> + </dict> + <dict> + <key>CLASS</key> + <string>FirstResponder</string> + <key>LANGUAGE</key> + <string>ObjC</string> + <key>SUPERCLASS</key> + <string>NSObject</string> + </dict> + </array> + <key>IBVersion</key> + <string>1</string> +</dict> +</plist> diff --git a/src/plugins/platforms/cocoa/qt_menu.nib/info.nib b/src/plugins/platforms/cocoa/qt_menu.nib/info.nib new file mode 100644 index 0000000000..02e5cca562 --- /dev/null +++ b/src/plugins/platforms/cocoa/qt_menu.nib/info.nib @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>IBFramework Version</key> + <string>672</string> + <key>IBOldestOS</key> + <integer>5</integer> + <key>IBOpenObjects</key> + <array> + <integer>57</integer> + </array> + <key>IBSystem Version</key> + <string>9L31a</string> + <key>targetFramework</key> + <string>IBCocoaFramework</string> +</dict> +</plist> diff --git a/src/plugins/platforms/cocoa/qt_menu.nib/keyedobjects.nib b/src/plugins/platforms/cocoa/qt_menu.nib/keyedobjects.nib Binary files differnew file mode 100644 index 0000000000..3edb0ed2eb --- /dev/null +++ b/src/plugins/platforms/cocoa/qt_menu.nib/keyedobjects.nib diff --git a/src/plugins/platforms/directfb/directfb.pro b/src/plugins/platforms/directfb/directfb.pro index f830177dcb..e516fb11f3 100644 --- a/src/plugins/platforms/directfb/directfb.pro +++ b/src/plugins/platforms/directfb/directfb.pro @@ -2,6 +2,8 @@ TARGET = qdirectfb load(qt_plugin) DESTDIR = $$QT.gui.plugins/platforms +QT += core-private gui-private platformsupport-private + isEmpty(DIRECTFB_LIBS) { DIRECTFB_LIBS = -ldirectfb -lfusion -ldirect -lpthread } @@ -19,16 +21,16 @@ SOURCES = main.cpp \ qdirectfbconvenience.cpp \ qdirectfbinput.cpp \ qdirectfbcursor.cpp \ - qdirectfbwindow.cpp \ - qdirectfbglcontext.cpp + qdirectfbwindow.cpp HEADERS = qdirectfbintegration.h \ qdirectfbwindowsurface.h \ qdirectfbblitter.h \ qdirectfbconvenience.h \ qdirectfbinput.h \ qdirectfbcursor.h \ - qdirectfbwindow.h \ - qdirectfbglcontext.h + qdirectfbwindow.h + +# ### port the GL context include(../fontdatabases/genericunix/genericunix.pri) target.path += $$[QT_INSTALL_PLUGINS]/platforms diff --git a/src/plugins/platforms/directfb/qdirectfbblitter.cpp b/src/plugins/platforms/directfb/qdirectfbblitter.cpp index 86a8bf7cb7..a4da2d8142 100644 --- a/src/plugins/platforms/directfb/qdirectfbblitter.cpp +++ b/src/plugins/platforms/directfb/qdirectfbblitter.cpp @@ -92,10 +92,10 @@ void QDirectFbBlitter::fillRect(const QRectF &rect, const QColor &color) void QDirectFbBlitter::drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &srcRect) { - QPixmapData *data = pixmap.pixmapData(); + QPlatformPixmap *data = pixmap.handle(); Q_ASSERT(data->width() && data->height()); - Q_ASSERT(data->classId() == QPixmapData::BlitterClass); - QBlittablePixmapData *blitPm = static_cast<QBlittablePixmapData*>(data); + Q_ASSERT(data->classId() == QPlatformPixmap::BlitterClass); + QBlittablePlatformPixmap *blitPm = static_cast<QBlittablePlatformPixmap*>(data); QDirectFbBlitter *dfbBlitter = static_cast<QDirectFbBlitter *>(blitPm->blittable()); dfbBlitter->unlock(); diff --git a/src/plugins/platforms/directfb/qdirectfbblitter.h b/src/plugins/platforms/directfb/qdirectfbblitter.h index 16d7599c83..2dcb2be07a 100644 --- a/src/plugins/platforms/directfb/qdirectfbblitter.h +++ b/src/plugins/platforms/directfb/qdirectfbblitter.h @@ -67,7 +67,7 @@ protected: friend class QDirectFbConvenience; }; -class QDirectFbBlitterPixmapData : public QBlittablePixmapData +class QDirectFbBlitterPlatformPixmap : public QBlittablePlatformPixmap { public: QBlittable *createBlittable(const QSize &size) const { return new QDirectFbBlitter(size); } diff --git a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp index 37810dc461..38130c8deb 100644 --- a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp +++ b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp @@ -106,9 +106,9 @@ int QDirectFbConvenience::colorDepthForSurface(const DFBSurfacePixelFormat forma return ((0x1f << 7) & format) >> 7; } -IDirectFBSurface *QDirectFbConvenience::dfbSurfaceForPixmapData(QPixmapData *pixmapData) +IDirectFBSurface *QDirectFbConvenience::dfbSurfaceForPlatformPixmap(QPlatformPixmap *handle) { - QBlittablePixmapData *blittablePmData = static_cast<QBlittablePixmapData *>(pixmapData); + QBlittablePlatformPixmap *blittablePmData = static_cast<QBlittablePlatformPixmap *>(handle); if (blittablePmData) { QBlittable *blittable = blittablePmData->blittable(); QDirectFbBlitter *dfbBlitter = static_cast<QDirectFbBlitter *>(blittable); diff --git a/src/plugins/platforms/directfb/qdirectfbconvenience.h b/src/plugins/platforms/directfb/qdirectfbconvenience.h index c82bea84c7..93d47f3644 100644 --- a/src/plugins/platforms/directfb/qdirectfbconvenience.h +++ b/src/plugins/platforms/directfb/qdirectfbconvenience.h @@ -67,7 +67,7 @@ public: static IDirectFB *dfbInterface(); static IDirectFBDisplayLayer *dfbDisplayLayer(int display = DLID_PRIMARY); - static IDirectFBSurface *dfbSurfaceForPixmapData(QPixmapData *); + static IDirectFBSurface *dfbSurfaceForPlatformPixmap(QPlatformPixmap *); static Qt::MouseButton mouseButton(DFBInputDeviceButtonIdentifier identifier); static Qt::MouseButtons mouseButtons(DFBInputDeviceButtonMask mask); diff --git a/src/plugins/platforms/directfb/qdirectfbcursor.cpp b/src/plugins/platforms/directfb/qdirectfbcursor.cpp index 8a38bc4e83..b39a3f3c0a 100644 --- a/src/plugins/platforms/directfb/qdirectfbcursor.cpp +++ b/src/plugins/platforms/directfb/qdirectfbcursor.cpp @@ -43,25 +43,26 @@ #include "qdirectfbconvenience.h" -QDirectFBCursor::QDirectFBCursor(QPlatformScreen* screen) : - QPlatformCursor(screen), surface(0) +QDirectFBCursor::QDirectFBCursor(QPlatformScreen *screen) + : QPlatformCursor(screen) { QDirectFbConvenience::dfbInterface()->GetDisplayLayer(QDirectFbConvenience::dfbInterface(),DLID_PRIMARY, &m_layer); - image = new QPlatformCursorImage(0, 0, 0, 0, 0, 0); + m_image = new QPlatformCursorImage(0, 0, 0, 0, 0, 0); } -void QDirectFBCursor::changeCursor(QCursor * cursor, QWidget * widget) +#warning "Memory leak?" + +void QDirectFBCursor::changeCursor(QCursor *cursor, QWindow *) { - Q_UNUSED(widget); int xSpot; int ySpot; QPixmap map; if (cursor->shape() != Qt::BitmapCursor) { - image->set(cursor->shape()); - xSpot = image->hotspot().x(); - ySpot = image->hotspot().y(); - QImage *i = image->image(); + m_image->set(cursor->shape()); + xSpot = m_image->hotspot().x(); + ySpot = m_image->hotspot().y(); + QImage *i = m_image->image(); map = QPixmap::fromImage(*i); } else { QPoint point = cursor->hotSpot(); @@ -70,7 +71,7 @@ void QDirectFBCursor::changeCursor(QCursor * cursor, QWidget * widget) map = cursor->pixmap(); } - IDirectFBSurface *surface = QDirectFbConvenience::dfbSurfaceForPixmapData(map.pixmapData()); + IDirectFBSurface *surface = QDirectFbConvenience::dfbSurfaceForPlatformPixmap(map.handle()); if (m_layer->SetCooperativeLevel(m_layer, DLSCL_ADMINISTRATIVE) != DFB_OK) { return; diff --git a/src/plugins/platforms/directfb/qdirectfbcursor.h b/src/plugins/platforms/directfb/qdirectfbcursor.h index b148de5589..22328da402 100644 --- a/src/plugins/platforms/directfb/qdirectfbcursor.h +++ b/src/plugins/platforms/directfb/qdirectfbcursor.h @@ -51,13 +51,11 @@ class QDirectFBCursor : public QPlatformCursor { public: QDirectFBCursor(QPlatformScreen *screem); - void changeCursor(QCursor * cursor, QWidget * widget); + void changeCursor(QCursor *cursor, QWindow *window); private: - IDirectFBDisplayLayer * m_layer; - IDirectFBSurface * surface; - QPlatformCursorImage * image; - QDirectFbBlitter *blitter; + IDirectFBDisplayLayer *m_layer; + QPlatformCursorImage *m_image; }; #endif // QDIRECTFBCURSOR_H diff --git a/src/plugins/platforms/directfb/qdirectfbglcontext.cpp b/src/plugins/platforms/directfb/qdirectfbglcontext.cpp index aca28f1d62..1121a42944 100644 --- a/src/plugins/platforms/directfb/qdirectfbglcontext.cpp +++ b/src/plugins/platforms/directfb/qdirectfbglcontext.cpp @@ -70,13 +70,13 @@ QDirectFbGLContext::QDirectFbGLContext(IDirectFBGL *glContext) void QDirectFbGLContext::makeCurrent() { - QPlatformGLContext::makeCurrent(); + QPlatformOpenGLContext::makeCurrent(); m_dfbGlContext->Lock(m_dfbGlContext); } void QDirectFbGLContext::doneCurrent() { - QPlatformGLContext::doneCurrent(); + QPlatformOpenGLContext::doneCurrent(); m_dfbGlContext->Unlock(m_dfbGlContext); } diff --git a/src/plugins/platforms/directfb/qdirectfbglcontext.h b/src/plugins/platforms/directfb/qdirectfbglcontext.h index bff8b28d08..97bab0dcb0 100644 --- a/src/plugins/platforms/directfb/qdirectfbglcontext.h +++ b/src/plugins/platforms/directfb/qdirectfbglcontext.h @@ -42,11 +42,11 @@ #ifndef QDIRECTFBGLCONTEXT_H #define QDIRECTFBGLCONTEXT_H -#include <QPlatformGLContext> +#include <QPlatformOpenGLContext> #include "qdirectfbconvenience.h" -class QDirectFbGLContext : public QPlatformGLContext +class QDirectFbGLContext : public QPlatformOpenGLContext { public: explicit QDirectFbGLContext(IDirectFBGL *glContext); diff --git a/src/plugins/platforms/directfb/qdirectfbinput.cpp b/src/plugins/platforms/directfb/qdirectfbinput.cpp index d35cea5ee9..d05729b992 100644 --- a/src/plugins/platforms/directfb/qdirectfbinput.cpp +++ b/src/plugins/platforms/directfb/qdirectfbinput.cpp @@ -47,7 +47,6 @@ #include <QWindowSystemInterface> #include <QMouseEvent> #include <QEvent> -#include <QApplication> #include <directfb.h> @@ -82,9 +81,9 @@ void QDirectFbInput::stopInputEventLoop() m_waitStop.acquire(); } -void QDirectFbInput::addWindow(DFBWindowID id, QWidget *tlw) +void QDirectFbInput::addWindow(DFBWindowID id, QWindow *qt_window) { - m_tlwMap.insert(id,tlw); + m_tlwMap.insert(id,qt_window); IDirectFBWindow *window; m_dfbDisplayLayer->GetWindow(m_dfbDisplayLayer,id,&window); @@ -152,7 +151,7 @@ void QDirectFbInput::handleMouseEvents(const DFBEvent &event) } else if (event.window.type == DWET_BUTTONUP) { window->UngrabPointer(window); } - QWidget *tlw = m_tlwMap.value(event.window.window_id); + QWindow *tlw = m_tlwMap.value(event.window.window_id); QWindowSystemInterface::handleMouseEvent(tlw, timestamp, p, globalPos, buttons); } @@ -161,7 +160,7 @@ void QDirectFbInput::handleWheelEvent(const DFBEvent &event) QPoint p(event.window.cx, event.window.cy); QPoint globalPos = globalPoint(event); long timestamp = (event.window.timestamp.tv_sec*1000) + (event.window.timestamp.tv_usec/1000); - QWidget *tlw = m_tlwMap.value(event.window.window_id); + QWindow *tlw = m_tlwMap.value(event.window.window_id); QWindowSystemInterface::handleWheelEvent(tlw, timestamp, p, globalPos, event.window.step*120, Qt::Vertical); @@ -178,13 +177,13 @@ void QDirectFbInput::handleKeyEvents(const DFBEvent &event) QChar character; if (DFB_KEY_TYPE(event.window.key_symbol) == DIKT_UNICODE) character = QChar(event.window.key_symbol); - QWidget *tlw = m_tlwMap.value(event.window.window_id); + QWindow *tlw = m_tlwMap.value(event.window.window_id); QWindowSystemInterface::handleKeyEvent(tlw, timestamp, type, key, modifiers, character); } void QDirectFbInput::handleEnterLeaveEvents(const DFBEvent &event) { - QWidget *tlw = m_tlwMap.value(event.window.window_id); + QWindow *tlw = m_tlwMap.value(event.window.window_id); switch (event.window.type) { case DWET_ENTER: QWindowSystemInterface::handleEnterEvent(tlw); diff --git a/src/plugins/platforms/directfb/qdirectfbinput.h b/src/plugins/platforms/directfb/qdirectfbinput.h index 3b8008f1fe..b0fe0c79eb 100644 --- a/src/plugins/platforms/directfb/qdirectfbinput.h +++ b/src/plugins/platforms/directfb/qdirectfbinput.h @@ -57,7 +57,7 @@ class QDirectFbInput : public QObject Q_OBJECT public: QDirectFbInput(QObject *parent); - void addWindow(DFBWindowID id, QWidget *tlw); + void addWindow(DFBWindowID id, QWindow *window); void removeWindow(WId wId); public slots: @@ -80,7 +80,7 @@ private: bool m_shouldStop; QSemaphore m_waitStop; - QHash<DFBWindowID,QWidget *>m_tlwMap; + QHash<DFBWindowID,QWindow *>m_tlwMap; }; #endif // QDIRECTFBINPUT_H diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.cpp b/src/plugins/platforms/directfb/qdirectfbintegration.cpp index 61f1d2513b..7bf26b433a 100644 --- a/src/plugins/platforms/directfb/qdirectfbintegration.cpp +++ b/src/plugins/platforms/directfb/qdirectfbintegration.cpp @@ -46,20 +46,21 @@ #include "qdirectfbcursor.h" #include "qdirectfbwindow.h" -#include "qgenericunixfontdatabase.h" - -#include <private/qwindowsurface_raster_p.h> -#include <private/qpixmap_raster_p.h> +#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> #include <QtGui/private/qpixmap_blitter_p.h> -#include <QtGui/private/qpixmapdata_p.h> +#include <QtGui/private/qpixmap_raster_p.h> +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qplatformpixmap_qpa.h> #include <QtCore/QCoreApplication> #include <QtCore/QThread> +#include <QtCore/QAbstractEventDispatcher> QT_BEGIN_NAMESPACE QDirectFbScreen::QDirectFbScreen(int display) - :QPlatformScreen() + : QPlatformScreen() { m_layer = QDirectFbConvenience::dfbDisplayLayer(display); m_layer->SetCooperativeLevel(m_layer,DLSCL_SHARED); @@ -74,16 +75,20 @@ QDirectFbScreen::QDirectFbScreen(int display) m_depth = QDirectFbConvenience::colorDepthForSurface(config.pixelformat); m_physicalSize = QSize(qRound(config.width * inch / dpi), qRound(config.height *inch / dpi)); - cursor = new QDirectFBCursor(this); + m_cursor = new QDirectFBCursor(this); } QDirectFbScreen::~QDirectFbScreen() { +#warning "Delete the cursor?" } QDirectFbIntegration::QDirectFbIntegration() - : mFontDb(new QGenericUnixFontDatabase()) + : m_fontDb(new QGenericUnixFontDatabase()) + , m_eventDispatcher(createUnixEventDispatcher()) { + QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); + const QStringList args = QCoreApplication::arguments(); int argc = args.size(); char **argv = new char*[argc]; @@ -99,46 +104,51 @@ QDirectFbIntegration::QDirectFbIntegration() delete[] argv; + QDirectFbScreen *primaryScreen = new QDirectFbScreen(0); - mScreens.append(primaryScreen); + screenAdded(primaryScreen); - mInputRunner = new QThread; - mInput = new QDirectFbInput(0); - mInput->moveToThread(mInputRunner); - QObject::connect(mInputRunner,SIGNAL(started()),mInput,SLOT(runInputEventLoop())); - mInputRunner->start(); + m_inputRunner = new QThread; + m_input = new QDirectFbInput(0); + m_input->moveToThread(m_inputRunner); + QObject::connect(m_inputRunner,SIGNAL(started()),m_input,SLOT(runInputEventLoop())); + m_inputRunner->start(); } QDirectFbIntegration::~QDirectFbIntegration() { - mInput->stopInputEventLoop(); - delete mInputRunner; - delete mInput; + m_input->stopInputEventLoop(); + delete m_inputRunner; + delete m_input; } -QPixmapData *QDirectFbIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformPixmap *QDirectFbIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const { - if (type == QPixmapData::BitmapType) - return new QRasterPixmapData(type); + if (type == QPlatformPixmap::BitmapType) + return new QRasterPlatformPixmap(type); else - return new QDirectFbBlitterPixmapData; + return new QDirectFbBlitterPlatformPixmap; +} + +QPlatformWindow *QDirectFbIntegration::createPlatformWindow(QWindow *window) const +{ + QDirectFbInput *input = const_cast<QDirectFbInput *>(m_input);//gah + return new QDirectFbWindow(window,input); } -QPlatformWindow *QDirectFbIntegration::createPlatformWindow(QWidget *widget, WId winId) const +QAbstractEventDispatcher *QDirectFbIntegration::guiThreadEventDispatcher() const { - Q_UNUSED(winId); - QDirectFbInput *input = const_cast<QDirectFbInput *>(mInput);//gah - return new QDirectFbWindow(widget,input); + return m_eventDispatcher; } -QWindowSurface *QDirectFbIntegration::createWindowSurface(QWidget *widget, WId winId) const +QPlatformBackingStore *QDirectFbIntegration::createPlatformBackingStore(QWindow *window) const { - return new QDirectFbWindowSurface(widget,winId); + return new QDirectFbWindowSurface(window); } QPlatformFontDatabase *QDirectFbIntegration::fontDatabase() const { - return mFontDb; + return m_fontDb; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.h b/src/plugins/platforms/directfb/qdirectfbintegration.h index 0e8337a5fb..64f3b6005a 100644 --- a/src/plugins/platforms/directfb/qdirectfbintegration.h +++ b/src/plugins/platforms/directfb/qdirectfbintegration.h @@ -51,11 +51,11 @@ QT_BEGIN_NAMESPACE class QThread; +class QAbstractEventDispatcher; class QDirectFBCursor; class QDirectFbScreen : public QPlatformScreen { -Q_OBJECT public: QDirectFbScreen(int display); ~QDirectFbScreen(); @@ -74,8 +74,7 @@ public: IDirectFBDisplayLayer *m_layer; private: - QDirectFBCursor * cursor; - + QDirectFBCursor *m_cursor; }; class QDirectFbIntegration : public QPlatformIntegration @@ -84,19 +83,18 @@ public: QDirectFbIntegration(); ~QDirectFbIntegration(); - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId = 0) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; - - QList<QPlatformScreen *> screens() const { return mScreens; } + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + QAbstractEventDispatcher *guiThreadEventDispatcher() const; QPlatformFontDatabase *fontDatabase() const; private: - QList<QPlatformScreen *> mScreens; - QDirectFbInput *mInput; - QThread *mInputRunner; - QPlatformFontDatabase *mFontDb; + QDirectFbInput *m_input; + QThread *m_inputRunner; + QPlatformFontDatabase *m_fontDb; + QAbstractEventDispatcher *m_eventDispatcher; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbwindow.cpp b/src/plugins/platforms/directfb/qdirectfbwindow.cpp index d2c411eaeb..e75291b5c1 100644 --- a/src/plugins/platforms/directfb/qdirectfbwindow.cpp +++ b/src/plugins/platforms/directfb/qdirectfbwindow.cpp @@ -41,16 +41,13 @@ #include "qdirectfbwindow.h" #include "qdirectfbinput.h" -#include "qdirectfbglcontext.h" - -#include <QWidget> #include "qdirectfbwindowsurface.h" #include <directfb.h> -QDirectFbWindow::QDirectFbWindow(QWidget *tlw, QDirectFbInput *inputhandler) - : QPlatformWindow(tlw), m_inputHandler(inputhandler), m_context(0) +QDirectFbWindow::QDirectFbWindow(QWindow *tlw, QDirectFbInput *inputhandler) + : QPlatformWindow(tlw), m_inputHandler(inputhandler) { IDirectFBDisplayLayer *layer = QDirectFbConvenience::dfbDisplayLayer(); DFBDisplayLayerConfig layerConfig; @@ -63,10 +60,10 @@ QDirectFbWindow::QDirectFbWindow(QWidget *tlw, QDirectFbInput *inputhandler) |DWDESC_OPTIONS #endif |DWDESC_CAPS); - description.width = tlw->rect().width(); - description.height = tlw->rect().height(); - description.posx = tlw->rect().x(); - description.posy = tlw->rect().y(); + description.width = tlw->width(); + description.height = tlw->height(); + description.posx = tlw->x(); + description.posy = tlw->y(); if (layerConfig.surface_caps & DSCAPS_PREMULTIPLIED) description.surface_caps = DSCAPS_PREMULTIPLIED; @@ -85,7 +82,7 @@ QDirectFbWindow::QDirectFbWindow(QWidget *tlw, QDirectFbInput *inputhandler) m_dfbWindow->SetOpacity(m_dfbWindow,0xff); - setVisible(widget()->isVisible()); + setVisible(window()->visible()); DFBWindowID id; m_dfbWindow->GetID(m_dfbWindow, &id); @@ -100,17 +97,20 @@ QDirectFbWindow::~QDirectFbWindow() void QDirectFbWindow::setGeometry(const QRect &rect) { - bool isMoveOnly = (rect.topLeft() != geometry().topLeft()) && (rect.size() == geometry().size()); +// bool isMoveOnly = (rect.topLeft() != geometry().topLeft()) && (rect.size() == geometry().size()); + QPlatformWindow::setGeometry(rect); - if (widget()->isVisible() && !(widget()->testAttribute(Qt::WA_DontShowOnScreen))) { + if (window()->visible()) { m_dfbWindow->SetBounds(m_dfbWindow, rect.x(),rect.y(), rect.width(), rect.height()); - +// ### TODO port, verify if this is needed +#if 0 //Hack. When moving since the WindowSurface of a window becomes invalid when moved if (isMoveOnly) { //if resize then windowsurface is updated. widget()->windowSurface()->resize(rect.size()); - widget()->update(); + window()->update(); } +#endif } } @@ -169,23 +169,3 @@ WId QDirectFbWindow::winId() const m_dfbWindow->GetID(m_dfbWindow, &id); return WId(id); } - -QPlatformGLContext *QDirectFbWindow::glContext() const -{ - if (!m_context) { - IDirectFBSurface *surface; - DFBResult result = m_dfbWindow->GetSurface(m_dfbWindow,&surface); - if (result != DFB_OK) { - qWarning("could not retrieve surface in QDirectFbWindow::glContext()"); - return 0; - } - IDirectFBGL *gl; - result = surface->GetGL(surface,&gl); - if (result != DFB_OK) { - qWarning("could not retrieve IDirectFBGL in QDirectFbWindow::glContext()"); - return 0; - } - const_cast<QDirectFbWindow *>(this)->m_context = new QDirectFbGLContext(gl); - } - return m_context; -} diff --git a/src/plugins/platforms/directfb/qdirectfbwindow.h b/src/plugins/platforms/directfb/qdirectfbwindow.h index 4f839a05fa..4c9bbaaab5 100644 --- a/src/plugins/platforms/directfb/qdirectfbwindow.h +++ b/src/plugins/platforms/directfb/qdirectfbwindow.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE class QDirectFbWindow : public QPlatformWindow { public: - QDirectFbWindow(QWidget *tlw, QDirectFbInput *inputhandler); + QDirectFbWindow(QWindow *tlw, QDirectFbInput *inputhandler); ~QDirectFbWindow(); void setGeometry(const QRect &rect); @@ -65,13 +65,9 @@ public: void lower(); WId winId() const; - QPlatformGLContext *glContext() const; - private: IDirectFBWindow *m_dfbWindow; QDirectFbInput *m_inputHandler; - - QPlatformGLContext *m_context; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbwindowsurface.cpp b/src/plugins/platforms/directfb/qdirectfbwindowsurface.cpp index 730f01fa1b..ab355c48f4 100644 --- a/src/plugins/platforms/directfb/qdirectfbwindowsurface.cpp +++ b/src/plugins/platforms/directfb/qdirectfbwindowsurface.cpp @@ -49,21 +49,21 @@ QT_BEGIN_NAMESPACE -QDirectFbWindowSurface::QDirectFbWindowSurface(QWidget *window, WId wId) - : QWindowSurface(window), m_pixmap(0), m_pmdata(0), m_dfbSurface(0) +QDirectFbWindowSurface::QDirectFbWindowSurface(QWindow *window) + : QPlatformBackingStore(window), m_pixmap(0), m_pmdata(0), m_dfbSurface(0) { IDirectFBDisplayLayer *layer = QDirectFbConvenience::dfbDisplayLayer(); - DFBWindowID id(wId); + DFBWindowID id(window->winId()); IDirectFBWindow *dfbWindow; layer->GetWindow(layer,id,&dfbWindow); dfbWindow->GetSurface(dfbWindow,&m_dfbSurface); //WRONGSIZE - QDirectFbBlitter *blitter = new QDirectFbBlitter(window->rect().size(), m_dfbSurface); - m_pmdata = new QDirectFbBlitterPixmapData; + QDirectFbBlitter *blitter = new QDirectFbBlitter(window->size(), m_dfbSurface); + m_pmdata = new QDirectFbBlitterPlatformPixmap; m_pmdata->setBlittable(blitter); m_pixmap = new QPixmap(m_pmdata); } @@ -78,9 +78,8 @@ QPaintDevice *QDirectFbWindowSurface::paintDevice() return m_pixmap; } -void QDirectFbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QDirectFbWindowSurface::flush(QWindow *, const QRegion ®ion, const QPoint &offset) { - Q_UNUSED(widget); m_pmdata->blittable()->unlock(); QVector<QRect> rects = region.rects(); @@ -91,9 +90,9 @@ void QDirectFbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const } } -void QDirectFbWindowSurface::resize(const QSize &size) +void QDirectFbWindowSurface::resize(const QSize &size, const QRegion& reg) { - QWindowSurface::resize(size); + QPlatformBackingStore::resize(size, reg); //Have to add 1 ref ass it will be removed by deleting the old blitter in setBlittable m_dfbSurface->AddRef(m_dfbSurface); diff --git a/src/plugins/platforms/directfb/qdirectfbwindowsurface.h b/src/plugins/platforms/directfb/qdirectfbwindowsurface.h index 7f1140d4eb..2b6cb58aef 100644 --- a/src/plugins/platforms/directfb/qdirectfbwindowsurface.h +++ b/src/plugins/platforms/directfb/qdirectfbwindowsurface.h @@ -42,22 +42,22 @@ #ifndef QWINDOWSURFACE_DIRECTFB_H #define QWINDOWSURFACE_DIRECTFB_H -#include <QtGui/private/qwindowsurface_p.h> +#include <qplatformbackingstore_qpa.h> #include <private/qpixmap_blitter_p.h> #include <directfb.h> QT_BEGIN_NAMESPACE -class QDirectFbWindowSurface : public QWindowSurface +class QDirectFbWindowSurface : public QPlatformBackingStore { public: - QDirectFbWindowSurface(QWidget *window, WId wid); + QDirectFbWindowSurface(QWindow *window); ~QDirectFbWindowSurface(); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - void resize (const QSize &size); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + void resize (const QSize &size, const QRegion &staticContents); bool scroll(const QRegion &area, int dx, int dy); void beginPaint(const QRegion ®ion); @@ -67,7 +67,7 @@ private: void lockSurfaceToImage(); QPixmap *m_pixmap; - QBlittablePixmapData *m_pmdata; + QBlittablePlatformPixmap *m_pmdata; IDirectFBSurface *m_dfbSurface; }; diff --git a/src/plugins/platforms/eglconvenience/eglconvenience.pri b/src/plugins/platforms/eglconvenience/eglconvenience.pri deleted file mode 100644 index 322d4e4633..0000000000 --- a/src/plugins/platforms/eglconvenience/eglconvenience.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -SOURCES += \ - $$PWD/qeglconvenience.cpp - -HEADERS += \ - $$PWD/qeglconvenience.h diff --git a/src/plugins/platforms/eglconvenience/qeglconvenience.cpp b/src/plugins/platforms/eglconvenience/qeglconvenience.cpp deleted file mode 100644 index 69747a87e8..0000000000 --- a/src/plugins/platforms/eglconvenience/qeglconvenience.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qeglconvenience.h" - -QT_BEGIN_NAMESPACE - -QVector<EGLint> q_createConfigAttributesFromFormat(const QPlatformWindowFormat &format) -{ - int redSize = format.redBufferSize(); - int greenSize = format.greenBufferSize(); - int blueSize = format.blueBufferSize(); - int alphaSize = format.alphaBufferSize(); - int depthSize = format.depthBufferSize(); - int stencilSize = format.stencilBufferSize(); - int sampleCount = format.samples(); - - // QPlatformWindowFormat uses a magic value of -1 to indicate "don't care", even when a buffer of that - // type has been requested. So we must check QPlatformWindowFormat's booleans too if size is -1: - if (format.alpha() && alphaSize <= 0) - alphaSize = 1; - if (format.depth() && depthSize <= 0) - depthSize = 1; - if (format.stencil() && stencilSize <= 0) - stencilSize = 1; - if (format.sampleBuffers() && sampleCount <= 0) - sampleCount = 1; - - // We want to make sure 16-bit configs are chosen over 32-bit configs as they will provide - // the best performance. The EGL config selection algorithm is a bit stange in this regard: - // The selection criteria for EGL_BUFFER_SIZE is "AtLeast", so we can't use it to discard - // 32-bit configs completely from the selection. So it then comes to the sorting algorithm. - // The red/green/blue sizes have a sort priority of 3, so they are sorted by first. The sort - // order is special and described as "by larger _total_ number of color bits.". So EGL will - // put 32-bit configs in the list before the 16-bit configs. However, the spec also goes on - // to say "If the requested number of bits in attrib_list for a particular component is 0, - // then the number of bits for that component is not considered". This part of the spec also - // seems to imply that setting the red/green/blue bits to zero means none of the components - // are considered and EGL disregards the entire sorting rule. It then looks to the next - // highest priority rule, which is EGL_BUFFER_SIZE. Despite the selection criteria being - // "AtLeast" for EGL_BUFFER_SIZE, it's sort order is "smaller" meaning 16-bit configs are - // put in the list before 32-bit configs. So, to make sure 16-bit is preffered over 32-bit, - // we must set the red/green/blue sizes to zero. This has an unfortunate consequence that - // if the application sets the red/green/blue size to 5/6/5 on the QPlatformWindowFormat, - // they will probably get a 32-bit config, even when there's an RGB565 config available. - - // Now normalize the values so -1 becomes 0 - redSize = redSize > 0 ? redSize : 0; - greenSize = greenSize > 0 ? greenSize : 0; - blueSize = blueSize > 0 ? blueSize : 0; - alphaSize = alphaSize > 0 ? alphaSize : 0; - depthSize = depthSize > 0 ? depthSize : 0; - stencilSize = stencilSize > 0 ? stencilSize : 0; - sampleCount = sampleCount > 0 ? sampleCount : 0; - - QVector<EGLint> configAttributes; - - configAttributes.append(EGL_RED_SIZE); - configAttributes.append(redSize); - - configAttributes.append(EGL_GREEN_SIZE); - configAttributes.append(greenSize); - - configAttributes.append(EGL_BLUE_SIZE); - configAttributes.append(blueSize); - - configAttributes.append(EGL_ALPHA_SIZE); - configAttributes.append(alphaSize); - - configAttributes.append(EGL_DEPTH_SIZE); - configAttributes.append(depthSize); - - configAttributes.append(EGL_STENCIL_SIZE); - configAttributes.append(stencilSize); - - configAttributes.append(EGL_SAMPLES); - configAttributes.append(sampleCount); - - configAttributes.append(EGL_SAMPLE_BUFFERS); - configAttributes.append(sampleCount? 1:0); - - return configAttributes; -} - -bool q_reduceConfigAttributes(QVector<EGLint> *configAttributes) -{ - int i = -1; - // Reduce the complexity of a configuration request to ask for less - // because the previous request did not result in success. Returns - // true if the complexity was reduced, or false if no further - // reductions in complexity are possible. - - i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR); - if (i >= 0) { - configAttributes->remove(i,2); - } - -#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - // For OpenVG, we sometimes try to create a surface using a pre-multiplied format. If we can't - // find a config which supports pre-multiplied formats, remove the flag on the surface type: - - i = configAttributes->indexOf(EGL_SURFACE_TYPE); - if (i >= 0) { - EGLint surfaceType = configAttributes->at(i +1); - if (surfaceType & EGL_VG_ALPHA_FORMAT_PRE_BIT) { - surfaceType ^= EGL_VG_ALPHA_FORMAT_PRE_BIT; - configAttributes->replace(i+1,surfaceType); - return true; - } - } -#endif - - // EGL chooses configs with the highest color depth over - // those with smaller (but faster) lower color depths. One - // way around this is to set EGL_BUFFER_SIZE to 16, which - // trumps the others. Of course, there may not be a 16-bit - // config available, so it's the first restraint we remove. - i = configAttributes->indexOf(EGL_BUFFER_SIZE); - if (i >= 0) { - if (configAttributes->at(i+1) == 16) { - configAttributes->remove(i,2); - return true; - } - } - - i = configAttributes->indexOf(EGL_SAMPLE_BUFFERS); - if (i >= 0) { - configAttributes->remove(i,2); - i = configAttributes->indexOf(EGL_SAMPLES); - if (i >= 0) { - configAttributes->remove(i,2); - } - return true; - } - - i = configAttributes->indexOf(EGL_ALPHA_SIZE); - if (i >= 0) { - configAttributes->remove(i,2); -#if defined(EGL_BIND_TO_TEXTURE_RGBA) && defined(EGL_BIND_TO_TEXTURE_RGB) - i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGBA); - if (i >= 0) { - configAttributes->replace(i,EGL_BIND_TO_TEXTURE_RGB); - configAttributes->replace(i+1,TRUE); - - } -#endif - return true; - } - - i = configAttributes->indexOf(EGL_STENCIL_SIZE); - if (i >= 0) { - configAttributes->remove(i,2); - return true; - } - i = configAttributes->indexOf(EGL_DEPTH_SIZE); - if (i >= 0) { - configAttributes->remove(i,2); - return true; - } -#ifdef EGL_BIND_TO_TEXTURE_RGB - i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGB); - if (i >= 0) { - configAttributes->remove(i,2); - return true; - } -#endif - - return false; -} - -EGLConfig q_configFromQPlatformWindowFormat(EGLDisplay display, const QPlatformWindowFormat &format, bool highestPixelFormat, int surfaceType) -{ - EGLConfig cfg = 0; - QVector<EGLint> configureAttributes = q_createConfigAttributesFromFormat(format); - configureAttributes.append(EGL_SURFACE_TYPE); //we only support eglconfigs for windows for now - configureAttributes.append(surfaceType); - - configureAttributes.append(EGL_RENDERABLE_TYPE); - if (format.windowApi() == QPlatformWindowFormat::OpenVG) { - configureAttributes.append(EGL_OPENVG_BIT); - } else { - configureAttributes.append(EGL_OPENGL_ES2_BIT); - } - configureAttributes.append(EGL_NONE); - - do { - // Get the number of matching configurations for this set of properties. - EGLint matching = 0; - if (!eglChooseConfig(display, configureAttributes.constData(), 0, 0, &matching) || !matching) - continue; - - // If we want the best pixel format, then return the first - // matching configuration. - if (highestPixelFormat) { - eglChooseConfig(display, configureAttributes.constData(), &cfg, 1, &matching); - if (matching < 1) - continue; - return cfg; - } - - // Fetch all of the matching configurations and find the - // first that matches the pixel format we wanted. - int i = configureAttributes.indexOf(EGL_RED_SIZE); - int confAttrRed = configureAttributes.at(i+1); - i = configureAttributes.indexOf(EGL_GREEN_SIZE); - int confAttrGreen = configureAttributes.at(i+1); - i = configureAttributes.indexOf(EGL_BLUE_SIZE); - int confAttrBlue = configureAttributes.at(i+1); - i = configureAttributes.indexOf(EGL_ALPHA_SIZE); - int confAttrAlpha = configureAttributes.at(i+1); - - EGLint size = matching; - EGLConfig *configs = new EGLConfig [size]; - eglChooseConfig(display, configureAttributes.constData(), configs, size, &matching); - for (EGLint index = 0; index < size; ++index) { - EGLint red, green, blue, alpha; - eglGetConfigAttrib(display, configs[index], EGL_RED_SIZE, &red); - eglGetConfigAttrib(display, configs[index], EGL_GREEN_SIZE, &green); - eglGetConfigAttrib(display, configs[index], EGL_BLUE_SIZE, &blue); - eglGetConfigAttrib(display, configs[index], EGL_ALPHA_SIZE, &alpha); - if (red == confAttrRed && - green == confAttrGreen && - blue == confAttrBlue && - (confAttrAlpha == 0 || - alpha == confAttrAlpha)) { - cfg = configs[index]; - delete [] configs; - return cfg; - } - } - delete [] configs; - } while (q_reduceConfigAttributes(&configureAttributes)); - qWarning("Cant find EGLConfig, returning null config"); - return 0; -} - -QPlatformWindowFormat qt_qPlatformWindowFormatFromConfig(EGLDisplay display, const EGLConfig config) -{ - QPlatformWindowFormat format; - EGLint redSize = 0; - EGLint greenSize = 0; - EGLint blueSize = 0; - EGLint alphaSize = 0; - EGLint depthSize = 0; - EGLint stencilSize = 0; - EGLint sampleCount = 0; - EGLint level = 0; - - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redSize); - eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenSize); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueSize); - eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaSize); - eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depthSize); - eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencilSize); - eglGetConfigAttrib(display, config, EGL_SAMPLES, &sampleCount); - eglGetConfigAttrib(display, config, EGL_LEVEL, &level); - - format.setRedBufferSize(redSize); - format.setGreenBufferSize(greenSize); - format.setBlueBufferSize(blueSize); - format.setAlphaBufferSize(alphaSize); - format.setDepthBufferSize(depthSize); - format.setStencilBufferSize(stencilSize); - format.setSamples(sampleCount); - format.setDirectRendering(true); // All EGL contexts are direct-rendered - format.setRgba(true); // EGL doesn't support colour index rendering - format.setStereo(false); // EGL doesn't support stereo buffers - format.setAccumBufferSize(0); // EGL doesn't support accululation buffers - - // Clear the EGL error state because some of the above may - // have errored out because the attribute is not applicable - // to the surface type. Such errors don't matter. - eglGetError(); - - return format; -} - -bool q_hasEglExtension(EGLDisplay display, const char* extensionName) -{ - QList<QByteArray> extensions = - QByteArray(reinterpret_cast<const char *> - (eglQueryString(display, EGL_EXTENSIONS))).split(' '); - return extensions.contains(extensionName); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglconvenience/qeglconvenience.h b/src/plugins/platforms/eglconvenience/qeglconvenience.h deleted file mode 100644 index da4a0cdded..0000000000 --- a/src/plugins/platforms/eglconvenience/qeglconvenience.h +++ /dev/null @@ -1,60 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEGLCONVENIENCE_H -#define QEGLCONVENIENCE_H - - -#include <QtGui/QPlatformWindowFormat> -#include <QtCore/QVector> - -#include <EGL/egl.h> -QT_BEGIN_NAMESPACE - -QVector<EGLint> q_createConfigAttributesFromFormat(const QPlatformWindowFormat &format); -bool q_reduceConfigAttributes(QVector<EGLint> *configAttributes); -EGLConfig q_configFromQPlatformWindowFormat(EGLDisplay display, const QPlatformWindowFormat &format, bool highestPixelFormat = false, int surfaceType = EGL_WINDOW_BIT); -QPlatformWindowFormat qt_qPlatformWindowFormatFromConfig(EGLDisplay display, const EGLConfig config); -bool q_hasEglExtension(EGLDisplay display,const char* extensionName); - -QT_END_NAMESPACE - -#endif //QEGLCONVENIENCE_H diff --git a/src/plugins/platforms/eglconvenience/qeglplatformcontext.cpp b/src/plugins/platforms/eglconvenience/qeglplatformcontext.cpp deleted file mode 100644 index 4d1d63e37f..0000000000 --- a/src/plugins/platforms/eglconvenience/qeglplatformcontext.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qeglplatformcontext.h" - - -#include <QtGui/QPlatformWindow> - -#include "qeglconvenience.h" - -#include <EGL/egl.h> - -QEGLPlatformContext::QEGLPlatformContext(EGLDisplay display, EGLConfig config, EGLint contextAttrs[], EGLSurface surface, EGLenum eglApi) - : QPlatformGLContext() - , m_eglDisplay(display) - , m_eglSurface(surface) - , m_eglApi(eglApi) -{ - if (m_eglSurface == EGL_NO_SURFACE) { - qWarning("Createing QEGLPlatformContext with no surface"); - } - - eglBindAPI(m_eglApi); - m_eglContext = eglCreateContext(m_eglDisplay,config, 0,contextAttrs); - if (m_eglContext == EGL_NO_CONTEXT) { - qWarning("Could not create the egl context\n"); - eglTerminate(m_eglDisplay); - qFatal("EGL error"); - } - - m_windowFormat = qt_qPlatformWindowFormatFromConfig(display,config); -} - -QEGLPlatformContext::~QEGLPlatformContext() -{ -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglContext::~QEglContext(): %p\n",this); -#endif - if (m_eglSurface != EGL_NO_SURFACE) { - doneCurrent(); - eglDestroySurface(m_eglDisplay, m_eglSurface); - m_eglSurface = EGL_NO_SURFACE; - } - - if (m_eglContext != EGL_NO_CONTEXT) { - eglDestroyContext(m_eglDisplay, m_eglContext); - m_eglContext = EGL_NO_CONTEXT; - } -} - -void QEGLPlatformContext::makeCurrent() -{ - QPlatformGLContext::makeCurrent(); -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglContext::makeCurrent: %p\n",this); -#endif - eglBindAPI(m_eglApi); - bool ok = eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); - if (!ok) - qWarning("QEGLPlatformContext::makeCurrent: eglError: %d, this: %p \n", eglGetError(), this); -#ifdef QEGL_EXTRA_DEBUG - static bool showDebug = true; - if (showDebug) { - showDebug = false; - const char *str = (const char*)glGetString(GL_VENDOR); - qWarning("Vendor %s\n", str); - str = (const char*)glGetString(GL_RENDERER); - qWarning("Renderer %s\n", str); - str = (const char*)glGetString(GL_VERSION); - qWarning("Version %s\n", str); - - str = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION); - qWarning("Extensions %s\n",str); - - str = (const char*)glGetString(GL_EXTENSIONS); - qWarning("Extensions %s\n", str); - - } -#endif -} -void QEGLPlatformContext::doneCurrent() -{ - QPlatformGLContext::doneCurrent(); -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglContext::doneCurrent:%p\n",this); -#endif - eglBindAPI(m_eglApi); - bool ok = eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (!ok) - qWarning("QEGLPlatformContext::doneCurrent(): eglError: %d, this: %p \n", eglGetError(), this); -} -void QEGLPlatformContext::swapBuffers() -{ -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglContext::swapBuffers:%p\n",this); -#endif - eglBindAPI(m_eglApi); - bool ok = eglSwapBuffers(m_eglDisplay, m_eglSurface); - if (!ok) - qWarning("QEGLPlatformContext::swapBuffers(): eglError: %d, this: %p \n", eglGetError(), this); -} -void* QEGLPlatformContext::getProcAddress(const QString& procName) -{ -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglContext::getProcAddress%p\n",this); -#endif - eglBindAPI(m_eglApi); - return (void *)eglGetProcAddress(qPrintable(procName)); -} - -QPlatformWindowFormat QEGLPlatformContext::platformWindowFormat() const -{ - return m_windowFormat; -} - -EGLContext QEGLPlatformContext::eglContext() const -{ - return m_eglContext; -} diff --git a/src/plugins/platforms/eglconvenience/qxlibeglintegration.cpp b/src/plugins/platforms/eglconvenience/qxlibeglintegration.cpp deleted file mode 100644 index cbd8f7d7c6..0000000000 --- a/src/plugins/platforms/eglconvenience/qxlibeglintegration.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qxlibeglintegration.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, EGLDisplay eglDisplay, EGLConfig config) -{ - VisualID visualId = 0; - EGLint eglValue = 0; - - 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/eglconvenience/xlibeglintegration.pri b/src/plugins/platforms/eglconvenience/xlibeglintegration.pri deleted file mode 100644 index 9404a70373..0000000000 --- a/src/plugins/platforms/eglconvenience/xlibeglintegration.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/qxlibeglintegration.h - -SOURCES += \ - $$PWD/qxlibeglintegration.cpp diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro index 471cf63dd8..73698322dd 100644 --- a/src/plugins/platforms/eglfs/eglfs.pro +++ b/src/plugins/platforms/eglfs/eglfs.pro @@ -2,7 +2,7 @@ TARGET = qeglfs TEMPLATE = lib CONFIG += plugin -QT += opengl core-private gui-private opengl-private +QT += opengl core-private gui-private opengl-private platformsupport-private widgets-private DESTDIR = $$QT.gui.plugins/platforms @@ -12,20 +12,16 @@ DESTDIR = $$QT.gui.plugins/platforms SOURCES = main.cpp \ qeglfsintegration.cpp \ - ../eglconvenience/qeglconvenience.cpp \ - ../eglconvenience/qeglplatformcontext.cpp \ qeglfswindow.cpp \ - qeglfswindowsurface.cpp \ + qeglfsbackingstore.cpp \ qeglfsscreen.cpp HEADERS = qeglfsintegration.h \ - ../eglconvenience/qeglconvenience.h \ - ../eglconvenience/qeglplatformcontext.h \ qeglfswindow.h \ - qeglfswindowsurface.h \ + qeglfsbackingstore.h \ qeglfsscreen.h -include(../fontdatabases/genericunix/genericunix.pri) +include(../../../platformsupport/fontdatabases/genericunix/genericunix.pri) target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/eglfs/qeglfswindowsurface.cpp b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp index 970402015f..1d27be7fb3 100644 --- a/src/plugins/platforms/eglfs/qeglfswindowsurface.cpp +++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp @@ -39,11 +39,13 @@ ** ****************************************************************************/ -#include "qeglfswindowsurface.h" +#include <QtOpenGL/private/qgl_p.h> -#include <QtGui/QPlatformGLContext> +#include "qeglfsbackingstore.h" + +#include <QtGui/QPlatformOpenGLContext> +#include <QtGui/QScreen> -#include <QtOpenGL/private/qgl_p.h> #include <QtOpenGL/private/qglpaintdevice_p.h> QT_BEGIN_NAMESPACE @@ -51,16 +53,16 @@ QT_BEGIN_NAMESPACE class QEglFSPaintDevice : public QGLPaintDevice { public: - QEglFSPaintDevice(QEglFSScreen *screen, QWidget *widget) + QEglFSPaintDevice(QEglFSScreen *screen) :QGLPaintDevice(), m_screen(screen) { #ifdef QEGL_EXTRA_DEBUG - qWarning("QEglPaintDevice %p, %p, %p",this, screen, widget); + qWarning("QEglPaintDevice %p, %p",this, screen); #endif } QSize size() const { return m_screen->geometry().size(); } - QGLContext* context() const { return QGLContext::fromPlatformGLContext(m_screen->platformContext());} + QGLContext* context() const { return QGLContext::fromOpenGLContext(m_screen->platformContext()->context()); } QPaintEngine *paintEngine() const { return qt_qgl_paint_engine(); } @@ -73,29 +75,30 @@ private: }; -QEglFSWindowSurface::QEglFSWindowSurface( QEglFSScreen *screen, QWidget *window ) - :QWindowSurface(window) +QEglFSBackingStore::QEglFSBackingStore(QWindow *window) + : QPlatformBackingStore(window) { #ifdef QEGL_EXTRA_DEBUG - qWarning("QEglWindowSurface %p, %p", window, screen); + qWarning("QEglBackingStore %p, %p", window, screen); #endif - m_paintDevice = new QEglFSPaintDevice(screen,window); + m_paintDevice = new QEglFSPaintDevice(static_cast<QEglFSScreen *>(window->screen()->handle())); } -void QEglFSWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QEglFSBackingStore::flush(QWindow *widget, const QRegion ®ion, const QPoint &offset) { Q_UNUSED(widget); Q_UNUSED(region); Q_UNUSED(offset); #ifdef QEGL_EXTRA_DEBUG - qWarning("QEglWindowSurface::flush %p",widget); + qWarning("QEglBackingStore::flush %p",widget); #endif - widget->platformWindow()->glContext()->swapBuffers(); + static_cast<QEglFSPaintDevice *>(m_paintDevice)->context()->swapBuffers(); } -void QEglFSWindowSurface::resize(const QSize &size) +void QEglFSBackingStore::resize(const QSize &size, const QRegion &staticContents) { Q_UNUSED(size); + Q_UNUSED(staticContents); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfswindowsurface.h b/src/plugins/platforms/eglfs/qeglfsbackingstore.h index 9ce8fd4f53..d6a28a7665 100644 --- a/src/plugins/platforms/eglfs/qeglfswindowsurface.h +++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.h @@ -45,19 +45,20 @@ #include "qeglfsintegration.h" #include "qeglfswindow.h" -#include <QtGui/private/qwindowsurface_p.h> +#include <QtGui/qplatformbackingstore_qpa.h> QT_BEGIN_NAMESPACE -class QEglFSWindowSurface : public QWindowSurface +class QEglFSBackingStore : public QPlatformBackingStore { public: - QEglFSWindowSurface(QEglFSScreen *screen, QWidget *window); - ~QEglFSWindowSurface() {} + QEglFSBackingStore(QWindow *window); + ~QEglFSBackingStore() {} QPaintDevice *paintDevice() { return m_paintDevice; } - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - void resize(const QSize &size); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + void resize(const QSize &size, const QRegion &staticContents); + private: QPaintDevice *m_paintDevice; }; diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index 9e8596f19e..3d3e05d351 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -42,13 +42,15 @@ #include "qeglfsintegration.h" #include "qeglfswindow.h" -#include "qeglfswindowsurface.h" +#include "qeglfsbackingstore.h" -#include "qgenericunixfontdatabase.h" +#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> #include <QtGui/QPlatformWindow> -#include <QtGui/QPlatformWindowFormat> -#include <QtGui/private/qpixmap_raster_p.h> +#include <QtGui/QSurfaceFormat> +#include <QtGui/QOpenGLContext> +#include <QtGui/QScreen> #include <EGL/egl.h> @@ -57,9 +59,8 @@ QT_BEGIN_NAMESPACE QEglFSIntegration::QEglFSIntegration() : mFontDb(new QGenericUnixFontDatabase()) { - m_primaryScreen = new QEglFSScreen(EGL_DEFAULT_DISPLAY); + screenAdded(new QEglFSScreen(EGL_DEFAULT_DISPLAY)); - mScreens.append(m_primaryScreen); #ifdef QEGL_EXTRA_DEBUG qWarning("QEglIntegration\n"); #endif @@ -69,36 +70,32 @@ bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) cons { switch (cap) { case ThreadedPixmaps: return true; + case OpenGL: return true; + case ThreadedOpenGL: return true; default: return QPlatformIntegration::hasCapability(cap); } } -QPixmapData *QEglFSIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const { #ifdef QEGL_EXTRA_DEBUG - qWarning("QEglIntegration::createPixmapData %d\n", type); + qWarning("QEglIntegration::createPlatformWindow %p\n",window); #endif - return new QRasterPixmapData(type); + return new QEglFSWindow(window); } -QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWidget *widget, WId winId) const + +QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *window) const { - Q_UNUSED(winId); #ifdef QEGL_EXTRA_DEBUG - qWarning("QEglIntegration::createPlatformWindow %p\n",widget); + qWarning("QEglIntegration::createWindowSurface %p\n",widget); #endif - return new QEglFSWindow(widget, m_primaryScreen); + return new QEglFSBackingStore(window); } - -QWindowSurface *QEglFSIntegration::createWindowSurface(QWidget *widget, WId winId) const +QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - Q_UNUSED(winId); - -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglIntegration::createWindowSurface %p\n",widget); -#endif - return new QEglFSWindowSurface(m_primaryScreen,widget); + return static_cast<QEglFSScreen *>(context->screen()->handle())->platformContext(); } QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const @@ -106,4 +103,9 @@ QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const return mFontDb; } +QAbstractEventDispatcher *QEglFSIntegration::guiThreadEventDispatcher() const +{ + return createUnixEventDispatcher(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index 6252a9c0e4..9538850faf 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -57,18 +57,17 @@ public: QEglFSIntegration(); bool hasCapability(QPlatformIntegration::Capability cap) const; - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; - QList<QPlatformScreen *> screens() const { return mScreens; } + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; QPlatformFontDatabase *fontDatabase() const; + QAbstractEventDispatcher *guiThreadEventDispatcher() const; + private: QPlatformFontDatabase *mFontDb; - QList<QPlatformScreen *> mScreens; - QEglFSScreen *m_primaryScreen; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp index 42195364ae..6f317a375f 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp @@ -40,9 +40,10 @@ ****************************************************************************/ #include "qeglfsscreen.h" +#include "qeglfswindow.h" -#include "../eglconvenience/qeglconvenience.h" -#include "../eglconvenience/qeglplatformcontext.h" +#include <QtPlatformSupport/private/qeglconvenience_p.h> +#include <QtPlatformSupport/private/qeglplatformcontext_p.h> #ifdef Q_OPENKODE #include <KD/kd.h> @@ -86,6 +87,23 @@ static struct AttrInfo attrs[] = { {-1, 0}}; #endif //QEGL_EXTRA_DEBUG +class QEglFSContext : public QEGLPlatformContext +{ +public: + QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, + EGLint eglClientVersion = 2, EGLenum eglApi = EGL_OPENGL_ES_API) + : QEGLPlatformContext(format, share, display, eglClientVersion, eglApi) + { + } + + EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) + { + QEglFSWindow *window = static_cast<QEglFSWindow *>(surface); + QEglFSScreen *screen = static_cast<QEglFSScreen *>(window->screen()); + return screen->surface(); + } +}; + QEglFSScreen::QEglFSScreen(EGLNativeDisplayType display) : m_depth(32) , m_format(QImage::Format_Invalid) @@ -136,32 +154,29 @@ void QEglFSScreen::createAndSetPlatformContext() const { void QEglFSScreen::createAndSetPlatformContext() { - QPlatformWindowFormat platformFormat = QPlatformWindowFormat::defaultFormat(); - - platformFormat.setWindowApi(QPlatformWindowFormat::OpenGL); + QSurfaceFormat platformFormat; QByteArray depthString = qgetenv("QT_QPA_EGLFS_DEPTH"); if (depthString.toInt() == 16) { - platformFormat.setDepth(16); + platformFormat.setDepthBufferSize(16); platformFormat.setRedBufferSize(5); platformFormat.setGreenBufferSize(6); platformFormat.setBlueBufferSize(5); m_depth = 16; m_format = QImage::Format_RGB16; } else { - platformFormat.setDepth(32); + platformFormat.setDepthBufferSize(32); platformFormat.setRedBufferSize(8); platformFormat.setGreenBufferSize(8); platformFormat.setBlueBufferSize(8); m_depth = 32; m_format = QImage::Format_RGB32; } - if (!qgetenv("QT_QPA_EGLFS_MULTISAMPLE").isEmpty()) { - platformFormat.setSampleBuffers(true); - } + if (!qgetenv("QT_QPA_EGLFS_MULTISAMPLE").isEmpty()) + platformFormat.setSamples(4); - EGLConfig config = q_configFromQPlatformWindowFormat(m_dpy, platformFormat); + EGLConfig config = q_configFromGLFormat(m_dpy, platformFormat); EGLNativeWindowType eglWindow = 0; #ifdef Q_OPENKODE @@ -193,16 +208,7 @@ void QEglFSScreen::createAndSetPlatformContext() qWarning("\n"); #endif - EGLint temp; - EGLint attribList[32]; - - temp = 0; - - attribList[temp++] = EGL_CONTEXT_CLIENT_VERSION; - attribList[temp++] = 2; // GLES version 2 - attribList[temp++] = EGL_NONE; - - QEGLPlatformContext *platformContext = new QEGLPlatformContext(m_dpy,config,attribList,m_surface,EGL_OPENGL_ES_API); + QEGLPlatformContext *platformContext = new QEglFSContext(platformFormat, 0, m_dpy); m_platformContext = platformContext; EGLint w,h; // screen size detection @@ -232,7 +238,7 @@ QImage::Format QEglFSScreen::format() const createAndSetPlatformContext(); return m_format; } -QPlatformGLContext *QEglFSScreen::platformContext() const +QPlatformOpenGLContext *QEglFSScreen::platformContext() const { if (!m_platformContext) { QEglFSScreen *that = const_cast<QEglFSScreen *>(this); diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h index 5cf1daca6f..41465d871c 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.h +++ b/src/plugins/platforms/eglfs/qeglfsscreen.h @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE -class QPlatformGLContext; +class QPlatformOpenGLContext; class QEglFSScreen : public QPlatformScreen //huh: FullScreenScreen ;) just to follow namespace { @@ -62,7 +62,9 @@ public: int depth() const; QImage::Format format() const; - QPlatformGLContext *platformContext() const; + QPlatformOpenGLContext *platformContext() const; + + EGLSurface surface() const { return m_surface; } private: void createAndSetPlatformContext() const; @@ -71,7 +73,7 @@ private: QRect m_geometry; int m_depth; QImage::Format m_format; - QPlatformGLContext *m_platformContext; + QPlatformOpenGLContext *m_platformContext; EGLDisplay m_dpy; EGLSurface m_surface; }; diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index 24b17b75e7..a6115cc829 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -45,25 +45,26 @@ QT_BEGIN_NAMESPACE -QEglFSWindow::QEglFSWindow(QWidget *w, QEglFSScreen *screen) - : QPlatformWindow(w), m_screen(screen) +QEglFSWindow::QEglFSWindow(QWindow *w) + : QPlatformWindow(w) { static int serialNo = 0; m_winid = ++serialNo; #ifdef QEGL_EXTRA_DEBUG - qWarning("QEglWindow %p: %p %p 0x%x\n", this, w, screen, uint(m_winid)); + qWarning("QEglWindow %p: %p 0x%x\n", this, w, uint(m_winid)); #endif -} + QRect screenGeometry(screen()->availableGeometry()); + if (w->geometry() != screenGeometry) { + QWindowSystemInterface::handleGeometryChange(w, screenGeometry); + } +} void QEglFSWindow::setGeometry(const QRect &) { // We only support full-screen windows - QRect rect(m_screen->availableGeometry()); - QWindowSystemInterface::handleGeometryChange(this->widget(), rect); - - // Since toplevels are fullscreen, propegate the screen size back to the widget - widget()->setGeometry(rect); + QRect rect(screen()->availableGeometry()); + QWindowSystemInterface::handleGeometryChange(window(), rect); QPlatformWindow::setGeometry(rect); } @@ -73,15 +74,4 @@ WId QEglFSWindow::winId() const return m_winid; } - - -QPlatformGLContext *QEglFSWindow::glContext() const -{ -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglWindow::glContext %p\n", m_screen->platformContext()); -#endif - Q_ASSERT(m_screen); - return m_screen->platformContext(); -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index 95a9ff51b9..09f553d3b7 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -46,22 +46,19 @@ #include "qeglfsscreen.h" #include <QPlatformWindow> -#include <QtGui/QWidget> +#include <QtWidgets/QWidget> QT_BEGIN_NAMESPACE class QEglFSWindow : public QPlatformWindow { public: - QEglFSWindow(QWidget *w, QEglFSScreen *screen); + QEglFSWindow(QWindow *w); void setGeometry(const QRect &); WId winId() const; - QPlatformGLContext *glContext() const; - private: - QEglFSScreen *m_screen; WId m_winid; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/externalplugin.pri b/src/plugins/platforms/externalplugin.pri deleted file mode 100644 index 9b00acb4e9..0000000000 --- a/src/plugins/platforms/externalplugin.pri +++ /dev/null @@ -1,29 +0,0 @@ -# -# Lighthouse now has preliminarily support for building and -# loading platform plugins from outside the Qt source/build -# tree. -# -# 1) Building external plugins: -# Set QTDIR to the Qt build directory, copy this file to -# the plugin source repository and include it at the top -# of the plugin's pro file. Use QT_SOURCE_TREE if you -# want to pull in source code from Qt: -# -# include($$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri) -# -# 2) Loading external plugins: -# Specify the path to the directory containing the -# plugin on the command line, in addition to the -# platform name. -# -# ./wiggly -platformPluginPath /path/to/myPlugin -platform gullfaksA -# - -!exists($$(QTDIR)/.qmake.cache) { - error("Please set QTDIR to the Qt build directory") -} - -QT_SOURCE_TREE = $$fromfile($$(QTDIR)/.qmake.cache,QT_SOURCE_TREE) -QT_BUILD_TREE = $$fromfile($$(QTDIR)/.qmake.cache,QT_BUILD_TREE) - -load(qt_plugin) diff --git a/src/plugins/platforms/fb_base/fb_base.cpp b/src/plugins/platforms/fb_base/fb_base.cpp deleted file mode 100644 index a83d739083..0000000000 --- a/src/plugins/platforms/fb_base/fb_base.cpp +++ /dev/null @@ -1,507 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "fb_base.h" -#include <qpainter.h> -#include <qdebug.h> -#include <qbitmap.h> -#include <QPlatformCursor> -#include <QWindowSystemInterface> - -QPlatformSoftwareCursor::QPlatformSoftwareCursor(QPlatformScreen *scr) - : QPlatformCursor(scr), currentRect(QRect()), prevRect(QRect()) -{ - graphic = new QPlatformCursorImage(0, 0, 0, 0, 0, 0); - setCursor(Qt::ArrowCursor); -} - -QRect QPlatformSoftwareCursor::getCurrentRect() -{ - QRect rect = graphic->image()->rect().translated(-graphic->hotspot().x(), - -graphic->hotspot().y()); - rect.translate(QCursor::pos()); - QPoint screenOffset = screen->geometry().topLeft(); - rect.translate(-screenOffset); // global to local translation - return rect; -} - - -void QPlatformSoftwareCursor::pointerEvent(const QMouseEvent & e) -{ - Q_UNUSED(e); - QPoint screenOffset = screen->geometry().topLeft(); - currentRect = getCurrentRect(); - // global to local translation - if (onScreen || screen->geometry().intersects(currentRect.translated(screenOffset))) { - setDirty(); - } -} - -QRect QPlatformSoftwareCursor::drawCursor(QPainter & painter) -{ - dirty = false; - if (currentRect.isNull()) - return QRect(); - - // We need this because the cursor might be dirty due to moving off screen - QPoint screenOffset = screen->geometry().topLeft(); - // global to local translation - if (!currentRect.translated(screenOffset).intersects(screen->geometry())) - return QRect(); - - prevRect = currentRect; - painter.drawImage(prevRect, *graphic->image()); - onScreen = true; - return prevRect; -} - -QRect QPlatformSoftwareCursor::dirtyRect() -{ - if (onScreen) { - onScreen = false; - return prevRect; - } - return QRect(); -} - -void QPlatformSoftwareCursor::setCursor(Qt::CursorShape shape) -{ - graphic->set(shape); -} - -void QPlatformSoftwareCursor::setCursor(const QImage &image, int hotx, int hoty) -{ - graphic->set(image, hotx, hoty); -} - -void QPlatformSoftwareCursor::setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY) -{ - graphic->set(data, mask, width, height, hotX, hotY); -} - -void QPlatformSoftwareCursor::changeCursor(QCursor * widgetCursor, QWidget * widget) -{ - Q_UNUSED(widget); - Qt::CursorShape shape = widgetCursor->shape(); - - if (shape == Qt::BitmapCursor) { - // application supplied cursor - QPoint spot = widgetCursor->hotSpot(); - setCursor(widgetCursor->pixmap().toImage(), spot.x(), spot.y()); - } else { - // system cursor - setCursor(shape); - } - currentRect = getCurrentRect(); - QPoint screenOffset = screen->geometry().topLeft(); // global to local translation - if (onScreen || screen->geometry().intersects(currentRect.translated(screenOffset))) - setDirty(); -} - -QFbScreen::QFbScreen() : cursor(0), mGeometry(), mDepth(16), mFormat(QImage::Format_RGB16), mScreenImage(0), compositePainter(0), isUpToDate(false) -{ - mScreenImage = new QImage(mGeometry.size(), mFormat); - redrawTimer.setSingleShot(true); - redrawTimer.setInterval(0); - QObject::connect(&redrawTimer, SIGNAL(timeout()), this, SLOT(doRedraw())); -} - -void QFbScreen::setGeometry(QRect rect) -{ - delete mScreenImage; - mGeometry = rect; - mScreenImage = new QImage(mGeometry.size(), mFormat); - delete compositePainter; - compositePainter = 0; - invalidateRectCache(); -} - -void QFbScreen::setDepth(int depth) -{ - mDepth = depth; -} - -void QFbScreen::setPhysicalSize(QSize size) -{ - mPhysicalSize = size; -} - -void QFbScreen::setFormat(QImage::Format format) -{ - mFormat = format; - delete mScreenImage; - mScreenImage = new QImage(mGeometry.size(), mFormat); - delete compositePainter; - compositePainter = 0; -} - -QFbScreen::~QFbScreen() -{ - delete compositePainter; - delete mScreenImage; -} - -void QFbScreen::setDirty(const QRect &rect) -{ - QRect intersection = rect.intersected(mGeometry); - QPoint screenOffset = mGeometry.topLeft(); - repaintRegion += intersection.translated(-screenOffset); // global to local translation - if (!redrawTimer.isActive()) { - redrawTimer.start(); - } -} - -void QFbScreen::generateRects() -{ - cachedRects.clear(); - QPoint screenOffset = mGeometry.topLeft(); - QRegion remainingScreen(mGeometry.translated(-screenOffset)); // global to local translation - - for (int i = 0; i < windowStack.length(); i++) { - if (remainingScreen.isEmpty()) - break; - if (!windowStack[i]->visible()) - continue; - if (windowStack[i]->widget()->isMinimized()) - continue; - - if (!windowStack[i]->widget()->testAttribute(Qt::WA_TranslucentBackground)) { - QRect localGeometry = windowStack.at(i)->geometry().translated(-screenOffset); // global to local translation - remainingScreen -= localGeometry; - QRegion windowRegion(localGeometry); - windowRegion -= remainingScreen; - foreach(QRect rect, windowRegion.rects()) { - cachedRects += QPair<QRect, int>(rect, i); - } - } - } - foreach (QRect rect, remainingScreen.rects()) - cachedRects += QPair<QRect, int>(rect, -1); - isUpToDate = true; - return; -} - - - -QRegion QFbScreen::doRedraw() -{ - QPoint screenOffset = mGeometry.topLeft(); - - QRegion touchedRegion; - if (cursor && cursor->isDirty() && cursor->isOnScreen()) { - QRect lastCursor = cursor->dirtyRect(); - repaintRegion += lastCursor; - } - if (repaintRegion.isEmpty() && (!cursor || !cursor->isDirty())) { - return touchedRegion; - } - - QVector<QRect> rects = repaintRegion.rects(); - - if (!isUpToDate) - generateRects(); - - if (!compositePainter) - compositePainter = new QPainter(mScreenImage); - for (int rectIndex = 0; rectIndex < repaintRegion.numRects(); rectIndex++) { - QRegion rectRegion = rects[rectIndex]; - - for(int i = 0; i < cachedRects.length(); i++) { - QRect screenSubRect = cachedRects[i].first; - int layer = cachedRects[i].second; - QRegion intersect = rectRegion.intersected(screenSubRect); - - if (intersect.isEmpty()) - continue; - - rectRegion -= intersect; - - // we only expect one rectangle, but defensive coding... - foreach (QRect rect, intersect.rects()) { - bool firstLayer = true; - if (layer == -1) { - compositePainter->fillRect(rect, Qt::black); - firstLayer = false; - layer = windowStack.size() - 1; - } - - for (int layerIndex = layer; layerIndex != -1; layerIndex--) { - if (!windowStack[layerIndex]->visible()) - continue; - if (windowStack[layerIndex]->widget()->isMinimized()) - continue; - QRect windowRect = windowStack[layerIndex]->geometry().translated(-screenOffset); - QRect windowIntersect = rect.translated(-windowRect.left(), - -windowRect.top()); - compositePainter->drawImage(rect, windowStack[layerIndex]->surface->image(), - windowIntersect); - if (firstLayer) { - firstLayer = false; - } - } - } - } - } - - QRect cursorRect; - if (cursor && (cursor->isDirty() || repaintRegion.intersects(cursor->lastPainted()))) { - cursorRect = cursor->drawCursor(*compositePainter); - touchedRegion += cursorRect; - } - touchedRegion += repaintRegion; - repaintRegion = QRegion(); - - - -// qDebug() << "QFbScreen::doRedraw" << windowStack.size() << mScreenImage->size() << touchedRegion; - - - return touchedRegion; -} - -void QFbScreen::addWindow(QFbWindow *surface) -{ - windowStack.prepend(surface); - surface->mScreens.append(this); - invalidateRectCache(); - setDirty(surface->geometry()); -} - -void QFbScreen::removeWindow(QFbWindow * surface) -{ - windowStack.removeOne(surface); - surface->mScreens.removeOne(this); - invalidateRectCache(); - setDirty(surface->geometry()); -} - -void QFbWindow::raise() -{ - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->raise(this); - ++i; - } -} - -void QFbScreen::raise(QPlatformWindow * surface) -{ - QFbWindow *s = static_cast<QFbWindow *>(surface); - int index = windowStack.indexOf(s); - if (index <= 0) - return; - windowStack.move(index, 0); - invalidateRectCache(); - setDirty(s->geometry()); -} - -void QFbWindow::lower() -{ - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->lower(this); - ++i; - } -} - -void QFbScreen::lower(QPlatformWindow * surface) -{ - QFbWindow *s = static_cast<QFbWindow *>(surface); - int index = windowStack.indexOf(s); - if (index == -1 || index == (windowStack.size() - 1)) - return; - windowStack.move(index, windowStack.size() - 1); - invalidateRectCache(); - setDirty(s->geometry()); -} - -QWidget * QFbScreen::topLevelAt(const QPoint & p) const -{ - for(int i = 0; i < windowStack.size(); i++) { - if (windowStack[i]->geometry().contains(p, false) && - windowStack[i]->visible() && - !windowStack[i]->widget()->isMinimized()) { - return windowStack[i]->widget(); - } - } - return 0; -} - -QFbWindow::QFbWindow(QWidget *window) - :QPlatformWindow(window), - visibleFlag(false) -{ - static QAtomicInt winIdGenerator(1); - windowId = winIdGenerator.fetchAndAddRelaxed(1); -} - - -QFbWindow::~QFbWindow() -{ - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->removeWindow(this); - ++i; - } -} - - -QFbWindowSurface::QFbWindowSurface(QFbScreen *screen, QWidget *window) - : QWindowSurface(window), - mScreen(screen) -{ - mImage = QImage(window->size(), mScreen->format()); - - platformWindow = static_cast<QFbWindow*>(window->platformWindow()); - platformWindow->surface = this; -} - -QFbWindowSurface::~QFbWindowSurface() -{ -} - -void QFbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) -{ - Q_UNUSED(widget); - Q_UNUSED(offset); - - -// qDebug() << "QFbWindowSurface::flush" << region; - - - platformWindow->repaint(region); -} - - -void QFbWindow::repaint(const QRegion ®ion) -{ - QRect currentGeometry = geometry(); - - QRect dirtyClient = region.boundingRect(); - QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(), - currentGeometry.top() + dirtyClient.top(), - dirtyClient.width(), - dirtyClient.height()); - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - QRect oldGeometryLocal = oldGeometry; - oldGeometry = currentGeometry; - while (i != end) { - // If this is a move, redraw the previous location - if (oldGeometryLocal != currentGeometry) { - (*i)->setDirty(oldGeometryLocal); - } - (*i)->setDirty(dirtyRegion); - ++i; - } -} - -void QFbWindowSurface::resize(const QSize &size) -{ - // change the widget's QImage if this is a resize - if (mImage.size() != size) - mImage = QImage(size, mScreen->format()); - QWindowSurface::resize(size); -} - -void QFbWindow::setGeometry(const QRect &rect) -{ -// store previous geometry for screen update - oldGeometry = geometry(); - - - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->invalidateRectCache(); - ++i; - } -//### QWindowSystemInterface::handleGeometryChange(window(), rect); - - QPlatformWindow::setGeometry(rect); -} - -bool QFbWindowSurface::scroll(const QRegion &area, int dx, int dy) -{ - return QWindowSurface::scroll(area, dx, dy); -} - -void QFbWindowSurface::beginPaint(const QRegion ®ion) -{ - Q_UNUSED(region); -} - -void QFbWindowSurface::endPaint(const QRegion ®ion) -{ - Q_UNUSED(region); -} - -void QFbWindow::setVisible(bool visible) -{ - visibleFlag = visible; - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->invalidateRectCache(); - (*i)->setDirty(geometry()); - ++i; - } -} - -Qt::WindowFlags QFbWindow::setWindowFlags(Qt::WindowFlags type) -{ - flags = type; - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->invalidateRectCache(); - ++i; - } - return flags; -} - -Qt::WindowFlags QFbWindow::windowFlags() const -{ - return flags; -} diff --git a/src/plugins/platforms/fb_base/fb_base.h b/src/plugins/platforms/fb_base/fb_base.h deleted file mode 100644 index 6b0b152482..0000000000 --- a/src/plugins/platforms/fb_base/fb_base.h +++ /dev/null @@ -1,210 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QLIGHTHOUSEGRAPHICSSCREEN_H -#define QLIGHTHOUSEGRAPHICSSCREEN_H - -#include <qrect.h> -#include <qimage.h> -#include <qtimer.h> -#include <qpainter.h> -#include <QPlatformCursor> -#include <QPlatformScreen> -#include <QPlatformWindow> -#include <QtGui/private/qwindowsurface_p.h> - -class QMouseEvent; -class QSize; -class QPainter; - -class QFbScreen; - -class QPlatformSoftwareCursor : public QPlatformCursor -{ -public: - QPlatformSoftwareCursor(QPlatformScreen * scr); - - // output methods - QRect dirtyRect(); - virtual QRect drawCursor(QPainter & painter); - - // input methods - virtual void pointerEvent(const QMouseEvent & event); - virtual void changeCursor(QCursor * widgetCursor, QWidget * widget); - - virtual void setDirty() { dirty = true; screen->setDirty(QRect()); } - virtual bool isDirty() { return dirty; } - virtual bool isOnScreen() { return onScreen; } - virtual QRect lastPainted() { return prevRect; } - -protected: - QPlatformCursorImage * graphic; - -private: - void setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY); - void setCursor(Qt::CursorShape shape); - void setCursor(const QImage &image, int hotx, int hoty); - QRect currentRect; // next place to draw the cursor - QRect prevRect; // last place the cursor was drawn - QRect getCurrentRect(); - bool dirty; - bool onScreen; -}; - -class QFbWindow; - -class QFbWindowSurface : public QWindowSurface -{ -public: - QFbWindowSurface(QFbScreen *screen, QWidget *window); - ~QFbWindowSurface(); - - virtual QPaintDevice *paintDevice() { return &mImage; } - virtual void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - virtual bool scroll(const QRegion &area, int dx, int dy); - - virtual void beginPaint(const QRegion ®ion); - virtual void endPaint(const QRegion ®ion); - - - const QImage image() { return mImage; } - void resize(const QSize &size); - -protected: - friend class QFbWindow; - QFbWindow *platformWindow; - - QFbScreen *mScreen; - QImage mImage; -}; - - -class QFbWindow : public QPlatformWindow -{ -public: - - QFbWindow(QWidget *window); - ~QFbWindow(); - - - virtual void setVisible(bool visible); - virtual bool visible() { return visibleFlag; } - - virtual void raise(); - virtual void lower(); - - void setGeometry(const QRect &rect); - - virtual Qt::WindowFlags setWindowFlags(Qt::WindowFlags type); - virtual Qt::WindowFlags windowFlags() const; - - WId winId() const { return windowId; } - - virtual void repaint(const QRegion&); - -protected: - friend class QFbWindowSurface; - friend class QFbScreen; - QFbWindowSurface *surface; - QList<QFbScreen *> mScreens; - QRect oldGeometry; - bool visibleFlag; - Qt::WindowFlags flags; - - WId windowId; -}; - -class QFbScreen : public QPlatformScreen -{ - Q_OBJECT -public: - QFbScreen(); - ~QFbScreen(); - - virtual QRect geometry() const { return mGeometry; } - virtual int depth() const { return mDepth; } - virtual QImage::Format format() const { return mFormat; } - virtual QSize physicalSize() const { return mPhysicalSize; } - - virtual void setGeometry(QRect rect); - virtual void setDepth(int depth); - virtual void setFormat(QImage::Format format); - virtual void setPhysicalSize(QSize size); - - virtual void setDirty(const QRect &rect); - - virtual void removeWindow(QFbWindow * surface); - virtual void addWindow(QFbWindow * surface); - virtual void raise(QPlatformWindow * surface); - virtual void lower(QPlatformWindow * surface); - virtual QWidget * topLevelAt(const QPoint & p) const; - - QImage * image() const { return mScreenImage; } - QPaintDevice * paintDevice() const { return mScreenImage; } - -protected: - QList<QFbWindow *> windowStack; - QRegion repaintRegion; - QPlatformSoftwareCursor * cursor; - QTimer redrawTimer; - -protected slots: - virtual QRegion doRedraw(); - -protected: - QRect mGeometry; - int mDepth; - QImage::Format mFormat; - QSize mPhysicalSize; - QImage *mScreenImage; - -private: - QPainter * compositePainter; - void generateRects(); - QList<QPair<QRect, int> > cachedRects; - - void invalidateRectCache() { isUpToDate = false; } - friend class QFbWindowSurface; - friend class QFbWindow; - bool isUpToDate; -}; - -#endif // QLIGHTHOUSEGRAPHICSSCREEN_H diff --git a/src/plugins/platforms/fb_base/fb_base.pri b/src/plugins/platforms/fb_base/fb_base.pri deleted file mode 100644 index 41bd87fbca..0000000000 --- a/src/plugins/platforms/fb_base/fb_base.pri +++ /dev/null @@ -1,2 +0,0 @@ -SOURCES += ../fb_base/fb_base.cpp -HEADERS += ../fb_base/fb_base.h diff --git a/src/plugins/platforms/fb_base/fb_base.pro b/src/plugins/platforms/fb_base/fb_base.pro deleted file mode 100644 index 4ebd53b407..0000000000 --- a/src/plugins/platforms/fb_base/fb_base.pro +++ /dev/null @@ -1,23 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2009-11-05T13:22:31 -# -#------------------------------------------------- - -#QT -= core gui -TARGET = fb_base -#load(qt_plugin) - -DESTDIR = $$QT.gui.plugins/graphicssystems - -TEMPLATE = lib - -#DEFINES += STATIC_LIBRARY -CONFIG += staticlib - -SOURCES += fb_base.cpp - -HEADERS += fb_base.h - -target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems -INSTALLS += target diff --git a/src/plugins/platforms/fontdatabases/basicunix/basicunix.pri b/src/plugins/platforms/fontdatabases/basicunix/basicunix.pri deleted file mode 100644 index c1fbf3e411..0000000000 --- a/src/plugins/platforms/fontdatabases/basicunix/basicunix.pri +++ /dev/null @@ -1,88 +0,0 @@ -DEFINES += QT_NO_FONTCONFIG -HEADERS += \ - $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h \ - $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft_p.h - -SOURCES += \ - $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp \ - $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft.cpp - -DEFINES += QT_COMPILES_IN_HARFBUZZ - -INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src - -INCLUDEPATH += $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/basicunix - -CONFIG += opentype - -contains(QT_CONFIG, freetype) { - SOURCES += \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftbase.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftbbox.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftdebug.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftglyph.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftinit.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftmm.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/fttype1.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftsynth.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftbitmap.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/bdf/bdf.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/cache/ftcache.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/cff/cff.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/cid/type1cid.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/gzip/ftgzip.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/pcf/pcf.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/pfr/pfr.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/psaux/psaux.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/pshinter/pshinter.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/psnames/psmodule.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/raster/raster.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/sfnt/sfnt.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/smooth/smooth.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/truetype/truetype.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/type1/type1.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/type42/type42.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/winfonts/winfnt.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/lzw/ftlzw.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvalid.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvbase.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvgdef.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvjstf.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvcommn.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvgpos.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvgsub.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvmod.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afangles.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afglobal.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/aflatin.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afmodule.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afdummy.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afhints.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afloader.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/autofit.c - - symbian { - SOURCES += \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftsystem.c - } else { - SOURCES += \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/builds/unix/ftsystem.c - INCLUDEPATH += \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/builds/unix - } - - INCLUDEPATH += \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/include - - DEFINES += FT2_BUILD_LIBRARY - contains(QT_CONFIG, system-zlib) { - DEFINES += FT_CONFIG_OPTION_SYSTEM_ZLIB - } - - } else:contains(QT_CONFIG, system-freetype) { - # pull in the proper freetype2 include directory - include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri) - LIBS_PRIVATE += -lfreetype - } - diff --git a/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp b/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp deleted file mode 100644 index d91cce59a9..0000000000 --- a/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp +++ /dev/null @@ -1,355 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qbasicunixfontdatabase.h" - -#include <QtGui/private/qapplication_p.h> -#include <QtGui/QPlatformScreen> - -#include <QtCore/QFile> -#include <QtCore/QLibraryInfo> -#include <QtCore/QDir> - -#undef QT_NO_FREETYPE -#include <QtGui/private/qfontengine_ft_p.h> -#include <QtGui/private/qfontengine_p.h> - -#include <ft2build.h> -#include FT_TRUETYPE_TABLES_H - -#define SimplifiedChineseCsbBit 18 -#define TraditionalChineseCsbBit 20 -#define JapaneseCsbBit 17 -#define KoreanCsbBit 21 - -static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { - // Any, - { 127, 127 }, - // Latin, - { 0, 127 }, - // Greek, - { 7, 127 }, - // Cyrillic, - { 9, 127 }, - // Armenian, - { 10, 127 }, - // Hebrew, - { 11, 127 }, - // Arabic, - { 13, 127 }, - // Syriac, - { 71, 127 }, - //Thaana, - { 72, 127 }, - //Devanagari, - { 15, 127 }, - //Bengali, - { 16, 127 }, - //Gurmukhi, - { 17, 127 }, - //Gujarati, - { 18, 127 }, - //Oriya, - { 19, 127 }, - //Tamil, - { 20, 127 }, - //Telugu, - { 21, 127 }, - //Kannada, - { 22, 127 }, - //Malayalam, - { 23, 127 }, - //Sinhala, - { 73, 127 }, - //Thai, - { 24, 127 }, - //Lao, - { 25, 127 }, - //Tibetan, - { 70, 127 }, - //Myanmar, - { 74, 127 }, - // Georgian, - { 26, 127 }, - // Khmer, - { 80, 127 }, - // SimplifiedChinese, - { 126, 127 }, - // TraditionalChinese, - { 126, 127 }, - // Japanese, - { 126, 127 }, - // Korean, - { 56, 127 }, - // Vietnamese, - { 0, 127 }, // same as latin1 - // Other, - { 126, 127 }, - // Ogham, - { 78, 127 }, - // Runic, - { 79, 127 }, - // Nko, - { 14, 127 }, -}; - -static QSupportedWritingSystems determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]) -{ - QSupportedWritingSystems writingSystems; - bool hasScript = false; - - int i; - for(i = 0; i < QFontDatabase::WritingSystemsCount; i++) { - int bit = requiredUnicodeBits[i][0]; - int index = bit/32; - int flag = 1 << (bit&31); - if (bit != 126 && unicodeRange[index] & flag) { - bit = requiredUnicodeBits[i][1]; - index = bit/32; - - flag = 1 << (bit&31); - if (bit == 127 || unicodeRange[index] & flag) { - writingSystems.setSupported(QFontDatabase::WritingSystem(i)); - hasScript = true; - // qDebug("font %s: index=%d, flag=%8x supports script %d", familyName.latin1(), index, flag, i); - } - } - } - if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) { - writingSystems.setSupported(QFontDatabase::SimplifiedChinese); - hasScript = true; - //qDebug("font %s supports Simplified Chinese", familyName.latin1()); - } - if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) { - writingSystems.setSupported(QFontDatabase::TraditionalChinese); - hasScript = true; - //qDebug("font %s supports Traditional Chinese", familyName.latin1()); - } - if(codePageRange[0] & (1 << JapaneseCsbBit)) { - writingSystems.setSupported(QFontDatabase::Japanese); - hasScript = true; - //qDebug("font %s supports Japanese", familyName.latin1()); - } - if(codePageRange[0] & (1 << KoreanCsbBit)) { - writingSystems.setSupported(QFontDatabase::Korean); - hasScript = true; - //qDebug("font %s supports Korean", familyName.latin1()); - } - if (!hasScript) - writingSystems.setSupported(QFontDatabase::Symbol); - - return writingSystems; -} - -static inline bool scriptRequiresOpenType(int script) -{ - return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) - || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); -} - -void QBasicUnixFontDatabase::populateFontDatabase() -{ - QPlatformFontDatabase::populateFontDatabase(); - QString fontpath = fontDir(); - - if(!QFile::exists(fontpath)) { - qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?", - qPrintable(fontpath)); - } - - QDir dir(fontpath); - dir.setNameFilters(QStringList() << QLatin1String("*.ttf") - << QLatin1String("*.ttc") << QLatin1String("*.pfa") - << QLatin1String("*.pfb")); - dir.refresh(); - for (int i = 0; i < int(dir.count()); ++i) { - const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i])); -// qDebug() << "looking at" << file; - addTTFile(QByteArray(), file); - } -} - -QFontEngine *QBasicUnixFontDatabase::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *usrPtr) -{ - QFontEngineFT *engine; - FontFile *fontfile = static_cast<FontFile *> (usrPtr); - QFontEngine::FaceId fid; - fid.filename = fontfile->fileName.toLocal8Bit(); - fid.index = fontfile->indexValue; - engine = new QFontEngineFT(fontDef); - - bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); - QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; - if (!engine->init(fid,antialias,format)) { - delete engine; - engine = 0; - return engine; - } - if (engine->invalid()) { - delete engine; - engine = 0; - } else if (scriptRequiresOpenType(script)) { - HB_Face hbFace = engine->harfbuzzFace(); - if (!hbFace || !hbFace->supported_scripts[script]) { - delete engine; - engine = 0; - } - } - - return engine; -} - -QStringList QBasicUnixFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const -{ - Q_UNUSED(family); - Q_UNUSED(style); - Q_UNUSED(script); - return QStringList(); -} - -QStringList QBasicUnixFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) -{ - return addTTFile(fontData,fileName.toLocal8Bit()); -} - -void QBasicUnixFontDatabase::releaseHandle(void *handle) -{ - FontFile *file = static_cast<FontFile *>(handle); - delete file; -} - -QStringList QBasicUnixFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file) -{ - extern FT_Library qt_getFreetype(); - FT_Library library = qt_getFreetype(); - - int index = 0; - int numFaces = 0; - QStringList families; - do { - FT_Face face; - FT_Error error; - if (!fontData.isEmpty()) { - error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); - } else { - error = FT_New_Face(library, file.constData(), index, &face); - } - if (error != FT_Err_Ok) { - qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; - break; - } - numFaces = face->num_faces; - - QFont::Weight weight = QFont::Normal; - - QFont::Style style = QFont::StyleNormal; - if (face->style_flags & FT_STYLE_FLAG_ITALIC) - style = QFont::StyleItalic; - - if (face->style_flags & FT_STYLE_FLAG_BOLD) - weight = QFont::Bold; - - QSupportedWritingSystems writingSystems; - // detect symbol fonts - for (int i = 0; i < face->num_charmaps; ++i) { - FT_CharMap cm = face->charmaps[i]; - if (cm->encoding == ft_encoding_adobe_custom - || cm->encoding == ft_encoding_symbol) { - writingSystems.setSupported(QFontDatabase::Symbol); - break; - } - } - - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); - if (os2) { - quint32 unicodeRange[4] = { - os2->ulUnicodeRange1, os2->ulUnicodeRange2, os2->ulUnicodeRange3, os2->ulUnicodeRange4 - }; - quint32 codePageRange[2] = { - os2->ulCodePageRange1, os2->ulCodePageRange2 - }; - - writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - - if (os2->usWeightClass == 0) - ; - else if (os2->usWeightClass < 350) - weight = QFont::Light; - else if (os2->usWeightClass < 450) - weight = QFont::Normal; - else if (os2->usWeightClass < 650) - weight = QFont::DemiBold; - else if (os2->usWeightClass < 750) - weight = QFont::Bold; - else if (os2->usWeightClass < 1000) - weight = QFont::Black; - - if (os2->panose[2] >= 2) { - int w = os2->panose[2]; - if (w <= 3) - weight = QFont::Light; - else if (w <= 5) - weight = QFont::Normal; - else if (w <= 7) - weight = QFont::DemiBold; - else if (w <= 8) - weight = QFont::Bold; - else if (w <= 10) - weight = QFont::Black; - } - } - - QString family = QString::fromAscii(face->family_name); - FontFile *fontFile = new FontFile; - fontFile->fileName = file; - fontFile->indexValue = index; - - QFont::Stretch stretch = QFont::Unstretched; - - registerFont(family,"",weight,style,stretch,true,true,0,writingSystems,fontFile); - - families.append(family); - - FT_Done_Face(face); - ++index; - } while (index < numFaces); - return families; -} diff --git a/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h b/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h deleted file mode 100644 index 0e17ed55b6..0000000000 --- a/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QBASICUNIXFONTDATABASE_H -#define QBASICUNIXFONTDATABASE_H - -#include <QPlatformFontDatabase> -#include <QtCore/QByteArray> -#include <QtCore/QString> - -struct FontFile -{ - QString fileName; - int indexValue; -}; - -class QBasicUnixFontDatabase : public QPlatformFontDatabase -{ -public: - void populateFontDatabase(); - QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); - QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const; - QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); - void releaseHandle(void *handle); - - static QStringList addTTFile(const QByteArray &fontData, const QByteArray &file); -}; - -#endif // QBASICUNIXFONTDATABASE_H diff --git a/src/plugins/platforms/fontdatabases/fontconfig/fontconfig.pri b/src/plugins/platforms/fontdatabases/fontconfig/fontconfig.pri deleted file mode 100644 index 19c74ed089..0000000000 --- a/src/plugins/platforms/fontdatabases/fontconfig/fontconfig.pri +++ /dev/null @@ -1,12 +0,0 @@ -include(../basicunix/basicunix.pri) - -HEADERS += \ - $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h - -SOURCES += \ - $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp - -INCLUDEPATH += $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/fontconfig -LIBS_PRIVATE += -lfontconfig - - diff --git a/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp deleted file mode 100644 index 50cf4ed75a..0000000000 --- a/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qfontconfigdatabase.h" - -#include <QtCore/QList> -#include <QtGui/private/qfont_p.h> - -#include <QtCore/QElapsedTimer> - -#include <QtGui/private/qapplication_p.h> -#include <QtGui/QPlatformScreen> - -#include <QtGui/private/qfontengine_ft_p.h> -#include <QtGui/private/qfontengine_p.h> - - - -#include <ft2build.h> -#include FT_TRUETYPE_TABLES_H - -#include <fontconfig/fontconfig.h> - -#define SimplifiedChineseCsbBit 18 -#define TraditionalChineseCsbBit 20 -#define JapaneseCsbBit 17 -#define KoreanCsbBit 21 - -static inline bool requiresOpenType(int writingSystem) -{ - return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala) - || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko); -} -static inline bool scriptRequiresOpenType(int script) -{ - return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) - || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); -} - -static int getFCWeight(int fc_weight) -{ - int qtweight = QFont::Black; - if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2) - qtweight = QFont::Light; - else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) - qtweight = QFont::Normal; - else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) - qtweight = QFont::DemiBold; - else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2) - qtweight = QFont::Bold; - - return qtweight; -} - -static const char *specialLanguages[] = { - "en", // Common - "el", // Greek - "ru", // Cyrillic - "hy", // Armenian - "he", // Hebrew - "ar", // Arabic - "syr", // Syriac - "div", // Thaana - "hi", // Devanagari - "bn", // Bengali - "pa", // Gurmukhi - "gu", // Gujarati - "or", // Oriya - "ta", // Tamil - "te", // Telugu - "kn", // Kannada - "ml", // Malayalam - "si", // Sinhala - "th", // Thai - "lo", // Lao - "bo", // Tibetan - "my", // Myanmar - "ka", // Georgian - "ko", // Hangul - "", // Ogham - "", // Runic - "km", // Khmer - "" // N'Ko -}; -enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) }; - -static const ushort specialChars[] = { - 0, // English - 0, // Greek - 0, // Cyrillic - 0, // Armenian - 0, // Hebrew - 0, // Arabic - 0, // Syriac - 0, // Thaana - 0, // Devanagari - 0, // Bengali - 0, // Gurmukhi - 0, // Gujarati - 0, // Oriya - 0, // Tamil - 0xc15, // Telugu - 0xc95, // Kannada - 0xd15, // Malayalam - 0xd9a, // Sinhala - 0, // Thai - 0, // Lao - 0, // Tibetan - 0x1000, // Myanmar - 0, // Georgian - 0, // Hangul - 0x1681, // Ogham - 0x16a0, // Runic - 0, // Khmer - 0x7ca // N'Ko -}; -enum { SpecialCharCount = sizeof(specialChars) / sizeof(ushort) }; - -// this could become a list of all languages used for each writing -// system, instead of using the single most common language. -static const char *languageForWritingSystem[] = { - 0, // Any - "en", // Latin - "el", // Greek - "ru", // Cyrillic - "hy", // Armenian - "he", // Hebrew - "ar", // Arabic - "syr", // Syriac - "div", // Thaana - "hi", // Devanagari - "bn", // Bengali - "pa", // Gurmukhi - "gu", // Gujarati - "or", // Oriya - "ta", // Tamil - "te", // Telugu - "kn", // Kannada - "ml", // Malayalam - "si", // Sinhala - "th", // Thai - "lo", // Lao - "bo", // Tibetan - "my", // Myanmar - "ka", // Georgian - "km", // Khmer - "zh-cn", // SimplifiedChinese - "zh-tw", // TraditionalChinese - "ja", // Japanese - "ko", // Korean - "vi", // Vietnamese - 0, // Symbol - 0, // Ogham - 0, // Runic - 0 // N'Ko -}; -enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) }; - -// Unfortunately FontConfig doesn't know about some languages. We have to test these through the -// charset. The lists below contain the systems where we need to do this. -static const ushort sampleCharForWritingSystem[] = { - 0, // Any - 0, // Latin - 0, // Greek - 0, // Cyrillic - 0, // Armenian - 0, // Hebrew - 0, // Arabic - 0, // Syriac - 0, // Thaana - 0, // Devanagari - 0, // Bengali - 0, // Gurmukhi - 0, // Gujarati - 0, // Oriya - 0, // Tamil - 0xc15, // Telugu - 0xc95, // Kannada - 0xd15, // Malayalam - 0xd9a, // Sinhala - 0, // Thai - 0, // Lao - 0, // Tibetan - 0x1000, // Myanmar - 0, // Georgian - 0, // Khmer - 0, // SimplifiedChinese - 0, // TraditionalChinese - 0, // Japanese - 0, // Korean - 0, // Vietnamese - 0, // Symbol - 0x1681, // Ogham - 0x16a0, // Runic - 0x7ca // N'Ko -}; -enum { SampleCharCount = sizeof(sampleCharForWritingSystem) / sizeof(ushort) }; - -// Newer FontConfig let's us sort out fonts that contain certain glyphs, but no -// open type tables for is directly. Do this so we don't pick some strange -// pseudo unicode font -static const char *openType[] = { - 0, // Any - 0, // Latin - 0, // Greek - 0, // Cyrillic - 0, // Armenian - 0, // Hebrew - 0, // Arabic - "syrc", // Syriac - "thaa", // Thaana - "deva", // Devanagari - "beng", // Bengali - "guru", // Gurmukhi - "gurj", // Gujarati - "orya", // Oriya - "taml", // Tamil - "telu", // Telugu - "knda", // Kannada - "mlym", // Malayalam - "sinh", // Sinhala - 0, // Thai - 0, // Lao - "tibt", // Tibetan - "mymr", // Myanmar - 0, // Georgian - "khmr", // Khmer - 0, // SimplifiedChinese - 0, // TraditionalChinese - 0, // Japanese - 0, // Korean - 0, // Vietnamese - 0, // Symbol - 0, // Ogham - 0, // Runic - "nko " // N'Ko -}; - -static const char *getFcFamilyForStyleHint(const QFont::StyleHint style) -{ - const char *stylehint = 0; - switch (style) { - case QFont::SansSerif: - stylehint = "sans-serif"; - break; - case QFont::Serif: - stylehint = "serif"; - break; - case QFont::TypeWriter: - stylehint = "monospace"; - break; - default: - break; - } - return stylehint; -} - -void QFontconfigDatabase::populateFontDatabase() -{ - FcFontSet *fonts; - - QString familyName; - FcChar8 *value = 0; - int weight_value; - int slant_value; - int spacing_value; - FcChar8 *file_value; - int indexValue; - FcChar8 *foundry_value; - FcBool scalable; - FcBool antialias; - - { - FcObjectSet *os = FcObjectSetCreate(); - FcPattern *pattern = FcPatternCreate(); - const char *properties [] = { - FC_FAMILY, FC_WEIGHT, FC_SLANT, - FC_SPACING, FC_FILE, FC_INDEX, - FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT, - FC_WIDTH, -#if FC_VERSION >= 20297 - FC_CAPABILITY, -#endif - (const char *)0 - }; - const char **p = properties; - while (*p) { - FcObjectSetAdd(os, *p); - ++p; - } - fonts = FcFontList(0, pattern, os); - FcObjectSetDestroy(os); - FcPatternDestroy(pattern); - } - - for (int i = 0; i < fonts->nfont; i++) { - if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) - continue; - // capitalize(value); - familyName = QString::fromUtf8((const char *)value); - slant_value = FC_SLANT_ROMAN; - weight_value = FC_WEIGHT_MEDIUM; - spacing_value = FC_PROPORTIONAL; - file_value = 0; - indexValue = 0; - scalable = FcTrue; - - - if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch) - slant_value = FC_SLANT_ROMAN; - if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch) - weight_value = FC_WEIGHT_MEDIUM; - if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch) - spacing_value = FC_PROPORTIONAL; - if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch) - file_value = 0; - if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &indexValue) != FcResultMatch) - indexValue = 0; - if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch) - scalable = FcTrue; - if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch) - foundry_value = 0; - if(FcPatternGetBool(fonts->fonts[i],FC_ANTIALIAS,0,&antialias) != FcResultMatch) - antialias = true; - - QSupportedWritingSystems writingSystems; - FcLangSet *langset = 0; - FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset); - if (res == FcResultMatch) { - for (int i = 1; i < LanguageCount; ++i) { - const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i]; - if (lang) { - FcLangResult langRes = FcLangSetHasLang(langset, lang); - if (langRes != FcLangDifferentLang) - writingSystems.setSupported(QFontDatabase::WritingSystem(i)); - } - } - } else { - // we set Other to supported for symbol fonts. It makes no - // sense to merge these with other ones, as they are - // special in a way. - writingSystems.setSupported(QFontDatabase::Other); - } - - FcCharSet *cs = 0; - res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs); - if (res == FcResultMatch) { - // some languages are not supported by FontConfig, we rather check the - // charset to detect these - for (int i = 1; i < SampleCharCount; ++i) { - if (!sampleCharForWritingSystem[i]) - continue; - if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i])) - writingSystems.setSupported(QFontDatabase::WritingSystem(i)); - } - } - -#if FC_VERSION >= 20297 - for (int j = 1; j < LanguageCount; ++j) { - if (writingSystems.supported(QFontDatabase::WritingSystem(j)) - && requiresOpenType(j) && openType[j]) { - FcChar8 *cap; - res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap); - if (res != FcResultMatch || !strstr((const char *)cap, openType[j])) - writingSystems.setSupported(QFontDatabase::WritingSystem(j),false); - } - } -#endif - - FontFile *fontFile = new FontFile; - fontFile->fileName = QLatin1String((const char *)file_value); - fontFile->indexValue = indexValue; - - QFont::Style style = (slant_value == FC_SLANT_ITALIC) - ? QFont::StyleItalic - : ((slant_value == FC_SLANT_OBLIQUE) - ? QFont::StyleOblique - : QFont::StyleNormal); - QFont::Weight weight = QFont::Weight(getFCWeight(weight_value)); - - double pixel_size = 0; - if (!scalable) { - int width = 100; - FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width); - FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size); - } - - QFont::Stretch stretch = QFont::Unstretched; - QPlatformFontDatabase::registerFont(familyName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,writingSystems,fontFile); -// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; - } - - FcFontSetDestroy (fonts); - - struct FcDefaultFont { - const char *qtname; - const char *rawname; - bool fixed; - }; - const FcDefaultFont defaults[] = { - { "Serif", "serif", false }, - { "Sans Serif", "sans-serif", false }, - { "Monospace", "monospace", true }, - { 0, 0, false } - }; - const FcDefaultFont *f = defaults; - // aliases only make sense for 'common', not for any of the specials - QSupportedWritingSystems ws; - ws.setSupported(QFontDatabase::Latin); - - - while (f->qtname) { - registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,ws,0); - registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,ws,0); - registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,ws,0); - ++f; - } - - //Lighthouse has very lazy population of the font db. We want it to be initialized when - //QApplication is constructed, so that the population procedure can do something like this to - //set the default font -// const FcDefaultFont *s = defaults; -// QFont font("Sans Serif"); -// font.setPointSize(9); -// QApplication::setFont(font); -} - -QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QUnicodeTables::Script script, void *usrPtr) -{ - if (!usrPtr) - return 0; - QFontDef fontDef = f; - - QFontEngineFT *engine; - FontFile *fontfile = static_cast<FontFile *> (usrPtr); - QFontEngine::FaceId fid; - fid.filename = fontfile->fileName.toLocal8Bit(); - fid.index = fontfile->indexValue; - - bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); - QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; - - engine = new QFontEngineFT(fontDef); - - // try and get the pattern - FcPattern *pattern = FcPatternCreate(); - - FcValue value; - value.type = FcTypeString; - QByteArray cs = fontDef.family.toUtf8(); - value.u.s = (const FcChar8 *)cs.data(); - FcPatternAdd(pattern,FC_FAMILY,value,true); - - - value.u.s = (const FcChar8 *)fid.filename.data(); - FcPatternAdd(pattern,FC_FILE,value,true); - - value.type = FcTypeInteger; - value.u.i = fid.index; - FcPatternAdd(pattern,FC_INDEX,value,true); - - if (FcConfigSubstitute(0,pattern,FcMatchPattern)) { - QFontEngineFT::HintStyle default_hint_style; - - //hinting - int hint_style = 0; - if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch) - hint_style = QFontEngineFT::HintFull; - switch (hint_style) { - case FC_HINT_NONE: - default_hint_style = QFontEngineFT::HintNone; - break; - case FC_HINT_SLIGHT: - default_hint_style = QFontEngineFT::HintLight; - break; - case FC_HINT_MEDIUM: - default_hint_style = QFontEngineFT::HintMedium; - break; - default: - default_hint_style = QFontEngineFT::HintFull; - break; - } - engine->setDefaultHintStyle(default_hint_style); - } - FcPatternDestroy(pattern); - - if (!engine->init(fid,antialias,format)) { - delete engine; - engine = 0; - return engine; - } - if (engine->invalid()) { - delete engine; - engine = 0; - } else if (scriptRequiresOpenType(script)) { - HB_Face hbFace = engine->harfbuzzFace(); - if (!hbFace || !hbFace->supported_scripts[script]) { - delete engine; - engine = 0; - } - } - - return engine; -} - -QStringList QFontconfigDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const -{ - QStringList fallbackFamilies; - FcPattern *pattern = FcPatternCreate(); - if (!pattern) - return fallbackFamilies; - - FcValue value; - value.type = FcTypeString; - QByteArray cs = family.toUtf8(); - value.u.s = (const FcChar8 *)cs.data(); - FcPatternAdd(pattern,FC_FAMILY,value,true); - - int slant_value = FC_SLANT_ROMAN; - if (style == QFont::StyleItalic) - slant_value = FC_SLANT_ITALIC; - else if (style == QFont::StyleOblique) - slant_value = FC_SLANT_OBLIQUE; - FcPatternAddInteger(pattern, FC_SLANT, slant_value); - - if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') { - Q_ASSERT(script < QUnicodeTables::ScriptCount); - FcLangSet *ls = FcLangSetCreate(); - FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]); - FcPatternAddLangSet(pattern, FC_LANG, ls); - FcLangSetDestroy(ls); - } - - const char *stylehint = getFcFamilyForStyleHint(styleHint); - if (stylehint) { - value.u.s = (const FcChar8 *)stylehint; - FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue); - } - - FcConfigSubstitute(0, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - - FcResult result = FcResultMatch; - FcFontSet *fontSet = FcFontSort(0,pattern,FcFalse,0,&result); - FcPatternDestroy(pattern); - - if (fontSet) { - if (result == FcResultMatch) { - for (int i = 0; i < fontSet->nfont; i++) { - FcChar8 *value = 0; - if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) - continue; - // capitalize(value); - QString familyName = QString::fromUtf8((const char *)value); - if (!fallbackFamilies.contains(familyName,Qt::CaseInsensitive) && - familyName.compare(family, Qt::CaseInsensitive)) { - fallbackFamilies << familyName; - } - } - } - FcFontSetDestroy(fontSet); - } -// qDebug() << "fallbackFamilies for:" << family << style << styleHint << script << fallbackFamilies; - - return fallbackFamilies; -} diff --git a/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h b/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h deleted file mode 100644 index 61700e391a..0000000000 --- a/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QFONTCONFIGDATABASE_H -#define QFONTCONFIGDATABASE_H - -#include <QPlatformFontDatabase> -#include "qbasicunixfontdatabase.h" - -class QFontconfigDatabase : public QBasicUnixFontDatabase -{ -public: - void populateFontDatabase(); - QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); - QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const; -}; - -#endif // QFONTCONFIGDATABASE_H diff --git a/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri b/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri deleted file mode 100644 index 1153ab36b7..0000000000 --- a/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri +++ /dev/null @@ -1,10 +0,0 @@ -contains(QT_CONFIG, fontconfig) { - include(../fontconfig/fontconfig.pri) - DEFINES += Q_FONTCONFIGDATABASE -} else { - include(../basicunix/basicunix.pri) -} - -INCLUDEPATH += $$PWD -HEADERS += \ - $$PWD/qgenericunixfontdatabase.h diff --git a/src/plugins/platforms/glxconvenience/glxconvenience.pri b/src/plugins/platforms/glxconvenience/glxconvenience.pri deleted file mode 100644 index b4d43a30b5..0000000000 --- a/src/plugins/platforms/glxconvenience/glxconvenience.pri +++ /dev/null @@ -1,15 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/qglxconvenience.h - -SOURCES += \ - $$PWD/qglxconvenience.cpp - -CONFIG += xrender - -xrender { - LIBS += -lXrender -} else { - DEFINES += QT_NO_XRENDER -} diff --git a/src/plugins/platforms/glxconvenience/qglxconvenience.cpp b/src/plugins/platforms/glxconvenience/qglxconvenience.cpp deleted file mode 100644 index 34633d9692..0000000000 --- a/src/plugins/platforms/glxconvenience/qglxconvenience.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglxconvenience.h" - -#include <QtCore/QVector> - -#ifndef QT_NO_XRENDER -#include <X11/extensions/Xrender.h> -#endif - -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 - -QVector<int> qglx_buildSpec(const QPlatformWindowFormat &format, int drawableBit) -{ - QVector<int> spec(48); - int i = 0; - - spec[i++] = GLX_LEVEL; - spec[i++] = 0; - spec[i++] = GLX_DRAWABLE_TYPE; spec[i++] = drawableBit; - - 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(); - } - - if (format.accum()) { - 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 qglx_findConfig(Display *display, int screen , const QPlatformWindowFormat &format, int drawableBit) -{ - bool reduced = true; - GLXFBConfig chosenConfig = 0; - QPlatformWindowFormat reducedFormat = format; - while (!chosenConfig && reduced) { - QVector<int> spec = qglx_buildSpec(reducedFormat, drawableBit); - int confcount = 0; - GLXFBConfig *configs; - configs = glXChooseFBConfig(display, screen,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(display,configs[i],GLX_ALPHA_SIZE,&alphaSize); - if (alphaSize > 0) { - XVisualInfo *visual = glXGetVisualFromFBConfig(display, chosenConfig); -#if !defined(QT_NO_XRENDER) - XRenderPictFormat *pictFormat = XRenderFindVisualFormat(display, visual->visual); - if (pictFormat->direct.alphaMask > 0) - break; -#else - if (visual->depth == 32) - break; -#endif - } - } else { - break; // Just choose the first in the list if there's no alpha requested - } - } - - XFree(configs); - } - reducedFormat = qglx_reducePlatformWindowFormat(reducedFormat,&reduced); - } - - if (!chosenConfig) - qWarning("Warning: no suitable glx confiuration found"); - - return chosenConfig; -} - -XVisualInfo *qglx_findVisualInfo(Display *display, int screen, const QPlatformWindowFormat &format) -{ - GLXFBConfig config = qglx_findConfig(display,screen,format); - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(display,config); - return visualInfo; -} - -QPlatformWindowFormat qglx_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 qglx_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; -} diff --git a/src/plugins/platforms/glxconvenience/qglxconvenience.h b/src/plugins/platforms/glxconvenience/qglxconvenience.h deleted file mode 100644 index 7478abfeba..0000000000 --- a/src/plugins/platforms/glxconvenience/qglxconvenience.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGLXCONVENIENCE_H -#define QGLXCONVENIENCE_H - -#include <QPlatformWindowFormat> - -#include <X11/Xlib.h> -#include <GL/glx.h> - -XVisualInfo *qglx_findVisualInfo(Display *display, int screen, const QPlatformWindowFormat &format); -GLXFBConfig qglx_findConfig(Display *display, int screen, const QPlatformWindowFormat &format, int drawableBit = GLX_WINDOW_BIT); -QPlatformWindowFormat qglx_platformWindowFromGLXFBConfig(Display *display, GLXFBConfig config, GLXContext context); -QVector<int> qglx_buildSpec(const QPlatformWindowFormat &format, int drawableBit = GLX_WINDOW_BIT); -QPlatformWindowFormat qglx_reducePlatformWindowFormat(const QPlatformWindowFormat &format, bool *reduced); - -#endif // QGLXCONVENIENCE_H diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro new file mode 100644 index 0000000000..73a3fa0418 --- /dev/null +++ b/src/plugins/platforms/kms/kms.pro @@ -0,0 +1,42 @@ +TARGET = qkms + +load(qt_plugin) +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms + +QT = core-private gui-private platformsupport-private opengl-private + +CONFIG += link_pkgconfig qpa/genericunixfontdatabase + +PKGCONFIG += libdrm egl gbm glesv2 + +SOURCES = main.cpp \ + qkmsintegration.cpp \ + qkmsscreen.cpp \ + qkmscontext.cpp \ + qkmswindow.cpp \ + qkmscursor.cpp \ + qkmsdevice.cpp \ + qkmsbuffermanager.cpp \ + qkmsbackingstore.cpp +HEADERS = qkmsintegration.h \ + qkmsscreen.h \ + qkmscontext.h \ + qkmswindow.h \ + qkmscursor.h \ + qkmsdevice.h \ + qkmsbuffermanager.h \ + qkmsbackingstore.h + +target.path += $$[QT_INSTALL_PLUGINS]/platforms +INSTALLS += target + + + + + + + + + + + diff --git a/src/plugins/graphicssystems/openvg/main.cpp b/src/plugins/platforms/kms/main.cpp index 0aa265e50b..a07f1645dc 100644 --- a/src/plugins/graphicssystems/openvg/main.cpp +++ b/src/plugins/platforms/kms/main.cpp @@ -39,33 +39,34 @@ ** ****************************************************************************/ -#include <private/qgraphicssystemplugin_p.h> -#include "qgraphicssystem_vg_p.h" +#include <QtGui/QPlatformIntegrationPlugin> +#include "qkmsintegration.h" QT_BEGIN_NAMESPACE -class QVGGraphicsSystemPlugin : public QGraphicsSystemPlugin +class QKmsIntegrationPlugin : public QPlatformIntegrationPlugin { public: QStringList keys() const; - QGraphicsSystem *create(const QString&); + QPlatformIntegration *create(const QString&, const QStringList&); }; -QStringList QVGGraphicsSystemPlugin::keys() const +QStringList QKmsIntegrationPlugin::keys() const { QStringList list; - list << "OpenVG"; + list << "kms"; return list; } -QGraphicsSystem* QVGGraphicsSystemPlugin::create(const QString& system) +QPlatformIntegration *QKmsIntegrationPlugin::create(const QString& system, const QStringList& paramList) { - if (system.toLower() == "openvg") - return new QVGGraphicsSystem; + Q_UNUSED(paramList); + if (system.toLower() == "kms") + return new QKmsIntegration; return 0; } -Q_EXPORT_PLUGIN2(openvg, QVGGraphicsSystemPlugin) +Q_EXPORT_PLUGIN2(kms, QKmsIntegrationPlugin) QT_END_NAMESPACE diff --git a/src/plugins/decorations/windows/main.cpp b/src/plugins/platforms/kms/qkmsbackingstore.cpp index 8ee8a156e8..eb682e8ab3 100644 --- a/src/plugins/decorations/windows/main.cpp +++ b/src/plugins/platforms/kms/qkmsbackingstore.cpp @@ -39,38 +39,34 @@ ** ****************************************************************************/ -#include <qdecorationplugin_qws.h> -#include <qdecorationwindows_qws.h> +#include "qkmsbackingstore.h" QT_BEGIN_NAMESPACE -class DecorationWindows : public QDecorationPlugin -{ -public: - DecorationWindows(); - - QStringList keys() const; - QDecoration *create(const QString&); -}; - -DecorationWindows::DecorationWindows() - : QDecorationPlugin() +QKmsBackingStore::QKmsBackingStore(QWindow *window) + : QPlatformBackingStore(window) { } -QStringList DecorationWindows::keys() const +QPaintDevice *QKmsBackingStore::paintDevice() { - return (QStringList() << QLatin1String("Windows")); + return &m_image; } -QDecoration* DecorationWindows::create(const QString& s) +void QKmsBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { - if (s.toLower() == QLatin1String("windows")) - return new QDecorationWindows(); + //'window' can be a child window, in which case 'region' is in child window coordinates and + // offset is the (child) window's offset in relation to the window surface. - return 0; + Q_UNUSED(region) + Q_UNUSED(offset) + Q_UNUSED(window) } -Q_EXPORT_PLUGIN2(qdecorationwindows, DecorationWindows) +void QKmsBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + Q_UNUSED(staticContents) + m_image = QImage(size, QImage::Format_RGB32); +} QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.h b/src/plugins/platforms/kms/qkmsbackingstore.h index a4c8cd67e4..e270d04db0 100644 --- a/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.h +++ b/src/plugins/platforms/kms/qkmsbackingstore.h @@ -39,20 +39,25 @@ ** ****************************************************************************/ -#ifndef SHIVAVGGRAPHICSSYSTEM_H -#define SHIVAVGGRAPHICSSYSTEM_H +#ifndef QBACKINGSTORE_KMS_H +#define QBACKINGSTORE_KMS_H -#include <QtGui/private/qgraphicssystem_p.h> +#include <QtGui/QPlatformBackingStore> +#include <QImage> QT_BEGIN_NAMESPACE -class ShivaVGGraphicsSystem : public QGraphicsSystem +class QKmsBackingStore : public QPlatformBackingStore { public: - ShivaVGGraphicsSystem(); + QKmsBackingStore(QWindow *window); - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QWindowSurface *createWindowSurface(QWidget *widget) const; + QPaintDevice *paintDevice(); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + void resize(const QSize &size, const QRegion &staticContents); + +private: + QImage m_image; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsbuffermanager.cpp b/src/plugins/platforms/kms/qkmsbuffermanager.cpp new file mode 100644 index 0000000000..0c2eec0f3b --- /dev/null +++ b/src/plugins/platforms/kms/qkmsbuffermanager.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qkmsbuffermanager.h" +#include "qkmsscreen.h" +#include "qkmscontext.h" +#include "qkmsdevice.h" + +QT_BEGIN_NAMESPACE + +QKmsBufferManager::QKmsBufferManager(QKmsScreen *screen) : + m_screen(screen), + m_frameBufferObject(0), + m_renderTarget(0), + m_displayCanidate(0), + m_currentDisplay(0) +{ +} + +QKmsBufferManager::~QKmsBufferManager() +{ + clearBuffers(); + glDeleteFramebuffers(1, &m_frameBufferObject); +} + +void QKmsBufferManager::setupBuffersForMode(const drmModeModeInfo &mode, int numBuffers) +{ + eglMakeCurrent(m_screen->device()->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, m_screen->device()->eglContext()); + m_screen->bindFramebuffer(); + + + if (m_frameBufferObject) { + clearBuffers(); + } else { + //Setup Framebuffer Object + glGenFramebuffers(1, &m_frameBufferObject); + glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferObject); + } + + //Setup shared Depth/Stencil buffer + glGenRenderbuffers(1, &m_depthAndStencilBufferObject); + glBindRenderbuffer(GL_RENDERBUFFER, m_depthAndStencilBufferObject); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, + mode.hdisplay, mode.vdisplay); + + //Setup "numBuffer" many rendering targets + for (int i = 0; i < numBuffers; i++) { + QKmsFramebuffer *buffer = new QKmsFramebuffer(); + + glGenRenderbuffers(1, &buffer->renderBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, buffer->renderBuffer); + + buffer->graphicsBufferObject = gbm_bo_create(m_screen->device()->gbmDevice(), + mode.hdisplay, mode.vdisplay, + GBM_BO_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + buffer->eglImage = eglCreateImageKHR(m_screen->device()->eglDisplay(), 0, EGL_NATIVE_PIXMAP_KHR, + buffer->graphicsBufferObject, 0); + glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, buffer->eglImage); + + quint32 stride = gbm_bo_get_pitch(buffer->graphicsBufferObject); + quint32 handle = gbm_bo_get_handle(buffer->graphicsBufferObject).u32; + + int status = drmModeAddFB(m_screen->device()->fd(), mode.hdisplay, mode.vdisplay, + 32, 32, stride, handle, &buffer->framebufferId); + //Todo: IF this returns true, then this is one less buffer that we use + //Not so fatal, but not handled at the moment. + if (status) + qFatal("failed to add framebuffer"); + m_framebuffers.append(buffer); + } + //Attach the Depth and Stencil buffer + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, + m_depthAndStencilBufferObject); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, + m_depthAndStencilBufferObject); + //Attach renderbuffer as Color Attachment. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + this->renderTargetBuffer()); +} + +void QKmsBufferManager::clearBuffers() +{ + //Make sure that the FBO is binded + glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferObject); + //Detach the Color/Depth/Stencil Attachments. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, + 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, + 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + //Delete the shared Depth/Stencil buffer + glDeleteRenderbuffers(1, &m_depthAndStencilBufferObject); + + //Delete each renderbuffer object + //Delete each EGLImage + //Remove each drm Framebuffer + foreach (QKmsFramebuffer *buffer, m_framebuffers) { + glDeleteRenderbuffers(1, &buffer->renderBuffer); + eglDestroyImageKHR(m_screen->device()->eglDisplay(), buffer->eglImage); + drmModeRmFB(m_screen->device()->fd(), buffer->framebufferId); + delete buffer; + } + m_framebuffers.clear(); +} + +GLuint QKmsBufferManager::renderTargetBuffer() +{ + //TODO: Handle more senarios than assuming at least 2 buffers + if (!m_renderTarget) { + m_renderTarget = m_framebuffers.at(1); + } + return m_renderTarget->renderBuffer; +} + +quint32 QKmsBufferManager::displayFramebufferId() +{ + if (!m_currentDisplay) { + m_currentDisplay = m_framebuffers.at(0); + m_currentDisplay->available = false; + return m_currentDisplay->framebufferId; + } + + if (!m_displayCanidate) + return m_currentDisplay->framebufferId; + + m_currentDisplay->available = true; + m_displayCanidate->available = false; + m_currentDisplay = m_displayCanidate; + return m_currentDisplay->framebufferId; + +} + +bool QKmsBufferManager::nextBuffer() +{ + m_displayCanidate = m_renderTarget; + foreach (QKmsFramebuffer *buffer, m_framebuffers) { + if (buffer->available && buffer != m_displayCanidate) { + m_renderTarget = buffer; + return true; + } + } + return false; +} + +QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsbuffermanager.h b/src/plugins/platforms/kms/qkmsbuffermanager.h new file mode 100644 index 0000000000..59db7ebeb1 --- /dev/null +++ b/src/plugins/platforms/kms/qkmsbuffermanager.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QKMSBUFFERMANAGER_H +#define QKMSBUFFERMANAGER_H + +#include <QObject> +#include <QList> + +#define EGL_EGLEXT_PROTOTYPES 1 +#define GL_GLEXT_PROTOTYPES 1 + +extern "C" { +#include <gbm.h> +#include <xf86drmMode.h> +#include <xf86drm.h> +} + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +QT_BEGIN_NAMESPACE + +class QKmsScreen; + +class QKmsFramebuffer +{ +public: + QKmsFramebuffer() : available(true) {} + gbm_bo *graphicsBufferObject; + GLuint renderBuffer; + EGLImageKHR eglImage; + quint32 framebufferId; + bool available; +}; + + +class QKmsBufferManager +{ +public: + explicit QKmsBufferManager(QKmsScreen *screen); + ~QKmsBufferManager(); + void setupBuffersForMode(const drmModeModeInfo &mode, int numBuffers = 3); + GLuint framebufferObject() const { return m_frameBufferObject; } + quint32 displayFramebufferId(); + GLuint renderTargetBuffer(); + bool nextBuffer(); + +private: + void clearBuffers(); + + QKmsScreen *m_screen; + QList<QKmsFramebuffer*> m_framebuffers; + GLuint m_frameBufferObject; + GLuint m_depthAndStencilBufferObject; + + QKmsFramebuffer *m_renderTarget; + QKmsFramebuffer *m_displayCanidate; + QKmsFramebuffer *m_currentDisplay; + +}; + +QT_END_NAMESPACE + +#endif // QKMSBUFFERMANAGER_H diff --git a/src/plugins/platforms/kms/qkmscontext.cpp b/src/plugins/platforms/kms/qkmscontext.cpp new file mode 100644 index 0000000000..f27673a24d --- /dev/null +++ b/src/plugins/platforms/kms/qkmscontext.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qkmsscreen.h" +#include "qkmsdevice.h" +#include "qkmscontext.h" +#include "qkmswindow.h" + + +QT_BEGIN_NAMESPACE + +QKmsContext::QKmsContext(QKmsDevice *device) + : QPlatformOpenGLContext(), + m_device(device) +{ +} + +bool QKmsContext::makeCurrent(QPlatformSurface *surface) +{ + EGLDisplay display = m_device->eglDisplay(); + EGLContext context = m_device->eglContext(); + + bool ok = eglMakeCurrent(display, EGL_NO_SURFACE, + EGL_NO_SURFACE, context); + if (!ok) + qWarning("QKmsContext::makeCurrent(): eglError: %d, this: %p", + eglGetError(), this); + + QPlatformWindow *window = static_cast<QPlatformWindow *>(surface); + QKmsScreen *screen = static_cast<QKmsScreen *> (QPlatformScreen::platformScreenForWindow(window->window())); + screen->bindFramebuffer(); + return true; +} + +void QKmsContext::doneCurrent() +{ + QPlatformOpenGLContext::doneCurrent(); + bool ok = eglMakeCurrent(m_device->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + if (!ok) + qWarning("QKmsContext::doneCurrent(): eglError: %d, this: %p", + eglGetError(), this); + +} + +void QKmsContext::swapBuffers(QPlatformSurface *surface) +{ + //After flush, the current render target should be moved to + //latest complete + glFlush(); + + //Cast context to a window surface and get the screen the context + //is on and call swapBuffers on that screen. + QPlatformWindow *window = static_cast<QPlatformWindow *>(surface); + QKmsScreen *screen = static_cast<QKmsScreen *> (QPlatformScreen::platformScreenForWindow(window->window())); + screen->swapBuffers(); +} + +void (*QKmsContext::getProcAddress(const QByteArray &procName)) () +{ + return eglGetProcAddress(procName.data()); +} + + +EGLContext QKmsContext::eglContext() const +{ + return m_device->eglContext(); +} + +QSurfaceFormat QKmsContext::format() const +{ + return QSurfaceFormat(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmscontext.h b/src/plugins/platforms/kms/qkmscontext.h new file mode 100644 index 0000000000..2f4f44c3d0 --- /dev/null +++ b/src/plugins/platforms/kms/qkmscontext.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QKMSCONTEXT_H +#define QKMSCONTEXT_H + +#include <QtGui/QPlatformOpenGLContext> + +#define EGL_EGLEXT_PROTOTYPES 1 +#include <EGL/egl.h> + +QT_BEGIN_NAMESPACE + +class QKmsDevice; + +class QKmsContext : public QPlatformOpenGLContext +{ +public: + QKmsContext(QKmsDevice *device); + + bool makeCurrent(QPlatformSurface *surface); + void doneCurrent(); + void swapBuffers(QPlatformSurface *surface); + void (*getProcAddress(const QByteArray &procName)) (); + + QSurfaceFormat format() const; + + EGLContext eglContext() const; + +private: + + QKmsDevice *m_device; +}; + +QT_END_NAMESPACE + +#endif // QKMSCONTEXT_H diff --git a/src/plugins/platforms/kms/qkmscursor.cpp b/src/plugins/platforms/kms/qkmscursor.cpp new file mode 100644 index 0000000000..91c23b0f1c --- /dev/null +++ b/src/plugins/platforms/kms/qkmscursor.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//#include <QDebug> +#include "qkmscursor.h" +#include "qkmsscreen.h" +#include "qkmsdevice.h" + +QT_BEGIN_NAMESPACE + +QKmsCursor::QKmsCursor(QKmsScreen *screen) + : QPlatformCursor(screen), m_screen(screen), + m_graphicsBufferManager(screen->device()->gbmDevice()) +{ + gbm_bo *bo = gbm_bo_create(m_graphicsBufferManager, 64, 64, + GBM_BO_FORMAT_ARGB8888, + GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_RENDERING); + + m_eglImage = eglCreateImageKHR(m_screen->device()->eglDisplay(), 0, EGL_NATIVE_PIXMAP_KHR, + bo, 0); + gbm_bo_destroy(bo); + m_cursorImage = new QPlatformCursorImage(0, 0, 0, 0, 0, 0); +} + +void QKmsCursor::pointerEvent(const QMouseEvent &event) +{ + int status = drmModeMoveCursor(m_screen->device()->fd(), + m_screen->crtcId(), + event.globalX(), + event.globalY()); + if (status) { + qWarning("failed to move cursor: %d", status); + } +} + +void QKmsCursor::changeCursor(QCursor *widgetCursor, QWindow *window) +{ + Q_UNUSED(window) + + if (widgetCursor->shape() != Qt::BitmapCursor) { + m_cursorImage->set(widgetCursor->shape()); + } else { + m_cursorImage->set(widgetCursor->pixmap().toImage(), + widgetCursor->hotSpot().x(), + widgetCursor->hotSpot().y()); + } + + if ((m_cursorImage->image()->width() > 64) || (m_cursorImage->image()->width() > 64)) { + qWarning("failed to set hardware cursor: larger than 64x64."); + return; + } + + QImage cursorImage = m_cursorImage->image()->convertToFormat(QImage::Format_RGB32); + + //Load cursor image into EGLImage + GLuint cursorTexture; + glGenTextures(1, &cursorTexture); + glBindTexture(GL_TEXTURE_2D, cursorTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + + //TODO: Format may be wrong here, need a color icon to test. + if (m_eglImage != EGL_NO_IMAGE_KHR) { + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cursorImage.width(), + cursorImage.height(), GL_RGBA, + GL_UNSIGNED_BYTE, cursorImage.constBits()); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cursorImage.width(), + cursorImage.height(), 0, GL_RGBA, + GL_UNSIGNED_BYTE, cursorImage.constBits()); + } + + //EGLImage needs to contain sprite before calling this: + gbm_bo *bufferObject = gbm_bo_create_from_egl_image(m_graphicsBufferManager, + m_screen->device()->eglDisplay(), + m_eglImage, 64, 64, + GBM_BO_USE_CURSOR_64X64); + quint32 handle = gbm_bo_get_handle(bufferObject).u32; + + gbm_bo_destroy(bufferObject); + + int status = drmModeSetCursor(m_screen->device()->fd(), + m_screen->crtcId(), handle, 64, 64); + + if (status) { + qWarning("failed to set cursor: %d", status); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h b/src/plugins/platforms/kms/qkmscursor.h index 6641379261..96be88e991 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h +++ b/src/plugins/platforms/kms/qkmscursor.h @@ -39,36 +39,36 @@ ** ****************************************************************************/ -#ifndef QDIRECTFBKEYBOARD_H -#define QDIRECTFBKEYBOARD_H +#ifndef QKMSCURSOR_H +#define QKMSCURSOR_H -#include <qglobal.h> -#include <QtGui/qkbd_qws.h> +#include <QtGui/QPlatformCursor> -#ifndef QT_NO_QWS_DIRECTFB +#define EGL_EGLEXT_PROTOTYPES 1 -QT_BEGIN_HEADER +#include <EGL/egl.h> +#include <EGL/eglext.h> QT_BEGIN_NAMESPACE -QT_MODULE(Gui) +class QKmsScreen; +class gbm_device; -class QDirectFBKeyboardHandlerPrivate; - -class QDirectFBKeyboardHandler : public QWSKeyboardHandler +class QKmsCursor : public QPlatformCursor { public: - QDirectFBKeyboardHandler(const QString &device); - ~QDirectFBKeyboardHandler(); + QKmsCursor(QKmsScreen *screen); + + void pointerEvent(const QMouseEvent &event); + void changeCursor(QCursor *widgetCursor, QWindow *window); private: - QDirectFBKeyboardHandlerPrivate *d; + QKmsScreen *m_screen; + gbm_device *m_graphicsBufferManager; + EGLImageKHR m_eglImage; + QPlatformCursorImage *m_cursorImage; }; QT_END_NAMESPACE -#endif // QT_NO_QWS_DIRECTFB - -QT_END_HEADER - -#endif // QDIRECTFBKEYBOARD_H +#endif // QKMSCURSOR_H diff --git a/src/plugins/platforms/kms/qkmsdevice.cpp b/src/plugins/platforms/kms/qkmsdevice.cpp new file mode 100644 index 0000000000..e0fac5611d --- /dev/null +++ b/src/plugins/platforms/kms/qkmsdevice.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//#include <QDebug> +#include "qkmsscreen.h" +#include "qkmsdevice.h" + +#include "qkmsintegration.h" + +#include <QtCore/QSocketNotifier> +#include <QtCore/private/qcore_unix_p.h> + +QT_BEGIN_NAMESPACE + +QKmsDevice::QKmsDevice(const QString &path, QKmsIntegration *parent) : + QObject(0), m_integration(parent) +{ + m_fd = QT_OPEN(path.toAscii().constData(), O_RDWR); + if (m_fd < 0) { + qWarning("Could not open %s.", path.toAscii().constData()); + qFatal("No DRM display device"); + } + + m_graphicsBufferManager = gbm_create_device(m_fd); + m_eglDisplay = eglGetDisplay(m_graphicsBufferManager); + + if (m_eglDisplay == EGL_NO_DISPLAY) { + qWarning("Could not open EGL display"); + qFatal("EGL error"); + } + + EGLint major; + EGLint minor; + if (!eglInitialize(m_eglDisplay, &major, &minor)) { + qWarning("Could not initialize EGL display"); + qFatal("EGL error"); + } + + QString extensions = eglQueryString(m_eglDisplay, EGL_EXTENSIONS); + if (!extensions.contains(QString::fromLatin1("EGL_KHR_surfaceless_opengl"))) { + qFatal("EGL_KHR_surfaceless_opengl extension not available"); + } + + //Initialize EGLContext + static EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + eglBindAPI(EGL_OPENGL_ES_API); + m_eglContext = eglCreateContext(m_eglDisplay, 0, 0, contextAttribs); + if (m_eglContext == EGL_NO_CONTEXT) { + qWarning("Could not create the EGL context."); + eglTerminate(m_eglDisplay); + qFatal("EGL error"); + } + + createScreens(); + + QSocketNotifier *notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), this, SLOT(handlePageFlipCompleted())); +} + +QKmsDevice::~QKmsDevice() +{ + if (m_eglContext != EGL_NO_CONTEXT) { + eglDestroyContext(m_eglDisplay, m_eglContext); + m_eglContext = EGL_NO_CONTEXT; + } +} + +void QKmsDevice::createScreens() +{ + drmModeRes *resources = 0; + resources = drmModeGetResources(m_fd); + if (!resources) + qFatal("drmModeGetResources failed"); + + //Iterate connectors and create screens on each one active + for (int i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector = 0; + connector = drmModeGetConnector(m_fd, resources->connectors[i]); + if (connector && connector->connection == DRM_MODE_CONNECTED) { + m_integration->addScreen(new QKmsScreen(this, connector->connector_id)); + } + drmModeFreeConnector(connector); + } + drmModeFreeResources(resources); +} + +void QKmsDevice::handlePageFlipCompleted() +{ + //qDebug() << "Display signal recieved"; + drmEventContext eventContext; + + memset(&eventContext, 0, sizeof eventContext); + eventContext.version = DRM_EVENT_CONTEXT_VERSION; + eventContext.page_flip_handler = QKmsDevice::pageFlipHandler; + drmHandleEvent(m_fd, &eventContext); + +} + +void QKmsDevice::pageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) +{ + Q_UNUSED(fd) + Q_UNUSED(frame) + Q_UNUSED(sec) + Q_UNUSED(usec) + static unsigned int previousTime = 0; + + unsigned int currentTime = sec * 1000000 + usec; + unsigned int refreshTime = 0; +// qDebug() << "fd: " << fd << " frame: " << frame << " sec: " +// << sec << " usec: " << usec << " data: " << data +// << "msecs" << sec * 1000 + usec / 1000; + QKmsScreen *screen = static_cast<QKmsScreen *>(data); + + if (previousTime == 0) + refreshTime = 16000; + else + refreshTime = currentTime - previousTime; + + screen->setFlipReady(refreshTime); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglconvenience/qeglplatformcontext.h b/src/plugins/platforms/kms/qkmsdevice.h index 9be1480735..4868a72ede 100644 --- a/src/plugins/platforms/eglconvenience/qeglplatformcontext.h +++ b/src/plugins/platforms/kms/qkmsdevice.h @@ -39,33 +39,49 @@ ** ****************************************************************************/ -#ifndef QOPENKODEGLINTEGRATION_H -#define QOPENKODEGLINTEGRATION_H +#ifndef QKMSDEVICE_H +#define QKMSDEVICE_H -#include <QtGui/QPlatformGLContext> +extern "C" { +#include <gbm.h> +} #include <EGL/egl.h> -class QEGLPlatformContext : public QPlatformGLContext +#include <QObject> + +QT_BEGIN_NAMESPACE + +class gbm_device; +class QKmsIntegration; + +class QKmsDevice : public QObject { + Q_OBJECT public: - QEGLPlatformContext(EGLDisplay display, EGLConfig config, EGLint contextAttrs[], EGLSurface surface, EGLenum eglApi); - ~QEGLPlatformContext(); + explicit QKmsDevice(const QString &path, QKmsIntegration *parent); + ~QKmsDevice(); - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); - void* getProcAddress(const QString& procName); + EGLDisplay eglDisplay() { return m_eglDisplay; } + gbm_device *gbmDevice() { return m_graphicsBufferManager; } + EGLContext eglContext() { return m_eglContext; } + int fd() const { return m_fd; } - QPlatformWindowFormat platformWindowFormat() const; + static void pageFlipHandler(int fd, unsigned int frame, unsigned int sec, + unsigned int usec, void *data); - EGLContext eglContext() const; +public slots: + void handlePageFlipCompleted(); private: - EGLContext m_eglContext; - EGLDisplay m_eglDisplay; - EGLSurface m_eglSurface; - EGLenum m_eglApi; + void createScreens(); - QPlatformWindowFormat m_windowFormat; + QKmsIntegration *m_integration; + + EGLDisplay m_eglDisplay; + EGLContext m_eglContext; + gbm_device *m_graphicsBufferManager; + int m_fd; }; -#endif //QOPENKODEGLINTEGRATION_H +QT_END_NAMESPACE + +#endif // QKMSDEVICE_H diff --git a/src/plugins/platforms/kms/qkmsintegration.cpp b/src/plugins/platforms/kms/qkmsintegration.cpp new file mode 100644 index 0000000000..d8e4876eee --- /dev/null +++ b/src/plugins/platforms/kms/qkmsintegration.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qkmsintegration.h" +#include "qkmsdevice.h" +#include "qkmsscreen.h" +#include "qkmswindow.h" +#include "qkmsbackingstore.h" +#include "qkmscontext.h" + +#include <QtPlatformSupport/private/qgenericunixprintersupport_p.h> +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/QOpenGLContext> +#include <QtGui/QScreen> + +QT_BEGIN_NAMESPACE + +QKmsIntegration::QKmsIntegration() + : QPlatformIntegration(), + m_fontDatabase(new QGenericUnixFontDatabase()), + m_printerSupport(new QGenericUnixPrinterSupport()), + m_eventDispatcher(createUnixEventDispatcher()) +{ + QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); + setenv("EGL_PLATFORM", "drm",1); + QStringList drmDevices = findDrmDevices(); + foreach (QString path, drmDevices) { + m_devices.append(new QKmsDevice(path, this)); + } +} + +QKmsIntegration::~QKmsIntegration() +{ + foreach (QKmsDevice *device, m_devices) { + delete device; + } + foreach (QPlatformScreen *screen, m_screens) { + delete screen; + } + delete m_printerSupport; + delete m_fontDatabase; +} + +bool QKmsIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ + switch (cap) { + case ThreadedPixmaps: return true; + case OpenGL: return true; + case ThreadedOpenGL: return true; + default: return QPlatformIntegration::hasCapability(cap); + } +} + +QPlatformOpenGLContext *QKmsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ + QKmsScreen *screen = static_cast<QKmsScreen *>(context->screen()->handle()); + return new QKmsContext(screen->device()); +} + +QPlatformWindow *QKmsIntegration::createPlatformWindow(QWindow *window) const +{ + return new QKmsWindow(window); +} + +QPlatformBackingStore *QKmsIntegration::createPlatformBackingStore(QWindow *window) const +{ + return new QKmsBackingStore(window); +} + +QPlatformFontDatabase *QKmsIntegration::fontDatabase() const +{ + return m_fontDatabase; +} + +QStringList QKmsIntegration::findDrmDevices() +{ + //Return a list addresses of DRM supported devices + //Hardcoded now, but could use udev to return a list + //of multiple devices. + return QStringList(QString::fromLatin1("/dev/dri/card0")); +} + +void QKmsIntegration::addScreen(QKmsScreen *screen) +{ + m_screens.append(screen); + screenAdded(screen); +} + +QAbstractEventDispatcher *QKmsIntegration::guiThreadEventDispatcher() const +{ + return m_eventDispatcher; +} + +QPlatformPrinterSupport *QKmsIntegration::printerSupport() const +{ + return m_printerSupport; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsintegration.h b/src/plugins/platforms/kms/qkmsintegration.h new file mode 100644 index 0000000000..a1f3623280 --- /dev/null +++ b/src/plugins/platforms/kms/qkmsintegration.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPLATFORMINTEGRATION_KMS_H +#define QPLATFORMINTEGRATION_KMS_H + +#include <QtGui/QPlatformIntegration> + +QT_BEGIN_NAMESPACE + +class QKmsScreen; +class QKmsDevice; + +class QKmsIntegration : public QPlatformIntegration +{ +public: + QKmsIntegration(); + ~QKmsIntegration(); + + bool hasCapability(QPlatformIntegration::Capability cap) const; + + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + + QPlatformFontDatabase *fontDatabase() const; + QPlatformPrinterSupport *printerSupport() const; + QAbstractEventDispatcher *guiThreadEventDispatcher() const; + + void addScreen(QKmsScreen *screen); + +private: + QStringList findDrmDevices(); + + QList<QPlatformScreen *> m_screens; + QList<QKmsDevice *> m_devices; + QPlatformFontDatabase *m_fontDatabase; + QPlatformPrinterSupport *m_printerSupport; + QAbstractEventDispatcher *m_eventDispatcher; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/kms/qkmsscreen.cpp b/src/plugins/platforms/kms/qkmsscreen.cpp new file mode 100644 index 0000000000..0cd1530930 --- /dev/null +++ b/src/plugins/platforms/kms/qkmsscreen.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//#include <QDebug> +#include "qkmscursor.h" +#include "qkmsscreen.h" +#include "qkmsdevice.h" +#include "qkmscontext.h" +#include "qkmsbuffermanager.h" + +QT_BEGIN_NAMESPACE + +//Fallback mode (taken from Wayland DRM demo compositor) +static drmModeModeInfo builtin_1024x768 = { + 63500, //clock + 1024, 1072, 1176, 1328, 0, + 768, 771, 775, 798, 0, + 59920, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC, + 0, + "1024x768" +}; + +QKmsScreen::QKmsScreen(QKmsDevice *device, int connectorId) + : m_device(device), + m_flipReady(true), + m_connectorId(connectorId), + m_depth(32), + m_format(QImage::Format_Invalid), + m_bufferManager(this), + m_refreshTime(16000) +{ + m_cursor = new QKmsCursor(this); + initializeScreenMode(); +} + +QKmsScreen::~QKmsScreen() +{ + delete m_cursor; +} + +QRect QKmsScreen::geometry() const +{ + return m_geometry; +} + +int QKmsScreen::depth() const +{ + return m_depth; +} + +QImage::Format QKmsScreen::format() const +{ + return m_format; +} + +QSize QKmsScreen::physicalSize() const +{ + return m_physicalSize; +} + +GLuint QKmsScreen::framebufferObject() const +{ + return m_bufferManager.framebufferObject(); +} + +void QKmsScreen::initializeScreenMode() +{ + //Determine optimal mode for screen + drmModeRes *resources = drmModeGetResources(m_device->fd()); + if (!resources) + qFatal("drmModeGetResources failed"); + + drmModeConnector *connector = drmModeGetConnector(m_device->fd(), m_connectorId); + drmModeModeInfo *mode = 0; + if (connector->count_modes > 0) + mode = &connector->modes[0]; + else + mode = &builtin_1024x768; + + drmModeEncoder *encoder = drmModeGetEncoder(m_device->fd(), connector->encoders[0]); + if (encoder == 0) + qFatal("No encoder for connector."); + + int i; + for (i = 0; i < resources->count_crtcs; i++) { + if (encoder->possible_crtcs & (1 << i)) + break; + } + if (i == resources->count_crtcs) + qFatal("No usable crtc for encoder."); + + m_crtcId = resources->crtcs[i]; + m_mode = *mode; + m_geometry = QRect(0, 0, m_mode.hdisplay, m_mode.vdisplay); + m_depth = 32; + m_format = QImage::Format_RGB32; + m_physicalSize = QSize(connector->mmWidth, connector->mmHeight); + + //Setup three buffers for current mode + m_bufferManager.setupBuffersForMode(m_mode, 3); + + //Set the Mode of the screen. + int ret = drmModeSetCrtc(m_device->fd(), m_crtcId, m_bufferManager.displayFramebufferId(), + 0, 0, &m_connectorId, 1, &m_mode); + if (ret) + qFatal("failed to set mode"); + + //Cleanup + drmModeFreeEncoder(encoder); + drmModeFreeConnector(connector); + drmModeFreeResources(resources); +} + +void QKmsScreen::bindFramebuffer() +{ + if (m_bufferManager.framebufferObject()) { + glBindFramebuffer(GL_FRAMEBUFFER, m_bufferManager.framebufferObject()); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + m_bufferManager.renderTargetBuffer()); + } +} + +void QKmsScreen::swapBuffers() +{ + waitForPageFlipComplete(); + + if ( m_flipReady ) + performPageFlip(); + //TODO: Do something with return value here + m_bufferManager.nextBuffer(); + //qDebug() << "swapBuffers now rendering to " << m_bufferManager.renderTargetBuffer(); + bindFramebuffer(); +} + +void QKmsScreen::performPageFlip() +{ + quint32 displayFramebufferId = m_bufferManager.displayFramebufferId(); + //qDebug() << "Flipping to framebuffer: " << displayFramebufferId; + + int pageFlipStatus = drmModePageFlip(m_device->fd(), m_crtcId, + displayFramebufferId, + DRM_MODE_PAGE_FLIP_EVENT, this); + if (pageFlipStatus) + qWarning("Pageflip status: %d", pageFlipStatus); + + m_flipReady = false; +} + +void QKmsScreen::setFlipReady(unsigned int time) +{ + m_flipReady = true; + m_refreshTime = time; + performPageFlip(); +} + +QKmsDevice * QKmsScreen::device() const +{ + return m_device; +} + +void QKmsScreen::waitForPageFlipComplete() +{ + //Check manually if there is something to be read on the device + //as there are senarios where the signal is not received (starvation) + fd_set fdSet; + timeval timeValue; + int returnValue; + + FD_ZERO(&fdSet); + FD_SET(m_device->fd(), &fdSet); + timeValue.tv_sec = 0; + timeValue.tv_usec = m_refreshTime; + + returnValue = select(1, &fdSet, 0, 0, &timeValue); + + if (returnValue) { + m_device->handlePageFlipCompleted(); + } + +} + + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsscreen.h b/src/plugins/platforms/kms/qkmsscreen.h new file mode 100644 index 0000000000..5c8b5ca4f5 --- /dev/null +++ b/src/plugins/platforms/kms/qkmsscreen.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QKMSSCREEN_H +#define QKMSSCREEN_H + +#include <QtGui/QPlatformScreen> +#include "qkmsbuffermanager.h" + +QT_BEGIN_NAMESPACE + +class QKmsCursor; +class QKmsDevice; +class QKmsContext; + +class QKmsScreen : public QPlatformScreen +{ +public: + QKmsScreen(QKmsDevice *device, int connectorId); + ~QKmsScreen(); + + QRect geometry() const; + int depth() const; + QImage::Format format() const; + QSize physicalSize() const; + + GLuint framebufferObject() const; + quint32 crtcId() const { return m_crtcId; } + QKmsDevice *device() const; + + //Called by context for each screen + void bindFramebuffer(); + void swapBuffers(); + void setFlipReady(unsigned int time); + +private: + void performPageFlip(); + void initializeScreenMode(); + void waitForPageFlipComplete(); + + QKmsDevice *m_device; + bool m_flipReady; + quint32 m_connectorId; + + quint32 m_crtcId; + drmModeModeInfo m_mode; + QRect m_geometry; + QSize m_physicalSize; + int m_depth; + QImage::Format m_format; + + QKmsCursor *m_cursor; + QKmsBufferManager m_bufferManager; + unsigned int m_refreshTime; +}; + +QT_END_NAMESPACE + +#endif // QKMSSCREEN_H diff --git a/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.cpp b/src/plugins/platforms/kms/qkmswindow.cpp index 48526538ab..63271c4ef5 100644 --- a/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.cpp +++ b/src/plugins/platforms/kms/qkmswindow.cpp @@ -39,24 +39,26 @@ ** ****************************************************************************/ -#include "shivavggraphicssystem.h" -#include "shivavgwindowsurface.h" -#include <QtGui/private/qpixmap_raster_p.h> +#include "qkmswindow.h" +#include "qkmsscreen.h" +#include <QtGui/QWindowSystemInterface> QT_BEGIN_NAMESPACE -ShivaVGGraphicsSystem::ShivaVGGraphicsSystem() +QKmsWindow::QKmsWindow(QWindow *window) + : QPlatformWindow(window) { + m_screen = QPlatformScreen::platformScreenForWindow(window); } -QPixmapData *ShivaVGGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +void QKmsWindow::setGeometry(const QRect &rect) { - return new QRasterPixmapData(type); -} + Q_UNUSED(rect) + //All Windows must be fullscreen + QRect fullscreenRect = m_screen->availableGeometry(); + QWindowSystemInterface::handleGeometryChange(window(), fullscreenRect); -QWindowSurface *ShivaVGGraphicsSystem::createWindowSurface(QWidget *widget) const -{ - return new ShivaVGWindowSurface(widget); + QPlatformWindow::setGeometry(fullscreenRect); } QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystemplugin.h b/src/plugins/platforms/kms/qkmswindow.h index e38033a6cd..789d42e6f8 100644 --- a/src/plugins/graphicssystems/meego/qmeegographicssystemplugin.h +++ b/src/plugins/platforms/kms/qkmswindow.h @@ -39,16 +39,24 @@ ** ****************************************************************************/ -#ifndef MGRAPHICSSYSTEMPLUGIN_H -#define MGRAPHICSSYSTEMPLUGIN_H +#ifndef QKMSWINDOW_H +#define QKMSWINDOW_H -#include <private/qgraphicssystemplugin_p.h> +#include <QtGui/QPlatformWindow> -class QMeeGoGraphicsSystemPlugin : public QGraphicsSystemPlugin +QT_BEGIN_NAMESPACE + +class QKmsWindow : public QPlatformWindow { public: - virtual QStringList keys() const; - virtual QGraphicsSystem *create(const QString&); + QKmsWindow(QWindow *window); + + void setGeometry(const QRect &rect); + +private: + QPlatformScreen *m_screen; }; -#endif +QT_END_NAMESPACE + +#endif // QKMSWINDOW_H diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro index ce6814ecc1..9375486d8b 100644 --- a/src/plugins/platforms/linuxfb/linuxfb.pro +++ b/src/plugins/platforms/linuxfb/linuxfb.pro @@ -3,6 +3,8 @@ load(qt_plugin) DESTDIR = $$QT.gui.plugins/platforms +QT += core-private gui-private platformsupport-private + SOURCES = main.cpp qlinuxfbintegration.cpp HEADERS = qlinuxfbintegration.h diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index 4a24d6614a..1c098a0ffc 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -42,6 +42,7 @@ #include "qlinuxfbintegration.h" #include "../fb_base/fb_base.h" #include "qgenericunixfontdatabase.h" +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> #include <QtGui/private/qpixmap_raster_p.h> #include <private/qcore_unix_p.h> // overrides QT_OPEN #include <qimage.h> @@ -791,9 +792,9 @@ bool QLinuxFbIntegration::hasCapability(QPlatformIntegration::Capability cap) co } -QPixmapData *QLinuxFbIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformPixmap *QLinuxFbIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const { - return new QRasterPixmapData(type); + return new QRasterPlatformPixmap(type); } QWindowSurface *QLinuxFbIntegration::createWindowSurface(QWidget *widget, WId) const @@ -810,6 +811,11 @@ QPlatformWindow *QLinuxFbIntegration::createPlatformWindow(QWidget *widget, WId return w; } +QAbstractEventDispatcher *QMinimalIntegration::createEventDispatcher() const +{ + return createUnixEventDispatcher(); +} + QPlatformFontDatabase *QLinuxFbIntegration::fontDatabase() const { return fontDb; diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h index b96749ff03..f972a30452 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h @@ -70,6 +70,7 @@ class QLinuxFbIntegrationPrivate; struct fb_cmap; struct fb_var_screeninfo; struct fb_fix_screeninfo; +class QAbstractEventDispatcher; class QLinuxFbIntegration : public QPlatformIntegration { @@ -79,9 +80,10 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; QPlatformWindow *createPlatformWindow(QWidget *widget, WId WinId) const; QWindowSurface *createWindowSurface(QWidget *widget, WId WinId) const; + QAbstractEventDispatcher *createEventDispatcher() const; QList<QPlatformScreen *> screens() const { return mScreens; } diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro index d51b6b2ed0..392d12d19a 100644 --- a/src/plugins/platforms/minimal/minimal.pro +++ b/src/plugins/platforms/minimal/minimal.pro @@ -1,14 +1,14 @@ TARGET = qminimal load(qt_plugin) -QT = core-private gui-private +QT += core-private gui-private platformsupport-private DESTDIR = $$QT.gui.plugins/platforms SOURCES = main.cpp \ qminimalintegration.cpp \ - qminimalwindowsurface.cpp + qminimalbackingstore.cpp HEADERS = qminimalintegration.h \ - qminimalwindowsurface.h + qminimalbackingstore.h target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/minimal/qminimalwindowsurface.cpp b/src/plugins/platforms/minimal/qminimalbackingstore.cpp index 91c68d1d2d..08281405a4 100644 --- a/src/plugins/platforms/minimal/qminimalwindowsurface.cpp +++ b/src/plugins/platforms/minimal/qminimalbackingstore.cpp @@ -40,45 +40,45 @@ ****************************************************************************/ -#include "qminimalwindowsurface.h" +#include "qminimalbackingstore.h" +#include "qscreen.h" #include <QtCore/qdebug.h> -#include <QtGui/private/qapplication_p.h> +#include <private/qguiapplication_p.h> QT_BEGIN_NAMESPACE -QMinimalWindowSurface::QMinimalWindowSurface(QWidget *window) - : QWindowSurface(window) +QMinimalBackingStore::QMinimalBackingStore(QWindow *window) + : QPlatformBackingStore(window) { - //qDebug() << "QMinimalWindowSurface::QMinimalWindowSurface:" << (long)this; + //qDebug() << "QMinimalBackingStore::QMinimalBackingStore:" << (long)this; } -QMinimalWindowSurface::~QMinimalWindowSurface() +QMinimalBackingStore::~QMinimalBackingStore() { } -QPaintDevice *QMinimalWindowSurface::paintDevice() +QPaintDevice *QMinimalBackingStore::paintDevice() { - //qDebug() << "QMinimalWindowSurface::paintDevice"; + //qDebug() << "QMinimalBackingStore::paintDevice"; return &mImage; } -void QMinimalWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QMinimalBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { - Q_UNUSED(widget); + Q_UNUSED(window); Q_UNUSED(region); Q_UNUSED(offset); static int c = 0; QString filename = QString("output%1.png").arg(c++, 4, 10, QLatin1Char('0')); - qDebug() << "QMinimalWindowSurface::flush() saving contents to" << filename.toLocal8Bit().constData(); + qDebug() << "QMinimalBackingStore::flush() saving contents to" << filename.toLocal8Bit().constData(); mImage.save(filename); } -void QMinimalWindowSurface::resize(const QSize &size) +void QMinimalBackingStore::resize(const QSize &size, const QRegion &) { - //qDebug() << "QMinimalWindowSurface::setGeometry:" << (long)this << rect; - QWindowSurface::resize(size); - QImage::Format format = QApplicationPrivate::platformIntegration()->screens().first()->format(); + //qDebug() << "QMinimalBackingStore::setGeometry:" << (long)this << rect; + QImage::Format format = QGuiApplication::primaryScreen()->handle()->format(); if (mImage.size() != size) mImage = QImage(size, format); } diff --git a/src/plugins/platforms/minimal/qminimalwindowsurface.h b/src/plugins/platforms/minimal/qminimalbackingstore.h index 2c6196a19a..9b61275e9d 100644 --- a/src/plugins/platforms/minimal/qminimalwindowsurface.h +++ b/src/plugins/platforms/minimal/qminimalbackingstore.h @@ -39,24 +39,24 @@ ** ****************************************************************************/ -#ifndef QWINDOWSURFACE_MINIMAL_H -#define QWINDOWSURFACE_MINIMAL_H - -#include <QtGui/private/qwindowsurface_p.h> +#ifndef QBACKINGSTORE_MINIMAL_H +#define QBACKINGSTORE_MINIMAL_H +#include <QtGui/QPlatformBackingStore> #include <QtGui/QPlatformWindow> +#include <QtGui/QImage> QT_BEGIN_NAMESPACE -class QMinimalWindowSurface : public QWindowSurface +class QMinimalBackingStore : public QPlatformBackingStore { public: - QMinimalWindowSurface(QWidget *window); - ~QMinimalWindowSurface(); + QMinimalBackingStore(QWindow *window); + ~QMinimalBackingStore(); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - void resize(const QSize &size); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + void resize(const QSize &size, const QRegion &staticContents); private: QImage mImage; diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp index b9ab528b50..2f2da6967a 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.cpp +++ b/src/plugins/platforms/minimal/qminimalintegration.cpp @@ -40,20 +40,34 @@ ****************************************************************************/ #include "qminimalintegration.h" -#include "qminimalwindowsurface.h" +#include "qminimalbackingstore.h" +#ifndef Q_OS_WIN +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#else +#include <QtCore/private/qeventdispatcher_win_p.h> +#endif #include <QtGui/private/qpixmap_raster_p.h> +#include <QtGui/private/qguiapplication_p.h> #include <QtGui/QPlatformWindow> -QMinimalIntegration::QMinimalIntegration() +QT_BEGIN_NAMESPACE + +QMinimalIntegration::QMinimalIntegration() : +#ifdef Q_OS_WIN + m_eventDispatcher(new QEventDispatcherWin32()) +#else + m_eventDispatcher(createUnixEventDispatcher()) +#endif { + QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); QMinimalScreen *mPrimaryScreen = new QMinimalScreen(); mPrimaryScreen->mGeometry = QRect(0, 0, 240, 320); mPrimaryScreen->mDepth = 32; mPrimaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied; - mScreens.append(mPrimaryScreen); + screenAdded(mPrimaryScreen); } bool QMinimalIntegration::hasCapability(QPlatformIntegration::Capability cap) const @@ -64,19 +78,20 @@ bool QMinimalIntegration::hasCapability(QPlatformIntegration::Capability cap) co } } -QPixmapData *QMinimalIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformWindow *QMinimalIntegration::createPlatformWindow(QWindow *window) const { - return new QRasterPixmapData(type); + Q_UNUSED(window); + return new QPlatformWindow(window); } -QPlatformWindow *QMinimalIntegration::createPlatformWindow(QWidget *widget, WId winId) const +QPlatformBackingStore *QMinimalIntegration::createPlatformBackingStore(QWindow *window) const { - Q_UNUSED(winId); - return new QPlatformWindow(widget); + return new QMinimalBackingStore(window); } -QWindowSurface *QMinimalIntegration::createWindowSurface(QWidget *widget, WId winId) const +QAbstractEventDispatcher *QMinimalIntegration::guiThreadEventDispatcher() const { - Q_UNUSED(winId); - return new QMinimalWindowSurface(widget); + return m_eventDispatcher; } + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/minimal/qminimalintegration.h b/src/plugins/platforms/minimal/qminimalintegration.h index d1fcc42c68..0835c39ab6 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.h +++ b/src/plugins/platforms/minimal/qminimalintegration.h @@ -71,14 +71,12 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; - - QList<QPlatformScreen *> screens() const { return mScreens; } + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + QAbstractEventDispatcher *guiThreadEventDispatcher() const; private: - QList<QPlatformScreen *> mScreens; + QAbstractEventDispatcher *m_eventDispatcher; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/openkode/qopenkodeintegration.cpp b/src/plugins/platforms/openkode/qopenkodeintegration.cpp index 89475db54b..38c4325bb4 100644 --- a/src/plugins/platforms/openkode/qopenkodeintegration.cpp +++ b/src/plugins/platforms/openkode/qopenkodeintegration.cpp @@ -43,7 +43,7 @@ #include "qopenkodewindow.h" #include "qopenkodeeventloopintegration.h" -#include <QtOpenGL/private/qpixmapdata_gl_p.h> +#include <QtOpenGL/qplatformpixmap_gl_p.h> #include <QtOpenGL/private/qwindowsurface_gl_p.h> #include <QtGui/private/qpixmap_raster_p.h> @@ -197,9 +197,9 @@ bool QOpenKODEIntegration::hasCapability(QPlatformIntegration::Capability cap) c } } -QPixmapData *QOpenKODEIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformPixmap *QOpenKODEIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const { - return new QGLPixmapData(type); + return new QGLPlatformPixmap(type); } QPlatformWindow *QOpenKODEIntegration::createPlatformWindow(QWidget *tlw, WId ) const diff --git a/src/plugins/platforms/openkode/qopenkodeintegration.h b/src/plugins/platforms/openkode/qopenkodeintegration.h index 0f001c957b..43961add6d 100644 --- a/src/plugins/platforms/openkode/qopenkodeintegration.h +++ b/src/plugins/platforms/openkode/qopenkodeintegration.h @@ -48,7 +48,7 @@ #include <QtGui/QPlatformIntegration> #include <QtGui/QPlatformScreen> -#include <QtGui/QPlatformGLContext> +#include <QtGui/QPlatformOpenGLContext> #include <QtGui/QPlatformFontDatabase> #include <GLES2/gl2.h> @@ -92,7 +92,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId = 0) const; QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; diff --git a/src/plugins/platforms/openkode/qopenkodewindow.cpp b/src/plugins/platforms/openkode/qopenkodewindow.cpp index c6fe6d0176..e20904470f 100644 --- a/src/plugins/platforms/openkode/qopenkodewindow.cpp +++ b/src/plugins/platforms/openkode/qopenkodewindow.cpp @@ -53,7 +53,7 @@ #include <EGL/egl.h> -#include <QtGui/qwidget.h> +#include <QtWidgets/qwidget.h> #include <QtGui/private/qwidget_p.h> #include <QtGui/private/qapplication_p.h> @@ -235,7 +235,7 @@ WId QOpenKODEWindow::winId() const return i++; } -QPlatformGLContext *QOpenKODEWindow::glContext() const +QPlatformOpenGLContext *QOpenKODEWindow::glContext() const { return m_platformGlContext; } diff --git a/src/plugins/platforms/openkode/qopenkodewindow.h b/src/plugins/platforms/openkode/qopenkodewindow.h index 317a6b5cd6..f48c3a2bc0 100644 --- a/src/plugins/platforms/openkode/qopenkodewindow.h +++ b/src/plugins/platforms/openkode/qopenkodewindow.h @@ -63,7 +63,7 @@ public: void setVisible(bool visible); WId winId() const; - QPlatformGLContext *glContext() const; + QPlatformOpenGLContext *glContext() const; void raise(); void lower(); diff --git a/src/plugins/platforms/openvglite/qgraphicssystem_vglite.cpp b/src/plugins/platforms/openvglite/qgraphicssystem_vglite.cpp index 203896f489..d8e4cc984c 100644 --- a/src/plugins/platforms/openvglite/qgraphicssystem_vglite.cpp +++ b/src/plugins/platforms/openvglite/qgraphicssystem_vglite.cpp @@ -41,7 +41,7 @@ #include "qgraphicssystem_vglite.h" #include "qwindowsurface_vglite.h" -#include <QtOpenVG/private/qpixmapdata_vg_p.h> +#include <QtOpenVG/qplatformpixmap_vg_p.h> #include <QtGui/private/qegl_p.h> #include <QtCore/qdebug.h> #ifdef OPENVG_USBHP_INIT @@ -163,16 +163,16 @@ QVGLiteGraphicsSystem::~QVGLiteGraphicsSystem() { } -QPixmapData *QVGLiteGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +QPlatformPixmap *QVGLiteGraphicsSystem::createPlatformPixmap(QPlatformPixmap::PixelType type) const { #if !defined(QVGLite_NO_SINGLE_CONTEXT) && !defined(QVGLite_NO_PIXMAP_DATA) - // Pixmaps can use QVGLitePixmapData; bitmaps must use raster. - if (type == QPixmapData::PixmapType) - return new QVGPixmapData(type); + // Pixmaps can use QVGLitePlatformPixmap; bitmaps must use raster. + if (type == QPlatformPixmap::PixmapType) + return new QVGPlatformPixmap(type); else - return new QRasterPixmapData(type); + return new QRasterPlatformPixmap(type); #else - return new QRasterPixmapData(type); + return new QRasterPlatformPixmap(type); #endif } diff --git a/src/plugins/platforms/openvglite/qgraphicssystem_vglite.h b/src/plugins/platforms/openvglite/qgraphicssystem_vglite.h index 41b1d286bc..6dc6a38439 100644 --- a/src/plugins/platforms/openvglite/qgraphicssystem_vglite.h +++ b/src/plugins/platforms/openvglite/qgraphicssystem_vglite.h @@ -57,7 +57,7 @@ public: QVGLiteGraphicsSystem(); ~QVGLiteGraphicsSystem(); - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; QWindowSurface *createWindowSurface(QWidget *widget) const; QList<QGraphicsSystemScreen *> screens() const { return mScreens; } diff --git a/src/plugins/graphicssystems/shivavg/main.cpp b/src/plugins/platforms/openwfd/main.cpp index 53bc782378..c0159e7218 100644 --- a/src/plugins/graphicssystems/shivavg/main.cpp +++ b/src/plugins/platforms/openwfd/main.cpp @@ -39,33 +39,34 @@ ** ****************************************************************************/ -#include <private/qgraphicssystemplugin_p.h> -#include "shivavggraphicssystem.h" +#include <QtGui/QPlatformIntegrationPlugin> +#include "qopenwfdintegration.h" QT_BEGIN_NAMESPACE -class ShivaVGGraphicsSystemPlugin : public QGraphicsSystemPlugin +class QOpenWFDIntegrationPlugin : public QPlatformIntegrationPlugin { public: QStringList keys() const; - QGraphicsSystem *create(const QString&); + QPlatformIntegration *create(const QString&, const QStringList&); }; -QStringList ShivaVGGraphicsSystemPlugin::keys() const +QStringList QOpenWFDIntegrationPlugin::keys() const { QStringList list; - list << "ShivaVG"; + list << "OpenWFD"; return list; } -QGraphicsSystem* ShivaVGGraphicsSystemPlugin::create(const QString& system) +QPlatformIntegration* QOpenWFDIntegrationPlugin::create(const QString& system, const QStringList& paramList) { - if (system.toLower() == "shivavg") - return new ShivaVGGraphicsSystem; + Q_UNUSED(paramList); + if (system.toLower() == "openwfd") + return new QOpenWFDIntegration; return 0; } -Q_EXPORT_PLUGIN2(shivavg, ShivaVGGraphicsSystemPlugin) +Q_EXPORT_PLUGIN2(openwfd, QOpenWFDIntegrationPlugin) QT_END_NAMESPACE diff --git a/src/plugins/platforms/openwfd/openwf.pro b/src/plugins/platforms/openwfd/openwf.pro new file mode 100644 index 0000000000..d913a84411 --- /dev/null +++ b/src/plugins/platforms/openwfd/openwf.pro @@ -0,0 +1,41 @@ +TARGET = qopenwf + +load(qt_plugin) +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms + +QT += core-private gui-private platformsupport-private + +CONFIG += qpa/genericunixfontdatabase + +HEADERS += \ + qopenwfddevice.h \ + qopenwfdintegration.h \ + qopenwfdnativeinterface.h \ + qopenwfdscreen.h \ + qopenwfdbackingstore.h \ + qopenwfdevent.h \ + qopenwfdglcontext.h \ + qopenwfdoutputbuffer.h \ + qopenwfdport.h \ + qopenwfdwindow.h \ + qopenwfdportmode.h + +SOURCES += \ + main.cpp \ + qopenwfddevice.cpp \ + qopenwfdintegration.cpp \ + qopenwfdnativeinterface.cpp \ + qopenwfdscreen.cpp \ + qopenwfdbackingstore.cpp \ + qopenwfdevent.cpp \ + qopenwfdglcontext.cpp \ + qopenwfdoutputbuffer.cpp \ + qopenwfdport.cpp \ + qopenwfdportmode.cpp \ + qopenwfdwindow.cpp + +LIBS += -lWFD -lgbm -lGLESv2 -lEGL + +target.path += $$[QT_INSTALL_PLUGINS]/platforms +INSTALLS += target + diff --git a/src/plugins/platforms/openwfd/qopenwfdbackingstore.cpp b/src/plugins/platforms/openwfd/qopenwfdbackingstore.cpp new file mode 100644 index 0000000000..2638d8cd5a --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdbackingstore.cpp @@ -0,0 +1,25 @@ +#include "qopenwfdbackingstore.h" + +QOpenWFDBackingStore::QOpenWFDBackingStore(QWindow *window) + : QPlatformBackingStore(window) +{ +} + +QPaintDevice * QOpenWFDBackingStore::paintDevice() +{ + return &mImage; +} + +//we don't support flush yet :) +void QOpenWFDBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(window); + Q_UNUSED(region); + Q_UNUSED(offset); +} + +void QOpenWFDBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + Q_UNUSED(staticContents); + mImage = QImage(size,QImage::Format_RGB32); +} diff --git a/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.h b/src/plugins/platforms/openwfd/qopenwfdbackingstore.h index 00da6976b8..c173de6c19 100644 --- a/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.h +++ b/src/plugins/platforms/openwfd/qopenwfdbackingstore.h @@ -39,31 +39,27 @@ ** ****************************************************************************/ -#ifndef QWAYLANDDRMSURFACE_H -#define QWAYLANDDRMSURFACE_H +#ifndef QOPENWFDBACKINGSTORE_H +#define QOPENWFDBACKINGSTORE_H -#include "qwaylanddisplay.h" +#include <QtGui/QPlatformBackingStore> +#include <QtGui/QImage> -#include <QtGui/private/qwindowsurface_p.h> - -class QGLFramebufferObject; - -class QWaylandGLWindowSurface : public QWindowSurface +class QOpenWFDBackingStore : public QPlatformBackingStore { public: - QWaylandGLWindowSurface(QWidget *window); - ~QWaylandGLWindowSurface(); - - void beginPaint(const QRegion &); + QOpenWFDBackingStore(QWindow *window); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - void resize(const QSize &size); + // 'window' can be a child window, in which case 'region' is in child window coordinates and + // offset is the (child) window's offset in relation to the window surface. + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + + void resize(const QSize &size, const QRegion &staticContents); private: - QWaylandDisplay *mDisplay; - QGLFramebufferObject *mPaintDevice; + QImage mImage; }; -#endif // QWAYLANDDRMSURFACE_H +#endif // QOPENWFDBACKINGSTORE_H diff --git a/src/plugins/platforms/openwfd/qopenwfddevice.cpp b/src/plugins/platforms/openwfd/qopenwfddevice.cpp new file mode 100644 index 0000000000..d3ff6d45d8 --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfddevice.cpp @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenwfddevice.h" + +#include "qopenwfdport.h" +#include "qopenwfdscreen.h" + +#include <QtCore/QDebug> + +#include <WF/wfdext.h> +#include <gbm.h> + +QOpenWFDDevice::QOpenWFDDevice(QOpenWFDIntegration *integration, WFDint device_enumeration) + : mIntegration(integration) + , mDeviceEnum(device_enumeration) + , mCommitedDevice(false) + , mWaitingForBindSourceEvent(false) +{ + mDevice = wfdCreateDevice(WFD_DEFAULT_DEVICE_ID,WFD_NONE); + if (mDevice == WFD_INVALID_HANDLE) + qDebug() << "failed to create device"; + + mEvent = wfdCreateEvent(mDevice,0); + if (mEvent == WFD_INVALID_HANDLE) + qDebug() << "failed to create event handle"; + + //initialize pipelines for device. + wfdEnumeratePipelines(mDevice,WFD_NONE,0,WFD_NONE); + + initializeGbmAndEgl(); + + WFDint numberOfPorts = wfdEnumeratePorts(mDevice,0,0,0); + WFDint port_enumerations[numberOfPorts]; + WFDint actualNumberOfPorts = wfdEnumeratePorts(mDevice,port_enumerations,numberOfPorts,WFD_NONE); + Q_ASSERT(actualNumberOfPorts == numberOfPorts); + + for (int i = 0; i < actualNumberOfPorts; i++) + { + QOpenWFDPort *port = new QOpenWFDPort(this,port_enumerations[i]); + if (port->attached()) { + mPorts.append(port); + } else { + delete port; + } + } + + int fd = wfdDeviceEventGetFD(mDevice,mEvent); + mEventSocketNotifier = new QSocketNotifier(fd,QSocketNotifier::Read,this); + connect(mEventSocketNotifier,SIGNAL(activated(int)),SLOT(readEvents())); + + mCommitedDevice = true; + commit(WFD_COMMIT_ENTIRE_DEVICE, handle()); +} + +QOpenWFDDevice::~QOpenWFDDevice() +{ + delete mEventSocketNotifier; + wfdDestroyEvent(mDevice,mEvent); + + for (int i = 0; i < mPorts.size(); i++) { + //probably don't need to remove them from the list + QList <WFDint> keys = mUsedPipelines.keys(mPorts.at(i)); + for (int keyIndex = 0; keyIndex < keys.size(); keyIndex++) { + mUsedPipelines.remove(keys.at(keyIndex)); + } + //but we have to delete them :) + delete mPorts[i]; + } + + eglDestroyContext(mEglDisplay,mEglContext); + eglTerminate(mEglDisplay); + + gbm_device_destroy(mGbmDevice); + + wfdDestroyDevice(mDevice); +} + +WFDDevice QOpenWFDDevice::handle() const +{ + return mDevice; +} + +QOpenWFDIntegration * QOpenWFDDevice::integration() const +{ + return mIntegration; +} + +bool QOpenWFDDevice::isPipelineUsed(WFDint pipelineId) +{ + return mUsedPipelines.contains(pipelineId); +} + +void QOpenWFDDevice::addToUsedPipelineSet(WFDint pipelineId,QOpenWFDPort *port) +{ + mUsedPipelines.insert(pipelineId,port); +} + +void QOpenWFDDevice::removeFromUsedPipelineSet(WFDint pipelineId) +{ + mUsedPipelines.remove(pipelineId); +} + +gbm_device * QOpenWFDDevice::gbmDevice() const + +{ + return mGbmDevice; +} + +EGLDisplay QOpenWFDDevice::eglDisplay() const +{ + return mEglDisplay; +} + +EGLContext QOpenWFDDevice::eglContext() const +{ + return mEglContext; +} + +void QOpenWFDDevice::commit(WFDCommitType type, WFDHandle handle) +{ + if (mCommitedDevice) { + wfdDeviceCommit(mDevice,type,handle); + } +} + +void QOpenWFDDevice::waitForPipelineBindSourceCompleteEvent() +{ + mWaitingForBindSourceEvent = true; + + while (mWaitingForBindSourceEvent) { + readEvents(WFD_FOREVER); + } +} + +void QOpenWFDDevice::readEvents(WFDtime wait) +{ + WFDEventType type = wfdDeviceEventWait(mDevice,mEvent,wait); + + if (type == WFD_EVENT_NONE || type == WFD_EVENT_DESTROYED) { + return; + } + switch (type) { + case WFD_EVENT_INVALID: + case WFD_EVENT_NONE: + return; + case WFD_EVENT_DESTROYED: + qDebug() << "Event or Device destoryed!"; + return; + case WFD_EVENT_PORT_ATTACH_DETACH: + handlePortAttachDetach(); + break; + case WFD_EVENT_PORT_PROTECTION_FAILURE: + qDebug() << "Port protection event handling not implemented"; + break; + case WFD_EVENT_PIPELINE_BIND_SOURCE_COMPLETE: + handlePipelineBindSourceComplete(); + break; + case WFD_EVENT_PIPELINE_BIND_MASK_COMPLETE: + qDebug() << "Pipeline bind mask event handling not implemented"; + break; + default: + qDebug() << "Not recognised event type"; + break; + } + + +} + +void QOpenWFDDevice::initializeGbmAndEgl() +{ + + qDebug() << "initializing GBM and EGL"; + int fd = wfdGetDeviceAttribi(mDevice,WFD_DEVICE_ID); + if (fd < 0) { + qDebug() << "failed to get WFD_DEVICE_ID"; + } + + mGbmDevice = gbm_create_device(fd); + + setenv("EGL_PLATFORM", "drm",1); + + mEglDisplay = eglGetDisplay(mGbmDevice); + + EGLint minor, major; + + if (!eglInitialize(mEglDisplay,&major,&minor)) { + qDebug() << "failed to initialize egl"; + } + + QByteArray eglExtensions = eglQueryString(mEglDisplay, EGL_EXTENSIONS); + if (!eglExtensions.contains("EGL_KHR_surfaceless_opengl")) { + qDebug() << "This egl implementation does not have the required EGL extension EGL_KHR_surfaceless_opengl"; + } + + eglBindAPI(EGL_OPENGL_ES_API); + + EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + mEglContext = eglCreateContext(mEglDisplay,NULL,EGL_NO_CONTEXT,contextAttribs); + if (mEglContext == EGL_NO_CONTEXT) { + qDebug() << "Failed to create EGL context"; + } + + eglCreateImage = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR"); + if (!eglCreateImage) { + qWarning("failed to load extension eglCreateImageKHR"); + } + + eglDestroyImage = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR"); + if (!eglDestroyImage) { + qWarning("failed to load extension eglDestoryImageKHR"); + } + + glEglImageTargetRenderBufferStorage = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES"); + if (!glEglImageTargetRenderBufferStorage) { + qWarning("failed to load extension glEGLImageTargetRenderbufferStorageOES"); + } +} + +void QOpenWFDDevice::handlePortAttachDetach() +{ + WFDint id = wfdGetEventAttribi(mDevice,mEvent,WFD_EVENT_PORT_ATTACH_PORT_ID); + if (id == WFD_INVALID_PORT_ID) + return; + + WFDint attachState = wfdGetEventAttribi(mDevice,mEvent,WFD_EVENT_PORT_ATTACH_STATE); + if (attachState == WFD_TRUE) { + int indexToAdd = -1; + for (int i = 0; i < mPorts.size(); i++) { + if (mPorts.at(i)->portId() == id) { + indexToAdd = i; + qDebug() << "found index to attach"; + break; + } + } + if (indexToAdd >= 0) { + mPorts[indexToAdd]->attach(); + } else { + mPorts.append(new QOpenWFDPort(this,id)); + } + + } else { + int indexToDelete = -1; + for (int i = 0; i < mPorts.size(); i++) { + if (mPorts.at(i)->portId() == id) { + indexToDelete = i; + break; + } + } + if (indexToDelete >= 0) { + QOpenWFDPort *portToDelete = mPorts.at(indexToDelete); + mPorts.removeAt(indexToDelete); + delete portToDelete; + } + } +} + +void QOpenWFDDevice::handlePipelineBindSourceComplete() +{ + mWaitingForBindSourceEvent = false; + + WFDint overflow = wfdGetEventAttribi(mDevice,mEvent, WFD_EVENT_PIPELINE_BIND_QUEUE_OVERFLOW); + if (overflow == WFD_TRUE) { + qDebug() << "PIPELINE_BIND_QUEUE_OVERFLOW event occured"; + } + + WFDint pipelineId = wfdGetEventAttribi(mDevice,mEvent,WFD_EVENT_PIPELINE_BIND_PIPELINE_ID); + for (int i = 0; i < mPorts.size(); i++) { + if (pipelineId != WFD_INVALID_PIPELINE_ID && mUsedPipelines.contains(pipelineId)) { + QOpenWFDPort *port = mUsedPipelines.value(pipelineId); + port->screen()->pipelineBindSourceComplete(); + break; + } + } +} diff --git a/src/plugins/platforms/openwfd/qopenwfddevice.h b/src/plugins/platforms/openwfd/qopenwfddevice.h new file mode 100644 index 0000000000..83a5539124 --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfddevice.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENWFDDEVICE_H +#define QOPENWFDDEVICE_H + +#include "qopenwfdintegration.h" + +#include <QtCore/QList> +#include <QtCore/QSet> +#include <QtCore/QSocketNotifier> + +#include <WF/wfd.h> + +#include <gbm.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +class QOpenWFDPort; + +class QOpenWFDDevice : public QObject +{ + Q_OBJECT +public: + QOpenWFDDevice(QOpenWFDIntegration *integration, WFDint handle); + ~QOpenWFDDevice(); + WFDDevice handle() const; + QOpenWFDIntegration *integration() const; + + + bool isPipelineUsed(WFDint pipelineId); + void addToUsedPipelineSet(WFDint pipelineId, QOpenWFDPort *port); + void removeFromUsedPipelineSet(WFDint pipelineId); + + gbm_device *gbmDevice() const; + EGLDisplay eglDisplay() const; + EGLContext eglContext() const; + + PFNEGLCREATEIMAGEKHRPROC eglCreateImage; + PFNEGLDESTROYIMAGEKHRPROC eglDestroyImage; + PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEglImageTargetRenderBufferStorage; + + void commit(WFDCommitType type, WFDHandle handle); + bool isDeviceInitializedAndCommited() const { return mCommitedDevice; } + + void waitForPipelineBindSourceCompleteEvent(); + +public slots: + void readEvents(WFDtime wait = 0); +private: + void initializeGbmAndEgl(); + void handlePortAttachDetach(); + void handlePipelineBindSourceComplete(); + QOpenWFDIntegration *mIntegration; + WFDint mDeviceEnum; + WFDDevice mDevice; + + WFDEvent mEvent; + QSocketNotifier *mEventSocketNotifier; + + QList<QOpenWFDPort *> mPorts; + + QMap<WFDint, QOpenWFDPort *> mUsedPipelines; + + struct gbm_device *mGbmDevice; + EGLDisplay mEglDisplay; + EGLContext mEglContext; + + bool mCommitedDevice; + bool mWaitingForBindSourceEvent; +}; + +#endif // QOPENWFDDEVICE_H diff --git a/src/plugins/platforms/eglconvenience/qxlibeglintegration.h b/src/plugins/platforms/openwfd/qopenwfdevent.cpp index 1d02ab8677..748dde65e7 100644 --- a/src/plugins/platforms/eglconvenience/qxlibeglintegration.h +++ b/src/plugins/platforms/openwfd/qopenwfdevent.cpp @@ -39,15 +39,8 @@ ** ****************************************************************************/ -#ifndef QTESTLITEEGLINTEGRATION_H -#define QTESTLITEEGLINTEGRATION_H +#include "qopenwfdevent.h" -#include "qeglconvenience.h" - -class QXlibEglIntegration +QOpenWFDEvent::QOpenWFDEvent() { -public: - static VisualID getCompatibleVisualId(Display *display, EGLDisplay eglDisplay, EGLConfig config); -}; - -#endif // QTESTLITEEGLINTEGRATION_H +} diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.h b/src/plugins/platforms/openwfd/qopenwfdevent.h index c0e5c2a524..3010fdb55b 100644 --- a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.h +++ b/src/plugins/platforms/openwfd/qopenwfdevent.h @@ -39,9 +39,13 @@ ** ****************************************************************************/ -#ifndef EGLNULLWSSCREENPLUGIN_H -#define EGLNULLWSSCREENPLUGIN_H +#ifndef QOPENWFDEVENT_H +#define QOPENWFDEVENT_H -const char *const PluginName = "eglnullws"; +class QOpenWFDEvent +{ +public: + QOpenWFDEvent(); +}; -#endif // EGLNULLWSSCREENPLUGIN_H +#endif // QOPENWFDEVENT_H diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp b/src/plugins/platforms/openwfd/qopenwfdglcontext.cpp index 829996b0b0..0db717c4d6 100644 --- a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp +++ b/src/plugins/platforms/openwfd/qopenwfdglcontext.cpp @@ -39,50 +39,59 @@ ** ****************************************************************************/ -#include "qgraphicssystem_vg_p.h" -#include <QtOpenVG/private/qpixmapdata_vg_p.h> -#include <QtOpenVG/private/qwindowsurface_vg_p.h> -#include <QtOpenVG/private/qvgimagepool_p.h> -#if defined(Q_OS_SYMBIAN) -#include <QtGui/private/qwidget_p.h> -#endif -#include <QtGui/private/qapplication_p.h> +#include "qopenwfdglcontext.h" -QT_BEGIN_NAMESPACE +#include "qopenwfdwindow.h" +#include "qopenwfdscreen.h" -QVGGraphicsSystem::QVGGraphicsSystem() +QOpenWFDGLContext::QOpenWFDGLContext(QOpenWFDDevice *device) + : QPlatformOpenGLContext() + , mWfdDevice(device) { - QApplicationPrivate::graphics_system_name = QLatin1String("openvg"); } -QPixmapData *QVGGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +QSurfaceFormat QOpenWFDGLContext::format() const { -#if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QVG_NO_PIXMAP_DATA) - // Pixmaps can use QVGPixmapData; bitmaps must use raster. - if (type == QPixmapData::PixmapType) - return new QVGPixmapData(type); - else - return new QRasterPixmapData(type); -#else - return new QRasterPixmapData(type); -#endif + return QSurfaceFormat(); } -QWindowSurface *QVGGraphicsSystem::createWindowSurface(QWidget *widget) const +bool QOpenWFDGLContext::makeCurrent(QPlatformSurface *surface) { -#if defined(Q_OS_SYMBIAN) - if (!QApplicationPrivate::instance()->useTranslucentEGLSurfaces) { - QWidgetPrivate *d = qt_widget_private(widget); - if (!d->isOpaque && widget->testAttribute(Qt::WA_TranslucentBackground)) - return d->createDefaultWindowSurface_sys(); + EGLDisplay display = mWfdDevice->eglDisplay(); + EGLContext context = mWfdDevice->eglContext(); + if (!eglMakeCurrent(display,EGL_NO_SURFACE,EGL_NO_SURFACE,context)) { + qDebug() << "GLContext: eglMakeCurrent FAILED!"; } -#endif - return new QVGWindowSurface(widget); + + QPlatformWindow *window = static_cast<QPlatformWindow *>(surface); + QOpenWFDScreen *screen = static_cast<QOpenWFDScreen *>(QPlatformScreen::platformScreenForWindow(window->window())); + screen->bindFramebuffer(); + return true; } -void QVGGraphicsSystem::releaseCachedResources() +void QOpenWFDGLContext::doneCurrent() { - QVGImagePool::instance()->hibernate(); + //do nothing :) } -QT_END_NAMESPACE +void QOpenWFDGLContext::swapBuffers(QPlatformSurface *surface) +{ + glFlush(); + + QPlatformWindow *window = static_cast<QPlatformWindow *>(surface); + QOpenWFDScreen *screen = static_cast<QOpenWFDScreen *>(QPlatformScreen::platformScreenForWindow(window->window())); + + screen->swapBuffers(); +} + +void (*QOpenWFDGLContext::getProcAddress(const QByteArray &procName)) () +{ + return eglGetProcAddress(procName.data()); +} + +EGLContext QOpenWFDGLContext::eglContext() const +{ + return mWfdDevice->eglContext(); +} + + diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.h b/src/plugins/platforms/openwfd/qopenwfdglcontext.h index bdb1d42d7e..3287a853c7 100644 --- a/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.h +++ b/src/plugins/platforms/openwfd/qopenwfdglcontext.h @@ -39,25 +39,30 @@ ** ****************************************************************************/ -#ifndef EGLNULLWSWINDOWSURFACE_H -#define EGLNULLWSWINDOWSURFACE_H +#ifndef QOPENWFDGLCONTEXT_H +#define QOPENWFDGLCONTEXT_H -#include <private/qglwindowsurface_qws_p.h> +#include <QtGui/QPlatformOpenGLContext> -class EGLNullWSWindowSurface : public QWSGLWindowSurface +#include "qopenwfddevice.h" + +class QOpenWFDGLContext : public QPlatformOpenGLContext { public: - EGLNullWSWindowSurface(QWidget *widget); - EGLNullWSWindowSurface(); - virtual ~EGLNullWSWindowSurface(); + QOpenWFDGLContext(QOpenWFDDevice *device); + + QSurfaceFormat format() const; + + bool makeCurrent(QPlatformSurface *surface); + void doneCurrent(); + + void swapBuffers(QPlatformSurface *surface); - virtual QString key() const; - virtual QPaintDevice *paintDevice(); - virtual bool isValid() const; - virtual QImage image() const; + void (*getProcAddress(const QByteArray &procName)) (); + EGLContext eglContext() const; private: - QWidget *widget; + QOpenWFDDevice *mWfdDevice; }; -#endif // EGLNULLWSWINDOWSURFACE_H +#endif // QOPENWFDGLCONTEXT_H diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp new file mode 100644 index 0000000000..3d57759183 --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenwfdintegration.h" +#include "qopenwfdscreen.h" +#include "qopenwfdnativeinterface.h" +#include "qopenwfddevice.h" +#include "qopenwfdwindow.h" +#include "qopenwfdglcontext.h" +#include "qopenwfdbackingstore.h" + +#include <QtPlatformSupport/private/qgenericunixprintersupport_p.h> + +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/QOpenGLContext> +#include <QtGui/QScreen> + +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> + +#include <stdio.h> + +#include <WF/wfd.h> + +QOpenWFDIntegration::QOpenWFDIntegration() + : QPlatformIntegration() + , mPrinterSupport(new QGenericUnixPrinterSupport) + , mEventDispatcher(createUnixEventDispatcher()) +{ + QGuiApplicationPrivate::instance()->setEventDispatcher(mEventDispatcher); + int numberOfDevices = wfdEnumerateDevices(0,0,0); + + WFDint devices[numberOfDevices]; + int actualNumberOfDevices = wfdEnumerateDevices(devices,numberOfDevices,0); + Q_ASSERT(actualNumberOfDevices == numberOfDevices); + + for (int i = 0; i < actualNumberOfDevices; i++) { + mDevices.append(new QOpenWFDDevice(this,devices[i])); + } + + mFontDatabase = new QGenericUnixFontDatabase(); + mNativeInterface = new QOpenWFDNativeInterface; +} + +QOpenWFDIntegration::~QOpenWFDIntegration() +{ + //dont delete screens since they are deleted by the devices + qDebug() << "deleting platform integration"; + for (int i = 0; i < mDevices.size(); i++) { + delete mDevices[i]; + } + + delete mFontDatabase; + delete mNativeInterface; + delete mPrinterSupport; +} + +bool QOpenWFDIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ + switch (cap) { + case ThreadedPixmaps: return true; + case OpenGL: return true; + default: return QPlatformIntegration::hasCapability(cap); + } +} + +QPlatformWindow *QOpenWFDIntegration::createPlatformWindow(QWindow *window) const +{ + return new QOpenWFDWindow(window); +} + +QPlatformOpenGLContext *QOpenWFDIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ + QOpenWFDScreen *screen = static_cast<QOpenWFDScreen *>(context->screen()->handle()); + + return new QOpenWFDGLContext(screen->port()->device()); +} + +QPlatformBackingStore *QOpenWFDIntegration::createPlatformBackingStore(QWindow *window) const +{ + return new QOpenWFDBackingStore(window); +} + +QAbstractEventDispatcher *QOpenWFDIntegration::guiThreadEventDispatcher() const +{ + return mEventDispatcher; +} + +QPlatformFontDatabase *QOpenWFDIntegration::fontDatabase() const +{ + return mFontDatabase; +} + +QPlatformNativeInterface * QOpenWFDIntegration::nativeInterface() const +{ + return mNativeInterface; +} + +QPlatformPrinterSupport * QOpenWFDIntegration::printerSupport() const +{ + return mPrinterSupport; +} + +void QOpenWFDIntegration::addScreen(QOpenWFDScreen *screen) +{ + screenAdded(screen); +} diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.h b/src/plugins/platforms/openwfd/qopenwfdintegration.h new file mode 100644 index 0000000000..b5315b31da --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdintegration.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENWFDINTEGRATION_H +#define QOPENWFDINTEGRATION_H + +#include <QtGui/QPlatformIntegration> +#include <QtGui/QPlatformScreen> + +QT_BEGIN_NAMESPACE + +class QOpenWFDDevice; +class QOpenWFDScreen; + +class QOpenWFDIntegration : public QPlatformIntegration +{ +public: + QOpenWFDIntegration(); + ~QOpenWFDIntegration(); + + bool hasCapability(Capability cap) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + + //This should not be a factory interface, but rather a accessor + QAbstractEventDispatcher *guiThreadEventDispatcher() const; + + QPlatformFontDatabase *fontDatabase() const; + + QPlatformNativeInterface *nativeInterface()const; + + QPlatformPrinterSupport *printerSupport() const; + + void addScreen(QOpenWFDScreen *screen); +private: + QList<QPlatformScreen *> mScreens; + QList<QOpenWFDDevice *>mDevices; + + QPlatformFontDatabase *mFontDatabase; + QPlatformNativeInterface *mNativeInterface; + QPlatformPrinterSupport *mPrinterSupport; + QAbstractEventDispatcher *mEventDispatcher; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp b/src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp new file mode 100644 index 0000000000..758e0c4398 --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenwfdnativeinterface.h" + +#include "qopenwfdscreen.h" +#include "qopenwfdwindow.h" +#include "qopenwfdglcontext.h" + +#include <private/qguiapplication_p.h> +#include <QtCore/QMap> + +#include <QtCore/QDebug> + +#include <QtGui/qguiglcontext_qpa.h> + +class QOpenWFDResourceMap : public QMap<QByteArray, QOpenWFDNativeInterface::ResourceType> +{ +public: + QOpenWFDResourceMap() + :QMap<QByteArray, QOpenWFDNativeInterface::ResourceType>() + { + insert("wfddevice",QOpenWFDNativeInterface::WFDDevice); + insert("egldisplay",QOpenWFDNativeInterface::EglDisplay); + insert("eglcontext",QOpenWFDNativeInterface::EglContext); + insert("wfdport",QOpenWFDNativeInterface::WFDPort); + insert("wfdpipeline",QOpenWFDNativeInterface::WFDPipeline); + } +}; + +Q_GLOBAL_STATIC(QOpenWFDResourceMap, qOpenWFDResourceMap) + +void *QOpenWFDNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) +{ + QByteArray lowerCaseResource = resourceString.toLower(); + ResourceType resource = qOpenWFDResourceMap()->value(lowerCaseResource); + void *result = 0; + switch (resource) { + case EglContext: + result = eglContextForContext(context); + break; + default: + result = 0; + } + return result; +} + +void *QOpenWFDNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) +{ + QByteArray lowerCaseResource = resourceString.toLower(); + ResourceType resource = qOpenWFDResourceMap()->value(lowerCaseResource); + void *result = 0; + switch (resource) { + //What should we do for int wfd handles? This is clearly not the solution + case WFDDevice: + result = (void *)wfdDeviceForWindow(window); + break; + case WFDPort: + result = (void *)wfdPortForWindow(window); + break; + case WFDPipeline: + result = (void *)wfdPipelineForWindow(window); + break; + case EglDisplay: + result = eglDisplayForWindow(window); + break; + default: + result = 0; + } + return result; +} + +WFDHandle QOpenWFDNativeInterface::wfdDeviceForWindow(QWindow *window) +{ + QOpenWFDWindow *openWFDwindow = static_cast<QOpenWFDWindow *>(window->handle()); + return openWFDwindow->port()->device()->handle(); +} + +WFDHandle QOpenWFDNativeInterface::wfdPortForWindow(QWindow *window) +{ + QOpenWFDWindow *openWFDwindow = static_cast<QOpenWFDWindow *>(window->handle()); + return openWFDwindow->port()->handle(); +} + +WFDHandle QOpenWFDNativeInterface::wfdPipelineForWindow(QWindow *window) + +{ + QOpenWFDWindow *openWFDwindow = static_cast<QOpenWFDWindow *>(window->handle()); + return openWFDwindow->port()->pipeline(); + +} + +void *QOpenWFDNativeInterface::eglDisplayForWindow(QWindow *window) +{ + QOpenWFDWindow *openWFDwindow = static_cast<QOpenWFDWindow *>(window->handle()); + return openWFDwindow->port()->device()->eglDisplay(); +} + +void * QOpenWFDNativeInterface::eglContextForContext(QOpenGLContext *context) +{ + QOpenWFDGLContext *openWFDContext = static_cast<QOpenWFDGLContext *>(context->handle()); + return openWFDContext->eglContext(); +} diff --git a/src/plugins/graphicssystems/trace/qgraphicssystem_trace_p.h b/src/plugins/platforms/openwfd/qopenwfdnativeinterface.h index b6cfc60293..cff49dc8b0 100644 --- a/src/plugins/graphicssystems/trace/qgraphicssystem_trace_p.h +++ b/src/plugins/platforms/openwfd/qopenwfdnativeinterface.h @@ -39,33 +39,38 @@ ** ****************************************************************************/ -#ifndef QGRAPHICSSYSTEM_TRACE_P_H -#define QGRAPHICSSYSTEM_TRACE_P_H +#ifndef QOPENWFDNATIVEINTERFACE_H +#define QOPENWFDNATIVEINTERFACE_H -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// +#include <QtGui/QPlatformNativeInterface> -#include <QtGui/private/qgraphicssystem_p.h> +#include <WF/wfdplatform.h> -QT_BEGIN_NAMESPACE +class QOpenWFDScreen; -class QTraceGraphicsSystem : public QGraphicsSystem +class QOpenWFDNativeInterface : public QPlatformNativeInterface { public: - QTraceGraphicsSystem(); + enum ResourceType { + WFDDevice, + EglDisplay, + EglContext, + WFDPort, + WFDPipeline + }; - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QWindowSurface *createWindowSurface(QWidget *widget) const; -}; + void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); + void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); + + WFDHandle wfdDeviceForWindow(QWindow *window); + void *eglDisplayForWindow(QWindow *window); + WFDHandle wfdPortForWindow(QWindow *window); + WFDHandle wfdPipelineForWindow(QWindow *window); -QT_END_NAMESPACE + void *eglContextForContext(QOpenGLContext *context); + +private: + static QOpenWFDScreen *qPlatformScreenForWindow(QWindow *window); +}; -#endif +#endif // QOPENWFDNATIVEINTERFACE_H diff --git a/src/plugins/platforms/fontdatabases/genericunix/qgenericunixfontdatabase.h b/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.cpp index 8bf542a215..fb3292c31a 100644 --- a/src/plugins/platforms/fontdatabases/genericunix/qgenericunixfontdatabase.h +++ b/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.cpp @@ -39,15 +39,52 @@ ** ****************************************************************************/ -#ifndef QGENERICUNIXFONTDATABASE_H -#define QGENERICUNIXFONTDATABASE_H - -#ifdef Q_FONTCONFIGDATABASE -#include "qfontconfigdatabase.h" -typedef QFontconfigDatabase QGenericUnixFontDatabase; -#else -#include "qbasicunixfontdatabase.h" -typedef QBasicUnixFontDatabase QGenericUnixFontDatabase; -#endif //Q_FONTCONFIGDATABASE - -#endif // QGENERICUNIXFONTDATABASE_H +#include "qopenwfdoutputbuffer.h" + +#include "qopenwfdport.h" + +QOpenWFDOutputBuffer::QOpenWFDOutputBuffer(const QSize &size, QOpenWFDPort *port) + : mPort(port) + , mAvailable(true) +{ + qDebug() << "creating output buffer for size" << size; + glGenRenderbuffers(1,&mRbo); + glBindRenderbuffer(GL_RENDERBUFFER, mRbo); + + mGbm_buffer = gbm_bo_create(port->device()->gbmDevice(), + size.width(), + size.height(), + GBM_BO_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + + mEglImage = port->device()->eglCreateImage(port->device()->eglDisplay(),0, EGL_NATIVE_PIXMAP_KHR, mGbm_buffer, 0); + + port->device()->glEglImageTargetRenderBufferStorage(GL_RENDERBUFFER,mEglImage); + + mWfdSource = wfdCreateSourceFromImage(port->device()->handle(),port->pipeline(),mEglImage,WFD_NONE); + if (mWfdSource == WFD_INVALID_HANDLE) { + qWarning("failed to create wfdSource from image"); + } +} + +QOpenWFDOutputBuffer::~QOpenWFDOutputBuffer() +{ + wfdDestroySource(mPort->device()->handle(),mWfdSource); + if (!mPort->device()->eglDestroyImage(mPort->device()->eglDisplay(),mEglImage)) { + qDebug() << "could not delete eglImage"; + } + gbm_bo_destroy(mGbm_buffer); + + glDeleteRenderbuffers(1, &mRbo); +} + +void QOpenWFDOutputBuffer::bindToCurrentFbo() +{ + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + mRbo); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + qDebug() << "framebuffer not ready!"; + } +} diff --git a/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.h b/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.h new file mode 100644 index 0000000000..1697f076a9 --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENWFDOUTPUTBUFFER_H +#define QOPENWFDOUTPUTBUFFER_H + +#include "qopenwfdport.h" + +#include <EGL/egl.h> +#include <GLES2/gl2.h> + +class QOpenWFDOutputBuffer +{ +public: + QOpenWFDOutputBuffer(const QSize &size, QOpenWFDPort *port); + ~QOpenWFDOutputBuffer(); + void bindToCurrentFbo(); + bool isAvailable() const { return mAvailable; } + void setAvailable(bool available) { mAvailable = available; } + + WFDSource wfdSource() const { return mWfdSource; } +private: + QOpenWFDPort *mPort; + WFDSource mWfdSource; + GLuint mRbo; + EGLImageKHR mEglImage; + struct gbm_bo *mGbm_buffer; + bool mAvailable; +}; + +#endif // QOPENWFDOUTPUTBUFFER_H diff --git a/src/plugins/platforms/openwfd/qopenwfdport.cpp b/src/plugins/platforms/openwfd/qopenwfdport.cpp new file mode 100644 index 0000000000..5f38e48eed --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdport.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenwfdport.h" + +#include "qopenwfdportmode.h" +#include "qopenwfdscreen.h" + +#include <QtCore/QDebug> + +QOpenWFDPort::QOpenWFDPort(QOpenWFDDevice *device, WFDint portEnumeration) + : mDevice(device) + , mPortId(portEnumeration) + , mAttached(false) + , mPipelineId(WFD_INVALID_PIPELINE_ID) + , mPipeline(WFD_INVALID_HANDLE) +{ + mPort = wfdCreatePort(device->handle(),portEnumeration,0); + WFDint isPortAttached = wfdGetPortAttribi(device->handle(),mPort,WFD_PORT_ATTACHED); + if (isPortAttached) { + attach(); + } +} + +QOpenWFDPort::~QOpenWFDPort() +{ + detach(); + + wfdDestroyPort(mDevice->handle(),mPort); +} + +void QOpenWFDPort::attach() +{ + if (mAttached) { + return; + } + + //just forcing port to be on + wfdSetPortAttribi(mDevice->handle(), mPort, WFD_PORT_POWER_MODE, WFD_POWER_MODE_ON); + + int numberOfPortModes = wfdGetPortModes(mDevice->handle(),mPort,0,0); + WFDPortMode portModes[numberOfPortModes]; + int actualNumberOfPortModes = wfdGetPortModes(mDevice->handle(),mPort,portModes,numberOfPortModes); + Q_ASSERT(actualNumberOfPortModes == numberOfPortModes); + + if (!actualNumberOfPortModes) { + qDebug() << "didn't find any available port modes"; + return; + } + + for (int i = 0; i < actualNumberOfPortModes; i++) { + if (portModes[i] != WFD_INVALID_HANDLE) { + mPortModes.append(QOpenWFDPortMode(this,portModes[i])); + qDebug() << "PortModeAdded:" << mPortModes.at(mPortModes.size()-1); + } + } + + + mPixelSize = setNativeResolutionMode(); + if (mPixelSize.isEmpty()) { + qDebug() << "Could not set native resolution mode in QOpenWFPort"; + } + + WFDfloat physicalWFDSize[2]; + wfdGetPortAttribfv(mDevice->handle(),mPort,WFD_PORT_PHYSICAL_SIZE,2,physicalWFDSize); + mPhysicalSize = QSizeF(physicalWFDSize[0],physicalWFDSize[1]); + + WFDint numAvailablePipelines = wfdGetPortAttribi(mDevice->handle(),mPort,WFD_PORT_PIPELINE_ID_COUNT); + if (!numAvailablePipelines) { + qFatal("Not possible to make screen that is not possible to create WFPort with no pipline"); + } + + WFDint pipeIds[numAvailablePipelines]; + wfdGetPortAttribiv(mDevice->handle(),mPort,WFD_PORT_BINDABLE_PIPELINE_IDS,numAvailablePipelines,pipeIds); + + for (int i = 0; i < numAvailablePipelines; i++) { + if (pipeIds[i] != WFD_INVALID_PIPELINE_ID && !mDevice->isPipelineUsed(pipeIds[i])) { + mPipelineId = pipeIds[i]; + mDevice-> addToUsedPipelineSet(mPipelineId,this); + + mPipeline = wfdCreatePipeline(mDevice->handle(),mPipelineId,WFD_NONE); + if (mPipeline == WFD_INVALID_HANDLE) { + qFatal("Failed to create pipeline for port %p", this); + } + break; + } + } + + if (mPipeline == WFD_INVALID_HANDLE) { + qWarning("Failed to create pipeline and cant bind it to port"); + } + + WFDint geomerty[] = { 0, 0, mPixelSize.width(), mPixelSize.height() }; + + wfdSetPipelineAttribiv(mDevice->handle(),mPipeline, WFD_PIPELINE_SOURCE_RECTANGLE, 4, geomerty); + wfdSetPipelineAttribiv(mDevice->handle(),mPipeline, WFD_PIPELINE_DESTINATION_RECTANGLE, 4, geomerty); + + wfdBindPipelineToPort(mDevice->handle(),mPort,mPipeline); + + mScreen = new QOpenWFDScreen(this); + mDevice->integration()->addScreen(mScreen); + mAttached = true; +} + +void QOpenWFDPort::detach() +{ + if (!mAttached) + return; + + mAttached = false; + mOn = false; + + delete mScreen; + + wfdDestroyPipeline(mDevice->handle(),mPipeline); + mPipelineId = WFD_INVALID_PIPELINE_ID; + mPipeline = WFD_INVALID_HANDLE; +} + +bool QOpenWFDPort::attached() const +{ + return mAttached; +} + +QSize QOpenWFDPort::setNativeResolutionMode() +{ + WFDint nativePixelSize[2]; + wfdGetPortAttribiv(device()->handle(),mPort,WFD_PORT_NATIVE_RESOLUTION,2,nativePixelSize); + QSize nativeSize(nativePixelSize[0],nativePixelSize[1]); + + for (int i = 0; i < mPortModes.size(); i++) { + const QOpenWFDPortMode &mode = mPortModes.at(i); + if (nativeSize == mode.size()) { + wfdSetPortMode(device()->handle(),mPort,mode.handle()); + return nativeSize; + } + } + return QSize(); +} + +QSize QOpenWFDPort::pixelSize() const +{ + return mPixelSize; +} + +QSizeF QOpenWFDPort::physicalSize() const +{ + return mPhysicalSize; +} + +QOpenWFDDevice * QOpenWFDPort::device() const +{ + return mDevice; +} + +WFDPort QOpenWFDPort::handle() const +{ + return mPort; +} + +WFDint QOpenWFDPort::portId() const +{ + return mPortId; +} + +WFDPipeline QOpenWFDPort::pipeline() const +{ + return mPipeline; +} + +QOpenWFDScreen * QOpenWFDPort::screen() const +{ + return mScreen; +} diff --git a/src/plugins/platforms/openwfd/qopenwfdport.h b/src/plugins/platforms/openwfd/qopenwfdport.h new file mode 100644 index 0000000000..497c43749e --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdport.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENWFDPORT_H +#define QOPENWFDPORT_H + +#include "qopenwfddevice.h" +#include "qopenwfdportmode.h" + +#include <WF/wfd.h> + +class QOpenWFDPort +{ +public: + QOpenWFDPort(QOpenWFDDevice *device, WFDint portEnumeration); + ~QOpenWFDPort(); + void attach(); + void detach(); + bool attached() const; + + QSize setNativeResolutionMode(); + + QSize pixelSize() const; + QSizeF physicalSize() const; + + QOpenWFDDevice *device() const; + WFDPort handle() const; + WFDint portId() const; + WFDPipeline pipeline() const; + QOpenWFDScreen *screen() const; + +private: + QOpenWFDDevice *mDevice; + WFDPort mPort; + WFDint mPortId; + + QList<QOpenWFDPortMode> mPortModes; + + bool mAttached; + bool mOn; + QSize mPixelSize; + QSizeF mPhysicalSize; + + QOpenWFDScreen *mScreen; + + WFDint mPipelineId; + WFDPipeline mPipeline; + +}; + +#endif // QOPENWFDPORT_H diff --git a/src/plugins/gfxdrivers/ahi/qscreenahiplugin.cpp b/src/plugins/platforms/openwfd/qopenwfdportmode.cpp index 8cbc0447e5..4e507a42a1 100644 --- a/src/plugins/gfxdrivers/ahi/qscreenahiplugin.cpp +++ b/src/plugins/platforms/openwfd/qopenwfdportmode.cpp @@ -39,36 +39,25 @@ ** ****************************************************************************/ -#include "qscreenahi_qws.h" +#include "qopenwfdportmode.h" -#include <QScreenDriverPlugin> -#include <QStringList> +#include "qopenwfdport.h" -class QAhiScreenPlugin : public QScreenDriverPlugin +QOpenWFDPortMode::QOpenWFDPortMode(QOpenWFDPort *port, WFDPortMode portMode) + : mPortMode(portMode) { -public: - QAhiScreenPlugin(); + int width = wfdGetPortModeAttribi(port->device()->handle(),port->handle(),portMode,WFD_PORT_MODE_WIDTH); + int height = wfdGetPortModeAttribi(port->device()->handle(),port->handle(),portMode,WFD_PORT_MODE_HEIGHT); + mSize = QSize(width,height); - QStringList keys() const; - QScreen *create(const QString&, int displayId); -}; - -QAhiScreenPlugin::QAhiScreenPlugin() - : QScreenDriverPlugin() -{ + mRefresh = wfdGetPortModeAttribf(port->device()->handle(),port->handle(),portMode,WFD_PORT_MODE_REFRESH_RATE); + mFlipMirror = wfdGetPortModeAttribi(port->device()->handle(),port->handle(),portMode,WFD_PORT_MODE_FLIP_MIRROR_SUPPORT); + mInterlaced = wfdGetPortModeAttribi(port->device()->handle(), port->handle(),portMode,WFD_PORT_MODE_INTERLACED); } -QStringList QAhiScreenPlugin::keys() const +QDebug operator<<(QDebug s, const QOpenWFDPortMode &portMode) { - return (QStringList() << "ahi"); + s.nospace() << "QOpenWFPortMode( " << portMode.size() << " Refreash: " << portMode.refreshRate() + << " FlipMirror: " << portMode.flipMirror() << " Interlaced: " << portMode.interlaced(); + return s; } - -QScreen* QAhiScreenPlugin::create(const QString& driver, int displayId) -{ - if (driver.toLower() != "ahi") - return 0; - - return new QAhiScreen(displayId); -} - -Q_EXPORT_PLUGIN2(qahiscreen, QAhiScreenPlugin) diff --git a/src/plugins/platforms/openwfd/qopenwfdportmode.h b/src/plugins/platforms/openwfd/qopenwfdportmode.h new file mode 100644 index 0000000000..dd95339404 --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdportmode.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENWFDPORTMODE_H +#define QOPENWFDPORTMODE_H + +#include <WF/wfd.h> + +#include <QtCore/QSize> + +#include <QtCore/QDebug> + +class QOpenWFDPort; + +class QOpenWFDPortMode +{ +public: + QOpenWFDPortMode(QOpenWFDPort *port, WFDPortMode portMode); + + QSize size() const {return mSize;} + qreal refreshRate() const { return mRefresh; } + bool flipMirror() const { return mFlipMirror; } + bool interlaced() const { return mInterlaced; } + + WFDPortMode handle() const { return mPortMode; } +private: + WFDPortMode mPortMode; + + QSize mSize; + qreal mRefresh; + bool mFlipMirror; + bool mInterlaced; +}; + +QDebug operator<<(QDebug, const QOpenWFDPortMode &); +#endif // QOPENWFPORTMODE_H diff --git a/src/plugins/platforms/openwfd/qopenwfdscreen.cpp b/src/plugins/platforms/openwfd/qopenwfdscreen.cpp new file mode 100644 index 0000000000..785bee9c55 --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdscreen.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenwfdscreen.h" + +#include "qopenwfdport.h" +#include "qopenwfdoutputbuffer.h" + +#include <QtGui/QGuiApplication> + +QOpenWFDScreen::QOpenWFDScreen(QOpenWFDPort *port) + : mPort(port) + , mFbo(0) + , mOutputBuffers(BUFFER_NUM) + , mCurrentRenderBufferIndex(0) + , mStagedBackBufferIndex(-1) + , mCommitedBackBufferIndex(-1) + , mBackBufferIndex(-1) +{ + printf ("\n"); + printf ("Information of screen %p:\n", this); + printf (" width..........: %d\n", port->pixelSize().width()); + printf (" height.........: %d\n", port->pixelSize().height()); + printf (" physical width.: %f\n", port->physicalSize().width()); + printf (" physical height: %f\n", port->physicalSize().height()); + printf ("\n"); + + EGLDisplay display = mPort->device()->eglDisplay(); + EGLContext context = mPort->device()->eglContext(); + + if (!eglMakeCurrent(display,EGL_NO_SURFACE,EGL_NO_SURFACE,context)) { + qDebug() << "screen: eglMakeCurrent FAILED"; + } + + glGenFramebuffers(1,&mFbo); + glBindFramebuffer(GL_FRAMEBUFFER,mFbo); + + for (int i = 0; i < mOutputBuffers.size(); i++) { + mOutputBuffers[i] = new QOpenWFDOutputBuffer(mPort->pixelSize(),mPort); + } + + mStagedBackBufferIndex = mOutputBuffers.size()-1; + mOutputBuffers[mStagedBackBufferIndex]->setAvailable(false);; + commitStagedOutputBuffer(); + + mOutputBuffers.at(mCurrentRenderBufferIndex)->bindToCurrentFbo(); + + if (mPort->device()->isDeviceInitializedAndCommited()) { + mPort->device()->commit(WFD_COMMIT_ENTIRE_PORT,mPort->handle()); + } + +} + +QOpenWFDScreen::~QOpenWFDScreen() +{ + for (int i = 0; i < mOutputBuffers.size(); i++) { + delete mOutputBuffers[i]; + } + glDeleteFramebuffers(1, &mFbo); +} + +QRect QOpenWFDScreen::geometry() const +{ + return QRect(QPoint(),mPort->pixelSize()); +} + +int QOpenWFDScreen::depth() const +{ + return 32; +} + +QImage::Format QOpenWFDScreen::format() const +{ + return QImage::Format_RGB32; +} + +QSize QOpenWFDScreen::physicalSize() const +{ + return mPort->physicalSize().toSize(); +} + +QOpenWFDPort * QOpenWFDScreen::port() const +{ + return mPort; +} + +void QOpenWFDScreen::swapBuffers() +{ + glFlush(); + + setStagedBackBuffer(mCurrentRenderBufferIndex); + mCurrentRenderBufferIndex = nextAvailableRenderBuffer(); + + bindFramebuffer(); + mOutputBuffers.at(mCurrentRenderBufferIndex)->bindToCurrentFbo(); +} + +void QOpenWFDScreen::bindFramebuffer() +{ + glBindFramebuffer(GL_FRAMEBUFFER,mFbo); +} + +void QOpenWFDScreen::setStagedBackBuffer(int bufferIndex) +{ + if (mStagedBackBufferIndex >= 0) { + mOutputBuffers[mStagedBackBufferIndex]->setAvailable(true); + } + + mOutputBuffers[bufferIndex]->setAvailable(false);; + mStagedBackBufferIndex = bufferIndex; + + if (mCommitedBackBufferIndex < 0) { + commitStagedOutputBuffer(); + } +} + +void QOpenWFDScreen::commitStagedOutputBuffer() +{ + Q_ASSERT(mStagedBackBufferIndex >= 0); + wfdBindSourceToPipeline(mPort->device()->handle(), + mPort->pipeline(), + mOutputBuffers.at(mStagedBackBufferIndex)->wfdSource(), + WFD_TRANSITION_AT_VSYNC, + 0); + mPort->device()->commit(WFD_COMMIT_PIPELINE,mPort->pipeline()); + mCommitedBackBufferIndex = mStagedBackBufferIndex; + mStagedBackBufferIndex = -1; +} + +int QOpenWFDScreen::nextAvailableRenderBuffer() const +{ + while (true) { + for (int i = 0; i < mOutputBuffers.size(); i++) { + if (mOutputBuffers.at(i)->isAvailable()) { + return i; + } + } + mPort->device()->waitForPipelineBindSourceCompleteEvent(); + } +} + +void QOpenWFDScreen::pipelineBindSourceComplete() +{ + if (mBackBufferIndex >= 0) { + mOutputBuffers[mBackBufferIndex]->setAvailable(true); + } + + mBackBufferIndex = mCommitedBackBufferIndex; + mCommitedBackBufferIndex = -1; + + if (mStagedBackBufferIndex >= 0) { + commitStagedOutputBuffer(); + } +} diff --git a/src/plugins/platforms/openwfd/qopenwfdscreen.h b/src/plugins/platforms/openwfd/qopenwfdscreen.h new file mode 100644 index 0000000000..bb23744ac4 --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdscreen.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENWFDSCREEN_H +#define QOPENWFDSCREEN_H + +#include <QtGui/QPlatformScreen> + + +#include "qopenwfdoutputbuffer.h" + +#include <WF/wfd.h> + +#include <QtCore/QVarLengthArray> +#include <QtCore/QLinkedList> + +#define BUFFER_NUM 4 + +class QOpenWFDPort; +class QOpenWFDScreen : public QPlatformScreen +{ +public: + QOpenWFDScreen(QOpenWFDPort *port); + ~QOpenWFDScreen(); + + QRect geometry() const; + int depth() const; + QImage::Format format() const; + QSize physicalSize() const; + + QOpenWFDPort *port() const; + + void swapBuffers(); + void bindFramebuffer(); + void pipelineBindSourceComplete(); + +private: + void setStagedBackBuffer(int bufferIndex); + void commitStagedOutputBuffer(); + int nextAvailableRenderBuffer() const; + + QOpenWFDPort *mPort; + + GLuint mFbo; + + QVarLengthArray<QOpenWFDOutputBuffer *, BUFFER_NUM> mOutputBuffers; + int mCurrentRenderBufferIndex; + int mStagedBackBufferIndex; + int mCommitedBackBufferIndex; + int mBackBufferIndex; +}; + +#endif diff --git a/src/plugins/graphicssystems/meego/qmeegorasterpixmapdata.cpp b/src/plugins/platforms/openwfd/qopenwfdwindow.cpp index 3d6545e017..15dc4b11c4 100644 --- a/src/plugins/graphicssystems/meego/qmeegorasterpixmapdata.cpp +++ b/src/plugins/platforms/openwfd/qopenwfdwindow.cpp @@ -39,22 +39,23 @@ ** ****************************************************************************/ -#include "qmeegorasterpixmapdata.h" +#include "qopenwfdwindow.h" -/* Public */ +#include "qopenwfdscreen.h" +#include "QtGui/QWindowSystemInterface" -QMeeGoRasterPixmapData::QMeeGoRasterPixmapData() : QRasterPixmapData(QPixmapData::PixmapType) +QOpenWFDWindow::QOpenWFDWindow(QWindow *window) + : QPlatformWindow(window) { -} -QMeeGoRasterPixmapData::QMeeGoRasterPixmapData(QPixmapData::PixelType t) : QRasterPixmapData(t) -{ + QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(window); + mPort = static_cast<QOpenWFDScreen *>(platformScreen)->port(); + + QWindowSystemInterface::handleGeometryChange(window,QRect(QPoint(0,0),mPort->screen()->geometry().size())); } -void QMeeGoRasterPixmapData::copy(const QPixmapData *data, const QRect &rect) +QOpenWFDPort *QOpenWFDWindow::port() const { - if (data->classId() == QPixmapData::OpenGLClass) - fromImage(data->toImage(rect).copy(), Qt::NoOpaqueDetection); - else - QRasterPixmapData::copy(data, rect); + return mPort; } + diff --git a/src/plugins/platforms/openwfd/qopenwfdwindow.h b/src/plugins/platforms/openwfd/qopenwfdwindow.h new file mode 100644 index 0000000000..3c97b014b1 --- /dev/null +++ b/src/plugins/platforms/openwfd/qopenwfdwindow.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENWFDWINDOW_H +#define QOPENWFDWINDOW_H + +#include <QtGui/QPlatformWindow> +#include <QtCore/QVarLengthArray> + +#include "qopenwfdport.h" + +class QOpenWFDWindow : public QPlatformWindow +{ +public: + QOpenWFDWindow(QWindow *window); + + QOpenWFDPort *port() const; + +private: + QOpenWFDPort *mPort; +}; + +#endif // QOPENWFWINDOW_H diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 492569796f..ac001b665b 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -9,3 +9,9 @@ contains(QT_CONFIG, wayland) { contains(QT_CONFIG, xcb) { SUBDIRS += xcb } + +mac { + SUBDIRS += cocoa +} + +win32: SUBDIRS += windows diff --git a/src/plugins/platforms/qvfb/qvfb.pro b/src/plugins/platforms/qvfb/qvfb.pro index 5db8533264..a95b13efc7 100644 --- a/src/plugins/platforms/qvfb/qvfb.pro +++ b/src/plugins/platforms/qvfb/qvfb.pro @@ -3,6 +3,7 @@ load(qt_plugin) DESTDIR = $$QT.gui.plugins/platforms +QT += core-private gui-private platformsupport-private SOURCES = main.cpp qvfbintegration.cpp qvfbwindowsurface.cpp HEADERS = qvfbintegration.h qvfbwindowsurface.h diff --git a/src/plugins/platforms/qvfb/qvfbintegration.cpp b/src/plugins/platforms/qvfb/qvfbintegration.cpp index 6b54420402..d4d8183936 100644 --- a/src/plugins/platforms/qvfb/qvfbintegration.cpp +++ b/src/plugins/platforms/qvfb/qvfbintegration.cpp @@ -63,6 +63,7 @@ #include <QWindowSystemInterface> #include "qgenericunixfontdatabase.h" +#include "qgenericunixeventdispatcher.h" QT_BEGIN_NAMESPACE @@ -422,9 +423,9 @@ QVFbIntegration::QVFbIntegration(const QStringList ¶mList) mScreens.append(mPrimaryScreen); } -QPixmapData *QVFbIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformPixmap *QVFbIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const { - return new QRasterPixmapData(type); + return new QRasterPlatformPixmap(type); } QWindowSurface *QVFbIntegration::createWindowSurface(QWidget *widget, WId) const @@ -438,6 +439,11 @@ QPlatformWindow *QVFbIntegration::createPlatformWindow(QWidget *widget, WId) con return new QVFbWindow(mPrimaryScreen, widget); } +QAbstractEventDispatcher *QVFbIntegration::createEventDispatcher() const +{ + return createUnixEventDispatcher(); +} + QPlatformFontDatabase *QVFbIntegration::fontDatabase() const { return mFontDb; diff --git a/src/plugins/platforms/qvfb/qvfbintegration.h b/src/plugins/platforms/qvfb/qvfbintegration.h index ae3ba7bcc3..1c736c24e0 100644 --- a/src/plugins/platforms/qvfb/qvfbintegration.h +++ b/src/plugins/platforms/qvfb/qvfbintegration.h @@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE class QVFbScreenPrivate; +class QAbstractEventDispatcher; class QVFbScreen : public QPlatformScreen { @@ -78,9 +79,10 @@ class QVFbIntegration : public QPlatformIntegration public: QVFbIntegration(const QStringList ¶mList); - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; + QAbstractEventDispatcher *createEventDispatcher() const; QList<QPlatformScreen *> screens() const { return mScreens; } diff --git a/src/plugins/platforms/uikit/quikitintegration.h b/src/plugins/platforms/uikit/quikitintegration.h index 92247fdff3..b8a15b3807 100644 --- a/src/plugins/platforms/uikit/quikitintegration.h +++ b/src/plugins/platforms/uikit/quikitintegration.h @@ -52,7 +52,7 @@ public: QUIKitIntegration(); ~QUIKitIntegration(); - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId = 0) const; QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; diff --git a/src/plugins/platforms/uikit/quikitintegration.mm b/src/plugins/platforms/uikit/quikitintegration.mm index 737fa40d05..37ba2b9a02 100644 --- a/src/plugins/platforms/uikit/quikitintegration.mm +++ b/src/plugins/platforms/uikit/quikitintegration.mm @@ -64,9 +64,9 @@ QUIKitIntegration::~QUIKitIntegration() { } -QPixmapData *QUIKitIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformPixmap *QUIKitIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const { - return new QRasterPixmapData(type); + return new QRasterPlatformPixmap(type); } QPlatformWindow *QUIKitIntegration::createPlatformWindow(QWidget *widget, WId winId) const diff --git a/src/plugins/platforms/uikit/quikitwindow.h b/src/plugins/platforms/uikit/quikitwindow.h index c482dae3d5..67f0242a48 100644 --- a/src/plugins/platforms/uikit/quikitwindow.h +++ b/src/plugins/platforms/uikit/quikitwindow.h @@ -117,7 +117,7 @@ public: UIWindow *ensureNativeWindow(); - QPlatformGLContext *glContext() const; + QPlatformOpenGLContext *glContext() const; private: QUIKitScreen *mScreen; diff --git a/src/plugins/platforms/uikit/quikitwindow.mm b/src/plugins/platforms/uikit/quikitwindow.mm index 29ca88b75a..cc17dbcbfb 100644 --- a/src/plugins/platforms/uikit/quikitwindow.mm +++ b/src/plugins/platforms/uikit/quikitwindow.mm @@ -48,12 +48,12 @@ #include <QtDebug> #include <QtGui/QApplication> #include <QtGui/QKeyEvent> -#include <QtGui/QPlatformGLContext> +#include <QtGui/QPlatformOpenGLContext> #include <QtGui/QWindowSystemInterface> #include <QtDebug> -class EAGLPlatformContext : public QPlatformGLContext +class EAGLPlatformContext : public QPlatformOpenGLContext { public: EAGLPlatformContext(EAGLView *view) @@ -91,13 +91,13 @@ public: void makeCurrent() { - QPlatformGLContext::makeCurrent(); + QPlatformOpenGLContext::makeCurrent(); [mView makeCurrent]; } void doneCurrent() { - QPlatformGLContext::doneCurrent(); + QPlatformOpenGLContext::doneCurrent(); } void swapBuffers() @@ -381,7 +381,7 @@ UIWindow *QUIKitWindow::ensureNativeWindow() return mWindow; } -QPlatformGLContext *QUIKitWindow::glContext() const +QPlatformOpenGLContext *QUIKitWindow::glContext() const { if (!mContext) { mContext = new EAGLPlatformContext(mView); diff --git a/src/plugins/platforms/uikit/uikit.pro b/src/plugins/platforms/uikit/uikit.pro index 45a48dc92a..5e3a0e6b7c 100644 --- a/src/plugins/platforms/uikit/uikit.pro +++ b/src/plugins/platforms/uikit/uikit.pro @@ -1,5 +1,5 @@ TARGET = quikit -load(qt_plugin) +load(qpa/plugin) QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms QT += opengl @@ -22,6 +22,6 @@ HEADERS = quikitsoftwareinputhandler.h #add libz for freetype. LIBS += -lz -#include(../fontdatabases/basicunix/basicunix.pri) +#load(qpa/fontdatabases/basicunix) target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/vnc/qvncintegration.cpp b/src/plugins/platforms/vnc/qvncintegration.cpp index 1e8c6c1bc5..7506bff307 100644 --- a/src/plugins/platforms/vnc/qvncintegration.cpp +++ b/src/plugins/platforms/vnc/qvncintegration.cpp @@ -161,9 +161,9 @@ bool QVNCIntegration::hasCapability(QPlatformIntegration::Capability cap) const } -QPixmapData *QVNCIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformPixmap *QVNCIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const { - return new QRasterPixmapData(type); + return new QRasterPlatformPixmap(type); } QWindowSurface *QVNCIntegration::createWindowSurface(QWidget *widget, WId) const @@ -173,6 +173,10 @@ QWindowSurface *QVNCIntegration::createWindowSurface(QWidget *widget, WId) const return surface; } +QAbstractEventDispatcher *QVFbIntegration::createEventDispatcher() const +{ + return createUnixEventDispatcher(); +} QPlatformWindow *QVNCIntegration::createPlatformWindow(QWidget *widget, WId /*winId*/) const { diff --git a/src/plugins/platforms/vnc/qvncintegration.h b/src/plugins/platforms/vnc/qvncintegration.h index 3e13bc3b8d..9787a59f0f 100644 --- a/src/plugins/platforms/vnc/qvncintegration.h +++ b/src/plugins/platforms/vnc/qvncintegration.h @@ -74,7 +74,7 @@ private: }; class QVNCIntegrationPrivate; - +class QAbstractEventDispatcher; class QVNCIntegration : public QPlatformIntegration { @@ -82,9 +82,10 @@ public: QVNCIntegration(const QStringList& paramList); bool hasCapability(QPlatformIntegration::Capability cap) const; - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; + QAbstractEventDispatcher createEventDispatcher() const; QPixmap grabWindow(WId window, int x, int y, int width, int height) const; diff --git a/src/plugins/platforms/vnc/qvncserver.cpp b/src/plugins/platforms/vnc/qvncserver.cpp index 8b25e054d1..37412b6bd1 100644 --- a/src/plugins/platforms/vnc/qvncserver.cpp +++ b/src/plugins/platforms/vnc/qvncserver.cpp @@ -43,7 +43,7 @@ #include <QtCore/qtimer.h> #include <QtCore/qregexp.h> -#include <QtGui/qwidget.h> +#include <QtWidgets/qwidget.h> #include <QtGui/qpolygon.h> #include <QtGui/qpainter.h> diff --git a/src/plugins/platforms/vnc/vnc.pro b/src/plugins/platforms/vnc/vnc.pro index 85bffb0637..321cee4790 100644 --- a/src/plugins/platforms/vnc/vnc.pro +++ b/src/plugins/platforms/vnc/vnc.pro @@ -1,7 +1,7 @@ TARGET = qvncgraphicssystem load(qt_plugin) -QT += network +QT += network core-private gui-private platformsupport-private DESTDIR = $$QT.gui.plugins/platforms diff --git a/src/plugins/platforms/wayland/gl_integration/gl_integration.pri b/src/plugins/platforms/wayland/gl_integration/gl_integration.pri index d9b5fa9bff..20c3aa0bd9 100644 --- a/src/plugins/platforms/wayland/gl_integration/gl_integration.pri +++ b/src/plugins/platforms/wayland/gl_integration/gl_integration.pri @@ -3,12 +3,10 @@ contains(QT_CONFIG, opengl) { QT += opengl HEADERS += \ - $$PWD/qwaylandglintegration.h \ - $$PWD/qwaylandglwindowsurface.h + $$PWD/qwaylandglintegration.h SOURCES += \ - $$PWD/qwaylandglintegration.cpp \ - $$PWD/qwaylandglwindowsurface.cpp + $$PWD/qwaylandglintegration.cpp QT_WAYLAND_GL_CONFIG = $$(QT_WAYLAND_GL_CONFIG) contains(QT_CONFIG, opengles2) { @@ -22,6 +20,9 @@ SOURCES += \ QT_WAYLAND_GL_INTEGRATION = xcomposite_egl CONFIG += xcomposite_egl } + } else:mac { + QT_WAYLAND_GL_INTEGRATION = readback_cgl + CONFIG += readback_cgl } else { isEqual(QT_WAYLAND_GL_CONFIG, readback) { QT_WAYLAND_GL_INTEGRATION = readback_glx @@ -48,6 +49,10 @@ readback_glx { include ($$PWD/readback_glx/readback_glx.pri) } +readback_cgl { + include ($$PWD/readback_cgl/readback_cgl.pri) +} + xcomposite_glx { include ($$PWD/xcomposite_glx/xcomposite_glx.pri) } diff --git a/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h b/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h index 4b50b4bd68..4f688e41d8 100644 --- a/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h @@ -44,7 +44,10 @@ class QWaylandWindow; class QWaylandDisplay; -class QWidget; +class QWindow; + +class QPlatformOpenGLContext; +class QSurfaceFormat; class QWaylandGLIntegration { @@ -54,7 +57,8 @@ public: virtual void initialize() = 0; - virtual QWaylandWindow *createEglWindow(QWidget *widget) = 0; + virtual QWaylandWindow *createEglWindow(QWindow *window) = 0; + virtual QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const = 0; static QWaylandGLIntegration *createGLIntegration(QWaylandDisplay *waylandDisplay); }; diff --git a/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp b/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp deleted file mode 100644 index fef07e6bf7..0000000000 --- a/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************** -** -** 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 plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwaylandglwindowsurface.h" - -#include "qwaylanddisplay.h" -#include "qwaylandwindow.h" -#include "qwaylandscreen.h" - -#include <QtOpenGL/QGLFramebufferObject> -#include <QtOpenGL/QGLContext> - -#include <QtOpenGL/private/qglengineshadermanager_p.h> - -QT_BEGIN_NAMESPACE - -static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &br) -{ -#if !defined(QT_OPENGL_ES_2) - QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); -#endif - const GLenum target = GL_TEXTURE_2D; - QRectF src = br.isEmpty() - ? QRectF(QPointF(), texSize) - : QRectF(QPointF(br.x(), texSize.height() - br.bottom()), br.size()); - - if (target == GL_TEXTURE_2D) { - qreal width = texSize.width(); - qreal height = texSize.height(); - - src.setLeft(src.left() / width); - src.setRight(src.right() / width); - src.setTop(src.top() / height); - src.setBottom(src.bottom() / height); - } - - const GLfloat tx1 = src.left(); - const GLfloat tx2 = src.right(); - const GLfloat ty1 = src.top(); - const GLfloat ty2 = src.bottom(); - - GLfloat texCoordArray[4*2] = { - tx1, ty2, tx2, ty2, tx2, ty1, tx1, ty1 - }; - - GLfloat vertexArray[4*2]; - vertexArray[0] = rect.left(); vertexArray[1] = rect.top(); - vertexArray[2] = rect.right(); vertexArray[3] = rect.top(); - vertexArray[4] = rect.right(); vertexArray[5] = rect.bottom(); - vertexArray[6] = rect.left(); vertexArray[7] = rect.bottom(); - - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray); - glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, texCoordArray); - - glBindTexture(target, tex_id); - - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - - glBindTexture(target, 0); -} - -static void blitTexture(QGLContext *ctx, GLuint texture, const QSize &viewport, const QSize &texSize, const QRect &targetRect, const QRect &sourceRect) -{ - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glViewport(0, 0, viewport.width(), viewport.height()); - - QGLShaderProgram *blitProgram = - QGLEngineSharedShaders::shadersForContext(ctx)->blitProgram(); - blitProgram->bind(); - blitProgram->setUniformValue("imageTexture", 0 /*QT_IMAGE_TEXTURE_UNIT*/); - - // The shader manager's blit program does not multiply the - // vertices by the pmv matrix, so we need to do the effect - // of the orthographic projection here ourselves. - QRectF r; - qreal w = viewport.width(); - qreal h = viewport.height(); - r.setLeft((targetRect.left() / w) * 2.0f - 1.0f); - if (targetRect.right() == (viewport.width() - 1)) - r.setRight(1.0f); - else - r.setRight((targetRect.right() / w) * 2.0f - 1.0f); - r.setBottom((targetRect.top() / h) * 2.0f - 1.0f); - if (targetRect.bottom() == (viewport.height() - 1)) - r.setTop(1.0f); - else - r.setTop((targetRect.bottom() / w) * 2.0f - 1.0f); - - drawTexture(r, texture, texSize, sourceRect); -} - -QWaylandGLWindowSurface::QWaylandGLWindowSurface(QWidget *window) - : QWindowSurface(window) - , mDisplay(QWaylandScreen::waylandScreenFromWidget(window)->display()) - , mPaintDevice(0) -{ - -} - -QWaylandGLWindowSurface::~QWaylandGLWindowSurface() -{ - delete mPaintDevice; -} - -QPaintDevice *QWaylandGLWindowSurface::paintDevice() -{ - return mPaintDevice; -} - -void QWaylandGLWindowSurface::beginPaint(const QRegion &) -{ - window()->platformWindow()->glContext()->makeCurrent(); - glClearColor(0,0,0,0xff); - glClear(GL_COLOR_BUFFER_BIT); -} - -void QWaylandGLWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) -{ - Q_UNUSED(offset); - Q_UNUSED(region); - QWaylandWindow *ww = (QWaylandWindow *) widget->platformWindow(); - - if (mPaintDevice->isBound()) - mPaintDevice->release(); - - QRect rect(0,0,size().width(),size().height()); - QGLContext *ctx = QGLContext::fromPlatformGLContext(ww->glContext()); - blitTexture(ctx,mPaintDevice->texture(),size(),mPaintDevice->size(),rect,rect); - ww->glContext()->swapBuffers(); -} - -void QWaylandGLWindowSurface::resize(const QSize &size) -{ - QWindowSurface::resize(size); - window()->platformWindow()->glContext()->makeCurrent(); - delete mPaintDevice; - mPaintDevice = new QGLFramebufferObject(size,QGLFramebufferObject::CombinedDepthStencil); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.cpp new file mode 100644 index 0000000000..5f7663ef55 --- /dev/null +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandreadbackcglcontext.h" + +#include "qwaylandshmbackingstore.h" +#include "qwaylandreadbackcglwindow.h" + +#include <QtGui/QOpenGLContext> +#include <QtCore/QDebug> + +#include <OpenGL/OpenGL.h> +#include <OpenGL/glext.h> +#include <OpenGL/glu.h> + +#include <QtPlatformSupport/private/cglconvenience_p.h> + +QWaylandReadbackCGLContext::QWaylandReadbackCGLContext(QPlatformOpenGLContext *share) + : QPlatformOpenGLContext() +{ + Q_UNUSED(share); + m_glContext = qcgl_createGlContext(); +} + +QSurfaceFormat QWaylandReadbackCGLContext::format() const +{ + return qcgl_surfaceFormat(); +} + +bool QWaylandReadbackCGLContext::makeCurrent(QPlatformSurface *surface) +{ + QWaylandReadbackCGLWindow *window = static_cast<QWaylandReadbackCGLWindow *>(surface); + CGLSetPBuffer(m_glContext, window->pixelBuffer(), 0, 0, 0); + CGLSetCurrentContext(m_glContext); + return true; +} + +void QWaylandReadbackCGLContext::doneCurrent() +{ + CGLSetCurrentContext(0); +} + +void QWaylandReadbackCGLContext::swapBuffers(QPlatformSurface *surface) +{ + Q_UNUSED(surface); + + if (QOpenGLContext::currentContext()->handle() != this) { + makeCurrent(surface); + } + CGLFlushDrawable(m_glContext); + + QWaylandReadbackCGLWindow *window = static_cast<QWaylandReadbackCGLWindow *>(surface); + QSize size = window->geometry().size(); + + uchar *dstBits = const_cast<uchar *>(window->buffer()); + glReadPixels(0,0, size.width(), size.height(), GL_BGRA,GL_UNSIGNED_BYTE, dstBits); + + window->damage(QRect(QPoint(0,0),size)); + + // ### Should sync here but this call deadlocks with the server. + //window->waitForFrameSync(); +} + +void (*QWaylandReadbackCGLContext::getProcAddress(const QByteArray &procName)) () +{ + return qcgl_getProcAddress(procName); +} + diff --git a/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.h b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.h new file mode 100644 index 0000000000..eb065c3f69 --- /dev/null +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDREADBACKCGLCONTEXT_H +#define QWAYLANDREADBACKCGLCONTEXT_H + +#include <QPlatformOpenGLContext> + +#include "qwaylandreadbackcglintegration.h" + +#include <OpenGL/OpenGL.h> + +class QWaylandReadbackCGLWindow; +class QWaylandShmBuffer; + +class QWaylandReadbackCGLContext : public QPlatformOpenGLContext +{ +public: + QWaylandReadbackCGLContext(QPlatformOpenGLContext *share); + + QSurfaceFormat format() const; + + bool makeCurrent(QPlatformSurface *surface); + void doneCurrent(); + void swapBuffers(QPlatformSurface *surface); + void (*getProcAddress(const QByteArray &procName)) (); + + void geometryChanged(); + +private: + CGLContextObj m_glContext; +}; + +#endif // QWAYLANDREADBACKCGLCONTEXT_H diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.cpp b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.cpp index e5ac994a05..2878f9e292 100644 --- a/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.cpp @@ -39,46 +39,44 @@ ** ****************************************************************************/ -#include "eglnullwswindowsurface.h" -#include "eglnullwsscreenplugin.h" +#include "qwaylandreadbackcglintegration.h" +#include "qwaylandreadbackcglcontext.h" +#include "qwaylandreadbackcglwindow.h" -#include <QGLWidget> +#include <QtCore/QDebug> -static const QWSWindowSurface::SurfaceFlags Flags - = QWSWindowSurface::RegionReserved | QWSWindowSurface::RegionReserved; - -EGLNullWSWindowSurface::EGLNullWSWindowSurface(QWidget *w) - : - QWSGLWindowSurface(w), - widget(w) +QWaylandGLIntegration * QWaylandGLIntegration::createGLIntegration(QWaylandDisplay *waylandDisplay) { - setSurfaceFlags(Flags); + return new QWaylandReadbackCGLIntegration(waylandDisplay); } -EGLNullWSWindowSurface::EGLNullWSWindowSurface() - : widget(0) +QWaylandReadbackCGLIntegration::QWaylandReadbackCGLIntegration(QWaylandDisplay * waylandDispaly) + : QWaylandGLIntegration() + , mWaylandDisplay(waylandDispaly) { - setSurfaceFlags(Flags); + qDebug() << "Using Readback-CGL"; } -EGLNullWSWindowSurface::~EGLNullWSWindowSurface() {} +QWaylandReadbackCGLIntegration::~QWaylandReadbackCGLIntegration() +{ + +} -QString EGLNullWSWindowSurface::key() const +void QWaylandReadbackCGLIntegration::initialize() { - return QLatin1String(PluginName); } -QPaintDevice *EGLNullWSWindowSurface::paintDevice() +QWaylandWindow * QWaylandReadbackCGLIntegration::createEglWindow(QWindow *window) { - return widget; + return new QWaylandReadbackCGLWindow(window,this); } -bool EGLNullWSWindowSurface::isValid() const +QPlatformOpenGLContext *QWaylandReadbackCGLIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const { - return qobject_cast<QGLWidget *>(window()); + return new QWaylandReadbackCGLContext(share); } -QImage EGLNullWSWindowSurface::image() const +QWaylandDisplay * QWaylandReadbackCGLIntegration::waylandDisplay() const { - return QImage(); + return mWaylandDisplay; } diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.h index 6f8f8dce66..34c8d00a7c 100644 --- a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.h @@ -39,35 +39,33 @@ ** ****************************************************************************/ -#ifndef QGRAPHICSSYSTEM_VG_P_H -#define QGRAPHICSSYSTEM_VG_P_H +#ifndef QWAYLANDREADBACKGLXINTEGRATION_H +#define QWAYLANDREADBACKGLXINTEGRATION_H -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// +#include "gl_integration/qwaylandglintegration.h" -#include <QtGui/private/qgraphicssystem_p.h> +#include <QtCore/QTextStream> +#include <QtCore/QDataStream> +#include <QtCore/QMetaType> +#include <QtCore/QVariant> +#include <QtGui/QWindow> -QT_BEGIN_NAMESPACE +#include <X11/Xlib.h> -class QVGGraphicsSystem : public QGraphicsSystem +class QWaylandReadbackCGLIntegration : public QWaylandGLIntegration { public: - QVGGraphicsSystem(); + QWaylandReadbackCGLIntegration(QWaylandDisplay * waylandDispaly); + ~QWaylandReadbackCGLIntegration(); - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QWindowSurface *createWindowSurface(QWidget *widget) const; + void initialize(); - void releaseCachedResources(); -}; + QWaylandWindow *createEglWindow(QWindow *window); + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; + QWaylandDisplay *waylandDisplay() const; -QT_END_NAMESPACE +private: + QWaylandDisplay *mWaylandDisplay; +}; -#endif +#endif // QWAYLANDREADBACKGLXINTEGRATION_H diff --git a/src/plugins/graphicssystems/opengl/main.cpp b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglwindow.cpp index ee0fa802dd..9e7f8520c9 100644 --- a/src/plugins/graphicssystems/opengl/main.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglwindow.cpp @@ -39,57 +39,68 @@ ** ****************************************************************************/ -#include <private/qgraphicssystemplugin_p.h> -#include <private/qgraphicssystem_gl_p.h> -#include <qgl.h> +#include "qwaylandreadbackcglwindow.h" +#include "qwaylandshmbackingstore.h" -QT_BEGIN_NAMESPACE +#include <OpenGL/OpenGL.h> +#include <OpenGL/glext.h> -class QGLGraphicsSystemPlugin : public QGraphicsSystemPlugin +QWaylandReadbackCGLWindow::QWaylandReadbackCGLWindow(QWindow *window, QWaylandReadbackCGLIntegration *cglIntegration) + : QWaylandShmWindow(window) + , m_CglIntegration(cglIntegration) + , mContext(0) + , m_buffer(0) + , m_pixelBuffer(0) { -public: - QStringList keys() const; - QGraphicsSystem *create(const QString&); -}; +} -QStringList QGLGraphicsSystemPlugin::keys() const +QWaylandWindow::WindowType QWaylandReadbackCGLWindow::windowType() const { - QStringList list; - list << QLatin1String("OpenGL") << QLatin1String("OpenGL1"); -#if !defined(QT_OPENGL_ES_1) - list << QLatin1String("OpenGL2"); -#endif -#if defined(Q_WS_X11) && !defined(QT_NO_EGL) - list << QLatin1String("X11GL"); -#endif - return list; + //yeah. this type needs a new name + return QWaylandWindow::Egl; } -QGraphicsSystem* QGLGraphicsSystemPlugin::create(const QString& system) + +void QWaylandReadbackCGLWindow::setGeometry(const QRect &rect) { - if (system.toLower() == QLatin1String("opengl1")) { - QGL::setPreferredPaintEngine(QPaintEngine::OpenGL); - return new QGLGraphicsSystem(false); - } + QWaylandShmWindow::setGeometry(rect); + + if (m_buffer) { + delete m_buffer; + m_buffer = 0; -#if !defined(QT_OPENGL_ES_1) - if (system.toLower() == QLatin1String("opengl2")) { - QGL::setPreferredPaintEngine(QPaintEngine::OpenGL2); - return new QGLGraphicsSystem(false); + CGLDestroyPBuffer(m_pixelBuffer); + m_pixelBuffer = 0; } -#endif +} -#if defined(Q_WS_X11) && !defined(QT_NO_EGL) - if (system.toLower() == QLatin1String("x11gl")) - return new QGLGraphicsSystem(true); -#endif +CGLPBufferObj QWaylandReadbackCGLWindow::pixelBuffer() +{ + if (!m_pixelBuffer) + createSurface(); - if (system.toLower() == QLatin1String("opengl")) - return new QGLGraphicsSystem(false); + return m_pixelBuffer; +} - return 0; +uchar *QWaylandReadbackCGLWindow::buffer() +{ + return m_buffer->image()->bits(); } -Q_EXPORT_PLUGIN2(opengl, QGLGraphicsSystemPlugin) +void QWaylandReadbackCGLWindow::createSurface() +{ + QSize size(geometry().size()); + if (size.isEmpty()) { + //QGLWidget wants a context for a window without geometry + size = QSize(1,1); + } + + waitForFrameSync(); + + CGLCreatePBuffer(size.width(), size.height(), GL_TEXTURE_RECTANGLE_ARB, GL_BGRA, 0, &m_pixelBuffer); + + delete m_buffer; + m_buffer = new QWaylandShmBuffer(m_CglIntegration->waylandDisplay(),size,QImage::Format_ARGB32); + attach(m_buffer); +} -QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.h b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglwindow.h index a9de7f5239..0598cf9037 100644 --- a/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglwindow.h @@ -39,38 +39,32 @@ ** ****************************************************************************/ -#ifndef SHIVAVGWINDOWSURFACE_H -#define SHIVAVGWINDOWSURFACE_H +#ifndef QWAYLANDREADBACKGLXWINDOW_H +#define QWAYLANDREADBACKGLXWINDOW_H -#include <QtGui/private/qwindowsurface_p.h> +#include "qwaylandshmwindow.h" +#include "qwaylandreadbackcglintegration.h" +#include "qwaylandreadbackcglcontext.h" -QT_BEGIN_NAMESPACE +#include <OpenGL/OpenGL.h> -class ShivaVGWindowSurfacePrivate; - -class ShivaVGWindowSurface : public QWindowSurface, public QPaintDevice +class QWaylandReadbackCGLWindow : public QWaylandShmWindow { public: - ShivaVGWindowSurface(QWidget *window); - virtual ~ShivaVGWindowSurface(); + QWaylandReadbackCGLWindow(QWindow *window, QWaylandReadbackCGLIntegration *cglIntegration); + WindowType windowType() const; - QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); void setGeometry(const QRect &rect); - bool scroll(const QRegion &area, int dx, int dy); - - void beginPaint(const QRegion ®ion); - void endPaint(const QRegion ®ion); - - QPaintEngine *paintEngine() const; + CGLPBufferObj pixelBuffer(); + uchar *buffer(); +private: + void createSurface(); -protected: - int metric(PaintDeviceMetric metric) const; + QWaylandReadbackCGLIntegration *m_CglIntegration; + QWaylandReadbackCGLContext *mContext; -private: - ShivaVGWindowSurfacePrivate *d_ptr; + QWaylandShmBuffer *m_buffer; + CGLPBufferObj m_pixelBuffer; }; -QT_END_NAMESPACE - -#endif +#endif // QWAYLANDREADBACKGLXWINDOW_H diff --git a/src/plugins/platforms/wayland/gl_integration/readback_cgl/readback_cgl.pri b/src/plugins/platforms/wayland/gl_integration/readback_cgl/readback_cgl.pri new file mode 100644 index 0000000000..91cb90a30c --- /dev/null +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/readback_cgl.pri @@ -0,0 +1,10 @@ +HEADERS += \ + $$PWD/qwaylandreadbackcglintegration.h \ + $$PWD/qwaylandreadbackcglwindow.h \ + $$PWD/qwaylandreadbackcglcontext.h + +SOURCES += \ + $$PWD/qwaylandreadbackcglintegration.cpp \ + $$PWD/qwaylandreadbackcglwindow.cpp \ + $$PWD/qwaylandreadbackcglcontext.cpp + diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp index f02a10a05b..c03e8a9444 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp @@ -41,14 +41,16 @@ #include "qwaylandreadbackeglcontext.h" -#include "../../../eglconvenience/qeglconvenience.h" +#include <QPlatformSupport/eglconvenience/qeglconvenience_p.h> + +#include <QtCore/QDebug> +#include <QtGui/QWindowContext> #include <QtOpenGL/QGLContext> #include <QtOpenGL/private/qglextensions_p.h> #include "qwaylandshmsurface.h" -#include <QtCore/QDebug> static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) { @@ -77,7 +79,7 @@ QWaylandReadbackEglContext::QWaylandReadbackEglContext(QWaylandReadbackEglIntegr , mWindow(window) , mBuffer(0) , mPixmap(0) - , mConfig(q_configFromQPlatformWindowFormat(eglIntegration->eglDisplay(),window->widget()->platformWindowFormat(),true,EGL_PIXMAP_BIT)) + , mConfig(q_configFromQWindowFormat(eglIntegration->eglDisplay(),window->window()->requestedWindowFormat(),true,EGL_PIXMAP_BIT)) , mPixmapSurface(EGL_NO_SURFACE) { QVector<EGLint> eglContextAttrs; @@ -97,8 +99,6 @@ QWaylandReadbackEglContext::~QWaylandReadbackEglContext() void QWaylandReadbackEglContext::makeCurrent() { - QPlatformGLContext::makeCurrent(); - mWindow->waitForFrameSync(); eglMakeCurrent(mEglIntegration->eglDisplay(),mPixmapSurface,mPixmapSurface,mContext); @@ -106,7 +106,7 @@ void QWaylandReadbackEglContext::makeCurrent() void QWaylandReadbackEglContext::doneCurrent() { - QPlatformGLContext::doneCurrent(); + QPlatformOpenGLContext::doneCurrent(); eglMakeCurrent(mEglIntegration->eglDisplay(),EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT); } @@ -114,7 +114,7 @@ void QWaylandReadbackEglContext::swapBuffers() { eglSwapBuffers(mEglIntegration->eglDisplay(),mPixmapSurface); - if (QPlatformGLContext::currentContext() != this) { + if (QWindowContext::currentContext()->handle() != this) { makeCurrent(); } @@ -143,9 +143,9 @@ void * QWaylandReadbackEglContext::getProcAddress(const QString &procName) return (void *) eglGetProcAddress(procName.toLatin1().data()); } -QPlatformWindowFormat QWaylandReadbackEglContext::platformWindowFormat() const +QWindowFormat QWaylandReadbackEglContext::windowFormat() const { - return qt_qPlatformWindowFormatFromConfig(mEglIntegration->eglDisplay(),mConfig); + return q_windowFormatFromConfig(mEglIntegration->eglDisplay(),mConfig); } void QWaylandReadbackEglContext::geometryChanged() diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h index f9ab3783dd..75755fbd1a 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h @@ -42,15 +42,14 @@ #ifndef QWAYLANDREADBACKEGLGLCONTEXT_H #define QWAYLANDREADBACKEGLGLCONTEXT_H -#include <QPlatformGLContext> -#include <QtGui/QWidget> +#include <QPlatformOpenGLContext> #include "qwaylandreadbackeglintegration.h" #include "qwaylandreadbackeglwindow.h" class QWaylandShmBuffer; -class QWaylandReadbackEglContext : public QPlatformGLContext +class QWaylandReadbackEglContext : public QPlatformOpenGLContext { public: QWaylandReadbackEglContext(QWaylandReadbackEglIntegration *eglIntegration, QWaylandReadbackEglWindow *window); @@ -61,7 +60,7 @@ public: void swapBuffers(); void* getProcAddress(const QString& procName); - virtual QPlatformWindowFormat platformWindowFormat() const; + virtual QWindowFormat windowFormat() const; void geometryChanged(); diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp index 6bbac603cf..39fa3d589c 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp @@ -81,9 +81,14 @@ void QWaylandReadbackEglIntegration::initialize() } } -QWaylandWindow * QWaylandReadbackEglIntegration::createEglWindow(QWidget *widget) +QWaylandWindow * QWaylandReadbackEglIntegration::createEglWindow(QWindow *window) { - return new QWaylandReadbackEglWindow(widget,this); + return new QWaylandReadbackEglWindow(window, this); +} + +QPlatformOpenGLContext *QWaylandReadbackEglWindow::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const +{ + return new QWaylandReadbackEglContext(glFormat, share, this); } EGLDisplay QWaylandReadbackEglIntegration::eglDisplay() diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h index ae1e8e5095..0d6aa55e4e 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h @@ -48,7 +48,8 @@ #include <QtCore/QDataStream> #include <QtCore/QMetaType> #include <QtCore/QVariant> -#include <QtGui/QWidget> +#include <QtCore/QEvent> +#include <QtGui/QCursor> #include <X11/Xlib.h> @@ -61,7 +62,8 @@ public: ~QWaylandReadbackEglIntegration(); void initialize(); - QWaylandWindow *createEglWindow(QWidget *widget); + QWaylandWindow *createEglWindow(QWindow *window); + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; QWaylandDisplay *waylandDisplay() const; Display *xDisplay() const; diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp index 868e32e030..f4bc6379d6 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp @@ -43,7 +43,7 @@ #include "qwaylandreadbackeglcontext.h" -QWaylandReadbackEglWindow::QWaylandReadbackEglWindow(QWidget *window, QWaylandReadbackEglIntegration *eglIntegration) +QWaylandReadbackEglWindow::QWaylandReadbackEglWindow(QWindow *window, QWaylandReadbackEglIntegration *eglIntegration) : QWaylandShmWindow(window) , mEglIntegration(eglIntegration) , mContext(0) @@ -57,7 +57,7 @@ QWaylandWindow::WindowType QWaylandReadbackEglWindow::windowType() const return QWaylandWindow::Egl; } -QPlatformGLContext *QWaylandReadbackEglWindow::glContext() const +QPlatformOpenGLContext *QWaylandReadbackEglWindow::glContext() const { if (!mContext) { QWaylandReadbackEglWindow *that = const_cast<QWaylandReadbackEglWindow *>(this); diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h index 1433483923..0852a8ee66 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h @@ -50,11 +50,11 @@ class QWaylandReadbackEglContext; class QWaylandReadbackEglWindow : public QWaylandShmWindow { public: - QWaylandReadbackEglWindow(QWidget *window, QWaylandReadbackEglIntegration *eglIntegration); + QWaylandReadbackEglWindow(QWindow *window, QWaylandReadbackEglIntegration *eglIntegration); WindowType windowType() const; - QPlatformGLContext *glContext() const; + QPlatformOpenGLContext *glContext() const; void setGeometry(const QRect &rect); diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/readback_egl.pri b/src/plugins/platforms/wayland/gl_integration/readback_egl/readback_egl.pri index 0d8e01b6bb..3325fe8ec9 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/readback_egl.pri +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/readback_egl.pri @@ -1,14 +1,12 @@ - LIBS += -lX11 -lXext -lEGL +load(qpa/egl/convenience) HEADERS += \ $$PWD/qwaylandreadbackeglintegration.h \ $$PWD/qwaylandreadbackeglcontext.h \ $$PWD/qwaylandreadbackeglwindow.h \ - $$PWD/../../../eglconvenience/qeglconvenience.h SOURCES += \ $$PWD/qwaylandreadbackeglintegration.cpp \ $$PWD/qwaylandreadbackeglwindow.cpp \ $$PWD/qwaylandreadbackeglcontext.cpp \ - $$PWD/../../../eglconvenience/qeglconvenience.cpp diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp index 857c1db6e3..850e7bb0ac 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp @@ -41,9 +41,10 @@ #include "qwaylandreadbackglxcontext.h" -#include "qwaylandshmsurface.h" +#include "qwaylandshmbackingstore.h" #include "qwaylandreadbackglxwindow.h" +#include <QtGui/QOpenGLContext> #include <QtCore/QDebug> static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) @@ -68,96 +69,66 @@ static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) } } -QWaylandReadbackGlxContext::QWaylandReadbackGlxContext(QWaylandReadbackGlxIntegration *glxIntegration, QWaylandReadbackGlxWindow *window) - : QPlatformGLContext() - , mGlxIntegration(glxIntegration) - , mWindow(window) - , mBuffer(0) - , mPixmap(0) - , mConfig(qglx_findConfig(glxIntegration->xDisplay(),glxIntegration->screen(),window->widget()->platformWindowFormat(),GLX_PIXMAP_BIT)) - , mGlxPixmap(0) +QWaylandReadbackGlxContext::QWaylandReadbackGlxContext(const QSurfaceFormat &format, + QPlatformOpenGLContext *share, Display *display, int screen) + : m_display(display) { - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(glxIntegration->xDisplay(),mConfig); - mContext = glXCreateContext(glxIntegration->xDisplay(),visualInfo,0,TRUE); + GLXFBConfig config = qglx_findConfig(display, screen, format, GLX_PIXMAP_BIT); - geometryChanged(); + GLXContext shareContext = share ? static_cast<QWaylandReadbackGlxContext *>(share)->m_context : 0; + + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(display, config); + m_context = glXCreateContext(display, visualInfo, shareContext, TRUE); + m_format = qglx_surfaceFormatFromGLXFBConfig(display, config, m_context); +} + +QSurfaceFormat QWaylandReadbackGlxContext::format() const +{ + return m_format; } -void QWaylandReadbackGlxContext::makeCurrent() +bool QWaylandReadbackGlxContext::makeCurrent(QPlatformSurface *surface) { - QPlatformGLContext::makeCurrent(); + GLXPixmap glxPixmap = static_cast<QWaylandReadbackGlxWindow *>(surface)->glxPixmap(); - glXMakeCurrent(mGlxIntegration->xDisplay(),mGlxPixmap,mContext); + return glXMakeCurrent(m_display, glxPixmap, m_context); } void QWaylandReadbackGlxContext::doneCurrent() { - QPlatformGLContext::doneCurrent(); + glXMakeCurrent(m_display, 0, 0); } -void QWaylandReadbackGlxContext::swapBuffers() +void QWaylandReadbackGlxContext::swapBuffers(QPlatformSurface *surface) { - if (QPlatformGLContext::currentContext() != this) { - makeCurrent(); - } + // #### makeCurrent() directly on the platform context doesn't update QOpenGLContext::currentContext() + if (QOpenGLContext::currentContext()->handle() != this) + makeCurrent(surface); + + QWaylandReadbackGlxWindow *w = static_cast<QWaylandReadbackGlxWindow *>(surface); - QSize size = mWindow->geometry().size(); + QSize size = w->geometry().size(); - QImage img(size,QImage::Format_ARGB32); + QImage img(size, QImage::Format_ARGB32); const uchar *constBits = img.bits(); void *pixels = const_cast<uchar *>(constBits); - glReadPixels(0,0, size.width(), size.height(), GL_RGBA,GL_UNSIGNED_BYTE, pixels); + glReadPixels(0, 0, size.width(), size.height(), GL_RGBA,GL_UNSIGNED_BYTE, pixels); img = img.mirrored(); - qgl_byteSwapImage(img,GL_UNSIGNED_INT_8_8_8_8_REV); + qgl_byteSwapImage(img, GL_UNSIGNED_INT_8_8_8_8_REV); constBits = img.bits(); - const uchar *constDstBits = mBuffer->image()->bits(); + const uchar *constDstBits = w->buffer(); uchar *dstBits = const_cast<uchar *>(constDstBits); - memcpy(dstBits,constBits,(img.width()*4) * img.height()); + memcpy(dstBits, constBits, (img.width() * 4) * img.height()); + w->damage(QRect(QPoint(), size)); - mWindow->damage(QRegion(QRect(QPoint(0,0),size))); - mWindow->waitForFrameSync(); - + w->waitForFrameSync(); } -void * QWaylandReadbackGlxContext::getProcAddress(const QString &procName) +void (*QWaylandReadbackGlxContext::getProcAddress(const QByteArray &procName)) () { - return (void *) glXGetProcAddress(reinterpret_cast<GLubyte *>(procName.toLatin1().data())); -} - -QPlatformWindowFormat QWaylandReadbackGlxContext::platformWindowFormat() const -{ - return qglx_platformWindowFromGLXFBConfig(mGlxIntegration->xDisplay(),mConfig,mContext); -} - -void QWaylandReadbackGlxContext::geometryChanged() -{ - QSize size(mWindow->geometry().size()); - if (size.isEmpty()) { - //QGLWidget wants a context for a window without geometry - size = QSize(1,1); - } - - mWindow->waitForFrameSync(); - - delete mBuffer; - //XFreePixmap deletes the glxPixmap as well - if (mPixmap) { - XFreePixmap(mGlxIntegration->xDisplay(),mPixmap); - } - - mBuffer = new QWaylandShmBuffer(mGlxIntegration->waylandDisplay(),size,QImage::Format_ARGB32); - mWindow->attach(mBuffer); - int depth = XDefaultDepth(mGlxIntegration->xDisplay(),mGlxIntegration->screen()); - mPixmap = XCreatePixmap(mGlxIntegration->xDisplay(),mGlxIntegration->rootWindow(),size.width(),size.height(),depth); - XSync(mGlxIntegration->xDisplay(),False); - - mGlxPixmap = glXCreatePixmap(mGlxIntegration->xDisplay(),mConfig,mPixmap,0); - - if (!mGlxPixmap) { - qDebug() << "Could not make egl surface out of pixmap :("; - } + return glXGetProcAddress(reinterpret_cast<const GLubyte *>(procName.constData())); } diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h index 07e0f620de..7b5eeece93 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h @@ -42,38 +42,35 @@ #ifndef QWAYLANDREADBACKGLXCONTEXT_H #define QWAYLANDREADBACKGLXCONTEXT_H -#include <QPlatformGLContext> +#include <QPlatformOpenGLContext> +#include <QSurfaceFormat> #include "qwaylandreadbackglxintegration.h" -#include "qglxconvenience.h" +#include <QtPlatformSupport/private/qglxconvenience_p.h> class QWaylandReadbackGlxWindow; class QWaylandShmBuffer; -class QWaylandReadbackGlxContext : public QPlatformGLContext +class QWaylandReadbackGlxContext : public QPlatformOpenGLContext { public: - QWaylandReadbackGlxContext(QWaylandReadbackGlxIntegration *glxIntegration, QWaylandReadbackGlxWindow *window); + QWaylandReadbackGlxContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, Display *display, int screen); - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); - void* getProcAddress(const QString& procName); + QSurfaceFormat format() const; + + void swapBuffers(QPlatformSurface *surface); - QPlatformWindowFormat platformWindowFormat() const; + bool makeCurrent(QPlatformSurface *surface); + void doneCurrent(); - void geometryChanged(); + void (*getProcAddress(const QByteArray &procName)) (); private: - QWaylandReadbackGlxIntegration *mGlxIntegration; - QWaylandReadbackGlxWindow *mWindow; - QWaylandShmBuffer *mBuffer; + GLXContext m_context; - Pixmap mPixmap; - GLXFBConfig mConfig; - GLXContext mContext; - GLXPixmap mGlxPixmap; + Display *m_display; + QSurfaceFormat m_format; }; #endif // QWAYLANDREADBACKGLXCONTEXT_H diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp index 37a14a9f4c..752bb06a43 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp @@ -66,9 +66,14 @@ void QWaylandReadbackGlxIntegration::initialize() { } -QWaylandWindow * QWaylandReadbackGlxIntegration::createEglWindow(QWidget *widget) +QWaylandWindow * QWaylandReadbackGlxIntegration::createEglWindow(QWindow *window) { - return new QWaylandReadbackGlxWindow(widget,this); + return new QWaylandReadbackGlxWindow(window,this); +} + +QPlatformOpenGLContext *QWaylandReadbackGlxIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const +{ + return new QWaylandReadbackGlxContext(glFormat, share, mDisplay, mScreen); } QWaylandGLIntegration * QWaylandGLIntegration::createGLIntegration(QWaylandDisplay *waylandDisplay) diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h index d267d8dffe..ee50d74ebd 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h @@ -48,7 +48,7 @@ #include <QtCore/QDataStream> #include <QtCore/QMetaType> #include <QtCore/QVariant> -#include <QtGui/QWidget> +#include <QtGui/QWindow> #include <X11/Xlib.h> @@ -60,7 +60,8 @@ public: void initialize(); - QWaylandWindow *createEglWindow(QWidget *widget); + QWaylandWindow *createEglWindow(QWindow *window); + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; QWaylandDisplay *waylandDisplay() const; diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.cpp b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.cpp index 98198dfa06..35c3ca3154 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.cpp @@ -39,12 +39,19 @@ ** ****************************************************************************/ +#include <QtDebug> + #include "qwaylandreadbackglxwindow.h" +#include "qwaylandshmbackingstore.h" -QWaylandReadbackGlxWindow::QWaylandReadbackGlxWindow(QWidget *window, QWaylandReadbackGlxIntegration *glxIntegration) +QWaylandReadbackGlxWindow::QWaylandReadbackGlxWindow(QWindow *window, QWaylandReadbackGlxIntegration *glxIntegration) : QWaylandShmWindow(window) - , mGlxIntegration(glxIntegration) - , mContext(0) + , m_glxIntegration(glxIntegration) + , m_buffer(0) + , m_pixmap(0) + , m_config(0) + , m_glxPixmap(0) + , m_window(window) { } @@ -54,20 +61,54 @@ QWaylandWindow::WindowType QWaylandReadbackGlxWindow::windowType() const return QWaylandWindow::Egl; } -QPlatformGLContext * QWaylandReadbackGlxWindow::glContext() const +void QWaylandReadbackGlxWindow::setGeometry(const QRect &rect) { - if (!mContext) { - QWaylandReadbackGlxWindow *that = const_cast<QWaylandReadbackGlxWindow *>(this); - that->mContext = new QWaylandReadbackGlxContext(mGlxIntegration,that); + QWaylandShmWindow::setGeometry(rect); + + if (m_pixmap) { + delete mBuffer; + //XFreePixmap deletes the glxPixmap as well + XFreePixmap(m_glxIntegration->xDisplay(), m_pixmap); + m_pixmap = 0; } - return mContext; } -void QWaylandReadbackGlxWindow::setGeometry(const QRect &rect) +GLXPixmap QWaylandReadbackGlxWindow::glxPixmap() const { - QWaylandShmWindow::setGeometry(rect); + if (!m_pixmap) + const_cast<QWaylandReadbackGlxWindow *>(this)->createSurface(); + + return m_glxPixmap; +} - if (mContext) { - mContext->geometryChanged(); +uchar *QWaylandReadbackGlxWindow::buffer() +{ + return m_buffer->image()->bits(); +} + +void QWaylandReadbackGlxWindow::createSurface() +{ + QSize size(geometry().size()); + if (size.isEmpty()) { + //QGLWidget wants a context for a window without geometry + size = QSize(1,1); } + + waitForFrameSync(); + + m_buffer = new QWaylandShmBuffer(m_glxIntegration->waylandDisplay(), size, QImage::Format_ARGB32); + attach(m_buffer); + + int depth = XDefaultDepth(m_glxIntegration->xDisplay(), m_glxIntegration->screen()); + m_pixmap = XCreatePixmap(m_glxIntegration->xDisplay(), m_glxIntegration->rootWindow(), size.width(), size.height(), depth); + XSync(m_glxIntegration->xDisplay(), False); + + if (!m_config) + m_config = qglx_findConfig(m_glxIntegration->xDisplay(), m_glxIntegration->screen(), m_window->format()); + + m_glxPixmap = glXCreatePixmap(m_glxIntegration->xDisplay(), m_config, m_pixmap,0); + + if (!m_glxPixmap) + qDebug() << "Could not make glx surface out of pixmap :("; } + diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.h b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.h index d478961d53..c92646c80d 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.h @@ -49,17 +49,25 @@ class QWaylandReadbackGlxWindow : public QWaylandShmWindow { public: - QWaylandReadbackGlxWindow(QWidget *window, QWaylandReadbackGlxIntegration *glxIntegration); + QWaylandReadbackGlxWindow(QWindow *window, QWaylandReadbackGlxIntegration *glxIntegration); WindowType windowType() const; - QPlatformGLContext *glContext() const; - void setGeometry(const QRect &rect); + Pixmap glxPixmap() const; + + uchar *buffer(); + private: - QWaylandReadbackGlxIntegration *mGlxIntegration; - QWaylandReadbackGlxContext *mContext; + void createSurface(); + + QWaylandReadbackGlxIntegration *m_glxIntegration; + QWaylandShmBuffer *m_buffer; + Pixmap m_pixmap; + GLXFBConfig m_config; + GLXPixmap m_glxPixmap; + QWindow *m_window; }; #endif // QWAYLANDREADBACKGLXWINDOW_H diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/readback_glx.pri b/src/plugins/platforms/wayland/gl_integration/readback_glx/readback_glx.pri index f8ea005937..746d594fa2 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/readback_glx.pri +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/readback_glx.pri @@ -1,4 +1,3 @@ -include (../../../glxconvenience/glxconvenience.pri) HEADERS += \ $$PWD/qwaylandreadbackglxintegration.h \ $$PWD/qwaylandreadbackglxwindow.h \ diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp index d4deb01022..27f17a6153 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp @@ -44,11 +44,12 @@ #include "gl_integration/qwaylandglintegration.h" #include "qwaylandeglwindow.h" +#include "qwaylandglcontext.h" #include <QtCore/QDebug> QWaylandEglIntegration::QWaylandEglIntegration(struct wl_display *waylandDisplay) - : mWaylandDisplay(waylandDisplay) + : m_waylandDisplay(waylandDisplay) { qDebug() << "Using Wayland-EGL"; } @@ -56,31 +57,41 @@ QWaylandEglIntegration::QWaylandEglIntegration(struct wl_display *waylandDisplay QWaylandEglIntegration::~QWaylandEglIntegration() { - eglTerminate(mEglDisplay); + eglTerminate(m_eglDisplay); } void QWaylandEglIntegration::initialize() { + QByteArray eglPlatform = qgetenv("EGL_PLATFORM"); + if (eglPlatform.isEmpty()) { + setenv("EGL_PLATFORM","wayland",true); + } + EGLint major,minor; - mEglDisplay = eglGetDisplay(mWaylandDisplay); - if (mEglDisplay == NULL) { + m_eglDisplay = eglGetDisplay(m_waylandDisplay); + if (m_eglDisplay == NULL) { qWarning("EGL not available"); } else { - if (!eglInitialize(mEglDisplay, &major, &minor)) { + if (!eglInitialize(m_eglDisplay, &major, &minor)) { qWarning("failed to initialize EGL display"); return; } } } -QWaylandWindow *QWaylandEglIntegration::createEglWindow(QWidget *window) +QWaylandWindow *QWaylandEglIntegration::createEglWindow(QWindow *window) { return new QWaylandEglWindow(window); } +QPlatformOpenGLContext *QWaylandEglIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const +{ + return new QWaylandGLContext(m_eglDisplay, glFormat, share); +} + EGLDisplay QWaylandEglIntegration::eglDisplay() const { - return mEglDisplay; + return m_eglDisplay; } QWaylandGLIntegration *QWaylandGLIntegration::createGLIntegration(QWaylandDisplay *waylandDisplay) diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h index ea8b0f725c..7a26c57658 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h @@ -47,7 +47,7 @@ #include "qwaylandeglinclude.h" class QWaylandWindow; -class QWidget; +class QWindow; class QWaylandEglIntegration : public QWaylandGLIntegration { @@ -57,14 +57,15 @@ public: void initialize(); - QWaylandWindow *createEglWindow(QWidget *window); + QWaylandWindow *createEglWindow(QWindow *window); + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; EGLDisplay eglDisplay() const; - struct wl_egl_display *nativeDisplay() const; + private: - struct wl_display *mWaylandDisplay; + struct wl_display *m_waylandDisplay; - EGLDisplay mEglDisplay; + EGLDisplay m_eglDisplay; }; #endif // QWAYLANDEGLINTEGRATION_H diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.cpp b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.cpp index cd8b5b3524..e0e1f772b9 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.cpp @@ -44,19 +44,30 @@ #include "qwaylandscreen.h" #include "qwaylandglcontext.h" -QWaylandEglWindow::QWaylandEglWindow(QWidget *window) +#include <QtPlatformSupport/private/qeglconvenience_p.h> + +#include <QtGui/QWindow> +#include <QtGui/QWindowSystemInterface> + +QWaylandEglWindow::QWaylandEglWindow(QWindow *window) : QWaylandWindow(window) - , mGLContext(0) - , mWaylandEglWindow(0) + , m_waylandEglWindow(0) + , m_eglSurface(0) + , m_eglConfig(0) + , m_format(window->format()) { - mEglIntegration = static_cast<QWaylandEglIntegration *>(mDisplay->eglIntegration()); + m_eglIntegration = static_cast<QWaylandEglIntegration *>(mDisplay->eglIntegration()); + //super creates a new surface newSurfaceCreated(); } QWaylandEglWindow::~QWaylandEglWindow() { - delete mGLContext; + if (m_eglSurface) { + eglDestroySurface(m_eglIntegration->eglDisplay(), m_eglSurface); + m_eglSurface = 0; + } } QWaylandWindow::WindowType QWaylandEglWindow::windowType() const @@ -67,46 +78,48 @@ QWaylandWindow::WindowType QWaylandEglWindow::windowType() const void QWaylandEglWindow::setGeometry(const QRect &rect) { QWaylandWindow::setGeometry(rect); - if (mWaylandEglWindow) { - wl_egl_window_resize(mWaylandEglWindow,rect.width(),rect.height(),0,0); + if (m_waylandEglWindow){ + wl_egl_window_resize(m_waylandEglWindow, rect.width(), rect.height(), 0, 0); + QWindowSystemInterface::handleGeometryChange(window(), rect); } } -void QWaylandEglWindow::setParent(const QPlatformWindow *parent) +void QWaylandEglWindow::newSurfaceCreated() { - const QWaylandWindow *wParent = static_cast<const QWaylandWindow *>(parent); + if (m_waylandEglWindow) + wl_egl_window_destroy(m_waylandEglWindow); - mParentWindow = wParent; -} - -QPlatformGLContext * QWaylandEglWindow::glContext() const -{ - if (!mGLContext) { - QWaylandEglWindow *that = const_cast<QWaylandEglWindow *>(this); - that->mGLContext = new QWaylandGLContext(mEglIntegration->eglDisplay(),widget()->platformWindowFormat()); + wl_visual *visual = QWaylandScreen::waylandScreenFromWindow(window())->visual(); + QSize size = geometry().size(); + if (!size.isValid()) + size = QSize(0,0); - EGLNativeWindowType window(reinterpret_cast<EGLNativeWindowType>(mWaylandEglWindow)); - EGLSurface surface = eglCreateWindowSurface(mEglIntegration->eglDisplay(),mGLContext->eglConfig(),window,NULL); - that->mGLContext->setEglSurface(surface); + if (m_eglSurface) { + eglDestroySurface(m_eglIntegration->eglDisplay(), m_eglSurface); + m_eglSurface = 0; } - return mGLContext; + m_waylandEglWindow = wl_egl_window_create(mSurface, size.width(), size.height(), visual); } -void QWaylandEglWindow::newSurfaceCreated() +QSurfaceFormat QWaylandEglWindow::format() const { - if (mWaylandEglWindow) { - wl_egl_window_destroy(mWaylandEglWindow); - } - wl_visual *visual = QWaylandScreen::waylandScreenFromWidget(widget())->visual(); - QSize size = geometry().size(); - if (!size.isValid()) - size = QSize(0,0); + return m_format; +} - mWaylandEglWindow = wl_egl_window_create(mSurface,size.width(),size.height(),visual); - if (mGLContext) { - EGLNativeWindowType window(reinterpret_cast<EGLNativeWindowType>(mWaylandEglWindow)); - EGLSurface surface = eglCreateWindowSurface(mEglIntegration->eglDisplay(),mGLContext->eglConfig(),window,NULL); - mGLContext->setEglSurface(surface); +EGLSurface QWaylandEglWindow::eglSurface() const +{ + if (!m_waylandEglWindow) + return 0; + + if (!m_eglSurface) { + if (!m_eglConfig) + m_eglConfig = q_configFromGLFormat(m_eglIntegration->eglDisplay(), window()->format(), true); + + EGLNativeWindowType window = m_waylandEglWindow; + m_eglSurface = eglCreateWindowSurface(m_eglIntegration->eglDisplay(), m_eglConfig, window, 0); } + + return m_eglSurface; } + diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.h b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.h index 6d2038824a..d435a511c4 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.h @@ -51,20 +51,28 @@ class QWaylandGLContext; class QWaylandEglWindow : public QWaylandWindow { public: - QWaylandEglWindow(QWidget *window); + QWaylandEglWindow(QWindow *window); ~QWaylandEglWindow(); WindowType windowType() const; void setGeometry(const QRect &rect); - void setParent(const QPlatformWindow *parent); - QPlatformGLContext *glContext() const; + + EGLSurface eglSurface() const; + + QSurfaceFormat format() const; + protected: void newSurfaceCreated(); + private: - QWaylandEglIntegration *mEglIntegration; - QWaylandGLContext *mGLContext; - struct wl_egl_window *mWaylandEglWindow; + QWaylandEglIntegration *m_eglIntegration; + struct wl_egl_window *m_waylandEglWindow; + + const QWaylandWindow *m_parentWindow; + + mutable EGLSurface m_eglSurface; + mutable EGLConfig m_eglConfig; - const QWaylandWindow *mParentWindow; + QSurfaceFormat m_format; }; #endif // QWAYLANDEGLWINDOW_H diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp index 0f27501c71..aa61405eb6 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp @@ -43,26 +43,21 @@ #include "qwaylanddisplay.h" #include "qwaylandwindow.h" +#include "qwaylandeglwindow.h" -#include "../../../eglconvenience/qeglconvenience.h" +#include <QtPlatformSupport/private/qeglconvenience_p.h> -#include <QtGui/QPlatformGLContext> -#include <QtGui/QPlatformWindowFormat> +#include <QtGui/QPlatformOpenGLContext> +#include <QtGui/QSurfaceFormat> #include <QtCore/QMutex> -QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, const QPlatformWindowFormat &format) - : QPlatformGLContext() - , mEglDisplay(eglDisplay) - , mSurface(EGL_NO_SURFACE) - , mConfig(q_configFromQPlatformWindowFormat(mEglDisplay,format,true)) - , mFormat(qt_qPlatformWindowFormatFromConfig(mEglDisplay,mConfig)) +QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, const QSurfaceFormat &format, QPlatformOpenGLContext *share) + : QPlatformOpenGLContext() + , m_eglDisplay(eglDisplay) + , m_config(q_configFromGLFormat(m_eglDisplay, format, true)) + , m_format(q_glFormatFromConfig(m_eglDisplay, m_config)) { - QPlatformGLContext *sharePlatformContext = 0; - sharePlatformContext = format.sharedGLContext(); - mFormat.setSharedContext(sharePlatformContext); - EGLContext shareEGLContext = EGL_NO_CONTEXT; - if (sharePlatformContext) - shareEGLContext = static_cast<const QWaylandGLContext*>(sharePlatformContext)->mContext; + EGLContext shareEGLContext = share ? static_cast<QWaylandGLContext *>(share)->eglContext() : EGL_NO_CONTEXT; eglBindAPI(EGL_OPENGL_ES_API); @@ -71,63 +66,38 @@ QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, const QPlatformWindo eglContextAttrs.append(2); eglContextAttrs.append(EGL_NONE); - mContext = eglCreateContext(mEglDisplay, mConfig, - shareEGLContext, eglContextAttrs.constData()); + m_context = eglCreateContext(m_eglDisplay, m_config, shareEGLContext, eglContextAttrs.constData()); } -QWaylandGLContext::QWaylandGLContext() - : QPlatformGLContext() - , mEglDisplay(0) - , mContext(EGL_NO_CONTEXT) - , mSurface(EGL_NO_SURFACE) - , mConfig(0) -{ } - QWaylandGLContext::~QWaylandGLContext() { - eglDestroyContext(mEglDisplay,mContext); + eglDestroyContext(m_eglDisplay, m_context); } -void QWaylandGLContext::makeCurrent() +bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface) { - QPlatformGLContext::makeCurrent(); - if (mSurface == EGL_NO_SURFACE) { - qWarning("makeCurrent with EGL_NO_SURFACE"); - } - eglMakeCurrent(mEglDisplay, mSurface, mSurface, mContext); + EGLSurface eglSurface = static_cast<QWaylandEglWindow *>(surface)->eglSurface(); + return eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_context); } void QWaylandGLContext::doneCurrent() { - QPlatformGLContext::doneCurrent(); - eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); -} - -void QWaylandGLContext::swapBuffers() -{ - eglSwapBuffers(mEglDisplay,mSurface); + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -void *QWaylandGLContext::getProcAddress(const QString &string) +void QWaylandGLContext::swapBuffers(QPlatformSurface *surface) { - return (void *) eglGetProcAddress(string.toLatin1().data()); + EGLSurface eglSurface = static_cast<QWaylandEglWindow *>(surface)->eglSurface(); + eglSwapBuffers(m_eglDisplay, eglSurface); } -void QWaylandGLContext::setEglSurface(EGLSurface surface) +void (*QWaylandGLContext::getProcAddress(const QByteArray &procName)) () { - bool wasCurrent = false; - if (QPlatformGLContext::currentContext() == this) { - wasCurrent = true; - doneCurrent(); - } - mSurface = surface; - if (wasCurrent) { - makeCurrent(); - } + return eglGetProcAddress(procName.constData()); } EGLConfig QWaylandGLContext::eglConfig() const { - return mConfig; + return m_config; } diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h index 2c6feb498c..16d9fa4ada 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h @@ -44,36 +44,36 @@ #include "qwaylanddisplay.h" -#include <QtGui/QPlatformGLContext> +#include <QtGui/QPlatformOpenGLContext> #include "qwaylandeglinclude.h" class QWaylandWindow; class QWaylandGLWindowSurface; -class QWaylandGLContext : public QPlatformGLContext { +class QWaylandGLContext : public QPlatformOpenGLContext { public: - QWaylandGLContext(EGLDisplay eglDisplay, const QPlatformWindowFormat &format); + QWaylandGLContext(EGLDisplay eglDisplay, const QSurfaceFormat &format, QPlatformOpenGLContext *share); ~QWaylandGLContext(); - void makeCurrent(); + + void swapBuffers(QPlatformSurface *surface); + + bool makeCurrent(QPlatformSurface *surface); void doneCurrent(); - void swapBuffers(); - void* getProcAddress(const QString&); - QPlatformWindowFormat platformWindowFormat() const { return mFormat; } + void (*getProcAddress(const QByteArray &procName)) (); - void setEglSurface(EGLSurface surface); - EGLConfig eglConfig() const; -private: - EGLDisplay mEglDisplay; + QSurfaceFormat format() const { return m_format; } - EGLContext mContext; - EGLSurface mSurface; - EGLConfig mConfig; - QPlatformWindowFormat mFormat; + EGLConfig eglConfig() const; + EGLContext eglContext() const { return m_context; } - QWaylandGLContext(); +private: + EGLDisplay m_eglDisplay; + EGLContext m_context; + EGLConfig m_config; + QSurfaceFormat m_format; }; diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/wayland_egl.pri b/src/plugins/platforms/wayland/gl_integration/wayland_egl/wayland_egl.pri index cd0701150f..8b4b163b03 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/wayland_egl.pri +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/wayland_egl.pri @@ -1,5 +1,3 @@ -include (../../../eglconvenience/eglconvenience.pri) - LIBS += -lwayland-egl -lEGL INCLUDEPATH += $$PWD SOURCES += $$PWD/qwaylandeglintegration.cpp \ diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp index 999a411397..f2f9d1ceb6 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp @@ -42,128 +42,31 @@ #include "qwaylandxcompositeeglcontext.h" #include "qwaylandxcompositeeglwindow.h" -#include "qwaylandxcompositebuffer.h" -#include "wayland-xcomposite-client-protocol.h" #include <QtCore/QDebug> +#include <QtGui/QRegion> -#include "qeglconvenience.h" -#include "qxlibeglintegration.h" +#include <QtPlatformSupport/private/qeglconvenience_p.h> -#include <X11/extensions/Xcomposite.h> - -QWaylandXCompositeEGLContext::QWaylandXCompositeEGLContext(QWaylandXCompositeEGLIntegration *glxIntegration, QWaylandXCompositeEGLWindow *window) - : QPlatformGLContext() - , mEglIntegration(glxIntegration) - , mWindow(window) - , mBuffer(0) - , mXWindow(0) - , mConfig(q_configFromQPlatformWindowFormat(glxIntegration->eglDisplay(),window->widget()->platformWindowFormat(),true,EGL_WINDOW_BIT)) - , mWaitingForSync(false) -{ - QVector<EGLint> eglContextAttrs; - eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); eglContextAttrs.append(2); - eglContextAttrs.append(EGL_NONE); - - mContext = eglCreateContext(glxIntegration->eglDisplay(),mConfig,EGL_NO_CONTEXT,eglContextAttrs.constData()); - if (mContext == EGL_NO_CONTEXT) { - qFatal("failed to find context"); - } - - geometryChanged(); -} - -void QWaylandXCompositeEGLContext::makeCurrent() -{ - QPlatformGLContext::makeCurrent(); - - eglMakeCurrent(mEglIntegration->eglDisplay(),mEglWindowSurface,mEglWindowSurface,mContext); -} - -void QWaylandXCompositeEGLContext::doneCurrent() +QWaylandXCompositeEGLContext::QWaylandXCompositeEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display) + : QEGLPlatformContext(format, share, display) { - QPlatformGLContext::doneCurrent(); - eglMakeCurrent(mEglIntegration->eglDisplay(),EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT); } -void QWaylandXCompositeEGLContext::swapBuffers() +void QWaylandXCompositeEGLContext::swapBuffers(QPlatformSurface *surface) { - QSize size = mWindow->geometry().size(); + QEGLPlatformContext::swapBuffers(surface); - eglSwapBuffers(mEglIntegration->eglDisplay(),mEglWindowSurface); - mWindow->damage(QRect(QPoint(0,0),size)); - mWindow->waitForFrameSync(); -} + QWaylandXCompositeEGLWindow *w = + static_cast<QWaylandXCompositeEGLWindow *>(surface); -void * QWaylandXCompositeEGLContext::getProcAddress(const QString &procName) -{ - return (void *)eglGetProcAddress(qPrintable(procName)); -} + QSize size = w->geometry().size(); -QPlatformWindowFormat QWaylandXCompositeEGLContext::platformWindowFormat() const -{ - return qt_qPlatformWindowFormatFromConfig(mEglIntegration->eglDisplay(),mConfig); + w->damage(QRect(QPoint(), size)); + w->waitForFrameSync(); } -void QWaylandXCompositeEGLContext::sync_function(void *data) +EGLSurface QWaylandXCompositeEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) { - QWaylandXCompositeEGLContext *that = static_cast<QWaylandXCompositeEGLContext *>(data); - that->mWaitingForSync = false; -} - -void QWaylandXCompositeEGLContext::geometryChanged() -{ - QSize size(mWindow->geometry().size()); - if (size.isEmpty()) { - //QGLWidget wants a context for a window without geometry - size = QSize(1,1); - } - - delete mBuffer; - //XFreePixmap deletes the glxPixmap as well - if (mXWindow) { - XDestroyWindow(mEglIntegration->xDisplay(),mXWindow); - } - - VisualID visualId = QXlibEglIntegration::getCompatibleVisualId(mEglIntegration->xDisplay(),mEglIntegration->eglDisplay(),mConfig); - - XVisualInfo visualInfoTemplate; - memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); - visualInfoTemplate.visualid = visualId; - - int matchingCount = 0; - XVisualInfo *visualInfo = XGetVisualInfo(mEglIntegration->xDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount); - - Colormap cmap = XCreateColormap(mEglIntegration->xDisplay(),mEglIntegration->rootWindow(),visualInfo->visual,AllocNone); - - XSetWindowAttributes a; - a.colormap = cmap; - mXWindow = XCreateWindow(mEglIntegration->xDisplay(), mEglIntegration->rootWindow(),0, 0, size.width(), size.height(), - 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWColormap, &a); - - XCompositeRedirectWindow(mEglIntegration->xDisplay(), mXWindow, CompositeRedirectManual); - XMapWindow(mEglIntegration->xDisplay(), mXWindow); - - mEglWindowSurface = eglCreateWindowSurface(mEglIntegration->eglDisplay(),mConfig,mXWindow,0); - if (mEglWindowSurface == EGL_NO_SURFACE) { - qFatal("Could not make eglsurface"); - } - - XSync(mEglIntegration->xDisplay(),False); - mBuffer = new QWaylandXCompositeBuffer(mEglIntegration->waylandXComposite(), - (uint32_t)mXWindow, - size, - mEglIntegration->waylandDisplay()->argbVisual()); - mWindow->attach(mBuffer); - wl_display_sync_callback(mEglIntegration->waylandDisplay()->wl_display(), - QWaylandXCompositeEGLContext::sync_function, - this); - - mWaitingForSync = true; - wl_display_sync(mEglIntegration->waylandDisplay()->wl_display(),0); - mEglIntegration->waylandDisplay()->flushRequests(); - while (mWaitingForSync) { - mEglIntegration->waylandDisplay()->readEvents(); - } + return static_cast<QWaylandXCompositeEGLWindow *>(surface)->eglSurface(); } diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h index 9d9dd53e0b..8420f2be13 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h @@ -42,41 +42,23 @@ #ifndef QWAYLANDXCOMPOSITEEGLCONTEXT_H #define QWAYLANDXCOMPOSITEEGLCONTEXT_H -#include <QtGui/QPlatformGLContext> +#include <QtGui/QPlatformOpenGLContext> -#include <QtCore/QWaitCondition> - -#include "qwaylandbuffer.h" #include "qwaylandxcompositeeglintegration.h" +#include <QtPlatformSupport/private/qeglplatformcontext_p.h> + class QWaylandXCompositeEGLWindow; -class QWaylandXCompositeEGLContext : public QPlatformGLContext +class QWaylandXCompositeEGLContext : public QEGLPlatformContext { public: - QWaylandXCompositeEGLContext(QWaylandXCompositeEGLIntegration *glxIntegration, QWaylandXCompositeEGLWindow *window); - - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); - void* getProcAddress(const QString& procName); + QWaylandXCompositeEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display); - QPlatformWindowFormat platformWindowFormat() const; - - void geometryChanged(); + void swapBuffers(QPlatformSurface *surface); private: - QWaylandXCompositeEGLIntegration *mEglIntegration; - QWaylandXCompositeEGLWindow *mWindow; - QWaylandBuffer *mBuffer; - - Window mXWindow; - EGLConfig mConfig; - EGLContext mContext; - EGLSurface mEglWindowSurface; - - static void sync_function(void *data); - bool mWaitingForSync; + EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); }; #endif // QWAYLANDXCOMPOSITEEGLCONTEXT_H diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp index 53199e87b8..d7e37f8e70 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp @@ -70,9 +70,14 @@ void QWaylandXCompositeEGLIntegration::initialize() { } -QWaylandWindow * QWaylandXCompositeEGLIntegration::createEglWindow(QWidget *widget) +QWaylandWindow * QWaylandXCompositeEGLIntegration::createEglWindow(QWindow *window) { - return new QWaylandXCompositeEGLWindow(widget,this); + return new QWaylandXCompositeEGLWindow(window,this); +} + +QPlatformOpenGLContext *QWaylandXCompositeEGLIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const +{ + return new QWaylandXCompositeEGLContext(glFormat, share, eglDisplay()); } Display * QWaylandXCompositeEGLIntegration::xDisplay() const diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h index 1e8055944f..74ea930e9a 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h @@ -49,7 +49,9 @@ #include <QtCore/QDataStream> #include <QtCore/QMetaType> #include <QtCore/QVariant> -#include <QtGui/QWidget> +#include <QtGui/QWindow> + +#include <QPlatformOpenGLContext> #include <QWaitCondition> @@ -66,7 +68,8 @@ public: void initialize(); - QWaylandWindow *createEglWindow(QWidget *widget); + QWaylandWindow *createEglWindow(QWindow *window); + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; QWaylandDisplay *waylandDisplay() const; struct wl_xcomposite *waylandXComposite() const; diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.cpp index 1047cb8b0a..320113f58d 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.cpp @@ -40,17 +40,29 @@ ****************************************************************************/ #include "qwaylandxcompositeeglwindow.h" +#include "qwaylandxcompositebuffer.h" + +#include <QtPlatformSupport/private/qeglconvenience_p.h> +#include <QtPlatformSupport/private/qxlibeglintegration_p.h> + +#include "wayland-xcomposite-client-protocol.h" + +#include <X11/extensions/Xcomposite.h> #include "qwaylandxcompositeeglintegration.h" #include "windowmanager_integration/qwaylandwindowmanagerintegration.h" #include <QtCore/QDebug> -QWaylandXCompositeEGLWindow::QWaylandXCompositeEGLWindow(QWidget *window, QWaylandXCompositeEGLIntegration *glxIntegration) +QWaylandXCompositeEGLWindow::QWaylandXCompositeEGLWindow(QWindow *window, QWaylandXCompositeEGLIntegration *glxIntegration) : QWaylandWindow(window) - , mGlxIntegration(glxIntegration) - , mContext(0) + , m_glxIntegration(glxIntegration) + , m_context(0) + , m_buffer(0) + , m_xWindow(0) + , m_config(q_configFromGLFormat(glxIntegration->eglDisplay(), window->format(), true)) + , m_surface(0) + , m_waitingForSync(false) { - } QWaylandWindow::WindowType QWaylandXCompositeEGLWindow::windowType() const @@ -59,23 +71,83 @@ QWaylandWindow::WindowType QWaylandXCompositeEGLWindow::windowType() const return QWaylandWindow::Egl; } -QPlatformGLContext * QWaylandXCompositeEGLWindow::glContext() const +void QWaylandXCompositeEGLWindow::setGeometry(const QRect &rect) { - if (!mContext) { - qDebug() << "creating glcontext;"; - QWaylandXCompositeEGLWindow *that = const_cast<QWaylandXCompositeEGLWindow *>(this); - that->mContext = new QWaylandXCompositeEGLContext(mGlxIntegration,that); + QWaylandWindow::setGeometry(rect); + + if (m_surface) { + eglDestroySurface(m_glxIntegration->eglDisplay(), m_surface); + m_surface = 0; } - return mContext; } -void QWaylandXCompositeEGLWindow::setGeometry(const QRect &rect) +EGLSurface QWaylandXCompositeEGLWindow::eglSurface() const { - QWaylandWindow::setGeometry(rect); + if (!m_surface) + const_cast<QWaylandXCompositeEGLWindow *>(this)->createEglSurface(); + return m_surface; +} + +void QWaylandXCompositeEGLWindow::createEglSurface() +{ + QSize size(geometry().size()); + if (size.isEmpty()) { + // QGLWidget wants a context for a window without geometry + size = QSize(1,1); + } - if (mContext) { - mContext->geometryChanged(); + delete m_buffer; + //XFreePixmap deletes the glxPixmap as well + if (m_xWindow) { + XDestroyWindow(m_glxIntegration->xDisplay(), m_xWindow); } + + VisualID visualId = QXlibEglIntegration::getCompatibleVisualId(m_glxIntegration->xDisplay(), m_glxIntegration->eglDisplay(), m_config); + + XVisualInfo visualInfoTemplate; + memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); + visualInfoTemplate.visualid = visualId; + + int matchingCount = 0; + XVisualInfo *visualInfo = XGetVisualInfo(m_glxIntegration->xDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount); + + Colormap cmap = XCreateColormap(m_glxIntegration->xDisplay(),m_glxIntegration->rootWindow(),visualInfo->visual,AllocNone); + + XSetWindowAttributes a; + a.colormap = cmap; + m_xWindow = XCreateWindow(m_glxIntegration->xDisplay(), m_glxIntegration->rootWindow(),0, 0, size.width(), size.height(), + 0, visualInfo->depth, InputOutput, visualInfo->visual, + CWColormap, &a); + + XCompositeRedirectWindow(m_glxIntegration->xDisplay(), m_xWindow, CompositeRedirectManual); + XMapWindow(m_glxIntegration->xDisplay(), m_xWindow); + + m_surface = eglCreateWindowSurface(m_glxIntegration->eglDisplay(), m_config, m_xWindow,0); + if (m_surface == EGL_NO_SURFACE) { + qFatal("Could not make eglsurface"); + } + + XSync(m_glxIntegration->xDisplay(),False); + mBuffer = new QWaylandXCompositeBuffer(m_glxIntegration->waylandXComposite(), + (uint32_t)m_xWindow, + size, + m_glxIntegration->waylandDisplay()->argbVisual()); + attach(m_buffer); + wl_display_sync_callback(m_glxIntegration->waylandDisplay()->wl_display(), + QWaylandXCompositeEGLWindow::sync_function, + this); + + m_waitingForSync = true; + wl_display_sync(m_glxIntegration->waylandDisplay()->wl_display(),0); + m_glxIntegration->waylandDisplay()->flushRequests(); + while (m_waitingForSync) + m_glxIntegration->waylandDisplay()->readEvents(); +} + +void QWaylandXCompositeEGLWindow::sync_function(void *data) +{ + QWaylandXCompositeEGLWindow *that = static_cast<QWaylandXCompositeEGLWindow *>(data); + that->m_waitingForSync = false; } void QWaylandXCompositeEGLWindow::requestActivateWindow() diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.h index ea4dd2d626..b2f8fbe6c4 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.h @@ -43,24 +43,36 @@ #define QWAYLANDXCOMPOSITEEGLWINDOW_H #include "qwaylandwindow.h" +#include "qwaylandbuffer.h" + #include "qwaylandxcompositeeglintegration.h" #include "qwaylandxcompositeeglcontext.h" class QWaylandXCompositeEGLWindow : public QWaylandWindow { public: - QWaylandXCompositeEGLWindow(QWidget *window, QWaylandXCompositeEGLIntegration *glxIntegration); + QWaylandXCompositeEGLWindow(QWindow *window, QWaylandXCompositeEGLIntegration *glxIntegration); WindowType windowType() const; - QPlatformGLContext *glContext() const; - void setGeometry(const QRect &rect); void requestActivateWindow(); + EGLSurface eglSurface() const; + private: - QWaylandXCompositeEGLIntegration *mGlxIntegration; - QWaylandXCompositeEGLContext *mContext; + void createEglSurface(); + + QWaylandXCompositeEGLIntegration *m_glxIntegration; + QWaylandXCompositeEGLContext *m_context; + QWaylandBuffer *m_buffer; + + Window m_xWindow; + EGLConfig m_config; + EGLSurface m_surface; + + bool m_waitingForSync; + static void sync_function(void *data); }; #endif // QWAYLANDXCOMPOSITEEGLWINDOW_H diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/xcomposite_egl.pri b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/xcomposite_egl.pri index c3533f9ce3..5f86bd9588 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/xcomposite_egl.pri +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/xcomposite_egl.pri @@ -1,6 +1,4 @@ include (../xcomposite_share/xcomposite_share.pri) -include (../../../eglconvenience/eglconvenience.pri) -include (../../../eglconvenience/xlibeglintegration.pri) LIBS += -lXcomposite -lEGL diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp index 3d49790f3a..75881a7fdd 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp @@ -39,114 +39,56 @@ ** ****************************************************************************/ +#include <QtCore/QDebug> + #include "qwaylandxcompositeglxcontext.h" #include "qwaylandxcompositeglxwindow.h" -#include "qwaylandxcompositebuffer.h" -#include "wayland-xcomposite-client-protocol.h" -#include <QtCore/QDebug> +#include <QRegion> -#include <X11/extensions/Xcomposite.h> - -QWaylandXCompositeGLXContext::QWaylandXCompositeGLXContext(QWaylandXCompositeGLXIntegration *glxIntegration, QWaylandXCompositeGLXWindow *window) - : QPlatformGLContext() - , mGlxIntegration(glxIntegration) - , mWindow(window) - , mBuffer(0) - , mXWindow(0) - , mConfig(qglx_findConfig(glxIntegration->xDisplay(),glxIntegration->screen(),window->widget()->platformWindowFormat())) - , mWaitingForSyncCallback(false) +QWaylandXCompositeGLXContext::QWaylandXCompositeGLXContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, Display *display, int screen) + : m_display(display) { - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(glxIntegration->xDisplay(),mConfig); - mContext = glXCreateContext(glxIntegration->xDisplay(),visualInfo,0,TRUE); - - geometryChanged(); + qDebug("creating XComposite-GLX context"); + GLXContext shareContext = share ? static_cast<QWaylandXCompositeGLXContext *>(share)->m_context : 0; + GLXFBConfig config = qglx_findConfig(display, screen, format); + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(display, config); + m_context = glXCreateContext(display, visualInfo, shareContext, true); + m_format = qglx_surfaceFormatFromGLXFBConfig(display, config, m_context); } -void QWaylandXCompositeGLXContext::makeCurrent() +bool QWaylandXCompositeGLXContext::makeCurrent(QPlatformSurface *surface) { - QPlatformGLContext::makeCurrent(); - glXMakeCurrent(mGlxIntegration->xDisplay(),mXWindow,mContext); + Window xWindow = static_cast<QWaylandXCompositeGLXWindow *>(surface)->xWindow(); + + return glXMakeCurrent(m_display, xWindow, m_context); } void QWaylandXCompositeGLXContext::doneCurrent() { - glXMakeCurrent(mGlxIntegration->xDisplay(),0,0); - QPlatformGLContext::doneCurrent(); + glXMakeCurrent(m_display, 0, 0); } -void QWaylandXCompositeGLXContext::swapBuffers() +void QWaylandXCompositeGLXContext::swapBuffers(QPlatformSurface *surface) { - QSize size = mWindow->geometry().size(); + QWaylandXCompositeGLXWindow *w = static_cast<QWaylandXCompositeGLXWindow *>(surface); - glXSwapBuffers(mGlxIntegration->xDisplay(),mXWindow); - mWindow->damage(QRect(QPoint(0,0),size)); - mWindow->waitForFrameSync(); -} + QSize size = w->geometry().size(); -void * QWaylandXCompositeGLXContext::getProcAddress(const QString &procName) -{ - return (void *) glXGetProcAddress(reinterpret_cast<GLubyte *>(procName.toLatin1().data())); -} + glXSwapBuffers(m_display, w->xWindow()); -QPlatformWindowFormat QWaylandXCompositeGLXContext::platformWindowFormat() const -{ - return qglx_platformWindowFromGLXFBConfig(mGlxIntegration->xDisplay(),mConfig,mContext); + w->damage(QRect(QPoint(), size)); + w->waitForFrameSync(); } -void QWaylandXCompositeGLXContext::sync_function(void *data) +void (*QWaylandXCompositeGLXContext::getProcAddress(const QByteArray &procName)) () { - QWaylandXCompositeGLXContext *that = static_cast<QWaylandXCompositeGLXContext *>(data); - that->mWaitingForSyncCallback = false; + return glXGetProcAddress(reinterpret_cast<const GLubyte *>(procName.constData())); } -void QWaylandXCompositeGLXContext::waitForSync() +QSurfaceFormat QWaylandXCompositeGLXContext::format() const { - wl_display_sync_callback(mGlxIntegration->waylandDisplay()->wl_display(), - QWaylandXCompositeGLXContext::sync_function, - this); - mWaitingForSyncCallback = true; - wl_display_sync(mGlxIntegration->waylandDisplay()->wl_display(),0); - mGlxIntegration->waylandDisplay()->flushRequests(); - while (mWaitingForSyncCallback) { - mGlxIntegration->waylandDisplay()->readEvents(); - } + return m_format; } -void QWaylandXCompositeGLXContext::geometryChanged() -{ - QSize size(mWindow->geometry().size()); - if (size.isEmpty()) { - //QGLWidget wants a context for a window without geometry - size = QSize(1,1); - } - - delete mBuffer; - //XFreePixmap deletes the glxPixmap as well - if (mXWindow) { - XDestroyWindow(mGlxIntegration->xDisplay(),mXWindow); - } - - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(mGlxIntegration->xDisplay(),mConfig); - Colormap cmap = XCreateColormap(mGlxIntegration->xDisplay(),mGlxIntegration->rootWindow(),visualInfo->visual,AllocNone); - - XSetWindowAttributes a; - a.background_pixel = WhitePixel(mGlxIntegration->xDisplay(), mGlxIntegration->screen()); - a.border_pixel = BlackPixel(mGlxIntegration->xDisplay(), mGlxIntegration->screen()); - a.colormap = cmap; - mXWindow = XCreateWindow(mGlxIntegration->xDisplay(), mGlxIntegration->rootWindow(),0, 0, size.width(), size.height(), - 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWBackPixel|CWBorderPixel|CWColormap, &a); - - XCompositeRedirectWindow(mGlxIntegration->xDisplay(), mXWindow, CompositeRedirectManual); - XMapWindow(mGlxIntegration->xDisplay(), mXWindow); - - XSync(mGlxIntegration->xDisplay(),False); - mBuffer = new QWaylandXCompositeBuffer(mGlxIntegration->waylandXComposite(), - (uint32_t)mXWindow, - size, - mGlxIntegration->waylandDisplay()->argbVisual()); - mWindow->attach(mBuffer); - waitForSync(); -} diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h index b6ee2bbc23..3364d88ec4 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h @@ -42,44 +42,33 @@ #ifndef QWAYLANDXCOMPOSITEGLXCONTEXT_H #define QWAYLANDXCOMPOSITEGLXCONTEXT_H -#include <QtGui/QPlatformGLContext> +#include <QtGui/QPlatformOpenGLContext> -#include <QtCore/QWaitCondition> - -#include "qwaylandbuffer.h" #include "qwaylandxcompositeglxintegration.h" - -#include "qglxconvenience.h" +#include <QtPlatformSupport/private/qglxconvenience_p.h> class QWaylandXCompositeGLXWindow; class QWaylandShmBuffer; -class QWaylandXCompositeGLXContext : public QPlatformGLContext +class QWaylandXCompositeGLXContext : public QPlatformOpenGLContext { public: - QWaylandXCompositeGLXContext(QWaylandXCompositeGLXIntegration *glxIntegration, QWaylandXCompositeGLXWindow *window); + QWaylandXCompositeGLXContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, Display *display, int screen); - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); - void* getProcAddress(const QString& procName); + QSurfaceFormat format() const; - QPlatformWindowFormat platformWindowFormat() const; + void swapBuffers(QPlatformSurface *surface); - void geometryChanged(); + bool makeCurrent(QPlatformSurface *surface); + void doneCurrent(); -private: - QWaylandXCompositeGLXIntegration *mGlxIntegration; - QWaylandXCompositeGLXWindow *mWindow; - QWaylandBuffer *mBuffer; + void (*getProcAddress(const QByteArray &procName)) (); - Window mXWindow; - GLXFBConfig mConfig; - GLXContext mContext; +private: + GLXContext m_context; - static void sync_function(void *data); - void waitForSync(); - bool mWaitingForSyncCallback; + Display *m_display; + QSurfaceFormat m_format; }; #endif // QWAYLANDXCOMPOSITEGLXCONTEXT_H diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp index e8dbea48c6..e1eb2e635a 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp @@ -52,12 +52,15 @@ QWaylandGLIntegration * QWaylandGLIntegration::createGLIntegration(QWaylandDispl return new QWaylandXCompositeGLXIntegration(waylandDisplay); } -QWaylandXCompositeGLXIntegration::QWaylandXCompositeGLXIntegration(QWaylandDisplay * waylandDispaly) - : QWaylandGLIntegration() - , mWaylandDisplay(waylandDispaly) +QWaylandXCompositeGLXIntegration::QWaylandXCompositeGLXIntegration(QWaylandDisplay *waylandDisplay) + : mWaylandDisplay(waylandDisplay) + , mWaylandComposite(0) + , mDisplay(0) + , mScreen(0) + , mRootWindow(0) { qDebug() << "Using XComposite-GLX"; - wl_display_add_global_listener(waylandDispaly->wl_display(), QWaylandXCompositeGLXIntegration::wlDisplayHandleGlobal, + wl_display_add_global_listener(waylandDisplay->wl_display(), QWaylandXCompositeGLXIntegration::wlDisplayHandleGlobal, this); } @@ -70,9 +73,14 @@ void QWaylandXCompositeGLXIntegration::initialize() { } -QWaylandWindow * QWaylandXCompositeGLXIntegration::createEglWindow(QWidget *widget) +QWaylandWindow * QWaylandXCompositeGLXIntegration::createEglWindow(QWindow *window) { - return new QWaylandXCompositeGLXWindow(widget,this); + return new QWaylandXCompositeGLXWindow(window, this); +} + +QPlatformOpenGLContext *QWaylandXCompositeGLXIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const +{ + return new QWaylandXCompositeGLXContext(glFormat, share, mDisplay, mScreen); } Display * QWaylandXCompositeGLXIntegration::xDisplay() const @@ -107,6 +115,7 @@ void QWaylandXCompositeGLXIntegration::wlDisplayHandleGlobal(wl_display *display { Q_UNUSED(version); if (strcmp(interface, "wl_xcomposite") == 0) { + qDebug("XComposite-GLX: got wl_xcomposite global"); QWaylandXCompositeGLXIntegration *integration = static_cast<QWaylandXCompositeGLXIntegration *>(data); integration->mWaylandComposite = wl_xcomposite_create(display,id,1); wl_xcomposite_add_listener(integration->mWaylandComposite,&xcomposite_listener,integration); @@ -119,6 +128,8 @@ void QWaylandXCompositeGLXIntegration::rootInformation(void *data, wl_xcomposite Q_UNUSED(xcomposite); QWaylandXCompositeGLXIntegration *integration = static_cast<QWaylandXCompositeGLXIntegration *>(data); + qDebug("XComposite-GLX: xcomposite listener callback"); + integration->mDisplay = XOpenDisplay(display_name); integration->mRootWindow = (Window) root_window; integration->mScreen = XDefaultScreen(integration->mDisplay); diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h index 17f2f6d4e4..b028067d8e 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h @@ -49,7 +49,7 @@ #include <QtCore/QDataStream> #include <QtCore/QMetaType> #include <QtCore/QVariant> -#include <QtGui/QWidget> +#include <QtGui/QWindow> #include <X11/Xlib.h> @@ -63,7 +63,8 @@ public: void initialize(); - QWaylandWindow *createEglWindow(QWidget *widget); + QWaylandWindow *createEglWindow(QWindow *window); + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; QWaylandDisplay *waylandDisplay() const; struct wl_xcomposite *waylandXComposite() const; diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.cpp index cd7ae1964c..abaf3b16a9 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.cpp @@ -40,15 +40,24 @@ ****************************************************************************/ #include "qwaylandxcompositeglxwindow.h" +#include "qwaylandxcompositebuffer.h" #include <QtCore/QDebug> -QWaylandXCompositeGLXWindow::QWaylandXCompositeGLXWindow(QWidget *window, QWaylandXCompositeGLXIntegration *glxIntegration) +#include "wayland-xcomposite-client-protocol.h" +#include <QtGui/QRegion> + +#include <X11/extensions/Xcomposite.h> + + +QWaylandXCompositeGLXWindow::QWaylandXCompositeGLXWindow(QWindow *window, QWaylandXCompositeGLXIntegration *glxIntegration) : QWaylandWindow(window) - , mGlxIntegration(glxIntegration) - , mContext(0) + , m_glxIntegration(glxIntegration) + , m_xWindow(0) + , m_config(qglx_findConfig(glxIntegration->xDisplay(), glxIntegration->screen(), window->format())) + , m_buffer(0) + , m_waitingForSync(false) { - } QWaylandWindow::WindowType QWaylandXCompositeGLXWindow::windowType() const @@ -57,21 +66,79 @@ QWaylandWindow::WindowType QWaylandXCompositeGLXWindow::windowType() const return QWaylandWindow::Egl; } -QPlatformGLContext * QWaylandXCompositeGLXWindow::glContext() const +void QWaylandXCompositeGLXWindow::setGeometry(const QRect &rect) { - if (!mContext) { - qDebug() << "creating glcontext;"; - QWaylandXCompositeGLXWindow *that = const_cast<QWaylandXCompositeGLXWindow *>(this); - that->mContext = new QWaylandXCompositeGLXContext(mGlxIntegration,that); + QWaylandWindow::setGeometry(rect); + + if (m_xWindow) { + delete m_buffer; + + XDestroyWindow(m_glxIntegration->xDisplay(), m_xWindow); + m_xWindow = 0; } - return mContext; } -void QWaylandXCompositeGLXWindow::setGeometry(const QRect &rect) +Window QWaylandXCompositeGLXWindow::xWindow() const { - QWaylandWindow::setGeometry(rect); + if (!m_xWindow) + const_cast<QWaylandXCompositeGLXWindow *>(this)->createSurface(); - if (mContext) { - mContext->geometryChanged(); + return m_xWindow; +} + +void QWaylandXCompositeGLXWindow::waitForSync() +{ + wl_display_sync_callback(m_glxIntegration->waylandDisplay()->wl_display(), + QWaylandXCompositeGLXWindow::sync_function, + this); + m_waitingForSync= true; + wl_display_sync(m_glxIntegration->waylandDisplay()->wl_display(), 0); + m_glxIntegration->waylandDisplay()->flushRequests(); + while (m_waitingForSync) + m_glxIntegration->waylandDisplay()->readEvents(); +} + + +void QWaylandXCompositeGLXWindow::createSurface() +{ + QSize size(geometry().size()); + if (size.isEmpty()) { + //QGLWidget wants a context for a window without geometry + size = QSize(1,1); } + + if (!m_glxIntegration->xDisplay()) { + qWarning("XCompositeGLXWindow: X display still null?!"); + return; + } + + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(m_glxIntegration->xDisplay(), m_config); + Colormap cmap = XCreateColormap(m_glxIntegration->xDisplay(), m_glxIntegration->rootWindow(), + visualInfo->visual, AllocNone); + + XSetWindowAttributes a; + a.background_pixel = WhitePixel(m_glxIntegration->xDisplay(), m_glxIntegration->screen()); + a.border_pixel = BlackPixel(m_glxIntegration->xDisplay(), m_glxIntegration->screen()); + a.colormap = cmap; + m_xWindow = XCreateWindow(m_glxIntegration->xDisplay(), m_glxIntegration->rootWindow(),0, 0, size.width(), size.height(), + 0, visualInfo->depth, InputOutput, visualInfo->visual, + CWBackPixel|CWBorderPixel|CWColormap, &a); + + XCompositeRedirectWindow(m_glxIntegration->xDisplay(), m_xWindow, CompositeRedirectManual); + XMapWindow(m_glxIntegration->xDisplay(), m_xWindow); + + XSync(m_glxIntegration->xDisplay(), False); + m_buffer = new QWaylandXCompositeBuffer(m_glxIntegration->waylandXComposite(), + (uint32_t)m_xWindow, + size, + m_glxIntegration->waylandDisplay()->argbVisual()); + attach(m_buffer); + waitForSync(); +} + +void QWaylandXCompositeGLXWindow::sync_function(void *data) +{ + QWaylandXCompositeGLXWindow *that = static_cast<QWaylandXCompositeGLXWindow *>(data); + that->m_waitingForSync = false; } + diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.h index 8808f2d482..acf6c8e63e 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.h @@ -46,20 +46,34 @@ #include "qwaylandxcompositeglxintegration.h" #include "qwaylandxcompositeglxcontext.h" +#include <QtCore/QWaitCondition> + +#include "qwaylandbuffer.h" + class QWaylandXCompositeGLXWindow : public QWaylandWindow { public: - QWaylandXCompositeGLXWindow(QWidget *window, QWaylandXCompositeGLXIntegration *glxIntegration); + QWaylandXCompositeGLXWindow(QWindow *window, QWaylandXCompositeGLXIntegration *glxIntegration); WindowType windowType() const; - QPlatformGLContext *glContext() const; - void setGeometry(const QRect &rect); + Window xWindow() const; + private: - QWaylandXCompositeGLXIntegration *mGlxIntegration; - QWaylandXCompositeGLXContext *mContext; + void createSurface(); + + QWaylandXCompositeGLXIntegration *m_glxIntegration; + + Window m_xWindow; + GLXFBConfig m_config; + + QWaylandBuffer *m_buffer; + + void waitForSync(); + bool m_waitingForSync; + static void sync_function(void *data); }; #endif // QWAYLANDXCOMPOSITEGLXWINDOW_H diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/xcomposite_glx.pri b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/xcomposite_glx.pri index 43295e91e7..bbd6c12e42 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/xcomposite_glx.pri +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/xcomposite_glx.pri @@ -1,5 +1,4 @@ include (../xcomposite_share/xcomposite_share.pri) -include (../../../glxconvenience/glxconvenience.pri) LIBS += -lXcomposite SOURCES += \ diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.cpp index 7d309ef877..f4bacc3c1f 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.cpp @@ -42,6 +42,7 @@ #include "qwaylandxcompositebuffer.h" #include "wayland-client.h" +#include "wayland-xcomposite-client-protocol.h" QWaylandXCompositeBuffer::QWaylandXCompositeBuffer(wl_xcomposite *xcomposite, uint32_t window, const QSize &size, wl_visual *visual) :mSize(size) diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.h index cbd40ad381..02176d7850 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.h @@ -43,8 +43,10 @@ #define QWAYLANDXCOMPOSITEBUFFER_H #include "qwaylandbuffer.h" +#include <stdint.h> -#include "wayland-xcomposite-client-protocol.h" +struct wl_xcomposite; +struct wl_visual; class QWaylandXCompositeBuffer : public QWaylandBuffer { diff --git a/src/plugins/platforms/wayland/main.cpp b/src/plugins/platforms/wayland/main.cpp index ba365ca3a1..e4d420d68a 100644 --- a/src/plugins/platforms/wayland/main.cpp +++ b/src/plugins/platforms/wayland/main.cpp @@ -54,8 +54,7 @@ public: QStringList QWaylandIntegrationPlugin::keys() const { QStringList list; - list << "Wayland"; - list << "WaylandGL"; + list << "wayland"; return list; } @@ -63,9 +62,7 @@ QPlatformIntegration *QWaylandIntegrationPlugin::create(const QString& system, c { Q_UNUSED(paramList); if (system.toLower() == "wayland") - return new QWaylandIntegration; - if (system.toLower() == "waylandgl") - return new QWaylandIntegration(true); + return new QWaylandIntegration(); return 0; } diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.cpp b/src/plugins/platforms/wayland/qwaylandclipboard.cpp index 45f0abc00a..f90d1a9802 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.cpp +++ b/src/plugins/platforms/wayland/qwaylandclipboard.cpp @@ -44,7 +44,7 @@ #include "qwaylandinputdevice.h" #include "qwaylandmime.h" #include <QtGui/QPlatformNativeInterface> -#include <QtGui/QApplication> +#include <QtGui/QGuiApplication> #include <QtCore/QMimeData> #include <QtCore/QStringList> #include <QtCore/QFile> diff --git a/src/plugins/platforms/wayland/qwaylandcursor.cpp b/src/plugins/platforms/wayland/qwaylandcursor.cpp index 87b846cefb..bbbab6dca7 100644 --- a/src/plugins/platforms/wayland/qwaylandcursor.cpp +++ b/src/plugins/platforms/wayland/qwaylandcursor.cpp @@ -43,10 +43,11 @@ #include "qwaylanddisplay.h" #include "qwaylandinputdevice.h" -#include "qwaylandshmsurface.h" #include "qwaylandscreen.h" +#include "qwaylandshmbackingstore.h" #include <QtGui/QImageReader> +#include <QDebug> #define DATADIR "/usr/share" @@ -108,14 +109,15 @@ QWaylandCursor::QWaylandCursor(QWaylandScreen *screen) { } -void QWaylandCursor::changeCursor(QCursor *cursor, QWidget *widget) +void QWaylandCursor::changeCursor(QCursor *cursor, QWindow *window) { const struct pointer_image *p; - if (widget == NULL) + if (window == NULL) return; p = NULL; + bool isBitmap = false; switch (cursor->shape()) { case Qt::ArrowCursor: @@ -152,32 +154,53 @@ void QWaylandCursor::changeCursor(QCursor *cursor, QWidget *widget) p = &pointer_images[cursor->shape()]; break; - default: case Qt::BitmapCursor: + isBitmap = true; + break; + + default: break; } - if (!p) { + if (!p && !isBitmap) { p = &pointer_images[0]; qWarning("unhandled cursor %d", cursor->shape()); } - QImageReader reader(p->filename); - - if (!reader.canRead()) - return; - - if (mBuffer == NULL || mBuffer->size() != reader.size()) { - if (mBuffer) + if (isBitmap && !cursor->pixmap().isNull()) { + setupPixmapCursor(cursor); + } else if (isBitmap && cursor->bitmap()) { + qWarning("unsupported QBitmap cursor"); + } else { + QImageReader reader(p->filename); + if (!reader.canRead()) + return; + if (mBuffer == NULL || mBuffer->size() != reader.size()) { delete mBuffer; + mBuffer = new QWaylandShmBuffer(mDisplay, reader.size(), + QImage::Format_ARGB32); + } + reader.read(mBuffer->image()); + mDisplay->setCursor(mBuffer, p->hotspot_x, p->hotspot_y); + } +} - mBuffer = new QWaylandShmBuffer(mDisplay, reader.size(), +void QWaylandCursor::setupPixmapCursor(QCursor *cursor) +{ + if (!cursor) { + delete mBuffer; + mBuffer = 0; + return; + } + if (!mBuffer || mBuffer->size() != cursor->pixmap().size()) { + delete mBuffer; + mBuffer = new QWaylandShmBuffer(mDisplay, cursor->pixmap().size(), QImage::Format_ARGB32); } - - reader.read(mBuffer->image()); - - mDisplay->setCursor(mBuffer, p->hotspot_x, p->hotspot_y); + QImage src = cursor->pixmap().toImage().convertToFormat(QImage::Format_ARGB32); + for (int y = 0; y < src.height(); ++y) + qMemCopy(mBuffer->image()->scanLine(y), src.scanLine(y), src.bytesPerLine()); + mDisplay->setCursor(mBuffer, cursor->hotSpot().x(), cursor->hotSpot().y()); } void QWaylandDisplay::setCursor(QWaylandBuffer *buffer, int32_t x, int32_t y) @@ -189,3 +212,19 @@ void QWaylandDisplay::setCursor(QWaylandBuffer *buffer, int32_t x, int32_t y) inputDevice->attach(buffer, x, y); } } + +void QWaylandCursor::pointerEvent(const QMouseEvent &event) +{ + mLastPos = event.globalPos(); +} + +QPoint QWaylandCursor::pos() const +{ + return mLastPos; +} + +void QWaylandCursor::setPos(const QPoint &pos) +{ + Q_UNUSED(pos); + qWarning() << "QWaylandCursor::setPos: not implemented"; +} diff --git a/src/plugins/platforms/wayland/qwaylandcursor.h b/src/plugins/platforms/wayland/qwaylandcursor.h index 236bfc56ee..8753aa5698 100644 --- a/src/plugins/platforms/wayland/qwaylandcursor.h +++ b/src/plugins/platforms/wayland/qwaylandcursor.h @@ -48,13 +48,23 @@ class QWaylandShmBuffer; class QWaylandDisplay; class QWaylandScreen; -class QWaylandCursor : QPlatformCursor { +class QWaylandCursor : public QPlatformCursor +{ public: QWaylandCursor(QWaylandScreen *screen); - void changeCursor(QCursor *cursor, QWidget *widget); + void changeCursor(QCursor *cursor, QWindow *window); + void pointerEvent(const QMouseEvent &event); + QPoint pos() const; + void setPos(const QPoint &pos); + + void setupPixmapCursor(QCursor *cursor); + QWaylandShmBuffer *mBuffer; QWaylandDisplay *mDisplay; + +private: + QPoint mLastPos; }; #endif // QWAYLANDCURSOR_H diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 26e0e8ebeb..588096933c 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -46,6 +46,7 @@ #include "qwaylandcursor.h" #include "qwaylandinputdevice.h" #include "qwaylandclipboard.h" +#include "qwaylanddnd.h" #ifdef QT_WAYLAND_GL_SUPPORT #include "gl_integration/qwaylandglintegration.h" @@ -56,8 +57,7 @@ #endif #include <QtCore/QAbstractEventDispatcher> -#include <QtGui/QApplication> -#include <QtGui/private/qapplication_p.h> +#include <QtGui/private/qguiapplication_p.h> #include <unistd.h> #include <fcntl.h> @@ -142,6 +142,13 @@ QWaylandDisplay::QWaylandDisplay(void) wl_display_add_global_listener(mDisplay, QWaylandDisplay::displayHandleGlobal, this); + mFd = wl_display_get_fd(mDisplay, sourceUpdate, this); + QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; + connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(flushRequests())); + + mReadNotifier = new QSocketNotifier(mFd, QSocketNotifier::Read, this); + connect(mReadNotifier, SIGNAL(activated(int)), this, SLOT(readEvents())); + #ifdef QT_WAYLAND_GL_SUPPORT mEglIntegration = QWaylandGLIntegration::createGLIntegration(this); #endif @@ -156,13 +163,6 @@ QWaylandDisplay::QWaylandDisplay(void) mEglIntegration->initialize(); #endif - connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(flushRequests())); - - mFd = wl_display_get_fd(mDisplay, sourceUpdate, this); - - mReadNotifier = new QSocketNotifier(mFd, QSocketNotifier::Read, this); - connect(mReadNotifier, SIGNAL(activated(int)), this, SLOT(readEvents())); - waitForScreens(); } @@ -313,6 +313,8 @@ void QWaylandDisplay::displayHandleGlobal(uint32_t id, mInputDevices.append(inputDevice); } else if (interface == "wl_selection_offer") { QWaylandClipboard::instance(display)->createSelectionOffer(id); + } else if (interface == "wl_drag_offer") { + QWaylandDrag::instance(display)->createDragOffer(id); } } diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.h b/src/plugins/platforms/wayland/qwaylanddisplay.h index 4dff24d086..2b7f33f4f6 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay.h @@ -49,6 +49,7 @@ #include <wayland-client.h> +class QAbstractEventDispatcher; class QWaylandInputDevice; class QSocketNotifier; class QWaylandBuffer; @@ -142,6 +143,7 @@ private: static void handleVisual(void *data, struct wl_compositor *compositor, uint32_t id, uint32_t token); + #ifdef QT_WAYLAND_GL_SUPPORT QWaylandGLIntegration *mEglIntegration; #endif diff --git a/src/plugins/platforms/wayland/qwaylanddnd.cpp b/src/plugins/platforms/wayland/qwaylanddnd.cpp new file mode 100644 index 0000000000..5368daaf63 --- /dev/null +++ b/src/plugins/platforms/wayland/qwaylanddnd.cpp @@ -0,0 +1,423 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylanddnd.h" +#include "qwaylandinputdevice.h" +#include <QStringList> +#include <QFile> +#include <QtGui/private/qdnd_p.h> +#include <QGuiApplication> +#include <QSocketNotifier> +#include <sys/time.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <QDebug> + +#include <QPlatformCursor> +#include "qwaylandcursor.h" + +class QWaylandDragWrapper +{ +public: + QWaylandDragWrapper(QWaylandDisplay *display, QMimeData *data); + ~QWaylandDragWrapper(); + QMimeData *mimeData() const { return mData; } + +private: + static void target(void *data, wl_drag *drag, const char *mimeType); + static void finish(void *data, wl_drag *drag, int fd); + static void reject(void *data, wl_drag *drag); + static const wl_drag_listener dragListener; + + QWaylandDisplay *mDisplay; + wl_drag *mDrag; + QMimeData *mData; + QString mAcceptedType; +}; + +class QWaylandDragOfferWrapper +{ +public: + QWaylandDragOfferWrapper(QWaylandDisplay *display, QMimeData *data, uint32_t id); + ~QWaylandDragOfferWrapper(); + +private: + static void offer(void *data, struct wl_drag_offer *offer, const char *mimeType); + static void pointerFocus(void *data, struct wl_drag_offer *offer, uint32_t time, + wl_surface *surface, + int32_t x, int32_t y, + int32_t surfaceX, int32_t surfaceY); + static void motion(void *data, struct wl_drag_offer *offer, uint32_t time, + int32_t x, int32_t y, + int32_t surfaceX, int32_t surfaceY); + static void drop(void *data, struct wl_drag_offer *offer); + static const wl_drag_offer_listener dragOfferListener; + + void sendEventToWindow(struct wl_drag_offer *offer, uint32_t time, + wl_surface *surface, const QPoint &pos); + + QWaylandDisplay *mDisplay; + QMimeData *mData; + struct wl_drag_offer *mOffer; + QMimeData mOfferedTypes; // no data in this one, just the formats + wl_surface *mFocusSurface; + bool mAccepted; + QPoint mLastEventPos; + friend class QWaylandDrag; +}; + +static QWaylandDrag *dnd = 0; + +QWaylandDrag *QWaylandDrag::instance(QWaylandDisplay *display) +{ + if (!dnd) + dnd = new QWaylandDrag(display); + return dnd; +} + +QWaylandDrag::QWaylandDrag(QWaylandDisplay *display) + : mDisplay(display), mDropData(0), mCurrentDrag(0), mCurrentOffer(0) +{ + mDropData = new QMimeData; +} + +QWaylandDrag::~QWaylandDrag() +{ + delete mCurrentDrag; + delete mCurrentOffer; + delete mDropData; +} + +QMimeData *QWaylandDrag::platformDropData() +{ + return mDropData; +} + +static void showDragPixmap(bool show) +{ + QCursor c(QDragManager::self()->object->pixmap()); + QList<QWeakPointer<QPlatformCursor> > cursors = QPlatformCursorPrivate::getInstances(); + foreach (QWeakPointer<QPlatformCursor> cursor, cursors) + if (cursor) + static_cast<QWaylandCursor *>(cursor.data())->setupPixmapCursor(show ? &c : 0); +} + + +QWaylandDragWrapper::QWaylandDragWrapper(QWaylandDisplay *display, QMimeData *data) + : mDisplay(display), mDrag(0), mData(data) +{ + QWaylandWindow *w = mDisplay->inputDevices().at(0)->pointerFocus(); + if (!w) { + qWarning("QWaylandDragWrapper: No window with pointer focus?!"); + return; + } + qDebug() << "QWaylandDragWrapper" << data->formats(); + struct wl_shell *shell = display->wl_shell(); + mDrag = wl_shell_create_drag(shell); + wl_drag_add_listener(mDrag, &dragListener, this); + foreach (const QString &format, data->formats()) + wl_drag_offer(mDrag, format.toLatin1().constData()); + struct timeval tv; + gettimeofday(&tv, 0); + wl_drag_activate(mDrag, + w->wl_surface(), + display->inputDevices().at(0)->wl_input_device(), + tv.tv_sec * 1000 + tv.tv_usec / 1000); + showDragPixmap(true); +} + +QWaylandDragWrapper::~QWaylandDragWrapper() +{ + QWaylandDrag *dragHandler = QWaylandDrag::instance(mDisplay); + if (dragHandler->mCurrentDrag == this) + dragHandler->mCurrentDrag = 0; + wl_drag_destroy(mDrag); +} + +const wl_drag_listener QWaylandDragWrapper::dragListener = { + QWaylandDragWrapper::target, + QWaylandDragWrapper::finish, + QWaylandDragWrapper::reject +}; + +void QWaylandDragWrapper::target(void *data, wl_drag *drag, const char *mimeType) +{ + Q_UNUSED(drag); + QWaylandDragWrapper *self = static_cast<QWaylandDragWrapper *>(data); + self->mAcceptedType = mimeType ? QString::fromLatin1(mimeType) : QString(); + qDebug() << "target" << self->mAcceptedType; + QDragManager *manager = QDragManager::self(); + if (mimeType) + manager->global_accepted_action = manager->defaultAction(manager->possible_actions, + QGuiApplication::keyboardModifiers()); + else + manager->global_accepted_action = Qt::IgnoreAction; +} + +void QWaylandDragWrapper::finish(void *data, wl_drag *drag, int fd) +{ + Q_UNUSED(drag); + QWaylandDragWrapper *self = static_cast<QWaylandDragWrapper *>(data); + qDebug() << "finish" << self->mAcceptedType; + if (self->mAcceptedType.isEmpty()) + return; // no drag target was valid when the drag finished + QByteArray content = self->mData->data(self->mAcceptedType); + if (!content.isEmpty()) { + QFile f; + if (f.open(fd, QIODevice::WriteOnly)) + f.write(content); + } + close(fd); + // Drag finished on source side with drop. + + QDragManager::self()->stopDrag(); + showDragPixmap(false); + delete self; + qDebug() << " *** DRAG OVER WITH DROP"; +} + +void QWaylandDragWrapper::reject(void *data, wl_drag *drag) +{ + Q_UNUSED(drag); + QWaylandDragWrapper *self = static_cast<QWaylandDragWrapper *>(data); + self->mAcceptedType = QString(); + qDebug() << "reject"; + QDragManager::self()->global_accepted_action = Qt::IgnoreAction; +} + + +QWaylandDragOfferWrapper::QWaylandDragOfferWrapper(QWaylandDisplay *display, + QMimeData *data, + uint32_t id) + : mDisplay(display), mData(data), mOffer(0), mFocusSurface(0), + mAccepted(false) +{ + mOffer = wl_drag_offer_create(mDisplay->wl_display(), id, 1); + wl_drag_offer_add_listener(mOffer, &dragOfferListener, this); +} + +QWaylandDragOfferWrapper::~QWaylandDragOfferWrapper() +{ + QWaylandDrag *dragHandler = QWaylandDrag::instance(mDisplay); + if (dragHandler->mCurrentOffer == this) + dragHandler->mCurrentOffer = 0; + wl_drag_offer_destroy(mOffer); +} + +const wl_drag_offer_listener QWaylandDragOfferWrapper::dragOfferListener = { + QWaylandDragOfferWrapper::offer, + QWaylandDragOfferWrapper::pointerFocus, + QWaylandDragOfferWrapper::motion, + QWaylandDragOfferWrapper::drop +}; + +void QWaylandDragOfferWrapper::offer(void *data, struct wl_drag_offer *offer, const char *mimeType) +{ + // Called for each type before pointerFocus. + Q_UNUSED(offer); + QWaylandDragOfferWrapper *self = static_cast<QWaylandDragOfferWrapper *>(data); + self->mOfferedTypes.setData(QString::fromLatin1(mimeType), QByteArray()); +} + +void QWaylandDragOfferWrapper::pointerFocus(void *data, struct wl_drag_offer *offer, uint32_t time, + wl_surface *surface, + int32_t x, int32_t y, + int32_t surfaceX, int32_t surfaceY) +{ + qDebug() << "pointerFocus" << surface << x << y << surfaceX << surfaceY; + QWaylandDragOfferWrapper *self = static_cast<QWaylandDragOfferWrapper *>(data); + QWaylandDrag *mgr = QWaylandDrag::instance(self->mDisplay); + + if (!surface) { + if (self->mFocusSurface) { + // This is a DragLeave. + QWindow *window = static_cast<QWaylandWindow *>( + wl_surface_get_user_data(self->mFocusSurface))->window(); + QWindowSystemInterface::handleDrag(window, 0, QPoint()); + if (self->mAccepted) { + wl_drag_offer_reject(offer); + self->mAccepted = false; + } + if (!mgr->mCurrentDrag) // no drag -> this is not the source side -> offer can be destroyed + delete mgr->mCurrentOffer; + } else { + // Drag finished on source side without drop. + QDragManager::self()->stopDrag(); + showDragPixmap(false); + delete mgr->mCurrentDrag; + qDebug() << " *** DRAG OVER WITHOUT DROP"; + } + } + + self->mFocusSurface = surface; + + // This is a DragMove or DragEnter+DragMove. + if (surface) + self->sendEventToWindow(offer, time, surface, QPoint(surfaceX, surfaceY)); +} + +void QWaylandDragOfferWrapper::motion(void *data, struct wl_drag_offer *offer, uint32_t time, + int32_t x, int32_t y, + int32_t surfaceX, int32_t surfaceY) +{ + Q_UNUSED(x); + Q_UNUSED(y); + QWaylandDragOfferWrapper *self = static_cast<QWaylandDragOfferWrapper *>(data); + if (!self->mFocusSurface) + return; +// qDebug() << "motion" << self->mFocusSurface << x << y << surfaceX << surfaceY; + self->sendEventToWindow(offer, time, self->mFocusSurface, QPoint(surfaceX, surfaceY)); +} + +void QWaylandDragOfferWrapper::sendEventToWindow(struct wl_drag_offer *offer, uint32_t time, + wl_surface *surface, const QPoint &pos) +{ + QWindow *window = static_cast<QWaylandWindow *>(wl_surface_get_user_data(surface))->window(); + Qt::DropAction action = QWindowSystemInterface::handleDrag(window, &mOfferedTypes, pos); + bool accepted = (action != Qt::IgnoreAction && !mOfferedTypes.formats().isEmpty()); + if (accepted != mAccepted) { + mAccepted = accepted; + if (mAccepted) { + // What can we do, just accept the first type... + QByteArray ba = mOfferedTypes.formats().first().toLatin1(); + qDebug() << "wl_drag_offer_accept" << ba; + wl_drag_offer_accept(offer, time, ba.constData()); + } else { + qDebug() << "wl_drag_offer_reject"; + wl_drag_offer_reject(offer); + } + } + mLastEventPos = pos; +} + +void QWaylandDragOfferWrapper::drop(void *data, struct wl_drag_offer *offer) +{ + QWaylandDragOfferWrapper *self = static_cast<QWaylandDragOfferWrapper *>(data); + if (!self->mAccepted) { + wl_drag_offer_reject(offer); + return; + } + + QWaylandDrag *mgr = QWaylandDrag::instance(self->mDisplay); + QMimeData *mimeData = QWaylandDrag::instance(self->mDisplay)->platformDropData(); + mimeData->clear(); + if (mgr->mCurrentDrag) { // means this offer is the client's own + QMimeData *localData = mgr->mCurrentDrag->mimeData(); + foreach (const QString &format, localData->formats()) + mimeData->setData(format, localData->data(format)); + QWindow *window = static_cast<QWaylandWindow *>( + wl_surface_get_user_data(self->mFocusSurface))->window(); + QWindowSystemInterface::handleDrop(window, mimeData, self->mLastEventPos); + // Drag finished with drop (source == target). + QDragManager::self()->stopDrag(); + showDragPixmap(false); + delete mgr->mCurrentOffer; + qDebug() << " *** DRAG OVER WITH DROP, SOURCE == TARGET"; + } else { + // ### TODO + // This is a bit broken: The QMimeData will only contain the data for + // the first type. The Wayland protocol and QDropEvents/QMimeData do not + // match perfectly at the moment. + QString format = self->mOfferedTypes.formats().first(); + QByteArray mimeTypeBa = format.toLatin1(); + int pipefd[2]; + if (pipe(pipefd) == -1) { + qWarning("QWaylandDragOfferWrapper: pipe() failed"); + return; + } + fcntl(pipefd[0], F_SETFL, fcntl(pipefd[0], F_GETFL, 0) | O_NONBLOCK); + wl_drag_offer_receive(offer, pipefd[1]); + mgr->mPipeData.clear(); + mgr->mMimeFormat = format; + mgr->mPipeWriteEnd = pipefd[1]; + mgr->mPipeWatcher = new QSocketNotifier(pipefd[0], QSocketNotifier::Read); + QObject::connect(mgr->mPipeWatcher, SIGNAL(activated(int)), mgr, SLOT(pipeReadable(int))); + } +} + + +void QWaylandDrag::pipeReadable(int fd) +{ + if (mPipeWriteEnd) { + close(mPipeWriteEnd); + mPipeWriteEnd = 0; + } + char buf[256]; + int n; + while ((n = read(fd, &buf, sizeof buf)) > 0 || errno == EINTR) + if (n > 0) + mPipeData.append(buf, n); + if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + return; + delete mPipeWatcher; + close(fd); + + QMimeData *mimeData = platformDropData(); + mimeData->setData(mMimeFormat, mPipeData); + foreach (const QString &format, mimeData->formats()) + qDebug() << " got type" << format << "with data" << mimeData->data(format); + + QWindow *window = static_cast<QWaylandWindow *>( + wl_surface_get_user_data(mCurrentOffer->mFocusSurface))->window(); + QWindowSystemInterface::handleDrop(window, mimeData, mCurrentOffer->mLastEventPos); + + // Drag finished on target side with drop. + delete mCurrentOffer; + qDebug() << " *** DRAG OVER ON TARGET WITH DROP"; +} + +void QWaylandDrag::createDragOffer(uint32_t id) +{ + delete mCurrentOffer; + mCurrentOffer = new QWaylandDragOfferWrapper(mDisplay, mDropData, id); +} + +void QWaylandDrag::startDrag() +{ + QDragManager *manager = QDragManager::self(); + + // No need for the traditional desktop-oriented event handling in QDragManager. + manager->unmanageEvents(); + + delete mCurrentDrag; + mCurrentDrag = new QWaylandDragWrapper(mDisplay, manager->dropData()); +} diff --git a/src/plugins/platforms/wayland/qwaylanddnd.h b/src/plugins/platforms/wayland/qwaylanddnd.h new file mode 100644 index 0000000000..ebafd960ec --- /dev/null +++ b/src/plugins/platforms/wayland/qwaylanddnd.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDDND_H +#define QWAYLANDDND_H + +#include <QtGui/QPlatformDrag> +#include <QtCore/QMimeData> +#include "qwaylanddisplay.h" + +class QWaylandDragWrapper; +class QWaylandDragOfferWrapper; +class QSocketNotifier; + +class QWaylandDrag : public QObject, public QPlatformDrag +{ + Q_OBJECT + +public: + static QWaylandDrag *instance(QWaylandDisplay *display); + ~QWaylandDrag(); + void createDragOffer(uint32_t id); + + QMimeData *platformDropData(); + void startDrag(); + void move(const QMouseEvent *) { } + void drop(const QMouseEvent *) { } + void cancel() { } + +private slots: + void pipeReadable(int fd); + +private: + QWaylandDrag(QWaylandDisplay *display); + + QWaylandDisplay *mDisplay; + QMimeData *mDropData; + QWaylandDragWrapper *mCurrentDrag; + QWaylandDragOfferWrapper *mCurrentOffer; + int mPipeWriteEnd; + QSocketNotifier *mPipeWatcher; + QByteArray mPipeData; + QString mMimeFormat; + friend class QWaylandDragWrapper; + friend class QWaylandDragOfferWrapper; +}; + +#endif // QWAYLANDDND_H diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp index 3c9afafada..c1e2325766 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp @@ -113,7 +113,7 @@ void QWaylandInputDevice::inputHandleMotion(void *data, inputDevice->mSurfacePos = QPoint(surface_x, surface_y); inputDevice->mGlobalPos = QPoint(x, y); inputDevice->mTime = time; - QWindowSystemInterface::handleMouseEvent(window->widget(), + QWindowSystemInterface::handleMouseEvent(window->window(), time, inputDevice->mSurfacePos, inputDevice->mGlobalPos, @@ -155,7 +155,7 @@ void QWaylandInputDevice::inputHandleButton(void *data, inputDevice->mButtons &= ~qt_button; inputDevice->mTime = time; - QWindowSystemInterface::handleMouseEvent(window->widget(), + QWindowSystemInterface::handleMouseEvent(window->window(), time, inputDevice->mSurfacePos, inputDevice->mGlobalPos, @@ -272,7 +272,7 @@ void QWaylandInputDevice::inputHandleKey(void *data, sym = translateKey(sym, s, sizeof s); if (window) { - QWindowSystemInterface::handleKeyEvent(window->widget(), + QWindowSystemInterface::handleKeyEvent(window->window(), time, type, sym, inputDevice->mModifiers, QString::fromLatin1(s)); @@ -295,13 +295,13 @@ void QWaylandInputDevice::inputHandlePointerFocus(void *data, if (inputDevice->mPointerFocus) { window = inputDevice->mPointerFocus; - QWindowSystemInterface::handleLeaveEvent(window->widget()); + QWindowSystemInterface::handleLeaveEvent(window->window()); inputDevice->mPointerFocus = NULL; } if (surface) { window = (QWaylandWindow *) wl_surface_get_user_data(surface); - QWindowSystemInterface::handleEnterEvent(window->widget()); + QWindowSystemInterface::handleEnterEvent(window->window()); inputDevice->mPointerFocus = window; } @@ -333,7 +333,7 @@ void QWaylandInputDevice::inputHandleKeyboardFocus(void *data, if (surface) { window = (QWaylandWindow *) wl_surface_get_user_data(surface); inputDevice->mKeyboardFocus = window; - QWindowSystemInterface::handleWindowActivated(window->widget()); + QWindowSystemInterface::handleWindowActivated(window->window()); } else { inputDevice->mKeyboardFocus = NULL; QWindowSystemInterface::handleWindowActivated(0); diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.h b/src/plugins/platforms/wayland/qwaylandinputdevice.h index 008ecf144d..05ebe05969 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.h +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.h @@ -63,6 +63,7 @@ public: void attach(QWaylandBuffer *buffer, int x, int y); void handleWindowDestroyed(QWaylandWindow *window); struct wl_input_device *wl_input_device() const { return mInputDevice; } + QWaylandWindow *pointerFocus() const { return mPointerFocus; } private: QWaylandDisplay *mQDisplay; diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp index 5df71dc936..e17c2f8d95 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.cpp +++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp @@ -42,30 +42,36 @@ #include "qwaylandintegration.h" #include "qwaylanddisplay.h" -#include "qwaylandshmsurface.h" +#include "qwaylandshmbackingstore.h" #include "qwaylandshmwindow.h" #include "qwaylandnativeinterface.h" #include "qwaylandclipboard.h" +#include "qwaylanddnd.h" -#include "qgenericunixfontdatabase.h" +#include "QtPlatformSupport/private/qgenericunixfontdatabase_p.h" +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> + +#include <QtGui/private/qguiapplication_p.h> #include <QtGui/QWindowSystemInterface> #include <QtGui/QPlatformCursor> -#include <QtGui/QPlatformWindowFormat> +#include <QtGui/QSurfaceFormat> +#include <QtGui/QOpenGLContext> -#include <QtGui/private/qpixmap_raster_p.h> #ifdef QT_WAYLAND_GL_SUPPORT #include "gl_integration/qwaylandglintegration.h" -#include "gl_integration/qwaylandglwindowsurface.h" -#include <QtOpenGL/private/qpixmapdata_gl_p.h> #endif -QWaylandIntegration::QWaylandIntegration(bool useOpenGL) +QWaylandIntegration::QWaylandIntegration() : mFontDb(new QGenericUnixFontDatabase()) - , mDisplay(new QWaylandDisplay()) - , mUseOpenGL(useOpenGL) + , mEventDispatcher(createUnixEventDispatcher()) , mNativeInterface(new QWaylandNativeInterface) { + QGuiApplicationPrivate::instance()->setEventDispatcher(mEventDispatcher); + mDisplay = new QWaylandDisplay(); + + foreach (QPlatformScreen *screen, mDisplay->screens()) + screenAdded(screen); } QPlatformNativeInterface * QWaylandIntegration::nativeInterface() const @@ -73,68 +79,63 @@ QPlatformNativeInterface * QWaylandIntegration::nativeInterface() const return mNativeInterface; } -QList<QPlatformScreen *> -QWaylandIntegration::screens() const -{ - return mDisplay->screens(); -} - bool QWaylandIntegration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { case ThreadedPixmaps: return true; - case OpenGL: return hasOpenGL(); + case OpenGL: +#ifdef QT_WAYLAND_GL_SUPPORT + return true; +#else + return false; +#endif + case ThreadedOpenGL: + return hasCapability(OpenGL); default: return QPlatformIntegration::hasCapability(cap); } } -QPixmapData *QWaylandIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWindow *window) const { #ifdef QT_WAYLAND_GL_SUPPORT - if (mUseOpenGL) - return new QGLPixmapData(type); + if (window->surfaceType() == QWindow::OpenGLSurface) + return mDisplay->eglIntegration()->createEglWindow(window); #endif - return new QRasterPixmapData(type); + return new QWaylandShmWindow(window); } -QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWidget *widget, WId winId) const +QPlatformOpenGLContext *QWaylandIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - Q_UNUSED(winId); #ifdef QT_WAYLAND_GL_SUPPORT - bool useOpenGL = mUseOpenGL || (widget->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL); - if (useOpenGL) - return mDisplay->eglIntegration()->createEglWindow(widget); + return mDisplay->eglIntegration()->createPlatformOpenGLContext(context->format(), context->shareHandle()); +#else + Q_UNUSED(glFormat); + Q_UNUSED(share); + return 0; #endif - return new QWaylandShmWindow(widget); } -QWindowSurface *QWaylandIntegration::createWindowSurface(QWidget *widget, WId winId) const +QPlatformBackingStore *QWaylandIntegration::createPlatformBackingStore(QWindow *window) const { - Q_UNUSED(winId); - Q_UNUSED(winId); -#ifdef QT_WAYLAND_GL_SUPPORT - bool useOpenGL = mUseOpenGL || (widget->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL); - if (useOpenGL) - return new QWaylandGLWindowSurface(widget); -#endif - return new QWaylandShmWindowSurface(widget); + return new QWaylandShmBackingStore(window); } -QPlatformFontDatabase *QWaylandIntegration::fontDatabase() const +QAbstractEventDispatcher *QWaylandIntegration::guiThreadEventDispatcher() const { - return mFontDb; + return mEventDispatcher; } -bool QWaylandIntegration::hasOpenGL() const +QPlatformFontDatabase *QWaylandIntegration::fontDatabase() const { -#ifdef QT_WAYLAND_GL_SUPPORT - return true; -#else - return false; -#endif + return mFontDb; } QPlatformClipboard *QWaylandIntegration::clipboard() const { return QWaylandClipboard::instance(mDisplay); } + +QPlatformDrag *QWaylandIntegration::drag() const +{ + return QWaylandDrag::instance(mDisplay); +} diff --git a/src/plugins/platforms/wayland/qwaylandintegration.h b/src/plugins/platforms/wayland/qwaylandintegration.h index f617d9697b..61e8559a7d 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.h +++ b/src/plugins/platforms/wayland/qwaylandintegration.h @@ -48,18 +48,19 @@ QT_BEGIN_NAMESPACE class QWaylandBuffer; class QWaylandDisplay; +class QAbstractEventDispatcher; class QWaylandIntegration : public QPlatformIntegration { public: - QWaylandIntegration(bool useOpenGL = false); + QWaylandIntegration(); bool hasCapability(QPlatformIntegration::Capability cap) const; - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; - QList<QPlatformScreen *> screens() const; + QAbstractEventDispatcher *guiThreadEventDispatcher() const; QPlatformFontDatabase *fontDatabase() const; @@ -67,12 +68,12 @@ public: QPlatformClipboard *clipboard() const; -private: - bool hasOpenGL() const; + QPlatformDrag *drag() const; +private: QPlatformFontDatabase *mFontDb; + QAbstractEventDispatcher *mEventDispatcher; QWaylandDisplay *mDisplay; - bool mUseOpenGL; QPlatformNativeInterface *mNativeInterface; }; diff --git a/src/plugins/platforms/wayland/qwaylandnativeinterface.cpp b/src/plugins/platforms/wayland/qwaylandnativeinterface.cpp index 17736968c6..d81fa350e9 100644 --- a/src/plugins/platforms/wayland/qwaylandnativeinterface.cpp +++ b/src/plugins/platforms/wayland/qwaylandnativeinterface.cpp @@ -42,34 +42,33 @@ #include "qwaylandnativeinterface.h" #include "qwaylanddisplay.h" #include "qwaylandwindow.h" +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/QScreen> #include "windowmanager_integration/qwaylandwindowmanagerintegration.h" -#include <QtGui/private/qapplication_p.h> -#include <QDebug> - -void *QWaylandNativeInterface::nativeResourceForWidget(const QByteArray &resourceString, QWidget *widget) +void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { QByteArray lowerCaseResource = resourceString.toLower(); if (lowerCaseResource == "display") - return qPlatformScreenForWidget(widget)->display()->wl_display(); + return qPlatformScreenForWindow(window)->display()->wl_display(); if (lowerCaseResource == "surface") { - return ((QWaylandWindow *) widget->platformWindow())->wl_surface(); + return ((QWaylandWindow *) window->handle())->wl_surface(); } return NULL; } -QWaylandScreen * QWaylandNativeInterface::qPlatformScreenForWidget(QWidget *widget) +QWaylandScreen * QWaylandNativeInterface::qPlatformScreenForWindow(QWindow *window) { QWaylandScreen *screen; - if (widget) { - screen = static_cast<QWaylandScreen *>(QPlatformScreen::platformScreenForWidget(widget)); + if (window) { + screen = static_cast<QWaylandScreen *>(window->screen()->handle()); } else { - screen = static_cast<QWaylandScreen *>(QApplicationPrivate::platformIntegration()->screens()[0]); + screen = static_cast<QWaylandScreen *>(QGuiApplication::primaryScreen()->handle()); } return screen; } diff --git a/src/plugins/platforms/wayland/qwaylandnativeinterface.h b/src/plugins/platforms/wayland/qwaylandnativeinterface.h index c92b44eb03..9db442a265 100644 --- a/src/plugins/platforms/wayland/qwaylandnativeinterface.h +++ b/src/plugins/platforms/wayland/qwaylandnativeinterface.h @@ -49,8 +49,8 @@ class QWaylandNativeInterface : public QPlatformNativeInterface { public: - void *nativeResourceForWidget(const QByteArray &resourceString, - QWidget *widget); + void *nativeResourceForWindow(const QByteArray &resourceString, + QWindow *window); QVariantMap windowProperties(QPlatformWindow *window) const; QVariant windowProperty(QPlatformWindow *window, const QString &name) const; @@ -58,7 +58,7 @@ public: void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value); private: - static QWaylandScreen *qPlatformScreenForWidget(QWidget *widget); + static QWaylandScreen *qPlatformScreenForWindow(QWindow *window); private: QHash<QPlatformWindow*, QVariantMap> m_windowProperties; diff --git a/src/plugins/platforms/wayland/qwaylandscreen.cpp b/src/plugins/platforms/wayland/qwaylandscreen.cpp index be6dcb2e88..7b064bac40 100644 --- a/src/plugins/platforms/wayland/qwaylandscreen.cpp +++ b/src/plugins/platforms/wayland/qwaylandscreen.cpp @@ -53,7 +53,6 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, struct wl_output , mFormat(QImage::Format_ARGB32_Premultiplied) , mWaylandCursor(new QWaylandCursor(this)) { - moveToThread(waylandDisplay->thread()); } QWaylandScreen::~QWaylandScreen() @@ -81,9 +80,9 @@ QImage::Format QWaylandScreen::format() const return mFormat; } -QWaylandScreen * QWaylandScreen::waylandScreenFromWidget(QWidget *widget) +QWaylandScreen * QWaylandScreen::waylandScreenFromWindow(QWindow *window) { - QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWidget(widget); + QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(window); return static_cast<QWaylandScreen *>(platformScreen); } diff --git a/src/plugins/platforms/wayland/qwaylandscreen.h b/src/plugins/platforms/wayland/qwaylandscreen.h index f2b3bcefbc..9bf4f6574a 100644 --- a/src/plugins/platforms/wayland/qwaylandscreen.h +++ b/src/plugins/platforms/wayland/qwaylandscreen.h @@ -62,7 +62,7 @@ public: wl_visual *visual() const; - static QWaylandScreen *waylandScreenFromWidget(QWidget *widget); + static QWaylandScreen *waylandScreenFromWindow(QWindow *window); private: QWaylandDisplay *mWaylandDisplay; diff --git a/src/plugins/platforms/wayland/qwaylandshmsurface.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp index b24c419424..25a1b466d4 100644 --- a/src/plugins/platforms/wayland/qwaylandshmsurface.cpp +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp @@ -38,10 +38,9 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include "qwaylandshmsurface.h" +#include "qwaylandshmbackingstore.h" #include <QtCore/qdebug.h> -#include <QtGui/private/qapplication_p.h> #include "qwaylanddisplay.h" #include "qwaylandshmwindow.h" @@ -91,34 +90,34 @@ QWaylandShmBuffer::~QWaylandShmBuffer(void) wl_buffer_destroy(mBuffer); } -QWaylandShmWindowSurface::QWaylandShmWindowSurface(QWidget *window) - : QWindowSurface(window) +QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window) + : QPlatformBackingStore(window) , mBuffer(0) - , mDisplay(QWaylandScreen::waylandScreenFromWidget(window)->display()) + , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display()) { } -QWaylandShmWindowSurface::~QWaylandShmWindowSurface() +QWaylandShmBackingStore::~QWaylandShmBackingStore() { } -QPaintDevice *QWaylandShmWindowSurface::paintDevice() +QPaintDevice *QWaylandShmBackingStore::paintDevice() { return mBuffer->image(); } -void QWaylandShmWindowSurface::beginPaint(const QRegion &) +void QWaylandShmBackingStore::beginPaint(const QRegion &) { - QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->platformWindow()); + QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->handle()); Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); waylandWindow->waitForFrameSync(); } -void QWaylandShmWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QWaylandShmBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { - Q_UNUSED(widget); + Q_UNUSED(window); Q_UNUSED(offset); - QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->platformWindow()); + QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window->handle()); Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); QVector<QRect> rects = region.rects(); for (int i = 0; i < rects.size(); i++) { @@ -128,13 +127,12 @@ void QWaylandShmWindowSurface::flush(QWidget *widget, const QRegion ®ion, con } } -void QWaylandShmWindowSurface::resize(const QSize &size) +void QWaylandShmBackingStore::resize(const QSize &size, const QRegion &) { - QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->platformWindow()); + QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->handle()); Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); - QWindowSurface::resize(size); - QImage::Format format = QPlatformScreen::platformScreenForWidget(window())->format(); + QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format(); if (mBuffer != NULL && mBuffer->size() == size) return; diff --git a/src/plugins/platforms/wayland/qwaylandshmsurface.h b/src/plugins/platforms/wayland/qwaylandshmbackingstore.h index f3db8b86e5..5e6959dc2f 100644 --- a/src/plugins/platforms/wayland/qwaylandshmsurface.h +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.h @@ -39,12 +39,12 @@ ** ****************************************************************************/ -#ifndef QWINDOWSURFACE_WAYLAND_H -#define QWINDOWSURFACE_WAYLAND_H +#ifndef QWAYLANDSHMBACKINGSTORE_H +#define QWAYLANDSHMBACKINGSTORE_H #include "qwaylandbuffer.h" -#include <QtGui/private/qwindowsurface_p.h> - +#include <QtGui/QPlatformBackingStore> +#include <QtGui/QImage> #include <QtGui/QPlatformWindow> QT_BEGIN_NAMESPACE @@ -62,15 +62,15 @@ private: QImage mImage; }; -class QWaylandShmWindowSurface : public QWindowSurface +class QWaylandShmBackingStore : public QPlatformBackingStore { public: - QWaylandShmWindowSurface(QWidget *window); - ~QWaylandShmWindowSurface(); + QWaylandShmBackingStore(QWindow *window); + ~QWaylandShmBackingStore(); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - void resize(const QSize &size); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + void resize(const QSize &size, const QRegion &staticContents); void beginPaint(const QRegion &); private: diff --git a/src/plugins/platforms/wayland/qwaylandshmwindow.cpp b/src/plugins/platforms/wayland/qwaylandshmwindow.cpp index a6b7050f7a..ba5e46cab1 100644 --- a/src/plugins/platforms/wayland/qwaylandshmwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandshmwindow.cpp @@ -47,8 +47,8 @@ #include <QtCore/QDebug> -QWaylandShmWindow::QWaylandShmWindow(QWidget *widget) - : QWaylandWindow(widget) +QWaylandShmWindow::QWaylandShmWindow(QWindow *window) + : QWaylandWindow(window) { newSurfaceCreated(); } @@ -63,9 +63,3 @@ QWaylandWindow::WindowType QWaylandShmWindow::windowType() const return QWaylandWindow::Shm; } -QPlatformGLContext * QWaylandShmWindow::glContext() const -{ - qWarning("Trying to retrieve a glContext from a Raster window surface!"); - return 0; -} - diff --git a/src/plugins/platforms/wayland/qwaylandshmwindow.h b/src/plugins/platforms/wayland/qwaylandshmwindow.h index 8033703391..36f9f225b7 100644 --- a/src/plugins/platforms/wayland/qwaylandshmwindow.h +++ b/src/plugins/platforms/wayland/qwaylandshmwindow.h @@ -48,11 +48,11 @@ class QWaylandShmWindow : public QWaylandWindow { public: - QWaylandShmWindow(QWidget *widget); + QWaylandShmWindow(QWindow *window); ~QWaylandShmWindow(); WindowType windowType() const; - QPlatformGLContext *glContext() const; + QSurfaceFormat format() const { return QSurfaceFormat(); } }; #endif // QWAYLANDSHMWINDOW_H diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index 099ebabb06..6011621044 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -46,20 +46,21 @@ #include "qwaylandinputdevice.h" #include "qwaylandscreen.h" +#include <QtGui/QWindow> + #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT #include "windowmanager_integration/qwaylandwindowmanagerintegration.h" #endif #include <QCoreApplication> -#include <QtGui/QWidget> #include <QtGui/QWindowSystemInterface> #include <QDebug> -QWaylandWindow::QWaylandWindow(QWidget *window) +QWaylandWindow::QWaylandWindow(QWindow *window) : QPlatformWindow(window) , mSurface(0) - , mDisplay(QWaylandScreen::waylandScreenFromWidget(window)->display()) + , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display()) , mBuffer(0) , mWaitingForFrameSync(false) { @@ -112,11 +113,11 @@ void QWaylandWindow::configure(uint32_t time, uint32_t edges, { Q_UNUSED(time); Q_UNUSED(edges); - QRect geometry = QRect(x, y, width, height); + QRect geometry = QRect(x, y, width, height); setGeometry(geometry); - QWindowSystemInterface::handleGeometryChange(widget(), geometry); + QWindowSystemInterface::handleGeometryChange(window(), geometry); } void QWaylandWindow::attach(QWaylandBuffer *buffer) @@ -124,6 +125,7 @@ void QWaylandWindow::attach(QWaylandBuffer *buffer) mBuffer = buffer; if (mSurface) { wl_surface_attach(mSurface, buffer->buffer(),0,0); + QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRect(QPoint(), geometry().size())); } } diff --git a/src/plugins/platforms/wayland/qwaylandwindow.h b/src/plugins/platforms/wayland/qwaylandwindow.h index b91f6b6eb8..4f1e2c8183 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.h +++ b/src/plugins/platforms/wayland/qwaylandwindow.h @@ -59,7 +59,7 @@ public: Egl }; - QWaylandWindow(QWidget *window); + QWaylandWindow(QWindow *window); ~QWaylandWindow(); virtual WindowType windowType() const = 0; diff --git a/src/plugins/platforms/wayland/wayland.pro b/src/plugins/platforms/wayland/wayland.pro index 1e0bbe6cdd..fd6ffc06de 100644 --- a/src/plugins/platforms/wayland/wayland.pro +++ b/src/plugins/platforms/wayland/wayland.pro @@ -1,19 +1,23 @@ TARGET = qwayland load(qt_plugin) -QT+=gui-private core-private opengl-private +CONFIG += qpa/genericunixfontdatabase DESTDIR = $$QT.gui.plugins/platforms DEFINES += Q_PLATFORM_WAYLAND DEFINES += $$QMAKE_DEFINES_WAYLAND -QT += core-private gui-private opengl-private +mac { + DEFINES += QT_NO_WAYLAND_XKB +} + +QT += core-private gui-private opengl-private platformsupport-private SOURCES = main.cpp \ qwaylandintegration.cpp \ qwaylandnativeinterface.cpp \ - qwaylandshmsurface.cpp \ + qwaylandshmbackingstore.cpp \ qwaylandinputdevice.cpp \ qwaylandcursor.cpp \ qwaylanddisplay.cpp \ @@ -21,6 +25,7 @@ SOURCES = main.cpp \ qwaylandscreen.cpp \ qwaylandshmwindow.cpp \ qwaylandclipboard.cpp \ + qwaylanddnd.cpp \ qwaylandmime.cpp HEADERS = qwaylandintegration.h \ @@ -29,23 +34,23 @@ HEADERS = qwaylandintegration.h \ qwaylanddisplay.h \ qwaylandwindow.h \ qwaylandscreen.h \ - qwaylandshmsurface.h \ + qwaylandshmbackingstore.h \ qwaylandbuffer.h \ qwaylandshmwindow.h \ qwaylandclipboard.h \ + qwaylanddnd.h \ qwaylandmime.h INCLUDEPATH += $$QMAKE_INCDIR_WAYLAND LIBS += $$QMAKE_LIBS_WAYLAND -QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_WAYLAND - -INCLUDEPATH += $$PWD +mac { + LIBS += -lwayland-client +} -include ($$PWD/gl_integration/gl_integration.pri) -include ($$PWD/windowmanager_integration/windowmanager_integration.pri) - -include (../fontdatabases/genericunix/genericunix.pri) +QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_WAYLAND target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target +include ($$PWD/gl_integration/gl_integration.pri) +include ($$PWD/windowmanager_integration/windowmanager_integration.pri) diff --git a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp index 798900bbce..7d68571c24 100644 --- a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp +++ b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp @@ -49,8 +49,7 @@ #include <QtGui/QPlatformNativeInterface> #include <QtGui/QPlatformWindow> #include <QtGui/QtEvents> -#include <QtGui/QWidget> -#include <QtGui/QApplication> +#include <QtGui/QGuiApplication> #include <QDebug> @@ -237,15 +236,15 @@ void QWaylandWindowManagerIntegration::wlHandleWindowPropertyChange(void *data, QPlatformNativeInterface *nativeInterface = qApp->platformNativeInterface(); QWaylandWindowManagerIntegration *inst = QWaylandWindowManagerIntegration::instance(); - QWidgetList widgets = qApp->topLevelWidgets(); - foreach (QWidget *widget, widgets) { - QPlatformWindow *platformWindowForWidget = widget->platformWindow(); - if (!platformWindowForWidget) + QList<QWindow *> windows = qApp->topLevelWindows(); + foreach (QWindow *window, windows) { + QPlatformWindow *platformWindowForWindow = window->handle(); + if (!platformWindowForWindow) continue; - QWaylandWindow *window = static_cast<QWaylandWindow*>(platformWindowForWidget); - wl_surface *windowSurface = (wl_surface*)nativeInterface->nativeResourceForWidget(QByteArray("surface"), widget); + QWaylandWindow *waylandWindow = static_cast<QWaylandWindow*>(platformWindowForWindow); + wl_surface *windowSurface = (wl_surface*)nativeInterface->nativeResourceForWindow(QByteArray("surface"), window); if (windowSurface == surface) { - inst->handleWindowPropertyChange(window, QString(propertyName), variantValue); + inst->handleWindowPropertyChange(waylandWindow, QString(propertyName), variantValue); break; } } diff --git a/src/plugins/platforms/windows/array.h b/src/plugins/platforms/windows/array.h new file mode 100644 index 0000000000..216f1e8945 --- /dev/null +++ b/src/plugins/platforms/windows/array.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ARRAY_H +#define ARRAY_H + +#include <QtCore/QtAlgorithms> + +QT_BEGIN_NAMESPACE + +/* A simple, non-shared array. */ + +template <class T> +class Array +{ + Q_DISABLE_COPY(Array) +public: + enum { initialSize = 5 }; + + typedef T* const_iterator; + + explicit Array(size_t size= 0) : data(0), m_capacity(0), m_size(0) + { if (size) resize(size); } + ~Array() { delete [] data; } + + T *data; + inline size_t size() const { return m_size; } + inline const_iterator begin() const { return data; } + inline const_iterator end() const { return data + m_size; } + + inline void append(const T &value) + { + const size_t oldSize = m_size; + resize(m_size + 1); + data[oldSize] = value; + } + + inline void resize(size_t size) + { + if (size > m_size) + reserve(size > 1 ? size + size / 2 : size_t(initialSize)); + m_size = size; + } + + void reserve(size_t capacity) + { + if (capacity > m_capacity) { + const T *oldData = data; + data = new T[capacity]; + if (oldData) { + qCopy(oldData, oldData + m_size, data); + delete [] oldData; + } + m_capacity = capacity; + } + } + +private: + size_t m_capacity; + size_t m_size; +}; + +QT_END_NAMESPACE + +#endif // ARRAY_H diff --git a/src/plugins/decorations/default/main.cpp b/src/plugins/platforms/windows/main.cpp index b93b6f8b0e..933aa76df8 100644 --- a/src/plugins/decorations/default/main.cpp +++ b/src/plugins/platforms/windows/main.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Contact: Nokia Corporation (info@qt.nokia.com) ** ** This file is part of the plugins of the Qt Toolkit. ** @@ -39,38 +39,74 @@ ** ****************************************************************************/ -#include <qdecorationplugin_qws.h> -#include <qdecorationdefault_qws.h> + +#include <QtGui/QPlatformIntegrationPlugin> +#include <QtCore/QStringList> + +#include "qwindowsintegration.h" QT_BEGIN_NAMESPACE -class DecorationDefault : public QDecorationPlugin +/*! + \group qt-lighthouse-win + \title Qt Lighthouse plugin for Windows + + \brief Class documentation of the Qt Lighthouse plugin for Windows. + + \section1 Tips + + \list + \o The environment variable \c QT_LIGHTHOUSE_WINDOWS_VERBOSE controls + the debug level. It takes the form + \c{<keyword1>:<level1>,<keyword2>:<level2>}, where + keyword is one of \c integration, \c windows, \c backingstore and + \c fonts. Level is an integer 0..9. + \endlist + */ + +/*! + \class QWindowsIntegrationPlugin + \brief Plugin. + \ingroup qt-lighthouse-win + */ + +/*! + \namespace QtWindows + + \brief Namespace for enumerations, etc. + \ingroup qt-lighthouse-win +*/ + +/*! + \enum QtWindows::WindowsEventType + + \brief Enumerations for WM_XX events. + + With flags that should help to structure the code. + + \ingroup qt-lighthouse-win +*/ + +class QWindowsIntegrationPlugin : public QPlatformIntegrationPlugin { public: - DecorationDefault(); - QStringList keys() const; - QDecoration *create(const QString&); + QPlatformIntegration *create(const QString&, const QStringList&); }; -DecorationDefault::DecorationDefault() - : QDecorationPlugin() +QStringList QWindowsIntegrationPlugin::keys() const { + return QStringList(QStringLiteral("windows")); } -QStringList DecorationDefault::keys() const +QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList) { - return (QStringList() << QLatin1String("Default")); -} - -QDecoration* DecorationDefault::create(const QString& s) -{ - if (s.toLower() == QLatin1String("default")) - return new QDecorationDefault(); - + Q_UNUSED(paramList); + if (system.compare(system, QStringLiteral("windows"), Qt::CaseInsensitive) == 0) + return new QWindowsIntegration; return 0; } -Q_EXPORT_PLUGIN2(qdecorationdefault, DecorationDefault) +Q_EXPORT_PLUGIN2(windows, QWindowsIntegrationPlugin) QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/pixmaputils.cpp b/src/plugins/platforms/windows/pixmaputils.cpp new file mode 100644 index 0000000000..111df5a4b9 --- /dev/null +++ b/src/plugins/platforms/windows/pixmaputils.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pixmaputils.h" + +#include <QtGui/QBitmap> +#include <QtGui/QImage> +#include <QtGui/QPlatformPixmap> +#include <QtGui/private/qpixmap_raster_p.h> + +#include <QtCore/QScopedArrayPointer> +#include <QtCore/QDebug> + +#include <string.h> + +QT_BEGIN_NAMESPACE + +HBITMAP createIconMask(const QBitmap &bitmap) +{ + QImage bm = bitmap.toImage().convertToFormat(QImage::Format_Mono); + const int w = bm.width(); + const int h = bm.height(); + const int bpl = ((w+15)/16)*2; // bpl, 16 bit alignment + QScopedArrayPointer<uchar> bits(new uchar[bpl * h]); + bm.invertPixels(); + for (int y = 0; y < h; ++y) + memcpy(bits.data() + y * bpl, bm.scanLine(y), bpl); + HBITMAP hbm = CreateBitmap(w, h, 1, 1, bits.data()); + return hbm; +} + +HBITMAP qPixmapToWinHBITMAP(const QPixmap &p, HBitmapFormat format) +{ + if (p.isNull()) + return 0; + + HBITMAP bitmap = 0; + if (p.handle()->classId() != QPlatformPixmap::RasterClass) { + QRasterPlatformPixmap *data = new QRasterPlatformPixmap(p.depth() == 1 ? + QRasterPlatformPixmap::BitmapType : QRasterPlatformPixmap::PixmapType); + data->fromImage(p.toImage(), Qt::AutoColor); + return qPixmapToWinHBITMAP(QPixmap(data), format); + } + + QRasterPlatformPixmap *d = static_cast<QRasterPlatformPixmap*>(p.handle()); + const QImage *rasterImage = d->buffer(); + const int w = rasterImage->width(); + const int h = rasterImage->height(); + + HDC display_dc = GetDC(0); + + // Define the header + BITMAPINFO bmi; + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = w; + bmi.bmiHeader.biHeight = -h; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = w * h * 4; + + // Create the pixmap + uchar *pixels = 0; + bitmap = CreateDIBSection(display_dc, &bmi, DIB_RGB_COLORS, (void **) &pixels, 0, 0); + ReleaseDC(0, display_dc); + if (!bitmap) { + qErrnoWarning("%s, failed to create dibsection", __FUNCTION__); + return 0; + } + if (!pixels) { + qErrnoWarning("%s, did not allocate pixel data", __FUNCTION__); + return 0; + } + + // Copy over the data + QImage::Format imageFormat = QImage::Format_ARGB32; + if (format == HBitmapAlpha) + imageFormat = QImage::Format_RGB32; + else if (format == HBitmapPremultipliedAlpha) + imageFormat = QImage::Format_ARGB32_Premultiplied; + const QImage image = rasterImage->convertToFormat(imageFormat); + const int bytes_per_line = w * 4; + for (int y=0; y < h; ++y) + memcpy(pixels + y * bytes_per_line, image.scanLine(y), bytes_per_line); + + return bitmap; +} + +QPixmap qPixmapFromWinHBITMAP(HBITMAP bitmap, HBitmapFormat format) +{ + // Verify size + BITMAP bitmap_info; + memset(&bitmap_info, 0, sizeof(BITMAP)); + + const int res = GetObject(bitmap, sizeof(BITMAP), &bitmap_info); + if (!res) { + qErrnoWarning("QPixmap::fromWinHBITMAP(), failed to get bitmap info"); + return QPixmap(); + } + const int w = bitmap_info.bmWidth; + const int h = bitmap_info.bmHeight; + + BITMAPINFO bmi; + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = w; + bmi.bmiHeader.biHeight = -h; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = w * h * 4; + + // Get bitmap bits + QScopedArrayPointer<uchar> data(new uchar[bmi.bmiHeader.biSizeImage]); + HDC display_dc = GetDC(0); + if (!GetDIBits(display_dc, bitmap, 0, h, data.data(), &bmi, DIB_RGB_COLORS)) { + ReleaseDC(0, display_dc); + qWarning("%s, failed to get bitmap bits", __FUNCTION__); + return QPixmap(); + } + + QImage::Format imageFormat = QImage::Format_ARGB32_Premultiplied; + uint mask = 0; + if (format == HBitmapNoAlpha) { + imageFormat = QImage::Format_RGB32; + mask = 0xff000000; + } + + // Create image and copy data into image. + QImage image(w, h, imageFormat); + if (image.isNull()) { // failed to alloc? + ReleaseDC(0, display_dc); + qWarning("%s, failed create image of %dx%d", __FUNCTION__, w, h); + return QPixmap(); + } + const int bytes_per_line = w * sizeof(QRgb); + for (int y = 0; y < h; ++y) { + QRgb *dest = (QRgb *) image.scanLine(y); + const QRgb *src = (const QRgb *) (data.data() + y * bytes_per_line); + for (int x = 0; x < w; ++x) { + const uint pixel = src[x]; + if ((pixel & 0xff000000) == 0 && (pixel & 0x00ffffff) != 0) + dest[x] = pixel | 0xff000000; + else + dest[x] = pixel | mask; + } + } + ReleaseDC(0, display_dc); + return QPixmap::fromImage(image); +} + +HICON qPixmapToWinHICON(const QPixmap &p) +{ + QBitmap maskBitmap = p.mask(); + if (maskBitmap.isNull()) { + maskBitmap = QBitmap(p.size()); + maskBitmap.fill(Qt::color1); + } + + ICONINFO ii; + ii.fIcon = true; + ii.hbmMask = createIconMask(maskBitmap); + ii.hbmColor = qPixmapToWinHBITMAP(p, HBitmapAlpha); + ii.xHotspot = 0; + ii.yHotspot = 0; + + HICON hIcon = CreateIconIndirect(&ii); + + DeleteObject(ii.hbmColor); + DeleteObject(ii.hbmMask); + + return hIcon; +} + +static QImage qImageFromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h) +{ + BITMAPINFO bmi; + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = w; + bmi.bmiHeader.biHeight = -h; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = w * h * 4; + + QImage image(w, h, QImage::Format_ARGB32_Premultiplied); + if (image.isNull()) + return image; + + // Get bitmap bits + QScopedPointer<uchar> data(new uchar [bmi.bmiHeader.biSizeImage]); + if (!GetDIBits(hdc, bitmap, 0, h, data.data(), &bmi, DIB_RGB_COLORS)) { + qErrnoWarning("%s: failed to get bitmap bits", __FUNCTION__); + return QImage(); + } + // Create image and copy data into image. + for (int y = 0; y < h; ++y) { + void *dest = (void *) image.scanLine(y); + void *src = data.data() + y * image.bytesPerLine(); + memcpy(dest, src, image.bytesPerLine()); + } + return image; +} + +QPixmap qPixmapFromWinHICON(HICON icon) +{ + bool foundAlpha = false; + HDC screenDevice = GetDC(0); + HDC hdc = CreateCompatibleDC(screenDevice); + ReleaseDC(0, screenDevice); + + ICONINFO iconinfo; + const bool result = GetIconInfo(icon, &iconinfo); //x and y Hotspot describes the icon center + if (!result) { + qErrnoWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()"); + return QPixmap(); + } + + const int w = iconinfo.xHotspot * 2; + const int h = iconinfo.yHotspot * 2; + + BITMAPINFOHEADER bitmapInfo; + bitmapInfo.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.biWidth = w; + bitmapInfo.biHeight = h; + bitmapInfo.biPlanes = 1; + bitmapInfo.biBitCount = 32; + bitmapInfo.biCompression = BI_RGB; + bitmapInfo.biSizeImage = 0; + bitmapInfo.biXPelsPerMeter = 0; + bitmapInfo.biYPelsPerMeter = 0; + bitmapInfo.biClrUsed = 0; + bitmapInfo.biClrImportant = 0; + DWORD* bits; + + HBITMAP winBitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS, (VOID**)&bits, NULL, 0); + HGDIOBJ oldhdc = (HBITMAP)SelectObject(hdc, winBitmap); + DrawIconEx( hdc, 0, 0, icon, iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 0, 0, DI_NORMAL); + QImage image = qImageFromWinHBITMAP(hdc, winBitmap, w, h); + + for (int y = 0 ; y < h && !foundAlpha ; y++) { + const QRgb *scanLine= reinterpret_cast<const QRgb *>(image.scanLine(y)); + for (int x = 0; x < w ; x++) { + if (qAlpha(scanLine[x]) != 0) { + foundAlpha = true; + break; + } + } + } + if (!foundAlpha) { + //If no alpha was found, we use the mask to set alpha values + DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_MASK); + const QImage mask = qImageFromWinHBITMAP(hdc, winBitmap, w, h); + + for (int y = 0 ; y < h ; y++){ + QRgb *scanlineImage = reinterpret_cast<QRgb *>(image.scanLine(y)); + const QRgb *scanlineMask = mask.isNull() ? 0 : reinterpret_cast<const QRgb *>(mask.scanLine(y)); + for (int x = 0; x < w ; x++){ + if (scanlineMask && qRed(scanlineMask[x]) != 0) + scanlineImage[x] = 0; //mask out this pixel + else + scanlineImage[x] |= 0xff000000; // set the alpha channel to 255 + } + } + } + //dispose resources created by iconinfo call + DeleteObject(iconinfo.hbmMask); + DeleteObject(iconinfo.hbmColor); + + SelectObject(hdc, oldhdc); //restore state + DeleteObject(winBitmap); + DeleteDC(hdc); + return QPixmap::fromImage(image); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/pixmaputils.h b/src/plugins/platforms/windows/pixmaputils.h new file mode 100644 index 0000000000..bf94a2695c --- /dev/null +++ b/src/plugins/platforms/windows/pixmaputils.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PIXMAPUTILS_H +#define PIXMAPUTILS_H + +#include "qtwindows_additional.h" + +#include <QtCore/QtGlobal> + +QT_BEGIN_NAMESPACE + +class QBitmap; +class QPixmap; + +enum HBitmapFormat +{ + HBitmapNoAlpha, + HBitmapPremultipliedAlpha, + HBitmapAlpha +}; + +HBITMAP createIconMask(const QBitmap &bitmap); + +HBITMAP qPixmapToWinHBITMAP(const QPixmap &p, HBitmapFormat format); +HICON qPixmapToWinHICON(const QPixmap &p); + +QPixmap qPixmapFromWinHBITMAP(HBITMAP bitmap, HBitmapFormat format); +QPixmap qPixmapFromWinHICON(HICON icon); + +QT_END_NAMESPACE + +#endif // PIXMAPUTILS_H diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h new file mode 100644 index 0000000000..e262159b7b --- /dev/null +++ b/src/plugins/platforms/windows/qtwindows_additional.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTWINDOWS_ADDITIONAL_H +#define QTWINDOWS_ADDITIONAL_H + +#include <QtCore/QtGlobal> // get compiler define +#include <QtCore/qt_windows.h> + +/* Complement the definitions and declarations missing + * when using MinGW or older Windows SDKs. */ + +#if defined(Q_CC_MINGW) +# if !defined(ULW_ALPHA) +# define ULW_ALPHA 0x00000002 +# define LWA_ALPHA 0x00000002 +# endif // !defined(ULW_ALPHA) +# define SPI_GETFONTSMOOTHINGTYPE 0x200A +# define FE_FONTSMOOTHINGCLEARTYPE 0x0002 +# define CLEARTYPE_QUALITY 5 + +# define CF_DIBV5 17 + +#define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L) + +typedef struct tagUPDATELAYEREDWINDOWINFO { + DWORD cbSize; + HDC hdcDst; + const POINT *pptDst; + const SIZE *psize; + HDC hdcSrc; + const POINT *pptSrc; + COLORREF crKey; + const BLENDFUNCTION *pblend; + DWORD dwFlags; + const RECT *prcDirty; +} UPDATELAYEREDWINDOWINFO, *PUPDATELAYEREDWINDOWINFO; + +// OpenGL Pixelformat flags. +#define PFD_SUPPORT_DIRECTDRAW 0x00002000 +#define PFD_DIRECT3D_ACCELERATED 0x00004000 +#define PFD_SUPPORT_COMPOSITION 0x00008000 + +// IME. +#define IMR_CONFIRMRECONVERTSTRING 0x0005 + +#endif // if defined(Q_CC_MINGW) + +/* Touch is supported from Windows 7 onwards and data structures + * are present in the Windows SDK's, but not in older MSVC Express + * versions. */ + +#if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE) + +#define WM_TOUCH 0x0240 + +typedef struct tagTOUCHINPUT { + LONG x; + LONG y; + HANDLE hSource; + DWORD dwID; + DWORD dwFlags; + DWORD dwMask; + DWORD dwTime; + ULONG_PTR dwExtraInfo; + DWORD cxContact; + DWORD cyContact; +} TOUCHINPUT, *PTOUCHINPUT; +typedef TOUCHINPUT const * PCTOUCHINPUT; + +# define TOUCHEVENTF_MOVE 0x0001 +# define TOUCHEVENTF_DOWN 0x0002 +# define TOUCHEVENTF_UP 0x0004 +# define TOUCHEVENTF_INRANGE 0x0008 +# define TOUCHEVENTF_PRIMARY 0x0010 +# define TOUCHEVENTF_NOCOALESCE 0x0020 +# define TOUCHEVENTF_PALM 0x0080 +# define TOUCHINPUTMASKF_CONTACTAREA 0x0004 +# define TOUCHINPUTMASKF_EXTRAINFO 0x0002 + +#endif // if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE) + +#endif // QTWINDOWS_ADDITIONAL_H diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h new file mode 100644 index 0000000000..692489dfc6 --- /dev/null +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTWINDOWSGLOBAL_H +#define QTWINDOWSGLOBAL_H + +#include "qtwindows_additional.h" +#include <QtCore/qnamespace.h> + +QT_BEGIN_NAMESPACE + +namespace QtWindows +{ + +enum +{ + WindowEventFlag = 0x10000, + MouseEventFlag = 0x20000, + NonClientEventFlag = 0x40000, + InputMethodEventFlag = 0x80000, + KeyEventFlag = 0x100000, + KeyDownEventFlag = 0x200000, + TouchEventFlag = 0x400000, + ClipboardEventFlag = 0x800000, + ApplicationEventFlag = 0x1000000 +}; + +enum WindowsEventType // Simplify event types +{ + ExposeEvent = WindowEventFlag + 1, + ActivateWindowEvent = WindowEventFlag + 2, + DeactivateWindowEvent = WindowEventFlag + 3, + LeaveEvent = WindowEventFlag + 5, + CloseEvent = WindowEventFlag + 6, + ShowEvent = WindowEventFlag + 7, + HideEvent = WindowEventFlag + 8, + DestroyEvent = WindowEventFlag + 9, + MoveEvent = WindowEventFlag + 10, + ResizeEvent = WindowEventFlag + 12, + QuerySizeHints = WindowEventFlag + 15, + CalculateSize = WindowEventFlag + 16, + MouseEvent = MouseEventFlag + 1, + MouseWheelEvent = MouseEventFlag + 2, + TouchEvent = TouchEventFlag + 1, + NonClientMouseEvent = NonClientEventFlag + MouseEventFlag + 1, + KeyEvent = KeyEventFlag + 1, + KeyDownEvent = KeyEventFlag + KeyDownEventFlag + 1, + InputMethodKeyEvent = InputMethodEventFlag + KeyEventFlag + 1, + InputMethodKeyDownEvent = InputMethodEventFlag + KeyEventFlag + KeyDownEventFlag + 1, + ClipboardEvent = ClipboardEventFlag + 1, + ActivateApplicationEvent = ApplicationEventFlag + 1, + DeactivateApplicationEvent = ApplicationEventFlag + 2, + InputMethodStartCompositionEvent = InputMethodEventFlag + 1, + InputMethodCompositionEvent = InputMethodEventFlag + 2, + InputMethodEndCompositionEvent = InputMethodEventFlag + 3, + InputMethodOpenCandidateWindowEvent = InputMethodEventFlag + 4, + InputMethodCloseCandidateWindowEvent = InputMethodEventFlag + 5, + InputMethodRequest = InputMethodEventFlag + 6, + UnknownEvent = 542 +}; + +} // namespace QtWindows + +inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn) +{ + switch (message) { + case WM_PAINT: + case WM_ERASEBKGND: + return QtWindows::ExposeEvent; + case WM_CLOSE: + return QtWindows::CloseEvent; + case WM_DESTROY: + return QtWindows::DestroyEvent; + case WM_ACTIVATEAPP: + return (int)wParamIn ? + QtWindows::ActivateApplicationEvent : QtWindows::DeactivateApplicationEvent; + case WM_ACTIVATE: + return LOWORD(wParamIn) == WA_INACTIVE ? + QtWindows::DeactivateWindowEvent : QtWindows::ActivateWindowEvent; + case WM_MOUSELEAVE: + return QtWindows::MouseEvent; + case WM_MOUSEWHEEL: + case WM_MOUSEHWHEEL: + return QtWindows::MouseWheelEvent; + case WM_MOVE: + return QtWindows::MoveEvent; + case WM_SHOWWINDOW: + return wParamIn ? QtWindows::ShowEvent : QtWindows::HideEvent; + case WM_SIZE: + return QtWindows::ResizeEvent; + case WM_NCCALCSIZE: + return QtWindows::CalculateSize; + case WM_GETMINMAXINFO: + return QtWindows::QuerySizeHints; + case WM_KEYDOWN: // keyboard event + case WM_SYSKEYDOWN: + return QtWindows::KeyDownEvent; + case WM_KEYUP: + case WM_SYSKEYUP: + case WM_CHAR: + return QtWindows::KeyEvent; + case WM_IME_CHAR: + return QtWindows::InputMethodKeyEvent; + case WM_IME_KEYDOWN: + return QtWindows::InputMethodKeyDownEvent; + case WM_TOUCH: + return QtWindows::TouchEvent; + case WM_CHANGECBCHAIN: + case WM_DRAWCLIPBOARD: + case WM_RENDERFORMAT: + case WM_RENDERALLFORMATS: + case WM_DESTROYCLIPBOARD: + return QtWindows::ClipboardEvent; + case WM_IME_STARTCOMPOSITION: + return QtWindows::InputMethodStartCompositionEvent; + case WM_IME_ENDCOMPOSITION: + return QtWindows::InputMethodEndCompositionEvent; + case WM_IME_COMPOSITION: + return QtWindows::InputMethodCompositionEvent; + case WM_IME_REQUEST: + return QtWindows::InputMethodRequest; + case WM_IME_NOTIFY: + switch (int(wParamIn)) { + case IMN_OPENCANDIDATE: + return QtWindows::InputMethodOpenCandidateWindowEvent; + case IMN_CLOSECANDIDATE: + return QtWindows::InputMethodCloseCandidateWindowEvent; + default: + break; + } + default: + break; + } + if (message >= WM_NCMOUSEMOVE && message <= WM_NCMBUTTONDBLCLK) + return QtWindows::NonClientMouseEvent; // + if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) + || (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK)) + return QtWindows::MouseEvent; + return QtWindows::UnknownEvent; +} + +QT_END_NAMESPACE + +#endif // QTWINDOWSGLOBAL_H diff --git a/src/plugins/platforms/windows/qwindows.qdocconf b/src/plugins/platforms/windows/qwindows.qdocconf new file mode 100644 index 0000000000..c5a1ee904a --- /dev/null +++ b/src/plugins/platforms/windows/qwindows.qdocconf @@ -0,0 +1,27 @@ +project = "Qt Windows Lighthouse Plugin" +description = "Documentation of the Qt Windows Lighthouse Plugin" + +language = Cpp + +headerdirs = . + +sourcedirs = . + +showinternal = true + +headers.fileextensions = "*.h" +sources.fileextensions = "*.cpp *.qdoc" + +outputdir = doc + +qhp.projects = QtLighthouseWindows +qhp.QtLighthouseWindowsDev.file = qtlighthousewindows-dev.qhp +qhp.QtLighthouseWindowsDev.namespace = com.nokia.qt.developer.lighthouse +qhp.QtLighthouseWindowsDev.virtualFolder = doc +qhp.QtLighthouseWindowsDev.indexTitle = Qt Windows Lighthouse Plugin +qhp.QtLighthouseWindowsDev.indexRoot = + +# Doxygen compatibility commands + +macro.see = "\\sa" +macro.function = "\\fn" diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp new file mode 100644 index 0000000000..a3698c4a7c --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsbackingstore.h" +#include "qwindowswindow.h" +#include "qwindowsnativeimage.h" +#include "qwindowscontext.h" + +#include <QtGui/QWindow> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsBackingStore + \brief Backing store for windows. + \ingroup qt-lighthouse-win +*/ + +QWindowsBackingStore::QWindowsBackingStore(QWindow *window) : + QPlatformBackingStore(window) +{ + if (QWindowsContext::verboseBackingStore) + qDebug() << __FUNCTION__ << this << window; +} + +QWindowsBackingStore::~QWindowsBackingStore() +{ + if (QWindowsContext::verboseBackingStore) + qDebug() << __FUNCTION__ << this; +} + +QPaintDevice *QWindowsBackingStore::paintDevice() +{ + Q_ASSERT(!m_image.isNull()); + return &m_image->image(); +} + +void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, + const QPoint &offset) +{ + // TODO: Prepare paint for translucent windows. + const QRect br = region.boundingRect(); + if (QWindowsContext::verboseBackingStore > 1) + qDebug() << __FUNCTION__ << window << offset << br; + QWindowsWindow *rw = rasterWindow(); + const HDC dc = rw->getDC(); + if (!dc) { + qErrnoWarning("%s: GetDC failed", __FUNCTION__); + return; + } + + if (!BitBlt(dc, br.x(), br.y(), br.width(), br.height(), + m_image->hdc(), br.x() + offset.x(), br.y() + offset.y(), SRCCOPY)) + qErrnoWarning("%s: BitBlt failed", __FUNCTION__); + rw->releaseDC(); + // Write image for debug purposes. + if (QWindowsContext::verboseBackingStore > 2) { + static int n = 0; + const QString fileName = QString::fromAscii("win%1_%2.png"). + arg(rw->winId()).arg(n++); + m_image->image().save(fileName); + qDebug() << "Wrote " << m_image->image().size() << fileName; + } +} + +void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) +{ + if (m_image.isNull() || m_image->image().size() != size) { + if (QWindowsContext::verboseBackingStore) { + QDebug nsp = qDebug().nospace(); + nsp << __FUNCTION__ << ' ' << rasterWindow()->window() + << ' ' << size << ' ' << region; + if (!m_image.isNull()) + nsp << " from: " << m_image->image().size(); + } + m_image.reset(new QWindowsNativeImage(size.width(), size.height(), + QWindowsNativeImage::systemFormat())); + } +} + +void QWindowsBackingStore::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); + if (QWindowsContext::verboseBackingStore > 1) + qDebug() << __FUNCTION__; +} + +QWindowsWindow *QWindowsBackingStore::rasterWindow() const +{ + if (const QWindow *w = window()) + if (QPlatformWindow *pw = w->handle()) + return static_cast<QWindowsWindow *>(pw); + return 0; +} + +HDC QWindowsBackingStore::getDC() const +{ + if (!m_image.isNull()) + return m_image->hdc(); + return 0; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h new file mode 100644 index 0000000000..53f033d14b --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSBACKINGSTORE_H +#define QWINDOWSBACKINGSTORE_H + +#include "qtwindows_additional.h" + +#include <QtGui/QPlatformBackingStore> +#include <QtCore/QScopedPointer> + +QT_BEGIN_NAMESPACE + +class QWindowsWindow; +class QWindowsNativeImage; + +class QWindowsBackingStore : public QPlatformBackingStore +{ + Q_DISABLE_COPY(QWindowsBackingStore) +public: + QWindowsBackingStore(QWindow *window); + ~QWindowsBackingStore(); + + virtual QPaintDevice *paintDevice(); + virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + virtual void resize(const QSize &size, const QRegion &r); + virtual void beginPaint(const QRegion &); + + HDC getDC() const; + +private: + QWindowsWindow *rasterWindow() const; + + QScopedPointer<QWindowsNativeImage> m_image; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSBACKINGSTORE_H diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp new file mode 100644 index 0000000000..93063441ba --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -0,0 +1,366 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsclipboard.h" +#include "qwindowscontext.h" +#include "qwindowsole.h" +#include "qwindowsmime.h" +#include "qwindowsguieventdispatcher.h" + +#include <QtGui/QGuiApplication> +#include <QtGui/QClipboard> +#include <QtGui/QColor> +#include <QtGui/QImage> + +#include <QtCore/QDebug> +#include <QtCore/QMimeData> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +static const char formatTextPlainC[] = "text/plain"; +static const char formatTextHtmlC[] = "text/html"; + +/*! + \class QWindowsClipboard + \brief Clipboard implementation. + + Registers a non-visible clipboard viewer window that + receives clipboard events in its own window procedure to be + able to receive clipboard-changed events, which + QPlatformClipboard needs to emit. That requires housekeeping + of the next in the viewer chain. + + \note The OLE-functions used in this class require OleInitialize(). + + \ingroup qt-lighthouse-win +*/ + +QDebug operator<<(QDebug d, const QMimeData &m) +{ + QDebug nospace = d.nospace(); + const QStringList formats = m.formats(); + nospace << "QMimeData: " << formats.join(QStringLiteral(", ")) << '\n' + << " Text=" << m.hasText() << " HTML=" << m.hasHtml() + << " Color=" << m.hasColor() << " Image=" << m.hasImage() + << " URLs=" << m.hasUrls() << '\n'; + if (m.hasText()) + nospace << " Text: '" << m.text() << "'\n"; + if (m.hasHtml()) + nospace << " HTML: '" << m.html() << "'\n"; + if (m.hasColor()) + nospace << " Color: " << qvariant_cast<QColor>(m.colorData()) << '\n'; + if (m.hasImage()) + nospace << " Image: " << qvariant_cast<QImage>(m.imageData()).size() << '\n'; + if (m.hasUrls()) + nospace << " URLs: " << m.urls() << '\n'; + return d; +} + +/*! + \class QWindowsInternalMimeDataBase + \brief Base for implementations of QInternalMimeData using a IDataObject COM object. + + In clipboard handling and Drag and drop, static instances + of QInternalMimeData implementations are kept and passed to the client. + + QInternalMimeData provides virtuals that query the formats and retrieve + mime data on demand when the client invokes functions like QMimeData::hasHtml(), + QMimeData::html() on the instance returned. Otherwise, expensive + construction of a new QMimeData object containing all possible + formats would have to be done in each call to mimeData(). + + The base class introduces new virtuals to obtain and release + the instances IDataObject from the clipboard or Drag and Drop and + does conversion using QWindowsMime classes. + + \sa QInternalMimeData, QWindowsMime, QWindowsMimeConverter + \ingroup qt-lighthouse-win +*/ + +bool QWindowsInternalMimeData::hasFormat_sys(const QString &mime) const +{ + IDataObject *pDataObj = retrieveDataObject(); + if (!pDataObj) + return false; + + const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); + const bool has = mc.converterToMime(mime, pDataObj) != 0; + releaseDataObject(pDataObj); + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << mime << has; + return has; +} + +QStringList QWindowsInternalMimeData::formats_sys() const +{ + IDataObject *pDataObj = retrieveDataObject(); + if (!pDataObj) + return QStringList(); + + const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); + const QStringList fmts = mc.allMimesForFormats(pDataObj); + releaseDataObject(pDataObj); + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << fmts; + return fmts; +} + +QVariant QWindowsInternalMimeData::retrieveData_sys(const QString &mimeType, + QVariant::Type type) const +{ + IDataObject *pDataObj = retrieveDataObject(); + if (!pDataObj) + return QVariant(); + + QVariant result; + const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); + if (const QWindowsMime *converter = mc.converterToMime(mimeType, pDataObj)) + result = converter->convertToMime(mimeType, pDataObj, type); + releaseDataObject(pDataObj); + if (QWindowsContext::verboseOLE) { + QDebug nospace = qDebug().nospace(); + nospace << __FUNCTION__ << ' ' << mimeType << ' ' << type + << " returns " << result.type(); + if (result.type() != QVariant::ByteArray) + nospace << ' ' << result; + } + return result; +} + +/*! + \class QWindowsClipboardRetrievalMimeData + \brief Special mime data class managing delayed retrieval of clipboard data. + + Implementation of QWindowsInternalMimeDataBase that obtains the + IDataObject from the clipboard. + + \sa QWindowsInternalMimeDataBase, QWindowsClipboard + \ingroup qt-lighthouse-win +*/ + +IDataObject *QWindowsClipboardRetrievalMimeData::retrieveDataObject() const +{ + IDataObject * pDataObj = 0; + if (OleGetClipboard(&pDataObj) == S_OK) + return pDataObj; + return 0; +} + +void QWindowsClipboardRetrievalMimeData::releaseDataObject(IDataObject *dataObject) const +{ + dataObject->Release(); +} + +extern "C" LRESULT QT_WIN_CALLBACK qClipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT result = 0; + if (QWindowsClipboard::instance() + && QWindowsClipboard::instance()->clipboardViewerWndProc(hwnd, message, wParam, lParam, &result)) + return result; + return DefWindowProc(hwnd, message, wParam, lParam); +} + +QWindowsClipboard *QWindowsClipboard::m_instance = 0; + +QWindowsClipboard::QWindowsClipboard() : + m_data(0), m_clipboardViewer(0), m_nextClipboardViewer(0) +{ + QWindowsClipboard::m_instance = this; +} + +QWindowsClipboard::~QWindowsClipboard() +{ + unregisterViewer(); // Should release data if owner. + releaseIData(); + QWindowsClipboard::m_instance = 0; +} + +void QWindowsClipboard::releaseIData() +{ + if (m_data) { + delete m_data->mimeData(); + m_data->releaseQt(); + m_data->Release(); + m_data = 0; + } +} + +void QWindowsClipboard::registerViewer() +{ + m_clipboardViewer = QWindowsContext::instance()-> + createDummyWindow(QStringLiteral("Qt5ClipboardView"), L"Qt5ClipboardView", + qClipboardViewerWndProc, WS_OVERLAPPED); + m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer); + + if (QWindowsContext::verboseOLE) + qDebug("%s m_clipboardViewer: %p next=%p", __FUNCTION__, + m_clipboardViewer, m_nextClipboardViewer); +} + +void QWindowsClipboard::unregisterViewer() +{ + if (m_clipboardViewer) { + ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer); + DestroyWindow(m_clipboardViewer); + m_clipboardViewer = m_nextClipboardViewer = 0; + } +} + +void QWindowsClipboard::propagateClipboardMessage(UINT message, WPARAM wParam, LPARAM lParam) const +{ + if (!m_nextClipboardViewer) + return; + // In rare cases, a clipboard viewer can hang (application crashed, + // suspended by a shell prompt 'Select' or debugger). + if (QWindowsContext::user32dll.isHungAppWindow + && QWindowsContext::user32dll.isHungAppWindow(m_nextClipboardViewer)) { + qWarning("%s: Cowardly refusing to send clipboard message to hung application...", Q_FUNC_INFO); + return; + } + SendMessage(m_nextClipboardViewer, message, wParam, lParam); +} + +/*! + \brief Windows procedure of the clipboard viewer. Emits changed and does + housekeeping of the viewer chain. +*/ + +bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) +{ + *result = 0; + if (QWindowsContext::verboseOLE) + qDebug("%s HWND=%p 0x%x %s", __FUNCTION__, hwnd, message, + QWindowsGuiEventDispatcher::windowsMessageName(message)); + + switch (message) { + case WM_CHANGECBCHAIN: { + const HWND toBeRemoved = (HWND)wParam; + if (toBeRemoved == m_nextClipboardViewer) { + m_nextClipboardViewer = (HWND)lParam; + } else { + propagateClipboardMessage(message, wParam, lParam); + } + } + return true; + case WM_DRAWCLIPBOARD: + if (QWindowsContext::verboseOLE) + qDebug("Clipboard changed"); + emitChanged(QClipboard::Clipboard); + // clean up the clipboard object if we no longer own the clipboard + if (!ownsClipboard() && m_data) + releaseIData(); + propagateClipboardMessage(message, wParam, lParam); + return true; + case WM_DESTROY: + // Recommended shutdown + if (ownsClipboard()) { + if (QWindowsContext::verboseOLE) + qDebug("Clipboard owner on shutdown, releasing."); + OleFlushClipboard(); + releaseIData(); + } + return true; + } // switch (message) + return false; +} + +QMimeData *QWindowsClipboard::mimeData(QClipboard::Mode mode) +{ + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << mode; + if (mode != QClipboard::Clipboard) + return 0; + return &m_retrievalData; +} + +void QWindowsClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) +{ + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << mode << *mimeData; + if (mode != QClipboard::Clipboard) + return; + + const bool newData = !m_data || m_data->mimeData() != mimeData; + if (newData) { + releaseIData(); + m_data = new QWindowsOleDataObject(mimeData); + } + + const HRESULT src = OleSetClipboard(m_data); + if (src != S_OK) { + qErrnoWarning("OleSetClipboard: Failed to set data on clipboard: %s", + QWindowsContext::comErrorString(src).constData()); + releaseIData(); + return; + } +} + +void QWindowsClipboard::clear() +{ + const HRESULT src = OleSetClipboard(0); + if (src != S_OK) + qErrnoWarning("OleSetClipboard: Failed to clear the clipboard: 0x%lx", src); +} + +bool QWindowsClipboard::supportsMode(QClipboard::Mode mode) const +{ + return mode == QClipboard::Clipboard; +} + +// Need a non-virtual in destructor. +bool QWindowsClipboard::ownsClipboard() const +{ + return m_data && OleIsCurrentClipboard(m_data) == S_OK; +} + +bool QWindowsClipboard::ownsMode(QClipboard::Mode mode) const +{ + const bool result = mode == QClipboard::Clipboard ? + ownsClipboard() : false; + if (QWindowsContext::verboseOLE) + qDebug("%s %d returns %d", __FUNCTION__, mode, result); + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h new file mode 100644 index 0000000000..fab6871012 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsclipboard.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSCLIPBOARD_H +#define QWINDOWSCLIPBOARD_H + +#include "qwindowsinternalmimedata.h" + +#include <QtGui/QPlatformClipboard> + +QT_BEGIN_NAMESPACE + +class QWindowsOleDataObject; + +class QWindowsClipboardRetrievalMimeData : public QWindowsInternalMimeData { +public: + +protected: + virtual IDataObject *retrieveDataObject() const; + virtual void releaseDataObject(IDataObject *) const; +}; + +class QWindowsClipboard : public QPlatformClipboard +{ +public: + QWindowsClipboard(); + ~QWindowsClipboard(); + void registerViewer(); // Call in initialization, when context is up. + + virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard); + virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); + virtual bool supportsMode(QClipboard::Mode mode) const; + virtual bool ownsMode(QClipboard::Mode mode) const; + + inline bool clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); + + static QWindowsClipboard *instance() { return m_instance; } + +private: + void clear(); + void releaseIData(); + inline void propagateClipboardMessage(UINT message, WPARAM wParam, LPARAM lParam) const; + inline void unregisterViewer(); + inline bool ownsClipboard() const; + + static QWindowsClipboard *m_instance; + + QWindowsClipboardRetrievalMimeData m_retrievalData; + QWindowsOleDataObject *m_data; + HWND m_clipboardViewer; + HWND m_nextClipboardViewer; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSCLIPBOARD_H diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp new file mode 100644 index 0000000000..c77a111490 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -0,0 +1,750 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowscontext.h" +#include "qwindowswindow.h" +#include "qwindowskeymapper.h" +#include "qwindowsguieventdispatcher.h" +#include "qwindowsmousehandler.h" +#include "qtwindowsglobal.h" +#include "qwindowsmime.h" +#include "qwindowsinputcontext.h" + +#include <QtGui/QWindow> +#include <QtGui/QWindowSystemInterface> + +#include <QtCore/QSet> +#include <QtCore/QHash> +#include <QtCore/QStringList> +#include <QtCore/QDebug> +#include <QtCore/QSysInfo> +#include <QtCore/QScopedArrayPointer> +#include <QtCore/private/qsystemlibrary_p.h> + +#include <stdlib.h> +#include <stdio.h> +#include <windowsx.h> + +QT_BEGIN_NAMESPACE + +// Verbosity of components +int QWindowsContext::verboseIntegration = 0; +int QWindowsContext::verboseWindows = 0; +int QWindowsContext::verboseEvents = 0; +int QWindowsContext::verboseBackingStore = 0; +int QWindowsContext::verboseFonts = 0; +int QWindowsContext::verboseGL = 0; +int QWindowsContext::verboseOLE = 0; +int QWindowsContext::verboseInputMethods = 0; + +// Get verbosity of components from "foo:2,bar:3" +static inline int componentVerbose(const char *v, const char *keyWord) +{ + if (const char *k = strstr(v, keyWord)) { + k += qstrlen(keyWord); + if (*k == ':') { + ++k; + if (isdigit(*k)) + return *k - '0'; + } + } + return 0; +} + +static inline bool hasTouchSupport(QSysInfo::WinVersion wv) +{ + enum { QT_SM_DIGITIZER = 94, QT_NID_INTEGRATED_TOUCH = 0x1, + QT_NID_EXTERNAL_TOUCH = 0x02, QT_NID_MULTI_INPUT = 0x40 }; + + return wv < QSysInfo::WV_WINDOWS7 ? false : + (GetSystemMetrics(QT_SM_DIGITIZER) & (QT_NID_INTEGRATED_TOUCH | QT_NID_EXTERNAL_TOUCH | QT_NID_MULTI_INPUT)) != 0; +} + +#if !defined(LANG_SYRIAC) +# define LANG_SYRIAC 0x5a +#endif + +static inline bool useRTL_Extensions(QSysInfo::WinVersion ver) +{ + if ((ver & QSysInfo::WV_NT_based) && (ver >= QSysInfo::WV_VISTA)) { + // Since the IsValidLanguageGroup/IsValidLocale functions always return true on + // Vista, check the Keyboard Layouts for enabling RTL. + if (const UINT nLayouts = GetKeyboardLayoutList(0, 0)) { + QScopedArrayPointer<HKL> lpList(new HKL[nLayouts]); + GetKeyboardLayoutList(nLayouts, lpList.data()); + for (UINT i = 0; i < nLayouts; ++i) { + switch (PRIMARYLANGID((quintptr)lpList[i])) { + case LANG_ARABIC: + case LANG_HEBREW: + case LANG_FARSI: + case LANG_SYRIAC: + return true; + default: + break; + } + } + } + return false; + } // NT/Vista + // Pre-NT: figure out whether a RTL language is installed + return IsValidLanguageGroup(LGRPID_ARABIC, LGRPID_INSTALLED) + || IsValidLanguageGroup(LGRPID_HEBREW, LGRPID_INSTALLED) + || IsValidLocale(MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED) + || IsValidLocale(MAKELCID(MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED) + || IsValidLocale(MAKELCID(MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED) + || IsValidLocale(MAKELCID(MAKELANGID(LANG_FARSI, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED); +} + +/*! + \class QWindowsUser32DLL + \brief Struct that contains dynamically resolved symbols of User32.dll. + + The stub libraries shipped with the MinGW compiler miss some of the + functions. They need to be retrieved dynamically. + + In addition, touch-related functions are available only from Windows onwards. + These need to resolved dynamically for Q_CC_MSVC as well. + + \ingroup qt-lighthouse-win +*/ + +QWindowsUser32DLL::QWindowsUser32DLL() : + setLayeredWindowAttributes(0), updateLayeredWindow(0), + updateLayeredWindowIndirect(0), + isHungAppWindow(0), + registerTouchWindow(0), getTouchInputInfo(0), closeTouchInputHandle(0) +{ +} + +void QWindowsUser32DLL::init() +{ + QSystemLibrary library(QStringLiteral("user32")); + // MinGW (g++ 3.4.5) accepts only C casts. + setLayeredWindowAttributes = (SetLayeredWindowAttributes)(library.resolve("SetLayeredWindowAttributes")); + updateLayeredWindow = (UpdateLayeredWindow)(library.resolve("UpdateLayeredWindow")); + updateLayeredWindowIndirect = (UpdateLayeredWindowIndirect)(library.resolve("UpdateLayeredWindowIndirect")); + + Q_ASSERT(setLayeredWindowAttributes && updateLayeredWindow + && updateLayeredWindowIndirect); + + isHungAppWindow = (IsHungAppWindow)library.resolve("IsHungAppWindow"); +} + +bool QWindowsUser32DLL::initTouch() +{ + QSystemLibrary library(QStringLiteral("user32")); + registerTouchWindow = (RegisterTouchWindow)(library.resolve("RegisterTouchWindow")); + getTouchInputInfo = (GetTouchInputInfo)(library.resolve("GetTouchInputInfo")); + closeTouchInputHandle = (CloseTouchInputHandle)(library.resolve("CloseTouchInputHandle")); + return registerTouchWindow && getTouchInputInfo && getTouchInputInfo; +} + +QWindowsUser32DLL QWindowsContext::user32dll; + +QWindowsContext *QWindowsContext::m_instance = 0; + +/*! + \class QWindowsContext + \brief Singleton container for all relevant information. + + Holds state information formerly stored in \c qapplication_win.cpp. + \ingroup qt-lighthouse-win +*/ + +typedef QHash<HWND, QWindowsWindow *> HandleBaseWindowHash; + +struct QWindowsContextPrivate { + explicit QWindowsContextPrivate(bool isOpenGL); + + const bool m_isOpenGL; + unsigned m_systemInfo; + QSet<QString> m_registeredWindowClassNames; + HandleBaseWindowHash m_windows; + HDC m_displayContext; + const int m_defaultDPI; + QWindowsKeyMapper m_keyMapper; + QWindowsMouseHandler m_mouseHandler; + QWindowsMimeConverter m_mimeConverter; + QSharedPointer<QWindowCreationContext> m_creationContext; + const HRESULT m_oleInitializeResult; +}; + +QWindowsContextPrivate::QWindowsContextPrivate(bool isOpenGL) : + m_isOpenGL(isOpenGL), + m_systemInfo(0), + m_displayContext(GetDC(0)), + m_defaultDPI(GetDeviceCaps(m_displayContext,LOGPIXELSY)), + m_oleInitializeResult(OleInitialize(NULL)) +{ + QWindowsContext::user32dll.init(); + + const QSysInfo::WinVersion ver = QSysInfo::windowsVersion(); + + if (hasTouchSupport(ver) && QWindowsContext::user32dll.initTouch()) + m_systemInfo |= QWindowsContext::SI_SupportsTouch; + + if (useRTL_Extensions(ver)) { + m_systemInfo |= QWindowsContext::SI_RTL_Extensions; + m_keyMapper.setUseRTLExtensions(true); + } +} + +QWindowsContext::QWindowsContext(bool isOpenGL) : + d(new QWindowsContextPrivate(isOpenGL)) +{ +#ifdef Q_CC_MSVC +# pragma warning( disable : 4996 ) +#endif + m_instance = this; + if (const char *v = getenv("QT_LIGHTHOUSE_WINDOWS_VERBOSE")) { + QWindowsContext::verboseIntegration = componentVerbose(v, "integration"); + QWindowsContext::verboseWindows = componentVerbose(v, "windows"); + QWindowsContext::verboseEvents = componentVerbose(v, "events"); + QWindowsContext::verboseBackingStore = componentVerbose(v, "backingstore"); + QWindowsContext::verboseFonts = componentVerbose(v, "fonts"); + QWindowsContext::verboseGL = componentVerbose(v, "gl"); + QWindowsContext::verboseOLE = componentVerbose(v, "ole"); + QWindowsContext::verboseInputMethods = componentVerbose(v, "im"); + } +} + +QWindowsContext::~QWindowsContext() +{ + unregisterWindowClasses(); + if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) + OleUninitialize(); + + m_instance = 0; +} + +QWindowsContext *QWindowsContext::instance() +{ + return m_instance; +} + +unsigned QWindowsContext::systemInfo() const +{ + return d->m_systemInfo; +} + +void QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx) +{ + d->m_creationContext = ctx; +} + +bool QWindowsContext::isOpenGL() const +{ + return d->m_isOpenGL; +} + +int QWindowsContext::defaultDPI() const +{ + return d->m_defaultDPI; +} + +HDC QWindowsContext::displayContext() const +{ + return d->m_displayContext; +} + +QWindow *QWindowsContext::keyGrabber() const +{ + return d->m_keyMapper.keyGrabber(); +} + +void QWindowsContext::setKeyGrabber(QWindow *w) +{ + d->m_keyMapper.setKeyGrabber(w); +} + +// Window class registering code (from qapplication_win.cpp) +// If 0 is passed as the widget pointer, register a window class +// for QWidget as default. This is used in QGLTemporaryContext +// during GL initialization, where we don't want to use temporary +// QWidgets or QGLWidgets, neither do we want to have separate code +// to register window classes. + +QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL) +{ + const Qt::WindowFlags flags = w ? w->windowFlags() : (Qt::WindowFlags)0; + const Qt::WindowFlags type = flags & Qt::WindowType_Mask; + + uint style = 0; + bool icon = false; + QString cname = "Qt5"; + if (w && isGL) { + cname += QStringLiteral("QGLWindow"); + style = CS_DBLCLKS|CS_OWNDC; + icon = true; + } else if (w && (flags & Qt::MSWindowsOwnDC)) { + cname += QStringLiteral("QWindowOwnDC"); + style = CS_DBLCLKS|CS_OWNDC; + icon = true; + } else if (w && (type == Qt::Tool || type == Qt::ToolTip)) { + style = CS_DBLCLKS; + if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) { + if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) { + style |= CS_DROPSHADOW; + } + cname += QStringLiteral("QToolTip"); + } else { + cname += QStringLiteral("QTool"); + } + style |= CS_SAVEBITS; + icon = false; + } else if (w && (type == Qt::Popup)) { + cname += QStringLiteral("QPopup"); + style = CS_DBLCLKS|CS_SAVEBITS; + if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + style |= CS_DROPSHADOW; + icon = false; + } else { + cname += QStringLiteral("QWindow"); + style = CS_DBLCLKS; + icon = true; + } + + // force CS_OWNDC when the GL graphics system is + // used as the default renderer + if (d->m_isOpenGL) + style |= CS_OWNDC; + + HBRUSH brush = 0; + if (w && !isGL) + brush = GetSysColorBrush(COLOR_WINDOW); + return registerWindowClass(cname, qWindowsWndProc, style, brush, icon); +} + +QString QWindowsContext::registerWindowClass(QString cname, + WNDPROC proc, + unsigned style, + HBRUSH brush, + bool icon) +{ + // since multiple Qt versions can be used in one process + // each one has to have window class names with a unique name + // The first instance gets the unmodified name; if the class + // has already been registered by another instance of Qt then + // add an instance-specific ID, the address of the window proc. + static int classExists = -1; + + const HINSTANCE appInstance = (HINSTANCE)GetModuleHandle(0); + if (classExists == -1) { + WNDCLASS wcinfo; + classExists = GetClassInfo(appInstance, (wchar_t*)cname.utf16(), &wcinfo); + classExists = classExists && wcinfo.lpfnWndProc != proc; + } + + if (classExists) + cname += QString::number((quintptr)proc); + + if (d->m_registeredWindowClassNames.contains(cname)) // already registered in our list + return cname; + + WNDCLASSEX wc; + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = style; + wc.lpfnWndProc = proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = appInstance; + if (icon) { + wc.hIcon = (HICON)LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + if (wc.hIcon) { + int sw = GetSystemMetrics(SM_CXSMICON); + int sh = GetSystemMetrics(SM_CYSMICON); + wc.hIconSm = (HICON)LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, sw, sh, 0); + } else { + wc.hIcon = (HICON)LoadImage(0, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + wc.hIconSm = 0; + } + } else { + wc.hIcon = 0; + wc.hIconSm = 0; + } + wc.hCursor = 0; + wc.hbrBackground = brush; + wc.lpszMenuName = 0; + wc.lpszClassName = (wchar_t*)cname.utf16(); + ATOM atom = RegisterClassEx(&wc); + + if (!atom) + qErrnoWarning("QApplication::regClass: Registering window class '%s' failed.", + qPrintable(cname)); + + d->m_registeredWindowClassNames.insert(cname); + if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) + qDebug().nospace() << __FUNCTION__ << ' ' << cname + << " style=0x" << QString::number(style, 16) + << " brush=" << brush << " icon=" << icon << " atom=" << atom; + return cname; +} + +void QWindowsContext::unregisterWindowClasses() +{ + const HINSTANCE appInstance = (HINSTANCE)GetModuleHandle(0); + + foreach (const QString &name, d->m_registeredWindowClassNames) { + if (QWindowsContext::verboseIntegration) + qDebug() << __FUNCTION__ << name; + UnregisterClass((wchar_t*)name.utf16(), appInstance); + } + d->m_registeredWindowClassNames.clear(); +} + +int QWindowsContext::screenDepth() const +{ + return GetDeviceCaps(d->m_displayContext, BITSPIXEL); +} + +QString QWindowsContext::windowsErrorMessage(unsigned long errorCode) +{ + QString rc = QString::fromLatin1("#%1: ").arg(errorCode); + ushort *lpMsgBuf; + + const int len = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorCode, 0, (LPTSTR)&lpMsgBuf, 0, NULL); + if (len) { + rc = QString::fromUtf16(lpMsgBuf, len); + LocalFree(lpMsgBuf); + } else { + rc += QString::fromLatin1("<unknown error>"); + } + return rc; +} + +void QWindowsContext::addWindow(HWND hwnd, QWindowsWindow *w) +{ + d->m_windows.insert(hwnd, w); +} + +void QWindowsContext::removeWindow(HWND hwnd) +{ + const HandleBaseWindowHash::iterator it = d->m_windows.find(hwnd); + if (it != d->m_windows.end()) { + if (d->m_keyMapper.keyGrabber() == it.value()->window()) + d->m_keyMapper.setKeyGrabber(0); + d->m_windows.erase(it); + } +} + +QWindowsWindow *QWindowsContext::findPlatformWindow(HWND hwnd) const +{ + return d->m_windows.value(hwnd); +} + +QWindow *QWindowsContext::findWindow(HWND hwnd) const +{ + if (const QWindowsWindow *bw = findPlatformWindow(hwnd)) + return bw->window(); + return 0; +} + +QWindow *QWindowsContext::windowUnderMouse() const +{ + return d->m_mouseHandler.windowUnderMouse(); +} + +/*! + \brief Find a child window at a screen point. + + Deep search for a QWindow at global point, skipping non-owned + windows (accessibility?). Implemented using ChildWindowFromPointEx() + instead of (historically used) WindowFromPoint() to get a well-defined + behaviour for hidden/transparent windows. + + \a cwex_flags are flags of ChildWindowFromPointEx(). + \a parent is the parent window, pass GetDesktopWindow() for top levels. +*/ + +QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent, + const QPoint &screenPointIn, + unsigned cwex_flags) const +{ + QWindowsWindow *result = 0; + const POINT screenPoint = { screenPointIn.x(), screenPointIn.y() }; + while (true) { + POINT point = screenPoint; + ScreenToClient(parent, &point); + // Returns parent if inside & none matched. + const HWND child = ChildWindowFromPointEx(parent, point, cwex_flags); + if (child && child != parent) { + if (QWindowsWindow *window = findPlatformWindow(child)) + result = window; + parent = child; + } else { + break; + } + } + return result; +} + +QWindowsMimeConverter &QWindowsContext::mimeConverter() const +{ + return d->m_mimeConverter; +} + +/*! + \brief Convenience to create a non-visible dummy window + for example used as clipboard watcher or for GL. +*/ + +HWND QWindowsContext::createDummyWindow(const QString &classNameIn, + const wchar_t *windowName, + WNDPROC wndProc, DWORD style) +{ + if (!wndProc) + wndProc = DefWindowProc; + QString className = registerWindowClass(classNameIn, wndProc); + return CreateWindowEx(0, (wchar_t*)className.utf16(), + windowName, style, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + 0, NULL, (HINSTANCE)GetModuleHandle(0), NULL); +} + +/*! + \brief Common COM error strings. +*/ + +QByteArray QWindowsContext::comErrorString(HRESULT hr) +{ + switch (hr) { + case S_OK: + return QByteArray("S_OK"); + case S_FALSE: + return QByteArray("S_FALSE"); + case E_UNEXPECTED: + return QByteArray("E_UNEXPECTED"); + case CO_E_ALREADYINITIALIZED: + return QByteArray("CO_E_ALREADYINITIALIZED"); + case CO_E_NOTINITIALIZED: + return QByteArray("CO_E_NOTINITIALIZED"); + case RPC_E_CHANGED_MODE: + return QByteArray("RPC_E_CHANGED_MODE"); + case OLE_E_WRONGCOMPOBJ: + return QByteArray("OLE_E_WRONGCOMPOBJ"); + case CO_E_NOT_SUPPORTED: + return QByteArray("CO_E_NOT_SUPPORTED"); + case E_NOTIMPL: + return QByteArray("E_NOTIMPL"); + case E_INVALIDARG: + return QByteArray(""); + case E_NOINTERFACE: + return QByteArray(""); + case E_POINTER: + return QByteArray(""); + case E_HANDLE: + return QByteArray(""); + case E_ABORT: + return QByteArray(""); + case E_FAIL: + return QByteArray(""); + case E_ACCESSDENIED: + return QByteArray(""); + default: + break; + } + return "Unknown error 0x" + QByteArray::number(quint64(hr), 16); +} + +/*! + \brief Main windows procedure registered for windows. + + \sa QWindowsGuiEventDispatcher +*/ + +bool QWindowsContext::windowsProc(HWND hwnd, UINT message, + QtWindows::WindowsEventType et, + WPARAM wParam, LPARAM lParam, LRESULT *result) +{ + *result = 0; + // Events without an associated QWindow or events we are not interested in. + switch (et) { + case QtWindows::DeactivateApplicationEvent: + case QtWindows::DeactivateWindowEvent: + QWindowSystemInterface::handleWindowActivated(0); + return true; + case QtWindows::InputMethodStartCompositionEvent: + return QWindowsInputContext::instance()->startComposition(hwnd); + case QtWindows::InputMethodCompositionEvent: + return QWindowsInputContext::instance()->composition(hwnd, lParam); + case QtWindows::InputMethodEndCompositionEvent: + return QWindowsInputContext::instance()->endComposition(hwnd); + case QtWindows::InputMethodRequest: + return QWindowsInputContext::instance()->handleIME_Request(wParam, lParam, result); + case QtWindows::InputMethodOpenCandidateWindowEvent: + case QtWindows::InputMethodCloseCandidateWindowEvent: + // TODO: Release/regrab mouse if a popup has mouse grab. + return false; + case QtWindows::ClipboardEvent: + case QtWindows::DestroyEvent: + + case QtWindows::UnknownEvent: + return false; + default: + break; + } + + QWindowsWindow *platformWindow = findPlatformWindow(hwnd); + // Before CreateWindowEx() returns, some events are sent, + // for example WM_GETMINMAXINFO asking for size constraints for top levels. + // Pass on to current creation context + if (!platformWindow && !d->m_creationContext.isNull()) { + switch (et) { + case QtWindows::QuerySizeHints: + d->m_creationContext->applyToMinMaxInfo(reinterpret_cast<MINMAXINFO *>(lParam)); + return true; + case QtWindows::ResizeEvent: + d->m_creationContext->obtainedGeometry.setSize(QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); + return true; + case QtWindows::MoveEvent: + d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + return true; + case QtWindows::CalculateSize: + return false; + default: + break; + } + } + if (platformWindow) { + if (QWindowsContext::verboseEvents > 1) + qDebug().nospace() << "Event window: " << platformWindow->window(); + } else { + qWarning("%s: No Qt Window found for event 0x%x (%s), hwnd=0x%p.", + __FUNCTION__, message, + QWindowsGuiEventDispatcher::windowsMessageName(message), hwnd); + return false; + } + + MSG msg; + msg.hwnd = hwnd; // re-create MSG structure + msg.message = message; // time and pt fields ignored + msg.wParam = wParam; + msg.lParam = lParam; + msg.pt.x = GET_X_LPARAM(lParam); + msg.pt.y = GET_Y_LPARAM(lParam); + + switch (et) { + case QtWindows::KeyDownEvent: + case QtWindows::KeyEvent: + case QtWindows::InputMethodKeyEvent: + case QtWindows::InputMethodKeyDownEvent: + return d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result); + case QtWindows::MoveEvent: + platformWindow->handleMoved(); + return true; + case QtWindows::ResizeEvent: + platformWindow->handleResized((int)wParam); + return true; + case QtWindows::QuerySizeHints: + platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam)); + return true; + case QtWindows::CalculateSize: + // NCCALCSIZE_PARAMS structure if wParam==TRUE + if (wParam && QWindowsContext::verboseWindows) { + const NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(lParam); + qDebug() << platformWindow->window() << *ncp; + } + break; + case QtWindows::ExposeEvent: + platformWindow->handleWmPaint(hwnd, message, wParam, lParam); + return true; + case QtWindows::MouseWheelEvent: + case QtWindows::MouseEvent: + case QtWindows::NonClientMouseEvent: + case QtWindows::LeaveEvent: + return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result); + case QtWindows::TouchEvent: + return d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result); + case QtWindows::ActivateWindowEvent: + QWindowSystemInterface::handleWindowActivated(platformWindow->window()); + return true; + case QtWindows::ShowEvent: + platformWindow->handleShown(); + return true; + case QtWindows::HideEvent: + platformWindow->handleHidden(); + return true; + case QtWindows::CloseEvent: + QWindowSystemInterface::handleCloseEvent(platformWindow->window()); + return true; + default: + break; + } + return false; +} + +/*! + \brief Windows functions for actual windows. + + There is another one for timers, sockets, etc in + QEventDispatcherWin32. + + \ingroup qt-lighthouse-win +*/ + +extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT result; + const QtWindows::WindowsEventType et = windowsEventType(message, wParam); + const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result); + const bool guiEventsQueued = QWindowSystemInterface::windowSystemEventsQueued(); + if (QWindowsContext::verboseEvents > 1) + if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) + qDebug("EVENT: hwd=%p %s msg=0x%x et=0x%x wp=%d at %d,%d handled=%d gui=%d", + hwnd, eventName, message, et, int(wParam), + GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), handled, guiEventsQueued); + if (guiEventsQueued) { + const QWindowsGuiEventDispatcher::DispatchContext dispatchContext = + QWindowsGuiEventDispatcher::currentDispatchContext(); + if (dispatchContext.first) + QWindowSystemInterface::sendWindowSystemEvents(dispatchContext.first, dispatchContext.second); + } + if (!handled) + result = DefWindowProc(hwnd, message, wParam, lParam); + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h new file mode 100644 index 0000000000..93662384c0 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSCONTEXT_H +#define QWINDOWSCONTEXT_H + +#include "qtwindowsglobal.h" +#include "qtwindows_additional.h" + +#include <QtCore/QScopedPointer> +#include <QtCore/QSharedPointer> + +QT_BEGIN_NAMESPACE + +class QWindow; +class QPlatformScreen; +class QWindowsWindow; +class QWindowsMimeConverter; +struct QWindowCreationContext; +struct QWindowsContextPrivate; +class QPoint; + +struct QWindowsUser32DLL +{ + QWindowsUser32DLL(); + inline void init(); + inline bool initTouch(); + + typedef BOOL (WINAPI *RegisterTouchWindow)(HWND, ULONG); + typedef BOOL (WINAPI *GetTouchInputInfo)(HANDLE, UINT, PVOID, int); + typedef BOOL (WINAPI *CloseTouchInputHandle)(HANDLE); + typedef BOOL (WINAPI *SetLayeredWindowAttributes)(HWND, COLORREF, BYTE, DWORD); + typedef BOOL (WINAPI *UpdateLayeredWindow)(HWND, HDC , const POINT *, + const SIZE *, HDC, const POINT *, COLORREF, + const BLENDFUNCTION *, DWORD); + typedef BOOL (WINAPI *UpdateLayeredWindowIndirect)(HWND, const UPDATELAYEREDWINDOWINFO *); + typedef BOOL (WINAPI *IsHungAppWindow)(HWND); + + // Functions missing in Q_CC_GNU stub libraries. + SetLayeredWindowAttributes setLayeredWindowAttributes; + UpdateLayeredWindow updateLayeredWindow; + UpdateLayeredWindowIndirect updateLayeredWindowIndirect; + + // Functions missing in older versions of Windows + IsHungAppWindow isHungAppWindow; + + // Touch functions from Windows 7 onwards (also for use with Q_CC_MSVC). + RegisterTouchWindow registerTouchWindow; + GetTouchInputInfo getTouchInputInfo; + CloseTouchInputHandle closeTouchInputHandle; +}; + +class QWindowsContext +{ + Q_DISABLE_COPY(QWindowsContext) +public: + enum SystemInfoFlags + { + SI_RTL_Extensions = 0x1, + SI_SupportsTouch = 0x2 + }; + + // Verbose flag set by environment variable QT_LIGHTHOUSE_WINDOWS_VERBOSE + static int verboseIntegration; + static int verboseWindows; + static int verboseBackingStore; + static int verboseEvents; + static int verboseFonts; + static int verboseGL; + static int verboseOLE; + static int verboseInputMethods; + + explicit QWindowsContext(bool isOpenGL); + ~QWindowsContext(); + + bool isOpenGL() const; + + int defaultDPI() const; + + QString registerWindowClass(const QWindow *w, bool isGL); + QString registerWindowClass(QString cname, WNDPROC proc, + unsigned style = 0, HBRUSH brush = 0, + bool icon = false); + HWND createDummyWindow(const QString &classNameIn, + const wchar_t *windowName, + WNDPROC wndProc = 0, DWORD style = WS_OVERLAPPED); + + HDC displayContext() const; + int screenDepth() const; + + static QWindowsContext *instance(); + + static QString windowsErrorMessage(unsigned long errorCode); + + void addWindow(HWND, QWindowsWindow *w); + void removeWindow(HWND); + + QWindowsWindow *findPlatformWindow(HWND) const; + QWindow *findWindow(HWND) const; + QWindowsWindow *findPlatformWindowAt(HWND parent, const QPoint &screenPoint, + unsigned cwex_flags) const; + + QWindow *windowUnderMouse() const; + + inline bool windowsProc(HWND hwnd, UINT message, + QtWindows::WindowsEventType et, + WPARAM wParam, LPARAM lParam, LRESULT *result); + + QWindow *keyGrabber() const; + void setKeyGrabber(QWindow *hwnd); + + void setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx); + + // Returns a combination of SystemInfoFlags + unsigned systemInfo() const; + + QWindowsMimeConverter &mimeConverter() const; + + static QWindowsUser32DLL user32dll; + + static QByteArray comErrorString(HRESULT hr); + +private: + void unregisterWindowClasses(); + + QScopedPointer<QWindowsContextPrivate> d; + static QWindowsContext *m_instance; +}; + +extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND, UINT, WPARAM, LPARAM); + +QT_END_NAMESPACE + +#endif // QWINDOWSCONTEXT_H diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp new file mode 100644 index 0000000000..1ad2079962 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowscursor.h" +#include "qwindowscontext.h" +#include "qwindowswindow.h" +#include "qwindowsscreen.h" +#include "pixmaputils.h" + +#include <QtGui/QPixmap> +#include <QtGui/QImage> +#include <QtGui/QBitmap> +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> +#include <QtGui/private/qguiapplication_p.h> // getPixmapCursor() + +#include <QtCore/QDebug> +#include <QtCore/QScopedArrayPointer> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsCursor + \brief Platform cursor implementation + + Note that whereas under X11, a cursor can be set as a property of + a window, there is only a global SetCursor() function on Windows. + Each Window sets on the global cursor on receiving a Enter-event + as do the Window manager frames (resize/move handles). + + \ingroup qt-lighthouse-win + \sa QWindowsWindowCursor +*/ + +QWindowsCursor::QWindowsCursor(QPlatformScreen *s) : + QPlatformCursor(s) +{ +} + +HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY) +{ + HCURSOR cur = 0; + QBitmap mask = pixmap.mask(); + if (mask.isNull()) { + mask = QBitmap(pixmap.size()); + mask.fill(Qt::color1); + } + + HBITMAP ic = qPixmapToWinHBITMAP(pixmap, HBitmapAlpha); + const HBITMAP im = createIconMask(mask); + + ICONINFO ii; + ii.fIcon = 0; + ii.xHotspot = hotX; + ii.yHotspot = hotY; + ii.hbmMask = im; + ii.hbmColor = ic; + + cur = CreateIconIndirect(&ii); + + DeleteObject(ic); + DeleteObject(im); + return cur; +} + +HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) +{ + int hx = c.hotSpot().x(); + int hy = c.hotSpot().y(); + const Qt::CursorShape cshape = c.shape(); + if (cshape == Qt::BitmapCursor) { + const QPixmap pixmap = c.pixmap(); + if (!pixmap.isNull()) + if (const HCURSOR hc = createPixmapCursor(pixmap, hx, hy)) + return hc; + } + + // Non-standard Windows cursors are created from bitmaps + + static const uchar vsplit_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const uchar vsplitm_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00, + 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, + 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const uchar hsplit_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03, + 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const uchar hsplitm_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, + 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00, + 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07, + 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00, + 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, + 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const uchar phand_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, + 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, + 0x80, 0x1c, 0x00, 0x00, 0x80, 0xe4, 0x00, 0x00, 0x80, 0x24, 0x03, 0x00, + 0x80, 0x24, 0x05, 0x00, 0xb8, 0x24, 0x09, 0x00, 0xc8, 0x00, 0x09, 0x00, + 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0xa0, 0x00, 0x08, 0x00, + 0x20, 0x00, 0x08, 0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x04, 0x00, + 0x80, 0x00, 0x04, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x01, 0x02, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + static const uchar phandm_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, + 0x80, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0xff, 0x03, 0x00, + 0x80, 0xff, 0x07, 0x00, 0xb8, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x0f, 0x00, + 0xf8, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x0f, 0x00, + 0xe0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x07, 0x00, + 0x80, 0xff, 0x07, 0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00, + 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + static const uchar openhand_bits[] = { + 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92, + 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20, + 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00}; + static const uchar openhandm_bits[] = { + 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff, + 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f, + 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00}; + static const uchar closedhand_bits[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50, + 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10, + 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00}; + static const uchar closedhandm_bits[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f, + 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f, + 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00}; + + static const uchar * const cursor_bits32[] = { + vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits, + phand_bits, phandm_bits + }; + + wchar_t *sh = 0; + switch (c.shape()) { // map to windows cursor + case Qt::ArrowCursor: + sh = IDC_ARROW; + break; + case Qt::UpArrowCursor: + sh = IDC_UPARROW; + break; + case Qt::CrossCursor: + sh = IDC_CROSS; + break; + case Qt::WaitCursor: + sh = IDC_WAIT; + break; + case Qt::IBeamCursor: + sh = IDC_IBEAM; + break; + case Qt::SizeVerCursor: + sh = IDC_SIZENS; + break; + case Qt::SizeHorCursor: + sh = IDC_SIZEWE; + break; + case Qt::SizeBDiagCursor: + sh = IDC_SIZENESW; + break; + case Qt::SizeFDiagCursor: + sh = IDC_SIZENWSE; + break; + case Qt::SizeAllCursor: + sh = IDC_SIZEALL; + break; + case Qt::ForbiddenCursor: + sh = IDC_NO; + break; + case Qt::WhatsThisCursor: + sh = IDC_HELP; + break; + case Qt::BusyCursor: + sh = IDC_APPSTARTING; + break; + case Qt::PointingHandCursor: + sh = IDC_HAND; + break; + case Qt::BlankCursor: + case Qt::SplitVCursor: + case Qt::SplitHCursor: + case Qt::OpenHandCursor: + case Qt::ClosedHandCursor: + case Qt::BitmapCursor: { + QImage bbits, mbits; + bool invb, invm; + if (cshape == Qt::BlankCursor) { + bbits = QImage(32, 32, QImage::Format_Mono); + bbits.fill(0); // ignore color table + mbits = bbits.copy(); + hx = hy = 16; + invb = invm = false; + } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) { + bool open = cshape == Qt::OpenHandCursor; + QBitmap cb = QBitmap::fromData(QSize(16, 16), open ? openhand_bits : closedhand_bits); + QBitmap cm = QBitmap::fromData(QSize(16, 16), open ? openhandm_bits : closedhandm_bits); + bbits = cb.toImage().convertToFormat(QImage::Format_Mono); + mbits = cm.toImage().convertToFormat(QImage::Format_Mono); + hx = hy = 8; + invb = invm = false; + } else if (cshape != Qt::BitmapCursor) { + int i = cshape - Qt::SplitVCursor; + QBitmap cb = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2]); + QBitmap cm = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2 + 1]); + bbits = cb.toImage().convertToFormat(QImage::Format_Mono); + mbits = cm.toImage().convertToFormat(QImage::Format_Mono); + if (cshape == Qt::PointingHandCursor) { + hx = 7; + hy = 0; + } else + hx = hy = 16; + invb = invm = false; + } else { + bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono); + mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono); + invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1)); + invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1)); + } + const int n = qMax(1, bbits.width() / 8); + const int h = bbits.height(); + QScopedArrayPointer<uchar> xBits(new uchar[h * n]); + QScopedArrayPointer<uchar> xMask(new uchar[h * n]); + int x = 0; + for (int i = 0; i < h; ++i) { + uchar *bits = bbits.scanLine(i); + uchar *mask = mbits.scanLine(i); + for (int j = 0; j < n; ++j) { + uchar b = bits[j]; + uchar m = mask[j]; + if (invb) + b ^= 0xff; + if (invm) + m ^= 0xff; + xBits[x] = ~m; + xMask[x] = b ^ m; + ++x; + } + } + return CreateCursor(GetModuleHandle(0), hx, hy, bbits.width(), bbits.height(), + xBits.data(), xMask.data()); + } + case Qt::DragCopyCursor: + case Qt::DragMoveCursor: + case Qt::DragLinkCursor: { + const QPixmap pixmap = QGuiApplicationPrivate::instance()->getPixmapCursor(cshape); + return createPixmapCursor(pixmap, hx, hy); + } + default: + qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cshape); + return 0; + } + return (HCURSOR)LoadImage(0, sh, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); +} + +/*! + \brief Return cached standard cursor resources or create new ones. +*/ + +QWindowsWindowCursor QWindowsCursor::standardWindowCursor(Qt::CursorShape shape) +{ + StandardCursorCache::iterator it = m_standardCursorCache.find(shape); + if (it == m_standardCursorCache.end()) + it = m_standardCursorCache.insert(shape, QWindowsWindowCursor(QCursor(shape))); + return it.value(); +} + +/*! + \brief Set a cursor on a window. + + This is called frequently as the mouse moves over widgets in the window + (QLineEdits, etc). +*/ + +void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window) +{ + + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << cursorIn << window; + if (!cursorIn || !window) + return; + const QWindowsWindowCursor wcursor = + cursorIn->shape() == Qt::BitmapCursor ? + QWindowsWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape()); + if (wcursor.handle()) { + QWindowsWindow::baseWindowOf(window)->setCursor(wcursor); + } else { + qWarning("%s: Unable to obtain system cursor for %d", + __FUNCTION__, cursorIn->shape()); + } +} + +QPoint QWindowsCursor::mousePosition() +{ + POINT p; + GetCursorPos(&p); + if (QWindowsContext::verboseWindows) + qDebug("%s %ld,%ld", __FUNCTION__, p.x, p.y); + return QPoint(p.x, p.y); +} + +void QWindowsCursor::setPos(const QPoint &pos) +{ + if (QWindowsContext::verboseWindows) + qDebug("%s %d,%d", __FUNCTION__, pos.x(), pos.y()); + SetCursorPos(pos.x(), pos.y()); +} + +/*! + \class QWindowsWindowCursor + \brief Per-Window cursor. Contains a QCursor and manages its associated system + cursor handle resource. + + Based on QSharedDataPointer, so that it can be passed around and + used as a property of QWindowsBaseWindow. + + \ingroup qt-lighthouse-win + \sa QWindowsCursor +*/ + +class QWindowsWindowCursorData : public QSharedData +{ +public: + explicit QWindowsWindowCursorData(const QCursor &c); + ~QWindowsWindowCursorData(); + + const QCursor m_cursor; + const HCURSOR m_handle; +}; + +QWindowsWindowCursorData::QWindowsWindowCursorData(const QCursor &c) : + m_cursor(c), + m_handle(QWindowsCursor::createSystemCursor(c)) +{ +} + +QWindowsWindowCursorData::~QWindowsWindowCursorData() +{ + DestroyCursor(m_handle); +} + +QWindowsWindowCursor::QWindowsWindowCursor(const QCursor &c) : + m_data(new QWindowsWindowCursorData(c)) +{ +} + +QWindowsWindowCursor::~QWindowsWindowCursor() +{ +} + +QWindowsWindowCursor::QWindowsWindowCursor(const QWindowsWindowCursor &rhs) : + m_data(rhs.m_data) +{ +} + +QWindowsWindowCursor & QWindowsWindowCursor::operator =(const QWindowsWindowCursor &rhs) +{ + if (this != &rhs) + m_data.operator =(rhs.m_data); + return *this; +} + +QCursor QWindowsWindowCursor::cursor() const +{ + return m_data->m_cursor; +} + +HCURSOR QWindowsWindowCursor::handle() const +{ + return m_data->m_handle; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h new file mode 100644 index 0000000000..bf8cb837d9 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSCURSOR_H +#define QWINDOWSCURSOR_H + +#include "qtwindows_additional.h" + +#include <QtGui/QPlatformCursor> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QHash> + +QT_BEGIN_NAMESPACE + +class QWindowsWindowCursorData; + +class QWindowsWindowCursor +{ +public: + explicit QWindowsWindowCursor(const QCursor &c); + ~QWindowsWindowCursor(); + QWindowsWindowCursor(const QWindowsWindowCursor &c); + QWindowsWindowCursor &operator=(const QWindowsWindowCursor &c); + + QCursor cursor() const; + HCURSOR handle() const; + +private: + QSharedDataPointer<QWindowsWindowCursorData> m_data; +}; + +class QWindowsCursor : public QPlatformCursor +{ +public: + explicit QWindowsCursor(QPlatformScreen *); + + virtual void changeCursor(QCursor * widgetCursor, QWindow * widget); + virtual QPoint pos() const { return mousePosition(); } + virtual void setPos(const QPoint &pos); + + static HCURSOR createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY); + static HCURSOR createSystemCursor(const QCursor &c); + static QPoint mousePosition(); + + QWindowsWindowCursor standardWindowCursor(Qt::CursorShape s = Qt::ArrowCursor); + +private: + typedef QHash<Qt::CursorShape, QWindowsWindowCursor> StandardCursorCache; + + StandardCursorCache m_standardCursorCache; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSCURSOR_H diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp new file mode 100644 index 0000000000..1535437a32 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -0,0 +1,721 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsdrag.h" +#include "qwindowscontext.h" +#include "qwindowsclipboard.h" +#include "qwindowsintegration.h" +#include "qwindowsole.h" +#include "qtwindows_additional.h" +#include "qwindowswindow.h" +#include "qwindowsmousehandler.h" +#include "qwindowscursor.h" + +#include <QtGui/QMouseEvent> +#include <QtGui/QPixmap> +#include <QtGui/QPainter> +#include <QtGui/QGuiApplication> + +#include <QtCore/QDebug> +#include <QtCore/QPoint> + +#include <shlobj.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsDropMimeData + \brief Special mime data class for data retrieval from Drag operations. + + Implementation of QWindowsInternalMimeDataBase which retrieves the + current drop data object from QWindowsDrag. + + \sa QWindowsDrag + \ingroup qt-lighthouse-win +*/ + +IDataObject *QWindowsDropMimeData::retrieveDataObject() const +{ + return QWindowsDrag::instance()->dropDataObject(); +} + +static inline Qt::DropActions translateToQDragDropActions(DWORD pdwEffects) +{ + Qt::DropActions actions = Qt::IgnoreAction; + if (pdwEffects & DROPEFFECT_LINK) + actions |= Qt::LinkAction; + if (pdwEffects & DROPEFFECT_COPY) + actions |= Qt::CopyAction; + if (pdwEffects & DROPEFFECT_MOVE) + actions |= Qt::MoveAction; + return actions; +} + +static inline Qt::DropAction translateToQDragDropAction(DWORD pdwEffect) +{ + if (pdwEffect & DROPEFFECT_LINK) + return Qt::LinkAction; + if (pdwEffect & DROPEFFECT_COPY) + return Qt::CopyAction; + if (pdwEffect & DROPEFFECT_MOVE) + return Qt::MoveAction; + return Qt::IgnoreAction; +} + +static inline DWORD translateToWinDragEffects(Qt::DropActions action) +{ + DWORD effect = DROPEFFECT_NONE; + if (action & Qt::LinkAction) + effect |= DROPEFFECT_LINK; + if (action & Qt::CopyAction) + effect |= DROPEFFECT_COPY; + if (action & Qt::MoveAction) + effect |= DROPEFFECT_MOVE; + return effect; +} + +static inline Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState) +{ + Qt::KeyboardModifiers modifiers = Qt::NoModifier; + + if (keyState & MK_SHIFT) + modifiers |= Qt::ShiftModifier; + if (keyState & MK_CONTROL) + modifiers |= Qt::ControlModifier; + if (keyState & MK_ALT) + modifiers |= Qt::AltModifier; + + return modifiers; +} + +/*! + \class QWindowsOleDropSource + \brief Implementation of IDropSource + + Used for drag operations. + + \sa QWindowsDrag + \ingroup qt-lighthouse-win +*/ + +class QWindowsOleDropSource : public IDropSource +{ +public: + QWindowsOleDropSource(); + virtual ~QWindowsOleDropSource(); + + void createCursors(); + + // IUnknown methods + STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj); + STDMETHOD_(ULONG,AddRef)(void); + STDMETHOD_(ULONG,Release)(void); + + // IDropSource methods + STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState); + STDMETHOD(GiveFeedback)(DWORD dwEffect); + +private: + typedef QMap <Qt::DropAction, HCURSOR> ActionCursorMap; + + inline void clearCursors(); + + Qt::MouseButtons m_currentButtons; + Qt::DropAction m_currentAction; + ActionCursorMap m_cursors; + + ULONG m_refs; +}; + +QWindowsOleDropSource::QWindowsOleDropSource() : + m_currentButtons(Qt::NoButton), m_currentAction(Qt::IgnoreAction), + m_refs(1) +{ + if (QWindowsContext::verboseOLE) + qDebug("%s", __FUNCTION__); +} + +QWindowsOleDropSource::~QWindowsOleDropSource() +{ + clearCursors(); + if (QWindowsContext::verboseOLE) + qDebug("%s", __FUNCTION__); +} + +void QWindowsOleDropSource::createCursors() +{ + QDragManager *manager = QDragManager::self(); + if (!manager || !manager->object) + return; + const QPixmap pixmap = manager->object->pixmap(); + const bool hasPixmap = !pixmap.isNull(); + if (!hasPixmap && manager->dragPrivate()->customCursors.isEmpty()) + return; + + QList<Qt::DropAction> actions; + actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction; + if (hasPixmap) + actions << Qt::IgnoreAction; + const QPoint hotSpot = manager->object->hotSpot(); + for (int cnum = 0; cnum < actions.size(); ++cnum) { + const QPixmap cpm = manager->dragCursor(actions.at(cnum)); + int w = cpm.width(); + int h = cpm.height(); + + if (hasPixmap) { + const int x1 = qMin(-hotSpot.x(), 0); + const int x2 = qMax(pixmap.width() - hotSpot.x(), cpm.width()); + const int y1 = qMin(-hotSpot.y(), 0); + const int y2 = qMax(pixmap.height() - hotSpot.y(), cpm.height()); + + w = x2 - x1 + 1; + h = y2 - y1 + 1; + } + + const QRect srcRect = pixmap.rect(); + const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); + const QPoint newHotSpot = hotSpot; + QPixmap newCursor(w, h); + if (hasPixmap) { + newCursor.fill(QColor(0, 0, 0, 0)); + QPainter p(&newCursor); + p.drawPixmap(pmDest, pixmap, srcRect); + p.drawPixmap(qMax(0,newHotSpot.x()),qMax(0,newHotSpot.y()),cpm); + } else { + newCursor = cpm; + } + + const int hotX = hasPixmap ? qMax(0,newHotSpot.x()) : 0; + const int hotY = hasPixmap ? qMax(0,newHotSpot.y()) : 0; + + if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newCursor, hotX, hotY)) + m_cursors.insert(actions.at(cnum), sysCursor); + } + if (QWindowsContext::verboseOLE) + qDebug("%s %d cursors", __FUNCTION__, m_cursors.size()); +} + +void QWindowsOleDropSource::clearCursors() +{ + if (!m_cursors.isEmpty()) { + const ActionCursorMap::const_iterator cend = m_cursors.constEnd(); + for (ActionCursorMap::const_iterator it = m_cursors.constBegin(); it != cend; ++it) + DestroyCursor(it.value()); + m_cursors.clear(); + } +} + +//--------------------------------------------------------------------- +// IUnknown Methods +//--------------------------------------------------------------------- + +STDMETHODIMP +QWindowsOleDropSource::QueryInterface(REFIID iid, void FAR* FAR* ppv) +{ + if (iid == IID_IUnknown || iid == IID_IDropSource) { + *ppv = this; + ++m_refs; + return NOERROR; + } + *ppv = NULL; + return ResultFromScode(E_NOINTERFACE); +} + +STDMETHODIMP_(ULONG) +QWindowsOleDropSource::AddRef(void) +{ + return ++m_refs; +} + +STDMETHODIMP_(ULONG) +QWindowsOleDropSource::Release(void) +{ + if (--m_refs == 0) { + delete this; + return 0; + } + return m_refs; +} + +/*! + \brief Check for cancel. +*/ + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) +{ + HRESULT hr = S_OK; + do { + if (fEscapePressed || QWindowsDrag::instance()->dragBeingCancelled()) { + hr = ResultFromScode(DRAGDROP_S_CANCEL); + break; + } + + // grfKeyState is broken on CE & some Windows XP versions, + // therefore we need to check the state manually + if ((GetAsyncKeyState(VK_LBUTTON) == 0) + && (GetAsyncKeyState(VK_MBUTTON) == 0) + && (GetAsyncKeyState(VK_RBUTTON) == 0)) { + hr = ResultFromScode(DRAGDROP_S_DROP); + break; + } + + const Qt::MouseButtons buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); + if (m_currentButtons == Qt::NoButton) { + m_currentButtons = buttons; + } else { + // Button changed: Complete Drop operation. + if (!(m_currentButtons & buttons)) { + hr = ResultFromScode(DRAGDROP_S_DROP); + break; + } + } + + QGuiApplication::processEvents(); + + } while (false); + + QDragManager::self()->willDrop = hr == DRAGDROP_S_DROP; + + if (QWindowsContext::verboseOLE + && (QWindowsContext::verboseOLE > 1 || hr != S_OK)) + qDebug("%s fEscapePressed=%d, grfKeyState=%lu buttons=%d willDrop = %d returns 0x%x", + __FUNCTION__, fEscapePressed,grfKeyState, int(m_currentButtons), + QDragManager::self()->willDrop, int(hr)); + return hr; +} + +/*! + \brief Give feedback: Change cursor accoding to action. +*/ + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) +{ + const Qt::DropAction action = translateToQDragDropAction(dwEffect); + + if (QWindowsContext::verboseOLE > 2) + qDebug("%s dwEffect=%lu, action=%d", __FUNCTION__, dwEffect, action); + + if (m_currentAction != action) { + m_currentAction = action; + QDragManager::self()->emitActionChanged(m_currentAction); + } + + const ActionCursorMap::const_iterator it = m_cursors.constFind(m_currentAction); + if (it != m_cursors.constEnd()) { + SetCursor(it.value()); + return ResultFromScode(S_OK); + } + + return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS); +} + +/*! + \class QWindowsOleDropTarget + \brief Implementation of IDropTarget + + To be registered for each window. Currently, drop sites + are enabled for top levels. The child window handling + (sending DragEnter/Leave, etc) is handled in here. + + \sa QWindowsDrag + \ingroup qt-lighthouse-win +*/ + +QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) : + m_refs(1), m_window(w), m_currentWindow(0), m_chosenEffect(0), m_lastKeyState(0) +{ + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << this << w; +} + +QWindowsOleDropTarget::~QWindowsOleDropTarget() +{ + if (QWindowsContext::verboseOLE) + qDebug("%s %p", __FUNCTION__, this); +} + +STDMETHODIMP +QWindowsOleDropTarget::QueryInterface(REFIID iid, void FAR* FAR* ppv) +{ + if (iid == IID_IUnknown || iid == IID_IDropTarget) { + *ppv = this; + AddRef(); + return NOERROR; + } + *ppv = NULL; + return ResultFromScode(E_NOINTERFACE); +} + +STDMETHODIMP_(ULONG) +QWindowsOleDropTarget::AddRef(void) +{ + return ++m_refs; +} + +STDMETHODIMP_(ULONG) +QWindowsOleDropTarget::Release(void) +{ + if (--m_refs == 0) { + delete this; + return 0; + } + return m_refs; +} + +QWindow *QWindowsOleDropTarget::findDragOverWindow(const POINTL &pt) const +{ + if (QWindowsWindow *child = + QWindowsWindow::baseWindowOf(m_window)->childAtScreenPoint(QPoint(pt.x, pt.y))) + return child->window(); + return m_window; +} + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, + POINTL pt, LPDWORD pdwEffect) +{ + if (QWindowsContext::verboseOLE) + qDebug("%s widget=%p key=%lu, pt=%ld,%ld", __FUNCTION__, m_window, grfKeyState, pt.x, pt.y); + + QWindowsDrag::instance()->setDropDataObject(pDataObj); + pDataObj->AddRef(); + m_currentWindow = m_window; + sendDragEnterEvent(m_window, grfKeyState, pt, pdwEffect); + *pdwEffect = m_chosenEffect; + return NOERROR; +} + +void QWindowsOleDropTarget::sendDragEnterEvent(QWindow *dragEnterWidget, + DWORD grfKeyState, + POINTL pt, LPDWORD pdwEffect) +{ + Q_ASSERT(dragEnterWidget); + + m_lastPoint = QWindowsGeometryHint::mapFromGlobal(dragEnterWidget, QPoint(pt.x,pt.y)); + m_lastKeyState = grfKeyState; + + m_chosenEffect = DROPEFFECT_NONE; + + QDragManager *manager = QDragManager::self(); + QMimeData *md = manager->dropData(); + const Qt::MouseButtons mouseButtons + = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); + const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); + const Qt::KeyboardModifiers keyMods = toQtKeyboardModifiers(grfKeyState); + QDragEnterEvent enterEvent(m_lastPoint, actions, md, mouseButtons, keyMods); + QGuiApplication::sendEvent(m_currentWindow, &enterEvent); + m_answerRect = enterEvent.answerRect(); + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << " sent drag enter to " << m_window + << *md << " actions=" << actions + << " mods=" << keyMods << " accepted: " + << enterEvent.isAccepted(); + + if (enterEvent.isAccepted()) + m_chosenEffect = translateToWinDragEffects(enterEvent.dropAction()); + // Documentation states that a drag move event is sent immediately after + // a drag enter event. This will honor widgets overriding dragMoveEvent only: + if (enterEvent.isAccepted()) { + QDragMoveEvent moveEvent(m_lastPoint, actions, md, mouseButtons, keyMods); + m_answerRect = enterEvent.answerRect(); + moveEvent.setDropAction(enterEvent.dropAction()); + moveEvent.accept(); // accept by default, since enter event was accepted. + + QGuiApplication::sendEvent(dragEnterWidget, &moveEvent); + if (moveEvent.isAccepted()) { + m_answerRect = moveEvent.answerRect(); + m_chosenEffect = translateToWinDragEffects(moveEvent.dropAction()); + } else { + m_chosenEffect = DROPEFFECT_NONE; + } + } +} + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) +{ + QWindow *dragOverWindow = findDragOverWindow(pt); + + const QPoint tmpPoint = QWindowsGeometryHint::mapFromGlobal(dragOverWindow, QPoint(pt.x,pt.y)); + // see if we should compress this event + if ((tmpPoint == m_lastPoint || m_answerRect.contains(tmpPoint)) + && m_lastKeyState == grfKeyState) { + *pdwEffect = m_chosenEffect; + return NOERROR; + } + + if (QWindowsContext::verboseOLE > 1) + qDebug().nospace() << '>' << __FUNCTION__ << ' ' << m_window << " current " + << dragOverWindow << " key=" << grfKeyState + << " pt=" <<pt.x << ',' << pt.y; + + if (dragOverWindow != m_currentWindow) { + QPointer<QWindow> dragOverWindowGuard(dragOverWindow); + // Send drag leave event to the previous drag widget. + // Drag-Over widget might be deleted in DragLeave, + // (tasktracker 218353). + QDragLeaveEvent dragLeave; + if (m_currentWindow) + QGuiApplication::sendEvent(m_currentWindow, &dragLeave); + if (!dragOverWindowGuard) { + dragOverWindow = findDragOverWindow(pt); + } + // Send drag enter event to the current drag widget. + m_currentWindow = dragOverWindow; + sendDragEnterEvent(dragOverWindow, grfKeyState, pt, pdwEffect); + } + + QDragManager *manager = QDragManager::self(); + QMimeData *md = manager->dropData(); + + const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); + + QDragMoveEvent oldEvent(m_lastPoint, actions, md, + QWindowsMouseHandler::keyStateToMouseButtons(m_lastKeyState), + toQtKeyboardModifiers(m_lastKeyState)); + + m_lastPoint = tmpPoint; + m_lastKeyState = grfKeyState; + + QDragMoveEvent e(tmpPoint, actions, md, + QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState), + toQtKeyboardModifiers(grfKeyState)); + if (m_chosenEffect != DROPEFFECT_NONE) { + if (oldEvent.dropAction() == e.dropAction() && + oldEvent.keyboardModifiers() == e.keyboardModifiers()) + e.setDropAction(translateToQDragDropAction(m_chosenEffect)); + e.accept(); + } + QGuiApplication::sendEvent(dragOverWindow, &e); + + m_answerRect = e.answerRect(); + if (e.isAccepted()) + m_chosenEffect = translateToWinDragEffects(e.dropAction()); + else + m_chosenEffect = DROPEFFECT_NONE; + *pdwEffect = m_chosenEffect; + + if (QWindowsContext::verboseOLE > 1) + qDebug("<%s effect=0x%lx", __FUNCTION__, m_chosenEffect); + return NOERROR; +} + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropTarget::DragLeave() +{ + if (QWindowsContext::verboseOLE) + qDebug().nospace() <<__FUNCTION__ << ' ' << m_window; + + m_currentWindow = 0; + QDragLeaveEvent e; + QGuiApplication::sendEvent(m_window, &e); + QWindowsDrag::instance()->releaseDropDataObject(); + + return NOERROR; +} + +#define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, + POINTL pt, LPDWORD pdwEffect) +{ + QWindow *dropWindow = findDragOverWindow(pt); + + if (QWindowsContext::verboseOLE) + qDebug().nospace() << __FUNCTION__ << ' ' << m_window + << " on " << dropWindow + << " keys=" << grfKeyState << " pt=" + << pt.x << ',' << pt.y; + + m_lastPoint = QWindowsGeometryHint::mapFromGlobal(dropWindow, QPoint(pt.x,pt.y)); + // grfKeyState does not all ways contain button state in the drop so if + // it doesn't then use the last known button state; + if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0) + grfKeyState |= m_lastKeyState & KEY_STATE_BUTTON_MASK; + m_lastKeyState = grfKeyState; + + QWindowsDrag *windowsDrag = QWindowsDrag::instance(); + QDragManager *manager = QDragManager::self(); + QMimeData *md = manager->dropData(); + QDropEvent e(m_lastPoint, translateToQDragDropActions(*pdwEffect), md, + QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState), + toQtKeyboardModifiers(grfKeyState)); + if (m_chosenEffect != DROPEFFECT_NONE) + e.setDropAction(translateToQDragDropAction(m_chosenEffect)); + + QGuiApplication::sendEvent(dropWindow, &e); + if (m_chosenEffect != DROPEFFECT_NONE) + e.accept(); + + if (e.isAccepted()) { + if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) { + if (e.dropAction() == Qt::MoveAction) + m_chosenEffect = DROPEFFECT_MOVE; + else + m_chosenEffect = DROPEFFECT_COPY; + HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD)); + if (hData) { + DWORD *moveEffect = (DWORD *)GlobalLock(hData);; + *moveEffect = DROPEFFECT_MOVE; + GlobalUnlock(hData); + STGMEDIUM medium; + memset(&medium, 0, sizeof(STGMEDIUM)); + medium.tymed = TYMED_HGLOBAL; + medium.hGlobal = hData; + FORMATETC format; + format.cfFormat = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); + format.tymed = TYMED_HGLOBAL; + format.ptd = 0; + format.dwAspect = 1; + format.lindex = -1; + windowsDrag->dropDataObject()->SetData(&format, &medium, true); + } + } else { + m_chosenEffect = translateToWinDragEffects(e.dropAction()); + } + } else { + m_chosenEffect = DROPEFFECT_NONE; + } + *pdwEffect = m_chosenEffect; + + windowsDrag->releaseDropDataObject(); + return NOERROR; +} + +/*! + \class QWindowsDrag + \brief Windows drag implementation. + + \ingroup qt-lighthouse-win +*/ + +QWindowsDrag::QWindowsDrag() : m_dropDataObject(0), m_dragBeingCancelled(false) +{ +} + +QWindowsDrag::~QWindowsDrag() +{ +} + +void QWindowsDrag::startDrag() +{ + // TODO: Accessibility handling? + QDragManager *dragManager = QDragManager::self(); + QMimeData *dropData = dragManager->dropData(); + m_dragBeingCancelled = false; + + DWORD resultEffect; + QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(); + windowDropSource->createCursors(); + QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData); + const Qt::DropActions possibleActions = dragManager->possible_actions; + const DWORD allowedEffects = translateToWinDragEffects(possibleActions); + if (QWindowsContext::verboseOLE) + qDebug(">%s possible Actions=%x, effects=0x%lx", __FUNCTION__, + int(possibleActions), allowedEffects); + const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect); + const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect(); + Qt::DropAction ret = Qt::IgnoreAction; + if (r == DRAGDROP_S_DROP) { + if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) { + ret = Qt::TargetMoveAction; + resultEffect = DROPEFFECT_MOVE; + } else { + ret = translateToQDragDropAction(resultEffect); + } + // Force it to be a copy if an unsupported operation occurred. + // This indicates a bug in the drop target. + if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects)) + ret = Qt::CopyAction; + } else { + dragManager->setCurrentTarget(0); + } + + // clean up + dropDataObject->releaseQt(); + dropDataObject->Release(); // Will delete obj if refcount becomes 0 + windowDropSource->Release(); // Will delete src if refcount becomes 0 + if (QWindowsContext::verboseOLE) + qDebug("<%s allowedEffects=0x%lx, reportedPerformedEffect=0x%lx, resultEffect=0x%lx, hr=0x%x, dropAction=%d", + __FUNCTION__, allowedEffects, reportedPerformedEffect, resultEffect, int(r), ret); +} + +void QWindowsDrag::move(const QMouseEvent *me) +{ + const QPoint pos = me->pos(); + if (QWindowsContext::verboseOLE) + qDebug("%s %d %d", __FUNCTION__, pos.x(), pos.y()); +} + +void QWindowsDrag::drop(const QMouseEvent *me) +{ + const QPoint pos = me->pos(); + if (QWindowsContext::verboseOLE) + qDebug("%s %d %d", __FUNCTION__, pos.x(), pos.y()); +} + +void QWindowsDrag::cancel() +{ + // TODO: Accessibility handling? + if (QWindowsContext::verboseOLE) + qDebug("%s", __FUNCTION__); + m_dragBeingCancelled = true; +} + +QWindowsDrag *QWindowsDrag::instance() +{ + return static_cast<QWindowsDrag *>(QWindowsIntegration::instance()->drag()); +} + +void QWindowsDrag::releaseDropDataObject() +{ + if (QWindowsContext::verboseOLE) + qDebug("%s %p", __FUNCTION__, m_dropDataObject); + if (m_dropDataObject) { + m_dropDataObject->Release(); + m_dropDataObject = 0; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h new file mode 100644 index 0000000000..6e6ebe0424 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsdrag.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSDRAG_H +#define QWINDOWSDRAG_H + +#include "qwindowsinternalmimedata.h" + +#include <QtGui/QPlatformDrag> + +QT_BEGIN_NAMESPACE + +class QWindowsDropMimeData : public QWindowsInternalMimeData { +public: + QWindowsDropMimeData() {} + virtual IDataObject *retrieveDataObject() const; +}; + +class QWindowsOleDropTarget : public IDropTarget +{ +public: + explicit QWindowsOleDropTarget(QWindow *w); + virtual ~QWindowsOleDropTarget(); + + // IUnknown methods + STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + + // IDropTarget methods + STDMETHOD(DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); + STDMETHOD(DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); + STDMETHOD(DragLeave)(); + STDMETHOD(Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); + +private: + inline QWindow *findDragOverWindow(const POINTL &pt) const; + void sendDragEnterEvent(QWindow *to, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); + + ULONG m_refs; + QWindow *const m_window; + QWindow *m_currentWindow; + QRect m_answerRect; + QPoint m_lastPoint; + DWORD m_chosenEffect; + DWORD m_lastKeyState; +}; + +class QWindowsDrag : public QPlatformDrag +{ +public: + QWindowsDrag(); + virtual ~QWindowsDrag(); + + virtual QMimeData *platformDropData() { return &m_dropData; } + + virtual void startDrag(); + virtual void move(const QMouseEvent *me); + virtual void drop(const QMouseEvent *me); + virtual void cancel(); + + static QWindowsDrag *instance(); + + IDataObject *dropDataObject() const { return m_dropDataObject; } + void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; } + void releaseDropDataObject(); + + bool dragBeingCancelled() const { return m_dragBeingCancelled; } + +private: + QWindowsDropMimeData m_dropData; + IDataObject *m_dropDataObject; + bool m_dragBeingCancelled; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDRAG_H diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp new file mode 100644 index 0000000000..ea35ab5f9f --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -0,0 +1,950 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsfontdatabase.h" +#include "qwindowscontext.h" +#include "qwindowsfontengine.h" +#include "qwindowsfontenginedirectwrite.h" +#include "qtwindows_additional.h" + +#include <QtGui/QFont> +#include <QtGui/QGuiApplication> + +#include <QtCore/qmath.h> +#include <QtCore/QDebug> + +#if !defined(QT_NO_DIRECTWRITE) +# include <dwrite.h> +# include <d2d1.h> +#endif + +QT_BEGIN_NAMESPACE + +/*! + \struct QWindowsFontEngineData + \brief Static constant data shared by the font engines. + \ingroup qt-lighthouse-win +*/ + +QWindowsFontEngineData::QWindowsFontEngineData() +#if !defined(QT_NO_DIRECTWRITE) + : directWriteFactory(0) + , directWriteGdiInterop(0) +#endif +{ + // from qapplication_win.cpp + UINT result = 0; + if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0)) + clearTypeEnabled = (result == FE_FONTSMOOTHINGCLEARTYPE); + + int winSmooth; + if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0)) { + fontSmoothingGamma = winSmooth / qreal(1000.0); + } else { + fontSmoothingGamma = 1.0; + } + + // Safeguard ourselves against corrupt registry values... + if (fontSmoothingGamma > 5 || fontSmoothingGamma < 1) + fontSmoothingGamma = qreal(1.4); + + const qreal gray_gamma = 2.31; + for (int i=0; i<256; ++i) + pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047)); + + HDC displayDC = GetDC(0); + hdc = CreateCompatibleDC(displayDC); + ReleaseDC(0, displayDC); +} + +QWindowsFontEngineData::~QWindowsFontEngineData() +{ + if (hdc) + ReleaseDC(0, hdc); +#if !defined(QT_NO_DIRECTWRITE) + if (directWriteGdiInterop) + directWriteGdiInterop->Release(); + if (directWriteFactory) + directWriteFactory->Release(); +#endif +} + +#if !defined(QT_NO_DIRECTWRITE) +static inline bool initDirectWrite(QWindowsFontEngineData *d) +{ + if (!d->directWriteFactory) { + const HRESULT hr = DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast<IUnknown **>(&d->directWriteFactory) + ); + if (FAILED(hr)) { + qErrnoWarning("%s: DWriteCreateFactory failed", __FUNCTION__); + return false; + } + } + if (!d->directWriteGdiInterop) { + const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__); + return false; + } + } + return true; +} + +#endif // !defined(QT_NO_DIRECTWRITE) + +/*! + \class QWindowsFontDatabase + \brief Font database for Windows + + \note The Qt 4.8 WIndows font database employed a mechanism of + delayed population of the database again passing a font name + to EnumFontFamiliesEx(), working around the fact that + EnumFontFamiliesEx() does not list all fonts by default. + This should be introduced to Lighthouse as well? + + \ingroup qt-lighthouse-win +*/ + +QDebug operator<<(QDebug d, const QFontDef &def) +{ + d.nospace() << "Family=" << def.family << " Stylename=" << def.styleName + << " pointsize=" << def.pointSize << " pixelsize=" << def.pixelSize + << " styleHint=" << def.styleHint << " weight=" << def.weight + << " stretch=" << def.stretch << " hintingPreference=" + << def.hintingPreference << ' '; + return d; +} + +/* From QFontDatabase.cpp, qt_determine_writing_systems_from_truetype_bits(). + * Fixme: Make public? */ + +// see the Unicode subset bitfields in the MSDN docs +static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { + // Any, + { 127, 127 }, + // Latin, + { 0, 127 }, + // Greek, + { 7, 127 }, + // Cyrillic, + { 9, 127 }, + // Armenian, + { 10, 127 }, + // Hebrew, + { 11, 127 }, + // Arabic, + { 13, 127 }, + // Syriac, + { 71, 127 }, + //Thaana, + { 72, 127 }, + //Devanagari, + { 15, 127 }, + //Bengali, + { 16, 127 }, + //Gurmukhi, + { 17, 127 }, + //Gujarati, + { 18, 127 }, + //Oriya, + { 19, 127 }, + //Tamil, + { 20, 127 }, + //Telugu, + { 21, 127 }, + //Kannada, + { 22, 127 }, + //Malayalam, + { 23, 127 }, + //Sinhala, + { 73, 127 }, + //Thai, + { 24, 127 }, + //Lao, + { 25, 127 }, + //Tibetan, + { 70, 127 }, + //Myanmar, + { 74, 127 }, + // Georgian, + { 26, 127 }, + // Khmer, + { 80, 127 }, + // SimplifiedChinese, + { 126, 127 }, + // TraditionalChinese, + { 126, 127 }, + // Japanese, + { 126, 127 }, + // Korean, + { 56, 127 }, + // Vietnamese, + { 0, 127 }, // same as latin1 + // Other, + { 126, 127 }, + // Ogham, + { 78, 127 }, + // Runic, + { 79, 127 }, + // Nko, + { 14, 127 }, +}; + +enum +{ + SimplifiedChineseCsbBit = 18, + TraditionalChineseCsbBit = 20, + JapaneseCsbBit = 17, + KoreanCsbBit = 21 +}; + +static inline void writingSystemsFromTrueTypeBits(quint32 unicodeRange[4], + quint32 codePageRange[2], + QSupportedWritingSystems *ws) +{ + bool hasScript = false; + for(int i = 0; i < QFontDatabase::WritingSystemsCount; i++) { + int bit = requiredUnicodeBits[i][0]; + int index = bit/32; + int flag = 1 << (bit&31); + if (bit != 126 && unicodeRange[index] & flag) { + bit = requiredUnicodeBits[i][1]; + index = bit/32; + + flag = 1 << (bit&31); + if (bit == 127 || unicodeRange[index] & flag) { + ws->setSupported(QFontDatabase::WritingSystem(i), true); + hasScript = true; + } + } + } + if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) { + ws->setSupported(QFontDatabase::SimplifiedChinese, true); + hasScript = true; + } + if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) { + ws->setSupported(QFontDatabase::TraditionalChinese, true); + hasScript = true; + } + if(codePageRange[0] & (1 << JapaneseCsbBit)) { + ws->setSupported(QFontDatabase::Japanese, true); + hasScript = true; + //qDebug("font %s supports Japanese", familyName.latin1()); + } + if(codePageRange[0] & (1 << KoreanCsbBit)) { + ws->setSupported(QFontDatabase::Korean, true); + hasScript = true; + } + if (!hasScript) + ws->setSupported(QFontDatabase::Symbol, true); +} + +// convert 0 ~ 1000 integer to QFont::Weight +static inline QFont::Weight weightFromInteger(long weight) +{ + if (weight < 400) + return QFont::Light; + if (weight < 600) + return QFont::Normal; + if (weight < 700) + return QFont::DemiBold; + if (weight < 800) + return QFont::Bold; + return QFont::Black; +} + +static inline QFontDatabase::WritingSystem writingSystemFromScript(const QString &scriptName) +{ + if (scriptName == QStringLiteral("Western") + || scriptName == QStringLiteral("Baltic") + || scriptName == QStringLiteral("Central European") + || scriptName == QStringLiteral("Turkish") + || scriptName == QStringLiteral("Vietnamese") + || scriptName == QStringLiteral("OEM/Dos")) + return QFontDatabase::Latin; + if (scriptName == QStringLiteral("Thai")) + return QFontDatabase::Thai; + if (scriptName == QStringLiteral("Symbol") + || scriptName == QStringLiteral("Other")) + return QFontDatabase::Symbol; + if (scriptName == QStringLiteral("CHINESE_GB2312")) + return QFontDatabase::SimplifiedChinese; + if (scriptName == QStringLiteral("CHINESE_BIG5")) + return QFontDatabase::TraditionalChinese; + if (scriptName == QStringLiteral("Cyrillic")) + return QFontDatabase::Cyrillic; + if (scriptName == QStringLiteral("Hangul")) + return QFontDatabase::Korean; + if (scriptName == QStringLiteral("Hebrew")) + return QFontDatabase::Hebrew; + if (scriptName == QStringLiteral("Greek")) + return QFontDatabase::Greek; + if (scriptName == QStringLiteral("Japanese")) + return QFontDatabase::Japanese; + if (scriptName == QStringLiteral("Arabic")) + return QFontDatabase::Arabic; + return QFontDatabase::Any; +} + +static bool addFontToDatabase(QString familyName, const QString &scriptName, + const TEXTMETRIC *textmetric, + const FONTSIGNATURE *signature, + int type) +{ + // the "@family" fonts are just the same as "family". Ignore them. + if (familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QStringLiteral("WST_"))) + return false; + + static const int SMOOTH_SCALABLE = 0xffff; + const QString foundryName; // No such concept. + const NEWTEXTMETRIC *tm = (NEWTEXTMETRIC *)textmetric; + const bool fixed = !(tm->tmPitchAndFamily & TMPF_FIXED_PITCH); + const bool ttf = (tm->tmPitchAndFamily & TMPF_TRUETYPE); + const bool scalable = tm->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE); + const int size = scalable ? SMOOTH_SCALABLE : tm->tmHeight; + const QFont::Style style = tm->tmItalic ? QFont::StyleItalic : QFont::StyleNormal; + const bool antialias = false; + const QFont::Weight weight = weightFromInteger(tm->tmWeight); + const QFont::Stretch stretch = QFont::Unstretched; + + Q_UNUSED(fixed) + + if (QWindowsContext::verboseFonts > 2) { + QDebug nospace = qDebug().nospace(); + nospace << __FUNCTION__ << familyName << scriptName + << "TTF=" << ttf; + if (type & DEVICE_FONTTYPE) + nospace << " DEVICE"; + if (type & RASTER_FONTTYPE) + nospace << " RASTER"; + if (type & TRUETYPE_FONTTYPE) + nospace << " TRUETYPE"; + nospace << " scalable=" << scalable << " Size=" << size + << " Style=" << style << " Weight=" << weight + << " stretch=" << stretch; + } + +/* Fixme: omitted for the moment + if(ttf && localizedName(familyName) && family->english_name.isEmpty()) + family->english_name = getEnglishName(familyName); +*/ + QSupportedWritingSystems writingSystems; + if (type & TRUETYPE_FONTTYPE) { + quint32 unicodeRange[4] = { + signature->fsUsb[0], signature->fsUsb[1], + signature->fsUsb[2], signature->fsUsb[3] + }; + quint32 codePageRange[2] = { + signature->fsCsb[0], signature->fsCsb[1] + }; + writingSystemsFromTrueTypeBits(unicodeRange, codePageRange, &writingSystems); + // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains + // the symbol for Baht, and Windows thus reports that it supports the Thai script. + // Since it's the default UI font on this platform, most widgets will be unable to + // display Thai text by default. As a temporary work around, we special case Segoe UI + // and remove the Thai script from its list of supported writing systems. + if (writingSystems.supported(QFontDatabase::Thai) && + familyName == QStringLiteral("Segoe UI")) + writingSystems.setSupported(QFontDatabase::Thai, false); + } else { + const QFontDatabase::WritingSystem ws = writingSystemFromScript(scriptName); + if (ws != QFontDatabase::Any) + writingSystems.setSupported(ws); + } + + QPlatformFontDatabase::registerFont(familyName, foundryName, weight, + style, stretch, antialias, scalable, size, writingSystems, 0); + // add fonts windows can generate for us: + if (weight <= QFont::DemiBold) + QPlatformFontDatabase::registerFont(familyName, foundryName, QFont::Bold, + style, stretch, antialias, scalable, size, writingSystems, 0); + if (style != QFont::StyleItalic) + QPlatformFontDatabase::registerFont(familyName, foundryName, weight, + QFont::StyleItalic, stretch, antialias, scalable, size, writingSystems, 0); + if (weight <= QFont::DemiBold && style != QFont::StyleItalic) + QPlatformFontDatabase::registerFont(familyName, foundryName, QFont::Bold, + QFont::StyleItalic, stretch, antialias, scalable, size, writingSystems, 0); + return true; +} + +static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, + int type, LPARAM namesSetIn) +{ + typedef QSet<QString> StringSet; + const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName); + const QString script = QString::fromWCharArray(f->elfScript); + + const FONTSIGNATURE signature = textmetric->ntmFontSig; + + // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is + // identical to a TEXTMETRIC except for the last four members, which we don't use + // anyway + if (addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type)) + reinterpret_cast<StringSet *>(namesSetIn)->insert(familyName); + + // keep on enumerating + return 1; +} + +void QWindowsFontDatabase::populateFontDatabase() +{ + if (m_families.isEmpty()) { + QPlatformFontDatabase::populateFontDatabase(); + populate(); // Called multiple times. + // Work around EnumFontFamiliesEx() not listing the system font, see below. + const QString sysFontFamily = QGuiApplication::font().family(); + if (!m_families.contains(sysFontFamily)) + populate(sysFontFamily); + } +} + +/*! + \brief Populate font database using EnumFontFamiliesEx(). + + Normally, leaving the name empty should enumerate + all fonts, however, system fonts like "MS Shell Dlg 2" + are only found when specifying the name explicitly. +*/ + +void QWindowsFontDatabase::populate(const QString &family) + { + + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << m_families.size() << family; + + HDC dummy = GetDC(0); + LOGFONT lf; + lf.lfCharSet = DEFAULT_CHARSET; + if (family.size() >= LF_FACESIZE) { + qWarning("%s: Unable to enumerate family '%s'.", + __FUNCTION__, qPrintable(family)); + return; + } + wmemcpy(lf.lfFaceName, reinterpret_cast<const wchar_t*>(family.utf16()), + family.size() + 1); + lf.lfPitchAndFamily = 0; + EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFont, + (LPARAM)&m_families, 0); + ReleaseDC(0, dummy); +} + +QWindowsFontDatabase::QWindowsFontDatabase() : + m_fontEngineData(new QWindowsFontEngineData) +{ + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << "Clear type: " + << m_fontEngineData->clearTypeEnabled << "gamma: " + << m_fontEngineData->fontSmoothingGamma; +} + +QWindowsFontDatabase::~QWindowsFontDatabase() +{ +} + +QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, + QUnicodeTables::Script script, + void *handle) +{ + QFontEngine *fe = QWindowsFontDatabase::createEngine(script, fontDef, + 0, QWindowsContext::instance()->defaultDPI(), false, + QStringList(), m_fontEngineData); + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << "FONTDEF" << fontDef << script << fe << handle; + return fe; +} + +QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) +{ + QFontEngine *fe = QPlatformFontDatabase::fontEngine(fontData, pixelSize, hintingPreference); + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fe; + return fe; +} + +QStringList QWindowsFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const +{ + QStringList result = QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script); + if (!result.isEmpty()) + return result; + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << family << style << styleHint + << script << result << m_families.size(); + return result; +} + +QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) +{ + const QStringList result = QPlatformFontDatabase::addApplicationFont(fontData, fileName); + Q_UNIMPLEMENTED(); + return result; +} + +void QWindowsFontDatabase::releaseHandle(void *handle) +{ + if (handle && QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << handle; +} + +QString QWindowsFontDatabase::fontDir() const +{ + const QString result = QPlatformFontDatabase::fontDir(); + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << result; + return result; +} + +HFONT QWindowsFontDatabase::systemFont() +{ + static const HFONT stock_sysfont = (HFONT)GetStockObject(SYSTEM_FONT); + return stock_sysfont; +} + +// Creation functions + +static inline bool scriptRequiresOpenType(int script) +{ + return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) + || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); +} + +static const char *other_tryFonts[] = { + "Arial", + "MS UI Gothic", + "Gulim", + "SimSun", + "PMingLiU", + "Arial Unicode MS", + 0 +}; + +static const char *jp_tryFonts [] = { + "MS UI Gothic", + "Arial", + "Gulim", + "SimSun", + "PMingLiU", + "Arial Unicode MS", + 0 +}; + +static const char *ch_CN_tryFonts [] = { + "SimSun", + "Arial", + "PMingLiU", + "Gulim", + "MS UI Gothic", + "Arial Unicode MS", + 0 +}; + +static const char *ch_TW_tryFonts [] = { + "PMingLiU", + "Arial", + "SimSun", + "Gulim", + "MS UI Gothic", + "Arial Unicode MS", + 0 +}; + +static const char *kr_tryFonts[] = { + "Gulim", + "Arial", + "PMingLiU", + "SimSun", + "MS UI Gothic", + "Arial Unicode MS", + 0 +}; + +static const char **tryFonts = 0; + +QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &request, + HDC fontHdc, int dpi, bool rawMode, + const QStringList &family_list, + const QSharedPointer<QWindowsFontEngineData> &data) +{ + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + + const bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc; + + const HDC hdc = useDevice ? fontHdc : data->hdc; + + bool stockFont = false; + bool preferClearTypeAA = false; + + HFONT hfont = 0; + +#if !defined(QT_NO_DIRECTWRITE) + bool useDirectWrite = (request.hintingPreference == QFont::PreferNoHinting) + || (request.hintingPreference == QFont::PreferVerticalHinting); + IDWriteFont *directWriteFont = 0; +#else + bool useDirectWrite = false; +#endif + + if (rawMode) { // will choose a stock font + int f = SYSTEM_FONT; + const QString fam = request.family.toLower(); + if (fam == QStringLiteral("default") || fam == QStringLiteral("system")) + f = SYSTEM_FONT; + else if (fam == QStringLiteral("system_fixed")) + f = SYSTEM_FIXED_FONT; + else if (fam == QStringLiteral("ansi_fixed")) + f = ANSI_FIXED_FONT; + else if (fam == QStringLiteral("ansi_var")) + f = ANSI_VAR_FONT; + else if (fam == QStringLiteral("device_default")) + f = DEVICE_DEFAULT_FONT; + else if (fam == QStringLiteral("oem_fixed")) + f = OEM_FIXED_FONT; + else if (fam.at(0) == QLatin1Char('#')) + f = fam.right(fam.length()-1).toInt(); + hfont = (HFONT)GetStockObject(f); + if (!hfont) { + qErrnoWarning("%s: GetStockObject failed", __FUNCTION__); + hfont = QWindowsFontDatabase::systemFont(); + } + stockFont = true; + } else { + int hint = FF_DONTCARE; + switch (request.styleHint) { + case QFont::Helvetica: + hint = FF_SWISS; + break; + case QFont::Times: + hint = FF_ROMAN; + break; + case QFont::Courier: + hint = FF_MODERN; + break; + case QFont::OldEnglish: + hint = FF_DECORATIVE; + break; + case QFont::System: + hint = FF_MODERN; + break; + default: + break; + } + + lf.lfHeight = -qRound(request.pixelSize); + lf.lfWidth = 0; + lf.lfEscapement = 0; + lf.lfOrientation = 0; + if (request.weight == 50) + lf.lfWeight = FW_DONTCARE; + else + lf.lfWeight = (request.weight*900)/99; + lf.lfItalic = request.style != QFont::StyleNormal; + lf.lfCharSet = DEFAULT_CHARSET; + + int strat = OUT_DEFAULT_PRECIS; + if (request.styleStrategy & QFont::PreferBitmap) { + strat = OUT_RASTER_PRECIS; + } else if (request.styleStrategy & QFont::PreferDevice) { + strat = OUT_DEVICE_PRECIS; + } else if (request.styleStrategy & QFont::PreferOutline) { + strat = OUT_OUTLINE_PRECIS; + } else if (request.styleStrategy & QFont::ForceOutline) { + strat = OUT_TT_ONLY_PRECIS; + } + + lf.lfOutPrecision = strat; + + int qual = DEFAULT_QUALITY; + + if (request.styleStrategy & QFont::PreferMatch) + qual = DRAFT_QUALITY; + else if (request.styleStrategy & QFont::PreferQuality) + qual = PROOF_QUALITY; + + if (request.styleStrategy & QFont::PreferAntialias) { + if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) { + qual = CLEARTYPE_QUALITY; + preferClearTypeAA = true; + } else { + qual = ANTIALIASED_QUALITY; + } + } else if (request.styleStrategy & QFont::NoAntialias) { + qual = NONANTIALIASED_QUALITY; + } + + lf.lfQuality = qual; + + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfPitchAndFamily = DEFAULT_PITCH | hint; + + QString fam = request.family; + + if(fam.isEmpty()) + fam = QStringLiteral("MS Sans Serif"); + + if ((fam == QStringLiteral("MS Sans Serif")) + && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) { + fam = QStringLiteral("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale + } + if (fam == QStringLiteral("Courier") && !(request.styleStrategy & QFont::PreferBitmap)) + fam = QStringLiteral("Courier New"); + + memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded + + hfont = CreateFontIndirect(&lf); + if (!hfont) + qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__); + + stockFont = (hfont == 0); + bool ttf = false; + int avWidth = 0; + BOOL res; + HGDIOBJ oldObj = SelectObject(hdc, hfont); + + TEXTMETRIC tm; + res = GetTextMetrics(hdc, &tm); + avWidth = tm.tmAveCharWidth; + ttf = tm.tmPitchAndFamily & TMPF_TRUETYPE; + SelectObject(hdc, oldObj); + + if (!ttf || !useDirectWrite) { + useDirectWrite = false; + + if (hfont && (!ttf || request.stretch != 100)) { + DeleteObject(hfont); + if (!res) + qErrnoWarning("QFontEngine::loadEngine: GetTextMetrics failed"); + lf.lfWidth = avWidth * request.stretch/100; + hfont = CreateFontIndirect(&lf); + if (!hfont) + qErrnoWarning("%s: CreateFontIndirect with stretch failed", __FUNCTION__); + } + + if (hfont == 0) { + hfont = (HFONT)GetStockObject(ANSI_VAR_FONT); + stockFont = true; + } + } + +#if !defined(QT_NO_DIRECTWRITE) + else { + // Default to false for DirectWrite (and re-enable once/if everything + // turns out okay) + useDirectWrite = false; + if (initDirectWrite(data.data())) { + const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName)); + memcpy(lf.lfFaceName, nameSubstitute.utf16(), + sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE)); + + HRESULT hr = data->directWriteGdiInterop->CreateFontFromLOGFONT( + &lf, + &directWriteFont); + if (FAILED(hr)) { + qErrnoWarning("%s: CreateFontFromLOGFONT failed", __FUNCTION__); + } else { + DeleteObject(hfont); + useDirectWrite = true; + } + } + } +#endif + } + + QFontEngine *fe = 0; + if (!useDirectWrite) { + QWindowsFontEngine *few = new QWindowsFontEngine(request.family, hfont, stockFont, lf, data); + few->setObjectName(QStringLiteral("QWindowsFontEngine_") + request.family); + if (preferClearTypeAA) + few->glyphFormat = QFontEngineGlyphCache::Raster_RGBMask; + + // Also check for OpenType tables when using complex scripts + // ### TODO: This only works for scripts that require OpenType. More generally + // for scripts that do not require OpenType we should just look at the list of + // supported writing systems in the font's OS/2 table. + if (scriptRequiresOpenType(script)) { + HB_Face hbFace = few->harfbuzzFace(); + if (!hbFace || !hbFace->supported_scripts[script]) { + qWarning(" OpenType support missing for script\n"); + delete few; + return 0; + } + } + + few->initFontInfo(request, fontHdc, dpi); + fe = few; + } + +#if !defined(QT_NO_DIRECTWRITE) + else { + IDWriteFontFace *directWriteFontFace = NULL; + HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace); + if (SUCCEEDED(hr)) { + QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, + request.pixelSize, + data); + fedw->initFontInfo(request, dpi, directWriteFont); + fedw->setObjectName(QStringLiteral("QWindowsFontEngineDirectWrite_") + request.family); + fe = fedw; + } else { + qErrnoWarning("%s: CreateFontFace failed", __FUNCTION__); + } + } + + if (directWriteFont != 0) + directWriteFont->Release(); +#endif + + if(script == QUnicodeTables::Common + && !(request.styleStrategy & QFont::NoFontMerging)) { + QFontDatabase db; + if (!db.writingSystems(request.family).contains(QFontDatabase::Symbol)) { + if(!tryFonts) { + LANGID lid = GetUserDefaultLangID(); + switch( lid&0xff ) { + case LANG_CHINESE: // Chinese (Taiwan) + if ( lid == 0x0804 ) // Taiwan + tryFonts = ch_TW_tryFonts; + else + tryFonts = ch_CN_tryFonts; + break; + case LANG_JAPANESE: + tryFonts = jp_tryFonts; + break; + case LANG_KOREAN: + tryFonts = kr_tryFonts; + break; + default: + tryFonts = other_tryFonts; + break; + } + } + QStringList fm = QFontDatabase().families(); + QStringList list = family_list; + const char **tf = tryFonts; + while(tf && *tf) { + if(fm.contains(QLatin1String(*tf))) + list << QLatin1String(*tf); + ++tf; + } + QFontEngine *mfe = new QWindowsMultiFontEngine(fe, list); + mfe->setObjectName(QStringLiteral("QWindowsMultiFontEngine_") + request.family); + mfe->fontDef = fe->fontDef; + fe = mfe; + } + } + return fe; +} + +static inline int verticalDPI() +{ + return GetDeviceCaps(QWindowsContext::instance()->displayContext(), LOGPIXELSY); +} + +QFont QWindowsFontDatabase::defaultFont() const +{ + LOGFONT lf; + GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf); + QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(lf); + // "MS Shell Dlg 2" is the correct system font >= Win2k + if (systemFont.family() == QStringLiteral("MS Shell Dlg")) + systemFont.setFamily(QStringLiteral("MS Shell Dlg 2")); + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << systemFont; + return systemFont; +} + +QHash<QByteArray, QFont> QWindowsFontDatabase::defaultFonts() const +{ + QHash<QByteArray, QFont> result; + NONCLIENTMETRICS ncm; + ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); + + const int verticalRes = verticalDPI(); + + const QFont menuFont = LOGFONT_to_QFont(ncm.lfMenuFont, verticalRes); + const QFont messageFont = LOGFONT_to_QFont(ncm.lfMessageFont, verticalRes); + const QFont statusFont = LOGFONT_to_QFont(ncm.lfStatusFont, verticalRes); + const QFont titleFont = LOGFONT_to_QFont(ncm.lfCaptionFont, verticalRes); + + LOGFONT lfIconTitleFont; + SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); + const QFont iconTitleFont = LOGFONT_to_QFont(lfIconTitleFont, verticalRes); + + result.insert(QByteArray("QMenu"), menuFont); + result.insert(QByteArray("QMenuBar"), menuFont); + result.insert(QByteArray("QMessageBox"), messageFont); + result.insert(QByteArray("QTipLabel"), statusFont); + result.insert(QByteArray("QStatusBar"), statusFont); + result.insert(QByteArray("Q3TitleBar"), titleFont); + result.insert(QByteArray("QWorkspaceTitleBar"), titleFont); + result.insert(QByteArray("QAbstractItemView"), iconTitleFont); + result.insert(QByteArray("QDockWidgetTitle"), iconTitleFont); + if (QWindowsContext::verboseFonts) { + typedef QHash<QByteArray, QFont>::const_iterator CIT; + QDebug nsp = qDebug().nospace(); + nsp << __FUNCTION__ << " DPI=" << verticalRes << "\n"; + const CIT cend = result.constEnd(); + for (CIT it = result.constBegin(); it != cend; ++it) + nsp << it.key() << ' ' << it.value() << '\n'; + } + return result; +} + +QFont QWindowsFontDatabase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In) +{ + if (verticalDPI_In <= 0) + verticalDPI_In = verticalDPI(); + QFont qFont(QString::fromWCharArray(logFont.lfFaceName)); + qFont.setItalic(logFont.lfItalic); + if (logFont.lfWeight != FW_DONTCARE) + qFont.setWeight(weightFromInteger(logFont.lfWeight)); + const qreal logFontHeight = qAbs(logFont.lfHeight); + qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In)); + qFont.setUnderline(false); + qFont.setOverline(false); + qFont.setStrikeOut(false); + return qFont; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h new file mode 100644 index 0000000000..a80482f6e2 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSFONTDATABASE_H +#define QWINDOWSFONTDATABASE_H + +#include <QtGui/QPlatformFontDatabase> +#include <QtCore/QSharedPointer> +#include "qtwindows_additional.h" + +QT_BEGIN_NAMESPACE + +#if !defined(QT_NO_DIRECTWRITE) + struct IDWriteFactory; + struct IDWriteGdiInterop; +#endif + +class QWindowsFontEngineData +{ + Q_DISABLE_COPY(QWindowsFontEngineData) +public: + QWindowsFontEngineData(); + ~QWindowsFontEngineData(); + + uint pow_gamma[256]; + + bool clearTypeEnabled; + qreal fontSmoothingGamma; + HDC hdc; +#if !defined(QT_NO_DIRECTWRITE) + IDWriteFactory *directWriteFactory; + IDWriteGdiInterop *directWriteGdiInterop; +#endif +}; + +class QWindowsFontDatabase : public QPlatformFontDatabase +{ +public: + QWindowsFontDatabase(); + ~QWindowsFontDatabase(); + + virtual void populateFontDatabase(); + virtual QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); + virtual QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); + virtual QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const; + virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); + virtual void releaseHandle(void *handle); + virtual QString fontDir() const; + + virtual QFont defaultFont() const; + virtual QHash<QByteArray, QFont> defaultFonts() const; + + static QFontEngine *createEngine(int script, const QFontDef &request, + HDC fontHdc, int dpi, bool rawMode, + const QStringList &family_list, + const QSharedPointer<QWindowsFontEngineData> &data); + + static HFONT systemFont(); + static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0); + +private: + void populate(const QString &family = QString()); + QSharedPointer<QWindowsFontEngineData> m_fontEngineData; + QSet<QString> m_families; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSFONTDATABASE_H diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp new file mode 100644 index 0000000000..80d9ed4686 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -0,0 +1,1223 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#if _WIN32_WINNT < 0x0500 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif + +#include "qwindowsfontengine.h" +#include "qwindowsnativeimage.h" +#include "qwindowscontext.h" +#include "qwindowsfontdatabase.h" +#include "qtwindows_additional.h" + +#include <QtGui/private/qtextengine_p.h> // glyph_metrics_t +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/QPaintDevice> +#include <QtGui/QBitmap> +#include <QtGui/QPainter> +#include <QtGui/private/qpainter_p.h> +#include <QtGui/QPaintEngine> +#include <QtGui/private/qpaintengine_raster_p.h> + +#include <QtCore/QtEndian> +#include <QtCore/qmath.h> +#include <QtCore/QThreadStorage> +#include <QtCore/private/qsystemlibrary_p.h> + +#include <QtCore/private/qunicodetables_p.h> +#include <QtCore/QDebug> + +#include <limits.h> + +QT_BEGIN_NAMESPACE + +//### mingw needed define +#ifndef TT_PRIM_CSPLINE +#define TT_PRIM_CSPLINE 3 +#endif + +#ifdef MAKE_TAG +#undef MAKE_TAG +#endif +// GetFontData expects the tags in little endian ;( +#define MAKE_TAG(ch1, ch2, ch3, ch4) (\ + (((quint32)(ch4)) << 24) | \ + (((quint32)(ch3)) << 16) | \ + (((quint32)(ch2)) << 8) | \ + ((quint32)(ch1)) \ + ) + +// common DC for all fonts + +QT_BEGIN_NAMESPACE + +typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT); +static PtrGetCharWidthI ptrGetCharWidthI = 0; +static bool resolvedGetCharWidthI = false; + +static void resolveGetCharWidthI() +{ + if (resolvedGetCharWidthI) + return; + resolvedGetCharWidthI = true; + ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI"); +} + +// defined in qtextengine_win.cpp +typedef void *SCRIPT_CACHE; +typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *); +extern fScriptFreeCache ScriptFreeCache; + +static inline quint32 getUInt(unsigned char *p) +{ + quint32 val; + val = *p++ << 24; + val |= *p++ << 16; + val |= *p++ << 8; + val |= *p; + + return val; +} + +static inline quint16 getUShort(unsigned char *p) +{ + quint16 val; + val = *p++ << 8; + val |= *p; + + return val; +} + +// general font engine + +QFixed QWindowsFontEngine::lineThickness() const +{ + if(lineWidth > 0) + return lineWidth; + + return QFontEngine::lineThickness(); +} + +static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc) +{ + int size; + size = GetOutlineTextMetrics(hdc, 0, 0); + OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)malloc(size); + GetOutlineTextMetrics(hdc, size, otm); + return otm; +} + +void QWindowsFontEngine::getCMap() +{ + ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE); + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + bool symb = false; + if (ttf) { + cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p'))); + int size = 0; + cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()), + cmapTable.size(), &symb, &size); + } + if (!cmap) { + ttf = false; + symb = false; + } + symbol = symb; + designToDevice = 1; + _faceId.index = 0; + if(cmap) { + OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc); + designToDevice = QFixed((int)otm->otmEMSquare)/int(otm->otmTextMetrics.tmHeight); + unitsPerEm = otm->otmEMSquare; + x_height = (int)otm->otmsXHeight; + loadKerningPairs(designToDevice); + _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFullName)).toLatin1(); + lineWidth = otm->otmsUnderscoreSize; + fsType = otm->otmfsType; + free(otm); + } else { + unitsPerEm = tm.tmHeight; + } +} + + +inline unsigned int getChar(const QChar *str, int &i, const int len) +{ + unsigned int uc = str[i].unicode(); + if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) { + uint low = str[i+1].unicode(); + if (low >= 0xdc00 && low < 0xe000) { + uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000; + ++i; + } + } + return uc; +} + +int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const +{ + int i = 0; + int glyph_pos = 0; + if (mirrored) { + if (symbol) { + for (; i < numChars; ++i, ++glyph_pos) { + unsigned int uc = getChar(str, i, numChars); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + if (!glyphs->glyphs[glyph_pos] && uc < 0x100) + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); + } + } else if (ttf) { + for (; i < numChars; ++i, ++glyph_pos) { + unsigned int uc = getChar(str, i, numChars); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc)); + } + } else { + wchar_t first = tm.tmFirstChar; + wchar_t last = tm.tmLastChar; + + for (; i < numChars; ++i, ++glyph_pos) { + uint ucs = QChar::mirroredChar(getChar(str, i, numChars)); + if (ucs >= first && ucs <= last) + glyphs->glyphs[glyph_pos] = ucs; + else + glyphs->glyphs[glyph_pos] = 0; + } + } + } else { + if (symbol) { + for (; i < numChars; ++i, ++glyph_pos) { + unsigned int uc = getChar(str, i, numChars); + glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc); + if(!glyphs->glyphs[glyph_pos] && uc < 0x100) + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); + } + } else if (ttf) { + for (; i < numChars; ++i, ++glyph_pos) { + unsigned int uc = getChar(str, i, numChars); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + } + } else { + wchar_t first = tm.tmFirstChar; + wchar_t last = tm.tmLastChar; + + for (; i < numChars; ++i, ++glyph_pos) { + uint uc = getChar(str, i, numChars); + if (uc >= first && uc <= last) + glyphs->glyphs[glyph_pos] = uc; + else + glyphs->glyphs[glyph_pos] = 0; + } + } + } + glyphs->numGlyphs = glyph_pos; + return glyph_pos; +} + +/*! + \class QWindowsFontEngine + \brief Standard Windows font engine. + \ingroup qt-lighthouse-win + + Will probably be superseded by a common Free Type font engine in Qt 5.X. +*/ + +QWindowsFontEngine::QWindowsFontEngine(const QString &name, + HFONT _hfont, bool stockFontIn, LOGFONT lf, + QSharedPointer<QWindowsFontEngineData> fontEngineData) : + m_fontEngineData(fontEngineData), + _name(name), + hfont(_hfont), + m_logfont(lf), + stockFont(stockFontIn), + ttf(0), + hasOutline(0), + lw(0), + cmap(0), + lbearing(SHRT_MIN), + rbearing(SHRT_MIN), + x_height(-1), + synthesized_flags(-1), + lineWidth(-1), + widthCache(0), + widthCacheSize(0), + designAdvances(0), + designAdvancesSize(0) +{ + if (QWindowsContext::verboseFonts) + qDebug("%s: font='%s', size=%ld", __FUNCTION__, qPrintable(name), lf.lfHeight); + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + fontDef.pixelSize = -lf.lfHeight; + const BOOL res = GetTextMetrics(hdc, &tm); + fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); + if (!res) { + qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__); + ZeroMemory(&tm, sizeof(TEXTMETRIC)); + } + + cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000; + getCMap(); + + if (!resolvedGetCharWidthI) + resolveGetCharWidthI(); +} + +QWindowsFontEngine::~QWindowsFontEngine() +{ + if (designAdvances) + free(designAdvances); + + if (widthCache) + free(widthCache); + + // make sure we aren't by accident still selected + SelectObject(m_fontEngineData->hdc, (HFONT)GetStockObject(SYSTEM_FONT)); + + if (!stockFont) { + if (!DeleteObject(hfont)) + qErrnoWarning("%s: QFontEngineWin: failed to delete non-stock font... failed", __FUNCTION__); + } + if (QWindowsContext::verboseFonts) + if (QWindowsContext::verboseFonts) + qDebug("%s: font='%s", __FUNCTION__, qPrintable(_name)); +} + +HGDIOBJ QWindowsFontEngine::selectDesignFont() const +{ + LOGFONT f = m_logfont; + f.lfHeight = unitsPerEm; + HFONT designFont = CreateFontIndirect(&f); + return SelectObject(m_fontEngineData->hdc, designFont); +} + +bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const +{ + if (*nglyphs < len) { + *nglyphs = len; + return false; + } + + *nglyphs = getGlyphIndexes(str, len, glyphs, flags & QTextEngine::RightToLeft); + + if (flags & QTextEngine::GlyphIndicesOnly) + return true; + + recalcAdvances(glyphs, flags); + return true; +} + +inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width) +{ + if (ptrGetCharWidthI) + ptrGetCharWidthI(hdc, glyph, 1, 0, &width); +} + +void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const +{ + HGDIOBJ oldFont = 0; + HDC hdc = m_fontEngineData->hdc; + if (ttf && (flags & QTextEngine::DesignMetrics)) { + for(int i = 0; i < glyphs->numGlyphs; i++) { + unsigned int glyph = glyphs->glyphs[i]; + if(int(glyph) >= designAdvancesSize) { + int newSize = (glyph + 256) >> 8 << 8; + designAdvances = q_check_ptr((QFixed *)realloc(designAdvances, + newSize*sizeof(QFixed))); + for(int i = designAdvancesSize; i < newSize; ++i) + designAdvances[i] = -1000000; + designAdvancesSize = newSize; + } + if (designAdvances[glyph] < -999999) { + if (!oldFont) + oldFont = selectDesignFont(); + + int width = 0; + calculateTTFGlyphWidth(hdc, glyph, width); + designAdvances[glyph] = QFixed(width) / designToDevice; + } + glyphs->advances_x[i] = designAdvances[glyph]; + glyphs->advances_y[i] = 0; + } + if(oldFont) + DeleteObject(SelectObject(hdc, oldFont)); + } else { + for(int i = 0; i < glyphs->numGlyphs; i++) { + unsigned int glyph = glyphs->glyphs[i]; + + glyphs->advances_y[i] = 0; + + if (glyph >= widthCacheSize) { + int newSize = (glyph + 256) >> 8 << 8; + widthCache = q_check_ptr((unsigned char *)realloc(widthCache, + newSize*sizeof(QFixed))); + memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize); + widthCacheSize = newSize; + } + glyphs->advances_x[i] = widthCache[glyph]; + // font-width cache failed + if (glyphs->advances_x[i] == 0) { + int width = 0; + if (!oldFont) + oldFont = SelectObject(hdc, hfont); + + if (!ttf) { + QChar ch[2] = { ushort(glyph), 0 }; + int chrLen = 1; + if (glyph > 0xffff) { + ch[0] = QChar::highSurrogate(glyph); + ch[1] = QChar::lowSurrogate(glyph); + ++chrLen; + } + SIZE size = {0, 0}; + GetTextExtentPoint32(hdc, (wchar_t *)ch, chrLen, &size); + width = size.cx; + } else { + calculateTTFGlyphWidth(hdc, glyph, width); + } + glyphs->advances_x[i] = width; + // if glyph's within cache range, store it for later + if (width > 0 && width < 0x100) + widthCache[glyph] = width; + } + } + + if (oldFont) + SelectObject(hdc, oldFont); + } +} + +glyph_metrics_t QWindowsFontEngine::boundingBox(const QGlyphLayout &glyphs) +{ + if (glyphs.numGlyphs == 0) + return glyph_metrics_t(); + + QFixed w = 0; + for (int i = 0; i < glyphs.numGlyphs; ++i) + w += glyphs.effectiveAdvance(i); + + return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0); +} + +bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const +{ + Q_ASSERT(metrics != 0); + + HDC hdc = m_fontEngineData->hdc; + + GLYPHMETRICS gm; + DWORD res = 0; + MAT2 mat; + mat.eM11.value = mat.eM22.value = 1; + mat.eM11.fract = mat.eM22.fract = 0; + mat.eM21.value = mat.eM12.value = 0; + mat.eM21.fract = mat.eM12.fract = 0; + + if (t.type() > QTransform::TxTranslate) { + // We need to set the transform using the HDC's world + // matrix rather than using the MAT2 above, because the + // results provided when transforming via MAT2 does not + // match the glyphs that are drawn using a WorldTransform + XFORM xform; + xform.eM11 = t.m11(); + xform.eM12 = t.m12(); + xform.eM21 = t.m21(); + xform.eM22 = t.m22(); + xform.eDx = 0; + xform.eDy = 0; + SetGraphicsMode(hdc, GM_ADVANCED); + SetWorldTransform(hdc, &xform); + } + + uint format = GGO_METRICS; + if (ttf) + format |= GGO_GLYPH_INDEX; + res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat); + + if (t.type() > QTransform::TxTranslate) { + XFORM xform; + xform.eM11 = xform.eM22 = 1; + xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0; + SetWorldTransform(hdc, &xform); + SetGraphicsMode(hdc, GM_COMPATIBLE); + } + + if (res != GDI_ERROR) { + *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y, + (int)gm.gmBlackBoxX, (int)gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY); + return true; + } else { + return false; + } +} + +glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph, const QTransform &t) +{ + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + + glyph_metrics_t glyphMetrics; + bool success = getOutlineMetrics(glyph, t, &glyphMetrics); + + if (!ttf && !success) { + // Bitmap fonts + wchar_t ch = glyph; + ABCFLOAT abc; + GetCharABCWidthsFloat(hdc, ch, ch, &abc); + int width = qRound(abc.abcfB); + + return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t); + } + + return glyphMetrics; +} + +QFixed QWindowsFontEngine::ascent() const +{ + return tm.tmAscent; +} + +QFixed QWindowsFontEngine::descent() const +{ + // ### we subtract 1 to even out the historical +1 in QFontMetrics' + // ### height=asc+desc+1 equation. Fix in Qt5. + return tm.tmDescent - 1; +} + +QFixed QWindowsFontEngine::leading() const +{ + return tm.tmExternalLeading; +} + + +QFixed QWindowsFontEngine::xHeight() const +{ + if(x_height >= 0) + return x_height; + return QFontEngine::xHeight(); +} + +QFixed QWindowsFontEngine::averageCharWidth() const +{ + return tm.tmAveCharWidth; +} + +qreal QWindowsFontEngine::maxCharWidth() const +{ + return tm.tmMaxCharWidth; +} + +enum { max_font_count = 256 }; +static const ushort char_table[] = { + 40, + 67, + 70, + 75, + 86, + 88, + 89, + 91, + 102, + 114, + 124, + 127, + 205, + 645, + 884, + 922, + 1070, + 12386, + 0 +}; + +static const int char_table_entries = sizeof(char_table)/sizeof(ushort); + +#ifndef Q_CC_MINGW +void QWindowsFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing) +{ + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + + if (ttf) + { + ABC abcWidths; + GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths); + if (leftBearing) + *leftBearing = abcWidths.abcA; + if (rightBearing) + *rightBearing = abcWidths.abcC; + } else { + QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing); + } +} +#endif // Q_CC_MINGW + +qreal QWindowsFontEngine::minLeftBearing() const +{ + if (lbearing == SHRT_MIN) + minRightBearing(); // calculates both + + return lbearing; +} + +qreal QWindowsFontEngine::minRightBearing() const +{ + if (rbearing == SHRT_MIN) { + int ml = 0; + int mr = 0; + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + if (ttf) { + ABC *abc = 0; + int n = tm.tmLastChar - tm.tmFirstChar; + if (n <= max_font_count) { + abc = new ABC[n+1]; + GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc); + } else { + abc = new ABC[char_table_entries+1]; + for(int i = 0; i < char_table_entries; i++) + GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i); + n = char_table_entries; + } + ml = abc[0].abcA; + mr = abc[0].abcC; + for (int i = 1; i < n; i++) { + if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) { + ml = qMin(ml,abc[i].abcA); + mr = qMin(mr,abc[i].abcC); + } + } + delete [] abc; + } else { + ABCFLOAT *abc = 0; + int n = tm.tmLastChar - tm.tmFirstChar+1; + if (n <= max_font_count) { + abc = new ABCFLOAT[n]; + GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc); + } else { + abc = new ABCFLOAT[char_table_entries]; + for(int i = 0; i < char_table_entries; i++) + GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i); + n = char_table_entries; + } + float fml = abc[0].abcfA; + float fmr = abc[0].abcfC; + for (int i=1; i<n; i++) { + if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) { + fml = qMin(fml,abc[i].abcfA); + fmr = qMin(fmr,abc[i].abcfC); + } + } + ml = int(fml - 0.9999); + mr = int(fmr - 0.9999); + delete [] abc; + } + lbearing = ml; + rbearing = mr; + } + + return rbearing; +} + + +const char *QWindowsFontEngine::name() const +{ + return 0; +} + +bool QWindowsFontEngine::canRender(const QChar *string, int len) +{ + if (symbol) { + for (int i = 0; i < len; ++i) { + unsigned int uc = getChar(string, i, len); + if (getTrueTypeGlyphIndex(cmap, uc) == 0) { + if (uc < 0x100) { + if (getTrueTypeGlyphIndex(cmap, uc + 0xf000) == 0) + return false; + } else { + return false; + } + } + } + } else if (ttf) { + for (int i = 0; i < len; ++i) { + unsigned int uc = getChar(string, i, len); + if (getTrueTypeGlyphIndex(cmap, uc) == 0) + return false; + } + } else { + while(len--) { + if (tm.tmFirstChar > string->unicode() || tm.tmLastChar < string->unicode()) + return false; + } + } + return true; +} + +QFontEngine::Type QWindowsFontEngine::type() const +{ + return QFontEngine::Win; +} + +static inline double qt_fixed_to_double(const FIXED &p) { + return ((p.value << 16) + p.fract) / 65536.0; +} + +static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) { + return QPointF(qt_fixed_to_double(pt.x) * scale, -qt_fixed_to_double(pt.y) * scale); +} + +#ifndef GGO_UNHINTED +#define GGO_UNHINTED 0x0100 +#endif + +static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, + QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1) +{ + MAT2 mat; + mat.eM11.value = mat.eM22.value = 1; + mat.eM11.fract = mat.eM22.fract = 0; + mat.eM21.value = mat.eM12.value = 0; + mat.eM21.fract = mat.eM12.fract = 0; + uint glyphFormat = GGO_NATIVE; + + if (ttf) + glyphFormat |= GGO_GLYPH_INDEX; + + GLYPHMETRICS gMetric; + memset(&gMetric, 0, sizeof(GLYPHMETRICS)); + int bufferSize = GDI_ERROR; + bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat); + if ((DWORD)bufferSize == GDI_ERROR) { + return false; + } + + void *dataBuffer = new char[bufferSize]; + DWORD ret = GDI_ERROR; + ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat); + if (ret == GDI_ERROR) { + delete [](char *)dataBuffer; + return false; + } + + if(metric) { + // #### obey scale + *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y, + (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY, + gMetric.gmCellIncX, gMetric.gmCellIncY); + } + + int offset = 0; + int headerOffset = 0; + TTPOLYGONHEADER *ttph = 0; + + QPointF oset = position.toPointF(); + while (headerOffset < bufferSize) { + ttph = (TTPOLYGONHEADER*)((char *)dataBuffer + headerOffset); + + QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale)); + path->moveTo(lastPoint + oset); + offset += sizeof(TTPOLYGONHEADER); + TTPOLYCURVE *curve; + while (offset<int(headerOffset + ttph->cb)) { + curve = (TTPOLYCURVE*)((char*)(dataBuffer) + offset); + switch (curve->wType) { + case TT_PRIM_LINE: { + for (int i=0; i<curve->cpfx; ++i) { + QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset; + path->lineTo(p); + } + break; + } + case TT_PRIM_QSPLINE: { + const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1); + QPointF prev(elm.x, elm.y); + QPointF endPoint; + for (int i=0; i<curve->cpfx - 1; ++i) { + QPointF p1 = qt_to_qpointf(curve->apfx[i], scale) + oset; + QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale) + oset; + if (i < curve->cpfx - 2) { + endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2); + } else { + endPoint = p2; + } + + path->quadTo(p1, endPoint); + prev = endPoint; + } + + break; + } + case TT_PRIM_CSPLINE: { + for (int i=0; i<curve->cpfx; ) { + QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale) + oset; + QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale) + oset; + QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale) + oset; + path->cubicTo(p2, p3, p4); + } + break; + } + default: + qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case"); + } + offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX); + } + path->closeSubpath(); + headerOffset += ttph->cb; + } + delete [] (char*)dataBuffer; + + return true; +} + +void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, + QPainterPath *path, QTextItem::RenderFlags) +{ + LOGFONT lf = m_logfont; + // The sign must be negative here to make sure we match against character height instead of + // hinted cell height. This ensures that we get linear matching, and we need this for + // paths since we later on apply a scaling transform to the glyph outline to get the + // font at the correct pixel size. + lf.lfHeight = -unitsPerEm; + lf.lfWidth = 0; + HFONT hf = CreateFontIndirect(&lf); + HDC hdc = m_fontEngineData->hdc; + HGDIOBJ oldfont = SelectObject(hdc, hf); + + for(int i = 0; i < nglyphs; ++i) { + if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0, + qreal(fontDef.pixelSize) / unitsPerEm)) { + // Some windows fonts, like "Modern", are vector stroke + // fonts, which are reported as TMPF_VECTOR but do not + // support GetGlyphOutline, and thus we set this bit so + // that addOutLineToPath can check it and return safely... + hasOutline = false; + break; + } + } + DeleteObject(SelectObject(hdc, oldfont)); +} + +void QWindowsFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, + QPainterPath *path, QTextItem::RenderFlags flags) +{ + if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) { + hasOutline = true; + QFontEngine::addOutlineToPath(x, y, glyphs, path, flags); + if (hasOutline) { + // has_outline is set to false if addGlyphToPath gets + // false from GetGlyphOutline, meaning its not an outline + // font. + return; + } + } + QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags); +} + +QFontEngine::FaceId QWindowsFontEngine::faceId() const +{ + return _faceId; +} + +QT_BEGIN_INCLUDE_NAMESPACE +#include <qdebug.h> +QT_END_INCLUDE_NAMESPACE + +int QWindowsFontEngine::synthesized() const +{ + if(synthesized_flags == -1) { + synthesized_flags = 0; + if(ttf) { + const DWORD HEAD = MAKE_TAG('h', 'e', 'a', 'd'); + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + uchar data[4]; + GetFontData(hdc, HEAD, 44, &data, 4); + USHORT macStyle = getUShort(data); + if (tm.tmItalic && !(macStyle & 2)) + synthesized_flags = SynthesizedItalic; + if (fontDef.stretch != 100 && ttf) + synthesized_flags |= SynthesizedStretch; + if (tm.tmWeight >= 500 && !(macStyle & 1)) + synthesized_flags |= SynthesizedBold; + //qDebug() << "font is" << _name << + // "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags; + } + } + return synthesized_flags; +} + +QFixed QWindowsFontEngine::emSquareSize() const +{ + return unitsPerEm; +} + +QFontEngine::Properties QWindowsFontEngine::properties() const +{ + LOGFONT lf = m_logfont; + lf.lfHeight = unitsPerEm; + HFONT hf = CreateFontIndirect(&lf); + HDC hdc = m_fontEngineData->hdc; + HGDIOBJ oldfont = SelectObject(hdc, hf); + OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc); + Properties p; + p.emSquare = unitsPerEm; + p.italicAngle = otm->otmItalicAngle; + p.postscriptName = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFamilyName)).toLatin1(); + p.postscriptName += QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpStyleName)).toLatin1(); + p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(p.postscriptName); + p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top, + otm->otmrcFontBox.right - otm->otmrcFontBox.left, + otm->otmrcFontBox.top - otm->otmrcFontBox.bottom); + p.ascent = otm->otmAscent; + p.descent = -otm->otmDescent; + p.leading = (int)otm->otmLineGap; + p.capHeight = 0; + p.lineWidth = otm->otmsUnderscoreSize; + free(otm); + DeleteObject(SelectObject(hdc, oldfont)); + return p; +} + +void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) +{ + LOGFONT lf = m_logfont; + lf.lfHeight = unitsPerEm; + int flags = synthesized(); + if(flags & SynthesizedItalic) + lf.lfItalic = false; + lf.lfWidth = 0; + HFONT hf = CreateFontIndirect(&lf); + HDC hdc = m_fontEngineData->hdc; + HGDIOBJ oldfont = SelectObject(hdc, hf); + QFixedPoint p; + p.x = 0; + p.y = 0; + addGlyphToPath(glyph, p, hdc, path, ttf, metrics); + DeleteObject(SelectObject(hdc, oldfont)); +} + +bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const +{ + if (!ttf) + return false; + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + DWORD t = qbswap<quint32>(tag); + *length = GetFontData(hdc, t, 0, buffer, *length); + return *length != GDI_ERROR; +} + +#if !defined(CLEARTYPE_QUALITY) +# define CLEARTYPE_QUALITY 5 +#endif + +QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, int margin, + const QTransform &t, + QImage::Format mask_format) +{ + Q_UNUSED(mask_format) + glyph_metrics_t gm = boundingBox(glyph); + +// printf(" -> for glyph %4x\n", glyph); + + int gx = gm.x.toInt(); + int gy = gm.y.toInt(); + int iw = gm.width.toInt(); + int ih = gm.height.toInt(); + + if (iw <= 0 || iw <= 0) + return 0; + + bool has_transformation = t.type() > QTransform::TxTranslate; + + unsigned int options = ttf ? ETO_GLYPH_INDEX : 0; + XFORM xform; + + if (has_transformation) { + xform.eM11 = t.m11(); + xform.eM12 = t.m12(); + xform.eM21 = t.m21(); + xform.eM22 = t.m22(); + xform.eDx = margin; + xform.eDy = margin; + + HDC hdc = CreateCompatibleDC(QWindowsContext::instance()->displayContext()); + + SetGraphicsMode(hdc, GM_ADVANCED); + SetWorldTransform(hdc, &xform); + HGDIOBJ old_font = SelectObject(hdc, font); + + int ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0); + GLYPHMETRICS tgm; + MAT2 mat; + memset(&mat, 0, sizeof(mat)); + mat.eM11.value = mat.eM22.value = 1; + + if (GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat) == GDI_ERROR) { + qWarning("QWinFontEngine: unable to query transformed glyph metrics..."); + return 0; + } + + iw = tgm.gmBlackBoxX; + ih = tgm.gmBlackBoxY; + + xform.eDx -= tgm.gmptGlyphOrigin.x; + xform.eDy += tgm.gmptGlyphOrigin.y; + + SetGraphicsMode(hdc, GM_COMPATIBLE); + SelectObject(hdc, old_font); + ReleaseDC(0, hdc); + } + QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin + 4, + ih + 2 * margin + 4, + QWindowsNativeImage::systemFormat()); + + /*If cleartype is enabled we use the standard system format even on Windows CE + and not the special textbuffer format we have to use if cleartype is disabled*/ + + ni->image().fill(0xffffffff); + + HDC hdc = ni->hdc(); + + SelectObject(hdc, GetStockObject(NULL_BRUSH)); + SelectObject(hdc, GetStockObject(BLACK_PEN)); + SetTextColor(hdc, RGB(0,0,0)); + SetBkMode(hdc, TRANSPARENT); + SetTextAlign(hdc, TA_BASELINE); + + HGDIOBJ old_font = SelectObject(hdc, font); + + if (has_transformation) { + SetGraphicsMode(hdc, GM_ADVANCED); + SetWorldTransform(hdc, &xform); + ExtTextOut(hdc, 0, 0, options, 0, (LPCWSTR) &glyph, 1, 0); + } else + { + ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, (LPCWSTR) &glyph, 1, 0); + } + + SelectObject(hdc, old_font); + return ni; +} + +QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xform) +{ + HFONT font = hfont; + if (m_fontEngineData->clearTypeEnabled) { + LOGFONT lf = m_logfont; + lf.lfQuality = ANTIALIASED_QUALITY; + font = CreateFontIndirect(&lf); + } + QImage::Format mask_format = QWindowsNativeImage::systemFormat(); + mask_format = QImage::Format_RGB32; + + QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format); + if (mask == 0) + return QImage(); + + QImage indexed(mask->width(), mask->height(), QImage::Format_Indexed8); + + // ### This part is kinda pointless, but we'll crash later if we don't because some + // code paths expects there to be colortables for index8-bit... + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgba(0, 0, 0, i); + indexed.setColorTable(colors); + + // Copy data... Cannot use QPainter here as GDI has messed up the + // Alpha channel of the ni.image pixels... + for (int y=0; y<mask->height(); ++y) { + uchar *dest = indexed.scanLine(y); + if (mask->image().format() == QImage::Format_RGB16) { + const qint16 *src = (qint16 *) ((const QImage &) mask->image()).scanLine(y); + for (int x=0; x<mask->width(); ++x) + dest[x] = 255 - qGray(src[x]); + } else { + const uint *src = (uint *) ((const QImage &) mask->image()).scanLine(y); + for (int x=0; x<mask->width(); ++x) { + if (QWindowsNativeImage::systemFormat() == QImage::Format_RGB16) + dest[x] = 255 - qGray(src[x]); + else + dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.); + } + } + } + + // Cleanup... + delete mask; + if (m_fontEngineData->clearTypeEnabled) { + DeleteObject(font); + } + + return indexed; +} + +#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C +#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D + +QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, int margin, const QTransform &t) +{ + HFONT font = hfont; + + int contrast; + SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0); + SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0); + + QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32); + SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0); + + if (mask == 0) + return QImage(); + + // Gracefully handle the odd case when the display is 16-bit + const QImage source = mask->image().depth() == 32 + ? mask->image() + : mask->image().convertToFormat(QImage::Format_RGB32); + + QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32); + for (int y=0; y<mask->height(); ++y) { + uint *dest = (uint *) rgbMask.scanLine(y); + const uint *src = (uint *) source.scanLine(y); + for (int x=0; x<mask->width(); ++x) { + dest[x] = 0xffffffff - (0x00ffffff & src[x]); + } + } + + delete mask; + + return rgbMask; +} + +QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const +{ + QFontDef request = fontDef; + QString actualFontName = request.family; + if (!uniqueFamilyName.isEmpty()) + request.family = uniqueFamilyName; + request.pixelSize = pixelSize; + + QFontEngine *fontEngine = + QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0, + QWindowsContext::instance()->defaultDPI(), + false, + QStringList(), m_fontEngineData); + if (fontEngine) + fontEngine->fontDef.family = actualFontName; + return fontEngine; +} + +void QWindowsFontEngine::initFontInfo(const QFontDef &request, + HDC fontHdc, + int dpi) +{ + fontDef = request; // most settings are equal + HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : m_fontEngineData->hdc; + SelectObject(dc, hfont); + wchar_t n[64]; + GetTextFace(dc, 64, n); + fontDef.family = QString::fromWCharArray(n); + fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); + if (fontDef.pointSize < 0) { + fontDef.pointSize = fontDef.pixelSize * 72. / dpi; + } else if (fontDef.pixelSize == -1) { + fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.); + } +} + +/*! + \class QWindowsMultiFontEngine + \brief Standard Windows Multi font engine. + \ingroup qt-lighthouse-win + + "Merges" several font engines that have gaps in the + supported writing systems. + + Will probably be superseded by a common Free Type font engine in Qt 5.X. +*/ + +QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *first, const QStringList &fallbacks) + : QFontEngineMulti(fallbacks.size()+1), + fallbacks(fallbacks) +{ + if (QWindowsContext::verboseFonts) + qDebug() << __FUNCTION__ << engines.size() << first << first->fontDef.family << fallbacks; + engines[0] = first; + first->ref.ref(); + fontDef = engines[0]->fontDef; + cache_cost = first->cache_cost; +} + +QWindowsMultiFontEngine::~QWindowsMultiFontEngine() +{ + if (QWindowsContext::verboseFonts) + qDebug("%s", __FUNCTION__); +} + +void QWindowsMultiFontEngine::loadEngine(int at) +{ + Q_ASSERT(at < engines.size()); + Q_ASSERT(engines.at(at) == 0); + + const QString fam = fallbacks.at(at-1); + QWindowsFontEngine *fe = static_cast<QWindowsFontEngine*>(engines.at(0)); + LOGFONT lf = fe->logfont(); + memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded + HFONT hfont = CreateFontIndirect(&lf); + + bool stockFont = false; + if (hfont == 0) { + hfont = (HFONT)GetStockObject(ANSI_VAR_FONT); + stockFont = true; + } + engines[at] = new QWindowsFontEngine(fam, hfont, stockFont, lf, fe->fontEngineData()); + engines[at]->ref.ref(); + engines[at]->fontDef = fontDef; + if (QWindowsContext::verboseFonts) + qDebug("%s %d %s", __FUNCTION__, at, qPrintable(fam)); + + + // TODO: increase cost in QFontCache for the font engine loaded here +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h new file mode 100644 index 0000000000..bed5ecffbd --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSFONTENGINE_H +#define QWINDOWSFONTENGINE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// Enable access to HB_Face in harfbuzz includes included by qfontengine_p.h. +#define QT_BUILD_GUI_LIB +#include <QtGui/private/qfontengine_p.h> +#undef QT_BUILD_GUI_LIB + +#include <QtGui/QImage> +#include <QtCore/QSharedPointer> + +#include "qtwindows_additional.h" + +QT_BEGIN_NAMESPACE + +class QWindowsNativeImage; +class QWindowsFontEngineData; + +class QWindowsFontEngine : public QFontEngine +{ + Q_DISABLE_COPY(QWindowsFontEngine) +public: + QWindowsFontEngine(const QString &name, HFONT, bool, LOGFONT, + QSharedPointer<QWindowsFontEngineData> fontEngineData); + + ~QWindowsFontEngine(); + void initFontInfo(const QFontDef &request, + HDC fontHdc, int dpi); + + virtual QFixed lineThickness() const; + virtual Properties properties() const; + virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics); + virtual FaceId faceId() const; + virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const; + virtual int synthesized() const; + virtual QFixed emSquareSize() const; + + virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; + virtual void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const; + + virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags); + virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, + QPainterPath *path, QTextItem::RenderFlags flags); + + HGDIOBJ selectDesignFont() const; + + virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); + virtual glyph_metrics_t boundingBox(glyph_t g) { return boundingBox(g, QTransform()); } + virtual glyph_metrics_t boundingBox(glyph_t g, const QTransform &t); + + + virtual QFixed ascent() const; + virtual QFixed descent() const; + virtual QFixed leading() const; + virtual QFixed xHeight() const; + virtual QFixed averageCharWidth() const; + virtual qreal maxCharWidth() const; + virtual qreal minLeftBearing() const; + virtual qreal minRightBearing() const; + + virtual const char *name() const; + + bool canRender(const QChar *string, int len); + + Type type() const; + + virtual QImage alphaMapForGlyph(glyph_t t) { return alphaMapForGlyph(t, QTransform()); } + virtual QImage alphaMapForGlyph(glyph_t, const QTransform &xform); + virtual QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform); + + virtual QFontEngine *cloneWithSize(qreal pixelSize) const; + +#ifndef Q_CC_MINGW + virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0); +#endif + + int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, bool mirrored) const; + void getCMap(); + + bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const; + + static QFontEngine *createEngine(int script, const QFontDef &request, + HDC fontHdc, int dpi, bool rawMode, + const QStringList &family_list, + const QSharedPointer<QWindowsFontEngineData> &data); + + QSharedPointer<QWindowsFontEngineData> fontEngineData() const { return m_fontEngineData; } + LOGFONT logfont() const { return m_logfont; } + +private: + QWindowsNativeImage *drawGDIGlyph(HFONT font, glyph_t, int margin, const QTransform &xform, + QImage::Format mask_format); + + const QSharedPointer<QWindowsFontEngineData> m_fontEngineData; + + const QString _name; + QString uniqueFamilyName; + const HFONT hfont; + const LOGFONT m_logfont; + uint stockFont : 1; + uint ttf : 1; + uint hasOutline : 1; + TEXTMETRIC tm; + int lw; + const unsigned char *cmap; + QByteArray cmapTable; + mutable qreal lbearing; + mutable qreal rbearing; + QFixed designToDevice; + int unitsPerEm; + QFixed x_height; + FaceId _faceId; + + mutable int synthesized_flags; + mutable QFixed lineWidth; + mutable unsigned char *widthCache; + mutable uint widthCacheSize; + mutable QFixed *designAdvances; + mutable int designAdvancesSize; +}; + +class QWindowsMultiFontEngine : public QFontEngineMulti +{ +public: + QWindowsMultiFontEngine(QFontEngine *first, const QStringList &fallbacks); + virtual ~QWindowsMultiFontEngine(); + void loadEngine(int at); + + QStringList fallbacks; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSFONTENGINE_H diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp new file mode 100644 index 0000000000..46f0b0c336 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -0,0 +1,737 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_DIRECTWRITE + +#include "qwindowsfontenginedirectwrite.h" +#include "qwindowsfontdatabase.h" +#include "qwindowscontext.h" + +#include <QtCore/QSettings> +#include <QtCore/QtEndian> + +#include <dwrite.h> +#include <d2d1.h> + +QT_BEGIN_NAMESPACE + +// Convert from design units to logical pixels +#define DESIGN_TO_LOGICAL(DESIGN_UNIT_VALUE) \ + QFixed::fromReal((qreal(DESIGN_UNIT_VALUE) / qreal(m_unitsPerEm)) * fontDef.pixelSize) + +namespace { + + class GeometrySink: public IDWriteGeometrySink + { + public: + GeometrySink(QPainterPath *path) : m_path(path), m_refCount(0) + { + Q_ASSERT(m_path != 0); + } + + IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount); + IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount); + IFACEMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin); + IFACEMETHOD(Close)(); + IFACEMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd); + IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode); + IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags); + + IFACEMETHOD_(unsigned long, AddRef)(); + IFACEMETHOD_(unsigned long, Release)(); + IFACEMETHOD(QueryInterface)(IID const &riid, void **ppvObject); + + private: + inline static QPointF fromD2D1_POINT_2F(const D2D1_POINT_2F &inp) + { + return QPointF(inp.x, inp.y); + } + + unsigned long m_refCount; + QPointF m_startPoint; + QPainterPath *m_path; + }; + + void GeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, + UINT bezierCount) + { + for (uint i=0; i<bezierCount; ++i) { + QPointF c1 = fromD2D1_POINT_2F(beziers[i].point1); + QPointF c2 = fromD2D1_POINT_2F(beziers[i].point2); + QPointF p2 = fromD2D1_POINT_2F(beziers[i].point3); + + m_path->cubicTo(c1, c2, p2); + } + } + + void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount) + { + for (uint i=0; i<pointsCount; ++i) + m_path->lineTo(fromD2D1_POINT_2F(points[i])); + } + + void GeometrySink::BeginFigure(D2D1_POINT_2F startPoint, + D2D1_FIGURE_BEGIN /*figureBegin*/) + { + m_startPoint = fromD2D1_POINT_2F(startPoint); + m_path->moveTo(m_startPoint); + } + + IFACEMETHODIMP GeometrySink::Close() + { + return E_NOTIMPL; + } + + void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd) + { + if (figureEnd == D2D1_FIGURE_END_CLOSED) + m_path->closeSubpath(); + } + + void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode) + { + m_path->setFillRule(fillMode == D2D1_FILL_MODE_ALTERNATE + ? Qt::OddEvenFill + : Qt::WindingFill); + } + + void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/) + { + /* Not implemented */ + } + + IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef() + { + return InterlockedIncrement(&m_refCount); + } + + IFACEMETHODIMP_(unsigned long) GeometrySink::Release() + { + unsigned long newCount = InterlockedDecrement(&m_refCount); + if (newCount == 0) + { + delete this; + return 0; + } + + return newCount; + } + + IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject) + { + if (__uuidof(IDWriteGeometrySink) == riid) { + *ppvObject = this; + } else if (__uuidof(IUnknown) == riid) { + *ppvObject = this; + } else { + *ppvObject = NULL; + return E_FAIL; + } + + AddRef(); + return S_OK; + } + +} + +/*! + \class QWindowsFontEngineDirectWrite + \brief Windows font engine using Direct Write. + \ingroup qt-lighthouse-win + + Font engine for subpixel positioned text on Windows Vista + (with platform update) and Windows 7. If selected during + configuration, the engine will be selected only when the hinting + preference of a font is set to None or Vertical hinting. The font + database uses most of the same logic but creates a direct write + font based on the LOGFONT rather than a GDI handle. + + The engine is currently regarded as experimental, meaning that code + using it should do substantial testing to make sure it covers their + use cases. + + Will probably be superseded by a common Free Type font engine in Qt 5.X. +*/ + +QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace, + qreal pixelSize, + const QSharedPointer<QWindowsFontEngineData> &d) + + : m_fontEngineData(d) + , m_directWriteFontFace(directWriteFontFace) + , m_directWriteBitmapRenderTarget(0) + , m_lineThickness(-1) + , m_unitsPerEm(-1) + , m_ascent(-1) + , m_descent(-1) + , m_xHeight(-1) + , m_lineGap(-1) +{ + if (QWindowsContext::verboseFonts) + qDebug("%s %g", __FUNCTION__, pixelSize); + + d->directWriteFactory->AddRef(); + m_directWriteFontFace->AddRef(); + + fontDef.pixelSize = pixelSize; + collectMetrics(); +} + +QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite() +{ + if (QWindowsContext::verboseFonts) + qDebug("%s", __FUNCTION__); + + m_fontEngineData->directWriteFactory->Release(); + m_directWriteFontFace->Release(); + + if (m_directWriteBitmapRenderTarget != 0) + m_directWriteBitmapRenderTarget->Release(); +} + +void QWindowsFontEngineDirectWrite::collectMetrics() +{ + if (m_directWriteFontFace != 0) { + DWRITE_FONT_METRICS metrics; + + m_directWriteFontFace->GetMetrics(&metrics); + m_unitsPerEm = metrics.designUnitsPerEm; + + m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); + m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); + m_descent = DESIGN_TO_LOGICAL(metrics.descent); + m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); + m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap); + } +} + +QFixed QWindowsFontEngineDirectWrite::lineThickness() const +{ + if (m_lineThickness > 0) + return m_lineThickness; + else + return QFontEngine::lineThickness(); +} + +bool QWindowsFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, uint *length) const +{ + if (m_directWriteFontFace) { + DWORD t = qbswap<quint32>(tag); + + const void *tableData = 0; + void *tableContext = 0; + UINT32 tableSize; + BOOL exists; + HRESULT hr = m_directWriteFontFace->TryGetFontTable( + t, &tableData, &tableSize, &tableContext, &exists + ); + + if (SUCCEEDED(hr)) { + if (!exists) + return false; + + if (buffer == 0) { + *length = tableSize; + return true; + } else if (*length < tableSize) { + return false; + } + + qMemCopy(buffer, tableData, tableSize); + m_directWriteFontFace->ReleaseFontTable(tableContext); + + return true; + } else { + qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__); + } + } + + return false; +} + +QFixed QWindowsFontEngineDirectWrite::emSquareSize() const +{ + if (m_unitsPerEm > 0) + return m_unitsPerEm; + else + return QFontEngine::emSquareSize(); +} + +inline unsigned int getChar(const QChar *str, int &i, const int len) +{ + unsigned int uc = str[i].unicode(); + if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) { + uint low = str[i+1].unicode(); + if (low >= 0xdc00 && low < 0xe000) { + uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000; + ++i; + } + } + return uc; +} + +bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, + int *nglyphs, QTextEngine::ShaperFlags flags) const +{ + if (m_directWriteFontFace != 0) { + QVarLengthArray<UINT32> codePoints(len); + for (int i=0; i<len; ++i) { + codePoints[i] = getChar(str, i, len); + if (flags & QTextEngine::RightToLeft) + codePoints[i] = QChar::mirroredChar(codePoints[i]); + } + + QVarLengthArray<UINT16> glyphIndices(len); + HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), + len, + glyphIndices.data()); + + if (SUCCEEDED(hr)) { + for (int i=0; i<len; ++i) + glyphs->glyphs[i] = glyphIndices[i]; + + *nglyphs = len; + + if (!(flags & QTextEngine::GlyphIndicesOnly)) + recalcAdvances(glyphs, 0); + + return true; + } else { + qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); + } + } + + return false; +} + +void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const +{ + if (m_directWriteFontFace == 0) + return; + + QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs); + + // ### Caching? + for(int i=0; i<glyphs->numGlyphs; i++) + glyphIndices[i] = UINT16(glyphs->glyphs[i]); + + QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size()); + HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(), + glyphIndices.size(), + glyphMetrics.data()); + if (SUCCEEDED(hr)) { + for (int i=0; i<glyphs->numGlyphs; ++i) { + glyphs->advances_x[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth); + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + glyphs->advances_x[i] = glyphs->advances_x[i].round(); + glyphs->advances_y[i] = 0; + } + } else { + qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); + } +} + +void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, + QPainterPath *path, QTextItem::RenderFlags flags) +{ + if (m_directWriteFontFace == 0) + return; + + QVarLengthArray<UINT16> glyphIndices(nglyphs); + QVarLengthArray<DWRITE_GLYPH_OFFSET> glyphOffsets(nglyphs); + QVarLengthArray<FLOAT> glyphAdvances(nglyphs); + + for (int i=0; i<nglyphs; ++i) { + glyphIndices[i] = glyphs[i]; + glyphOffsets[i].advanceOffset = positions[i].x.toReal(); + glyphOffsets[i].ascenderOffset = -positions[i].y.toReal(); + glyphAdvances[i] = 0.0; + } + + GeometrySink geometrySink(path); + HRESULT hr = m_directWriteFontFace->GetGlyphRunOutline( + fontDef.pixelSize, + glyphIndices.data(), + glyphAdvances.data(), + glyphOffsets.data(), + nglyphs, + false, + flags & QTextItem::RightToLeft, + &geometrySink + ); + + if (FAILED(hr)) + qErrnoWarning("%s: GetGlyphRunOutline failed", __FUNCTION__); +} + +glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &glyphs) +{ + if (glyphs.numGlyphs == 0) + return glyph_metrics_t(); + + bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics; + + QFixed w = 0; + for (int i = 0; i < glyphs.numGlyphs; ++i) { + w += round ? glyphs.effectiveAdvance(i).round() : glyphs.effectiveAdvance(i); + + } + + return glyph_metrics_t(0, -m_ascent, w - lastRightBearing(glyphs), m_ascent + m_descent, w, 0); +} + +glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g) +{ + if (m_directWriteFontFace == 0) + return glyph_metrics_t(); + + UINT16 glyphIndex = g; + + DWRITE_GLYPH_METRICS glyphMetrics; + HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(&glyphIndex, 1, &glyphMetrics); + if (SUCCEEDED(hr)) { + QFixed advanceWidth = DESIGN_TO_LOGICAL(glyphMetrics.advanceWidth); + QFixed leftSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.leftSideBearing); + QFixed rightSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.rightSideBearing); + QFixed advanceHeight = DESIGN_TO_LOGICAL(glyphMetrics.advanceHeight); + QFixed verticalOriginY = DESIGN_TO_LOGICAL(glyphMetrics.verticalOriginY); + + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { + advanceWidth = advanceWidth.round(); + advanceHeight = advanceHeight.round(); + } + + QFixed width = advanceWidth - leftSideBearing - rightSideBearing; + + return glyph_metrics_t(-leftSideBearing, -verticalOriginY, + width, m_ascent + m_descent, + advanceWidth, advanceHeight); + } else { + qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); + } + + return glyph_metrics_t(); +} + +QFixed QWindowsFontEngineDirectWrite::ascent() const +{ + return fontDef.styleStrategy & QFont::ForceIntegerMetrics + ? m_ascent.round() + : m_ascent; +} + +QFixed QWindowsFontEngineDirectWrite::descent() const +{ + return fontDef.styleStrategy & QFont::ForceIntegerMetrics + ? (m_descent - 1).round() + : (m_descent - 1); +} + +QFixed QWindowsFontEngineDirectWrite::leading() const +{ + return fontDef.styleStrategy & QFont::ForceIntegerMetrics + ? m_lineGap.round() + : m_lineGap; +} + +QFixed QWindowsFontEngineDirectWrite::xHeight() const +{ + return fontDef.styleStrategy & QFont::ForceIntegerMetrics + ? m_xHeight.round() + : m_xHeight; +} + +qreal QWindowsFontEngineDirectWrite::maxCharWidth() const +{ + // ### + return 0; +} + +QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) +{ + QImage im = imageForGlyph(glyph, subPixelPosition, 0, QTransform()); + + QImage indexed(im.width(), im.height(), QImage::Format_Indexed8); + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgba(0, 0, 0, i); + indexed.setColorTable(colors); + + for (int y=0; y<im.height(); ++y) { + uint *src = (uint*) im.scanLine(y); + uchar *dst = indexed.scanLine(y); + for (int x=0; x<im.width(); ++x) { + *dst = 255 - (m_fontEngineData->pow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.); + ++dst; + ++src; + } + } + + return indexed; +} + +bool QWindowsFontEngineDirectWrite::supportsSubPixelPositions() const +{ + return true; +} + +QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, + QFixed subPixelPosition, + int margin, + const QTransform &xform) +{ + glyph_metrics_t metrics = QFontEngine::boundingBox(t, xform); + int width = (metrics.width + margin * 2 + 4).ceil().toInt() ; + int height = (metrics.height + margin * 2 + 4).ceil().toInt(); + + UINT16 glyphIndex = t; + FLOAT glyphAdvance = metrics.xoff.toReal(); + + DWRITE_GLYPH_OFFSET glyphOffset; + glyphOffset.advanceOffset = 0; + glyphOffset.ascenderOffset = 0; + + DWRITE_GLYPH_RUN glyphRun; + glyphRun.fontFace = m_directWriteFontFace; + glyphRun.fontEmSize = fontDef.pixelSize; + glyphRun.glyphCount = 1; + glyphRun.glyphIndices = &glyphIndex; + glyphRun.glyphAdvances = &glyphAdvance; + glyphRun.isSideways = false; + glyphRun.bidiLevel = 0; + glyphRun.glyphOffsets = &glyphOffset; + + QFixed x = margin - metrics.x.round() + subPixelPosition; + QFixed y = margin - metrics.y.floor(); + + DWRITE_MATRIX transform; + transform.dx = x.toReal(); + transform.dy = y.toReal(); + transform.m11 = xform.m11(); + transform.m12 = xform.m12(); + transform.m21 = xform.m21(); + transform.m22 = xform.m22(); + + IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; + HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( + &glyphRun, + 1.0f, + &transform, + DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, + DWRITE_MEASURING_MODE_NATURAL, + 0.0, 0.0, + &glyphAnalysis + ); + + if (SUCCEEDED(hr)) { + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = width; + rect.bottom = height; + + int size = width * height * 3; + BYTE *alphaValues = new BYTE[size]; + qMemSet(alphaValues, size, 0); + + hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, + &rect, + alphaValues, + size); + + if (SUCCEEDED(hr)) { + QImage img(width, height, QImage::Format_RGB32); + img.fill(0xffffffff); + + for (int y=0; y<height; ++y) { + uint *dest = reinterpret_cast<uint *>(img.scanLine(y)); + BYTE *src = alphaValues + width * 3 * y; + + for (int x=0; x<width; ++x) { + dest[x] = *(src) << 16 + | *(src + 1) << 8 + | *(src + 2); + + src += 3; + } + } + + delete[] alphaValues; + glyphAnalysis->Release(); + + return img; + } else { + delete[] alphaValues; + glyphAnalysis->Release(); + + qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__); + } + + } else { + qErrnoWarning("%s: CreateGlyphRunAnalysis failed", __FUNCTION__); + } + + return QImage(); +} + +QImage QWindowsFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t, + QFixed subPixelPosition, + int margin, + const QTransform &xform) +{ + QImage mask = imageForGlyph(t, subPixelPosition, margin, xform); + return mask.depth() == 32 + ? mask + : mask.convertToFormat(QImage::Format_RGB32); +} + +const char *QWindowsFontEngineDirectWrite::name() const +{ + return 0; +} + +bool QWindowsFontEngineDirectWrite::canRender(const QChar *string, int len) +{ + QVarLengthArray<UINT32> codePoints(len); + int actualLength = 0; + for (int i=0; i<len; ++i, actualLength++) + codePoints[actualLength] = getChar(string, i, len); + + QVarLengthArray<UINT16> glyphIndices(actualLength); + HRESULT hr = m_directWriteFontFace->GetGlyphIndices(codePoints.data(), actualLength, + glyphIndices.data()); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGlyphIndices failed", __FUNCTION__); + return false; + } else { + for (int i=0; i<glyphIndices.size(); ++i) { + if (glyphIndices.at(i) == 0) + return false; + } + + return true; + } +} + +QFontEngine::Type QWindowsFontEngineDirectWrite::type() const +{ + return QFontEngine::DirectWrite; +} + +QFontEngine *QWindowsFontEngineDirectWrite::cloneWithSize(qreal pixelSize) const +{ + QFontEngine *fontEngine = new QWindowsFontEngineDirectWrite(m_directWriteFontFace, + pixelSize, m_fontEngineData); + + fontEngine->fontDef = fontDef; + fontEngine->fontDef.pixelSize = pixelSize; + + return fontEngine; +} + +void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request, + int dpi, IDWriteFont *font) +{ + fontDef = request; + + IDWriteFontFamily *fontFamily = NULL; + HRESULT hr = font->GetFontFamily(&fontFamily); + + IDWriteLocalizedStrings *familyNames = NULL; + if (SUCCEEDED(hr)) + hr = fontFamily->GetFamilyNames(&familyNames); + + UINT32 index = 0; + BOOL exists = false; + + wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; + + if (SUCCEEDED(hr)) { + int defaultLocaleSuccess = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH); + + if (defaultLocaleSuccess) + hr = familyNames->FindLocaleName(localeName, &index, &exists); + + if (SUCCEEDED(hr) && !exists) + hr = familyNames->FindLocaleName(L"en-us", &index, &exists); + } + + if (!exists) + index = 0; + + UINT32 length = 0; + if (SUCCEEDED(hr)) + hr = familyNames->GetStringLength(index, &length); + + wchar_t *name = new (std::nothrow) wchar_t[length+1]; + if (name == NULL) + hr = E_OUTOFMEMORY; + + // Get the family name. + if (SUCCEEDED(hr)) + hr = familyNames->GetString(index, name, length + 1); + + if (SUCCEEDED(hr)) + fontDef.family = QString::fromWCharArray(name); + + delete[] name; + if (familyNames != NULL) + familyNames->Release(); + + if (FAILED(hr)) + qErrnoWarning(hr, "initFontInfo: Failed to get family name"); + + if (fontDef.pointSize < 0) + fontDef.pointSize = fontDef.pixelSize * 72. / dpi; + else if (fontDef.pixelSize == -1) + fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.); +} + +QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyName) +{ + static const char keyC[] = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\" + "FontSubstitutes"; + return QSettings(QLatin1String(keyC), QSettings::NativeFormat).value(familyName, familyName).toString(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_DIRECTWRITE diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h new file mode 100644 index 0000000000..1333720481 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSFONTENGINEDIRECTWRITE_H +#define QWINDOWSFONTENGINEDIRECTWRITE_H + +#ifndef QT_NO_DIRECTWRITE + +// Enable access to HB_Face in harfbuzz includes included by qfontengine_p.h. +#define QT_BUILD_GUI_LIB +#include <QtGui/private/qfontengine_p.h> +#undef QT_BUILD_GUI_LIB + +#include <QtCore/QSharedPointer> + +class QWindowsFontEngineData; + +struct IDWriteFont ; +struct IDWriteFontFace ; +struct IDWriteFactory ; +struct IDWriteBitmapRenderTarget ; +struct IDWriteGdiInterop ; + +QT_BEGIN_NAMESPACE + +class QWindowsFontEngineDirectWrite : public QFontEngine +{ + Q_OBJECT +public: + explicit QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace, + qreal pixelSize, + const QSharedPointer<QWindowsFontEngineData> &d); + ~QWindowsFontEngineDirectWrite(); + + void initFontInfo(const QFontDef &request, int dpi, IDWriteFont *font); + + QFixed lineThickness() const; + bool getSfntTableData(uint tag, uchar *buffer, uint *length) const; + QFixed emSquareSize() const; + + bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; + void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const; + + void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, + QPainterPath *path, QTextItem::RenderFlags flags); + + glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); + glyph_metrics_t boundingBox(glyph_t g); + + QFixed ascent() const; + QFixed descent() const; + QFixed leading() const; + QFixed xHeight() const; + qreal maxCharWidth() const; + + const char *name() const; + + bool supportsSubPixelPositions() const; + + QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition); + QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, int margin, + const QTransform &xform); + + QFontEngine *cloneWithSize(qreal pixelSize) const; + + bool canRender(const QChar *string, int len); + Type type() const; + + static QString fontNameSubstitute(const QString &familyName); + +private: + friend class QRawFontPrivate; + + QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform); + void collectMetrics(); + + const QSharedPointer<QWindowsFontEngineData> m_fontEngineData; + + IDWriteFontFace *m_directWriteFontFace; + IDWriteBitmapRenderTarget *m_directWriteBitmapRenderTarget; + + QFixed m_lineThickness; + int m_unitsPerEm; + QFixed m_ascent; + QFixed m_descent; + QFixed m_xHeight; + QFixed m_lineGap; + FaceId m_faceId; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_DIRECTWRITE + +#endif // QWINDOWSFONTENGINEDIRECTWRITE_H diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp new file mode 100644 index 0000000000..4abccfb416 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -0,0 +1,971 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsglcontext.h" +#include "qwindowscontext.h" +#include "qwindowswindow.h" + +#include <QtCore/QDebug> +#include <QtCore/QSysInfo> + +#include <WinGDI.h> +#if defined(Q_CC_MINGW) +# include <GL/Gl.h> +#else +# include <Gl.h> +#endif + +// #define DEBUG_GL + +// ARB extension API +#ifndef WGL_ARB_multisample +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 +#endif + +#ifndef WGL_ARB_pixel_format +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_DRAW_TO_BITMAP_ARB 0x2002 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NEED_PALETTE_ARB 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_NUMBER_OVERLAYS_ARB 0x2008 +#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define WGL_TRANSPARENT_ARB 0x200A +#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +#define WGL_SHARE_DEPTH_ARB 0x200C +#define WGL_SHARE_STENCIL_ARB 0x200D +#define WGL_SHARE_ACCUM_ARB 0x200E +#define WGL_SUPPORT_GDI_ARB 0x200F +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201A +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ALPHA_SHIFT_ARB 0x201C +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_SWAP_COPY_ARB 0x2029 +#define WGL_SWAP_UNDEFINED_ARB 0x202A +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C +#endif + +#ifndef WGL_ARB_create_context +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x0001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x0002 +// Error codes returned by GetLastError(). +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif + +#ifndef GL_VERSION_3_2 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 +#endif + +QT_BEGIN_NAMESPACE + +template <class MaskType, class FlagType> inline bool testFlag(MaskType mask, FlagType flag) +{ + return (mask & MaskType(flag)) != 0; +} + +static inline bool hasGLOverlay(const PIXELFORMATDESCRIPTOR &pd) +{ return (pd.bReserved & 0x0f) != 0; } + +static inline bool isDirectRendering(const PIXELFORMATDESCRIPTOR &pfd) +{ return (pfd.dwFlags & PFD_GENERIC_ACCELERATED) || !(pfd.dwFlags & PFD_GENERIC_FORMAT); } + +static inline void initPixelFormatDescriptor(PIXELFORMATDESCRIPTOR *d) +{ + memset(d, 0, sizeof(PIXELFORMATDESCRIPTOR)); + d->nSize = sizeof(PIXELFORMATDESCRIPTOR); + d->nVersion = 1; +} + +QDebug operator<<(QDebug d, const PIXELFORMATDESCRIPTOR &pd) +{ + QDebug nsp = d.nospace(); + nsp << "PIXELFORMATDESCRIPTOR " + << "dwFlags=" << hex << showbase << pd.dwFlags << dec << noshowbase; + if (pd.dwFlags & PFD_DRAW_TO_WINDOW) nsp << " PFD_DRAW_TO_WINDOW"; + if (pd.dwFlags & PFD_DRAW_TO_BITMAP) nsp << " PFD_DRAW_TO_BITMAP"; + if (pd.dwFlags & PFD_SUPPORT_GDI) nsp << " PFD_SUPPORT_GDI"; + if (pd.dwFlags & PFD_SUPPORT_OPENGL) nsp << " PFD_SUPPORT_OPENGL"; + if (pd.dwFlags & PFD_GENERIC_ACCELERATED) nsp << " PFD_GENERIC_ACCELERATED"; + if (pd.dwFlags & PFD_SUPPORT_DIRECTDRAW) nsp << " PFD_SUPPORT_DIRECTDRAW"; + if (pd.dwFlags & PFD_DIRECT3D_ACCELERATED) nsp << " PFD_DIRECT3D_ACCELERATED"; + if (pd.dwFlags & PFD_SUPPORT_COMPOSITION) nsp << " PFD_SUPPORT_COMPOSITION"; + if (pd.dwFlags & PFD_GENERIC_FORMAT) nsp << " PFD_GENERIC_FORMAT"; + if (pd.dwFlags & PFD_NEED_PALETTE) nsp << " PFD_NEED_PALETTE"; + if (pd.dwFlags & PFD_NEED_SYSTEM_PALETTE) nsp << " PFD_NEED_SYSTEM_PALETTE"; + if (pd.dwFlags & PFD_DOUBLEBUFFER) nsp << " PFD_DOUBLEBUFFER"; + if (pd.dwFlags & PFD_STEREO) nsp << " PFD_STEREO"; + if (pd.dwFlags & PFD_SWAP_LAYER_BUFFERS) nsp << " PFD_SWAP_LAYER_BUFFERS"; + if (hasGLOverlay(pd)) nsp << " overlay"; + nsp << " iPixelType=" << pd.iPixelType << " cColorBits=" << pd.cColorBits + << " cRedBits=" << pd.cRedBits << " cRedShift=" << pd.cRedShift + << " cGreenBits=" << pd.cGreenBits << " cGreenShift=" << pd.cGreenShift + << " cBlueBits=" << pd.cBlueBits << " cBlueShift=" << pd.cBlueShift; + nsp << " cDepthBits=" << pd.cDepthBits; + if (pd.cStencilBits) + nsp << " cStencilBits=" << pd.cStencilBits; + if (pd.cAuxBuffers) + nsp << " cAuxBuffers=" << pd.cAuxBuffers; + nsp << " iLayerType=" << pd.iLayerType; + if (pd.dwVisibleMask) + nsp << " dwVisibleMask=" << pd.dwVisibleMask; + if (pd.cAlphaBits) + nsp << " cAlphaBits=" << pd.cAlphaBits << " cAlphaShift=" << pd.cAlphaShift; + if (pd.cAccumBits) + nsp << " cAccumBits=" << pd.cAccumBits << " cAccumRedBits=" << pd.cAccumRedBits + << " cAccumGreenBits=" << pd.cAccumGreenBits << " cAccumBlueBits=" << pd.cAccumBlueBits + << " cAccumAlphaBits=" << pd.cAccumAlphaBits; + return d; +} + +// Check whether an obtained PIXELFORMATDESCRIPTOR matches the request. +static inline bool + isAcceptableFormat(const QWindowsOpenGLAdditionalFormat &additional, + const PIXELFORMATDESCRIPTOR &pfd, + bool ignoreGLSupport = false) // ARB format may not contain it. +{ + const bool pixmapRequested = testFlag(additional.formatFlags, QWindowsGLRenderToPixmap); + return (ignoreGLSupport || testFlag(pfd.dwFlags, PFD_SUPPORT_OPENGL)) + && testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP) == pixmapRequested + && hasGLOverlay(pfd) == testFlag(additional.formatFlags, QWindowsGLOverlay) + && (!pixmapRequested || pfd.cColorBits == additional.pixmapDepth); +} + +static void describeFormats(HDC hdc) +{ + const int pfiMax = DescribePixelFormat(hdc, 0, 0, NULL); + for (int i = 0; i < pfiMax; i++) { + PIXELFORMATDESCRIPTOR pfd; + initPixelFormatDescriptor(&pfd); + DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + qDebug() << '#' << i << '/' << pfiMax << ':' << pfd; + } +} + +// Classic GDI API +namespace GDI { +static QSurfaceFormat + qSurfaceFormatFromPixelFormat(const PIXELFORMATDESCRIPTOR &pfd, + QWindowsOpenGLAdditionalFormat *additionalIn = 0) +{ + QSurfaceFormat format; + if (pfd.dwFlags & PFD_DOUBLEBUFFER) + format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + format.setDepthBufferSize(pfd.cDepthBits); + + if (pfd.iPixelType == PFD_TYPE_RGBA) + format.setAlphaBufferSize(pfd.cAlphaBits); + format.setRedBufferSize(pfd.cRedBits); + format.setGreenBufferSize(pfd.cGreenBits); + format.setBlueBufferSize(pfd.cBlueBits); + format.setStencilBufferSize(pfd.cStencilBits); + format.setStereo(pfd.dwFlags & PFD_STEREO); + if (additionalIn) { + QWindowsOpenGLAdditionalFormat additional; + if (isDirectRendering(pfd)) + additional.formatFlags |= QWindowsGLDirectRendering; + if (hasGLOverlay(pfd)) + additional.formatFlags |= QWindowsGLOverlay; + if (pfd.cAccumRedBits) + additional.formatFlags |= QWindowsGLAccumBuffer; + if (testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP)) { + additional.formatFlags |= QWindowsGLRenderToPixmap; + additional.pixmapDepth = pfd.cColorBits; + } + *additionalIn = additional; + } + return format; +} + +static PIXELFORMATDESCRIPTOR + qPixelFormatFromSurfaceFormat(const QSurfaceFormat &format, + const QWindowsOpenGLAdditionalFormat &additional) +{ + PIXELFORMATDESCRIPTOR pfd; + initPixelFormatDescriptor(&pfd); + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.iLayerType = PFD_MAIN_PLANE; + pfd.dwFlags = PFD_SUPPORT_OPENGL; + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) + pfd.dwFlags = PFD_SUPPORT_COMPOSITION; + const bool isPixmap = (additional.formatFlags & QWindowsGLRenderToPixmap) != 0; + pfd.dwFlags |= isPixmap ? PFD_DRAW_TO_BITMAP : PFD_DRAW_TO_WINDOW; + if (!(additional.formatFlags & QWindowsGLDirectRendering)) + pfd.dwFlags |= PFD_GENERIC_FORMAT; + + if (format.stereo()) + pfd.dwFlags |= PFD_STEREO; + if (format.swapBehavior() == QSurfaceFormat::DoubleBuffer && !isPixmap) + pfd.dwFlags |= PFD_DOUBLEBUFFER; + pfd.cDepthBits = + format.depthBufferSize() >= 0 ? format.depthBufferSize() : 32; + pfd.cAlphaBits = format.alphaBufferSize() > 0 ? format.alphaBufferSize() : 8; + pfd.cStencilBits = format.stencilBufferSize() > 0 ? format.stencilBufferSize() : 8; + if (additional.formatFlags & QWindowsGLAccumBuffer) + pfd.cAccumRedBits = pfd.cAccumGreenBits = pfd.cAccumBlueBits = pfd.cAccumAlphaBits = 16; + return pfd; +} + +// Choose a suitable pixelformat using GDI WinAPI in case ARB +// functions cannot be found. First tries to find a suitable +// format using GDI function ChoosePixelFormat(). Since that +// does not handle overlay and direct-rendering requests, manually loop +// over the available formats to find the best one. +// Note: As of Windows 7, it seems direct-rendering is handled, so, +// the code might be obsolete? +static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format, + const QWindowsOpenGLAdditionalFormat &additional, + PIXELFORMATDESCRIPTOR *obtainedPfd) +{ + // 1) Try ChoosePixelFormat(). + PIXELFORMATDESCRIPTOR requestedPfd = qPixelFormatFromSurfaceFormat(format, QWindowsGLDirectRendering); + initPixelFormatDescriptor(obtainedPfd); + int pixelFormat = ChoosePixelFormat(hdc, &requestedPfd); + if (pixelFormat >= 0) { + DescribePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd); + if (isAcceptableFormat(additional, *obtainedPfd)) + return pixelFormat; + } + // 2) No matching format found, manual search loop. + const int pfiMax = DescribePixelFormat(hdc, 0, 0, NULL); + int bestScore = -1; + int bestPfi = -1; + const bool stereoRequested = format.stereo(); + const bool accumBufferRequested = testFlag(additional.formatFlags, QWindowsGLAccumBuffer); + const bool doubleBufferRequested = format.swapBehavior() == QSurfaceFormat::DoubleBuffer; + const bool directRenderingRequested = testFlag(additional.formatFlags, QWindowsGLDirectRendering); + for (int pfi = 1; pfi <= pfiMax; pfi++) { + PIXELFORMATDESCRIPTOR checkPfd; + initPixelFormatDescriptor(&checkPfd); + DescribePixelFormat(hdc, pfi, sizeof(PIXELFORMATDESCRIPTOR), &checkPfd); + if (isAcceptableFormat(additional, checkPfd)) { + int score = checkPfd.cColorBits + checkPfd.cAlphaBits + checkPfd.cStencilBits; + if (accumBufferRequested) + score += checkPfd.cAccumBits; + if (doubleBufferRequested == testFlag(checkPfd.dwFlags, PFD_DOUBLEBUFFER)) + score += 1000; + if (stereoRequested == testFlag(checkPfd.dwFlags, PFD_STEREO)) + score += 2000; + if (directRenderingRequested == isDirectRendering(checkPfd)) + score += 4000; + if (checkPfd.iPixelType == PFD_TYPE_RGBA) + score += 8000; + if (score > bestScore) { + bestScore = score; + bestPfi = pfi; + *obtainedPfd = checkPfd; + } + if (QWindowsContext::verboseGL) + qDebug() << __FUNCTION__ << " checking " << pfi << '/' << pfiMax + << " score=" << score << " (best " << bestPfi << '/' << bestScore + << ") " << checkPfd; + } + } // for + if (bestPfi > 0) + pixelFormat = bestPfi; + return pixelFormat; +} + +static inline HGLRC createContext(HDC hdc, HGLRC shared) +{ + HGLRC result = wglCreateContext(hdc); + if (!result) { + qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__); + return 0; + } + if (shared && !wglShareLists(shared, result)) + qErrnoWarning("%s: wglShareLists() failed.", __FUNCTION__); + return result; +} +} // namespace GDI + +// ARB OpenGL extension API +namespace ARB { +// Choose a suitable pixelformat using ARB extension functions. +static int choosePixelFormat(HDC hdc, + const QOpenGLStaticContext &staticContext, + const QSurfaceFormat &format, + const QWindowsOpenGLAdditionalFormat &additional, + PIXELFORMATDESCRIPTOR *obtainedPfd) +{ + enum { attribSize =40 }; + if ((additional.formatFlags & QWindowsGLRenderToPixmap) || !staticContext.hasExtensions()) + return 0; + + int iAttributes[attribSize]; + qFill(iAttributes, iAttributes + attribSize, int(0)); + int i = 0; + iAttributes[i++] = WGL_ACCELERATION_ARB; + iAttributes[i++] = testFlag(additional.formatFlags, QWindowsGLDirectRendering) ? + WGL_FULL_ACCELERATION_ARB : WGL_NO_ACCELERATION_ARB; + iAttributes[i++] = WGL_SUPPORT_OPENGL_ARB; + iAttributes[i++] = TRUE; + iAttributes[i++] = WGL_DRAW_TO_WINDOW_ARB; + iAttributes[i++] = TRUE; + iAttributes[i++] = WGL_COLOR_BITS_ARB; + iAttributes[i++] = 24; + switch (format.swapBehavior()) { + case QSurfaceFormat::DefaultSwapBehavior: + case QSurfaceFormat::TripleBuffer: + break; + case QSurfaceFormat::SingleBuffer: + iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB; + iAttributes[i++] = FALSE; + break; + case QSurfaceFormat::DoubleBuffer: + iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB; + iAttributes[i++] = TRUE; + break; + } + if (format.stereo()) { + iAttributes[i++] = WGL_STEREO_ARB; + iAttributes[i++] = TRUE; + } + if (format.depthBufferSize() >= 0) { + iAttributes[i++] = WGL_DEPTH_BITS_ARB; + iAttributes[i++] = format.depthBufferSize(); + } + iAttributes[i++] = WGL_PIXEL_TYPE_ARB; + iAttributes[i++] = WGL_TYPE_RGBA_ARB; + if (format.redBufferSize() >= 0) { + iAttributes[i++] = WGL_RED_BITS_ARB; + iAttributes[i++] = format.redBufferSize(); + } + if (format.greenBufferSize() >= 0) { + iAttributes[i++] = WGL_GREEN_BITS_ARB; + iAttributes[i++] = format.greenBufferSize(); + } + if (format.blueBufferSize() >= 0) { + iAttributes[i++] = WGL_BLUE_BITS_ARB; + iAttributes[i++] = format.blueBufferSize(); + } + iAttributes[i++] = WGL_ALPHA_BITS_ARB; + iAttributes[i++] = format.alphaBufferSize() >= 0 ? format.alphaBufferSize() : 8; + if (additional.formatFlags & QWindowsGLAccumBuffer) { + iAttributes[i++] = WGL_ACCUM_BITS_ARB; + iAttributes[i++] = 16; + } + iAttributes[i++] = WGL_STENCIL_BITS_ARB; + iAttributes[i++] = 8; + if (additional.formatFlags & QWindowsGLOverlay) { + iAttributes[i++] = WGL_NUMBER_OVERLAYS_ARB; + iAttributes[i++] = 1; + } + const bool sampleBuffersRequested = format.samples() > 1 + && testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers); + int samplesValuePosition = 0; + int samplesEnabledPosition = 0; + if (sampleBuffersRequested) { + iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB; + samplesEnabledPosition = i; + iAttributes[i++] = TRUE; + iAttributes[i++] = WGL_SAMPLES_ARB; + samplesValuePosition = i; + iAttributes[i++] = format.samples(); + } + // If sample buffer request cannot be satisfied, reduce request. + int pixelFormat = 0; + uint numFormats = 0; + while (true) { + const bool valid = + staticContext.wglChoosePixelFormatARB(hdc, iAttributes, 0, 1, + &pixelFormat, &numFormats) + && numFormats >= 1; + if (valid || !sampleBuffersRequested) + break; + if (iAttributes[samplesValuePosition] > 1) { + iAttributes[samplesValuePosition] /= 2; + } else { + break; + } + } + // Verify if format is acceptable. Note that the returned + // formats have been observed to not contain PFD_SUPPORT_OPENGL, ignore. + initPixelFormatDescriptor(obtainedPfd); + DescribePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd); + if (!isAcceptableFormat(additional, *obtainedPfd, true)) { + if (QWindowsContext::verboseGL) + qDebug() << __FUNCTION__ << " obtained px #" << pixelFormat + << " not acceptable=" << *obtainedPfd; + pixelFormat = 0; + } + + if (QWindowsContext::verboseGL) { + QDebug nsp = qDebug().nospace(); + nsp << __FUNCTION__; + if (sampleBuffersRequested) + nsp << " samples=" << iAttributes[samplesValuePosition]; + nsp << " Attributes: " << hex << showbase; + for (int ii = 0; ii < i; ++ii) + nsp << iAttributes[ii] << ','; + nsp << noshowbase << dec << "\n obtained px #" << pixelFormat + << " of " << numFormats << "\n " << *obtainedPfd; + } // Debug + + return pixelFormat; +} + +static QSurfaceFormat + qSurfaceFormatFromHDC(const QOpenGLStaticContext &staticContext, + HDC hdc, int pixelFormat, + QWindowsOpenGLAdditionalFormat *additionalIn = 0) +{ + enum { attribSize =40 }; + + QSurfaceFormat result; + if (!staticContext.hasExtensions()) + return result; + int iAttributes[attribSize]; + int iValues[attribSize]; + qFill(iAttributes, iAttributes + attribSize, int(0)); + qFill(iValues, iValues + attribSize, int(0)); + + int i = 0; + const bool hasSampleBuffers = testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers); + + iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB; // 0 + iAttributes[i++] = WGL_DEPTH_BITS_ARB; // 1 + iAttributes[i++] = WGL_PIXEL_TYPE_ARB; // 2 + iAttributes[i++] = WGL_RED_BITS_ARB; // 3 + iAttributes[i++] = WGL_GREEN_BITS_ARB; // 4 + iAttributes[i++] = WGL_BLUE_BITS_ARB; // 5 + iAttributes[i++] = WGL_ALPHA_BITS_ARB; // 6 + iAttributes[i++] = WGL_ACCUM_BITS_ARB; // 7 + iAttributes[i++] = WGL_STENCIL_BITS_ARB; // 8 + iAttributes[i++] = WGL_STEREO_ARB; // 9 + iAttributes[i++] = WGL_ACCELERATION_ARB; // 10 + iAttributes[i++] = WGL_NUMBER_OVERLAYS_ARB; // 11 + if (hasSampleBuffers) { + iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB; // 12 + iAttributes[i++] = WGL_SAMPLES_ARB; // 13 + } + if (!staticContext.wglGetPixelFormatAttribIVARB(hdc, pixelFormat, 0, i, + iAttributes, iValues)) + return result; + if (iValues[0]) + result.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + result.setDepthBufferSize(iValues[1]); + result.setRedBufferSize(iValues[3]); + result.setGreenBufferSize(iValues[4]); + result.setBlueBufferSize(iValues[5]); + result.setAlphaBufferSize(iValues[6]); + result.setStencilBufferSize(iValues[8]); + result.setStereo(iValues[9]); + if (hasSampleBuffers) + result.setSamples(iValues[13]); + if (additionalIn) { + if (iValues[7]) + additionalIn->formatFlags |= QWindowsGLAccumBuffer; + if (iValues[10] == WGL_FULL_ACCELERATION_ARB) + additionalIn->formatFlags |= QWindowsGLDirectRendering; + if (iValues[11]) + additionalIn->formatFlags |= QWindowsGLOverlay; + } + return result; +} + +static HGLRC createContext(const QOpenGLStaticContext &staticContext, + HDC hdc, + const QSurfaceFormat &format, + const QWindowsOpenGLAdditionalFormat &additional, + int majorVersion = 0, + int minorVersion = 0, + HGLRC shared = 0) +{ + enum { attribSize = 11 }; + + if (!staticContext.hasExtensions()) + return 0; + int attributes[attribSize]; + int attribIndex = 0; + qFill(attributes, attributes + attribSize, int(0)); + + if (majorVersion) { + attributes[attribIndex++] = WGL_CONTEXT_MAJOR_VERSION_ARB; + attributes[attribIndex++] = majorVersion; + attributes[attribIndex++] = WGL_CONTEXT_MINOR_VERSION_ARB; + attributes[attribIndex++] = minorVersion; + } + if (majorVersion >= 3 && additional.formatFlags & QWindowsGLDeprecatedFunctions) { + attributes[attribIndex++] = WGL_CONTEXT_FLAGS_ARB; + attributes[attribIndex++] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + } + if ((staticContext.majorVersion == 3 && staticContext.minorVersion >= 2) + || staticContext.majorVersion > 3) { + switch (format.profile()) { + case QSurfaceFormat::NoProfile: + break; + case QSurfaceFormat::CoreProfile: + attributes[attribIndex++] = WGL_CONTEXT_PROFILE_MASK_ARB; + attributes[attribIndex++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + break; + case QSurfaceFormat::CompatibilityProfile: + attributes[attribIndex++] = WGL_CONTEXT_PROFILE_MASK_ARB; + attributes[attribIndex++] = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + break; + } + } + const HGLRC result = + staticContext.wglCreateContextAttribsARB(hdc, shared, attributes); + if (!result) + qErrnoWarning("%s: wglCreateContextAttribsARB() failed.", __FUNCTION__); + return result; +} + +} // namespace ARB + +// Helpers for temporary contexts +static inline HWND createDummyGLWindow() +{ + return QWindowsContext::instance()-> + createDummyWindow(QStringLiteral("QtOpenGLDummyWindow"), + L"OpenGLDummyWindow", 0, WS_OVERLAPPED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); +} + +// Create a dummy GL context (see QOpenGLTemporaryContext). +static inline HGLRC createDummyGLContext(HDC dc) +{ + if (!dc) + return 0; + PIXELFORMATDESCRIPTOR pixelFormDescriptor; + initPixelFormatDescriptor(&pixelFormDescriptor); + pixelFormDescriptor.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT; + pixelFormDescriptor.iPixelType = PFD_TYPE_RGBA; + const int pixelFormat = ChoosePixelFormat(dc, &pixelFormDescriptor); + if (!pixelFormat) { + qErrnoWarning("%s: ChoosePixelFormat failed.", __FUNCTION__); + return 0; + } + if (!SetPixelFormat(dc, pixelFormat, &pixelFormDescriptor)) { + qErrnoWarning("%s: SetPixelFormat failed.", __FUNCTION__); + return 0; + } + HGLRC rc = wglCreateContext(dc); + if (!rc) { + qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__); + return 0; + } + return rc; +} + +static inline QOpenGLContextData currentOpenGLContextData() +{ + QOpenGLContextData result; + result.hdc = wglGetCurrentDC(); + result.renderingContext = wglGetCurrentContext(); + return result; +} + +static inline QOpenGLContextData createDummyWindowOpenGLContextData() +{ + QOpenGLContextData result; + result.hwnd = createDummyGLWindow(); + result.hdc = GetDC(result.hwnd); + result.renderingContext = createDummyGLContext(result.hdc); + return result; +} + +/*! + \class QOpenGLTemporaryContext + \brief A temporary context that can be instantiated on the stack. + + Functions like wglGetProcAddress() or glGetString() only work if there + is a current GL context. + + \ingroup qt-lighthouse-win +*/ + +class QOpenGLTemporaryContext +{ + Q_DISABLE_COPY(QOpenGLTemporaryContext) +public: + QOpenGLTemporaryContext(); + ~QOpenGLTemporaryContext(); + +private: + const QOpenGLContextData m_previous; + const QOpenGLContextData m_current; +}; + +QOpenGLTemporaryContext::QOpenGLTemporaryContext() : + m_previous(currentOpenGLContextData()), + m_current(createDummyWindowOpenGLContextData()) +{ + wglMakeCurrent(m_current.hdc, m_current.renderingContext); +} + +QOpenGLTemporaryContext::~QOpenGLTemporaryContext() +{ + wglMakeCurrent(m_previous.hdc, m_previous.renderingContext); + ReleaseDC(m_current.hwnd, m_current.hdc); + DestroyWindow(m_current.hwnd); + wglDeleteContext(m_current.renderingContext); +} + +/*! + \class QWindowsOpenGLAdditionalFormat + \brief Additional format information that is not in QSurfaceFormat + \ingroup qt-lighthouse-win +*/ + +/*! + \class QOpenGLStaticContext + \brief Static Open GL context containing version information, extension function pointers, etc. + + Functions pending integration in the next version of OpenGL are post-fixed ARB. + + \note Initialization requires an active context (see create()). + + \sa QWindowsGLContext + \ingroup qt-lighthouse-win +*/ + +#define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample" + +QOpenGLStaticContext::QOpenGLStaticContext() : + vendor(QOpenGLStaticContext::getGlString(GL_VENDOR)), + renderer(QOpenGLStaticContext::getGlString(GL_RENDERER)), + extensionNames(QOpenGLStaticContext::getGlString(GL_EXTENSIONS)), + majorVersion(0), minorVersion(0), + extensions(0), + wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)wglGetProcAddress("wglGetPixelFormatAttribivARB")), + wglChoosePixelFormatARB((WglChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB")), + wglCreateContextAttribsARB((WglCreateContextAttribsARB)wglGetProcAddress("wglCreateContextAttribsARB")) +{ + if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION" ") + || extensionNames.indexOf(" "SAMPLE_BUFFER_EXTENSION" ") != -1) + extensions |= SampleBuffers; + // Get version + do { + const QByteArray version = QOpenGLStaticContext::getGlString(GL_VERSION); + if (version.isEmpty()) + break; + const int majorDot = version.indexOf('.'); + if (majorDot == -1) + break; + int minorDot = version.indexOf('.', majorDot + 1); + if (minorDot == -1) + minorDot = version.size(); + majorVersion = version.mid(0, majorDot).toInt(); + minorVersion = version.mid(majorDot + 1, minorDot - majorDot - 1).toInt(); + } while (false); +} + +QByteArray QOpenGLStaticContext::getGlString(unsigned int which) +{ + if (const GLubyte *s = glGetString(which)) + return QByteArray((const char*)s); + return QByteArray(); +} + +QOpenGLStaticContext *QOpenGLStaticContext::create() +{ + // We need a current context for wglGetProcAdress()/getGLString() to work. + QScopedPointer<QOpenGLTemporaryContext> temporaryContext; + if (!wglGetCurrentContext()) + temporaryContext.reset(new QOpenGLTemporaryContext); + QOpenGLStaticContext *result = new QOpenGLStaticContext; + if (QWindowsContext::verboseGL) + qDebug() << __FUNCTION__ << *result; + return result; +} + +QDebug operator<<(QDebug d, const QOpenGLStaticContext &s) +{ + QDebug nsp = d.nospace(); + nsp << "OpenGL: " << s.vendor << ',' << s.renderer << ",v" + << s.majorVersion << '.' << s.minorVersion; + if (s.extensions & QOpenGLStaticContext::SampleBuffers) + nsp << ",SampleBuffers"; + if (s.hasExtensions()) + nsp << ", Extension-API present"; + nsp << "\nExtensions: " << s.extensionNames; + return d; +} + +/*! + \class QWindowsGLContext + \brief Open GL context. + + An Open GL context for use with several windows. + As opposed to other implementations, activating a GL context for + a window requires a HDC allocated for it. The first time this + HDC is created for the window, the pixel format must be applied, + which will affect the window as well. The HDCs are stored in a list of + QOpenGLContextData and are released in doneCurrent(). + + \ingroup qt-lighthouse-win +*/ + +QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext, + QOpenGLContext *context) : + m_staticContext(staticContext), + m_context(context), + m_pixelFormat(0), m_extensionsUsed(false) +{ + // workaround for matrox driver: + // make a cheap call to opengl to force loading of DLL + static bool opengl32dll = false; + if (!opengl32dll) { + GLint params; + glGetIntegerv(GL_DEPTH_BITS, ¶ms); + opengl32dll = true; + } + + // SetPixelFormat (as of Windows 7) requires a real window. + // Create a dummy one as we are not associated with a window yet. + // Try to find a suitable pixel format using preferably ARB extensions + // (default to GDI) and store that. + HWND dummyWindow = 0; + HDC hdc = 0; + do { + dummyWindow = createDummyGLWindow(); + if (!dummyWindow) + break; + hdc = GetDC(dummyWindow); + if (!hdc) + break; + + if (QWindowsContext::verboseGL > 1) + describeFormats(hdc); + // Preferably use direct rendering and ARB extensions (unless pixmap) + const QWindowsOpenGLAdditionalFormat + requestedAdditional(QWindowsGLDirectRendering|QWindowsGLDeprecatedFunctions); + const bool tryExtensions = m_staticContext->hasExtensions() + && !testFlag(requestedAdditional.formatFlags, QWindowsGLRenderToPixmap); + QWindowsOpenGLAdditionalFormat obtainedAdditional; + if (tryExtensions) { + m_pixelFormat = + ARB::choosePixelFormat(hdc, *m_staticContext, context->format(), + requestedAdditional, &m_obtainedPixelFormatDescriptor); + if (m_pixelFormat > 0) { + m_obtainedFormat = + ARB::qSurfaceFormatFromHDC(*m_staticContext, hdc, m_pixelFormat, + &obtainedAdditional); + m_extensionsUsed = true; + } + } // tryExtensions + if (!m_pixelFormat) { // Failed, try GDI + m_pixelFormat = GDI::choosePixelFormat(hdc, context->format(), requestedAdditional, + &m_obtainedPixelFormatDescriptor); + if (m_pixelFormat) + m_obtainedFormat = + GDI::qSurfaceFormatFromPixelFormat(m_obtainedPixelFormatDescriptor, + &obtainedAdditional); + } // try GDI + if (!m_pixelFormat) { + qWarning("%s: Unable find a suitable pixel format.", __FUNCTION__); + break; + } + if (!SetPixelFormat(hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { + qErrnoWarning("SetPixelFormat failed."); + break; + } + // Create context with sharing, again preferably using ARB. + HGLRC sharingRenderingContext = 0; + if (const QPlatformOpenGLContext *sc = context->shareHandle()) + sharingRenderingContext = static_cast<const QWindowsGLContext *>(sc)->renderingContext(); + + if (m_extensionsUsed) + m_renderingContext = + ARB::createContext(*m_staticContext, hdc, context->format(), + requestedAdditional, 0, 0, sharingRenderingContext); + if (!m_renderingContext) + m_renderingContext = GDI::createContext(hdc, sharingRenderingContext); + + if (!m_renderingContext) { + qWarning("Unable to create a GL Context."); + break; + } + } while (false); + if (hdc) + ReleaseDC(dummyWindow, hdc); + if (dummyWindow) + DestroyWindow(dummyWindow); + + if (QWindowsContext::verboseGL) + qDebug() + << __FUNCTION__ << this << " requested: " << context->format() + << "\n obtained #" << m_pixelFormat << (m_extensionsUsed ? "ARB" : "GDI") + << m_obtainedFormat << "\n " << m_obtainedPixelFormatDescriptor + << "\n HGLRC=" << m_renderingContext; +} + +QWindowsGLContext::~QWindowsGLContext() +{ + if (m_renderingContext) + wglDeleteContext(m_renderingContext); + releaseDCs(); +} + +void QWindowsGLContext::releaseDCs() +{ + const QOpenGLContextData *end = m_windowContexts.end(); + for (const QOpenGLContextData *p = m_windowContexts.begin(); p < end; ++p) + ReleaseDC(p->hwnd, p->hdc); + m_windowContexts.resize(0); +} + +static inline QWindowsWindow *glWindowOf(QPlatformSurface *s) +{ + return static_cast<QWindowsWindow *>(s); +} + +static inline HWND handleOf(QPlatformSurface *s) +{ + return glWindowOf(s)->handle(); +} + +// Find a window in a context list. +static inline const QOpenGLContextData * + findByHWND(const Array<QOpenGLContextData> &data, HWND hwnd) +{ + const QOpenGLContextData *end = data.end(); + for (const QOpenGLContextData *p = data.begin(); p < end; ++p) + if (p->hwnd == hwnd) + return p; + return 0; +} + +void QWindowsGLContext::swapBuffers(QPlatformSurface *surface) +{ + if (QWindowsContext::verboseGL > 1) + qDebug() << __FUNCTION__ << surface; + if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, handleOf(surface))) { + SwapBuffers(contextData->hdc); + } else { + qWarning("%s: Cannot find window %p", __FUNCTION__, handleOf(surface)); + } +} + +bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) +{ +#ifdef DEBUG_GL + if (QWindowsContext::verboseGL > 1) + qDebug("%s context=%p contexts=%d", __FUNCTION__, this, m_windowContexts.size()); +#endif // DEBUG_GL + // Do we already have a DC entry for that window? + QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); + const HWND hwnd = window->handle(); + if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, hwnd)) + return wglMakeCurrent(contextData->hdc, contextData->renderingContext); + // Create a new entry. + const QOpenGLContextData newContext(m_renderingContext, hwnd, GetDC(hwnd)); + if (!newContext.hdc) + return false; + // Initialize pixel format first time. This will apply to + // the HWND as well and must be done only once. + if (!window->testFlag(QWindowsWindow::PixelFormatInitialized)) { + if (!SetPixelFormat(newContext.hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { + qErrnoWarning("%s: SetPixelFormat() failed", __FUNCTION__); + ReleaseDC(newContext.hwnd, newContext.hdc); + return false; + } + window->setFlag(QWindowsWindow::PixelFormatInitialized); + } + m_windowContexts.append(newContext); + return wglMakeCurrent(newContext.hdc, newContext.renderingContext); +} + +void QWindowsGLContext::doneCurrent() +{ +#ifdef DEBUG_GL + if (QWindowsContext::verboseGL > 1) + qDebug("%s context=%p %d contexts", __FUNCTION__, this, m_windowContexts.size()); +#endif // DEBUG_GL + wglMakeCurrent(0, 0); + releaseDCs(); +} + +QWindowsGLContext::GL_Proc QWindowsGLContext::getProcAddress(const QByteArray &procName) +{ + // TODO: Will that work with the calling conventions? + GL_Proc procAddress = reinterpret_cast<GL_Proc>(wglGetProcAddress(procName.constData())); + if (QWindowsContext::verboseGL) + qDebug("%s('%s') with current_hglrc=%p returns %p", + __FUNCTION__, procName.constData(), + wglGetCurrentContext(), procAddress); + return procAddress; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h new file mode 100644 index 0000000000..0bf8ffbbc5 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSGLCONTEXT_H +#define QWINDOWSGLCONTEXT_H + +#include "array.h" +#include "qtwindows_additional.h" + +#include <QtGui/QPlatformOpenGLContext> +#include <QtGui/QOpenGLContext> +#include <QtCore/QSharedPointer> + +QT_BEGIN_NAMESPACE + +class QDebug; + +enum QWindowsGLFormatFlags +{ + QWindowsGLDirectRendering = 0x1, + QWindowsGLOverlay = 0x2, + QWindowsGLRenderToPixmap = 0x4, + QWindowsGLAccumBuffer = 0x8, + QWindowsGLDeprecatedFunctions = 0x10 +}; + +// Additional format information for Windows. +struct QWindowsOpenGLAdditionalFormat +{ + QWindowsOpenGLAdditionalFormat(unsigned formatFlagsIn = 0, unsigned pixmapDepthIn = 0) : + formatFlags(formatFlagsIn), pixmapDepth(pixmapDepthIn) {} + unsigned formatFlags; // QWindowsGLFormatFlags. + unsigned pixmapDepth; // for QWindowsGLRenderToPixmap +}; + +// Per-window data for active OpenGL contexts. +struct QOpenGLContextData +{ + QOpenGLContextData(HGLRC r, HWND h, HDC d) : renderingContext(r), hwnd(h), hdc(d) {} + QOpenGLContextData() : renderingContext(0), hwnd(0), hdc(0) {} + + HGLRC renderingContext; + HWND hwnd; + HDC hdc; +}; + +class QOpenGLStaticContext +{ + Q_DISABLE_COPY(QOpenGLStaticContext) + QOpenGLStaticContext(); +public: + enum Extensions + { + SampleBuffers = 0x1 + }; + + typedef bool + (APIENTRY *WglGetPixelFormatAttribIVARB) + (HDC hdc, int iPixelFormat, int iLayerPlane, + uint nAttributes, const int *piAttributes, int *piValues); + + typedef bool + (APIENTRY *WglChoosePixelFormatARB)(HDC hdc, const int *piAttribList, + const float *pfAttribFList, uint nMaxFormats, int *piFormats, + UINT *nNumFormats); + + typedef HGLRC + (APIENTRY *WglCreateContextAttribsARB)(HDC, HGLRC, const int *); + + bool hasExtensions() const + { return wglGetPixelFormatAttribIVARB && wglChoosePixelFormatARB && wglCreateContextAttribsARB; } + + static QOpenGLStaticContext *create(); + static QByteArray getGlString(unsigned int which); + + const QByteArray vendor; + const QByteArray renderer; + const QByteArray extensionNames; + int majorVersion; + int minorVersion; + unsigned extensions; + + WglGetPixelFormatAttribIVARB wglGetPixelFormatAttribIVARB; + WglChoosePixelFormatARB wglChoosePixelFormatARB; + WglCreateContextAttribsARB wglCreateContextAttribsARB; +}; + +QDebug operator<<(QDebug d, const QOpenGLStaticContext &); + +class QWindowsGLContext : public QPlatformOpenGLContext +{ +public: + typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr; + + explicit QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext, + QOpenGLContext *context); + virtual ~QWindowsGLContext(); + bool isValid() const { return m_renderingContext; } + virtual QSurfaceFormat format() const { return m_obtainedFormat; } + + virtual void swapBuffers(QPlatformSurface *surface); + + virtual bool makeCurrent(QPlatformSurface *surface); + virtual void doneCurrent(); + + typedef void (*GL_Proc) (); + + virtual GL_Proc getProcAddress(const QByteArray &procName); + + HGLRC renderingContext() const { return m_renderingContext; } + +private: + inline void releaseDCs(); + + const QOpenGLStaticContextPtr m_staticContext; + QOpenGLContext *m_context; + QSurfaceFormat m_obtainedFormat; + HGLRC m_renderingContext; + Array<QOpenGLContextData> m_windowContexts; + PIXELFORMATDESCRIPTOR m_obtainedPixelFormatDescriptor; + int m_pixelFormat; + bool m_extensionsUsed; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSGLCONTEXT_H diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp new file mode 100644 index 0000000000..fe03a7ffe8 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsguieventdispatcher.h" +#include "qwindowscontext.h" + +#include <QtGui/QWindowSystemInterface> + +#include <QtCore/QStack> +#include <QtCore/QDebug> + +#include <windowsx.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsGuiEventDispatcher + \brief Event dispatcher for Windows + + Maintains a global stack storing the current event dispatcher and + its processing flags for access from the Windows procedure + qWindowsWndProc. Handling the Lighthouse gui events should be done + from within the qWindowsWndProc to ensure correct processing of messages. + + \ingroup qt-lighthouse-win +*/ + +typedef QStack<QWindowsGuiEventDispatcher::DispatchContext> DispatchContextStack; + +Q_GLOBAL_STATIC(DispatchContextStack, dispatchContextStack) + +QWindowsGuiEventDispatcher::QWindowsGuiEventDispatcher(QObject *parent) : + QEventDispatcherWin32(parent) +{ + setObjectName(QStringLiteral("QWindowsGuiEventDispatcher_0x") + QString::number((quintptr)this, 16)); + if (QWindowsContext::verboseEvents) + qDebug("%s %s", __FUNCTION__, qPrintable(objectName())); + dispatchContextStack()->push(DispatchContext(this, QEventLoop::AllEvents)); +} + +QWindowsGuiEventDispatcher::~QWindowsGuiEventDispatcher() +{ + if (QWindowsContext::verboseEvents) + qDebug("%s %s", __FUNCTION__, qPrintable(objectName())); + if (!dispatchContextStack()->isEmpty()) + dispatchContextStack()->pop(); +} + +bool QWindowsGuiEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + DispatchContextStack &stack = *dispatchContextStack(); + if (QWindowsContext::verboseEvents > 2) + qDebug(">%s %s %d", __FUNCTION__, qPrintable(objectName()), stack.size()); + stack.push(DispatchContext(this, flags)); + const bool rc = QEventDispatcherWin32::processEvents(flags); + stack.pop(); + if (QWindowsContext::verboseEvents > 2) + qDebug("<%s %s returns %d", __FUNCTION__, qPrintable(objectName()), rc); + return rc; +} + +QWindowsGuiEventDispatcher::DispatchContext QWindowsGuiEventDispatcher::currentDispatchContext() +{ + const DispatchContextStack &stack = *dispatchContextStack(); + if (stack.isEmpty()) { + qWarning("%s: No dispatch context", __FUNCTION__); + return DispatchContext(0, 0); + } + return stack.top(); +} + +// Helpers for printing debug output for WM_* messages. +struct MessageDebugEntry +{ + UINT message; + const char *description; + bool interesting; +}; + +static const MessageDebugEntry +messageDebugEntries[] = { + {WM_CREATE, "WM_CREATE", true}, + {WM_PAINT, "WM_PAINT", true}, + {WM_CLOSE, "WM_CLOSE", true}, + {WM_DESTROY, "WM_DESTROY", true}, + {WM_MOVE, "WM_MOVE", true}, + {WM_SIZE, "WM_SIZE", true}, + {WM_MOUSEACTIVATE,"WM_MOUSEACTIVATE", true}, + {WM_CHILDACTIVATE, "WM_CHILDACTIVATE", true}, + {WM_PARENTNOTIFY, "WM_PARENTNOTIFY", true}, + {WM_GETICON, "WM_GETICON", false}, + {WM_KEYDOWN, "WM_KEYDOWN", true}, + {WM_SYSKEYDOWN, "WM_SYSKEYDOWN", true}, + {WM_SYSCOMMAND, "WM_SYSCOMMAND", true}, + {WM_KEYUP, "WM_KEYUP", true}, + {WM_SYSKEYUP, "WM_SYSKEYUP", true}, + {WM_IME_CHAR, "WM_IMECHAR", true}, + {WM_IME_KEYDOWN, "WM_IMECHAR", true}, + {WM_CANCELMODE, "WM_CANCELMODE", true}, + {WM_CHAR, "WM_CHAR", true}, + {WM_DEADCHAR, "WM_DEADCHAR", true}, + {WM_ACTIVATE, "WM_ACTIVATE", true}, + {WM_GETMINMAXINFO, "WM_GETMINMAXINFO", true}, + {WM_SETFOCUS, "WM_SETFOCUS", true}, + {WM_KILLFOCUS, "WM_KILLFOCUS", true}, + {WM_ENABLE, "WM_ENABLE", true}, + {WM_SHOWWINDOW, "WM_SHOWWINDOW", true}, + {WM_GETMINMAXINFO, "WM_GETMINMAXINFO"}, + {WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING", true}, + {WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED", true}, + {WM_SETCURSOR, "WM_SETCURSOR", false}, + {WM_GETFONT, "WM_GETFONT", true}, + {WM_NCMOUSEMOVE, "WM_NCMOUSEMOVE", true}, + {WM_LBUTTONDOWN, "WM_LBUTTONDOWN", true}, + {WM_LBUTTONUP, "WM_LBUTTONUP", true}, + {WM_LBUTTONDBLCLK, "WM_LBUTTONDBLCLK", true}, + {WM_RBUTTONDOWN, "WM_RBUTTONDOWN", true}, + {WM_RBUTTONUP, "WM_RBUTTONUP", true}, + {WM_RBUTTONDBLCLK, "WM_RBUTTONDBLCLK", true}, + {WM_MBUTTONDOWN, "WM_MBUTTONDOWN", true}, + {WM_MBUTTONUP, "WM_MBUTTONUP", true}, + {WM_MBUTTONDBLCLK, "WM_MBUTTONDBLCLK", true}, + {WM_MOUSEWHEEL, "WM_MOUSEWHEEL", true}, + {WM_XBUTTONDOWN, "WM_XBUTTONDOWN", true}, + {WM_XBUTTONUP, "WM_XBUTTONUP", true}, + {WM_XBUTTONDBLCLK, "WM_XBUTTONDBLCLK", true}, + {WM_MOUSEHWHEEL, "WM_MOUSEHWHEEL", true}, + {WM_NCCREATE, "WM_NCCREATE", true}, + {WM_NCCALCSIZE, "WM_NCCALCSIZE", true}, + {WM_NCACTIVATE, "WM_NCACTIVATE", true}, + {WM_NCMOUSELEAVE, "WM_NCMOUSELEAVE", true}, + {WM_NCLBUTTONDOWN, "WM_NCLBUTTONDOWN", true}, + {WM_NCLBUTTONUP, "WM_NCLBUTTONUP", true}, + {WM_ACTIVATEAPP, "WM_ACTIVATEAPP", true}, + {WM_NCPAINT, "WM_NCPAINT", true}, + {WM_ERASEBKGND, "WM_ERASEBKGND", true}, + {WM_MOUSEMOVE, "WM_MOUSEMOVE", true}, + {WM_MOUSELEAVE, "WM_MOUSELEAVE", true}, + {WM_NCHITTEST, "WM_NCHITTEST", false}, + {WM_IME_SETCONTEXT, "WM_IME_SETCONTEXT", true}, + {WM_INPUTLANGCHANGE, "WM_INPUTLANGCHANGE", true}, + {WM_IME_NOTIFY, "WM_IME_NOTIFY", true}, +#if defined(WM_DWMNCRENDERINGCHANGED) + {WM_DWMNCRENDERINGCHANGED, "WM_DWMNCRENDERINGCHANGED", true}, +#endif + {WM_IME_SETCONTEXT, "WM_IME_SETCONTEXT", true}, + {WM_IME_NOTIFY, "WM_IME_NOTIFY", true}, + {WM_TOUCH, "WM_TOUCH", true}, + {WM_CHANGECBCHAIN, "WM_CHANGECBCHAIN", true}, + {WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD", true}, + {WM_RENDERFORMAT, "WM_RENDERFORMAT", true}, + {WM_RENDERALLFORMATS, "WM_RENDERALLFORMATS", true}, + {WM_DESTROYCLIPBOARD, "WM_DESTROYCLIPBOARD", true}, + {WM_CAPTURECHANGED, "WM_CAPTURECHANGED", true}, + {WM_IME_STARTCOMPOSITION, "WM_IME_STARTCOMPOSITION"}, + {WM_IME_COMPOSITION, "WM_IME_COMPOSITION"}, + {WM_IME_ENDCOMPOSITION, "WM_IME_ENDCOMPOSITION"}, + {WM_IME_NOTIFY, "WM_IME_NOTIFY"}, + {WM_IME_REQUEST, "WM_IME_REQUEST"} +}; + +static inline const MessageDebugEntry *messageDebugEntry(UINT msg) +{ + for (size_t i = 0; i < sizeof(messageDebugEntries)/sizeof(MessageDebugEntry); i++) + if (messageDebugEntries[i].message == msg) + return messageDebugEntries + i; + return 0; +} + +const char *QWindowsGuiEventDispatcher::windowsMessageName(UINT msg) +{ + if (const MessageDebugEntry *e = messageDebugEntry(msg)) + return e->description; + return "Unknown"; +} + +QT_END_NAMESPACE diff --git a/src/plugins/gfxdrivers/ahi/qscreenahi_qws.h b/src/plugins/platforms/windows/qwindowsguieventdispatcher.h index a00cf77abf..00fd234eff 100644 --- a/src/plugins/gfxdrivers/ahi/qscreenahi_qws.h +++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Contact: Nokia Corporation (info@qt.nokia.com) ** ** This file is part of the plugins of the Qt Toolkit. ** @@ -39,46 +39,33 @@ ** ****************************************************************************/ -#ifndef QAHISCREEN_H -#define QAHISCREEN_H +#ifndef QWINDOWSGUIEVENTDISPATCHER_H +#define QWINDOWSGUIEVENTDISPATCHER_H -#include <QtGui/qscreenlinuxfb_qws.h> +#include "qtwindowsglobal.h" +#include "qtwindows_additional.h" -#ifndef QT_NO_QWS_AHI - -QT_BEGIN_HEADER +#include <QtCore/QPair> +#include <QtCore/private/qeventdispatcher_win_p.h> QT_BEGIN_NAMESPACE -QT_MODULE(Gui) - -class QAhiScreenPrivate; - -class QAhiScreen : public QScreen +class QWindowsGuiEventDispatcher : public QEventDispatcherWin32 { + Q_OBJECT public: - QAhiScreen(int displayId); - ~QAhiScreen(); + explicit QWindowsGuiEventDispatcher(QObject *parent = 0); + ~QWindowsGuiEventDispatcher(); - bool connect(const QString &displaySpec); - void disconnect(); - bool initDevice(); - void shutdownDevice(); - void setMode(int width, int height, int depth); + typedef QPair<QAbstractEventDispatcher *, QEventLoop::ProcessEventsFlags> DispatchContext; - void blit(const QImage &image, const QPoint &topLeft, - const QRegion ®ion); - void solidFill(const QColor &color, const QRegion ®ion); + static DispatchContext currentDispatchContext(); -private: - bool configure(); + static const char *windowsMessageName(UINT msg); - QAhiScreenPrivate *d_ptr; + virtual bool QT_ENSURE_STACK_ALIGNED_FOR_SSE processEvents(QEventLoop::ProcessEventsFlags flags); }; QT_END_NAMESPACE -QT_END_HEADER - -#endif // QT_NO_QWS_AHI -#endif // QAHISCREEN_H +#endif // QWINDOWSGUIEVENTDISPATCHER_H diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp new file mode 100644 index 0000000000..e3dc100805 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -0,0 +1,598 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsinputcontext.h" +#include "qwindowscontext.h" +#include "qwindowswindow.h" +#include "qwindowsintegration.h" +#include "qwindowsmousehandler.h" + +#include <QtCore/QDebug> +#include <QtCore/QObject> +#include <QtCore/QRect> +#include <QtCore/QTextBoundaryFinder> + +#include <QtGui/QInputMethodEvent> +#include <QtGui/QTextCharFormat> +#include <QtGui/QPalette> +#include <QtGui/QGuiApplication> + +QT_BEGIN_NAMESPACE + +static inline QByteArray debugComposition(int lParam) +{ + QByteArray str; + if (lParam & GCS_RESULTSTR) + str += "RESULTSTR "; + if (lParam & GCS_COMPSTR) + str += "COMPSTR "; + if (lParam & GCS_COMPATTR) + str += "COMPATTR "; + if (lParam & GCS_CURSORPOS) + str += "CURSORPOS "; + if (lParam & GCS_COMPCLAUSE) + str += "COMPCLAUSE "; + if (lParam & CS_INSERTCHAR) + str += "INSERTCHAR "; + if (lParam & CS_NOMOVECARET) + str += "NOMOVECARET "; + return str; +} + +// Cancel current IME composition. +static inline void imeNotifyCancelComposition(HWND hwnd) +{ + const HIMC himc = ImmGetContext(hwnd); + ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); + ImmReleaseContext(hwnd, himc); +} + +// Query a QObject for an InputMethod-related value +// by sending a QInputMethodQueryEvent. +template <class T> + bool inputMethodQuery(QObject *fo, Qt::InputMethodQuery query, T *result) +{ + QInputMethodQueryEvent queryEvent(query); + if (!QCoreApplication::sendEvent(fo, &queryEvent)) + return false; + *result = qvariant_cast<T>(queryEvent.value()); + return true; +} + +/*! + \class QWindowsInputContext + \brief Windows Input context implementation + + Handles input of foreign characters (particularly East Asian) + languages. + + \section1 Testing + + \list + \o Install the East Asian language support and choose Japanese (say). + \o Compile the \a mainwindows/mdi example and open a text window. + \o In the language bar, switch to Japanese and choose the + Input method 'Hiragana'. + \o In a text editor control, type the syllable \a 'la'. + Underlined characters show up, indicating that there is completion + available. Press the Space key two times. A completion popup occurs + which shows the options. + \endlist + + Reconversion: Input texts can be 'converted' into different + input modes or more completion suggestions can be made based on + context to correct errors. This is bound to the 'Conversion key' + (F13-key in Japanese, which can be changed in the + configuration). After writing text, pressing the key selects text + and triggers a conversion popup, which shows the alternatives for + the word. + + \section1 Interaction + + When the user activates input methods, Windows sends + WM_IME_STARTCOMPOSITION, WM_IME_COMPOSITION, + WM_IME_ENDCOMPOSITION messages that trigger startComposition(), + composition(), endComposition(), respectively. No key events are sent. + + composition() determines the markup of the pre-edit or selected + text and/or the final text and sends that to the focus object. + + In between startComposition(), endComposition(), multiple + compositions may happen (isComposing). + + update() is called to synchronize the position of the candidate + window with the microfocus rectangle of the focus object. + Also, a hidden caret is moved along with that position, + which is important for some Chinese input methods. + + reset() is called to cancel a composition if the mouse is + moved outside or for example some Undo/Redo operation is + invoked. + + \note Mouse interaction of popups with + QtWindows::InputMethodOpenCandidateWindowEvent and + QtWindows::InputMethodCloseCandidateWindowEvent + needs to be checked (mouse grab might interfere with candidate window). + + \ingroup qt-lighthouse-win +*/ + +QWindowsInputContext::CompositionContext::CompositionContext() : + hwnd(0), haveCaret(false), position(0), isComposing(false) +{ +} + +QWindowsInputContext::QWindowsInputContext() : + m_WM_MSIME_MOUSE(RegisterWindowMessage(L"MSIMEMouseOperation")), + m_endCompositionRecursionGuard(false) +{ +} + +QWindowsInputContext::~QWindowsInputContext() +{ +} + +/*! + \brief Cancels a composition. +*/ + +void QWindowsInputContext::reset() +{ + QPlatformInputContext::reset(); + if (!m_compositionContext.hwnd) + return; + QObject *fo = focusObject(); + if (QWindowsContext::verboseInputMethods) + qDebug() << __FUNCTION__<< fo; + if (!fo) + return; + if (m_compositionContext.isComposing) { + QInputMethodEvent event; + if (!m_compositionContext.composition.isEmpty()) + event.setCommitString(m_compositionContext.composition); + QCoreApplication::sendEvent(fo, &event); + endContextComposition(); + } + imeNotifyCancelComposition(m_compositionContext.hwnd); + doneContext(); +} + +/*! + \brief Moves the candidate window along with microfocus of the focus object. +*/ + +void QWindowsInputContext::update() +{ + QPlatformInputContext::update(); + if (!m_compositionContext.hwnd) + return; + QObject *fo = focusObject(); + if (!fo) + return; + const HIMC himc = ImmGetContext(m_compositionContext.hwnd); + if (!himc) + return; + // Move candidate list window to the microfocus position. + QRect globalMicroFocusRect; + if (!inputMethodQuery(fo, Qt::ImCursorRectangle, &globalMicroFocusRect) || !globalMicroFocusRect.isValid()) + return; + if (QWindowsContext::verboseInputMethods) + qDebug() << __FUNCTION__ << himc << globalMicroFocusRect; + + if (globalMicroFocusRect.isValid()) { + const QRect microFocusRect(QWindowsGeometryHint::mapFromGlobal(m_compositionContext.hwnd, + globalMicroFocusRect.topLeft()), + globalMicroFocusRect.size()); + COMPOSITIONFORM cf; + // ### need X-like inputStyle config settings + cf.dwStyle = CFS_FORCE_POSITION; + cf.ptCurrentPos.x = microFocusRect.x(); + cf.ptCurrentPos.y = microFocusRect.y(); + + CANDIDATEFORM candf; + candf.dwIndex = 0; + candf.dwStyle = CFS_EXCLUDE; + candf.ptCurrentPos.x = microFocusRect.x(); + candf.ptCurrentPos.y = microFocusRect.y() + microFocusRect.height(); + candf.rcArea.left = microFocusRect.x(); + candf.rcArea.top = microFocusRect.y(); + candf.rcArea.right = microFocusRect.x() + microFocusRect.width(); + candf.rcArea.bottom = microFocusRect.y() + microFocusRect.height(); + + if (m_compositionContext.haveCaret) + SetCaretPos(microFocusRect.x(), microFocusRect.y()); + + ImmSetCompositionWindow(himc, &cf); + ImmSetCandidateWindow(himc, &candf); + } + ImmReleaseContext(m_compositionContext.hwnd, himc); +} + +void QWindowsInputContext::mouseHandler(int pos, QMouseEvent *event) +{ + if (event->type() != QEvent::MouseButtonPress || !m_compositionContext.hwnd) + return; + if (QWindowsContext::verboseInputMethods) + qDebug() << __FUNCTION__ << pos << event; + + if (pos < 0 || pos > m_compositionContext.composition.size()) + reset(); + + // Magic code that notifies Japanese IME about the cursor + // position. + const DWORD button = QWindowsMouseHandler::mouseButtonsToKeyState(event->buttons()); + const HIMC himc = ImmGetContext(m_compositionContext.hwnd); + const HWND imeWindow = ImmGetDefaultIMEWnd(m_compositionContext.hwnd); + SendMessage(imeWindow, m_WM_MSIME_MOUSE, MAKELONG(MAKEWORD(button, pos == 0 ? 2 : 1), pos), (LPARAM)himc); + ImmReleaseContext(m_compositionContext.hwnd, himc); +} + +void QWindowsInputContext::setFocusObject(QObject *object) +{ + if (QWindowsContext::verboseInputMethods) + qDebug() << __FUNCTION__ << object; + + QPlatformInputContext::setFocusObject(object); +} + +QWindowsInputContext *QWindowsInputContext::instance() +{ + return static_cast<QWindowsInputContext *>(QWindowsIntegration::instance()->inputContext()); +} + +static inline QString getCompositionString(HIMC himc, DWORD dwIndex) +{ + enum { bufferSize = 256 }; + wchar_t buffer[bufferSize]; + const int length = ImmGetCompositionString(himc, dwIndex, buffer, bufferSize * sizeof(wchar_t)); + return QString::fromWCharArray(buffer, length / sizeof(wchar_t)); +} + +// Determine the converted string range as pair of start/length to be selected. +static inline void getCompositionStringConvertedRange(HIMC himc, int *selStart, int *selLength) +{ + enum { bufferSize = 256 }; + // Find the range of bytes with ATTR_TARGET_CONVERTED set. + char attrBuffer[bufferSize]; + *selStart = *selLength = 0; + if (const int attrLength = ImmGetCompositionString(himc, GCS_COMPATTR, attrBuffer, bufferSize)) { + int start = 0; + while (start < attrLength && !(attrBuffer[start] & ATTR_TARGET_CONVERTED)) + start++; + if (start < attrLength) { + int end = start + 1; + while (end < attrLength && (attrBuffer[end] & ATTR_TARGET_CONVERTED)) + end++; + *selStart = start; + *selLength = end - start; + } + } +} + +enum StandardFormat { + PreeditFormat, + SelectionFormat +}; + +static inline QTextFormat standardFormat(StandardFormat format) +{ + QTextCharFormat result; + switch (format) { + case PreeditFormat: + result.setUnderlineStyle(QTextCharFormat::DashUnderline); + break; + case SelectionFormat: { + // TODO: Should be that of the widget? + const QPalette palette = QGuiApplication::palette(); + const QColor background = palette.text().color(); + result.setBackground(QBrush(background)); + result.setForeground(palette.background()); + break; + } + } + return result; +} + +bool QWindowsInputContext::startComposition(HWND hwnd) +{ + const QObject *fo = focusObject(); + if (!fo) + return false; + // This should always match the object. + QWindow *window = QGuiApplication::activeWindow(); + if (!window) + return false; + if (QWindowsContext::verboseInputMethods) + qDebug() << __FUNCTION__ << fo << window; + if (!fo || QWindowsWindow::handleOf(window) != hwnd) + return false; + initContext(hwnd); + startContextComposition(); + return true; +} + +void QWindowsInputContext::startContextComposition() +{ + if (m_compositionContext.isComposing) { + qWarning("%s: Called out of sequence.", __FUNCTION__); + return; + } + m_compositionContext.isComposing = true; + m_compositionContext.composition.clear(); + m_compositionContext.position = 0; + update(); +} + +void QWindowsInputContext::endContextComposition() +{ + if (!m_compositionContext.isComposing) { + qWarning("%s: Called out of sequence.", __FUNCTION__); + return; + } + m_compositionContext.composition.clear(); + m_compositionContext.position = 0; + m_compositionContext.isComposing = false; +} + +// Create a list of markup attributes for QInputMethodEvent +// to display the selected part of the intermediate composition +// result differently. +static inline QList<QInputMethodEvent::Attribute> + intermediateMarkup(int position, int compositionLength, + int selStart, int selLength) +{ + QList<QInputMethodEvent::Attribute> attributes; + if (selStart > 0) + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, selStart, + standardFormat(PreeditFormat)); + if (selLength) + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, selStart, selLength, + standardFormat(SelectionFormat)); + if (selStart + selLength < compositionLength) + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, selStart + selLength, + compositionLength - selStart - selLength, + standardFormat(PreeditFormat)); + if (position >= 0) + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, position, selLength ? 0 : 1, QVariant()); + return attributes; +} + +/*! + \brief Notify focus object about markup or final text. +*/ + +bool QWindowsInputContext::composition(HWND hwnd, LPARAM lParamIn) +{ + QObject *fo = focusObject(); + const int lParam = int(lParamIn); + if (QWindowsContext::verboseInputMethods) + qDebug() << '>' << __FUNCTION__ << fo << debugComposition(lParam) + << " composing=" << m_compositionContext.isComposing; + if (!fo || m_compositionContext.hwnd != hwnd || !lParam) + return false; + const HIMC himc = ImmGetContext(m_compositionContext.hwnd); + if (!himc) + return false; + + QScopedPointer<QInputMethodEvent> event; + if (lParam & (GCS_COMPSTR | GCS_COMPATTR | GCS_CURSORPOS)) { + if (!m_compositionContext.isComposing) + startContextComposition(); + // Some intermediate composition result. Parametrize event with + // attribute sequence specifying the formatting of the converted part. + int selStart, selLength; + m_compositionContext.composition = getCompositionString(himc, GCS_COMPSTR); + m_compositionContext.position = ImmGetCompositionString(himc, GCS_CURSORPOS, 0, 0); + getCompositionStringConvertedRange(himc, &selStart, &selLength); + if ((lParam & CS_INSERTCHAR) && (lParam & CS_NOMOVECARET)) { + // make Korean work correctly. Hope this is correct for all IMEs + selStart = 0; + selLength = m_compositionContext.composition.size(); + } + if (!selLength) + selStart = 0; + + event.reset(new QInputMethodEvent(m_compositionContext.composition, + intermediateMarkup(m_compositionContext.position, + m_compositionContext.composition.size(), + selStart, selLength))); + } + if (event.isNull()) + event.reset(new QInputMethodEvent); + + if (lParam & GCS_RESULTSTR) { + // A fixed result, return the converted string + event->setCommitString(getCompositionString(himc, GCS_RESULTSTR)); + endContextComposition(); + } + const bool result = QCoreApplication::sendEvent(fo, event.data()); + if (QWindowsContext::verboseInputMethods) + qDebug() << '<' << __FUNCTION__ << "sending markup=" + << event->attributes().size() + << " commit=" << event->commitString() + << " to " << fo << " returns " << result; + update(); + ImmReleaseContext(m_compositionContext.hwnd, himc); + return result; +} + +bool QWindowsInputContext::endComposition(HWND hwnd) +{ + if (QWindowsContext::verboseInputMethods) + qDebug() << __FUNCTION__ << m_endCompositionRecursionGuard << hwnd; + // Googles Pinyin Input Method likes to call endComposition again + // when we call notifyIME with CPS_CANCEL, so protect ourselves + // against that. + if (m_endCompositionRecursionGuard || m_compositionContext.hwnd != hwnd) + return false; + QObject *fo = focusObject(); + if (!fo) + return false; + + m_endCompositionRecursionGuard = true; + + imeNotifyCancelComposition(m_compositionContext.hwnd); + if (m_compositionContext.isComposing) { + QInputMethodEvent event; + QCoreApplication::sendEvent(fo, &event); + } + doneContext(); + + m_endCompositionRecursionGuard = false; + return true; +} + +void QWindowsInputContext::initContext(HWND hwnd) +{ + if (m_compositionContext.hwnd) + doneContext(); + m_compositionContext.hwnd = hwnd; + // Create a hidden caret which is kept at the microfocus + // position in update(). This is important for some + // Chinese input methods. + m_compositionContext.haveCaret = CreateCaret(hwnd, 0, 1, 1); + HideCaret(hwnd); + update(); + m_compositionContext.isComposing = false; + m_compositionContext.position = 0; +} + +void QWindowsInputContext::doneContext() +{ + if (!m_compositionContext.hwnd) + return; + if (m_compositionContext.haveCaret) + DestroyCaret(); + m_compositionContext.hwnd = 0; + m_compositionContext.composition.clear(); + m_compositionContext.position = 0; + m_compositionContext.isComposing = m_compositionContext.haveCaret = false; +} + +bool QWindowsInputContext::handleIME_Request(WPARAM wParam, + LPARAM lParam, + LRESULT *result) +{ + switch (int(wParam)) { + case IMR_RECONVERTSTRING: { + const int size = reconvertString(reinterpret_cast<RECONVERTSTRING *>(lParam)); + if (size < 0) + return false; + *result = size; + return true; + } + break; + case IMR_CONFIRMRECONVERTSTRING: + return true; + default: + break; + } + return false; +} + +/*! + \brief Determines the string for reconversion with selection. + + This is triggered twice by WM_IME_REQUEST, first with reconv=0 + to determine the length and later with a reconv struct to obtain + the string with the position of the selection to be reconverted. + + Obtains the text from the focus object and marks the word + for selection (might not be entirely correct for Japanese). +*/ + +int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv) +{ + QObject *fo = focusObject(); + if (!fo) + return false; + + QString surroundingText; + if (!inputMethodQuery(fo, Qt::ImSurroundingText, &surroundingText)) + return -1; + const DWORD memSize = sizeof(RECONVERTSTRING) + + (surroundingText.length() + 1) * sizeof(ushort); + if (QWindowsContext::verboseInputMethods) + qDebug() << __FUNCTION__ << " reconv=" << reconv + << " surroundingText=" << surroundingText + << " size=" << memSize; + // If memory is not allocated, return the required size. + if (!reconv) + return surroundingText.isEmpty() ? -1 : int(memSize); + + int pos = 0; + inputMethodQuery(fo, Qt::ImCursorPosition, &pos); + // Find the word in the surrounding text. + QTextBoundaryFinder bounds(QTextBoundaryFinder::Word, surroundingText); + bounds.setPosition(pos); + if (bounds.isAtBoundary()) { + if (QTextBoundaryFinder::EndWord == bounds.boundaryReasons()) + bounds.toPreviousBoundary(); + } else { + bounds.toPreviousBoundary(); + } + const int startPos = bounds.position(); + bounds.toNextBoundary(); + const int endPos = bounds.position(); + if (QWindowsContext::verboseInputMethods) + qDebug() << __FUNCTION__ << " boundary=" << startPos << endPos; + // Select the text, this will be overwritten by following IME events. + QList<QInputMethodEvent::Attribute> attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, startPos, endPos-startPos, QVariant()); + QInputMethodEvent selectEvent(QString(), attributes); + QCoreApplication::sendEvent(fo, &selectEvent); + + reconv->dwSize = memSize; + reconv->dwVersion = 0; + + reconv->dwStrLen = surroundingText.size(); + reconv->dwStrOffset = sizeof(RECONVERTSTRING); + reconv->dwCompStrLen = endPos - startPos; // TCHAR count. + reconv->dwCompStrOffset = startPos * sizeof(ushort); // byte count. + reconv->dwTargetStrLen = reconv->dwCompStrLen; + reconv->dwTargetStrOffset = reconv->dwCompStrOffset; + ushort *pastReconv = reinterpret_cast<ushort *>(reconv + 1); + qCopy(surroundingText.utf16(), surroundingText.utf16() + surroundingText.size(), + pastReconv); + return memSize; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h new file mode 100644 index 0000000000..8ea66774d4 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsinputcontext.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSINPUTCONTEXT_H +#define QWINDOWSINPUTCONTEXT_H + +#include "qtwindows_additional.h" + +#include <QtGui/QPlatformInputContext> + +QT_BEGIN_NAMESPACE + +class QInputMethodEvent; + +class QWindowsInputContext : public QPlatformInputContext +{ + struct CompositionContext + { + CompositionContext(); + + HWND hwnd; + bool haveCaret; + QString composition; + int position; + bool isComposing; + }; +public: + explicit QWindowsInputContext(); + ~QWindowsInputContext(); + + virtual void reset(); + virtual void update(); + + virtual void mouseHandler(int x, QMouseEvent *event); + virtual void setFocusObject(QObject *o); + + static QWindowsInputContext *instance(); + + bool startComposition(HWND hwnd); + bool composition(HWND hwnd, LPARAM lParam); + bool endComposition(HWND hwnd); + + int reconvertString(RECONVERTSTRING *reconv); + + bool handleIME_Request(WPARAM wparam, LPARAM lparam, LRESULT *result); + +private: + void initContext(HWND hwnd); + void doneContext(); + void startContextComposition(); + void endContextComposition(); + + const DWORD m_WM_MSIME_MOUSE; + CompositionContext m_compositionContext; + bool m_endCompositionRecursionGuard; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSINPUTCONTEXT_H diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp new file mode 100644 index 0000000000..cde6da671a --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsintegration.h" +#include "qwindowsbackingstore.h" +#include "qwindowswindow.h" +#include "qwindowscontext.h" +#include "qwindowsglcontext.h" +#include "qwindowsscreen.h" +#include "qwindowsfontdatabase.h" +#include "qwindowsguieventdispatcher.h" +#include "qwindowsclipboard.h" +#include "qwindowsdrag.h" +#include "qwindowsinputcontext.h" + +#include <QtGui/QPlatformNativeInterface> +#include <QtGui/QWindowSystemInterface> +#include <QtGui/QBackingStore> +#include <QtGui/private/qpixmap_raster_p.h> +#include <QtGui/private/qguiapplication_p.h> + +#include <QtCore/private/qeventdispatcher_win_p.h> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsNativeInterface + \brief Provides access to native handles. + + Currently implemented keys + \list + \o handle (HWND) + \o getDC (DC) + \o releaseDC Releases the previously acquired DC and returns 0. + \endlist + + \ingroup qt-lighthouse-win +*/ + +class QWindowsNativeInterface : public QPlatformNativeInterface +{ +public: + virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); + virtual void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs); +}; + +void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window) +{ + if (!window || !window->handle()) { + qWarning("%s: '%s' requested for null window or window without handle.", __FUNCTION__, resource.constData()); + return 0; + } + QWindowsWindow *bw = static_cast<QWindowsWindow *>(window->handle()); + if (resource == "handle") + return bw->handle(); + if (window->surfaceType() == QWindow::RasterSurface) { + if (resource == "getDC") + return bw->getDC(); + if (resource == "releaseDC") { + bw->releaseDC(); + return 0; + } + } + qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); + return 0; +} + +void *QWindowsNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) +{ + if (!bs || !bs->handle()) { + qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData()); + return 0; + } + QWindowsBackingStore *wbs = static_cast<QWindowsBackingStore *>(bs->handle()); + if (resource == "getDC") + return wbs->getDC(); + qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); + return 0; +} + +/*! + \class QWindowsIntegration + \brief QPlatformIntegration implementation for Windows. + \ingroup qt-lighthouse-win +*/ + +struct QWindowsIntegrationPrivate +{ + typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr; + + explicit QWindowsIntegrationPrivate(bool openGL); + + const bool m_openGL; + QWindowsContext m_context; + QWindowsFontDatabase m_fontDatabase; + QWindowsNativeInterface m_nativeInterface; + QWindowsClipboard m_clipboard; + QWindowsDrag m_drag; + QWindowsGuiEventDispatcher *m_eventDispatcher; + QOpenGLStaticContextPtr m_staticOpenGLContext; + QWindowsInputContext m_inputContext; +}; + +QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(bool openGL) + : m_openGL(openGL) + , m_context(openGL) + , m_eventDispatcher(new QWindowsGuiEventDispatcher) +{ +} + +QWindowsIntegration::QWindowsIntegration(bool openGL) : + d(new QWindowsIntegrationPrivate(openGL)) +{ + QGuiApplicationPrivate::instance()->setEventDispatcher(d->m_eventDispatcher); + d->m_clipboard.registerViewer(); + foreach (QPlatformScreen *pscr, QWindowsScreen::screens()) + screenAdded(pscr); +} + +QWindowsIntegration::~QWindowsIntegration() +{ + if (QWindowsContext::verboseIntegration) + qDebug("%s", __FUNCTION__); +} + +bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ + switch (cap) { + case ThreadedPixmaps: + return true; + case OpenGL: + return true; + case ThreadedOpenGL: + return true; + default: + return QPlatformIntegration::hasCapability(cap); + } + return false; +} + +QPlatformPixmap *QWindowsIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const +{ + if (QWindowsContext::verboseIntegration) + qDebug() << __FUNCTION__ << type; + return new QRasterPlatformPixmap(type); +} + +QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const +{ + const bool isGL = window->surfaceType() == QWindow::OpenGLSurface; + QWindowsWindow::WindowData requested; + requested.flags = window->windowFlags(); + requested.geometry = window->geometry(); + const QWindowsWindow::WindowData obtained + = QWindowsWindow::WindowData::create(window, requested, window->windowTitle(), isGL); + if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) + qDebug().nospace() + << __FUNCTION__ << ' ' << window << '\n' + << " Requested: " << requested.geometry << " Flags=" + << QWindowsWindow::debugWindowFlags(requested.flags) << '\n' + << " Obtained : " << obtained.geometry << " Margins " + << obtained.frame << " Flags=" + << QWindowsWindow::debugWindowFlags(obtained.flags) + << " Handle=" << obtained.hwnd << '\n'; + if (!obtained.hwnd) + return 0; + if (requested.flags != obtained.flags) + window->setWindowFlags(obtained.flags); + if (requested.geometry != obtained.geometry) + QWindowSystemInterface::handleGeometryChange(window, obtained.geometry); + return new QWindowsWindow(window, obtained); +} + +QPlatformBackingStore *QWindowsIntegration::createPlatformBackingStore(QWindow *window) const +{ + if (QWindowsContext::verboseIntegration) + qDebug() << __FUNCTION__ << window; + return new QWindowsBackingStore(window); +} + +QPlatformOpenGLContext + *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ + if (QWindowsContext::verboseIntegration) + qDebug() << __FUNCTION__ << context->format(); + if (d->m_staticOpenGLContext.isNull()) + d->m_staticOpenGLContext = + QSharedPointer<QOpenGLStaticContext>(QOpenGLStaticContext::create()); + QScopedPointer<QWindowsGLContext> result(new QWindowsGLContext(d->m_staticOpenGLContext, context)); + if (result->isValid()) + return result.take(); + return 0; +} + +QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const +{ + return &d->m_fontDatabase; +} + +QPlatformNativeInterface *QWindowsIntegration::nativeInterface() const +{ + return &d->m_nativeInterface; +} + +QPlatformClipboard * QWindowsIntegration::clipboard() const +{ + return &d->m_clipboard; +} + +QPlatformDrag *QWindowsIntegration::drag() const +{ + if (QWindowsContext::verboseIntegration) + qDebug("%s", __FUNCTION__ ); + return &d->m_drag; +} + +QPlatformInputContext * QWindowsIntegration::inputContext() const +{ + return &d->m_inputContext; +} + +QWindowsIntegration *QWindowsIntegration::instance() +{ + return static_cast<QWindowsIntegration *>(QGuiApplicationPrivate::platformIntegration()); +} + +QAbstractEventDispatcher * QWindowsIntegration::guiThreadEventDispatcher() const +{ + return d->m_eventDispatcher; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h new file mode 100644 index 0000000000..14a65c67e0 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSINTEGRATION_H +#define QWINDOWSINTEGRATION_H + +#include <QtGui/QPlatformIntegration> +#include <QtCore/QScopedPointer> + +QT_BEGIN_NAMESPACE + +struct QWindowsIntegrationPrivate; + +class QWindowsIntegration : public QPlatformIntegration +{ +public: + QWindowsIntegration(bool openGL = false); + virtual ~QWindowsIntegration(); + + bool hasCapability(QPlatformIntegration::Capability cap) const; + + virtual QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const; + + virtual QPlatformClipboard *clipboard() const; + virtual QPlatformDrag *drag() const; + virtual QPlatformInputContext *inputContext() const; + virtual QPlatformNativeInterface *nativeInterface() const; + virtual QPlatformFontDatabase *fontDatabase() const; + + static QWindowsIntegration *instance(); + +private: + QScopedPointer<QWindowsIntegrationPrivate> d; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h b/src/plugins/platforms/windows/qwindowsinternalmimedata.h index 12004571cb..49fc69059b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h +++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Contact: Nokia Corporation (info@qt.nokia.com) ** ** This file is part of the plugins of the Qt Toolkit. ** @@ -39,37 +39,32 @@ ** ****************************************************************************/ -#ifndef QDIRECTFBMOUSE_H -#define QDIRECTFBMOUSE_H +#ifndef QWINDOWSINTERNALMIME_H +#define QWINDOWSINTERNALMIME_H -#include <qglobal.h> -#include <QtGui/qmouse_qws.h> +#include "qtwindows_additional.h" -#ifndef QT_NO_QWS_DIRECTFB - -QT_BEGIN_HEADER +#include <QtGui/private/qdnd_p.h> // QInternalMime +#include <QtCore/QVariant> QT_BEGIN_NAMESPACE -QT_MODULE(Gui) - -class QDirectFBMouseHandlerPrivate; +class QDebug; -class QDirectFBMouseHandler : public QWSMouseHandler -{ +// Implementation in qwindowsclipboard.cpp. +class QWindowsInternalMimeData : public QInternalMimeData { public: - explicit QDirectFBMouseHandler(const QString &driver = QString(), - const QString &device = QString()); - ~QDirectFBMouseHandler(); + virtual bool hasFormat_sys(const QString &mimetype) const; + virtual QStringList formats_sys() const; + virtual QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const; - void suspend(); - void resume(); protected: - QDirectFBMouseHandlerPrivate *d; + virtual IDataObject *retrieveDataObject() const = 0; + virtual void releaseDataObject(IDataObject *) const {} }; +QDebug operator<<(QDebug d, const QMimeData &m); + QT_END_NAMESPACE -QT_END_HEADER -#endif // QT_NO_QWS_DIRECTFB -#endif // QDIRECTFBMOUSE_H +#endif // QWINDOWSINTERNALMIME_H diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp new file mode 100644 index 0000000000..40613ea1f1 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -0,0 +1,1075 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowskeymapper.h" +#include "qwindowscontext.h" +#include "qwindowswindow.h" +#include "qwindowsguieventdispatcher.h" + +#include <QtGui/QWindow> +#include <QtGui/QWindowSystemInterface> +#include <QtGui/QKeyEvent> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsKeyMapper + \brief Translates Windows keys to QWindowSystemInterface events. + \ingroup qt-lighthouse-win + + In addition, handles some special keys to display system menus, etc. + The code originates from \c qkeymapper_win.cpp. +*/ + +QWindowsKeyMapper::QWindowsKeyMapper() + : m_useRTLExtensions(false), m_keyGrabber(0) +{ + memset(keyLayout, 0, sizeof(keyLayout)); +} + +QWindowsKeyMapper::~QWindowsKeyMapper() +{ + deleteLayouts(); +} + +#ifndef LANG_PASHTO +#define LANG_PASHTO 0x63 +#endif +#ifndef LANG_SYRIAC +#define LANG_SYRIAC 0x5a +#endif +#ifndef LANG_DIVEHI +#define LANG_DIVEHI 0x65 +#endif +#ifndef VK_OEM_PLUS +#define VK_OEM_PLUS 0xBB +#endif +#ifndef VK_OEM_3 +#define VK_OEM_3 0xC0 +#endif + +// Key recorder ------------------------------------------------------------------------[ start ] -- +struct KeyRecord { + KeyRecord(int c, int a, int s, const QString &t) : code(c), ascii(a), state(s), text(t) {} + KeyRecord() {} + + int code; + int ascii; + int state; + QString text; +}; + +static const int QT_MAX_KEY_RECORDINGS = 64; // User has LOTS of fingers... +struct KeyRecorder +{ + KeyRecorder() : nrecs(0) {} + + inline KeyRecord *findKey(int code, bool remove); + inline void storeKey(int code, int ascii, int state, const QString& text); + inline void clearKeys(); + + int nrecs; + KeyRecord deleted_record; // A copy of last entry removed from records[] + KeyRecord records[QT_MAX_KEY_RECORDINGS]; +}; +static KeyRecorder key_recorder; + +KeyRecord *KeyRecorder::findKey(int code, bool remove) +{ + KeyRecord *result = 0; + for (int i = 0; i < nrecs; ++i) { + if (records[i].code == code) { + if (remove) { + deleted_record = records[i]; + // Move rest down, and decrease count + while (i + 1 < nrecs) { + records[i] = records[i + 1]; + ++i; + } + --nrecs; + result = &deleted_record; + } else { + result = &records[i]; + } + break; + } + } + return result; +} + +void KeyRecorder::storeKey(int code, int ascii, int state, const QString& text) +{ + Q_ASSERT_X(nrecs != QT_MAX_KEY_RECORDINGS, + "Internal KeyRecorder", + "Keyboard recorder buffer overflow, consider increasing QT_MAX_KEY_RECORDINGS"); + + if (nrecs == QT_MAX_KEY_RECORDINGS) { + qWarning("Qt: Internal keyboard buffer overflow"); + return; + } + records[nrecs++] = KeyRecord(code,ascii,state,text); +} + +void KeyRecorder::clearKeys() +{ + nrecs = 0; +} +// Key recorder --------------------------------------------------------------------------[ end ] -- + + +// Key translation ---------------------------------------------------------------------[ start ] -- +// Meaning of values: +// 0 = Character output key, needs keyboard driver mapping +// Key_unknown = Unknown Virtual Key, no translation possible, ignore +static const uint KeyTbl[] = { // Keyboard mapping table + // Dec | Hex | Windows Virtual key + Qt::Key_unknown, // 0 0x00 + Qt::Key_unknown, // 1 0x01 VK_LBUTTON | Left mouse button + Qt::Key_unknown, // 2 0x02 VK_RBUTTON | Right mouse button + Qt::Key_Cancel, // 3 0x03 VK_CANCEL | Control-Break processing + Qt::Key_unknown, // 4 0x04 VK_MBUTTON | Middle mouse button + Qt::Key_unknown, // 5 0x05 VK_XBUTTON1 | X1 mouse button + Qt::Key_unknown, // 6 0x06 VK_XBUTTON2 | X2 mouse button + Qt::Key_unknown, // 7 0x07 -- unassigned -- + Qt::Key_Backspace, // 8 0x08 VK_BACK | BackSpace key + Qt::Key_Tab, // 9 0x09 VK_TAB | Tab key + Qt::Key_unknown, // 10 0x0A -- reserved -- + Qt::Key_unknown, // 11 0x0B -- reserved -- + Qt::Key_Clear, // 12 0x0C VK_CLEAR | Clear key + Qt::Key_Return, // 13 0x0D VK_RETURN | Enter key + Qt::Key_unknown, // 14 0x0E -- unassigned -- + Qt::Key_unknown, // 15 0x0F -- unassigned -- + Qt::Key_Shift, // 16 0x10 VK_SHIFT | Shift key + Qt::Key_Control, // 17 0x11 VK_CONTROL | Ctrl key + Qt::Key_Alt, // 18 0x12 VK_MENU | Alt key + Qt::Key_Pause, // 19 0x13 VK_PAUSE | Pause key + Qt::Key_CapsLock, // 20 0x14 VK_CAPITAL | Caps-Lock + Qt::Key_unknown, // 21 0x15 VK_KANA / VK_HANGUL | IME Kana or Hangul mode + Qt::Key_unknown, // 22 0x16 -- unassigned -- + Qt::Key_unknown, // 23 0x17 VK_JUNJA | IME Junja mode + Qt::Key_unknown, // 24 0x18 VK_FINAL | IME final mode + Qt::Key_unknown, // 25 0x19 VK_HANJA / VK_KANJI | IME Hanja or Kanji mode + Qt::Key_unknown, // 26 0x1A -- unassigned -- + Qt::Key_Escape, // 27 0x1B VK_ESCAPE | Esc key + Qt::Key_unknown, // 28 0x1C VK_CONVERT | IME convert + Qt::Key_unknown, // 29 0x1D VK_NONCONVERT | IME non-convert + Qt::Key_unknown, // 30 0x1E VK_ACCEPT | IME accept + Qt::Key_Mode_switch,// 31 0x1F VK_MODECHANGE | IME mode change request + Qt::Key_Space, // 32 0x20 VK_SPACE | Spacebar + Qt::Key_PageUp, // 33 0x21 VK_PRIOR | Page Up key + Qt::Key_PageDown, // 34 0x22 VK_NEXT | Page Down key + Qt::Key_End, // 35 0x23 VK_END | End key + Qt::Key_Home, // 36 0x24 VK_HOME | Home key + Qt::Key_Left, // 37 0x25 VK_LEFT | Left arrow key + Qt::Key_Up, // 38 0x26 VK_UP | Up arrow key + Qt::Key_Right, // 39 0x27 VK_RIGHT | Right arrow key + Qt::Key_Down, // 40 0x28 VK_DOWN | Down arrow key + Qt::Key_Select, // 41 0x29 VK_SELECT | Select key + Qt::Key_Printer, // 42 0x2A VK_PRINT | Print key + Qt::Key_Execute, // 43 0x2B VK_EXECUTE | Execute key + Qt::Key_Print, // 44 0x2C VK_SNAPSHOT | Print Screen key + Qt::Key_Insert, // 45 0x2D VK_INSERT | Ins key + Qt::Key_Delete, // 46 0x2E VK_DELETE | Del key + Qt::Key_Help, // 47 0x2F VK_HELP | Help key + 0, // 48 0x30 (VK_0) | 0 key + 0, // 49 0x31 (VK_1) | 1 key + 0, // 50 0x32 (VK_2) | 2 key + 0, // 51 0x33 (VK_3) | 3 key + 0, // 52 0x34 (VK_4) | 4 key + 0, // 53 0x35 (VK_5) | 5 key + 0, // 54 0x36 (VK_6) | 6 key + 0, // 55 0x37 (VK_7) | 7 key + 0, // 56 0x38 (VK_8) | 8 key + 0, // 57 0x39 (VK_9) | 9 key + Qt::Key_unknown, // 58 0x3A -- unassigned -- + Qt::Key_unknown, // 59 0x3B -- unassigned -- + Qt::Key_unknown, // 60 0x3C -- unassigned -- + Qt::Key_unknown, // 61 0x3D -- unassigned -- + Qt::Key_unknown, // 62 0x3E -- unassigned -- + Qt::Key_unknown, // 63 0x3F -- unassigned -- + Qt::Key_unknown, // 64 0x40 -- unassigned -- + 0, // 65 0x41 (VK_A) | A key + 0, // 66 0x42 (VK_B) | B key + 0, // 67 0x43 (VK_C) | C key + 0, // 68 0x44 (VK_D) | D key + 0, // 69 0x45 (VK_E) | E key + 0, // 70 0x46 (VK_F) | F key + 0, // 71 0x47 (VK_G) | G key + 0, // 72 0x48 (VK_H) | H key + 0, // 73 0x49 (VK_I) | I key + 0, // 74 0x4A (VK_J) | J key + 0, // 75 0x4B (VK_K) | K key + 0, // 76 0x4C (VK_L) | L key + 0, // 77 0x4D (VK_M) | M key + 0, // 78 0x4E (VK_N) | N key + 0, // 79 0x4F (VK_O) | O key + 0, // 80 0x50 (VK_P) | P key + 0, // 81 0x51 (VK_Q) | Q key + 0, // 82 0x52 (VK_R) | R key + 0, // 83 0x53 (VK_S) | S key + 0, // 84 0x54 (VK_T) | T key + 0, // 85 0x55 (VK_U) | U key + 0, // 86 0x56 (VK_V) | V key + 0, // 87 0x57 (VK_W) | W key + 0, // 88 0x58 (VK_X) | X key + 0, // 89 0x59 (VK_Y) | Y key + 0, // 90 0x5A (VK_Z) | Z key + Qt::Key_Meta, // 91 0x5B VK_LWIN | Left Windows - MS Natural kbd + Qt::Key_Meta, // 92 0x5C VK_RWIN | Right Windows - MS Natural kbd + Qt::Key_Menu, // 93 0x5D VK_APPS | Application key-MS Natural kbd + Qt::Key_unknown, // 94 0x5E -- reserved -- + Qt::Key_Sleep, // 95 0x5F VK_SLEEP + Qt::Key_0, // 96 0x60 VK_NUMPAD0 | Numeric keypad 0 key + Qt::Key_1, // 97 0x61 VK_NUMPAD1 | Numeric keypad 1 key + Qt::Key_2, // 98 0x62 VK_NUMPAD2 | Numeric keypad 2 key + Qt::Key_3, // 99 0x63 VK_NUMPAD3 | Numeric keypad 3 key + Qt::Key_4, // 100 0x64 VK_NUMPAD4 | Numeric keypad 4 key + Qt::Key_5, // 101 0x65 VK_NUMPAD5 | Numeric keypad 5 key + Qt::Key_6, // 102 0x66 VK_NUMPAD6 | Numeric keypad 6 key + Qt::Key_7, // 103 0x67 VK_NUMPAD7 | Numeric keypad 7 key + Qt::Key_8, // 104 0x68 VK_NUMPAD8 | Numeric keypad 8 key + Qt::Key_9, // 105 0x69 VK_NUMPAD9 | Numeric keypad 9 key + Qt::Key_Asterisk, // 106 0x6A VK_MULTIPLY | Multiply key + Qt::Key_Plus, // 107 0x6B VK_ADD | Add key + Qt::Key_Comma, // 108 0x6C VK_SEPARATOR | Separator key + Qt::Key_Minus, // 109 0x6D VK_SUBTRACT | Subtract key + Qt::Key_Period, // 110 0x6E VK_DECIMAL | Decimal key + Qt::Key_Slash, // 111 0x6F VK_DIVIDE | Divide key + Qt::Key_F1, // 112 0x70 VK_F1 | F1 key + Qt::Key_F2, // 113 0x71 VK_F2 | F2 key + Qt::Key_F3, // 114 0x72 VK_F3 | F3 key + Qt::Key_F4, // 115 0x73 VK_F4 | F4 key + Qt::Key_F5, // 116 0x74 VK_F5 | F5 key + Qt::Key_F6, // 117 0x75 VK_F6 | F6 key + Qt::Key_F7, // 118 0x76 VK_F7 | F7 key + Qt::Key_F8, // 119 0x77 VK_F8 | F8 key + Qt::Key_F9, // 120 0x78 VK_F9 | F9 key + Qt::Key_F10, // 121 0x79 VK_F10 | F10 key + Qt::Key_F11, // 122 0x7A VK_F11 | F11 key + Qt::Key_F12, // 123 0x7B VK_F12 | F12 key + Qt::Key_F13, // 124 0x7C VK_F13 | F13 key + Qt::Key_F14, // 125 0x7D VK_F14 | F14 key + Qt::Key_F15, // 126 0x7E VK_F15 | F15 key + Qt::Key_F16, // 127 0x7F VK_F16 | F16 key + Qt::Key_F17, // 128 0x80 VK_F17 | F17 key + Qt::Key_F18, // 129 0x81 VK_F18 | F18 key + Qt::Key_F19, // 130 0x82 VK_F19 | F19 key + Qt::Key_F20, // 131 0x83 VK_F20 | F20 key + Qt::Key_F21, // 132 0x84 VK_F21 | F21 key + Qt::Key_F22, // 133 0x85 VK_F22 | F22 key + Qt::Key_F23, // 134 0x86 VK_F23 | F23 key + Qt::Key_F24, // 135 0x87 VK_F24 | F24 key + Qt::Key_unknown, // 136 0x88 -- unassigned -- + Qt::Key_unknown, // 137 0x89 -- unassigned -- + Qt::Key_unknown, // 138 0x8A -- unassigned -- + Qt::Key_unknown, // 139 0x8B -- unassigned -- + Qt::Key_unknown, // 140 0x8C -- unassigned -- + Qt::Key_unknown, // 141 0x8D -- unassigned -- + Qt::Key_unknown, // 142 0x8E -- unassigned -- + Qt::Key_unknown, // 143 0x8F -- unassigned -- + Qt::Key_NumLock, // 144 0x90 VK_NUMLOCK | Num Lock key + Qt::Key_ScrollLock, // 145 0x91 VK_SCROLL | Scroll Lock key + // Fujitsu/OASYS kbd -------------------- + 0, //Qt::Key_Jisho, // 146 0x92 VK_OEM_FJ_JISHO | 'Dictionary' key / + // VK_OEM_NEC_EQUAL = key on numpad on NEC PC-9800 kbd + Qt::Key_Massyo, // 147 0x93 VK_OEM_FJ_MASSHOU | 'Unregister word' key + Qt::Key_Touroku, // 148 0x94 VK_OEM_FJ_TOUROKU | 'Register word' key + 0, //Qt::Key_Oyayubi_Left,//149 0x95 VK_OEM_FJ_LOYA | 'Left OYAYUBI' key + 0, //Qt::Key_Oyayubi_Right,//150 0x96 VK_OEM_FJ_ROYA | 'Right OYAYUBI' key + Qt::Key_unknown, // 151 0x97 -- unassigned -- + Qt::Key_unknown, // 152 0x98 -- unassigned -- + Qt::Key_unknown, // 153 0x99 -- unassigned -- + Qt::Key_unknown, // 154 0x9A -- unassigned -- + Qt::Key_unknown, // 155 0x9B -- unassigned -- + Qt::Key_unknown, // 156 0x9C -- unassigned -- + Qt::Key_unknown, // 157 0x9D -- unassigned -- + Qt::Key_unknown, // 158 0x9E -- unassigned -- + Qt::Key_unknown, // 159 0x9F -- unassigned -- + Qt::Key_Shift, // 160 0xA0 VK_LSHIFT | Left Shift key + Qt::Key_Shift, // 161 0xA1 VK_RSHIFT | Right Shift key + Qt::Key_Control, // 162 0xA2 VK_LCONTROL | Left Ctrl key + Qt::Key_Control, // 163 0xA3 VK_RCONTROL | Right Ctrl key + Qt::Key_Alt, // 164 0xA4 VK_LMENU | Left Menu key + Qt::Key_Alt, // 165 0xA5 VK_RMENU | Right Menu key + Qt::Key_Back, // 166 0xA6 VK_BROWSER_BACK | Browser Back key + Qt::Key_Forward, // 167 0xA7 VK_BROWSER_FORWARD | Browser Forward key + Qt::Key_Refresh, // 168 0xA8 VK_BROWSER_REFRESH | Browser Refresh key + Qt::Key_Stop, // 169 0xA9 VK_BROWSER_STOP | Browser Stop key + Qt::Key_Search, // 170 0xAA VK_BROWSER_SEARCH | Browser Search key + Qt::Key_Favorites, // 171 0xAB VK_BROWSER_FAVORITES| Browser Favorites key + Qt::Key_HomePage, // 172 0xAC VK_BROWSER_HOME | Browser Start and Home key + Qt::Key_VolumeMute, // 173 0xAD VK_VOLUME_MUTE | Volume Mute key + Qt::Key_VolumeDown, // 174 0xAE VK_VOLUME_DOWN | Volume Down key + Qt::Key_VolumeUp, // 175 0xAF VK_VOLUME_UP | Volume Up key + Qt::Key_MediaNext, // 176 0xB0 VK_MEDIA_NEXT_TRACK | Next Track key + Qt::Key_MediaPrevious, //177 0xB1 VK_MEDIA_PREV_TRACK | Previous Track key + Qt::Key_MediaStop, // 178 0xB2 VK_MEDIA_STOP | Stop Media key + Qt::Key_MediaPlay, // 179 0xB3 VK_MEDIA_PLAY_PAUSE | Play/Pause Media key + Qt::Key_LaunchMail, // 180 0xB4 VK_LAUNCH_MAIL | Start Mail key + Qt::Key_LaunchMedia,// 181 0xB5 VK_LAUNCH_MEDIA_SELECT Select Media key + Qt::Key_Launch0, // 182 0xB6 VK_LAUNCH_APP1 | Start Application 1 key + Qt::Key_Launch1, // 183 0xB7 VK_LAUNCH_APP2 | Start Application 2 key + Qt::Key_unknown, // 184 0xB8 -- reserved -- + Qt::Key_unknown, // 185 0xB9 -- reserved -- + 0, // 186 0xBA VK_OEM_1 | ';:' for US + 0, // 187 0xBB VK_OEM_PLUS | '+' any country + 0, // 188 0xBC VK_OEM_COMMA | ',' any country + 0, // 189 0xBD VK_OEM_MINUS | '-' any country + 0, // 190 0xBE VK_OEM_PERIOD | '.' any country + 0, // 191 0xBF VK_OEM_2 | '/?' for US + 0, // 192 0xC0 VK_OEM_3 | '`~' for US + Qt::Key_unknown, // 193 0xC1 -- reserved -- + Qt::Key_unknown, // 194 0xC2 -- reserved -- + Qt::Key_unknown, // 195 0xC3 -- reserved -- + Qt::Key_unknown, // 196 0xC4 -- reserved -- + Qt::Key_unknown, // 197 0xC5 -- reserved -- + Qt::Key_unknown, // 198 0xC6 -- reserved -- + Qt::Key_unknown, // 199 0xC7 -- reserved -- + Qt::Key_unknown, // 200 0xC8 -- reserved -- + Qt::Key_unknown, // 201 0xC9 -- reserved -- + Qt::Key_unknown, // 202 0xCA -- reserved -- + Qt::Key_unknown, // 203 0xCB -- reserved -- + Qt::Key_unknown, // 204 0xCC -- reserved -- + Qt::Key_unknown, // 205 0xCD -- reserved -- + Qt::Key_unknown, // 206 0xCE -- reserved -- + Qt::Key_unknown, // 207 0xCF -- reserved -- + Qt::Key_unknown, // 208 0xD0 -- reserved -- + Qt::Key_unknown, // 209 0xD1 -- reserved -- + Qt::Key_unknown, // 210 0xD2 -- reserved -- + Qt::Key_unknown, // 211 0xD3 -- reserved -- + Qt::Key_unknown, // 212 0xD4 -- reserved -- + Qt::Key_unknown, // 213 0xD5 -- reserved -- + Qt::Key_unknown, // 214 0xD6 -- reserved -- + Qt::Key_unknown, // 215 0xD7 -- reserved -- + Qt::Key_unknown, // 216 0xD8 -- unassigned -- + Qt::Key_unknown, // 217 0xD9 -- unassigned -- + Qt::Key_unknown, // 218 0xDA -- unassigned -- + 0, // 219 0xDB VK_OEM_4 | '[{' for US + 0, // 220 0xDC VK_OEM_5 | '\|' for US + 0, // 221 0xDD VK_OEM_6 | ']}' for US + 0, // 222 0xDE VK_OEM_7 | ''"' for US + 0, // 223 0xDF VK_OEM_8 + Qt::Key_unknown, // 224 0xE0 -- reserved -- + Qt::Key_unknown, // 225 0xE1 VK_OEM_AX | 'AX' key on Japanese AX kbd + Qt::Key_unknown, // 226 0xE2 VK_OEM_102 | "<>" or "\|" on RT 102-key kbd + Qt::Key_unknown, // 227 0xE3 VK_ICO_HELP | Help key on ICO + Qt::Key_unknown, // 228 0xE4 VK_ICO_00 | 00 key on ICO + Qt::Key_unknown, // 229 0xE5 VK_PROCESSKEY | IME Process key + Qt::Key_unknown, // 230 0xE6 VK_ICO_CLEAR | + Qt::Key_unknown, // 231 0xE7 VK_PACKET | Unicode char as keystrokes + Qt::Key_unknown, // 232 0xE8 -- unassigned -- + // Nokia/Ericsson definitions --------------- + Qt::Key_unknown, // 233 0xE9 VK_OEM_RESET + Qt::Key_unknown, // 234 0xEA VK_OEM_JUMP + Qt::Key_unknown, // 235 0xEB VK_OEM_PA1 + Qt::Key_unknown, // 236 0xEC VK_OEM_PA2 + Qt::Key_unknown, // 237 0xED VK_OEM_PA3 + Qt::Key_unknown, // 238 0xEE VK_OEM_WSCTRL + Qt::Key_unknown, // 239 0xEF VK_OEM_CUSEL + Qt::Key_unknown, // 240 0xF0 VK_OEM_ATTN + Qt::Key_unknown, // 241 0xF1 VK_OEM_FINISH + Qt::Key_unknown, // 242 0xF2 VK_OEM_COPY + Qt::Key_unknown, // 243 0xF3 VK_OEM_AUTO + Qt::Key_unknown, // 244 0xF4 VK_OEM_ENLW + Qt::Key_unknown, // 245 0xF5 VK_OEM_BACKTAB + Qt::Key_unknown, // 246 0xF6 VK_ATTN | Attn key + Qt::Key_unknown, // 247 0xF7 VK_CRSEL | CrSel key + Qt::Key_unknown, // 248 0xF8 VK_EXSEL | ExSel key + Qt::Key_unknown, // 249 0xF9 VK_EREOF | Erase EOF key + Qt::Key_Play, // 250 0xFA VK_PLAY | Play key + Qt::Key_Zoom, // 251 0xFB VK_ZOOM | Zoom key + Qt::Key_unknown, // 252 0xFC VK_NONAME | Reserved + Qt::Key_unknown, // 253 0xFD VK_PA1 | PA1 key + Qt::Key_Clear, // 254 0xFE VK_OEM_CLEAR | Clear key + 0 +}; + +// Possible modifier states. +// NOTE: The order of these states match the order in QWindowsKeyMapper::updatePossibleKeyCodes()! +static const Qt::KeyboardModifiers ModsTbl[] = { + Qt::NoModifier, // 0 + Qt::ShiftModifier, // 1 + Qt::ControlModifier, // 2 + Qt::ControlModifier | Qt::ShiftModifier, // 3 + Qt::AltModifier, // 4 + Qt::AltModifier | Qt::ShiftModifier, // 5 + Qt::AltModifier | Qt::ControlModifier, // 6 + Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7 + Qt::NoModifier, // Fall-back to raw Key_* +}; + +/** + Remap return or action key to select key for windows mobile. +*/ +inline int winceKeyBend(int keyCode) +{ + return KeyTbl[keyCode]; +} + +// Translate a VK into a Qt key code, or unicode character +static inline int toKeyOrUnicode(int vk, int scancode, unsigned char *kbdBuffer, bool *isDeadkey = 0) +{ + Q_ASSERT(vk > 0 && vk < 256); + int code = 0; + QChar unicodeBuffer[5]; + int res = ToUnicode(vk, scancode, kbdBuffer, reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0); + if (res) + code = unicodeBuffer[0].toUpper().unicode(); + + // Qt::Key_*'s are not encoded below 0x20, so try again, and DEL keys (0x7f) is encoded with a + // proper Qt::Key_ code + if (code < 0x20 || code == 0x7f) // Handles res==0 too + code = winceKeyBend(vk); + + if (isDeadkey) + *isDeadkey = (res == -1); + + return code == Qt::Key_unknown ? 0 : code; +} + +int qt_translateKeyCode(int vk) +{ + int code = winceKeyBend((vk < 0 || vk > 255) ? 0 : vk); + return code == Qt::Key_unknown ? 0 : code; +} + +static inline int asciiToKeycode(char a, int state) +{ + if (a >= 'a' && a <= 'z') + a = toupper(a); + if ((state & Qt::ControlModifier) != 0) { + if (a >= 0 && a <= 31) // Ctrl+@..Ctrl+A..CTRL+Z..Ctrl+_ + a += '@'; // to @..A..Z.._ + } + return a & 0xff; +} + +static inline bool isModifierKey(int code) +{ + return (code >= Qt::Key_Shift) && (code <= Qt::Key_ScrollLock); +} +// Key translation -----------------------------------------------------------------------[ end ]--- + + +// Keyboard map private ----------------------------------------------------------------[ start ]--- + +/* + \internal + A Windows KeyboardLayoutItem has 8 possible states: + 1. Unmodified + 2. Shift + 3. Control + 4. Control + Shift + 5. Alt + 6. Alt + Shift + 7. Alt + Control + 8. Alt + Control + Shift +*/ +struct KeyboardLayoutItem { + bool dirty; + quint8 deadkeys; + quint32 qtKey[9]; // Can by any Qt::Key_<foo>, or unicode character +}; + +void QWindowsKeyMapper::deleteLayouts() +{ + for (int i = 0; i < 255; ++i) { + if (keyLayout[i]) { + delete keyLayout[i]; + keyLayout[i] = 0; + } + } +} + +void QWindowsKeyMapper::changeKeyboard() +{ + deleteLayouts(); + + /* MAKELCID()'s first argument is a WORD, and GetKeyboardLayout() + * returns a DWORD. */ + + LCID newLCID = MAKELCID((quintptr)GetKeyboardLayout(0), SORT_DEFAULT); +// keyboardInputLocale = qt_localeFromLCID(newLCID); + + bool bidi = false; + wchar_t LCIDFontSig[16]; + if (GetLocaleInfo(newLCID, LOCALE_FONTSIGNATURE, LCIDFontSig, sizeof(LCIDFontSig) / sizeof(wchar_t)) + && (LCIDFontSig[7] & (wchar_t)0x0800)) + bidi = true; + + keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight; +} + +void QWindowsKeyMapper::clearRecordedKeys() +{ + key_recorder.clearKeys(); +} + + +inline void setKbdState(unsigned char *kbd, bool shift, bool ctrl, bool alt) +{ + kbd[VK_LSHIFT ] = (shift ? 0x80 : 0); + kbd[VK_SHIFT ] = (shift ? 0x80 : 0); + kbd[VK_LCONTROL] = (ctrl ? 0x80 : 0); + kbd[VK_CONTROL ] = (ctrl ? 0x80 : 0); + kbd[VK_RMENU ] = (alt ? 0x80 : 0); + kbd[VK_MENU ] = (alt ? 0x80 : 0); +} + +void QWindowsKeyMapper::updateKeyMap(const MSG &msg) +{ + unsigned char kbdBuffer[256]; // Will hold the complete keyboard state + GetKeyboardState(kbdBuffer); + quint32 scancode = (msg.lParam >> 16) & 0xfff; + updatePossibleKeyCodes(kbdBuffer, scancode, msg.wParam); +} + +void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 scancode, + quint32 vk_key) +{ + if (!vk_key || (keyLayout[vk_key] && !keyLayout[vk_key]->dirty)) + return; + + if (!keyLayout[vk_key]) + keyLayout[vk_key] = new KeyboardLayoutItem; + + // Copy keyboard state, so we can modify and query output for each possible permutation + unsigned char buffer[256]; + memcpy(buffer, kbdBuffer, sizeof(buffer)); + // Always 0, as Windows doesn't treat these as modifiers; + buffer[VK_LWIN ] = 0; + buffer[VK_RWIN ] = 0; + buffer[VK_CAPITAL ] = 0; + buffer[VK_NUMLOCK ] = 0; + buffer[VK_SCROLL ] = 0; + // Always 0, since we'll only change the other versions + buffer[VK_RSHIFT ] = 0; + buffer[VK_RCONTROL] = 0; + buffer[VK_LMENU ] = 0; // Use right Alt, since left Ctrl + right Alt is considered AltGraph + + bool isDeadKey = false; + keyLayout[vk_key]->deadkeys = 0; + keyLayout[vk_key]->dirty = false; + setKbdState(buffer, false, false, false); + keyLayout[vk_key]->qtKey[0] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x01 : 0; + setKbdState(buffer, true, false, false); + keyLayout[vk_key]->qtKey[1] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x02 : 0; + setKbdState(buffer, false, true, false); + keyLayout[vk_key]->qtKey[2] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x04 : 0; + setKbdState(buffer, true, true, false); + keyLayout[vk_key]->qtKey[3] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x08 : 0; + setKbdState(buffer, false, false, true); + keyLayout[vk_key]->qtKey[4] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x10 : 0; + setKbdState(buffer, true, false, true); + keyLayout[vk_key]->qtKey[5] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x20 : 0; + setKbdState(buffer, false, true, true); + keyLayout[vk_key]->qtKey[6] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x40 : 0; + setKbdState(buffer, true, true, true); + keyLayout[vk_key]->qtKey[7] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x80 : 0; + // Add a fall back key for layouts which don't do composition and show non-latin1 characters + int fallbackKey = winceKeyBend(vk_key); + if (!fallbackKey || fallbackKey == Qt::Key_unknown) { + fallbackKey = 0; + if (vk_key != keyLayout[vk_key]->qtKey[0] && vk_key < 0x5B && vk_key > 0x2F) + fallbackKey = vk_key; + } + keyLayout[vk_key]->qtKey[8] = fallbackKey; + + // If this vk_key a Dead Key + if (MapVirtualKey(vk_key, 2) & 0x80000000) { + // Push a Space, then the original key through the low-level ToAscii functions. + // We do this because these functions (ToAscii / ToUnicode) will alter the internal state of + // the keyboard driver By doing the following, we set the keyboard driver state back to what + // it was before we wrecked it with the code above. + // We need to push the space with an empty keystate map, since the driver checks the map for + // transitions in modifiers, so this helps us capture all possible deadkeys. + unsigned char emptyBuffer[256]; + memset(emptyBuffer, 0, sizeof(emptyBuffer)); + ::ToAscii(VK_SPACE, 0, emptyBuffer, reinterpret_cast<LPWORD>(&buffer), 0); + ::ToAscii(vk_key, scancode, kbdBuffer, reinterpret_cast<LPWORD>(&buffer), 0); + } + + if (QWindowsContext::verboseEvents > 1) { + qDebug("updatePossibleKeyCodes for virtual key = 0x%02x!", vk_key); + for (int i = 0; i < 9; ++i) { + qDebug(" [%d] (%d,0x%02x,'%c') %s", i, + keyLayout[vk_key]->qtKey[i], + keyLayout[vk_key]->qtKey[i], + keyLayout[vk_key]->qtKey[i] ? keyLayout[vk_key]->qtKey[i] : 0x03, + keyLayout[vk_key]->deadkeys & (1<<i) ? "deadkey" : ""); + } + } +} + +bool QWindowsKeyMapper::isADeadKey(unsigned int vk_key, unsigned int modifiers) +{ + if (keyLayout && (vk_key < 256) && keyLayout[vk_key]) { + for (register int i = 0; i < 9; ++i) { + if (uint(ModsTbl[i]) == modifiers) + return bool(keyLayout[vk_key]->deadkeys & 1<<i); + } + } + return false; +} + +static inline QString messageKeyText(const MSG &msg) +{ + const QChar ch = QChar((ushort)msg.wParam); + return ch.isNull() ? QString() : QString(ch); +} + +static void showSystemMenu(QWindow* w) +{ + QWindow *topLevel = QWindowsWindow::topLevelOf(w); + HWND topLevelHwnd = QWindowsWindow::handleOf(topLevel); + HMENU menu = GetSystemMenu(topLevelHwnd, FALSE); + if (!menu) + return; // no menu for this window + +#define enabled (MF_BYCOMMAND | MF_ENABLED) +#define disabled (MF_BYCOMMAND | MF_GRAYED) + + EnableMenuItem(menu, SC_MINIMIZE, (topLevel->windowFlags() & Qt::WindowMinimizeButtonHint)?enabled:disabled); + bool maximized = IsZoomed(topLevelHwnd); + + EnableMenuItem(menu, SC_MAXIMIZE, ! (topLevel->windowFlags() & Qt::WindowMaximizeButtonHint) || maximized?disabled:enabled); + EnableMenuItem(menu, SC_RESTORE, maximized?enabled:disabled); + + // We should _not_ check with the setFixedSize(x,y) case here, since Windows is not able to check + // this and our menu here would be out-of-sync with the menu produced by mouse-click on the + // System Menu, or right-click on the title bar. + EnableMenuItem(menu, SC_SIZE, (topLevel->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) || maximized?disabled:enabled); + EnableMenuItem(menu, SC_MOVE, maximized?disabled:enabled); + EnableMenuItem(menu, SC_CLOSE, enabled); + // Set bold on close menu item + MENUITEMINFO closeItem; + closeItem.cbSize = sizeof(MENUITEMINFO); + closeItem.fMask = MIIM_STATE; + closeItem.fState = MFS_DEFAULT; + SetMenuItemInfo(menu, SC_CLOSE, FALSE, &closeItem); + +#undef enabled +#undef disabled + const int ret = TrackPopupMenuEx(menu, + TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD, + topLevel->geometry().x(), topLevel->geometry().y(), + topLevelHwnd, + 0); + if (ret) + qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, ret, 0); +} + +static inline void sendExtendedPressRelease(QWindow *w, int k, + Qt::KeyboardModifiers mods, + quint32 nativeScanCode, + quint32 nativeVirtualKey, + quint32 nativeModifiers, + const QString & text = QString(), + bool autorep = false, + ushort count = 1) +{ + QWindowSystemInterface::handleExtendedKeyEvent(w, QEvent::KeyPress, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); + QWindowSystemInterface::handleExtendedKeyEvent(w, QEvent::KeyRelease, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); +} + +/*! + \brief To be called from the window procedure. +*/ + +bool QWindowsKeyMapper::translateKeyEvent(QWindow *widget, HWND hwnd, + const MSG &msg, LRESULT *result) +{ + *result = 0; + MSG peekedMsg; + // consume dead chars?(for example, typing '`','a' resulting in a-accent). + if (PeekMessage(&peekedMsg, hwnd, 0, 0, PM_NOREMOVE) && peekedMsg.message == WM_DEADCHAR) + return true; + if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN) + updateKeyMap(msg); + return translateKeyEventInternal(widget, msg, false); +} + +bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &msg, bool /* grab */) +{ + const int msgType = msg.message; + + const quint32 scancode = (msg.lParam >> 16) & 0xfff; + const quint32 vk_key = MapVirtualKey(scancode, 1); + const bool isNumpad = (msg.wParam >= VK_NUMPAD0 && msg.wParam <= VK_NUMPAD9); + quint32 nModifiers = 0; + + QWindow *receiver = m_keyGrabber ? m_keyGrabber : window; + + // Map native modifiers to some bit representation + nModifiers |= (GetKeyState(VK_LSHIFT ) & 0x80 ? ShiftLeft : 0); + nModifiers |= (GetKeyState(VK_RSHIFT ) & 0x80 ? ShiftRight : 0); + nModifiers |= (GetKeyState(VK_LCONTROL) & 0x80 ? ControlLeft : 0); + nModifiers |= (GetKeyState(VK_RCONTROL) & 0x80 ? ControlRight : 0); + nModifiers |= (GetKeyState(VK_LMENU ) & 0x80 ? AltLeft : 0); + nModifiers |= (GetKeyState(VK_RMENU ) & 0x80 ? AltRight : 0); + nModifiers |= (GetKeyState(VK_LWIN ) & 0x80 ? MetaLeft : 0); + nModifiers |= (GetKeyState(VK_RWIN ) & 0x80 ? MetaRight : 0); + // Add Lock keys to the same bits + nModifiers |= (GetKeyState(VK_CAPITAL ) & 0x01 ? CapsLock : 0); + nModifiers |= (GetKeyState(VK_NUMLOCK ) & 0x01 ? NumLock : 0); + nModifiers |= (GetKeyState(VK_SCROLL ) & 0x01 ? ScrollLock : 0); + + if (msg.lParam & ExtendedKey) + nModifiers |= msg.lParam & ExtendedKey; + + // Get the modifier states (may be altered later, depending on key code) + int state = 0; + state |= (nModifiers & ShiftAny ? Qt::ShiftModifier : 0); + state |= (nModifiers & ControlAny ? Qt::ControlModifier : 0); + state |= (nModifiers & AltAny ? Qt::AltModifier : 0); + state |= (nModifiers & MetaAny ? Qt::MetaModifier : 0); + + // Now we know enough to either have MapVirtualKey or our own keymap tell us if it's a deadkey + const bool isDeadKey = isADeadKey(msg.wParam, state) + || MapVirtualKey(msg.wParam, 2) & 0x80000000; + + // A multi-character key or a Input method character + // not found by our look-ahead + if (msgType == WM_CHAR || msgType == WM_IME_CHAR) { + sendExtendedPressRelease(receiver, 0, Qt::KeyboardModifier(state), scancode, vk_key, nModifiers, messageKeyText(msg), false, 0); + return true; + } + + bool result = false; + // handle Directionality changes (BiDi) with RTL extensions + if (m_useRTLExtensions) { + static int dirStatus = 0; + if (!dirStatus && state == Qt::ControlModifier + && msg.wParam == VK_CONTROL + && msgType == WM_KEYDOWN) { + if (GetKeyState(VK_LCONTROL) < 0) + dirStatus = VK_LCONTROL; + else if (GetKeyState(VK_RCONTROL) < 0) + dirStatus = VK_RCONTROL; + } else if (dirStatus) { + if (msgType == WM_KEYDOWN) { + if (msg.wParam == VK_SHIFT) { + if (dirStatus == VK_LCONTROL && GetKeyState(VK_LSHIFT) < 0) + dirStatus = VK_LSHIFT; + else if (dirStatus == VK_RCONTROL && GetKeyState(VK_RSHIFT) < 0) + dirStatus = VK_RSHIFT; + } else { + dirStatus = 0; + } + } else if (msgType == WM_KEYUP) { + if (dirStatus == VK_LSHIFT + && ((msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL)) + || (msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT)))) { + sendExtendedPressRelease(receiver, Qt::Key_Direction_L, 0, scancode, msg.wParam, nModifiers, QString(), false, 0); + result = true; + dirStatus = 0; + } else if (dirStatus == VK_RSHIFT + && ( (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL)) + || (msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT)))) { + sendExtendedPressRelease(receiver, Qt::Key_Direction_R, 0, scancode, msg.wParam, nModifiers, QString(), false, 0); + result = true; + dirStatus = 0; + } else { + dirStatus = 0; + } + } else { + dirStatus = 0; + } + } + } // RTL + + // IME will process these keys, so simply return + if (msg.wParam == VK_PROCESSKEY) + return true; + + // Ignore invalid virtual keycodes (see bugs 127424, QTBUG-3630) + if (msg.wParam == 0 || msg.wParam == 0xFF) + return true; + + // Translate VK_* (native) -> Key_* (Qt) keys + // If it's a dead key, we cannot use the toKeyOrUnicode() function, since that will change + // the internal state of the keyboard driver, resulting in that dead keys no longer works. + // ..also if we're typing numbers on the keypad, while holding down the Alt modifier. + int code = 0; + if (isNumpad && (nModifiers & AltAny)) { + code = winceKeyBend(msg.wParam); + } else if (!isDeadKey) { + unsigned char kbdBuffer[256]; // Will hold the complete keyboard state + GetKeyboardState(kbdBuffer); + code = toKeyOrUnicode(msg.wParam, scancode, kbdBuffer); + } + + // Invert state logic: + // If the key actually pressed is a modifier key, then we remove its modifier key from the + // state, since a modifier-key can't have itself as a modifier + if (code == Qt::Key_Control) + state = state ^ Qt::ControlModifier; + else if (code == Qt::Key_Shift) + state = state ^ Qt::ShiftModifier; + else if (code == Qt::Key_Alt) + state = state ^ Qt::AltModifier; + + // If the bit 24 of lParm is set you received a enter, + // otherwise a Return. (This is the extended key bit) + if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000)) + code = Qt::Key_Enter; + + // All cursor keys without extended bit + if (!(msg.lParam & 0x1000000)) { + switch (code) { + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Up: + case Qt::Key_Down: + case Qt::Key_PageUp: + case Qt::Key_PageDown: + case Qt::Key_Home: + case Qt::Key_End: + case Qt::Key_Insert: + case Qt::Key_Delete: + case Qt::Key_Asterisk: + case Qt::Key_Plus: + case Qt::Key_Minus: + case Qt::Key_Period: + case Qt::Key_0: + case Qt::Key_1: + case Qt::Key_2: + case Qt::Key_3: + case Qt::Key_4: + case Qt::Key_5: + case Qt::Key_6: + case Qt::Key_7: + case Qt::Key_8: + case Qt::Key_9: + state |= ((msg.wParam >= '0' && msg.wParam <= '9') + || (msg.wParam >= VK_OEM_PLUS && msg.wParam <= VK_OEM_3)) + ? 0 : Qt::KeypadModifier; + default: + if ((uint)msg.lParam == 0x004c0001 || (uint)msg.lParam == 0xc04c0001) + state |= Qt::KeypadModifier; + break; + } + } + // Other keys with with extended bit + else { + switch (code) { + case Qt::Key_Enter: + case Qt::Key_Slash: + case Qt::Key_NumLock: + state |= Qt::KeypadModifier; + default: + break; + } + } + + // KEYDOWN --------------------------------------------------------------------------------- + if (msgType == WM_KEYDOWN || msgType == WM_IME_KEYDOWN || msgType == WM_SYSKEYDOWN) { + // Get the last record of this key press, so we can validate the current state + // The record is not removed from the list + KeyRecord *rec = key_recorder.findKey(msg.wParam, false); + + // If rec's state doesn't match the current state, something has changed behind our back + // (Consumed by modal widget is one possibility) So, remove the record from the list + // This will stop the auto-repeat of the key, should a modifier change, for example + if (rec && rec->state != state) { + key_recorder.findKey(msg.wParam, true); + rec = 0; + } + + // Find unicode character from Windows Message Queue + MSG wm_char; + UINT charType = (msgType == WM_KEYDOWN + ? WM_CHAR + : msgType == WM_IME_KEYDOWN ? WM_IME_CHAR : WM_SYSCHAR); + + QChar uch; + if (PeekMessage(&wm_char, 0, charType, charType, PM_REMOVE)) { + // Found a ?_CHAR + uch = QChar((ushort)wm_char.wParam); + if (msgType == WM_SYSKEYDOWN && uch.isLetter() && (msg.lParam & KF_ALTDOWN)) + uch = uch.toLower(); // (See doc of WM_SYSCHAR) Alt-letter + if (!code && !uch.row()) + code = asciiToKeycode(uch.cell(), state); + } + + // Special handling for the WM_IME_KEYDOWN message. Microsoft IME (Korean) will not + // generate a WM_IME_CHAR message corresponding to this message. We might get wrong + // results, if we map this virtual key-code directly (for eg '?' US layouts). So try + // to find the correct key using the current message parameters & keyboard state. + if (uch.isNull() && msgType == WM_IME_KEYDOWN) { + BYTE keyState[256]; + wchar_t newKey[3] = {0}; + GetKeyboardState(keyState); + int val = ToUnicode(vk_key, scancode, keyState, newKey, 2, 0); + if (val == 1) { + uch = QChar(newKey[0]); + } else { + // If we are still not able to find a unicode key, pass the WM_IME_KEYDOWN + // message to DefWindowProc() for generating a proper WM_KEYDOWN. + return false; + } + } + + // If no ?_CHAR was found in the queue; deduct character from the ?_KEYDOWN parameters + if (uch.isNull()) { + if (msg.wParam == VK_DELETE) { + uch = QChar(QLatin1Char(0x7f)); // Windows doesn't know this one. + } else { + if (msgType != WM_SYSKEYDOWN || !code) { + UINT map = MapVirtualKey(msg.wParam, 2); + // If the high bit of the return value is set, it's a deadkey + if (!(map & 0x80000000)) + uch = QChar((ushort)map); + } + } + if (!code && !uch.row()) + code = asciiToKeycode(uch.cell(), state); + } + + // Special handling of global Windows hotkeys + if (state == Qt::AltModifier) { + switch (code) { + case Qt::Key_Escape: + case Qt::Key_Tab: + case Qt::Key_Enter: + case Qt::Key_F4: + return false; // Send the event on to Windows + case Qt::Key_Space: + // do not pass this key to windows, we will process it ourselves + showSystemMenu(receiver); + return true; + default: + break; + } + } + + // Map SHIFT + Tab to SHIFT + BackTab, QShortcutMap knows about this translation + if (code == Qt::Key_Tab && (state & Qt::ShiftModifier) == Qt::ShiftModifier) + code = Qt::Key_Backtab; + + // If we have a record, it means that the key is already pressed, the state is the same + // so, we have an auto-repeating key + if (rec) { + if (code < Qt::Key_Shift || code > Qt::Key_ScrollLock) { + QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyRelease, code, + Qt::KeyboardModifier(state), scancode, msg.wParam, nModifiers, rec->text, true, 0); + QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code, + Qt::KeyboardModifier(state), scancode, msg.wParam, nModifiers, rec->text, true, 0); + result = true; + } + } + // No record of the key being previous pressed, so we now send a QEvent::KeyPress event, + // and store the key data into our records. + else { + const QString text = uch.isNull() ? QString() : QString(uch); + const char a = uch.row() ? 0 : uch.cell(); + key_recorder.storeKey(msg.wParam, a, state, text); + QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code, + Qt::KeyboardModifier(state), scancode, msg.wParam, nModifiers, text, false, 0); + result =true; + bool store = true; + // Alt+<alphanumerical> go to the Win32 menu system if unhandled by Qt + if (msgType == WM_SYSKEYDOWN && !result && a) { + HWND parent = GetParent(QWindowsWindow::handleOf(receiver)); + while (parent) { + if (GetMenu(parent)) { + SendMessage(parent, WM_SYSCOMMAND, SC_KEYMENU, a); + store = false; + result = true; + break; + } + parent = GetParent(parent); + } + } + if (!store) + key_recorder.findKey(msg.wParam, true); + } + } + + // KEYUP ----------------------------------------------------------------------------------- + else { + // Try to locate the key in our records, and remove it if it exists. + // The key may not be in our records if, for example, the down event was handled by + // win32 natively, or our window gets focus while a key is already press, but now gets + // the key release event. + KeyRecord* rec = key_recorder.findKey(msg.wParam, true); + if (!rec && !(code == Qt::Key_Shift + || code == Qt::Key_Control + || code == Qt::Key_Meta + || code == Qt::Key_Alt)) { + // Someone ate the key down event + } else { + if (!code) + code = asciiToKeycode(rec->ascii ? rec->ascii : msg.wParam, state); + + // Map SHIFT + Tab to SHIFT + BackTab, QShortcutMap knows about this translation + if (code == Qt::Key_Tab && (state & Qt::ShiftModifier) == Qt::ShiftModifier) + code = Qt::Key_Backtab; + QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyRelease, code, + Qt::KeyboardModifier(state), scancode, msg.wParam, nModifiers, + (rec ? rec->text : QString()), false, 0); + result = true; + // don't pass Alt to Windows unless we are embedded in a non-Qt window + if (code == Qt::Key_Alt) { + const QWindowsContext *context = QWindowsContext::instance(); + HWND parent = GetParent(QWindowsWindow::handleOf(receiver)); + while (parent) { + if (!context->findPlatformWindow(parent) && GetMenu(parent)) { + result = false; + break; + } + parent = GetParent(parent); + } + } + } + } + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h new file mode 100644 index 0000000000..0d50193730 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowskeymapper.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSKEYMAPPER_H +#define QWINDOWSKEYMAPPER_H + +#include "qtwindows_additional.h" + +#include <QtCore/QLocale> + +QT_BEGIN_NAMESPACE + +class QWindow; + +struct KeyboardLayoutItem; + +class QWindowsKeyMapper +{ + Q_DISABLE_COPY(QWindowsKeyMapper) +public: + explicit QWindowsKeyMapper(); + ~QWindowsKeyMapper(); + + void changeKeyboard(); + + void setUseRTLExtensions(bool e) { m_useRTLExtensions = e; } + bool useRTLExtensions() const { return m_useRTLExtensions; } + + bool translateKeyEvent(QWindow *widget, HWND hwnd, const MSG &msg, LRESULT *result); + + QWindow *keyGrabber() const { return m_keyGrabber; } + void setKeyGrabber(QWindow *w) { m_keyGrabber = w; } + +private: + bool translateKeyEventInternal(QWindow *receiver, const MSG &msg, bool grab); + void updateKeyMap(const MSG &msg); + + bool m_useRTLExtensions; + + QLocale keyboardInputLocale; + Qt::LayoutDirection keyboardInputDirection; + + void clearRecordedKeys(); + void updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 scancode, quint32 vk_key); + bool isADeadKey(unsigned int vk_key, unsigned int modifiers); + void deleteLayouts(); + + KeyboardLayoutItem *keyLayout[256]; + QWindow *m_keyGrabber; +}; + +enum WindowsNativeModifiers { + ShiftLeft = 0x00000001, + ControlLeft = 0x00000002, + AltLeft = 0x00000004, + MetaLeft = 0x00000008, + ShiftRight = 0x00000010, + ControlRight = 0x00000020, + AltRight = 0x00000040, + MetaRight = 0x00000080, + CapsLock = 0x00000100, + NumLock = 0x00000200, + ScrollLock = 0x00000400, + ExtendedKey = 0x01000000, + + // Convenience mappings + ShiftAny = 0x00000011, + ControlAny = 0x00000022, + AltAny = 0x00000044, + MetaAny = 0x00000088, + LockAny = 0x00000700 +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSKEYMAPPER_H diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp new file mode 100644 index 0000000000..09104a43cf --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -0,0 +1,1557 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsmime.h" +#include "qwindowscontext.h" + +#include <QtGui/private/qdnd_p.h> +#include <QtCore/QTextCodec> +#include <QtCore/QMap> +#include <QtCore/QUrl> +#include <QtCore/QDir> +#include <QtCore/QDebug> +#include <QtCore/QBuffer> +#include <QtGui/QImageReader> +#include <QtGui/QImageWriter> + +#include <shlobj.h> + +QT_BEGIN_NAMESPACE + +/* The MSVC compilers allows multi-byte characters, that has the behavior of + * that each character gets shifted into position. 0x73524742 below is for MSVC + * equivalent to doing 'sRGB', but this does of course not work + * on conformant C++ compilers. */ +#define BMP_LCS_sRGB 0x73524742 +#define BMP_LCS_GM_IMAGES 0x00000004L + +struct _CIEXYZ { + long ciexyzX, ciexyzY, ciexyzZ; +}; + +struct _CIEXYZTRIPLE { + _CIEXYZ ciexyzRed, ciexyzGreen, ciexyzBlue; +}; + +struct BMP_BITMAPV5HEADER { + DWORD bV5Size; + LONG bV5Width; + LONG bV5Height; + WORD bV5Planes; + WORD bV5BitCount; + DWORD bV5Compression; + DWORD bV5SizeImage; + LONG bV5XPelsPerMeter; + LONG bV5YPelsPerMeter; + DWORD bV5ClrUsed; + DWORD bV5ClrImportant; + DWORD bV5RedMask; + DWORD bV5GreenMask; + DWORD bV5BlueMask; + DWORD bV5AlphaMask; + DWORD bV5CSType; + _CIEXYZTRIPLE bV5Endpoints; + DWORD bV5GammaRed; + DWORD bV5GammaGreen; + DWORD bV5GammaBlue; + DWORD bV5Intent; + DWORD bV5ProfileData; + DWORD bV5ProfileSize; + DWORD bV5Reserved; +}; +static const int BMP_BITFIELDS = 3; + +static const char dibFormatC[] = "dib"; + +static inline QByteArray msgConversionError(const char *func, const char *format) +{ + QByteArray msg = func; + msg += ": Unable to convert DIB image. The image converter plugin for '"; + msg += format; + msg += "' is not available. Available formats: "; + foreach (const QByteArray &af, QImageReader::supportedImageFormats()) { + msg += af; + msg += ' '; + } + return msg; +} + +static inline QImage readDib(QByteArray data) +{ + QBuffer buffer(&data); + buffer.open(QIODevice::ReadOnly); + QImageReader reader(&buffer, dibFormatC); + if (!reader.canRead()) { + qWarning("%s", msgConversionError(__FUNCTION__, dibFormatC).constData()); + return QImage(); + } + return reader.read(); +} + +static QByteArray writeDib(const QImage &img) +{ + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::ReadWrite); + QImageWriter writer(&buffer, dibFormatC); + if (!writer.canWrite()) { + qWarning("%s", msgConversionError(__FUNCTION__, dibFormatC).constData()); + return ba; + } + if (!writer.write(img)) + ba.clear(); + return ba; +} + +static bool qt_write_dibv5(QDataStream &s, QImage image) +{ + QIODevice* d = s.device(); + if (!d->isWritable()) + return false; + + //depth will be always 32 + int bpl_bmp = image.width()*4; + + BMP_BITMAPV5HEADER bi ={0}; + bi.bV5Size = sizeof(BMP_BITMAPV5HEADER); + bi.bV5Width = image.width(); + bi.bV5Height = image.height(); + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5SizeImage = bpl_bmp*image.height(); + bi.bV5XPelsPerMeter = 0; + bi.bV5YPelsPerMeter = 0; + bi.bV5ClrUsed = 0; + bi.bV5ClrImportant = 0; + bi.bV5BlueMask = 0x000000ff; + bi.bV5GreenMask = 0x0000ff00; + bi.bV5RedMask = 0x00ff0000; + bi.bV5AlphaMask = 0xff000000; + bi.bV5CSType = BMP_LCS_sRGB; //LCS_sRGB + bi.bV5Intent = BMP_LCS_GM_IMAGES; //LCS_GM_IMAGES + + d->write(reinterpret_cast<const char*>(&bi), bi.bV5Size); + if (s.status() != QDataStream::Ok) + return false; + + DWORD colorSpace[3] = {0x00ff0000,0x0000ff00,0x000000ff}; + d->write(reinterpret_cast<const char*>(colorSpace), sizeof(colorSpace)); + if (s.status() != QDataStream::Ok) + return false; + + if (image.format() != QImage::Format_ARGB32) + image = image.convertToFormat(QImage::Format_ARGB32); + + uchar *buf = new uchar[bpl_bmp]; + uchar *b; + + memset(buf, 0, bpl_bmp); + for (int y=image.height()-1; y>=0; y--) { + // write the image bits + QRgb *p = (QRgb *)image.scanLine(y); + QRgb *end = p + image.width(); + b = buf; + while (p < end) { + int alpha = qAlpha(*p); + if (alpha) { + *b++ = qBlue(*p); + *b++ = qGreen(*p); + *b++ = qRed(*p); + } else { + //white for fully transparent pixels. + *b++ = 0xff; + *b++ = 0xff; + *b++ = 0xff; + } + *b++ = alpha; + p++; + } + d->write((char*)buf, bpl_bmp); + if (s.status() != QDataStream::Ok) { + delete[] buf; + return false; + } + } + delete[] buf; + return true; +} + +static int calc_shift(int mask) +{ + int result = 0; + while (!(mask & 1)) { + result++; + mask >>= 1; + } + return result; +} + +//Supports only 32 bit DIBV5 +static bool qt_read_dibv5(QDataStream &s, QImage &image) +{ + BMP_BITMAPV5HEADER bi; + QIODevice* d = s.device(); + if (d->atEnd()) + return false; + + d->read((char *)&bi, sizeof(bi)); // read BITMAPV5HEADER header + if (s.status() != QDataStream::Ok) + return false; + + int nbits = bi.bV5BitCount; + int comp = bi.bV5Compression; + if (nbits != 32 || bi.bV5Planes != 1 || comp != BMP_BITFIELDS) + return false; //Unsupported DIBV5 format + + int w = bi.bV5Width, h = bi.bV5Height; + int red_mask = bi.bV5RedMask; + int green_mask = bi.bV5GreenMask; + int blue_mask = bi.bV5BlueMask; + int alpha_mask = bi.bV5AlphaMask; + int red_shift = 0; + int green_shift = 0; + int blue_shift = 0; + int alpha_shift = 0; + QImage::Format format = QImage::Format_ARGB32; + + if (bi.bV5Height < 0) + h = -h; // support images with negative height + if (image.size() != QSize(w, h) || image.format() != format) { + image = QImage(w, h, format); + if (image.isNull()) // could not create image + return false; + } + image.setDotsPerMeterX(bi.bV5XPelsPerMeter); + image.setDotsPerMeterY(bi.bV5YPelsPerMeter); + // read color table + DWORD colorSpace[3]; + if (d->read((char *)colorSpace, sizeof(colorSpace)) != sizeof(colorSpace)) + return false; + + red_shift = calc_shift(red_mask); + green_shift = calc_shift(green_mask); + blue_shift = calc_shift(blue_mask); + if (alpha_mask) { + alpha_shift = calc_shift(alpha_mask); + } + + int bpl = image.bytesPerLine(); + uchar *data = image.bits(); + register QRgb *p; + QRgb *end; + uchar *buf24 = new uchar[bpl]; + int bpl24 = ((w*nbits+31)/32)*4; + uchar *b; + unsigned int c; + + while (--h >= 0) { + p = (QRgb *)(data + h*bpl); + end = p + w; + if (d->read((char *)buf24,bpl24) != bpl24) + break; + b = buf24; + while (p < end) { + c = *b | (*(b+1))<<8 | (*(b+2))<<16 | (*(b+3))<<24; + *p++ = qRgba(((c & red_mask) >> red_shift) , + ((c & green_mask) >> green_shift), + ((c & blue_mask) >> blue_shift), + ((c & alpha_mask) >> alpha_shift)); + b += 4; + } + } + delete[] buf24; + + if (bi.bV5Height < 0) { + // Flip the image + uchar *buf = new uchar[bpl]; + h = -bi.bV5Height; + for (int y = 0; y < h/2; ++y) { + memcpy(buf, data + y*bpl, bpl); + memcpy(data + y*bpl, data + (h-y-1)*bpl, bpl); + memcpy(data + (h-y-1)*bpl, buf, bpl); + } + delete [] buf; + } + + return true; +} + +//#define QMIME_DEBUG + +// helpers for using global memory + +static int getCf(const FORMATETC &formatetc) +{ + return formatetc.cfFormat; +} + +static FORMATETC setCf(int cf) +{ + FORMATETC formatetc; + formatetc.cfFormat = cf; + formatetc.dwAspect = DVASPECT_CONTENT; + formatetc.lindex = -1; + formatetc.ptd = NULL; + formatetc.tymed = TYMED_HGLOBAL; + return formatetc; +} + +static bool setData(const QByteArray &data, STGMEDIUM *pmedium) +{ + HGLOBAL hData = GlobalAlloc(0, data.size()); + if (!hData) + return false; + + void *out = GlobalLock(hData); + memcpy(out, data.data(), data.size()); + GlobalUnlock(hData); + pmedium->tymed = TYMED_HGLOBAL; + pmedium->hGlobal = hData; + pmedium->pUnkForRelease = 0; + return true; +} + +static QByteArray getData(int cf, IDataObject *pDataObj) +{ + QByteArray data; + FORMATETC formatetc = setCf(cf); + STGMEDIUM s; + if (pDataObj->GetData(&formatetc, &s) == S_OK) { + DWORD * val = (DWORD*)GlobalLock(s.hGlobal); + data = QByteArray::fromRawData((char*)val, GlobalSize(s.hGlobal)); + data.detach(); + GlobalUnlock(s.hGlobal); + ReleaseStgMedium(&s); + } else { + //Try reading IStream data + formatetc.tymed = TYMED_ISTREAM; + if (pDataObj->GetData(&formatetc, &s) == S_OK) { + char szBuffer[4096]; + ULONG actualRead = 0; + LARGE_INTEGER pos = {{0, 0}}; + //Move to front (can fail depending on the data model implemented) + HRESULT hr = s.pstm->Seek(pos, STREAM_SEEK_SET, NULL); + while(SUCCEEDED(hr)){ + hr = s.pstm->Read(szBuffer, sizeof(szBuffer), &actualRead); + if (SUCCEEDED(hr) && actualRead > 0) { + data += QByteArray::fromRawData(szBuffer, actualRead); + } + if (actualRead != sizeof(szBuffer)) + break; + } + data.detach(); + ReleaseStgMedium(&s); + } + } + return data; +} + +static bool canGetData(int cf, IDataObject * pDataObj) +{ + FORMATETC formatetc = setCf(cf); + if (pDataObj->QueryGetData(&formatetc) != S_OK){ + formatetc.tymed = TYMED_ISTREAM; + return pDataObj->QueryGetData(&formatetc) == S_OK; + } + return true; +} + +/*! + \class QWindowsMime + \brief The QWindowsMime class maps open-standard MIME to Window Clipboard formats. + \ingroup qt-lighthouse-win + + Qt's drag-and-drop and clipboard facilities use the MIME standard. + On X11, this maps trivially to the Xdnd protocol, but on Windows + although some applications use MIME types to describe clipboard + formats, others use arbitrary non-standardized naming conventions, + or unnamed built-in formats of Windows. + + By instantiating subclasses of QWindowsMime that provide conversions + between Windows Clipboard and MIME formats, you can convert + proprietary clipboard formats to MIME formats. + + Qt has predefined support for the following Windows Clipboard formats: + + \table + \header \o Windows Format \o Equivalent MIME type + \row \o \c CF_UNICODETEXT \o \c text/plain + \row \o \c CF_TEXT \o \c text/plain + \row \o \c CF_DIB \o \c{image/xyz}, where \c xyz is + a \l{QImageWriter::supportedImageFormats()}{Qt image format} + \row \o \c CF_HDROP \o \c text/uri-list + \row \o \c CF_INETURL \o \c text/uri-list + \row \o \c CF_HTML \o \c text/html + \endtable + + An example use of this class would be to map the Windows Metafile + clipboard format (\c CF_METAFILEPICT) to and from the MIME type + \c{image/x-wmf}. This conversion might simply be adding or removing + a header, or even just passing on the data. See \l{Drag and Drop} + for more information on choosing and definition MIME types. + + You can check if a MIME type is convertible using canConvertFromMime() and + can perform conversions with convertToMime() and convertFromMime(). + + \sa QWindowsMimeConverter +*/ + +/*! +Constructs a new conversion object, adding it to the globally accessed +list of available converters. +*/ +QWindowsMime::QWindowsMime() +{ +} + +/*! +Destroys a conversion object, removing it from the global +list of available converters. +*/ +QWindowsMime::~QWindowsMime() +{ +} + +/*! + Registers the MIME type \a mime, and returns an ID number + identifying the format on Windows. +*/ +int QWindowsMime::registerMimeType(const QString &mime) +{ + int f = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (mime.utf16())); + if (!f) + qErrnoWarning("QWindowsMime::registerMimeType: Failed to register clipboard format"); + + return f; +} + +/*! +\fn bool QWindowsMime::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const + + Returns true if the converter can convert from the \a mimeData to + the format specified in \a formatetc. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn bool QWindowsMime::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const + + Returns true if the converter can convert to the \a mimeType from + the available formats in \a pDataObj. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! +\fn QString QWindowsMime::mimeForFormat(const FORMATETC &formatetc) const + + Returns the mime type that will be created form the format specified + in \a formatetc, or an empty string if this converter does not support + \a formatetc. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! +\fn QVector<FORMATETC> QWindowsMime::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const + + Returns a QVector of FORMATETC structures representing the different windows clipboard + formats that can be provided for the \a mimeType from the \a mimeData. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn QVariant QWindowsMime::convertToMime(const QString &mimeType, IDataObject *pDataObj, + QVariant::Type preferredType) const + + Returns a QVariant containing the converted data for \a mimeType from \a pDataObj. + If possible the QVariant should be of the \a preferredType to avoid needless conversions. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! +\fn bool QWindowsMime::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const + + Convert the \a mimeData to the format specified in \a formatetc. + The converted data should then be placed in \a pmedium structure. + + Return true if the conversion was successful. + + All subclasses must reimplement this pure virtual function. +*/ + +class QWindowsMimeText : public QWindowsMime +{ +public: + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const; + QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const; + QString mimeForFormat(const FORMATETC &formatetc) const; + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const; +}; + +bool QWindowsMimeText::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const +{ + int cf = getCf(formatetc); + return (cf == CF_UNICODETEXT || cf == CF_TEXT) && mimeData->hasText(); +} + +/* +text/plain is defined as using CRLF, but so many programs don't, +and programmers just look for '\n' in strings. +Windows really needs CRLF, so we ensure it here. +*/ +bool QWindowsMimeText::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const +{ + if (canConvertFromMime(formatetc, mimeData)) { + QByteArray data; + int cf = getCf(formatetc); + if (cf == CF_TEXT) { + data = mimeData->text().toLocal8Bit(); + // Anticipate required space for CRLFs at 1/40 + int maxsize=data.size()+data.size()/40+3; + QByteArray r(maxsize, '\0'); + char* o = r.data(); + const char* d = data.data(); + const int s = data.size(); + bool cr=false; + int j=0; + for (int i=0; i<s; i++) { + char c = d[i]; + if (c=='\r') + cr=true; + else { + if (c=='\n') { + if (!cr) + o[j++]='\r'; + } + cr=false; + } + o[j++]=c; + if (j+3 >= maxsize) { + maxsize += maxsize/4; + r.resize(maxsize); + o = r.data(); + } + } + o[j]=0; + return setData(r, pmedium); + } else if (cf == CF_UNICODETEXT) { + QString str = mimeData->text(); + const QChar *u = str.unicode(); + QString res; + const int s = str.length(); + int maxsize = s + s/40 + 3; + res.resize(maxsize); + int ri = 0; + bool cr = false; + for (int i=0; i < s; ++i) { + if (*u == QLatin1Char('\r')) + cr = true; + else { + if (*u == QLatin1Char('\n') && !cr) + res[ri++] = QLatin1Char('\r'); + cr = false; + } + res[ri++] = *u; + if (ri+3 >= maxsize) { + maxsize += maxsize/4; + res.resize(maxsize); + } + ++u; + } + res.truncate(ri); + const int byteLength = res.length() * sizeof(ushort); + QByteArray r(byteLength + 2, '\0'); + memcpy(r.data(), res.unicode(), byteLength); + r[byteLength] = 0; + r[byteLength+1] = 0; + return setData(r, pmedium); + } + } + return false; +} + +bool QWindowsMimeText::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const +{ + return mimeType.startsWith(QStringLiteral("text/plain")) + && (canGetData(CF_UNICODETEXT, pDataObj) + || canGetData(CF_TEXT, pDataObj)); +} + +QString QWindowsMimeText::mimeForFormat(const FORMATETC &formatetc) const +{ + int cf = getCf(formatetc); + if (cf == CF_UNICODETEXT || cf == CF_TEXT) + return QStringLiteral("text/plain"); + return QString(); +} + + +QVector<FORMATETC> QWindowsMimeText::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const +{ + QVector<FORMATETC> formatics; + if (mimeType.startsWith(QStringLiteral("text/plain")) && mimeData->hasText()) { + formatics += setCf(CF_UNICODETEXT); + formatics += setCf(CF_TEXT); + } + return formatics; +} + +QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const +{ + QVariant ret; + + if (canConvertToMime(mime, pDataObj)) { + QString str; + QByteArray data = getData(CF_UNICODETEXT, pDataObj); + if (!data.isEmpty()) { + str = QString::fromWCharArray((const wchar_t *)data.data()); + str.replace(QStringLiteral("\r\n"), QStringLiteral("\n")); + } else { + data = getData(CF_TEXT, pDataObj); + if (!data.isEmpty()) { + const char* d = data.data(); + const int s = qstrlen(d); + QByteArray r(data.size()+1, '\0'); + char* o = r.data(); + int j=0; + for (int i=0; i<s; i++) { + char c = d[i]; + if (c!='\r') + o[j++]=c; + } + o[j]=0; + str = QString::fromLocal8Bit(r); + } + } + if (preferredType == QVariant::String) + ret = str; + else + ret = str.toUtf8(); + } + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << ret; + return ret; +} + +class QWindowsMimeURI : public QWindowsMime +{ +public: + QWindowsMimeURI(); + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const; + QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const; + QString mimeForFormat(const FORMATETC &formatetc) const; + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const; +private: + int CF_INETURL_W; // wide char version + int CF_INETURL; +}; + +QWindowsMimeURI::QWindowsMimeURI() +{ + CF_INETURL_W = QWindowsMime::registerMimeType(QStringLiteral("UniformResourceLocatorW")); + CF_INETURL = QWindowsMime::registerMimeType(QStringLiteral("UniformResourceLocator")); +} + +bool QWindowsMimeURI::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const +{ + if (getCf(formatetc) == CF_HDROP) { + QList<QUrl> urls = mimeData->urls(); + for (int i=0; i<urls.size(); i++) { + if (!urls.at(i).toLocalFile().isEmpty()) + return true; + } + } + return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasFormat(QStringLiteral("text/uri-list")); +} + +bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const +{ + if (canConvertFromMime(formatetc, mimeData)) { + if (getCf(formatetc) == CF_HDROP) { + QList<QUrl> urls = mimeData->urls(); + QStringList fileNames; + int size = sizeof(DROPFILES)+2; + for (int i=0; i<urls.size(); i++) { + QString fn = QDir::toNativeSeparators(urls.at(i).toLocalFile()); + if (!fn.isEmpty()) { + size += sizeof(ushort) * (fn.length() + 1); + fileNames.append(fn); + } + } + + QByteArray result(size, '\0'); + DROPFILES* d = (DROPFILES*)result.data(); + d->pFiles = sizeof(DROPFILES); + GetCursorPos(&d->pt); // try + d->fNC = true; + char* files = ((char*)d) + d->pFiles; + + d->fWide = true; + wchar_t* f = (wchar_t*)files; + for (int i=0; i<fileNames.size(); i++) { + int l = fileNames.at(i).length(); + memcpy(f, fileNames.at(i).utf16(), l * sizeof(ushort)); + f += l; + *f++ = 0; + } + *f = 0; + + return setData(result, pmedium); + } else if (getCf(formatetc) == CF_INETURL_W) { + QList<QUrl> urls = mimeData->urls(); + QByteArray result; + if (!urls.isEmpty()) { + QString url = urls.at(0).toString(); + result = QByteArray((const char *)url.utf16(), url.length() * sizeof(ushort)); + } + result.append('\0'); + result.append('\0'); + return setData(result, pmedium); + } else if (getCf(formatetc) == CF_INETURL) { + QList<QUrl> urls = mimeData->urls(); + QByteArray result; + if (!urls.isEmpty()) + result = urls.at(0).toString().toLocal8Bit(); + return setData(result, pmedium); + } + } + + return false; +} + +bool QWindowsMimeURI::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const +{ + return mimeType == QStringLiteral("text/uri-list") + && (canGetData(CF_HDROP, pDataObj) || canGetData(CF_INETURL_W, pDataObj) || canGetData(CF_INETURL, pDataObj)); +} + +QString QWindowsMimeURI::mimeForFormat(const FORMATETC &formatetc) const +{ + QString format; + if (getCf(formatetc) == CF_HDROP || getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) + format = QStringLiteral("text/uri-list"); + return format; +} + +QVector<FORMATETC> QWindowsMimeURI::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const +{ + QVector<FORMATETC> formatics; + if (mimeType == QStringLiteral("text/uri-list")) { + if (canConvertFromMime(setCf(CF_HDROP), mimeData)) + formatics += setCf(CF_HDROP); + if (canConvertFromMime(setCf(CF_INETURL_W), mimeData)) + formatics += setCf(CF_INETURL_W); + if (canConvertFromMime(setCf(CF_INETURL), mimeData)) + formatics += setCf(CF_INETURL); + } + return formatics; +} + +QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const +{ + if (mimeType == QStringLiteral("text/uri-list")) { + if (canGetData(CF_HDROP, pDataObj)) { + QByteArray texturi; + QList<QVariant> urls; + + QByteArray data = getData(CF_HDROP, pDataObj); + if (data.isEmpty()) + return QVariant(); + + LPDROPFILES hdrop = (LPDROPFILES)data.data(); + if (hdrop->fWide) { + const wchar_t* filesw = (const wchar_t *)(data.data() + hdrop->pFiles); + int i = 0; + while (filesw[i]) { + QString fileurl = QString::fromWCharArray(filesw + i); + urls += QUrl::fromLocalFile(fileurl); + i += fileurl.length()+1; + } + } else { + const char* files = (const char *)data.data() + hdrop->pFiles; + int i=0; + while (files[i]) { + urls += QUrl::fromLocalFile(QString::fromLocal8Bit(files+i)); + i += int(strlen(files+i))+1; + } + } + + if (preferredType == QVariant::Url && urls.size() == 1) + return urls.at(0); + else if (!urls.isEmpty()) + return urls; + } else if (canGetData(CF_INETURL_W, pDataObj)) { + QByteArray data = getData(CF_INETURL_W, pDataObj); + if (data.isEmpty()) + return QVariant(); + return QUrl(QString::fromWCharArray((const wchar_t *)data.constData())); + } else if (canGetData(CF_INETURL, pDataObj)) { + QByteArray data = getData(CF_INETURL, pDataObj); + if (data.isEmpty()) + return QVariant(); + return QUrl(QString::fromLocal8Bit(data.constData())); + } + } + return QVariant(); +} + +class QWindowsMimeHtml : public QWindowsMime +{ +public: + QWindowsMimeHtml(); + + // for converting from Qt + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const; + + // for converting to Qt + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const; + QString mimeForFormat(const FORMATETC &formatetc) const; + +private: + int CF_HTML; +}; + +QWindowsMimeHtml::QWindowsMimeHtml() +{ + CF_HTML = QWindowsMime::registerMimeType(QStringLiteral("HTML Format")); +} + +QVector<FORMATETC> QWindowsMimeHtml::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const +{ + QVector<FORMATETC> formatetcs; + if (mimeType == QStringLiteral("text/html") && (!mimeData->html().isEmpty())) + formatetcs += setCf(CF_HTML); + return formatetcs; +} + +QString QWindowsMimeHtml::mimeForFormat(const FORMATETC &formatetc) const +{ + if (getCf(formatetc) == CF_HTML) + return QStringLiteral("text/html"); + return QString(); +} + +bool QWindowsMimeHtml::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const +{ + return mimeType == QStringLiteral("text/html") && canGetData(CF_HTML, pDataObj); +} + + +bool QWindowsMimeHtml::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const +{ + return getCf(formatetc) == CF_HTML && (!mimeData->html().isEmpty()); +} + +/* +The windows HTML clipboard format is as follows (xxxxxxxxxx is a 10 integer number giving the positions +in bytes). Charset used is mostly utf8, but can be different, ie. we have to look for the <meta> charset tag + + Version: 1.0 + StartHTML:xxxxxxxxxx + EndHTML:xxxxxxxxxx + StartFragment:xxxxxxxxxx + EndFragment:xxxxxxxxxx + ...html... + +*/ +QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const +{ + Q_UNUSED(preferredType); + QVariant result; + if (canConvertToMime(mime, pDataObj)) { + QByteArray html = getData(CF_HTML, pDataObj); +#ifdef QMIME_DEBUG + qDebug("QWindowsMimeHtml::convertToMime"); + qDebug("raw :"); + qDebug(html); +#endif + int start = html.indexOf("StartFragment:"); + int end = html.indexOf("EndFragment:"); + + if (start != -1) { + int startOffset = start + 14; + int i = startOffset; + while (html.at(i) != '\r' && html.at(i) != '\n') + ++i; + QByteArray bytecount = html.mid(startOffset, i - startOffset); + start = bytecount.toInt(); + } + + if (end != -1) { + int endOffset = end + 12; + int i = endOffset ; + while (html.at(i) != '\r' && html.at(i) != '\n') + ++i; + QByteArray bytecount = html.mid(endOffset , i - endOffset); + end = bytecount.toInt(); + } + + if (end > start && start > 0) { + html = "<!--StartFragment-->" + html.mid(start, end - start); + html += "<!--EndFragment-->"; + html.replace('\r', ""); + result = QString::fromUtf8(html); + } + } + return result; +} + +bool QWindowsMimeHtml::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const +{ + if (canConvertFromMime(formatetc, mimeData)) { + QByteArray data = mimeData->html().toUtf8(); + QByteArray result = + "Version:1.0\r\n" // 0-12 + "StartHTML:0000000105\r\n" // 13-35 + "EndHTML:0000000000\r\n" // 36-55 + "StartFragment:0000000000\r\n" // 58-86 + "EndFragment:0000000000\r\n\r\n"; // 87-105 + + if (data.indexOf("<!--StartFragment-->") == -1) + result += "<!--StartFragment-->"; + result += data; + if (data.indexOf("<!--EndFragment-->") == -1) + result += "<!--EndFragment-->"; + + // set the correct number for EndHTML + QByteArray pos = QString::number(result.size()).toLatin1(); + memcpy((char *)(result.data() + 53 - pos.length()), pos.constData(), pos.length()); + + // set correct numbers for StartFragment and EndFragment + pos = QString::number(result.indexOf("<!--StartFragment-->") + 20).toLatin1(); + memcpy((char *)(result.data() + 79 - pos.length()), pos.constData(), pos.length()); + pos = QString::number(result.indexOf("<!--EndFragment-->")).toLatin1(); + memcpy((char *)(result.data() + 103 - pos.length()), pos.constData(), pos.length()); + + return setData(result, pmedium); + } + return false; +} + + +#ifndef QT_NO_IMAGEFORMAT_BMP +class QWindowsMimeImage : public QWindowsMime +{ +public: + QWindowsMimeImage(); + // for converting from Qt + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const; + + // for converting to Qt + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const; + QString mimeForFormat(const FORMATETC &formatetc) const; +private: + bool hasOriginalDIBV5(IDataObject *pDataObj) const; + UINT CF_PNG; +}; + +QWindowsMimeImage::QWindowsMimeImage() +{ + CF_PNG = RegisterClipboardFormat(L"PNG"); +} + +QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const +{ + QVector<FORMATETC> formatetcs; + if (mimeData->hasImage() && mimeType == QStringLiteral("application/x-qt-image")) { + //add DIBV5 if image has alpha channel + QImage image = qvariant_cast<QImage>(mimeData->imageData()); + if (!image.isNull() && image.hasAlphaChannel()) + formatetcs += setCf(CF_DIBV5); + formatetcs += setCf(CF_DIB); + } + return formatetcs; +} + +QString QWindowsMimeImage::mimeForFormat(const FORMATETC &formatetc) const +{ + int cf = getCf(formatetc); + if (cf == CF_DIB || cf == CF_DIBV5 || cf == int(CF_PNG)) + return QStringLiteral("application/x-qt-image"); + return QString(); +} + +bool QWindowsMimeImage::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const +{ + if ((mimeType == QStringLiteral("application/x-qt-image")) && + (canGetData(CF_DIB, pDataObj) || canGetData(CF_PNG, pDataObj))) + return true; + return false; +} + +bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const +{ + int cf = getCf(formatetc); + if (mimeData->hasImage()) { + if (cf == CF_DIB) + return true; + else if (cf == CF_DIBV5) { + //support DIBV5 conversion only if the image has alpha channel + QImage image = qvariant_cast<QImage>(mimeData->imageData()); + if (!image.isNull() && image.hasAlphaChannel()) + return true; + } + } + return false; +} + +bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const +{ + int cf = getCf(formatetc); + if ((cf == CF_DIB || cf == CF_DIBV5) && mimeData->hasImage()) { + QImage img = qvariant_cast<QImage>(mimeData->imageData()); + if (img.isNull()) + return false; + QByteArray ba; + if (cf == CF_DIB) { + if (img.format() > QImage::Format_ARGB32) + img = img.convertToFormat(QImage::Format_RGB32); + const QByteArray ba = writeDib(img); + if (!ba.isEmpty()) + return setData(ba, pmedium); + } else { + QDataStream s(&ba, QIODevice::WriteOnly); + s.setByteOrder(QDataStream::LittleEndian);// Intel byte order #### + if (qt_write_dibv5(s, img)) + return setData(ba, pmedium); + } + } + return false; +} + +bool QWindowsMimeImage::hasOriginalDIBV5(IDataObject *pDataObj) const +{ + bool isSynthesized = true; + IEnumFORMATETC *pEnum =NULL; + HRESULT res = pDataObj->EnumFormatEtc(1, &pEnum); + if (res == S_OK && pEnum) { + FORMATETC fc; + while ((res = pEnum->Next(1, &fc, 0)) == S_OK) { + if (fc.ptd) + CoTaskMemFree(fc.ptd); + if (fc.cfFormat == CF_DIB) + break; + else if (fc.cfFormat == CF_DIBV5) { + isSynthesized = false; + break; + } + } + pEnum->Release(); + } + return !isSynthesized; +} + +QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const +{ + Q_UNUSED(preferredType); + QVariant result; + if (mimeType != QStringLiteral("application/x-qt-image")) + return result; + //Try to convert from a format which has more data + //DIBV5, use only if its is not synthesized + if (canGetData(CF_DIBV5, pDataObj) && hasOriginalDIBV5(pDataObj)) { + QImage img; + QByteArray data = getData(CF_DIBV5, pDataObj); + QDataStream s(&data, QIODevice::ReadOnly); + s.setByteOrder(QDataStream::LittleEndian); + if (qt_read_dibv5(s, img)) { // #### supports only 32bit DIBV5 + return img; + } + } + //PNG, MS Office place this (undocumented) + if (canGetData(CF_PNG, pDataObj)) { + QImage img; + QByteArray data = getData(CF_PNG, pDataObj); + if (img.loadFromData(data, "PNG")) { + return img; + } + } + //Fallback to DIB + if (canGetData(CF_DIB, pDataObj)) { + const QImage img = readDib(getData(CF_DIB, pDataObj)); + if (!img.isNull()) + return img; + } + // Failed + return result; +} +#endif + +class QBuiltInMimes : public QWindowsMime +{ +public: + QBuiltInMimes(); + + // for converting from Qt + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const; + + // for converting to Qt + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const; + QString mimeForFormat(const FORMATETC &formatetc) const; + +private: + QMap<int, QString> outFormats; + QMap<int, QString> inFormats; +}; + +QBuiltInMimes::QBuiltInMimes() +: QWindowsMime() +{ + outFormats.insert(QWindowsMime::registerMimeType(QStringLiteral("application/x-color")), QStringLiteral("application/x-color")); + inFormats.insert(QWindowsMime::registerMimeType(QStringLiteral("application/x-color")), QStringLiteral("application/x-color")); +} + +bool QBuiltInMimes::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const +{ + // really check + return formatetc.tymed & TYMED_HGLOBAL + && outFormats.contains(formatetc.cfFormat) + && mimeData->formats().contains(outFormats.value(formatetc.cfFormat)); +} + +bool QBuiltInMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const +{ + if (canConvertFromMime(formatetc, mimeData)) { + QByteArray data; + if (outFormats.value(getCf(formatetc)) == QStringLiteral("text/html")) { + // text/html is in wide chars on windows (compatible with mozillia) + QString html = mimeData->html(); + // same code as in the text converter up above + const QChar *u = html.unicode(); + QString res; + const int s = html.length(); + int maxsize = s + s/40 + 3; + res.resize(maxsize); + int ri = 0; + bool cr = false; + for (int i=0; i < s; ++i) { + if (*u == QLatin1Char('\r')) + cr = true; + else { + if (*u == QLatin1Char('\n') && !cr) + res[ri++] = QLatin1Char('\r'); + cr = false; + } + res[ri++] = *u; + if (ri+3 >= maxsize) { + maxsize += maxsize/4; + res.resize(maxsize); + } + ++u; + } + res.truncate(ri); + const int byteLength = res.length() * sizeof(ushort); + QByteArray r(byteLength + 2, '\0'); + memcpy(r.data(), res.unicode(), byteLength); + r[byteLength] = 0; + r[byteLength+1] = 0; + data = r; + } else { +#ifndef QT_NO_DRAGANDDROP + data = QInternalMimeData::renderDataHelper(outFormats.value(getCf(formatetc)), mimeData); +#endif //QT_NO_DRAGANDDROP + } + return setData(data, pmedium); + } + return false; +} + +QVector<FORMATETC> QBuiltInMimes::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const +{ + QVector<FORMATETC> formatetcs; + if (!outFormats.keys(mimeType).isEmpty() && mimeData->formats().contains(mimeType)) + formatetcs += setCf(outFormats.key(mimeType)); + return formatetcs; +} + +bool QBuiltInMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const +{ + return (!inFormats.keys(mimeType).isEmpty()) + && canGetData(inFormats.key(mimeType), pDataObj); +} + +QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const +{ + QVariant val; + if (canConvertToMime(mimeType, pDataObj)) { + QByteArray data = getData(inFormats.key(mimeType), pDataObj); + if (!data.isEmpty()) { +#ifdef QMIME_DEBUG + qDebug("QBuiltInMimes::convertToMime()"); +#endif + if (mimeType == QStringLiteral("text/html") && preferredType == QVariant::String) { + // text/html is in wide chars on windows (compatible with Mozilla) + val = QString::fromWCharArray((const wchar_t *)data.data()); + } else { + val = data; // it should be enough to return the data and let QMimeData do the rest. + } + } + } + return val; +} + +QString QBuiltInMimes::mimeForFormat(const FORMATETC &formatetc) const +{ + return inFormats.value(getCf(formatetc)); +} + + +class QLastResortMimes : public QWindowsMime +{ +public: + + QLastResortMimes(); + // for converting from Qt + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const; + + // for converting to Qt + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const; + QString mimeForFormat(const FORMATETC &formatetc) const; + +private: + QMap<int, QString> formats; + static QStringList ianaTypes; + static QStringList excludeList; +}; + +QStringList QLastResortMimes::ianaTypes; +QStringList QLastResortMimes::excludeList; + +QLastResortMimes::QLastResortMimes() +{ + //MIME Media-Types + if (!ianaTypes.size()) { + ianaTypes.append(QStringLiteral("application/")); + ianaTypes.append(QStringLiteral("audio/")); + ianaTypes.append(QStringLiteral("example/")); + ianaTypes.append(QStringLiteral("image/")); + ianaTypes.append(QStringLiteral("message/")); + ianaTypes.append(QStringLiteral("model/")); + ianaTypes.append(QStringLiteral("multipart/")); + ianaTypes.append(QStringLiteral("text/")); + ianaTypes.append(QStringLiteral("video/")); + } + //Types handled by other classes + if (!excludeList.size()) { + excludeList.append(QStringLiteral("HTML Format")); + excludeList.append(QStringLiteral("UniformResourceLocator")); + excludeList.append(QStringLiteral("text/html")); + excludeList.append(QStringLiteral("text/plain")); + excludeList.append(QStringLiteral("text/uri-list")); + excludeList.append(QStringLiteral("application/x-qt-image")); + excludeList.append(QStringLiteral("application/x-color")); + } +} + +bool QLastResortMimes::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const +{ + // really check +#ifndef QT_NO_DRAGANDDROP + return formatetc.tymed & TYMED_HGLOBAL + && (formats.contains(formatetc.cfFormat) + && QInternalMimeData::hasFormatHelper(formats.value(formatetc.cfFormat), mimeData)); +#else + Q_UNUSED(mimeData); + Q_UNUSED(formatetc); + return formatetc.tymed & TYMED_HGLOBAL + && formats.contains(formatetc.cfFormat); +#endif //QT_NO_DRAGANDDROP +} + +bool QLastResortMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const +{ +#ifndef QT_NO_DRAGANDDROP + return canConvertFromMime(formatetc, mimeData) + && setData(QInternalMimeData::renderDataHelper(formats.value(getCf(formatetc)), mimeData), pmedium); +#else + Q_UNUSED(mimeData); + Q_UNUSED(formatetc); + Q_UNUSED(pmedium); + return false; +#endif //QT_NO_DRAGANDDROP +} + +QVector<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, const QMimeData * /*mimeData*/) const +{ + QVector<FORMATETC> formatetcs; + if (!formats.keys(mimeType).isEmpty()) { + formatetcs += setCf(formats.key(mimeType)); + } else if (!excludeList.contains(mimeType, Qt::CaseInsensitive)){ + // register any other available formats + int cf = QWindowsMime::registerMimeType(mimeType); + QLastResortMimes *that = const_cast<QLastResortMimes *>(this); + that->formats.insert(cf, mimeType); + formatetcs += setCf(cf); + } + return formatetcs; +} +static const char x_qt_windows_mime[] = "application/x-qt-windows-mime;value=\""; + +static bool isCustomMimeType(const QString &mimeType) +{ + return mimeType.startsWith(QLatin1String(x_qt_windows_mime), Qt::CaseInsensitive); +} + +static QString customMimeType(const QString &mimeType) +{ + int len = sizeof(x_qt_windows_mime) - 1; + int n = mimeType.lastIndexOf(QLatin1Char('\"'))-len; + return mimeType.mid(len, n); +} + +bool QLastResortMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const +{ + if (isCustomMimeType(mimeType)) { + QString clipFormat = customMimeType(mimeType); + int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16())); + return canGetData(cf, pDataObj); + } else if (formats.keys(mimeType).isEmpty()) { + // if it is not in there then register it an see if we can get it + int cf = QWindowsMime::registerMimeType(mimeType); + return canGetData(cf, pDataObj); + } else { + return canGetData(formats.key(mimeType), pDataObj); + } + return false; +} + +QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const +{ + Q_UNUSED(preferredType); + QVariant val; + if (canConvertToMime(mimeType, pDataObj)) { + QByteArray data; + if (isCustomMimeType(mimeType)) { + QString clipFormat = customMimeType(mimeType); + int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16())); + data = getData(cf, pDataObj); + } else if (formats.keys(mimeType).isEmpty()) { + int cf = QWindowsMime::registerMimeType(mimeType); + data = getData(cf, pDataObj); + } else { + data = getData(formats.key(mimeType), pDataObj); + } + if (!data.isEmpty()) + val = data; // it should be enough to return the data and let QMimeData do the rest. + } + return val; +} + +QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const +{ + QString format = formats.value(getCf(formatetc)); + if (!format.isEmpty()) + return format; + + wchar_t buffer[256]; + int len = GetClipboardFormatName(getCf(formatetc), buffer, 256); + + if (len) { + QString clipFormat = QString::fromWCharArray(buffer, len); +#ifndef QT_NO_DRAGANDDROP + if (QInternalMimeData::canReadData(clipFormat)) + format = clipFormat; + else if((formatetc.cfFormat >= 0xC000)){ + //create the mime as custom. not registered. + if (!excludeList.contains(clipFormat, Qt::CaseInsensitive)) { + //check if this is a mime type + bool ianaType = false; + int sz = ianaTypes.size(); + for (int i = 0; i < sz; i++) { + if (clipFormat.startsWith(ianaTypes[i], Qt::CaseInsensitive)) { + ianaType = true; + break; + } + } + if (!ianaType) + format = QLatin1String(x_qt_windows_mime) + clipFormat + QLatin1Char('\"'); + else + format = clipFormat; + } + } +#endif //QT_NO_DRAGANDDROP + } + + return format; +} + +/*! + \class QWindowsMimeConverter + \brief Manages the list of QWindowsMime instances. + \ingroup qt-lighthouse-win + \sa QWindowsMime +*/ + +QWindowsMimeConverter::QWindowsMimeConverter() +{ +} + +QWindowsMimeConverter::~QWindowsMimeConverter() +{ + qDeleteAll(m_mimes); +} + +QWindowsMime * QWindowsMimeConverter::converterToMime(const QString &mimeType, IDataObject *pDataObj) const +{ + ensureInitialized(); + for (int i = m_mimes.size()-1; i >= 0; --i) { + if (m_mimes.at(i)->canConvertToMime(mimeType, pDataObj)) + return m_mimes.at(i); + } + return 0; +} + +QStringList QWindowsMimeConverter::allMimesForFormats(IDataObject *pDataObj) const +{ + ensureInitialized(); + QStringList formats; + LPENUMFORMATETC FAR fmtenum; + HRESULT hr = pDataObj->EnumFormatEtc(DATADIR_GET, &fmtenum); + + if (hr == NOERROR) { + FORMATETC fmtetc; + while (S_OK == fmtenum->Next(1, &fmtetc, 0)) { +#if defined(QMIME_DEBUG) + qDebug("QWindowsMime::allMimesForFormats()"); + wchar_t buf[256] = {0}; + GetClipboardFormatName(fmtetc.cfFormat, buf, 255); + qDebug("CF = %d : %s", fmtetc.cfFormat, QString::fromWCharArray(buf)); +#endif + for (int i= m_mimes.size() - 1; i >= 0; --i) { + QString format = m_mimes.at(i)->mimeForFormat(fmtetc); + if (!format.isEmpty() && !formats.contains(format)) { + formats += format; + } + } + // as documented in MSDN to avoid possible memleak + if (fmtetc.ptd) + CoTaskMemFree(fmtetc.ptd); + } + fmtenum->Release(); + } + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << pDataObj << formats; + return formats; +} + +QWindowsMime * QWindowsMimeConverter::converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const +{ + ensureInitialized(); + for (int i = m_mimes.size()-1; i >= 0; --i) { + if (m_mimes.at(i)->canConvertFromMime(formatetc, mimeData)) + return m_mimes.at(i); + } + return 0; +} + +QVector<FORMATETC> QWindowsMimeConverter::allFormatsForMime(const QMimeData *mimeData) const +{ + ensureInitialized(); + QVector<FORMATETC> formatics; +#ifdef QT_NO_DRAGANDDROP + Q_UNUSED(mimeData); +#else + formatics.reserve(20); + const QStringList formats = QInternalMimeData::formatsHelper(mimeData); + for (int f = 0; f < formats.size(); ++f) { + for (int i = m_mimes.size() - 1; i >= 0; --i) + formatics += m_mimes.at(i)->formatsForMime(formats.at(f), mimeData); + } +#endif //QT_NO_DRAGANDDROP + return formatics; +} + +void QWindowsMimeConverter::ensureInitialized() const +{ + if (m_mimes.isEmpty()) { + m_mimes << new QWindowsMimeImage << new QLastResortMimes + << new QWindowsMimeText << new QWindowsMimeURI + << new QWindowsMimeHtml << new QBuiltInMimes; + } +} + +QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes, + IDataObject *pDataObj, + QVariant::Type preferredType, + QString *formatIn /* = 0 */) const +{ + foreach (const QString &format, mimeTypes) { + if (const QWindowsMime *converter = converterToMime(format, pDataObj)) { + if (converter->canConvertToMime(format, pDataObj)) { + const QVariant dataV = converter->convertToMime(format, pDataObj, preferredType); + if (dataV.isValid()) { + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << mimeTypes << "\nFormat: " + << format << pDataObj << " returns " << dataV; + if (formatIn) + *formatIn = format; + return dataV; + } + } + } + } + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << "fails" << mimeTypes << pDataObj << preferredType; + return QVariant(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h new file mode 100644 index 0000000000..85f61a91e2 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsmime.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSMIME_H +#define QWINDOWSMIME_H + +#include "qtwindows_additional.h" + +#include <QtCore/QVector> +#include <QtCore/QList> +#include <QtCore/QVariant> +#include <QtCore/QSharedPointer> + +QT_BEGIN_NAMESPACE + +class QMimeData; + +class QWindowsMime +{ + Q_DISABLE_COPY(QWindowsMime) +public: + QWindowsMime(); + virtual ~QWindowsMime(); + + // for converting from Qt + virtual bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const = 0; + virtual bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const = 0; + virtual QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const = 0; + + // for converting to Qt + virtual bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const = 0; + virtual QVariant convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const = 0; + virtual QString mimeForFormat(const FORMATETC &formatetc) const = 0; + + static int registerMimeType(const QString &mime); +}; + +class QWindowsMimeConverter +{ + Q_DISABLE_COPY(QWindowsMimeConverter) +public: + QWindowsMimeConverter(); + ~QWindowsMimeConverter(); + + QWindowsMime *converterToMime(const QString &mimeType, IDataObject *pDataObj) const; + QStringList allMimesForFormats(IDataObject *pDataObj) const; + QWindowsMime *converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; + QVector<FORMATETC> allFormatsForMime(const QMimeData *mimeData) const; + + // Convenience. + QVariant convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QVariant::Type preferredType, + QString *format = 0) const; + +private: + typedef QSharedPointer<QWindowsMime> MimePtr; + + void ensureInitialized() const; + + mutable QList<QWindowsMime *> m_mimes; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSMIME_H diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp new file mode 100644 index 0000000000..dea965b439 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsmousehandler.h" +#include "qwindowscontext.h" +#include "qwindowswindow.h" +#include "qwindowsintegration.h" + +#include <QtGui/QWindowSystemInterface> +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> + +#include <QtCore/QDebug> +#include <QtCore/QScopedArrayPointer> + +#include <windowsx.h> + +QT_BEGIN_NAMESPACE + +static inline void compressMouseMove(MSG *msg) +{ + // Compress mouse move events + if (msg->message == WM_MOUSEMOVE) { + MSG mouseMsg; + while (PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEFIRST, + WM_MOUSELAST, PM_NOREMOVE)) { + if (mouseMsg.message == WM_MOUSEMOVE) { +#define PEEKMESSAGE_IS_BROKEN 1 +#ifdef PEEKMESSAGE_IS_BROKEN + // Since the Windows PeekMessage() function doesn't + // correctly return the wParam for WM_MOUSEMOVE events + // if there is a key release event in the queue + // _before_ the mouse event, we have to also consider + // key release events (kls 2003-05-13): + MSG keyMsg; + bool done = false; + while (PeekMessage(&keyMsg, 0, WM_KEYFIRST, WM_KEYLAST, + PM_NOREMOVE)) { + if (keyMsg.time < mouseMsg.time) { + if ((keyMsg.lParam & 0xC0000000) == 0x40000000) { + PeekMessage(&keyMsg, 0, keyMsg.message, + keyMsg.message, PM_REMOVE); + } else { + done = true; + break; + } + } else { + break; // no key event before the WM_MOUSEMOVE event + } + } + if (done) + break; +#else + // Actually the following 'if' should work instead of + // the above key event checking, but apparently + // PeekMessage() is broken :-( + if (mouseMsg.wParam != msg.wParam) + break; // leave the message in the queue because + // the key state has changed +#endif + // Update the passed in MSG structure with the + // most recent one. + msg->lParam = mouseMsg.lParam; + msg->wParam = mouseMsg.wParam; + // Extract the x,y coordinates from the lParam as we do in the WndProc + msg->pt.x = GET_X_LPARAM(mouseMsg.lParam); + msg->pt.y = GET_Y_LPARAM(mouseMsg.lParam); + ClientToScreen(msg->hwnd, &(msg->pt)); + // Remove the mouse move message + PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEMOVE, + WM_MOUSEMOVE, PM_REMOVE); + } else { + break; // there was no more WM_MOUSEMOVE event + } + } + } +} + +/*! + \class QWindowsMouseHandler + \brief Windows mouse handler + + Dispatches mouse and touch events. Separate for code cleanliness. + + \ingroup qt-lighthouse-win +*/ + +QWindowsMouseHandler::QWindowsMouseHandler() : + m_windowUnderMouse(0) +{ +} + +bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, + QtWindows::WindowsEventType et, + MSG msg, LRESULT *result) +{ + if (et & QtWindows::NonClientEventFlag) + return false; + if (et == QtWindows::MouseWheelEvent) + return translateMouseWheelEvent(window, hwnd, msg, result); + *result = 0; + if (msg.message == WM_MOUSELEAVE) { + // When moving out of a child, MouseMove within parent is received first + // (see below) + if (QWindowsContext::verboseEvents) + qDebug() << "WM_MOUSELEAVE for " << window << " current= " << m_windowUnderMouse; + if (window == m_windowUnderMouse) { + QWindowSystemInterface::handleLeaveEvent(window); + m_windowUnderMouse = 0; + } + return true; + } + compressMouseMove(&msg); + const QPoint client(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); + // Enter new window: track to generate leave event. + if (m_windowUnderMouse != window) { + // The tracking on m_windowUnderMouse might still be active and + // trigger later on. + if (m_windowUnderMouse) { + if (QWindowsContext::verboseEvents) + qDebug() << "Synthetic leave for " << m_windowUnderMouse; + QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse); + } + m_windowUnderMouse = window; + if (QWindowsContext::verboseEvents) + qDebug() << "Entering " << window; + QWindowsWindow::baseWindowOf(window)->applyCursor(); + QWindowSystemInterface::handleEnterEvent(window); + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hwnd; + tme.dwHoverTime = HOVER_DEFAULT; // + if (!TrackMouseEvent(&tme)) + qWarning("TrackMouseEvent failed."); + } + QWindowSystemInterface::handleMouseEvent(window, client, + QWindowsGeometryHint::mapToGlobal(hwnd, client), + keyStateToMouseButtons((int)msg.wParam)); + return true; +} + +bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND, + MSG msg, LRESULT *) +{ + const Qt::MouseButtons buttons = keyStateToMouseButtons((int)msg.wParam); + int delta; + if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL) + delta = (short) HIWORD (msg.wParam); + else + delta = (int) msg.wParam; + + Qt::Orientation orientation = (msg.message == WM_MOUSEHWHEEL + || (buttons & Qt::AltModifier)) ? + Qt::Horizontal : Qt::Vertical; + + // according to the MSDN documentation on WM_MOUSEHWHEEL: + // a positive value indicates that the wheel was rotated to the right; + // a negative value indicates that the wheel was rotated to the left. + // Qt defines this value as the exact opposite, so we have to flip the value! + if (msg.message == WM_MOUSEHWHEEL) + delta = -delta; + + const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); + // TODO: if there is a widget under the mouse and it is not shadowed + // QWindow *receiver = windowAt(pos); + // by modality, we send the event to it first. + //synaptics touchpad shows its own widget at this position + //so widgetAt() will fail with that HWND, try child of this widget + // if (!receiver) receiver = window->childAt(pos); + QWindow *receiver = window; + QWindowSystemInterface::handleWheelEvent(receiver, + QWindowsGeometryHint::mapFromGlobal(receiver, globalPos), + globalPos, + delta, orientation); + return true; +} + +// from bool QApplicationPrivate::translateTouchEvent() +bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, + QtWindows::WindowsEventType, + MSG msg, LRESULT *) +{ + typedef QWindowSystemInterface::TouchPoint QTouchPoint; + typedef QList<QWindowSystemInterface::TouchPoint> QTouchPointList; + + const QRect screenGeometry = window->screen()->geometry(); + + const int winTouchPointCount = msg.wParam; + QScopedArrayPointer<TOUCHINPUT> winTouchInputs(new TOUCHINPUT[winTouchPointCount]); + memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchPointCount); + + QTouchPointList touchPoints; + touchPoints.reserve(winTouchPointCount); + Qt::TouchPointStates allStates = 0; + + Q_ASSERT(QWindowsContext::user32dll.getTouchInputInfo); + + QWindowsContext::user32dll.getTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); + for (int i = 0; i < winTouchPointCount; ++i) { + const TOUCHINPUT &winTouchInput = winTouchInputs[i]; + QTouchPoint touchPoint; + touchPoint.pressure = 1.0; + touchPoint.isPrimary = (winTouchInput.dwFlags & TOUCHEVENTF_PRIMARY) != 0; + touchPoint.id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1); + if (touchPoint.id == -1) { + touchPoint.id = m_touchInputIDToTouchPointID.size(); + m_touchInputIDToTouchPointID.insert(winTouchInput.dwID, touchPoint.id); + } + + QPointF screenPos = QPointF(qreal(winTouchInput.x) / qreal(100.), qreal(winTouchInput.y) / qreal(100.)); + if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA) + touchPoint.area.setSize(QSizeF(qreal(winTouchInput.cxContact) / qreal(100.), + qreal(winTouchInput.cyContact) / qreal(100.))); + touchPoint.area.moveCenter(screenPos); + + if (winTouchInput.dwFlags & TOUCHEVENTF_DOWN) { + touchPoint.state = Qt::TouchPointPressed; + } else if (winTouchInput.dwFlags & TOUCHEVENTF_UP) { + touchPoint.state = Qt::TouchPointReleased; + } else { + // TODO: Previous code checked" + // screenPos == touchPoint.normalPosition -> Qt::TouchPointStationary, but + // but touchPoint.normalPosition was never initialized? + touchPoint.state = touchPoint.state; + } + + touchPoint.normalPosition = QPointF(screenPos.x() / screenGeometry.width(), + screenPos.y() / screenGeometry.height()); + + allStates |= touchPoint.state; + + touchPoints.append(touchPoint); + } + + QWindowsContext::user32dll.closeTouchInputHandle((HANDLE) msg.lParam); + + // all touch points released, forget the ids we've seen, they may not be reused + if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) + m_touchInputIDToTouchPointID.clear(); + + // TODO: Device used to be hardcoded to screen in previous code. + // What is the correct event type? Which parts of translateRawTouchEvent() are required? + QWindowSystemInterface::handleTouchEvent(window, QEvent::TouchBegin, + QTouchEvent::TouchScreen, + touchPoints); + return true; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h new file mode 100644 index 0000000000..953649102a --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsmousehandler.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSMOUSEHANDLER_H +#define QWINDOWSMOUSEHANDLER_H + +#include "qtwindowsglobal.h" +#include "qtwindows_additional.h" + +#include <QtCore/QPointer> +#include <QtCore/QHash> + +QT_BEGIN_NAMESPACE + +class QWindow; + +class QWindowsMouseHandler +{ + Q_DISABLE_COPY(QWindowsMouseHandler) +public: + QWindowsMouseHandler(); + + bool translateMouseEvent(QWindow *widget, HWND hwnd, + QtWindows::WindowsEventType t, MSG msg, + LRESULT *result); + bool translateTouchEvent(QWindow *widget, HWND hwnd, + QtWindows::WindowsEventType t, MSG msg, + LRESULT *result); + + static inline Qt::MouseButtons keyStateToMouseButtons(int); + static inline int mouseButtonsToKeyState(Qt::MouseButtons); + + QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); } + +private: + inline bool translateMouseWheelEvent(QWindow *window, HWND hwnd, + MSG msg, LRESULT *result); + + QPointer<QWindow> m_windowUnderMouse; + QHash<DWORD, int> m_touchInputIDToTouchPointID; +}; + +Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(int wParam) +{ + Qt::MouseButtons mb(Qt::NoButton); + if (wParam & MK_LBUTTON) + mb |= Qt::LeftButton; + if (wParam & MK_MBUTTON) + mb |= Qt::MiddleButton; + if (wParam & MK_RBUTTON) + mb |= Qt::RightButton; + if (wParam & MK_XBUTTON1) + mb |= Qt::XButton1; + if (wParam & MK_XBUTTON2) + mb |= Qt::XButton2; + return mb; +} + +int QWindowsMouseHandler::mouseButtonsToKeyState(Qt::MouseButtons mb) +{ + int result = 0; + if (mb & Qt::LeftButton) + result |= MK_LBUTTON; + if (mb & Qt::MiddleButton) + result |= MK_MBUTTON; + if (mb & Qt::RightButton) + result |= MK_RBUTTON; + if (mb & Qt::XButton1) + result |= MK_XBUTTON1; + if (mb & Qt::XButton2) + result |= MK_XBUTTON2; + return result; +} + +QT_END_NAMESPACE + +#endif // QWINDOWSMOUSEHANDLER_H diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.cpp b/src/plugins/platforms/windows/qwindowsnativeimage.cpp new file mode 100644 index 0000000000..2ecf334b39 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsnativeimage.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsnativeimage.h" +#include "qwindowscontext.h" + +#include <QtGui/private/qpaintengine_p.h> +#include <QtGui/private/qpaintengine_raster_p.h> + +QT_BEGIN_NAMESPACE + +typedef struct { + BITMAPINFOHEADER bmiHeader; + DWORD redMask; + DWORD greenMask; + DWORD blueMask; +} BITMAPINFO_MASK; + +/*! + \class QWindowsNativeImage + \brief Windows Native image + + Note that size can be 0 (widget autotests with zero size), which + causes CreateDIBSection() to fail. + + \sa QWindowsBackingStore + \ingroup qt-lighthouse-win +*/ + +static inline HDC createDC() +{ + HDC display_dc = GetDC(0); + HDC hdc = CreateCompatibleDC(display_dc); + ReleaseDC(0, display_dc); + Q_ASSERT(hdc); + return hdc; +} + +static inline HBITMAP createDIB(HDC hdc, int width, int height, + QImage::Format format, + uchar **bitsIn) +{ + BITMAPINFO_MASK bmi; + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; // top-down. + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biSizeImage = 0; + + if (format == QImage::Format_RGB16) { + bmi.bmiHeader.biBitCount = 16; + bmi.bmiHeader.biCompression = BI_BITFIELDS; + bmi.redMask = 0xF800; + bmi.greenMask = 0x07E0; + bmi.blueMask = 0x001F; + } else { + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.redMask = 0; + bmi.greenMask = 0; + bmi.blueMask = 0; + } + + void *bits = 0; + HBITMAP bitmap = CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO *>(&bmi), + DIB_RGB_COLORS, &bits, 0, 0); + if (!bitmap || !bits) + qFatal("%s: CreateDIBSection failed.", __FUNCTION__); + + *bitsIn = (uchar*)bits; + return bitmap; +} + +QWindowsNativeImage::QWindowsNativeImage(int width, int height, + QImage::Format format) : + m_hdc(createDC()), + m_bitmap(0), + m_null_bitmap(0) +{ + if (width != 0 && height != 0) { + uchar *bits; + m_bitmap = createDIB(m_hdc, width, height, format, &bits); + m_null_bitmap = (HBITMAP)SelectObject(m_hdc, m_bitmap); + m_image = QImage(bits, width, height, format); + Q_ASSERT(m_image.paintEngine()->type() == QPaintEngine::Raster); + static_cast<QRasterPaintEngine *>(m_image.paintEngine())->setDC(m_hdc); + } else { + m_image = QImage(width, height, format); + } + + GdiFlush(); +} + +QWindowsNativeImage::~QWindowsNativeImage() +{ + if (m_hdc) { + if (m_bitmap) { + if (m_null_bitmap) + SelectObject(m_hdc, m_null_bitmap); + DeleteObject(m_bitmap); + } + DeleteDC(m_hdc); + } +} + +QImage::Format QWindowsNativeImage::systemFormat() +{ + static const int depth = QWindowsContext::instance()->screenDepth(); + return depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.h b/src/plugins/platforms/windows/qwindowsnativeimage.h new file mode 100644 index 0000000000..c77805a10a --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsnativeimage.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSNATIVEIMAGE_H +#define QWINDOWSNATIVEIMAGE_H + +#include "qtwindows_additional.h" + +#include <QtGui/QImage> + +#include <QtCore/QtGlobal> + +QT_BEGIN_NAMESPACE + +class QWindowsNativeImage +{ + Q_DISABLE_COPY(QWindowsNativeImage) +public: + QWindowsNativeImage(int width, int height, + QImage::Format format); + + ~QWindowsNativeImage(); + + inline int width() const { return m_image.width(); } + inline int height() const { return m_image.height(); } + + QImage &image() { return m_image; } + const QImage &image() const { return m_image; } + + HDC hdc() const { return m_hdc; } + + static QImage::Format systemFormat(); + +private: + const HDC m_hdc; + QImage m_image; + + HBITMAP m_bitmap; + HBITMAP m_null_bitmap; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSNATIVEIMAGE_H diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp new file mode 100644 index 0000000000..864dc3dbb7 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsole.cpp @@ -0,0 +1,476 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsole.h" +#include "qwindowsmime.h" +#include "qwindowscontext.h" +\ +#include <QtGui/QMouseEvent> +#include <QtGui/QWindow> +#include <QtGui/QPainter> +#include <QtGui/QCursor> +#include <QtGui/QGuiApplication> + +#include <QtCore/QMimeData> +#include <QtCore/QDebug> + +#include <shlobj.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsOleDataObject + \brief OLE data container + + The following methods are NOT supported for data transfer using the + clipboard or drag-drop: + \list + \o IDataObject::SetData -- return E_NOTIMPL + \o IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED + \o ::DUnadvise + \o ::EnumDAdvise + \o IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL + (NOTE: must set pformatetcOut->ptd = NULL) + \endlist + + \ingroup qt-lighthouse-win +*/ + +QWindowsOleDataObject::QWindowsOleDataObject(QMimeData *mimeData) : + m_refs(1), data(mimeData), + CF_PERFORMEDDROPEFFECT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT)), + performedEffect(DROPEFFECT_NONE) +{ + if (QWindowsContext::verboseOLE) + qDebug("%s '%s'", __FUNCTION__, qPrintable(mimeData->formats().join(QStringLiteral(", ")))); +} + +QWindowsOleDataObject::~QWindowsOleDataObject() +{ + if (QWindowsContext::verboseOLE) + qDebug("%s", __FUNCTION__); +} + +void QWindowsOleDataObject::releaseQt() +{ + data = 0; +} + +QMimeData *QWindowsOleDataObject::mimeData() const +{ + return data.data(); +} + +DWORD QWindowsOleDataObject::reportedPerformedEffect() const +{ + return performedEffect; +} + +//--------------------------------------------------------------------- +// IUnknown Methods +//--------------------------------------------------------------------- + +STDMETHODIMP +QWindowsOleDataObject::QueryInterface(REFIID iid, void FAR* FAR* ppv) +{ + if (iid == IID_IUnknown || iid == IID_IDataObject) { + *ppv = this; + AddRef(); + return NOERROR; + } + *ppv = NULL; + return ResultFromScode(E_NOINTERFACE); +} + +STDMETHODIMP_(ULONG) +QWindowsOleDataObject::AddRef(void) +{ + return ++m_refs; +} + +STDMETHODIMP_(ULONG) +QWindowsOleDataObject::Release(void) +{ + if (--m_refs == 0) { + releaseQt(); + delete this; + return 0; + } + return m_refs; +} + +STDMETHODIMP +QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) +{ + HRESULT hr = ResultFromScode(DATA_E_FORMATETC); + + if (QWindowsContext::verboseOLE) { + wchar_t buf[256] = {0}; + GetClipboardFormatName(pformatetc->cfFormat, buf, 255); + qDebug("%s CF = %d : %s", __FUNCTION__, pformatetc->cfFormat, qPrintable(QString::fromWCharArray(buf))); + } + + if (data) { + const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); + if (QWindowsMime *converter = mc.converterFromMime(*pformatetc, data)) + if (converter->convertFromMime(*pformatetc, data, pmedium)) + hr = ResultFromScode(S_OK); + } + + if (QWindowsContext::verboseOLE) { + wchar_t buf[256] = {0}; + GetClipboardFormatName(pformatetc->cfFormat, buf, 255); + qDebug("%s CF = %d : %s returns 0x%x", __FUNCTION__, pformatetc->cfFormat, + qPrintable(QString::fromWCharArray(buf)), int(hr)); + } + + return hr; +} + +STDMETHODIMP +QWindowsOleDataObject::GetDataHere(LPFORMATETC, LPSTGMEDIUM) +{ + return ResultFromScode(DATA_E_FORMATETC); +} + +STDMETHODIMP +QWindowsOleDataObject::QueryGetData(LPFORMATETC pformatetc) +{ + HRESULT hr = ResultFromScode(DATA_E_FORMATETC); + + if (QWindowsContext::verboseOLE > 1) + qDebug("%s", __FUNCTION__); + + if (data) { + const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); + hr = mc.converterFromMime(*pformatetc, data) ? + ResultFromScode(S_OK) : ResultFromScode(S_FALSE); + } + if (QWindowsContext::verboseOLE > 1) + qDebug("%s returns 0x%x", __FUNCTION__, int(hr)); + return hr; +} + +STDMETHODIMP +QWindowsOleDataObject::GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC pformatetcOut) +{ + pformatetcOut->ptd = NULL; + return ResultFromScode(E_NOTIMPL); +} + +STDMETHODIMP +QWindowsOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL fRelease) +{ + if (QWindowsContext::verboseOLE > 1) + qDebug("%s", __FUNCTION__); + + HRESULT hr = ResultFromScode(E_NOTIMPL); + + if (pFormatetc->cfFormat == CF_PERFORMEDDROPEFFECT && pMedium->tymed == TYMED_HGLOBAL) { + DWORD * val = (DWORD*)GlobalLock(pMedium->hGlobal); + performedEffect = *val; + GlobalUnlock(pMedium->hGlobal); + if (fRelease) + ReleaseStgMedium(pMedium); + hr = ResultFromScode(S_OK); + } + if (QWindowsContext::verboseOLE > 1) + qDebug("%s returns 0x%x", __FUNCTION__, int(hr)); + return hr; +} + + +STDMETHODIMP +QWindowsOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc) +{ + if (QWindowsContext::verboseOLE > 1) + qDebug("%s", __FUNCTION__); + + if (!data) + return ResultFromScode(DATA_E_FORMATETC); + + SCODE sc = S_OK; + + QVector<FORMATETC> fmtetcs; + if (dwDirection == DATADIR_GET) { + QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); + fmtetcs = mc.allFormatsForMime(data); + } else { + FORMATETC formatetc; + formatetc.cfFormat = CF_PERFORMEDDROPEFFECT; + formatetc.dwAspect = DVASPECT_CONTENT; + formatetc.lindex = -1; + formatetc.ptd = NULL; + formatetc.tymed = TYMED_HGLOBAL; + fmtetcs.append(formatetc); + } + + QWindowsOleEnumFmtEtc *enumFmtEtc = new QWindowsOleEnumFmtEtc(fmtetcs); + *ppenumFormatEtc = enumFmtEtc; + if (enumFmtEtc->isNull()) { + delete enumFmtEtc; + *ppenumFormatEtc = NULL; + sc = E_OUTOFMEMORY; + } + + return ResultFromScode(sc); +} + +STDMETHODIMP +QWindowsOleDataObject::DAdvise(FORMATETC FAR*, DWORD, + LPADVISESINK, DWORD FAR*) +{ + return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); +} + + +STDMETHODIMP +QWindowsOleDataObject::DUnadvise(DWORD) +{ + return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); +} + +STDMETHODIMP +QWindowsOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*) +{ + return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); +} + +/*! + \class QWindowsOleEnumFmtEtc + \brief Enumerates the FORMATETC structures supported by QWindowsOleDataObject. + \ingroup qt-lighthouse-win +*/ + +QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) : + m_dwRefs(1), m_nIndex(0), m_isNull(false) +{ + if (QWindowsContext::verboseOLE > 1) + qDebug("%s", __FUNCTION__); + m_lpfmtetcs.reserve(fmtetcs.count()); + for (int idx = 0; idx < fmtetcs.count(); ++idx) { + LPFORMATETC destetc = new FORMATETC(); + if (copyFormatEtc(destetc, (LPFORMATETC)&(fmtetcs.at(idx)))) { + m_lpfmtetcs.append(destetc); + } else { + m_isNull = true; + delete destetc; + break; + } + } +} + +QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs) : + m_dwRefs(1), m_nIndex(0), m_isNull(false) +{ + if (QWindowsContext::verboseOLE > 1) + qDebug("%s", __FUNCTION__); + m_lpfmtetcs.reserve(lpfmtetcs.count()); + for (int idx = 0; idx < lpfmtetcs.count(); ++idx) { + LPFORMATETC srcetc = lpfmtetcs.at(idx); + LPFORMATETC destetc = new FORMATETC(); + if (copyFormatEtc(destetc, srcetc)) { + m_lpfmtetcs.append(destetc); + } else { + m_isNull = true; + delete destetc; + break; + } + } +} + +QWindowsOleEnumFmtEtc::~QWindowsOleEnumFmtEtc() +{ + LPMALLOC pmalloc; + + if (CoGetMalloc(MEMCTX_TASK, &pmalloc) == NOERROR) { + for (int idx = 0; idx < m_lpfmtetcs.count(); ++idx) { + LPFORMATETC tmpetc = m_lpfmtetcs.at(idx); + if (tmpetc->ptd) + pmalloc->Free(tmpetc->ptd); + delete tmpetc; + } + + pmalloc->Release(); + } + m_lpfmtetcs.clear(); +} + +bool QWindowsOleEnumFmtEtc::isNull() const +{ + return m_isNull; +} + +// IUnknown methods +STDMETHODIMP +QWindowsOleEnumFmtEtc::QueryInterface(REFIID riid, void FAR* FAR* ppvObj) +{ + if (riid == IID_IUnknown || riid == IID_IEnumFORMATETC) { + *ppvObj = this; + AddRef(); + return NOERROR; + } + *ppvObj = NULL; + return ResultFromScode(E_NOINTERFACE); +} + +STDMETHODIMP_(ULONG) +QWindowsOleEnumFmtEtc::AddRef(void) +{ + return ++m_dwRefs; +} + +STDMETHODIMP_(ULONG) +QWindowsOleEnumFmtEtc::Release(void) +{ + if (--m_dwRefs == 0) { + delete this; + return 0; + } + return m_dwRefs; +} + +// IEnumFORMATETC methods +STDMETHODIMP +QWindowsOleEnumFmtEtc::Next(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetched) +{ + ULONG i=0; + ULONG nOffset; + + if (rgelt == NULL) + return ResultFromScode(E_INVALIDARG); + + while (i < celt) { + nOffset = m_nIndex + i; + + if (nOffset < ULONG(m_lpfmtetcs.count())) { + copyFormatEtc((LPFORMATETC)&(rgelt[i]), m_lpfmtetcs.at(nOffset)); + i++; + } else { + break; + } + } + + m_nIndex += (WORD)i; + + if (pceltFetched != NULL) + *pceltFetched = i; + + if (i != celt) + return ResultFromScode(S_FALSE); + + return NOERROR; +} + +STDMETHODIMP +QWindowsOleEnumFmtEtc::Skip(ULONG celt) +{ + ULONG i=0; + ULONG nOffset; + + while (i < celt) { + nOffset = m_nIndex + i; + + if (nOffset < ULONG(m_lpfmtetcs.count())) { + i++; + } else { + break; + } + } + + m_nIndex += (WORD)i; + + if (i != celt) + return ResultFromScode(S_FALSE); + + return NOERROR; +} + +STDMETHODIMP +QWindowsOleEnumFmtEtc::Reset() +{ + m_nIndex = 0; + return NOERROR; +} + +STDMETHODIMP +QWindowsOleEnumFmtEtc::Clone(LPENUMFORMATETC FAR* newEnum) +{ + if (newEnum == NULL) + return ResultFromScode(E_INVALIDARG); + + QWindowsOleEnumFmtEtc *result = new QWindowsOleEnumFmtEtc(m_lpfmtetcs); + result->m_nIndex = m_nIndex; + + if (result->isNull()) { + delete result; + return ResultFromScode(E_OUTOFMEMORY); + } else { + *newEnum = result; + } + + return NOERROR; +} + +bool QWindowsOleEnumFmtEtc::copyFormatEtc(LPFORMATETC dest, LPFORMATETC src) const +{ + if (dest == NULL || src == NULL) + return false; + + *dest = *src; + + if (src->ptd) { + LPVOID pout; + LPMALLOC pmalloc; + + if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) + return false; + + pout = (LPVOID)pmalloc->Alloc(src->ptd->tdSize); + memcpy(dest->ptd, src->ptd, size_t(src->ptd->tdSize)); + + pmalloc->Release(); + } + + return true; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsole.h b/src/plugins/platforms/windows/qwindowsole.h new file mode 100644 index 0000000000..d979af3b31 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsole.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSOLE_H +#define QWINDOWSOLE_H + +#include "qtwindows_additional.h" + +#include <QtCore/QObject> +#include <QtCore/QMap> +#include <QtCore/QPoint> +#include <QtCore/QPointer> +#include <QtCore/QVector> +#include <QtCore/QRect> + +#include <objidl.h> + +QT_BEGIN_NAMESPACE + +class QMimeData; +class QWindow; + +class QWindowsOleDataObject : public IDataObject +{ +public: + explicit QWindowsOleDataObject(QMimeData *mimeData); + virtual ~QWindowsOleDataObject(); + + void releaseQt(); + QMimeData *mimeData() const; + DWORD reportedPerformedEffect() const; + + // IUnknown methods + STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); + STDMETHOD_(ULONG,AddRef)(void); + STDMETHOD_(ULONG,Release)(void); + + // IDataObject methods + STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium); + STDMETHOD(GetDataHere)(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium); + STDMETHOD(QueryGetData)(LPFORMATETC pformatetc); + STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut); + STDMETHOD(SetData)(LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium, + BOOL fRelease); + STDMETHOD(EnumFormatEtc)(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc); + STDMETHOD(DAdvise)(FORMATETC FAR* pFormatetc, DWORD advf, + LPADVISESINK pAdvSink, DWORD FAR* pdwConnection); + STDMETHOD(DUnadvise)(DWORD dwConnection); + STDMETHOD(EnumDAdvise)(LPENUMSTATDATA FAR* ppenumAdvise); + +private: + ULONG m_refs; + QPointer<QMimeData> data; + int CF_PERFORMEDDROPEFFECT; + DWORD performedEffect; +}; + +class QWindowsOleEnumFmtEtc : public IEnumFORMATETC +{ +public: + explicit QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs); + explicit QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs); + virtual ~QWindowsOleEnumFmtEtc(); + + bool isNull() const; + + // IUnknown methods + STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); + STDMETHOD_(ULONG,AddRef)(void); + STDMETHOD_(ULONG,Release)(void); + + // IEnumFORMATETC methods + STDMETHOD(Next)(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetched); + STDMETHOD(Skip)(ULONG celt); + STDMETHOD(Reset)(void); + STDMETHOD(Clone)(LPENUMFORMATETC FAR* newEnum); + +private: + bool copyFormatEtc(LPFORMATETC dest, LPFORMATETC src) const; + + ULONG m_dwRefs; + ULONG m_nIndex; + QVector<LPFORMATETC> m_lpfmtetcs; + bool m_isNull; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSOLE_H diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp new file mode 100644 index 0000000000..3de508a1c7 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsscreen.h" +#include "qwindowscontext.h" +#include "qwindowswindow.h" +#include "pixmaputils.h" +#include "qwindowscursor.h" + +#include "qtwindows_additional.h" + +#include <QtGui/QPixmap> +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +typedef QPair<int, int> DPI; + +QWindowsScreenData::QWindowsScreenData() : + dpi(96, 96), + depth(32), + format(QImage::Format_ARGB32_Premultiplied), primary(false) +{ +} + +static inline DPI deviceDPI(HDC hdc) +{ + return DPI(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY)); +} + +static inline QSize deviceSizeMM(const QSize &pixels, const DPI &dpi) +{ + const qreal inchToMM = 25.4; + const qreal h = qreal(pixels.width()) / qreal(dpi.first) * inchToMM; + const qreal v = qreal(pixels.height()) / qreal(dpi.second) * inchToMM; + return QSize(qRound(h), qRound(v)); +} + +static inline DPI deviceDPI(const QSize &pixels, const QSize &physicalSizeMM) +{ + const qreal inchToMM = 25.4; + const qreal h = qreal(pixels.width()) / (qreal(physicalSizeMM.width()) / inchToMM); + const qreal v = qreal(pixels.height()) / (qreal(physicalSizeMM.height()) / inchToMM); + return DPI(qRound(v), qRound(h)); +} + +typedef QList<QWindowsScreenData> WindowsScreenDataList; + +// from QDesktopWidget, taking WindowsScreenDataList as LPARAM +BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) +{ + MONITORINFOEX info; + memset(&info, 0, sizeof(MONITORINFOEX)); + info.cbSize = sizeof(MONITORINFOEX); + if (GetMonitorInfo(hMonitor, &info) == FALSE) + return TRUE; + + WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p); + QWindowsScreenData data; + data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); + if (HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL)) { + data.dpi = deviceDPI(hdc); + DeleteDC(hdc); + } else { + qWarning("%s: Unable to obtain handle for monitor '%s', defaulting to %d DPI.", + __FUNCTION__, qPrintable(QString::fromWCharArray(info.szDevice)), + data.dpi.first); + } + data.physicalSizeMM = deviceSizeMM(data.geometry.size(), data.dpi); + data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); + data.availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1)); + data.primary = (info.dwFlags & MONITORINFOF_PRIMARY) != 0; + result->append(data); + return TRUE; +} + +/*! + \class QWindowsScreen + \brief Windows screen. + \ingroup qt-lighthouse-win +*/ + +QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) : + m_data(data), m_cursor(this) +{ +} + +QList<QPlatformScreen *> QWindowsScreen::screens() +{ + // Retrieve monitors and add static depth information to each. + WindowsScreenDataList data; + EnumDisplayMonitors(0, 0, monitorEnumCallback, (LPARAM)&data); + + const int depth = QWindowsContext::instance()->screenDepth(); + const QImage::Format format = depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; + QList<QPlatformScreen *> result; + + const WindowsScreenDataList::const_iterator scend = data.constEnd(); + for (WindowsScreenDataList::const_iterator it = data.constBegin(); it != scend; ++it) { + QWindowsScreenData d = *it; + d.depth = depth; + d.format = format; + if (QWindowsContext::verboseIntegration) + qDebug() << "Screen" << d.geometry << d.availableGeometry << d.primary + << " physical " << d.physicalSizeMM << " DPI" << d.dpi + << "Depth: " << d.depth << " Format: " << d.format; + result.append(new QWindowsScreen(d)); + } + return result; +} + +QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int height) const +{ + if (QWindowsContext::verboseIntegration) + qDebug() << __FUNCTION__ << window << x << y << width << height; + RECT r; + HWND hwnd = (HWND)window; + GetClientRect(hwnd, &r); + + if (width < 0) width = r.right - r.left; + if (height < 0) height = r.bottom - r.top; + + // Create and setup bitmap + HDC display_dc = GetDC(0); + HDC bitmap_dc = CreateCompatibleDC(display_dc); + HBITMAP bitmap = CreateCompatibleBitmap(display_dc, width, height); + HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap); + + // copy data + HDC window_dc = GetDC(hwnd); + BitBlt(bitmap_dc, 0, 0, width, height, window_dc, x, y, SRCCOPY | CAPTUREBLT); + + // clean up all but bitmap + ReleaseDC(hwnd, window_dc); + SelectObject(bitmap_dc, null_bitmap); + DeleteDC(bitmap_dc); + + const QPixmap pixmap = qPixmapFromWinHBITMAP(bitmap, HBitmapNoAlpha); + + DeleteObject(bitmap); + ReleaseDC(0, display_dc); + + return pixmap; +} + +/*! + \brief Find a top level window taking the flags of ChildWindowFromPointEx. +*/ + +QWindow *QWindowsScreen::findTopLevelAt(const QPoint &point, unsigned flags) +{ + QWindow* result = 0; + if (QPlatformWindow *bw = QWindowsContext::instance()-> + findPlatformWindowAt(GetDesktopWindow(), point, flags)) + result = QWindowsWindow::topLevelOf(bw->window()); + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << point << flags << result; + return result; +} + +QWindow *QWindowsScreen::windowAt(const QPoint &screenPoint, unsigned flags) +{ + QWindow* result = 0; + if (QPlatformWindow *bw = QWindowsContext::instance()-> + findPlatformWindowAt(GetDesktopWindow(), screenPoint, flags)) + result = bw->window(); + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << screenPoint << " returns " << result; + return result; +} + +QWindow *QWindowsScreen::windowUnderMouse(unsigned flags) +{ + return QWindowsScreen::windowAt(QWindowsCursor::mousePosition(), flags); +} + +QWindowsScreen *QWindowsScreen::screenOf(const QWindow *w) +{ + if (w) + if (const QScreen *s = w->screen()) + if (QPlatformScreen *pscr = s->handle()) + return static_cast<QWindowsScreen *>(pscr); + if (const QScreen *ps = QGuiApplication::primaryScreen()) + if (QPlatformScreen *ppscr = ps->handle()) + return static_cast<QWindowsScreen *>(ppscr); + return 0; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h new file mode 100644 index 0000000000..e24af7af09 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSSCREEN_H +#define QWINDOWSSCREEN_H + +#include "qwindowscursor.h" + +#include <QtCore/QList> +#include <QtCore/QPair> +#include <QtGui/QPlatformScreen> + +QT_BEGIN_NAMESPACE + +struct QWindowsScreenData +{ + QWindowsScreenData(); + + QRect geometry; + QRect availableGeometry; + QPair<int, int> dpi; + QSize physicalSizeMM; + int depth; + QImage::Format format; + bool primary; +}; + +class QWindowsScreen : public QPlatformScreen +{ +public: + explicit QWindowsScreen(const QWindowsScreenData &data); + + static QWindowsScreen *screenOf(const QWindow *w = 0); + + virtual QRect geometry() const { return m_data.geometry; } + virtual QRect availableGeometry() const { return m_data.availableGeometry; } + virtual int depth() const { return m_data.depth; } + virtual QImage::Format format() const { return m_data.format; } + virtual QSize physicalSize() const { return m_data.physicalSizeMM; } + + virtual QWindow *topLevelAt(const QPoint &point) const + { return QWindowsScreen::findTopLevelAt(point, CWP_SKIPINVISIBLE); } + + static QWindow *findTopLevelAt(const QPoint &point, unsigned flags); + static QWindow *windowAt(const QPoint &point, unsigned flags = CWP_SKIPINVISIBLE); + static QWindow *windowUnderMouse(unsigned flags = CWP_SKIPINVISIBLE); + + static QList<QPlatformScreen *> screens(); + + virtual QPixmap grabWindow(WId window, int x, int y, int width, int height) const; + + const QWindowsCursor &cursor() const { return m_cursor; } + QWindowsCursor &cursor() { return m_cursor; } + +private: + const QWindowsScreenData m_data; + QWindowsCursor m_cursor; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSSCREEN_H diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp new file mode 100644 index 0000000000..8e10ae694a --- /dev/null +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -0,0 +1,1317 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowswindow.h" +#include "qwindowsnativeimage.h" +#include "qwindowscontext.h" +#include "qwindowsdrag.h" +#include "qwindowsscreen.h" +#include "qwindowscursor.h" + +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> +#include <QtGui/QWindow> +#include <QtGui/QWindowSystemInterface> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +static QByteArray debugWinStyle(DWORD style) +{ + + QByteArray rc = "0x"; + rc += QByteArray::number(qulonglong(style), 16); + if (style & WS_POPUP) + rc += " WS_POPUP"; + if (style & WS_CHILD) + rc += " WS_CHILD"; + if (style & WS_OVERLAPPED) + rc += " WS_OVERLAPPED"; + if (style & WS_CLIPSIBLINGS) + rc += " WS_CLIPSIBLINGS"; + if (style & WS_CLIPCHILDREN) + rc += " WS_CLIPCHILDREN"; + if (style & WS_THICKFRAME) + rc += " WS_THICKFRAME"; + if (style & WS_DLGFRAME) + rc += " WS_DLGFRAME"; + if (style & WS_SYSMENU) + rc += " WS_SYSMENU"; + if (style & WS_MINIMIZEBOX) + rc += " WS_MINIMIZEBOX"; + if (style & WS_MAXIMIZEBOX) + rc += " WS_MAXIMIZEBOX"; + return rc; +} + +static QByteArray debugWindowStates(Qt::WindowStates s) +{ + + QByteArray rc = "0x"; + rc += QByteArray::number(int(s), 16); + if (s & Qt::WindowMinimized) + rc += " WindowMinimized"; + if (s & Qt::WindowMaximized) + rc += " WindowMaximized"; + if (s & Qt::WindowFullScreen) + rc += " WindowFullScreen"; + if (s & Qt::WindowActive) + rc += " WindowActive"; + return rc; +} + +QDebug operator<<(QDebug d, const MINMAXINFO &i) +{ + d.nospace() << "MINMAXINFO maxSize=" << i.ptMaxSize.x << ',' + << i.ptMaxSize.y << " maxpos=" << i.ptMaxPosition.x + << ',' << i.ptMaxPosition.y << " mintrack=" + << i.ptMinTrackSize.x << ',' << i.ptMinTrackSize.y + << " maxtrack=" << i.ptMaxTrackSize.x << ',' + << i.ptMaxTrackSize.y; + return d; +} + +static inline QSize qSizeOfRect(const RECT &rect) +{ + return QSize(rect.right -rect.left, rect.bottom - rect.top); +} + +static inline QRect qrectFromRECT(const RECT &rect) +{ + return QRect(QPoint(rect.left, rect.top), qSizeOfRect(rect)); +} + +QDebug operator<<(QDebug d, const RECT &r) +{ + d.nospace() << "RECT: left/top=" << r.left << ',' << r.top + << " right/bottom=" << r.right << ',' << r.bottom; + return d; +} + +QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p) +{ + qDebug().nospace() << "NCCALCSIZE_PARAMS " + << qrectFromRECT(p.rgrc[0]) + << ' ' << qrectFromRECT(p.rgrc[1]) << ' ' + << qrectFromRECT(p.rgrc[2]); + return d; +} + +static inline QRect frameGeometry(HWND hwnd) +{ + RECT rect = { 0, 0, 0, 0 }; + GetWindowRect(hwnd, &rect); + return qrectFromRECT(rect); +} + +QSize clientSize(HWND hwnd) +{ + RECT rect = { 0, 0, 0, 0 }; + GetClientRect(hwnd, &rect); // Always returns point 0,0, thus unusable for geometry. + return qSizeOfRect(rect); +} + +// from qwidget_win.cpp/maximum layout size check removed. +static bool shouldShowMaximizeButton(Qt::WindowFlags flags) +{ + if (flags & Qt::MSWindowsFixedSizeDialogHint) + return false; + // if the user explicitly asked for the maximize button, we try to add + // it even if the window has fixed size. + if (flags & Qt::CustomizeWindowHint && + flags & Qt::WindowMaximizeButtonHint) + return true; + return flags & Qt::WindowMaximizeButtonHint; +} + +/*! + \class WindowCreationData + \brief Window creation code. + + This struct gathers all information required to create a window. + Window creation is split in 3 steps: + + \list + \o fromWindow() Gather all required information + \o create() Create the system handle. + \o initialize() Post creation initialization steps. + \endlist + + The reason for this split is to also enable changing the QWindowFlags + by calling: + + \list + \o fromWindow() Gather information and determine new system styles + \o applyWindowFlags() to apply the new window system styles. + \o initialize() Post creation initialization steps. + \endlist + + Contains the window creation code formerly in qwidget_win.cpp. + + \sa QWindowCreationContext + \ingroup qt-lighthouse-win +*/ + +struct WindowCreationData +{ + typedef QWindowsWindow::WindowData WindowData; + + WindowCreationData() : parentHandle(0), type(Qt::Widget), style(0), exStyle(0), + topLevel(false), popup(false), dialog(false), desktop(false), + tool(false) {} + + void fromWindow(const QWindow *w, const Qt::WindowFlags flags, bool isGL); + inline WindowData create(const QWindow *w, const QRect &geometry, QString title) const; + inline void applyWindowFlags(HWND hwnd) const; + void initialize(HWND h, bool frameChange) const; + + Qt::WindowFlags flags; + HWND parentHandle; + Qt::WindowType type; + unsigned style; + unsigned exStyle; + bool isGL; + bool topLevel; + bool popup; + bool dialog; + bool desktop; + bool tool; +}; + +QDebug operator<<(QDebug debug, const WindowCreationData &d) +{ + debug.nospace() << QWindowsWindow::debugWindowFlags(d.flags) + << " gs=" << d.isGL << " topLevel=" << d.topLevel << " popup=" + << d.popup << " dialog=" << d.dialog << " desktop=" << d.desktop + << " tool=" << d.tool << " style=" << debugWinStyle(d.style) + << " exStyle=0x" << QString::number(d.exStyle, 16) + << " parent=" << d.parentHandle; + return debug; +} + +void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn, + bool isGLin) +{ + isGL = isGLin; + flags = flagsIn; + topLevel = w->isTopLevel(); + + if (topLevel && flags == 1) { + qWarning("Remove me: fixing toplevel window flags"); + flags |= Qt::WindowTitleHint|Qt::WindowSystemMenuHint|Qt::WindowMinimizeButtonHint + |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint; + } + + type = static_cast<Qt::WindowType>(int(flags) & Qt::WindowType_Mask); + switch (type) { + case Qt::Dialog: + case Qt::Sheet: + dialog = true; + break; + case Qt::Drawer: + case Qt::Tool: + tool = true; + break; + case Qt::Popup: + popup = true; + break; + case Qt::Desktop: + desktop = true; + break; + default: + break; + } + if ((flags & Qt::MSWindowsFixedSizeDialogHint)) + dialog = true; + + // Parent: Use transient parent for top levels. + if (popup) { + flags |= Qt::WindowStaysOnTopHint; // a popup stays on top, no parent. + } else { + if (const QWindow *parentWindow = topLevel ? w->transientParent() : w->parent()) + parentHandle = QWindowsWindow::handleOf(parentWindow); + } + + if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) { + style = WS_POPUP; + } else if (topLevel && !desktop) { + if (flags & Qt::FramelessWindowHint) + style = WS_POPUP; // no border + else if (flags & Qt::WindowTitleHint) + style = WS_OVERLAPPED; + else + style = 0; + } else { + style = WS_CHILD; + } + + if (!desktop) { + // if (!testAttribute(Qt::WA_PaintUnclipped)) + // ### Commented out for now as it causes some problems, but + // this should be correct anyway, so dig some more into this +#ifdef Q_FLATTEN_EXPOSE + if (isGL) + style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // see SetPixelFormat +#else + style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ; +#endif + if (topLevel) { + if ((type == Qt::Window || dialog || tool)) { + if (!(flags & Qt::FramelessWindowHint)) { + style |= WS_POPUP; + if (flags & Qt::MSWindowsFixedSizeDialogHint) { + style |= WS_DLGFRAME; + } else { + style |= WS_THICKFRAME; + } + } + if (flags & Qt::WindowTitleHint) + style |= WS_CAPTION; + if (flags & Qt::WindowSystemMenuHint) + style |= WS_SYSMENU; + if (flags & Qt::WindowMinimizeButtonHint) + style |= WS_MINIMIZEBOX; + if (shouldShowMaximizeButton(flags)) + style |= WS_MAXIMIZEBOX; + if (tool) + exStyle |= WS_EX_TOOLWINDOW; + if (flags & Qt::WindowContextHelpButtonHint) + exStyle |= WS_EX_CONTEXTHELP; + } else { + exStyle |= WS_EX_TOOLWINDOW; + } + } + } +} + +QWindowsWindow::WindowData + WindowCreationData::create(const QWindow *w, const QRect &geometry, QString title) const +{ + typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr; + + WindowData result; + result.flags = flags; + + if (desktop) { // desktop widget. No frame, hopefully? + result.hwnd = GetDesktopWindow(); + result.geometry = frameGeometry(result.hwnd); + if (QWindowsContext::verboseWindows) + qDebug().nospace() << "Created desktop window " << w << result.hwnd; + return result; + } + + const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0); + + const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL); + + if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) + title = topLevel ? qAppName() : w->objectName(); + + const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16()); + const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16()); + + // Capture events before CreateWindowEx() returns. + const QWindowCreationContextPtr context(new QWindowCreationContext(w, geometry, style, exStyle)); + QWindowsContext::instance()->setWindowCreationContext(context); + + if (QWindowsContext::verboseWindows) + qDebug().nospace() + << "CreateWindowEx: " << w << *this + << " class=" <<windowClassName << " title=" << title + << "\nrequested: " << geometry << ": " + << context->frameWidth << 'x' << context->frameHeight + << '+' << context->frameX << '+' << context->frameY; + + result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16, + style, + context->frameX, context->frameY, + context->frameWidth, context->frameHeight, + parentHandle, NULL, appinst, NULL); + QWindowsContext::instance()->setWindowCreationContext(QWindowCreationContextPtr()); + if (QWindowsContext::verboseWindows) + qDebug().nospace() + << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: " + << context->obtainedGeometry << context->margins; + + if (!result.hwnd) { + qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__); + return result; + } + + result.geometry = context->obtainedGeometry; + result.frame = context->margins; + return result; +} + +void WindowCreationData::applyWindowFlags(HWND hwnd) const +{ + // Keep enabled and visible from the current style. + const LONG_PTR oldStyle = GetWindowLongPtr(hwnd, GWL_STYLE); + const LONG_PTR oldExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE); + + const LONG_PTR newStyle = style | (oldStyle & (WS_DISABLED|WS_VISIBLE)); + if (oldStyle != newStyle) + SetWindowLongPtr(hwnd, GWL_STYLE, newStyle); + const LONG_PTR newExStyle = exStyle; + if (newExStyle != oldExStyle) + SetWindowLongPtr(hwnd, GWL_EXSTYLE, newExStyle); + if (QWindowsContext::verboseWindows) + qDebug().nospace() << __FUNCTION__ << hwnd << *this + << "\n Style from " << debugWinStyle(oldStyle) << "\n to " + << debugWinStyle(newStyle) << "\n ExStyle from 0x" + << QByteArray::number(qulonglong(oldExStyle), 16) << " to 0x" + << QByteArray::number(qulonglong(newExStyle), 16); +} + +void WindowCreationData::initialize(HWND hwnd, bool frameChange) const +{ + if (desktop || !hwnd) + return; + UINT flags = SWP_NOMOVE | SWP_NOSIZE; + if (frameChange) + flags |= SWP_FRAMECHANGED; + if (topLevel) { + flags |= SWP_NOACTIVATE; + if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) { + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, flags); + if (flags & Qt::WindowStaysOnBottomHint) + qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time"; + } else if (flags & Qt::WindowStaysOnBottomHint) { + SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, flags); + } + if (flags & (Qt::CustomizeWindowHint|Qt::WindowTitleHint)) { + HMENU systemMenu = GetSystemMenu(hwnd, FALSE); + if (flags & Qt::WindowCloseButtonHint) + EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED); + else + EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED); + } + } else { // child. + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags); + } +} + +/*! + \class QWindowsGeometryHint + \brief Stores geometry constraints and provides utility functions. + + Geometry constraints ready to apply to a MINMAXINFO taking frame + into account. + + \ingroup qt-lighthouse-win +*/ + +#define QWINDOWSIZE_MAX ((1<<24)-1) + +QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w) : + minimumSize(w->minimumSize()), + maximumSize(w->maximumSize()) +{ +} + +bool QWindowsGeometryHint::validSize(const QSize &s) const +{ + const int width = s.width(); + const int height = s.height(); + return width >= minimumSize.width() && width <= maximumSize.width() + && height >= minimumSize.height() && height <= maximumSize.height(); +} + +QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle) +{ + RECT rect = {0,0,0,0}; + style &= ~(WS_OVERLAPPED); // Not permitted, see docs. + if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle)) + qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__); + const QMargins result(qAbs(rect.left), qAbs(rect.top), + qAbs(rect.right), qAbs(rect.bottom)); + if (QWindowsContext::verboseWindows) + qDebug().nospace() << __FUNCTION__ << " style= 0x" + << QString::number(style, 16) + << " exStyle=0x" << QString::number(exStyle, 16) << ' ' << rect << ' ' << result; + + return result; +} + +void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const +{ + return applyToMinMaxInfo(GetWindowLong(hwnd, GWL_STYLE), + GetWindowLong(hwnd, GWL_EXSTYLE), mmi); +} + +void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const +{ + if (QWindowsContext::verboseWindows) + qDebug().nospace() << '>' << __FUNCTION__ << '<' << " min=" + << minimumSize.width() << ',' << minimumSize.height() + << " max=" << maximumSize.width() << ',' << maximumSize.height() + << " in " << *mmi; + + const QMargins margins = QWindowsGeometryHint::frame(style, exStyle); + const int frameWidth = margins.left() + margins.right(); + const int frameHeight = margins.top() + margins.bottom(); + if (minimumSize.width() > 0) + mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth; + if (minimumSize.height() > 0) + mmi->ptMinTrackSize.y = minimumSize.height() + frameHeight; + + const int maximumWidth = qMax(maximumSize.width(), minimumSize.width()); + const int maximumHeight = qMax(maximumSize.height(), minimumSize.height()); + if (maximumWidth < QWINDOWSIZE_MAX) + mmi->ptMaxTrackSize.x = maximumWidth + frameWidth; + // windows with title bar have an implicit size limit of 112 pixels + if (maximumHeight < QWINDOWSIZE_MAX) + mmi->ptMaxTrackSize.y = qMax(maximumHeight + frameHeight, 112); + if (QWindowsContext::verboseWindows) + qDebug().nospace() << '<' << __FUNCTION__ + << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight + << " out " << *mmi; +} + +/*! + \class QWindowCreationContext + \brief Active Context for creating windows. + + There is a phase in window creation (WindowCreationData::create()) + in which events are sent before the system API CreateWindowEx() returns + the handle. These cannot be handled by the platform window as the association + of the unknown handle value to the window does not exist yet and as not + to trigger recursive handle creation, etc. + + In that phase, an instance of QWindowCreationContext is set on + QWindowsContext. + + QWindowCreationContext stores the information to answer the initial + WM_GETMINMAXINFO and obtains the corrected size/position. + + \sa WindowCreationData, QWindowsContext + \ingroup qt-lighthouse-win +*/ + +QWindowCreationContext::QWindowCreationContext(const QWindow *w, + const QRect &geometry, + DWORD style_, DWORD exStyle_) : + geometryHint(w), style(style_), exStyle(exStyle_), + requestedGeometry(geometry), obtainedGeometry(geometry), + margins(QWindowsGeometryHint::frame(style, exStyle)), + frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT), + frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT) +{ + // Geometry of toplevels does not consider window frames. + // TODO: No concept of WA_wasMoved yet that would indicate a + // CW_USEDEFAULT unless set. For now, assume that 0,0 means 'default' + // for toplevels. + if (geometry.isValid()) { + if (!w->isTopLevel() || geometry.y() >= margins.top()) { + frameX = geometry.x() - margins.left(); + frameY = geometry.y() - margins.top(); + } + frameWidth = geometry.width() + margins.left() + margins.right(); + frameHeight = geometry.height() + margins.top() + margins.bottom(); + } + if (QWindowsContext::verboseWindows) + qDebug().nospace() + << __FUNCTION__ << ' ' << w << " min" << geometryHint.minimumSize + << " min" << geometryHint.maximumSize; +} + +/*! + \class QWindowsBaseWindow + \brief Raster or OpenGL Window. + + \list + \o Raster type: handleWmPaint() is implemented to + to bitblt the image. The DC can be accessed + via getDC/Relase DC, which has a special handling + when within a paint event (in that case, the DC obtained + from BeginPaint() is returned). + + \o Open GL: The first time QWindowsGLContext accesses + the handle, it sets up the pixelformat on the DC + which in turn sets it on the window (see flag + PixelFormatInitialized). + handleWmPaint() is empty (although required). + \endlist + + \ingroup qt-lighthouse-win +*/ + +QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : + QPlatformWindow(aWindow), + m_data(data), + m_flags(0), + m_hdc(0), + m_windowState(aWindow->windowState()), + m_opacity(1.0), + m_mouseGrab(false), + m_cursor(QWindowsScreen::screenOf(aWindow)->cursor().standardWindowCursor()), + m_dropTarget(0) +{ + if (aWindow->surfaceType() == QWindow::OpenGLSurface) + setFlag(OpenGL_Surface); + QWindowsContext::instance()->addWindow(m_data.hwnd, this); + if (aWindow->isTopLevel()) { + switch (aWindow->windowType()) { + case Qt::Window: + case Qt::Dialog: + case Qt::Sheet: + case Qt::Drawer: + case Qt::Popup: + case Qt::Tool: + registerDropSite(); + break; + default: + break; + } + } +} + +QWindowsWindow::~QWindowsWindow() +{ + destroyWindow(); +} + +void QWindowsWindow::destroyWindow() +{ + if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window() << m_data.hwnd; + if (m_data.hwnd) { + unregisterDropSite(); + if (m_data.hwnd != GetDesktopWindow()) + DestroyWindow(m_data.hwnd); + QWindowsContext::instance()->removeWindow(m_data.hwnd); + m_data.hwnd = 0; + } +} + +void QWindowsWindow::registerDropSite() +{ + if (m_data.hwnd && !m_dropTarget) { + m_dropTarget = new QWindowsOleDropTarget(window()); + RegisterDragDrop(m_data.hwnd, m_dropTarget); + CoLockObjectExternal(m_dropTarget, true, true); + } +} + +void QWindowsWindow::unregisterDropSite() +{ + if (m_data.hwnd && m_dropTarget) { + m_dropTarget->Release(); + CoLockObjectExternal(m_dropTarget, false, true); + RevokeDragDrop(m_data.hwnd); + m_dropTarget = 0; + } +} + +QWindow *QWindowsWindow::topLevelOf(QWindow *w) +{ + while (QWindow *parent = w->parent()) + w = parent; + return w; +} + +QWindowsWindow::WindowData + QWindowsWindow::WindowData::create(const QWindow *w, + const WindowData ¶meters, + const QString &title, + bool isGL) +{ + WindowCreationData creationData; + creationData.fromWindow(w, parameters.flags, isGL); + WindowData result = creationData.create(w, parameters.geometry, title); + creationData.initialize(result.hwnd, false); + return result; +} + +void QWindowsWindow::setVisible(bool visible) +{ + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window() << m_data.hwnd << visible; + if (m_data.hwnd) { + if (visible) { + show_sys(); + } else { + hide_sys(); + } + } +} + +bool QWindowsWindow::isVisible() const +{ + return m_data.hwnd && IsWindowVisible(m_data.hwnd); +} + +// partially from QWidgetPrivate::show_sys() +void QWindowsWindow::show_sys() const +{ + int sm = SW_SHOWNORMAL; + bool fakedMaximize = false; + const QWindow *w = window(); + const Qt::WindowFlags flags = w->windowFlags(); + const Qt::WindowType type = w->windowType(); + if (w->isTopLevel()) { + const Qt::WindowState state = w->windowState(); + if (state & Qt::WindowMinimized) { + sm = SW_SHOWMINIMIZED; + if (!isVisible()) + sm = SW_SHOWMINNOACTIVE; + } else if (state & Qt::WindowMaximized) { + sm = SW_SHOWMAXIMIZED; + // Windows will not behave correctly when we try to maximize a window which does not + // have minimize nor maximize buttons in the window frame. Windows would then ignore + // non-available geometry, and rather maximize the widget to the full screen, minus the + // window frame (caption). So, we do a trick here, by adding a maximize button before + // maximizing the widget, and then remove the maximize button afterwards. + if (flags & Qt::WindowTitleHint && + !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) { + fakedMaximize = TRUE; + setStyle(style() | WS_MAXIMIZEBOX); + } + } + } + if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool) + sm = SW_SHOWNOACTIVATE; + + ShowWindow(m_data.hwnd, sm); + + if (fakedMaximize) { + setStyle(style() & ~WS_MAXIMIZEBOX); + SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER + | SWP_FRAMECHANGED); + } +} + +// partially from QWidgetPrivate::hide_sys() +void QWindowsWindow::hide_sys() const +{ + const Qt::WindowFlags flags = window()->windowFlags(); + if (flags != Qt::Desktop) { + if (flags & Qt::Popup) + ShowWindow(m_data.hwnd, SW_HIDE); + else + SetWindowPos(m_data.hwnd,0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER); + } +} + +void QWindowsWindow::setParent(const QPlatformWindow *newParent) +{ + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << window() << newParent; + + if (newParent != parent() && m_data.hwnd) + setParent_sys(newParent); +} + +void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const +{ + HWND parentHWND = 0; + if (parent) { + const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent); + parentHWND = parentW->handle(); + } + SetParent(m_data.hwnd, parentHWND); +} + +void QWindowsWindow::handleShown() +{ + QWindowSystemInterface::handleMapEvent(window()); +} + +void QWindowsWindow::handleHidden() +{ + QWindowSystemInterface::handleUnmapEvent(window()); +} + +void QWindowsWindow::setGeometry(const QRect &rect) +{ + const QSize oldSize = m_data.geometry.size(); + m_data.geometry = rect; + const QSize newSize = rect.size(); + // Check on hint. + if (newSize != oldSize) { + const QWindowsGeometryHint hint(window()); + if (!hint.validSize(newSize)) { + qWarning("%s: Attempt to set a size (%dx%d) violating the constraints" + "(%dx%d - %dx%d) on window '%s'.", __FUNCTION__, + newSize.width(), newSize.height(), + hint.minimumSize.width(), hint.minimumSize.height(), + hint.maximumSize.width(), hint.maximumSize.height(), + qPrintable(window()->objectName())); + } + } + if (m_data.hwnd) { + // A ResizeEvent with resulting geometry will be sent. If we cannot + // achieve that size (for example, window title minimal constraint), + // notify and warn. + setGeometry_sys(rect); + if (m_data.geometry != rect) { + qWarning("%s: Unable to set geometry %dx%d+%d+%d on '%s'." + " Resulting geometry: %dx%d+%d+%d.", + __FUNCTION__, + rect.width(), rect.height(), rect.x(), rect.y(), + qPrintable(window()->objectName()), + m_data.geometry.width(), m_data.geometry.height(), + m_data.geometry.x(), m_data.geometry.y()); + } + } else { + QPlatformWindow::setGeometry(rect); + } +} + +void QWindowsWindow::handleMoved() +{ + if (!IsIconic(m_data.hwnd)) // Minimize can send nonsensical move events. + handleGeometryChange(); +} + +void QWindowsWindow::handleResized(int wParam) +{ + switch (wParam) { + case SIZE_MAXHIDE: // Some other window affected. + case SIZE_MAXSHOW: + return; + case SIZE_MINIMIZED: + handleWindowStateChange(Qt::WindowMinimized); + return; + case SIZE_MAXIMIZED: + handleWindowStateChange(Qt::WindowMaximized); + handleGeometryChange(); + break; + case SIZE_RESTORED: + if (m_windowState != Qt::WindowNoState) + handleWindowStateChange(Qt::WindowNoState); + handleGeometryChange(); + break; + } +} + +void QWindowsWindow::handleGeometryChange() +{ + m_data.geometry = geometry_sys(); + QPlatformWindow::setGeometry(m_data.geometry); + QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); + + if (QWindowsContext::verboseEvents || QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window() << m_data.geometry; +} + +void QWindowsWindow::setGeometry_sys(const QRect &rect) const +{ + const QRect frameGeometry = rect + frameMargins(); + + if (QWindowsContext::verboseWindows) + qDebug() << '>' << __FUNCTION__ << this << window() + << " \n from " << geometry_sys() << " to " <<rect + << " new frame: " << frameGeometry; + + const bool rc = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(), + frameGeometry.width(), frameGeometry.height(), true); + if (QWindowsContext::verboseWindows) + qDebug() << '<' << __FUNCTION__ << this << window() + << " \n resulting " << rc << geometry_sys(); +} + +QRect QWindowsWindow::geometry_sys() const +{ + // Warning: Returns bogus values when minimized. + return frameGeometry(m_data.hwnd) - frameMargins(); +} + +/*! + Allocates a HDC for the window or returns the temporary one + obtained from WinAPI BeginPaint within a WM_PAINT event. + + \sa releaseDC() +*/ + +HDC QWindowsWindow::getDC() +{ + if (!m_hdc) + m_hdc = GetDC(handle()); + return m_hdc; +} + +/*! + Relases the HDC for the window or does nothing in + case it was obtained from WinAPI BeginPaint within a WM_PAINT event. + + \sa getDC() +*/ + +void QWindowsWindow::releaseDC() +{ + if (m_hdc && !testFlag(WithinWmPaint)) { + ReleaseDC(handle(), m_hdc); + m_hdc = 0; + } +} + +void QWindowsWindow::handleWmPaint(HWND hwnd, UINT, + WPARAM, LPARAM) +{ + PAINTSTRUCT ps; + if (testFlag(OpenGL_Surface)) { + BeginPaint(hwnd, &ps); // WM_ERASEBKGND needs to be handled. + EndPaint(hwnd, &ps); + } else { + releaseDC(); + m_hdc = BeginPaint(hwnd, &ps); + setFlag(WithinWmPaint); + + const QRect updateRect = qrectFromRECT(ps.rcPaint); + if (QWindowsContext::verboseIntegration) + qDebug() << __FUNCTION__ << this << window() << updateRect; + + QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRegion(updateRect)); + clearFlag(WithinWmPaint); + m_hdc = 0; + EndPaint(hwnd, &ps); + } +} + +void QWindowsWindow::setWindowTitle(const QString &title) +{ + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window() <<title; + if (m_data.hwnd) + SetWindowText(m_data.hwnd, (const wchar_t*)title.utf16()); +} + +Qt::WindowFlags QWindowsWindow::setWindowFlags(Qt::WindowFlags flags) +{ + if (QWindowsContext::verboseWindows) + qDebug() << '>' << __FUNCTION__ << this << window() << "\n from: " + << QWindowsWindow::debugWindowFlags(m_data.flags) + << "\n to: " << QWindowsWindow::debugWindowFlags(flags); + if (m_data.flags != flags) { + m_data.flags = flags; + if (m_data.hwnd) + m_data = setWindowFlags_sys(flags); + } + if (QWindowsContext::verboseWindows) + qDebug() << '<' << __FUNCTION__ << "\n returns: " + << QWindowsWindow::debugWindowFlags(m_data.flags); + return m_data.flags; +} + +QWindowsWindow::WindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt) const +{ + // Geometry changes have not been observed here. Frames change, though. + WindowCreationData creationData; + creationData.fromWindow(window(), wt, window()->surfaceType() == QWindow::OpenGLSurface); + creationData.applyWindowFlags(m_data.hwnd); + creationData.initialize(m_data.hwnd, true); + WindowData result = m_data; + result.flags = creationData.flags; + setFlag(FrameDirty); + return result; +} + +void QWindowsWindow::handleWindowStateChange(Qt::WindowState state) +{ + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window() + << "\n from " << debugWindowStates(m_windowState) + << " to " << debugWindowStates(state); + setFlag(FrameDirty); + m_windowState = state; + QWindowSystemInterface::handleWindowStateChanged(window(), state); +} + +Qt::WindowState QWindowsWindow::setWindowState(Qt::WindowState state) +{ + if (m_data.hwnd) { + setWindowState_sys(state); + m_windowState = state; + } + return state; +} + +Qt::WindowState QWindowsWindow::windowState_sys() const +{ + if (IsIconic(m_data.hwnd)) + return Qt::WindowMinimized; + if (IsZoomed(m_data.hwnd)) + return Qt::WindowMaximized; + if (geometry_sys() == window()->screen()->geometry()) + return Qt::WindowFullScreen; + return Qt::WindowNoState; +} + +Qt::WindowStates QWindowsWindow::windowStates_sys() const +{ + Qt::WindowStates result = windowState_sys(); + if (GetActiveWindow() == m_data.hwnd) + result |= Qt::WindowActive; + return result; +} + +/*! + \brief Change the window state. + + \note Window frames change when maximized; + the top margin shrinks somewhat but that cannot be obtained using + AdjustWindowRectEx(). + + \note Some calls to SetWindowLong require a subsequent call + to ShowWindow. +*/ + +void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) +{ + const Qt::WindowStates oldStates = windowStates_sys(); + // Maintain the active flag as the platform window API does not + // use it. + Qt::WindowStates newStates = newState; + if (oldStates & Qt::WindowActive) + newStates |= Qt::WindowActive; + if (oldStates == newStates) + return; + if (QWindowsContext::verboseWindows) + qDebug() << '>' << __FUNCTION__ << this << window() + << " from " << debugWindowStates(oldStates) + << " to " << debugWindowStates(newStates); + + const bool isActive = newStates & Qt::WindowActive; + const int max = isActive ? SW_SHOWMAXIMIZED : SW_MAXIMIZE; + const int normal = isActive ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE; + const int min = isActive ? SW_SHOWMINIMIZED : SW_MINIMIZE; + const bool visible = isVisible(); + + setFlag(FrameDirty); + + if ((oldStates & Qt::WindowMaximized) != (newStates & Qt::WindowMaximized)) { + if (visible && !(newStates & Qt::WindowMinimized)) + ShowWindow(m_data.hwnd, (newStates & Qt::WindowMaximized) ? max : normal); + } + + if ((oldStates & Qt::WindowFullScreen) != (newStates & Qt::WindowFullScreen)) { + if (newStates & Qt::WindowFullScreen) { +#ifndef Q_FLATTEN_EXPOSE + UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP; +#else + UINT newStyle = WS_POPUP; +#endif + if (style() & WS_SYSMENU) + newStyle |= WS_SYSMENU; + if (visible) + newStyle |= WS_VISIBLE; + setStyle(newStyle); + + const QRect r = window()->screen()->geometry(); + UINT swpf = SWP_FRAMECHANGED; + if (newStates & Qt::WindowActive) + swpf |= SWP_NOACTIVATE; + + SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); + } else { + if (visible) + setStyle(style() | WS_VISIBLE); + UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; + if (newStates & Qt::WindowActive) + swpf |= SWP_NOACTIVATE; + SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0, swpf); + + // preserve maximized state + if (visible) + ShowWindow(m_data.hwnd, (newStates & Qt::WindowMaximized) ? max : normal); + } + } + + if ((oldStates & Qt::WindowMinimized) != (newStates & Qt::WindowMinimized)) { + if (visible) + ShowWindow(m_data.hwnd, (newStates & Qt::WindowMinimized) ? min : + (newStates & Qt::WindowMaximized) ? max : normal); + } + if (QWindowsContext::verboseWindows) + qDebug() << '<' << __FUNCTION__ << this << window() + << debugWindowStates(newStates); +} + +void QWindowsWindow::setStyle(unsigned s) const +{ + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window() << debugWinStyle(s); + setFlag(FrameDirty); + SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s); +} + +void QWindowsWindow::setExStyle(unsigned s) const +{ + if (QWindowsContext::verboseWindows) + qDebug().nospace() << __FUNCTION__ << ' ' << this << ' ' << window() + << " 0x" << QByteArray::number(s, 16); + setFlag(FrameDirty); + SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s); +} + +void QWindowsWindow::raise() +{ + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window(); + SetWindowPos(m_data.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +} + +void QWindowsWindow::lower() +{ + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window(); + if (m_data.hwnd) + SetWindowPos(m_data.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +} + +void QWindowsWindow::propagateSizeHints() +{ + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window(); +} + +QMargins QWindowsWindow::frameMargins() const +{ + // Frames are invalidated by style changes (window state, flags). + // As they are also required for geometry calculations in resize + // event sequences, introduce a dirty flag mechanism to be able + // to cache results. + if (testFlag(FrameDirty)) { + m_data.frame = QWindowsGeometryHint::frame(style(), exStyle()); + clearFlag(FrameDirty); + } + return m_data.frame; +} + +void QWindowsWindow::setOpacity(qreal level) +{ + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << level; + if (m_opacity != level) { + m_opacity = level; + if (m_data.hwnd) + setOpacity_sys(level); + } +} + +void QWindowsWindow::setOpacity_sys(qreal level) const +{ + const long wl = GetWindowLong(m_data.hwnd, GWL_EXSTYLE); + const bool isOpaque = level == 1.0; + + if (isOpaque) { + if (wl & WS_EX_LAYERED) + SetWindowLong(m_data.hwnd, GWL_EXSTYLE, wl & ~WS_EX_LAYERED); + } else { + if ((wl & WS_EX_LAYERED) == 0) + SetWindowLong(m_data.hwnd, GWL_EXSTYLE, wl | WS_EX_LAYERED); + if (m_data.flags & Qt::FramelessWindowHint) { + BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * level), AC_SRC_ALPHA}; + QWindowsContext::user32dll.updateLayeredWindow(m_data.hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA); + } else { + QWindowsContext::user32dll.setLayeredWindowAttributes(m_data.hwnd, 0, (int)(level * 255), LWA_ALPHA); + } + } +} + +void QWindowsWindow::requestActivateWindow() +{ + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window(); + if (m_data.hwnd) + SetForegroundWindow(m_data.hwnd); +} + +bool QWindowsWindow::setKeyboardGrabEnabled(bool grab) +{ + if (!m_data.hwnd) { + qWarning("%s: No handle", __FUNCTION__); + return false; + } + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << this << window() << grab; + + QWindowsContext *context = QWindowsContext::instance(); + if (grab) { + context->setKeyGrabber(window()); + } else { + if (context->keyGrabber() == window()) + context->setKeyGrabber(0); + } + return true; +} + +bool QWindowsWindow::setMouseGrabEnabled(bool grab) +{ + bool result = false; + if (!m_data.hwnd) { + qWarning("%s: No handle", __FUNCTION__); + return result; + } + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << window() << grab; + + if (m_mouseGrab != grab) { + m_mouseGrab = grab; + if (isVisible()) + setMouseGrabEnabled_sys(grab); + } + return grab; +} + +void QWindowsWindow::setMouseGrabEnabled_sys(bool grab) +{ + if (grab) { + SetCapture(m_data.hwnd); + } else { + ReleaseCapture(); + } +} + +void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const +{ + const QWindowsGeometryHint hint(window()); + hint.applyToMinMaxInfo(m_data.hwnd, mmi); + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << window() << *mmi; +} + +/*! + \brief Applies to cursor property set on the window to the global cursor + unless there is an override cursor. + + \sa QWindowsCursor +*/ + +void QWindowsWindow::applyCursor() +{ + if (!QGuiApplication::overrideCursor()) + SetCursor(m_cursor.handle()); +} + +void QWindowsWindow::setCursor(const QWindowsWindowCursor &c) +{ + if (c.handle() != m_cursor.handle()) { + const bool underMouse = QWindowsContext::instance()->windowUnderMouse() == window(); + if (QWindowsContext::verboseWindows) + qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape() + << " isWUM=" << underMouse; + m_cursor = c; + if (underMouse) + applyCursor(); + } +} + +/*! + \brief Find a child window using flags from ChildWindowFromPointEx. +*/ + +QWindowsWindow *QWindowsWindow::childAtScreenPoint(const QPoint &screenPoint, + unsigned cwexflags) const +{ + if (m_data.hwnd) + return QWindowsContext::instance()->findPlatformWindowAt(m_data.hwnd, screenPoint, cwexflags); + return 0; +} + +QWindowsWindow *QWindowsWindow::childAt(const QPoint &clientPoint, unsigned cwexflags) const +{ + if (m_data.hwnd) + return childAtScreenPoint(QWindowsGeometryHint::mapToGlobal(m_data.hwnd, clientPoint), + cwexflags); + return 0; +} + +QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf) +{ + const int iwf = int(wf); + QByteArray rc = "0x"; + rc += QByteArray::number(iwf, 16); + rc += " ["; + + switch ((iwf & Qt::WindowType_Mask)) { + case Qt::Widget: + rc += " Widget"; + break; + case Qt::Window: + rc += " Window"; + break; + case Qt::Dialog: + rc += " Dialog"; + break; + case Qt::Sheet: + rc += " Sheet"; + break; + case Qt::Popup: + rc += " Popup"; + break; + case Qt::Tool: + rc += " Tool"; + break; + case Qt::ToolTip: + rc += " ToolTip"; + break; + case Qt::SplashScreen: + rc += " SplashScreen"; + break; + case Qt::Desktop: + rc += " Desktop"; + break; + case Qt::SubWindow: + rc += " SubWindow"; + break; + } + if (iwf & Qt::MSWindowsFixedSizeDialogHint) rc += " MSWindowsFixedSizeDialogHint"; + if (iwf & Qt::MSWindowsOwnDC) rc += " MSWindowsOwnDC"; + if (iwf & Qt::FramelessWindowHint) rc += " FramelessWindowHint"; + if (iwf & Qt::WindowTitleHint) rc += " WindowTitleHint"; + if (iwf & Qt::WindowSystemMenuHint) rc += " WindowSystemMenuHint"; + if (iwf & Qt::WindowMinimizeButtonHint) rc += " WindowMinimizeButtonHint"; + if (iwf & Qt::WindowMaximizeButtonHint) rc += " WindowMaximizeButtonHint"; + if (iwf & Qt::WindowContextHelpButtonHint) rc += " WindowContextHelpButtonHint"; + if (iwf & Qt::WindowShadeButtonHint) rc += " WindowShadeButtonHint"; + if (iwf & Qt::WindowStaysOnTopHint) rc += " WindowStaysOnTopHint"; + if (iwf & Qt::CustomizeWindowHint) rc += " CustomizeWindowHint"; + if (iwf & Qt::WindowStaysOnBottomHint) rc += " WindowStaysOnBottomHint"; + if (iwf & Qt::WindowCloseButtonHint) rc += " WindowCloseButtonHint"; + rc += ']'; + return rc; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h new file mode 100644 index 0000000000..dfaeb2a86d --- /dev/null +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSWINDOW_H +#define QWINDOWSWINDOW_H + +#include "qtwindows_additional.h" +#include "qwindowscursor.h" + +#include <QtGui/QPlatformWindow> + +QT_BEGIN_NAMESPACE + +class QWindowsOleDropTarget; +class QDebug; + +struct QWindowsGeometryHint +{ + QWindowsGeometryHint() {} + explicit QWindowsGeometryHint(const QWindow *w); + static QMargins frame(DWORD style, DWORD exStyle); + void applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const; + void applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const; + bool validSize(const QSize &s) const; + + static inline QPoint mapToGlobal(HWND hwnd, const QPoint &); + static inline QPoint mapToGlobal(const QWindow *w, const QPoint &); + static inline QPoint mapFromGlobal(const HWND hwnd, const QPoint &); + static inline QPoint mapFromGlobal(const QWindow *w, const QPoint &); + + QSize minimumSize; + QSize maximumSize; +}; + +struct QWindowCreationContext +{ + QWindowCreationContext(const QWindow *w, const QRect &r, + DWORD style, DWORD exStyle); + + void applyToMinMaxInfo(MINMAXINFO *mmi) const + { geometryHint.applyToMinMaxInfo(style, exStyle, mmi); } + + QWindowsGeometryHint geometryHint; + DWORD style; + DWORD exStyle; + QRect requestedGeometry; + QRect obtainedGeometry; + QMargins margins; + int frameX; // Passed on to CreateWindowEx(), including frame. + int frameY; + int frameWidth; + int frameHeight; +}; + +class QWindowsWindow : public QPlatformWindow +{ +public: + enum Flags + { + OpenGL_Surface = 0x1, + WithinWmPaint = 0x2, + PixelFormatInitialized = 0x4, + FrameDirty = 0x8 //! Frame outdated by setStyle, recalculate in next query. + }; + + struct WindowData + { + WindowData() : hwnd(0) {} + + Qt::WindowFlags flags; + QRect geometry; + QMargins frame; // Do not use directly for windows, see FrameDirty. + HWND hwnd; + + static WindowData create(const QWindow *w, + const WindowData ¶meters, + const QString &title, + bool isGL); + }; + + QWindowsWindow(QWindow *window, const WindowData &data); + ~QWindowsWindow(); + + virtual void setGeometry(const QRect &rect); + virtual QRect geometry() const { return m_data.geometry; } + + virtual void setVisible(bool visible); + bool isVisible() const; + virtual Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags); + virtual Qt::WindowState setWindowState(Qt::WindowState state); + + HWND handle() const { return m_data.hwnd; } + + virtual WId winId() const { return WId(m_data.hwnd); } + virtual void setParent(const QPlatformWindow *window); + + virtual void setWindowTitle(const QString &title); + virtual void raise(); + virtual void lower(); + + virtual void propagateSizeHints(); + virtual QMargins frameMargins() const; + + virtual void setOpacity(qreal level); + virtual void requestActivateWindow(); + + virtual bool setKeyboardGrabEnabled(bool grab); + virtual bool setMouseGrabEnabled(bool grab); + + Qt::WindowState windowState_sys() const; + Qt::WindowStates windowStates_sys() const; + + inline unsigned style() const + { return GetWindowLongPtr(m_data.hwnd, GWL_STYLE); } + void setStyle(unsigned s) const; + inline unsigned exStyle() const + { return GetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE); } + void setExStyle(unsigned s) const; + + void handleWmPaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + + void handleMoved(); + void handleResized(int wParam); + void handleShown(); + void handleHidden(); + + static inline HWND handleOf(const QWindow *w); + static inline QWindowsWindow *baseWindowOf(const QWindow *w); + static QWindow *topLevelOf(QWindow *w); + static inline void *userDataOf(HWND hwnd); + static inline void setUserDataOf(HWND hwnd, void *ud); + + HDC getDC(); + void releaseDC(); + + void getSizeHints(MINMAXINFO *mmi) const; + + QWindowsWindowCursor cursor() const { return m_cursor; } + void setCursor(const QWindowsWindowCursor &c); + void applyCursor(); + + QWindowsWindow *childAt(const QPoint &clientPoint, + unsigned cwexflags = CWP_SKIPINVISIBLE) const; + QWindowsWindow *childAtScreenPoint(const QPoint &screenPoint, + unsigned cwexflags = CWP_SKIPINVISIBLE) const; + + static QByteArray debugWindowFlags(Qt::WindowFlags wf); + + inline bool testFlag(unsigned f) const { return (m_flags & f) != 0; } + inline void setFlag(unsigned f) const { m_flags |= f; } + inline void clearFlag(unsigned f) const { m_flags &= ~f; } + +private: + inline void show_sys() const; + inline void hide_sys() const; + inline void setGeometry_sys(const QRect &rect) const; + inline QRect geometry_sys() const; + inline WindowData setWindowFlags_sys(Qt::WindowFlags wt) const; + inline void setWindowState_sys(Qt::WindowState newState); + inline void setParent_sys(const QPlatformWindow *parent) const; + inline void setOpacity_sys(qreal level) const; + inline void setMouseGrabEnabled_sys(bool grab); + void destroyWindow(); + void registerDropSite(); + void unregisterDropSite(); + void handleGeometryChange(); + void handleWindowStateChange(Qt::WindowState state); + + mutable WindowData m_data; + mutable unsigned m_flags; + HDC m_hdc; + Qt::WindowState m_windowState; + qreal m_opacity; + bool m_mouseGrab; + QWindowsWindowCursor m_cursor; + QWindowsOleDropTarget *m_dropTarget; +}; + +// Conveniences for window frames. +inline QRect operator+(const QRect &r, const QMargins &m) +{ + return r.adjusted(-m.left(), -m.top(), m.right(), m.bottom()); +} + +inline QRect operator-(const QRect &r, const QMargins &m) +{ + return r.adjusted(m.left(), m.top(), -m.right(), -m.bottom()); +} + +// Debug +QDebug operator<<(QDebug d, const RECT &r); +QDebug operator<<(QDebug d, const MINMAXINFO &i); +QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p); + +// ---------- QWindowsGeometryHint inline functions. +QPoint QWindowsGeometryHint::mapToGlobal(HWND hwnd, const QPoint &qp) +{ + POINT p = { qp.x(), qp.y() }; + ClientToScreen(hwnd, &p); + return QPoint(p.x, p.y); +} + +QPoint QWindowsGeometryHint::mapFromGlobal(const HWND hwnd, const QPoint &qp) +{ + POINT p = { qp.x(), qp.y() }; + ScreenToClient(hwnd, &p); + return QPoint(p.x, p.y); +} + +QPoint QWindowsGeometryHint::mapToGlobal(const QWindow *w, const QPoint &p) + { return QWindowsGeometryHint::mapToGlobal(QWindowsWindow::handleOf(w), p); } + +QPoint QWindowsGeometryHint::mapFromGlobal(const QWindow *w, const QPoint &p) + { return QWindowsGeometryHint::mapFromGlobal(QWindowsWindow::handleOf(w), p); } + + +// ---------- QWindowsBaseWindow inline functions. + +QWindowsWindow *QWindowsWindow::baseWindowOf(const QWindow *w) +{ + if (w) + if (QPlatformWindow *pw = w->handle()) + return static_cast<QWindowsWindow *>(pw); + return 0; +} + +HWND QWindowsWindow::handleOf(const QWindow *w) +{ + if (const QWindowsWindow *bw = QWindowsWindow::baseWindowOf(w)) + return bw->handle(); + return 0; +} + +void *QWindowsWindow::userDataOf(HWND hwnd) +{ + return (void *)GetWindowLongPtr(hwnd, GWLP_USERDATA); +} + +void QWindowsWindow::setUserDataOf(HWND hwnd, void *ud) +{ + SetWindowLongPtr(hwnd, GWLP_USERDATA, LONG_PTR(ud)); +} + +QT_END_NAMESPACE + +#endif // QWINDOWSWINDOW_H diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro new file mode 100644 index 0000000000..e5627ae574 --- /dev/null +++ b/src/plugins/platforms/windows/windows.pro @@ -0,0 +1,70 @@ +TARGET = windows +load(qt_plugin) + +QT *= core-private +QT *= gui-private + +INCLUDEPATH += ../../../3rdparty/harfbuzz/src +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms + +# Note: OpenGL32 must precede Gdi32 as it overwrites some functions. +LIBS *= -lOpenGL32 -lGdi32 -lUser32 -lOle32 -lWinspool -lImm32 +win32-g++: LIBS *= -luuid + +contains(QT_CONFIG, directwrite) { + LIBS *= -ldwrite + SOURCES += qwindowsfontenginedirectwrite.cpp + HEADERS += qwindowsfontenginedirectwrite.h +} else { + DEFINES *= QT_NO_DIRECTWRITE +} + +SOURCES += \ + main.cpp \ + qwindowsnativeimage.cpp \ + qwindowswindow.cpp \ + qwindowsintegration.cpp \ + qwindowscontext.cpp \ + qwindowsbackingstore.cpp \ + qwindowsscreen.cpp \ + qwindowskeymapper.cpp \ + qwindowsfontengine.cpp \ + qwindowsfontdatabase.cpp \ + qwindowsmousehandler.cpp \ + qwindowsguieventdispatcher.cpp \ + qwindowsglcontext.cpp \ + qwindowsclipboard.cpp \ + qwindowsole.cpp \ + qwindowsmime.cpp \ + qwindowsdrag.cpp \ + qwindowscursor.cpp \ + pixmaputils.cpp \ + qwindowsinputcontext.cpp + +HEADERS += \ + qwindowsnativeimage.h \ + qwindowswindow.h \ + qwindowsintegration.h \ + qwindowscontext.h \ + qwindowsbackingstore.h \ + qwindowsscreen.h \ + qwindowskeymapper.h \ + qwindowsfontengine.h \ + qwindowsfontdatabase.h \ + qwindowsmousehandler.h \ + qwindowsguieventdispatcher.h \ + qtwindowsglobal.h \ + qtwindows_additional.h \ + qwindowsglcontext.h \ + qwindowsclipboard.h \ + qwindowsole.h \ + qwindowsmime.h \ + qwindowsdrag.h \ + qwindowsinternalmimedata.h \ + qwindowscursor.h \ + pixmaputils.h \ + array.h \ + qwindowsinputcontext.h + +target.path += $$[QT_INSTALL_PLUGINS]/platforms +INSTALLS += target diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README index 17a86e6d08..d2884f109c 100644 --- a/src/plugins/platforms/xcb/README +++ b/src/plugins/platforms/xcb/README @@ -1,3 +1,3 @@ Required packages: -libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev +libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev diff --git a/src/plugins/platforms/xcb/main.cpp b/src/plugins/platforms/xcb/main.cpp index 7fee7455be..c544f7073d 100644 --- a/src/plugins/platforms/xcb/main.cpp +++ b/src/plugins/platforms/xcb/main.cpp @@ -58,11 +58,10 @@ QStringList QXcbIntegrationPlugin::keys() const return list; } -QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& paramList) +QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters) { - Q_UNUSED(paramList); if (system.toLower() == "xcb") - return new QXcbIntegration; + return new QXcbIntegration(parameters); return 0; } diff --git a/src/plugins/platforms/xcb/qdri2context.cpp b/src/plugins/platforms/xcb/qdri2context.cpp index 8bcdacb92b..5f4aff5455 100644 --- a/src/plugins/platforms/xcb/qdri2context.cpp +++ b/src/plugins/platforms/xcb/qdri2context.cpp @@ -45,7 +45,7 @@ #include "qxcbconnection.h" #include <QtCore/QDebug> -#include <QtGui/QWidget> +#include <QtWidgets/QWidget> #include <xcb/dri2.h> #include <xcb/xfixes.h> @@ -134,9 +134,9 @@ QDri2Context::QDri2Context(QXcbWindow *window) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERER,d->depth); //restore the old current context - const QPlatformGLContext *currentContext = QPlatformGLContext::currentContext(); + const QPlatformOpenGLContext *currentContext = QPlatformOpenGLContext::currentContext(); if (currentContext) - const_cast<QPlatformGLContext*>(currentContext)->makeCurrent(); + const_cast<QPlatformOpenGLContext*>(currentContext)->makeCurrent(); } QDri2Context::~QDri2Context() @@ -146,7 +146,6 @@ QDri2Context::~QDri2Context() void QDri2Context::makeCurrent() { - QPlatformGLContext::makeCurrent(); Q_D(QDri2Context); eglMakeCurrent(EGL_DISPLAY_FROM_XCB(d->qXcbWindow),EGL_NO_SURFACE,EGL_NO_SURFACE,d->eglContext); @@ -156,7 +155,6 @@ void QDri2Context::makeCurrent() void QDri2Context::doneCurrent() { - QPlatformGLContext::doneCurrent(); Q_D(QDri2Context); eglMakeCurrent(EGL_DISPLAY_FROM_XCB(d->qXcbWindow),EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT); } diff --git a/src/plugins/platforms/xcb/qdri2context.h b/src/plugins/platforms/xcb/qdri2context.h index be7d637643..ec8b251c3f 100644 --- a/src/plugins/platforms/xcb/qdri2context.h +++ b/src/plugins/platforms/xcb/qdri2context.h @@ -42,14 +42,14 @@ #ifndef QDRI2CONTEXT_H #define QDRI2CONTEXT_H -#include <QtGui/QPlatformGLContext> +#include <QtGui/QPlatformOpenGLContext> class QXcbWindow; class QDri2ContextPrivate; struct xcb_dri2_dri2_buffer_t; -class QDri2Context : public QPlatformGLContext +class QDri2Context : public QPlatformOpenGLContext { Q_DECLARE_PRIVATE(QDri2Context); public: diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index 8e04cbcb71..41bceaf406 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -41,7 +41,6 @@ #include <QDebug> #include <QLibrary> -#include <QGLFormat> #include "qxcbwindow.h" #include "qxcbscreen.h" @@ -50,72 +49,56 @@ #include <X11/Xutil.h> #include <GL/glx.h> +#include <QtGui/QOpenGLContext> + #include "qglxintegration.h" -#include "qglxconvenience.h" +#include <QtPlatformSupport/private/qglxconvenience_p.h> #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) #include <dlfcn.h> #endif -QGLXContext::QGLXContext(Window window, QXcbScreen *screen, const QPlatformWindowFormat &format) - : QPlatformGLContext() +QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share) + : QPlatformOpenGLContext() , m_screen(screen) - , m_drawable((Drawable)window) , m_context(0) { - Q_XCB_NOOP(m_screen->connection()); - const QPlatformGLContext *sharePlatformContext; - sharePlatformContext = format.sharedGLContext(); GLXContext shareGlxContext = 0; - if (sharePlatformContext) - shareGlxContext = static_cast<const QGLXContext*>(sharePlatformContext)->glxContext(); + if (share) + shareGlxContext = static_cast<const QGLXContext*>(share)->glxContext(); GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),format); m_context = glXCreateNewContext(DISPLAY_FROM_XCB(screen), config, GLX_RGBA_TYPE, shareGlxContext, TRUE); - m_windowFormat = qglx_platformWindowFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context); - Q_XCB_NOOP(m_screen->connection()); -} - -QGLXContext::QGLXContext(QXcbScreen *screen, Drawable drawable, GLXContext context) - : QPlatformGLContext(), m_screen(screen), m_drawable(drawable), m_context(context) -{ - + m_format = qglx_surfaceFormatFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context); } QGLXContext::~QGLXContext() { - Q_XCB_NOOP(m_screen->connection()); - if (m_context) - glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context); - Q_XCB_NOOP(m_screen->connection()); + glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context); } -void QGLXContext::makeCurrent() +bool QGLXContext::makeCurrent(QPlatformSurface *surface) { - Q_XCB_NOOP(m_screen->connection()); - QPlatformGLContext::makeCurrent(); - glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), m_drawable, m_context); - Q_XCB_NOOP(m_screen->connection()); + Q_ASSERT(surface); + + GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window(); + + return glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), glxDrawable, m_context); } void QGLXContext::doneCurrent() { - Q_XCB_NOOP(m_screen->connection()); - QPlatformGLContext::doneCurrent(); glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0); - Q_XCB_NOOP(m_screen->connection()); } -void QGLXContext::swapBuffers() +void QGLXContext::swapBuffers(QPlatformSurface *surface) { - Q_XCB_NOOP(m_screen->connection()); - glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), m_drawable); - Q_XCB_NOOP(m_screen->connection()); + GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window(); + glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), glxDrawable); } -void* QGLXContext::getProcAddress(const QString& procName) +void (*QGLXContext::getProcAddress(const QByteArray &procName)) () { - Q_XCB_NOOP(m_screen->connection()); typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *); static qt_glXGetProcAddressARB glXGetProcAddressARB = 0; static bool resolved = false; @@ -144,10 +127,10 @@ void* QGLXContext::getProcAddress(const QString& procName) } if (!glXGetProcAddressARB) return 0; - return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.toLatin1().data())); + return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.constData())); } -QPlatformWindowFormat QGLXContext::platformWindowFormat() const +QSurfaceFormat QGLXContext::format() const { - return m_windowFormat; + return m_format; } diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h index 84de7b7143..bbe67b653a 100644 --- a/src/plugins/platforms/xcb/qglxintegration.h +++ b/src/plugins/platforms/xcb/qglxintegration.h @@ -43,36 +43,34 @@ #define QGLXINTEGRATION_H #include "qxcbwindow.h" +#include "qxcbscreen.h" -#include <QtGui/QPlatformGLContext> -#include <QtGui/QPlatformWindowFormat> +#include <QtGui/QPlatformOpenGLContext> +#include <QtGui/QSurfaceFormat> #include <QtCore/QMutex> #include <GL/glx.h> -class QGLXContext : public QPlatformGLContext +class QGLXContext : public QPlatformOpenGLContext { public: - QGLXContext(Window window, QXcbScreen *xd, const QPlatformWindowFormat &format); + QGLXContext(QXcbScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share); ~QGLXContext(); - virtual void makeCurrent(); - virtual void doneCurrent(); - virtual void swapBuffers(); - virtual void* getProcAddress(const QString& procName); + bool makeCurrent(QPlatformSurface *surface); + void doneCurrent(); + void swapBuffers(QPlatformSurface *surface); + void (*getProcAddress(const QByteArray &procName)) (); - GLXContext glxContext() const { return m_context; } + QSurfaceFormat format() const; - QPlatformWindowFormat platformWindowFormat() const; + GLXContext glxContext() const { return m_context; } private: QXcbScreen *m_screen; - Drawable m_drawable; GLXContext m_context; - QPlatformWindowFormat m_windowFormat; - - QGLXContext (QXcbScreen *screen, Drawable drawable, GLXContext context); + QSurfaceFormat m_format; }; #endif diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 4fcd207df3..fadcb4d5b8 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qxcbwindowsurface.h" +#include "qxcbbackingstore.h" #include "qxcbconnection.h" #include "qxcbscreen.h" @@ -52,9 +52,11 @@ #include <sys/shm.h> #include <stdio.h> +#include <errno.h> #include <qdebug.h> #include <qpainter.h> +#include <qscreen.h> class QXcbShmImage : public QXcbObject { @@ -63,6 +65,7 @@ public: ~QXcbShmImage() { destroy(); } QImage *image() { return &m_qimage; } + QSize size() const { return m_qimage.size(); } void put(xcb_window_t window, const QPoint &dst, const QRect &source); void preparePaint(const QRegion ®ion); @@ -97,30 +100,54 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI ~0, 0); - m_shm_info.shmid = shmget (IPC_PRIVATE, - m_xcb_image->stride * m_xcb_image->height, IPC_CREAT|0777); + const int segmentSize = m_xcb_image->stride * m_xcb_image->height; + if (!segmentSize) + return; + int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0777); + if (id == -1) + qWarning("QXcbShmImage: shmget() failed (%d) for size %d (%dx%d)", + errno, segmentSize, size.width(), size.height()); + else + m_shm_info.shmid = id; m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat (m_shm_info.shmid, 0, 0); m_shm_info.shmseg = xcb_generate_id(xcb_connection()); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), xcb_shm_attach_checked(xcb_connection(), m_shm_info.shmseg, m_shm_info.shmid, false)); if (error) { - qWarning() << "QXcbWindowSurface: Unable to attach to shared memory segment"; free(error); - } - if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1) - qWarning() << "QXcbWindowSurface: Error while marking the shared memory segment to be destroyed"; + shmdt(m_shm_info.shmaddr); + shmctl(m_shm_info.shmid, IPC_RMID, 0); + + m_shm_info.shmaddr = 0; + + m_xcb_image->data = (uint8_t *)qMalloc(segmentSize); + } else { + if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1) + qWarning() << "QXcbBackingStore: Error while marking the shared memory segment to be destroyed"; + } m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format); } void QXcbShmImage::destroy() { - Q_XCB_CALL(xcb_shm_detach(xcb_connection(), m_shm_info.shmseg)); + const int segmentSize = m_xcb_image ? (m_xcb_image->stride * m_xcb_image->height) : 0; + if (segmentSize && m_shm_info.shmaddr) + Q_XCB_CALL(xcb_shm_detach(xcb_connection(), m_shm_info.shmseg)); + xcb_image_destroy(m_xcb_image); - shmdt(m_shm_info.shmaddr); - shmctl(m_shm_info.shmid, IPC_RMID, 0); + + if (segmentSize) { + if (m_shm_info.shmaddr) { + shmdt(m_shm_info.shmaddr); + shmctl(m_shm_info.shmid, IPC_RMID, 0); + } else { + qFree(m_xcb_image->data); + } + } + if (m_gc) Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); } @@ -139,18 +166,32 @@ void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &s } Q_XCB_NOOP(connection()); - xcb_image_shm_put(xcb_connection(), + if (m_shm_info.shmaddr) { + xcb_image_shm_put(xcb_connection(), + window, + m_gc, + m_xcb_image, + m_shm_info, + source.x(), + source.y(), + target.x(), + target.y(), + source.width(), + source.height(), + false); + } else { + xcb_image_t *subimage = xcb_image_subimage(m_xcb_image, source.x(), source.y(), source.width(), source.height(), + 0, 0, 0); + xcb_image_put(xcb_connection(), window, m_gc, - m_xcb_image, - m_shm_info, - source.x(), - source.y(), + subimage, target.x(), target.y(), - source.width(), - source.height(), - false); + 0); + + xcb_image_destroy(subimage); + } Q_XCB_NOOP(connection()); m_dirty = m_dirty | source; @@ -168,29 +209,30 @@ void QXcbShmImage::preparePaint(const QRegion ®ion) } } -QXcbWindowSurface::QXcbWindowSurface(QWidget *widget, bool setDefaultSurface) - : QWindowSurface(widget, setDefaultSurface) +QXcbBackingStore::QXcbBackingStore(QWindow *window) + : QPlatformBackingStore(window) , m_image(0) , m_syncingResize(false) { - QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(widget)); + QXcbScreen *screen = static_cast<QXcbScreen *>(window->screen()->handle()); setConnection(screen->connection()); } -QXcbWindowSurface::~QXcbWindowSurface() +QXcbBackingStore::~QXcbBackingStore() { delete m_image; } -QPaintDevice *QXcbWindowSurface::paintDevice() +QPaintDevice *QXcbBackingStore::paintDevice() { return m_image->image(); } -void QXcbWindowSurface::beginPaint(const QRegion ®ion) +void QXcbBackingStore::beginPaint(const QRegion ®ion) { m_image->preparePaint(region); +#if 0 if (m_image->image()->hasAlphaChannel()) { QPainter p(m_image->image()); p.setCompositionMode(QPainter::CompositionMode_Source); @@ -200,29 +242,27 @@ void QXcbWindowSurface::beginPaint(const QRegion ®ion) p.fillRect(*it, blank); } } +#endif } -void QXcbWindowSurface::endPaint(const QRegion &) +void QXcbBackingStore::endPaint(const QRegion &) { } -void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { QRect bounds = region.boundingRect(); - if (size().isEmpty() || !geometry().contains(bounds)) + if (!m_image || m_image->size().isEmpty()) return; Q_XCB_NOOP(connection()); - QXcbWindow *window = static_cast<QXcbWindow *>(widget->window()->platformWindow()); - - extern QWidgetData* qt_widget_data(QWidget *); - QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft(); + QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle()); QVector<QRect> rects = region.rects(); for (int i = 0; i < rects.size(); ++i) - m_image->put(window->window(), rects.at(i).topLeft() - widgetOffset, rects.at(i).translated(offset)); + m_image->put(platformWindow->xcb_window(), rects.at(i).topLeft(), rects.at(i).translated(offset)); Q_XCB_NOOP(connection()); @@ -230,23 +270,22 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoi xcb_flush(xcb_connection()); connection()->sync(); m_syncingResize = false; - window->updateSyncRequestCounter(); + platformWindow->updateSyncRequestCounter(); } } -void QXcbWindowSurface::resize(const QSize &size) +void QXcbBackingStore::resize(const QSize &size, const QRegion &) { - if (size == QWindowSurface::size()) + if (m_image && size == m_image->size()) return; Q_XCB_NOOP(connection()); - QWindowSurface::resize(size); - QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(window())); - QXcbWindow* win = static_cast<QXcbWindow *>(window()->platformWindow()); + QXcbScreen *screen = static_cast<QXcbScreen *>(window()->screen()->handle()); + QXcbWindow* win = static_cast<QXcbWindow *>(window()->handle()); delete m_image; - m_image = new QXcbShmImage(screen, size, win->depth(), win->format()); + m_image = new QXcbShmImage(screen, size, win->depth(), win->imageFormat()); Q_XCB_NOOP(connection()); m_syncingResize = true; @@ -254,9 +293,9 @@ void QXcbWindowSurface::resize(const QSize &size) extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); -bool QXcbWindowSurface::scroll(const QRegion &area, int dx, int dy) +bool QXcbBackingStore::scroll(const QRegion &area, int dx, int dy) { - if (m_image->image()->isNull()) + if (!m_image || m_image->image()->isNull()) return false; m_image->preparePaint(area); diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.h b/src/plugins/platforms/xcb/qxcbbackingstore.h index 5f61815b65..db94d26b09 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.h +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -39,10 +39,10 @@ ** ****************************************************************************/ -#ifndef QXCBWINDOWSURFACE_H -#define QXCBWINDOWSURFACE_H +#ifndef QXCBBACKINGSTORE_H +#define QXCBBACKINGSTORE_H -#include <private/qwindowsurface_p.h> +#include <qplatformbackingstore_qpa.h> #include <xcb/xcb.h> @@ -50,15 +50,15 @@ class QXcbShmImage; -class QXcbWindowSurface : public QXcbObject, public QWindowSurface +class QXcbBackingStore : public QXcbObject, public QPlatformBackingStore { public: - QXcbWindowSurface(QWidget *widget, bool setDefaultSurface = true); - ~QXcbWindowSurface(); + QXcbBackingStore(QWindow *widget); + ~QXcbBackingStore(); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - void resize(const QSize &size); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + void resize(const QSize &size, const QRegion &staticContents); bool scroll(const QRegion &area, int dx, int dy); void beginPaint(const QRegion &); diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp new file mode 100644 index 0000000000..550b8cbd73 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -0,0 +1,848 @@ +/**************************************************************************** +** +** 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 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 "qxcbclipboard.h" + +#include "qxcbconnection.h" +#include "qxcbscreen.h" +#include "qxcbmime.h" + +#include <private/qguiapplication_p.h> +#include <QElapsedTimer> + +#include <QtCore/QDebug> + +#include <xcb/xcb_icccm.h> + +class QXcbClipboardMime : public QXcbMime +{ + Q_OBJECT +public: + QXcbClipboardMime(QClipboard::Mode mode, QXcbClipboard *clipboard) + : QXcbMime() + , m_clipboard(clipboard) + { + switch (mode) { + case QClipboard::Selection: + modeAtom = XCB_ATOM_PRIMARY; + break; + + case QClipboard::Clipboard: + modeAtom = m_clipboard->atom(QXcbAtom::CLIPBOARD); + break; + + default: + qWarning("QTestLiteMime: Internal error: Unsupported clipboard mode"); + break; + } + } + +protected: + QStringList formats_sys() const + { + if (empty()) + return QStringList(); + + if (!formatList.count()) { + QXcbClipboardMime *that = const_cast<QXcbClipboardMime *>(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, m_clipboard->atom(QXcbAtom::TARGETS)); + + if (format_atoms.size() > 0) { + xcb_atom_t *targets = (xcb_atom_t *) format_atoms.data(); + int size = format_atoms.size() / sizeof(xcb_atom_t); + + for (int i = 0; i < size; ++i) { + if (targets[i] == 0) + continue; + + QString format = mimeAtomToString(m_clipboard->connection(), targets[i]); + if (!formatList.contains(format)) + that->formatList.append(format); + } + } + } + + 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<xcb_atom_t> atoms; + xcb_atom_t *targets = (xcb_atom_t *) format_atoms.data(); + int size = format_atoms.size() / sizeof(xcb_atom_t); + for (int i = 0; i < size; ++i) + atoms.append(targets[i]); + + QByteArray encoding; + xcb_atom_t fmtatom = mimeAtomForFormat(m_clipboard->connection(), fmt, requestedType, atoms, &encoding); + + if (fmtatom == 0) + return QVariant(); + + return mimeConvertToFormat(m_clipboard->connection(), fmtatom, m_clipboard->getDataInFormat(modeAtom, fmtatom), fmt, requestedType, encoding); + } +private: + bool empty() const + { + return m_clipboard->getSelectionOwner(modeAtom) == XCB_NONE; + } + + + xcb_atom_t modeAtom; + QXcbClipboard *m_clipboard; + QStringList formatList; + QByteArray format_atoms; +}; + +const int QXcbClipboard::clipboard_timeout = 5000; + +QXcbClipboard::QXcbClipboard(QXcbConnection *c) + : QXcbObject(c), QPlatformClipboard() + , m_requestor(XCB_NONE) + , m_owner(XCB_NONE) +{ + Q_ASSERT(QClipboard::Clipboard == 0); + Q_ASSERT(QClipboard::Selection == 1); + m_xClipboard[QClipboard::Clipboard] = 0; + m_xClipboard[QClipboard::Selection] = 0; + m_clientClipboard[QClipboard::Clipboard] = 0; + m_clientClipboard[QClipboard::Selection] = 0; + m_timestamp[QClipboard::Clipboard] = XCB_CURRENT_TIME; + m_timestamp[QClipboard::Selection] = XCB_CURRENT_TIME; + + m_screen = connection()->screens().at(connection()->primaryScreen()); + + int x = 0, y = 0, w = 3, h = 3; + + m_owner = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, // depth -- same as root + m_owner, // window id + m_screen->screen()->root, // parent window id + x, y, w, h, + 0, // border width + XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class + m_screen->screen()->root_visual, // visual + 0, // value mask + 0)); // value list + + if (connection()->hasXFixes()) { + const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | + XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY | + XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE; + Q_XCB_CALL(xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask)); + Q_XCB_CALL(xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask)); + } +} + +QXcbClipboard::~QXcbClipboard() +{ + // Transfer the clipboard content to the clipboard manager if we own a selection + if (m_timestamp[QClipboard::Clipboard] != XCB_CURRENT_TIME || + m_timestamp[QClipboard::Selection] != XCB_CURRENT_TIME) { + + // First we check if there is a clipboard manager. + xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(xcb_connection(), atom(QXcbAtom::CLIPBOARD_MANAGER)); + xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply(xcb_connection(), cookie, 0); + if (reply && reply->owner != XCB_NONE) { + // we delete the property so the manager saves all TARGETS. + xcb_delete_property(xcb_connection(), m_owner, atom(QXcbAtom::_QT_SELECTION)); + xcb_convert_selection(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD_MANAGER), atom(QXcbAtom::SAVE_TARGETS), + atom(QXcbAtom::_QT_SELECTION), connection()->time()); + connection()->sync(); + + // waiting until the clipboard manager fetches the content. + if (!waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, 5000)) { + qWarning("QClipboard: Unable to receive an event from the " + "clipboard manager in a reasonable time"); + } + } + } +} + + +xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const +{ + xcb_connection_t *c = xcb_connection(); + xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(c, atom); + xcb_get_selection_owner_reply_t *reply; + reply = xcb_get_selection_owner_reply(c, cookie, 0); + xcb_window_t win = reply->owner; + free(reply); + return win; +} + +xcb_atom_t QXcbClipboard::atomForMode(QClipboard::Mode mode) const +{ + if (mode == QClipboard::Clipboard) + return atom(QXcbAtom::CLIPBOARD); + if (mode == QClipboard::Selection) + return XCB_ATOM_PRIMARY; + return XCB_NONE; +} + +QClipboard::Mode QXcbClipboard::modeForAtom(xcb_atom_t a) const +{ + if (a == XCB_ATOM_PRIMARY) + return QClipboard::Selection; + if (a == atom(QXcbAtom::CLIPBOARD)) + return QClipboard::Clipboard; + // not supported enum value, used to detect errors + return QClipboard::FindBuffer; +} + + +QMimeData * QXcbClipboard::mimeData(QClipboard::Mode mode) +{ + if (mode > QClipboard::Selection) + return 0; + + xcb_window_t clipboardOwner = getSelectionOwner(atomForMode(mode)); + if (clipboardOwner == owner()) { + return m_clientClipboard[mode]; + } else { + if (!m_xClipboard[mode]) + m_xClipboard[mode] = new QXcbClipboardMime(mode, this); + + return m_xClipboard[mode]; + } +} + +void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) +{ + if (mode > QClipboard::Selection) + return; + + xcb_atom_t modeAtom = atomForMode(mode); + + if (m_clientClipboard[mode] == data) + return; + + xcb_window_t newOwner = XCB_NONE; + + if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection]) + delete m_clientClipboard[mode]; + m_clientClipboard[mode] = 0; + m_timestamp[mode] = XCB_CURRENT_TIME; + + if (data) { + newOwner = owner(); + + m_clientClipboard[mode] = data; + m_timestamp[mode] = connection()->time(); + } + + xcb_set_selection_owner(xcb_connection(), newOwner, modeAtom, connection()->time()); + + if (getSelectionOwner(modeAtom) != newOwner) { + qWarning("QClipboard::setData: Cannot set X11 selection owner"); + } + +} + +bool QXcbClipboard::supportsMode(QClipboard::Mode mode) const +{ + if (mode <= QClipboard::Selection) + return true; + return false; +} + +bool QXcbClipboard::ownsMode(QClipboard::Mode mode) const +{ + if (m_owner == XCB_NONE || mode > QClipboard::Selection) + return false; + + Q_ASSERT(m_timestamp[mode] == XCB_CURRENT_TIME || getSelectionOwner(atomForMode(mode)) == m_owner); + + return m_timestamp[mode] != XCB_CURRENT_TIME; +} + +xcb_window_t QXcbClipboard::requestor() const +{ + if (!m_requestor) { + const int x = 0, y = 0, w = 3, h = 3; + QXcbClipboard *that = const_cast<QXcbClipboard *>(this); + + xcb_window_t window = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, // depth -- same as root + window, // window id + m_screen->screen()->root, // parent window id + x, y, w, h, + 0, // border width + XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class + m_screen->screen()->root_visual, // visual + 0, // value mask + 0)); // value list + + uint32_t mask = XCB_EVENT_MASK_PROPERTY_CHANGE; + xcb_change_window_attributes(xcb_connection(), window, XCB_CW_EVENT_MASK, &mask); + + that->setRequestor(window); + } + return m_requestor; +} + +void QXcbClipboard::setRequestor(xcb_window_t window) +{ + if (m_requestor != XCB_NONE) { + xcb_destroy_window(xcb_connection(), m_requestor); + } + m_requestor = window; +} + +xcb_window_t QXcbClipboard::owner() const +{ + return m_owner; +} + +xcb_atom_t QXcbClipboard::sendTargetsSelection(QMimeData *d, xcb_window_t window, xcb_atom_t property) +{ + QVector<xcb_atom_t> types; + QStringList formats = QInternalMimeData::formatsHelper(d); + for (int i = 0; i < formats.size(); ++i) { + QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), formats.at(i)); + for (int j = 0; j < atoms.size(); ++j) { + if (!types.contains(atoms.at(j))) + types.append(atoms.at(j)); + } + } + types.append(atom(QXcbAtom::TARGETS)); + types.append(atom(QXcbAtom::MULTIPLE)); + types.append(atom(QXcbAtom::TIMESTAMP)); + types.append(atom(QXcbAtom::SAVE_TARGETS)); + + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, XCB_ATOM_ATOM, + 32, types.size(), (const void *)types.constData()); + return property; +} + +xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_window_t window, xcb_atom_t property) +{ + xcb_atom_t atomFormat = target; + int dataFormat = 0; + QByteArray data; + + QString fmt = QXcbMime::mimeAtomToString(connection(), target); + if (fmt.isEmpty()) { // Not a MIME type we have +// qDebug() << "QClipboard: send_selection(): converting to type" << connection()->atomName(target) << "is not supported"; + return XCB_NONE; + } +// qDebug() << "QClipboard: send_selection(): converting to type" << fmt; + + if (QXcbMime::mimeDataForAtom(connection(), target, d, &data, &atomFormat, &dataFormat)) { + + // don't allow INCR transfers when using MULTIPLE or to + // Motif clients (since Motif doesn't support INCR) + static xcb_atom_t motif_clip_temporary = atom(QXcbAtom::CLIP_TEMPORARY); + bool allow_incr = property != motif_clip_temporary; + + // X_ChangeProperty protocol request is 24 bytes + const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; + if (data.size() > increment && allow_incr) { + long bytes = data.size(); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, + atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes); + +// (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment); + qWarning() << "not implemented INCR just YET!"; + return property; + } + + // make sure we can perform the XChangeProperty in a single request + if (data.size() > increment) + return XCB_NONE; // ### perhaps use several XChangeProperty calls w/ PropModeAppend? + int dataSize = data.size() / (dataFormat / 8); + // use a single request to transfer data + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, atomFormat, + dataFormat, dataSize, (const void *)data.constData()); + } + return property; +} + +void QXcbClipboard::handleSelectionClearRequest(xcb_selection_clear_event_t *event) +{ + QClipboard::Mode mode = modeForAtom(event->selection); + if (mode > QClipboard::Selection) + return; + + // ignore the event if it was generated before we gained selection ownership + if (m_timestamp[mode] != XCB_CURRENT_TIME && event->time <= m_timestamp[mode]) + return; + +// DEBUG("QClipboard: new selection owner 0x%lx at time %lx (ours %lx)", +// XGetSelectionOwner(dpy, XA_PRIMARY), +// xevent->xselectionclear.time, d->timestamp); + +// if (!waiting_for_data) { + setMimeData(0, mode); + emitChanged(mode); +// } else { +// pending_selection_changed = true; +// if (! pending_timer_id) +// pending_timer_id = QApplication::clipboard()->startTimer(0); +// } +} + +void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req) +{ + if (requestor() && req->requestor == requestor()) { + qDebug() << "This should be caught before"; + return; + } + + xcb_selection_notify_event_t event; + event.response_type = XCB_SELECTION_NOTIFY; + event.requestor = req->requestor; + event.selection = req->selection; + event.target = req->target; + event.property = XCB_NONE; + event.time = req->time; + + QMimeData *d; + QClipboard::Mode mode = modeForAtom(req->selection); + if (mode > QClipboard::Selection) { + qWarning() << "QClipboard: Unknown selection" << connection()->atomName(req->selection); + xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); + return; + } + + d = m_clientClipboard[mode]; + + if (!d) { + qWarning("QClipboard: Cannot transfer data, no data available"); + xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); + return; + } + + if (m_timestamp[mode] == XCB_CURRENT_TIME // we don't own the selection anymore + || (req->time != XCB_CURRENT_TIME && req->time < m_timestamp[mode])) { + qDebug("QClipboard: SelectionRequest too old"); + xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); + return; + } + + xcb_atom_t xa_targets = atom(QXcbAtom::TARGETS); + xcb_atom_t xa_multiple = atom(QXcbAtom::MULTIPLE); + xcb_atom_t xa_timestamp = atom(QXcbAtom::TIMESTAMP); + + struct AtomPair { xcb_atom_t target; xcb_atom_t property; } *multi = 0; + xcb_atom_t multi_type = XCB_NONE; + 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 == XCB_NONE + || !clipboardReadProperty(req->requestor, req->property, false, &multi_data, + 0, &multi_type, &multi_format) + || multi_format != 32) { + // MULTIPLE property not formatted correctly + xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&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) { + xcb_atom_t target; + xcb_atom_t property; + + if (multi) { + target = multi[imulti].target; + property = multi[imulti].property; + } else { + target = req->target; + property = req->property; + if (property == XCB_NONE) // obsolete client + property = target; + } + + xcb_atom_t ret = XCB_NONE; + if (target == XCB_NONE || property == XCB_NONE) { + ; + } else if (target == xa_timestamp) { + if (m_timestamp[mode] != XCB_CURRENT_TIME) { + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, req->requestor, + property, XCB_ATOM_INTEGER, 32, 1, &m_timestamp[mode]); + 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 == XCB_NONE) { + multi[imulti].property = XCB_NONE; + multi_writeback = true; + } + } else { + event.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 + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, req->requestor, req->property, + multi_type, 32, nmulti*2, (const void *)multi); + } + + delete [] multi; + event.property = req->property; + } + + // send selection notify to requestor + xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); +} + +void QXcbClipboard::handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event) +{ + QClipboard::Mode mode = modeForAtom(event->selection); + if (event->owner != owner() && m_clientClipboard[mode] && m_timestamp[mode] < event->selection_timestamp) { + setMimeData(0, mode); + emitChanged(mode); + } +} + + +static inline int maxSelectionIncr(xcb_connection_t *c) +{ + int l = xcb_get_maximum_request_length(c); + return (l > 65536 ? 65536*4 : l*4) - 100; +} + +bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const +{ + int maxsize = maxSelectionIncr(xcb_connection()); + ulong bytes_left; // bytes_after + xcb_atom_t dummy_type; + int dummy_format; + + 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 + xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, win, property, XCB_GET_PROPERTY_TYPE_ANY, 0, 0)); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); + if (!reply || reply->type == XCB_NONE) { + buffer->resize(0); + return false; + } + *type = reply->type; + *format = reply->format; + bytes_left = reply->bytes_after; + free(reply); + + 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... + + xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, win, property, XCB_GET_PROPERTY_TYPE_ANY, offset, maxsize/4)); + reply = xcb_get_property_reply(xcb_connection(), cookie, 0); + if (!reply || reply->type == XCB_NONE) { + free(reply); + break; + } + *type = reply->type; + *format = reply->format; + bytes_left = reply->bytes_after; + char *data = (char *)xcb_get_property_value(reply); + int length = xcb_get_property_value_length(reply); + + 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; + + free(reply); + } + } + + + // correct size, not 0-term. + if (size) + *size = buffer_offset; + + if (deleteProperty) + xcb_delete_property(xcb_connection(), win, property); + + connection()->flush(); + + return ok; +} + + +namespace +{ + class Notify { + public: + Notify(xcb_window_t win, int t) + : window(win), type(t) {} + xcb_window_t window; + int type; + bool check(xcb_generic_event_t *event) const { + if (!event) + return false; + int t = event->response_type & 0x7f; + if (t != type) + return false; + if (t == XCB_PROPERTY_NOTIFY) { + xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + if (pn->window == window) + return true; + } else if (t == XCB_SELECTION_NOTIFY) { + xcb_selection_notify_event_t *sn = (xcb_selection_notify_event_t *)event; + if (sn->requestor == window) + return true; + } + return false; + } + }; + class ClipboardEvent { + public: + ClipboardEvent(QXcbConnection *c) + { clipboard = c->internAtom("CLIPBOARD"); } + xcb_atom_t clipboard; + bool check(xcb_generic_event_t *e) const { + if (!e) + return false; + int type = e->response_type & 0x7f; + if (type == XCB_SELECTION_REQUEST) { + xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)e; + return sr->selection == XCB_ATOM_PRIMARY || sr->selection == clipboard; + } else if (type == XCB_SELECTION_CLEAR) { + xcb_selection_clear_event_t *sc = (xcb_selection_clear_event_t *)e; + return sc->selection == XCB_ATOM_PRIMARY || sc->selection == clipboard; + } + return false; + } + }; +} + +xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t win, int type, int timeout) +{ + QElapsedTimer timer; + timer.start(); + do { + Notify notify(win, type); + xcb_generic_event_t *e = connection()->checkEvent(notify); + if (e) + return e; + + // process other clipboard events, since someone is probably requesting data from us + ClipboardEvent clipboard(connection()); + e = connection()->checkEvent(clipboard); + if (e) { + connection()->handleXcbEvent(e); + free(e); + } + + connection()->flush(); + + // 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 0; +} + +QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm) +{ + 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 (;;) { + connection()->flush(); + xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY, clipboard_timeout); + if (!ge) + break; + + xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge; + if (event->atom != property || event->state != XCB_PROPERTY_NEW_VALUE) + 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; + } + + free(ge); + } + + // 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 QXcbClipboard::getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtAtom) +{ + return getSelection(modeAtom, fmtAtom, atom(QXcbAtom::_QT_SELECTION)); +} + +QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property) +{ + QByteArray buf; + xcb_window_t win = requestor(); + + xcb_delete_property(xcb_connection(), win, property); + xcb_convert_selection(xcb_connection(), win, selection, target, property, connection()->time()); + + connection()->sync(); + + xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_SELECTION_NOTIFY, clipboard_timeout); + bool no_selection = !ge || ((xcb_selection_notify_event_t *)ge)->property == XCB_NONE; + free(ge); + + if (no_selection) + return buf; + + xcb_atom_t type; + if (clipboardReadProperty(win, property, true, &buf, 0, &type, 0)) { + if (type == atom(QXcbAtom::INCR)) { + int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0; + buf = clipboardReadIncrementalProperty(win, property, nbytes, false); + } + } + + return buf; +} + +#include "qxcbclipboard.moc" diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h new file mode 100644 index 0000000000..d23f93529b --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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 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 QXCBCLIPBOARD_H +#define QXCBCLIPBOARD_H + +#include <QPlatformClipboard> +#include <qxcbobject.h> +#include <xcb/xcb.h> +#include <xcb/xfixes.h> + +class QXcbConnection; +class QXcbScreen; +class QXcbClipboardMime; + +class QXcbClipboard : public QXcbObject, public QPlatformClipboard +{ +public: + QXcbClipboard(QXcbConnection *connection); + ~QXcbClipboard(); + + QMimeData *mimeData(QClipboard::Mode mode); + void setMimeData(QMimeData *data, QClipboard::Mode mode); + + bool supportsMode(QClipboard::Mode mode) const; + bool ownsMode(QClipboard::Mode mode) const; + + QXcbScreen *screen() const { return m_screen; } + + xcb_window_t requestor() const; + void setRequestor(xcb_window_t window); + + xcb_window_t owner() const; + + void handleSelectionRequest(xcb_selection_request_event_t *event); + void handleSelectionClearRequest(xcb_selection_clear_event_t *event); + void handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event); + + bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const; + QByteArray clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm); + + QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom); + + xcb_window_t getSelectionOwner(xcb_atom_t atom) const; + QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property); + +private: + xcb_generic_event_t *waitForClipboardEvent(xcb_window_t win, int type, int timeout); + + xcb_atom_t sendTargetsSelection(QMimeData *d, xcb_window_t window, xcb_atom_t property); + xcb_atom_t sendSelection(QMimeData *d, xcb_atom_t target, xcb_window_t window, xcb_atom_t property); + + xcb_atom_t atomForMode(QClipboard::Mode mode) const; + QClipboard::Mode modeForAtom(xcb_atom_t atom) const; + + QXcbScreen *m_screen; + + // Selection and Clipboard + QXcbClipboardMime *m_xClipboard[2]; + QMimeData *m_clientClipboard[2]; + xcb_timestamp_t m_timestamp[2]; + + xcb_window_t m_requestor; + xcb_window_t m_owner; + + static const int clipboard_timeout; + +}; + +#endif // QXCBCLIPBOARD_H diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 80a1624380..a0b894602d 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -39,33 +39,41 @@ ** ****************************************************************************/ +#include <QtGui/private/qguiapplication_p.h> +#include <QtCore/QDebug> + #include "qxcbconnection.h" #include "qxcbkeyboard.h" #include "qxcbscreen.h" #include "qxcbwindow.h" +#include "qxcbclipboard.h" +#include "qxcbdrag.h" +#include "qxcbwmsupport.h" #include <QtAlgorithms> #include <QSocketNotifier> -#include <QtGui/private/qapplication_p.h> #include <QAbstractEventDispatcher> - -#include <QtCore/QDebug> +#include <QTimer> #include <stdio.h> #include <errno.h> +#include <xcb/xfixes.h> #ifdef XCB_USE_XLIB #include <X11/Xlib.h> #include <X11/Xlib-xcb.h> #endif +#ifdef XCB_USE_RENDER +#include <xcb/render.h> +#endif + #ifdef XCB_USE_EGL //dont pull in eglext prototypes #include <EGL/egl.h> #endif #ifdef XCB_USE_DRI2 #include <xcb/dri2.h> -#include <xcb/xfixes.h> extern "C" { #include <xf86drm.h> } @@ -83,12 +91,13 @@ QXcbConnection::QXcbConnection(const char *displayName) , m_dri2_support_probed(false) , m_has_support_for_dri2(false) #endif + , xfixes_first_event(0) { - int primaryScreen = 0; + m_primaryScreen = 0; #ifdef XCB_USE_XLIB Display *dpy = XOpenDisplay(m_displayName.constData()); - primaryScreen = DefaultScreen(dpy); + m_primaryScreen = DefaultScreen(dpy); m_connection = XGetXCBConnection(dpy); XSetEventQueueOwner(dpy, XCBOwnsEventQueue); m_xlib_display = dpy; @@ -100,13 +109,33 @@ QXcbConnection::QXcbConnection(const char *displayName) m_has_egl = eglInitialize(eglDisplay,&major,&minor); #endif //XCB_USE_EGL #else - m_connection = xcb_connect(m_displayName.constData(), &primaryScreen); - + m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreen); #endif //XCB_USE_XLIB + + if (m_connection) + printf("Successfully connected to display %s\n", m_displayName.constData()); + + m_reader = new QXcbEventReader(m_connection); +#ifdef XCB_POLL_FOR_QUEUED_EVENT + connect(m_reader, SIGNAL(eventPending()), this, SLOT(processXcbEvents()), Qt::QueuedConnection); + m_reader->start(); +#else + QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents())); + + QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; + connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents())); + connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents())); +#endif + + xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id); + m_setup = xcb_get_setup(xcb_connection()); initializeAllAtoms(); + m_time = XCB_CURRENT_TIME; + xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup); int screenNumber = 0; @@ -115,25 +144,38 @@ QXcbConnection::QXcbConnection(const char *displayName) xcb_screen_next(&it); } + m_connectionEventListener = xcb_generate_id(m_connection); + xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, + m_connectionEventListener, m_screens.at(0)->root(), + 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, + m_screens.at(0)->screen()->root_visual, 0, 0); + + initializeXFixes(); + initializeXRender(); + + m_wmSupport = new QXcbWMSupport(this); m_keyboard = new QXcbKeyboard(this); + m_clipboard = new QXcbClipboard(this); + m_drag = new QXcbDrag(this); #ifdef XCB_USE_DRI2 initializeDri2(); #endif - - QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this); - connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents())); - - QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); - connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents())); - sync(); } QXcbConnection::~QXcbConnection() { + delete m_clipboard; + qDeleteAll(m_screens); +#ifdef XCB_POLL_FOR_QUEUED_EVENT + sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION); + m_reader->wait(); +#endif + delete m_reader; + #ifdef XCB_USE_XLIB XCloseDisplay((Display *)m_xlib_display); #else @@ -143,22 +185,26 @@ QXcbConnection::~QXcbConnection() delete m_keyboard; } -QXcbWindow *platformWindowFromId(xcb_window_t id) +void QXcbConnection::addWindow(xcb_window_t id, QXcbWindow *window) { - QWidget *widget = QWidget::find(id); - if (widget) - return static_cast<QXcbWindow *>(widget->platformWindow()); - return 0; + m_mapper.insert(id, window); +} + +void QXcbConnection::removeWindow(xcb_window_t id) +{ + m_mapper.remove(id); +} + +QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id) +{ + return m_mapper.value(id, 0); } -#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, window, handler) \ +#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \ { \ event_t *e = (event_t *)event; \ - if (QXcbWindow *platformWindow = platformWindowFromId(e->window)) { \ - QObjectPrivate *d = QObjectPrivate::get(platformWindow->widget()); \ - if (!d->wasDeleted) \ - platformWindow->handler(e); \ - } \ + if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember)) \ + platformWindow->handler(e); \ } \ break; @@ -166,7 +212,7 @@ break; { \ event_t *e = (event_t *)event; \ if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) \ - m_keyboard->handler(platformWindow->widget(), e); \ + m_keyboard->handler(platformWindow, e); \ } \ break; @@ -373,6 +419,7 @@ const char *xcb_protocol_request_codes[] = #ifdef Q_XCB_DEBUG void QXcbConnection::log(const char *file, int line, int sequence) { + QMutexLocker locker(&m_callLogMutex); CallInfo info; info.sequence = sequence; info.file = file; @@ -392,6 +439,7 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error) int(error->major_code), xcb_protocol_request_codes[clamped_major_code], int(error->minor_code)); #ifdef Q_XCB_DEBUG + QMutexLocker locker(&m_callLogMutex); int i = 0; for (; i < m_callLog.size(); ++i) { if (m_callLog.at(i).sequence == error->sequence) { @@ -409,67 +457,236 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error) #endif } +void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) +{ +#ifdef Q_XCB_DEBUG + { + QMutexLocker locker(&m_callLogMutex); + int i = 0; + for (; i < m_callLog.size(); ++i) + if (m_callLog.at(i).sequence >= event->sequence) + break; + m_callLog.remove(0, i); + } +#endif + bool handled = true; + + uint response_type = event->response_type & ~0x80; + + switch (response_type) { + case XCB_EXPOSE: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); + case XCB_BUTTON_PRESS: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); + case XCB_BUTTON_RELEASE: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); + case XCB_MOTION_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); + case XCB_CONFIGURE_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); + case XCB_MAP_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent); + case XCB_UNMAP_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent); + case XCB_CLIENT_MESSAGE: + handleClientMessageEvent((xcb_client_message_event_t *)event); + case XCB_ENTER_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); + case XCB_LEAVE_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent); + case XCB_FOCUS_IN: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent); + case XCB_FOCUS_OUT: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent); + case XCB_KEY_PRESS: + HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent); + case XCB_KEY_RELEASE: + HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); + case XCB_MAPPING_NOTIFY: + m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event); + break; + case XCB_SELECTION_REQUEST: + { + xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event; + if (sr->selection == atom(QXcbAtom::XdndSelection)) + m_drag->handleSelectionRequest(sr); + else + m_clipboard->handleSelectionRequest(sr); + break; + } + case XCB_SELECTION_CLEAR: + setTime(((xcb_selection_clear_event_t *)event)->time); + m_clipboard->handleSelectionClearRequest((xcb_selection_clear_event_t *)event); + handled = true; + break; + case XCB_SELECTION_NOTIFY: + setTime(((xcb_selection_notify_event_t *)event)->time); + qDebug() << "XCB_SELECTION_NOTIFY"; + handled = false; + break; + case XCB_PROPERTY_NOTIFY: + setTime(((xcb_property_notify_event_t *)event)->time); +// qDebug() << "XCB_PROPERTY_NOTIFY"; + handled = false; + break; + default: + handled = false; + break; + } + + if (!handled) { + if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) { + setTime(((xcb_xfixes_selection_notify_event_t *)event)->timestamp); + m_clipboard->handleXFixesSelectionRequest((xcb_xfixes_selection_notify_event_t *)event); + handled = true; + } + } + + if (handled) + printXcbEvent("Handled XCB event", event); + else + printXcbEvent("Unhandled XCB event", event); +} + +void QXcbConnection::addPeekFunc(PeekFunc f) +{ + m_peekFuncs.append(f); +} + +#ifdef XCB_POLL_FOR_QUEUED_EVENT +void QXcbEventReader::run() +{ + xcb_generic_event_t *event; + while (m_connection && (event = xcb_wait_for_event(m_connection))) { + m_mutex.lock(); + addEvent(event); + while (m_connection && (event = xcb_poll_for_queued_event(m_connection))) + addEvent(event); + m_mutex.unlock(); + emit eventPending(); + } + + for (int i = 0; i < m_events.size(); ++i) + free(m_events.at(i)); +} +#endif + +void QXcbEventReader::addEvent(xcb_generic_event_t *event) +{ + if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE + && ((xcb_client_message_event_t *)event)->type == QXcbAtom::_QT_CLOSE_CONNECTION) + m_connection = 0; + m_events << event; +} + +QList<xcb_generic_event_t *> *QXcbEventReader::lock() +{ + m_mutex.lock(); +#ifndef XCB_POLL_FOR_QUEUED_EVENT + while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection)) + m_events << event; +#endif + return &m_events; +} + +void QXcbEventReader::unlock() +{ + m_mutex.unlock(); +} + +void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom atom, uint id) +{ + xcb_client_message_event_t event; + memset(&event, 0, sizeof(event)); + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.sequence = 0; + event.window = m_connectionEventListener; + event.type = atom; + event.data.data32[0] = id; + + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event)); + xcb_flush(xcb_connection()); +} + void QXcbConnection::processXcbEvents() { - while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) { - bool handled = true; + QList<xcb_generic_event_t *> *eventqueue = m_reader->lock(); + + for(int i = 0; i < eventqueue->size(); ++i) { + xcb_generic_event_t *event = eventqueue->at(i); + if (!event) + continue; + (*eventqueue)[i] = 0; uint response_type = event->response_type & ~0x80; if (!response_type) { handleXcbError((xcb_generic_error_t *)event); - continue; + } else { + QVector<PeekFunc>::iterator it = m_peekFuncs.begin(); + while (it != m_peekFuncs.end()) { + // These callbacks return true if the event is what they were + // waiting for, remove them from the list in that case. + if ((*it)(event)) + it = m_peekFuncs.erase(it); + else + ++it; + } + handleXcbEvent(event); } -#ifdef Q_XCB_DEBUG - { - int i = 0; - for (; i < m_callLog.size(); ++i) - if (m_callLog.at(i).sequence >= event->sequence) - break; - m_callLog.remove(0, i); - } -#endif + free(event); + } - switch (response_type) { - case XCB_EXPOSE: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); - case XCB_BUTTON_PRESS: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); - case XCB_BUTTON_RELEASE: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); - case XCB_MOTION_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); - case XCB_CONFIGURE_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); - case XCB_CLIENT_MESSAGE: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent); - case XCB_ENTER_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); - case XCB_LEAVE_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent); - case XCB_FOCUS_IN: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent); - case XCB_FOCUS_OUT: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent); - case XCB_KEY_PRESS: - HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent); - case XCB_KEY_RELEASE: - HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); - case XCB_MAPPING_NOTIFY: - m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event); - break; - default: - handled = false; - break; + eventqueue->clear(); + + m_reader->unlock(); + + // Indicate with a null event that the event the callbacks are waiting for + // is not in the queue currently. + Q_FOREACH (PeekFunc f, m_peekFuncs) + f(0); + m_peekFuncs.clear(); + + xcb_flush(xcb_connection()); +} + +void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *event) +{ + if (event->format != 32) + return; + + if (event->type == atom(QXcbAtom::XdndStatus)) { + drag()->handleStatus(event, false); + } else if (event->type == atom(QXcbAtom::XdndFinished)) { + drag()->handleFinished(event, false); + } + + QXcbWindow *window = platformWindowFromId(event->window); + if (!window) + return; + + window->handleClientMessageEvent(event); +} + +xcb_generic_event_t *QXcbConnection::checkEvent(int type) +{ + QList<xcb_generic_event_t *> *eventqueue = m_reader->lock(); + + for (int i = 0; i < eventqueue->size(); ++i) { + xcb_generic_event_t *event = eventqueue->at(i); + if (event->response_type == type) { + (*eventqueue)[i] = 0; + m_reader->unlock(); + return event; } - if (handled) - printXcbEvent("Handled XCB event", event); - else - printXcbEvent("Unhandled XCB event", event); } - xcb_flush(xcb_connection()); + m_reader->unlock(); + + return 0; } static const char * xcb_atomnames = { @@ -511,6 +728,8 @@ static const char * xcb_atomnames = { "_QT_SCROLL_DONE\0" "_QT_INPUT_ENCODING\0" + "_QT_CLOSE_CONNECTION\0" + "_MOTIF_WM_HINTS\0" "DTWM_IS_RUNNING\0" @@ -579,7 +798,6 @@ static const char * xcb_atomnames = { "_NET_ACTIVE_WINDOW\0" // Property formats - "COMPOUND_TEXT\0" "TEXT\0" "UTF8_STRING\0" @@ -659,8 +877,57 @@ void QXcbConnection::initializeAllAtoms() { for (i = 0; i < QXcbAtom::NAtoms; ++i) cookies[i] = xcb_intern_atom(xcb_connection(), false, strlen(names[i]), names[i]); - for (i = 0; i < QXcbAtom::NAtoms; ++i) - m_allAtoms[i] = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0)->atom; + for (i = 0; i < QXcbAtom::NAtoms; ++i) { + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0); + m_allAtoms[i] = reply->atom; + free(reply); + } +} + +xcb_atom_t QXcbConnection::internAtom(const char *name) +{ + if (!name || *name == 0) + return XCB_NONE; + + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xcb_connection(), false, strlen(name), name); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookie, 0); + int atom = reply->atom; + free(reply); + return atom; +} + +QByteArray QXcbConnection::atomName(xcb_atom_t atom) +{ + if (!atom) + return QByteArray(); + + xcb_generic_error_t *error = 0; + xcb_get_atom_name_cookie_t cookie = Q_XCB_CALL(xcb_get_atom_name(xcb_connection(), atom)); + xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(xcb_connection(), cookie, &error); + if (error) { + qWarning() << "QXcbConnection::atomName: bad Atom" << atom; + } + if (reply) { + QByteArray result(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply)); + free(reply); + return result; + } + return QByteArray(); +} + +const xcb_format_t *QXcbConnection::formatForDepth(uint8_t depth) const +{ + xcb_format_iterator_t iterator = + xcb_setup_pixmap_formats_iterator(m_setup); + + while (iterator.rem) { + xcb_format_t *format = iterator.data; + if (format->depth == depth) + return format; + xcb_format_next(&iterator); + } + + return 0; } void QXcbConnection::sync() @@ -670,6 +937,43 @@ void QXcbConnection::sync() free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0)); } +void QXcbConnection::initializeXFixes() +{ + xcb_generic_error_t *error = 0; + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id); + xfixes_first_event = reply->first_event; + + xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection, + XCB_XFIXES_MAJOR_VERSION, + XCB_XFIXES_MINOR_VERSION); + xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection, + xfixes_query_cookie, &error); + if (!xfixes_query || error || xfixes_query->major_version < 2) { + qWarning("Failed to initialize XFixes"); + free(error); + xfixes_first_event = 0; + } + free(xfixes_query); + +} + +void QXcbConnection::initializeXRender() +{ +#ifdef XCB_USE_RENDER + xcb_generic_error_t *error = 0; + xcb_render_query_version_cookie_t xrender_query_cookie = xcb_render_query_version(m_connection, + XCB_RENDER_MAJOR_VERSION, + XCB_RENDER_MINOR_VERSION); + xcb_render_query_version_reply_t *xrender_query = xcb_render_query_version_reply(m_connection, + xrender_query_cookie, &error); + if (!xrender_query || error || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) { + qWarning("Failed to initialize XRender"); + free(error); + } + free(xrender_query); +#endif +} + #if defined(XCB_USE_EGL) bool QXcbConnection::hasEgl() const { @@ -740,26 +1044,12 @@ bool QXcbConnection::hasSupportForDri2() const if (!m_dri2_support_probed) { xcb_generic_error_t *error = 0; - xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id); xcb_prefetch_extension_data (m_connection, &xcb_dri2_id); - xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection, - XCB_XFIXES_MAJOR_VERSION, - XCB_XFIXES_MINOR_VERSION); - xcb_dri2_query_version_cookie_t dri2_query_cookie = xcb_dri2_query_version (m_connection, XCB_DRI2_MAJOR_VERSION, XCB_DRI2_MINOR_VERSION); - xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection, - xfixes_query_cookie, &error); - if (!xfixes_query || error || xfixes_query->major_version < 2) { - delete error; - delete xfixes_query; - return false; - } - delete xfixes_query; - xcb_dri2_query_version_reply_t *dri2_query = xcb_dri2_query_version_reply (m_connection, dri2_query_cookie, &error); if (!dri2_query || error) { diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 01bc719546..6d93093072 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -44,13 +44,23 @@ #include <xcb/xcb.h> +#include <QHash> #include <QList> +#include <QMutex> #include <QObject> +#include <QThread> #include <QVector> #define Q_XCB_DEBUG class QXcbScreen; +class QXcbWindow; +class QXcbDrag; +class QXcbKeyboard; +class QXcbClipboard; +class QXcbWMSupport; + +typedef QHash<xcb_window_t, QXcbWindow *> WindowMapper; namespace QXcbAtom { enum Atom { @@ -92,6 +102,9 @@ namespace QXcbAtom { _QT_SCROLL_DONE, _QT_INPUT_ENCODING, + // Qt/XCB specific + _QT_CLOSE_CONNECTION, + _MOTIF_WM_HINTS, DTWM_IS_RUNNING, @@ -160,7 +173,6 @@ namespace QXcbAtom { _NET_ACTIVE_WINDOW, // Property formats - COMPOUND_TEXT, TEXT, UTF8_STRING, @@ -215,8 +227,34 @@ namespace QXcbAtom { }; } -class QXcbKeyboard; +class QXcbEventReader : public QThread +{ + Q_OBJECT +public: + QXcbEventReader(xcb_connection_t *connection) + : m_connection(connection) + { + } + +#ifdef XCB_POLL_FOR_QUEUED_EVENT + void run(); +#endif + QList<xcb_generic_event_t *> *lock(); + void unlock(); + +signals: + void eventPending(); + +private: + void addEvent(xcb_generic_event_t *event); + + QMutex m_mutex; + QList<xcb_generic_event_t *> m_events; + xcb_connection_t *m_connection; +}; + +class QAbstractEventDispatcher; class QXcbConnection : public QObject { Q_OBJECT @@ -226,17 +264,26 @@ public: QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); } - QList<QXcbScreen *> screens() const { return m_screens; } + const QList<QXcbScreen *> &screens() const { return m_screens; } int primaryScreen() const { return m_primaryScreen; } xcb_atom_t atom(QXcbAtom::Atom atom); + xcb_atom_t internAtom(const char *name); + QByteArray atomName(xcb_atom_t atom); const char *displayName() const { return m_displayName.constData(); } xcb_connection_t *xcb_connection() const { return m_connection; } + const xcb_setup_t *setup() const { return m_setup; } + const xcb_format_t *formatForDepth(uint8_t depth) const; QXcbKeyboard *keyboard() const { return m_keyboard; } + QXcbClipboard *clipboard() const { return m_clipboard; } + QXcbDrag *drag() const { return m_drag; } + + QXcbWMSupport *wmSupport() const { return m_wmSupport; } + #ifdef XCB_USE_XLIB void *xlib_display() const { return m_xlib_display; } #endif @@ -253,7 +300,26 @@ public: #endif void sync(); + void flush() { xcb_flush(m_connection); } + void handleXcbError(xcb_generic_error_t *error); + void handleXcbEvent(xcb_generic_event_t *event); + + void addWindow(xcb_window_t id, QXcbWindow *window); + void removeWindow(xcb_window_t id); + QXcbWindow *platformWindowFromId(xcb_window_t id); + + xcb_generic_event_t *checkEvent(int type); + template<typename T> + inline xcb_generic_event_t *checkEvent(const T &checker); + + typedef bool (*PeekFunc)(xcb_generic_event_t *); + void addPeekFunc(PeekFunc f); + + inline xcb_timestamp_t time() const { return m_time; } + inline void setTime(xcb_timestamp_t t) { if (t > m_time) m_time = t; } + + bool hasXFixes() const { return xfixes_first_event > 0; } private slots: void processXcbEvents(); @@ -261,9 +327,12 @@ private slots: private: void initializeAllAtoms(); void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0); + void initializeXFixes(); + void initializeXRender(); #ifdef XCB_USE_DRI2 void initializeDri2(); #endif + void handleClientMessageEvent(const xcb_client_message_event_t *event); xcb_connection_t *m_connection; const xcb_setup_t *m_setup; @@ -273,14 +342,21 @@ private: xcb_atom_t m_allAtoms[QXcbAtom::NAtoms]; + xcb_timestamp_t m_time; + QByteArray m_displayName; + xcb_window_t m_connectionEventListener; + QXcbKeyboard *m_keyboard; + QXcbClipboard *m_clipboard; + QXcbDrag *m_drag; + QXcbWMSupport *m_wmSupport; #if defined(XCB_USE_XLIB) void *m_xlib_display; #endif - + QXcbEventReader *m_reader; #ifdef XCB_USE_DRI2 uint32_t m_dri2_major; uint32_t m_dri2_minor; @@ -299,14 +375,39 @@ private: int line; }; QVector<CallInfo> m_callLog; + QMutex m_callLogMutex; void log(const char *file, int line, int sequence); template <typename cookie_t> friend cookie_t q_xcb_call_template(const cookie_t &cookie, QXcbConnection *connection, const char *file, int line); #endif + + WindowMapper m_mapper; + + QVector<PeekFunc> m_peekFuncs; + + uint32_t xfixes_first_event; }; #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) +template<typename T> +xcb_generic_event_t *QXcbConnection::checkEvent(const T &checker) +{ + QList<xcb_generic_event_t *> *eventqueue = m_reader->lock(); + + for (int i = 0; i < eventqueue->size(); ++i) { + xcb_generic_event_t *event = eventqueue->at(i); + if (checker.check(event)) { + (*eventqueue)[i] = 0; + m_reader->unlock(); + return event; + } + } + m_reader->unlock(); + return 0; +} + + #ifdef Q_XCB_DEBUG template <typename cookie_t> cookie_t q_xcb_call_template(const cookie_t &cookie, QXcbConnection *connection, const char *file, int line) diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp new file mode 100644 index 0000000000..f6856d5694 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -0,0 +1,546 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbcursor.h" +#include "qxcbconnection.h" +#include "qxcbwindow.h" +#include "qxcbimage.h" +#include <QtCore/QLibrary> +#include <QtGui/QWindow> +#include <QtGui/QBitmap> +#include <QtGui/private/qguiapplication_p.h> +#include <X11/cursorfont.h> +#include <xcb/xfixes.h> +#include <xcb/xcb_image.h> + +QT_BEGIN_NAMESPACE + +typedef int (*PtrXcursorLibraryLoadCursor)(void *, const char *); +static PtrXcursorLibraryLoadCursor ptrXcursorLibraryLoadCursor = 0; +static xcb_font_t cursorFont = 0; +static int cursorCount = 0; + +static uint8_t cur_blank_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const uint8_t cur_ver_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xf0, 0x0f, + 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00 }; +static const uint8_t mcur_ver_bits[] = { + 0x00, 0x00, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, + 0xfc, 0x7f, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xfc, 0x7f, 0xf8, 0x3f, + 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03 }; +static const uint8_t cur_hor_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x30, 0x18, + 0x38, 0x38, 0xfc, 0x7f, 0xfc, 0x7f, 0x38, 0x38, 0x30, 0x18, 0x20, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t mcur_hor_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x60, 0x0c, 0x70, 0x1c, 0x78, 0x3c, + 0xfc, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0x7f, 0x78, 0x3c, + 0x70, 0x1c, 0x60, 0x0c, 0x40, 0x04, 0x00, 0x00 }; +static const uint8_t cur_bdiag_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x3e, + 0x00, 0x37, 0x88, 0x23, 0xd8, 0x01, 0xf8, 0x00, 0x78, 0x00, 0xf8, 0x00, + 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t mcur_bdiag_bits[] = { + 0x00, 0x00, 0xc0, 0x7f, 0x80, 0x7f, 0x00, 0x7f, 0x00, 0x7e, 0x04, 0x7f, + 0x8c, 0x7f, 0xdc, 0x77, 0xfc, 0x63, 0xfc, 0x41, 0xfc, 0x00, 0xfc, 0x01, + 0xfc, 0x03, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t cur_fdiag_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0xf8, 0x00, 0x78, 0x00, + 0xf8, 0x00, 0xd8, 0x01, 0x88, 0x23, 0x00, 0x37, 0x00, 0x3e, 0x00, 0x3c, + 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t mcur_fdiag_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x01, 0xfc, 0x00, + 0xfc, 0x41, 0xfc, 0x63, 0xdc, 0x77, 0x8c, 0x7f, 0x04, 0x7f, 0x00, 0x7e, + 0x00, 0x7f, 0x80, 0x7f, 0xc0, 0x7f, 0x00, 0x00 }; +static const uint8_t *cursor_bits16[] = { + cur_ver_bits, mcur_ver_bits, cur_hor_bits, mcur_hor_bits, + cur_bdiag_bits, mcur_bdiag_bits, cur_fdiag_bits, mcur_fdiag_bits, + 0, 0, cur_blank_bits, cur_blank_bits }; + +static const uint8_t vsplit_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t vsplitm_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00, + 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, + 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t hsplit_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03, + 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t hsplitm_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, + 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00, + 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07, + 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00, + 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, + 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t whatsthis_bits[] = { + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0xf0, 0x07, 0x00, + 0x09, 0x18, 0x0e, 0x00, 0x11, 0x1c, 0x0e, 0x00, 0x21, 0x1c, 0x0e, 0x00, + 0x41, 0x1c, 0x0e, 0x00, 0x81, 0x1c, 0x0e, 0x00, 0x01, 0x01, 0x07, 0x00, + 0x01, 0x82, 0x03, 0x00, 0xc1, 0xc7, 0x01, 0x00, 0x49, 0xc0, 0x01, 0x00, + 0x95, 0xc0, 0x01, 0x00, 0x93, 0xc0, 0x01, 0x00, 0x21, 0x01, 0x00, 0x00, + 0x20, 0xc1, 0x01, 0x00, 0x40, 0xc2, 0x01, 0x00, 0x40, 0x02, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static const uint8_t whatsthism_bits[] = { + 0x01, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x07, 0x00, 0x07, 0xf8, 0x0f, 0x00, + 0x0f, 0xfc, 0x1f, 0x00, 0x1f, 0x3e, 0x1f, 0x00, 0x3f, 0x3e, 0x1f, 0x00, + 0x7f, 0x3e, 0x1f, 0x00, 0xff, 0x3e, 0x1f, 0x00, 0xff, 0x9d, 0x0f, 0x00, + 0xff, 0xc3, 0x07, 0x00, 0xff, 0xe7, 0x03, 0x00, 0x7f, 0xe0, 0x03, 0x00, + 0xf7, 0xe0, 0x03, 0x00, 0xf3, 0xe0, 0x03, 0x00, 0xe1, 0xe1, 0x03, 0x00, + 0xe0, 0xe1, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static const uint8_t busy_bits[] = { + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x41, 0xe0, 0xff, 0x00, 0x81, 0x20, 0x80, 0x00, 0x01, 0xe1, 0xff, 0x00, + 0x01, 0x42, 0x40, 0x00, 0xc1, 0x47, 0x40, 0x00, 0x49, 0x40, 0x55, 0x00, + 0x95, 0x80, 0x2a, 0x00, 0x93, 0x00, 0x15, 0x00, 0x21, 0x01, 0x0a, 0x00, + 0x20, 0x01, 0x11, 0x00, 0x40, 0x82, 0x20, 0x00, 0x40, 0x42, 0x44, 0x00, + 0x80, 0x41, 0x4a, 0x00, 0x00, 0x40, 0x55, 0x00, 0x00, 0xe0, 0xff, 0x00, + 0x00, 0x20, 0x80, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t busym_bits[] = { + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, + 0x7f, 0xe0, 0xff, 0x00, 0xff, 0xe0, 0xff, 0x00, 0xff, 0xe1, 0xff, 0x00, + 0xff, 0xc3, 0x7f, 0x00, 0xff, 0xc7, 0x7f, 0x00, 0x7f, 0xc0, 0x7f, 0x00, + 0xf7, 0x80, 0x3f, 0x00, 0xf3, 0x00, 0x1f, 0x00, 0xe1, 0x01, 0x0e, 0x00, + 0xe0, 0x01, 0x1f, 0x00, 0xc0, 0x83, 0x3f, 0x00, 0xc0, 0xc3, 0x7f, 0x00, + 0x80, 0xc1, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00, + 0x00, 0xe0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t * const cursor_bits32[] = { + vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits, + 0, 0, 0, 0, whatsthis_bits, whatsthism_bits, busy_bits, busym_bits +}; + +static const uint8_t forbidden_bits[] = { + 0x00,0x00,0x00,0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xf0,0x00,0x38,0xc0,0x01, + 0x7c,0x80,0x03,0xec,0x00,0x03,0xce,0x01,0x07,0x86,0x03,0x06,0x06,0x07,0x06, + 0x06,0x0e,0x06,0x06,0x1c,0x06,0x0e,0x38,0x07,0x0c,0x70,0x03,0x1c,0xe0,0x03, + 0x38,0xc0,0x01,0xf0,0xe0,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00,0x00,0x00,0x00 }; + +static const uint8_t forbiddenm_bits[] = { + 0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xff,0x00,0xf8,0xff,0x01,0xfc,0xf0,0x03, + 0xfe,0xc0,0x07,0xfe,0x81,0x07,0xff,0x83,0x0f,0xcf,0x07,0x0f,0x8f,0x0f,0x0f, + 0x0f,0x1f,0x0f,0x0f,0x3e,0x0f,0x1f,0xfc,0x0f,0x1e,0xf8,0x07,0x3e,0xf0,0x07, + 0xfc,0xe0,0x03,0xf8,0xff,0x01,0xf0,0xff,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00}; + +static const uint8_t openhand_bits[] = { + 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92, + 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20, + 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00}; +static const uint8_t openhandm_bits[] = { + 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff, + 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f, + 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00}; +static const uint8_t closedhand_bits[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50, + 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10, + 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00}; +static const uint8_t closedhandm_bits[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f, + 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f, + 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00}; + +static const uint8_t * const cursor_bits20[] = { + forbidden_bits, forbiddenm_bits +}; + +static const char * const cursorNames[] = { + "left_ptr", + "up_arrow", + "cross", + "wait", + "ibeam", + "size_ver", + "size_hor", + "size_bdiag", + "size_fdiag", + "size_all", + "blank", + "split_v", + "split_h", + "pointing_hand", + "forbidden", + "whats_this", + "left_ptr_watch", + "openhand", + "closedhand", + "copy", + "move", + "link" +}; + +QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen) + : QXcbObject(conn), QPlatformCursor(screen), m_screen(screen) +{ + if (cursorCount++) + return; + + cursorFont = xcb_generate_id(xcb_connection()); + const char *cursorStr = "cursor"; + xcb_open_font(xcb_connection(), cursorFont, strlen(cursorStr), cursorStr); + +#ifdef XCB_USE_XLIB + QLibrary xcursorLib(QLatin1String("Xcursor"), 1); + bool xcursorFound = xcursorLib.load(); + if (!xcursorFound) { // try without the version number + xcursorLib.setFileName(QLatin1String("Xcursor")); + xcursorFound = xcursorLib.load(); + } + if (xcursorFound) + ptrXcursorLibraryLoadCursor = + (PtrXcursorLibraryLoadCursor) xcursorLib.resolve("XcursorLibraryLoadCursor"); +#endif +} + +QXcbCursor::~QXcbCursor() +{ + if (!--cursorCount) + xcb_close_font(xcb_connection(), cursorFont); +} + +void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget) +{ + QXcbWindow *w = 0; + if (widget && widget->handle()) + w = static_cast<QXcbWindow *>(widget->handle()); + else + // No X11 cursor control when there is no widget under the cursor + return; + + xcb_cursor_t c; + if (cursor->shape() == Qt::BitmapCursor) { + qint64 id = cursor->pixmap().cacheKey(); + if (!m_bitmapCursorMap.contains(id)) + m_bitmapCursorMap.insert(id, createBitmapCursor(cursor)); + c = m_bitmapCursorMap.value(id); + } else { + int id = cursor->handle(); + if (!m_shapeCursorMap.contains(id)) + m_shapeCursorMap.insert(id, createFontCursor(cursor->shape())); + c = m_shapeCursorMap.value(id); + } + + w->setCursor(c); +} + +static int cursorIdForShape(int cshape) +{ + int cursorId = 0; + switch (cshape) { + case Qt::ArrowCursor: + cursorId = XC_left_ptr; + break; + case Qt::UpArrowCursor: + cursorId = XC_center_ptr; + break; + case Qt::CrossCursor: + cursorId = XC_crosshair; + break; + case Qt::WaitCursor: + cursorId = XC_watch; + break; + case Qt::IBeamCursor: + cursorId = XC_xterm; + break; + case Qt::SizeAllCursor: + cursorId = XC_fleur; + break; + case Qt::PointingHandCursor: + cursorId = XC_hand2; + break; + case Qt::SizeBDiagCursor: + cursorId = XC_top_right_corner; + break; + case Qt::SizeFDiagCursor: + cursorId = XC_bottom_right_corner; + break; + case Qt::SizeVerCursor: + case Qt::SplitVCursor: + cursorId = XC_sb_v_double_arrow; + break; + case Qt::SizeHorCursor: + case Qt::SplitHCursor: + cursorId = XC_sb_h_double_arrow; + break; + case Qt::WhatsThisCursor: + cursorId = XC_question_arrow; + break; + case Qt::ForbiddenCursor: + cursorId = XC_circle; + break; + case Qt::BusyCursor: + cursorId = XC_watch; + break; + default: + break; + } + return cursorId; +} + +xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape) +{ + xcb_cursor_t cursor = 0; + xcb_connection_t *conn = xcb_connection(); + + if (cshape == Qt::BlankCursor) { + xcb_pixmap_t cp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16, + 1, 0, 0, 0); + xcb_pixmap_t mp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16, + 1, 0, 0, 0); + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8); + } else if (cshape >= Qt::SizeVerCursor && cshape < Qt::SizeAllCursor) { + int i = (cshape - Qt::SizeVerCursor) * 2; + xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits16[i]), + 16, 16, 1, 0, 0, 0); + xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits16[i + 1]), + 16, 16, 1, 0, 0, 0); + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8); + } else if ((cshape >= Qt::SplitVCursor && cshape <= Qt::SplitHCursor) + || cshape == Qt::WhatsThisCursor || cshape == Qt::BusyCursor) { + int i = (cshape - Qt::SplitVCursor) * 2; + xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits32[i]), + 32, 32, 1, 0, 0, 0); + xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits32[i + 1]), + 32, 32, 1, 0, 0, 0); + int hs = (cshape == Qt::PointingHandCursor || cshape == Qt::WhatsThisCursor + || cshape == Qt::BusyCursor) ? 0 : 16; + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, hs, hs); + } else if (cshape == Qt::ForbiddenCursor) { + int i = (cshape - Qt::ForbiddenCursor) * 2; + xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits20[i]), + 20, 20, 1, 0, 0, 0); + xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits20[i + 1]), + 20, 20, 1, 0, 0, 0); + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 10, 10); + } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) { + bool open = cshape == Qt::OpenHandCursor; + xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(open ? openhand_bits : closedhand_bits), + 16, 16, 1, 0, 0, 0); + xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(open ? openhandm_bits : closedhandm_bits), + 16, 16, 1, 0, 0, 0); + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8); + } else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor + || cshape == Qt::DragLinkCursor) { + QImage image = QGuiApplicationPrivate::instance()->getPixmapCursor(static_cast<Qt::CursorShape>(cshape)).toImage(); + xcb_pixmap_t pm = qt_xcb_XPixmapFromBitmap(m_screen, image); + xcb_pixmap_t pmm = qt_xcb_XPixmapFromBitmap(m_screen, image.createAlphaMask()); + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8); + } + + return cursor; +} + +xcb_cursor_t QXcbCursor::createFontCursor(int cshape) +{ + xcb_connection_t *conn = xcb_connection(); + int cursorId = cursorIdForShape(cshape); + xcb_cursor_t cursor = XCB_NONE; + + // Try Xcursor first +#ifdef XCB_USE_XLIB + if (ptrXcursorLibraryLoadCursor && cshape >= 0 && cshape < Qt::LastCursor) { + void *dpy = connection()->xlib_display(); + // special case for non-standard dnd-* cursors + switch (cshape) { + case Qt::DragCopyCursor: + cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-copy"); + break; + case Qt::DragMoveCursor: + cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-move"); + break; + case Qt::DragLinkCursor: + cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-link"); + break; + default: + break; + } + if (!cursor) + cursor = ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]); + } + if (cursor) + return cursor; +#endif + + // Non-standard X11 cursors are created from bitmaps + cursor = createNonStandardCursor(cshape); + + // Create a glpyh cursor if everything else failed + if (!cursor && cursorId) { + cursor = xcb_generate_id(conn); + xcb_create_glyph_cursor(conn, cursor, cursorFont, cursorFont, + cursorId, cursorId + 1, + 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0); + } + + if (cursor && cshape >= 0 && cshape < Qt::LastCursor) { + const char *name = cursorNames[cshape]; + xcb_xfixes_set_cursor_name(conn, cursor, strlen(name), name); + } + + return cursor; +} + +xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor) +{ + xcb_connection_t *conn = xcb_connection(); + QPoint spot = cursor->hotSpot(); + xcb_cursor_t c = XCB_NONE; + if (cursor->pixmap().depth() > 1) + c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot); + if (!c) { + xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap()->toImage()); + xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask()->toImage()); + c = xcb_generate_id(conn); + xcb_create_cursor(conn, c, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, + spot.x(), spot.y()); + xcb_free_pixmap(conn, cp); + xcb_free_pixmap(conn, mp); + } + return c; +} + +static void getPosAndRoot(xcb_connection_t *conn, xcb_window_t *rootWin, QPoint *pos) +{ + if (pos) + *pos = QPoint(); + xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(conn)); + while (it.rem) { + xcb_window_t root = it.data->root; + xcb_query_pointer_cookie_t cookie = xcb_query_pointer(conn, root); + xcb_generic_error_t *err = 0; + xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(conn, cookie, &err); + if (!err && reply) { + if (pos) + *pos = QPoint(reply->root_x, reply->root_y); + if (rootWin) + *rootWin = root; + free(reply); + return; + } + free(err); + free(reply); + xcb_screen_next(&it); + } +} + +QPoint QXcbCursor::pos() const +{ + QPoint p; + getPosAndRoot(xcb_connection(), 0, &p); + return p; +} + +void QXcbCursor::setPos(const QPoint &pos) +{ + xcb_connection_t *conn = xcb_connection(); + xcb_window_t root; + getPosAndRoot(conn, &root, 0); + xcb_warp_pointer(conn, XCB_NONE, root, 0, 0, 0, 0, pos.x(), pos.y()); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbcursor.h b/src/plugins/platforms/xcb/qxcbcursor.h new file mode 100644 index 0000000000..4bbb9a928b --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbcursor.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXCBCURSOR_H +#define QXCBCURSOR_H + +#include <QtGui/QPlatformCursor> +#include "qxcbscreen.h" + +QT_BEGIN_NAMESPACE + +class QXcbCursor : public QXcbObject, public QPlatformCursor +{ +public: + QXcbCursor(QXcbConnection *conn, QXcbScreen *screen); + ~QXcbCursor(); + void changeCursor(QCursor *cursor, QWindow *widget); + QPoint pos() const; + void setPos(const QPoint &pos); + +private: + xcb_cursor_t createFontCursor(int cshape); + xcb_cursor_t createBitmapCursor(QCursor *cursor); + xcb_cursor_t createNonStandardCursor(int cshape); + + QXcbScreen *m_screen; + QMap<int, xcb_cursor_t> m_shapeCursorMap; + QMap<qint64, xcb_cursor_t> m_bitmapCursorMap; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp new file mode 100644 index 0000000000..8a6fd29986 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -0,0 +1,1332 @@ +/**************************************************************************** +** +** 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 QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbdrag.h" +#include <xcb/xcb.h> +#include "qxcbconnection.h" +#include "qxcbclipboard.h" +#include "qxcbmime.h" +#include "qxcbwindow.h" +#include "qxcbscreen.h" +#include "qwindow.h" +#include <private/qdnd_p.h> +#include <qdebug.h> +#include <qevent.h> +#include <qguiapplication.h> +#include <qrect.h> + +QT_BEGIN_NAMESPACE + +//#define DND_DEBUG +#ifdef DND_DEBUG +#define DEBUG qDebug +#else +#define DEBUG if(0) qDebug +#endif + +#ifdef DND_DEBUG +#define DNDDEBUG qDebug() +#else +#define DNDDEBUG if(0) qDebug() +#endif + +const int xdnd_version = 5; + +static inline xcb_window_t xcb_window(QWindow *w) +{ + return static_cast<QXcbWindow *>(w->handle())->xcb_window(); +} + + +static xcb_window_t xdndProxy(QXcbConnection *c, xcb_window_t w) +{ + xcb_window_t proxy = XCB_NONE; + + xcb_get_property_cookie_t cookie = Q_XCB_CALL2(xcb_get_property(c->xcb_connection(), false, w, c->atom(QXcbAtom::XdndProxy), + XCB_ATOM_WINDOW, 0, 1), c); + xcb_get_property_reply_t *reply = xcb_get_property_reply(c->xcb_connection(), cookie, 0); + + if (reply && reply->type == XCB_ATOM_WINDOW) + proxy = *((xcb_window_t *)xcb_get_property_value(reply)); + free(reply); + + if (proxy == XCB_NONE) + return proxy; + + // exists and is real? + cookie = Q_XCB_CALL2(xcb_get_property(c->xcb_connection(), false, proxy, c->atom(QXcbAtom::XdndProxy), + XCB_ATOM_WINDOW, 0, 1), c); + reply = xcb_get_property_reply(c->xcb_connection(), cookie, 0); + + if (reply && reply->type == XCB_ATOM_WINDOW) { + xcb_window_t p = *((xcb_window_t *)xcb_get_property_value(reply)); + if (proxy != p) + proxy = 0; + } else { + proxy = 0; + } + + free(reply); + + return proxy; +} + + +class QDropData : public QXcbMime +{ +public: + QDropData(QXcbDrag *d); + ~QDropData(); + +protected: + bool hasFormat_sys(const QString &mimeType) const; + QStringList formats_sys() const; + QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const; + + QVariant xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const; + + QXcbDrag *drag; +}; + + +QXcbDrag::QXcbDrag(QXcbConnection *c) + : QXcbObject(c) +{ + dropData = new QDropData(this); + + init(); + heartbeat = -1; + + transaction_expiry_timer = -1; +} + +QXcbDrag::~QXcbDrag() +{ + delete dropData; +} + +void QXcbDrag::init() +{ + currentWindow.clear(); + + xdnd_dragsource = XCB_NONE; + last_target_accepted_action = Qt::IgnoreAction; + + waiting_for_status = false; + current_target = XCB_NONE; + current_proxy_target = XCB_NONE; + xdnd_dragging = false; + + source_time = XCB_CURRENT_TIME; + target_time = XCB_CURRENT_TIME; + + current_screen = 0; + drag_types.clear(); +} + +QMimeData *QXcbDrag::platformDropData() +{ + return dropData; +} + +void QXcbDrag::startDrag() +{ + init(); + + heartbeat = startTimer(200); + xdnd_dragging = true; + + xcb_set_selection_owner(xcb_connection(), connection()->clipboard()->owner(), + atom(QXcbAtom::XdndSelection), connection()->time()); + + QDragManager *manager = QDragManager::self(); + QStringList fmts = QXcbMime::formatsHelper(manager->dropData()); + for (int i = 0; i < fmts.size(); ++i) { + QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i)); + for (int j = 0; j < atoms.size(); ++j) { + if (!drag_types.contains(atoms.at(j))) + drag_types.append(atoms.at(j)); + } + } + if (drag_types.size() > 3) + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, connection()->clipboard()->owner(), + atom(QXcbAtom::XdndTypelist), + XCB_ATOM_ATOM, 32, drag_types.size(), (const void *)drag_types.constData()); + + QPointF pos = QCursor::pos(); + QMouseEvent me(QEvent::MouseMove, pos, pos, pos, Qt::LeftButton, + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + move(&me); + +// if (!QWidget::mouseGrabber()) +// manager->shapedPixmapWindow->grabMouse(); +} + +void QXcbDrag::endDrag() +{ + Q_ASSERT(heartbeat != -1); + killTimer(heartbeat); + heartbeat = -1; + + xdnd_dragging = false; +} + +static xcb_translate_coordinates_reply_t * +translateCoordinates(QXcbConnection *c, xcb_window_t from, xcb_window_t to, int x, int y) +{ + xcb_translate_coordinates_cookie_t cookie = + xcb_translate_coordinates(c->xcb_connection(), from, to, x, y); + return xcb_translate_coordinates_reply(c->xcb_connection(), cookie, 0); +} + +void QXcbDrag::move(const QMouseEvent *me) +{ + DEBUG() << "QDragManager::move enter"; + + // ### + QPoint globalPos = me->globalPos(); + + if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid()) + return; + + const QList<QXcbScreen *> &screens = connection()->screens(); + QXcbScreen *screen = screens.at(connection()->primaryScreen()); + for (int i = 0; i < screens.size(); ++i) { + if (screens.at(i)->geometry().contains(globalPos)) { + screen = screens.at(i); + break; + } + } + if (screen != current_screen) { + // ### need to recreate the shaped pixmap window? +// int screen = QCursor::x11Screen(); +// if ((qt_xdnd_current_screen == -1 && screen != X11->defaultScreen) || (screen != qt_xdnd_current_screen)) { +// // recreate the pixmap on the new screen... +// delete xdnd_data.deco; +// QWidget* parent = object->source()->window()->x11Info().screen() == screen +// ? object->source()->window() : QApplication::desktop()->screen(screen); +// xdnd_data.deco = new QShapedPixmapWidget(parent); +// if (!QWidget::mouseGrabber()) { +// updatePixmap(); +// xdnd_data.deco->grabMouse(); +// } +// } +// xdnd_data.deco->move(QCursor::pos() - xdnd_data.deco->pm_hot); + current_screen = screen; + } + + +// qt_xdnd_current_screen = screen; + xcb_window_t rootwin = current_screen->root(); + xcb_translate_coordinates_reply_t *translate = + ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y()); + if (!translate) + return; + xcb_window_t target = translate->child; + int lx = translate->dst_x; + int ly = translate->dst_y; + free (translate); + + if (target == rootwin) { + // Ok. + } else if (target) { + //me + xcb_window_t src = rootwin; + while (target != 0) { + DNDDEBUG << "checking target for XdndAware" << target; + + // translate coordinates + translate = ::translateCoordinates(connection(), src, target, lx, ly); + if (!translate) { + target = 0; + break; + } + lx = translate->dst_x; + ly = translate->dst_y; + src = translate->child; + free(translate); + + // check if it has XdndAware + xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, target, + atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0)); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); + bool aware = reply && reply->type != XCB_NONE; + free(reply); + if (aware) { + DNDDEBUG << "Found XdndAware on " << target; + break; + } + + // find child at the coordinates + translate = ::translateCoordinates(connection(), src, src, lx, ly); + if (!translate) { + target = 0; + break; + } + target = translate->child; + free(translate); + } + // #### +// if (xdnd_data.deco && (!target || target == xdnd_data.deco->effectiveWinId())) { +// DNDDEBUG << "need to find real window"; +// target = findRealWindow(globalPos, rootwin, 6); +// DNDDEBUG << "real window found" << QWidget::find(target) << target; +// } + } + + QXcbWindow *w = 0; + if (target) { + w = connection()->platformWindowFromId(target); + if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) + w = 0; + } else { + w = 0; + target = rootwin; + } + + DNDDEBUG << "and the final target is " << target; + DNDDEBUG << "the widget w is" << (w ? w->window() : 0); + + xcb_window_t proxy_target = xdndProxy(connection(), target); + if (!proxy_target) + proxy_target = target; + int target_version = 1; + + if (proxy_target) { + xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, target, + atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 1); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); + if (!reply || reply->type == XCB_NONE) + target = 0; + target_version = xcb_get_property_value_length(reply) == 1 ? *(uint32_t *)xcb_get_property_value(reply) : 1; + if (target_version > xdnd_version) + target_version = xdnd_version; + + free(reply); + } + + DEBUG() << "target=" << target << "current_target=" << current_target; + if (target != current_target) { + if (current_target) + send_leave(); + + current_target = target; + current_proxy_target = proxy_target; + if (target) { + int flags = target_version << 24; + if (drag_types.size() > 3) + flags |= 0x0001; + + xcb_client_message_event_t enter; + enter.response_type = XCB_CLIENT_MESSAGE; + enter.window = target; + enter.format = 32; + enter.type = atom(QXcbAtom::XdndEnter); + enter.data.data32[0] = connection()->clipboard()->owner(); + enter.data.data32[1] = flags; + enter.data.data32[2] = drag_types.size()>0 ? drag_types.at(0) : 0; + enter.data.data32[3] = drag_types.size()>1 ? drag_types.at(1) : 0; + enter.data.data32[4] = drag_types.size()>2 ? drag_types.at(2) : 0; + // provisionally set the rectangle to 5x5 pixels... + source_sameanswer = QRect(globalPos.x() - 2, globalPos.y() -2 , 5, 5); + + DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0]; + if (w) + handleEnter(w->window(), &enter); + else if (target) + xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&enter); + waiting_for_status = false; + } + } + if (waiting_for_status) + return; + + QDragManager *m = QDragManager::self(); + + if (target) { + waiting_for_status = true; + + xcb_client_message_event_t move; + move.response_type = XCB_CLIENT_MESSAGE; + move.window = target; + move.format = 32; + move.type = atom(QXcbAtom::XdndPosition); + move.window = target; + move.data.data32[0] = connection()->clipboard()->owner(); + move.data.data32[1] = 0; // flags + move.data.data32[2] = (globalPos.x() << 16) + globalPos.y(); + move.data.data32[3] = connection()->time(); + move.data.data32[4] = toXdndAction(m->defaultAction(m->dragPrivate()->possible_actions, QGuiApplication::keyboardModifiers())); + DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window; + + source_time = connection()->time(); + + if (w) + handle_xdnd_position(w->window(), &move, false); + else + xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move); + } else { + if (m->willDrop) { + m->willDrop = false; + m->updateCursor(); + } + } + DEBUG() << "QDragManager::move leave"; +} + +void QXcbDrag::drop(const QMouseEvent *) +{ + endDrag(); + + if (!current_target) + return; + + xcb_client_message_event_t drop; + drop.response_type = XCB_CLIENT_MESSAGE; + drop.window = current_target; + drop.format = 32; + drop.type = atom(QXcbAtom::XdndDrop); + drop.data.data32[0] = connection()->clipboard()->owner(); + drop.data.data32[1] = 0; // flags + drop.data.data32[2] = connection()->time(); + + drop.data.data32[3] = 0; + drop.data.data32[4] = 0; + + QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target); + + if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) + w = 0; + + QDragManager *manager = QDragManager::self(); + + Transaction t = { + connection()->time(), + current_target, + current_proxy_target, + (w ? w->window() : 0), +// current_embedding_widget, + manager->object + }; + transactions.append(t); + restartDropExpiryTimer(); + + if (w) + handleDrop(w->window(), &drop, false); + else + xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop); + + current_target = 0; + current_proxy_target = 0; + source_time = 0; +// current_embedding_widget = 0; + manager->object = 0; +} + +Qt::DropAction QXcbDrag::toDropAction(xcb_atom_t a) const +{ + if (a == atom(QXcbAtom::XdndActionCopy) || a == 0) + return Qt::CopyAction; + if (a == atom(QXcbAtom::XdndActionLink)) + return Qt::LinkAction; + if (a == atom(QXcbAtom::XdndActionMove)) + return Qt::MoveAction; + return Qt::CopyAction; +} + +xcb_atom_t QXcbDrag::toXdndAction(Qt::DropAction a) const +{ + switch (a) { + case Qt::CopyAction: + return atom(QXcbAtom::XdndActionCopy); + case Qt::LinkAction: + return atom(QXcbAtom::XdndActionLink); + case Qt::MoveAction: + case Qt::TargetMoveAction: + return atom(QXcbAtom::XdndActionMove); + case Qt::IgnoreAction: + return XCB_NONE; + default: + return atom(QXcbAtom::XdndActionCopy); + } +} + +// timer used to discard old XdndDrop transactions +enum { XdndDropTransactionTimeout = 5000 }; // 5 seconds + +void QXcbDrag::restartDropExpiryTimer() +{ + if (transaction_expiry_timer != -1) + killTimer(transaction_expiry_timer); + transaction_expiry_timer = startTimer(XdndDropTransactionTimeout); +} + +int QXcbDrag::findTransactionByWindow(xcb_window_t window) +{ + int at = -1; + for (int i = 0; i < transactions.count(); ++i) { + const Transaction &t = transactions.at(i); + if (t.target == window || t.proxy_target == window) { + at = i; + break; + } + } + return at; +} + +int QXcbDrag::findTransactionByTime(xcb_timestamp_t timestamp) +{ + int at = -1; + for (int i = 0; i < transactions.count(); ++i) { + const Transaction &t = transactions.at(i); + if (t.timestamp == timestamp) { + at = i; + break; + } + } + return at; +} + +#if 0 + +// find an ancestor with XdndAware on it +static Window findXdndAwareParent(Window window) +{ + Window target = 0; + forever { + // check if window has XdndAware + Atom type = 0; + int f; + unsigned long n, a; + unsigned char *data = 0; + if (XGetWindowProperty(X11->display, window, ATOM(XdndAware), 0, 0, False, + AnyPropertyType, &type, &f,&n,&a,&data) == Success) { + if (data) + XFree(data); + if (type) { + target = window; + break; + } + } + + // try window's parent + Window root; + Window parent; + Window *children; + uint unused; + if (!XQueryTree(X11->display, window, &root, &parent, &children, &unused)) + break; + if (children) + XFree(children); + if (window == root) + break; + window = parent; + } + return target; +} + + +// for embedding only +static QWidget* current_embedding_widget = 0; +static xcb_client_message_event_t last_enter_event; + + +static bool checkEmbedded(QWidget* w, const XEvent* xe) +{ + if (!w) + return false; + + if (current_embedding_widget != 0 && current_embedding_widget != w) { + current_target = ((QExtraWidget*)current_embedding_widget)->extraData()->xDndProxy; + current_proxy_target = current_target; + qt_xdnd_send_leave(); + current_target = 0; + current_proxy_target = 0; + current_embedding_widget = 0; + } + + QWExtra* extra = ((QExtraWidget*)w)->extraData(); + if (extra && extra->xDndProxy != 0) { + + if (current_embedding_widget != w) { + + last_enter_event.xany.window = extra->xDndProxy; + XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, &last_enter_event); + current_embedding_widget = w; + } + + ((XEvent*)xe)->xany.window = extra->xDndProxy; + XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, (XEvent*)xe); + if (currentWindow != w) { + currentWindow = w; + } + return true; + } + current_embedding_widget = 0; + return false; +} +#endif + + +void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *event) +{ + Q_UNUSED(window); + DEBUG() << "handleEnter" << window; + + xdnd_types.clear(); +// motifdnd_active = false; +// last_enter_event.xclient = xe->xclient; + + int version = (int)(event->data.data32[1] >> 24); + if (version > xdnd_version) + return; + + xdnd_dragsource = event->data.data32[0]; + + if (event->data.data32[1] & 1) { + // get the types from XdndTypeList + xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, xdnd_dragsource, + atom(QXcbAtom::XdndTypelist), XCB_ATOM_ATOM, + 0, xdnd_max_type); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); + if (reply && reply->type != XCB_NONE && reply->format == 32) { + int length = xcb_get_property_value_length(reply) / 4; + if (length > xdnd_max_type) + length = xdnd_max_type; + + xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); + for (int i = 0; i < length; ++i) + xdnd_types.append(atoms[i]); + } + free(reply); + } else { + // get the types from the message + for(int i = 2; i < 5; i++) { + if (event->data.data32[i]) + xdnd_types.append(event->data.data32[i]); + } + } + for(int i = 0; i < xdnd_types.length(); ++i) + DEBUG() << " " << connection()->atomName(xdnd_types.at(i)); +} + +void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *e, bool passive) +{ + QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff); + Q_ASSERT(w); + QRect geometry = w->geometry(); + + p -= geometry.topLeft(); + + // #### +// if (!passive && checkEmbedded(w, e)) +// return; + + if (!w || (/*!w->acceptDrops() &&*/ (w->windowType() == Qt::Desktop))) + return; + + if (e->data.data32[0] != xdnd_dragsource) { + DEBUG("xdnd drag position from unexpected source (%x not %x)", e->data.data32[0], xdnd_dragsource); + return; + } + + // timestamp from the source + if (e->data.data32[3] != XCB_NONE) + target_time /*= X11->userTime*/ = e->data.data32[3]; + + QDragManager *manager = QDragManager::self(); + QMimeData *dropData = manager->dropData(); + + xcb_client_message_event_t response; + response.response_type = XCB_CLIENT_MESSAGE; + response.window = xdnd_dragsource; + response.format = 32; + response.type = atom(QXcbAtom::XdndStatus); + response.data.data32[0] = xcb_window(w); + response.data.data32[1] = 0; // flags + response.data.data32[2] = 0; // x, y + response.data.data32[3] = 0; // w, h + response.data.data32[4] = 0; // action + + if (!passive) { // otherwise just reject + QRect answerRect(p + geometry.topLeft(), QSize(1,1)); + + if (manager->object) { + manager->possible_actions = manager->dragPrivate()->possible_actions; + } else { + manager->possible_actions = Qt::DropActions(toDropAction(e->data.data32[4])); + } + QDragMoveEvent me(p, manager->possible_actions, dropData, + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + + Qt::DropAction accepted_action = Qt::IgnoreAction; + + currentPosition = p; + + if (w != currentWindow.data()) { + if (currentWindow) { + QDragLeaveEvent e; + QGuiApplication::sendEvent(currentWindow.data(), &e); + } + currentWindow = w; + + last_target_accepted_action = Qt::IgnoreAction; + QDragEnterEvent de(p, manager->possible_actions, dropData, + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + QGuiApplication::sendEvent(w, &de); + if (de.isAccepted() && de.dropAction() != Qt::IgnoreAction) + last_target_accepted_action = de.dropAction(); + } + + DEBUG() << "qt_handle_xdnd_position action=" << connection()->atomName(e->data.data32[4]); + + if (last_target_accepted_action != Qt::IgnoreAction) { + me.setDropAction(last_target_accepted_action); + me.accept(); + } + QGuiApplication::sendEvent(w, &me); + if (me.isAccepted()) { + response.data.data32[1] = 1; // yes + accepted_action = me.dropAction(); + last_target_accepted_action = accepted_action; + } else { + response.data.data32[0] = 0; + last_target_accepted_action = Qt::IgnoreAction; + } + answerRect = me.answerRect().translated(geometry.topLeft()).intersected(geometry); + + if (answerRect.left() < 0) + answerRect.setLeft(0); + if (answerRect.right() > 4096) + answerRect.setRight(4096); + if (answerRect.top() < 0) + answerRect.setTop(0); + if (answerRect.bottom() > 4096) + answerRect.setBottom(4096); + if (answerRect.width() < 0) + answerRect.setWidth(0); + if (answerRect.height() < 0) + answerRect.setHeight(0); + +// response.data.data32[2] = (answerRect.x() << 16) + answerRect.y(); +// response.data.data32[3] = (answerRect.width() << 16) + answerRect.height(); + response.data.data32[4] = toXdndAction(accepted_action); + } + + // reset + target_time = XCB_CURRENT_TIME; + + DEBUG() << "sending XdndStatus" << (xdnd_dragsource == connection()->clipboard()->owner()) << xdnd_dragsource + << response.data.data32[1] << connection()->atomName(response.data.data32[4]); + if (xdnd_dragsource == connection()->clipboard()->owner()) + handle_xdnd_status(&response, passive); + else + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource, + XCB_EVENT_MASK_NO_EVENT, (const char *)&response)); +} + +namespace +{ + class ClientMessageScanner { + public: + ClientMessageScanner(xcb_atom_t a) : atom(a) {} + xcb_atom_t atom; + bool check(xcb_generic_event_t *event) const { + if (!event) + return false; + if ((event->response_type & 0x7f) != XCB_CLIENT_MESSAGE) + return false; + return ((xcb_client_message_event_t *)event)->type == atom; + } + }; +} + +void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *event, bool passive) +{ + xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event); + xcb_generic_event_t *nextEvent; + ClientMessageScanner scanner(atom(QXcbAtom::XdndPosition)); + while ((nextEvent = connection()->checkEvent(scanner))) { + if (lastEvent != event) + free(lastEvent); + lastEvent = (xcb_client_message_event_t *)nextEvent; + } + + handle_xdnd_position(w, lastEvent, passive); + if (lastEvent != event) + free(lastEvent); +} + +void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event, bool) +{ + DEBUG("xdndHandleStatus"); + // ignore late status messages + if (event->data.data32[0] && event->data.data32[0] != current_proxy_target) + return; + + Qt::DropAction newAction = (event->data.data32[1] & 0x1) ? toDropAction(event->data.data32[4]) : Qt::IgnoreAction; + + if ((event->data.data32[1] & 2) == 0) { + QPoint p((event->data.data32[2] & 0xffff0000) >> 16, event->data.data32[2] & 0x0000ffff); + QSize s((event->data.data32[3] & 0xffff0000) >> 16, event->data.data32[3] & 0x0000ffff); + source_sameanswer = QRect(p, s); + } else { + source_sameanswer = QRect(); + } + QDragManager *manager = QDragManager::self(); + manager->willDrop = (event->data.data32[1] & 0x1); + if (manager->global_accepted_action != newAction) { + manager->global_accepted_action = newAction; + manager->emitActionChanged(newAction); + } + DEBUG() << "willDrop=" << manager->willDrop << "action=" << newAction; + manager->updateCursor(); + waiting_for_status = false; +} + +void QXcbDrag::handleStatus(const xcb_client_message_event_t *event, bool passive) +{ + if (event->window != connection()->clipboard()->owner()) + return; + + xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event); + qDebug() << "handleStatus" << lastEvent->window << lastEvent->data.data32[0]; + xcb_generic_event_t *nextEvent; + ClientMessageScanner scanner(atom(QXcbAtom::XdndStatus)); + while ((nextEvent = connection()->checkEvent(scanner))) { + if (lastEvent != event) + free(lastEvent); + lastEvent = (xcb_client_message_event_t *)nextEvent; + } + + handle_xdnd_status(lastEvent, passive); + if (lastEvent != event) + free(lastEvent); + DEBUG("xdndHandleStatus end"); +} + +void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event, bool /*passive*/) +{ + DEBUG("xdnd leave"); + if (!currentWindow || w != currentWindow.data()) + return; // sanity + + // ### +// if (checkEmbedded(current_embedding_widget, event)) { +// current_embedding_widget = 0; +// currentWindow.clear(); +// return; +// } + + if (event->data.data32[0] != xdnd_dragsource) { + // This often happens - leave other-process window quickly + DEBUG("xdnd drag leave from unexpected source (%x not %x", event->data.data32[0], xdnd_dragsource); + } + + QDragLeaveEvent e; + QGuiApplication::sendEvent(currentWindow.data(), &e); + + xdnd_dragsource = 0; + xdnd_types.clear(); + currentWindow.clear(); +} + +void QXcbDrag::send_leave() +{ + if (!current_target) + return; + + QDragManager *manager = QDragManager::self(); + + xcb_client_message_event_t leave; + leave.response_type = XCB_CLIENT_MESSAGE; + leave.window = current_target; + leave.format = 32; + leave.type = atom(QXcbAtom::XdndLeave); + leave.data.data32[0] = connection()->clipboard()->owner(); + leave.data.data32[1] = 0; // flags + leave.data.data32[2] = 0; // x, y + leave.data.data32[3] = 0; // w, h + leave.data.data32[4] = 0; // just null + + QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target); + + if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) + w = 0; + + if (w) + handleLeave(w->window(), (const xcb_client_message_event_t *)&leave, false); + else + xcb_send_event(xcb_connection(), false,current_proxy_target, + XCB_EVENT_MASK_NO_EVENT, (const char *)&leave); + + // reset the drag manager state + manager->willDrop = false; + if (manager->global_accepted_action != Qt::IgnoreAction) + manager->emitActionChanged(Qt::IgnoreAction); + manager->global_accepted_action = Qt::IgnoreAction; + manager->updateCursor(); + current_target = 0; + current_proxy_target = 0; + source_time = XCB_CURRENT_TIME; + waiting_for_status = false; +} + +void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bool passive) +{ + DEBUG("xdndHandleDrop"); + if (!currentWindow) { + xdnd_dragsource = 0; + return; // sanity + } + + // ### +// if (!passive && checkEmbedded(currentWindow, xe)){ +// current_embedding_widget = 0; +// xdnd_dragsource = 0; +// currentWindow = 0; +// return; +// } + const uint32_t *l = event->data.data32; + + QDragManager *manager = QDragManager::self(); + DEBUG("xdnd drop"); + + if (l[0] != xdnd_dragsource) { + DEBUG("xdnd drop from unexpected source (%x not %x", l[0], xdnd_dragsource); + return; + } + + // update the "user time" from the timestamp in the event. + if (l[2] != 0) + target_time = /*X11->userTime =*/ l[2]; + + if (!passive) { + // this could be a same-application drop, just proxied due to + // some XEMBEDding, so try to find the real QMimeData used + // based on the timestamp for this drop. + QMimeData *dropData = 0; + // ### +// int at = findXdndDropTransactionByTime(target_time); +// if (at != -1) +// dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data; + // if we can't find it, then use the data in the drag manager + if (!dropData) + dropData = manager->dropData(); + + // Drop coming from another app? Update keyboard modifiers. +// if (!qt_xdnd_dragging) { +// QApplicationPrivate::modifier_buttons = currentKeyboardModifiers(); +// } + + QDropEvent de(currentPosition, manager->possible_actions, dropData, + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + QGuiApplication::sendEvent(currentWindow.data(), &de); + if (!de.isAccepted()) { + // Ignore a failed drag + manager->global_accepted_action = Qt::IgnoreAction; + } else { + manager->global_accepted_action = de.dropAction(); + } + xcb_client_message_event_t finished; + finished.response_type = XCB_CLIENT_MESSAGE; + finished.window = xdnd_dragsource; + finished.format = 32; + finished.type = atom(QXcbAtom::XdndFinished); + DNDDEBUG << "xdndHandleDrop" + << "currentWindow" << currentWindow.data() + << (currentWindow ? xcb_window(currentWindow.data()) : 0); + finished.data.data32[0] = currentWindow ? xcb_window(currentWindow.data()) : XCB_NONE; + finished.data.data32[1] = de.isAccepted() ? 1 : 0; // flags + finished.data.data32[2] = toXdndAction(manager->global_accepted_action); + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource, + XCB_EVENT_MASK_NO_EVENT, (char *)&finished)); + } else { + QDragLeaveEvent e; + QGuiApplication::sendEvent(currentWindow.data(), &e); + } + xdnd_dragsource = 0; + currentWindow.clear(); + waiting_for_status = false; + + // reset + target_time = XCB_CURRENT_TIME; +} + + +void QXcbDrag::handleFinished(const xcb_client_message_event_t *event, bool) +{ + DEBUG("xdndHandleFinished"); + if (event->window != connection()->clipboard()->owner()) + return; + + const unsigned long *l = (const unsigned long *)event->data.data32; + + DNDDEBUG << "xdndHandleFinished, l[0]" << l[0] + << "current_target" << current_target + << "qt_xdnd_current_proxy_targe" << current_proxy_target; + + if (l[0]) { + int at = findTransactionByWindow(l[0]); + if (at != -1) { + restartDropExpiryTimer(); + + Transaction t = transactions.takeAt(at); +// QDragManager *manager = QDragManager::self(); + +// Window target = current_target; +// Window proxy_target = current_proxy_target; +// QWidget *embedding_widget = current_embedding_widget; +// QDrag *currentObject = manager->object; + +// current_target = t.target; +// current_proxy_target = t.proxy_target; +// current_embedding_widget = t.embedding_widget; +// manager->object = t.object; + +// if (!passive) +// (void) checkEmbedded(currentWindow, xe); + +// current_embedding_widget = 0; +// current_target = 0; +// current_proxy_target = 0; + + if (t.object) + t.object->deleteLater(); + +// current_target = target; +// current_proxy_target = proxy_target; +// current_embedding_widget = embedding_widget; +// manager->object = currentObject; + } + } + waiting_for_status = false; +} + + +void QXcbDrag::timerEvent(QTimerEvent* e) +{ + if (e->timerId() == heartbeat && source_sameanswer.isNull()) { + QPointF pos = QCursor::pos(); + QMouseEvent me(QEvent::MouseMove, pos, pos, pos, Qt::LeftButton, + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + move(&me); + } else if (e->timerId() == transaction_expiry_timer) { + for (int i = 0; i < transactions.count(); ++i) { + const Transaction &t = transactions.at(i); + if (t.targetWindow) { + // dnd within the same process, don't delete these + continue; + } + t.object->deleteLater(); + transactions.removeAt(i--); + } + + killTimer(transaction_expiry_timer); + transaction_expiry_timer = -1; + } +} + +void QXcbDrag::cancel() +{ + DEBUG("QXcbDrag::cancel"); + endDrag(); + + if (current_target) + send_leave(); + + current_target = 0; +} + +#if 0 + +static +Window findRealWindow(const QPoint & pos, Window w, int md) +{ + if (xdnd_data.deco && w == xdnd_data.deco->effectiveWinId()) + return 0; + + if (md) { + X11->ignoreBadwindow(); + XWindowAttributes attr; + XGetWindowAttributes(X11->display, w, &attr); + if (X11->badwindow()) + return 0; + + if (attr.map_state == IsViewable + && QRect(attr.x,attr.y,attr.width,attr.height).contains(pos)) { + { + Atom type = XNone; + int f; + unsigned long n, a; + unsigned char *data; + + XGetWindowProperty(X11->display, w, ATOM(XdndAware), 0, 0, False, + AnyPropertyType, &type, &f,&n,&a,&data); + if (data) XFree(data); + if (type) + return w; + } + + Window r, p; + Window* c; + uint nc; + if (XQueryTree(X11->display, w, &r, &p, &c, &nc)) { + r=0; + for (uint i=nc; !r && i--;) { + r = findRealWindow(pos-QPoint(attr.x,attr.y), + c[i], md-1); + } + XFree(c); + if (r) + return r; + + // We didn't find a client window! Just use the + // innermost window. + } + + // No children! + return w; + } + } + return 0; +} +#endif + +void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event) +{ + xcb_selection_notify_event_t notify; + notify.response_type = XCB_SELECTION_NOTIFY; + notify.requestor = event->requestor; + notify.selection = event->selection; + notify.target = XCB_NONE; + notify.property = XCB_NONE; + notify.time = event->time; + + QDragManager *manager = QDragManager::self(); + QDrag *currentObject = manager->object; + + // which transaction do we use? (note: -2 means use current manager->object) + int at = -1; + + // figure out which data the requestor is really interested in + if (manager->object && event->time == source_time) { + // requestor wants the current drag data + at = -2; + } else { + // if someone has requested data in response to XdndDrop, find the corresponding transaction. the + // spec says to call XConvertSelection() using the timestamp from the XdndDrop + at = findTransactionByTime(event->time); + if (at == -1) { + // no dice, perhaps the client was nice enough to use the same window id in XConvertSelection() + // that we sent the XdndDrop event to. + at = findTransactionByWindow(event->requestor); + } +// if (at == -1 && event->time == XCB_CURRENT_TIME) { +// // previous Qt versions always requested the data on a child of the target window +// // using CurrentTime... but it could be asking for either drop data or the current drag's data +// Window target = findXdndAwareParent(event->requestor); +// if (target) { +// if (current_target && current_target == target) +// at = -2; +// else +// at = findXdndDropTransactionByWindow(target); +// } +// } + } + if (at >= 0) { + restartDropExpiryTimer(); + + // use the drag object from an XdndDrop tansaction + manager->object = transactions.at(at).object; + } else if (at != -2) { + // no transaction found, we'll have to reject the request + manager->object = 0; + } + if (manager->object) { + xcb_atom_t atomFormat = event->target; + int dataFormat = 0; + QByteArray data; + if (QXcbMime::mimeDataForAtom(connection(), event->target, manager->dragPrivate()->data, + &data, &atomFormat, &dataFormat)) { + int dataSize = data.size() / (dataFormat / 8); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, event->requestor, event->property, + atomFormat, dataFormat, dataSize, (const void *)data.constData()); + notify.property = event->property; + notify.target = atomFormat; + } + } + + // reset manager->object in case we modified it above + manager->object = currentObject; + + xcb_send_event(xcb_connection(), false, event->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)¬ify); +} + + +bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) +{ + DNDDEBUG << "xdndEnable" << w << on; + if (on) { + QXcbWindow *xdnd_widget = 0; + if ((w->window()->windowType() == Qt::Desktop)) { + if (desktop_proxy) // *WE* already have one. + return false; + + xcb_grab_server(xcb_connection()); + + // As per Xdnd4, use XdndProxy + xcb_window_t proxy_id = xdndProxy(connection(), w->xcb_window()); + + if (!proxy_id) { + desktop_proxy = new QWindow; + xdnd_widget = static_cast<QXcbWindow *>(desktop_proxy->handle()); + proxy_id = xdnd_widget->xcb_window(); + xcb_atom_t xdnd_proxy = atom(QXcbAtom::XdndProxy); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, w->xcb_window(), xdnd_proxy, + XCB_ATOM_WINDOW, 32, 1, &proxy_id); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, proxy_id, xdnd_proxy, + XCB_ATOM_WINDOW, 32, 1, &proxy_id); + } + + xcb_ungrab_server(xcb_connection()); + } else { + xdnd_widget = w; + } + if (xdnd_widget) { + DNDDEBUG << "setting XdndAware for" << xdnd_widget << xdnd_widget->xcb_window(); + xcb_atom_t atm = xdnd_version; + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, xdnd_widget->xcb_window(), + atom(QXcbAtom::XdndAware), XCB_ATOM_ATOM, 32, 1, &atm); + return true; + } else { + return false; + } + } else { + if ((w->window()->windowType() == Qt::Desktop)) { + xcb_delete_property(xcb_connection(), w->xcb_window(), atom(QXcbAtom::XdndProxy)); + delete desktop_proxy; + desktop_proxy = 0; + } else { + DNDDEBUG << "not deleting XDndAware"; + } + return true; + } +} + + + + +QDropData::QDropData(QXcbDrag *d) + : QXcbMime(), + drag(d) +{ +} + +QDropData::~QDropData() +{ +} + +QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const +{ + QByteArray mime = mimetype.toLatin1(); + QVariant data = /*X11->motifdnd_active + ? X11->motifdndObtainData(mime) + :*/ xdndObtainData(mime, requestedType); + return data; +} + +QVariant QDropData::xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const +{ + QByteArray result; + + QDragManager *manager = QDragManager::self(); + QXcbConnection *c = drag->connection(); + QXcbWindow *xcb_window = c->platformWindowFromId(drag->xdnd_dragsource); + if (xcb_window && manager->object && xcb_window->window()->windowType() != Qt::Desktop) { + QDragPrivate *o = manager->dragPrivate(); + if (o->data->hasFormat(QLatin1String(format))) + result = o->data->data(QLatin1String(format)); + return result; + } + + QList<xcb_atom_t> atoms = drag->xdnd_types; + QByteArray encoding; + xcb_atom_t a = mimeAtomForFormat(c, QLatin1String(format), requestedType, atoms, &encoding); + if (a == XCB_NONE) + return result; + + if (c->clipboard()->getSelectionOwner(drag->atom(QXcbAtom::XdndSelection)) == XCB_NONE) + return result; // should never happen? + + xcb_atom_t xdnd_selection = c->atom(QXcbAtom::XdndSelection); + result = c->clipboard()->getSelection(xdnd_selection, a, xdnd_selection); + + return mimeConvertToFormat(c, a, result, QLatin1String(format), requestedType, encoding); +} + + +bool QDropData::hasFormat_sys(const QString &format) const +{ + return formats().contains(format); +} + +QStringList QDropData::formats_sys() const +{ + QStringList formats; +// if (X11->motifdnd_active) { +// int i = 0; +// QByteArray fmt; +// while (!(fmt = X11->motifdndFormat(i)).isEmpty()) { +// formats.append(QLatin1String(fmt)); +// ++i; +// } +// } else { + for (int i = 0; i < drag->xdnd_types.size(); ++i) { + QString f = mimeAtomToString(drag->connection(), drag->xdnd_types.at(i)); + if (!formats.contains(f)) + formats.append(f); + } +// } + return formats; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h new file mode 100644 index 0000000000..ce0f8faa54 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** 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 QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXCBDRAG_H +#define QXCBDRAG_H + +#include <qplatformdrag_qpa.h> +#include <qxcbobject.h> +#include <xcb/xcb.h> +#include <qlist.h> +#include <qpoint.h> +#include <qrect.h> +#include <qsharedpointer.h> +#include <qvector.h> + +QT_BEGIN_NAMESPACE + +class QMouseEvent; +class QWindow; +class QXcbConnection; +class QXcbWindow; +class QDropData; +class QXcbScreen; +class QDrag; + +class QXcbDrag : public QObject, public QXcbObject, public QPlatformDrag +{ +public: + QXcbDrag(QXcbConnection *c); + ~QXcbDrag(); + + virtual QMimeData *platformDropData(); + +// virtual Qt::DropAction drag(QDrag *); + + virtual void startDrag(); + virtual void cancel(); + virtual void move(const QMouseEvent *me); + virtual void drop(const QMouseEvent *me); + void endDrag(); + + void handleEnter(QWindow *window, const xcb_client_message_event_t *event); + void handlePosition(QWindow *w, const xcb_client_message_event_t *event, bool passive); + void handleLeave(QWindow *w, const xcb_client_message_event_t *event, bool /*passive*/); + void handleDrop(QWindow *, const xcb_client_message_event_t *event, bool passive); + + void handleStatus(const xcb_client_message_event_t *event, bool passive); + void handleSelectionRequest(const xcb_selection_request_event_t *event); + void handleFinished(const xcb_client_message_event_t *event, bool passive); + + bool dndEnable(QXcbWindow *win, bool on); + +protected: + void timerEvent(QTimerEvent* e); + +private: + friend class QDropData; + + void init(); + + void handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *event, bool passive); + void handle_xdnd_status(const xcb_client_message_event_t *event, bool); + void send_leave(); + + Qt::DropAction toDropAction(xcb_atom_t atom) const; + xcb_atom_t toXdndAction(Qt::DropAction a) const; + + QWeakPointer<QWindow> currentWindow; + QPoint currentPosition; + + QDropData *dropData; + + QWindow *desktop_proxy; + + xcb_atom_t xdnd_dragsource; + + // the types in this drop. 100 is no good, but at least it's big. + enum { xdnd_max_type = 100 }; + QList<xcb_atom_t> xdnd_types; + + xcb_timestamp_t target_time; + xcb_timestamp_t source_time; + Qt::DropAction last_target_accepted_action; + + // rectangle in which the answer will be the same + QRect source_sameanswer; + bool waiting_for_status; + + // top-level window we sent position to last. + xcb_window_t current_target; + // window to send events to (always valid if current_target) + xcb_window_t current_proxy_target; + + QXcbScreen *current_screen; + + int heartbeat; + bool xdnd_dragging; + + QVector<xcb_atom_t> drag_types; + + struct Transaction + { + xcb_timestamp_t timestamp; + xcb_window_t target; + xcb_window_t proxy_target; + QWindow *targetWindow; +// QWidget *embedding_widget; + QDrag *object; + }; + QList<Transaction> transactions; + + int transaction_expiry_timer; + void restartDropExpiryTimer(); + int findTransactionByWindow(xcb_window_t window); + int findTransactionByTime(xcb_timestamp_t timestamp); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/xcb/qxcbeglsurface.h b/src/plugins/platforms/xcb/qxcbeglsurface.h new file mode 100644 index 0000000000..a1e6c148a2 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbeglsurface.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXCBEGLSURFACE_H +#define QXCBEGLSURFACE_H + +#include <EGL/egl.h> + +class QXcbEGLSurface +{ +public: + QXcbEGLSurface(EGLDisplay display, EGLSurface surface) + : m_display(display) + , m_surface(surface) + { + } + + ~QXcbEGLSurface() + { + eglDestroySurface(m_display, m_surface); + } + + EGLSurface surface() const { return m_surface; } + +private: + EGLDisplay m_display; + EGLSurface m_surface; +}; + +#endif diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp new file mode 100644 index 0000000000..569e4fc4e4 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbimage.h" +#include <QtGui/QColor> +#include <QtGui/private/qimage_p.h> +#include <QtGui/private/qdrawhelper_p.h> +#ifdef XCB_USE_RENDER +#include <xcb/render.h> +// 'template' is used as a function argument name in xcb_renderutil.h +#define template template_param +// extern "C" is missing too +extern "C" { +#include <xcb/xcb_renderutil.h> +} +#undef template +#endif + +QT_BEGIN_NAMESPACE + +QImage::Format qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t depth, + const xcb_visualtype_t *visual) +{ + const xcb_format_t *format = connection->formatForDepth(depth); + + if (!visual || !format) + return QImage::Format_Invalid; + + if (depth == 32 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000 + && visual->green_mask == 0xff00 && visual->blue_mask == 0xff) + return QImage::Format_ARGB32_Premultiplied; + + if (depth == 24 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000 + && visual->green_mask == 0xff00 && visual->blue_mask == 0xff) + return QImage::Format_RGB32; + + if (depth == 16 && format->bits_per_pixel == 16 && visual->red_mask == 0xf800 + && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f) + return QImage::Format_RGB16; + + return QImage::Format_Invalid; +} + +QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap, + int width, int height, int depth, + const xcb_visualtype_t *visual) +{ + xcb_connection_t *conn = connection->xcb_connection(); + xcb_generic_error_t *error = 0; + + xcb_get_image_cookie_t get_image_cookie = + xcb_get_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, + 0, 0, width, height, 0xffffffff); + + xcb_get_image_reply_t *image_reply = + xcb_get_image_reply(conn, get_image_cookie, &error); + + if (!image_reply) { + if (error) { + connection->handleXcbError(error); + free(error); + } + return QPixmap(); + } + + uint8_t *data = xcb_get_image_data(image_reply); + uint32_t length = xcb_get_image_data_length(image_reply); + + QPixmap result; + + QImage::Format format = qt_xcb_imageFormatForVisual(connection, depth, visual); + if (format != QImage::Format_Invalid) { + uint32_t bytes_per_line = length / height; + QImage image(const_cast<uint8_t *>(data), width, height, bytes_per_line, format); + uint8_t image_byte_order = connection->setup()->image_byte_order; + + // we may have to swap the byte order + if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && image_byte_order == XCB_IMAGE_ORDER_MSB_FIRST) + || (QSysInfo::ByteOrder == QSysInfo::BigEndian && image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) + { + for (int i=0; i < image.height(); i++) { + switch (format) { + case QImage::Format_RGB16: { + ushort *p = (ushort*)image.scanLine(i); + ushort *end = p + image.width(); + while (p < end) { + *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff); + p++; + } + break; + } + case QImage::Format_RGB32: // fall-through + case QImage::Format_ARGB32_Premultiplied: { + 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++; + } + break; + } + default: + Q_ASSERT(false); + } + } + } + + // fix-up alpha channel + if (format == QImage::Format_RGB32) { + QRgb *p = (QRgb *)image.bits(); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) + p[x] |= 0xff000000; + p += bytes_per_line / 4; + } + } + + result = QPixmap::fromImage(image.copy()); + } + + free(image_reply); + return result; +} + +xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image) +{ + xcb_connection_t *conn = screen->xcb_connection(); + QImage bitmap = image.convertToFormat(QImage::Format_MonoLSB); + const QRgb c0 = QColor(Qt::black).rgb(); + const QRgb c1 = QColor(Qt::white).rgb(); + if (bitmap.color(0) == c0 && bitmap.color(1) == c1) { + bitmap.invertPixels(); + bitmap.setColor(0, c1); + bitmap.setColor(1, c0); + } + const int width = bitmap.width(); + const int height = bitmap.height(); + const int bytesPerLine = bitmap.bytesPerLine(); + int destLineSize = width / 8; + if (width % 8) + ++destLineSize; + const uchar *map = bitmap.bits(); + uint8_t *buf = new uint8_t[height * destLineSize]; + for (int i = 0; i < height; i++) + memcpy(buf + (destLineSize * i), map + (bytesPerLine * i), destLineSize); + xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, screen->root(), buf, + width, height, 1, 0, 0, 0); + delete[] buf; + return pm; +} + +xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, + const QPoint &spot) +{ +#ifdef XCB_USE_RENDER + xcb_connection_t *conn = screen->xcb_connection(); + const int w = image.width(); + const int h = image.height(); + xcb_generic_error_t *error = 0; + xcb_render_query_pict_formats_cookie_t formatsCookie = xcb_render_query_pict_formats(conn); + xcb_render_query_pict_formats_reply_t *formatsReply = xcb_render_query_pict_formats_reply(conn, + formatsCookie, + &error); + if (!formatsReply || error) { + qWarning("createCursorXRender: query_pict_formats failed"); + free(formatsReply); + free(error); + return XCB_NONE; + } + xcb_render_pictforminfo_t *fmt = xcb_render_util_find_standard_format(formatsReply, + XCB_PICT_STANDARD_ARGB_32); + if (!fmt) { + qWarning("createCursorXRender: Failed to find format PICT_STANDARD_ARGB_32"); + free(formatsReply); + return XCB_NONE; + } + + QImage img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + xcb_image_t *xi = xcb_image_create(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP, + 32, 32, 32, 32, + QSysInfo::ByteOrder == QSysInfo::BigEndian ? XCB_IMAGE_ORDER_MSB_FIRST : XCB_IMAGE_ORDER_LSB_FIRST, + XCB_IMAGE_ORDER_MSB_FIRST, + 0, 0, 0); + if (!xi) { + qWarning("createCursorXRender: xcb_image_create failed"); + free(formatsReply); + return XCB_NONE; + } + xi->data = (uint8_t *) malloc(xi->stride * h); + if (!xi->data) { + qWarning("createCursorXRender: Failed to malloc() image data"); + xcb_image_destroy(xi); + free(formatsReply); + return XCB_NONE; + } + memcpy(xi->data, img.constBits(), img.byteCount()); + + xcb_pixmap_t pix = xcb_generate_id(conn); + xcb_create_pixmap(conn, 32, pix, screen->root(), w, h); + + xcb_render_picture_t pic = xcb_generate_id(conn); + xcb_render_create_picture(conn, pic, pix, fmt->id, 0, 0); + + xcb_gcontext_t gc = xcb_generate_id(conn); + xcb_create_gc(conn, gc, pix, 0, 0); + xcb_image_put(conn, pix, gc, xi, 0, 0, 0); + xcb_free_gc(conn, gc); + + xcb_cursor_t cursor = xcb_generate_id(conn); + xcb_render_create_cursor(conn, cursor, pic, spot.x(), spot.y()); + + free(xi->data); + xcb_image_destroy(xi); + xcb_render_free_picture(conn, pic); + xcb_free_pixmap(conn, pix); + free(formatsReply); + return cursor; + +#else + Q_UNUSED(screen); + Q_UNUSED(image); + Q_UNUSED(spot); + return XCB_NONE; +#endif +} + +QT_END_NAMESPACE diff --git a/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.h b/src/plugins/platforms/xcb/qxcbimage.h index 014486bdb4..1e7f104084 100644 --- a/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.h +++ b/src/plugins/platforms/xcb/qxcbimage.h @@ -39,50 +39,26 @@ ** ****************************************************************************/ -#ifndef QSCREENVNC_QWS_H -#define QSCREENVNC_QWS_H +#ifndef QXCBIMAGE_H +#define QXCBIMAGE_H -#include <QtGui/qscreenproxy_qws.h> - -#ifndef QT_NO_QWS_VNC - -QT_BEGIN_HEADER +#include "qxcbscreen.h" +#include <QtCore/QPair> +#include <QtGui/QImage> +#include <QtGui/QPixmap> +#include <xcb/xcb_image.h> QT_BEGIN_NAMESPACE -QT_MODULE(Gui) - -class QVNCScreenPrivate; - -class QVNCScreen : public QProxyScreen -{ -public: - explicit QVNCScreen(int display_id); - virtual ~QVNCScreen(); - - bool initDevice(); - bool connect(const QString &displaySpec); - void disconnect(); - void shutdownDevice(); - - void setDirty(const QRect&); - -private: - friend class QVNCCursor; - friend class QVNCClientCursor; - friend class QVNCServer; - friend class QVNCScreenPrivate; - -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - bool swapBytes() const; -#endif - - QVNCScreenPrivate *d_ptr; -}; +QImage::Format qt_xcb_imageFormatForVisual(QXcbConnection *connection, + uint8_t depth, const xcb_visualtype_t *visual); +QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap, + int width, int height, int depth, + const xcb_visualtype_t *visual); +xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image); +xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, + const QPoint &spot); QT_END_NAMESPACE -QT_END_HEADER - -#endif // QT_NO_QWS_VNC -#endif // QSCREENVNC_QWS_H +#endif diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 12b63f36ea..b0d377bcac 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -43,76 +43,161 @@ #include "qxcbconnection.h" #include "qxcbscreen.h" #include "qxcbwindow.h" -#include "qxcbwindowsurface.h" +#include "qxcbbackingstore.h" #include "qxcbnativeinterface.h" +#include "qxcbclipboard.h" +#include "qxcbdrag.h" #include <xcb/xcb.h> -#include <private/qpixmap_raster_p.h> - -#include "qgenericunixfontdatabase.h" +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> #include <stdio.h> +//this has to be included before egl, since egl pulls in X headers +#include <QtGui/private/qguiapplication_p.h> + #ifdef XCB_USE_EGL #include <EGL/egl.h> #endif -QXcbIntegration::QXcbIntegration() - : m_connection(new QXcbConnection) +#include <private/qplatforminputcontextfactory_qpa_p.h> +#include <qplatforminputcontext_qpa.h> + +#if defined(XCB_USE_GLX) +#include "qglxintegration.h" +#elif defined(XCB_USE_EGL) +#include "qxcbeglsurface.h" +#include <QtPlatformSupport/private/qeglplatformcontext_p.h> +#endif + +#include <QtGui/QOpenGLContext> +#include <QtGui/QScreen> + +QXcbIntegration::QXcbIntegration(const QStringList ¶meters) + : m_eventDispatcher(createUnixEventDispatcher()) { - foreach (QXcbScreen *screen, m_connection->screens()) - m_screens << screen; + QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); + +#ifdef XCB_USE_XLIB + XInitThreads(); +#endif + + m_connections << new QXcbConnection; + + for (int i = 0; i < parameters.size() - 1; i += 2) { + qDebug() << parameters.at(i) << parameters.at(i+1); + QString display = parameters.at(i) + ':' + parameters.at(i+1); + m_connections << new QXcbConnection(display.toAscii().constData()); + } + + foreach (QXcbConnection *connection, m_connections) + foreach (QXcbScreen *screen, connection->screens()) + screenAdded(screen); m_fontDatabase = new QGenericUnixFontDatabase(); m_nativeInterface = new QXcbNativeInterface; + + m_inputContext = QPlatformInputContextFactory::create(); } QXcbIntegration::~QXcbIntegration() { - delete m_connection; + qDeleteAll(m_connections); } -bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const +QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const { - switch (cap) { - case ThreadedPixmaps: return true; - case OpenGL: return hasOpenGL(); - default: return QPlatformIntegration::hasCapability(cap); - } + return new QXcbWindow(window); } -QPixmapData *QXcbIntegration::createPixmapData(QPixmapData::PixelType type) const +#if defined(XCB_USE_EGL) +class QEGLXcbPlatformContext : public QEGLPlatformContext { - return new QRasterPixmapData(type); -} +public: + QEGLXcbPlatformContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share, + EGLDisplay display, QXcbConnection *c) + : QEGLPlatformContext(glFormat, share, display) + , m_connection(c) + { + Q_XCB_NOOP(m_connection); + } + + void swapBuffers(QPlatformSurface *surface) + { + Q_XCB_NOOP(m_connection); + QEGLPlatformContext::swapBuffers(surface); + Q_XCB_NOOP(m_connection); + } + + bool makeCurrent(QPlatformSurface *surface) + { + Q_XCB_NOOP(m_connection); + bool ret = QEGLPlatformContext::makeCurrent(surface); + Q_XCB_NOOP(m_connection); + return ret; + } + + void doneCurrent() + { + Q_XCB_NOOP(m_connection); + QEGLPlatformContext::doneCurrent(); + Q_XCB_NOOP(m_connection); + } + + EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) + { + return static_cast<QXcbWindow *>(surface)->eglSurface()->surface(); + } -QPlatformWindow *QXcbIntegration::createPlatformWindow(QWidget *widget, WId winId) const +private: + QXcbConnection *m_connection; +}; +#endif + +QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - Q_UNUSED(winId); - return new QXcbWindow(widget); + QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle()); +#if defined(XCB_USE_GLX) + return new QGLXContext(screen, context->format(), context->shareHandle()); +#elif defined(XCB_USE_EGL) + return new QEGLXcbPlatformContext(context->format(), context->shareHandle(), + screen->connection()->egl_display(), screen->connection()); +#elif defined(XCB_USE_DRI2) + return new QDri2Context(context->format(), context->shareHandle()); +#endif } -QWindowSurface *QXcbIntegration::createWindowSurface(QWidget *widget, WId winId) const +QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window) const { - Q_UNUSED(winId); - return new QXcbWindowSurface(widget); + return new QXcbBackingStore(window); } -QList<QPlatformScreen *> QXcbIntegration::screens() const +bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const { - return m_screens; + switch (cap) { + case ThreadedPixmaps: return true; + case OpenGL: return true; + case ThreadedOpenGL: +#ifdef XCB_POLL_FOR_QUEUED_EVENT + return true; +#else + return false; +#endif + default: return QPlatformIntegration::hasCapability(cap); + } } -void QXcbIntegration::moveToScreen(QWidget *window, int screen) +QAbstractEventDispatcher *QXcbIntegration::guiThreadEventDispatcher() const { - Q_UNUSED(window); - Q_UNUSED(screen); + return m_eventDispatcher; } -bool QXcbIntegration::isVirtualDesktop() +void QXcbIntegration::moveToScreen(QWindow *window, int screen) { - return false; + Q_UNUSED(window); + Q_UNUSED(screen); } QPlatformFontDatabase *QXcbIntegration::fontDatabase() const @@ -120,32 +205,22 @@ QPlatformFontDatabase *QXcbIntegration::fontDatabase() const return m_fontDatabase; } -QPixmap QXcbIntegration::grabWindow(WId window, int x, int y, int width, int height) const +QPlatformNativeInterface * QXcbIntegration::nativeInterface() const { - Q_UNUSED(window); - Q_UNUSED(x); - Q_UNUSED(y); - Q_UNUSED(width); - Q_UNUSED(height); - return QPixmap(); + return m_nativeInterface; } +QPlatformClipboard *QXcbIntegration::clipboard() const +{ + return m_connections.at(0)->clipboard(); +} -bool QXcbIntegration::hasOpenGL() const +QPlatformDrag *QXcbIntegration::drag() const { -#if defined(XCB_USE_GLX) - return true; -#elif defined(XCB_USE_EGL) - return m_connection->hasEgl(); -#elif defined(XCB_USE_DRI2) - if (m_connection->hasSupportForDri2()) { - return true; - } -#endif - return false; + return m_connections.at(0)->drag(); } -QPlatformNativeInterface * QXcbIntegration::nativeInterface() const +QPlatformInputContext *QXcbIntegration::inputContext() const { - return m_nativeInterface; + return m_inputContext; } diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index cd68919b54..cad127c28e 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -48,34 +48,40 @@ QT_BEGIN_NAMESPACE class QXcbConnection; +class QAbstractEventDispatcher; class QXcbIntegration : public QPlatformIntegration { public: - QXcbIntegration(); + QXcbIntegration(const QStringList ¶meters); ~QXcbIntegration(); + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + bool hasCapability(Capability cap) const; - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; + QAbstractEventDispatcher *guiThreadEventDispatcher() const; - QList<QPlatformScreen *> screens() const; - void moveToScreen(QWidget *window, int screen); - bool isVirtualDesktop(); - QPixmap grabWindow(WId window, int x, int y, int width, int height) const; + void moveToScreen(QWindow *window, int screen); QPlatformFontDatabase *fontDatabase() const; QPlatformNativeInterface *nativeInterface()const; + QPlatformClipboard *clipboard() const; + QPlatformDrag *drag() const; + + QPlatformInputContext *inputContext() const; + private: - bool hasOpenGL() const; - QList<QPlatformScreen *> m_screens; - QXcbConnection *m_connection; + QList<QXcbConnection *> m_connections; QPlatformFontDatabase *m_fontDatabase; QPlatformNativeInterface *m_nativeInterface; + + QPlatformInputContext *m_inputContext; + QAbstractEventDispatcher *m_eventDispatcher; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 6bbc3c18ca..907dd0f1b6 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -40,16 +40,17 @@ ****************************************************************************/ #include "qxcbkeyboard.h" - +#include "qxcbwindow.h" +#include "qxcbscreen.h" #include <xcb/xcb_keysyms.h> - #include <X11/keysym.h> - #include <QtGui/QWindowSystemInterface> #include <QtCore/QTextCodec> - +#include <private/qguiapplication_p.h> #include <stdio.h> +#include <qplatforminputcontext_qpa.h> + #ifndef XK_ISO_Left_Tab #define XK_ISO_Left_Tab 0xFE20 #endif @@ -898,12 +899,9 @@ QString QXcbKeyboard::translateKeySym(xcb_keysym_t keysym, uint xmodifiers, QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) : QXcbObject(connection) - , m_alt_mask(0) - , m_super_mask(0) - , m_hyper_mask(0) - , m_meta_mask(0) { m_key_symbols = xcb_key_symbols_alloc(xcb_connection()); + setupModifiers(); } QXcbKeyboard::~QXcbKeyboard() @@ -911,18 +909,113 @@ QXcbKeyboard::~QXcbKeyboard() xcb_key_symbols_free(m_key_symbols); } -// #define XCB_KEYBOARD_DEBUG +void QXcbKeyboard::setupModifiers() +{ + m_alt_mask = 0; + m_super_mask = 0; + m_hyper_mask = 0; + m_meta_mask = 0; + m_mode_switch_mask = 0; + m_num_lock_mask = 0; + m_caps_lock_mask = 0; + + xcb_generic_error_t *error = 0; + xcb_connection_t *conn = xcb_connection(); + xcb_get_modifier_mapping_cookie_t modMapCookie = xcb_get_modifier_mapping(conn); + xcb_get_modifier_mapping_reply_t *modMapReply = + xcb_get_modifier_mapping_reply(conn, modMapCookie, &error); + if (error) { + qWarning("xcb keyboard: failed to get modifier mapping"); + free(error); + return; + } + + // Figure out the modifier mapping, ICCCM 6.6 + typedef QPair<uint, xcb_keycode_t *> SymCodes; + QList<SymCodes> modKeyCodes; + + // for Alt and Meta L and R are the same + modKeyCodes << SymCodes(XK_Alt_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Alt_L)); + modKeyCodes << SymCodes(XK_Meta_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Meta_L)); + modKeyCodes << SymCodes(XK_Super_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Super_L)); + modKeyCodes << SymCodes(XK_Super_R, xcb_key_symbols_get_keycode(m_key_symbols, XK_Super_R)); + modKeyCodes << SymCodes(XK_Hyper_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Hyper_L)); + modKeyCodes << SymCodes(XK_Hyper_R, xcb_key_symbols_get_keycode(m_key_symbols, XK_Hyper_R)); + modKeyCodes << SymCodes(XK_Num_Lock, xcb_key_symbols_get_keycode(m_key_symbols, XK_Num_Lock)); + modKeyCodes << SymCodes(XK_Mode_switch, xcb_key_symbols_get_keycode(m_key_symbols, XK_Mode_switch)); + modKeyCodes << SymCodes(XK_Caps_Lock, xcb_key_symbols_get_keycode(m_key_symbols, XK_Caps_Lock)); + + xcb_keycode_t *modMap = xcb_get_modifier_mapping_keycodes(modMapReply); + const int w = modMapReply->keycodes_per_modifier; + for (int i = 0; i < modKeyCodes.count(); ++i) { + for (int bit = 0; bit < 8; ++bit) { + uint mask = 1 << bit; + for (int x = 0; x < w; ++x) { + xcb_keycode_t keyCode = modMap[x + bit * w]; + xcb_keycode_t *itk = modKeyCodes.at(i).second; + while (itk && *itk != XCB_NO_SYMBOL) + if (*itk++ == keyCode) + setMask(modKeyCodes.at(i).first, mask); + } + } + } -void QXcbKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time) + for (int i = 0; i < modKeyCodes.count(); ++i) + free(modKeyCodes.at(i).second); + free(modMapReply); +} + +void QXcbKeyboard::setMask(uint sym, uint mask) { - int col = state & XCB_MOD_MASK_SHIFT ? 1 : 0; + 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; + + if (m_caps_lock_mask == 0 && sym == XK_Caps_Lock) + m_caps_lock_mask = mask; +} - const int altGrOffset = 4; - if (state & 128) - col += altGrOffset; +// #define XCB_KEYBOARD_DEBUG +void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, + quint16 state, xcb_timestamp_t time) +{ Q_XCB_NOOP(connection()); - #ifdef XCB_KEYBOARD_DEBUG printf("key code: %d, state: %d, syms: ", code, state); for (int i = 0; i <= 5; ++i) { @@ -931,43 +1024,105 @@ void QXcbKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycod printf("\n"); #endif - Q_XCB_NOOP(connection()); + QByteArray chars; + xcb_keysym_t sym = lookupString(window, state, code, type, &chars); + + + if (QObject* inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext()) { + bool retval; + QMetaObject::invokeMethod(inputContext, "x11FilterEvent", Qt::DirectConnection, + Q_RETURN_ARG(bool, retval), + Q_ARG(uint, sym), + Q_ARG(uint, code), + Q_ARG(uint, state), + Q_ARG(bool, type == QEvent::KeyPress)); + if (retval) + return; + } + Qt::KeyboardModifiers modifiers; + int qtcode = 0; + int count = chars.count(); + QString string = translateKeySym(sym, state, qtcode, modifiers, chars, count); + QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers, + code, 0, state, string.left(count)); +} + +#ifdef XCB_USE_XLIB +extern "C" { + int XLookupString(void *event, char *buf, int count, void *keysym, void *comp); +} +typedef struct { // must match XKeyEvent in Xlib.h + int type; + unsigned long serial; + int send_event; + void *display; + unsigned long window; + unsigned long root; + unsigned long subwindow; + unsigned long time; + int x, y; + int x_root, y_root; + unsigned int state; + unsigned int keycode; + int same_screen; +} FakeXKeyEvent; +#endif + +xcb_keysym_t QXcbKeyboard::lookupString(QWindow *window, uint state, xcb_keycode_t code, + QEvent::Type type, QByteArray *chars) +{ +#ifdef XCB_USE_XLIB + + xcb_keysym_t sym = XCB_NO_SYMBOL; + chars->resize(512); + FakeXKeyEvent event; + memset(&event, 0, sizeof(event)); + event.type = (type == QEvent::KeyRelease ? 3 : 2); + event.display = connection()->xlib_display(); + event.window = static_cast<QXcbWindow *>(window->handle())->xcb_window(); + event.root = connection()->screens().at(0)->root(); + event.state = state; + event.keycode = code; + int count = XLookupString(&event, chars->data(), chars->size(), &sym, 0); + chars->resize(count); + return sym; + +#else + + // No XLookupString available. The following is really incomplete... + + int col = state & XCB_MOD_MASK_SHIFT ? 1 : 0; + const int altGrOffset = 4; + if (state & 128) + col += altGrOffset; xcb_keysym_t sym = xcb_key_symbols_get_keysym(m_key_symbols, code, col); if (sym == XCB_NO_SYMBOL) sym = xcb_key_symbols_get_keysym(m_key_symbols, code, col ^ 0x1); - if (state & XCB_MOD_MASK_LOCK && sym <= 0x7f && isprint(sym)) { if (isupper(sym)) sym = tolower(sym); else sym = toupper(sym); } + return sym; - Q_XCB_NOOP(connection()); - - QByteArray chars; - - Qt::KeyboardModifiers modifiers; - int qtcode = 0; - int count = 0; - - QString string = translateKeySym(sym, state, qtcode, modifiers, chars, count); - - QWindowSystemInterface::handleExtendedKeyEvent(widget, time, type, qtcode, modifiers, code, 0, state, string.left(count)); +#endif } -void QXcbKeyboard::handleKeyPressEvent(QWidget *widget, const xcb_key_press_event_t *event) +void QXcbKeyboard::handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event) { - handleKeyEvent(widget, QEvent::KeyPress, event->detail, event->state, event->time); + window->updateNetWmUserTime(event->time); + handleKeyEvent(window->window(), QEvent::KeyPress, event->detail, event->state, event->time); } -void QXcbKeyboard::handleKeyReleaseEvent(QWidget *widget, const xcb_key_release_event_t *event) +void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event) { - handleKeyEvent(widget, QEvent::KeyRelease, event->detail, event->state, event->time); + handleKeyEvent(window->window(), QEvent::KeyRelease, event->detail, event->state, event->time); } void QXcbKeyboard::handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event) { xcb_refresh_keyboard_mapping(m_key_symbols, const_cast<xcb_mapping_notify_event_t *>(event)); + setupModifiers(); } diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index 095c3e4efb..ea5f84e8c2 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -48,26 +48,32 @@ #include <QEvent> +class QWindow; + class QXcbKeyboard : public QXcbObject { public: QXcbKeyboard(QXcbConnection *connection); ~QXcbKeyboard(); - void handleKeyPressEvent(QWidget *widget, const xcb_key_press_event_t *event); - void handleKeyReleaseEvent(QWidget *widget, const xcb_key_release_event_t *event); + void handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event); + void handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event); void handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event); Qt::KeyboardModifiers translateModifiers(int s); private: - void handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time); + void handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time); int translateKeySym(uint key) const; QString translateKeySym(xcb_keysym_t keysym, uint xmodifiers, int &code, Qt::KeyboardModifiers &modifiers, QByteArray &chars, int &count); + void setupModifiers(); + void setMask(uint sym, uint mask); + xcb_keysym_t lookupString(QWindow *window, uint state, xcb_keycode_t code, + QEvent::Type type, QByteArray *chars); uint m_alt_mask; uint m_super_mask; @@ -75,6 +81,7 @@ private: uint m_meta_mask; uint m_mode_switch_mask; uint m_num_lock_mask; + uint m_caps_lock_mask; xcb_key_symbols_t *m_key_symbols; }; diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp new file mode 100644 index 0000000000..d4f80ca09d --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbmime.cpp @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** 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 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 "qxcbmime.h" + +#include <QtCore/QTextCodec> +#include <QtGui/QImageWriter> +#include <QtCore/QBuffer> +#include <qdebug.h> + +#include <X11/Xutil.h> + +#undef XCB_ATOM_STRING +#undef XCB_ATOM_PIXMAP +#undef XCB_ATOM_BITMAP + +QXcbMime::QXcbMime() + : QInternalMimeData() +{ } + +QXcbMime::~QXcbMime() +{} + + + +QString QXcbMime::mimeAtomToString(QXcbConnection *connection, xcb_atom_t a) +{ + if (a == XCB_NONE) + return QString(); + + // special cases for string type + if (a == XCB_ATOM_STRING + || a == connection->atom(QXcbAtom::UTF8_STRING) + || a == connection->atom(QXcbAtom::TEXT)) + return QLatin1String("text/plain"); + + // special case for images + if (a == XCB_ATOM_PIXMAP) + return QLatin1String("image/ppm"); + + QByteArray atomName = connection->atomName(a); + + // special cases for uris + if (atomName == "text/x-moz-url") + atomName = "text/uri-list"; + + return QString::fromLatin1(atomName.constData()); +} + +bool QXcbMime::mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data, + xcb_atom_t *atomFormat, int *dataFormat) +{ + if (!data) + return false; + + bool ret = false; + *atomFormat = a; + *dataFormat = 8; + + if ((a == connection->atom(QXcbAtom::UTF8_STRING) + || a == XCB_ATOM_STRING + || a == connection->atom(QXcbAtom::TEXT)) + && QInternalMimeData::hasFormatHelper(QLatin1String("text/plain"), mimeData)) { + if (a == connection->atom(QXcbAtom::UTF8_STRING)) { + *data = QInternalMimeData::renderDataHelper(QLatin1String("text/plain"), mimeData); + ret = true; + } else if (a == XCB_ATOM_STRING || + a == connection->atom(QXcbAtom::TEXT)) { + // ICCCM says STRING is latin1 + *data = QString::fromUtf8(QInternalMimeData::renderDataHelper( + QLatin1String("text/plain"), mimeData)).toLatin1(); + ret = true; + } + return ret; + } + + QString atomName = mimeAtomToString(connection, a); + if (QInternalMimeData::hasFormatHelper(atomName, mimeData)) { + *data = QInternalMimeData::renderDataHelper(atomName, mimeData); + if (atomName == QLatin1String("application/x-color")) + *dataFormat = 16; + ret = true; + } 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 == XCB_ATOM_PIXMAP || a == XCB_ATOM_BITMAP) && mimeData->hasImage()) { + ret = true; + } + return ret; +} + +QList<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, const QString &format) +{ + QList<xcb_atom_t> atoms; + atoms.append(connection->internAtom(format.toLatin1())); + + // special cases for strings + if (format == QLatin1String("text/plain")) { + atoms.append(connection->atom(QXcbAtom::UTF8_STRING)); + atoms.append(XCB_ATOM_STRING); + atoms.append(connection->atom(QXcbAtom::TEXT)); + } + + // special cases for uris + if (format == QLatin1String("text/uri-list")) + atoms.append(connection->internAtom("text/x-moz-url")); + + //special cases for images + if (format == QLatin1String("image/ppm")) + atoms.append(XCB_ATOM_PIXMAP); + if (format == QLatin1String("image/pbm")) + atoms.append(XCB_ATOM_BITMAP); + + return atoms; +} + +QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format, + QVariant::Type requestedType, const QByteArray &encoding) +{ + QString atomName = mimeAtomToString(connection, a); +// qDebug() << "mimeConvertDataToFormat" << format << atomName << 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 == connection->atom(QXcbAtom::UTF8_STRING)) + return QString::fromUtf8(data); + if (a == XCB_ATOM_STRING || + a == connection->atom(QXcbAtom::TEXT)) + return QString::fromLatin1(data); + } + + // 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(); + } + } + + if (atomName == format) + return data; + +#if 0 // ### + // special case for images + if (format == QLatin1String("image/ppm")) { + if (a == XCB_ATOM_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(); + } + } +#endif + return QVariant(); +} + +xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType, + const QList<xcb_atom_t> &atoms, QByteArray *requestedEncoding) +{ + requestedEncoding->clear(); + + // find matches for string types + if (format == QLatin1String("text/plain")) { + if (atoms.contains(connection->atom(QXcbAtom::UTF8_STRING))) + return connection->atom(QXcbAtom::UTF8_STRING); + if (atoms.contains(XCB_ATOM_STRING)) + return XCB_ATOM_STRING; + if (atoms.contains(connection->atom(QXcbAtom::TEXT))) + return connection->atom(QXcbAtom::TEXT); + } + + // find matches for uri types + if (format == QLatin1String("text/uri-list")) { + xcb_atom_t a = connection->internAtom(format.toLatin1()); + if (a && atoms.contains(a)) + return a; + a = connection->internAtom("text/x-moz-url"); + if (a && atoms.contains(a)) + return a; + } + + // find match for image + if (format == QLatin1String("image/ppm")) { + if (atoms.contains(XCB_ATOM_PIXMAP)) + return XCB_ATOM_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")); + + xcb_atom_t a = connection->internAtom(formatWithCharset.toLatin1()); + if (a && atoms.contains(a)) { + *requestedEncoding = "utf-8"; + return a; + } + } + + xcb_atom_t a = connection->internAtom(format.toLatin1()); + if (a && atoms.contains(a)) + return a; + + return 0; +} diff --git a/src/plugins/platforms/xcb/qxcbmime.h b/src/plugins/platforms/xcb/qxcbmime.h new file mode 100644 index 0000000000..4ab38ed803 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbmime.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 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 QXCBMIME_H +#define QXCBMIME_H + +#include <private/qdnd_p.h> + +#include <QtGui/QClipboard> + +#include "qxcbintegration.h" +#include "qxcbconnection.h" + +class QXcbMime : public QInternalMimeData { + Q_OBJECT +public: + QXcbMime(); + ~QXcbMime(); + + static QList<xcb_atom_t> mimeAtomsForFormat(QXcbConnection *connection, const QString &format); + static QString mimeAtomToString(QXcbConnection *connection, xcb_atom_t a); + static bool mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data, + xcb_atom_t *atomFormat, int *dataFormat); + static QVariant mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format, + QVariant::Type requestedType, const QByteArray &encoding); + static xcb_atom_t mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType, + const QList<xcb_atom_t> &atoms, QByteArray *requestedEncoding); +}; + +#endif // QXCBMIME_H diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 6423f1b798..3c9cdfd257 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -43,13 +43,16 @@ #include "qxcbscreen.h" -#include <QtGui/private/qapplication_p.h> +#include <private/qguiapplication_p.h> #include <QtCore/QMap> #include <QtCore/QDebug> +#include <QtGui/qopenglcontext.h> +#include <QtGui/qscreen.h> + #if defined(XCB_USE_EGL) -#include "../eglconvenience/qeglplatformcontext.h" +#include "QtPlatformSupport/private/qeglplatformcontext_p.h" #elif defined (XCB_USE_DRI2) #include "qdri2context.h" #endif @@ -71,29 +74,41 @@ public: Q_GLOBAL_STATIC(QXcbResourceMap, qXcbResourceMap) -void *QXcbNativeInterface::nativeResourceForWidget(const QByteArray &resourceString, QWidget *widget) +void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) +{ + QByteArray lowerCaseResource = resourceString.toLower(); + ResourceType resource = qXcbResourceMap()->value(lowerCaseResource); + void *result = 0; + switch(resource) { + case EglContext: + result = eglContextForContext(context); + break; + default: + result = 0; + } + return result; +} + +void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { QByteArray lowerCaseResource = resourceString.toLower(); ResourceType resource = qXcbResourceMap()->value(lowerCaseResource); void *result = 0; switch(resource) { case Display: - result = displayForWidget(widget); + result = displayForWindow(window); break; case EglDisplay: - result = eglDisplayForWidget(widget); + result = eglDisplayForWindow(window); break; case Connection: - result = connectionForWidget(widget); + result = connectionForWindow(window); break; case Screen: - result = qPlatformScreenForWidget(widget); + result = qPlatformScreenForWindow(window); break; case GraphicsDevice: - result = graphicsDeviceForWidget(widget); - break; - case EglContext: - result = eglContextForWidget(widget); + result = graphicsDeviceForWindow(window); break; default: result = 0; @@ -101,75 +116,76 @@ void *QXcbNativeInterface::nativeResourceForWidget(const QByteArray &resourceStr return result; } -QXcbScreen *QXcbNativeInterface::qPlatformScreenForWidget(QWidget *widget) +QXcbScreen *QXcbNativeInterface::qPlatformScreenForWindow(QWindow *window) { QXcbScreen *screen; - if (widget) { - screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(widget)); - }else { - screen = static_cast<QXcbScreen *>(QApplicationPrivate::platformIntegration()->screens()[0]); + if (window) { + screen = static_cast<QXcbScreen *>(window->screen()->handle()); + } else { + screen = static_cast<QXcbScreen *>(QGuiApplication::primaryScreen()->handle()); } return screen; } -void *QXcbNativeInterface::displayForWidget(QWidget *widget) +void *QXcbNativeInterface::displayForWindow(QWindow *window) { #if defined(XCB_USE_XLIB) - QXcbScreen *screen = qPlatformScreenForWidget(widget); + QXcbScreen *screen = qPlatformScreenForWindow(window); return screen->connection()->xlib_display(); #else - Q_UNUSED(widget); + Q_UNUSED(window); return 0; #endif } -void *QXcbNativeInterface::eglDisplayForWidget(QWidget *widget) +void *QXcbNativeInterface::eglDisplayForWindow(QWindow *window) { #if defined(XCB_USE_DRI2) || defined(XCB_USE_EGL) - QXcbScreen *screen = qPlatformScreenForWidget(widget); + QXcbScreen *screen = qPlatformScreenForWindow(window); return screen->connection()->egl_display(); #else - Q_UNUSED(widget) + Q_UNUSED(window) return 0; #endif } -void *QXcbNativeInterface::connectionForWidget(QWidget *widget) +void *QXcbNativeInterface::connectionForWindow(QWindow *window) { - QXcbScreen *screen = qPlatformScreenForWidget(widget); + QXcbScreen *screen = qPlatformScreenForWindow(window); return screen->xcb_connection(); } -void *QXcbNativeInterface::screenForWidget(QWidget *widget) +void *QXcbNativeInterface::screenForWindow(QWindow *window) { - QXcbScreen *screen = qPlatformScreenForWidget(widget); + QXcbScreen *screen = qPlatformScreenForWindow(window); return screen->screen(); } -void *QXcbNativeInterface::graphicsDeviceForWidget(QWidget *widget) +void *QXcbNativeInterface::graphicsDeviceForWindow(QWindow *window) { #if defined(XCB_USE_DRI2) - QXcbScreen *screen = qPlatformScreenForWidget(widget); + QXcbScreen *screen = qPlatformScreenForWindow(window); QByteArray deviceName = screen->connection()->dri2DeviceName(); return deviceName.data(); #else - Q_UNUSED(widget); + Q_UNUSED(window); return 0; #endif } -void * QXcbNativeInterface::eglContextForWidget(QWidget *widget) +void * QXcbNativeInterface::eglContextForContext(QOpenGLContext *context) { - Q_ASSERT(widget); - if (!widget->platformWindow()) { - qDebug() << "QPlatformWindow does not exist for widget" << widget - << "cannot return EGLContext"; - return 0; - } - QPlatformGLContext *platformContext = widget->platformWindow()->glContext(); + Q_ASSERT(context); +#if defined(XCB_USE_EGL) + QEGLPlatformContext *eglPlatformContext = static_cast<QEGLPlatformContext *>(context->handle()); + return eglPlatformContext->eglContext(); +#endif +#if 0 + Q_ASSERT(window); + QPlatformOpenGLContext *platformContext = window->glContext()->handle(); if (!platformContext) { - qDebug() << "QPlatformWindow" << widget->platformWindow() << "does not have a glContext" + qDebug() << "QWindow" << window << "does not have a glContext" << "cannot return EGLContext"; return 0; } @@ -182,4 +198,7 @@ void * QXcbNativeInterface::eglContextForWidget(QWidget *widget) #else return 0; #endif +#else + return 0; +#endif } diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index 3fb0fa5e2d..8dec83267a 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -59,17 +59,19 @@ public: EglContext }; - void *nativeResourceForWidget(const QByteArray &resourceString, QWidget *widget); + void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); + void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); - void *displayForWidget(QWidget *widget); - void *eglDisplayForWidget(QWidget *widget); - void *connectionForWidget(QWidget *widget); - void *screenForWidget(QWidget *widget); - void *graphicsDeviceForWidget(QWidget *widget); - void *eglContextForWidget(QWidget *widget); + void *displayForWindow(QWindow *window); + void *eglDisplayForWindow(QWindow *window); + void *connectionForWindow(QWindow *window); + void *screenForWindow(QWindow *window); + void *graphicsDeviceForWindow(QWindow *window); + + void *eglContextForContext(QOpenGLContext *context); private: - static QXcbScreen *qPlatformScreenForWidget(QWidget *widget); + static QXcbScreen *qPlatformScreenForWindow(QWindow *window); }; #endif // QXCBNATIVEINTERFACE_H diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 9a4858123b..42259feda8 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -40,6 +40,9 @@ ****************************************************************************/ #include "qxcbscreen.h" +#include "qxcbwindow.h" +#include "qxcbcursor.h" +#include "qxcbimage.h" #include <stdio.h> @@ -102,10 +105,104 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num free(reply); m_syncRequestSupported = m_windowManagerName != QLatin1String("KWin"); + + m_clientLeader = xcb_generate_id(xcb_connection()); + Q_XCB_CALL2(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, + m_clientLeader, + m_screen->root, + 0, 0, 1, 1, + 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + m_screen->root_visual, + 0, 0), connection); + + Q_XCB_CALL2(xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, + m_clientLeader, + atom(QXcbAtom::WM_CLIENT_LEADER), + XCB_ATOM_WINDOW, + 32, + 1, + &m_clientLeader), connection); + + xcb_depth_iterator_t depth_iterator = + xcb_screen_allowed_depths_iterator(screen); + + while (depth_iterator.rem) { + xcb_depth_t *depth = depth_iterator.data; + xcb_visualtype_iterator_t visualtype_iterator = + xcb_depth_visuals_iterator(depth); + + while (visualtype_iterator.rem) { + xcb_visualtype_t *visualtype = visualtype_iterator.data; + m_visuals.insert(visualtype->visual_id, *visualtype); + xcb_visualtype_next(&visualtype_iterator); + } + + xcb_depth_next(&depth_iterator); + } + + m_cursor = new QXcbCursor(connection, this); } QXcbScreen::~QXcbScreen() { + delete m_cursor; +} + + +QWindow *QXcbScreen::topLevelAt(const QPoint &p) const +{ + xcb_window_t root = m_screen->root; + + int x = p.x(); + int y = p.y(); + + xcb_generic_error_t *error; + + xcb_window_t parent = root; + xcb_window_t child = root; + + do { + xcb_translate_coordinates_cookie_t translate_cookie = + xcb_translate_coordinates(xcb_connection(), parent, child, x, y); + + xcb_translate_coordinates_reply_t *translate_reply = + xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, &error); + + if (!translate_reply) { + if (error) { + connection()->handleXcbError(error); + free(error); + } + return 0; + } + + parent = child; + child = translate_reply->child; + x = translate_reply->dst_x; + y = translate_reply->dst_y; + + free(translate_reply); + + if (!child || child == root) + return 0; + + QPlatformWindow *platformWindow = connection()->platformWindowFromId(child); + if (platformWindow) + return platformWindow->window(); + } while (parent != child); + + return 0; +} + +const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const +{ + QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid); + if (it == m_visuals.constEnd()) + return 0; + return &*it; } QRect QXcbScreen::geometry() const @@ -132,3 +229,126 @@ int QXcbScreen::screenNumber() const { return m_number; } + +QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) const +{ + if (width == 0 || height == 0) + return QPixmap(); + + xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry(xcb_connection(), window); + + xcb_generic_error_t *error; + xcb_get_geometry_reply_t *reply = + xcb_get_geometry_reply(xcb_connection(), geometry_cookie, &error); + + if (!reply) { + if (error) { + connection()->handleXcbError(error); + free(error); + } + return QPixmap(); + } + + if (width < 0) + width = reply->width - x; + if (height < 0) + height = reply->height - y; + + // TODO: handle multiple screens + QXcbScreen *screen = const_cast<QXcbScreen *>(this); + xcb_window_t root = screen->root(); + geometry_cookie = xcb_get_geometry(xcb_connection(), root); + xcb_get_geometry_reply_t *root_reply = + xcb_get_geometry_reply(xcb_connection(), geometry_cookie, &error); + + if (!root_reply) { + if (error) { + connection()->handleXcbError(error); + free(error); + } + free(reply); + return QPixmap(); + } + + if (reply->depth == root_reply->depth) { + // if the depth of the specified window and the root window are the + // same, grab pixels from the root window (so that we get the any + // overlapping windows and window manager frames) + + // map x and y to the root window + xcb_translate_coordinates_cookie_t translate_cookie = + xcb_translate_coordinates(xcb_connection(), window, root, x, y); + + xcb_translate_coordinates_reply_t *translate_reply = + xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, &error); + + if (!translate_reply) { + if (error) { + connection()->handleXcbError(error); + free(error); + } + free(reply); + free(root_reply); + return QPixmap(); + } + + x = translate_reply->dst_x; + y = translate_reply->dst_y; + + window = root; + + free(translate_reply); + free(reply); + reply = root_reply; + } else { + free(root_reply); + root_reply = 0; + } + + xcb_get_window_attributes_reply_t *attributes_reply = + xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes(xcb_connection(), window), &error); + + if (!attributes_reply) { + if (error) { + connection()->handleXcbError(error); + free(error); + } + free(reply); + return QPixmap(); + } + + const xcb_visualtype_t *visual = screen->visualForId(attributes_reply->visual); + free(attributes_reply); + + xcb_pixmap_t pixmap = xcb_generate_id(xcb_connection()); + error = xcb_request_check(xcb_connection(), xcb_create_pixmap_checked(xcb_connection(), reply->depth, pixmap, window, width, height)); + if (error) { + connection()->handleXcbError(error); + free(error); + } + + uint32_t gc_value_mask = XCB_GC_SUBWINDOW_MODE; + uint32_t gc_value_list[] = { XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS }; + + xcb_gcontext_t gc = xcb_generate_id(xcb_connection()); + xcb_create_gc(xcb_connection(), gc, pixmap, gc_value_mask, gc_value_list); + + error = xcb_request_check(xcb_connection(), xcb_copy_area_checked(xcb_connection(), window, pixmap, gc, x, y, 0, 0, width, height)); + if (error) { + connection()->handleXcbError(error); + free(error); + } + + QPixmap result = qt_xcb_pixmapFromXPixmap(connection(), pixmap, width, height, reply->depth, visual); + + free(reply); + xcb_free_gc(xcb_connection(), gc); + xcb_free_pixmap(xcb_connection(), pixmap); + + return result; +} + +QString QXcbScreen::name() const +{ + return connection()->displayName() + QLatin1String(".") + QString::number(screenNumber()); +} diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index a78ee822f4..07d855b398 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -50,6 +50,7 @@ #include "qxcbobject.h" class QXcbConnection; +class QXcbCursor; class QXcbScreen : public QXcbObject, public QPlatformScreen { @@ -57,6 +58,10 @@ public: QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int number); ~QXcbScreen(); + QPixmap grabWindow(WId window, int x, int y, int width, int height) const; + + QWindow *topLevelAt(const QPoint &point) const; + QRect geometry() const; int depth() const; QImage::Format format() const; @@ -67,14 +72,23 @@ public: xcb_screen_t *screen() const { return m_screen; } xcb_window_t root() const { return m_screen->root; } + xcb_window_t clientLeader() const { return m_clientLeader; } + QString windowManagerName() const { return m_windowManagerName; } bool syncRequestSupported() const { return m_syncRequestSupported; } + const xcb_visualtype_t *visualForId(xcb_visualid_t) const; + + QString name() const; + private: xcb_screen_t *m_screen; int m_number; QString m_windowManagerName; bool m_syncRequestSupported; + xcb_window_t m_clientLeader; + QMap<xcb_visualid_t, xcb_visualtype_t> m_visuals; + QXcbCursor *m_cursor; }; #endif diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 20e4187541..db8d37e817 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -42,9 +42,13 @@ #include "qxcbwindow.h" #include <QtDebug> +#include <QScreen> #include "qxcbconnection.h" #include "qxcbscreen.h" +#include "qxcbdrag.h" +#include "qxcbwmsupport.h" + #ifdef XCB_USE_DRI2 #include "qdri2context.h" #endif @@ -61,9 +65,10 @@ #define xcb_set_wm_hints xcb_icccm_set_wm_hints #endif -#include <private/qapplication_p.h> -#include <private/qwindowsurface_p.h> +#include <private/qguiapplication_p.h> +#include <private/qwindow_p.h> +#include <QtGui/QPlatformBackingStore> #include <QtGui/QWindowSystemInterface> #include <stdio.h> @@ -75,38 +80,71 @@ #if defined(XCB_USE_GLX) #include "qglxintegration.h" -#include "qglxconvenience.h" +#include <QtPlatformSupport/private/qglxconvenience_p.h> #elif defined(XCB_USE_EGL) -#include "../eglconvenience/qeglplatformcontext.h" -#include "../eglconvenience/qeglconvenience.h" -#include "../eglconvenience/qxlibeglintegration.h" +#include "qxcbeglsurface.h" +#include <QtPlatformSupport/private/qeglconvenience_p.h> +#include <QtPlatformSupport/private/qxlibeglintegration_p.h> #endif +#define XCOORD_MAX 16383 + +//#ifdef NET_WM_STATE_DEBUG + // Returns true if we should set WM_TRANSIENT_FOR on \a w -static inline bool isTransient(const QWidget *w) +static inline bool isTransient(const QWindow *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)); + 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; } -QXcbWindow::QXcbWindow(QWidget *tlw) - : QPlatformWindow(tlw) - , m_context(0) +QXcbWindow::QXcbWindow(QWindow *window) + : QPlatformWindow(window) + , m_window(0) + , m_syncCounter(0) + , m_mapped(false) + , m_netWmUserTimeWindow(XCB_NONE) +#if defined(XCB_USE_EGL) + , m_eglSurface(0) +#endif { - m_screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(tlw)); + m_screen = static_cast<QXcbScreen *>(window->screen()->handle()); setConnection(m_screen->connection()); - const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_EVENT_MASK; + create(); +} + +void QXcbWindow::create() +{ + destroy(); + + m_windowState = Qt::WindowNoState; + m_dirtyFrameMargins = true; + + Qt::WindowType type = window()->windowType(); + + if (type == Qt::Desktop) { + m_window = m_screen->root(); + m_depth = m_screen->screen()->root_depth; + m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + connection()->addWindow(m_window, this); + return; + } + + const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK; const quint32 values[] = { // XCB_CW_BACK_PIXMAP XCB_NONE, + // XCB_CW_OVERRIDE_REDIRECT + type == Qt::Popup || type == Qt::ToolTip, + // XCB_CW_SAVE_UNDER + type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer, // XCB_CW_EVENT_MASK XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY @@ -117,20 +155,33 @@ QXcbWindow::QXcbWindow(QWidget *tlw) | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW + | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE }; -#if defined(XCB_USE_GLX) || defined(XCB_USE_EGL) - if (tlw->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL - && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL) - || tlw->platformWindowFormat().alpha()) + QRect rect = window()->geometry(); + QPlatformWindow::setGeometry(rect); + + rect.setWidth(qBound(1, rect.width(), XCOORD_MAX)); + rect.setHeight(qBound(1, rect.height(), XCOORD_MAX)); + + xcb_window_t xcb_parent_id = m_screen->root(); + if (parent()) + xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window(); + + m_requestedFormat = window()->format(); + +#if (defined(XCB_USE_GLX) || defined(XCB_USE_EGL)) && defined(XCB_USE_XLIB) + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL) + || window()->format().hasAlpha()) { #if defined(XCB_USE_GLX) - XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), tlw->platformWindowFormat()); + XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), window()->format()); + #elif defined(XCB_USE_EGL) EGLDisplay eglDisplay = connection()->egl_display(); - EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,tlw->platformWindowFormat(),true); + EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, window()->format(), true); VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig); XVisualInfo visualInfoTemplate; @@ -143,18 +194,16 @@ QXcbWindow::QXcbWindow(QWidget *tlw) #endif //XCB_USE_GLX if (visualInfo) { m_depth = visualInfo->depth; - m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; - Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), m_screen->root(), visualInfo->visual, AllocNone); + m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone); XSetWindowAttributes a; a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); a.colormap = cmap; - m_window = XCreateWindow(DISPLAY_FROM_XCB(this), m_screen->root(), tlw->x(), tlw->y(), tlw->width(), tlw->height(), + m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(), 0, visualInfo->depth, InputOutput, visualInfo->visual, CWBackPixel|CWBorderPixel|CWColormap, &a); - - printf("created GL window: %d\n", m_window); } else { qFatal("no window!"); } @@ -163,25 +212,25 @@ QXcbWindow::QXcbWindow(QWidget *tlw) { m_window = xcb_generate_id(xcb_connection()); m_depth = m_screen->screen()->root_depth; - m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; Q_XCB_CALL(xcb_create_window(xcb_connection(), XCB_COPY_FROM_PARENT, // depth -- same as root m_window, // window id - m_screen->root(), // parent window id - tlw->x(), - tlw->y(), - tlw->width(), - tlw->height(), + xcb_parent_id, // parent window id + rect.x(), + rect.y(), + rect.width(), + rect.height(), 0, // border width XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class m_screen->screen()->root_visual, // visual 0, // value mask 0)); // value list - - printf("created regular window: %d\n", m_window); } + connection()->addWindow(m_window, this); + Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values)); xcb_atom_t properties[4]; @@ -193,7 +242,7 @@ QXcbWindow::QXcbWindow(QWidget *tlw) if (m_screen->syncRequestSupported()) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST); - if (tlw->windowFlags() & Qt::WindowContextHelpButtonHint) + if (window()->windowFlags() & Qt::WindowContextHelpButtonHint) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP); Q_XCB_CALL(xcb_change_property(xcb_connection(), @@ -221,29 +270,49 @@ QXcbWindow::QXcbWindow(QWidget *tlw) &m_syncCounter)); } - if (isTransient(tlw) && tlw->parentWidget()) { - // ICCCM 4.1.2.6 - QWidget *p = tlw->parentWidget()->window(); - xcb_window_t parentWindow = p->winId(); - Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, - 1, &parentWindow)); - - } - // set the PID to let the WM kill the application if unresponsive long pid = getpid(); Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 32, 1, &pid)); + + xcb_wm_hints_t hints; + memset(&hints, 0, sizeof(hints)); + xcb_wm_hints_set_normal(&hints); + + xcb_set_wm_hints(xcb_connection(), m_window, &hints); + + xcb_window_t leader = m_screen->clientLeader(); + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32, + 1, &leader)); + + setWindowFlags(window()->windowFlags()); + setWindowTitle(window()->windowTitle()); + setWindowState(window()->windowState()); + + connection()->drag()->dndEnable(this, true); } QXcbWindow::~QXcbWindow() { - delete m_context; - if (m_screen->syncRequestSupported()) + destroy(); +} + +void QXcbWindow::destroy() +{ + if (m_syncCounter && m_screen->syncRequestSupported()) Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter)); - Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window)); + if (m_window) { + connection()->removeWindow(m_window); + Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window)); + } + m_mapped = false; + +#if defined(XCB_USE_EGL) + delete m_eglSurface; + m_eglSurface = 0; +#endif } void QXcbWindow::setGeometry(const QRect &rect) @@ -251,40 +320,182 @@ void QXcbWindow::setGeometry(const QRect &rect) QPlatformWindow::setGeometry(rect); const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; - const quint32 values[] = { rect.x(), rect.y(), rect.width(), rect.height() }; + const quint32 values[] = { rect.x(), + rect.y(), + qBound(1, rect.width(), XCOORD_MAX), + qBound(1, rect.height(), XCOORD_MAX) }; Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values)); } +QMargins QXcbWindow::frameMargins() const +{ + if (m_dirtyFrameMargins) { + xcb_window_t window = m_window; + xcb_window_t parent = m_window; + + bool foundRoot = false; + + const QVector<xcb_window_t> &virtualRoots = + connection()->wmSupport()->virtualRoots(); + + while (!foundRoot) { + xcb_query_tree_cookie_t cookie = xcb_query_tree(xcb_connection(), parent); + + xcb_generic_error_t *error; + xcb_query_tree_reply_t *reply = xcb_query_tree_reply(xcb_connection(), cookie, &error); + if (reply) { + if (reply->root == reply->parent || virtualRoots.indexOf(reply->parent) != -1) { + foundRoot = true; + } else { + window = parent; + parent = reply->parent; + } + + free(reply); + } else { + if (error) { + connection()->handleXcbError(error); + free(error); + } + + m_dirtyFrameMargins = false; + m_frameMargins = QMargins(); + return m_frameMargins; + } + } + + QPoint offset; + + xcb_generic_error_t *error; + xcb_translate_coordinates_reply_t *reply = + xcb_translate_coordinates_reply( + xcb_connection(), + xcb_translate_coordinates(xcb_connection(), window, parent, 0, 0), + &error); + + if (reply) { + offset = QPoint(reply->dst_x, reply->dst_y); + free(reply); + } else if (error) { + free(error); + } + + xcb_get_geometry_reply_t *geom = + xcb_get_geometry_reply( + xcb_connection(), + xcb_get_geometry(xcb_connection(), parent), + &error); + + if (geom) { + // -- + // add the border_width for the window managers frame... some window managers + // do not use a border_width of zero for their frames, and if we the left and + // top strut, we ensure that pos() is absolutely correct. frameGeometry() + // will still be incorrect though... perhaps i should have foffset as well, to + // indicate the frame offset (equal to the border_width on X). + // - Brad + // -- copied from qwidget_x11.cpp + + int left = offset.x() + geom->border_width; + int top = offset.y() + geom->border_width; + int right = geom->width + geom->border_width - geometry().width() - offset.x(); + int bottom = geom->height + geom->border_width - geometry().height() - offset.y(); + + m_frameMargins = QMargins(left, top, right, bottom); + + free(geom); + } else if (error) { + free(error); + } + + m_dirtyFrameMargins = false; + } + + return m_frameMargins; +} + void QXcbWindow::setVisible(bool visible) { - xcb_wm_hints_t hints; - if (visible) { - if (widget()->isMinimized()) + if (visible) + show(); + else + hide(); +} + +void QXcbWindow::show() +{ + if (window()->isTopLevel()) { + xcb_get_property_cookie_t cookie = xcb_get_wm_hints(xcb_connection(), m_window); + + xcb_generic_error_t *error; + + xcb_wm_hints_t hints; + xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, &error); + + if (error) { + connection()->handleXcbError(error); + free(error); + } + + m_dirtyFrameMargins = true; + + if (window()->windowState() & Qt::WindowMinimized) xcb_wm_hints_set_iconic(&hints); else xcb_wm_hints_set_normal(&hints); + xcb_set_wm_hints(xcb_connection(), m_window, &hints); - Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); - connection()->sync(); - } else { - Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window)); - - // send synthetic UnmapNotify event according to icccm 4.1.4 - xcb_unmap_notify_event_t event; - event.response_type = XCB_UNMAP_NOTIFY; - event.sequence = 0; // does this matter? - event.event = m_screen->root(); - event.window = m_window; - event.from_configure = false; - Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(), - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); - xcb_flush(xcb_connection()); + // update WM_NORMAL_HINTS + propagateSizeHints(); + + // update WM_TRANSIENT_FOR + if (window()->transientParent() && isTransient(window())) { + QXcbWindow *transientXcbParent = static_cast<QXcbWindow *>(window()->transientParent()->handle()); + if (transientXcbParent) { + // ICCCM 4.1.2.6 + xcb_window_t parentWindow = transientXcbParent->xcb_window(); + + // todo: set transient for group (wm_client_leader) if no parent, a la qwidget_x11.cpp + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, + 1, &parentWindow)); + } + } + + // update _MOTIF_WM_HINTS + updateMotifWmHintsBeforeMap(); + + // update _NET_WM_STATE + updateNetWmStateBeforeMap(); } + + Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); + xcb_flush(xcb_connection()); + + connection()->sync(); +} + +void QXcbWindow::hide() +{ + Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window)); + + // send synthetic UnmapNotify event according to icccm 4.1.4 + xcb_unmap_notify_event_t event; + event.response_type = XCB_UNMAP_NOTIFY; + event.event = m_screen->root(); + event.window = m_window; + event.from_configure = false; + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(), + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); + + xcb_flush(xcb_connection()); + + m_mapped = false; } -struct QtMWMHints { +struct QtMotifWmHints { quint32 flags, functions, decorations; qint32 input_mode; quint32 status; @@ -317,33 +528,142 @@ enum { MWM_INPUT_FULL_APPLICATION_MODAL = 3L }; +static QtMotifWmHints getMotifWmHints(QXcbConnection *c, xcb_window_t window) +{ + QtMotifWmHints hints; + + xcb_get_property_cookie_t get_cookie = + xcb_get_property(c->xcb_connection(), 0, window, c->atom(QXcbAtom::_MOTIF_WM_HINTS), + c->atom(QXcbAtom::_MOTIF_WM_HINTS), 0, 20); + + xcb_generic_error_t *error; + + xcb_get_property_reply_t *reply = + xcb_get_property_reply(c->xcb_connection(), get_cookie, &error); + + if (reply && reply->format == 32 && reply->type == c->atom(QXcbAtom::_MOTIF_WM_HINTS)) { + hints = *((QtMotifWmHints *)xcb_get_property_value(reply)); + } else if (error) { + c->handleXcbError(error); + free(error); + + hints.flags = 0L; + hints.functions = MWM_FUNC_ALL; + hints.decorations = MWM_DECOR_ALL; + hints.input_mode = 0L; + hints.status = 0L; + } + + free(reply); + + return hints; +} + +static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMotifWmHints &hints) +{ + if (hints.flags != 0l) { + Q_XCB_CALL2(xcb_change_property(c->xcb_connection(), + XCB_PROP_MODE_REPLACE, + window, + c->atom(QXcbAtom::_MOTIF_WM_HINTS), + c->atom(QXcbAtom::_MOTIF_WM_HINTS), + 32, + 5, + &hints), c); + } else { + Q_XCB_CALL2(xcb_delete_property(c->xcb_connection(), window, c->atom(QXcbAtom::_MOTIF_WM_HINTS)), c); + } +} + +void QXcbWindow::printNetWmState(const QVector<xcb_atom_t> &state) +{ + printf("_NET_WM_STATE (%d): ", state.size()); + for (int i = 0; i < state.size(); ++i) { +#define CHECK_WM_STATE(state_atom) \ + if (state.at(i) == atom(QXcbAtom::state_atom))\ + printf(#state_atom " "); + CHECK_WM_STATE(_NET_WM_STATE_ABOVE) + CHECK_WM_STATE(_NET_WM_STATE_BELOW) + CHECK_WM_STATE(_NET_WM_STATE_FULLSCREEN) + CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_HORZ) + CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_VERT) + CHECK_WM_STATE(_NET_WM_STATE_MODAL) + CHECK_WM_STATE(_NET_WM_STATE_STAYS_ON_TOP) + CHECK_WM_STATE(_NET_WM_STATE_DEMANDS_ATTENTION) +#undef CHECK_WM_STATE + } + printf("\n"); +} + +QVector<xcb_atom_t> QXcbWindow::getNetWmState() +{ + QVector<xcb_atom_t> result; + + xcb_get_property_cookie_t get_cookie = + xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE), + XCB_ATOM_ATOM, 0, 1024); + + xcb_generic_error_t *error; + + xcb_get_property_reply_t *reply = + xcb_get_property_reply(xcb_connection(), get_cookie, &error); + + if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) { + result.resize(reply->length); + + memcpy(result.data(), xcb_get_property_value(reply), reply->length * sizeof(xcb_atom_t)); + +#ifdef NET_WM_STATE_DEBUG + printf("getting net wm state (%x)\n", m_window); + printNetWmState(result); +#endif + + free(reply); + } else if (error) { + connection()->handleXcbError(error); + free(error); + } else { +#ifdef NET_WM_STATE_DEBUG + printf("getting net wm state (%x), empty\n", m_window); +#endif + } + + return result; +} + +void QXcbWindow::setNetWmState(const QVector<xcb_atom_t> &atoms) +{ + if (atoms.isEmpty()) { + Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE))); + } else { + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::_NET_WM_STATE), XCB_ATOM_ATOM, 32, + atoms.count(), atoms.constData())); + } + xcb_flush(xcb_connection()); +} + + Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); - setNetWmWindowTypes(flags); - 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); + setNetWmWindowFlags(flags); + setMotifWindowFlags(flags); - Q_UNUSED(topLevel); - Q_UNUSED(dialog); - Q_UNUSED(desktop); - Q_UNUSED(tool); + return flags; +} - bool tooltip = (type == Qt::ToolTip); +void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags) +{ + Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); - QtMWMHints mwmhints; + QtMotifWmHints mwmhints; mwmhints.flags = 0L; mwmhints.functions = 0L; mwmhints.decorations = 0; @@ -403,30 +723,90 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) mwmhints.decorations = 0; } - if (mwmhints.flags != 0l) { - Q_XCB_CALL(xcb_change_property(xcb_connection(), - XCB_PROP_MODE_REPLACE, - m_window, - atom(QXcbAtom::_MOTIF_WM_HINTS), - atom(QXcbAtom::_MOTIF_WM_HINTS), - 32, - 5, - &mwmhints)); - } else { - Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS))); - } + setMotifWmHints(connection(), m_window, mwmhints); +} + +void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) +{ + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.window = m_window; + event.type = atom(QXcbAtom::_NET_WM_STATE); + event.data.data32[0] = set ? 1 : 0; + event.data.data32[1] = one; + event.data.data32[2] = two; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + + Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); +} - if (popup || tooltip) { - const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER; - const quint32 values[] = { true, true }; +Qt::WindowState QXcbWindow::setWindowState(Qt::WindowState state) +{ + if (state == m_windowState) + return state; + + m_dirtyFrameMargins = true; + + // unset old state + switch (m_windowState) { + case Qt::WindowMinimized: + Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); + break; + case Qt::WindowMaximized: + changeNetWmState(false, + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + break; + case Qt::WindowFullScreen: + changeNetWmState(false, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + break; + default: + break; + } - Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values)); + // set new state + switch (state) { + case Qt::WindowMinimized: + { + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.window = m_window; + event.type = atom(QXcbAtom::WM_CHANGE_STATE); + event.data.data32[0] = XCB_WM_STATE_ICONIC; + event.data.data32[1] = 0; + event.data.data32[2] = 0; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + + Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); + } + break; + case Qt::WindowMaximized: + changeNetWmState(true, + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + break; + case Qt::WindowFullScreen: + changeNetWmState(true, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + break; + case Qt::WindowNoState: + break; + default: + break; } - return QPlatformWindow::setWindowFlags(flags); + connection()->sync(); + + m_windowState = state; + return m_windowState; } -void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags) +void QXcbWindow::setNetWmWindowFlags(Qt::WindowFlags flags) { // in order of decreasing priority QVector<uint> windowTypes; @@ -462,6 +842,127 @@ void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags) windowTypes.count(), windowTypes.constData())); } +void QXcbWindow::updateMotifWmHintsBeforeMap() +{ + QtMotifWmHints mwmhints = getMotifWmHints(connection(), m_window); + + if (window()->windowModality() != Qt::NonModal) { + switch (window()->windowModality()) { + case Qt::WindowModal: + mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL; + break; + case Qt::ApplicationModal: + default: + mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL; + break; + } + mwmhints.flags |= MWM_HINTS_INPUT_MODE; + } else { + mwmhints.input_mode = MWM_INPUT_MODELESS; + mwmhints.flags &= ~MWM_HINTS_INPUT_MODE; + } + + if (window()->minimumSize() == window()->maximumSize()) { + // fixed size, remove the resize handle (since mwm/dtwm + // isn't smart enough to do it itself) + mwmhints.flags |= MWM_HINTS_FUNCTIONS; + if (mwmhints.functions == MWM_FUNC_ALL) { + mwmhints.functions = MWM_FUNC_MOVE; + } else { + mwmhints.functions &= ~MWM_FUNC_RESIZE; + } + + if (mwmhints.decorations == MWM_DECOR_ALL) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + mwmhints.decorations = (MWM_DECOR_BORDER + | MWM_DECOR_TITLE + | MWM_DECOR_MENU); + } else { + mwmhints.decorations &= ~MWM_DECOR_RESIZEH; + } + } + + if (window()->windowFlags() & Qt::WindowMinimizeButtonHint) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + mwmhints.decorations |= MWM_DECOR_MINIMIZE; + mwmhints.functions |= MWM_FUNC_MINIMIZE; + } + if (window()->windowFlags() & Qt::WindowMaximizeButtonHint) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + mwmhints.decorations |= MWM_DECOR_MAXIMIZE; + mwmhints.functions |= MWM_FUNC_MAXIMIZE; + } + if (window()->windowFlags() & Qt::WindowCloseButtonHint) + mwmhints.functions |= MWM_FUNC_CLOSE; + + setMotifWmHints(connection(), m_window, mwmhints); +} + +void QXcbWindow::updateNetWmStateBeforeMap() +{ + QVector<xcb_atom_t> netWmState; + + Qt::WindowFlags flags = window()->windowFlags(); + if (flags & Qt::WindowStaysOnTopHint) { + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); + } else if (flags & Qt::WindowStaysOnBottomHint) { + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_BELOW)); + } + + if (window()->windowState() & Qt::WindowFullScreen) { + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + } + + if (window()->windowState() & Qt::WindowMaximized) { + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)); + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + } + + if (window()->windowModality() != Qt::NonModal) { + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MODAL)); + } + + setNetWmState(netWmState); +} + +void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp) +{ + xcb_window_t wid = m_window; + + const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW)); + if (m_netWmUserTimeWindow || isSupportedByWM) { + if (!m_netWmUserTimeWindow) { + m_netWmUserTimeWindow = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, // depth -- same as root + m_netWmUserTimeWindow, // window id + m_window, // parent window id + -1, -1, 1, 1, + 0, // border width + XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class + m_screen->screen()->root_visual, // visual + 0, // value mask + 0)); // value list + wid = m_netWmUserTimeWindow; + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW), + XCB_ATOM_WINDOW, 32, 1, &m_netWmUserTimeWindow); + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME)); + } else if (!isSupportedByWM) { + // WM no longer supports it, then we should remove the + // _NET_WM_USER_TIME_WINDOW atom. + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW)); + xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow); + m_netWmUserTimeWindow = XCB_NONE; + } else { + wid = m_netWmUserTimeWindow; + } + } + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::_NET_WM_USER_TIME), + XCB_ATOM_CARDINAL, 32, 1, ×tamp); +} + + WId QXcbWindow::winId() const { return m_window; @@ -469,8 +970,13 @@ WId QXcbWindow::winId() const void QXcbWindow::setParent(const QPlatformWindow *parent) { + // re-create for compatibility + create(); + QPoint topLeft = geometry().topLeft(); - Q_XCB_CALL(xcb_reparent_window(xcb_connection(), window(), static_cast<const QXcbWindow *>(parent)->window(), topLeft.x(), topLeft.y())); + + xcb_window_t xcb_parent_id = parent ? static_cast<const QXcbWindow *>(parent)->xcb_window() : m_screen->root(); + Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y())); } void QXcbWindow::setWindowTitle(const QString &title) @@ -500,56 +1006,87 @@ void QXcbWindow::lower() Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values)); } +void QXcbWindow::propagateSizeHints() +{ + // update WM_NORMAL_HINTS + xcb_size_hints_t hints; + memset(&hints, 0, sizeof(hints)); + + QRect rect = geometry(); + + xcb_size_hints_set_position(&hints, true, rect.x(), rect.y()); + xcb_size_hints_set_size(&hints, true, rect.width(), rect.height()); + xcb_size_hints_set_win_gravity(&hints, XCB_GRAVITY_STATIC); + + QWindow *win = window(); + + QSize minimumSize = win->minimumSize(); + QSize maximumSize = win->maximumSize(); + QSize baseSize = win->baseSize(); + QSize sizeIncrement = win->sizeIncrement(); + + if (minimumSize.width() > 0 || minimumSize.height() > 0) + xcb_size_hints_set_min_size(&hints, minimumSize.width(), minimumSize.height()); + + if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX) + xcb_size_hints_set_max_size(&hints, + qMin(XCOORD_MAX, maximumSize.width()), + qMin(XCOORD_MAX, maximumSize.height())); + + if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) { + xcb_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height()); + xcb_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height()); + } + + xcb_set_wm_normal_hints(xcb_connection(), m_window, &hints); +} + void QXcbWindow::requestActivateWindow() { - Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, XCB_TIME_CURRENT_TIME)); + if (m_mapped){ + updateNetWmUserTime(connection()->time()); + Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time())); + } connection()->sync(); } -QPlatformGLContext *QXcbWindow::glContext() const +QSurfaceFormat QXcbWindow::format() const { - if (!QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { - printf("no opengl\n"); - return 0; - } - if (!m_context) { -#if defined(XCB_USE_GLX) - QXcbWindow *that = const_cast<QXcbWindow *>(this); - that->m_context = new QGLXContext(m_window, m_screen, widget()->platformWindowFormat()); -#elif defined(XCB_USE_EGL) + // ### return actual format + return m_requestedFormat; +} + +#if defined(XCB_USE_EGL) +QXcbEGLSurface *QXcbWindow::eglSurface() const +{ + if (!m_eglSurface) { EGLDisplay display = connection()->egl_display(); - EGLConfig config = q_configFromQPlatformWindowFormat(display,widget()->platformWindowFormat(),true); - QVector<EGLint> eglContextAttrs; - eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); - eglContextAttrs.append(2); - eglContextAttrs.append(EGL_NONE); - - EGLSurface eglSurface = eglCreateWindowSurface(display,config,(EGLNativeWindowType)m_window,0); - QXcbWindow *that = const_cast<QXcbWindow *>(this); - that->m_context = new QEGLPlatformContext(display, config, eglContextAttrs.data(), eglSurface, EGL_OPENGL_ES_API); -#elif defined(XCB_USE_DRI2) - QXcbWindow *that = const_cast<QXcbWindow *>(this); - that->m_context = new QDri2Context(that); -#endif + EGLConfig config = q_configFromGLFormat(display, window()->format(), true); + EGLSurface surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)m_window, 0); + + m_eglSurface = new QXcbEGLSurface(display, surface); } - return m_context; + + return m_eglSurface; } +#endif void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) { - QWindowSurface *surface = widget()->windowSurface(); - if (surface) { - QRect rect(event->x, event->y, event->width, event->height); - - surface->flush(widget(), rect, QPoint()); - } + QRect rect(event->x, event->y, event->width, event->height); + QWindowSystemInterface::handleSynchronousExposeEvent(window(), rect); } void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *event) { - if (event->format == 32 && event->type == atom(QXcbAtom::WM_PROTOCOLS)) { + if (event->format != 32) + return; + + if (event->type == atom(QXcbAtom::WM_PROTOCOLS)) { if (event->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW)) { - QWindowSystemInterface::handleCloseEvent(widget()); + QWindowSystemInterface::handleCloseEvent(window()); + } else if (event->data.data32[0] == atom(QXcbAtom::WM_TAKE_FOCUS)) { + connection()->setTime(event->data.data32[1]); } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) { xcb_client_message_event_t reply = *event; @@ -559,13 +1096,22 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply); xcb_flush(xcb_connection()); } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) { - if (!m_hasReceivedSyncRequest) { - m_hasReceivedSyncRequest = true; - printf("Window manager supports _NET_WM_SYNC_REQUEST, syncing resizes\n"); - } + connection()->setTime(event->data.data32[1]); m_syncValue.lo = event->data.data32[2]; m_syncValue.hi = event->data.data32[3]; + } else { + qWarning() << "unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]); } + } else if (event->type == atom(QXcbAtom::XdndEnter)) { + connection()->drag()->handleEnter(window(), event); + } else if (event->type == atom(QXcbAtom::XdndPosition)) { + connection()->drag()->handlePosition(window(), event, false); + } else if (event->type == atom(QXcbAtom::XdndLeave)) { + connection()->drag()->handleLeave(window(), event, false); + } else if (event->type == atom(QXcbAtom::XdndDrop)) { + connection()->drag()->handleDrop(window(), event, false); + } else { + qWarning() << "unhandled client message:" << connection()->atomName(event->type); } } @@ -581,11 +1127,8 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * QRect rect(xpos, ypos, event->width, event->height); - if (rect == geometry()) - return; - QPlatformWindow::setGeometry(rect); - QWindowSystemInterface::handleGeometryChange(widget(), rect); + QWindowSystemInterface::handleGeometryChange(window(), rect); #if XCB_USE_DRI2 if (m_context) @@ -593,6 +1136,22 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * #endif } +void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) +{ + if (event->window == m_window) { + m_mapped = true; + QWindowSystemInterface::handleMapEvent(window()); + } +} + +void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) +{ + if (event->window == m_window) { + m_mapped = false; + QWindowSystemInterface::handleUnmapEvent(window()); + } +} + static Qt::MouseButtons translateMouseButtons(int s) { Qt::MouseButtons ret = 0; @@ -621,6 +1180,8 @@ static Qt::MouseButton translateMouseButton(xcb_button_t s) void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) { + updateNetWmUserTime(event->time); + QPoint local(event->event_x, event->event_y); QPoint global(event->root_x, event->root_y); @@ -633,7 +1194,7 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) && (modifiers & Qt::AltModifier)) || (event->detail == 6 || event->detail == 7)); - QWindowSystemInterface::handleWheelEvent(widget(), event->time, + QWindowSystemInterface::handleWheelEvent(window(), event->time, local, global, delta, hor ? Qt::Horizontal : Qt::Vertical); return; } @@ -659,32 +1220,65 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event) void QXcbWindow::handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global) { + connection()->setTime(time); + Qt::MouseButtons buttons = translateMouseButtons(state); Qt::MouseButton button = translateMouseButton(detail); buttons ^= button; // X event uses state *before*, Qt uses state *after* - QWindowSystemInterface::handleMouseEvent(widget(), time, local, global, buttons); + QWindowSystemInterface::handleMouseEvent(window(), time, local, global, buttons); } -void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *) +void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) { - QWindowSystemInterface::handleEnterEvent(widget()); + connection()->setTime(event->time); + + if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB) + || event->detail == XCB_NOTIFY_DETAIL_VIRTUAL + || event->detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL) + { + return; + } + + QWindowSystemInterface::handleEnterEvent(window()); } -void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *) +void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) { - QWindowSystemInterface::handleLeaveEvent(widget()); + connection()->setTime(event->time); + + if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB) + || event->detail == XCB_NOTIFY_DETAIL_INFERIOR) + { + return; + } + + QWindowSystemInterface::handleLeaveEvent(window()); } void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *) { - QWindowSystemInterface::handleWindowActivated(widget()); + QWindowSystemInterface::handleWindowActivated(window()); +} + +static bool focusInPeeker(xcb_generic_event_t *event) +{ + if (!event) { + // FocusIn event is not in the queue, proceed with FocusOut normally. + QWindowSystemInterface::handleWindowActivated(0); + return true; + } + uint response_type = event->response_type & ~0x80; + return response_type == XCB_FOCUS_IN; } void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *) { - QWindowSystemInterface::handleWindowActivated(0); + // Do not set the active window to 0 if there is a FocusIn coming. + // There is however no equivalent for XPutBackEvent so register a + // callback for QXcbConnection instead. + connection()->addPeekFunc(focusInPeeker); } void QXcbWindow::updateSyncRequestCounter() @@ -698,3 +1292,47 @@ void QXcbWindow::updateSyncRequestCounter() m_syncValue.hi = 0; } } + +bool QXcbWindow::setKeyboardGrabEnabled(bool grab) +{ + if (!grab) { + xcb_ungrab_keyboard(xcb_connection(), XCB_TIME_CURRENT_TIME); + return true; + } + xcb_grab_keyboard_cookie_t cookie = xcb_grab_keyboard(xcb_connection(), false, + m_window, XCB_TIME_CURRENT_TIME, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + xcb_generic_error_t *err; + xcb_grab_keyboard_reply_t *reply = xcb_grab_keyboard_reply(xcb_connection(), cookie, &err); + bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS); + free(reply); + free(err); + return result; +} + +bool QXcbWindow::setMouseGrabEnabled(bool grab) +{ + if (!grab) { + xcb_ungrab_pointer(xcb_connection(), XCB_TIME_CURRENT_TIME); + return true; + } + xcb_grab_pointer_cookie_t cookie = xcb_grab_pointer(xcb_connection(), false, m_window, + (XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE + | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_ENTER_WINDOW + | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_POINTER_MOTION), + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, + XCB_WINDOW_NONE, XCB_CURSOR_NONE, + XCB_TIME_CURRENT_TIME); + xcb_generic_error_t *err; + xcb_grab_pointer_reply_t *reply = xcb_grab_pointer_reply(xcb_connection(), cookie, &err); + bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS); + free(reply); + free(err); + return result; +} + +void QXcbWindow::setCursor(xcb_cursor_t cursor) +{ + xcb_change_window_attributes(xcb_connection(), m_window, XCB_CW_CURSOR, &cursor); + xcb_flush(xcb_connection()); +} diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 69d0bc2f1d..a85760ea8d 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -43,7 +43,7 @@ #define QXCBWINDOW_H #include <QtGui/QPlatformWindow> -#include <QtGui/QPlatformWindowFormat> +#include <QtGui/QSurfaceFormat> #include <QtGui/QImage> #include <xcb/xcb.h> @@ -52,35 +52,47 @@ #include "qxcbobject.h" class QXcbScreen; +class QXcbEGLSurface; class QXcbWindow : public QXcbObject, public QPlatformWindow { public: - QXcbWindow(QWidget *tlw); + QXcbWindow(QWindow *window); ~QXcbWindow(); void setGeometry(const QRect &rect); + QMargins frameMargins() const; + void setVisible(bool visible); Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags); + Qt::WindowState setWindowState(Qt::WindowState state); WId winId() const; void setParent(const QPlatformWindow *window); void setWindowTitle(const QString &title); void raise(); void lower(); + void propagateSizeHints(); void requestActivateWindow(); - QPlatformGLContext *glContext() const; + bool setKeyboardGrabEnabled(bool grab); + bool setMouseGrabEnabled(bool grab); + + void setCursor(xcb_cursor_t cursor); - xcb_window_t window() const { return m_window; } + QSurfaceFormat format() const; + + xcb_window_t xcb_window() const { return m_window; } uint depth() const { return m_depth; } - QImage::Format format() const { return m_format; } + QImage::Format imageFormat() const { return m_imageFormat; } void handleExposeEvent(const xcb_expose_event_t *event); void handleClientMessageEvent(const xcb_client_message_event_t *event); void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event); + void handleMapNotifyEvent(const xcb_map_notify_event_t *event); + void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event); void handleButtonPressEvent(const xcb_button_press_event_t *event); void handleButtonReleaseEvent(const xcb_button_release_event_t *event); void handleMotionNotifyEvent(const xcb_motion_notify_event_t *event); @@ -93,22 +105,54 @@ public: void handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global); void updateSyncRequestCounter(); + void updateNetWmUserTime(xcb_timestamp_t timestamp); + void netWmUserTime() const; + +#if defined(XCB_USE_EGL) + QXcbEGLSurface *eglSurface() const; +#endif private: - void setNetWmWindowTypes(Qt::WindowFlags flags); + void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); + QVector<xcb_atom_t> getNetWmState(); + void setNetWmState(const QVector<xcb_atom_t> &atoms); + void printNetWmState(const QVector<xcb_atom_t> &state); + + void setNetWmWindowFlags(Qt::WindowFlags flags); + void setMotifWindowFlags(Qt::WindowFlags flags); + + void updateMotifWmHintsBeforeMap(); + void updateNetWmStateBeforeMap(); + + void create(); + void destroy(); + + void show(); + void hide(); QXcbScreen *m_screen; xcb_window_t m_window; - QPlatformGLContext *m_context; uint m_depth; - QImage::Format m_format; + QImage::Format m_imageFormat; xcb_sync_int64_t m_syncValue; xcb_sync_counter_t m_syncCounter; - bool m_hasReceivedSyncRequest; + Qt::WindowState m_windowState; + + bool m_mapped; + xcb_window_t m_netWmUserTimeWindow; + + QSurfaceFormat m_requestedFormat; + + mutable bool m_dirtyFrameMargins; + mutable QMargins m_frameMargins; + +#if defined(XCB_USE_EGL) + mutable QXcbEGLSurface *m_eglSurface; +#endif }; #endif diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.cpp b/src/plugins/platforms/xcb/qxcbwmsupport.cpp new file mode 100644 index 0000000000..5fb67b6377 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbwmsupport.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** 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 plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbwmsupport.h" +#include "qxcbscreen.h" + +#include <qdebug.h> + +QXcbWMSupport::QXcbWMSupport(QXcbConnection *c) + : QXcbObject(c) +{ + updateNetWMAtoms(); + updateVirtualRoots(); +} + +bool QXcbWMSupport::isSupportedByWM(xcb_atom_t atom) const +{ + return net_wm_atoms.contains(atom); +} + + + +void QXcbWMSupport::updateNetWMAtoms() +{ + net_wm_atoms.clear(); + + xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root(); + int offset = 0; + int remaining = 0; + do { + xcb_generic_error_t *error = 0; + xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, root, atom(QXcbAtom::_NET_SUPPORTED), XCB_ATOM_ATOM, offset, 1024); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, &error); + if (!reply || error) + break; + + remaining = 0; + + if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { + int len = xcb_get_property_value_length(reply)/4; + xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); + int s = net_wm_atoms.size(); + net_wm_atoms.resize(s + len); + memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t)); + + remaining = reply->bytes_after; + offset += len; + } + + free(reply); + } while (remaining > 0); + +// qDebug() << "======== updateNetWMAtoms"; +// for (int i = 0; i < net_wm_atoms.size(); ++i) +// qDebug() << atomName(net_wm_atoms.at(i)); +// qDebug() << "======== updateNetWMAtoms"; +} + +// update the virtual roots array +void QXcbWMSupport::updateVirtualRoots() +{ + net_virtual_roots.clear(); + + if (!isSupportedByWM(atom(QXcbAtom::_NET_VIRTUAL_ROOTS))) + return; + + xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root(); + int offset = 0; + int remaining = 0; + do { + xcb_generic_error_t *error = 0; + xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, root, atom(QXcbAtom::_NET_VIRTUAL_ROOTS), XCB_ATOM_ATOM, offset, 1024); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, &error); + if (!reply || error) + break; + + remaining = 0; + + if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { + int len = xcb_get_property_value_length(reply)/4; + xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); + int s = net_wm_atoms.size(); + net_wm_atoms.resize(s + len); + memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t)); + + remaining = reply->bytes_after; + offset += len; + } + + free(reply); + } while (remaining > 0); + + qDebug() << "======== updateVirtualRoots"; + for (int i = 0; i < net_virtual_roots.size(); ++i) + qDebug() << connection()->atomName(net_virtual_roots.at(i)); + qDebug() << "======== updateVirtualRoots"; +} + diff --git a/src/plugins/platforms/cocoa/qcocoaeventloopintegration.h b/src/plugins/platforms/xcb/qxcbwmsupport.h index 5765483fc7..3b02ef3e7e 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventloopintegration.h +++ b/src/plugins/platforms/xcb/qxcbwmsupport.h @@ -38,28 +38,30 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#ifndef QXCBWMSUPPORT_H +#define QXCBWMSUPPORT_H -#ifndef QCOCAEVENTLOOPINTEGRATION_H -#define QCOCAEVENTLOOPINTEGRATION_H +#include "qxcbobject.h" +#include "qxcbconnection.h" +#include <qvector.h> -#include <Cocoa/Cocoa.h> - -#include <QPlatformEventLoopIntegration> - - -class QCocoaEventLoopIntegration : public QPlatformEventLoopIntegration +class QXcbWMSupport : public QXcbObject { public: - QCocoaEventLoopIntegration(); - void startEventLoop(); - void quitEventLoop(); - void qtNeedsToProcessEvents(); + QXcbWMSupport(QXcbConnection *c); + + + bool isSupportedByWM(xcb_atom_t atom) const; + const QVector<xcb_window_t> &virtualRoots() const { return net_virtual_roots; } private: - CFRunLoopSourceContext m_sourceContext; - CFRunLoopTimerContext m_timerContext; - CFRunLoopSourceRef m_source; + friend class QXcbConnection; + void updateNetWMAtoms(); + void updateVirtualRoots(); + + QVector<xcb_atom_t> net_wm_atoms; + QVector<xcb_window_t> net_virtual_roots; }; -#endif // QCOCAEVENTLOOPINTEGRATION_H +#endif diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index 27d10b6756..143a671047 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -3,70 +3,91 @@ TARGET = xcb load(qt_plugin) QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms -QT += core-private gui-private +QT += core-private gui-private platformsupport-private SOURCES = \ + qxcbclipboard.cpp \ qxcbconnection.cpp \ qxcbintegration.cpp \ qxcbkeyboard.cpp \ + qxcbmime.cpp \ + qxcbdrag.cpp \ qxcbscreen.cpp \ qxcbwindow.cpp \ - qxcbwindowsurface.cpp \ + qxcbbackingstore.cpp \ + qxcbwmsupport.cpp \ main.cpp \ - qxcbnativeinterface.cpp + qxcbnativeinterface.cpp \ + qxcbcursor.cpp \ + qxcbimage.cpp HEADERS = \ + qxcbclipboard.h \ qxcbconnection.h \ qxcbintegration.h \ qxcbkeyboard.h \ + qxcbdrag.h \ + qxcbmime.h \ qxcbobject.h \ qxcbscreen.h \ qxcbwindow.h \ - qxcbwindowsurface.h \ - qxcbnativeinterface.h + qxcbbackingstore.h \ + qxcbwmsupport.h \ + qxcbnativeinterface.h \ + qxcbcursor.h \ + qxcbimage.h -contains(QT_CONFIG, opengl) { - QT += opengl +contains(QT_CONFIG, xcb-poll-for-queued-event) { + DEFINES += XCB_POLL_FOR_QUEUED_EVENT +} + +# needed by GLX, Xcursor, XLookupString, ... +contains(QT_CONFIG, xcb-xlib) { + DEFINES += XCB_USE_XLIB + LIBS += -lX11 -lX11-xcb +} + +# to support custom cursors with depth > 1 +contains(QT_CONFIG, xcb-render) { + DEFINES += XCB_USE_RENDER + LIBS += -lxcb-render -lxcb-render-util -lXrender +} # DEFINES += XCB_USE_DRI2 - contains(DEFINES, XCB_USE_DRI2) { - LIBS += -lxcb-dri2 -lxcb-xfixes -lEGL - - CONFIG += link_pkgconfig - PKGCONFIG += libdrm - - HEADERS += qdri2context.h - SOURCES += qdri2context.cpp - - } else { - DEFINES += XCB_USE_XLIB - LIBS += -lX11 -lX11-xcb - - contains(QT_CONFIG, opengles2) { - DEFINES += XCB_USE_EGL - HEADERS += \ - ../eglconvenience/qeglplatformcontext.h \ - ../eglconvenience/qeglconvenience.h \ - ../eglconvenience/qxlibeglintegration.h - - SOURCES += \ - ../eglconvenience/qeglplatformcontext.cpp \ - ../eglconvenience/qeglconvenience.cpp \ - ../eglconvenience/qxlibeglintegration.cpp - - LIBS += -lEGL - } else { - DEFINES += XCB_USE_GLX - include (../glxconvenience/glxconvenience.pri) - HEADERS += qglxintegration.h - SOURCES += qglxintegration.cpp - } +contains(DEFINES, XCB_USE_DRI2) { + LIBS += -lxcb-dri2 -lEGL + + CONFIG += link_pkgconfig + PKGCONFIG += libdrm + + HEADERS += qdri2context.h + SOURCES += qdri2context.cpp + +} else { + contains(QT_CONFIG, opengles2) { + DEFINES += XCB_USE_EGL + LIBS += -lEGL + HEADERS += qxcbeglsurface.h + } else:contains(QT_CONFIG, xcb-xlib) { + DEFINES += XCB_USE_GLX + HEADERS += qglxintegration.h + SOURCES += qglxintegration.cpp } } -LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync +LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes + +DEFINES += $$QMAKE_DEFINES_XCB +LIBS += $$QMAKE_LIBS_XCB +QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB -include (../fontdatabases/genericunix/genericunix.pri) +CONFIG += qpa/genericunixfontdatabase + +contains(QT_CONFIG, dbus) { +DEFINES += XCB_USE_IBUS +QT += dbus +LIBS += -ldbus-1 +} target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/xlib/main.cpp b/src/plugins/platforms/xlib/main.cpp index 63eba3288b..b4241fa228 100644 --- a/src/plugins/platforms/xlib/main.cpp +++ b/src/plugins/platforms/xlib/main.cpp @@ -54,10 +54,7 @@ public: QStringList QXlibIntegrationPlugin::keys() const { QStringList list; - list << "Xlib"; -#ifndef QT_NO_OPENGL - list << "XlibGL"; -#endif + list << "xlib"; return list; } @@ -66,10 +63,6 @@ QPlatformIntegration* QXlibIntegrationPlugin::create(const QString& system, cons 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; } diff --git a/src/plugins/platforms/xlib/qglxintegration.cpp b/src/plugins/platforms/xlib/qglxintegration.cpp index d827d606bb..6733f22093 100644 --- a/src/plugins/platforms/xlib/qglxintegration.cpp +++ b/src/plugins/platforms/xlib/qglxintegration.cpp @@ -51,7 +51,7 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> #include <GL/glx.h> -#include "qglxconvenience.h" +#include "private/qglxconvenience_p.h" #include "qglxintegration.h" @@ -61,34 +61,24 @@ QT_BEGIN_NAMESPACE -QGLXContext::QGLXContext(Window window, QXlibScreen *screen, const QPlatformWindowFormat &format) - : QPlatformGLContext() +QGLXContext::QGLXContext(QXlibScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share) + : QPlatformOpenGLContext() , m_screen(screen) - , m_drawable((Drawable)window) , m_context(0) { - - const QPlatformGLContext *sharePlatformContext; - sharePlatformContext = format.sharedGLContext(); GLXContext shareGlxContext = 0; - if (sharePlatformContext) - shareGlxContext = static_cast<const QGLXContext*>(sharePlatformContext)->glxContext(); + if (share) + shareGlxContext = static_cast<const QGLXContext*>(share)->glxContext(); GLXFBConfig config = qglx_findConfig(screen->display()->nativeDisplay(),screen->xScreenNumber(),format); m_context = glXCreateNewContext(screen->display()->nativeDisplay(),config,GLX_RGBA_TYPE,shareGlxContext,TRUE); - m_windowFormat = qglx_platformWindowFromGLXFBConfig(screen->display()->nativeDisplay(),config,m_context); + m_windowFormat = qglx_surfaceFormatFromGLXFBConfig(screen->display()->nativeDisplay(),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) { @@ -97,27 +87,36 @@ QGLXContext::~QGLXContext() } } -void QGLXContext::makeCurrent() +QSurfaceFormat QGLXContext::format() const { - QPlatformGLContext::makeCurrent(); + return m_windowFormat; +} + +bool QGLXContext::makeCurrent(QPlatformSurface *surface) +{ + Q_UNUSED(surface); + + GLXDrawable glxDrawable = static_cast<QXlibWindow *>(surface)->winId(); #ifdef MYX11_DEBUG - qDebug("QGLXGLContext::makeCurrent(window=0x%x, ctx=0x%x)", m_drawable, m_context); + qDebug("QGLXGLContext::makeCurrent(window=0x%x, ctx=0x%x)", glxDrawable, m_context); #endif - glXMakeCurrent(m_screen->display()->nativeDisplay(), m_drawable, m_context); + return glXMakeCurrent(m_screen->display()->nativeDisplay(), glxDrawable, m_context); } void QGLXContext::doneCurrent() { - QPlatformGLContext::doneCurrent(); glXMakeCurrent(m_screen->display()->nativeDisplay(), 0, 0); } -void QGLXContext::swapBuffers() +void QGLXContext::swapBuffers(QPlatformSurface *surface) { - glXSwapBuffers(m_screen->display()->nativeDisplay(), m_drawable); + Q_UNUSED(surface); + + GLXDrawable glxDrawable = static_cast<QXlibWindow *>(surface)->winId(); + glXSwapBuffers(m_screen->display()->nativeDisplay(), glxDrawable); } -void* QGLXContext::getProcAddress(const QString& procName) +void (*QGLXContext::getProcAddress(const QByteArray& procName))() { typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *); static qt_glXGetProcAddressARB glXGetProcAddressARB = 0; @@ -147,10 +146,10 @@ void* QGLXContext::getProcAddress(const QString& procName) } if (!glXGetProcAddressARB) return 0; - return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.toLatin1().data())); + return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.constData())); } -QPlatformWindowFormat QGLXContext::platformWindowFormat() const +QSurfaceFormat QGLXContext::surfaceFormat() const { return m_windowFormat; } diff --git a/src/plugins/platforms/xlib/qglxintegration.h b/src/plugins/platforms/xlib/qglxintegration.h index 07c2a77f5d..e3172b718c 100644 --- a/src/plugins/platforms/xlib/qglxintegration.h +++ b/src/plugins/platforms/xlib/qglxintegration.h @@ -44,8 +44,8 @@ #include "qxlibwindow.h" -#include <QtGui/QPlatformGLContext> -#include <QtGui/QPlatformWindowFormat> +#include <QtGui/QPlatformOpenGLContext> +#include <QtGui/qsurfaceformat.h> #include <QtCore/QMutex> @@ -54,28 +54,26 @@ QT_BEGIN_NAMESPACE -class QGLXContext : public QPlatformGLContext +class QGLXContext : public QPlatformOpenGLContext { public: - QGLXContext(Window window, QXlibScreen *xd, const QPlatformWindowFormat &format); + QGLXContext(QXlibScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share); ~QGLXContext(); - virtual void makeCurrent(); - virtual void doneCurrent(); - virtual void swapBuffers(); - virtual void* getProcAddress(const QString& procName); + QSurfaceFormat format() const; + void swapBuffers(QPlatformSurface *surface); + bool makeCurrent(QPlatformSurface *surface); + void doneCurrent(); + virtual void (*getProcAddress(const QByteArray& procName))(); GLXContext glxContext() const {return m_context;} - QPlatformWindowFormat platformWindowFormat() const; + QSurfaceFormat surfaceFormat() const; private: QXlibScreen *m_screen; - Drawable m_drawable; GLXContext m_context; - QPlatformWindowFormat m_windowFormat; - - QGLXContext (QXlibScreen *screen, Drawable drawable, GLXContext context); + QSurfaceFormat m_windowFormat; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qxlibwindowsurface.cpp b/src/plugins/platforms/xlib/qxlibbackingstore.cpp index e0c272d110..24a346a29d 100644 --- a/src/plugins/platforms/xlib/qxlibwindowsurface.cpp +++ b/src/plugins/platforms/xlib/qxlibbackingstore.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qxlibwindowsurface.h" +#include "qxlibbackingstore.h" #include "qxlibintegration.h" #include <QtCore/qdebug.h> @@ -57,7 +57,6 @@ QT_BEGIN_NAMESPACE - struct QXlibShmImageInfo { QXlibShmImageInfo(Display *xdisplay) : image(0), display(xdisplay) {} ~QXlibShmImageInfo() { destroy(); } @@ -80,13 +79,15 @@ void QXlibShmImageInfo::destroy() } #endif -void QXlibWindowSurface::resizeShmImage(int width, int height) +void QXlibBackingStore::resizeShmImage(int width, int height) { QXlibScreen *screen = QXlibScreen::testLiteScreenForWidget(window()); - QXlibWindow *win = static_cast<QXlibWindow*>(window()->platformWindow()); + QXlibWindow *win = static_cast<QXlibWindow*>(window()->handle()); + + QImage::Format format = win->depth() == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; #ifdef DONT_USE_MIT_SHM - shm_img = QImage(width, height, win->format()); + shm_img = QImage(width, height, format); #else if (image_info) @@ -110,69 +111,68 @@ void QXlibWindowSurface::resizeShmImage(int width, int height) Q_ASSERT(shm_attach_status == True); - shm_img = QImage( (uchar*) image->data, image->width, image->height, image->bytes_per_line, win->format() ); + shm_img = QImage((uchar*) image->data, image->width, image->height, image->bytes_per_line, format); #endif painted = false; } -void QXlibWindowSurface::resizeBuffer(QSize s) +void QXlibBackingStore::resizeBuffer(QSize s) { if (shm_img.size() != s) resizeShmImage(s.width(), s.height()); } -QSize QXlibWindowSurface::bufferSize() const +QSize QXlibBackingStore::bufferSize() const { return shm_img.size(); } -QXlibWindowSurface::QXlibWindowSurface (QWidget *window) - : QWindowSurface(window), +QXlibBackingStore::QXlibBackingStore(QWindow *window) + : QPlatformBackingStore(window), painted(false), image_info(0) { - xw = static_cast<QXlibWindow*>(window->platformWindow()); + xw = static_cast<QXlibWindow*>(window->handle()); // qDebug() << "QTestLiteWindowSurface::QTestLiteWindowSurface:" << xw->window; } -QXlibWindowSurface::~QXlibWindowSurface() +QXlibBackingStore::~QXlibBackingStore() { delete image_info; } -QPaintDevice *QXlibWindowSurface::paintDevice() +QPaintDevice *QXlibBackingStore::paintDevice() { return &shm_img; } -void QXlibWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QXlibBackingStore::flush(QWindow *w, const QRegion ®ion, const QPoint &offset) { - Q_UNUSED(widget); Q_UNUSED(region); Q_UNUSED(offset); if (!painted) return; - QXlibScreen *screen = QXlibScreen::testLiteScreenForWidget(widget); + QXlibScreen *screen = QXlibScreen::testLiteScreenForWidget(w); GC gc = xw->graphicsContext(); Window window = xw->xWindow(); #ifdef DONT_USE_MIT_SHM // just convert the image every time... if (!shm_img.isNull()) { - QXlibWindow *win = static_cast<QXlibWindow*>(window()->platformWindow()); + QXlibWindow *win = static_cast<QXlibWindow*>(w->handle()); QImage image = shm_img; //img.convertToFormat( - XImage *xi = XCreateImage(screen->display(), win->visual(), win->depth(), ZPixmap, + XImage *xi = XCreateImage(screen->display()->nativeDisplay(), win->visual(), win->depth(), 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()); + /*int r =*/ XPutImage(screen->display()->nativeDisplay(), window, gc, xi, 0, 0, x, y, image.width(), image.height()); xi->data = 0; // QImage owns these bits XDestroyImage(xi); @@ -195,26 +195,15 @@ void QXlibWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPo #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) +void QXlibBackingStore::resize(const QSize &size, const QRegion &) { - 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; + resizeBuffer(size); } -void QXlibWindowSurface::beginPaint(const QRegion ®ion) +void QXlibBackingStore::beginPaint(const QRegion ®ion) { Q_UNUSED(region); - resizeBuffer(size()); if (shm_img.hasAlphaChannel()) { QPainter p(&shm_img); @@ -227,9 +216,8 @@ void QXlibWindowSurface::beginPaint(const QRegion ®ion) } } -void QXlibWindowSurface::endPaint(const QRegion ®ion) +void QXlibBackingStore::endPaint() { - Q_UNUSED(region); painted = true; //there is content in the buffer } QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qxlibwindowsurface.h b/src/plugins/platforms/xlib/qxlibbackingstore.h index aeec781fc9..35093f6784 100644 --- a/src/plugins/platforms/xlib/qxlibwindowsurface.h +++ b/src/plugins/platforms/xlib/qxlibbackingstore.h @@ -42,8 +42,8 @@ #ifndef QWINDOWSURFACE_TESTLITE_H #define QWINDOWSURFACE_TESTLITE_H -#include <QtGui/private/qwindowsurface_p.h> - +#include <QtGui/qplatformbackingstore_qpa.h> +#include <QtGui/QImage> QT_BEGIN_NAMESPACE @@ -52,18 +52,19 @@ class QXlibIntegration; class QXlibScreen; class QXlibShmImageInfo; -class QXlibWindowSurface : public QWindowSurface +class QXlibBackingStore : public QPlatformBackingStore { public: - QXlibWindowSurface (QWidget *window); - ~QXlibWindowSurface(); + QXlibBackingStore (QWindow *window); + ~QXlibBackingStore(); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - bool scroll(const QRegion &area, int dx, int dy); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + + void resize(const QSize &size, const QRegion &staticContents); void beginPaint(const QRegion ®ion); - void endPaint(const QRegion ®ion); + void endPaint(); private: bool painted; diff --git a/src/plugins/platforms/xlib/qxlibclipboard.cpp b/src/plugins/platforms/xlib/qxlibclipboard.cpp index 2c1d91bde8..3ee4d4269c 100644 --- a/src/plugins/platforms/xlib/qxlibclipboard.cpp +++ b/src/plugins/platforms/xlib/qxlibclipboard.cpp @@ -39,14 +39,14 @@ ** ****************************************************************************/ +#include <private/qguiapplication_p.h> + #include "qxlibclipboard.h" #include "qxlibscreen.h" #include "qxlibmime.h" #include "qxlibdisplay.h" -#include <private/qapplication_p.h> - #include <QtCore/QDebug> class QXlibClipboardMime : public QXlibMime diff --git a/src/plugins/platforms/xlib/qxlibcursor.cpp b/src/plugins/platforms/xlib/qxlibcursor.cpp index 0af4aefecd..7a074bc0e6 100644 --- a/src/plugins/platforms/xlib/qxlibcursor.cpp +++ b/src/plugins/platforms/xlib/qxlibcursor.cpp @@ -57,12 +57,11 @@ QXlibCursor::QXlibCursor(QXlibScreen *screen) { } -void QXlibCursor::changeCursor(QCursor *cursor, QWidget *widget) +void QXlibCursor::changeCursor(QCursor *cursor, QWindow *window) { QXlibWindow *w = 0; - if (widget) { - QWidget *window = widget->window(); - w = static_cast<QXlibWindow*>(window->platformWindow()); + if (window) { + w = static_cast<QXlibWindow*>(window->handle()); } else { // No X11 cursor control when there is no widget under the cursor return; diff --git a/src/plugins/platforms/xlib/qxlibcursor.h b/src/plugins/platforms/xlib/qxlibcursor.h index e2543d2e2a..fd574778d7 100644 --- a/src/plugins/platforms/xlib/qxlibcursor.h +++ b/src/plugins/platforms/xlib/qxlibcursor.h @@ -53,7 +53,7 @@ class QXlibCursor : QPlatformCursor public: QXlibCursor(QXlibScreen *screen); - void changeCursor(QCursor * cursor, QWidget * widget); + void changeCursor(QCursor * cursor, QWindow * widget); private: Cursor createCursorBitmap(QCursor * cursor); diff --git a/src/plugins/platforms/xlib/qxlibintegration.cpp b/src/plugins/platforms/xlib/qxlibintegration.cpp index 02104d9f74..c1f0941619 100644 --- a/src/plugins/platforms/xlib/qxlibintegration.cpp +++ b/src/plugins/platforms/xlib/qxlibintegration.cpp @@ -39,91 +39,66 @@ ** ****************************************************************************/ +#include <private/qguiapplication_p.h> #include "qxlibintegration.h" -#include "qxlibwindowsurface.h" +#include "qxlibbackingstore.h" #include <QtGui/private/qpixmap_raster_p.h> #include <QtCore/qdebug.h> +#include <QtGui/qopenglcontext.h> +#include <QtGui/qscreen.h> #include "qxlibwindow.h" -#include "qgenericunixfontdatabase.h" +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> #include "qxlibscreen.h" #include "qxlibclipboard.h" #include "qxlibdisplay.h" #include "qxlibnativeinterface.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 +#include "qglxintegration.h" QT_BEGIN_NAMESPACE -QXlibIntegration::QXlibIntegration(bool useOpenGL) - : mUseOpenGL(useOpenGL) - , mFontDb(new QGenericUnixFontDatabase()) +QXlibIntegration::QXlibIntegration() + : mFontDb(new QGenericUnixFontDatabase()) , mClipboard(0) , mNativeInterface(new QXlibNativeInterface) { + mEventDispatcher = createUnixEventDispatcher(); + QGuiApplicationPrivate::instance()->setEventDispatcher(mEventDispatcher); + + XInitThreads(); + mPrimaryScreen = new QXlibScreen(); mScreens.append(mPrimaryScreen); + screenAdded(mPrimaryScreen); } -bool QXlibIntegration::hasCapability(QPlatformIntegration::Capability cap) const +bool QXlibIntegration::hasCapability(QPlatformIntegration::Capability) const { - switch (cap) { - case ThreadedPixmaps: return true; - case OpenGL: return hasOpenGL(); - default: return QPlatformIntegration::hasCapability(cap); - } + return true; } -QPixmapData *QXlibIntegration::createPixmapData(QPixmapData::PixelType type) const +QPlatformBackingStore *QXlibIntegration::createPlatformBackingStore(QWindow *window) const { -#ifndef QT_NO_OPENGL - if (mUseOpenGL) - return new QGLPixmapData(type); -#endif - return new QRasterPixmapData(type); + return new QXlibBackingStore(window); } -QWindowSurface *QXlibIntegration::createWindowSurface(QWidget *widget, WId) const +QPlatformOpenGLContext *QXlibIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { -#ifndef QT_NO_OPENGL - if (mUseOpenGL) - return new QGLWindowSurface(widget); -#endif - return new QXlibWindowSurface(widget); + QXlibScreen *screen = static_cast<QXlibScreen *>(context->screen()->handle()); + + return new QGLXContext(screen, context->format(), context->shareHandle()); } -QPlatformWindow *QXlibIntegration::createPlatformWindow(QWidget *widget, WId /*winId*/) const +QPlatformWindow *QXlibIntegration::createPlatformWindow(QWindow *window) const { - return new QXlibWindow(widget); + return new QXlibWindow(window); } - - -QPixmap QXlibIntegration::grabWindow(WId window, int x, int y, int width, int height) const +QAbstractEventDispatcher *QXlibIntegration::guiThreadEventDispatcher() 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); + return mEventDispatcher; } QPlatformFontDatabase *QXlibIntegration::fontDatabase() const @@ -146,28 +121,4 @@ QPlatformNativeInterface * QXlibIntegration::nativeInterface() const return mNativeInterface; } -bool QXlibIntegration::hasOpenGL() const -{ -#if !defined(QT_NO_OPENGL) -#if !defined(QT_OPENGL_ES_2) - QXlibScreen *screen = static_cast<QXlibScreen *>(mScreens.at(0)); - return glXQueryExtension(screen->display()->nativeDisplay(), 0, 0) != 0; -#else - static bool eglHasbeenInitialized = false; - static bool wasEglInitialized = false; - if (!eglHasbeenInitialized) { - eglHasbeenInitialized = true; - QXlibScreen *screen = static_cast<QXlibScreen *>(mScreens.at(0)); - EGLint major, minor; - eglBindAPI(EGL_OPENGL_ES_API); - EGLDisplay disp = eglGetDisplay(screen->display()->nativeDisplay()); - wasEglInitialized = eglInitialize(disp,&major,&minor); - screen->setEglDisplay(disp); - } - return wasEglInitialized; -#endif -#endif - return false; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qxlibintegration.h b/src/plugins/platforms/xlib/qxlibintegration.h index 9c814ead69..f5150fca6f 100644 --- a/src/plugins/platforms/xlib/qxlibintegration.h +++ b/src/plugins/platforms/xlib/qxlibintegration.h @@ -58,12 +58,15 @@ class QXlibScreen; class QXlibIntegration : public QPlatformIntegration { public: - QXlibIntegration(bool useOpenGL = false); + QXlibIntegration(); bool hasCapability(Capability cap) const; - QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; + + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + + QAbstractEventDispatcher *guiThreadEventDispatcher() const; QPixmap grabWindow(WId window, int x, int y, int width, int height) const; @@ -75,14 +78,12 @@ public: QPlatformNativeInterface *nativeInterface() const; private: - bool hasOpenGL() const; - - bool mUseOpenGL; QXlibScreen *mPrimaryScreen; QList<QPlatformScreen *> mScreens; QPlatformFontDatabase *mFontDb; QPlatformClipboard *mClipboard; QPlatformNativeInterface *mNativeInterface; + QAbstractEventDispatcher *mEventDispatcher; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qxlibkeyboard.cpp b/src/plugins/platforms/xlib/qxlibkeyboard.cpp index c152070e5a..66e48fec93 100644 --- a/src/plugins/platforms/xlib/qxlibkeyboard.cpp +++ b/src/plugins/platforms/xlib/qxlibkeyboard.cpp @@ -987,7 +987,7 @@ static Qt::KeyboardModifiers modifierFromKeyCode(int qtcode) } } -void QXlibKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, XKeyEvent *ev) +void QXlibKeyboard::handleKeyEvent(QWindow *widget, QEvent::Type type, XKeyEvent *ev) { int qtcode = 0; Qt::KeyboardModifiers modifiers = translateModifiers(ev->state); diff --git a/src/plugins/platforms/xlib/qxlibkeyboard.h b/src/plugins/platforms/xlib/qxlibkeyboard.h index 71dbf8f78d..a33ad61d27 100644 --- a/src/plugins/platforms/xlib/qxlibkeyboard.h +++ b/src/plugins/platforms/xlib/qxlibkeyboard.h @@ -51,7 +51,7 @@ public: void changeLayout(); - void handleKeyEvent(QWidget *widget, QEvent::Type type, XKeyEvent *ev); + void handleKeyEvent(QWindow *widget, QEvent::Type type, XKeyEvent *ev); Qt::KeyboardModifiers translateModifiers(int s); diff --git a/src/plugins/platforms/xlib/qxlibnativeinterface.cpp b/src/plugins/platforms/xlib/qxlibnativeinterface.cpp index 76396aaeb6..2c706e64e4 100644 --- a/src/plugins/platforms/xlib/qxlibnativeinterface.cpp +++ b/src/plugins/platforms/xlib/qxlibnativeinterface.cpp @@ -39,10 +39,11 @@ ** ****************************************************************************/ +#include <private/qguiapplication_p.h> #include "qxlibnativeinterface.h" #include "qxlibdisplay.h" -#include <QtGui/private/qapplication_p.h> +#include "qscreen.h" class QXlibResourceMap : public QMap<QByteArray, QXlibNativeInterface::ResourceType> { @@ -62,29 +63,29 @@ public: Q_GLOBAL_STATIC(QXlibResourceMap, qXlibResourceMap) -void * QXlibNativeInterface::nativeResourceForWidget(const QByteArray &resourceString, QWidget *widget) +void * QXlibNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { QByteArray lowerCaseResource = resourceString.toLower(); ResourceType resource = qXlibResourceMap()->value(lowerCaseResource); void *result = 0; switch(resource) { case Display: - result = displayForWidget(widget); + result = displayForWindow(window); break; case EglDisplay: - result = eglDisplayForWidget(widget); + result = eglDisplayForWindow(window); break; case Connection: - result = connectionForWidget(widget); + result = connectionForWindow(window); break; case Screen: - result = reinterpret_cast<void *>(qPlatformScreenForWidget(widget)->xScreenNumber()); + result = reinterpret_cast<void *>(qPlatformScreenForWindow(window)->xScreenNumber()); break; case GraphicsDevice: - result = graphicsDeviceForWidget(widget); + result = graphicsDeviceForWindow(window); break; case EglContext: - result = eglContextForWidget(widget); + result = eglContextForWindow(window); break; default: result = 0; @@ -92,42 +93,37 @@ void * QXlibNativeInterface::nativeResourceForWidget(const QByteArray &resourceS return result; } -void * QXlibNativeInterface::displayForWidget(QWidget *widget) +void * QXlibNativeInterface::displayForWindow(QWindow *window) { - return qPlatformScreenForWidget(widget)->display()->nativeDisplay(); + return qPlatformScreenForWindow(window)->display()->nativeDisplay(); } -void * QXlibNativeInterface::eglDisplayForWidget(QWidget *widget) +void * QXlibNativeInterface::eglDisplayForWindow(QWindow *window) { - Q_UNUSED(widget); + Q_UNUSED(window); return 0; } -void * QXlibNativeInterface::screenForWidget(QWidget *widget) +void * QXlibNativeInterface::screenForWindow(QWindow *window) { - Q_UNUSED(widget); + Q_UNUSED(window); return 0; } -void * QXlibNativeInterface::graphicsDeviceForWidget(QWidget *widget) +void * QXlibNativeInterface::graphicsDeviceForWindow(QWindow *window) { - Q_UNUSED(widget); + Q_UNUSED(window); return 0; } -void * QXlibNativeInterface::eglContextForWidget(QWidget *widget) +void * QXlibNativeInterface::eglContextForWindow(QWindow *window) { - Q_UNUSED(widget); + Q_UNUSED(window); return 0; } -QXlibScreen * QXlibNativeInterface::qPlatformScreenForWidget(QWidget *widget) +QXlibScreen * QXlibNativeInterface::qPlatformScreenForWindow(QWindow *window) { - QXlibScreen *screen; - if (widget) { - screen = static_cast<QXlibScreen *>(QPlatformScreen::platformScreenForWidget(widget)); - }else { - screen = static_cast<QXlibScreen *>(QApplicationPrivate::platformIntegration()->screens()[0]); - } - return screen; + QScreen *screen = window ? window->screen() : QGuiApplication::primaryScreen(); + return static_cast<QXlibScreen *>(screen->handle()); } diff --git a/src/plugins/platforms/xlib/qxlibnativeinterface.h b/src/plugins/platforms/xlib/qxlibnativeinterface.h index e1f5cea8b2..4c6ce770b0 100644 --- a/src/plugins/platforms/xlib/qxlibnativeinterface.h +++ b/src/plugins/platforms/xlib/qxlibnativeinterface.h @@ -58,17 +58,17 @@ public: EglContext }; - void *nativeResourceForWidget(const QByteArray &resourceString, QWidget *widget); + void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); - void *displayForWidget(QWidget *widget); - void *eglDisplayForWidget(QWidget *widget); - void *connectionForWidget(QWidget *widget); - void *screenForWidget(QWidget *widget); - void *graphicsDeviceForWidget(QWidget *widget); - void *eglContextForWidget(QWidget *widget); + void *displayForWindow(QWindow *window); + void *eglDisplayForWindow(QWindow *window); + void *connectionForWindow(QWindow *window); + void *screenForWindow(QWindow *window); + void *graphicsDeviceForWindow(QWindow *window); + void *eglContextForWindow(QWindow *window); private: - static QXlibScreen *qPlatformScreenForWidget(QWidget *widget); + static QXlibScreen *qPlatformScreenForWindow(QWindow *window); }; diff --git a/src/plugins/platforms/xlib/qxlibscreen.cpp b/src/plugins/platforms/xlib/qxlibscreen.cpp index b069985a5c..e6263c0b33 100644 --- a/src/plugins/platforms/xlib/qxlibscreen.cpp +++ b/src/plugins/platforms/xlib/qxlibscreen.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include <private/qguiapplication_p.h> #include "qxlibscreen.h" #include <X11/extensions/Xfixes.h> @@ -54,7 +55,7 @@ #include <QtCore/QSocketNotifier> #include <QtCore/QElapsedTimer> -#include <private/qapplication_p.h> +#include <QtGui/QScreen> QT_BEGIN_NAMESPACE @@ -263,11 +264,9 @@ unsigned long QXlibScreen::whitePixel() 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()); - } + QXlibWindow *platformWindow = QXlibWindow::platformWindowForXWindow(xe->xany.window); + if (!platformWindow) + return false; Atom wmProtocolsAtom = QXlibStatic::atom(QXlibStatic::WM_PROTOCOLS); Atom wmDeleteWindowAtom = QXlibStatic::atom(QXlibStatic::WM_DELETE_WINDOW); @@ -282,56 +281,48 @@ bool QXlibScreen::handleEvent(XEvent *xe) break; case Expose: - if (platformWindow) - if (xe->xexpose.count == 0) - platformWindow->paintEvent(); + // ### +// if (xe->xexpose.count == 0) +// platformWindow->paintEvent(); break; case ConfigureNotify: - if (platformWindow) - platformWindow->resizeEvent(&xe->xconfigure); + platformWindow->resizeEvent(&xe->xconfigure); break; case ButtonPress: - if (platformWindow) - platformWindow->mousePressEvent(&xe->xbutton); + platformWindow->mousePressEvent(&xe->xbutton); break; case ButtonRelease: - if (platformWindow) - platformWindow->handleMouseEvent(QEvent::MouseButtonRelease, &xe->xbutton); + platformWindow->handleMouseEvent(QEvent::MouseButtonRelease, &xe->xbutton); break; case MotionNotify: - if (platformWindow) - platformWindow->handleMouseEvent(QEvent::MouseMove, &xe->xbutton); + platformWindow->handleMouseEvent(QEvent::MouseMove, &xe->xbutton); break; - case XKeyPress: - mKeyboard->handleKeyEvent(widget,QEvent::KeyPress, &xe->xkey); + case XKeyPress: + mKeyboard->handleKeyEvent(platformWindow->window(), QEvent::KeyPress, &xe->xkey); break; case XKeyRelease: - mKeyboard->handleKeyEvent(widget,QEvent::KeyRelease, &xe->xkey); + mKeyboard->handleKeyEvent(platformWindow->window(), QEvent::KeyRelease, &xe->xkey); break; case EnterNotify: - if (platformWindow) - platformWindow->handleEnterEvent(); + platformWindow->handleEnterEvent(); break; case LeaveNotify: - if (platformWindow) - platformWindow->handleLeaveEvent(); + platformWindow->handleLeaveEvent(); break; case XFocusIn: - if (platformWindow) - platformWindow->handleFocusInEvent(); + platformWindow->handleFocusInEvent(); break; case XFocusOut: - if (platformWindow) - platformWindow->handleFocusOutEvent(); + platformWindow->handleFocusOutEvent(); break; case PropertyNotify: @@ -452,10 +443,9 @@ QImage QXlibScreen::grabWindow(Window window, int x, int y, int w, int h) return result; } -QXlibScreen * QXlibScreen::testLiteScreenForWidget(QWidget *widget) +QXlibScreen * QXlibScreen::testLiteScreenForWidget(QWindow *widget) { - QPlatformScreen *platformScreen = platformScreenForWidget(widget); - return static_cast<QXlibScreen *>(platformScreen); + return static_cast<QXlibScreen *>(widget->screen()->handle()); } QXlibDisplay * QXlibScreen::display() const @@ -480,7 +470,7 @@ QXlibKeyboard * QXlibScreen::keyboard() const void QXlibScreen::handleSelectionRequest(XEvent *event) { - QPlatformIntegration *integration = QApplicationPrivate::platformIntegration(); + QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration(); QXlibClipboard *clipboard = static_cast<QXlibClipboard *>(integration->clipboard()); clipboard->handleSelectionRequest(event); } diff --git a/src/plugins/platforms/xlib/qxlibscreen.h b/src/plugins/platforms/xlib/qxlibscreen.h index 81625e561e..6e1a3e401d 100644 --- a/src/plugins/platforms/xlib/qxlibscreen.h +++ b/src/plugins/platforms/xlib/qxlibscreen.h @@ -51,7 +51,7 @@ class QXlibCursor; class QXlibKeyboard; class QXlibDisplay; -class QXlibScreen : public QPlatformScreen +class QXlibScreen : public QObject, public QPlatformScreen { Q_OBJECT public: @@ -73,7 +73,7 @@ public: QImage grabWindow(Window window, int x, int y, int w, int h); - static QXlibScreen *testLiteScreenForWidget(QWidget *widget); + static QXlibScreen *testLiteScreenForWidget(QWindow *widget); QXlibDisplay *display() const; int xScreenNumber() const; diff --git a/src/plugins/platforms/xlib/qxlibstatic.cpp b/src/plugins/platforms/xlib/qxlibstatic.cpp index 3ba0eb4c32..c9ed13aeea 100644 --- a/src/plugins/platforms/xlib/qxlibstatic.cpp +++ b/src/plugins/platforms/xlib/qxlibstatic.cpp @@ -39,13 +39,14 @@ ** ****************************************************************************/ +#include <private/qguiapplication_p.h> #include "qxlibstatic.h" #include "qxlibscreen.h" #include "qxlibdisplay.h" #include <qplatformdefs.h> +#include <QtGui/qscreen.h> -#include <QtGui/private/qapplication_p.h> #include <QtCore/QBuffer> #include <QtCore/QLibrary> @@ -258,7 +259,7 @@ public: , xfixes_eventbase(0) , xfixes_errorbase(0) { - QXlibScreen *screen = qobject_cast<QXlibScreen *> (QApplicationPrivate::platformIntegration()->screens().at(0)); + QXlibScreen *screen = static_cast<QXlibScreen *> (QGuiApplication::primaryScreen()->handle()); Q_ASSERT(screen); initializeAllAtoms(screen); diff --git a/src/plugins/platforms/xlib/qxlibwindow.cpp b/src/plugins/platforms/xlib/qxlibwindow.cpp index 823fae9de3..e388f1054d 100644 --- a/src/plugins/platforms/xlib/qxlibwindow.cpp +++ b/src/plugins/platforms/xlib/qxlibwindow.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include <QtGui/private/qguiapplication_p.h> #include "qxlibwindow.h" #include "qxlibintegration.h" @@ -50,7 +51,7 @@ #if !defined(QT_NO_OPENGL) #if !defined(QT_OPENGL_ES_2) #include "qglxintegration.h" -#include "qglxconvenience.h" +#include "private/qglxconvenience_p.h" #else #include "../eglconvenience/qeglconvenience.h" #include "../eglconvenience/qeglplatformcontext.h" @@ -64,14 +65,14 @@ #include <QApplication> #include <QDebug> -#include <QtGui/private/qwindowsurface_p.h> -#include <QtGui/private/qapplication_p.h> - //#define MYX11_DEBUG QT_BEGIN_NAMESPACE -QXlibWindow::QXlibWindow(QWidget *window) +QHash<Window, QXlibWindow *> QXlibWindow::windowMap; + + +QXlibWindow::QXlibWindow(QWindow *window) : QPlatformWindow(window) , mGLContext(0) , mScreen(QXlibScreen::testLiteScreenForWidget(window)) @@ -82,11 +83,10 @@ QXlibWindow::QXlibWindow(QWidget *window) int h = window->height(); #if !defined(QT_NO_OPENGL) - if(window->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL - && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL) - || window->platformWindowFormat().alpha()) { + if(window->surfaceType() == QWindow::OpenGLSurface) { #if !defined(QT_OPENGL_ES_2) - XVisualInfo *visualInfo = qglx_findVisualInfo(mScreen->display()->nativeDisplay(),mScreen->xScreenNumber(),window->platformWindowFormat()); + XVisualInfo *visualInfo = qglx_findVisualInfo(mScreen->display()->nativeDisplay(), mScreen->xScreenNumber(), + window->format()); #else QPlatformWindowFormat windowFormat = correctColorBuffers(window->platformWindowFormat()); @@ -156,6 +156,8 @@ QXlibWindow::QXlibWindow(QWidget *window) if (window->windowFlags() & Qt::WindowContextHelpButtonHint) protocols[n++] = QXlibStatic::atom(QXlibStatic::_NET_WM_CONTEXT_HELP); XSetWMProtocols(mScreen->display()->nativeDisplay(), x_window, protocols, n); + + windowMap.insert(x_window, this); } @@ -165,6 +167,9 @@ QXlibWindow::~QXlibWindow() #ifdef MYX11_DEBUG qDebug() << "~QTestLiteWindow" << hex << x_window; #endif + + windowMap.remove(x_window); + delete mGLContext; XFreeGC(mScreen->display()->nativeDisplay(), gc); XDestroyWindow(mScreen->display()->nativeDisplay(), x_window); @@ -209,7 +214,7 @@ void QXlibWindow::handleMouseEvent(QEvent::Type type, XButtonEvent *e) bool hor = (((e->button == Button4 || e->button == Button5) && (modifiers & Qt::AltModifier)) || (e->button == 6 || e->button == 7)); - QWindowSystemInterface::handleWheelEvent(widget(), e->time, + QWindowSystemInterface::handleWheelEvent(window(), e->time, QPoint(e->x, e->y), QPoint(e->x_root, e->y_root), delta, hor ? Qt::Horizontal : Qt::Vertical); @@ -222,7 +227,7 @@ void QXlibWindow::handleMouseEvent(QEvent::Type type, XButtonEvent *e) buttons ^= button; // X event uses state *before*, Qt uses state *after* - QWindowSystemInterface::handleMouseEvent(widget(), e->time, QPoint(e->x, e->y), + QWindowSystemInterface::handleMouseEvent(window(), e->time, QPoint(e->x, e->y), QPoint(e->x_root, e->y_root), buttons); @@ -231,23 +236,23 @@ void QXlibWindow::handleMouseEvent(QEvent::Type type, XButtonEvent *e) void QXlibWindow::handleCloseEvent() { - QWindowSystemInterface::handleCloseEvent(widget()); + QWindowSystemInterface::handleCloseEvent(window()); } void QXlibWindow::handleEnterEvent() { - QWindowSystemInterface::handleEnterEvent(widget()); + QWindowSystemInterface::handleEnterEvent(window()); } void QXlibWindow::handleLeaveEvent() { - QWindowSystemInterface::handleLeaveEvent(widget()); + QWindowSystemInterface::handleLeaveEvent(window()); } void QXlibWindow::handleFocusInEvent() { - QWindowSystemInterface::handleWindowActivated(widget()); + QWindowSystemInterface::handleWindowActivated(window()); } void QXlibWindow::handleFocusOutEvent() @@ -313,16 +318,6 @@ GC QXlibWindow::createGC() 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()->nativeDisplay(), x_window, XRevertToParent, CurrentTime); @@ -340,11 +335,12 @@ void QXlibWindow::resizeEvent(XConfigureEvent *e) 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; + qDebug() << hex << x_window << dec << "ConfigureNotify" << e->x << e->y << e->width << e->height << + "geometry" << xpos << ypos << e->width << e->height; #endif QRect newRect(xpos, ypos, e->width, e->height); - QWindowSystemInterface::handleGeometryChange(widget(), newRect); + QWindowSystemInterface::handleGeometryChange(window(), newRect); } void QXlibWindow::mousePressEvent(XButtonEvent *e) @@ -413,16 +409,15 @@ void QXlibWindow::setMWMHints(const QXlibMWMHints &mwmhints) } // Returns true if we should set WM_TRANSIENT_FOR on \a w -static inline bool isTransient(const QWidget *w) +static inline bool isTransient(const QWindow *w) { - return ((w->windowType() == Qt::Dialog + 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)); + || w->windowType() == Qt::Popup); } QVector<Atom> QXlibWindow::getNetWmState() const @@ -568,9 +563,9 @@ Qt::WindowFlags QXlibWindow::setWindowFlags(Qt::WindowFlags flags) mwmhints.decorations = 0; } - if (widget()->windowModality() == Qt::WindowModal) { + if (window()->windowModality() == Qt::WindowModal) { mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL; - } else if (widget()->windowModality() == Qt::ApplicationModal) { + } else if (window()->windowModality() == Qt::ApplicationModal) { mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL; } @@ -580,7 +575,7 @@ Qt::WindowFlags QXlibWindow::setWindowFlags(Qt::WindowFlags flags) 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"; + qWarning() << "QWindow: 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))) @@ -589,17 +584,17 @@ Qt::WindowFlags QXlibWindow::setWindowFlags(Qt::WindowFlags flags) if (!netWmState.contains(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_BELOW))) netWmState.append(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_BELOW)); } - if (widget()->isFullScreen()) { + if (window()->windowState() & Qt::WindowFullScreen) { if (!netWmState.contains(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_FULLSCREEN))) netWmState.append(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_FULLSCREEN)); } - if (widget()->isMaximized()) { + if (window()->windowState() & Qt::WindowMaximized) { 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 (window()->windowModality() != Qt::NonModal) { if (!netWmState.contains(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_MODAL))) netWmState.append(QXlibStatic::atom(QXlibStatic::_NET_WM_STATE_MODAL)); } @@ -634,24 +629,29 @@ Qt::WindowFlags QXlibWindow::setWindowFlags(Qt::WindowFlags flags) return flags; } +Qt::WindowState QXlibWindow::setWindowState(Qt::WindowState state) +{ + // #### + return state; +} + void QXlibWindow::setVisible(bool visible) { #ifdef MYX11_DEBUG qDebug() << "QTestLiteWindow::setVisible" << visible << hex << x_window; #endif - if (isTransient(widget())) { + if (isTransient(window())) { 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; - } + QWindow *parent = window()->parent(); + if (parent && parent->handle()) { + QXlibWindow *xlibParent = static_cast<QXlibWindow *>(parent->handle()); + parentXWindow = xlibParent->x_window; } XSetTransientForHint(mScreen->display()->nativeDisplay(),x_window,parentXWindow); } if (visible) { + qDebug() << ">>> mapping"; //ensure that the window is viewed in correct position. doSizeHints(); XMapWindow(mScreen->display()->nativeDisplay(), x_window); @@ -666,34 +666,12 @@ void QXlibWindow::setCursor(const Cursor &cursor) mScreen->display()->flush(); } -QPlatformGLContext *QXlibWindow::glContext() const +QSurfaceFormat QXlibWindow::format() const { - if (!QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) - 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 = mScreen->eglDisplay(); - - 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; + return window()->format(); } + Window QXlibWindow::xWindow() const { return x_window; @@ -706,7 +684,7 @@ GC QXlibWindow::graphicsContext() const void QXlibWindow::doSizeHints() { - Q_ASSERT(widget()->testAttribute(Qt::WA_WState_Created)); +// Q_ASSERT(window()->testAttribute(Qt::WA_WState_Created)); XSizeHints s; s.flags = 0; QRect g = geometry(); @@ -723,27 +701,10 @@ void QXlibWindow::doSizeHints() XSetWMNormalHints(mScreen->display()->nativeDisplay(), 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; +QXlibWindow *QXlibWindow::platformWindowForXWindow(Window window) +{ + return windowMap.value(window); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/xlib/qxlibwindow.h b/src/plugins/platforms/xlib/qxlibwindow.h index da29efbff1..9b64dc5624 100644 --- a/src/plugins/platforms/xlib/qxlibwindow.h +++ b/src/plugins/platforms/xlib/qxlibwindow.h @@ -49,6 +49,7 @@ #include <QObject> #include <QImage> +#include <QHash> struct QXlibMWMHints { ulong flags, functions, decorations; @@ -86,7 +87,7 @@ enum { class QXlibWindow : public QPlatformWindow { public: - QXlibWindow(QWidget *window); + QXlibWindow(QWindow *window); ~QXlibWindow(); @@ -100,7 +101,6 @@ public: void handleFocusOutEvent(); void resizeEvent(XConfigureEvent *configure_event); - void paintEvent(); void requestActivateWindow(); @@ -108,6 +108,8 @@ public: Qt::WindowFlags setWindowFlags(Qt::WindowFlags type); Qt::WindowFlags windowFlags() const; + Qt::WindowState setWindowState(Qt::WindowState state); + void setVisible(bool visible); WId winId() const; void setParent(const QPlatformWindow *window); @@ -117,14 +119,14 @@ public: void setCursor(const Cursor &cursor); - QPlatformGLContext *glContext() const; - Window xWindow() const; GC graphicsContext() const; - inline uint depth() const { return mDepth; } - QImage::Format format() const { return mFormat; } + QSurfaceFormat format() const; Visual* visual() const { return mVisual; } + int depth() const { return mDepth; } + + static QXlibWindow *platformWindowForXWindow(Window window); protected: QVector<Atom> getNetWmState() const; @@ -134,8 +136,6 @@ protected: void doSizeHints(); private: - QPlatformWindowFormat correctColorBuffers(const QPlatformWindowFormat &windowFormat)const; - Window x_window; GC gc; @@ -145,9 +145,11 @@ private: GC createGC(); - QPlatformGLContext *mGLContext; + QPlatformOpenGLContext *mGLContext; QXlibScreen *mScreen; Qt::WindowFlags mWindowFlags; + + static QHash<Window, QXlibWindow *> windowMap; }; #endif diff --git a/src/plugins/platforms/xlib/xlib.pro b/src/plugins/platforms/xlib/xlib.pro index 2cba5513d5..ea95ae83a1 100644 --- a/src/plugins/platforms/xlib/xlib.pro +++ b/src/plugins/platforms/xlib/xlib.pro @@ -1,14 +1,14 @@ TARGET = qxlib load(qt_plugin) -DESTDIR = $$QT.gui.plugins/platforms +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms -QT += core-private gui-private opengl-private +QT += core-private gui-private platformsupport-private SOURCES = \ main.cpp \ qxlibintegration.cpp \ - qxlibwindowsurface.cpp \ + qxlibbackingstore.cpp \ qxlibwindow.cpp \ qxlibcursor.cpp \ qxlibscreen.cpp \ @@ -21,7 +21,7 @@ SOURCES = \ HEADERS = \ qxlibintegration.h \ - qxlibwindowsurface.h \ + qxlibbackingstore.h \ qxlibwindow.h \ qxlibcursor.h \ qxlibscreen.h \ @@ -38,24 +38,18 @@ mac { LIBS += -L/usr/X11/lib -lz -framework Carbon } -include (../fontdatabases/genericunix/genericunix.pri) +CONFIG += qpa/genericunixfontdatabase contains(QT_CONFIG, opengl) { QT += opengl !contains(QT_CONFIG, opengles2) { - include (../glxconvenience/glxconvenience.pri) +# load(qpa/glx/convenience) 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 \ - ../eglconvenience/qxlibeglintegration.h - - SOURCES += \ - ../eglconvenience/qeglplatformcontext.cpp \ - ../eglconvenience/qeglconvenience.cpp \ - ../eglconvenience/qxlibeglintegration.cpp +# load(qpa/egl/context) +# load(qpa/egl/convenience) +# load(qpa/egl/xlibintegration) LIBS += -lEGL } } diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 0f2392eeeb..f47c000dfb 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -6,12 +6,11 @@ unix:!symbian { } else { SUBDIRS *= codecs } -!contains(QT_CONFIG, no-gui) { - SUBDIRS *= imageformats - !embedded:!qpa:SUBDIRS *= graphicssystems - !win32:!embedded:!mac:!symbian:SUBDIRS *= inputmethods - !symbian:SUBDIRS += accessible -} -embedded:SUBDIRS *= gfxdrivers decorations mousedrivers kbddrivers +!contains(QT_CONFIG, no-gui): SUBDIRS *= imageformats +!symbian:!contains(QT_CONFIG, no-gui):SUBDIRS += accessible + symbian:SUBDIRS += s60 -qpa:SUBDIRS += platforms +qpa: { + SUBDIRS += platforms + SUBDIRS += platforminputcontexts +} |