diff --git a/dbusinterface.cpp b/dbusinterface.cpp
index 8aaaa32ed8..ea5f5955da 100644
--- a/dbusinterface.cpp
+++ b/dbusinterface.cpp
@@ -23,6 +23,7 @@ along with this program. If not, see .
#include "compositingadaptor.h"
// kwin
+#include "abstract_client.h"
#include "atoms.h"
#include "composite.h"
#include "debug_console.h"
@@ -187,6 +188,46 @@ void DBusInterface::showDebugConsole()
console->show();
}
+QVariantMap DBusInterface::queryWindowInfo()
+{
+ m_replyQueryWindowInfo = message();
+ setDelayedReply(true);
+ kwinApp()->platform()->startInteractiveWindowSelection(
+ [this] (Toplevel *t) {
+ if (auto c = qobject_cast(t)) {
+ const QVariantMap ret{
+ {QStringLiteral("resourceClass"), c->resourceClass()},
+ {QStringLiteral("resourceName"), c->resourceName()},
+ {QStringLiteral("role"), c->windowRole()},
+ {QStringLiteral("caption"), c->captionNormal()},
+ {QStringLiteral("clientMachine"), c->wmClientMachine(true)},
+ {QStringLiteral("type"), c->windowType()},
+ {QStringLiteral("x"), c->x()},
+ {QStringLiteral("y"), c->y()},
+ {QStringLiteral("width"), c->width()},
+ {QStringLiteral("height"), c->height()},
+ {QStringLiteral("x11DesktopNumber"), c->desktop()},
+ {QStringLiteral("minimized"), c->isMinimized()},
+ {QStringLiteral("shaded"), c->isShade()},
+ {QStringLiteral("fullscreen"), c->isFullScreen()},
+ {QStringLiteral("keepAbove"), c->keepAbove()},
+ {QStringLiteral("keepBelow"), c->keepBelow()},
+ {QStringLiteral("noBorder"), c->noBorder()},
+ {QStringLiteral("skipTaskbar"), c->skipTaskbar()},
+ {QStringLiteral("skipPager"), c->skipPager()},
+ {QStringLiteral("skipSwitcher"), c->skipSwitcher()},
+ {QStringLiteral("maximizeHorizontal"), c->maximizeMode() & MaximizeHorizontal},
+ {QStringLiteral("maximizeVertical"), c->maximizeMode() & MaximizeVertical}
+ };
+ QDBusConnection::sessionBus().send(m_replyQueryWindowInfo.createReply(ret));
+ } else {
+ QDBusConnection::sessionBus().send(m_replyQueryWindowInfo.createErrorReply(QString(), QString()));
+ }
+ }
+ );
+ return QVariantMap{};
+}
+
CompositorDBusInterface::CompositorDBusInterface(Compositor *parent)
: QObject(parent)
, m_compositor(parent)
diff --git a/dbusinterface.h b/dbusinterface.h
index 5781a28e89..489030acbf 100644
--- a/dbusinterface.h
+++ b/dbusinterface.h
@@ -43,7 +43,7 @@ class Compositor;
*
* @author Martin Gräßlin
**/
-class DBusInterface: public QObject
+class DBusInterface: public QObject, protected QDBusContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.KWin")
@@ -66,12 +66,15 @@ public Q_SLOTS: // METHODS
Q_NOREPLY void unclutterDesktop();
Q_NOREPLY void showDebugConsole();
+ QVariantMap queryWindowInfo();
+
private Q_SLOTS:
void becomeKWinService(const QString &service);
private:
void announceService();
QString m_serviceName;
+ QDBusMessage m_replyQueryWindowInfo;
};
class CompositorDBusInterface : public QObject
diff --git a/kcmkwin/kwinrules/CMakeLists.txt b/kcmkwin/kwinrules/CMakeLists.txt
index fbe3e6d21b..b53f7b5f51 100644
--- a/kcmkwin/kwinrules/CMakeLists.txt
+++ b/kcmkwin/kwinrules/CMakeLists.txt
@@ -29,7 +29,6 @@ set(kcm_libs
KF5::Service
KF5::WindowSystem
KF5::XmlGui
- ${X11_LIBRARIES}
)
if(KWIN_BUILD_ACTIVITIES)
diff --git a/kcmkwin/kwinrules/detectwidget.cpp b/kcmkwin/kwinrules/detectwidget.cpp
index 2e0cfa3964..db00184e7b 100644
--- a/kcmkwin/kwinrules/detectwidget.cpp
+++ b/kcmkwin/kwinrules/detectwidget.cpp
@@ -31,11 +31,12 @@
#include
#include
-#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+
+Q_DECLARE_METATYPE(NET::WindowType)
namespace KWin
{
@@ -47,8 +48,7 @@ DetectWidget::DetectWidget(QWidget* parent)
}
DetectDialog::DetectDialog(QWidget* parent, const char* name)
- : QDialog(parent),
- grabber()
+ : QDialog(parent)
{
setObjectName(name);
setModal(true);
@@ -64,34 +64,9 @@ DetectDialog::DetectDialog(QWidget* parent, const char* name)
connect(buttons, SIGNAL(rejected()), SLOT(reject()));
}
-void DetectDialog::detect(WId window, int secs)
+void DetectDialog::detect(int secs)
{
- if (window == 0)
- QTimer::singleShot(secs*1000, this, SLOT(selectWindow()));
- else
- readWindow(window);
-}
-
-void DetectDialog::readWindow(WId w)
-{
- if (w == 0) {
- emit detectionDone(false);
- return;
- }
- info.reset(new KWindowInfo(w, NET::WMAllProperties, NET::WM2AllProperties)); // read everything
- if (!info->valid()) {
- emit detectionDone(false);
- return;
- }
- wmclass_class = info->windowClassClass();
- wmclass_name = info->windowClassName();
- role = info->windowRole();
- type = info->windowType(NET::NormalMask | NET::DesktopMask | NET::DockMask
- | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask
- | NET::UtilityMask | NET::SplashMask);
- title = info->name();
- machine = info->clientMachine();
- executeDialog();
+ QTimer::singleShot(secs*1000, this, SLOT(selectWindow()));
}
void DetectDialog::executeDialog()
@@ -170,79 +145,31 @@ QByteArray DetectDialog::selectedMachine() const
void DetectDialog::selectWindow()
{
- if (!KWin::Cursor::self()) {
- qApp->setProperty("x11Connection", QVariant::fromValue(QX11Info::connection()));
- qApp->setProperty("x11RootWindow", QVariant::fromValue(QX11Info::appRootWindow()));
- new X11Cursor(this);
- }
- // use a dialog, so that all user input is blocked
- // use WX11BypassWM and moving away so that it's not actually visible
- // grab only mouse, so that keyboard can be used e.g. for switching windows
- grabber.reset(new QDialog(nullptr, Qt::X11BypassWindowManagerHint));
- grabber->move(-1000, -1000);
- grabber->setModal(true);
- grabber->show();
- // Qt uses QX11Info::appTime() to grab the pointer, what can silently fail (#318437) ...
- XSync(QX11Info::display(), false);
- if (XGrabPointer(QX11Info::display(), grabber->winId(), false, ButtonReleaseMask,
- GrabModeAsync, GrabModeAsync, None, KWin::Cursor::x11Cursor(Qt::CrossCursor),
- CurrentTime) == Success) { // ...so we use the far more convincing CurrentTime
- QCoreApplication::instance()->installNativeEventFilter(this);
- } else {
- // ... and if we fail, cleanup, so we won't receive random events
- grabber.reset();
- }
-}
+ QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"),
+ QStringLiteral("/KWin"),
+ QStringLiteral("org.kde.KWin"),
+ QStringLiteral("queryWindowInfo"));
+ QDBusPendingReply async = QDBusConnection::sessionBus().asyncCall(message);
-bool DetectDialog::nativeEventFilter(const QByteArray &eventType, void *message, long int*)
-{
- if (eventType != QByteArrayLiteral("xcb_generic_event_t")) {
- return false;
- }
- auto *event = reinterpret_cast(message);
- if ((event->response_type & ~0x80) != XCB_BUTTON_RELEASE) {
- return false;
- }
- QCoreApplication::instance()->removeNativeEventFilter(this);
- grabber.reset();
- auto *me = reinterpret_cast(event);
- if (me->detail != XCB_BUTTON_INDEX_1) {
- emit detectionDone(false);
- return true;
- }
- readWindow(findWindow());
- return true;
-}
-
-WId DetectDialog::findWindow()
-{
- Window root;
- Window child;
- uint mask;
- int rootX, rootY, x, y;
- Window parent = QX11Info::appRootWindow();
- Atom wm_state = XInternAtom(QX11Info::display(), "WM_STATE", False);
- for (int i = 0;
- i < 10;
- ++i) {
- XQueryPointer(QX11Info::display(), parent, &root, &child,
- &rootX, &rootY, &x, &y, &mask);
- if (child == None)
- return 0;
- Atom type;
- int format;
- unsigned long nitems, after;
- unsigned char* prop;
- if (XGetWindowProperty(QX11Info::display(), child, wm_state, 0, 0, False, AnyPropertyType,
- &type, &format, &nitems, &after, &prop) == Success) {
- if (prop != nullptr)
- XFree(prop);
- if (type != None)
- return child;
+ QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, this);
+ connect(callWatcher, &QDBusPendingCallWatcher::finished, this,
+ [this](QDBusPendingCallWatcher *self) {
+ QDBusPendingReply reply = *self;
+ self->deleteLater();
+ if (!reply.isValid()) {
+ emit detectionDone(false);
+ return;
+ }
+ m_windowInfo = reply.value();
+ wmclass_class = m_windowInfo.value("resourceClass").toByteArray();
+ wmclass_name = m_windowInfo.value("resourceName").toByteArray();
+ role = m_windowInfo.value("role").toByteArray();
+ type = m_windowInfo.value("type").value();
+ title = m_windowInfo.value("caption").toString();
+ machine = m_windowInfo.value("clientMachine").toByteArray();
+ executeDialog();
}
- parent = child;
- }
- return 0;
+ );
}
} // namespace
diff --git a/kcmkwin/kwinrules/detectwidget.h b/kcmkwin/kwinrules/detectwidget.h
index efc8980c41..c0a208f60a 100644
--- a/kcmkwin/kwinrules/detectwidget.h
+++ b/kcmkwin/kwinrules/detectwidget.h
@@ -22,7 +22,6 @@
#include
#include
-#include
#include "../../rules.h"
//Added by qt3to4:
@@ -43,12 +42,12 @@ public:
};
class DetectDialog
- : public QDialog, public QAbstractNativeEventFilter
+ : public QDialog
{
Q_OBJECT
public:
explicit DetectDialog(QWidget* parent = nullptr, const char* name = nullptr);
- void detect(WId window, int secs = 0);
+ void detect(int secs = 0);
QByteArray selectedClass() const;
bool selectedWholeClass() const;
QByteArray selectedRole() const;
@@ -57,17 +56,17 @@ public:
QString selectedTitle() const;
Rules::StringMatch titleMatch() const;
QByteArray selectedMachine() const;
- const KWindowInfo& windowInfo() const;
- virtual bool nativeEventFilter(const QByteArray& eventType, void* message, long int* result) override;
+ const QVariantMap &windowInfo() const {
+ return m_windowInfo;
+ }
+
Q_SIGNALS:
void detectionDone(bool);
private Q_SLOTS:
void selectWindow();
private:
- void readWindow(WId window);
void executeDialog();
- WId findWindow();
QByteArray wmclass_class;
QByteArray wmclass_name;
QByteArray role;
@@ -76,17 +75,9 @@ private:
QByteArray extrarole;
QByteArray machine;
DetectWidget* widget;
- QScopedPointer grabber;
- QScopedPointer info;
+ QVariantMap m_windowInfo;
};
-inline
-const KWindowInfo& DetectDialog::windowInfo() const
-{
- Q_ASSERT(!info.isNull());
- return *(info.data());
-}
-
} // namespace
#endif
diff --git a/kcmkwin/kwinrules/ruleswidget.cpp b/kcmkwin/kwinrules/ruleswidget.cpp
index b6765da9a8..240027f24d 100644
--- a/kcmkwin/kwinrules/ruleswidget.cpp
+++ b/kcmkwin/kwinrules/ruleswidget.cpp
@@ -41,6 +41,8 @@
#include "detectwidget.h"
+Q_DECLARE_METATYPE(NET::WindowType)
+
namespace KWin
{
@@ -680,7 +682,7 @@ void RulesWidget::detectClicked()
assert(detect_dlg == nullptr);
detect_dlg = new DetectDialog;
connect(detect_dlg, SIGNAL(detectionDone(bool)), this, SLOT(detected(bool)));
- detect_dlg->detect(0, Ui::RulesWidgetBase::detection_delay->value());
+ detect_dlg->detect(Ui::RulesWidgetBase::detection_delay->value());
}
void RulesWidget::detected(bool ok)
@@ -714,8 +716,7 @@ void RulesWidget::detected(bool ok)
machine_match->setCurrentIndex(Rules::UnimportantMatch);
machineMatchChanged();
// prefill values from to window to settings which already set
- const KWindowInfo& info = detect_dlg->windowInfo();
- prefillUnusedValues(info);
+ prefillUnusedValues(detect_dlg->windowInfo());
}
delete detect_dlg;
detect_dlg = nullptr;
@@ -771,6 +772,44 @@ void RulesWidget::prefillUnusedValues(const KWindowInfo& info)
//CHECKBOX_PREFILL( blockcompositing, );
}
+void RulesWidget::prefillUnusedValues(const QVariantMap& info)
+{
+ const QSize windowSize{info.value("width").toInt(), info.value("height").toInt()};
+ LINEEDIT_PREFILL(position, positionToStr, QPoint(info.value("x").toInt(), info.value("y").toInt()));
+ LINEEDIT_PREFILL(size, sizeToStr, windowSize);
+ COMBOBOX_PREFILL(desktop, desktopToCombo, info.value("x11DesktopNumber").toInt());
+ // COMBOBOX_PREFILL(activity, activityToCombo, info.activity()); // TODO: ivan
+ CHECKBOX_PREFILL(maximizehoriz, , info.value("maximizeHorizontal").toBool());
+ CHECKBOX_PREFILL(maximizevert, , info.value("maximizeVertical").toBool());
+ CHECKBOX_PREFILL(minimize, , info.value("minimized").toBool());
+ CHECKBOX_PREFILL(shade, , info.value("shaded").toBool());
+ CHECKBOX_PREFILL(fullscreen, , info.value("fullscreen").toBool());
+ //COMBOBOX_PREFILL( placement, placementToCombo );
+ CHECKBOX_PREFILL(above, , info.value("keepAbove").toBool());
+ CHECKBOX_PREFILL(below, , info.value("keepBelow").toBool());
+ CHECKBOX_PREFILL(noborder, , info.value("noBorder").toBool());
+ CHECKBOX_PREFILL(skiptaskbar, , info.value("skipTaskbar").toBool());
+ CHECKBOX_PREFILL(skippager, , info.value("skipPager").toBool());
+ CHECKBOX_PREFILL(skipswitcher, , info.value("skipSwitcher").toBool());
+ //CHECKBOX_PREFILL( acceptfocus, );
+ //CHECKBOX_PREFILL( closeable, );
+ //CHECKBOX_PREFILL( autogroup, );
+ //CHECKBOX_PREFILL( autogroupfg, );
+ //LINEEDIT_PREFILL( autogroupid, );
+ SPINBOX_PREFILL(opacityactive, , 100 /*get the actual opacity somehow*/);
+ SPINBOX_PREFILL(opacityinactive, , 100 /*get the actual opacity somehow*/);
+ //LINEEDIT_PREFILL( shortcut, );
+ //COMBOBOX_PREFILL( fsplevel, );
+ //COMBOBOX_PREFILL( fpplevel, );
+ COMBOBOX_PREFILL(type, typeToCombo, info.value("type").value());
+ //CHECKBOX_PREFILL( ignoregeometry, );
+ LINEEDIT_PREFILL(minsize, sizeToStr, windowSize);
+ LINEEDIT_PREFILL(maxsize, sizeToStr, windowSize);
+ //CHECKBOX_PREFILL( strictgeometry, );
+ //CHECKBOX_PREFILL( disableglobalshortcuts, );
+ //CHECKBOX_PREFILL( blockcompositing, );
+}
+
#undef GENERIC_PREFILL
#undef CHECKBOX_PREFILL
#undef LINEEDIT_PREFILL
@@ -804,6 +843,7 @@ bool RulesWidget::finalCheck()
void RulesWidget::prepareWindowSpecific(WId window)
{
+ // TODO: adjust for Wayland
tabs->setCurrentIndex(1); // geometry tab, skip tab for window identification
KWindowInfo info(window, NET::WMAllProperties, NET::WM2AllProperties); // read everything
prefillUnusedValues(info);
diff --git a/kcmkwin/kwinrules/ruleswidget.h b/kcmkwin/kwinrules/ruleswidget.h
index 7a4e3f27f7..714ed885c9 100644
--- a/kcmkwin/kwinrules/ruleswidget.h
+++ b/kcmkwin/kwinrules/ruleswidget.h
@@ -117,6 +117,7 @@ private:
int inc(int i) const { return i+1; }
int dec(int i) const { return i-1; }
void prefillUnusedValues(const KWindowInfo& info);
+ void prefillUnusedValues(const QVariantMap& info);
DetectDialog* detect_dlg;
bool detect_dlg_ok;
};
diff --git a/org.kde.KWin.xml b/org.kde.KWin.xml
index 7f57f0c1f3..4794335f5b 100644
--- a/org.kde.KWin.xml
+++ b/org.kde.KWin.xml
@@ -36,5 +36,9 @@
+
+
+
+