text: Rename and extend text_model key event
[platform/upstream/weston.git] / src / text-backend.c
1 /*
2  * Copyright © 2012 Openismus GmbH
3  * Copyright © 2012 Intel Corporation
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and
6  * its documentation for any purpose is hereby granted without fee, provided
7  * that the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of the copyright holders not be used in
10  * advertising or publicity pertaining to distribution of the software
11  * without specific, written prior permission.  The copyright holders make
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "compositor.h"
28 #include "text-server-protocol.h"
29 #include "input-method-server-protocol.h"
30
31 struct input_method;
32 struct input_method_context;
33 struct text_backend;
34
35 struct text_model {
36         struct wl_resource resource;
37
38         struct weston_compositor *ec;
39
40         struct wl_list input_methods;
41
42         struct wl_surface *surface;
43 };
44
45 struct text_model_factory {
46         struct wl_global *text_model_factory_global;
47         struct wl_listener destroy_listener;
48
49         struct weston_compositor *ec;
50 };
51
52 struct input_method {
53         struct wl_resource *input_method_binding;
54         struct wl_global *input_method_global;
55         struct wl_listener destroy_listener;
56
57         struct weston_seat *seat;
58         struct text_model *model;
59
60         struct wl_list link;
61
62         struct wl_listener keyboard_focus_listener;
63
64         int focus_listener_initialized;
65
66         struct input_method_context *context;
67
68         struct text_backend *text_backend;
69 };
70
71 struct input_method_context {
72         struct wl_resource resource;
73
74         struct text_model *model;
75
76         struct wl_list link;
77 };
78
79 struct text_backend {
80         struct weston_compositor *compositor;
81
82         struct {
83                 char *path;
84                 struct wl_resource *binding;
85                 struct weston_process process;
86                 struct wl_client *client;
87         } input_method;
88
89         struct wl_listener seat_created_listener;
90         struct wl_listener destroy_listener;
91 };
92
93 static void input_method_context_create(struct text_model *model,
94                                         struct input_method *input_method);
95
96 static void input_method_init_seat(struct weston_seat *seat);
97
98 static void
99 deactivate_text_model(struct text_model *text_model,
100                       struct input_method *input_method)
101 {
102         struct weston_compositor *ec = text_model->ec;
103
104         if (input_method->model == text_model) {
105                 if (input_method->context && input_method->input_method_binding)
106                         input_method_send_deactivate(input_method->input_method_binding, &input_method->context->resource);
107                 wl_list_remove(&input_method->link);
108                 input_method->model = NULL;
109                 input_method->context = NULL;
110                 wl_signal_emit(&ec->hide_input_panel_signal, ec);
111                 text_model_send_leave(&text_model->resource);
112         }
113 }
114
115 static void
116 destroy_text_model(struct wl_resource *resource)
117 {
118         struct text_model *text_model =
119                 container_of(resource, struct text_model, resource);
120         struct input_method *input_method, *next;
121
122         wl_list_for_each_safe(input_method, next, &text_model->input_methods, link)
123                 deactivate_text_model(text_model, input_method);
124
125         free(text_model);
126 }
127
128 static void
129 text_model_set_surrounding_text(struct wl_client *client,
130                                 struct wl_resource *resource,
131                                 const char *text,
132                                 uint32_t cursor,
133                                 uint32_t anchor)
134 {
135         struct text_model *text_model = resource->data;
136         struct input_method *input_method, *next;
137
138         wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
139                 if (!input_method->context)
140                         continue;
141                 input_method_context_send_surrounding_text(&input_method->context->resource,
142                                                            text,
143                                                            cursor,
144                                                            anchor);
145         }
146 }
147
148 static void
149 text_model_activate(struct wl_client *client,
150                     struct wl_resource *resource,
151                     struct wl_resource *seat,
152                     struct wl_resource *surface)
153 {
154         struct text_model *text_model = resource->data;
155         struct weston_seat *weston_seat = seat->data;
156         struct input_method *input_method = weston_seat->input_method;
157         struct text_model *old = weston_seat->input_method->model;
158         struct weston_compositor *ec = text_model->ec;
159
160         if (old == text_model)
161                 return;
162
163         if (old) {
164                 deactivate_text_model(old,
165                                       weston_seat->input_method);
166         }
167
168         input_method->model = text_model;
169         wl_list_insert(&text_model->input_methods, &input_method->link);
170         input_method_init_seat(weston_seat);
171
172         text_model->surface = surface->data;
173
174         input_method_context_create(text_model, input_method);
175
176         wl_signal_emit(&ec->show_input_panel_signal, ec);
177
178         text_model_send_enter(&text_model->resource, &text_model->surface->resource);
179 }
180
181 static void
182 text_model_deactivate(struct wl_client *client,
183                       struct wl_resource *resource,
184                       struct wl_resource *seat)
185 {
186         struct text_model *text_model = resource->data;
187         struct weston_seat *weston_seat = seat->data;
188
189         deactivate_text_model(text_model,
190                               weston_seat->input_method);
191 }
192
193 static void
194 text_model_reset(struct wl_client *client,
195                  struct wl_resource *resource)
196 {
197         struct text_model *text_model = resource->data;
198         struct input_method *input_method, *next;
199
200         wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
201                 if (!input_method->context)
202                         continue;
203                 input_method_context_send_reset(&input_method->context->resource);
204         }
205 }
206
207 static void
208 text_model_set_micro_focus(struct wl_client *client,
209                            struct wl_resource *resource,
210                            int32_t x,
211                            int32_t y,
212                            int32_t width,
213                            int32_t height)
214 {
215 }
216
217 static void
218 text_model_set_preedit(struct wl_client *client,
219                        struct wl_resource *resource)
220 {
221 }
222
223 static void
224 text_model_set_content_type(struct wl_client *client,
225                             struct wl_resource *resource)
226 {
227 }
228
229 static const struct text_model_interface text_model_implementation = {
230         text_model_set_surrounding_text,
231         text_model_activate,
232         text_model_deactivate,
233         text_model_reset,
234         text_model_set_micro_focus,
235         text_model_set_preedit,
236         text_model_set_content_type
237 };
238
239 static void text_model_factory_create_text_model(struct wl_client *client,
240                                                  struct wl_resource *resource,
241                                                  uint32_t id)
242 {
243         struct text_model_factory *text_model_factory = resource->data;
244         struct text_model *text_model;
245
246         text_model = calloc(1, sizeof *text_model);
247
248         text_model->resource.object.id = id;
249         text_model->resource.object.interface = &text_model_interface;
250         text_model->resource.object.implementation =
251                 (void (**)(void)) &text_model_implementation;
252
253         text_model->resource.data = text_model;
254         text_model->resource.destroy = destroy_text_model;
255
256         text_model->ec = text_model_factory->ec;
257
258         wl_list_init(&text_model->input_methods);
259
260         wl_client_add_resource(client, &text_model->resource);
261 };
262
263 static const struct text_model_factory_interface text_model_factory_implementation = {
264         text_model_factory_create_text_model
265 };
266
267 static void
268 bind_text_model_factory(struct wl_client *client,
269                         void *data,
270                         uint32_t version,
271                         uint32_t id)
272 {
273         struct text_model_factory *text_model_factory = data;
274
275         /* No checking for duplicate binding necessary.
276          * No events have to be sent, so we don't need the return value. */
277         wl_client_add_object(client, &text_model_factory_interface,
278                              &text_model_factory_implementation,
279                              id, text_model_factory);
280 }
281
282 static void
283 text_model_factory_notifier_destroy(struct wl_listener *listener, void *data)
284 {
285         struct text_model_factory *text_model_factory =
286                 container_of(listener, struct text_model_factory, destroy_listener);
287
288         wl_display_remove_global(text_model_factory->ec->wl_display,
289                                  text_model_factory->text_model_factory_global);
290
291         free(text_model_factory);
292 }
293
294 static void
295 text_model_factory_create(struct weston_compositor *ec)
296 {
297         struct text_model_factory *text_model_factory;
298
299         text_model_factory = calloc(1, sizeof *text_model_factory);
300
301         text_model_factory->ec = ec;
302
303         text_model_factory->text_model_factory_global =
304                 wl_display_add_global(ec->wl_display,
305                                       &text_model_factory_interface,
306                                       text_model_factory, bind_text_model_factory);
307
308         text_model_factory->destroy_listener.notify = text_model_factory_notifier_destroy;
309         wl_signal_add(&ec->destroy_signal, &text_model_factory->destroy_listener);
310 }
311
312 static void
313 input_method_context_destroy(struct wl_client *client,
314                              struct wl_resource *resource)
315 {
316         wl_resource_destroy(resource);
317 }
318
319 static void
320 input_method_context_commit_string(struct wl_client *client,
321                                    struct wl_resource *resource,
322                                    const char *text,
323                                    uint32_t index)
324 {
325         struct input_method_context *context = resource->data;
326
327         text_model_send_commit_string(&context->model->resource, text, index);
328 }
329
330 static void
331 input_method_context_preedit_string(struct wl_client *client,
332                                    struct wl_resource *resource,
333                                    const char *text,
334                                    uint32_t index)
335 {
336         struct input_method_context *context = resource->data;
337
338         text_model_send_preedit_string(&context->model->resource, text, index);
339 }
340
341 static void
342 input_method_context_delete_surrounding_text(struct wl_client *client,
343                                              struct wl_resource *resource,
344                                              int32_t index,
345                                              uint32_t length)
346 {
347         struct input_method_context *context = resource->data;
348
349         text_model_send_delete_surrounding_text(&context->model->resource, index, length);
350 }
351
352 static void
353 input_method_context_modifiers_map(struct wl_client *client,
354                                    struct wl_resource *resource,
355                                    struct wl_array *map)
356 {
357         struct input_method_context *context = resource->data;
358
359         text_model_send_modifiers_map(&context->model->resource, map);
360 }
361
362 static void
363 input_method_context_keysym(struct wl_client *client,
364                             struct wl_resource *resource,
365                             uint32_t serial,
366                             uint32_t time,
367                             uint32_t sym,
368                             uint32_t state,
369                             uint32_t modifiers)
370 {
371         struct input_method_context *context = resource->data;
372
373         text_model_send_keysym(&context->model->resource, serial, time,
374                                sym, state, modifiers);
375 }
376
377 static const struct input_method_context_interface input_method_context_implementation = {
378         input_method_context_destroy,
379         input_method_context_commit_string,
380         input_method_context_preedit_string,
381         input_method_context_delete_surrounding_text,
382         input_method_context_modifiers_map,
383         input_method_context_keysym
384 };
385
386 static void
387 destroy_input_method_context(struct wl_resource *resource)
388 {
389         struct input_method_context *context = resource->data;
390
391         free(context);
392 }
393
394 static void
395 input_method_context_create(struct text_model *model,
396                             struct input_method *input_method)
397 {
398         struct input_method_context *context;
399
400         if (!input_method->input_method_binding)
401                 return;
402
403         context = malloc(sizeof *context);
404         if (context == NULL)
405                 return;
406
407         context->resource.destroy = destroy_input_method_context;
408         context->resource.object.id = 0;
409         context->resource.object.interface = &input_method_context_interface;
410         context->resource.object.implementation =
411                 (void (**)(void)) &input_method_context_implementation;
412         context->resource.data = context;
413         wl_signal_init(&context->resource.destroy_signal);
414
415         context->model = model;
416         input_method->context = context;
417
418         wl_client_add_resource(input_method->input_method_binding->client, &context->resource);
419
420         input_method_send_activate(input_method->input_method_binding, &context->resource);
421 }
422
423 static void
424 unbind_input_method(struct wl_resource *resource)
425 {
426         struct input_method *input_method = resource->data;
427         struct text_backend *text_backend = input_method->text_backend;
428
429         input_method->input_method_binding = NULL;
430         input_method->context = NULL;
431
432         text_backend->input_method.binding = NULL;
433
434         free(resource);
435 }
436
437 static void
438 bind_input_method(struct wl_client *client,
439                   void *data,
440                   uint32_t version,
441                   uint32_t id)
442 {
443         struct input_method *input_method = data;
444         struct text_backend *text_backend = input_method->text_backend;
445         struct wl_resource *resource;
446
447         resource = wl_client_add_object(client, &input_method_interface,
448                                         NULL,
449                                         id, input_method);
450
451         if (input_method->input_method_binding == NULL) {
452                 resource->destroy = unbind_input_method;
453                 input_method->input_method_binding = resource;
454
455                 text_backend->input_method.binding = resource;
456                 return;
457         }
458
459         wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
460                                "interface object already bound");
461         wl_resource_destroy(resource);
462 }
463
464 static void
465 input_method_notifier_destroy(struct wl_listener *listener, void *data)
466 {
467         struct input_method *input_method =
468                 container_of(listener, struct input_method, destroy_listener);
469
470         if (input_method->model)
471                 deactivate_text_model(input_method->model, input_method);
472
473         wl_display_remove_global(input_method->seat->compositor->wl_display,
474                                  input_method->input_method_global);
475
476         free(input_method);
477 }
478
479 static void
480 handle_keyboard_focus(struct wl_listener *listener, void *data)
481 {
482         struct wl_keyboard *keyboard = data;
483         struct input_method *input_method =
484                 container_of(listener, struct input_method, keyboard_focus_listener);
485         struct wl_surface *surface = keyboard->focus;
486
487         if (!input_method->model)
488                 return;
489
490         if (!surface || input_method->model->surface != surface)
491                 deactivate_text_model(input_method->model,
492                                       input_method);
493 }
494
495 static void
496 input_method_init_seat(struct weston_seat *seat)
497 {
498         if (seat->input_method->focus_listener_initialized)
499                 return;
500
501         if (seat->has_keyboard) {
502                 seat->input_method->keyboard_focus_listener.notify = handle_keyboard_focus;
503                 wl_signal_add(&seat->seat.keyboard->focus_signal, &seat->input_method->keyboard_focus_listener);
504         }
505
506         seat->input_method->focus_listener_initialized = 1;
507 }
508
509 static void
510 handle_input_method_sigchld(struct weston_process *process, int status)
511 {
512         struct text_backend *text_backend =
513                 container_of(process, struct text_backend, input_method.process);
514
515         text_backend->input_method.process.pid = 0;
516         text_backend->input_method.client = NULL;
517 }
518
519 static void
520 launch_input_method(struct text_backend *text_backend)
521 {
522         if (text_backend->input_method.binding)
523                 return;
524
525         if (!text_backend->input_method.path)
526                 return;
527
528         if (text_backend->input_method.process.pid != 0)
529                 return;
530
531         text_backend->input_method.client = weston_client_launch(text_backend->compositor,
532                                                                 &text_backend->input_method.process,
533                                                                 text_backend->input_method.path,
534                                                                 handle_input_method_sigchld);
535
536         if (!text_backend->input_method.client)
537                 weston_log("not able to start %s\n", text_backend->input_method.path);
538 }
539
540 static void
541 handle_seat_created(struct wl_listener *listener,
542                     void *data)
543 {
544         struct weston_seat *seat = data;
545         struct text_backend *text_backend =
546                 container_of(listener, struct text_backend,
547                              seat_created_listener);
548         struct input_method *input_method;
549         struct weston_compositor *ec = seat->compositor;
550
551         input_method = calloc(1, sizeof *input_method);
552
553         input_method->seat = seat;
554         input_method->model = NULL;
555         input_method->focus_listener_initialized = 0;
556         input_method->context = NULL;
557         input_method->text_backend = text_backend;
558
559         input_method->input_method_global =
560                 wl_display_add_global(ec->wl_display,
561                                       &input_method_interface,
562                                       input_method, bind_input_method);
563
564         input_method->destroy_listener.notify = input_method_notifier_destroy;
565         wl_signal_add(&seat->seat.destroy_signal, &input_method->destroy_listener);
566
567         seat->input_method = input_method;
568
569         launch_input_method(text_backend);
570 }
571
572 static void
573 text_backend_configuration(struct text_backend *text_backend)
574 {
575         char *config_file;
576         char *path = NULL;
577
578         struct config_key input_method_keys[] = {
579                 { "path", CONFIG_KEY_STRING, &path }
580         };
581
582         struct config_section cs[] = {
583                 { "input-method", input_method_keys, ARRAY_LENGTH(input_method_keys), NULL }
584         };
585
586         config_file = config_file_path("weston.ini");
587         parse_config_file(config_file, cs, ARRAY_LENGTH(cs), text_backend);
588         free(config_file);
589
590         if (path)
591                 text_backend->input_method.path = path;
592         else
593                 text_backend->input_method.path = strdup(LIBEXECDIR "/weston-keyboard");
594 }
595
596 static void
597 text_backend_notifier_destroy(struct wl_listener *listener, void *data)
598 {
599         struct text_backend *text_backend =
600                 container_of(listener, struct text_backend, destroy_listener);
601
602         if (text_backend->input_method.client)
603                 wl_client_destroy(text_backend->input_method.client);
604
605         free(text_backend->input_method.path);
606
607         free(text_backend);
608 }
609
610
611 WL_EXPORT int
612 text_backend_init(struct weston_compositor *ec)
613 {
614         struct text_backend *text_backend;
615
616         text_backend = calloc(1, sizeof(*text_backend));
617
618         text_backend->compositor = ec;
619
620         text_backend->seat_created_listener.notify = handle_seat_created;
621         wl_signal_add(&ec->seat_created_signal,
622                       &text_backend->seat_created_listener);
623
624         text_backend->destroy_listener.notify = text_backend_notifier_destroy;
625         wl_signal_add(&ec->destroy_signal, &text_backend->destroy_listener);
626
627         text_backend_configuration(text_backend);
628
629         text_model_factory_create(ec);
630
631         return 0;
632 }