Changeset View
Changeset View
Standalone View
Standalone View
src/SpectacleCore.cpp
Show All 38 Lines | |||||
39 | #include <QClipboard> | 39 | #include <QClipboard> | ||
40 | #include <QDir> | 40 | #include <QDir> | ||
41 | #include <QDrag> | 41 | #include <QDrag> | ||
42 | #include <QKeySequence> | 42 | #include <QKeySequence> | ||
43 | #include <QMimeData> | 43 | #include <QMimeData> | ||
44 | #include <QProcess> | 44 | #include <QProcess> | ||
45 | #include <QTimer> | 45 | #include <QTimer> | ||
46 | 46 | | |||
47 | SpectacleCore::SpectacleCore(StartMode theStartMode, | 47 | SpectacleCore::SpectacleCore(QObject *parent): | ||
48 | Spectacle::CaptureMode theCaptureMode, | | |||
49 | QString &theSaveFileName, | | |||
50 | qint64 theDelayMsec, | | |||
51 | bool theNotifyOnGrab, | | |||
52 | bool theCopyToClipboard, | | |||
53 | QObject *parent) : | | |||
54 | QObject(parent), | | |||
55 | mStartMode(theStartMode), | | |||
56 | mNotify(theNotifyOnGrab), | | |||
57 | mPlatform(loadPlatform()), | | |||
58 | mMainWindow(nullptr), | 48 | mMainWindow(nullptr), | ||
59 | mIsGuiInited(false), | 49 | mIsGuiInited(false), | ||
60 | mCopyToClipboard(theCopyToClipboard), | 50 | mWaylandPlasmashell(nullptr), | ||
61 | mWaylandPlasmashell(nullptr) | 51 | QObject(parent) | ||
davidre: Can you do
```
{
}
```
| |||||
52 | {} | ||||
53 | | ||||
54 | void SpectacleCore::init() | ||||
62 | { | 55 | { | ||
63 | if (!(theSaveFileName.isEmpty() || theSaveFileName.isNull())) { | 56 | mPlatform = loadPlatform(); | ||
64 | if (QDir::isRelativePath(theSaveFileName)) { | | |||
65 | theSaveFileName = QDir::current().absoluteFilePath(theSaveFileName); | | |||
66 | } | | |||
67 | setFilename(theSaveFileName); | | |||
68 | } | | |||
69 | 57 | | |||
70 | // essential connections | 58 | // essential connections | ||
71 | connect(this, &SpectacleCore::errorMessage, this, &SpectacleCore::showErrorMessage); | 59 | connect(this, &SpectacleCore::errorMessage, this, &SpectacleCore::showErrorMessage); | ||
72 | connect(mPlatform.get(), &Platform::newScreenshotTaken, this, &SpectacleCore::screenshotUpdated); | 60 | connect(mPlatform.get(), &Platform::newScreenshotTaken, this, &SpectacleCore::screenshotUpdated); | ||
73 | connect(mPlatform.get(), &Platform::newScreenshotFailed, this, &SpectacleCore::screenshotFailed); | 61 | connect(mPlatform.get(), &Platform::newScreenshotFailed, this, &SpectacleCore::screenshotFailed); | ||
74 | 62 | | |||
75 | auto lImmediateAvailable = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::Immediate); | | |||
76 | auto lOnClickAvailable = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::OnClick); | | |||
77 | if ((!lOnClickAvailable) && (theDelayMsec < 0)) { | | |||
78 | theDelayMsec = 0; | | |||
79 | } | | |||
80 | | ||||
81 | // reset last region if it should not be remembered across restarts | | |||
82 | if(!Settings::alwaysRememberRegion()) { | | |||
83 | Settings::setCropRegion({0, 0, 0, 0}); | | |||
84 | } | | |||
85 | | ||||
86 | // set up the export manager | 63 | // set up the export manager | ||
87 | auto lExportManager = ExportManager::instance(); | 64 | auto lExportManager = ExportManager::instance(); | ||
88 | lExportManager->setCaptureMode(theCaptureMode); | | |||
89 | connect(lExportManager, &ExportManager::errorMessage, this, &SpectacleCore::showErrorMessage); | 65 | connect(lExportManager, &ExportManager::errorMessage, this, &SpectacleCore::showErrorMessage); | ||
90 | connect(lExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doCopyPath); | 66 | connect(lExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doCopyPath); | ||
91 | connect(lExportManager, &ExportManager::forceNotify, this, &SpectacleCore::doNotify); | 67 | connect(lExportManager, &ExportManager::forceNotify, this, &SpectacleCore::doNotify); | ||
92 | connect(mPlatform.get(), &Platform::windowTitleChanged, lExportManager, &ExportManager::setWindowTitle); | 68 | connect(mPlatform.get(), &Platform::windowTitleChanged, lExportManager, &ExportManager::setWindowTitle); | ||
93 | 69 | | |||
94 | // Needed so the QuickEditor can go fullscreen on wayland | 70 | // Needed so the QuickEditor can go fullscreen on wayland | ||
95 | if (KWindowSystem::isPlatformWayland()) { | 71 | if (KWindowSystem::isPlatformWayland()) { | ||
96 | using namespace KWayland::Client; | 72 | using namespace KWayland::Client; | ||
97 | ConnectionThread *connection = ConnectionThread::fromApplication(this); | 73 | ConnectionThread *connection = ConnectionThread::fromApplication(this); | ||
98 | if (!connection) { | 74 | if (!connection) { | ||
99 | return; | 75 | return; | ||
100 | } | 76 | } | ||
101 | Registry *registry = new Registry(this); | 77 | Registry *registry = new Registry(this); | ||
102 | registry->create(connection); | 78 | registry->create(connection); | ||
103 | connect(registry, &Registry::plasmaShellAnnounced, this, | 79 | connect(registry, &Registry::plasmaShellAnnounced, this, | ||
104 | [this, registry] (quint32 name, quint32 version) { | 80 | [this, registry] (quint32 name, quint32 version) { | ||
105 | mWaylandPlasmashell = registry->createPlasmaShell(name, version, this); | 81 | mWaylandPlasmashell = registry->createPlasmaShell(name, version, this); | ||
106 | } | 82 | } | ||
107 | ); | 83 | ); | ||
108 | registry->setup(); | 84 | registry->setup(); | ||
109 | connection->roundtrip(); | 85 | connection->roundtrip(); | ||
110 | } | 86 | } | ||
87 | setUpShortcuts(); | ||||
88 | } | ||||
89 | | ||||
90 | void SpectacleCore::onActivateRequested(QStringList arguments, const QString& /*workingDirectory */) | ||||
91 | { | ||||
92 | // QCommandLineParser expects the first argument to be the executable name | ||||
93 | // In the current version it just strips it away | ||||
94 | arguments.prepend(qApp->applicationFilePath()); | ||||
95 | | ||||
96 | // We can't re-use QCommandLineParser instances, it preserves earlier parsed values | ||||
97 | auto parser = new QCommandLineParser; | ||||
broulik: This leaks | |||||
98 | populateCommandLineParser(parser); | ||||
99 | parser->parse(arguments); | ||||
100 | | ||||
101 | // extract the capture mode | ||||
102 | Spectacle::CaptureMode lCaptureMode = Spectacle::CaptureMode::AllScreens; | ||||
103 | if (parser->isSet(QStringLiteral("current"))) { | ||||
104 | lCaptureMode = Spectacle::CaptureMode::CurrentScreen; | ||||
105 | } else if (parser->isSet(QStringLiteral("activewindow"))) { | ||||
106 | lCaptureMode = Spectacle::CaptureMode::ActiveWindow; | ||||
107 | } else if (parser->isSet(QStringLiteral("region"))) { | ||||
108 | lCaptureMode = Spectacle::CaptureMode::RectangularRegion; | ||||
109 | } else if (parser->isSet(QStringLiteral("windowundercursor"))) { | ||||
110 | lCaptureMode = Spectacle::CaptureMode::TransientWithParent; | ||||
111 | } else if (parser->isSet(QStringLiteral("transientonly"))) { | ||||
112 | lCaptureMode = Spectacle::CaptureMode::WindowUnderCursor; | ||||
113 | } | ||||
114 | | ||||
115 | mStartMode = SpectacleCore::StartMode::Gui; | ||||
116 | mNotify = true; | ||||
117 | mCopyToClipboard = Settings::copyImageToClipboard(); | ||||
118 | qint64 lDelayMsec = 0; | ||||
119 | QString lFileName = QString(); | ||||
120 | | ||||
121 | // are we ask to run in background or dbus mode? | ||||
122 | if (parser->isSet(QStringLiteral("background"))) { | ||||
123 | mStartMode = SpectacleCore::StartMode::Background; | ||||
124 | } else if (parser->isSet(QStringLiteral("dbus"))) { | ||||
125 | mStartMode = SpectacleCore::StartMode::DBus; | ||||
126 | } | ||||
127 | | ||||
128 | switch(mStartMode) { | ||||
129 | case SpectacleCore::StartMode::Background: | ||||
130 | if (parser->isSet(QStringLiteral("nonotify"))) { | ||||
131 | mNotify = false; | ||||
132 | } | ||||
133 | | ||||
134 | if (parser->isSet(QStringLiteral("output"))) { | ||||
135 | lFileName = parser->value(QStringLiteral("output")); | ||||
136 | } | ||||
137 | | ||||
138 | if (parser->isSet(QStringLiteral("delay"))) { | ||||
139 | bool lParseOk = false; | ||||
140 | qint64 lDelayValue = parser->value(QStringLiteral("delay")).toLongLong(&lParseOk); | ||||
141 | if (lParseOk) { | ||||
142 | lDelayMsec = lDelayValue; | ||||
143 | } | ||||
144 | } | ||||
145 | | ||||
146 | if (parser->isSet(QStringLiteral("onclick"))) { | ||||
147 | lDelayMsec = -1; | ||||
148 | } | ||||
149 | | ||||
150 | if (parser->isSet(QStringLiteral("clipboard"))) { | ||||
151 | mCopyToClipboard = true; | ||||
152 | } | ||||
153 | | ||||
154 | if (!mIsGuiInited) { | ||||
155 | static_cast<QGuiApplication *>(qApp->instance())->setQuitOnLastWindowClosed(false); | ||||
156 | } | ||||
157 | break; | ||||
158 | case SpectacleCore::StartMode::DBus: | ||||
159 | static_cast<QGuiApplication *>(qApp->instance())->setQuitOnLastWindowClosed(false); | ||||
160 | break; | ||||
161 | case SpectacleCore::StartMode::Gui: | ||||
162 | break; | ||||
163 | } | ||||
164 | | ||||
165 | auto lExportManager = ExportManager::instance(); | ||||
166 | lExportManager->setCaptureMode(lCaptureMode); | ||||
111 | 167 | | |||
112 | switch (theStartMode) { | 168 | auto lOnClickAvailable = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::OnClick); | ||
169 | if ((!lOnClickAvailable) && (lDelayMsec < 0)) { | ||||
170 | lDelayMsec = 0; | ||||
171 | } | ||||
172 | | ||||
173 | if (!(lFileName.isEmpty() || lFileName.isNull())) { | ||||
174 | if (QDir::isRelativePath(lFileName)) { | ||||
175 | lFileName = QDir::current().absoluteFilePath(lFileName); | ||||
176 | } | ||||
177 | setFilename(lFileName); | ||||
178 | } | ||||
179 | | ||||
180 | // reset last region if it should not be remembered across restarts | ||||
181 | if(!Settings::alwaysRememberRegion()) { | ||||
182 | Settings::setCropRegion({0, 0, 0, 0}); | ||||
183 | } | ||||
184 | | ||||
185 | switch (mStartMode) { | ||||
113 | case StartMode::DBus: | 186 | case StartMode::DBus: | ||
114 | break; | 187 | break; | ||
115 | case StartMode::Background: { | 188 | case StartMode::Background: { | ||
116 | auto lMsec = (KWindowSystem::compositingActive() ? 200 : 50) + theDelayMsec; | | |||
117 | auto lShutterMode = lImmediateAvailable ? Platform::ShutterMode::Immediate : Platform::ShutterMode::OnClick; | | |||
118 | auto lIncludePointer = Settings::includePointer(); | 189 | auto lIncludePointer = Settings::includePointer(); | ||
119 | auto lIncludeDecorations = Settings::includeDecorations(); | 190 | auto lIncludeDecorations = Settings::includeDecorations(); | ||
120 | const Platform::GrabMode lCaptureMode = toPlatformGrabMode(theCaptureMode); | 191 | takeNewScreenshot(lCaptureMode, lDelayMsec, lIncludePointer, lIncludeDecorations); | ||
121 | QTimer::singleShot(lMsec, this, [ this, lCaptureMode, lShutterMode, lIncludePointer, lIncludeDecorations ]() { | | |||
122 | mPlatform->doGrab(lShutterMode, lCaptureMode, lIncludePointer, lIncludeDecorations); | | |||
123 | }); | | |||
124 | } | 192 | } | ||
125 | break; | 193 | break; | ||
126 | case StartMode::Gui: | 194 | case StartMode::Gui: | ||
127 | initGui(Settings::includePointer(), Settings::includeDecorations()); | 195 | initGui(lDelayMsec, Settings::includePointer(), Settings::includeDecorations()); | ||
128 | break; | 196 | break; | ||
129 | } | 197 | } | ||
130 | setUpShortcuts(); | | |||
131 | } | 198 | } | ||
132 | 199 | | |||
133 | void SpectacleCore::setUpShortcuts() | 200 | void SpectacleCore::setUpShortcuts() | ||
134 | { | 201 | { | ||
135 | KGlobalAccel::self()->setGlobalShortcut(ShortcutActions::self()->openAction(), Qt::Key_Print); | 202 | KGlobalAccel::self()->setGlobalShortcut(ShortcutActions::self()->openAction(), Qt::Key_Print); | ||
136 | 203 | | |||
137 | KGlobalAccel::self()->setGlobalShortcut(ShortcutActions::self()->fullScreenAction(), Qt::SHIFT + Qt::Key_Print); | 204 | KGlobalAccel::self()->setGlobalShortcut(ShortcutActions::self()->fullScreenAction(), Qt::SHIFT + Qt::Key_Print); | ||
138 | 205 | | |||
Show All 10 Lines | |||||
149 | } | 216 | } | ||
150 | 217 | | |||
151 | void SpectacleCore::setFilename(const QString &filename) | 218 | void SpectacleCore::setFilename(const QString &filename) | ||
152 | { | 219 | { | ||
153 | mFileNameString = filename; | 220 | mFileNameString = filename; | ||
154 | mFileNameUrl = QUrl::fromUserInput(filename); | 221 | mFileNameUrl = QUrl::fromUserInput(filename); | ||
155 | } | 222 | } | ||
156 | 223 | | |||
157 | // Slots | | |||
158 | | ||||
159 | void SpectacleCore::dbusStartAgent() | | |||
160 | { | | |||
161 | qApp->setQuitOnLastWindowClosed(true); | | |||
162 | | ||||
163 | auto lConfig = KSharedConfig::openConfig(QStringLiteral("spectaclerc")); | | |||
164 | KConfigGroup lGuiConfig(lConfig, "GuiConfig"); | | |||
165 | auto lIncludePointer = lGuiConfig.readEntry("includePointer", true); | | |||
166 | auto lIncludeDecorations = lGuiConfig.readEntry("includeDecorations", true); | | |||
167 | | ||||
168 | if (!(mStartMode == StartMode::Gui)) { | | |||
169 | mStartMode = StartMode::Gui; | | |||
170 | initGui(lIncludePointer, lIncludeDecorations); | | |||
171 | } else { | | |||
172 | using Actions = Settings::EnumPrintKeyActionRunning; | | |||
173 | switch (Settings::printKeyActionRunning()) { | | |||
174 | case Actions::TakeNewScreenshot: { | | |||
175 | // 0 means Immediate, -1 onClick | | |||
176 | int timeout = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::Immediate) ? 0 : -1; | | |||
177 | takeNewScreenshot(Settings::captureMode(), timeout, Settings::includePointer(), Settings::includeDecorations()); | | |||
178 | break; | | |||
179 | } | | |||
180 | case Actions::FocusWindow: | | |||
181 | if (mMainWindow->isMinimized()) { | | |||
182 | mMainWindow->setWindowState(mMainWindow->windowState() & ~Qt::WindowMinimized); | | |||
183 | } | | |||
184 | mMainWindow->activateWindow(); | | |||
185 | break; | | |||
186 | case Actions::StartNewInstance: | | |||
187 | QProcess newInstance; | | |||
188 | newInstance.setProgram(QStringLiteral("spectacle")); | | |||
189 | newInstance.startDetached(); | | |||
190 | break; | | |||
191 | } | | |||
192 | } | | |||
193 | } | | |||
194 | | ||||
195 | void SpectacleCore::takeNewScreenshot(Spectacle::CaptureMode theCaptureMode, | 224 | void SpectacleCore::takeNewScreenshot(Spectacle::CaptureMode theCaptureMode, | ||
196 | int theTimeout, | 225 | int theTimeout, | ||
197 | bool theIncludePointer, | 226 | bool theIncludePointer, | ||
198 | bool theIncludeDecorations) | 227 | bool theIncludeDecorations) | ||
199 | { | 228 | { | ||
200 | ExportManager::instance()->setCaptureMode(theCaptureMode); | 229 | ExportManager::instance()->setCaptureMode(theCaptureMode); | ||
201 | auto lGrabMode = toPlatformGrabMode(theCaptureMode); | 230 | auto lGrabMode = toPlatformGrabMode(theCaptureMode); | ||
202 | 231 | | |||
203 | if (theTimeout < 0) { | 232 | if (theTimeout < 0 || !mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::Immediate)) { | ||
204 | mPlatform->doGrab(Platform::ShutterMode::OnClick, lGrabMode, theIncludePointer, theIncludeDecorations); | 233 | mPlatform->doGrab(Platform::ShutterMode::OnClick, lGrabMode, theIncludePointer, theIncludeDecorations); | ||
205 | return; | 234 | return; | ||
206 | } | 235 | } | ||
207 | 236 | | |||
208 | // when compositing is enabled, we need to give it enough time for the window | 237 | // when compositing is enabled, we need to give it enough time for the window | ||
209 | // to disappear and all the effects are complete before we take the shot. there's | 238 | // to disappear and all the effects are complete before we take the shot. there's | ||
210 | // no way of knowing how long the disappearing effects take, but as per default | 239 | // no way of knowing how long the disappearing effects take, but as per default | ||
211 | // settings (and unless the user has set an extremely slow effect), 200 | 240 | // settings (and unless the user has set an extremely slow effect), 200 | ||
Show All 36 Lines | 259 | { | |||
248 | 277 | | |||
249 | lExportManager->setPixmap(thePixmap); | 278 | lExportManager->setPixmap(thePixmap); | ||
250 | lExportManager->updatePixmapTimestamp(); | 279 | lExportManager->updatePixmapTimestamp(); | ||
251 | 280 | | |||
252 | switch (mStartMode) { | 281 | switch (mStartMode) { | ||
253 | case StartMode::Background: | 282 | case StartMode::Background: | ||
254 | case StartMode::DBus: | 283 | case StartMode::DBus: | ||
255 | { | 284 | { | ||
256 | if (mNotify) { | | |||
257 | connect(lExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doNotify); | | |||
258 | } | | |||
259 | | ||||
260 | if (mCopyToClipboard) { | 285 | if (mCopyToClipboard) { | ||
261 | lExportManager->doCopyToClipboard(mNotify); | 286 | lExportManager->doCopyToClipboard(mNotify); | ||
262 | } else { | 287 | } else { | ||
263 | QUrl lSavePath = (mStartMode == StartMode::Background && mFileNameUrl.isValid() && mFileNameUrl.isLocalFile()) ? | 288 | QUrl lSavePath = (mStartMode == StartMode::Background && mFileNameUrl.isValid() && mFileNameUrl.isLocalFile()) ? | ||
264 | mFileNameUrl : QUrl(); | 289 | mFileNameUrl : QUrl(); | ||
265 | lExportManager->doSave(lSavePath); | 290 | lExportManager->doSave(lSavePath, mNotify); | ||
266 | } | 291 | } | ||
267 | 292 | | |||
293 | // if we don't have a Gui already opened, emit allDone | ||||
294 | if (!this->mIsGuiInited) { | ||||
268 | // if we notify, we emit allDone only if the user either dismissed the notification or pressed | 295 | // if we notify, we emit allDone only if the user either dismissed the notification or pressed | ||
269 | // the "Open" button, otherwise the app closes before it can react to it. | 296 | // the "Open" button, otherwise the app closes before it can react to it. | ||
270 | if (!mNotify && mCopyToClipboard) { | 297 | if (!mNotify && mCopyToClipboard) { | ||
271 | // Allow some time for clipboard content to transfer if '--nonotify' is used, see Bug #411263 | 298 | // Allow some time for clipboard content to transfer if '--nonotify' is used, see Bug #411263 | ||
272 | // TODO: Find better solution | 299 | // TODO: Find better solution | ||
273 | QTimer::singleShot(250, this, &SpectacleCore::allDone); | 300 | QTimer::singleShot(250, this, &SpectacleCore::allDone); | ||
274 | } else if (!mNotify) { | 301 | } else if (!mNotify) { | ||
275 | emit allDone(); | 302 | emit allDone(); | ||
276 | } | 303 | } | ||
277 | } | 304 | } | ||
305 | } | ||||
278 | break; | 306 | break; | ||
279 | case StartMode::Gui: | 307 | case StartMode::Gui: | ||
280 | mMainWindow->setScreenshotAndShow(thePixmap); | 308 | mMainWindow->setScreenshotAndShow(thePixmap); | ||
281 | 309 | | |||
282 | bool autoSaveImage = Settings::autoSaveImage(); | 310 | bool autoSaveImage = Settings::autoSaveImage(); | ||
283 | bool copyImageToClipboard = Settings::copyImageToClipboard(); | 311 | mCopyImageToClipboard = Settings::copyImageToClipboard(); | ||
284 | 312 | | |||
285 | if (autoSaveImage && copyImageToClipboard) { | 313 | if (autoSaveImage && mCopyImageToClipboard) { | ||
286 | lExportManager->doSaveAndCopy(); | 314 | lExportManager->doSaveAndCopy(); | ||
287 | } else if (autoSaveImage) { | 315 | } else if (autoSaveImage) { | ||
288 | lExportManager->doSave(); | 316 | lExportManager->doSave(); | ||
289 | } else if (copyImageToClipboard) { | 317 | } else if (mCopyImageToClipboard) { | ||
290 | lExportManager->doCopyToClipboard(false); | 318 | lExportManager->doCopyToClipboard(false); | ||
291 | } | 319 | } | ||
292 | } | 320 | } | ||
293 | } | 321 | } | ||
294 | 322 | | |||
295 | void SpectacleCore::screenshotFailed() | 323 | void SpectacleCore::screenshotFailed() | ||
296 | { | 324 | { | ||
297 | if (ExportManager::instance()->captureMode() == Spectacle::CaptureMode::RectangularRegion && mQuickEditor) { | 325 | if (ExportManager::instance()->captureMode() == Spectacle::CaptureMode::RectangularRegion && mQuickEditor) { | ||
Show All 35 Lines | 359 | case Spectacle::CaptureMode::TransientWithParent: | |||
333 | break; | 361 | break; | ||
334 | case Spectacle::CaptureMode::RectangularRegion: | 362 | case Spectacle::CaptureMode::RectangularRegion: | ||
335 | lNotify->setTitle(i18nc("A rectangular region was captured, heading", "Rectangular Region Captured")); | 363 | lNotify->setTitle(i18nc("A rectangular region was captured, heading", "Rectangular Region Captured")); | ||
336 | break; | 364 | break; | ||
337 | case Spectacle::CaptureMode::InvalidChoice: | 365 | case Spectacle::CaptureMode::InvalidChoice: | ||
338 | break; | 366 | break; | ||
339 | } | 367 | } | ||
340 | 368 | | |||
369 | lNotify->setPixmap(ExportManager::instance()->pixmap()); | ||||
370 | | ||||
341 | // a speaking message is prettier than a URL, special case for copy to clipboard and the default pictures location | 371 | // a speaking message is prettier than a URL, special case for copy to clipboard and the default pictures location | ||
342 | const QString &lSavePath = theSavedAt.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path(); | 372 | const QString &lSavePath = theSavedAt.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path(); | ||
343 | if (mCopyToClipboard) { | 373 | if (mCopyToClipboard) { | ||
344 | lNotify->setText(i18n("A screenshot was saved to your clipboard.")); | 374 | lNotify->setText(i18n("A screenshot was saved to your clipboard.")); | ||
345 | } else if (lSavePath == QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)) { | 375 | } else if (lSavePath == QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)) { | ||
346 | lNotify->setText(i18nc("Placeholder is filename", "A screenshot was saved as '%1' to your Pictures folder.", theSavedAt.fileName())); | 376 | lNotify->setText(i18nc("Placeholder is filename", "A screenshot was saved as '%1' to your Pictures folder.", theSavedAt.fileName())); | ||
347 | } else { | 377 | } else { | ||
348 | lNotify->setText(i18n("A screenshot was saved as '%1' to '%2'.", theSavedAt.fileName(), lSavePath)); | 378 | lNotify->setText(i18n("A screenshot was saved as '%1' to '%2'.", theSavedAt.fileName(), lSavePath)); | ||
349 | } | 379 | } | ||
350 | 380 | | |||
351 | if (!mCopyToClipboard) { | 381 | if (!mCopyToClipboard) { | ||
352 | lNotify->setUrls({theSavedAt}); | 382 | lNotify->setUrls({theSavedAt}); | ||
353 | lNotify->setDefaultAction(i18nc("Open the screenshot we just saved", "Open")); | 383 | lNotify->setDefaultAction(i18nc("Open the screenshot we just saved", "Open")); | ||
354 | connect(lNotify, QOverload<uint>::of(&KNotification::activated), this, [this, theSavedAt](uint index) { | 384 | connect(lNotify, QOverload<uint>::of(&KNotification::activated), this, [this, theSavedAt](uint index) { | ||
355 | if (index == 0) { | 385 | if (index == 0) { | ||
356 | new KRun(theSavedAt, nullptr); | 386 | new KRun(theSavedAt, nullptr); | ||
357 | QTimer::singleShot(250, this, [this] { | 387 | QTimer::singleShot(250, this, [this] { | ||
358 | if (mStartMode != StartMode::Gui || Settings::quitAfterSaveCopyExport()) { | 388 | if (!mIsGuiInited || Settings::quitAfterSaveCopyExport()) { | ||
359 | emit allDone(); | 389 | emit allDone(); | ||
360 | } | 390 | } | ||
361 | }); | 391 | }); | ||
362 | } | 392 | } | ||
363 | }); | 393 | }); | ||
364 | } | 394 | } | ||
365 | 395 | | |||
366 | connect(lNotify, &QObject::destroyed, this, [this] { | 396 | connect(lNotify, &QObject::destroyed, this, [this] { | ||
367 | if (mStartMode != StartMode::Gui || Settings::quitAfterSaveCopyExport()) { | 397 | if (!mIsGuiInited || Settings::quitAfterSaveCopyExport()) { | ||
368 | emit allDone(); | 398 | emit allDone(); | ||
369 | } | 399 | } | ||
370 | }); | 400 | }); | ||
371 | 401 | | |||
372 | lNotify->sendEvent(); | 402 | lNotify->sendEvent(); | ||
373 | } | 403 | } | ||
374 | 404 | | |||
375 | void SpectacleCore::doCopyPath(const QUrl &savedAt) | 405 | void SpectacleCore::doCopyPath(const QUrl &savedAt) | ||
376 | { | 406 | { | ||
377 | if (Settings::copySaveLocation()) { | 407 | if (Settings::copySaveLocation()) { | ||
378 | qApp->clipboard()->setText(savedAt.toLocalFile()); | 408 | qApp->clipboard()->setText(savedAt.toLocalFile()); | ||
379 | } | 409 | } | ||
380 | } | 410 | } | ||
381 | 411 | | |||
412 | void SpectacleCore::populateCommandLineParser(QCommandLineParser *lCmdLineParser) | ||||
413 | { | ||||
414 | lCmdLineParser->addOptions({ | ||||
415 | {{QStringLiteral("f"), QStringLiteral("fullscreen")}, i18n("Capture the entire desktop (default)")}, | ||||
416 | {{QStringLiteral("m"), QStringLiteral("current")}, i18n("Capture the current monitor")}, | ||||
417 | {{QStringLiteral("a"), QStringLiteral("activewindow")}, i18n("Capture the active window")}, | ||||
418 | {{QStringLiteral("u"), QStringLiteral("windowundercursor")}, i18n("Capture the window currently under the cursor, including parents of pop-up menus")}, | ||||
419 | {{QStringLiteral("t"), QStringLiteral("transientonly")}, i18n("Capture the window currently under the cursor, excluding parents of pop-up menus")}, | ||||
420 | {{QStringLiteral("r"), QStringLiteral("region")}, i18n("Capture a rectangular region of the screen")}, | ||||
421 | {{QStringLiteral("g"), QStringLiteral("gui")}, i18n("Start in GUI mode (default)")}, | ||||
422 | {{QStringLiteral("b"), QStringLiteral("background")}, i18n("Take a screenshot and exit without showing the GUI")}, | ||||
423 | {{QStringLiteral("s"), QStringLiteral("dbus")}, i18n("Start in DBus-Activation mode")}, | ||||
424 | {{QStringLiteral("n"), QStringLiteral("nonotify")}, i18n("In background mode, do not pop up a notification when the screenshot is taken")}, | ||||
425 | {{QStringLiteral("o"), QStringLiteral("output")}, i18n("In background mode, save image to specified file"), QStringLiteral("fileName")}, | ||||
426 | {{QStringLiteral("d"), QStringLiteral("delay")}, i18n("In background mode, delay before taking the shot (in milliseconds)"), QStringLiteral("delayMsec")}, | ||||
427 | {{QStringLiteral("c"), QStringLiteral("clipboard")}, i18n("In background mode, copy screenshot to clipboard")}, | ||||
428 | {{QStringLiteral("w"), QStringLiteral("onclick")}, i18n("Wait for a click before taking screenshot. Invalidates delay")} | ||||
429 | }); | ||||
430 | } | ||||
431 | | ||||
382 | void SpectacleCore::doStartDragAndDrop() | 432 | void SpectacleCore::doStartDragAndDrop() | ||
383 | { | 433 | { | ||
384 | auto lExportManager = ExportManager::instance(); | 434 | auto lExportManager = ExportManager::instance(); | ||
385 | QUrl lTempFile = lExportManager->tempSave(); | 435 | QUrl lTempFile = lExportManager->tempSave(); | ||
386 | if (!lTempFile.isValid()) { | 436 | if (!lTempFile.isValid()) { | ||
387 | return; | 437 | return; | ||
388 | } | 438 | } | ||
389 | 439 | | |||
Show All 24 Lines | 453 | { | |||
414 | case Spectacle::CaptureMode::ActiveWindow: | 464 | case Spectacle::CaptureMode::ActiveWindow: | ||
415 | return Platform::GrabMode::ActiveWindow; | 465 | return Platform::GrabMode::ActiveWindow; | ||
416 | case Spectacle::CaptureMode::WindowUnderCursor: | 466 | case Spectacle::CaptureMode::WindowUnderCursor: | ||
417 | return Platform::GrabMode::WindowUnderCursor; | 467 | return Platform::GrabMode::WindowUnderCursor; | ||
418 | } | 468 | } | ||
419 | return Platform::GrabMode::InvalidChoice; | 469 | return Platform::GrabMode::InvalidChoice; | ||
420 | } | 470 | } | ||
421 | 471 | | |||
422 | void SpectacleCore::initGui(bool theIncludePointer, bool theIncludeDecorations) | 472 | void SpectacleCore::initGui(int theDelay, bool theIncludePointer, bool theIncludeDecorations) | ||
423 | { | 473 | { | ||
424 | if (!mIsGuiInited) { | 474 | if (!mIsGuiInited) { | ||
425 | mMainWindow = std::make_unique<KSMainWindow>(mPlatform->supportedGrabModes(), mPlatform->supportedShutterModes()); | 475 | mMainWindow = std::make_unique<KSMainWindow>(mPlatform->supportedGrabModes(), mPlatform->supportedShutterModes()); | ||
426 | 476 | | |||
427 | connect(mMainWindow.get(), &KSMainWindow::newScreenshotRequest, this, &SpectacleCore::takeNewScreenshot); | 477 | connect(mMainWindow.get(), &KSMainWindow::newScreenshotRequest, this, &SpectacleCore::takeNewScreenshot); | ||
428 | connect(mMainWindow.get(), &KSMainWindow::dragAndDropRequest, this, &SpectacleCore::doStartDragAndDrop); | 478 | connect(mMainWindow.get(), &KSMainWindow::dragAndDropRequest, this, &SpectacleCore::doStartDragAndDrop); | ||
429 | 479 | | |||
430 | mIsGuiInited = true; | 480 | mIsGuiInited = true; | ||
431 | | ||||
432 | auto lShutterMode = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::Immediate) ? Platform::ShutterMode::Immediate : Platform::ShutterMode::OnClick; | | |||
433 | auto lGrabMode = toPlatformGrabMode(ExportManager::instance()->captureMode()); | | |||
434 | | ||||
435 | QTimer::singleShot(0, this, [this, lShutterMode, lGrabMode, theIncludePointer, theIncludeDecorations]() { | | |||
436 | mPlatform->doGrab(lShutterMode, lGrabMode, theIncludePointer, theIncludeDecorations); | | |||
437 | }); | | |||
438 | } | 481 | } | ||
482 | | ||||
483 | takeNewScreenshot(ExportManager::instance()->captureMode(), theDelay, theIncludePointer, theIncludeDecorations); | ||||
439 | } | 484 | } |
Can you do