diff options
author | Jeremy Katz <jeremy.katz@nokia.com> | 2009-12-04 13:37:02 +0100 |
---|---|---|
committer | Jeremy Katz <jeremy.katz@nokia.com> | 2009-12-04 13:37:02 +0100 |
commit | b699cdad144e0a23f1dabf26c05fde2f4e3ec6f9 (patch) | |
tree | f308344722d8d95b293c284e9b6d71596d24ac44 /src | |
parent | afc403f3c04c6ef995ed7272b277c0f62c24d5e5 (diff) |
caching of X11 cursors, with an expiration after 3 seconds
This also contains a stub for Qt::BitmapCursor cursors. Conversion to the
X11 bitmap format is missing.
Diffstat (limited to 'src')
5 files changed, 282 insertions, 60 deletions
diff --git a/src/plugins/graphicssystems/testlite/qgraphicssystem_testlite.cpp b/src/plugins/graphicssystems/testlite/qgraphicssystem_testlite.cpp index bdcac37a62..72d364af59 100644 --- a/src/plugins/graphicssystems/testlite/qgraphicssystem_testlite.cpp +++ b/src/plugins/graphicssystems/testlite/qgraphicssystem_testlite.cpp @@ -70,7 +70,7 @@ public: if (!ws) return; - ws->setCursor(cursor->shape()); + ws->setCursor(cursor); } }; diff --git a/src/plugins/graphicssystems/testlite/qwindowsurface_testlite.cpp b/src/plugins/graphicssystems/testlite/qwindowsurface_testlite.cpp index 13dbae1649..fde54a1d78 100644 --- a/src/plugins/graphicssystems/testlite/qwindowsurface_testlite.cpp +++ b/src/plugins/graphicssystems/testlite/qwindowsurface_testlite.cpp @@ -595,8 +595,8 @@ void QTestLiteWindowSurface::setWindowTitle(const QString &title) xw->setWindowTitle(title); } -void QTestLiteWindowSurface::setCursor(Qt::CursorShape shape) +void QTestLiteWindowSurface::setCursor(QCursor *cursor) { - xw->setCursorShape(shape); + xw->setCursor(cursor); } QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/testlite/qwindowsurface_testlite.h b/src/plugins/graphicssystems/testlite/qwindowsurface_testlite.h index 43d1b233b2..9f9f0520d9 100644 --- a/src/plugins/graphicssystems/testlite/qwindowsurface_testlite.h +++ b/src/plugins/graphicssystems/testlite/qwindowsurface_testlite.h @@ -83,7 +83,7 @@ public: void lower(); void setWindowTitle(const QString &title); - void setCursor(Qt::CursorShape shape); + void setCursor(QCursor * cursor); private: QTestLiteGraphicsSystem *mGraphicsSystem; diff --git a/src/plugins/graphicssystems/testlite/x11util.cpp b/src/plugins/graphicssystems/testlite/x11util.cpp index 8c0b6c1669..1a421e82fa 100644 --- a/src/plugins/graphicssystems/testlite/x11util.cpp +++ b/src/plugins/graphicssystems/testlite/x11util.cpp @@ -57,6 +57,10 @@ #include <X11/cursorfont.h> +#include <QBitmap> +#include <QCursor> +#include <QDateTime> +#include <QPixmap> //### remove stuff we don't want from qt_x11_p.h #undef ATOM @@ -325,6 +329,7 @@ MyDisplay::MyDisplay() wmProtocolsAtom = XInternAtom (display, "WM_PROTOCOLS", False); wmDeleteWindowAtom = XInternAtom (display, "WM_DELETE_WINDOW", False); + cursors = new MyX11Cursors(display); } @@ -401,6 +406,7 @@ MyWindow::MyWindow(MyDisplay *display, int x, int y, int w, int h) setWindowTitle(QLatin1String("Qt Lighthouse")); + currentCursor = -1; } @@ -802,71 +808,228 @@ void MyWindow::setVisible(bool visible) XUnmapWindow(xd->display, window); } +MyX11Cursors::MyX11Cursors(Display * d) : firstExpired(0), lastExpired(0), display(d), removalDelay(3) +{ + connect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); +} -void MyWindow::setCursorShape(int cshape) +void MyX11Cursors::insertNode(MyX11CursorNode * node) { - if (cshape < 0 || cshape > Qt::LastCursor) - return; + QDateTime now = QDateTime::currentDateTime(); + QDateTime timeout = now.addSecs(removalDelay); + node->setExpiration(timeout); + node->setPost(0); + if (lastExpired) { + lastExpired->setPost(node); + node->setAnte(lastExpired); + } + lastExpired = node; + if (!firstExpired) { + firstExpired = node; + node->setAnte(0); + int interval = removalDelay * 1000; + timer.setInterval(interval); + timer.start(); + } +} - static Cursor cursors[Qt::LastCursor+1] = {XNone}; +void MyX11Cursors::removeNode(MyX11CursorNode * node) +{ + MyX11CursorNode *pre = node->ante(); + MyX11CursorNode *post = node->post(); + if (pre) + pre->setPost(post); + if (post) + post->setAnte(pre); + if (node == lastExpired) + lastExpired = pre; + if (node == firstExpired) { + firstExpired = post; + if (!firstExpired) { + timer.stop(); + return; + } + int interval = QDateTime::currentDateTime().secsTo(firstExpired->expiration()) * 1000; + timer.stop(); + timer.setInterval(interval); + timer.start(); + } +} - Cursor cursor = cursors[cshape]; - if (!cursor) { - switch (cshape) { - case Qt::ArrowCursor: - cursor = XCreateFontCursor(xd->display, XC_left_ptr); - break; - case Qt::UpArrowCursor: - cursor = XCreateFontCursor(xd->display, XC_center_ptr); - break; - case Qt::CrossCursor: - cursor = XCreateFontCursor(xd->display, XC_crosshair); - break; - case Qt::WaitCursor: - cursor = XCreateFontCursor(xd->display, XC_watch); - break; - case Qt::IBeamCursor: - cursor = XCreateFontCursor(xd->display, XC_xterm); - break; - case Qt::SizeAllCursor: - cursor = XCreateFontCursor(xd->display, XC_fleur); - break; - case Qt::PointingHandCursor: - cursor = XCreateFontCursor(xd->display, XC_hand2); - break; - case Qt::SizeBDiagCursor: - cursor = XCreateFontCursor(xd->display, XC_top_right_corner); - break; - case Qt::SizeFDiagCursor: - cursor = XCreateFontCursor(xd->display, XC_bottom_right_corner); - break; - case Qt::SizeVerCursor: - case Qt::SplitVCursor: - cursor = XCreateFontCursor(xd->display, XC_sb_v_double_arrow); - break; - case Qt::SizeHorCursor: - case Qt::SplitHCursor: - cursor = XCreateFontCursor(xd->display, XC_sb_h_double_arrow); - break; - case Qt::WhatsThisCursor: - cursor = XCreateFontCursor(xd->display, XC_question_arrow); - break; - case Qt::ForbiddenCursor: - cursor = XCreateFontCursor(xd->display, XC_circle); - break; - case Qt::BusyCursor: - cursor = XCreateFontCursor(xd->display, XC_watch); - break; +void MyX11Cursors::incrementUseCount(int id) +{ + MyX11CursorNode * node = lookupMap.value(id); + Q_ASSERT(node); + if (!node->refCount) + removeNode(node); + node->refCount++; +} - default: //default cursor for all the rest - break; +void MyX11Cursors::decrementUseCount(int id) +{ + MyX11CursorNode * node = lookupMap.value(id); + Q_ASSERT(node); + node->refCount--; + if (!node->refCount) + insertNode(node); +} + +void MyX11Cursors::createNode(int id, Cursor c) +{ + MyX11CursorNode * node = new MyX11CursorNode(id, c); + lookupMap.insert(id, node); +} + +void MyX11Cursors::timeout() +{ + MyX11CursorNode * node; + node = firstExpired; + QDateTime now = QDateTime::currentDateTime(); + while (node && now.secsTo(node->expiration()) < 1) { + Cursor c = node->cursor(); + int id = node->id(); + lookupMap.take(id); + MyX11CursorNode * tmp = node; + node = node->post(); + delete tmp; + XFreeCursor(display, c); + } + firstExpired = node; + if (node == 0) { + timer.stop(); + lastExpired = 0; + } + else { + int interval = QDateTime::currentDateTime().secsTo(firstExpired->expiration()) * 1000; + timer.setInterval(interval); + timer.start(); + } +} + +Cursor MyX11Cursors::cursor(int id) +{ + MyX11CursorNode * node = lookupMap.value(id); + Q_ASSERT(node); + return node->cursor(); +} + +void MyWindow::setCursor(QCursor * cursor) +{ + int id = cursor->handle(); + if (id == currentCursor) + return; + Cursor c; + if (!xd->cursors->exists(id)) { + if (cursor->shape() == Qt::BitmapCursor) + c = createCursorBitmap(cursor); + else + c = createCursorShape(cursor->shape()); + if (!c) { + return; } - cursors[cshape] = cursor; + xd->cursors->createNode(id, c); + } else { + xd->cursors->incrementUseCount(id); + c = xd->cursors->cursor(id); } - XDefineCursor(xd->display, window, cursor); + + if (currentCursor != -1) + xd->cursors->decrementUseCount(currentCursor); + currentCursor = id; + + XDefineCursor(xd->display, window, c); XFlush(xd->display); } +Cursor MyWindow::createCursorBitmap(QCursor * cursor) +{ +/* + XColor bg, fg; + bg.red = 255 << 8; + bg.green = 255 << 8; + bg.blue = 255 << 8; + fg.red = 0; + fg.green = 0; + fg.blue = 0; + QPoint spot = cursor->hotSpot(); + Window rootwin = window; + + const QBitmap * map = cursor->bitmap(); + char * mapBits = reinterpret_cast<char *>(map->toImage().bits()); + const QBitmap * mask = cursor->mask(); + char * maskBits = reinterpret_cast<char *>(mask->toImage().bits()); + + Pixmap cp = XCreateBitmapFromData(xd->display, rootwin, mapBits, map->width(), map->height()); + Pixmap mp = XCreateBitmapFromData(xd->display, rootwin, maskBits, map->width(), map->height()); + Cursor c = XCreatePixmapCursor(xd->display, cp, mp, &fg, &bg, spot.x(), spot.y()); + XFreePixmap(xd->display, cp); + XFreePixmap(xd->display, mp); + + return c; +*/ + // correct pixmap cursor parsing not implemented yet + return createCursorShape(Qt::ArrowCursor); +} + +Cursor MyWindow::createCursorShape(int cshape) +{ + Cursor cursor = 0; + + if (cshape < 0 || cshape > Qt::LastCursor) + return 0; + + switch (cshape) { + case Qt::ArrowCursor: + cursor = XCreateFontCursor(xd->display, XC_left_ptr); + break; + case Qt::UpArrowCursor: + cursor = XCreateFontCursor(xd->display, XC_center_ptr); + break; + case Qt::CrossCursor: + cursor = XCreateFontCursor(xd->display, XC_crosshair); + break; + case Qt::WaitCursor: + cursor = XCreateFontCursor(xd->display, XC_watch); + break; + case Qt::IBeamCursor: + cursor = XCreateFontCursor(xd->display, XC_xterm); + break; + case Qt::SizeAllCursor: + cursor = XCreateFontCursor(xd->display, XC_fleur); + break; + case Qt::PointingHandCursor: + cursor = XCreateFontCursor(xd->display, XC_hand2); + break; + case Qt::SizeBDiagCursor: + cursor = XCreateFontCursor(xd->display, XC_top_right_corner); + break; + case Qt::SizeFDiagCursor: + cursor = XCreateFontCursor(xd->display, XC_bottom_right_corner); + break; + case Qt::SizeVerCursor: + case Qt::SplitVCursor: + cursor = XCreateFontCursor(xd->display, XC_sb_v_double_arrow); + break; + case Qt::SizeHorCursor: + case Qt::SplitHCursor: + cursor = XCreateFontCursor(xd->display, XC_sb_h_double_arrow); + break; + case Qt::WhatsThisCursor: + cursor = XCreateFontCursor(xd->display, XC_question_arrow); + break; + case Qt::ForbiddenCursor: + cursor = XCreateFontCursor(xd->display, XC_circle); + break; + case Qt::BusyCursor: + cursor = XCreateFontCursor(xd->display, XC_watch); + break; + + default: //default cursor for all the rest + break; + } + return cursor; +} + #if 0 diff --git a/src/plugins/graphicssystems/testlite/x11util.h b/src/plugins/graphicssystems/testlite/x11util.h index fc88297f1b..2a73f3ed52 100644 --- a/src/plugins/graphicssystems/testlite/x11util.h +++ b/src/plugins/graphicssystems/testlite/x11util.h @@ -44,6 +44,8 @@ #include <QObject> #include <QImage> +#include <qtimer.h> +#include <QDateTime> #include <private/qt_x11_p.h> @@ -52,6 +54,7 @@ class MyWindow; +class MyX11Cursors; class MyDisplay : public QObject { @@ -77,6 +80,8 @@ public: //### int physicalHeight; QList<MyWindow*> windowList; + + MyX11Cursors * cursors; }; class QTestLiteWindowSurface; //### abstract callback interface, anyone? @@ -109,7 +114,9 @@ public: Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags); void setVisible(bool visible); - void setCursorShape(int cshape); + void setCursor(QCursor * cursor); + Cursor createCursorShape(int cshape); + Cursor createCursorBitmap(QCursor * cursor); void setWindowTitle(const QString &title); @@ -123,10 +130,62 @@ public: //### GC gc; QTestLiteWindowSurface *windowSurface; + + int currentCursor; +}; + +class MyX11CursorNode +{ +public: + MyX11CursorNode(int id, Cursor c) { idValue = id; cursorValue = c; refCount = 1; } + QDateTime expiration() { return t; } + void setExpiration(QDateTime val) { t = val; } + MyX11CursorNode * ante() { return before; } + void setAnte(MyX11CursorNode *node) { before = node; } + MyX11CursorNode * post() { return after; } + void setPost(MyX11CursorNode *node) { after = node; } + Cursor cursor() { return cursorValue; } + int id() { return idValue; } + unsigned int refCount; + +private: + MyX11CursorNode *before; + MyX11CursorNode *after; + QDateTime t; + Cursor cursorValue; + int idValue; + + Display * display; }; +class MyX11Cursors : public QObject +{ + Q_OBJECT +public: + MyX11Cursors(Display * d); + ~MyX11Cursors() { timer.stop(); } + void incrementUseCount(int id); + void decrementUseCount(int id); + void createNode(int id, Cursor c); + bool exists(int id) { return lookupMap.contains(id); } + Cursor cursor(int id); +public slots: + void timeout(); +private: + void removeNode(MyX11CursorNode *node); + void insertNode(MyX11CursorNode *node); + // linked list of cursors currently not assigned to any window + MyX11CursorNode *firstExpired; + MyX11CursorNode *lastExpired; + QHash<int, MyX11CursorNode *> lookupMap; + QTimer timer; + + Display *display; + + int removalDelay; +}; #endif // MYX11UTIL_H |