From c3fc75d89ef6cb50f395eaa93adc0fd28535056d Mon Sep 17 00:00:00 2001 From: Seunghun Date: Mon, 8 Aug 2022 16:15:58 +0900 Subject: [PATCH 01/16] tinyds: Update seat capabilities properly Change-Id: I1c3cee34e5c70bdfc4374f67e56e9d7236b5fda6 --- examples/tinyds.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/examples/tinyds.c b/examples/tinyds.c index 1154f0b..010cd25 100644 --- a/examples/tinyds.c +++ b/examples/tinyds.c @@ -99,6 +99,8 @@ struct tinyds_server struct ds_seat *seat; struct ds_data_device_manager *data_device; + struct wl_event_source *idle_task; + enum wl_seat_capability seat_caps; struct wl_list views; @@ -109,6 +111,10 @@ struct tinyds_server struct wl_listener new_xdg_surface; struct wl_listener request_set_selection; struct wl_listener request_data_offer_receive; + + struct { + bool seat_caps; + } changes; }; struct tinyds_view @@ -130,6 +136,10 @@ static bool server_init(struct tinyds_server *server, struct wl_display *display); static bool server_init_backend(struct tinyds_server *server); static bool server_init_protocols(struct tinyds_server *server); +static void server_schedule_idle_task(struct tinyds_server *server); +static void server_update_seat_caps(struct tinyds_server *server, + enum wl_seat_capability caps); +static void server_handle_idle_task(void *data); static void server_handle_display_destroy(struct wl_listener *listener, void *data); static void server_handle_new_input(struct wl_listener *listener, void *data); @@ -280,6 +290,9 @@ server_handle_display_destroy(struct wl_listener *listener, void *data) if (server->output) output_destroy(server->output); + if (server->idle_task) + wl_event_source_remove(server->idle_task); + /* It's safe to remove links of all listener here because * server_handle_display_destroy must be the first to be called * before other objects such as backend. */ @@ -355,11 +368,45 @@ server_init_protocols(struct tinyds_server *server) } static void +server_schedule_idle_task(struct tinyds_server *server) +{ + if (server->idle_task) + return; + + server->idle_task = + wl_event_loop_add_idle(wl_display_get_event_loop(server->display), + server_handle_idle_task, server); +} + +static void +server_update_seat_caps(struct tinyds_server *server, + enum wl_seat_capability caps) +{ + server->seat_caps = caps; + server->changes.seat_caps = true; + server_schedule_idle_task(server); +} + +static void +server_handle_idle_task(void *data) +{ + struct tinyds_server *server = data; + + server->idle_task = NULL; + + if (server->changes.seat_caps) { + server->changes.seat_caps = false; + ds_seat_set_capabilities(server->seat, server->seat_caps); + } +} + +static void server_handle_new_input(struct wl_listener *listener, void *data) { struct tinyds_server *server; struct ds_input_device *dev = data; enum ds_input_device_type dev_type; + enum wl_seat_capability new_cap; server = wl_container_of(listener, server, new_input); @@ -367,21 +414,22 @@ server_handle_new_input(struct wl_listener *listener, void *data) switch (dev_type) { case DS_INPUT_DEVICE_KEYBOARD: server_add_keyboard(server, dev); - server->seat_caps |= WL_SEAT_CAPABILITY_KEYBOARD; + new_cap = WL_SEAT_CAPABILITY_KEYBOARD; break; case DS_INPUT_DEVICE_TOUCH: server_add_touch(server, dev); + new_cap = WL_SEAT_CAPABILITY_TOUCH; break; case DS_INPUT_DEVICE_POINTER: server_add_pointer(server, dev); - server->seat_caps |= WL_SEAT_CAPABILITY_POINTER; + new_cap = WL_SEAT_CAPABILITY_POINTER; break; default: ds_err("Unknown type(%d) of ds_input_device", dev_type); - break; + return; } - ds_seat_set_capabilities(server->seat, server->seat_caps); + server_update_seat_caps(server, (server->seat_caps | new_cap)); } static void @@ -804,11 +852,15 @@ static void keyboard_handle_device_destroy(struct wl_listener *listener, void *data) { struct tinyds_keyboard *kbd; + enum wl_seat_capability new_caps; kbd = wl_container_of(listener, kbd, destroy); ds_inf("Keyboard(%p) destroyed", kbd); + new_caps = kbd->server->seat_caps & ~WL_SEAT_CAPABILITY_KEYBOARD; + server_update_seat_caps(kbd->server, new_caps); + wl_list_remove(&kbd->destroy.link); wl_list_remove(&kbd->key.link); @@ -869,11 +921,15 @@ static void touch_handle_device_destroy(struct wl_listener *listener, void *data) { struct tinyds_touch *touch; + enum wl_seat_capability new_caps; touch = wl_container_of(listener, touch, destroy); ds_inf("Touch(%p) destroyed", touch); + new_caps = touch->server->seat_caps & ~WL_SEAT_CAPABILITY_TOUCH; + server_update_seat_caps(touch->server, new_caps); + wl_list_remove(&touch->destroy.link); wl_list_remove(&touch->down.link); wl_list_remove(&touch->up.link); @@ -904,11 +960,15 @@ static void pointer_handle_device_destroy(struct wl_listener *listener, void *data) { struct tinyds_pointer *pointer; + enum wl_seat_capability new_caps; pointer = wl_container_of(listener, pointer, destroy); ds_inf("Pointer(%p) destroyed", pointer); + new_caps = pointer->server->seat_caps & ~WL_SEAT_CAPABILITY_POINTER; + server_update_seat_caps(pointer->server, new_caps); + wl_list_remove(&pointer->destroy.link); wl_list_remove(&pointer->motion.link); wl_list_remove(&pointer->motion_absolute.link); -- 2.7.4 From 58bc3733f6259bc55582c3d80caf406e32be5688 Mon Sep 17 00:00:00 2001 From: Seunghun Date: Mon, 8 Aug 2022 16:29:14 +0900 Subject: [PATCH 02/16] tinyds: Integrate idle_redraw into idle_task Change-Id: Id653519e35f5a9787451abe481012ea9fa5996eb --- examples/tinyds.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/examples/tinyds.c b/examples/tinyds.c index 010cd25..cdadfac 100644 --- a/examples/tinyds.c +++ b/examples/tinyds.c @@ -77,8 +77,6 @@ struct tinyds_output struct ds_allocator *allocator; struct ds_swapchain *swapchain; - struct wl_event_source *idle_redraw; - struct wl_listener output_destroy; struct wl_listener output_frame; @@ -172,8 +170,7 @@ static void output_unlink_ds_output(struct tinyds_output *output); static void output_handle_destroy(struct wl_listener *listener, void *data); static void output_handle_frame(struct wl_listener *listener, void *data); static void output_damage(struct tinyds_output *output); -static void output_schedule_idle_redraw(struct tinyds_output *output); -static void output_handle_idle_redraw(void *data); +static void output_redraw(struct tinyds_output *output); static void keyboard_handle_device_destroy(struct wl_listener *listener, void *data); static void keyboard_handle_key(struct wl_listener *listener, void *data); @@ -398,6 +395,9 @@ server_handle_idle_task(void *data) server->changes.seat_caps = false; ds_seat_set_capabilities(server->seat, server->seat_caps); } + + if (server->output && server->output->damaged) + output_redraw(server->output); } static void @@ -784,39 +784,23 @@ output_handle_frame(struct wl_listener *listener, void *data) output->drawable = true; if (output->damaged) - output_schedule_idle_redraw(output); + server_schedule_idle_task(output->server); } static void output_damage(struct tinyds_output *output) { output->damaged = true; - output_schedule_idle_redraw(output); + server_schedule_idle_task(output->server); } static void -output_schedule_idle_redraw(struct tinyds_output *output) +output_redraw(struct tinyds_output *output) { - struct tinyds_server *server = output->server; - - if (output->idle_redraw) - return; - - output->idle_redraw = - wl_event_loop_add_idle(wl_display_get_event_loop(server->display), - output_handle_idle_redraw, output); -} - -static void -output_handle_idle_redraw(void *data) -{ - struct tinyds_output *output = data; struct ds_buffer *output_buffer; pixman_image_t *output_image; struct tinyds_view *view; - output->idle_redraw = NULL; - if (!output->drawable || !output->damaged) return; -- 2.7.4 From 1ab419bbce371b1b3212cd08d46426b9ed9eaaf3 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 14 Jul 2022 09:30:42 +0900 Subject: [PATCH 03/16] exmaples: Remove an example 'wl-backend' The 'wl-backend' is no longer necessary. Change-Id: I98421fc0ae02f65693468ea013a24320092a4bda --- examples/meson.build | 7 -- examples/wl-backend.c | 226 -------------------------------------------------- 2 files changed, 233 deletions(-) delete mode 100644 examples/wl-backend.c diff --git a/examples/meson.build b/examples/meson.build index 87d8654..dcfed15 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -3,13 +3,6 @@ common_deps = [ dependency('wayland-server', required: true), ] -executable('wl-backend', - 'wl-backend.c', - dependencies: common_deps, - install_dir: libds_bindir, - install : true -) - executable('tinyds', [ 'tinyds.c', diff --git a/examples/wl-backend.c b/examples/wl-backend.c deleted file mode 100644 index 38dea1b..0000000 --- a/examples/wl-backend.c +++ /dev/null @@ -1,226 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define WIDTH 700 -#define HEIGHT 400 - -struct server -{ - struct ds_backend *backend; - struct ds_output *output; - struct ds_allocator *allocator; - struct ds_swapchain *swapchain; - struct ds_buffer *front_buffer; - - struct wl_display *display; - - struct { - struct wl_listener output_destroy; - struct wl_listener output_frame; - } listener; - - int width, height; -}; - -struct server _server; - -static void init_server(struct server *server, struct wl_display *display); -static void fini_server(struct server *server); -static void output_handle_destroy(struct wl_listener *listener, void *data); -static void output_handle_frame(struct wl_listener *listener, void *data); -static void draw_output(struct server *server); - -int -main(void) -{ - struct server *server = &_server; - struct wl_display *display; - - ds_log_init(DS_DBG, NULL); - - display = wl_display_create(); - assert(display); - - server->width = WIDTH; - server->height = HEIGHT; - - init_server(server, display); - - server->listener.output_destroy.notify = output_handle_destroy; - ds_output_add_destroy_listener(server->output, - &server->listener.output_destroy); - - server->listener.output_frame.notify = output_handle_frame; - ds_output_add_frame_listener(server->output, - &server->listener.output_frame); - - ds_backend_start(server->backend); - - draw_output(server); - - wl_display_run(server->display); - - fini_server(server); - wl_display_destroy(display); - return 0; -} - -static struct ds_backend * -create_backend_auto(struct wl_display *display) -{ - struct ds_backend *backend = NULL; - char name[512]; - int i; - - for (i = 0; i < 5; i++) { - snprintf(name, sizeof name, "wayland-%d", i); - backend = ds_wl_backend_create(display, name); - if (backend) - break; - } - - return backend; -} - -static void -init_server(struct server *server, struct wl_display *display) -{ - server->display = display; - - server->backend = create_backend_auto(display); - assert(server->backend); - - server->allocator = ds_shm_allocator_create(); - assert(server->allocator); - - server->swapchain = ds_swapchain_create(server->allocator, - server->width, server->height, WL_SHM_FORMAT_XRGB8888); - assert(server->swapchain); - - server->output = - ds_wl_backend_create_output(server->backend); - assert(server->output); -} - -static void -fini_server(struct server *server) -{ - ds_buffer_unlock(server->front_buffer); - ds_swapchain_destroy(server->swapchain); - ds_allocator_destroy(server->allocator); -} - -static void -paint_pixels(void *image, int padding, int width, int height, uint32_t time) -{ - const int halfh = padding + (height - padding * 2) / 2; - const int halfw = padding + (width - padding * 2) / 2; - int ir, or; - uint32_t *pixel = image; - int y; - - /* squared radii thresholds */ - or = (halfw < halfh ? halfw : halfh) - 8; - ir = or - 32; - or *= or; - ir *= ir; - - pixel += padding * width; - for (y = padding; y < height - padding; y++) { - int x; - int y2 = (y - halfh) * (y - halfh); - - pixel += padding; - for (x = padding; x < width - padding; x++) { - uint32_t v; - - /* squared distance from center */ - int r2 = (x - halfw) * (x - halfw) + y2; - - if (r2 < ir) - v = (r2 / 32 + time / 64) * 0x0080401; - else if (r2 < or) - v = (y + time / 32) * 0x0080401; - else - v = (x + time / 16) * 0x0080401; - v &= 0x00ffffff; - - /* cross if compositor uses X from XRGB as alpha */ - if (abs(x - y) > 6 && abs(x + y - height) > 6) - v |= 0xff000000; - - *pixel++ = v; - } - - pixel += padding; - } -} - -static inline int64_t -timespec_to_msec(const struct timespec *a) -{ - return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; -} - -static void -output_handle_destroy(struct wl_listener *listener, - void *data __attribute__((unused))) -{ - struct server *server = - wl_container_of(listener, server, listener.output_destroy); - wl_display_terminate(server->display); -} - -static void -output_handle_frame(struct wl_listener *listener, - void *data __attribute__((unused))) -{ - struct server *server = - wl_container_of(listener, server, listener.output_frame); - draw_output(server); -} - -static void -draw_output(struct server *server) -{ - struct ds_buffer *buffer; - void *data; - uint32_t format; - size_t stride; - struct timespec now; - uint32_t frame_time_msec; - - ds_dbg("Redraw output"); - - clock_gettime(CLOCK_MONOTONIC, &now); - frame_time_msec = timespec_to_msec(&now); - - buffer = ds_swapchain_acquire(server->swapchain, NULL); - assert(buffer); - - assert(ds_buffer_begin_data_ptr_access(buffer, - 0, &data, &format, &stride) == true); - - paint_pixels(data, 20, server->width, server->height, frame_time_msec); - - ds_buffer_end_data_ptr_access(buffer); - - ds_output_attach_buffer(server->output, buffer); - ds_output_commit(server->output); - - if (server->front_buffer) - ds_buffer_unlock(server->front_buffer); - - server->front_buffer = buffer; -} -- 2.7.4 From 63e2de2d9491ea975e88c2e71cdcb0d77f8e091b Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 10 Aug 2022 14:07:53 +0900 Subject: [PATCH 04/16] packaging: Fix packaging break Remove wl-backend binary from packaging. This change should have been applied to a follow commit. Author: Seunghun Lee Date: Thu Jul 14 09:30:42 2022 +0900 exmaples: Remove an example 'wl-backend' The 'wl-backend' is no longer necessary. Change-Id: Ia5d5a8038c8ee16dedf8a65f253cf761a5606ebc --- packaging/libds.spec | 1 - 1 file changed, 1 deletion(-) diff --git a/packaging/libds.spec b/packaging/libds.spec index 43071ed..ecf2b73 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -74,7 +74,6 @@ ninja -C builddir install %{_includedir}/libds/* %{_libdir}/pkgconfig/libds.pc %{_libdir}/libds.so -%{_bindir}/wl-backend %{_bindir}/tinyds %{_bindir}/input-device-test %{_bindir}/libinput-backend -- 2.7.4 From 2d737182e3e07d16e0fffdc8ad549c67daad0064 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 3 Aug 2022 13:15:06 +0900 Subject: [PATCH 05/16] xdg_shell: Add toplevel_set_activated() Change-Id: Ic6b9a12ce5a158e6e737593c05e6b765ee5c0673 --- src/xdg_shell/xdg_toplevel.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/xdg_shell/xdg_toplevel.c b/src/xdg_shell/xdg_toplevel.c index 2a1e6d7..cd24bbc 100644 --- a/src/xdg_shell/xdg_toplevel.c +++ b/src/xdg_shell/xdg_toplevel.c @@ -14,6 +14,15 @@ static const struct xdg_toplevel_interface xdg_toplevel_impl; static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource); +WL_EXPORT uint32_t +ds_xdg_toplevel_set_activated(struct ds_xdg_surface *surface, bool activated) +{ + assert(surface->role == DS_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel->scheduled.activated = activated; + + return ds_xdg_surface_schedule_configure(surface); +} + void create_xdg_toplevel(struct ds_xdg_surface *surface, uint32_t id) { -- 2.7.4 From 98c094be1ec0432ed0095420f5ac992e74487d0a Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Fri, 12 Aug 2022 19:36:10 +0900 Subject: [PATCH 06/16] seat: add extern 'C' in seat.h Without this extern "C", C++ program (ex. test cases) does not recognize the symbols in this header file. Change-Id: I8d86fbfe59aa7f8f051ba34e7240ac5bbfcc9969 --- include/libds/seat.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/libds/seat.h b/include/libds/seat.h index aced712..8c3d6ce 100644 --- a/include/libds/seat.h +++ b/include/libds/seat.h @@ -9,6 +9,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct ds_seat; struct ds_seat_client; @@ -205,4 +209,8 @@ void ds_seat_touch_add_grab_start_listener(struct ds_seat *seat, void ds_seat_set_selection(struct ds_seat *seat, struct ds_data_source *source, uint32_t serial); +#ifdef __cplusplus +} +#endif + #endif -- 2.7.4 From 30bce87c4329a86b654211c9fb734debe08a2eaf Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 11 Aug 2022 09:34:34 +0900 Subject: [PATCH 07/16] seat: Fix formatting This removes braces from if having one statement. Change-Id: Iaa06dc69ce3a32bf112adfb9bbd5f28feca1bb2b --- src/seat/seat_keyboard.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/seat/seat_keyboard.c b/src/seat/seat_keyboard.c index 9ebe17c..867a60f 100644 --- a/src/seat/seat_keyboard.c +++ b/src/seat/seat_keyboard.c @@ -148,9 +148,7 @@ ds_seat_create_keyboard_grab(struct ds_seat *seat, grab = calloc(1, sizeof *grab); if (!grab) - { return NULL; - } grab->iface = iface; grab->seat = seat; -- 2.7.4 From ae1a09c942f1fe33d69648b35ba5c29be0fbbd55 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 11 Aug 2022 09:45:03 +0900 Subject: [PATCH 08/16] seat: Rename ds_seat_keyboard_destroy_grab properly This renames ds_seat_keyboard_destroy_grab to ds_seat_keyboard_grab_destroy The function takes ds_seat_keyboard_grab as a first argument, and we use, by convention, name of object at the beginning of function name. Change-Id: Ifaf19e319025644dfcee4a8f88bcfb3d0816aba0 --- include/libds/seat.h | 2 +- src/seat/seat_keyboard.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/libds/seat.h b/include/libds/seat.h index 8c3d6ce..d618ff5 100644 --- a/include/libds/seat.h +++ b/include/libds/seat.h @@ -162,7 +162,7 @@ void ds_seat_keyboard_notify_key(struct ds_seat *seat, uint32_t time_msec, struct ds_seat_keyboard_grab *ds_seat_create_keyboard_grab(struct ds_seat *seat, const struct ds_keyboard_grab_interface *iface, void *data); -void ds_seat_keyboard_destroy_grab(struct ds_seat_keyboard_grab *grab); +void ds_seat_keyboard_grab_destroy(struct ds_seat_keyboard_grab *grab); void *ds_seat_keyboard_grab_get_data(struct ds_seat_keyboard_grab *grab); diff --git a/src/seat/seat_keyboard.c b/src/seat/seat_keyboard.c index 867a60f..85cf672 100644 --- a/src/seat/seat_keyboard.c +++ b/src/seat/seat_keyboard.c @@ -158,7 +158,7 @@ ds_seat_create_keyboard_grab(struct ds_seat *seat, } WL_EXPORT void -ds_seat_keyboard_destroy_grab(struct ds_seat_keyboard_grab *grab) +ds_seat_keyboard_grab_destroy(struct ds_seat_keyboard_grab *grab) { free(grab); } -- 2.7.4 From 1ae4b2d7823af8fc47711c5c842b6db0e8b8c47c Mon Sep 17 00:00:00 2001 From: Seunghun Date: Tue, 9 Aug 2022 19:49:54 +0900 Subject: [PATCH 09/16] data_device: Start implementing drag and drop This patch introduces ds_drag and ds_drag_icon to handle drag and drop operation. Change-Id: Icfeedc47fba42f77fa632e186379373b925d9f44 --- include/libds/data_device.h | 15 +++ src/data_device/data_device.c | 29 +++++- src/data_device/data_device_private.h | 43 +++++++++ src/data_device/drag.c | 173 ++++++++++++++++++++++++++++++++++ src/data_device/manager.c | 1 + src/data_device/meson.build | 1 + 6 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 src/data_device/drag.c diff --git a/include/libds/data_device.h b/include/libds/data_device.h index f4956a2..4401002 100644 --- a/include/libds/data_device.h +++ b/include/libds/data_device.h @@ -33,6 +33,8 @@ struct ds_data_source; */ struct ds_data_offer; +struct ds_drag; + struct ds_event_request_set_selection { struct ds_seat *seat; @@ -40,6 +42,14 @@ struct ds_event_request_set_selection uint32_t serial; }; +struct ds_event_request_start_drag +{ + struct ds_seat *seat; + struct ds_surface *origin; + struct ds_drag *drag; + uint32_t serial; +}; + struct ds_event_request_data_offer_receive { struct ds_data_offer *offer; @@ -56,12 +66,17 @@ void ds_data_device_manager_add_destroy_listener( void ds_data_device_manager_add_request_set_selection_listener( struct ds_data_device_manager *manager, struct wl_listener *listener); +void ds_data_device_manager_add_request_start_drag_listener( + struct ds_data_device_manager *manager, struct wl_listener *listener); + void ds_data_device_manager_add_request_data_offer_receive_listener( struct ds_data_device_manager *manager, struct wl_listener *listener); void ds_data_offer_send(struct ds_data_offer *offer, const char *mime_type, int32_t fd); +void ds_drag_destroy(struct ds_drag *drag); + #ifdef __cplusplus } #endif diff --git a/src/data_device/data_device.c b/src/data_device/data_device.c index 267f662..b85a9bf 100644 --- a/src/data_device/data_device.c +++ b/src/data_device/data_device.c @@ -1,5 +1,6 @@ #include +#include "libds/log.h" #include "data_device_private.h" static const struct wl_data_device_interface data_device_iface; @@ -131,12 +132,36 @@ data_device_handle_start_drag(struct wl_client *client, uint32_t serial) { struct ds_data_device *data_device; + struct ds_data_source_client *source_client = NULL; + struct ds_data_source *source = NULL; + struct ds_drag *drag; data_device = wl_resource_get_user_data(resource); - if (!data_device) + if (!data_device || !data_device->seat_client) + return; + + if (source_resource) { + source_client = wl_resource_get_user_data(source_resource); + source = &source_client->base; + } + + drag = create_drag(data_device->seat_client, source, icon_resource); + if (!drag) { + ds_err("Could not create ds_drag"); + wl_resource_post_no_memory(resource); return; + } + + if (source_client) + source_client->finalized = true; - // TODO + struct ds_event_request_start_drag event = { + .seat = data_device->seat, + .drag = drag, + .origin = ds_surface_from_resource(origin_resource), + .serial = serial, + }; + wl_signal_emit(&data_device->manager->events.request_start_drag, &event); } static void diff --git a/src/data_device/data_device_private.h b/src/data_device/data_device_private.h index 0ea1752..5cd1c4d 100644 --- a/src/data_device/data_device_private.h +++ b/src/data_device/data_device_private.h @@ -22,6 +22,7 @@ struct ds_data_device_manager struct { struct wl_signal destroy; struct wl_signal request_set_selection; + struct wl_signal request_start_drag; struct wl_signal request_data_offer_receive; } events; }; @@ -64,6 +65,45 @@ struct ds_data_offer struct wl_listener source_destroy; }; +struct ds_drag_icon; + +struct ds_drag +{ + struct ds_seat_keyboard_grab keyboard_grab; + struct ds_seat_pointer_grab pointer_grab; + struct ds_seat_touch_grab touch_grab; + + struct ds_seat *seat; + struct ds_seat_client *seat_client; + struct ds_seat_client *focused_client; + + struct ds_drag_icon *icon; + struct ds_data_source *source; + + struct wl_listener icon_destroy; + struct wl_listener source_destroy; + + struct { + struct wl_signal destroy; + } events; +}; + +struct ds_drag_icon +{ + struct ds_drag *drag; + struct ds_surface *surface; + + struct wl_listener surface_destroy; + + struct { + struct wl_signal destroy; + struct wl_signal map; + struct wl_signal unmap; + } events; + + bool mapped; +}; + struct ds_data_device *create_data_device( struct ds_data_device_manager *manager, struct wl_client *client, uint32_t version, uint32_t id, struct wl_resource *seat_resource); @@ -77,4 +117,7 @@ struct ds_data_offer * create_data_offer(struct ds_data_device *data_device, struct ds_data_source *source, enum ds_data_offer_type type); +struct ds_drag *create_drag(struct ds_seat_client *seat_client, + struct ds_data_source *source, struct wl_resource *icon_resource); + #endif diff --git a/src/data_device/drag.c b/src/data_device/drag.c new file mode 100644 index 0000000..d0a3402 --- /dev/null +++ b/src/data_device/drag.c @@ -0,0 +1,173 @@ +#include +#include "data_device_private.h" + +static void drag_destroy(struct ds_drag *drag); +static struct ds_drag_icon *create_drag_icon(struct ds_drag *drag, + struct wl_resource *icon_resource); +static void drag_handle_icon_destroy(struct wl_listener *listener, void *data); +static void drag_handle_source_destroy(struct wl_listener *listener, + void *data); +static void drag_icon_destroy(struct ds_drag_icon *icon); + +WL_EXPORT void +ds_drag_destroy(struct ds_drag *drag) +{ + drag_destroy(drag); +} + +struct ds_drag * +create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source, + struct wl_resource *icon_resource) +{ + struct ds_drag *drag; + + drag = calloc(1, sizeof *drag); + if (!drag) + return NULL; + + drag->seat = ds_seat_client_get_seat(seat_client); + drag->seat_client = seat_client; + + // FIXME ds_seat_client_add_destroy_listener()? + + if (icon_resource) { + drag->icon = create_drag_icon(drag, icon_resource); + if (!drag->icon) { + free(drag); + return NULL; + } + + drag->icon_destroy.notify = drag_handle_icon_destroy; + wl_signal_add(&drag->icon->events.destroy, &drag->icon_destroy); + } + + if (source) { + drag->source = source; + + drag->source_destroy.notify = drag_handle_source_destroy; + wl_signal_add(&source->events.destroy, &drag->source_destroy); + } + + // TODO Add grab interface + + return drag; +} + +static void +drag_destroy(struct ds_drag *drag) +{ + wl_signal_emit(&drag->events.destroy, drag); + + if (drag->source) + wl_list_remove(&drag->source_destroy.link); + + if (drag->icon) { + wl_list_remove(&drag->icon_destroy.link); + drag_icon_destroy(drag->icon); + } + + free(drag); +} + +static void +drag_handle_icon_destroy(struct wl_listener *listener, void *data) +{ + struct ds_drag *drag; + + drag = wl_container_of(listener, drag, icon_destroy); + drag->icon = NULL; +} + +static void +drag_handle_source_destroy(struct wl_listener *listener, void *data) +{ + struct ds_drag *drag; + + drag = wl_container_of(listener, drag, source_destroy); + drag_destroy(drag); +} + +const struct ds_surface_role drag_icon_surface_role; + +static void drag_icon_handle_surface_destroy(struct wl_listener *listener, + void *data); +static void drag_icon_set_mapped(struct ds_drag_icon *icon, bool mapped); + +static struct ds_drag_icon * +create_drag_icon(struct ds_drag *drag, struct wl_resource *icon_resource) +{ + struct ds_drag_icon *icon; + + icon = calloc(1, sizeof *icon); + if (!icon) + return NULL; + + icon->drag = drag; + + wl_signal_init(&icon->events.destroy); + wl_signal_init(&icon->events.map); + wl_signal_init(&icon->events.unmap); + + icon->surface = ds_surface_from_resource(icon_resource); + if (!ds_surface_set_role(icon->surface, &drag_icon_surface_role, icon, + icon_resource, WL_DATA_DEVICE_ERROR_ROLE)) { + free(icon); + return NULL; + } + + icon->surface_destroy.notify = drag_icon_handle_surface_destroy; + ds_surface_add_destroy_listener(icon->surface, &icon->surface_destroy); + + if (ds_surface_has_buffer(icon->surface)) + drag_icon_set_mapped(icon, true); + + return icon; +} + +static void +drag_icon_destroy(struct ds_drag_icon *icon) +{ + drag_icon_set_mapped(icon, false); + wl_signal_emit(&icon->events.destroy, icon); + wl_list_remove(&icon->surface_destroy.link); + ds_surface_reset_role_data(icon->surface); + free(icon); +} + +static void drag_icon_set_mapped(struct ds_drag_icon *icon, bool mapped) +{ + if (mapped && !icon->mapped) { + icon->mapped = true; + wl_signal_emit(&icon->events.map, icon); + } + else if (!mapped && icon->mapped) { + wl_signal_emit(&icon->events.unmap, icon); + icon->mapped = false; + } +} + +static void +drag_icon_surface_role_commit(struct ds_surface *surface) +{ + struct ds_drag_icon *icon; + + icon = ds_surface_get_role_data(surface); + if (!icon) + return; + + drag_icon_set_mapped(icon, ds_surface_has_buffer(surface)); +} + +const struct ds_surface_role drag_icon_surface_role = { + .name = "wl_data_device-icon", + .commit = drag_icon_surface_role_commit, +}; + +static void +drag_icon_handle_surface_destroy(struct wl_listener *listener, void *data) +{ + struct ds_drag_icon *icon; + + icon = wl_container_of(listener, icon, surface_destroy); + drag_icon_destroy(icon); +} diff --git a/src/data_device/manager.c b/src/data_device/manager.c index ed79be3..abf6ff8 100644 --- a/src/data_device/manager.c +++ b/src/data_device/manager.c @@ -28,6 +28,7 @@ ds_data_device_manager_create(struct wl_display *display) wl_signal_init(&manager->events.destroy); wl_signal_init(&manager->events.request_set_selection); + wl_signal_init(&manager->events.request_start_drag); wl_signal_init(&manager->events.request_data_offer_receive); manager->global = wl_global_create(display, diff --git a/src/data_device/meson.build b/src/data_device/meson.build index cc438f6..a508673 100644 --- a/src/data_device/meson.build +++ b/src/data_device/meson.build @@ -4,4 +4,5 @@ libds_files += files( 'data_source.c', 'data_source_client.c', 'data_offer.c', + 'drag.c', ) -- 2.7.4 From daa501d8e5cf5df305f8579622dff31770b47a2b Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 11 Aug 2022 11:08:52 +0900 Subject: [PATCH 10/16] data_deivce: Add dnd implementation to ds_data_source This adds dnd interface to ds_data_source. Change-Id: I35f75977396f82774cf350df42d20f44c5903e80 --- src/data_device.h | 18 ++++++++++++++++++ src/data_device/data_source.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/data_device.h b/src/data_device.h index 0295fb3..de09eeb 100644 --- a/src/data_device.h +++ b/src/data_device.h @@ -12,6 +12,11 @@ struct ds_data_source_interface { int32_t fd); void (*accept)(struct ds_data_source *source, uint32_t serial, const char *mime_type); + + void (*dnd_drop)(struct ds_data_source *source); + void (*dnd_finish)(struct ds_data_source *source); + void (*dnd_action)(struct ds_data_source *source, + enum wl_data_device_manager_dnd_action action); }; struct ds_data_source @@ -19,6 +24,9 @@ struct ds_data_source const struct ds_data_source_interface *iface; struct wl_array mime_types; + int32_t actions; + + enum wl_data_device_manager_dnd_action current_dnd_action; struct { struct wl_signal destroy; @@ -35,4 +43,14 @@ void ds_data_source_destroy(struct ds_data_source *source); void ds_data_source_send(struct ds_data_source *source, const char *mime_type, int32_t fd); +void ds_data_source_accept(struct ds_data_source *source, uint32_t serial, + const char *mime_type); + +void ds_data_source_dnd_drop(struct ds_data_source *source); + +void ds_data_source_dnd_finish(struct ds_data_source *source); + +void ds_data_source_dnd_action(struct ds_data_source *source, + enum wl_data_device_manager_dnd_action action); + #endif diff --git a/src/data_device/data_source.c b/src/data_device/data_source.c index 5f52ad5..198d0c0 100644 --- a/src/data_device/data_source.c +++ b/src/data_device/data_source.c @@ -37,3 +37,34 @@ ds_data_source_send(struct ds_data_source *source, const char *mime_type, { source->iface->send(source, mime_type, fd); } + +void +ds_data_source_accept(struct ds_data_source *source, uint32_t serial, + const char *mime_type) +{ + source->accepted = (mime_type != NULL); + if (source->iface->accept) + source->iface->accept(source, serial, mime_type); +} + +void +ds_data_source_dnd_drop(struct ds_data_source *source) +{ + if (source->iface->dnd_drop) + source->iface->dnd_drop(source); +} + +void +ds_data_source_dnd_finish(struct ds_data_source *source) +{ + if (source->iface->dnd_finish) + source->iface->dnd_finish(source); +} + +void +ds_data_source_dnd_action(struct ds_data_source *source, + enum wl_data_device_manager_dnd_action action) +{ + if (source->iface->dnd_action) + source->iface->dnd_action(source, action); +} -- 2.7.4 From e77f00a77b0aacc1d8bec5648d9688d2c19c344e Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 11 Aug 2022 16:05:16 +0900 Subject: [PATCH 11/16] data_device: Add dnd implementation to ds_data_offer Change-Id: I5c38f00421dda52dcaa08bf90cca18b2bc73f939 --- src/data_device/data_device_private.h | 6 ++ src/data_device/data_offer.c | 129 +++++++++++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 3 deletions(-) diff --git a/src/data_device/data_device_private.h b/src/data_device/data_device_private.h index 5cd1c4d..e766cd3 100644 --- a/src/data_device/data_device_private.h +++ b/src/data_device/data_device_private.h @@ -6,9 +6,14 @@ #include "data_device.h" #include "seat.h" +#define DATA_DEVICE_ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \ + WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \ + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) + enum ds_data_offer_type { DS_DATA_OFFER_SELECTION, + DS_DATA_OFFER_DRAG, }; struct ds_data_device_manager @@ -59,6 +64,7 @@ struct ds_data_offer enum ds_data_offer_type type; uint32_t actions; + enum wl_data_device_manager_dnd_action preferred_action; struct wl_list link; // ds_data_device.data_offers diff --git a/src/data_device/data_offer.c b/src/data_device/data_offer.c index 4c1395b..23d71c1 100644 --- a/src/data_device/data_offer.c +++ b/src/data_device/data_offer.c @@ -1,5 +1,8 @@ +#include #include +#include +#include "libds/log.h" #include "data_device_private.h" static const struct wl_data_offer_interface data_offer_iface; @@ -7,6 +10,8 @@ static const struct wl_data_offer_interface data_offer_iface; static void data_offer_handle_resource_destroy(struct wl_resource *resource); static void data_offer_handle_source_destroy(struct wl_listener *listener, void *data); +static uint32_t data_offer_choose_action(struct ds_data_offer *offer); +static void data_offer_source_dnd_finish(struct ds_data_offer *offer); WL_EXPORT void ds_data_offer_send(struct ds_data_offer *offer, const char *mime_type, @@ -55,6 +60,26 @@ create_data_offer(struct ds_data_device *data_device, return offer; } +void +data_offer_update_action(struct ds_data_offer *offer) +{ + uint32_t action; + + assert(offer->type == DS_DATA_OFFER_DRAG); + + action = data_offer_choose_action(offer); + if (offer->source->current_dnd_action == action) + return; + + offer->source->current_dnd_action = action; + + ds_data_source_dnd_action(offer->source, action); + + if (wl_resource_get_version(offer->resource) >= + WL_DATA_OFFER_ACTION_SINCE_VERSION) + wl_data_offer_send_action(offer->resource, action); +} + static void data_offer_destroy(struct ds_data_offer *offer) { @@ -96,7 +121,13 @@ data_offer_handle_accept(struct wl_client *client, if (!offer) return; - // TODO + if (offer->type != DS_DATA_OFFER_DRAG) { + ds_dbg("Ignoring wl_data_offer.accept request on a " + "non-drag-and-drop offer"); + return; + } + + ds_data_source_accept(offer->source, serial, mime_type); } static void @@ -131,12 +162,38 @@ data_offer_handle_finish(struct wl_client *client, struct wl_resource *resource) { struct ds_data_offer *offer; + enum wl_data_device_manager_dnd_action action; offer = wl_resource_get_user_data(resource); if (!offer) return; - // TODO + // TODO: also fail while we have a drag-and-drop grab + if (offer->type != DS_DATA_OFFER_DRAG) { + wl_resource_post_error(offer->resource, + WL_DATA_OFFER_ERROR_INVALID_FINISH, + "Offer is not drag-and-drop"); + return; + } + + if (!offer->source->accepted) { + wl_resource_post_error(offer->resource, + WL_DATA_OFFER_ERROR_INVALID_FINISH, + "Premature finish request"); + return; + } + + action = offer->source->current_dnd_action; + if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE || + action == WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) { + wl_resource_post_error(offer->resource, + WL_DATA_OFFER_ERROR_INVALID_FINISH, + "Offer finished with an invalid action"); + return; + } + + data_offer_source_dnd_finish(offer); + data_offer_destroy(offer); } static void @@ -150,7 +207,30 @@ data_offer_handle_set_actions(struct wl_client *client, if (!offer) return; - // TODO + if (actions & ~DATA_DEVICE_ALL_ACTIONS) { + wl_resource_post_error(offer->resource, + WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK, + "invalid action mask %x", actions); + return; + } + + if (preferred_action && (!(preferred_action & actions) || + __builtin_popcount(preferred_action) > 1)) { + wl_resource_post_error(offer->resource, + WL_DATA_OFFER_ERROR_INVALID_ACTION, + "invalid action %x", preferred_action); + return; + } + + if (offer->type != DS_DATA_OFFER_DRAG) { + wl_resource_post_error(offer->resource, + WL_DATA_OFFER_ERROR_INVALID_OFFER, + "set_action can only be sent to drag-and-drop offers"); + return; + } + + offer->actions = actions; + offer->preferred_action = preferred_action; } static const struct wl_data_offer_interface data_offer_iface = { @@ -160,3 +240,46 @@ static const struct wl_data_offer_interface data_offer_iface = { .finish = data_offer_handle_finish, .set_actions = data_offer_handle_set_actions, }; + +static uint32_t +data_offer_choose_action(struct ds_data_offer *offer) +{ + uint32_t offer_actions, preferred_action = 0; + uint32_t source_actions, available_actions; + + if (wl_resource_get_version(offer->resource) >= + WL_DATA_OFFER_ACTION_SINCE_VERSION) { + offer_actions = offer->actions; + preferred_action = offer->preferred_action; + } + else { + offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + } + + if (offer->source->actions >= 0) + source_actions = offer->source->actions; + else + source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + + available_actions = offer_actions & source_actions; + if (!available_actions) + return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; + + if ((preferred_action & available_actions) != 0) + return preferred_action; + + // Use the first found action, in bit order + return 1 << (ffs(available_actions) - 1); +} + +static void +data_offer_source_dnd_finish(struct ds_data_offer *offer) +{ + struct ds_data_source *source; + + source = offer->source; + if (source->actions < 0) + return; + + ds_data_source_dnd_finish(source); +} -- 2.7.4 From 2eb1eac6a6d6025203313dfea945097b3257622a Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 11 Aug 2022 17:44:59 +0900 Subject: [PATCH 12/16] data_device: Add dnd implementation to ds_data_source_client Change-Id: I2c08a3a803419e079bf0607dbfd2bae699732fc7 --- src/data_device/data_source_client.c | 79 +++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/data_device/data_source_client.c b/src/data_device/data_source_client.c index 11501f8..3fa1225 100644 --- a/src/data_device/data_source_client.c +++ b/src/data_device/data_source_client.c @@ -13,6 +13,13 @@ static void data_source_client_iface_accept(struct ds_data_source *source, static void data_handle_client_iface_send(struct ds_data_source *source, const char *mime_type, int32_t fd); static void data_source_client_iface_destroy(struct ds_data_source *source); +static void data_source_client_iface_dnd_drop( + struct ds_data_source *ds_source); +static void data_source_client_iface_dnd_finish( + struct ds_data_source *ds_source); +static void data_source_client_iface_dnd_action( + struct ds_data_source *ds_source, + enum wl_data_device_manager_dnd_action action); struct ds_data_source_client * create_data_source_client(struct wl_client *client, uint32_t version, @@ -39,6 +46,21 @@ create_data_source_client(struct wl_client *client, uint32_t version, source->iface.send = data_handle_client_iface_send; source->iface.destroy = data_source_client_iface_destroy; + if (wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) { + source->iface.dnd_drop = data_source_client_iface_dnd_drop; + } + + if (wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { + source->iface.dnd_finish = data_source_client_iface_dnd_finish; + } + + if (wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION) { + source->iface.dnd_action = data_source_client_iface_dnd_action; + } + ds_data_source_init(&source->base, &source->iface); return source; @@ -114,7 +136,28 @@ data_source_client_handle_set_actions(struct wl_client *client, if (!source) return; - // TODO + if (source->base.actions >= 0) { + wl_resource_post_error(source->resource, + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, + "cannot set actions more than once"); + return; + } + + if (dnd_actions & ~DATA_DEVICE_ALL_ACTIONS) { + wl_resource_post_error(source->resource, + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, + "invalid action mask %x", dnd_actions); + return; + } + + if (source->finalized) { + wl_resource_post_error(source->resource, + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, + "invalid action change after wl_data_device.start_drag"); + return; + } + + source->base.actions = dnd_actions; } static const struct wl_data_source_interface wl_data_source_iface = { @@ -161,3 +204,37 @@ data_source_client_iface_destroy(struct ds_data_source *ds_source) wl_resource_set_user_data(source->resource, NULL); free(source); } + +static void +data_source_client_iface_dnd_drop(struct ds_data_source *ds_source) +{ + struct ds_data_source_client *source; + + source = data_source_client_from_data_source(ds_source); + assert(wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION); + wl_data_source_send_dnd_drop_performed(source->resource); +} + +static void +data_source_client_iface_dnd_finish(struct ds_data_source *ds_source) +{ + struct ds_data_source_client *source; + + source = data_source_client_from_data_source(ds_source); + assert(wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION); + wl_data_source_send_dnd_finished(source->resource); +} + +static void +data_source_client_iface_dnd_action(struct ds_data_source *ds_source, + enum wl_data_device_manager_dnd_action action) +{ + struct ds_data_source_client *source; + + source = data_source_client_from_data_source(ds_source); + assert(wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION); + wl_data_source_send_dnd_finished(source->resource); +} -- 2.7.4 From c2a0e15dadbc0d7b4722b7f64afa8a7bb1996dff Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Fri, 12 Aug 2022 11:17:40 +0900 Subject: [PATCH 13/16] data_device: Create ds_data_device per seat_client Change-Id: Ib2c74c3f26ca7bead4d707e7b642a8e8d605be7c --- src/data_device/data_device.c | 164 ++++++++++++++++++++++++++-------- src/data_device/data_device_private.h | 17 ++-- src/data_device/data_offer.c | 15 ++-- src/data_device/manager.c | 20 ++++- 4 files changed, 160 insertions(+), 56 deletions(-) diff --git a/src/data_device/data_device.c b/src/data_device/data_device.c index b85a9bf..24f8032 100644 --- a/src/data_device/data_device.c +++ b/src/data_device/data_device.c @@ -5,7 +5,16 @@ static const struct wl_data_device_interface data_device_iface; +static struct ds_data_device * +data_device_get_or_create(struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client); +static struct ds_data_device *create_data_device( + struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client); +static void data_device_destroy(struct ds_data_device *data_device); static void data_device_handle_resource_destroy(struct wl_resource *resource); +static void data_device_handle_manager_destroy(struct wl_listener *listener, + void *data); static void data_device_handle_seat_client_destroy( struct wl_listener *listener, void *data); static void data_device_handle_seat_set_selection(struct wl_listener *listener, @@ -13,32 +22,77 @@ static void data_device_handle_seat_set_selection(struct wl_listener *listener, static void data_device_handle_keyboard_focus_change( struct wl_listener *listener, void *data); static void data_device_update_selection(struct ds_data_device *data_device); +static void data_device_send_selection(struct ds_data_device *data_device, + struct wl_resource *resource); -struct ds_data_device * -create_data_device(struct ds_data_device_manager *manager, +void +create_data_device_resource(struct ds_data_device_manager *manager, struct wl_client *client, uint32_t version, uint32_t id, struct wl_resource *seat_resource) { struct ds_data_device *data_device; + struct ds_seat_client *seat_client, *focused_client; + struct wl_resource *resource; - data_device = calloc(1, sizeof *data_device); - if (!data_device) - return NULL; + seat_client = ds_seat_client_from_resource(seat_resource); + data_device = data_device_get_or_create(manager, seat_client); + if (!data_device) { + ds_err("Could not create data_device"); + wl_client_post_no_memory(client); + return; + } - data_device->resource = wl_resource_create(client, - &wl_data_device_interface, version, id); - if (!data_device->resource) { + resource = wl_resource_create(client, &wl_data_device_interface, + version, id); + if (!resource) { wl_client_post_no_memory(client); - return NULL; + return; } - wl_resource_set_implementation(data_device->resource, &data_device_iface, + wl_resource_set_implementation(resource, &data_device_iface, data_device, data_device_handle_resource_destroy); + wl_list_insert(&data_device->resources, wl_resource_get_link(resource)); + + focused_client = ds_seat_keyboard_get_focused_client(data_device->seat); + if (data_device->seat_client == focused_client) + data_device_send_selection(data_device, resource); +} + +static struct ds_data_device * +data_device_get_or_create(struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client) +{ + struct ds_data_device *data_device; + + data_device = data_device_for_seat_client(manager, seat_client); + if (!data_device) + data_device = create_data_device(manager, seat_client); + + return data_device; +} + +static struct ds_data_device * +create_data_device(struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client) +{ + struct ds_data_device *data_device; + + data_device = calloc(1, sizeof *data_device); + if (!data_device) + return NULL; + + + wl_list_init(&data_device->resources); + wl_list_init(&data_device->selection_offers); + data_device->manager = manager; - data_device->seat_client = ds_seat_client_from_resource(seat_resource); + data_device->seat_client = seat_client; data_device->seat = ds_seat_client_get_seat(data_device->seat_client); + data_device->manager_destroy.notify = data_device_handle_manager_destroy; + wl_signal_add(&manager->events.destroy, &data_device->manager_destroy); + data_device->seat_client_destroy.notify = data_device_handle_seat_client_destroy; ds_seat_client_add_destroy_listener(data_device->seat_client, @@ -52,28 +106,35 @@ create_data_device(struct ds_data_device_manager *manager, data_device->keyboard_focus_change.notify = data_device_handle_keyboard_focus_change; ds_seat_keyboard_add_focus_change_listener(data_device->seat, - &data_device->keyboard_focus_change); - - data_device_update_selection(data_device); + &data_device->keyboard_focus_change); wl_list_insert(&manager->data_devices, &data_device->link); return data_device; } -void +static void data_device_destroy(struct ds_data_device *data_device) { - wl_list_remove(&data_device->link); + struct wl_resource *resource, *resource_tmp; + struct ds_data_offer *offer, *offer_tmp; - if (data_device->seat_client) { - wl_list_remove(&data_device->seat_client_destroy.link); - wl_list_remove(&data_device->seat_set_selection.link); - wl_list_remove(&data_device->keyboard_focus_change.link); + wl_list_for_each_safe(offer, offer_tmp, &data_device->selection_offers, + link) { + data_offer_destroy(offer); } - wl_resource_set_user_data(data_device->resource, NULL); + wl_resource_for_each_safe(resource, resource_tmp, + &data_device->resources) { + wl_list_remove(wl_resource_get_link(resource)); + wl_resource_set_user_data(resource, NULL); + } + wl_list_remove(&data_device->link); + wl_list_remove(&data_device->manager_destroy.link); + wl_list_remove(&data_device->seat_client_destroy.link); + wl_list_remove(&data_device->seat_set_selection.link); + wl_list_remove(&data_device->keyboard_focus_change.link); free(data_device); } @@ -86,6 +147,19 @@ data_device_handle_resource_destroy(struct wl_resource *resource) if (!data_device) return; + wl_list_remove(wl_resource_get_link(resource)); + if (!wl_list_empty(&data_device->resources)) + return; + + data_device_destroy(data_device); +} + +static void data_device_handle_manager_destroy(struct wl_listener *listener, + void *data) +{ + struct ds_data_device *data_device; + + data_device = wl_container_of(listener, data_device, manager_destroy); data_device_destroy(data_device); } @@ -96,13 +170,7 @@ data_device_handle_seat_client_destroy(struct wl_listener *listener, struct ds_data_device *data_device; data_device = wl_container_of(listener, data_device, seat_client_destroy); - - wl_list_remove(&data_device->seat_client_destroy.link); - wl_list_remove(&data_device->seat_set_selection.link); - wl_list_remove(&data_device->keyboard_focus_change.link); - - data_device->seat_client = NULL; - data_device->seat = NULL; + data_device_destroy(data_device); } static void @@ -137,7 +205,7 @@ data_device_handle_start_drag(struct wl_client *client, struct ds_drag *drag; data_device = wl_resource_get_user_data(resource); - if (!data_device || !data_device->seat_client) + if (!data_device) return; if (source_resource) { @@ -173,7 +241,7 @@ data_device_handle_set_selection(struct wl_client *client, struct ds_data_source_client *source = NULL; data_device = wl_resource_get_user_data(resource); - if (!data_device || !data_device->seat_client) + if (!data_device) return; if (source_resource) { @@ -208,26 +276,46 @@ static const struct wl_data_device_interface data_device_iface = { static void data_device_update_selection(struct ds_data_device *data_device) { - struct ds_seat_client *focused_client; struct ds_data_source *source; - struct ds_data_offer *offer; + struct ds_data_offer *offer, *tmp; + struct ds_seat_client *focused_client; + struct wl_resource *resource; + + source = ds_seat_get_selection(data_device->seat); + if (source) + source->accepted = false; + + wl_list_for_each_safe(offer, tmp, &data_device->selection_offers, link) + data_offer_destroy(offer); focused_client = ds_seat_keyboard_get_focused_client(data_device->seat); - if (data_device->seat_client != focused_client) - return; + if (data_device->seat_client == focused_client) { + wl_resource_for_each(resource, &data_device->resources) + data_device_send_selection(data_device, resource); + } +} + +static void +data_device_send_selection(struct ds_data_device *data_device, + struct wl_resource *device_resource) +{ + struct ds_data_source *source; + struct ds_data_offer *offer; source = ds_seat_get_selection(data_device->seat); if (source) { - offer = create_data_offer(data_device, source, + offer = create_data_offer(device_resource, source, DS_DATA_OFFER_SELECTION); if (!offer) { - wl_resource_post_no_memory(data_device->resource); + wl_resource_post_no_memory(device_resource); return; } - wl_data_device_send_selection(data_device->resource, offer->resource); + wl_list_insert(&data_device->selection_offers, &offer->link); + + wl_data_device_send_selection(device_resource, offer->resource); } else { - wl_data_device_send_selection(data_device->resource, NULL); + wl_data_device_send_selection(device_resource, NULL); } } diff --git a/src/data_device/data_device_private.h b/src/data_device/data_device_private.h index e766cd3..e86d5c7 100644 --- a/src/data_device/data_device_private.h +++ b/src/data_device/data_device_private.h @@ -34,14 +34,15 @@ struct ds_data_device_manager struct ds_data_device { - struct wl_resource *resource; struct ds_data_device_manager *manager; struct ds_seat_client *seat_client; struct ds_seat *seat; + struct wl_list resources; struct wl_list selection_offers; // ds_data_offer.link struct wl_list link; // ds_data_device_manager.data_devices + struct wl_listener manager_destroy; struct wl_listener seat_client_destroy; struct wl_listener seat_set_selection; struct wl_listener keyboard_focus_change; @@ -110,19 +111,23 @@ struct ds_drag_icon bool mapped; }; -struct ds_data_device *create_data_device( - struct ds_data_device_manager *manager, struct wl_client *client, - uint32_t version, uint32_t id, struct wl_resource *seat_resource); +struct ds_data_device * +data_device_for_seat_client(struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client); -void data_device_destroy(struct ds_data_device *data_device); +void create_data_device_resource(struct ds_data_device_manager *manager, + struct wl_client *client, uint32_t version, + uint32_t id, struct wl_resource *seat_resource); struct ds_data_source_client *create_data_source_client( struct wl_client *wl_client, uint32_t version, uint32_t id); struct ds_data_offer * -create_data_offer(struct ds_data_device *data_device, +create_data_offer(struct wl_resource *device_resource, struct ds_data_source *source, enum ds_data_offer_type type); +void data_offer_destroy(struct ds_data_offer *offer); + struct ds_drag *create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source, struct wl_resource *icon_resource); diff --git a/src/data_device/data_offer.c b/src/data_device/data_offer.c index 23d71c1..46b0ac4 100644 --- a/src/data_device/data_offer.c +++ b/src/data_device/data_offer.c @@ -21,12 +21,11 @@ ds_data_offer_send(struct ds_data_offer *offer, const char *mime_type, } struct ds_data_offer * -create_data_offer(struct ds_data_device *data_device, +create_data_offer(struct wl_resource *device_resource, struct ds_data_source *source, enum ds_data_offer_type type) { struct ds_data_offer *offer; struct wl_client *client; - uint32_t version; char **p; offer = calloc(1, sizeof *offer); @@ -34,13 +33,12 @@ create_data_offer(struct ds_data_device *data_device, return NULL; offer->source = source; - offer->data_device = data_device; + offer->data_device = wl_resource_get_user_data(device_resource); offer->type = type; - client = wl_resource_get_client(data_device->resource); - version = wl_resource_get_version(data_device->resource); + client = wl_resource_get_client(device_resource); offer->resource = wl_resource_create(client, &wl_data_offer_interface, - version, 0); + wl_resource_get_version(device_resource), 0); if (!offer->resource) { free(offer); return NULL; @@ -52,7 +50,7 @@ create_data_offer(struct ds_data_device *data_device, offer->source_destroy.notify = data_offer_handle_source_destroy; wl_signal_add(&source->events.destroy, &offer->source_destroy); - wl_data_device_send_data_offer(data_device->resource, offer->resource); + wl_data_device_send_data_offer(device_resource, offer->resource); wl_array_for_each(p, &source->mime_types) wl_data_offer_send_offer(offer->resource, *p); @@ -80,9 +78,10 @@ data_offer_update_action(struct ds_data_offer *offer) wl_data_offer_send_action(offer->resource, action); } -static void +void data_offer_destroy(struct ds_data_offer *offer) { + wl_list_remove(&offer->link); wl_list_remove(&offer->source_destroy.link); wl_resource_set_user_data(offer->resource, NULL); diff --git a/src/data_device/manager.c b/src/data_device/manager.c index abf6ff8..61300ce 100644 --- a/src/data_device/manager.c +++ b/src/data_device/manager.c @@ -69,6 +69,20 @@ ds_data_device_manager_add_request_data_offer_receive_listener( wl_signal_add(&manager->events.request_data_offer_receive, listener); } +struct ds_data_device * +data_device_for_seat_client(struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client) +{ + struct ds_data_device *data_device; + + wl_list_for_each(data_device, &manager->data_devices, link) { + if (data_device->seat_client == seat_client) + return data_device; + } + + return NULL; +} + static const struct wl_data_device_manager_interface data_device_manager_iface; static void @@ -114,12 +128,10 @@ static void data_device_manager_handle_get_data_device( uint32_t id, struct wl_resource *seat_resource) { struct ds_data_device_manager *manager; - uint32_t version; manager = wl_resource_get_user_data(resource); - version = wl_resource_get_version(resource); - - create_data_device(manager, client, version, id, seat_resource); + create_data_device_resource(manager, client, + wl_resource_get_version(resource), id, seat_resource); } static const struct wl_data_device_manager_interface -- 2.7.4 From 9d2c6c869e09659a3c4f272fbf7ba151dcdf3b58 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Tue, 16 Aug 2022 19:10:54 +0900 Subject: [PATCH 14/16] seat: Add APIs needed by data_device Change-Id: I879fccd534aec397fcca2e41a9cc9ac4169d0eba --- src/seat.h | 11 +++++++++++ src/seat/seat.c | 38 ++++++++++++++++++++++++++++++++++++++ src/seat/seat_pointer.c | 12 ++++++++++++ src/seat/seat_private.h | 4 ++++ 4 files changed, 65 insertions(+) diff --git a/src/seat.h b/src/seat.h index 59a1d10..a5b3e59 100644 --- a/src/seat.h +++ b/src/seat.h @@ -3,6 +3,7 @@ #include "libds/keyboard.h" #include "libds/seat.h" +#include "data_device.h" struct ds_pointer_grab_interface; @@ -36,11 +37,17 @@ void ds_seat_add_set_selection_listener(struct ds_seat *seat, struct ds_data_source *ds_seat_get_selection(struct ds_seat *seat); +void ds_seat_start_drag(struct ds_seat *seat, + struct ds_data_source *drag_source, uint32_t serial); + struct ds_seat_client *ds_seat_client_from_resource( struct wl_resource *resource); struct ds_seat *ds_seat_client_get_seat(struct ds_seat_client *seat_client); +struct wl_client *ds_seat_client_get_wl_client( + struct ds_seat_client *seat_client); + void ds_seat_pointer_enter(struct ds_seat *seat, struct ds_surface *surface, double sx, double sy); @@ -58,6 +65,10 @@ void ds_seat_pointer_send_axis(struct ds_seat *seat, uint32_t time_msec, void ds_seat_pointer_send_frame(struct ds_seat *seat); +uint32_t ds_seat_pointer_get_grab_button(struct ds_seat *seat); + +size_t ds_seat_pointer_get_grab_button_count(struct ds_seat *seat); + void ds_seat_keyboard_enter(struct ds_seat *seat, struct ds_surface *surface, uint32_t keycodes[], size_t num_keycodes, struct ds_keyboard_modifiers *modifiers); diff --git a/src/seat/seat.c b/src/seat/seat.c index 09fbb51..174f672 100644 --- a/src/seat/seat.c +++ b/src/seat/seat.c @@ -20,6 +20,8 @@ static void seat_handle_display_destroy(struct wl_listener *listener, void *data); static void seat_handle_selection_source_destroy(struct wl_listener *listener, void *data); +static void seat_handle_drag_source_destroy(struct wl_listener *listener, + void *data); static void seat_destroy(struct ds_seat *seat); static struct ds_seat_client *seat_client_create(struct ds_seat *seat, struct wl_client *wl_client); @@ -72,6 +74,7 @@ ds_seat_create(struct wl_display *display, const char *name) wl_signal_init(&seat->events.touch_grab_begin); wl_signal_init(&seat->events.touch_grab_end); wl_signal_init(&seat->events.set_selection); + wl_signal_init(&seat->events.start_drag); seat->display_destroy.notify = seat_handle_display_destroy; wl_display_add_destroy_listener(display, &seat->display_destroy); @@ -210,6 +213,25 @@ ds_seat_get_selection(struct ds_seat *seat) return seat->selection_source; } +void +ds_seat_start_drag(struct ds_seat *seat, struct ds_data_source *drag_source, + uint32_t serial) +{ + seat->drag_serial = serial; + + if (seat->drag_source) + ds_data_source_destroy(seat->drag_source); + + if (drag_source) { + seat->drag_source = drag_source; + seat->drag_source_destroy.notify = seat_handle_drag_source_destroy; + ds_data_source_add_destroy_listener(drag_source, + &seat->drag_source_destroy); + } + + wl_signal_emit(&seat->events.start_drag, seat); +} + struct ds_seat * ds_seat_client_get_seat(struct ds_seat_client *seat_client) { @@ -223,6 +245,12 @@ ds_seat_add_set_selection_listener(struct ds_seat *seat, wl_signal_add(&seat->events.set_selection, listener); } +struct wl_client * +ds_seat_client_get_wl_client(struct ds_seat_client *seat_client) +{ + return seat_client->wl_client; +} + struct ds_seat_client * seat_client_for_wl_client(struct ds_seat *seat, struct wl_client *wl_client) { @@ -420,6 +448,16 @@ seat_handle_selection_source_destroy(struct wl_listener *listener, } static void +seat_handle_drag_source_destroy(struct wl_listener *listener, void *data) +{ + struct ds_seat *seat; + + seat = wl_container_of(listener, seat, drag_source_destroy); + wl_list_remove(&seat->drag_source_destroy.link); + seat->drag_source = NULL; +} + +static void seat_destroy(struct ds_seat *seat) { struct ds_seat_client *seat_client, *tmp; diff --git a/src/seat/seat_pointer.c b/src/seat/seat_pointer.c index dd9abcf..0f6e96d 100644 --- a/src/seat/seat_pointer.c +++ b/src/seat/seat_pointer.c @@ -283,6 +283,18 @@ ds_seat_pointer_send_frame(struct ds_seat *seat) pointer_send_frame(resource); } +uint32_t +ds_seat_pointer_get_grab_button(struct ds_seat *seat) +{ + return seat->pointer.grab_button; +} + +size_t +ds_seat_pointer_get_grab_button_count(struct ds_seat *seat) +{ + return seat->pointer.button_count; +} + bool seat_pointer_init(struct ds_seat *seat) { diff --git a/src/seat/seat_private.h b/src/seat/seat_private.h index 4c6833d..7d7e063 100644 --- a/src/seat/seat_private.h +++ b/src/seat/seat_private.h @@ -123,6 +123,9 @@ struct ds_seat struct ds_data_source *selection_source; uint32_t selection_serial; + struct ds_data_source *drag_source; + uint32_t drag_serial; + struct wl_list clients; // ds_seat_client::link struct ds_seat_pointer pointer; @@ -131,6 +134,7 @@ struct ds_seat struct wl_listener display_destroy; struct wl_listener selection_source_destroy; + struct wl_listener drag_source_destroy; struct { struct wl_signal destroy; -- 2.7.4 From 16bc80088f28a5cda12541625d98ab4d747cc8f3 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Tue, 16 Aug 2022 19:11:42 +0900 Subject: [PATCH 15/16] data_device: Add start drag operation Change-Id: I70007fd98a9e64653bb06a14e16ec5dc21b05b7c --- include/libds/data_device.h | 25 +++ src/data_device.h | 3 + src/data_device/data_device.c | 8 +- src/data_device/data_device_private.h | 23 +- src/data_device/data_offer.c | 20 +- src/data_device/data_source.c | 8 + src/data_device/data_source_client.c | 2 +- src/data_device/drag.c | 398 +++++++++++++++++++++++++++++++++- src/data_device/manager.c | 9 + 9 files changed, 486 insertions(+), 10 deletions(-) diff --git a/include/libds/data_device.h b/include/libds/data_device.h index 4401002..d11f1c2 100644 --- a/include/libds/data_device.h +++ b/include/libds/data_device.h @@ -57,6 +57,17 @@ struct ds_event_request_data_offer_receive int32_t fd; }; +struct ds_event_drag_motion { + struct ds_drag *drag; + uint32_t time; + double sx, sy; +}; + +struct ds_event_drag_drop { + struct ds_drag *drag; + uint32_t time; +}; + struct ds_data_device_manager * ds_data_device_manager_create(struct wl_display *display); @@ -77,6 +88,20 @@ void ds_data_offer_send(struct ds_data_offer *offer, const char *mime_type, void ds_drag_destroy(struct ds_drag *drag); +void ds_drag_start_pointer_drag(struct ds_drag *drag, uint32_t serial); + +void ds_drag_add_destroy_listener(struct ds_drag *drag, + struct wl_listener *listener); + +void ds_drag_add_focus_listener(struct ds_drag *drag, + struct wl_listener *listener); + +void ds_drag_add_motion_listener(struct ds_drag *drag, + struct wl_listener *listener); + +void ds_drag_add_drop_listener(struct ds_drag *drag, + struct wl_listener *listener); + #ifdef __cplusplus } #endif diff --git a/src/data_device.h b/src/data_device.h index de09eeb..3c8827c 100644 --- a/src/data_device.h +++ b/src/data_device.h @@ -40,6 +40,9 @@ void ds_data_source_init(struct ds_data_source *source, void ds_data_source_destroy(struct ds_data_source *source); +void ds_data_source_add_destroy_listener(struct ds_data_source *source, + struct wl_listener *listener); + void ds_data_source_send(struct ds_data_source *source, const char *mime_type, int32_t fd); diff --git a/src/data_device/data_device.c b/src/data_device/data_device.c index 24f8032..ef2a89e 100644 --- a/src/data_device/data_device.c +++ b/src/data_device/data_device.c @@ -85,6 +85,7 @@ create_data_device(struct ds_data_device_manager *manager, wl_list_init(&data_device->resources); wl_list_init(&data_device->selection_offers); + wl_list_init(&data_device->drag_offers); data_device->manager = manager; data_device->seat_client = seat_client; @@ -124,6 +125,9 @@ data_device_destroy(struct ds_data_device *data_device) data_offer_destroy(offer); } + wl_list_for_each_safe(offer, offer_tmp, &data_device->drag_offers, link) + data_offer_destroy(offer); + wl_resource_for_each_safe(resource, resource_tmp, &data_device->resources) { wl_list_remove(wl_resource_get_link(resource)); @@ -213,7 +217,7 @@ data_device_handle_start_drag(struct wl_client *client, source = &source_client->base; } - drag = create_drag(data_device->seat_client, source, icon_resource); + drag = create_drag(data_device, source, icon_resource); if (!drag) { ds_err("Could not create ds_drag"); wl_resource_post_no_memory(resource); @@ -311,8 +315,6 @@ data_device_send_selection(struct ds_data_device *data_device, return; } - wl_list_insert(&data_device->selection_offers, &offer->link); - wl_data_device_send_selection(device_resource, offer->resource); } else { diff --git a/src/data_device/data_device_private.h b/src/data_device/data_device_private.h index e86d5c7..26b0b91 100644 --- a/src/data_device/data_device_private.h +++ b/src/data_device/data_device_private.h @@ -16,9 +16,17 @@ enum ds_data_offer_type DS_DATA_OFFER_DRAG, }; +enum ds_drag_grab_type +{ + DS_DRAG_GRAB_KEYBOARD, + DS_DRAG_GRAB_KEYBOARD_POINTER, + DS_DRAG_GRAB_KEYBOARD_TOUCH, +}; + struct ds_data_device_manager { struct wl_global *global; + struct wl_display *display; struct wl_list data_devices; // ds_data_device.link @@ -40,6 +48,7 @@ struct ds_data_device struct wl_list resources; struct wl_list selection_offers; // ds_data_offer.link + struct wl_list drag_offers; // ds_data_offer.link struct wl_list link; // ds_data_device_manager.data_devices struct wl_listener manager_destroy; @@ -80,19 +89,29 @@ struct ds_drag struct ds_seat_pointer_grab pointer_grab; struct ds_seat_touch_grab touch_grab; + struct ds_data_device *data_device; struct ds_seat *seat; struct ds_seat_client *seat_client; struct ds_seat_client *focused_client; struct ds_drag_icon *icon; + struct ds_surface *focused_surface; struct ds_data_source *source; + enum ds_drag_grab_type grab_type; + struct wl_listener icon_destroy; struct wl_listener source_destroy; + struct wl_listener seat_client_destroy; struct { struct wl_signal destroy; + struct wl_signal focus; + struct wl_signal motion; + struct wl_signal drop; } events; + + bool started, dropped, cancelling; }; struct ds_drag_icon @@ -128,7 +147,9 @@ create_data_offer(struct wl_resource *device_resource, void data_offer_destroy(struct ds_data_offer *offer); -struct ds_drag *create_drag(struct ds_seat_client *seat_client, +void data_offer_update_action(struct ds_data_offer *offer); + +struct ds_drag *create_drag(struct ds_data_device *data_device, struct ds_data_source *source, struct wl_resource *icon_resource); #endif diff --git a/src/data_device/data_offer.c b/src/data_device/data_offer.c index 46b0ac4..955fd0e 100644 --- a/src/data_device/data_offer.c +++ b/src/data_device/data_offer.c @@ -25,15 +25,18 @@ create_data_offer(struct wl_resource *device_resource, struct ds_data_source *source, enum ds_data_offer_type type) { struct ds_data_offer *offer; + struct ds_data_device *data_device; struct wl_client *client; char **p; + data_device = wl_resource_get_user_data(device_resource); + offer = calloc(1, sizeof *offer); if (!offer) return NULL; offer->source = source; - offer->data_device = wl_resource_get_user_data(device_resource); + offer->data_device = data_device; offer->type = type; client = wl_resource_get_client(device_resource); @@ -47,6 +50,18 @@ create_data_offer(struct wl_resource *device_resource, wl_resource_set_implementation(offer->resource, &data_offer_iface, offer, data_offer_handle_resource_destroy); + switch (type) { + case DS_DATA_OFFER_SELECTION: + wl_list_insert(&data_device->selection_offers, &offer->link); + break; + case DS_DATA_OFFER_DRAG: + wl_list_insert(&data_device->drag_offers, &offer->link); + break; + default: + assert(0 && "cannot reach here"); + break; + } + offer->source_destroy.notify = data_offer_handle_source_destroy; wl_signal_add(&source->events.destroy, &offer->source_destroy); @@ -230,6 +245,8 @@ data_offer_handle_set_actions(struct wl_client *client, offer->actions = actions; offer->preferred_action = preferred_action; + + data_offer_update_action(offer); } static const struct wl_data_offer_interface data_offer_iface = { @@ -261,6 +278,7 @@ data_offer_choose_action(struct ds_data_offer *offer) source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; available_actions = offer_actions & source_actions; + if (!available_actions) return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; diff --git a/src/data_device/data_source.c b/src/data_device/data_source.c index 198d0c0..afecbbc 100644 --- a/src/data_device/data_source.c +++ b/src/data_device/data_source.c @@ -10,6 +10,7 @@ ds_data_source_init(struct ds_data_source *source, assert(iface->send); source->iface = iface; + source->actions = -1; wl_array_init(&source->mime_types); wl_signal_init(&source->events.destroy); } @@ -32,6 +33,13 @@ ds_data_source_destroy(struct ds_data_source *source) } void +ds_data_source_add_destroy_listener(struct ds_data_source *source, + struct wl_listener *listener) +{ + wl_signal_add(&source->events.destroy, listener); +} + +void ds_data_source_send(struct ds_data_source *source, const char *mime_type, int32_t fd) { diff --git a/src/data_device/data_source_client.c b/src/data_device/data_source_client.c index 3fa1225..60aafeb 100644 --- a/src/data_device/data_source_client.c +++ b/src/data_device/data_source_client.c @@ -236,5 +236,5 @@ data_source_client_iface_dnd_action(struct ds_data_source *ds_source, source = data_source_client_from_data_source(ds_source); assert(wl_resource_get_version(source->resource) >= WL_DATA_SOURCE_ACTION_SINCE_VERSION); - wl_data_source_send_dnd_finished(source->resource); + wl_data_source_send_action(source->resource, action); } diff --git a/src/data_device/drag.c b/src/data_device/drag.c index d0a3402..9baf351 100644 --- a/src/data_device/drag.c +++ b/src/data_device/drag.c @@ -1,12 +1,22 @@ +#include #include #include "data_device_private.h" +static const struct ds_pointer_grab_interface drag_pointer_grab_iface; +static const struct ds_keyboard_grab_interface drag_keyboard_grab_iface; + static void drag_destroy(struct ds_drag *drag); static struct ds_drag_icon *create_drag_icon(struct ds_drag *drag, struct wl_resource *icon_resource); static void drag_handle_icon_destroy(struct wl_listener *listener, void *data); static void drag_handle_source_destroy(struct wl_listener *listener, void *data); +static void drag_handle_seat_client_destroy(struct wl_listener *listener, + void *data); +static void drag_start(struct ds_drag *drag, uint32_t serial); +static void drag_set_focus(struct ds_drag *drag, struct ds_surface *surface, + double sx, double sy); +static void drag_drop(struct ds_drag *drag, uint32_t time); static void drag_icon_destroy(struct ds_drag_icon *icon); WL_EXPORT void @@ -15,8 +25,58 @@ ds_drag_destroy(struct ds_drag *drag) drag_destroy(drag); } +WL_EXPORT void +ds_drag_start_pointer_drag(struct ds_drag *drag, uint32_t serial) +{ + drag->grab_type = DS_DRAG_GRAB_KEYBOARD_POINTER; + + ds_seat_pointer_clear_focus(drag->seat); + ds_seat_pointer_start_grab(drag->seat, &drag->pointer_grab); + + drag_start(drag, serial); +} + +WL_EXPORT void +ds_drag_start_touch_drag(struct ds_drag *drag, uint32_t serial) +{ + drag->grab_type = DS_DRAG_GRAB_KEYBOARD_TOUCH; + + // TODO +} + +WL_EXPORT void +ds_drag_add_destroy_listener(struct ds_drag *drag, + struct wl_listener *listener) +{ + wl_signal_add(&drag->events.destroy, listener); +} + +WL_EXPORT void +ds_drag_add_focus_listener(struct ds_drag *drag, struct wl_listener *listener) +{ + wl_signal_add(&drag->events.focus, listener); +} + +WL_EXPORT void +ds_drag_add_motion_listener(struct ds_drag *drag, struct wl_listener *listener) +{ + wl_signal_add(&drag->events.motion, listener); +} + +WL_EXPORT void +ds_drag_add_drop_listener(struct ds_drag *drag, struct wl_listener *listener) +{ + wl_signal_add(&drag->events.drop, listener); +} + +struct ds_data_source * +ds_drag_get_source(struct ds_drag *drag) +{ + return drag->source; +} + struct ds_drag * -create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source, +create_drag(struct ds_data_device *data_device, struct ds_data_source *source, struct wl_resource *icon_resource) { struct ds_drag *drag; @@ -25,8 +85,14 @@ create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source, if (!drag) return NULL; - drag->seat = ds_seat_client_get_seat(seat_client); - drag->seat_client = seat_client; + wl_signal_init(&drag->events.destroy); + wl_signal_init(&drag->events.focus); + wl_signal_init(&drag->events.motion); + wl_signal_init(&drag->events.drop); + + drag->data_device = data_device; + drag->seat_client = data_device->seat_client; + drag->seat = ds_seat_client_get_seat(drag->seat_client); // FIXME ds_seat_client_add_destroy_listener()? @@ -48,7 +114,13 @@ create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source, wl_signal_add(&source->events.destroy, &drag->source_destroy); } - // TODO Add grab interface + drag->pointer_grab.data = drag; + drag->pointer_grab.iface = &drag_pointer_grab_iface; + + drag->keyboard_grab.data = drag; + drag->keyboard_grab.iface = &drag_keyboard_grab_iface; + + // TODO Add touch grab return drag; } @@ -56,8 +128,31 @@ create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source, static void drag_destroy(struct ds_drag *drag) { + if (drag->cancelling) + return; + + drag->cancelling = true; + + if (drag->started) { + ds_seat_keyboard_end_grab(drag->seat); + switch (drag->grab_type) { + case DS_DRAG_GRAB_KEYBOARD_POINTER: + ds_seat_pointer_end_grab(drag->seat); + break; + case DS_DRAG_GRAB_KEYBOARD_TOUCH: + // TODO + break; + default: + case DS_DRAG_GRAB_KEYBOARD: + break; + } + } + wl_signal_emit(&drag->events.destroy, drag); + if (drag->started) + drag_set_focus(drag, NULL, 0, 0); + if (drag->source) wl_list_remove(&drag->source_destroy.link); @@ -171,3 +266,298 @@ drag_icon_handle_surface_destroy(struct wl_listener *listener, void *data) icon = wl_container_of(listener, icon, surface_destroy); drag_icon_destroy(icon); } + +static void +drag_pointer_grab_iface_enter(struct ds_seat_pointer_grab *grab, + struct ds_surface *surface, double sx, double sy) +{ + struct ds_drag *drag = grab->data; + drag_set_focus(drag, surface, sx, sy); +} + +static void +drag_pointer_grab_iface_clear_focus(struct ds_seat_pointer_grab *grab) +{ + struct ds_drag *drag = grab->data; + drag_set_focus(drag, NULL, 0, 0); +} + +static void +drag_pointer_grab_iface_motion(struct ds_seat_pointer_grab *grab, + uint32_t time, double sx, double sy) +{ + struct ds_drag *drag = grab->data; + struct ds_data_device *data_device; + struct wl_resource *resource; + + if (!drag->focused_surface || !drag->focused_client) + return; + + data_device = data_device_for_seat_client(drag->data_device->manager, + drag->focused_client); + if (data_device) { + wl_resource_for_each(resource, &data_device->resources) { + wl_data_device_send_motion(resource, time, + wl_fixed_from_double(sx), wl_fixed_from_double(sy)); + } + } + + struct ds_event_drag_motion event = { + .drag = drag, + .time = time, + .sx = sx, + .sy = sy, + }; + wl_signal_emit(&drag->events.motion, &event); +} + +static uint32_t +drag_pointer_grab_iface_button(struct ds_seat_pointer_grab *grab, + uint32_t time, uint32_t button, uint32_t state) +{ + struct ds_drag *drag = grab->data; + uint32_t grab_button; + size_t grab_button_count; + + grab_button = ds_seat_pointer_get_grab_button(grab->seat); + if (drag->source && grab_button == button && + state == WL_POINTER_BUTTON_STATE_RELEASED) { + if (drag->focused_client && drag->source->current_dnd_action && + drag->source->accepted) { + drag_drop(drag, time); + } + else if (drag->source->iface->dnd_finish) { + ds_data_source_destroy(drag->source); + return 0; + } + } + + grab_button_count = ds_seat_pointer_get_grab_button(drag->seat); + if (grab_button_count == 0 && + state == WL_POINTER_BUTTON_STATE_RELEASED) { + drag_destroy(drag); + } + + return 0; +} + +static void +drag_pointer_grab_iface_axis(struct ds_seat_pointer_grab *grab, + uint32_t time, enum ds_axis_orientation orientation, double value, + int32_t value_discrete, enum ds_axis_source source) +{ + // This space is intentionally left blank +} + +static void +drag_pointer_grab_iface_cancel(struct ds_seat_pointer_grab *grab) +{ + struct ds_drag *drag = grab->data; + + drag_destroy(drag); +} + +static const struct ds_pointer_grab_interface drag_pointer_grab_iface = { + .enter = drag_pointer_grab_iface_enter, + .clear_focus = drag_pointer_grab_iface_clear_focus, + .motion = drag_pointer_grab_iface_motion, + .button = drag_pointer_grab_iface_button, + .axis = drag_pointer_grab_iface_axis, + .cancel = drag_pointer_grab_iface_cancel, +}; + +static void +drag_keyboard_grab_iface_enter(struct ds_seat_keyboard_grab *grab, + struct ds_surface *surface, uint32_t keycodes[], size_t num_keycodes, + struct ds_keyboard_modifiers *modifiers) +{ + // nothing has keyboard focus during drags +} + +static void +drag_keyboard_grab_iface_clear_focus(struct ds_seat_keyboard_grab *grab) +{ + // nothing has keyboard focus during drags +} + +static void +drag_keyboard_grab_iface_key(struct ds_seat_keyboard_grab *grab, + uint32_t time, uint32_t key, uint32_t state) +{ + // no keyboard input during drags +} + +static void +drag_keyboard_grab_iface_modifiers(struct ds_seat_keyboard_grab *grab, + struct ds_keyboard_modifiers *modifiers) +{ + // TODO change the dnd action based on what modifier is passed on the + // keyboard +} + +static void +drag_keyboard_grab_iface_cancel(struct ds_seat_keyboard_grab *grab) +{ + struct ds_drag *drag = grab->data; + + drag_destroy(drag); +} + +static const struct ds_keyboard_grab_interface drag_keyboard_grab_iface = { + .enter = drag_keyboard_grab_iface_enter, + .clear_focus = drag_keyboard_grab_iface_clear_focus, + .key = drag_keyboard_grab_iface_key, + .modifiers = drag_keyboard_grab_iface_modifiers, + .cancel = drag_keyboard_grab_iface_cancel, +}; + +static void +drag_start(struct ds_drag *drag, uint32_t serial) +{ + assert(!drag->started); + drag->started = true; + + ds_seat_keyboard_start_grab(drag->seat, &drag->keyboard_grab); + + ds_seat_start_drag(drag->seat, drag->source, serial); +} + +static void +drag_set_focus(struct ds_drag *drag, struct ds_surface *surface, + double sx, double sy) +{ + struct ds_seat_client *focused_client; + struct ds_data_device *data_device; + struct wl_resource *device_resource, *surface_resource; + struct ds_data_offer *offer, *tmp; + uint32_t serial; + + if (drag->focused_surface == surface) + return; + + if (drag->focused_client) { + wl_list_remove(&drag->seat_client_destroy.link); + + wl_list_for_each(data_device, + &drag->data_device->manager->data_devices, link) { + if (data_device->seat != + ds_seat_client_get_seat(drag->focused_client)) + continue; + + wl_list_for_each_safe(offer, tmp, + &data_device->drag_offers, link) { + if (!drag->dropped && + offer->source == drag->source && + (wl_resource_get_client(offer->resource) == + ds_seat_client_get_wl_client(drag->focused_client))) { + offer->source = NULL; + data_offer_destroy(offer); + } + } + } + + data_device = data_device_for_seat_client(drag->data_device->manager, + drag->focused_client); + if (data_device) { + wl_resource_for_each(device_resource, &data_device->resources) + wl_data_device_send_leave(device_resource); + } + + drag->focused_client = NULL; + drag->focused_surface = NULL; + } + + if (!surface) + goto out; + + surface_resource = ds_surface_get_wl_resource(surface); + + focused_client = ds_seat_client_for_wl_client(drag->seat, + wl_resource_get_client(surface_resource)); + if (!focused_client) + goto out; + + if (!drag->source) { + if (wl_resource_get_client(surface_resource) != + ds_seat_client_get_wl_client(drag->seat_client)) + goto out; + } + else { + drag->source->accepted = false; + + data_device = data_device_for_seat_client(drag->data_device->manager, + focused_client); + if (data_device) { + wl_resource_for_each(device_resource, &data_device->resources) { + offer = create_data_offer(device_resource, drag->source, + DS_DATA_OFFER_DRAG); + if (!offer) { + wl_resource_post_no_memory(device_resource); + return; + } + + data_offer_update_action(offer); + + if (wl_resource_get_version(offer->resource) >= + WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) { + wl_data_offer_send_source_actions(offer->resource, + drag->source->actions); + } + + serial = wl_display_next_serial( + drag->data_device->manager->display); + wl_data_device_send_enter(device_resource, serial, + surface_resource, + wl_fixed_from_double(sx), wl_fixed_from_double(sy), + offer->resource); + } + } + } + + drag->focused_surface = surface; + drag->focused_client = focused_client; + drag->seat_client_destroy.notify = drag_handle_seat_client_destroy; + ds_seat_client_add_destroy_listener(focused_client, + &drag->seat_client_destroy); + +out: + wl_signal_emit(&drag->events.focus, drag); +} + +static void +drag_drop(struct ds_drag *drag, uint32_t time) +{ + struct ds_data_device *data_device; + struct wl_resource *resource; + + assert(drag->focused_client); + + drag->dropped = true; + + data_device = data_device_for_seat_client(drag->data_device->manager, + drag->focused_client); + if (data_device) { + wl_resource_for_each(resource, &data_device->resources) + wl_data_device_send_drop(resource); + } + + if (drag->source) + ds_data_source_dnd_drop(drag->source); + + struct ds_event_drag_drop event = { + .drag = drag, + .time = time, + }; + wl_signal_emit(&drag->events.drop, &event); +} + +static void +drag_handle_seat_client_destroy(struct wl_listener *listener, void *data) +{ + struct ds_drag *drag; + + drag = wl_container_of(listener, drag, seat_client_destroy); + + drag->focused_client = NULL; + wl_list_remove(&drag->seat_client_destroy.link); +} diff --git a/src/data_device/manager.c b/src/data_device/manager.c index 61300ce..79ccc7f 100644 --- a/src/data_device/manager.c +++ b/src/data_device/manager.c @@ -24,6 +24,8 @@ ds_data_device_manager_create(struct wl_display *display) return NULL; } + manager->display = display; + wl_list_init(&manager->data_devices); wl_signal_init(&manager->events.destroy); @@ -63,6 +65,13 @@ ds_data_device_manager_add_request_set_selection_listener( } WL_EXPORT void +ds_data_device_manager_add_request_start_drag_listener( + struct ds_data_device_manager *manager, struct wl_listener *listener) +{ + wl_signal_add(&manager->events.request_start_drag, listener); +} + +WL_EXPORT void ds_data_device_manager_add_request_data_offer_receive_listener( struct ds_data_device_manager *manager, struct wl_listener *listener) { -- 2.7.4 From 044a321fdefa6b92a817cc842d8a4253539e2e8d Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Tue, 16 Aug 2022 19:14:03 +0900 Subject: [PATCH 16/16] tinyds: Place toplevel surfaces on random position This is to make drag and drop test easier. Change-Id: I11d8da198a42398e11c21b9901db3952f3daef59 --- examples/tinyds.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/examples/tinyds.c b/examples/tinyds.c index cdadfac..0c2e3f0 100644 --- a/examples/tinyds.c +++ b/examples/tinyds.c @@ -128,6 +128,7 @@ struct tinyds_view int x, y; bool mapped; + bool placed; }; static bool server_init(struct tinyds_server *server, @@ -1093,8 +1094,22 @@ static void view_handle_surface_commit(struct wl_listener *listener, void *data) { struct tinyds_view *view; + struct ds_buffer *buffer; + int w = 0, h = 0; view = wl_container_of(listener, view, surface_commit); + + buffer = ds_surface_get_buffer( + ds_xdg_surface_get_surface(view->xdg_surface)); + if (!view->placed && buffer) { + view->placed = true; + + ds_buffer_get_size(buffer, &w, &h); + + view->x = rand() % (OUTPUT_WIDTH - w); + view->y = rand() % (OUTPUT_HEIGHT - h); + } + output_damage(view->server->output); } @@ -1115,7 +1130,7 @@ view_composite(struct tinyds_view *view, pixman_image_t *dst_image) src_image, NULL, dst_image, - 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, view->x, view->y, pixman_image_get_width(src_image), pixman_image_get_height(src_image)); pixman_image_unref(src_image); -- 2.7.4