From c3d2f960d23e06d5081894fd49db2ccf9663b4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armin=20Krezovi=C4=87?= Date: Fri, 30 Sep 2016 14:11:10 +0200 Subject: [PATCH] weston: Port X11 backend to new output handling API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a complete port of the X11 backend that uses recently added output handling API for output configuration. - Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually, obtained from the configuration file or obtained from the command line using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. - Output can be created at runtime using the output API. The output creation only creates a pending output, which needs to be configured the same way as mentioned above. Same as before, a single output is created at runtime using the default configuration or a configuration parsed from the command line. The output-count functionality is also preserved, which means more than one output can be created initially, and more outputs can be added at runtime using the output API. v2: - Fix wet_configure_windowed_output_from_config() usage. - Call x11_output_disable() explicitly from x11_output_destroy(). v3: - Remove unneeded free(). - Disallow calling x11_output_configure more than once. - Remove unneeded checks for output->name == NULL as that has been disallowed. - Use weston_compositor_add_pending_output(). - Bump weston_x11_backend_config version to 2. Reviewed-by: Pekka Paalanen Signed-off-by: Armin Krezović --- compositor/main.c | 151 +++++++----------- libweston/compositor-x11.c | 312 +++++++++++++++++++++---------------- libweston/compositor-x11.h | 13 +- 3 files changed, 235 insertions(+), 241 deletions(-) diff --git a/compositor/main.c b/compositor/main.c index d19b3f0b..fca97784 100644 --- a/compositor/main.c +++ b/compositor/main.c @@ -1426,48 +1426,43 @@ out: return ret; } -static int -weston_x11_backend_config_append_output_config(struct weston_x11_backend_config *config, - struct weston_x11_backend_output_config *output_config) { - struct weston_x11_backend_output_config *new_outputs; - - new_outputs = realloc(config->outputs, (config->num_outputs+1) * - sizeof(struct weston_x11_backend_output_config)); - if (new_outputs == NULL) - return -1; - - config->outputs = new_outputs; - config->outputs[config->num_outputs].width = output_config->width; - config->outputs[config->num_outputs].height = output_config->height; - config->outputs[config->num_outputs].transform = output_config->transform; - config->outputs[config->num_outputs].scale = output_config->scale; - config->outputs[config->num_outputs].name = strdup(output_config->name); - config->num_outputs++; +static void +x11_backend_output_configure(struct wl_listener *listener, void *data) +{ + struct weston_output *output = data; + struct wet_output_config defaults = { + .width = 1024, + .height = 600, + .scale = 1, + .transform = WL_OUTPUT_TRANSFORM_NORMAL + }; - return 0; + if (wet_configure_windowed_output_from_config(output, &defaults) < 0) + weston_log("Cannot configure output \"%s\".\n", output->name); } static int load_x11_backend(struct weston_compositor *c, int *argc, char **argv, struct weston_config *wc) { - struct weston_x11_backend_output_config default_output; + char *default_output; + const struct weston_windowed_output_api *api; struct weston_x11_backend_config config = {{ 0, }}; struct weston_config_section *section; int ret = 0; - int option_width = 0; - int option_height = 0; - int option_scale = 0; int option_count = 1; int output_count = 0; char const *section_name; int i; - uint32_t j; + + struct wet_output_config *parsed_options = wet_init_parsed_options(c); + if (!parsed_options) + return -1; const struct weston_option options[] = { - { WESTON_OPTION_INTEGER, "width", 0, &option_width }, - { WESTON_OPTION_INTEGER, "height", 0, &option_height }, - { WESTON_OPTION_INTEGER, "scale", 0, &option_scale }, + { WESTON_OPTION_INTEGER, "width", 0, &parsed_options->width }, + { WESTON_OPTION_INTEGER, "height", 0, &parsed_options->height }, + { WESTON_OPTION_INTEGER, "scale", 0, &parsed_options->scale }, { WESTON_OPTION_BOOLEAN, "fullscreen", 'f', &config.fullscreen }, { WESTON_OPTION_INTEGER, "output-count", 0, &option_count }, { WESTON_OPTION_BOOLEAN, "no-input", 0, &config.no_input }, @@ -1476,94 +1471,66 @@ load_x11_backend(struct weston_compositor *c, parse_options(options, ARRAY_LENGTH(options), argc, argv); + config.base.struct_version = WESTON_X11_BACKEND_CONFIG_VERSION; + config.base.struct_size = sizeof(struct weston_x11_backend_config); + + /* load the actual backend and configure it */ + ret = weston_compositor_load_backend(c, WESTON_BACKEND_X11, + &config.base); + + if (ret < 0) + return ret; + + wet_set_pending_output_handler(c, x11_backend_output_configure); + + api = weston_windowed_output_get_api(c); + + if (!api) { + weston_log("Cannot use weston_windowed_output_api.\n"); + return -1; + } + section = NULL; while (weston_config_next_section(wc, §ion, §ion_name)) { - struct weston_x11_backend_output_config current_output = { 0, }; - char *t; - char *mode; + char *output_name; + + if (output_count >= option_count) + break; if (strcmp(section_name, "output") != 0) { continue; } - weston_config_section_get_string(section, "name", ¤t_output.name, NULL); - if (current_output.name == NULL || current_output.name[0] != 'X') { - free(current_output.name); + weston_config_section_get_string(section, "name", &output_name, NULL); + if (output_name == NULL || output_name[0] != 'X') { + free(output_name); continue; } - weston_config_section_get_string(section, "mode", &mode, "1024x600"); - if (sscanf(mode, "%dx%d", ¤t_output.width, - ¤t_output.height) != 2) { - weston_log("Invalid mode \"%s\" for output %s\n", - mode, current_output.name); - current_output.width = 1024; - current_output.height = 600; - } - free(mode); - if (current_output.width < 1) - current_output.width = 1024; - if (current_output.height < 1) - current_output.height = 600; - if (option_width) - current_output.width = option_width; - if (option_height) - current_output.height = option_height; - - weston_config_section_get_int(section, "scale", ¤t_output.scale, 1); - if (option_scale) - current_output.scale = option_scale; - - weston_config_section_get_string(section, - "transform", &t, "normal"); - if (weston_parse_transform(t, ¤t_output.transform) < 0) - weston_log("Invalid transform \"%s\" for output %s\n", - t, current_output.name); - free(t); - - if (weston_x11_backend_config_append_output_config(&config, ¤t_output) < 0) { - ret = -1; - goto out; + if (api->output_create(c, output_name) < 0) { + free(output_name); + return -1; } + free(output_name); output_count++; - if (output_count >= option_count) - break; } - default_output.name = NULL; - default_output.width = option_width ? option_width : 1024; - default_output.height = option_height ? option_height : 600; - default_output.scale = option_scale ? option_scale : 1; - default_output.transform = WL_OUTPUT_TRANSFORM_NORMAL; + default_output = NULL; for (i = output_count; i < option_count; i++) { - if (asprintf(&default_output.name, "screen%d", i) < 0) { - ret = -1; - goto out; + if (asprintf(&default_output, "screen%d", i) < 0) { + return -1; } - if (weston_x11_backend_config_append_output_config(&config, &default_output) < 0) { - ret = -1; - free(default_output.name); - goto out; + if (api->output_create(c, default_output) < 0) { + free(default_output); + return -1; } - free(default_output.name); + free(default_output); } - config.base.struct_version = WESTON_X11_BACKEND_CONFIG_VERSION; - config.base.struct_size = sizeof(struct weston_x11_backend_config); - - /* load the actual backend and configure it */ - ret = weston_compositor_load_backend(c, WESTON_BACKEND_X11, - &config.base); - -out: - for (j = 0; j < config.num_outputs; ++j) - free(config.outputs[j].name); - free(config.outputs); - - return ret; + return 0; } static void diff --git a/libweston/compositor-x11.c b/libweston/compositor-x11.c index 3e0d20fb..86241c67 100644 --- a/libweston/compositor-x11.c +++ b/libweston/compositor-x11.c @@ -59,6 +59,7 @@ #include "pixman-renderer.h" #include "presentation-time-server-protocol.h" #include "linux-dmabuf.h" +#include "windowed-output-api.h" #define DEFAULT_AXIS_STEP_DISTANCE 10 @@ -75,6 +76,8 @@ struct x11_backend { struct xkb_keymap *xkb_keymap; unsigned int has_xkb; uint8_t xkb_event_base; + int fullscreen; + int no_input; int use_pixman; int has_net_wm_state_fullscreen; @@ -515,30 +518,6 @@ x11_output_deinit_shm(struct x11_backend *b, struct x11_output *output) shmdt(output->buf); } -static void -x11_output_destroy(struct weston_output *output_base) -{ - struct x11_output *output = to_x11_output(output_base); - struct x11_backend *backend = - to_x11_backend(output->base.compositor); - - wl_event_source_remove(output->finish_frame_timer); - - if (backend->use_pixman) { - pixman_renderer_output_destroy(output_base); - x11_output_deinit_shm(backend, output); - } else - gl_renderer->output_destroy(output_base); - - xcb_destroy_window(backend->conn, output->window); - - xcb_flush(backend->conn); - - weston_output_destroy(&output->base); - - free(output); -} - static void x11_output_set_wm_protocols(struct x11_backend *b, struct x11_output *output) @@ -789,20 +768,54 @@ x11_output_init_shm(struct x11_backend *b, struct x11_output *output, return 0; } -static struct x11_output * -x11_backend_create_output(struct x11_backend *b, int x, int y, - int width, int height, int fullscreen, - int no_input, char *configured_name, - uint32_t transform, int32_t scale) +static int +x11_output_disable(struct weston_output *base) +{ + struct x11_output *output = to_x11_output(base); + struct x11_backend *backend = to_x11_backend(base->compositor); + + if (!output->base.enabled) + return 0; + + wl_event_source_remove(output->finish_frame_timer); + + if (backend->use_pixman) { + pixman_renderer_output_destroy(&output->base); + x11_output_deinit_shm(backend, output); + } else { + gl_renderer->output_destroy(&output->base); + } + + xcb_destroy_window(backend->conn, output->window); + xcb_flush(backend->conn); + + return 0; +} + +static void +x11_output_destroy(struct weston_output *base) +{ + struct x11_output *output = to_x11_output(base); + + x11_output_disable(&output->base); + weston_output_destroy(&output->base); + + free(output); +} + +static int +x11_output_enable(struct weston_output *base) { + struct x11_output *output = to_x11_output(base); + struct x11_backend *b = to_x11_backend(base->compositor); + static const char name[] = "Weston Compositor"; static const char class[] = "weston-1\0Weston Compositor"; char *title = NULL; - struct x11_output *output; xcb_screen_t *screen; struct wm_normal_hints normal_hints; struct wl_event_loop *loop; - int output_width, output_height, width_mm, height_mm; + int ret; uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR; xcb_atom_t atom_list[1]; @@ -812,10 +825,7 @@ x11_backend_create_output(struct x11_backend *b, int x, int y, 0 }; - output_width = width * scale; - output_height = height * scale; - - if (!no_input) + if (!b->no_input) values[0] |= XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | @@ -827,22 +837,6 @@ x11_backend_create_output(struct x11_backend *b, int x, int y, XCB_EVENT_MASK_KEYMAP_STATE | XCB_EVENT_MASK_FOCUS_CHANGE; - output = zalloc(sizeof *output); - if (output == NULL) { - perror("zalloc"); - return NULL; - } - - output->mode.flags = - WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED; - - output->mode.width = output_width; - output->mode.height = output_height; - output->mode.refresh = 60000; - output->scale = scale; - wl_list_init(&output->base.mode_list); - wl_list_insert(&output->base.mode_list, &output->mode.link); - values[1] = b->null_cursor; output->window = xcb_generate_id(b->conn); screen = x11_compositor_get_default_screen(b); @@ -851,13 +845,14 @@ x11_backend_create_output(struct x11_backend *b, int x, int y, output->window, screen->root, 0, 0, - output_width, output_height, + output->base.current_mode->width, + output->base.current_mode->height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values); - if (fullscreen) { + if (b->fullscreen) { atom_list[0] = b->atom.net_wm_state_fullscreen; xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window, @@ -869,10 +864,10 @@ x11_backend_create_output(struct x11_backend *b, int x, int y, memset(&normal_hints, 0, sizeof normal_hints); normal_hints.flags = WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE; - normal_hints.min_width = output_width; - normal_hints.min_height = output_height; - normal_hints.max_width = output_width; - normal_hints.max_height = output_height; + normal_hints.min_width = output->base.current_mode->width; + normal_hints.min_height = output->base.current_mode->height; + normal_hints.max_width = output->base.current_mode->width; + normal_hints.max_height = output->base.current_mode->height; xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window, b->atom.wm_normal_hints, b->atom.wm_size_hints, 32, @@ -881,8 +876,8 @@ x11_backend_create_output(struct x11_backend *b, int x, int y, } /* Set window name. Don't bother with non-EWMH WMs. */ - if (configured_name) { - if (asprintf(&title, "%s - %s", name, configured_name) < 0) + if (output->base.name) { + if (asprintf(&title, "%s - %s", name, output->base.name) < 0) title = NULL; } else { title = strdup(name); @@ -894,9 +889,7 @@ x11_backend_create_output(struct x11_backend *b, int x, int y, strlen(title), title); free(title); } else { - xcb_destroy_window(b->conn, output->window); - free(output); - return NULL; + goto err; } xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window, @@ -909,44 +902,20 @@ x11_backend_create_output(struct x11_backend *b, int x, int y, xcb_map_window(b->conn, output->window); - if (fullscreen) + if (b->fullscreen) x11_output_wait_for_map(b, output); - output->base.start_repaint_loop = x11_output_start_repaint_loop; - if (b->use_pixman) - output->base.repaint = x11_output_repaint_shm; - else - output->base.repaint = x11_output_repaint_gl; - output->base.destroy = x11_output_destroy; - output->base.assign_planes = NULL; - output->base.set_backlight = NULL; - output->base.set_dpms = NULL; - output->base.switch_mode = NULL; - output->base.current_mode = &output->mode; - output->base.make = "weston-X11"; - output->base.model = "none"; - - if (configured_name) - output->base.name = strdup(configured_name); - - width_mm = width * b->screen->width_in_millimeters / - b->screen->width_in_pixels; - height_mm = height * b->screen->height_in_millimeters / - b->screen->height_in_pixels; - weston_output_init(&output->base, b->compositor, - x, y, width_mm, height_mm, transform, scale); - if (b->use_pixman) { if (x11_output_init_shm(b, output, - output->mode.width, - output->mode.height) < 0) { + output->base.current_mode->width, + output->base.current_mode->height) < 0) { weston_log("Failed to initialize SHM for the X11 output\n"); - return NULL; + goto err; } if (pixman_renderer_output_create(&output->base) < 0) { weston_log("Failed to create pixman renderer for output\n"); x11_output_deinit_shm(b, output); - return NULL; + goto err; } } else { /* eglCreatePlatformWindowSurfaceEXT takes a Window* @@ -960,19 +929,112 @@ x11_backend_create_output(struct x11_backend *b, int x, int y, NULL, 0); if (ret < 0) - return NULL; + goto err; } loop = wl_display_get_event_loop(b->compositor->wl_display); output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output); - weston_compositor_add_output(b->compositor, &output->base); - weston_log("x11 output %dx%d, window id %d\n", - width, height, output->window); + output->base.current_mode->width, + output->base.current_mode->height, + output->window); + + return 0; - return output; +err: + xcb_destroy_window(b->conn, output->window); + xcb_flush(b->conn); + + return -1; +} + +static int +x11_output_set_size(struct weston_output *base, int width, int height) +{ + struct x11_output *output = to_x11_output(base); + struct x11_backend *b = to_x11_backend(base->compositor); + int output_width, output_height; + + /* We can only be called once. */ + assert(!output->base.current_mode); + + /* Make sure we have scale set. */ + assert(output->base.scale); + + if (width < 1) { + weston_log("Invalid width \"%d\" for output %s\n", + width, output->base.name); + return -1; + } + + if (height < 1) { + weston_log("Invalid height \"%d\" for output %s\n", + height, output->base.name); + return -1; + } + + output_width = width * output->base.scale; + output_height = height * output->base.scale; + + output->mode.flags = + WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED; + + output->mode.width = output_width; + output->mode.height = output_height; + output->mode.refresh = 60000; + output->scale = output->base.scale; + wl_list_init(&output->base.mode_list); + wl_list_insert(&output->base.mode_list, &output->mode.link); + + output->base.current_mode = &output->mode; + output->base.make = "weston-X11"; + output->base.model = "none"; + + output->base.mm_width = width * b->screen->width_in_millimeters / + b->screen->width_in_pixels; + output->base.mm_height = height * b->screen->height_in_millimeters / + b->screen->height_in_pixels; + + if (b->use_pixman) + output->base.repaint = x11_output_repaint_shm; + else + output->base.repaint = x11_output_repaint_gl; + + output->base.start_repaint_loop = x11_output_start_repaint_loop; + output->base.assign_planes = NULL; + output->base.set_backlight = NULL; + output->base.set_dpms = NULL; + output->base.switch_mode = NULL; + + return 0; +} + +static int +x11_output_create(struct weston_compositor *compositor, + const char *name) +{ + struct x11_output *output; + + /* name can't be NULL. */ + assert(name); + + output = zalloc(sizeof *output); + if (output == NULL) { + perror("zalloc"); + return -1; + } + + output->base.name = strdup(name); + output->base.destroy = x11_output_destroy; + output->base.disable = x11_output_disable; + output->base.enable = x11_output_enable; + + weston_output_init_pending(&output->base, compositor); + weston_compositor_add_pending_output(&output->base, compositor); + + return 0; } static struct x11_output * @@ -1588,21 +1650,27 @@ init_gl_renderer(struct x11_backend *b) return ret; } +static const struct weston_windowed_output_api api = { + x11_output_set_size, + x11_output_create, +}; + static struct x11_backend * x11_backend_create(struct weston_compositor *compositor, struct weston_x11_backend_config *config) { struct x11_backend *b; - struct x11_output *output; struct wl_event_loop *loop; - int x = 0; - unsigned i; + int ret; b = zalloc(sizeof *b); if (b == NULL) return NULL; b->compositor = compositor; + b->fullscreen = config->fullscreen; + b->no_input = config->no_input; + if (weston_compositor_set_presentation_clock_software(compositor) < 0) goto err_free; @@ -1648,44 +1716,6 @@ x11_backend_create(struct weston_compositor *compositor, goto err_renderer; } - for (i = 0; i < config->num_outputs; ++i) { - struct weston_x11_backend_output_config *output_iterator = - &config->outputs[i]; - - if (output_iterator->name == NULL) { - continue; - } - - if (output_iterator->width < 1) { - weston_log("Invalid width \"%d\" for output %s\n", - output_iterator->width, output_iterator->name); - goto err_x11_input; - } - - if (output_iterator->height < 1) { - weston_log("Invalid height \"%d\" for output %s\n", - output_iterator->height, output_iterator->name); - goto err_x11_input; - } - - output = x11_backend_create_output(b, - x, - 0, - output_iterator->width, - output_iterator->height, - config->fullscreen, - config->no_input, - output_iterator->name, - output_iterator->transform, - output_iterator->scale); - if (output == NULL) { - weston_log("Failed to create configured x11 output\n"); - goto err_x11_input; - } - - x = pixman_region32_extents(&output->base.region)->x2; - } - loop = wl_display_get_event_loop(compositor->wl_display); b->xcb_source = wl_event_loop_add_fd(loop, @@ -1702,6 +1732,14 @@ x11_backend_create(struct weston_compositor *compositor, compositor->backend = &b->base; + ret = weston_plugin_api_register(compositor, WESTON_WINDOWED_OUTPUT_API_NAME, + &api, sizeof(api)); + + if (ret < 0) { + weston_log("Failed to register output API.\n"); + goto err_x11_input; + } + return b; err_x11_input: diff --git a/libweston/compositor-x11.h b/libweston/compositor-x11.h index 6a17f96e..8989fc26 100644 --- a/libweston/compositor-x11.h +++ b/libweston/compositor-x11.h @@ -34,15 +34,7 @@ extern "C" { #include "compositor.h" -#define WESTON_X11_BACKEND_CONFIG_VERSION 1 - -struct weston_x11_backend_output_config { - int width; - int height; - char *name; - uint32_t transform; - int32_t scale; -}; +#define WESTON_X11_BACKEND_CONFIG_VERSION 2 struct weston_x11_backend_config { struct weston_backend_config base; @@ -52,9 +44,6 @@ struct weston_x11_backend_config { /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */ bool use_pixman; - - uint32_t num_outputs; - struct weston_x11_backend_output_config *outputs; }; #ifdef __cplusplus