From 7d216da6668ce78ab02bdf586126562e3be691e5 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Fri, 3 Jul 2020 12:37:37 +0800 Subject: [PATCH 19/95] backend-drm: Support controlling output dynamically Use config file to set output's rotate/down-scale/size/pos/mode/off/ freeze/input/display-rectangle and prefer/primary output. Default config file is "/tmp/.weston_drm.conf", can override with "WESTON_DRM_CONFIG" environment. Supported configs format is "output::", for example: echo "output:DSI-1:off" >> /tmp/.weston_drm.conf echo "output:eDP-1:freeze" >> /tmp/.weston_drm.conf echo "output:all:rotate90" >> /tmp/.weston_drm.conf echo "output:all:rect=<100,20,1636,2068>" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:mode=800x600" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:pos=100,200" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:size=1920x1080" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:prefer" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:primary" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:down-scale=0.5" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:input=*" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:input=" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:input=event6" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:input=goodix*" >> /tmp/.weston_drm.conf echo "output:HDMI-A-1:input=goodix-ts" >> /tmp/.weston_drm.conf Signed-off-by: Jeffy Chen --- compositor/main.c | 14 ++ desktop-shell/shell.c | 58 +++++- include/libweston/libweston.h | 7 + libweston/backend-drm/drm-internal.h | 16 ++ libweston/backend-drm/drm.c | 266 ++++++++++++++++++++++++++- libweston/backend-drm/modes.c | 20 +- libweston/compositor.c | 30 ++- libweston/libinput-seat.c | 43 +++++ libweston/libweston-internal.h | 3 + libweston/renderer-gl/gl-renderer.c | 4 + 10 files changed, 435 insertions(+), 26 deletions(-) diff --git a/compositor/main.c b/compositor/main.c index dcfe85b..d65f8aa 100644 --- a/compositor/main.c +++ b/compositor/main.c @@ -2080,6 +2080,20 @@ drm_backend_output_configure(struct weston_output *output, } free(s); + weston_config_section_get_string(section, "pos", &s, NULL); + if (s) { + if (sscanf(s, "%d,%d", &output->x, &output->y) == 2) + output->fixed_position = true; + free(s); + } + + weston_config_section_get_string(section, "size", &s, NULL); + if (s) { + if (sscanf(s, "%dx%d", &output->width, &output->height) == 2) + output->fixed_size = true; + free(s); + } + if (api->set_mode(output, mode, modeline) < 0) { weston_log("Cannot configure an output using weston_drm_output_api.\n"); free(modeline); diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 7aa787c..be36b70 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -3831,7 +3831,7 @@ weston_view_set_initial_position(struct weston_view *view, int ix = 0, iy = 0; int32_t range_x, range_y; int32_t x, y; - struct weston_output *output, *target_output = NULL; + struct weston_output *output, *target_output = NULL, *prefer_output = NULL; struct weston_seat *seat; pixman_rectangle32_t area; @@ -3856,16 +3856,20 @@ weston_view_set_initial_position(struct weston_view *view, } } - wl_list_for_each(output, &compositor->output_list, link) { + wl_list_for_each_reverse(output, &compositor->output_list, link) { if (output->unavailable) continue; - if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) { + if (output == compositor->prefer_output) + prefer_output = output; + + if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) target_output = output; - break; - } } + if (prefer_output) + target_output = prefer_output; + if (!target_output) { weston_view_set_position(view, 10 + random() % 400, 10 + random() % 400); @@ -4382,6 +4386,41 @@ shell_resize_surface_to_output(struct desktop_shell *shell, output->height); } +static void +handle_output_resize_layer(struct desktop_shell *shell, + struct weston_layer *layer, void *data) +{ + struct weston_output *output = data; + struct weston_view *view; + + wl_list_for_each(view, &layer->view_list.link, layer_link.link) { + struct weston_desktop_surface *desktop_surface; + struct shell_surface *shsurf; + bool dirty = false; + + if (view->output != output) + continue; + + shsurf = get_shell_surface(view->surface); + if (!shsurf) + continue; + + desktop_surface = shsurf->desktop_surface; + if (weston_desktop_surface_get_fullscreen(desktop_surface)) { + set_fullscreen(shsurf, true, output); + dirty = true; + } + if (weston_desktop_surface_get_maximized(desktop_surface)) { + set_maximized(shsurf, true); + dirty = true; + } + + if (dirty) { + weston_view_geometry_dirty(view); + weston_surface_damage(view->surface); + } + } +} static void handle_output_resized(struct wl_listener *listener, void *data) @@ -4391,8 +4430,13 @@ handle_output_resized(struct wl_listener *listener, void *data) struct weston_output *output = (struct weston_output *)data; struct shell_output *sh_output = find_shell_output_from_weston_output(shell, output); + if (shell->lock_surface) + shell->lock_surface->committed(shell->lock_surface, 0, 0); + shell_resize_surface_to_output(shell, sh_output->background_surface, output); shell_resize_surface_to_output(shell, sh_output->panel_surface, output); + + shell_for_each_layer(shell, handle_output_resize_layer, data); } static void @@ -4441,7 +4485,9 @@ handle_output_move_layer(struct desktop_shell *shell, x = view->geometry.x + output->move_x; y = view->geometry.y + output->move_y; - weston_view_set_position(view, x, y); + + if (pixman_region32_contains_point(&output->region, x, y, NULL)) + weston_view_set_position(view, x, y); } } diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h index a8ec105..84b16fe 100644 --- a/include/libweston/libweston.h +++ b/include/libweston/libweston.h @@ -575,6 +575,12 @@ struct weston_output { struct weston_head *head); bool unavailable; + bool freezing; + + bool fixed_position; + bool fixed_size; + + double down_scale; }; #define weston_output_valid(o) \ ((o) && !(o)->destroying && !(o)->unavailable) @@ -1333,6 +1339,7 @@ struct weston_compositor { bool warned_about_unmapped_surface_or_view; enum weston_output_flow output_flow; + struct weston_output *prefer_output; }; struct weston_solid_buffer_values { diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 037c937..532593e 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -115,6 +115,9 @@ #define DRM_RESIZE_FREEZE_MS 600 +#define WESTON_DRM_CONFIG_FILE "/tmp/.weston_drm.conf" +#define DRM_CONFIG_UPDATE_MS 100 + /** * Represents the values of an enum-type KMS property */ @@ -364,6 +367,9 @@ struct drm_backend { int virtual_height; bool mirror_mode; + + struct wl_event_source *config_timer; + struct stat config_stat; }; struct drm_mode { @@ -641,6 +647,9 @@ struct drm_output { bool is_mirror; pixman_box32_t plane_bounds; + + uint32_t original_transform; + int64_t last_resize_ms; }; void @@ -739,6 +748,13 @@ drm_mode_list_destroy(struct drm_device *device, struct wl_list *mode_list); void drm_output_print_modes(struct drm_output *output); +struct drm_mode * +drm_output_choose_initial_mode(struct drm_device *device, + struct drm_output *output, + enum weston_drm_backend_output_mode mode, + const char *modeline, + const drmModeModeInfo *current_mode); + int drm_output_set_mode(struct weston_output *base, enum weston_drm_backend_output_mode mode, diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index fc035b9..6c7a567 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,8 @@ static const char default_seat[] = "seat0"; +static int config_timer_handler(void *data); + static inline bool drm_head_is_external(struct drm_head *head) { @@ -510,6 +513,12 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags, return; } + if (!sec && !usec) { + weston_output_finish_frame(&output->base, NULL, + WP_PRESENTATION_FEEDBACK_INVALID); + return; + } + ts.tv_sec = sec; ts.tv_nsec = usec * 1000; @@ -689,8 +698,13 @@ out: return; } - sw = fb->width; - sh = fb->height; + if (output->base.down_scale != 1.0f && b->use_pixman) { + weston_log("pixman renderer could not support down-scale\n"); + output->base.down_scale = 1.0f; + } + + sw = fb->width * output->base.down_scale; + sh = fb->height * output->base.down_scale; dx = output->plane_bounds.x1; dy = output->plane_bounds.y1; @@ -832,7 +846,8 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) weston_compositor_read_presentation_clock(b->compositor, &now); now_ms = timespec_to_msec(&now); - if (now_ms < b->last_resize_ms + b->resize_freeze_ms) { + if (now_ms < b->last_resize_ms + b->resize_freeze_ms || + now_ms < output->last_resize_ms + b->resize_freeze_ms) { /* Resize fullscreen/maxmium views(not always success) */ if (now_ms < b->last_resize_ms + DRM_RESIZE_FREEZE_MS) wl_signal_emit(&b->compositor->output_resized_signal, @@ -841,7 +856,7 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) weston_output_damage(output_base); weston_output_finish_frame(output_base, NULL, WP_PRESENTATION_FEEDBACK_INVALID); - return 0; + goto not_repainted; } /* If planes have been disabled in the core, we might not have @@ -872,7 +887,8 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) err: drm_output_state_free(state); - return 0; +not_repainted: + return 1; } /* Determine the type of vblank synchronization to use for the output. @@ -2296,6 +2312,8 @@ drm_output_enable(struct weston_output *base) output->base.switch_mode = drm_output_switch_mode; output->base.set_gamma = drm_output_set_gamma; + output->original_transform = output->base.transform; + output->state_invalid = true; weston_log("Output %s (crtc %d) video modes:\n", @@ -3188,6 +3206,7 @@ drm_destroy(struct weston_compositor *ec) udev_input_destroy(&b->input); + wl_event_source_remove(b->config_timer); wl_event_source_remove(b->hotplug_timer); wl_event_source_remove(b->udev_drm_source); wl_event_source_remove(b->drm_source); @@ -3608,6 +3627,10 @@ output_create_notify(struct wl_listener *listener, void *data) output_create_listener); drm_backend_update_outputs(b); + + /* Force reload config */ + memset(&b->config_stat, 0, sizeof(b->config_stat)); + config_timer_handler(b); } static const struct weston_drm_output_api api = { @@ -3617,6 +3640,235 @@ static const struct weston_drm_output_api api = { drm_output_set_max_bpc, }; +static void +drm_output_rotate(struct drm_output *output, int rotate) +{ + struct drm_backend *b = to_drm_backend(output->base.compositor); + uint32_t transform = output->original_transform; + struct timespec now; + + /* Hacky way to rotate transform */ + transform = (transform / 4) * 4 + (transform + rotate) % 4; + + if (output->base.transform == transform) + return; + + /* Freeze output when rotating */ + weston_compositor_read_presentation_clock(b->compositor, &now); + output->last_resize_ms = timespec_to_msec(&now); + + weston_output_set_transform(&output->base, transform); +} + +static void +drm_output_modeset(struct drm_output *output, const char *modeline) +{ + struct drm_backend *b = to_drm_backend(output->base.compositor); + struct drm_head *head = + to_drm_head(weston_output_get_first_head(&output->base)); + struct drm_mode *mode; + struct timespec now; + + /* Unable to switch mode, let's retry later */ + if (output->page_flip_pending || output->atomic_complete_pending) { + memset(&b->config_stat, 0, sizeof(b->config_stat)); + return; + } + + mode = drm_output_choose_initial_mode(b->drm, output, + WESTON_DRM_BACKEND_OUTPUT_PREFERRED, + modeline, + &head->inherited_mode); + + weston_output_mode_set_native(&output->base, &mode->base, + output->base.current_scale); + weston_output_damage(&output->base); + + mode = to_drm_mode(output->base.current_mode); + + weston_log("Output %s changed to %dx%d@%d for mode(%s)\n", + output->base.name, + mode->mode_info.hdisplay, mode->mode_info.vdisplay, + mode->mode_info.vrefresh, + modeline); + + weston_compositor_read_presentation_clock(b->compositor, &now); + b->last_update_ms = timespec_to_msec(&now); +} + +static void +drm_output_set_size(struct drm_output *output, const int w, const int h) +{ + struct drm_backend *b = to_drm_backend(output->base.compositor); + struct weston_mode *mode; + struct timespec now; + + if (output->base.fixed_size && + output->base.current_mode->width == w && + output->base.current_mode->height == h) + return; + + wl_list_for_each(mode, &output->base.mode_list, link) { + mode->width = w; + mode->height = h; + } + + output->base.fixed_size = true; + + /* Freeze output when resizing */ + weston_compositor_read_presentation_clock(b->compositor, &now); + output->last_resize_ms = timespec_to_msec(&now); + + weston_output_set_transform(&output->base, output->base.transform); + + if (b->use_pixman) { + drm_output_fini_pixman(output); + if (drm_output_init_pixman(output, b) < 0) + weston_log("failed to init output pixman state with " + "new mode\n"); + } else { + drm_output_fini_egl(output); + if (drm_output_init_egl(output, b) < 0) + weston_log("failed to init output egl state with " + "new mode"); + } + + drm_output_print_modes(output); +} + +static void +config_handle_output(struct drm_backend *b, const char *name, + const char *config) +{ + struct drm_output *output; + bool is_all = !strcmp(name, "all"); + + wl_list_for_each(output, &b->compositor->output_list, base.link) { + if (!is_all && strcmp(name, output->base.name)) + continue; + + if (!strcmp(config, "primary")) { + setenv("WESTON_DRM_PRIMARY", name, 1); + hotplug_timer_handler(b->drm); + } else if (!strcmp(config, "prefer")) { + b->compositor->prefer_output = &output->base; + } else if (!strncmp(config, "rotate", strlen("rotate"))) { + int rotate = atoi(config + strlen("rotate")) / 90; + drm_output_rotate(output, rotate); + } else if (!strncmp(config, "mode=", strlen("mode="))) { + drm_output_modeset(output, config + strlen("mode=")); + } else if (!strcmp(config, "freeze")) { + output->base.freezing = true; + } else if (!strcmp(config, "off")) { + output->base.freezing = true; + if (!output->virtual) + drm_set_dpms(&output->base, WESTON_DPMS_OFF); + } else if (!strcmp(config, "unfreeze") || + !strcmp(config, "on")) { + if (!output->base.freezing) + continue; + + output->base.freezing = false; + + if (!output->virtual) + drm_set_dpms(&output->base, WESTON_DPMS_ON); + + weston_output_damage(&output->base); + } else if (!strncmp(config, "down-scale=", + strlen("down-scale="))) { + double down_scale = + atof(config + strlen("down-scale=")); + if (down_scale == output->base.down_scale || + down_scale < 0.125 || down_scale > 1) + continue; + + output->base.down_scale = down_scale; + weston_output_damage(&output->base); + } else if (!strncmp(config, "size=", strlen("size="))) { + int w, h; + + if (sscanf(config, "size=%dx%d", &w, &h) != 2) + continue; + + drm_output_set_size(output, w, h); + } else if (!strncmp(config, "pos=", strlen("pos="))) { + int x, y; + + if (sscanf(config, "pos=%d,%d", &x, &y) != 2) + continue; + + weston_output_move(&output->base, x, y); + output->base.fixed_position = true; + + weston_compositor_reflow_outputs(b->compositor); + } else if (!strncmp(config, "rect=", strlen("rect="))) { + int x1, y1, x2, y2, ret; + + ret = sscanf(config, "rect=<%d,%d,%d,%d>", + &x1, &y1, &x2, &y2); + if (ret != 4) + continue; + + output->plane_bounds.x1 = x1; + output->plane_bounds.y1 = y1; + output->plane_bounds.x2 = x2; + output->plane_bounds.y2 = y2; + weston_output_schedule_repaint(&output->base); + } else if (!strncmp(config, "input=", strlen("input="))) { + weston_output_bind_input(&output->base, + config + strlen("input=")); + } + } +} + +static int +config_timer_handler(void *data) +{ +#define MAX_CONF_LEN 512 +#define _STR(x) #x +#define STR(x) _STR(x) + + struct drm_backend *b = data; + struct stat st; + char type[MAX_CONF_LEN], key[MAX_CONF_LEN], value[MAX_CONF_LEN]; + const char *config_file; + FILE *conf_fp; + + wl_event_source_timer_update(b->config_timer, DRM_CONFIG_UPDATE_MS); + + config_file = getenv("WESTON_DRM_CONFIG"); + if (!config_file) + config_file = WESTON_DRM_CONFIG_FILE; + + if (stat(config_file, &st) < 0) + return 0; + + if (st.st_mtime && !memcmp(&st, &b->config_stat, sizeof(st))) + return 0; + + conf_fp = fopen(config_file, "r"); + if (!conf_fp) + return 0; + + /** + * Parse configs, formated with :: + * For example: "output:all:rotate90" + */ + while (3 == fscanf(conf_fp, + "%" STR(MAX_CONF_LEN) "[^:]:" + "%" STR(MAX_CONF_LEN) "[^:]:" + "%" STR(MAX_CONF_LEN) "[^\n]%*c", type, key, value)) { + if (!strcmp(type, "output")) + config_handle_output(b, key, value); + } + + fclose(conf_fp); + + stat(config_file, &st); + b->config_stat = st; + return 0; +} + enum drm_head_mode { DRM_HEAD_MODE_DEFAULT, DRM_HEAD_MODE_PRIMARY, @@ -3960,6 +4212,10 @@ drm_backend_create(struct weston_compositor *compositor, b->hotplug_timer = wl_event_loop_add_timer(loop, hotplug_timer_handler, b->drm); + b->config_timer = + wl_event_loop_add_timer(loop, config_timer_handler, b); + config_timer_handler(b); + return b; err_udev_monitor: diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c index 7e7865b..f3d2c00 100644 --- a/libweston/backend-drm/modes.c +++ b/libweston/backend-drm/modes.c @@ -405,15 +405,19 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info) if (mode == NULL) return NULL; - mode->base.flags = 0; - mode->base.width = info->hdisplay; - mode->base.height = info->vdisplay; - - if (b->virtual_width && b->virtual_height) { + if (output->base.fixed_size) { + mode->base.width = output->base.width; + mode->base.height = output->base.height; + } else if (b->virtual_width && b->virtual_height) { mode->base.width = b->virtual_width; mode->base.height = b->virtual_height; + } else { + mode->base.width = info->hdisplay; + mode->base.height = info->vdisplay; } + mode->base.flags = 0; + mode->base.refresh = drm_refresh_rate_mHz(info); mode->mode_info = *info; mode->blob_id = 0; @@ -589,7 +593,7 @@ update_head_from_connector(struct drm_head *head) * @param current_mode Mode currently being displayed on this output * @returns A mode from the output's mode list, or NULL if none available */ -static struct drm_mode * +struct drm_mode * drm_output_choose_initial_mode(struct drm_device *device, struct drm_output *output, enum weston_drm_backend_output_mode mode, @@ -642,8 +646,8 @@ drm_output_choose_initial_mode(struct drm_device *device, } wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) { - if (width == drm_mode->base.width && - height == drm_mode->base.height && + if (width == drm_mode->mode_info.hdisplay && + height == drm_mode->mode_info.vdisplay && (refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) { if (!device->aspect_ratio_supported || aspect_ratio == drm_mode->base.aspect_ratio) diff --git a/libweston/compositor.c b/libweston/compositor.c index eea8da2..d9f6682 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -3372,6 +3372,11 @@ weston_output_repaint(struct weston_output *output) static void weston_output_schedule_repaint_reset(struct weston_output *output) { + if (output->idle_repaint_source) { + wl_event_source_remove(output->idle_repaint_source); + output->idle_repaint_source = NULL; + } + output->repaint_status = REPAINT_NOT_SCHEDULED; TL_POINT(output->compositor, "core_repaint_exit_loop", TLP_OUTPUT(output), TLP_END); @@ -3384,6 +3389,11 @@ weston_output_maybe_repaint(struct weston_output *output, struct timespec *now) int ret = 0; int64_t msec_to_repaint; + /* If we're sleeping, drop the repaint machinery entirely; we will + * explicitly repaint it when we come back. */ + if (output->freezing) + goto err; + /* We're not ready yet; come back to make a decision later. */ if (output->repaint_status != REPAINT_SCHEDULED) return ret; @@ -3410,11 +3420,11 @@ weston_output_maybe_repaint(struct weston_output *output, struct timespec *now) * output. */ ret = weston_output_repaint(output); weston_compositor_read_presentation_clock(compositor, now); - if (ret != 0) + if (ret < 0) goto err; - output->repainted = true; - return ret; + output->repainted = !ret; + return 0; err: weston_output_schedule_repaint_reset(output); @@ -3480,7 +3490,7 @@ output_repaint_timer_handler(void *data) struct weston_compositor *compositor = data; struct weston_output *output; struct timespec now; - int ret = 0; + int ret = 0, repainted = 0; if (!access(getenv("WESTON_FREEZE_DISPLAY") ? : "", F_OK)) { usleep(DEFAULT_REPAINT_WINDOW * 1000); @@ -3497,9 +3507,11 @@ output_repaint_timer_handler(void *data) ret = weston_output_maybe_repaint(output, &now); if (ret) break; + + repainted |= output->repainted; } - if (ret == 0) { + if (ret == 0 && repainted) { if (compositor->backend->repaint_flush) ret = compositor->backend->repaint_flush(compositor); } else { @@ -6544,7 +6556,7 @@ weston_compositor_reflow_outputs(struct weston_compositor *compositor) wl_list_for_each(head, &output->head_list, output_link) weston_head_update_global(head); - if (!weston_output_valid(output)) + if (!weston_output_valid(output) || output->fixed_position) continue; x = next_x; @@ -7050,6 +7062,9 @@ weston_output_set_transform(struct weston_output *output, weston_compositor_reflow_outputs(output->compositor); + wl_signal_emit(&output->compositor->output_resized_signal, + output); + /* Notify clients of the change for output transform. */ wl_list_for_each(head, &output->head_list, output_link) { wl_resource_for_each(resource, &head->resource_list) { @@ -7288,6 +7303,8 @@ weston_output_init(struct weston_output *output, /* Can't use -1 on uint32_t and 0 is valid enum value */ output->transform = UINT32_MAX; + output->down_scale = 1.0f; + pixman_region32_init(&output->damage); pixman_region32_init(&output->region); wl_list_init(&output->mode_list); @@ -7420,7 +7437,6 @@ weston_output_enable(struct weston_output *output) weston_output_transform_scale_init(output, output->transform, output->scale); weston_output_init_geometry(output, output->x, output->y); - weston_output_damage(output); wl_list_init(&output->animation_list); wl_list_init(&output->feedback_list); diff --git a/libweston/libinput-seat.c b/libweston/libinput-seat.c index 57ff181..100b47d 100644 --- a/libweston/libinput-seat.c +++ b/libweston/libinput-seat.c @@ -534,3 +534,46 @@ udev_seat_get_named(struct udev_input *input, const char *seat_name) return udev_seat_create(input, seat_name); } + +void +weston_output_bind_input(struct weston_output *output, const char *match) +{ + struct weston_compositor *compositor = output->compositor; + struct evdev_device *device; + struct udev_seat *seat; + const char *sysname, *name; + int len = strlen(match); + int clear = !len; + + /* Handle pattern match */ + if (len && match[len - 1] == '*') + len--; + + wl_list_for_each(seat, &compositor->seat_list, base.link) { + wl_list_for_each(device, &seat->devices_list, link) { + if (clear) { + /* Clear all bounded inputs */ + if (!device->output_name || + strcmp(device->output_name, output->name)) + continue; + + free(device->output_name); + device->output_name = NULL; + continue; + } + + sysname = libinput_device_get_sysname(device->device); + name = libinput_device_get_name(device->device); + + if (!len || !strncmp(name, match, len) || + !strncmp(sysname, match, len)) { + if (device->output_name) + free(device->output_name); + + device->output_name = strdup(output->name); + } + } + + udev_seat_update_output(seat); + } +} diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h index 8bdac33..39d9e85 100644 --- a/libweston/libweston-internal.h +++ b/libweston/libweston-internal.h @@ -193,6 +193,9 @@ weston_output_disable_planes_incr(struct weston_output *output); void weston_output_disable_planes_decr(struct weston_output *output); +void +weston_output_bind_input(struct weston_output *output, const char *name); + /* weston_plane */ void diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index db4c7b1..3437bf2 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -1685,6 +1685,10 @@ gl_renderer_repaint_output(struct weston_output *output, /* Calculate the global GL matrix */ go->output_matrix = output->matrix; + + weston_matrix_scale(&go->output_matrix, + output->down_scale, output->down_scale, 1); + weston_matrix_translate(&go->output_matrix, -(output->current_mode->width / 2.0), -(output->current_mode->height / 2.0), 0); -- 2.20.1