src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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
+
+