Changeset View
Changeset View
Standalone View
Standalone View
src/SpectacleCore.cpp
Context not available. | |||||
21 | #include "spectacle_core_debug.h" | 21 | #include "spectacle_core_debug.h" | ||
---|---|---|---|---|---|
22 | 22 | | |||
23 | #include "Config.h" | 23 | #include "Config.h" | ||
24 | #include "PlatformBackends/DummyImageGrabber.h" | | |||
25 | #ifdef XCB_FOUND | | |||
26 | #include "PlatformBackends/X11ImageGrabber.h" | | |||
27 | #endif | | |||
28 | #include "PlatformBackends/KWinWaylandImageGrabber.h" | | |||
29 | 24 | | |||
30 | #include <KLocalizedString> | 25 | #include <KLocalizedString> | ||
31 | #include <KMessageBox> | 26 | #include <KMessageBox> | ||
Context not available. | |||||
33 | #include <KRun> | 28 | #include <KRun> | ||
34 | #include <KWindowSystem> | 29 | #include <KWindowSystem> | ||
35 | 30 | | |||
31 | #include <QApplication> | ||||
36 | #include <QClipboard> | 32 | #include <QClipboard> | ||
37 | #include <QDebug> | 33 | #include <QDebug> | ||
38 | #include <QDir> | 34 | #include <QDir> | ||
Context not available. | |||||
41 | #include <QProcess> | 37 | #include <QProcess> | ||
42 | #include <QTimer> | 38 | #include <QTimer> | ||
43 | 39 | | |||
44 | SpectacleCore::SpectacleCore(StartMode startMode, ImageGrabber::GrabMode grabMode, QString &saveFileName, | 40 | SpectacleCore::SpectacleCore(StartMode theStartMode, | ||
45 | qint64 delayMsec, bool notifyOnGrab, bool copyToClipboard, QObject *parent) : | 41 | Spectacle::CaptureMode theCaptureMode, | ||
42 | QString &theSaveFileName, | ||||
43 | qint64 theDelayMsec, | ||||
44 | bool theNotifyOnGrab, | ||||
45 | bool theCopyToClipboard, | ||||
46 | QObject *parent) : | ||||
46 | QObject(parent), | 47 | QObject(parent), | ||
47 | mExportManager(ExportManager::instance()), | 48 | mStartMode(theStartMode), | ||
48 | mStartMode(startMode), | 49 | mNotify(theNotifyOnGrab), | ||
49 | mNotify(notifyOnGrab), | 50 | mPlatform(loadPlatform()), | ||
50 | mImageGrabber(nullptr), | | |||
51 | mMainWindow(nullptr), | 51 | mMainWindow(nullptr), | ||
52 | isGuiInited(false), | 52 | mIsGuiInited(false), | ||
53 | copyToClipboard(copyToClipboard) | 53 | mCopyToClipboard(theCopyToClipboard) | ||
54 | { | 54 | { | ||
55 | KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("spectaclerc")); | 55 | auto lConfig = KSharedConfig::openConfig(QStringLiteral("spectaclerc")); | ||
56 | KConfigGroup guiConfig(config, "GuiConfig"); | 56 | KConfigGroup lGuiConfig(lConfig, "GuiConfig"); | ||
57 | 57 | | |||
58 | if (!(saveFileName.isEmpty() || saveFileName.isNull())) { | 58 | if (!(theSaveFileName.isEmpty() || theSaveFileName.isNull())) { | ||
59 | if (QDir::isRelativePath(saveFileName)) { | 59 | if (QDir::isRelativePath(theSaveFileName)) { | ||
60 | saveFileName = QDir::current().absoluteFilePath(saveFileName); | 60 | theSaveFileName = QDir::current().absoluteFilePath(theSaveFileName); | ||
61 | } | 61 | } | ||
62 | setFilename(saveFileName); | 62 | setFilename(theSaveFileName); | ||
63 | } | 63 | } | ||
64 | 64 | | |||
65 | // We might be using the XCB platform (with Xwayland) in a wayland session, | 65 | // essential connections | ||
66 | // but the X11 grabber won't work in that case. So force the Wayland grabber | 66 | connect(this, &SpectacleCore::errorMessage, this, &SpectacleCore::showErrorMessage); | ||
67 | // in Wayland sessions. | 67 | connect(mPlatform.get(), &Platform::newScreenshotTaken, this, &SpectacleCore::screenshotUpdated); | ||
68 | if (KWindowSystem::isPlatformWayland() || qstrcmp(qgetenv("XDG_SESSION_TYPE"), "wayland") == 0) { | 68 | connect(mPlatform.get(), &Platform::newScreenshotFailed, this, &SpectacleCore::screenshotFailed); | ||
69 | mImageGrabber = new KWinWaylandImageGrabber; | | |||
70 | } | | |||
71 | #ifdef XCB_FOUND | | |||
72 | else if (KWindowSystem::isPlatformX11()) { | | |||
73 | mImageGrabber = new X11ImageGrabber; | | |||
74 | } | | |||
75 | #endif | | |||
76 | 69 | | |||
77 | else { | 70 | auto lImmediateAvailable = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::Immediate); | ||
78 | mImageGrabber = new DummyImageGrabber; | 71 | auto lOnClickAvailable = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::OnClick); | ||
72 | if ((!lOnClickAvailable) && (theDelayMsec < 0)) { | ||||
73 | theDelayMsec = 0; | ||||
79 | } | 74 | } | ||
80 | 75 | | |||
81 | setGrabMode(grabMode); | 76 | // reset last region if it should not be remembered across restarts | ||
82 | mImageGrabber->setCapturePointer(guiConfig.readEntry("includePointer", true)); | 77 | auto lSpectacleConfig = SpectacleConfig::instance(); | ||
83 | mImageGrabber->setCaptureDecorations(guiConfig.readEntry("includeDecorations", true)); | 78 | if(!lSpectacleConfig->alwaysRememberRegion()) { | ||
84 | 79 | lSpectacleConfig->setCropRegion(QRect()); | |||
85 | if ((!(mImageGrabber->onClickGrabSupported())) && (delayMsec < 0)) { | | |||
86 | delayMsec = 0; | | |||
87 | } | 80 | } | ||
88 | 81 | | |||
89 | //Reset last region if it should not be remembered across restarts | 82 | // set up the export manager | ||
90 | SpectacleConfig* cfg = SpectacleConfig::instance(); | 83 | auto lExportManager = ExportManager::instance(); | ||
91 | if(!cfg->alwaysRememberRegion()) { | 84 | lExportManager->setCaptureMode(theCaptureMode); | ||
92 | cfg->setCropRegion(QRect()); | 85 | connect(lExportManager, &ExportManager::errorMessage, this, &SpectacleCore::showErrorMessage); | ||
93 | } | 86 | connect(lExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doCopyPath); | ||
87 | connect(lExportManager, &ExportManager::forceNotify, this, &SpectacleCore::doNotify); | ||||
88 | connect(mPlatform.get(), &Platform::windowTitleChanged, lExportManager, &ExportManager::setWindowTitle); | ||||
94 | 89 | | |||
95 | connect(mExportManager, &ExportManager::errorMessage, this, &SpectacleCore::showErrorMessage); | 90 | switch (theStartMode) { | ||
96 | connect(this, &SpectacleCore::errorMessage, this, &SpectacleCore::showErrorMessage); | 91 | case StartMode::DBus: | ||
97 | connect(mImageGrabber, &ImageGrabber::pixmapChanged, this, &SpectacleCore::screenshotUpdated); | | |||
98 | connect(mImageGrabber, &ImageGrabber::windowTitleChanged, mExportManager, &ExportManager::setWindowTitle); | | |||
99 | connect(mImageGrabber, &ImageGrabber::imageGrabFailed, this, &SpectacleCore::screenshotFailed); | | |||
100 | connect(mExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doCopyPath); | | |||
101 | connect(mExportManager, &ExportManager::forceNotify, this, &SpectacleCore::doNotify); | | |||
102 | | ||||
103 | switch (startMode) { | | |||
104 | case DBusMode: | | |||
105 | default: | | |||
106 | break; | 92 | break; | ||
107 | case BackgroundMode: { | 93 | case StartMode::Background: { | ||
108 | int msec = (KWindowSystem::compositingActive() ? 200 : 50) + delayMsec; | 94 | auto lMsec = (KWindowSystem::compositingActive() ? 200 : 50) + theDelayMsec; | ||
109 | QTimer::singleShot(msec, mImageGrabber, &ImageGrabber::doImageGrab); | 95 | auto lShutterMode = lImmediateAvailable ? Platform::ShutterMode::Immediate : Platform::ShutterMode::OnClick; | ||
96 | auto lIncludePointer = lGuiConfig.readEntry("includePointer", true); | ||||
97 | auto lIncludeDecorations = lGuiConfig.readEntry("includeDecorations", true); | ||||
98 | const Platform::GrabMode lCaptureMode = toPlatformGrabMode(theCaptureMode); | ||||
99 | QTimer::singleShot(lMsec, [ this, lCaptureMode, lShutterMode, lIncludePointer, lIncludeDecorations ]() { | ||||
100 | mPlatform->doGrab(lShutterMode, lCaptureMode, lIncludePointer, lIncludeDecorations); | ||||
101 | }); | ||||
110 | } | 102 | } | ||
111 | break; | 103 | break; | ||
112 | case GuiMode: | 104 | case StartMode::Gui: | ||
113 | initGui(); | 105 | initGui(lGuiConfig.readEntry("includePointer", true), lGuiConfig.readEntry("includeDecorations", true)); | ||
114 | break; | 106 | break; | ||
115 | } | 107 | } | ||
116 | } | 108 | } | ||
117 | 109 | | |||
118 | SpectacleCore::~SpectacleCore() | | |||
119 | { | | |||
120 | if (mMainWindow) { | | |||
121 | delete mMainWindow; | | |||
122 | } | | |||
123 | delete mImageGrabber; | | |||
124 | } | | |||
125 | | ||||
126 | // Q_PROPERTY stuff | | |||
127 | | ||||
128 | QString SpectacleCore::filename() const | 110 | QString SpectacleCore::filename() const | ||
129 | { | 111 | { | ||
130 | return mFileNameString; | 112 | return mFileNameString; | ||
Context not available. | |||||
136 | mFileNameUrl = QUrl::fromUserInput(filename); | 118 | mFileNameUrl = QUrl::fromUserInput(filename); | ||
137 | } | 119 | } | ||
138 | 120 | | |||
139 | ImageGrabber::GrabMode SpectacleCore::grabMode() const | | |||
140 | { | | |||
141 | return mImageGrabber->grabMode(); | | |||
142 | } | | |||
143 | | ||||
144 | void SpectacleCore::setGrabMode(ImageGrabber::GrabMode grabMode) | | |||
145 | { | | |||
146 | mImageGrabber->setGrabMode(grabMode); | | |||
147 | mExportManager->setGrabMode(grabMode); | | |||
148 | } | | |||
149 | | ||||
150 | // Slots | 121 | // Slots | ||
151 | 122 | | |||
152 | void SpectacleCore::dbusStartAgent() | 123 | void SpectacleCore::dbusStartAgent() | ||
153 | { | 124 | { | ||
154 | qApp->setQuitOnLastWindowClosed(true); | 125 | qApp->setQuitOnLastWindowClosed(true); | ||
155 | if (!(mStartMode == GuiMode)) { | 126 | | ||
156 | mStartMode = GuiMode; | 127 | auto lConfig = KSharedConfig::openConfig(QStringLiteral("spectaclerc")); | ||
157 | initGui(); | 128 | KConfigGroup lGuiConfig(lConfig, "GuiConfig"); | ||
129 | auto lIncludePointer = lGuiConfig.readEntry("includePointer", true); | ||||
130 | auto lIncludeDecorations = lGuiConfig.readEntry("includeDecorations", true); | ||||
131 | | ||||
132 | if (!(mStartMode == StartMode::Gui)) { | ||||
133 | mStartMode = StartMode::Gui; | ||||
134 | initGui(lIncludePointer, lIncludeDecorations); | ||||
158 | } else { | 135 | } else { | ||
159 | using Actions = SpectacleConfig::PrintKeyActionRunning; | 136 | using Actions = SpectacleConfig::PrintKeyActionRunning; | ||
160 | switch (SpectacleConfig::instance()->printKeyActionRunning()) { | 137 | switch (SpectacleConfig::instance()->printKeyActionRunning()) { | ||
161 | case Actions::TakeNewScreenshot: | 138 | case Actions::TakeNewScreenshot: { | ||
162 | QTimer::singleShot(KWindowSystem::compositingActive() ? 200 : 50, mImageGrabber, &ImageGrabber::doImageGrab); | 139 | auto lShutterMode = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::Immediate) ? Platform::ShutterMode::Immediate : Platform::ShutterMode::OnClick; | ||
140 | auto lGrabMode = toPlatformGrabMode(ExportManager::instance()->captureMode()); | ||||
141 | QTimer::singleShot(KWindowSystem::compositingActive() ? 200 : 50, [this, lShutterMode, lGrabMode, lIncludePointer, lIncludeDecorations]() { | ||||
142 | mPlatform->doGrab(lShutterMode, lGrabMode, lIncludePointer, lIncludeDecorations); | ||||
143 | }); | ||||
163 | break; | 144 | break; | ||
145 | } | ||||
164 | case Actions::FocusWindow: | 146 | case Actions::FocusWindow: | ||
165 | KWindowSystem::forceActiveWindow(mMainWindow->winId());; | 147 | KWindowSystem::forceActiveWindow(mMainWindow->winId()); | ||
166 | break; | 148 | break; | ||
167 | case Actions::StartNewInstance: | 149 | case Actions::StartNewInstance: | ||
168 | QProcess newInstance; | 150 | QProcess newInstance; | ||
Context not available. | |||||
173 | } | 155 | } | ||
174 | } | 156 | } | ||
175 | 157 | | |||
176 | void SpectacleCore::takeNewScreenshot(const ImageGrabber::GrabMode &mode, | 158 | void SpectacleCore::takeNewScreenshot(Spectacle::CaptureMode theCaptureMode, | ||
177 | const int &timeout, const bool &includePointer, const bool &includeDecorations) | 159 | int theTimeout, | ||
160 | bool theIncludePointer, | ||||
161 | bool theIncludeDecorations) | ||||
178 | { | 162 | { | ||
179 | setGrabMode(mode); | 163 | ExportManager::instance()->setCaptureMode(theCaptureMode); | ||
180 | mImageGrabber->setCapturePointer(includePointer); | 164 | auto lGrabMode = toPlatformGrabMode(theCaptureMode); | ||
181 | mImageGrabber->setCaptureDecorations(includeDecorations); | | |||
182 | 165 | | |||
183 | if (timeout < 0) { | 166 | if (theTimeout < 0) { | ||
184 | mImageGrabber->doOnClickGrab(); | 167 | mPlatform->doGrab(Platform::ShutterMode::OnClick, lGrabMode, theIncludePointer, theIncludeDecorations); | ||
185 | return; | 168 | return; | ||
186 | } | 169 | } | ||
187 | 170 | | |||
Context not available. | |||||
191 | // settings (and unless the user has set an extremely slow effect), 200 | 174 | // settings (and unless the user has set an extremely slow effect), 200 | ||
192 | // milliseconds is a good amount of wait time. | 175 | // milliseconds is a good amount of wait time. | ||
193 | 176 | | |||
194 | const int msec = KWindowSystem::compositingActive() ? 200 : 50; | 177 | auto lMsec = KWindowSystem::compositingActive() ? 200 : 50; | ||
195 | QTimer::singleShot(timeout + msec, mImageGrabber, &ImageGrabber::doImageGrab); | 178 | QTimer::singleShot(theTimeout + lMsec, [this, lGrabMode, theIncludePointer, theIncludeDecorations]() { | ||
179 | mPlatform->doGrab(Platform::ShutterMode::Immediate, lGrabMode, theIncludePointer, theIncludeDecorations); | ||||
180 | }); | ||||
196 | } | 181 | } | ||
197 | 182 | | |||
198 | void SpectacleCore::showErrorMessage(const QString &errString) | 183 | void SpectacleCore::showErrorMessage(const QString &theErrString) | ||
199 | { | 184 | { | ||
200 | qCDebug(SPECTACLE_CORE_LOG) << "ERROR: " << errString; | 185 | qCDebug(SPECTACLE_CORE_LOG) << "ERROR: " << theErrString; | ||
201 | 186 | | |||
202 | if (mStartMode == GuiMode) { | 187 | if (mStartMode == StartMode::Gui) { | ||
203 | KMessageBox::error(nullptr, errString); | 188 | KMessageBox::error(nullptr, theErrString); | ||
204 | } | 189 | } | ||
205 | } | 190 | } | ||
206 | 191 | | |||
207 | void SpectacleCore::screenshotUpdated(const QPixmap &pixmap) | 192 | void SpectacleCore::screenshotUpdated(const QPixmap &thePixmap) | ||
208 | { | 193 | { | ||
209 | mExportManager->setPixmap(pixmap); | 194 | auto lExportManager = ExportManager::instance(); | ||
210 | mExportManager->updatePixmapTimestamp(); | 195 | | ||
196 | // if we were running in rectangular crop mode, now would be | ||||
197 | // the time to further process the image | ||||
198 | | ||||
199 | if (lExportManager->captureMode() == Spectacle::CaptureMode::RectangularRegion) { | ||||
200 | if(!mQuickEditor) { | ||||
201 | mQuickEditor = std::make_unique<QuickEditor>(thePixmap); | ||||
202 | connect(mQuickEditor.get(), &QuickEditor::grabDone, this, &SpectacleCore::screenshotUpdated); | ||||
203 | connect(mQuickEditor.get(), &QuickEditor::grabCancelled, this, &SpectacleCore::screenshotFailed); | ||||
204 | mQuickEditor->showFullScreen(); | ||||
205 | return; | ||||
206 | } else { | ||||
207 | mQuickEditor->hide(); | ||||
208 | mQuickEditor.reset(nullptr); | ||||
209 | } | ||||
210 | } | ||||
211 | | ||||
212 | lExportManager->setPixmap(thePixmap); | ||||
213 | lExportManager->updatePixmapTimestamp(); | ||||
211 | 214 | | |||
212 | switch (mStartMode) { | 215 | switch (mStartMode) { | ||
213 | case BackgroundMode: | 216 | case StartMode::Background: | ||
214 | case DBusMode: | 217 | case StartMode::DBus: | ||
215 | default: | | |||
216 | { | 218 | { | ||
217 | if (mNotify) { | 219 | if (mNotify) { | ||
218 | connect(mExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doNotify); | 220 | connect(lExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doNotify); | ||
219 | } | 221 | } | ||
220 | 222 | | |||
221 | if (copyToClipboard) { | 223 | if (mCopyToClipboard) { | ||
222 | mExportManager->doCopyToClipboard(mNotify); | 224 | lExportManager->doCopyToClipboard(mNotify); | ||
223 | } else { | 225 | } else { | ||
224 | QUrl savePath = (mStartMode == BackgroundMode && mFileNameUrl.isValid() && mFileNameUrl.isLocalFile()) ? | 226 | QUrl lSavePath = (mStartMode == StartMode::Background && mFileNameUrl.isValid() && mFileNameUrl.isLocalFile()) ? | ||
225 | mFileNameUrl : QUrl(); | 227 | mFileNameUrl : QUrl(); | ||
226 | mExportManager->doSave(savePath); | 228 | lExportManager->doSave(lSavePath); | ||
227 | } | 229 | } | ||
228 | 230 | | |||
229 | // if we notify, we emit allDone only if the user either dismissed the notification or pressed | 231 | // if we notify, we emit allDone only if the user either dismissed the notification or pressed | ||
Context not available. | |||||
233 | } | 235 | } | ||
234 | } | 236 | } | ||
235 | break; | 237 | break; | ||
236 | case GuiMode: | 238 | case StartMode::Gui: | ||
237 | mMainWindow->setScreenshotAndShow(pixmap); | 239 | mMainWindow->setScreenshotAndShow(thePixmap); | ||
238 | } | 240 | } | ||
239 | } | 241 | } | ||
240 | 242 | | |||
241 | void SpectacleCore::screenshotFailed() | 243 | void SpectacleCore::screenshotFailed() | ||
242 | { | 244 | { | ||
245 | if (ExportManager::instance()->captureMode() == Spectacle::CaptureMode::RectangularRegion && mQuickEditor) { | ||||
246 | mQuickEditor->hide(); | ||||
247 | mQuickEditor.reset(nullptr); | ||||
248 | } | ||||
249 | | ||||
243 | switch (mStartMode) { | 250 | switch (mStartMode) { | ||
244 | case BackgroundMode: | 251 | case StartMode::Background: | ||
245 | showErrorMessage(i18n("Screenshot capture canceled or failed")); | 252 | showErrorMessage(i18n("Screenshot capture canceled or failed")); | ||
246 | emit allDone(); | 253 | emit allDone(); | ||
247 | return; | 254 | return; | ||
248 | case DBusMode: | 255 | case StartMode::DBus: | ||
249 | default: | | |||
250 | emit grabFailed(); | 256 | emit grabFailed(); | ||
251 | emit allDone(); | 257 | emit allDone(); | ||
252 | return; | 258 | return; | ||
253 | case GuiMode: | 259 | case StartMode::Gui: | ||
254 | mMainWindow->show(); | 260 | mMainWindow->show(); | ||
255 | } | 261 | } | ||
256 | } | 262 | } | ||
257 | 263 | | |||
258 | void SpectacleCore::doNotify(const QUrl &savedAt) | 264 | void SpectacleCore::doNotify(const QUrl &theSavedAt) | ||
259 | { | 265 | { | ||
260 | KNotification *notify = new KNotification(QStringLiteral("newScreenshotSaved")); | 266 | KNotification *lNotify = new KNotification(QStringLiteral("newScreenshotSaved")); | ||
261 | 267 | | |||
262 | switch(mImageGrabber->grabMode()) { | 268 | switch(ExportManager::instance()->captureMode()) { | ||
263 | case ImageGrabber::GrabMode::FullScreen: | 269 | case Spectacle::CaptureMode::AllScreens: | ||
264 | notify->setTitle(i18nc("The entire screen area was captured, heading", "Full Screen Captured")); | 270 | lNotify->setTitle(i18nc("The entire screen area was captured, heading", "Full Screen Captured")); | ||
265 | break; | 271 | break; | ||
266 | case ImageGrabber::GrabMode::CurrentScreen: | 272 | case Spectacle::CaptureMode::CurrentScreen: | ||
267 | notify->setTitle(i18nc("The current screen was captured, heading", "Current Screen Captured")); | 273 | lNotify->setTitle(i18nc("The current screen was captured, heading", "Current Screen Captured")); | ||
268 | break; | 274 | break; | ||
269 | case ImageGrabber::GrabMode::ActiveWindow: | 275 | case Spectacle::CaptureMode::ActiveWindow: | ||
270 | notify->setTitle(i18nc("The active window was captured, heading", "Active Window Captured")); | 276 | lNotify->setTitle(i18nc("The active window was captured, heading", "Active Window Captured")); | ||
271 | break; | 277 | break; | ||
272 | case ImageGrabber::GrabMode::WindowUnderCursor: | 278 | case Spectacle::CaptureMode::WindowUnderCursor: | ||
273 | case ImageGrabber::GrabMode::TransientWithParent: | 279 | case Spectacle::CaptureMode::TransientWithParent: | ||
274 | notify->setTitle(i18nc("The window under the mouse was captured, heading", "Window Under Cursor Captured")); | 280 | lNotify->setTitle(i18nc("The window under the mouse was captured, heading", "Window Under Cursor Captured")); | ||
275 | break; | 281 | break; | ||
276 | case ImageGrabber::GrabMode::RectangularRegion: | 282 | case Spectacle::CaptureMode::RectangularRegion: | ||
277 | notify->setTitle(i18nc("A rectangular region was captured, heading", "Rectangular Region Captured")); | 283 | lNotify->setTitle(i18nc("A rectangular region was captured, heading", "Rectangular Region Captured")); | ||
278 | break; | 284 | break; | ||
279 | case ImageGrabber::GrabMode::InvalidChoice: | 285 | case Spectacle::CaptureMode::InvalidChoice: | ||
280 | default: | | |||
281 | break; | 286 | break; | ||
282 | } | 287 | } | ||
283 | 288 | | |||
284 | const QString &path = savedAt.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path(); | | |||
285 | | ||||
286 | // a speaking message is prettier than a URL, special case for copy to clipboard and the default pictures location | 289 | // a speaking message is prettier than a URL, special case for copy to clipboard and the default pictures location | ||
287 | if (copyToClipboard) { | 290 | const QString &lSavePath = theSavedAt.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path(); | ||
288 | notify->setText(i18n("A screenshot was saved to your clipboard.")); | 291 | if (mCopyToClipboard) { | ||
289 | } else if (path == QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)) { | 292 | lNotify->setText(i18n("A screenshot was saved to your clipboard.")); | ||
290 | notify->setText(i18nc("Placeholder is filename", "A screenshot was saved as '%1' to your Pictures folder.", savedAt.fileName())); | 293 | } else if (lSavePath == QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)) { | ||
294 | lNotify->setText(i18nc("Placeholder is filename", "A screenshot was saved as '%1' to your Pictures folder.", theSavedAt.fileName())); | ||||
291 | } else { | 295 | } else { | ||
292 | notify->setText(i18n("A screenshot was saved as '%1' to '%2'.", savedAt.fileName(), path)); | 296 | lNotify->setText(i18n("A screenshot was saved as '%1' to '%2'.", theSavedAt.fileName(), lSavePath)); | ||
293 | } | 297 | } | ||
294 | 298 | | |||
295 | if (!copyToClipboard) { | 299 | if (!mCopyToClipboard) { | ||
296 | notify->setUrls({savedAt}); | 300 | lNotify->setUrls({theSavedAt}); | ||
297 | 301 | lNotify->setDefaultAction(i18nc("Open the screenshot we just saved", "Open")); | |||
298 | notify->setDefaultAction(i18nc("Open the screenshot we just saved", "Open")); | 302 | connect(lNotify, QOverload<uint>::of(&KNotification::activated), this, [this, theSavedAt](uint index) { | ||
299 | connect(notify, QOverload<uint>::of(&KNotification::activated), this, [this, savedAt](uint index) { | | |||
300 | if (index == 0) { | 303 | if (index == 0) { | ||
301 | new KRun(savedAt, nullptr); | 304 | new KRun(theSavedAt, nullptr); | ||
302 | QTimer::singleShot(250, this, &SpectacleCore::allDone); | 305 | QTimer::singleShot(250, this, &SpectacleCore::allDone); | ||
303 | } | 306 | } | ||
304 | }); | 307 | }); | ||
305 | } | 308 | } | ||
306 | 309 | | |||
307 | connect(notify, &QObject::destroyed, this, &SpectacleCore::allDone); | 310 | connect(lNotify, &QObject::destroyed, this, &SpectacleCore::allDone); | ||
308 | 311 | lNotify->sendEvent(); | |||
309 | notify->sendEvent(); | | |||
310 | } | 312 | } | ||
311 | 313 | | |||
312 | void SpectacleCore::doCopyPath(const QUrl &savedAt) | 314 | void SpectacleCore::doCopyPath(const QUrl &savedAt) | ||
Context not available. | |||||
318 | 320 | | |||
319 | void SpectacleCore::doStartDragAndDrop() | 321 | void SpectacleCore::doStartDragAndDrop() | ||
320 | { | 322 | { | ||
321 | QUrl tempFile = mExportManager->tempSave(); | 323 | auto lExportManager = ExportManager::instance(); | ||
322 | if (!tempFile.isValid()) { | 324 | QUrl lTempFile = lExportManager->tempSave(); | ||
325 | if (!lTempFile.isValid()) { | ||||
323 | return; | 326 | return; | ||
324 | } | 327 | } | ||
325 | 328 | | |||
326 | QMimeData *mimeData = new QMimeData; | 329 | auto lMimeData = new QMimeData; | ||
327 | mimeData->setUrls(QList<QUrl> { tempFile }); | 330 | lMimeData->setUrls(QList<QUrl> { lTempFile }); | ||
328 | mimeData->setData(QStringLiteral("application/x-kde-suggestedfilename"), QFile::encodeName(tempFile.fileName())); | 331 | lMimeData->setData(QStringLiteral("application/x-kde-suggestedfilename"), QFile::encodeName(lTempFile.fileName())); | ||
329 | 332 | | |||
330 | QDrag *dragHandler = new QDrag(this); | 333 | auto lDragHandler = new QDrag(this); | ||
331 | dragHandler->setMimeData(mimeData); | 334 | lDragHandler->setMimeData(lMimeData); | ||
332 | dragHandler->setPixmap(mExportManager->pixmap().scaled(256, 256, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation)); | 335 | lDragHandler->setPixmap(lExportManager->pixmap().scaled(256, 256, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation)); | ||
333 | dragHandler->exec(Qt::CopyAction); | 336 | lDragHandler->exec(Qt::CopyAction); | ||
334 | } | 337 | } | ||
335 | 338 | | |||
336 | // Private | 339 | // Private | ||
337 | 340 | | |||
338 | void SpectacleCore::initGui() | 341 | Platform::GrabMode SpectacleCore::toPlatformGrabMode(Spectacle::CaptureMode theCaptureMode) | ||
342 | { | ||||
343 | switch(theCaptureMode) { | ||||
344 | case Spectacle::CaptureMode::InvalidChoice: | ||||
345 | return Platform::GrabMode::InvalidChoice; | ||||
346 | case Spectacle::CaptureMode::AllScreens: | ||||
347 | case Spectacle::CaptureMode::RectangularRegion: | ||||
348 | return Platform::GrabMode::AllScreens; | ||||
349 | case Spectacle::CaptureMode::TransientWithParent: | ||||
350 | return Platform::GrabMode::TransientWithParent; | ||||
351 | case Spectacle::CaptureMode::CurrentScreen: | ||||
352 | return Platform::GrabMode::CurrentScreen; | ||||
353 | case Spectacle::CaptureMode::ActiveWindow: | ||||
354 | return Platform::GrabMode::ActiveWindow; | ||||
355 | case Spectacle::CaptureMode::WindowUnderCursor: | ||||
356 | return Platform::GrabMode::WindowUnderCursor; | ||||
357 | } | ||||
358 | return Platform::GrabMode::InvalidChoice; | ||||
359 | } | ||||
360 | | ||||
361 | void SpectacleCore::initGui(bool theIncludePointer, bool theIncludeDecorations) | ||||
339 | { | 362 | { | ||
340 | if (!isGuiInited) { | 363 | if (!mIsGuiInited) { | ||
341 | mMainWindow = new KSMainWindow(mImageGrabber->supportedModes(), mImageGrabber->onClickGrabSupported()); | 364 | mMainWindow = std::make_unique<KSMainWindow>(mPlatform->supportedGrabModes(), mPlatform->supportedShutterModes()); | ||
365 | | ||||
366 | connect(mMainWindow.get(), &KSMainWindow::newScreenshotRequest, this, &SpectacleCore::takeNewScreenshot); | ||||
367 | connect(mMainWindow.get(), &KSMainWindow::dragAndDropRequest, this, &SpectacleCore::doStartDragAndDrop); | ||||
342 | 368 | | |||
343 | connect(mMainWindow, &KSMainWindow::newScreenshotRequest, this, &SpectacleCore::takeNewScreenshot); | 369 | mIsGuiInited = true; | ||
344 | connect(mMainWindow, &KSMainWindow::dragAndDropRequest, this, &SpectacleCore::doStartDragAndDrop); | | |||
345 | 370 | | |||
346 | isGuiInited = true; | 371 | auto lShutterMode = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::Immediate) ? Platform::ShutterMode::Immediate : Platform::ShutterMode::OnClick; | ||
347 | QMetaObject::invokeMethod(mImageGrabber, "doImageGrab", Qt::QueuedConnection); | 372 | auto lGrabMode = toPlatformGrabMode(ExportManager::instance()->captureMode()); | ||
373 | | ||||
374 | QTimer::singleShot(0, [this, lShutterMode, lGrabMode, theIncludePointer, theIncludeDecorations]() { | ||||
375 | mPlatform->doGrab(lShutterMode, lGrabMode, theIncludePointer, theIncludeDecorations); | ||||
376 | }); | ||||
348 | } | 377 | } | ||
349 | } | 378 | } | ||
Context not available. |