enlightenment/src/modules/wl_desktop/e_mod_main.c

846 lines
26 KiB
C

#include "e.h"
#include "e_mod_main.h"
/* local function prototypes */
static void _e_desktop_shell_cb_destroy(struct wl_listener *listener, void *data EINA_UNUSED);
static void _e_desktop_shell_cb_bind(struct wl_client *client, void *data, unsigned int version EINA_UNUSED, unsigned int id);
static void _e_desktop_shell_cb_shell_surface_get(struct wl_client *client, struct wl_resource *resource, unsigned int id, struct wl_resource *surface_resource);
static void _e_desktop_shell_cb_ping(E_Surface *es, unsigned int serial);
static int _e_desktop_shell_cb_ping_timeout(void *data);
static void _e_desktop_shell_shell_surface_cb_destroy_notify(struct wl_listener *listener, void *data EINA_UNUSED);
static void _e_desktop_shell_shell_surface_cb_destroy(struct wl_resource *resource);
static void _e_desktop_shell_shell_surface_configure(E_Surface *es, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h);
static void _e_desktop_shell_shell_surface_activate(E_Surface *es, E_Input *seat);
static void _e_desktop_shell_shell_surface_map(E_Surface *es, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h);
static void _e_desktop_shell_shell_surface_unmap(E_Surface *es);
static Eina_Bool _e_desktop_shell_shell_surface_move(E_Shell_Surface *ess, E_Input *seat);
/* shell surface interface prototypes */
static void _e_desktop_shell_shell_surface_cb_pong(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, unsigned int serial);
static void _e_desktop_shell_shell_surface_cb_move(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource, unsigned int serial);
static void _e_desktop_shell_shell_surface_cb_resize(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource, unsigned int serial, unsigned int edges);
static void _e_desktop_shell_shell_surface_cb_toplevel_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource);
static void _e_desktop_shell_shell_surface_cb_transient_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *parent_resource, int x, int y, unsigned int flags);
static void _e_desktop_shell_shell_surface_cb_fullscreen_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, unsigned int method EINA_UNUSED, unsigned int framerate EINA_UNUSED, struct wl_resource *output_resource EINA_UNUSED);
static void _e_desktop_shell_shell_surface_cb_popup_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource, unsigned int serial, struct wl_resource *parent_resource, int x, int y, unsigned int flags EINA_UNUSED);
static void _e_desktop_shell_shell_surface_cb_maximized_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *output_resource EINA_UNUSED);
static void _e_desktop_shell_shell_surface_cb_title_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *title);
static void _e_desktop_shell_shell_surface_cb_class_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *clas);
static void _e_desktop_shell_shell_surface_type_set(E_Shell_Surface *ess);
static void _e_desktop_shell_shell_surface_type_reset(E_Shell_Surface *ess);
static void _e_desktop_shell_surface_map_toplevel(E_Shell_Surface *ess);
static void _e_desktop_shell_surface_map_popup(E_Shell_Surface *ess);
static void _e_desktop_shell_popup_grab_add(E_Shell_Surface *ess, E_Input *seat);
static void _e_desktop_shell_popup_grab_focus(E_Input_Pointer_Grab *grab);
static void _e_desktop_shell_popup_grab_motion(E_Input_Pointer_Grab *grab, unsigned int timestamp);
static void _e_desktop_shell_popup_grab_button(E_Input_Pointer_Grab *grab, unsigned int timestamp, unsigned int button, unsigned int state);
static void _e_desktop_shell_popup_grab_end(E_Input_Pointer *pointer);
static void _e_desktop_shell_pointer_focus_listener_add(E_Input *seat);
static void _e_desktop_shell_pointer_cb_focus(struct wl_listener *listener, void *data);
/* local wayland interfaces */
static const struct wl_shell_interface _e_desktop_shell_interface =
{
_e_desktop_shell_cb_shell_surface_get
};
static const struct wl_shell_surface_interface
_e_desktop_shell_surface_interface =
{
_e_desktop_shell_shell_surface_cb_pong,
_e_desktop_shell_shell_surface_cb_move,
_e_desktop_shell_shell_surface_cb_resize,
_e_desktop_shell_shell_surface_cb_toplevel_set,
_e_desktop_shell_shell_surface_cb_transient_set,
_e_desktop_shell_shell_surface_cb_fullscreen_set,
_e_desktop_shell_shell_surface_cb_popup_set,
_e_desktop_shell_shell_surface_cb_maximized_set,
_e_desktop_shell_shell_surface_cb_title_set,
_e_desktop_shell_shell_surface_cb_class_set
};
static E_Input_Pointer_Grab_Interface _popup_grab_interface =
{
_e_desktop_shell_popup_grab_focus,
_e_desktop_shell_popup_grab_motion,
_e_desktop_shell_popup_grab_button,
};
EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Wl_Desktop" };
EAPI void *
e_modapi_init(E_Module *m)
{
E_Desktop_Shell *shell;
struct wl_global *global;
Eina_List *l;
E_Input *seat;
/* try to allocate space for our shell */
if (!(shell = E_NEW(E_Desktop_Shell, 1)))
return NULL;
/* get a reference to the compositor */
shell->compositor = _e_comp;
/* setup shell destroy listener */
shell->wl.destroy_listener.notify = _e_desktop_shell_cb_destroy;
wl_signal_add(&_e_comp->signals.destroy, &shell->wl.destroy_listener);
/* set a reference to this shell in the compositor */
shell->compositor->shell_interface.shell = shell;
shell->compositor->cb_ping = _e_desktop_shell_cb_ping;
/* try to add this shell to the globals */
if (!(global =
wl_display_add_global(_e_comp->wl.display, &wl_shell_interface,
shell, _e_desktop_shell_cb_bind)))
{
ERR("Could not add shell to globals: %m");
goto err;
}
/* TODO: finish me */
EINA_LIST_FOREACH(_e_comp->inputs, l, seat)
_e_desktop_shell_pointer_focus_listener_add(seat);
return m;
err:
/* reset compositor shell interface */
_e_comp->shell_interface.shell = NULL;
/* remove the destroy signal */
wl_list_remove(&shell->wl.destroy_listener.link);
/* free the allocated structure */
E_FREE(shell);
return NULL;
}
EAPI int
e_modapi_shutdown(E_Module *m)
{
return 1;
}
/* local functions */
static void
_e_desktop_shell_cb_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
{
E_Desktop_Shell *shell;
/* try to get the shell from the listener */
shell = container_of(listener, E_Desktop_Shell, wl.destroy_listener);
/* reset compositor shell interface */
shell->compositor->shell_interface.shell = NULL;
/* remove the destroy signal */
wl_list_remove(&shell->wl.destroy_listener.link);
/* free the allocated structure */
E_FREE(shell);
}
static void
_e_desktop_shell_cb_bind(struct wl_client *client, void *data, unsigned int version EINA_UNUSED, unsigned int id)
{
E_Desktop_Shell *shell;
/* try to cast data to our shell */
if (!(shell = data)) return;
/* try to add the shell to the client */
wl_client_add_object(client, &wl_shell_interface,
&_e_desktop_shell_interface, id, shell);
}
static void
_e_desktop_shell_cb_shell_surface_get(struct wl_client *client, struct wl_resource *resource, unsigned int id, struct wl_resource *surface_resource)
{
E_Surface *es;
E_Shell_Surface *ess;
/* try to cast the resource to our structure */
if (!(es = wl_resource_get_user_data(surface_resource))) return;
/* check if this surface has already been configured */
if ((es->configure) &&
(es->configure == _e_desktop_shell_shell_surface_configure))
{
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"Shell surface already requested for surface");
return;
}
/* try to create new shell surface */
if (!(ess = e_shell_surface_new(es, id)))
{
wl_resource_post_no_memory(resource);
return;
}
es->configure = _e_desktop_shell_shell_surface_configure;
es->map = _e_desktop_shell_shell_surface_map;
es->unmap = _e_desktop_shell_shell_surface_unmap;
/* setup shell surface destroy callback */
wl_signal_init(&ess->signals.destroy);
ess->wl.surface_destroy.notify =
_e_desktop_shell_shell_surface_cb_destroy_notify;
wl_signal_add(&es->signals.destroy, &ess->wl.surface_destroy);
/* setup shell surface interface */
ess->wl.resource =
wl_client_add_object(client, &wl_shell_surface_interface,
&_e_desktop_shell_surface_interface, id, ess);
wl_resource_set_destructor(ess->wl.resource,
_e_desktop_shell_shell_surface_cb_destroy);
}
static void
_e_desktop_shell_cb_ping(E_Surface *es, unsigned int serial)
{
E_Shell_Surface *ess;
if (!(ess = es->shell_surface)) return;
if (!ess->wl.resource) return;
if (!ess->ping_timer)
{
struct wl_event_loop *loop;
if (!(ess->ping_timer = E_NEW(E_Shell_Surface_Ping_Timer, 1)))
return;
ess->ping_timer->serial = serial;
loop = wl_display_get_event_loop(_e_comp->wl.display);
ess->ping_timer->source =
wl_event_loop_add_timer(loop, _e_desktop_shell_cb_ping_timeout, ess);
wl_event_source_timer_update(ess->ping_timer->source, 200);
wl_shell_surface_send_ping(ess->wl.resource, serial);
}
}
static int
_e_desktop_shell_cb_ping_timeout(void *data)
{
E_Shell_Surface *ess;
E_Input *seat;
Eina_List *l;
if (!(ess = data)) return 0;
ess->active = EINA_FALSE;
EINA_LIST_FOREACH(_e_comp->inputs, l, seat)
{
if (seat->pointer->focus == ess->surface)
{
printf("Set Busy Cursor\n");
}
}
return 1;
}
static void
_e_desktop_shell_shell_surface_cb_destroy_notify(struct wl_listener *listener, void *data EINA_UNUSED)
{
E_Shell_Surface *ess;
/* try to get the shell surface from the listener */
if (!(ess = container_of(listener, E_Shell_Surface, wl.surface_destroy)))
return;
if (ess->wl.resource)
wl_resource_destroy(ess->wl.resource);
else
e_shell_surface_destroy(ess);
}
static void
_e_desktop_shell_shell_surface_cb_destroy(struct wl_resource *resource)
{
E_Shell_Surface *ess;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
e_shell_surface_destroy(ess);
}
static void
_e_desktop_shell_shell_surface_configure(E_Surface *es, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
{
E_Shell_Surface *ess;
Eina_Bool changed = EINA_FALSE;
if ((es->configure == _e_desktop_shell_shell_surface_configure))
{
if (!(ess = es->shell_surface)) return;
}
else
return;
/* handle surface type change */
if ((ess->ntype != E_SHELL_SURFACE_TYPE_NONE) &&
(ess->type != ess->ntype))
{
/* set the new surface type */
_e_desktop_shell_shell_surface_type_set(ess);
changed = EINA_TRUE;
}
/* check if surface has been mapped */
if (!es->mapped)
{
/* if we have a map function, then call it */
if (es->map) es->map(es, x, y, w, h);
}
else if ((changed) || (x != 0) || (y != 0) ||
(es->geometry.w != w) || (es->geometry.h != h))
{
Evas_Coord fx = 0, fy = 0, tx = 0, ty = 0;
fx += es->geometry.x;
fy += es->geometry.y;
tx = (x + es->geometry.x);
ty = (y + es->geometry.y);
es->geometry.x = (es->geometry.x + tx - fx);
es->geometry.y = (es->geometry.y + ty - fy);
es->geometry.w = w;
es->geometry.h = h;
es->geometry.changed = EINA_TRUE;
}
}
static void
_e_desktop_shell_shell_surface_activate(E_Surface *es, E_Input *seat)
{
e_surface_activate(es, seat);
}
static void
_e_desktop_shell_shell_surface_map(E_Surface *es, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
{
Eina_List *l;
E_Input *seat;
/* safety check */
if (!es) return;
/* update surface geometry */
es->geometry.w = w;
es->geometry.h = h;
es->geometry.changed = EINA_TRUE;
/* starting position */
switch (es->shell_surface->type)
{
case E_SHELL_SURFACE_TYPE_TOPLEVEL:
case E_SHELL_SURFACE_TYPE_POPUP:
es->geometry.x = x;
es->geometry.y = y;
es->geometry.changed = EINA_TRUE;
break;
case E_SHELL_SURFACE_TYPE_FULLSCREEN:
/* center */
/* map fullscreen */
break;
case E_SHELL_SURFACE_TYPE_MAXIMIZED:
/* maximize */
break;
case E_SHELL_SURFACE_TYPE_NONE:
es->geometry.x += x;
es->geometry.y += y;
es->geometry.changed = EINA_TRUE;
break;
default:
break;
}
/* stacking */
if (es->shell_surface->type != E_SHELL_SURFACE_TYPE_NONE)
e_surface_output_assign(es);
/* map */
switch (es->shell_surface->type)
{
case E_SHELL_SURFACE_TYPE_TOPLEVEL:
_e_desktop_shell_surface_map_toplevel(es->shell_surface);
break;
case E_SHELL_SURFACE_TYPE_POPUP:
_e_desktop_shell_surface_map_popup(es->shell_surface);
break;
default:
break;
}
/* activate */
switch (es->shell_surface->type)
{
case E_SHELL_SURFACE_TYPE_TOPLEVEL:
case E_SHELL_SURFACE_TYPE_FULLSCREEN:
case E_SHELL_SURFACE_TYPE_MAXIMIZED:
EINA_LIST_FOREACH(_e_comp->inputs, l, seat)
_e_desktop_shell_shell_surface_activate(es, seat);
break;
default:
break;
}
es->mapped = EINA_TRUE;
}
static void
_e_desktop_shell_shell_surface_unmap(E_Surface *es)
{
/* Eina_List *l = NULL; */
/* E_Wayland_Input *input; */
if (!es) return;
/* EINA_LIST_FOREACH(_e_wl_comp->seats, l, input) */
/* { */
/* if ((input->wl.seat.keyboard) && */
/* (input->wl.seat.keyboard->focus == &es->wl.surface)) */
/* wl_keyboard_set_focus(input->wl.seat.keyboard, NULL); */
/* if ((input->wl.seat.pointer) && */
/* (input->wl.seat.pointer->focus == &es->wl.surface)) */
/* wl_pointer_set_focus(input->wl.seat.pointer, NULL, 0, 0); */
/* } */
/* if (es->ee) ecore_evas_free(es->ee); */
es->mapped = EINA_FALSE;
}
static Eina_Bool
_e_desktop_shell_shell_surface_move(E_Shell_Surface *ess, E_Input *seat)
{
return EINA_FALSE;
}
/* shell surface interface functions */
static void
_e_desktop_shell_shell_surface_cb_pong(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, unsigned int serial)
{
E_Shell_Surface *ess;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
if (!ess->ping_timer) return;
if (ess->ping_timer->serial == serial)
{
ess->active = EINA_TRUE;
/* TODO: Unset busy cursor */
if (ess->ping_timer->source)
wl_event_source_remove(ess->ping_timer->source);
E_FREE(ess->ping_timer);
}
}
static void
_e_desktop_shell_shell_surface_cb_move(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource, unsigned int serial)
{
E_Shell_Surface *ess;
E_Input *seat;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
if (!(seat = wl_resource_get_user_data(seat_resource))) return;
printf("Shell Surface Move\n");
if ((seat->pointer->grab->button_count == 0) ||
(seat->pointer->grab->serial != serial))
return;
if (!_e_desktop_shell_shell_surface_move(ess, seat))
wl_resource_post_no_memory(resource);
}
static void
_e_desktop_shell_shell_surface_cb_resize(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource, unsigned int serial, unsigned int edges)
{
E_Shell_Surface *ess;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
printf("Shell Surface Resize\n");
}
static void
_e_desktop_shell_shell_surface_cb_toplevel_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
E_Shell_Surface *ess;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
/* set next surface type */
ess->ntype = E_SHELL_SURFACE_TYPE_TOPLEVEL;
}
static void
_e_desktop_shell_shell_surface_cb_transient_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *parent_resource, int x, int y, unsigned int flags)
{
E_Shell_Surface *ess;
E_Surface *es;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
es = wl_resource_get_user_data(parent_resource);
ess->parent = es;
ess->transient.x = x;
ess->transient.y = y;
ess->transient.flags = flags;
/* set next surface type */
ess->ntype = E_SHELL_SURFACE_TYPE_TRANSIENT;
}
static void
_e_desktop_shell_shell_surface_cb_fullscreen_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, unsigned int method EINA_UNUSED, unsigned int framerate EINA_UNUSED, struct wl_resource *output_resource EINA_UNUSED)
{
E_Shell_Surface *ess;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
/* set next surface type */
ess->ntype = E_SHELL_SURFACE_TYPE_FULLSCREEN;
}
static void
_e_desktop_shell_shell_surface_cb_popup_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource, unsigned int serial, struct wl_resource *parent_resource, int x, int y, unsigned int flags EINA_UNUSED)
{
E_Shell_Surface *ess;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
/* set next surface type */
ess->ntype = E_SHELL_SURFACE_TYPE_POPUP;
ess->parent = wl_resource_get_user_data(parent_resource);
ess->popup.seat = wl_resource_get_user_data(seat_resource);
/* FIXME: BIG GIAN HACK !!! */
ess->popup.serial = serial - 1;
ess->popup.x = x;
ess->popup.y = y;
}
static void
_e_desktop_shell_shell_surface_cb_maximized_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *output_resource EINA_UNUSED)
{
E_Shell_Surface *ess;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
/* set next surface type */
ess->ntype = E_SHELL_SURFACE_TYPE_MAXIMIZED;
}
static void
_e_desktop_shell_shell_surface_cb_title_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *title)
{
E_Shell_Surface *ess;
E_Surface *es;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
/* free any previous title */
free(ess->title);
ess->title = strdup(title);
if ((es = ess->surface))
{
/* TODO: Finish me */
}
}
static void
_e_desktop_shell_shell_surface_cb_class_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *clas)
{
E_Shell_Surface *ess;
E_Surface *es;
/* try to cast the resource to our shell surface */
if (!(ess = wl_resource_get_user_data(resource))) return;
/* free any previous title */
free(ess->clas);
ess->clas = strdup(clas);
if ((es = ess->surface))
{
/* TODO: Finish me */
}
}
static void
_e_desktop_shell_shell_surface_type_set(E_Shell_Surface *ess)
{
/* safety check */
if (!ess) return;
/* reset the shell surface type */
_e_desktop_shell_shell_surface_type_reset(ess);
ess->type = ess->ntype;
ess->ntype = E_SHELL_SURFACE_TYPE_NONE;
switch (ess->type)
{
case E_SHELL_SURFACE_TYPE_TRANSIENT:
ess->surface->geometry.x =
ess->parent->geometry.x + ess->transient.x;
ess->surface->geometry.y =
ess->parent->geometry.y + ess->transient.y;
break;
/* record the current geometry so we can restore it */
case E_SHELL_SURFACE_TYPE_FULLSCREEN:
case E_SHELL_SURFACE_TYPE_MAXIMIZED:
ess->saved.x = ess->surface->geometry.x;
ess->saved.y = ess->surface->geometry.y;
ess->saved.w = ess->surface->geometry.w;
ess->saved.h = ess->surface->geometry.h;
ess->saved.valid = EINA_TRUE;
break;
default:
break;
}
}
static void
_e_desktop_shell_shell_surface_type_reset(E_Shell_Surface *ess)
{
/* safety check */
if (!ess) return;
switch (ess->type)
{
case E_SHELL_SURFACE_TYPE_FULLSCREEN:
/* ecore_evas_fullscreen_set(ess->surface->ee, EINA_FALSE); */
/* unfullscreen the border */
/* if (ess->surface->bd) */
/* e_border_unfullscreen(ess->surface->bd); */
/* restore the saved geometry */
ess->surface->geometry.x = ess->saved.x;
ess->surface->geometry.y = ess->saved.y;
ess->surface->geometry.w = ess->saved.w;
ess->surface->geometry.h = ess->saved.h;
ess->surface->geometry.changed = EINA_TRUE;
break;
case E_SHELL_SURFACE_TYPE_MAXIMIZED:
/* unmaximize the border */
/* if (ess->surface->bd) */
/* e_border_unmaximize(ess->surface->bd, */
/* (e_config->maximize_policy & E_MAXIMIZE_TYPE) | */
/* E_MAXIMIZE_BOTH); */
/* restore the saved geometry */
ess->surface->geometry.x = ess->saved.x;
ess->surface->geometry.y = ess->saved.y;
ess->surface->geometry.w = ess->saved.w;
ess->surface->geometry.h = ess->saved.h;
ess->surface->geometry.changed = EINA_TRUE;
break;
default:
break;
}
/* reset the current type to none */
ess->type = E_SHELL_SURFACE_TYPE_NONE;
}
static void
_e_desktop_shell_surface_map_toplevel(E_Shell_Surface *ess)
{
/* if (!(es->ee = */
/* e_canvas_new(0, es->geometry.x, es->geometry.y, */
/* es->geometry.w, es->geometry.h, EINA_FALSE, */
/* EINA_FALSE, NULL))) */
/* return; */
/* e_canvas_add(es->ee); */
/* ecore_evas_data_set(es->ee, "surface", es); */
/* es->evas = ecore_evas_get(es->ee); */
}
static void
_e_desktop_shell_surface_map_popup(E_Shell_Surface *ess)
{
E_Surface *es, *parent;
E_Input *seat;
es = ess->surface;
parent = ess->parent;
seat = ess->popup.seat;
/* set popup position */
es->geometry.x = ess->popup.x;
es->geometry.y = ess->popup.y;
es->geometry.changed = EINA_TRUE;
printf("Popup Serial: %d\n", ess->popup.serial);
printf("Grab Serial: %d\n", seat->pointer->grab->serial);
if ((seat) && (seat->pointer->grab->serial == ess->popup.serial))
_e_desktop_shell_popup_grab_add(ess, seat);
else
{
wl_shell_surface_send_popup_done(ess->wl.resource);
seat->pointer->grab->client = NULL;
}
}
static void
_e_desktop_shell_popup_grab_add(E_Shell_Surface *ess, E_Input *seat)
{
if (wl_list_empty(&seat->pointer->grab->surfaces))
{
seat->pointer->grab->client = wl_resource_get_client(ess->wl.resource);
seat->pointer->grab->interface = &_popup_grab_interface;
if (seat->pointer->grab->button_count > 0)
seat->pointer->grab->up = EINA_FALSE;
e_input_pointer_grab_start(seat->pointer);
}
wl_list_insert(&seat->pointer->grab->surfaces, &ess->wl.link);
}
static void
_e_desktop_shell_popup_grab_focus(E_Input_Pointer_Grab *grab)
{
E_Input_Pointer *ptr;
E_Surface *es;
if (!(ptr = grab->pointer)) return;
es = e_compositor_surface_find(ptr->seat->compositor, ptr->x, ptr->y);
if ((es) && (wl_resource_get_client(es->wl.resource) == grab->client))
e_input_pointer_focus_set(ptr, es, ptr->x, ptr->y);
else
e_input_pointer_focus_set(ptr, NULL, 0, 0);
}
static void
_e_desktop_shell_popup_grab_motion(E_Input_Pointer_Grab *grab, unsigned int timestamp)
{
E_Input_Pointer *ptr;
ptr = grab->pointer;
if ((ptr) && (ptr->focus_resource))
wl_pointer_send_motion(ptr->focus_resource, timestamp, ptr->x, ptr->y);
}
static void
_e_desktop_shell_popup_grab_button(E_Input_Pointer_Grab *grab, unsigned int timestamp, unsigned int button, unsigned int state)
{
struct wl_resource *res;
if ((res = grab->pointer->focus_resource))
{
struct wl_display *disp;
unsigned int serial = 0;
disp = wl_client_get_display(res->client);
serial = wl_display_get_serial(disp);
wl_pointer_send_button(res, serial, timestamp, button, state);
}
else if ((state == WL_POINTER_BUTTON_STATE_RELEASED) &&
((grab->up) || ((timestamp - grab->timestamp) > 500)))
_e_desktop_shell_popup_grab_end(grab->pointer);
if (state == WL_POINTER_BUTTON_STATE_RELEASED)
grab->up = EINA_TRUE;
}
static void
_e_desktop_shell_popup_grab_end(E_Input_Pointer *pointer)
{
E_Input_Pointer_Grab *grab;
if (!(grab = pointer->grab)) return;
if (grab->interface == &_popup_grab_interface)
{
E_Shell_Surface *ess;
e_input_pointer_grab_end(grab->pointer);
grab->client = NULL;
grab->interface = NULL;
wl_list_for_each(ess, &grab->surfaces, wl.link)
wl_shell_surface_send_popup_done(ess->wl.resource);
wl_list_init(&grab->surfaces);
}
}
static void
_e_desktop_shell_pointer_focus_listener_add(E_Input *seat)
{
struct wl_listener *listener;
if (!seat->pointer) return;
listener = malloc(sizeof(*listener));
listener->notify = _e_desktop_shell_pointer_cb_focus;
wl_signal_add(&seat->pointer->signals.focus, listener);
}
static void
_e_desktop_shell_pointer_cb_focus(struct wl_listener *listener, void *data)
{
E_Input_Pointer *ptr;
E_Surface *es;
E_Shell_Surface *ess;
E_Compositor *comp;
if (!(ptr = data)) return;
if (!(es = ptr->focus)) return;
if (!(ess = es->shell_surface)) return;
if (!(comp = ptr->seat->compositor)) return;
if ((ess) && (!ess->active))
{
printf("\tShell Surface Not Active. Set Busy Cursor\n");
}
else
{
unsigned int serial = 0;
serial = wl_display_next_serial(comp->wl.display);
if (comp->cb_ping) comp->cb_ping(es, serial);
}
}