2 * Copyright © 2012 Openismus GmbH
3 * Copyright © 2012 Intel Corporation
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.
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.
27 #include "compositor.h"
28 #include "text-server-protocol.h"
29 #include "input-method-server-protocol.h"
32 struct input_method_context;
36 struct wl_resource resource;
38 struct weston_compositor *ec;
40 struct wl_list input_methods;
42 struct wl_surface *surface;
45 struct text_model_factory {
46 struct wl_global *text_model_factory_global;
47 struct wl_listener destroy_listener;
49 struct weston_compositor *ec;
53 struct wl_resource *input_method_binding;
54 struct wl_global *input_method_global;
55 struct wl_listener destroy_listener;
57 struct weston_seat *seat;
58 struct text_model *model;
62 struct wl_listener keyboard_focus_listener;
64 int focus_listener_initialized;
66 struct input_method_context *context;
68 struct text_backend *text_backend;
71 struct input_method_context {
72 struct wl_resource resource;
74 struct text_model *model;
80 struct weston_compositor *compositor;
84 struct wl_resource *binding;
85 struct weston_process process;
86 struct wl_client *client;
89 struct wl_listener seat_created_listener;
90 struct wl_listener destroy_listener;
93 static void input_method_context_create(struct text_model *model,
94 struct input_method *input_method);
96 static void input_method_init_seat(struct weston_seat *seat);
99 deactivate_text_model(struct text_model *text_model,
100 struct input_method *input_method)
102 struct weston_compositor *ec = text_model->ec;
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);
116 destroy_text_model(struct wl_resource *resource)
118 struct text_model *text_model =
119 container_of(resource, struct text_model, resource);
120 struct input_method *input_method, *next;
122 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link)
123 deactivate_text_model(text_model, input_method);
129 text_model_set_surrounding_text(struct wl_client *client,
130 struct wl_resource *resource,
135 struct text_model *text_model = resource->data;
136 struct input_method *input_method, *next;
138 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
139 if (!input_method->context)
141 input_method_context_send_surrounding_text(&input_method->context->resource,
149 text_model_activate(struct wl_client *client,
150 struct wl_resource *resource,
151 struct wl_resource *seat,
152 struct wl_resource *surface)
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;
160 if (old == text_model)
164 deactivate_text_model(old,
165 weston_seat->input_method);
168 input_method->model = text_model;
169 wl_list_insert(&text_model->input_methods, &input_method->link);
170 input_method_init_seat(weston_seat);
172 text_model->surface = surface->data;
174 input_method_context_create(text_model, input_method);
176 wl_signal_emit(&ec->show_input_panel_signal, ec);
178 text_model_send_enter(&text_model->resource, &text_model->surface->resource);
182 text_model_deactivate(struct wl_client *client,
183 struct wl_resource *resource,
184 struct wl_resource *seat)
186 struct text_model *text_model = resource->data;
187 struct weston_seat *weston_seat = seat->data;
189 deactivate_text_model(text_model,
190 weston_seat->input_method);
194 text_model_reset(struct wl_client *client,
195 struct wl_resource *resource)
197 struct text_model *text_model = resource->data;
198 struct input_method *input_method, *next;
200 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
201 if (!input_method->context)
203 input_method_context_send_reset(&input_method->context->resource);
208 text_model_set_micro_focus(struct wl_client *client,
209 struct wl_resource *resource,
218 text_model_set_preedit(struct wl_client *client,
219 struct wl_resource *resource)
224 text_model_set_content_type(struct wl_client *client,
225 struct wl_resource *resource)
229 static const struct text_model_interface text_model_implementation = {
230 text_model_set_surrounding_text,
232 text_model_deactivate,
234 text_model_set_micro_focus,
235 text_model_set_preedit,
236 text_model_set_content_type
239 static void text_model_factory_create_text_model(struct wl_client *client,
240 struct wl_resource *resource,
243 struct text_model_factory *text_model_factory = resource->data;
244 struct text_model *text_model;
246 text_model = calloc(1, sizeof *text_model);
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;
253 text_model->resource.data = text_model;
254 text_model->resource.destroy = destroy_text_model;
256 text_model->ec = text_model_factory->ec;
258 wl_list_init(&text_model->input_methods);
260 wl_client_add_resource(client, &text_model->resource);
263 static const struct text_model_factory_interface text_model_factory_implementation = {
264 text_model_factory_create_text_model
268 bind_text_model_factory(struct wl_client *client,
273 struct text_model_factory *text_model_factory = data;
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);
283 text_model_factory_notifier_destroy(struct wl_listener *listener, void *data)
285 struct text_model_factory *text_model_factory =
286 container_of(listener, struct text_model_factory, destroy_listener);
288 wl_display_remove_global(text_model_factory->ec->wl_display,
289 text_model_factory->text_model_factory_global);
291 free(text_model_factory);
295 text_model_factory_create(struct weston_compositor *ec)
297 struct text_model_factory *text_model_factory;
299 text_model_factory = calloc(1, sizeof *text_model_factory);
301 text_model_factory->ec = ec;
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);
308 text_model_factory->destroy_listener.notify = text_model_factory_notifier_destroy;
309 wl_signal_add(&ec->destroy_signal, &text_model_factory->destroy_listener);
313 input_method_context_destroy(struct wl_client *client,
314 struct wl_resource *resource)
316 wl_resource_destroy(resource);
320 input_method_context_commit_string(struct wl_client *client,
321 struct wl_resource *resource,
325 struct input_method_context *context = resource->data;
327 text_model_send_commit_string(&context->model->resource, text, index);
331 input_method_context_preedit_string(struct wl_client *client,
332 struct wl_resource *resource,
336 struct input_method_context *context = resource->data;
338 text_model_send_preedit_string(&context->model->resource, text, index);
342 input_method_context_delete_surrounding_text(struct wl_client *client,
343 struct wl_resource *resource,
347 struct input_method_context *context = resource->data;
349 text_model_send_delete_surrounding_text(&context->model->resource, index, length);
353 input_method_context_modifiers_map(struct wl_client *client,
354 struct wl_resource *resource,
355 struct wl_array *map)
357 struct input_method_context *context = resource->data;
359 text_model_send_modifiers_map(&context->model->resource, map);
363 input_method_context_keysym(struct wl_client *client,
364 struct wl_resource *resource,
371 struct input_method_context *context = resource->data;
373 text_model_send_keysym(&context->model->resource, serial, time,
374 sym, state, modifiers);
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
387 destroy_input_method_context(struct wl_resource *resource)
389 struct input_method_context *context = resource->data;
395 input_method_context_create(struct text_model *model,
396 struct input_method *input_method)
398 struct input_method_context *context;
400 if (!input_method->input_method_binding)
403 context = malloc(sizeof *context);
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);
415 context->model = model;
416 input_method->context = context;
418 wl_client_add_resource(input_method->input_method_binding->client, &context->resource);
420 input_method_send_activate(input_method->input_method_binding, &context->resource);
424 unbind_input_method(struct wl_resource *resource)
426 struct input_method *input_method = resource->data;
427 struct text_backend *text_backend = input_method->text_backend;
429 input_method->input_method_binding = NULL;
430 input_method->context = NULL;
432 text_backend->input_method.binding = NULL;
438 bind_input_method(struct wl_client *client,
443 struct input_method *input_method = data;
444 struct text_backend *text_backend = input_method->text_backend;
445 struct wl_resource *resource;
447 resource = wl_client_add_object(client, &input_method_interface,
451 if (input_method->input_method_binding == NULL) {
452 resource->destroy = unbind_input_method;
453 input_method->input_method_binding = resource;
455 text_backend->input_method.binding = resource;
459 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
460 "interface object already bound");
461 wl_resource_destroy(resource);
465 input_method_notifier_destroy(struct wl_listener *listener, void *data)
467 struct input_method *input_method =
468 container_of(listener, struct input_method, destroy_listener);
470 if (input_method->model)
471 deactivate_text_model(input_method->model, input_method);
473 wl_display_remove_global(input_method->seat->compositor->wl_display,
474 input_method->input_method_global);
480 handle_keyboard_focus(struct wl_listener *listener, void *data)
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;
487 if (!input_method->model)
490 if (!surface || input_method->model->surface != surface)
491 deactivate_text_model(input_method->model,
496 input_method_init_seat(struct weston_seat *seat)
498 if (seat->input_method->focus_listener_initialized)
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);
506 seat->input_method->focus_listener_initialized = 1;
510 handle_input_method_sigchld(struct weston_process *process, int status)
512 struct text_backend *text_backend =
513 container_of(process, struct text_backend, input_method.process);
515 text_backend->input_method.process.pid = 0;
516 text_backend->input_method.client = NULL;
520 launch_input_method(struct text_backend *text_backend)
522 if (text_backend->input_method.binding)
525 if (!text_backend->input_method.path)
528 if (text_backend->input_method.process.pid != 0)
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);
536 if (!text_backend->input_method.client)
537 weston_log("not able to start %s\n", text_backend->input_method.path);
541 handle_seat_created(struct wl_listener *listener,
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;
551 input_method = calloc(1, sizeof *input_method);
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;
559 input_method->input_method_global =
560 wl_display_add_global(ec->wl_display,
561 &input_method_interface,
562 input_method, bind_input_method);
564 input_method->destroy_listener.notify = input_method_notifier_destroy;
565 wl_signal_add(&seat->seat.destroy_signal, &input_method->destroy_listener);
567 seat->input_method = input_method;
569 launch_input_method(text_backend);
573 text_backend_configuration(struct text_backend *text_backend)
578 struct config_key input_method_keys[] = {
579 { "path", CONFIG_KEY_STRING, &path }
582 struct config_section cs[] = {
583 { "input-method", input_method_keys, ARRAY_LENGTH(input_method_keys), NULL }
586 config_file = config_file_path("weston.ini");
587 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), text_backend);
591 text_backend->input_method.path = path;
593 text_backend->input_method.path = strdup(LIBEXECDIR "/weston-keyboard");
597 text_backend_notifier_destroy(struct wl_listener *listener, void *data)
599 struct text_backend *text_backend =
600 container_of(listener, struct text_backend, destroy_listener);
602 if (text_backend->input_method.client)
603 wl_client_destroy(text_backend->input_method.client);
605 free(text_backend->input_method.path);
612 text_backend_init(struct weston_compositor *ec)
614 struct text_backend *text_backend;
616 text_backend = calloc(1, sizeof(*text_backend));
618 text_backend->compositor = ec;
620 text_backend->seat_created_listener.notify = handle_seat_created;
621 wl_signal_add(&ec->seat_created_signal,
622 &text_backend->seat_created_listener);
624 text_backend->destroy_listener.notify = text_backend_notifier_destroy;
625 wl_signal_add(&ec->destroy_signal, &text_backend->destroy_listener);
627 text_backend_configuration(text_backend);
629 text_model_factory_create(ec);