From 771263380c3b3b4b412964b0fe53619aa7c580e2 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 4 Jan 2018 12:46:15 +0100 Subject: [PATCH 01/21] Add wlr_output::enabled --- backend/drm/drm.c | 9 +++-- backend/headless/backend.c | 2 +- backend/headless/output.c | 5 ++- backend/wayland/output.c | 5 ++- backend/x11/backend.c | 8 ++-- include/wlr/interfaces/wlr_output.h | 7 +--- include/wlr/types/wlr_output.h | 10 +++-- types/wlr_output.c | 62 +++++++++++++++++------------ 8 files changed, 63 insertions(+), 45 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index dd5c97f5..32b2f88c 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -257,6 +257,8 @@ static void wlr_drm_connector_enable(struct wlr_output *output, bool enable) { if (enable) { wlr_drm_connector_start_renderer(conn); } + + wlr_output_update_enabled(&conn->output, enable); } static void realloc_planes(struct wlr_drm_backend *drm, const uint32_t *crtc_in, @@ -722,7 +724,8 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *drm) { drmModeFreeConnector(drm_conn); continue; } - wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl); + wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl, + drm->display); struct wl_event_loop *ev = wl_display_get_event_loop(drm->display); wlr_conn->retry_pageflip = wl_event_loop_add_timer(ev, retry_pageflip, @@ -792,7 +795,7 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *drm) { wl_list_insert(&wlr_conn->output.modes, &mode->wlr_mode.link); } - wlr_output_create_global(&wlr_conn->output, drm->display); + wlr_output_update_enabled(&wlr_conn->output, true); wlr_conn->state = WLR_DRM_CONN_NEEDS_MODESET; wlr_log(L_INFO, "Sending modesetting signal for '%s'", @@ -802,7 +805,7 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *drm) { drm_conn->connection != DRM_MODE_CONNECTED) { wlr_log(L_INFO, "'%s' disconnected", wlr_conn->output.name); - wlr_output_destroy_global(&wlr_conn->output); + wlr_output_update_enabled(&wlr_conn->output, false); wlr_drm_connector_cleanup(wlr_conn); } diff --git a/backend/headless/backend.c b/backend/headless/backend.c index f95e3897..cef8eec4 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -15,7 +15,7 @@ static bool backend_start(struct wlr_backend *wlr_backend) { struct wlr_headless_output *output; wl_list_for_each(output, &backend->outputs, link) { wl_event_source_timer_update(output->frame_timer, output->frame_delay); - wlr_output_create_global(&output->wlr_output, backend->display); + wlr_output_update_enabled(&output->wlr_output, true); wl_signal_emit(&backend->backend.events.output_add, &output->wlr_output); } diff --git a/backend/headless/output.c b/backend/headless/output.c index 511c2c53..9fc92e88 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -105,7 +105,8 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, return NULL; } output->backend = backend; - wlr_output_init(&output->wlr_output, &backend->backend, &output_impl); + wlr_output_init(&output->wlr_output, &backend->backend, &output_impl, + backend->display); struct wlr_output *wlr_output = &output->wlr_output; output->egl_surface = egl_create_surface(&backend->egl, width, height); @@ -138,7 +139,7 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, if (backend->started) { wl_event_source_timer_update(output->frame_timer, output->frame_delay); - wlr_output_create_global(wlr_output, backend->display); + wlr_output_update_enabled(wlr_output, true); wl_signal_emit(&backend->backend.events.output_add, wlr_output); } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index d76f6366..52791679 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -261,7 +261,8 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) { wlr_log(L_ERROR, "Failed to allocate wlr_wl_backend_output"); return NULL; } - wlr_output_init(&output->wlr_output, &backend->backend, &output_impl); + wlr_output_init(&output->wlr_output, &backend->backend, &output_impl, + backend->local_display); struct wlr_output *wlr_output = &output->wlr_output; wlr_output_update_custom_mode(wlr_output, 1280, 720, 0); @@ -325,7 +326,7 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) { } wl_list_insert(&backend->outputs, &output->link); - wlr_output_create_global(wlr_output, backend->local_display); + wlr_output_update_enabled(wlr_output, true); wl_signal_emit(&backend->backend.events.output_add, wlr_output); return wlr_output; diff --git a/backend/x11/backend.c b/backend/x11/backend.c index d2690342..e1622d06 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -181,7 +181,8 @@ static int signal_frame(void *data) { static void init_atom(struct wlr_x11_backend *x11, struct wlr_x11_atom *atom, uint8_t only_if_exists, const char *name) { - atom->cookie = xcb_intern_atom(x11->xcb_conn, only_if_exists, strlen(name), name); + atom->cookie = xcb_intern_atom(x11->xcb_conn, only_if_exists, strlen(name), + name); atom->reply = xcb_intern_atom_reply(x11->xcb_conn, atom->cookie, NULL); } @@ -201,7 +202,8 @@ static bool wlr_x11_backend_start(struct wlr_backend *backend) { output->x11 = x11; - wlr_output_init(&output->wlr_output, &x11->backend, &output_impl); + wlr_output_init(&output->wlr_output, &x11->backend, &output_impl, + x11->wl_display); snprintf(output->wlr_output.name, sizeof(output->wlr_output.name), "X11-1"); output->win = xcb_generate_id(x11->xcb_conn); @@ -224,7 +226,7 @@ static bool wlr_x11_backend_start(struct wlr_backend *backend) { xcb_map_window(x11->xcb_conn, output->win); xcb_flush(x11->xcb_conn); - wlr_output_create_global(&output->wlr_output, x11->wl_display); + wlr_output_update_enabled(&output->wlr_output, true); wl_signal_emit(&x11->backend.events.output_add, output); wl_signal_emit(&x11->backend.events.input_add, &x11->keyboard_dev); diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index 6d71f9b6..d5837def 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -26,14 +26,11 @@ struct wlr_output_impl { }; void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, - const struct wlr_output_impl *impl); -void wlr_output_free(struct wlr_output *output); + const struct wlr_output_impl *impl, struct wl_display *display); void wlr_output_update_mode(struct wlr_output *output, struct wlr_output_mode *mode); void wlr_output_update_custom_mode(struct wlr_output *output, int32_t width, int32_t height, int32_t refresh); -struct wl_global *wlr_output_create_global(struct wlr_output *wlr_output, - struct wl_display *display); -void wlr_output_destroy_global(struct wlr_output *wlr_output); +void wlr_output_update_enabled(struct wlr_output *output, bool enabled); #endif diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 6374ae9b..e7491704 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -36,19 +36,19 @@ struct wlr_output_impl; struct wlr_output { const struct wlr_output_impl *impl; struct wlr_backend *backend; + struct wl_display *display; struct wl_global *wl_global; struct wl_list wl_resources; - uint32_t flags; char name[16]; char make[48]; char model[16]; char serial[16]; - float scale; - int32_t width, height; - int32_t refresh; // mHz int32_t phys_width, phys_height; // mm + + bool enabled; + float scale; enum wl_output_subpixel subpixel; enum wl_output_transform transform; bool needs_swap; @@ -58,6 +58,8 @@ struct wlr_output { // Note: some backends may have zero modes struct wl_list modes; struct wlr_output_mode *current_mode; + int32_t width, height; + int32_t refresh; // mHz struct { struct wl_signal frame; diff --git a/types/wlr_output.c b/types/wlr_output.c index 14d12da9..18c2ef89 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -113,38 +113,39 @@ static void wl_output_bind(struct wl_client *wl_client, void *data, wl_output_send_to_resource(wl_resource); } -static void handle_display_destroy(struct wl_listener *listener, void *data) { - struct wlr_output *output = - wl_container_of(listener, output, display_destroy); - wlr_output_destroy_global(output); -} - -struct wl_global *wlr_output_create_global(struct wlr_output *wlr_output, - struct wl_display *display) { - if (wlr_output->wl_global != NULL) { - return wlr_output->wl_global; +static void wlr_output_create_global(struct wlr_output *output) { + if (output->wl_global != NULL) { + return; } - struct wl_global *wl_global = wl_global_create(display, - &wl_output_interface, 3, wlr_output, wl_output_bind); - wlr_output->wl_global = wl_global; - - wlr_output->display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(display, &wlr_output->display_destroy); - - return wl_global; + struct wl_global *wl_global = wl_global_create(output->display, + &wl_output_interface, 3, output, wl_output_bind); + output->wl_global = wl_global; } -void wlr_output_destroy_global(struct wlr_output *wlr_output) { - if (wlr_output->wl_global == NULL) { +static void wlr_output_destroy_global(struct wlr_output *output) { + if (output->wl_global == NULL) { return; } - wl_list_remove(&wlr_output->display_destroy.link); struct wl_resource *resource, *tmp; - wl_resource_for_each_safe(resource, tmp, &wlr_output->wl_resources) { + wl_resource_for_each_safe(resource, tmp, &output->wl_resources) { wl_resource_destroy(resource); } - wl_global_destroy(wlr_output->wl_global); - wlr_output->wl_global = NULL; + wl_global_destroy(output->wl_global); + output->wl_global = NULL; +} + +void wlr_output_update_enabled(struct wlr_output *output, bool enabled) { + if (output->enabled == enabled) { + return; + } + + output->enabled = enabled; + + if (enabled) { + wlr_output_create_global(output); + } else { + wlr_output_destroy_global(output); + } } static void wlr_output_update_matrix(struct wlr_output *output) { @@ -248,11 +249,18 @@ void wlr_output_set_scale(struct wlr_output *output, float scale) { wl_signal_emit(&output->events.scale, output); } +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_output *output = + wl_container_of(listener, output, display_destroy); + wlr_output_destroy_global(output); +} + void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, - const struct wlr_output_impl *impl) { + const struct wlr_output_impl *impl, struct wl_display *display) { assert(impl->make_current && impl->swap_buffers && impl->transform); output->backend = backend; output->impl = impl; + output->display = display; wl_list_init(&output->modes); output->transform = WL_OUTPUT_TRANSFORM_NORMAL; output->scale = 1; @@ -264,6 +272,9 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.scale); wl_signal_init(&output->events.transform); wl_signal_init(&output->events.destroy); + + output->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &output->display_destroy); } void wlr_output_destroy(struct wlr_output *output) { @@ -271,6 +282,7 @@ void wlr_output_destroy(struct wlr_output *output) { return; } + wl_list_remove(&output->display_destroy.link); wlr_output_destroy_global(output); wlr_output_set_fullscreen_surface(output, NULL); From d9ecfbaf325f66b15d60d0f8c4fe08a939cb6576 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 4 Jan 2018 14:51:36 +0100 Subject: [PATCH 02/21] Add wlr_output enable event --- include/wlr/types/wlr_output.h | 1 + types/wlr_output.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index e7491704..a726c4c8 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -64,6 +64,7 @@ struct wlr_output { struct { struct wl_signal frame; struct wl_signal swap_buffers; + struct wl_signal enable; struct wl_signal resolution; struct wl_signal scale; struct wl_signal transform; diff --git a/types/wlr_output.c b/types/wlr_output.c index 18c2ef89..4b842571 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -146,6 +146,8 @@ void wlr_output_update_enabled(struct wlr_output *output, bool enabled) { } else { wlr_output_destroy_global(output); } + + wl_signal_emit(&output->events.enable, output); } static void wlr_output_update_matrix(struct wlr_output *output) { @@ -269,6 +271,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.frame); wl_signal_init(&output->events.swap_buffers); wl_signal_init(&output->events.resolution); + wl_signal_init(&output->events.enable); wl_signal_init(&output->events.scale); wl_signal_init(&output->events.transform); wl_signal_init(&output->events.destroy); From be3a7b0017823d80cd50c830d788a96e0e0ef6e8 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 4 Jan 2018 15:48:28 +0100 Subject: [PATCH 03/21] Disable outputs in rootston config --- include/rootston/config.h | 1 + rootston/config.c | 11 ++++++++++- rootston/output.c | 21 +++++++++++++-------- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/include/rootston/config.h b/include/rootston/config.h index bd24e577..05f23b75 100644 --- a/include/rootston/config.h +++ b/include/rootston/config.h @@ -7,6 +7,7 @@ struct roots_output_config { char *name; + bool enable; enum wl_output_transform transform; int x, y; float scale; diff --git a/rootston/config.c b/rootston/config.c index f9fde369..31bde2b0 100644 --- a/rootston/config.c +++ b/rootston/config.c @@ -263,10 +263,19 @@ static int config_ini_handler(void *user, const char *section, const char *name, oc->name = strdup(output_name); oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; oc->scale = 1; + oc->enable = true; wl_list_insert(&config->outputs, &oc->link); } - if (strcmp(name, "x") == 0) { + if (strcmp(name, "enable") == 0) { + if (strcasecmp(value, "true") == 0) { + oc->enable = true; + } else if (strcasecmp(value, "false") == 0) { + oc->enable = false; + } else { + wlr_log(L_ERROR, "got invalid output enable value: %s", value); + } + } else if (strcmp(name, "x") == 0) { oc->x = strtol(value, NULL, 10); } else if (strcmp(name, "y") == 0) { oc->y = strtol(value, NULL, 10); diff --git a/rootston/output.c b/rootston/output.c index 10450df3..7e05136a 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -324,9 +324,10 @@ void output_add_notify(struct wl_listener *listener, void *data) { wlr_log(L_DEBUG, "'%s %s %s' %"PRId32"mm x %"PRId32"mm", wlr_output->make, wlr_output->model, wlr_output->serial, wlr_output->phys_width, wlr_output->phys_height); + if (wl_list_length(&wlr_output->modes) > 0) { - struct wlr_output_mode *mode = NULL; - mode = wl_container_of((&wlr_output->modes)->prev, mode, link); + struct wlr_output_mode *mode = + wl_container_of((&wlr_output->modes)->prev, mode, link); wlr_output_set_mode(wlr_output, mode); } @@ -341,13 +342,17 @@ void output_add_notify(struct wl_listener *listener, void *data) { struct roots_output_config *output_config = roots_config_get_output(config, wlr_output); if (output_config) { - if (output_config->mode.width) { - set_mode(wlr_output, output_config); + if (output_config->enable) { + if (output_config->mode.width) { + set_mode(wlr_output, output_config); + } + wlr_output_set_scale(wlr_output, output_config->scale); + wlr_output_set_transform(wlr_output, output_config->transform); + wlr_output_layout_add(desktop->layout, wlr_output, output_config->x, + output_config->y); + } else { + wlr_output_enable(wlr_output, false); } - wlr_output_set_scale(wlr_output, output_config->scale); - wlr_output_set_transform(wlr_output, output_config->transform); - wlr_output_layout_add(desktop->layout, wlr_output, output_config->x, - output_config->y); } else { wlr_output_layout_add_auto(desktop->layout, wlr_output); } From 6fe380a1769fe40a9ce0f1d6f1aeb1b3beb63c16 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 6 Jan 2018 12:39:15 +0100 Subject: [PATCH 04/21] output_layout: handle output enable event --- types/wlr_output_layout.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 5b2dee8c..7e782399 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -18,6 +18,7 @@ struct wlr_output_layout_output_state { struct wlr_box _box; // should never be read directly, use the getter bool auto_configured; + struct wl_listener enable; struct wl_listener resolution; struct wl_listener scale; struct wl_listener transform; @@ -47,6 +48,7 @@ struct wlr_output_layout *wlr_output_layout_create() { static void wlr_output_layout_output_destroy( struct wlr_output_layout_output *l_output) { wl_signal_emit(&l_output->events.destroy, l_output); + wl_list_remove(&l_output->state->enable.link); wl_list_remove(&l_output->state->resolution.link); wl_list_remove(&l_output->state->scale.link); wl_list_remove(&l_output->state->transform.link); @@ -74,12 +76,19 @@ void wlr_output_layout_destroy(struct wlr_output_layout *layout) { static struct wlr_box *wlr_output_layout_output_get_box( struct wlr_output_layout_output *l_output) { - l_output->state->_box.x = l_output->x; - l_output->state->_box.y = l_output->y; - int width, height; - wlr_output_effective_resolution(l_output->output, &width, &height); - l_output->state->_box.width = width; - l_output->state->_box.height = height; + if (!l_output->output->enabled) { + l_output->state->_box.x = 0; + l_output->state->_box.y = 0; + l_output->state->_box.width = 0; + l_output->state->_box.height = 0; + } else { + l_output->state->_box.x = l_output->x; + l_output->state->_box.y = l_output->y; + int width, height; + wlr_output_effective_resolution(l_output->output, &width, &height); + l_output->state->_box.width = width; + l_output->state->_box.height = height; + } return &l_output->state->_box; } @@ -98,7 +107,7 @@ static void wlr_output_layout_reconfigure(struct wlr_output_layout *layout) { // in the layout struct wlr_output_layout_output *l_output; wl_list_for_each(l_output, &layout->outputs, link) { - if (l_output->state->auto_configured) { + if (l_output->state->auto_configured || !l_output->output->enabled) { continue; } @@ -116,7 +125,7 @@ static void wlr_output_layout_reconfigure(struct wlr_output_layout *layout) { } wl_list_for_each(l_output, &layout->outputs, link) { - if (!l_output->state->auto_configured) { + if (!l_output->state->auto_configured || !l_output->output->enabled) { continue; } struct wlr_box *box = wlr_output_layout_output_get_box(l_output); @@ -126,12 +135,21 @@ static void wlr_output_layout_reconfigure(struct wlr_output_layout *layout) { } wl_list_for_each(l_output, &layout->outputs, link) { + if (!l_output->output->enabled) { + continue; + } wlr_output_set_position(l_output->output, l_output->x, l_output->y); } wl_signal_emit(&layout->events.change, layout); } +static void handle_output_enable(struct wl_listener *listener, void *data) { + struct wlr_output_layout_output_state *state = + wl_container_of(listener, state, enable); + wlr_output_layout_reconfigure(state->layout); +} + static void handle_output_resolution(struct wl_listener *listener, void *data) { struct wlr_output_layout_output_state *state = wl_container_of(listener, state, resolution); @@ -176,6 +194,8 @@ static struct wlr_output_layout_output *wlr_output_layout_output_create( wl_signal_init(&l_output->events.destroy); wl_list_insert(&layout->outputs, &l_output->link); + wl_signal_add(&output->events.enable, &l_output->state->enable); + l_output->state->enable.notify = handle_output_enable; wl_signal_add(&output->events.resolution, &l_output->state->resolution); l_output->state->resolution.notify = handle_output_resolution; wl_signal_add(&output->events.scale, &l_output->state->scale); From 8ebd7d4dbebc89aedf5e08d30ebcb5326b92f80b Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 6 Jan 2018 12:42:32 +0100 Subject: [PATCH 05/21] output: rename resolution event to mode --- examples/support/shared.c | 2 +- include/wlr/types/wlr_output.h | 2 +- types/wlr_output.c | 4 ++-- types/wlr_output_layout.c | 12 ++++++------ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/support/shared.c b/examples/support/shared.c index f76e4389..6cfaa6aa 100644 --- a/examples/support/shared.c +++ b/examples/support/shared.c @@ -425,7 +425,7 @@ static void output_add_notify(struct wl_listener *listener, void *data) { ostate->frame.notify = output_frame_notify; ostate->resolution.notify = output_resolution_notify; wl_signal_add(&output->events.frame, &ostate->frame); - wl_signal_add(&output->events.resolution, &ostate->resolution); + wl_signal_add(&output->events.mode, &ostate->resolution); wl_list_insert(&state->outputs, &ostate->link); if (state->output_add_cb) { state->output_add_cb(ostate); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index a726c4c8..71463cb5 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -65,7 +65,7 @@ struct wlr_output { struct wl_signal frame; struct wl_signal swap_buffers; struct wl_signal enable; - struct wl_signal resolution; + struct wl_signal mode; struct wl_signal scale; struct wl_signal transform; struct wl_signal destroy; diff --git a/types/wlr_output.c b/types/wlr_output.c index 4b842571..8194c17e 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -202,7 +202,7 @@ void wlr_output_update_custom_mode(struct wlr_output *output, int32_t width, wlr_output_send_current_mode_to_resource(resource); } - wl_signal_emit(&output->events.resolution, output); + wl_signal_emit(&output->events.mode, output); } void wlr_output_set_transform(struct wlr_output *output, @@ -270,8 +270,8 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_list_init(&output->wl_resources); wl_signal_init(&output->events.frame); wl_signal_init(&output->events.swap_buffers); - wl_signal_init(&output->events.resolution); wl_signal_init(&output->events.enable); + wl_signal_init(&output->events.mode); wl_signal_init(&output->events.scale); wl_signal_init(&output->events.transform); wl_signal_init(&output->events.destroy); diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 7e782399..9b9b0c68 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -19,7 +19,7 @@ struct wlr_output_layout_output_state { bool auto_configured; struct wl_listener enable; - struct wl_listener resolution; + struct wl_listener mode; struct wl_listener scale; struct wl_listener transform; struct wl_listener output_destroy; @@ -49,7 +49,7 @@ static void wlr_output_layout_output_destroy( struct wlr_output_layout_output *l_output) { wl_signal_emit(&l_output->events.destroy, l_output); wl_list_remove(&l_output->state->enable.link); - wl_list_remove(&l_output->state->resolution.link); + wl_list_remove(&l_output->state->mode.link); wl_list_remove(&l_output->state->scale.link); wl_list_remove(&l_output->state->transform.link); wl_list_remove(&l_output->state->output_destroy.link); @@ -150,9 +150,9 @@ static void handle_output_enable(struct wl_listener *listener, void *data) { wlr_output_layout_reconfigure(state->layout); } -static void handle_output_resolution(struct wl_listener *listener, void *data) { +static void handle_output_mode(struct wl_listener *listener, void *data) { struct wlr_output_layout_output_state *state = - wl_container_of(listener, state, resolution); + wl_container_of(listener, state, mode); wlr_output_layout_reconfigure(state->layout); } @@ -196,8 +196,8 @@ static struct wlr_output_layout_output *wlr_output_layout_output_create( wl_signal_add(&output->events.enable, &l_output->state->enable); l_output->state->enable.notify = handle_output_enable; - wl_signal_add(&output->events.resolution, &l_output->state->resolution); - l_output->state->resolution.notify = handle_output_resolution; + wl_signal_add(&output->events.mode, &l_output->state->mode); + l_output->state->mode.notify = handle_output_mode; wl_signal_add(&output->events.scale, &l_output->state->scale); l_output->state->scale.notify = handle_output_scale; wl_signal_add(&output->events.transform, &l_output->state->transform); From 53ba9b4eec4345cb5ba6640e8677f3b2477d2693 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 7 Jan 2018 00:28:21 +0100 Subject: [PATCH 06/21] Fix output enable in DRM backend --- backend/drm/atomic.c | 14 +++++++++++--- backend/drm/drm.c | 5 ++++- backend/drm/legacy.c | 5 +++-- include/backend/drm/iface.h | 2 +- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index e7374a00..8d98bac2 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -123,14 +123,22 @@ static bool atomic_crtc_pageflip(struct wlr_drm_backend *drm, mode); } -static void atomic_conn_enable(struct wlr_drm_backend *drm, +static bool atomic_conn_enable(struct wlr_drm_backend *drm, struct wlr_drm_connector *conn, bool enable) { struct wlr_drm_crtc *crtc = conn->crtc; - struct atomic atom; + struct atomic atom; atomic_begin(crtc, &atom); atomic_add(&atom, crtc->id, crtc->props.active, enable); - atomic_end(drm->fd, &atom); + if (enable) { + atomic_add(&atom, conn->id, conn->props.crtc_id, crtc->id); + atomic_add(&atom, crtc->id, crtc->props.mode_id, crtc->mode_id); + } else { + atomic_add(&atom, conn->id, conn->props.crtc_id, 0); + atomic_add(&atom, crtc->id, crtc->props.mode_id, 0); + } + return atomic_commit(drm->fd, &atom, conn, DRM_MODE_ATOMIC_ALLOW_MODESET, + true); } bool legacy_crtc_set_cursor(struct wlr_drm_backend *drm, diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 32b2f88c..0d32605a 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -252,7 +252,10 @@ static void wlr_drm_connector_enable(struct wlr_output *output, bool enable) { } struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; - drm->iface->conn_enable(drm, conn, enable); + bool ok = drm->iface->conn_enable(drm, conn, enable); + if (!ok) { + return; + } if (enable) { wlr_drm_connector_start_renderer(conn); diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index d75eb2cb..61140cec 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -25,10 +25,11 @@ static bool legacy_crtc_pageflip(struct wlr_drm_backend *drm, return true; } -static void legacy_conn_enable(struct wlr_drm_backend *drm, +static bool legacy_conn_enable(struct wlr_drm_backend *drm, struct wlr_drm_connector *conn, bool enable) { - drmModeConnectorSetProperty(drm->fd, conn->id, conn->props.dpms, + int ret = drmModeConnectorSetProperty(drm->fd, conn->id, conn->props.dpms, enable ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF); + return ret >= 0; } bool legacy_crtc_set_cursor(struct wlr_drm_backend *drm, diff --git a/include/backend/drm/iface.h b/include/backend/drm/iface.h index bc61eb51..4a5d2e9d 100644 --- a/include/backend/drm/iface.h +++ b/include/backend/drm/iface.h @@ -15,7 +15,7 @@ struct wlr_drm_crtc; // Used to provide atomic or legacy DRM functions struct wlr_drm_interface { // Enable or disable DPMS for connector - void (*conn_enable)(struct wlr_drm_backend *drm, + bool (*conn_enable)(struct wlr_drm_backend *drm, struct wlr_drm_connector *conn, bool enable); // Pageflip on crtc. If mode is non-NULL perform a full modeset using it. bool (*crtc_pageflip)(struct wlr_drm_backend *drm, From 77fc0505e6afed714fc4e96358fc04dc1c1be54b Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 7 Jan 2018 00:30:55 +0100 Subject: [PATCH 07/21] rootston: do not attempt to render disabled outputs --- rootston/output.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rootston/output.c b/rootston/output.c index 7e05136a..a8866fa6 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -211,6 +211,10 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct roots_desktop *desktop = output->desktop; struct roots_server *server = desktop->server; + if (!wlr_output->enabled) { + return; + } + struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); From e56b82e89639d3699cee8ada8eac7e8507e8c864 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 7 Jan 2018 00:37:36 +0100 Subject: [PATCH 08/21] rootston: add toggle_outputs command --- rootston/keyboard.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/rootston/keyboard.c b/rootston/keyboard.c index 7b281308..14199afd 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -85,6 +86,8 @@ static void pressed_keysyms_update(xkb_keysym_t *pressed_keysyms, static const char *exec_prefix = "exec "; +static bool outputs_enabled = true; + static void keyboard_binding_execute(struct roots_keyboard *keyboard, const char *command) { struct roots_seat *seat = keyboard->seat; @@ -119,6 +122,12 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, } } else if (strcmp(command, "nop") == 0) { wlr_log(L_DEBUG, "nop command"); + } else if (strcmp(command, "toggle_outputs") == 0) { + outputs_enabled = !outputs_enabled; + struct roots_output *output; + wl_list_for_each(output, &keyboard->input->server->desktop->outputs, link) { + wlr_output_enable(output->wlr_output, outputs_enabled); + } } else { wlr_log(L_ERROR, "unknown binding command: %s", command); } From 33c427a6aaf472577dcde7ab85ff2cf0e379b4c3 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 7 Jan 2018 18:40:58 +0100 Subject: [PATCH 09/21] output_layout: disabled outputs are just like enabled outputs --- types/wlr_output_layout.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 9b9b0c68..d1d67e7d 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -18,7 +18,6 @@ struct wlr_output_layout_output_state { struct wlr_box _box; // should never be read directly, use the getter bool auto_configured; - struct wl_listener enable; struct wl_listener mode; struct wl_listener scale; struct wl_listener transform; @@ -48,7 +47,6 @@ struct wlr_output_layout *wlr_output_layout_create() { static void wlr_output_layout_output_destroy( struct wlr_output_layout_output *l_output) { wl_signal_emit(&l_output->events.destroy, l_output); - wl_list_remove(&l_output->state->enable.link); wl_list_remove(&l_output->state->mode.link); wl_list_remove(&l_output->state->scale.link); wl_list_remove(&l_output->state->transform.link); @@ -76,19 +74,12 @@ void wlr_output_layout_destroy(struct wlr_output_layout *layout) { static struct wlr_box *wlr_output_layout_output_get_box( struct wlr_output_layout_output *l_output) { - if (!l_output->output->enabled) { - l_output->state->_box.x = 0; - l_output->state->_box.y = 0; - l_output->state->_box.width = 0; - l_output->state->_box.height = 0; - } else { - l_output->state->_box.x = l_output->x; - l_output->state->_box.y = l_output->y; - int width, height; - wlr_output_effective_resolution(l_output->output, &width, &height); - l_output->state->_box.width = width; - l_output->state->_box.height = height; - } + l_output->state->_box.x = l_output->x; + l_output->state->_box.y = l_output->y; + int width, height; + wlr_output_effective_resolution(l_output->output, &width, &height); + l_output->state->_box.width = width; + l_output->state->_box.height = height; return &l_output->state->_box; } @@ -107,7 +98,7 @@ static void wlr_output_layout_reconfigure(struct wlr_output_layout *layout) { // in the layout struct wlr_output_layout_output *l_output; wl_list_for_each(l_output, &layout->outputs, link) { - if (l_output->state->auto_configured || !l_output->output->enabled) { + if (l_output->state->auto_configured) { continue; } @@ -125,7 +116,7 @@ static void wlr_output_layout_reconfigure(struct wlr_output_layout *layout) { } wl_list_for_each(l_output, &layout->outputs, link) { - if (!l_output->state->auto_configured || !l_output->output->enabled) { + if (!l_output->state->auto_configured) { continue; } struct wlr_box *box = wlr_output_layout_output_get_box(l_output); @@ -135,21 +126,12 @@ static void wlr_output_layout_reconfigure(struct wlr_output_layout *layout) { } wl_list_for_each(l_output, &layout->outputs, link) { - if (!l_output->output->enabled) { - continue; - } wlr_output_set_position(l_output->output, l_output->x, l_output->y); } wl_signal_emit(&layout->events.change, layout); } -static void handle_output_enable(struct wl_listener *listener, void *data) { - struct wlr_output_layout_output_state *state = - wl_container_of(listener, state, enable); - wlr_output_layout_reconfigure(state->layout); -} - static void handle_output_mode(struct wl_listener *listener, void *data) { struct wlr_output_layout_output_state *state = wl_container_of(listener, state, mode); @@ -194,8 +176,6 @@ static struct wlr_output_layout_output *wlr_output_layout_output_create( wl_signal_init(&l_output->events.destroy); wl_list_insert(&layout->outputs, &l_output->link); - wl_signal_add(&output->events.enable, &l_output->state->enable); - l_output->state->enable.notify = handle_output_enable; wl_signal_add(&output->events.mode, &l_output->state->mode); l_output->state->mode.notify = handle_output_mode; wl_signal_add(&output->events.scale, &l_output->state->scale); From 21cc5e6fefaf737b6468dd1783ea1afa23ee8313 Mon Sep 17 00:00:00 2001 From: Heghedus Razvan Date: Sun, 7 Jan 2018 21:41:43 +0200 Subject: [PATCH 10/21] Add idle protocol Signed-off-by: Heghedus Razvan --- include/wlr/types/wlr_idle.h | 51 ++++++++++ protocol/idle.xml | 49 +++++++++ protocol/meson.build | 2 + types/meson.build | 1 + types/wlr_idle.c | 190 +++++++++++++++++++++++++++++++++++ 5 files changed, 293 insertions(+) create mode 100644 include/wlr/types/wlr_idle.h create mode 100644 protocol/idle.xml create mode 100644 types/wlr_idle.c diff --git a/include/wlr/types/wlr_idle.h b/include/wlr/types/wlr_idle.h new file mode 100644 index 00000000..689c33a4 --- /dev/null +++ b/include/wlr/types/wlr_idle.h @@ -0,0 +1,51 @@ +#ifndef WLR_TYPES_WLR_IDLE_H +#define WLR_TYPES_WLR_IDLE_H + +#include +#include + +/** + * Idle protocol is used to create timers which will notify the client when the + * compositor does not receive any input for a given time(in milliseconds). Also + * the client will be notify when the timer receve an activity notify and already + * was in idle state. Besides this, the client is able to simulate user activity + * which will reset the timers and at any time can destroy the timer. + */ + + +struct wlr_idle { + struct wl_global *wl_global; + struct wl_list idle_timers; // wlr_idle_timeout::link + struct wl_event_loop *event_loop; + + struct wl_listener display_destroy; + struct wl_signal activity_notify; + + void *data; +}; + +struct wlr_idle_timeout { + struct wl_resource *resource; + struct wl_list link; + struct wlr_seat *seat; + + struct wl_event_source *idle_source; + bool idle_state; + uint32_t timeout; // milliseconds + + struct wl_listener input_listener; + struct wl_listener seat_destroy; + + void *data; +}; + +struct wlr_idle *wlr_idle_create(struct wl_display *display); + +void wlr_idle_destroy(struct wlr_idle *idle); + +/** + * Send notification to restart all timers for the given seat. Called by + * compositor when there is an user activity event on that seat. + */ +void wlr_idle_notify_activity(struct wlr_idle *idle, struct wlr_seat *seat); +#endif diff --git a/protocol/idle.xml b/protocol/idle.xml new file mode 100644 index 00000000..92d9989c --- /dev/null +++ b/protocol/idle.xml @@ -0,0 +1,49 @@ + + + . + ]]> + + + This interface allows to monitor user idle time on a given seat. The interface + allows to register timers which trigger after no user activity was registered + on the seat for a given interval. It notifies when user activity resumes. + + This is useful for applications wanting to perform actions when the user is not + interacting with the system, e.g. chat applications setting the user as away, power + management features to dim screen, etc.. + + + + + + + + + + + + + + + + + + + + + + diff --git a/protocol/meson.build b/protocol/meson.build index f6aca5f5..6e9f4125 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -26,6 +26,7 @@ protocols = [ 'gtk-primary-selection.xml', 'screenshooter.xml', 'server-decoration.xml', + 'idle.xml', ] client_protocols = [ @@ -34,6 +35,7 @@ client_protocols = [ 'gtk-primary-selection.xml', 'screenshooter.xml', 'server-decoration.xml', + 'idle.xml', ] wl_protos_src = [] diff --git a/types/meson.build b/types/meson.build index 82031e89..62a2faec 100644 --- a/types/meson.build +++ b/types/meson.build @@ -6,6 +6,7 @@ lib_wlr_types = static_library( 'wlr_compositor.c', 'wlr_cursor.c', 'wlr_gamma_control.c', + 'wlr_idle.c', 'wlr_input_device.c', 'wlr_keyboard.c', 'wlr_list.c', diff --git a/types/wlr_idle.c b/types/wlr_idle.c new file mode 100644 index 00000000..f2cad42b --- /dev/null +++ b/types/wlr_idle.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include +#include +#include "idle-protocol.h" + +static void idle_timeout_destroy(struct wlr_idle_timeout *timer) { + wl_list_remove(&timer->input_listener.link); + wl_list_remove(&timer->seat_destroy.link); + wl_event_source_remove(timer->idle_source); + wl_list_remove(&timer->link); + wl_resource_set_user_data(timer->resource, NULL); + free(timer); +} + +static int idle_notify(void *data) { + struct wlr_idle_timeout *timer = data; + timer->idle_state = true; + org_kde_kwin_idle_timeout_send_idle(timer->resource); + return 1; +} + +static void handle_activity(struct wlr_idle_timeout *timer) { + // rearm the timer + wl_event_source_timer_update(timer->idle_source, timer->timeout); + // in case the previous state was sleeping send a resume event and switch state + if (timer->idle_state) { + timer->idle_state = false; + org_kde_kwin_idle_timeout_send_resumed(timer->resource); + } +} + +static void handle_timer_resource_destroy(struct wl_resource *timer_resource) { + struct wlr_idle_timeout *timer = wl_resource_get_user_data(timer_resource); + if (timer != NULL) { + idle_timeout_destroy(timer); + } +} + +static void handle_seat_destroy(struct wl_listener *listener, void *data) { + struct wlr_idle_timeout *timer = wl_container_of(listener, timer, seat_destroy); + if (timer != NULL) { + idle_timeout_destroy(timer); + } +} + +static void release_idle_timeout(struct wl_client *client, + struct wl_resource *resource){ + handle_timer_resource_destroy(resource); +} + +static void simulate_activity(struct wl_client *client, + struct wl_resource *resource){ + struct wlr_idle_timeout *timer = wl_resource_get_user_data(resource); + handle_activity(timer); +} + +static struct org_kde_kwin_idle_timeout_interface idle_timeout_impl = { + .release = release_idle_timeout, + .simulate_user_activity = simulate_activity, +}; + +static void handle_input_notification(struct wl_listener *listener, void *data) { + struct wlr_idle_timeout *timer = wl_container_of(listener, timer, input_listener); + struct wlr_seat *seat = data; + if (timer->seat == seat) { + handle_activity(timer); + } +} + +static void create_idle_timer(struct wl_client *client, + struct wl_resource *idle_resource, + uint32_t id, + struct wl_resource *seat_resource, + uint32_t timeout) { + struct wlr_idle *idle = wl_resource_get_user_data(idle_resource); + struct wlr_seat_client *client_seat = + wl_resource_get_user_data(seat_resource); + + struct wlr_idle_timeout *timer = + calloc(1, sizeof(struct wlr_idle_timeout)); + if (!timer) { + wl_resource_post_no_memory(idle_resource); + return; + } + timer->seat = client_seat->seat; + timer->timeout = timeout; + timer->idle_state = false; + timer->resource = wl_resource_create(client, + &org_kde_kwin_idle_timeout_interface, + wl_resource_get_version(idle_resource), id); + if (timer->resource == NULL) { + free(timer); + wl_resource_post_no_memory(idle_resource); + return; + } + wl_resource_set_implementation(timer->resource, &idle_timeout_impl, timer, + handle_timer_resource_destroy); + wl_list_insert(&idle->idle_timers, &timer->link); + + timer->seat_destroy.notify = handle_seat_destroy; + wl_signal_add(&timer->seat->events.destroy, &timer->seat_destroy); + + timer->input_listener.notify = handle_input_notification; + wl_signal_add(&idle->activity_notify, &timer->input_listener); + // create the timer + timer->idle_source = + wl_event_loop_add_timer(idle->event_loop, idle_notify, timer); + if (timer->idle_source == NULL) { + wl_list_remove(&timer->link); + wl_list_remove(&timer->input_listener.link); + wl_list_remove(&timer->seat_destroy.link); + wl_resource_set_user_data(timer->resource, NULL); + free(timer); + wl_resource_post_no_memory(idle_resource); + return; + } + // arm the timer + wl_event_source_timer_update(timer->idle_source, timer->timeout); +} + +static struct org_kde_kwin_idle_interface idle_impl = { + .get_idle_timeout = create_idle_timer, +}; + +static void idle_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) { + struct wlr_idle *idle = data; + assert(wl_client && idle); + + struct wl_resource *wl_resource = wl_resource_create(wl_client, + &org_kde_kwin_idle_interface, version, id); + if (wl_resource == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + wl_resource_set_implementation(wl_resource, &idle_impl, idle, NULL); +} + +void wlr_idle_destroy(struct wlr_idle *idle) { + if (!idle) { + return; + } + wl_list_remove(&idle->display_destroy.link); + struct wlr_idle_timeout *timer, *tmp; + wl_list_for_each_safe(timer, tmp, &idle->idle_timers, link) { + idle_timeout_destroy(timer); + } + wl_global_destroy(idle->wl_global); + free(idle); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_idle *idle = wl_container_of(listener, idle, display_destroy); + wlr_idle_destroy(idle); +} + +struct wlr_idle *wlr_idle_create(struct wl_display *display) { + struct wlr_idle *idle = calloc(1, sizeof(struct wlr_idle)); + if (!idle) { + return NULL; + } + wl_list_init(&idle->idle_timers); + wl_signal_init(&idle->activity_notify); + + idle->event_loop = wl_display_get_event_loop(display); + if (idle->event_loop == NULL) { + free(idle); + return NULL; + } + + idle->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &idle->display_destroy); + + idle->wl_global = wl_global_create(display, &org_kde_kwin_idle_interface, + 1, idle, idle_bind); + if (idle->wl_global == NULL){ + wl_list_remove(&idle->display_destroy.link); + free(idle); + return NULL; + } + wlr_log(L_DEBUG, "idle manager created"); + return idle; +} + +void wlr_idle_notify_activity(struct wlr_idle *idle, struct wlr_seat *seat) { + wl_signal_emit(&idle->activity_notify, seat); +} From 440cf7112df12bd84dc15c07d65dab1ae26630ba Mon Sep 17 00:00:00 2001 From: Heghedus Razvan Date: Sun, 7 Jan 2018 21:42:06 +0200 Subject: [PATCH 11/21] Include idle protocol in rootston Signed-off-by: Heghedus Razvan --- include/rootston/desktop.h | 2 ++ rootston/desktop.c | 2 ++ rootston/seat.c | 25 +++++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 8d706b65..9dfd7b10 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "rootston/view.h" #include "rootston/config.h" @@ -44,6 +45,7 @@ struct roots_desktop { struct wlr_screenshooter *screenshooter; struct wlr_server_decoration_manager *server_decoration_manager; struct wlr_primary_selection_device_manager *primary_selection_device_manager; + struct wlr_idle *idle; struct wl_listener output_add; struct wl_listener output_remove; diff --git a/rootston/desktop.c b/rootston/desktop.c index b74e2cb1..d7da1600 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -502,6 +503,7 @@ struct roots_desktop *desktop_create(struct roots_server *server, WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); desktop->primary_selection_device_manager = wlr_primary_selection_device_manager_create(server->wl_display); + desktop->idle = wlr_idle_create(server->wl_display); return desktop; } diff --git a/rootston/seat.c b/rootston/seat.c index 2728ca96..130c7b27 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "rootston/xcursor.h" #include "rootston/input.h" #include "rootston/seat.h" @@ -14,6 +15,8 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { struct roots_keyboard *keyboard = wl_container_of(listener, keyboard, keyboard_key); + struct roots_desktop *desktop = keyboard->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, keyboard->seat->seat); struct wlr_event_keyboard_key *event = data; roots_keyboard_handle_key(keyboard, event); } @@ -22,12 +25,16 @@ static void handle_keyboard_modifiers(struct wl_listener *listener, void *data) { struct roots_keyboard *keyboard = wl_container_of(listener, keyboard, keyboard_modifiers); + struct roots_desktop *desktop = keyboard->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, keyboard->seat->seat); roots_keyboard_handle_modifiers(keyboard); } static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, motion); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_pointer_motion *event = data; roots_cursor_handle_motion(cursor, event); } @@ -36,6 +43,8 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, motion_absolute); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_pointer_motion_absolute *event = data; roots_cursor_handle_motion_absolute(cursor, event); } @@ -43,6 +52,8 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, static void handle_cursor_button(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, button); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_pointer_button *event = data; roots_cursor_handle_button(cursor, event); } @@ -50,6 +61,8 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { static void handle_cursor_axis(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, axis); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_pointer_axis *event = data; roots_cursor_handle_axis(cursor, event); } @@ -57,6 +70,8 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) { static void handle_touch_down(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, touch_down); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_touch_down *event = data; roots_cursor_handle_touch_down(cursor, event); } @@ -64,6 +79,8 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { static void handle_touch_up(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, touch_up); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_touch_up *event = data; roots_cursor_handle_touch_up(cursor, event); } @@ -71,6 +88,8 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { static void handle_touch_motion(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, touch_motion); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_touch_motion *event = data; roots_cursor_handle_touch_motion(cursor, event); } @@ -78,6 +97,8 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { static void handle_tool_axis(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, tool_axis); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_tablet_tool_axis *event = data; roots_cursor_handle_tool_axis(cursor, event); } @@ -85,6 +106,8 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) { static void handle_tool_tip(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, tool_tip); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_tablet_tool_tip *event = data; roots_cursor_handle_tool_tip(cursor, event); } @@ -93,6 +116,8 @@ static void handle_request_set_cursor(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, request_set_cursor); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_seat_pointer_request_set_cursor_event *event = data; roots_cursor_handle_request_set_cursor(cursor, event); } From 9e85283f063d32c5e35b2091c4e67fc5cea0b630 Mon Sep 17 00:00:00 2001 From: Heghedus Razvan Date: Sun, 7 Jan 2018 21:42:33 +0200 Subject: [PATCH 12/21] Add example for idle protocol Signed-off-by: Heghedus Razvan --- examples/idle.c | 189 +++++++++++++++++++++++++++++++++++++++++++ examples/meson.build | 9 +++ 2 files changed, 198 insertions(+) create mode 100644 examples/idle.c diff --git a/examples/idle.c b/examples/idle.c new file mode 100644 index 00000000..e5e01f63 --- /dev/null +++ b/examples/idle.c @@ -0,0 +1,189 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct org_kde_kwin_idle *idle_manager = NULL; +static struct wl_seat *seat = NULL; +static uint32_t timeout = 0, simulate_activity_timeout = 0, close_timeout = 0; +static int run = 1; + +struct thread_args { + struct wl_display *display; + struct org_kde_kwin_idle_timeout *timer; +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + fprintf(stdout, "interfaces found: %s\n", interface); + if (strcmp(interface, "org_kde_kwin_idle") == 0) { + idle_manager = wl_registry_bind(registry, name, &org_kde_kwin_idle_interface, 1); + } + else if (strcmp(interface, "wl_seat") == 0) { + seat = wl_registry_bind(registry, name, &wl_seat_interface, 1); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { + //TODO +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +static void handle_idle(void* data, struct org_kde_kwin_idle_timeout *timer) { + fprintf(stdout, "idle state\n"); +} + +static void handle_resume(void* data, struct org_kde_kwin_idle_timeout *timer) { + fprintf(stdout, "active state\n"); +} + +static const struct org_kde_kwin_idle_timeout_listener idle_timer_listener = { + .idle = handle_idle, + .resumed = handle_resume, +}; + +int parse_args(int argc, char *argv[]) { + int c; + while ((c = getopt(argc, argv, "c:hs:t:")) != -1) { + switch(c) + { + case 'c': + close_timeout = strtoul(optarg, NULL, 10); + break; + case 's': + simulate_activity_timeout = strtoul(optarg, NULL, 10); + break; + case 't': + timeout = strtoul(optarg, NULL, 10); + break; + case 'h': + case '?': + printf("Usage: %s [OPTIONS]\n", argv[0]); + printf(" -t seconds\t\t\tidle timeout in seconds\n"); + printf(" -s seconds optional\t\tsimulate user activity after x seconds\n"); + printf(" -c seconds optional\t\tclose program after x seconds\n"); + printf(" -h\t\t\t\tthis help menu\n"); + return 1; + default: + return 1; + } + } + return 0; +} + +void *simulate_activity(void *data) { + sleep(simulate_activity_timeout); + fprintf(stdout, "simulate user activity\n"); + struct thread_args *arg = data; + org_kde_kwin_idle_timeout_simulate_user_activity(arg->timer); + wl_display_roundtrip(arg->display); + return NULL; +} + +void *close_program(void *data) { + sleep(close_timeout); + struct thread_args *arg = data; + org_kde_kwin_idle_timeout_release(arg->timer); + wl_display_roundtrip(arg->display); + fprintf(stdout, "close program\n"); + run = 0; + return NULL; +} + +void *main_loop(void *data) { + struct wl_display *display = data; + while (wl_display_dispatch(display) != -1) { + ; + } + return NULL; +} + +int main(int argc, char *argv[]) { + + if (parse_args(argc, argv) != 0) { + return -1; + } + if (timeout == 0) { + printf("idle timeout 0 is invalid\n"); + return -1; + } + + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "failed to create display\n"); + return -1; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (idle_manager == NULL) { + fprintf(stderr, "display doesn't support idle protocol\n"); + return -1; + } + if (seat== NULL) { + fprintf(stderr, "seat error\n"); + return -1; + } + struct org_kde_kwin_idle_timeout *timer = + org_kde_kwin_idle_get_idle_timeout(idle_manager, seat, timeout * 1000); + + if (timer == NULL) { + fprintf(stderr, "Could not create idle_timeout\n"); + return -1; + } + + pthread_t t1, t2, t3; + struct thread_args arg = { + .timer = timer, + .display = display, + }; + + if (simulate_activity_timeout != 0 && simulate_activity_timeout < close_timeout) { + if (pthread_create(&t1, NULL, &simulate_activity, (void *)&arg) != 0) { + return -1; + } + } + if (close_timeout != 0) { + if (pthread_create(&t2, NULL, &close_program, (void *)&arg) != 0) { + if (simulate_activity_timeout != 0) { + pthread_cancel(t1); + } + return -1; + } + } + + org_kde_kwin_idle_timeout_add_listener(timer, &idle_timer_listener, timer); + fprintf(stdout, "waiting\n"); + + if (pthread_create(&t3, NULL, &main_loop, (void *)display) != 0) { + if (simulate_activity_timeout != 0) { + pthread_cancel(t1); + } + if (close_timeout != 0 ) { + pthread_cancel(t2); + } + } + + if (simulate_activity_timeout != 0) { + pthread_join(t1, NULL); + } + if (close_timeout != 0) { + pthread_join(t2, NULL); + } + pthread_cancel(t3); + + wl_display_disconnect(display); + return 0; +} diff --git a/examples/meson.build b/examples/meson.build index af0f5a18..aa9eac47 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -5,6 +5,8 @@ lib_shared = static_library( include_directories: include_directories('support') ) +threads = dependency('threads') + executable('simple', 'simple.c', dependencies: wlroots, link_with: lib_shared) executable('pointer', 'pointer.c', dependencies: wlroots, link_with: lib_shared) executable('touch', 'touch.c', dependencies: wlroots, link_with: lib_shared) @@ -32,3 +34,10 @@ executable( dependencies: [wayland_client, wlr_protos, wlroots], link_with: lib_shared, ) + +executable( + 'idle', + 'idle.c', + dependencies: [wayland_client, wlr_protos, wlroots, threads], + link_with: lib_shared, +) From c00e9d1416e609543b41d15550841a10a9b38632 Mon Sep 17 00:00:00 2001 From: Markus Ongyerth Date: Sat, 13 Jan 2018 21:20:15 +0100 Subject: [PATCH 13/21] adds remote argument to wayland backend create Add a remote display name argument to wlr_wl_backend_create. If NULL is passed to the wayland backend at all times, creating a wayland backend *after* the compositor was started up, would require changing the WAYLAND_DISPLAY environment variable. --- backend/backend.c | 2 +- backend/wayland/backend.c | 4 ++-- include/wlr/backend/wayland.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index 6b32bc6a..54e1cdca 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -53,7 +53,7 @@ struct wlr_egl *wlr_backend_get_egl(struct wlr_backend *backend) { } static struct wlr_backend *attempt_wl_backend(struct wl_display *display) { - struct wlr_backend *backend = wlr_wl_backend_create(display); + struct wlr_backend *backend = wlr_wl_backend_create(display, NULL); if (backend) { int outputs = 1; const char *_outputs = getenv("WLR_WL_OUTPUTS"); diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 36fbd8e0..32fdc2b6 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -158,7 +158,7 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { wlr_wl_backend_destroy(&backend->backend); } -struct wlr_backend *wlr_wl_backend_create(struct wl_display *display) { +struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, const char *remote) { wlr_log(L_INFO, "Creating wayland backend"); struct wlr_wl_backend *backend = calloc(1, sizeof(struct wlr_wl_backend)); @@ -173,7 +173,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display) { backend->local_display = display; - backend->remote_display = wl_display_connect(NULL); + backend->remote_display = wl_display_connect(remote); if (!backend->remote_display) { wlr_log_errno(L_ERROR, "Could not connect to remote display"); return false; diff --git a/include/wlr/backend/wayland.h b/include/wlr/backend/wayland.h index b10ffee3..02ee5b2d 100644 --- a/include/wlr/backend/wayland.h +++ b/include/wlr/backend/wayland.h @@ -12,7 +12,7 @@ * Creates a new wlr_wl_backend. This backend will be created with no outputs; * you must use wlr_wl_output_create to add them. */ -struct wlr_backend *wlr_wl_backend_create(struct wl_display *display); +struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, const char *remote); /** * Adds a new output to this backend. You may remove outputs by destroying them. From dfae5ff98f15ad65472cb2d39a8153ced14be1b8 Mon Sep 17 00:00:00 2001 From: Markus Ongyerth Date: Sat, 13 Jan 2018 21:41:04 +0100 Subject: [PATCH 14/21] Update comment for wlr_headless_backend_create --- include/wlr/backend/wayland.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/wlr/backend/wayland.h b/include/wlr/backend/wayland.h index 02ee5b2d..f89a6383 100644 --- a/include/wlr/backend/wayland.h +++ b/include/wlr/backend/wayland.h @@ -11,6 +11,10 @@ /** * Creates a new wlr_wl_backend. This backend will be created with no outputs; * you must use wlr_wl_output_create to add them. + * + * The `remote` argument is the name of the host compositor wayland socket. Set + * to NULL for the default behaviour (WAYLAND_DISPLAY env variable or wayland-0 + * default) */ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, const char *remote); From 66d4d2928f66bc33a8ac7c271e9ac4c992ccdd47 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 13 Jan 2018 20:29:54 -0500 Subject: [PATCH 15/21] Remove unnecessary wlr_backend_destroy --- rootston/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/rootston/main.c b/rootston/main.c index 46ec3671..a327576a 100644 --- a/rootston/main.c +++ b/rootston/main.c @@ -37,7 +37,6 @@ int main(int argc, char **argv) { if (server.backend == NULL) { wlr_log(L_ERROR, "could not start backend"); - wlr_backend_destroy(server.backend); return 1; } From 65b28b3823f42ba04629defbde136e04619c63a9 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 14 Jan 2018 18:19:37 +0100 Subject: [PATCH 16/21] xwayland: render children window in fullscreen --- include/wlr/xwayland.h | 5 ++++- rootston/output.c | 36 +++++++++++++++++++++++++++++------- xwayland/xwm.c | 10 ++++++++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index b6671de1..c0135943 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -98,9 +98,12 @@ struct wlr_xwayland_surface { char *title; char *class; char *instance; - struct wlr_xwayland_surface *parent; pid_t pid; + struct wl_list children; // wlr_xwayland_surface::parent_link + struct wlr_xwayland_surface *parent; + struct wl_list parent_link; // wlr_xwayland_surface::children + xcb_atom_t *window_type; size_t window_type_len; diff --git a/rootston/output.c b/rootston/output.c index 10450df3..9048766f 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -169,6 +169,19 @@ static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, } } +static void render_xwayland_children(struct wlr_xwayland_surface *surface, + struct roots_desktop *desktop, struct wlr_output *wlr_output, + struct timespec *when) { + struct wlr_xwayland_surface *child; + wl_list_for_each(child, &surface->children, parent_link) { + if (child->surface != NULL && child->added) { + render_surface(child->surface, desktop, wlr_output, when, + child->x, child->y, 0); + } + render_xwayland_children(child, desktop, wlr_output, when); + } +} + static void render_view(struct roots_view *view, struct roots_desktop *desktop, struct wlr_output *wlr_output, struct timespec *when) { switch (view->type) { @@ -200,7 +213,7 @@ static bool has_standalone_surface(struct roots_view *view) { case ROOTS_WL_SHELL_VIEW: return wl_list_empty(&view->wl_shell_surface->popups); case ROOTS_XWAYLAND_VIEW: - return true; + return wl_list_empty(&view->xwayland_surface->children); } return true; } @@ -218,27 +231,36 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { wlr_renderer_begin(server->renderer, wlr_output); if (output->fullscreen_view != NULL) { + struct roots_view *view = output->fullscreen_view; + // Make sure the view is centered on screen const struct wlr_box *output_box = wlr_output_layout_get_box(desktop->layout, wlr_output); struct wlr_box view_box; - view_get_box(output->fullscreen_view, &view_box); + view_get_box(view, &view_box); double view_x = (double)(output_box->width - view_box.width) / 2 + output_box->x; double view_y = (double)(output_box->height - view_box.height) / 2 + output_box->y; - view_move(output->fullscreen_view, view_x, view_y); + view_move(view, view_x, view_y); - if (has_standalone_surface(output->fullscreen_view)) { - wlr_output_set_fullscreen_surface(wlr_output, - output->fullscreen_view->wlr_surface); + if (has_standalone_surface(view)) { + wlr_output_set_fullscreen_surface(wlr_output, view->wlr_surface); } else { wlr_output_set_fullscreen_surface(wlr_output, NULL); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); - render_view(output->fullscreen_view, desktop, wlr_output, &now); + render_view(view, desktop, wlr_output, &now); + + // During normal rendering the xwayland window tree isn't traversed + // because all windows are rendered. Here we only want to render + // the fullscreen window's children so we have to traverse the tree. + if (view->type == ROOTS_XWAYLAND_VIEW) { + render_xwayland_children(view->xwayland_surface, desktop, + wlr_output, &now); + } } wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output); diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 53aac6a4..dc349ab2 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -96,6 +96,8 @@ static struct wlr_xwayland_surface *wlr_xwayland_surface_create( surface->height = height; surface->override_redirect = override_redirect; wl_list_insert(&xwm->surfaces, &surface->link); + wl_list_init(&surface->children); + wl_list_init(&surface->parent_link); wl_signal_init(&surface->events.destroy); wl_signal_init(&surface->events.request_configure); wl_signal_init(&surface->events.request_move); @@ -215,6 +217,7 @@ static void wlr_xwayland_surface_destroy( } wl_list_remove(&xsurface->link); + wl_list_remove(&xsurface->parent_link); if (xsurface->surface_id) { wl_list_remove(&xsurface->unpaired_link); @@ -305,6 +308,13 @@ static void read_surface_parent(struct wlr_xwm *xwm, xsurface->parent = NULL; } + wl_list_remove(&xsurface->parent_link); + if (xsurface->parent != NULL) { + wl_list_insert(&xsurface->parent->children, &xsurface->parent_link); + } else { + wl_list_init(&xsurface->parent_link); + } + wlr_log(L_DEBUG, "XCB_ATOM_WM_TRANSIENT_FOR: %p", xid); wl_signal_emit(&xsurface->events.set_parent, xsurface); } From 3101c300b1b60bf47e7dd8032aff4da88a7b9e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Mon, 15 Jan 2018 12:21:22 +0000 Subject: [PATCH 17/21] Don't crash if crtc->cursor is NULL Same as what atomic_crtc_set_cursor does Core was generated by `_build/rootston/rootston'. Program terminated with signal SIGSEGV, Segmentation fault. 0 0xb6f28a1c in atomic_crtc_move_cursor (drm=0x1ebc8e8, crtc=0x1ead498, x=0, y=0) at ../backend/drm/atomic.c:170 170 if (!crtc || !crtc->cursor) { (gdb) bt 0 0xb6f28a1c in atomic_crtc_move_cursor (drm=0x1ebc8e8, crtc=0x1ead498, x=0, y=0) at ../backend/drm/atomic.c:170 1 0xb6f2a856 in wlr_drm_connector_move_cursor (output=0x2242b28, x=0, y=0) at ../backend/drm/drm.c:634 2 0xb6f3cea0 in wlr_output_cursor_set_image (cursor=0x21a0338, pixels=0x22e1290 "", stride=24, width=24, height=24, hotspot_x=4, hotspot_y=4) at ../types/wlr_output.c:516 3 0xb6f39da2 in wlr_cursor_set_image (cur=0x22cfc90, pixels=0x22e1290 "", stride=24, width=24, height=24, hotspot_x=4, hotspot_y=4, scale=1) at ../types/wlr_cursor.c:310 4 0xb6f44d2a in wlr_xcursor_manager_set_cursor_image (manager=0x22cfd10, name=0x434420 "left_ptr", cursor=0x22cfc90) at ../types/wlr_xcursor_manager.c:80 5 0x00431c0a in roots_seat_configure_xcursor (seat=0x22cef08) at ../rootston/seat.c:515 6 0x0043137c in roots_seat_init_cursor (seat=0x22cef08) at ../rootston/seat.c:210 7 0x004315ec in roots_seat_create (input=0x218d220, name=0x434594 "seat0") at ../rootston/seat.c:289 8 0x0042ecba in input_get_seat (input=0x218d220, name=0x434594 "seat0") at ../rootston/input.c:39 9 0x0042ed04 in input_add_notify (listener=0x218d228, data=0x218d3b0) at ../rootston/input.c:54 10 0xb6f2f2e6 in wl_signal_emit (signal=0x1ea548c, data=0x218d3b0) at /usr/include/wayland-server-core.h:387 11 0xb6f2f572 in input_add_reemit (listener=0x1ea9990, data=0x218d3b0) at ../backend/multi/backend.c:101 12 0xb6f2db7e in wl_signal_emit (signal=0x1ea992c, data=0x218d3b0) at /usr/include/wayland-server-core.h:387 13 0xb6f2ddaa in handle_device_added (backend=0x1ea9920, libinput_dev=0x2292598) at ../backend/libinput/events.c:87 14 0xb6f2e164 in wlr_libinput_event (backend=0x1ea9920, event=0x2292b78) at ../backend/libinput/events.c:198 15 0xb6f2d678 in wlr_libinput_readable (fd=23, mask=1, _backend=0x1ea9920) at ../backend/libinput/backend.c:28 16 0xb6f2d7c0 in wlr_libinput_backend_start (_backend=0x1ea9920) at ../backend/libinput/backend.c:74 17 0xb6f27170 in wlr_backend_start (backend=0x1ea9920) at ../backend/backend.c:30 18 0xb6f2f320 in multi_backend_start (wlr_backend=0x1ea5480) at ../backend/multi/backend.c:22 19 0xb6f27170 in wlr_backend_start (backend=0x1ea5480) at ../backend/backend.c:30 20 0x0042fbc6 in main (argc=1, argv=0xbe89dd04) at ../rootston/main.c:60 --- backend/drm/atomic.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index e7374a00..64fae6e4 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -167,6 +167,10 @@ bool legacy_crtc_move_cursor(struct wlr_drm_backend *drm, static bool atomic_crtc_move_cursor(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, int x, int y) { + if (!crtc || !crtc->cursor) { + return true; + } + struct wlr_drm_plane *plane = crtc->cursor; // We can't use atomic operations on fake planes if (plane->id == 0) { From 0eebaf98d0550a9ea7adb743a5b85634f1d76b73 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 15 Jan 2018 21:49:37 +0100 Subject: [PATCH 18/21] drm: do not pageflip when enabling output --- backend/drm/atomic.c | 24 +++++++++++++----------- types/wlr_output.c | 4 ++++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 8d98bac2..3e8866ad 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -33,7 +33,6 @@ static bool atomic_end(int drm_fd, struct atomic *atom) { } uint32_t flags = DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_NONBLOCK; - if (drmModeAtomicCommit(drm_fd, atom->req, flags, NULL)) { wlr_log_errno(L_ERROR, "Atomic test failed"); drmModeAtomicSetCursor(atom->req, atom->cursor); @@ -44,13 +43,11 @@ static bool atomic_end(int drm_fd, struct atomic *atom) { } static bool atomic_commit(int drm_fd, struct atomic *atom, - struct wlr_drm_connector *conn, uint32_t flag, bool modeset) { + struct wlr_drm_connector *conn, uint32_t flags, bool modeset) { if (atom->failed) { return false; } - uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT | flag; - int ret = drmModeAtomicCommit(drm_fd, atom->req, flags, conn); if (ret) { wlr_log_errno(L_ERROR, "%s: Atomic commit failed (%s)", @@ -59,7 +56,8 @@ static bool atomic_commit(int drm_fd, struct atomic *atom, // Try to commit without new changes drmModeAtomicSetCursor(atom->req, atom->cursor); if (drmModeAtomicCommit(drm_fd, atom->req, flags, conn)) { - wlr_log_errno(L_ERROR, "%s: Atomic commit failed (%s)", + wlr_log_errno(L_ERROR, + "%s: Atomic commit without new changes failed (%s)", conn->output.name, modeset ? "modeset" : "pageflip"); } } @@ -100,8 +98,8 @@ static bool atomic_crtc_pageflip(struct wlr_drm_backend *drm, struct wlr_drm_connector *conn, struct wlr_drm_crtc *crtc, uint32_t fb_id, drmModeModeInfo *mode) { - if (mode) { - if (crtc->mode_id) { + if (mode != NULL) { + if (crtc->mode_id != 0) { drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id); } @@ -111,16 +109,20 @@ static bool atomic_crtc_pageflip(struct wlr_drm_backend *drm, } } - struct atomic atom; + uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT; + if (mode != NULL) { + flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; + } else { + flags |= DRM_MODE_ATOMIC_NONBLOCK; + } + struct atomic atom; atomic_begin(crtc, &atom); atomic_add(&atom, conn->id, conn->props.crtc_id, crtc->id); atomic_add(&atom, crtc->id, crtc->props.mode_id, crtc->mode_id); atomic_add(&atom, crtc->id, crtc->props.active, 1); set_plane_props(&atom, crtc->primary, crtc->id, fb_id, true); - return atomic_commit(drm->fd, &atom, conn, - mode ? DRM_MODE_ATOMIC_ALLOW_MODESET : DRM_MODE_ATOMIC_NONBLOCK, - mode); + return atomic_commit(drm->fd, &atom, conn, flags, mode); } static bool atomic_conn_enable(struct wlr_drm_backend *drm, diff --git a/types/wlr_output.c b/types/wlr_output.c index 8194c17e..b47fb3a0 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -156,6 +156,10 @@ static void wlr_output_update_matrix(struct wlr_output *output) { } void wlr_output_enable(struct wlr_output *output, bool enable) { + if (output->enabled == enable) { + return; + } + if (output->impl->enable) { output->impl->enable(output, enable); } From 264ef0c261db998ada651984136776fd336c4a72 Mon Sep 17 00:00:00 2001 From: Timidger Date: Mon, 15 Jan 2018 22:51:00 -0500 Subject: [PATCH 19/21] Fixed logging for examples --- examples/idle.c | 2 ++ examples/multi-pointer.c | 1 + examples/output-layout.c | 1 + examples/pointer.c | 1 + examples/rotation.c | 1 + examples/screenshot.c | 2 ++ examples/simple.c | 1 + examples/tablet.c | 1 + examples/touch.c | 1 + 9 files changed, 11 insertions(+) diff --git a/examples/idle.c b/examples/idle.c index e5e01f63..57c366d1 100644 --- a/examples/idle.c +++ b/examples/idle.c @@ -7,6 +7,7 @@ #include #include #include +#include static struct org_kde_kwin_idle *idle_manager = NULL; static struct wl_seat *seat = NULL; @@ -108,6 +109,7 @@ void *main_loop(void *data) { } int main(int argc, char *argv[]) { + wlr_log_init(L_DEBUG, NULL); if (parse_args(argc, argv) != 0) { return -1; diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 3f8b2415..62aa1bac 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -176,6 +176,7 @@ static void handle_input_remove(struct compositor_state *state, } int main(int argc, char *argv[]) { + wlr_log_init(L_DEBUG, NULL); struct sample_state state = { .default_color = { 0.25f, 0.25f, 0.25f, 1 }, .clear_color = { 0.25f, 0.25f, 0.25f, 1 }, diff --git a/examples/output-layout.c b/examples/output-layout.c index d9325838..35ed22a8 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -181,6 +181,7 @@ static void handle_keyboard_key(struct keyboard_state *kbstate, } int main(int argc, char *argv[]) { + wlr_log_init(L_DEBUG, NULL); struct sample_state state = {0}; state.x_vel = 500; diff --git a/examples/pointer.c b/examples/pointer.c index 280372e0..9894e311 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -257,6 +257,7 @@ static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { } int main(int argc, char *argv[]) { + wlr_log_init(L_DEBUG, NULL); struct sample_state state = { .default_color = { 0.25f, 0.25f, 0.25f, 1 }, .clear_color = { 0.25f, 0.25f, 0.25f, 1 }, diff --git a/examples/rotation.c b/examples/rotation.c index f9307ed3..1d974025 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -123,6 +123,7 @@ static void handle_keyboard_key(struct keyboard_state *kbstate, } int main(int argc, char *argv[]) { + wlr_log_init(L_DEBUG, NULL); struct sample_state state = {0}; state.config = parse_args(argc, argv); diff --git a/examples/screenshot.c b/examples/screenshot.c index 77652805..441d8684 100644 --- a/examples/screenshot.c +++ b/examples/screenshot.c @@ -36,6 +36,7 @@ #include #include #include "util/os-compatibility.h" +#include static struct wl_shm *shm = NULL; static struct orbital_screenshooter *screenshooter = NULL; @@ -242,6 +243,7 @@ static int set_buffer_size(int *width, int *height) { } int main(int argc, char *argv[]) { + wlr_log_init(L_DEBUG, NULL); struct wl_display * display = wl_display_connect(NULL); if (display == NULL) { fprintf(stderr, "failed to create display: %m\n"); diff --git a/examples/simple.c b/examples/simple.c index ad1b0792..95c056c8 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -44,6 +44,7 @@ void handle_output_frame(struct output_state *output, struct timespec *ts) { } int main() { + wlr_log_init(L_DEBUG, NULL); struct sample_state state = { .color = { 1.0, 0.0, 0.0 }, .dec = 0, diff --git a/examples/tablet.c b/examples/tablet.c index 4eaa204a..f3cd5339 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -139,6 +139,7 @@ static void handle_pad_button(struct tablet_pad_state *pstate, } int main(int argc, char *argv[]) { + wlr_log_init(L_DEBUG, NULL); struct sample_state state = { .tool_color = { 1, 1, 1, 1 }, .pad_color = { 0.75, 0.75, 0.75, 1.0 } diff --git a/examples/touch.c b/examples/touch.c index f18b5d26..4c1f97b6 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -94,6 +94,7 @@ static void handle_touch_motion(struct touch_state *tstate, int32_t touch_id, } int main(int argc, char *argv[]) { + wlr_log_init(L_DEBUG, NULL); struct sample_state state; wl_list_init(&state.touch_points); From 7f56ccd71395d2280ec463d8847b27d62c2855a6 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 16 Jan 2018 20:33:55 +0100 Subject: [PATCH 20/21] rootston: set real seat capabilities --- rootston/seat.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/rootston/seat.c b/rootston/seat.c index 130c7b27..c0cda3b0 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -293,11 +293,6 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { return NULL; } - wlr_seat_set_capabilities(seat->seat, - WL_SEAT_CAPABILITY_KEYBOARD | - WL_SEAT_CAPABILITY_POINTER | - WL_SEAT_CAPABILITY_TOUCH); - wl_list_insert(&input->seats, &seat->link); seat->seat_destroy.notify = roots_seat_handle_seat_destroy; @@ -306,6 +301,20 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { return seat; } +static void seat_update_capabilities(struct roots_seat *seat) { + uint32_t caps = 0; + if (!wl_list_empty(&seat->keyboards)) { + caps |= WL_SEAT_CAPABILITY_KEYBOARD; + } + if (!wl_list_empty(&seat->pointers) || !wl_list_empty(&seat->tablet_tools)) { + caps |= WL_SEAT_CAPABILITY_POINTER; + } + if (!wl_list_empty(&seat->touch)) { + caps |= WL_SEAT_CAPABILITY_TOUCH; + } + wlr_seat_set_capabilities(seat->seat, caps); +} + static void seat_add_keyboard(struct roots_seat *seat, struct wlr_input_device *device) { assert(device->type == WLR_INPUT_DEVICE_KEYBOARD); @@ -404,6 +413,8 @@ void roots_seat_add_device(struct roots_seat *seat, seat_add_tablet_tool(seat, device); break; } + + seat_update_capabilities(seat); } static void seat_remove_keyboard(struct roots_seat *seat, @@ -480,6 +491,8 @@ void roots_seat_remove_device(struct roots_seat *seat, seat_remove_tablet_tool(seat, device); break; } + + seat_update_capabilities(seat); } void roots_seat_configure_xcursor(struct roots_seat *seat) { From 6e9c652fc4c3dc65d313f4cb8823995a98d65964 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 16 Jan 2018 20:37:32 +0100 Subject: [PATCH 21/21] rootston: hide cursor if seat has no pointer --- rootston/seat.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rootston/seat.c b/rootston/seat.c index c0cda3b0..a61057bd 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -313,6 +313,14 @@ static void seat_update_capabilities(struct roots_seat *seat) { caps |= WL_SEAT_CAPABILITY_TOUCH; } wlr_seat_set_capabilities(seat->seat, caps); + + // Hide cursor if seat doesn't have pointer capability + if ((caps & WL_SEAT_CAPABILITY_POINTER) == 0) { + wlr_cursor_set_image(seat->cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); + } else { + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + seat->cursor->default_xcursor, seat->cursor->cursor); + } } static void seat_add_keyboard(struct roots_seat *seat,