3
Copyright (c) 2006-2007 uim Project http://uim.freedesktop.org/
7
Redistribution and use in source and binary forms, with or without
8
modification, are permitted provided that the following conditions
11
1. Redistributions of source code must retain the above copyright
12
notice, this list of conditions and the following disclaimer.
13
2. Redistributions in binary form must reproduce the above copyright
14
notice, this list of conditions and the following disclaimer in the
15
documentation and/or other materials provided with the distribution.
16
3. Neither the name of authors nor the names of its contributors
17
may be used to endorse or promote products derived from this software
18
without specific prior written permission.
20
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38
#include <glib/gprintf.h>
45
#include "gtk-im-uim.h"
46
#include "text-util.h"
49
acquire_text_in_gtk_text_view(GtkTextView *text_view, enum UTextOrigin origin,
50
int former_req_len, int latter_req_len,
51
char **former, char **latter)
53
GtkTextIter current, start, end;
55
if (!text_view->buffer)
58
gtk_text_buffer_get_iter_at_mark(text_view->buffer, ¤t,
59
gtk_text_buffer_get_mark(text_view->buffer,
62
case UTextOrigin_Cursor:
66
if (former_req_len >= 0) {
67
gtk_text_iter_backward_chars(&start, former_req_len);
69
if (former_req_len == UTextExtent_Full)
70
gtk_text_buffer_get_start_iter(text_view->buffer, &start);
71
else if (former_req_len == UTextExtent_Line)
72
gtk_text_view_backward_display_line_start(text_view, &start);
76
*former = gtk_text_iter_get_slice(&start, ¤t);
78
if (latter_req_len >= 0)
79
gtk_text_iter_forward_chars(&end, latter_req_len);
81
if (latter_req_len == UTextExtent_Full)
82
gtk_text_buffer_get_end_iter(text_view->buffer, &end);
83
else if (latter_req_len == UTextExtent_Line)
84
gtk_text_view_forward_display_line_end(text_view, &end);
90
*latter = gtk_text_iter_get_slice(¤t, &end);
93
case UTextOrigin_Beginning:
94
gtk_text_buffer_get_start_iter(text_view->buffer, &start);
99
if (latter_req_len >= 0)
100
gtk_text_iter_forward_chars(&end, latter_req_len);
102
if (latter_req_len == UTextExtent_Full)
103
gtk_text_buffer_get_end_iter(text_view->buffer, &end);
104
else if (latter_req_len == UTextExtent_Line)
105
gtk_text_view_forward_display_line_end(text_view, &end);
109
*latter = gtk_text_iter_get_slice(&start, &end);
112
case UTextOrigin_End:
113
gtk_text_buffer_get_end_iter(text_view->buffer, &end);
116
if (former_req_len >= 0) {
117
gtk_text_iter_backward_chars(&start, former_req_len);
119
if (former_req_len == UTextExtent_Full)
120
gtk_text_buffer_get_start_iter(text_view->buffer, &start);
121
else if (former_req_len == UTextExtent_Line)
122
gtk_text_view_backward_display_line_start(text_view, &start);
126
*former = gtk_text_iter_get_slice(&start, &end);
131
case UTextOrigin_Unspecified:
140
im_uim_acquire_primary_text(IMUIMContext *uic, enum UTextOrigin origin,
141
int former_req_len, int latter_req_len,
142
char **former, char **latter)
144
gchar *text, *former_start, *p;
145
gint cursor_index, len, precedence_len, following_len;
150
* We may try a specific way for GtkTextView since
151
* gtk_im_context_get_surrounding cannot get text with multiple lines.
153
if (GTK_IS_TEXT_VIEW(uic->widget))
154
return acquire_text_in_gtk_text_view(GTK_TEXT_VIEW(uic->widget), origin,
155
former_req_len, latter_req_len,
158
/* cursor_index is represented with byte index */
159
success = gtk_im_context_get_surrounding(GTK_IM_CONTEXT(uic), &text,
165
precedence_len = g_utf8_strlen(text, cursor_index);
166
following_len = g_utf8_strlen(text + cursor_index, strlen(text) -
169
case UTextOrigin_Cursor:
171
if (former_req_len >= 0) {
172
if (precedence_len > former_req_len)
173
offset = precedence_len - former_req_len;
175
if (!(~former_req_len & (~UTextExtent_Line | ~UTextExtent_Full))) {
180
former_start = g_utf8_offset_to_pointer(text, offset);
181
*former = g_strndup(former_start, text - former_start + cursor_index);
184
if (latter_req_len >= 0) {
185
if (following_len > latter_req_len)
186
offset = strlen(g_utf8_offset_to_pointer(text, precedence_len +
189
if (!(~latter_req_len & (~UTextExtent_Line | ~UTextExtent_Full))) {
195
*latter = g_strndup(text + cursor_index, len - cursor_index - offset);
196
if (latter_req_len == UTextExtent_Line) {
197
gchar *p = strchr(*latter, '\n');
203
case UTextOrigin_Beginning:
207
if (latter_req_len >= 0) {
208
if ((precedence_len + following_len) > latter_req_len)
209
offset = text + len - g_utf8_offset_to_pointer(text, latter_req_len);
211
if (!(~latter_req_len & (~UTextExtent_Line | ~UTextExtent_Full))) {
216
*latter = g_strndup(text, len - offset);
217
if (latter_req_len == UTextExtent_Line &&
218
(p = strchr(*latter, '\n')))
222
case UTextOrigin_End:
224
if (former_req_len >= 0) {
225
if ((precedence_len + following_len) > former_req_len)
226
offset = precedence_len + following_len - former_req_len;
228
if (!(~former_req_len & (~UTextExtent_Line | ~UTextExtent_Full))) {
233
former_start = g_utf8_offset_to_pointer(text, offset);
234
if (former_req_len == UTextExtent_Line &&
235
(p = strrchr(former_start, '\n')))
236
*former = g_strdup(p + 1);
238
*former = g_strndup(former_start, text + len - former_start);
243
case UTextOrigin_Unspecified:
254
im_uim_acquire_selection_text(IMUIMContext *uic, enum UTextOrigin origin,
255
int former_req_len, int latter_req_len,
256
char **former, char **latter)
258
gchar *former_start, *text = NULL, *p;
261
gboolean cursor_at_beginning = FALSE;
263
if (GTK_IS_ENTRY(uic->widget)) {
264
gint start, end, current;
266
if (gtk_editable_get_selection_bounds(GTK_EDITABLE(uic->widget),
268
text = gtk_editable_get_chars(GTK_EDITABLE(uic->widget), start, end);
269
current = GTK_ENTRY(uic->widget)->current_pos;
270
if (current == start)
271
cursor_at_beginning = TRUE;
273
} else if (GTK_IS_TEXT_VIEW(uic->widget)) {
274
GtkTextIter start, end, current;
276
if (GTK_TEXT_VIEW(uic->widget)->buffer &&
277
gtk_text_buffer_get_selection_bounds(GTK_TEXT_VIEW(uic->widget)->buffer, &start, &end)) {
278
text = gtk_text_iter_get_visible_text(&start, &end);
279
gtk_text_buffer_get_iter_at_mark(GTK_TEXT_VIEW(uic->widget)->buffer,
281
gtk_text_buffer_get_mark(GTK_TEXT_VIEW(uic->widget)->buffer, "insert"));
282
if (gtk_text_iter_compare(&start, ¤t) == 0)
283
cursor_at_beginning = TRUE;
287
* We use GDK_SELECTION_PRIMARY for the rest of widget, which means it is
288
* impossible to guarantee whether the obtained one is the selected text on
289
* the target application.
291
text = gtk_clipboard_wait_for_text(gtk_widget_get_clipboard(GTK_WIDGET(uic->widget), GDK_SELECTION_PRIMARY));
298
text_len = g_utf8_strlen(text, -1);
300
if (origin == UTextOrigin_Beginning ||
301
(origin == UTextOrigin_Cursor && cursor_at_beginning)) {
305
if (latter_req_len >= 0) {
306
if (latter_req_len < text_len)
307
offset = text + len - g_utf8_offset_to_pointer(text, latter_req_len);
309
if (!(~latter_req_len & (~UTextExtent_Line | ~UTextExtent_Full))) {
314
*latter = g_strndup(text, len - offset);
315
if (latter_req_len == UTextExtent_Line && (p = strchr(*latter, '\n')))
318
} else if (origin == UTextOrigin_End ||
319
(origin == UTextOrigin_Cursor && !cursor_at_beginning)) {
321
if (former_req_len >= 0) {
322
if (former_req_len < text_len)
323
offset = text_len - former_req_len;
325
if (!(~former_req_len & (~UTextExtent_Line | ~UTextExtent_Full))) {
330
former_start = g_utf8_offset_to_pointer(text, offset);
331
if (former_req_len == UTextExtent_Line &&
332
(p = strrchr(former_start, '\n')))
333
*former = g_strdup(p + 1);
335
*former = g_strndup(former_start, text + len - former_start);
348
im_uim_acquire_clipboard_text(IMUIMContext *uic, enum UTextOrigin origin,
349
int former_req_len, int latter_req_len,
350
char **former, char **latter)
352
gchar *former_start, *text = NULL, *p;
356
text = gtk_clipboard_wait_for_text(gtk_widget_get_clipboard(GTK_WIDGET(uic->widget), GDK_SELECTION_CLIPBOARD));
362
text_len = g_utf8_strlen(text, -1);
364
/* treat cursor position is virtually at the end for UTextArea_Clipboard */
366
case UTextOrigin_Cursor:
367
case UTextOrigin_End:
369
if (former_req_len >= 0) {
370
if (former_req_len < text_len)
371
offset = text_len - former_req_len;
373
if (!(~former_req_len & (~UTextExtent_Line | ~UTextExtent_Full))) {
378
former_start = g_utf8_offset_to_pointer(text, offset);
379
if (former_req_len == UTextExtent_Line &&
380
(p = strrchr(former_start, '\n')))
381
*former = g_strdup(p + 1);
383
*former = g_strndup(former_start, text + len - former_start);
386
case UTextOrigin_Beginning:
388
if (latter_req_len >= 0) {
389
if (latter_req_len < text_len)
390
offset = text + len - g_utf8_offset_to_pointer(text, latter_req_len);
392
if (!(~latter_req_len & (~UTextExtent_Line | ~UTextExtent_Full))) {
396
if (latter_req_len == UTextExtent_Line && (p = strchr(text, '\n')))
397
offset = text + len - p;
399
*latter = g_strndup(text, len - offset);
402
case UTextOrigin_Unspecified:
413
delete_text_in_gtk_entry(GtkEntry *entry, enum UTextOrigin origin,
414
int former_req_len, int latter_req_len)
416
gint start_pos, end_pos, current_pos;
418
current_pos = entry->current_pos;
421
case UTextOrigin_Cursor:
422
if (former_req_len >= 0) {
423
start_pos = current_pos - former_req_len;
425
if (!(~former_req_len & (~UTextExtent_Line | ~UTextExtent_Full)))
430
if (latter_req_len >= 0)
431
end_pos = current_pos + latter_req_len;
433
if (!(~latter_req_len & (~UTextExtent_Line | ~UTextExtent_Full)))
435
end_pos = entry->text_length;
439
case UTextOrigin_Beginning:
442
if (latter_req_len >= 0)
443
end_pos = latter_req_len;
445
if (!(~latter_req_len & (~UTextExtent_Line | ~UTextExtent_Full)))
447
end_pos = entry->text_length;
451
case UTextOrigin_End:
452
if (former_req_len >= 0)
453
start_pos = entry->text_length - former_req_len;
455
if (!(~former_req_len & (~UTextExtent_Line | ~UTextExtent_Full)))
460
end_pos = entry->text_length;
463
case UTextOrigin_Unspecified:
468
gtk_editable_delete_text(GTK_EDITABLE(entry), start_pos, end_pos);
474
delete_text_in_gtk_text_view(GtkTextView *text_view, enum UTextOrigin origin,
475
int former_req_len, int latter_req_len)
477
GtkTextIter current, start, end;
479
if (!text_view->buffer)
482
gtk_text_buffer_get_iter_at_mark(text_view->buffer, ¤t,
483
gtk_text_buffer_get_mark(text_view->buffer,
489
case UTextOrigin_Cursor:
490
if (former_req_len >= 0) {
491
gtk_text_iter_backward_chars(&start, former_req_len);
493
if (former_req_len == UTextExtent_Full)
494
gtk_text_buffer_get_start_iter(text_view->buffer, &start);
495
else if (former_req_len == UTextExtent_Line)
496
gtk_text_view_backward_display_line_start(text_view, &start);
501
if (latter_req_len >= 0)
502
gtk_text_iter_forward_chars(&end, latter_req_len);
504
if (latter_req_len == UTextExtent_Full)
505
gtk_text_buffer_get_end_iter(text_view->buffer, &end);
506
else if (latter_req_len == UTextExtent_Line)
507
gtk_text_view_forward_display_line_end(text_view, &end);
513
case UTextOrigin_Beginning:
514
gtk_text_buffer_get_start_iter(text_view->buffer, &start);
517
if (latter_req_len >= 0)
518
gtk_text_iter_forward_chars(&end, latter_req_len);
520
if (latter_req_len == UTextExtent_Full)
521
gtk_text_buffer_get_end_iter(text_view->buffer, &end);
522
else if (latter_req_len == UTextExtent_Line)
523
gtk_text_view_forward_display_line_end(text_view, &end);
529
case UTextOrigin_End:
530
gtk_text_buffer_get_end_iter(text_view->buffer, &end);
533
if (former_req_len >= 0) {
534
gtk_text_iter_backward_chars(&start, former_req_len);
536
if (former_req_len == UTextExtent_Full)
537
gtk_text_buffer_get_start_iter(text_view->buffer, &start);
538
else if (former_req_len == UTextExtent_Line)
539
gtk_text_view_backward_display_line_start(text_view, &start);
545
case UTextOrigin_Unspecified:
550
gtk_text_buffer_delete_interactive(text_view->buffer, &start, &end,
551
text_view->editable);
557
im_uim_delete_primary_text(IMUIMContext *uic, enum UTextOrigin origin,
558
int former_req_len, int latter_req_len)
561
gint offset, n_chars;
563
/* specific widgets handling */
564
if (GTK_IS_ENTRY(uic->widget))
565
return delete_text_in_gtk_entry(GTK_ENTRY(uic->widget), origin,
566
former_req_len, latter_req_len);
567
else if (GTK_IS_TEXT_VIEW(uic->widget))
568
return delete_text_in_gtk_text_view(GTK_TEXT_VIEW(uic->widget), origin,
569
former_req_len, latter_req_len);
571
* For the rest of widget, we use delete_surrounding, which means explicit
572
* value for former_len and latter_len is required and its origin must be the
575
offset = n_chars = 0;
578
case UTextOrigin_Cursor:
579
if (former_req_len >= 0) {
580
offset = -former_req_len;
581
n_chars = former_req_len;
586
if (latter_req_len >= 0)
587
n_chars += latter_req_len;
592
case UTextOrigin_Beginning:
593
case UTextOrigin_End:
594
case UTextOrigin_Unspecified:
599
success = gtk_im_context_delete_surrounding(GTK_IM_CONTEXT(uic), offset,
601
return success ? 0 : -1;
605
delete_selection_in_gtk_entry(GtkEntry *entry, enum UTextOrigin origin,
606
int former_req_len, int latter_req_len)
608
gint start, end, current_pos;
609
gboolean cursor_at_beginning = FALSE;
611
if (!gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end))
614
current_pos = entry->current_pos;
615
if (current_pos == start)
616
cursor_at_beginning = TRUE;
618
if (origin == UTextOrigin_Beginning ||
619
(origin == UTextOrigin_Cursor && cursor_at_beginning)) {
620
if (latter_req_len >= 0) {
621
if (latter_req_len < end - start)
622
end = start + latter_req_len;
624
if (!(~latter_req_len & (~UTextExtent_Line | ~UTextExtent_Full)))
627
} else if (origin == UTextOrigin_End ||
628
(origin == UTextOrigin_Cursor && !cursor_at_beginning)) {
629
if (former_req_len >= 0) {
630
if (former_req_len < end - start)
631
start = end - former_req_len;
633
if (!(~former_req_len & (~UTextExtent_Line | ~UTextExtent_Full)))
640
gtk_editable_delete_text(GTK_EDITABLE(entry), start, end);
646
delete_selection_in_gtk_text_view(GtkTextView *text_view,
647
enum UTextOrigin origin, int former_req_len,
650
GtkTextIter current, start, end, tmp_start, tmp_end;
651
gboolean cursor_at_beginning = FALSE;
653
if (!text_view->buffer)
656
if (gtk_text_buffer_get_selection_bounds(text_view->buffer, &start, &end)) {
657
gtk_text_buffer_get_iter_at_mark(text_view->buffer, ¤t,
658
gtk_text_buffer_get_mark(text_view->buffer, "insert"));
659
if (gtk_text_iter_compare(&start, ¤t) == 0)
660
cursor_at_beginning = TRUE;
665
if (origin == UTextOrigin_Beginning ||
666
(origin == UTextOrigin_Cursor && cursor_at_beginning)) {
670
if (latter_req_len >= 0) {
671
gtk_text_iter_forward_chars(&tmp_end, latter_req_len);
672
if (gtk_text_iter_compare(&tmp_end, &end) < 0)
675
if (latter_req_len == UTextExtent_Line) {
676
gtk_text_view_forward_display_line_end(text_view, &tmp_end);
677
if (gtk_text_iter_compare(&tmp_end, &end) < 0)
680
if (!(latter_req_len == UTextExtent_Full))
685
} else if (origin == UTextOrigin_End ||
686
(origin == UTextOrigin_Cursor && !cursor_at_beginning)) {
690
if (former_req_len >= 0) {
691
gtk_text_iter_backward_chars(&tmp_start, former_req_len);
692
if (gtk_text_iter_compare(&tmp_start, &start) > 0)
695
if (former_req_len == UTextExtent_Line) {
696
gtk_text_view_backward_display_line_start(text_view, &tmp_start);
697
if (gtk_text_iter_compare(&tmp_start, &start) > 0)
700
if (!(former_req_len == UTextExtent_Full))
709
gtk_text_buffer_delete_interactive(text_view->buffer, &start, &end,
710
text_view->editable);
716
im_uim_delete_selection_text(IMUIMContext *uic, enum UTextOrigin origin,
717
int former_req_len, int latter_req_len)
719
/* specific widgets handling */
720
if (GTK_IS_ENTRY(uic->widget))
721
return delete_selection_in_gtk_entry(GTK_ENTRY(uic->widget), origin,
722
former_req_len, latter_req_len);
723
else if (GTK_IS_TEXT_VIEW(uic->widget))
724
return delete_selection_in_gtk_text_view(GTK_TEXT_VIEW(uic->widget), origin,
725
former_req_len, latter_req_len);
727
* How can we delete a selected text?
728
* We just expect the selected text will be overridden by a newly committed