blob: f096a9bbcec5df222aab693094fa29331d14704b [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 Petersen0eabcaa2013-01-31 15:52:20 +0100260static void
261text_model_commit(struct wl_client *client,
262 struct wl_resource *resource)
263{
264 struct text_model *text_model = resource->data;
265 struct input_method *input_method, *next;
266
267 wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
268 if (!input_method->context)
269 continue;
270 input_method_context_send_commit(&input_method->context->resource);
271 }
272}
273
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200274static const struct text_model_interface text_model_implementation = {
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200275 text_model_set_surrounding_text,
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200276 text_model_activate,
277 text_model_deactivate,
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200278 text_model_reset,
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200279 text_model_set_micro_focus,
Jan Arne Petersenadfedc12013-01-16 21:26:46 +0100280 text_model_set_content_type,
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100281 text_model_invoke_action,
282 text_model_commit
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200283};
284
Jan Arne Petersen51963742012-08-10 16:47:20 +0200285static void text_model_factory_create_text_model(struct wl_client *client,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200286 struct wl_resource *resource,
Jan Arne Petersen4c265182012-09-09 23:08:30 +0200287 uint32_t id)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200288{
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200289 struct text_model_factory *text_model_factory = resource->data;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200290 struct text_model *text_model;
291
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200292 text_model = calloc(1, sizeof *text_model);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200293
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200294 text_model->resource.object.id = id;
295 text_model->resource.object.interface = &text_model_interface;
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200296 text_model->resource.object.implementation =
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200297 (void (**)(void)) &text_model_implementation;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200298
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200299 text_model->resource.data = text_model;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200300 text_model->resource.destroy = destroy_text_model;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200301
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200302 text_model->ec = text_model_factory->ec;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200303
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200304 wl_list_init(&text_model->input_methods);
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200305
306 wl_client_add_resource(client, &text_model->resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200307};
308
Jan Arne Petersen51963742012-08-10 16:47:20 +0200309static const struct text_model_factory_interface text_model_factory_implementation = {
310 text_model_factory_create_text_model
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200311};
312
313static void
Jan Arne Petersen51963742012-08-10 16:47:20 +0200314bind_text_model_factory(struct wl_client *client,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200315 void *data,
316 uint32_t version,
317 uint32_t id)
318{
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200319 struct text_model_factory *text_model_factory = data;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200320
321 /* No checking for duplicate binding necessary.
322 * No events have to be sent, so we don't need the return value. */
Jan Arne Petersen51963742012-08-10 16:47:20 +0200323 wl_client_add_object(client, &text_model_factory_interface,
324 &text_model_factory_implementation,
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200325 id, text_model_factory);
326}
327
328static void
329text_model_factory_notifier_destroy(struct wl_listener *listener, void *data)
330{
331 struct text_model_factory *text_model_factory =
332 container_of(listener, struct text_model_factory, destroy_listener);
333
334 wl_display_remove_global(text_model_factory->ec->wl_display,
335 text_model_factory->text_model_factory_global);
336
337 free(text_model_factory);
338}
339
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100340static void
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200341text_model_factory_create(struct weston_compositor *ec)
342{
343 struct text_model_factory *text_model_factory;
344
345 text_model_factory = calloc(1, sizeof *text_model_factory);
346
347 text_model_factory->ec = ec;
348
349 text_model_factory->text_model_factory_global =
350 wl_display_add_global(ec->wl_display,
351 &text_model_factory_interface,
352 text_model_factory, bind_text_model_factory);
353
354 text_model_factory->destroy_listener.notify = text_model_factory_notifier_destroy;
355 wl_signal_add(&ec->destroy_signal, &text_model_factory->destroy_listener);
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200356}
357
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200358static void
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200359input_method_context_destroy(struct wl_client *client,
360 struct wl_resource *resource)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200361{
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200362 wl_resource_destroy(resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200363}
364
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200365static void
366input_method_context_commit_string(struct wl_client *client,
367 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100368 uint32_t serial,
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200369 const char *text,
370 uint32_t index)
371{
372 struct input_method_context *context = resource->data;
373
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100374 text_model_send_commit_string(&context->model->resource, serial, text, index);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200375}
376
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200377static void
378input_method_context_preedit_string(struct wl_client *client,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100379 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100380 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100381 const char *text,
382 const char *commit)
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200383{
384 struct input_method_context *context = resource->data;
385
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100386 text_model_send_preedit_string(&context->model->resource, serial, text, commit);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100387}
388
389static void
390input_method_context_preedit_styling(struct wl_client *client,
391 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100392 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100393 uint32_t index,
394 uint32_t length,
395 uint32_t style)
396{
397 struct input_method_context *context = resource->data;
398
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100399 text_model_send_preedit_styling(&context->model->resource, serial, index, length, style);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100400}
401
402static void
403input_method_context_preedit_cursor(struct wl_client *client,
404 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100405 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100406 int32_t cursor)
407{
408 struct input_method_context *context = resource->data;
409
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100410 text_model_send_preedit_cursor(&context->model->resource, serial, cursor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200411}
412
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200413static void
414input_method_context_delete_surrounding_text(struct wl_client *client,
415 struct wl_resource *resource,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100416 uint32_t serial,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200417 int32_t index,
418 uint32_t length)
419{
420 struct input_method_context *context = resource->data;
421
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100422 text_model_send_delete_surrounding_text(&context->model->resource, serial, index, length);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200423}
424
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200425static void
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100426input_method_context_modifiers_map(struct wl_client *client,
427 struct wl_resource *resource,
428 struct wl_array *map)
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200429{
430 struct input_method_context *context = resource->data;
431
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100432 text_model_send_modifiers_map(&context->model->resource, map);
433}
434
435static void
436input_method_context_keysym(struct wl_client *client,
437 struct wl_resource *resource,
438 uint32_t serial,
439 uint32_t time,
440 uint32_t sym,
441 uint32_t state,
442 uint32_t modifiers)
443{
444 struct input_method_context *context = resource->data;
445
446 text_model_send_keysym(&context->model->resource, serial, time,
447 sym, state, modifiers);
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200448}
449
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100450static void
451unbind_keyboard(struct wl_resource *resource)
452{
453 struct input_method_context *context = resource->data;
454
455 input_method_context_end_keyboard_grab(context);
456 context->keyboard = NULL;
457
458 free(resource);
459}
460
461static void
462input_method_context_grab_key(struct wl_keyboard_grab *grab,
463 uint32_t time, uint32_t key, uint32_t state_w)
464{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100465 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
466 struct wl_display *display;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100467 uint32_t serial;
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100468
469 if (!keyboard->input_method_resource)
470 return;
471
472 display = wl_client_get_display(keyboard->input_method_resource->client);
473 serial = wl_display_next_serial(display);
474 wl_keyboard_send_key(keyboard->input_method_resource,
475 serial, time, key, state_w);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100476}
477
478static void
479input_method_context_grab_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
480 uint32_t mods_depressed, uint32_t mods_latched,
481 uint32_t mods_locked, uint32_t group)
482{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100483 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100484
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100485 if (!keyboard->input_method_resource)
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100486 return;
487
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100488 wl_keyboard_send_modifiers(keyboard->input_method_resource,
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100489 serial, mods_depressed, mods_latched,
490 mods_locked, group);
491}
492
493static const struct wl_keyboard_grab_interface input_method_context_grab = {
494 input_method_context_grab_key,
495 input_method_context_grab_modifier,
496};
497
498static void
499input_method_context_grab_keyboard(struct wl_client *client,
500 struct wl_resource *resource,
501 uint32_t id)
502{
503 struct input_method_context *context = resource->data;
504 struct wl_resource *cr;
505 struct weston_seat *seat = context->input_method->seat;
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100506 struct weston_keyboard *keyboard = &seat->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100507
508 cr = wl_client_add_object(client, &wl_keyboard_interface,
509 NULL, id, context);
510 cr->destroy = unbind_keyboard;
511
512 context->keyboard = cr;
513
514 wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
515 seat->xkb_info.keymap_fd,
516 seat->xkb_info.keymap_size);
517
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100518 if (keyboard->keyboard.grab != &keyboard->keyboard.default_grab) {
519 wl_keyboard_end_grab(&keyboard->keyboard);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100520 }
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100521 wl_keyboard_start_grab(&keyboard->keyboard, &keyboard->input_method_grab);
522 keyboard->input_method_resource = cr;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100523}
524
Jan Arne Petersen337df952012-11-18 19:06:46 +0100525static void
526input_method_context_key(struct wl_client *client,
527 struct wl_resource *resource,
528 uint32_t serial,
529 uint32_t time,
530 uint32_t key,
531 uint32_t state_w)
532{
533 struct input_method_context *context = resource->data;
534 struct weston_seat *seat = context->input_method->seat;
535 struct wl_keyboard *keyboard = seat->seat.keyboard;
536 struct wl_keyboard_grab *default_grab = &keyboard->default_grab;
537
538 default_grab->interface->key(default_grab, time, key, state_w);
539}
540
541static void
542input_method_context_modifiers(struct wl_client *client,
543 struct wl_resource *resource,
544 uint32_t serial,
545 uint32_t mods_depressed,
546 uint32_t mods_latched,
547 uint32_t mods_locked,
548 uint32_t group)
549{
550 struct input_method_context *context = resource->data;
551
552 struct weston_seat *seat = context->input_method->seat;
553 struct wl_keyboard *keyboard = seat->seat.keyboard;
554 struct wl_keyboard_grab *default_grab = &keyboard->default_grab;
555
556 default_grab->interface->modifiers(default_grab,
557 serial, mods_depressed,
558 mods_latched, mods_locked,
559 group);
560}
561
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200562static const struct input_method_context_interface input_method_context_implementation = {
563 input_method_context_destroy,
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200564 input_method_context_commit_string,
565 input_method_context_preedit_string,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100566 input_method_context_preedit_styling,
567 input_method_context_preedit_cursor,
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200568 input_method_context_delete_surrounding_text,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100569 input_method_context_modifiers_map,
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100570 input_method_context_keysym,
Jan Arne Petersen337df952012-11-18 19:06:46 +0100571 input_method_context_grab_keyboard,
572 input_method_context_key,
573 input_method_context_modifiers
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200574};
575
576static void
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200577destroy_input_method_context(struct wl_resource *resource)
578{
579 struct input_method_context *context = resource->data;
580
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100581 if (context->keyboard) {
582 wl_resource_destroy(context->keyboard);
583 }
584
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200585 free(context);
586}
587
588static void
589input_method_context_create(struct text_model *model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100590 struct input_method *input_method,
591 uint32_t serial)
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200592{
593 struct input_method_context *context;
594
595 if (!input_method->input_method_binding)
596 return;
597
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100598 context = calloc(1, sizeof *context);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200599 if (context == NULL)
600 return;
601
602 context->resource.destroy = destroy_input_method_context;
603 context->resource.object.id = 0;
604 context->resource.object.interface = &input_method_context_interface;
605 context->resource.object.implementation =
606 (void (**)(void)) &input_method_context_implementation;
607 context->resource.data = context;
608 wl_signal_init(&context->resource.destroy_signal);
609
610 context->model = model;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100611 context->input_method = input_method;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200612 input_method->context = context;
613
614 wl_client_add_resource(input_method->input_method_binding->client, &context->resource);
615
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100616 input_method_send_activate(input_method->input_method_binding, &context->resource, serial);
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200617}
618
619static void
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100620input_method_context_end_keyboard_grab(struct input_method_context *context)
621{
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100622 struct wl_keyboard_grab *grab = &context->input_method->seat->keyboard.input_method_grab;
623 struct weston_keyboard *keyboard = (struct weston_keyboard *)grab->keyboard;
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100624
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100625 if (!grab->keyboard)
626 return;
627
628 if (grab->keyboard->grab == grab)
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100629 wl_keyboard_end_grab(grab->keyboard);
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100630
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100631 keyboard->input_method_resource = NULL;
632}
Jan Arne Petersen466b9c12012-11-18 19:06:45 +0100633
634static void
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200635unbind_input_method(struct wl_resource *resource)
636{
637 struct input_method *input_method = resource->data;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100638 struct text_backend *text_backend = input_method->text_backend;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200639
640 input_method->input_method_binding = NULL;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200641 input_method->context = NULL;
642
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100643 text_backend->input_method.binding = NULL;
644
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200645 free(resource);
646}
647
648static void
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200649bind_input_method(struct wl_client *client,
650 void *data,
651 uint32_t version,
652 uint32_t id)
653{
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200654 struct input_method *input_method = data;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100655 struct text_backend *text_backend = input_method->text_backend;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200656 struct wl_resource *resource;
657
658 resource = wl_client_add_object(client, &input_method_interface,
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200659 NULL,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200660 id, input_method);
661
662 if (input_method->input_method_binding == NULL) {
663 resource->destroy = unbind_input_method;
664 input_method->input_method_binding = resource;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100665
666 text_backend->input_method.binding = resource;
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200667 return;
668 }
669
670 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
671 "interface object already bound");
672 wl_resource_destroy(resource);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200673}
674
675static void
676input_method_notifier_destroy(struct wl_listener *listener, void *data)
677{
Kristian Høgsbergf97f3792012-07-22 11:51:42 -0400678 struct input_method *input_method =
679 container_of(listener, struct input_method, destroy_listener);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200680
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200681 if (input_method->model)
682 deactivate_text_model(input_method->model, input_method);
683
684 wl_display_remove_global(input_method->seat->compositor->wl_display,
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200685 input_method->input_method_global);
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200686
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200687 free(input_method);
688}
689
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200690static void
691handle_keyboard_focus(struct wl_listener *listener, void *data)
692{
693 struct wl_keyboard *keyboard = data;
694 struct input_method *input_method =
695 container_of(listener, struct input_method, keyboard_focus_listener);
696 struct wl_surface *surface = keyboard->focus;
697
698 if (!input_method->model)
699 return;
700
701 if (!surface || input_method->model->surface != surface)
702 deactivate_text_model(input_method->model,
703 input_method);
704}
705
706static void
707input_method_init_seat(struct weston_seat *seat)
708{
709 if (seat->input_method->focus_listener_initialized)
710 return;
711
712 if (seat->has_keyboard) {
713 seat->input_method->keyboard_focus_listener.notify = handle_keyboard_focus;
714 wl_signal_add(&seat->seat.keyboard->focus_signal, &seat->input_method->keyboard_focus_listener);
Jan Arne Petersena75a7892013-01-16 21:26:50 +0100715 seat->keyboard.input_method_grab.interface = &input_method_context_grab;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200716 }
717
718 seat->input_method->focus_listener_initialized = 1;
719}
720
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100721static void
722handle_input_method_sigchld(struct weston_process *process, int status)
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200723{
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100724 struct text_backend *text_backend =
725 container_of(process, struct text_backend, input_method.process);
726
727 text_backend->input_method.process.pid = 0;
728 text_backend->input_method.client = NULL;
729}
730
731static void
732launch_input_method(struct text_backend *text_backend)
733{
734 if (text_backend->input_method.binding)
735 return;
736
737 if (!text_backend->input_method.path)
738 return;
739
740 if (text_backend->input_method.process.pid != 0)
741 return;
742
743 text_backend->input_method.client = weston_client_launch(text_backend->compositor,
744 &text_backend->input_method.process,
745 text_backend->input_method.path,
746 handle_input_method_sigchld);
747
748 if (!text_backend->input_method.client)
749 weston_log("not able to start %s\n", text_backend->input_method.path);
750}
751
752static void
753handle_seat_created(struct wl_listener *listener,
754 void *data)
755{
756 struct weston_seat *seat = data;
757 struct text_backend *text_backend =
758 container_of(listener, struct text_backend,
759 seat_created_listener);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200760 struct input_method *input_method;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100761 struct weston_compositor *ec = seat->compositor;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200762
Philipp Brüschweiler17467812012-07-11 22:25:30 +0200763 input_method = calloc(1, sizeof *input_method);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200764
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200765 input_method->seat = seat;
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200766 input_method->model = NULL;
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200767 input_method->focus_listener_initialized = 0;
Jan Arne Petersen620cd622012-09-09 23:08:32 +0200768 input_method->context = NULL;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100769 input_method->text_backend = text_backend;
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200770
Philipp Brüschweilerf25602b2012-07-11 22:25:31 +0200771 input_method->input_method_global =
772 wl_display_add_global(ec->wl_display,
773 &input_method_interface,
774 input_method, bind_input_method);
775
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200776 input_method->destroy_listener.notify = input_method_notifier_destroy;
Philipp Brüschweilerb13b9ff2012-09-09 23:08:31 +0200777 wl_signal_add(&seat->seat.destroy_signal, &input_method->destroy_listener);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200778
779 seat->input_method = input_method;
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100780
781 launch_input_method(text_backend);
Jan Arne Petersen1f17be42012-06-21 21:52:18 +0200782}
Jan Arne Petersencd8cdcc2012-08-10 16:47:23 +0200783
Jan Arne Petersen674fd1d2012-11-18 19:06:42 +0100784static void
785text_backend_configuration(struct text_backend *text_backend)
786{
787 char *config_file;
788 char *path = NULL;
789
790 struct config_key input_method_keys[] = {
791 { "path", CONFIG_KEY_STRING, &path }
792 };
793
794 struct config_section cs[] = {
795 { "input-method", input_method_keys, ARRAY_LENGTH(input_method_keys), NULL }
796 };
797
798 config_file = config_file_path("weston.ini");
799 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), text_backend);
800 free(config_file);
801
802 if (path)
803 text_backend->input_method.path = path;
804 else
805 text_backend->input_method.path = strdup(LIBEXECDIR "/weston-keyboard");
806}
807
808static void
809text_backend_notifier_destroy(struct wl_listener *listener, void *data)
810{
811 struct text_backend *text_backend =
812 container_of(listener, struct text_backend, destroy_listener);
813
814 if (text_backend->input_method.client)
815 wl_client_destroy(text_backend->input_method.client);
816
817 free(text_backend->input_method.path);
818
819 free(text_backend);
820}
821
822
823WL_EXPORT int
824text_backend_init(struct weston_compositor *ec)
825{
826 struct text_backend *text_backend;
827
828 text_backend = calloc(1, sizeof(*text_backend));
829
830 text_backend->compositor = ec;
831
832 text_backend->seat_created_listener.notify = handle_seat_created;
833 wl_signal_add(&ec->seat_created_signal,
834 &text_backend->seat_created_listener);
835
836 text_backend->destroy_listener.notify = text_backend_notifier_destroy;
837 wl_signal_add(&ec->destroy_signal, &text_backend->destroy_listener);
838
839 text_backend_configuration(text_backend);
840
841 text_model_factory_create(ec);
842
843 return 0;
844}