-#include "pixman-helper.h"
-
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <libds/pointer.h>
#include <libds/seat.h>
-// FIXME Instead of including interfaces, add api for getting modifiers
+// FIXME Instead of including interfaces here,
+// add api for getting modifiers in keyboard.h
#include <libds/interfaces/input_device.h>
#include <libds/interfaces/keyboard.h>
+#include "pixman-helper.h"
+
#define OUTPUT_WIDTH 1280
#define OUTPUT_HEIGHT 720
struct tinyds_pointer
{
- struct ds_input_device *dev;
struct tinyds_server *server;
-
struct tinyds_view *focused_view;
-
- double x, y;
+ struct ds_input_device *dev;
struct wl_listener destroy;
struct wl_listener motion;
struct wl_listener motion_absolute;
struct wl_listener button;
struct wl_listener frame;
+
+ double x, y;
};
struct tinyds_keyboard
{
- struct ds_input_device *dev;
struct tinyds_server *server;
-
struct tinyds_view *focused_view;
+ struct ds_input_device *dev;
struct wl_listener destroy;
struct wl_listener key;
struct tinyds_touch
{
- struct ds_input_device *dev;
struct tinyds_server *server;
+ struct ds_input_device *dev;
struct wl_listener destroy;
struct wl_listener down;
struct ds_allocator *allocator;
struct ds_swapchain *swapchain;
+ struct wl_event_source *idle_redraw;
+
struct wl_listener output_destroy;
struct wl_listener output_frame;
struct tinyds_server
{
+ struct tinyds_output *output;
+ struct tinyds_keyboard *keyboard;
struct wl_display *display;
-
struct ds_backend *backend;
struct ds_compositor *compositor;
struct ds_xdg_shell *xdg_shell;
struct ds_seat *seat;
struct ds_data_device_manager *data_device;
- struct tinyds_output output;
- struct tinyds_keyboard *keyboard;
-
struct wl_list views;
+ struct wl_listener display_destroy;
struct wl_listener new_output;
struct wl_listener new_input;
struct wl_listener new_xdg_surface;
struct tinyds_view
{
struct tinyds_server *server;
-
struct ds_xdg_surface *xdg_surface;
struct wl_listener xdg_surface_map;
static bool server_init(struct tinyds_server *server,
struct wl_display *display);
-static void server_fini(struct tinyds_server *server);
-static bool server_init_data_device(struct tinyds_server *server);
+static bool server_init_backend(struct tinyds_server *server);
+static bool server_init_protocols(struct tinyds_server *server);
+static void server_handle_display_destroy(struct wl_listener *listener,
+ void *data);
+static void server_handle_new_input(struct wl_listener *listener, void *data);
+static void server_handle_new_output(struct wl_listener *listener, void *data);
+static void server_handle_new_xdg_surface(struct wl_listener *listener,
+ void *data);
+static void server_handle_request_set_selection(struct wl_listener *listener,
+ void *data);
+static void server_handle_request_data_offer_receive(
+ struct wl_listener *listener, void *data);
+static bool server_handle_keybinding(struct tinyds_server *server,
+ xkb_keysym_t sym);
+static void server_add_output(struct tinyds_server *server,
+ struct ds_output *ds_output, int width, int height);
+static void server_add_keyboard(struct tinyds_server *server,
+ struct ds_input_device *dev);
+static void server_add_touch(struct tinyds_server *server,
+ struct ds_input_device *dev);
+static void server_add_pointer(struct tinyds_server *server,
+ struct ds_input_device *dev);
static void server_add_view(struct tinyds_server *server,
struct ds_xdg_surface *xdg_surface);
+static struct tinyds_view *server_view_at(struct tinyds_server *server,
+ double lx, double ly, double *sx, double *sy);
static void server_next_focus(struct tinyds_server *server);
static void server_focus_view(struct tinyds_server *server,
struct tinyds_view *view);
-static struct tinyds_view *server_view_at(struct tinyds_server *server,
- double lx, double ly, double *sx, double *sy);
-static bool output_init(struct tinyds_output *output,
- struct tinyds_server *server, struct ds_output *ds_output,
- int width, int height);
-static void output_fini(struct tinyds_output *output);
+static void output_destroy(struct tinyds_output *output);
+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_redraw(struct tinyds_output *output);
+static void output_schedule_idle_redraw(struct tinyds_output *output);
+static void output_handle_idle_redraw(void *data);
+static void keyboard_handle_device_destroy(struct wl_listener *listener,
+ void *data);
+static void keyboard_handle_key(struct wl_listener *listener, void *data);
+static void keyboard_handle_modifiers(struct wl_listener *listener,
+ void *data);
+static void touch_handle_device_destroy(struct wl_listener *listener,
+ void *data);
+static void touch_handle_down(struct wl_listener *listener, void *data);
+static void touch_handle_up(struct wl_listener *listener, void *data);
+static void touch_handle_motion(struct wl_listener *listener, void *data);
+static void pointer_handle_device_destroy(struct wl_listener *listener,
+ void *data);
+static void pointer_handle_motion(struct wl_listener *listener, void *data);
+static void pointer_handle_motion_absolute(struct wl_listener *listener,
+ void *data);
+static void pointer_handle_button(struct wl_listener *listener, void *data);
+static void pointer_handle_frame(struct wl_listener *listener, void *data);
static void view_destroy(struct tinyds_view *view);
+static void view_handle_xdg_surface_map(struct wl_listener *listener,
+ void *data);
+static void view_handle_xdg_surface_unmap(struct wl_listener *listener,
+ void *data);
+static void view_handle_xdg_surface_destroy(struct wl_listener *listener,
+ void *data);
+static void view_handle_surface_commit(struct wl_listener *listener,
+ void *data);
static void view_composite(struct tinyds_view *view,
pixman_image_t *dst_image);
+static void view_send_frame_done(struct tinyds_view *view);
int
main(void)
{
- struct tinyds_server server;
+ struct tinyds_server server = {0, };
struct wl_display *display;
const char *socket;
+ int ret = EXIT_FAILURE;
ds_log_init(DS_DBG, NULL);
display = wl_display_create();
- assert(display);
-
- assert(server_init(&server, display) == true);
+ if (!display) {
+ ds_err("Could not create wl_display");
+ return ret;
+ }
- socket = wl_display_add_socket_auto(display);
- assert(socket);
+ if (!server_init(&server, display)) {
+ ds_err("Could not initialize server");
+ goto end;
+ }
ds_backend_start(server.backend);
+ if (!server.output) {
+ ds_err("No available output");
+ goto end;
+ }
- output_damage(&server.output);
- output_redraw(&server.output);
+ socket = wl_display_add_socket_auto(display);
+ if (!socket) {
+ ds_err("Could not add display socket");
+ goto end;
+ }
setenv("WAYLAND_DISPLAY", socket, true);
wl_display_run(server.display);
- server_fini(&server);
+ wl_display_destroy_clients(display);
+
+ ret = EXIT_SUCCESS;
+end:
wl_display_destroy(display);
- return 0;
+ return ret;
+}
+
+static bool
+server_init(struct tinyds_server *server, struct wl_display *display)
+{
+ server->display = display;
+
+ server->display_destroy.notify = server_handle_display_destroy;
+ wl_display_add_destroy_listener(display, &server->display_destroy);
+
+ wl_list_init(&server->views);
+
+ if (wl_display_init_shm(display) != 0)
+ return false;
+
+ if (!server_init_backend(server))
+ return false;
+
+ if (!server_init_protocols(server)) {
+ ds_backend_destroy(server->backend);
+ return false;
+ }
+
+ return true;
+}
+
+static void
+server_handle_display_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_server *server;
+ struct tinyds_view *view, *tmp;
+
+ server = wl_container_of(listener, server, display_destroy);
+
+ wl_list_for_each_safe(view, tmp, &server->views, link)
+ view_destroy(view);
+
+ if (server->output)
+ output_destroy(server->output);
+
+ /* 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. */
+ wl_list_remove(&server->display_destroy.link);
+ wl_list_remove(&server->new_output.link);
+ wl_list_remove(&server->new_input.link);
+ wl_list_remove(&server->new_xdg_surface.link);
+ wl_list_remove(&server->request_set_selection.link);
+ wl_list_remove(&server->request_data_offer_receive.link);
}
static struct ds_backend *
return ds_wl_backend_create(display, NULL);
}
+static bool
+server_init_backend(struct tinyds_server *server)
+{
+ server->backend = create_wl_backend(server->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);
+
+ server->new_output.notify = server_handle_new_output;
+ ds_backend_add_new_output_listener(server->backend, &server->new_output);
+
+ return true;
+}
+
+static bool
+server_init_protocols(struct tinyds_server *server)
+{
+ server->compositor = ds_compositor_create(server->display);
+ if (!server->compositor)
+ return false;
+
+ server->seat = ds_seat_create(server->display, "seat0" /* arbitrary name */);
+ if (!server->seat)
+ return false;
+
+ server->xdg_shell = ds_xdg_shell_create(server->display);
+ if (!server->xdg_shell)
+ return false;
+
+ server->new_xdg_surface.notify = server_handle_new_xdg_surface;
+ ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
+ &server->new_xdg_surface);
+
+ server->data_device = ds_data_device_manager_create(server->display);
+ if (!server->data_device)
+ return false;
+
+ server->request_set_selection.notify =
+ server_handle_request_set_selection;
+ ds_data_device_manager_add_request_set_selection_listener(
+ server->data_device, &server->request_set_selection);
+
+ server->request_data_offer_receive.notify =
+ server_handle_request_data_offer_receive;
+ ds_data_device_manager_add_request_data_offer_receive_listener(
+ server->data_device, &server->request_data_offer_receive);
+
+ return true;
+}
+
+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);
+ ds_seat_set_capabilities(server->seat,
+ WL_SEAT_CAPABILITY_KEYBOARD);
+ break;
+ case DS_INPUT_DEVICE_TOUCH:
+ server_add_touch(server, dev);
+ break;
+ case DS_INPUT_DEVICE_POINTER:
+ server_add_pointer(server, dev);
+ ds_seat_set_capabilities(server->seat,
+ WL_SEAT_CAPABILITY_POINTER);
+ break;
+ default:
+ ds_err("Unknown type(%d) of ds_input_device", dev_type);
+ break;
+ }
+}
+
static void
server_handle_new_output(struct wl_listener *listener, void *data)
{
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);
+ server_add_output(server, ds_output, OUTPUT_WIDTH, OUTPUT_HEIGHT);
}
static void
-keyboard_handle_device_destroy(struct wl_listener *listener, void *data)
+server_handle_new_xdg_surface(struct wl_listener *listener, void *data)
{
- struct tinyds_keyboard *kbd;
+ struct tinyds_server *server;
- kbd = wl_container_of(listener, kbd, destroy);
+ server = wl_container_of(listener, server, new_xdg_surface);
+ server_add_view(server, (struct ds_xdg_surface *)data);
+}
- ds_inf("Keyboard(%p) destroyed", kbd);
+static void
+server_handle_request_set_selection(struct wl_listener *listener, void *data)
+{
+ struct ds_event_request_set_selection *event = data;
- wl_list_remove(&kbd->destroy.link);
- wl_list_remove(&kbd->key.link);
+ ds_seat_set_selection(event->seat, event->source, event->serial);
+}
- free(kbd);
+static void
+server_handle_request_data_offer_receive(struct wl_listener *listener, void *data)
+{
+ struct ds_event_request_data_offer_receive *event = data;
+
+ ds_data_offer_send(event->offer, event->mime_type, event->fd);
}
static bool
}
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;
- bool handled = false;
-
- 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++) {
- handled = server_handle_keybinding(kbd->server, syms[i]);
- }
- }
- }
-
- if (!handled) {
- ds_seat_set_keyboard(kbd->server->seat, kbd->dev);
- ds_seat_keyboard_notify_key(kbd->server->seat, event->time_msec,
- event->keycode, event->state);
- }
-}
-
-static void
-keyboard_handle_modifiers(struct wl_listener *listener, void *data)
-{
- struct tinyds_keyboard *kbd;
-
- kbd = wl_container_of(listener, kbd, modifiers);
-
- ds_seat_set_keyboard(kbd->server->seat, kbd->dev);
- ds_seat_keyboard_notify_modifiers(kbd->server->seat,
- &kbd->dev->keyboard->modifiers);
-}
-
-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);
+ if (!kbd) {
+ ds_err("Could not allocate memory");
+ return;
+ }
kbd->dev = dev;
kbd->server = server;
}
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);
+ if (!touch) {
+ ds_err("Could not allocate memory");
+ return;
+ }
touch->dev = dev;
touch->server = server;
}
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;
- struct tinyds_view *view;
- double sx, sy;
-
- 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);
-
- pointer->x = event->x * OUTPUT_WIDTH;
- pointer->y = event->y * OUTPUT_HEIGHT;
- view = server_view_at(pointer->server, pointer->x, pointer->y, &sx, &sy);
-
- if (pointer->focused_view != view) {
- if (pointer->focused_view) {
- ds_inf("Clear pointer focus from view(%p)", pointer->focused_view);
- ds_seat_pointer_notify_clear_focus(pointer->server->seat);
- pointer->focused_view = NULL;
- }
-
- if (view) {
- ds_inf("Set pointer focus to view(%p)", view);
- ds_seat_pointer_notify_enter(pointer->server->seat,
- ds_xdg_surface_get_surface(view->xdg_surface), sx, sy);
- pointer->focused_view = view;
- }
- }
-
- if (view) {
- ds_seat_pointer_notify_motion(pointer->server->seat,
- event->time_msec, sx, sy);
- }
-}
-
-static void
-pointer_handle_button(struct wl_listener *listener, void *data)
-{
- struct tinyds_pointer *pointer;
- struct ds_event_pointer_button *event = data;
- struct tinyds_view *view;
- double sx, sy;
-
- 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);
-
- ds_seat_pointer_notify_button(pointer->server->seat, event->time_msec,
- event->button, event->state);
-
- if (event->state == DS_BUTTON_PRESSED) {
- view = server_view_at(pointer->server, pointer->x, pointer->y,
- &sx, &sy);
- if (view)
- server_focus_view(pointer->server, view);
- }
-}
-
-static void
-pointer_handle_frame(struct wl_listener *listener, void *data)
-{
- struct tinyds_pointer *pointer;
-
- pointer = wl_container_of(listener, pointer, frame);
-
- ds_inf("Pointer(%p) frame", pointer);
- ds_seat_pointer_notify_frame(pointer->server->seat);
-}
-
-static void
-server_add_pointer(struct tinyds_server *server, struct ds_input_device *dev)
+server_add_pointer(struct tinyds_server *server, struct ds_input_device *dev)
{
struct tinyds_pointer *pointer;
pointer = calloc(1, sizeof *pointer);
- assert(pointer);
+ if (!pointer) {
+ ds_err("Could not allocate memory");
+ return;
+ }
pointer->dev = dev;
pointer->server = server;
}
static void
-server_handle_new_input(struct wl_listener *listener, void *data)
+server_add_view(struct tinyds_server *server, struct ds_xdg_surface *xdg_surface)
{
- 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);
+ struct tinyds_view *view;
- dev_type = ds_input_device_get_type(dev);
- switch (dev_type) {
- case DS_INPUT_DEVICE_KEYBOARD:
- server_add_keyboard(server, dev);
- ds_seat_set_capabilities(server->seat, WL_SEAT_CAPABILITY_KEYBOARD);
- break;
- case DS_INPUT_DEVICE_TOUCH:
- server_add_touch(server, dev);
- break;
- case DS_INPUT_DEVICE_POINTER:
- server_add_pointer(server, dev);
- ds_seat_set_capabilities(server->seat, WL_SEAT_CAPABILITY_POINTER);
- break;
- default:
- ds_err("Unknown type(%d) of ds_input_device", dev_type);
- break;
+ view = calloc(1, sizeof *view);
+ if (!view) {
+ ds_err("Could not allocate memory");
+ return;
}
-}
-
-static void
-view_handle_xdg_surface_map(struct wl_listener *listener, void *data)
-{
- struct tinyds_view *view;
- view = wl_container_of(listener, view, xdg_surface_map);
- view->mapped = true;
- server_focus_view(view->server, view);
-}
+ view->server = server;
+ view->xdg_surface = xdg_surface;
-static void
-view_handle_xdg_surface_unmap(struct wl_listener *listener, void *data)
-{
- struct tinyds_view *view;
+ view->xdg_surface_map.notify = view_handle_xdg_surface_map;
+ ds_xdg_surface_add_map_listener(xdg_surface,
+ &view->xdg_surface_map);
- view = wl_container_of(listener, view, xdg_surface_unmap);
- view->mapped = false;
-}
+ view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
+ ds_xdg_surface_add_unmap_listener(xdg_surface,
+ &view->xdg_surface_unmap);
-static void
-view_handle_xdg_surface_destroy(struct wl_listener *listener, void *data)
-{
- struct tinyds_view *view;
+ view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
+ ds_xdg_surface_add_destroy_listener(xdg_surface,
+ &view->xdg_surface_destroy);
- view = wl_container_of(listener, 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);
- output_damage(&view->server->output);
- output_redraw(&view->server->output);
+ wl_list_insert(&server->views, &view->link);
- view_destroy(view);
+ ds_inf("View(%p) added", view);
}
-static void
-view_handle_surface_commit(struct wl_listener *listener, void *data)
+static struct tinyds_view *
+server_view_at(struct tinyds_server *server, double lx, double ly,
+ double *sx, double *sy)
{
struct tinyds_view *view;
+ struct ds_surface *surface;
+ struct ds_buffer *buffer;
+ int x, y, w = 0, h = 0;
- view = wl_container_of(listener, view, surface_commit);
+ wl_list_for_each(view, &server->views, link) {
+ surface = ds_xdg_surface_get_surface(view->xdg_surface);
+ buffer = ds_surface_get_buffer(surface);
+ ds_buffer_get_size(buffer, &w, &h);
- output_damage(&view->server->output);
- output_redraw(&view->server->output);
-}
+ x = view->x;
+ y = view->y;
-static void
-server_new_xdg_surface(struct wl_listener *listener, void *data)
-{
- struct tinyds_server *server;
+ if (lx >= x && lx <= w && ly >= y && ly <= h) {
+ if (sx)
+ *sx = lx - x;
+ if (sy)
+ *sy = ly - y;
- server = wl_container_of(listener, server, new_xdg_surface);
+ return view;
+ }
+ }
- server_add_view(server, (struct ds_xdg_surface *)data);
+ return NULL;
}
static void
if (wl_list_length(&server->views) < 2)
return;
- top = wl_container_of(server->views.prev, top, link);
- next = wl_container_of(top->link.prev, next, link);
+ top = wl_container_of(server->views.next, top, link);
+ next = wl_container_of(top->link.next, next, link);
server_focus_view(server, next);
wl_list_remove(&top->link);
- wl_list_insert(&server->views, &top->link);
+ wl_list_insert(server->views.prev, &top->link);
- output_damage(&server->output);
- output_redraw(&server->output);
+ output_damage(server->output);
}
static void
if (view) {
wl_list_remove(&view->link);
- wl_list_insert(server->views.prev, &view->link);
+ wl_list_insert(&server->views, &view->link);
ds_seat_keyboard_notify_enter(server->seat,
ds_xdg_surface_get_surface(view->xdg_surface),
}
}
-static bool
-server_init(struct tinyds_server *server, struct wl_display *display)
+static void
+server_add_output(struct tinyds_server *server, struct ds_output *ds_output,
+ int width, int height)
{
- server->display = display;
-
- wl_list_init(&server->views);
+ struct tinyds_output *output;
- if (wl_display_init_shm(display) != 0)
- return false;
-
- server->backend = create_wl_backend(display);
- if (!server->backend)
- return false;
+ if (server->output) {
+ ds_err("Output already exists. Not support multi output yet.");
+ return;
+ }
- ds_wl_backend_create_output(server->backend);
+ output = calloc(1, sizeof *output);
+ if (!output) {
+ ds_err("Could not allocate memory for output");
+ return;
+ }
- server->new_input.notify = server_handle_new_input;
- ds_backend_add_new_input_listener(server->backend, &server->new_input);
+ output->server = server;
+ output->ds_output = ds_output;
+ output->width = width;
+ output->height = height;
+ output->drawable = true;
- server->new_output.notify = server_handle_new_output;
- ds_backend_add_new_output_listener(server->backend, &server->new_output);
+ ds_output_set_custom_mode(ds_output, width, height, 0);
- server->compositor = ds_compositor_create(display);
- if (!server->compositor)
- goto err;
+ output->allocator = ds_shm_allocator_create();
+ if (!output->allocator) {
+ ds_err("Could not create shm_allocator");
+ goto err_alloc;
+ }
- server->xdg_shell = ds_xdg_shell_create(display);
- if (!server->xdg_shell)
- goto err;
+ output->swapchain = ds_swapchain_create(output->allocator,
+ width, height, DRM_FORMAT_XRGB8888);
+ if (!output->swapchain) {
+ ds_err("Could not create swapchain");
+ goto err_swapchain;
+ }
- server->new_xdg_surface.notify = server_new_xdg_surface;
- ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
- &server->new_xdg_surface);
+ output->output_destroy.notify = output_handle_destroy;
+ ds_output_add_destroy_listener(output->ds_output, &output->output_destroy);
- server->seat = ds_seat_create(display, "seat0" /* arbitrary name */);
- if (!server->seat)
- goto err;
+ output->output_frame.notify = output_handle_frame;
+ ds_output_add_frame_listener(output->ds_output, &output->output_frame);
- if (!server_init_data_device(server))
- goto err;
+ output_damage(output);
- return true;
+ server->output = output;
-err:
- ds_backend_destroy(server->backend);
+ return;
- return false;
+err_swapchain:
+ ds_allocator_destroy(output->allocator);
+err_alloc:
+ free(output);
}
static void
-server_fini(struct tinyds_server *server)
+output_destroy(struct tinyds_output *output)
{
- struct tinyds_view *view, *tmp;
-
- wl_list_for_each_safe(view, tmp, &server->views, link)
- view_destroy(view);
-
- output_fini(&server->output);
+ if (output->ds_output)
+ output_unlink_ds_output(output);
- wl_list_remove(&server->new_xdg_surface.link);
+ ds_swapchain_destroy(output->swapchain);
+ ds_allocator_destroy(output->allocator);
+ free(output);
}
static void
-output_handle_destroy(struct wl_listener *listener, void *data)
+output_unlink_ds_output(struct tinyds_output *output)
{
- struct tinyds_output *output =
- wl_container_of(listener, output, output_destroy);
-
wl_list_remove(&output->output_destroy.link);
wl_list_remove(&output->output_frame.link);
+
output->ds_output = NULL;
+}
+
+static void
+output_handle_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_output *output;
+ output = wl_container_of(listener, output, output_destroy);
+ output_unlink_ds_output(output);
wl_display_terminate(output->server->display);
}
static void
output_handle_frame(struct wl_listener *listener, void *data)
{
- struct tinyds_output *output =
- wl_container_of(listener, output, output_frame);
+ struct tinyds_output *output;
+ output = wl_container_of(listener, output, output_frame);
output->drawable = true;
- output_redraw(output);
+
+ if (output->damaged)
+ output_schedule_idle_redraw(output);
}
-static bool
-output_init(struct tinyds_output *output, struct tinyds_server *server,
- struct ds_output *ds_output, int width, int height)
+static void
+output_damage(struct tinyds_output *output)
{
- output->server = server;
- output->ds_output = ds_output;
- output->width = width;
- 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;
-
- output->swapchain = ds_swapchain_create(output->allocator,
- width, height, DRM_FORMAT_XRGB8888);
- if (!output->swapchain)
- goto err_swapchain;
-
- output->output_destroy.notify = output_handle_destroy;
- ds_output_add_destroy_listener(output->ds_output, &output->output_destroy);
-
- output->output_frame.notify = output_handle_frame;
- ds_output_add_frame_listener(output->ds_output, &output->output_frame);
-
- return true;
-
-err_swapchain:
- ds_allocator_destroy(output->allocator);
-
- return false;
+ output->damaged = true;
+ output_schedule_idle_redraw(output);
}
static void
-output_fini(struct tinyds_output *output)
+output_schedule_idle_redraw(struct tinyds_output *output)
{
- ds_output_destroy(output->ds_output);
- ds_swapchain_destroy(output->swapchain);
- ds_allocator_destroy(output->allocator);
-}
+ struct tinyds_server *server = output->server;
-static void
-output_damage(struct tinyds_output *output)
-{
- output->damaged = true;
+ 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_redraw(struct tinyds_output *output)
+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;
pixman_image_fill_color(output_image, 80, 80, 80);
- wl_list_for_each(view, &output->server->views, link) {
+ wl_list_for_each_reverse(view, &output->server->views, link) {
if (!view->mapped)
continue;
view_composite(view, output_image);
}
static void
-server_handle_request_set_selection(struct wl_listener *listener, void *data)
+keyboard_handle_device_destroy(struct wl_listener *listener, void *data)
{
- struct ds_event_request_set_selection *event = data;
+ struct tinyds_keyboard *kbd;
- ds_seat_set_selection(event->seat, event->source, event->serial);
+ 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 void
-server_handle_request_data_offer_receive(struct wl_listener *listener, void *data)
+keyboard_handle_key(struct wl_listener *listener, void *data)
{
- struct ds_event_request_data_offer_receive *event = 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;
+ bool handled = false;
- ds_data_offer_send(event->offer, event->mime_type, event->fd);
+ 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++) {
+ handled = server_handle_keybinding(kbd->server, syms[i]);
+ }
+ }
+ }
+
+ if (!handled) {
+ ds_seat_set_keyboard(kbd->server->seat, kbd->dev);
+ ds_seat_keyboard_notify_key(kbd->server->seat, event->time_msec,
+ event->keycode, event->state);
+ }
}
-static bool
-server_init_data_device(struct tinyds_server *server)
+static void
+keyboard_handle_modifiers(struct wl_listener *listener, void *data)
{
- server->data_device = ds_data_device_manager_create(server->display);
- if (!server->data_device)
- return false;
+ struct tinyds_keyboard *kbd;
- server->request_set_selection.notify =
- server_handle_request_set_selection;
- ds_data_device_manager_add_request_set_selection_listener(
- server->data_device, &server->request_set_selection);
+ kbd = wl_container_of(listener, kbd, modifiers);
- server->request_data_offer_receive.notify =
- server_handle_request_data_offer_receive;
- ds_data_device_manager_add_request_data_offer_receive_listener(
- server->data_device, &server->request_data_offer_receive);
+ ds_seat_set_keyboard(kbd->server->seat, kbd->dev);
+ ds_seat_keyboard_notify_modifiers(kbd->server->seat,
+ &kbd->dev->keyboard->modifiers);
+}
- return true;
+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
-server_add_view(struct tinyds_server *server, struct ds_xdg_surface *xdg_surface)
+touch_handle_down(struct wl_listener *listener, void *data)
{
- struct tinyds_view *view;
+ ds_inf("Touch device(%p): down", data);
+}
- view = calloc(1, sizeof *view);
- view->server = server;
- view->xdg_surface = xdg_surface;
+static void
+touch_handle_up(struct wl_listener *listener, void *data)
+{
+ ds_inf("Touch device(%p): up", data);
+}
- view->xdg_surface_map.notify = view_handle_xdg_surface_map;
- ds_xdg_surface_add_map_listener(xdg_surface,
- &view->xdg_surface_map);
+static void
+touch_handle_motion(struct wl_listener *listener, void *data)
+{
+ ds_inf("Touch device(%p): motion", data);
+}
- view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
- ds_xdg_surface_add_unmap_listener(xdg_surface,
- &view->xdg_surface_unmap);
+static void
+pointer_handle_device_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_pointer *pointer;
- view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
- ds_xdg_surface_add_destroy_listener(xdg_surface,
- &view->xdg_surface_destroy);
+ pointer = wl_container_of(listener, pointer, destroy);
- view->surface_commit.notify = view_handle_surface_commit;
- ds_surface_add_commit_listener(
- ds_xdg_surface_get_surface(xdg_surface),
- &view->surface_commit);
+ ds_inf("Pointer(%p) destroyed", pointer);
- wl_list_insert(server->views.prev, &view->link);
+ 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);
- ds_inf("View(%p) added", view);
+ free(pointer);
}
-static struct tinyds_view *
-server_view_at(struct tinyds_server *server, double lx, double ly,
- double *sx, double *sy)
+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;
struct tinyds_view *view;
- struct ds_surface *surface;
- struct ds_buffer *buffer;
- int x, y, w = 0, h = 0;
+ double sx, sy;
- wl_list_for_each(view, &server->views, link) {
- surface = ds_xdg_surface_get_surface(view->xdg_surface);
- buffer = ds_surface_get_buffer(surface);
- ds_buffer_get_size(buffer, &w, &h);
+ pointer = wl_container_of(listener, pointer, motion_absolute);
- x = view->x;
- y = view->y;
+ ds_inf("Pointer(%p) motion absolute: (x %f y %f) time(%d)",
+ pointer, event->x, event->y, event->time_msec);
- if (lx >= x && lx <= w && ly >= y && ly <= h) {
- *sx = lx - x;
- *sy = ly - y;
+ pointer->x = event->x * OUTPUT_WIDTH;
+ pointer->y = event->y * OUTPUT_HEIGHT;
- return view;
+ view = server_view_at(pointer->server, pointer->x, pointer->y, &sx, &sy);
+ if (pointer->focused_view != view) {
+ if (pointer->focused_view) {
+ ds_inf("Clear pointer focus from view(%p)", pointer->focused_view);
+ ds_seat_pointer_notify_clear_focus(pointer->server->seat);
+ pointer->focused_view = NULL;
+ }
+
+ if (view) {
+ ds_inf("Set pointer focus to view(%p)", view);
+ ds_seat_pointer_notify_enter(pointer->server->seat,
+ ds_xdg_surface_get_surface(view->xdg_surface), sx, sy);
+ pointer->focused_view = view;
}
}
- return NULL;
+ if (view) {
+ ds_seat_pointer_notify_motion(pointer->server->seat,
+ event->time_msec, sx, sy);
+ }
+}
+
+static void
+pointer_handle_button(struct wl_listener *listener, void *data)
+{
+ struct tinyds_pointer *pointer;
+ struct ds_event_pointer_button *event = data;
+ struct tinyds_view *view;
+
+ 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);
+
+ ds_seat_pointer_notify_button(pointer->server->seat, event->time_msec,
+ event->button, event->state);
+
+ if (event->state == DS_BUTTON_PRESSED) {
+ view = server_view_at(pointer->server, pointer->x, pointer->y,
+ NULL, NULL);
+ if (view)
+ server_focus_view(pointer->server, view);
+ }
+}
+
+static void
+pointer_handle_frame(struct wl_listener *listener, void *data)
+{
+ struct tinyds_pointer *pointer;
+
+ pointer = wl_container_of(listener, pointer, frame);
+
+ ds_inf("Pointer(%p) frame", pointer);
+ ds_seat_pointer_notify_frame(pointer->server->seat);
}
static void
}
static void
-view_send_frame_done(struct tinyds_view *view)
+view_handle_xdg_surface_map(struct wl_listener *listener, void *data)
{
- struct timespec now;
+ struct tinyds_view *view;
- clock_gettime(CLOCK_MONOTONIC, &now);
- ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
- &now);
+ view = wl_container_of(listener, view, xdg_surface_map);
+ view->mapped = true;
+ server_focus_view(view->server, view);
+}
+
+static void
+view_handle_xdg_surface_unmap(struct wl_listener *listener, void *data)
+{
+ struct tinyds_view *view;
+
+ view = wl_container_of(listener, view, xdg_surface_unmap);
+ view->mapped = false;
+ output_damage(view->server->output);
+}
+
+static void
+view_handle_xdg_surface_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_view *view;
+
+ view = wl_container_of(listener, view, xdg_surface_destroy);
+ output_damage(view->server->output);
+ view_destroy(view);
+}
+
+static void
+view_handle_surface_commit(struct wl_listener *listener, void *data)
+{
+ struct tinyds_view *view;
+
+ view = wl_container_of(listener, view, surface_commit);
+ output_damage(view->server->output);
}
static void
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);
+}