Changeset View
Changeset View
Standalone View
Standalone View
src/SpectacleConfig.cpp
Show All 11 Lines | |||||
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. | ||
13 | * | 13 | * | ||
14 | * You should have received a copy of the GNU Lesser General Public License | 14 | * You should have received a copy of the GNU Lesser General Public License | ||
15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, | 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
17 | * Boston, MA 02110-1301, USA. | 17 | * Boston, MA 02110-1301, USA. | ||
18 | */ | 18 | */ | ||
19 | 19 | | |||
20 | #include "Config.h" | ||||
20 | #include "SpectacleConfig.h" | 21 | #include "SpectacleConfig.h" | ||
21 | 22 | | |||
22 | #include <KLocalizedString> | 23 | #include <KLocalizedString> | ||
23 | #include <KWindowSystem> | 24 | #include <KWindowSystem> | ||
24 | 25 | | |||
26 | #include <QPluginLoader> | ||||
27 | #include <QApplication> | ||||
28 | #include <QDir> | ||||
25 | 29 | | |||
30 | #include <QJsonObject> | ||||
31 | #include <QJsonValue> | ||||
32 | #include <QJsonArray> | ||||
33 | | ||||
34 | namespace { | ||||
35 | static QString determinePlatform() { | ||||
36 | QString platform = QString(); | ||||
37 | | ||||
38 | // We might be using the XCB platform (with Xwayland) in a wayland session, | ||||
39 | // but the X11 grabber won't work in that case. So force the Wayland grabber | ||||
40 | // in Wayland sessions. | ||||
41 | if (KWindowSystem::isPlatformWayland() || qstrcmp(qgetenv("XDG_SESSION_TYPE"), "wayland") == 0) { | ||||
42 | platform = QStringLiteral("Wayland"); | ||||
43 | } | ||||
44 | | ||||
45 | // Try checking if we're running under X11 now | ||||
46 | #ifdef XCB_FOUND | ||||
47 | if (KWindowSystem::isPlatformX11()) { | ||||
48 | platform = QStringLiteral("Xcb");; | ||||
49 | } | ||||
50 | #endif | ||||
51 | | ||||
52 | return platform; | ||||
53 | } | ||||
54 | } | ||||
26 | 55 | | |||
27 | SpectacleConfig::SpectacleConfig(QObject *parent) : | 56 | SpectacleConfig::SpectacleConfig(QObject *parent) : | ||
28 | QObject(parent) | 57 | QObject(parent), | ||
58 | mPlatform(determinePlatform()) | ||||
29 | { | 59 | { | ||
30 | mConfig = KSharedConfig::openConfig(QStringLiteral("spectaclerc")); | 60 | mConfig = KSharedConfig::openConfig(QStringLiteral("spectaclerc")); | ||
31 | mGeneralConfig = KConfigGroup(mConfig, "General"); | 61 | mGeneralConfig = KConfigGroup(mConfig, "General"); | ||
32 | mGuiConfig = KConfigGroup(mConfig, "GuiConfig"); | 62 | mGuiConfig = KConfigGroup(mConfig, "GuiConfig"); | ||
33 | 63 | | |||
34 | shortCutActions = new KActionCollection(this); | 64 | shortCutActions = new KActionCollection(this); | ||
35 | 65 | | |||
36 | //everything here is named to match the jumplist actions in our .desktop file | 66 | //everything here is named to match the jumplist actions in our .desktop file | ||
Show All 24 Lines | 89 | { | |||
61 | action->setObjectName(QStringLiteral("ActiveWindowScreenShot")); | 91 | action->setObjectName(QStringLiteral("ActiveWindowScreenShot")); | ||
62 | shortCutActions->addAction(action->objectName(), action); | 92 | shortCutActions->addAction(action->objectName(), action); | ||
63 | } | 93 | } | ||
64 | { | 94 | { | ||
65 | QAction *action = new QAction(i18n("Capture Rectangular Region")); | 95 | QAction *action = new QAction(i18n("Capture Rectangular Region")); | ||
66 | action->setObjectName(QStringLiteral("RectangularRegionScreenShot")); | 96 | action->setObjectName(QStringLiteral("RectangularRegionScreenShot")); | ||
67 | shortCutActions->addAction(action->objectName(), action); | 97 | shortCutActions->addAction(action->objectName(), action); | ||
68 | } | 98 | } | ||
99 | | ||||
100 | findPlugins(); | ||||
101 | selectScreenshotBackend(); | ||||
69 | } | 102 | } | ||
70 | 103 | | |||
71 | SpectacleConfig::~SpectacleConfig() | 104 | SpectacleConfig::~SpectacleConfig() | ||
72 | {} | 105 | {} | ||
73 | 106 | | |||
107 | void SpectacleConfig::findPlugins() { | ||||
108 | QDir pluginsDir { qApp->applicationDirPath() }; | ||||
109 | pluginsDir.cd(QStringLiteral("build/bin")); | ||||
110 | | ||||
111 | // Iterate over all plugins and save their filepath and their metadata in a pair | ||||
112 | const auto entryList = pluginsDir.entryList(QDir::Files); | ||||
113 | for (const QString &fileName : entryList) { | ||||
114 | QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); | ||||
115 | QJsonObject metaData = QJsonObject(loader.metaData())[QStringLiteral("MetaData")].toObject(); | ||||
116 | | ||||
117 | if (metaData[QStringLiteral("Type")].toString() == QStringLiteral("Screenshot Backend")) { | ||||
118 | mScreenshotPlugins.push_back({fileName, metaData, nullptr}); | ||||
119 | } | ||||
120 | } | ||||
121 | | ||||
122 | // Sort plugins after recommendation | ||||
123 | std::sort(mScreenshotPlugins.begin(), mScreenshotPlugins.end(), [](const ScreenshotPlugin &plugin1, const ScreenshotPlugin &plugin2) { | ||||
124 | return plugin1.metaData[QStringLiteral("Recommended")].toInt() > plugin2.metaData[QStringLiteral("Recommended")].toInt(); | ||||
125 | }); | ||||
126 | } | ||||
127 | | ||||
128 | void SpectacleConfig::selectScreenshotBackend() { | ||||
129 | // Find default plugin | ||||
130 | if (findScreenshotBackend(screenshotBackendName())) { | ||||
131 | return; | ||||
132 | } | ||||
133 | | ||||
134 | // Find other suitable plugin | ||||
135 | for(auto& plugin : mScreenshotPlugins) { | ||||
136 | if(!plugin.metaData[QStringLiteral("Platforms")].toArray().contains(mPlatform)) { | ||||
137 | continue; | ||||
138 | } | ||||
139 | | ||||
140 | if(setScreenshotBackend(plugin, nullptr)) { | ||||
141 | break; | ||||
142 | } | ||||
143 | } | ||||
144 | } | ||||
145 | | ||||
146 | bool SpectacleConfig::findScreenshotBackend(const QString& name) { | ||||
147 | //Find old plugin | ||||
148 | auto oldPluginIterator = std::find_if(mScreenshotPlugins.begin(), mScreenshotPlugins.end(), [&name](const ScreenshotPlugin &plugin) { | ||||
149 | return plugin.backend; | ||||
150 | }); | ||||
151 | | ||||
152 | // Find new plugin | ||||
153 | auto newPluginIterator = std::find_if(mScreenshotPlugins.begin(), mScreenshotPlugins.end(), [&name](const ScreenshotPlugin &plugin) { | ||||
154 | return plugin.metaData[QStringLiteral("Name")].toString() == name; | ||||
155 | }); | ||||
156 | | ||||
157 | if(newPluginIterator == mScreenshotPlugins.end()) { | ||||
158 | return false; | ||||
159 | } | ||||
160 | | ||||
161 | if(oldPluginIterator != mScreenshotPlugins.end()) { | ||||
162 | if(setScreenshotBackend(*newPluginIterator, &(*oldPluginIterator))) { | ||||
163 | return true; | ||||
164 | } | ||||
165 | } else { | ||||
166 | if(setScreenshotBackend(*newPluginIterator, nullptr)) { | ||||
167 | return true; | ||||
168 | } | ||||
169 | } | ||||
170 | return false; | ||||
171 | } | ||||
172 | | ||||
173 | //TO DO: std::optional instead of pointer in C++17 | ||||
174 | bool SpectacleConfig::setScreenshotBackend(ScreenshotPlugin& newPlugin, ScreenshotPlugin* oldPlugin) { | ||||
175 | //Check if there is a change | ||||
176 | if(oldPlugin && newPlugin.fileName == (*oldPlugin).fileName) { | ||||
177 | return true; | ||||
178 | } | ||||
179 | | ||||
180 | // Test if plugin can be used (runtime checks) | ||||
181 | QPluginLoader newLoader { newPlugin.fileName }; | ||||
182 | newPlugin.backend = qobject_cast<ScreenshotInterface *>(newLoader.instance()); | ||||
183 | | ||||
184 | if(!newPlugin.backend->requirementsComplied()) { | ||||
185 | newPlugin.backend = nullptr; | ||||
186 | newLoader.unload(); | ||||
187 | return false; | ||||
188 | } | ||||
189 | | ||||
190 | // If there was an old plugin, unload it | ||||
191 | if(oldPlugin) { | ||||
192 | QPluginLoader oldLoader { oldPlugin->fileName }; | ||||
193 | oldLoader.unload(); | ||||
194 | oldPlugin->backend = nullptr; | ||||
195 | } | ||||
196 | | ||||
197 | // Update active screenshot Backend and filename | ||||
198 | setScreenshotBackendName(newPlugin.metaData[QStringLiteral("Name")].toString()); | ||||
199 | emit screenshotBackendChanged(newPlugin.backend); | ||||
200 | return true; | ||||
201 | } | ||||
202 | | ||||
74 | SpectacleConfig* SpectacleConfig::instance() | 203 | SpectacleConfig* SpectacleConfig::instance() | ||
75 | { | 204 | { | ||
76 | static SpectacleConfig instance; | 205 | static SpectacleConfig instance; | ||
77 | return &instance; | 206 | return &instance; | ||
78 | } | 207 | } | ||
79 | 208 | | |||
209 | const QString& SpectacleConfig::platform() const | ||||
210 | { | ||||
211 | return mPlatform; | ||||
212 | } | ||||
213 | | ||||
214 | ScreenshotInterface* SpectacleConfig::screenshotBackend() const | ||||
215 | { | ||||
216 | auto pluginIterator = std::find_if(mScreenshotPlugins.begin(), mScreenshotPlugins.end(), [](const ScreenshotPlugin &plugin) { | ||||
217 | return plugin.backend; | ||||
218 | }); | ||||
219 | | ||||
220 | if(pluginIterator != mScreenshotPlugins.end()) { | ||||
221 | return (*pluginIterator).backend; | ||||
222 | } | ||||
223 | return nullptr; | ||||
224 | } | ||||
225 | | ||||
226 | const std::vector<ScreenshotPlugin>& SpectacleConfig::screenshotPlugins() const { | ||||
227 | return mScreenshotPlugins; | ||||
228 | } | ||||
229 | | ||||
80 | QString SpectacleConfig::defaultFilename() const | 230 | QString SpectacleConfig::defaultFilename() const | ||
81 | { | 231 | { | ||
82 | return QStringLiteral("Screenshot"); | 232 | return QStringLiteral("Screenshot"); | ||
83 | } | 233 | } | ||
84 | 234 | | |||
85 | QString SpectacleConfig::defaultTimestampTemplate() const | 235 | QString SpectacleConfig::defaultTimestampTemplate() const | ||
86 | { | 236 | { | ||
87 | // includes separator at the front | 237 | // includes separator at the front | ||
▲ Show 20 Lines • Show All 292 Lines • ▼ Show 20 Line(s) | |||||
380 | } | 530 | } | ||
381 | 531 | | |||
382 | void SpectacleConfig::setSaveImageFormat(const QString &saveFmt) | 532 | void SpectacleConfig::setSaveImageFormat(const QString &saveFmt) | ||
383 | { | 533 | { | ||
384 | mGeneralConfig.writeEntry(QStringLiteral("default-save-image-format"), saveFmt); | 534 | mGeneralConfig.writeEntry(QStringLiteral("default-save-image-format"), saveFmt); | ||
385 | mGeneralConfig.sync(); | 535 | mGeneralConfig.sync(); | ||
386 | } | 536 | } | ||
387 | 537 | | |||
538 | QString SpectacleConfig::screenshotBackendName() const | ||||
539 | { | ||||
540 | if(mPlatform == QStringLiteral("Xcb")) { | ||||
541 | return screenshotXcbBackendName(); | ||||
542 | } else if(mPlatform == QStringLiteral("Wayland")) { | ||||
543 | return screenshotWaylandBackendName(); | ||||
544 | } | ||||
545 | return QString(); | ||||
546 | } | ||||
547 | | ||||
548 | void SpectacleConfig::setScreenshotBackendName(const QString& name) | ||||
549 | { | ||||
550 | if(mPlatform == QStringLiteral("Xcb")) { | ||||
551 | setScreenshotXcbBackendName(name); | ||||
552 | } else if(mPlatform == QStringLiteral("Wayland")) { | ||||
553 | setScreenshotWaylandBackendName(name); | ||||
554 | } | ||||
555 | } | ||||
556 | | ||||
557 | QString SpectacleConfig::screenshotXcbBackendName() const { | ||||
558 | return mGeneralConfig.readEntry(QStringLiteral("screenshotXcbBackendName"), QString()); | ||||
559 | } | ||||
560 | | ||||
561 | void SpectacleConfig::setScreenshotXcbBackendName(const QString& name) { | ||||
562 | mGeneralConfig.writeEntry(QStringLiteral("screenshotXcbBackendName"), name); | ||||
563 | mGeneralConfig.sync(); | ||||
564 | emit screenshotBackendNameChanged(name); | ||||
565 | } | ||||
566 | | ||||
567 | QString SpectacleConfig::screenshotWaylandBackendName() const { | ||||
568 | return mGeneralConfig.readEntry(QStringLiteral("screenshotWaylandBackendName"), QString()); | ||||
569 | } | ||||
570 | | ||||
571 | void SpectacleConfig::setScreenshotWaylandBackendName(const QString& name) { | ||||
572 | mGeneralConfig.writeEntry(QStringLiteral("screenshotWaylandBackendName"), name); | ||||
573 | mGeneralConfig.sync(); | ||||
574 | emit screenshotBackendNameChanged(name); | ||||
575 | } | ||||
576 | | ||||
388 | SpectacleConfig::PrintKeyActionRunning SpectacleConfig::printKeyActionRunning() const | 577 | SpectacleConfig::PrintKeyActionRunning SpectacleConfig::printKeyActionRunning() const | ||
389 | { | 578 | { | ||
390 | mConfig->reparseConfiguration(); | 579 | mConfig->reparseConfiguration(); | ||
391 | int newScreenshotAction = static_cast<int>(SpectacleConfig::PrintKeyActionRunning::TakeNewScreenshot); | 580 | int newScreenshotAction = static_cast<int>(SpectacleConfig::PrintKeyActionRunning::TakeNewScreenshot); | ||
392 | int readValue = mGuiConfig.readEntry(QStringLiteral("printKeyActionRunning"), newScreenshotAction); | 581 | int readValue = mGuiConfig.readEntry(QStringLiteral("printKeyActionRunning"), newScreenshotAction); | ||
393 | if ((KWindowSystem::isPlatformWayland() || qstrcmp(qgetenv("XDG_SESSION_TYPE"), "wayland") == 0 ) | 582 | if ((KWindowSystem::isPlatformWayland() || qstrcmp(qgetenv("XDG_SESSION_TYPE"), "wayland") == 0 ) | ||
394 | && readValue == SpectacleConfig::PrintKeyActionRunning::FocusWindow) { | 583 | && readValue == SpectacleConfig::PrintKeyActionRunning::FocusWindow) { | ||
395 | return SpectacleConfig::PrintKeyActionRunning::TakeNewScreenshot; | 584 | return SpectacleConfig::PrintKeyActionRunning::TakeNewScreenshot; | ||
Show All 9 Lines |