diff --git a/compositor/main.c b/compositor/main.c index 12f5e76b..70079019 100644 --- a/compositor/main.c +++ b/compositor/main.c @@ -1282,14 +1282,47 @@ load_headless_backend(struct weston_compositor *c, return 0; } +static void +rdp_backend_output_configure(struct wl_listener *listener, void *data) +{ + struct weston_output *output = data; + struct wet_compositor *compositor = to_wet_compositor(output->compositor); + struct wet_output_config *parsed_options = compositor->parsed_options; + const struct weston_rdp_output_api *api = weston_rdp_output_get_api(output->compositor); + int width = 640; + int height = 480; + + assert(parsed_options); + + if (!api) { + weston_log("Cannot use weston_rdp_output_api.\n"); + return; + } + + if (parsed_options->width) + width = parsed_options->width; + + if (parsed_options->height) + height = parsed_options->height; + + weston_output_set_scale(output, 1); + weston_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); + + if (api->output_set_size(output, width, height) < 0) { + weston_log("Cannot configure output \"%s\" using weston_rdp_output_api.\n", + output->name); + return; + } + + weston_output_enable(output); +} + static void weston_rdp_backend_config_init(struct weston_rdp_backend_config *config) { config->base.struct_version = WESTON_RDP_BACKEND_CONFIG_VERSION; config->base.struct_size = sizeof(struct weston_rdp_backend_config); - config->width = 640; - config->height = 480; config->bind_address = NULL; config->port = 3389; config->rdp_key = NULL; @@ -1306,12 +1339,16 @@ load_rdp_backend(struct weston_compositor *c, struct weston_rdp_backend_config config = {{ 0, }}; int ret = 0; + struct wet_output_config *parsed_options = wet_init_parsed_options(c); + if (!parsed_options) + return -1; + weston_rdp_backend_config_init(&config); const struct weston_option rdp_options[] = { { WESTON_OPTION_BOOLEAN, "env-socket", 0, &config.env_socket }, - { WESTON_OPTION_INTEGER, "width", 0, &config.width }, - { WESTON_OPTION_INTEGER, "height", 0, &config.height }, + { WESTON_OPTION_INTEGER, "width", 0, &parsed_options->width }, + { WESTON_OPTION_INTEGER, "height", 0, &parsed_options->height }, { WESTON_OPTION_STRING, "address", 0, &config.bind_address }, { WESTON_OPTION_INTEGER, "port", 0, &config.port }, { WESTON_OPTION_BOOLEAN, "no-clients-resize", 0, &config.no_clients_resize }, @@ -1325,10 +1362,17 @@ load_rdp_backend(struct weston_compositor *c, ret = weston_compositor_load_backend(c, WESTON_BACKEND_RDP, &config.base); + if (ret < 0) + goto out; + + wet_set_pending_output_handler(c, rdp_backend_output_configure); + +out: free(config.bind_address); free(config.rdp_key); free(config.server_cert); free(config.server_key); + return ret; } diff --git a/libweston/compositor-rdp.c b/libweston/compositor-rdp.c index ee813009..b34024a7 100644 --- a/libweston/compositor-rdp.c +++ b/libweston/compositor-rdp.c @@ -25,6 +25,7 @@ #include "config.h" +#include #include #include #include @@ -371,15 +372,6 @@ rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) return 0; } -static void -rdp_output_destroy(struct weston_output *output_base) -{ - struct rdp_output *output = to_rdp_output(output_base); - - wl_event_source_remove(output->finish_frame_timer); - free(output); -} - static int finish_frame_handler(void *data) { @@ -471,16 +463,15 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) } static int -rdp_backend_create_output(struct rdp_backend *b, int width, int height) +rdp_output_set_size(struct weston_output *base, + int width, int height) { - struct rdp_output *output; - struct wl_event_loop *loop; + struct rdp_output *output = to_rdp_output(base); struct weston_mode *currentMode; struct weston_mode initMode; - output = zalloc(sizeof *output); - if (output == NULL) - return -1; + /* We can only be called once. */ + assert(!output->base.current_mode); wl_list_init(&output->peers); wl_list_init(&output->base.mode_list); @@ -492,48 +483,100 @@ rdp_backend_create_output(struct rdp_backend *b, int width, int height) currentMode = ensure_matching_mode(&output->base, &initMode); if (!currentMode) - goto out_free_output; + return -1; output->base.current_mode = output->base.native_mode = currentMode; - weston_output_init(&output->base, b->compositor, 0, 0, width, height, - WL_OUTPUT_TRANSFORM_NORMAL, 1); - output->base.make = "weston"; output->base.model = "rdp"; + + /* XXX: Calculate proper size. */ + output->base.mm_width = width; + output->base.mm_height = height; + + output->base.start_repaint_loop = rdp_output_start_repaint_loop; + output->base.repaint = rdp_output_repaint; + output->base.assign_planes = NULL; + output->base.set_backlight = NULL; + output->base.set_dpms = NULL; + output->base.switch_mode = rdp_switch_mode; + + return 0; +} + +static int +rdp_output_enable(struct weston_output *base) +{ + struct rdp_output *output = to_rdp_output(base); + struct rdp_backend *b = to_rdp_backend(base->compositor); + struct wl_event_loop *loop; + output->shadow_surface = pixman_image_create_bits(PIXMAN_x8r8g8b8, - width, height, - NULL, - width * 4); + output->base.current_mode->width, + output->base.current_mode->height, + NULL, + output->base.current_mode->width * 4); if (output->shadow_surface == NULL) { weston_log("Failed to create surface for frame buffer.\n"); - goto out_output; + return -1; } - if (pixman_renderer_output_create(&output->base) < 0) - goto out_shadow_surface; + if (pixman_renderer_output_create(&output->base) < 0) { + pixman_image_unref(output->shadow_surface); + return -1; + } loop = wl_display_get_event_loop(b->compositor->wl_display); output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output); - output->base.start_repaint_loop = rdp_output_start_repaint_loop; - output->base.repaint = rdp_output_repaint; - output->base.destroy = rdp_output_destroy; - output->base.assign_planes = NULL; - output->base.set_backlight = NULL; - output->base.set_dpms = NULL; - output->base.switch_mode = rdp_switch_mode; b->output = output; - weston_compositor_add_output(b->compositor, &output->base); return 0; +} + +static int +rdp_output_disable(struct weston_output *base) +{ + struct rdp_output *output = to_rdp_output(base); + struct rdp_backend *b = to_rdp_backend(base->compositor); + + if (!output->base.enabled) + return 0; + + wl_event_source_remove(output->finish_frame_timer); + b->output = NULL; -out_shadow_surface: - pixman_image_unref(output->shadow_surface); -out_output: + return 0; +} + +static void +rdp_output_destroy(struct weston_output *base) +{ + struct rdp_output *output = to_rdp_output(base); + + rdp_output_disable(&output->base); weston_output_destroy(&output->base); -out_free_output: + free(output); - return -1; +} + +static int +rdp_backend_create_output(struct weston_compositor *compositor) +{ + struct rdp_output *output; + + output = zalloc(sizeof *output); + if (output == NULL) + return -1; + + output->base.name = strdup("rdp"); + output->base.destroy = rdp_output_destroy; + output->base.disable = rdp_output_disable; + output->base.enable = rdp_output_enable; + + weston_output_init_pending(&output->base, compositor); + weston_compositor_add_pending_output(&output->base, compositor); + + return 0; } static void @@ -1216,6 +1259,10 @@ rdp_incoming_peer(freerdp_listener *instance, freerdp_peer *client) FREERDP_CB_RETURN(TRUE); } +static const struct weston_rdp_output_api api = { + rdp_output_set_size, +}; + static struct rdp_backend * rdp_backend_create(struct weston_compositor *compositor, struct weston_rdp_backend_config *config) @@ -1223,7 +1270,7 @@ rdp_backend_create(struct weston_compositor *compositor, struct rdp_backend *b; char *fd_str; char *fd_tail; - int fd; + int fd, ret; b = zalloc(sizeof *b); if (b == NULL) @@ -1251,7 +1298,7 @@ rdp_backend_create(struct weston_compositor *compositor, if (pixman_renderer_init(compositor) < 0) goto err_compositor; - if (rdp_backend_create_output(b, config->width, config->height) < 0) + if (rdp_backend_create_output(compositor) < 0) goto err_compositor; compositor->capabilities |= WESTON_CAP_ARBITRARY_MODES; @@ -1282,6 +1329,15 @@ rdp_backend_create(struct weston_compositor *compositor, } compositor->backend = &b->base; + + ret = weston_plugin_api_register(compositor, WESTON_RDP_OUTPUT_API_NAME, + &api, sizeof(api)); + + if (ret < 0) { + weston_log("Failed to register output API.\n"); + goto err_output; + } + return b; err_listener: @@ -1301,8 +1357,6 @@ err_free_strings: static void config_init_to_defaults(struct weston_rdp_backend_config *config) { - config->width = 640; - config->height = 480; config->bind_address = NULL; config->port = 3389; config->rdp_key = NULL; diff --git a/libweston/compositor-rdp.h b/libweston/compositor-rdp.h index dfa1759a..bd0a6a90 100644 --- a/libweston/compositor-rdp.h +++ b/libweston/compositor-rdp.h @@ -31,13 +31,33 @@ extern "C" { #endif #include "compositor.h" +#include "plugin-registry.h" -#define WESTON_RDP_BACKEND_CONFIG_VERSION 1 +#define WESTON_RDP_OUTPUT_API_NAME "weston_rdp_output_api_v1" + +struct weston_rdp_output_api { + /** Initialize a RDP output with specified width and height. + * + * Returns 0 on success, -1 on failure. + */ + int (*output_set_size)(struct weston_output *output, + int width, int height); +}; + +static inline const struct weston_rdp_output_api * +weston_rdp_output_get_api(struct weston_compositor *compositor) +{ + const void *api; + api = weston_plugin_api_get(compositor, WESTON_RDP_OUTPUT_API_NAME, + sizeof(struct weston_rdp_output_api)); + + return (const struct weston_rdp_output_api *)api; +} + +#define WESTON_RDP_BACKEND_CONFIG_VERSION 2 struct weston_rdp_backend_config { struct weston_backend_config base; - int width; - int height; char *bind_address; int port; char *rdp_key;