diff --git a/cage.c b/cage.c
index b2523ca..7b51e48 100644
--- a/cage.c
+++ b/cage.c
@@ -518,6 +518,15 @@ main(int argc, char *argv[])
server.output_manager_test.notify = handle_output_manager_test;
wl_signal_add(&server.output_manager_v1->events.test, &server.output_manager_test);
+ server.output_power_manager_v1 = wlr_output_power_manager_v1_create(server.wl_display);
+ if (!server.output_power_manager_v1) {
+ wlr_log(WLR_ERROR, "Unable to create the output power manager");
+ ret = 1;
+ goto end;
+ }
+ server.output_power_manager_set_mode.notify = handle_output_power_manager_set_mode;
+ wl_signal_add(&server.output_power_manager_v1->events.set_mode, &server.output_power_manager_set_mode);
+
#if WLR_HAS_DRM_BACKEND
server.drm_lease_v1 = wlr_drm_lease_v1_manager_create(server.wl_display, server.backend);
if (server.drm_lease_v1) {
@@ -662,6 +671,7 @@ main(int argc, char *argv[])
wl_list_remove(&server.new_idle_inhibitor_v1.link);
wl_list_remove(&server.new_output.link);
wl_list_remove(&server.output_layout_change.link);
+ wl_list_remove(&server.output_power_manager_set_mode.link);
end:
if (pid != 0)
diff --git a/meson.build b/meson.build
index 586e999..3c08d9e 100644
--- a/meson.build
+++ b/meson.build
@@ -102,9 +102,11 @@ if conf_data.get('CAGE_HAS_XWAYLAND', 0) == 1
cage_sources += 'xwayland.c'
endif
+subdir('protocols')
+
executable(
meson.project_name(),
- cage_sources,
+ cage_sources + wl_protos_src,
dependencies: [
wayland_server,
wlroots,
diff --git a/output.c b/output.c
index 9f2a708..758d933 100644
--- a/output.c
+++ b/output.c
@@ -112,6 +112,7 @@ output_enable(struct cg_output *output)
if (wlr_output_commit_state(wlr_output, &state)) {
output_layout_add_auto(output);
}
+ output->dpms_powered_off = false;
update_output_manager_config(output->server);
}
@@ -401,6 +402,29 @@ out:
return ok;
}
+void
+handle_output_power_manager_set_mode(struct wl_listener *listener, void *data)
+{
+ struct wlr_output_power_v1_set_mode_event *event = data;
+ struct cg_output *output = event->output->data;
+
+ if (event->mode == ZWLR_OUTPUT_POWER_V1_MODE_ON) {
+ if (!output->dpms_powered_off) {
+ return;
+ }
+ output->dpms_powered_off = false;
+ } else {
+ output->dpms_powered_off = true;
+ }
+
+ struct wlr_output_state state = {0};
+ wlr_output_state_set_enabled(&state, event->mode == ZWLR_OUTPUT_POWER_V1_MODE_ON);
+
+ if (!wlr_output_commit_state(output->wlr_output, &state)) {
+ wlr_log(WLR_ERROR, "Failed to set power mode for output %s", output->wlr_output->name);
+ }
+}
+
void
handle_output_manager_apply(struct wl_listener *listener, void *data)
{
diff --git a/output.h b/output.h
index fa72545..774b673 100644
--- a/output.h
+++ b/output.h
@@ -18,6 +18,8 @@ struct cg_output {
struct wl_listener frame;
struct wl_list link; // cg_server::outputs
+
+ bool dpms_powered_off;
};
void handle_output_manager_apply(struct wl_listener *listener, void *data);
@@ -25,5 +27,6 @@ void handle_output_manager_test(struct wl_listener *listener, void *data);
void handle_output_layout_change(struct wl_listener *listener, void *data);
void handle_new_output(struct wl_listener *listener, void *data);
void output_set_window_title(struct cg_output *output, const char *title);
+void handle_output_power_manager_set_mode(struct wl_listener *listener, void *data);
#endif
diff --git a/protocols/meson.build b/protocols/meson.build
new file mode 100644
index 0000000..c6aadfb
--- /dev/null
+++ b/protocols/meson.build
@@ -0,0 +1,26 @@
+wayland_scanner_dep = dependency('wayland-scanner', native: true)
+wayland_scanner = find_program(
+ wayland_scanner_dep.get_variable('wayland_scanner'),
+ native: true,
+)
+
+wl_protos_src = []
+
+protocols = [
+ 'wlr-output-power-management-unstable-v1.xml',
+]
+
+foreach xml : protocols
+ wl_protos_src += custom_target(
+ xml.underscorify() + '_c',
+ input: xml,
+ output: '@BASENAME@-protocol.c',
+ command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'],
+ )
+ wl_protos_src += custom_target(
+ xml.underscorify() + '_server_h',
+ input: xml,
+ output: '@BASENAME@-protocol.h',
+ command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'],
+ )
+endforeach
diff --git a/protocols/wlr-output-power-management-unstable-v1.xml b/protocols/wlr-output-power-management-unstable-v1.xml
new file mode 100644
index 0000000..e45b613
--- /dev/null
+++ b/protocols/wlr-output-power-management-unstable-v1.xml
@@ -0,0 +1,129 @@
+
+
+
+ Copyright © 2019 Purism SPC
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+
+
+ This protocol allows clients to control power management modes
+ of outputs that are currently part of the compositor space. The
+ intent is to allow special clients like desktop shells to power
+ down outputs when the system is idle.
+
+ To modify outputs not currently part of the compositor space see
+ wlr-output-management.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+
+
+
+
+ This interface is a manager that allows creating per-output power
+ management mode controls.
+
+
+
+
+ Create an output power management mode control that can be used to
+ adjust the power management mode for a given output.
+
+
+
+
+
+
+
+ All objects created by the manager will still remain valid, until their
+ appropriate destroy request has been called.
+
+
+
+
+
+
+ This object offers requests to set the power management mode of
+ an output.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set an output's power save mode to the given mode. The mode change
+ is effective immediately. If the output does not support the given
+ mode a failed event is sent.
+
+
+
+
+
+
+ Report the power management mode change of an output.
+
+ The mode event is sent after an output changed its power
+ management mode. The reason can be a client using set_mode or the
+ compositor deciding to change an output's mode.
+ This event is also sent immediately when the object is created
+ so the client is informed about the current power management mode.
+
+
+
+
+
+
+ This event indicates that the output power management mode control
+ is no longer valid. This can happen for a number of reasons,
+ including:
+ - The output doesn't support power management
+ - Another client already has exclusive power management mode control
+ for this output
+ - The output disappeared
+
+ Upon receiving this event, the client should destroy this object.
+
+
+
+
+
+ Destroys the output power management mode control object.
+
+
+
+
+
diff --git a/server.h b/server.h
index a5b7138..3f7e92a 100644
--- a/server.h
+++ b/server.h
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -61,6 +62,9 @@ struct cg_server {
struct wl_listener output_manager_apply;
struct wl_listener output_manager_test;
+ struct wlr_output_power_manager_v1 *output_power_manager_v1;
+ struct wl_listener output_power_manager_set_mode;
+
#if WLR_HAS_DRM_BACKEND
struct wlr_drm_lease_v1_manager *drm_lease_v1;
struct wl_listener drm_lease_request;