e_input: Remove eeze dependency
[platform/upstream/enlightenment.git] / src / bin / e_input.c
1 #include "e_input_intern.h"
2 #include "e_input_log.h"
3 #include "e_comp_screen_intern.h"
4 #include "e_comp_wl_input_intern.h"
5 #include "e_comp_wl_intern.h"
6 #include "e_utils_intern.h"
7
8 #include <Ecore_Input_Evas.h>
9 #include <cpu-boosting.h>
10 #include <pthread.h>
11
12 static int _e_input_hooks_delete = 0;
13 static int _e_input_hooks_walking = 0;
14
15 static pid_t _e_input_thread_id = 0;
16 static pid_t _e_input_main_thread_id = 0;
17 static pthread_key_t thread_id_key = 0;
18 static pthread_once_t once_init = PTHREAD_ONCE_INIT;
19 static int _e_input_thread_error = 0;
20
21 static Eina_Inlist *_e_input_hooks[] =
22 {
23    [E_INPUT_HOOK_POINTER_WARP] = NULL,
24    [E_INPUT_HOOK_INPUT_THREAD_START] = NULL,
25 };
26
27 int _e_input_init_count;
28 int _e_input_log_dom = -1;
29
30 EINTERN int E_INPUT_EVENT_SEAT_ADD = -1;
31 EINTERN int E_EVENT_INPUT_ENABLED = -1;
32 EINTERN int E_EVENT_INPUT_DISABLED = -1;
33
34 E_API E_Input *e_input = NULL;
35
36 E_API E_Input_Hook *
37 e_input_hook_add(E_Input_Hook_Point hookpoint, E_Input_Hook_Cb func, const void *data)
38 {
39    E_Input_Hook *hook;
40
41    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_INPUT_HOOK_LAST, NULL);
42    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
43    hook = E_NEW(E_Input_Hook, 1);
44    if (!hook) return NULL;
45    hook->hookpoint = hookpoint;
46    hook->func = func;
47    hook->data = (void*)data;
48    _e_input_hooks[hookpoint] = eina_inlist_append(_e_input_hooks[hookpoint], EINA_INLIST_GET(hook));
49    return hook;
50 }
51
52 E_API void
53 e_input_hook_del(E_Input_Hook *hook)
54 {
55    EINA_SAFETY_ON_NULL_RETURN(hook);
56
57    hook->delete_me = 1;
58    if (_e_input_hooks_walking == 0)
59      {
60         _e_input_hooks[hook->hookpoint] = eina_inlist_remove(_e_input_hooks[hook->hookpoint], EINA_INLIST_GET(hook));
61         free(hook);
62      }
63    else
64      _e_input_hooks_delete++;
65 }
66
67 static void
68 _e_input_hooks_clean(void)
69 {
70    Eina_Inlist *l;
71    E_Input_Hook *hook;
72    unsigned int x;
73    for (x = 0; x < E_INPUT_HOOK_LAST; x++)
74      EINA_INLIST_FOREACH_SAFE(_e_input_hooks[x], l, hook)
75        {
76           if (!hook->delete_me) continue;
77           _e_input_hooks[x] = eina_inlist_remove(_e_input_hooks[x], EINA_INLIST_GET(hook));
78           free(hook);
79        }
80
81    _e_input_hooks_delete = 0;
82 }
83
84 void
85 _e_input_hook_call(E_Input_Hook_Point hookpoint, const char *device_name)
86 {
87    E_Input_Hook *hook;
88
89    _e_input_hooks_walking++;
90    EINA_INLIST_FOREACH(_e_input_hooks[hookpoint], hook)
91      {
92         if (hook->delete_me) continue;
93         hook->func(hook->data, device_name);
94      }
95    _e_input_hooks_walking--;
96    if ((_e_input_hooks_walking == 0) && (_e_input_hooks_delete > 0))
97      _e_input_hooks_clean();
98 }
99
100 static Eina_Bool
101 _e_input_cb_screen_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
102 {
103    Eina_List *l;
104    Eina_List *devices;
105    E_Input_Device *dev_data;
106
107    devices = (Eina_List *)e_input_devices_get();
108
109    EINA_LIST_FOREACH(devices, l, dev_data)
110      {
111         e_input_device_output_changed(dev_data);
112      }
113    return ECORE_CALLBACK_PASS_ON;
114 }
115
116 EINTERN const char *
117 e_input_base_dir_get(void)
118 {
119    return e_input->input_base_dir;
120 }
121
122 EINTERN Eina_Bool
123 e_input_thread_enabled_get(void)
124 {
125    return e_input->use_thread;
126 }
127
128 EINTERN int
129 e_input_init(Ecore_Evas *ee)
130 {
131    char *env = NULL;
132    unsigned int seat_caps = 0;
133
134    E_Input_Device *dev;
135
136    Eina_Bool use_udev_backend = EINA_FALSE;
137    Eina_Bool use_path_backend = EINA_FALSE;
138    Eina_Bool skip_udev_enumeration = EINA_FALSE;
139
140    EINA_SAFETY_ON_NULL_RETURN_VAL(ee, _e_input_init_count);
141
142    TRACE_INPUT_BEGIN(e_input_init);
143
144    if (++_e_input_init_count != 1) return _e_input_init_count;
145    if (!ecore_event_evas_init()) goto ecore_event_evas_err;
146
147    _e_input_log_dom = eina_log_domain_register("e_input", EINA_COLOR_GREEN);
148    if (!_e_input_log_dom)
149      {
150         EINA_LOG_ERR("Could not create logging domain for E_Input");
151         goto log_err;
152      }
153    eina_log_domain_level_set("e_input", EINA_LOG_LEVEL_INFO);
154
155    E_INPUT_EVENT_SEAT_ADD = ecore_event_type_new();
156    E_EVENT_INPUT_ENABLED = ecore_event_type_new();
157    E_EVENT_INPUT_DISABLED = ecore_event_type_new();
158
159    ecore_event_add(E_EVENT_INPUT_ENABLED, NULL, NULL, NULL);
160
161    ecore_evas_input_event_register_with_multi2(ee);
162
163    if (!e_input)
164      {
165         e_input = (E_Input *)calloc(1, sizeof(E_Input));
166      }
167
168    if (!e_input)
169      {
170         EINA_LOG_ERR("Failed to alloc memory for e_input\n");
171         goto log_err;
172      }
173
174    // TODO : make this variable configurable e.g. e.cfg
175    e_input->input_base_dir = eina_stringshare_add("/dev/input");
176    e_input->use_thread = EINA_FALSE;
177
178    e_input->touch_device_count = 0;
179    e_input->touch_max_count = 1;//This is going to updated when a touch device is attached.
180
181    dev = e_input_device_open();
182
183    e_input->ee = ee;
184    e_input->dev = dev;
185
186    if (!dev)
187      {
188         EINA_LOG_ERR("Failed to open device\n");
189         goto log_err;
190      }
191
192    e_input->window = ecore_evas_window_get(ee);
193    e_input_device_window_set(dev, e_input->window);
194
195    env = e_util_env_get("E_INPUT_USE_THREAD_INIT");
196
197    if (env)
198      {
199         e_input->use_thread = EINA_TRUE;
200         E_FREE(env);
201      }
202
203    env = e_util_env_get("LIBINPUT_UDEV_SKIP_INITIAL_ENUMERATION");
204    if (env)
205      {
206         skip_udev_enumeration = EINA_TRUE;
207         E_FREE(env);
208      }
209
210    env = e_util_env_get("E_INPUT_USE_LIBINPUT_UDEV_BACKEND");
211    if (env)
212      {
213         use_udev_backend = EINA_TRUE;
214         E_FREE(env);
215      }
216
217    env = e_util_env_get("E_INPUT_USE_LIBINPUT_PATH_BACKEND");
218    if (env)
219      {
220         use_path_backend = EINA_TRUE;
221         E_FREE(env);
222      }
223
224    TRACE_INPUT_BEGIN(e_input_device_input_backend_create);
225
226    /* FIXME: we need to select default backend udev or path.
227     *        Input system will not be initialized, if there are no environment is set.
228     */
229    if ((!use_udev_backend) && (!use_path_backend))
230      {
231         EINA_LOG_INFO("This system doesn't select input backend. We use udev backend defaultly\n");
232         use_udev_backend = EINA_TRUE;
233      }
234
235    if ((use_udev_backend) &&
236        (!e_input_device_input_backend_create(dev, E_INPUT_LIBINPUT_BACKEND_UDEV)))
237      {
238         EINA_LOG_ERR("Failed to create e_input_device\n");
239         TRACE_INPUT_END();
240         goto device_create_err;
241      }
242
243    if ((use_path_backend) && (!use_udev_backend || skip_udev_enumeration) &&
244        (!e_input_device_input_backend_create(dev, E_INPUT_LIBINPUT_BACKEND_PATH)))
245      {
246         EINA_LOG_ERR("Failed to create e_input_device\n");
247         TRACE_INPUT_END();
248         goto device_create_err;
249      }
250
251    TRACE_INPUT_END();
252
253    if (use_udev_backend && skip_udev_enumeration && !use_path_backend)
254      {
255         /* Enable some of keyboard, touch devices temporarily */
256         /* FIXME : get seat caps from e_input configuration or env */
257         seat_caps = E_INPUT_SEAT_KEYBOARD | E_INPUT_SEAT_TOUCH;
258         e_comp_wl_input_seat_caps_set(seat_caps);
259      }
260
261    E_LIST_HANDLER_APPEND(e_input->handlers, E_EVENT_SCREEN_CHANGE, _e_input_cb_screen_change, NULL);
262
263    TRACE_INPUT_END();
264
265    return _e_input_init_count;
266
267 device_create_err:
268    e_input_device_close(dev);
269
270 log_err:
271    if (e_input && e_input->input_base_dir)
272      {
273         eina_stringshare_del(e_input->input_base_dir);
274         e_input->input_base_dir = NULL;
275      }
276
277    ecore_event_evas_shutdown();
278
279 ecore_event_evas_err:
280
281    TRACE_INPUT_END();
282
283    return --_e_input_init_count;
284 }
285
286 EINTERN int
287 e_input_shutdown(void)
288 {
289    Ecore_Event_Handler *h = NULL;
290
291    if (_e_input_init_count < 1) return 0;
292    if (--_e_input_init_count != 0) return _e_input_init_count;
293
294    ecore_event_add(E_EVENT_INPUT_DISABLED, NULL, NULL, NULL);
295
296    E_INPUT_EVENT_SEAT_ADD = -1;
297    E_EVENT_INPUT_ENABLED = -1;
298    E_EVENT_INPUT_DISABLED = -1;
299
300    EINA_LIST_FREE(e_input->handlers, h)
301      ecore_event_handler_del(h);
302
303    if (e_input->input_base_dir)
304      eina_stringshare_del(e_input->input_base_dir);
305    e_input_device_close(e_input->dev);
306
307    free(e_input);
308
309    ecore_event_evas_shutdown();
310    ecore_event_shutdown();
311    ecore_shutdown();
312    eina_shutdown();
313
314    return _e_input_init_count;
315 }
316
317 EINTERN E_Input *
318 e_input_get()
319 {
320    if (e_input) return e_input;
321    return NULL;
322 }
323
324 EINTERN Ecore_Evas *
325 e_input_ecore_evas_get(E_Input *ei)
326 {
327    if (ei) return ei->ee;
328    return NULL;
329 }
330
331 E_API unsigned int
332 e_input_touch_max_count_get()
333 {
334    if (e_input)
335      return e_input->touch_max_count;
336    else
337      return 0;
338 }
339
340 EINTERN void
341 e_input_touch_max_count_set(unsigned int max_count)
342 {
343    if (e_input)
344      e_input->touch_max_count = max_count;
345 }
346
347 EINTERN Eina_Bool
348 e_input_relative_motion_handler_set(e_input_relative_motion_cb handler)
349 {
350    if (!e_input)
351      return EINA_FALSE;
352
353    e_input->relative_motion_handler = handler;
354    return EINA_TRUE;
355 }
356
357 EINTERN e_input_relative_motion_cb
358 e_input_relative_motion_handler_get(void)
359 {
360    if (e_input)
361      return e_input->relative_motion_handler;
362
363    return NULL;
364 }
365
366 EINTERN Eina_Bool
367 e_input_keyboard_grab_key_handler_set(e_input_keyboard_grab_key_cb handler)
368 {
369    if (!e_input)
370      return EINA_FALSE;
371
372    e_input->keyboard_grab_key_handler = handler;
373    return EINA_TRUE;
374 }
375
376 EINTERN e_input_keyboard_grab_key_cb
377 e_input_keyboard_grab_key_handler_get(void)
378 {
379    if (e_input)
380      return e_input->keyboard_grab_key_handler;
381
382    return NULL;
383 }
384
385 static void
386 _keyboard_share_key_event_flush_cb(void *data)
387 {
388    INF("flush keyboard share key events");
389    e_comp_wl_display_flush();
390 }
391
392 void
393 e_input_flush_keyboard_share_events(void)
394 {
395    ecore_main_loop_thread_safe_call_async(_keyboard_share_key_event_flush_cb, NULL);
396 }
397
398 E_API pid_t e_input_thread_id_get()
399 {
400    return _e_input_thread_id;
401 }
402
403 void
404 e_input_init_thread()
405 {
406    int ret = pthread_key_create(&thread_id_key, NULL);
407    if (ret < 0)
408      {
409         ERR("failed to create pthread_key");
410      }
411
412    _e_input_thread_error = ret;
413 }
414
415 EINTERN void e_input_thread_id_set(pid_t tid)
416 {
417    _e_input_thread_id = tid;
418
419    pthread_once(&once_init, e_input_init_thread);
420    int ret = pthread_setspecific(thread_id_key, &_e_input_thread_id);
421    if (ret < 0)
422      {
423         ERR("failed to set thread specific");
424      }
425
426    _e_input_thread_error = ret;
427 }
428
429 E_API pid_t e_input_main_thread_id_get()
430 {
431    return _e_input_main_thread_id;
432 }
433
434 EINTERN void e_input_main_thread_id_set(pid_t tid)
435 {
436    _e_input_main_thread_id = tid;
437 }
438
439 void
440 _e_input_main_thread_set_boosting()
441 {
442    if (!pthread_getspecific(thread_id_key))
443      return;
444
445    pid_t main_thread_id = e_input_main_thread_id_get();
446    if (main_thread_id <= 0)
447      {
448         ERR("Failed to get main thread id");
449         return;
450      }
451
452    TRACE_INPUT_BEGIN(_e_input_main_thread_set_boosting);
453    resource_pid_t resource;
454    resource.pid = 0;
455    resource.tid = &main_thread_id;
456    resource.tid_count = 1;
457
458    int ret = resource_set_cpu_boosting(resource, CPU_BOOSTING_LEVEL_STRONG, CPU_BOOSTING_RESET_ON_FORK, -1);
459    TRACE_INPUT_END();
460
461    if (ret != 0)
462      ERR("set_cpu_boosting failed. error %d", ret);
463 }
464
465 void
466 _e_input_main_thread_clear_boosting()
467 {
468    if (!pthread_getspecific(thread_id_key))
469      return;
470
471    pid_t main_thread_id = e_input_main_thread_id_get();
472    if (main_thread_id <= 0)
473      {
474         ERR("Failed to get main thread id");
475         return;
476      }
477
478    TRACE_INPUT_BEGIN(_e_input_main_thread_clear_boosting);
479    resource_pid_t resource;
480    resource.pid = 0;
481    resource.tid = &main_thread_id;
482    resource.tid_count = 1;
483
484    int ret = resource_clear_cpu_boosting(resource);
485    TRACE_INPUT_END();
486
487    if (ret != 0)
488      ERR("clear_cpu_boosting failed. error %d", ret);
489
490 }
491
492 EINTERN void e_input_boost_lock(GMutex *mutex)
493 {
494    if (!g_mutex_trylock(mutex))
495      {
496         _e_input_main_thread_set_boosting();
497         g_mutex_lock(mutex);
498         _e_input_main_thread_clear_boosting();
499      }
500 }
501
502 EINTERN void e_input_boost_unlock(GMutex *mutex)
503 {
504    g_mutex_unlock(mutex);
505 }