1 | /* GTK - The GIMP Toolkit |
2 | * Copyright (C) 2000 Red Hat, Inc. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | #include "config.h" |
19 | |
20 | #include <string.h> |
21 | #include <locale.h> |
22 | |
23 | #include "gtkimmulticontext.h" |
24 | #include "gtkimmoduleprivate.h" |
25 | #include "gtkintl.h" |
26 | #include "gtklabel.h" |
27 | #include "gtkmain.h" |
28 | #include "gtkprivate.h" |
29 | #include "gtksettings.h" |
30 | |
31 | |
32 | /** |
33 | * GtkIMMulticontext: |
34 | * |
35 | * `GtkIMMulticontext` is an input method context supporting multiple, |
36 | * switchable input methods. |
37 | * |
38 | * Text widgets such as `GtkText` or `GtkTextView` use a `GtkIMMultiContext` |
39 | * to implement their `im-module` property for switching between different |
40 | * input methods. |
41 | */ |
42 | |
43 | |
44 | struct _GtkIMMulticontextPrivate |
45 | { |
46 | GtkIMContext *delegate; |
47 | |
48 | GtkWidget *client_widget; |
49 | GdkRectangle cursor_location; |
50 | |
51 | char *context_id; |
52 | char *context_id_aux; |
53 | |
54 | guint use_preedit : 1; |
55 | guint have_cursor_location : 1; |
56 | guint focus_in : 1; |
57 | }; |
58 | |
59 | static void gtk_im_multicontext_notify (GObject *object, |
60 | GParamSpec *pspec); |
61 | static void gtk_im_multicontext_finalize (GObject *object); |
62 | |
63 | static void gtk_im_multicontext_set_delegate (GtkIMMulticontext *multicontext, |
64 | GtkIMContext *delegate, |
65 | gboolean finalizing); |
66 | |
67 | static void gtk_im_multicontext_set_client_widget (GtkIMContext *context, |
68 | GtkWidget *widget); |
69 | static void gtk_im_multicontext_get_preedit_string (GtkIMContext *context, |
70 | char **str, |
71 | PangoAttrList **attrs, |
72 | int *cursor_pos); |
73 | static gboolean gtk_im_multicontext_filter_keypress (GtkIMContext *context, |
74 | GdkEvent *event); |
75 | static void gtk_im_multicontext_focus_in (GtkIMContext *context); |
76 | static void gtk_im_multicontext_focus_out (GtkIMContext *context); |
77 | static void gtk_im_multicontext_reset (GtkIMContext *context); |
78 | static void gtk_im_multicontext_set_cursor_location (GtkIMContext *context, |
79 | GdkRectangle *area); |
80 | static void gtk_im_multicontext_set_use_preedit (GtkIMContext *context, |
81 | gboolean use_preedit); |
82 | static gboolean gtk_im_multicontext_get_surrounding_with_selection |
83 | (GtkIMContext *context, |
84 | char **text, |
85 | int *cursor_index, |
86 | int *anchor_index); |
87 | static void gtk_im_multicontext_set_surrounding_with_selection |
88 | (GtkIMContext *context, |
89 | const char *text, |
90 | int len, |
91 | int cursor_index, |
92 | int anchor_index); |
93 | |
94 | static void gtk_im_multicontext_preedit_start_cb (GtkIMContext *delegate, |
95 | GtkIMMulticontext *multicontext); |
96 | static void gtk_im_multicontext_preedit_end_cb (GtkIMContext *delegate, |
97 | GtkIMMulticontext *multicontext); |
98 | static void gtk_im_multicontext_preedit_changed_cb (GtkIMContext *delegate, |
99 | GtkIMMulticontext *multicontext); |
100 | static void gtk_im_multicontext_commit_cb (GtkIMContext *delegate, |
101 | const char *str, |
102 | GtkIMMulticontext *multicontext); |
103 | static gboolean gtk_im_multicontext_retrieve_surrounding_cb (GtkIMContext *delegate, |
104 | GtkIMMulticontext *multicontext); |
105 | static gboolean gtk_im_multicontext_delete_surrounding_cb (GtkIMContext *delegate, |
106 | int offset, |
107 | int n_chars, |
108 | GtkIMMulticontext *multicontext); |
109 | |
110 | static void propagate_purpose (GtkIMMulticontext *context); |
111 | |
112 | G_DEFINE_TYPE_WITH_PRIVATE (GtkIMMulticontext, gtk_im_multicontext, GTK_TYPE_IM_CONTEXT) |
113 | |
114 | static void |
115 | gtk_im_multicontext_class_init (GtkIMMulticontextClass *class) |
116 | { |
117 | GObjectClass *gobject_class = G_OBJECT_CLASS (class); |
118 | GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class); |
119 | |
120 | gobject_class->notify = gtk_im_multicontext_notify; |
121 | |
122 | im_context_class->set_client_widget = gtk_im_multicontext_set_client_widget; |
123 | im_context_class->get_preedit_string = gtk_im_multicontext_get_preedit_string; |
124 | im_context_class->filter_keypress = gtk_im_multicontext_filter_keypress; |
125 | im_context_class->focus_in = gtk_im_multicontext_focus_in; |
126 | im_context_class->focus_out = gtk_im_multicontext_focus_out; |
127 | im_context_class->reset = gtk_im_multicontext_reset; |
128 | im_context_class->set_cursor_location = gtk_im_multicontext_set_cursor_location; |
129 | im_context_class->set_use_preedit = gtk_im_multicontext_set_use_preedit; |
130 | im_context_class->set_surrounding_with_selection = gtk_im_multicontext_set_surrounding_with_selection; |
131 | im_context_class->get_surrounding_with_selection = gtk_im_multicontext_get_surrounding_with_selection; |
132 | |
133 | gobject_class->finalize = gtk_im_multicontext_finalize; |
134 | } |
135 | |
136 | static void |
137 | gtk_im_multicontext_init (GtkIMMulticontext *multicontext) |
138 | { |
139 | GtkIMMulticontextPrivate *priv; |
140 | |
141 | multicontext->priv = gtk_im_multicontext_get_instance_private (self: multicontext); |
142 | priv = multicontext->priv; |
143 | |
144 | priv->delegate = NULL; |
145 | priv->use_preedit = TRUE; |
146 | priv->have_cursor_location = FALSE; |
147 | priv->focus_in = FALSE; |
148 | } |
149 | |
150 | /** |
151 | * gtk_im_multicontext_new: |
152 | * |
153 | * Creates a new `GtkIMMulticontext`. |
154 | * |
155 | * Returns: a new `GtkIMMulticontext`. |
156 | */ |
157 | GtkIMContext * |
158 | gtk_im_multicontext_new (void) |
159 | { |
160 | return g_object_new (GTK_TYPE_IM_MULTICONTEXT, NULL); |
161 | } |
162 | |
163 | static void |
164 | gtk_im_multicontext_finalize (GObject *object) |
165 | { |
166 | GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (object); |
167 | GtkIMMulticontextPrivate *priv = multicontext->priv; |
168 | |
169 | gtk_im_multicontext_set_delegate (multicontext, NULL, TRUE); |
170 | g_free (mem: priv->context_id); |
171 | g_free (mem: priv->context_id_aux); |
172 | |
173 | G_OBJECT_CLASS (gtk_im_multicontext_parent_class)->finalize (object); |
174 | } |
175 | |
176 | static void |
177 | gtk_im_multicontext_set_delegate (GtkIMMulticontext *multicontext, |
178 | GtkIMContext *delegate, |
179 | gboolean finalizing) |
180 | { |
181 | GtkIMMulticontextPrivate *priv = multicontext->priv; |
182 | gboolean need_preedit_changed = FALSE; |
183 | |
184 | if (priv->delegate) |
185 | { |
186 | if (!finalizing) |
187 | gtk_im_context_reset (context: priv->delegate); |
188 | |
189 | g_signal_handlers_disconnect_by_func (priv->delegate, |
190 | gtk_im_multicontext_preedit_start_cb, |
191 | multicontext); |
192 | g_signal_handlers_disconnect_by_func (priv->delegate, |
193 | gtk_im_multicontext_preedit_end_cb, |
194 | multicontext); |
195 | g_signal_handlers_disconnect_by_func (priv->delegate, |
196 | gtk_im_multicontext_preedit_changed_cb, |
197 | multicontext); |
198 | g_signal_handlers_disconnect_by_func (priv->delegate, |
199 | gtk_im_multicontext_commit_cb, |
200 | multicontext); |
201 | g_signal_handlers_disconnect_by_func (priv->delegate, |
202 | gtk_im_multicontext_retrieve_surrounding_cb, |
203 | multicontext); |
204 | g_signal_handlers_disconnect_by_func (priv->delegate, |
205 | gtk_im_multicontext_delete_surrounding_cb, |
206 | multicontext); |
207 | |
208 | if (priv->client_widget) |
209 | gtk_im_context_set_client_widget (context: priv->delegate, NULL); |
210 | |
211 | g_object_unref (object: priv->delegate); |
212 | priv->delegate = NULL; |
213 | |
214 | if (!finalizing) |
215 | need_preedit_changed = TRUE; |
216 | } |
217 | |
218 | priv->delegate = delegate; |
219 | |
220 | if (priv->delegate) |
221 | { |
222 | g_object_ref (priv->delegate); |
223 | |
224 | propagate_purpose (context: multicontext); |
225 | |
226 | g_signal_connect (priv->delegate, "preedit-start" , |
227 | G_CALLBACK (gtk_im_multicontext_preedit_start_cb), |
228 | multicontext); |
229 | g_signal_connect (priv->delegate, "preedit-end" , |
230 | G_CALLBACK (gtk_im_multicontext_preedit_end_cb), |
231 | multicontext); |
232 | g_signal_connect (priv->delegate, "preedit-changed" , |
233 | G_CALLBACK (gtk_im_multicontext_preedit_changed_cb), |
234 | multicontext); |
235 | g_signal_connect (priv->delegate, "commit" , |
236 | G_CALLBACK (gtk_im_multicontext_commit_cb), |
237 | multicontext); |
238 | g_signal_connect (priv->delegate, "retrieve-surrounding" , |
239 | G_CALLBACK (gtk_im_multicontext_retrieve_surrounding_cb), |
240 | multicontext); |
241 | g_signal_connect (priv->delegate, "delete-surrounding" , |
242 | G_CALLBACK (gtk_im_multicontext_delete_surrounding_cb), |
243 | multicontext); |
244 | |
245 | if (!priv->use_preedit) /* Default is TRUE */ |
246 | gtk_im_context_set_use_preedit (context: delegate, FALSE); |
247 | if (priv->client_widget) |
248 | gtk_im_context_set_client_widget (context: delegate, widget: priv->client_widget); |
249 | if (priv->have_cursor_location) |
250 | gtk_im_context_set_cursor_location (context: delegate, area: &priv->cursor_location); |
251 | if (priv->focus_in) |
252 | gtk_im_context_focus_in (context: delegate); |
253 | } |
254 | |
255 | if (need_preedit_changed) |
256 | g_signal_emit_by_name (instance: multicontext, detailed_signal: "preedit-changed" ); |
257 | } |
258 | |
259 | static const char * |
260 | get_effective_context_id (GtkIMMulticontext *multicontext) |
261 | { |
262 | GtkIMMulticontextPrivate *priv = multicontext->priv; |
263 | GdkDisplay *display; |
264 | |
265 | if (priv->context_id_aux) |
266 | return priv->context_id_aux; |
267 | |
268 | if (priv->client_widget) |
269 | display = gtk_widget_get_display (widget: priv->client_widget); |
270 | else |
271 | display = gdk_display_get_default (); |
272 | |
273 | return _gtk_im_module_get_default_context_id (display); |
274 | } |
275 | |
276 | static GtkIMContext * |
277 | gtk_im_multicontext_get_delegate (GtkIMMulticontext *multicontext) |
278 | { |
279 | GtkIMMulticontextPrivate *priv = multicontext->priv; |
280 | |
281 | if (!priv->delegate) |
282 | { |
283 | GtkIMContext *delegate; |
284 | |
285 | g_free (mem: priv->context_id); |
286 | |
287 | priv->context_id = g_strdup (str: get_effective_context_id (multicontext)); |
288 | |
289 | delegate = _gtk_im_module_create (context_id: priv->context_id); |
290 | if (delegate) |
291 | { |
292 | gtk_im_multicontext_set_delegate (multicontext, delegate, FALSE); |
293 | g_object_unref (object: delegate); |
294 | } |
295 | } |
296 | |
297 | return priv->delegate; |
298 | } |
299 | |
300 | static void |
301 | im_module_setting_changed (GtkSettings *settings, |
302 | GParamSpec *pspec, |
303 | GtkIMMulticontext *self) |
304 | { |
305 | gtk_im_multicontext_set_delegate (multicontext: self, NULL, FALSE); |
306 | } |
307 | |
308 | static void |
309 | gtk_im_multicontext_set_client_widget (GtkIMContext *context, |
310 | GtkWidget *widget) |
311 | { |
312 | GtkIMMulticontext *self = GTK_IM_MULTICONTEXT (context); |
313 | GtkIMMulticontextPrivate *priv = self->priv; |
314 | GtkIMContext *delegate; |
315 | GtkSettings *settings; |
316 | |
317 | if (priv->client_widget == widget) |
318 | return; |
319 | |
320 | gtk_im_multicontext_set_delegate (multicontext: self, NULL, TRUE); |
321 | |
322 | if (priv->client_widget != NULL) |
323 | { |
324 | settings = gtk_widget_get_settings (widget: priv->client_widget); |
325 | |
326 | g_signal_handlers_disconnect_by_func (settings, |
327 | im_module_setting_changed, |
328 | self); |
329 | } |
330 | |
331 | priv->client_widget = widget; |
332 | |
333 | if (widget) |
334 | { |
335 | settings = gtk_widget_get_settings (widget); |
336 | |
337 | g_signal_connect (settings, "notify::gtk-im-module" , |
338 | G_CALLBACK (im_module_setting_changed), |
339 | self); |
340 | |
341 | delegate = gtk_im_multicontext_get_delegate (multicontext: self); |
342 | if (delegate) |
343 | gtk_im_context_set_client_widget (context: delegate, widget); |
344 | } |
345 | } |
346 | |
347 | static void |
348 | gtk_im_multicontext_get_preedit_string (GtkIMContext *context, |
349 | char **str, |
350 | PangoAttrList **attrs, |
351 | int *cursor_pos) |
352 | { |
353 | GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); |
354 | GtkIMContext *delegate = gtk_im_multicontext_get_delegate (multicontext); |
355 | |
356 | if (delegate) |
357 | gtk_im_context_get_preedit_string (context: delegate, str, attrs, cursor_pos); |
358 | else |
359 | { |
360 | if (str) |
361 | *str = g_strdup (str: "" ); |
362 | if (attrs) |
363 | *attrs = pango_attr_list_new (); |
364 | } |
365 | } |
366 | |
367 | static gboolean |
368 | gtk_im_multicontext_filter_keypress (GtkIMContext *context, |
369 | GdkEvent *event) |
370 | { |
371 | GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); |
372 | GtkIMContext *delegate = gtk_im_multicontext_get_delegate (multicontext); |
373 | guint keyval, state; |
374 | |
375 | if (delegate) |
376 | { |
377 | return gtk_im_context_filter_keypress (context: delegate, event); |
378 | } |
379 | else |
380 | { |
381 | GdkModifierType no_text_input_mask; |
382 | |
383 | keyval = gdk_key_event_get_keyval (event); |
384 | state = gdk_event_get_modifier_state (event); |
385 | |
386 | no_text_input_mask = GDK_ALT_MASK|GDK_CONTROL_MASK; |
387 | |
388 | if (gdk_event_get_event_type (event) == GDK_KEY_PRESS && |
389 | (state & no_text_input_mask) == 0) |
390 | { |
391 | gunichar ch; |
392 | |
393 | ch = gdk_keyval_to_unicode (keyval); |
394 | if (ch != 0 && !g_unichar_iscntrl (c: ch)) |
395 | { |
396 | int len; |
397 | char buf[10]; |
398 | |
399 | len = g_unichar_to_utf8 (c: ch, outbuf: buf); |
400 | buf[len] = '\0'; |
401 | |
402 | g_signal_emit_by_name (instance: multicontext, detailed_signal: "commit" , buf); |
403 | |
404 | return TRUE; |
405 | } |
406 | } |
407 | } |
408 | |
409 | return FALSE; |
410 | } |
411 | |
412 | static void |
413 | gtk_im_multicontext_focus_in (GtkIMContext *context) |
414 | { |
415 | GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); |
416 | GtkIMMulticontextPrivate *priv = multicontext->priv; |
417 | GtkIMContext *delegate = gtk_im_multicontext_get_delegate (multicontext); |
418 | |
419 | priv->focus_in = TRUE; |
420 | |
421 | if (delegate) |
422 | gtk_im_context_focus_in (context: delegate); |
423 | } |
424 | |
425 | static void |
426 | gtk_im_multicontext_focus_out (GtkIMContext *context) |
427 | { |
428 | GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); |
429 | GtkIMMulticontextPrivate *priv = multicontext->priv; |
430 | GtkIMContext *delegate = gtk_im_multicontext_get_delegate (multicontext); |
431 | |
432 | priv->focus_in = FALSE; |
433 | |
434 | if (delegate) |
435 | gtk_im_context_focus_out (context: delegate); |
436 | } |
437 | |
438 | static void |
439 | gtk_im_multicontext_reset (GtkIMContext *context) |
440 | { |
441 | GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); |
442 | GtkIMContext *delegate = gtk_im_multicontext_get_delegate (multicontext); |
443 | |
444 | if (delegate) |
445 | gtk_im_context_reset (context: delegate); |
446 | } |
447 | |
448 | static void |
449 | gtk_im_multicontext_set_cursor_location (GtkIMContext *context, |
450 | GdkRectangle *area) |
451 | { |
452 | GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); |
453 | GtkIMMulticontextPrivate *priv = multicontext->priv; |
454 | GtkIMContext *delegate = gtk_im_multicontext_get_delegate (multicontext); |
455 | |
456 | priv->have_cursor_location = TRUE; |
457 | priv->cursor_location = *area; |
458 | |
459 | if (delegate) |
460 | gtk_im_context_set_cursor_location (context: delegate, area); |
461 | } |
462 | |
463 | static void |
464 | gtk_im_multicontext_set_use_preedit (GtkIMContext *context, |
465 | gboolean use_preedit) |
466 | { |
467 | GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); |
468 | GtkIMMulticontextPrivate *priv = multicontext->priv; |
469 | GtkIMContext *delegate = gtk_im_multicontext_get_delegate (multicontext); |
470 | |
471 | use_preedit = use_preedit != FALSE; |
472 | |
473 | priv->use_preedit = use_preedit; |
474 | |
475 | if (delegate) |
476 | gtk_im_context_set_use_preedit (context: delegate, use_preedit); |
477 | } |
478 | |
479 | static gboolean |
480 | gtk_im_multicontext_get_surrounding_with_selection (GtkIMContext *context, |
481 | char **text, |
482 | int *cursor_index, |
483 | int *anchor_index) |
484 | { |
485 | GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); |
486 | GtkIMContext *delegate = gtk_im_multicontext_get_delegate (multicontext); |
487 | |
488 | if (delegate) |
489 | return gtk_im_context_get_surrounding_with_selection (context: delegate, text, cursor_index, anchor_index); |
490 | else |
491 | { |
492 | if (text) |
493 | *text = NULL; |
494 | if (cursor_index) |
495 | *cursor_index = 0; |
496 | if (anchor_index) |
497 | *anchor_index = 0; |
498 | |
499 | return FALSE; |
500 | } |
501 | } |
502 | |
503 | static void |
504 | gtk_im_multicontext_set_surrounding_with_selection (GtkIMContext *context, |
505 | const char *text, |
506 | int len, |
507 | int cursor_index, |
508 | int anchor_index) |
509 | { |
510 | GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context); |
511 | GtkIMContext *delegate = gtk_im_multicontext_get_delegate (multicontext); |
512 | |
513 | if (delegate) |
514 | gtk_im_context_set_surrounding_with_selection (context: delegate, text, len, cursor_index, anchor_index); |
515 | } |
516 | |
517 | static void |
518 | gtk_im_multicontext_preedit_start_cb (GtkIMContext *delegate, |
519 | GtkIMMulticontext *multicontext) |
520 | { |
521 | g_signal_emit_by_name (instance: multicontext, detailed_signal: "preedit-start" ); |
522 | } |
523 | |
524 | static void |
525 | gtk_im_multicontext_preedit_end_cb (GtkIMContext *delegate, |
526 | GtkIMMulticontext *multicontext) |
527 | { |
528 | g_signal_emit_by_name (instance: multicontext, detailed_signal: "preedit-end" ); |
529 | } |
530 | |
531 | static void |
532 | gtk_im_multicontext_preedit_changed_cb (GtkIMContext *delegate, |
533 | GtkIMMulticontext *multicontext) |
534 | { |
535 | g_signal_emit_by_name (instance: multicontext, detailed_signal: "preedit-changed" ); |
536 | } |
537 | |
538 | static void |
539 | gtk_im_multicontext_commit_cb (GtkIMContext *delegate, |
540 | const char *str, |
541 | GtkIMMulticontext *multicontext) |
542 | { |
543 | g_signal_emit_by_name (instance: multicontext, detailed_signal: "commit" , str); |
544 | } |
545 | |
546 | static gboolean |
547 | gtk_im_multicontext_retrieve_surrounding_cb (GtkIMContext *delegate, |
548 | GtkIMMulticontext *multicontext) |
549 | { |
550 | gboolean result; |
551 | |
552 | g_signal_emit_by_name (instance: multicontext, detailed_signal: "retrieve-surrounding" , &result); |
553 | |
554 | return result; |
555 | } |
556 | |
557 | static gboolean |
558 | gtk_im_multicontext_delete_surrounding_cb (GtkIMContext *delegate, |
559 | int offset, |
560 | int n_chars, |
561 | GtkIMMulticontext *multicontext) |
562 | { |
563 | gboolean result; |
564 | |
565 | g_signal_emit_by_name (instance: multicontext, detailed_signal: "delete-surrounding" , |
566 | offset, n_chars, &result); |
567 | |
568 | return result; |
569 | } |
570 | |
571 | /** |
572 | * gtk_im_multicontext_get_context_id: |
573 | * @context: a `GtkIMMulticontext` |
574 | * |
575 | * Gets the id of the currently active delegate of the @context. |
576 | * |
577 | * Returns: the id of the currently active delegate |
578 | */ |
579 | const char * |
580 | gtk_im_multicontext_get_context_id (GtkIMMulticontext *context) |
581 | { |
582 | GtkIMMulticontextPrivate *priv = context->priv; |
583 | |
584 | g_return_val_if_fail (GTK_IS_IM_MULTICONTEXT (context), NULL); |
585 | |
586 | if (priv->context_id == NULL) |
587 | gtk_im_multicontext_get_delegate (multicontext: context); |
588 | |
589 | return priv->context_id; |
590 | } |
591 | |
592 | /** |
593 | * gtk_im_multicontext_set_context_id: |
594 | * @context: a `GtkIMMulticontext` |
595 | * @context_id: (nullable): the id to use |
596 | * |
597 | * Sets the context id for @context. |
598 | * |
599 | * This causes the currently active delegate of @context to be |
600 | * replaced by the delegate corresponding to the new context id. |
601 | * |
602 | * Setting this to a non-%NULL value overrides the system-wide |
603 | * IM module setting. See the [property@Gtk.Settings:gtk-im-module] |
604 | * property. |
605 | */ |
606 | void |
607 | gtk_im_multicontext_set_context_id (GtkIMMulticontext *context, |
608 | const char *context_id) |
609 | { |
610 | GtkIMMulticontextPrivate *priv; |
611 | |
612 | g_return_if_fail (GTK_IS_IM_MULTICONTEXT (context)); |
613 | |
614 | priv = context->priv; |
615 | |
616 | gtk_im_context_reset (GTK_IM_CONTEXT (context)); |
617 | g_free (mem: priv->context_id_aux); |
618 | priv->context_id_aux = g_strdup (str: context_id); |
619 | gtk_im_multicontext_set_delegate (multicontext: context, NULL, FALSE); |
620 | } |
621 | |
622 | static void |
623 | propagate_purpose (GtkIMMulticontext *context) |
624 | { |
625 | GtkInputPurpose purpose; |
626 | GtkInputHints hints; |
627 | |
628 | if (context->priv->delegate == NULL) |
629 | return; |
630 | |
631 | g_object_get (object: context, first_property_name: "input-purpose" , &purpose, NULL); |
632 | g_object_set (object: context->priv->delegate, first_property_name: "input-purpose" , purpose, NULL); |
633 | |
634 | g_object_get (object: context, first_property_name: "input-hints" , &hints, NULL); |
635 | g_object_set (object: context->priv->delegate, first_property_name: "input-hints" , hints, NULL); |
636 | } |
637 | |
638 | static void |
639 | gtk_im_multicontext_notify (GObject *object, |
640 | GParamSpec *pspec) |
641 | { |
642 | propagate_purpose (GTK_IM_MULTICONTEXT (object)); |
643 | } |
644 | |