refactor(wayland): make all wayland code optional

This commit is contained in:
Jeremy Attali 2019-12-30 01:20:30 -05:00
parent c4ea305ae6
commit cf33f3a4fb
11 changed files with 283 additions and 238 deletions

View File

@ -17,6 +17,7 @@
"ostream": "c",
"sstream": "c",
"streambuf": "c",
"clipboard.h": "c"
"clipboard.h": "c",
"buffer.h": "c"
}
}

View File

@ -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:

View File

@ -4,24 +4,12 @@
#include <wayland-client.h>
#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);

View File

@ -6,9 +6,11 @@
#include <stdint.h>
#include <stdlib.h>
#include <wayland-client.h>
#ifdef HAVE_WAYLAND_PROTOCOLS
#include <xdg-output-unstable-v1-client-protocol.h>
#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
};

View File

@ -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')

View File

@ -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 = []

View File

@ -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;

View File

@ -5,6 +5,7 @@
#include <sys/mman.h>
#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;
}
}

View File

@ -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;
}

View File

@ -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.

View File

@ -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, &registry_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, &registry_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;
}