From b02ddd29685df69324ca646f462e38e3726d0006 Mon Sep 17 00:00:00 2001 From: Vasilito Date: Thu, 7 May 2026 20:55:17 +0100 Subject: [PATCH] fix: guard Qt Wayland empty cursors Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../qtwayland-empty-cursor-guards.patch | 71 +++++++++++++++++++ .../qtwayland-empty-cursor-guards.patch | 71 +++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 local/patches/qtbase/qtwayland-empty-cursor-guards.patch create mode 100644 local/recipes/qt/qtbase/qtwayland-empty-cursor-guards.patch diff --git a/local/patches/qtbase/qtwayland-empty-cursor-guards.patch b/local/patches/qtbase/qtwayland-empty-cursor-guards.patch new file mode 100644 index 000000000..366c3cb04 --- /dev/null +++ b/local/patches/qtbase/qtwayland-empty-cursor-guards.patch @@ -0,0 +1,71 @@ +--- a/src/plugins/platforms/wayland/qwaylandcursor.cpp ++++ b/src/plugins/platforms/wayland/qwaylandcursor.cpp +@@ -177,6 +177,10 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape) + ShapeAndName{shape, ""}, byShape); + for (auto it = p.first; it != p.second; ++it) { + if (wl_cursor *cursor = wl_cursor_theme_get_cursor(m_theme, it->name)) { ++ if (cursor->image_count == 0 || !cursor->images || !cursor->images[0]) { ++ qCWarning(lcQpaWayland) << "Ignoring empty Wayland cursor" << it->name; ++ continue; ++ } + m_cursors[shape] = cursor; + return cursor; + } +--- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp ++++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +@@ -225,6 +225,10 @@ void QWaylandInputDevice::Pointer::updateCursorTheme() + return; // A warning has already been printed in loadCursorTheme + + if (auto *arrow = mCursor.theme->cursor(Qt::ArrowCursor)) { ++ if (arrow->image_count == 0 || !arrow->images || !arrow->images[0]) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an empty arrow cursor"; ++ return; ++ } + int arrowPixelSize = qMax(arrow->images[0]->width, arrow->images[0]->height); // Not all cursor themes are square + while (scale > 1 && arrowPixelSize / scale < cursorSize.width()) + --scale; +@@ -279,8 +283,16 @@ void QWaylandInputDevice::Pointer::updateCursor() + + if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) { ++ if (waylandCursor->image_count == 0 || !waylandCursor->images) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an empty cursor" << shape; ++ return; ++ } + uint duration = 0; + int frame = wl_cursor_frame_and_duration(waylandCursor, time, &duration); ++ if (frame < 0 || uint(frame) >= waylandCursor->image_count || !waylandCursor->images[frame]) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an invalid cursor frame" << shape << frame; ++ return; ++ } + ::wl_cursor_image *image = waylandCursor->images[frame]; + + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); +--- a/src/plugins/platforms/wayland/qwaylandtabletv2.cpp ++++ b/src/plugins/platforms/wayland/qwaylandtabletv2.cpp +@@ -62,6 +62,10 @@ void QWaylandTabletToolV2::updateCursorTheme() + return; // A warning has already been printed in loadCursorTheme + + if (auto *arrow = mCursor.theme->cursor(Qt::ArrowCursor)) { ++ if (arrow->image_count == 0 || !arrow->images || !arrow->images[0]) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an empty tablet arrow cursor"; ++ return; ++ } + int arrowPixelSize = qMax(arrow->images[0]->width, + arrow->images[0]->height); // Not all cursor themes are square + while (scale > 1 && arrowPixelSize / scale < cursorSize.width()) +@@ -117,8 +121,16 @@ void QWaylandTabletToolV2::updateCursor() + + if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) { ++ if (waylandCursor->image_count == 0 || !waylandCursor->images) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an empty tablet cursor" << shape; ++ return; ++ } + uint duration = 0; + int frame = wl_cursor_frame_and_duration(waylandCursor, time, &duration); ++ if (frame < 0 || uint(frame) >= waylandCursor->image_count || !waylandCursor->images[frame]) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an invalid tablet cursor frame" << shape << frame; ++ return; ++ } + ::wl_cursor_image *image = waylandCursor->images[frame]; + + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); diff --git a/local/recipes/qt/qtbase/qtwayland-empty-cursor-guards.patch b/local/recipes/qt/qtbase/qtwayland-empty-cursor-guards.patch new file mode 100644 index 000000000..f50a70f43 --- /dev/null +++ b/local/recipes/qt/qtbase/qtwayland-empty-cursor-guards.patch @@ -0,0 +1,71 @@ +--- source/src/plugins/platforms/wayland/qwaylandcursor.cpp ++++ source/src/plugins/platforms/wayland/qwaylandcursor.cpp +@@ -177,6 +177,10 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape) + ShapeAndName{shape, ""}, byShape); + for (auto it = p.first; it != p.second; ++it) { + if (wl_cursor *cursor = wl_cursor_theme_get_cursor(m_theme, it->name)) { ++ if (cursor->image_count == 0 || !cursor->images || !cursor->images[0]) { ++ qCWarning(lcQpaWayland) << "Ignoring empty Wayland cursor" << it->name; ++ continue; ++ } + m_cursors[shape] = cursor; + return cursor; + } +--- source/src/plugins/platforms/wayland/qwaylandinputdevice.cpp ++++ source/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +@@ -225,6 +225,10 @@ void QWaylandInputDevice::Pointer::updateCursorTheme() + return; // A warning has already been printed in loadCursorTheme + + if (auto *arrow = mCursor.theme->cursor(Qt::ArrowCursor)) { ++ if (arrow->image_count == 0 || !arrow->images || !arrow->images[0]) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an empty arrow cursor"; ++ return; ++ } + int arrowPixelSize = qMax(arrow->images[0]->width, arrow->images[0]->height); // Not all cursor themes are square + while (scale > 1 && arrowPixelSize / scale < cursorSize.width()) + --scale; +@@ -279,8 +283,16 @@ void QWaylandInputDevice::Pointer::updateCursor() + + if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) { ++ if (waylandCursor->image_count == 0 || !waylandCursor->images) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an empty cursor" << shape; ++ return; ++ } + uint duration = 0; + int frame = wl_cursor_frame_and_duration(waylandCursor, time, &duration); ++ if (frame < 0 || uint(frame) >= waylandCursor->image_count || !waylandCursor->images[frame]) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an invalid cursor frame" << shape << frame; ++ return; ++ } + ::wl_cursor_image *image = waylandCursor->images[frame]; + + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); +--- source/src/plugins/platforms/wayland/qwaylandtabletv2.cpp ++++ source/src/plugins/platforms/wayland/qwaylandtabletv2.cpp +@@ -62,6 +62,10 @@ void QWaylandTabletToolV2::updateCursorTheme() + return; // A warning has already been printed in loadCursorTheme + + if (auto *arrow = mCursor.theme->cursor(Qt::ArrowCursor)) { ++ if (arrow->image_count == 0 || !arrow->images || !arrow->images[0]) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an empty tablet arrow cursor"; ++ return; ++ } + int arrowPixelSize = qMax(arrow->images[0]->width, + arrow->images[0]->height); // Not all cursor themes are square + while (scale > 1 && arrowPixelSize / scale < cursorSize.width()) +@@ -117,8 +121,16 @@ void QWaylandTabletToolV2::updateCursor() + + if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) { ++ if (waylandCursor->image_count == 0 || !waylandCursor->images) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an empty tablet cursor" << shape; ++ return; ++ } + uint duration = 0; + int frame = wl_cursor_frame_and_duration(waylandCursor, time, &duration); ++ if (frame < 0 || uint(frame) >= waylandCursor->image_count || !waylandCursor->images[frame]) { ++ qCWarning(lcQpaWayland) << "Cursor theme returned an invalid tablet cursor frame" << shape << frame; ++ return; ++ } + ::wl_cursor_image *image = waylandCursor->images[frame]; + + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);