diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -117,6 +117,7 @@
add_subdirectory(desktop)
add_subdirectory(icons)
add_subdirectory(doc)
+add_subdirectory(kconf_update)
# summaries
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
@@ -24,6 +24,16 @@
Whether to include an image of the mouse pointer.
+
+
+ Whether to copy the image to clipboard.
+
+
+
+
+ Whether to save the image to file.
+
+
Takes a full-screen screenshot.
@@ -38,6 +48,16 @@
Whether to include an image of the mouse pointer.
+
+
+ Whether to copy the image to clipboard.
+
+
+
+
+ Whether to save the image to file.
+
+
Takes a screenshot of the current screen.
@@ -52,6 +72,16 @@
Whether to include the window titlebars and frames.
+
+
+ Whether to copy the image to clipboard.
+
+
+
+
+ Whether to save the image to file.
+
+
Whether to include an image of the mouse pointer.
@@ -76,6 +106,16 @@
Whether to include an image of the mouse pointer.
+
+
+ Whether to copy the image to clipboard.
+
+
+
+
+ Whether to save the image to file.
+
+
Takes a screenshot of the window that is currently under the mouse cursor.
@@ -90,6 +130,16 @@
Whether to include an image of the mouse pointer.
+
+
+ Whether to copy the image to clipboard.
+
+
+
+
+ Whether to save the image to file.
+
+
Takes a screenshot of a rectangular region.
diff --git a/desktop/spectacle.khotkeys b/desktop/spectacle.khotkeys
--- a/desktop/spectacle.khotkeys
+++ b/desktop/spectacle.khotkeys
@@ -42,7 +42,7 @@
Comment[x-test]=xxShortcuts for taking screenshotsxx
Comment[zh_CN]=截图快捷键
Comment[zh_TW]=螢幕快照的快捷鍵
-DataCount=4
+DataCount=7
Enabled=true
Name=Screenshots
Name[ca]=Captures de pantalla
@@ -254,7 +254,7 @@
Comment[zh_CN]=对全屏 (所有显示器) 截图并保存
Comment[zh_TW]=取得全螢幕(所有螢幕)快照並儲存
Enabled=true
-Name=Take Full Screen Screenshot
+Name=Save Screenshot of Full Screen to File
Name[ca]=Pren una captura de pantalla completa
Name[ca@valencia]=Pren una captura de pantalla completa
Name[cs]=Zachytit snímek celé obrazovky
@@ -295,7 +295,7 @@
ActionsCount=1
[Data_1_2Actions0]
-Arguments=false
+Arguments=false false true
Call=FullScreen
RemoteApp=org.kde.Spectacle
RemoteObj=/
@@ -383,7 +383,7 @@
Comment[zh_CN]=对当前活动窗口截图并保存
Comment[zh_TW]=取得目前作用中視窗的快照並儲存
Enabled=true
-Name=Take Active Window Screenshot
+Name=Save Screenshot of Active Window to File
Name[ca]=Pren una captura de pantalla de la finestra activa
Name[ca@valencia]=Pren una captura de pantalla de la finestra activa
Name[cs]=Zachytit snímek aktivního okna
@@ -424,7 +424,7 @@
ActionsCount=1
[Data_1_3Actions0]
-Arguments=true false
+Arguments=true false false true
Call=ActiveWindow
RemoteApp=org.kde.Spectacle
RemoteObj=/
@@ -477,7 +477,7 @@
Type=SHORTCUT
[Data_1_4]
-Comment=Take a screenshot of a rectangular region you specify and save it
+Comment=Save Screenshot of a rectangular region you specify to File
Comment[ca]=Pren una captura de pantalla d'una regió rectangular i la desa
Comment[ca@valencia]=Pren una captura de pantalla d'una regió rectangular i la guarda
Comment[da]=Tag skærmbillede af et firkantet område som du angiver og gem det
@@ -512,7 +512,7 @@
Comment[zh_CN]=对指定矩形区域截图并保存
Comment[zh_TW]=取得您指定的矩形區域的快照並儲存
Enabled=true
-Name=Take Rectangular Region Screenshot
+Name=Save Screenshot of Rectangular Region To File
Name[ca]=Pren una captura de pantalla d'una regió rectangular
Name[ca@valencia]=Pren una captura de pantalla d'una regió rectangular
Name[cs]=Zachytit snímek obdélníkové oblasti
@@ -553,7 +553,7 @@
ActionsCount=1
[Data_1_4Actions0]
-Arguments=true
+Arguments=true false true
Call=RectangularRegion
RemoteApp=org.kde.Spectacle
RemoteObj=/
@@ -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 Screenshot of Full Screen to Clipboard
+Type=SIMPLE_ACTION_DATA
+
+[Data_1_5Actions]
+ActionsCount=1
+
+[Data_1_5Actions0]
+Arguments=false true false
+Call=FullScreen
+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 Screenshot of Active Window to Clipboard
+Type=SIMPLE_ACTION_DATA
+
+[Data_1_6Actions]
+ActionsCount=1
+
+[Data_1_6Actions0]
+Arguments=true false true false
+Call=ActiveWindow
+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 Screenshot of Rectangular Region To Clipboard
+Type=SIMPLE_ACTION_DATA
+
+[Data_1_7Actions]
+ActionsCount=1
+
+[Data_1_7Actions0]
+Arguments=true true false
+Call=RectangularRegion
+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/kconf_update/CMakeLists.txt b/kconf_update/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/kconf_update/CMakeLists.txt
@@ -0,0 +1,14 @@
+find_package(Qt5 REQUIRED COMPONENTS Core)
+find_package(KF5 REQUIRED COMPONENTS Config)
+
+add_executable(spectacle_update spectacle_update.cpp)
+
+target_link_libraries(spectacle_update Qt5::Core KF5::ConfigCore)
+
+install(TARGETS spectacle_update
+ DESTINATION ${LIB_INSTALL_DIR}/kconf_update_bin/)
+
+install(FILES spectacle.upd
+ DESTINATION ${KDE_INSTALL_KCONFUPDATEDIR}
+)
+
diff --git a/kconf_update/spectacle.upd b/kconf_update/spectacle.upd
new file mode 100644
--- /dev/null
+++ b/kconf_update/spectacle.upd
@@ -0,0 +1,4 @@
+Version=5
+
+Id=spectacle01
+Script=spectacle_update
diff --git a/kconf_update/spectacle_update.cpp b/kconf_update/spectacle_update.cpp
new file mode 100644
--- /dev/null
+++ b/kconf_update/spectacle_update.cpp
@@ -0,0 +1,44 @@
+#include
+#include
+
+int main(void)
+{
+ KConfig config(QStringLiteral("khotkeysrc"));
+
+ // Remove spectacle (if present) from entry "AlreadyImported" of [Main] group of file khotkeysrc
+ if (config.hasGroup(QStringLiteral("Main"))
+ && config.group(QStringLiteral("Main")).hasKey(QStringLiteral("AlreadyImported"))) {
+
+ QStringList importedList(config.group(QStringLiteral("Main")).readEntry(
+ QStringLiteral("AlreadyImported")).split(QStringLiteral(","), QString::SkipEmptyParts));
+
+ QStringListIterator it(importedList);
+ QStringList updatedHotkeys;
+ while (it.hasNext()) {
+ QString entry = it.next().simplified();
+ if (entry != QStringLiteral("spectacle")) {
+ updatedHotkeys.push_back(entry);
+ }
+ }
+
+ updatedHotkeys.join(QStringLiteral(","));
+ config.group(QStringLiteral("Main")).writeEntry(QStringLiteral("AlreadyImported"),
+ updatedHotkeys.join(QStringLiteral(",")));
+ }
+
+ // Remove all shortcuts for spectacle present in file khotkeysrc
+ QStringList groupList(config.groupList());
+ for (int i = 1; groupList.contains(QStringLiteral("Data_%1").arg(QString::number(i))); i++) {
+
+ KConfigGroup group = config.group(QStringLiteral("Data_%1").arg(QString::number(i)));
+ if (group.hasKey(QStringLiteral("ImportId"))
+ && group.readEntry(QStringLiteral("ImportId")) == QStringLiteral("spectacle")) {
+
+ for (const QString groupName : groupList) {
+ if (groupName.startsWith(QStringLiteral("Data_%1").arg(QString::number(i)))) {
+ config.group(groupName).deleteGroup();
+ }
+ }
+ }
+ }
+}
diff --git a/src/ExportManager.cpp b/src/ExportManager.cpp
--- a/src/ExportManager.cpp
+++ b/src/ExportManager.cpp
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include
#include
@@ -434,6 +435,10 @@
void ExportManager::doCopyToClipboard()
{
QApplication::clipboard()->setPixmap(mSavePixmap, QClipboard::Clipboard);
+ QMimeData *mimeData = new QMimeData();
+ mimeData->setImageData(mSavePixmap.toImage());
+ mimeData->setData(QStringLiteral("x-kde-force-image-copy"), mimeData->data(QStringLiteral("application/x-qt-image")));
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
}
void ExportManager::doPrint(QPrinter *printer)
diff --git a/src/PlatformBackends/ImageGrabber.h b/src/PlatformBackends/ImageGrabber.h
--- a/src/PlatformBackends/ImageGrabber.h
+++ b/src/PlatformBackends/ImageGrabber.h
@@ -52,19 +52,28 @@
Q_ENUM(GrabMode);
+ enum SaveMode {
+ File = 0,
+ Clipboard = 1
+ };
+
+ Q_ENUM(SaveMode);
+
explicit ImageGrabber(QObject *parent = 0);
~ImageGrabber();
QPixmap pixmap() const;
bool capturePointer() const;
bool captureDecorations() const;
GrabMode grabMode() const;
+ SaveMode saveMode() const;
virtual bool onClickGrabSupported() const;
void setCapturePointer(const bool newCapturePointer);
void setCaptureDecorations(const bool newCaptureDecorations);
void setGrabMode(const GrabMode newGrabMode);
+ void setSaveMode(const SaveMode newSaveMode);
signals:
@@ -93,6 +102,7 @@
bool mCapturePointer;
bool mCaptureDecorations;
GrabMode mGrabMode;
+ SaveMode mSaveMode;
QPixmap mPixmap;
};
diff --git a/src/PlatformBackends/ImageGrabber.cpp b/src/PlatformBackends/ImageGrabber.cpp
--- a/src/PlatformBackends/ImageGrabber.cpp
+++ b/src/PlatformBackends/ImageGrabber.cpp
@@ -61,6 +61,11 @@
return mGrabMode;
}
+ImageGrabber::SaveMode ImageGrabber::saveMode() const
+{
+ return mSaveMode;
+}
+
void ImageGrabber::setCapturePointer(const bool newCapturePointer)
{
mCapturePointer = newCapturePointer;
@@ -76,6 +81,11 @@
mGrabMode = newGrabMode;
}
+void ImageGrabber::setSaveMode(const SaveMode newSaveMode)
+{
+ mSaveMode = newSaveMode;
+}
+
// Slots
void ImageGrabber::doOnClickGrab()
diff --git a/src/SpectacleCore.h b/src/SpectacleCore.h
--- a/src/SpectacleCore.h
+++ b/src/SpectacleCore.h
@@ -60,7 +60,8 @@
public slots:
- void takeNewScreenshot(const ImageGrabber::GrabMode &mode, const int &timeout, const bool &includePointer, const bool &includeDecorations);
+ void takeNewScreenshot(const ImageGrabber::GrabMode &mode, const int &timeout, const bool &includePointer,
+ const bool &includeDecorations, const bool &shouldCopy = false, const bool &shouldSave = true);
void showErrorMessage(const QString &errString);
void screenshotUpdated(const QPixmap &pixmap);
void screenshotFailed();
diff --git a/src/SpectacleCore.cpp b/src/SpectacleCore.cpp
--- a/src/SpectacleCore.cpp
+++ b/src/SpectacleCore.cpp
@@ -40,7 +40,7 @@
#include
SpectacleCore::SpectacleCore(StartMode startMode, ImageGrabber::GrabMode grabMode, QString &saveFileName,
- qint64 delayMsec, bool notifyOnGrab, QObject *parent) :
+ qint64 delayMsec, bool notifyOnGrab, QObject *parent) :
QObject(parent),
mExportManager(ExportManager::instance()),
mStartMode(startMode),
@@ -75,6 +75,7 @@
setGrabMode(grabMode);
mImageGrabber->setCapturePointer(guiConfig.readEntry("includePointer", true));
mImageGrabber->setCaptureDecorations(guiConfig.readEntry("includeDecorations", true));
+ mImageGrabber->setSaveMode(ImageGrabber::SaveMode::File);
if ((!(mImageGrabber->onClickGrabSupported())) && (delayMsec < 0)) {
delayMsec = 0;
@@ -92,10 +93,10 @@
case DBusMode:
break;
case BackgroundMode: {
- int msec = (KWindowSystem::compositingActive() ? 200 : 50) + delayMsec;
- QTimer::singleShot(msec, mImageGrabber, &ImageGrabber::doImageGrab);
- }
- break;
+ int msec = (KWindowSystem::compositingActive() ? 200 : 50) + delayMsec;
+ QTimer::singleShot(msec, mImageGrabber, &ImageGrabber::doImageGrab);
+ }
+ break;
case GuiMode:
initGui();
break;
@@ -145,11 +146,17 @@
}
void SpectacleCore::takeNewScreenshot(const ImageGrabber::GrabMode &mode,
- const int &timeout, const bool &includePointer, const bool &includeDecorations)
+ const int &timeout, const bool &includePointer,
+ const bool &includeDecorations, const bool &shouldCopy, const bool &shouldSave)
{
setGrabMode(mode);
mImageGrabber->setCapturePointer(includePointer);
mImageGrabber->setCaptureDecorations(includeDecorations);
+ if (shouldSave) {
+ mImageGrabber->setSaveMode(ImageGrabber::SaveMode::File);
+ } else {
+ mImageGrabber->setSaveMode(ImageGrabber::SaveMode::Clipboard);
+ }
if (timeout < 0) {
mImageGrabber->doOnClickGrab();
@@ -178,17 +185,21 @@
void SpectacleCore::screenshotUpdated(const QPixmap &pixmap)
{
mExportManager->setPixmap(pixmap);
+ if (mImageGrabber->saveMode() == ImageGrabber::SaveMode::Clipboard) {
+ mExportManager->doCopyToClipboard();
+ QTimer::singleShot(250, this, &SpectacleCore::allDone);
+ }
- switch (mStartMode) {
- case BackgroundMode:
- case DBusMode:
- {
+ if (mImageGrabber->saveMode() == ImageGrabber::SaveMode::File) {
+ 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();
+ mFileNameUrl : QUrl();
mExportManager->doSave(savePath);
// if we notify, we emit allDone only if the user either dismissed the notification or pressed
@@ -198,8 +209,9 @@
}
}
break;
- case GuiMode:
- mMainWindow->setScreenshotAndShow(pixmap);
+ case GuiMode:
+ mMainWindow->setScreenshotAndShow(pixmap);
+ }
}
}
@@ -223,7 +235,7 @@
{
KNotification *notify = new KNotification(QStringLiteral("newScreenshotSaved"));
- switch(mImageGrabber->grabMode()) {
+ switch (mImageGrabber->grabMode()) {
case ImageGrabber::GrabMode::FullScreen:
notify->setTitle(i18nc("The entire screen area was captured, heading", "Full Screen Captured"));
break;
@@ -295,7 +307,10 @@
if (!isGuiInited) {
mMainWindow = new KSMainWindow(mImageGrabber->onClickGrabSupported());
- connect(mMainWindow, &KSMainWindow::newScreenshotRequest, this, &SpectacleCore::takeNewScreenshot);
+ connect(mMainWindow, &KSMainWindow::newScreenshotRequest,
+ [this](const ImageGrabber::GrabMode & mode, const int &timeout, const bool & includePointer, const bool & includeDecorations) {
+ takeNewScreenshot(mode, timeout, includePointer, includeDecorations);
+ });
connect(mMainWindow, &KSMainWindow::dragAndDropRequest, this, &SpectacleCore::doStartDragAndDrop);
isGuiInited = true;
diff --git a/src/SpectacleDBusAdapter.h b/src/SpectacleDBusAdapter.h
--- a/src/SpectacleDBusAdapter.h
+++ b/src/SpectacleDBusAdapter.h
@@ -33,20 +33,30 @@
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
" \n"
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
" \n"
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
" \n"
" \n"
" \n"
@@ -67,11 +77,11 @@
public slots:
Q_NOREPLY void StartAgent();
- Q_NOREPLY void FullScreen(bool includeMousePointer);
- Q_NOREPLY void CurrentScreen(bool includeMousePointer);
- 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 FullScreen(bool includeMousePointer, bool shouldCopy, bool shouldSave);
+ Q_NOREPLY void CurrentScreen(bool includeMousePointer, bool shouldCopy, bool shouldSave);
+ Q_NOREPLY void ActiveWindow(bool includeWindowDecorations, bool includeMousePointer, bool shouldCopy, bool shouldSave);
+ Q_NOREPLY void WindowUnderCursor(bool includeWindowDecorations, bool includeMousePointer, bool shouldCopy, bool shouldSave);
+ Q_NOREPLY void RectangularRegion(bool includeMousePointer, bool shouldCopy, bool shouldSave);
signals:
diff --git a/src/SpectacleDBusAdapter.cpp b/src/SpectacleDBusAdapter.cpp
--- a/src/SpectacleDBusAdapter.cpp
+++ b/src/SpectacleDBusAdapter.cpp
@@ -38,27 +38,27 @@
parent()->dbusStartAgent();
}
-Q_NOREPLY void SpectacleDBusAdapter::FullScreen(bool includeMousePointer)
+Q_NOREPLY void SpectacleDBusAdapter::FullScreen(bool includeMousePointer, bool shouldCopy, bool shouldSave)
{
- parent()->takeNewScreenshot(ImageGrabber::FullScreen, 0, includeMousePointer, true);
+ parent()->takeNewScreenshot(ImageGrabber::FullScreen, 0, includeMousePointer, true, shouldCopy, shouldSave);
}
-Q_NOREPLY void SpectacleDBusAdapter::CurrentScreen(bool includeMousePointer)
+Q_NOREPLY void SpectacleDBusAdapter::CurrentScreen(bool includeMousePointer, bool shouldCopy, bool shouldSave)
{
- parent()->takeNewScreenshot(ImageGrabber::CurrentScreen, 0, includeMousePointer, true);
+ parent()->takeNewScreenshot(ImageGrabber::CurrentScreen, 0, includeMousePointer, true, shouldCopy, shouldSave);
}
-Q_NOREPLY void SpectacleDBusAdapter::ActiveWindow(bool includeWindowDecorations, bool includeMousePointer)
+Q_NOREPLY void SpectacleDBusAdapter::ActiveWindow(bool includeWindowDecorations, bool includeMousePointer, bool shouldCopy, bool shouldSave)
{
- parent()->takeNewScreenshot(ImageGrabber::ActiveWindow, 0, includeMousePointer, includeWindowDecorations);
+ parent()->takeNewScreenshot(ImageGrabber::ActiveWindow, 0, includeMousePointer, includeWindowDecorations, shouldCopy, shouldSave);
}
-Q_NOREPLY void SpectacleDBusAdapter::WindowUnderCursor(bool includeWindowDecorations, bool includeMousePointer)
+Q_NOREPLY void SpectacleDBusAdapter::WindowUnderCursor(bool includeWindowDecorations, bool includeMousePointer, bool shouldCopy, bool shouldSave)
{
- parent()->takeNewScreenshot(ImageGrabber::WindowUnderCursor, 0, includeMousePointer, includeWindowDecorations);
+ parent()->takeNewScreenshot(ImageGrabber::WindowUnderCursor, 0, includeMousePointer, includeWindowDecorations, shouldCopy, shouldSave);
}
-Q_NOREPLY void SpectacleDBusAdapter::RectangularRegion(bool includeMousePointer)
+Q_NOREPLY void SpectacleDBusAdapter::RectangularRegion(bool includeMousePointer, bool shouldCopy, bool shouldSave)
{
- parent()->takeNewScreenshot(ImageGrabber::RectangularRegion, 0, includeMousePointer, false);
+ parent()->takeNewScreenshot(ImageGrabber::RectangularRegion, 0, includeMousePointer, false, shouldCopy, shouldSave);
}