diff options
Diffstat (limited to 'src/plugins/gfxdrivers/directfb')
16 files changed, 4645 insertions, 0 deletions
diff --git a/src/plugins/gfxdrivers/directfb/directfb.pro b/src/plugins/gfxdrivers/directfb/directfb.pro new file mode 100644 index 0000000..96eb536 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/directfb.pro @@ -0,0 +1,40 @@ +TARGET = qdirectfbscreen +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers + +# These defines might be necessary if your DirectFB driver doesn't +# support all of the DirectFB API. +# +#DEFINES += QT_NO_DIRECTFB_WM +#DEFINES += QT_NO_DIRECTFB_LAYER +#DEFINES += QT_NO_DIRECTFB_PALETTE +#DEFINES += QT_NO_DIRECTFB_PREALLOCATED +#DEFINES += QT_NO_DIRECTFB_MOUSE +#DEFINES += QT_NO_DIRECTFB_KEYBOARD + +target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers +INSTALLS += target + +HEADERS = \ + qdirectfbscreen.h \ + qdirectfbsurface.h \ + qdirectfbpaintengine.h \ + qdirectfbpaintdevice.h \ + qdirectfbpixmap.h \ + qdirectfbkeyboard.h \ + qdirectfbmouse.h + +SOURCES = \ + qdirectfbscreen.cpp \ + qdirectfbscreenplugin.cpp \ + qdirectfbsurface.cpp \ + qdirectfbpaintengine.cpp \ + qdirectfbpaintdevice.cpp \ + qdirectfbpixmap.cpp \ + qdirectfbkeyboard.cpp \ + qdirectfbmouse.cpp + +QMAKE_CXXFLAGS += $$QT_CFLAGS_DIRECTFB +LIBS += $$QT_LIBS_DIRECTFB + diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp new file mode 100644 index 0000000..cd19f69 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbkeyboard.h" + +#ifndef QT_NO_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> + +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; + +private slots: + void readKeyboardData(); +}; + +QDirectFBKeyboardHandlerPrivate::QDirectFBKeyboardHandlerPrivate(QDirectFBKeyboardHandler *h) + : handler(h), eventBuffer(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)); + bytesRead = 0; + + + 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; + + 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; + } + // 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 int warningCount = 0; + if (!warningCount) { + qWarning("QDirectFBKeyboardHandler - Getting unexpected non-keyboard related events"); + warningCount = 100; + } + else + warningCount--; + break; + } + + bool press = input.type & DIET_KEYPRESS; + DFBInputDeviceKeySymbol symbol = input.key_symbol; + int unicode = -1; + int keycode = 0; + + keycode = keymap()->value(symbol); + if (keycode == 0 && DFB_KEY_TYPE(symbol) == DIKT_UNICODE) + unicode = symbol; + + if (unicode != -1 || keycode != 0) { + handler->processKeyEvent(unicode, keycode, + modifiers, press, false); + } + } +} + +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); +} + +#include "qdirectfbkeyboard.moc" + +#endif // QT_NO_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h new file mode 100644 index 0000000..234a266 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTFBKEYBOARD_H +#define QDIRECTFBKEYBOARD_H + +#include <QtGui/qkbd_qws.h> + +QT_BEGIN_HEADER + +QT_MODULE(Gui) + +#ifndef QT_NO_DIRECTFB + +class QDirectFBKeyboardHandlerPrivate; + +class QDirectFBKeyboardHandler : public QWSKeyboardHandler +{ +public: + QDirectFBKeyboardHandler(const QString &device); + ~QDirectFBKeyboardHandler(); + +private: + QDirectFBKeyboardHandlerPrivate *d; +}; + +#endif // QT_NO_DIRECTFB + +QT_END_HEADER + +#endif // QDIRECTFBKEYBOARD_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp new file mode 100644 index 0000000..f4d9b46 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbmouse.h" + +#include "qdirectfbscreen.h" +#include <qsocketnotifier.h> + +#include <directfb.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +class QDirectFBMouseHandlerPrivate : public QObject +{ + Q_OBJECT +public: + QDirectFBMouseHandlerPrivate(QDirectFBMouseHandler *h); + ~QDirectFBMouseHandlerPrivate(); + + void suspend(); + void resume(); + +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 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 = DFBInputDeviceCapabilities(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())); + resume(); +} + +QDirectFBMouseHandlerPrivate::~QDirectFBMouseHandlerPrivate() +{ + if (eventBuffer) + eventBuffer->Release(eventBuffer); +} + +void QDirectFBMouseHandlerPrivate::suspend() +{ + mouseNotifier->setEnabled(false); +} + +void QDirectFBMouseHandlerPrivate::resume() +{ + eventBuffer->Reset(eventBuffer); + mouseNotifier->setEnabled(true); +} + +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) { +#ifdef QT_NO_DIRECTFB_LAYER + 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->suspend(); +} + +void QDirectFBMouseHandler::resume() +{ + d->resume(); +} + +#include "qdirectfbmouse.moc" + diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h new file mode 100644 index 0000000..e81a4ba --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTFBMOUSE_H +#define QDIRECTFBMOUSE_H + +#include <QtGui/qmouse_qws.h> + +QT_BEGIN_HEADER + +QT_MODULE(Gui) + +#ifndef QT_NO_DIRECTFB + +class QDirectFBMouseHandlerPrivate; + +class QDirectFBMouseHandler : public QWSMouseHandler +{ +public: + explicit QDirectFBMouseHandler(const QString &driver = QString(), + const QString &device = QString()); + ~QDirectFBMouseHandler(); + + void suspend(); + void resume(); + +protected: + QDirectFBMouseHandlerPrivate *d; +}; + +#endif // QT_NO_DIRECTFB + +QT_END_HEADER + +#endif // QDIRECTFBMOUSE_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp new file mode 100644 index 0000000..d1802e4 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_DIRECTFB + +#include "qdirectfbscreen.h" +#include "qdirectfbpaintdevice.h" + + +IDirectFBSurface *QDirectFBPaintDevice::directFbSurface() const +{ + return dfbSurface; +} + + +// Locks the dfb surface and creates a QImage (lockedImage) from the pointer +void QDirectFBPaintDevice::lockDirectFB() { + + if (lockedImage) + return; // Already locked + + void *mem; + int w, h; + int bpl; + DFBSurfacePixelFormat format; + + DFBResult result = dfbSurface->Lock(dfbSurface, DSLF_WRITE, &mem, &bpl); + if (result != DFB_OK || !mem) { + DirectFBError("QDirectFBPixmapData::buffer()", result); + return; + } + + dfbSurface->GetSize(dfbSurface, &w, &h); + dfbSurface->GetPixelFormat(dfbSurface, &format); + + lockedImage = new QImage(static_cast<uchar*>(mem), w, h, bpl, + QDirectFBScreen::getImageFormat(format)); +} + + +void QDirectFBPaintDevice::unlockDirectFB() +{ + if (!lockedImage) + return; + + dfbSurface->Unlock(dfbSurface); + delete lockedImage; + lockedImage = 0; +} + + +void* QDirectFBPaintDevice::memory() const +{ + QDirectFBPaintDevice* that = const_cast<QDirectFBPaintDevice*>(this); + that->lockDirectFB(); + Q_ASSERT(that->lockedImage); + return that->lockedImage->bits(); +} + + +QImage::Format QDirectFBPaintDevice::format() const +{ + DFBSurfacePixelFormat dfbFormat; + dfbSurface->GetPixelFormat(dfbSurface, &dfbFormat); + return QDirectFBScreen::getImageFormat(dfbFormat); +} + + +int QDirectFBPaintDevice::bytesPerLine() const +{ + // Can only get the stride when we lock the surface + QDirectFBPaintDevice* that = const_cast<QDirectFBPaintDevice*>(this); + that->lockDirectFB(); + Q_ASSERT(that->lockedImage); + return that->lockedImage->bytesPerLine(); +} + + +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; + + int w, h; + dfbSurface->GetSize(dfbSurface, &w, &h); + + int dpmX, dpmY; // Dots-per-meter ;-) + + // Do some common calculations: + switch (metric) { + case QPaintDevice::PdmWidthMM: + case QPaintDevice::PdmPhysicalDpiX: + case QPaintDevice::PdmDpiX: + dpmX = (screen->deviceWidth() * 1000) / screen->physicalWidth(); + break; + case QPaintDevice::PdmHeightMM: + case QPaintDevice::PdmPhysicalDpiY: + case QPaintDevice::PdmDpiY: + dpmY = (screen->deviceHeight() * 1000) / screen->physicalHeight(); + break; + default: + break; + } + + // Now use those calculations + switch (metric) { + case QPaintDevice::PdmWidth: + return w; + case QPaintDevice::PdmHeight: + return h; + case QPaintDevice::PdmWidthMM: + return (w * 1000) / dpmX; + case QPaintDevice::PdmHeightMM: + return (h * 1000) / dpmY; + case QPaintDevice::PdmPhysicalDpiX: + case QPaintDevice::PdmDpiX: + return (dpmX * 254) / 10000; // 0.0254 meters-per-inch + case QPaintDevice::PdmPhysicalDpiY: + case QPaintDevice::PdmDpiY: + return (dpmY * 254) / 10000; // 0.0254 meters-per-inch + case QPaintDevice::PdmDepth: + DFBSurfacePixelFormat format; + dfbSurface->GetPixelFormat(dfbSurface, &format); + return QDirectFBScreen::depth(format); + case QPaintDevice::PdmNumColors: { + if (lockedImage) + return lockedImage->numColors(); + + 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; + } +} + +#endif diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h new file mode 100644 index 0000000..c28d37c --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTFBPAINTDEVICE_H +#define QDIRECTFBPAINTDEVICE_H + +#include <private/qpaintengine_raster_p.h> +#include <directfb.h> +#include "qdirectfbscreen.h" + +QT_BEGIN_HEADER + +QT_MODULE(Gui) + +// Inherited by both window surface and pixmap +class QDirectFBPaintDevice : public QCustomRasterPaintDevice +{ +public: + QDirectFBPaintDevice(QDirectFBScreen *scr = QDirectFBScreen::instance()) + : QCustomRasterPaintDevice(0), + dfbSurface(0), + lockedImage(0), + screen(scr) {} + + IDirectFBSurface *directFbSurface() const; + + void lockDirectFB(); + void unlockDirectFB(); + + // Reimplemented from QCustomRasterPaintDevice: + void* memory() const; + QImage::Format format() const; + int bytesPerLine() const; + QSize size() const; + int metric(QPaintDevice::PaintDeviceMetric metric) const; + +protected: + IDirectFBSurface *dfbSurface; + QImage *lockedImage; + QDirectFBScreen *screen; +}; + +QT_END_HEADER + +#endif //QDIRECTFBPAINTDEVICE_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp new file mode 100644 index 0000000..4fc4035 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -0,0 +1,1261 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbpaintengine.h" + +#ifndef QT_NO_DIRECTFB + +#include "qdirectfbsurface.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> + +static inline uint ALPHA_MUL(uint x, uint a) +{ + uint t = x * a; + t = ((t + (t >> 8) + 0x80) >> 8) & 0xff; + return t; +} + +static inline QRect mapRect(const QTransform &transform, const QRect &rect) +{ + return (transform.isIdentity() ? rect : transform.mapRect(rect)); +} + +static inline QRect mapRect(const QTransform &transform, const QRectF &rect) +{ + return (transform.isIdentity() ? rect : transform.mapRect(rect)). + toRect(); +} + +class SurfaceCache +{ +public: + SurfaceCache(); + ~SurfaceCache(); + + inline IDirectFBSurface *getSurface(const uint *buffer, int size); + inline void clear(); + +private: + IDirectFBSurface *surface; + uint *buffer; + int bufsize; +}; + +SurfaceCache::SurfaceCache() + : surface(0), buffer(0), bufsize(0) +{ +} + +class CachedImage +{ +public: + CachedImage(const QImage &image); + ~CachedImage(); + + IDirectFBSurface *surface() { return s; } + +private: + IDirectFBSurface *s; +}; + +CachedImage::CachedImage(const QImage &image) + : s(0) +{ + IDirectFBSurface *tmpSurface = 0; + DFBSurfaceDescription description; + description = QDirectFBScreen::getSurfaceDescription(image); + QDirectFBScreen* screen = QDirectFBScreen::instance(); + + tmpSurface = screen->createDFBSurface(&description); + if (!tmpSurface) { + qWarning("CachedImage CreateSurface failed!"); + return; + } + +#ifndef QT_NO_DIRECTFB_PALETTE + QDirectFBScreen::setSurfaceColorTable(tmpSurface, image); +#endif + + description.flags = DFBSurfaceDescriptionFlags(description.flags & ~DSDESC_PREALLOCATED); + + s = screen->createDFBSurface(&description); + if (!s) + qWarning("QDirectFBPaintEngine failed caching image"); + +#ifndef QT_NO_DIRECTFB_PALETTE + QDirectFBScreen::setSurfaceColorTable(s, image); +#endif + + if (s) { + s->SetBlittingFlags(s, DSBLIT_NOFX); + s->Blit(s, tmpSurface, 0, 0, 0); + s->ReleaseSource(s); + } + if (tmpSurface) + screen->releaseDFBSurface(tmpSurface); +} + +CachedImage::~CachedImage() +{ + if (s && QDirectFBScreen::instance()) + QDirectFBScreen::instance()->releaseDFBSurface(s); +} + +static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB + +IDirectFBSurface* SurfaceCache::getSurface(const uint *buf, int size) +{ + if (buffer == buf && bufsize == size) + return surface; + + clear(); + + DFBSurfaceDescription description; + description = QDirectFBScreen::getSurfaceDescription(buf, size); + + surface = QDirectFBScreen::instance()->createDFBSurface(&description); + 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()->releaseDFBSurface(surface); + surface = 0; + buffer = 0; + bufsize = 0; +} + +SurfaceCache::~SurfaceCache() +{ + clear(); +} + +class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate +{ +public: + QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p); + ~QDirectFBPaintEnginePrivate(); + + IDirectFBSurface *surface; + + QPen pen; + QBrush brush; + + bool antialiased; + + bool simplePen; + bool simpleBrush; + + bool matrixRotShear; + bool matrixScale; + + void setTransform(const QTransform &m); + void setPen(const QPen &pen); + void setBrush(const QBrush &brush); + void setCompositionMode(QPainter::CompositionMode mode); + void setOpacity(const qreal value); + void setRenderHints(QPainter::RenderHints hints); + + inline void setDFBColor(const QColor &color) const; + + inline bool lock(); + inline void unlock(); + + inline bool dfbCanHandleClip(const QRect &rect) const; + inline bool dfbCanHandleClip(const QRectF &rect) const; + inline bool dfbCanHandleClip() const; + + void drawLines(const QLine *lines, int count) const; + void drawLines(const QLineF *lines, int count) const; + + void fillRegion(const QRegion &r) const; + void fillRects(const QRect *rects, int count) const; + void drawRects(const QRect *rects, int count) const; + void fillRects(const QRectF *rects, int count) const; + void drawRects(const QRectF *rects, int count) const; + + void drawPixmap(const QRectF &dest, + const QPixmap &pixmap, const QRectF &src); + void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap); + void drawImage(const QRectF &dest, const QImage &image, const QRectF &src); + + void updateClip(); + void updateFlags(); + inline void setClipDirty(); + void systemStateChanged(); //Needed to be notified when system clip changes + + void begin(QPaintDevice *device); + void end(); + + SurfaceCache *surfaceCache; + +private: +// QRegion rectsToClippedRegion(const QRect *rects, int n) const; +// QRegion rectsToClippedRegion(const QRectF *rects, int n) const; + + IDirectFB *fb; + DFBSurfaceDescription fbDescription; + int fbWidth; + int fbHeight; + + quint8 opacity; + QTransform transform; + + quint32 drawFlags; + quint32 blitFlags; + quint32 duffFlags; + bool dirtyFlags; + bool dirtyClip; + bool dfbHandledClip; + + QDirectFBPaintEngine *q; +}; + +QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p) + : surface(0), antialiased(false), simplePen(false), + simpleBrush(false), matrixRotShear(false), matrixScale(false), fbWidth(-1), fbHeight(-1), + opacity(255), drawFlags(0), blitFlags(0), duffFlags(0), dirtyFlags(false), dirtyClip(true), + dfbHandledClip(false), q(p) +{ + fb = QDirectFBScreen::instance()->dfb(); + surfaceCache = new SurfaceCache; + static int cacheLimit = qgetenv("QT_DIRECTFB_IMAGECACHE").toInt(); + if (cacheLimit > 0) + imageCache.setMaxCost(cacheLimit * 1024); +} + +QDirectFBPaintEnginePrivate::~QDirectFBPaintEnginePrivate() +{ + unlock(); + delete surfaceCache; +} + +bool QDirectFBPaintEnginePrivate::dfbCanHandleClip(const QRect &rect) const +{ + // TODO: Check to see if DirectFB can handle the clip for the given rect + return dfbHandledClip; +} + +bool QDirectFBPaintEnginePrivate::dfbCanHandleClip(const QRectF &rect) const +{ + // TODO: Check to see if DirectFB can handle the clip for the given rect + return dfbHandledClip; +} + +bool QDirectFBPaintEnginePrivate::dfbCanHandleClip() const +{ + return dfbHandledClip; +} + +void QDirectFBPaintEnginePrivate::setClipDirty() +{ + dirtyClip = true; +} + + +bool 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. + if (device->devType() == QInternal::CustomRaster) { + prepare(static_cast<QCustomRasterPaintDevice*>(device)); + return true; + } + return false; +} + +void QDirectFBPaintEnginePrivate::unlock() +{ + QPaintDevice *device = q->paintDevice(); + if (!device) //XXX This should probably be an assert + return; + + Q_ASSERT(device->devType() == QInternal::CustomRaster); + QDirectFBPaintDevice* dfbDevice = static_cast<QDirectFBPaintDevice*>(device); + dfbDevice->unlockDirectFB(); +} + +void QDirectFBPaintEnginePrivate::setTransform(const QTransform &m) +{ + transform = m; + matrixRotShear = (transform.m12() != 0 || transform.m21() != 0); + matrixScale = (transform.m11() != 1 || transform.m22() != 1); +} + +void QDirectFBPaintEnginePrivate::begin(QPaintDevice *device) +{ + QDirectFBPaintDevice* dfbDevice = 0; + + if (device->devType() == QInternal::CustomRaster) + dfbDevice = static_cast<QDirectFBPaintDevice*>(device); + else if (device->devType() == QInternal::Pixmap) { + QPixmapData *data = static_cast<QPixmap*>(device)->pixmapData(); + if (data->classId() == QPixmapData::DirectFBClass) { + QDirectFBPixmapData* dfbPixmapData = static_cast<QDirectFBPixmapData*>(data); + dfbDevice = static_cast<QDirectFBPaintDevice*>(dfbPixmapData); + } + } + + if (dfbDevice) + surface = dfbDevice->directFbSurface(); + + if (!surface) { + qFatal("QDirectFBPaintEngine used on an invalid device: 0x%x", + device->devType()); + } + + surface->GetSize(surface, &fbWidth, &fbHeight); + + setTransform(QTransform()); + antialiased = false; + drawFlags = DSDRAW_BLEND; + blitFlags = DSBLIT_BLEND_ALPHACHANNEL; + duffFlags = DSPD_SRC_OVER; + opacity = 255; + dirtyFlags = true; + dirtyClip = true; + setPen(q->state()->pen); + setDFBColor(pen.color()); +} + +void QDirectFBPaintEnginePrivate::end() +{ + surface->ReleaseSource(surface); + surface->SetClip(surface, NULL); + surface = 0; +} + +void QDirectFBPaintEnginePrivate::setPen(const QPen &p) +{ + pen = p; + simplePen = (pen.style() == Qt::NoPen) || + (pen.style() == Qt::SolidLine && !antialiased + && (pen.widthF() <= 1 && !matrixScale)); +} + +void QDirectFBPaintEnginePrivate::setBrush(const QBrush &b) +{ + // TODO: accelerate texture pattern + brush = b; + simpleBrush = (brush.style() == Qt::NoBrush) || + (brush.style() == Qt::SolidPattern && !antialiased); +} + +void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode mode) +{ + drawFlags &= ~(DSDRAW_XOR); + blitFlags &= ~(DSBLIT_XOR); + + // TODO: check these mappings!!!! + quint32 duff = DSPD_NONE; + quint32 blit = blitFlags; + + switch (mode) { + case QPainter::CompositionMode_SourceOver: + duff = DSPD_SRC_OVER; + blit |= DSBLIT_BLEND_ALPHACHANNEL; + break; + case QPainter::CompositionMode_DestinationOver: + duff = DSPD_DST_OVER; + blit |= DSBLIT_BLEND_ALPHACHANNEL; + break; + case QPainter::CompositionMode_Clear: + duff = DSPD_CLEAR; + blit &= ~DSBLIT_BLEND_ALPHACHANNEL; + break; + case QPainter::CompositionMode_Source: + duff = DSPD_SRC; + blit &= ~DSBLIT_BLEND_ALPHACHANNEL; + break; + case QPainter::CompositionMode_Destination: + blit &= ~DSBLIT_BLEND_ALPHACHANNEL; + return; + case QPainter::CompositionMode_SourceIn: + duff = DSPD_SRC_IN; + blit |= DSBLIT_BLEND_ALPHACHANNEL; + break; + case QPainter::CompositionMode_DestinationIn: + duff = DSPD_DST_IN; + blit |= DSBLIT_BLEND_ALPHACHANNEL; + break; + case QPainter::CompositionMode_SourceOut: + duff = DSPD_SRC_OUT; + blit |= DSBLIT_BLEND_ALPHACHANNEL; + break; + case QPainter::CompositionMode_DestinationOut: + duff = DSPD_DST_OUT; + blit |= DSBLIT_BLEND_ALPHACHANNEL; + break; + case QPainter::CompositionMode_SourceAtop: + duff = DSPD_SRC_OVER; + blit |= DSBLIT_BLEND_ALPHACHANNEL; + break; + case QPainter::CompositionMode_DestinationAtop: + duff = DSPD_DST_OVER; + break; + case QPainter::CompositionMode_Xor: + duff = DSPD_NONE; + blit |= DSBLIT_BLEND_ALPHACHANNEL; + drawFlags |= DSDRAW_XOR; + blit |= DSBLIT_XOR; + dirtyFlags = true; + break; + default: + qWarning("QDirectFBPaintEnginePrivate::setCompositionMode(): " + "mode %d not implemented", mode); + break; + } + + if (duff != duffFlags || blit != blitFlags) { + duffFlags = duff; + blitFlags = blit; + dirtyFlags = true; + } +} + +void QDirectFBPaintEnginePrivate::setOpacity(const qreal value) +{ + const bool wasOpaque = (opacity == 255); + opacity = quint8(value * 255); + const bool opaque = (opacity == 255); + + if (opaque == wasOpaque) + return; + + if (opaque) + blitFlags &= ~(DSBLIT_BLEND_COLORALPHA | DSBLIT_SRC_PREMULTCOLOR); + else + blitFlags |= (DSBLIT_BLEND_COLORALPHA | DSBLIT_SRC_PREMULTCOLOR); + + dirtyFlags = true; +} + +void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints) +{ + const bool old = antialiased; + antialiased = bool(hints & QPainter::Antialiasing); + if (old != antialiased) { + setPen(q->state()->pen); + } +} + +void QDirectFBPaintEnginePrivate::updateFlags() +{ + if (!dirtyFlags) + return; + surface->SetDrawingFlags(surface, DFBSurfaceDrawingFlags(drawFlags)); + surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(blitFlags)); + surface->SetPorterDuff(surface, DFBSurfacePorterDuffRule(duffFlags)); + dirtyFlags = false; +} + +void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color) const +{ + const quint8 alpha = (opacity == 255 ? + color.alpha() : ALPHA_MUL(color.alpha(), opacity)); + surface->SetColor(surface, + color.red(), color.green(), color.blue(), alpha); +} + +void QDirectFBPaintEnginePrivate::drawLines(const QLine *lines, int n) const +{ + QVarLengthArray<DFBRegion> regions(n); + + for (int i = 0; i < n; ++i) { + const QLine l = transform.map(lines[i]); + + // TODO: clip! + + regions[i].x1 = l.x1(); + regions[i].y1 = l.y1(); + regions[i].x2 = l.x2(); + regions[i].y2 = l.y2(); + } + surface->DrawLines(surface, regions.data(), n); +} + +void QDirectFBPaintEnginePrivate::drawLines(const QLineF *lines, int n) const +{ + QVarLengthArray<DFBRegion> regions(n); + + for (int i = 0; i < n; ++i) { + const QLine l = transform.map(lines[i]).toLine(); + + // TODO: clip! + + regions[i].x1 = l.x1(); + regions[i].y1 = l.y1(); + regions[i].x2 = l.x2(); + regions[i].y2 = l.y2(); + } + surface->DrawLines(surface, regions.data(), n); +} + +/* ### Commented out until it can be implemented properly using raster's QClipData +QRegion QDirectFBPaintEnginePrivate::rectsToClippedRegion(const QRect *rects, + int n) const +{ + QRegion region; + + for (int i = 0; i < n; ++i) { + const QRect r = ::mapRect(transform, rects[i]); + region += clip & r; + } + + return region; +} + +QRegion QDirectFBPaintEnginePrivate::rectsToClippedRegion(const QRectF *rects, + int n) const +{ + QRegion region; + + for (int i = 0; i < n; ++i) { + const QRect r = ::mapRect(transform, rects[i]); + region += clip & r; + } + + return region; +} +*/ + +void QDirectFBPaintEnginePrivate::fillRegion(const QRegion ®ion) const +{ + const QVector<QRect> rects = region.rects(); + const int n = rects.size(); + QVarLengthArray<DFBRectangle> dfbRects(n); + + for (int i = 0; i < n; ++i) { + const QRect r = rects.at(i); + dfbRects[i].x = r.x(); + dfbRects[i].y = r.y(); + dfbRects[i].w = r.width(); + dfbRects[i].h = r.height(); + + } + surface->FillRectangles(surface, dfbRects.data(), n); +} + +void QDirectFBPaintEnginePrivate::fillRects(const QRect *rects, int n) const +{ + QVarLengthArray<DFBRectangle> dfbRects(n); + for (int i = 0; i < n; ++i) { + const QRect r = ::mapRect(transform, rects[i]); + dfbRects[i].x = r.x(); + dfbRects[i].y = r.y(); + dfbRects[i].w = r.width(); + dfbRects[i].h = r.height(); + } + surface->FillRectangles(surface, dfbRects.data(), n); +} + +void QDirectFBPaintEnginePrivate::fillRects(const QRectF *rects, int n) const +{ + QVarLengthArray<DFBRectangle> dfbRects(n); + for (int i = 0; i < n; ++i) { + const QRect r = ::mapRect(transform, rects[i]); + dfbRects[i].x = r.x(); + dfbRects[i].y = r.y(); + dfbRects[i].w = r.width(); + dfbRects[i].h = r.height(); + } + surface->FillRectangles(surface, dfbRects.data(), n); +} + +void QDirectFBPaintEnginePrivate::drawRects(const QRect *rects, int n) const +{ + for (int i = 0; i < n; ++i) { + const QRect r = ::mapRect(transform, rects[i]); + surface->DrawRectangle(surface, r.x(), r.y(), + r.width() + 1, r.height() + 1); + } +} + +void QDirectFBPaintEnginePrivate::drawRects(const QRectF *rects, int n) const +{ + for (int i = 0; i < n; ++i) { + const QRect r = ::mapRect(transform, rects[i]); + surface->DrawRectangle(surface, r.x(), r.y(), + r.width() + 1, r.height() + 1); + } +} + +void QDirectFBPaintEnginePrivate::drawPixmap(const QRectF &dest, + const QPixmap &pixmap, + const QRectF &src) +{ + surface->SetColor(surface, 0xff, 0xff, 0xff, opacity); + + const bool changeFlags = !pixmap.hasAlphaChannel() + && (blitFlags & DSBLIT_BLEND_ALPHACHANNEL); + if (changeFlags) { + quint32 flags = blitFlags & ~DSBLIT_BLEND_ALPHACHANNEL; + surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(flags)); + } + + QPixmapData *data = pixmap.pixmapData(); + Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); + QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); + IDirectFBSurface *s = dfbData->directFbSurface(); + const QRect sr = src.toRect(); + const QRect dr = ::mapRect(transform, dest); + 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 { + 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); + if (changeFlags) + surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(blitFlags)); +} + +void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, + const QPixmap &pixmap) +{ + surface->SetColor(surface, 0xff, 0xff, 0xff, opacity); + + const bool changeFlags = !pixmap.hasAlphaChannel() + && (blitFlags & DSBLIT_BLEND_ALPHACHANNEL); + if (changeFlags) { + quint32 flags = blitFlags & ~DSBLIT_BLEND_ALPHACHANNEL; + surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(flags)); + } + + QPixmapData *data = pixmap.pixmapData(); + Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); + QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); + IDirectFBSurface *s = dfbData->directFbSurface(); + const QRect dr = ::mapRect(transform, dest); + DFBResult result = DFB_OK; + + if (!matrixScale && dr == QRect(0, 0, fbWidth, fbHeight)) { + result = surface->TileBlit(surface, s, 0, 0, 0); + } else if (!matrixScale) { + const int dx = pixmap.width(); + const int dy = pixmap.height(); + const DFBRectangle rect = { 0, 0, dx, dy }; + QVarLengthArray<DFBRectangle> rects; + QVarLengthArray<DFBPoint> points; + + for (int y = dr.y(); y <= dr.bottom(); y += dy) { + for (int x = dr.x(); x <= dr.right(); x += dx) { + rects.append(rect); + const DFBPoint point = { x, y }; + points.append(point); + } + } + result = surface->BatchBlit(surface, s, rects.constData(), + points.constData(), points.size()); + } else { + const QRect sr = ::mapRect(transform, QRect(0, 0, pixmap.width(), pixmap.height())); + const int dx = sr.width(); + const int dy = sr.height(); + const DFBRectangle sRect = { 0, 0, dx, dy }; + + for (int y = dr.y(); y <= dr.bottom(); y += dy) { + for (int x = dr.x(); x <= dr.right(); x += dx) { + const DFBRectangle dRect = { x, y, dx, dy }; + result = surface->StretchBlit(surface, s, &sRect, &dRect); + if (result != DFB_OK) { + y = dr.bottom() + 1; + break; + } + } + } + } + + if (result != DFB_OK) + DirectFBError("QDirectFBPaintEngine::drawTiledPixmap()", result); + + if (changeFlags) + surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(blitFlags)); +} + +void QDirectFBPaintEnginePrivate::drawImage(const QRectF &dest, + const QImage &srcImage, + const QRectF &src) +{ + QImage image = srcImage; + if (QDirectFBScreen::getSurfacePixelFormat(image) == DSPF_UNKNOWN) { + QImage::Format format; + if (image.hasAlphaChannel()) + format = QImage::Format_ARGB32_Premultiplied; + else + format = QImage::Format_RGB32; + image = image.convertToFormat(format); + } + + CachedImage *img = imageCache[image.cacheKey()]; + IDirectFBSurface *imgSurface = 0; + bool doRelease = false; + + if (img) { + imgSurface = img->surface(); + } else { + const int cost = image.width() * image.height() * image.depth() / 8; + if (cost <= imageCache.maxCost()) { + img = new CachedImage(image); + imgSurface = img->surface(); + if (imgSurface) { + imageCache.insert(image.cacheKey(), img, cost); + } else { + delete img; + img = 0; + } + } + + if (!imgSurface) { + DFBSurfaceDescription description; + + description = QDirectFBScreen::getSurfaceDescription(image); + imgSurface = QDirectFBScreen::instance()->createDFBSurface(&description); + if (!imgSurface) { + qWarning("QDirectFBPaintEnginePrivate::drawImage"); + return; + } + +#ifndef QT_NO_DIRECTFB_PALETTE + QDirectFBScreen::setSurfaceColorTable(surface, image); +#endif + doRelease = (imgSurface != 0); + } + } + + const QRect sr = src.toRect(); + const QRect dr = ::mapRect(transform, dest); + const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() }; + + surface->SetColor(surface, 0xff, 0xff, 0xff, opacity); + + const bool changeFlags = !image.hasAlphaChannel() + && (blitFlags & DSBLIT_BLEND_ALPHACHANNEL); + if (changeFlags) { + quint32 flags = blitFlags & ~DSBLIT_BLEND_ALPHACHANNEL; + surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(flags)); + } + if (dr.size() == sr.size()) { + surface->Blit(surface, imgSurface, &sRect, dr.x(), dr.y()); + } else { + const DFBRectangle dRect = { dr.x(), dr.y(), + dr.width(), dr.height() }; + surface->StretchBlit(surface, imgSurface, &sRect, &dRect); + } + if (changeFlags) + surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(blitFlags)); + if (doRelease) + QDirectFBScreen::instance()->releaseDFBSurface(imgSurface); +} + +void QDirectFBPaintEnginePrivate::updateClip() +{ + if (!dirtyClip) + return; + + if (!clip() || !clip()->enabled) { + surface->SetClip(surface, NULL); + dfbHandledClip = true; + } + else if (clip()->hasRectClip) { + const DFBRegion r = { + clip()->clipRect.x(), + clip()->clipRect.y(), + clip()->clipRect.x() + clip()->clipRect.width(), + clip()->clipRect.y() + clip()->clipRect.height() + }; + surface->SetClip(surface, &r); + + dfbHandledClip = true; + } + else + dfbHandledClip = false; + + dirtyClip = false; +} + +void QDirectFBPaintEnginePrivate::systemStateChanged() +{ + setClipDirty(); + QRasterPaintEnginePrivate::systemStateChanged(); +} + +QDirectFBPaintEngine::QDirectFBPaintEngine(QPaintDevice *device) + : QRasterPaintEngine(*(new QDirectFBPaintEnginePrivate(this)), device) +{ +} + +QDirectFBPaintEngine::~QDirectFBPaintEngine() +{ +} + +bool QDirectFBPaintEngine::begin(QPaintDevice *device) +{ + Q_D(QDirectFBPaintEngine); + d->begin(device); + const bool status = QRasterPaintEngine::begin(device); + + // XXX: QRasterPaintEngine::begin() resets the capabilities + gccaps |= PorterDuff; + + return status; +} + +bool QDirectFBPaintEngine::end() +{ + Q_D(QDirectFBPaintEngine); + d->end(); + return QRasterPaintEngine::end(); +} + + + +void QDirectFBPaintEngine::clipEnabledChanged() +{ + Q_D(QDirectFBPaintEngine); + d->setClipDirty(); + QRasterPaintEngine::clipEnabledChanged(); +} + +void QDirectFBPaintEngine::penChanged() +{ + Q_D(QDirectFBPaintEngine); + d->setPen(state()->pen); + + QRasterPaintEngine::penChanged(); +} + +void QDirectFBPaintEngine::brushChanged() +{ + Q_D(QDirectFBPaintEngine); + d->setBrush(state()->brush); + + QRasterPaintEngine::brushChanged(); +} + +void QDirectFBPaintEngine::opacityChanged() +{ + Q_D(QDirectFBPaintEngine); + d->setOpacity(state()->opacity); + + 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); + const bool old = d->matrixScale; + d->setTransform(state()->transform()); + if (d->matrixScale != old) { + d->setPen(state()->pen); + } + QRasterPaintEngine::transformChanged(); +} + +void QDirectFBPaintEngine::setState(QPainterState *s) +{ + Q_D(QDirectFBPaintEngine); + QRasterPaintEngine::setState(s); + if (d->surface) + d->updateClip(); + d->setPen(state()->pen); + d->setBrush(state()->brush); + d->setOpacity(state()->opacity); + d->setCompositionMode(state()->compositionMode()); + d->setTransform(state()->transform()); +} + +void QDirectFBPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) +{ + Q_D(QDirectFBPaintEngine); + d->setClipDirty(); + QRasterPaintEngine::clip(path, op); +} + +void QDirectFBPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) +{ + Q_D(QDirectFBPaintEngine); + d->setClipDirty(); + QRasterPaintEngine::clip(rect, op); +} + + +void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount) +{ + Q_D(QDirectFBPaintEngine); + d->updateClip(); + if (!d->dfbCanHandleClip() || d->matrixRotShear || !d->simpleBrush || !d->simplePen) { + d->lock(); + QRasterPaintEngine::drawRects(rects, rectCount); + return; + } + + d->unlock(); + + if (d->brush != Qt::NoBrush) { + d->updateFlags(); + d->setDFBColor(d->brush.color()); + d->fillRects(rects, rectCount); + } + if (d->pen != Qt::NoPen) { + d->updateFlags(); + d->setDFBColor(d->pen.color()); + d->drawRects(rects, rectCount); + } +} + +void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount) +{ + Q_D(QDirectFBPaintEngine); + d->updateClip(); + if (!d->dfbCanHandleClip() || d->matrixRotShear || !d->simpleBrush || !d->simplePen) { + d->lock(); + QRasterPaintEngine::drawRects(rects, rectCount); + return; + } + + d->unlock(); + + if (d->brush != Qt::NoBrush) { + d->updateFlags(); + d->setDFBColor(d->brush.color()); + d->fillRects(rects, rectCount); + } + if (d->pen != Qt::NoPen) { + d->updateFlags(); + d->setDFBColor(d->pen.color()); + d->drawRects(rects, rectCount); + } +} + +void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount) +{ + Q_D(QDirectFBPaintEngine); + d->updateClip(); + if (!d->simplePen || !d->dfbCanHandleClip()) { + d->lock(); + QRasterPaintEngine::drawLines(lines, lineCount); + return; + } + + if (d->pen != Qt::NoPen) { + d->unlock(); + d->updateFlags(); + d->setDFBColor(d->pen.color()); + d->drawLines(lines, lineCount); + } +} + +void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount) +{ + Q_D(QDirectFBPaintEngine); + d->updateClip(); + if (!d->simplePen || !d->dfbCanHandleClip()) { + d->lock(); + QRasterPaintEngine::drawLines(lines, lineCount); + return; + } + + if (d->pen != Qt::NoPen) { + d->unlock(); + d->updateFlags(); + d->setDFBColor(d->pen.color()); + d->drawLines(lines, lineCount); + } +} + +void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, + const QRectF &sr, + Qt::ImageConversionFlags flags) +{ + Q_D(QDirectFBPaintEngine); + Q_UNUSED(flags); // XXX + +#ifndef QT_NO_DIRECTFB_PREALLOCATED + d->updateClip(); + if (!d->dfbCanHandleClip(r) || d->matrixRotShear) +#endif + { + d->lock(); + QRasterPaintEngine::drawImage(r, image, sr, flags); + return; + } + +#ifndef QT_NO_DIRECTFB_PREALLOCATED + d->unlock(); + d->updateFlags(); + d->drawImage(r, image, sr); +#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); + d->updateClip(); + + if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) { + d->lock(); + QRasterPaintEngine::drawPixmap(r, pixmap, sr); + } + else if (!d->dfbCanHandleClip(r) || d->matrixRotShear) { + const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(); + d->lock(); + QRasterPaintEngine::drawImage(r, *img, sr); + } + else { + d->unlock(); + d->updateFlags(); + d->drawPixmap(r, pixmap, 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 &sp) +{ + Q_D(QDirectFBPaintEngine); + d->updateClip(); + if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) { + d->lock(); + QRasterPaintEngine::drawTiledPixmap(r, pixmap, sp); + } + else if (!d->dfbCanHandleClip(r) || d->matrixRotShear || !sp.isNull()) { + QImage* img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(); + QRasterPixmapData *data = new QRasterPixmapData(QPixmapData::PixmapType); + data->fromImage(*img, Qt::AutoColor); + const QPixmap pix(data); + d->lock(); + QRasterPaintEngine::drawTiledPixmap(r, pix, sp); + } + else { + d->unlock(); + d->updateFlags(); + d->drawTiledPixmap(r, pixmap); + } +} + + +void QDirectFBPaintEngine::stroke(const QVectorPath &path, const QPen &pen) +{ + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::stroke(path, pen); +} + +void QDirectFBPaintEngine::drawPath(const QPainterPath &path) +{ + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawPath(path); +} + +void QDirectFBPaintEngine::drawPoints(const QPointF *points, int pointCount) +{ + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawPoints(points, pointCount); +} + +void QDirectFBPaintEngine::drawPoints(const QPoint *points, int pointCount) +{ + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawPoints(points, pointCount); +} + +void QDirectFBPaintEngine::drawEllipse(const QRectF &rect) +{ + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawEllipse(rect); +} + +void QDirectFBPaintEngine::drawPolygon(const QPointF *points, int pointCount, + PolygonDrawMode mode) +{ + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawPolygon(points, pointCount, mode); +} + +void QDirectFBPaintEngine::drawPolygon(const QPoint *points, int pointCount, + PolygonDrawMode mode) +{ + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawPolygon(points, pointCount, mode); +} + +void QDirectFBPaintEngine::drawTextItem(const QPointF &p, + const QTextItem &textItem) +{ + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawTextItem(p, textItem); +} + +void QDirectFBPaintEngine::fill(const QVectorPath &path, const QBrush &brush) +{ + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::fill(path, brush); +} + +void QDirectFBPaintEngine::fillRect(const QRectF &r, const QBrush &brush) +{ + Q_D(QDirectFBPaintEngine); + if (brush.style() != Qt::SolidPattern) { + d->lock(); + QRasterPaintEngine::fillRect(r, brush); + } + else + fillRect(r, brush.color()); +} + +void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color) +{ + Q_D(QDirectFBPaintEngine); + d->updateClip(); + if (!d->dfbCanHandleClip() || d->matrixRotShear) { + d->lock(); + QRasterPaintEngine::fillRect(rect, color); + } else { + d->unlock(); + d->updateFlags(); + d->setDFBColor(color); + d->fillRects(&rect, 1); + } +} + + + + + + + +void QDirectFBPaintEngine::drawColorSpans(const QSpan *spans, int count, + uint color) +{ + Q_D(QDirectFBPaintEngine); + color = INV_PREMUL(color); + + QVarLengthArray<DFBRegion> lines(count); + int j = 0; + for (int i = 0; i < count; ++i) { + if (spans[i].coverage == 255) { + lines[j].x1 = spans[i].x; + lines[j].y1 = spans[i].y; + lines[j].x2 = spans[i].x + spans[i].len - 1; + lines[j].y2 = spans[i].y; + ++j; + } else { + DFBSpan span = { spans[i].x, spans[i].len }; + uint c = BYTE_MUL(color, spans[i].coverage); + d->surface->SetColor(d->surface, + qRed(c), qGreen(c), qBlue(c), qAlpha(c)); + d->surface->FillSpans(d->surface, spans[i].y, &span, 1); + } + } + if (j > 0) { + d->surface->SetColor(d->surface, + qRed(color), qGreen(color), qBlue(color), + qAlpha(color)); + d->surface->DrawLines(d->surface, lines.data(), j); + } +} + +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); + src->SetColor(src, 0, 0, 0, const_alpha); + const DFBRectangle rect = { 0, 0, length, 1 }; + d->surface->Blit(d->surface, src, &rect, x, y); +} + +#endif // QT_NO_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h new file mode 100644 index 0000000..3c2cefa --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTENGINE_DIRECTFB_P_H +#define QPAINTENGINE_DIRECTFB_P_H + +#include <QtGui/qpaintengine.h> +#include <private/qpaintengine_raster_p.h> + +QT_BEGIN_HEADER + +QT_MODULE(Gui) + +class QDirectFBPaintEnginePrivate; + +class QDirectFBPaintEngine : public QRasterPaintEngine +{ + Q_DECLARE_PRIVATE(QDirectFBPaintEngine) +public: + QDirectFBPaintEngine(QPaintDevice *device); + ~QDirectFBPaintEngine(); + + bool begin(QPaintDevice *device); + bool end(); + + void drawRects(const QRect *rects, int rectCount); + void drawRects(const QRectF *rects, int rectCount); + + void fillRect(const QRectF &r, const QBrush &brush); + void fillRect(const QRectF &r, const QColor &color); + + void drawLines(const QLine *line, int lineCount); + void drawLines(const QLineF *line, int lineCount); + + void drawImage(const QPointF &p, const QImage &img); + void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, + Qt::ImageConversionFlags falgs = Qt::AutoColor); + + void drawPixmap(const QPointF &p, const QPixmap &pm); + void drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr); + void drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr); + + void drawColorSpans(const QSpan *spans, int count, uint color); + void drawBufferSpan(const uint *buffer, int bufsize, + int x, int y, int length, uint const_alpha); + + + // The following methods simply lock the surface & call the base implementation + void stroke(const QVectorPath &path, const QPen &pen); + void drawPath(const QPainterPath &path); + void drawPoints(const QPointF *points, int pointCount); + void drawPoints(const QPoint *points, int pointCount); + void drawEllipse(const QRectF &rect); + void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); + void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode); + void drawTextItem(const QPointF &p, const QTextItem &textItem); + void fill(const QVectorPath &path, const QBrush &brush); + + virtual void clipEnabledChanged(); + virtual void penChanged(); + virtual void brushChanged(); + 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 QRect &rect, Qt::ClipOperation op); + +}; + +QT_END_HEADER + +#endif // QPAINTENGINE_DIRECTFB_P_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp new file mode 100644 index 0000000..6352652 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -0,0 +1,363 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbpixmap.h" + +#include "qdirectfbscreen.h" +#include "qdirectfbpaintengine.h" + +#include <QtGui/qbitmap.h> +#include <directfb.h> + +static int global_ser_no = 0; + +QDirectFBPixmapData::QDirectFBPixmapData(PixelType pixelType) + : QPixmapData(pixelType, DirectFBClass), + engine(0) +{ + setSerialNumber(0); +} + +QDirectFBPixmapData::~QDirectFBPixmapData() +{ + unlockDirectFB(); + if (dfbSurface && QDirectFBScreen::instance()) + screen->releaseDFBSurface(dfbSurface); + delete engine; +} + +void QDirectFBPixmapData::resize(int width, int height) +{ + if (width <= 0 || height <= 0) { + setSerialNumber(0); + return; + } + + DFBSurfaceDescription description; + description.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | + DSDESC_HEIGHT); + description.width = width; + description.height = height; + + dfbSurface = screen->createDFBSurface(&description); + if (!dfbSurface) + qCritical("QDirectFBPixmapData::resize(): Unable to allocate surface"); + + setSerialNumber(++global_ser_no); +} + +void QDirectFBPixmapData::fromImage(const QImage &img, + Qt::ImageConversionFlags) +{ + QImage image; + if (QDirectFBScreen::getSurfacePixelFormat(img) == DSPF_UNKNOWN) + image = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); + else + image = img; + + DFBSurfaceDescription description; + description = QDirectFBScreen::getSurfaceDescription(image); + +#ifndef QT_NO_DIRECTFB_PREALLOCATED + IDirectFBSurface *imgSurface; + imgSurface = screen->createDFBSurface(&description); + if (!imgSurface) { + qWarning("QDirectFBPixmapData::fromImage()"); + setSerialNumber(0); + return; + } +#ifndef QT_NO_DIRECTFB_PALETTE + QDirectFBScreen::setSurfaceColorTable(imgSurface, image); +#endif +#endif // QT_NO_DIRECTFB_PREALLOCATED + + description.flags = DFBSurfaceDescriptionFlags(description.flags + & ~DSDESC_PREALLOCATED); + dfbSurface = screen->createDFBSurface(&description); + if (!dfbSurface) { + qWarning("QDirectFBPixmapData::fromImage()"); + setSerialNumber(0); + return; + } + +#ifndef QT_NO_DIRECTFB_PALETTE + QDirectFBScreen::setSurfaceColorTable(dfbSurface, image); +#endif + +#ifdef QT_NO_DIRECTFB_PREALLOCATED + char *mem; + surface->Lock(surface, DSLF_WRITE, (void**)&mem, &bpl); + const int w = image.width() * image.depth() / 8; + for (int i = 0; i < image.height(); ++i) { + memcpy(mem, image.scanLine(i), w); + mem += bpl; + } + surface->Unlock(surface); +#else + DFBResult result; + dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); + result = dfbSurface->Blit(dfbSurface, imgSurface, 0, 0, 0); + if (result != DFB_OK) + DirectFBError("QDirectFBPixmapData::fromImage()", result); + dfbSurface->Flip(dfbSurface, 0, DSFLIP_NONE); + dfbSurface->ReleaseSource(dfbSurface); + screen->releaseDFBSurface(imgSurface); +#endif // QT_NO_DIRECTFB_PREALLOCATED + + setSerialNumber(++global_ser_no); +} + +void QDirectFBPixmapData::copy(const QPixmapData *data, const QRect &rect) +{ + if (data->classId() != DirectFBClass) { + QPixmapData::copy(data, rect); + return; + } + + IDirectFBSurface *src = static_cast<const QDirectFBPixmapData*>(data)->directFbSurface(); + + DFBSurfaceDescription description; + description.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | + DSDESC_HEIGHT | + DSDESC_PIXELFORMAT); + description.width = rect.width(); + description.height = rect.height(); + src->GetPixelFormat(src, &description.pixelformat); + + dfbSurface = screen->createDFBSurface(&description); + if (!dfbSurface) { + qWarning("QDirectFBPixmapData::copy()"); + setSerialNumber(0); + return; + } + + DFBResult result; +#ifndef QT_NO_DIRECTFB_PALETTE + IDirectFBPalette *palette; + result = src->GetPalette(src, &palette); + if (result == DFB_OK) { + dfbSurface->SetPalette(dfbSurface, palette); + palette->Release(palette); + } +#endif + + dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); + const DFBRectangle blitRect = { rect.x(), rect.y(), + rect.width(), rect.height() }; + result = dfbSurface->Blit(dfbSurface, src, &blitRect, 0, 0); + if (result != DFB_OK) + DirectFBError("QDirectFBPixmapData::copy()", result); + + setSerialNumber(++global_ser_no); +} + + +void QDirectFBPixmapData::fill(const QColor &color) +{ + if (!serialNumber()) + return; + + Q_ASSERT(dfbSurface); + + if (color.alpha() < 255 && !hasAlphaChannel()) { + // convert to surface supporting alpha channel + DFBSurfacePixelFormat format; + dfbSurface->GetPixelFormat(dfbSurface, &format); + switch (format) { + case DSPF_YUY2: + case DSPF_UYVY: + format = DSPF_AYUV; + break; +#if (Q_DIRECTFB_VERSION >= 0x010100) + case DSPF_RGB444: + format = DSPF_ARGB4444; + break; + case DSPF_RGB555: +#endif + case DSPF_RGB18: + format = DSPF_ARGB6666; + break; + default: + format = DSPF_ARGB; + break; + } + + DFBSurfaceDescription description; + description.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | + DSDESC_HEIGHT | + DSDESC_PIXELFORMAT); + dfbSurface->GetSize(dfbSurface, &description.width, &description.height); + description.pixelformat = format; + screen->releaseDFBSurface(dfbSurface); // release old surface + + dfbSurface = screen->createDFBSurface(&description); + if (!dfbSurface) { + qWarning("QDirectFBPixmapData::fill()"); + setSerialNumber(0); + return; + } + } + + dfbSurface->Clear(dfbSurface, color.red(), color.green(), color.blue(), + color.alpha()); +} + +bool QDirectFBPixmapData::hasAlphaChannel() const +{ + if (!serialNumber()) + return false; + + DFBSurfacePixelFormat format; + dfbSurface->GetPixelFormat(dfbSurface, &format); + switch (format) { + case DSPF_ARGB1555: + case DSPF_ARGB: + case DSPF_LUT8: + case DSPF_AiRGB: + case DSPF_A1: + case DSPF_ARGB2554: + case DSPF_ARGB4444: + case DSPF_AYUV: + case DSPF_A4: + case DSPF_ARGB1666: + case DSPF_ARGB6666: + case DSPF_LUT2: + return true; + default: + return false; + } +} + +QPixmap QDirectFBPixmapData::transformed(const QTransform &transform, + Qt::TransformationMode mode) const +{ + if (!dfbSurface || transform.type() != QTransform::TxScale + || mode != Qt::FastTransformation) + { + QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); + const QImage *image = that->buffer(); + if (image) { // avoid deep copy + const QImage transformed = image->transformed(transform, mode); + that->unlockDirectFB(); + QDirectFBPixmapData *data = new QDirectFBPixmapData(pixelType()); + data->fromImage(transformed, Qt::AutoColor); + return QPixmap(data); + } + return QPixmapData::transformed(transform, mode); + } + + int w, h; + dfbSurface->GetSize(dfbSurface, &w, &h); + + const QSize size = transform.mapRect(QRect(0, 0, w, h)).size(); + if (size.isEmpty()) + return QPixmap(); + + QDirectFBPixmapData *data = new QDirectFBPixmapData(pixelType()); + data->resize(size.width(), size.height()); + + IDirectFBSurface *dest = data->dfbSurface; + dest->SetBlittingFlags(dest, DSBLIT_NOFX); + + const DFBRectangle srcRect = { 0, 0, w, h }; + const DFBRectangle destRect = { 0, 0, size.width(), size.height() }; + dest->StretchBlit(dest, dfbSurface, &srcRect, &destRect); + + return QPixmap(data); +} + +QImage QDirectFBPixmapData::toImage() const +{ + if (!dfbSurface) + return QImage(); + +#ifdef QT_NO_DIRECTFB_PREALLOCATED + QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); + const QImage *img = that->buffer(); + const QImage copied = img->copy(); + that->unlockDirectFB(); + return copied; +#else + + int w, h; + dfbSurface->GetSize(dfbSurface, &w, &h); + + // Always convert to ARGB32: + QImage image(w, h, QImage::Format_ARGB32); + + DFBSurfaceDescription description; + description = QDirectFBScreen::getSurfaceDescription(image); + + IDirectFBSurface *imgSurface = screen->createDFBSurface(&description); + if (!imgSurface) { + qWarning("QDirectFBPixmapData::toImage()"); + return QImage(); + } + + imgSurface->SetBlittingFlags(imgSurface, DSBLIT_NOFX); + DFBResult result = imgSurface->Blit(imgSurface, dfbSurface, 0, 0, 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBPixmapData::toImage() blit failed", result); + return QImage(); + } + screen->releaseDFBSurface(imgSurface); + + return image; +#endif // QT_NO_DIRECTFB_PREALLOCATED +} + +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() +{ + lockDirectFB(); + return lockedImage; +} diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h new file mode 100644 index 0000000..32676f8 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTFBPIXMAP_H +#define QDIRECTFBPIXMAP_H + +#include <QtGui/private/qpixmapdata_p.h> +#include <QtGui/private/qpaintengine_raster_p.h> +#include "qdirectfbpaintdevice.h" +#include <directfb.h> + +QT_BEGIN_HEADER + +QT_MODULE(Gui) + +class QDirectFBPaintEngine; + +class QDirectFBPixmapData : public QPixmapData, public QDirectFBPaintDevice +{ +public: + QDirectFBPixmapData(PixelType pixelType); + ~QDirectFBPixmapData(); + + // Re-implemented from QPixmapData: + void resize(int width, int height); + void fromImage(const QImage &image, Qt::ImageConversionFlags flags); + void copy(const QPixmapData *data, const QRect &rect); + void fill(const QColor &color); + bool hasAlphaChannel() const; + QPixmap transformed(const QTransform &matrix, + Qt::TransformationMode mode) const; + QImage toImage() const; + QPaintEngine* paintEngine() const; + QImage *buffer(); + + // Pure virtual in QPixmapData, so re-implement here and delegate to QDirectFBPaintDevice + int metric(QPaintDevice::PaintDeviceMetric m) const {return QDirectFBPaintDevice::metric(m);} + +private: + QDirectFBPaintEngine *engine; +}; + +QT_END_HEADER + +#endif // QDIRECTFBPIXMAP_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp new file mode 100644 index 0000000..3249e65 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp @@ -0,0 +1,1064 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbscreen.h" +#include "qdirectfbsurface.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> + +class QDirectFBScreenPrivate : public QObject, public QWSGraphicsSystem +{ +public: + QDirectFBScreenPrivate(QDirectFBScreen*); + ~QDirectFBScreenPrivate(); + + void setFlipFlags(const QStringList &args); + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + + IDirectFB *dfb; + IDirectFBSurface *dfbSurface; + DFBSurfaceFlipFlags flipFlags; +#ifndef QT_NO_DIRECTFB_LAYER + IDirectFBDisplayLayer *dfbLayer; +#endif + IDirectFBScreen *dfbScreen; + QRegion prevExpose; + + QSet<IDirectFBSurface*> allocatedSurfaces; + +#ifndef QT_NO_DIRECTFB_MOUSE + QDirectFBMouseHandler *mouse; +#endif +#ifndef QT_NO_DIRECTFB_KEYBOARD + QDirectFBKeyboardHandler *keyboard; +#endif + bool videoonly; +}; + +QDirectFBScreenPrivate::QDirectFBScreenPrivate(QDirectFBScreen* screen) + : QWSGraphicsSystem(screen), dfb(0), dfbSurface(0), flipFlags(DSFLIP_BLIT) +#ifndef QT_NO_DIRECTFB_LAYER + , dfbLayer(0) +#endif +#ifndef QT_NO_DIRECTFB_MOUSE + , mouse(0) +#endif +#ifndef QT_NO_DIRECTFB_KEYBOARD + , keyboard(0) +#endif + , videoonly(false) +{ +#ifndef QT_NO_QWS_SIGNALHANDLER + QWSSignalHandler::instance()->addObject(this); +#endif +} + +QDirectFBScreenPrivate::~QDirectFBScreenPrivate() +{ +#ifndef QT_NO_DIRECTFB_MOUSE + delete mouse; +#endif +#ifndef QT_NO_DIRECTFB_KEYBOARD + delete keyboard; +#endif + + foreach (IDirectFBSurface* surf, allocatedSurfaces) + surf->Release(surf); + allocatedSurfaces.clear(); + + if (dfbSurface) + dfbSurface->Release(dfbSurface); + +#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 DFBSurfaceDescription* desc, bool track) +{ + DFBResult result; + IDirectFBSurface* newSurface = 0; + + if (!d_ptr->dfb) { + qWarning("QDirectFBScreen::createDFBSurface() - not connected"); + return 0; + } + + if (d_ptr->videoonly && !(desc->flags & DSDESC_PREALLOCATED)) { + // Add the video only capability. This means the surface will be created in video ram + DFBSurfaceDescription voDesc = *desc; + voDesc.caps = DFBSurfaceCapabilities(voDesc.caps | DSCAPS_VIDEOONLY); + voDesc.flags = DFBSurfaceDescriptionFlags(voDesc.flags | DSDESC_CAPS); + result = d_ptr->dfb->CreateSurface(d_ptr->dfb, &voDesc, &newSurface); + } + + if (!newSurface) + result = d_ptr->dfb->CreateSurface(d_ptr->dfb, desc, &newSurface); + + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::createDFBSurface", result); + return 0; + } + + Q_ASSERT(newSurface); + + if (track) { + d_ptr->allocatedSurfaces.insert(newSurface); + + //qDebug("Created a new DirectFB surface at %p. New count = %d", + // newSurface, d_ptr->allocatedSurfaces.count()); + } + + return newSurface; +} + +void QDirectFBScreen::releaseDFBSurface(IDirectFBSurface* surface) +{ + 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()); +} + +bool QDirectFBScreen::preferVideoOnly() const +{ + return d_ptr->videoonly; +} + +IDirectFB* QDirectFBScreen::dfb() +{ + return d_ptr->dfb; +} + +IDirectFBSurface* QDirectFBScreen::dfbSurface() +{ + return d_ptr->dfbSurface; +} + +#ifndef QT_NO_DIRECTFB_LAYER +IDirectFBDisplayLayer* QDirectFBScreen::dfbDisplayLayer() +{ + return d_ptr->dfbLayer; +} +#endif + +DFBSurfacePixelFormat QDirectFBScreen::getSurfacePixelFormat(const QImage &image) +{ + switch (image.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; + case QImage::Format_ARGB6666_Premultiplied: + return DSPF_ARGB6666; + case QImage::Format_RGB666: + return DSPF_RGB18; + 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(DFBSurfacePixelFormat 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; + case DSPF_ARGB6666: + return QImage::Format_ARGB6666_Premultiplied; + case DSPF_RGB18: + return QImage::Format_RGB666; + case DSPF_RGB32: + return QImage::Format_RGB32; + case DSPF_ARGB: + return QImage::Format_ARGB32_Premultiplied; + default: + break; + } + return QImage::Format_Invalid; +} + +DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const QImage &image) +{ + DFBSurfaceDescription description; + DFBSurfacePixelFormat format = getSurfacePixelFormat(image); + + if (format == DSPF_UNKNOWN || image.isNull()) { + description.flags = DFBSurfaceDescriptionFlags(0); + return description; + } + + description.flags = DFBSurfaceDescriptionFlags(DSDESC_CAPS + | DSDESC_WIDTH + | DSDESC_HEIGHT + | DSDESC_PIXELFORMAT + | DSDESC_PREALLOCATED); + + description.caps = DSCAPS_NONE; + description.width = image.width(); + description.height = image.height(); + description.pixelformat = format; + description.preallocated[0].data = (void*)(image.bits()); + description.preallocated[0].pitch = image.bytesPerLine(); + description.preallocated[1].data = 0; + description.preallocated[1].pitch = 0; + + switch (image.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: + description.caps = DSCAPS_PREMULTIPLIED; + default: + break; + } + + return description; +} + +DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const uint *buffer, + int length) +{ + DFBSurfaceDescription description; + + description.flags = DFBSurfaceDescriptionFlags(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.numColors(); + if (numColors == 0) + return; + + QVarLengthArray<DFBColor> 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); +} + +void QDirectFBScreen::setImageColorTable(QImage *image, IDirectFBSurface *surface) +{ + if (!image || !surface || image->depth() > 8) + return; + + IDirectFBPalette *palette = 0; + unsigned int numColors = 0; + DFBResult result; + do { + result = surface->GetPalette(surface, &palette); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::setImageColorTable GetPalette", result); + break; + } + + result = palette->GetSize(palette, &numColors); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::setImageColorTable GetPalette", result); + break; + } + + if (numColors == 0) + break; + + QVarLengthArray<DFBColor> dfbColors(numColors); + result = palette->GetEntries(palette, dfbColors.data(), numColors, 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::setImageColorTable GetPalette", result); + break; + } + + QVector<QRgb> qtColors(numColors); + for (unsigned int i=0; i<numColors; ++i) { + const DFBColor &col = dfbColors[i]; + qtColors[i] = qRgba(col.r, col.g, col.b, col.a); + } + image->setColorTable(qtColors); + + } while (0); + + if (palette) + palette->Release(palette); +} + +#endif // QT_NO_DIRECTFB_PALETTE + +#if !defined(QT_NO_DIRECTFB_LAYER) && !defined(QT_NO_QWS_CURSOR) +class Q_GUI_EXPORT QDirectFBScreenCursor : public QScreenCursor +{ +public: + QDirectFBScreenCursor(); + ~QDirectFBScreenCursor(); + + void set(const QImage &image, int hotx, int hoty); + void move(int x, int y); + void show(); + void hide(); + +private: + IDirectFBDisplayLayer *layer; + bool implicitHide; +}; + +QDirectFBScreenCursor::QDirectFBScreenCursor() +{ + IDirectFB *fb = QDirectFBScreen::instance()->dfb(); + if (!fb) + qFatal("QDirectFBScreenCursor: DirectFB not initialized"); + + layer = QDirectFBScreen::instance()->dfbDisplayLayer(); + + if (layer) + layer->SetCooperativeLevel(layer, DLSCL_SHARED); // XXX: hw: remove? + else + qFatal("QDirectFBScreenCursor: Unable to get primary display layer!"); + + enable = true; + hwaccel = true; + implicitHide = false; + supportsAlpha = true; + + set(QImage(), 0, 0); +} + +QDirectFBScreenCursor::~QDirectFBScreenCursor() +{ +} + +void QDirectFBScreenCursor::show() +{ + DFBResult result; + result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to set cooperative level", result); + } + result = layer->EnableCursor(layer, 1); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to enable cursor", result); + } + result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to reset cooperative level", result); + } + implicitHide = false; +} + +void QDirectFBScreenCursor::hide() +{ + DFBResult result; + result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::hide: " + "Unable to set cooperative level", result); + } + result = layer->EnableCursor(layer, 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::hide: " + "Unable to disable cursor", result); + } + result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::hide: " + "Unable to reset cooperative level", result); + } + implicitHide = true; +} + +void QDirectFBScreenCursor::move(int x, int y) +{ + layer->WarpCursor(layer, x, y); +} + +void QDirectFBScreenCursor::set(const QImage &image, int hotx, int hoty) +{ + if (image.isNull() && isVisible()) { + hide(); + implicitHide = true; + } else if (!image.isNull() && implicitHide) { + show(); + } + +#ifdef QT_NO_DIRECTFB_PALETTE + if (image.numColors() > 0) + cursor = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + else +#endif + if (image.format() == QImage::Format_Indexed8) { + cursor = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + } else { + cursor = image; + } + size = cursor.size(); + hotspot = QPoint(hotx, hoty); + + DFBSurfaceDescription description; + description = QDirectFBScreen::getSurfaceDescription(cursor); + + IDirectFBSurface *surface; + surface = QDirectFBScreen::instance()->createDFBSurface(&description); + if (!surface) { + qWarning("QDirectFBScreenCursor::set: Unable to create surface"); + return; + } +#ifndef QT_NO_DIRECTFB_PALETTE + QDirectFBScreen::setSurfaceColorTable(surface, cursor); +#endif + + DFBResult result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::set: " + "Unable to set cooperative level", result); + } + result = layer->SetCursorShape(layer, surface, hotx, hoty); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::set: Unable to set cursor shape", + result); + } + + result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::set: " + "Unable to reset cooperative level", result); + } + + if (surface) + QDirectFBScreen::instance()->releaseDFBSurface(surface); +} +#endif // QT_NO_DIRECTFB_LAYER + +QDirectFBScreen::QDirectFBScreen(int display_id) + : QScreen(display_id, DirectFBClass), d_ptr(new QDirectFBScreenPrivate(this)) +{ +} + +QDirectFBScreen::~QDirectFBScreen() +{ + delete d_ptr; +} + +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; +} + +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 (QString flip, flips) { + if (flip == QLatin1String("wait")) + flipFlags = DFBSurfaceFlipFlags(flipFlags | DSFLIP_WAIT); + else if (flip == QLatin1String("blit")) + flipFlags = DFBSurfaceFlipFlags(flipFlags | DSFLIP_BLIT); + else if (flip == QLatin1String("onsync")) + flipFlags = DFBSurfaceFlipFlags(flipFlags | DSFLIP_ONSYNC); + else if (flip == QLatin1String("pipeline")) + flipFlags = DFBSurfaceFlipFlags(flipFlags | DSFLIP_PIPELINE); + else + qWarning("QDirectFBScreen: Unknown flip argument: %s", + qPrintable(flip)); + } + } +} + +QPixmapData* QDirectFBScreenPrivate::createPixmapData(QPixmapData::PixelType type) const +{ + if (type == QPixmapData::BitmapType) + return QWSGraphicsSystem::createPixmapData(type); + + return new QDirectFBPixmapData(type); +} + +static void printDirectFBInfo(IDirectFB *fb) +{ + DFBResult result; + DFBGraphicsDeviceDescription dev; + + result = fb->GetDeviceDescription(fb, &dev); + if (result != DFB_OK) { + DirectFBError("Error reading graphics device description", result); + return; + } + + qDebug("Device: %s (%s), Driver: %s v%i.%i (%s)\n" + " acceleration: 0x%x, blit: 0x%x, draw: 0x%0x video: %i\n", + dev.name, dev.vendor, dev.driver.name, dev.driver.major, + dev.driver.minor, dev.driver.vendor, dev.acceleration_mask, + dev.blitting_flags, dev.drawing_flags, dev.video_memory); +} + +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("debug"), Qt::CaseInsensitive)) + printDirectFBInfo(d_ptr->dfb); + + if (displayArgs.contains(QLatin1String("videoonly"))) + d_ptr->videoonly = true; + +#ifndef QT_NO_DIRECTFB_WM + if (displayArgs.contains(QLatin1String("fullscreen"))) +#endif + d_ptr->dfb->SetCooperativeLevel(d_ptr->dfb, DFSCL_FULLSCREEN); + + DFBSurfaceDescription description; + description.flags = DFBSurfaceDescriptionFlags(DSDESC_CAPS); + description.caps = DFBSurfaceCapabilities(DSCAPS_PRIMARY + | DSCAPS_DOUBLE + | DSCAPS_STATIC_ALLOC); + if (!(d_ptr->flipFlags & DSFLIP_BLIT)) { + description.caps = DFBSurfaceCapabilities(description.caps + | DSCAPS_DOUBLE + | DSCAPS_TRIPLE); + } + + + // We don't track the primary surface as it's released in disconnect + d_ptr->dfbSurface = createDFBSurface(&description, false); + if (!d_ptr->dfbSurface) { + DirectFBError("QDirectFBScreen: error creating primary surface", + result); + return false; + } + d_ptr->dfbSurface->GetSize(d_ptr->dfbSurface, &w, &h); + + data = 0; + lstep = 0; + size = 0; + dw = w; + dh = h; + + DFBSurfacePixelFormat format; + result = d_ptr->dfbSurface->GetPixelFormat(d_ptr->dfbSurface, &format); + if (result == DFB_OK) + QScreen::d = depth(format); + else + DirectFBError("QDirectFBScreen: error getting surface format", result); + + setPixelFormat(getImageFormat(format)); + + physWidth = physHeight = -1; + QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)")); + int dimIdxW = displayArgs.indexOf(mmWidthRx); + if (dimIdxW >= 0) { + mmWidthRx.exactMatch(displayArgs.at(dimIdxW)); + physWidth = mmWidthRx.cap(1).toInt(); + } + QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)")); + int dimIdxH = displayArgs.indexOf(mmHeightRx); + if (dimIdxH >= 0) { + mmHeightRx.exactMatch(displayArgs.at(dimIdxH)); + physHeight = mmHeightRx.cap(1).toInt(); + } + const int dpi = 72; + if (physWidth < 0) + physWidth = qRound(dw * 25.4 / dpi); + if (physHeight < 0) + physHeight = qRound(dh * 25.4 / dpi); + +#ifndef QT_NO_DIRECTFB_LAYER + result = d_ptr->dfb->GetDisplayLayer(d_ptr->dfb, DLID_PRIMARY, + &d_ptr->dfbLayer); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::connect: " + "Unable to get primary 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 (result != DFB_OK) { + DirectFBError("QDirectFBScreen::connect: " + "Unable to get screen!", result); + return false; + } + + setGraphicsSystem(d_ptr); + + return true; +} + +void QDirectFBScreen::disconnect() +{ + d_ptr->dfbSurface->Release(d_ptr->dfbSurface); + d_ptr->dfbSurface = 0; + + 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() +{ + QWSServer *server = QWSServer::instance(); +#ifndef QT_NO_DIRECTFB_MOUSE + if (qgetenv("QWS_MOUSE_PROTO").isEmpty()) { + server->setDefaultMouse("None"); + d_ptr->mouse = new QDirectFBMouseHandler; + } +#endif +#ifndef QT_NO_DIRECTFB_KEYBOARD + if (qgetenv("QWS_KEYBOARD").isEmpty()) { + server->setDefaultKeyboard("None"); + d_ptr->keyboard = new QDirectFBKeyboardHandler(QString()); + } +#endif + +#ifndef QT_NO_QWS_CURSOR +#ifdef QT_NO_DIRECTFB_LAYER + QScreenCursor::initSoftwareCursor(); +#else + qt_screencursor = new QDirectFBScreenCursor; +#endif +#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 QDirectFBSurface(const_cast<QDirectFBScreen*>(this), widget); + else + return QScreen::createSurface(widget); +#else + return new QDirectFBSurface(const_cast<QDirectFBScreen*>(this), widget); +#endif +} + +QWSWindowSurface* QDirectFBScreen::createSurface(const QString &key) const +{ + if (key == QLatin1String("directfb")) + return new QDirectFBSurface(const_cast<QDirectFBScreen*>(this)); + return QScreen::createSurface(key); +} + +void QDirectFBScreen::compose(const QRegion ®ion) +{ + const QList<QWSWindow*> windows = QWSServer::instance()->clientWindows(); + + QRegion blitRegion = region; + QRegion blendRegion; + + d_ptr->dfbSurface->SetBlittingFlags(d_ptr->dfbSurface, DSBLIT_NOFX); + + // blit opaque region + for (int i = 0; i < windows.size(); ++i) { + QWSWindow *win = windows.at(i); + QWSWindowSurface *surface = win->windowSurface(); + if (!surface) + continue; + + const QRegion r = win->allocatedRegion() & blitRegion; + if (r.isEmpty()) + continue; + + blitRegion -= r; + + if (surface->isRegionReserved()) { + // nothing + } else if (win->isOpaque()) { + const QPoint offset = win->requestedRegion().boundingRect().topLeft(); + + if (surface->key() == QLatin1String("directfb")) { + QDirectFBSurface *s = static_cast<QDirectFBSurface*>(surface); + blit(s->directFbSurface(), offset, r); + } else { + blit(surface->image(), offset, r); + } + } else { + blendRegion += r; + } + if (blitRegion.isEmpty()) + break; + } + + { // fill background + const QRegion fill = blitRegion + blendRegion; + if (!fill.isEmpty()) { + const QColor color = QWSServer::instance()->backgroundBrush().color(); + solidFill(color, fill); + blitRegion = QRegion(); + } + } + + if (blendRegion.isEmpty()) + return; + + // blend non-opaque region + for (int i = windows.size() - 1; i >= 0; --i) { + QWSWindow *win = windows.at(i); + QWSWindowSurface *surface = win->windowSurface(); + if (!surface) + continue; + + const QRegion r = win->allocatedRegion() & blendRegion; + if (r.isEmpty()) + continue; + + DFBSurfaceBlittingFlags flags = DSBLIT_NOFX; + if (!win->isOpaque()) { + flags = DFBSurfaceBlittingFlags(flags | DSBLIT_BLEND_ALPHACHANNEL); + const uint opacity = win->opacity(); + if (opacity < 255) { + flags = DFBSurfaceBlittingFlags(flags | DSBLIT_BLEND_COLORALPHA); + d_ptr->dfbSurface->SetColor(d_ptr->dfbSurface, 0xff, 0xff, 0xff, opacity); + } + } + d_ptr->dfbSurface->SetBlittingFlags(d_ptr->dfbSurface, flags); + + const QPoint offset = win->requestedRegion().boundingRect().topLeft(); + + if (surface->key() == QLatin1String("directfb")) { + QDirectFBSurface *s = static_cast<QDirectFBSurface*>(surface); + blit(s->directFbSurface(), offset, r); + } else { + blit(surface->image(), offset, r); + } + } +} + +// Normally, when using DirectFB to compose the windows (I.e. when +// QT_NO_DIRECTFB_WM isn't set), exposeRegion will simply return. If +// QT_NO_DIRECTFB_WM is set, exposeRegion will compose only non-directFB +// window surfaces. Normal, directFB surfaces are handled by DirectFB. +void QDirectFBScreen::exposeRegion(QRegion r, int changing) +{ + const QList<QWSWindow*> windows = QWSServer::instance()->clientWindows(); + if (changing < 0 || changing >= windows.size()) + return; + +#ifndef QT_NO_DIRECTFB_WM + QWSWindow *win = windows.at(changing); + QWSWindowSurface *s = win->windowSurface(); + if (s && s->key() == QLatin1String("directfb")) + return; +#endif + + r &= region(); + if (r.isEmpty()) + return; + + if (d_ptr->flipFlags & DSFLIP_BLIT) { + const QRect brect = r.boundingRect(); + DFBRegion dfbRegion = { brect.left(), brect.top(), + brect.right(), brect.bottom() }; + compose(r); + d_ptr->dfbSurface->Flip(d_ptr->dfbSurface, &dfbRegion, + d_ptr->flipFlags); + } else { + compose(r + d_ptr->prevExpose); + d_ptr->dfbSurface->Flip(d_ptr->dfbSurface, 0, d_ptr->flipFlags); + } + d_ptr->prevExpose = r; +} + + +void QDirectFBScreen::blit(const QImage &img, const QPoint &topLeft, + const QRegion ®) +{ + IDirectFBSurface *src = 0; + DFBSurfaceDescription description = getSurfaceDescription(img); + + src = createDFBSurface(&description); + if (!src) { + qWarning("QDirectFBScreen::blit(): Error creating surface"); + return; + } +#ifndef QT_NO_DIRECTFB_PALETTE + setSurfaceColorTable(d_ptr->dfbSurface, img); +#endif + + blit(src, topLeft, reg); + + releaseDFBSurface(src); +} + +void QDirectFBScreen::blit(IDirectFBSurface *src, const QPoint &topLeft, + const QRegion ®ion) +{ + const QVector<QRect> rs = region.translated(-offset()).rects(); + const int size = rs.size(); + const QPoint tl = topLeft - offset(); + + QVarLengthArray<DFBRectangle> rects(size); + QVarLengthArray<DFBPoint> points(size); + + int n = 0; + for (int i = 0; i < size; ++i) { + const QRect r = rs.at(i); + if (!r.isValid()) + continue; + rects[n].x = r.x() - tl.x(); + rects[n].y = r.y() - tl.y(); + rects[n].w = r.width(); + rects[n].h = r.height(); + points[n].x = r.x(); + points[n].y = r.y(); + ++n; + } + + d_ptr->dfbSurface->BatchBlit(d_ptr->dfbSurface, src, rects.data(), + points.data(), n); +} + +void QDirectFBScreen::solidFill(const QColor &color, const QRegion ®ion) +{ + if (region.isEmpty()) + return; + + const QVector<QRect> rects = region.rects(); + QVarLengthArray<DFBRectangle> dfbRects(rects.size()); + for (int i = 0; i < rects.size(); ++i) { + const QRect r = rects.at(i); + dfbRects[i].x = r.x(); + dfbRects[i].y = r.y(); + dfbRects[i].w = r.width(); + dfbRects[i].h = r.height(); + } + + d_ptr->dfbSurface->SetColor(d_ptr->dfbSurface, + color.red(), color.green(), color.blue(), + color.alpha()); + d_ptr->dfbSurface->FillRectangles(d_ptr->dfbSurface, dfbRects.data(), + dfbRects.size()); +} + diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h new file mode 100644 index 0000000..e9a2f63 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTFBSCREEN_H +#define QDIRECTFBSCREEN_H + +#include <QtGui/qscreen_qws.h> +#include <directfb.h> + +QT_BEGIN_HEADER + +QT_MODULE(Gui) + +#define Q_DIRECTFB_VERSION ((DIRECTFB_MAJOR_VERSION << 16) | (DIRECTFB_MINOR_VERION << 8) | DIRECTFB_MICRO_VERSION) + +class QDirectFBScreenPrivate; + +class Q_GUI_EXPORT QDirectFBScreen : public QScreen +{ +public: + QDirectFBScreen(int display_id); + ~QDirectFBScreen(); + + bool connect(const QString &displaySpec); + void disconnect(); + bool initDevice(); + void shutdownDevice(); + + void exposeRegion(QRegion r, int changing); + void blit(const QImage &img, const QPoint &topLeft, const QRegion ®ion); + void scroll(const QRegion ®ion, const QPoint &offset); + void solidFill(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 inline QDirectFBScreen* instance() { + QScreen *inst = QScreen::instance(); + Q_ASSERT(!inst || inst->classId() == QScreen::DirectFBClass); + return static_cast<QDirectFBScreen*>(inst); + } + + IDirectFB* dfb(); + IDirectFBSurface* dfbSurface(); +#ifndef QT_NO_DIRECTFB_LAYER + IDirectFBDisplayLayer* dfbDisplayLayer(); +#endif + + // Track surface creation/release so we can release all on exit + IDirectFBSurface* createDFBSurface(const DFBSurfaceDescription* desc, bool track = true); + void releaseDFBSurface(IDirectFBSurface* surface); + bool preferVideoOnly() const; + + static int depth(DFBSurfacePixelFormat format); + + static DFBSurfacePixelFormat getSurfacePixelFormat(const QImage &image); + static DFBSurfaceDescription getSurfaceDescription(const QImage &image); + static DFBSurfaceDescription getSurfaceDescription(const uint *buffer, + int length); + static QImage::Format getImageFormat(DFBSurfacePixelFormat format); + static inline bool isPremultiplied(QImage::Format format); + +#ifndef QT_NO_DIRECTFB_PALETTE + static void setSurfaceColorTable(IDirectFBSurface *surface, + const QImage &image); + static void setImageColorTable(QImage *image, IDirectFBSurface *surface); +#endif + +private: + void compose(const QRegion &r); + void blit(IDirectFBSurface *src, const QPoint &topLeft, + const QRegion ®ion); + + QDirectFBScreenPrivate *d_ptr; +}; + +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; +} + + +QT_END_HEADER + +#endif // QDIRECTFBSCREEN_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp new file mode 100644 index 0000000..ca863d2 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbscreen.h" + +#include <QtGui/qscreendriverplugin_qws.h> +#include <QtCore/qstringlist.h> + +class DirectFBScreenDriverPlugin : public QScreenDriverPlugin +{ +public: + DirectFBScreenDriverPlugin(); + + QStringList keys() const; + QScreen *create(const QString&, int displayId); +}; + +DirectFBScreenDriverPlugin::DirectFBScreenDriverPlugin() + : QScreenDriverPlugin() +{ +} + +QStringList DirectFBScreenDriverPlugin::keys() const +{ + return (QStringList() << "directfb"); +} + +QScreen* DirectFBScreenDriverPlugin::create(const QString& driver, + int displayId) +{ + if (driver.toLower() != "directfb") + return 0; + + return new QDirectFBScreen(displayId); +} + +Q_EXPORT_PLUGIN2(qdirectfbscreen, DirectFBScreenDriverPlugin) diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbsurface.cpp new file mode 100644 index 0000000..ab1d0f1 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbsurface.cpp @@ -0,0 +1,393 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbsurface.h" +#include "qdirectfbscreen.h" +#include "qdirectfbpaintengine.h" + +#include <qwidget.h> +#include <qpaintdevice.h> +#include <qvarlengtharray.h> + + +//#define QT_DIRECTFB_DEBUG_SURFACES 1 + +QDirectFBSurface::QDirectFBSurface(QDirectFBScreen* scr) + : QDirectFBPaintDevice(scr) +#ifndef QT_NO_DIRECTFB_WM + , dfbWindow(0) +#endif + , engine(0) +{ + setSurfaceFlags(Opaque | Buffered); +} + +QDirectFBSurface::QDirectFBSurface(QDirectFBScreen* scr, QWidget *widget) + : QWSWindowSurface(widget), QDirectFBPaintDevice(scr) +#ifndef QT_NO_DIRECTFB_WM + , dfbWindow(0) +#endif + , engine(0) +{ + onscreen = widget->testAttribute(Qt::WA_PaintOnScreen); + if (onscreen) + setSurfaceFlags(Opaque | RegionReserved); + else + setSurfaceFlags(Opaque | Buffered); +} + +QDirectFBSurface::~QDirectFBSurface() +{ +} + +bool QDirectFBSurface::isValid() const +{ + return true; +} + +#ifndef QT_NO_DIRECTFB_WM +void QDirectFBSurface::createWindow() +{ + IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer(); + if (!layer) + qFatal("QDirectFBWindowSurface: Unable to get primary display layer!"); + + DFBWindowDescription description; + description.caps = DFBWindowCapabilities(DWCAPS_NODECORATION | + DWCAPS_ALPHACHANNEL); + description.flags = DWDESC_CAPS; + + DFBResult result = layer->CreateWindow(layer, &description, &dfbWindow); + if (result != DFB_OK) + DirectFBErrorFatal("QDirectFBWindowSurface::createWindow", result); + + if (dfbSurface) + dfbSurface->Release(dfbSurface); + + dfbWindow->GetSurface(dfbWindow, &dfbSurface); +} +#endif // QT_NO_DIRECTFB_WM + +void QDirectFBSurface::setGeometry(const QRect &rect, const QRegion &mask) +{ + if (rect.isNull()) { +#ifndef QT_NO_DIRECTFB_WM + if (dfbWindow) { + dfbWindow->Release(dfbWindow); + dfbWindow = 0; + } +#endif + if (dfbSurface) { + dfbSurface->Release(dfbSurface); + dfbSurface = 0; + } + } else if (rect != geometry()) { + const bool isResize = rect.size() != geometry().size(); + DFBResult result = DFB_OK; + + // If we're in a resize, the surface shouldn't be locked + Q_ASSERT( (lockedImage == 0) || (isResize == false)); + + IDirectFBSurface *s = screen->dfbSurface(); + if (onscreen && s) { + if (dfbSurface) + dfbSurface->Release(dfbSurface); + + DFBRectangle r = { rect.x(), rect.y(), + rect.width(), rect.height() }; + result = s->GetSubSurface(s, &r, &dfbSurface); + } else { +#ifdef QT_NO_DIRECTFB_WM + if (isResize) { + if (dfbSurface) + dfbSurface->Release(dfbSurface); + + IDirectFB *dfb = screen->dfb(); + if (!dfb) { + qFatal("QDirectFBWindowSurface::setGeometry(): " + "Unable to get DirectFB handle!"); + } + + DFBSurfaceDescription description; + description.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | + DSDESC_HEIGHT | + DSDESC_PIXELFORMAT); + description.width = rect.width(); + description.height = rect.height(); + description.pixelformat = DSPF_ARGB; + + dfbSurface = QDirectFBScreen::instance()->createDFBSurface(&description, false); + } else { + Q_ASSERT(dfbSurface); + } +#else + const QRect oldRect = geometry(); + const bool isMove = oldRect.isEmpty() || + rect.topLeft() != oldRect.topLeft(); + + if (!dfbWindow) + createWindow(); + + 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()); +#endif + } + + if (result != DFB_OK) + DirectFBErrorFatal("QDirectFBSurface::setGeometry()", result); + } + + QWSWindowSurface::setGeometry(rect, mask); +} + +QByteArray QDirectFBSurface::permanentState() const +{ + QByteArray array; +#ifdef QT_NO_DIRECTFB_WM + array.resize(sizeof(SurfaceFlags) + sizeof(IDirectFBSurface*)); +#else + array.resize(sizeof(SurfaceFlags)); +#endif + char *ptr = array.data(); + + *reinterpret_cast<SurfaceFlags*>(ptr) = surfaceFlags(); + ptr += sizeof(SurfaceFlags); + +#ifdef QT_NO_DIRECTFB_WM + *reinterpret_cast<IDirectFBSurface**>(ptr) = dfbSurface; +#endif + return array; +} + +void QDirectFBSurface::setPermanentState(const QByteArray &state) +{ + SurfaceFlags flags; + const char *ptr = state.constData(); + + flags = *reinterpret_cast<const SurfaceFlags*>(ptr); + setSurfaceFlags(flags); + +#ifdef QT_NO_DIRECTFB_WM + ptr += sizeof(SurfaceFlags); + dfbSurface = *reinterpret_cast<IDirectFBSurface* const*>(ptr); +#endif +} + +bool QDirectFBSurface::scroll(const QRegion ®ion, int dx, int dy) +{ + if (!dfbSurface) + return false; + + const QVector<QRect> rects = region.rects(); + const int n = rects.size(); + + QVarLengthArray<DFBRectangle, 8> dfbRects(n); + QVarLengthArray<DFBPoint, 8> dfbPoints(n); + + for (int i = 0; i < n; ++i) { + const QRect r = rects.at(i); + dfbRects[i].x = r.x(); + dfbRects[i].y = r.y(); + dfbRects[i].w = r.width(); + dfbRects[i].h = r.height(); + dfbPoints[i].x = r.x() + dx; + dfbPoints[i].y = r.y() + dy; + } + + dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); + dfbSurface->BatchBlit(dfbSurface, dfbSurface, + dfbRects.data(), dfbPoints.data(), n); + + return true; +} + +bool QDirectFBSurface::move(const QPoint &offset) +{ + QWSWindowSurface::move(offset); + +#ifdef QT_NO_DIRECTFB_WM + return true; // buffered +#else + if (!dfbWindow) + return false; + + DFBResult status = dfbWindow->Move(dfbWindow, offset.x(), offset.y()); + return (status == DFB_OK); +#endif +} + +QRegion QDirectFBSurface::move(const QPoint &offset, const QRegion &newClip) +{ +#ifdef QT_NO_DIRECTFB_WM + return QWSWindowSurface::move(offset, newClip); +#else + Q_UNUSED(offset); + Q_UNUSED(newClip); + + // DirectFB handles the entire move, so there's no need to blit. + return QRegion(); +#endif +} + +QPaintEngine* QDirectFBSurface::paintEngine() const +{ + if (!engine) { + QDirectFBSurface *that = const_cast<QDirectFBSurface*>(this); + that->engine = new QDirectFBPaintEngine(that); + return that->engine; + } + return engine; +} + +// hw: XXX: copied from QWidgetPrivate::isOpaque() +inline bool isWidgetOpaque(const QWidget *w) +{ + if (w->testAttribute(Qt::WA_OpaquePaintEvent) + || w->testAttribute(Qt::WA_PaintOnScreen)) + return true; + + const QPalette &pal = w->palette(); + + if (w->autoFillBackground()) { + const QBrush &autoFillBrush = pal.brush(w->backgroundRole()); + if (autoFillBrush.style() != Qt::NoBrush && autoFillBrush.isOpaque()) + return true; + } + + if (!w->testAttribute(Qt::WA_NoSystemBackground)) { + const QBrush &windowBrush = w->palette().brush(QPalette::Window); + if (windowBrush.style() != Qt::NoBrush && windowBrush.isOpaque()) + return true; + } + + return false; +} + +void QDirectFBSurface::flush(QWidget *widget, const QRegion ®ion, + const QPoint &offset) +{ + QWidget *win = window(); + + // hw: make sure opacity information is updated before compositing + const bool opaque = isWidgetOpaque(win); + if (opaque != isOpaque()) { + SurfaceFlags flags = Buffered; + if (opaque) + flags |= Opaque; + setSurfaceFlags(flags); + } + +#ifndef QT_NO_DIRECTFB_WM + const quint8 winOpacity = quint8(win->windowOpacity() * 255); + quint8 opacity; + + if (dfbWindow) { + dfbWindow->GetOpacity(dfbWindow, &opacity); + if (winOpacity != opacity) + dfbWindow->SetOpacity(dfbWindow, winOpacity); + } +#endif + + // XXX: have to call the base function first as the decoration is + // currently painted there + QWSWindowSurface::flush(widget, region, offset); + +#ifndef QT_NO_DIRECTFB_WM + const QRect br = region.boundingRect().translated(painterOffset()); + const DFBRegion r = { br.x(), br.y(), + br.x() + br.width(), br.y() + br.height() }; + + dfbSurface->Flip(dfbSurface, &r, DSFLIP_NONE); +#endif +} + + +void QDirectFBSurface::beginPaint(const QRegion &) +{ +} + +void QDirectFBSurface::endPaint(const QRegion &) +{ +#ifdef QT_DIRECTFB_DEBUG_SURFACES + if (bufferImages.count()) { + qDebug("QDirectFBSurface::endPaint() this=%p", this); + + foreach(QImage* bufferImg, bufferImages) + qDebug(" Deleting buffer image %p", bufferImg); + } +#endif + + qDeleteAll(bufferImages); + bufferImages.clear(); + unlockDirectFB(); +} + + +QImage* QDirectFBSurface::buffer(const QWidget *widget) +{ + if (!lockedImage) + return 0; + + const QRect rect = QRect(offset(widget), widget->size()) + & lockedImage->rect(); + if (rect.isEmpty()) + return 0; + + QImage *img = new QImage(lockedImage->scanLine(rect.y()) + + rect.x() * (lockedImage->depth() / 8), + rect.width(), rect.height(), + lockedImage->bytesPerLine(), + lockedImage->format()); + bufferImages.append(img); + +#ifdef QT_DIRECTFB_DEBUG_SURFACES + qDebug("QDirectFBSurface::buffer() Created & returned %p", img); +#endif + + return img; +} + diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbsurface.h b/src/plugins/gfxdrivers/directfb/qdirectfbsurface.h new file mode 100644 index 0000000..a9cdb7d --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbsurface.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECFBWINDOWSURFACE_H +#define QDIRECFBWINDOWSURFACE_H + +#include "qdirectfbpaintengine.h" +#include "qdirectfbpaintdevice.h" +#include "qdirectfbscreen.h" + +#include <private/qpaintengine_raster_p.h> +#include <private/qwindowsurface_qws_p.h> +#include <directfb.h> + +QT_BEGIN_HEADER + +QT_MODULE(Gui) + +class QDirectFBSurface: public QWSWindowSurface, public QDirectFBPaintDevice +{ +public: + QDirectFBSurface(QDirectFBScreen* scr); + QDirectFBSurface(QDirectFBScreen* scr, QWidget *widget); + ~QDirectFBSurface(); + + bool isValid() const; + + void setGeometry(const QRect &rect, const QRegion &mask); + + 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); + QRegion move(const QPoint &offset, const QRegion &newClip); + + QImage image() const { return QImage(); } + QPaintDevice* paintDevice() { return this; } + QPaintEngine* paintEngine() const; + + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + + void beginPaint(const QRegion &); + void endPaint(const QRegion &); + + QImage* buffer(const QWidget *widget); + +private: +#ifndef QT_NO_DIRECTFB_WM + void createWindow(); + IDirectFBWindow *dfbWindow; +#endif + QDirectFBPaintEngine *engine; + + bool onscreen; + + QList<QImage*> bufferImages; +}; + +QT_END_HEADER + +#endif // QDIRECFBWINDOWSURFACE_H |