Changeset View
Changeset View
Standalone View
Standalone View
kcmkwin/kwinrules/main.cpp
Show All 15 Lines | |||||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
17 | */ | 17 | */ | ||
18 | 18 | | |||
19 | #include <QCommandLineParser> | 19 | #include <QCommandLineParser> | ||
20 | #include <QApplication> | 20 | #include <QApplication> | ||
21 | #include <kconfig.h> | 21 | #include <kconfig.h> | ||
22 | #include <KLocalizedString> | 22 | #include <KLocalizedString> | ||
23 | #include <kwindowsystem.h> | 23 | #include <kwindowsystem.h> | ||
24 | #include <QtDBus> | | |||
25 | #include <QX11Info> | | |||
26 | #include <X11/Xlib.h> | | |||
27 | #include <fixx11h.h> | | |||
28 | 24 | | |||
29 | #include "ruleswidget.h" | 25 | #include "ruleswidget.h" | ||
30 | #include "../../rules.h" | 26 | #include "../../rules.h" | ||
31 | #include "../../client_machine.h" | | |||
32 | #include <QByteArray> | 27 | #include <QByteArray> | ||
33 | 28 | | |||
29 | #include <QDBusConnection> | ||||
30 | #include <QDBusMessage> | ||||
31 | #include <QDBusPendingCallWatcher> | ||||
32 | #include <QDBusPendingReply> | ||||
33 | #include <QUuid> | ||||
34 | | ||||
35 | Q_DECLARE_METATYPE(NET::WindowType) | ||||
36 | | ||||
34 | namespace KWin | 37 | namespace KWin | ||
35 | { | 38 | { | ||
36 | 39 | | |||
37 | static void loadRules(QList< Rules* >& rules) | 40 | static void loadRules(QList< Rules* >& rules) | ||
38 | { | 41 | { | ||
39 | KConfig _cfg("kwinrulesrc", KConfig::NoGlobals); | 42 | KConfig _cfg("kwinrulesrc", KConfig::NoGlobals); | ||
40 | KConfigGroup cfg(&_cfg, "General"); | 43 | KConfigGroup cfg(&_cfg, "General"); | ||
41 | int count = cfg.readEntry("count", 0); | 44 | int count = cfg.readEntry("count", 0); | ||
Show All 20 Lines | 64 | for (QList< Rules* >::ConstIterator it = rules.constBegin(); | |||
62 | it != rules.constEnd(); | 65 | it != rules.constEnd(); | ||
63 | ++it) { | 66 | ++it) { | ||
64 | KConfigGroup cg(&cfg, QString::number(i)); | 67 | KConfigGroup cg(&cfg, QString::number(i)); | ||
65 | (*it)->write(cg); | 68 | (*it)->write(cg); | ||
66 | ++i; | 69 | ++i; | ||
67 | } | 70 | } | ||
68 | } | 71 | } | ||
69 | 72 | | |||
70 | static Rules* findRule(const QList< Rules* >& rules, Window wid, bool whole_app) | 73 | static Rules* findRule(const QList< Rules* >& rules, const QVariantMap &data, bool whole_app) | ||
71 | { | 74 | { | ||
72 | // ClientMachine::resolve calls NETWinInfo::update() which requires properties | 75 | QByteArray wmclass_class = data.value("resourceClass").toByteArray().toLower(); | ||
73 | // bug #348472 ./. bug #346748 | 76 | QByteArray wmclass_name = data.value("resourceName").toByteArray().toLower(); | ||
74 | if (QX11Info::isPlatformX11()) { | 77 | QByteArray role = data.value("role").toByteArray().toLower(); | ||
75 | qApp->setProperty("x11Connection", QVariant::fromValue<void*>(QX11Info::connection())); | 78 | NET::WindowType type = data.value("type").value<NET::WindowType>(); | ||
76 | qApp->setProperty("x11RootWindow", QVariant::fromValue(QX11Info::appRootWindow())); | 79 | QString title = data.value("caption").toString(); | ||
77 | } | 80 | QByteArray machine = data.value("clientMachine").toByteArray(); | ||
78 | KWindowInfo info = KWindowInfo(wid, | | |||
79 | NET::WMName | NET::WMWindowType, | | |||
80 | NET::WM2WindowClass | NET::WM2WindowRole | NET::WM2ClientMachine); | | |||
81 | if (!info.valid()) // shouldn't really happen | | |||
82 | return nullptr; | | |||
83 | ClientMachine clientMachine; | | |||
84 | clientMachine.resolve(info.win(), info.groupLeader()); | | |||
85 | QByteArray wmclass_class = info.windowClassClass().toLower(); | | |||
86 | QByteArray wmclass_name = info.windowClassName().toLower(); | | |||
87 | QByteArray role = info.windowRole().toLower(); | | |||
88 | NET::WindowType type = info.windowType(NET::NormalMask | NET::DesktopMask | NET::DockMask | | |||
89 | | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask | | |||
90 | | NET::UtilityMask | NET::SplashMask); | | |||
91 | QString title = info.name(); | | |||
92 | QByteArray machine = clientMachine.hostName(); | | |||
93 | Rules* best_match = nullptr; | 81 | Rules* best_match = nullptr; | ||
zzag: Shouldn't these ones call toLower()? | |||||
94 | int match_quality = 0; | 82 | int match_quality = 0; | ||
95 | for (QList< Rules* >::ConstIterator it = rules.constBegin(); | 83 | for (QList< Rules* >::ConstIterator it = rules.constBegin(); | ||
96 | it != rules.constEnd(); | 84 | it != rules.constEnd(); | ||
97 | ++it) { | 85 | ++it) { | ||
98 | // try to find an exact match, i.e. not a generic rule | 86 | // try to find an exact match, i.e. not a generic rule | ||
99 | Rules* rule = *it; | 87 | Rules* rule = *it; | ||
100 | int quality = 0; | 88 | int quality = 0; | ||
101 | bool generic = true; | 89 | bool generic = true; | ||
Show All 29 Lines | 118 | if (generic) // ignore generic rules, use only the ones that are for this window | |||
131 | continue; | 119 | continue; | ||
132 | } else { | 120 | } else { | ||
133 | if (rule->types == NET::AllTypesMask) | 121 | if (rule->types == NET::AllTypesMask) | ||
134 | quality += 2; | 122 | quality += 2; | ||
135 | } | 123 | } | ||
136 | if (!rule->matchType(type) | 124 | if (!rule->matchType(type) | ||
137 | || !rule->matchRole(role) | 125 | || !rule->matchRole(role) | ||
138 | || !rule->matchTitle(title) | 126 | || !rule->matchTitle(title) | ||
139 | || !rule->matchClientMachine(machine, clientMachine.isLocal())) | 127 | || !rule->matchClientMachine(machine, data.value("localhost").toBool())) | ||
140 | continue; | 128 | continue; | ||
141 | if (quality > match_quality) { | 129 | if (quality > match_quality) { | ||
142 | best_match = rule; | 130 | best_match = rule; | ||
143 | match_quality = quality; | 131 | match_quality = quality; | ||
144 | } | 132 | } | ||
145 | } | 133 | } | ||
146 | if (best_match != nullptr) | 134 | if (best_match != nullptr) | ||
147 | return best_match; | 135 | return best_match; | ||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Line(s) | 186 | } else { | |||
207 | ret->wmclasscomplete = false; | 195 | ret->wmclasscomplete = false; | ||
208 | ret->wmclass = wmclass_class; | 196 | ret->wmclass = wmclass_class; | ||
209 | ret->wmclassmatch = Rules::ExactMatch; | 197 | ret->wmclassmatch = Rules::ExactMatch; | ||
210 | } | 198 | } | ||
211 | } | 199 | } | ||
212 | return ret; | 200 | return ret; | ||
213 | } | 201 | } | ||
214 | 202 | | |||
215 | static int edit(Window wid, bool whole_app) | 203 | static void edit(const QVariantMap &data, bool whole_app) | ||
216 | { | 204 | { | ||
217 | QList< Rules* > rules; | 205 | QList< Rules* > rules; | ||
218 | loadRules(rules); | 206 | loadRules(rules); | ||
219 | Rules* orig_rule = findRule(rules, wid, whole_app); | 207 | Rules* orig_rule = findRule(rules, data, whole_app); | ||
220 | RulesDialog dlg; | 208 | RulesDialog dlg; | ||
221 | if (whole_app) | 209 | if (whole_app) | ||
222 | dlg.setWindowTitle(i18nc("Window caption for the application wide rules dialog", "Edit Application-Specific Settings")); | 210 | dlg.setWindowTitle(i18nc("Window caption for the application wide rules dialog", "Edit Application-Specific Settings")); | ||
223 | // dlg.edit() creates new Rules instance if edited | 211 | // dlg.edit() creates new Rules instance if edited | ||
224 | Rules* edited_rule = dlg.edit(orig_rule, wid, true); | 212 | Rules* edited_rule = dlg.edit(orig_rule, data, true); | ||
225 | if (edited_rule == nullptr || edited_rule->isEmpty()) { | 213 | if (edited_rule == nullptr || edited_rule->isEmpty()) { | ||
226 | rules.removeAll(orig_rule); | 214 | rules.removeAll(orig_rule); | ||
227 | delete orig_rule; | 215 | delete orig_rule; | ||
228 | if (orig_rule != edited_rule) | 216 | if (orig_rule != edited_rule) | ||
229 | delete edited_rule; | 217 | delete edited_rule; | ||
230 | } else if (edited_rule != orig_rule) { | 218 | } else if (edited_rule != orig_rule) { | ||
231 | int pos = rules.indexOf(orig_rule); | 219 | int pos = rules.indexOf(orig_rule); | ||
232 | if (pos != -1) | 220 | if (pos != -1) | ||
233 | rules[ pos ] = edited_rule; | 221 | rules[ pos ] = edited_rule; | ||
234 | else | 222 | else | ||
235 | rules.prepend(edited_rule); | 223 | rules.prepend(edited_rule); | ||
236 | delete orig_rule; | 224 | delete orig_rule; | ||
237 | } | 225 | } | ||
238 | saveRules(rules); | 226 | saveRules(rules); | ||
239 | // Send signal to all kwin instances | 227 | // Send signal to all kwin instances | ||
240 | QDBusMessage message = | 228 | QDBusMessage message = | ||
241 | QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); | 229 | QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); | ||
242 | QDBusConnection::sessionBus().send(message); | 230 | QDBusConnection::sessionBus().send(message); | ||
243 | return 0; | 231 | qApp->quit(); | ||
244 | } | 232 | } | ||
245 | 233 | | |||
246 | } // namespace | 234 | } // namespace | ||
247 | 235 | | |||
248 | extern "C" | 236 | extern "C" | ||
249 | KWIN_EXPORT int kdemain(int argc, char* argv[]) | 237 | KWIN_EXPORT int kdemain(int argc, char* argv[]) | ||
250 | { | 238 | { | ||
251 | qputenv("QT_QPA_PLATFORM", "xcb"); | | |||
252 | QApplication app(argc, argv); | 239 | QApplication app(argc, argv); | ||
253 | app.setApplicationDisplayName(i18n("KWin")); | 240 | app.setApplicationDisplayName(i18n("KWin")); | ||
254 | app.setApplicationName("kwin_rules_dialog"); | 241 | app.setApplicationName("kwin_rules_dialog"); | ||
255 | app.setApplicationVersion("1.0"); | 242 | app.setApplicationVersion("1.0"); | ||
256 | bool whole_app = false; | 243 | bool whole_app = false; | ||
257 | bool id_ok = false; | 244 | QUuid uuid; | ||
258 | Window id = None; | | |||
259 | { | 245 | { | ||
260 | QCommandLineParser parser; | 246 | QCommandLineParser parser; | ||
261 | parser.setApplicationDescription(i18n("KWin helper utility")); | 247 | parser.setApplicationDescription(i18n("KWin helper utility")); | ||
262 | parser.addOption(QCommandLineOption("wid", i18n("WId of the window for special window settings."), "wid")); | 248 | parser.addOption(QCommandLineOption("uuid", i18n("KWin id of the window for special window settings."), "uuid")); | ||
263 | parser.addOption(QCommandLineOption("whole-app", i18n("Whether the settings should affect all windows of the application."))); | 249 | parser.addOption(QCommandLineOption("whole-app", i18n("Whether the settings should affect all windows of the application."))); | ||
264 | parser.process(app); | 250 | parser.process(app); | ||
265 | 251 | | |||
266 | id = parser.value("wid").toULongLong(&id_ok); | 252 | uuid = QUuid::fromString(parser.value("uuid")); | ||
267 | whole_app = parser.isSet("whole-app"); | 253 | whole_app = parser.isSet("whole-app"); | ||
268 | } | 254 | } | ||
269 | 255 | | |||
270 | if (!id_ok || id == None) { | 256 | | ||
257 | if (uuid.isNull()) { | ||||
271 | printf("%s\n", qPrintable(i18n("This helper utility is not supposed to be called directly."))); | 258 | printf("%s\n", qPrintable(i18n("This helper utility is not supposed to be called directly."))); | ||
272 | return 1; | 259 | return 1; | ||
273 | } | 260 | } | ||
274 | return KWin::edit(id, whole_app); | 261 | QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"), | ||
262 | QStringLiteral("/KWin"), | ||||
263 | QStringLiteral("org.kde.KWin"), | ||||
264 | QStringLiteral("getWindowInfo")); | ||||
265 | message.setArguments({uuid.toString()}); | ||||
266 | QDBusPendingReply<QVariantMap> async = QDBusConnection::sessionBus().asyncCall(message); | ||||
267 | | ||||
268 | QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, &app); | ||||
269 | QObject::connect(callWatcher, &QDBusPendingCallWatcher::finished, &app, | ||||
270 | [&whole_app] (QDBusPendingCallWatcher *self) { | ||||
271 | QDBusPendingReply<QVariantMap> reply = *self; | ||||
272 | self->deleteLater(); | ||||
273 | if (!reply.isValid() || reply.value().isEmpty()) { | ||||
274 | qApp->quit(); | ||||
275 | return; | ||||
276 | } | ||||
277 | KWin::edit(reply.value(), whole_app); | ||||
278 | } | ||||
279 | ); | ||||
280 | | ||||
281 | | ||||
282 | | ||||
zzag: One empty line would be enough. :-) | |||||
283 | return app.exec(); | ||||
275 | } | 284 | } |
Shouldn't these ones call toLower()?