src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the plugins of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qdirectfbmouse.h"
       
    43 
       
    44 #ifndef QT_NO_QWS_DIRECTFB
       
    45 
       
    46 #include "qdirectfbscreen.h"
       
    47 #include <qsocketnotifier.h>
       
    48 
       
    49 #include <directfb.h>
       
    50 #include <unistd.h>
       
    51 #include <fcntl.h>
       
    52 #include <errno.h>
       
    53 
       
    54 QT_BEGIN_NAMESPACE
       
    55 
       
    56 class QDirectFBMouseHandlerPrivate : public QObject
       
    57 {
       
    58     Q_OBJECT
       
    59 public:
       
    60     QDirectFBMouseHandlerPrivate(QDirectFBMouseHandler *h);
       
    61     ~QDirectFBMouseHandlerPrivate();
       
    62 
       
    63     void setEnabled(bool on);
       
    64 private:
       
    65     QDirectFBMouseHandler *handler;
       
    66     IDirectFBEventBuffer *eventBuffer;
       
    67 #ifndef QT_NO_DIRECTFB_LAYER
       
    68     IDirectFBDisplayLayer *layer;
       
    69 #endif
       
    70     QSocketNotifier *mouseNotifier;
       
    71 
       
    72     QPoint prevPoint;
       
    73     Qt::MouseButtons prevbuttons;
       
    74 
       
    75     DFBEvent event;
       
    76     uint bytesRead;
       
    77 
       
    78 private Q_SLOTS:
       
    79     void readMouseData();
       
    80 };
       
    81 
       
    82 QDirectFBMouseHandlerPrivate::QDirectFBMouseHandlerPrivate(QDirectFBMouseHandler *h)
       
    83     : handler(h), eventBuffer(0)
       
    84 {
       
    85     DFBResult result;
       
    86 
       
    87     QScreen *screen = QScreen::instance();
       
    88     if (!screen) {
       
    89         qCritical("QDirectFBMouseHandler: no screen instance found");
       
    90         return;
       
    91     }
       
    92 
       
    93     IDirectFB *fb = QDirectFBScreen::instance()->dfb();
       
    94     if (!fb) {
       
    95         qCritical("QDirectFBMouseHandler: DirectFB not initialized");
       
    96         return;
       
    97     }
       
    98 
       
    99 #ifndef QT_NO_DIRECTFB_LAYER
       
   100     layer = QDirectFBScreen::instance()->dfbDisplayLayer();
       
   101     if (!layer) {
       
   102         qCritical("QDirectFBMouseHandler: Unable to get primary display layer");
       
   103         return;
       
   104     }
       
   105 #endif
       
   106 
       
   107     DFBInputDeviceCapabilities caps;
       
   108     caps = DICAPS_BUTTONS | DICAPS_AXES;
       
   109     result = fb->CreateInputEventBuffer(fb, caps, DFB_TRUE, &eventBuffer);
       
   110     if (result != DFB_OK) {
       
   111         DirectFBError("QDirectFBMouseHandler: "
       
   112                       "Unable to create input event buffer", result);
       
   113         return;
       
   114     }
       
   115 
       
   116     int fd;
       
   117     result = eventBuffer->CreateFileDescriptor(eventBuffer, &fd);
       
   118     if (result != DFB_OK) {
       
   119         DirectFBError("QDirectFBMouseHandler: "
       
   120                       "Unable to create file descriptor", result);
       
   121         return;
       
   122     }
       
   123 
       
   124     int flags = fcntl(fd, F_GETFL, 0);
       
   125     fcntl(fd, F_SETFL, flags | O_NONBLOCK);
       
   126 
       
   127     // DirectFB seems to assume that the mouse always starts centered
       
   128     prevPoint = QPoint(screen->deviceWidth() / 2, screen->deviceHeight() / 2);
       
   129     prevbuttons = Qt::NoButton;
       
   130     memset(&event, 0, sizeof(event));
       
   131     bytesRead = 0;
       
   132 
       
   133     mouseNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
       
   134     connect(mouseNotifier, SIGNAL(activated(int)),this, SLOT(readMouseData()));
       
   135     setEnabled(true);
       
   136 }
       
   137 
       
   138 QDirectFBMouseHandlerPrivate::~QDirectFBMouseHandlerPrivate()
       
   139 {
       
   140     if (eventBuffer)
       
   141         eventBuffer->Release(eventBuffer);
       
   142 }
       
   143 
       
   144 void QDirectFBMouseHandlerPrivate::setEnabled(bool on)
       
   145 {
       
   146     if (mouseNotifier->isEnabled() != on) {
       
   147 #ifndef QT_NO_DIRECTFB_LAYER
       
   148         DFBResult result;
       
   149         result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE);
       
   150         if (result != DFB_OK) {
       
   151             DirectFBError("QDirectFBScreenCursor::QDirectFBScreenCursor: "
       
   152                           "Unable to set cooperative level", result);
       
   153         }
       
   154         result = layer->EnableCursor(layer, on ? 1 : 0);
       
   155         if (result != DFB_OK) {
       
   156             DirectFBError("QDirectFBScreenCursor::QDirectFBScreenCursor: "
       
   157                           "Unable to enable cursor", result);
       
   158         }
       
   159 
       
   160         result = layer->SetCooperativeLevel(layer, DLSCL_SHARED);
       
   161         if (result != DFB_OK) {
       
   162             DirectFBError("QDirectFBScreenCursor::show: "
       
   163                           "Unable to set cooperative level", result);
       
   164         }
       
   165 
       
   166         layer->SetCooperativeLevel(layer, DLSCL_SHARED);
       
   167 #endif
       
   168         mouseNotifier->setEnabled(on);
       
   169     }
       
   170 }
       
   171 
       
   172 void QDirectFBMouseHandlerPrivate::readMouseData()
       
   173 {
       
   174     if (!QScreen::instance())
       
   175         return;
       
   176 
       
   177     for (;;) {
       
   178         // GetEvent returns DFB_UNSUPPORTED after CreateFileDescriptor().
       
   179         // This seems stupid and I really hope it's a bug which will be fixed.
       
   180 
       
   181         // DFBResult ret = eventBuffer->GetEvent(eventBuffer, &event);
       
   182 
       
   183         char *buf = reinterpret_cast<char*>(&event);
       
   184         int ret = ::read(mouseNotifier->socket(),
       
   185                          buf + bytesRead, sizeof(DFBEvent) - bytesRead);
       
   186         if (ret == -1) {
       
   187             if (errno == EINTR)
       
   188                 continue;
       
   189             if (errno == EAGAIN)
       
   190                 return;
       
   191             qWarning("QDirectFBMouseHandlerPrivate::readMouseData(): %s",
       
   192                      strerror(errno));
       
   193             return;
       
   194         }
       
   195 
       
   196         Q_ASSERT(ret >= 0);
       
   197         bytesRead += ret;
       
   198         if (bytesRead < sizeof(DFBEvent))
       
   199             break;
       
   200         bytesRead = 0;
       
   201 
       
   202         Q_ASSERT(event.clazz == DFEC_INPUT);
       
   203 
       
   204         const DFBInputEvent input = event.input;
       
   205         int x = prevPoint.x();
       
   206         int y = prevPoint.y();
       
   207         int wheel = 0;
       
   208 
       
   209         if (input.type == DIET_AXISMOTION) {
       
   210 #if defined(QT_NO_DIRECTFB_LAYER) || defined(QT_DIRECTFB_WINDOW_AS_CURSOR)
       
   211             if (input.flags & DIEF_AXISABS) {
       
   212                 switch (input.axis) {
       
   213                 case DIAI_X: x = input.axisabs; break;
       
   214                 case DIAI_Y: y = input.axisabs; break;
       
   215                 default:
       
   216                     qWarning("QDirectFBMouseHandlerPrivate::readMouseData: "
       
   217                              "unknown axis (absolute) %d", input.axis);
       
   218                     break;
       
   219                 }
       
   220             } else if (input.flags & DIEF_AXISREL) {
       
   221                 switch (input.axis) {
       
   222                 case DIAI_X: x += input.axisrel; break;
       
   223                 case DIAI_Y: y += input.axisrel; break;
       
   224                 case DIAI_Z: wheel = -120 * input.axisrel; break;
       
   225                 default:
       
   226                     qWarning("QDirectFBMouseHandlerPrivate::readMouseData: "
       
   227                              "unknown axis (releative) %d", input.axis);
       
   228                 }
       
   229             }
       
   230 #else
       
   231             if (input.axis == DIAI_X || input.axis == DIAI_Y) {
       
   232                 DFBResult result = layer->GetCursorPosition(layer, &x, &y);
       
   233                 if (result != DFB_OK) {
       
   234                     DirectFBError("QDirectFBMouseHandler::readMouseData",
       
   235                                   result);
       
   236                 }
       
   237             } else if (input.axis == DIAI_Z) {
       
   238                 Q_ASSERT(input.flags & DIEF_AXISREL);
       
   239                 wheel = input.axisrel;
       
   240                 wheel *= -120;
       
   241             }
       
   242 #endif
       
   243         }
       
   244 
       
   245         Qt::MouseButtons buttons = Qt::NoButton;
       
   246         if (input.flags & DIEF_BUTTONS) {
       
   247             if (input.buttons & DIBM_LEFT)
       
   248                 buttons |= Qt::LeftButton;
       
   249             if (input.buttons & DIBM_MIDDLE)
       
   250                 buttons |= Qt::MidButton;
       
   251             if (input.buttons & DIBM_RIGHT)
       
   252                 buttons |= Qt::RightButton;
       
   253         }
       
   254 
       
   255         QPoint p = QPoint(x, y);
       
   256         handler->limitToScreen(p);
       
   257 
       
   258         if (p == prevPoint && wheel == 0 && buttons == prevbuttons)
       
   259             continue;
       
   260 
       
   261         prevPoint = p;
       
   262         prevbuttons = buttons;
       
   263 
       
   264         handler->mouseChanged(p, buttons, wheel);
       
   265     }
       
   266 }
       
   267 
       
   268 QDirectFBMouseHandler::QDirectFBMouseHandler(const QString &driver,
       
   269                                              const QString &device)
       
   270     : QWSMouseHandler(driver, device)
       
   271 {
       
   272     d = new QDirectFBMouseHandlerPrivate(this);
       
   273 }
       
   274 
       
   275 QDirectFBMouseHandler::~QDirectFBMouseHandler()
       
   276 {
       
   277     delete d;
       
   278 }
       
   279 
       
   280 void QDirectFBMouseHandler::suspend()
       
   281 {
       
   282     d->setEnabled(false);
       
   283 }
       
   284 
       
   285 void QDirectFBMouseHandler::resume()
       
   286 {
       
   287     d->setEnabled(true);
       
   288 }
       
   289 
       
   290 QT_END_NAMESPACE
       
   291 #include "qdirectfbmouse.moc"
       
   292 #endif // QT_NO_QWS_DIRECTFB
       
   293 
       
   294