mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
feat(widgets): add idle inhibitor
This commit is contained in:
@@ -71,6 +71,8 @@ set(XDG_ACTIVATION_XML
|
||||
"${WAYLAND_PROTOCOLS_PKGDATADIR}/staging/xdg-activation/xdg-activation-v1.xml")
|
||||
set(EXT_SESSION_LOCK_XML
|
||||
"${WAYLAND_PROTOCOLS_PKGDATADIR}/staging/ext-session-lock/ext-session-lock-v1.xml")
|
||||
set(IDLE_INHIBIT_XML
|
||||
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml")
|
||||
set(WLR_FOREIGN_TOPLEVEL_XML
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/protocols/wlr-foreign-toplevel-management-unstable-v1.xml")
|
||||
set(WLR_DATA_CONTROL_XML
|
||||
@@ -110,6 +112,10 @@ set(EXT_SESSION_LOCK_PROTOCOL_C
|
||||
"${GENERATED_PROTOCOL_DIR}/ext-session-lock-v1-client-protocol.c")
|
||||
set(EXT_SESSION_LOCK_PROTOCOL_H
|
||||
"${GENERATED_PROTOCOL_DIR}/ext-session-lock-v1-client-protocol.h")
|
||||
set(IDLE_INHIBIT_PROTOCOL_C
|
||||
"${GENERATED_PROTOCOL_DIR}/idle-inhibit-unstable-v1-client-protocol.c")
|
||||
set(IDLE_INHIBIT_PROTOCOL_H
|
||||
"${GENERATED_PROTOCOL_DIR}/idle-inhibit-unstable-v1-client-protocol.h")
|
||||
set(WLR_FOREIGN_TOPLEVEL_PROTOCOL_C
|
||||
"${GENERATED_PROTOCOL_DIR}/wlr-foreign-toplevel-management-unstable-v1-client-protocol.c")
|
||||
set(WLR_FOREIGN_TOPLEVEL_PROTOCOL_H
|
||||
@@ -262,6 +268,20 @@ add_custom_command(
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${IDLE_INHIBIT_PROTOCOL_C}"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" private-code "${IDLE_INHIBIT_XML}" "${IDLE_INHIBIT_PROTOCOL_C}"
|
||||
DEPENDS "${IDLE_INHIBIT_XML}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${IDLE_INHIBIT_PROTOCOL_H}"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" client-header "${IDLE_INHIBIT_XML}" "${IDLE_INHIBIT_PROTOCOL_H}"
|
||||
DEPENDS "${IDLE_INHIBIT_XML}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${WLR_FOREIGN_TOPLEVEL_PROTOCOL_C}"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" private-code "${WLR_FOREIGN_TOPLEVEL_XML}" "${WLR_FOREIGN_TOPLEVEL_PROTOCOL_C}"
|
||||
@@ -310,6 +330,8 @@ add_custom_target(noctalia_wayland_protocols
|
||||
"${XDG_ACTIVATION_PROTOCOL_H}"
|
||||
"${EXT_SESSION_LOCK_PROTOCOL_C}"
|
||||
"${EXT_SESSION_LOCK_PROTOCOL_H}"
|
||||
"${IDLE_INHIBIT_PROTOCOL_C}"
|
||||
"${IDLE_INHIBIT_PROTOCOL_H}"
|
||||
"${WLR_FOREIGN_TOPLEVEL_PROTOCOL_C}"
|
||||
"${WLR_FOREIGN_TOPLEVEL_PROTOCOL_H}"
|
||||
"${WLR_DATA_CONTROL_PROTOCOL_C}"
|
||||
@@ -336,6 +358,7 @@ add_executable(noctalia
|
||||
src/dbus/upower/upower_service.cpp
|
||||
src/debug/debug_service.cpp
|
||||
src/font/font_service.cpp
|
||||
src/idle/idle_inhibitor.cpp
|
||||
src/ipc/ipc_client.cpp
|
||||
src/ipc/ipc_service.cpp
|
||||
src/launcher/app_provider.cpp
|
||||
@@ -398,6 +421,7 @@ add_executable(noctalia
|
||||
src/shell/widgets/active_window_widget.cpp
|
||||
src/shell/widgets/battery_widget.cpp
|
||||
src/shell/widgets/clock_widget.cpp
|
||||
src/shell/widgets/idle_inhibitor_widget.cpp
|
||||
src/shell/widgets/launcher_widget.cpp
|
||||
src/shell/widgets/media_mini_widget.cpp
|
||||
src/shell/widgets/notification_widget.cpp
|
||||
@@ -455,6 +479,7 @@ add_executable(noctalia
|
||||
"${EXT_DATA_CONTROL_PROTOCOL_C}"
|
||||
"${XDG_ACTIVATION_PROTOCOL_C}"
|
||||
"${EXT_SESSION_LOCK_PROTOCOL_C}"
|
||||
"${IDLE_INHIBIT_PROTOCOL_C}"
|
||||
"${WLR_FOREIGN_TOPLEVEL_PROTOCOL_C}"
|
||||
"${WLR_DATA_CONTROL_PROTOCOL_C}"
|
||||
)
|
||||
|
||||
@@ -232,6 +232,24 @@ No configurable settings.
|
||||
|
||||
---
|
||||
|
||||
### `idle_inhibitor`
|
||||
|
||||
Shows a keep-awake glyph and toggles the compositor idle inhibitor on click.
|
||||
|
||||
This uses the standard Wayland `zwp_idle_inhibit_manager_v1` protocol when available.
|
||||
|
||||
No configurable settings.
|
||||
|
||||
You can also control it over Noctalia IPC:
|
||||
|
||||
```sh
|
||||
noctalia-ipc enable-idle-inhibitor
|
||||
noctalia-ipc disable-idle-inhibitor
|
||||
noctalia-ipc toggle-idle-inhibitor
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `sysmon`
|
||||
|
||||
System resource monitor. Shows an icon and value for one configurable stat. Multiple instances with different stats can coexist on the same bar.
|
||||
|
||||
@@ -178,7 +178,7 @@ gdbus call --session --dest dev.noctalia.Debug --object-path /dev/noctalia/Debug
|
||||
- [ ] PipeWire audio spectrum
|
||||
- [~] Clipboard manager <- missing auto-paste /
|
||||
- [~] Lock screen (ext-session-lock-v1) <- still needs polish
|
||||
- [ ] Idle inhibitor (prevent sleep)
|
||||
- [x] Idle inhibitor (prevent sleep)
|
||||
- [~] More compositors (Labwc pending)
|
||||
- [ ] Application file search provider
|
||||
|
||||
|
||||
+37
-1
@@ -221,6 +221,9 @@ void Application::initServices() {
|
||||
m_wayland.setWorkspaceChangeCallback([this]() { m_bar.refresh(); });
|
||||
m_wayland.setToplevelChangeCallback([this]() { m_bar.refresh(); });
|
||||
|
||||
m_idleInhibitor.initialize(m_wayland, &m_renderContext);
|
||||
m_idleInhibitor.setChangeCallback([this]() { m_bar.refresh(); });
|
||||
|
||||
m_wallpaper.initialize(m_wayland, &m_configService, &m_stateService);
|
||||
m_overview.initialize(m_wayland, &m_configService, &m_stateService, &m_wallpaper);
|
||||
|
||||
@@ -418,7 +421,7 @@ void Application::initUi() {
|
||||
|
||||
m_bar.initialize(m_wayland, &m_configService, &m_timeService, &m_notificationManager, m_trayService.get(),
|
||||
m_pipewireService.get(), m_upowerService.get(), m_systemMonitor.get(), m_powerProfilesService.get(),
|
||||
m_mprisService.get(), &m_httpClient, &m_weatherService, &m_renderContext);
|
||||
&m_idleInhibitor, m_mprisService.get(), &m_httpClient, &m_weatherService, &m_renderContext);
|
||||
|
||||
if (m_pipewireService != nullptr) {
|
||||
m_audioOsd.suppressFor(std::chrono::milliseconds(2000));
|
||||
@@ -571,6 +574,39 @@ void Application::initIpc() {
|
||||
return "ok\n";
|
||||
},
|
||||
"toggle-clipboard", "Toggle the clipboard history panel");
|
||||
|
||||
m_ipcService.registerHandler(
|
||||
"enable-idle-inhibitor",
|
||||
[this](const std::string&) -> std::string {
|
||||
if (!m_idleInhibitor.available()) {
|
||||
return "error: idle inhibitor protocol unavailable\n";
|
||||
}
|
||||
m_idleInhibitor.setEnabled(true);
|
||||
return "ok\n";
|
||||
},
|
||||
"enable-idle-inhibitor", "Enable the compositor idle inhibitor");
|
||||
|
||||
m_ipcService.registerHandler(
|
||||
"disable-idle-inhibitor",
|
||||
[this](const std::string&) -> std::string {
|
||||
if (!m_idleInhibitor.available()) {
|
||||
return "error: idle inhibitor protocol unavailable\n";
|
||||
}
|
||||
m_idleInhibitor.setEnabled(false);
|
||||
return "ok\n";
|
||||
},
|
||||
"disable-idle-inhibitor", "Disable the compositor idle inhibitor");
|
||||
|
||||
m_ipcService.registerHandler(
|
||||
"toggle-idle-inhibitor",
|
||||
[this](const std::string&) -> std::string {
|
||||
if (!m_idleInhibitor.available()) {
|
||||
return "error: idle inhibitor protocol unavailable\n";
|
||||
}
|
||||
m_idleInhibitor.toggle();
|
||||
return "ok\n";
|
||||
},
|
||||
"toggle-idle-inhibitor", "Toggle the compositor idle inhibitor");
|
||||
}
|
||||
|
||||
std::vector<PollSource*> Application::buildPollSources() {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "dbus/tray/tray_service.h"
|
||||
#include "dbus/upower/upower_service.h"
|
||||
#include "debug/debug_service.h"
|
||||
#include "idle/idle_inhibitor.h"
|
||||
#include "ipc/ipc_poll_source.h"
|
||||
#include "ipc/ipc_service.h"
|
||||
#include "net/http_client.h"
|
||||
@@ -78,6 +79,7 @@ private:
|
||||
std::unique_ptr<SystemBus> m_systemBus;
|
||||
std::unique_ptr<SystemMonitorService> m_systemMonitor;
|
||||
std::unique_ptr<DebugService> m_debugService;
|
||||
IdleInhibitor m_idleInhibitor;
|
||||
std::unique_ptr<MprisService> m_mprisService;
|
||||
std::unique_ptr<PowerProfilesService> m_powerProfilesService;
|
||||
std::unique_ptr<UPowerService> m_upowerService;
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
#include "idle/idle_inhibitor.h"
|
||||
|
||||
#include "core/log.h"
|
||||
#include "wayland/layer_surface.h"
|
||||
#include "wayland/wayland_connection.h"
|
||||
|
||||
#include "idle-inhibit-unstable-v1-client-protocol.h"
|
||||
#include <wayland-client.h>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr Logger kLog("idle");
|
||||
|
||||
} // namespace
|
||||
|
||||
IdleInhibitor::IdleInhibitor() = default;
|
||||
|
||||
IdleInhibitor::~IdleInhibitor() {
|
||||
destroyInhibitor();
|
||||
m_surface.reset();
|
||||
}
|
||||
|
||||
bool IdleInhibitor::initialize(WaylandConnection& wayland, RenderContext* renderContext) {
|
||||
m_wayland = &wayland;
|
||||
m_renderContext = renderContext;
|
||||
m_manager = m_wayland->idleInhibitManager();
|
||||
|
||||
if (m_manager == nullptr) {
|
||||
kLog.info("idle inhibit protocol unavailable");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IdleInhibitor::toggle() { setEnabled(!m_enabled); }
|
||||
|
||||
void IdleInhibitor::setEnabled(bool enabled) {
|
||||
if (m_enabled == enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_enabled = enabled;
|
||||
syncInhibitor();
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
void IdleInhibitor::setChangeCallback(ChangeCallback callback) { m_changeCallback = std::move(callback); }
|
||||
|
||||
void IdleInhibitor::ensureSurface() {
|
||||
if (m_surface != nullptr || m_wayland == nullptr || m_renderContext == nullptr || m_wayland->outputs().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& output = m_wayland->outputs().front();
|
||||
LayerSurfaceConfig config{
|
||||
.nameSpace = "noctalia-idle-inhibitor",
|
||||
.layer = LayerShellLayer::Overlay,
|
||||
.anchor = LayerShellAnchor::Top | LayerShellAnchor::Left,
|
||||
.width = 1,
|
||||
.height = 1,
|
||||
.exclusiveZone = 0,
|
||||
.marginTop = 0,
|
||||
.marginRight = 0,
|
||||
.marginBottom = 0,
|
||||
.marginLeft = 0,
|
||||
.keyboard = LayerShellKeyboard::None,
|
||||
.defaultWidth = 1,
|
||||
.defaultHeight = 1,
|
||||
};
|
||||
|
||||
auto surface = std::make_unique<LayerSurface>(*m_wayland, std::move(config));
|
||||
surface->setRenderContext(m_renderContext);
|
||||
surface->setConfigureCallback([](std::uint32_t /*width*/, std::uint32_t /*height*/) {});
|
||||
|
||||
if (!surface->initialize(output.output, output.scale)) {
|
||||
kLog.warn("failed to initialize idle inhibitor surface");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wl_region* region = wl_compositor_create_region(m_wayland->compositor()); region != nullptr) {
|
||||
wl_surface_set_input_region(surface->wlSurface(), region);
|
||||
wl_region_destroy(region);
|
||||
wl_surface_commit(surface->wlSurface());
|
||||
}
|
||||
|
||||
m_surface = std::move(surface);
|
||||
}
|
||||
|
||||
void IdleInhibitor::syncInhibitor() {
|
||||
if (m_manager == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_enabled) {
|
||||
destroyInhibitor();
|
||||
return;
|
||||
}
|
||||
|
||||
ensureSurface();
|
||||
if (m_surface == nullptr || m_surface->wlSurface() == nullptr || m_inhibitor != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_inhibitor = zwp_idle_inhibit_manager_v1_create_inhibitor(m_manager, m_surface->wlSurface());
|
||||
if (m_inhibitor != nullptr) {
|
||||
kLog.info("idle inhibitor enabled");
|
||||
}
|
||||
}
|
||||
|
||||
void IdleInhibitor::destroyInhibitor() {
|
||||
if (m_inhibitor != nullptr) {
|
||||
zwp_idle_inhibitor_v1_destroy(m_inhibitor);
|
||||
m_inhibitor = nullptr;
|
||||
kLog.info("idle inhibitor disabled");
|
||||
}
|
||||
}
|
||||
|
||||
void IdleInhibitor::notifyChanged() {
|
||||
if (m_changeCallback) {
|
||||
m_changeCallback();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
class LayerSurface;
|
||||
class RenderContext;
|
||||
class WaylandConnection;
|
||||
struct zwp_idle_inhibit_manager_v1;
|
||||
struct zwp_idle_inhibitor_v1;
|
||||
|
||||
class IdleInhibitor {
|
||||
public:
|
||||
using ChangeCallback = std::function<void()>;
|
||||
|
||||
IdleInhibitor();
|
||||
~IdleInhibitor();
|
||||
|
||||
IdleInhibitor(const IdleInhibitor&) = delete;
|
||||
IdleInhibitor& operator=(const IdleInhibitor&) = delete;
|
||||
|
||||
bool initialize(WaylandConnection& wayland, RenderContext* renderContext);
|
||||
void toggle();
|
||||
void setEnabled(bool enabled);
|
||||
[[nodiscard]] bool enabled() const noexcept { return m_enabled; }
|
||||
[[nodiscard]] bool available() const noexcept { return m_manager != nullptr; }
|
||||
void setChangeCallback(ChangeCallback callback);
|
||||
|
||||
private:
|
||||
void ensureSurface();
|
||||
void syncInhibitor();
|
||||
void destroyInhibitor();
|
||||
void notifyChanged();
|
||||
|
||||
WaylandConnection* m_wayland = nullptr;
|
||||
RenderContext* m_renderContext = nullptr;
|
||||
zwp_idle_inhibit_manager_v1* m_manager = nullptr;
|
||||
zwp_idle_inhibitor_v1* m_inhibitor = nullptr;
|
||||
std::unique_ptr<LayerSurface> m_surface;
|
||||
ChangeCallback m_changeCallback;
|
||||
bool m_enabled = false;
|
||||
};
|
||||
@@ -109,7 +109,7 @@ Bar::Bar() = default;
|
||||
bool Bar::initialize(WaylandConnection& wayland, ConfigService* config, TimeService* timeService,
|
||||
NotificationManager* notifications, TrayService* tray, PipeWireService* audio,
|
||||
UPowerService* upower, SystemMonitorService* sysmon, PowerProfilesService* powerProfiles,
|
||||
MprisService* mpris,
|
||||
IdleInhibitor* idleInhibitor, MprisService* mpris,
|
||||
HttpClient* httpClient, WeatherService* weatherService, RenderContext* renderContext) {
|
||||
m_wayland = &wayland;
|
||||
m_config = config;
|
||||
@@ -120,13 +120,14 @@ bool Bar::initialize(WaylandConnection& wayland, ConfigService* config, TimeServ
|
||||
m_upower = upower;
|
||||
m_sysmon = sysmon;
|
||||
m_powerProfiles = powerProfiles;
|
||||
m_idleInhibitor = idleInhibitor;
|
||||
m_mpris = mpris;
|
||||
m_httpClient = httpClient;
|
||||
m_weatherService = weatherService;
|
||||
m_renderContext = renderContext;
|
||||
|
||||
m_widgetFactory = std::make_unique<WidgetFactory>(*m_wayland, m_time, m_config->config(), m_notifications, m_tray,
|
||||
m_audio, m_upower, m_sysmon, m_powerProfiles, m_mpris, m_httpClient,
|
||||
m_audio, m_upower, m_sysmon, m_powerProfiles, m_idleInhibitor, m_mpris, m_httpClient,
|
||||
m_weatherService);
|
||||
|
||||
if (timeService != nullptr) {
|
||||
@@ -153,7 +154,7 @@ bool Bar::initialize(WaylandConnection& wayland, ConfigService* config, TimeServ
|
||||
void Bar::reload() {
|
||||
kLog.info("reloading config");
|
||||
m_widgetFactory = std::make_unique<WidgetFactory>(*m_wayland, m_time, m_config->config(), m_notifications, m_tray,
|
||||
m_audio, m_upower, m_sysmon, m_powerProfiles, m_mpris, m_httpClient,
|
||||
m_audio, m_upower, m_sysmon, m_powerProfiles, m_idleInhibitor, m_mpris, m_httpClient,
|
||||
m_weatherService);
|
||||
m_instances.clear();
|
||||
m_surfaceMap.clear();
|
||||
|
||||
+3
-1
@@ -9,6 +9,7 @@
|
||||
|
||||
class ConfigService;
|
||||
class HttpClient;
|
||||
class IdleInhibitor;
|
||||
class MprisService;
|
||||
class NotificationManager;
|
||||
class PipeWireService;
|
||||
@@ -30,7 +31,7 @@ public:
|
||||
bool initialize(WaylandConnection& wayland, ConfigService* config, TimeService* timeService,
|
||||
NotificationManager* notifications, TrayService* tray, PipeWireService* audio,
|
||||
UPowerService* upower, SystemMonitorService* sysmon, PowerProfilesService* powerProfiles,
|
||||
MprisService* mpris, HttpClient* httpClient, WeatherService* weatherService,
|
||||
IdleInhibitor* idleInhibitor, MprisService* mpris, HttpClient* httpClient, WeatherService* weatherService,
|
||||
RenderContext* renderContext);
|
||||
void reload();
|
||||
void closeAllInstances();
|
||||
@@ -60,6 +61,7 @@ private:
|
||||
UPowerService* m_upower = nullptr;
|
||||
SystemMonitorService* m_sysmon = nullptr;
|
||||
PowerProfilesService* m_powerProfiles = nullptr;
|
||||
IdleInhibitor* m_idleInhibitor = nullptr;
|
||||
MprisService* m_mpris = nullptr;
|
||||
HttpClient* m_httpClient = nullptr;
|
||||
WeatherService* m_weatherService = nullptr;
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
#include "dbus/power/power_profiles_service.h"
|
||||
#include "dbus/mpris/mpris_service.h"
|
||||
#include "dbus/tray/tray_service.h"
|
||||
#include "idle/idle_inhibitor.h"
|
||||
#include "net/http_client.h"
|
||||
#include "notification/notification_manager.h"
|
||||
#include "shell/widgets/active_window_widget.h"
|
||||
#include "shell/widgets/battery_widget.h"
|
||||
#include "shell/widgets/clock_widget.h"
|
||||
#include "shell/widgets/idle_inhibitor_widget.h"
|
||||
#include "shell/widgets/launcher_widget.h"
|
||||
#include "shell/widgets/media_mini_widget.h"
|
||||
#include "shell/widgets/notification_widget.h"
|
||||
@@ -29,9 +31,9 @@
|
||||
WidgetFactory::WidgetFactory(WaylandConnection& wayland, TimeService* time, const Config& config,
|
||||
NotificationManager* notifications, TrayService* tray, PipeWireService* audio,
|
||||
UPowerService* upower, SystemMonitorService* sysmon, PowerProfilesService* powerProfiles,
|
||||
MprisService* mpris, HttpClient* httpClient, WeatherService* weather)
|
||||
IdleInhibitor* idleInhibitor, MprisService* mpris, HttpClient* httpClient, WeatherService* weather)
|
||||
: m_wayland(wayland), m_time(time), m_config(config), m_notifications(notifications), m_tray(tray), m_audio(audio),
|
||||
m_upower(upower), m_sysmon(sysmon), m_powerProfiles(powerProfiles), m_mpris(mpris), m_httpClient(httpClient),
|
||||
m_upower(upower), m_sysmon(sysmon), m_powerProfiles(powerProfiles), m_idleInhibitor(idleInhibitor), m_mpris(mpris), m_httpClient(httpClient),
|
||||
m_weather(weather) {}
|
||||
|
||||
std::unique_ptr<Widget> WidgetFactory::create(const std::string& name, wl_output* output, float contentScale) const {
|
||||
@@ -119,6 +121,12 @@ std::unique_ptr<Widget> WidgetFactory::create(const std::string& name, wl_output
|
||||
return widget;
|
||||
}
|
||||
|
||||
if (type == "idle_inhibitor") {
|
||||
auto widget = std::make_unique<IdleInhibitorWidget>(m_idleInhibitor);
|
||||
widget->setContentScale(contentScale);
|
||||
return widget;
|
||||
}
|
||||
|
||||
if (type == "volume") {
|
||||
std::int32_t scale = 1;
|
||||
const auto* wlOutput = m_wayland.findOutputByWl(output);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
struct Config;
|
||||
class NotificationManager;
|
||||
class HttpClient;
|
||||
class IdleInhibitor;
|
||||
class MprisService;
|
||||
class PipeWireService;
|
||||
class PowerProfilesService;
|
||||
@@ -23,7 +24,7 @@ class WidgetFactory {
|
||||
public:
|
||||
WidgetFactory(WaylandConnection& wayland, TimeService* time, const Config& config, NotificationManager* notifications,
|
||||
TrayService* tray, PipeWireService* audio, UPowerService* upower, SystemMonitorService* sysmon,
|
||||
PowerProfilesService* powerProfiles, MprisService* mpris, HttpClient* httpClient,
|
||||
PowerProfilesService* powerProfiles, IdleInhibitor* idleInhibitor, MprisService* mpris, HttpClient* httpClient,
|
||||
WeatherService* weather);
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Widget> create(const std::string& name, wl_output* output,
|
||||
@@ -39,6 +40,7 @@ private:
|
||||
UPowerService* m_upower;
|
||||
SystemMonitorService* m_sysmon;
|
||||
PowerProfilesService* m_powerProfiles;
|
||||
IdleInhibitor* m_idleInhibitor;
|
||||
MprisService* m_mpris;
|
||||
HttpClient* m_httpClient;
|
||||
WeatherService* m_weather;
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#include "shell/widgets/idle_inhibitor_widget.h"
|
||||
|
||||
#include "idle/idle_inhibitor.h"
|
||||
#include "render/core/renderer.h"
|
||||
#include "render/scene/input_area.h"
|
||||
#include "ui/controls/glyph.h"
|
||||
#include "ui/palette.h"
|
||||
#include "ui/style.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace {
|
||||
|
||||
const char* glyphForState(bool enabled) {
|
||||
return enabled ? "keep-awake-on" : "keep-awake-off";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
IdleInhibitorWidget::IdleInhibitorWidget(IdleInhibitor* inhibitor) : m_inhibitor(inhibitor) {}
|
||||
|
||||
void IdleInhibitorWidget::create() {
|
||||
auto area = std::make_unique<InputArea>();
|
||||
area->setOnClick([this](const InputArea::PointerData& /*data*/) {
|
||||
if (m_inhibitor != nullptr && m_inhibitor->available()) {
|
||||
m_inhibitor->toggle();
|
||||
}
|
||||
});
|
||||
m_area = area.get();
|
||||
|
||||
auto glyph = std::make_unique<Glyph>();
|
||||
glyph->setGlyph(glyphForState(false));
|
||||
glyph->setGlyphSize(Style::fontSizeBody * m_contentScale);
|
||||
glyph->setColor(palette.onSurfaceVariant);
|
||||
m_glyph = glyph.get();
|
||||
area->addChild(std::move(glyph));
|
||||
|
||||
setRoot(std::move(area));
|
||||
}
|
||||
|
||||
void IdleInhibitorWidget::layout(Renderer& renderer, float /*containerWidth*/, float /*containerHeight*/) {
|
||||
if (m_glyph == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
syncState(renderer);
|
||||
m_glyph->setGlyphSize(Style::fontSizeBody * m_contentScale);
|
||||
m_glyph->measure(renderer);
|
||||
|
||||
if (auto* node = root(); node != nullptr) {
|
||||
node->setSize(m_glyph->width(), m_glyph->height());
|
||||
}
|
||||
}
|
||||
|
||||
void IdleInhibitorWidget::update(Renderer& renderer) {
|
||||
syncState(renderer);
|
||||
Widget::update(renderer);
|
||||
}
|
||||
|
||||
void IdleInhibitorWidget::syncState(Renderer& renderer) {
|
||||
if (m_glyph == nullptr || m_area == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool available = m_inhibitor != nullptr && m_inhibitor->available();
|
||||
const bool enabled = available && m_inhibitor->enabled();
|
||||
|
||||
if (available == m_lastAvailable && enabled == m_lastEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_lastAvailable = available;
|
||||
m_lastEnabled = enabled;
|
||||
|
||||
m_glyph->setGlyph(glyphForState(enabled));
|
||||
m_glyph->setGlyphSize(Style::fontSizeBody * m_contentScale);
|
||||
m_glyph->setColor(!available ? palette.onSurfaceVariant : (enabled ? palette.primary : palette.onSurface));
|
||||
m_glyph->measure(renderer);
|
||||
m_area->setEnabled(available);
|
||||
if (auto* node = root(); node != nullptr) {
|
||||
node->setOpacity(available ? 1.0f : 0.55f);
|
||||
}
|
||||
requestRedraw();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "shell/widget/widget.h"
|
||||
|
||||
class Glyph;
|
||||
class IdleInhibitor;
|
||||
class InputArea;
|
||||
|
||||
class IdleInhibitorWidget : public Widget {
|
||||
public:
|
||||
explicit IdleInhibitorWidget(IdleInhibitor* inhibitor);
|
||||
|
||||
void create() override;
|
||||
void layout(Renderer& renderer, float containerWidth, float containerHeight) override;
|
||||
void update(Renderer& renderer) override;
|
||||
|
||||
private:
|
||||
void syncState(Renderer& renderer);
|
||||
|
||||
IdleInhibitor* m_inhibitor = nullptr;
|
||||
InputArea* m_area = nullptr;
|
||||
Glyph* m_glyph = nullptr;
|
||||
bool m_lastEnabled = false;
|
||||
bool m_lastAvailable = false;
|
||||
};
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "ext-data-control-v1-client-protocol.h"
|
||||
#include "ext-session-lock-v1-client-protocol.h"
|
||||
#include "ext-workspace-v1-client-protocol.h"
|
||||
#include "idle-inhibit-unstable-v1-client-protocol.h"
|
||||
#include "wlr-data-control-unstable-v1-client-protocol.h"
|
||||
#include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
@@ -32,6 +33,7 @@ namespace {
|
||||
constexpr std::uint32_t kCursorShapeManagerVersion = 1;
|
||||
constexpr std::uint32_t kXdgActivationVersion = 1;
|
||||
constexpr std::uint32_t kExtSessionLockManagerVersion = 1;
|
||||
constexpr std::uint32_t kIdleInhibitManagerVersion = 1;
|
||||
constexpr std::uint32_t kOutputVersion = 4;
|
||||
|
||||
const wl_registry_listener kRegistryListener = {
|
||||
@@ -296,6 +298,7 @@ bool WaylandConnection::hasExtWorkspaceManager() const noexcept { return m_hasEx
|
||||
bool WaylandConnection::hasMangoWorkspaceManager() const noexcept { return m_hasMangoWorkspaceGlobal; }
|
||||
bool WaylandConnection::hasForeignToplevelManager() const noexcept { return m_hasForeignToplevelManagerGlobal; }
|
||||
bool WaylandConnection::hasSessionLockManager() const noexcept { return m_sessionLockManager != nullptr; }
|
||||
bool WaylandConnection::hasIdleInhibitManager() const noexcept { return m_idleInhibitManager != nullptr; }
|
||||
bool WaylandConnection::hasXdgActivation() const noexcept { return m_xdgActivation != nullptr; }
|
||||
|
||||
std::string WaylandConnection::requestActivationToken(wl_surface* surface) const {
|
||||
@@ -338,6 +341,7 @@ wl_shm* WaylandConnection::shm() const noexcept { return m_shm; }
|
||||
zwlr_layer_shell_v1* WaylandConnection::layerShell() const noexcept { return m_layerShell; }
|
||||
|
||||
ext_session_lock_manager_v1* WaylandConnection::sessionLockManager() const noexcept { return m_sessionLockManager; }
|
||||
zwp_idle_inhibit_manager_v1* WaylandConnection::idleInhibitManager() const noexcept { return m_idleInhibitManager; }
|
||||
|
||||
const std::vector<WaylandOutput>& WaylandConnection::outputs() const noexcept { return m_outputs; }
|
||||
|
||||
@@ -474,6 +478,13 @@ void WaylandConnection::bindGlobal(wl_registry* registry, std::uint32_t name, co
|
||||
return;
|
||||
}
|
||||
|
||||
if (interfaceName == zwp_idle_inhibit_manager_v1_interface.name) {
|
||||
const auto bindVersion = std::min(version, kIdleInhibitManagerVersion);
|
||||
m_idleInhibitManager = static_cast<zwp_idle_inhibit_manager_v1*>(
|
||||
wl_registry_bind(registry, name, &zwp_idle_inhibit_manager_v1_interface, bindVersion));
|
||||
return;
|
||||
}
|
||||
|
||||
if (interfaceName == ext_data_control_manager_v1_interface.name) {
|
||||
if (m_dataControlManager != nullptr && m_dataControlOps != extDataControlOps()) {
|
||||
m_dataControlOps->destroyManager(m_dataControlManager);
|
||||
@@ -562,6 +573,10 @@ void WaylandConnection::cleanup() {
|
||||
ext_session_lock_manager_v1_destroy(m_sessionLockManager);
|
||||
m_sessionLockManager = nullptr;
|
||||
}
|
||||
if (m_idleInhibitManager != nullptr) {
|
||||
zwp_idle_inhibit_manager_v1_destroy(m_idleInhibitManager);
|
||||
m_idleInhibitManager = nullptr;
|
||||
}
|
||||
|
||||
if (m_dataControlManager != nullptr && m_dataControlOps != nullptr) {
|
||||
m_dataControlOps->destroyManager(m_dataControlManager);
|
||||
|
||||
@@ -21,6 +21,7 @@ struct zwlr_layer_shell_v1;
|
||||
struct zxdg_output_manager_v1;
|
||||
struct zxdg_output_v1;
|
||||
struct wp_cursor_shape_manager_v1;
|
||||
struct zwp_idle_inhibit_manager_v1;
|
||||
struct xdg_activation_v1;
|
||||
struct ext_session_lock_manager_v1;
|
||||
struct zwlr_foreign_toplevel_manager_v1;
|
||||
@@ -85,11 +86,13 @@ public:
|
||||
[[nodiscard]] bool hasMangoWorkspaceManager() const noexcept;
|
||||
[[nodiscard]] bool hasForeignToplevelManager() const noexcept;
|
||||
[[nodiscard]] bool hasSessionLockManager() const noexcept;
|
||||
[[nodiscard]] bool hasIdleInhibitManager() const noexcept;
|
||||
[[nodiscard]] wl_display* display() const noexcept;
|
||||
[[nodiscard]] wl_compositor* compositor() const noexcept;
|
||||
[[nodiscard]] wl_shm* shm() const noexcept;
|
||||
[[nodiscard]] zwlr_layer_shell_v1* layerShell() const noexcept;
|
||||
[[nodiscard]] ext_session_lock_manager_v1* sessionLockManager() const noexcept;
|
||||
[[nodiscard]] zwp_idle_inhibit_manager_v1* idleInhibitManager() const noexcept;
|
||||
[[nodiscard]] const std::vector<WaylandOutput>& outputs() const noexcept;
|
||||
[[nodiscard]] WaylandOutput* findOutputByWl(wl_output* wlOutput);
|
||||
[[nodiscard]] WaylandOutput* findOutputByXdg(zxdg_output_v1* xdgOutput);
|
||||
@@ -128,6 +131,7 @@ private:
|
||||
wp_cursor_shape_manager_v1* m_cursorShapeManager = nullptr;
|
||||
xdg_activation_v1* m_xdgActivation = nullptr;
|
||||
ext_session_lock_manager_v1* m_sessionLockManager = nullptr;
|
||||
zwp_idle_inhibit_manager_v1* m_idleInhibitManager = nullptr;
|
||||
void* m_dataControlManager = nullptr;
|
||||
const DataControlOps* m_dataControlOps = nullptr;
|
||||
ClipboardService* m_clipboardService = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user