summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <marcel@osg.samsung.com>2020-07-02 12:18:42 +0200
committerMarcel Hollerbach <marcel@osg.samsung.com>2020-07-21 10:05:32 +0200
commit304afe7ea3daf5b2b651ff01e3127304692be950 (patch)
tree3bef0cd7d2238386f4a122a32288d8088566d209
parent1fa239b404ead097c1e019f6cdad6eb5f9f2f7e0 (diff)
Introduce gesture recognitiondevs/bu5hm4n/recognition
This is currently using libinputs gesture recognition. And offers a config screen to setup new gestures. 1. No default gesture bindings are setup 2. When libinput is not available the module is not going to be loaded, and nothing is recognited.+ 3. Only swipe gestures are recognized yet. 4. For now, you are required to be part of the input group, otherwise we cannot get the libinput events. (See Todo 1) 5. The visual representation is not really good. In terms of UI, it is visually showing a value coming from left to right, which is indicating a direction, which is not always the direction of the gesture, which is kind of bad. More improvements needed here. Some things that still can be done: 1. The whole libinput things should be handled by elput, either with the input group hack, or logind, or simply by root. The ideal idea would be that e_sys is creating the elput context, which also listens for new devices etc.. When all this is done, and it recognizes a new device, it can simply sent a message from e_sys to e, that there is some new device, with a opened fd. (However, this all needs to be locked up in a way that e_sys cannot be abused) -
-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 016dd8124..faedfeada 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -297,3 +297,7 @@ option('conf-window-remembers',
297 type: 'boolean', 297 type: 'boolean',
298 value: true, 298 value: true,
299 description: 'enable conf-window-remembers module: (default=true)') 299 description: 'enable conf-window-remembers module: (default=true)')
300option('gesture-recognition',
301 type: 'boolean',
302 value: true,
303 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 084e6ef51..7e4c1408e 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);
7static void _e_bindings_signal_free(E_Binding_Signal *bind); 7static void _e_bindings_signal_free(E_Binding_Signal *bind);
8static void _e_bindings_wheel_free(E_Binding_Wheel *bind); 8static void _e_bindings_wheel_free(E_Binding_Wheel *bind);
9static void _e_bindings_acpi_free(E_Binding_Acpi *bind); 9static void _e_bindings_acpi_free(E_Binding_Acpi *bind);
10static void _e_bindings_swipe_free(E_Binding_Swipe *bind);
10static Eina_Bool _e_bindings_edge_cb_timer(void *data); 11static Eina_Bool _e_bindings_edge_cb_timer(void *data);
11 12
12/* local subsystem globals */ 13/* local subsystem globals */
@@ -17,9 +18,13 @@ static Eina_List *edge_bindings = NULL;
17static Eina_List *signal_bindings = NULL; 18static Eina_List *signal_bindings = NULL;
18static Eina_List *wheel_bindings = NULL; 19static Eina_List *wheel_bindings = NULL;
19static Eina_List *acpi_bindings = NULL; 20static Eina_List *acpi_bindings = NULL;
21static Eina_List *swipe_bindings = NULL;
20 22
21static unsigned int bindings_disabled = 0; 23static unsigned int bindings_disabled = 0;
22 24
25static E_Bindings_Swipe_Live_Update live_update;
26static E_Bindings_Swipe_Live_Update live_update_data;
27
23EINTERN E_Action *(*e_binding_key_list_cb)(E_Binding_Context, Ecore_Event_Key*, E_Binding_Modifier, E_Binding_Key **); 28EINTERN E_Action *(*e_binding_key_list_cb)(E_Binding_Context, Ecore_Event_Key*, E_Binding_Modifier, E_Binding_Key **);
24 29
25typedef struct _E_Binding_Edge_Data E_Binding_Edge_Data; 30typedef struct _E_Binding_Edge_Data E_Binding_Edge_Data;
@@ -43,6 +48,7 @@ e_bindings_init(void)
43 E_Config_Binding_Edge *ebe; 48 E_Config_Binding_Edge *ebe;
44 E_Config_Binding_Key *ebk; 49 E_Config_Binding_Key *ebk;
45 E_Config_Binding_Acpi *eba; 50 E_Config_Binding_Acpi *eba;
51 E_Config_Binding_Acpi *ebsw;
46 Eina_List *l; 52 Eina_List *l;
47 53
48 EINA_LIST_FOREACH(e_bindings->mouse_bindings, l, ebm) 54 EINA_LIST_FOREACH(e_bindings->mouse_bindings, l, ebm)
@@ -86,6 +92,8 @@ e_bindings_init(void)
86 e_bindings_acpi_add(eba->context, eba->type, eba->status, 92 e_bindings_acpi_add(eba->context, eba->type, eba->status,
87 eba->action, eba->params); 93 eba->action, eba->params);
88 94
95 e_bindings_swipe_reset();
96
89 return 1; 97 return 1;
90} 98}
91 99
@@ -98,6 +106,7 @@ e_bindings_shutdown(void)
98 E_FREE_LIST(signal_bindings, _e_bindings_signal_free); 106 E_FREE_LIST(signal_bindings, _e_bindings_signal_free);
99 E_FREE_LIST(wheel_bindings, _e_bindings_wheel_free); 107 E_FREE_LIST(wheel_bindings, _e_bindings_wheel_free);
100 E_FREE_LIST(acpi_bindings, _e_bindings_acpi_free); 108 E_FREE_LIST(acpi_bindings, _e_bindings_acpi_free);
109 E_FREE_LIST(swipe_bindings, _e_bindings_swipe_free);
101 110
102 return 1; 111 return 1;
103} 112}
@@ -325,6 +334,18 @@ e_bindings_key_reset(void)
325} 334}
326 335
327E_API void 336E_API void
337e_bindings_swipe_reset(void)
338{
339 E_Config_Binding_Swipe *eswipe;
340 Eina_List *l;
341
342 E_FREE_LIST(swipe_bindings, _e_bindings_swipe_free);
343
344 EINA_LIST_FOREACH(e_bindings->swipe_bindings, l, eswipe)
345 e_bindings_swipe_add(eswipe->context, eswipe->direction, eswipe->length, eswipe->fingers, eswipe->error, eswipe->action, eswipe->params);
346}
347
348E_API void
328e_bindings_reset(void) 349e_bindings_reset(void)
329{ 350{
330 e_bindings_signal_reset(); 351 e_bindings_signal_reset();
@@ -332,6 +353,7 @@ e_bindings_reset(void)
332 e_bindings_wheel_reset(); 353 e_bindings_wheel_reset();
333 e_bindings_edge_reset(); 354 e_bindings_edge_reset();
334 e_bindings_key_reset(); 355 e_bindings_key_reset();
356 e_bindings_swipe_reset();
335} 357}
336 358
337E_API void 359E_API void
@@ -1514,6 +1536,14 @@ _e_bindings_acpi_free(E_Binding_Acpi *binding)
1514 E_FREE(binding); 1536 E_FREE(binding);
1515} 1537}
1516 1538
1539static void
1540_e_bindings_swipe_free(E_Binding_Swipe *binding)
1541{
1542 if (binding->action) eina_stringshare_del(binding->action);
1543 if (binding->params) eina_stringshare_del(binding->params);
1544 E_FREE(binding);
1545}
1546
1517E_API int 1547E_API int
1518e_bindings_context_match(E_Binding_Context bctxt, E_Binding_Context ctxt) 1548e_bindings_context_match(E_Binding_Context bctxt, E_Binding_Context ctxt)
1519{ 1549{
@@ -1583,3 +1613,114 @@ _e_bindings_edge_cb_timer(void *data)
1583 1613
1584 return ECORE_CALLBACK_CANCEL; 1614 return ECORE_CALLBACK_CANCEL;
1585} 1615}
1616
1617E_API void
1618e_bindings_swipe_add(E_Binding_Context ctxt, double direction, double length, unsigned int fingers, double error, const char *action, const char *params)
1619{
1620 E_Binding_Swipe *binding = E_NEW(E_Binding_Swipe, 1);
1621
1622 binding->ctxt = ctxt;
1623 binding->direction = direction;
1624 binding->length = length;
1625 binding->fingers = fingers;
1626 binding->error = error;
1627 if (action)
1628 binding->action = eina_stringshare_add(action);
1629 if (params)
1630 binding->params = eina_stringshare_add(params);
1631
1632 swipe_bindings = eina_list_append(swipe_bindings, binding);
1633}
1634
1635E_API void
1636e_bindings_swipe_del(E_Binding_Context ctxt, double direction, double length, unsigned int fingers, double error, const char *action, const char *params)
1637{
1638 E_Binding_Swipe *binding;
1639 Eina_List *n;
1640
1641 EINA_LIST_FOREACH(swipe_bindings, n, binding)
1642 {
1643 if (binding->ctxt == ctxt &&
1644 binding->action == action &&
1645 binding->params == params &&
1646 EINA_DBL_EQ(direction, binding->direction) &&
1647 EINA_DBL_EQ(length, binding->length) &&
1648 EINA_DBL_EQ(fingers, binding->fingers) &&
1649 EINA_DBL_EQ(error, binding->error))
1650 {
1651 _e_bindings_swipe_free(binding);
1652 swipe_bindings = eina_list_remove_list(swipe_bindings, n);
1653 break;
1654 }
1655 }
1656}
1657
1658E_API Eina_Bool
1659e_bindings_swipe_available(void)
1660{
1661 return eina_list_count(swipe_bindings) > 0;
1662}
1663
1664E_API E_Action*
1665e_bindings_swipe_handle(E_Binding_Context ctxt, E_Object *obj, double direction, double length, unsigned int fingers)
1666{
1667 E_Binding_Swipe *binding;
1668 Eina_List *n;
1669 E_Action *act = NULL;
1670
1671 EINA_LIST_FOREACH(swipe_bindings, n, binding)
1672 {
1673 if (binding->ctxt == ctxt &&
1674 binding->length < length &&
1675 EINA_DBL_EQ(fingers, binding->fingers) &&
1676 fmod(binding->direction - binding->error, 2*M_PI) < direction &&
1677 fmod(binding->direction + binding->error, 2*M_PI) > direction)
1678 {
1679 act = e_action_find(binding->action);
1680 act->func.go(obj, binding->params);
1681 }
1682 }
1683 return act;
1684}
1685
1686
1687E_API Eina_Inarray*
1688e_bindings_swipe_find_candidates(E_Binding_Context ctxt, double direction, double length, unsigned int fingers)
1689{
1690 Eina_Inarray *ret = eina_inarray_new(sizeof(E_Binding_Swipe_Candidate), 10);
1691 E_Binding_Swipe *binding;
1692 Eina_List *n;
1693
1694 EINA_LIST_FOREACH(swipe_bindings, n, binding)
1695 {
1696 if (binding->ctxt == ctxt &&
1697 EINA_DBL_EQ(fingers, binding->fingers) &&
1698 fmod(binding->direction - binding->error, 2*M_PI) < direction &&
1699 fmod(binding->direction + binding->error, 2*M_PI) > direction)
1700 {
1701 E_Binding_Swipe_Candidate cad = {binding->action, length / binding->length};
1702 eina_inarray_push(ret, &cad);
1703 }
1704 }
1705
1706 return ret;
1707}
1708
1709E_API void
1710e_bindings_swipe_live_update_hook_set(E_Bindings_Swipe_Live_Update update, void *data)
1711{
1712 live_update = update;
1713 live_update_data = data;
1714}
1715
1716E_API E_Bindings_Swipe_Live_Update
1717e_bindings_swipe_live_update_hook_get(void)
1718{
1719 return live_update;
1720}
1721
1722E_API void*
1723e_bindings_swipe_live_update_hook_data_get(void)
1724{
1725 return live_update_data;
1726}
diff --git a/src/bin/e_bindings.h b/src/bin/e_bindings.h
index 043118cbf..b65fabe38 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;
35typedef struct _E_Binding_Signal E_Binding_Signal; 35typedef struct _E_Binding_Signal E_Binding_Signal;
36typedef struct _E_Binding_Wheel E_Binding_Wheel; 36typedef struct _E_Binding_Wheel E_Binding_Wheel;
37typedef struct _E_Binding_Acpi E_Binding_Acpi; 37typedef struct _E_Binding_Acpi E_Binding_Acpi;
38typedef struct _E_Binding_Swipe E_Binding_Swipe;
38 39
39typedef struct E_Binding_Event_Mouse_Button E_Binding_Event_Mouse_Button; 40typedef struct E_Binding_Event_Mouse_Button E_Binding_Event_Mouse_Button;
40typedef struct E_Binding_Event_Wheel E_Binding_Event_Wheel; 41typedef struct E_Binding_Event_Wheel E_Binding_Event_Wheel;
@@ -131,6 +132,15 @@ struct _E_Binding_Acpi
131 const char *action, *params; 132 const char *action, *params;
132}; 133};
133 134
135struct _E_Binding_Swipe
136{
137 E_Binding_Context ctxt;
138 double direction, length, error;
139 unsigned int fingers;
140 const char *action, *params;
141};
142
143
134EINTERN int e_bindings_init(void); 144EINTERN int e_bindings_init(void);
135EINTERN int e_bindings_shutdown(void); 145EINTERN int e_bindings_shutdown(void);
136 146
@@ -139,6 +149,7 @@ E_API void e_bindings_key_reset(void);
139E_API void e_bindings_wheel_reset(void); 149E_API void e_bindings_wheel_reset(void);
140E_API void e_bindings_edge_reset(void); 150E_API void e_bindings_edge_reset(void);
141E_API void e_bindings_signal_reset(void); 151E_API void e_bindings_signal_reset(void);
152E_API void e_bindings_swipe_reset(void);
142E_API void e_bindings_reset(void); 153E_API void e_bindings_reset(void);
143 154
144E_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); 155E_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
196E_API E_Action *e_bindings_acpi_find(E_Binding_Context ctxt, E_Event_Acpi *ev, E_Binding_Acpi **bind_ret); 207E_API E_Action *e_bindings_acpi_find(E_Binding_Context ctxt, E_Event_Acpi *ev, E_Binding_Acpi **bind_ret);
197E_API E_Action *e_bindings_acpi_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Acpi *ev); 208E_API E_Action *e_bindings_acpi_event_handle(E_Binding_Context ctxt, E_Object *obj, E_Event_Acpi *ev);
198 209
210typedef struct {
211 const char *name;
212 double acceptance; //0 to 1
213} E_Binding_Swipe_Candidate;
214
215typedef void (*E_Bindings_Swipe_Live_Update)(void *data, Eina_Bool end, double direction, double length, double error, unsigned int fingers);
216
217/**
218 * Direction is in radiens, 0 is pointing to the right. Going clockwise. (Only positive range)
219 */
220E_API Eina_Bool e_bindings_swipe_available(void);
221E_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);
222E_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);
223E_API E_Action* e_bindings_swipe_handle(E_Binding_Context ctxt, E_Object *obj, double direction, double length, unsigned int fingers);
224E_API Eina_Inarray/*<E_Bindings_Swipe_Candidate>*/* e_bindings_swipe_find_candidates(E_Binding_Context ctxt, double direction, double lenght, unsigned int fingers);
225E_API void e_bindings_swipe_live_update_hook_set(E_Bindings_Swipe_Live_Update update, void *data);
226E_API E_Bindings_Swipe_Live_Update e_bindings_swipe_live_update_hook_get(void);
227E_API void* e_bindings_swipe_live_update_hook_data_get(void);
228
199E_API int e_bindings_evas_modifiers_convert(Evas_Modifier *modifiers); 229E_API int e_bindings_evas_modifiers_convert(Evas_Modifier *modifiers);
200E_API int e_bindings_modifiers_to_ecore_convert(E_Binding_Modifier modifiers); 230E_API int e_bindings_modifiers_to_ecore_convert(E_Binding_Modifier modifiers);
201E_API void e_bindings_evas_event_mouse_button_convert(const Evas_Event_Mouse_Down *ev, E_Binding_Event_Mouse_Button *event); 231E_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 6c792d4f2..3e5d68f76 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;
28static E_Config_DD *_e_config_bindings_signal_edd = NULL; 28static E_Config_DD *_e_config_bindings_signal_edd = NULL;
29static E_Config_DD *_e_config_bindings_wheel_edd = NULL; 29static E_Config_DD *_e_config_bindings_wheel_edd = NULL;
30static E_Config_DD *_e_config_bindings_acpi_edd = NULL; 30static E_Config_DD *_e_config_bindings_acpi_edd = NULL;
31static E_Config_DD *_e_config_bindings_swipe_edd = NULL;
31static E_Config_DD *_e_config_path_append_edd = NULL; 32static E_Config_DD *_e_config_path_append_edd = NULL;
32static E_Config_DD *_e_config_desktop_bg_edd = NULL; 33static E_Config_DD *_e_config_desktop_bg_edd = NULL;
33static E_Config_DD *_e_config_desklock_bg_edd = NULL; 34static E_Config_DD *_e_config_desklock_bg_edd = NULL;
@@ -460,6 +461,7 @@ _e_config_edd_init(Eina_Bool old)
460 E_CONFIG_LIST(D, T, signal_bindings, _e_config_bindings_signal_edd); /**/ 461 E_CONFIG_LIST(D, T, signal_bindings, _e_config_bindings_signal_edd); /**/
461 E_CONFIG_LIST(D, T, wheel_bindings, _e_config_bindings_wheel_edd); /**/ 462 E_CONFIG_LIST(D, T, wheel_bindings, _e_config_bindings_wheel_edd); /**/
462 E_CONFIG_LIST(D, T, acpi_bindings, _e_config_bindings_acpi_edd); /**/ 463 E_CONFIG_LIST(D, T, acpi_bindings, _e_config_bindings_acpi_edd); /**/
464 E_CONFIG_LIST(D, T, swipe_bindings, _e_config_bindings_swipe_edd); /**/
463 E_CONFIG_LIST(D, T, path_append_data, _e_config_path_append_edd); /**/ 465 E_CONFIG_LIST(D, T, path_append_data, _e_config_path_append_edd); /**/
464 E_CONFIG_LIST(D, T, path_append_images, _e_config_path_append_edd); /**/ 466 E_CONFIG_LIST(D, T, path_append_images, _e_config_path_append_edd); /**/
465 E_CONFIG_LIST(D, T, path_append_fonts, _e_config_path_append_edd); /**/ 467 E_CONFIG_LIST(D, T, path_append_fonts, _e_config_path_append_edd); /**/
@@ -924,6 +926,21 @@ e_config_init(void)
924 E_CONFIG_VAL(D, T, action, STR); 926 E_CONFIG_VAL(D, T, action, STR);
925 E_CONFIG_VAL(D, T, params, STR); 927 E_CONFIG_VAL(D, T, params, STR);
926 928
929 _e_config_bindings_swipe_edd = E_CONFIG_DD_NEW("E_Config_Binding_Swipe",
930 E_Config_Binding_Swipe);
931#undef T
932#undef D
933#define T E_Config_Binding_Swipe
934#define D _e_config_bindings_swipe_edd
935
936 E_CONFIG_VAL(D, T, context, INT);
937 E_CONFIG_VAL(D, T, fingers, UINT);
938 E_CONFIG_VAL(D, T, direction, DOUBLE);
939 E_CONFIG_VAL(D, T, length, DOUBLE);
940 E_CONFIG_VAL(D, T, error, DOUBLE);
941 E_CONFIG_VAL(D, T, action, STR);
942 E_CONFIG_VAL(D, T, params, STR);
943
927 _e_config_edd_init(EINA_FALSE); 944 _e_config_edd_init(EINA_FALSE);
928 945
929 _e_config_binding_edd = E_CONFIG_DD_NEW("E_Config_Bindings", E_Config_Bindings); 946 _e_config_binding_edd = E_CONFIG_DD_NEW("E_Config_Bindings", E_Config_Bindings);
@@ -938,6 +955,7 @@ e_config_init(void)
938 E_CONFIG_LIST(D, T, signal_bindings, _e_config_bindings_signal_edd); /**/ 955 E_CONFIG_LIST(D, T, signal_bindings, _e_config_bindings_signal_edd); /**/
939 E_CONFIG_LIST(D, T, wheel_bindings, _e_config_bindings_wheel_edd); /**/ 956 E_CONFIG_LIST(D, T, wheel_bindings, _e_config_bindings_wheel_edd); /**/
940 E_CONFIG_LIST(D, T, acpi_bindings, _e_config_bindings_acpi_edd); /**/ 957 E_CONFIG_LIST(D, T, acpi_bindings, _e_config_bindings_acpi_edd); /**/
958 E_CONFIG_LIST(D, T, swipe_bindings, _e_config_bindings_swipe_edd); /**/
941 959
942 e_config_load(); 960 e_config_load();
943 961
@@ -2258,6 +2276,16 @@ e_config_mode_changed(void)
2258} 2276}
2259 2277
2260E_API void 2278E_API void
2279e_config_binding_swipe_free(E_Config_Binding_Swipe *eba)
2280{
2281 if (!eba) return;
2282 eina_stringshare_del(eba->action);
2283 eina_stringshare_del(eba->params);
2284 free(eba);
2285}
2286
2287
2288E_API void
2261e_config_binding_acpi_free(E_Config_Binding_Acpi *eba) 2289e_config_binding_acpi_free(E_Config_Binding_Acpi *eba)
2262{ 2290{
2263 if (!eba) return; 2291 if (!eba) return;
diff --git a/src/bin/e_config.h b/src/bin/e_config.h
index deae01d31..3b1c304ca 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;
10typedef struct _E_Config_Binding_Signal E_Config_Binding_Signal; 10typedef struct _E_Config_Binding_Signal E_Config_Binding_Signal;
11typedef struct _E_Config_Binding_Wheel E_Config_Binding_Wheel; 11typedef struct _E_Config_Binding_Wheel E_Config_Binding_Wheel;
12typedef struct _E_Config_Binding_Acpi E_Config_Binding_Acpi; 12typedef struct _E_Config_Binding_Acpi E_Config_Binding_Acpi;
13typedef struct _E_Config_Binding_Swipe E_Config_Binding_Swipe;
13typedef struct _E_Config_Desktop_Background E_Config_Desktop_Background; 14typedef struct _E_Config_Desktop_Background E_Config_Desktop_Background;
14typedef struct _E_Config_Desklock_Background E_Config_Desklock_Background; 15typedef struct _E_Config_Desklock_Background E_Config_Desklock_Background;
15typedef struct _E_Config_Desktop_Name E_Config_Desktop_Name; 16typedef struct _E_Config_Desktop_Name E_Config_Desktop_Name;
@@ -87,6 +88,7 @@ struct _E_Config
87 Eina_List *signal_bindings; // GUI 88 Eina_List *signal_bindings; // GUI
88 Eina_List *wheel_bindings; // GUI 89 Eina_List *wheel_bindings; // GUI
89 Eina_List *acpi_bindings; // GUI 90 Eina_List *acpi_bindings; // GUI
91 Eina_List *swipe_bindings; // GUI
90 92
91 Eina_List *path_append_data; // GUI 93 Eina_List *path_append_data; // GUI
92 Eina_List *path_append_images; // GUI 94 Eina_List *path_append_images; // GUI
@@ -452,6 +454,7 @@ struct E_Config_Bindings
452 Eina_List *signal_bindings; // GUI 454 Eina_List *signal_bindings; // GUI
453 Eina_List *wheel_bindings; // GUI 455 Eina_List *wheel_bindings; // GUI
454 Eina_List *acpi_bindings; // GUI 456 Eina_List *acpi_bindings; // GUI
457 Eina_List *swipe_bindings;
455}; 458};
456 459
457struct _E_Config_Desklock_Background 460struct _E_Config_Desklock_Background
@@ -542,6 +545,14 @@ struct _E_Config_Binding_Acpi
542 const char *action, *params; 545 const char *action, *params;
543}; 546};
544 547
548struct _E_Config_Binding_Swipe
549{
550 int context;
551 unsigned int fingers;
552 double direction, length, error;
553 const char *action, *params;
554};
555
545struct _E_Config_Desktop_Background 556struct _E_Config_Desktop_Background
546{ 557{
547 int zone; 558 int zone;
@@ -675,6 +686,7 @@ E_API void e_config_binding_mouse_free(E_Config_Binding_Mouse *ebm);
675E_API void e_config_binding_edge_free(E_Config_Binding_Edge *ebe); 686E_API void e_config_binding_edge_free(E_Config_Binding_Edge *ebe);
676E_API void e_config_binding_key_free(E_Config_Binding_Key *ebk); 687E_API void e_config_binding_key_free(E_Config_Binding_Key *ebk);
677E_API void e_config_binding_acpi_free(E_Config_Binding_Acpi *eba); 688E_API void e_config_binding_acpi_free(E_Config_Binding_Acpi *eba);
689E_API void e_config_binding_swipe_free(E_Config_Binding_Swipe *eba);
678 690
679extern E_API E_Config *e_config; 691extern E_API E_Config *e_config;
680extern E_API E_Config_Bindings *e_bindings; 692extern 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 000000000..7c47aaa92
--- /dev/null
+++ b/src/modules/conf_bindings/e_int_config_swipebindings.c
@@ -0,0 +1,978 @@
1#include "e.h"
2
3#define TEXT_NO_PARAMS _("<None>")
4
5struct _E_Config_Dialog_Data
6{
7 Evas *evas;
8 struct
9 {
10 Eina_List *swipe;
11 } binding;
12 struct
13 {
14 const char *binding, *action;
15 char *params;
16 const char *cur;
17 int button;
18 int cur_act;
19 const char *swipe;
20 const char *source;
21
22 E_Dialog *dia;
23 double degree;
24 double error;
25 double length;
26 unsigned int fingers;
27 } locals;
28 struct
29 {
30 Evas_Object *o_add, *o_del, *o_del_all;
31 Evas_Object *o_binding_list, *o_action_list;
32 Evas_Object *o_params, *o_selector;
33 } gui;
34
35 const char *params;
36
37 int fullscreen_flip;
38 int multiscreen_flip;
39
40 E_Config_Dialog *cfd;
41};
42
43static E_Config_Binding_Swipe *
44_swipe_binding_copy(E_Config_Binding_Swipe *bi)
45{
46 E_Config_Binding_Swipe *bi2;
47 if (!bi) return NULL;
48
49 bi2 = E_NEW(E_Config_Binding_Swipe, 1);
50 bi2->context = bi->context;
51 bi2->direction = bi->direction;
52 bi2->length = bi->length;
53 bi2->fingers = bi->fingers;
54 bi2->error = bi->error;
55 bi2->action = bi->action;
56 bi2->params = bi->params;
57 return bi2;
58}
59
60static void
61_swipe_binding_free(E_Config_Binding_Swipe *bi)
62{
63 if (!bi) return;
64 eina_stringshare_del(bi->action);
65 eina_stringshare_del(bi->params);
66 free(bi);
67}
68
69
70static void
71_auto_apply_changes(E_Config_Dialog_Data *cfdata)
72{
73 int n, g, a, ok;
74 E_Config_Binding_Swipe *bi;
75 E_Action_Group *actg;
76 E_Action_Description *actd;
77
78 if ((!cfdata->locals.cur) || (!cfdata->locals.cur[0]) ||
79 (!cfdata->locals.action) || (!cfdata->locals.action[0])) return;
80
81 if (sscanf(cfdata->locals.cur, "s%d", &n) != 1)
82 return;
83 if (sscanf(cfdata->locals.action, "%d %d", &g, &a) != 2)
84 return;
85
86 bi = eina_list_nth(cfdata->binding.swipe, n);
87 if (!bi) return;
88
89 actg = eina_list_nth(e_action_groups_get(), g);
90 if (!actg) return;
91 actd = eina_list_nth(actg->acts, a);
92 if (!actd) return;
93
94 eina_stringshare_del(bi->action);
95 bi->action = NULL;
96
97 if (actd->act_cmd) bi->action = eina_stringshare_add(actd->act_cmd);
98
99 eina_stringshare_del(bi->params);
100 bi->params = NULL;
101
102 if (actd->act_params)
103 bi->params = eina_stringshare_add(actd->act_params);
104 else
105 {
106 ok = 1;
107 if (cfdata->locals.params)
108 {
109 if (!strcmp(cfdata->locals.params, TEXT_NO_PARAMS))
110 ok = 0;
111
112 if ((actd->param_example) && (!strcmp(cfdata->locals.params, actd->param_example)))
113 ok = 0;
114 }
115 else
116 ok = 0;
117
118 if (ok)
119 bi->params = eina_stringshare_add(cfdata->locals.params);
120 }
121}
122
123static void
124_fill_data(E_Config_Dialog_Data *cfdata)
125{
126 E_Config_Binding_Swipe *bi, *bi2;
127 Eina_List *l;
128
129 cfdata->locals.params = strdup("");
130 cfdata->locals.action = eina_stringshare_add("");
131 cfdata->locals.binding = eina_stringshare_add("");
132 cfdata->locals.swipe = eina_stringshare_add("");
133 cfdata->locals.source = eina_stringshare_add("");
134 cfdata->locals.cur = NULL;
135 cfdata->locals.dia = NULL;
136 cfdata->binding.swipe = NULL;
137
138 EINA_LIST_FOREACH(e_bindings->swipe_bindings, l, bi)
139 {
140 if (!bi) continue;
141 bi2 = _swipe_binding_copy(bi);
142 cfdata->binding.swipe = eina_list_append(cfdata->binding.swipe, bi2);
143 }
144}
145
146static void *
147_create_data(E_Config_Dialog *cfd)
148{
149 E_Config_Dialog_Data *cfdata;
150
151 cfdata = E_NEW(E_Config_Dialog_Data, 1);
152 cfdata->cfd = cfd;
153 _fill_data(cfdata);
154
155 return cfdata;
156}
157
158static void
159_free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
160{
161 E_FREE_LIST(cfdata->binding.swipe, _swipe_binding_free);
162
163 eina_stringshare_del(cfdata->locals.cur);
164 eina_stringshare_del(cfdata->params);
165 eina_stringshare_del(cfdata->locals.binding);
166 eina_stringshare_del(cfdata->locals.action);
167 eina_stringshare_del(cfdata->locals.swipe);
168 eina_stringshare_del(cfdata->locals.source);
169
170 if (cfdata->locals.dia) e_object_del(E_OBJECT(cfdata->locals.dia));
171
172 free(cfdata->locals.params);
173 E_FREE(cfdata);
174}
175
176
177static void
178_update_action_params(E_Config_Dialog_Data *cfdata)
179{
180 int g, a, b;
181 E_Action_Group *actg;
182 E_Action_Description *actd;
183 E_Config_Binding_Swipe *bi;
184 const char *action, *params;
185
186#define SIGNAL_EXAMPLE_PARAMS \
187 if ((!actd->param_example) || (!actd->param_example[0])) \
188 e_widget_entry_text_set(cfdata->gui.o_params, TEXT_NO_PARAMS); \
189 else \
190 e_widget_entry_text_set(cfdata->gui.o_params, actd->param_example)
191
192 if ((!cfdata->locals.action) || (!cfdata->locals.action[0]))
193 {
194 e_widget_disabled_set(cfdata->gui.o_params, 1);
195 e_widget_entry_clear(cfdata->gui.o_params);
196 return;
197 }
198 if (sscanf(cfdata->locals.action, "%d %d", &g, &a) != 2)
199 return;
200
201 actg = eina_list_nth(e_action_groups_get(), g);
202 if (!actg) return;
203 actd = eina_list_nth(actg->acts, a);
204 if (!actd) return;
205
206 if (actd->act_params)
207 {
208 e_widget_disabled_set(cfdata->gui.o_params, 1);
209 e_widget_entry_text_set(cfdata->gui.o_params, actd->act_params);
210 return;
211 }
212
213 if ((!cfdata->locals.cur) || (!cfdata->locals.cur[0]))
214 {
215 e_widget_disabled_set(cfdata->gui.o_params, 1);
216 SIGNAL_EXAMPLE_PARAMS;
217 return;
218 }
219
220 if (!actd->editable)
221 e_widget_disabled_set(cfdata->gui.o_params, 1);
222 else
223 e_widget_disabled_set(cfdata->gui.o_params, 0);
224
225 if (cfdata->locals.cur[0] == 's')
226 {
227 if (sscanf(cfdata->locals.cur, "s%d", &b) != 1)
228 {
229 e_widget_disabled_set(cfdata->gui.o_params, 1);
230 SIGNAL_EXAMPLE_PARAMS;
231 return;
232 }
233
234 bi = eina_list_nth(cfdata->binding.swipe, b);
235 if (!bi)
236 {
237 e_widget_disabled_set(cfdata->gui.o_params, 1);
238 SIGNAL_EXAMPLE_PARAMS;
239 return;
240 }
241 action = bi->action;
242 params = bi->params;
243 }
244 else
245 {
246 e_widget_disabled_set(cfdata->gui.o_params, 1);
247 SIGNAL_EXAMPLE_PARAMS;
248 return;
249 }
250
251 if (action)
252 {
253 if (!strcmp(action, actd->act_cmd))
254 {
255 if ((!params) || (!params[0]))
256 SIGNAL_EXAMPLE_PARAMS;
257 else
258 e_widget_entry_text_set(cfdata->gui.o_params, params);
259 }
260 else
261 SIGNAL_EXAMPLE_PARAMS;
262 }
263 else
264 SIGNAL_EXAMPLE_PARAMS;
265}
266
267static void
268_action_change_cb(void *data)
269{
270 E_Config_Dialog_Data *cfdata;
271
272 cfdata = data;
273 _update_action_params(cfdata);
274}
275
276static int
277_swipe_binding_sort_cb(E_Config_Binding_Swipe *a, E_Config_Binding_Swipe *b)
278{
279 int finger_diff = (a->fingers == b->fingers)*-1;
280 if (!finger_diff)
281 {
282 return a->direction - b->direction;
283 }
284 return finger_diff;
285}
286
287static void
288_update_buttons(E_Config_Dialog_Data *cfdata)
289{
290 if (e_widget_ilist_count(cfdata->gui.o_binding_list))
291 e_widget_disabled_set(cfdata->gui.o_del_all, 0);
292 else
293 e_widget_disabled_set(cfdata->gui.o_del_all, 1);
294
295 if (!cfdata->locals.cur)
296 {
297 e_widget_disabled_set(cfdata->gui.o_del, 1);
298 return;
299 }
300 e_widget_disabled_set(cfdata->gui.o_del, 0);
301}
302
303
304static void
305_find_swipe_binding_action(const char *action, const char *params, int *g, int *a, int *n)
306{
307 Eina_List *l, *l2;
308 int gg = -1, aa = -1, nn = -1, found;
309 E_Action_Group *actg;
310 E_Action_Description *actd;
311
312 if (g) *g = -1;
313 if (a) *a = -1;
314 if (n) *n = -1;
315
316 found = 0;
317 for (l = e_action_groups_get(), gg = 0, nn = 0; l; l = l->next, gg++)
318 {
319 actg = l->data;
320
321 for (l2 = actg->acts, aa = 0; l2; l2 = l2->next, aa++)
322 {
323 actd = l2->data;
324 if (!strcmp((!action ? "" : action), (!actd->act_cmd ? "" : actd->act_cmd)))
325 {
326 if (!params || !params[0])
327 {
328 if ((!actd->act_params) || (!actd->act_params[0]))
329 {
330 if (g) *g = gg;
331 if (a) *a = aa;
332 if (n) *n = nn;
333 return;
334 }
335 else
336 continue;
337 }
338 else
339 {
340 if ((!actd->act_params) || (!actd->act_params[0]))
341 {
342 if (g) *g = gg;
343 if (a) *a = aa;
344 if (n) *n = nn;
345 found = 1;
346 }
347 else
348 {
349 if (!strcmp(params, actd->act_params))
350 {
351 if (g) *g = gg;
352 if (a) *a = aa;
353 if (n) *n = nn;
354 return;
355 }
356 }
357 }
358 }
359 nn++;
360 }
361 if (found) break;
362 }
363
364 if (!found)
365 {
366 if (g) *g = -1;
367 if (a) *a = -1;
368 if (n) *n = -1;
369 }
370}
371
372static void
373_update_action_list(E_Config_Dialog_Data *cfdata)
374{
375 E_Config_Binding_Swipe *bi;
376 int j = -1, i, n;
377 const char *action, *params;
378
379 if (!cfdata->locals.cur) return;
380
381 if (cfdata->locals.cur[0] == 's')
382 {
383 if (sscanf(cfdata->locals.cur, "s%d", &n) != 1)
384 return;
385
386 bi = eina_list_nth(cfdata->binding.swipe, n);
387 if (!bi)
388 {
389 e_widget_ilist_unselect(cfdata->gui.o_action_list);
390 e_widget_entry_clear(cfdata->gui.o_params);
391 e_widget_disabled_set(cfdata->gui.o_params, 1);
392 return;
393 }
394 action = bi->action;
395 params = bi->params;
396 }
397 else
398 return;
399
400 _find_swipe_binding_action(action, params, NULL, NULL, &j);
401
402 if (j >= 0)
403 {
404 for (i = 0; i < e_widget_ilist_count(cfdata->gui.o_action_list); i++)
405 {
406 if (i > j) break;
407 if (e_widget_ilist_nth_is_header(cfdata->gui.o_action_list, i)) j++;
408 }
409 }
410
411 if (j >= 0)
412 {
413 if (j == e_widget_ilist_selected_get(cfdata->gui.o_action_list))
414 _update_action_params(cfdata);
415 else
416 e_widget_ilist_selected_set(cfdata->gui.o_action_list, j);
417 }
418 else
419 {
420 e_widget_ilist_unselect(cfdata->gui.o_action_list);
421 eina_stringshare_del(cfdata->locals.action);
422 cfdata->locals.action = eina_stringshare_add("");
423 e_widget_entry_clear(cfdata->gui.o_params);
424 }
425}
426
427static void
428_binding_change_cb(void *data)
429{
430 E_Config_Dialog_Data *cfdata;
431
432 cfdata = data;
433
434 _auto_apply_changes(cfdata);
435 if (cfdata->locals.cur) eina_stringshare_del(cfdata->locals.cur);
436 cfdata->locals.cur = NULL;
437
438 if ((!cfdata->locals.binding) || (!cfdata->locals.binding[0])) return;
439
440 cfdata->locals.cur = eina_stringshare_ref(cfdata->locals.binding);
441
442 _update_buttons(cfdata);
443 _update_action_list(cfdata);
444}
445
446
447static int
448_basic_apply_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
449{
450 Eina_List *l;
451 E_Config_Binding_Swipe *bi, *bi2;
452
453 _auto_apply_changes(cfdata);
454 E_FREE_LIST(e_bindings->swipe_bindings, _swipe_binding_free);
455 EINA_LIST_FOREACH(cfdata->binding.swipe, l, bi2)
456 {
457 bi = _swipe_binding_copy(bi2);
458 e_bindings->swipe_bindings = eina_list_append(e_bindings->swipe_bindings, bi);
459 }
460 e_bindings_swipe_reset();
461
462 e_config_save_queue();
463
464 return 1;
465}
466
467static Evas_Object*
468create_visualisation(Evas *e, double direction, double error)
469{
470 Evas_Vg_Container *vg = NULL;
471 Evas_Vg_Shape *container, *shape, *viewport = NULL;
472
473 double center_x = 15, center_y = 15;
474
475 vg = evas_object_vg_add(e);
476 evas_object_vg_viewbox_set(vg, EINA_RECT(0, 0, 50, 50));
477
478 container = evas_vg_container_add(vg);
479
480 viewport = evas_vg_shape_add(container);
481 evas_vg_shape_append_rect(viewport, 0, 0, 51, 51, 0, 0);
482 evas_vg_shape_stroke_cap_set(viewport, EVAS_VG_CAP_SQUARE);
483 evas_vg_shape_stroke_color_set(viewport, 0, 0, 0, 0);
484 evas_vg_shape_stroke_width_set(viewport, 1);
485
486 shape = evas_vg_shape_add(container);
487 evas_vg_shape_append_rect(shape, 1, 1, 29, 29, 0, 0);
488 evas_vg_shape_stroke_cap_set(shape, EVAS_VG_CAP_SQUARE);
489 evas_vg_shape_stroke_color_set(shape, 100, 100, 100, 255);
490 evas_vg_shape_stroke_width_set(shape, 1);
491
492 shape = evas_vg_shape_add(container);
493 evas_vg_shape_append_line_to(shape, center_x, center_y);
494 evas_vg_shape_append_line_to(shape, center_x + cos(direction - error)*11, center_y + sin(direction - error)*11);
495 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);
496 evas_vg_shape_append_line_to(shape, center_x, center_y);
497
498 evas_vg_shape_stroke_cap_set(shape, EVAS_VG_CAP_ROUND);
499 evas_vg_shape_stroke_color_set(shape, 255, 0, 0, 255);
500 evas_vg_shape_stroke_width_set(shape, 2);
501
502 evas_object_vg_root_node_set(vg, container);
503
504 evas_object_show(vg);
505
506 return vg;
507}
508
509static void
510_update_swipe_binding_list(E_Config_Dialog_Data *cfdata)
511{
512 int i = 0;
513 char b2[64], b3[64];
514 Eina_List *l;
515 E_Config_Binding_Swipe *bi;
516 unsigned int previous_fingers = 0;
517
518 evas_event_freeze(evas_object_evas_get(cfdata->gui.o_binding_list));
519 edje_freeze();
520 e_widget_ilist_freeze(cfdata->gui.o_binding_list);
521
522 e_widget_ilist_clear(cfdata->gui.o_binding_list);
523 e_widget_ilist_go(cfdata->gui.o_binding_list);
524
525 if (cfdata->binding.swipe)
526 cfdata->binding.swipe = eina_list_sort(cfdata->binding.swipe, 0, (Eina_Compare_Cb)_swipe_binding_sort_cb);
527
528 EINA_LIST_FOREACH(cfdata->binding.swipe, l, bi)
529 {
530 Evas_Object *vis;
531
532 vis = create_visualisation(evas_object_evas_get(cfdata->gui.o_binding_list), bi->direction, bi->error);
533 if (bi->fingers != previous_fingers)
534 {
535 snprintf(b3, sizeof(b3), "%d Fingers", bi->fingers);
536 previous_fingers = bi->fingers;
537 e_widget_ilist_header_append(cfdata->gui.o_binding_list, NULL, b3);
538 }
539 snprintf(b2, sizeof(b2), "s%d", i);
540 snprintf(b3, sizeof(b3), "Length: %.2f Error: %.2f", bi->length, bi->error);
541
542 e_widget_ilist_append(cfdata->gui.o_binding_list, vis, b3, _binding_change_cb, cfdata, b2);
543 i++;
544 }
545 e_widget_ilist_go(cfdata->gui.o_binding_list);
546
547 e_widget_ilist_thaw(cfdata->gui.o_binding_list);
548 edje_thaw();
549 evas_event_thaw(evas_object_evas_get(cfdata->gui.o_binding_list));
550
551 if (eina_list_count(cfdata->binding.swipe))
552 e_widget_disabled_set(cfdata->gui.o_del_all, 0);
553 else
554 e_widget_disabled_set(cfdata->gui.o_del_all, 1);
555}
556
557static void
558_fill_actions_list(E_Config_Dialog_Data *cfdata)
559{
560 char buf[1024];
561 Eina_List *l, *l2;
562 E_Action_Group *actg;
563 E_Action_Description *actd;
564 int g, a;
565
566 evas_event_freeze(evas_object_evas_get(cfdata->gui.o_action_list));
567 edje_freeze();
568 e_widget_ilist_freeze(cfdata->gui.o_action_list);
569
570 e_widget_ilist_clear(cfdata->gui.o_action_list);
571 for (l = e_action_groups_get(), g = 0; l; l = l->next, g++)
572 {
573 actg = l->data;
574
575 if (!actg->acts) continue;
576
577 e_widget_ilist_header_append(cfdata->gui.o_action_list, NULL, _(actg->act_grp));
578
579 for (l2 = actg->acts, a = 0; l2; l2 = l2->next, a++)
580 {
581 actd = l2->data;
582
583 snprintf(buf, sizeof(buf), "%d %d", g, a);
584 e_widget_ilist_append(cfdata->gui.o_action_list, NULL, _(actd->act_name),
585 _action_change_cb, cfdata, buf);
586 }
587 }
588 e_widget_ilist_go(cfdata->gui.o_action_list);
589 e_widget_ilist_thaw(cfdata->gui.o_action_list);
590 edje_thaw();
591 evas_event_thaw(evas_object_evas_get(cfdata->gui.o_action_list));
592}
593
594static void
595_flush_binding_swipe(E_Config_Dialog_Data *cfdata)
596{
597 E_Config_Binding_Swipe *bi;
598
599 bi = E_NEW(E_Config_Binding_Swipe, 1);
600 bi->context = E_BINDING_CONTEXT_NONE;
601 bi->length = cfdata->locals.length;
602 bi->direction = cfdata->locals.degree;
603 bi->error = cfdata->locals.error;
604 bi->fingers = cfdata->locals.fingers;
605
606 cfdata->binding.swipe = eina_list_append(cfdata->binding.swipe, bi);
607 _update_swipe_binding_list(cfdata);
608}
609
610static void
611_swipe_add_cb_ok(void *data, E_Dialog *dia)
612{
613 E_Config_Dialog_Data *cfdata = data;
614
615 _flush_binding_swipe(cfdata);
616
617 e_object_del(E_OBJECT(dia));
618}
619
620static void
621_swipe_add_cb_cancel(void *data EINA_UNUSED, E_Dialog *dia)
622{
623 e_object_del(E_OBJECT(dia));
624}
625
626static void
627_swipe_add_del(void *data)
628{
629 E_Dialog *dia = data;
630 E_Config_Dialog_Data *cfdata;
631
632 if (!dia->data) return;
633 cfdata = dia->data;
634 cfdata->locals.dia = NULL;
635}
636
637static void
638_double_getter(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
639{
640 double *container = data;
641 double tmp = elm_spinner_value_get(obj);
642 *container = tmp;
643}
644
645static void
646_int_getter(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
647{
648 unsigned int *container = data;
649 double tmp = elm_spinner_value_get(obj);
650 *container = tmp;
651}
652
653static void
654_swipe_add_show(E_Config_Dialog_Data *cfdata)
655{
656 Evas_Object *o, *obg, *ol, *entry;
657 Evas *evas;
658 int w, h;
659
660 if (cfdata->locals.dia) return;
661
662 cfdata->locals.dia = e_dialog_new(cfdata->cfd->dia->win, "E", "_swipebind_new_dialog");
663 e_dialog_resizable_set(cfdata->locals.dia, 1);
664 e_dialog_title_set(cfdata->locals.dia, _("Add Swipe Binding"));
665 e_dialog_icon_set(cfdata->locals.dia, "enlightenment/swipes", 48);
666 e_dialog_button_add(cfdata->locals.dia, _("OK"), NULL, _swipe_add_cb_ok, cfdata);
667 e_dialog_button_add(cfdata->locals.dia, _("Cancel"), NULL, _swipe_add_cb_cancel, cfdata);
668 e_object_del_attach_func_set(E_OBJECT(cfdata->locals.dia), _swipe_add_del);
669 cfdata->locals.dia->data = cfdata;
670 elm_win_center(cfdata->locals.dia->win, 1, 1);
671
672 evas = evas_object_evas_get(cfdata->locals.dia->win);
673 obg = e_widget_list_add(evas, 1, 0);
674
675 ol = e_widget_framelist_add(evas, _("Direction:"), 0);
676 entry = o = elm_spinner_add(cfdata->locals.dia->win);
677 evas_object_smart_callback_add(o, "changed", _double_getter, &cfdata->locals.degree);
678 elm_spinner_min_max_set(o, 0, 2*M_PI);
679 elm_spinner_label_format_set(o, "%f");
680 elm_spinner_step_set(o, 0.1);
681 elm_spinner_editable_set(o, EINA_TRUE);
682 e_widget_framelist_object_append(ol, o);
683 e_widget_list_object_append(obg, ol, 1, 0, 0.5);
684
685 ol = e_widget_framelist_add(evas, _("Error:"), 0);
686 entry = o = elm_spinner_add(cfdata->locals.dia->win);
687 evas_object_smart_callback_add(o, "changed", _double_getter, &cfdata->locals.error);
688 elm_spinner_min_max_set(o, 0, 2*M_PI);
689 elm_spinner_label_format_set(o, "%f");
690 elm_spinner_step_set(o, 0.1);
691 elm_spinner_editable_set(o, EINA_TRUE);
692 e_widget_framelist_object_append(ol, o);
693 e_widget_list_object_append(obg, ol, 1, 0, 0.5);
694
695 ol = e_widget_framelist_add(evas, _("Length:"), 0);
696 entry = o = elm_spinner_add(cfdata->locals.dia->win);
697 evas_object_smart_callback_add(o, "changed", _double_getter, &cfdata->locals.length);
698 elm_spinner_min_max_set(o, 0, 200);
699 elm_spinner_step_set(o, 5);
700 elm_spinner_editable_set(o, EINA_TRUE);
701 e_widget_framelist_object_append(ol, o);
702 e_widget_list_object_append(obg, ol, 1, 0, 0.5);
703
704 cfdata->locals.fingers = 3;
705 ol = e_widget_framelist_add(evas, _("Fingers:"), 0);
706 entry = o = elm_spinner_add(cfdata->locals.dia->win);
707 evas_object_smart_callback_add(o, "changed", _int_getter, &cfdata->locals.fingers);
708 elm_spinner_min_max_set(o, 3, 10);
709 elm_spinner_value_set(o, 3.0);
710 elm_spinner_editable_set(o, EINA_TRUE);
711 e_widget_framelist_object_append(ol, o);
712 e_widget_list_object_append(obg, ol, 1, 0, 0.5);
713
714 e_widget_size_min_get(obg, &w, &h);
715 e_dialog_content_set(cfdata->locals.dia, obg, MAX(w, 200), MAX(h, 100));
716
717 e_dialog_show(cfdata->locals.dia);
718 e_widget_focus_set(entry, 1);
719}
720
721static void
722_add_swipe_binding_cb(void *data, void *data2 EINA_UNUSED)
723{
724 E_Config_Dialog_Data *cfdata = data;
725
726 _auto_apply_changes(cfdata);
727 _swipe_add_show(cfdata);
728}
729
730static void
731_update_swipe_cb(void *data, Eina_Bool end, double direction, double length, double error, unsigned int fingers)
732{
733 E_Config_Dialog_Data *cfdata = data;
734
735 if (end)
736 {
737 e_object_del(E_OBJECT(cfdata->locals.dia));
738 cfdata->locals.dia = NULL;
739 cfdata->locals.degree = direction;
740 cfdata->locals.length = length;
741 cfdata->locals.error = error;
742 cfdata->locals.fingers = fingers;
743 _flush_binding_swipe(cfdata);
744 e_bindings_swipe_live_update_hook_set(NULL, NULL);
745 }
746 else
747 {
748 char text_buf[1000];
749 Evas_Object *vis;
750
751 vis = create_visualisation(evas_object_evas_get(cfdata->locals.dia->win), direction, error);
752 evas_object_size_hint_align_set(vis, 0.0, 0.5);
753 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);
754 e_dialog_text_set(cfdata->locals.dia, text_buf);
755 elm_object_part_content_set(cfdata->locals.dia->bg_object, "e.swallow.icon", vis);
756 evas_object_size_hint_min_set(vis, 30 * e_scale, 30 * e_scale);
757 elm_layout_signal_emit(cfdata->locals.dia->bg_object, "e,state,icon", "e");
758 elm_layout_signal_emit(cfdata->locals.dia->bg_object, "e,icon,enabled", "e");
759 }
760}
761
762static void
763_add_swipe_binding_by_sample_cb(void *data, void *data2 EINA_UNUSED)
764{
765 E_Config_Dialog_Data *cfdata = data;
766
767 cfdata->locals.dia = e_dialog_new(cfdata->cfd->dia->win, "E", "_swipe_recognition");
768 e_dialog_title_set(cfdata->locals.dia, "Swipe recognition");
769 e_dialog_text_set(cfdata->locals.dia, "Do your swipe gesture.<br>");
770 elm_win_center(cfdata->locals.dia->win, 1, 1);
771 elm_win_borderless_set(cfdata->locals.dia->win, 1);
772 e_dialog_resizable_set(cfdata->locals.dia, 0);
773 e_dialog_show(cfdata->locals.dia);
774 evas_object_layer_set(e_win_client_get(cfdata->locals.dia->win)->frame, E_LAYER_CLIENT_PRIO);
775
776 e_bindings_swipe_live_update_hook_set(_update_swipe_cb, data);
777}
778
779static void
780_delete_swipe_binding_cb(void *data, void *data2 EINA_UNUSED)
781{
782 Eina_List *l = NULL;
783 int sel, n;
784 E_Config_Dialog_Data *cfdata;
785
786 cfdata = data;
787
788 sel = e_widget_ilist_selected_get(cfdata->gui.o_binding_list);
789 if (cfdata->locals.binding[0] == 's')
790 {
791 if (sscanf(cfdata->locals.binding, "s%d", &n) != 1)
792 return;
793
794 l = eina_list_nth_list(cfdata->binding.swipe, n);
795
796 if (l)
797 {
798 _swipe_binding_free(eina_list_data_get(l));
799 cfdata->binding.swipe = eina_list_remove_list(cfdata->binding.swipe, l);
800 }
801 }
802
803 _update_swipe_binding_list(cfdata);
804
805 if (sel >= e_widget_ilist_count(cfdata->gui.o_binding_list))
806 sel = e_widget_ilist_count(cfdata->gui.o_binding_list) - 1;
807
808 eina_stringshare_del(cfdata->locals.cur);
809 cfdata->locals.cur = NULL;
810
811 e_widget_ilist_selected_set(cfdata->gui.o_binding_list, sel);
812 if (sel < 0)
813 {
814 e_widget_ilist_unselect(cfdata->gui.o_action_list);
815 e_widget_entry_clear(cfdata->gui.o_params);
816 e_widget_disabled_set(cfdata->gui.o_params, 1);
817 _update_buttons(cfdata);
818 }
819}
820
821
822static void
823_delete_all_swipe_binding_cb(void *data, void *data2 EINA_UNUSED)
824{
825 E_Config_Binding_Swipe *bi;
826 E_Config_Dialog_Data *cfdata;
827
828 cfdata = data;
829
830 EINA_LIST_FREE(cfdata->binding.swipe, bi)
831 _swipe_binding_free(bi);
832
833 eina_stringshare_del(cfdata->locals.cur);
834 cfdata->locals.cur = NULL;
835
836 e_widget_ilist_clear(cfdata->gui.o_binding_list);
837 e_widget_ilist_go(cfdata->gui.o_binding_list);
838 e_widget_ilist_unselect(cfdata->gui.o_action_list);
839 e_widget_entry_clear(cfdata->gui.o_params);
840 e_widget_disabled_set(cfdata->gui.o_params, 1);
841
842 _update_buttons(cfdata);
843}
844
845
846static void
847_restore_swipe_binding_defaults_cb(void *data, void *data2 EINA_UNUSED)
848{
849 E_Config_Bindings *ecb;
850 Eina_Stringshare *prof;
851 E_Config_Dialog_Data *cfdata = data;
852
853 ecb = e_config_domain_system_load("e_bindings", e_config_descriptor_find("E_Config_Bindings"));
854 if (!ecb)
855 {
856 const char *type;
857
858 prof = eina_stringshare_ref(e_config_profile_get());
859 switch (e_config->config_type)
860 {
861 case E_CONFIG_PROFILE_TYPE_DESKTOP:
862 type = "standard";
863 break;
864 case E_CONFIG_PROFILE_TYPE_MOBILE:
865 type = "mobile";
866 break;
867 //case E_CONFIG_PROFILE_TYPE_TABLET: FIXME - not used
868 default:
869 type = "default";
870 break;
871 }
872 e_config_profile_set(type);
873 ecb = e_config_domain_system_load("e_bindings", e_config_descriptor_find("E_Config_Bindings"));
874 e_config_profile_set(prof);
875 eina_stringshare_del(prof);
876 }
877 if (!ecb) return;
878 E_FREE_LIST(cfdata->binding.swipe, e_config_binding_swipe_free);
879 cfdata->binding.swipe = ecb->swipe_bindings, ecb->swipe_bindings = NULL;
880 e_config_bindings_free(ecb);
881
882 eina_stringshare_del(cfdata->locals.cur);
883 cfdata->locals.cur = NULL;
884
885 _update_swipe_binding_list(cfdata);
886 _update_buttons(cfdata);
887
888 e_widget_ilist_unselect(cfdata->gui.o_action_list);
889 e_widget_entry_clear(cfdata->gui.o_params);
890 e_widget_disabled_set(cfdata->gui.o_params, 1);
891}
892
893static Evas_Object *
894_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata)
895{
896 Evas_Object *o, *ol, *ot, *of, *ob;
897
898 cfdata->evas = evas;
899 o = e_widget_list_add(evas, 0, 0);
900 ol = e_widget_list_add(evas, 0, 1);
901
902 of = e_widget_frametable_add(evas, _("Swipe Bindings"), 0);
903 ob = e_widget_ilist_add(evas, 32, 32, &(cfdata->locals.binding));
904 cfdata->gui.o_binding_list = ob;
905 e_widget_size_min_set(ob, 200, 160);
906 e_widget_frametable_object_append(of, ob, 0, 0, 2, 1, 1, 1, 1, 1);
907
908 ob = e_widget_button_add(evas, _("Add"), "list-add", _add_swipe_binding_by_sample_cb, cfdata, NULL);
909 e_widget_frametable_object_append(of, ob, 0, 1, 1, 1, 1, 0, 1, 0);
910
911 ob = e_widget_button_add(evas, _("Add by props"), "list-add", _add_swipe_binding_cb, cfdata, NULL);
912 cfdata->gui.o_add = ob;
913 e_widget_frametable_object_append(of, ob, 0, 2, 1, 1, 1, 0, 1, 0);
914
915 ob = e_widget_button_add(evas, _("Delete"), "list-remove", _delete_swipe_binding_cb, cfdata, NULL);
916 cfdata->gui.o_del = ob;
917 e_widget_disabled_set(ob, 1);
918 e_widget_frametable_object_append(of, ob, 1, 1, 1, 1, 1, 0, 1, 0);
919 ob = e_widget_button_add(evas, _("Delete All"), "edit-clear", _delete_all_swipe_binding_cb, cfdata, NULL);
920 cfdata->gui.o_del_all = ob;
921 e_widget_disabled_set(ob, 1);
922 e_widget_frametable_object_append(of, ob, 1, 2, 1, 1, 1, 0, 1, 0);
923 ob = e_widget_button_add(evas, _("Restore Default Bindings"), "enlightenment", _restore_swipe_binding_defaults_cb, cfdata, NULL);
924 e_widget_frametable_object_append(of, ob, 0, 3, 2, 1, 1, 0, 1, 0);
925 e_widget_list_object_append(ol, of, 1, 1, 0.5);
926
927 ot = e_widget_table_add(e_win_evas_win_get(evas), 0);
928 of = e_widget_framelist_add(evas, _("Action"), 0);
929 ob = e_widget_ilist_add(evas, 24, 24, &(cfdata->locals.action));
930 cfdata->gui.o_action_list = ob;
931 e_widget_size_min_set(ob, 200, 240);
932 e_widget_framelist_object_append(of, ob);
933 e_widget_table_object_append(ot, of, 0, 0, 1, 1, 1, 1, 1, 1);
934
935 of = e_widget_framelist_add(evas, _("Action Params"), 0);
936 ob = e_widget_entry_add(cfd->dia->win, &(cfdata->locals.params), NULL, NULL, NULL);
937 cfdata->gui.o_params = ob;
938 e_widget_disabled_set(ob, 1);
939 e_widget_framelist_object_append(of, ob);
940 e_widget_table_object_append(ot, of, 0, 3, 1, 1, 1, 1, 1, 0);
941 e_widget_list_object_append(ol, ot, 1, 1, 0.5);
942
943 e_widget_list_object_append(o, ol, 1, 1, 0.5);
944
945 _update_swipe_binding_list(cfdata);
946 _fill_actions_list(cfdata);
947
948 e_dialog_resizable_set(cfd->dia, 1);
949 return o;
950}
951
952
953E_Config_Dialog *
954e_int_config_swipebindings(Evas_Object *parent EINA_UNUSED, const char *params)
955{
956 E_Config_Dialog *cfd;
957 E_Config_Dialog_View *v;
958
959 if (e_config_dialog_find("E", "keyboard_and_mouse/swipe_bindings")) return NULL;
960 v = E_NEW(E_Config_Dialog_View, 1);
961
962 v->create_cfdata = _create_data;
963 v->free_cfdata = _free_data;
964 v->basic.apply_cfdata = _basic_apply_data;
965 v->basic.create_widgets = _basic_create_widgets;
966 v->override_auto_apply = 1;
967
968 cfd = e_config_dialog_new(NULL, _("Swipe Bindings Settings"), "E",
969 "keyboard_and_mouse/swipe_bindings",
970 "enlightenment/swipes", 0, v, NULL);
971 if ((params) && (params[0]))
972 {
973 cfd->cfdata->params = eina_stringshare_add(params);
974// _add_swipe_binding_cb(cfd->cfdata, NULL);
975 }
976
977 return cfd;
978}
diff --git a/src/modules/conf_bindings/e_mod_main.c b/src/modules/conf_bindings/e_mod_main.c
index 97f0a46b7..8800faed8 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)
33 _("Edge Bindings"), NULL, 33 _("Edge Bindings"), NULL,
34 "preferences-desktop-edge-bindings", 34 "preferences-desktop-edge-bindings",
35 e_int_config_edgebindings); 35 e_int_config_edgebindings);
36 e_configure_registry_item_add("keyboard_and_mouse/swipe_bindings", 10,
37 _("Swipe Bindings"), NULL,
38 "preferences-desktop-swipe-bindings",
39 e_int_config_swipebindings);
36 40
37 e_configure_registry_category_add("advanced", 80, _("Advanced"), NULL, "preferences-advanced"); 41 e_configure_registry_category_add("advanced", 80, _("Advanced"), NULL, "preferences-advanced");
38 e_configure_registry_item_add("advanced/signal_bindings", 10, 42 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 d33fab98d..cc99913a3 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
6E_Config_Dialog *e_int_config_mousebindings(Evas_Object *parent, const char *params EINA_UNUSED); 6E_Config_Dialog *e_int_config_mousebindings(Evas_Object *parent, const char *params EINA_UNUSED);
7E_Config_Dialog *e_int_config_edgebindings(Evas_Object *parent, const char *params EINA_UNUSED); 7E_Config_Dialog *e_int_config_edgebindings(Evas_Object *parent, const char *params EINA_UNUSED);
8E_Config_Dialog *e_int_config_signalbindings(Evas_Object *parent, const char *params); 8E_Config_Dialog *e_int_config_signalbindings(Evas_Object *parent, const char *params);
9 9E_Config_Dialog *e_int_config_swipebindings(Evas_Object *parent EINA_UNUSED, const char *params);
10/** 10/**
11 * @addtogroup Optional_Conf 11 * @addtogroup Optional_Conf
12 * @{ 12 * @{
diff --git a/src/modules/conf_bindings/meson.build b/src/modules/conf_bindings/meson.build
index aec7492fd..ee1adad55 100644
--- a/src/modules/conf_bindings/meson.build
+++ b/src/modules/conf_bindings/meson.build
@@ -5,6 +5,7 @@ src = files(
5 'e_int_config_keybindings.c', 5 'e_int_config_keybindings.c',
6 'e_int_config_mousebindings.c', 6 'e_int_config_mousebindings.c',
7 'e_int_config_signalbindings.c', 7 'e_int_config_signalbindings.c',
8 'e_int_config_swipebindings.c',
8 'e_mod_main.h' 9 'e_mod_main.h'
9) 10)
10 11
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 000000000..2ebbebecc
--- /dev/null
+++ b/src/modules/gesture_recognition/e_mod_main.c
@@ -0,0 +1,287 @@
1#include <e.h>
2#include <Eina.h>
3#include <libinput.h>
4#include <grp.h>
5#include <sys/types.h>
6#include <pwd.h>
7
8E_API E_Module_Api e_modapi =
9 {
10 E_MODULE_API_VERSION,
11 "Gesture Recognition"
12 };
13
14static struct libinput *gesture_recognition_ctx;
15static Ecore_Fd_Handler *fd_listener;
16
17static int open_restricted(const char *path, int flags, void *user_data EINA_UNUSED)
18{
19 int fd = open(path, flags);
20 return fd < 0 ? -errno : fd;
21}
22
23static void close_restricted(int fd, void *user_data EINA_UNUSED)
24{
25 close(fd);
26}
27
28static const struct libinput_interface interface = {
29 .open_restricted = open_restricted,
30 .close_restricted = close_restricted,
31};
32
33static void
34_find_all_touch_input_devices(const char *path, struct libinput *li)
35{
36 Eina_File_Direct_Info *info;
37 Eina_Iterator *input_devies = eina_file_direct_ls(path);
38
39 EINA_ITERATOR_FOREACH(input_devies, info)
40 {
41 struct libinput_device *dev = libinput_path_add_device(li, info->path);
42
43 if (!dev) continue;
44
45 if (!libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_GESTURE))
46 {
47 libinput_path_remove_device(dev);
48 }
49 }
50}
51
52static Eina_Hash *active_gestures;
53
54typedef struct {
55 Eina_Vector2 pos;
56 unsigned int fingers;
57 struct {
58 Evas_Object *visuals, *win;
59 } visuals;
60} Swipe_Stats;
61
62
63static Swipe_Stats*
64_find_swipe_gesture_recognizition(struct libinput_device *dev)
65{
66 Swipe_Stats *stats = eina_hash_find(active_gestures, dev);
67
68 return stats;
69}
70
71static Swipe_Stats*
72_start_swipe_gesture_recognizition(struct libinput_device *dev)
73{
74 Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev);
75
76 if (stats)
77 eina_hash_del_by_key(active_gestures, dev);
78
79 stats = calloc(1, sizeof(Swipe_Stats));
80 EINA_SAFETY_ON_NULL_RETURN_VAL(stats, NULL);
81
82 if (e_bindings_swipe_available())
83 {
84 stats->visuals.win = elm_notify_add(e_comp->elm);
85 elm_notify_align_set(stats->visuals.win, 0.5, 0.5);
86 elm_object_tree_focus_allow_set(stats->visuals.win, EINA_FALSE);
87 evas_object_layer_set(stats->visuals.win, E_LAYER_CLIENT_PRIO);
88 evas_object_show(stats->visuals.win);
89
90 stats->visuals.visuals = elm_progressbar_add(stats->visuals.win);
91 elm_object_text_set(stats->visuals.visuals, "Progress of visuals");
92 evas_object_size_hint_min_set(stats->visuals.visuals, 300, 50);
93 evas_object_show(stats->visuals.visuals);
94 elm_object_content_set(stats->visuals.win, stats->visuals.visuals);
95 }
96
97
98 eina_hash_add(active_gestures, dev, stats);
99
100 return stats;
101}
102
103static void
104_end_swipe_gesture_recognizition(struct libinput_device *dev)
105{
106 eina_hash_del_by_key(active_gestures, dev);
107}
108
109static double
110_config_angle(Eina_Vector2 pos)
111{
112 double res = atan(pos.y/pos.x);
113
114 if (res < 0) res += M_PI;
115 if (pos.y < 0) res += M_PI;
116 return res;
117}
118
119static Eina_Bool
120_cb_input_dispatch(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
121{
122 struct libinput *li = data;
123 struct libinput_event *event;
124
125 if (libinput_dispatch(li) != 0)
126 printf("Failed to dispatch libinput events");
127
128 while((event = libinput_get_event(li)))
129 {
130 E_Bindings_Swipe_Live_Update live_update = e_bindings_swipe_live_update_hook_get();
131
132 enum libinput_event_type type = libinput_event_get_type(event);
133 struct libinput_device *dev = libinput_event_get_device(event);
134 if (type == LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN)
135 {
136 struct libinput_event_gesture *gesture = libinput_event_get_gesture_event(event);
137
138 Swipe_Stats *stats = _start_swipe_gesture_recognizition(dev);
139 stats->fingers = libinput_event_gesture_get_finger_count(gesture);
140 stats->pos.x = stats->pos.y = 0;
141 }
142 else if (type == LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE)
143 {
144 struct libinput_event_gesture *gesture = libinput_event_get_gesture_event(event);
145 Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev);
146
147 stats->pos.x += libinput_event_gesture_get_dx(gesture);
148 stats->pos.y += libinput_event_gesture_get_dy(gesture);
149 if (live_update)
150 {
151 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);
152 }
153 else if (stats->visuals.win)
154 {
155 Eina_Inarray *res = e_bindings_swipe_find_candidates(E_BINDING_CONTEXT_NONE, _config_angle (stats->pos), eina_vector2_length_get(&stats->pos), stats->fingers);
156 E_Binding_Swipe_Candidate *itr;
157 double total = 0.0f;
158 unsigned int len = 0;
159
160 EINA_INARRAY_FOREACH(res, itr)
161 {
162 total += itr->acceptance;
163 len ++;
164 }
165
166 if (len > 0)
167 {
168 char text_buffer[1000];
169
170 snprintf(text_buffer, sizeof(text_buffer), "%d gestures possible", len);
171 elm_progressbar_value_set(stats->visuals.visuals, total/len);
172 elm_object_text_set(stats->visuals.visuals, text_buffer);
173 }
174 else
175 {
176 elm_progressbar_value_set(stats->visuals.visuals, 0.0f);
177 elm_object_text_set(stats->visuals.visuals, "No gesture found");
178 }
179
180 eina_inarray_free(res);
181 }
182 }
183 else if (type == LIBINPUT_EVENT_GESTURE_SWIPE_END)
184 {
185 Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev);
186
187 if (live_update)
188 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);
189 else
190 e_bindings_swipe_handle(E_BINDING_CONTEXT_NONE, NULL, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), stats->fingers);
191
192 _end_swipe_gesture_recognizition(dev);
193 }
194 libinput_event_destroy(event);
195 }
196 return EINA_TRUE;
197}
198
199static void
200_setup_libinput(void)
201{
202 gesture_recognition_ctx = libinput_path_create_context(&interface, NULL);
203
204 _find_all_touch_input_devices("/dev/input/", gesture_recognition_ctx);
205
206 fd_listener = ecore_main_fd_handler_add(libinput_get_fd(gesture_recognition_ctx), ECORE_FD_READ, _cb_input_dispatch, gesture_recognition_ctx, NULL, NULL);
207}
208
209
210static void
211_tear_down_libinput(void)
212{
213 ecore_main_fd_handler_del(fd_listener);
214 libinput_unref(gesture_recognition_ctx);
215}
216
217static Eina_Bool
218_user_part_of_input(void)
219{
220 uid_t user = getuid();
221 struct passwd *user_pw = getpwuid(user);
222 gid_t *gids = NULL;
223 int number_of_groups = 0;
224 struct group *input_group = getgrnam("input");
225
226 EINA_SAFETY_ON_NULL_RETURN_VAL(user_pw, EINA_FALSE);
227 EINA_SAFETY_ON_NULL_RETURN_VAL(input_group, EINA_FALSE);
228
229 if (getgrouplist(user_pw->pw_name, getgid(), NULL, &number_of_groups) != -1)
230 {
231 ERR("Failed to enumerate groups of user");
232 return EINA_FALSE;
233 }
234 number_of_groups ++;
235 gids = alloca((number_of_groups) * sizeof(gid_t));
236 if (getgrouplist(user_pw->pw_name, getgid(), gids, &number_of_groups) == -1)
237 {
238 ERR("Failed to get groups of user");
239 return EINA_FALSE;
240 }
241
242 for (int i = 0; i < number_of_groups; ++i)
243 {
244 if (gids[i] == input_group->gr_gid)
245 return EINA_TRUE;
246 }
247 return EINA_FALSE;
248}
249
250static void
251_stats_free(void *ptr)
252{
253 Swipe_Stats *stats = ptr;
254
255 evas_object_del(stats->visuals.win);
256 free(stats);
257}
258
259E_API int
260e_modapi_init(E_Module *m EINA_UNUSED)
261{
262 if (!_user_part_of_input())
263 {
264 e_module_dialog_show(m, "Gesture Recognition", "Your user is not part of the input group, libinput cannot be used.");
265
266 return 0;
267 }
268 active_gestures = eina_hash_pointer_new(_stats_free);
269 _setup_libinput();
270
271 return 1;
272}
273
274E_API int
275e_modapi_shutdown(E_Module *m EINA_UNUSED)
276{
277 _tear_down_libinput();
278 return 1;
279}
280
281E_API int
282e_modapi_save(E_Module *m EINA_UNUSED)
283{
284
285 return 1;
286}
287
diff --git a/src/modules/gesture_recognition/meson.build b/src/modules/gesture_recognition/meson.build
new file mode 100644
index 000000000..5a007ee8e
--- /dev/null
+++ b/src/modules/gesture_recognition/meson.build
@@ -0,0 +1,5 @@
1src = files(
2 'e_mod_main.c',
3)
4deps += [dependency('libinput')]
5desktop_only = true
diff --git a/src/modules/gesture_recognition/module.desktop b/src/modules/gesture_recognition/module.desktop
new file mode 100644
index 000000000..8136450cb
--- /dev/null
+++ b/src/modules/gesture_recognition/module.desktop
@@ -0,0 +1,6 @@
1[Desktop Entry]
2Type=Link
3Name=Gesture Recognition
4Comment=Gesture recognition using libinput
5Icon=e-module-start
6X-Enlightenment-ModuleType=utils
diff --git a/src/modules/meson.build b/src/modules/meson.build
index 21a8f1a23..735cd0e77 100644
--- a/src/modules/meson.build
+++ b/src/modules/meson.build
@@ -45,6 +45,7 @@ mods = [
45 'tiling', 45 'tiling',
46 'packagekit', 46 'packagekit',
47 'vkbd', 47 'vkbd',
48 'gesture_recognition',
48# modules have a custom binary as well 49# modules have a custom binary as well
49 'battery', 50 'battery',
50 'cpufreq', 51 'cpufreq',