also add demo "start" gadgetdevs/discomfitor/sandblog2017
parent
f1fd2a827a
commit
26c589e745
5 changed files with 726 additions and 19 deletions
@ -0,0 +1,77 @@ |
||||
<protocol name="zwp_action_route"> |
||||
<interface name="action_route" version="1"> |
||||
<enum name="mode"> |
||||
<description summary="types of state on the surface"> |
||||
</description> |
||||
<entry name="focus_shared" value="1" summary="Activatable by any surface if its wl_client has focus"> |
||||
</entry> |
||||
<entry name="focus_topmost" value="2" summary="Activatable by topmost surface with focus"> |
||||
<description summary="Restricts activation to only the top-most client"/> |
||||
</entry> |
||||
<entry name="exclusive" value="3" summary="Activatable by one surface at any time"> |
||||
<description summary="Allows activation for exactly one client at all times"/> |
||||
</entry> |
||||
</enum> |
||||
<enum name="modifiers"> |
||||
<entry name="shift" value="1"></entry> |
||||
<entry name="control" value="2"></entry> |
||||
<entry name="alt" value="4"></entry> |
||||
<entry name="win" value="8"></entry> |
||||
<entry name="altgr" value="16"></entry> |
||||
</enum> |
||||
<request name="bind_action"> |
||||
<description summary="Request a new grab for a key press"> |
||||
</description> |
||||
<arg name="id" type="new_id" interface="action_route_bind"/> |
||||
<arg name="action" type="string"/> |
||||
</request> |
||||
<request name="grab_key"> |
||||
<description summary="Request a new grab for a key press"> |
||||
</description> |
||||
<arg name="id" type="new_id" interface="action_route_key_grab"/> |
||||
<arg name="surface" type="object" interface="wl_surface"/> |
||||
<arg name="key" type="string"/> |
||||
<arg name="mode" type="uint"/> |
||||
<arg name="modifiers" type="uint"/> |
||||
<arg name="action" type="string"/> |
||||
<arg name="params" type="string" allow-null="true"/> |
||||
</request> |
||||
</interface> |
||||
<interface name="action_route_bind" version="1"> |
||||
<enum name="state"> |
||||
<entry name="Rejected" value="0"></entry> |
||||
<entry name="Active" value="1"></entry> |
||||
<entry name="Queued" value="2"></entry> |
||||
</enum> |
||||
<event name="status"> |
||||
<description summary="Status update on a bind request"></description> |
||||
<arg name="state" type="uint"/> |
||||
</event> |
||||
<request name="activate"> |
||||
<description summary="Activate a bind"/> |
||||
<arg name="params" type="string" allow-null="true"/> |
||||
</request> |
||||
<request name="destroy" type="destructor"> |
||||
<description summary="Destroy a requested bind"> |
||||
</description> |
||||
</request> |
||||
<event name="end"> |
||||
<description summary="The bind has completed execution"/> |
||||
</event> |
||||
</interface> |
||||
<interface name="action_route_key_grab" version="1"> |
||||
<enum name="state"> |
||||
<entry name="Rejected" value="0"></entry> |
||||
<entry name="Active" value="1"></entry> |
||||
<entry name="Queued" value="2"></entry> |
||||
</enum> |
||||
<event name="status"> |
||||
<description summary="Status update on a grab request"></description> |
||||
<arg name="state" type="uint"/> |
||||
</event> |
||||
<request name="destroy" type="destructor"> |
||||
<description summary="Destroy a requested grab"> |
||||
</description> |
||||
</request> |
||||
</interface> |
||||
</protocol> |
@ -0,0 +1,288 @@ |
||||
#include "config.h" |
||||
#define EFL_BETA_API_SUPPORT |
||||
#include <Ecore_Wl2.h> |
||||
#include <Elementary.h> |
||||
#include <dlfcn.h> |
||||
#include "e-gadget-client-protocol.h" |
||||
#include "action_route-client-protocol.h" |
||||
#include <uuid.h> |
||||
|
||||
static Ecore_Event_Handler *handler; |
||||
|
||||
static Eina_Hash *wins; |
||||
static Eina_Hash *gadget_globals; |
||||
static Eina_Hash *ar_globals; |
||||
static Eina_Hash *display_actions; |
||||
|
||||
typedef struct Gadget_Action |
||||
{ |
||||
Ecore_Wl2_Display *d; |
||||
Eina_Stringshare *action; |
||||
char handle[37]; |
||||
Eina_List *requestors; |
||||
struct action_route_bind *ar_bind; |
||||
} Gadget_Action; |
||||
|
||||
static inline Ecore_Wl2_Display * |
||||
win_display_get(Evas_Object *win) |
||||
{ |
||||
Ecore_Wl2_Window *ww; |
||||
ww = elm_win_wl_window_get(win); |
||||
return ecore_wl2_window_display_get(ww); |
||||
} |
||||
|
||||
static void |
||||
wins_emit(Ecore_Wl2_Display *d, const char *sig, uint32_t val) |
||||
{ |
||||
Eina_List *l, *ll; |
||||
Evas_Object *win; |
||||
|
||||
l = eina_hash_find(wins, &d); |
||||
EINA_LIST_FOREACH(l, ll, win) |
||||
evas_object_smart_callback_call(win, sig, (uintptr_t*)(uintptr_t)val); |
||||
} |
||||
|
||||
static void |
||||
_gadget_anchor(void *data, struct e_gadget *e_gadget EINA_UNUSED, uint32_t anchor) |
||||
{ |
||||
wins_emit(data, "gadget_site_anchor", anchor); |
||||
} |
||||
|
||||
static void |
||||
_gadget_orient(void *data, struct e_gadget *e_gadget EINA_UNUSED, uint32_t orient) |
||||
{ |
||||
wins_emit(data, "gadget_site_orient", orient); |
||||
} |
||||
|
||||
static void |
||||
_gadget_gravity(void *data, struct e_gadget *e_gadget EINA_UNUSED, uint32_t gravity) |
||||
{ |
||||
wins_emit(data, "gadget_site_gravity", gravity); |
||||
} |
||||
|
||||
static const struct e_gadget_listener _gadget_listener = |
||||
{ |
||||
_gadget_anchor, |
||||
_gadget_orient, |
||||
_gadget_gravity, |
||||
}; |
||||
|
||||
static void |
||||
_gadget_global_bind(Ecore_Wl2_Display *d, uint32_t id) |
||||
{ |
||||
struct e_gadget *gadget_global = wl_registry_bind(ecore_wl2_display_registry_get(d), id, &e_gadget_interface, 1); |
||||
e_gadget_add_listener(gadget_global, &_gadget_listener, d); |
||||
eina_hash_add(gadget_globals, &d, gadget_global); |
||||
} |
||||
|
||||
static void |
||||
_ar_global_bind(Ecore_Wl2_Display *d, uint32_t id) |
||||
{ |
||||
struct action_route *ar_global = wl_registry_bind(ecore_wl2_display_registry_get(d), id, &action_route_interface, 1); |
||||
eina_hash_add(ar_globals, &d, ar_global); |
||||
} |
||||
|
||||
static Eina_Bool |
||||
_global_added(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Wl2_Event_Global *ev) |
||||
{ |
||||
if (eina_streq(ev->interface, "e_gadget")) |
||||
_gadget_global_bind(ev->display, ev->id); |
||||
else if (eina_streq(ev->interface, "action_route")) |
||||
_ar_global_bind(ev->display, ev->id); |
||||
return ECORE_CALLBACK_RENEW; |
||||
} |
||||
|
||||
static void |
||||
_gadget_init(Ecore_Wl2_Display *d) |
||||
{ |
||||
Eina_Iterator *it; |
||||
Ecore_Wl2_Global *g; |
||||
|
||||
if (wins) |
||||
{ |
||||
if (eina_hash_find(gadget_globals, &d)) return; |
||||
} |
||||
else |
||||
{ |
||||
gadget_globals = eina_hash_pointer_new(NULL); |
||||
ar_globals = eina_hash_pointer_new(NULL); |
||||
} |
||||
it = ecore_wl2_display_globals_get(d); |
||||
EINA_ITERATOR_FOREACH(it, g) |
||||
{ |
||||
if (eina_streq(g->interface, "e_gadget")) |
||||
_gadget_global_bind(d, g->id); |
||||
else if (eina_streq(g->interface, "action_route")) |
||||
_ar_global_bind(d, g->id); |
||||
} |
||||
eina_iterator_free(it); |
||||
if (!handler) |
||||
handler = ecore_event_handler_add(ECORE_WL2_EVENT_GLOBAL_ADDED, (Ecore_Event_Handler_Cb)_global_added, NULL); |
||||
} |
||||
|
||||
static void |
||||
_ar_bind_activate(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) |
||||
{ |
||||
const char *params = event_info; |
||||
Gadget_Action *ga = data; |
||||
|
||||
if (params && (!params[0])) params = NULL; |
||||
action_route_bind_activate(ga->ar_bind, params); |
||||
} |
||||
|
||||
static void |
||||
_ar_bind_del(Gadget_Action *ga) |
||||
{ |
||||
Evas_Object *r; |
||||
eina_stringshare_del(ga->action); |
||||
EINA_LIST_FREE(ga->requestors, r) |
||||
evas_object_smart_callback_del_full(r, ga->handle, _ar_bind_activate, ga); |
||||
free(ga); |
||||
} |
||||
|
||||
static void |
||||
_ar_bind_end(void *data, struct action_route_bind *action_route_bind EINA_UNUSED) |
||||
{ |
||||
Gadget_Action *ga = data; |
||||
Eina_List *l; |
||||
Evas_Object *r; |
||||
|
||||
EINA_LIST_FOREACH(ga->requestors, l, r) |
||||
evas_object_smart_callback_call(r, "gadget_action_end", ga->handle); |
||||
} |
||||
|
||||
static void |
||||
_ar_bind_status(void *data, struct action_route_bind *action_route_bind, uint32_t state) |
||||
{ |
||||
uuid_t u; |
||||
Gadget_Action *ga = data; |
||||
Evas_Object *r; |
||||
|
||||
if (state == ACTION_ROUTE_BIND_STATE_REJECTED) |
||||
{ |
||||
Eina_Hash *h; |
||||
Eina_List *l; |
||||
h = eina_hash_find(display_actions, &ga->d); |
||||
EINA_LIST_FOREACH(ga->requestors, l, r) |
||||
{ |
||||
if (ga->handle[0]) |
||||
evas_object_smart_callback_call(r, "gadget_action_deleted", ga->handle); |
||||
else |
||||
evas_object_smart_callback_call(r, "gadget_action", NULL); |
||||
} |
||||
eina_hash_del_by_key(h, ga->action); |
||||
return; |
||||
} |
||||
uuid_generate(u); |
||||
uuid_unparse_lower(u, ga->handle); |
||||
ga->ar_bind = action_route_bind; |
||||
r = eina_list_data_get(ga->requestors); |
||||
evas_object_smart_callback_add(r, ga->handle, _ar_bind_activate, ga); |
||||
evas_object_smart_callback_call(r, "gadget_action", ga->handle); |
||||
} |
||||
|
||||
static const struct action_route_bind_listener _ar_bind_interface = |
||||
{ |
||||
_ar_bind_status, |
||||
_ar_bind_end |
||||
}; |
||||
|
||||
static void |
||||
action_request(void *data, Evas_Object *obj, void *event_info) |
||||
{ |
||||
Gadget_Action *ga; |
||||
const char *action = event_info; |
||||
Ecore_Wl2_Display *d = data; |
||||
void *ar_global; |
||||
struct action_route_bind *ar_bind; |
||||
Eina_Hash *h; |
||||
|
||||
if ((!action) || (!action[0])) |
||||
{ |
||||
evas_object_smart_callback_call(obj, "gadget_action", NULL); |
||||
return; |
||||
} |
||||
if (display_actions) |
||||
{ |
||||
h = eina_hash_find(display_actions, &d); |
||||
if (h) |
||||
{ |
||||
ga = eina_hash_find(h, action); |
||||
if (ga && (!eina_list_data_find(ga->requestors, obj))) |
||||
{ |
||||
ga->requestors = eina_list_append(ga->requestors, obj); |
||||
evas_object_smart_callback_add(obj, ga->handle, _ar_bind_activate, ga); |
||||
} |
||||
evas_object_smart_callback_call(obj, "gadget_action", ga ? ga->handle : NULL); |
||||
return; |
||||
} |
||||
} |
||||
ar_global = eina_hash_find(ar_globals, &d); |
||||
if (!ar_global) |
||||
{ |
||||
evas_object_smart_callback_call(obj, "gadget_action", NULL); |
||||
return; |
||||
} |
||||
ga = calloc(1, sizeof(Gadget_Action)); |
||||
ga->d = d; |
||||
ga->requestors = eina_list_append(ga->requestors, obj); |
||||
ga->action = eina_stringshare_add(action); |
||||
if (!display_actions) |
||||
display_actions = eina_hash_string_superfast_new(NULL); |
||||
h = eina_hash_find(display_actions, &d); |
||||
if (!h) |
||||
{ |
||||
h = eina_hash_pointer_new((Eina_Free_Cb)_ar_bind_del); |
||||
eina_hash_add(display_actions, &d, h); |
||||
} |
||||
|
||||
ar_bind = action_route_bind_action(ar_global, action); |
||||
action_route_bind_add_listener(ar_bind, &_ar_bind_interface, ga); |
||||
wl_display_roundtrip(ecore_wl2_display_get(d)); |
||||
} |
||||
|
||||
static void |
||||
win_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) |
||||
{ |
||||
Ecore_Wl2_Display *d = win_display_get(obj); |
||||
eina_hash_list_remove(wins, &d, obj); |
||||
} |
||||
|
||||
static Evas_Object * |
||||
win_add(Evas_Object *win) |
||||
{ |
||||
Ecore_Wl2_Display *d; |
||||
if (!win) return NULL; |
||||
d = win_display_get(win); |
||||
_gadget_init(d); |
||||
if (!wins) |
||||
wins = eina_hash_pointer_new(NULL); |
||||
eina_hash_list_append(wins, &d, win); |
||||
evas_object_smart_callback_add(win, "gadget_action_request", action_request, d); |
||||
evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, win_del, NULL); |
||||
return win; |
||||
} |
||||
|
||||
Evas_Object * |
||||
elm_win_util_dialog_add(Evas_Object *parent, const char *name, const char *title) |
||||
{ |
||||
Evas_Object *(*_elm_win_util_dialog_add)(Evas_Object *, const char *, const char *) = dlsym(RTLD_NEXT, __func__); |
||||
|
||||
return win_add(_elm_win_util_dialog_add(parent, name, title)); |
||||
} |
||||
|
||||
Evas_Object * |
||||
elm_win_util_standard_add(const char *name, const char *title) |
||||
{ |
||||
Evas_Object *(*_elm_win_util_standard_add)(const char *, const char *) = dlsym(RTLD_NEXT, __func__); |
||||
|
||||
return win_add(_elm_win_util_standard_add(name, title)); |
||||
} |
||||
|
||||
Evas_Object * |
||||
elm_win_add(Evas_Object *parent, const char *name, Elm_Win_Type type) |
||||
{ |
||||
Evas_Object *(*_elm_win_add)(Evas_Object *,const char*, Elm_Win_Type) = dlsym(RTLD_NEXT, __func__); |
||||
|
||||
return win_add(_elm_win_add(parent, name, type)); |
||||
} |
@ -0,0 +1,182 @@ |
||||
#include <Elementary.h> |
||||
#include <e_gadget_types.h> |
||||
|
||||
static E_Gadget_Site_Orient gorient; |
||||
static E_Gadget_Site_Anchor ganchor; |
||||
static char *menu_action; |
||||
|
||||
static void |
||||
do_orient(Evas_Object *ly, E_Gadget_Site_Orient orient, E_Gadget_Site_Anchor anchor) |
||||
{ |
||||
char buf[4096]; |
||||
const char *s = "float"; |
||||
|
||||
if (anchor & E_GADGET_SITE_ANCHOR_LEFT) |
||||
{ |
||||
if (anchor & E_GADGET_SITE_ANCHOR_TOP) |
||||
{ |
||||
switch (orient) |
||||
{ |
||||
case E_GADGET_SITE_ORIENT_HORIZONTAL: |
||||
s = "top_left"; |
||||
break; |
||||
case E_GADGET_SITE_ORIENT_VERTICAL: |
||||
s = "left_top"; |
||||
break; |
||||
case E_GADGET_SITE_ORIENT_NONE: |
||||
s = "left_top"; |
||||
break; |
||||
} |
||||
} |
||||
else if (anchor & E_GADGET_SITE_ANCHOR_BOTTOM) |
||||
{ |
||||
switch (orient) |
||||
{ |
||||
case E_GADGET_SITE_ORIENT_HORIZONTAL: |
||||
s = "bottom_left"; |
||||
break; |
||||
case E_GADGET_SITE_ORIENT_VERTICAL: |
||||
s = "left_bottom"; |
||||
break; |
||||
case E_GADGET_SITE_ORIENT_NONE: |
||||
s = "left_bottom"; |
||||
break; |
||||
} |
||||
} |
||||
else |
||||
s = "left"; |
||||
} |
||||
else if (anchor & E_GADGET_SITE_ANCHOR_RIGHT) |
||||
{ |
||||
if (anchor & E_GADGET_SITE_ANCHOR_TOP) |
||||
{ |
||||
switch (orient) |
||||
{ |
||||
case E_GADGET_SITE_ORIENT_HORIZONTAL: |
||||
s = "top_right"; |
||||
break; |
||||
case E_GADGET_SITE_ORIENT_VERTICAL: |
||||
s = "right_top"; |
||||
break; |
||||
case E_GADGET_SITE_ORIENT_NONE: |
||||
s = "right_top"; |
||||
break; |
||||
} |
||||
} |
||||
else if (anchor & E_GADGET_SITE_ANCHOR_BOTTOM) |
||||
{ |
||||
switch (orient) |
||||
{ |
||||
case E_GADGET_SITE_ORIENT_HORIZONTAL: |
||||
s = "bottom_right"; |
||||
break; |
||||
case E_GADGET_SITE_ORIENT_VERTICAL: |
||||
s = "right_bottom"; |
||||
break; |
||||
case E_GADGET_SITE_ORIENT_NONE: |
||||
s = "right_bottom"; |
||||
break; |
||||
} |
||||
} |
||||
else |
||||
s = "right"; |
||||
} |
||||
else if (anchor & E_GADGET_SITE_ANCHOR_TOP) |
||||
s = "top"; |
||||
else if (anchor & E_GADGET_SITE_ANCHOR_BOTTOM) |
||||
s = "bottom"; |
||||
else |
||||
{ |
||||
switch (orient) |
||||
{ |
||||
case E_GADGET_SITE_ORIENT_HORIZONTAL: |
||||
s = "horizontal"; |
||||
break; |
||||
case E_GADGET_SITE_ORIENT_VERTICAL: |
||||
s = "vertical"; |
||||
break; |
||||
default: break; |
||||
} |
||||
} |
||||
snprintf(buf, sizeof(buf), "e,state,orientation,%s", s); |
||||
elm_layout_signal_emit(ly, buf, "e"); |
||||
} |
||||
|
||||
static void |
||||
_menu_cb_post(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) |
||||
{ |
||||
if (eina_streq(event_info, menu_action)) |
||||
elm_layout_signal_emit(data, "e,state,unfocused", "e"); |
||||
} |
||||
|
||||
static void |
||||
_button_cb_mouse_down(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) |
||||
{ |
||||
Evas_Event_Mouse_Down *ev = event_info; |
||||
|
||||
if (ev->button != 1) return; |
||||
if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; |
||||
if (!menu_action) return; |
||||
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; |
||||
evas_object_smart_callback_call(elm_win_get(obj), menu_action, "main"); |
||||
elm_layout_signal_emit(obj, "e,state,focused", "e"); |
||||
} |
||||
|
||||
static void |
||||
anchor_change(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) |
||||
{ |
||||
ganchor = (uintptr_t)event_info; |
||||
do_orient(data, gorient, ganchor); |
||||
} |
||||
|
||||
static void |
||||
orient_change(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) |
||||
{ |
||||
gorient = (uintptr_t)event_info; |
||||
do_orient(data, gorient, ganchor); |
||||
} |
||||
|
||||
static void |
||||
action_deleted(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) |
||||
{ |
||||
if (eina_streq(menu_action, event_info)) |
||||
{ |
||||
free(menu_action); |
||||
menu_action = NULL; |
||||
} |
||||
} |
||||
|
||||
static void |
||||
action_return(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) |
||||
{ |
||||
fprintf(stderr, "AR RETURN: %s\n", (char*)event_info); |
||||
menu_action = eina_strdup(event_info); |
||||
} |
||||
|
||||
int |
||||
main(int argc, char *argv[]) |
||||
{ |
||||
Evas_Object *win, *ly; |
||||
|
||||
elm_init(argc, (char**)argv); |
||||
win = elm_win_add(NULL, "start", ELM_WIN_BASIC); |
||||
elm_win_autodel_set(win, 1); |
||||
elm_win_alpha_set(win, 1); |
||||
ly = elm_layout_add(win); |
||||
evas_object_size_hint_min_set(win, 100, 100); |
||||
evas_object_size_hint_aspect_set(ly, EVAS_ASPECT_CONTROL_BOTH, 1, 1); |
||||
elm_layout_file_set(ly, |
||||
elm_theme_group_path_find(NULL, "e/gadget/start/main"), "e/gadget/start/main"); |
||||
elm_win_resize_object_add(win, ly); |
||||
evas_object_show(ly); |
||||
evas_object_smart_callback_add(win, "gadget_site_anchor", anchor_change, ly); |
||||
evas_object_smart_callback_add(win, "gadget_site_orient", orient_change, ly); |
||||
evas_object_smart_callback_add(win, "gadget_action", action_return, NULL); |
||||
evas_object_smart_callback_add(win, "gadget_action_end", _menu_cb_post, ly); |
||||
evas_object_smart_callback_add(win, "gadget_action_deleted", action_deleted, NULL); |
||||
evas_object_event_callback_add(ly, EVAS_CALLBACK_MOUSE_DOWN, _button_cb_mouse_down, NULL); |
||||
evas_object_smart_callback_call(win, "gadget_action_request", "menu_show"); |
||||
evas_object_show(win); |
||||
ecore_main_loop_begin(); |
||||
return 0; |
||||
} |
Loading…
Reference in new issue