diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 0da84745..f202d4d6 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -101,3 +101,11 @@ error_backend: free(backend); return NULL; } + +void wlr_drm_backend_dpms(struct wlr_backend *backend, bool screen_on) { + struct wlr_backend_state *state = backend->state; + for (size_t i = 0; i < state->outputs->length; ++i) { + struct wlr_output_state *output = state->outputs->items[i]; + wlr_drm_output_dpms(state->fd, output, screen_on); + } +} diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 7cbd3e4a..a8e8c9ae 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -249,6 +249,30 @@ static struct wlr_output_impl output_impl = { .destroy = wlr_drm_output_destroy, }; +static void scan_property_ids(int fd, drmModeConnector *conn, + struct wlr_output_state *output) { + for (int i = 0; i < conn->count_props; ++i) { + drmModePropertyRes *prop = drmModeGetProperty(fd, conn->props[i]); + if (!prop) { + continue; + } + + // I think this is guranteed to exist + if (strcmp(prop->name, "DPMS") == 0) { + output->props.dpms = prop->prop_id; + + /* There may be more properties we want to get, + * but since it's currently only this, we exit early + */ + + drmModeFreeProperty(prop); + break; + } + + drmModeFreeProperty(prop); + } +} + void wlr_drm_scan_connectors(struct wlr_backend_state *state) { wlr_log(L_INFO, "Scanning DRM connectors"); @@ -300,6 +324,8 @@ void wlr_drm_scan_connectors(struct wlr_backend_state *state) { free(curr_enc); } + scan_property_ids(state->fd, conn, output); + list_add(state->outputs, output); wlr_log(L_INFO, "Found display '%s'", output->name); } else { @@ -416,3 +442,23 @@ void wlr_drm_output_cleanup(struct wlr_output_state *output, bool restore) { } // TODO: free wlr_output } + +void wlr_drm_output_dpms(int fd, struct wlr_output_state *output, bool screen_on) { + if (output->state != DRM_OUTPUT_CONNECTED) { + return; + } + + if (screen_on) { + drmModeConnectorSetProperty(fd, output->connector, output->props.dpms, + DRM_MODE_DPMS_ON); + + // Start rendering loop again by drawing a black frame + wlr_drm_output_begin(output->wlr_output); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + wlr_drm_output_end(output->wlr_output); + } else { + drmModeConnectorSetProperty(fd, output->connector, output->props.dpms, + DRM_MODE_DPMS_STANDBY); + } +} diff --git a/example/main.c b/example/main.c index 2c168d98..ed9eac0b 100644 --- a/example/main.c +++ b/example/main.c @@ -81,6 +81,18 @@ int timer_done(void *data) { return 1; } +int dpms_on(void *data) { + struct wlr_backend *backend = data; + wlr_drm_backend_dpms(backend, false); + return 1; +} + +int dpms_off(void *data) { + struct wlr_backend *backend = data; + wlr_drm_backend_dpms(backend, true); + return 1; +} + int main() { if (getenv("DISPLAY")) { fprintf(stderr, "Detected that X is running. Run this in its own virtual terminal.\n"); @@ -120,8 +132,14 @@ int main() { bool done = false; struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, timer_done, &done); - - wl_event_source_timer_update(timer, 5000); + struct wl_event_source *timer_dpms_on = wl_event_loop_add_timer(event_loop, + dpms_on, wlr); + struct wl_event_source *timer_dpms_off = wl_event_loop_add_timer(event_loop, + dpms_off, wlr); + + wl_event_source_timer_update(timer, 20000); + wl_event_source_timer_update(timer_dpms_on, 5000); + wl_event_source_timer_update(timer_dpms_off, 10000); while (!done) { wl_event_loop_dispatch(event_loop, 0); diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 4b42aa68..93de4fb8 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -36,6 +36,10 @@ struct wlr_output_state { uint32_t connector; char name[16]; + struct { + uint32_t dpms; + } props; + uint32_t width; uint32_t height; @@ -51,6 +55,7 @@ struct wlr_output_state { }; void wlr_drm_output_cleanup(struct wlr_output_state *output, bool restore); +void wlr_drm_output_dpms(int fd, struct wlr_output_state *output, bool screen_on); void wlr_drm_scan_connectors(struct wlr_backend_state *state); int wlr_drm_event(int fd, uint32_t mask, void *data); diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h index 2d9bf879..c76d280a 100644 --- a/include/wlr/backend/drm.h +++ b/include/wlr/backend/drm.h @@ -10,6 +10,8 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, struct wlr_session *session); +void wlr_drm_backend_dpms(struct wlr_backend *backend, bool screen_on); + void wlr_drm_output_begin(struct wlr_output *out); void wlr_drm_output_end(struct wlr_output *out);