11 Commits
Author SHA1 Message Date
Fredrik Averpil 9b0f339b19 launch: set desktop file name before constructing the app 2026-10-21 23:48:02 -07:00
Domen Kožar 3c5323bcf5 service/tray: forward Wayland activation tokens on primary clicks 2026-10-21 23:47:48 -07:00
bbedward 5c4f4c7148 service/greetd: discard responses to cancelled sessions 2026-10-21 17:11:13 -07:00
Jeff Zhou 1039e2b9d5 service/pipewire: call pw_loop_enter/leave on the SPA event loop 2026-10-21 17:11:09 -07:00
2 * r + 2 * t 2b4501a282 build: expose dependency metatypes in light dep
If not Qt will generate stubs for unknown types, which qmllint reads and
treats as the real type
2026-10-16 22:20:46 -07:00
Alberto Cerqua 95a1f91125 wayland/screencopy: avoid crash when capturing null screen
Prevent null pointer dereference in IccOutputSourceManager, WlrScreencopyManager, and ScreencopyManager when captureSource references a null screen.
2026-10-16 20:21:29 -07:00
Dmitry Litoshik 18c95fae4a wayland/lock: emit lockStateChanged on unlock 2026-10-16 18:13:15 -07:00
2 * r + 2 * t 1c1cc91533 all: include type namespaces in MOC'd members 2026-10-16 18:04:32 -07:00
2 * r + 2 * t 30a5d60a31 core/desktopentry: trim lines in desktop entries when parsing 2026-10-16 17:59:45 -07:00
Ryan Hughes 4befab5bc6 hyprland/ipc: follow workspace id changes 2026-10-16 17:51:32 -07:00
outfoxxed d7ee6d125c core/scriptmodel: emit row updates for rows changed by only identity
Fixes updates not being emitted when using objectProp.
Changes that compared structurally equal are also reported,
which might cover some additional JS equality cases.
2026-10-16 17:50:59 -07:00
84 changed files with 558 additions and 164 deletions

No files matched your search

+14
View File
@@ -0,0 +1,14 @@
## Other Changes
- `SystemTrayItem.activate()` now forwards Wayland activation tokens to applications.
## Bug Fixes
- Fixed ScriptModel not sending role updates on changed data that compares equal by key or structure.
- Fixed Hyprland workspaces keeping their old id after Hyprland changes it.
- Fixed desktop entries being parsed incorrectly with trailing whitespace or CRLF line endings.
- Fixed `WlSessionLock.locked` changes not being emitted on unlock.
- Fixed a crash when unplugging a screen being captured by ScreencopyView or trying to capture the fallback screen.
- Fixed most broken qml types in qmlls/qmllint for Qt 6.12.
- Fixed missing thread entry for Pipewire event loop resulting in Pipewire connection failing.
- Fixed Greetd treating responses for a cancelled session as responses for the next one.
+21 -2
View File
@@ -21,8 +21,27 @@ endfunction()
# DEPENDENCIES introduces a cmake dependency which we don't need with static modules.
# This greatly improves comp speed by not introducing those dependencies.
function (qs_add_module_deps_light target)
foreach (dep IN LISTS ARGN)
string(APPEND qmldir_extra "depends ${dep}\n")
cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "URIS")
set(uris)
# Add dep metatypes files to target so it picks up the dep type data
foreach (dep IN LISTS arg_UNPARSED_ARGUMENTS)
get_target_property(uri ${dep} QT_QML_MODULE_URI)
get_target_property(metatypes ${dep} INTERFACE_QT_META_TYPES_BUILD_FILE)
if (NOT uri OR NOT metatypes)
message(FATAL_ERROR "${dep} must be a qml module defined before ${target}")
endif()
list(APPEND uris ${uri})
target_sources(${target} PRIVATE ${metatypes})
endforeach()
list(APPEND uris ${arg_URIS})
foreach (uri IN LISTS uris)
string(APPEND qmldir_extra "depends ${uri}\n")
endforeach()
qs_append_qmldir(${target} "${qmldir_extra}")
+2
View File
@@ -29,6 +29,8 @@ qt_add_qml_module(quickshell-bluetooth
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-bluetooth quickshell-core)
install_qml_module(quickshell-bluetooth)
# dbus headers
+2 -2
View File
@@ -32,7 +32,7 @@ public:
};
Q_ENUM(Enum);
Q_INVOKABLE static QString toString(BluetoothAdapterState::Enum state);
Q_INVOKABLE static QString toString(qs::bluetooth::BluetoothAdapterState::Enum state);
};
} // namespace qs::bluetooth
@@ -64,7 +64,7 @@ class BluetoothAdapter: public QObject {
/// True if the adapter is currently enabled. More detailed state is available from @@state.
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged);
/// Detailed power state of the adapter.
Q_PROPERTY(BluetoothAdapterState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState);
Q_PROPERTY(qs::bluetooth::BluetoothAdapterState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState);
/// True if the adapter can be discovered by other bluetooth devices.
Q_PROPERTY(bool discoverable READ discoverable WRITE setDiscoverable NOTIFY discoverableChanged);
/// Timeout in seconds for how long the adapter stays discoverable after @@discoverable is set to true.
+1 -1
View File
@@ -66,7 +66,7 @@ class BluezQml: public QObject {
QML_SINGLETON;
// clang-format off
/// The default bluetooth adapter. Usually there is only one.
Q_PROPERTY(BluetoothAdapter* defaultAdapter READ default NOTIFY defaultAdapterChanged BINDABLE bindableDefaultAdapter);
Q_PROPERTY(qs::bluetooth::BluetoothAdapter* defaultAdapter READ default NOTIFY defaultAdapterChanged BINDABLE bindableDefaultAdapter);
QSDOC_TYPE_OVERRIDE(ObjectModel<qs::bluetooth::BluetoothAdapter>*);
/// A list of all bluetooth adapters. See @@defaultAdapter for the default.
Q_PROPERTY(UntypedObjectModel* adapters READ adapters CONSTANT);
+3 -3
View File
@@ -29,7 +29,7 @@ public:
};
Q_ENUM(Enum);
Q_INVOKABLE static QString toString(BluetoothDeviceState::Enum state);
Q_INVOKABLE static QString toString(qs::bluetooth::BluetoothDeviceState::Enum state);
};
struct BatteryPercentage {};
@@ -70,7 +70,7 @@ class BluetoothDevice: public QObject {
/// System icon representing the device type. Use @@Quickshell.Quickshell.iconPath() to display this in an image.
Q_PROPERTY(QString icon READ default NOTIFY iconChanged BINDABLE bindableIcon);
/// Connection state of the device.
Q_PROPERTY(BluetoothDeviceState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState);
Q_PROPERTY(qs::bluetooth::BluetoothDeviceState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState);
/// True if the device is currently connected to the computer.
///
/// Setting this property is equivalent to calling @@connect() and @@disconnect().
@@ -100,7 +100,7 @@ class BluetoothDevice: public QObject {
/// Battery level of the connected device, from `0.0` to `1.0`. Only valid if @@batteryAvailable is true.
Q_PROPERTY(qreal battery READ default NOTIFY batteryChanged BINDABLE bindableBattery);
/// The Bluetooth adapter this device belongs to.
Q_PROPERTY(BluetoothAdapter* adapter READ adapter NOTIFY adapterChanged);
Q_PROPERTY(qs::bluetooth::BluetoothAdapter* adapter READ adapter NOTIFY adapterChanged);
/// DBus path of the device under the `org.bluez` system service.
Q_PROPERTY(QString dbusPath READ path CONSTANT);
// clang-format on
+7 -6
View File
@@ -158,22 +158,23 @@ ParsedDesktopEntryData DesktopEntry::parseText(const QString& id, const QString&
};
for (auto& line: text.split(u'\n', Qt::SkipEmptyParts)) {
if (line.startsWith(u'#')) continue;
const auto trimmed = line.trimmed();
if (trimmed.isEmpty() || trimmed.startsWith(u'#')) continue;
if (line.startsWith(u'[') && line.endsWith(u']')) {
if (trimmed.startsWith(u'[') && trimmed.endsWith(u']')) {
finishCategory();
groupName = line.sliced(1, line.length() - 2);
groupName = trimmed.sliced(1, trimmed.length() - 2);
continue;
}
auto splitIdx = line.indexOf(u'=');
auto splitIdx = trimmed.indexOf(u'=');
if (splitIdx == -1) {
qCWarning(logDesktopEntry) << "Encountered invalid line in desktop entry (no =)" << line;
continue;
}
auto key = line.sliced(0, splitIdx);
const auto& value = line.sliced(splitIdx + 1);
auto key = trimmed.sliced(0, splitIdx);
const auto& value = trimmed.sliced(splitIdx + 1);
auto localeIdx = key.indexOf('[');
Locale locale;
+1 -1
View File
@@ -120,7 +120,7 @@ public slots:
void initFs();
private slots:
void onMessage(const LogMessage& msg, bool showInSparse);
void onMessage(const qs::log::LogMessage& msg, bool showInSparse);
private:
QFile* file = nullptr;
+22 -19
View File
@@ -199,31 +199,34 @@ bool ScriptModel::updateValuesUnique(const QList<QJSValue>& newValues) {
this->endInsertRows();
anyChanges = true;
}
} else if (!newIter->strictlyEquals(*iter)) {
auto first = static_cast<qint32>(std::distance(this->mValues.begin(), iter));
auto index = first;
do {
this->mValues.replace(index, *newIter);
++iter;
++newIter;
++index;
} while (iter != this->mValues.end() && newIter != newValues.end()
&& !newIter->strictlyEquals(*iter));
this->dataChanged(
this->index(first, 0, QModelIndex()),
this->index(index - 1, 0, QModelIndex()),
{Qt::UserRole}
);
anyChanges = true;
} else {
++iter;
++newIter;
}
}
for (auto i = 0; i != this->mValues.length();) {
if (this->mValues.at(i).strictlyEquals(newValues.at(i))) {
++i;
continue;
}
auto first = i;
do {
this->mValues.replace(i, newValues.at(i));
++i;
} while (i != this->mValues.length() && !this->mValues.at(i).strictlyEquals(newValues.at(i)));
this->dataChanged(
this->index(first, 0, QModelIndex()),
this->index(i - 1, 0, QModelIndex()),
{Qt::UserRole}
);
anyChanges = true;
}
this->isModifying = false;
if (this->stagedValues.has_value()) {
+103
View File
@@ -4,6 +4,7 @@
#include <qabstractitemmodeltester.h>
#include <qcontainerfwd.h>
#include <qdebug.h>
#include <qhash.h>
#include <qjsengine.h>
#include <qjsvalue.h>
#include <qlist.h>
@@ -47,6 +48,7 @@ ChangeObserver::ChangeObserver(QAbstractItemModel* model) {
QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &ChangeObserver::onInsert);
QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &ChangeObserver::onRemove);
QObject::connect(model, &QAbstractItemModel::rowsMoved, this, &ChangeObserver::onMove);
QObject::connect(model, &QAbstractItemModel::dataChanged, this, &ChangeObserver::onDataChanged);
}
void ChangeObserver::onInsert(const QModelIndex& parent, int first, int last) {
@@ -72,6 +74,10 @@ void ChangeObserver::onMove(
.emplaceBack(ModelOperation::Move, sourceStart, sourceEnd - sourceStart + 1, destStart);
}
void ChangeObserver::onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) {
this->mChanges.emplaceBack(topLeft.row(), bottomRight.row());
}
// NOLINTNEXTLINE(misc-use-internal-linkage)
QDebug& operator<<(QDebug& debug, const QJSValueList& list) {
QString str;
@@ -186,6 +192,7 @@ void TestScriptModel::unique() {
model.setValues(newList);
QVERIFY(qjsValueListsEqual(model.values(), newList));
QCOMPARE_EQ(observer.operations(), operations);
QCOMPARE_EQ(observer.changes(), ChangeList());
}
void TestScriptModel::structuralEquality() {
@@ -280,4 +287,100 @@ void TestScriptModel::comparisonModes() {
QCOMPARE_EQ(observer.operations(), OpList());
}
void TestScriptModel::dataUpdated_data() {
QTest::addColumn<QString>("oldstr");
QTest::addColumn<QString>("newstr");
QTest::addColumn<OpList>("operations");
QTest::addColumn<ChangeList>("changes");
// Uppercase = same data, Lowercase = data updated
QTest::addRow("insert") << "ABC" << "AXBC" << OpList({{ModelOperation::Insert, 1, 1}})
<< ChangeList();
QTest::addRow("remove") << "AXBC" << "ABC" << OpList({{ModelOperation::Remove, 1, 1}})
<< ChangeList();
QTest::addRow("move") << "ABCD" << "ACBD" << OpList({{ModelOperation::Move, 2, 1, 1}})
<< ChangeList();
QTest::addRow("move_range") << "ABCDEF" << "ADEBCF" << OpList({{ModelOperation::Move, 3, 2, 1}})
<< ChangeList();
QTest::addRow("state_ok") << "ABCDEFG" << "ABEFXYCDG"
<< OpList({
{ModelOperation::Move, 4, 2, 2}, // ABEFCDG
{ModelOperation::Insert, 4, 2}, // ABEFXYCDG
})
<< ChangeList();
QTest::addRow("insert_all_updated") << "ABC" << "aXbc" << OpList({{ModelOperation::Insert, 1, 1}})
<< ChangeList({{0, 0}, {2, 3}});
QTest::addRow("remove_all_updated")
<< "AXBC" << "abc" << OpList({{ModelOperation::Remove, 1, 1}}) << ChangeList({{0, 2}});
QTest::addRow("move_all_updated")
<< "ABCD" << "acbd" << OpList({{ModelOperation::Move, 2, 1, 1}}) << ChangeList({{0, 3}});
QTest::addRow("move_range_all_updated")
<< "ABCDEF" << "adebcf" << OpList({{ModelOperation::Move, 3, 2, 1}}) << ChangeList({{0, 5}});
QTest::addRow("state_ok_all_updated") << "ABCDEFG" << "abefXYcdg"
<< OpList({
{ModelOperation::Move, 4, 2, 2}, // abefCDG
{ModelOperation::Insert, 4, 2}, // abefXYCDG
})
<< ChangeList({{0, 3}, {6, 8}});
QTest::addRow("update_in_place") << "ABC" << "aBc" << OpList() << ChangeList({{0, 0}, {2, 2}});
QTest::addRow("move_updated") << "ABCDEF" << "AdeBCF" << OpList({{ModelOperation::Move, 3, 2, 1}})
<< ChangeList({{1, 2}});
QTest::addRow("move_neighbours_updated")
<< "ABCD" << "aCbd" << OpList({{ModelOperation::Move, 2, 1, 1}})
<< ChangeList({{0, 0}, {2, 3}});
QTest::addRow("move_partially_updated")
<< "ABCDEF" << "aCdEbf" << OpList({{ModelOperation::Move, 2, 3, 1}})
<< ChangeList({{0, 0}, {2, 2}, {4, 5}});
}
void TestScriptModel::dataUpdated() {
QFETCH(const QString, oldstr);
QFETCH(const QString, newstr);
QFETCH(const OpList, operations);
QFETCH(const ChangeList, changes);
QJSEngine engine;
auto version = 0;
QHash<QString, QJSValue> oldValues;
auto strToJsValueList = [&](const QString& str) -> QJSValueList {
QJSValueList list;
for (auto c: str) {
auto key = QString(c.toUpper());
if (c.isUpper() && oldValues.contains(key)) {
list.emplace_back(oldValues.value(key));
continue;
}
auto value = engine.newObject();
value.setProperty("key", key);
value.setProperty("version", version);
list.emplace_back(value);
}
version++;
return list;
};
auto oldList = strToJsValueList(oldstr);
for (const auto& value: oldList) oldValues.insert(value.property("key").toString(), value);
auto newList = strToJsValueList(newstr);
ScriptModel model;
model.setObjectProp("key");
auto modelTester = QAbstractItemModelTester(&model);
model.setValues(oldList);
auto observer = ChangeObserver(&model);
model.setValues(newList);
QVERIFY(qjsValueListsEqual(model.values(), newList));
QCOMPARE_EQ(observer.operations(), operations);
QCOMPARE_EQ(observer.changes(), changes);
}
QTEST_MAIN(TestScriptModel);
+12 -1
View File
@@ -4,6 +4,7 @@
#include <qdebug.h>
#include <qlist.h>
#include <qobject.h>
#include <qpair.h>
#include <qtmetamacros.h>
#include <qtypes.h>
@@ -29,13 +30,19 @@ struct ModelOperation {
};
using OpList = QList<ModelOperation>;
// First and last row of each dataChanged, in emission order.
using ChangeList = QList<QPair<qint32, qint32>>;
class ChangeObserver: public QObject {
public:
explicit ChangeObserver(QAbstractItemModel* model);
[[nodiscard]] const OpList& operations() const { return this->mOperations; }
void clear() { this->mOperations.clear(); }
[[nodiscard]] const ChangeList& changes() const { return this->mChanges; }
void clear() {
this->mOperations.clear();
this->mChanges.clear();
}
private:
void onInsert(const QModelIndex& parent, int first, int last);
@@ -47,8 +54,10 @@ private:
const QModelIndex& destParent,
int destStart
);
void onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
OpList mOperations;
ChangeList mChanges;
};
QDebug& operator<<(QDebug& debug, const ModelOperation& op);
@@ -61,4 +70,6 @@ private slots:
static void unique();
static void structuralEquality();
static void comparisonModes();
static void dataUpdated_data(); // NOLINT
static void dataUpdated();
};
+1 -1
View File
@@ -20,7 +20,7 @@ qt_add_qml_module(quickshell-dbusmenu
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-dbusmenu Quickshell)
qs_add_module_deps_light(quickshell-dbusmenu quickshell-core)
install_qml_module(quickshell-dbusmenu)
+1 -1
View File
@@ -21,7 +21,7 @@ qt_add_qml_module(quickshell-io
FileView.qml
)
qs_add_module_deps_light(quickshell-io Quickshell)
qs_add_module_deps_light(quickshell-io quickshell-core)
install_qml_module(quickshell-io)
target_link_libraries(quickshell-io PRIVATE Qt::Quick quickshell-ipc)
+1 -1
View File
@@ -227,7 +227,7 @@ class FileView: public QObject {
/// Its state may be saved with @@writeAdapter().
///
/// Currently the only adapter is @@JsonAdapter.
Q_PROPERTY(FileViewAdapter* adapter READ adapter WRITE setAdapter NOTIFY adapterChanged);
Q_PROPERTY(qs::io::FileViewAdapter* adapter READ adapter WRITE setAdapter NOTIFY adapterChanged);
QSDOC_HIDE Q_PROPERTY(QString __path READ path WRITE setPath NOTIFY pathChanged);
QSDOC_HIDE Q_PROPERTY(QString __text READ text NOTIFY internalTextChanged);
+1 -2
View File
@@ -277,6 +277,7 @@ int launch(const LaunchArgs& args, char** argv) {
QIcon::setFallbackSearchPaths(fallbackPaths);
}
QGuiApplication::setDesktopFileName(appId);
QGuiApplication::setDesktopSettingsAware(pragmas.desktopSettingsAware);
QGuiApplication* app = nullptr;
@@ -291,8 +292,6 @@ int launch(const LaunchArgs& args, char** argv) {
LogManager::initThreadLogging();
LogManager::initFs();
QGuiApplication::setDesktopFileName(appId);
if (args.debugPort != -1) {
QQmlDebuggingEnabler::enableDebugging(true);
auto wait = args.waitForDebug ? QQmlDebuggingEnabler::WaitForClient
+1 -1
View File
@@ -19,7 +19,7 @@ qt_add_qml_module(quickshell-network
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-network Quickshell)
qs_add_module_deps_light(quickshell-network quickshell-core)
install_qml_module(quickshell-network)
target_link_libraries(quickshell-network PRIVATE quickshell-network-nm Qt::Qml Qt::DBus)
qs_add_link_dependencies(quickshell-network quickshell-dbus)
+1 -1
View File
@@ -25,7 +25,7 @@ class NetworkDevice: public QObject {
/// When the device type is `Wifi`, the device object is a @@WifiDevice.
/// When the device type is `Wired`, the device object is a @@WiredDevice.
/// connection and scanning.
Q_PROPERTY(DeviceType::Enum type READ type CONSTANT);
Q_PROPERTY(qs::network::DeviceType::Enum type READ type CONSTANT);
/// The name of the device's control interface.
Q_PROPERTY(QString name READ name NOTIFY nameChanged BINDABLE bindableName);
/// A list of available or connected networks for this device.
+7 -7
View File
@@ -27,7 +27,7 @@ public:
Full = 4,
};
Q_ENUM(Enum);
Q_INVOKABLE static QString toString(NetworkConnectivity::Enum conn);
Q_INVOKABLE static QString toString(qs::network::NetworkConnectivity::Enum conn);
};
///! The backend supplying the Network service.
@@ -42,7 +42,7 @@ public:
NetworkManager = 1,
};
Q_ENUM(Enum);
Q_INVOKABLE static QString toString(NetworkBackendType::Enum type);
Q_INVOKABLE static QString toString(qs::network::NetworkBackendType::Enum type);
};
///! The connection state of a device or network.
@@ -60,7 +60,7 @@ public:
Disconnected = 4,
};
Q_ENUM(Enum);
Q_INVOKABLE static QString toString(ConnectionState::Enum state);
Q_INVOKABLE static QString toString(qs::network::ConnectionState::Enum state);
};
///! The reason a connection failed.
@@ -85,7 +85,7 @@ public:
WifiNetworkLost = 5,
};
Q_ENUM(Enum);
Q_INVOKABLE static QString toString(ConnectionFailReason::Enum reason);
Q_INVOKABLE static QString toString(qs::network::ConnectionFailReason::Enum reason);
};
///! Type of a @@NetworkDevice.
@@ -101,7 +101,7 @@ public:
Wired = 2,
};
Q_ENUM(Enum);
Q_INVOKABLE static QString toString(DeviceType::Enum type);
Q_INVOKABLE static QString toString(qs::network::DeviceType::Enum type);
};
///! The security type of a @@WifiNetwork.
@@ -126,7 +126,7 @@ public:
Unknown = 11,
};
Q_ENUM(Enum);
Q_INVOKABLE static QString toString(WifiSecurityType::Enum type);
Q_INVOKABLE static QString toString(qs::network::WifiSecurityType::Enum type);
};
///! The 802.11 mode of a @@WifiDevice.
@@ -149,7 +149,7 @@ public:
Unknown = 4,
};
Q_ENUM(Enum);
Q_INVOKABLE static QString toString(WifiDeviceMode::Enum mode);
Q_INVOKABLE static QString toString(qs::network::WifiDeviceMode::Enum mode);
};
} // namespace qs::network
+6 -6
View File
@@ -27,17 +27,17 @@ class Network: public QObject {
/// The name of the network.
Q_PROPERTY(QString name READ default NOTIFY nameChanged BINDABLE bindableName);
/// The device this network belongs to.
Q_PROPERTY(NetworkDevice* device READ device CONSTANT);
Q_PROPERTY(qs::network::NetworkDevice* device READ device CONSTANT);
/// A list of NetworkManager connection settings profiles for this network.
///
/// > [!WARNING] Only valid for the NetworkManager backend.
Q_PROPERTY(QList<NMSettings*> nmSettings READ default NOTIFY nmSettingsChanged BINDABLE bindableNmSettings);
Q_PROPERTY(QList<qs::network::NMSettings*> nmSettings READ default NOTIFY nmSettingsChanged BINDABLE bindableNmSettings);
/// True if the network is connected.
Q_PROPERTY(bool connected READ default NOTIFY connectedChanged BINDABLE bindableConnected);
/// True if the wifi network has known connection settings saved.
Q_PROPERTY(bool known READ default NOTIFY knownChanged BINDABLE bindableKnown);
/// The connectivity state of the network.
Q_PROPERTY(ConnectionState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState);
Q_PROPERTY(qs::network::ConnectionState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState);
/// If the network is currently connecting or disconnecting. Shorthand for checking @@state.
Q_PROPERTY(bool stateChanging READ default NOTIFY stateChangingChanged BINDABLE bindableStateChanging);
// clang-format on
@@ -53,7 +53,7 @@ public:
/// Attempt to connect to the network with a specific @@nmSettings entry.
///
/// > [!WARNING] Only valid for the NetworkManager backend.
Q_INVOKABLE void connectWithSettings(NMSettings* settings);
Q_INVOKABLE void connectWithSettings(qs::network::NMSettings* settings);
/// Disconnect from the network.
Q_INVOKABLE void disconnect();
/// Forget all connection settings for this network.
@@ -77,7 +77,7 @@ public:
signals:
/// Signals that a connection to the network has failed because of the given @@ConnectionFailReason.
void connectionFailed(ConnectionFailReason::Enum reason);
void connectionFailed(qs::network::ConnectionFailReason::Enum reason);
void nameChanged();
void connectedChanged();
@@ -86,7 +86,7 @@ signals:
void stateChangingChanged();
void nmSettingsChanged();
QSDOC_HIDE void requestConnect();
QSDOC_HIDE void requestConnectWithSettings(NMSettings* settings);
QSDOC_HIDE void requestConnectWithSettings(qs::network::NMSettings* settings);
QSDOC_HIDE void requestDisconnect();
QSDOC_HIDE void requestForget();
+5 -5
View File
@@ -61,11 +61,11 @@ signals:
void loaded();
void ssidChanged(const QByteArray& ssid);
void signalStrengthChanged(quint8 signal);
void flagsChanged(NM80211ApFlags::Enum flags);
void wpaFlagsChanged(NM80211ApSecurityFlags::Enum wpaFlags);
void rsnFlagsChanged(NM80211ApSecurityFlags::Enum rsnFlags);
void modeChanged(NM80211Mode::Enum mode);
void securityChanged(WifiSecurityType::Enum security);
void flagsChanged(qs::network::NM80211ApFlags::Enum flags);
void wpaFlagsChanged(qs::network::NM80211ApSecurityFlags::Enum wpaFlags);
void rsnFlagsChanged(qs::network::NM80211ApSecurityFlags::Enum rsnFlags);
void modeChanged(qs::network::NM80211Mode::Enum mode);
void securityChanged(qs::network::WifiSecurityType::Enum security);
private:
// clang-format off
+2 -2
View File
@@ -43,8 +43,8 @@ public:
signals:
void loaded();
void connectionChanged(QDBusObjectPath path);
void stateChanged(NMConnectionState::Enum state);
void stateReasonChanged(NMConnectionStateReason::Enum reason);
void stateChanged(qs::network::NMConnectionState::Enum state);
void stateReasonChanged(qs::network::NMConnectionStateReason::Enum reason);
private slots:
void onStateChanged(quint32 state, quint32 reason);
+4 -4
View File
@@ -44,11 +44,11 @@ public:
[[nodiscard]] NMConnectivityState::Enum connectivity() const { return this->bConnectivity; }
signals:
void deviceAdded(NetworkDevice* device);
void deviceRemoved(NetworkDevice* device);
void deviceAdded(qs::network::NetworkDevice* device);
void deviceRemoved(qs::network::NetworkDevice* device);
void wifiEnabledChanged(bool enabled);
void wifiHardwareEnabledChanged(bool enabled);
void connectivityStateChanged(NMConnectivityState::Enum state);
void connectivityStateChanged(qs::network::NMConnectivityState::Enum state);
void connectivityCheckAvailableChanged(bool available);
void connectivityCheckEnabledChanged(bool enabled);
@@ -64,7 +64,7 @@ private slots:
void onServiceUnregistered();
void activateConnection(const QDBusObjectPath& connPath, const QDBusObjectPath& devPath);
void addAndActivateConnection(
const NMSettingsMap& settings,
const qs::network::NMSettingsMap& settings,
const QDBusObjectPath& devPath,
const QDBusObjectPath& specificObjectPath
);
+10 -10
View File
@@ -64,25 +64,25 @@ signals:
void loaded();
void activateConnection(const QDBusObjectPath& connPath, const QDBusObjectPath& devPath);
void addAndActivateConnection(
const NMSettingsMap& settings,
const qs::network::NMSettingsMap& settings,
const QDBusObjectPath& devPath,
const QDBusObjectPath& specificObjectPath
);
void networkAdded(Network* net);
void networkRemoved(Network* net);
void settingsLoaded(NMSettings* settings);
void settingsRemoved(NMSettings* settings);
void networkAdded(qs::network::Network* net);
void networkRemoved(qs::network::Network* net);
void settingsLoaded(qs::network::NMSettings* settings);
void settingsRemoved(qs::network::NMSettings* settings);
void availableSettingsPathsChanged(QList<QDBusObjectPath> paths);
void activeConnectionPathChanged(const QDBusObjectPath& connection);
void activeConnectionLoaded(NMActiveConnection* active);
void activeConnectionLoaded(qs::network::NMActiveConnection* active);
void interfaceChanged(const QString& interface);
void hwAddressChanged(const QString& hwAddress);
void managedChanged(bool managed);
void stateChanged(NMDeviceState::Enum state);
void stateReasonChanged(NMDeviceStateReason::Enum reason);
void lastFailReasonChanged(NMDeviceStateReason::Enum reason);
void stateChanged(qs::network::NMDeviceState::Enum state);
void stateReasonChanged(qs::network::NMDeviceStateReason::Enum reason);
void lastFailReasonChanged(qs::network::NMDeviceStateReason::Enum reason);
void autoconnectChanged(bool autoconnect);
void interfaceFlagsChanged(NMDeviceInterfaceFlags::Enum flags);
void interfaceFlagsChanged(qs::network::NMDeviceInterfaceFlags::Enum flags);
public slots:
void disconnect();
+14 -12
View File
@@ -41,16 +41,18 @@ public:
signals:
void requestDisconnect();
void requestActivateConnection(const QString& settingsPath);
void
requestAddAndActivateConnection(const NMSettingsMap& settingsMap, const QString& specificObject);
void requestAddAndActivateConnection(
const qs::network::NMSettingsMap& settingsMap,
const QString& specificObject
);
void settingsAdded(NMSettings* settings);
void settingsRemoved(NMSettings* settings);
void stateChanged(NMConnectionState::Enum state);
void settingsAdded(qs::network::NMSettings* settings);
void settingsRemoved(qs::network::NMSettings* settings);
void stateChanged(qs::network::NMConnectionState::Enum state);
void knownChanged(bool known);
void reasonChanged(NMConnectionStateReason::Enum reason);
void deviceFailReasonChanged(NMDeviceStateReason::Enum reason);
void referenceSettingsChanged(NMSettings* settings);
void reasonChanged(qs::network::NMConnectionStateReason::Enum reason);
void deviceFailReasonChanged(qs::network::NMDeviceStateReason::Enum reason);
void referenceSettingsChanged(qs::network::NMSettings* settings);
void visibilityChanged(bool visible);
protected:
@@ -113,11 +115,11 @@ public:
signals:
void disappeared();
void signalStrengthChanged(quint8 signal);
void securityChanged(WifiSecurityType::Enum security);
void securityChanged(qs::network::WifiSecurityType::Enum security);
void activeApPathChanged(QString path);
void referenceApChanged(NMAccessPoint* ap);
void capabilitiesChanged(NMWirelessCapabilities::Enum caps);
void apRemoved(NMAccessPoint* ap);
void referenceApChanged(qs::network::NMAccessPoint* ap);
void capabilitiesChanged(qs::network::NMWirelessCapabilities::Enum caps);
void apRemoved(qs::network::NMAccessPoint* ap);
private:
void updateReferenceAp();
+1 -1
View File
@@ -61,7 +61,7 @@ public:
signals:
void loaded();
void settingsChanged(NMSettingsMap settings);
void settingsChanged(qs::network::NMSettingsMap settings);
void idChanged(QString id);
void uuidChanged(QString uuid);
+2 -2
View File
@@ -32,8 +32,8 @@ signals:
void speedChanged(quint32 speed);
private slots:
void onSettingsLoaded(NMSettings* settings);
void onActiveConnectionLoaded(NMActiveConnection* active);
void onSettingsLoaded(qs::network::NMSettings* settings);
void onActiveConnectionLoaded(qs::network::NMActiveConnection* active);
private:
void initWired();
+7 -7
View File
@@ -51,20 +51,20 @@ public:
[[nodiscard]] WifiDevice* frontend() override { return this->mFrontend; };
signals:
void accessPointLoaded(NMAccessPoint* ap);
void accessPointRemoved(NMAccessPoint* ap);
void accessPointLoaded(qs::network::NMAccessPoint* ap);
void accessPointRemoved(qs::network::NMAccessPoint* ap);
void lastScanChanged(QDateTime lastScan);
void scanningChanged(bool scanning);
void capabilitiesChanged(NMWirelessCapabilities::Enum caps);
void capabilitiesChanged(qs::network::NMWirelessCapabilities::Enum caps);
void activeAccessPointChanged(const QDBusObjectPath& path);
void modeChanged(NM80211Mode::Enum mode);
void modeChanged(qs::network::NM80211Mode::Enum mode);
private slots:
void onAccessPointAdded(const QDBusObjectPath& path);
void onAccessPointRemoved(const QDBusObjectPath& path);
void onAccessPointLoaded(NMAccessPoint* ap);
void onSettingsLoaded(NMSettings* settings);
void onActiveConnectionLoaded(NMActiveConnection* active);
void onAccessPointLoaded(qs::network::NMAccessPoint* ap);
void onSettingsLoaded(qs::network::NMSettings* settings);
void onActiveConnectionLoaded(qs::network::NMActiveConnection* active);
void onScanTimeout();
void onScanningChanged(bool scanning);
+2 -2
View File
@@ -55,8 +55,8 @@ signals:
void connectivityChanged();
private slots:
void deviceAdded(NetworkDevice* dev);
void deviceRemoved(NetworkDevice* dev);
void deviceAdded(qs::network::NetworkDevice* dev);
void deviceRemoved(qs::network::NetworkDevice* dev);
private:
explicit Networking(QObject* parent = nullptr);
+2 -2
View File
@@ -22,7 +22,7 @@ class WifiNetwork: public Network {
/// The current signal strength of the network, from 0.0 to 1.0.
Q_PROPERTY(qreal signalStrength READ default NOTIFY signalStrengthChanged BINDABLE bindableSignalStrength);
/// The security type of the wifi network.
Q_PROPERTY(WifiSecurityType::Enum security READ default NOTIFY securityChanged BINDABLE bindableSecurity);
Q_PROPERTY(qs::network::WifiSecurityType::Enum security READ default NOTIFY securityChanged BINDABLE bindableSecurity);
// clang-format on
public:
@@ -64,7 +64,7 @@ class WifiDevice: public NetworkDevice {
/// When enabled, the scanner populates the device with an active list of available wifi networks.
Q_PROPERTY(bool scannerEnabled READ scannerEnabled WRITE setScannerEnabled NOTIFY scannerEnabledChanged BINDABLE bindableScannerEnabled);
/// The 802.11 mode the device is in.
Q_PROPERTY(WifiDeviceMode::Enum mode READ default NOTIFY modeChanged BINDABLE bindableMode);
Q_PROPERTY(qs::network::WifiDeviceMode::Enum mode READ default NOTIFY modeChanged BINDABLE bindableMode);
// clang-format on
public:
+3 -1
View File
@@ -20,7 +20,9 @@ class WiredDevice: public NetworkDevice {
/// The wired network for this device or `null`.
///
/// > [!NOTE] This network is only available when @@hasLink is `true`.
Q_PROPERTY(Network* network READ network NOTIFY networkChanged BINDABLE bindableNetwork);
Q_PROPERTY(
qs::network::Network* network READ network NOTIFY networkChanged BINDABLE bindableNetwork
);
/// The maximum speed of the physical device link, in megabits per second.
Q_PROPERTY(quint32 linkSpeed READ default NOTIFY linkSpeedChanged BINDABLE bindableLinkSpeed);
/// True if the wired device has a physical link (cable plugged in).
+12
View File
@@ -126,6 +126,8 @@ void GreetdConnection::setActive(bool active) {
{"type", "cancel_session"},
});
// Greetd requests are answered in order, so drop all responses to requests prior to cancelling.
this->mCancelledResponses = this->mPendingResponses;
this->setInactive();
}
} else {
@@ -172,6 +174,14 @@ void GreetdConnection::onSocketReady() {
qCDebug(logGreetd).noquote() << "Received greetd response:" << text;
if (this->mPendingResponses != 0) this->mPendingResponses--;
if (this->mCancelledResponses != 0) {
qCDebug(logGreetd) << "Discarding response to a cancelled session.";
this->mCancelledResponses--;
continue;
}
if (type == "success") {
switch (this->mState) {
case GreetdState::Authenticating:
@@ -260,6 +270,8 @@ void GreetdConnection::sendRequest(const QJsonObject& json) {
this->socket.write(text);
this->socket.flush();
this->mPendingResponses++;
}
GreetdConnection* GreetdConnection::instance() {
+2
View File
@@ -74,6 +74,8 @@ private:
bool mExitAfterLaunch = false;
QString mMessage;
bool mResponseRequired = false;
quint32 mPendingResponses = 0;
quint32 mCancelledResponses = 0;
QString mUser;
QLocalSocket socket;
StreamReader reader;
+1 -1
View File
@@ -33,7 +33,7 @@ qt_add_qml_module(quickshell-service-mpris
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-service-mpris Quickshell)
qs_add_module_deps_light(quickshell-service-mpris quickshell-core)
install_qml_module(quickshell-service-mpris)
+1 -1
View File
@@ -22,7 +22,7 @@ qt_add_qml_module(quickshell-service-notifications
VERSION 0.1
)
qs_add_module_deps_light(quickshell-service-notifications Quickshell)
qs_add_module_deps_light(quickshell-service-notifications quickshell-core)
install_qml_module(quickshell-service-notifications)
target_link_libraries(quickshell-service-notifications PRIVATE Qt::Quick Qt::DBus)
+1 -1
View File
@@ -20,7 +20,7 @@ qt_add_qml_module(quickshell-service-pipewire
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-service-pipewire Quickshell)
qs_add_module_deps_light(quickshell-service-pipewire quickshell-core)
install_qml_module(quickshell-service-pipewire)
+3
View File
@@ -55,6 +55,8 @@ bool PwCore::start(bool retry) {
return false;
}
pw_loop_enter(this->loop);
this->context = pw_context_new(this->loop, nullptr, 0);
if (this->context == nullptr) {
if (retry) {
@@ -103,6 +105,7 @@ void PwCore::shutdown() {
}
if (this->loop != nullptr) {
pw_loop_leave(this->loop);
pw_loop_destroy(this->loop);
this->loop = nullptr;
}
+2 -2
View File
@@ -41,9 +41,9 @@ signals:
void defaultConfiguredSourceNameChanged();
private slots:
void onMetadataAdded(PwMetadata* metadata);
void onMetadataAdded(qs::service::pipewire::PwMetadata* metadata);
void onMetadataProperty(const char* key, const char* type, const char* value);
void onNodeAdded(PwNode* node);
void onNodeAdded(qs::service::pipewire::PwNode* node);
void onDefaultSinkDestroyed();
void onDefaultSourceDestroyed();
void onDefaultConfiguredSinkDestroyed();
+2 -1
View File
@@ -39,7 +39,8 @@ public:
signals:
void deviceReady();
void routeVolumesChanged(qint32 routeDevice, const PwVolumeProps& volumeProps);
void
routeVolumesChanged(qint32 routeDevice, const qs::service::pipewire::PwVolumeProps& volumeProps);
private slots:
void polled();
+2 -1
View File
@@ -209,7 +209,8 @@ signals:
private slots:
void onDeviceReady();
void onDeviceVolumesChanged(qint32 routeDevice, const PwVolumeProps& props);
void
onDeviceVolumesChanged(qint32 routeDevice, const qs::service::pipewire::PwVolumeProps& props);
private:
void updateVolumeProps(const PwVolumeProps& volumeProps);
+5 -5
View File
@@ -158,11 +158,11 @@ signals:
void readyChanged();
private slots:
void onNodeAdded(PwNode* node);
void onNodeAdded(qs::service::pipewire::PwNode* node);
void onNodeRemoved(QObject* object);
void onLinkAdded(PwLink* link);
void onLinkAdded(qs::service::pipewire::PwLink* link);
void onLinkRemoved(QObject* object);
void onLinkGroupAdded(PwLinkGroup* group);
void onLinkGroupAdded(qs::service::pipewire::PwLinkGroup* group);
void onLinkGroupRemoved(QObject* object);
private:
@@ -199,7 +199,7 @@ signals:
private slots:
void onNodeDestroyed();
void onLinkGroupCreated(PwLinkGroup* linkGroup);
void onLinkGroupCreated(qs::service::pipewire::PwLinkGroup* linkGroup);
void onLinkGroupDestroyed(QObject* object);
private:
@@ -361,7 +361,7 @@ class PwLinkIface: public PwObjectIface {
/// The current state of the link.
///
/// > [!WARNING] This property is invalid unless the node is bound using @@PwObjectTracker.
Q_PROPERTY(PwLinkState::Enum state READ state NOTIFY stateChanged);
Q_PROPERTY(qs::service::pipewire::PwLinkState::Enum state READ state NOTIFY stateChanged);
QML_NAMED_ELEMENT(PwLink);
QML_UNCREATABLE("PwLinks cannot be created directly");
+5 -5
View File
@@ -49,7 +49,7 @@ public:
signals:
// goes with safeDestroy
void destroying(PwBindableObject* self);
void destroying(qs::service::pipewire::PwBindableObject* self);
protected:
void registryBind(const char* interface, quint32 version);
@@ -132,10 +132,10 @@ public:
[[nodiscard]] PwNode* findNodeByName(QStringView name) const;
signals:
void nodeAdded(PwNode* node);
void linkAdded(PwLink* link);
void linkGroupAdded(PwLinkGroup* group);
void metadataAdded(PwMetadata* metadata);
void nodeAdded(qs::service::pipewire::PwNode* node);
void linkAdded(qs::service::pipewire::PwLink* link);
void linkGroupAdded(qs::service::pipewire::PwLinkGroup* group);
void metadataAdded(qs::service::pipewire::PwMetadata* metadata);
void initialized();
void cleared();
+2 -2
View File
@@ -45,12 +45,12 @@ class AuthFlow
/// Each identity may be a user or a group. You may select any of them to
/// authenticate by setting @@selectedIdentity. By default, the first identity
/// in the list is selected.
Q_PROPERTY(QList<Identity*> identities READ identities CONSTANT);
Q_PROPERTY(QList<qs::service::polkit::Identity*> identities READ identities CONSTANT);
/// The identity that will be used to authenticate.
///
/// Changing this will abort any ongoing authentication conversations and start a new one.
Q_PROPERTY(Identity* selectedIdentity READ default WRITE setSelectedIdentity NOTIFY selectedIdentityChanged BINDABLE selectedIdentity);
Q_PROPERTY(qs::service::polkit::Identity* selectedIdentity READ default WRITE setSelectedIdentity NOTIFY selectedIdentityChanged BINDABLE selectedIdentity);
/// Indicates that a response from the user is required from the user,
/// typically a password.
+1 -1
View File
@@ -47,7 +47,7 @@ class PolkitAgent
/// The current authentication state if an authentication request is active.
///
/// Null when no authentication request is active.
Q_PROPERTY(AuthFlow* flow READ default NOTIFY flowChanged BINDABLE flow);
Q_PROPERTY(qs::service::polkit::AuthFlow* flow READ default NOTIFY flowChanged BINDABLE flow);
public:
explicit PolkitAgent(QObject* parent = nullptr): QObject(parent) {};
+8 -1
View File
@@ -44,7 +44,7 @@ qt_add_qml_module(quickshell-service-statusnotifier
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-service-statusnotifier Quickshell Quickshell.DBusMenu)
qs_add_module_deps_light(quickshell-service-statusnotifier quickshell-core quickshell-dbusmenu)
install_qml_module(quickshell-service-statusnotifier)
@@ -52,3 +52,10 @@ target_link_libraries(quickshell-service-statusnotifier PRIVATE Qt::Quick Qt::DB
target_link_libraries(quickshell PRIVATE quickshell-service-statusnotifierplugin)
qs_module_pch(quickshell-service-statusnotifier SET dbus)
if (WAYLAND)
target_compile_definitions(quickshell-service-statusnotifier PRIVATE QS_WAYLAND)
target_link_libraries(quickshell-service-statusnotifier PRIVATE
quickshell-wayland-activation
)
endif()
+3 -3
View File
@@ -29,9 +29,9 @@ public:
static StatusNotifierHost* instance();
signals:
void itemRegistered(StatusNotifierItem* item);
void itemReady(StatusNotifierItem* item);
void itemUnregistered(StatusNotifierItem* item);
void itemRegistered(qs::service::sni::StatusNotifierItem* item);
void itemReady(qs::service::sni::StatusNotifierItem* item);
void itemUnregistered(qs::service::sni::StatusNotifierItem* item);
private slots:
void onWatcherRegistered();
+38
View File
@@ -12,6 +12,7 @@
#include <qobject.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qpointer.h>
#include <qqmlengine.h>
#include <qrect.h>
#include <qsize.h>
@@ -30,6 +31,10 @@
#include "host.hpp"
#include "watcher.hpp"
#ifdef QS_WAYLAND
#include "../../wayland/activation.hpp"
#endif
using namespace qs::dbus;
using namespace qs::dbus::dbusmenu;
using namespace qs::menu::platform;
@@ -219,6 +224,39 @@ QPixmap StatusNotifierItem::createPixmap(const QSize& size) const {
}
void StatusNotifierItem::activate() {
#ifdef QS_WAYLAND
auto callback = [item = QPointer(this)](const QString& token) {
if (item) item->activateWithToken(token);
};
if (qs::wayland::activation::requestActivationToken(callback)) return;
#endif
this->activateWithoutToken();
}
void StatusNotifierItem::activateWithToken(const QString& token) {
if (token.isEmpty()) {
this->activateWithoutToken();
return;
}
auto* call = new QDBusPendingCallWatcher(this->item->ProvideXdgActivationToken(token), this);
QObject::connect(
call,
&QDBusPendingCallWatcher::finished,
this,
[this](QDBusPendingCallWatcher* call) {
const QDBusPendingReply<> reply = *call;
if (reply.isError() && reply.error().type() != QDBusError::UnknownMethod) {
qCWarning(logStatusNotifierItem) << "Error providing activation token:" << reply.error();
}
delete call;
this->activateWithoutToken();
}
);
}
void StatusNotifierItem::activateWithoutToken() {
auto pendingCall = this->item->Activate(0, 0);
auto* call = new QDBusPendingCallWatcher(pendingCall, this);
+2
View File
@@ -169,6 +169,8 @@ private slots:
void onGetAllFailed() const;
private:
void activateWithToken(const QString& token);
void activateWithoutToken();
void updateMenuState();
void updatePixmapIndex();
void onMenuPathChanged();
@@ -29,6 +29,9 @@
<arg type="i" direction="in" name="x"/>
<arg type="i" direction="in" name="y"/>
</method>
<method name="ProvideXdgActivationToken">
<arg type="s" direction="in" name="token"/>
</method>
<method name="Activate">
<arg type="i" direction="in" name="x"/>
<arg type="i" direction="in" name="y"/>
+1 -1
View File
@@ -34,7 +34,7 @@ qt_add_qml_module(quickshell-service-upower
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-service-upower Quickshell)
qs_add_module_deps_light(quickshell-service-upower quickshell-core)
install_qml_module(quickshell-service-upower)
+11 -1
View File
@@ -73,6 +73,16 @@ endfunction()
# -----
wl_proto(wlp-xdg-activation xdg-activation-v1 "${WAYLAND_PROTOCOLS}/staging/xdg-activation")
qt_add_library(quickshell-wayland-activation STATIC
activation.cpp
)
target_link_libraries(quickshell-wayland-activation PRIVATE
Qt::Gui Qt::WaylandClient Qt::WaylandClientPrivate wlp-xdg-activation
)
qt_add_library(quickshell-wayland STATIC
wl_proxy_safe_deref.cpp
platformmenu.cpp
@@ -148,7 +158,7 @@ qt_add_qml_module(quickshell-wayland
IMPORTS ${WAYLAND_MODULES}
)
qs_add_module_deps_light(quickshell-wayland Quickshell)
qs_add_module_deps_light(quickshell-wayland quickshell-core)
install_qml_module(quickshell-wayland)
+89
View File
@@ -0,0 +1,89 @@
#include "activation.hpp"
#include <functional>
#include <utility>
#include <private/qwaylanddisplay_p.h>
#include <private/qwaylandinputdevice_p.h>
#include <private/qwaylandintegration_p.h>
#include <private/qwaylandwindow_p.h>
#include <qguiapplication.h>
#include <qnamespace.h>
#include <qobject.h>
#include <qpointer.h>
#include <qstring.h>
#include <qtclasshelpermacros.h>
#include <qtmetamacros.h>
#include <qtypes.h>
#include <qwayland-xdg-activation-v1.h>
#include <qwaylandclientextension.h>
#include "wayland-xdg-activation-v1-client-protocol.h"
namespace qs::wayland::activation {
namespace {
class ActivationManager
: public QWaylandClientExtensionTemplate<ActivationManager>
, public QtWayland::xdg_activation_v1 {
public:
ActivationManager(): QWaylandClientExtensionTemplate(1) { this->initialize(); }
};
class ActivationToken
: public QObject
, public QtWayland::xdg_activation_token_v1 {
public:
ActivationToken(::xdg_activation_token_v1* token, QtWaylandClient::QWaylandWindow* window)
: QObject(window)
, QtWayland::xdg_activation_token_v1(token)
, window(window) {}
~ActivationToken() override { this->destroy(); }
Q_DISABLE_COPY_MOVE(ActivationToken);
private:
void xdg_activation_token_v1_done(const QString& token) override {
this->deleteLater();
if (this->window) emit this->window->xdgActivationTokenCreated(token);
}
QPointer<QtWaylandClient::QWaylandWindow> window;
};
} // namespace
bool requestActivationToken(std::function<void(const QString&)> callback) {
if (QGuiApplication::platformName() != "wayland") return false;
auto* display = QtWaylandClient::QWaylandIntegration::instance()->display();
auto* window = display->lastInputWindow();
if (!window || !window->surface() || !display->lastInputDevice()) return false;
QObject::connect(
window,
&QtWaylandClient::QWaylandWindow::xdgActivationTokenCreated,
window,
std::move(callback),
Qt::SingleShotConnection
);
window->requestXdgActivationToken(display->lastInputSerial());
return true;
}
void requestXdgActivationToken(QtWaylandClient::QWaylandWindow* window, quint32 serial) {
auto* display = window->display();
auto* seat = display->lastInputDevice();
static auto* manager = new ActivationManager(); // NOLINT
if (!manager->isActive() || !window->surface() || !seat) {
emit window->xdgActivationTokenCreated({});
return;
}
auto* token = new ActivationToken(manager->get_activation_token(), window);
token->set_serial(serial, seat->object());
token->set_surface(window->surface());
token->commit();
}
} // namespace qs::wayland::activation
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <functional>
#include <qstring.h>
#include <qtypes.h>
namespace QtWaylandClient { // NOLINT(readability-identifier-naming)
class QWaylandWindow;
}
namespace qs::wayland::activation {
// Request a token using Qt's most recent input event. Returns false if unable to request a token.
bool requestActivationToken(std::function<void(const QString&)> callback);
// Request an activation token for a window to be delivered via QWaylandWindow::xdgActivationTokenCreated
void requestXdgActivationToken(QtWaylandClient::QWaylandWindow* window, quint32 serial);
} // namespace qs::wayland::activation
@@ -10,6 +10,8 @@ qt_add_qml_module(quickshell-wayland-background-effect
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-wayland-background-effect quickshell-core)
install_qml_module(quickshell-wayland-background-effect)
wl_proto(wlp-background-effect ext-background-effect-v1 "${WAYLAND_PROTOCOLS}/staging/ext-background-effect")
+1 -1
View File
@@ -30,7 +30,7 @@ qt_add_qml_module(quickshell-hyprland
IMPORTS ${HYPRLAND_MODULES}
)
qs_add_module_deps_light(quickshell-io Quickshell)
qs_add_module_deps_light(quickshell-hyprland quickshell-core)
install_qml_module(quickshell-hyprland)
# intentionally no pch as the module is empty
@@ -10,7 +10,7 @@ qt_add_qml_module(quickshell-hyprland-focus-grab
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-hyprland-focus-grab Quickshell)
qs_add_module_deps_light(quickshell-hyprland-focus-grab quickshell-core)
install_qml_module(quickshell-hyprland-focus-grab)
+3 -1
View File
@@ -11,13 +11,15 @@ qt_add_qml_module(quickshell-hyprland-ipc
DEPENDENCIES QtQuick
)
qs_add_module_deps_light(quickshell-hyprland-ipc Quickshell)
qs_add_module_deps_light(quickshell-hyprland-ipc quickshell-core)
install_qml_module(quickshell-hyprland-ipc)
target_link_libraries(quickshell-hyprland-ipc PRIVATE Qt::Quick quickshell-core)
if (WAYLAND_TOPLEVEL_MANAGEMENT)
qs_add_module_deps_light(quickshell-hyprland-ipc quickshell-wayland-toplevel-management)
target_sources(quickshell-hyprland-ipc PRIVATE
toplevel_mapping.cpp
hyprland_toplevel.cpp
+25
View File
@@ -452,6 +452,31 @@ void HyprlandIpc::onEvent(HyprlandIpcEvent* event) {
<< (*workspaceIter)->bindableName().value() << "to" << name;
(*workspaceIter)->bindableName().setValue(name);
} else if (event->name == "changeworkspaceid") {
auto args = event->parseView(2);
auto oldAddress = QString::fromUtf8(args.at(0));
auto newAddress = QString::fromUtf8(args.at(1));
const auto& mList = this->mWorkspaces.valueList();
auto workspaceIter = std::ranges::find_if(mList, [&](HyprlandWorkspace* m) {
return m->bindableAddress().value() == oldAddress;
});
if (workspaceIter == mList.end()) return;
auto* workspace = *workspaceIter;
qCDebug(logHyprlandIpc) << "Workspace with address" << oldAddress << "changed id to"
<< newAddress;
// Hyprland names a workspace after its new id unless it was renamed.
auto name = workspace->bindableName().value();
if (name == oldAddress) name = newAddress;
// The list is sorted by id, so the workspace moves to its new place in it.
this->mWorkspaces.removeObject(workspace);
workspace->updateInitial(newAddress, name);
this->mWorkspaces.insertObjectSorted(workspace, &HyprlandIpc::compareWorkspaces);
} else if (event->name == "fullscreen") {
if (auto* workspace = this->bFocusedWorkspace.value()) {
workspace->bindableHasFullscreen().setValue(event->data == "1");
+1 -1
View File
@@ -112,7 +112,7 @@ public:
signals:
void connected();
void rawEvent(HyprlandIpcEvent* event);
void rawEvent(qs::hyprland::ipc::HyprlandIpcEvent* event);
void usingLuaChanged();
void focusedMonitorChanged();
@@ -28,7 +28,7 @@ class HyprlandToplevel: public QObject {
Q_PROPERTY(QString address READ addressStr NOTIFY addressChanged);
/// The toplevel handle, exposing the Hyprland toplevel.
/// Will be null until the address is reported
Q_PROPERTY(HyprlandToplevel* handle READ hyprlandHandle NOTIFY hyprlandHandleChanged);
Q_PROPERTY(qs::hyprland::ipc::HyprlandToplevel* handle READ hyprlandHandle NOTIFY hyprlandHandleChanged);
/// The wayland toplevel handle. Will be null intil the address is reported
Q_PROPERTY(qs::wayland::toplevel::Toplevel* wayland READ waylandHandle NOTIFY waylandHandleChanged);
/// The title of the toplevel
+1 -1
View File
@@ -52,7 +52,7 @@ public:
Q_INVOKABLE static void dispatch(const QString& request);
/// Get the HyprlandMonitor object that corresponds to a quickshell screen.
Q_INVOKABLE static HyprlandMonitor* monitorFor(QuickshellScreenInfo* screen);
Q_INVOKABLE static qs::hyprland::ipc::HyprlandMonitor* monitorFor(QuickshellScreenInfo* screen);
/// Refresh monitor information.
///
@@ -10,6 +10,8 @@ qt_add_qml_module(quickshell-hyprland-surface-extensions
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-hyprland-surface-extensions quickshell-core)
install_qml_module(quickshell-hyprland-surface-extensions)
wl_proto(wlp-hyprland-surface hyprland-surface-v1 "${CMAKE_CURRENT_SOURCE_DIR}")
+1 -1
View File
@@ -11,7 +11,7 @@ qt_add_qml_module(quickshell-wayland-idle-inhibit
install_qml_module(quickshell-wayland-idle-inhibit)
qs_add_module_deps_light(quickshell-wayland-idle-inhibit Quickshell)
qs_add_module_deps_light(quickshell-wayland-idle-inhibit quickshell-core)
wl_proto(wlp-idle-inhibit idle-inhibit-unstable-v1 "${WAYLAND_PROTOCOLS}/unstable/idle-inhibit")
+1 -1
View File
@@ -11,7 +11,7 @@ qt_add_qml_module(quickshell-wayland-idle-notify
install_qml_module(quickshell-wayland-idle-notify)
qs_add_module_deps_light(quickshell-wayland-idle-notify Quickshell)
qs_add_module_deps_light(quickshell-wayland-idle-notify quickshell-core)
wl_proto(wlp-idle-notify ext-idle-notify-v1 "${WAYLAND_PROTOCOLS}/staging/ext-idle-notify")
@@ -220,6 +220,8 @@ IccOutputSourceManager* IccOutputSourceManager::instance() {
}
ScreencopyContext* IccOutputSourceManager::captureOutput(QScreen* screen, bool paintCursors) {
if (screen == nullptr) return nullptr;
auto* waylandScreen = dynamic_cast<QtWaylandClient::QWaylandScreen*>(screen->handle());
if (!waylandScreen) return nullptr;
+2
View File
@@ -25,6 +25,8 @@ namespace qs::wayland::screencopy {
ScreencopyContext* ScreencopyManager::createContext(QObject* object, bool paintCursors) {
if (auto* screen = qobject_cast<QuickshellScreenInfo*>(object)) {
if (screen->screen == nullptr) return nullptr;
#if SCREENCOPY_ICC
{
auto* manager = icc::IccOutputSourceManager::instance();
@@ -34,6 +34,7 @@ WlrScreencopyManager* WlrScreencopyManager::instance() {
ScreencopyContext*
WlrScreencopyManager::captureOutput(QScreen* screen, bool paintCursors, QRect region) {
if (screen == nullptr) return nullptr;
if (!dynamic_cast<QtWaylandClient::QWaylandScreen*>(screen->handle())) return nullptr;
return new WlrScreencopyContext(this, screen, paintCursors, region);
}
+2 -1
View File
@@ -179,8 +179,9 @@ void WlSessionLock::unlock() {
this->surfaces.clear();
auto wasLocked = this->isLocked();
if (this->manager) this->manager->unlock();
if (this->isLocked()) emit this->lockStateChanged();
if (wasLocked) emit this->lockStateChanged();
}
void WlSessionLock::onScreensChanged() {
+1 -1
View File
@@ -11,7 +11,7 @@ qt_add_qml_module(quickshell-wayland-shortcuts-inhibit
install_qml_module(quickshell-wayland-shortcuts-inhibit)
qs_add_module_deps_light(quickshell-wayland-shortcuts-inhibit Quickshell)
qs_add_module_deps_light(quickshell-wayland-shortcuts-inhibit quickshell-core)
wl_proto(wlp-shortcuts-inhibit keyboard-shortcuts-inhibit-unstable-v1 "${WAYLAND_PROTOCOLS}/unstable/keyboard-shortcuts-inhibit")
+2 -1
View File
@@ -10,7 +10,8 @@ qt_add_qml_module(quickshell-wayland-toplevel-management
)
qs_add_module_deps_light(quickshell-wayland-toplevel-management
Quickshell Quickshell.Wayland
quickshell-core
URIS Quickshell.Wayland
)
install_qml_module(quickshell-wayland-toplevel-management)
+1 -1
View File
@@ -94,7 +94,7 @@ public:
static ToplevelManager* instance();
signals:
void toplevelReady(ToplevelHandle* toplevel);
void toplevelReady(qs::wayland::toplevel::wlr::ToplevelHandle* toplevel);
protected:
explicit ToplevelManager();
+4 -4
View File
@@ -33,10 +33,10 @@ public:
signals:
void serverCommit();
void workspaceCreated(Workspace* workspace);
void workspaceDestroyed(Workspace* workspace);
void groupCreated(WorkspaceGroup* group);
void groupDestroyed(WorkspaceGroup* group);
void workspaceCreated(qs::wayland::workspace::Workspace* workspace);
void workspaceDestroyed(qs::wayland::workspace::Workspace* workspace);
void groupCreated(qs::wayland::workspace::WorkspaceGroup* group);
void groupDestroyed(qs::wayland::workspace::WorkspaceGroup* group);
protected:
void ext_workspace_manager_v1_workspace_group(::ext_workspace_group_handle_v1* handle) override;
+5 -2
View File
@@ -10,7 +10,10 @@ qt_add_qml_module(quickshell-wayland-layershell
DEPENDENCIES QtQuick
)
qs_add_module_deps_light(quickshell-wayland-layershell Quickshell Quickshell.Wayland)
qs_add_module_deps_light(quickshell-wayland-layershell
quickshell-core quickshell-window
URIS Quickshell.Wayland
)
install_qml_module(quickshell-wayland-layershell)
@@ -21,7 +24,7 @@ wl_proto(wlp-xdg-shell xdg-shell "${WAYLAND_PROTOCOLS}/stable/xdg-shell")
target_link_libraries(quickshell-wayland-layershell PRIVATE
Qt::Quick Qt::WaylandClient Qt::WaylandClientPrivate wayland-client
wlp-layer-shell wlp-xdg-shell
wlp-layer-shell wlp-xdg-shell quickshell-wayland-activation
)
qs_module_pch(quickshell-wayland-layershell SET large)
+5
View File
@@ -20,6 +20,7 @@
#include <wayland-xdg-shell-client-protocol.h>
#include "../../window/panelinterface.hpp"
#include "../activation.hpp"
#include "shell_integration.hpp"
#include "wlr_layershell.hpp"
@@ -130,6 +131,10 @@ LayerSurfaceBridge* LayerSurfaceBridge::init(QWindow* window, LayerSurfaceState
return bridge;
}
void LayerSurface::requestXdgActivationToken(quint32 serial) {
activation::requestXdgActivationToken(this->window(), serial);
}
LayerSurface::LayerSurface(LayerShellIntegration* shell, QtWaylandClient::QWaylandWindow* window)
: QtWaylandClient::QWaylandShellSurface(window) {
+2
View File
@@ -66,6 +66,8 @@ public:
void applyConfigure() override;
void setWindowGeometry(const QRect& /*geometry*/) override {}
void requestXdgActivationToken(quint32 serial) override;
void attachPopup(QtWaylandClient::QWaylandShellSurface* popup) override;
void commit();
+1 -1
View File
@@ -12,7 +12,7 @@ qt_add_qml_module(quickshell-window
DEPENDENCIES QtQuick
)
qs_add_module_deps_light(quickshell-window Quickshell)
qs_add_module_deps_light(quickshell-window quickshell-core)
install_qml_module(quickshell-window)
+1 -1
View File
@@ -10,7 +10,7 @@ qt_add_qml_module(quickshell-windowmanager
DEPENDENCIES QtQuick
)
qs_add_module_deps_light(quickshell-windowmanager Quickshell)
qs_add_module_deps_light(quickshell-windowmanager quickshell-core)
install_qml_module(quickshell-windowmanager)
+4 -4
View File
@@ -23,7 +23,7 @@ public:
static void setProvider(std::function<WindowManager*()> provider);
static WindowManager* instance();
Q_INVOKABLE ScreenProjection* screenProjection(QuickshellScreenInfo* screen);
Q_INVOKABLE qs::wm::ScreenProjection* screenProjection(QuickshellScreenInfo* screen);
[[nodiscard]] QBindable<QList<Windowset*>> bindableWindowsets() const {
return &this->bWindowsets;
@@ -64,10 +64,10 @@ class WindowManagerQml: public QObject {
QML_SINGLETON;
// clang-format off
/// All windowsets tracked by the WM across all projections.
Q_PROPERTY(QList<Windowset*> windowsets READ default BINDABLE bindableWindowsets);
Q_PROPERTY(QList<qs::wm::Windowset*> windowsets READ default BINDABLE bindableWindowsets);
/// All windowset projections tracked by the WM. Does not include
/// internal projections from @@screenProjection().
Q_PROPERTY(QList<WindowsetProjection*> windowsetProjections READ default BINDABLE bindableWindowsetProjections);
Q_PROPERTY(QList<qs::wm::WindowsetProjection*> windowsetProjections READ default BINDABLE bindableWindowsetProjections);
// clang-format on
public:
@@ -75,7 +75,7 @@ public:
/// windowsets on that screen, regardless of the WM-specified projection. Depending on
/// how the WM lays out its actual projections, multiple ScreenProjections may contain
/// the same Windowsets.
Q_INVOKABLE static ScreenProjection* screenProjection(QuickshellScreenInfo* screen) {
Q_INVOKABLE static qs::wm::ScreenProjection* screenProjection(QuickshellScreenInfo* screen) {
return WindowManager::instance()->screenProjection(screen);
}
+3 -3
View File
@@ -41,7 +41,7 @@ class Windowset: public QObject {
Q_PROPERTY(bool active READ default NOTIFY activeChanged BINDABLE bindableActive);
/// The projection this windowset is a member of. A projection is the set of screens covered by
/// a windowset.
Q_PROPERTY(WindowsetProjection* projection READ default NOTIFY projectionChanged BINDABLE bindableProjection);
Q_PROPERTY(qs::wm::WindowsetProjection* projection READ default NOTIFY projectionChanged BINDABLE bindableProjection);
/// If false, this windowset should generally be hidden from workspace pickers.
Q_PROPERTY(bool shouldDisplay READ default NOTIFY shouldDisplayChanged BINDABLE bindableShouldDisplay);
/// If true, a window in this windowset has been marked as urgent.
@@ -70,7 +70,7 @@ public:
Q_INVOKABLE virtual void remove();
/// Move the windowset to a different projection. A projection represents the set of screens
/// a workspace spans. Requires @@canSetProjection.
Q_INVOKABLE virtual void setProjection(WindowsetProjection* projection);
Q_INVOKABLE virtual void setProjection(qs::wm::WindowsetProjection* projection);
[[nodiscard]] QBindable<QString> bindableId() const { return &this->bId; }
[[nodiscard]] QBindable<QString> bindableName() const { return &this->bName; }
@@ -134,7 +134,7 @@ class WindowsetProjection: public QObject {
/// Screens the windowset projection spans, often a single screen or all screens.
Q_PROPERTY(QList<QuickshellScreenInfo*> screens READ screens NOTIFY screensChanged);
/// Windowsets that are currently present on the projection.
Q_PROPERTY(QList<Windowset*> windowsets READ default NOTIFY windowsetsChanged BINDABLE bindableWindowsets);
Q_PROPERTY(QList<qs::wm::Windowset*> windowsets READ default NOTIFY windowsetsChanged BINDABLE bindableWindowsets);
// clang-format on
public:
+2
View File
@@ -11,6 +11,8 @@ qt_add_qml_module(quickshell-x11
DEPENDENCIES QtQuick
)
qs_add_module_deps_light(quickshell-x11 quickshell-core quickshell-window)
install_qml_module(quickshell-x11)
add_library(quickshell-x11-init OBJECT init.cpp)
+1 -1
View File
@@ -13,7 +13,7 @@ qt_add_qml_module(quickshell-i3-ipc
DEPENDENCIES QtQml
)
qs_add_module_deps_light(quickshell-i3-ipc Quickshell)
qs_add_module_deps_light(quickshell-i3-ipc quickshell-core)
install_qml_module(quickshell-i3-ipc)
+1 -1
View File
@@ -80,7 +80,7 @@ public:
signals:
void connected();
void rawEvent(I3IpcEvent* event);
void rawEvent(qs::i3::ipc::I3IpcEvent* event);
protected slots:
void eventSocketError(QLocalSocket::LocalSocketError error) const;
+1 -1
View File
@@ -56,7 +56,7 @@ signals:
private slots:
void onFocusedMonitorDestroyed();
void onEvent(I3IpcEvent* event);
void onEvent(qs::i3::ipc::I3IpcEvent* event);
void onConnected();
private:
+1 -1
View File
@@ -52,7 +52,7 @@ public:
void setSubscriptions(QList<QString> subscriptions);
signals:
void ipcEvent(I3IpcEvent* event);
void ipcEvent(qs::i3::ipc::I3IpcEvent* event);
void subscriptionsChanged();
private:
+4 -4
View File
@@ -43,13 +43,13 @@ public:
Q_INVOKABLE static void refreshWorkspaces();
/// Find an I3Workspace using its name, returns null if the workspace doesn't exist.
Q_INVOKABLE static I3Workspace* findWorkspaceByName(const QString& name);
Q_INVOKABLE static qs::i3::ipc::I3Workspace* findWorkspaceByName(const QString& name);
/// Find an I3Monitor using its name, returns null if the monitor doesn't exist.
Q_INVOKABLE static I3Monitor* findMonitorByName(const QString& name);
Q_INVOKABLE static qs::i3::ipc::I3Monitor* findMonitorByName(const QString& name);
/// Return the i3/Sway monitor associated with `screen`
Q_INVOKABLE static I3Monitor* monitorFor(QuickshellScreenInfo* screen);
Q_INVOKABLE static qs::i3::ipc::I3Monitor* monitorFor(QuickshellScreenInfo* screen);
/// The path to the I3 or Sway socket currently being used
[[nodiscard]] static QString socketPath();
@@ -67,7 +67,7 @@ public:
[[nodiscard]] static QBindable<I3Monitor*> bindableFocusedMonitor();
signals:
void rawEvent(I3IpcEvent* event);
void rawEvent(qs::i3::ipc::I3IpcEvent* event);
void connected();
void focusedWorkspaceChanged();
void focusedMonitorChanged();