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