diff options
Diffstat (limited to 'src/plugins/gfxdrivers/directfb')
16 files changed, 6304 insertions, 0 deletions
diff --git a/src/plugins/gfxdrivers/directfb/directfb.pro b/src/plugins/gfxdrivers/directfb/directfb.pro new file mode 100644 index 0000000000..d397050bdc --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/directfb.pro @@ -0,0 +1,15 @@ +TARGET = qdirectfbscreen +include(../../qpluginbase.pri) +include($$QT_SOURCE_TREE/src/gui/embedded/directfb.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers + +target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers +INSTALLS += target + +SOURCES += qdirectfbscreenplugin.cpp + +QMAKE_CXXFLAGS += $$QT_CFLAGS_DIRECTFB +LIBS += $$QT_LIBS_DIRECTFB +DEFINES += $$QT_DEFINES_DIRECTFB +contains(gfx-plugins, directfb):DEFINES += QT_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp new file mode 100644 index 0000000000..5c6842edca --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp @@ -0,0 +1,436 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbkeyboard.h" + +#ifndef QT_NO_QWS_DIRECTFB + +#include "qdirectfbscreen.h" +#include <qobject.h> +#include <qsocketnotifier.h> +#include <qhash.h> + +#include <directfb.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +QT_BEGIN_NAMESPACE + +class KeyMap : public QHash<DFBInputDeviceKeySymbol, Qt::Key> +{ +public: + KeyMap(); +}; + +Q_GLOBAL_STATIC(KeyMap, keymap); + +class QDirectFBKeyboardHandlerPrivate : public QObject +{ + Q_OBJECT +public: + QDirectFBKeyboardHandlerPrivate(QDirectFBKeyboardHandler *handler); + ~QDirectFBKeyboardHandlerPrivate(); + + void suspend(); + void resume(); + +private: + QDirectFBKeyboardHandler *handler; + IDirectFBEventBuffer *eventBuffer; + QSocketNotifier *keyboardNotifier; + DFBEvent event; + int bytesRead; + int lastUnicode, lastKeycode; + Qt::KeyboardModifiers lastModifiers; +private Q_SLOTS: + void readKeyboardData(); +}; + +QDirectFBKeyboardHandlerPrivate::QDirectFBKeyboardHandlerPrivate(QDirectFBKeyboardHandler *h) + : handler(h), eventBuffer(0), keyboardNotifier(0), bytesRead(0), + lastUnicode(0), lastKeycode(0), lastModifiers(0) +{ + Q_ASSERT(qt_screen); + + IDirectFB *fb = QDirectFBScreen::instance()->dfb(); + if (!fb) { + qCritical("QDirectFBKeyboardHandler: DirectFB not initialized"); + return; + } + + DFBResult result; + result = fb->CreateInputEventBuffer(fb, DICAPS_KEYS, DFB_TRUE, + &eventBuffer); + if (result != DFB_OK) { + DirectFBError("QDirectFBKeyboardHandler: " + "Unable to create input event buffer", result); + return; + } + + int fd; + result = eventBuffer->CreateFileDescriptor(eventBuffer, &fd); + if (result != DFB_OK) { + DirectFBError("QDirectFBKeyboardHandler: " + "Unable to create file descriptor", result); + return; + } + + int flags = ::fcntl(fd, F_GETFL, 0); + ::fcntl(fd, F_SETFL, flags | O_NONBLOCK); + + memset(&event, 0, sizeof(event)); + + keyboardNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); + connect(keyboardNotifier, SIGNAL(activated(int)), + this, SLOT(readKeyboardData())); + resume(); +} + +void QDirectFBKeyboardHandlerPrivate::suspend() +{ + keyboardNotifier->setEnabled(false); +} + +void QDirectFBKeyboardHandlerPrivate::resume() +{ + eventBuffer->Reset(eventBuffer); + keyboardNotifier->setEnabled(true); +} + +QDirectFBKeyboardHandlerPrivate::~QDirectFBKeyboardHandlerPrivate() +{ + if (eventBuffer) + eventBuffer->Release(eventBuffer); +} + +void QDirectFBKeyboardHandlerPrivate::readKeyboardData() +{ + if(!qt_screen) + return; + + for (;;) { + // GetEvent returns DFB_UNSUPPORTED after CreateFileDescriptor(). + // This seems stupid and I really hope it's a bug which will be fixed. + + // DFBResult ret = eventBuffer->GetEvent(eventBuffer, &event); + + char *buf = reinterpret_cast<char*>(&event); + int ret = ::read(keyboardNotifier->socket(), + buf + bytesRead, sizeof(DFBEvent) - bytesRead); + if (ret == -1) { + if (errno != EAGAIN) + qWarning("QDirectFBKeyboardHandlerPrivate::readKeyboardData(): %s", + strerror(errno)); + return; + } + + Q_ASSERT(ret >= 0); + bytesRead += ret; + if (bytesRead < int(sizeof(DFBEvent))) + break; + bytesRead = 0; + + Q_ASSERT(event.clazz == DFEC_INPUT); + + const DFBInputEvent input = event.input; + + Qt::KeyboardModifiers modifiers = Qt::NoModifier; + + // Not implemented: + // if (input.modifiers & DIMM_SUPER) + // if (input.modifiers & DIMM_HYPER) + + if (!(input.flags & DIEF_KEYSYMBOL) || + !(input.flags & DIEF_KEYID) || + !(input.type & (DIET_KEYPRESS|DIET_KEYRELEASE))) + { + static bool first = true; + if (first) { + qWarning("QDirectFBKeyboardHandler - Getting unexpected non-keyboard related events"); + first = false; + } + break; + } + + if (input.flags & DIEF_MODIFIERS) { + if (input.modifiers & DIMM_SHIFT) + modifiers |= Qt::ShiftModifier; + if (input.modifiers & DIMM_CONTROL) + modifiers |= Qt::ControlModifier; + if (input.modifiers & DIMM_ALT) + modifiers |= Qt::AltModifier; + if (input.modifiers & DIMM_ALTGR) + modifiers |= Qt::AltModifier; + if (input.modifiers & DIMM_META) + modifiers |= Qt::MetaModifier; + } + + + const bool press = input.type & DIET_KEYPRESS; + DFBInputDeviceKeySymbol symbol = input.key_symbol; + int unicode = -1; + int keycode = 0; + + keycode = keymap()->value(symbol); + if (DFB_KEY_TYPE(symbol) == DIKT_UNICODE) + unicode = symbol; + + if (unicode != -1 || keycode != 0) { + bool autoRepeat = false; + if (press) { + if (unicode == lastUnicode && keycode == lastKeycode && modifiers == lastModifiers) { + autoRepeat = true; + } else { + lastUnicode = unicode; + lastKeycode = keycode; + lastModifiers = modifiers; + } + } else { + lastUnicode = lastKeycode = -1; + lastModifiers = 0; + } + if (autoRepeat) { + handler->processKeyEvent(unicode, keycode, + modifiers, false, autoRepeat); + + } + + handler->processKeyEvent(unicode, keycode, + modifiers, press, autoRepeat); + } + } +} + +QDirectFBKeyboardHandler::QDirectFBKeyboardHandler(const QString &device) + : QWSKeyboardHandler() +{ + Q_UNUSED(device); + d = new QDirectFBKeyboardHandlerPrivate(this); +} + +QDirectFBKeyboardHandler::~QDirectFBKeyboardHandler() +{ + delete d; +} + +KeyMap::KeyMap() +{ + insert(DIKS_BACKSPACE , Qt::Key_Backspace); + insert(DIKS_TAB , Qt::Key_Tab); + insert(DIKS_RETURN , Qt::Key_Return); + insert(DIKS_ESCAPE , Qt::Key_Escape); + insert(DIKS_DELETE , Qt::Key_Delete); + + insert(DIKS_CURSOR_LEFT , Qt::Key_Left); + insert(DIKS_CURSOR_RIGHT , Qt::Key_Right); + insert(DIKS_CURSOR_UP , Qt::Key_Up); + insert(DIKS_CURSOR_DOWN , Qt::Key_Down); + insert(DIKS_INSERT , Qt::Key_Insert); + insert(DIKS_HOME , Qt::Key_Home); + insert(DIKS_END , Qt::Key_End); + insert(DIKS_PAGE_UP , Qt::Key_PageUp); + insert(DIKS_PAGE_DOWN , Qt::Key_PageDown); + insert(DIKS_PRINT , Qt::Key_Print); + insert(DIKS_PAUSE , Qt::Key_Pause); + insert(DIKS_SELECT , Qt::Key_Select); + insert(DIKS_GOTO , Qt::Key_OpenUrl); + insert(DIKS_CLEAR , Qt::Key_Clear); + insert(DIKS_MENU , Qt::Key_Menu); + insert(DIKS_HELP , Qt::Key_Help); + + insert(DIKS_INTERNET , Qt::Key_HomePage); + insert(DIKS_MAIL , Qt::Key_LaunchMail); + insert(DIKS_FAVORITES , Qt::Key_Favorites); + + insert(DIKS_BACK , Qt::Key_Back); + insert(DIKS_FORWARD , Qt::Key_Forward); + insert(DIKS_VOLUME_UP , Qt::Key_VolumeUp); + insert(DIKS_VOLUME_DOWN , Qt::Key_VolumeDown); + insert(DIKS_MUTE , Qt::Key_VolumeMute); + insert(DIKS_PLAYPAUSE , Qt::Key_Pause); + insert(DIKS_PLAY , Qt::Key_MediaPlay); + insert(DIKS_STOP , Qt::Key_MediaStop); + insert(DIKS_RECORD , Qt::Key_MediaRecord); + insert(DIKS_PREVIOUS , Qt::Key_MediaPrevious); + insert(DIKS_NEXT , Qt::Key_MediaNext); + + insert(DIKS_F1 , Qt::Key_F1); + insert(DIKS_F2 , Qt::Key_F2); + insert(DIKS_F3 , Qt::Key_F3); + insert(DIKS_F4 , Qt::Key_F4); + insert(DIKS_F5 , Qt::Key_F5); + insert(DIKS_F6 , Qt::Key_F6); + insert(DIKS_F7 , Qt::Key_F7); + insert(DIKS_F8 , Qt::Key_F8); + insert(DIKS_F9 , Qt::Key_F9); + insert(DIKS_F10 , Qt::Key_F10); + insert(DIKS_F11 , Qt::Key_F11); + insert(DIKS_F12 , Qt::Key_F12); + + insert(DIKS_SHIFT , Qt::Key_Shift); + insert(DIKS_CONTROL , Qt::Key_Control); + insert(DIKS_ALT , Qt::Key_Alt); + insert(DIKS_ALTGR , Qt::Key_AltGr); + + insert(DIKS_META , Qt::Key_Meta); + insert(DIKS_SUPER , Qt::Key_Super_L); // ??? + insert(DIKS_HYPER , Qt::Key_Hyper_L); // ??? + + insert(DIKS_CAPS_LOCK , Qt::Key_CapsLock); + insert(DIKS_NUM_LOCK , Qt::Key_NumLock); + insert(DIKS_SCROLL_LOCK , Qt::Key_ScrollLock); + + insert(DIKS_DEAD_ABOVEDOT , Qt::Key_Dead_Abovedot); + insert(DIKS_DEAD_ABOVERING , Qt::Key_Dead_Abovering); + insert(DIKS_DEAD_ACUTE , Qt::Key_Dead_Acute); + insert(DIKS_DEAD_BREVE , Qt::Key_Dead_Breve); + insert(DIKS_DEAD_CARON , Qt::Key_Dead_Caron); + insert(DIKS_DEAD_CEDILLA , Qt::Key_Dead_Cedilla); + insert(DIKS_DEAD_CIRCUMFLEX , Qt::Key_Dead_Circumflex); + insert(DIKS_DEAD_DIAERESIS , Qt::Key_Dead_Diaeresis); + insert(DIKS_DEAD_DOUBLEACUTE , Qt::Key_Dead_Doubleacute); + insert(DIKS_DEAD_GRAVE , Qt::Key_Dead_Grave); + insert(DIKS_DEAD_IOTA , Qt::Key_Dead_Iota); + insert(DIKS_DEAD_MACRON , Qt::Key_Dead_Macron); + insert(DIKS_DEAD_OGONEK , Qt::Key_Dead_Ogonek); + insert(DIKS_DEAD_SEMIVOICED_SOUND , Qt::Key_Dead_Semivoiced_Sound); + insert(DIKS_DEAD_TILDE , Qt::Key_Dead_Tilde); + insert(DIKS_DEAD_VOICED_SOUND , Qt::Key_Dead_Voiced_Sound); + insert(DIKS_SPACE , Qt::Key_Space); + insert(DIKS_EXCLAMATION_MARK , Qt::Key_Exclam); + insert(DIKS_QUOTATION , Qt::Key_QuoteDbl); + insert(DIKS_NUMBER_SIGN , Qt::Key_NumberSign); + insert(DIKS_DOLLAR_SIGN , Qt::Key_Dollar); + insert(DIKS_PERCENT_SIGN , Qt::Key_Percent); + insert(DIKS_AMPERSAND , Qt::Key_Ampersand); + insert(DIKS_APOSTROPHE , Qt::Key_Apostrophe); + insert(DIKS_PARENTHESIS_LEFT , Qt::Key_ParenLeft); + insert(DIKS_PARENTHESIS_RIGHT , Qt::Key_ParenRight); + insert(DIKS_ASTERISK , Qt::Key_Asterisk); + insert(DIKS_PLUS_SIGN , Qt::Key_Plus); + insert(DIKS_COMMA , Qt::Key_Comma); + insert(DIKS_MINUS_SIGN , Qt::Key_Minus); + insert(DIKS_PERIOD , Qt::Key_Period); + insert(DIKS_SLASH , Qt::Key_Slash); + insert(DIKS_0 , Qt::Key_0); + insert(DIKS_1 , Qt::Key_1); + insert(DIKS_2 , Qt::Key_2); + insert(DIKS_3 , Qt::Key_3); + insert(DIKS_4 , Qt::Key_4); + insert(DIKS_5 , Qt::Key_5); + insert(DIKS_6 , Qt::Key_6); + insert(DIKS_7 , Qt::Key_7); + insert(DIKS_8 , Qt::Key_8); + insert(DIKS_9 , Qt::Key_9); + insert(DIKS_COLON , Qt::Key_Colon); + insert(DIKS_SEMICOLON , Qt::Key_Semicolon); + insert(DIKS_LESS_THAN_SIGN , Qt::Key_Less); + insert(DIKS_EQUALS_SIGN , Qt::Key_Equal); + insert(DIKS_GREATER_THAN_SIGN , Qt::Key_Greater); + insert(DIKS_QUESTION_MARK , Qt::Key_Question); + insert(DIKS_AT , Qt::Key_At); + insert(DIKS_CAPITAL_A , Qt::Key_A); + insert(DIKS_CAPITAL_B , Qt::Key_B); + insert(DIKS_CAPITAL_C , Qt::Key_C); + insert(DIKS_CAPITAL_D , Qt::Key_D); + insert(DIKS_CAPITAL_E , Qt::Key_E); + insert(DIKS_CAPITAL_F , Qt::Key_F); + insert(DIKS_CAPITAL_G , Qt::Key_G); + insert(DIKS_CAPITAL_H , Qt::Key_H); + insert(DIKS_CAPITAL_I , Qt::Key_I); + insert(DIKS_CAPITAL_J , Qt::Key_J); + insert(DIKS_CAPITAL_K , Qt::Key_K); + insert(DIKS_CAPITAL_L , Qt::Key_L); + insert(DIKS_CAPITAL_M , Qt::Key_M); + insert(DIKS_CAPITAL_N , Qt::Key_N); + insert(DIKS_CAPITAL_O , Qt::Key_O); + insert(DIKS_CAPITAL_P , Qt::Key_P); + insert(DIKS_CAPITAL_Q , Qt::Key_Q); + insert(DIKS_CAPITAL_R , Qt::Key_R); + insert(DIKS_CAPITAL_S , Qt::Key_S); + insert(DIKS_CAPITAL_T , Qt::Key_T); + insert(DIKS_CAPITAL_U , Qt::Key_U); + insert(DIKS_CAPITAL_V , Qt::Key_V); + insert(DIKS_CAPITAL_W , Qt::Key_W); + insert(DIKS_CAPITAL_X , Qt::Key_X); + insert(DIKS_CAPITAL_Y , Qt::Key_Y); + insert(DIKS_CAPITAL_Z , Qt::Key_Z); + insert(DIKS_SQUARE_BRACKET_LEFT , Qt::Key_BracketLeft); + insert(DIKS_BACKSLASH , Qt::Key_Backslash); + insert(DIKS_SQUARE_BRACKET_RIGHT , Qt::Key_BracketRight); + insert(DIKS_CIRCUMFLEX_ACCENT , Qt::Key_AsciiCircum); + insert(DIKS_UNDERSCORE , Qt::Key_Underscore); + insert(DIKS_SMALL_A , Qt::Key_A); + insert(DIKS_SMALL_B , Qt::Key_B); + insert(DIKS_SMALL_C , Qt::Key_C); + insert(DIKS_SMALL_D , Qt::Key_D); + insert(DIKS_SMALL_E , Qt::Key_E); + insert(DIKS_SMALL_F , Qt::Key_F); + insert(DIKS_SMALL_G , Qt::Key_G); + insert(DIKS_SMALL_H , Qt::Key_H); + insert(DIKS_SMALL_I , Qt::Key_I); + insert(DIKS_SMALL_J , Qt::Key_J); + insert(DIKS_SMALL_K , Qt::Key_K); + insert(DIKS_SMALL_L , Qt::Key_L); + insert(DIKS_SMALL_M , Qt::Key_M); + insert(DIKS_SMALL_N , Qt::Key_N); + insert(DIKS_SMALL_O , Qt::Key_O); + insert(DIKS_SMALL_P , Qt::Key_P); + insert(DIKS_SMALL_Q , Qt::Key_Q); + insert(DIKS_SMALL_R , Qt::Key_R); + insert(DIKS_SMALL_S , Qt::Key_S); + insert(DIKS_SMALL_T , Qt::Key_T); + insert(DIKS_SMALL_U , Qt::Key_U); + insert(DIKS_SMALL_V , Qt::Key_V); + insert(DIKS_SMALL_W , Qt::Key_W); + insert(DIKS_SMALL_X , Qt::Key_X); + insert(DIKS_SMALL_Y , Qt::Key_Y); + insert(DIKS_SMALL_Z , Qt::Key_Z); + insert(DIKS_CURLY_BRACKET_LEFT , Qt::Key_BraceLeft); + insert(DIKS_VERTICAL_BAR , Qt::Key_Bar); + insert(DIKS_CURLY_BRACKET_RIGHT , Qt::Key_BraceRight); + insert(DIKS_TILDE , Qt::Key_AsciiTilde); +} + +QT_END_NAMESPACE +#include "qdirectfbkeyboard.moc" +#endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h new file mode 100644 index 0000000000..49c1c18b22 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTFBKEYBOARD_H +#define QDIRECTFBKEYBOARD_H + +#include <qglobal.h> +#include <QtGui/qkbd_qws.h> + +#ifndef QT_NO_QWS_DIRECTFB + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QDirectFBKeyboardHandlerPrivate; + +class QDirectFBKeyboardHandler : public QWSKeyboardHandler +{ +public: + QDirectFBKeyboardHandler(const QString &device); + ~QDirectFBKeyboardHandler(); + +private: + QDirectFBKeyboardHandlerPrivate *d; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_QWS_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 0000000000..3999b85afb --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbmouse.h" + +#ifndef QT_NO_QWS_DIRECTFB + +#include "qdirectfbscreen.h" +#include <qsocketnotifier.h> + +#include <directfb.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +QT_BEGIN_NAMESPACE + +class QDirectFBMouseHandlerPrivate : public QObject +{ + Q_OBJECT +public: + QDirectFBMouseHandlerPrivate(QDirectFBMouseHandler *h); + ~QDirectFBMouseHandlerPrivate(); + + void setEnabled(bool on); +private: + QDirectFBMouseHandler *handler; + IDirectFBEventBuffer *eventBuffer; +#ifndef QT_NO_DIRECTFB_LAYER + IDirectFBDisplayLayer *layer; +#endif + QSocketNotifier *mouseNotifier; + + QPoint prevPoint; + Qt::MouseButtons prevbuttons; + + DFBEvent event; + uint bytesRead; + +private Q_SLOTS: + void readMouseData(); +}; + +QDirectFBMouseHandlerPrivate::QDirectFBMouseHandlerPrivate(QDirectFBMouseHandler *h) + : handler(h), eventBuffer(0) +{ + DFBResult result; + + QScreen *screen = QScreen::instance(); + if (!screen) { + qCritical("QDirectFBMouseHandler: no screen instance found"); + return; + } + + IDirectFB *fb = QDirectFBScreen::instance()->dfb(); + if (!fb) { + qCritical("QDirectFBMouseHandler: DirectFB not initialized"); + return; + } + +#ifndef QT_NO_DIRECTFB_LAYER + layer = QDirectFBScreen::instance()->dfbDisplayLayer(); + if (!layer) { + qCritical("QDirectFBMouseHandler: Unable to get primary display layer"); + return; + } +#endif + + DFBInputDeviceCapabilities caps; + caps = DICAPS_BUTTONS | DICAPS_AXES; + result = fb->CreateInputEventBuffer(fb, caps, DFB_TRUE, &eventBuffer); + if (result != DFB_OK) { + DirectFBError("QDirectFBMouseHandler: " + "Unable to create input event buffer", result); + return; + } + + int fd; + result = eventBuffer->CreateFileDescriptor(eventBuffer, &fd); + if (result != DFB_OK) { + DirectFBError("QDirectFBMouseHandler: " + "Unable to create file descriptor", result); + return; + } + + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + + // DirectFB seems to assume that the mouse always starts centered + prevPoint = QPoint(screen->deviceWidth() / 2, screen->deviceHeight() / 2); + prevbuttons = Qt::NoButton; + memset(&event, 0, sizeof(event)); + bytesRead = 0; + + mouseNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); + connect(mouseNotifier, SIGNAL(activated(int)),this, SLOT(readMouseData())); + setEnabled(true); +} + +QDirectFBMouseHandlerPrivate::~QDirectFBMouseHandlerPrivate() +{ + if (eventBuffer) + eventBuffer->Release(eventBuffer); +} + +void QDirectFBMouseHandlerPrivate::setEnabled(bool on) +{ + if (mouseNotifier->isEnabled() != on) { +#ifndef QT_NO_DIRECTFB_LAYER + DFBResult result; + result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::QDirectFBScreenCursor: " + "Unable to set cooperative level", result); + } + result = layer->EnableCursor(layer, on ? 1 : 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::QDirectFBScreenCursor: " + "Unable to enable cursor", result); + } + + result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to set cooperative level", result); + } + + layer->SetCooperativeLevel(layer, DLSCL_SHARED); +#endif + mouseNotifier->setEnabled(on); + } +} + +void QDirectFBMouseHandlerPrivate::readMouseData() +{ + if (!QScreen::instance()) + return; + + for (;;) { + // GetEvent returns DFB_UNSUPPORTED after CreateFileDescriptor(). + // This seems stupid and I really hope it's a bug which will be fixed. + + // DFBResult ret = eventBuffer->GetEvent(eventBuffer, &event); + + char *buf = reinterpret_cast<char*>(&event); + int ret = ::read(mouseNotifier->socket(), + buf + bytesRead, sizeof(DFBEvent) - bytesRead); + if (ret == -1) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + return; + qWarning("QDirectFBMouseHandlerPrivate::readMouseData(): %s", + strerror(errno)); + return; + } + + Q_ASSERT(ret >= 0); + bytesRead += ret; + if (bytesRead < sizeof(DFBEvent)) + break; + bytesRead = 0; + + Q_ASSERT(event.clazz == DFEC_INPUT); + + const DFBInputEvent input = event.input; + int x = prevPoint.x(); + int y = prevPoint.y(); + int wheel = 0; + + if (input.type == DIET_AXISMOTION) { +#if defined(QT_NO_DIRECTFB_LAYER) || defined(QT_DIRECTFB_WINDOW_AS_CURSOR) + if (input.flags & DIEF_AXISABS) { + switch (input.axis) { + case DIAI_X: x = input.axisabs; break; + case DIAI_Y: y = input.axisabs; break; + default: + qWarning("QDirectFBMouseHandlerPrivate::readMouseData: " + "unknown axis (absolute) %d", input.axis); + break; + } + } else if (input.flags & DIEF_AXISREL) { + switch (input.axis) { + case DIAI_X: x += input.axisrel; break; + case DIAI_Y: y += input.axisrel; break; + case DIAI_Z: wheel = -120 * input.axisrel; break; + default: + qWarning("QDirectFBMouseHandlerPrivate::readMouseData: " + "unknown axis (releative) %d", input.axis); + } + } +#else + if (input.axis == DIAI_X || input.axis == DIAI_Y) { + DFBResult result = layer->GetCursorPosition(layer, &x, &y); + if (result != DFB_OK) { + DirectFBError("QDirectFBMouseHandler::readMouseData", + result); + } + } else if (input.axis == DIAI_Z) { + Q_ASSERT(input.flags & DIEF_AXISREL); + wheel = input.axisrel; + wheel *= -120; + } +#endif + } + + Qt::MouseButtons buttons = Qt::NoButton; + if (input.flags & DIEF_BUTTONS) { + if (input.buttons & DIBM_LEFT) + buttons |= Qt::LeftButton; + if (input.buttons & DIBM_MIDDLE) + buttons |= Qt::MidButton; + if (input.buttons & DIBM_RIGHT) + buttons |= Qt::RightButton; + } + + QPoint p = QPoint(x, y); + handler->limitToScreen(p); + + if (p == prevPoint && wheel == 0 && buttons == prevbuttons) + continue; + + prevPoint = p; + prevbuttons = buttons; + + handler->mouseChanged(p, buttons, wheel); + } +} + +QDirectFBMouseHandler::QDirectFBMouseHandler(const QString &driver, + const QString &device) + : QWSMouseHandler(driver, device) +{ + d = new QDirectFBMouseHandlerPrivate(this); +} + +QDirectFBMouseHandler::~QDirectFBMouseHandler() +{ + delete d; +} + +void QDirectFBMouseHandler::suspend() +{ + d->setEnabled(false); +} + +void QDirectFBMouseHandler::resume() +{ + d->setEnabled(true); +} + +QT_END_NAMESPACE +#include "qdirectfbmouse.moc" +#endif // QT_NO_QWS_DIRECTFB + + diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h new file mode 100644 index 0000000000..ac0fcadfaa --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTFBMOUSE_H +#define QDIRECTFBMOUSE_H + +#include <qglobal.h> +#include <QtGui/qmouse_qws.h> + +#ifndef QT_NO_QWS_DIRECTFB + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +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; +}; + +QT_END_NAMESPACE + +QT_END_HEADER +#endif // QT_NO_QWS_DIRECTFB +#endif // QDIRECTFBMOUSE_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp new file mode 100644 index 0000000000..10f1bb3f46 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbscreen.h" +#include "qdirectfbpaintdevice.h" +#include "qdirectfbpaintengine.h" + +#ifndef QT_NO_QWS_DIRECTFB + +QT_BEGIN_NAMESPACE + +QDirectFBPaintDevice::QDirectFBPaintDevice(QDirectFBScreen *scr) + : QCustomRasterPaintDevice(0), dfbSurface(0), screen(scr), + bpl(-1), lockFlgs(DFBSurfaceLockFlags(0)), mem(0), engine(0), imageFormat(QImage::Format_Invalid) +{ +#ifdef QT_DIRECTFB_SUBSURFACE + subSurface = 0; + syncPending = false; +#endif +} + +QDirectFBPaintDevice::~QDirectFBPaintDevice() +{ + if (QDirectFBScreen::instance()) { + unlockSurface(); +#ifdef QT_DIRECTFB_SUBSURFACE + releaseSubSurface(); +#endif + if (dfbSurface) { + screen->releaseDFBSurface(dfbSurface); + } + } + delete engine; +} + +IDirectFBSurface *QDirectFBPaintDevice::directFBSurface() const +{ + return dfbSurface; +} + +bool QDirectFBPaintDevice::lockSurface(DFBSurfaceLockFlags lockFlags) +{ + if (lockFlgs && (lockFlags & ~lockFlgs)) + unlockSurface(); + if (!mem) { + Q_ASSERT(dfbSurface); +#ifdef QT_DIRECTFB_SUBSURFACE + if (!subSurface) { + DFBResult result; + subSurface = screen->getSubSurface(dfbSurface, QRect(), QDirectFBScreen::TrackSurface, &result); + if (result != DFB_OK || !subSurface) { + DirectFBError("Couldn't create sub surface", result); + return false; + } + } + IDirectFBSurface *surface = subSurface; +#else + IDirectFBSurface *surface = dfbSurface; +#endif + Q_ASSERT(surface); + mem = QDirectFBScreen::lockSurface(surface, lockFlags, &bpl); + lockFlgs = lockFlags; + Q_ASSERT(mem); + Q_ASSERT(bpl > 0); + const QSize s = size(); + lockedImage = QImage(mem, s.width(), s.height(), bpl, + QDirectFBScreen::getImageFormat(dfbSurface)); + return true; + } +#ifdef QT_DIRECTFB_SUBSURFACE + if (syncPending) { + syncPending = false; + screen->waitIdle(); + } +#endif + return false; +} + +void QDirectFBPaintDevice::unlockSurface() +{ + if (QDirectFBScreen::instance() && lockFlgs) { +#ifdef QT_DIRECTFB_SUBSURFACE + IDirectFBSurface *surface = subSurface; +#else + IDirectFBSurface *surface = dfbSurface; +#endif + if (surface) { + surface->Unlock(surface); + lockFlgs = static_cast<DFBSurfaceLockFlags>(0); + mem = 0; + } + } +} + +void *QDirectFBPaintDevice::memory() const +{ + return mem; +} + +QImage::Format QDirectFBPaintDevice::format() const +{ + return imageFormat; +} + +int QDirectFBPaintDevice::bytesPerLine() const +{ + Q_ASSERT(!mem || bpl != -1); + return bpl; +} + +QSize QDirectFBPaintDevice::size() const +{ + int w, h; + dfbSurface->GetSize(dfbSurface, &w, &h); + return QSize(w, h); +} + +int QDirectFBPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + if (!dfbSurface) + return 0; + + switch (metric) { + case QPaintDevice::PdmWidth: + case QPaintDevice::PdmHeight: + return (metric == PdmWidth ? size().width() : size().height()); + case QPaintDevice::PdmWidthMM: + return (size().width() * 1000) / dotsPerMeterX(); + case QPaintDevice::PdmHeightMM: + return (size().height() * 1000) / dotsPerMeterY(); + case QPaintDevice::PdmPhysicalDpiX: + case QPaintDevice::PdmDpiX: + return (dotsPerMeterX() * 254) / 10000; // 0.0254 meters-per-inch + case QPaintDevice::PdmPhysicalDpiY: + case QPaintDevice::PdmDpiY: + return (dotsPerMeterY() * 254) / 10000; // 0.0254 meters-per-inch + case QPaintDevice::PdmDepth: + return QDirectFBScreen::depth(imageFormat); + case QPaintDevice::PdmNumColors: { + if (!lockedImage.isNull()) + return lockedImage.colorCount(); + + DFBResult result; + IDirectFBPalette *palette = 0; + unsigned int numColors = 0; + + result = dfbSurface->GetPalette(dfbSurface, &palette); + if ((result != DFB_OK) || !palette) + return 0; + + result = palette->GetSize(palette, &numColors); + palette->Release(palette); + if (result != DFB_OK) + return 0; + + return numColors; + } + default: + qCritical("QDirectFBPaintDevice::metric(): Unhandled metric!"); + return 0; + } +} + +QPaintEngine *QDirectFBPaintDevice::paintEngine() const +{ + return engine; +} + +#ifdef QT_DIRECTFB_SUBSURFACE +void QDirectFBPaintDevice::releaseSubSurface() +{ + Q_ASSERT(QDirectFBScreen::instance()); + if (subSurface) { + unlockSurface(); + screen->releaseDFBSurface(subSurface); + subSurface = 0; + } +} +#endif + +QT_END_NAMESPACE + +#endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h new file mode 100644 index 0000000000..71a7a8e104 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTFBPAINTDEVICE_H +#define QDIRECTFBPAINTDEVICE_H + +#include <private/qpaintengine_raster_p.h> +#include "qdirectfbscreen.h" + +#ifndef QT_NO_QWS_DIRECTFB + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +// Inherited by both window surface and pixmap +class QDirectFBPaintEngine; +class QDirectFBPaintDevice : public QCustomRasterPaintDevice +{ +public: + ~QDirectFBPaintDevice(); + + virtual IDirectFBSurface *directFBSurface() const; + + bool lockSurface(DFBSurfaceLockFlags lockFlags); + void unlockSurface(); + + // Reimplemented from QCustomRasterPaintDevice: + void *memory() const; + QImage::Format format() const; + int bytesPerLine() const; + QSize size() const; + int metric(QPaintDevice::PaintDeviceMetric metric) const; + DFBSurfaceLockFlags lockFlags() const { return lockFlgs; } + QPaintEngine *paintEngine() const; +protected: + QDirectFBPaintDevice(QDirectFBScreen *scr); + inline int dotsPerMeterX() const + { + return (screen->deviceWidth() * 1000) / screen->physicalWidth(); + } + inline int dotsPerMeterY() const + { + return (screen->deviceHeight() * 1000) / screen->physicalHeight(); + } + + IDirectFBSurface *dfbSurface; +#ifdef QT_DIRECTFB_SUBSURFACE + void releaseSubSurface(); + IDirectFBSurface *subSurface; + friend class QDirectFBPaintEnginePrivate; + bool syncPending; +#endif + QImage lockedImage; + QDirectFBScreen *screen; + int bpl; + DFBSurfaceLockFlags lockFlgs; + uchar *mem; + QDirectFBPaintEngine *engine; + QImage::Format imageFormat; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_QWS_DIRECTFB +#endif //QDIRECTFBPAINTDEVICE_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp new file mode 100644 index 0000000000..6d6fb02a68 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -0,0 +1,1430 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbpaintengine.h" + +#ifndef QT_NO_QWS_DIRECTFB + +#include "qdirectfbwindowsurface.h" +#include "qdirectfbscreen.h" +#include "qdirectfbpixmap.h" +#include <directfb.h> +#include <qtransform.h> +#include <qvarlengtharray.h> +#include <qcache.h> +#include <qmath.h> +#include <private/qpixmapdata_p.h> +#include <private/qpixmap_raster_p.h> +#include <private/qimagepixmapcleanuphooks_p.h> + + +QT_BEGIN_NAMESPACE + +class SurfaceCache; +class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate +{ +public: + enum TransformationTypeFlags { + Matrix_NegativeScale = 0x100, + Matrix_RectsUnsupported = (QTransform::TxRotate|QTransform::TxShear|QTransform::TxProject), + Matrix_BlitsUnsupported = (Matrix_NegativeScale|Matrix_RectsUnsupported) + }; + + inline static uint getTransformationType(const QTransform &transform) + { + int ret = transform.type(); + if (qMin(transform.m11(), transform.m22()) < 0) { + ret |= QDirectFBPaintEnginePrivate::Matrix_NegativeScale; + } + return ret; + } + + enum CompositionModeStatus { + PorterDuff_None = 0x0, + PorterDuff_Supported = 0x1, + PorterDuff_PremultiplyColors = 0x2, + PorterDuff_AlwaysBlend = 0x4 + }; + + enum ClipType { + ClipUnset, + NoClip, + RectClip, + RegionClip, + ComplexClip + }; + + QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p); + ~QDirectFBPaintEnginePrivate(); + + inline void setTransform(const QTransform &transforma); + inline void setPen(const QPen &pen); + inline void setCompositionMode(QPainter::CompositionMode mode); + inline void setRenderHints(QPainter::RenderHints hints); + + inline void setDFBColor(const QColor &color); + + inline void lock(); + inline void unlock(); + static inline void unlock(QDirectFBPaintDevice *device); + + inline bool isSimpleBrush(const QBrush &brush) const; + + void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos, const QTransform &pixmapTransform); + void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src); + + inline bool supportsStretchBlit() const; + + inline void updateClip(); + virtual void systemStateChanged(); + + static IDirectFBSurface *getSurface(const QImage &img, bool *release); + +#ifdef QT_DIRECTFB_IMAGECACHE + static inline int cacheCost(const QImage &img) { return img.width() * img.height() * img.depth() / 8; } +#endif + + enum BlitFlag { + HasAlpha = 0x1, + Premultiplied = 0x2 + }; + void prepareForBlit(uint blitFlags); + + IDirectFBSurface *surface; + + bool antialiased; + bool simplePen; + + uint transformationType; // this is QTransform::type() + Matrix_NegativeScale if qMin(transform.m11(), transform.m22()) < 0 + + SurfaceCache *surfaceCache; + IDirectFB *fb; + quint8 opacity; + + ClipType clipType; + QDirectFBPaintDevice *dfbDevice; + uint compositionModeStatus; + bool isPremultiplied; + + bool inClip; + QRect currentClip; + + QDirectFBPaintEngine *q; +}; + +class SurfaceCache +{ +public: + SurfaceCache() : surface(0), buffer(0), bufsize(0) {} + ~SurfaceCache() { clear(); } + IDirectFBSurface *getSurface(const uint *buf, int size); + void clear(); +private: + IDirectFBSurface *surface; + uint *buffer; + int bufsize; +}; + + +#ifdef QT_DIRECTFB_IMAGECACHE +QT_BEGIN_INCLUDE_NAMESPACE +#include <private/qimage_p.h> +QT_END_INCLUDE_NAMESPACE +struct CachedImage +{ + IDirectFBSurface *surface; + ~CachedImage() + { + if (surface && QDirectFBScreen::instance()) { + QDirectFBScreen::instance()->releaseDFBSurface(surface); + } + } +}; +static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB +#endif + +#define VOID_ARG() static_cast<bool>(false) +enum PaintOperation { + DRAW_RECTS = 0x0001, DRAW_LINES = 0x0002, DRAW_IMAGE = 0x0004, + DRAW_PIXMAP = 0x0008, DRAW_TILED_PIXMAP = 0x0010, STROKE_PATH = 0x0020, + DRAW_PATH = 0x0040, DRAW_POINTS = 0x0080, DRAW_ELLIPSE = 0x0100, + DRAW_POLYGON = 0x0200, DRAW_TEXT = 0x0400, FILL_PATH = 0x0800, + FILL_RECT = 0x1000, DRAW_COLORSPANS = 0x2000, DRAW_ROUNDED_RECT = 0x4000, + DRAW_STATICTEXT = 0x8000, ALL = 0xffff +}; + +enum { RasterWarn = 1, RasterDisable = 2 }; +static inline uint rasterFallbacksMask(PaintOperation op) +{ + uint ret = 0; +#ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS + if (op & QT_DIRECTFB_WARN_ON_RASTERFALLBACKS) + ret |= RasterWarn; +#endif +#ifdef QT_DIRECTFB_DISABLE_RASTERFALLBACKS + if (op & QT_DIRECTFB_DISABLE_RASTERFALLBACKS) + ret |= RasterDisable; +#endif + static int warningMask = -1; + static int disableMask = -1; + if (warningMask < 0) { + struct { + const char *name; + PaintOperation operation; + } const operations[] = { + { "DRAW_RECTS", DRAW_RECTS }, + { "DRAW_LINES", DRAW_LINES }, + { "DRAW_IMAGE", DRAW_IMAGE }, + { "DRAW_PIXMAP", DRAW_PIXMAP }, + { "DRAW_TILED_PIXMAP", DRAW_TILED_PIXMAP }, + { "STROKE_PATH", STROKE_PATH }, + { "DRAW_PATH", DRAW_PATH }, + { "DRAW_POINTS", DRAW_POINTS }, + { "DRAW_ELLIPSE", DRAW_ELLIPSE }, + { "DRAW_POLYGON", DRAW_POLYGON }, + { "DRAW_TEXT", DRAW_TEXT }, + { "FILL_PATH", FILL_PATH }, + { "FILL_RECT", FILL_RECT }, + { "DRAW_COLORSPANS", DRAW_COLORSPANS }, + { "DRAW_ROUNDED_RECT", DRAW_ROUNDED_RECT }, + { "ALL", ALL }, + { 0, ALL } + }; + + QStringList warning = QString::fromLatin1(qgetenv("QT_DIRECTFB_WARN_ON_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'), + QString::SkipEmptyParts); + QStringList disable = QString::fromLatin1(qgetenv("QT_DIRECTFB_DISABLE_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'), + QString::SkipEmptyParts); + warningMask = 0; + disableMask = 0; + if (!warning.isEmpty() || !disable.isEmpty()) { + for (int i=0; operations[i].name; ++i) { + const QString name = QString::fromLatin1(operations[i].name); + int idx = warning.indexOf(name); + if (idx != -1) { + warningMask |= operations[i].operation; + warning.erase(warning.begin() + idx); + } + idx = disable.indexOf(name); + if (idx != -1) { + disableMask |= operations[i].operation; + disable.erase(disable.begin() + idx); + } + } + } + if (!warning.isEmpty()) { + qWarning("QDirectFBPaintEngine QT_DIRECTFB_WARN_ON_RASTERFALLBACKS Unknown operation(s): %s", + qPrintable(warning.join(QLatin1String("|")))); + } + if (!disable.isEmpty()) { + qWarning("QDirectFBPaintEngine QT_DIRECTFB_DISABLE_RASTERFALLBACKS Unknown operation(s): %s", + qPrintable(disable.join(QLatin1String("|")))); + } + } + if (op & warningMask) + ret |= RasterWarn; + if (op & disableMask) + ret |= RasterDisable; + return ret; +} + +template <typename device, typename T1, typename T2, typename T3> +static void rasterFallbackWarn(const char *msg, const char *func, const device *dev, + uint transformationType, bool simplePen, + uint clipType, uint compositionModeStatus, + const char *nameOne, const T1 &one, + const char *nameTwo, const T2 &two, + const char *nameThree, const T3 &three); + +#define RASTERFALLBACK(op, one, two, three) \ + { \ + static const uint rasterFallbacks = rasterFallbacksMask(op); \ + switch (rasterFallbacks) { \ + case 0: break; \ + case RasterWarn: \ + rasterFallbackWarn("Falling back to raster engine for", \ + __FUNCTION__, \ + state()->painter->device(), \ + d_func()->transformationType, \ + d_func()->simplePen, \ + d_func()->clipType, \ + d_func()->compositionModeStatus, \ + #one, one, #two, two, #three, three); \ + break; \ + case RasterDisable|RasterWarn: \ + rasterFallbackWarn("Disabled raster engine operation", \ + __FUNCTION__, \ + state()->painter->device(), \ + d_func()->transformationType, \ + d_func()->simplePen, \ + d_func()->clipType, \ + d_func()->compositionModeStatus, \ + #one, one, #two, two, #three, three); \ + case RasterDisable: \ + return; \ + } \ + } + +template <class T> +static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface); +template <class T> +static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface); +template <class T> +static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface); + +#define CLIPPED_PAINT(operation) { \ + d->unlock(); \ + DFBRegion clipRegion; \ + switch (d->clipType) { \ + case QDirectFBPaintEnginePrivate::NoClip: \ + case QDirectFBPaintEnginePrivate::RectClip: \ + operation; \ + break; \ + case QDirectFBPaintEnginePrivate::RegionClip: { \ + Q_ASSERT(d->clip()); \ + const QVector<QRect> cr = d->clip()->clipRegion.rects(); \ + const int size = cr.size(); \ + for (int i=0; i<size; ++i) { \ + d->currentClip = cr.at(i); \ + clipRegion.x1 = d->currentClip.x(); \ + clipRegion.y1 = d->currentClip.y(); \ + clipRegion.x2 = d->currentClip.right(); \ + clipRegion.y2 = d->currentClip.bottom(); \ + d->surface->SetClip(d->surface, &clipRegion); \ + operation; \ + } \ + d->updateClip(); \ + break; } \ + case QDirectFBPaintEnginePrivate::ComplexClip: \ + case QDirectFBPaintEnginePrivate::ClipUnset: \ + qFatal("CLIPPED_PAINT internal error %d", d->clipType); \ + break; \ + } \ + } + + +QDirectFBPaintEngine::QDirectFBPaintEngine(QPaintDevice *device) + : QRasterPaintEngine(*(new QDirectFBPaintEnginePrivate(this)), device) +{ +} + +QDirectFBPaintEngine::~QDirectFBPaintEngine() +{ +} + +bool QDirectFBPaintEngine::begin(QPaintDevice *device) +{ + Q_D(QDirectFBPaintEngine); + if (device->devType() == QInternal::CustomRaster) { + d->dfbDevice = static_cast<QDirectFBPaintDevice*>(device); + } else if (device->devType() == QInternal::Pixmap) { + QPixmapData *data = static_cast<QPixmap*>(device)->pixmapData(); + Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); + QDirectFBPixmapData *dfbPixmapData = static_cast<QDirectFBPixmapData*>(data); + QDirectFBPaintEnginePrivate::unlock(dfbPixmapData); + d->dfbDevice = static_cast<QDirectFBPaintDevice*>(dfbPixmapData); + } + + if (d->dfbDevice) + d->surface = d->dfbDevice->directFBSurface(); + + if (!d->surface) { + qFatal("QDirectFBPaintEngine used on an invalid device: 0x%x", + device->devType()); + } + d->isPremultiplied = QDirectFBScreen::isPremultiplied(d->dfbDevice->format()); + + d->prepare(d->dfbDevice); + gccaps = AllFeatures; + d->setCompositionMode(state()->composition_mode); + + return QRasterPaintEngine::begin(device); +} + +bool QDirectFBPaintEngine::end() +{ + Q_D(QDirectFBPaintEngine); + d->unlock(); + d->dfbDevice = 0; +#if (Q_DIRECTFB_VERSION >= 0x010000) + d->surface->ReleaseSource(d->surface); +#endif + d->currentClip = QRect(); + d->surface->SetClip(d->surface, NULL); + d->surface = 0; + return QRasterPaintEngine::end(); +} + +void QDirectFBPaintEngine::clipEnabledChanged() +{ + Q_D(QDirectFBPaintEngine); + QRasterPaintEngine::clipEnabledChanged(); + d->updateClip(); +} + +void QDirectFBPaintEngine::penChanged() +{ + Q_D(QDirectFBPaintEngine); + d->setPen(state()->pen); + + QRasterPaintEngine::penChanged(); +} + +void QDirectFBPaintEngine::opacityChanged() +{ + Q_D(QDirectFBPaintEngine); + d->opacity = quint8(state()->opacity * 255); + QRasterPaintEngine::opacityChanged(); +} + +void QDirectFBPaintEngine::compositionModeChanged() +{ + Q_D(QDirectFBPaintEngine); + d->setCompositionMode(state()->compositionMode()); + QRasterPaintEngine::compositionModeChanged(); +} + +void QDirectFBPaintEngine::renderHintsChanged() +{ + Q_D(QDirectFBPaintEngine); + d->setRenderHints(state()->renderHints); + QRasterPaintEngine::renderHintsChanged(); +} + +void QDirectFBPaintEngine::transformChanged() +{ + Q_D(QDirectFBPaintEngine); + d->setTransform(state()->matrix); + QRasterPaintEngine::transformChanged(); +} + +void QDirectFBPaintEngine::setState(QPainterState *state) +{ + Q_D(QDirectFBPaintEngine); + QRasterPaintEngine::setState(state); + d->setPen(state->pen); + d->opacity = quint8(state->opacity * 255); + d->setCompositionMode(state->compositionMode()); + d->setTransform(state->transform()); + d->setRenderHints(state->renderHints); + if (d->surface) + d->updateClip(); +} + +void QDirectFBPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) +{ + Q_D(QDirectFBPaintEngine); + const bool wasInClip = d->inClip; + d->inClip = true; + QRasterPaintEngine::clip(path, op); + if (!wasInClip) { + d->inClip = false; + d->updateClip(); + } +} + +void QDirectFBPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) +{ + Q_D(QDirectFBPaintEngine); + const bool wasInClip = d->inClip; + d->inClip = true; + QRasterPaintEngine::clip(region, op); + if (!wasInClip) { + d->inClip = false; + d->updateClip(); + } +} + +void QDirectFBPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) +{ + Q_D(QDirectFBPaintEngine); + const bool wasInClip = d->inClip; + d->inClip = true; + QRasterPaintEngine::clip(rect, op); + if (!wasInClip) { + d->inClip = false; + d->updateClip(); + } +} + +void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount) +{ + Q_D(QDirectFBPaintEngine); + const QPen &pen = state()->pen; + const QBrush &brush = state()->brush; + if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen) + return; + + if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) + || !d->simplePen + || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip + || !d->isSimpleBrush(brush) + || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { + RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG()); + d->lock(); + QRasterPaintEngine::drawRects(rects, rectCount); + return; + } + + if (brush.style() != Qt::NoBrush) { + d->setDFBColor(brush.color()); + CLIPPED_PAINT(QT_PREPEND_NAMESPACE(fillRects<QRect>)(rects, rectCount, state()->matrix, d->surface)); + } + + if (pen.style() != Qt::NoPen) { + d->setDFBColor(pen.color()); + CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawRects<QRect>)(rects, rectCount, state()->matrix, d->surface)); + } +} + +void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount) +{ + Q_D(QDirectFBPaintEngine); + const QPen &pen = state()->pen; + const QBrush &brush = state()->brush; + if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen) + return; + + if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) + || !d->simplePen + || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip + || !d->isSimpleBrush(brush) + || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { + RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG()); + d->lock(); + QRasterPaintEngine::drawRects(rects, rectCount); + return; + } + + if (brush.style() != Qt::NoBrush) { + d->setDFBColor(brush.color()); + CLIPPED_PAINT(fillRects<QRectF>(rects, rectCount, state()->matrix, d->surface)); + } + + if (pen.style() != Qt::NoPen) { + d->setDFBColor(pen.color()); + CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawRects<QRectF>)(rects, rectCount, state()->matrix, d->surface)); + } +} + +void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount) +{ + Q_D(QDirectFBPaintEngine); + + const QPen &pen = state()->pen; + if (!d->simplePen + || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip + || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { + RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG()); + d->lock(); + QRasterPaintEngine::drawLines(lines, lineCount); + return; + } + + if (pen.style() != Qt::NoPen) { + d->setDFBColor(pen.color()); + CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLine>)(lines, lineCount, state()->matrix, d->surface)); + } +} + +void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount) +{ + Q_D(QDirectFBPaintEngine); + + const QPen &pen = state()->pen; + if (!d->simplePen + || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip + || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { + RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG()); + d->lock(); + QRasterPaintEngine::drawLines(lines, lineCount); + return; + } + + if (pen.style() != Qt::NoPen) { + d->setDFBColor(pen.color()); + CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLineF>)(lines, lineCount, state()->matrix, d->surface)); + } +} + +void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, + const QRectF &sr, + Qt::ImageConversionFlags flags) +{ + Q_D(QDirectFBPaintEngine); + Q_UNUSED(flags); + + /* This is hard to read. The way it works is like this: + + - If you do not have support for preallocated surfaces and do not use an + image cache we always fall back to raster engine. + + - If it's rotated/sheared/mirrored (negative scale) or we can't + clip it we fall back to raster engine. + + - If we don't cache the image, but we do have support for + preallocated surfaces we fall back to the raster engine if the + image is in a format DirectFB can't handle. + + - If we do cache the image but don't have support for preallocated + images and the cost of caching the image (bytes used) is higher + than the max image cache size we fall back to raster engine. + */ + +#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE + if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported) + || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) + || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) + || (!d->supportsStretchBlit() && state()->matrix.mapRect(r).size() != sr.size()) +#ifndef QT_DIRECTFB_IMAGECACHE + || (QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN) +#elif defined QT_NO_DIRECTFB_PREALLOCATED + || (QDirectFBPaintEnginePrivate::cacheCost(image) > imageCache.maxCost()) +#endif + ) +#endif + { + RASTERFALLBACK(DRAW_IMAGE, r, image.size(), sr); + d->lock(); + QRasterPaintEngine::drawImage(r, image, sr, flags); + return; + } +#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE + bool release; + IDirectFBSurface *imgSurface = d->getSurface(image, &release); + uint blitFlags = 0; + if (image.hasAlphaChannel()) + blitFlags |= QDirectFBPaintEnginePrivate::HasAlpha; + if (QDirectFBScreen::isPremultiplied(image.format())) + blitFlags |= QDirectFBPaintEnginePrivate::Premultiplied; + d->prepareForBlit(blitFlags); + CLIPPED_PAINT(d->blit(r, imgSurface, sr)); + if (release) { +#if (Q_DIRECTFB_VERSION >= 0x010000) + d->surface->ReleaseSource(d->surface); +#endif + imgSurface->Release(imgSurface); + } +#endif +} + +void QDirectFBPaintEngine::drawImage(const QPointF &p, const QImage &img) +{ + drawImage(QRectF(p, img.size()), img, img.rect()); +} + +void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, + const QRectF &sr) +{ + Q_D(QDirectFBPaintEngine); + + if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) { + RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); + d->lock(); + QRasterPaintEngine::drawPixmap(r, pixmap, sr); + } else { + QPixmapData *data = pixmap.pixmapData(); + Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); + QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); + if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported) + || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) + || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) + || (!d->supportsStretchBlit() && state()->matrix.mapRect(r).size() != sr.size())) { + RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); + const QImage *img = dfbData->buffer(); + d->lock(); + QRasterPaintEngine::drawImage(r, *img, sr); + } else { + QDirectFBPaintEnginePrivate::unlock(dfbData); + IDirectFBSurface *s = dfbData->directFBSurface(); + uint blitFlags = 0; + if (pixmap.hasAlphaChannel()) + blitFlags |= QDirectFBPaintEnginePrivate::HasAlpha; + if (QDirectFBScreen::isPremultiplied(dfbData->pixelFormat())) + blitFlags |= QDirectFBPaintEnginePrivate::Premultiplied; + + d->prepareForBlit(blitFlags); + CLIPPED_PAINT(d->blit(r, s, sr)); + } + } +} + +void QDirectFBPaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm) +{ + drawPixmap(QRectF(p, pm.size()), pm, pm.rect()); +} + +void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r, + const QPixmap &pixmap, + const QPointF &offset) +{ + Q_D(QDirectFBPaintEngine); + if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) { + RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset); + d->lock(); + QRasterPaintEngine::drawTiledPixmap(r, pixmap, offset); + } else if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported) + || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) + || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) + || (!d->supportsStretchBlit() && state()->matrix.isScaling())) { + RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset); + QPixmapData *pixmapData = pixmap.pixmapData(); + Q_ASSERT(pixmapData->classId() == QPixmapData::DirectFBClass); + QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(pixmapData); + const QImage *img = dfbData->buffer(); + d->lock(); + QRasterPixmapData *data = new QRasterPixmapData(QPixmapData::PixmapType); + data->fromImage(*img, Qt::AutoColor); + const QPixmap pix(data); + QRasterPaintEngine::drawTiledPixmap(r, pix, offset); + } else { + QTransform transform(state()->matrix); + CLIPPED_PAINT(d->drawTiledPixmap(r, pixmap, offset, transform)); + } +} + + +void QDirectFBPaintEngine::stroke(const QVectorPath &path, const QPen &pen) +{ + RASTERFALLBACK(STROKE_PATH, path, VOID_ARG(), VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::stroke(path, pen); +} + +void QDirectFBPaintEngine::drawPath(const QPainterPath &path) +{ + RASTERFALLBACK(DRAW_PATH, path, VOID_ARG(), VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawPath(path); +} + +void QDirectFBPaintEngine::drawPoints(const QPointF *points, int pointCount) +{ + RASTERFALLBACK(DRAW_POINTS, pointCount, VOID_ARG(), VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawPoints(points, pointCount); +} + +void QDirectFBPaintEngine::drawPoints(const QPoint *points, int pointCount) +{ + RASTERFALLBACK(DRAW_POINTS, pointCount, VOID_ARG(), VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawPoints(points, pointCount); +} + +void QDirectFBPaintEngine::drawEllipse(const QRectF &rect) +{ + RASTERFALLBACK(DRAW_ELLIPSE, rect, VOID_ARG(), VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawEllipse(rect); +} + +void QDirectFBPaintEngine::drawPolygon(const QPointF *points, int pointCount, + PolygonDrawMode mode) +{ + RASTERFALLBACK(DRAW_POLYGON, pointCount, mode, VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawPolygon(points, pointCount, mode); +} + +void QDirectFBPaintEngine::drawPolygon(const QPoint *points, int pointCount, + PolygonDrawMode mode) +{ + RASTERFALLBACK(DRAW_POLYGON, pointCount, mode, VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawPolygon(points, pointCount, mode); +} + +void QDirectFBPaintEngine::drawTextItem(const QPointF &p, + const QTextItem &textItem) +{ + RASTERFALLBACK(DRAW_TEXT, p, textItem.text(), VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawTextItem(p, textItem); +} + +void QDirectFBPaintEngine::fill(const QVectorPath &path, const QBrush &brush) +{ + if (brush.style() == Qt::NoBrush) + return; + RASTERFALLBACK(FILL_PATH, path, brush, VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::fill(path, brush); +} + +void QDirectFBPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode) +{ + RASTERFALLBACK(DRAW_ROUNDED_RECT, rect, xrad, yrad); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawRoundedRect(rect, xrad, yrad, mode); +} + +void QDirectFBPaintEngine::drawStaticTextItem(QStaticTextItem *item) +{ + RASTERFALLBACK(DRAW_STATICTEXT, item, VOID_ARG(), VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawStaticTextItem(item); +} + +void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) +{ + Q_D(QDirectFBPaintEngine); + if (brush.style() == Qt::NoBrush) + return; + if (d->clipType != QDirectFBPaintEnginePrivate::ComplexClip) { + switch (brush.style()) { + case Qt::SolidPattern: { + const QColor color = brush.color(); + if (!color.isValid()) + return; + + if (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported + || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { + break; + } + d->setDFBColor(color); + const QRect r = state()->matrix.mapRect(rect).toRect(); + CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height())); + return; } + + case Qt::TexturePattern: { + const QPointF &brushOrigin = state()->brushOrigin; + const QTransform stateTransform = state()->matrix; + QTransform transform(stateTransform); + transform.translate(brushOrigin.x(), brushOrigin.y()); + transform = brush.transform() * transform; + if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported) + || (QDirectFBPaintEnginePrivate::getTransformationType(transform) & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) + || (!d->supportsStretchBlit() && transform.isScaling())) { + break; + } + + const QPixmap texture = brush.texture(); + if (texture.pixmapData()->classId() != QPixmapData::DirectFBClass) + break; + + CLIPPED_PAINT(d->drawTiledPixmap(stateTransform.mapRect(rect), texture, rect.topLeft() - brushOrigin, transform)); + return; } + default: + break; + } + } + RASTERFALLBACK(FILL_RECT, rect, brush, VOID_ARG()); + d->lock(); + QRasterPaintEngine::fillRect(rect, brush); +} + +void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color) +{ + if (!color.isValid()) + return; + Q_D(QDirectFBPaintEngine); + if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) + || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) + || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) { + RASTERFALLBACK(FILL_RECT, rect, color, VOID_ARG()); + d->lock(); + QRasterPaintEngine::fillRect(rect, color); + } else { + d->setDFBColor(color); + const QRect r = state()->matrix.mapRect(rect).toRect(); + CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height())); + } +} + +void QDirectFBPaintEngine::drawBufferSpan(const uint *buffer, int bufsize, + int x, int y, int length, + uint const_alpha) +{ + Q_D(QDirectFBPaintEngine); + IDirectFBSurface *src = d->surfaceCache->getSurface(buffer, bufsize); + // ### how does this play with setDFBColor + src->SetColor(src, 0, 0, 0, const_alpha); + const DFBRectangle rect = { 0, 0, length, 1 }; + d->surface->Blit(d->surface, src, &rect, x, y); +} + +#ifdef QT_DIRECTFB_IMAGECACHE +static void cachedImageCleanupHook(qint64 key) +{ + delete imageCache.take(key); +} +void QDirectFBPaintEngine::initImageCache(int size) +{ + Q_ASSERT(size >= 0); + imageCache.setMaxCost(size); + QImagePixmapCleanupHooks::instance()->addImageHook(cachedImageCleanupHook); +} + +#endif // QT_DIRECTFB_IMAGECACHE + +// ---- QDirectFBPaintEnginePrivate ---- + + +QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p) + : surface(0), antialiased(false), simplePen(false), + transformationType(0), opacity(255), + clipType(ClipUnset), dfbDevice(0), + compositionModeStatus(0), isPremultiplied(false), inClip(false), q(p) +{ + fb = QDirectFBScreen::instance()->dfb(); + surfaceCache = new SurfaceCache; +} + +QDirectFBPaintEnginePrivate::~QDirectFBPaintEnginePrivate() +{ + delete surfaceCache; +} + +bool QDirectFBPaintEnginePrivate::isSimpleBrush(const QBrush &brush) const +{ + return (brush.style() == Qt::NoBrush) || (brush.style() == Qt::SolidPattern && !antialiased); +} + +void QDirectFBPaintEnginePrivate::lock() +{ + // We will potentially get a new pointer to the buffer after a + // lock so we need to call the base implementation of prepare so + // it updates its rasterBuffer to point to the new buffer address. + Q_ASSERT(dfbDevice); + if (dfbDevice->lockSurface(DSLF_READ|DSLF_WRITE)) { + prepare(dfbDevice); + } +} + +void QDirectFBPaintEnginePrivate::unlock() +{ + Q_ASSERT(dfbDevice); +#ifdef QT_DIRECTFB_SUBSURFACE + dfbDevice->syncPending = true; +#else + QDirectFBPaintEnginePrivate::unlock(dfbDevice); +#endif +} + +void QDirectFBPaintEnginePrivate::unlock(QDirectFBPaintDevice *device) +{ +#ifdef QT_NO_DIRECTFB_SUBSURFACE + Q_ASSERT(device); + device->unlockSurface(); +#else + Q_UNUSED(device); +#endif +} + +void QDirectFBPaintEnginePrivate::setTransform(const QTransform &transform) +{ + transformationType = getTransformationType(transform); + setPen(q->state()->pen); +} + +void QDirectFBPaintEnginePrivate::setPen(const QPen &pen) +{ + if (pen.style() == Qt::NoPen) { + simplePen = true; + } else if (pen.style() == Qt::SolidLine + && !antialiased + && pen.brush().style() == Qt::SolidPattern + && pen.widthF() <= 1.0 + && (transformationType < QTransform::TxScale || pen.isCosmetic())) { + simplePen = true; + } else { + simplePen = false; + } +} + +void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode mode) +{ + if (!surface) + return; + + static const bool forceRasterFallBack = qgetenv("QT_DIRECTFB_FORCE_RASTER").toInt() > 0; + if (forceRasterFallBack) { + compositionModeStatus = PorterDuff_None; + return; + } + + compositionModeStatus = PorterDuff_Supported|PorterDuff_PremultiplyColors|PorterDuff_AlwaysBlend; + switch (mode) { + case QPainter::CompositionMode_Clear: + surface->SetPorterDuff(surface, DSPD_CLEAR); + break; + case QPainter::CompositionMode_Source: + surface->SetPorterDuff(surface, DSPD_SRC); + compositionModeStatus &= ~PorterDuff_AlwaysBlend; + if (!isPremultiplied) + compositionModeStatus &= ~PorterDuff_PremultiplyColors; + break; + case QPainter::CompositionMode_SourceOver: + compositionModeStatus &= ~PorterDuff_AlwaysBlend; + surface->SetPorterDuff(surface, DSPD_SRC_OVER); + break; + case QPainter::CompositionMode_DestinationOver: + surface->SetPorterDuff(surface, DSPD_DST_OVER); + break; + case QPainter::CompositionMode_SourceIn: + surface->SetPorterDuff(surface, DSPD_SRC_IN); + if (!isPremultiplied) + compositionModeStatus &= ~PorterDuff_PremultiplyColors; + break; + case QPainter::CompositionMode_DestinationIn: + surface->SetPorterDuff(surface, DSPD_DST_IN); + break; + case QPainter::CompositionMode_SourceOut: + surface->SetPorterDuff(surface, DSPD_SRC_OUT); + break; + case QPainter::CompositionMode_DestinationOut: + surface->SetPorterDuff(surface, DSPD_DST_OUT); + break; + case QPainter::CompositionMode_Destination: + surface->SetSrcBlendFunction(surface, DSBF_ZERO); + surface->SetDstBlendFunction(surface, DSBF_ONE); + break; +#if (Q_DIRECTFB_VERSION >= 0x010000) + case QPainter::CompositionMode_SourceAtop: + surface->SetPorterDuff(surface, DSPD_SRC_ATOP); + break; + case QPainter::CompositionMode_DestinationAtop: + surface->SetPorterDuff(surface, DSPD_DST_ATOP); + break; + case QPainter::CompositionMode_Plus: + surface->SetPorterDuff(surface, DSPD_ADD); + break; + case QPainter::CompositionMode_Xor: + surface->SetPorterDuff(surface, DSPD_XOR); + break; +#endif + default: + compositionModeStatus = PorterDuff_None; + break; + } +} + +void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints) +{ + const bool old = antialiased; + antialiased = bool(hints & QPainter::Antialiasing); + if (old != antialiased) { + setPen(q->state()->pen); + } +} + +void QDirectFBPaintEnginePrivate::prepareForBlit(uint flags) +{ + DFBSurfaceBlittingFlags blittingFlags = DSBLIT_NOFX; + if (flags & Premultiplied) + blittingFlags |= DSBLIT_SRC_PREMULTIPLY; + if (flags & HasAlpha) + blittingFlags |= DSBLIT_BLEND_ALPHACHANNEL; + if (opacity != 255) { + blittingFlags |= DSBLIT_BLEND_COLORALPHA; + surface->SetColor(surface, 0xff, 0xff, 0xff, opacity); + } + + surface->SetBlittingFlags(surface, blittingFlags); +} + +static inline uint ALPHA_MUL(uint x, uint a) +{ + uint t = x * a; + t = ((t + (t >> 8) + 0x80) >> 8) & 0xff; + return t; +} + +void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color) +{ + Q_ASSERT(surface); + Q_ASSERT(compositionModeStatus & PorterDuff_Supported); + const quint8 alpha = (opacity == 255 ? + color.alpha() : ALPHA_MUL(color.alpha(), opacity)); + QColor col; + if (compositionModeStatus & PorterDuff_PremultiplyColors) { + col = QColor(ALPHA_MUL(color.red(), alpha), + ALPHA_MUL(color.green(), alpha), + ALPHA_MUL(color.blue(), alpha), + alpha); + } else { + col = QColor(color.red(), color.green(), color.blue(), alpha); + } + surface->SetColor(surface, col.red(), col.green(), col.blue(), col.alpha()); + surface->SetDrawingFlags(surface, alpha == 255 && !(compositionModeStatus & PorterDuff_AlwaysBlend) ? DSDRAW_NOFX : DSDRAW_BLEND); +} + +IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, bool *release) +{ +#ifdef QT_NO_DIRECTFB_IMAGECACHE + *release = true; + return QDirectFBScreen::instance()->createDFBSurface(img, img.format(), QDirectFBScreen::DontTrackSurface); +#else + const qint64 key = img.cacheKey(); + *release = false; + if (imageCache.contains(key)) { + return imageCache[key]->surface; + } + + const int cost = cacheCost(img); + const bool cache = cost <= imageCache.maxCost(); + QDirectFBScreen *screen = QDirectFBScreen::instance(); + const QImage::Format format = (img.format() == screen->alphaPixmapFormat() || QDirectFBPixmapData::hasAlphaChannel(img) + ? screen->alphaPixmapFormat() : screen->pixelFormat()); + + IDirectFBSurface *surface = screen->createDFBSurface(img, format, + cache + ? QDirectFBScreen::TrackSurface + : QDirectFBScreen::DontTrackSurface); + if (cache) { + CachedImage *cachedImage = new CachedImage; + const_cast<QImage&>(img).data_ptr()->is_cached = true; + cachedImage->surface = surface; + imageCache.insert(key, cachedImage, cost); + } else { + *release = true; + } + return surface; +#endif +} + + +void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, const QRectF &src) +{ + const QRect sr = src.toRect(); + const QRect dr = q->state()->matrix.mapRect(dest).toRect(); + if (dr.isEmpty()) + return; + const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() }; + DFBResult result; + + if (dr.size() == sr.size()) { + result = surface->Blit(surface, s, &sRect, dr.x(), dr.y()); + } else { + Q_ASSERT(supportsStretchBlit()); + const DFBRectangle dRect = { dr.x(), dr.y(), dr.width(), dr.height() }; + result = surface->StretchBlit(surface, s, &sRect, &dRect); + } + if (result != DFB_OK) + DirectFBError("QDirectFBPaintEngine::drawPixmap()", result); +} + +static inline qreal fixCoord(qreal rect_pos, qreal pixmapSize, qreal offset) +{ + qreal pos = rect_pos - offset; + while (pos > rect_pos) + pos -= pixmapSize; + while (pos + pixmapSize < rect_pos) + pos += pixmapSize; + return pos; +} + +void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, + const QPointF &off, const QTransform &pixmapTransform) +{ + const QTransform &transform = q->state()->matrix; + Q_ASSERT(!(getTransformationType(transform) & Matrix_BlitsUnsupported) && + !(getTransformationType(pixmapTransform) & Matrix_BlitsUnsupported)); + const QRect destinationRect = transform.mapRect(dest).toRect().normalized(); + QRect newClip = destinationRect; + if (!currentClip.isEmpty()) + newClip &= currentClip; + + if (newClip.isNull()) + return; + + const DFBRegion clip = { + newClip.x(), + newClip.y(), + newClip.right(), + newClip.bottom() + }; + surface->SetClip(surface, &clip); + + QPointF offset = pixmapTransform.inverted().map(off); + Q_ASSERT(transform.type() <= QTransform::TxScale); + QPixmapData *data = pixmap.pixmapData(); + Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); + QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); + IDirectFBSurface *sourceSurface = dfbData->directFBSurface(); + uint blitFlags = 0; + if (dfbData->hasAlphaChannel()) + blitFlags |= HasAlpha; + if (QDirectFBScreen::isPremultiplied(dfbData->pixelFormat())) + blitFlags |= Premultiplied; + prepareForBlit(blitFlags); + QDirectFBPaintEnginePrivate::unlock(dfbData); + const QSize pixmapSize = dfbData->size(); + if (transform.isScaling() || pixmapTransform.isScaling()) { + Q_ASSERT(supportsStretchBlit()); + Q_ASSERT(qMin(transform.m11(), transform.m22()) >= 0); + offset.rx() *= transform.m11(); + offset.ry() *= transform.m22(); + + const QSizeF mappedSize(pixmapSize.width() * pixmapTransform.m11(), pixmapSize.height() * pixmapTransform.m22()); + qreal y = fixCoord(destinationRect.y(), mappedSize.height(), offset.y()); + const qreal startX = fixCoord(destinationRect.x(), mappedSize.width(), offset.x()); + while (y <= destinationRect.bottom()) { + qreal x = startX; + while (x <= destinationRect.right()) { + const DFBRectangle destination = { qRound(x), qRound(y), mappedSize.width(), mappedSize.height() }; + surface->StretchBlit(surface, sourceSurface, 0, &destination); + x += mappedSize.width(); + } + y += mappedSize.height(); + } + } else { + qreal y = fixCoord(destinationRect.y(), pixmapSize.height(), offset.y()); + const qreal startX = fixCoord(destinationRect.x(), pixmapSize.width(), offset.x()); + int horizontal = qMax(1, destinationRect.width() / pixmapSize.width()) + 1; + if (startX != destinationRect.x()) + ++horizontal; + int vertical = qMax(1, destinationRect.height() / pixmapSize.height()) + 1; + if (y != destinationRect.y()) + ++vertical; + + const int maxCount = (vertical * horizontal); + QVarLengthArray<DFBRectangle, 16> sourceRects(maxCount); + QVarLengthArray<DFBPoint, 16> points(maxCount); + + int i = 0; + while (y <= destinationRect.bottom()) { + Q_ASSERT(i < maxCount); + qreal x = startX; + while (x <= destinationRect.right()) { + points[i].x = qRound(x); + points[i].y = qRound(y); + sourceRects[i].x = 0; + sourceRects[i].y = 0; + sourceRects[i].w = int(pixmapSize.width()); + sourceRects[i].h = int(pixmapSize.height()); + x += pixmapSize.width(); + ++i; + } + y += pixmapSize.height(); + } + surface->BatchBlit(surface, sourceSurface, sourceRects.constData(), points.constData(), i); + } + + if (currentClip.isEmpty()) { + surface->SetClip(surface, 0); + } else { + const DFBRegion clip = { + currentClip.x(), + currentClip.y(), + currentClip.right(), + currentClip.bottom() + }; + surface->SetClip(surface, &clip); + } +} + +void QDirectFBPaintEnginePrivate::updateClip() +{ + Q_ASSERT(surface); + currentClip = QRect(); + const QClipData *clipData = clip(); + if (!clipData || !clipData->enabled) { + surface->SetClip(surface, NULL); + clipType = NoClip; + } else if (clipData->hasRectClip) { + const DFBRegion r = { + clipData->clipRect.x(), + clipData->clipRect.y(), + clipData->clipRect.right(), + clipData->clipRect.bottom() + }; + surface->SetClip(surface, &r); + currentClip = clipData->clipRect.normalized(); + // ### is this guaranteed to always be normalized? + clipType = RectClip; + } else if (clipData->hasRegionClip) { + clipType = RegionClip; + } else { + clipType = ComplexClip; + } +} + +bool QDirectFBPaintEnginePrivate::supportsStretchBlit() const +{ +#ifdef QT_DIRECTFB_STRETCHBLIT + return !(q->state()->renderHints & QPainter::SmoothPixmapTransform); +#else + return false; +#endif +} + + +void QDirectFBPaintEnginePrivate::systemStateChanged() +{ + QRasterPaintEnginePrivate::systemStateChanged(); + updateClip(); +} + +IDirectFBSurface *SurfaceCache::getSurface(const uint *buf, int size) +{ + if (buffer == buf && bufsize == size) + return surface; + + clear(); + + const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size); + surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface, 0); + if (!surface) + qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface"); + + buffer = const_cast<uint*>(buf); + bufsize = size; + + return surface; +} + +void SurfaceCache::clear() +{ + if (surface && QDirectFBScreen::instance()) + QDirectFBScreen::instance()->releaseDFBSurface(surface); + surface = 0; + buffer = 0; + bufsize = 0; +} + + +static inline QRect mapRect(const QTransform &transform, const QRect &rect) { return transform.mapRect(rect); } +static inline QRect mapRect(const QTransform &transform, const QRectF &rect) { return transform.mapRect(rect).toRect(); } +static inline QLine map(const QTransform &transform, const QLine &line) { return transform.map(line); } +static inline QLine map(const QTransform &transform, const QLineF &line) { return transform.map(line).toLine(); } +template <class T> +static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface) +{ + if (n == 1) { + const QLine l = map(transform, lines[0]); + surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); + } else { + QVarLengthArray<DFBRegion, 32> lineArray(n); + for (int i=0; i<n; ++i) { + const QLine l = map(transform, lines[i]); + lineArray[i].x1 = l.x1(); + lineArray[i].y1 = l.y1(); + lineArray[i].x2 = l.x2(); + lineArray[i].y2 = l.y2(); + } + surface->DrawLines(surface, lineArray.constData(), n); + } +} + +template <class T> +static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface) +{ + if (n == 1) { + const QRect r = mapRect(transform, rects[0]); + surface->FillRectangle(surface, r.x(), r.y(), r.width(), r.height()); + } else { + QVarLengthArray<DFBRectangle, 32> rectArray(n); + for (int i=0; i<n; ++i) { + const QRect r = mapRect(transform, rects[i]); + rectArray[i].x = r.x(); + rectArray[i].y = r.y(); + rectArray[i].w = r.width(); + rectArray[i].h = r.height(); + } + surface->FillRectangles(surface, rectArray.constData(), n); + } +} + +template <class T> +static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface) +{ + for (int i=0; i<n; ++i) { + const QRect r = mapRect(transform, rects[i]); + surface->DrawRectangle(surface, r.x(), r.y(), r.width(), r.height()); + } +} + +template <typename T> inline const T *ptr(const T &t) { return &t; } +template <> inline const bool* ptr<bool>(const bool &) { return 0; } +template <typename device, typename T1, typename T2, typename T3> +static void rasterFallbackWarn(const char *msg, const char *func, const device *dev, + uint transformationType, bool simplePen, + uint clipType, uint compositionModeStatus, + const char *nameOne, const T1 &one, + const char *nameTwo, const T2 &two, + const char *nameThree, const T3 &three) +{ + QString out; + QDebug dbg(&out); + dbg << msg << (QByteArray(func) + "()") << "painting on"; + if (dev->devType() == QInternal::Widget) { + dbg << static_cast<const QWidget*>(dev); + } else { + dbg << dev << "of type" << dev->devType(); + } + + dbg << QString::fromLatin1("transformationType 0x%1").arg(transformationType, 3, 16, QLatin1Char('0')) + << "simplePen" << simplePen + << "clipType" << clipType + << "compositionModeStatus" << compositionModeStatus; + + const T1 *t1 = ptr(one); + const T2 *t2 = ptr(two); + const T3 *t3 = ptr(three); + + if (t1) { + dbg << nameOne << *t1; + if (t2) { + dbg << nameTwo << *t2; + if (t3) { + dbg << nameThree << *t3; + } + } + } + qWarning("%s", qPrintable(out)); +} + +QT_END_NAMESPACE + +#endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h new file mode 100644 index 0000000000..1908f3ad32 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTENGINE_DIRECTFB_P_H +#define QPAINTENGINE_DIRECTFB_P_H + +#include <QtGui/qpaintengine.h> +#include <private/qpaintengine_raster_p.h> + +#ifndef QT_NO_QWS_DIRECTFB + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QDirectFBPaintEnginePrivate; + +class QDirectFBPaintEngine : public QRasterPaintEngine +{ + Q_DECLARE_PRIVATE(QDirectFBPaintEngine) +public: + QDirectFBPaintEngine(QPaintDevice *device); + virtual ~QDirectFBPaintEngine(); + + virtual bool begin(QPaintDevice *device); + virtual bool end(); + + virtual void drawRects(const QRect *rects, int rectCount); + virtual void drawRects(const QRectF *rects, int rectCount); + + virtual void fillRect(const QRectF &r, const QBrush &brush); + virtual void fillRect(const QRectF &r, const QColor &color); + + virtual void drawLines(const QLine *line, int lineCount); + virtual void drawLines(const QLineF *line, int lineCount); + + virtual void drawImage(const QPointF &p, const QImage &img); + virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, + Qt::ImageConversionFlags falgs = Qt::AutoColor); + + virtual void drawPixmap(const QPointF &p, const QPixmap &pm); + virtual void drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr); + virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr); + + virtual void drawBufferSpan(const uint *buffer, int bufsize, + int x, int y, int length, uint const_alpha); + + virtual void stroke(const QVectorPath &path, const QPen &pen); + virtual void drawPath(const QPainterPath &path); + virtual void drawPoints(const QPointF *points, int pointCount); + virtual void drawPoints(const QPoint *points, int pointCount); + virtual void drawEllipse(const QRectF &rect); + virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); + virtual void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode); + virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); + virtual void fill(const QVectorPath &path, const QBrush &brush); + virtual void drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode); + + virtual void clipEnabledChanged(); + virtual void penChanged(); + virtual void opacityChanged(); + virtual void compositionModeChanged(); + virtual void renderHintsChanged(); + virtual void transformChanged(); + + virtual void setState(QPainterState *state); + + virtual void clip(const QVectorPath &path, Qt::ClipOperation op); + virtual void clip(const QRegion ®ion, Qt::ClipOperation op); + virtual void clip(const QRect &rect, Qt::ClipOperation op); + + virtual void drawStaticTextItem(QStaticTextItem *item); + + static void initImageCache(int size); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_QWS_DIRECTFB + +#endif // QPAINTENGINE_DIRECTFB_P_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp new file mode 100644 index 0000000000..eaff74a41c --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -0,0 +1,588 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbpixmap.h" + +#ifndef QT_NO_QWS_DIRECTFB + +#include "qdirectfbscreen.h" +#include "qdirectfbpaintengine.h" + +#include <QtGui/qbitmap.h> +#include <QtCore/qfile.h> +#include <directfb.h> + + +QT_BEGIN_NAMESPACE + +static int global_ser_no = 0; + +QDirectFBPixmapData::QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType) + : QPixmapData(pixelType, DirectFBClass), QDirectFBPaintDevice(screen), + alpha(false) +{ + setSerialNumber(0); +} + +QDirectFBPixmapData::~QDirectFBPixmapData() +{ +} + +void QDirectFBPixmapData::resize(int width, int height) +{ + if (width <= 0 || height <= 0) { + invalidate(); + return; + } + + imageFormat = screen->pixelFormat(); + dfbSurface = screen->createDFBSurface(QSize(width, height), + imageFormat, + QDirectFBScreen::TrackSurface); + d = QDirectFBScreen::depth(imageFormat); + alpha = false; + if (!dfbSurface) { + invalidate(); + qWarning("QDirectFBPixmapData::resize(): Unable to allocate surface"); + return; + } + + w = width; + h = height; + is_null = (w <= 0 || h <= 0); + setSerialNumber(++global_ser_no); +} + +#ifdef QT_DIRECTFB_OPAQUE_DETECTION +// mostly duplicated from qimage.cpp (QImageData::checkForAlphaPixels) +static bool checkForAlphaPixels(const QImage &img) +{ + const uchar *bits = img.bits(); + const int bytes_per_line = img.bytesPerLine(); + const uchar *end_bits = bits + bytes_per_line; + const int width = img.width(); + const int height = img.height(); + switch (img.format()) { + case QImage::Format_Indexed8: + return img.hasAlphaChannel(); + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + for (int y=0; y<height; ++y) { + for (int x=0; x<width; ++x) { + if ((((uint *)bits)[x] & 0xff000000) != 0xff000000) { + return true; + } + } + bits += bytes_per_line; + } + break; + + case QImage::Format_ARGB8555_Premultiplied: + case QImage::Format_ARGB8565_Premultiplied: + for (int y=0; y<height; ++y) { + while (bits < end_bits) { + if (bits[0] != 0) { + return true; + } + bits += 3; + } + bits = end_bits; + end_bits += bytes_per_line; + } + break; + + case QImage::Format_ARGB6666_Premultiplied: + for (int y=0; y<height; ++y) { + while (bits < end_bits) { + if ((bits[0] & 0xfc) != 0) { + return true; + } + bits += 3; + } + bits = end_bits; + end_bits += bytes_per_line; + } + break; + + case QImage::Format_ARGB4444_Premultiplied: + for (int y=0; y<height; ++y) { + while (bits < end_bits) { + if ((bits[0] & 0xf0) != 0) { + return true; + } + bits += 2; + } + bits = end_bits; + end_bits += bytes_per_line; + } + break; + + default: + break; + } + + return false; +} +#endif // QT_DIRECTFB_OPAQUE_DETECTION + +bool QDirectFBPixmapData::hasAlphaChannel(const QImage &img, Qt::ImageConversionFlags flags) +{ + if (img.depth() == 1) + return true; +#ifdef QT_DIRECTFB_OPAQUE_DETECTION + return ((flags & Qt::NoOpaqueDetection) ? img.hasAlphaChannel() : checkForAlphaPixels(img)); +#else + Q_UNUSED(flags); + return img.hasAlphaChannel(); +#endif +} + +#ifdef QT_DIRECTFB_IMAGEPROVIDER +bool QDirectFBPixmapData::fromFile(const QString &filename, const char *format, + Qt::ImageConversionFlags flags) +{ + if (!QFile::exists(filename)) + return false; + if (flags == Qt::AutoColor) { + if (filename.startsWith(QLatin1Char(':'))) { // resource + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) + return false; + const QByteArray data = file.readAll(); + file.close(); + return fromData(reinterpret_cast<const uchar*>(data.constData()), data.size(), format, flags); + } else { + DFBDataBufferDescription description; + description.flags = DBDESC_FILE; + const QByteArray fileNameData = filename.toLocal8Bit(); + description.file = fileNameData.constData(); + if (fromDataBufferDescription(description)) { + return true; + } + // fall back to Qt + } + } + return QPixmapData::fromFile(filename, format, flags); +} + +bool QDirectFBPixmapData::fromData(const uchar *buffer, uint len, const char *format, + Qt::ImageConversionFlags flags) +{ + if (flags == Qt::AutoColor) { + DFBDataBufferDescription description; + description.flags = DBDESC_MEMORY; + description.memory.data = buffer; + description.memory.length = len; + if (fromDataBufferDescription(description)) + return true; + // fall back to Qt + } + return QPixmapData::fromData(buffer, len, format, flags); +} + +template <typename T> struct QDirectFBInterfaceCleanupHandler +{ + static void cleanup(T *t) { if (t) t->Release(t); } +}; + +template <typename T> +class QDirectFBPointer : public QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> > +{ +public: + QDirectFBPointer(T *t = 0) + : QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> >(t) + {} +}; + +bool QDirectFBPixmapData::fromDataBufferDescription(const DFBDataBufferDescription &dataBufferDescription) +{ + IDirectFB *dfb = screen->dfb(); + Q_ASSERT(dfb); + DFBResult result = DFB_OK; + IDirectFBDataBuffer *dataBufferPtr; + if ((result = dfb->CreateDataBuffer(dfb, &dataBufferDescription, &dataBufferPtr)) != DFB_OK) { + DirectFBError("QDirectFBPixmapData::fromDataBufferDescription()", result); + return false; + } + QDirectFBPointer<IDirectFBDataBuffer> dataBuffer(dataBufferPtr); + + IDirectFBImageProvider *providerPtr; + if ((result = dataBuffer->CreateImageProvider(dataBuffer.data(), &providerPtr)) != DFB_OK) + return false; + + QDirectFBPointer<IDirectFBImageProvider> provider(providerPtr); + + DFBImageDescription imageDescription; + result = provider->GetImageDescription(provider.data(), &imageDescription); + if (result != DFB_OK) { + DirectFBError("QDirectFBPixmapData::fromSurfaceDescription(): Can't get image description", result); + return false; + } + + if (imageDescription.caps & DICAPS_COLORKEY) { + return false; + } + + DFBSurfaceDescription surfaceDescription; + if ((result = provider->GetSurfaceDescription(provider.data(), &surfaceDescription)) != DFB_OK) { + DirectFBError("QDirectFBPixmapData::fromDataBufferDescription(): Can't get surface description", result); + return false; + } + + alpha = imageDescription.caps & DICAPS_ALPHACHANNEL; + imageFormat = alpha ? screen->alphaPixmapFormat() : screen->pixelFormat(); + + dfbSurface = screen->createDFBSurface(QSize(surfaceDescription.width, surfaceDescription.height), + imageFormat, QDirectFBScreen::TrackSurface); + + result = provider->RenderTo(provider.data(), dfbSurface, 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBPixmapData::fromSurfaceDescription(): Can't render to surface", result); + return false; + } + + w = surfaceDescription.width; + h = surfaceDescription.height; + is_null = (w <= 0 || h <= 0); + d = QDirectFBScreen::depth(imageFormat); + setSerialNumber(++global_ser_no); + +#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE + screen->setDirectFBImageProvider(providerPtr); + provider.take(); +#endif + + return true; +} + +#endif + +void QDirectFBPixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) +{ + alpha = QDirectFBPixmapData::hasAlphaChannel(img, flags); + imageFormat = alpha ? screen->alphaPixmapFormat() : screen->pixelFormat(); + + QImage image; + if ((flags & ~Qt::NoOpaqueDetection) != Qt::AutoColor) { + image = img.convertToFormat(imageFormat, flags); + flags = Qt::AutoColor; + } else if (img.format() == QImage::Format_RGB32 || img.depth() == 1) { + image = img.convertToFormat(imageFormat, flags); + } else if (img.format() != imageFormat) { + image = img.convertToFormat(imageFormat, flags); + } else { + image = img; + } + + dfbSurface = screen->createDFBSurface(image, image.format(), QDirectFBScreen::NoPreallocated | QDirectFBScreen::TrackSurface); + if (!dfbSurface) { + qWarning("QDirectFBPixmapData::fromImage()"); + invalidate(); + return; + } + + w = image.width(); + h = image.height(); + is_null = (w <= 0 || h <= 0); + d = QDirectFBScreen::depth(imageFormat); + setSerialNumber(++global_ser_no); +#ifdef QT_NO_DIRECTFB_OPAQUE_DETECTION + Q_UNUSED(flags); +#endif +} + +void QDirectFBPixmapData::copy(const QPixmapData *data, const QRect &rect) +{ + if (data->classId() != DirectFBClass) { + QPixmapData::copy(data, rect); + return; + } + + const QDirectFBPixmapData *otherData = static_cast<const QDirectFBPixmapData*>(data); +#ifdef QT_NO_DIRECTFB_SUBSURFACE + if (otherData->lockFlags()) { + const_cast<QDirectFBPixmapData*>(otherData)->unlockSurface(); + } +#endif + IDirectFBSurface *src = otherData->directFBSurface(); + alpha = data->hasAlphaChannel(); + imageFormat = (alpha + ? QDirectFBScreen::instance()->alphaPixmapFormat() + : QDirectFBScreen::instance()->pixelFormat()); + + + dfbSurface = screen->createDFBSurface(rect.size(), imageFormat, + QDirectFBScreen::TrackSurface); + if (!dfbSurface) { + qWarning("QDirectFBPixmapData::copy()"); + invalidate(); + return; + } + + if (alpha) { + dfbSurface->Clear(dfbSurface, 0, 0, 0, 0); + dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_BLEND_ALPHACHANNEL); + } else { + dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); + } + const DFBRectangle blitRect = { rect.x(), rect.y(), + rect.width(), rect.height() }; + w = rect.width(); + h = rect.height(); + d = otherData->d; + is_null = (w <= 0 || h <= 0); + unlockSurface(); + DFBResult result = dfbSurface->Blit(dfbSurface, src, &blitRect, 0, 0); +#if (Q_DIRECTFB_VERSION >= 0x010000) + dfbSurface->ReleaseSource(dfbSurface); +#endif + if (result != DFB_OK) { + DirectFBError("QDirectFBPixmapData::copy()", result); + invalidate(); + return; + } + + setSerialNumber(++global_ser_no); +} + +static inline bool isOpaqueFormat(QImage::Format format) +{ + switch (format) { + case QImage::Format_RGB32: + case QImage::Format_RGB16: + case QImage::Format_RGB666: + case QImage::Format_RGB555: + case QImage::Format_RGB888: + case QImage::Format_RGB444: + return true; + default: + break; + } + return false; +} + +void QDirectFBPixmapData::fill(const QColor &color) +{ + if (!serialNumber()) + return; + + Q_ASSERT(dfbSurface); + + alpha |= (color.alpha() < 255); + + if (alpha && isOpaqueFormat(imageFormat)) { + QSize size; + dfbSurface->GetSize(dfbSurface, &size.rwidth(), &size.rheight()); + screen->releaseDFBSurface(dfbSurface); + imageFormat = screen->alphaPixmapFormat(); + d = QDirectFBScreen::depth(imageFormat); + dfbSurface = screen->createDFBSurface(size, screen->alphaPixmapFormat(), QDirectFBScreen::TrackSurface); + setSerialNumber(++global_ser_no); + if (!dfbSurface) { + qWarning("QDirectFBPixmapData::fill()"); + invalidate(); + return; + } + } + + dfbSurface->Clear(dfbSurface, color.red(), color.green(), color.blue(), color.alpha()); +} + +QPixmap QDirectFBPixmapData::transformed(const QTransform &transform, + Qt::TransformationMode mode) const +{ + QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); +#ifdef QT_NO_DIRECTFB_SUBSURFACE + if (lockFlags()) + that->unlockSurface(); +#endif + + if (!dfbSurface || transform.type() != QTransform::TxScale + || mode != Qt::FastTransformation) + { + const QImage *image = that->buffer(); + Q_ASSERT(image); + const QImage transformed = image->transformed(transform, mode); + QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType); + data->fromImage(transformed, Qt::AutoColor); + return QPixmap(data); + } + + const QSize size = transform.mapRect(QRect(0, 0, w, h)).size(); + if (size.isEmpty()) + return QPixmap(); + + QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType); + data->setSerialNumber(++global_ser_no); + DFBSurfaceBlittingFlags flags = DSBLIT_NOFX; + data->alpha = alpha; + if (alpha) { + flags = DSBLIT_BLEND_ALPHACHANNEL; + } + data->dfbSurface = screen->createDFBSurface(size, + imageFormat, + QDirectFBScreen::TrackSurface); + if (flags & DSBLIT_BLEND_ALPHACHANNEL) { + data->dfbSurface->Clear(data->dfbSurface, 0, 0, 0, 0); + } + data->dfbSurface->SetBlittingFlags(data->dfbSurface, flags); + + const DFBRectangle destRect = { 0, 0, size.width(), size.height() }; + data->dfbSurface->StretchBlit(data->dfbSurface, dfbSurface, 0, &destRect); + data->w = size.width(); + data->h = size.height(); + data->is_null = (data->w <= 0 || data->h <= 0); + +#if (Q_DIRECTFB_VERSION >= 0x010000) + data->dfbSurface->ReleaseSource(data->dfbSurface); +#endif + return QPixmap(data); +} + +QImage QDirectFBPixmapData::toImage() const +{ + if (!dfbSurface) + return QImage(); + +#if 0 + // In later versions of DirectFB one can set a flag to tell + // DirectFB not to move the surface to videomemory. When that + // happens we can use this (hopefully faster) codepath +#ifndef QT_NO_DIRECTFB_PREALLOCATED + QImage ret(w, h, QDirectFBScreen::getImageFormat(dfbSurface)); + if (IDirectFBSurface *imgSurface = screen->createDFBSurface(ret, QDirectFBScreen::DontTrackSurface)) { + if (hasAlphaChannel()) { + imgSurface->SetBlittingFlags(imgSurface, DSBLIT_BLEND_ALPHACHANNEL); + imgSurface->Clear(imgSurface, 0, 0, 0, 0); + } else { + imgSurface->SetBlittingFlags(imgSurface, DSBLIT_NOFX); + } + imgSurface->Blit(imgSurface, dfbSurface, 0, 0, 0); +#if (Q_DIRECTFB_VERSION >= 0x010000) + imgSurface->ReleaseSource(imgSurface); +#endif + imgSurface->Release(imgSurface); + return ret; + } +#endif +#endif + + QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); + const QImage *img = that->buffer(); + return img->copy(); +} + +/* This is QPixmapData::paintEngine(), not QPaintDevice::paintEngine() */ + +QPaintEngine *QDirectFBPixmapData::paintEngine() const +{ + if (!engine) { + // QDirectFBPixmapData is also a QCustomRasterPaintDevice, so pass + // that to the paint engine: + QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); + that->engine = new QDirectFBPaintEngine(that); + } + return engine; +} + +QImage *QDirectFBPixmapData::buffer() +{ + if (!lockFlgs) { + lockSurface(DSLF_READ|DSLF_WRITE); + } + Q_ASSERT(lockFlgs); + Q_ASSERT(!lockedImage.isNull()); + return &lockedImage; +} + + +bool QDirectFBPixmapData::scroll(int dx, int dy, const QRect &rect) +{ + if (!dfbSurface) { + return false; + } + unlockSurface(); + DFBResult result = dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); + if (result != DFB_OK) { + DirectFBError("QDirectFBPixmapData::scroll", result); + return false; + } + result = dfbSurface->SetPorterDuff(dfbSurface, DSPD_NONE); + if (result != DFB_OK) { + DirectFBError("QDirectFBPixmapData::scroll", result); + return false; + } + + const DFBRectangle source = { rect.x(), rect.y(), rect.width(), rect.height() }; + result = dfbSurface->Blit(dfbSurface, dfbSurface, &source, source.x + dx, source.y + dy); + if (result != DFB_OK) { + DirectFBError("QDirectFBPixmapData::scroll", result); + return false; + } + + return true; +} + +void QDirectFBPixmapData::invalidate() +{ + if (dfbSurface) { + screen->releaseDFBSurface(dfbSurface); + dfbSurface = 0; + } + setSerialNumber(0); + alpha = false; + d = w = h = 0; + is_null = true; + imageFormat = QImage::Format_Invalid; +} + +Q_GUI_EXPORT IDirectFBSurface *qt_directfb_surface_for_pixmap(const QPixmap &pixmap) +{ + const QPixmapData *data = pixmap.pixmapData(); + if (!data || data->classId() != QPixmapData::DirectFBClass) + return 0; + const QDirectFBPixmapData *dfbData = static_cast<const QDirectFBPixmapData*>(data); + return dfbData->directFBSurface(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h new file mode 100644 index 0000000000..f8e3fa1d84 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTFBPIXMAP_H +#define QDIRECTFBPIXMAP_H + +#include <qglobal.h> + +#ifndef QT_NO_QWS_DIRECTFB + +#include <QtGui/private/qpixmapdata_p.h> +#include <QtGui/private/qpaintengine_raster_p.h> +#include "qdirectfbpaintdevice.h" +#include <directfb.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QDirectFBPaintEngine; + +class QDirectFBPixmapData : public QPixmapData, public QDirectFBPaintDevice +{ +public: + QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType); + ~QDirectFBPixmapData(); + + // Re-implemented from QPixmapData: + virtual void resize(int width, int height); + virtual void fromImage(const QImage &image, Qt::ImageConversionFlags flags); +#ifdef QT_DIRECTFB_IMAGEPROVIDER + virtual bool fromFile(const QString &filename, const char *format, + Qt::ImageConversionFlags flags); + virtual bool fromData(const uchar *buffer, uint len, const char *format, + Qt::ImageConversionFlags flags); +#endif + virtual void copy(const QPixmapData *data, const QRect &rect); + virtual void fill(const QColor &color); + virtual QPixmap transformed(const QTransform &matrix, + Qt::TransformationMode mode) const; + virtual QImage toImage() const; + virtual QPaintEngine *paintEngine() const; + virtual QImage *buffer(); + virtual bool scroll(int dx, int dy, const QRect &rect); + // Pure virtual in QPixmapData, so re-implement here and delegate to QDirectFBPaintDevice + virtual int metric(QPaintDevice::PaintDeviceMetric m) const { return QDirectFBPaintDevice::metric(m); } + + inline QImage::Format pixelFormat() const { return imageFormat; } + inline bool hasAlphaChannel() const { return alpha; } + static bool hasAlphaChannel(const QImage &img, Qt::ImageConversionFlags flags = Qt::AutoColor); +private: +#ifdef QT_DIRECTFB_IMAGEPROVIDER + bool fromDataBufferDescription(const DFBDataBufferDescription &dataBuffer); +#endif + void invalidate(); + bool alpha; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_QWS_DIRECTFB + +#endif // QDIRECTFBPIXMAP_H diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp new file mode 100644 index 0000000000..ff15078ee4 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp @@ -0,0 +1,1819 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbscreen.h" +#include "qdirectfbwindowsurface.h" +#include "qdirectfbpixmap.h" +#include "qdirectfbmouse.h" +#include "qdirectfbkeyboard.h" +#include <QtGui/qwsdisplay_qws.h> +#include <QtGui/qcolor.h> +#include <QtGui/qapplication.h> +#include <QtGui/qwindowsystem_qws.h> +#include <QtGui/private/qgraphicssystem_qws_p.h> +#include <QtGui/private/qwssignalhandler_p.h> +#include <QtCore/qvarlengtharray.h> +#include <QtCore/qvector.h> +#include <QtCore/qrect.h> + +#ifndef QT_NO_QWS_DIRECTFB + +QT_BEGIN_NAMESPACE + +class QDirectFBScreenPrivate : public QObject, public QWSGraphicsSystem +{ + Q_OBJECT +public: + QDirectFBScreenPrivate(QDirectFBScreen *qptr); + ~QDirectFBScreenPrivate(); + + void setFlipFlags(const QStringList &args); + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; +public slots: +#ifdef QT_DIRECTFB_WM + void onWindowEvent(QWSWindow *window, QWSServer::WindowEvent event); +#endif +public: + IDirectFB *dfb; + DFBSurfaceFlipFlags flipFlags; + QDirectFBScreen::DirectFBFlags directFBFlags; + QImage::Format alphaPixmapFormat; + IDirectFBScreen *dfbScreen; +#ifdef QT_NO_DIRECTFB_WM + IDirectFBSurface *primarySurface; + QColor backgroundColor; +#endif +#ifndef QT_NO_DIRECTFB_LAYER + IDirectFBDisplayLayer *dfbLayer; +#endif + QSet<IDirectFBSurface*> allocatedSurfaces; + +#ifndef QT_NO_DIRECTFB_MOUSE + QDirectFBMouseHandler *mouse; +#endif +#ifndef QT_NO_DIRECTFB_KEYBOARD + QDirectFBKeyboardHandler *keyboard; +#endif +#if defined QT_DIRECTFB_IMAGEPROVIDER && defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE + IDirectFBImageProvider *imageProvider; +#endif + IDirectFBSurface *cursorSurface; + qint64 cursorImageKey; + + QDirectFBScreen *q; + static QDirectFBScreen *instance; +}; + +QDirectFBScreen *QDirectFBScreenPrivate::instance = 0; + +QDirectFBScreenPrivate::QDirectFBScreenPrivate(QDirectFBScreen *qptr) + : QWSGraphicsSystem(qptr), dfb(0), flipFlags(DSFLIP_NONE), + directFBFlags(QDirectFBScreen::NoFlags), alphaPixmapFormat(QImage::Format_Invalid), + dfbScreen(0) +#ifdef QT_NO_DIRECTFB_WM + , primarySurface(0) +#endif +#ifndef QT_NO_DIRECTFB_LAYER + , dfbLayer(0) +#endif +#ifndef QT_NO_DIRECTFB_MOUSE + , mouse(0) +#endif +#ifndef QT_NO_DIRECTFB_KEYBOARD + , keyboard(0) +#endif +#if defined QT_DIRECTFB_IMAGEPROVIDER && defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE + , imageProvider(0) +#endif + , cursorSurface(0) + , cursorImageKey(0) + , q(qptr) +{ +#ifndef QT_NO_QWS_SIGNALHANDLER + QWSSignalHandler::instance()->addObject(this); +#endif +#ifdef QT_DIRECTFB_WM + connect(QWSServer::instance(), SIGNAL(windowEvent(QWSWindow*,QWSServer::WindowEvent)), + this, SLOT(onWindowEvent(QWSWindow*,QWSServer::WindowEvent))); +#endif +} + +QDirectFBScreenPrivate::~QDirectFBScreenPrivate() +{ +#ifndef QT_NO_DIRECTFB_MOUSE + delete mouse; +#endif +#ifndef QT_NO_DIRECTFB_KEYBOARD + delete keyboard; +#endif +#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE + if (imageProvider) + imageProvider->Release(imageProvider); +#endif + + for (QSet<IDirectFBSurface*>::const_iterator it = allocatedSurfaces.begin(); it != allocatedSurfaces.end(); ++it) { + (*it)->Release(*it); + } + +#ifdef QT_NO_DIRECTFB_WM + if (primarySurface) + primarySurface->Release(primarySurface); +#endif + +#ifndef QT_NO_DIRECTFB_LAYER + if (dfbLayer) + dfbLayer->Release(dfbLayer); +#endif + + if (dfbScreen) + dfbScreen->Release(dfbScreen); + + if (dfb) + dfb->Release(dfb); +} + +IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QImage &image, QImage::Format format, SurfaceCreationOptions options, DFBResult *resultPtr) +{ + if (image.isNull()) // assert? + return 0; + + if (QDirectFBScreen::getSurfacePixelFormat(format) == DSPF_UNKNOWN) { + format = QDirectFBPixmapData::hasAlphaChannel(image) ? d_ptr->alphaPixmapFormat : pixelFormat(); + } + if (image.format() != format) { + return createDFBSurface(image.convertToFormat(format), format, options | NoPreallocated, resultPtr); + } + + DFBSurfaceDescription description; + memset(&description, 0, sizeof(DFBSurfaceDescription)); + description.width = image.width(); + description.height = image.height(); + description.flags = DSDESC_WIDTH|DSDESC_HEIGHT|DSDESC_PIXELFORMAT; + initSurfaceDescriptionPixelFormat(&description, format); + bool doMemCopy = true; +#ifdef QT_DIRECTFB_PREALLOCATED + if (!(options & NoPreallocated)) { + doMemCopy = false; + description.flags |= DSDESC_PREALLOCATED; + description.preallocated[0].data = const_cast<uchar*>(image.bits()); + description.preallocated[0].pitch = image.bytesPerLine(); + description.preallocated[1].data = 0; + description.preallocated[1].pitch = 0; + } +#endif + DFBResult result; + IDirectFBSurface *surface = createDFBSurface(description, options, &result); + if (resultPtr) + *resultPtr = result; + if (!surface) { + DirectFBError("Couldn't create surface createDFBSurface(QImage, QImage::Format, SurfaceCreationOptions)", result); + return 0; + } + if (doMemCopy) { + int bplDFB; + uchar *mem = QDirectFBScreen::lockSurface(surface, DSLF_WRITE, &bplDFB); + if (mem) { + const int height = image.height(); + const int bplQt = image.bytesPerLine(); + if (bplQt == bplDFB && bplQt == (image.width() * image.depth() / 8)) { + memcpy(mem, image.bits(), image.byteCount()); + } else { + for (int i=0; i<height; ++i) { + memcpy(mem, image.scanLine(i), bplQt); + mem += bplDFB; + } + } + surface->Unlock(surface); + } + } +#ifdef QT_DIRECTFB_PALETTE + if (image.colorCount() != 0 && surface) + QDirectFBScreen::setSurfaceColorTable(surface, image); +#endif + return surface; +} + +IDirectFBSurface *QDirectFBScreen::copyDFBSurface(IDirectFBSurface *src, + QImage::Format format, + SurfaceCreationOptions options, + DFBResult *result) +{ + Q_ASSERT(src); + QSize size; + src->GetSize(src, &size.rwidth(), &size.rheight()); + IDirectFBSurface *surface = createDFBSurface(size, format, options, result); + DFBSurfaceBlittingFlags flags = QDirectFBScreen::hasAlphaChannel(surface) + ? DSBLIT_BLEND_ALPHACHANNEL + : DSBLIT_NOFX; + if (flags & DSBLIT_BLEND_ALPHACHANNEL) + surface->Clear(surface, 0, 0, 0, 0); + + surface->SetBlittingFlags(surface, flags); + surface->Blit(surface, src, 0, 0, 0); +#if (Q_DIRECTFB_VERSION >= 0x010000) + surface->ReleaseSource(surface); +#endif + return surface; +} + +IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QSize &size, + QImage::Format format, + SurfaceCreationOptions options, + DFBResult *result) +{ + DFBSurfaceDescription desc; + memset(&desc, 0, sizeof(DFBSurfaceDescription)); + desc.flags |= DSDESC_WIDTH|DSDESC_HEIGHT; + if (!QDirectFBScreen::initSurfaceDescriptionPixelFormat(&desc, format)) + return 0; + desc.width = size.width(); + desc.height = size.height(); + return createDFBSurface(desc, options, result); +} + +IDirectFBSurface *QDirectFBScreen::createDFBSurface(DFBSurfaceDescription desc, SurfaceCreationOptions options, DFBResult *resultPtr) +{ + DFBResult tmp; + DFBResult &result = (resultPtr ? *resultPtr : tmp); + result = DFB_OK; + IDirectFBSurface *newSurface = 0; + + if (!d_ptr->dfb) { + qWarning("QDirectFBScreen::createDFBSurface() - not connected"); + return 0; + } + + if (d_ptr->directFBFlags & VideoOnly + && !(desc.flags & DSDESC_PREALLOCATED) + && (!(desc.flags & DSDESC_CAPS) || !(desc.caps & DSCAPS_SYSTEMONLY))) { + // Add the video only capability. This means the surface will be created in video ram + if (!(desc.flags & DSDESC_CAPS)) { + desc.caps = DSCAPS_VIDEOONLY; + desc.flags |= DSDESC_CAPS; + } else { + desc.caps |= DSCAPS_VIDEOONLY; + } + result = d_ptr->dfb->CreateSurface(d_ptr->dfb, &desc, &newSurface); + if (result != DFB_OK +#ifdef QT_NO_DEBUG + && (desc.flags & DSDESC_CAPS) && (desc.caps & DSCAPS_PRIMARY) +#endif + ) { + qWarning("QDirectFBScreen::createDFBSurface() Failed to create surface in video memory!\n" + " Flags %0x Caps %0x width %d height %d pixelformat %0x %d preallocated %p %d\n%s", + desc.flags, desc.caps, desc.width, desc.height, + desc.pixelformat, DFB_PIXELFORMAT_INDEX(desc.pixelformat), + desc.preallocated[0].data, desc.preallocated[0].pitch, + DirectFBErrorString(result)); + } + desc.caps &= ~DSCAPS_VIDEOONLY; + } + + if (d_ptr->directFBFlags & SystemOnly) + desc.caps |= DSCAPS_SYSTEMONLY; + + if (!newSurface) + result = d_ptr->dfb->CreateSurface(d_ptr->dfb, &desc, &newSurface); + + if (result != DFB_OK) { + qWarning("QDirectFBScreen::createDFBSurface() Failed!\n" + " Flags %0x Caps %0x width %d height %d pixelformat %0x %d preallocated %p %d\n%s", + desc.flags, desc.caps, desc.width, desc.height, + desc.pixelformat, DFB_PIXELFORMAT_INDEX(desc.pixelformat), + desc.preallocated[0].data, desc.preallocated[0].pitch, + DirectFBErrorString(result)); + return 0; + } + + Q_ASSERT(newSurface); + + if (options & TrackSurface) { + d_ptr->allocatedSurfaces.insert(newSurface); + } + + return newSurface; +} + +#ifdef QT_DIRECTFB_SUBSURFACE +IDirectFBSurface *QDirectFBScreen::getSubSurface(IDirectFBSurface *surface, + const QRect &rect, + SurfaceCreationOptions options, + DFBResult *resultPtr) +{ + Q_ASSERT(!(options & NoPreallocated)); + Q_ASSERT(surface); + DFBResult res; + DFBResult &result = (resultPtr ? *resultPtr : res); + IDirectFBSurface *subSurface = 0; + if (rect.isNull()) { + result = surface->GetSubSurface(surface, 0, &subSurface); + } else { + const DFBRectangle subRect = { rect.x(), rect.y(), rect.width(), rect.height() }; + result = surface->GetSubSurface(surface, &subRect, &subSurface); + } + if (result != DFB_OK) { + DirectFBError("Can't get sub surface", result); + } else if (options & TrackSurface) { + d_ptr->allocatedSurfaces.insert(subSurface); + } + return subSurface; +} +#endif + + +void QDirectFBScreen::releaseDFBSurface(IDirectFBSurface *surface) +{ + Q_ASSERT(QDirectFBScreen::instance()); + Q_ASSERT(surface); + surface->Release(surface); + if (!d_ptr->allocatedSurfaces.remove(surface)) + qWarning("QDirectFBScreen::releaseDFBSurface() - %p not in list", surface); + + //qDebug("Released surface at %p. New count = %d", surface, d_ptr->allocatedSurfaces.count()); +} + +QDirectFBScreen::DirectFBFlags QDirectFBScreen::directFBFlags() const +{ + return d_ptr->directFBFlags; +} + +IDirectFB *QDirectFBScreen::dfb() +{ + return d_ptr->dfb; +} + +#ifdef QT_NO_DIRECTFB_WM +IDirectFBSurface *QDirectFBScreen::primarySurface() +{ + return d_ptr->primarySurface; +} +#endif + +#ifndef QT_NO_DIRECTFB_LAYER +IDirectFBDisplayLayer *QDirectFBScreen::dfbDisplayLayer() +{ + return d_ptr->dfbLayer; +} +#endif + +DFBSurfacePixelFormat QDirectFBScreen::getSurfacePixelFormat(QImage::Format format) +{ + switch (format) { +#ifndef QT_NO_DIRECTFB_PALETTE + case QImage::Format_Indexed8: + return DSPF_LUT8; +#endif + case QImage::Format_RGB888: + return DSPF_RGB24; + case QImage::Format_ARGB4444_Premultiplied: + return DSPF_ARGB4444; +#if (Q_DIRECTFB_VERSION >= 0x010100) + case QImage::Format_RGB444: + return DSPF_RGB444; + case QImage::Format_RGB555: + return DSPF_RGB555; +#endif + case QImage::Format_RGB16: + return DSPF_RGB16; +#if (Q_DIRECTFB_VERSION >= 0x010000) + case QImage::Format_ARGB6666_Premultiplied: + return DSPF_ARGB6666; + case QImage::Format_RGB666: + return DSPF_RGB18; +#endif + case QImage::Format_RGB32: + return DSPF_RGB32; + case QImage::Format_ARGB32_Premultiplied: + case QImage::Format_ARGB32: + return DSPF_ARGB; + default: + return DSPF_UNKNOWN; + }; +} + +QImage::Format QDirectFBScreen::getImageFormat(IDirectFBSurface *surface) +{ + DFBSurfacePixelFormat format; + surface->GetPixelFormat(surface, &format); + + switch (format) { + case DSPF_LUT8: + return QImage::Format_Indexed8; + case DSPF_RGB24: + return QImage::Format_RGB888; + case DSPF_ARGB4444: + return QImage::Format_ARGB4444_Premultiplied; +#if (Q_DIRECTFB_VERSION >= 0x010100) + case DSPF_RGB444: + return QImage::Format_RGB444; + case DSPF_RGB555: +#endif + case DSPF_ARGB1555: + return QImage::Format_RGB555; + case DSPF_RGB16: + return QImage::Format_RGB16; +#if (Q_DIRECTFB_VERSION >= 0x010000) + case DSPF_ARGB6666: + return QImage::Format_ARGB6666_Premultiplied; + case DSPF_RGB18: + return QImage::Format_RGB666; +#endif + case DSPF_RGB32: + return QImage::Format_RGB32; + case DSPF_ARGB: { + DFBSurfaceCapabilities caps; + const DFBResult result = surface->GetCapabilities(surface, &caps); + Q_ASSERT(result == DFB_OK); + Q_UNUSED(result); + return (caps & DSCAPS_PREMULTIPLIED + ? QImage::Format_ARGB32_Premultiplied + : QImage::Format_ARGB32); } + default: + break; + } + return QImage::Format_Invalid; +} + +DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const uint *buffer, + int length) +{ + DFBSurfaceDescription description; + memset(&description, 0, sizeof(DFBSurfaceDescription)); + + description.flags = DSDESC_CAPS|DSDESC_WIDTH|DSDESC_HEIGHT|DSDESC_PIXELFORMAT|DSDESC_PREALLOCATED; + description.caps = DSCAPS_PREMULTIPLIED; + description.width = length; + description.height = 1; + description.pixelformat = DSPF_ARGB; + description.preallocated[0].data = (void*)buffer; + description.preallocated[0].pitch = length * sizeof(uint); + description.preallocated[1].data = 0; + description.preallocated[1].pitch = 0; + return description; +} + +#ifndef QT_NO_DIRECTFB_PALETTE +void QDirectFBScreen::setSurfaceColorTable(IDirectFBSurface *surface, + const QImage &image) +{ + if (!surface) + return; + + const int numColors = image.colorCount(); + if (numColors == 0) + return; + + QVarLengthArray<DFBColor, 256> colors(numColors); + for (int i = 0; i < numColors; ++i) { + QRgb c = image.color(i); + colors[i].a = qAlpha(c); + colors[i].r = qRed(c); + colors[i].g = qGreen(c); + colors[i].b = qBlue(c); + } + + IDirectFBPalette *palette; + DFBResult result; + result = surface->GetPalette(surface, &palette); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::setSurfaceColorTable GetPalette", + result); + return; + } + result = palette->SetEntries(palette, colors.data(), numColors, 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::setSurfaceColorTable SetEntries", + result); + } + palette->Release(palette); +} + +#endif // QT_NO_DIRECTFB_PALETTE + +#if defined QT_DIRECTFB_CURSOR +class Q_GUI_EXPORT QDirectFBScreenCursor : public QScreenCursor +{ +public: + QDirectFBScreenCursor(); + virtual void set(const QImage &image, int hotx, int hoty); + virtual void move(int x, int y); + virtual void show(); + virtual void hide(); +private: +#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR + ~QDirectFBScreenCursor(); + bool createWindow(); + IDirectFBWindow *window; +#endif + IDirectFBDisplayLayer *layer; +}; + +QDirectFBScreenCursor::QDirectFBScreenCursor() +{ + IDirectFB *fb = QDirectFBScreen::instance()->dfb(); + if (!fb) + qFatal("QDirectFBScreenCursor: DirectFB not initialized"); + + layer = QDirectFBScreen::instance()->dfbDisplayLayer(); + Q_ASSERT(layer); + + enable = false; + hwaccel = true; + supportsAlpha = true; +#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR + window = 0; + DFBResult result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::hide: " + "Unable to set cooperative level", result); + } + result = layer->SetCursorOpacity(layer, 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::hide: " + "Unable to set cursor opacity", result); + } + + result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::hide: " + "Unable to set cooperative level", result); + } +#endif +} + +#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR +QDirectFBScreenCursor::~QDirectFBScreenCursor() +{ + if (window) { + window->Release(window); + window = 0; + } +} + +bool QDirectFBScreenCursor::createWindow() +{ + Q_ASSERT(!window); + Q_ASSERT(!cursor.isNull()); + DFBWindowDescription description; + memset(&description, 0, sizeof(DFBWindowDescription)); + description.flags = DWDESC_POSX|DWDESC_POSY|DWDESC_WIDTH|DWDESC_HEIGHT|DWDESC_CAPS|DWDESC_PIXELFORMAT|DWDESC_SURFACE_CAPS; + description.width = cursor.width(); + description.height = cursor.height(); + description.posx = pos.x() - hotspot.x(); + description.posy = pos.y() - hotspot.y(); +#if (Q_DIRECTFB_VERSION >= 0x010100) + description.flags |= DWDESC_OPTIONS; + description.options = DWOP_GHOST|DWOP_ALPHACHANNEL; +#endif + description.caps = DWCAPS_NODECORATION|DWCAPS_DOUBLEBUFFER; + const QImage::Format format = QDirectFBScreen::instance()->alphaPixmapFormat(); + description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(format); + if (QDirectFBScreen::isPremultiplied(format)) + description.surface_caps = DSCAPS_PREMULTIPLIED; + + DFBResult result = layer->CreateWindow(layer, &description, &window); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::createWindow: Unable to create window", result); + return false; + } + result = window->SetOpacity(window, 255); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::createWindow: Unable to set opacity ", result); + return false; + } + + result = window->SetStackingClass(window, DWSC_UPPER); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::createWindow: Unable to set stacking class ", result); + return false; + } + + result = window->RaiseToTop(window); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::createWindow: Unable to raise window ", result); + return false; + } + + return true; +} +#endif + +void QDirectFBScreenCursor::move(int x, int y) +{ + pos = QPoint(x, y); +#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR + if (window) { + const QPoint p = pos - hotspot; + DFBResult result = window->MoveTo(window, p.x(), p.y()); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::move: Unable to move window", result); + } + } +#else + layer->WarpCursor(layer, x, y); +#endif +} + +void QDirectFBScreenCursor::hide() +{ + if (enable) { + enable = false; + DFBResult result; +#ifndef QT_DIRECTFB_WINDOW_AS_CURSOR + result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::hide: " + "Unable to set cooperative level", result); + } + result = layer->SetCursorOpacity(layer, 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::hide: " + "Unable to set cursor opacity", result); + } + result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::hide: " + "Unable to set cooperative level", result); + } +#else + if (window) { + result = window->SetOpacity(window, 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::hide: " + "Unable to set window opacity", result); + } + } +#endif + } +} + +void QDirectFBScreenCursor::show() +{ + if (!enable) { + enable = true; + DFBResult result; + result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to set cooperative level", result); + } + result = layer->SetCursorOpacity(layer, +#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR + 0 +#else + 255 +#endif + ); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to set cursor shape", result); + } + result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to set cooperative level", result); + } +#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR + if (window) { + DFBResult result = window->SetOpacity(window, 255); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to set window opacity", result); + } + } +#endif + } +} + +void QDirectFBScreenCursor::set(const QImage &image, int hotx, int hoty) +{ + QDirectFBScreen *screen = QDirectFBScreen::instance(); + if (!screen) + return; + + if (image.isNull()) { + cursor = QImage(); + hide(); + } else { + cursor = image.convertToFormat(screen->alphaPixmapFormat()); + size = cursor.size(); + hotspot = QPoint(hotx, hoty); + DFBResult result = DFB_OK; + IDirectFBSurface *surface = screen->createDFBSurface(cursor, screen->alphaPixmapFormat(), + QDirectFBScreen::DontTrackSurface, &result); + if (!surface) { + DirectFBError("QDirectFBScreenCursor::set: Unable to create surface", result); + return; + } +#ifndef QT_DIRECTFB_WINDOW_AS_CURSOR + result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to set cooperative level", result); + } + result = layer->SetCursorShape(layer, surface, hotx, hoty); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to set cursor shape", result); + } + result = layer->SetCooperativeLevel(layer, DLSCL_SHARED); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::show: " + "Unable to set cooperative level", result); + } +#else + if (window || createWindow()) { + QSize windowSize; + result = window->GetSize(window, &windowSize.rwidth(), &windowSize.rheight()); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::set: " + "Unable to get window size", result); + } + result = window->Resize(window, size.width(), size.height()); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::set: Unable to resize window", result); + } + + IDirectFBSurface *windowSurface; + result = window->GetSurface(window, &windowSurface); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::set: Unable to get window surface", result); + } else { + result = windowSurface->Clear(windowSurface, 0, 0, 0, 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::set: Unable to clear surface", result); + } + + result = windowSurface->Blit(windowSurface, surface, 0, 0, 0); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::set: Unable to blit to surface", result); + } + } + result = windowSurface->Flip(windowSurface, 0, DSFLIP_NONE); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::set: Unable to flip window", result); + } + + windowSurface->Release(windowSurface); + } +#endif + surface->Release(surface); + show(); + } + +} +#endif // QT_DIRECTFB_CURSOR + +QDirectFBScreen::QDirectFBScreen(int display_id) + : QScreen(display_id, DirectFBClass), d_ptr(new QDirectFBScreenPrivate(this)) +{ + QDirectFBScreenPrivate::instance = this; +} + +QDirectFBScreen::~QDirectFBScreen() +{ + if (QDirectFBScreenPrivate::instance == this) + QDirectFBScreenPrivate::instance = 0; + delete d_ptr; +} + +QDirectFBScreen *QDirectFBScreen::instance() +{ + return QDirectFBScreenPrivate::instance; +} + +int QDirectFBScreen::depth(DFBSurfacePixelFormat format) +{ + switch (format) { + case DSPF_A1: + return 1; + case DSPF_A8: + case DSPF_RGB332: + case DSPF_LUT8: + case DSPF_ALUT44: + return 8; + case DSPF_I420: + case DSPF_YV12: + case DSPF_NV12: + case DSPF_NV21: +#if (Q_DIRECTFB_VERSION >= 0x010100) + case DSPF_RGB444: +#endif + return 12; +#if (Q_DIRECTFB_VERSION >= 0x010100) + case DSPF_RGB555: + return 15; +#endif + case DSPF_ARGB1555: + case DSPF_RGB16: + case DSPF_YUY2: + case DSPF_UYVY: + case DSPF_NV16: + case DSPF_ARGB2554: + case DSPF_ARGB4444: + return 16; + case DSPF_RGB24: + return 24; + case DSPF_RGB32: + case DSPF_ARGB: + case DSPF_AiRGB: + return 32; + case DSPF_UNKNOWN: + default: + return 0; + }; + return 0; +} + +int QDirectFBScreen::depth(QImage::Format format) +{ + int depth = 0; + switch(format) { + case QImage::Format_Invalid: + case QImage::NImageFormats: + Q_ASSERT(false); + case QImage::Format_Mono: + case QImage::Format_MonoLSB: + depth = 1; + break; + case QImage::Format_Indexed8: + depth = 8; + break; + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + depth = 32; + break; + case QImage::Format_RGB555: + case QImage::Format_RGB16: + case QImage::Format_RGB444: + case QImage::Format_ARGB4444_Premultiplied: + depth = 16; + break; + case QImage::Format_RGB666: + case QImage::Format_ARGB6666_Premultiplied: + case QImage::Format_ARGB8565_Premultiplied: + case QImage::Format_ARGB8555_Premultiplied: + case QImage::Format_RGB888: + depth = 24; + break; + } + return depth; +} + +void QDirectFBScreenPrivate::setFlipFlags(const QStringList &args) +{ + QRegExp flipRegexp(QLatin1String("^flip=([\\w,]*)$")); + int index = args.indexOf(flipRegexp); + if (index >= 0) { + const QStringList flips = flipRegexp.cap(1).split(QLatin1Char(','), + QString::SkipEmptyParts); + flipFlags = DSFLIP_NONE; + foreach(const QString &flip, flips) { + if (flip == QLatin1String("wait")) + flipFlags |= DSFLIP_WAIT; + else if (flip == QLatin1String("blit")) + flipFlags |= DSFLIP_BLIT; + else if (flip == QLatin1String("onsync")) + flipFlags |= DSFLIP_ONSYNC; + else if (flip == QLatin1String("pipeline")) + flipFlags |= DSFLIP_PIPELINE; + else + qWarning("QDirectFBScreen: Unknown flip argument: %s", + qPrintable(flip)); + } + } else { + flipFlags = DSFLIP_BLIT|DSFLIP_ONSYNC; + } +} + +#ifdef QT_DIRECTFB_WM +void QDirectFBScreenPrivate::onWindowEvent(QWSWindow *window, QWSServer::WindowEvent event) +{ + if (event == QWSServer::Raise) { + QWSWindowSurface *windowSurface = window->windowSurface(); + if (windowSurface && windowSurface->key() == QLatin1String("directfb")) { + static_cast<QDirectFBWindowSurface*>(windowSurface)->raise(); + } + } +} +#endif + +QPixmapData *QDirectFBScreenPrivate::createPixmapData(QPixmapData::PixelType type) const +{ + if (type == QPixmapData::BitmapType) + return QWSGraphicsSystem::createPixmapData(type); + + return new QDirectFBPixmapData(q, type); +} + +#if (Q_DIRECTFB_VERSION >= 0x000923) +#ifdef QT_NO_DEBUG +struct FlagDescription; +static const FlagDescription *accelerationDescriptions = 0; +static const FlagDescription *blitDescriptions = 0; +static const FlagDescription *drawDescriptions = 0; +#else +struct FlagDescription { + const char *name; + uint flag; +}; + +static const FlagDescription accelerationDescriptions[] = { + { "DFXL_NONE", DFXL_NONE }, + { "DFXL_FILLRECTANGLE", DFXL_FILLRECTANGLE }, + { "DFXL_DRAWRECTANGLE", DFXL_DRAWRECTANGLE }, + { "DFXL_DRAWLINE", DFXL_DRAWLINE }, + { "DFXL_FILLTRIANGLE", DFXL_FILLTRIANGLE }, + { "DFXL_BLIT", DFXL_BLIT }, + { "DFXL_STRETCHBLIT", DFXL_STRETCHBLIT }, + { "DFXL_TEXTRIANGLES", DFXL_TEXTRIANGLES }, + { "DFXL_DRAWSTRING", DFXL_DRAWSTRING }, + { 0, 0 } +}; + +static const FlagDescription blitDescriptions[] = { + { "DSBLIT_NOFX", DSBLIT_NOFX }, + { "DSBLIT_BLEND_ALPHACHANNEL", DSBLIT_BLEND_ALPHACHANNEL }, + { "DSBLIT_BLEND_COLORALPHA", DSBLIT_BLEND_COLORALPHA }, + { "DSBLIT_COLORIZE", DSBLIT_COLORIZE }, + { "DSBLIT_SRC_COLORKEY", DSBLIT_SRC_COLORKEY }, + { "DSBLIT_DST_COLORKEY", DSBLIT_DST_COLORKEY }, + { "DSBLIT_SRC_PREMULTIPLY", DSBLIT_SRC_PREMULTIPLY }, + { "DSBLIT_DST_PREMULTIPLY", DSBLIT_DST_PREMULTIPLY }, + { "DSBLIT_DEMULTIPLY", DSBLIT_DEMULTIPLY }, + { "DSBLIT_DEINTERLACE", DSBLIT_DEINTERLACE }, +#if (Q_DIRECTFB_VERSION >= 0x000923) + { "DSBLIT_SRC_PREMULTCOLOR", DSBLIT_SRC_PREMULTCOLOR }, + { "DSBLIT_XOR", DSBLIT_XOR }, +#endif +#if (Q_DIRECTFB_VERSION >= 0x010000) + { "DSBLIT_INDEX_TRANSLATION", DSBLIT_INDEX_TRANSLATION }, +#endif + { 0, 0 } +}; + +static const FlagDescription drawDescriptions[] = { + { "DSDRAW_NOFX", DSDRAW_NOFX }, + { "DSDRAW_BLEND", DSDRAW_BLEND }, + { "DSDRAW_DST_COLORKEY", DSDRAW_DST_COLORKEY }, + { "DSDRAW_SRC_PREMULTIPLY", DSDRAW_SRC_PREMULTIPLY }, + { "DSDRAW_DST_PREMULTIPLY", DSDRAW_DST_PREMULTIPLY }, + { "DSDRAW_DEMULTIPLY", DSDRAW_DEMULTIPLY }, + { "DSDRAW_XOR", DSDRAW_XOR }, + { 0, 0 } +}; +#endif + +static const QByteArray flagDescriptions(uint mask, const FlagDescription *flags) +{ +#ifdef QT_NO_DEBUG + Q_UNUSED(mask); + Q_UNUSED(flags); + return QByteArray(""); +#else + if (!mask) + return flags[0].name; + + QStringList list; + for (int i=1; flags[i].name; ++i) { + if (mask & flags[i].flag) { + list.append(QString::fromLatin1(flags[i].name)); + } + } + Q_ASSERT(!list.isEmpty()); + return (QLatin1Char(' ') + list.join(QLatin1String("|"))).toLatin1(); +#endif +} +static void printDirectFBInfo(IDirectFB *fb, IDirectFBSurface *primarySurface) +{ + DFBResult result; + DFBGraphicsDeviceDescription dev; + + result = fb->GetDeviceDescription(fb, &dev); + if (result != DFB_OK) { + DirectFBError("Error reading graphics device description", result); + return; + } + + DFBSurfacePixelFormat pixelFormat; + primarySurface->GetPixelFormat(primarySurface, &pixelFormat); + + qDebug("Device: %s (%s), Driver: %s v%i.%i (%s) Pixelformat: %d (%d)\n" + "acceleration: 0x%x%s\nblit: 0x%x%s\ndraw: 0x%0x%s\nvideo: %iKB\n", + dev.name, dev.vendor, dev.driver.name, dev.driver.major, + dev.driver.minor, dev.driver.vendor, DFB_PIXELFORMAT_INDEX(pixelFormat), + QDirectFBScreen::getImageFormat(primarySurface), dev.acceleration_mask, + flagDescriptions(dev.acceleration_mask, accelerationDescriptions).constData(), + dev.blitting_flags, flagDescriptions(dev.blitting_flags, blitDescriptions).constData(), + dev.drawing_flags, flagDescriptions(dev.drawing_flags, drawDescriptions).constData(), + (dev.video_memory >> 10)); +} +#endif + +static inline bool setIntOption(const QStringList &arguments, const QString &variable, int *value) +{ + Q_ASSERT(value); + QRegExp rx(QString::fromLatin1("%1=?(\\d+)").arg(variable)); + rx.setCaseSensitivity(Qt::CaseInsensitive); + if (arguments.indexOf(rx) != -1) { + *value = rx.cap(1).toInt(); + return true; + } + return false; +} + +static inline QColor colorFromName(const QString &name) +{ + QRegExp rx(QLatin1String("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])")); + rx.setCaseSensitivity(Qt::CaseInsensitive); + if (rx.exactMatch(name)) { + Q_ASSERT(rx.captureCount() == 4); + int ints[4]; + int i; + for (i=0; i<4; ++i) { + bool ok; + ints[i] = rx.cap(i + 1).toUInt(&ok, 16); + if (!ok || ints[i] > 255) + break; + } + if (i == 4) + return QColor(ints[0], ints[1], ints[2], ints[3]); + } + return QColor(name); +} + +bool QDirectFBScreen::connect(const QString &displaySpec) +{ + DFBResult result = DFB_OK; + + { // pass command line arguments to DirectFB + const QStringList args = QCoreApplication::arguments(); + int argc = args.size(); + char **argv = new char*[argc]; + + for (int i = 0; i < argc; ++i) + argv[i] = qstrdup(args.at(i).toLocal8Bit().constData()); + + result = DirectFBInit(&argc, &argv); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen: error initializing DirectFB", + result); + } + delete[] argv; + } + + const QStringList displayArgs = displaySpec.split(QLatin1Char(':'), + QString::SkipEmptyParts); + + d_ptr->setFlipFlags(displayArgs); + + result = DirectFBCreate(&d_ptr->dfb); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen: error creating DirectFB interface", + result); + return false; + } + + if (displayArgs.contains(QLatin1String("videoonly"), Qt::CaseInsensitive)) + d_ptr->directFBFlags |= VideoOnly; + + if (displayArgs.contains(QLatin1String("systemonly"), Qt::CaseInsensitive)) { + if (d_ptr->directFBFlags & VideoOnly) { + qWarning("QDirectFBScreen: error. videoonly and systemonly are mutually exclusive"); + } else { + d_ptr->directFBFlags |= SystemOnly; + } + } + + if (displayArgs.contains(QLatin1String("boundingrectflip"), Qt::CaseInsensitive)) { + d_ptr->directFBFlags |= BoundingRectFlip; + } else if (displayArgs.contains(QLatin1String("nopartialflip"), Qt::CaseInsensitive)) { + d_ptr->directFBFlags |= NoPartialFlip; + } + +#ifdef QT_DIRECTFB_IMAGECACHE + int imageCacheSize = 4 * 1024 * 1024; // 4 MB + setIntOption(displayArgs, QLatin1String("imagecachesize"), &imageCacheSize); + QDirectFBPaintEngine::initImageCache(imageCacheSize); +#endif + +#ifndef QT_NO_DIRECTFB_WM + if (displayArgs.contains(QLatin1String("fullscreen"))) +#endif + d_ptr->dfb->SetCooperativeLevel(d_ptr->dfb, DFSCL_FULLSCREEN); + + const bool forcePremultiplied = displayArgs.contains(QLatin1String("forcepremultiplied"), Qt::CaseInsensitive); + + DFBSurfaceDescription description; + memset(&description, 0, sizeof(DFBSurfaceDescription)); + IDirectFBSurface *surface; + +#ifdef QT_NO_DIRECTFB_WM + description.flags = DSDESC_CAPS; + if (::setIntOption(displayArgs, QLatin1String("width"), &description.width)) + description.flags |= DSDESC_WIDTH; + if (::setIntOption(displayArgs, QLatin1String("height"), &description.height)) + description.flags |= DSDESC_HEIGHT; + + description.caps = DSCAPS_PRIMARY|DSCAPS_DOUBLE; + struct { + const char *name; + const DFBSurfaceCapabilities cap; + } const capabilities[] = { + { "static_alloc", DSCAPS_STATIC_ALLOC }, + { "triplebuffer", DSCAPS_TRIPLE }, + { "interlaced", DSCAPS_INTERLACED }, + { "separated", DSCAPS_SEPARATED }, +// { "depthbuffer", DSCAPS_DEPTH }, // only makes sense with TextureTriangles which are not supported + { 0, DSCAPS_NONE } + }; + for (int i=0; capabilities[i].name; ++i) { + if (displayArgs.contains(QString::fromLatin1(capabilities[i].name), Qt::CaseInsensitive)) + description.caps |= capabilities[i].cap; + } + + if (forcePremultiplied) { + description.caps |= DSCAPS_PREMULTIPLIED; + } + + // We don't track the primary surface as it's released in disconnect + d_ptr->primarySurface = createDFBSurface(description, DontTrackSurface, &result); + if (!d_ptr->primarySurface) { + DirectFBError("QDirectFBScreen: error creating primary surface", + result); + return false; + } + + surface = d_ptr->primarySurface; +#else + description.flags = DSDESC_WIDTH|DSDESC_HEIGHT; + description.width = description.height = 1; + surface = createDFBSurface(description, DontTrackSurface, &result); + if (!surface) { + DirectFBError("QDirectFBScreen: error creating surface", result); + return false; + } +#endif + // Work out what format we're going to use for surfaces with an alpha channel + QImage::Format pixelFormat = QDirectFBScreen::getImageFormat(surface); + d_ptr->alphaPixmapFormat = pixelFormat; + + switch (pixelFormat) { + case QImage::Format_RGB666: + d_ptr->alphaPixmapFormat = QImage::Format_ARGB6666_Premultiplied; + break; + case QImage::Format_RGB444: + d_ptr->alphaPixmapFormat = QImage::Format_ARGB4444_Premultiplied; + break; + case QImage::Format_RGB32: + pixelFormat = d_ptr->alphaPixmapFormat = QImage::Format_ARGB32_Premultiplied; + // ### Format_RGB32 doesn't work so well with Qt. Force ARGB32 for windows/pixmaps + break; + case QImage::Format_Indexed8: + qWarning("QDirectFBScreen::connect(). Qt/DirectFB does not work with the LUT8 pixelformat."); + return false; + case QImage::NImageFormats: + case QImage::Format_Invalid: + case QImage::Format_Mono: + case QImage::Format_MonoLSB: + case QImage::Format_RGB888: + case QImage::Format_RGB16: + case QImage::Format_RGB555: + d_ptr->alphaPixmapFormat = QImage::Format_ARGB32_Premultiplied; + break; + case QImage::Format_ARGB32: + if (forcePremultiplied) + d_ptr->alphaPixmapFormat = pixelFormat = QImage::Format_ARGB32_Premultiplied; + case QImage::Format_ARGB32_Premultiplied: + case QImage::Format_ARGB4444_Premultiplied: + case QImage::Format_ARGB8555_Premultiplied: + case QImage::Format_ARGB8565_Premultiplied: + case QImage::Format_ARGB6666_Premultiplied: + // works already + break; + } + setPixelFormat(pixelFormat); + QScreen::d = QDirectFBScreen::depth(pixelFormat); + data = 0; + lstep = 0; + size = 0; + + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::connect: " + "Unable to get screen!", result); + return false; + } + const QString qws_size = QString::fromLatin1(qgetenv("QWS_SIZE")); + if (!qws_size.isEmpty()) { + QRegExp rx(QLatin1String("(\\d+)x(\\d+)")); + if (!rx.exactMatch(qws_size)) { + qWarning("QDirectFBScreen::connect: Can't parse QWS_SIZE=\"%s\"", qPrintable(qws_size)); + } else { + int *ints[2] = { &w, &h }; + for (int i=0; i<2; ++i) { + *ints[i] = rx.cap(i + 1).toInt(); + if (*ints[i] <= 0) { + qWarning("QDirectFBScreen::connect: %s is not a positive integer", + qPrintable(rx.cap(i + 1))); + w = h = 0; + break; + } + } + } + } + + setIntOption(displayArgs, QLatin1String("width"), &w); + setIntOption(displayArgs, QLatin1String("height"), &h); + +#ifndef QT_NO_DIRECTFB_LAYER + int layerId = DLID_PRIMARY; + setIntOption(displayArgs, QLatin1String("layerid"), &layerId); + + result = d_ptr->dfb->GetDisplayLayer(d_ptr->dfb, static_cast<DFBDisplayLayerID>(layerId), + &d_ptr->dfbLayer); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::connect: " + "Unable to get display layer!", result); + return false; + } + result = d_ptr->dfbLayer->GetScreen(d_ptr->dfbLayer, &d_ptr->dfbScreen); +#else + result = d_ptr->dfb->GetScreen(d_ptr->dfb, 0, &d_ptr->dfbScreen); +#endif + + if (w <= 0 || h <= 0) { +#ifdef QT_NO_DIRECTFB_WM + result = d_ptr->primarySurface->GetSize(d_ptr->primarySurface, &w, &h); +#elif (Q_DIRECTFB_VERSION >= 0x010000) + IDirectFBSurface *layerSurface; + if (d_ptr->dfbLayer->GetSurface(d_ptr->dfbLayer, &layerSurface) == DFB_OK) { + result = layerSurface->GetSize(layerSurface, &w, &h); + layerSurface->Release(layerSurface); + } + if (w <= 0 || h <= 0) { + result = d_ptr->dfbScreen->GetSize(d_ptr->dfbScreen, &w, &h); + } +#else + qWarning("QDirectFBScreen::connect: DirectFB versions prior to 1.0 do not offer a way\n" + "query the size of the primary surface in windowed mode. You have to specify\n" + "the size of the display using QWS_SIZE=[0-9]x[0-9] or\n" + "QWS_DISPLAY=directfb:width=[0-9]:height=[0-9]"); + return false; +#endif + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::connect: " + "Unable to get screen size!", result); + return false; + } + } + + + dw = w; + dh = h; + + Q_ASSERT(dw != 0 && dh != 0); + + physWidth = physHeight = -1; + setIntOption(displayArgs, QLatin1String("mmWidth"), &physWidth); + setIntOption(displayArgs, QLatin1String("mmHeight"), &physHeight); + const int dpi = 72; + if (physWidth < 0) + physWidth = qRound(dw * 25.4 / dpi); + if (physHeight < 0) + physHeight = qRound(dh * 25.4 / dpi); + + setGraphicsSystem(d_ptr); + +#if (Q_DIRECTFB_VERSION >= 0x000923) + if (displayArgs.contains(QLatin1String("debug"), Qt::CaseInsensitive)) + printDirectFBInfo(d_ptr->dfb, surface); +#endif +#ifdef QT_DIRECTFB_WM + surface->Release(surface); + QColor backgroundColor; +#else + QColor &backgroundColor = d_ptr->backgroundColor; +#endif + + QRegExp backgroundColorRegExp(QLatin1String("bgcolor=(.+)")); + backgroundColorRegExp.setCaseSensitivity(Qt::CaseInsensitive); + if (displayArgs.indexOf(backgroundColorRegExp) != -1) { + backgroundColor = colorFromName(backgroundColorRegExp.cap(1)); + } +#ifdef QT_NO_DIRECTFB_WM + if (!backgroundColor.isValid()) + backgroundColor = Qt::green; + d_ptr->primarySurface->Clear(d_ptr->primarySurface, backgroundColor.red(), + backgroundColor.green(), backgroundColor.blue(), + backgroundColor.alpha()); + d_ptr->primarySurface->Flip(d_ptr->primarySurface, 0, d_ptr->flipFlags); +#else + if (backgroundColor.isValid()) { + DFBResult result = d_ptr->dfbLayer->SetCooperativeLevel(d_ptr->dfbLayer, DLSCL_ADMINISTRATIVE); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::connect " + "Unable to set cooperative level", result); + } + result = d_ptr->dfbLayer->SetBackgroundColor(d_ptr->dfbLayer, backgroundColor.red(), backgroundColor.green(), + backgroundColor.blue(), backgroundColor.alpha()); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::connect: " + "Unable to set background color", result); + } + + result = d_ptr->dfbLayer->SetBackgroundMode(d_ptr->dfbLayer, DLBM_COLOR); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreenCursor::connect: " + "Unable to set background mode", result); + } + + result = d_ptr->dfbLayer->SetCooperativeLevel(d_ptr->dfbLayer, DLSCL_SHARED); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::connect " + "Unable to set cooperative level", result); + } + + } +#endif + + return true; +} + +void QDirectFBScreen::disconnect() +{ +#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE + if (d_ptr->imageProvider) + d_ptr->imageProvider->Release(d_ptr->imageProvider); +#endif +#ifdef QT_NO_DIRECTFB_WM + d_ptr->primarySurface->Release(d_ptr->primarySurface); + d_ptr->primarySurface = 0; +#endif + + foreach (IDirectFBSurface *surf, d_ptr->allocatedSurfaces) + surf->Release(surf); + d_ptr->allocatedSurfaces.clear(); + +#ifndef QT_NO_DIRECTFB_LAYER + d_ptr->dfbLayer->Release(d_ptr->dfbLayer); + d_ptr->dfbLayer = 0; +#endif + + d_ptr->dfbScreen->Release(d_ptr->dfbScreen); + d_ptr->dfbScreen = 0; + + d_ptr->dfb->Release(d_ptr->dfb); + d_ptr->dfb = 0; +} + +bool QDirectFBScreen::initDevice() +{ +#ifndef QT_NO_DIRECTFB_MOUSE + if (qgetenv("QWS_MOUSE_PROTO").isEmpty()) { + QWSServer::instance()->setDefaultMouse("None"); + d_ptr->mouse = new QDirectFBMouseHandler; + } +#endif +#ifndef QT_NO_DIRECTFB_KEYBOARD + if (qgetenv("QWS_KEYBOARD").isEmpty()) { + QWSServer::instance()->setDefaultKeyboard("None"); + d_ptr->keyboard = new QDirectFBKeyboardHandler(QString()); + } +#endif + +#ifdef QT_DIRECTFB_CURSOR + qt_screencursor = new QDirectFBScreenCursor; +#elif !defined QT_NO_QWS_CURSOR + QScreenCursor::initSoftwareCursor(); +#endif + return true; +} + +void QDirectFBScreen::shutdownDevice() +{ +#ifndef QT_NO_DIRECTFB_MOUSE + delete d_ptr->mouse; + d_ptr->mouse = 0; +#endif +#ifndef QT_NO_DIRECTFB_KEYBOARD + delete d_ptr->keyboard; + d_ptr->keyboard = 0; +#endif + +#ifndef QT_NO_QWS_CURSOR + delete qt_screencursor; + qt_screencursor = 0; +#endif +} + +void QDirectFBScreen::setMode(int width, int height, int depth) +{ + d_ptr->dfb->SetVideoMode(d_ptr->dfb, width, height, depth); +} + +void QDirectFBScreen::blank(bool on) +{ + d_ptr->dfbScreen->SetPowerMode(d_ptr->dfbScreen, + (on ? DSPM_ON : DSPM_SUSPEND)); +} + +QWSWindowSurface *QDirectFBScreen::createSurface(QWidget *widget) const +{ +#ifdef QT_NO_DIRECTFB_WM + if (QApplication::type() == QApplication::GuiServer) { + return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this), widget); + } else { + return QScreen::createSurface(widget); + } +#else + return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this), widget); +#endif +} + +QWSWindowSurface *QDirectFBScreen::createSurface(const QString &key) const +{ + if (key == QLatin1String("directfb")) { + return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this)); + } + return QScreen::createSurface(key); +} + +#if defined QT_NO_DIRECTFB_WM +struct PaintCommand { + PaintCommand() : dfbSurface(0), windowOpacity(255), blittingFlags(DSBLIT_NOFX) {} + IDirectFBSurface *dfbSurface; + QImage image; + QPoint windowPosition; + QRegion source; + quint8 windowOpacity; + DFBSurfaceBlittingFlags blittingFlags; +}; + +static inline void initParameters(DFBRectangle &source, const QRect &sourceGlobal, const QPoint &pos) +{ + source.x = sourceGlobal.x() - pos.x(); + source.y = sourceGlobal.y() - pos.y(); + source.w = sourceGlobal.width(); + source.h = sourceGlobal.height(); +} +#endif + +void QDirectFBScreen::exposeRegion(QRegion r, int) +{ + Q_UNUSED(r); +#if defined QT_NO_DIRECTFB_WM + + r &= region(); + if (r.isEmpty()) { + return; + } + r = r.boundingRect(); + + IDirectFBSurface *primary = d_ptr->primarySurface; + const QList<QWSWindow*> windows = QWSServer::instance()->clientWindows(); + QVarLengthArray<PaintCommand, 4> commands(windows.size()); + QRegion region = r; + int idx = 0; + for (int i=0; i<windows.size(); ++i) { + QWSWindowSurface *surface = windows.at(i)->windowSurface(); + if (!surface) + continue; + + const QRect windowGeometry = surface->geometry(); + const QRegion intersection = region & windowGeometry; + if (intersection.isEmpty()) { + continue; + } + + PaintCommand &cmd = commands[idx]; + + if (surface->key() == QLatin1String("directfb")) { + const QDirectFBWindowSurface *ws = static_cast<QDirectFBWindowSurface*>(surface); + cmd.dfbSurface = ws->directFBSurface(); + + if (!cmd.dfbSurface) { + continue; + } + } else { + cmd.image = surface->image(); + if (cmd.image.isNull()) { + continue; + } + } + ++idx; + + cmd.windowPosition = windowGeometry.topLeft(); + cmd.source = intersection; + if (windows.at(i)->isOpaque()) { + region -= intersection; + if (region.isEmpty()) + break; + } else { + cmd.windowOpacity = windows.at(i)->opacity(); + cmd.blittingFlags = cmd.windowOpacity == 255 + ? DSBLIT_BLEND_ALPHACHANNEL + : (DSBLIT_BLEND_ALPHACHANNEL|DSBLIT_BLEND_COLORALPHA); + } + } + + solidFill(d_ptr->backgroundColor, region); + + while (idx > 0) { + const PaintCommand &cmd = commands[--idx]; + Q_ASSERT(cmd.dfbSurface || !cmd.image.isNull()); + IDirectFBSurface *surface; + if (cmd.dfbSurface) { + surface = cmd.dfbSurface; + } else { + Q_ASSERT(!cmd.image.isNull()); + DFBResult result; + surface = createDFBSurface(cmd.image, cmd.image.format(), DontTrackSurface, &result); + Q_ASSERT((result != DFB_OK) == !surface); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::exposeRegion: Can't create surface from image", result); + continue; + } + } + + primary->SetBlittingFlags(primary, cmd.blittingFlags); + if (cmd.blittingFlags & DSBLIT_BLEND_COLORALPHA) { + primary->SetColor(primary, 0xff, 0xff, 0xff, cmd.windowOpacity); + } + const QRegion ®ion = cmd.source; + const int rectCount = region.rectCount(); + DFBRectangle source; + if (rectCount == 1) { + ::initParameters(source, region.boundingRect(), cmd.windowPosition); + primary->Blit(primary, surface, &source, cmd.windowPosition.x() + source.x, cmd.windowPosition.y() + source.y); + } else { + const QVector<QRect> rects = region.rects(); + for (int i=0; i<rectCount; ++i) { + ::initParameters(source, rects.at(i), cmd.windowPosition); + primary->Blit(primary, surface, &source, cmd.windowPosition.x() + source.x, cmd.windowPosition.y() + source.y); + } + } + if (surface != cmd.dfbSurface) { + surface->Release(surface); + } + } + + primary->SetColor(primary, 0xff, 0xff, 0xff, 0xff); + +#if defined QT_NO_DIRECTFB_CURSOR and !defined QT_NO_QWS_CURSOR + if (QScreenCursor *cursor = QScreenCursor::instance()) { + const QRect cursorRectangle = cursor->boundingRect(); + if (cursor->isVisible() && !cursor->isAccelerated() && r.intersects(cursorRectangle)) { + const QImage image = cursor->image(); + if (image.cacheKey() != d_ptr->cursorImageKey) { + if (d_ptr->cursorSurface) { + releaseDFBSurface(d_ptr->cursorSurface); + } + d_ptr->cursorSurface = createDFBSurface(image, image.format(), QDirectFBScreen::TrackSurface); + d_ptr->cursorImageKey = image.cacheKey(); + } + + Q_ASSERT(d_ptr->cursorSurface); + primary->SetBlittingFlags(primary, DSBLIT_BLEND_ALPHACHANNEL); + primary->Blit(primary, d_ptr->cursorSurface, 0, cursorRectangle.x(), cursorRectangle.y()); + } + } +#endif + flipSurface(primary, d_ptr->flipFlags, r, QPoint()); + primary->SetBlittingFlags(primary, DSBLIT_NOFX); +#endif +} + +void QDirectFBScreen::solidFill(const QColor &color, const QRegion ®ion) +{ +#ifdef QT_DIRECTFB_WM + Q_UNUSED(color); + Q_UNUSED(region); +#else + QDirectFBScreen::solidFill(d_ptr->primarySurface, color, region); +#endif +} + +static inline void clearRect(IDirectFBSurface *surface, const QColor &color, const QRect &rect) +{ + Q_ASSERT(surface); + const DFBRegion region = { rect.left(), rect.top(), rect.right(), rect.bottom() }; + // could just reinterpret_cast this to a DFBRegion + surface->SetClip(surface, ®ion); + surface->Clear(surface, color.red(), color.green(), color.blue(), color.alpha()); +} + +void QDirectFBScreen::solidFill(IDirectFBSurface *surface, const QColor &color, const QRegion ®ion) +{ + if (region.isEmpty()) + return; + + const int n = region.rectCount(); + if (n == 1) { + clearRect(surface, color, region.boundingRect()); + } else { + const QVector<QRect> rects = region.rects(); + for (int i=0; i<n; ++i) { + clearRect(surface, color, rects.at(i)); + } + } + surface->SetClip(surface, 0); +} + +QImage::Format QDirectFBScreen::alphaPixmapFormat() const +{ + return d_ptr->alphaPixmapFormat; +} + +bool QDirectFBScreen::initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *description, + QImage::Format format) +{ + const DFBSurfacePixelFormat pixelformat = QDirectFBScreen::getSurfacePixelFormat(format); + if (pixelformat == DSPF_UNKNOWN) + return false; + description->flags |= DSDESC_PIXELFORMAT; + description->pixelformat = pixelformat; + if (QDirectFBScreen::isPremultiplied(format)) { + if (!(description->flags & DSDESC_CAPS)) { + description->caps = DSCAPS_PREMULTIPLIED; + description->flags |= DSDESC_CAPS; + } else { + description->caps |= DSCAPS_PREMULTIPLIED; + } + } + return true; +} + +uchar *QDirectFBScreen::lockSurface(IDirectFBSurface *surface, DFBSurfaceLockFlags flags, int *bpl) +{ + void *mem = 0; + const DFBResult result = surface->Lock(surface, flags, &mem, bpl); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::lockSurface()", result); + } + + return reinterpret_cast<uchar*>(mem); +} + +static inline bool isFullUpdate(IDirectFBSurface *surface, const QRegion ®ion, const QPoint &offset) +{ + if (offset == QPoint(0, 0) && region.rectCount() == 1) { + QSize size; + surface->GetSize(surface, &size.rwidth(), &size.rheight()); + if (region.boundingRect().size() == size) + return true; + } + return false; +} + +void QDirectFBScreen::flipSurface(IDirectFBSurface *surface, DFBSurfaceFlipFlags flipFlags, + const QRegion ®ion, const QPoint &offset) +{ + if (d_ptr->directFBFlags & NoPartialFlip + || (!(flipFlags & DSFLIP_BLIT) && QT_PREPEND_NAMESPACE(isFullUpdate(surface, region, offset)))) { + surface->Flip(surface, 0, flipFlags); + } else { + if (!(d_ptr->directFBFlags & BoundingRectFlip) && region.rectCount() > 1) { + const QVector<QRect> rects = region.rects(); + const DFBSurfaceFlipFlags nonWaitFlags = flipFlags & ~DSFLIP_WAIT; + for (int i=0; i<rects.size(); ++i) { + const QRect &r = rects.at(i); + const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(), + r.right() + offset.x(), + r.bottom() + offset.y() }; + surface->Flip(surface, &dfbReg, i + 1 < rects.size() ? nonWaitFlags : flipFlags); + } + } else { + const QRect r = region.boundingRect(); + const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(), + r.right() + offset.x(), + r.bottom() + offset.y() }; + surface->Flip(surface, &dfbReg, flipFlags); + } + } +} + +#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE +void QDirectFBScreen::setDirectFBImageProvider(IDirectFBImageProvider *provider) +{ + Q_ASSERT(provider); + if (d_ptr->imageProvider) + d_ptr->imageProvider->Release(d_ptr->imageProvider); + d_ptr->imageProvider = provider; +} +#endif + +void QDirectFBScreen::waitIdle() +{ + d_ptr->dfb->WaitIdle(d_ptr->dfb); +} + +#ifdef QT_DIRECTFB_WM +IDirectFBWindow *QDirectFBScreen::windowForWidget(const QWidget *widget) const +{ + if (widget) { + const QWSWindowSurface *surface = static_cast<const QWSWindowSurface*>(widget->windowSurface()); + if (surface && surface->key() == QLatin1String("directfb")) { + return static_cast<const QDirectFBWindowSurface*>(surface)->directFBWindow(); + } + } + return 0; +} +#endif + +IDirectFBSurface * QDirectFBScreen::surfaceForWidget(const QWidget *widget, QRect *rect) const +{ + Q_ASSERT(widget); + if (!widget->isVisible() || widget->size().isNull()) + return 0; + + const QWSWindowSurface *surface = static_cast<const QWSWindowSurface*>(widget->windowSurface()); + if (surface && surface->key() == QLatin1String("directfb")) { + return static_cast<const QDirectFBWindowSurface*>(surface)->surfaceForWidget(widget, rect); + } + return 0; +} + +#ifdef QT_DIRECTFB_SUBSURFACE +IDirectFBSurface *QDirectFBScreen::subSurfaceForWidget(const QWidget *widget, const QRect &area) const +{ + Q_ASSERT(widget); + QRect rect; + IDirectFBSurface *surface = surfaceForWidget(widget, &rect); + IDirectFBSurface *subSurface = 0; + if (surface) { + if (!area.isNull()) + rect &= area.translated(widget->mapTo(widget->window(), QPoint(0, 0))); + if (!rect.isNull()) { + const DFBRectangle subRect = { rect.x(), rect.y(), rect.width(), rect.height() }; + const DFBResult result = surface->GetSubSurface(surface, &subRect, &subSurface); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen::subSurface(): Can't get sub surface", result); + } + } + } + return subSurface; +} +#endif + +Q_GUI_EXPORT IDirectFBSurface *qt_directfb_surface_for_widget(const QWidget *widget, QRect *rect) +{ + return QDirectFBScreen::instance() ? QDirectFBScreen::instance()->surfaceForWidget(widget, rect) : 0; +} +#ifdef QT_DIRECTFB_SUBSURFACE +Q_GUI_EXPORT IDirectFBSurface *qt_directfb_subsurface_for_widget(const QWidget *widget, const QRect &area) +{ + return QDirectFBScreen::instance() ? QDirectFBScreen::instance()->subSurfaceForWidget(widget, area) : 0; +} +#endif +#ifdef QT_DIRECTFB_WM +Q_GUI_EXPORT IDirectFBWindow *qt_directfb_window_for_widget(const QWidget *widget) +{ + return QDirectFBScreen::instance() ? QDirectFBScreen::instance()->windowForWidget(widget) : 0; +} + +#endif + +QT_END_NAMESPACE + +#include "qdirectfbscreen.moc" +#endif // QT_NO_QWS_DIRECTFB + diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h new file mode 100644 index 0000000000..0e9098df3b --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTFBSCREEN_H +#define QDIRECTFBSCREEN_H + +#include <qglobal.h> +#ifndef QT_NO_QWS_DIRECTFB +#include <QtGui/qscreen_qws.h> +#include <directfb.h> +#include <directfb_version.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#if !defined QT_DIRECTFB_SUBSURFACE && !defined QT_NO_DIRECTFB_SUBSURFACE +#define QT_NO_DIRECTFB_SUBSURFACE +#endif +#if !defined QT_NO_DIRECTFB_LAYER && !defined QT_DIRECTFB_LAYER +#define QT_DIRECTFB_LAYER +#endif +#if !defined QT_NO_DIRECTFB_WM && !defined QT_DIRECTFB_WM +#define QT_DIRECTFB_WM +#endif +#if !defined QT_DIRECTFB_IMAGECACHE && !defined QT_NO_DIRECTFB_IMAGECACHE +#define QT_NO_DIRECTFB_IMAGECACHE +#endif +#if !defined QT_NO_DIRECTFB_IMAGEPROVIDER && !defined QT_DIRECTFB_IMAGEPROVIDER +#define QT_DIRECTFB_IMAGEPROVIDER +#endif +#if !defined QT_NO_DIRECTFB_STRETCHBLIT && !defined QT_DIRECTFB_STRETCHBLIT +#define QT_DIRECTFB_STRETCHBLIT +#endif +#if !defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE && !defined QT_NO_DIRECTFB_IMAGEPROVIDER_KEEPALIVE +#define QT_NO_DIRECTFB_IMAGEPROVIDER_KEEPALIVE +#endif +#if !defined QT_DIRECTFB_WINDOW_AS_CURSOR && !defined QT_NO_DIRECTFB_WINDOW_AS_CURSOR +#define QT_NO_DIRECTFB_WINDOW_AS_CURSOR +#endif +#if !defined QT_DIRECTFB_PALETTE && !defined QT_NO_DIRECTFB_PALETTE +#define QT_NO_DIRECTFB_PALETTE +#endif +#if !defined QT_NO_DIRECTFB_PREALLOCATED && !defined QT_DIRECTFB_PREALLOCATED +#define QT_DIRECTFB_PREALLOCATED +#endif +#if !defined QT_NO_DIRECTFB_MOUSE && !defined QT_DIRECTFB_MOUSE +#define QT_DIRECTFB_MOUSE +#endif +#if !defined QT_NO_DIRECTFB_KEYBOARD && !defined QT_DIRECTFB_KEYBOARD +#define QT_DIRECTFB_KEYBOARD +#endif +#if !defined QT_NO_DIRECTFB_OPAQUE_DETECTION && !defined QT_DIRECTFB_OPAQUE_DETECTION +#define QT_DIRECTFB_OPAQUE_DETECTION +#endif +#ifndef QT_NO_QWS_CURSOR +#if defined QT_DIRECTFB_WM && defined QT_DIRECTFB_WINDOW_AS_CURSOR +#define QT_DIRECTFB_CURSOR +#elif defined QT_DIRECTFB_LAYER +#define QT_DIRECTFB_CURSOR +#endif +#endif +#ifndef QT_DIRECTFB_CURSOR +#define QT_NO_DIRECTFB_CURSOR +#endif +#if defined QT_NO_DIRECTFB_LAYER && defined QT_DIRECTFB_WM +#error QT_NO_DIRECTFB_LAYER requires QT_NO_DIRECTFB_WM +#endif +#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE && defined QT_NO_DIRECTFB_IMAGEPROVIDER +#error QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE requires QT_DIRECTFB_IMAGEPROVIDER to be defined +#endif +#if defined QT_DIRECTFB_WINDOW_AS_CURSOR && defined QT_NO_DIRECTFB_WM +#error QT_DIRECTFB_WINDOW_AS_CURSOR requires QT_DIRECTFB_WM to be defined +#endif + +#define Q_DIRECTFB_VERSION ((DIRECTFB_MAJOR_VERSION << 16) | (DIRECTFB_MINOR_VERSION << 8) | DIRECTFB_MICRO_VERSION) + +#define DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(F) \ + static inline F operator~(F f) { return F(~int(f)); } \ + static inline F operator&(F left, F right) { return F(int(left) & int(right)); } \ + static inline F operator|(F left, F right) { return F(int(left) | int(right)); } \ + static inline F &operator|=(F &left, F right) { left = (left | right); return left; } \ + static inline F &operator&=(F &left, F right) { left = (left & right); return left; } + +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBInputDeviceCapabilities); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBWindowDescriptionFlags); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBWindowCapabilities); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBWindowOptions); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceDescriptionFlags); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceCapabilities); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceLockFlags); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceBlittingFlags); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceDrawingFlags); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceFlipFlags); + +class QDirectFBScreenPrivate; +class Q_GUI_EXPORT QDirectFBScreen : public QScreen +{ +public: + QDirectFBScreen(int display_id); + ~QDirectFBScreen(); + + enum DirectFBFlag { + NoFlags = 0x00, + VideoOnly = 0x01, + SystemOnly = 0x02, + BoundingRectFlip = 0x04, + NoPartialFlip = 0x08 + }; + + Q_DECLARE_FLAGS(DirectFBFlags, DirectFBFlag); + + DirectFBFlags directFBFlags() const; + + bool connect(const QString &displaySpec); + void disconnect(); + bool initDevice(); + void shutdownDevice(); + + void exposeRegion(QRegion r, int changing); + void solidFill(const QColor &color, const QRegion ®ion); + static void solidFill(IDirectFBSurface *surface, const QColor &color, const QRegion ®ion); + + void setMode(int width, int height, int depth); + void blank(bool on); + + QWSWindowSurface *createSurface(QWidget *widget) const; + QWSWindowSurface *createSurface(const QString &key) const; + + static QDirectFBScreen *instance(); + void waitIdle(); + IDirectFBSurface *surfaceForWidget(const QWidget *widget, QRect *rect) const; +#ifdef QT_DIRECTFB_SUBSURFACE + IDirectFBSurface *subSurfaceForWidget(const QWidget *widget, const QRect &area = QRect()) const; +#endif + IDirectFB *dfb(); +#ifdef QT_DIRECTFB_WM + IDirectFBWindow *windowForWidget(const QWidget *widget) const; +#else + IDirectFBSurface *primarySurface(); +#endif +#ifndef QT_NO_DIRECTFB_LAYER + IDirectFBDisplayLayer *dfbDisplayLayer(); +#endif + + // Track surface creation/release so we can release all on exit + enum SurfaceCreationOption { + DontTrackSurface = 0x1, + TrackSurface = 0x2, + NoPreallocated = 0x4 + }; + Q_DECLARE_FLAGS(SurfaceCreationOptions, SurfaceCreationOption); + IDirectFBSurface *createDFBSurface(const QImage &image, + QImage::Format format, + SurfaceCreationOptions options, + DFBResult *result = 0); + IDirectFBSurface *createDFBSurface(const QSize &size, + QImage::Format format, + SurfaceCreationOptions options, + DFBResult *result = 0); + IDirectFBSurface *copyDFBSurface(IDirectFBSurface *src, + QImage::Format format, + SurfaceCreationOptions options, + DFBResult *result = 0); + IDirectFBSurface *createDFBSurface(DFBSurfaceDescription desc, + SurfaceCreationOptions options, + DFBResult *result); +#ifdef QT_DIRECTFB_SUBSURFACE + IDirectFBSurface *getSubSurface(IDirectFBSurface *surface, + const QRect &rect, + SurfaceCreationOptions options, + DFBResult *result); +#endif + + void flipSurface(IDirectFBSurface *surface, DFBSurfaceFlipFlags flipFlags, + const QRegion ®ion, const QPoint &offset); + void releaseDFBSurface(IDirectFBSurface *surface); + + using QScreen::depth; + static int depth(DFBSurfacePixelFormat format); + static int depth(QImage::Format format); + + static DFBSurfacePixelFormat getSurfacePixelFormat(QImage::Format format); + static DFBSurfaceDescription getSurfaceDescription(const uint *buffer, + int length); + static QImage::Format getImageFormat(IDirectFBSurface *surface); + static bool initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *description, QImage::Format format); + static inline bool isPremultiplied(QImage::Format format); + static inline bool hasAlphaChannel(DFBSurfacePixelFormat format); + static inline bool hasAlphaChannel(IDirectFBSurface *surface); + QImage::Format alphaPixmapFormat() const; + +#ifndef QT_NO_DIRECTFB_PALETTE + static void setSurfaceColorTable(IDirectFBSurface *surface, + const QImage &image); +#endif + + static uchar *lockSurface(IDirectFBSurface *surface, DFBSurfaceLockFlags flags, int *bpl = 0); +#if defined QT_DIRECTFB_IMAGEPROVIDER && defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE + void setDirectFBImageProvider(IDirectFBImageProvider *provider); +#endif +private: + QDirectFBScreenPrivate *d_ptr; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QDirectFBScreen::SurfaceCreationOptions); +Q_DECLARE_OPERATORS_FOR_FLAGS(QDirectFBScreen::DirectFBFlags); + +inline bool QDirectFBScreen::isPremultiplied(QImage::Format format) +{ + switch (format) { + case QImage::Format_ARGB32_Premultiplied: + case QImage::Format_ARGB8565_Premultiplied: + case QImage::Format_ARGB6666_Premultiplied: + case QImage::Format_ARGB8555_Premultiplied: + case QImage::Format_ARGB4444_Premultiplied: + return true; + default: + break; + } + return false; +} + +inline bool QDirectFBScreen::hasAlphaChannel(DFBSurfacePixelFormat format) +{ + switch (format) { + case DSPF_ARGB1555: + case DSPF_ARGB: + case DSPF_LUT8: + case DSPF_AiRGB: + case DSPF_A1: + case DSPF_ARGB2554: + case DSPF_ARGB4444: +#if (Q_DIRECTFB_VERSION >= 0x000923) + case DSPF_AYUV: +#endif +#if (Q_DIRECTFB_VERSION >= 0x010000) + case DSPF_A4: + case DSPF_ARGB1666: + case DSPF_ARGB6666: + case DSPF_LUT2: +#endif + return true; + default: + return false; + } +} + +inline bool QDirectFBScreen::hasAlphaChannel(IDirectFBSurface *surface) +{ + Q_ASSERT(surface); + DFBSurfacePixelFormat format; + surface->GetPixelFormat(surface, &format); + return QDirectFBScreen::hasAlphaChannel(format); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_QWS_DIRECTFB +#endif // QDIRECTFBSCREEN_H + diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp new file mode 100644 index 0000000000..742c857e9e --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbscreen.h" + +#include <QtGui/qscreendriverplugin_qws.h> +#include <QtCore/qstringlist.h> +#ifndef QT_NO_QWS_DIRECTFB + +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) + +#endif diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp new file mode 100644 index 0000000000..9a94c30d8c --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -0,0 +1,506 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectfbwindowsurface.h" +#include "qdirectfbscreen.h" +#include "qdirectfbpaintengine.h" + +#include <private/qwidget_p.h> +#include <qwidget.h> +#include <qwindowsystem_qws.h> +#include <qpaintdevice.h> +#include <qvarlengtharray.h> + +#ifndef QT_NO_QWS_DIRECTFB + +QT_BEGIN_NAMESPACE + +QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr) + : QDirectFBPaintDevice(scr) +#ifndef QT_NO_DIRECTFB_WM + , dfbWindow(0) +#endif + , flipFlags(flip) + , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip) + , flushPending(false) +{ +#ifdef QT_NO_DIRECTFB_WM + mode = Offscreen; +#endif + setSurfaceFlags(Opaque | Buffered); +#ifdef QT_DIRECTFB_TIMING + frames = 0; + timer.start(); +#endif +} + +QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr, QWidget *widget) + : QWSWindowSurface(widget), QDirectFBPaintDevice(scr) +#ifndef QT_NO_DIRECTFB_WM + , dfbWindow(0) +#endif + , flipFlags(flip) + , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip) + , flushPending(false) +{ + SurfaceFlags flags = 0; + if (!widget || widget->window()->windowOpacity() == 0xff) + flags |= Opaque; +#ifdef QT_NO_DIRECTFB_WM + if (widget && widget->testAttribute(Qt::WA_PaintOnScreen)) { + flags = RegionReserved; + mode = Primary; + } else { + mode = Offscreen; + flags = Buffered; + } +#endif + setSurfaceFlags(flags); +#ifdef QT_DIRECTFB_TIMING + frames = 0; + timer.start(); +#endif +} + +QDirectFBWindowSurface::~QDirectFBWindowSurface() +{ + releaseSurface(); + // these are not tracked by QDirectFBScreen so we don't want QDirectFBPaintDevice to release it +} + +bool QDirectFBWindowSurface::isValid() const +{ + return true; +} + +#ifdef QT_DIRECTFB_WM +void QDirectFBWindowSurface::raise() +{ + if (IDirectFBWindow *window = directFBWindow()) { + window->RaiseToTop(window); + } +} + +IDirectFBWindow *QDirectFBWindowSurface::directFBWindow() const +{ + return dfbWindow; +} + +void QDirectFBWindowSurface::createWindow(const QRect &rect) +{ + IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer(); + if (!layer) + qFatal("QDirectFBWindowSurface: Unable to get primary display layer!"); + + updateIsOpaque(); + + DFBWindowDescription description; + memset(&description, 0, sizeof(DFBWindowDescription)); + + description.flags = DWDESC_CAPS|DWDESC_HEIGHT|DWDESC_WIDTH|DWDESC_POSX|DWDESC_POSY|DWDESC_SURFACE_CAPS|DWDESC_PIXELFORMAT; + description.caps = DWCAPS_NODECORATION; + description.surface_caps = DSCAPS_NONE; + imageFormat = screen->pixelFormat(); + + if (!(surfaceFlags() & Opaque)) { + imageFormat = screen->alphaPixmapFormat(); + description.caps |= DWCAPS_ALPHACHANNEL; +#if (Q_DIRECTFB_VERSION >= 0x010200) + description.flags |= DWDESC_OPTIONS; + description.options |= DWOP_ALPHACHANNEL; +#endif + } + description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(imageFormat); + description.posx = rect.x(); + description.posy = rect.y(); + description.width = rect.width(); + description.height = rect.height(); + + if (QDirectFBScreen::isPremultiplied(imageFormat)) + description.surface_caps = DSCAPS_PREMULTIPLIED; + + if (screen->directFBFlags() & QDirectFBScreen::VideoOnly) + description.surface_caps |= DSCAPS_VIDEOONLY; + + DFBResult result = layer->CreateWindow(layer, &description, &dfbWindow); + + if (result != DFB_OK) + DirectFBErrorFatal("QDirectFBWindowSurface::createWindow", result); + + if (window()) { + if (window()->windowFlags() & Qt::WindowStaysOnTopHint) { + dfbWindow->SetStackingClass(dfbWindow, DWSC_UPPER); + } + DFBWindowID winid; + result = dfbWindow->GetID(dfbWindow, &winid); + if (result != DFB_OK) { + DirectFBError("QDirectFBWindowSurface::createWindow. Can't get ID", result); + } else { + window()->setProperty("_q_DirectFBWindowID", winid); + } + } + + Q_ASSERT(!dfbSurface); + dfbWindow->GetSurface(dfbWindow, &dfbSurface); +} + +static DFBResult setWindowGeometry(IDirectFBWindow *dfbWindow, const QRect &old, const QRect &rect) +{ + DFBResult result = DFB_OK; + const bool isMove = old.isEmpty() || rect.topLeft() != old.topLeft(); + const bool isResize = rect.size() != old.size(); + +#if (Q_DIRECTFB_VERSION >= 0x010000) + if (isResize && isMove) { + result = dfbWindow->SetBounds(dfbWindow, rect.x(), rect.y(), + rect.width(), rect.height()); + } else if (isResize) { + result = dfbWindow->Resize(dfbWindow, + rect.width(), rect.height()); + } else if (isMove) { + result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y()); + } +#else + if (isResize) { + result = dfbWindow->Resize(dfbWindow, + rect.width(), rect.height()); + } + if (isMove) { + result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y()); + } +#endif + return result; +} +#endif // QT_NO_DIRECTFB_WM + +void QDirectFBWindowSurface::setGeometry(const QRect &rect) +{ + const QRect oldRect = geometry(); + if (oldRect == rect) + return; + + IDirectFBSurface *oldSurface = dfbSurface; + const bool sizeChanged = oldRect.size() != rect.size(); + if (sizeChanged) { + delete engine; + engine = 0; + releaseSurface(); + Q_ASSERT(!dfbSurface); + } + + if (rect.isNull()) { +#ifndef QT_NO_DIRECTFB_WM + if (dfbWindow) { + if (window()) + window()->setProperty("_q_DirectFBWindowID", QVariant()); + + dfbWindow->Release(dfbWindow); + dfbWindow = 0; + } +#endif + Q_ASSERT(!dfbSurface); +#ifdef QT_DIRECTFB_SUBSURFACE + Q_ASSERT(!subSurface); +#endif + } else { +#ifdef QT_DIRECTFB_WM + if (!dfbWindow) { + createWindow(rect); + } else { + setWindowGeometry(dfbWindow, oldRect, rect); + Q_ASSERT(!sizeChanged || !dfbSurface); + if (sizeChanged) + dfbWindow->GetSurface(dfbWindow, &dfbSurface); + } +#else + IDirectFBSurface *primarySurface = screen->primarySurface(); + DFBResult result = DFB_OK; + if (mode == Primary) { + Q_ASSERT(primarySurface); + if (rect == screen->region().boundingRect()) { + dfbSurface = primarySurface; + } else { + const DFBRectangle r = { rect.x(), rect.y(), + rect.width(), rect.height() }; + result = primarySurface->GetSubSurface(primarySurface, &r, &dfbSurface); + } + } else { // mode == Offscreen + if (!dfbSurface) { + dfbSurface = screen->createDFBSurface(rect.size(), surfaceFlags() & Opaque ? screen->pixelFormat() : screen->alphaPixmapFormat(), + QDirectFBScreen::DontTrackSurface); + } + } + if (result != DFB_OK) + DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result); +#endif + } + if (oldSurface != dfbSurface) { + imageFormat = dfbSurface ? QDirectFBScreen::getImageFormat(dfbSurface) : QImage::Format_Invalid; + } + + if (oldRect.size() != rect.size()) { + QWSWindowSurface::setGeometry(rect); + } else { + QWindowSurface::setGeometry(rect); + } +} + +QByteArray QDirectFBWindowSurface::permanentState() const +{ + QByteArray state(sizeof(SurfaceFlags) + sizeof(DFBWindowID), 0); + char *ptr = state.data(); + SurfaceFlags flags = surfaceFlags(); + memcpy(ptr, &flags, sizeof(SurfaceFlags)); + ptr += sizeof(SurfaceFlags); + DFBWindowID did = (DFBWindowID)(-1); + if (dfbWindow) + dfbWindow->GetID(dfbWindow, &did); + memcpy(ptr, &did, sizeof(DFBWindowID)); + return state; +} + +void QDirectFBWindowSurface::setPermanentState(const QByteArray &state) +{ + const char *ptr = state.constData(); + IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer(); + SurfaceFlags flags; + memcpy(&flags, ptr, sizeof(SurfaceFlags)); + + setSurfaceFlags(flags); + ptr += sizeof(SurfaceFlags); + DFBWindowID id; + memcpy(&id, ptr, sizeof(DFBWindowID)); + if (dfbSurface) + dfbSurface->Release(dfbSurface); + if (id != (DFBWindowID)-1) { + IDirectFBWindow *dw; + layer->GetWindow(layer, id, &dw); + if (dw->GetSurface(dw, &dfbSurface) != DFB_OK) + dfbSurface = 0; + dw->Release(dw); + } + else { + dfbSurface = 0; + } +} + +bool QDirectFBWindowSurface::scroll(const QRegion ®ion, int dx, int dy) +{ + if (!dfbSurface || !(flipFlags & DSFLIP_BLIT) || region.rectCount() != 1) + return false; + if (flushPending) { + dfbSurface->Flip(dfbSurface, 0, DSFLIP_BLIT); + } else { + flushPending = true; + } + dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); + const QRect r = region.boundingRect(); + const DFBRectangle rect = { r.x(), r.y(), r.width(), r.height() }; + dfbSurface->Blit(dfbSurface, dfbSurface, &rect, r.x() + dx, r.y() + dy); + return true; +} + +bool QDirectFBWindowSurface::move(const QPoint &moveBy) +{ + setGeometry(geometry().translated(moveBy)); + return true; +} + +void QDirectFBWindowSurface::setOpaque(bool opaque) +{ + SurfaceFlags flags = surfaceFlags(); + if (opaque != (flags & Opaque)) { + if (opaque) { + flags |= Opaque; + } else { + flags &= ~Opaque; + } + setSurfaceFlags(flags); + } +} + + +void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion ®ion, + const QPoint &offset) +{ + QWidget *win = window(); + if (!win) + return; + +#if !defined(QT_NO_QWS_PROXYSCREEN) && !defined(QT_NO_GRAPHICSVIEW) + QWExtra *extra = qt_widget_private(widget)->extraData(); + if (extra && extra->proxyWidget) + return; +#else + Q_UNUSED(widget); +#endif + + const quint8 windowOpacity = quint8(win->windowOpacity() * 0xff); + const QRect windowGeometry = geometry(); +#ifdef QT_DIRECTFB_WM + quint8 currentOpacity; + Q_ASSERT(dfbWindow); + dfbWindow->GetOpacity(dfbWindow, ¤tOpacity); + if (currentOpacity != windowOpacity) { + dfbWindow->SetOpacity(dfbWindow, windowOpacity); + } + + screen->flipSurface(dfbSurface, flipFlags, region, offset); +#else + setOpaque(windowOpacity == 0xff); + if (mode == Offscreen) { + screen->exposeRegion(region.translated(offset + geometry().topLeft()), 0); + } else { + screen->flipSurface(dfbSurface, flipFlags, region, offset); + } +#endif + +#ifdef QT_DIRECTFB_TIMING + enum { Secs = 3 }; + ++frames; + if (timer.elapsed() >= Secs * 1000) { + qDebug("%d fps", int(double(frames) / double(Secs))); + frames = 0; + timer.restart(); + } +#endif + flushPending = false; +} + +void QDirectFBWindowSurface::beginPaint(const QRegion ®ion) +{ + if (!engine) { + engine = new QDirectFBPaintEngine(this); + } + + if (dfbSurface) { + const QWidget *win = window(); + if (win && win->testAttribute(Qt::WA_NoSystemBackground)) { + QDirectFBScreen::solidFill(dfbSurface, Qt::transparent, region); + } + } + flushPending = true; +} + +void QDirectFBWindowSurface::endPaint(const QRegion &) +{ +#ifdef QT_NO_DIRECTFB_SUBSURFACE + unlockSurface(); +#endif +} + +IDirectFBSurface *QDirectFBWindowSurface::directFBSurface() const +{ + return dfbSurface; +} + + +IDirectFBSurface *QDirectFBWindowSurface::surfaceForWidget(const QWidget *widget, QRect *rect) const +{ + Q_ASSERT(widget); + if (!dfbSurface) + return 0; + QWidget *win = window(); + Q_ASSERT(win); + if (rect) { + if (win == widget) { + *rect = widget->rect(); + } else { + *rect = QRect(widget->mapTo(win, QPoint(0, 0)), widget->size()); + } + } + + Q_ASSERT(win == widget || win->isAncestorOf(widget)); + return dfbSurface; +} + +void QDirectFBWindowSurface::releaseSurface() +{ + if (dfbSurface) { +#ifdef QT_DIRECTFB_SUBSURFACE + releaseSubSurface(); +#else + unlockSurface(); +#endif +#ifdef QT_NO_DIRECTFB_WM + Q_ASSERT(screen->primarySurface()); + if (dfbSurface != screen->primarySurface()) +#endif + + dfbSurface->Release(dfbSurface); + dfbSurface = 0; + } +} + +void QDirectFBWindowSurface::updateIsOpaque() +{ + const QWidget *win = window(); + Q_ASSERT(win); + if (win->testAttribute(Qt::WA_OpaquePaintEvent) || win->testAttribute(Qt::WA_PaintOnScreen)) { + setOpaque(true); + return; + } + + if (qFuzzyCompare(static_cast<float>(win->windowOpacity()), 1.0f)) { + const QPalette &pal = win->palette(); + + if (win->autoFillBackground()) { + const QBrush &autoFillBrush = pal.brush(win->backgroundRole()); + if (autoFillBrush.style() != Qt::NoBrush && autoFillBrush.isOpaque()) { + setOpaque(true); + return; + } + } + + if (win->isWindow() && !win->testAttribute(Qt::WA_NoSystemBackground)) { + const QBrush &windowBrush = win->palette().brush(QPalette::Window); + if (windowBrush.style() != Qt::NoBrush && windowBrush.isOpaque()) { + setOpaque(true); + return; + } + } + } + setOpaque(false); +} + +QT_END_NAMESPACE + +#endif // QT_NO_QWS_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h new file mode 100644 index 0000000000..75d462b523 --- /dev/null +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECFBWINDOWSURFACE_H +#define QDIRECFBWINDOWSURFACE_H + +#include "qdirectfbpaintengine.h" +#include "qdirectfbpaintdevice.h" +#include "qdirectfbscreen.h" + +#ifndef QT_NO_QWS_DIRECTFB + +#include <private/qpaintengine_raster_p.h> +#include <private/qwindowsurface_qws_p.h> + +#ifdef QT_DIRECTFB_TIMING +#include <qdatetime.h> +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QDirectFBWindowSurface : public QWSWindowSurface, public QDirectFBPaintDevice +{ +public: + QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen *scr); + QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen *scr, QWidget *widget); + ~QDirectFBWindowSurface(); + +#ifdef QT_DIRECTFB_WM + void raise(); +#endif + bool isValid() const; + + void setGeometry(const QRect &rect); + + QString key() const { return QLatin1String("directfb"); } + QByteArray permanentState() const; + void setPermanentState(const QByteArray &state); + + bool scroll(const QRegion &area, int dx, int dy); + + bool move(const QPoint &offset); + + QImage image() const { return QImage(); } + QPaintDevice *paintDevice() { return this; } + + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + + void beginPaint(const QRegion &); + void endPaint(const QRegion &); + + IDirectFBSurface *surfaceForWidget(const QWidget *widget, QRect *rect) const; + IDirectFBSurface *directFBSurface() const; +#ifdef QT_DIRECTFB_WM + IDirectFBWindow *directFBWindow() const; +#endif +private: + void updateIsOpaque(); + void setOpaque(bool opaque); + void releaseSurface(); + +#ifdef QT_DIRECTFB_WM + void createWindow(const QRect &rect); + IDirectFBWindow *dfbWindow; +#else + enum Mode { + Primary, + Offscreen + } mode; +#endif + + DFBSurfaceFlipFlags flipFlags; + bool boundingRectFlip; + bool flushPending; +#ifdef QT_DIRECTFB_TIMING + int frames; + QTime timer; +#endif +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_QWS_DIRECTFB + +#endif // QDIRECFBWINDOWSURFACE_H |