commit:     f77dfc2425bbeb45ab71c5b33123de0e34ed1287
Author:     Sam James <sam <AT> gentoo <DOT> org>
AuthorDate: Mon Mar  9 10:16:58 2026 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Mon Mar  9 10:16:58 2026 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=f77dfc24

kde-plasma/spectacle: fix crash on quit

KDE-bug: https://bugs.kde.org/show_bug.cgi?id=517064
Signed-off-by: Sam James <sam <AT> gentoo.org>

 .../files/spectacle-6.6.2-crash-quit.patch         | 308 +++++++++++++++++++++
 ...acle-6.6.2.ebuild => spectacle-6.6.2-r1.ebuild} |   4 +
 2 files changed, 312 insertions(+)

diff --git a/kde-plasma/spectacle/files/spectacle-6.6.2-crash-quit.patch 
b/kde-plasma/spectacle/files/spectacle-6.6.2-crash-quit.patch
new file mode 100644
index 000000000000..b757f9172ff3
--- /dev/null
+++ b/kde-plasma/spectacle/files/spectacle-6.6.2-crash-quit.patch
@@ -0,0 +1,308 @@
+https://invent.kde.org/plasma/spectacle/-/commit/e5f1a6ef499d4569db8dc2ddd0a282caa6cf7c60
+
+From e5f1a6ef499d4569db8dc2ddd0a282caa6cf7c60 Mon Sep 17 00:00:00 2001
+From: Noah Davis <[email protected]>
+Date: Thu, 5 Mar 2026 13:05:24 -0500
+Subject: [PATCH] Fix crash on quit with a quickly selected region
+
+If you quickly selected a region and quickly pressed escape to quit, it could 
cause a crash.
+
+BUG: 517064
+
+FIXED-IN: 6.6.3
+
+
+(cherry picked from commit 3dff870b1628c29a0bbbab0fa44ebd0515769524)
+
+Co-authored-by: Noah Davis <[email protected]>
+---
+ src/Gui/ExportMenu.cpp         | 21 +++++++++++++++------
+ src/Gui/ExportMenu.h           |  1 +
+ src/Gui/HelpMenu.cpp           | 21 +++++++++++++++------
+ src/Gui/HelpMenu.h             |  1 +
+ src/Gui/OptionsMenu.cpp        | 21 +++++++++++++++------
+ src/Gui/OptionsMenu.h          |  1 +
+ src/Gui/RecordingModeMenu.cpp  | 21 +++++++++++++++------
+ src/Gui/RecordingModeMenu.h    |  1 +
+ src/Gui/ScreenshotModeMenu.cpp | 21 +++++++++++++++------
+ src/Gui/ScreenshotModeMenu.h   |  1 +
+ 10 files changed, 80 insertions(+), 30 deletions(-)
+
+diff --git a/src/Gui/ExportMenu.cpp b/src/Gui/ExportMenu.cpp
+index cf8a98a6c..a1a361315 100644
+--- a/src/Gui/ExportMenu.cpp
++++ b/src/Gui/ExportMenu.cpp
+@@ -33,7 +33,7 @@
+ using namespace std::chrono_literals;
+ using namespace Qt::StringLiterals;
+ 
+-static std::unique_ptr<ExportMenu> s_instance = nullptr;
++static ExportMenu *s_instance = nullptr;
+ 
+ ExportMenu::ExportMenu(QWidget *parent)
+     : SpectacleMenu(parent)
+@@ -60,16 +60,25 @@ ExportMenu::ExportMenu(QWidget *parent)
+     getKServiceItems();
+ }
+ 
++ExportMenu::~ExportMenu()
++{
++    s_instance = nullptr;
++}
++
+ ExportMenu *ExportMenu::instance()
+ {
+     if (!s_instance && SpectacleCore::instance()) {
+-        s_instance = std::unique_ptr<ExportMenu>(new ExportMenu);
+-        // We have to destroy this after SpectacleCore to prevent a crash 
from the Qt Quick UI.
+-        connect(SpectacleCore::instance(), &QObject::destroyed, 
s_instance.get(), [] {
+-            s_instance.reset();
++        s_instance = new ExportMenu;
++        // We have to destroy this after SpectacleCore to ensure that 
destructors
++        // are called. We don't just rely on smart pointers because they 
won't delete
++        // the menus at the right time and cause a crash while quitting.
++        connect(SpectacleCore::instance(), &QObject::destroyed, qApp, [] {
++            if (s_instance) {
++                delete s_instance;
++            }
+         });
+     }
+-    return s_instance.get();
++    return s_instance;
+ }
+ 
+ void ExportMenu::onImageChanged()
+diff --git a/src/Gui/ExportMenu.h b/src/Gui/ExportMenu.h
+index 192b9d315..688abad76 100644
+--- a/src/Gui/ExportMenu.h
++++ b/src/Gui/ExportMenu.h
+@@ -47,6 +47,7 @@ Q_SIGNALS:
+ 
+ private:
+     explicit ExportMenu(QWidget *parent = nullptr);
++    ~ExportMenu();
+ 
+     Q_SLOT void onImageChanged();
+     Q_SLOT void openScreenshotsFolder();
+diff --git a/src/Gui/HelpMenu.cpp b/src/Gui/HelpMenu.cpp
+index e78a65c46..9cd2d8050 100644
+--- a/src/Gui/HelpMenu.cpp
++++ b/src/Gui/HelpMenu.cpp
+@@ -17,7 +17,7 @@
+ 
+ using namespace Qt::StringLiterals;
+ 
+-static std::unique_ptr<HelpMenu> s_instance = nullptr;
++static HelpMenu *s_instance = nullptr;
+ 
+ static QObject *findWidgetOfType(const char *className)
+ {
+@@ -43,16 +43,25 @@ HelpMenu::HelpMenu(QWidget* parent)
+     connect(this, &QMenu::triggered, this, &HelpMenu::onTriggered);
+ }
+ 
++HelpMenu::~HelpMenu()
++{
++    s_instance = nullptr;
++}
++
+ HelpMenu *HelpMenu::instance()
+ {
+     if (!s_instance && SpectacleCore::instance()) {
+-        s_instance = std::unique_ptr<HelpMenu>(new HelpMenu);
+-        // We have to destroy this after SpectacleCore to prevent a crash 
from the Qt Quick UI.
+-        connect(SpectacleCore::instance(), &QObject::destroyed, 
s_instance.get(), [] {
+-            s_instance.reset();
++        s_instance = new HelpMenu;
++        // We have to destroy this after SpectacleCore to ensure that 
destructors
++        // are called. We don't just rely on smart pointers because they 
won't delete
++        // the menus at the right time and cause a crash while quitting.
++        connect(SpectacleCore::instance(), &QObject::destroyed, qApp, [] {
++            if (s_instance) {
++                delete s_instance;
++            }
+         });
+     }
+-    return s_instance.get();
++    return s_instance;
+ }
+ 
+ void HelpMenu::showAppHelp()
+diff --git a/src/Gui/HelpMenu.h b/src/Gui/HelpMenu.h
+index 475ca8a64..81d760379 100644
+--- a/src/Gui/HelpMenu.h
++++ b/src/Gui/HelpMenu.h
+@@ -34,6 +34,7 @@ public:
+ 
+ private:
+     explicit HelpMenu(QWidget *parent = nullptr);
++    ~HelpMenu();
+     Q_SLOT void onTriggered(QAction *action);
+     const std::unique_ptr<KHelpMenu> kHelpMenu;
+     friend class HelpMenuSingleton;
+diff --git a/src/Gui/OptionsMenu.cpp b/src/Gui/OptionsMenu.cpp
+index 8a70f20ad..25fa1096a 100644
+--- a/src/Gui/OptionsMenu.cpp
++++ b/src/Gui/OptionsMenu.cpp
+@@ -23,7 +23,7 @@
+ 
+ using namespace Qt::StringLiterals;
+ 
+-static std::unique_ptr<OptionsMenu> s_instance = nullptr;
++static OptionsMenu *s_instance = nullptr;
+ 
+ OptionsMenu::OptionsMenu(QWidget *parent)
+     : SpectacleMenu(parent)
+@@ -152,16 +152,25 @@ OptionsMenu::OptionsMenu(QWidget *parent)
+             });
+ }
+ 
++OptionsMenu::~OptionsMenu()
++{
++    s_instance = nullptr;
++}
++
+ OptionsMenu *OptionsMenu::instance()
+ {
+     if (!s_instance && SpectacleCore::instance()) {
+-        s_instance = std::unique_ptr<OptionsMenu>(new OptionsMenu);
+-        // We have to destroy this after SpectacleCore to prevent a crash 
from the Qt Quick UI.
+-        connect(SpectacleCore::instance(), &QObject::destroyed, 
s_instance.get(), [] {
+-            s_instance.reset();
++        s_instance = new OptionsMenu;
++        // We have to destroy this after SpectacleCore to ensure that 
destructors
++        // are called. We don't just rely on smart pointers because they 
won't delete
++        // the menus at the right time and cause a crash while quitting.
++        connect(SpectacleCore::instance(), &QObject::destroyed, qApp, [] {
++            if (s_instance) {
++                delete s_instance;
++            }
+         });
+     }
+-    return s_instance.get();
++    return s_instance;
+ }
+ 
+ void OptionsMenu::showPreferencesDialog()
+diff --git a/src/Gui/OptionsMenu.h b/src/Gui/OptionsMenu.h
+index b600f3f4c..a000186a0 100644
+--- a/src/Gui/OptionsMenu.h
++++ b/src/Gui/OptionsMenu.h
+@@ -42,6 +42,7 @@ protected:
+     void mouseReleaseEvent(QMouseEvent *event) override;
+ 
+     explicit OptionsMenu(QWidget *parent = nullptr);
++    ~OptionsMenu();
+ 
+     void delayActionLayoutUpdate();
+     const std::unique_ptr<QWidgetAction> m_delayAction;
+diff --git a/src/Gui/RecordingModeMenu.cpp b/src/Gui/RecordingModeMenu.cpp
+index 425f28d9e..981f9c9b6 100644
+--- a/src/Gui/RecordingModeMenu.cpp
++++ b/src/Gui/RecordingModeMenu.cpp
+@@ -10,7 +10,7 @@
+ 
+ using namespace Qt::StringLiterals;
+ 
+-static std::unique_ptr<RecordingModeMenu> s_instance = nullptr;
++static RecordingModeMenu *s_instance = nullptr;
+ 
+ RecordingModeMenu::RecordingModeMenu(QWidget *parent)
+     : SpectacleMenu(i18nc("@title:menu", "Recording Modes"), parent)
+@@ -54,16 +54,25 @@ RecordingModeMenu::RecordingModeMenu(QWidget *parent)
+     connect(RecordingModeModel::instance(), 
&RecordingModeModel::recordingModesChanged, this, addModes);
+ }
+ 
++RecordingModeMenu::~RecordingModeMenu()
++{
++    s_instance = nullptr;
++}
++
+ RecordingModeMenu *RecordingModeMenu::instance()
+ {
+     if (!s_instance && SpectacleCore::instance()) {
+-        s_instance = std::unique_ptr<RecordingModeMenu>(new 
RecordingModeMenu);
+-        // We have to destroy this after SpectacleCore to prevent a crash 
from the Qt Quick UI.
+-        connect(SpectacleCore::instance(), &QObject::destroyed, 
s_instance.get(), [] {
+-            s_instance.reset();
++        s_instance = new RecordingModeMenu;
++        // We have to destroy this after SpectacleCore to ensure that 
destructors
++        // are called. We don't just rely on smart pointers because they 
won't delete
++        // the menus at the right time and cause a crash while quitting.
++        connect(SpectacleCore::instance(), &QObject::destroyed, qApp, [] {
++            if (s_instance) {
++                delete s_instance;
++            }
+         });
+     }
+-    return s_instance.get();
++    return s_instance;
+ }
+ 
+ #include "moc_RecordingModeMenu.cpp"
+diff --git a/src/Gui/RecordingModeMenu.h b/src/Gui/RecordingModeMenu.h
+index fe8f0a712..c45ca3c80 100644
+--- a/src/Gui/RecordingModeMenu.h
++++ b/src/Gui/RecordingModeMenu.h
+@@ -27,4 +27,5 @@ public:
+ 
+ private:
+     explicit RecordingModeMenu(QWidget *parent = nullptr);
++    ~RecordingModeMenu();
+ };
+diff --git a/src/Gui/ScreenshotModeMenu.cpp b/src/Gui/ScreenshotModeMenu.cpp
+index c557c2169..b27900f02 100644
+--- a/src/Gui/ScreenshotModeMenu.cpp
++++ b/src/Gui/ScreenshotModeMenu.cpp
+@@ -10,7 +10,7 @@
+ 
+ using namespace Qt::StringLiterals;
+ 
+-static std::unique_ptr<ScreenshotModeMenu> s_instance = nullptr;
++static ScreenshotModeMenu *s_instance = nullptr;
+ 
+ ScreenshotModeMenu::ScreenshotModeMenu(QWidget *parent)
+     : SpectacleMenu(i18nc("@title:menu", "Screenshot Modes"), parent)
+@@ -63,16 +63,25 @@ ScreenshotModeMenu::ScreenshotModeMenu(QWidget *parent)
+     connect(CaptureModeModel::instance(), 
&CaptureModeModel::captureModesChanged, this, addModes);
+ }
+ 
++ScreenshotModeMenu::~ScreenshotModeMenu()
++{
++    s_instance = nullptr;
++}
++
+ ScreenshotModeMenu *ScreenshotModeMenu::instance()
+ {
+     if (!s_instance && SpectacleCore::instance()) {
+-        s_instance = std::unique_ptr<ScreenshotModeMenu>(new 
ScreenshotModeMenu);
+-        // We have to destroy this after SpectacleCore to prevent a crash 
from the Qt Quick UI.
+-        connect(SpectacleCore::instance(), &QObject::destroyed, 
s_instance.get(), [] {
+-            s_instance.reset();
++        s_instance = new ScreenshotModeMenu;
++        // We have to destroy this after SpectacleCore to ensure that 
destructors
++        // are called. We don't just rely on smart pointers because they 
won't delete
++        // the menus at the right time and cause a crash while quitting.
++        connect(SpectacleCore::instance(), &QObject::destroyed, qApp, [] {
++            if (s_instance) {
++                delete s_instance;
++            }
+         });
+     }
+-    return s_instance.get();
++    return s_instance;
+ }
+ 
+ #include "moc_ScreenshotModeMenu.cpp"
+diff --git a/src/Gui/ScreenshotModeMenu.h b/src/Gui/ScreenshotModeMenu.h
+index 387a05db0..9ce75fa50 100644
+--- a/src/Gui/ScreenshotModeMenu.h
++++ b/src/Gui/ScreenshotModeMenu.h
+@@ -27,4 +27,5 @@ public:
+ 
+ private:
+     explicit ScreenshotModeMenu(QWidget *parent = nullptr);
++    ~ScreenshotModeMenu();
+ };
+-- 
+GitLab

diff --git a/kde-plasma/spectacle/spectacle-6.6.2.ebuild 
b/kde-plasma/spectacle/spectacle-6.6.2-r1.ebuild
similarity index 97%
rename from kde-plasma/spectacle/spectacle-6.6.2.ebuild
rename to kde-plasma/spectacle/spectacle-6.6.2-r1.ebuild
index a476242165ce..a383086656f5 100644
--- a/kde-plasma/spectacle/spectacle-6.6.2.ebuild
+++ b/kde-plasma/spectacle/spectacle-6.6.2-r1.ebuild
@@ -65,6 +65,10 @@ BDEPEND="
        virtual/pkgconfig
 "
 
+PATCHES=(
+       "${FILESDIR}"/${P}-crash-quit.patch
+)
+
 src_configure() {
        local mycmakeargs=(
                $(cmake_use_find_package share KF6Purpose)

Reply via email to