Skip to content

Commit 016b919

Browse files
MitnitskyCopilot
andauthored
fix(macos): fix clipboard copy failing from tray and GUI (flameshot-org#4629)
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>
1 parent c4db15c commit 016b919

File tree

2 files changed

+15
-59
lines changed

2 files changed

+15
-59
lines changed

src/core/flameshotdaemon.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,7 @@ void FlameshotDaemon::createPin(const QPixmap& capture, QRect geometry)
141141

142142
void FlameshotDaemon::copyToClipboard(const QPixmap& capture)
143143
{
144-
#if defined(Q_OS_MACOS) && defined(USE_KDSINGLEAPPLICATION)
145-
auto kdsa = KDSingleApplication(QStringLiteral("org.flameshot.Flameshot"));
146-
if (kdsa.isPrimaryInstance() && instance()) {
147-
#else
148144
if (instance()) {
149-
#endif
150145
instance()->attachScreenshotToClipboard(capture);
151146
return;
152147
}
@@ -156,9 +151,7 @@ void FlameshotDaemon::copyToClipboard(const QPixmap& capture)
156151

157152
#if defined(USE_KDSINGLEAPPLICATION) && \
158153
(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
159-
#if defined(Q_OS_WIN)
160154
auto kdsa = KDSingleApplication(QStringLiteral("org.flameshot.Flameshot"));
161-
#endif
162155
stream << QStringLiteral("attachScreenshotToClipboard") << capture;
163156
kdsa.sendMessage(data);
164157
#else
@@ -174,21 +167,14 @@ void FlameshotDaemon::copyToClipboard(const QPixmap& capture)
174167
void FlameshotDaemon::copyToClipboard(const QString& text,
175168
const QString& notification)
176169
{
177-
#if defined(Q_OS_MACOS) && defined(USE_KDSINGLEAPPLICATION)
178-
auto kdsa = KDSingleApplication(QStringLiteral("org.flameshot.Flameshot"));
179-
if (kdsa.isPrimaryInstance() && instance()) {
180-
#else
181170
if (instance()) {
182-
#endif
183171
instance()->attachTextToClipboard(text, notification);
184172
return;
185173
}
186174

187175
#if defined(USE_KDSINGLEAPPLICATION) && \
188176
(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
189-
#if defined(Q_OS_WIN)
190177
auto kdsa = KDSingleApplication(QStringLiteral("org.flameshot.Flameshot"));
191-
#endif
192178
QByteArray data;
193179
QDataStream stream(&data, QIODevice::WriteOnly);
194180
stream << QStringLiteral("attachTextToClipboard") << text << notification;

src/utils/screenshotsaver.cpp

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -111,45 +111,6 @@ QString ShowSaveFileDialog(const QString& title, const QString& directory)
111111
}
112112
}
113113

114-
void saveJpegToClipboardMacOS(const QPixmap& capture)
115-
{
116-
// Convert QPixmap to JPEG data
117-
QByteArray jpegData;
118-
QBuffer buffer(&jpegData);
119-
buffer.open(QIODevice::WriteOnly);
120-
121-
QImageWriter imageWriter(&buffer, "jpeg");
122-
123-
// Set JPEG quality to whatever is in settings
124-
imageWriter.setQuality(ConfigHandler().jpegQuality());
125-
if (!imageWriter.write(capture.toImage())) {
126-
qWarning() << "Failed to write image to JPEG format.";
127-
return;
128-
}
129-
130-
// Save JPEG data to a temporary file
131-
QTemporaryFile tempFile;
132-
if (!tempFile.open()) {
133-
qWarning() << "Failed to open temporary file for writing.";
134-
return;
135-
}
136-
tempFile.write(jpegData);
137-
tempFile.close();
138-
139-
// Use osascript to copy the contents of the file to clipboard
140-
QProcess process;
141-
QString script =
142-
QString("set the clipboard to (read (POSIX file \"%1\") as «class PNGf»)")
143-
.arg(tempFile.fileName());
144-
process.start("osascript", QStringList() << "-e" << script);
145-
if (!process.waitForFinished()) {
146-
qWarning() << "Failed to execute AppleScript.";
147-
}
148-
149-
// Clean up
150-
tempFile.remove();
151-
}
152-
153114
void saveToClipboardMime(const QPixmap& capture, const QString& imageType)
154115
{
155116
QByteArray array;
@@ -169,7 +130,14 @@ void saveToClipboardMime(const QPixmap& capture, const QString& imageType)
169130

170131
auto* mimeData = new QMimeData();
171132

172-
#ifdef USE_WAYLAND_CLIPBOARD
133+
#if defined(Q_OS_MACOS)
134+
// setImageData provides the image in a native pasteboard format
135+
// (public.tiff) that macOS can always access. Also include the
136+
// original format bytes for apps that prefer PNG/JPEG.
137+
mimeData->setImageData(formattedPixmap.toImage());
138+
mimeData->setData("image/" + imageType, array);
139+
QApplication::clipboard()->setMimeData(mimeData);
140+
#elif defined(USE_WAYLAND_CLIPBOARD)
173141
if (QGuiApplication::platformName() == "wayland") {
174142
mimeData->setImageData(formattedPixmap.toImage());
175143
mimeData->setData(QStringLiteral("x-kde-force-image-copy"),
@@ -205,14 +173,15 @@ void saveToClipboard(const QPixmap& capture)
205173
} else {
206174
AbstractLogger() << QObject::tr("Capture saved to clipboard.");
207175
}
208-
if (ConfigHandler().useJpgForClipboard()) {
209-
#ifdef Q_OS_MACOS
210-
saveJpegToClipboardMacOS(capture);
176+
#if defined(Q_OS_MACOS)
177+
// On macOS, setPixmap uses lazy clipboard which fails when the
178+
// process exits ("Cannot keep promise"). Always use serialized bytes.
179+
saveToClipboardMime(capture,
180+
ConfigHandler().useJpgForClipboard() ? "jpeg" : "png");
211181
#else
182+
if (ConfigHandler().useJpgForClipboard()) {
212183
saveToClipboardMime(capture, "jpeg");
213-
#endif
214184
} else {
215-
// Need to send message before copying to clipboard
216185
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
217186
if (DesktopInfo().waylandDetected()) {
218187
saveToClipboardMime(capture, "png");
@@ -223,6 +192,7 @@ void saveToClipboard(const QPixmap& capture)
223192
QApplication::clipboard()->setPixmap(capture);
224193
#endif
225194
}
195+
#endif
226196
}
227197

228198
class ClipboardWatcherMimeData : public QMimeData

0 commit comments

Comments
 (0)