Skip to content

Commit

Permalink
Manage power only during capturing
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
any1 committed Aug 3, 2024
1 parent e64e95c commit 380ea7b
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 35 deletions.
5 changes: 3 additions & 2 deletions include/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
26 changes: 16 additions & 10 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,15 +254,14 @@ 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;
}

if (strcmp(interface, zwlr_output_power_manager_v1_interface.name) == 0) {
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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1053,15 +1057,15 @@ 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)
return;

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:
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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)
Expand Down
46 changes: 23 additions & 23 deletions src/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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;
}

0 comments on commit 380ea7b

Please sign in to comment.