summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJeremy Katz <jeremy.katz@nokia.com>2009-12-04 13:37:02 +0100
committerJeremy Katz <jeremy.katz@nokia.com>2009-12-04 13:37:02 +0100
commitb699cdad144e0a23f1dabf26c05fde2f4e3ec6f9 (patch)
treef308344722d8d95b293c284e9b6d71596d24ac44 /src
parentafc403f3c04c6ef995ed7272b277c0f62c24d5e5 (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')
-rw-r--r--src/plugins/graphicssystems/testlite/qgraphicssystem_testlite.cpp2
-rw-r--r--src/plugins/graphicssystems/testlite/qwindowsurface_testlite.cpp4
-rw-r--r--src/plugins/graphicssystems/testlite/qwindowsurface_testlite.h2
-rw-r--r--src/plugins/graphicssystems/testlite/x11util.cpp273
-rw-r--r--src/plugins/graphicssystems/testlite/x11util.h61
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