From 44181b57aceb2a49846d15e9cea11a704cba9786 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 16 Aug 2017 11:51:22 -0400 Subject: [PATCH 01/11] Add wlr_output_layout implementation An output layout consists of a mapping of outputs to their position in a global coordinate system that usually cooresponds to the output position in physical space in front of the user. Add an example that allows configuration of an output layout and demonstrates its boundaries with a bouncing image. --- examples/meson.build | 1 + examples/output-layout.c | 276 ++++++++++++++++++++++++++ include/wlr/types/wlr_output_layout.h | 40 ++++ types/meson.build | 1 + types/wlr_output_layout.c | 104 ++++++++++ 5 files changed, 422 insertions(+) create mode 100644 examples/output-layout.c create mode 100644 include/wlr/types/wlr_output_layout.h create mode 100644 types/wlr_output_layout.c diff --git a/examples/meson.build b/examples/meson.build index 1ce9c342..e2c0189c 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -7,6 +7,7 @@ executable('rotation', 'rotation.c', dependencies: wlroots, link_with: lib_share executable('pointer', 'pointer.c', dependencies: wlroots, link_with: lib_shared) executable('touch', 'touch.c', dependencies: wlroots, link_with: lib_shared) executable('tablet', 'tablet.c', dependencies: wlroots, link_with: lib_shared) +executable('output-layout', 'output-layout.c', dependencies: wlroots, link_with: lib_shared) compositor_src = [ 'compositor/main.c', diff --git a/examples/output-layout.c b/examples/output-layout.c new file mode 100644 index 00000000..f0e2d2d4 --- /dev/null +++ b/examples/output-layout.c @@ -0,0 +1,276 @@ +#define _POSIX_C_SOURCE 199309L +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "shared.h" +#include "cat.h" + +struct sample_state { + struct wl_list config; + struct wlr_renderer *renderer; + struct wlr_texture *cat_texture; + struct wlr_output_layout *layout; + float x_offs, y_offs; + float x_vel, y_vel; + struct wlr_output *main_output; +}; + +struct output_config { + char *name; + enum wl_output_transform transform; + int x, y; + struct wl_list link; +}; + +static void handle_output_frame(struct output_state *output, struct timespec *ts) { + struct compositor_state *state = output->compositor; + struct sample_state *sample = state->data; + struct wlr_output *wlr_output = output->output; + + int32_t width, height; + wlr_output_effective_resolution(wlr_output, &width, &height); + + wlr_output_make_current(wlr_output); + wlr_renderer_begin(sample->renderer, wlr_output); + + float matrix[16]; + + // transform global coordinates to local coordinates + int local_x = sample->x_offs; + int local_y = sample->y_offs; + + wlr_output_layout_output_coords(sample->layout, output->output, &local_x, + &local_y); + + wlr_texture_get_matrix(sample->cat_texture, &matrix, + &wlr_output->transform_matrix, local_x, local_y); + wlr_render_with_matrix(sample->renderer, + sample->cat_texture, &matrix); + + wlr_renderer_end(sample->renderer); + wlr_output_swap_buffers(wlr_output); + + if (output->output == sample->main_output) { + long ms = (ts->tv_sec - output->last_frame.tv_sec) * 1000 + + (ts->tv_nsec - output->last_frame.tv_nsec) / 1000000; + // how many seconds have passed since the last frame + float seconds = ms / 1000.0f; + + // check for collisions and bounce + bool ur_collision = !wlr_output_layout_output_at(sample->layout, + sample->x_offs + 128, sample->y_offs); + bool ul_collision = !wlr_output_layout_output_at(sample->layout, + sample->x_offs, sample->y_offs); + bool ll_collision = !wlr_output_layout_output_at(sample->layout, + sample->x_offs, sample->y_offs + 128); + bool lr_collision = !wlr_output_layout_output_at(sample->layout, + sample->x_offs + 128, sample->y_offs + 128); + bool has_double_collision = false; + + if ((ur_collision && ul_collision) || (lr_collision && ll_collision)) { + sample->y_vel *= -1; + has_double_collision = true; + } + + if ((ll_collision && ul_collision) || (ur_collision && lr_collision)) { + sample->x_vel *= -1; + has_double_collision = true; + } + + if (!has_double_collision && + (ur_collision || ul_collision || lr_collision || ll_collision)) { + sample->x_vel *= -1; + sample->y_vel *= -1; + } + + sample->x_offs += sample->x_vel * seconds; + sample->y_offs += sample->y_vel * seconds; + } +} + +static void handle_output_add(struct output_state *output) { + struct sample_state *sample = output->compositor->data; + + struct output_config *conf; + wl_list_for_each(conf, &sample->config, link) { + if (strcmp(conf->name, output->output->name) == 0) { + wlr_output_layout_add(sample->layout, output->output, + conf->x, conf->y); + wlr_output_transform(output->output, conf->transform); + + if (!sample->main_output) { + sample->main_output = output->output; + sample->x_offs = conf->x + 20; + sample->y_offs = conf->y + 20; + sample->x_vel = 500; + sample->y_vel = 500; + } + wlr_log(L_DEBUG, "Adding output to layout: %s", output->output->name); + } + + } +} + +static void update_velocities(struct compositor_state *state, + float x_diff, float y_diff) { + struct sample_state *sample = state->data; + sample->x_vel += x_diff; + sample->y_vel += y_diff; +} + +static void handle_keyboard_key(struct keyboard_state *kbstate, + xkb_keysym_t sym, enum wlr_key_state key_state) { + // NOTE: It may be better to simply refer to our key state during each frame + // and make this change in pixels/sec^2 + // Also, key repeat + int delta = 75; + if (key_state == WLR_KEY_PRESSED) { + switch (sym) { + case XKB_KEY_Left: + update_velocities(kbstate->compositor, -delta, 0); + break; + case XKB_KEY_Right: + update_velocities(kbstate->compositor, delta, 0); + break; + case XKB_KEY_Up: + update_velocities(kbstate->compositor, 0, -delta); + break; + case XKB_KEY_Down: + update_velocities(kbstate->compositor, 0, delta); + break; + } + } +} + +static void usage(const char *name, int ret) { + fprintf(stderr, + "usage: %s [-d [-r | -f]]*\n" + "\n" + " -o The name of the DRM display. e.g. DVI-I-1.\n" + " -r The rotation counter clockwise. Valid values are 90, 180, 270.\n" + " -x The X-axis coordinate position of this output in the layout.\n" + " -y The Y-axis coordinate position of this output in the layout.\n" + " -f Flip the output along the vertical axis.\n", name); + + exit(ret); +} + +static void parse_args(int argc, char *argv[], struct wl_list *config) { + struct output_config *oc = NULL; + + int c; + while ((c = getopt(argc, argv, "o:r:x:y:fh")) != -1) { + switch (c) { + case 'o': + oc = calloc(1, sizeof(*oc)); + oc->name = optarg; + oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; + wl_list_insert(config, &oc->link); + break; + case 'r': + if (!oc) { + fprintf(stderr, "You must specify an output first\n"); + usage(argv[0], 1); + } + + if (oc->transform != WL_OUTPUT_TRANSFORM_NORMAL + && oc->transform != WL_OUTPUT_TRANSFORM_FLIPPED) { + fprintf(stderr, "Rotation for %s already specified\n", oc->name); + usage(argv[0], 1); + } + + if (strcmp(optarg, "90") == 0) { + oc->transform += WL_OUTPUT_TRANSFORM_90; + } else if (strcmp(optarg, "180") == 0) { + oc->transform += WL_OUTPUT_TRANSFORM_180; + } else if (strcmp(optarg, "270") == 0) { + oc->transform += WL_OUTPUT_TRANSFORM_270; + } else { + fprintf(stderr, "Invalid rotation '%s'\n", optarg); + usage(argv[0], 1); + } + break; + case 'x': + if (!oc) { + fprintf(stderr, "You must specify an output first\n"); + usage(argv[0], 1); + } + oc->x = strtol(optarg, NULL, 0); + break; + case 'y': + if (!oc) { + fprintf(stderr, "You must specify an output first\n"); + usage(argv[0], 1); + } + oc->y = strtol(optarg, NULL, 0); + break; + case 'f': + if (!oc) { + fprintf(stderr, "You must specify an output first\n"); + usage(argv[0], 1); + } + + if (oc->transform >= WL_OUTPUT_TRANSFORM_FLIPPED) { + fprintf(stderr, "Flip for %s already specified\n", oc->name); + usage(argv[0], 1); + } + + oc->transform += WL_OUTPUT_TRANSFORM_FLIPPED; + break; + case 'h': + case '?': + usage(argv[0], c != 'h'); + } + } +} + +int main(int argc, char *argv[]) { + struct sample_state state = {0}; + + state.layout = wlr_output_layout_init(); + + wl_list_init(&state.config); + parse_args(argc, argv, &state.config); + + struct compositor_state compositor = { 0 }; + compositor.data = &state; + compositor.output_add_cb = handle_output_add; + compositor.output_frame_cb = handle_output_frame; + compositor.keyboard_key_cb = handle_keyboard_key; + compositor_init(&compositor); + + state.renderer = wlr_gles2_renderer_init(compositor.backend); + state.cat_texture = wlr_render_texture_init(state.renderer); + wlr_texture_upload_pixels(state.cat_texture, WL_SHM_FORMAT_ABGR8888, + cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data); + + compositor_run(&compositor); + + wlr_texture_destroy(state.cat_texture); + wlr_renderer_destroy(state.renderer); + + wlr_output_layout_destroy(state.layout); + + struct output_config *ptr, *tmp; + wl_list_for_each_safe(ptr, tmp, &state.config, link) { + free(ptr); + } +} diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h new file mode 100644 index 00000000..cd36482a --- /dev/null +++ b/include/wlr/types/wlr_output_layout.h @@ -0,0 +1,40 @@ +#ifndef _WLR_TYPES_OUTPUT_LAYOUT_H +#define _WLR_TYPES_OUTPUT_LAYOUT_H +#include +#include +#include + +struct wlr_output_layout { + struct wl_list outputs; +}; + +struct wlr_output_layout_output { + struct wlr_output *output; + int x, y; + struct wl_list link; +}; + +struct wlr_output_layout *wlr_output_layout_init(); + +void wlr_output_layout_destroy(struct wlr_output_layout *layout); + +struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, + double x, double y); + +void wlr_output_layout_add(struct wlr_output_layout *layout, + struct wlr_output *output, int x, int y); + +void wlr_output_layout_move(struct wlr_output_layout *layout, + struct wlr_output *output, int x, int y); + +void wlr_output_layout_remove(struct wlr_output_layout *layout, + struct wlr_output *output); + +/** + * Given x and y as pointers to global coordinates, adjusts them to local output + * coordinates relative to the given reference output. + */ +void wlr_output_layout_output_coords(struct wlr_output_layout *layout, + struct wlr_output *reference, int *x, int *y); + +#endif diff --git a/types/meson.build b/types/meson.build index 61dd913c..bb313565 100644 --- a/types/meson.build +++ b/types/meson.build @@ -2,6 +2,7 @@ lib_wlr_types = static_library('wlr_types', files( 'wlr_input_device.c', 'wlr_keyboard.c', 'wlr_output.c', + 'wlr_output_layout.c', 'wlr_pointer.c', 'wlr_region.c', 'wlr_seat.c', diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c new file mode 100644 index 00000000..8b4256f9 --- /dev/null +++ b/types/wlr_output_layout.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include + +struct wlr_output_layout *wlr_output_layout_init() { + struct wlr_output_layout *layout = calloc(1, sizeof(struct wlr_output_layout)); + wl_list_init(&layout->outputs); + return layout; +} + +void wlr_output_layout_destroy(struct wlr_output_layout *layout) { + if (!layout) { + return; + } + + struct wlr_output_layout_output *_output, *temp = NULL; + wl_list_for_each_safe(_output, temp, &layout->outputs, link) { + wl_list_remove(&_output->link); + free(_output); + } + + free(layout); +} + +void wlr_output_layout_add(struct wlr_output_layout *layout, + struct wlr_output *output, int x, int y) { + struct wlr_output_layout_output *layout_output = calloc(1, sizeof(struct wlr_output_layout_output)); + layout_output->output = output; + layout_output->x = x; + layout_output->y = y; + wl_list_insert(&layout->outputs, &layout_output->link); +} + +static struct wlr_output_layout_output *wlr_output_layout_get( + struct wlr_output_layout *layout, struct wlr_output *reference) { + struct wlr_output_layout_output *ret = NULL; + struct wlr_output_layout_output *_output; + wl_list_for_each(_output, &layout->outputs, link) { + if (_output->output) { + ret = _output; + } + } + + return ret; + +} + +struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, + double x, double y) { + struct wlr_output *ret = NULL; + struct wlr_output_layout_output *_output; + wl_list_for_each(_output, &layout->outputs, link) { + if (_output->output) { + int width, height; + wlr_output_effective_resolution(_output->output, &width, &height); + bool has_x = x >= _output->x && x <= _output->x + width; + bool has_y = y >= _output->y && y <= _output->y + height; + if (has_x && has_y) { + ret = _output->output; + break; + } + } + } + + return ret; +} + +void wlr_output_layout_move(struct wlr_output_layout *layout, + struct wlr_output *output, int x, int y) { + struct wlr_output_layout_output *layout_output = + wlr_output_layout_get(layout, output); + if (layout_output) { + layout_output->x = x; + layout_output->y = y; + } +} + +void wlr_output_layout_remove(struct wlr_output_layout *layout, + struct wlr_output *output) { + struct wlr_output_layout_output *layout_output = + wlr_output_layout_get(layout, output); + if (layout_output) { + wl_list_remove(&layout_output->link); + free(layout_output); + } +} + +void wlr_output_layout_output_coords(struct wlr_output_layout *layout, + struct wlr_output *reference, int *x, int *y) { + assert(layout && reference); + int src_x = *x; + int src_y = *y; + + struct wlr_output_layout_output *_output; + wl_list_for_each(_output, &layout->outputs, link) { + if (_output->output == reference) { + *x = src_x - _output->x; + *y = src_y - _output->y; + return; + } + } +} From 2e9e237f9d5485f65afbf3d8b49c740ed0653e5b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 16 Aug 2017 15:00:15 -0400 Subject: [PATCH 02/11] layout-output example: handle empty config --- examples/output-layout.c | 31 +++++++++++++++++++++++++-- include/wlr/types/wlr_output_layout.h | 3 +++ types/wlr_output_layout.c | 2 +- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/examples/output-layout.c b/examples/output-layout.c index f0e2d2d4..81a7251b 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -31,6 +31,7 @@ struct sample_state { float x_offs, y_offs; float x_vel, y_vel; struct wlr_output *main_output; + struct wl_list outputs; }; struct output_config { @@ -109,6 +110,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts static void handle_output_add(struct output_state *output) { struct sample_state *sample = output->compositor->data; + bool found = false; struct output_config *conf; wl_list_for_each(conf, &sample->config, link) { if (strcmp(conf->name, output->output->name) == 0) { @@ -120,13 +122,35 @@ static void handle_output_add(struct output_state *output) { sample->main_output = output->output; sample->x_offs = conf->x + 20; sample->y_offs = conf->y + 20; - sample->x_vel = 500; - sample->y_vel = 500; } wlr_log(L_DEBUG, "Adding output to layout: %s", output->output->name); + found = true; + break; + } + } + + // if it's not in the config, just place it next to the rightmost output + if (!found) { + int x = 0; + struct output_state *_output; + wl_list_for_each(_output, &sample->outputs, link) { + struct wlr_output_layout_output *layout_output = + wlr_output_layout_get(sample->layout, _output->output); + if (layout_output && layout_output->output) { + x += layout_output->x + _output->output->width; + } } + wlr_output_layout_add(sample->layout, output->output, x, 0); + + if (wl_list_empty(&sample->config) && !sample->main_output) { + sample->main_output = output->output; + sample->x_offs = x + 20; + sample->y_offs = 20; + } } + + wl_list_insert(&sample->outputs, &output->link); } static void update_velocities(struct compositor_state *state, @@ -245,9 +269,12 @@ static void parse_args(int argc, char *argv[], struct wl_list *config) { int main(int argc, char *argv[]) { struct sample_state state = {0}; + state.x_vel = 500; + state.y_vel = 500; state.layout = wlr_output_layout_init(); wl_list_init(&state.config); + wl_list_init(&state.outputs); parse_args(argc, argv, &state.config); struct compositor_state compositor = { 0 }; diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index cd36482a..7c904838 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -18,6 +18,9 @@ struct wlr_output_layout *wlr_output_layout_init(); void wlr_output_layout_destroy(struct wlr_output_layout *layout); +struct wlr_output_layout_output *wlr_output_layout_get( + struct wlr_output_layout *layout, struct wlr_output *reference); + struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, double x, double y); diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 8b4256f9..dd31aef8 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -33,7 +33,7 @@ void wlr_output_layout_add(struct wlr_output_layout *layout, wl_list_insert(&layout->outputs, &layout_output->link); } -static struct wlr_output_layout_output *wlr_output_layout_get( +struct wlr_output_layout_output *wlr_output_layout_get( struct wlr_output_layout *layout, struct wlr_output *reference) { struct wlr_output_layout_output *ret = NULL; struct wlr_output_layout_output *_output; From dfb6a1203690061f9a8910028690a7a69e926b6f Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 16 Aug 2017 15:06:38 -0400 Subject: [PATCH 03/11] layout-output example: only render if its on the output --- examples/output-layout.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/output-layout.c b/examples/output-layout.c index 81a7251b..cc363504 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -61,10 +61,14 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_layout_output_coords(sample->layout, output->output, &local_x, &local_y); - wlr_texture_get_matrix(sample->cat_texture, &matrix, - &wlr_output->transform_matrix, local_x, local_y); - wlr_render_with_matrix(sample->renderer, - sample->cat_texture, &matrix); + if (local_x < width && local_x + 128 > 0 && local_y < height && + local_y + 128 > 0) { + // render the image if it intersects with the output + wlr_texture_get_matrix(sample->cat_texture, &matrix, + &wlr_output->transform_matrix, local_x, local_y); + wlr_render_with_matrix(sample->renderer, + sample->cat_texture, &matrix); + } wlr_renderer_end(sample->renderer); wlr_output_swap_buffers(wlr_output); From 420bd3e4223d67c7bfe153be365caec342a18238 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 17 Aug 2017 08:51:47 -0400 Subject: [PATCH 04/11] bugfix: correctly get the output_layout --- types/wlr_output_layout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index dd31aef8..b4a3565e 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -38,7 +38,7 @@ struct wlr_output_layout_output *wlr_output_layout_get( struct wlr_output_layout_output *ret = NULL; struct wlr_output_layout_output *_output; wl_list_for_each(_output, &layout->outputs, link) { - if (_output->output) { + if (_output->output == reference) { ret = _output; } } From 5a9baf487e0161cfbf9481c31eb6f72be0ec2fbe Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 17 Aug 2017 10:12:36 -0400 Subject: [PATCH 05/11] add helper methods for intersection --- examples/output-layout.c | 22 ++++++++------------ include/wlr/types/wlr_output_layout.h | 6 ++++++ types/wlr_output_layout.c | 30 +++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/examples/output-layout.c b/examples/output-layout.c index cc363504..13abb6a1 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -46,24 +46,20 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts struct sample_state *sample = state->data; struct wlr_output *wlr_output = output->output; - int32_t width, height; - wlr_output_effective_resolution(wlr_output, &width, &height); - wlr_output_make_current(wlr_output); wlr_renderer_begin(sample->renderer, wlr_output); - float matrix[16]; + if (wlr_output_layout_intersects(sample->layout, output->output, + sample->x_offs, sample->y_offs, + sample->x_offs + 128, sample->y_offs + 128)) { + float matrix[16]; - // transform global coordinates to local coordinates - int local_x = sample->x_offs; - int local_y = sample->y_offs; + // transform global coordinates to local coordinates + int local_x = sample->x_offs; + int local_y = sample->y_offs; + wlr_output_layout_output_coords(sample->layout, output->output, &local_x, + &local_y); - wlr_output_layout_output_coords(sample->layout, output->output, &local_x, - &local_y); - - if (local_x < width && local_x + 128 > 0 && local_y < height && - local_y + 128 > 0) { - // render the image if it intersects with the output wlr_texture_get_matrix(sample->cat_texture, &matrix, &wlr_output->transform_matrix, local_x, local_y); wlr_render_with_matrix(sample->renderer, diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 7c904838..1b83bfaf 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -40,4 +40,10 @@ void wlr_output_layout_remove(struct wlr_output_layout *layout, void wlr_output_layout_output_coords(struct wlr_output_layout *layout, struct wlr_output *reference, int *x, int *y); +bool wlr_output_layout_contains_point(struct wlr_output_layout *layout, + struct wlr_output *reference, int x, int y); + +bool wlr_output_layout_intersects(struct wlr_output_layout *layout, + struct wlr_output *reference, int x1, int y1, int x2, int y2); + #endif diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index b4a3565e..ea93610d 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -47,6 +47,36 @@ struct wlr_output_layout_output *wlr_output_layout_get( } +static bool output_contains_point( struct wlr_output_layout_output *l_output, + int x, int y, int width, int height) { + return x >= l_output->x && x <= l_output->x + width && + y >= l_output->y && y <= l_output->y + height; +} + +bool wlr_output_layout_contains_point(struct wlr_output_layout *layout, + struct wlr_output *reference, int x, int y) { + struct wlr_output_layout_output *layout_output = wlr_output_layout_get(layout, reference); + int width, height; + wlr_output_effective_resolution(layout_output->output, &width, &height); + return output_contains_point(layout_output, x, y, width, height); +} + +bool wlr_output_layout_intersects(struct wlr_output_layout *layout, + struct wlr_output *reference, int x1, int y1, int x2, int y2) { + struct wlr_output_layout_output *l_output = wlr_output_layout_get(layout, reference); + if (!l_output) { + return false; + } + int width, height; + wlr_output_effective_resolution(l_output->output, &width, &height); + + // the output must contain one of the points + return output_contains_point(l_output, x1, y1, width, height) || + output_contains_point(l_output, x2, y2, width, height) || + output_contains_point(l_output, x2, y1, width, height) || + output_contains_point(l_output, y2, x1, width, height); +} + struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, double x, double y) { struct wlr_output *ret = NULL; From d9ebf0615a2f548a66abc590dbca9ae395cdfd0e Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 17 Aug 2017 11:21:54 -0400 Subject: [PATCH 06/11] add output resolution notify to example shared --- examples/shared.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/shared.c b/examples/shared.c index 58aef21a..1474f8a2 100644 --- a/examples/shared.c +++ b/examples/shared.c @@ -428,6 +428,15 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { compositor->last_frame = now; } +static void output_resolution_notify(struct wl_listener *listener, void *data) { + struct output_state *output = wl_container_of(listener, output, resolution); + struct compositor_state *compositor = output->compositor; + + if (compositor->output_resolution_cb) { + compositor->output_resolution_cb(output); + } +} + static void output_add_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; struct compositor_state *state = wl_container_of(listener, state, output_add); @@ -442,8 +451,10 @@ static void output_add_notify(struct wl_listener *listener, void *data) { ostate->output = output; ostate->compositor = state; ostate->frame.notify = output_frame_notify; + ostate->resolution.notify = output_resolution_notify; wl_list_init(&ostate->frame.link); wl_signal_add(&output->events.frame, &ostate->frame); + wl_signal_add(&output->events.resolution, &ostate->resolution); wl_list_insert(&state->outputs, &ostate->link); if (state->output_add_cb) { state->output_add_cb(ostate); @@ -468,6 +479,7 @@ static void output_remove_notify(struct wl_listener *listener, void *data) { } wl_list_remove(&ostate->link); wl_list_remove(&ostate->frame.link); + wl_list_remove(&ostate->resolution.link); free(ostate); } From 128f06405bf20358ae4a685d3df9e471ad693cb3 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 17 Aug 2017 16:15:49 -0400 Subject: [PATCH 07/11] vt change bugfix --- examples/output-layout.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/output-layout.c b/examples/output-layout.c index 13abb6a1..41b79596 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -75,6 +75,12 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts // how many seconds have passed since the last frame float seconds = ms / 1000.0f; + if (seconds > 0.1f) { + // XXX when we switch vt, the rendering loop stops so try to detect + // that and pause when it happens. + seconds = 0.0f; + } + // check for collisions and bounce bool ur_collision = !wlr_output_layout_output_at(sample->layout, sample->x_offs + 128, sample->y_offs); From e0b409760d22a2507c515ddfc1eb755b89b73757 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 17 Aug 2017 16:19:08 -0400 Subject: [PATCH 08/11] fix output resolution callback --- examples/shared.c | 2 +- examples/shared.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/shared.c b/examples/shared.c index 1474f8a2..5ebb7aa6 100644 --- a/examples/shared.c +++ b/examples/shared.c @@ -433,7 +433,7 @@ static void output_resolution_notify(struct wl_listener *listener, void *data) { struct compositor_state *compositor = output->compositor; if (compositor->output_resolution_cb) { - compositor->output_resolution_cb(output); + compositor->output_resolution_cb(compositor, output); } } diff --git a/examples/shared.h b/examples/shared.h index 9ffd506a..e2ebadef 100644 --- a/examples/shared.h +++ b/examples/shared.h @@ -16,6 +16,7 @@ struct output_state { struct compositor_state *compositor; struct wlr_output *output; struct wl_listener frame; + struct wl_listener resolution; struct timespec last_frame; struct wl_list link; void *data; @@ -78,6 +79,8 @@ struct compositor_state { void (*keyboard_add_cb)(struct keyboard_state *s); void (*output_frame_cb)(struct output_state *s, struct timespec *ts); void (*output_remove_cb)(struct output_state *s); + void (*output_resolution_cb)(struct compositor_state *compositor, + struct output_state *s); void (*keyboard_remove_cb)(struct keyboard_state *s); void (*keyboard_key_cb)(struct keyboard_state *s, uint32_t keycode, xkb_keysym_t sym, enum wlr_key_state key_state); From 59a71f59b98bfd34ba700993bcfbbd43f3804290 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 17 Aug 2017 16:20:15 -0400 Subject: [PATCH 09/11] reconfigure output on resolution change --- examples/output-layout.c | 107 ++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 41 deletions(-) diff --git a/examples/output-layout.c b/examples/output-layout.c index 41b79596..77e2ff7c 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -113,50 +114,73 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts } } +static inline int max(int a, int b) { + if (a < b) + return b; + return a; +} + +static void configure_layout(struct sample_state *sample) { + wlr_output_layout_destroy(sample->layout); + sample->layout = wlr_output_layout_init(); + sample->main_output = NULL; + int max_x = wl_list_empty(&sample->config) ? 0 : INT_MIN; + + // first add all the configure outputs + struct output_state *output; + wl_list_for_each(output, &sample->outputs, link) { + struct output_config *conf; + wl_list_for_each(conf, &sample->config, link) { + if (strcmp(conf->name, output->output->name) == 0) { + wlr_output_layout_add(sample->layout, output->output, + conf->x, conf->y); + wlr_output_transform(output->output, conf->transform); + int width, height; + wlr_output_effective_resolution(output->output, &width, &height); + max_x = max(max_x, conf->x + width); + + if (!sample->main_output) { + sample->main_output = output->output; + sample->x_offs = conf->x + 20; + sample->y_offs = conf->y + 20; + } + break; + } + } + } + + // now add all the other configured outputs in a sensible position + wl_list_for_each(output, &sample->outputs, link) { + if (wlr_output_layout_get(sample->layout, output->output)) { + continue; + } + wlr_output_layout_add(sample->layout, output->output, max_x, 0); + int width, height; + wlr_output_effective_resolution(output->output, &width, &height); + wlr_output_effective_resolution(output->output, &width, &height); + if (!sample->main_output) { + sample->main_output = output->output; + sample->x_offs = max_x + 200; + sample->y_offs = 200; + } + max_x += width; + } +} + +static void handle_output_resolution(struct compositor_state *state, struct output_state *output) { + struct sample_state *sample = state->data; + configure_layout(sample); + + // reset the image + struct wlr_output_layout_output *l_output = wlr_output_layout_get(sample->layout, sample->main_output); + sample->x_offs = l_output->x + 20; + sample->y_offs = l_output->y + 20; +} + static void handle_output_add(struct output_state *output) { struct sample_state *sample = output->compositor->data; - - bool found = false; - struct output_config *conf; - wl_list_for_each(conf, &sample->config, link) { - if (strcmp(conf->name, output->output->name) == 0) { - wlr_output_layout_add(sample->layout, output->output, - conf->x, conf->y); - wlr_output_transform(output->output, conf->transform); - - if (!sample->main_output) { - sample->main_output = output->output; - sample->x_offs = conf->x + 20; - sample->y_offs = conf->y + 20; - } - wlr_log(L_DEBUG, "Adding output to layout: %s", output->output->name); - found = true; - break; - } - } - - // if it's not in the config, just place it next to the rightmost output - if (!found) { - int x = 0; - struct output_state *_output; - wl_list_for_each(_output, &sample->outputs, link) { - struct wlr_output_layout_output *layout_output = - wlr_output_layout_get(sample->layout, _output->output); - if (layout_output && layout_output->output) { - x += layout_output->x + _output->output->width; - } - } - - wlr_output_layout_add(sample->layout, output->output, x, 0); - - if (wl_list_empty(&sample->config) && !sample->main_output) { - sample->main_output = output->output; - sample->x_offs = x + 20; - sample->y_offs = 20; - } - } - wl_list_insert(&sample->outputs, &output->link); + configure_layout(sample); } static void update_velocities(struct compositor_state *state, @@ -287,6 +311,7 @@ int main(int argc, char *argv[]) { compositor.data = &state; compositor.output_add_cb = handle_output_add; compositor.output_frame_cb = handle_output_frame; + compositor.output_resolution_cb = handle_output_resolution; compositor.keyboard_key_cb = handle_keyboard_key; compositor_init(&compositor); From 854a9381ca2040c3b550323ff9f90c864a431b27 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 17 Aug 2017 18:46:05 -0400 Subject: [PATCH 10/11] improve collision detection algorithm --- examples/output-layout.c | 42 ++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/examples/output-layout.c b/examples/output-layout.c index 77e2ff7c..320d11f8 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -91,22 +91,34 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts sample->x_offs, sample->y_offs + 128); bool lr_collision = !wlr_output_layout_output_at(sample->layout, sample->x_offs + 128, sample->y_offs + 128); - bool has_double_collision = false; - if ((ur_collision && ul_collision) || (lr_collision && ll_collision)) { - sample->y_vel *= -1; - has_double_collision = true; - } - - if ((ll_collision && ul_collision) || (ur_collision && lr_collision)) { - sample->x_vel *= -1; - has_double_collision = true; - } - - if (!has_double_collision && - (ur_collision || ul_collision || lr_collision || ll_collision)) { - sample->x_vel *= -1; - sample->y_vel *= -1; + if (ur_collision && ul_collision && ll_collision && lr_collision) { + // oops we went off the screen somehow + struct wlr_output_layout_output *main_l_output; + main_l_output = wlr_output_layout_get(sample->layout, sample->main_output); + sample->x_offs = main_l_output->x + 20; + sample->y_offs = main_l_output->y + 20; + } else if (ur_collision && ul_collision) { + sample->y_vel = fabs(sample->y_vel); + } else if (lr_collision && ll_collision) { + sample->y_vel = -fabs(sample->y_vel); + } else if (ll_collision && ul_collision) { + sample->x_vel = fabs(sample->x_vel); + } else if (ur_collision && lr_collision) { + sample->x_vel = -fabs(sample->x_vel); + } else { + if (ur_collision || lr_collision) { + sample->x_vel = -fabs(sample->x_vel); + } + if (ul_collision || ll_collision) { + sample->x_vel = fabs(sample->x_vel); + } + if (ul_collision || ur_collision) { + sample->y_vel = fabs(sample->y_vel); + } + if (ll_collision || lr_collision) { + sample->y_vel = -fabs(sample->y_vel); + } } sample->x_offs += sample->x_vel * seconds; From 3138c5ddf04441fb7572db8c1a80b3789c4cc563 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 17 Aug 2017 21:04:05 -0400 Subject: [PATCH 11/11] Clean up wlr_output_layout --- examples/output-layout.c | 8 +++----- include/wlr/types/wlr_output_layout.h | 14 +++++++------- types/wlr_output_layout.c | 14 ++++---------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/examples/output-layout.c b/examples/output-layout.c index 320d11f8..c16af634 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -127,9 +127,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts } static inline int max(int a, int b) { - if (a < b) - return b; - return a; + return a < b ? b : a; } static void configure_layout(struct sample_state *sample) { @@ -202,8 +200,8 @@ static void update_velocities(struct compositor_state *state, sample->y_vel += y_diff; } -static void handle_keyboard_key(struct keyboard_state *kbstate, - xkb_keysym_t sym, enum wlr_key_state key_state) { +static void handle_keyboard_key(struct keyboard_state *kbstate, uint32_t keycode, + xkb_keysym_t sym, enum wlr_key_state key_state) { // NOTE: It may be better to simply refer to our key state during each frame // and make this change in pixels/sec^2 // Also, key repeat diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 1b83bfaf..f6a1efdd 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -22,28 +22,28 @@ struct wlr_output_layout_output *wlr_output_layout_get( struct wlr_output_layout *layout, struct wlr_output *reference); struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, - double x, double y); + double x, double y); void wlr_output_layout_add(struct wlr_output_layout *layout, - struct wlr_output *output, int x, int y); + struct wlr_output *output, int x, int y); void wlr_output_layout_move(struct wlr_output_layout *layout, - struct wlr_output *output, int x, int y); + struct wlr_output *output, int x, int y); void wlr_output_layout_remove(struct wlr_output_layout *layout, - struct wlr_output *output); + struct wlr_output *output); /** * Given x and y as pointers to global coordinates, adjusts them to local output * coordinates relative to the given reference output. */ void wlr_output_layout_output_coords(struct wlr_output_layout *layout, - struct wlr_output *reference, int *x, int *y); + struct wlr_output *reference, int *x, int *y); bool wlr_output_layout_contains_point(struct wlr_output_layout *layout, - struct wlr_output *reference, int x, int y); + struct wlr_output *reference, int x, int y); bool wlr_output_layout_intersects(struct wlr_output_layout *layout, - struct wlr_output *reference, int x1, int y1, int x2, int y2); + struct wlr_output *reference, int x1, int y1, int x2, int y2); #endif diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index ea93610d..2e2032b3 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -35,16 +35,13 @@ void wlr_output_layout_add(struct wlr_output_layout *layout, struct wlr_output_layout_output *wlr_output_layout_get( struct wlr_output_layout *layout, struct wlr_output *reference) { - struct wlr_output_layout_output *ret = NULL; struct wlr_output_layout_output *_output; wl_list_for_each(_output, &layout->outputs, link) { if (_output->output == reference) { - ret = _output; + return _output; } } - - return ret; - + return NULL; } static bool output_contains_point( struct wlr_output_layout_output *l_output, @@ -79,7 +76,6 @@ bool wlr_output_layout_intersects(struct wlr_output_layout *layout, struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, double x, double y) { - struct wlr_output *ret = NULL; struct wlr_output_layout_output *_output; wl_list_for_each(_output, &layout->outputs, link) { if (_output->output) { @@ -88,13 +84,11 @@ struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, bool has_x = x >= _output->x && x <= _output->x + width; bool has_y = y >= _output->y && y <= _output->y + height; if (has_x && has_y) { - ret = _output->output; - break; + return _output->output; } } } - - return ret; + return NULL; } void wlr_output_layout_move(struct wlr_output_layout *layout,