enlightenment/src/bin/e_comp_wl.c

2890 lines
90 KiB
C

#include "e.h"
#include "e_comp_wl.h"
#include <sys/mman.h>
#define e_pixmap_parent_window_set(X, Y) e_pixmap_parent_window_set(X, (Ecore_Window)(uintptr_t)Y)
/* compositor function prototypes */
static void _seat_send_updated_caps(struct wl_seat *seat);
static void _move_resources(struct wl_list *dest, struct wl_list *src);
static void _move_resources_for_client(struct wl_list *dest, struct wl_list *src, struct wl_client *client);
static struct wl_resource *_find_resource_for_surface(struct wl_list *list, struct wl_resource *surface);
static void _default_grab_focus(struct wl_pointer_grab *grab, struct wl_resource *surface, wl_fixed_t x, wl_fixed_t y);
static void _default_grab_motion(struct wl_pointer_grab *grab, uint32_t timestamp, wl_fixed_t x, wl_fixed_t y);
static void _default_grab_button(struct wl_pointer_grab *grab, uint32_t timestamp, uint32_t button, uint32_t state_w);
static void _default_grab_touch_down(struct wl_touch_grab *grab, uint32_t timestamp, int touch_id, wl_fixed_t sx, wl_fixed_t sy);
static void _default_grab_touch_up(struct wl_touch_grab *grab, uint32_t timestamp, int touch_id);
static void _default_grab_touch_motion(struct wl_touch_grab *grab, uint32_t timestamp, int touch_id, wl_fixed_t sx, wl_fixed_t sy);
static void _data_offer_accept(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *mime_type);
static void _data_offer_receive(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *mime_type, int32_t fd);
static void _data_offer_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource);
static void _destroy_data_offer(struct wl_resource *resource);
static void _destroy_offer_data_source(struct wl_listener *listener, void *data EINA_UNUSED);
static void _create_data_source(struct wl_client *client, struct wl_resource *resource, uint32_t id);
static void _get_data_device(struct wl_client *client, struct wl_resource *manager_resource EINA_UNUSED, uint32_t id, struct wl_resource *seat_resource);
static void _current_surface_destroy(struct wl_listener *listener, void *data EINA_UNUSED);
static void _bind_manager(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id);
static void _default_grab_key(struct wl_keyboard_grab *grab, uint32_t timestamp, uint32_t key, uint32_t state);
static void _default_grab_modifiers(struct wl_keyboard_grab *grab, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group);
static void _data_device_start_drag(struct wl_client *client, struct wl_resource *resource, struct wl_resource *source_resource, struct wl_resource *origin_resource EINA_UNUSED, struct wl_resource *icon_resource, uint32_t serial EINA_UNUSED);
static void _data_device_set_selection(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *source_resource, uint32_t serial);
static void _destroy_data_device_icon(struct wl_listener *listener, void *data EINA_UNUSED);
static void _destroy_selection_data_source(struct wl_listener *listener, void *data EINA_UNUSED);
static void _data_source_offer(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *type);
static void _data_source_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource);
static void _destroy_data_source(struct wl_resource *resource);
static void _destroy_data_device_source(struct wl_listener *listener, void *data EINA_UNUSED);
static void _data_device_end_drag_grab(struct wl_seat *seat);
static void _drag_grab_button(struct wl_pointer_grab *grab, uint32_t timestamp EINA_UNUSED, uint32_t button, uint32_t state_w);
static void _drag_grab_motion(struct wl_pointer_grab *grab, uint32_t timestamp, wl_fixed_t x, wl_fixed_t y);
static void _destroy_drag_focus(struct wl_listener *listener, void *data EINA_UNUSED);
static void _drag_grab_focus(struct wl_pointer_grab *grab, struct wl_resource *surface, wl_fixed_t x, wl_fixed_t y);
static void _client_source_accept(struct wl_data_source *source, uint32_t timestamp EINA_UNUSED, const char *mime_type);
static void _client_source_send(struct wl_data_source *source, const char *mime_type, int32_t fd);
static void _client_source_cancel(struct wl_data_source *source);
static void _e_comp_wl_cb_bind(struct wl_client *client, void *data, unsigned int version, unsigned int id);
static Eina_Bool _e_comp_wl_cb_read(void *data EINA_UNUSED, Ecore_Fd_Handler *hdl EINA_UNUSED);
static Eina_Bool _e_comp_wl_cb_idle(void *data EINA_UNUSED);
static Eina_Bool _e_comp_wl_cb_module_idle(void *data EINA_UNUSED);
/* compositor interface prototypes */
static void _e_comp_wl_cb_surface_create(struct wl_client *client, struct wl_resource *resource, unsigned int id);
static void _e_comp_wl_cb_surface_destroy(struct wl_resource *resource);
static void _e_comp_wl_cb_region_create(struct wl_client *client, struct wl_resource *resource, unsigned int id);
static void _e_comp_wl_cb_region_destroy(struct wl_resource *resource);
/* input function prototypes */
static Eina_Bool _e_comp_wl_input_init(void);
static void _e_comp_wl_input_shutdown(void);
static void _e_comp_wl_input_cb_bind(struct wl_client *client, void *data, unsigned int version EINA_UNUSED, unsigned int id);
static void _e_comp_wl_input_cb_unbind(struct wl_resource *resource);
static struct xkb_keymap *_e_comp_wl_input_keymap_get(void);
static int _e_comp_wl_input_keymap_fd_get(off_t size);
static E_Wayland_Keyboard_Info *_e_comp_wl_input_keyboard_info_get(struct xkb_keymap *keymap);
/* input interface prototypes */
static void _e_comp_wl_input_cb_pointer_get(struct wl_client *client, struct wl_resource *resource, unsigned int id);
static void _e_comp_wl_input_cb_keyboard_get(struct wl_client *client, struct wl_resource *resource, unsigned int id);
static void _e_comp_wl_input_cb_touch_get(struct wl_client *client, struct wl_resource *resource, unsigned int id);
/* pointer function prototypes */
static void _e_comp_wl_pointer_cb_destroy(struct wl_listener *listener, void *data EINA_UNUSED);
static void _e_comp_wl_pointer_configure(E_Wayland_Surface *ews, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h);
static void _e_comp_wl_pointer_unmap(E_Wayland_Surface *ews);
/* pointer interface prototypes */
static void _e_comp_wl_pointer_cb_cursor_set(struct wl_client *client, struct wl_resource *resource, unsigned int serial, struct wl_resource *surface_resource, int x, int y);
static void _e_comp_wl_pointer_cb_release(struct wl_client *client, struct wl_resource *resource);
/* keyboard interface prototypes */
static void _e_comp_wl_keyboard_cb_release(struct wl_client *client, struct wl_resource *resource);
/* touch interface prototypes */
static void _e_comp_wl_touch_cb_release(struct wl_client *client, struct wl_resource *resource);
/* region interface prototypes */
static void _e_comp_wl_region_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource);
static void _e_comp_wl_region_cb_add(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int x, int y, int w, int h);
static void _e_comp_wl_region_cb_subtract(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int x, int y, int w, int h);
/* surface function prototypes */
static void _e_comp_wl_surface_cb_pending_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED);
static void _e_comp_wl_surface_cb_frame_destroy(struct wl_resource *resource);
static void _e_comp_wl_surface_buffer_reference(E_Wayland_Buffer_Reference *ref, E_Wayland_Buffer *buffer);
static void _e_comp_wl_surface_buffer_reference_cb_destroy(struct wl_listener *listener, void *data EINA_UNUSED);
static E_Wayland_Buffer *_e_comp_wl_surface_buffer_resource(struct wl_resource *resource);
static void _e_comp_wl_surface_buffer_cb_destroy(struct wl_listener *listener, void *data EINA_UNUSED);
/* surface interface prototypes */
static void _e_comp_wl_surface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource);
static void _e_comp_wl_surface_cb_attach(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *buffer_resource, int x, int y);
static void _e_comp_wl_surface_cb_damage(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int x, int y, int w, int h);
static void _e_comp_wl_surface_cb_frame(struct wl_client *client, struct wl_resource *resource, unsigned int callback);
static void _e_comp_wl_surface_cb_opaque_region_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *region_resource);
static void _e_comp_wl_surface_cb_input_region_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *region_resource);
static void _e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_resource *resource);
static void _e_comp_wl_surface_cb_buffer_transform_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, int transform EINA_UNUSED);
static void _e_comp_wl_surface_cb_buffer_scale_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, int scale EINA_UNUSED);
/* local wayland interfaces */
static const struct wl_compositor_interface _e_compositor_interface =
{
_e_comp_wl_cb_surface_create,
_e_comp_wl_cb_region_create
};
static const struct wl_seat_interface _e_input_interface =
{
_e_comp_wl_input_cb_pointer_get,
_e_comp_wl_input_cb_keyboard_get,
_e_comp_wl_input_cb_touch_get,
};
static const struct wl_pointer_interface _e_pointer_interface =
{
_e_comp_wl_pointer_cb_cursor_set,
_e_comp_wl_pointer_cb_release
};
static const struct wl_keyboard_interface _e_keyboard_interface =
{
_e_comp_wl_keyboard_cb_release
};
static const struct wl_touch_interface _e_touch_interface =
{
_e_comp_wl_touch_cb_release
};
static const struct wl_region_interface _e_region_interface =
{
_e_comp_wl_region_cb_destroy,
_e_comp_wl_region_cb_add,
_e_comp_wl_region_cb_subtract
};
static const struct wl_surface_interface _e_surface_interface =
{
_e_comp_wl_surface_cb_destroy,
_e_comp_wl_surface_cb_attach,
_e_comp_wl_surface_cb_damage,
_e_comp_wl_surface_cb_frame,
_e_comp_wl_surface_cb_opaque_region_set,
_e_comp_wl_surface_cb_input_region_set,
_e_comp_wl_surface_cb_commit,
_e_comp_wl_surface_cb_buffer_transform_set,
_e_comp_wl_surface_cb_buffer_scale_set
};
static const struct wl_pointer_grab_interface _e_pointer_grab_interface =
{
_default_grab_focus,
_default_grab_motion,
_default_grab_button
};
static const struct wl_keyboard_grab_interface _e_default_keyboard_grab_interface =
{
_default_grab_key,
_default_grab_modifiers,
};
static const struct wl_data_offer_interface _e_data_offer_interface =
{
_data_offer_accept,
_data_offer_receive,
_data_offer_destroy,
};
static const struct wl_data_device_manager_interface _e_manager_interface =
{
_create_data_source,
_get_data_device
};
static const struct wl_data_device_interface _e_data_device_interface =
{
_data_device_start_drag,
_data_device_set_selection,
};
static const struct wl_touch_grab_interface _e_default_touch_grab_interface =
{
_default_grab_touch_down,
_default_grab_touch_up,
_default_grab_touch_motion
};
static struct wl_data_source_interface _e_data_source_interface =
{
_data_source_offer,
_data_source_destroy
};
static const struct wl_pointer_grab_interface _e_drag_grab_interface =
{
_drag_grab_focus,
_drag_grab_motion,
_drag_grab_button,
};
/* local variables */
static Ecore_Idler *_module_idler = NULL;
/* external variables */
EAPI E_Wayland_Compositor *_e_wl_comp;
/* external functions */
EAPI Eina_Bool
e_comp_wl_init(void)
{
int fd = 0;
/* try to allocate space for a new compositor */
if (!(_e_wl_comp = E_NEW(E_Wayland_Compositor, 1)))
return EINA_FALSE;
/* try to create a wayland display */
if (!(_e_wl_comp->wl.display = wl_display_create()))
{
ERR("Could not create a Wayland Display: %m");
goto err;
}
/* init compositor signals */
wl_signal_init(&_e_wl_comp->signals.destroy);
wl_signal_init(&_e_wl_comp->signals.activate);
wl_signal_init(&_e_wl_comp->signals.kill);
wl_signal_init(&_e_wl_comp->signals.seat);
/* try to add compositor to the displays globals */
if (!wl_global_create(_e_wl_comp->wl.display, &wl_compositor_interface, 3,
_e_wl_comp, _e_comp_wl_cb_bind))
{
ERR("Could not add compositor to globals: %m");
goto err;
}
/* init data device manager */
wl_data_device_manager_init(_e_wl_comp->wl.display);
/* try to init shm mechanism */
if (wl_display_init_shm(_e_wl_comp->wl.display) < 0)
ERR("Could not initialize SHM: %m");
#ifdef HAVE_WAYLAND_EGL
/* try to get the egl display
*
* NB: This is interesting....if we try to eglGetDisplay and pass in the
* wayland display, then EGL fails due to XCB not owning the event queue.
* If we pass it a NULL, it inits just fine */
_e_wl_comp->egl.display = eglGetDisplay(NULL);
if (_e_wl_comp->egl.display == EGL_NO_DISPLAY)
ERR("Could not get EGL display: %m");
else
{
EGLint major, minor;
/* try to initialize egl */
if (!eglInitialize(_e_wl_comp->egl.display, &major, &minor))
{
ERR("Could not initialize EGL: %m");
eglTerminate(_e_wl_comp->egl.display);
}
else
{
EGLint n;
EGLint attribs[] =
{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 1, EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES2_BIT, EGL_NONE
};
/* const char *exts; */
if ((!eglChooseConfig(_e_wl_comp->egl.display, attribs,
&_e_wl_comp->egl.config, 1, &n) || (n == 0)))
{
ERR("Could not choose EGL config: %m");
eglTerminate(_e_wl_comp->egl.display);
}
}
}
#endif
/* try to initialize input */
if (!_e_comp_wl_input_init())
{
ERR("Could not initialize input: %m");
goto err;
}
#ifndef WAYLAND_ONLY
/* setup keymap_change event handler */
_e_wl_comp->kbd_handler =
ecore_event_handler_add(ECORE_X_EVENT_XKB_STATE_NOTIFY,
e_comp_wl_cb_keymap_changed, NULL);
#endif
/* get the displays event loop */
_e_wl_comp->wl.loop = wl_display_get_event_loop(_e_wl_comp->wl.display);
/* get the event loop's file descriptor so we can listen on it */
fd = wl_event_loop_get_fd(_e_wl_comp->wl.loop);
/* add the fd to E's main loop */
_e_wl_comp->fd_handler =
ecore_main_fd_handler_add(fd, ECORE_FD_READ,
_e_comp_wl_cb_read, NULL, NULL, NULL);
/* add an idler for flushing clients */
_e_wl_comp->idler = ecore_idle_enterer_add(_e_comp_wl_cb_idle, NULL);
/* TODO: event handlers ?? */
/* try to add a display socket */
if (wl_display_add_socket(_e_wl_comp->wl.display, NULL) < 0)
{
ERR("Could not add a Wayland Display socket: %m");
goto err;
}
wl_event_loop_dispatch(_e_wl_comp->wl.loop, 0);
#ifndef WAYLAND_ONLY
/* add an idler for deferred shell module loading */
_module_idler = ecore_idler_add(_e_comp_wl_cb_module_idle, NULL);
#endif
/* return success */
return EINA_TRUE;
err:
/* remove kbd handler */
if (_e_wl_comp->kbd_handler)
ecore_event_handler_del(_e_wl_comp->kbd_handler);
#ifndef WAYLAND_ONLY
/* remove the module idler */
if (_module_idler) ecore_idler_del(_module_idler);
#endif
#ifdef HAVE_WAYLAND_EGL
/* unbind wayland display */
if (_e_wl_comp->egl.bound)
_e_wl_comp->egl.unbind_display(_e_wl_comp->egl.display, _e_wl_comp->wl.display);
/* terminate the egl display */
if (_e_wl_comp->egl.display) eglTerminate(_e_wl_comp->egl.display);
eglReleaseThread();
#endif
/* if we have a display, destroy it */
if (_e_wl_comp->wl.display) wl_display_destroy(_e_wl_comp->wl.display);
/* free the compositor */
E_FREE(_e_wl_comp);
/* return failure */
return EINA_FALSE;
}
EINTERN void
e_comp_wl_shutdown(void)
{
E_Module *mod = NULL;
if (_e_wl_comp)
{
/* remove the idler */
if (_e_wl_comp->idler) ecore_idler_del(_e_wl_comp->idler);
/* remove the fd handler */
if (_e_wl_comp->fd_handler)
ecore_main_fd_handler_del(_e_wl_comp->fd_handler);
/* shutdown input */
_e_comp_wl_input_shutdown();
#ifdef HAVE_WAYLAND_EGL
/* unbind wayland display */
if (_e_wl_comp->egl.bound)
_e_wl_comp->egl.unbind_display(_e_wl_comp->egl.display, _e_wl_comp->wl.display);
/* terminate the egl display */
if (_e_wl_comp->egl.display) eglTerminate(_e_wl_comp->egl.display);
eglReleaseThread();
#endif
/* if we have a display, destroy it */
if (_e_wl_comp->wl.display) wl_display_destroy(_e_wl_comp->wl.display);
/* free the compositor */
E_FREE(_e_wl_comp);
}
/* disable the loaded shell module */
/* TODO: we should have a config variable somewhere to store which
* shell we want to unload (tablet, mobile, etc) */
if ((mod = e_module_find("wl_desktop_shell")))
e_module_disable(mod);
}
#ifdef WAYLAND_ONLY
EAPI int
e_comp_wl_input_read(int fd EINA_UNUSED, unsigned int mask EINA_UNUSED, void *data)
{
E_Wayland_Compositor *wl_comp = data;
wl_event_loop_dispatch(wl_comp->wl.input_loop, 0);
return 1;
}
#endif
EAPI void
wl_seat_init(struct wl_seat *seat)
{
memset(seat, 0, sizeof *seat);
wl_signal_init(&seat->destroy_signal);
seat->selection_data_source = NULL;
wl_list_init(&seat->base_resource_list);
wl_signal_init(&seat->selection_signal);
wl_list_init(&seat->drag_resource_list);
wl_signal_init(&seat->drag_icon_signal);
}
EAPI void
wl_seat_release(struct wl_seat *seat)
{
/* if (seat->pointer) */
/* { */
/* if (seat->pointer->focus) */
/* wl_list_remove(&seat->pointer->focus_listener.link); */
/* } */
/* if (seat->keyboard) */
/* { */
/* if (seat->keyboard->focus) */
/* wl_list_remove(&seat->keyboard->focus_listener.link); */
/* } */
/* if (seat->touch) */
/* { */
/* if (seat->touch->focus) */
/* wl_list_remove(&seat->touch->focus_listener.link); */
/* } */
wl_signal_emit(&seat->destroy_signal, seat);
}
EAPI void
wl_seat_set_pointer(struct wl_seat *seat, struct wl_pointer *pointer)
{
if (pointer && (seat->pointer || pointer->seat)) return; /* XXX: error? */
if (!pointer && !seat->pointer) return;
seat->pointer = pointer;
if (pointer) pointer->seat = seat;
_seat_send_updated_caps(seat);
}
EAPI void
wl_seat_set_keyboard(struct wl_seat *seat, struct wl_keyboard *keyboard)
{
if (keyboard && (seat->keyboard || keyboard->seat)) return; /* XXX: error? */
if (!keyboard && !seat->keyboard) return;
seat->keyboard = keyboard;
if (keyboard) keyboard->seat = seat;
_seat_send_updated_caps(seat);
}
EAPI void
wl_seat_set_touch(struct wl_seat *seat, struct wl_touch *touch)
{
if (touch && (seat->touch || touch->seat)) return; /* XXX: error? */
if (!touch && !seat->touch) return;
seat->touch = touch;
if (touch) touch->seat = seat;
_seat_send_updated_caps(seat);
}
EAPI void
wl_pointer_init(struct wl_pointer *pointer)
{
memset(pointer, 0, sizeof *pointer);
wl_list_init(&pointer->resource_list);
wl_list_init(&pointer->focus_resource_list);
pointer->default_grab.interface = &_e_pointer_grab_interface;
pointer->default_grab.pointer = pointer;
pointer->grab = &pointer->default_grab;
wl_signal_init(&pointer->focus_signal);
pointer->x = wl_fixed_from_int(100);
pointer->y = wl_fixed_from_int(100);
}
EAPI void
wl_pointer_set_focus(struct wl_pointer *pointer, struct wl_resource *surface, wl_fixed_t sx, wl_fixed_t sy)
{
struct wl_keyboard *kbd = pointer->seat->keyboard;
struct wl_resource *res;
struct wl_list *lst;
uint32_t serial;
lst = &pointer->focus_resource_list;
if ((!wl_list_empty(lst)) && (pointer->focus != surface))
{
serial = wl_display_next_serial(_e_wl_comp->wl.display);
wl_resource_for_each(res, lst)
wl_pointer_send_leave(res, serial, pointer->focus);
_move_resources(&pointer->resource_list, lst);
}
if ((_find_resource_for_surface(&pointer->resource_list, surface)) &&
(pointer->focus != surface))
{
struct wl_client *client;
client = wl_resource_get_client(surface);
_move_resources_for_client(lst, &pointer->resource_list, client);
wl_resource_for_each(res, lst)
wl_pointer_send_enter(res, serial, surface, sx, sy);
pointer->focus_serial = serial;
}
if ((kbd) && (surface) && (kbd->focus != pointer->focus))
{
struct wl_client *client;
client = wl_resource_get_client(surface);
wl_resource_for_each(res, &kbd->resource_list)
{
if (wl_resource_get_client(res) == client)
wl_keyboard_send_modifiers(res, serial,
kbd->modifiers.mods_depressed,
kbd->modifiers.mods_latched,
kbd->modifiers.mods_locked,
kbd->modifiers.group);
}
}
pointer->focus = surface;
pointer->default_grab.focus = surface;
wl_signal_emit(&pointer->focus_signal, pointer);
}
EAPI void
wl_pointer_start_grab(struct wl_pointer *pointer, struct wl_pointer_grab *grab)
{
const struct wl_pointer_grab_interface *interface;
pointer->grab = grab;
interface = pointer->grab->interface;
grab->pointer = pointer;
if (pointer->current)
interface->focus(pointer->grab, pointer->current,
pointer->current_x, pointer->current_y);
}
EAPI void
wl_pointer_end_grab(struct wl_pointer *pointer)
{
const struct wl_pointer_grab_interface *interface;
pointer->grab = &pointer->default_grab;
interface = pointer->grab->interface;
interface->focus(pointer->grab, pointer->current,
pointer->current_x, pointer->current_y);
}
EAPI void
wl_keyboard_init(struct wl_keyboard *keyboard)
{
memset(keyboard, 0, sizeof *keyboard);
wl_list_init(&keyboard->resource_list);
wl_array_init(&keyboard->keys);
wl_list_init(&keyboard->focus_resource_list);
keyboard->default_grab.interface = &_e_default_keyboard_grab_interface;
keyboard->default_grab.keyboard = keyboard;
keyboard->grab = &keyboard->default_grab;
wl_signal_init(&keyboard->focus_signal);
}
EAPI void
wl_keyboard_set_focus(struct wl_keyboard *keyboard, struct wl_resource *surface)
{
struct wl_resource *res;
struct wl_list *lst;
uint32_t serial;
lst = &keyboard->focus_resource_list;
if ((!wl_list_empty(lst)) && (keyboard->focus != surface))
{
serial = wl_display_next_serial(_e_wl_comp->wl.display);
wl_resource_for_each(res, lst)
wl_keyboard_send_leave(res, serial, keyboard->focus);
_move_resources(&keyboard->resource_list, lst);
}
if ((_find_resource_for_surface(&keyboard->resource_list, surface)) &&
(keyboard->focus != surface))
{
struct wl_client *client;
client = wl_resource_get_client(surface);
serial = wl_display_next_serial(_e_wl_comp->wl.display);
_move_resources_for_client(lst, &keyboard->resource_list, client);
wl_resource_for_each(res, lst)
{
wl_keyboard_send_modifiers(res, serial,
keyboard->modifiers.mods_depressed,
keyboard->modifiers.mods_latched,
keyboard->modifiers.mods_locked,
keyboard->modifiers.group);
wl_keyboard_send_enter(res, serial, surface, &keyboard->keys);
}
keyboard->focus_serial = serial;
}
keyboard->focus = surface;
wl_signal_emit(&keyboard->focus_signal, keyboard);
}
EAPI void
wl_keyboard_start_grab(struct wl_keyboard *device, struct wl_keyboard_grab *grab)
{
device->grab = grab;
grab->keyboard = device;
}
EAPI void
wl_keyboard_end_grab(struct wl_keyboard *keyboard)
{
keyboard->grab = &keyboard->default_grab;
}
EAPI void
wl_touch_init(struct wl_touch *touch)
{
memset(touch, 0, sizeof *touch);
wl_list_init(&touch->resource_list);
wl_list_init(&touch->focus_resource_list);
touch->default_grab.interface = &_e_default_touch_grab_interface;
touch->default_grab.touch = touch;
touch->grab = &touch->default_grab;
wl_signal_init(&touch->focus_signal);
}
EAPI void
wl_touch_start_grab(struct wl_touch *device, struct wl_touch_grab *grab)
{
device->grab = grab;
grab->touch = device;
}
EAPI void
wl_touch_end_grab(struct wl_touch *touch)
{
touch->grab = &touch->default_grab;
}
EAPI void
wl_data_device_set_keyboard_focus(struct wl_seat *seat)
{
struct wl_resource *data_device, *focus, *offer;
struct wl_data_source *source;
if (!seat->keyboard) return;
focus = seat->keyboard->focus;
if (!focus) return;
data_device =
wl_resource_find_for_client(&seat->drag_resource_list,
wl_resource_get_client(focus));
if (!data_device) return;
source = seat->selection_data_source;
if (source)
{
offer = wl_data_source_send_offer(source, data_device);
wl_data_device_send_selection(data_device, offer);
}
}
EAPI int
wl_data_device_manager_init(struct wl_display *display)
{
if (!wl_global_create(display, &wl_data_device_manager_interface, 1,
NULL, _bind_manager))
return -1;
return 0;
}
EAPI struct wl_resource *
wl_data_source_send_offer(struct wl_data_source *source, struct wl_resource *target)
{
struct wl_data_offer *offer;
char **p;
offer = malloc(sizeof *offer);
if (offer == NULL) return NULL;
offer->resource =
wl_resource_create(wl_resource_get_client(target),
&wl_data_offer_interface, 1, 0);
if (!offer->resource)
{
free(offer);
return NULL;
}
wl_resource_set_implementation(offer->resource, &_e_data_offer_interface,
offer, _destroy_data_offer);
offer->source = source;
offer->source_destroy_listener.notify = _destroy_offer_data_source;
wl_signal_add(&source->destroy_signal,
&offer->source_destroy_listener);
wl_data_device_send_data_offer(target, offer->resource);
wl_array_for_each(p, &source->mime_types)
wl_data_offer_send_offer(offer->resource, *p);
return offer->resource;
}
EAPI void
wl_seat_set_selection(struct wl_seat *seat, struct wl_data_source *source, uint32_t serial)
{
struct wl_resource *data_device, *offer;
struct wl_resource *focus = NULL;
if (seat->selection_data_source &&
seat->selection_serial - serial < UINT32_MAX / 2)
return;
if (seat->selection_data_source)
{
seat->selection_data_source->cancel(seat->selection_data_source);
wl_list_remove(&seat->selection_data_source_listener.link);
seat->selection_data_source = NULL;
}
seat->selection_data_source = source;
seat->selection_serial = serial;
if (seat->keyboard)
focus = seat->keyboard->focus;
if (focus)
{
data_device =
wl_resource_find_for_client(&seat->drag_resource_list,
wl_resource_get_client(focus));
if (data_device && source)
{
offer = wl_data_source_send_offer(seat->selection_data_source,
data_device);
wl_data_device_send_selection(data_device, offer);
}
else if (data_device)
{
wl_data_device_send_selection(data_device, NULL);
}
}
wl_signal_emit(&seat->selection_signal, seat);
if (source)
{
seat->selection_data_source_listener.notify =
_destroy_selection_data_source;
wl_signal_add(&source->destroy_signal,
&seat->selection_data_source_listener);
}
}
EAPI unsigned int
e_comp_wl_time_get(void)
{
struct timeval tm;
gettimeofday(&tm, NULL);
return (tm.tv_sec * 1000 + tm.tv_usec / 1000);
}
EAPI void
e_comp_wl_mouse_button(struct wl_resource *resource, uint32_t serial, uint32_t timestamp, uint32_t button, uint32_t state_w)
{
switch (button)
{
case BTN_LEFT:
case BTN_MIDDLE:
case BTN_RIGHT:
wl_pointer_send_button(resource, serial, timestamp,
button, state_w);
break;
case 4:
if (state_w)
wl_pointer_send_axis(resource, timestamp,
WL_POINTER_AXIS_VERTICAL_SCROLL,
-wl_fixed_from_int(1));
break;
case 5:
if (state_w)
wl_pointer_send_axis(resource, timestamp,
WL_POINTER_AXIS_VERTICAL_SCROLL,
wl_fixed_from_int(1));
break;
case 6:
if (state_w)
wl_pointer_send_axis(resource, timestamp,
WL_POINTER_AXIS_HORIZONTAL_SCROLL,
-wl_fixed_from_int(1));
break;
case 7:
if (state_w)
wl_pointer_send_axis(resource, timestamp,
WL_POINTER_AXIS_HORIZONTAL_SCROLL,
wl_fixed_from_int(1));
break;
}
}
EAPI void
e_comp_wl_input_modifiers_update(unsigned int serial)
{
struct wl_keyboard *kbd;
struct wl_keyboard_grab *grab;
unsigned int pressed = 0, latched = 0, locked = 0, group = 0;
Eina_Bool changed = EINA_FALSE;
/* check for valid keyboard */
if (!(kbd = _e_wl_comp->input->wl.seat.keyboard))
return;
/* try to get the current keyboard's grab interface.
* Fallback to the default grab */
if (!(grab = kbd->grab)) grab = &kbd->default_grab;
pressed = xkb_state_serialize_mods(_e_wl_comp->input->xkb.state,
XKB_STATE_DEPRESSED);
latched = xkb_state_serialize_mods(_e_wl_comp->input->xkb.state,
XKB_STATE_LATCHED);
locked = xkb_state_serialize_mods(_e_wl_comp->input->xkb.state,
XKB_STATE_LOCKED);
group = xkb_state_serialize_group(_e_wl_comp->input->xkb.state,
XKB_STATE_EFFECTIVE);
if ((pressed != kbd->modifiers.mods_depressed) ||
(latched != kbd->modifiers.mods_latched) ||
(locked != kbd->modifiers.mods_locked) ||
(group != kbd->modifiers.group))
changed = EINA_TRUE;
kbd->modifiers.mods_depressed = pressed;
kbd->modifiers.mods_latched = latched;
kbd->modifiers.mods_locked = locked;
kbd->modifiers.group = group;
/* TODO: update leds ? */
if (changed)
grab->interface->modifiers(grab, serial,
kbd->modifiers.mods_depressed,
kbd->modifiers.mods_latched,
kbd->modifiers.mods_locked,
kbd->modifiers.group);
}
/* local functions */
static void
_seat_send_updated_caps(struct wl_seat *seat)
{
struct wl_resource *res;
enum wl_seat_capability caps = 0;
if (seat->pointer)
caps |= WL_SEAT_CAPABILITY_POINTER;
if (seat->keyboard)
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
if (seat->touch)
caps |= WL_SEAT_CAPABILITY_TOUCH;
wl_resource_for_each(res, &seat->base_resource_list)
wl_seat_send_capabilities(res, caps);
}
static void
_move_resources(struct wl_list *dest, struct wl_list *src)
{
wl_list_insert_list(dest, src);
wl_list_init(src);
}
static void
_move_resources_for_client(struct wl_list *dest, struct wl_list *src, struct wl_client *client)
{
struct wl_resource *res, *tmp;
wl_resource_for_each_safe(res, tmp, src)
{
if (wl_resource_get_client(res) == client)
{
wl_list_remove(wl_resource_get_link(res));
wl_list_insert(dest, wl_resource_get_link(res));
}
}
}
static struct wl_resource *
_find_resource_for_surface(struct wl_list *list, struct wl_resource *surface)
{
if (!surface) return NULL;
return wl_resource_find_for_client(list, wl_resource_get_client(surface));
}
static void
_default_grab_focus(struct wl_pointer_grab *grab, struct wl_resource *surface, wl_fixed_t x, wl_fixed_t y)
{
struct wl_pointer *pointer = grab->pointer;
if (pointer->button_count > 0) return;
wl_pointer_set_focus(pointer, surface, x, y);
}
static void
_default_grab_motion(struct wl_pointer_grab *grab, uint32_t timestamp, wl_fixed_t x, wl_fixed_t y)
{
struct wl_list *lst;
struct wl_resource *res;
lst = &grab->pointer->focus_resource_list;
wl_resource_for_each(res, lst)
wl_pointer_send_motion(res, timestamp, x, y);
}
static void
_default_grab_button(struct wl_pointer_grab *grab, uint32_t timestamp, uint32_t button, uint32_t state_w)
{
struct wl_pointer *pointer = grab->pointer;
struct wl_list *lst;
struct wl_resource *res;
enum wl_pointer_button_state state = state_w;
lst = &pointer->focus_resource_list;
if (!wl_list_empty(lst))
{
uint32_t serial;
serial = wl_display_next_serial(_e_wl_comp->wl.display);
wl_resource_for_each(res, lst)
e_comp_wl_mouse_button(res, serial, timestamp, button, state_w);
}
}
static void
_default_grab_touch_down(struct wl_touch_grab *grab, uint32_t timestamp, int touch_id, wl_fixed_t sx, wl_fixed_t sy)
{
struct wl_resource *res;
struct wl_list *lst;
struct wl_touch *touch = grab->touch;
lst = &touch->focus_resource_list;
if (!wl_list_empty(lst) && (touch->focus))
{
uint32_t serial;
serial = wl_display_next_serial(_e_wl_comp->wl.display);
wl_resource_for_each(res, lst)
wl_touch_send_down(res, serial, timestamp,
touch->focus, touch_id, sx, sy);
}
}
static void
_default_grab_touch_up(struct wl_touch_grab *grab, uint32_t timestamp, int touch_id)
{
struct wl_resource *res;
struct wl_list *lst;
struct wl_touch *touch = grab->touch;
lst = &touch->focus_resource_list;
if (!wl_list_empty(lst) && (touch->focus))
{
uint32_t serial;
serial = wl_display_next_serial(_e_wl_comp->wl.display);
wl_resource_for_each(res, lst)
wl_touch_send_up(res, serial, timestamp, touch_id);
}
}
static void
_default_grab_touch_motion(struct wl_touch_grab *grab, uint32_t timestamp, int touch_id, wl_fixed_t sx, wl_fixed_t sy)
{
struct wl_resource *res;
struct wl_list *lst;
struct wl_touch *touch = grab->touch;
lst = &touch->focus_resource_list;
wl_resource_for_each(res, lst)
wl_touch_send_motion(res, timestamp, touch_id, sx, sy);
}
static void
_data_offer_accept(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *mime_type)
{
struct wl_data_offer *offer;
offer = wl_resource_get_user_data(resource);
if (offer->source)
offer->source->accept(offer->source, serial, mime_type);
}
static void
_data_offer_receive(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *mime_type, int32_t fd)
{
struct wl_data_offer *offer;
offer = wl_resource_get_user_data(resource);
if (offer->source)
offer->source->send(offer->source, mime_type, fd);
else
close(fd);
}
static void
_data_offer_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
_destroy_data_offer(struct wl_resource *resource)
{
struct wl_data_offer *offer;
offer = wl_resource_get_user_data(resource);
if (offer->source)
wl_list_remove(&offer->source_destroy_listener.link);
free(offer);
}
static void
_destroy_offer_data_source(struct wl_listener *listener, void *data EINA_UNUSED)
{
struct wl_data_offer *offer;
offer = container_of(listener, struct wl_data_offer,
source_destroy_listener);
offer->source = NULL;
}
static void
_create_data_source(struct wl_client *client, struct wl_resource *resource, uint32_t id)
{
struct wl_data_source *source;
source = malloc(sizeof *source);
if (source == NULL)
{
wl_resource_post_no_memory(resource);
return;
}
wl_signal_init(&source->destroy_signal);
source->accept = _client_source_accept;
source->send = _client_source_send;
source->cancel = _client_source_cancel;
wl_array_init(&source->mime_types);
source->resource =
wl_resource_create(client, &wl_data_source_interface, 1, id);
wl_resource_set_implementation(source->resource,
&_e_data_source_interface, source,
_destroy_data_source);
}
static void
_unbind_data_device(struct wl_resource *resource)
{
wl_list_remove(wl_resource_get_link(resource));
}
static void
_get_data_device(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *seat_resource)
{
struct wl_seat *seat;
struct wl_resource *resource;
seat = wl_resource_get_user_data(seat_resource);
resource =
wl_resource_create(client, &wl_data_device_interface, 1, id);
if (!resource)
{
wl_resource_post_no_memory(manager_resource);
return;
}
wl_list_insert(&seat->drag_resource_list, wl_resource_get_link(resource));
wl_resource_set_implementation(resource, &_e_data_device_interface, seat,
_unbind_data_device);
}
static void
_current_surface_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
{
struct wl_pointer *pointer =
container_of(listener, struct wl_pointer, current_listener);
pointer->current = NULL;
}
static void
_bind_manager(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id)
{
struct wl_resource *res;
res = wl_resource_create(client, &wl_data_device_manager_interface, 1, id);
if (!res)
{
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(res, &_e_manager_interface, NULL, NULL);
}
static void
_default_grab_key(struct wl_keyboard_grab *grab, uint32_t timestamp, uint32_t key, uint32_t state)
{
struct wl_keyboard *keyboard = grab->keyboard;
struct wl_resource *res;
struct wl_list *lst;
lst = &keyboard->focus_resource_list;
if (!wl_list_empty(lst))
{
uint32_t serial;
serial = wl_display_next_serial(_e_wl_comp->wl.display);
wl_resource_for_each(res, lst)
wl_keyboard_send_key(res, serial, timestamp, key, state);
}
}
static void
_default_grab_modifiers(struct wl_keyboard_grab *grab, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
{
struct wl_keyboard *keyboard = grab->keyboard;
struct wl_pointer *pointer = keyboard->seat->pointer;
struct wl_resource *res;
struct wl_list *lst;
lst = &keyboard->focus_resource_list;
wl_resource_for_each(res, lst)
wl_keyboard_send_modifiers(res, serial, mods_depressed, mods_latched,
mods_locked, group);
if (pointer && pointer->focus && pointer->focus != keyboard->focus)
{
struct wl_client *client;
lst = &keyboard->resource_list;
client = wl_resource_get_client(pointer->focus);
wl_resource_for_each(res, lst)
{
if (wl_resource_get_client(res) == client)
wl_keyboard_send_modifiers(res, serial, mods_depressed,
mods_latched, mods_locked, group);
}
}
}
static void
_data_device_start_drag(struct wl_client *client, struct wl_resource *resource, struct wl_resource *source_resource, struct wl_resource *origin_resource, struct wl_resource *icon_resource, uint32_t serial EINA_UNUSED)
{
struct wl_seat *seat;
seat = wl_resource_get_user_data(resource);
if ((seat->pointer->button_count == 0) ||
(seat->pointer->grab_serial != serial) ||
(seat->pointer->focus != wl_resource_get_user_data(origin_resource)))
return;
seat->drag_grab.interface = &_e_drag_grab_interface;
seat->drag_client = client;
seat->drag_data_source = NULL;
if (source_resource)
{
struct wl_data_source *source;
source = wl_resource_get_user_data(source_resource);
seat->drag_data_source = source;
seat->drag_data_source_listener.notify =
_destroy_data_device_source;
wl_signal_add(&source->destroy_signal,
&seat->drag_data_source_listener);
}
if (icon_resource)
{
E_Wayland_Surface *icon;
icon = wl_resource_get_user_data(icon_resource);
seat->drag_surface = icon->wl.surface;
seat->drag_icon_listener.notify = _destroy_data_device_icon;
wl_signal_add(&icon->wl.destroy_signal,
&seat->drag_icon_listener);
/* wl_signal_emit(&seat->drag_icon_signal, icon_resource); */
}
wl_pointer_set_focus(seat->pointer, NULL,
wl_fixed_from_int(0), wl_fixed_from_int(0));
wl_pointer_start_grab(seat->pointer, &seat->drag_grab);
}
static void
_data_device_set_selection(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *source_resource, uint32_t serial)
{
struct wl_data_source *source;
struct wl_seat *seat;
if (!(seat = wl_resource_get_user_data(resource))) return;
source = wl_resource_get_user_data(source_resource);
wl_seat_set_selection(seat, source, serial);
}
static void
_destroy_data_device_icon(struct wl_listener *listener, void *data EINA_UNUSED)
{
struct wl_seat *seat =
container_of(listener, struct wl_seat, drag_icon_listener);
seat->drag_surface = NULL;
}
static void
_destroy_selection_data_source(struct wl_listener *listener, void *data EINA_UNUSED)
{
struct wl_seat *seat =
container_of(listener, struct wl_seat, selection_data_source_listener);
struct wl_resource *data_device;
struct wl_resource *focus = NULL;
seat->selection_data_source = NULL;
if (seat->keyboard)
focus = seat->keyboard->focus;
if (focus)
{
data_device =
wl_resource_find_for_client(&seat->drag_resource_list,
wl_resource_get_client(focus));
if (data_device)
wl_data_device_send_selection(data_device, NULL);
}
wl_signal_emit(&seat->selection_signal, seat);
}
static void
_destroy_data_device_source(struct wl_listener *listener, void *data EINA_UNUSED)
{
struct wl_seat *seat =
container_of(listener, struct wl_seat, drag_data_source_listener);
_data_device_end_drag_grab(seat);
}
static void
_data_source_offer(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *type)
{
struct wl_data_source *source;
char **p;
source = wl_resource_get_user_data(resource);
p = wl_array_add(&source->mime_types, sizeof *p);
if (p) *p = strdup(type);
if (!p || !*p) wl_resource_post_no_memory(resource);
}
static void
_data_source_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
_destroy_data_source(struct wl_resource *resource)
{
struct wl_data_source *source;
char **p;
source = wl_resource_get_user_data(resource);
wl_signal_emit(&source->destroy_signal, source);
wl_array_for_each(p, &source->mime_types)
free(*p);
wl_array_release(&source->mime_types);
source->resource = NULL;
}
static void
_data_device_end_drag_grab(struct wl_seat *seat)
{
if (seat->drag_surface)
{
seat->drag_surface = NULL;
wl_signal_emit(&seat->drag_icon_signal, NULL);
wl_list_remove(&seat->drag_icon_listener.link);
}
_drag_grab_focus(&seat->drag_grab, NULL,
wl_fixed_from_int(0), wl_fixed_from_int(0));
wl_pointer_end_grab(seat->pointer);
seat->drag_data_source = NULL;
seat->drag_client = NULL;
}
static void
_drag_grab_button(struct wl_pointer_grab *grab, uint32_t timestamp EINA_UNUSED, uint32_t button, uint32_t state_w)
{
struct wl_seat *seat = container_of(grab, struct wl_seat, drag_grab);
enum wl_pointer_button_state state = state_w;
if (seat->drag_focus_resource &&
seat->pointer->grab_button == button &&
state == WL_POINTER_BUTTON_STATE_RELEASED)
wl_data_device_send_drop(seat->drag_focus_resource);
if (seat->pointer->button_count == 0 &&
state == WL_POINTER_BUTTON_STATE_RELEASED)
{
if (seat->drag_data_source)
wl_list_remove(&seat->drag_data_source_listener.link);
_data_device_end_drag_grab(seat);
}
}
static void
_drag_grab_motion(struct wl_pointer_grab *grab, uint32_t timestamp, wl_fixed_t x, wl_fixed_t y)
{
struct wl_seat *seat = container_of(grab, struct wl_seat, drag_grab);
if (seat->drag_focus_resource)
wl_data_device_send_motion(seat->drag_focus_resource,
timestamp, x, y);
}
static void
_destroy_drag_focus(struct wl_listener *listener, void *data EINA_UNUSED)
{
struct wl_seat *seat =
container_of(listener, struct wl_seat, drag_focus_listener);
seat->drag_focus_resource = NULL;
}
static void
_drag_grab_focus(struct wl_pointer_grab *grab, struct wl_resource *surface, wl_fixed_t x, wl_fixed_t y)
{
struct wl_seat *seat = container_of(grab, struct wl_seat, drag_grab);
struct wl_resource *resource, *offer = NULL;
struct wl_display *display;
uint32_t serial;
E_Wayland_Surface *ews;
if (seat->drag_focus_resource)
{
wl_data_device_send_leave(seat->drag_focus_resource);
wl_list_remove(&seat->drag_focus_listener.link);
seat->drag_focus_resource = NULL;
seat->drag_focus = NULL;
}
if (!surface) return;
if (!seat->drag_data_source &&
wl_resource_get_client(surface) != seat->drag_client)
return;
resource =
wl_resource_find_for_client(&seat->drag_resource_list,
wl_resource_get_client(surface));
if (!resource) return;
display = wl_client_get_display(wl_resource_get_client(resource));
serial = wl_display_next_serial(display);
if (seat->drag_data_source)
offer = wl_data_source_send_offer(seat->drag_data_source,
resource);
wl_data_device_send_enter(resource, serial, surface, x, y, offer);
ews = wl_resource_get_user_data(surface);
seat->drag_focus = surface;
seat->drag_focus_listener.notify = _destroy_drag_focus;
wl_signal_add(&ews->wl.destroy_signal, &seat->drag_focus_listener);
seat->drag_focus_resource = resource;
grab->focus = surface;
}
static void
_client_source_accept(struct wl_data_source *source, uint32_t timestamp EINA_UNUSED, const char *mime_type)
{
wl_data_source_send_target(source->resource, mime_type);
}
static void
_client_source_send(struct wl_data_source *source, const char *mime_type, int32_t fd)
{
wl_data_source_send_send(source->resource, mime_type, fd);
close(fd);
}
static void
_client_source_cancel(struct wl_data_source *source)
{
wl_data_source_send_cancelled(source->resource);
}
static void
_e_comp_wl_cb_bind(struct wl_client *client, void *data, unsigned int version, unsigned int id)
{
E_Wayland_Compositor *comp;
struct wl_resource *res;
if (!(comp = data)) return;
res =
wl_resource_create(client, &wl_compositor_interface, MIN(version, 3), id);
if (res)
wl_resource_set_implementation(res, &_e_compositor_interface, comp, NULL);
}
static Eina_Bool
_e_comp_wl_cb_read(void *data EINA_UNUSED, Ecore_Fd_Handler *hdl EINA_UNUSED)
{
/* flush any events before we sleep */
wl_display_flush_clients(_e_wl_comp->wl.display);
wl_event_loop_dispatch(_e_wl_comp->wl.loop, 0);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_wl_cb_idle(void *data EINA_UNUSED)
{
if ((_e_wl_comp) && (_e_wl_comp->wl.display))
{
/* flush any clients before we idle */
wl_display_flush_clients(_e_wl_comp->wl.display);
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_wl_cb_module_idle(void *data EINA_UNUSED)
{
E_Module *mod = NULL;
/* if we are still in the process of loading modules, then we will wait */
if (e_module_loading_get()) return ECORE_CALLBACK_RENEW;
/* try to find the shell module, and create it if not found
*
* TODO: we should have a config variable somewhere to store which
* shell we want to load (tablet, mobile, etc) */
if (!(mod = e_module_find("wl_desktop_shell")))
mod = e_module_new("wl_desktop_shell");
/* if we have the module now, load it */
if (mod)
{
e_module_enable(mod);
_module_idler = NULL;
/* flush any pending events
*
* NB: This advertises out any globals so it needs to be deferred
* until after the shell has been loaded */
wl_event_loop_dispatch(_e_wl_comp->wl.loop, 0);
return ECORE_CALLBACK_CANCEL;
}
return ECORE_CALLBACK_RENEW;
}
EAPI Eina_Bool
e_comp_wl_cb_keymap_changed(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
{
struct xkb_keymap *keymap;
/* try to fetch the keymap */
if (!(keymap = _e_comp_wl_input_keymap_get()))
return ECORE_CALLBACK_PASS_ON;
/* destroy keyboard */
if (_e_wl_comp->input->xkb.info)
{
/* if we have a keymap, unreference it */
if (_e_wl_comp->input->xkb.info->keymap)
xkb_map_unref(_e_wl_comp->input->xkb.info->keymap);
/* if we have a keymap mmap'd area, unmap it */
if (_e_wl_comp->input->xkb.info->area)
munmap(_e_wl_comp->input->xkb.info->area,
_e_wl_comp->input->xkb.info->size);
/* if we created an fd for keyboard input, close it */
if (_e_wl_comp->input->xkb.info->fd)
close(_e_wl_comp->input->xkb.info->fd);
/* free the allocated keyboard info structure */
E_FREE(_e_wl_comp->input->xkb.info);
}
/* unreference the xkb state we created */
if (_e_wl_comp->input->xkb.state)
xkb_state_unref(_e_wl_comp->input->xkb.state);
/* unreference the xkb context we created */
if (_e_wl_comp->xkb.context)
xkb_context_unref(_e_wl_comp->xkb.context);
/* create the xkb context */
_e_wl_comp->xkb.context = xkb_context_new(0);
/* try to fetch the keymap */
// if ((keymap = _e_comp_wl_input_keymap_get()))
{
/* try to create new keyboard info */
_e_wl_comp->input->xkb.info =
_e_comp_wl_input_keyboard_info_get(keymap);
/* create new xkb state */
_e_wl_comp->input->xkb.state = xkb_state_new(keymap);
/* unreference the keymap */
xkb_map_unref(keymap);
}
/* check for valid keyboard */
if (!_e_wl_comp->input->wl.keyboard_resource)
return ECORE_CALLBACK_PASS_ON;
/* send the current keymap to the keyboard object */
wl_keyboard_send_keymap(_e_wl_comp->input->wl.keyboard_resource,
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
_e_wl_comp->input->xkb.info->fd,
_e_wl_comp->input->xkb.info->size);
return ECORE_CALLBACK_PASS_ON;
}
/* compositor interface functions */
static void
_e_comp_wl_cb_surface_create(struct wl_client *client, struct wl_resource *resource, unsigned int id)
{
E_Wayland_Surface *ews = NULL;
uint64_t wid;
pid_t pid;
/* try to allocate space for a new surface */
if (!(ews = E_NEW(E_Wayland_Surface, 1)))
{
wl_resource_post_no_memory(resource);
return;
}
ews->wl.client = client;
wl_client_get_credentials(client, &pid, NULL, NULL);
wid = e_comp_wl_id_get(pid, id);
ews->pixmap = e_pixmap_find(E_PIXMAP_TYPE_WL, wid);
if (!ews->pixmap)
ews->pixmap = e_pixmap_new(E_PIXMAP_TYPE_WL, wid);
e_pixmap_parent_window_set(ews->pixmap, ews);
e_pixmap_usable_set(ews->pixmap, 1);
/* initialize the destroy signal */
wl_signal_init(&ews->wl.destroy_signal);
/* initialize the link */
wl_list_init(&ews->wl.link);
/* initialize the lists of frames */
wl_list_init(&ews->wl.frames);
wl_list_init(&ews->pending.frames);
ews->wl.surface = NULL;
/* set destroy function for pending buffers */
ews->pending.buffer_destroy.notify =
_e_comp_wl_surface_cb_pending_buffer_destroy;
/* initialize regions */
pixman_region32_init(&ews->region.opaque);
pixman_region32_init(&ews->region.damage);
pixman_region32_init(&ews->region.clip);
pixman_region32_init_rect(&ews->region.input, INT32_MIN, INT32_MIN,
UINT32_MAX, UINT32_MAX);
/* initialize pending regions */
pixman_region32_init(&ews->pending.opaque);
pixman_region32_init(&ews->pending.damage);
pixman_region32_init_rect(&ews->pending.input, INT32_MIN, INT32_MIN,
UINT32_MAX, UINT32_MAX);
ews->wl.surface =
wl_resource_create(client, &wl_surface_interface,
wl_resource_get_version(resource), id);
wl_resource_set_implementation(ews->wl.surface, &_e_surface_interface,
ews, _e_comp_wl_cb_surface_destroy);
/* add this surface to the list of surfaces */
_e_wl_comp->surfaces = eina_inlist_append(_e_wl_comp->surfaces, EINA_INLIST_GET(ews));
}
static void
_e_comp_wl_cb_surface_destroy(struct wl_resource *resource)
{
E_Wayland_Surface *ews = NULL;
E_Wayland_Surface_Frame_Callback *cb = NULL, *ncb = NULL;
struct wl_pointer *pointer;
Eina_Inlist *l;
E_Wayland_Buffer *buffer;
/* try to get the surface from this resource */
if (!(ews = wl_resource_get_user_data(resource)))
return;
pointer = &_e_wl_comp->input->wl.pointer;
if (pointer->focus == resource)
{
wl_pointer_set_focus(pointer, NULL,
wl_fixed_from_int(0), wl_fixed_from_int(0));
_e_wl_comp->input->pointer.surface = NULL;
}
/* if this surface is mapped, unmap it */
if (ews->mapped)
{
if (ews->unmap) ews->unmap(ews);
}
if (ews->buffer_reference.buffer)
ews->buffer_reference.buffer->ews = NULL;
if (ews->pending.buffer)
ews->pending.buffer->ews = NULL;
/* loop any pending surface frame callbacks and destroy them */
wl_list_for_each_safe(cb, ncb, &ews->pending.frames, wl.link)
wl_resource_destroy(cb->wl.resource);
/* clear any pending regions */
pixman_region32_fini(&ews->pending.damage);
pixman_region32_fini(&ews->pending.opaque);
pixman_region32_fini(&ews->pending.input);
/* remove the pending buffer from the list */
if (ews->pending.buffer)
wl_list_remove(&ews->pending.buffer_destroy.link);
/* dereference any existing buffers */
_e_comp_wl_surface_buffer_reference(&ews->buffer_reference, NULL);
/* clear any active regions */
pixman_region32_fini(&ews->region.damage);
pixman_region32_fini(&ews->region.opaque);
pixman_region32_fini(&ews->region.input);
pixman_region32_fini(&ews->region.clip);
/* loop any active surface frame callbacks and destroy them */
wl_list_for_each_safe(cb, ncb, &ews->wl.frames, wl.link)
wl_resource_destroy(cb->wl.resource);
EINA_INLIST_FOREACH_SAFE(ews->buffers, l, buffer)
{
buffer->ews = NULL;
ews->buffers = eina_inlist_remove(ews->buffers, EINA_INLIST_GET(buffer));
}
if (e_comp_get(NULL)->pointer->pixmap == ews->pixmap)
{
e_pointer_image_set(e_comp_get(NULL)->pointer, NULL, 0, 0, 0, 0);
}
e_pixmap_parent_window_set(ews->pixmap, NULL);
e_pixmap_free(ews->pixmap);
/* remove this surface from the compositor's list of surfaces */
_e_wl_comp->surfaces = eina_inlist_remove(_e_wl_comp->surfaces, EINA_INLIST_GET(ews));
/* free the allocated surface structure */
free(ews);
}
static void
_e_comp_wl_cb_region_create(struct wl_client *client, struct wl_resource *resource, unsigned int id)
{
E_Wayland_Region *ewr = NULL;
/* try to allocate space for a new region */
if (!(ewr = E_NEW_RAW(E_Wayland_Region, 1)))
{
wl_resource_post_no_memory(resource);
return;
}
pixman_region32_init(&ewr->region);
ewr->wl.resource =
wl_resource_create(client, &wl_region_interface,
wl_resource_get_version(resource), id);
wl_resource_set_implementation(ewr->wl.resource, &_e_region_interface, ewr,
_e_comp_wl_cb_region_destroy);
}
static void
_e_comp_wl_cb_region_destroy(struct wl_resource *resource)
{
E_Wayland_Region *ewr = NULL;
/* try to get the region from this resource */
if (!(ewr = wl_resource_get_user_data(resource)))
return;
/* tell pixman we are finished with this region */
pixman_region32_fini(&ewr->region);
/* free the allocated region structure */
E_FREE(ewr);
}
/* input functions */
static Eina_Bool
_e_comp_wl_input_init(void)
{
struct xkb_keymap *keymap;
/* try to allocate space for a new compositor */
if (!(_e_wl_comp->input = E_NEW(E_Wayland_Input, 1)))
return EINA_FALSE;
/* initialize the seat */
wl_seat_init(&_e_wl_comp->input->wl.seat);
/* try to add this input to the diplay's list of globals */
if (!wl_global_create(_e_wl_comp->wl.display, &wl_seat_interface, 2,
_e_wl_comp->input, _e_comp_wl_input_cb_bind))
{
ERR("Could not add Input to Wayland Display Globals: %m");
goto err;
}
_e_wl_comp->input->pointer.surface = NULL;
_e_wl_comp->input->pointer.surface_destroy.notify =
_e_comp_wl_pointer_cb_destroy;
_e_wl_comp->input->pointer.hot.x = 16;
_e_wl_comp->input->pointer.hot.y = 16;
/* initialize wayland pointer */
wl_pointer_init(&_e_wl_comp->input->wl.pointer);
/* tell the seat about this pointer */
wl_seat_set_pointer(&_e_wl_comp->input->wl.seat,
&_e_wl_comp->input->wl.pointer);
/* set flag to indicate we have a pointer */
_e_wl_comp->input->has_pointer = EINA_TRUE;
/* create the xkb context */
_e_wl_comp->xkb.context = xkb_context_new(0);
/* try to fetch the keymap */
if ((keymap = _e_comp_wl_input_keymap_get()))
{
/* try to create new keyboard info */
_e_wl_comp->input->xkb.info =
_e_comp_wl_input_keyboard_info_get(keymap);
/* create new xkb state */
_e_wl_comp->input->xkb.state = xkb_state_new(keymap);
/* unreference the keymap */
xkb_map_unref(keymap);
}
/* initialize the keyboard */
wl_keyboard_init(&_e_wl_comp->input->wl.keyboard);
/* tell the seat about this keyboard */
wl_seat_set_keyboard(&_e_wl_comp->input->wl.seat,
&_e_wl_comp->input->wl.keyboard);
/* set flag to indicate we have a keyboard */
_e_wl_comp->input->has_keyboard = EINA_TRUE;
wl_list_init(&_e_wl_comp->input->wl.link);
/* append this input to the list */
_e_wl_comp->seats = eina_list_append(_e_wl_comp->seats, _e_wl_comp->input);
/* emit a signal saying that input has been initialized */
wl_signal_emit(&_e_wl_comp->signals.seat, _e_wl_comp->input);
/* return success */
return EINA_TRUE;
err:
/* release the wl_seat */
wl_seat_release(&_e_wl_comp->input->wl.seat);
/* free the allocated input structure */
E_FREE(_e_wl_comp->input);
/* return failure */
return EINA_FALSE;
}
static void
_e_comp_wl_input_shutdown(void)
{
/* safety check */
if (!_e_wl_comp->input) return;
/* destroy keyboard */
if (_e_wl_comp->input->xkb.info)
{
/* if we have a keymap, unreference it */
if (_e_wl_comp->input->xkb.info->keymap)
xkb_map_unref(_e_wl_comp->input->xkb.info->keymap);
/* if we have a keymap mmap'd area, unmap it */
if (_e_wl_comp->input->xkb.info->area)
munmap(_e_wl_comp->input->xkb.info->area,
_e_wl_comp->input->xkb.info->size);
/* if we created an fd for keyboard input, close it */
if (_e_wl_comp->input->xkb.info->fd)
close(_e_wl_comp->input->xkb.info->fd);
/* free the allocated keyboard info structure */
E_FREE(_e_wl_comp->input->xkb.info);
}
/* unreference the xkb state we created */
if (_e_wl_comp->input->xkb.state)
xkb_state_unref(_e_wl_comp->input->xkb.state);
/* unreference the xkb context we created */
if (_e_wl_comp->xkb.context)
xkb_context_unref(_e_wl_comp->xkb.context);
/* TODO: destroy pointer surface
*
* NB: Currently, we do not create one */
wl_list_remove(&_e_wl_comp->input->wl.link);
/* release the seat */
wl_seat_release(&_e_wl_comp->input->wl.seat);
/* free the allocated input structure */
E_FREE(_e_wl_comp->input);
}
static void
_e_comp_wl_input_cb_bind(struct wl_client *client, void *data, unsigned int version, unsigned int id)
{
struct wl_seat *seat = NULL;
struct wl_resource *resource = NULL;
enum wl_seat_capability caps = 0;
/* try to cast data to our seat */
if (!(seat = data)) return;
/* add the seat object to the client */
resource =
wl_resource_create(client, &wl_seat_interface, MIN(version, 2), id);
wl_list_insert(&seat->base_resource_list, wl_resource_get_link(resource));
wl_resource_set_implementation(resource, &_e_input_interface, data,
_e_comp_wl_input_cb_unbind);
/* set capabilities based on seat */
if (seat->pointer) caps |= WL_SEAT_CAPABILITY_POINTER;
if (seat->keyboard) caps |= WL_SEAT_CAPABILITY_KEYBOARD;
if (seat->touch) caps |= WL_SEAT_CAPABILITY_TOUCH;
/* inform the resource about the seat capabilities */
wl_seat_send_capabilities(resource, caps);
}
static void
_e_comp_wl_input_cb_unbind(struct wl_resource *resource)
{
/* remove the link */
wl_list_remove(wl_resource_get_link(resource));
}
static struct xkb_keymap *
_e_comp_wl_input_keymap_get(void)
{
E_Config_XKB_Layout *kbd_layout;
struct xkb_keymap *keymap;
struct xkb_rule_names names;
memset(&names, 0, sizeof(names));
if ((kbd_layout = e_xkb_layout_get()))
{
names.model = strdup(kbd_layout->model);
names.layout = strdup(kbd_layout->name);
}
#ifndef WAYLAND_ONLY
/* if we are running under X11, try to get the xkb rule names atom */
if (getenv("DISPLAY"))
{
Ecore_X_Atom rules = 0;
Ecore_X_Window root = 0;
int len = 0;
unsigned char *data;
/* TODO: FIXME: NB:
*
* The below commented out code is for using the "already" configured
* E xkb settings in the wayland clients. The only Major problem with
* that is: That the E_Config_XKB_Layout does not define a
* 'RULES' which we need ....
*
*/
root = ecore_x_window_root_first_get();
rules = ecore_x_atom_get("_XKB_RULES_NAMES");
ecore_x_window_prop_property_get(root, rules, ECORE_X_ATOM_STRING,
1024, &data, &len);
if ((data) && (len > 0))
{
names.rules = (char*)data;
data += strlen((const char *)data) + 1;
if (!names.model)
names.model = strdup((const char *)data);
data += strlen((const char *)data) + 1;
if (!names.layout)
names.layout = strdup((const char *)data);
}
}
#endif
printf("Keymap\n");
printf("\tRules: %s\n", names.rules);
printf("\tModel: %s\n", names.model);
printf("\tLayout: %s\n", names.layout);
keymap = xkb_map_new_from_names(_e_wl_comp->xkb.context, &names, 0);
free((char *)names.rules);
free((char *)names.model);
free((char *)names.layout);
return keymap;
}
static int
_e_comp_wl_input_keymap_fd_get(off_t size)
{
char tmp[PATH_MAX];
const char *path;
int fd = 0;
long flags;
if (!(path = getenv("XDG_RUNTIME_DIR")))
return -1;
strcpy(tmp, path);
strcat(tmp, "/e-wl-keymap-XXXXXX");
if ((fd = mkstemp(tmp)) < 0)
return -1;
/* TODO: really should error check the returns here */
flags = fcntl(fd, F_GETFD);
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
if (ftruncate(fd, size) < 0)
{
close(fd);
return -1;
}
unlink(tmp);
return fd;
}
static E_Wayland_Keyboard_Info *
_e_comp_wl_input_keyboard_info_get(struct xkb_keymap *keymap)
{
E_Wayland_Keyboard_Info *info = NULL;
char *tmp;
/* try to allocate space for the keyboard info structure */
if (!(info = E_NEW(E_Wayland_Keyboard_Info, 1)))
return NULL;
if (!(info->keymap = xkb_map_ref(keymap)))
{
E_FREE(info);
return NULL;
}
/* init modifiers */
info->mod_shift = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
info->mod_caps = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
info->mod_ctrl = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
info->mod_alt = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_ALT);
info->mod_super = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_LOGO);
/* try to get a string of this keymap */
if (!(tmp = xkb_map_get_as_string(keymap)))
{
printf("Could not get keymap as string\n");
E_FREE(info);
return NULL;
}
info->size = strlen(tmp) + 1;
/* try to create an fd we can listen on for input */
info->fd = _e_comp_wl_input_keymap_fd_get(info->size);
if (info->fd < 0)
{
printf("Could not create keymap fd\n");
E_FREE(info);
return NULL;
}
info->area =
mmap(NULL, info->size, PROT_READ | PROT_WRITE, MAP_SHARED, info->fd, 0);
/* TODO: error check mmap */
if ((info->area) && (tmp))
{
strcpy(info->area, tmp);
free(tmp);
}
return info;
}
/* input interface functions */
static void
_e_comp_wl_input_cb_pointer_get(struct wl_client *client, struct wl_resource *resource, unsigned int id)
{
E_Wayland_Input *input = NULL;
struct wl_resource *ptr = NULL;
/* try to cast the resource data to our input structure */
if (!(input = wl_resource_get_user_data(resource)))
return;
/* check that input has a pointer */
if (!input->has_pointer) return;
/* add a pointer object to the client */
ptr = wl_resource_create(client, &wl_pointer_interface,
wl_resource_get_version(resource), id);
wl_list_insert(&input->wl.seat.pointer->resource_list,
wl_resource_get_link(ptr));
wl_resource_set_implementation(ptr, &_e_pointer_interface,
input, _e_comp_wl_input_cb_unbind);
/* if the pointer has a focused surface, set it */
if ((input->wl.seat.pointer->focus) &&
(wl_resource_get_client(input->wl.seat.pointer->focus) == client))
{
/* tell pointer which surface is focused */
wl_list_remove(wl_resource_get_link(ptr));
wl_list_insert(&input->wl.seat.pointer->focus_resource_list,
wl_resource_get_link(ptr));
wl_pointer_send_enter(ptr, input->wl.seat.pointer->focus_serial,
input->wl.seat.pointer->focus,
input->wl.seat.pointer->x,
input->wl.seat.pointer->y);
}
}
static void
_e_comp_wl_input_cb_keyboard_get(struct wl_client *client, struct wl_resource *resource, unsigned int id)
{
E_Wayland_Input *input = NULL;
struct wl_resource *kbd = NULL;
/* try to cast the resource data to our input structure */
if (!(input = wl_resource_get_user_data(resource)))
return;
/* check that input has a keyboard */
if (!input->has_keyboard) return;
/* add a keyboard object to the client */
kbd = wl_resource_create(client, &wl_keyboard_interface,
wl_resource_get_version(resource), id);
wl_list_insert(&input->wl.seat.keyboard->resource_list,
wl_resource_get_link(kbd));
wl_resource_set_implementation(kbd, &_e_keyboard_interface, input,
_e_comp_wl_input_cb_unbind);
/* send the current keymap to the keyboard object */
wl_keyboard_send_keymap(kbd, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
input->xkb.info->fd, input->xkb.info->size);
if (((input->wl.seat.keyboard) && (input->wl.seat.keyboard->focus) &&
(wl_resource_get_client(input->wl.seat.keyboard->focus) == client)) ||
((input->wl.seat.pointer) && (input->wl.seat.pointer->focus) &&
(wl_resource_get_client(input->wl.seat.pointer->focus) == client)))
{
wl_keyboard_send_modifiers(kbd, input->wl.seat.keyboard->focus_serial,
input->wl.seat.keyboard->modifiers.mods_depressed,
input->wl.seat.keyboard->modifiers.mods_latched,
input->wl.seat.keyboard->modifiers.mods_locked,
input->wl.seat.keyboard->modifiers.group);
}
/* test if keyboard has a focused client */
if ((input->wl.seat.keyboard->focus) &&
(wl_resource_get_client(input->wl.seat.keyboard->focus) == client))
{
wl_list_remove(wl_resource_get_link(kbd));
wl_list_insert(&input->wl.seat.keyboard->focus_resource_list,
wl_resource_get_link(kbd));
wl_keyboard_send_enter(kbd, input->wl.seat.keyboard->focus_serial,
input->wl.seat.keyboard->focus,
&input->wl.seat.keyboard->keys);
if (input->wl.seat.keyboard->focus_resource_list.prev ==
wl_resource_get_link(kbd))
{
/* update the keyboard focus in the data device */
wl_data_device_set_keyboard_focus(&input->wl.seat);
}
}
input->wl.keyboard_resource = kbd;
}
static void
_e_comp_wl_input_cb_touch_get(struct wl_client *client, struct wl_resource *resource, unsigned int id)
{
E_Wayland_Input *input = NULL;
struct wl_resource *tch = NULL;
/* try to cast the resource data to our input structure */
if (!(input = wl_resource_get_user_data(resource)))
return;
/* check that input has a touch */
if (!input->has_touch) return;
/* add a touch object to the client */
tch = wl_resource_create(client, &wl_touch_interface,
wl_resource_get_version(resource), id);
if ((input->wl.seat.touch->focus) &&
(wl_resource_get_client(input->wl.seat.touch->focus) == client))
{
wl_list_insert(&input->wl.seat.touch->resource_list,
wl_resource_get_link(tch));
}
else
wl_list_insert(&input->wl.seat.touch->focus_resource_list,
wl_resource_get_link(tch));
wl_resource_set_implementation(tch, &_e_touch_interface, input,
_e_comp_wl_input_cb_unbind);
}
/* pointer functions */
static void
_e_comp_wl_pointer_cb_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
{
E_Wayland_Input *input = NULL;
/* try to get the input from this listener */
if (!(input = container_of(listener, E_Wayland_Input, pointer.surface_destroy)))
return;
input->pointer.surface = NULL;
}
static void
_e_comp_wl_pointer_configure(E_Wayland_Surface *ews, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
{
E_Wayland_Input *input = NULL;
E_Wayland_Surface *focus = NULL;
/* safety check */
if (!ews) return;
/* see if this surface has 'input' */
if (!(input = ews->input)) return;
input->pointer.hot.x -= x;
input->pointer.hot.y -= y;
/* configure the surface geometry */
ews->geometry.x = x;
ews->geometry.h = h;
ews->geometry.w = w;
ews->geometry.h = h;
ews->geometry.changed = EINA_TRUE;
/* tell pixman we are finished with this region */
pixman_region32_fini(&ews->pending.input);
/* reinitalize the pending input region */
pixman_region32_init(&ews->pending.input);
/* do we have a focused surface ? */
if (!input->wl.seat.pointer->focus) return;
focus = wl_resource_get_user_data(input->wl.seat.pointer->focus);
if (!focus) return;
/* NB: Ideally, I wanted to use the e_pointer methods here so that
* the cursor would match the E theme, however Wayland currently
* provides NO Method to get the cursor name :( so we are stuck
* using the pixels from their cursor surface */
/* is it mapped ? */
if ((!focus->mapped) || (!focus->ec)) return;
e_pixmap_dirty(ews->pixmap);
e_pointer_image_set(focus->ec->comp->pointer, ews->pixmap, w, h, input->pointer.hot.x, input->pointer.hot.y);
}
static void
_e_comp_wl_pointer_unmap(E_Wayland_Surface *ews)
{
E_Wayland_Input *input = NULL;
/* safety check */
if (!ews) return;
if (!(input = ews->input)) return;
wl_list_remove(&input->pointer.surface_destroy.link);
if (input->pointer.surface)
input->pointer.surface->configure = NULL;
input->pointer.surface = NULL;
}
/* pointer interface functions */
static void
_e_comp_wl_pointer_cb_cursor_set(struct wl_client *client, struct wl_resource *resource, unsigned int serial, struct wl_resource *surface_resource, int x, int y)
{
E_Wayland_Input *input = NULL;
E_Wayland_Surface *ews = NULL;
/* try to cast the resource data to our input structure */
if (!(input = wl_resource_get_user_data(resource)))
return;
/* if we were passed in a surface, try to cast it to our structure */
if (surface_resource) ews = wl_resource_get_user_data(surface_resource);
/* if this input has no pointer, get out */
if (!input->has_pointer) return;
/* if the input has no current focus, get out */
if (!input->wl.seat.pointer->focus)
{
/* if we have an existing pointer surface, unmap it */
if (input->pointer.surface)
{
/* call the unmap function */
if (input->pointer.surface->unmap)
input->pointer.surface->unmap(input->pointer.surface);
}
input->pointer.surface = NULL;
return;
}
if (wl_resource_get_client(input->wl.seat.pointer->focus) != client) return;
if ((input->wl.seat.pointer->focus_serial - serial) > (UINT32_MAX / 2))
return;
/* is the passed in surface the same as our pointer surface ? */
if ((ews) && (ews != input->pointer.surface))
{
if (ews->configure)
{
wl_resource_post_error(ews->wl.surface,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"Surface already configured");
return;
}
}
/* if we have an existing pointer surface, unmap it */
if (input->pointer.surface)
{
/* call the unmap function */
if (input->pointer.surface->unmap)
input->pointer.surface->unmap(input->pointer.surface);
}
input->pointer.surface = ews;
/* if we don't have a pointer surface, we are done here */
if (!ews)
{
e_pointer_hide(e_comp_get(NULL)->pointer);
return;
}
/* set the destroy listener */
wl_signal_add(&ews->wl.destroy_signal,
&input->pointer.surface_destroy);
/* set some properties on this surface */
ews->unmap = _e_comp_wl_pointer_unmap;
ews->configure = _e_comp_wl_pointer_configure;
ews->input = input;
/* update input structure with new values */
input->pointer.hot.x = x;
input->pointer.hot.y = y;
if (&ews->buffer_reference)
{
E_Wayland_Buffer *buf;
if ((buf = ews->buffer_reference.buffer))
{
Evas_Coord bw = 0, bh = 0;
bw = buf->w;
bh = buf->h;
/* configure the pointer surface */
_e_comp_wl_pointer_configure(ews, 0, 0, bw, bh);
}
}
}
static void
_e_comp_wl_pointer_cb_release(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
/* keyboard interface functions */
static void
_e_comp_wl_keyboard_cb_release(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
/* touch interface functions */
static void
_e_comp_wl_touch_cb_release(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
/* region interface functions */
static void
_e_comp_wl_region_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
_e_comp_wl_region_cb_add(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int x, int y, int w, int h)
{
E_Wayland_Region *ewr = NULL;
/* try to cast the resource data to our region structure */
if (!(ewr = wl_resource_get_user_data(resource))) return;
/* tell pixman to union this region with any previous one */
pixman_region32_union_rect(&ewr->region, &ewr->region, x, y, w, h);
}
static void
_e_comp_wl_region_cb_subtract(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int x, int y, int w, int h)
{
E_Wayland_Region *ewr = NULL;
pixman_region32_t region;
/* try to cast the resource data to our region structure */
if (!(ewr = wl_resource_get_user_data(resource))) return;
/* ask pixman to create a new temporary rect */
pixman_region32_init_rect(&region, x, y, w, h);
/* ask pixman to subtract this temp rect from the existing region */
pixman_region32_subtract(&ewr->region, &ewr->region, &region);
/* tell pixman we are finished with the temporary rect */
pixman_region32_fini(&region);
}
/* surface functions */
static void
_e_comp_wl_surface_cb_pending_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
{
E_Wayland_Surface *ews = NULL;
/* try to get the surface from this listener */
if (!(ews = container_of(listener, E_Wayland_Surface,
pending.buffer_destroy)))
return;
/* set surface pending buffer to null */
ews->pending.buffer = NULL;
}
static void
_e_comp_wl_surface_cb_frame_destroy(struct wl_resource *resource)
{
E_Wayland_Surface_Frame_Callback *cb = NULL;
/* try to cast the resource data to our surface frame callback structure */
if (!(cb = wl_resource_get_user_data(resource))) return;
wl_list_remove(&cb->wl.link);
/* free the allocated callback structure */
E_FREE(cb);
}
static void
_e_comp_wl_surface_buffer_reference(E_Wayland_Buffer_Reference *ref, E_Wayland_Buffer *buffer)
{
if ((ref->buffer) && (buffer != ref->buffer))
{
ref->buffer->busy_count--;
if (ref->buffer->busy_count == 0)
wl_resource_queue_event(ref->buffer->wl.resource, WL_BUFFER_RELEASE);
wl_list_remove(&ref->destroy_listener.link);
}
if ((buffer) && (buffer != ref->buffer))
{
buffer->busy_count++;
wl_signal_add(&buffer->wl.destroy_signal, &ref->destroy_listener);
}
//INF("CURRENT BUFFER SWAP: %p->%p", ref->buffer, buffer);
ref->buffer = buffer;
ref->destroy_listener.notify =
_e_comp_wl_surface_buffer_reference_cb_destroy;
}
static void
_e_comp_wl_surface_buffer_reference_cb_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
{
E_Wayland_Buffer_Reference *ref;
/* try to get the surface from this listener */
ref = container_of(listener, E_Wayland_Buffer_Reference, destroy_listener);
if (!ref) return;
/* set referenced buffer to null */
ref->buffer = NULL;
}
static E_Wayland_Buffer *
_e_comp_wl_surface_buffer_resource(struct wl_resource *resource)
{
E_Wayland_Buffer *buffer;
struct wl_listener *listener;
listener =
wl_resource_get_destroy_listener(resource,
_e_comp_wl_surface_buffer_cb_destroy);
if (listener)
buffer = container_of(listener, E_Wayland_Buffer, wl.destroy_listener);
else
{
buffer = E_NEW_RAW(E_Wayland_Buffer, 1);
memset(buffer, 0, sizeof(*buffer));
buffer->wl.resource = resource;
wl_signal_init(&buffer->wl.destroy_signal);
buffer->wl.destroy_listener.notify =
_e_comp_wl_surface_buffer_cb_destroy;
wl_resource_add_destroy_listener(resource,
&buffer->wl.destroy_listener);
}
return buffer;
}
static void
_e_comp_wl_surface_buffer_cb_destroy(struct wl_listener *listener, void *data)
{
E_Wayland_Buffer *buffer;
buffer = container_of(listener, E_Wayland_Buffer, wl.destroy_listener);
wl_signal_emit(&buffer->wl.destroy_signal, buffer);
if (buffer->ews)
{
if (buffer->ews->ec && buffer->ews->pixmap && (e_pixmap_resource_get(buffer->ews->pixmap) == data) &&
evas_object_visible_get(buffer->ews->ec->frame))
{
//INF("DESTROYED CURRENT BUFFER: %s", e_pixmap_dirty_get(buffer->ews->pixmap) ? "DIRTY" : "CLEAN");
e_pixmap_usable_set(buffer->ews->pixmap, 0);
if (!e_pixmap_image_exists(buffer->ews->pixmap))
{
e_pixmap_image_refresh(buffer->ews->pixmap);
}
e_pixmap_image_clear(buffer->ews->pixmap, 0);
e_comp_object_damage(buffer->ews->ec->frame, 0, 0, buffer->ews->ec->client.w, buffer->ews->ec->client.h);
e_comp_object_render(buffer->ews->ec->frame);
e_comp_object_render_update_del(buffer->ews->ec->frame);
}
buffer->ews->buffers = eina_inlist_remove(buffer->ews->buffers, EINA_INLIST_GET(buffer));
}
E_FREE(buffer);
}
/* surface interface functionss */
static void
_e_comp_wl_surface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
_e_comp_wl_surface_cb_attach(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *buffer_resource, int x, int y)
{
E_Wayland_Surface *ews = NULL;
E_Wayland_Buffer *buffer = NULL;
/* try to cast the resource data to our surface structure */
if (!(ews = wl_resource_get_user_data(resource))) return;
if (buffer_resource)
{
buffer = _e_comp_wl_surface_buffer_resource(buffer_resource);
if (ews->ec && (!ews->buffer_reference.buffer))
{
e_pixmap_usable_set(ews->pixmap, 1);
}
}
/* reference any existing buffers */
_e_comp_wl_surface_buffer_reference(&ews->buffer_reference, buffer);
if (buffer)
{
if (!buffer->ews)
ews->buffers = eina_inlist_append(ews->buffers, EINA_INLIST_GET(buffer));
buffer->ews = ews;
}
//INF("ATTACHED NEW BUFFER");
e_pixmap_dirty(ews->pixmap);
//if (ews->ec)
//e_comp_object_damage(ews->ec->frame, 0, 0, ews->ec->client.w, ews->ec->client.h);
/* if we are setting a null buffer, then unmap the surface */
if (!buffer)
{
if (ews->mapped)
{
if (ews->unmap) ews->unmap(ews);
}
}
/* if we already have a pending buffer, remove the listener */
if (ews->pending.buffer)
wl_list_remove(&ews->pending.buffer_destroy.link);
/* set some pending values */
ews->pending.x = x;
ews->pending.y = y;
ews->pending.buffer = buffer;
// if (buffer)
ews->pending.new_buffer = EINA_TRUE;
/* if we were given a buffer, initialize the destroy signal */
if (buffer)
wl_signal_add(&buffer->wl.destroy_signal, &ews->pending.buffer_destroy);
}
static void
_e_comp_wl_surface_cb_damage(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int x, int y, int w, int h)
{
E_Wayland_Surface *ews = NULL;
/* try to cast the resource data to our surface structure */
if (!(ews = wl_resource_get_user_data(resource))) return;
e_pixmap_image_clear(ews->pixmap, 1);
/* tell pixman to add this damage to pending */
pixman_region32_union_rect(&ews->pending.damage, &ews->pending.damage,
x, y, w, h);
}
static void
_e_comp_wl_surface_cb_frame(struct wl_client *client, struct wl_resource *resource, unsigned int callback)
{
E_Wayland_Surface *ews = NULL;
E_Wayland_Surface_Frame_Callback *cb = NULL;
/* try to cast the resource data to our surface structure */
if (!(ews = wl_resource_get_user_data(resource))) return;
/* try to allocate space for a new frame callback */
if (!(cb = E_NEW(E_Wayland_Surface_Frame_Callback, 1)))
{
wl_resource_post_no_memory(resource);
return;
}
cb->wl.resource =
wl_resource_create(client, &wl_callback_interface, 1, callback);
wl_resource_set_implementation(cb->wl.resource, NULL, cb,
_e_comp_wl_surface_cb_frame_destroy);
/* add this callback to the surface list of pending frames */
wl_list_insert(ews->pending.frames.prev, &cb->wl.link);
}
static void
_e_comp_wl_surface_cb_opaque_region_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *region_resource)
{
E_Wayland_Surface *ews = NULL;
/* try to cast the resource data to our surface structure */
if (!(ews = wl_resource_get_user_data(resource))) return;
if (region_resource)
{
E_Wayland_Region *ewr = NULL;
/* copy this region to the pending opaque region */
if ((ewr = wl_resource_get_user_data(region_resource)))
pixman_region32_copy(&ews->pending.opaque, &ewr->region);
}
else
{
/* tell pixman we are finished with this region */
pixman_region32_fini(&ews->pending.opaque);
/* reinitalize the pending opaque region */
pixman_region32_init(&ews->pending.opaque);
}
}
static void
_e_comp_wl_surface_cb_input_region_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *region_resource)
{
E_Wayland_Surface *ews = NULL;
/* try to cast the resource data to our surface structure */
if (!(ews = wl_resource_get_user_data(resource))) return;
if (region_resource)
{
E_Wayland_Region *ewr = NULL;
/* copy this region to the pending input region */
if ((ewr = wl_resource_get_user_data(region_resource)))
pixman_region32_copy(&ews->pending.input, &ewr->region);
}
else
{
/* tell pixman we are finished with this region */
pixman_region32_fini(&ews->pending.input);
/* reinitalize the pending input region */
pixman_region32_init_rect(&ews->pending.input, INT32_MIN, INT32_MIN,
UINT32_MAX, UINT32_MAX);
}
}
static void
_e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
E_Wayland_Surface *ews = NULL;
Evas_Coord bw = 0, bh = 0;
pixman_region32_t opaque;
pixman_box32_t *rects;
int n = 0;
/* FIXME */
/* try to cast the resource data to our surface structure */
if (!(ews = wl_resource_get_user_data(resource))) return;
/* if we have a pending buffer or a new pending buffer, attach it */
if ((ews->pending.buffer) || (ews->pending.new_buffer))
{
/* reference the pending buffer */
_e_comp_wl_surface_buffer_reference(&ews->buffer_reference,
ews->pending.buffer);
/* if the pending buffer is NULL, unmap the surface */
if (!ews->pending.buffer)
{
if (ews->mapped)
{
if (ews->unmap) ews->unmap(ews);
}
}
}
e_pixmap_dirty(ews->pixmap);
e_pixmap_refresh(ews->pixmap);
e_pixmap_size_get(ews->pixmap, &bw, &bh);
/* if we have a new pending buffer, call configure */
if ((ews->configure) && (ews->pending.new_buffer))
// ews->configure(ews, ews->pending.x, ews->pending.y, bw, bh);
ews->configure(ews, ews->geometry.x, ews->geometry.y, bw, bh);
if (ews->pending.buffer)
wl_list_remove(&ews->pending.buffer_destroy.link);
/* set some pending values */
ews->pending.buffer = NULL;
ews->pending.x = 0;
ews->pending.y = 0;
ews->pending.new_buffer = EINA_FALSE;
/* set surface damage */
pixman_region32_union(&ews->region.damage, &ews->region.damage,
&ews->pending.damage);
pixman_region32_intersect_rect(&ews->region.damage, &ews->region.damage,
0, 0, ews->geometry.w, ews->geometry.h);
/* empty any pending damage */
pixman_region32_fini(&ews->pending.damage);
pixman_region32_init(&ews->pending.damage);
/* get the extent of the damage region */
if (ews->ec)
{
rects = pixman_region32_rectangles(&ews->region.damage, &n);
while (n--)
{
pixman_box32_t *r;
r = &rects[n];
/* send damages to the image */
e_comp_object_damage(ews->ec->frame, r->x1, r->y1, r->x2, r->y2);
}
}
/* tell pixman we are finished with this region */
/* pixman_region32_fini(&ews->region.damage); */
/* reinitalize the damage region */
/* pixman_region32_init(&ews->region.damage); */
/* calculate new opaque region */
pixman_region32_init_rect(&opaque, 0, 0, ews->geometry.w, ews->geometry.h);
pixman_region32_intersect(&opaque, &opaque, &ews->pending.opaque);
/* if new opaque region is not equal to the current one, then update */
if (!pixman_region32_equal(&opaque, &ews->region.opaque))
{
pixman_region32_copy(&ews->region.opaque, &opaque);
ews->geometry.changed = EINA_TRUE;
}
/* tell pixman we are done with this temporary region */
pixman_region32_fini(&opaque);
/* clear any existing input region */
pixman_region32_fini(&ews->region.input);
/* initialize a new input region */
pixman_region32_init_rect(&ews->region.input, 0, 0,
ews->geometry.w, ews->geometry.h);
/* put pending input region into new input region */
pixman_region32_intersect(&ews->region.input, &ews->region.input,
&ews->pending.input);
/* check for valid input region */
// if (pixman_region32_not_empty(&ews->region.input))
{
/* get the extent of the input region */
rects = pixman_region32_extents(&ews->region.input);
/* update the smart object's input region */
if (ews->ec)
e_comp_object_input_area_set(ews->ec->frame, rects->x1, rects->y1,
rects->x2, rects->y2);
}
/* put any pending frame callbacks into active list */
wl_list_insert_list(&ews->wl.frames, &ews->pending.frames);
/* clear list of pending frame callbacks */
wl_list_init(&ews->pending.frames);
ews->updates = 1;
_e_wl_comp->surfaces = eina_inlist_promote(_e_wl_comp->surfaces, EINA_INLIST_GET(ews));
/* TODO: schedule repaint ?? */
}
static void
_e_comp_wl_surface_cb_buffer_transform_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, int transform EINA_UNUSED)
{
}
static void
_e_comp_wl_surface_cb_buffer_scale_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, int scale EINA_UNUSED)
{
}