From e30fb49b70feb11340ad459347e7978838ea3e40 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 6 Jul 2022 09:25:07 +0900 Subject: [PATCH 01/16] seat: Add API for keyrouter The keyrouter module which lives in libds-tizen project needs to send keyboard key events to several wl_clients according to its policy. To support this functionality, this patch implements related API. Among them, the notable API is ds_seat_client_send_key() which enables keyrouter to send keyboard key events to non-focused wl_client. Change-Id: I8cfd47d6ed6536163d0eb1bb0102fb102d78afd9 --- include/libds/seat.h | 14 ++++++++++++++ src/seat/seat.c | 20 ++++++++++++++++++++ src/seat/seat_keyboard.c | 24 +++++++++++++++++++----- src/seat/seat_private.h | 3 +++ 4 files changed, 56 insertions(+), 5 deletions(-) diff --git a/include/libds/seat.h b/include/libds/seat.h index 928861d..8790bf9 100644 --- a/include/libds/seat.h +++ b/include/libds/seat.h @@ -10,6 +10,8 @@ struct ds_seat; +struct ds_seat_client; + enum ds_axis_orientation { DS_AXIS_ORIENTATION_VERTICAL, @@ -100,6 +102,15 @@ void ds_seat_set_keyboard(struct ds_seat *seat, struct ds_input_device *device); void ds_seat_add_destroy_listener(struct ds_seat *seat, struct wl_listener *listener); +struct ds_seat_client *ds_seat_client_for_wl_client(struct ds_seat *seat, + struct wl_client *wl_client); + +void ds_seat_client_add_destroy_listener(struct ds_seat_client *seat_client, + struct wl_listener *listener); + +void ds_seat_client_send_key(struct ds_seat_client *seat_client, + uint32_t time_msec, uint32_t key, uint32_t state); + void ds_seat_pointer_notify_enter(struct ds_seat *seat, struct ds_surface *surface, double sx, double sy); @@ -164,6 +175,9 @@ void ds_seat_keyboard_add_grab_end_listener(struct ds_seat *seat, void ds_seat_keyboard_add_focus_change_listener(struct ds_seat *seat, struct wl_listener *listener); +struct ds_seat_client * +ds_seat_keyboard_get_focused_client(struct ds_seat *seat); + void ds_seat_touch_end_grab_start_listener(struct ds_seat *seat, struct wl_listener *listener); diff --git a/src/seat/seat.c b/src/seat/seat.c index 51d5c23..bec9059 100644 --- a/src/seat/seat.c +++ b/src/seat/seat.c @@ -136,6 +136,26 @@ ds_seat_add_destroy_listener(struct ds_seat *seat, wl_signal_add(&seat->events.destroy, listener); } +WL_EXPORT void +ds_seat_client_send_key(struct ds_seat_client *seat_client, + uint32_t time_msec, uint32_t key, uint32_t state) +{ + seat_client_send_key(seat_client, time_msec, key, state); +} + +WL_EXPORT struct ds_seat_client * +ds_seat_client_for_wl_client(struct ds_seat *seat, struct wl_client *wl_client) +{ + return seat_client_for_wl_client(seat, wl_client); +} + +WL_EXPORT void +ds_seat_client_add_destroy_listener(struct ds_seat_client *seat_client, + struct wl_listener *listener) +{ + wl_signal_add(&seat_client->events.destroy, listener); +} + struct ds_seat_client * seat_client_for_wl_client(struct ds_seat *seat, struct wl_client *wl_client) { diff --git a/src/seat/seat_keyboard.c b/src/seat/seat_keyboard.c index 4846711..de2d3df 100644 --- a/src/seat/seat_keyboard.c +++ b/src/seat/seat_keyboard.c @@ -30,6 +30,12 @@ static void seat_keyboard_handle_keymap(struct wl_listener *listener, static void seat_keyboard_handle_repeat_info(struct wl_listener *listener, void *data); +WL_EXPORT struct ds_seat_client * +ds_seat_keyboard_get_focused_client(struct ds_seat *seat) +{ + return seat->keyboard.focused_client; +} + WL_EXPORT void ds_seat_set_keyboard(struct ds_seat *seat, struct ds_input_device *device) { @@ -257,16 +263,12 @@ ds_seat_keyboard_send_key(struct ds_seat *seat, uint32_t time_msec, uint32_t key, uint32_t state) { struct ds_seat_client *seat_client; - struct wl_resource *resource; - uint32_t serial; seat_client = seat->keyboard.focused_client; if (!seat_client) return; - serial = wl_display_next_serial(seat->display); - wl_resource_for_each(resource, &seat_client->keyboards) - wl_keyboard_send_key(resource, serial, time_msec, key, state); + seat_client_send_key(seat_client, time_msec, key, state); } void @@ -369,6 +371,18 @@ seat_client_remove_all_keyboard_resources(struct ds_seat_client *seat_client) } } +void +seat_client_send_key(struct ds_seat_client *seat_client, uint32_t time_msec, + uint32_t key, uint32_t state) +{ + struct wl_resource *resource; + uint32_t serial; + + serial = wl_display_next_serial(seat_client->seat->display); + wl_resource_for_each(resource, &seat_client->keyboards) + wl_keyboard_send_key(resource, serial, time_msec, key, state); +} + static void keyboard_handle_release(struct wl_client *client, struct wl_resource *resource) { diff --git a/src/seat/seat_private.h b/src/seat/seat_private.h index eeaa6ba..7a3bda6 100644 --- a/src/seat/seat_private.h +++ b/src/seat/seat_private.h @@ -173,4 +173,7 @@ void seat_client_add_touch_resource(struct ds_seat_client *seat_client, void seat_client_remove_all_touch_resources(struct ds_seat_client *seat_client); +void seat_client_send_key(struct ds_seat_client *seat_client, + uint32_t time_msec, uint32_t key, uint32_t state); + #endif -- 2.7.4 From 40cf90b0e2ab998038d6e72640cd5f3fba718f4d Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Tue, 12 Jul 2022 10:17:10 +0900 Subject: [PATCH 02/16] xdg_shell_v6: Remove 'xdg-shell-unstable-v6-server' dependency The rpm package 'xdg-shell-unstable-v6-server' isn't always provided on every platform. So, this patch generates code and header from wayland-protocols using wayland-scanner. Change-Id: I8dc7e751b1f9a2d2c02fb339efd2d620dfb63f7a --- packaging/libds.spec | 1 - src/xdg_shell_v6/meson.build | 21 ++++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packaging/libds.spec b/packaging/libds.spec index 13d59cf..ac79499 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -11,7 +11,6 @@ BuildRequires: meson BuildRequires: pkgconfig(wayland-server) BuildRequires: pkgconfig(wayland-client) BuildRequires: pkgconfig(wayland-protocols) -BuildRequires: pkgconfig(xdg-shell-unstable-v6-server) BuildRequires: pkgconfig(pixman-1) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(xkbcommon) diff --git a/src/xdg_shell_v6/meson.build b/src/xdg_shell_v6/meson.build index 55c9b85..d584968 100644 --- a/src/xdg_shell_v6/meson.build +++ b/src/xdg_shell_v6/meson.build @@ -4,9 +4,28 @@ libds_xdg_shell_v6_files = [ 'xdg_toplevel_v6.c', ] +protocol_name = 'xdg-shell-v6' +protocol_path = wl_protocol_dir / 'unstable/xdg-shell/xdg-shell-unstable-v6.xml' + +code = custom_target( + protocol_name.underscorify() + '_c', + input: protocol_path, + output: '@BASENAME@-protocol.c', + command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], +) +libds_xdg_shell_v6_files += code + +server_header = custom_target( + protocol_name.underscorify() + '_server_h', + input: protocol_path, + output: '@BASENAME@-server-protocol.h', + command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'], + build_by_default: false, +) +libds_xdg_shell_v6_files += server_header + libds_xdg_shell_v6_deps = [ dep_libds, - dependency('xdg-shell-unstable-v6-server', required: true), ] lib_libds_xdg_shell_v6 = shared_library('ds-xdg-shell-v6', libds_xdg_shell_v6_files, -- 2.7.4 From 42a84868ccac3a2bc2fbe7e08ad90837f5b63805 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 13 Jul 2022 12:09:31 +0900 Subject: [PATCH 03/16] tinyds: Notify button event of pointer Change-Id: Ie4ec66d5823978fa3a04b3cafa7dbc95ce8fdd38 --- examples/tinyds.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/tinyds.c b/examples/tinyds.c index 0e25462..26c08c5 100644 --- a/examples/tinyds.c +++ b/examples/tinyds.c @@ -405,6 +405,9 @@ pointer_handle_button(struct wl_listener *listener, void *data) pointer, event->button, (event->state == DS_BUTTON_PRESSED) ? "Pressed" : "Released", event->time_msec); + + ds_seat_pointer_notify_button(pointer->server->seat, event->time_msec, + event->button, event->state); } static void -- 2.7.4 From 49b6ebc6df66cb1b79f64af36b082c4ebb8b7620 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 13 Jul 2022 12:18:21 +0900 Subject: [PATCH 04/16] backend-wayland: Fix using uninitialized data Change-Id: Ia37e244b20dbc8f715d17c86ba92385571b5873f --- src/backend/wayland/output.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/backend/wayland/output.c b/src/backend/wayland/output.c index 7728abf..a5b7c12 100644 --- a/src/backend/wayland/output.c +++ b/src/backend/wayland/output.c @@ -229,6 +229,12 @@ create_wl_buffer(struct ds_wl_backend *backend, struct ds_buffer *ds_buffer) if (ds_buffer_get_shm(ds_buffer, &shm)) { wl_buffer = import_shm(backend, &shm); } + else { + return NULL; + } + + if (!wl_buffer) + return NULL; buffer = calloc(1, sizeof *buffer); if (!buffer) { -- 2.7.4 From df6e36f175d31ee3fb07e5d55389e880315c6e0b Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 13 Jul 2022 12:50:08 +0900 Subject: [PATCH 05/16] region: Remove unreachable code And this also adds an assert when unknown transform is given. Change-Id: Ic2e9b01ce2106f02f4a4032f2125a8fa9153ae54 --- src/region.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/region.c b/src/region.c index 92fe003..966fc1a 100644 --- a/src/region.c +++ b/src/region.c @@ -63,14 +63,6 @@ ds_region_transform(pixman_region32_t *dst, pixman_region32_t *src, for (i = 0; i < nrects; i++) { switch (transform) { - default: - ds_err("Unkown transform value(%d)", transform); - case WL_OUTPUT_TRANSFORM_NORMAL: - dst_rects[i].x1 = src_rects[i].x1; - dst_rects[i].y1 = src_rects[i].y1; - dst_rects[i].x2 = src_rects[i].x2; - dst_rects[i].y2 = src_rects[i].y2; - break; case WL_OUTPUT_TRANSFORM_90: dst_rects[i].x1 = height - src_rects[i].y2; dst_rects[i].y1 = src_rects[i].x1; @@ -113,6 +105,10 @@ ds_region_transform(pixman_region32_t *dst, pixman_region32_t *src, dst_rects[i].x2 = height - src_rects[i].y1; dst_rects[i].y2 = width - src_rects[i].x1; break; + default: + ds_err("Unkown transform value(%d)", transform); + assert(0 && "Cannot reach here"); + break; } } -- 2.7.4 From b403f9e0dc4417ee545b15b2ff559eb69c76828a Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 13 Jul 2022 13:42:09 +0900 Subject: [PATCH 06/16] shm: Use snprintf() instead of vulnerable strcat() Change-Id: I0c7a2dd640993387dcaf1bf8f1db0eae593b4030 --- src/util/shm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/util/shm.c b/src/util/shm.c index 4abd229..4c94b79 100644 --- a/src/util/shm.c +++ b/src/util/shm.c @@ -25,6 +25,7 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include #include #include @@ -119,6 +120,7 @@ allocate_shm_file(off_t size) static const char template[] = "/weston-shared-XXXXXX"; const char *path; char *name; + size_t name_size; int fd; int ret; @@ -141,12 +143,12 @@ allocate_shm_file(off_t size) return -1; } - name = malloc(strlen(path) + sizeof(template)); + name_size = strlen(path) + sizeof(template); + name = malloc(name_size); if (!name) return -1; - strcpy(name, path); - strcat(name, template); + snprintf(name, name_size, "%s%s", path, template); fd = create_tmpfile_cloexec(name); -- 2.7.4 From 23f35d7ce1effbc7d0dd00ea386ae6c514578849 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 13 Jul 2022 13:50:19 +0900 Subject: [PATCH 07/16] xdg_shell, xdg_shell_v6: Remove unreachable code Change-Id: I2ffdb8d385f5cfc07b272505e134f04b16bd7859 --- src/xdg_shell/xdg_surface.c | 6 +++--- src/xdg_shell_v6/xdg_surface_v6.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/xdg_shell/xdg_surface.c b/src/xdg_shell/xdg_surface.c index 1e1654e..35ca7a7 100644 --- a/src/xdg_shell/xdg_surface.c +++ b/src/xdg_shell/xdg_surface.c @@ -396,14 +396,14 @@ xdg_surface_handle_ack_configure(struct wl_client *client, } switch (surface->role) { - case DS_XDG_SURFACE_ROLE_NONE: - assert(0 && "not reached"); - break; case DS_XDG_SURFACE_ROLE_TOPLEVEL: // TODO break; case DS_XDG_SURFACE_ROLE_POPUP: break; + default: + assert(0 && "not reached"); + break; } surface->configured = true; diff --git a/src/xdg_shell_v6/xdg_surface_v6.c b/src/xdg_shell_v6/xdg_surface_v6.c index 69ab595..487ad45 100644 --- a/src/xdg_shell_v6/xdg_surface_v6.c +++ b/src/xdg_shell_v6/xdg_surface_v6.c @@ -402,14 +402,14 @@ xdg_surface_v6_handle_ack_configure(struct wl_client *client, } switch (surface->role) { - case DS_XDG_SURFACE_V6_ROLE_NONE: - assert(0 && "not reached"); - break; case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL: // TODO break; case DS_XDG_SURFACE_V6_ROLE_POPUP: break; + default: + assert(0 && "not reached"); + break; } surface->configured = true; -- 2.7.4 From c4ff64cb4f183f7ca78acb5e0972d6048bf463b3 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 13 Jul 2022 14:05:47 +0900 Subject: [PATCH 08/16] buffer: Add null check after wl_array_add() Change-Id: Id5047a9df1418069bd568a44dc702f13fcc509e7 --- src/buffer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/buffer.c b/src/buffer.c index 60b9925..86e7211 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -166,6 +166,11 @@ ds_buffer_register_resource_interface( } iface_ptr = wl_array_add(&buffer_resource_interfaces, sizeof(iface)); + if (!iface_ptr) { + ds_err("Could not allocate memory"); + return; + } + *iface_ptr = iface; } -- 2.7.4 From c16fa62c52a4b27ffa2a21472db0b1951f2fa95b Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EC=9D=B4=EC=8A=B9=ED=9B=88/Tizen=20Platform=20Lab=28SR=29/?= =?utf8?q?=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 13 Jul 2022 14:16:56 +0900 Subject: [PATCH 09/16] Fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Change-Id: Iafd3e13c80569e9468b894156d52920eb63c2e6f Co-authored-by: 코드리뷰봇/Quality Tool Lab(SR)/삼성전자 --- src/region.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/region.c b/src/region.c index 966fc1a..8fca28d 100644 --- a/src/region.c +++ b/src/region.c @@ -106,7 +106,7 @@ ds_region_transform(pixman_region32_t *dst, pixman_region32_t *src, dst_rects[i].y2 = width - src_rects[i].x1; break; default: - ds_err("Unkown transform value(%d)", transform); + ds_err("Unknown transform value(%d)", transform); assert(0 && "Cannot reach here"); break; } -- 2.7.4 From b54c36624274575cdcfad7750b4bcfb2ffcedadd Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 11 Jul 2022 11:36:50 +0900 Subject: [PATCH 10/16] seat: Fix dangling focused_client in keyboard This patch handles destroy signal of focused_client of keyboard, and also contains a bit of refactoring. Change-Id: I54473c3e37c770e4889066dba283fe65dc3751cd --- src/seat/seat.c | 9 ++ src/seat/seat_keyboard.c | 228 +++++++++++++++++++++++++++++++---------------- src/seat/seat_private.h | 4 + 3 files changed, 164 insertions(+), 77 deletions(-) diff --git a/src/seat/seat.c b/src/seat/seat.c index bec9059..36ed366 100644 --- a/src/seat/seat.c +++ b/src/seat/seat.c @@ -169,6 +169,15 @@ seat_client_for_wl_client(struct ds_seat *seat, struct wl_client *wl_client) return NULL; } +struct ds_seat_client * +seat_client_from_surface(struct ds_seat *seat, struct ds_surface *surface) +{ + struct wl_client *wl_client; + + wl_client = wl_resource_get_client(ds_surface_get_wl_resource(surface)); + return seat_client_for_wl_client(seat, wl_client); +} + static struct ds_seat_client * ds_seat_client_get_or_create(struct ds_seat *seat, struct wl_client *wl_client) { diff --git a/src/seat/seat_keyboard.c b/src/seat/seat_keyboard.c index de2d3df..9ebe17c 100644 --- a/src/seat/seat_keyboard.c +++ b/src/seat/seat_keyboard.c @@ -17,18 +17,28 @@ static void seat_client_send_keymap(struct ds_seat_client *seat_client, struct ds_keyboard *ds_keyboard); static void seat_client_send_repeat_info(struct ds_seat_client *seat_client, struct ds_keyboard *ds_keyboard); -static void seat_keyboard_handle_surface_destroy(struct wl_listener *listener, - void *data); static void keyboard_handle_resource_destroy(struct wl_resource *resource); static void seat_keyboard_set_keyboard(struct ds_seat_keyboard *keyboard, struct ds_input_device *device); static void seat_keyboard_unset_keyboard(struct ds_seat_keyboard *keyboard); +static void seat_keyboard_handle_surface_destroy(struct wl_listener *listener, + void *data); +static void seat_keyboard_handle_client_destroy(struct wl_listener *listener, + void *data); static void seat_keyboard_handle_keyboard_destroy(struct wl_listener *listener, void *data); static void seat_keyboard_handle_keymap(struct wl_listener *listener, void *data); static void seat_keyboard_handle_repeat_info(struct wl_listener *listener, void *data); +static void seat_keyboard_clear_focus(struct ds_seat_keyboard *keyboard); +static void seat_keyboard_set_focus_surface(struct ds_seat_keyboard *keyboard, + struct ds_surface *surface, uint32_t keycodes[], size_t num_keycodes, + struct ds_keyboard_modifiers *modifiers); +static void +seat_keyboard_unset_focus_surface(struct ds_seat_keyboard *keyboard); +static void seat_keyboard_emit_focus_change(struct ds_seat_keyboard *keyboard, + struct ds_surface *old_surface, struct ds_surface *new_surface); WL_EXPORT struct ds_seat_client * ds_seat_keyboard_get_focused_client(struct ds_seat *seat) @@ -181,81 +191,29 @@ ds_seat_keyboard_enter(struct ds_seat *seat, struct ds_surface *surface, struct ds_keyboard_modifiers *modifiers) { struct ds_seat_keyboard *keyboard = &seat->keyboard; - struct ds_seat_client *seat_client = NULL, *focused_client; - struct ds_surface *focused_surface; - struct wl_client *wl_client; - struct wl_array keys; - struct wl_resource *resource; - uint32_t *p; - uint32_t serial; + struct ds_surface *focused_surface = keyboard->focused_surface; - if (keyboard->focused_surface == surface) + if (focused_surface == surface) return; - if (surface) { - wl_client = - wl_resource_get_client(ds_surface_get_wl_resource(surface)); - seat_client = seat_client_for_wl_client(seat, wl_client); - } - - focused_client = keyboard->focused_client; - focused_surface = keyboard->focused_surface; - - if (focused_client != NULL && focused_surface != NULL) - seat_client_send_keyboard_leave_raw(focused_client, focused_surface); - - if (seat_client) { - wl_array_init(&keys); - - for (size_t i = 0; i < num_keycodes; i++) { - p = wl_array_add(&keys, sizeof(uint32_t)); - if (!p) { - ds_err("Cannot allocate memory, skipping keycode: %" PRIu32 - "\n", keycodes[i]); - continue; - } - *p = keycodes[i]; - } - - serial = wl_display_next_serial(seat->display); - - wl_resource_for_each(resource, &seat_client->keyboards) { - wl_keyboard_send_enter(resource, serial, - ds_surface_get_wl_resource(surface), &keys); - } - wl_array_release(&keys); - } - - wl_list_remove(&keyboard->surface_destroy.link); - wl_list_init(&keyboard->surface_destroy.link); + seat_keyboard_unset_focus_surface(keyboard); if (surface) { - keyboard->surface_destroy.notify = - seat_keyboard_handle_surface_destroy; - ds_surface_add_destroy_listener(surface, &keyboard->surface_destroy); + seat_keyboard_set_focus_surface(keyboard, surface, + keycodes, num_keycodes, modifiers); } - keyboard->focused_client = seat_client; - keyboard->focused_surface = surface; + ds_seat_keyboard_send_modifiers(seat, modifiers); - if (seat_client) { - ds_seat_keyboard_send_modifiers(seat, modifiers); + // TODO handle selection - // TODO handle selection - } - - struct ds_event_seat_keyboard_focus_change event = { - .seat = seat, - .old_surface = focused_surface, - .new_surface = surface, - }; - wl_signal_emit(&keyboard->events.focus_change, &event); + seat_keyboard_emit_focus_change(keyboard, focused_surface, surface); } void ds_seat_keyboard_clear_focus(struct ds_seat *seat) { - ds_seat_keyboard_enter(seat, NULL, NULL, 0, NULL); + seat_keyboard_clear_focus(&seat->keyboard); } void @@ -313,8 +271,14 @@ seat_keyboard_init(struct ds_seat *seat) keyboard->grab = grab; keyboard->seat = seat; + keyboard->surface_destroy.notify = + seat_keyboard_handle_surface_destroy; wl_list_init(&keyboard->surface_destroy.link); + keyboard->client_destroy.notify = + seat_keyboard_handle_client_destroy; + wl_list_init(&keyboard->client_destroy.link); + wl_signal_init(&keyboard->events.focus_change); return true; @@ -324,7 +288,12 @@ void seat_keyboard_finish(struct ds_seat *seat) { struct ds_seat_keyboard *keyboard = &seat->keyboard; - wl_list_remove(&keyboard->surface_destroy.link); + if (keyboard->focused_client) + wl_list_remove(&keyboard->client_destroy.link); + + if (keyboard->focused_surface) + wl_list_remove(&keyboard->surface_destroy.link); + free(keyboard->default_grab); } @@ -447,6 +416,37 @@ static const struct ds_keyboard_grab_interface default_keyboard_grab_iface = { }; static void +seat_client_send_keyboard_enter_raw(struct ds_seat_client *seat_client, + struct ds_surface *surface, uint32_t keycodes[], size_t num_keycodes, + struct ds_keyboard_modifiers *modifiers) +{ + struct wl_resource *resource; + struct wl_array keys; + uint32_t *p; + uint32_t serial; + + wl_array_init(&keys); + + for (size_t i = 0; i < num_keycodes; i++) { + p = wl_array_add(&keys, sizeof(uint32_t)); + if (!p) { + ds_err("Cannot allocate memory, skipping keycode: %" PRIu32 + "\n", keycodes[i]); + continue; + } + *p = keycodes[i]; + } + + serial = wl_display_next_serial(seat_client->seat->display); + + wl_resource_for_each(resource, &seat_client->keyboards) { + wl_keyboard_send_enter(resource, serial, + ds_surface_get_wl_resource(surface), &keys); + } + wl_array_release(&keys); +} + +static void seat_client_send_keyboard_leave_raw(struct ds_seat_client *seat_client, struct ds_surface *surface) { @@ -498,19 +498,6 @@ seat_client_send_repeat_info(struct ds_seat_client *seat_client, } static void -seat_keyboard_handle_surface_destroy(struct wl_listener *listener, - void *data) -{ - struct ds_seat_keyboard *keyboard; - - keyboard = wl_container_of(listener, keyboard, surface_destroy); - - wl_list_remove(&keyboard->surface_destroy.link); - wl_list_init(&keyboard->surface_destroy.link); - ds_seat_keyboard_clear_focus(keyboard->seat); -} - -static void seat_keyboard_set_keyboard(struct ds_seat_keyboard *keyboard, struct ds_input_device *device) { @@ -578,3 +565,90 @@ seat_keyboard_handle_repeat_info(struct wl_listener *listener, wl_list_for_each(seat_client, &keyboard->seat->clients, link) seat_client_send_repeat_info(seat_client, keyboard->ds_keyboard); } + +static void +seat_keyboard_clear_focus(struct ds_seat_keyboard *keyboard) +{ + struct ds_surface *focused_surface = keyboard->focused_surface; + + seat_keyboard_unset_focus_surface(keyboard); + + if (focused_surface) + seat_keyboard_emit_focus_change(keyboard, focused_surface, NULL); +} + +static void +seat_keyboard_set_focus_surface(struct ds_seat_keyboard *keyboard, + struct ds_surface *surface, uint32_t keycodes[], size_t num_keycodes, + struct ds_keyboard_modifiers *modifiers) +{ + struct ds_seat *seat = keyboard->seat; + struct ds_seat_client *seat_client; + + seat_client = seat_client_from_surface(seat, surface); + if (seat_client) { + seat_client_send_keyboard_enter_raw(seat_client, surface, + keycodes, num_keycodes, modifiers); + + wl_signal_add(&seat_client->events.destroy, &keyboard->client_destroy); + + keyboard->focused_client = seat_client; + } + + ds_surface_add_destroy_listener(surface, &keyboard->surface_destroy); + + keyboard->focused_surface = surface; +} + +static void +seat_keyboard_unset_focus_surface(struct ds_seat_keyboard *keyboard) +{ + struct ds_seat_client *focused_client = keyboard->focused_client; + struct ds_surface *focused_surface = keyboard->focused_surface; + + if (focused_client) + wl_list_remove(&keyboard->client_destroy.link); + + if (focused_surface) + wl_list_remove(&keyboard->surface_destroy.link); + + if (focused_client != NULL && focused_surface != NULL) + seat_client_send_keyboard_leave_raw(focused_client, focused_surface); + + keyboard->focused_client = NULL; + keyboard->focused_surface = NULL; +} + +static void +seat_keyboard_handle_client_destroy(struct wl_listener *listener, void *data) +{ + struct ds_seat_keyboard *keyboard; + + keyboard = wl_container_of(listener, keyboard, client_destroy); + + wl_list_remove(&keyboard->client_destroy.link); + keyboard->focused_client = NULL; +} + +static void +seat_keyboard_handle_surface_destroy(struct wl_listener *listener, + void *data) +{ + struct ds_seat_keyboard *keyboard; + + keyboard = wl_container_of(listener, keyboard, surface_destroy); + + seat_keyboard_clear_focus(keyboard); +} + +static void +seat_keyboard_emit_focus_change(struct ds_seat_keyboard *keyboard, + struct ds_surface *old_surface, struct ds_surface *new_surface) +{ + struct ds_event_seat_keyboard_focus_change event = { + .seat = keyboard->seat, + .old_surface = old_surface, + .new_surface = new_surface, + }; + wl_signal_emit(&keyboard->events.focus_change, &event); +} diff --git a/src/seat/seat_private.h b/src/seat/seat_private.h index 7a3bda6..0a5cf84 100644 --- a/src/seat/seat_private.h +++ b/src/seat/seat_private.h @@ -62,6 +62,7 @@ struct ds_seat_keyboard struct ds_seat_client *focused_client; struct ds_surface *focused_surface; + struct wl_listener client_destroy; struct wl_listener surface_destroy; struct wl_listener keyboard_destroy; struct wl_listener keymap; @@ -143,6 +144,9 @@ struct ds_seat struct ds_seat_client * seat_client_for_wl_client(struct ds_seat *seat, struct wl_client *wl_client); +struct ds_seat_client * +seat_client_from_surface(struct ds_seat *seat, struct ds_surface *surface); + bool seat_pointer_init(struct ds_seat *seat); void seat_pointer_finish(struct ds_seat *seat); -- 2.7.4 From 5823600e08e5e476837aa298db219ba41d9d15d2 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 11 Jul 2022 12:16:18 +0900 Subject: [PATCH 11/16] seat: Fix dangling focused_client in pointer This patch handles destroy signal of focused_client of pointer, and also contains a bit of refactoring. Change-Id: I091f9b5d580ba6a36e51360d6757dfb434b03eab --- src/seat/seat_pointer.c | 179 ++++++++++++++++++++++++++++++++++-------------- src/seat/seat_private.h | 1 + 2 files changed, 129 insertions(+), 51 deletions(-) diff --git a/src/seat/seat_pointer.c b/src/seat/seat_pointer.c index 2616756..dd9abcf 100644 --- a/src/seat/seat_pointer.c +++ b/src/seat/seat_pointer.c @@ -10,11 +10,23 @@ static const struct wl_pointer_interface pointer_impl; static void seat_pointer_warp(struct ds_seat *seat, double sx, double sy); static void +seat_client_send_pointer_enter_raw(struct ds_seat_client *seat_client, + struct ds_surface *surface, double sx, double sy); +static void seat_client_send_pointer_leave_raw(struct ds_seat_client *seat_client, struct ds_surface *surface); static void +seat_pointer_handle_client_destroy(struct wl_listener *listener, void *data); +static void seat_pointer_handle_surface_destroy(struct wl_listener *listener, void *data); +static void seat_pointer_clear_focus(struct ds_seat_pointer *pointer); +static void seat_pointer_set_focus_surface(struct ds_seat_pointer *pointer, + struct ds_surface *surface, double sx, double sy); +static void seat_pointer_unset_focus_surface(struct ds_seat_pointer *pointer); +static void seat_pointer_emit_focus_change(struct ds_seat_pointer *pointer, + struct ds_surface *old_surface, struct ds_surface *new_surface, + double sx, double sy); static void pointer_handle_resource_destroy(struct wl_resource *resource); static void pointer_send_frame(struct wl_resource *resource); @@ -142,69 +154,31 @@ ds_seat_pointer_enter(struct ds_seat *seat, struct ds_surface *surface, double sx, double sy) { struct ds_seat_pointer *pointer = &seat->pointer; - struct ds_seat_client *seat_client = NULL, *focused_client; - struct ds_surface *focused_surface; - struct wl_client *wl_client; - struct wl_resource *resource; - uint32_t serial; + struct ds_surface *focused_surface = pointer->focused_surface; - if (pointer->focused_surface == surface) { + if (focused_surface == surface) { // this surface already got an enter notify return; } - focused_client = pointer->focused_client; - focused_surface = pointer->focused_surface; - - if (focused_client != NULL && focused_surface != NULL) - seat_client_send_pointer_leave_raw(focused_client, focused_surface); + seat_pointer_unset_focus_surface(pointer); if (surface) { - wl_client = - wl_resource_get_client(ds_surface_get_wl_resource(surface)); - seat_client = seat_client_for_wl_client(seat, wl_client); - } - - if (seat_client) { - serial = wl_display_next_serial(seat->display); - wl_resource_for_each(resource, &seat_client->pointers) { - wl_pointer_send_enter(resource, serial, - ds_surface_get_wl_resource(surface), - wl_fixed_from_double(sx), wl_fixed_from_double(sy)); - pointer_send_frame(resource); - } - } + seat_pointer_set_focus_surface(pointer, surface, sx, sy); - wl_list_remove(&pointer->surface_destroy.link); - wl_list_init(&pointer->surface_destroy.link); - - if (surface) { - pointer->surface_destroy.notify = - seat_pointer_handle_surface_destroy; - ds_surface_add_destroy_listener(surface, &pointer->surface_destroy); - } - - pointer->focused_client = seat_client; - pointer->focused_surface = surface; - if (surface) seat_pointer_warp(seat, sx, sy); - else + } + else { seat_pointer_warp(seat, NAN, NAN); + } - struct ds_event_seat_pointer_focus_change event = { - .seat = seat, - .new_surface = surface, - .old_surface = focused_surface, - .sx = sx, - .sy = sy, - }; - wl_signal_emit(&pointer->events.focus_change, &event); + seat_pointer_emit_focus_change(pointer, focused_surface, surface, sx, sy); } void ds_seat_pointer_clear_focus(struct ds_seat *seat) { - ds_seat_pointer_enter(seat, NULL, 0, 0); + seat_pointer_clear_focus(&seat->pointer); } void @@ -326,6 +300,10 @@ seat_pointer_init(struct ds_seat *seat) pointer->grab = grab; pointer->seat = seat; + pointer->client_destroy.notify = seat_pointer_handle_client_destroy; + wl_list_init(&pointer->client_destroy.link); + + pointer->surface_destroy.notify = seat_pointer_handle_surface_destroy; wl_list_init(&pointer->surface_destroy.link); wl_signal_init(&pointer->events.focus_change); @@ -338,7 +316,12 @@ seat_pointer_finish(struct ds_seat *seat) { struct ds_seat_pointer *pointer = &seat->pointer; - wl_list_remove(&pointer->surface_destroy.link); + if (pointer->focused_client) + wl_list_remove(&pointer->client_destroy.link); + + if (pointer->focused_surface) + wl_list_remove(&pointer->surface_destroy.link); + free(pointer->default_grab); } @@ -385,6 +368,22 @@ seat_pointer_warp(struct ds_seat *seat, double sx, double sy) } static void +seat_client_send_pointer_enter_raw(struct ds_seat_client *seat_client, + struct ds_surface *surface, double sx, double sy) +{ + struct wl_resource *resource; + uint32_t serial; + + serial = wl_display_next_serial(seat_client->seat->display); + wl_resource_for_each(resource, &seat_client->pointers) { + wl_pointer_send_enter(resource, serial, + ds_surface_get_wl_resource(surface), + wl_fixed_from_double(sx), wl_fixed_from_double(sy)); + pointer_send_frame(resource); + } +} + +static void seat_client_send_pointer_leave_raw(struct ds_seat_client *seat_client, struct ds_surface *surface) { @@ -400,14 +399,92 @@ seat_client_send_pointer_leave_raw(struct ds_seat_client *seat_client, } static void +seat_pointer_handle_client_destroy(struct wl_listener *listener, void *data) +{ + struct ds_seat_pointer *pointer; + + pointer = wl_container_of(listener, pointer, client_destroy); + + wl_list_remove(&pointer->client_destroy.link); + pointer->focused_client = NULL; +} + +static void seat_pointer_handle_surface_destroy(struct wl_listener *listener, void *data) { struct ds_seat_pointer *pointer; pointer = wl_container_of(listener, pointer, surface_destroy); - wl_list_remove(&pointer->surface_destroy.link); - wl_list_init(&pointer->surface_destroy.link); - ds_seat_pointer_clear_focus(pointer->seat); + + seat_pointer_clear_focus(pointer); +} + +static void +seat_pointer_clear_focus(struct ds_seat_pointer *pointer) +{ + struct ds_surface *focused_surface = pointer->focused_surface; + + seat_pointer_unset_focus_surface(pointer); + + seat_pointer_warp(pointer->seat, NAN, NAN); + + if (focused_surface) + seat_pointer_emit_focus_change(pointer, focused_surface, NULL, 0, 0); +} + +static void +seat_pointer_set_focus_surface(struct ds_seat_pointer *pointer, + struct ds_surface *surface, double sx, double sy) +{ + struct ds_seat *seat = pointer->seat; + struct ds_seat_client *seat_client; + + seat_client = seat_client_from_surface(seat, surface); + if (seat_client) { + seat_client_send_pointer_enter_raw(seat_client, surface, sx, sy); + + wl_signal_add(&seat_client->events.destroy, &pointer->client_destroy); + + pointer->focused_client = seat_client; + } + + ds_surface_add_destroy_listener(surface, &pointer->surface_destroy); + + pointer->focused_surface = surface; +} + +static void +seat_pointer_unset_focus_surface(struct ds_seat_pointer *pointer) +{ + struct ds_seat_client *focused_client = pointer->focused_client; + struct ds_surface *focused_surface = pointer->focused_surface; + + if (focused_client) + wl_list_remove(&pointer->client_destroy.link); + + if (focused_surface) + wl_list_remove(&pointer->surface_destroy.link); + + if (focused_client != NULL && focused_surface != NULL) + seat_client_send_pointer_leave_raw(focused_client, focused_surface); + + pointer->focused_client = NULL; + pointer->focused_surface = NULL; +} + +static void +seat_pointer_emit_focus_change(struct ds_seat_pointer *pointer, + struct ds_surface *old_surface, struct ds_surface *new_surface, + double sx, double sy) +{ + struct ds_event_seat_pointer_focus_change event = { + .seat = pointer->seat, + .new_surface = new_surface, + .old_surface = old_surface, + .sx = sx, + .sy = sy, + }; + wl_signal_emit(&pointer->events.focus_change, &event); } static void diff --git a/src/seat/seat_private.h b/src/seat/seat_private.h index 0a5cf84..0211a72 100644 --- a/src/seat/seat_private.h +++ b/src/seat/seat_private.h @@ -47,6 +47,7 @@ struct ds_seat_pointer uint32_t grab_serial; uint32_t grab_time; + struct wl_listener client_destroy; struct wl_listener surface_destroy; struct { -- 2.7.4 From 187261b8152c80362ab7702dd58300e300513434 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 13 Jul 2022 15:39:36 +0900 Subject: [PATCH 12/16] build: Set default warning_level=3 This patch suppresses 'unused-parameter' and 'pedantic' GCC warnings that we don't care about. After suppressing these warnings, we can now enable the highest warning_level by default. Change-Id: I4402766a5cdabd6984582c17805c41c1f8a66645 --- meson.build | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index be7d520..03d6bc7 100644 --- a/meson.build +++ b/meson.build @@ -2,12 +2,26 @@ project('libds', 'c', license: 'MIT', version: '0.1.2', default_options: [ - 'warning_level=1', + 'warning_level=3', 'c_std=gnu99', 'buildtype=debug' ] ) +cc = meson.get_compiler('c') + +global_args = [] +global_args_maybe = [ + '-Wno-unused-parameter', + '-Wno-pedantic', +] +foreach a : global_args_maybe + if cc.has_argument(a) + global_args += a + endif +endforeach +add_global_arguments(global_args, language: 'c') + libds_version = meson.project_version() version_arr = libds_version.split('.') libds_version_major = version_arr[0] @@ -43,4 +57,4 @@ subdir('examples') subdir('clients') subdir('include') -configure_file(output: 'config.h', install: false, configuration: cdata) \ No newline at end of file +configure_file(output: 'config.h', install: false, configuration: cdata) -- 2.7.4 From 171bcf35e2a5f30f02dc2babb04d6e3450e1bdd6 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Jul 2022 18:25:12 +0900 Subject: [PATCH 13/16] output: Add ds_output_{create,destroy}_global() This adds wl_output globals for ds_outputs. Change-Id: I946206f33eeb00f484731767ce1b836b46b62947 --- include/libds/interfaces/output.h | 18 +++ src/output.c | 242 +++++++++++++++++++++++++++++++++++++- 2 files changed, 258 insertions(+), 2 deletions(-) diff --git a/include/libds/interfaces/output.h b/include/libds/interfaces/output.h index 53a4e0c..2c99b82 100644 --- a/include/libds/interfaces/output.h +++ b/include/libds/interfaces/output.h @@ -40,8 +40,12 @@ struct ds_output_state enum ds_output_state_field committed; struct ds_buffer *buffer; + enum wl_output_transform transform; enum ds_output_state_mode_type mode_type; const struct ds_output_mode *mode; + + float scale; + struct { int32_t width, height; int32_t refresh; // mHz, may be zero @@ -58,6 +62,18 @@ struct ds_output struct wl_display *display; struct wl_global *global; + struct wl_list resources; + + char name[24]; + char *description; + char make[56]; + char model[16]; + char serial[16]; + int32_t phys_width, phys_height; // mm + + float scale; + enum wl_output_transform transform; + enum wl_output_subpixel subpixel; struct ds_buffer *back_buffer, *front_buffer; const struct ds_output_mode *current_mode; @@ -65,6 +81,8 @@ struct ds_output int32_t refresh; // mHz, may be zero struct ds_output_state pending; + struct wl_event_source *idle_done; + struct wl_list modes; struct wl_listener display_destroy; diff --git a/src/output.c b/src/output.c index d5af56e..31cb068 100644 --- a/src/output.c +++ b/src/output.c @@ -5,12 +5,24 @@ #include "libds/output.h" #include "libds/interfaces/output.h" +#define OUTPUT_VERSION 3 + static void output_handle_display_destroy(struct wl_listener *listener, void *data); static void output_enable(struct ds_output *output, bool enable); static void output_state_clear(struct ds_output_state *state); static void output_state_clear_buffer(struct ds_output_state *state); static void output_state_clear_mode(struct ds_output_state *state); +static void output_destroy_global(struct ds_output *output); +static void output_bind(struct wl_client *client, void *data, uint32_t version, + uint32_t id); +static void output_handle_resource_destroy(struct wl_resource *resource); +static void output_schedule_done(struct ds_output *output); +static void output_handle_idle_done(void *data); +static void send_geometry(struct wl_resource *resource); +static void send_current_mode(struct wl_resource *resource); +static void send_scale(struct wl_resource *resource); +static void send_done(struct wl_resource *resource); WL_EXPORT void ds_output_init(struct ds_output *output, struct ds_backend *backend, @@ -37,8 +49,13 @@ ds_output_destroy(struct ds_output *output) { wl_list_remove(&output->display_destroy.link); + output_destroy_global(output); + wl_signal_emit(&output->events.destroy, output); + if (output->idle_done) + wl_event_source_remove(output->idle_done); + if (output->iface && output->iface->destroy) output->iface->destroy(output); else @@ -60,12 +77,40 @@ ds_output_disable(struct ds_output *output) WL_EXPORT bool ds_output_commit(struct ds_output *output) { + struct wl_resource *resource; + bool scale_updated; + bool geometry_updated; + // TODO signal precommit if (!output->iface->commit(output)) { return false; } + scale_updated = output->pending.committed & DS_OUTPUT_STATE_SCALE; + if (scale_updated) { + output->scale = output->pending.scale; + } + + if (output->pending.committed & DS_OUTPUT_STATE_TRANSFORM) { + output->transform = output->pending.transform; + // TODO update matrix + } + + geometry_updated = output->pending.committed & + (DS_OUTPUT_STATE_MODE | DS_OUTPUT_STATE_TRANSFORM); + if (geometry_updated || scale_updated) { + wl_resource_for_each(resource, &output->resources) { + if (geometry_updated) { + send_geometry(resource); + } + if (scale_updated) { + send_scale(resource); + } + } + output_schedule_done(output); + } + output_state_clear(&output->pending); // TODO signal commit @@ -130,6 +175,24 @@ ds_output_set_custom_mode(struct ds_output *output, } WL_EXPORT void +ds_output_create_global(struct ds_output *output) +{ + if (output->global) + return; + + output->global = wl_global_create(output->display, + &wl_output_interface, OUTPUT_VERSION, output, output_bind); + if (!output->global) + ds_err("Failed to allocate wl_output global"); +} + +WL_EXPORT void +ds_output_destroy_global(struct ds_output *output) +{ + output_destroy_global(output); +} + +WL_EXPORT void ds_output_add_destroy_listener(struct ds_output *output, struct wl_listener *listener) { @@ -150,6 +213,31 @@ ds_output_add_commit_listener(struct ds_output *output, wl_signal_add(&output->events.commit, listener); } +WL_EXPORT void +ds_output_set_transform(struct ds_output *output, + enum wl_output_transform transform) +{ + if (output->transform == transform) { + output->pending.committed &= ~DS_OUTPUT_STATE_TRANSFORM; + return; + } + + output->pending.committed |= DS_OUTPUT_STATE_TRANSFORM; + output->pending.transform = transform; +} + +WL_EXPORT void +ds_output_set_scale(struct ds_output *output, float scale) +{ + if (output->scale == scale) { + output->pending.committed &= ~DS_OUTPUT_STATE_SCALE; + return; + } + + output->pending.committed |= DS_OUTPUT_STATE_SCALE; + output->pending.scale = scale; +} + void ds_output_update_custom_mode(struct ds_output *output, int32_t width, int32_t height, int32_t refresh) @@ -163,14 +251,30 @@ ds_output_update_custom_mode(struct ds_output *output, output->refresh = refresh; } +void +ds_output_set_subpixel(struct ds_output *output, + enum wl_output_subpixel subpixel) +{ + struct wl_resource *resource; + + if (output->subpixel == subpixel) + return; + + output->subpixel = subpixel; + + wl_resource_for_each(resource, &output->resources) + send_geometry(resource); + + output_schedule_done(output); +} + static void output_handle_display_destroy(struct wl_listener *listener, void *data) { struct ds_output *output; output = wl_container_of(listener, output, display_destroy); - // TODO - // destroy wl_global + output_destroy_global(output); } static void @@ -213,3 +317,137 @@ output_state_clear_mode(struct ds_output_state *state) state->mode = NULL; state->committed &= ~DS_OUTPUT_STATE_MODE; } + +static void +output_destroy_global(struct ds_output *output) +{ + struct wl_resource *resource, *tmp; + + if (!output->global) + return; + + wl_resource_for_each_safe(resource, tmp, &output->resources) { + wl_resource_set_user_data(resource, NULL); + wl_list_remove(wl_resource_get_link(resource)); + } + + wl_global_destroy(output->global); + output->global = NULL; +} + +static const struct wl_output_interface output_impl; + +static void +output_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + struct ds_output *output = data; + struct wl_resource *resource; + + resource = wl_resource_create(client, &wl_output_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &output_impl, output, + output_handle_resource_destroy); + + wl_list_insert(&output->resources, wl_resource_get_link(resource)); + + send_geometry(resource); + send_current_mode(resource); + send_scale(resource); + send_done(resource); +} + +static void +output_handle_release(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct wl_output_interface output_impl = { + .release = output_handle_release, +}; + +static void +output_handle_resource_destroy(struct wl_resource *resource) +{ + wl_list_remove(wl_resource_get_link(resource)); +} + +static void +output_schedule_done(struct ds_output *output) +{ + struct wl_event_loop *loop; + + if (output->idle_done) + return; + + loop = wl_display_get_event_loop(output->display); + output->idle_done = + wl_event_loop_add_idle(loop, output_handle_idle_done, output); +} + +static void +output_handle_idle_done(void *data) +{ + struct ds_output *output = data; + struct wl_resource *resource; + + wl_resource_for_each(resource, &output->resources) + send_done(resource); + + output->idle_done = NULL; +} + +static void +send_geometry(struct wl_resource *resource) +{ + struct ds_output *output; + + output = wl_resource_get_user_data(resource); + wl_output_send_geometry(resource, 0, 0, + output->phys_width, output->phys_height, output->subpixel, + output->make, output->model, output->transform); +} + +static void +send_current_mode(struct wl_resource *resource) +{ + struct ds_output *output; + const struct ds_output_mode *mode; + + output = wl_resource_get_user_data(resource); + mode = output->current_mode; + if (mode) { + wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT, + mode->width, mode->height, mode->refresh); + } + else { + wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT, + output->width, output->height, output->refresh); + } +} + +static void +send_scale(struct wl_resource *resource) +{ + struct ds_output *output; + uint32_t version; + + output = wl_resource_get_user_data(resource); + version = wl_resource_get_version(resource); + if (version >= WL_OUTPUT_SCALE_SINCE_VERSION) + wl_output_send_scale(resource, (uint32_t)ceil(output->scale)); +} + +static void +send_done(struct wl_resource *resource) +{ + uint32_t version; + + version = wl_resource_get_version(resource); + if (version >= WL_OUTPUT_DONE_SINCE_VERSION) + wl_output_send_done(resource); +} -- 2.7.4 From c2a82498187693157761d1d08c8fa04a71f5ce81 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 3 Aug 2022 13:35:13 +0900 Subject: [PATCH 14/16] keyboard: Fix leak when destroying ds_keyboard Change-Id: I04f6446697d96ac023b23b9e1634580444c384a8 --- src/keyboard.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/keyboard.c b/src/keyboard.c index 72467ee..30668c4 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -260,6 +260,15 @@ ds_keyboard_init(struct ds_keyboard *keyboard, void ds_keyboard_destroy(struct ds_keyboard *keyboard) { + wl_signal_emit(&keyboard->events.destroy, keyboard); + + if (keyboard->keymap) { + close(keyboard->keymap_fd); + free(keyboard->keymap_string); + xkb_state_unref(keyboard->xkb_state); + xkb_keymap_unref(keyboard->keymap); + } + if (keyboard->iface && keyboard->iface->destroy) keyboard->iface->destroy(keyboard); else -- 2.7.4 From b4b70e97f5f97e543ea674a86de171e5446d79da Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 3 Aug 2022 18:53:32 +0900 Subject: [PATCH 15/16] output: Fix crash because of missing wl_list_init() Change-Id: Ia52d2cba5fc01ef998879b07fc4e0cfcaaf92828 --- src/output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/output.c b/src/output.c index 31cb068..1e34c86 100644 --- a/src/output.c +++ b/src/output.c @@ -35,6 +35,7 @@ ds_output_init(struct ds_output *output, struct ds_backend *backend, output->display = display; wl_list_init(&output->modes); + wl_list_init(&output->resources); wl_signal_init(&output->events.destroy); wl_signal_init(&output->events.frame); -- 2.7.4 From 05cf63f890b301033cbd9b1442d53f2b6b7f62c8 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 4 Aug 2022 10:06:17 +0900 Subject: [PATCH 16/16] add libds-tests libds-tests is unit tests using gtest framwork. Change-Id: I323fe81972d8f79018a39b55c820052c090db40c --- meson.build | 7 +++++-- meson_options.txt | 1 + packaging/libds.spec | 3 +++ tests/meson.build | 36 +++++++++++++----------------------- tests/tc_main.cpp | 26 ++++++++++++++++++++++++++ tests/tc_main.h | 12 ++++++++++++ 6 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 tests/tc_main.cpp create mode 100644 tests/tc_main.h diff --git a/meson.build b/meson.build index 03d6bc7..22f625e 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,5 @@ -project('libds', 'c', +project('libds', + ['c', 'cpp'], license: 'MIT', version: '0.1.2', default_options: [ @@ -52,7 +53,9 @@ wayland_scanner = find_program( ) subdir('src') -subdir('tests') +if get_option('tests') + subdir('tests') +endif subdir('examples') subdir('clients') subdir('include') diff --git a/meson_options.txt b/meson_options.txt index e69de29..193594f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -0,0 +1 @@ +option('tests', description: 'Display Server tests', type: 'boolean', value: 'false') diff --git a/packaging/libds.spec b/packaging/libds.spec index ac79499..43071ed 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -16,6 +16,7 @@ BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(xkbcommon) BuildRequires: pkgconfig(libinput) BuildRequires: pkgconfig(libudev) +BuildRequires: pkgconfig(gmock) %description Wayland Compositor Library @@ -52,6 +53,7 @@ meson setup \ --prefix /usr \ --libdir %{_libdir} \ --bindir %{_bindir} \ + -Dtests=true \ builddir ninja -C builddir all @@ -77,6 +79,7 @@ ninja -C builddir install %{_bindir}/input-device-test %{_bindir}/libinput-backend %{_bindir}/ds-simple-shm-shell +%{_bindir}/libds-tests %files xdg-shell-v6 %manifest %{name}.manifest diff --git a/tests/meson.build b/tests/meson.build index dd52176..6314d8a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,25 +1,15 @@ -tests = [ - { 'name': 'test-compositor' }, - { 'name': 'test-backend' }, - { - 'name': 'test-surface', - 'deps': [ dependency('wayland-client') ], - }, - { - 'name': 'test-subsurface', - 'deps': [ dependency('wayland-client') ], - }, +test_files = [ + 'tc_main.cpp', ] -foreach t : tests - t_deps = [ dep_libds ] - t_deps += t.get('deps', []) - - test('libds-' + t.get('name'), - executable('libds-' + t.get('name'), t.get('name') + '.c', - dependencies: t_deps , - include_directories: common_inc, - install: false - ) - ) -endforeach +executable('libds-tests', + test_files, + dependencies: [ + libds_deps, + dependency('gmock', required: true), + dependency('wayland-client', required: true), + dependency('libdrm', required: true), + ], + install_dir: libds_bindir, + install : true +) diff --git a/tests/tc_main.cpp b/tests/tc_main.cpp new file mode 100644 index 0000000..5e99a34 --- /dev/null +++ b/tests/tc_main.cpp @@ -0,0 +1,26 @@ +#include "gmock/gmock.h" + +int +main(int argc, char **argv) +{ + auto AllTestSuccess = false; + + try { + ::testing::InitGoogleMock(&argc, argv); + ::testing::FLAGS_gtest_death_test_style = "fast"; + } catch (...) { + std::cout << "error while trying to init google tests.\n"; + exit(EXIT_FAILURE); + } + + try { + AllTestSuccess = RUN_ALL_TESTS() == 0 ? true : false; + } catch (const ::testing::internal::GoogleTestFailureException &e) { + AllTestSuccess = false; + std::cout << "GoogleTestFailureException was thrown:" << e.what() + << std::endl; + std::cout << "\n"; + } + + return AllTestSuccess; +} diff --git a/tests/tc_main.h b/tests/tc_main.h new file mode 100644 index 0000000..41e630a --- /dev/null +++ b/tests/tc_main.h @@ -0,0 +1,12 @@ +#ifndef TC_MAIN_H +#define TC_MAIN_H + +#include +#include + +using ::testing::Bool; +using ::testing::Combine; +using ::testing::TestWithParam; +using ::testing::Values; + +#endif -- 2.7.4