mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Swaybackend for output management and Wayland connection handling.
This commit is contained in:
@@ -1,6 +1,73 @@
|
||||
#include "compositors/sway/sway_output_backend.h"
|
||||
|
||||
#include "core/log.h"
|
||||
#include "core/process.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <json.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr Logger kLog("sway_output");
|
||||
|
||||
[[nodiscard]] std::optional<std::string> parseFocusedOutputName(std::string_view payload) {
|
||||
if (payload.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
try {
|
||||
const auto json = nlohmann::json::parse(payload);
|
||||
if (!json.is_array()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
for (const auto& item : json) {
|
||||
if (!item.is_object() || !item.value("focused", false)) {
|
||||
continue;
|
||||
}
|
||||
if (auto it = item.find("name"); it != item.end() && it->is_string()) {
|
||||
const auto value = StringUtils::trim(it->get<std::string>());
|
||||
if (!value.empty()) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const nlohmann::json::exception&) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SwayOutputBackend::SwayOutputBackend(std::string_view compositorHint) {
|
||||
const bool hinted = StringUtils::containsInsensitive(compositorHint, "sway");
|
||||
const char* swaySocket = std::getenv("SWAYSOCK");
|
||||
const char* i3Socket = std::getenv("I3SOCK");
|
||||
m_enabled = hinted || (swaySocket != nullptr && swaySocket[0] != '\0') || (i3Socket != nullptr && i3Socket[0] != '\0');
|
||||
}
|
||||
|
||||
bool SwayOutputBackend::isAvailable() const noexcept { return m_enabled; }
|
||||
|
||||
std::optional<std::string> SwayOutputBackend::focusedOutputName() const {
|
||||
if (!m_enabled) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const char* msgCommand = process::commandExists("scrollmsg") ? "scrollmsg" : "swaymsg";
|
||||
if (!process::commandExists(msgCommand)) {
|
||||
msgCommand = "i3-msg";
|
||||
}
|
||||
|
||||
const auto result = process::runSync({msgCommand, "-t", "get_outputs", "-r"});
|
||||
if (!result) {
|
||||
kLog.debug("failed to resolve focused output via {}", msgCommand);
|
||||
return std::nullopt;
|
||||
}
|
||||
return parseFocusedOutputName(result.out);
|
||||
}
|
||||
|
||||
namespace compositors::sway {
|
||||
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
class SwayOutputBackend {
|
||||
public:
|
||||
explicit SwayOutputBackend(std::string_view compositorHint);
|
||||
|
||||
[[nodiscard]] bool isAvailable() const noexcept;
|
||||
[[nodiscard]] std::optional<std::string> focusedOutputName() const;
|
||||
|
||||
private:
|
||||
bool m_enabled = false;
|
||||
};
|
||||
|
||||
namespace compositors::sway {
|
||||
|
||||
[[nodiscard]] bool setOutputPower(bool on);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "compositors/compositor_detect.h"
|
||||
#include "compositors/niri/niri_output_backend.h"
|
||||
#include "compositors/niri/niri_workspace_backend.h"
|
||||
#include "compositors/sway/sway_output_backend.h"
|
||||
#include "core/log.h"
|
||||
#include "cursor-shape-v1-client-protocol.h"
|
||||
#include "dwl-ipc-unstable-v2-client-protocol.h"
|
||||
@@ -204,6 +205,7 @@ bool WaylandConnection::connect() {
|
||||
const std::string compositorHint(compositors::envHint());
|
||||
m_workspacesHandler.initialize(compositorHint);
|
||||
m_niriOutputBackend = std::make_unique<NiriOutputBackend>(compositorHint);
|
||||
m_swayOutputBackend = std::make_unique<SwayOutputBackend>(compositorHint);
|
||||
m_niriWorkspaceBackend = std::make_unique<NiriWorkspaceBackend>(compositorHint);
|
||||
logStartupSummary();
|
||||
return true;
|
||||
@@ -329,6 +331,19 @@ wl_output* WaylandConnection::preferredPanelOutput(std::chrono::milliseconds poi
|
||||
}
|
||||
}
|
||||
|
||||
if (m_swayOutputBackend != nullptr && m_swayOutputBackend->isAvailable()) {
|
||||
if (const auto focusedName = m_swayOutputBackend->focusedOutputName(); focusedName.has_value()) {
|
||||
for (const auto& output : m_outputs) {
|
||||
if (output.output == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (output.connectorName == *focusedName || output.description == *focusedName) {
|
||||
return output.output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wl_output* output = activeToplevelOutput(); output != nullptr) {
|
||||
return output;
|
||||
}
|
||||
@@ -1103,6 +1118,7 @@ void WaylandConnection::cleanup() {
|
||||
m_hasMangoWorkspaceGlobal = false;
|
||||
m_hasForeignToplevelManagerGlobal = false;
|
||||
m_niriOutputBackend.reset();
|
||||
m_swayOutputBackend.reset();
|
||||
}
|
||||
|
||||
void WaylandConnection::logStartupSummary() const {
|
||||
|
||||
@@ -43,6 +43,7 @@ class ClipboardService;
|
||||
class FocusGrabService;
|
||||
class NiriOutputBackend;
|
||||
class NiriWorkspaceBackend;
|
||||
class SwayOutputBackend;
|
||||
struct DataControlOps;
|
||||
class VirtualKeyboardService;
|
||||
|
||||
@@ -244,6 +245,7 @@ private:
|
||||
wl_output* m_lastPointerOutput = nullptr;
|
||||
std::chrono::steady_clock::time_point m_lastPointerOutputAt{};
|
||||
std::unique_ptr<NiriOutputBackend> m_niriOutputBackend;
|
||||
std::unique_ptr<SwayOutputBackend> m_swayOutputBackend;
|
||||
std::unique_ptr<NiriWorkspaceBackend> m_niriWorkspaceBackend;
|
||||
WaylandSeat::PointerEventCallback m_pointerEventCallback;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user