blob: c7761a965651d0ad027f888bc8c54c58d5bb5f16 [file] [log] [blame]
Jan Arne Petersen1f17be42012-06-21 21:52:18 +02001/*
2 * Copyright © 2012 Openismus GmbH
Jan Arne Petersen4c265182012-09-09 23:08:30 +02003 * Copyright © 2012 Intel Corporation
Jan Arne Petersen1f17be42012-06-21 21:52:18 +02004 *
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>
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +010025#include <string.h>
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020026
27#include "compositor.h"
28#include "text-server-protocol.h"
Jan Arne Petersen30b66ef2012-09-09 23:08:41 +020029#include "input-method-server-protocol.h"
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020030
31struct input_method;
Jan Arne Petersen620cd622012-09-09 23:08:32 +020032struct input_method_context;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +010033struct text_backend;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020034
35struct text_model {
36 struct wl_resource resource;
37
Jan Arne Petersene829adc2012-08-10 16:47:22 +020038 struct weston_compositor *ec;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020039
Jan Arne Petersene829adc2012-08-10 16:47:22 +020040 struct wl_list input_methods;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +020041
42 struct wl_surface *surface;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020043};
44
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +020045struct text_model_factory {
Jan Arne Petersen51963742012-08-10 16:47:20 +020046 struct wl_global *text_model_factory_global;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020047 struct wl_listener destroy_listener;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020048
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +020049 struct weston_compositor *ec;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +020050};
51
52struct input_method {
53 struct wl_resource *input_method_binding;
54 struct wl_global *input_method_global;
55 struct wl_listener destroy_listener;
56
57 struct weston_seat *seat;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020058 struct text_model *model;
59
60 struct wl_list link;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +020061
62 struct wl_listener keyboard_focus_listener;
63
64 int focus_listener_initialized;
Jan Arne Petersen620cd622012-09-09 23:08:32 +020065
66 struct input_method_context *context;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +010067
68 struct text_backend *text_backend;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020069};
70
Jan Arne Petersen620cd622012-09-09 23:08:32 +020071struct input_method_context {
72 struct wl_resource resource;
73
74 struct text_model *model;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +010075 struct input_method *input_method;
Jan Arne Petersen620cd622012-09-09 23:08:32 +020076
77 struct wl_list link;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +010078
79 struct wl_resource *keyboard;
Jan Arne Petersen620cd622012-09-09 23:08:32 +020080};
81
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +010082struct text_backend {
83 struct weston_compositor *compositor;
84
85 struct {
86 char *path;
87 struct wl_resource *binding;
88 struct weston_process process;
89 struct wl_client *client;
90 } input_method;
91
92 struct wl_listener seat_created_listener;
93 struct wl_listener destroy_listener;
94};
95
Jan Arne Petersen620cd622012-09-09 23:08:32 +020096static void input_method_context_create(struct text_model *model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010097 struct input_method *input_method,
98 uint32_t serial);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +010099static void input_method_context_end_keyboard_grab(struct input_method_context *context);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200100
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200101static void input_method_init_seat(struct weston_seat *seat);
102
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200103static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200104deactivate_text_model(struct text_model *text_model,
105 struct input_method *input_method)
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200106{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200107 struct weston_compositor *ec = text_model->ec;
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200108
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200109 if (input_method->model == text_model) {
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100110 if (input_method->context && input_method->input_method_binding) {
111 input_method_context_end_keyboard_grab(input_method->context);
112 input_method_send_deactivate(input_method->input_method_binding,
113 &input_method->context->resource);
114 }
115
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200116 wl_list_remove(&input_method->link);
117 input_method->model = NULL;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200118 input_method->context = NULL;
Kristian Høgsbergf97f3792012-07-22 11:51:42 -0400119 wl_signal_emit(&ec->hide_input_panel_signal, ec);
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200120 text_model_send_leave(&text_model->resource);
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200121 }
122}
123
124static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200125destroy_text_model(struct wl_resource *resource)
126{
Kristian Høgsbergf97f3792012-07-22 11:51:42 -0400127 struct text_model *text_model =
128 container_of(resource, struct text_model, resource);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200129 struct input_method *input_method, *next;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200130
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200131 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link)
132 deactivate_text_model(text_model, input_method);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200133
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200134 free(text_model);
135}
136
137static void
138text_model_set_surrounding_text(struct wl_client *client,
139 struct wl_resource *resource,
Jan Arne Petersencb08f4d2012-09-09 23:08:40 +0200140 const char *text,
141 uint32_t cursor,
142 uint32_t anchor)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200143{
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200144 struct text_model *text_model = resource->data;
145 struct input_method *input_method, *next;
146
147 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
148 if (!input_method->context)
149 continue;
Jan Arne Petersencb08f4d2012-09-09 23:08:40 +0200150 input_method_context_send_surrounding_text(&input_method->context->resource,
151 text,
152 cursor,
153 anchor);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200154 }
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200155}
156
157static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200158text_model_activate(struct wl_client *client,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200159 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100160 uint32_t serial,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200161 struct wl_resource *seat,
162 struct wl_resource *surface)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200163{
164 struct text_model *text_model = resource->data;
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200165 struct weston_seat *weston_seat = seat->data;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200166 struct input_method *input_method = weston_seat->input_method;
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200167 struct text_model *old = weston_seat->input_method->model;
168 struct weston_compositor *ec = text_model->ec;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200169
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200170 if (old == text_model)
171 return;
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200172
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200173 if (old) {
174 deactivate_text_model(old,
175 weston_seat->input_method);
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200176 }
177
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200178 input_method->model = text_model;
179 wl_list_insert(&text_model->input_methods, &input_method->link);
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200180 input_method_init_seat(weston_seat);
181
182 text_model->surface = surface->data;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200183
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100184 input_method_context_create(text_model, input_method, serial);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200185
Kristian Høgsbergf97f3792012-07-22 11:51:42 -0400186 wl_signal_emit(&ec->show_input_panel_signal, ec);
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200187
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200188 text_model_send_enter(&text_model->resource, &text_model->surface->resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200189}
190
191static void
192text_model_deactivate(struct wl_client *client,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200193 struct wl_resource *resource,
194 struct wl_resource *seat)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200195{
196 struct text_model *text_model = resource->data;
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200197 struct weston_seat *weston_seat = seat->data;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200198
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200199 deactivate_text_model(text_model,
200 weston_seat->input_method);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200201}
202
203static void
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200204text_model_reset(struct wl_client *client,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100205 struct wl_resource *resource,
206 uint32_t serial)
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200207{
208 struct text_model *text_model = resource->data;
209 struct input_method *input_method, *next;
210
211 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
212 if (!input_method->context)
213 continue;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100214 input_method_context_send_reset(&input_method->context->resource, serial);
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200215 }
216}
217
218static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200219text_model_set_micro_focus(struct wl_client *client,
220 struct wl_resource *resource,
221 int32_t x,
222 int32_t y,
223 int32_t width,
224 int32_t height)
225{
226}
227
228static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200229text_model_set_content_type(struct wl_client *client,
Jan Arne Petersen26ffa812013-01-16 21:26:43 +0100230 struct wl_resource *resource,
231 uint32_t hint,
232 uint32_t purpose)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200233{
Jan Arne Petersen26ffa812013-01-16 21:26:43 +0100234 struct text_model *text_model = resource->data;
235 struct input_method *input_method, *next;
236
237 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
238 if (!input_method->context)
239 continue;
240 input_method_context_send_content_type(&input_method->context->resource, hint, purpose);
241 }
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200242}
243
Jan Arne Petersenadfedc12013-01-16 21:26:46 +0100244static void
245text_model_invoke_action(struct wl_client *client,
246 struct wl_resource *resource,
247 uint32_t button,
248 uint32_t index)
249{
250 struct text_model *text_model = resource->data;
251 struct input_method *input_method, *next;
252
253 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
254 if (!input_method->context)
255 continue;
256 input_method_context_send_invoke_action(&input_method->context->resource, button, index);
257 }
258}
259
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200260static const struct text_model_interface text_model_implementation = {
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200261 text_model_set_surrounding_text,
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200262 text_model_activate,
263 text_model_deactivate,
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200264 text_model_reset,
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200265 text_model_set_micro_focus,
Jan Arne Petersenadfedc12013-01-16 21:26:46 +0100266 text_model_set_content_type,
267 text_model_invoke_action
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200268};
269
Jan Arne Petersen51963742012-08-10 16:47:20 +0200270static void text_model_factory_create_text_model(struct wl_client *client,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200271 struct wl_resource *resource,
Jan Arne Petersen4c265182012-09-09 23:08:30 +0200272 uint32_t id)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200273{
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200274 struct text_model_factory *text_model_factory = resource->data;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200275 struct text_model *text_model;
276
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200277 text_model = calloc(1, sizeof *text_model);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200278
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200279 text_model->resource.object.id = id;
280 text_model->resource.object.interface = &text_model_interface;
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200281 text_model->resource.object.implementation =
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200282 (void (**)(void)) &text_model_implementation;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200283
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200284 text_model->resource.data = text_model;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200285 text_model->resource.destroy = destroy_text_model;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200286
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200287 text_model->ec = text_model_factory->ec;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200288
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200289 wl_list_init(&text_model->input_methods);
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200290
291 wl_client_add_resource(client, &text_model->resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200292};
293
Jan Arne Petersen51963742012-08-10 16:47:20 +0200294static const struct text_model_factory_interface text_model_factory_implementation = {
295 text_model_factory_create_text_model
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200296};
297
298static void
Jan Arne Petersen51963742012-08-10 16:47:20 +0200299bind_text_model_factory(struct wl_client *client,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200300 void *data,
301 uint32_t version,
302 uint32_t id)
303{
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200304 struct text_model_factory *text_model_factory = data;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200305
306 /* No checking for duplicate binding necessary.
307 * No events have to be sent, so we don't need the return value. */
Jan Arne Petersen51963742012-08-10 16:47:20 +0200308 wl_client_add_object(client, &text_model_factory_interface,
309 &text_model_factory_implementation,
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200310 id, text_model_factory);
311}
312
313static void
314text_model_factory_notifier_destroy(struct wl_listener *listener, void *data)
315{
316 struct text_model_factory *text_model_factory =
317 container_of(listener, struct text_model_factory, destroy_listener);
318
319 wl_display_remove_global(text_model_factory->ec->wl_display,
320 text_model_factory->text_model_factory_global);
321
322 free(text_model_factory);
323}
324
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100325static void
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200326text_model_factory_create(struct weston_compositor *ec)
327{
328 struct text_model_factory *text_model_factory;
329
330 text_model_factory = calloc(1, sizeof *text_model_factory);
331
332 text_model_factory->ec = ec;
333
334 text_model_factory->text_model_factory_global =
335 wl_display_add_global(ec->wl_display,
336 &text_model_factory_interface,
337 text_model_factory, bind_text_model_factory);
338
339 text_model_factory->destroy_listener.notify = text_model_factory_notifier_destroy;
340 wl_signal_add(&ec->destroy_signal, &text_model_factory->destroy_listener);
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200341}
342
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200343static void
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200344input_method_context_destroy(struct wl_client *client,
345 struct wl_resource *resource)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200346{
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200347 wl_resource_destroy(resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200348}
349
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200350static void
351input_method_context_commit_string(struct wl_client *client,
352 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100353 uint32_t serial,
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200354 const char *text,
355 uint32_t index)
356{
357 struct input_method_context *context = resource->data;
358
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100359 text_model_send_commit_string(&context->model->resource, serial, text, index);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200360}
361
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200362static void
363input_method_context_preedit_string(struct wl_client *client,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100364 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100365 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100366 const char *text,
367 const char *commit)
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200368{
369 struct input_method_context *context = resource->data;
370
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100371 text_model_send_preedit_string(&context->model->resource, serial, text, commit);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100372}
373
374static void
375input_method_context_preedit_styling(struct wl_client *client,
376 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100377 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100378 uint32_t index,
379 uint32_t length,
380 uint32_t style)
381{
382 struct input_method_context *context = resource->data;
383
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100384 text_model_send_preedit_styling(&context->model->resource, serial, index, length, style);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100385}
386
387static void
388input_method_context_preedit_cursor(struct wl_client *client,
389 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100390 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100391 int32_t cursor)
392{
393 struct input_method_context *context = resource->data;
394
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100395 text_model_send_preedit_cursor(&context->model->resource, serial, cursor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200396}
397
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200398static void
399input_method_context_delete_surrounding_text(struct wl_client *client,
400 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100401 uint32_t serial,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200402 int32_t index,
403 uint32_t length)
404{
405 struct input_method_context *context = resource->data;
406
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100407 text_model_send_delete_surrounding_text(&context->model->resource, serial, index, length);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200408}
409
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200410static void
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100411input_method_context_modifiers_map(struct wl_client *client,
412 struct wl_resource *resource,
413 struct wl_array *map)
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200414{
415 struct input_method_context *context = resource->data;
416
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100417 text_model_send_modifiers_map(&context->model->resource, map);
418}
419
420static void
421input_method_context_keysym(struct wl_client *client,
422 struct wl_resource *resource,
423 uint32_t serial,
424 uint32_t time,
425 uint32_t sym,
426 uint32_t state,
427 uint32_t modifiers)
428{
429 struct input_method_context *context = resource->data;
430
431 text_model_send_keysym(&context->model->resource, serial, time,
432 sym, state, modifiers);
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200433}
434
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100435static void
436unbind_keyboard(struct wl_resource *resource)
437{
438 struct input_method_context *context = resource->data;
439
440 input_method_context_end_keyboard_grab(context);
441 context->keyboard = NULL;
442
443 free(resource);
444}
445
446static void
447input_method_context_grab_key(struct wl_keyboard_grab *grab,
448 uint32_t time, uint32_t key, uint32_t state_w)
449{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100450 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
451 struct wl_display *display;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100452 uint32_t serial;
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100453
454 if (!keyboard->input_method_resource)
455 return;
456
457 display = wl_client_get_display(keyboard->input_method_resource->client);
458 serial = wl_display_next_serial(display);
459 wl_keyboard_send_key(keyboard->input_method_resource,
460 serial, time, key, state_w);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100461}
462
463static void
464input_method_context_grab_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
465 uint32_t mods_depressed, uint32_t mods_latched,
466 uint32_t mods_locked, uint32_t group)
467{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100468 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100469
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100470 if (!keyboard->input_method_resource)
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100471 return;
472
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100473 wl_keyboard_send_modifiers(keyboard->input_method_resource,
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100474 serial, mods_depressed, mods_latched,
475 mods_locked, group);
476}
477
478static const struct wl_keyboard_grab_interface input_method_context_grab = {
479 input_method_context_grab_key,
480 input_method_context_grab_modifier,
481};
482
483static void
484input_method_context_grab_keyboard(struct wl_client *client,
485 struct wl_resource *resource,
486 uint32_t id)
487{
488 struct input_method_context *context = resource->data;
489 struct wl_resource *cr;
490 struct weston_seat *seat = context->input_method->seat;
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100491 struct weston_keyboard *keyboard = &seat->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100492
493 cr = wl_client_add_object(client, &wl_keyboard_interface,
494 NULL, id, context);
495 cr->destroy = unbind_keyboard;
496
497 context->keyboard = cr;
498
499 wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
500 seat->xkb_info.keymap_fd,
501 seat->xkb_info.keymap_size);
502
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100503 if (keyboard->keyboard.grab != &keyboard->keyboard.default_grab) {
504 wl_keyboard_end_grab(&keyboard->keyboard);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100505 }
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100506 wl_keyboard_start_grab(&keyboard->keyboard, &keyboard->input_method_grab);
507 keyboard->input_method_resource = cr;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100508}
509
Jan Arne Petersen337df952012-11-18 19:06:46 +0100510static void
511input_method_context_key(struct wl_client *client,
512 struct wl_resource *resource,
513 uint32_t serial,
514 uint32_t time,
515 uint32_t key,
516 uint32_t state_w)
517{
518 struct input_method_context *context = resource->data;
519 struct weston_seat *seat = context->input_method->seat;
520 struct wl_keyboard *keyboard = seat->seat.keyboard;
521 struct wl_keyboard_grab *default_grab = &keyboard->default_grab;
522
523 default_grab->interface->key(default_grab, time, key, state_w);
524}
525
526static void
527input_method_context_modifiers(struct wl_client *client,
528 struct wl_resource *resource,
529 uint32_t serial,
530 uint32_t mods_depressed,
531 uint32_t mods_latched,
532 uint32_t mods_locked,
533 uint32_t group)
534{
535 struct input_method_context *context = resource->data;
536
537 struct weston_seat *seat = context->input_method->seat;
538 struct wl_keyboard *keyboard = seat->seat.keyboard;
539 struct wl_keyboard_grab *default_grab = &keyboard->default_grab;
540
541 default_grab->interface->modifiers(default_grab,
542 serial, mods_depressed,
543 mods_latched, mods_locked,
544 group);
545}
546
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200547static const struct input_method_context_interface input_method_context_implementation = {
548 input_method_context_destroy,
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200549 input_method_context_commit_string,
550 input_method_context_preedit_string,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100551 input_method_context_preedit_styling,
552 input_method_context_preedit_cursor,
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200553 input_method_context_delete_surrounding_text,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100554 input_method_context_modifiers_map,
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100555 input_method_context_keysym,
Jan Arne Petersen337df952012-11-18 19:06:46 +0100556 input_method_context_grab_keyboard,
557 input_method_context_key,
558 input_method_context_modifiers
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200559};
560
561static void
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200562destroy_input_method_context(struct wl_resource *resource)
563{
564 struct input_method_context *context = resource->data;
565
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100566 if (context->keyboard) {
567 wl_resource_destroy(context->keyboard);
568 }
569
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200570 free(context);
571}
572
573static void
574input_method_context_create(struct text_model *model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100575 struct input_method *input_method,
576 uint32_t serial)
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200577{
578 struct input_method_context *context;
579
580 if (!input_method->input_method_binding)
581 return;
582
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100583 context = calloc(1, sizeof *context);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200584 if (context == NULL)
585 return;
586
587 context->resource.destroy = destroy_input_method_context;
588 context->resource.object.id = 0;
589 context->resource.object.interface = &input_method_context_interface;
590 context->resource.object.implementation =
591 (void (**)(void)) &input_method_context_implementation;
592 context->resource.data = context;
593 wl_signal_init(&context->resource.destroy_signal);
594
595 context->model = model;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100596 context->input_method = input_method;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200597 input_method->context = context;
598
599 wl_client_add_resource(input_method->input_method_binding->client, &context->resource);
600
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100601 input_method_send_activate(input_method->input_method_binding, &context->resource, serial);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200602}
603
604static void
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100605input_method_context_end_keyboard_grab(struct input_method_context *context)
606{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100607 struct wl_keyboard_grab *grab = &context->input_method->seat->keyboard.input_method_grab;
608 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100609
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100610 if (!grab->keyboard)
611 return;
612
613 if (grab->keyboard->grab == grab)
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100614 wl_keyboard_end_grab(grab->keyboard);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100615
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100616 keyboard->input_method_resource = NULL;
617}
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100618
619static void
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200620unbind_input_method(struct wl_resource *resource)
621{
622 struct input_method *input_method = resource->data;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100623 struct text_backend *text_backend = input_method->text_backend;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200624
625 input_method->input_method_binding = NULL;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200626 input_method->context = NULL;
627
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100628 text_backend->input_method.binding = NULL;
629
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200630 free(resource);
631}
632
633static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200634bind_input_method(struct wl_client *client,
635 void *data,
636 uint32_t version,
637 uint32_t id)
638{
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200639 struct input_method *input_method = data;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100640 struct text_backend *text_backend = input_method->text_backend;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200641 struct wl_resource *resource;
642
643 resource = wl_client_add_object(client, &input_method_interface,
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200644 NULL,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200645 id, input_method);
646
647 if (input_method->input_method_binding == NULL) {
648 resource->destroy = unbind_input_method;
649 input_method->input_method_binding = resource;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100650
651 text_backend->input_method.binding = resource;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200652 return;
653 }
654
655 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
656 "interface object already bound");
657 wl_resource_destroy(resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200658}
659
660static void
661input_method_notifier_destroy(struct wl_listener *listener, void *data)
662{
Kristian Høgsbergf97f3792012-07-22 11:51:42 -0400663 struct input_method *input_method =
664 container_of(listener, struct input_method, destroy_listener);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200665
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200666 if (input_method->model)
667 deactivate_text_model(input_method->model, input_method);
668
669 wl_display_remove_global(input_method->seat->compositor->wl_display,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200670 input_method->input_method_global);
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200671
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200672 free(input_method);
673}
674
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200675static void
676handle_keyboard_focus(struct wl_listener *listener, void *data)
677{
678 struct wl_keyboard *keyboard = data;
679 struct input_method *input_method =
680 container_of(listener, struct input_method, keyboard_focus_listener);
681 struct wl_surface *surface = keyboard->focus;
682
683 if (!input_method->model)
684 return;
685
686 if (!surface || input_method->model->surface != surface)
687 deactivate_text_model(input_method->model,
688 input_method);
689}
690
691static void
692input_method_init_seat(struct weston_seat *seat)
693{
694 if (seat->input_method->focus_listener_initialized)
695 return;
696
697 if (seat->has_keyboard) {
698 seat->input_method->keyboard_focus_listener.notify = handle_keyboard_focus;
699 wl_signal_add(&seat->seat.keyboard->focus_signal, &seat->input_method->keyboard_focus_listener);
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100700 seat->keyboard.input_method_grab.interface = &input_method_context_grab;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200701 }
702
703 seat->input_method->focus_listener_initialized = 1;
704}
705
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100706static void
707handle_input_method_sigchld(struct weston_process *process, int status)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200708{
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100709 struct text_backend *text_backend =
710 container_of(process, struct text_backend, input_method.process);
711
712 text_backend->input_method.process.pid = 0;
713 text_backend->input_method.client = NULL;
714}
715
716static void
717launch_input_method(struct text_backend *text_backend)
718{
719 if (text_backend->input_method.binding)
720 return;
721
722 if (!text_backend->input_method.path)
723 return;
724
725 if (text_backend->input_method.process.pid != 0)
726 return;
727
728 text_backend->input_method.client = weston_client_launch(text_backend->compositor,
729 &text_backend->input_method.process,
730 text_backend->input_method.path,
731 handle_input_method_sigchld);
732
733 if (!text_backend->input_method.client)
734 weston_log("not able to start %s\n", text_backend->input_method.path);
735}
736
737static void
738handle_seat_created(struct wl_listener *listener,
739 void *data)
740{
741 struct weston_seat *seat = data;
742 struct text_backend *text_backend =
743 container_of(listener, struct text_backend,
744 seat_created_listener);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200745 struct input_method *input_method;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100746 struct weston_compositor *ec = seat->compositor;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200747
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200748 input_method = calloc(1, sizeof *input_method);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200749
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200750 input_method->seat = seat;
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200751 input_method->model = NULL;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200752 input_method->focus_listener_initialized = 0;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200753 input_method->context = NULL;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100754 input_method->text_backend = text_backend;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200755
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200756 input_method->input_method_global =
757 wl_display_add_global(ec->wl_display,
758 &input_method_interface,
759 input_method, bind_input_method);
760
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200761 input_method->destroy_listener.notify = input_method_notifier_destroy;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200762 wl_signal_add(&seat->seat.destroy_signal, &input_method->destroy_listener);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200763
764 seat->input_method = input_method;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100765
766 launch_input_method(text_backend);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200767}
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200768
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100769static void
770text_backend_configuration(struct text_backend *text_backend)
771{
772 char *config_file;
773 char *path = NULL;
774
775 struct config_key input_method_keys[] = {
776 { "path", CONFIG_KEY_STRING, &path }
777 };
778
779 struct config_section cs[] = {
780 { "input-method", input_method_keys, ARRAY_LENGTH(input_method_keys), NULL }
781 };
782
783 config_file = config_file_path("weston.ini");
784 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), text_backend);
785 free(config_file);
786
787 if (path)
788 text_backend->input_method.path = path;
789 else
790 text_backend->input_method.path = strdup(LIBEXECDIR "/weston-keyboard");
791}
792
793static void
794text_backend_notifier_destroy(struct wl_listener *listener, void *data)
795{
796 struct text_backend *text_backend =
797 container_of(listener, struct text_backend, destroy_listener);
798
799 if (text_backend->input_method.client)
800 wl_client_destroy(text_backend->input_method.client);
801
802 free(text_backend->input_method.path);
803
804 free(text_backend);
805}
806
807
808WL_EXPORT int
809text_backend_init(struct weston_compositor *ec)
810{
811 struct text_backend *text_backend;
812
813 text_backend = calloc(1, sizeof(*text_backend));
814
815 text_backend->compositor = ec;
816
817 text_backend->seat_created_listener.notify = handle_seat_created;
818 wl_signal_add(&ec->seat_created_signal,
819 &text_backend->seat_created_listener);
820
821 text_backend->destroy_listener.notify = text_backend_notifier_destroy;
822 wl_signal_add(&ec->destroy_signal, &text_backend->destroy_listener);
823
824 text_backend_configuration(text_backend);
825
826 text_model_factory_create(ec);
827
828 return 0;
829}