text: Have only one text_model_factory
[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
29 struct input_method;
30
31 struct text_model {
32         struct wl_resource resource;
33
34         struct weston_compositor *ec;
35
36         struct wl_list input_methods;
37
38         struct wl_surface *surface;
39 };
40
41 struct text_model_factory {
42         struct wl_global *text_model_factory_global;
43         struct wl_listener destroy_listener;
44
45         struct weston_compositor *ec;
46 };
47
48 struct input_method {
49         struct wl_resource *input_method_binding;
50         struct wl_global *input_method_global;
51         struct wl_listener destroy_listener;
52
53         struct weston_seat *seat;
54         struct text_model *model;
55
56         struct wl_list link;
57
58         struct wl_listener keyboard_focus_listener;
59
60         int focus_listener_initialized;
61 };
62
63 static void input_method_init_seat(struct weston_seat *seat);
64
65 static void
66 deactivate_text_model(struct text_model *text_model,
67                       struct input_method *input_method)
68 {
69         struct weston_compositor *ec = text_model->ec;
70
71         if (input_method->model == text_model) {
72                 wl_list_remove(&input_method->link);
73                 input_method->model = NULL;
74                 wl_signal_emit(&ec->hide_input_panel_signal, ec);
75                 text_model_send_deactivated(&text_model->resource);
76         }
77 }
78
79 static void
80 destroy_text_model(struct wl_resource *resource)
81 {
82         struct text_model *text_model =
83                 container_of(resource, struct text_model, resource);
84         struct input_method *input_method, *next;
85
86         wl_list_for_each_safe(input_method, next, &text_model->input_methods, link)
87                 deactivate_text_model(text_model, input_method);
88
89         free(text_model);
90 }
91
92 static void
93 text_model_set_surrounding_text(struct wl_client *client,
94                                 struct wl_resource *resource,
95                                 const char *text)
96 {
97 }
98
99 static void
100 text_model_set_cursor_index(struct wl_client *client,
101                             struct wl_resource *resource,
102                             uint32_t index)
103 {
104 }
105
106 static void
107 text_model_activate(struct wl_client *client,
108                     struct wl_resource *resource,
109                     struct wl_resource *seat,
110                     struct wl_resource *surface)
111 {
112         struct text_model *text_model = resource->data;
113         struct weston_seat *weston_seat = seat->data;
114         struct text_model *old = weston_seat->input_method->model;
115         struct weston_compositor *ec = text_model->ec;
116
117         if (old == text_model)
118                 return;
119
120         if (old) {
121                 deactivate_text_model(old,
122                                       weston_seat->input_method);
123         }
124
125         weston_seat->input_method->model = text_model;
126         wl_list_insert(&text_model->input_methods, &weston_seat->input_method->link);
127         input_method_init_seat(weston_seat);
128
129         text_model->surface = surface->data;
130
131         wl_signal_emit(&ec->show_input_panel_signal, ec);
132
133         text_model_send_activated(&text_model->resource);
134 }
135
136 static void
137 text_model_deactivate(struct wl_client *client,
138                       struct wl_resource *resource,
139                       struct wl_resource *seat)
140 {
141         struct text_model *text_model = resource->data;
142         struct weston_seat *weston_seat = seat->data;
143
144         deactivate_text_model(text_model,
145                               weston_seat->input_method);
146 }
147
148 static void
149 text_model_set_selected_text(struct wl_client *client,
150                              struct wl_resource *resource,
151                              const char *text,
152                              int32_t index)
153 {
154 }
155
156 static void
157 text_model_set_micro_focus(struct wl_client *client,
158                            struct wl_resource *resource,
159                            int32_t x,
160                            int32_t y,
161                            int32_t width,
162                            int32_t height)
163 {
164 }
165
166 static void
167 text_model_set_preedit(struct wl_client *client,
168                        struct wl_resource *resource)
169 {
170 }
171
172 static void
173 text_model_set_content_type(struct wl_client *client,
174                             struct wl_resource *resource)
175 {
176 }
177
178 static const struct text_model_interface text_model_implementation = {
179         text_model_set_surrounding_text,
180         text_model_set_cursor_index,
181         text_model_activate,
182         text_model_deactivate,
183         text_model_set_selected_text,
184         text_model_set_micro_focus,
185         text_model_set_preedit,
186         text_model_set_content_type
187 };
188
189 static void text_model_factory_create_text_model(struct wl_client *client,
190                                                  struct wl_resource *resource,
191                                                  uint32_t id)
192 {
193         struct text_model_factory *text_model_factory = resource->data;
194         struct text_model *text_model;
195
196         text_model = calloc(1, sizeof *text_model);
197
198         text_model->resource.object.id = id;
199         text_model->resource.object.interface = &text_model_interface;
200         text_model->resource.object.implementation =
201                 (void (**)(void)) &text_model_implementation;
202
203         text_model->resource.data = text_model;
204         text_model->resource.destroy = destroy_text_model;
205
206         text_model->ec = text_model_factory->ec;
207
208         wl_list_init(&text_model->input_methods);
209
210         wl_client_add_resource(client, &text_model->resource);
211 };
212
213 static const struct text_model_factory_interface text_model_factory_implementation = {
214         text_model_factory_create_text_model
215 };
216
217 static void
218 bind_text_model_factory(struct wl_client *client,
219                         void *data,
220                         uint32_t version,
221                         uint32_t id)
222 {
223         struct text_model_factory *text_model_factory = data;
224
225         /* No checking for duplicate binding necessary.
226          * No events have to be sent, so we don't need the return value. */
227         wl_client_add_object(client, &text_model_factory_interface,
228                              &text_model_factory_implementation,
229                              id, text_model_factory);
230 }
231
232 static void
233 text_model_factory_notifier_destroy(struct wl_listener *listener, void *data)
234 {
235         struct text_model_factory *text_model_factory =
236                 container_of(listener, struct text_model_factory, destroy_listener);
237
238         wl_display_remove_global(text_model_factory->ec->wl_display,
239                                  text_model_factory->text_model_factory_global);
240
241         free(text_model_factory);
242 }
243
244 WL_EXPORT void
245 text_model_factory_create(struct weston_compositor *ec)
246 {
247         struct text_model_factory *text_model_factory;
248
249         text_model_factory = calloc(1, sizeof *text_model_factory);
250
251         text_model_factory->ec = ec;
252
253         text_model_factory->text_model_factory_global =
254                 wl_display_add_global(ec->wl_display,
255                                       &text_model_factory_interface,
256                                       text_model_factory, bind_text_model_factory);
257
258         text_model_factory->destroy_listener.notify = text_model_factory_notifier_destroy;
259         wl_signal_add(&ec->destroy_signal, &text_model_factory->destroy_listener);
260 }
261
262 static void
263 input_method_commit_string(struct wl_client *client,
264                            struct wl_resource *resource,
265                            const char *text,
266                            uint32_t index)
267 {
268         struct input_method *input_method = resource->data;
269
270         if (input_method->model) {
271                 text_model_send_commit_string(&input_method->model->resource, text, index);
272         }
273 }
274
275 static const struct input_method_interface input_method_implementation = {
276         input_method_commit_string
277 };
278
279 static void
280 unbind_input_method(struct wl_resource *resource)
281 {
282         struct input_method *input_method = resource->data;
283
284         input_method->input_method_binding = NULL;
285         free(resource);
286 }
287
288 static void
289 bind_input_method(struct wl_client *client,
290                   void *data,
291                   uint32_t version,
292                   uint32_t id)
293 {
294         struct input_method *input_method = data;
295         struct wl_resource *resource;
296
297         resource = wl_client_add_object(client, &input_method_interface,
298                                         &input_method_implementation,
299                                         id, input_method);
300
301         if (input_method->input_method_binding == NULL) {
302                 resource->destroy = unbind_input_method;
303                 input_method->input_method_binding = resource;
304                 return;
305         }
306
307         wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
308                                "interface object already bound");
309         wl_resource_destroy(resource);
310 }
311
312 static void
313 input_method_notifier_destroy(struct wl_listener *listener, void *data)
314 {
315         struct input_method *input_method =
316                 container_of(listener, struct input_method, destroy_listener);
317
318         if (input_method->model)
319                 deactivate_text_model(input_method->model, input_method);
320
321         wl_display_remove_global(input_method->seat->compositor->wl_display,
322                                  input_method->input_method_global);
323
324         free(input_method);
325 }
326
327 static void
328 handle_keyboard_focus(struct wl_listener *listener, void *data)
329 {
330         struct wl_keyboard *keyboard = data;
331         struct input_method *input_method =
332                 container_of(listener, struct input_method, keyboard_focus_listener);
333         struct wl_surface *surface = keyboard->focus;
334
335         if (!input_method->model)
336                 return;
337
338         if (!surface || input_method->model->surface != surface)
339                 deactivate_text_model(input_method->model,
340                                       input_method);
341 }
342
343 static void
344 input_method_init_seat(struct weston_seat *seat)
345 {
346         if (seat->input_method->focus_listener_initialized)
347                 return;
348
349         if (seat->has_keyboard) {
350                 seat->input_method->keyboard_focus_listener.notify = handle_keyboard_focus;
351                 wl_signal_add(&seat->seat.keyboard->focus_signal, &seat->input_method->keyboard_focus_listener);
352         }
353
354         seat->input_method->focus_listener_initialized = 1;
355 }
356
357 WL_EXPORT void
358 input_method_create(struct weston_compositor *ec,
359                     struct weston_seat *seat)
360 {
361         struct input_method *input_method;
362
363         input_method = calloc(1, sizeof *input_method);
364
365         input_method->seat = seat;
366         input_method->model = NULL;
367         input_method->focus_listener_initialized = 0;
368
369         input_method->input_method_global =
370                 wl_display_add_global(ec->wl_display,
371                                       &input_method_interface,
372                                       input_method, bind_input_method);
373
374         input_method->destroy_listener.notify = input_method_notifier_destroy;
375         wl_signal_add(&seat->seat.destroy_signal, &input_method->destroy_listener);
376
377         seat->input_method = input_method;
378 }
379