From cf33f3a4fb1912c34e1b5cae6f83ca4358690c09 Mon Sep 17 00:00:00 2001 From: Jeremy Attali Date: Mon, 30 Dec 2019 01:20:30 -0500 Subject: [PATCH] refactor(wayland): make all wayland code optional --- .vscode/settings.json | 3 +- README.md | 5 +- include/buffer.h | 18 +---- include/swappy.h | 80 ++++++++++++---------- meson.build | 7 +- protocol/meson.build | 20 ++++-- src/application.c | 10 ++- src/buffer.c | 153 ++++++++++++++++++++++++++++++++++-------- src/main.c | 7 -- src/render.c | 107 +++-------------------------- src/wayland.c | 111 +++++++++++++++++++----------- 11 files changed, 283 insertions(+), 238 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 1062544..e846235 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,6 +17,7 @@ "ostream": "c", "sstream": "c", "streambuf": "c", - "clipboard.h": "c" + "clipboard.h": "c", + "buffer.h": "c" } } \ No newline at end of file diff --git a/README.md b/README.md index 0f2f448..5768e00 100644 --- a/README.md +++ b/README.md @@ -94,13 +94,14 @@ Install dependencies: - meson - wayland -- wayland-protocols - cairo - gtk Optional dependencies: -- libnotify +- wayland-protocols (for the `-g` option to work with `screencopy` protocol). +- libnotify (not get notified when swappshot is copied or saved). +- scdoc to generate the man page Then run: diff --git a/include/buffer.h b/include/buffer.h index f60cfc4..0ca6819 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -4,24 +4,12 @@ #include #include "swappy.h" -#include "wlr-screencopy-unstable-v1-client-protocol.h" -void screencopy_frame_handle_buffer(void *data, - struct zwlr_screencopy_frame_v1 *frame, - uint32_t format, uint32_t width, - uint32_t height, uint32_t stride); -void screencopy_frame_handle_flags(void *data, - struct zwlr_screencopy_frame_v1 *frame, - uint32_t flags); -void screencopy_frame_handle_ready(void *data, - struct zwlr_screencopy_frame_v1 *frame, - uint32_t tv_sec_hi, uint32_t tv_sec_lo, - uint32_t tv_nsec); -void screencopy_frame_handle_failed(void *data, - struct zwlr_screencopy_frame_v1 *frame); -void screencopy_destroy_buffer(struct swappy_buffer *buffer); +void buffer_wayland_destroy(struct swappy_buffer *buffer); bool buffer_init_from_screencopy(struct swappy_state *state); bool buffer_init_from_file(struct swappy_state *state); bool buffer_parse_geometry(struct swappy_state *state); + +void buffer_free_all(struct swappy_state *state); diff --git a/include/swappy.h b/include/swappy.h index 3ad0cd9..0b53e0e 100644 --- a/include/swappy.h +++ b/include/swappy.h @@ -6,9 +6,11 @@ #include #include #include +#ifdef HAVE_WAYLAND_PROTOCOLS +#include +#endif #include "wlr-screencopy-unstable-v1-client-protocol.h" -#include "xdg-output-unstable-v1-client-protocol.h" #define MAX_PATH 4096 @@ -100,23 +102,56 @@ struct swappy_state_ui { GtkButton *stroke_size; }; -struct swappy_state { - GtkApplication *app; +struct swappy_buffer { + struct wl_buffer *wl_buffer; + void *data; + int32_t width, height, stride; + size_t size; + enum wl_shm_format format; +}; - struct swappy_state_ui *ui; +struct swappy_output { + struct swappy_state *state; + struct swappy_box geometry; + struct swappy_box logical_geometry; + struct wl_output *wl_output; + struct wl_list link; + int32_t scale; + struct swappy_buffer *buffer; - cairo_surface_t *cairo_surface; - cairo_surface_t *image_surface; + double logical_scale; // guessed from the logical size + char *name; + enum wl_output_transform transform; + struct zwlr_screencopy_frame_v1 *screencopy_frame; + uint32_t screencopy_frame_flags; // enum zwlr_screencopy_frame_v1_flags + +#ifdef HAVE_WAYLAND_PROTOCOLS + struct zxdg_output_v1 *xdg_output; +#endif +}; + +struct swappy_wayland { struct wl_display *display; struct wl_registry *registry; struct wl_compositor *compositor; struct wl_shm *shm; - struct zxdg_output_manager_v1 *xdg_output_manager; + struct wl_list outputs; struct zwlr_screencopy_manager_v1 *zwlr_screencopy_manager; - struct wl_list outputs; // mako_output::link - size_t n_done; +#ifdef HAVE_WAYLAND_PROTOCOLS + struct zxdg_output_manager_v1 *xdg_output_manager; +#endif +}; + +struct swappy_state { + GtkApplication *app; + + struct swappy_state_ui *ui; + struct swappy_wayland *wl; + + cairo_surface_t *cairo_surface; + GList *patterns; // List of cairo_pattern_t char *storage_path; @@ -137,30 +172,3 @@ struct swappy_state { int argc; char **argv; }; - -struct swappy_buffer { - struct wl_buffer *wl_buffer; - void *data; - int32_t width, height, stride; - size_t size; - enum wl_shm_format format; -}; - -struct swappy_output { - struct swappy_state *state; - struct wl_output *wl_output; - struct zxdg_output_v1 *xdg_output; - struct wl_list link; - - struct swappy_box geometry; - enum wl_output_transform transform; - int32_t scale; - - struct swappy_box logical_geometry; - double logical_scale; // guessed from the logical size - char *name; - - struct swappy_buffer *buffer; - struct zwlr_screencopy_frame_v1 *screencopy_frame; - uint32_t screencopy_frame_flags; // enum zwlr_screencopy_frame_v1_flags -}; diff --git a/meson.build b/meson.build index ef7d253..7df9f7e 100644 --- a/meson.build +++ b/meson.build @@ -28,7 +28,7 @@ realtime = cc.find_library('rt') gtk = dependency('gtk+-3.0', version: '>=3.20.0') wayland_client = dependency('wayland-client') wayland_cursor = dependency('wayland-cursor') -wayland_protos = dependency('wayland-protocols', version: '>=1.14') +wayland_protos = dependency('wayland-protocols', version: '>=1.14', required: false) libnotify = dependency('libnotify', required: false) @@ -36,6 +36,11 @@ if libnotify.found() add_project_arguments('-DHAVE_LIBNOTIFY', language: 'c') endif +if wayland_protos.found() + add_project_arguments('-DHAVE_WAYLAND_PROTOCOLS', language: 'c') +endif + + subdir('res') subdir('protocol') diff --git a/protocol/meson.build b/protocol/meson.build index f2c2465..a3bd96a 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -1,5 +1,3 @@ -wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') - wayland_scanner = find_program('wayland-scanner') # should check wayland_scanner's version, but it is hard to get @@ -21,11 +19,19 @@ wayland_scanner_client = generator( arguments: ['client-header', '@INPUT@', '@OUTPUT@'], ) -client_protocols = [ - [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], - [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], - ['wlr-screencopy-unstable-v1.xml'], -] +if wayland_protos.found() + wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') + client_protocols = [ + [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], + [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], + ['wlr-screencopy-unstable-v1.xml'], + ] +else + client_protocols = [ + ['wlr-screencopy-unstable-v1.xml'], + ] +endif + client_protos_src = [] client_protos_headers = [] diff --git a/src/application.c b/src/application.c index b223f38..46be32a 100644 --- a/src/application.c +++ b/src/application.c @@ -154,14 +154,16 @@ void arrow_clicked_handler(GtkWidget *widget, struct swappy_state *state) { void application_finish(struct swappy_state *state) { paint_free_all(state); + buffer_free_all(state); cairo_surface_destroy(state->cairo_surface); - cairo_surface_destroy(state->image_surface); g_free(state->storage_path); g_free(state->file_str); g_free(state->geometry_str); g_free(state->geometry); g_free(state->ui); g_object_unref(state->app); + + wayland_finish(state); } static void action_save_area_to_file(struct swappy_state *state) { @@ -544,6 +546,12 @@ static gboolean is_file_from_stdin(const char *file) { static gint command_line_handler(GtkApplication *app, GApplicationCommandLine *cmdline, struct swappy_state *state) { + if (!wayland_init(state)) { + g_warning( + "error while initializing wayland objects, can only be used in file " + "mode"); + } + if (has_option_geometry(state)) { if (!buffer_parse_geometry(state)) { return EXIT_FAILURE; diff --git a/src/buffer.c b/src/buffer.c index f6e4731..770395a 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -5,6 +5,7 @@ #include #include "box.h" +#include "wayland.h" static void randname(char *buf) { struct timespec ts; @@ -49,6 +50,30 @@ static int create_shm_file(off_t size) { return fd; } +static cairo_format_t get_cairo_format(enum wl_shm_format wl_fmt) { + switch (wl_fmt) { + case WL_SHM_FORMAT_ARGB8888: + return CAIRO_FORMAT_ARGB32; + case WL_SHM_FORMAT_XRGB8888: + return CAIRO_FORMAT_RGB24; + default: + return CAIRO_FORMAT_INVALID; + } +} + +static int get_output_flipped(enum wl_output_transform transform) { + return transform & WL_OUTPUT_TRANSFORM_FLIPPED ? -1 : 1; +} + +static void apply_output_transform(enum wl_output_transform transform, + int32_t *width, int32_t *height) { + if (transform & WL_OUTPUT_TRANSFORM_90) { + int32_t tmp = *width; + *width = *height; + *height = tmp; + } +} + static struct swappy_buffer *create_buffer(struct wl_shm *shm, enum wl_shm_format format, int32_t width, int32_t height, @@ -85,23 +110,13 @@ static struct swappy_buffer *create_buffer(struct wl_shm *shm, return buffer; } -void screencopy_destroy_buffer(struct swappy_buffer *buffer) { - if (buffer == NULL) { - return; - } - munmap(buffer->data, buffer->size); - wl_buffer_destroy(buffer->wl_buffer); - free(buffer); -} - -void screencopy_frame_handle_buffer(void *data, - struct zwlr_screencopy_frame_v1 *frame, - uint32_t format, uint32_t width, - uint32_t height, uint32_t stride) { +static void screencopy_frame_handle_buffer( + void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t format, + uint32_t width, uint32_t height, uint32_t stride) { struct swappy_output *output = data; output->buffer = - create_buffer(output->state->shm, format, width, height, stride); + create_buffer(output->state->wl->shm, format, width, height, stride); if (output->buffer == NULL) { g_warning("failed to create buffer"); exit(EXIT_FAILURE); @@ -110,29 +125,28 @@ void screencopy_frame_handle_buffer(void *data, zwlr_screencopy_frame_v1_copy(frame, output->buffer->wl_buffer); } -void screencopy_frame_handle_flags(void *data, - struct zwlr_screencopy_frame_v1 *frame, - uint32_t flags) { +static void screencopy_frame_handle_flags( + void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t flags) { struct swappy_output *output = data; output->screencopy_frame_flags = flags; } -void screencopy_frame_handle_ready(void *data, - struct zwlr_screencopy_frame_v1 *frame, - uint32_t tv_sec_hi, uint32_t tv_sec_lo, - uint32_t tv_nsec) { +static void screencopy_frame_handle_ready( + void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t tv_sec_hi, + uint32_t tv_sec_lo, uint32_t tv_nsec) { struct swappy_output *output = data; - ++output->state->n_done; + ++output->state->wl->n_done; } -void screencopy_frame_handle_failed(void *data, - struct zwlr_screencopy_frame_v1 *frame) { +static void screencopy_frame_handle_failed( + void *data, struct zwlr_screencopy_frame_v1 *frame) { struct swappy_output *output = data; g_warning("screencopy: failed to copy output %s", output->name); exit(EXIT_FAILURE); } bool buffer_init_from_screencopy(struct swappy_state *state) { + struct swappy_box *geometry = state->geometry; int32_t with_cursor = 0; size_t n_pending = 0; struct swappy_output *output; @@ -144,14 +158,14 @@ bool buffer_init_from_screencopy(struct swappy_state *state) { .failed = screencopy_frame_handle_failed, }; - wl_list_for_each(output, &state->outputs, link) { + wl_list_for_each(output, &state->wl->outputs, link) { if (state->geometry != NULL && !intersect_box(state->geometry, &output->logical_geometry)) { continue; } output->screencopy_frame = zwlr_screencopy_manager_v1_capture_output( - state->zwlr_screencopy_manager, with_cursor, output->wl_output); + state->wl->zwlr_screencopy_manager, with_cursor, output->wl_output); zwlr_screencopy_frame_v1_add_listener(output->screencopy_frame, &screencopy_frame_listener, output); @@ -163,14 +177,70 @@ bool buffer_init_from_screencopy(struct swappy_state *state) { } bool done = false; - while (!done && wl_display_dispatch(state->display) != -1) { - done = (state->n_done == n_pending); + while (!done && wl_display_dispatch(state->wl->display) != -1) { + done = (state->wl->n_done == n_pending); } if (!done) { g_warning("failed to screenshot all outputs"); return EXIT_FAILURE; } + wl_list_for_each(output, &state->wl->outputs, link) { + struct swappy_buffer *buffer = output->buffer; + + if (output->buffer == NULL) { + // screencopy buffer is empty, cannot draw it onto the paint area" + continue; + } + + cairo_format_t format = get_cairo_format(buffer->format); + + g_assert(format != CAIRO_FORMAT_INVALID); + + int32_t output_x = output->logical_geometry.x - geometry->x; + int32_t output_y = output->logical_geometry.y - geometry->y; + int32_t output_width = output->logical_geometry.width; + int32_t output_height = output->logical_geometry.height; + int32_t scale = output->scale; + + int32_t raw_output_width = output->geometry.width; + int32_t raw_output_height = output->geometry.height; + apply_output_transform(output->transform, &raw_output_width, + &raw_output_height); + + int output_flipped_x = get_output_flipped(output->transform); + int output_flipped_y = + output->screencopy_frame_flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT + ? -1 + : 1; + + cairo_surface_t *output_surface = cairo_image_surface_create_for_data( + buffer->data, format, buffer->width, buffer->height, buffer->stride); + cairo_pattern_t *output_pattern = + cairo_pattern_create_for_surface(output_surface); + + // All transformations are in pattern-local coordinates + cairo_matrix_t matrix; + cairo_matrix_init_identity(&matrix); + cairo_matrix_translate(&matrix, (double)output->geometry.width / 2, + (double)output->geometry.height / 2); + // cairo_matrix_rotate(&matrix, -get_output_rotation(output->transform)); + cairo_matrix_scale( + &matrix, (double)raw_output_width / output_width * output_flipped_x, + (double)raw_output_height / output_height * output_flipped_y); + cairo_matrix_translate(&matrix, -(double)output_width / 2, + -(double)output_height / 2); + cairo_matrix_translate(&matrix, -output_x, -output_y); + cairo_matrix_scale(&matrix, 1 / scale, 1 / scale); + cairo_pattern_set_matrix(output_pattern, &matrix); + + cairo_pattern_set_filter(output_pattern, CAIRO_FILTER_BEST); + + state->patterns = g_list_append(state->patterns, output_pattern); + + cairo_surface_destroy(output_surface); + } + return true; } @@ -197,7 +267,11 @@ bool buffer_init_from_file(struct swappy_state *state) { geometry->height = (int32_t)height; state->geometry = geometry; - state->image_surface = surface; + + cairo_pattern_t *output_pattern = cairo_pattern_create_for_surface(surface); + state->patterns = g_list_append(state->patterns, output_pattern); + + cairo_surface_destroy(surface); return true; } @@ -214,3 +288,24 @@ bool buffer_parse_geometry(struct swappy_state *state) { } return true; } + +void buffer_wayland_destroy(struct swappy_buffer *buffer) { + if (buffer == NULL) { + return; + } + munmap(buffer->data, buffer->size); + wl_buffer_destroy(buffer->wl_buffer); + free(buffer); +} + +static void free_pattern(gpointer data) { + cairo_pattern_t *pattern = data; + cairo_pattern_destroy(pattern); +} + +void buffer_free_all(struct swappy_state *state) { + if (state->patterns) { + g_list_free_full(state->patterns, free_pattern); + state->patterns = NULL; + } +} \ No newline at end of file diff --git a/src/main.c b/src/main.c index cbb5edb..3bc3b66 100644 --- a/src/main.c +++ b/src/main.c @@ -2,7 +2,6 @@ #include "application.h" #include "config.h" -#include "wayland.h" int main(int argc, char *argv[]) { struct swappy_state state = {0}; @@ -22,11 +21,6 @@ int main(int argc, char *argv[]) { exit(1); } - if (!wayland_init(&state)) { - g_critical("failed to initialize wayland"); - exit(1); - } - status = application_run(&state); if (status == 0) { @@ -34,7 +28,6 @@ int main(int argc, char *argv[]) { } application_finish(&state); - wayland_finish(&state); return status; } diff --git a/src/render.c b/src/render.c index 56644dd..9fa7e95 100644 --- a/src/render.c +++ b/src/render.c @@ -7,30 +7,6 @@ #define M_PI (3.14159265358979323846) #endif -static cairo_format_t get_cairo_format(enum wl_shm_format wl_fmt) { - switch (wl_fmt) { - case WL_SHM_FORMAT_ARGB8888: - return CAIRO_FORMAT_ARGB32; - case WL_SHM_FORMAT_XRGB8888: - return CAIRO_FORMAT_RGB24; - default: - return CAIRO_FORMAT_INVALID; - } -} - -static int get_output_flipped(enum wl_output_transform transform) { - return transform & WL_OUTPUT_TRANSFORM_FLIPPED ? -1 : 1; -} - -static void apply_output_transform(enum wl_output_transform transform, - int32_t *width, int32_t *height) { - if (transform & WL_OUTPUT_TRANSFORM_90) { - int32_t tmp = *width; - *width = *height; - *height = tmp; - } -} - static void render_shape_arrow(cairo_t *cr, struct swappy_paint_shape shape) { cairo_set_source_rgba(cr, shape.r, shape.g, shape.b, shape.a); cairo_set_line_width(cr, shape.w); @@ -142,82 +118,18 @@ static void render_shape(cairo_t *cr, struct swappy_paint_shape shape) { cairo_restore(cr); } -static void render_buffer(cairo_t *cr, struct swappy_state *state) { - // FIXME This is wrong, the geometry here is not quite valid - // It must be based on output, but will work fine on single screen - struct swappy_box *geometry = state->geometry; - struct swappy_output *output; - - wl_list_for_each(output, &state->outputs, link) { - struct swappy_buffer *buffer = output->buffer; - - if (output->buffer == NULL) { - // screencopy buffer is empty, cannot draw it onto the paint area" - continue; - } - - cairo_format_t format = get_cairo_format(buffer->format); - - g_assert(format != CAIRO_FORMAT_INVALID); - - int32_t output_x = output->logical_geometry.x - geometry->x; - int32_t output_y = output->logical_geometry.y - geometry->y; - int32_t output_width = output->logical_geometry.width; - int32_t output_height = output->logical_geometry.height; - int32_t scale = output->scale; - - int32_t raw_output_width = output->geometry.width; - int32_t raw_output_height = output->geometry.height; - apply_output_transform(output->transform, &raw_output_width, - &raw_output_height); - - int output_flipped_x = get_output_flipped(output->transform); - int output_flipped_y = - output->screencopy_frame_flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT - ? -1 - : 1; - - cairo_surface_t *output_surface = cairo_image_surface_create_for_data( - buffer->data, format, buffer->width, buffer->height, buffer->stride); - cairo_pattern_t *output_pattern = - cairo_pattern_create_for_surface(output_surface); - - // All transformations are in pattern-local coordinates - cairo_matrix_t matrix; - cairo_matrix_init_identity(&matrix); - cairo_matrix_translate(&matrix, (double)output->geometry.width / 2, - (double)output->geometry.height / 2); - // cairo_matrix_rotate(&matrix, -get_output_rotation(output->transform)); - cairo_matrix_scale( - &matrix, (double)raw_output_width / output_width * output_flipped_x, - (double)raw_output_height / output_height * output_flipped_y); - cairo_matrix_translate(&matrix, -(double)output_width / 2, - -(double)output_height / 2); - cairo_matrix_translate(&matrix, -output_x, -output_y); - cairo_matrix_scale(&matrix, 1 / scale, 1 / scale); - cairo_pattern_set_matrix(output_pattern, &matrix); - - cairo_pattern_set_filter(output_pattern, CAIRO_FILTER_BEST); - - cairo_set_source(cr, output_pattern); - cairo_pattern_destroy(output_pattern); - - cairo_paint(cr); - - cairo_surface_destroy(output_surface); - } -} - -static void render_image(cairo_t *cr, struct swappy_state *state) { - if (!state->image_surface) { +static void render_buffers(cairo_t *cr, struct swappy_state *state) { + if (!state->patterns) { return; } - cairo_pattern_t *output_pattern = - cairo_pattern_create_for_surface(state->image_surface); - cairo_set_source(cr, output_pattern); - cairo_pattern_destroy(output_pattern); cairo_paint(cr); + + for (GList *elem = state->patterns; elem; elem = elem->prev) { + cairo_pattern_t *pattern = elem->data; + cairo_set_source(cr, pattern); + cairo_paint(cr); + } } static void render_background(cairo_t *cr) { @@ -280,8 +192,7 @@ void render_state(struct swappy_state *state) { cairo_t *cr = cairo_create(state->cairo_surface); render_background(cr); - render_buffer(cr, state); - render_image(cr, state); + render_buffers(cr, state); render_paints(cr, state); // Drawing is finished, notify the GtkDrawingArea it needs to be redrawn. diff --git a/src/wayland.c b/src/wayland.c index 36d60ca..1631781 100644 --- a/src/wayland.c +++ b/src/wayland.c @@ -7,11 +7,14 @@ #include "buffer.h" #include "swappy.h" #include "wlr-screencopy-unstable-v1-client-protocol.h" + +#ifdef HAVE_WAYLAND_PROTOCOLS #include "xdg-output-unstable-v1-client-protocol.h" +#endif static bool guess_output_logical_geometry(struct swappy_output *output) { // TODO Implement - g_critical("guessing output is not yet implemented"); + g_warning("guessing output is not yet implemented"); return false; } @@ -24,6 +27,7 @@ void apply_output_transform(enum wl_output_transform transform, int32_t *width, } } +#ifdef HAVE_WAYLAND_PROTOCOLS static void xdg_output_handle_logical_position( void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y) { struct swappy_output *output = data; @@ -70,6 +74,7 @@ static const struct zxdg_output_v1_listener xdg_output_listener = { .name = xdg_output_handle_name, .description = xdg_output_handle_description, }; +#endif static void output_handle_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, @@ -120,11 +125,12 @@ static void global_registry_handler(void *data, struct wl_registry *registry, bool bound = false; if (strcmp(interface, wl_compositor_interface.name) == 0) { - state->compositor = + state->wl->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, version); bound = true; } else if (strcmp(interface, wl_shm_interface.name) == 0) { - state->shm = wl_registry_bind(registry, name, &wl_shm_interface, version); + state->wl->shm = + wl_registry_bind(registry, name, &wl_shm_interface, version); bound = true; } else if (strcmp(interface, wl_output_interface.name) == 0) { struct swappy_output *output = calloc(1, sizeof(struct swappy_output)); @@ -133,17 +139,21 @@ static void global_registry_handler(void *data, struct wl_registry *registry, output->wl_output = wl_registry_bind(registry, name, &wl_output_interface, 3); wl_output_add_listener(output->wl_output, &output_listener, output); - wl_list_insert(&state->outputs, &output->link); - bound = true; - } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) { - state->xdg_output_manager = wl_registry_bind( - registry, name, &zxdg_output_manager_v1_interface, version); + wl_list_insert(&state->wl->outputs, &output->link); bound = true; } else if (strcmp(interface, zwlr_screencopy_manager_v1_interface.name) == 0) { - state->zwlr_screencopy_manager = wl_registry_bind( + state->wl->zwlr_screencopy_manager = wl_registry_bind( registry, name, &zwlr_screencopy_manager_v1_interface, version); bound = true; + } else { +#ifdef HAVE_WAYLAND_PROTOCOLS + if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) { + state->wl->xdg_output_manager = wl_registry_bind( + registry, name, &zxdg_output_manager_v1_interface, version); + bound = true; + } +#endif } if (bound) { @@ -161,49 +171,56 @@ static struct wl_registry_listener registry_listener = { }; bool wayland_init(struct swappy_state *state) { - state->display = wl_display_connect(NULL); - if (state->display == NULL) { + state->wl = g_new(struct swappy_wayland, 1); + + state->wl->display = wl_display_connect(NULL); + if (state->wl->display == NULL) { g_warning("cannot connect to wayland display"); return false; } - wl_list_init(&state->outputs); - state->registry = wl_display_get_registry(state->display); - wl_registry_add_listener(state->registry, ®istry_listener, state); - wl_display_roundtrip(state->display); + wl_list_init(&state->wl->outputs); + state->wl->registry = wl_display_get_registry(state->wl->display); + wl_registry_add_listener(state->wl->registry, ®istry_listener, state); + wl_display_roundtrip(state->wl->display); - if (state->compositor == NULL) { + if (state->wl->compositor == NULL) { g_warning("compositor doesn't support wl_compositor"); return false; } - if (state->shm == NULL) { + if (state->wl->shm == NULL) { g_warning("compositor doesn't support wl_shm"); return false; } - if (wl_list_empty(&state->outputs)) { + if (wl_list_empty(&state->wl->outputs)) { g_warning("no wl_output found"); return false; } - if (state->xdg_output_manager != NULL) { + bool found_output_layout = false; +#ifdef HAVE_WAYLAND_PROTOCOLS + if (state->wl->xdg_output_manager != NULL) { struct swappy_output *output; - wl_list_for_each(output, &state->outputs, link) { + wl_list_for_each(output, &state->wl->outputs, link) { output->xdg_output = zxdg_output_manager_v1_get_xdg_output( - state->xdg_output_manager, output->wl_output); + state->wl->xdg_output_manager, output->wl_output); zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output); } - wl_display_dispatch(state->display); - wl_display_roundtrip(state->display); - } else { + wl_display_dispatch(state->wl->display); + wl_display_roundtrip(state->wl->display); + found_output_layout = true; + } +#endif + if (!found_output_layout) { g_warning( "zxdg_output_manager_v1 isn't available, guessing the output layout"); struct swappy_output *output; bool output_guessed = false; - wl_list_for_each(output, &state->outputs, link) { + wl_list_for_each(output, &state->wl->outputs, link) { output_guessed = guess_output_logical_geometry(output); } if (!output_guessed) { @@ -212,7 +229,7 @@ bool wayland_init(struct swappy_state *state) { } } - if (state->zwlr_screencopy_manager == NULL) { + if (state->wl->zwlr_screencopy_manager == NULL) { g_warning("compositor does not support zwlr_screencopy_v1"); return false; } @@ -223,41 +240,53 @@ bool wayland_init(struct swappy_state *state) { void wayland_finish(struct swappy_state *state) { struct swappy_output *output; struct swappy_output *output_tmp; - wl_list_for_each_safe(output, output_tmp, &state->outputs, link) { + + if (!state->wl) { + return; + } + + wl_list_for_each_safe(output, output_tmp, &state->wl->outputs, link) { wl_list_remove(&output->link); free(output->name); if (output->screencopy_frame != NULL) { zwlr_screencopy_frame_v1_destroy(output->screencopy_frame); } +#ifdef HAVE_WAYLAND_PROTOCOLS if (output->xdg_output != NULL) { zxdg_output_v1_destroy(output->xdg_output); } +#endif wl_output_release(output->wl_output); - screencopy_destroy_buffer(output->buffer); + buffer_wayland_destroy(output->buffer); free(output); } - if (state->compositor != NULL) { - wl_compositor_destroy(state->compositor); + if (state->wl->compositor != NULL) { + wl_compositor_destroy(state->wl->compositor); } - if (state->zwlr_screencopy_manager != NULL) { - zwlr_screencopy_manager_v1_destroy(state->zwlr_screencopy_manager); + if (state->wl->zwlr_screencopy_manager != NULL) { + zwlr_screencopy_manager_v1_destroy(state->wl->zwlr_screencopy_manager); } - if (state->xdg_output_manager != NULL) { - zxdg_output_manager_v1_destroy(state->xdg_output_manager); +#ifdef HAVE_WAYLAND_PROTOCOLS + if (state->wl->xdg_output_manager != NULL) { + zxdg_output_manager_v1_destroy(state->wl->xdg_output_manager); + } +#endif + + if (state->wl->shm != NULL) { + wl_shm_destroy(state->wl->shm); } - if (state->shm != NULL) { - wl_shm_destroy(state->shm); + if (state->wl->registry != NULL) { + wl_registry_destroy(state->wl->registry); } - if (state->registry != NULL) { - wl_registry_destroy(state->registry); + if (state->wl->display) { + wl_display_disconnect(state->wl->display); } - if (state->display) { - wl_display_disconnect(state->display); - } + g_free(state->wl); + state->wl = NULL; } \ No newline at end of file