From a615926156411daf9a8e476c1eb48b1bb56a96b9 Mon Sep 17 00:00:00 2001 From: StaszeKrk Date: Tue, 5 May 2026 18:37:11 +0200 Subject: [PATCH] feat: add sleep_monitor command with wake-on-input --- docs/bindings/keys.md | 1 + docs/configuration/monitors.md | 5 ++++- src/config/parse_config.h | 3 +++ src/dispatch/bind_declare.h | 1 + src/dispatch/bind_define.h | 17 +++++++++++++++++ src/mango.c | 25 +++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 1 deletion(-) diff --git a/docs/bindings/keys.md b/docs/bindings/keys.md index b3a4ab64..e77b2c4d 100644 --- a/docs/bindings/keys.md +++ b/docs/bindings/keys.md @@ -168,6 +168,7 @@ bindr=Super,Super_L,spawn,rofi -show run | `disable_monitor` | `monitor_spec` | Shutdown monitor. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | | `enable_monitor` | `monitor_spec` | Power on monitor. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | | `toggle_monitor` | `monitor_spec` | Toggle monitor power. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | +| `sleep_monitor` | `monitor_spec` | Turn off monitor and wake it automatically on the next keypress or mouse movement. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | ### Media Controls diff --git a/docs/configuration/monitors.md b/docs/configuration/monitors.md index 28ef240b..93f3ccdf 100644 --- a/docs/configuration/monitors.md +++ b/docs/configuration/monitors.md @@ -67,7 +67,7 @@ monitorrule=name:HEADLESS-.*,width:1920,height:1080,refresh:60,x:1926,y:0,scale: ## Monitor Spec Format -Several commands (`focusmon`, `tagmon`, `disable_monitor`, `enable_monitor`, `toggle_monitor`, `viewcrossmon`, `tagcrossmon`) accept a **monitor_spec** string to identify a monitor. +Several commands (`focusmon`, `tagmon`, `disable_monitor`, `enable_monitor`, `toggle_monitor`, `sleep_monitor`, `viewcrossmon`, `tagcrossmon`) accept a **monitor_spec** string to identify a monitor. **Format:** @@ -173,6 +173,9 @@ mmsg -d enable_monitor,eDP-1 # Toggle mmsg -d toggle_monitor,eDP-1 + +# Turn off and wake automatically on next keypress or mouse movement +mmsg -d sleep_monitor,eDP-1 ``` You can also use `wlr-randr` for monitor management: diff --git a/src/config/parse_config.h b/src/config/parse_config.h index f70a17d6..38bcfb11 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1209,6 +1209,9 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "toggle_monitor") == 0) { func = toggle_monitor; (*arg).v = strdup(arg_value); + } else if (strcmp(func_name, "sleep_monitor") == 0) { + func = sleep_monitor; + (*arg).v = strdup(arg_value); } else if (strcmp(func_name, "scroller_stack") == 0) { func = scroller_stack; (*arg).i = parse_direction(arg_value); diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index dbeebd33..5d5885ec 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -69,5 +69,6 @@ int32_t setoption(const Arg *arg); int32_t disable_monitor(const Arg *arg); int32_t enable_monitor(const Arg *arg); int32_t toggle_monitor(const Arg *arg); +int32_t sleep_monitor(const Arg *arg); int32_t scroller_stack(const Arg *arg); int32_t toggle_all_floating(const Arg *arg); \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index f8822af3..2481dbe0 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1772,6 +1772,23 @@ int32_t toggle_monitor(const Arg *arg) { return 0; } +/* Turns off a monitor and re-enables it on the next keypress or mouse input. */ +int32_t sleep_monitor(const Arg *arg) { + Monitor *m = NULL; + struct wlr_output_state state = {0}; + wl_list_for_each(m, &mons, link) { + if (match_monitor_spec(arg->v, m)) { + wlr_output_state_set_enabled(&state, false); + wlr_output_commit_state(m->wlr_output, &state); + m->asleep = 1; + m->wake_on_input = 1; + updatemons(NULL, NULL); + break; + } + } + return 0; +} + int32_t scroller_apply_stack(Client *c, Client *target_client, int32_t direction) { diff --git a/src/mango.c b/src/mango.c index b4bc67bf..051b12b2 100644 --- a/src/mango.c +++ b/src/mango.c @@ -537,6 +537,7 @@ struct Monitor { int32_t isoverview; int32_t is_in_hotarea; int32_t asleep; + int32_t wake_on_input; uint32_t visible_clients; uint32_t visible_tiling_clients; uint32_t visible_scroll_tiling_clients; @@ -751,6 +752,7 @@ static void set_rect_size(struct wlr_scene_rect *rect, int32_t width, int32_t height); static Client *center_tiled_select(Monitor *m); static void handlecursoractivity(void); +static void wakesleepingmons(void); static int32_t hidecursor(void *data); static bool check_hit_no_border(Client *c); static void reset_keyboard_layout(void); @@ -2229,6 +2231,9 @@ buttonpress(struct wl_listener *listener, void *data) { return; } + if (event->state == WL_POINTER_BUTTON_STATE_PRESSED) + wakesleepingmons(); + switch (event->state) { case WL_POINTER_BUTTON_STATE_PRESSED: cursor_mode = CurPressed; @@ -4053,6 +4058,9 @@ void keypress(struct wl_listener *listener, void *data) { wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) + wakesleepingmons(); + // ov tab mode detect moe key release if (config.ov_tab_mode && !locked && group == kb_group && event->state == WL_KEYBOARD_KEY_STATE_RELEASED && @@ -4536,6 +4544,7 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { + wakesleepingmons(); wlr_relative_pointer_manager_v1_send_relative_motion( relative_pointer_mgr, seat, (uint64_t)time * 1000, dx, dy, dx_unaccel, dy_unaccel); @@ -6150,6 +6159,22 @@ void handlecursoractivity(void) { last_cursor.hotspot_x, last_cursor.hotspot_y); } +void wakesleepingmons(void) { + Monitor *m; + struct wlr_output_state state; + wl_list_for_each(m, &mons, link) { + if (!m->wake_on_input) + continue; + wlr_output_state_init(&state); + wlr_output_state_set_enabled(&state, true); + wlr_output_commit_state(m->wlr_output, &state); + wlr_output_state_finish(&state); + m->asleep = 0; + m->wake_on_input = 0; + updatemons(NULL, NULL); + } +} + int32_t hidecursor(void *data) { wlr_cursor_unset_image(cursor); cursor_hidden = true;