From a3c0c7c510dbbd885c0ac521df414febf545a437 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 13:27:17 +0900 Subject: [PATCH 01/16] packaging: Add missing file mistakenly unpacked Change-Id: I4e9709f7677e717951c466a1092a76d2ca207673 --- packaging/libds.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/libds.spec b/packaging/libds.spec index 806c75b..efba8cb 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -69,6 +69,7 @@ ninja -C builddir install %{_libdir}/libds.so %{_bindir}/wl-backend %{_bindir}/tinyds +%{_bindir}/input-device-test %files tizen-devel %manifest %{name}.manifest -- 2.7.4 From 3bc198b97377e0770b88f81b3e9b29d7f1ce1ef2 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 20 Apr 2022 11:29:17 +0900 Subject: [PATCH 02/16] examples/tinyds: Handle ds_keyboard tinyds now handles ds_keyboard, and it may be terminated by pressing Alt + Ctrl + Shift + BackSapce. Change-Id: I6333e2b239f3d7b28e62ca3997180e1428c9c4f7 --- src/examples/tinyds.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index a4c1042..cfa55a6 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -17,12 +17,25 @@ #include #include #include +#include +#include #define TINYDS_UNUSED __attribute__((unused)) #define OUTPUT_WIDTH 1280 #define OUTPUT_HEIGHT 720 +struct tinyds_server; + +struct tinyds_keyboard +{ + struct ds_input_device *dev; + struct tinyds_server *server; + + struct wl_listener destroy; + struct wl_listener key; +}; + struct tinyds_output { struct tinyds_server *server; @@ -54,6 +67,7 @@ struct tinyds_server struct wl_list views; struct wl_list outputs; + struct wl_listener new_input; struct wl_listener new_xdg_surface; }; @@ -77,6 +91,7 @@ struct tinyds_server _tinyds; static bool init_server(struct tinyds_server *server, struct wl_display *display); static void fini_server(struct tinyds_server *server); +static void server_handle_new_input(struct wl_listener *listener, void *data); static bool init_output(struct tinyds_output *output, struct tinyds_server *server, int width, int height); static void fini_output(struct tinyds_output *output); @@ -240,6 +255,9 @@ init_server(struct tinyds_server *server, struct wl_display *display) if (!server->backend) return false; + server->new_input.notify = server_handle_new_input; + ds_backend_add_new_input_listener(server->backend, &server->new_input); + server->compositor = ds_compositor_create(display); if (!server->compositor) { ds_backend_destroy(server->backend); @@ -439,3 +457,103 @@ view_send_frame_done(struct tinyds_view *view) ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface), &now); } + +static void +keyboard_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_keyboard *kbd; + + kbd = wl_container_of(listener, kbd, destroy); + + ds_inf("Keyboard(%p) destroyed", kbd); + + wl_list_remove(&kbd->destroy.link); + wl_list_remove(&kbd->key.link); + + free(kbd); +} + +static bool +server_handle_keybinding(struct tinyds_server *server, xkb_keysym_t sym) +{ + switch (sym) { + case XKB_KEY_BackSpace: + wl_display_terminate(server->display); + break; + default: + return false; + } + + return true; +} + +static void +keyboard_handle_key(struct wl_listener *listener, void *data) +{ + struct tinyds_keyboard *kbd; + struct ds_event_keyboard_key *event = data; + struct ds_keyboard *ds_keyboard; + struct xkb_state *xkb_state; + const xkb_keysym_t *syms; + uint32_t modifiers; + int nsyms; + + kbd = wl_container_of(listener, kbd, key); + + ds_keyboard = ds_input_device_get_keyboard(kbd->dev); + + modifiers = ds_keyboard_get_modifiers(ds_keyboard); + if ((modifiers & DS_MODIFIER_CTRL) && + (modifiers & DS_MODIFIER_ALT) && + (modifiers & DS_MODIFIER_SHIFT) && + event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + xkb_state = ds_keyboard_get_xkb_state(ds_keyboard); + if (xkb_state) { + nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8, + &syms); + for (int i = 0; i < nsyms; i++) { + server_handle_keybinding(kbd->server, syms[i]); + } + } + } +} + +static void +server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev) +{ + struct tinyds_keyboard *kbd; + + kbd = calloc(1, sizeof *kbd); + assert(kbd); + + kbd->dev = dev; + kbd->server = server; + + kbd->destroy.notify = keyboard_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &kbd->destroy); + + kbd->key.notify = keyboard_handle_key; + ds_keyboard_add_key_listener(ds_input_device_get_keyboard(dev), &kbd->key); + + ds_inf("Keyboard(%p) added", kbd); +} + +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; + + server = wl_container_of(listener, server, new_input); + + dev_type = ds_input_device_get_type(dev); + switch (dev_type) { + case DS_INPUT_DEVICE_KEYBOARD: + server_add_keyboard(server, dev); + break; + default: + ds_err("Unknown type(%d) of ds_input_device", dev_type); + break; + } +} -- 2.7.4 From b2bd27050f3570a8354a8927193aa56f1ff2c792 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 20 Apr 2022 15:45:55 +0900 Subject: [PATCH 03/16] xdg_shell: Destroy ds_xdg_surfaces when cleaning up client This patch fixes memory corruption caused by removing ds_xdg_surfaces's link in destroy_xdg_surface(). When wl_client is destroyed, ds_xdg_shell_client can be destroyed before its own ds_xdg_surfaces. This led to memory corruption because of illegal access to a freed memory when trying to remove list of ds_xdg_surface.link. Change-Id: I40fa5c1121c86f0674d7df81643e9805594e9dae --- src/libds/xdg_shell/xdg_shell.c | 4 ++++ src/libds/xdg_shell/xdg_shell.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/libds/xdg_shell/xdg_shell.c b/src/libds/xdg_shell/xdg_shell.c index a53684a..0b5252c 100644 --- a/src/libds/xdg_shell/xdg_shell.c +++ b/src/libds/xdg_shell/xdg_shell.c @@ -140,9 +140,13 @@ static void xdg_client_handle_resource_destroy(struct wl_resource *resource) { struct ds_xdg_client *client; + struct ds_xdg_surface *surface, *tmp; client = wl_resource_get_user_data(resource); + wl_list_for_each_safe(surface, tmp, &client->surfaces, link) + destroy_xdg_surface(surface); + if (client->ping_timer != NULL) wl_event_source_remove(client->ping_timer); diff --git a/src/libds/xdg_shell/xdg_shell.h b/src/libds/xdg_shell/xdg_shell.h index ea67be7..dc50d37 100644 --- a/src/libds/xdg_shell/xdg_shell.h +++ b/src/libds/xdg_shell/xdg_shell.h @@ -168,6 +168,8 @@ struct ds_xdg_surface * create_xdg_surface(struct ds_xdg_client *client, struct ds_surface *surface, uint32_t id); +void destroy_xdg_surface(struct ds_xdg_surface *surface); + void reset_xdg_surface(struct ds_xdg_surface *surface); -- 2.7.4 From 334d29e9832e5227dc7c039c06f64ccd381c7537 Mon Sep 17 00:00:00 2001 From: Duna Oh Date: Wed, 20 Apr 2022 20:57:38 +0900 Subject: [PATCH 04/16] Add ds_touch Change-Id: I62c506d260eebdb5c4802ceaf54adc530255905d --- include/libds/input_device.h | 5 ++ include/libds/interfaces/input_device.h | 2 + include/libds/interfaces/touch.h | 30 +++++++++ include/libds/touch.h | 46 +++++++++++++ src/examples/tinyds.c | 76 +++++++++++++++++++++ src/libds/backend/wayland/backend.h | 8 +++ src/libds/backend/wayland/seat.c | 113 ++++++++++++++++++++++++++++++++ src/libds/input_device.c | 12 ++++ src/libds/meson.build | 1 + src/libds/touch.c | 55 ++++++++++++++++ 10 files changed, 348 insertions(+) create mode 100644 include/libds/interfaces/touch.h create mode 100644 include/libds/touch.h create mode 100644 src/libds/touch.c diff --git a/include/libds/input_device.h b/include/libds/input_device.h index 6143e00..1a3652b 100644 --- a/include/libds/input_device.h +++ b/include/libds/input_device.h @@ -7,6 +7,8 @@ struct ds_pointer; struct ds_keyboard; +struct ds_touch; + enum ds_button_state { DS_BUTTON_RELEASED, @@ -29,6 +31,9 @@ ds_input_device_get_pointer(struct ds_input_device *dev); struct ds_keyboard * ds_input_device_get_keyboard(struct ds_input_device *dev); +struct ds_touch * +ds_input_device_get_touch(struct ds_input_device *dev); + void ds_input_device_add_destroy_listener(struct ds_input_device *dev, struct wl_listener *listener); diff --git a/include/libds/interfaces/input_device.h b/include/libds/interfaces/input_device.h index 7828503..e39fecc 100644 --- a/include/libds/interfaces/input_device.h +++ b/include/libds/interfaces/input_device.h @@ -5,6 +5,7 @@ #include #include #include +#include struct ds_input_device_interface { @@ -24,6 +25,7 @@ struct ds_input_device void *_device; struct ds_pointer *pointer; struct ds_keyboard *keyboard; + struct ds_touch *touch; }; struct { diff --git a/include/libds/interfaces/touch.h b/include/libds/interfaces/touch.h new file mode 100644 index 0000000..25ff4e6 --- /dev/null +++ b/include/libds/interfaces/touch.h @@ -0,0 +1,30 @@ +#ifndef LIBDS_INTERFACES_TOUCH_H +#define LIBDS_INTERFACES_TOUCH_H + +#include + +struct ds_touch; + +struct ds_touch_interface +{ + void (*destroy)(struct ds_touch *touch); +}; + +struct ds_touch +{ + const struct ds_touch_interface *iface; + + struct { + struct wl_signal down; + struct wl_signal up; + struct wl_signal motion; + struct wl_signal frame; + } events; +}; + +void ds_touch_init(struct ds_touch *touch, + const struct ds_touch_interface *iface); + +void ds_touch_destroy(struct ds_touch *touch); + +#endif diff --git a/include/libds/touch.h b/include/libds/touch.h new file mode 100644 index 0000000..4b69b90 --- /dev/null +++ b/include/libds/touch.h @@ -0,0 +1,46 @@ +#ifndef LIBDS_TOUCH_H +#define LIBDS_TOUCH_H + +#include +#include +#include + +struct ds_touch; + +struct ds_event_touch_down +{ + struct ds_input_device *device; + uint32_t time_msec; + //wl_surface surface; + uint32_t id; + double x, y; +}; + +struct ds_event_touch_up +{ + struct ds_input_device *device; + uint32_t time_msec; + uint32_t id; +}; + +struct ds_event_touch_motion +{ + struct ds_input_device *device; + uint32_t time_msec; + uint32_t id; + double x, y; +}; + +void ds_touch_add_down_listener(struct ds_touch *touch, + struct wl_listener *listener); + +void ds_touch_add_up_listener(struct ds_touch *touch, + struct wl_listener *listener); + +void ds_touch_add_motion_listener(struct ds_touch *touch, + struct wl_listener *listener); + +void ds_touch_add_frame_listener(struct ds_touch *touch, + struct wl_listener *listener); + +#endif diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index cfa55a6..61366fb 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -19,6 +19,7 @@ #include #include #include +#include #define TINYDS_UNUSED __attribute__((unused)) @@ -36,6 +37,17 @@ struct tinyds_keyboard struct wl_listener key; }; +struct tinyds_touch +{ + struct ds_input_device *dev; + struct tinyds_server *server; + + struct wl_listener destroy; + struct wl_listener down; + struct wl_listener up; + struct wl_listener motion; +}; + struct tinyds_output { struct tinyds_server *server; @@ -539,6 +551,67 @@ server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev) } static void +touch_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_touch *touch; + + touch = wl_container_of(listener, touch, destroy); + + ds_inf("Touch(%p) destroyed", touch); + + wl_list_remove(&touch->destroy.link); + wl_list_remove(&touch->down.link); + wl_list_remove(&touch->up.link); + wl_list_remove(&touch->motion.link); + + free(touch); +} + +static void +touch_handle_down(struct wl_listener *listener, void *data) +{ + ds_inf("Touch device(%p): down", data); +} + +static void +touch_handle_up(struct wl_listener *listener, void *data) +{ + ds_inf("Touch device(%p): up", data); +} + +static void +touch_handle_motion(struct wl_listener *listener, void *data) +{ + ds_inf("Touch device(%p): motion", data); +} + +static void +server_add_touch(struct tinyds_server *server, struct ds_input_device *dev) +{ + struct tinyds_touch *touch; + + touch = calloc(1, sizeof *touch); + assert(touch); + + touch->dev = dev; + touch->server = server; + + touch->destroy.notify = touch_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &touch->destroy); + + touch->down.notify = touch_handle_down; + ds_touch_add_down_listener(ds_input_device_get_touch(dev), &touch->down); + + touch->up.notify = touch_handle_up; + ds_touch_add_up_listener(ds_input_device_get_touch(dev), &touch->up); + + touch->motion.notify = touch_handle_motion; + ds_touch_add_motion_listener(ds_input_device_get_touch(dev), &touch->motion); + + ds_inf("Touch(%p) added", touch); +} + +static void server_handle_new_input(struct wl_listener *listener, void *data) { struct tinyds_server *server; @@ -552,6 +625,9 @@ server_handle_new_input(struct wl_listener *listener, void *data) case DS_INPUT_DEVICE_KEYBOARD: server_add_keyboard(server, dev); break; + case DS_INPUT_DEVICE_TOUCH: + server_add_touch(server, dev); + break; default: ds_err("Unknown type(%d) of ds_input_device", dev_type); break; diff --git a/src/libds/backend/wayland/backend.h b/src/libds/backend/wayland/backend.h index c35f7d1..804fa22 100644 --- a/src/libds/backend/wayland/backend.h +++ b/src/libds/backend/wayland/backend.h @@ -6,6 +6,7 @@ #include "libds/interfaces/input_device.h" #include "libds/interfaces/pointer.h" #include "libds/interfaces/keyboard.h" +#include "libds/interfaces/touch.h" struct ds_wl_backend_server { @@ -111,6 +112,13 @@ struct ds_wl_keyboard struct wl_keyboard *wl_keyboard; }; +struct ds_wl_touch +{ + struct ds_touch base; + + struct wl_touch *wl_touch; +}; + struct ds_wl_backend * wl_backend_from_backend(struct ds_backend *backend); diff --git a/src/libds/backend/wayland/seat.c b/src/libds/backend/wayland/seat.c index 966bf77..6948efc 100644 --- a/src/libds/backend/wayland/seat.c +++ b/src/libds/backend/wayland/seat.c @@ -9,6 +9,7 @@ #include "libds/log.h" #include "libds/pointer.h" +#include "libds/touch.h" #include "util.h" #include "backend.h" @@ -29,6 +30,7 @@ create_wl_input_device(struct ds_wl_seat *seat, enum ds_input_device_type type); static struct ds_pointer *create_wl_pointer(struct ds_wl_seat *seat); static struct ds_keyboard *create_wl_keyboard(struct ds_wl_seat *seat); +static struct ds_touch *create_wl_touch(struct ds_wl_seat *seat); struct ds_wl_seat * create_wl_seat(struct ds_wl_backend *backend, uint32_t id, @@ -171,6 +173,9 @@ seat_update_capabilities(struct ds_wl_seat *seat, enum wl_seat_capability caps) ds_dbg("wl_backend: Seat(%p) offered touch", seat); seat->touch_dev = create_wl_input_device(seat, DS_INPUT_DEVICE_TOUCH); + seat->touch_dev->touch = create_wl_touch(seat); + wl_signal_emit(&seat->backend->base.events.new_input, + seat->touch_dev); } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch_dev != NULL) { @@ -601,3 +606,111 @@ create_wl_keyboard(struct ds_wl_seat *seat) return &keyboard->base; } + +static const struct ds_touch_interface touch_iface; + +static struct ds_wl_touch * +get_wl_touch_from_touch(struct ds_touch *ds_touch) +{ + assert(ds_touch->iface == &touch_iface); + return (struct ds_wl_touch *)ds_touch; +} + +static void +touch_iface_destroy(struct ds_touch *ds_touch) +{ + struct ds_wl_touch *touch; + + touch = get_wl_touch_from_touch(ds_touch); + + wl_touch_release(touch->wl_touch); + + free(touch); +} + +static const struct ds_touch_interface touch_iface = { + .destroy = touch_iface_destroy, +}; + +static void +touch_handle_down(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, + struct wl_surface *surface, int32_t id, + wl_fixed_t fixed_x, wl_fixed_t fixed_y) +{ + struct ds_wl_seat *seat = data; + + ds_dbg("wl_touch: down"); + + struct ds_event_touch_down event = { + .device = seat->touch_dev, + .id = id, + .x = fixed_x, + .y = fixed_y, + }; + + wl_signal_emit(&seat->touch_dev->touch->events.down, &event); +} + +static void +touch_handle_up(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, int32_t id) +{ + struct ds_wl_seat *seat = data; + + ds_dbg("wl_touch: up"); + + struct ds_event_touch_up event = { + .device = seat->touch_dev, + .id = id, + }; + + wl_signal_emit(&seat->touch_dev->touch->events.up, &event); +} + +static void +touch_handle_motion(void *data, struct wl_touch *wl_touch, + uint32_t time, int32_t id, + wl_fixed_t fixed_x, wl_fixed_t fixed_y) +{ + ds_dbg("wl_touch: motion"); +} + +static void +touch_handle_frame(void *data, struct wl_touch *wl_touch) +{ + ds_dbg("wl_touch: frame"); +} + +static void +touch_handle_cancel(void *data, struct wl_touch *wl_touch) +{ + ds_dbg("wl_touch: cancel"); +} + +static const struct wl_touch_listener wl_touch_listener = { + .down = touch_handle_down, + .up = touch_handle_up, + .motion = touch_handle_motion, + .frame = touch_handle_frame, + .cancel = touch_handle_cancel, +}; + +static struct ds_touch * +create_wl_touch(struct ds_wl_seat *seat) +{ + struct ds_wl_touch *touch; + + touch = calloc(1, sizeof *touch); + if (!touch) { + ds_err("Could not allocate memory"); + return NULL; + } + + ds_touch_init(&touch->base, &touch_iface); + + touch->wl_touch = wl_seat_get_touch(seat->wl_seat); + wl_touch_add_listener(touch->wl_touch, &wl_touch_listener, seat); + + return &touch->base; +} diff --git a/src/libds/input_device.c b/src/libds/input_device.c index 351361f..ad18e71 100644 --- a/src/libds/input_device.c +++ b/src/libds/input_device.c @@ -7,6 +7,7 @@ #include "libds/interfaces/input_device.h" #include "libds/interfaces/pointer.h" #include "libds/interfaces/keyboard.h" +#include "libds/interfaces/touch.h" WL_EXPORT enum ds_input_device_type ds_input_device_get_type(struct ds_input_device *dev) @@ -36,6 +37,17 @@ ds_input_device_get_keyboard(struct ds_input_device *dev) return dev->keyboard; } +WL_EXPORT struct ds_touch * +ds_input_device_get_touch(struct ds_input_device *dev) +{ + if (dev->type != DS_INPUT_DEVICE_TOUCH) { + ds_err("Given ds_input_device is not a touch device"); + return NULL; + } + + return dev->touch; +} + WL_EXPORT void ds_input_device_add_destroy_listener(struct ds_input_device *dev, struct wl_listener *listener) diff --git a/src/libds/meson.build b/src/libds/meson.build index 4d1ae39..be07132 100644 --- a/src/libds/meson.build +++ b/src/libds/meson.build @@ -21,6 +21,7 @@ libds_files = [ 'input_device.c', 'pointer.c', 'keyboard.c', + 'touch.c', ] protocols = { diff --git a/src/libds/touch.c b/src/libds/touch.c new file mode 100644 index 0000000..72a3660 --- /dev/null +++ b/src/libds/touch.c @@ -0,0 +1,55 @@ +#include +#include +#include "libds/interfaces/touch.h" + +void +ds_touch_init(struct ds_touch *touch, + const struct ds_touch_interface *iface) +{ + touch->iface = iface; + + wl_signal_init(&touch->events.down); + wl_signal_init(&touch->events.up); + wl_signal_init(&touch->events.motion); + wl_signal_init(&touch->events.frame); +} + +void +ds_touch_destroy(struct ds_touch *touch) +{ + if (!touch) + return; + + if (touch->iface && touch->iface->destroy) + touch->iface->destroy(touch); + else + free(touch); +} + +WL_EXPORT void +ds_touch_add_down_listener(struct ds_touch *touch, + struct wl_listener *listener) +{ + wl_signal_add(&touch->events.down, listener); +} + +WL_EXPORT void +ds_touch_add_up_listener(struct ds_touch *touch, + struct wl_listener *listener) +{ + wl_signal_add(&touch->events.up, listener); +} + +WL_EXPORT void +ds_touch_add_motion_listener(struct ds_touch *touch, + struct wl_listener *listener) +{ + wl_signal_add(&touch->events.motion, listener); +} + +WL_EXPORT void +ds_touch_add_frame_listener(struct ds_touch *touch, + struct wl_listener *listener) +{ + wl_signal_add(&touch->events.frame, listener); +} -- 2.7.4 From 2e9b47c8b8262eab508154877fa51272c40334f5 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 20 Apr 2022 18:10:04 +0900 Subject: [PATCH 05/16] examples/tinyds: Remove redundant referencing ds_buffer ds_buffer is supposed to be referenced by ds_output while using it, so tinyds doesn't have any reasons to reference a ds_buffer for the output. Change-Id: Ic1183d1517fb89711e0a53d3c3271ea2a1f598e9 --- src/examples/tinyds.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index 61366fb..ed3ed01 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -54,7 +54,6 @@ struct tinyds_output struct ds_output *ds_output; struct ds_allocator *allocator; struct ds_swapchain *swapchain; - struct ds_buffer *front_buffer; struct wl_listener output_destroy; struct wl_listener output_frame; @@ -325,7 +324,6 @@ init_output(struct tinyds_output *output, struct tinyds_server *server, output->server = server; output->width = width; output->height = height; - output->front_buffer = NULL; output->drawable = true; output->damaged = true; @@ -365,8 +363,6 @@ static void fini_output(struct tinyds_output *output) { wl_list_remove(&output->link); - if (output->front_buffer) - ds_buffer_unlock(output->front_buffer); if (output->ds_output) ds_output_destroy(output->ds_output); ds_swapchain_destroy(output->swapchain); @@ -411,10 +407,8 @@ draw_output(struct tinyds_output *output) output_image = pixman_image_from_buffer(output_buffer, DS_BUFFER_DATA_PTR_ACCESS_WRITE); - if (!output_image) { - ds_buffer_unlock(output_buffer); - return; - } + if (!output_image) + goto out; pixman_image_fill_color(output_image, 80, 80, 80); @@ -428,12 +422,11 @@ draw_output(struct tinyds_output *output) ds_output_attach_buffer(output->ds_output, output_buffer); ds_output_commit(output->ds_output); - if (output->front_buffer) - ds_buffer_unlock(output->front_buffer); - output->front_buffer = output_buffer; - output->drawable = false; output->damaged = false; + +out: + ds_buffer_unlock(output_buffer); } static void -- 2.7.4 From 50da8eacd8db81228b628a8a187af60629299287 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 20 Apr 2022 19:54:19 +0900 Subject: [PATCH 06/16] examples/tinyds: Clarify single output support tinyds doesn't support multiple outputs for now, so don't pretend to support multiple outputs. Change-Id: Ic28b275423e5618677f34373ad677ad387a7f754 --- src/examples/tinyds.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index ed3ed01..0c88849 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -57,7 +57,6 @@ struct tinyds_output struct wl_listener output_destroy; struct wl_listener output_frame; - struct wl_list link; // tinyds_server::outputs int width, height; @@ -73,10 +72,9 @@ struct tinyds_server struct ds_compositor *compositor; struct ds_xdg_shell *xdg_shell; - struct tinyds_output primary_output; + struct tinyds_output output; struct wl_list views; - struct wl_list outputs; struct wl_listener new_input; struct wl_listener new_xdg_surface; @@ -127,7 +125,7 @@ main(void) assert(init_server(server, display) == true); - assert(init_output(&server->primary_output, server, + assert(init_output(&server->output, server, OUTPUT_WIDTH, OUTPUT_HEIGHT) == true); socket = wl_display_add_socket_auto(display); @@ -143,7 +141,7 @@ main(void) wl_display_run(server->display); - fini_output(&server->primary_output); + fini_output(&server->output); fini_server(server); wl_display_destroy(display); @@ -256,7 +254,6 @@ init_server(struct tinyds_server *server, struct wl_display *display) { server->display = display; - wl_list_init(&server->outputs); wl_list_init(&server->views); if (wl_display_init_shm(display) != 0) @@ -347,8 +344,6 @@ init_output(struct tinyds_output *output, struct tinyds_server *server, output->output_frame.notify = output_handle_frame; ds_output_add_frame_listener(output->ds_output, &output->output_frame); - wl_list_insert(&server->outputs, &output->link); - return true; err_output: @@ -362,7 +357,6 @@ err_swapchain: static void fini_output(struct tinyds_output *output) { - wl_list_remove(&output->link); if (output->ds_output) ds_output_destroy(output->ds_output); ds_swapchain_destroy(output->swapchain); @@ -372,21 +366,16 @@ fini_output(struct tinyds_output *output) static void draw_server(struct tinyds_server *server) { - struct tinyds_output *output; - - wl_list_for_each(output, &server->outputs, link) - draw_output(output); + draw_output(&server->output); } static void draw_server_with_damage(struct tinyds_server *server) { - struct tinyds_output *output; + struct tinyds_output *output = &server->output; - wl_list_for_each(output, &server->outputs, link) { - output->damaged = true; - draw_output(output); - } + output->damaged = true; + draw_output(output); } static void view_send_frame_done(struct tinyds_view *view); -- 2.7.4 From 30ae9d060f4c9f7453111e9b61c34b59821b36d8 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 20 Apr 2022 20:11:59 +0900 Subject: [PATCH 07/16] examples/tinyds: Clean up all views when finish server Even though all view would have been cleaned up by an destroy event of xdg_surface, this is just to clean up views explicitly just in case. No functional changes. Change-Id: I3a91adb68d665b334c56f607975734a7e95dbcfd --- src/examples/tinyds.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index 0c88849..64aac83 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -109,6 +109,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data); static void draw_server(struct tinyds_server *server); static void draw_server_with_damage(struct tinyds_server *server); static void draw_output(struct tinyds_output *output); +static void view_destroy(struct tinyds_view *view); static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); int @@ -195,12 +196,7 @@ view_handle_xdg_surface_destroy(struct wl_listener *listener, draw_server_with_damage(view->server); - wl_list_remove(&view->xdg_surface_destroy.link); - wl_list_remove(&view->xdg_surface_map.link); - wl_list_remove(&view->xdg_surface_unmap.link); - wl_list_remove(&view->surface_commit.link); - wl_list_remove(&view->link); - free(view); + view_destroy(view); } static void @@ -288,6 +284,11 @@ init_server(struct tinyds_server *server, struct wl_display *display) static void fini_server(struct tinyds_server *server) { + struct tinyds_view *view, *tmp; + + wl_list_for_each_safe(view, tmp, &server->views, link) + view_destroy(view); + wl_list_remove(&server->new_xdg_surface.link); } @@ -419,6 +420,19 @@ out: } static void +view_destroy(struct tinyds_view *view) +{ + ds_inf("View(%p) destroyed", view); + + wl_list_remove(&view->xdg_surface_destroy.link); + wl_list_remove(&view->xdg_surface_map.link); + wl_list_remove(&view->xdg_surface_unmap.link); + wl_list_remove(&view->surface_commit.link); + wl_list_remove(&view->link); + free(view); +} + +static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image) { struct ds_buffer *buffer; -- 2.7.4 From fa3a6ff77ffc08840757cf6070055c3ef493da10 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 20 Apr 2022 20:16:37 +0900 Subject: [PATCH 08/16] examples/tinyds: Enhance readability No functional changes - Use a first argument of function as a prefix of function name. - Rename some of function name more clearly. - Remove forward declaration of event handlers. Change-Id: Id6c6dc54b638817caf47d4ba50692149e7ac9c7e --- src/examples/tinyds.c | 512 +++++++++++++++++++++++++------------------------- 1 file changed, 255 insertions(+), 257 deletions(-) diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index 64aac83..77ede91 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -96,26 +96,24 @@ struct tinyds_view bool mapped; }; -struct tinyds_server _tinyds; - -static bool init_server(struct tinyds_server *server, struct wl_display *display); -static void fini_server(struct tinyds_server *server); -static void server_handle_new_input(struct wl_listener *listener, void *data); -static bool init_output(struct tinyds_output *output, struct tinyds_server *server, - int width, int height); -static void fini_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 draw_server(struct tinyds_server *server); -static void draw_server_with_damage(struct tinyds_server *server); -static void draw_output(struct tinyds_output *output); +static bool server_init(struct tinyds_server *server, + struct wl_display *display); +static void server_fini(struct tinyds_server *server); +static void server_add_view(struct tinyds_server *server, + struct ds_xdg_surface *xdg_surface); +static bool output_init(struct tinyds_output *output, + struct tinyds_server *server, int width, int height); +static void output_fini(struct tinyds_output *output); +static void output_damage(struct tinyds_output *output); +static void output_redraw(struct tinyds_output *output); static void view_destroy(struct tinyds_view *view); -static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); +static void view_composite(struct tinyds_view *view, + pixman_image_t *dst_image); int main(void) { - struct tinyds_server *server = &_tinyds; + struct tinyds_server server; struct wl_display *display; const char *socket; @@ -124,33 +122,30 @@ main(void) display = wl_display_create(); assert(display); - assert(init_server(server, display) == true); - - assert(init_output(&server->output, server, - OUTPUT_WIDTH, OUTPUT_HEIGHT) == true); + assert(server_init(&server, display) == true); socket = wl_display_add_socket_auto(display); assert(socket); - ds_backend_start(server->backend); + ds_backend_start(server.backend); - draw_server(server); + output_damage(&server.output); + output_redraw(&server.output); setenv("WAYLAND_DISPLAY", socket, true); ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket); - wl_display_run(server->display); + wl_display_run(server.display); - fini_output(&server->output); - fini_server(server); + server_fini(&server); wl_display_destroy(display); return 0; } static struct ds_backend * -tinyds_create_backend_auto(struct wl_display *display) +create_wl_backend(struct wl_display *display) { struct ds_backend *backend = NULL; char name[512]; @@ -167,6 +162,170 @@ tinyds_create_backend_auto(struct wl_display *display) } static void +keyboard_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_keyboard *kbd; + + kbd = wl_container_of(listener, kbd, destroy); + + ds_inf("Keyboard(%p) destroyed", kbd); + + wl_list_remove(&kbd->destroy.link); + wl_list_remove(&kbd->key.link); + + free(kbd); +} + +static bool +server_handle_keybinding(struct tinyds_server *server, xkb_keysym_t sym) +{ + switch (sym) { + case XKB_KEY_BackSpace: + wl_display_terminate(server->display); + break; + default: + return false; + } + + return true; +} + +static void +keyboard_handle_key(struct wl_listener *listener, void *data) +{ + struct tinyds_keyboard *kbd; + struct ds_event_keyboard_key *event = data; + struct ds_keyboard *ds_keyboard; + struct xkb_state *xkb_state; + const xkb_keysym_t *syms; + uint32_t modifiers; + int nsyms; + + kbd = wl_container_of(listener, kbd, key); + + ds_keyboard = ds_input_device_get_keyboard(kbd->dev); + + modifiers = ds_keyboard_get_modifiers(ds_keyboard); + if ((modifiers & DS_MODIFIER_CTRL) && + (modifiers & DS_MODIFIER_ALT) && + (modifiers & DS_MODIFIER_SHIFT) && + event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + xkb_state = ds_keyboard_get_xkb_state(ds_keyboard); + if (xkb_state) { + nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8, + &syms); + for (int i = 0; i < nsyms; i++) { + server_handle_keybinding(kbd->server, syms[i]); + } + } + } +} + +static void +server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev) +{ + struct tinyds_keyboard *kbd; + + kbd = calloc(1, sizeof *kbd); + assert(kbd); + + kbd->dev = dev; + kbd->server = server; + + kbd->destroy.notify = keyboard_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &kbd->destroy); + + kbd->key.notify = keyboard_handle_key; + ds_keyboard_add_key_listener(ds_input_device_get_keyboard(dev), &kbd->key); + + ds_inf("Keyboard(%p) added", kbd); +} + +static void +touch_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_touch *touch; + + touch = wl_container_of(listener, touch, destroy); + + ds_inf("Touch(%p) destroyed", touch); + + wl_list_remove(&touch->destroy.link); + wl_list_remove(&touch->down.link); + wl_list_remove(&touch->up.link); + wl_list_remove(&touch->motion.link); + + free(touch); +} + +static void +touch_handle_down(struct wl_listener *listener, void *data) +{ + ds_inf("Touch device(%p): down", data); +} + +static void +touch_handle_up(struct wl_listener *listener, void *data) +{ + ds_inf("Touch device(%p): up", data); +} + +static void +touch_handle_motion(struct wl_listener *listener, void *data) +{ + ds_inf("Touch device(%p): motion", data); +} + +static void +server_add_touch(struct tinyds_server *server, struct ds_input_device *dev) +{ + struct tinyds_touch *touch; + + touch = calloc(1, sizeof *touch); + assert(touch); + + touch->dev = dev; + touch->server = server; + + touch->destroy.notify = touch_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &touch->destroy); + + touch->down.notify = touch_handle_down; + ds_touch_add_down_listener(ds_input_device_get_touch(dev), &touch->down); + + touch->up.notify = touch_handle_up; + ds_touch_add_up_listener(ds_input_device_get_touch(dev), &touch->up); + + touch->motion.notify = touch_handle_motion; + ds_touch_add_motion_listener(ds_input_device_get_touch(dev), &touch->motion); + + ds_inf("Touch(%p) added", touch); +} + +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; + + server = wl_container_of(listener, server, new_input); + + dev_type = ds_input_device_get_type(dev); + switch (dev_type) { + case DS_INPUT_DEVICE_KEYBOARD: + server_add_keyboard(server, dev); + break; + case DS_INPUT_DEVICE_TOUCH: + server_add_touch(server, dev); + break; + default: + ds_err("Unknown type(%d) of ds_input_device", dev_type); + break; + } +} + +static void view_handle_xdg_surface_map(struct wl_listener *listener, void *data TINYDS_UNUSED) { @@ -194,7 +353,8 @@ view_handle_xdg_surface_destroy(struct wl_listener *listener, view = wl_container_of(listener, view, xdg_surface_destroy); - draw_server_with_damage(view->server); + output_damage(&view->server->output); + output_redraw(&view->server->output); view_destroy(view); } @@ -206,47 +366,23 @@ view_handle_surface_commit(struct wl_listener *listener, struct tinyds_view *view; view = wl_container_of(listener, view, surface_commit); - draw_server_with_damage(view->server); + + output_damage(&view->server->output); + output_redraw(&view->server->output); } static void server_new_xdg_surface(struct wl_listener *listener, void *data) { struct tinyds_server *server; - struct tinyds_view *view; - struct ds_xdg_surface *xdg_surface; server = wl_container_of(listener, server, new_xdg_surface); - xdg_surface = data; - - ds_inf("New xdg_surface(%p)", (void *)xdg_surface); - - view = calloc(1, sizeof *view); - view->server = server; - view->xdg_surface = xdg_surface; - - view->xdg_surface_map.notify = view_handle_xdg_surface_map; - ds_xdg_surface_add_map_listener(xdg_surface, - &view->xdg_surface_map); - - view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap; - ds_xdg_surface_add_unmap_listener(xdg_surface, - &view->xdg_surface_unmap); - - view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy; - ds_xdg_surface_add_destroy_listener(xdg_surface, - &view->xdg_surface_destroy); - view->surface_commit.notify = view_handle_surface_commit; - ds_surface_add_commit_listener( - ds_xdg_surface_get_surface(xdg_surface), - &view->surface_commit); - - wl_list_insert(server->views.prev, &view->link); + server_add_view(server, (struct ds_xdg_surface *)data); } static bool -init_server(struct tinyds_server *server, struct wl_display *display) +server_init(struct tinyds_server *server, struct wl_display *display) { server->display = display; @@ -255,40 +391,46 @@ init_server(struct tinyds_server *server, struct wl_display *display) if (wl_display_init_shm(display) != 0) return false; - server->backend = tinyds_create_backend_auto(display); + server->backend = create_wl_backend(display); if (!server->backend) return false; server->new_input.notify = server_handle_new_input; ds_backend_add_new_input_listener(server->backend, &server->new_input); + if (!output_init(&server->output, server, OUTPUT_WIDTH, OUTPUT_HEIGHT)) + goto err; + server->compositor = ds_compositor_create(display); - if (!server->compositor) { - ds_backend_destroy(server->backend); - return false; - } + if (!server->compositor) + goto err; server->xdg_shell = ds_xdg_shell_create(display); - if (!server->xdg_shell) { - ds_backend_destroy(server->backend); - return false; - } + if (!server->xdg_shell) + goto err; server->new_xdg_surface.notify = server_new_xdg_surface; ds_xdg_shell_add_new_surface_listener(server->xdg_shell, &server->new_xdg_surface); return true; + +err: + ds_backend_destroy(server->backend); + + return false; } static void -fini_server(struct tinyds_server *server) +server_fini(struct tinyds_server *server) { struct tinyds_view *view, *tmp; wl_list_for_each_safe(view, tmp, &server->views, link) view_destroy(view); + output_fini(&server->output); + wl_list_remove(&server->new_xdg_surface.link); } @@ -312,18 +454,17 @@ output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED) wl_container_of(listener, output, output_frame); output->drawable = true; - draw_output(output); + output_redraw(output); } static bool -init_output(struct tinyds_output *output, struct tinyds_server *server, +output_init(struct tinyds_output *output, struct tinyds_server *server, int width, int height) { output->server = server; output->width = width; output->height = height; output->drawable = true; - output->damaged = true; output->allocator = ds_shm_allocator_create(); if (!output->allocator) @@ -356,7 +497,7 @@ err_swapchain: } static void -fini_output(struct tinyds_output *output) +output_fini(struct tinyds_output *output) { if (output->ds_output) ds_output_destroy(output->ds_output); @@ -365,24 +506,13 @@ fini_output(struct tinyds_output *output) } static void -draw_server(struct tinyds_server *server) +output_damage(struct tinyds_output *output) { - draw_output(&server->output); -} - -static void -draw_server_with_damage(struct tinyds_server *server) -{ - struct tinyds_output *output = &server->output; - output->damaged = true; - draw_output(output); } -static void view_send_frame_done(struct tinyds_view *view); - static void -draw_output(struct tinyds_output *output) +output_redraw(struct tinyds_output *output) { struct ds_buffer *output_buffer; pixman_image_t *output_image; @@ -405,7 +535,7 @@ draw_output(struct tinyds_output *output) wl_list_for_each(view, &output->server->views, link) { if (!view->mapped) continue; - draw_view(view, output_image); + view_composite(view, output_image); } pixman_image_unref(output_image); @@ -420,6 +550,37 @@ out: } static void +server_add_view(struct tinyds_server *server, struct ds_xdg_surface *xdg_surface) +{ + struct tinyds_view *view; + + view = calloc(1, sizeof *view); + view->server = server; + view->xdg_surface = xdg_surface; + + view->xdg_surface_map.notify = view_handle_xdg_surface_map; + ds_xdg_surface_add_map_listener(xdg_surface, + &view->xdg_surface_map); + + view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap; + ds_xdg_surface_add_unmap_listener(xdg_surface, + &view->xdg_surface_unmap); + + view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy; + ds_xdg_surface_add_destroy_listener(xdg_surface, + &view->xdg_surface_destroy); + + view->surface_commit.notify = view_handle_surface_commit; + ds_surface_add_commit_listener( + ds_xdg_surface_get_surface(xdg_surface), + &view->surface_commit); + + wl_list_insert(server->views.prev, &view->link); + + ds_inf("View(%p) added", view); +} + +static void view_destroy(struct tinyds_view *view) { ds_inf("View(%p) destroyed", view); @@ -433,7 +594,17 @@ view_destroy(struct tinyds_view *view) } static void -draw_view(struct tinyds_view *view, pixman_image_t *dst_image) +view_send_frame_done(struct tinyds_view *view) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface), + &now); +} + +static void +view_composite(struct tinyds_view *view, pixman_image_t *dst_image) { struct ds_buffer *buffer; pixman_image_t *src_image; @@ -456,176 +627,3 @@ draw_view(struct tinyds_view *view, pixman_image_t *dst_image) view_send_frame_done(view); } - -static void -view_send_frame_done(struct tinyds_view *view) -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface), - &now); -} - -static void -keyboard_handle_device_destroy(struct wl_listener *listener, void *data) -{ - struct tinyds_keyboard *kbd; - - kbd = wl_container_of(listener, kbd, destroy); - - ds_inf("Keyboard(%p) destroyed", kbd); - - wl_list_remove(&kbd->destroy.link); - wl_list_remove(&kbd->key.link); - - free(kbd); -} - -static bool -server_handle_keybinding(struct tinyds_server *server, xkb_keysym_t sym) -{ - switch (sym) { - case XKB_KEY_BackSpace: - wl_display_terminate(server->display); - break; - default: - return false; - } - - return true; -} - -static void -keyboard_handle_key(struct wl_listener *listener, void *data) -{ - struct tinyds_keyboard *kbd; - struct ds_event_keyboard_key *event = data; - struct ds_keyboard *ds_keyboard; - struct xkb_state *xkb_state; - const xkb_keysym_t *syms; - uint32_t modifiers; - int nsyms; - - kbd = wl_container_of(listener, kbd, key); - - ds_keyboard = ds_input_device_get_keyboard(kbd->dev); - - modifiers = ds_keyboard_get_modifiers(ds_keyboard); - if ((modifiers & DS_MODIFIER_CTRL) && - (modifiers & DS_MODIFIER_ALT) && - (modifiers & DS_MODIFIER_SHIFT) && - event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { - xkb_state = ds_keyboard_get_xkb_state(ds_keyboard); - if (xkb_state) { - nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8, - &syms); - for (int i = 0; i < nsyms; i++) { - server_handle_keybinding(kbd->server, syms[i]); - } - } - } -} - -static void -server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev) -{ - struct tinyds_keyboard *kbd; - - kbd = calloc(1, sizeof *kbd); - assert(kbd); - - kbd->dev = dev; - kbd->server = server; - - kbd->destroy.notify = keyboard_handle_device_destroy; - ds_input_device_add_destroy_listener(dev, &kbd->destroy); - - kbd->key.notify = keyboard_handle_key; - ds_keyboard_add_key_listener(ds_input_device_get_keyboard(dev), &kbd->key); - - ds_inf("Keyboard(%p) added", kbd); -} - -static void -touch_handle_device_destroy(struct wl_listener *listener, void *data) -{ - struct tinyds_touch *touch; - - touch = wl_container_of(listener, touch, destroy); - - ds_inf("Touch(%p) destroyed", touch); - - wl_list_remove(&touch->destroy.link); - wl_list_remove(&touch->down.link); - wl_list_remove(&touch->up.link); - wl_list_remove(&touch->motion.link); - - free(touch); -} - -static void -touch_handle_down(struct wl_listener *listener, void *data) -{ - ds_inf("Touch device(%p): down", data); -} - -static void -touch_handle_up(struct wl_listener *listener, void *data) -{ - ds_inf("Touch device(%p): up", data); -} - -static void -touch_handle_motion(struct wl_listener *listener, void *data) -{ - ds_inf("Touch device(%p): motion", data); -} - -static void -server_add_touch(struct tinyds_server *server, struct ds_input_device *dev) -{ - struct tinyds_touch *touch; - - touch = calloc(1, sizeof *touch); - assert(touch); - - touch->dev = dev; - touch->server = server; - - touch->destroy.notify = touch_handle_device_destroy; - ds_input_device_add_destroy_listener(dev, &touch->destroy); - - touch->down.notify = touch_handle_down; - ds_touch_add_down_listener(ds_input_device_get_touch(dev), &touch->down); - - touch->up.notify = touch_handle_up; - ds_touch_add_up_listener(ds_input_device_get_touch(dev), &touch->up); - - touch->motion.notify = touch_handle_motion; - ds_touch_add_motion_listener(ds_input_device_get_touch(dev), &touch->motion); - - ds_inf("Touch(%p) added", touch); -} - -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; - - server = wl_container_of(listener, server, new_input); - - dev_type = ds_input_device_get_type(dev); - switch (dev_type) { - case DS_INPUT_DEVICE_KEYBOARD: - server_add_keyboard(server, dev); - break; - case DS_INPUT_DEVICE_TOUCH: - server_add_touch(server, dev); - break; - default: - ds_err("Unknown type(%d) of ds_input_device", dev_type); - break; - } -} -- 2.7.4 From 19fc9e8bfa4b7a7dc2f7a5f5eccd8fb4e7e58221 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 21 Apr 2022 14:05:11 +0900 Subject: [PATCH 09/16] examples/tinyds: Handle ds_pointer This adds listeners of ds_pointer and prints logs. Change-Id: I10372862b9111e2cf01f88753e16a5036ffe8406 --- src/examples/tinyds.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index 77ede91..735fc30 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -20,6 +20,7 @@ #include #include #include +#include #define TINYDS_UNUSED __attribute__((unused)) @@ -28,6 +29,18 @@ struct tinyds_server; +struct tinyds_pointer +{ + struct ds_input_device *dev; + struct tinyds_server *server; + + struct wl_listener destroy; + struct wl_listener motion; + struct wl_listener motion_absolute; + struct wl_listener button; + struct wl_listener frame; +}; + struct tinyds_keyboard { struct ds_input_device *dev; @@ -303,6 +316,103 @@ server_add_touch(struct tinyds_server *server, struct ds_input_device *dev) } static void +pointer_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_pointer *pointer; + + pointer = wl_container_of(listener, pointer, destroy); + + ds_inf("Pointer(%p) destroyed", pointer); + + wl_list_remove(&pointer->destroy.link); + wl_list_remove(&pointer->motion.link); + wl_list_remove(&pointer->motion_absolute.link); + wl_list_remove(&pointer->button.link); + wl_list_remove(&pointer->frame.link); + + free(pointer); +} + +static void +pointer_handle_motion(struct wl_listener *listener, void *data) +{ + struct tinyds_pointer *pointer; + + pointer = wl_container_of(listener, pointer, motion); + + ds_inf("Pointer(%p) motion", pointer); +} + +static void +pointer_handle_motion_absolute(struct wl_listener *listener, void *data) +{ + struct tinyds_pointer *pointer; + struct ds_event_pointer_motion_absolute *event = data; + + pointer = wl_container_of(listener, pointer, motion_absolute); + + ds_inf("Pointer(%p) motion absolute: (x %f y %f) time(%d)", + pointer, event->x, event->y, event->time_msec); +} + +static void +pointer_handle_button(struct wl_listener *listener, void *data) +{ + struct tinyds_pointer *pointer; + struct ds_event_pointer_button *event = data; + + pointer = wl_container_of(listener, pointer, button); + + ds_inf("Pointer(%p) button(%d): state(%s) time(%d)", + pointer, event->button, + (event->state == DS_BUTTON_PRESSED) ? "Pressed" : "Released", + event->time_msec); +} + +static void +pointer_handle_frame(struct wl_listener *listener, void *data) +{ + struct tinyds_pointer *pointer; + + pointer = wl_container_of(listener, pointer, motion); + + ds_inf("Pointer(%p) frame", pointer); +} + +static void +server_add_pointer(struct tinyds_server *server, struct ds_input_device *dev) +{ + struct tinyds_pointer *pointer; + + pointer = calloc(1, sizeof *pointer); + assert(pointer); + + pointer->dev = dev; + pointer->server = server; + + pointer->destroy.notify = pointer_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &pointer->destroy); + + pointer->motion.notify = pointer_handle_motion; + ds_pointer_add_motion_listener(ds_input_device_get_pointer(dev), + &pointer->motion); + + pointer->motion_absolute.notify = pointer_handle_motion_absolute; + ds_pointer_add_motion_absolute_listener(ds_input_device_get_pointer(dev), + &pointer->motion_absolute); + + pointer->button.notify = pointer_handle_button; + ds_pointer_add_button_listener(ds_input_device_get_pointer(dev), + &pointer->button); + + pointer->frame.notify = pointer_handle_frame; + ds_pointer_add_frame_listener(ds_input_device_get_pointer(dev), + &pointer->frame); + + ds_inf("Pointer(%p) added", pointer); +} + +static void server_handle_new_input(struct wl_listener *listener, void *data) { struct tinyds_server *server; @@ -319,6 +429,9 @@ server_handle_new_input(struct wl_listener *listener, void *data) case DS_INPUT_DEVICE_TOUCH: server_add_touch(server, dev); break; + case DS_INPUT_DEVICE_POINTER: + server_add_pointer(server, dev); + break; default: ds_err("Unknown type(%d) of ds_input_device", dev_type); break; -- 2.7.4 From ad0d17962c56e51ed7b3e37a4be75d8e08dfc81f Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 21 Apr 2022 16:56:48 +0900 Subject: [PATCH 10/16] backend/wayland: Remove writable flag from event source Instead of having a writable flag on event source, it just marks wayland event source as needing a post-dispatch check. The event loop will call dispatch function again after all dispatching is done, with mask = 0. Change-Id: Iefdff50e2fa06d244f1ca3bffd0faa70da6ef364 --- src/libds/backend/wayland/backend.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libds/backend/wayland/backend.c b/src/libds/backend/wayland/backend.c index d956aa0..3b5d6ab 100644 --- a/src/libds/backend/wayland/backend.c +++ b/src/libds/backend/wayland/backend.c @@ -49,12 +49,13 @@ ds_wl_backend_create(struct wl_display *display, const char *server_name) fd = wl_display_get_fd(wl_backend->server.display); wl_backend->server_event_source = - wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE | WL_EVENT_READABLE, + wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE, wl_backend_handle_dispatch_events, wl_backend); if (!wl_backend->server_event_source) { ds_err("Failed to create event source"); goto err_src; } + wl_event_source_check(wl_backend->server_event_source); wl_backend->display_destroy.notify = wl_backend_handle_display_destroy; wl_display_add_destroy_listener(display, &wl_backend->display_destroy); -- 2.7.4 From c2c065107571ec35bcd667059372e087674b3d16 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 25 Apr 2022 16:06:21 +0900 Subject: [PATCH 11/16] tinyds: Use WAYLAND_DISPLAY and WAYLAND_SOCKET for wl backend Instead of assuming the name of wayland display server by iterating arbitrary number of names, it uses values of WAYLAND_DISPLAY and WAYLAND_SOCKET environments. The library of wayland-client uses these values when trying to connect to wayland server. Change-Id: Ieea1e2e55755ec10b6743568abf274e6a64aaf28 --- src/examples/tinyds.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index 735fc30..1c5ca4f 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -160,18 +160,10 @@ main(void) static struct ds_backend * create_wl_backend(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; - } + if (!getenv("WAYLAND_DISPLAY") && !getenv("WAYLAND_SOCKET")) + return NULL; - return backend; + return ds_wl_backend_create(display, NULL); } static void -- 2.7.4 From 1b8adba47741b76e36bb15d3810631f05d096363 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Fri, 22 Apr 2022 09:17:57 +0900 Subject: [PATCH 12/16] backend/wayland: Implement start() interface of ds_backend The wayland backend defers creating new outputs until a user calls ds_backend_start() even though a user requests creation of output before ds_backend_start(). The wayland backend now emits a signal of new_output if a user calls ds_backend_start(), which is for the behavior of ds_backend_start() to be consistent regardless of the actual running backend. Change-Id: I8d102ee90773c65634e7e360990abf995a156c29 --- src/examples/tinyds.c | 35 ++++++++++++++++++++++------------- src/libds/backend/wayland/backend.c | 17 ++++++++++++++++- src/libds/backend/wayland/backend.h | 4 ++++ src/libds/backend/wayland/output.c | 21 ++++++++++++++++++++- 4 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index 1c5ca4f..fcaabaf 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -89,6 +89,7 @@ struct tinyds_server struct wl_list views; + struct wl_listener new_output; struct wl_listener new_input; struct wl_listener new_xdg_surface; }; @@ -115,7 +116,8 @@ static void server_fini(struct tinyds_server *server); static void server_add_view(struct tinyds_server *server, struct ds_xdg_surface *xdg_surface); static bool output_init(struct tinyds_output *output, - struct tinyds_server *server, int width, int height); + struct tinyds_server *server, struct ds_output *ds_output, + int width, int height); static void output_fini(struct tinyds_output *output); static void output_damage(struct tinyds_output *output); static void output_redraw(struct tinyds_output *output); @@ -167,6 +169,18 @@ create_wl_backend(struct wl_display *display) } static void +server_handle_new_output(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct ds_output *ds_output = data; + + server = wl_container_of(listener, server, new_output); + + assert(output_init(&server->output, server, ds_output, + OUTPUT_WIDTH, OUTPUT_HEIGHT) == true); +} + +static void keyboard_handle_device_destroy(struct wl_listener *listener, void *data) { struct tinyds_keyboard *kbd; @@ -500,11 +514,13 @@ server_init(struct tinyds_server *server, struct wl_display *display) if (!server->backend) return false; + ds_wl_backend_create_output(server->backend); + server->new_input.notify = server_handle_new_input; ds_backend_add_new_input_listener(server->backend, &server->new_input); - if (!output_init(&server->output, server, OUTPUT_WIDTH, OUTPUT_HEIGHT)) - goto err; + server->new_output.notify = server_handle_new_output; + ds_backend_add_new_output_listener(server->backend, &server->new_output); server->compositor = ds_compositor_create(display); if (!server->compositor) @@ -564,9 +580,10 @@ output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED) static bool output_init(struct tinyds_output *output, struct tinyds_server *server, - int width, int height) + struct ds_output *ds_output, int width, int height) { output->server = server; + output->ds_output = ds_output; output->width = width; output->height = height; output->drawable = true; @@ -580,11 +597,6 @@ output_init(struct tinyds_output *output, struct tinyds_server *server, if (!output->swapchain) goto err_swapchain; - output->ds_output = - ds_wl_backend_create_output(server->backend); - if (!output->ds_output) - goto err_output; - output->output_destroy.notify = output_handle_destroy; ds_output_add_destroy_listener(output->ds_output, &output->output_destroy); @@ -593,8 +605,6 @@ output_init(struct tinyds_output *output, struct tinyds_server *server, return true; -err_output: - ds_swapchain_destroy(output->swapchain); err_swapchain: ds_allocator_destroy(output->allocator); @@ -604,8 +614,7 @@ err_swapchain: static void output_fini(struct tinyds_output *output) { - if (output->ds_output) - ds_output_destroy(output->ds_output); + ds_output_destroy(output->ds_output); ds_swapchain_destroy(output->swapchain); ds_allocator_destroy(output->allocator); } diff --git a/src/libds/backend/wayland/backend.c b/src/libds/backend/wayland/backend.c index 3b5d6ab..5719e09 100644 --- a/src/libds/backend/wayland/backend.c +++ b/src/libds/backend/wayland/backend.c @@ -81,6 +81,21 @@ wl_backend_from_backend(struct ds_backend *backend) return (struct ds_wl_backend *)backend; } +static bool +wl_backend_iface_start(struct ds_backend *ds_backend) +{ + struct ds_wl_backend *backend; + + backend = wl_backend_from_backend(ds_backend); + + ds_inf("Starting wayland backend"); + + for (size_t i = 0; i < backend->requested_outputs; i++) + create_wl_output(backend); + + return true; +} + static void wl_backend_destroy(struct ds_wl_backend *backend) { @@ -125,7 +140,7 @@ wl_backend_iface_destroy(struct ds_backend *backend) static const struct ds_backend_interface wl_backend_interface = { - .start = NULL, + .start = wl_backend_iface_start, .destroy = wl_backend_iface_destroy, .get_drm_fd = NULL, }; diff --git a/src/libds/backend/wayland/backend.h b/src/libds/backend/wayland/backend.h index 804fa22..12c8a27 100644 --- a/src/libds/backend/wayland/backend.h +++ b/src/libds/backend/wayland/backend.h @@ -32,6 +32,8 @@ struct ds_wl_backend struct wl_event_source *server_event_source; struct ds_wl_backend_server server; + + size_t requested_outputs; }; struct ds_wl_buffer @@ -122,6 +124,8 @@ struct ds_wl_touch struct ds_wl_backend * wl_backend_from_backend(struct ds_backend *backend); +struct ds_wl_output *create_wl_output(struct ds_wl_backend *backend); + void destroy_wl_buffer(struct ds_wl_buffer *buffer); diff --git a/src/libds/backend/wayland/output.c b/src/libds/backend/wayland/output.c index 36ea5f7..c57820f 100644 --- a/src/libds/backend/wayland/output.c +++ b/src/libds/backend/wayland/output.c @@ -23,6 +23,25 @@ ds_wl_backend_create_output(struct ds_backend *ds_backend) backend = wl_backend_from_backend(ds_backend); + if (!ds_backend->started) { + backend->requested_outputs++; + return NULL; + } + + output = create_wl_output(backend); + if (!output) { + ds_err("Could not create ds_wl_output"); + return NULL; + } + + return &output->base; +} + +struct ds_wl_output * +create_wl_output(struct ds_wl_backend *backend) +{ + struct ds_wl_output *output; + output = calloc(1, sizeof *output); if (!output) { ds_log_errno(DS_ERR, "Could not allocate ds_wl_output"); @@ -72,7 +91,7 @@ ds_wl_backend_create_output(struct ds_backend *ds_backend) ds_dbg("Wayland output(%p) created", output); - return &output->base; + return output; err: ds_output_destroy(&output->base); -- 2.7.4 From d1e6400f7e9b035502257919694a4281dd40fd17 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Tue, 26 Apr 2022 09:22:06 +0900 Subject: [PATCH 13/16] tinyds-tdm: Fix build break Change-Id: I75ab91d3d8195592b3aa661297cd8fa8f80d73f7 --- src/examples/tinyds-tdm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/examples/tinyds-tdm.c b/src/examples/tinyds-tdm.c index c14cb9e..4bc08f1 100644 --- a/src/examples/tinyds-tdm.c +++ b/src/examples/tinyds-tdm.c @@ -105,7 +105,8 @@ static void output_buffer_queue_init(struct tinyds_output *output); static void output_renderer_init(struct tinyds_output *output); static void output_draw_with_renderer(struct tinyds_output *output); #else -static void output_swapchain_init(struct tinyds_output *output); +static void output_swapchain_init(struct tinyds_output *output, + int width, int height, uint32_t format); static void output_draw_with_swapchain(struct tinyds_output *output); static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); #endif @@ -273,7 +274,8 @@ backend_handle_new_output(struct wl_listener *listener, void *data) output_buffer_queue_init(output); output_renderer_init(output); #else - output_swapchain_init(output); + output_swapchain_init(output, mode->width, mode->height, + DRM_FORMAT_XRGB8888); #endif output->output_destroy.notify = output_handle_destroy; @@ -456,13 +458,15 @@ output_draw_with_renderer(struct tinyds_output *output) } #else static void -output_swapchain_init(struct tinyds_output *output) +output_swapchain_init(struct tinyds_output *output, + int width, int height, uint32_t format); + { output->allocator = ds_tbm_allocator_create(); assert(output->allocator); output->swapchain = ds_swapchain_create(output->allocator, - mode->width, mode->height, DRM_FORMAT_XRGB8888); + width, height, format); assert(output->swapchain); } -- 2.7.4 From ac5fa7143dbbb7a956fa2f1c9abae32b1f8809c5 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 4 May 2022 15:31:58 +0900 Subject: [PATCH 14/16] tinyds: Fix passing wrong arg to wl_container_of This led segfault illegally accessing wrong pointer. Change-Id: I28e64be8c0d0abd5ee8e164353a5c038a2c7ce52 --- src/examples/tinyds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index fcaabaf..e054e71 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -380,7 +380,7 @@ pointer_handle_frame(struct wl_listener *listener, void *data) { struct tinyds_pointer *pointer; - pointer = wl_container_of(listener, pointer, motion); + pointer = wl_container_of(listener, pointer, frame); ds_inf("Pointer(%p) frame", pointer); } -- 2.7.4 From 6c6e5e02b50d4c1855981f6bd8df71754f71db40 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 4 May 2022 15:37:27 +0900 Subject: [PATCH 15/16] ds_output: Add ds_output_set_custom_mode Change-Id: Ie55a79f11a1450bae3ff6d83bb735c854459f050 --- include/libds/interfaces/output.h | 14 ++++++++++++ include/libds/output.h | 4 ++++ src/examples/tinyds.c | 2 ++ src/libds/backend/wayland/output.c | 19 ++++++++++++++++ src/libds/backend/wayland/seat.c | 7 ++++-- src/libds/output.c | 45 ++++++++++++++++++++++++++++++++++++-- src/libds/output.h | 11 ++++++++++ 7 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 src/libds/output.h diff --git a/include/libds/interfaces/output.h b/include/libds/interfaces/output.h index 6fb2909..53a4e0c 100644 --- a/include/libds/interfaces/output.h +++ b/include/libds/interfaces/output.h @@ -23,6 +23,12 @@ enum ds_output_state_field DS_OUTPUT_STATE_TRANSFORM = 1 << 5, }; +enum ds_output_state_mode_type +{ + DS_OUTPUT_STATE_MODE_FIXED, + DS_OUTPUT_STATE_MODE_CUSTOM, +}; + struct ds_output_interface { void (*destroy)(struct ds_output *output); @@ -33,7 +39,13 @@ struct ds_output_state { enum ds_output_state_field committed; struct ds_buffer *buffer; + + enum ds_output_state_mode_type mode_type; const struct ds_output_mode *mode; + struct { + int32_t width, height; + int32_t refresh; // mHz, may be zero + } custom_mode; bool enabled; }; @@ -49,6 +61,8 @@ struct ds_output struct ds_buffer *back_buffer, *front_buffer; const struct ds_output_mode *current_mode; + int32_t width, height; + int32_t refresh; // mHz, may be zero struct ds_output_state pending; struct wl_list modes; diff --git a/include/libds/output.h b/include/libds/output.h index cae9f7f..5cf1fce 100644 --- a/include/libds/output.h +++ b/include/libds/output.h @@ -40,6 +40,10 @@ ds_output_set_mode(struct ds_output *output, const struct ds_output_mode *mode); void +ds_output_set_custom_mode(struct ds_output *output, + int32_t width, int32_t height, int32_t refresh); + +void ds_output_add_destroy_listener(struct ds_output *output, struct wl_listener *listener); diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index e054e71..64612a6 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -588,6 +588,8 @@ output_init(struct tinyds_output *output, struct tinyds_server *server, output->height = height; output->drawable = true; + ds_output_set_custom_mode(ds_output, OUTPUT_WIDTH, OUTPUT_HEIGHT, 0); + output->allocator = ds_shm_allocator_create(); if (!output->allocator) return false; diff --git a/src/libds/backend/wayland/output.c b/src/libds/backend/wayland/output.c index c57820f..7728abf 100644 --- a/src/libds/backend/wayland/output.c +++ b/src/libds/backend/wayland/output.c @@ -7,6 +7,7 @@ #include "libds/output.h" #include "xdg-shell-client-protocol.h" +#include "output.h" #include "backend.h" const struct ds_output_interface wl_output_iface; @@ -14,6 +15,8 @@ static const struct xdg_surface_listener wl_output_xdg_surface_listener; static const struct xdg_toplevel_listener wl_output_xdg_toplevel_listener; static void output_update_cursor(struct ds_wl_output *output); +static bool output_set_custom_mode(struct ds_output *ds_output, + int32_t width, int32_t height, int32_t refresh); struct ds_output * ds_wl_backend_create_output(struct ds_backend *ds_backend) @@ -286,6 +289,14 @@ wl_output_iface_commit(struct ds_output *ds_output) output = wl_output_from_output(ds_output); + if (ds_output->pending.committed & DS_OUTPUT_STATE_MODE) { + if (!output_set_custom_mode(ds_output, + ds_output->pending.custom_mode.width, + ds_output->pending.custom_mode.height, + ds_output->pending.custom_mode.refresh)) + return false; + } + ds_buffer = ds_output->pending.buffer; buffer = get_or_create_wl_buffer(output->backend, ds_buffer); if (!buffer) @@ -355,3 +366,11 @@ static const struct xdg_toplevel_listener wl_output_xdg_toplevel_listener = .configure = wl_output_xdg_toplevel_handle_configure, .close = wl_output_xdg_toplevel_handle_close, }; + +static bool output_set_custom_mode(struct ds_output *ds_output, + int32_t width, int32_t height, int32_t refresh) +{ + ds_output_update_custom_mode(ds_output, width, height, 0); + + return true; +} diff --git a/src/libds/backend/wayland/seat.c b/src/libds/backend/wayland/seat.c index 6948efc..bec12ad 100644 --- a/src/libds/backend/wayland/seat.c +++ b/src/libds/backend/wayland/seat.c @@ -313,16 +313,19 @@ pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { struct ds_wl_seat *seat = data; + struct ds_output *ds_output; if (!seat->output) return; + ds_output = &seat->output->base; + // FIXME take size size of a output into account struct ds_event_pointer_motion_absolute event = { .device = seat->pointer_dev, .time_msec = time, - .x = wl_fixed_to_double(sx) / 700, - .y = wl_fixed_to_double(sy) / 400, + .x = wl_fixed_to_double(sx) / ds_output->width, + .y = wl_fixed_to_double(sy) / ds_output->height, }; wl_signal_emit(&seat->pointer_dev->pointer->events.motion_absolute, diff --git a/src/libds/output.c b/src/libds/output.c index bc286f7..d5af56e 100644 --- a/src/libds/output.c +++ b/src/libds/output.c @@ -10,6 +10,7 @@ static void output_handle_display_destroy(struct wl_listener *listener, 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); WL_EXPORT void ds_output_init(struct ds_output *output, struct ds_backend *backend, @@ -100,18 +101,35 @@ ds_output_get_preferred_mode(struct ds_output *output) WL_EXPORT void ds_output_set_mode(struct ds_output *output, const struct ds_output_mode *mode) { - output->pending.mode = NULL; - output->pending.committed &= ~DS_OUTPUT_STATE_MODE; + output_state_clear_mode(&output->pending); if (output->current_mode == mode) { return; } output->pending.committed |= DS_OUTPUT_STATE_MODE; + output->pending.mode_type = DS_OUTPUT_STATE_MODE_FIXED; output->pending.mode = mode; } WL_EXPORT void +ds_output_set_custom_mode(struct ds_output *output, + int32_t width, int32_t height, int32_t refresh) +{ + output_state_clear_mode(&output->pending); + + if (output->width == width && output->height == height && + output->refresh == refresh) + return; + + output->pending.committed |= DS_OUTPUT_STATE_MODE; + output->pending.mode_type = DS_OUTPUT_STATE_MODE_CUSTOM; + output->pending.custom_mode.width = width; + output->pending.custom_mode.height = height; + output->pending.custom_mode.refresh = refresh; +} + +WL_EXPORT void ds_output_add_destroy_listener(struct ds_output *output, struct wl_listener *listener) { @@ -132,6 +150,19 @@ ds_output_add_commit_listener(struct ds_output *output, wl_signal_add(&output->events.commit, listener); } +void +ds_output_update_custom_mode(struct ds_output *output, + int32_t width, int32_t height, int32_t refresh) +{ + if (output->width == width && output->height == height && + output->refresh == refresh) + return; + + output->width = width; + output->height = height; + output->refresh = refresh; +} + static void output_handle_display_destroy(struct wl_listener *listener, void *data) { @@ -172,3 +203,13 @@ output_enable(struct ds_output *output, bool enable) output->pending.committed |= DS_OUTPUT_STATE_ENABLED; output->pending.enabled = enable; } + +static void +output_state_clear_mode(struct ds_output_state *state) +{ + if (!(state->committed & DS_OUTPUT_STATE_MODE)) + return; + + state->mode = NULL; + state->committed &= ~DS_OUTPUT_STATE_MODE; +} diff --git a/src/libds/output.h b/src/libds/output.h new file mode 100644 index 0000000..edf4560 --- /dev/null +++ b/src/libds/output.h @@ -0,0 +1,11 @@ +#ifndef DS_OUTPUT_H +#define DS_OUTPUT_H + +#include + +#include "libds/output.h" + +void ds_output_update_custom_mode(struct ds_output *output, + int32_t width, int32_t height, int32_t refresh); + +#endif -- 2.7.4 From fc468ef9c026c6fc4910de018f81d90cb905d617 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 11 May 2022 16:45:58 +0900 Subject: [PATCH 16/16] add security api which uses cynara The keyrouter and devicemgr has to check the privilege when display server gets the requests from these extensions. For this, security api support the previlege check with cynara. Change-Id: I6086e60e9d611de219b05856da6668bd7510cdc4 --- src/libds-tizen/meson.build | 1 + src/libds-tizen/util.h | 17 ++++ src/libds-tizen/util/meson.build | 1 + src/libds-tizen/util/security.c | 162 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+) create mode 100644 src/libds-tizen/util.h create mode 100644 src/libds-tizen/util/meson.build create mode 100644 src/libds-tizen/util/security.c diff --git a/src/libds-tizen/meson.build b/src/libds-tizen/meson.build index 4f76b68..81370e6 100644 --- a/src/libds-tizen/meson.build +++ b/src/libds-tizen/meson.build @@ -12,6 +12,7 @@ libds_tizen_deps = [ subdir('allocator') subdir('backend') +subdir('util') lib_libds_tizen = shared_library('ds-tizen', libds_tizen_files, dependencies: libds_tizen_deps, diff --git a/src/libds-tizen/util.h b/src/libds-tizen/util.h new file mode 100644 index 0000000..18ad811 --- /dev/null +++ b/src/libds-tizen/util.h @@ -0,0 +1,17 @@ +#ifndef DS_UTIL_H +#define DS_UTIL_H + +#include + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +int +tizen_security_init(void); + +void +tizen_security_finish(void); + +bool +tizen_security_check_privilege(pid_t pid, uid_t uid, const char *privilege); + +#endif diff --git a/src/libds-tizen/util/meson.build b/src/libds-tizen/util/meson.build new file mode 100644 index 0000000..3d34ab8 --- /dev/null +++ b/src/libds-tizen/util/meson.build @@ -0,0 +1 @@ +libds_tizen_files += files('security.c') diff --git a/src/libds-tizen/util/security.c b/src/libds-tizen/util/security.c new file mode 100644 index 0000000..735caf5 --- /dev/null +++ b/src/libds-tizen/util/security.c @@ -0,0 +1,162 @@ + +#include +#include +#include + +#include "libds/log.h" + +#include "util.h" + +#ifdef HAVE_CYNARA +#include +#include +#include +#include +#include +#include + +#define CYNARA_BUFSIZE 128 + +static cynara *g_cynara = NULL; +static int g_cynara_refcount = 0; + +static void +__security_log_print(int err, const char *fmt, ...) +{ + int ret; + va_list args; + char buf[CYNARA_BUFSIZE] = "\0"; + char tmp[CYNARA_BUFSIZE + CYNARA_BUFSIZE] = "\0"; + + if (fmt) { + va_start(args, fmt); + vsnprintf(tmp, CYNARA_BUFSIZE + CYNARA_BUFSIZE, fmt, args); + va_end(args); + } + + ret = cynara_strerror(err, buf, CYNARA_BUFSIZE); + if (ret != CYNARA_API_SUCCESS) { + ds_err("Failed to get cynara_strerror. error : %d (error log about %s: %d)\n", ret, tmp, err); + return; + } + + ds_err("%s is failed. (%s)\n", tmp, buf); +} +#endif + +bool +tizen_security_check_privilege(pid_t pid, uid_t uid, const char *privilege) +{ +#ifdef HAVE_CYNARA + bool res = false; + char *client_smack = NULL; + char *client_session = NULL; + char uid_str[16] = { 0, }; + int len = -1; + int ret = -1; + + /* If cynara_initialize() has been (retried) and failed, we suppose that cynara is not available. */ + /* Then we return true as if there is no security check available. */ + if (!g_cynara) + return true; + + if (!g_cynara) { + ds_err("security has not been initialized.\n"); + return false; + } + + ret = smack_new_label_from_process((int)pid, &client_smack); + if (ret <= 0) + goto finish; + + snprintf(uid_str, 15, "%d", (int)uid); + + client_session = cynara_session_from_pid(pid); + if (!client_session) + goto finish; + + ret = cynara_check(g_cynara, client_smack, client_session, + uid_str, privilege); + + if (ret == CYNARA_API_ACCESS_ALLOWED) + res = true; + else + __security_log_print(ret, "privilege: %s, client_smack: %s, pid: %d", privilege, client_smack, pid); + +finish: + ds_dbg("Privilege Check For '%s' %s pid:%u uid:%u client_smack:%s(len:%d) client_session:%s ret:%d", + privilege, res ? "SUCCESS" : "FAIL", pid, uid, + client_smack ? client_smack : "N/A", len, + client_session ? client_session: "N/A", ret); + + if (client_session) + free(client_session); + if (client_smack) + free(client_smack); + + return res; +#else + return true; +#endif +} + +int +tizen_security_init(void) +{ +#ifdef HAVE_CYNARA + int ret = CYNARA_API_SUCCESS; + int retry_cnt = 0; + static bool retried = false; + + if (++g_cynara_refcount != 1) + return g_cynara_refcount; + + if (!g_cynara && false == retried) { + retried = true; + + for (retry_cnt = 0; retry_cnt < 5; retry_cnt++) { + ds_dbg("Retry cynara initialize: %d\n", retry_cnt + 1); + + ret = cynara_initialize(&g_cynara, NULL); + + if (CYNARA_API_SUCCESS == ret) { + ds_dbg("Succeed to initialize cynara !\n"); + return 1; + } + + __security_log_print(ret, "cynara_initialize"); + g_cynara = NULL; + } + } + + ds_err("Failed to initialize _security ! (error:%d, retry_cnt=%d)\n", + ret, retry_cnt); + --g_cynara_refcount; + + return 0; +#else + return 1; +#endif +} + +void +tizen_security_finish(void) +{ +#ifdef HAVE_CYNARA + if (g_cynara_refcount < 1) { + ds_err("%s called without tizen_security_init\n", __FUNCTION__); + return 0; + } + + if (--g_cynara_refcount != 0) + return 1; + + if (g_cynara) { + cynara_finish(g_cynara); + g_cynara = NULL; + } +#endif + + return 1; +} + -- 2.7.4