core/command: filter instance selection by current display

This commit is contained in:
outfoxxed 2025-10-12 17:33:21 -07:00
parent 1e8cc2e78d
commit 00858812f2
No known key found for this signature in database
GPG key ID: 4C88A185FB89301E
9 changed files with 50 additions and 9 deletions

View file

@ -4,6 +4,10 @@
- Added support for wayland idle timeouts.
- Added the ability to override Quickshell.cacheDir with a custom path.
## Other Changes
- IPC operations filter available instances to the current display connection by default.
## Bug Fixes
- Fixed volume control breaking with pipewire pro audio mode.

View file

@ -3,12 +3,14 @@
#include <qdatastream.h>
QDataStream& operator<<(QDataStream& stream, const InstanceInfo& info) {
stream << info.instanceId << info.configPath << info.shellId << info.launchTime << info.pid;
stream << info.instanceId << info.configPath << info.shellId << info.launchTime << info.pid
<< info.display;
return stream;
}
QDataStream& operator>>(QDataStream& stream, InstanceInfo& info) {
stream >> info.instanceId >> info.configPath >> info.shellId >> info.launchTime >> info.pid;
stream >> info.instanceId >> info.configPath >> info.shellId >> info.launchTime >> info.pid
>> info.display;
return stream;
}

View file

@ -11,6 +11,7 @@ struct InstanceInfo {
QString shellId;
QDateTime launchTime;
pid_t pid = -1;
QString display;
static InstanceInfo CURRENT; // NOLINT
};

View file

@ -411,7 +411,7 @@ bool QsPaths::checkLock(const QString& path, InstanceLockInfo* info, bool allowD
}
QPair<QVector<InstanceLockInfo>, QVector<InstanceLockInfo>>
QsPaths::collectInstances(const QString& path) {
QsPaths::collectInstances(const QString& path, const QString& display) {
qCDebug(logPaths) << "Collecting instances from" << path;
auto liveInstances = QVector<InstanceLockInfo>();
auto deadInstances = QVector<InstanceLockInfo>();
@ -425,6 +425,11 @@ QsPaths::collectInstances(const QString& path) {
qCDebug(logPaths).nospace() << "Found instance " << info.instance.instanceId << " (pid "
<< info.pid << ") at " << path;
if (!display.isEmpty() && info.instance.display != display) {
qCDebug(logPaths) << "Skipped instance with mismatched display at" << path;
continue;
}
if (info.pid == -1) {
deadInstances.push_back(info);
} else {

View file

@ -30,7 +30,7 @@ public:
static bool
checkLock(const QString& path, InstanceLockInfo* info = nullptr, bool allowDead = false);
static QPair<QVector<InstanceLockInfo>, QVector<InstanceLockInfo>>
collectInstances(const QString& path);
collectInstances(const QString& path, const QString& display);
QDir* baseRunDir();
QDir* shellRunDir();

View file

@ -13,6 +13,7 @@
#include <qdebug.h>
#include <qdir.h>
#include <qfileinfo.h>
#include <qguiapplication.h>
#include <qjsonarray.h>
#include <qjsondocument.h>
#include <qjsonobject.h>
@ -178,7 +179,8 @@ int selectInstance(CommandState& cmd, InstanceLockInfo* instance, bool deadFallb
}
} else if (!cmd.instance.id->isEmpty()) {
path = basePath->filePath("by-pid");
auto [liveInstances, deadInstances] = QsPaths::collectInstances(path);
auto [liveInstances, deadInstances] =
QsPaths::collectInstances(path, cmd.config.anyDisplay ? "" : getDisplayConnection());
liveInstances.removeIf([&](const InstanceLockInfo& info) {
return !info.instance.instanceId.startsWith(*cmd.instance.id);
@ -228,7 +230,8 @@ int selectInstance(CommandState& cmd, InstanceLockInfo* instance, bool deadFallb
path = QDir(basePath->filePath("by-path")).filePath(pathId);
auto [liveInstances, deadInstances] = QsPaths::collectInstances(path);
auto [liveInstances, deadInstances] =
QsPaths::collectInstances(path, cmd.config.anyDisplay ? "" : getDisplayConnection());
auto instances = liveInstances;
if (instances.isEmpty() && deadFallback) {
@ -311,7 +314,10 @@ int listInstances(CommandState& cmd) {
path = QDir(basePath->filePath("by-path")).filePath(pathId);
}
auto [liveInstances, deadInstances] = QsPaths::collectInstances(path);
auto [liveInstances, deadInstances] = QsPaths::collectInstances(
path,
cmd.config.anyDisplay || cmd.instance.all ? "" : getDisplayConnection()
);
sortInstances(liveInstances, cmd.config.newest);
@ -373,6 +379,7 @@ int listInstances(CommandState& cmd) {
<< " Process ID: " << instance.instance.pid << '\n'
<< " Shell ID: " << instance.instance.shellId << '\n'
<< " Config path: " << instance.instance.configPath << '\n'
<< " Display connection: " << instance.instance.display << '\n'
<< " Launch time: " << launchTimeStr
<< (isDead ? "" : " (running for " + runtimeStr + ")") << '\n'
<< (gray ? "\033[0m" : "");
@ -545,4 +552,18 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) {
return 0;
}
QString getDisplayConnection() {
auto platform = qEnvironmentVariable("QT_QPA_PLATFORM");
auto wlDisplay = qEnvironmentVariable("WAYLAND_DISPLAY");
auto xDisplay = qEnvironmentVariable("DISPLAY");
if (platform == "wayland" || (platform.isEmpty() && !wlDisplay.isEmpty())) {
return "wayland," + wlDisplay;
} else if (platform == "xcb" || (platform.isEmpty() && !xDisplay.isEmpty())) {
return "x11," + xDisplay;
} else {
return "unk," + QGuiApplication::platformName();
}
}
} // namespace qs::launch

View file

@ -134,6 +134,7 @@ int launch(const LaunchArgs& args, char** argv, QCoreApplication* coreApplicatio
.shellId = shellId,
.launchTime = qs::Common::LAUNCH_TIME,
.pid = getpid(),
.display = getDisplayConnection(),
};
#if CRASH_REPORTER

View file

@ -50,6 +50,7 @@ struct CommandState {
QStringOption manifest;
QStringOption name;
bool newest = false;
bool anyDisplay = false;
} config;
struct {
@ -106,6 +107,8 @@ void exitDaemon(int code);
int parseCommand(int argc, char** argv, CommandState& state);
int runCommand(int argc, char** argv, QCoreApplication* coreApplication);
QString getDisplayConnection();
int launch(const LaunchArgs& args, char** argv, QCoreApplication* coreApplication);
} // namespace qs::launch

View file

@ -16,7 +16,7 @@ int parseCommand(int argc, char** argv, CommandState& state) {
.argv = argv,
};
auto addConfigSelection = [&](CLI::App* cmd, bool withNewestOption = false) {
auto addConfigSelection = [&](CLI::App* cmd, bool filtering = false) {
auto* group =
cmd->add_option_group("Config Selection")
->description(
@ -49,9 +49,13 @@ int parseCommand(int argc, char** argv, CommandState& state) {
->envname("QS_MANIFEST")
->excludes(path);
if (withNewestOption) {
if (filtering) {
group->add_flag("-n,--newest", state.config.newest)
->description("Operate on the most recently launched instance instead of the oldest");
group->add_flag("--any-display", state.config.anyDisplay)
->description("If passed, instances will not be filtered by the display connection they "
"were launched on.");
}
return group;