blob: 00ca46e4f1b8b41b1f370f39311aff27c9ac2359 [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 Petersen620cd622012-09-09 23:08:32 +0200400 const char *text,
401 uint32_t index)
402{
403 struct input_method_context *context = resource->data;
404
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100405 text_model_send_commit_string(&context->model->resource, serial, text, index);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200406}
407
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200408static void
409input_method_context_preedit_string(struct wl_client *client,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100410 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100411 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100412 const char *text,
413 const char *commit)
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200414{
415 struct input_method_context *context = resource->data;
416
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100417 text_model_send_preedit_string(&context->model->resource, serial, text, commit);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100418}
419
420static void
421input_method_context_preedit_styling(struct wl_client *client,
422 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100423 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100424 uint32_t index,
425 uint32_t length,
426 uint32_t style)
427{
428 struct input_method_context *context = resource->data;
429
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100430 text_model_send_preedit_styling(&context->model->resource, serial, index, length, style);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100431}
432
433static void
434input_method_context_preedit_cursor(struct wl_client *client,
435 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100436 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100437 int32_t cursor)
438{
439 struct input_method_context *context = resource->data;
440
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100441 text_model_send_preedit_cursor(&context->model->resource, serial, cursor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200442}
443
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200444static void
445input_method_context_delete_surrounding_text(struct wl_client *client,
446 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100447 uint32_t serial,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200448 int32_t index,
449 uint32_t length)
450{
451 struct input_method_context *context = resource->data;
452
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100453 text_model_send_delete_surrounding_text(&context->model->resource, serial, index, length);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200454}
455
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200456static void
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100457input_method_context_modifiers_map(struct wl_client *client,
458 struct wl_resource *resource,
459 struct wl_array *map)
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200460{
461 struct input_method_context *context = resource->data;
462
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100463 text_model_send_modifiers_map(&context->model->resource, map);
464}
465
466static void
467input_method_context_keysym(struct wl_client *client,
468 struct wl_resource *resource,
469 uint32_t serial,
470 uint32_t time,
471 uint32_t sym,
472 uint32_t state,
473 uint32_t modifiers)
474{
475 struct input_method_context *context = resource->data;
476
477 text_model_send_keysym(&context->model->resource, serial, time,
478 sym, state, modifiers);
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200479}
480
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100481static void
482unbind_keyboard(struct wl_resource *resource)
483{
484 struct input_method_context *context = resource->data;
485
486 input_method_context_end_keyboard_grab(context);
487 context->keyboard = NULL;
488
489 free(resource);
490}
491
492static void
493input_method_context_grab_key(struct wl_keyboard_grab *grab,
494 uint32_t time, uint32_t key, uint32_t state_w)
495{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100496 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
497 struct wl_display *display;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100498 uint32_t serial;
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100499
500 if (!keyboard->input_method_resource)
501 return;
502
503 display = wl_client_get_display(keyboard->input_method_resource->client);
504 serial = wl_display_next_serial(display);
505 wl_keyboard_send_key(keyboard->input_method_resource,
506 serial, time, key, state_w);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100507}
508
509static void
510input_method_context_grab_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
511 uint32_t mods_depressed, uint32_t mods_latched,
512 uint32_t mods_locked, uint32_t group)
513{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100514 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100515
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100516 if (!keyboard->input_method_resource)
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100517 return;
518
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100519 wl_keyboard_send_modifiers(keyboard->input_method_resource,
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100520 serial, mods_depressed, mods_latched,
521 mods_locked, group);
522}
523
524static const struct wl_keyboard_grab_interface input_method_context_grab = {
525 input_method_context_grab_key,
526 input_method_context_grab_modifier,
527};
528
529static void
530input_method_context_grab_keyboard(struct wl_client *client,
531 struct wl_resource *resource,
532 uint32_t id)
533{
534 struct input_method_context *context = resource->data;
535 struct wl_resource *cr;
536 struct weston_seat *seat = context->input_method->seat;
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100537 struct weston_keyboard *keyboard = &seat->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100538
539 cr = wl_client_add_object(client, &wl_keyboard_interface,
540 NULL, id, context);
541 cr->destroy = unbind_keyboard;
542
543 context->keyboard = cr;
544
545 wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
546 seat->xkb_info.keymap_fd,
547 seat->xkb_info.keymap_size);
548
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100549 if (keyboard->keyboard.grab != &keyboard->keyboard.default_grab) {
550 wl_keyboard_end_grab(&keyboard->keyboard);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100551 }
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100552 wl_keyboard_start_grab(&keyboard->keyboard, &keyboard->input_method_grab);
553 keyboard->input_method_resource = cr;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100554}
555
Jan Arne Petersen337df952012-11-18 19:06:46 +0100556static void
557input_method_context_key(struct wl_client *client,
558 struct wl_resource *resource,
559 uint32_t serial,
560 uint32_t time,
561 uint32_t key,
562 uint32_t state_w)
563{
564 struct input_method_context *context = resource->data;
565 struct weston_seat *seat = context->input_method->seat;
566 struct wl_keyboard *keyboard = seat->seat.keyboard;
567 struct wl_keyboard_grab *default_grab = &keyboard->default_grab;
568
569 default_grab->interface->key(default_grab, time, key, state_w);
570}
571
572static void
573input_method_context_modifiers(struct wl_client *client,
574 struct wl_resource *resource,
575 uint32_t serial,
576 uint32_t mods_depressed,
577 uint32_t mods_latched,
578 uint32_t mods_locked,
579 uint32_t group)
580{
581 struct input_method_context *context = resource->data;
582
583 struct weston_seat *seat = context->input_method->seat;
584 struct wl_keyboard *keyboard = seat->seat.keyboard;
585 struct wl_keyboard_grab *default_grab = &keyboard->default_grab;
586
587 default_grab->interface->modifiers(default_grab,
588 serial, mods_depressed,
589 mods_latched, mods_locked,
590 group);
591}
592
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200593static const struct input_method_context_interface input_method_context_implementation = {
594 input_method_context_destroy,
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200595 input_method_context_commit_string,
596 input_method_context_preedit_string,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100597 input_method_context_preedit_styling,
598 input_method_context_preedit_cursor,
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200599 input_method_context_delete_surrounding_text,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100600 input_method_context_modifiers_map,
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100601 input_method_context_keysym,
Jan Arne Petersen337df952012-11-18 19:06:46 +0100602 input_method_context_grab_keyboard,
603 input_method_context_key,
604 input_method_context_modifiers
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200605};
606
607static void
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200608destroy_input_method_context(struct wl_resource *resource)
609{
610 struct input_method_context *context = resource->data;
611
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100612 if (context->keyboard) {
613 wl_resource_destroy(context->keyboard);
614 }
615
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200616 free(context);
617}
618
619static void
620input_method_context_create(struct text_model *model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100621 struct input_method *input_method,
622 uint32_t serial)
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200623{
624 struct input_method_context *context;
625
626 if (!input_method->input_method_binding)
627 return;
628
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100629 context = calloc(1, sizeof *context);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200630 if (context == NULL)
631 return;
632
633 context->resource.destroy = destroy_input_method_context;
634 context->resource.object.id = 0;
635 context->resource.object.interface = &input_method_context_interface;
636 context->resource.object.implementation =
637 (void (**)(void)) &input_method_context_implementation;
638 context->resource.data = context;
639 wl_signal_init(&context->resource.destroy_signal);
640
641 context->model = model;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100642 context->input_method = input_method;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200643 input_method->context = context;
644
645 wl_client_add_resource(input_method->input_method_binding->client, &context->resource);
646
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100647 input_method_send_activate(input_method->input_method_binding, &context->resource, serial);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200648}
649
650static void
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100651input_method_context_end_keyboard_grab(struct input_method_context *context)
652{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100653 struct wl_keyboard_grab *grab = &context->input_method->seat->keyboard.input_method_grab;
654 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100655
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100656 if (!grab->keyboard)
657 return;
658
659 if (grab->keyboard->grab == grab)
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100660 wl_keyboard_end_grab(grab->keyboard);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100661
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100662 keyboard->input_method_resource = NULL;
663}
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100664
665static void
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200666unbind_input_method(struct wl_resource *resource)
667{
668 struct input_method *input_method = resource->data;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100669 struct text_backend *text_backend = input_method->text_backend;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200670
671 input_method->input_method_binding = NULL;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200672 input_method->context = NULL;
673
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100674 text_backend->input_method.binding = NULL;
675
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200676 free(resource);
677}
678
679static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200680bind_input_method(struct wl_client *client,
681 void *data,
682 uint32_t version,
683 uint32_t id)
684{
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200685 struct input_method *input_method = data;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100686 struct text_backend *text_backend = input_method->text_backend;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200687 struct wl_resource *resource;
688
689 resource = wl_client_add_object(client, &input_method_interface,
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200690 NULL,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200691 id, input_method);
692
693 if (input_method->input_method_binding == NULL) {
694 resource->destroy = unbind_input_method;
695 input_method->input_method_binding = resource;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100696
697 text_backend->input_method.binding = resource;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200698 return;
699 }
700
701 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
702 "interface object already bound");
703 wl_resource_destroy(resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200704}
705
706static void
707input_method_notifier_destroy(struct wl_listener *listener, void *data)
708{
Kristian Høgsbergf97f3792012-07-22 11:51:42 -0400709 struct input_method *input_method =
710 container_of(listener, struct input_method, destroy_listener);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200711
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200712 if (input_method->model)
713 deactivate_text_model(input_method->model, input_method);
714
715 wl_display_remove_global(input_method->seat->compositor->wl_display,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200716 input_method->input_method_global);
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200717
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200718 free(input_method);
719}
720
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200721static void
722handle_keyboard_focus(struct wl_listener *listener, void *data)
723{
724 struct wl_keyboard *keyboard = data;
725 struct input_method *input_method =
726 container_of(listener, struct input_method, keyboard_focus_listener);
727 struct wl_surface *surface = keyboard->focus;
728
729 if (!input_method->model)
730 return;
731
732 if (!surface || input_method->model->surface != surface)
733 deactivate_text_model(input_method->model,
734 input_method);
735}
736
737static void
738input_method_init_seat(struct weston_seat *seat)
739{
740 if (seat->input_method->focus_listener_initialized)
741 return;
742
743 if (seat->has_keyboard) {
744 seat->input_method->keyboard_focus_listener.notify = handle_keyboard_focus;
745 wl_signal_add(&seat->seat.keyboard->focus_signal, &seat->input_method->keyboard_focus_listener);
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100746 seat->keyboard.input_method_grab.interface = &input_method_context_grab;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200747 }
748
749 seat->input_method->focus_listener_initialized = 1;
750}
751
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100752static void
753handle_input_method_sigchld(struct weston_process *process, int status)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200754{
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100755 struct text_backend *text_backend =
756 container_of(process, struct text_backend, input_method.process);
757
758 text_backend->input_method.process.pid = 0;
759 text_backend->input_method.client = NULL;
760}
761
762static void
763launch_input_method(struct text_backend *text_backend)
764{
765 if (text_backend->input_method.binding)
766 return;
767
768 if (!text_backend->input_method.path)
769 return;
770
771 if (text_backend->input_method.process.pid != 0)
772 return;
773
774 text_backend->input_method.client = weston_client_launch(text_backend->compositor,
775 &text_backend->input_method.process,
776 text_backend->input_method.path,
777 handle_input_method_sigchld);
778
779 if (!text_backend->input_method.client)
780 weston_log("not able to start %s\n", text_backend->input_method.path);
781}
782
783static void
784handle_seat_created(struct wl_listener *listener,
785 void *data)
786{
787 struct weston_seat *seat = data;
788 struct text_backend *text_backend =
789 container_of(listener, struct text_backend,
790 seat_created_listener);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200791 struct input_method *input_method;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100792 struct weston_compositor *ec = seat->compositor;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200793
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200794 input_method = calloc(1, sizeof *input_method);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200795
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200796 input_method->seat = seat;
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200797 input_method->model = NULL;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200798 input_method->focus_listener_initialized = 0;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200799 input_method->context = NULL;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100800 input_method->text_backend = text_backend;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200801
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200802 input_method->input_method_global =
803 wl_display_add_global(ec->wl_display,
804 &input_method_interface,
805 input_method, bind_input_method);
806
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200807 input_method->destroy_listener.notify = input_method_notifier_destroy;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200808 wl_signal_add(&seat->seat.destroy_signal, &input_method->destroy_listener);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200809
810 seat->input_method = input_method;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100811
812 launch_input_method(text_backend);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200813}
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200814
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100815static void
816text_backend_configuration(struct text_backend *text_backend)
817{
818 char *config_file;
819 char *path = NULL;
820
821 struct config_key input_method_keys[] = {
822 { "path", CONFIG_KEY_STRING, &path }
823 };
824
825 struct config_section cs[] = {
826 { "input-method", input_method_keys, ARRAY_LENGTH(input_method_keys), NULL }
827 };
828
829 config_file = config_file_path("weston.ini");
830 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), text_backend);
831 free(config_file);
832
833 if (path)
834 text_backend->input_method.path = path;
835 else
836 text_backend->input_method.path = strdup(LIBEXECDIR "/weston-keyboard");
837}
838
839static void
840text_backend_notifier_destroy(struct wl_listener *listener, void *data)
841{
842 struct text_backend *text_backend =
843 container_of(listener, struct text_backend, destroy_listener);
844
845 if (text_backend->input_method.client)
846 wl_client_destroy(text_backend->input_method.client);
847
848 free(text_backend->input_method.path);
849
850 free(text_backend);
851}
852
853
854WL_EXPORT int
855text_backend_init(struct weston_compositor *ec)
856{
857 struct text_backend *text_backend;
858
859 text_backend = calloc(1, sizeof(*text_backend));
860
861 text_backend->compositor = ec;
862
863 text_backend->seat_created_listener.notify = handle_seat_created;
864 wl_signal_add(&ec->seat_created_signal,
865 &text_backend->seat_created_listener);
866
867 text_backend->destroy_listener.notify = text_backend_notifier_destroy;
868 wl_signal_add(&ec->destroy_signal, &text_backend->destroy_listener);
869
870 text_backend_configuration(text_backend);
871
872 text_model_factory_create(ec);
873
874 return 0;
875}