136 lines
5.1 KiB
Diff
136 lines
5.1 KiB
Diff
From 422838685c31d9b57133a8711bfd5db92095d96d Mon Sep 17 00:00:00 2001
|
|
From: Robin Burchell <robin.burchell@viroteck.net>
|
|
Date: Wed, 7 Sep 2016 14:34:03 +0200
|
|
Subject: [PATCH] xcb: Treat bitmap cursors differently from shaped cursors
|
|
|
|
QXcbCursor had a "cache" of cursor handles. Unfortunately, as QXcbCursor has its
|
|
lifetime tied to the screen, this cache grew unbounded whenever the cursor was
|
|
set: this could be witnessed worst when repeatedly setting the current cursor to
|
|
a different pixmap each time.
|
|
|
|
We fix this by keeping the cursor cache only for the "regular" shaped cursors
|
|
that are often shared between windows, working on the assumption that custom
|
|
cursors are generally specific only to a given window. This makes the lifetime
|
|
of the bitmap cursors much more clear: they are tied to that window, and when
|
|
the window is destroyed (or changes cursor), so too is the bitmap cursor
|
|
destroyed (if set).
|
|
|
|
Reported-by: Will Thompson <wjt@endlessm.com>
|
|
Change-Id: Ia558d858ff49e89cd5220344567203eb0267a133
|
|
Reviewed-by: Uli Schlachter <psychon@znc.in>
|
|
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
|
|
---
|
|
src/plugins/platforms/xcb/qxcbcursor.cpp | 24 +++++++++++++++++-------
|
|
src/plugins/platforms/xcb/qxcbwindow.cpp | 22 +++++++++++++++++++---
|
|
src/plugins/platforms/xcb/qxcbwindow.h | 3 ++-
|
|
3 files changed, 38 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
|
|
index b321ed9..4646ced 100644
|
|
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
|
|
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
|
|
@@ -353,17 +353,27 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget)
|
|
return;
|
|
|
|
xcb_cursor_t c = XCB_CURSOR_NONE;
|
|
+ bool isBitmapCursor = false;
|
|
+
|
|
if (cursor) {
|
|
- const QXcbCursorCacheKey key(*cursor);
|
|
- CursorHash::iterator it = m_cursorHash.find(key);
|
|
- if (it == m_cursorHash.end()) {
|
|
- const Qt::CursorShape shape = cursor->shape();
|
|
- it = m_cursorHash.insert(key, shape == Qt::BitmapCursor ? createBitmapCursor(cursor) : createFontCursor(shape));
|
|
+ const Qt::CursorShape shape = cursor->shape();
|
|
+ isBitmapCursor = shape == Qt::BitmapCursor;
|
|
+
|
|
+ if (!isBitmapCursor) {
|
|
+ const QXcbCursorCacheKey key(*cursor);
|
|
+ CursorHash::iterator it = m_cursorHash.find(key);
|
|
+ if (it == m_cursorHash.end()) {
|
|
+ it = m_cursorHash.insert(key, createFontCursor(shape));
|
|
+ }
|
|
+ c = it.value();
|
|
+ } else {
|
|
+ // Do not cache bitmap cursors, as otherwise they have unclear
|
|
+ // lifetime (we effectively leak xcb_cursor_t).
|
|
+ c = createBitmapCursor(cursor);
|
|
}
|
|
- c = it.value();
|
|
}
|
|
|
|
- w->setCursor(c);
|
|
+ w->setCursor(c, isBitmapCursor);
|
|
}
|
|
|
|
static int cursorIdForShape(int cshape)
|
|
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
|
|
index d46228c..5f402b6 100644
|
|
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
|
|
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
|
|
@@ -302,6 +302,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
|
|
, m_lastWindowStateEvent(-1)
|
|
, m_syncState(NoSyncNeeded)
|
|
, m_pendingSyncRequest(0)
|
|
+ , m_currentBitmapCursor(XCB_CURSOR_NONE)
|
|
{
|
|
setConnection(xcbScreen()->connection());
|
|
}
|
|
@@ -620,6 +621,9 @@ void QXcbWindow::create()
|
|
|
|
QXcbWindow::~QXcbWindow()
|
|
{
|
|
+ if (m_currentBitmapCursor != XCB_CURSOR_NONE) {
|
|
+ xcb_free_cursor(xcb_connection(), m_currentBitmapCursor);
|
|
+ }
|
|
if (window()->type() != Qt::ForeignWindow)
|
|
destroy();
|
|
else {
|
|
@@ -2665,10 +2669,22 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
|
|
return result;
|
|
}
|
|
|
|
-void QXcbWindow::setCursor(xcb_cursor_t cursor)
|
|
+void QXcbWindow::setCursor(xcb_cursor_t cursor, bool isBitmapCursor)
|
|
{
|
|
- xcb_change_window_attributes(xcb_connection(), m_window, XCB_CW_CURSOR, &cursor);
|
|
- xcb_flush(xcb_connection());
|
|
+ xcb_connection_t *conn = xcb_connection();
|
|
+
|
|
+ xcb_change_window_attributes(conn, m_window, XCB_CW_CURSOR, &cursor);
|
|
+ xcb_flush(conn);
|
|
+
|
|
+ if (m_currentBitmapCursor != XCB_CURSOR_NONE) {
|
|
+ xcb_free_cursor(conn, m_currentBitmapCursor);
|
|
+ }
|
|
+
|
|
+ if (isBitmapCursor) {
|
|
+ m_currentBitmapCursor = cursor;
|
|
+ } else {
|
|
+ m_currentBitmapCursor = XCB_CURSOR_NONE;
|
|
+ }
|
|
}
|
|
|
|
void QXcbWindow::windowEvent(QEvent *event)
|
|
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
|
|
index b8bcf44..f2b6904 100644
|
|
--- a/src/plugins/platforms/xcb/qxcbwindow.h
|
|
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
|
|
@@ -97,7 +97,7 @@ class Q_XCB_EXPORT QXcbWindow : public QXcbObject, public QXcbWindowEventListene
|
|
bool setKeyboardGrabEnabled(bool grab) Q_DECL_OVERRIDE;
|
|
bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE;
|
|
|
|
- void setCursor(xcb_cursor_t cursor);
|
|
+ void setCursor(xcb_cursor_t cursor, bool isBitmapCursor);
|
|
|
|
QSurfaceFormat format() const Q_DECL_OVERRIDE;
|
|
|
|
@@ -263,6 +263,7 @@ public Q_SLOTS:
|
|
SyncState m_syncState;
|
|
|
|
QXcbSyncWindowRequest *m_pendingSyncRequest;
|
|
+ xcb_cursor_t m_currentBitmapCursor;
|
|
};
|
|
|
|
QT_END_NAMESPACE
|