Use wl_signal_emit_mutable()
[platform/core/uifw/libds-tizen.git] / src / keyrouter / keyrouter.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <stdbool.h>
5 #include <unistd.h>
6
7 #include <libds/log.h>
8 #include "libds-tizen/keyrouter.h"
9
10 #include "util.h"
11 #include "security.h"
12 #include "keyrouter.h"
13
14 #define TIZEN_KEYROUTER_VERSION 2
15 #define TIZEN_KEYROUTER_PRIVILEGE "http://tizen.org/privilege/keygrab"
16
17 static void keyrouter_bind(struct wl_client *wl_client, void *data,
18         uint32_t version, uint32_t id);
19 static void keyrouter_handle_display_destroy(struct wl_listener *listener,
20         void *data);
21 static void keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter);
22 static void create_keyrouter_client(struct ds_tizen_keyrouter *keyrouter,
23         struct wl_client *wl_client, uint32_t version, uint32_t id);
24 static void destroy_keyrouter_client(struct keyrouter_client *client);
25 static bool
26 keyrouter_client_check_privilege(struct keyrouter_client *client, uint32_t mode,
27         uint32_t keycode);
28 static int keyrouter_client_grab_key(struct keyrouter_client *client, int mode,
29         int keycode);
30 static int keyrouter_client_ungrab_key(struct keyrouter_client *client,
31         int keycode);
32 static void
33 keyrouter_seat_broadcast_key(struct ds_seat *seat, struct wl_array *keyroutes,
34         bool with_focus, uint32_t time_msec, uint32_t keycode, uint32_t state);
35
36 WL_EXPORT struct ds_tizen_keyrouter *
37 ds_tizen_keyrouter_create(struct wl_display *display)
38 {
39     struct ds_tizen_keyrouter *keyrouter;
40
41     keyrouter = calloc(1, sizeof *keyrouter);
42     if (!keyrouter) {
43         return NULL;
44     }
45
46     keyrouter->global = wl_global_create(display, &tizen_keyrouter_interface,
47             TIZEN_KEYROUTER_VERSION, keyrouter, keyrouter_bind);
48     if (!keyrouter->global) {
49         free(keyrouter);
50         return NULL;
51     }
52
53     keyrouter_grab_init(&keyrouter->keygrab);
54
55     wl_list_init(&keyrouter->clients);
56
57     wl_signal_init(&keyrouter->events.destroy);
58
59     keyrouter->display_destroy.notify = keyrouter_handle_display_destroy;
60     wl_display_add_destroy_listener(display, &keyrouter->display_destroy);
61
62     keyrouter_options_set(keyrouter);
63
64     keyrouter->security_initialized = tizen_security_init();
65     if (!keyrouter->security_initialized) {
66         ds_inf("tizen_security_init() is not sucessful. "
67                 "keyrouter works without security.");
68     }
69
70     ds_inf("Global created: ds_tizen_keyrouter(%p)", keyrouter);
71
72     return keyrouter;
73 }
74
75 WL_EXPORT void
76 ds_tizen_keyrouter_add_destroy_listener(struct ds_tizen_keyrouter *keyrouter,
77         struct wl_listener *listener)
78 {
79     wl_signal_add(&keyrouter->events.destroy, listener);
80 }
81
82 WL_EXPORT void
83 ds_tizen_keyrouter_notify_key(struct ds_tizen_keyrouter *keyrouter,
84         struct ds_seat *seat, struct ds_surface *topmost_surface,
85         uint32_t time_msec, uint32_t keycode, uint32_t state)
86 {
87     struct wl_client *topmost_wl_client = NULL;
88     struct wl_resource *surface_resource;
89     struct wl_array keyroutes;
90     enum keyroute_mode mode;
91
92     wl_array_init(&keyroutes);
93
94     if (topmost_surface) {
95         surface_resource = ds_surface_get_wl_resource(topmost_surface);
96         if (surface_resource) {
97             topmost_wl_client = wl_resource_get_client(
98                     ds_surface_get_wl_resource(topmost_surface));
99         }
100     }
101
102     mode = keyrouter_grab_get_keyroutes(&keyrouter->keygrab, keycode + 8,
103             topmost_wl_client, &keyroutes);
104
105     if (mode == KEYROUTE_MODE_EXCLUSIVE) {
106         keyrouter_seat_broadcast_key(seat, &keyroutes, true,
107                 time_msec, keycode, state);
108
109         goto end;
110     }
111
112     if (mode == KEYROUTE_MODE_SHARED) {
113         keyrouter_seat_broadcast_key(seat, &keyroutes, false,
114                 time_msec, keycode, state);
115     }
116
117     ds_seat_keyboard_notify_key(seat, time_msec, keycode, state);
118
119 end:
120     wl_array_release(&keyroutes);
121 }
122
123 static void
124 keyrouter_client_handle_set_keygrab(struct wl_client *wl_client,
125         struct wl_resource *resource, struct wl_resource *surface,
126         uint32_t key, uint32_t mode)
127 {
128     struct keyrouter_client *client;
129     int err;
130
131     client = wl_resource_get_user_data(resource);
132     err = keyrouter_client_grab_key(client, mode, key);
133     tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, err);
134 }
135
136 static void
137 keyrouter_client_handle_unset_keygrab(struct wl_client *wl_client,
138         struct wl_resource *resource, struct wl_resource *surface,  uint32_t key)
139 {
140     struct keyrouter_client *client;
141     int err;
142
143     client = wl_resource_get_user_data(resource);
144     err = keyrouter_client_ungrab_key(client, key);
145     tizen_keyrouter_send_keygrab_notify(resource, surface, key,
146             TIZEN_KEYROUTER_MODE_NONE, err);
147 }
148
149 static void
150 keyrouter_client_handle_get_keygrab_status(struct wl_client *wl_client,
151         struct wl_resource *resource, struct wl_resource *surface, uint32_t key)
152 {
153     tizen_keyrouter_send_keygrab_notify(resource, surface, key,
154             TIZEN_KEYROUTER_MODE_NONE, TIZEN_KEYROUTER_ERROR_NO_PERMISSION);
155 }
156
157 static int
158 keyrouter_get_array_length(const struct wl_array *array)
159 {
160     int *data;
161     int count = 0;
162
163     wl_array_for_each(data, array)
164         count++;
165
166     return count;
167 }
168
169 static void
170 keyrouter_client_handle_set_keygrab_list(struct wl_client *wl_client,
171         struct wl_resource *resource, struct wl_resource *surface, struct wl_array *grab_list)
172 {
173     struct keyrouter_client *client;
174     struct ds_tizen_grab_data *grab_data;
175     struct wl_array *return_list;
176
177     if ((keyrouter_get_array_length(grab_list) % 3) != 0) {
178         ds_err("Invalid keycode and grab mode pair. Check arguments in a list.");
179         tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL);
180         return;
181     }
182
183     client = wl_resource_get_user_data(resource);
184
185     wl_array_for_each(grab_data, grab_list) {
186         grab_data->err = keyrouter_client_grab_key(client, grab_data->mode,
187                 grab_data->key);
188     }
189
190     return_list = grab_list;
191
192     tizen_keyrouter_send_keygrab_notify_list(resource, surface, return_list);
193 }
194
195 static void
196 keyrouter_client_handle_unset_keygrab_list(struct wl_client *wl_client,
197         struct wl_resource *resource, struct wl_resource *surface,
198         struct wl_array *ungrab_list)
199 {
200     struct keyrouter_client *client;
201     struct wl_array *return_list;
202     struct ds_tizen_ungrab_data *ungrab_data;
203
204     if ((keyrouter_get_array_length(ungrab_list) % 3) != 0) {
205         ds_err("Invalid keycode and grab mode pair. Check arguments in a list.");
206         tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL);
207         return;
208     }
209
210     client = wl_resource_get_user_data(resource);
211
212     wl_array_for_each(ungrab_data, ungrab_list) {
213         ungrab_data->err = keyrouter_client_ungrab_key(client,
214                 ungrab_data->key);
215     }
216
217     return_list = ungrab_list;
218
219     tizen_keyrouter_send_keygrab_notify_list(resource, surface, return_list);
220 }
221
222 static void
223 keyrouter_client_handle_get_keygrab_list(struct wl_client *wl_client,
224         struct wl_resource *resource, struct wl_resource *surface)
225 {
226     tizen_keyrouter_send_getgrab_notify_list(resource, surface, NULL);
227 }
228
229 static void
230 keyrouter_client_handle_set_register_none_key(struct wl_client *wl_client,
231         struct wl_resource *resource, struct wl_resource *surface,
232         uint32_t data)
233 {
234     tizen_keyrouter_send_set_register_none_key_notify(resource, NULL, 0);
235 }
236
237 static void
238 keyrouter_client_handle_get_keyregister_status(struct wl_client *wl_client,
239         struct wl_resource *resource, uint32_t key)
240 {
241     tizen_keyrouter_send_keyregister_notify(resource, (int)false);
242 }
243
244 static void
245 keyrouter_client_handle_set_input_config(struct wl_client *wl_client,
246         struct wl_resource *resource, struct wl_resource *surface,
247         uint32_t config_mode, uint32_t value)
248 {
249     tizen_keyrouter_send_set_input_config_notify(resource, (int)false);
250 }
251
252 static void
253 keyrouter_client_handle_destroy(struct wl_client *wl_client,
254         struct wl_resource *resource)
255 {
256     wl_resource_destroy(resource);
257 }
258
259 static const struct tizen_keyrouter_interface tizen_keyrouter_impl = {
260    .set_keygrab = keyrouter_client_handle_set_keygrab,
261    .unset_keygrab = keyrouter_client_handle_unset_keygrab,
262    .get_keygrab_status = keyrouter_client_handle_get_keygrab_status,
263    .set_keygrab_list = keyrouter_client_handle_set_keygrab_list,
264    .unset_keygrab_list = keyrouter_client_handle_unset_keygrab_list,
265    .get_keygrab_list = keyrouter_client_handle_get_keygrab_list,
266    .set_register_none_key = keyrouter_client_handle_set_register_none_key,
267    .get_keyregister_status = keyrouter_client_handle_get_keyregister_status,
268    .set_input_config = keyrouter_client_handle_set_input_config,
269    .destroy = keyrouter_client_handle_destroy
270 };
271
272 static void
273 keyrouter_client_handle_resource_destroy(struct wl_resource *resource)
274 {
275     struct keyrouter_client *client;
276
277     client = wl_resource_get_user_data(resource);
278     destroy_keyrouter_client(client);
279 }
280
281 static void
282 keyrouter_bind(struct wl_client *wl_client, void *data, uint32_t version,
283         uint32_t id)
284 {
285     struct ds_tizen_keyrouter *keyrouter = data;
286
287     create_keyrouter_client(keyrouter, wl_client, version, id);
288 }
289
290 static void
291 keyrouter_handle_display_destroy(struct wl_listener *listener, void *data)
292 {
293     struct ds_tizen_keyrouter *keyrouter;
294
295     keyrouter = wl_container_of(listener, keyrouter, display_destroy);
296
297     ds_inf("Global destroy: ds_tizen_keyrouter(%p)", keyrouter);
298
299     wl_signal_emit_mutable(&keyrouter->events.destroy, keyrouter);
300
301     if (keyrouter->security_initialized)
302         tizen_security_finish();
303
304     free(keyrouter->opts);
305
306     wl_list_remove(&keyrouter->display_destroy.link);
307
308     wl_global_destroy(keyrouter->global);
309
310     keyrouter_grab_finish(&keyrouter->keygrab);
311
312     free(keyrouter);
313 }
314
315 static void
316 keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter)
317 {
318     FILE *file;
319     int keycode;
320     char *ret, *tmp, *buf_ptr, buf[1024] = {0,};
321
322     keyrouter->opts = calloc(KEYROUTER_MAX_KEYS,
323             sizeof(struct keyrouter_key_options));
324     if (!keyrouter->opts) {
325         return;
326     }
327
328     file = fopen(KEYLAYOUT_DIR, "r");
329     if (!file) {
330         ds_err("Failed to open key layout file(%s): (err msg: %m)\n", KEYLAYOUT_DIR);
331         free(keyrouter->opts);
332         keyrouter->opts = NULL;
333         return;
334     }
335
336     while (!feof(file)) {
337         ret = fgets(buf, 1024, file);
338         if (!ret) continue;
339
340         tmp = strtok_r(buf, " ", &buf_ptr);
341         tmp = strtok_r(NULL, " ", &buf_ptr);
342         if (!tmp) continue;
343         keycode = atoi(tmp);
344         if ((0 >= keycode) || (keycode >= KEYROUTER_MAX_KEYS)) {
345             ds_err("Currently %d key is invalid to support\n", keycode);
346             continue;
347         }
348
349         keyrouter->opts[keycode].enabled = true;
350
351         if (strstr(buf_ptr, "no_priv") != NULL) {
352             keyrouter->opts[keycode].no_privilege = true;
353         }
354     }
355
356     fclose(file);
357 }
358
359 static void
360 create_keyrouter_client(struct ds_tizen_keyrouter *keyrouter,
361         struct wl_client *wl_client, uint32_t version, uint32_t id)
362 {
363     struct keyrouter_client *client;
364
365     client = calloc(1, sizeof *client);
366     if (!client) {
367         wl_client_post_no_memory(wl_client);
368         return;
369     }
370
371     client->keyrouter = keyrouter;
372     client->wl_client = wl_client;
373     client->resource = wl_resource_create(wl_client, &tizen_keyrouter_interface,
374             MIN(version, TIZEN_KEYROUTER_VERSION), id);
375     if (!client->resource) {
376         ds_err("wl_resource_create() failed. (version :%d, id:%d)",
377                 version, id);
378         free(client);
379         wl_client_post_no_memory(wl_client);
380         return;
381     }
382
383     wl_resource_set_implementation(client->resource, &tizen_keyrouter_impl,
384             client, keyrouter_client_handle_resource_destroy);
385
386     wl_list_insert(&keyrouter->clients, &client->link);
387 }
388
389 static void
390 destroy_keyrouter_client(struct keyrouter_client *client)
391 {
392     wl_list_remove(&client->link);
393     free(client);
394 }
395
396 static bool
397 keyrouter_client_check_privilege(struct keyrouter_client *client, uint32_t mode,
398         uint32_t keycode)
399 {
400     struct ds_tizen_keyrouter *keyrouter = client->keyrouter;
401     pid_t pid = 0;
402     uid_t uid = 0;
403
404     /* Top position grab is always allowed. This mode do not need privilege.*/
405     if (mode == TIZEN_KEYROUTER_MODE_TOPMOST)
406         return true;
407
408     // check no privilege option on the keycode
409     if (keyrouter->opts && keyrouter->opts[keycode].no_privilege)
410         return true;
411
412     // already checked the privilege before.
413     if (client->privileged)
414         return true;
415
416     wl_client_get_credentials(client->wl_client, &pid, &uid, NULL);
417
418     client->privileged = tizen_security_check_privilege(pid, uid,
419             TIZEN_KEYROUTER_PRIVILEGE);
420
421     return client->privileged;
422 }
423
424 static int
425 keyrouter_client_grab_key(struct keyrouter_client *client, int mode,
426         int keycode)
427 {
428     struct ds_tizen_keyrouter *keyrouter = client->keyrouter;
429
430     if (!keyrouter_client_check_privilege(client, mode, keycode))
431         return TIZEN_KEYROUTER_ERROR_NO_PERMISSION;
432
433     return keyrouter_grab_grab_key(&keyrouter->keygrab, mode, keycode,
434             client->wl_client);
435 }
436
437 static int
438 keyrouter_client_ungrab_key(struct keyrouter_client *client, int keycode)
439 {
440     struct ds_tizen_keyrouter *keyrouter = client->keyrouter;
441
442     /* ungrab TOP POSITION grab first, this grab mode is not check privilege */
443     keyrouter_grab_ungrab_key(&keyrouter->keygrab,
444         TIZEN_KEYROUTER_MODE_TOPMOST, keycode, client->wl_client);
445
446     if (!keyrouter_client_check_privilege(client, TIZEN_KEYROUTER_MODE_NONE,
447                 keycode))
448         return TIZEN_KEYROUTER_ERROR_NO_PERMISSION;
449
450     keyrouter_grab_ungrab_key(&keyrouter->keygrab,
451         TIZEN_KEYROUTER_MODE_EXCLUSIVE, keycode, client->wl_client);
452     keyrouter_grab_ungrab_key(&keyrouter->keygrab,
453         TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, keycode,
454         client->wl_client);
455     keyrouter_grab_ungrab_key(&keyrouter->keygrab,
456         TIZEN_KEYROUTER_MODE_TOPMOST, keycode, client->wl_client);
457     keyrouter_grab_ungrab_key(&keyrouter->keygrab,
458         TIZEN_KEYROUTER_MODE_SHARED, keycode, client->wl_client);
459
460     return TIZEN_KEYROUTER_ERROR_NONE;
461 }
462
463 static void
464 keyrouter_seat_broadcast_key(struct ds_seat *seat, struct wl_array *keyroutes,
465         bool with_focus, uint32_t time_msec, uint32_t keycode, uint32_t state)
466 {
467     struct ds_seat_client *seat_client, *focused_client;
468     struct wl_client **wl_client_ptr;
469
470     focused_client = ds_seat_keyboard_get_focused_client(seat);
471
472     wl_array_for_each(wl_client_ptr, keyroutes) {
473         seat_client = ds_seat_client_for_wl_client(seat, *wl_client_ptr);
474         if (!seat_client) {
475             ds_inf("Could not find ds_seat_client for given wl_client(%p)",
476                     *wl_client_ptr);
477             continue;
478         }
479
480         if (seat_client == focused_client) {
481             if (with_focus)
482                 ds_seat_keyboard_notify_key(seat, time_msec, keycode, state);
483         }
484         else {
485             ds_seat_client_send_key(seat_client, time_msec, keycode, state);
486         }
487     }
488 }