From ef678de7a10a03cef409efd2f3eeee7036dafadd Mon Sep 17 00:00:00 2001 From: Vladimir Mitnitsky <33536734+Mitnitsky@users.noreply.github.com> Date: Sun, 12 Apr 2026 16:04:37 +0300 Subject: [PATCH 1/3] fix(macos): use proper macos api to get privacy screen recorder access (#4617) --- src/core/flameshot.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/core/flameshot.cpp b/src/core/flameshot.cpp index 1c31d8bf5c..8a29e31f2d 100644 --- a/src/core/flameshot.cpp +++ b/src/core/flameshot.cpp @@ -7,6 +7,10 @@ #include "qhotkey.h" #endif +#if defined(Q_OS_MACOS) +#include +#endif + #include "config/configresolver.h" #include "config/configwindow.h" #include "core/qguiappcurrentscreen.h" @@ -54,11 +58,10 @@ Flameshot::Flameshot() qApp->setStyleSheet(StyleSheet); #if defined(Q_OS_MACOS) - // Try to take a test screenshot, MacOS will request a "Screen Recording" - // permissions on the first run. Otherwise it will be hidden under the - // CaptureWidget - QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen(); - currentScreen->grabWindow(0, 0, 0, 1, 1); + // Request Screen Recording permission via the proper CoreGraphics API + if (!CGPreflightScreenCaptureAccess()) { + CGRequestScreenCaptureAccess(); + } #endif #if (defined(Q_OS_MACOS) || defined(Q_OS_WIN)) // Set global shortcuts for MacOS or Windows From c4db15ccd34df7d970399b736ded997258c6cbe4 Mon Sep 17 00:00:00 2001 From: El Thoro Date: Sun, 12 Apr 2026 15:06:41 +0200 Subject: [PATCH 2/3] Fix KDE Plasma keyboard shortcut config file (#4637) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6bc86b406a..3863f708fe 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,7 @@ These shortcuts are available in GUI mode: #### On KDE Plasma desktop -To make configuration easier, there's a [file](docs/shortcuts-config/flameshot-shortcuts-kde.khotkeys) in the repository that more or less automates this process. This file will assign the following hotkeys by default: +To make configuration easier, there's a [file](docs/shortcuts-config/flameshot-shortcuts-kde.kksrc) in the repository that more or less automates this process. This file will assign the following hotkeys by default: | Keys | Description | |--- |--- | From 016b9197e88320eb42a7713265d1902aedf5a035 Mon Sep 17 00:00:00 2001 From: Vladimir Mitnitsky <33536734+Mitnitsky@users.noreply.github.com> Date: Sun, 12 Apr 2026 16:07:44 +0300 Subject: [PATCH 3/3] fix(macos): fix clipboard copy failing from tray and GUI (#4629) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clipboard copy from tray menu and capture GUI was broken on macOS: 1. FlameshotDaemon::copyToClipboard() created a KDSingleApplication instance and called isPrimaryInstance(), which always returned false (the daemon already holds the socket). This caused a 3-second IPC timeout before falling back. Fix: use instance() to check if the daemon singleton exists in-process, matching non-macOS behavior. 2. saveToClipboardMime() used setData("image/...") which puts a lazy reference on the macOS pasteboard. If the app exits before paste, data is lost ("Cannot keep promise"). Fix: use setImageData() for native pasteboard persistence, plus setData() for exact format. 3. saveJpegToClipboardMacOS() used osascript with a temp file and incorrectly labeled JPEG data as PNG UTI. Removed entirely — the fixed saveToClipboardMime() now handles both JPEG and PNG. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/core/flameshotdaemon.cpp | 14 -------- src/utils/screenshotsaver.cpp | 60 +++++++++-------------------------- 2 files changed, 15 insertions(+), 59 deletions(-) diff --git a/src/core/flameshotdaemon.cpp b/src/core/flameshotdaemon.cpp index 652792d801..8c7852e2aa 100644 --- a/src/core/flameshotdaemon.cpp +++ b/src/core/flameshotdaemon.cpp @@ -141,12 +141,7 @@ void FlameshotDaemon::createPin(const QPixmap& capture, QRect geometry) void FlameshotDaemon::copyToClipboard(const QPixmap& capture) { -#if defined(Q_OS_MACOS) && defined(USE_KDSINGLEAPPLICATION) - auto kdsa = KDSingleApplication(QStringLiteral("org.flameshot.Flameshot")); - if (kdsa.isPrimaryInstance() && instance()) { -#else if (instance()) { -#endif instance()->attachScreenshotToClipboard(capture); return; } @@ -156,9 +151,7 @@ void FlameshotDaemon::copyToClipboard(const QPixmap& capture) #if defined(USE_KDSINGLEAPPLICATION) && \ (defined(Q_OS_MACOS) || defined(Q_OS_WIN)) -#if defined(Q_OS_WIN) auto kdsa = KDSingleApplication(QStringLiteral("org.flameshot.Flameshot")); -#endif stream << QStringLiteral("attachScreenshotToClipboard") << capture; kdsa.sendMessage(data); #else @@ -174,21 +167,14 @@ void FlameshotDaemon::copyToClipboard(const QPixmap& capture) void FlameshotDaemon::copyToClipboard(const QString& text, const QString& notification) { -#if defined(Q_OS_MACOS) && defined(USE_KDSINGLEAPPLICATION) - auto kdsa = KDSingleApplication(QStringLiteral("org.flameshot.Flameshot")); - if (kdsa.isPrimaryInstance() && instance()) { -#else if (instance()) { -#endif instance()->attachTextToClipboard(text, notification); return; } #if defined(USE_KDSINGLEAPPLICATION) && \ (defined(Q_OS_MACOS) || defined(Q_OS_WIN)) -#if defined(Q_OS_WIN) auto kdsa = KDSingleApplication(QStringLiteral("org.flameshot.Flameshot")); -#endif QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << QStringLiteral("attachTextToClipboard") << text << notification; diff --git a/src/utils/screenshotsaver.cpp b/src/utils/screenshotsaver.cpp index 0e02833dd9..29fb9d28ce 100644 --- a/src/utils/screenshotsaver.cpp +++ b/src/utils/screenshotsaver.cpp @@ -111,45 +111,6 @@ QString ShowSaveFileDialog(const QString& title, const QString& directory) } } -void saveJpegToClipboardMacOS(const QPixmap& capture) -{ - // Convert QPixmap to JPEG data - QByteArray jpegData; - QBuffer buffer(&jpegData); - buffer.open(QIODevice::WriteOnly); - - QImageWriter imageWriter(&buffer, "jpeg"); - - // Set JPEG quality to whatever is in settings - imageWriter.setQuality(ConfigHandler().jpegQuality()); - if (!imageWriter.write(capture.toImage())) { - qWarning() << "Failed to write image to JPEG format."; - return; - } - - // Save JPEG data to a temporary file - QTemporaryFile tempFile; - if (!tempFile.open()) { - qWarning() << "Failed to open temporary file for writing."; - return; - } - tempFile.write(jpegData); - tempFile.close(); - - // Use osascript to copy the contents of the file to clipboard - QProcess process; - QString script = - QString("set the clipboard to (read (POSIX file \"%1\") as «class PNGf»)") - .arg(tempFile.fileName()); - process.start("osascript", QStringList() << "-e" << script); - if (!process.waitForFinished()) { - qWarning() << "Failed to execute AppleScript."; - } - - // Clean up - tempFile.remove(); -} - void saveToClipboardMime(const QPixmap& capture, const QString& imageType) { QByteArray array; @@ -169,7 +130,14 @@ void saveToClipboardMime(const QPixmap& capture, const QString& imageType) auto* mimeData = new QMimeData(); -#ifdef USE_WAYLAND_CLIPBOARD +#if defined(Q_OS_MACOS) + // setImageData provides the image in a native pasteboard format + // (public.tiff) that macOS can always access. Also include the + // original format bytes for apps that prefer PNG/JPEG. + mimeData->setImageData(formattedPixmap.toImage()); + mimeData->setData("image/" + imageType, array); + QApplication::clipboard()->setMimeData(mimeData); +#elif defined(USE_WAYLAND_CLIPBOARD) if (QGuiApplication::platformName() == "wayland") { mimeData->setImageData(formattedPixmap.toImage()); mimeData->setData(QStringLiteral("x-kde-force-image-copy"), @@ -205,14 +173,15 @@ void saveToClipboard(const QPixmap& capture) } else { AbstractLogger() << QObject::tr("Capture saved to clipboard."); } - if (ConfigHandler().useJpgForClipboard()) { -#ifdef Q_OS_MACOS - saveJpegToClipboardMacOS(capture); +#if defined(Q_OS_MACOS) + // On macOS, setPixmap uses lazy clipboard which fails when the + // process exits ("Cannot keep promise"). Always use serialized bytes. + saveToClipboardMime(capture, + ConfigHandler().useJpgForClipboard() ? "jpeg" : "png"); #else + if (ConfigHandler().useJpgForClipboard()) { saveToClipboardMime(capture, "jpeg"); -#endif } else { - // Need to send message before copying to clipboard #if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) if (DesktopInfo().waylandDetected()) { saveToClipboardMime(capture, "png"); @@ -223,6 +192,7 @@ void saveToClipboard(const QPixmap& capture) QApplication::clipboard()->setPixmap(capture); #endif } +#endif } class ClipboardWatcherMimeData : public QMimeData