#include "e.h" #include "e_comp_wl.h" #include "e_surface.h" #include /* compositor function prototypes */ static void _seat_send_updated_caps(struct wl_seat *seat); static void _lose_pointer_focus(struct wl_listener *listener, void *data EINA_UNUSED); static void _lose_keyboard_focus(struct wl_listener *listener, void *data EINA_UNUSED); static void _lose_touch_focus(struct wl_listener *listener, void *data EINA_UNUSED); static struct wl_resource *_find_resource_for_surface(struct wl_list *list, struct wl_resource *surface); static struct wl_resource *_find_resource_for_client(struct wl_list *list, struct wl_client *client); 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 EINA_UNUSED, unsigned int version EINA_UNUSED, 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); static Eina_Bool _e_comp_wl_cb_keymap_changed(void *data EINA_UNUSED, int type EINA_UNUSED, void *event 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); /* 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_Surface *ews, struct wl_buffer *buffer); static void _e_comp_wl_surface_buffer_reference_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); /* 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 }; 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, NULL // cb_buffer_transform_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 */ E_Wayland_Compositor *_e_wl_comp; /* external functions */ EINTERN 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; if (!getenv("XDG_RUNTIME_DIR")) e_util_env_set("XDG_RUNTIME_DIR", "/tmp"); /* 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_display_add_global(_e_wl_comp->wl.display, &wl_compositor_interface, _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((EGLNativeDisplayType)ecore_x_display_get()); 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); } /* if (!eglBindAPI(EGL_OPENGL_ES_API)) */ /* { */ /* ERR("Could not bind EGL API: %m"); */ /* eglTerminate(_e_wl_comp->egl.display); */ /* } */ /* exts = (const char *)eglQueryString(_e_wl_comp->egl.display, EGL_EXTENSIONS); */ /* if (!exts) */ /* { */ /* ERR("Could not get EGL Extensions: %m"); */ /* eglTerminate(_e_wl_comp->egl.display); */ /* } */ /* else */ /* { */ /* if (strstr(exts, "EGL_WL_bind_wayland_display")) */ /* { */ /* _e_wl_comp->egl.bind_display = */ /* (void *)eglGetProcAddress("eglBindWaylandDisplayWL"); */ /* _e_wl_comp->egl.unbind_display = */ /* (void *)eglGetProcAddress("eglUnbindWaylandDisplayWL"); */ /* } */ /* } */ /* if (_e_wl_comp->egl.bind_display) */ /* { */ /* EGLBoolean ret; */ /* ret = _e_wl_comp->egl.bind_display(_e_wl_comp->egl.display, */ /* _e_wl_comp->wl.display); */ /* if (!ret) */ /* { */ /* ERR("Could not bind EGL Wayland Display: %m"); */ /* _e_wl_comp->egl.bound = EINA_FALSE; */ /* } */ /* else */ /* _e_wl_comp->egl.bound = EINA_TRUE; */ /* } */ } } #endif /* try to initialize input */ if (!_e_comp_wl_input_init()) { ERR("Could not initialize input: %m"); goto err; } /* 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); /* add an idler for deferred shell module loading */ _module_idler = ecore_idler_add(_e_comp_wl_cb_module_idle, NULL); /* 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; } /* return success */ return EINA_TRUE; err: /* remove kbd handler */ if (_e_wl_comp->kbd_handler) ecore_event_handler_del(_e_wl_comp->kbd_handler); /* remove the module idler */ if (_module_idler) ecore_idler_del(_module_idler); #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); } 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) { wl_signal_emit(&seat->destroy_signal, seat); if (seat->pointer) wl_pointer_release(seat->pointer); if (seat->keyboard) wl_keyboard_release(seat->keyboard); if (seat->touch) wl_touch_release(seat->touch); } 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); pointer->focus_listener.notify = _lose_pointer_focus; 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_release(struct wl_pointer *pointer) { if (pointer->focus_resource) wl_list_remove(&pointer->focus_listener.link); } 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 *resource, *kr; uint32_t serial; resource = pointer->focus_resource; if (resource && pointer->focus != surface) { struct wl_display *disp; disp = wl_client_get_display(resource->client); serial = wl_display_next_serial(disp); wl_pointer_send_leave(resource, serial, pointer->focus); wl_list_remove(&pointer->focus_listener.link); } resource = _find_resource_for_surface(&pointer->resource_list, surface); if (resource && (pointer->focus != surface || pointer->focus_resource != resource)) { struct wl_display *disp; disp = wl_client_get_display(resource->client); serial = wl_display_next_serial(disp); if (kbd) { kr = _find_resource_for_surface(&kbd->resource_list, surface); if (kr) { wl_keyboard_send_modifiers(kr, serial, kbd->modifiers.mods_depressed, kbd->modifiers.mods_latched, kbd->modifiers.mods_locked, kbd->modifiers.group); } } wl_pointer_send_enter(resource, serial, surface, sx, sy); wl_signal_add(&resource->destroy_signal, &pointer->focus_listener); pointer->focus_serial = serial; } pointer->focus_resource = resource; 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_pointer_set_current(struct wl_pointer *pointer, struct wl_resource *surface) { if (pointer->current) wl_list_remove(&pointer->current_listener.link); pointer->current = surface; if (!surface) return; wl_signal_add(&surface->destroy_signal, &pointer->current_listener); pointer->current_listener.notify = _current_surface_destroy; } 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); keyboard->focus_listener.notify = _lose_keyboard_focus; 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_release(struct wl_keyboard *keyboard) { if (keyboard->focus_resource) wl_list_remove(&keyboard->focus_listener.link); wl_array_release(&keyboard->keys); } EAPI void wl_keyboard_set_focus(struct wl_keyboard *keyboard, struct wl_resource *surface) { struct wl_resource *resource; uint32_t serial; if (keyboard->focus_resource && keyboard->focus != surface) { struct wl_display *disp; disp = wl_client_get_display(keyboard->focus_resource->client); serial = wl_display_next_serial(disp); resource = keyboard->focus_resource; wl_keyboard_send_leave(resource, serial, keyboard->focus); wl_list_remove(&keyboard->focus_listener.link); } resource = _find_resource_for_surface(&keyboard->resource_list, surface); if (resource && (keyboard->focus != surface || keyboard->focus_resource != resource)) { struct wl_display *disp; disp = wl_client_get_display(resource->client); serial = wl_display_next_serial(disp); wl_keyboard_send_modifiers(resource, serial, keyboard->modifiers.mods_depressed, keyboard->modifiers.mods_latched, keyboard->modifiers.mods_locked, keyboard->modifiers.group); wl_keyboard_send_enter(resource, serial, surface, &keyboard->keys); wl_signal_add(&resource->destroy_signal, &keyboard->focus_listener); keyboard->focus_serial = serial; } keyboard->focus_resource = resource; 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); touch->focus_listener.notify = _lose_touch_focus; 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_release(struct wl_touch *touch) { if (touch->focus_resource) wl_list_remove(&touch->focus_listener.link); } 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_resource; if (!focus) return; data_device = _find_resource_for_client(&seat->drag_resource_list, focus->client); 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_display_add_global(display, &wl_data_device_manager_interface, NULL, _bind_manager) == NULL) 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; wl_resource_init(&offer->resource, &wl_data_offer_interface, &_e_data_offer_interface, 0, offer); offer->resource.destroy = _destroy_data_offer; offer->source = source; offer->source_destroy_listener.notify = _destroy_offer_data_source; wl_signal_add(&source->resource.destroy_signal, &offer->source_destroy_listener); wl_client_add_resource(target->client, &offer->resource); 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_resource; if (focus) { data_device = _find_resource_for_client(&seat->drag_resource_list, focus->client); 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->resource.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_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 *r; 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_list_for_each(r, &seat->base_resource_list, link) wl_seat_send_capabilities(r, caps); } static void _lose_pointer_focus(struct wl_listener *listener, void *data EINA_UNUSED) { struct wl_pointer *pointer = container_of(listener, struct wl_pointer, focus_listener); pointer->focus_resource = NULL; } static void _lose_keyboard_focus(struct wl_listener *listener, void *data EINA_UNUSED) { struct wl_keyboard *keyboard = container_of(listener, struct wl_keyboard, focus_listener); keyboard->focus_resource = NULL; } static void _lose_touch_focus(struct wl_listener *listener, void *data EINA_UNUSED) { struct wl_touch *touch = container_of(listener, struct wl_touch, focus_listener); touch->focus_resource = NULL; } static struct wl_resource * _find_resource_for_surface(struct wl_list *list, struct wl_resource *surface) { struct wl_resource *r; if (!surface) return NULL; wl_list_for_each(r, list, link) { if (r->client == surface->client) return r; } return NULL; } static struct wl_resource * _find_resource_for_client(struct wl_list *list, struct wl_client *client) { struct wl_resource *r; if (!client) return NULL; wl_list_for_each(r, list, link) { if (r->client == client) return r; } return NULL; } 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_resource *resource; resource = grab->pointer->focus_resource; if (resource) wl_pointer_send_motion(resource, 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_resource *resource; uint32_t serial; enum wl_pointer_button_state state = state_w; resource = pointer->focus_resource; if (resource) { struct wl_display *disp; disp = wl_client_get_display(resource->client); serial = wl_display_next_serial(disp); wl_pointer_send_button(resource, serial, timestamp, button, state_w); } if (pointer->button_count == 0 && state == WL_POINTER_BUTTON_STATE_RELEASED) wl_pointer_set_focus(pointer, pointer->current, pointer->current_x, pointer->current_y); } 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_touch *touch = grab->touch; uint32_t serial; if (touch->focus_resource && touch->focus) { struct wl_display *disp; disp = wl_client_get_display(touch->focus_resource->client); serial = wl_display_next_serial(disp); wl_touch_send_down(touch->focus_resource, 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_touch *touch = grab->touch; uint32_t serial; if (touch->focus_resource) { struct wl_display *disp; disp = wl_client_get_display(touch->focus_resource->client); serial = wl_display_next_serial(disp); wl_touch_send_up(touch->focus_resource, 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_touch *touch = grab->touch; if (touch->focus_resource) { wl_touch_send_motion(touch->focus_resource, 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 = resource->data; 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 = resource->data; 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 = resource->data; 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_resource_init(&source->resource, &wl_data_source_interface, &_e_data_source_interface, id, source); source->resource.destroy = _destroy_data_source; source->accept = _client_source_accept; source->send = _client_source_send; source->cancel = _client_source_cancel; wl_array_init(&source->mime_types); wl_client_add_resource(client, &source->resource); } static void _unbind_data_device(struct wl_resource *resource) { wl_list_remove(&resource->link); free(resource); } static void _get_data_device(struct wl_client *client, struct wl_resource *manager_resource EINA_UNUSED, uint32_t id, struct wl_resource *seat_resource) { struct wl_seat *seat = seat_resource->data; struct wl_resource *resource; resource = wl_client_add_object(client, &wl_data_device_interface, &_e_data_device_interface, id, seat); wl_list_insert(&seat->drag_resource_list, &resource->link); resource->destroy = _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) { wl_client_add_object(client, &wl_data_device_manager_interface, &_e_manager_interface, id, 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 *resource; uint32_t serial; resource = keyboard->focus_resource; if (resource) { struct wl_display *disp; disp = wl_client_get_display(resource->client); serial = wl_display_next_serial(disp); wl_keyboard_send_key(resource, 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 *resource, *pr; resource = keyboard->focus_resource; if (!resource) return; wl_keyboard_send_modifiers(resource, serial, mods_depressed, mods_latched, mods_locked, group); if (pointer && pointer->focus && pointer->focus != keyboard->focus) { pr = _find_resource_for_surface(&keyboard->resource_list, pointer->focus); if (pr) { wl_keyboard_send_modifiers(pr, serial, keyboard->modifiers.mods_depressed, keyboard->modifiers.mods_latched, keyboard->modifiers.mods_locked, keyboard->modifiers.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) { struct wl_seat *seat = resource->data; seat->drag_grab.interface = &_e_drag_grab_interface; seat->drag_client = client; seat->drag_data_source = NULL; if (source_resource) { seat->drag_data_source = source_resource->data; seat->drag_data_source_listener.notify = _destroy_data_device_source; wl_signal_add(&source_resource->destroy_signal, &seat->drag_data_source_listener); } if (icon_resource) { seat->drag_surface = icon_resource->data; seat->drag_icon_listener.notify = _destroy_data_device_icon; wl_signal_add(&icon_resource->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) { if (!source_resource) return; wl_seat_set_selection(resource->data, source_resource->data, 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_resource; if (focus) { data_device = _find_resource_for_client(&seat->drag_resource_list, focus->client); 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 = resource->data; char **p; 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 = container_of(resource, struct wl_data_source, resource); char **p; wl_array_for_each(p, &source->mime_types) free(*p); wl_array_release(&source->mime_types); source->resource.object.id = 0; } 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; 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 && surface->client != seat->drag_client) return; resource = _find_resource_for_client(&seat->drag_resource_list, surface->client); if (!resource) return; display = wl_client_get_display(resource->client); 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); seat->drag_focus = surface; seat->drag_focus_listener.notify = _destroy_drag_focus; wl_signal_add(&resource->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 EINA_UNUSED, unsigned int version EINA_UNUSED, unsigned int id) { /* add the compositor object to the client */ wl_client_add_object(client, &wl_compositor_interface, &_e_compositor_interface, id, _e_wl_comp); } 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_event_loop_dispatch(_e_wl_comp->wl.loop, 0); wl_display_flush_clients(_e_wl_comp->wl.display); 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; } static 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); } /* 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; /* try to allocate space for a new surface */ if (!(ews = E_NEW(E_Wayland_Surface, 1))) { wl_resource_post_no_memory(resource); return; } /* initialize the destroy signal */ wl_signal_init(&ews->wl.surface.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.client = 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); /* set some properties of the surface */ ews->wl.surface.destroy = _e_comp_wl_cb_surface_destroy; ews->wl.surface.object.id = id; ews->wl.surface.object.interface = &wl_surface_interface; ews->wl.surface.object.implementation = (void (**)(void))&_e_surface_interface; ews->wl.surface.data = ews; /* add this surface to the client */ wl_client_add_resource(client, &ews->wl.surface); /* add this surface to the list of surfaces */ _e_wl_comp->surfaces = eina_list_append(_e_wl_comp->surfaces, 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; /* try to get the surface from this resource */ if (!(ews = container_of(resource, E_Wayland_Surface, wl.surface))) return; /* if this surface is mapped, unmap it */ if (ews->mapped) { if (ews->unmap) ews->unmap(ews); } /* 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, 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); /* remove this surface from the compositor's list of surfaces */ _e_wl_comp->surfaces = eina_list_remove(_e_wl_comp->surfaces, ews); /* free the allocated surface structure */ E_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); /* set some properties of the region */ ewr->wl.resource.destroy = _e_comp_wl_cb_region_destroy; ewr->wl.resource.object.id = id; ewr->wl.resource.object.interface = &wl_region_interface; ewr->wl.resource.object.implementation = (void (**)(void))&_e_region_interface; ewr->wl.resource.data = ewr; /* add this region to the client */ wl_client_add_resource(client, &ewr->wl.resource); } 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 = container_of(resource, E_Wayland_Region, wl.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_display_add_global(_e_wl_comp->wl.display, &wl_seat_interface, _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 EINA_UNUSED, 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_client_add_object(client, &wl_seat_interface, &_e_input_interface, id, data); wl_list_insert(&seat->base_resource_list, &resource->link); /* set resource destroy callback */ resource->destroy = _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(&resource->link); /* free the resource */ free(resource); } static struct xkb_keymap * _e_comp_wl_input_keymap_get(void) { E_Config_XKB_Layout *kbd_layout; 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); } /* 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 = strdup((const 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); } } printf("Keymap\n"); printf("\tRules: %s\n", names.rules); printf("\tModel: %s\n", names.model); printf("\tLayout: %s\n", names.layout); return xkb_map_new_from_names(_e_wl_comp->xkb.context, &names, 0); } 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 = resource->data)) return; /* check that input has a pointer */ if (!input->has_pointer) return; /* add a pointer object to the client */ ptr = wl_client_add_object(client, &wl_pointer_interface, &_e_pointer_interface, id, input); wl_list_insert(&input->wl.seat.pointer->resource_list, &ptr->link); /* set pointer destroy callback */ ptr->destroy = _e_comp_wl_input_cb_unbind; /* if the pointer has a focused surface, set it */ if ((input->wl.seat.pointer->focus) && (input->wl.seat.pointer->focus->client == client)) { /* tell pointer which surface is focused */ wl_pointer_set_focus(input->wl.seat.pointer, 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 = resource->data)) return; /* check that input has a keyboard */ if (!input->has_keyboard) return; /* add a keyboard object to the client */ kbd = wl_client_add_object(client, &wl_keyboard_interface, NULL, id, input); wl_list_insert(&input->wl.seat.keyboard->resource_list, &kbd->link); /* set keyboard destroy callback */ kbd->destroy = _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); /* test if keyboard has a focused client */ if ((input->wl.seat.keyboard->focus) && (input->wl.seat.keyboard->focus->client == client)) { /* set keyboard focus */ wl_keyboard_set_focus(input->wl.seat.keyboard, input->wl.seat.keyboard->focus); /* 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 = resource->data)) return; /* check that input has a touch */ if (!input->has_touch) return; /* add a touch object to the client */ tch = wl_client_add_object(client, &wl_touch_interface, NULL, id, input); wl_list_insert(&input->wl.seat.touch->resource_list, &tch->link); /* set touch destroy callback */ tch->destroy = _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 ((focus = (E_Wayland_Surface *)input->wl.seat.pointer->focus)) { /* 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->ee)) { Ecore_Window win; /* try to get the ecore_window */ if ((win = ecore_evas_window_get(focus->ee))) { void *pixels; /* grab the pixels from the cursor surface */ if ((pixels = wl_shm_buffer_get_data(ews->reference.buffer))) { Ecore_X_Cursor cur; /* create the new X cursor with this image */ cur = ecore_x_cursor_new(win, pixels, w, h, input->pointer.hot.x, input->pointer.hot.y); /* set the cursor on this window */ ecore_x_window_cursor_set(win, cur); /* free the cursor */ ecore_x_cursor_free(cur); } else ecore_x_window_cursor_set(win, 0); } } } } 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 = resource->data)) return; /* if we were passed in a surface, try to cast it to our structure */ if (surface_resource) ews = (E_Wayland_Surface *)surface_resource->data; /* 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) return; if (input->wl.seat.pointer->focus->client != 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) return; /* set the destroy listener */ wl_signal_add(&ews->wl.surface.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->reference.buffer) { Evas_Coord bw = 0, bh = 0; /* grab the size of the buffer */ bw = ews->reference.buffer->width; bh = ews->reference.buffer->height; /* configure the pointer surface */ _e_comp_wl_pointer_configure(ews, 0, 0, bw, bh); } } /* 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 = resource->data)) 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 = resource->data)) return; /* ask pixman to create a new temporary rect */ pixman_region32_init_rect(®ion, x, y, w, h); /* ask pixman to subtract this temp rect from the existing region */ pixman_region32_subtract(&ewr->region, &ewr->region, ®ion); /* tell pixman we are finished with the temporary rect */ pixman_region32_fini(®ion); } /* 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 = resource->data)) 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_Surface *ews, struct wl_buffer *buffer) { /* check for valid surface */ if (!ews) return; /* if the surface already has a buffer referenced and it is not the * same as the one passed in */ if ((ews->reference.buffer) && (buffer != ews->reference.buffer)) { /* decrement the reference buffer busy count */ ews->reference.buffer->busy_count--; /* if the compositor is finished with this referenced buffer, then * we need to release it */ if (ews->reference.buffer->busy_count == 0) { if (ews->reference.buffer->resource.client) wl_resource_queue_event(&ews->reference.buffer->resource, WL_BUFFER_RELEASE); } /* remove the destroy link on the referenced buffer */ wl_list_remove(&ews->reference.buffer_destroy.link); } /* if we are passed in a buffer and it is not the one referenced */ if ((buffer) && (buffer != ews->reference.buffer)) { /* increment busy count */ buffer->busy_count++; /* setup destroy signal */ wl_signal_add(&buffer->resource.destroy_signal, &ews->reference.buffer_destroy); } /* set buffer reference */ ews->reference.buffer = buffer; /* setup destroy listener */ ews->reference.buffer_destroy.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_Surface *ews = NULL; /* try to get the surface from this listener */ ews = container_of(listener, E_Wayland_Surface, reference.buffer_destroy); if (!ews) return; /* set referenced buffer to null */ ews->reference.buffer = NULL; } /* 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; struct wl_buffer *buffer = NULL; /* try to cast the resource data to our surface structure */ if (!(ews = resource->data)) return; if (buffer_resource) buffer = buffer_resource->data; /* reference any existing buffers */ _e_comp_wl_surface_buffer_reference(ews, buffer); /* 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->resource.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 = resource->data)) return; /* 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 = resource->data)) 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; } /* set some properties on the callback */ cb->wl.resource.object.interface = &wl_callback_interface; cb->wl.resource.object.id = callback; cb->wl.resource.destroy = _e_comp_wl_surface_cb_frame_destroy; cb->wl.resource.client = client; cb->wl.resource.data = cb; /* add frame callback to client */ wl_client_add_resource(client, &cb->wl.resource); /* 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 = resource->data)) return; if (region_resource) { E_Wayland_Region *ewr = NULL; /* copy this region to the pending opaque region */ if ((ewr = region_resource->data)) 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 = resource->data)) return; if (region_resource) { E_Wayland_Region *ewr = NULL; /* copy this region to the pending input region */ if ((ewr = region_resource->data)) 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 = resource->data)) 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, 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); } } else { if (ews->obj) { void *data; bw = ews->pending.buffer->width; bh = ews->pending.buffer->height; /* grab the pixel data from the buffer */ data = wl_shm_buffer_get_data(ews->pending.buffer); /* send the pixel data to the smart object */ e_surface_image_set(ews->obj, bw, bh, data); } } } /* if we have a reference to a buffer, get it's size */ if (ews->reference.buffer) { bw = ews->reference.buffer->width; bh = ews->reference.buffer->height; } /* 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 */ rects = pixman_region32_rectangles(&ews->region.damage, &n); while (n--) { pixman_box32_t *r; r = &rects[n]; /* send damages to the image */ e_surface_damage_add(ews->obj, 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->obj) e_surface_input_set(ews->obj, rects->x1, rects->y1, (rects->x2 - rects->x1), (rects->y2 - rects->y1)); } /* 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); /* TODO: schedule repaint ?? */ }