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