text: Add support for control keys to the protocol
[profile/ivi/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
26 #include "compositor.h"
27 #include "text-server-protocol.h"
28 #include "input-method-server-protocol.h"
29
30 struct input_method;
31 struct input_method_context;
32
33 struct text_model {
34         struct wl_resource resource;
35
36         struct weston_compositor *ec;
37
38         struct wl_list input_methods;
39
40         struct wl_surface *surface;
41 };
42
43 struct text_model_factory {
44         struct wl_global *text_model_factory_global;
45         struct wl_listener destroy_listener;
46
47         struct weston_compositor *ec;
48 };
49
50 struct input_method {
51         struct wl_resource *input_method_binding;
52         struct wl_global *input_method_global;
53         struct wl_listener destroy_listener;
54
55         struct weston_seat *seat;
56         struct text_model *model;
57
58         struct wl_list link;
59
60         struct wl_listener keyboard_focus_listener;
61
62         int focus_listener_initialized;
63
64         struct input_method_context *context;
65 };
66
67 struct input_method_context {
68         struct wl_resource resource;
69
70         struct text_model *model;
71
72         struct wl_list link;
73 };
74
75 static void input_method_context_create(struct text_model *model,
76                                         struct input_method *input_method);
77
78 static void input_method_init_seat(struct weston_seat *seat);
79
80 static void
81 deactivate_text_model(struct text_model *text_model,
82                       struct input_method *input_method)
83 {
84         struct weston_compositor *ec = text_model->ec;
85
86         if (input_method->model == text_model) {
87                 if (input_method->input_method_binding)
88                         input_method_send_deactivate(input_method->input_method_binding, &input_method->context->resource);
89                 wl_list_remove(&input_method->link);
90                 input_method->model = NULL;
91                 input_method->context = NULL;
92                 wl_signal_emit(&ec->hide_input_panel_signal, ec);
93                 text_model_send_deactivated(&text_model->resource);
94         }
95 }
96
97 static void
98 destroy_text_model(struct wl_resource *resource)
99 {
100         struct text_model *text_model =
101                 container_of(resource, struct text_model, resource);
102         struct input_method *input_method, *next;
103
104         wl_list_for_each_safe(input_method, next, &text_model->input_methods, link)
105                 deactivate_text_model(text_model, input_method);
106
107         free(text_model);
108 }
109
110 static void
111 text_model_set_surrounding_text(struct wl_client *client,
112                                 struct wl_resource *resource,
113                                 const char *text,
114                                 uint32_t cursor,
115                                 uint32_t anchor)
116 {
117         struct text_model *text_model = resource->data;
118         struct input_method *input_method, *next;
119
120         wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
121                 if (!input_method->context)
122                         continue;
123                 input_method_context_send_surrounding_text(&input_method->context->resource,
124                                                            text,
125                                                            cursor,
126                                                            anchor);
127         }
128 }
129
130 static void
131 text_model_activate(struct wl_client *client,
132                     struct wl_resource *resource,
133                     struct wl_resource *seat,
134                     struct wl_resource *surface)
135 {
136         struct text_model *text_model = resource->data;
137         struct weston_seat *weston_seat = seat->data;
138         struct input_method *input_method = weston_seat->input_method;
139         struct text_model *old = weston_seat->input_method->model;
140         struct weston_compositor *ec = text_model->ec;
141
142         if (old == text_model)
143                 return;
144
145         if (old) {
146                 deactivate_text_model(old,
147                                       weston_seat->input_method);
148         }
149
150         input_method->model = text_model;
151         wl_list_insert(&text_model->input_methods, &input_method->link);
152         input_method_init_seat(weston_seat);
153
154         text_model->surface = surface->data;
155
156         input_method_context_create(text_model, input_method);
157
158         wl_signal_emit(&ec->show_input_panel_signal, ec);
159
160         text_model_send_activated(&text_model->resource);
161 }
162
163 static void
164 text_model_deactivate(struct wl_client *client,
165                       struct wl_resource *resource,
166                       struct wl_resource *seat)
167 {
168         struct text_model *text_model = resource->data;
169         struct weston_seat *weston_seat = seat->data;
170
171         deactivate_text_model(text_model,
172                               weston_seat->input_method);
173 }
174
175 static void
176 text_model_set_micro_focus(struct wl_client *client,
177                            struct wl_resource *resource,
178                            int32_t x,
179                            int32_t y,
180                            int32_t width,
181                            int32_t height)
182 {
183 }
184
185 static void
186 text_model_set_preedit(struct wl_client *client,
187                        struct wl_resource *resource)
188 {
189 }
190
191 static void
192 text_model_set_content_type(struct wl_client *client,
193                             struct wl_resource *resource)
194 {
195 }
196
197 static const struct text_model_interface text_model_implementation = {
198         text_model_set_surrounding_text,
199         text_model_activate,
200         text_model_deactivate,
201         text_model_set_micro_focus,
202         text_model_set_preedit,
203         text_model_set_content_type
204 };
205
206 static void text_model_factory_create_text_model(struct wl_client *client,
207                                                  struct wl_resource *resource,
208                                                  uint32_t id)
209 {
210         struct text_model_factory *text_model_factory = resource->data;
211         struct text_model *text_model;
212
213         text_model = calloc(1, sizeof *text_model);
214
215         text_model->resource.object.id = id;
216         text_model->resource.object.interface = &text_model_interface;
217         text_model->resource.object.implementation =
218                 (void (**)(void)) &text_model_implementation;
219
220         text_model->resource.data = text_model;
221         text_model->resource.destroy = destroy_text_model;
222
223         text_model->ec = text_model_factory->ec;
224
225         wl_list_init(&text_model->input_methods);
226
227         wl_client_add_resource(client, &text_model->resource);
228 };
229
230 static const struct text_model_factory_interface text_model_factory_implementation = {
231         text_model_factory_create_text_model
232 };
233
234 static void
235 bind_text_model_factory(struct wl_client *client,
236                         void *data,
237                         uint32_t version,
238                         uint32_t id)
239 {
240         struct text_model_factory *text_model_factory = data;
241
242         /* No checking for duplicate binding necessary.
243          * No events have to be sent, so we don't need the return value. */
244         wl_client_add_object(client, &text_model_factory_interface,
245                              &text_model_factory_implementation,
246                              id, text_model_factory);
247 }
248
249 static void
250 text_model_factory_notifier_destroy(struct wl_listener *listener, void *data)
251 {
252         struct text_model_factory *text_model_factory =
253                 container_of(listener, struct text_model_factory, destroy_listener);
254
255         wl_display_remove_global(text_model_factory->ec->wl_display,
256                                  text_model_factory->text_model_factory_global);
257
258         free(text_model_factory);
259 }
260
261 WL_EXPORT void
262 text_model_factory_create(struct weston_compositor *ec)
263 {
264         struct text_model_factory *text_model_factory;
265
266         text_model_factory = calloc(1, sizeof *text_model_factory);
267
268         text_model_factory->ec = ec;
269
270         text_model_factory->text_model_factory_global =
271                 wl_display_add_global(ec->wl_display,
272                                       &text_model_factory_interface,
273                                       text_model_factory, bind_text_model_factory);
274
275         text_model_factory->destroy_listener.notify = text_model_factory_notifier_destroy;
276         wl_signal_add(&ec->destroy_signal, &text_model_factory->destroy_listener);
277 }
278
279 static void
280 input_method_context_destroy(struct wl_client *client,
281                              struct wl_resource *resource)
282 {
283         wl_resource_destroy(resource);
284 }
285
286 static void
287 input_method_context_commit_string(struct wl_client *client,
288                                    struct wl_resource *resource,
289                                    const char *text,
290                                    uint32_t index)
291 {
292         struct input_method_context *context = resource->data;
293
294         text_model_send_commit_string(&context->model->resource, text, index);
295 }
296
297 static void
298 input_method_context_preedit_string(struct wl_client *client,
299                                    struct wl_resource *resource,
300                                    const char *text,
301                                    uint32_t index)
302 {
303         struct input_method_context *context = resource->data;
304
305         text_model_send_preedit_string(&context->model->resource, text, index);
306 }
307
308 static void
309 input_method_context_delete_surrounding_text(struct wl_client *client,
310                                              struct wl_resource *resource,
311                                              int32_t index,
312                                              uint32_t length)
313 {
314         struct input_method_context *context = resource->data;
315
316         text_model_send_delete_surrounding_text(&context->model->resource, index, length);
317 }
318
319 static void
320 input_method_context_key(struct wl_client *client,
321                          struct wl_resource *resource,
322                          uint32_t key,
323                          uint32_t state)
324 {
325         struct input_method_context *context = resource->data;
326
327         text_model_send_key(&context->model->resource, key, state);
328 }
329
330 static const struct input_method_context_interface input_method_context_implementation = {
331         input_method_context_destroy,
332         input_method_context_commit_string,
333         input_method_context_preedit_string,
334         input_method_context_delete_surrounding_text,
335         input_method_context_key
336 };
337
338 static void
339 destroy_input_method_context(struct wl_resource *resource)
340 {
341         struct input_method_context *context = resource->data;
342
343         free(context);
344 }
345
346 static void
347 input_method_context_create(struct text_model *model,
348                             struct input_method *input_method)
349 {
350         struct input_method_context *context;
351
352         if (!input_method->input_method_binding)
353                 return;
354
355         context = malloc(sizeof *context);
356         if (context == NULL)
357                 return;
358
359         context->resource.destroy = destroy_input_method_context;
360         context->resource.object.id = 0;
361         context->resource.object.interface = &input_method_context_interface;
362         context->resource.object.implementation =
363                 (void (**)(void)) &input_method_context_implementation;
364         context->resource.data = context;
365         wl_signal_init(&context->resource.destroy_signal);
366
367         context->model = model;
368         input_method->context = context;
369
370         wl_client_add_resource(input_method->input_method_binding->client, &context->resource);
371
372         input_method_send_activate(input_method->input_method_binding, &context->resource);
373 }
374
375 static void
376 unbind_input_method(struct wl_resource *resource)
377 {
378         struct input_method *input_method = resource->data;
379
380         input_method->input_method_binding = NULL;
381         input_method->context = NULL;
382
383         free(resource);
384 }
385
386 static void
387 bind_input_method(struct wl_client *client,
388                   void *data,
389                   uint32_t version,
390                   uint32_t id)
391 {
392         struct input_method *input_method = data;
393         struct wl_resource *resource;
394
395         resource = wl_client_add_object(client, &input_method_interface,
396                                         NULL,
397                                         id, input_method);
398
399         if (input_method->input_method_binding == NULL) {
400                 resource->destroy = unbind_input_method;
401                 input_method->input_method_binding = resource;
402                 return;
403         }
404
405         wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
406                                "interface object already bound");
407         wl_resource_destroy(resource);
408 }
409
410 static void
411 input_method_notifier_destroy(struct wl_listener *listener, void *data)
412 {
413         struct input_method *input_method =
414                 container_of(listener, struct input_method, destroy_listener);
415
416         if (input_method->model)
417                 deactivate_text_model(input_method->model, input_method);
418
419         wl_display_remove_global(input_method->seat->compositor->wl_display,
420                                  input_method->input_method_global);
421
422         free(input_method);
423 }
424
425 static void
426 handle_keyboard_focus(struct wl_listener *listener, void *data)
427 {
428         struct wl_keyboard *keyboard = data;
429         struct input_method *input_method =
430                 container_of(listener, struct input_method, keyboard_focus_listener);
431         struct wl_surface *surface = keyboard->focus;
432
433         if (!input_method->model)
434                 return;
435
436         if (!surface || input_method->model->surface != surface)
437                 deactivate_text_model(input_method->model,
438                                       input_method);
439 }
440
441 static void
442 input_method_init_seat(struct weston_seat *seat)
443 {
444         if (seat->input_method->focus_listener_initialized)
445                 return;
446
447         if (seat->has_keyboard) {
448                 seat->input_method->keyboard_focus_listener.notify = handle_keyboard_focus;
449                 wl_signal_add(&seat->seat.keyboard->focus_signal, &seat->input_method->keyboard_focus_listener);
450         }
451
452         seat->input_method->focus_listener_initialized = 1;
453 }
454
455 WL_EXPORT void
456 input_method_create(struct weston_compositor *ec,
457                     struct weston_seat *seat)
458 {
459         struct input_method *input_method;
460
461         input_method = calloc(1, sizeof *input_method);
462
463         input_method->seat = seat;
464         input_method->model = NULL;
465         input_method->focus_listener_initialized = 0;
466         input_method->context = NULL;
467
468         input_method->input_method_global =
469                 wl_display_add_global(ec->wl_display,
470                                       &input_method_interface,
471                                       input_method, bind_input_method);
472
473         input_method->destroy_listener.notify = input_method_notifier_destroy;
474         wl_signal_add(&seat->seat.destroy_signal, &input_method->destroy_listener);
475
476         seat->input_method = input_method;
477 }
478