From 380ea7bf93b5bb727cda78eaf4b3d0a580188efd Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sat, 3 Aug 2024 14:06:20 +0000 Subject: [PATCH] Manage power only during capturing This makes it possible for power management software to run in the system while wayvnc is running. The wlr-output-power-management-v1 protocol gives exclusive access to whichever client that holds an output-power object. Holding it while the process is running, precludes other clients from managing power. --- include/output.h | 5 +++-- src/main.c | 26 ++++++++++++++++---------- src/output.c | 46 +++++++++++++++++++++++----------------------- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/include/output.h b/include/output.h index 0d11e2ac..8706d9b8 100644 --- a/include/output.h +++ b/include/output.h @@ -68,8 +68,9 @@ struct output { struct output* output_new(struct wl_output* wl_output, uint32_t id); void output_destroy(struct output* output); -void output_setup_wl_managers(struct wl_list* list); -int output_set_power_state(struct output* output, enum output_power_state state); +void output_setup_xdg_output_managers(struct wl_list* list); +int output_acquire_power_on(struct output* output); +void output_release_power_on(struct output* output); void output_list_destroy(struct wl_list* list); struct output* output_find_by_id(struct wl_list* list, uint32_t id); struct output* output_find_by_name(struct wl_list* list, const char* name); diff --git a/src/main.c b/src/main.c index 16a2b673..99d57fa9 100644 --- a/src/main.c +++ b/src/main.c @@ -254,7 +254,7 @@ static void registry_add(void* data, struct wl_registry* registry, wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, 3); - output_setup_wl_managers(&self->outputs); + output_setup_xdg_output_managers(&self->outputs); return; } @@ -262,7 +262,6 @@ static void registry_add(void* data, struct wl_registry* registry, nvnc_trace("Registering new wlr_output_power_manager"); wlr_output_power_manager = wl_registry_bind(registry, id, &zwlr_output_power_manager_v1_interface, 1); - output_setup_wl_managers(&self->outputs); return; } @@ -1001,15 +1000,20 @@ int wayvnc_start_capture_immediate(struct wayvnc* self) if (self->capture_retry_timer) return 0; - if (self->selected_output->power == OUTPUT_POWER_OFF) { - nvnc_log(NVNC_LOG_WARNING, "Selected output is in powersaving mode. Delaying capture until it turns on."); - if (output_set_power_state(self->selected_output, OUTPUT_POWER_ON) - == 0) - nvnc_log(NVNC_LOG_WARNING, "Requested power ON."); + struct output* output = self->selected_output; + int rc = output_acquire_power_on(output); + if (rc == 0) { + nvnc_log(NVNC_LOG_DEBUG, "Acquired power state management. Waiting for power event to start capturing"); return 0; + } else if (rc > 0 && output->power != OUTPUT_POWER_ON) { + nvnc_log(NVNC_LOG_DEBUG, "Output power state management already acquired, but not yet powered on"); + return 0; + } else if (rc < 0) { + nvnc_log(NVNC_LOG_WARNING, "Failed to acquire power state control. Capturing may fail."); } - int rc = screencopy_start_immediate(&self->screencopy); + nvnc_log(NVNC_LOG_DEBUG, "screencopy_start_immediate"); + rc = screencopy_start_immediate(&self->screencopy); if (rc < 0) { nvnc_log(NVNC_LOG_ERROR, "Failed to start capture. Exiting..."); wayvnc_exit(self); @@ -1053,7 +1057,8 @@ void on_output_dimension_change(struct output* output) static void on_output_power_change(struct output* output) { - nvnc_trace("Output %s power state changed to %s", output->name, output_power_state_name(output->power)); + nvnc_trace("Output %s power state changed to %s", output->name, + output_power_state_name(output->power)); struct wayvnc* self = output->userdata; if (self->selected_output != output || self->nr_clients == 0) @@ -1061,7 +1066,6 @@ static void on_output_power_change(struct output* output) switch (output->power) { case OUTPUT_POWER_ON: - nvnc_log(NVNC_LOG_WARNING, "Output is now on. Restarting frame capture"); wayvnc_start_capture_immediate(self); break; case OUTPUT_POWER_OFF: @@ -1313,6 +1317,7 @@ static void client_destroy(void* obj) if (wayvnc->nr_clients == 0 && wayvnc->display) { nvnc_log(NVNC_LOG_INFO, "Stopping screen capture"); screencopy_stop(&wayvnc->screencopy); + output_release_power_on(wayvnc->selected_output); stop_performance_ticker(wayvnc); } @@ -1553,6 +1558,7 @@ void switch_to_output(struct wayvnc* self, struct output* output) return; } screencopy_stop(&self->screencopy); + output_release_power_on(output); set_selected_output(self, output); reinitialise_pointers(self); if (self->nr_clients > 0) diff --git a/src/output.c b/src/output.c index bc0f2608..88420f9c 100644 --- a/src/output.c +++ b/src/output.c @@ -184,6 +184,7 @@ static const struct wl_output_listener output_listener = { void output_destroy(struct output* output) { + output_release_power_on(output); if (output->xdg_output) zxdg_output_v1_destroy(output->xdg_output); if (output->wlr_output_power) @@ -307,34 +308,35 @@ static const struct zwlr_output_power_v1_listener wlr_output_power_listener = { .failed = output_power_failed, }; -static void output_setup_wlr_output_power_manager(struct output* self) +int output_acquire_power_on(struct output* output) { - if (!wlr_output_power_manager || self->wlr_output_power) - return; + if (output->wlr_output_power) + return 1; + + if (!wlr_output_power_manager) + return -1; struct zwlr_output_power_v1* wlr_output_power = zwlr_output_power_manager_v1_get_output_power( - wlr_output_power_manager, - self->wl_output); - self->wlr_output_power = wlr_output_power; + wlr_output_power_manager, output->wl_output); + output->wlr_output_power = wlr_output_power; + + zwlr_output_power_v1_add_listener(output->wlr_output_power, + &wlr_output_power_listener, output); - zwlr_output_power_v1_add_listener(self->wlr_output_power, - &wlr_output_power_listener, self); + zwlr_output_power_v1_set_mode(output->wlr_output_power, + ZWLR_OUTPUT_POWER_V1_MODE_ON); + return 0; } -int output_set_power_state(struct output* output, enum output_power_state state) +void output_release_power_on(struct output* output) { - assert(state != OUTPUT_POWER_UNKNOWN); - if (!output->wlr_output_power) { - errno = ENOENT; - return -1; - } - nvnc_trace("Output %s requesting power %s", output->name, - output_power_state_name(state)); - int mode = (state == OUTPUT_POWER_ON) ? ZWLR_OUTPUT_POWER_V1_MODE_ON : - ZWLR_OUTPUT_POWER_V1_MODE_OFF; - zwlr_output_power_v1_set_mode(output->wlr_output_power, mode); - return 0; + if (!output->wlr_output_power) + return; + + zwlr_output_power_v1_destroy(output->wlr_output_power); + output->wlr_output_power = NULL; + output->power = OUTPUT_POWER_UNKNOWN; } struct output* output_find_by_id(struct wl_list* list, uint32_t id) @@ -386,12 +388,11 @@ struct output* output_cycle(const struct wl_list* list, return wl_container_of(iter, output, link); } -void output_setup_wl_managers(struct wl_list* list) +void output_setup_xdg_output_managers(struct wl_list* list) { struct output* output; wl_list_for_each(output, list, link) { output_setup_xdg_output_manager(output); - output_setup_wlr_output_power_manager(output); } } @@ -411,7 +412,6 @@ struct output* output_new(struct wl_output* wl_output, uint32_t id) output); output_setup_xdg_output_manager(output); - output_setup_wlr_output_power_manager(output); return output; }