2 #include "e_mod_main_wl.h"
5 E_KeyrouterPtr krt = NULL;
6 E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Keyrouter Module of Window Manager" };
8 static E_Keyrouter_Config_Data *_e_keyrouter_init(E_Module *m);
9 static void _e_keyrouter_init_handlers(void);
10 static void _e_keyrouter_deinit_handlers(void);
12 static Eina_Bool _e_keyrouter_query_tizen_key_table(void);
13 static int _e_keyrouter_wl_array_length(const struct wl_array *array);
15 static Eina_Bool _e_keyrouter_client_cb_stack(void *data, int type, void *event);
16 static Eina_Bool _e_keyrouter_client_cb_remove(void *data, int type, void *event);
17 static void _e_keyrouter_wl_client_cb_destroy(struct wl_listener *l, void *data);
18 static void _e_keyrouter_wl_surface_cb_destroy(struct wl_listener *l, void *data);
20 static int _e_keyrouter_keygrab_set(struct wl_client *client, struct wl_resource *surface, uint32_t key, uint32_t mode);
21 static int _e_keyrouter_keygrab_unset(struct wl_client *client, struct wl_resource *surface, uint32_t key);
24 static void _e_keyrouter_util_cynara_log(const char *func_name, int err);
25 static Eina_Bool _e_keyrouter_util_do_privilege_check(struct wl_client *client, int socket_fd, uint32_t mode, uint32_t keycode);
27 #define E_KEYROUTER_CYNARA_ERROR_CHECK_GOTO(func_name, ret, label) \
30 if (EINA_UNLIKELY(CYNARA_API_SUCCESS != ret)) \
32 _e_keyrouter_util_cynara_log(func_name, ret); \
40 _e_keyrouter_keygrab_set(struct wl_client *client, struct wl_resource *surface, uint32_t key, uint32_t mode)
45 if (EINA_FALSE == _e_keyrouter_util_do_privilege_check(client,
46 wl_client_get_fd(client), mode, key))
48 return TIZEN_KEYROUTER_ERROR_NO_PERMISSION;
54 /* Regarding topmost mode, a client must request to grab a key with a valid surface. */
55 if (mode == TIZEN_KEYROUTER_MODE_TOPMOST)
57 KLWRN("Invalid surface for TOPMOST grab mode ! (key=%d, mode=%d)\n", key, mode);
59 return TIZEN_KEYROUTER_ERROR_INVALID_SURFACE;
63 /* Check the given key range */
64 if (krt->max_tizen_hwkeys < key)
66 KLWRN("Invalid range of key ! (keycode:%d)\n", key);
67 return TIZEN_KEYROUTER_ERROR_INVALID_KEY;
70 /* Check whether the key can be grabbed or not !
71 * Only key listed in Tizen key layout file can be grabbed. */
72 if (0 == krt->HardKeys[key].keycode)
74 KLWRN("Invalid key ! Disabled to grab ! (keycode:%d)\n", key);
75 return TIZEN_KEYROUTER_ERROR_INVALID_KEY;
78 /* Check whether the mode is valid or not */
79 if (TIZEN_KEYROUTER_MODE_REGISTERED < mode)
81 KLWRN("Invalid range of mode ! (mode:%d)\n", mode);
82 return TIZEN_KEYROUTER_ERROR_INVALID_MODE;
85 /* Check whether the request key can be grabbed or not */
86 res = e_keyrouter_set_keygrab_in_list(surface, client, key, mode);
92 _e_keyrouter_keygrab_unset(struct wl_client *client, struct wl_resource *surface, uint32_t key)
94 /* Ungrab top position grabs first. This grab mode do not need privilege */
96 e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_TOPMOST);
98 e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_TOPMOST);
101 if (EINA_FALSE == _e_keyrouter_util_do_privilege_check(client,
102 wl_client_get_fd(client), TIZEN_KEYROUTER_MODE_NONE, key))
104 return TIZEN_KEYROUTER_ERROR_NONE;
111 e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_EXCLUSIVE);
113 /* OVERRIDABLE_EXCLUSIVE grab */
114 e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE);
117 e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_SHARED);
119 return TIZEN_KEYROUTER_ERROR_NONE;
123 e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_EXCLUSIVE);
125 /* OVERRIDABLE_EXCLUSIVE grab */
126 e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE);
129 e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_SHARED);
131 /* REGISTERED grab */
132 e_keyrouter_unset_keyregister(surface, client, key);
134 return TIZEN_KEYROUTER_ERROR_NONE;
137 /* tizen_keyrouter_set_keygrab request handler */
139 _e_keyrouter_cb_keygrab_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key, uint32_t mode)
143 TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_set);
144 KLINF("Key grab request (client: %p, surface: %p, pid: %d, key:%d, mode:%d)\n", client, surface, e_keyrouter_util_get_pid(client, surface), key, mode);
146 res = _e_keyrouter_keygrab_set(client, surface, key, mode);
149 tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, res);
152 /* tizen_keyrouter unset_keygrab request handler */
154 _e_keyrouter_cb_keygrab_unset(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key)
158 TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_unset);
159 KLINF("Key ungrab request (client: %p, surface: %p, pid: %d, key:%d)\n", client, surface, e_keyrouter_util_get_pid(client, surface), key);
161 res = _e_keyrouter_keygrab_unset(client, surface, key);
164 tizen_keyrouter_send_keygrab_notify(resource, surface, key, TIZEN_KEYROUTER_MODE_NONE, res);
167 /* tizen_keyrouter get_keygrab_status request handler */
169 _e_keyrouter_cb_get_keygrab_status(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key)
175 int mode = TIZEN_KEYROUTER_MODE_NONE;
177 TRACE_INPUT_BEGIN(_e_keyrouter_cb_get_keygrab_status);
178 mode = e_keyrouter_find_key_in_list(surface, client, key);
181 tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, TIZEN_KEYROUTER_ERROR_NONE);
185 _e_keyrouter_cb_keygrab_set_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, struct wl_array *grab_list)
187 struct wl_array grab_result_list = {0,};
188 E_Keyrouter_Grab_Result *grab_result = NULL;
189 E_Keyrouter_Grab_Request *grab_request = NULL;
190 int res = TIZEN_KEYROUTER_ERROR_NONE;
192 TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_set_list);
194 wl_array_init(&grab_result_list);
196 if (0 != (_e_keyrouter_wl_array_length(grab_list) % 2))
198 /* FIX ME: Which way is effectively to notify invalid pair to client */
199 KLWRN("Invalid keycode and grab mode pair. Check arguments in a list\n");
200 grab_result = wl_array_add(&grab_result_list, sizeof(E_Keyrouter_Grab_Result));
201 grab_result->request_data.key = 0;
202 grab_result->request_data.mode = 0;
203 grab_result->err = TIZEN_KEYROUTER_ERROR_INVALID_ARRAY;
207 wl_array_for_each(grab_request, grab_list)
209 KLINF("Grab request using list (client: %p, surface: %p, pid: %d, key: %d, mode: %d]\n", client, surface, e_keyrouter_util_get_pid(client, surface), grab_request->key, grab_request->mode);
210 res = _e_keyrouter_keygrab_set(client, surface, grab_request->key, grab_request->mode);
211 grab_result = wl_array_add(&grab_result_list, sizeof(E_Keyrouter_Grab_Result));
214 grab_result->request_data.key = grab_request->key;
215 grab_result->request_data.mode = grab_request->mode;
216 grab_result->err = res;
222 tizen_keyrouter_send_keygrab_notify_list(resource, surface, &grab_result_list);
223 wl_array_release(&grab_result_list);
227 _e_keyrouter_cb_keygrab_unset_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, struct wl_array *ungrab_list)
229 struct wl_array grab_result_list = {0,};
230 E_Keyrouter_Grab_Result *grab_result = NULL;
231 int *ungrab_request = NULL;
232 int res = TIZEN_KEYROUTER_ERROR_NONE;
234 TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_unset_list);
236 wl_array_init(&grab_result_list);
238 wl_array_for_each(ungrab_request, ungrab_list)
240 KLINF("Ungrab request using list (client: %p, surface: %p, pid: %d, key: %d, res: %d]\n", client, surface, e_keyrouter_util_get_pid(client, surface), *ungrab_request, res);
241 res = _e_keyrouter_keygrab_unset(client, surface, *ungrab_request);
242 grab_result = wl_array_add(&grab_result_list, sizeof(E_Keyrouter_Grab_Result));
245 grab_result->request_data.key = *ungrab_request;
246 grab_result->request_data.mode = TIZEN_KEYROUTER_MODE_NONE;
247 grab_result->err = res;
252 tizen_keyrouter_send_keygrab_notify_list(resource, surface, &grab_result_list);
253 wl_array_release(&grab_result_list);
257 /* Function for registering wl_client destroy listener */
259 e_keyrouter_add_client_destroy_listener(struct wl_client *client)
261 struct wl_listener *destroy_listener = NULL;
263 struct wl_client *wc_data;
265 EINA_LIST_FOREACH(krt->grab_client_list, l, wc_data)
269 if (wc_data == client)
271 return TIZEN_KEYROUTER_ERROR_NONE;
276 destroy_listener = E_NEW(struct wl_listener, 1);
278 if (!destroy_listener)
280 KLERR("Failed to allocate memory for wl_client destroy listener !\n");
281 return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES;
284 destroy_listener->notify = _e_keyrouter_wl_client_cb_destroy;
285 wl_client_add_destroy_listener(client, destroy_listener);
286 krt->grab_client_list = eina_list_append(krt->grab_client_list, client);
288 return TIZEN_KEYROUTER_ERROR_NONE;
291 /* Function for registering wl_surface destroy listener */
293 e_keyrouter_add_surface_destroy_listener(struct wl_resource *surface)
295 struct wl_listener *destroy_listener = NULL;
297 struct wl_resource *surface_data;
299 EINA_LIST_FOREACH(krt->grab_surface_list, l, surface_data)
303 if (surface_data == surface)
305 return TIZEN_KEYROUTER_ERROR_NONE;
310 destroy_listener = E_NEW(struct wl_listener, 1);
312 if (!destroy_listener)
314 KLERR("Failed to allocate memory for wl_surface destroy listener !\n");
315 return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES;
318 destroy_listener->notify = _e_keyrouter_wl_surface_cb_destroy;
319 wl_resource_add_destroy_listener(surface, destroy_listener);
320 krt->grab_surface_list = eina_list_append(krt->grab_surface_list, surface);
322 return TIZEN_KEYROUTER_ERROR_NONE;
326 static const struct tizen_keyrouter_interface _e_keyrouter_implementation = {
327 _e_keyrouter_cb_keygrab_set,
328 _e_keyrouter_cb_keygrab_unset,
329 _e_keyrouter_cb_get_keygrab_status,
330 _e_keyrouter_cb_keygrab_set_list,
331 _e_keyrouter_cb_keygrab_unset_list
334 /* tizen_keyrouter global object destroy function */
336 _e_keyrouter_cb_destory(struct wl_resource *resource)
338 /* TODO : destroy resources if exist */
341 /* tizen_keyrouter global object bind function */
343 _e_keyrouter_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
345 E_KeyrouterPtr krt_instance = data;
346 struct wl_resource *resource;
348 resource = wl_resource_create(client, &tizen_keyrouter_interface, MIN(version, 1), id);
350 KLDBG("wl_resource_create(...,&tizen_keyrouter_interface,...)\n");
354 KLERR("Failed to create resource ! (version :%d, id:%d)\n", version, id);
355 wl_client_post_no_memory(client);
359 wl_resource_set_implementation(resource, &_e_keyrouter_implementation, krt_instance, _e_keyrouter_cb_destory);
363 _event_filter(void *data, void *loop_data EINA_UNUSED, int type, void *event)
369 /* Filter only for key down/up event */
370 if (ECORE_EVENT_KEY_DOWN == type || ECORE_EVENT_KEY_UP == type)
372 return e_keyrouter_process_key_event(event, type);
378 static E_Keyrouter_Config_Data *
379 _e_keyrouter_init(E_Module *m)
381 E_Keyrouter_Config_Data *kconfig = NULL;
382 krt = E_NEW(E_Keyrouter, 1);
383 Eina_Bool res = EINA_FALSE;
386 TRACE_INPUT_BEGIN(_e_keyrouter_init);
390 KLERR("Failed to allocate memory for krt !\n");
397 KLERR("Failed to initialize keyrouter module ! (e_comp == NULL)\n");
401 kconfig = E_NEW(E_Keyrouter_Config_Data, 1);
402 EINA_SAFETY_ON_NULL_GOTO(kconfig, err);
406 e_keyrouter_conf_init(kconfig);
407 EINA_SAFETY_ON_NULL_GOTO(kconfig->conf, err);
410 /* Get keyname and keycode pair from Tizen Key Layout file */
411 res = _e_keyrouter_query_tizen_key_table();
412 EINA_SAFETY_ON_FALSE_GOTO(res, err);
414 /* Add filtering mechanism */
415 krt->ef_handler = ecore_event_filter_add(NULL, _event_filter, NULL, NULL);
416 _e_keyrouter_init_handlers();
418 krt->global = wl_global_create(e_comp_wl->wl.disp, &tizen_keyrouter_interface, 1, krt, _e_keyrouter_cb_bind);
421 KLERR("Failed to create global !\n");
426 ret = cynara_initialize(&krt->p_cynara, NULL);
427 if (EINA_UNLIKELY(CYNARA_API_SUCCESS != ret))
429 _e_keyrouter_util_cynara_log("cynara_initialize", ret);
430 krt->p_cynara = NULL;
440 e_keyrouter_conf_deinit(kconfig);
443 _e_keyrouter_deinit_handlers();
444 if (krt && krt->ef_handler) ecore_event_filter_del(krt->ef_handler);
445 if (krt) E_FREE(krt);
452 e_modapi_init(E_Module *m)
454 return _e_keyrouter_init(m);
458 e_modapi_shutdown(E_Module *m)
460 E_Keyrouter_Config_Data *kconfig = m->data;
461 e_keyrouter_conf_deinit(kconfig);
462 _e_keyrouter_deinit_handlers();
465 if (krt->p_cynara) cynara_finish(krt->p_cynara);
467 /* TODO: free allocated memory */
473 e_modapi_save(E_Module *m)
475 /* Save something to be kept */
476 E_Keyrouter_Config_Data *kconfig = m->data;
477 e_config_domain_save("module.keyrouter",
484 /* Function for getting keyname/keycode information from a key layout file */
486 _e_keyrouter_query_tizen_key_table(void)
488 E_Keyrouter_Conf_Edd *kconf = krt->conf->conf;
490 E_Keyrouter_Tizen_HWKey *data;
492 /* TODO: Make struct in HardKeys to pointer.
493 If a key is defined, allocate memory to pointer,
494 that makes to save unnecessary memory */
495 krt->HardKeys = E_NEW(E_Keyrouter_Grabbed_Key, kconf->max_keycode + 1);
496 EINA_SAFETY_ON_NULL_RETURN_VAL(krt->HardKeys, EINA_FALSE);
498 krt->numTizenHWKeys = kconf->num_keycode;
499 krt->max_tizen_hwkeys = kconf->max_keycode;
501 EINA_LIST_FOREACH(kconf->KeyList, l, data)
505 if (0 > data->keycode || krt->max_tizen_hwkeys < data->keycode)
507 KLWRN("Given keycode(%d) is invalid. It must be bigger than zero, smaller than the maximum value(%d) or equal to it.\n", data->keycode, kconf->max_keycode);
511 krt->HardKeys[data->keycode].keycode = data->keycode;
512 krt->HardKeys[data->keycode].keyname = (char *)eina_stringshare_add(data->name);
513 krt->HardKeys[data->keycode].no_privcheck = data->no_privcheck ? EINA_TRUE : EINA_FALSE;
520 _e_keyrouter_wl_array_length(const struct wl_array *array)
525 wl_array_for_each(data, array)
534 _e_keyrouter_deinit_handlers(void)
536 Ecore_Event_Handler *h = NULL;
538 if (!krt || !krt->handlers) return;
540 EINA_LIST_FREE(krt->handlers, h)
541 ecore_event_handler_del(h);
545 _e_keyrouter_init_handlers(void)
547 E_LIST_HANDLER_APPEND(krt->handlers, E_EVENT_CLIENT_STACK, _e_keyrouter_client_cb_stack, NULL);
548 E_LIST_HANDLER_APPEND(krt->handlers, E_EVENT_CLIENT_REMOVE, _e_keyrouter_client_cb_remove, NULL);
552 _e_keyrouter_client_cb_stack(void *data, int type, void *event)
554 E_Event_Client *ev = event;
555 E_Client *ec = ev->ec;
563 //KLDBG("ec: %p, visibile: %d, focused: %d, take_focus: %d, want_focus: %d, bordername: %s, input_only: %d\n",
564 // ec, ec->visible, ec->focused, ec->take_focus, ec->want_focus, ec->bordername, ec->input_only);
566 krt->isWindowStackChanged = EINA_TRUE;
567 e_keyrouter_clear_registered_window();
569 return ECORE_CALLBACK_PASS_ON;
573 _e_keyrouter_client_cb_remove(void *data, int type, void *event)
575 E_Event_Client *ev = event;
576 E_Client *ec = ev->ec;
583 /* FIXME: Remove this callback or do something others.
584 * It was moved to _e_keyrouter_wl_surface_cb_destroy() where it had here.
587 return ECORE_CALLBACK_PASS_ON;
591 _e_keyrouter_wl_client_cb_destroy(struct wl_listener *l, void *data)
593 struct wl_client *client = data;
595 KLDBG("Listener(%p) called: wl_client: %p is died\n", l, client);
596 e_keyrouter_remove_client_from_list(NULL, client);
601 krt->grab_client_list = eina_list_remove(krt->grab_client_list, client);
605 _e_keyrouter_wl_surface_cb_destroy(struct wl_listener *l, void *data)
607 struct wl_resource *surface = data;
609 KLDBG("Listener(%p) called: surface: %p is died\n", l, surface);
610 e_keyrouter_remove_client_from_list(surface, NULL);
615 krt->grab_surface_list = eina_list_remove(krt->grab_surface_list, surface);
620 _e_keyrouter_util_cynara_log(const char *func_name, int err)
622 #define CYNARA_BUFSIZE 128
623 char buf[CYNARA_BUFSIZE] = "\0";
626 ret = cynara_strerror(err, buf, CYNARA_BUFSIZE);
627 if (ret != CYNARA_API_SUCCESS)
629 KLWRN("Failed to cynara_strerror: %d (error log about %s: %d)\n", ret, func_name, err);
632 KLWRN("%s is failed: %s\n", func_name, buf);
636 _e_keyrouter_util_do_privilege_check(struct wl_client *client, int socket_fd, uint32_t mode, uint32_t keycode)
638 int ret, pid, retry_cnt=0;
639 char *clientSmack=NULL, *uid=NULL, *client_session=NULL;
640 Eina_Bool res = EINA_FALSE;
642 struct wl_client *wc_data;
643 static Eina_Bool retried = EINA_FALSE;
645 /* Top position grab is always allowed. This mode do not need privilege.*/
646 if (mode == TIZEN_KEYROUTER_MODE_TOPMOST)
649 if (krt->HardKeys[keycode].no_privcheck == EINA_TRUE)
652 /* If initialize cynara is failed, allow keygrabs regardless of the previlege permition. */
653 if (krt->p_cynara == NULL)
655 if (retried == EINA_FALSE)
658 for(retry_cnt = 0; retry_cnt < 5; retry_cnt++)
660 KLDBG("Retry cynara initialize: %d\n", retry_cnt+1);
661 ret = cynara_initialize(&krt->p_cynara, NULL);
662 if (EINA_UNLIKELY(CYNARA_API_SUCCESS != ret))
664 _e_keyrouter_util_cynara_log("cynara_initialize", ret);
665 krt->p_cynara = NULL;
669 KLDBG("Success cynara initialize to try %d times\n", retry_cnt+1);
677 EINA_LIST_FOREACH(krt->grab_client_list, l, wc_data)
679 if (wc_data == client)
686 ret = cynara_creds_socket_get_client(socket_fd, CLIENT_METHOD_SMACK, &clientSmack);
687 E_KEYROUTER_CYNARA_ERROR_CHECK_GOTO("cynara_creds_socket_get_client", ret, finish);
689 ret = cynara_creds_socket_get_user(socket_fd, USER_METHOD_UID, &uid);
690 E_KEYROUTER_CYNARA_ERROR_CHECK_GOTO("cynara_creds_socket_get_user", ret, finish);
692 ret = cynara_creds_socket_get_pid(socket_fd, &pid);
693 E_KEYROUTER_CYNARA_ERROR_CHECK_GOTO("cynara_creds_socket_get_pid", ret, finish);
695 client_session = cynara_session_from_pid(pid);
697 ret = cynara_check(krt->p_cynara, clientSmack, client_session, uid, "http://tizen.org/privilege/keygrab");
698 if (CYNARA_API_ACCESS_ALLOWED == ret)
701 e_keyrouter_add_client_destroy_listener(client);
705 E_FREE(client_session);