summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--meson_options.txt4
-rw-r--r--src/bin/e_bindings.c141
-rw-r--r--src/bin/e_bindings.h30
-rw-r--r--src/bin/e_config.c28
-rw-r--r--src/bin/e_config.h12
-rw-r--r--src/modules/conf_bindings/e_int_config_swipebindings.c978
-rw-r--r--src/modules/conf_bindings/e_mod_main.c4
-rw-r--r--src/modules/conf_bindings/e_mod_main.h2
-rw-r--r--src/modules/conf_bindings/meson.build1
-rw-r--r--src/modules/gesture_recognition/e_mod_main.c287
-rw-r--r--src/modules/gesture_recognition/meson.build5
-rw-r--r--src/modules/gesture_recognition/module.desktop6
-rw-r--r--src/modules/meson.build1
13 files changed, 1498 insertions, 1 deletions
diff --git a/meson_options.txt b/meson_options.txt
index 016dd81249..faedfeada8 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -297,3 +297,7 @@ option('conf-window-remembers',
type: 'boolean',
value: true,
description: 'enable conf-window-remembers module: (default=true)')
+option('gesture-recognition',
+ type: 'boolean',
+ value: true,
+ description: 'Enable gesture recognition using libinput, needed to get swipe bindings beeing detected.')
diff --git a/src/bin/e_bindings.c b/src/bin/e_bindings.c
index 084e6ef51b..7e4c1408ec 100644
--- a/src/bin/e_bindings.c
+++ b/src/bin/e_bindings.c
@@ -7,6 +7,7 @@ static void _e_bindings_edge_free(E_Binding_Edge *bind);
static void _e_bindings_signal_free(E_Binding_Signal *bind);
static void _e_bindings_wheel_free(E_Binding_Wheel *bind);
static void _e_bindings_acpi_free(E_Binding_Acpi *bind);
+static void _e_bindings_swipe_free(E_Binding_Swipe *bind);
static Eina_Bool _e_bindings_edge_cb_timer(void *data);
/* local subsystem globals */
@@ -17,9 +18,13 @@ static Eina_List *edge_bindings = NULL;
static Eina_List *signal_bindings = NULL;
static Eina_List *wheel_bindings = NULL;
static Eina_List *acpi_bindings = NULL;
+static Eina_List *swipe_bindings = NULL;
static unsigned int bindings_disabled = 0;
+static E_Bindings_Swipe_Live_Update live_update;
+static E_Bindings_Swipe_Live_Update live_update_data;
+
EINTERN E_Action *(*e_binding_key_list_cb)(E_Binding_Context, Ecore_Event_Key*, E_Binding_Modifier, E_Binding_Key **);
typedef struct _E_Binding_Edge_Data E_Binding_Edge_Data;
@@ -43,6 +48,7 @@ e_bindings_init(void)
E_Config_Binding_Edge *ebe;
E_Config_Binding_Key *ebk;
E_Config_Binding_Acpi *eba;
+ E_Config_Binding_Acpi *ebsw;
Eina_List *l;
EINA_LIST_FOREACH(e_bindings->mouse_bindings, l, ebm)
@@ -86,6 +92,8 @@ e_bindings_init(void)
e_bindings_acpi_add(eba->context, eba->type, eba->status,
eba->action, eba->params);
+ e_bindings_swipe_reset();
+
return 1;
}
@@ -98,6 +106,7 @@ e_bindings_shutdown(void)
E_FREE_LIST(signal_bindings, _e_bindings_signal_free);
E_FREE_LIST(wheel_bindings, _e_bindings_wheel_free);
E_FREE_LIST(acpi_bindings, _e_bindings_acpi_free);
+ E_FREE_LIST(swipe_bindings, _e_bindings_swipe_free);
return 1;
}
@@ -325,6 +334,18 @@ e_bindings_key_reset(void)
}
E_API void
+e_bindings_swipe_reset(void)
+{
+ E_Config_Binding_Swipe *eswipe;
+ Eina_List *l;
+
+ E_FREE_LIST(swipe_bindings, _e_bindings_swipe_free);
+
+ EINA_LIST_FOREACH(e_bindings->swipe_bindings, l, eswipe)
+ e_bindings_swipe_add(eswipe->context, eswipe->direction, eswipe->length, eswipe->fingers, eswipe->error, eswipe->action, eswipe->params);
+}
+
+E_API void
e_bindings_reset(void)
{
e_bindings_signal_reset();
@@ -332,6 +353,7 @@ e_bindings_reset(void)
e_bindings_wheel_reset();
e_bindings_edge_reset();
e_bindings_key_reset();
+ e_bindings_swipe_reset();
}
E_API void
@@ -1514,6 +1536,14 @@ _e_bindings_acpi_free(E_Binding_Acpi *binding)
E_FREE(binding);
}
+static void
+_e_bindings_swipe_free(E_Binding_Swipe *binding)
+{
+ if (binding->action) eina_stringshare_del(binding->action);
+ if (binding->params) eina_stringshare_del(binding->params);
+ E_FREE(binding);
+}
+
E_API int
e_bindings_context_match(E_Binding_Context bctxt, E_Binding_Context ctxt)
{
@@ -1583,3 +1613,114 @@ _e_bindings_edge_cb_timer(void *data)
return ECORE_CALLBACK_CANCEL;
}
+
+E_API void
+e_bindings_swipe_add(E_Binding_Context ctxt, double direction, double length, unsigned int fingers, double error, const char *action, const char *params)
+{
+ E_Binding_Swipe *binding = E_NEW(E_Binding_Swipe, 1);
+
+ binding->ctxt = ctxt;
+ binding->direction = direction;
+ binding->length = length;
+ binding->fingers = fingers;
+ binding->error = error;
+ if (action)
+ binding->action = eina_stringshare_add(action);
+ if (params)
+ binding->params = eina_stringshare_add(params);
+
+ swipe_bindings = eina_list_append(swipe_bindings, binding);
+}
+
+E_API void
+e_bindings_swipe_del(E_Binding_Context ctxt, double direction, double length, unsigned int fingers, double error, const char *action, const char *params)
+{
+ E_Binding_Swipe *binding;
+ Eina_List *n;
+
+ EINA_LIST_FOREACH(swipe_bindings, n, binding)
+ {
+ if (binding->ctxt == ctxt &&
+ binding->action == action &&
+ binding->params == params &&
+ EINA_DBL_EQ(direction, binding->direction) &&
+ EINA_DBL_EQ(length, binding->length) &&
+ EINA_DBL_EQ(fingers, binding->fingers) &&
+ EINA_DBL_EQ(error, binding->error))
+ {
+ _e_bindings_swipe_free(binding);
+ swipe_bindings = eina_list_remove_list(swipe_bindings, n);
+ break;
+ }
+ }
+}
+
+E_API Eina_Bool
+e_bindings_swipe_available(void)
+{
+ return eina_list_count(swipe_bindings) > 0;
+}
+
+E_API E_Action*
+e_bindings_swipe_handle(E_Binding_Context ctxt, E_Object *obj, double direction, double length, unsigned int fingers)
+{
+ E_Binding_Swipe *binding;
+ Eina_List *n;
+ E_Action *act = NULL;
+
+ EINA_LIST_FOREACH(swipe_bindings, n, binding)
+ {
+ if (binding->ctxt == ctxt &&
+ binding->length < length &&
+ EINA_DBL_EQ(fingers, binding->fingers) &&
+ fmod(binding->direction - binding->error, 2*M_PI) < direction &&
+ fmod(binding->direction + binding->error, 2*M_PI) > direction)
+ {
+ act = e_action_find(binding->action);
+ act->func.go(obj, binding->params);
+ }
+ }
+ return act;
+}
+
+
+E_API Eina_Inarray*
+e_bindings_swipe_find_candidates(E_Binding_Context ctxt, double direction, double length, unsigned int fingers)
+{
+ Eina_Inarray *ret = eina_inarray_new(sizeof(E_Binding_Swipe_Candidate), 10);
+ E_Binding_Swipe *binding;
+ Eina_List *n;
+
+ EINA_LIST_FOREACH(swipe_bindings, n, binding)
+ {
+ if (binding->ctxt == ctxt &&
+ EINA_DBL_EQ(fingers, binding->fingers) &&
+ fmod(binding->direction - binding->error, 2*M_PI) < direction &&
+ fmod(binding->direction + binding->error, 2*M_PI) > direction)
+ {
+ E_Binding_Swipe_Candidate cad = {binding->action, length / binding->length};
+ eina_inarray_push(ret, &cad);
+ }
+ }
+
+ return ret;
+}
+
+E_API void
+e_bindings_swipe_live_update_hook_set(E_Bindings_Swipe_Live_Update update, void *data)
+{
+ live_update = update;
+ live_update_data = data;
+}
+
+E_API E_Bindings_Swipe_Live_Update
+e_bindings_swipe_live_update_hook_get(void)
+{
+ return live_update;
+}
+
+E_API void*
+e_bindings_swipe_live_update_hook_data_get(void)
+{
+ return live_update_data;
+}
diff --git a/src/bin/e_bindings.h b/src/bin/e_bindings.h
index 043118cbfa..b65fabe38f 100644
--- a/src/bin/e_bindings.h
+++ b/src/bin/e_bindings.h
@@ -35,6 +35,7 @@ typedef struct _E_Binding_Edge E_Binding_Edge;
typedef struct _E_Binding_Signal E_Binding_Signal;
typedef struct _E_Binding_Wheel E_Binding_Wheel;
typedef struct _E_Binding_Acpi E_Binding_Acpi;
+typedef struct _E_Binding_Swipe E_Binding_Swipe;
typedef struct E_Binding_Event_Mouse_Button E_Binding_Event_Mouse_Button;
typedef struct E_Binding_Event_Wheel E_Binding_Event_Wheel;
@@ -131,6 +132,15 @@ struct _E_Binding_Acpi
const char *action, *params;
};
+struct _E_Binding_Swipe
+{
+ E_Binding_Context ctxt;
+ double direction, length, error;
+ unsigned int fingers;
+ const char *action, *params;
+};
+
+
EINTERN int e_bindings_init(void);
EINTERN int e_bindings_shutdown(void);
@@ -139,6 +149,7 @@ E_API void e_bindings_key_reset(void);
E_API void e_bindings_wheel_reset(void);
E_API void e_bindings_edge_reset(void);
E_API void e_bindings_signal_reset(void);
+E_API void e_bindings_swipe_reset(void);
E_API void e_bindings_reset(void);
E_API void e_bindings_mouse_add(E_Binding_Context ctxt, int button, E_Binding_Modifier mod, int any_mod, const char *action, const char *params);
@@ -196,6 +207,25 @@ E_API void e_bindings_acpi_del(E_Binding_Context ctxt, int type, int status, con
E_API E_Action *e_bindings_acpi_find(E_Binding_Context ctxt, E_Event_Acpi *ev, E_Binding_Acpi **bind_ret);
E_API E_Action *e_bindings_acpi_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Acpi *ev);
+typedef struct {
+ const char *name;
+ double acceptance; //0 to 1
+} E_Binding_Swipe_Candidate;
+
+typedef void (*E_Bindings_Swipe_Live_Update)(void *data, Eina_Bool end, double direction, double length, double error, unsigned int fingers);
+
+/**
+ * Direction is in radiens, 0 is pointing to the right. Going clockwise. (Only positive range)
+ */
+E_API Eina_Bool e_bindings_swipe_available(void);
+E_API void e_bindings_swipe_add(E_Binding_Context ctxt, double direction, double length, unsigned int fingers, double error, const char *action, const char *params);
+E_API void e_bindings_swipe_del(E_Binding_Context ctxt, double direction, double length, unsigned int fingers, double error, const char *action, const char *params);
+E_API E_Action* e_bindings_swipe_handle(E_Binding_Context ctxt, E_Object *obj, double direction, double length, unsigned int fingers);
+E_API Eina_Inarray/*<E_Bindings_Swipe_Candidate>*/* e_bindings_swipe_find_candidates(E_Binding_Context ctxt, double direction, double lenght, unsigned int fingers);
+E_API void e_bindings_swipe_live_update_hook_set(E_Bindings_Swipe_Live_Update update, void *data);
+E_API E_Bindings_Swipe_Live_Update e_bindings_swipe_live_update_hook_get(void);
+E_API void* e_bindings_swipe_live_update_hook_data_get(void);
+
E_API int e_bindings_evas_modifiers_convert(Evas_Modifier *modifiers);
E_API int e_bindings_modifiers_to_ecore_convert(E_Binding_Modifier modifiers);
E_API void e_bindings_evas_event_mouse_button_convert(const Evas_Event_Mouse_Down *ev, E_Binding_Event_Mouse_Button *event);
diff --git a/src/bin/e_config.c b/src/bin/e_config.c
index 6c792d4f20..3e5d68f76f 100644
--- a/src/bin/e_config.c
+++ b/src/bin/e_config.c
@@ -28,6 +28,7 @@ static E_Config_DD *_e_config_bindings_edge_edd = NULL;
static E_Config_DD *_e_config_bindings_signal_edd = NULL;
static E_Config_DD *_e_config_bindings_wheel_edd = NULL;
static E_Config_DD *_e_config_bindings_acpi_edd = NULL;
+static E_Config_DD *_e_config_bindings_swipe_edd = NULL;
static E_Config_DD *_e_config_path_append_edd = NULL;
static E_Config_DD *_e_config_desktop_bg_edd = NULL;
static E_Config_DD *_e_config_desklock_bg_edd = NULL;
@@ -460,6 +461,7 @@ _e_config_edd_init(Eina_Bool old)
E_CONFIG_LIST(D, T, signal_bindings, _e_config_bindings_signal_edd); /**/
E_CONFIG_LIST(D, T, wheel_bindings, _e_config_bindings_wheel_edd); /**/
E_CONFIG_LIST(D, T, acpi_bindings, _e_config_bindings_acpi_edd); /**/
+ E_CONFIG_LIST(D, T, swipe_bindings, _e_config_bindings_swipe_edd); /**/
E_CONFIG_LIST(D, T, path_append_data, _e_config_path_append_edd); /**/
E_CONFIG_LIST(D, T, path_append_images, _e_config_path_append_edd); /**/
E_CONFIG_LIST(D, T, path_append_fonts, _e_config_path_append_edd); /**/
@@ -924,6 +926,21 @@ e_config_init(void)
E_CONFIG_VAL(D, T, action, STR);
E_CONFIG_VAL(D, T, params, STR);
+ _e_config_bindings_swipe_edd = E_CONFIG_DD_NEW("E_Config_Binding_Swipe",
+ E_Config_Binding_Swipe);
+#undef T
+#undef D
+#define T E_Config_Binding_Swipe
+#define D _e_config_bindings_swipe_edd
+
+ E_CONFIG_VAL(D, T, context, INT);
+ E_CONFIG_VAL(D, T, fingers, UINT);
+ E_CONFIG_VAL(D, T, direction, DOUBLE);
+ E_CONFIG_VAL(D, T, length, DOUBLE);
+ E_CONFIG_VAL(D, T, error, DOUBLE);
+ E_CONFIG_VAL(D, T, action, STR);
+ E_CONFIG_VAL(D, T, params, STR);
+
_e_config_edd_init(EINA_FALSE);
_e_config_binding_edd = E_CONFIG_DD_NEW("E_Config_Bindings", E_Config_Bindings);
@@ -938,6 +955,7 @@ e_config_init(void)
E_CONFIG_LIST(D, T, signal_bindings, _e_config_bindings_signal_edd); /**/
E_CONFIG_LIST(D, T, wheel_bindings, _e_config_bindings_wheel_edd); /**/
E_CONFIG_LIST(D, T, acpi_bindings, _e_config_bindings_acpi_edd); /**/
+ E_CONFIG_LIST(D, T, swipe_bindings, _e_config_bindings_swipe_edd); /**/
e_config_load();
@@ -2258,6 +2276,16 @@ e_config_mode_changed(void)
}
E_API void
+e_config_binding_swipe_free(E_Config_Binding_Swipe *eba)
+{
+ if (!eba) return;
+ eina_stringshare_del(eba->action);
+ eina_stringshare_del(eba->params);
+ free(eba);
+}
+
+
+E_API void
e_config_binding_acpi_free(E_Config_Binding_Acpi *eba)
{
if (!eba) return;
diff --git a/src/bin/e_config.h b/src/bin/e_config.h
index deae01d318..3b1c304ca6 100644
--- a/src/bin/e_config.h
+++ b/src/bin/e_config.h
@@ -10,6 +10,7 @@ typedef struct _E_Config_Binding_Edge E_Config_Binding_Edge;
typedef struct _E_Config_Binding_Signal E_Config_Binding_Signal;
typedef struct _E_Config_Binding_Wheel E_Config_Binding_Wheel;
typedef struct _E_Config_Binding_Acpi E_Config_Binding_Acpi;
+typedef struct _E_Config_Binding_Swipe E_Config_Binding_Swipe;
typedef struct _E_Config_Desktop_Background E_Config_Desktop_Background;
typedef struct _E_Config_Desklock_Background E_Config_Desklock_Background;
typedef struct _E_Config_Desktop_Name E_Config_Desktop_Name;
@@ -87,6 +88,7 @@ struct _E_Config
Eina_List *signal_bindings; // GUI
Eina_List *wheel_bindings; // GUI
Eina_List *acpi_bindings; // GUI
+ Eina_List *swipe_bindings; // GUI
Eina_List *path_append_data; // GUI
Eina_List *path_append_images; // GUI
@@ -452,6 +454,7 @@ struct E_Config_Bindings
Eina_List *signal_bindings; // GUI
Eina_List *wheel_bindings; // GUI
Eina_List *acpi_bindings; // GUI
+ Eina_List *swipe_bindings;
};
struct _E_Config_Desklock_Background
@@ -542,6 +545,14 @@ struct _E_Config_Binding_Acpi
const char *action, *params;
};
+struct _E_Config_Binding_Swipe
+{
+ int context;
+ unsigned int fingers;
+ double direction, length, error;
+ const char *action, *params;
+};
+
struct _E_Config_Desktop_Background
{
int zone;
@@ -675,6 +686,7 @@ E_API void e_config_binding_mouse_free(E_Config_Binding_Mouse *ebm);
E_API void e_config_binding_edge_free(E_Config_Binding_Edge *ebe);
E_API void e_config_binding_key_free(E_Config_Binding_Key *ebk);
E_API void e_config_binding_acpi_free(E_Config_Binding_Acpi *eba);
+E_API void e_config_binding_swipe_free(E_Config_Binding_Swipe *eba);
extern E_API E_Config *e_config;
extern E_API E_Config_Bindings *e_bindings;
diff --git a/src/modules/conf_bindings/e_int_config_swipebindings.c b/src/modules/conf_bindings/e_int_config_swipebindings.c
new file mode 100644
index 0000000000..7c47aaa928
--- /dev/null
+++ b/src/modules/conf_bindings/e_int_config_swipebindings.c
@@ -0,0 +1,978 @@
+#include "e.h"
+
+#define TEXT_NO_PARAMS _("<None>")
+
+struct _E_Config_Dialog_Data
+{
+ Evas *evas;
+ struct
+ {
+ Eina_List *swipe;
+ } binding;
+ struct
+ {
+ const char *binding, *action;
+ char *params;
+ const char *cur;
+ int button;
+ int cur_act;
+ const char *swipe;
+ const char *source;
+
+ E_Dialog *dia;
+ double degree;
+ double error;
+ double length;
+ unsigned int fingers;
+ } locals;
+ struct
+ {
+ Evas_Object *o_add, *o_del, *o_del_all;
+ Evas_Object *o_binding_list, *o_action_list;
+ Evas_Object *o_params, *o_selector;
+ } gui;
+
+ const char *params;
+
+ int fullscreen_flip;
+ int multiscreen_flip;
+
+ E_Config_Dialog *cfd;
+};
+
+static E_Config_Binding_Swipe *
+_swipe_binding_copy(E_Config_Binding_Swipe *bi)
+{
+ E_Config_Binding_Swipe *bi2;
+ if (!bi) return NULL;
+
+ bi2 = E_NEW(E_Config_Binding_Swipe, 1);
+ bi2->context = bi->context;
+ bi2->direction = bi->direction;
+ bi2->length = bi->length;
+ bi2->fingers = bi->fingers;
+ bi2->error = bi->error;
+ bi2->action = bi->action;
+ bi2->params = bi->params;
+ return bi2;
+}
+
+static void
+_swipe_binding_free(E_Config_Binding_Swipe *bi)
+{
+ if (!bi) return;
+ eina_stringshare_del(bi->action);
+ eina_stringshare_del(bi->params);
+ free(bi);
+}
+
+
+static void
+_auto_apply_changes(E_Config_Dialog_Data *cfdata)
+{
+ int n, g, a, ok;
+ E_Config_Binding_Swipe *bi;
+ E_Action_Group *actg;
+ E_Action_Description *actd;
+
+ if ((!cfdata->locals.cur) || (!cfdata->locals.cur[0]) ||
+ (!cfdata->locals.action) || (!cfdata->locals.action[0])) return;
+
+ if (sscanf(cfdata->locals.cur, "s%d", &n) != 1)
+ return;
+ if (sscanf(cfdata->locals.action, "%d %d", &g, &a) != 2)
+ return;
+
+ bi = eina_list_nth(cfdata->binding.swipe, n);
+ if (!bi) return;
+
+ actg = eina_list_nth(e_action_groups_get(), g);
+ if (!actg) return;
+ actd = eina_list_nth(actg->acts, a);
+ if (!actd) return;
+
+ eina_stringshare_del(bi->action);
+ bi->action = NULL;
+
+ if (actd->act_cmd) bi->action = eina_stringshare_add(actd->act_cmd);
+
+ eina_stringshare_del(bi->params);
+ bi->params = NULL;
+
+ if (actd->act_params)
+ bi->params = eina_stringshare_add(actd->act_params);
+ else
+ {
+ ok = 1;
+ if (cfdata->locals.params)
+ {
+ if (!strcmp(cfdata->locals.params, TEXT_NO_PARAMS))
+ ok = 0;
+
+ if ((actd->param_example) && (!strcmp(cfdata->locals.params, actd->param_example)))
+ ok = 0;
+ }
+ else
+ ok = 0;
+
+ if (ok)
+ bi->params = eina_stringshare_add(cfdata->locals.params);
+ }
+}
+
+static void
+_fill_data(E_Config_Dialog_Data *cfdata)
+{
+ E_Config_Binding_Swipe *bi, *bi2;
+ Eina_List *l;
+
+ cfdata->locals.params = strdup("");
+ cfdata->locals.action = eina_stringshare_add("");
+ cfdata->locals.binding = eina_stringshare_add("");
+ cfdata->locals.swipe = eina_stringshare_add("");
+ cfdata->locals.source = eina_stringshare_add("");
+ cfdata->locals.cur = NULL;
+ cfdata->locals.dia = NULL;
+ cfdata->binding.swipe = NULL;
+
+ EINA_LIST_FOREACH(e_bindings->swipe_bindings, l, bi)
+ {
+ if (!bi) continue;
+ bi2 = _swipe_binding_copy(bi);
+ cfdata->binding.swipe = eina_list_append(cfdata->binding.swipe, bi2);
+ }
+}
+
+static void *
+_create_data(E_Config_Dialog *cfd)
+{
+ E_Config_Dialog_Data *cfdata;
+
+ cfdata = E_NEW(E_Config_Dialog_Data, 1);
+ cfdata->cfd = cfd;
+ _fill_data(cfdata);
+
+ return cfdata;
+}
+
+static void
+_free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
+{
+ E_FREE_LIST(cfdata->binding.swipe, _swipe_binding_free);
+
+ eina_stringshare_del(cfdata->locals.cur);
+ eina_stringshare_del(cfdata->params);
+ eina_stringshare_del(cfdata->locals.binding);
+ eina_stringshare_del(cfdata->locals.action);
+ eina_stringshare_del(cfdata->locals.swipe);
+ eina_stringshare_del(cfdata->locals.source);
+
+ if (cfdata->locals.dia) e_object_del(E_OBJECT(cfdata->locals.dia));
+
+ free(cfdata->locals.params);
+ E_FREE(cfdata);
+}
+
+
+static void
+_update_action_params(E_Config_Dialog_Data *cfdata)
+{
+ int g, a, b;
+ E_Action_Group *actg;
+ E_Action_Description *actd;
+ E_Config_Binding_Swipe *bi;
+ const char *action, *params;
+
+#define SIGNAL_EXAMPLE_PARAMS \
+ if ((!actd->param_example) || (!actd->param_example[0])) \
+ e_widget_entry_text_set(cfdata->gui.o_params, TEXT_NO_PARAMS); \
+ else \
+ e_widget_entry_text_set(cfdata->gui.o_params, actd->param_example)
+
+ if ((!cfdata->locals.action) || (!cfdata->locals.action[0]))
+ {
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+ e_widget_entry_clear(cfdata->gui.o_params);
+ return;
+ }
+ if (sscanf(cfdata->locals.action, "%d %d", &g, &a) != 2)
+ return;
+
+ actg = eina_list_nth(e_action_groups_get(), g);
+ if (!actg) return;
+ actd = eina_list_nth(actg->acts, a);
+ if (!actd) return;
+
+ if (actd->act_params)
+ {
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+ e_widget_entry_text_set(cfdata->gui.o_params, actd->act_params);
+ return;
+ }
+
+ if ((!cfdata->locals.cur) || (!cfdata->locals.cur[0]))
+ {
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+ SIGNAL_EXAMPLE_PARAMS;
+ return;
+ }
+
+ if (!actd->editable)
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+ else
+ e_widget_disabled_set(cfdata->gui.o_params, 0);
+
+ if (cfdata->locals.cur[0] == 's')
+ {
+ if (sscanf(cfdata->locals.cur, "s%d", &b) != 1)
+ {
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+ SIGNAL_EXAMPLE_PARAMS;
+ return;
+ }
+
+ bi = eina_list_nth(cfdata->binding.swipe, b);
+ if (!bi)
+ {
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+ SIGNAL_EXAMPLE_PARAMS;
+ return;
+ }
+ action = bi->action;
+ params = bi->params;
+ }
+ else
+ {
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+ SIGNAL_EXAMPLE_PARAMS;
+ return;
+ }
+
+ if (action)
+ {
+ if (!strcmp(action, actd->act_cmd))
+ {
+ if ((!params) || (!params[0]))
+ SIGNAL_EXAMPLE_PARAMS;
+ else
+ e_widget_entry_text_set(cfdata->gui.o_params, params);
+ }
+ else
+ SIGNAL_EXAMPLE_PARAMS;
+ }
+ else
+ SIGNAL_EXAMPLE_PARAMS;
+}
+
+static void
+_action_change_cb(void *data)
+{
+ E_Config_Dialog_Data *cfdata;
+
+ cfdata = data;
+ _update_action_params(cfdata);
+}
+
+static int
+_swipe_binding_sort_cb(E_Config_Binding_Swipe *a, E_Config_Binding_Swipe *b)
+{
+ int finger_diff = (a->fingers == b->fingers)*-1;
+ if (!finger_diff)
+ {
+ return a->direction - b->direction;
+ }
+ return finger_diff;
+}
+
+static void
+_update_buttons(E_Config_Dialog_Data *cfdata)
+{
+ if (e_widget_ilist_count(cfdata->gui.o_binding_list))
+ e_widget_disabled_set(cfdata->gui.o_del_all, 0);
+ else
+ e_widget_disabled_set(cfdata->gui.o_del_all, 1);
+
+ if (!cfdata->locals.cur)
+ {
+ e_widget_disabled_set(cfdata->gui.o_del, 1);
+ return;
+ }
+ e_widget_disabled_set(cfdata->gui.o_del, 0);
+}
+
+
+static void
+_find_swipe_binding_action(const char *action, const char *params, int *g, int *a, int *n)
+{
+ Eina_List *l, *l2;
+ int gg = -1, aa = -1, nn = -1, found;
+ E_Action_Group *actg;
+ E_Action_Description *actd;
+
+ if (g) *g = -1;
+ if (a) *a = -1;
+ if (n) *n = -1;
+
+ found = 0;
+ for (l = e_action_groups_get(), gg = 0, nn = 0; l; l = l->next, gg++)
+ {
+ actg = l->data;
+
+ for (l2 = actg->acts, aa = 0; l2; l2 = l2->next, aa++)
+ {
+ actd = l2->data;
+ if (!strcmp((!action ? "" : action), (!actd->act_cmd ? "" : actd->act_cmd)))
+ {
+ if (!params || !params[0])
+ {
+ if ((!actd->act_params) || (!actd->act_params[0]))
+ {
+ if (g) *g = gg;
+ if (a) *a = aa;
+ if (n) *n = nn;
+ return;
+ }
+ else
+ continue;
+ }
+ else
+ {
+ if ((!actd->act_params) || (!actd->act_params[0]))
+ {
+ if (g) *g = gg;
+ if (a) *a = aa;
+ if (n) *n = nn;
+ found = 1;
+ }
+ else
+ {
+ if (!strcmp(params, actd->act_params))
+ {
+ if (g) *g = gg;
+ if (a) *a = aa;
+ if (n) *n = nn;
+ return;
+ }
+ }
+ }
+ }
+ nn++;
+ }
+ if (found) break;
+ }
+
+ if (!found)
+ {
+ if (g) *g = -1;
+ if (a) *a = -1;
+ if (n) *n = -1;
+ }
+}
+
+static void
+_update_action_list(E_Config_Dialog_Data *cfdata)
+{
+ E_Config_Binding_Swipe *bi;
+ int j = -1, i, n;
+ const char *action, *params;
+
+ if (!cfdata->locals.cur) return;
+
+ if (cfdata->locals.cur[0] == 's')
+ {
+ if (sscanf(cfdata->locals.cur, "s%d", &n) != 1)
+ return;
+
+ bi = eina_list_nth(cfdata->binding.swipe, n);
+ if (!bi)
+ {
+ e_widget_ilist_unselect(cfdata->gui.o_action_list);
+ e_widget_entry_clear(cfdata->gui.o_params);
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+ return;
+ }
+ action = bi->action;
+ params = bi->params;
+ }
+ else
+ return;
+
+ _find_swipe_binding_action(action, params, NULL, NULL, &j);
+
+ if (j >= 0)
+ {
+ for (i = 0; i < e_widget_ilist_count(cfdata->gui.o_action_list); i++)
+ {
+ if (i > j) break;
+ if (e_widget_ilist_nth_is_header(cfdata->gui.o_action_list, i)) j++;
+ }
+ }
+
+ if (j >= 0)
+ {
+ if (j == e_widget_ilist_selected_get(cfdata->gui.o_action_list))
+ _update_action_params(cfdata);
+ else
+ e_widget_ilist_selected_set(cfdata->gui.o_action_list, j);
+ }
+ else
+ {
+ e_widget_ilist_unselect(cfdata->gui.o_action_list);
+ eina_stringshare_del(cfdata->locals.action);
+ cfdata->locals.action = eina_stringshare_add("");
+ e_widget_entry_clear(cfdata->gui.o_params);
+ }
+}
+
+static void
+_binding_change_cb(void *data)
+{
+ E_Config_Dialog_Data *cfdata;
+
+ cfdata = data;
+
+ _auto_apply_changes(cfdata);
+ if (cfdata->locals.cur) eina_stringshare_del(cfdata->locals.cur);
+ cfdata->locals.cur = NULL;
+
+ if ((!cfdata->locals.binding) || (!cfdata->locals.binding[0])) return;
+
+ cfdata->locals.cur = eina_stringshare_ref(cfdata->locals.binding);
+
+ _update_buttons(cfdata);
+ _update_action_list(cfdata);
+}
+
+
+static int
+_basic_apply_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
+{
+ Eina_List *l;
+ E_Config_Binding_Swipe *bi, *bi2;
+
+ _auto_apply_changes(cfdata);
+ E_FREE_LIST(e_bindings->swipe_bindings, _swipe_binding_free);
+ EINA_LIST_FOREACH(cfdata->binding.swipe, l, bi2)
+ {
+ bi = _swipe_binding_copy(bi2);
+ e_bindings->swipe_bindings = eina_list_append(e_bindings->swipe_bindings, bi);
+ }
+ e_bindings_swipe_reset();
+
+ e_config_save_queue();
+
+ return 1;
+}
+
+static Evas_Object*
+create_visualisation(Evas *e, double direction, double error)
+{
+ Evas_Vg_Container *vg = NULL;
+ Evas_Vg_Shape *container, *shape, *viewport = NULL;
+
+ double center_x = 15, center_y = 15;
+
+ vg = evas_object_vg_add(e);
+ evas_object_vg_viewbox_set(vg, EINA_RECT(0, 0, 50, 50));
+
+ container = evas_vg_container_add(vg);
+
+ viewport = evas_vg_shape_add(container);
+ evas_vg_shape_append_rect(viewport, 0, 0, 51, 51, 0, 0);
+ evas_vg_shape_stroke_cap_set(viewport, EVAS_VG_CAP_SQUARE);
+ evas_vg_shape_stroke_color_set(viewport, 0, 0, 0, 0);
+ evas_vg_shape_stroke_width_set(viewport, 1);
+
+ shape = evas_vg_shape_add(container);
+ evas_vg_shape_append_rect(shape, 1, 1, 29, 29, 0, 0);
+ evas_vg_shape_stroke_cap_set(shape, EVAS_VG_CAP_SQUARE);
+ evas_vg_shape_stroke_color_set(shape, 100, 100, 100, 255);
+ evas_vg_shape_stroke_width_set(shape, 1);
+
+ shape = evas_vg_shape_add(container);
+ evas_vg_shape_append_line_to(shape, center_x, center_y);
+ evas_vg_shape_append_line_to(shape, center_x + cos(direction - error)*11, center_y + sin(direction - error)*11);
+ evas_vg_shape_append_arc_to(shape, center_x + cos(direction + error)*11, center_y + sin(direction + error)*11, 11, 11, 0, EINA_FALSE, EINA_TRUE);
+ evas_vg_shape_append_line_to(shape, center_x, center_y);
+
+ evas_vg_shape_stroke_cap_set(shape, EVAS_VG_CAP_ROUND);
+ evas_vg_shape_stroke_color_set(shape, 255, 0, 0, 255);
+ evas_vg_shape_stroke_width_set(shape, 2);
+
+ evas_object_vg_root_node_set(vg, container);
+
+ evas_object_show(vg);
+
+ return vg;
+}
+
+static void
+_update_swipe_binding_list(E_Config_Dialog_Data *cfdata)
+{
+ int i = 0;
+ char b2[64], b3[64];
+ Eina_List *l;
+ E_Config_Binding_Swipe *bi;
+ unsigned int previous_fingers = 0;
+
+ evas_event_freeze(evas_object_evas_get(cfdata->gui.o_binding_list));
+ edje_freeze();
+ e_widget_ilist_freeze(cfdata->gui.o_binding_list);
+
+ e_widget_ilist_clear(cfdata->gui.o_binding_list);
+ e_widget_ilist_go(cfdata->gui.o_binding_list);
+
+ if (cfdata->binding.swipe)
+ cfdata->binding.swipe = eina_list_sort(cfdata->binding.swipe, 0, (Eina_Compare_Cb)_swipe_binding_sort_cb);
+
+ EINA_LIST_FOREACH(cfdata->binding.swipe, l, bi)
+ {
+ Evas_Object *vis;
+
+ vis = create_visualisation(evas_object_evas_get(cfdata->gui.o_binding_list), bi->direction, bi->error);
+ if (bi->fingers != previous_fingers)
+ {
+ snprintf(b3, sizeof(b3), "%d Fingers", bi->fingers);
+ previous_fingers = bi->fingers;
+ e_widget_ilist_header_append(cfdata->gui.o_binding_list, NULL, b3);
+ }
+ snprintf(b2, sizeof(b2), "s%d", i);
+ snprintf(b3, sizeof(b3), "Length: %.2f Error: %.2f", bi->length, bi->error);
+
+ e_widget_ilist_append(cfdata->gui.o_binding_list, vis, b3, _binding_change_cb, cfdata, b2);
+ i++;
+ }
+ e_widget_ilist_go(cfdata->gui.o_binding_list);
+
+ e_widget_ilist_thaw(cfdata->gui.o_binding_list);
+ edje_thaw();
+ evas_event_thaw(evas_object_evas_get(cfdata->gui.o_binding_list));
+
+ if (eina_list_count(cfdata->binding.swipe))
+ e_widget_disabled_set(cfdata->gui.o_del_all, 0);
+ else
+ e_widget_disabled_set(cfdata->gui.o_del_all, 1);
+}
+
+static void
+_fill_actions_list(E_Config_Dialog_Data *cfdata)
+{
+ char buf[1024];
+ Eina_List *l, *l2;
+ E_Action_Group *actg;
+ E_Action_Description *actd;
+ int g, a;
+
+ evas_event_freeze(evas_object_evas_get(cfdata->gui.o_action_list));
+ edje_freeze();
+ e_widget_ilist_freeze(cfdata->gui.o_action_list);
+
+ e_widget_ilist_clear(cfdata->gui.o_action_list);
+ for (l = e_action_groups_get(), g = 0; l; l = l->next, g++)
+ {
+ actg = l->data;
+
+ if (!actg->acts) continue;
+
+ e_widget_ilist_header_append(cfdata->gui.o_action_list, NULL, _(actg->act_grp));
+
+ for (l2 = actg->acts, a = 0; l2; l2 = l2->next, a++)
+ {
+ actd = l2->data;
+
+ snprintf(buf, sizeof(buf), "%d %d", g, a);
+ e_widget_ilist_append(cfdata->gui.o_action_list, NULL, _(actd->act_name),
+ _action_change_cb, cfdata, buf);
+ }
+ }
+ e_widget_ilist_go(cfdata->gui.o_action_list);
+ e_widget_ilist_thaw(cfdata->gui.o_action_list);
+ edje_thaw();
+ evas_event_thaw(evas_object_evas_get(cfdata->gui.o_action_list));
+}
+
+static void
+_flush_binding_swipe(E_Config_Dialog_Data *cfdata)
+{
+ E_Config_Binding_Swipe *bi;
+
+ bi = E_NEW(E_Config_Binding_Swipe, 1);
+ bi->context = E_BINDING_CONTEXT_NONE;
+ bi->length = cfdata->locals.length;
+ bi->direction = cfdata->locals.degree;
+ bi->error = cfdata->locals.error;
+ bi->fingers = cfdata->locals.fingers;
+
+ cfdata->binding.swipe = eina_list_append(cfdata->binding.swipe, bi);
+ _update_swipe_binding_list(cfdata);
+}
+
+static void
+_swipe_add_cb_ok(void *data, E_Dialog *dia)
+{
+ E_Config_Dialog_Data *cfdata = data;
+
+ _flush_binding_swipe(cfdata);
+
+ e_object_del(E_OBJECT(dia));
+}
+
+static void
+_swipe_add_cb_cancel(void *data EINA_UNUSED, E_Dialog *dia)
+{
+ e_object_del(E_OBJECT(dia));
+}
+
+static void
+_swipe_add_del(void *data)
+{
+ E_Dialog *dia = data;
+ E_Config_Dialog_Data *cfdata;
+
+ if (!dia->data) return;
+ cfdata = dia->data;
+ cfdata->locals.dia = NULL;
+}
+
+static void
+_double_getter(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+ double *container = data;
+ double tmp = elm_spinner_value_get(obj);
+ *container = tmp;
+}
+
+static void
+_int_getter(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+ unsigned int *container = data;
+ double tmp = elm_spinner_value_get(obj);
+ *container = tmp;
+}
+
+static void
+_swipe_add_show(E_Config_Dialog_Data *cfdata)
+{
+ Evas_Object *o, *obg, *ol, *entry;
+ Evas *evas;
+ int w, h;
+
+ if (cfdata->locals.dia) return;
+
+ cfdata->locals.dia = e_dialog_new(cfdata->cfd->dia->win, "E", "_swipebind_new_dialog");
+ e_dialog_resizable_set(cfdata->locals.dia, 1);
+ e_dialog_title_set(cfdata->locals.dia, _("Add Swipe Binding"));
+ e_dialog_icon_set(cfdata->locals.dia, "enlightenment/swipes", 48);
+ e_dialog_button_add(cfdata->locals.dia, _("OK"), NULL, _swipe_add_cb_ok, cfdata);
+ e_dialog_button_add(cfdata->locals.dia, _("Cancel"), NULL, _swipe_add_cb_cancel, cfdata);
+ e_object_del_attach_func_set(E_OBJECT(cfdata->locals.dia), _swipe_add_del);
+ cfdata->locals.dia->data = cfdata;
+ elm_win_center(cfdata->locals.dia->win, 1, 1);
+
+ evas = evas_object_evas_get(cfdata->locals.dia->win);
+ obg = e_widget_list_add(evas, 1, 0);
+
+ ol = e_widget_framelist_add(evas, _("Direction:"), 0);
+ entry = o = elm_spinner_add(cfdata->locals.dia->win);
+ evas_object_smart_callback_add(o, "changed", _double_getter, &cfdata->locals.degree);
+ elm_spinner_min_max_set(o, 0, 2*M_PI);
+ elm_spinner_label_format_set(o, "%f");
+ elm_spinner_step_set(o, 0.1);
+ elm_spinner_editable_set(o, EINA_TRUE);
+ e_widget_framelist_object_append(ol, o);
+ e_widget_list_object_append(obg, ol, 1, 0, 0.5);
+
+ ol = e_widget_framelist_add(evas, _("Error:"), 0);
+ entry = o = elm_spinner_add(cfdata->locals.dia->win);
+ evas_object_smart_callback_add(o, "changed", _double_getter, &cfdata->locals.error);
+ elm_spinner_min_max_set(o, 0, 2*M_PI);
+ elm_spinner_label_format_set(o, "%f");
+ elm_spinner_step_set(o, 0.1);
+ elm_spinner_editable_set(o, EINA_TRUE);
+ e_widget_framelist_object_append(ol, o);
+ e_widget_list_object_append(obg, ol, 1, 0, 0.5);
+
+ ol = e_widget_framelist_add(evas, _("Length:"), 0);
+ entry = o = elm_spinner_add(cfdata->locals.dia->win);
+ evas_object_smart_callback_add(o, "changed", _double_getter, &cfdata->locals.length);
+ elm_spinner_min_max_set(o, 0, 200);
+ elm_spinner_step_set(o, 5);
+ elm_spinner_editable_set(o, EINA_TRUE);
+ e_widget_framelist_object_append(ol, o);
+ e_widget_list_object_append(obg, ol, 1, 0, 0.5);
+
+ cfdata->locals.fingers = 3;
+ ol = e_widget_framelist_add(evas, _("Fingers:"), 0);
+ entry = o = elm_spinner_add(cfdata->locals.dia->win);
+ evas_object_smart_callback_add(o, "changed", _int_getter, &cfdata->locals.fingers);
+ elm_spinner_min_max_set(o, 3, 10);
+ elm_spinner_value_set(o, 3.0);
+ elm_spinner_editable_set(o, EINA_TRUE);
+ e_widget_framelist_object_append(ol, o);
+ e_widget_list_object_append(obg, ol, 1, 0, 0.5);
+
+ e_widget_size_min_get(obg, &w, &h);
+ e_dialog_content_set(cfdata->locals.dia, obg, MAX(w, 200), MAX(h, 100));
+
+ e_dialog_show(cfdata->locals.dia);
+ e_widget_focus_set(entry, 1);
+}
+
+static void
+_add_swipe_binding_cb(void *data, void *data2 EINA_UNUSED)
+{
+ E_Config_Dialog_Data *cfdata = data;
+
+ _auto_apply_changes(cfdata);
+ _swipe_add_show(cfdata);
+}
+
+static void
+_update_swipe_cb(void *data, Eina_Bool end, double direction, double length, double error, unsigned int fingers)
+{
+ E_Config_Dialog_Data *cfdata = data;
+
+ if (end)
+ {
+ e_object_del(E_OBJECT(cfdata->locals.dia));
+ cfdata->locals.dia = NULL;
+ cfdata->locals.degree = direction;
+ cfdata->locals.length = length;
+ cfdata->locals.error = error;
+ cfdata->locals.fingers = fingers;
+ _flush_binding_swipe(cfdata);
+ e_bindings_swipe_live_update_hook_set(NULL, NULL);
+ }
+ else
+ {
+ char text_buf[1000];
+ Evas_Object *vis;
+
+ vis = create_visualisation(evas_object_evas_get(cfdata->locals.dia->win), direction, error);
+ evas_object_size_hint_align_set(vis, 0.0, 0.5);
+ snprintf(text_buf, sizeof(text_buf), "Using %d Fingers<br> <b>Direction</b> %f <b>Length</b> %f <b>Error</b> %f", fingers, direction, length, error);
+ e_dialog_text_set(cfdata->locals.dia, text_buf);
+ elm_object_part_content_set(cfdata->locals.dia->bg_object, "e.swallow.icon", vis);
+ evas_object_size_hint_min_set(vis, 30 * e_scale, 30 * e_scale);
+ elm_layout_signal_emit(cfdata->locals.dia->bg_object, "e,state,icon", "e");
+ elm_layout_signal_emit(cfdata->locals.dia->bg_object, "e,icon,enabled", "e");
+ }
+}
+
+static void
+_add_swipe_binding_by_sample_cb(void *data, void *data2 EINA_UNUSED)
+{
+ E_Config_Dialog_Data *cfdata = data;
+
+ cfdata->locals.dia = e_dialog_new(cfdata->cfd->dia->win, "E", "_swipe_recognition");
+ e_dialog_title_set(cfdata->locals.dia, "Swipe recognition");
+ e_dialog_text_set(cfdata->locals.dia, "Do your swipe gesture.<br>");
+ elm_win_center(cfdata->locals.dia->win, 1, 1);
+ elm_win_borderless_set(cfdata->locals.dia->win, 1);
+ e_dialog_resizable_set(cfdata->locals.dia, 0);
+ e_dialog_show(cfdata->locals.dia);
+ evas_object_layer_set(e_win_client_get(cfdata->locals.dia->win)->frame, E_LAYER_CLIENT_PRIO);
+
+ e_bindings_swipe_live_update_hook_set(_update_swipe_cb, data);
+}
+
+static void
+_delete_swipe_binding_cb(void *data, void *data2 EINA_UNUSED)
+{
+ Eina_List *l = NULL;
+ int sel, n;
+ E_Config_Dialog_Data *cfdata;
+
+ cfdata = data;
+
+ sel = e_widget_ilist_selected_get(cfdata->gui.o_binding_list);
+ if (cfdata->locals.binding[0] == 's')
+ {
+ if (sscanf(cfdata->locals.binding, "s%d", &n) != 1)
+ return;
+
+ l = eina_list_nth_list(cfdata->binding.swipe, n);
+
+ if (l)
+ {
+ _swipe_binding_free(eina_list_data_get(l));
+ cfdata->binding.swipe = eina_list_remove_list(cfdata->binding.swipe, l);
+ }
+ }
+
+ _update_swipe_binding_list(cfdata);
+
+ if (sel >= e_widget_ilist_count(cfdata->gui.o_binding_list))
+ sel = e_widget_ilist_count(cfdata->gui.o_binding_list) - 1;
+
+ eina_stringshare_del(cfdata->locals.cur);
+ cfdata->locals.cur = NULL;
+
+ e_widget_ilist_selected_set(cfdata->gui.o_binding_list, sel);
+ if (sel < 0)
+ {
+ e_widget_ilist_unselect(cfdata->gui.o_action_list);
+ e_widget_entry_clear(cfdata->gui.o_params);
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+ _update_buttons(cfdata);
+ }
+}
+
+
+static void
+_delete_all_swipe_binding_cb(void *data, void *data2 EINA_UNUSED)
+{
+ E_Config_Binding_Swipe *bi;
+ E_Config_Dialog_Data *cfdata;
+
+ cfdata = data;
+
+ EINA_LIST_FREE(cfdata->binding.swipe, bi)
+ _swipe_binding_free(bi);
+
+ eina_stringshare_del(cfdata->locals.cur);
+ cfdata->locals.cur = NULL;
+
+ e_widget_ilist_clear(cfdata->gui.o_binding_list);
+ e_widget_ilist_go(cfdata->gui.o_binding_list);
+ e_widget_ilist_unselect(cfdata->gui.o_action_list);
+ e_widget_entry_clear(cfdata->gui.o_params);
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+
+ _update_buttons(cfdata);
+}
+
+
+static void
+_restore_swipe_binding_defaults_cb(void *data, void *data2 EINA_UNUSED)
+{
+ E_Config_Bindings *ecb;
+ Eina_Stringshare *prof;
+ E_Config_Dialog_Data *cfdata = data;
+
+ ecb = e_config_domain_system_load("e_bindings", e_config_descriptor_find("E_Config_Bindings"));
+ if (!ecb)
+ {
+ const char *type;
+
+ prof = eina_stringshare_ref(e_config_profile_get());
+ switch (e_config->config_type)
+ {
+ case E_CONFIG_PROFILE_TYPE_DESKTOP:
+ type = "standard";
+ break;
+ case E_CONFIG_PROFILE_TYPE_MOBILE:
+ type = "mobile";
+ break;
+ //case E_CONFIG_PROFILE_TYPE_TABLET: FIXME - not used
+ default:
+ type = "default";
+ break;
+ }
+ e_config_profile_set(type);
+ ecb = e_config_domain_system_load("e_bindings", e_config_descriptor_find("E_Config_Bindings"));
+ e_config_profile_set(prof);
+ eina_stringshare_del(prof);
+ }
+ if (!ecb) return;
+ E_FREE_LIST(cfdata->binding.swipe, e_config_binding_swipe_free);
+ cfdata->binding.swipe = ecb->swipe_bindings, ecb->swipe_bindings = NULL;
+ e_config_bindings_free(ecb);
+
+ eina_stringshare_del(cfdata->locals.cur);
+ cfdata->locals.cur = NULL;
+
+ _update_swipe_binding_list(cfdata);
+ _update_buttons(cfdata);
+
+ e_widget_ilist_unselect(cfdata->gui.o_action_list);
+ e_widget_entry_clear(cfdata->gui.o_params);
+ e_widget_disabled_set(cfdata->gui.o_params, 1);
+}
+
+static Evas_Object *
+_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata)
+{
+ Evas_Object *o, *ol, *ot, *of, *ob;
+
+ cfdata->evas = evas;
+ o = e_widget_list_add(evas, 0, 0);
+ ol = e_widget_list_add(evas, 0, 1);
+
+ of = e_widget_frametable_add(evas, _("Swipe Bindings"), 0);
+ ob = e_widget_ilist_add(evas, 32, 32, &(cfdata->locals.binding));
+ cfdata->gui.o_binding_list = ob;
+ e_widget_size_min_set(ob, 200, 160);
+ e_widget_frametable_object_append(of, ob, 0, 0, 2, 1, 1, 1, 1, 1);
+
+ ob = e_widget_button_add(evas, _("Add"), "list-add", _add_swipe_binding_by_sample_cb, cfdata, NULL);
+ e_widget_frametable_object_append(of, ob, 0, 1, 1, 1, 1, 0, 1, 0);
+
+ ob = e_widget_button_add(evas, _("Add by props"), "list-add", _add_swipe_binding_cb, cfdata, NULL);
+ cfdata->gui.o_add = ob;
+ e_widget_frametable_object_append(of, ob, 0, 2, 1, 1, 1, 0, 1, 0);
+
+ ob = e_widget_button_add(evas, _("Delete"), "list-remove", _delete_swipe_binding_cb, cfdata, NULL);
+ cfdata->gui.o_del = ob;
+ e_widget_disabled_set(ob, 1);
+ e_widget_frametable_object_append(of, ob, 1, 1, 1, 1, 1, 0, 1, 0);
+ ob = e_widget_button_add(evas, _("Delete All"), "edit-clear", _delete_all_swipe_binding_cb, cfdata, NULL);
+ cfdata->gui.o_del_all = ob;
+ e_widget_disabled_set(ob, 1);
+ e_widget_frametable_object_append(of, ob, 1, 2, 1, 1, 1, 0, 1, 0);
+ ob = e_widget_button_add(evas, _("Restore Default Bindings"), "enlightenment", _restore_swipe_binding_defaults_cb, cfdata, NULL);
+ e_widget_frametable_object_append(of, ob, 0, 3, 2, 1, 1, 0, 1, 0);
+ e_widget_list_object_append(ol, of, 1, 1, 0.5);
+
+ ot = e_widget_table_add(e_win_evas_win_get(evas), 0);
+ of = e_widget_framelist_add(evas, _("Action"), 0);
+ ob = e_widget_ilist_add(evas, 24, 24, &(cfdata->locals.action));
+ cfdata->gui.o_action_list = ob;
+ e_widget_size_min_set(ob, 200, 240);
+ e_widget_framelist_object_append(of, ob);
+ e_widget_table_object_append(ot, of, 0, 0, 1, 1, 1, 1, 1, 1);
+
+ of = e_widget_framelist_add(evas, _("Action Params"), 0);
+ ob = e_widget_entry_add(cfd->dia->win, &(cfdata->locals.params), NULL, NULL, NULL);
+ cfdata->gui.o_params = ob;
+ e_widget_disabled_set(ob, 1);
+ e_widget_framelist_object_append(of, ob);
+ e_widget_table_object_append(ot, of, 0, 3, 1, 1, 1, 1, 1, 0);
+ e_widget_list_object_append(ol, ot, 1, 1, 0.5);
+
+ e_widget_list_object_append(o, ol, 1, 1, 0.5);
+
+ _update_swipe_binding_list(cfdata);
+ _fill_actions_list(cfdata);
+
+ e_dialog_resizable_set(cfd->dia, 1);
+ return o;
+}
+
+
+E_Config_Dialog *
+e_int_config_swipebindings(Evas_Object *parent EINA_UNUSED, const char *params)
+{
+ E_Config_Dialog *cfd;
+ E_Config_Dialog_View *v;
+
+ if (e_config_dialog_find("E", "keyboard_and_mouse/swipe_bindings")) return NULL;
+ v = E_NEW(E_Config_Dialog_View, 1);
+
+ v->create_cfdata = _create_data;
+ v->free_cfdata = _free_data;
+ v->basic.apply_cfdata = _basic_apply_data;
+ v->basic.create_widgets = _basic_create_widgets;
+ v->override_auto_apply = 1;
+
+ cfd = e_config_dialog_new(NULL, _("Swipe Bindings Settings"), "E",
+ "keyboard_and_mouse/swipe_bindings",
+ "enlightenment/swipes", 0, v, NULL);
+ if ((params) && (params[0]))
+ {
+ cfd->cfdata->params = eina_stringshare_add(params);
+// _add_swipe_binding_cb(cfd->cfdata, NULL);
+ }
+
+ return cfd;
+}
diff --git a/src/modules/conf_bindings/e_mod_main.c b/src/modules/conf_bindings/e_mod_main.c
index 97f0a46b77..8800faed8a 100644
--- a/src/modules/conf_bindings/e_mod_main.c
+++ b/src/modules/conf_bindings/e_mod_main.c
@@ -33,6 +33,10 @@ e_modapi_init(E_Module *m)
_("Edge Bindings"), NULL,
"preferences-desktop-edge-bindings",
e_int_config_edgebindings);
+ e_configure_registry_item_add("keyboard_and_mouse/swipe_bindings", 10,
+ _("Swipe Bindings"), NULL,
+ "preferences-desktop-swipe-bindings",
+ e_int_config_swipebindings);
e_configure_registry_category_add("advanced", 80, _("Advanced"), NULL, "preferences-advanced");
e_configure_registry_item_add("advanced/signal_bindings", 10,
diff --git a/src/modules/conf_bindings/e_mod_main.h b/src/modules/conf_bindings/e_mod_main.h
index d33fab98de..cc99913a3a 100644
--- a/src/modules/conf_bindings/e_mod_main.h
+++ b/src/modules/conf_bindings/e_mod_main.h
@@ -6,7 +6,7 @@ E_Config_Dialog *e_int_config_keybindings(Evas_Object *parent, const char *param
E_Config_Dialog *e_int_config_mousebindings(Evas_Object *parent, const char *params EINA_UNUSED);
E_Config_Dialog *e_int_config_edgebindings(Evas_Object *parent, const char *params EINA_UNUSED);
E_Config_Dialog *e_int_config_signalbindings(Evas_Object *parent, const char *params);
-
+E_Config_Dialog *e_int_config_swipebindings(Evas_Object *parent EINA_UNUSED, const char *params);
/**
* @addtogroup Optional_Conf
* @{
diff --git a/src/modules/conf_bindings/meson.build b/src/modules/conf_bindings/meson.build
index aec7492fda..ee1adad559 100644
--- a/src/modules/conf_bindings/meson.build
+++ b/src/modules/conf_bindings/meson.build
@@ -5,6 +5,7 @@ src = files(
'e_int_config_keybindings.c',
'e_int_config_mousebindings.c',
'e_int_config_signalbindings.c',
+ 'e_int_config_swipebindings.c',
'e_mod_main.h'
)
diff --git a/src/modules/gesture_recognition/e_mod_main.c b/src/modules/gesture_recognition/e_mod_main.c
new file mode 100644
index 0000000000..2ebbebecc1
--- /dev/null
+++ b/src/modules/gesture_recognition/e_mod_main.c
@@ -0,0 +1,287 @@
+#include <e.h>
+#include <Eina.h>
+#include <libinput.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+E_API E_Module_Api e_modapi =
+ {
+ E_MODULE_API_VERSION,
+ "Gesture Recognition"
+ };
+
+static struct libinput *gesture_recognition_ctx;
+static Ecore_Fd_Handler *fd_listener;
+
+static int open_restricted(const char *path, int flags, void *user_data EINA_UNUSED)
+{
+ int fd = open(path, flags);
+ return fd < 0 ? -errno : fd;
+}
+
+static void close_restricted(int fd, void *user_data EINA_UNUSED)
+{
+ close(fd);
+}
+
+static const struct libinput_interface interface = {
+ .open_restricted = open_restricted,
+ .close_restricted = close_restricted,
+};
+
+static void
+_find_all_touch_input_devices(const char *path, struct libinput *li)
+{
+ Eina_File_Direct_Info *info;
+ Eina_Iterator *input_devies = eina_file_direct_ls(path);
+
+ EINA_ITERATOR_FOREACH(input_devies, info)
+ {
+ struct libinput_device *dev = libinput_path_add_device(li, info->path);
+
+ if (!dev) continue;
+
+ if (!libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_GESTURE))
+ {
+ libinput_path_remove_device(dev);
+ }
+ }
+}
+
+static Eina_Hash *active_gestures;
+
+typedef struct {
+ Eina_Vector2 pos;
+ unsigned int fingers;
+ struct {
+ Evas_Object *visuals, *win;
+ } visuals;
+} Swipe_Stats;
+
+
+static Swipe_Stats*
+_find_swipe_gesture_recognizition(struct libinput_device *dev)
+{
+ Swipe_Stats *stats = eina_hash_find(active_gestures, dev);
+
+ return stats;
+}
+
+static Swipe_Stats*
+_start_swipe_gesture_recognizition(struct libinput_device *dev)
+{
+ Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev);
+
+ if (stats)
+ eina_hash_del_by_key(active_gestures, dev);
+
+ stats = calloc(1, sizeof(Swipe_Stats));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(stats, NULL);
+
+ if (e_bindings_swipe_available())
+ {
+ stats->visuals.win = elm_notify_add(e_comp->elm);
+ elm_notify_align_set(stats->visuals.win, 0.5, 0.5);
+ elm_object_tree_focus_allow_set(stats->visuals.win, EINA_FALSE);
+ evas_object_layer_set(stats->visuals.win, E_LAYER_CLIENT_PRIO);
+ evas_object_show(stats->visuals.win);
+
+ stats->visuals.visuals = elm_progressbar_add(stats->visuals.win);
+ elm_object_text_set(stats->visuals.visuals, "Progress of visuals");
+ evas_object_size_hint_min_set(stats->visuals.visuals, 300, 50);
+ evas_object_show(stats->visuals.visuals);
+ elm_object_content_set(stats->visuals.win, stats->visuals.visuals);
+ }
+
+
+ eina_hash_add(active_gestures, dev, stats);
+
+ return stats;
+}
+
+static void
+_end_swipe_gesture_recognizition(struct libinput_device *dev)
+{
+ eina_hash_del_by_key(active_gestures, dev);
+}
+
+static double
+_config_angle(Eina_Vector2 pos)
+{
+ double res = atan(pos.y/pos.x);
+
+ if (res < 0) res += M_PI;
+ if (pos.y < 0) res += M_PI;
+ return res;
+}
+
+static Eina_Bool
+_cb_input_dispatch(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
+{
+ struct libinput *li = data;
+ struct libinput_event *event;
+
+ if (libinput_dispatch(li) != 0)
+ printf("Failed to dispatch libinput events");
+
+ while((event = libinput_get_event(li)))
+ {
+ E_Bindings_Swipe_Live_Update live_update = e_bindings_swipe_live_update_hook_get();
+
+ enum libinput_event_type type = libinput_event_get_type(event);
+ struct libinput_device *dev = libinput_event_get_device(event);
+ if (type == LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN)
+ {
+ struct libinput_event_gesture *gesture = libinput_event_get_gesture_event(event);
+
+ Swipe_Stats *stats = _start_swipe_gesture_recognizition(dev);
+ stats->fingers = libinput_event_gesture_get_finger_count(gesture);
+ stats->pos.x = stats->pos.y = 0;
+ }
+ else if (type == LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE)
+ {
+ struct libinput_event_gesture *gesture = libinput_event_get_gesture_event(event);
+ Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev);
+
+ stats->pos.x += libinput_event_gesture_get_dx(gesture);
+ stats->pos.y += libinput_event_gesture_get_dy(gesture);
+ if (live_update)
+ {
+ live_update(e_bindings_swipe_live_update_hook_data_get(), EINA_FALSE, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), 0.8, stats->fingers);
+ }
+ else if (stats->visuals.win)
+ {
+ Eina_Inarray *res = e_bindings_swipe_find_candidates(E_BINDING_CONTEXT_NONE, _config_angle (stats->pos), eina_vector2_length_get(&stats->pos), stats->fingers);
+ E_Binding_Swipe_Candidate *itr;
+ double total = 0.0f;
+ unsigned int len = 0;
+
+ EINA_INARRAY_FOREACH(res, itr)
+ {
+ total += itr->acceptance;
+ len ++;
+ }
+
+ if (len > 0)
+ {
+ char text_buffer[1000];
+
+ snprintf(text_buffer, sizeof(text_buffer), "%d gestures possible", len);
+ elm_progressbar_value_set(stats->visuals.visuals, total/len);
+ elm_object_text_set(stats->visuals.visuals, text_buffer);
+ }
+ else
+ {
+ elm_progressbar_value_set(stats->visuals.visuals, 0.0f);
+ elm_object_text_set(stats->visuals.visuals, "No gesture found");
+ }
+
+ eina_inarray_free(res);
+ }
+ }
+ else if (type == LIBINPUT_EVENT_GESTURE_SWIPE_END)
+ {
+ Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev);
+
+ if (live_update)
+ live_update(e_bindings_swipe_live_update_hook_data_get(), EINA_TRUE, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), 0.8, stats->fingers);
+ else
+ e_bindings_swipe_handle(E_BINDING_CONTEXT_NONE, NULL, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), stats->fingers);
+
+ _end_swipe_gesture_recognizition(dev);
+ }
+ libinput_event_destroy(event);
+ }
+ return EINA_TRUE;
+}
+
+static void
+_setup_libinput(void)
+{
+ gesture_recognition_ctx = libinput_path_create_context(&interface, NULL);
+
+ _find_all_touch_input_devices("/dev/input/", gesture_recognition_ctx);
+
+ fd_listener = ecore_main_fd_handler_add(libinput_get_fd(gesture_recognition_ctx), ECORE_FD_READ, _cb_input_dispatch, gesture_recognition_ctx, NULL, NULL);
+}
+
+
+static void
+_tear_down_libinput(void)
+{
+ ecore_main_fd_handler_del(fd_listener);
+ libinput_unref(gesture_recognition_ctx);
+}
+
+static Eina_Bool
+_user_part_of_input(void)
+{
+ uid_t user = getuid();
+ struct passwd *user_pw = getpwuid(user);
+ gid_t *gids = NULL;
+ int number_of_groups = 0;
+ struct group *input_group = getgrnam("input");
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(user_pw, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(input_group, EINA_FALSE);
+
+ if (getgrouplist(user_pw->pw_name, getgid(), NULL, &number_of_groups) != -1)
+ {
+ ERR("Failed to enumerate groups of user");
+ return EINA_FALSE;
+ }
+ number_of_groups ++;
+ gids = alloca((number_of_groups) * sizeof(gid_t));
+ if (getgrouplist(user_pw->pw_name, getgid(), gids, &number_of_groups) == -1)
+ {
+ ERR("Failed to get groups of user");
+ return EINA_FALSE;
+ }
+
+ for (int i = 0; i < number_of_groups; ++i)
+ {
+ if (gids[i] == input_group->gr_gid)
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static void
+_stats_free(void *ptr)
+{
+ Swipe_Stats *stats = ptr;
+
+ evas_object_del(stats->visuals.win);
+ free(stats);
+}
+
+E_API int
+e_modapi_init(E_Module *m EINA_UNUSED)
+{
+ if (!_user_part_of_input())
+ {
+ e_module_dialog_show(m, "Gesture Recognition", "Your user is not part of the input group, libinput cannot be used.");
+
+ return 0;
+ }
+ active_gestures = eina_hash_pointer_new(_stats_free);
+ _setup_libinput();
+
+ return 1;
+}
+
+E_API int
+e_modapi_shutdown(E_Module *m EINA_UNUSED)
+{
+ _tear_down_libinput();
+ return 1;
+}
+
+E_API int
+e_modapi_save(E_Module *m EINA_UNUSED)
+{
+
+ return 1;
+}
+
diff --git a/src/modules/gesture_recognition/meson.build b/src/modules/gesture_recognition/meson.build
new file mode 100644
index 0000000000..5a007ee8ed
--- /dev/null
+++ b/src/modules/gesture_recognition/meson.build
@@ -0,0 +1,5 @@
+src = files(
+ 'e_mod_main.c',
+)
+deps += [dependency('libinput')]
+desktop_only = true
diff --git a/src/modules/gesture_recognition/module.desktop b/src/modules/gesture_recognition/module.desktop
new file mode 100644
index 0000000000..8136450cb0
--- /dev/null
+++ b/src/modules/gesture_recognition/module.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Type=Link
+Name=Gesture Recognition
+Comment=Gesture recognition using libinput
+Icon=e-module-start
+X-Enlightenment-ModuleType=utils
diff --git a/src/modules/meson.build b/src/modules/meson.build
index 21a8f1a235..735cd0e77c 100644
--- a/src/modules/meson.build
+++ b/src/modules/meson.build
@@ -45,6 +45,7 @@ mods = [
'tiling',
'packagekit',
'vkbd',
+ 'gesture_recognition',
# modules have a custom binary as well
'battery',
'cpufreq',