diff --git a/dbus/org.kde.Spectacle.xml b/dbus/org.kde.Spectacle.xml --- a/dbus/org.kde.Spectacle.xml +++ b/dbus/org.kde.Spectacle.xml @@ -98,6 +98,51 @@ + + + + Whether to include an image of the mouse pointer. + + + + + Takes a full-screen (all monitor) screenshot without spawning the GUI and copies it to clipboard. + + + + + + + + Whether to include the window titlebars and frames. + + + + + Whether to include an image of the mouse pointer. + + + + + Takes a screenshot of the window that currently has window focus without spawning the GUI and then copies it to clipboard. + + + + + + + + + Whether to include an image of the mouse pointer. + + + + + Takes a screenshot of a rectangular region without spawning the GUI and copies it to clipboard + + + + diff --git a/desktop/spectacle.khotkeys b/desktop/spectacle.khotkeys --- a/desktop/spectacle.khotkeys +++ b/desktop/spectacle.khotkeys @@ -604,3 +604,87 @@ [Data_1_4Triggers0] Key=Meta+Shift+Print Type=SHORTCUT + +[Data_1_5] +Comment= Take a full screen (all monitors) screenshot and save it to clipboard +Enabled=true +Name=Save Full Screen Screenshot To Clipboard +Type=SIMPLE_ACTION_DATA + +[Data_1_5Actions] +ActionsCount=1 + +[Data_1_5Actions0] +Arguments=false +Call=FullScreenClipboard +RemoteApp=org.kde.Spectacle +RemoteObj=/ +Type=DBUS + +[Data_1_5Conditions] +Comment= +ConditionsCount=0 + +[Data_1_5Triggers] +Comment=Simple_action +TriggersCount=1 + +[Data_1_5Triggers0] +Key=Ctrl+Shift+Print +Type=SHORTCUT + +[Data_1_6] +Comment=Take a screenshot of the currently active window and save it to clipboard +Enabled=true +Name=Save Active Window Screenshot To Clipboard +Type=SIMPLE_ACTION_DATA + +[Data_1_6Actions] +ActionsCount=1 + +[Data_1_6Actions0] +Arguments=true, false +Call=ActiveWindowClipboard +RemoteApp=org.kde.Spectacle +RemoteObj=/ +Type=DBUS + +[Data_1_6Conditions] +Comment= +ConditionsCount=0 + +[Data_1_6Triggers] +Comment=Simple_action +TriggersCount=1 + +[Data_1_6Triggers0] +Key=Ctrl+Meta+Print +Type=SHORTCUT + +[Data_1_7] +Comment=Take a screenshot of a rectangular region you specify and save it to clipboard +Enabled=true +Name=Save Rectangular Region Screenshot To Clipboard +Type=SIMPLE_ACTION_DATA + +[Data_1_7Actions] +ActionsCount=1 + +[Data_1_7Actions0] +Arguments=true +Call=RectangularRegionClipboard +RemoteApp=org.kde.Spectacle +RemoteObj=/ +Type=DBUS + +[Data_1_7Conditions] +Comment= +ConditionsCount=0 + +[Data_1_7Triggers] +Comment=Simple_action +TriggersCount=1 + +[Data_1_7Triggers0] +Key=Ctrl+Print +Type=SHORTCUT diff --git a/src/ExportManager.h b/src/ExportManager.h --- a/src/ExportManager.h +++ b/src/ExportManager.h @@ -66,6 +66,7 @@ void pixmapChanged(const QPixmap &pixmap); void imageSaved(const QUrl &savedAt); void forceNotify(const QUrl &savedAt); + void imageCopiedToClipboard(); public slots: diff --git a/src/ExportManager.cpp b/src/ExportManager.cpp --- a/src/ExportManager.cpp +++ b/src/ExportManager.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -363,7 +365,12 @@ void ExportManager::doCopyToClipboard() { - QApplication::clipboard()->setPixmap(mSavePixmap, QClipboard::Clipboard); + QMimeData *mimeData = new QMimeData(); + mimeData->setImageData(mSavePixmap.toImage()); + mimeData->setData("x-kde-force-image-copy", mimeData->data("application/x-qt-image")); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setMimeData(mimeData, QClipboard::Clipboard); + QTimer::singleShot(250, this, &ExportManager::imageCopiedToClipboard); } void ExportManager::doPrint(QPrinter *printer) diff --git a/src/SpectacleCore.h b/src/SpectacleCore.h --- a/src/SpectacleCore.h +++ b/src/SpectacleCore.h @@ -49,6 +49,8 @@ void setFilename(const QString &filename); ImageGrabber::GrabMode grabMode() const; void setGrabMode(const ImageGrabber::GrabMode &grabMode); + void takeNewScreenshotDBus(const ImageGrabber::GrabMode &mode, const bool &includePointer, const bool &includeDecorations, const bool &shouldSave); + signals: @@ -57,6 +59,7 @@ void filenameChanged(QString filename); void grabModeChanged(ImageGrabber::GrabMode mode); void grabFailed(); + void saveAndNotify(); public slots: @@ -68,6 +71,7 @@ void doStartDragAndDrop(); void doNotify(const QUrl &savedAt); void doCopyPath(const QUrl &savedAt); + void screenshotSaved(); private: diff --git a/src/SpectacleCore.cpp b/src/SpectacleCore.cpp --- a/src/SpectacleCore.cpp +++ b/src/SpectacleCore.cpp @@ -85,7 +85,11 @@ connect(mExportManager, &ExportManager::errorMessage, this, &SpectacleCore::showErrorMessage); connect(this, &SpectacleCore::errorMessage, this, &SpectacleCore::showErrorMessage); - connect(mImageGrabber, &ImageGrabber::pixmapChanged, this, &SpectacleCore::screenshotUpdated); + if(mStartMode != DBusMode) { + connect(mImageGrabber, &ImageGrabber::pixmapChanged, this, &SpectacleCore::screenshotUpdated); + connect(this, &SpectacleCore::saveAndNotify, this, &SpectacleCore::screenshotSaved); + } + connect(mImageGrabber, &ImageGrabber::imageGrabFailed, this, &SpectacleCore::screenshotFailed); connect(mExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doCopyPath); connect(mExportManager, &ExportManager::forceNotify, this, &SpectacleCore::doNotify); @@ -167,6 +171,30 @@ QTimer::singleShot(timeout + msec, mImageGrabber, &ImageGrabber::doImageGrab); } +void SpectacleCore::takeNewScreenshotDBus(const ImageGrabber::GrabMode &mode, const bool &includePointer, + const bool &includeDecorations, const bool &shouldSave) +{ + if(mStartMode != DBusMode) { + return; + } + + mImageGrabber->setGrabMode(mode); + mImageGrabber->setCapturePointer(includePointer); + mImageGrabber->setCaptureDecorations(includeDecorations); + + if(shouldSave) { + connect(mImageGrabber, &ImageGrabber::pixmapChanged, this, &SpectacleCore::screenshotUpdated); + connect(this, &SpectacleCore::saveAndNotify, this, &SpectacleCore::screenshotSaved); + mImageGrabber->doImageGrab(); + } else { + connect(mImageGrabber, &ImageGrabber::pixmapChanged, this, &SpectacleCore::screenshotUpdated); + connect(this, &SpectacleCore::saveAndNotify, mExportManager, &ExportManager::doCopyToClipboard); + connect(mExportManager, &ExportManager::imageCopiedToClipboard, this, &SpectacleCore::allDone); + mImageGrabber->doImageGrab(); + } + +} + void SpectacleCore::showErrorMessage(const QString &errString) { qDebug() << "ERROR: " << errString; @@ -178,32 +206,36 @@ void SpectacleCore::screenshotUpdated(const QPixmap &pixmap) { + mExportManager->setPixmap(pixmap); switch (mStartMode) { case BackgroundMode: case DBusMode: - { - if (mNotify) { - connect(mExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doNotify); - } - - QUrl savePath = (mStartMode == BackgroundMode && mFileNameUrl.isValid() && mFileNameUrl.isLocalFile()) ? - mFileNameUrl : QUrl(); - mExportManager->doSave(savePath); - - // if we notify, we emit allDone only if the user either dismissed the notification or pressed - // the "Open" button, otherwise the app closes before it can react to it. - if (!mNotify) { - emit allDone(); - } - } + emit saveAndNotify(); break; case GuiMode: mMainWindow->setScreenshotAndShow(pixmap); } } +void SpectacleCore::screenshotSaved() +{ + if (mNotify) { + connect(mExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doNotify); + } + + QUrl savePath = (mStartMode == BackgroundMode && mFileNameUrl.isValid() && mFileNameUrl.isLocalFile()) ? + mFileNameUrl : QUrl(); + mExportManager->doSave(savePath); + + // if we notify, we emit allDone only if the user either dismissed the notification or pressed + // the "Open" button, otherwise the app closes before it can react to it. + if (!mNotify) { + emit allDone(); + } +} + void SpectacleCore::screenshotFailed() { switch (mStartMode) { diff --git a/src/SpectacleDBusAdapter.h b/src/SpectacleDBusAdapter.h --- a/src/SpectacleDBusAdapter.h +++ b/src/SpectacleDBusAdapter.h @@ -48,6 +48,16 @@ " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -72,6 +82,9 @@ Q_NOREPLY void ActiveWindow(bool includeWindowDecorations, bool includeMousePointer); Q_NOREPLY void WindowUnderCursor(bool includeWindowDecorations, bool includeMousePointer); Q_NOREPLY void RectangularRegion(bool includeMousePointer); + Q_NOREPLY void FullScreenClipboard(bool includeMousePointer); + Q_NOREPLY void ActiveWindowClipboard(bool includeWindowDecorations, bool includeMousePointer); + Q_NOREPLY void RectangularRegionClipboard(bool includeMousePointer); signals: diff --git a/src/SpectacleDBusAdapter.cpp b/src/SpectacleDBusAdapter.cpp --- a/src/SpectacleDBusAdapter.cpp +++ b/src/SpectacleDBusAdapter.cpp @@ -40,25 +40,41 @@ Q_NOREPLY void SpectacleDBusAdapter::FullScreen(bool includeMousePointer) { - parent()->takeNewScreenshot(ImageGrabber::FullScreen, 0, includeMousePointer, true); + parent()->takeNewScreenshotDBus(ImageGrabber::FullScreen, includeMousePointer, true, true); } Q_NOREPLY void SpectacleDBusAdapter::CurrentScreen(bool includeMousePointer) { - parent()->takeNewScreenshot(ImageGrabber::CurrentScreen, 0, includeMousePointer, true); + parent()->takeNewScreenshotDBus(ImageGrabber::CurrentScreen, includeMousePointer, true, true); } Q_NOREPLY void SpectacleDBusAdapter::ActiveWindow(bool includeWindowDecorations, bool includeMousePointer) { - parent()->takeNewScreenshot(ImageGrabber::ActiveWindow, 0, includeMousePointer, includeWindowDecorations); + parent()->takeNewScreenshotDBus(ImageGrabber::ActiveWindow, includeMousePointer, includeWindowDecorations, true); } Q_NOREPLY void SpectacleDBusAdapter::WindowUnderCursor(bool includeWindowDecorations, bool includeMousePointer) { - parent()->takeNewScreenshot(ImageGrabber::WindowUnderCursor, 0, includeMousePointer, includeWindowDecorations); + parent()->takeNewScreenshotDBus(ImageGrabber::WindowUnderCursor, includeMousePointer, includeWindowDecorations, true); } Q_NOREPLY void SpectacleDBusAdapter::RectangularRegion(bool includeMousePointer) { - parent()->takeNewScreenshot(ImageGrabber::RectangularRegion, 0, includeMousePointer, false); + parent()->takeNewScreenshotDBus(ImageGrabber::RectangularRegion, includeMousePointer, false, true); } + +Q_NOREPLY void SpectacleDBusAdapter::FullScreenClipboard(bool includeMousePointer) +{ + parent()->takeNewScreenshotDBus(ImageGrabber::FullScreen, includeMousePointer, true, false); +} + +Q_NOREPLY void SpectacleDBusAdapter::ActiveWindowClipboard(bool includeWindowDecorations, bool includeMousePointer) +{ + parent()->takeNewScreenshotDBus(ImageGrabber::ActiveWindow, includeMousePointer, includeWindowDecorations, false); +} + +Q_NOREPLY void SpectacleDBusAdapter::RectangularRegionClipboard(bool includeMousePointer) +{ + parent()->takeNewScreenshotDBus(ImageGrabber::RectangularRegion, includeMousePointer, false, false); +} +