text: Add support for pre-edit string
[profile/ivi/weston-ivi-shell.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 const struct input_method_context_interface input_method_context_implementation = {
309         input_method_context_destroy,
310         input_method_context_commit_string,
311         input_method_context_preedit_string,
312 };
313
314 static void
315 destroy_input_method_context(struct wl_resource *resource)
316 {
317         struct input_method_context *context = resource->data;
318
319         free(context);
320 }
321
322 static void
323 input_method_context_create(struct text_model *model,
324                             struct input_method *input_method)
325 {
326         struct input_method_context *context;
327
328         if (!input_method->input_method_binding)
329                 return;
330
331         context = malloc(sizeof *context);
332         if (context == NULL)
333                 return;
334
335         context->resource.destroy = destroy_input_method_context;
336         context->resource.object.id = 0;
337         context->resource.object.interface = &input_method_context_interface;
338         context->resource.object.implementation =
339                 (void (**)(void)) &input_method_context_implementation;
340         context->resource.data = context;
341         wl_signal_init(&context->resource.destroy_signal);
342
343         context->model = model;
344         input_method->context = context;
345
346         wl_client_add_resource(input_method->input_method_binding->client, &context->resource);
347
348         input_method_send_activate(input_method->input_method_binding, &context->resource);
349 }
350
351 static void
352 unbind_input_method(struct wl_resource *resource)
353 {
354         struct input_method *input_method = resource->data;
355
356         input_method->input_method_binding = NULL;
357         input_method->context = NULL;
358
359         free(resource);
360 }
361
362 static void
363 bind_input_method(struct wl_client *client,
364                   void *data,
365                   uint32_t version,
366                   uint32_t id)
367 {
368         struct input_method *input_method = data;
369         struct wl_resource *resource;
370
371         resource = wl_client_add_object(client, &input_method_interface,
372                                         NULL,
373                                         id, input_method);
374
375         if (input_method->input_method_binding == NULL) {
376                 resource->destroy = unbind_input_method;
377                 input_method->input_method_binding = resource;
378                 return;
379         }
380
381         wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
382                                "interface object already bound");
383         wl_resource_destroy(resource);
384 }
385
386 static void
387 input_method_notifier_destroy(struct wl_listener *listener, void *data)
388 {
389         struct input_method *input_method =
390                 container_of(listener, struct input_method, destroy_listener);
391
392         if (input_method->model)
393                 deactivate_text_model(input_method->model, input_method);
394
395         wl_display_remove_global(input_method->seat->compositor->wl_display,
396                                  input_method->input_method_global);
397
398         free(input_method);
399 }
400
401 static void
402 handle_keyboard_focus(struct wl_listener *listener, void *data)
403 {
404         struct wl_keyboard *keyboard = data;
405         struct input_method *input_method =
406                 container_of(listener, struct input_method, keyboard_focus_listener);
407         struct wl_surface *surface = keyboard->focus;
408
409         if (!input_method->model)
410                 return;
411
412         if (!surface || input_method->model->surface != surface)
413                 deactivate_text_model(input_method->model,
414                                       input_method);
415 }
416
417 static void
418 input_method_init_seat(struct weston_seat *seat)
419 {
420         if (seat->input_method->focus_listener_initialized)
421                 return;
422
423         if (seat->has_keyboard) {
424                 seat->input_method->keyboard_focus_listener.notify = handle_keyboard_focus;
425                 wl_signal_add(&seat->seat.keyboard->focus_signal, &seat->input_method->keyboard_focus_listener);
426         }
427
428         seat->input_method->focus_listener_initialized = 1;
429 }
430
431 WL_EXPORT void
432 input_method_create(struct weston_compositor *ec,
433                     struct weston_seat *seat)
434 {
435         struct input_method *input_method;
436
437         input_method = calloc(1, sizeof *input_method);
438
439         input_method->seat = seat;
440         input_method->model = NULL;
441         input_method->focus_listener_initialized = 0;
442         input_method->context = NULL;
443
444         input_method->input_method_global =
445                 wl_display_add_global(ec->wl_display,
446                                       &input_method_interface,
447                                       input_method, bind_input_method);
448
449         input_method->destroy_listener.notify = input_method_notifier_destroy;
450         wl_signal_add(&seat->seat.destroy_signal, &input_method->destroy_listener);
451
452         seat->input_method = input_method;
453 }
454