blob: a92aebed2cf700e96ff2cb0df8517fe7cd493dbf [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 Petersen61381972013-01-31 15:52:21 +010043
44 uint32_t input_panel_visible;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020045};
46
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +020047struct text_model_factory {
Jan Arne Petersen51963742012-08-10 16:47:20 +020048 struct wl_global *text_model_factory_global;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020049 struct wl_listener destroy_listener;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020050
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +020051 struct weston_compositor *ec;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +020052};
53
54struct input_method {
55 struct wl_resource *input_method_binding;
56 struct wl_global *input_method_global;
57 struct wl_listener destroy_listener;
58
59 struct weston_seat *seat;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020060 struct text_model *model;
61
62 struct wl_list link;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +020063
64 struct wl_listener keyboard_focus_listener;
65
66 int focus_listener_initialized;
Jan Arne Petersen620cd622012-09-09 23:08:32 +020067
68 struct input_method_context *context;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +010069
70 struct text_backend *text_backend;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +020071};
72
Jan Arne Petersen620cd622012-09-09 23:08:32 +020073struct input_method_context {
74 struct wl_resource resource;
75
76 struct text_model *model;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +010077 struct input_method *input_method;
Jan Arne Petersen620cd622012-09-09 23:08:32 +020078
79 struct wl_list link;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +010080
81 struct wl_resource *keyboard;
Jan Arne Petersen620cd622012-09-09 23:08:32 +020082};
83
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +010084struct text_backend {
85 struct weston_compositor *compositor;
86
87 struct {
88 char *path;
89 struct wl_resource *binding;
90 struct weston_process process;
91 struct wl_client *client;
92 } input_method;
93
94 struct wl_listener seat_created_listener;
95 struct wl_listener destroy_listener;
96};
97
Jan Arne Petersen620cd622012-09-09 23:08:32 +020098static void input_method_context_create(struct text_model *model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010099 struct input_method *input_method,
100 uint32_t serial);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100101static void input_method_context_end_keyboard_grab(struct input_method_context *context);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200102
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200103static void input_method_init_seat(struct weston_seat *seat);
104
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200105static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200106deactivate_text_model(struct text_model *text_model,
107 struct input_method *input_method)
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200108{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200109 struct weston_compositor *ec = text_model->ec;
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200110
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200111 if (input_method->model == text_model) {
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100112 if (input_method->context && input_method->input_method_binding) {
113 input_method_context_end_keyboard_grab(input_method->context);
114 input_method_send_deactivate(input_method->input_method_binding,
115 &input_method->context->resource);
116 }
117
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200118 wl_list_remove(&input_method->link);
119 input_method->model = NULL;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200120 input_method->context = NULL;
Kristian Høgsbergf97f3792012-07-22 11:51:42 -0400121 wl_signal_emit(&ec->hide_input_panel_signal, ec);
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200122 text_model_send_leave(&text_model->resource);
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200123 }
124}
125
126static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200127destroy_text_model(struct wl_resource *resource)
128{
Kristian Høgsbergf97f3792012-07-22 11:51:42 -0400129 struct text_model *text_model =
130 container_of(resource, struct text_model, resource);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200131 struct input_method *input_method, *next;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200132
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200133 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link)
134 deactivate_text_model(text_model, input_method);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200135
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200136 free(text_model);
137}
138
139static void
140text_model_set_surrounding_text(struct wl_client *client,
141 struct wl_resource *resource,
Jan Arne Petersencb08f4d2012-09-09 23:08:40 +0200142 const char *text,
143 uint32_t cursor,
144 uint32_t anchor)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200145{
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200146 struct text_model *text_model = resource->data;
147 struct input_method *input_method, *next;
148
149 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
150 if (!input_method->context)
151 continue;
Jan Arne Petersencb08f4d2012-09-09 23:08:40 +0200152 input_method_context_send_surrounding_text(&input_method->context->resource,
153 text,
154 cursor,
155 anchor);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200156 }
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200157}
158
159static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200160text_model_activate(struct wl_client *client,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200161 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100162 uint32_t serial,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200163 struct wl_resource *seat,
164 struct wl_resource *surface)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200165{
166 struct text_model *text_model = resource->data;
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200167 struct weston_seat *weston_seat = seat->data;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200168 struct input_method *input_method = weston_seat->input_method;
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200169 struct text_model *old = weston_seat->input_method->model;
170 struct weston_compositor *ec = text_model->ec;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200171
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200172 if (old == text_model)
173 return;
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200174
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200175 if (old) {
176 deactivate_text_model(old,
177 weston_seat->input_method);
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200178 }
179
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200180 input_method->model = text_model;
181 wl_list_insert(&text_model->input_methods, &input_method->link);
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200182 input_method_init_seat(weston_seat);
183
184 text_model->surface = surface->data;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200185
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100186 input_method_context_create(text_model, input_method, serial);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200187
Jan Arne Petersen61381972013-01-31 15:52:21 +0100188 if (text_model->input_panel_visible)
189 wl_signal_emit(&ec->show_input_panel_signal, ec);
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200190
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200191 text_model_send_enter(&text_model->resource, &text_model->surface->resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200192}
193
194static void
195text_model_deactivate(struct wl_client *client,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200196 struct wl_resource *resource,
197 struct wl_resource *seat)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200198{
199 struct text_model *text_model = resource->data;
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200200 struct weston_seat *weston_seat = seat->data;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200201
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200202 deactivate_text_model(text_model,
203 weston_seat->input_method);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200204}
205
206static void
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200207text_model_reset(struct wl_client *client,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100208 struct wl_resource *resource,
209 uint32_t serial)
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200210{
211 struct text_model *text_model = resource->data;
212 struct input_method *input_method, *next;
213
214 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
215 if (!input_method->context)
216 continue;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100217 input_method_context_send_reset(&input_method->context->resource, serial);
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200218 }
219}
220
221static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200222text_model_set_micro_focus(struct wl_client *client,
223 struct wl_resource *resource,
224 int32_t x,
225 int32_t y,
226 int32_t width,
227 int32_t height)
228{
229}
230
231static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200232text_model_set_content_type(struct wl_client *client,
Jan Arne Petersen26ffa812013-01-16 21:26:43 +0100233 struct wl_resource *resource,
234 uint32_t hint,
235 uint32_t purpose)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200236{
Jan Arne Petersen26ffa812013-01-16 21:26:43 +0100237 struct text_model *text_model = resource->data;
238 struct input_method *input_method, *next;
239
240 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
241 if (!input_method->context)
242 continue;
243 input_method_context_send_content_type(&input_method->context->resource, hint, purpose);
244 }
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200245}
246
Jan Arne Petersenadfedc12013-01-16 21:26:46 +0100247static void
248text_model_invoke_action(struct wl_client *client,
249 struct wl_resource *resource,
250 uint32_t button,
251 uint32_t index)
252{
253 struct text_model *text_model = resource->data;
254 struct input_method *input_method, *next;
255
256 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
257 if (!input_method->context)
258 continue;
259 input_method_context_send_invoke_action(&input_method->context->resource, button, index);
260 }
261}
262
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100263static void
264text_model_commit(struct wl_client *client,
265 struct wl_resource *resource)
266{
267 struct text_model *text_model = resource->data;
268 struct input_method *input_method, *next;
269
270 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
271 if (!input_method->context)
272 continue;
273 input_method_context_send_commit(&input_method->context->resource);
274 }
275}
276
Jan Arne Petersen61381972013-01-31 15:52:21 +0100277static void
278text_model_show_input_panel(struct wl_client *client,
279 struct wl_resource *resource)
280{
281 struct text_model *text_model = resource->data;
282 struct weston_compositor *ec = text_model->ec;
283
284 text_model->input_panel_visible = 1;
285
286 if (!wl_list_empty(&text_model->input_methods))
287 wl_signal_emit(&ec->show_input_panel_signal, ec);
288}
289
290static void
291text_model_hide_input_panel(struct wl_client *client,
292 struct wl_resource *resource)
293{
294 struct text_model *text_model = resource->data;
295 struct weston_compositor *ec = text_model->ec;
296
297 text_model->input_panel_visible = 0;
298
299 if (!wl_list_empty(&text_model->input_methods))
300 wl_signal_emit(&ec->hide_input_panel_signal, ec);
301}
302
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200303static const struct text_model_interface text_model_implementation = {
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200304 text_model_set_surrounding_text,
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200305 text_model_activate,
306 text_model_deactivate,
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200307 text_model_reset,
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200308 text_model_set_micro_focus,
Jan Arne Petersenadfedc12013-01-16 21:26:46 +0100309 text_model_set_content_type,
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100310 text_model_invoke_action,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100311 text_model_commit,
312 text_model_show_input_panel,
313 text_model_hide_input_panel
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200314};
315
Jan Arne Petersen51963742012-08-10 16:47:20 +0200316static void text_model_factory_create_text_model(struct wl_client *client,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200317 struct wl_resource *resource,
Jan Arne Petersen4c265182012-09-09 23:08:30 +0200318 uint32_t id)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200319{
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200320 struct text_model_factory *text_model_factory = resource->data;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200321 struct text_model *text_model;
322
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200323 text_model = calloc(1, sizeof *text_model);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200324
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200325 text_model->resource.object.id = id;
326 text_model->resource.object.interface = &text_model_interface;
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200327 text_model->resource.object.implementation =
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200328 (void (**)(void)) &text_model_implementation;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200329
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200330 text_model->resource.data = text_model;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200331 text_model->resource.destroy = destroy_text_model;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200332
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200333 text_model->ec = text_model_factory->ec;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200334
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200335 wl_list_init(&text_model->input_methods);
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200336
337 wl_client_add_resource(client, &text_model->resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200338};
339
Jan Arne Petersen51963742012-08-10 16:47:20 +0200340static const struct text_model_factory_interface text_model_factory_implementation = {
341 text_model_factory_create_text_model
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200342};
343
344static void
Jan Arne Petersen51963742012-08-10 16:47:20 +0200345bind_text_model_factory(struct wl_client *client,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200346 void *data,
347 uint32_t version,
348 uint32_t id)
349{
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200350 struct text_model_factory *text_model_factory = data;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200351
352 /* No checking for duplicate binding necessary.
353 * No events have to be sent, so we don't need the return value. */
Jan Arne Petersen51963742012-08-10 16:47:20 +0200354 wl_client_add_object(client, &text_model_factory_interface,
355 &text_model_factory_implementation,
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200356 id, text_model_factory);
357}
358
359static void
360text_model_factory_notifier_destroy(struct wl_listener *listener, void *data)
361{
362 struct text_model_factory *text_model_factory =
363 container_of(listener, struct text_model_factory, destroy_listener);
364
365 wl_display_remove_global(text_model_factory->ec->wl_display,
366 text_model_factory->text_model_factory_global);
367
368 free(text_model_factory);
369}
370
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100371static void
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200372text_model_factory_create(struct weston_compositor *ec)
373{
374 struct text_model_factory *text_model_factory;
375
376 text_model_factory = calloc(1, sizeof *text_model_factory);
377
378 text_model_factory->ec = ec;
379
380 text_model_factory->text_model_factory_global =
381 wl_display_add_global(ec->wl_display,
382 &text_model_factory_interface,
383 text_model_factory, bind_text_model_factory);
384
385 text_model_factory->destroy_listener.notify = text_model_factory_notifier_destroy;
386 wl_signal_add(&ec->destroy_signal, &text_model_factory->destroy_listener);
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200387}
388
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200389static void
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200390input_method_context_destroy(struct wl_client *client,
391 struct wl_resource *resource)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200392{
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200393 wl_resource_destroy(resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200394}
395
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200396static void
397input_method_context_commit_string(struct wl_client *client,
398 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100399 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100400 const char *text)
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200401{
402 struct input_method_context *context = resource->data;
403
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100404 text_model_send_commit_string(&context->model->resource, serial, text);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200405}
406
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200407static void
408input_method_context_preedit_string(struct wl_client *client,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100409 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100410 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100411 const char *text,
412 const char *commit)
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200413{
414 struct input_method_context *context = resource->data;
415
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100416 text_model_send_preedit_string(&context->model->resource, serial, text, commit);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100417}
418
419static void
420input_method_context_preedit_styling(struct wl_client *client,
421 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100422 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100423 uint32_t index,
424 uint32_t length,
425 uint32_t style)
426{
427 struct input_method_context *context = resource->data;
428
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100429 text_model_send_preedit_styling(&context->model->resource, serial, index, length, style);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100430}
431
432static void
433input_method_context_preedit_cursor(struct wl_client *client,
434 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100435 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100436 int32_t cursor)
437{
438 struct input_method_context *context = resource->data;
439
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100440 text_model_send_preedit_cursor(&context->model->resource, serial, cursor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200441}
442
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200443static void
444input_method_context_delete_surrounding_text(struct wl_client *client,
445 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100446 uint32_t serial,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200447 int32_t index,
448 uint32_t length)
449{
450 struct input_method_context *context = resource->data;
451
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100452 text_model_send_delete_surrounding_text(&context->model->resource, serial, index, length);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200453}
454
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200455static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100456input_method_context_cursor_position(struct wl_client *client,
457 struct wl_resource *resource,
458 uint32_t serial,
459 int32_t index,
460 int32_t anchor)
461{
462 struct input_method_context *context = resource->data;
463
464 text_model_send_cursor_position(&context->model->resource, serial, index, anchor);
465}
466
467static void
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100468input_method_context_modifiers_map(struct wl_client *client,
469 struct wl_resource *resource,
470 struct wl_array *map)
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200471{
472 struct input_method_context *context = resource->data;
473
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100474 text_model_send_modifiers_map(&context->model->resource, map);
475}
476
477static void
478input_method_context_keysym(struct wl_client *client,
479 struct wl_resource *resource,
480 uint32_t serial,
481 uint32_t time,
482 uint32_t sym,
483 uint32_t state,
484 uint32_t modifiers)
485{
486 struct input_method_context *context = resource->data;
487
488 text_model_send_keysym(&context->model->resource, serial, time,
489 sym, state, modifiers);
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200490}
491
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100492static void
493unbind_keyboard(struct wl_resource *resource)
494{
495 struct input_method_context *context = resource->data;
496
497 input_method_context_end_keyboard_grab(context);
498 context->keyboard = NULL;
499
500 free(resource);
501}
502
503static void
504input_method_context_grab_key(struct wl_keyboard_grab *grab,
505 uint32_t time, uint32_t key, uint32_t state_w)
506{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100507 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
508 struct wl_display *display;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100509 uint32_t serial;
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100510
511 if (!keyboard->input_method_resource)
512 return;
513
514 display = wl_client_get_display(keyboard->input_method_resource->client);
515 serial = wl_display_next_serial(display);
516 wl_keyboard_send_key(keyboard->input_method_resource,
517 serial, time, key, state_w);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100518}
519
520static void
521input_method_context_grab_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
522 uint32_t mods_depressed, uint32_t mods_latched,
523 uint32_t mods_locked, uint32_t group)
524{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100525 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100526
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100527 if (!keyboard->input_method_resource)
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100528 return;
529
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100530 wl_keyboard_send_modifiers(keyboard->input_method_resource,
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100531 serial, mods_depressed, mods_latched,
532 mods_locked, group);
533}
534
535static const struct wl_keyboard_grab_interface input_method_context_grab = {
536 input_method_context_grab_key,
537 input_method_context_grab_modifier,
538};
539
540static void
541input_method_context_grab_keyboard(struct wl_client *client,
542 struct wl_resource *resource,
543 uint32_t id)
544{
545 struct input_method_context *context = resource->data;
546 struct wl_resource *cr;
547 struct weston_seat *seat = context->input_method->seat;
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100548 struct weston_keyboard *keyboard = &seat->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100549
550 cr = wl_client_add_object(client, &wl_keyboard_interface,
551 NULL, id, context);
552 cr->destroy = unbind_keyboard;
553
554 context->keyboard = cr;
555
556 wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
557 seat->xkb_info.keymap_fd,
558 seat->xkb_info.keymap_size);
559
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100560 if (keyboard->keyboard.grab != &keyboard->keyboard.default_grab) {
561 wl_keyboard_end_grab(&keyboard->keyboard);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100562 }
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100563 wl_keyboard_start_grab(&keyboard->keyboard, &keyboard->input_method_grab);
564 keyboard->input_method_resource = cr;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100565}
566
Jan Arne Petersen337df952012-11-18 19:06:46 +0100567static void
568input_method_context_key(struct wl_client *client,
569 struct wl_resource *resource,
570 uint32_t serial,
571 uint32_t time,
572 uint32_t key,
573 uint32_t state_w)
574{
575 struct input_method_context *context = resource->data;
576 struct weston_seat *seat = context->input_method->seat;
577 struct wl_keyboard *keyboard = seat->seat.keyboard;
578 struct wl_keyboard_grab *default_grab = &keyboard->default_grab;
579
580 default_grab->interface->key(default_grab, time, key, state_w);
581}
582
583static void
584input_method_context_modifiers(struct wl_client *client,
585 struct wl_resource *resource,
586 uint32_t serial,
587 uint32_t mods_depressed,
588 uint32_t mods_latched,
589 uint32_t mods_locked,
590 uint32_t group)
591{
592 struct input_method_context *context = resource->data;
593
594 struct weston_seat *seat = context->input_method->seat;
595 struct wl_keyboard *keyboard = seat->seat.keyboard;
596 struct wl_keyboard_grab *default_grab = &keyboard->default_grab;
597
598 default_grab->interface->modifiers(default_grab,
599 serial, mods_depressed,
600 mods_latched, mods_locked,
601 group);
602}
603
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200604static const struct input_method_context_interface input_method_context_implementation = {
605 input_method_context_destroy,
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200606 input_method_context_commit_string,
607 input_method_context_preedit_string,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100608 input_method_context_preedit_styling,
609 input_method_context_preedit_cursor,
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200610 input_method_context_delete_surrounding_text,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100611 input_method_context_cursor_position,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100612 input_method_context_modifiers_map,
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100613 input_method_context_keysym,
Jan Arne Petersen337df952012-11-18 19:06:46 +0100614 input_method_context_grab_keyboard,
615 input_method_context_key,
616 input_method_context_modifiers
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200617};
618
619static void
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200620destroy_input_method_context(struct wl_resource *resource)
621{
622 struct input_method_context *context = resource->data;
623
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100624 if (context->keyboard) {
625 wl_resource_destroy(context->keyboard);
626 }
627
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200628 free(context);
629}
630
631static void
632input_method_context_create(struct text_model *model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100633 struct input_method *input_method,
634 uint32_t serial)
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200635{
636 struct input_method_context *context;
637
638 if (!input_method->input_method_binding)
639 return;
640
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100641 context = calloc(1, sizeof *context);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200642 if (context == NULL)
643 return;
644
645 context->resource.destroy = destroy_input_method_context;
646 context->resource.object.id = 0;
647 context->resource.object.interface = &input_method_context_interface;
648 context->resource.object.implementation =
649 (void (**)(void)) &input_method_context_implementation;
650 context->resource.data = context;
651 wl_signal_init(&context->resource.destroy_signal);
652
653 context->model = model;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100654 context->input_method = input_method;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200655 input_method->context = context;
656
657 wl_client_add_resource(input_method->input_method_binding->client, &context->resource);
658
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100659 input_method_send_activate(input_method->input_method_binding, &context->resource, serial);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200660}
661
662static void
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100663input_method_context_end_keyboard_grab(struct input_method_context *context)
664{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100665 struct wl_keyboard_grab *grab = &context->input_method->seat->keyboard.input_method_grab;
666 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100667
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100668 if (!grab->keyboard)
669 return;
670
671 if (grab->keyboard->grab == grab)
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100672 wl_keyboard_end_grab(grab->keyboard);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100673
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100674 keyboard->input_method_resource = NULL;
675}
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100676
677static void
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200678unbind_input_method(struct wl_resource *resource)
679{
680 struct input_method *input_method = resource->data;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100681 struct text_backend *text_backend = input_method->text_backend;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200682
683 input_method->input_method_binding = NULL;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200684 input_method->context = NULL;
685
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100686 text_backend->input_method.binding = NULL;
687
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200688 free(resource);
689}
690
691static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200692bind_input_method(struct wl_client *client,
693 void *data,
694 uint32_t version,
695 uint32_t id)
696{
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200697 struct input_method *input_method = data;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100698 struct text_backend *text_backend = input_method->text_backend;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200699 struct wl_resource *resource;
700
701 resource = wl_client_add_object(client, &input_method_interface,
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200702 NULL,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200703 id, input_method);
704
705 if (input_method->input_method_binding == NULL) {
706 resource->destroy = unbind_input_method;
707 input_method->input_method_binding = resource;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100708
709 text_backend->input_method.binding = resource;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200710 return;
711 }
712
713 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
714 "interface object already bound");
715 wl_resource_destroy(resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200716}
717
718static void
719input_method_notifier_destroy(struct wl_listener *listener, void *data)
720{
Kristian Høgsbergf97f3792012-07-22 11:51:42 -0400721 struct input_method *input_method =
722 container_of(listener, struct input_method, destroy_listener);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200723
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200724 if (input_method->model)
725 deactivate_text_model(input_method->model, input_method);
726
727 wl_display_remove_global(input_method->seat->compositor->wl_display,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200728 input_method->input_method_global);
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200729
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200730 free(input_method);
731}
732
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200733static void
734handle_keyboard_focus(struct wl_listener *listener, void *data)
735{
736 struct wl_keyboard *keyboard = data;
737 struct input_method *input_method =
738 container_of(listener, struct input_method, keyboard_focus_listener);
739 struct wl_surface *surface = keyboard->focus;
740
741 if (!input_method->model)
742 return;
743
744 if (!surface || input_method->model->surface != surface)
745 deactivate_text_model(input_method->model,
746 input_method);
747}
748
749static void
750input_method_init_seat(struct weston_seat *seat)
751{
752 if (seat->input_method->focus_listener_initialized)
753 return;
754
755 if (seat->has_keyboard) {
756 seat->input_method->keyboard_focus_listener.notify = handle_keyboard_focus;
757 wl_signal_add(&seat->seat.keyboard->focus_signal, &seat->input_method->keyboard_focus_listener);
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100758 seat->keyboard.input_method_grab.interface = &input_method_context_grab;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200759 }
760
761 seat->input_method->focus_listener_initialized = 1;
762}
763
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100764static void
765handle_input_method_sigchld(struct weston_process *process, int status)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200766{
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100767 struct text_backend *text_backend =
768 container_of(process, struct text_backend, input_method.process);
769
770 text_backend->input_method.process.pid = 0;
771 text_backend->input_method.client = NULL;
772}
773
774static void
775launch_input_method(struct text_backend *text_backend)
776{
777 if (text_backend->input_method.binding)
778 return;
779
780 if (!text_backend->input_method.path)
781 return;
782
783 if (text_backend->input_method.process.pid != 0)
784 return;
785
786 text_backend->input_method.client = weston_client_launch(text_backend->compositor,
787 &text_backend->input_method.process,
788 text_backend->input_method.path,
789 handle_input_method_sigchld);
790
791 if (!text_backend->input_method.client)
792 weston_log("not able to start %s\n", text_backend->input_method.path);
793}
794
795static void
796handle_seat_created(struct wl_listener *listener,
797 void *data)
798{
799 struct weston_seat *seat = data;
800 struct text_backend *text_backend =
801 container_of(listener, struct text_backend,
802 seat_created_listener);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200803 struct input_method *input_method;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100804 struct weston_compositor *ec = seat->compositor;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200805
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200806 input_method = calloc(1, sizeof *input_method);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200807
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200808 input_method->seat = seat;
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200809 input_method->model = NULL;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200810 input_method->focus_listener_initialized = 0;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200811 input_method->context = NULL;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100812 input_method->text_backend = text_backend;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200813
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200814 input_method->input_method_global =
815 wl_display_add_global(ec->wl_display,
816 &input_method_interface,
817 input_method, bind_input_method);
818
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200819 input_method->destroy_listener.notify = input_method_notifier_destroy;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200820 wl_signal_add(&seat->seat.destroy_signal, &input_method->destroy_listener);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200821
822 seat->input_method = input_method;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100823
824 launch_input_method(text_backend);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200825}
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200826
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100827static void
828text_backend_configuration(struct text_backend *text_backend)
829{
830 char *config_file;
831 char *path = NULL;
832
833 struct config_key input_method_keys[] = {
834 { "path", CONFIG_KEY_STRING, &path }
835 };
836
837 struct config_section cs[] = {
838 { "input-method", input_method_keys, ARRAY_LENGTH(input_method_keys), NULL }
839 };
840
841 config_file = config_file_path("weston.ini");
842 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), text_backend);
843 free(config_file);
844
845 if (path)
846 text_backend->input_method.path = path;
847 else
848 text_backend->input_method.path = strdup(LIBEXECDIR "/weston-keyboard");
849}
850
851static void
852text_backend_notifier_destroy(struct wl_listener *listener, void *data)
853{
854 struct text_backend *text_backend =
855 container_of(listener, struct text_backend, destroy_listener);
856
857 if (text_backend->input_method.client)
858 wl_client_destroy(text_backend->input_method.client);
859
860 free(text_backend->input_method.path);
861
862 free(text_backend);
863}
864
865
866WL_EXPORT int
867text_backend_init(struct weston_compositor *ec)
868{
869 struct text_backend *text_backend;
870
871 text_backend = calloc(1, sizeof(*text_backend));
872
873 text_backend->compositor = ec;
874
875 text_backend->seat_created_listener.notify = handle_seat_created;
876 wl_signal_add(&ec->seat_created_signal,
877 &text_backend->seat_created_listener);
878
879 text_backend->destroy_listener.notify = text_backend_notifier_destroy;
880 wl_signal_add(&ec->destroy_signal, &text_backend->destroy_listener);
881
882 text_backend_configuration(text_backend);
883
884 text_model_factory_create(ec);
885
886 return 0;
887}