File: | ctk/ctktextbuffer.c |
Warning: | line 3485, column 70 The code calls sizeof() on a pointer type. This can produce an unexpected result |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* CTK - The GIMP Toolkit |
2 | * ctktextbuffer.c Copyright (C) 2000 Red Hat, Inc. |
3 | * Copyright (C) 2004 Nokia Corporation |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | /* |
20 | * Modified by the CTK+ Team and others 1997-2000. See the AUTHORS |
21 | * file for a list of people on the CTK+ Team. See the ChangeLog |
22 | * files for a list of changes. These files are distributed with |
23 | * CTK+ at ftp://ftp.ctk.org/pub/ctk/. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include <string.h> |
28 | #include <stdarg.h> |
29 | |
30 | #define CTK_TEXT_USE_INTERNAL_UNSUPPORTED_API |
31 | #include "ctkclipboard.h" |
32 | #include "ctkdnd.h" |
33 | #include "ctkinvisible.h" |
34 | #include "ctkmarshalers.h" |
35 | #include "ctktextbuffer.h" |
36 | #include "ctktextbufferprivate.h" |
37 | #include "ctktextbufferrichtext.h" |
38 | #include "ctktextbtree.h" |
39 | #include "ctktextiterprivate.h" |
40 | #include "ctktexttagprivate.h" |
41 | #include "ctktexttagtableprivate.h" |
42 | #include "ctkprivate.h" |
43 | #include "ctkintl.h" |
44 | |
45 | /** |
46 | * SECTION:ctktextbuffer |
47 | * @Short_description: Stores attributed text for display in a CtkTextView |
48 | * @Title: CtkTextBuffer |
49 | * @See_also: #CtkTextView, #CtkTextIter, #CtkTextMark |
50 | * |
51 | * You may wish to begin by reading the |
52 | * [text widget conceptual overview][TextWidget] |
53 | * which gives an overview of all the objects and data |
54 | * types related to the text widget and how they work together. |
55 | */ |
56 | |
57 | typedef struct _CtkTextLogAttrCache CtkTextLogAttrCache; |
58 | |
59 | struct _CtkTextBufferPrivate |
60 | { |
61 | CtkTargetList *copy_target_list; |
62 | CtkTargetEntry *copy_target_entries; |
63 | CtkTargetList *paste_target_list; |
64 | CtkTargetEntry *paste_target_entries; |
65 | |
66 | gint n_copy_target_entries; |
67 | gint n_paste_target_entries; |
68 | |
69 | CtkTextTagTable *tag_table; |
70 | CtkTextBTree *btree; |
71 | |
72 | GSList *clipboard_contents_buffers; |
73 | GSList *selection_clipboards; |
74 | |
75 | CtkTextLogAttrCache *log_attr_cache; |
76 | |
77 | guint user_action_count; |
78 | |
79 | /* Whether the buffer has been modified since last save */ |
80 | guint modified : 1; |
81 | guint has_selection : 1; |
82 | }; |
83 | |
84 | typedef struct _ClipboardRequest ClipboardRequest; |
85 | |
86 | struct _ClipboardRequest |
87 | { |
88 | CtkTextBuffer *buffer; |
89 | guint interactive : 1; |
90 | guint default_editable : 1; |
91 | guint replace_selection : 1; |
92 | }; |
93 | |
94 | enum { |
95 | INSERT_TEXT, |
96 | INSERT_PIXBUF, |
97 | INSERT_CHILD_ANCHOR, |
98 | DELETE_RANGE, |
99 | CHANGED, |
100 | MODIFIED_CHANGED, |
101 | MARK_SET, |
102 | MARK_DELETED, |
103 | APPLY_TAG, |
104 | REMOVE_TAG, |
105 | BEGIN_USER_ACTION, |
106 | END_USER_ACTION, |
107 | PASTE_DONE, |
108 | LAST_SIGNAL |
109 | }; |
110 | |
111 | enum { |
112 | PROP_0, |
113 | |
114 | /* Construct */ |
115 | PROP_TAG_TABLE, |
116 | |
117 | /* Normal */ |
118 | PROP_TEXT, |
119 | PROP_HAS_SELECTION, |
120 | PROP_CURSOR_POSITION, |
121 | PROP_COPY_TARGET_LIST, |
122 | PROP_PASTE_TARGET_LIST, |
123 | LAST_PROP |
124 | }; |
125 | |
126 | static void ctk_text_buffer_finalize (GObject *object); |
127 | |
128 | static void ctk_text_buffer_real_insert_text (CtkTextBuffer *buffer, |
129 | CtkTextIter *iter, |
130 | const gchar *text, |
131 | gint len); |
132 | static void ctk_text_buffer_real_insert_pixbuf (CtkTextBuffer *buffer, |
133 | CtkTextIter *iter, |
134 | GdkPixbuf *pixbuf); |
135 | static void ctk_text_buffer_real_insert_anchor (CtkTextBuffer *buffer, |
136 | CtkTextIter *iter, |
137 | CtkTextChildAnchor *anchor); |
138 | static void ctk_text_buffer_real_delete_range (CtkTextBuffer *buffer, |
139 | CtkTextIter *start, |
140 | CtkTextIter *end); |
141 | static void ctk_text_buffer_real_apply_tag (CtkTextBuffer *buffer, |
142 | CtkTextTag *tag, |
143 | const CtkTextIter *start_char, |
144 | const CtkTextIter *end_char); |
145 | static void ctk_text_buffer_real_remove_tag (CtkTextBuffer *buffer, |
146 | CtkTextTag *tag, |
147 | const CtkTextIter *start_char, |
148 | const CtkTextIter *end_char); |
149 | static void ctk_text_buffer_real_changed (CtkTextBuffer *buffer); |
150 | static void ctk_text_buffer_real_mark_set (CtkTextBuffer *buffer, |
151 | const CtkTextIter *iter, |
152 | CtkTextMark *mark); |
153 | |
154 | static CtkTextBTree* get_btree (CtkTextBuffer *buffer); |
155 | static void free_log_attr_cache (CtkTextLogAttrCache *cache); |
156 | |
157 | static void remove_all_selection_clipboards (CtkTextBuffer *buffer); |
158 | static void update_selection_clipboards (CtkTextBuffer *buffer); |
159 | |
160 | static CtkTextBuffer *create_clipboard_contents_buffer (CtkTextBuffer *buffer); |
161 | |
162 | static void ctk_text_buffer_free_target_lists (CtkTextBuffer *buffer); |
163 | |
164 | static void ctk_text_buffer_set_property (GObject *object, |
165 | guint prop_id, |
166 | const GValue *value, |
167 | GParamSpec *pspec); |
168 | static void ctk_text_buffer_get_property (GObject *object, |
169 | guint prop_id, |
170 | GValue *value, |
171 | GParamSpec *pspec); |
172 | static void ctk_text_buffer_notify (GObject *object, |
173 | GParamSpec *pspec); |
174 | |
175 | static guint signals[LAST_SIGNAL] = { 0 }; |
176 | static GParamSpec *text_buffer_props[LAST_PROP]; |
177 | |
178 | G_DEFINE_TYPE_WITH_PRIVATE (CtkTextBuffer, ctk_text_buffer, G_TYPE_OBJECT)static void ctk_text_buffer_init (CtkTextBuffer *self); static void ctk_text_buffer_class_init (CtkTextBufferClass *klass); static GType ctk_text_buffer_get_type_once (void); static gpointer ctk_text_buffer_parent_class = ((void*)0); static gint CtkTextBuffer_private_offset ; static void ctk_text_buffer_class_intern_init (gpointer klass ) { ctk_text_buffer_parent_class = g_type_class_peek_parent ( klass); if (CtkTextBuffer_private_offset != 0) g_type_class_adjust_private_offset (klass, &CtkTextBuffer_private_offset); ctk_text_buffer_class_init ((CtkTextBufferClass*) klass); } __attribute__ ((__unused__) ) static inline gpointer ctk_text_buffer_get_instance_private (CtkTextBuffer *self) { return (((gpointer) ((guint8*) (self ) + (glong) (CtkTextBuffer_private_offset)))); } GType ctk_text_buffer_get_type (void) { static GType static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); (void) ( 0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0)) ; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; __typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id ); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5) ; gapg_temp_newval; })) && g_once_init_enter_pointer ( &static_g_define_type_id)); })) ) { GType g_define_type_id = ctk_text_buffer_get_type_once (); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer) , "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id ) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer ((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id )); })) ; } return static_g_define_type_id; } __attribute__ ( (__noinline__)) static GType ctk_text_buffer_get_type_once (void ) { GType g_define_type_id = g_type_register_static_simple (( (GType) ((20) << (2))), g_intern_static_string ("CtkTextBuffer" ), sizeof (CtkTextBufferClass), (GClassInitFunc)(void (*)(void )) ctk_text_buffer_class_intern_init, sizeof (CtkTextBuffer), (GInstanceInitFunc)(void (*)(void)) ctk_text_buffer_init, (GTypeFlags ) 0); { {{ CtkTextBuffer_private_offset = g_type_add_instance_private (g_define_type_id, sizeof (CtkTextBufferPrivate)); };} } return g_define_type_id; } |
179 | |
180 | static void |
181 | ctk_text_buffer_class_init (CtkTextBufferClass *klass) |
182 | { |
183 | GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), (((GType) ((20) << (2)))))))); |
184 | |
185 | object_class->finalize = ctk_text_buffer_finalize; |
186 | object_class->set_property = ctk_text_buffer_set_property; |
187 | object_class->get_property = ctk_text_buffer_get_property; |
188 | object_class->notify = ctk_text_buffer_notify; |
189 | |
190 | klass->insert_text = ctk_text_buffer_real_insert_text; |
191 | klass->insert_pixbuf = ctk_text_buffer_real_insert_pixbuf; |
192 | klass->insert_child_anchor = ctk_text_buffer_real_insert_anchor; |
193 | klass->delete_range = ctk_text_buffer_real_delete_range; |
194 | klass->apply_tag = ctk_text_buffer_real_apply_tag; |
195 | klass->remove_tag = ctk_text_buffer_real_remove_tag; |
196 | klass->changed = ctk_text_buffer_real_changed; |
197 | klass->mark_set = ctk_text_buffer_real_mark_set; |
198 | |
199 | /* Construct */ |
200 | text_buffer_props[PROP_TAG_TABLE] = |
201 | g_param_spec_object ("tag-table", |
202 | P_("Tag Table")g_dgettext("ctk30" "-properties","Tag Table"), |
203 | P_("Text Tag Table")g_dgettext("ctk30" "-properties","Text Tag Table"), |
204 | CTK_TYPE_TEXT_TAG_TABLE(ctk_text_tag_table_get_type ()), |
205 | CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB | G_PARAM_CONSTRUCT_ONLY); |
206 | |
207 | /* Normal properties */ |
208 | |
209 | /** |
210 | * CtkTextBuffer:text: |
211 | * |
212 | * The text content of the buffer. Without child widgets and images, |
213 | * see ctk_text_buffer_get_text() for more information. |
214 | * |
215 | * Since: 2.8 |
216 | */ |
217 | text_buffer_props[PROP_TEXT] = |
218 | g_param_spec_string ("text", |
219 | P_("Text")g_dgettext("ctk30" "-properties","Text"), |
220 | P_("Current text of the buffer")g_dgettext("ctk30" "-properties","Current text of the buffer" ), |
221 | "", |
222 | CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB); |
223 | |
224 | /** |
225 | * CtkTextBuffer:has-selection: |
226 | * |
227 | * Whether the buffer has some text currently selected. |
228 | * |
229 | * Since: 2.10 |
230 | */ |
231 | text_buffer_props[PROP_HAS_SELECTION] = |
232 | g_param_spec_boolean ("has-selection", |
233 | P_("Has selection")g_dgettext("ctk30" "-properties","Has selection"), |
234 | P_("Whether the buffer has some text currently selected")g_dgettext("ctk30" "-properties","Whether the buffer has some text currently selected" ), |
235 | FALSE(0), |
236 | CTK_PARAM_READABLEG_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB); |
237 | |
238 | /** |
239 | * CtkTextBuffer:cursor-position: |
240 | * |
241 | * The position of the insert mark (as offset from the beginning |
242 | * of the buffer). It is useful for getting notified when the |
243 | * cursor moves. |
244 | * |
245 | * Since: 2.10 |
246 | */ |
247 | text_buffer_props[PROP_CURSOR_POSITION] = |
248 | g_param_spec_int ("cursor-position", |
249 | P_("Cursor position")g_dgettext("ctk30" "-properties","Cursor position"), |
250 | P_("The position of the insert mark (as offset from the beginning of the buffer)")g_dgettext("ctk30" "-properties","The position of the insert mark (as offset from the beginning of the buffer)" ), |
251 | 0, G_MAXINT2147483647, |
252 | 0, |
253 | CTK_PARAM_READABLEG_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB); |
254 | |
255 | /** |
256 | * CtkTextBuffer:copy-target-list: |
257 | * |
258 | * The list of targets this buffer supports for clipboard copying |
259 | * and as DND source. |
260 | * |
261 | * Since: 2.10 |
262 | */ |
263 | text_buffer_props[PROP_COPY_TARGET_LIST] = |
264 | g_param_spec_boxed ("copy-target-list", |
265 | P_("Copy target list")g_dgettext("ctk30" "-properties","Copy target list"), |
266 | P_("The list of targets this buffer supports for clipboard copying and DND source")g_dgettext("ctk30" "-properties","The list of targets this buffer supports for clipboard copying and DND source" ), |
267 | CTK_TYPE_TARGET_LIST(ctk_target_list_get_type ()), |
268 | CTK_PARAM_READABLEG_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB); |
269 | |
270 | /** |
271 | * CtkTextBuffer:paste-target-list: |
272 | * |
273 | * The list of targets this buffer supports for clipboard pasting |
274 | * and as DND destination. |
275 | * |
276 | * Since: 2.10 |
277 | */ |
278 | text_buffer_props[PROP_PASTE_TARGET_LIST] = |
279 | g_param_spec_boxed ("paste-target-list", |
280 | P_("Paste target list")g_dgettext("ctk30" "-properties","Paste target list"), |
281 | P_("The list of targets this buffer supports for clipboard pasting and DND destination")g_dgettext("ctk30" "-properties","The list of targets this buffer supports for clipboard pasting and DND destination" ), |
282 | CTK_TYPE_TARGET_LIST(ctk_target_list_get_type ()), |
283 | CTK_PARAM_READABLEG_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB); |
284 | |
285 | g_object_class_install_properties (object_class, LAST_PROP, text_buffer_props); |
286 | |
287 | /** |
288 | * CtkTextBuffer::insert-text: |
289 | * @textbuffer: the object which received the signal |
290 | * @location: position to insert @text in @textbuffer |
291 | * @text: the UTF-8 text to be inserted |
292 | * @len: length of the inserted text in bytes |
293 | * |
294 | * The ::insert-text signal is emitted to insert text in a #CtkTextBuffer. |
295 | * Insertion actually occurs in the default handler. |
296 | * |
297 | * Note that if your handler runs before the default handler it must not |
298 | * invalidate the @location iter (or has to revalidate it). |
299 | * The default signal handler revalidates it to point to the end of the |
300 | * inserted text. |
301 | * |
302 | * See also: |
303 | * ctk_text_buffer_insert(), |
304 | * ctk_text_buffer_insert_range(). |
305 | */ |
306 | signals[INSERT_TEXT] = |
307 | g_signal_new (I_("insert-text")g_intern_static_string ("insert-text"), |
308 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
309 | G_SIGNAL_RUN_LAST, |
310 | G_STRUCT_OFFSET (CtkTextBufferClass, insert_text)((glong) __builtin_offsetof(CtkTextBufferClass, insert_text)), |
311 | NULL((void*)0), NULL((void*)0), |
312 | _ctk_marshal_VOID__BOXED_STRING_INT, |
313 | G_TYPE_NONE((GType) ((1) << (2))), |
314 | 3, |
315 | CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()) | G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))), |
316 | G_TYPE_STRING((GType) ((16) << (2))) | G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))), |
317 | G_TYPE_INT((GType) ((6) << (2)))); |
318 | g_signal_set_va_marshaller (signals[INSERT_TEXT], G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type), |
319 | _ctk_marshal_VOID__BOXED_STRING_INTv); |
320 | |
321 | /** |
322 | * CtkTextBuffer::insert-pixbuf: |
323 | * @textbuffer: the object which received the signal |
324 | * @location: position to insert @pixbuf in @textbuffer |
325 | * @pixbuf: the #GdkPixbuf to be inserted |
326 | * |
327 | * The ::insert-pixbuf signal is emitted to insert a #GdkPixbuf |
328 | * in a #CtkTextBuffer. Insertion actually occurs in the default handler. |
329 | * |
330 | * Note that if your handler runs before the default handler it must not |
331 | * invalidate the @location iter (or has to revalidate it). |
332 | * The default signal handler revalidates it to be placed after the |
333 | * inserted @pixbuf. |
334 | * |
335 | * See also: ctk_text_buffer_insert_pixbuf(). |
336 | */ |
337 | signals[INSERT_PIXBUF] = |
338 | g_signal_new (I_("insert-pixbuf")g_intern_static_string ("insert-pixbuf"), |
339 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
340 | G_SIGNAL_RUN_LAST, |
341 | G_STRUCT_OFFSET (CtkTextBufferClass, insert_pixbuf)((glong) __builtin_offsetof(CtkTextBufferClass, insert_pixbuf )), |
342 | NULL((void*)0), NULL((void*)0), |
343 | _ctk_marshal_VOID__BOXED_OBJECT, |
344 | G_TYPE_NONE((GType) ((1) << (2))), |
345 | 2, |
346 | CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()) | G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))), |
347 | GDK_TYPE_PIXBUF(gdk_pixbuf_get_type ())); |
348 | g_signal_set_va_marshaller (signals[INSERT_PIXBUF], |
349 | G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type), |
350 | _ctk_marshal_VOID__BOXED_OBJECTv); |
351 | |
352 | |
353 | /** |
354 | * CtkTextBuffer::insert-child-anchor: |
355 | * @textbuffer: the object which received the signal |
356 | * @location: position to insert @anchor in @textbuffer |
357 | * @anchor: the #CtkTextChildAnchor to be inserted |
358 | * |
359 | * The ::insert-child-anchor signal is emitted to insert a |
360 | * #CtkTextChildAnchor in a #CtkTextBuffer. |
361 | * Insertion actually occurs in the default handler. |
362 | * |
363 | * Note that if your handler runs before the default handler it must |
364 | * not invalidate the @location iter (or has to revalidate it). |
365 | * The default signal handler revalidates it to be placed after the |
366 | * inserted @anchor. |
367 | * |
368 | * See also: ctk_text_buffer_insert_child_anchor(). |
369 | */ |
370 | signals[INSERT_CHILD_ANCHOR] = |
371 | g_signal_new (I_("insert-child-anchor")g_intern_static_string ("insert-child-anchor"), |
372 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
373 | G_SIGNAL_RUN_LAST, |
374 | G_STRUCT_OFFSET (CtkTextBufferClass, insert_child_anchor)((glong) __builtin_offsetof(CtkTextBufferClass, insert_child_anchor )), |
375 | NULL((void*)0), NULL((void*)0), |
376 | _ctk_marshal_VOID__BOXED_OBJECT, |
377 | G_TYPE_NONE((GType) ((1) << (2))), |
378 | 2, |
379 | CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()) | G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))), |
380 | CTK_TYPE_TEXT_CHILD_ANCHOR(ctk_text_child_anchor_get_type ())); |
381 | g_signal_set_va_marshaller (signals[INSERT_CHILD_ANCHOR], |
382 | G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type), |
383 | _ctk_marshal_VOID__BOXED_OBJECTv); |
384 | |
385 | /** |
386 | * CtkTextBuffer::delete-range: |
387 | * @textbuffer: the object which received the signal |
388 | * @start: the start of the range to be deleted |
389 | * @end: the end of the range to be deleted |
390 | * |
391 | * The ::delete-range signal is emitted to delete a range |
392 | * from a #CtkTextBuffer. |
393 | * |
394 | * Note that if your handler runs before the default handler it must not |
395 | * invalidate the @start and @end iters (or has to revalidate them). |
396 | * The default signal handler revalidates the @start and @end iters to |
397 | * both point to the location where text was deleted. Handlers |
398 | * which run after the default handler (see g_signal_connect_after()) |
399 | * do not have access to the deleted text. |
400 | * |
401 | * See also: ctk_text_buffer_delete(). |
402 | */ |
403 | signals[DELETE_RANGE] = |
404 | g_signal_new (I_("delete-range")g_intern_static_string ("delete-range"), |
405 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
406 | G_SIGNAL_RUN_LAST, |
407 | G_STRUCT_OFFSET (CtkTextBufferClass, delete_range)((glong) __builtin_offsetof(CtkTextBufferClass, delete_range) ), |
408 | NULL((void*)0), NULL((void*)0), |
409 | _ctk_marshal_VOID__BOXED_BOXED, |
410 | G_TYPE_NONE((GType) ((1) << (2))), |
411 | 2, |
412 | CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()) | G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))), |
413 | CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()) | G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0)))); |
414 | g_signal_set_va_marshaller (signals[DELETE_RANGE], |
415 | G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type), |
416 | _ctk_marshal_VOID__BOXED_BOXEDv); |
417 | |
418 | /** |
419 | * CtkTextBuffer::changed: |
420 | * @textbuffer: the object which received the signal |
421 | * |
422 | * The ::changed signal is emitted when the content of a #CtkTextBuffer |
423 | * has changed. |
424 | */ |
425 | signals[CHANGED] = |
426 | g_signal_new (I_("changed")g_intern_static_string ("changed"), |
427 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
428 | G_SIGNAL_RUN_LAST, |
429 | G_STRUCT_OFFSET (CtkTextBufferClass, changed)((glong) __builtin_offsetof(CtkTextBufferClass, changed)), |
430 | NULL((void*)0), NULL((void*)0), |
431 | NULL((void*)0), |
432 | G_TYPE_NONE((GType) ((1) << (2))), |
433 | 0); |
434 | |
435 | /** |
436 | * CtkTextBuffer::modified-changed: |
437 | * @textbuffer: the object which received the signal |
438 | * |
439 | * The ::modified-changed signal is emitted when the modified bit of a |
440 | * #CtkTextBuffer flips. |
441 | * |
442 | * See also: |
443 | * ctk_text_buffer_set_modified(). |
444 | */ |
445 | signals[MODIFIED_CHANGED] = |
446 | g_signal_new (I_("modified-changed")g_intern_static_string ("modified-changed"), |
447 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
448 | G_SIGNAL_RUN_LAST, |
449 | G_STRUCT_OFFSET (CtkTextBufferClass, modified_changed)((glong) __builtin_offsetof(CtkTextBufferClass, modified_changed )), |
450 | NULL((void*)0), NULL((void*)0), |
451 | NULL((void*)0), |
452 | G_TYPE_NONE((GType) ((1) << (2))), |
453 | 0); |
454 | |
455 | /** |
456 | * CtkTextBuffer::mark-set: |
457 | * @textbuffer: the object which received the signal |
458 | * @location: The location of @mark in @textbuffer |
459 | * @mark: The mark that is set |
460 | * |
461 | * The ::mark-set signal is emitted as notification |
462 | * after a #CtkTextMark is set. |
463 | * |
464 | * See also: |
465 | * ctk_text_buffer_create_mark(), |
466 | * ctk_text_buffer_move_mark(). |
467 | */ |
468 | signals[MARK_SET] = |
469 | g_signal_new (I_("mark-set")g_intern_static_string ("mark-set"), |
470 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
471 | G_SIGNAL_RUN_LAST, |
472 | G_STRUCT_OFFSET (CtkTextBufferClass, mark_set)((glong) __builtin_offsetof(CtkTextBufferClass, mark_set)), |
473 | NULL((void*)0), NULL((void*)0), |
474 | _ctk_marshal_VOID__BOXED_OBJECT, |
475 | G_TYPE_NONE((GType) ((1) << (2))), |
476 | 2, |
477 | CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()), |
478 | CTK_TYPE_TEXT_MARK(ctk_text_mark_get_type ())); |
479 | g_signal_set_va_marshaller (signals[MARK_SET], |
480 | G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type), |
481 | _ctk_marshal_VOID__BOXED_OBJECTv); |
482 | |
483 | /** |
484 | * CtkTextBuffer::mark-deleted: |
485 | * @textbuffer: the object which received the signal |
486 | * @mark: The mark that was deleted |
487 | * |
488 | * The ::mark-deleted signal is emitted as notification |
489 | * after a #CtkTextMark is deleted. |
490 | * |
491 | * See also: |
492 | * ctk_text_buffer_delete_mark(). |
493 | */ |
494 | signals[MARK_DELETED] = |
495 | g_signal_new (I_("mark-deleted")g_intern_static_string ("mark-deleted"), |
496 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
497 | G_SIGNAL_RUN_LAST, |
498 | G_STRUCT_OFFSET (CtkTextBufferClass, mark_deleted)((glong) __builtin_offsetof(CtkTextBufferClass, mark_deleted) ), |
499 | NULL((void*)0), NULL((void*)0), |
500 | NULL((void*)0), |
501 | G_TYPE_NONE((GType) ((1) << (2))), |
502 | 1, |
503 | CTK_TYPE_TEXT_MARK(ctk_text_mark_get_type ())); |
504 | |
505 | /** |
506 | * CtkTextBuffer::apply-tag: |
507 | * @textbuffer: the object which received the signal |
508 | * @tag: the applied tag |
509 | * @start: the start of the range the tag is applied to |
510 | * @end: the end of the range the tag is applied to |
511 | * |
512 | * The ::apply-tag signal is emitted to apply a tag to a |
513 | * range of text in a #CtkTextBuffer. |
514 | * Applying actually occurs in the default handler. |
515 | * |
516 | * Note that if your handler runs before the default handler it must not |
517 | * invalidate the @start and @end iters (or has to revalidate them). |
518 | * |
519 | * See also: |
520 | * ctk_text_buffer_apply_tag(), |
521 | * ctk_text_buffer_insert_with_tags(), |
522 | * ctk_text_buffer_insert_range(). |
523 | */ |
524 | signals[APPLY_TAG] = |
525 | g_signal_new (I_("apply-tag")g_intern_static_string ("apply-tag"), |
526 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
527 | G_SIGNAL_RUN_LAST, |
528 | G_STRUCT_OFFSET (CtkTextBufferClass, apply_tag)((glong) __builtin_offsetof(CtkTextBufferClass, apply_tag)), |
529 | NULL((void*)0), NULL((void*)0), |
530 | _ctk_marshal_VOID__OBJECT_BOXED_BOXED, |
531 | G_TYPE_NONE((GType) ((1) << (2))), |
532 | 3, |
533 | CTK_TYPE_TEXT_TAG(ctk_text_tag_get_type ()), |
534 | CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()), |
535 | CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ())); |
536 | g_signal_set_va_marshaller (signals[APPLY_TAG], |
537 | G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type), |
538 | _ctk_marshal_VOID__OBJECT_BOXED_BOXEDv); |
539 | |
540 | |
541 | /** |
542 | * CtkTextBuffer::remove-tag: |
543 | * @textbuffer: the object which received the signal |
544 | * @tag: the tag to be removed |
545 | * @start: the start of the range the tag is removed from |
546 | * @end: the end of the range the tag is removed from |
547 | * |
548 | * The ::remove-tag signal is emitted to remove all occurrences of @tag from |
549 | * a range of text in a #CtkTextBuffer. |
550 | * Removal actually occurs in the default handler. |
551 | * |
552 | * Note that if your handler runs before the default handler it must not |
553 | * invalidate the @start and @end iters (or has to revalidate them). |
554 | * |
555 | * See also: |
556 | * ctk_text_buffer_remove_tag(). |
557 | */ |
558 | signals[REMOVE_TAG] = |
559 | g_signal_new (I_("remove-tag")g_intern_static_string ("remove-tag"), |
560 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
561 | G_SIGNAL_RUN_LAST, |
562 | G_STRUCT_OFFSET (CtkTextBufferClass, remove_tag)((glong) __builtin_offsetof(CtkTextBufferClass, remove_tag)), |
563 | NULL((void*)0), NULL((void*)0), |
564 | _ctk_marshal_VOID__OBJECT_BOXED_BOXED, |
565 | G_TYPE_NONE((GType) ((1) << (2))), |
566 | 3, |
567 | CTK_TYPE_TEXT_TAG(ctk_text_tag_get_type ()), |
568 | CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()), |
569 | CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ())); |
570 | g_signal_set_va_marshaller (signals[REMOVE_TAG], |
571 | G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type), |
572 | _ctk_marshal_VOID__OBJECT_BOXED_BOXEDv); |
573 | |
574 | /** |
575 | * CtkTextBuffer::begin-user-action: |
576 | * @textbuffer: the object which received the signal |
577 | * |
578 | * The ::begin-user-action signal is emitted at the beginning of a single |
579 | * user-visible operation on a #CtkTextBuffer. |
580 | * |
581 | * See also: |
582 | * ctk_text_buffer_begin_user_action(), |
583 | * ctk_text_buffer_insert_interactive(), |
584 | * ctk_text_buffer_insert_range_interactive(), |
585 | * ctk_text_buffer_delete_interactive(), |
586 | * ctk_text_buffer_backspace(), |
587 | * ctk_text_buffer_delete_selection(). |
588 | */ |
589 | signals[BEGIN_USER_ACTION] = |
590 | g_signal_new (I_("begin-user-action")g_intern_static_string ("begin-user-action"), |
591 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
592 | G_SIGNAL_RUN_LAST, |
593 | G_STRUCT_OFFSET (CtkTextBufferClass, begin_user_action)((glong) __builtin_offsetof(CtkTextBufferClass, begin_user_action )), |
594 | NULL((void*)0), NULL((void*)0), |
595 | NULL((void*)0), |
596 | G_TYPE_NONE((GType) ((1) << (2))), |
597 | 0); |
598 | |
599 | /** |
600 | * CtkTextBuffer::end-user-action: |
601 | * @textbuffer: the object which received the signal |
602 | * |
603 | * The ::end-user-action signal is emitted at the end of a single |
604 | * user-visible operation on the #CtkTextBuffer. |
605 | * |
606 | * See also: |
607 | * ctk_text_buffer_end_user_action(), |
608 | * ctk_text_buffer_insert_interactive(), |
609 | * ctk_text_buffer_insert_range_interactive(), |
610 | * ctk_text_buffer_delete_interactive(), |
611 | * ctk_text_buffer_backspace(), |
612 | * ctk_text_buffer_delete_selection(), |
613 | * ctk_text_buffer_backspace(). |
614 | */ |
615 | signals[END_USER_ACTION] = |
616 | g_signal_new (I_("end-user-action")g_intern_static_string ("end-user-action"), |
617 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
618 | G_SIGNAL_RUN_LAST, |
619 | G_STRUCT_OFFSET (CtkTextBufferClass, end_user_action)((glong) __builtin_offsetof(CtkTextBufferClass, end_user_action )), |
620 | NULL((void*)0), NULL((void*)0), |
621 | NULL((void*)0), |
622 | G_TYPE_NONE((GType) ((1) << (2))), |
623 | 0); |
624 | |
625 | /** |
626 | * CtkTextBuffer::paste-done: |
627 | * @textbuffer: the object which received the signal |
628 | * @clipboard: the #CtkClipboard pasted from |
629 | * |
630 | * The paste-done signal is emitted after paste operation has been completed. |
631 | * This is useful to properly scroll the view to the end of the pasted text. |
632 | * See ctk_text_buffer_paste_clipboard() for more details. |
633 | * |
634 | * Since: 2.16 |
635 | */ |
636 | signals[PASTE_DONE] = |
637 | g_signal_new (I_("paste-done")g_intern_static_string ("paste-done"), |
638 | G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)), |
639 | G_SIGNAL_RUN_LAST, |
640 | G_STRUCT_OFFSET (CtkTextBufferClass, paste_done)((glong) __builtin_offsetof(CtkTextBufferClass, paste_done)), |
641 | NULL((void*)0), NULL((void*)0), |
642 | NULL((void*)0), |
643 | G_TYPE_NONE((GType) ((1) << (2))), |
644 | 1, |
645 | CTK_TYPE_CLIPBOARD(ctk_clipboard_get_type ())); |
646 | } |
647 | |
648 | static void |
649 | ctk_text_buffer_init (CtkTextBuffer *buffer) |
650 | { |
651 | buffer->priv = ctk_text_buffer_get_instance_private (buffer); |
652 | buffer->priv->clipboard_contents_buffers = NULL((void*)0); |
653 | buffer->priv->tag_table = NULL((void*)0); |
654 | |
655 | /* allow copying of arbiatray stuff in the internal rich text format */ |
656 | ctk_text_buffer_register_serialize_tagset (buffer, NULL((void*)0)); |
657 | } |
658 | |
659 | static void |
660 | set_table (CtkTextBuffer *buffer, CtkTextTagTable *table) |
661 | { |
662 | CtkTextBufferPrivate *priv = buffer->priv; |
663 | |
664 | g_return_if_fail (priv->tag_table == NULL)do { if ((priv->tag_table == ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "priv->tag_table == NULL" ); return; } } while (0); |
665 | |
666 | if (table) |
667 | { |
668 | priv->tag_table = table; |
669 | g_object_ref (priv->tag_table)((__typeof__ (priv->tag_table)) (g_object_ref) (priv->tag_table )); |
670 | _ctk_text_tag_table_add_buffer (table, buffer); |
671 | } |
672 | } |
673 | |
674 | static CtkTextTagTable* |
675 | get_table (CtkTextBuffer *buffer) |
676 | { |
677 | CtkTextBufferPrivate *priv = buffer->priv; |
678 | |
679 | if (priv->tag_table == NULL((void*)0)) |
680 | { |
681 | priv->tag_table = ctk_text_tag_table_new (); |
682 | _ctk_text_tag_table_add_buffer (priv->tag_table, buffer); |
683 | } |
684 | |
685 | return priv->tag_table; |
686 | } |
687 | |
688 | static void |
689 | ctk_text_buffer_set_property (GObject *object, |
690 | guint prop_id, |
691 | const GValue *value, |
692 | GParamSpec *pspec) |
693 | { |
694 | CtkTextBuffer *text_buffer; |
695 | |
696 | text_buffer = CTK_TEXT_BUFFER (object)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((ctk_text_buffer_get_type ())))))); |
697 | |
698 | switch (prop_id) |
699 | { |
700 | case PROP_TAG_TABLE: |
701 | set_table (text_buffer, g_value_get_object (value)); |
702 | break; |
703 | |
704 | case PROP_TEXT: |
705 | ctk_text_buffer_set_text (text_buffer, |
706 | g_value_get_string (value), -1); |
707 | break; |
708 | |
709 | default: |
710 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "ctktextbuffer.c", 710, ("property"), _glib__property_id, _glib__pspec ->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) ( _glib__pspec))->g_class))->g_type)))), (g_type_name ((( (((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); |
711 | break; |
712 | } |
713 | } |
714 | |
715 | static void |
716 | ctk_text_buffer_get_property (GObject *object, |
717 | guint prop_id, |
718 | GValue *value, |
719 | GParamSpec *pspec) |
720 | { |
721 | CtkTextBuffer *text_buffer; |
722 | CtkTextIter iter; |
723 | |
724 | text_buffer = CTK_TEXT_BUFFER (object)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((ctk_text_buffer_get_type ())))))); |
725 | |
726 | switch (prop_id) |
727 | { |
728 | case PROP_TAG_TABLE: |
729 | g_value_set_object (value, get_table (text_buffer)); |
730 | break; |
731 | |
732 | case PROP_TEXT: |
733 | { |
734 | CtkTextIter start, end; |
735 | |
736 | ctk_text_buffer_get_start_iter (text_buffer, &start); |
737 | ctk_text_buffer_get_end_iter (text_buffer, &end); |
738 | |
739 | g_value_take_string (value, |
740 | ctk_text_buffer_get_text (text_buffer, |
741 | &start, &end, FALSE(0))); |
742 | break; |
743 | } |
744 | |
745 | case PROP_HAS_SELECTION: |
746 | g_value_set_boolean (value, text_buffer->priv->has_selection); |
747 | break; |
748 | |
749 | case PROP_CURSOR_POSITION: |
750 | ctk_text_buffer_get_iter_at_mark (text_buffer, &iter, |
751 | ctk_text_buffer_get_insert (text_buffer)); |
752 | g_value_set_int (value, ctk_text_iter_get_offset (&iter)); |
753 | break; |
754 | |
755 | case PROP_COPY_TARGET_LIST: |
756 | g_value_set_boxed (value, ctk_text_buffer_get_copy_target_list (text_buffer)); |
757 | break; |
758 | |
759 | case PROP_PASTE_TARGET_LIST: |
760 | g_value_set_boxed (value, ctk_text_buffer_get_paste_target_list (text_buffer)); |
761 | break; |
762 | |
763 | default: |
764 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "ctktextbuffer.c", 764, ("property"), _glib__property_id, _glib__pspec ->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) ( _glib__pspec))->g_class))->g_type)))), (g_type_name ((( (((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); |
765 | break; |
766 | } |
767 | } |
768 | |
769 | static void |
770 | ctk_text_buffer_notify (GObject *object, |
771 | GParamSpec *pspec) |
772 | { |
773 | if (!strcmp (pspec->name, "copy-target-list") || |
774 | !strcmp (pspec->name, "paste-target-list")) |
775 | { |
776 | ctk_text_buffer_free_target_lists (CTK_TEXT_BUFFER (object)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((ctk_text_buffer_get_type ()))))))); |
777 | } |
778 | } |
779 | |
780 | /** |
781 | * ctk_text_buffer_new: |
782 | * @table: (allow-none): a tag table, or %NULL to create a new one |
783 | * |
784 | * Creates a new text buffer. |
785 | * |
786 | * Returns: a new text buffer |
787 | **/ |
788 | CtkTextBuffer* |
789 | ctk_text_buffer_new (CtkTextTagTable *table) |
790 | { |
791 | CtkTextBuffer *text_buffer; |
792 | |
793 | text_buffer = g_object_new (CTK_TYPE_TEXT_BUFFER(ctk_text_buffer_get_type ()), "tag-table", table, NULL((void*)0)); |
794 | |
795 | return text_buffer; |
796 | } |
797 | |
798 | static void |
799 | ctk_text_buffer_finalize (GObject *object) |
800 | { |
801 | CtkTextBuffer *buffer; |
802 | CtkTextBufferPrivate *priv; |
803 | |
804 | buffer = CTK_TEXT_BUFFER (object)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((ctk_text_buffer_get_type ())))))); |
805 | priv = buffer->priv; |
806 | |
807 | remove_all_selection_clipboards (buffer); |
808 | |
809 | if (priv->tag_table) |
810 | { |
811 | _ctk_text_tag_table_remove_buffer (priv->tag_table, buffer); |
812 | g_object_unref (priv->tag_table); |
813 | priv->tag_table = NULL((void*)0); |
814 | } |
815 | |
816 | if (priv->btree) |
817 | { |
818 | _ctk_text_btree_unref (priv->btree); |
819 | priv->btree = NULL((void*)0); |
820 | } |
821 | |
822 | if (priv->log_attr_cache) |
823 | free_log_attr_cache (priv->log_attr_cache); |
824 | |
825 | priv->log_attr_cache = NULL((void*)0); |
826 | |
827 | ctk_text_buffer_free_target_lists (buffer); |
828 | |
829 | G_OBJECT_CLASS (ctk_text_buffer_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((ctk_text_buffer_parent_class)), (((GType) ((20) << (2))))))))->finalize (object); |
830 | } |
831 | |
832 | static CtkTextBTree* |
833 | get_btree (CtkTextBuffer *buffer) |
834 | { |
835 | CtkTextBufferPrivate *priv = buffer->priv; |
836 | |
837 | if (priv->btree == NULL((void*)0)) |
838 | priv->btree = _ctk_text_btree_new (ctk_text_buffer_get_tag_table (buffer), |
839 | buffer); |
840 | |
841 | return priv->btree; |
842 | } |
843 | |
844 | CtkTextBTree* |
845 | _ctk_text_buffer_get_btree (CtkTextBuffer *buffer) |
846 | { |
847 | return get_btree (buffer); |
848 | } |
849 | |
850 | /** |
851 | * ctk_text_buffer_get_tag_table: |
852 | * @buffer: a #CtkTextBuffer |
853 | * |
854 | * Get the #CtkTextTagTable associated with this buffer. |
855 | * |
856 | * Returns: (transfer none): the buffer’s tag table |
857 | **/ |
858 | CtkTextTagTable* |
859 | ctk_text_buffer_get_tag_table (CtkTextBuffer *buffer) |
860 | { |
861 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
862 | |
863 | return get_table (buffer); |
864 | } |
865 | |
866 | /** |
867 | * ctk_text_buffer_set_text: |
868 | * @buffer: a #CtkTextBuffer |
869 | * @text: UTF-8 text to insert |
870 | * @len: length of @text in bytes |
871 | * |
872 | * Deletes current contents of @buffer, and inserts @text instead. If |
873 | * @len is -1, @text must be nul-terminated. @text must be valid UTF-8. |
874 | **/ |
875 | void |
876 | ctk_text_buffer_set_text (CtkTextBuffer *buffer, |
877 | const gchar *text, |
878 | gint len) |
879 | { |
880 | CtkTextIter start, end; |
881 | |
882 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
883 | g_return_if_fail (text != NULL)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "text != NULL"); return; } } while (0); |
884 | |
885 | if (len < 0) |
886 | len = strlen (text); |
887 | |
888 | ctk_text_buffer_get_bounds (buffer, &start, &end); |
889 | |
890 | ctk_text_buffer_delete (buffer, &start, &end); |
891 | |
892 | if (len > 0) |
893 | { |
894 | ctk_text_buffer_get_iter_at_offset (buffer, &start, 0); |
895 | ctk_text_buffer_insert (buffer, &start, text, len); |
896 | } |
897 | } |
898 | |
899 | |
900 | |
901 | /* |
902 | * Insertion |
903 | */ |
904 | |
905 | static void |
906 | ctk_text_buffer_real_insert_text (CtkTextBuffer *buffer, |
907 | CtkTextIter *iter, |
908 | const gchar *text, |
909 | gint len) |
910 | { |
911 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
912 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
913 | |
914 | _ctk_text_btree_insert (iter, text, len); |
915 | |
916 | g_signal_emit (buffer, signals[CHANGED], 0); |
917 | g_object_notify_by_pspec (G_OBJECT (buffer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((buffer)), (((GType) ((20) << (2)))))))), text_buffer_props[PROP_CURSOR_POSITION]); |
918 | } |
919 | |
920 | static void |
921 | ctk_text_buffer_emit_insert (CtkTextBuffer *buffer, |
922 | CtkTextIter *iter, |
923 | const gchar *text, |
924 | gint len) |
925 | { |
926 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
927 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
928 | g_return_if_fail (text != NULL)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "text != NULL"); return; } } while (0); |
929 | |
930 | if (len < 0) |
931 | len = strlen (text); |
932 | |
933 | g_return_if_fail (g_utf8_validate (text, len, NULL))do { if ((g_utf8_validate (text, len, ((void*)0)))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "g_utf8_validate (text, len, NULL)"); return; } } while (0); |
934 | |
935 | if (len > 0) |
936 | { |
937 | g_signal_emit (buffer, signals[INSERT_TEXT], 0, |
938 | iter, text, len); |
939 | } |
940 | } |
941 | |
942 | /** |
943 | * ctk_text_buffer_insert: |
944 | * @buffer: a #CtkTextBuffer |
945 | * @iter: a position in the buffer |
946 | * @text: text in UTF-8 format |
947 | * @len: length of text in bytes, or -1 |
948 | * |
949 | * Inserts @len bytes of @text at position @iter. If @len is -1, |
950 | * @text must be nul-terminated and will be inserted in its |
951 | * entirety. Emits the “insert-text” signal; insertion actually occurs |
952 | * in the default handler for the signal. @iter is invalidated when |
953 | * insertion occurs (because the buffer contents change), but the |
954 | * default signal handler revalidates it to point to the end of the |
955 | * inserted text. |
956 | **/ |
957 | void |
958 | ctk_text_buffer_insert (CtkTextBuffer *buffer, |
959 | CtkTextIter *iter, |
960 | const gchar *text, |
961 | gint len) |
962 | { |
963 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
964 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
965 | g_return_if_fail (text != NULL)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "text != NULL"); return; } } while (0); |
966 | g_return_if_fail (ctk_text_iter_get_buffer (iter) == buffer)do { if ((ctk_text_iter_get_buffer (iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (iter) == buffer"); return; } } while (0); |
967 | |
968 | ctk_text_buffer_emit_insert (buffer, iter, text, len); |
969 | } |
970 | |
971 | /** |
972 | * ctk_text_buffer_insert_at_cursor: |
973 | * @buffer: a #CtkTextBuffer |
974 | * @text: text in UTF-8 format |
975 | * @len: length of text, in bytes |
976 | * |
977 | * Simply calls ctk_text_buffer_insert(), using the current |
978 | * cursor position as the insertion point. |
979 | **/ |
980 | void |
981 | ctk_text_buffer_insert_at_cursor (CtkTextBuffer *buffer, |
982 | const gchar *text, |
983 | gint len) |
984 | { |
985 | CtkTextIter iter; |
986 | |
987 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
988 | g_return_if_fail (text != NULL)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "text != NULL"); return; } } while (0); |
989 | |
990 | ctk_text_buffer_get_iter_at_mark (buffer, &iter, |
991 | ctk_text_buffer_get_insert (buffer)); |
992 | |
993 | ctk_text_buffer_insert (buffer, &iter, text, len); |
994 | } |
995 | |
996 | /** |
997 | * ctk_text_buffer_insert_interactive: |
998 | * @buffer: a #CtkTextBuffer |
999 | * @iter: a position in @buffer |
1000 | * @text: some UTF-8 text |
1001 | * @len: length of text in bytes, or -1 |
1002 | * @default_editable: default editability of buffer |
1003 | * |
1004 | * Like ctk_text_buffer_insert(), but the insertion will not occur if |
1005 | * @iter is at a non-editable location in the buffer. Usually you |
1006 | * want to prevent insertions at ineditable locations if the insertion |
1007 | * results from a user action (is interactive). |
1008 | * |
1009 | * @default_editable indicates the editability of text that doesn't |
1010 | * have a tag affecting editability applied to it. Typically the |
1011 | * result of ctk_text_view_get_editable() is appropriate here. |
1012 | * |
1013 | * Returns: whether text was actually inserted |
1014 | **/ |
1015 | gboolean |
1016 | ctk_text_buffer_insert_interactive (CtkTextBuffer *buffer, |
1017 | CtkTextIter *iter, |
1018 | const gchar *text, |
1019 | gint len, |
1020 | gboolean default_editable) |
1021 | { |
1022 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return ((0)); } } while ( 0); |
1023 | g_return_val_if_fail (text != NULL, FALSE)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "text != NULL"); return ( (0)); } } while (0); |
1024 | g_return_val_if_fail (ctk_text_iter_get_buffer (iter) == buffer, FALSE)do { if ((ctk_text_iter_get_buffer (iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (iter) == buffer"); return ((0)) ; } } while (0); |
1025 | |
1026 | if (ctk_text_iter_can_insert (iter, default_editable)) |
1027 | { |
1028 | ctk_text_buffer_begin_user_action (buffer); |
1029 | ctk_text_buffer_emit_insert (buffer, iter, text, len); |
1030 | ctk_text_buffer_end_user_action (buffer); |
1031 | return TRUE(!(0)); |
1032 | } |
1033 | else |
1034 | return FALSE(0); |
1035 | } |
1036 | |
1037 | /** |
1038 | * ctk_text_buffer_insert_interactive_at_cursor: |
1039 | * @buffer: a #CtkTextBuffer |
1040 | * @text: text in UTF-8 format |
1041 | * @len: length of text in bytes, or -1 |
1042 | * @default_editable: default editability of buffer |
1043 | * |
1044 | * Calls ctk_text_buffer_insert_interactive() at the cursor |
1045 | * position. |
1046 | * |
1047 | * @default_editable indicates the editability of text that doesn't |
1048 | * have a tag affecting editability applied to it. Typically the |
1049 | * result of ctk_text_view_get_editable() is appropriate here. |
1050 | * |
1051 | * Returns: whether text was actually inserted |
1052 | **/ |
1053 | gboolean |
1054 | ctk_text_buffer_insert_interactive_at_cursor (CtkTextBuffer *buffer, |
1055 | const gchar *text, |
1056 | gint len, |
1057 | gboolean default_editable) |
1058 | { |
1059 | CtkTextIter iter; |
1060 | |
1061 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return ((0)); } } while ( 0); |
1062 | g_return_val_if_fail (text != NULL, FALSE)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "text != NULL"); return ( (0)); } } while (0); |
1063 | |
1064 | ctk_text_buffer_get_iter_at_mark (buffer, &iter, |
1065 | ctk_text_buffer_get_insert (buffer)); |
1066 | |
1067 | return ctk_text_buffer_insert_interactive (buffer, &iter, text, len, |
1068 | default_editable); |
1069 | } |
1070 | |
1071 | static gboolean |
1072 | possibly_not_text (gunichar ch, |
1073 | gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__))) |
1074 | { |
1075 | return ch == CTK_TEXT_UNKNOWN_CHAR0xFFFC; |
1076 | } |
1077 | |
1078 | static void |
1079 | insert_text_range (CtkTextBuffer *buffer, |
1080 | CtkTextIter *iter, |
1081 | const CtkTextIter *orig_start, |
1082 | const CtkTextIter *orig_end, |
1083 | gboolean interactive G_GNUC_UNUSED__attribute__ ((__unused__))) |
1084 | { |
1085 | gchar *text; |
1086 | |
1087 | text = ctk_text_iter_get_text (orig_start, orig_end); |
1088 | |
1089 | ctk_text_buffer_emit_insert (buffer, iter, text, -1); |
1090 | |
1091 | g_free (text); |
1092 | } |
1093 | |
1094 | typedef struct _Range Range; |
1095 | struct _Range |
1096 | { |
1097 | CtkTextBuffer *buffer; |
1098 | CtkTextMark *start_mark; |
1099 | CtkTextMark *end_mark; |
1100 | CtkTextMark *whole_end_mark; |
1101 | CtkTextIter *range_start; |
1102 | CtkTextIter *range_end; |
1103 | CtkTextIter *whole_end; |
1104 | }; |
1105 | |
1106 | static Range* |
1107 | save_range (CtkTextIter *range_start, |
1108 | CtkTextIter *range_end, |
1109 | CtkTextIter *whole_end) |
1110 | { |
1111 | Range *r; |
1112 | |
1113 | r = g_slice_new (Range)((Range*) g_slice_alloc (sizeof (Range))); |
1114 | |
1115 | r->buffer = ctk_text_iter_get_buffer (range_start); |
1116 | g_object_ref (r->buffer)((__typeof__ (r->buffer)) (g_object_ref) (r->buffer)); |
1117 | |
1118 | r->start_mark = |
1119 | ctk_text_buffer_create_mark (ctk_text_iter_get_buffer (range_start), |
1120 | NULL((void*)0), |
1121 | range_start, |
1122 | FALSE(0)); |
1123 | r->end_mark = |
1124 | ctk_text_buffer_create_mark (ctk_text_iter_get_buffer (range_start), |
1125 | NULL((void*)0), |
1126 | range_end, |
1127 | TRUE(!(0))); |
1128 | |
1129 | r->whole_end_mark = |
1130 | ctk_text_buffer_create_mark (ctk_text_iter_get_buffer (range_start), |
1131 | NULL((void*)0), |
1132 | whole_end, |
1133 | TRUE(!(0))); |
1134 | |
1135 | r->range_start = range_start; |
1136 | r->range_end = range_end; |
1137 | r->whole_end = whole_end; |
1138 | |
1139 | return r; |
1140 | } |
1141 | |
1142 | static void |
1143 | restore_range (Range *r) |
1144 | { |
1145 | ctk_text_buffer_get_iter_at_mark (r->buffer, |
1146 | r->range_start, |
1147 | r->start_mark); |
1148 | |
1149 | ctk_text_buffer_get_iter_at_mark (r->buffer, |
1150 | r->range_end, |
1151 | r->end_mark); |
1152 | |
1153 | ctk_text_buffer_get_iter_at_mark (r->buffer, |
1154 | r->whole_end, |
1155 | r->whole_end_mark); |
1156 | |
1157 | ctk_text_buffer_delete_mark (r->buffer, r->start_mark); |
1158 | ctk_text_buffer_delete_mark (r->buffer, r->end_mark); |
1159 | ctk_text_buffer_delete_mark (r->buffer, r->whole_end_mark); |
1160 | |
1161 | /* Due to the gravities on the marks, the ordering could have |
1162 | * gotten mangled; we switch to an empty range in that |
1163 | * case |
1164 | */ |
1165 | |
1166 | if (ctk_text_iter_compare (r->range_start, r->range_end) > 0) |
1167 | *r->range_start = *r->range_end; |
1168 | |
1169 | if (ctk_text_iter_compare (r->range_end, r->whole_end) > 0) |
1170 | *r->range_end = *r->whole_end; |
1171 | |
1172 | g_object_unref (r->buffer); |
1173 | g_slice_free (Range, r)do { if (1) g_slice_free1 (sizeof (Range), (r)); else (void) ( (Range*) 0 == (r)); } while (0); |
1174 | } |
1175 | |
1176 | static void |
1177 | insert_range_untagged (CtkTextBuffer *buffer, |
1178 | CtkTextIter *iter, |
1179 | const CtkTextIter *orig_start, |
1180 | const CtkTextIter *orig_end, |
1181 | gboolean interactive) |
1182 | { |
1183 | CtkTextIter range_start; |
1184 | CtkTextIter range_end; |
1185 | CtkTextIter start, end; |
1186 | Range *r; |
1187 | |
1188 | if (ctk_text_iter_equal (orig_start, orig_end)) |
1189 | return; |
1190 | |
1191 | start = *orig_start; |
1192 | end = *orig_end; |
1193 | |
1194 | range_start = start; |
1195 | range_end = start; |
1196 | |
1197 | while (TRUE(!(0))) |
1198 | { |
1199 | if (ctk_text_iter_equal (&range_start, &range_end)) |
1200 | { |
1201 | /* Figure out how to move forward */ |
1202 | |
1203 | g_assert (ctk_text_iter_compare (&range_end, &end) <= 0)do { if (ctk_text_iter_compare (&range_end, &end) <= 0) ; else g_assertion_message_expr ("Ctk", "ctktextbuffer.c" , 1203, ((const char*) (__func__)), "ctk_text_iter_compare (&range_end, &end) <= 0" ); } while (0); |
1204 | |
1205 | if (ctk_text_iter_equal (&range_end, &end)) |
1206 | { |
1207 | /* nothing left to do */ |
1208 | break; |
1209 | } |
1210 | else if (ctk_text_iter_get_char (&range_end) == CTK_TEXT_UNKNOWN_CHAR0xFFFC) |
1211 | { |
1212 | GdkPixbuf *pixbuf = NULL((void*)0); |
1213 | CtkTextChildAnchor *anchor = NULL((void*)0); |
1214 | pixbuf = ctk_text_iter_get_pixbuf (&range_end); |
1215 | anchor = ctk_text_iter_get_child_anchor (&range_end); |
1216 | |
1217 | if (pixbuf) |
1218 | { |
1219 | r = save_range (&range_start, |
1220 | &range_end, |
1221 | &end); |
1222 | |
1223 | ctk_text_buffer_insert_pixbuf (buffer, |
1224 | iter, |
1225 | pixbuf); |
1226 | |
1227 | restore_range (r); |
1228 | r = NULL((void*)0); |
1229 | |
1230 | ctk_text_iter_forward_char (&range_end); |
1231 | |
1232 | range_start = range_end; |
1233 | } |
1234 | else if (anchor) |
1235 | { |
1236 | /* Just skip anchors */ |
1237 | |
1238 | ctk_text_iter_forward_char (&range_end); |
1239 | range_start = range_end; |
1240 | } |
1241 | else |
1242 | { |
1243 | /* The CTK_TEXT_UNKNOWN_CHAR was in a text segment, so |
1244 | * keep going. |
1245 | */ |
1246 | ctk_text_iter_forward_find_char (&range_end, |
1247 | possibly_not_text, NULL((void*)0), |
1248 | &end); |
1249 | |
1250 | g_assert (ctk_text_iter_compare (&range_end, &end) <= 0)do { if (ctk_text_iter_compare (&range_end, &end) <= 0) ; else g_assertion_message_expr ("Ctk", "ctktextbuffer.c" , 1250, ((const char*) (__func__)), "ctk_text_iter_compare (&range_end, &end) <= 0" ); } while (0); |
1251 | } |
1252 | } |
1253 | else |
1254 | { |
1255 | /* Text segment starts here, so forward search to |
1256 | * find its possible endpoint |
1257 | */ |
1258 | ctk_text_iter_forward_find_char (&range_end, |
1259 | possibly_not_text, NULL((void*)0), |
1260 | &end); |
1261 | |
1262 | g_assert (ctk_text_iter_compare (&range_end, &end) <= 0)do { if (ctk_text_iter_compare (&range_end, &end) <= 0) ; else g_assertion_message_expr ("Ctk", "ctktextbuffer.c" , 1262, ((const char*) (__func__)), "ctk_text_iter_compare (&range_end, &end) <= 0" ); } while (0); |
1263 | } |
1264 | } |
1265 | else |
1266 | { |
1267 | r = save_range (&range_start, |
1268 | &range_end, |
1269 | &end); |
1270 | |
1271 | insert_text_range (buffer, |
1272 | iter, |
1273 | &range_start, |
1274 | &range_end, |
1275 | interactive); |
1276 | |
1277 | restore_range (r); |
1278 | r = NULL((void*)0); |
1279 | |
1280 | range_start = range_end; |
1281 | } |
1282 | } |
1283 | } |
1284 | |
1285 | static void |
1286 | insert_range_not_inside_self (CtkTextBuffer *buffer, |
1287 | CtkTextIter *iter, |
1288 | const CtkTextIter *orig_start, |
1289 | const CtkTextIter *orig_end, |
1290 | gboolean interactive) |
1291 | { |
1292 | /* Find each range of uniformly-tagged text, insert it, |
1293 | * then apply the tags. |
1294 | */ |
1295 | CtkTextIter start = *orig_start; |
1296 | CtkTextIter end = *orig_end; |
1297 | CtkTextIter range_start; |
1298 | CtkTextIter range_end; |
1299 | |
1300 | if (ctk_text_iter_equal (orig_start, orig_end)) |
1301 | return; |
1302 | |
1303 | ctk_text_iter_order (&start, &end); |
1304 | |
1305 | range_start = start; |
1306 | range_end = start; |
1307 | |
1308 | while (TRUE(!(0))) |
1309 | { |
1310 | gint start_offset; |
1311 | CtkTextIter start_iter; |
1312 | GSList *tags; |
1313 | GSList *tmp_list; |
1314 | Range *r; |
1315 | |
1316 | if (ctk_text_iter_equal (&range_start, &end)) |
1317 | break; /* All done */ |
1318 | |
1319 | g_assert (ctk_text_iter_compare (&range_start, &end) < 0)do { if (ctk_text_iter_compare (&range_start, &end) < 0) ; else g_assertion_message_expr ("Ctk", "ctktextbuffer.c" , 1319, ((const char*) (__func__)), "ctk_text_iter_compare (&range_start, &end) < 0" ); } while (0); |
1320 | |
1321 | ctk_text_iter_forward_to_tag_toggle (&range_end, NULL((void*)0)); |
1322 | |
1323 | g_assert (!ctk_text_iter_equal (&range_start, &range_end))do { if (!ctk_text_iter_equal (&range_start, &range_end )) ; else g_assertion_message_expr ("Ctk", "ctktextbuffer.c", 1323, ((const char*) (__func__)), "!ctk_text_iter_equal (&range_start, &range_end)" ); } while (0); |
1324 | |
1325 | /* Clamp to the end iterator */ |
1326 | if (ctk_text_iter_compare (&range_end, &end) > 0) |
1327 | range_end = end; |
1328 | |
1329 | /* We have a range with unique tags; insert it, and |
1330 | * apply all tags. |
1331 | */ |
1332 | start_offset = ctk_text_iter_get_offset (iter); |
1333 | |
1334 | r = save_range (&range_start, &range_end, &end); |
1335 | |
1336 | insert_range_untagged (buffer, iter, &range_start, &range_end, interactive); |
1337 | |
1338 | restore_range (r); |
1339 | r = NULL((void*)0); |
1340 | |
1341 | ctk_text_buffer_get_iter_at_offset (buffer, &start_iter, start_offset); |
1342 | |
1343 | tags = ctk_text_iter_get_tags (&range_start); |
1344 | tmp_list = tags; |
1345 | while (tmp_list != NULL((void*)0)) |
1346 | { |
1347 | ctk_text_buffer_apply_tag (buffer, |
1348 | tmp_list->data, |
1349 | &start_iter, |
1350 | iter); |
1351 | |
1352 | tmp_list = tmp_list->next; |
1353 | } |
1354 | g_slist_free (tags); |
1355 | |
1356 | range_start = range_end; |
1357 | } |
1358 | } |
1359 | |
1360 | static void |
1361 | ctk_text_buffer_real_insert_range (CtkTextBuffer *buffer, |
1362 | CtkTextIter *iter, |
1363 | const CtkTextIter *orig_start, |
1364 | const CtkTextIter *orig_end, |
1365 | gboolean interactive) |
1366 | { |
1367 | CtkTextBuffer *src_buffer; |
1368 | |
1369 | /* Find each range of uniformly-tagged text, insert it, |
1370 | * then apply the tags. |
1371 | */ |
1372 | if (ctk_text_iter_equal (orig_start, orig_end)) |
1373 | return; |
1374 | |
1375 | if (interactive) |
1376 | ctk_text_buffer_begin_user_action (buffer); |
1377 | |
1378 | src_buffer = ctk_text_iter_get_buffer (orig_start); |
1379 | |
1380 | if (ctk_text_iter_get_buffer (iter) != src_buffer || |
1381 | !ctk_text_iter_in_range (iter, orig_start, orig_end)) |
1382 | { |
1383 | insert_range_not_inside_self (buffer, iter, orig_start, orig_end, interactive); |
1384 | } |
1385 | else |
1386 | { |
1387 | /* If you insert a range into itself, it could loop infinitely |
1388 | * because the region being copied keeps growing as we insert. So |
1389 | * we have to separately copy the range before and after |
1390 | * the insertion point. |
1391 | */ |
1392 | CtkTextIter start = *orig_start; |
1393 | CtkTextIter end = *orig_end; |
1394 | CtkTextIter range_start; |
1395 | CtkTextIter range_end; |
1396 | Range *first_half; |
1397 | Range *second_half; |
1398 | |
1399 | ctk_text_iter_order (&start, &end); |
1400 | |
1401 | range_start = start; |
1402 | range_end = *iter; |
1403 | first_half = save_range (&range_start, &range_end, &end); |
1404 | |
1405 | range_start = *iter; |
1406 | range_end = end; |
1407 | second_half = save_range (&range_start, &range_end, &end); |
1408 | |
1409 | restore_range (first_half); |
1410 | insert_range_not_inside_self (buffer, iter, &range_start, &range_end, interactive); |
1411 | |
1412 | restore_range (second_half); |
1413 | insert_range_not_inside_self (buffer, iter, &range_start, &range_end, interactive); |
1414 | } |
1415 | |
1416 | if (interactive) |
1417 | ctk_text_buffer_end_user_action (buffer); |
1418 | } |
1419 | |
1420 | /** |
1421 | * ctk_text_buffer_insert_range: |
1422 | * @buffer: a #CtkTextBuffer |
1423 | * @iter: a position in @buffer |
1424 | * @start: a position in a #CtkTextBuffer |
1425 | * @end: another position in the same buffer as @start |
1426 | * |
1427 | * Copies text, tags, and pixbufs between @start and @end (the order |
1428 | * of @start and @end doesn’t matter) and inserts the copy at @iter. |
1429 | * Used instead of simply getting/inserting text because it preserves |
1430 | * images and tags. If @start and @end are in a different buffer from |
1431 | * @buffer, the two buffers must share the same tag table. |
1432 | * |
1433 | * Implemented via emissions of the insert_text and apply_tag signals, |
1434 | * so expect those. |
1435 | **/ |
1436 | void |
1437 | ctk_text_buffer_insert_range (CtkTextBuffer *buffer, |
1438 | CtkTextIter *iter, |
1439 | const CtkTextIter *start, |
1440 | const CtkTextIter *end) |
1441 | { |
1442 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
1443 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
1444 | g_return_if_fail (start != NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ; } } while (0); |
1445 | g_return_if_fail (end != NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return; } } while (0); |
1446 | g_return_if_fail (ctk_text_iter_get_buffer (start) ==do { if ((ctk_text_iter_get_buffer (start) == ctk_text_iter_get_buffer (end))) { } else { g_return_if_fail_warning ("Ctk", ((const char *) (__func__)), "ctk_text_iter_get_buffer (start) == ctk_text_iter_get_buffer (end)" ); return; } } while (0) |
1447 | ctk_text_iter_get_buffer (end))do { if ((ctk_text_iter_get_buffer (start) == ctk_text_iter_get_buffer (end))) { } else { g_return_if_fail_warning ("Ctk", ((const char *) (__func__)), "ctk_text_iter_get_buffer (start) == ctk_text_iter_get_buffer (end)" ); return; } } while (0); |
1448 | g_return_if_fail (ctk_text_iter_get_buffer (start)->priv->tag_table ==do { if ((ctk_text_iter_get_buffer (start)->priv->tag_table == buffer->priv->tag_table)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "ctk_text_iter_get_buffer (start)->priv->tag_table == buffer->priv->tag_table" ); return; } } while (0) |
1449 | buffer->priv->tag_table)do { if ((ctk_text_iter_get_buffer (start)->priv->tag_table == buffer->priv->tag_table)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "ctk_text_iter_get_buffer (start)->priv->tag_table == buffer->priv->tag_table" ); return; } } while (0); |
1450 | g_return_if_fail (ctk_text_iter_get_buffer (iter) == buffer)do { if ((ctk_text_iter_get_buffer (iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (iter) == buffer"); return; } } while (0); |
1451 | |
1452 | ctk_text_buffer_real_insert_range (buffer, iter, start, end, FALSE(0)); |
1453 | } |
1454 | |
1455 | /** |
1456 | * ctk_text_buffer_insert_range_interactive: |
1457 | * @buffer: a #CtkTextBuffer |
1458 | * @iter: a position in @buffer |
1459 | * @start: a position in a #CtkTextBuffer |
1460 | * @end: another position in the same buffer as @start |
1461 | * @default_editable: default editability of the buffer |
1462 | * |
1463 | * Same as ctk_text_buffer_insert_range(), but does nothing if the |
1464 | * insertion point isn’t editable. The @default_editable parameter |
1465 | * indicates whether the text is editable at @iter if no tags |
1466 | * enclosing @iter affect editability. Typically the result of |
1467 | * ctk_text_view_get_editable() is appropriate here. |
1468 | * |
1469 | * Returns: whether an insertion was possible at @iter |
1470 | **/ |
1471 | gboolean |
1472 | ctk_text_buffer_insert_range_interactive (CtkTextBuffer *buffer, |
1473 | CtkTextIter *iter, |
1474 | const CtkTextIter *start, |
1475 | const CtkTextIter *end, |
1476 | gboolean default_editable) |
1477 | { |
1478 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return ((0)); } } while ( 0); |
1479 | g_return_val_if_fail (iter != NULL, FALSE)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return ( (0)); } } while (0); |
1480 | g_return_val_if_fail (start != NULL, FALSE)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ((0)); } } while (0); |
1481 | g_return_val_if_fail (end != NULL, FALSE)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return ( (0)); } } while (0); |
1482 | g_return_val_if_fail (ctk_text_iter_get_buffer (start) ==do { if ((ctk_text_iter_get_buffer (start) == ctk_text_iter_get_buffer (end))) { } else { g_return_if_fail_warning ("Ctk", ((const char *) (__func__)), "ctk_text_iter_get_buffer (start) == ctk_text_iter_get_buffer (end)" ); return ((0)); } } while (0) |
1483 | ctk_text_iter_get_buffer (end), FALSE)do { if ((ctk_text_iter_get_buffer (start) == ctk_text_iter_get_buffer (end))) { } else { g_return_if_fail_warning ("Ctk", ((const char *) (__func__)), "ctk_text_iter_get_buffer (start) == ctk_text_iter_get_buffer (end)" ); return ((0)); } } while (0); |
1484 | g_return_val_if_fail (ctk_text_iter_get_buffer (start)->priv->tag_table ==do { if ((ctk_text_iter_get_buffer (start)->priv->tag_table == buffer->priv->tag_table)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "ctk_text_iter_get_buffer (start)->priv->tag_table == buffer->priv->tag_table" ); return ((0)); } } while (0) |
1485 | buffer->priv->tag_table, FALSE)do { if ((ctk_text_iter_get_buffer (start)->priv->tag_table == buffer->priv->tag_table)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "ctk_text_iter_get_buffer (start)->priv->tag_table == buffer->priv->tag_table" ); return ((0)); } } while (0); |
1486 | |
1487 | if (ctk_text_iter_can_insert (iter, default_editable)) |
1488 | { |
1489 | ctk_text_buffer_real_insert_range (buffer, iter, start, end, TRUE(!(0))); |
1490 | return TRUE(!(0)); |
1491 | } |
1492 | else |
1493 | return FALSE(0); |
1494 | } |
1495 | |
1496 | /** |
1497 | * ctk_text_buffer_insert_with_tags: |
1498 | * @buffer: a #CtkTextBuffer |
1499 | * @iter: an iterator in @buffer |
1500 | * @text: UTF-8 text |
1501 | * @len: length of @text, or -1 |
1502 | * @first_tag: first tag to apply to @text |
1503 | * @...: %NULL-terminated list of tags to apply |
1504 | * |
1505 | * Inserts @text into @buffer at @iter, applying the list of tags to |
1506 | * the newly-inserted text. The last tag specified must be %NULL to |
1507 | * terminate the list. Equivalent to calling ctk_text_buffer_insert(), |
1508 | * then ctk_text_buffer_apply_tag() on the inserted text; |
1509 | * ctk_text_buffer_insert_with_tags() is just a convenience function. |
1510 | **/ |
1511 | void |
1512 | ctk_text_buffer_insert_with_tags (CtkTextBuffer *buffer, |
1513 | CtkTextIter *iter, |
1514 | const gchar *text, |
1515 | gint len, |
1516 | CtkTextTag *first_tag, |
1517 | ...) |
1518 | { |
1519 | gint start_offset; |
1520 | CtkTextIter start; |
1521 | va_list args; |
1522 | CtkTextTag *tag; |
1523 | |
1524 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
1525 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
1526 | g_return_if_fail (text != NULL)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "text != NULL"); return; } } while (0); |
1527 | g_return_if_fail (ctk_text_iter_get_buffer (iter) == buffer)do { if ((ctk_text_iter_get_buffer (iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (iter) == buffer"); return; } } while (0); |
1528 | |
1529 | start_offset = ctk_text_iter_get_offset (iter); |
1530 | |
1531 | ctk_text_buffer_insert (buffer, iter, text, len); |
1532 | |
1533 | if (first_tag == NULL((void*)0)) |
1534 | return; |
1535 | |
1536 | ctk_text_buffer_get_iter_at_offset (buffer, &start, start_offset); |
1537 | |
1538 | va_start (args, first_tag)__builtin_va_start(args, first_tag); |
1539 | tag = first_tag; |
1540 | while (tag) |
1541 | { |
1542 | ctk_text_buffer_apply_tag (buffer, tag, &start, iter); |
1543 | |
1544 | tag = va_arg (args, CtkTextTag*)__builtin_va_arg(args, CtkTextTag*); |
1545 | } |
1546 | |
1547 | va_end (args)__builtin_va_end(args); |
1548 | } |
1549 | |
1550 | /** |
1551 | * ctk_text_buffer_insert_with_tags_by_name: |
1552 | * @buffer: a #CtkTextBuffer |
1553 | * @iter: position in @buffer |
1554 | * @text: UTF-8 text |
1555 | * @len: length of @text, or -1 |
1556 | * @first_tag_name: name of a tag to apply to @text |
1557 | * @...: more tag names |
1558 | * |
1559 | * Same as ctk_text_buffer_insert_with_tags(), but allows you |
1560 | * to pass in tag names instead of tag objects. |
1561 | **/ |
1562 | void |
1563 | ctk_text_buffer_insert_with_tags_by_name (CtkTextBuffer *buffer, |
1564 | CtkTextIter *iter, |
1565 | const gchar *text, |
1566 | gint len, |
1567 | const gchar *first_tag_name, |
1568 | ...) |
1569 | { |
1570 | gint start_offset; |
1571 | CtkTextIter start; |
1572 | va_list args; |
1573 | const gchar *tag_name; |
1574 | |
1575 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
1576 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
1577 | g_return_if_fail (text != NULL)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "text != NULL"); return; } } while (0); |
1578 | g_return_if_fail (ctk_text_iter_get_buffer (iter) == buffer)do { if ((ctk_text_iter_get_buffer (iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (iter) == buffer"); return; } } while (0); |
1579 | |
1580 | start_offset = ctk_text_iter_get_offset (iter); |
1581 | |
1582 | ctk_text_buffer_insert (buffer, iter, text, len); |
1583 | |
1584 | if (first_tag_name == NULL((void*)0)) |
1585 | return; |
1586 | |
1587 | ctk_text_buffer_get_iter_at_offset (buffer, &start, start_offset); |
1588 | |
1589 | va_start (args, first_tag_name)__builtin_va_start(args, first_tag_name); |
1590 | tag_name = first_tag_name; |
1591 | while (tag_name) |
1592 | { |
1593 | CtkTextTag *tag; |
1594 | |
1595 | tag = ctk_text_tag_table_lookup (buffer->priv->tag_table, |
1596 | tag_name); |
1597 | |
1598 | if (tag == NULL((void*)0)) |
1599 | { |
1600 | g_warning ("%s: no tag with name '%s'!", G_STRLOC"ctktextbuffer.c" ":" "1600", tag_name); |
1601 | va_end (args)__builtin_va_end(args); |
1602 | return; |
1603 | } |
1604 | |
1605 | ctk_text_buffer_apply_tag (buffer, tag, &start, iter); |
1606 | |
1607 | tag_name = va_arg (args, const gchar*)__builtin_va_arg(args, const gchar*); |
1608 | } |
1609 | |
1610 | va_end (args)__builtin_va_end(args); |
1611 | } |
1612 | |
1613 | |
1614 | /* |
1615 | * Deletion |
1616 | */ |
1617 | |
1618 | static void |
1619 | ctk_text_buffer_real_delete_range (CtkTextBuffer *buffer, |
1620 | CtkTextIter *start, |
1621 | CtkTextIter *end) |
1622 | { |
1623 | gboolean has_selection; |
1624 | |
1625 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
1626 | g_return_if_fail (start != NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ; } } while (0); |
1627 | g_return_if_fail (end != NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return; } } while (0); |
1628 | |
1629 | _ctk_text_btree_delete (start, end); |
1630 | |
1631 | /* may have deleted the selection... */ |
1632 | update_selection_clipboards (buffer); |
1633 | |
1634 | has_selection = ctk_text_buffer_get_selection_bounds (buffer, NULL((void*)0), NULL((void*)0)); |
1635 | if (has_selection != buffer->priv->has_selection) |
1636 | { |
1637 | buffer->priv->has_selection = has_selection; |
1638 | g_object_notify_by_pspec (G_OBJECT (buffer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((buffer)), (((GType) ((20) << (2)))))))), text_buffer_props[PROP_HAS_SELECTION]); |
1639 | } |
1640 | |
1641 | g_signal_emit (buffer, signals[CHANGED], 0); |
1642 | g_object_notify_by_pspec (G_OBJECT (buffer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((buffer)), (((GType) ((20) << (2)))))))), text_buffer_props[PROP_CURSOR_POSITION]); |
1643 | } |
1644 | |
1645 | static void |
1646 | ctk_text_buffer_emit_delete (CtkTextBuffer *buffer, |
1647 | CtkTextIter *start, |
1648 | CtkTextIter *end) |
1649 | { |
1650 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
1651 | g_return_if_fail (start != NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ; } } while (0); |
1652 | g_return_if_fail (end != NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return; } } while (0); |
1653 | |
1654 | if (ctk_text_iter_equal (start, end)) |
1655 | return; |
1656 | |
1657 | ctk_text_iter_order (start, end); |
1658 | |
1659 | g_signal_emit (buffer, |
1660 | signals[DELETE_RANGE], |
1661 | 0, |
1662 | start, end); |
1663 | } |
1664 | |
1665 | /** |
1666 | * ctk_text_buffer_delete: |
1667 | * @buffer: a #CtkTextBuffer |
1668 | * @start: a position in @buffer |
1669 | * @end: another position in @buffer |
1670 | * |
1671 | * Deletes text between @start and @end. The order of @start and @end |
1672 | * is not actually relevant; ctk_text_buffer_delete() will reorder |
1673 | * them. This function actually emits the “delete-range” signal, and |
1674 | * the default handler of that signal deletes the text. Because the |
1675 | * buffer is modified, all outstanding iterators become invalid after |
1676 | * calling this function; however, the @start and @end will be |
1677 | * re-initialized to point to the location where text was deleted. |
1678 | **/ |
1679 | void |
1680 | ctk_text_buffer_delete (CtkTextBuffer *buffer, |
1681 | CtkTextIter *start, |
1682 | CtkTextIter *end) |
1683 | { |
1684 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
1685 | g_return_if_fail (start != NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ; } } while (0); |
1686 | g_return_if_fail (end != NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return; } } while (0); |
1687 | g_return_if_fail (ctk_text_iter_get_buffer (start) == buffer)do { if ((ctk_text_iter_get_buffer (start) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (start) == buffer"); return; } } while (0); |
1688 | g_return_if_fail (ctk_text_iter_get_buffer (end) == buffer)do { if ((ctk_text_iter_get_buffer (end) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (end) == buffer"); return; } } while (0); |
1689 | |
1690 | ctk_text_buffer_emit_delete (buffer, start, end); |
1691 | } |
1692 | |
1693 | /** |
1694 | * ctk_text_buffer_delete_interactive: |
1695 | * @buffer: a #CtkTextBuffer |
1696 | * @start_iter: start of range to delete |
1697 | * @end_iter: end of range |
1698 | * @default_editable: whether the buffer is editable by default |
1699 | * |
1700 | * Deletes all editable text in the given range. |
1701 | * Calls ctk_text_buffer_delete() for each editable sub-range of |
1702 | * [@start,@end). @start and @end are revalidated to point to |
1703 | * the location of the last deleted range, or left untouched if |
1704 | * no text was deleted. |
1705 | * |
1706 | * Returns: whether some text was actually deleted |
1707 | **/ |
1708 | gboolean |
1709 | ctk_text_buffer_delete_interactive (CtkTextBuffer *buffer, |
1710 | CtkTextIter *start_iter, |
1711 | CtkTextIter *end_iter, |
1712 | gboolean default_editable) |
1713 | { |
1714 | CtkTextMark *end_mark; |
1715 | CtkTextMark *start_mark; |
1716 | CtkTextIter iter; |
1717 | gboolean current_state; |
1718 | gboolean deleted_stuff = FALSE(0); |
1719 | |
1720 | /* Delete all editable text in the range start_iter, end_iter */ |
1721 | |
1722 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return ((0)); } } while ( 0); |
1723 | g_return_val_if_fail (start_iter != NULL, FALSE)do { if ((start_iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start_iter != NULL"); return ((0)); } } while (0); |
1724 | g_return_val_if_fail (end_iter != NULL, FALSE)do { if ((end_iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end_iter != NULL"); return ((0)); } } while (0); |
1725 | g_return_val_if_fail (ctk_text_iter_get_buffer (start_iter) == buffer, FALSE)do { if ((ctk_text_iter_get_buffer (start_iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "ctk_text_iter_get_buffer (start_iter) == buffer"); return ((0)); } } while (0); |
1726 | g_return_val_if_fail (ctk_text_iter_get_buffer (end_iter) == buffer, FALSE)do { if ((ctk_text_iter_get_buffer (end_iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "ctk_text_iter_get_buffer (end_iter) == buffer"); return ( (0)); } } while (0); |
1727 | |
1728 | |
1729 | ctk_text_buffer_begin_user_action (buffer); |
1730 | |
1731 | ctk_text_iter_order (start_iter, end_iter); |
1732 | |
1733 | start_mark = ctk_text_buffer_create_mark (buffer, NULL((void*)0), |
1734 | start_iter, TRUE(!(0))); |
1735 | end_mark = ctk_text_buffer_create_mark (buffer, NULL((void*)0), |
1736 | end_iter, FALSE(0)); |
1737 | |
1738 | ctk_text_buffer_get_iter_at_mark (buffer, &iter, start_mark); |
1739 | |
1740 | current_state = ctk_text_iter_editable (&iter, default_editable); |
1741 | |
1742 | while (TRUE(!(0))) |
1743 | { |
1744 | gboolean new_state; |
1745 | gboolean done = FALSE(0); |
1746 | CtkTextIter end; |
1747 | |
1748 | ctk_text_iter_forward_to_tag_toggle (&iter, NULL((void*)0)); |
1749 | |
1750 | ctk_text_buffer_get_iter_at_mark (buffer, &end, end_mark); |
1751 | |
1752 | if (ctk_text_iter_compare (&iter, &end) >= 0) |
1753 | { |
1754 | done = TRUE(!(0)); |
1755 | iter = end; /* clamp to the last boundary */ |
1756 | } |
1757 | |
1758 | new_state = ctk_text_iter_editable (&iter, default_editable); |
1759 | |
1760 | if (current_state == new_state) |
1761 | { |
1762 | if (done) |
1763 | { |
1764 | if (current_state) |
1765 | { |
1766 | /* We're ending an editable region. Delete said region. */ |
1767 | CtkTextIter start; |
1768 | |
1769 | ctk_text_buffer_get_iter_at_mark (buffer, &start, start_mark); |
1770 | |
1771 | ctk_text_buffer_emit_delete (buffer, &start, &iter); |
1772 | |
1773 | deleted_stuff = TRUE(!(0)); |
1774 | |
1775 | /* revalidate user's iterators. */ |
1776 | *start_iter = start; |
1777 | *end_iter = iter; |
1778 | } |
1779 | |
1780 | break; |
1781 | } |
1782 | else |
1783 | continue; |
1784 | } |
1785 | |
1786 | if (current_state && !new_state) |
1787 | { |
1788 | /* End of an editable region. Delete it. */ |
1789 | CtkTextIter start; |
1790 | |
1791 | ctk_text_buffer_get_iter_at_mark (buffer, &start, start_mark); |
1792 | |
1793 | ctk_text_buffer_emit_delete (buffer, &start, &iter); |
1794 | |
1795 | /* It's more robust to ask for the state again then to assume that |
1796 | * we're on the next not-editable segment. We don't know what the |
1797 | * ::delete-range handler did.... maybe it deleted the following |
1798 | * not-editable segment because it was associated with the editable |
1799 | * segment. |
1800 | */ |
1801 | current_state = ctk_text_iter_editable (&iter, default_editable); |
1802 | deleted_stuff = TRUE(!(0)); |
1803 | |
1804 | /* revalidate user's iterators. */ |
1805 | *start_iter = start; |
1806 | *end_iter = iter; |
1807 | } |
1808 | else |
1809 | { |
1810 | /* We are at the start of an editable region. We won't be deleting |
1811 | * the previous region. Move start mark to start of this region. |
1812 | */ |
1813 | |
1814 | g_assert (!current_state && new_state)do { if (!current_state && new_state) ; else g_assertion_message_expr ("Ctk", "ctktextbuffer.c", 1814, ((const char*) (__func__)), "!current_state && new_state"); } while (0); |
1815 | |
1816 | ctk_text_buffer_move_mark (buffer, start_mark, &iter); |
1817 | |
1818 | current_state = TRUE(!(0)); |
1819 | } |
1820 | |
1821 | if (done) |
1822 | break; |
1823 | } |
1824 | |
1825 | ctk_text_buffer_delete_mark (buffer, start_mark); |
1826 | ctk_text_buffer_delete_mark (buffer, end_mark); |
1827 | |
1828 | ctk_text_buffer_end_user_action (buffer); |
1829 | |
1830 | return deleted_stuff; |
1831 | } |
1832 | |
1833 | /* |
1834 | * Extracting textual buffer contents |
1835 | */ |
1836 | |
1837 | /** |
1838 | * ctk_text_buffer_get_text: |
1839 | * @buffer: a #CtkTextBuffer |
1840 | * @start: start of a range |
1841 | * @end: end of a range |
1842 | * @include_hidden_chars: whether to include invisible text |
1843 | * |
1844 | * Returns the text in the range [@start,@end). Excludes undisplayed |
1845 | * text (text marked with tags that set the invisibility attribute) if |
1846 | * @include_hidden_chars is %FALSE. Does not include characters |
1847 | * representing embedded images, so byte and character indexes into |
1848 | * the returned string do not correspond to byte |
1849 | * and character indexes into the buffer. Contrast with |
1850 | * ctk_text_buffer_get_slice(). |
1851 | * |
1852 | * Returns: (transfer full): an allocated UTF-8 string |
1853 | **/ |
1854 | gchar* |
1855 | ctk_text_buffer_get_text (CtkTextBuffer *buffer, |
1856 | const CtkTextIter *start, |
1857 | const CtkTextIter *end, |
1858 | gboolean include_hidden_chars) |
1859 | { |
1860 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
1861 | g_return_val_if_fail (start != NULL, NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return (((void*)0)); } } while (0); |
1862 | g_return_val_if_fail (end != NULL, NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return ( ((void*)0)); } } while (0); |
1863 | g_return_val_if_fail (ctk_text_iter_get_buffer (start) == buffer, NULL)do { if ((ctk_text_iter_get_buffer (start) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (start) == buffer"); return (((void *)0)); } } while (0); |
1864 | g_return_val_if_fail (ctk_text_iter_get_buffer (end) == buffer, NULL)do { if ((ctk_text_iter_get_buffer (end) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (end) == buffer"); return (((void *)0)); } } while (0); |
1865 | |
1866 | if (include_hidden_chars) |
1867 | return ctk_text_iter_get_text (start, end); |
1868 | else |
1869 | return ctk_text_iter_get_visible_text (start, end); |
1870 | } |
1871 | |
1872 | /** |
1873 | * ctk_text_buffer_get_slice: |
1874 | * @buffer: a #CtkTextBuffer |
1875 | * @start: start of a range |
1876 | * @end: end of a range |
1877 | * @include_hidden_chars: whether to include invisible text |
1878 | * |
1879 | * Returns the text in the range [@start,@end). Excludes undisplayed |
1880 | * text (text marked with tags that set the invisibility attribute) if |
1881 | * @include_hidden_chars is %FALSE. The returned string includes a |
1882 | * 0xFFFC character whenever the buffer contains |
1883 | * embedded images, so byte and character indexes into |
1884 | * the returned string do correspond to byte |
1885 | * and character indexes into the buffer. Contrast with |
1886 | * ctk_text_buffer_get_text(). Note that 0xFFFC can occur in normal |
1887 | * text as well, so it is not a reliable indicator that a pixbuf or |
1888 | * widget is in the buffer. |
1889 | * |
1890 | * Returns: (transfer full): an allocated UTF-8 string |
1891 | **/ |
1892 | gchar* |
1893 | ctk_text_buffer_get_slice (CtkTextBuffer *buffer, |
1894 | const CtkTextIter *start, |
1895 | const CtkTextIter *end, |
1896 | gboolean include_hidden_chars) |
1897 | { |
1898 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
1899 | g_return_val_if_fail (start != NULL, NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return (((void*)0)); } } while (0); |
1900 | g_return_val_if_fail (end != NULL, NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return ( ((void*)0)); } } while (0); |
1901 | g_return_val_if_fail (ctk_text_iter_get_buffer (start) == buffer, NULL)do { if ((ctk_text_iter_get_buffer (start) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (start) == buffer"); return (((void *)0)); } } while (0); |
1902 | g_return_val_if_fail (ctk_text_iter_get_buffer (end) == buffer, NULL)do { if ((ctk_text_iter_get_buffer (end) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (end) == buffer"); return (((void *)0)); } } while (0); |
1903 | |
1904 | if (include_hidden_chars) |
1905 | return ctk_text_iter_get_slice (start, end); |
1906 | else |
1907 | return ctk_text_iter_get_visible_slice (start, end); |
1908 | } |
1909 | |
1910 | /* |
1911 | * Pixbufs |
1912 | */ |
1913 | |
1914 | static void |
1915 | ctk_text_buffer_real_insert_pixbuf (CtkTextBuffer *buffer, |
1916 | CtkTextIter *iter, |
1917 | GdkPixbuf *pixbuf) |
1918 | { |
1919 | _ctk_text_btree_insert_pixbuf (iter, pixbuf); |
1920 | |
1921 | g_signal_emit (buffer, signals[CHANGED], 0); |
1922 | } |
1923 | |
1924 | /** |
1925 | * ctk_text_buffer_insert_pixbuf: |
1926 | * @buffer: a #CtkTextBuffer |
1927 | * @iter: location to insert the pixbuf |
1928 | * @pixbuf: a #GdkPixbuf |
1929 | * |
1930 | * Inserts an image into the text buffer at @iter. The image will be |
1931 | * counted as one character in character counts, and when obtaining |
1932 | * the buffer contents as a string, will be represented by the Unicode |
1933 | * “object replacement character” 0xFFFC. Note that the “slice” |
1934 | * variants for obtaining portions of the buffer as a string include |
1935 | * this character for pixbufs, but the “text” variants do |
1936 | * not. e.g. see ctk_text_buffer_get_slice() and |
1937 | * ctk_text_buffer_get_text(). |
1938 | **/ |
1939 | void |
1940 | ctk_text_buffer_insert_pixbuf (CtkTextBuffer *buffer, |
1941 | CtkTextIter *iter, |
1942 | GdkPixbuf *pixbuf) |
1943 | { |
1944 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
1945 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
1946 | g_return_if_fail (GDK_IS_PIXBUF (pixbuf))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((pixbuf)); GType __t = ((gdk_pixbuf_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "GDK_IS_PIXBUF (pixbuf)"); return; } } while (0); |
1947 | g_return_if_fail (ctk_text_iter_get_buffer (iter) == buffer)do { if ((ctk_text_iter_get_buffer (iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (iter) == buffer"); return; } } while (0); |
1948 | |
1949 | g_signal_emit (buffer, signals[INSERT_PIXBUF], 0, |
1950 | iter, pixbuf); |
1951 | } |
1952 | |
1953 | /* |
1954 | * Child anchor |
1955 | */ |
1956 | |
1957 | |
1958 | static void |
1959 | ctk_text_buffer_real_insert_anchor (CtkTextBuffer *buffer, |
1960 | CtkTextIter *iter, |
1961 | CtkTextChildAnchor *anchor) |
1962 | { |
1963 | _ctk_text_btree_insert_child_anchor (iter, anchor); |
1964 | |
1965 | g_signal_emit (buffer, signals[CHANGED], 0); |
1966 | } |
1967 | |
1968 | /** |
1969 | * ctk_text_buffer_insert_child_anchor: |
1970 | * @buffer: a #CtkTextBuffer |
1971 | * @iter: location to insert the anchor |
1972 | * @anchor: a #CtkTextChildAnchor |
1973 | * |
1974 | * Inserts a child widget anchor into the text buffer at @iter. The |
1975 | * anchor will be counted as one character in character counts, and |
1976 | * when obtaining the buffer contents as a string, will be represented |
1977 | * by the Unicode “object replacement character” 0xFFFC. Note that the |
1978 | * “slice” variants for obtaining portions of the buffer as a string |
1979 | * include this character for child anchors, but the “text” variants do |
1980 | * not. E.g. see ctk_text_buffer_get_slice() and |
1981 | * ctk_text_buffer_get_text(). Consider |
1982 | * ctk_text_buffer_create_child_anchor() as a more convenient |
1983 | * alternative to this function. The buffer will add a reference to |
1984 | * the anchor, so you can unref it after insertion. |
1985 | **/ |
1986 | void |
1987 | ctk_text_buffer_insert_child_anchor (CtkTextBuffer *buffer, |
1988 | CtkTextIter *iter, |
1989 | CtkTextChildAnchor *anchor) |
1990 | { |
1991 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
1992 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
1993 | g_return_if_fail (CTK_IS_TEXT_CHILD_ANCHOR (anchor))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((anchor)); GType __t = ((ctk_text_child_anchor_get_type ( ))); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "CTK_IS_TEXT_CHILD_ANCHOR (anchor)"); return ; } } while (0); |
1994 | g_return_if_fail (ctk_text_iter_get_buffer (iter) == buffer)do { if ((ctk_text_iter_get_buffer (iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (iter) == buffer"); return; } } while (0); |
1995 | |
1996 | g_signal_emit (buffer, signals[INSERT_CHILD_ANCHOR], 0, |
1997 | iter, anchor); |
1998 | } |
1999 | |
2000 | /** |
2001 | * ctk_text_buffer_create_child_anchor: |
2002 | * @buffer: a #CtkTextBuffer |
2003 | * @iter: location in the buffer |
2004 | * |
2005 | * This is a convenience function which simply creates a child anchor |
2006 | * with ctk_text_child_anchor_new() and inserts it into the buffer |
2007 | * with ctk_text_buffer_insert_child_anchor(). The new anchor is |
2008 | * owned by the buffer; no reference count is returned to |
2009 | * the caller of ctk_text_buffer_create_child_anchor(). |
2010 | * |
2011 | * Returns: (transfer none): the created child anchor |
2012 | **/ |
2013 | CtkTextChildAnchor* |
2014 | ctk_text_buffer_create_child_anchor (CtkTextBuffer *buffer, |
2015 | CtkTextIter *iter) |
2016 | { |
2017 | CtkTextChildAnchor *anchor; |
2018 | |
2019 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
2020 | g_return_val_if_fail (iter != NULL, NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return ( ((void*)0)); } } while (0); |
2021 | g_return_val_if_fail (ctk_text_iter_get_buffer (iter) == buffer, NULL)do { if ((ctk_text_iter_get_buffer (iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (iter) == buffer"); return (((void *)0)); } } while (0); |
2022 | |
2023 | anchor = ctk_text_child_anchor_new (); |
2024 | |
2025 | ctk_text_buffer_insert_child_anchor (buffer, iter, anchor); |
2026 | |
2027 | g_object_unref (anchor); |
2028 | |
2029 | return anchor; |
2030 | } |
2031 | |
2032 | /* |
2033 | * Mark manipulation |
2034 | */ |
2035 | |
2036 | static void |
2037 | ctk_text_buffer_mark_set (CtkTextBuffer *buffer, |
2038 | const CtkTextIter *location, |
2039 | CtkTextMark *mark) |
2040 | { |
2041 | /* IMO this should NOT work like insert_text and delete_range, |
2042 | * where the real action happens in the default handler. |
2043 | * |
2044 | * The reason is that the default handler would be _required_, |
2045 | * i.e. the whole widget would start breaking and segfaulting if the |
2046 | * default handler didn't get run. So you can't really override the |
2047 | * default handler or stop the emission; that is, this signal is |
2048 | * purely for notification, and not to allow users to modify the |
2049 | * default behavior. |
2050 | */ |
2051 | |
2052 | g_object_ref (mark)((__typeof__ (mark)) (g_object_ref) (mark)); |
2053 | |
2054 | g_signal_emit (buffer, |
2055 | signals[MARK_SET], |
2056 | 0, |
2057 | location, |
2058 | mark); |
2059 | |
2060 | g_object_unref (mark); |
2061 | } |
2062 | |
2063 | /** |
2064 | * ctk_text_buffer_set_mark: |
2065 | * @buffer: a #CtkTextBuffer |
2066 | * @mark_name: name of the mark |
2067 | * @iter: location for the mark |
2068 | * @left_gravity: if the mark is created by this function, gravity for |
2069 | * the new mark |
2070 | * @should_exist: if %TRUE, warn if the mark does not exist, and return |
2071 | * immediately |
2072 | * |
2073 | * Move the mark to the given position, if not @should_exist, |
2074 | * create the mark. |
2075 | * |
2076 | * Returns: mark |
2077 | **/ |
2078 | static CtkTextMark* |
2079 | ctk_text_buffer_set_mark (CtkTextBuffer *buffer, |
2080 | CtkTextMark *existing_mark, |
2081 | const gchar *mark_name, |
2082 | const CtkTextIter *iter, |
2083 | gboolean left_gravity, |
2084 | gboolean should_exist) |
2085 | { |
2086 | CtkTextIter location; |
2087 | CtkTextMark *mark; |
2088 | |
2089 | g_return_val_if_fail (ctk_text_iter_get_buffer (iter) == buffer, NULL)do { if ((ctk_text_iter_get_buffer (iter) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (iter) == buffer"); return (((void *)0)); } } while (0); |
2090 | |
2091 | mark = _ctk_text_btree_set_mark (get_btree (buffer), |
2092 | existing_mark, |
2093 | mark_name, |
2094 | left_gravity, |
2095 | iter, |
2096 | should_exist); |
2097 | |
2098 | _ctk_text_btree_get_iter_at_mark (get_btree (buffer), |
2099 | &location, |
2100 | mark); |
2101 | |
2102 | ctk_text_buffer_mark_set (buffer, &location, mark); |
2103 | |
2104 | return mark; |
2105 | } |
2106 | |
2107 | /** |
2108 | * ctk_text_buffer_create_mark: |
2109 | * @buffer: a #CtkTextBuffer |
2110 | * @mark_name: (allow-none): name for mark, or %NULL |
2111 | * @where: location to place mark |
2112 | * @left_gravity: whether the mark has left gravity |
2113 | * |
2114 | * Creates a mark at position @where. If @mark_name is %NULL, the mark |
2115 | * is anonymous; otherwise, the mark can be retrieved by name using |
2116 | * ctk_text_buffer_get_mark(). If a mark has left gravity, and text is |
2117 | * inserted at the mark’s current location, the mark will be moved to |
2118 | * the left of the newly-inserted text. If the mark has right gravity |
2119 | * (@left_gravity = %FALSE), the mark will end up on the right of |
2120 | * newly-inserted text. The standard left-to-right cursor is a mark |
2121 | * with right gravity (when you type, the cursor stays on the right |
2122 | * side of the text you’re typing). |
2123 | * |
2124 | * The caller of this function does not own a |
2125 | * reference to the returned #CtkTextMark, so you can ignore the |
2126 | * return value if you like. Marks are owned by the buffer and go |
2127 | * away when the buffer does. |
2128 | * |
2129 | * Emits the #CtkTextBuffer::mark-set signal as notification of the mark's |
2130 | * initial placement. |
2131 | * |
2132 | * Returns: (transfer none): the new #CtkTextMark object |
2133 | **/ |
2134 | CtkTextMark* |
2135 | ctk_text_buffer_create_mark (CtkTextBuffer *buffer, |
2136 | const gchar *mark_name, |
2137 | const CtkTextIter *where, |
2138 | gboolean left_gravity) |
2139 | { |
2140 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
2141 | |
2142 | return ctk_text_buffer_set_mark (buffer, NULL((void*)0), mark_name, where, |
2143 | left_gravity, FALSE(0)); |
2144 | } |
2145 | |
2146 | /** |
2147 | * ctk_text_buffer_add_mark: |
2148 | * @buffer: a #CtkTextBuffer |
2149 | * @mark: the mark to add |
2150 | * @where: location to place mark |
2151 | * |
2152 | * Adds the mark at position @where. The mark must not be added to |
2153 | * another buffer, and if its name is not %NULL then there must not |
2154 | * be another mark in the buffer with the same name. |
2155 | * |
2156 | * Emits the #CtkTextBuffer::mark-set signal as notification of the mark's |
2157 | * initial placement. |
2158 | * |
2159 | * Since: 2.12 |
2160 | **/ |
2161 | void |
2162 | ctk_text_buffer_add_mark (CtkTextBuffer *buffer, |
2163 | CtkTextMark *mark, |
2164 | const CtkTextIter *where) |
2165 | { |
2166 | const gchar *name; |
2167 | |
2168 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2169 | g_return_if_fail (CTK_IS_TEXT_MARK (mark))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((mark)); GType __t = ((ctk_text_mark_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_MARK (mark)"); return; } } while (0); |
2170 | g_return_if_fail (where != NULL)do { if ((where != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "where != NULL"); return ; } } while (0); |
2171 | g_return_if_fail (ctk_text_mark_get_buffer (mark) == NULL)do { if ((ctk_text_mark_get_buffer (mark) == ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "ctk_text_mark_get_buffer (mark) == NULL"); return; } } while (0); |
2172 | |
2173 | name = ctk_text_mark_get_name (mark); |
2174 | |
2175 | if (name != NULL((void*)0) && ctk_text_buffer_get_mark (buffer, name) != NULL((void*)0)) |
2176 | { |
2177 | g_critical ("Mark %s already exists in the buffer", name); |
2178 | return; |
2179 | } |
2180 | |
2181 | ctk_text_buffer_set_mark (buffer, mark, NULL((void*)0), where, FALSE(0), FALSE(0)); |
2182 | } |
2183 | |
2184 | /** |
2185 | * ctk_text_buffer_move_mark: |
2186 | * @buffer: a #CtkTextBuffer |
2187 | * @mark: a #CtkTextMark |
2188 | * @where: new location for @mark in @buffer |
2189 | * |
2190 | * Moves @mark to the new location @where. Emits the #CtkTextBuffer::mark-set |
2191 | * signal as notification of the move. |
2192 | **/ |
2193 | void |
2194 | ctk_text_buffer_move_mark (CtkTextBuffer *buffer, |
2195 | CtkTextMark *mark, |
2196 | const CtkTextIter *where) |
2197 | { |
2198 | g_return_if_fail (CTK_IS_TEXT_MARK (mark))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((mark)); GType __t = ((ctk_text_mark_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_MARK (mark)"); return; } } while (0); |
2199 | g_return_if_fail (!ctk_text_mark_get_deleted (mark))do { if ((!ctk_text_mark_get_deleted (mark))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "!ctk_text_mark_get_deleted (mark)" ); return; } } while (0); |
2200 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2201 | |
2202 | ctk_text_buffer_set_mark (buffer, mark, NULL((void*)0), where, FALSE(0), TRUE(!(0))); |
2203 | } |
2204 | |
2205 | /** |
2206 | * ctk_text_buffer_get_iter_at_mark: |
2207 | * @buffer: a #CtkTextBuffer |
2208 | * @iter: (out): iterator to initialize |
2209 | * @mark: a #CtkTextMark in @buffer |
2210 | * |
2211 | * Initializes @iter with the current position of @mark. |
2212 | **/ |
2213 | void |
2214 | ctk_text_buffer_get_iter_at_mark (CtkTextBuffer *buffer, |
2215 | CtkTextIter *iter, |
2216 | CtkTextMark *mark) |
2217 | { |
2218 | g_return_if_fail (CTK_IS_TEXT_MARK (mark))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((mark)); GType __t = ((ctk_text_mark_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_MARK (mark)"); return; } } while (0); |
2219 | g_return_if_fail (!ctk_text_mark_get_deleted (mark))do { if ((!ctk_text_mark_get_deleted (mark))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "!ctk_text_mark_get_deleted (mark)" ); return; } } while (0); |
2220 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2221 | |
2222 | _ctk_text_btree_get_iter_at_mark (get_btree (buffer), |
2223 | iter, |
2224 | mark); |
2225 | } |
2226 | |
2227 | /** |
2228 | * ctk_text_buffer_delete_mark: |
2229 | * @buffer: a #CtkTextBuffer |
2230 | * @mark: a #CtkTextMark in @buffer |
2231 | * |
2232 | * Deletes @mark, so that it’s no longer located anywhere in the |
2233 | * buffer. Removes the reference the buffer holds to the mark, so if |
2234 | * you haven’t called g_object_ref() on the mark, it will be freed. Even |
2235 | * if the mark isn’t freed, most operations on @mark become |
2236 | * invalid, until it gets added to a buffer again with |
2237 | * ctk_text_buffer_add_mark(). Use ctk_text_mark_get_deleted() to |
2238 | * find out if a mark has been removed from its buffer. |
2239 | * The #CtkTextBuffer::mark-deleted signal will be emitted as notification after |
2240 | * the mark is deleted. |
2241 | **/ |
2242 | void |
2243 | ctk_text_buffer_delete_mark (CtkTextBuffer *buffer, |
2244 | CtkTextMark *mark) |
2245 | { |
2246 | g_return_if_fail (CTK_IS_TEXT_MARK (mark))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((mark)); GType __t = ((ctk_text_mark_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_MARK (mark)"); return; } } while (0); |
2247 | g_return_if_fail (!ctk_text_mark_get_deleted (mark))do { if ((!ctk_text_mark_get_deleted (mark))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "!ctk_text_mark_get_deleted (mark)" ); return; } } while (0); |
2248 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2249 | |
2250 | g_object_ref (mark)((__typeof__ (mark)) (g_object_ref) (mark)); |
2251 | |
2252 | _ctk_text_btree_remove_mark (get_btree (buffer), mark); |
2253 | |
2254 | /* See rationale above for MARK_SET on why we emit this after |
2255 | * removing the mark, rather than removing the mark in a default |
2256 | * handler. |
2257 | */ |
2258 | g_signal_emit (buffer, signals[MARK_DELETED], |
2259 | 0, |
2260 | mark); |
2261 | |
2262 | g_object_unref (mark); |
2263 | } |
2264 | |
2265 | /** |
2266 | * ctk_text_buffer_get_mark: |
2267 | * @buffer: a #CtkTextBuffer |
2268 | * @name: a mark name |
2269 | * |
2270 | * Returns the mark named @name in buffer @buffer, or %NULL if no such |
2271 | * mark exists in the buffer. |
2272 | * |
2273 | * Returns: (nullable) (transfer none): a #CtkTextMark, or %NULL |
2274 | **/ |
2275 | CtkTextMark* |
2276 | ctk_text_buffer_get_mark (CtkTextBuffer *buffer, |
2277 | const gchar *name) |
2278 | { |
2279 | CtkTextMark *mark; |
2280 | |
2281 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
2282 | g_return_val_if_fail (name != NULL, NULL)do { if ((name != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "name != NULL"); return ( ((void*)0)); } } while (0); |
2283 | |
2284 | mark = _ctk_text_btree_get_mark_by_name (get_btree (buffer), name); |
2285 | |
2286 | return mark; |
2287 | } |
2288 | |
2289 | /** |
2290 | * ctk_text_buffer_move_mark_by_name: |
2291 | * @buffer: a #CtkTextBuffer |
2292 | * @name: name of a mark |
2293 | * @where: new location for mark |
2294 | * |
2295 | * Moves the mark named @name (which must exist) to location @where. |
2296 | * See ctk_text_buffer_move_mark() for details. |
2297 | **/ |
2298 | void |
2299 | ctk_text_buffer_move_mark_by_name (CtkTextBuffer *buffer, |
2300 | const gchar *name, |
2301 | const CtkTextIter *where) |
2302 | { |
2303 | CtkTextMark *mark; |
2304 | |
2305 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2306 | g_return_if_fail (name != NULL)do { if ((name != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "name != NULL"); return; } } while (0); |
2307 | |
2308 | mark = _ctk_text_btree_get_mark_by_name (get_btree (buffer), name); |
2309 | |
2310 | if (mark == NULL((void*)0)) |
2311 | { |
2312 | g_warning ("%s: no mark named '%s'", G_STRLOC"ctktextbuffer.c" ":" "2312", name); |
2313 | return; |
2314 | } |
2315 | |
2316 | ctk_text_buffer_move_mark (buffer, mark, where); |
2317 | } |
2318 | |
2319 | /** |
2320 | * ctk_text_buffer_delete_mark_by_name: |
2321 | * @buffer: a #CtkTextBuffer |
2322 | * @name: name of a mark in @buffer |
2323 | * |
2324 | * Deletes the mark named @name; the mark must exist. See |
2325 | * ctk_text_buffer_delete_mark() for details. |
2326 | **/ |
2327 | void |
2328 | ctk_text_buffer_delete_mark_by_name (CtkTextBuffer *buffer, |
2329 | const gchar *name) |
2330 | { |
2331 | CtkTextMark *mark; |
2332 | |
2333 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2334 | g_return_if_fail (name != NULL)do { if ((name != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "name != NULL"); return; } } while (0); |
2335 | |
2336 | mark = _ctk_text_btree_get_mark_by_name (get_btree (buffer), name); |
2337 | |
2338 | if (mark == NULL((void*)0)) |
2339 | { |
2340 | g_warning ("%s: no mark named '%s'", G_STRLOC"ctktextbuffer.c" ":" "2340", name); |
2341 | return; |
2342 | } |
2343 | |
2344 | ctk_text_buffer_delete_mark (buffer, mark); |
2345 | } |
2346 | |
2347 | /** |
2348 | * ctk_text_buffer_get_insert: |
2349 | * @buffer: a #CtkTextBuffer |
2350 | * |
2351 | * Returns the mark that represents the cursor (insertion point). |
2352 | * Equivalent to calling ctk_text_buffer_get_mark() to get the mark |
2353 | * named “insert”, but very slightly more efficient, and involves less |
2354 | * typing. |
2355 | * |
2356 | * Returns: (transfer none): insertion point mark |
2357 | **/ |
2358 | CtkTextMark* |
2359 | ctk_text_buffer_get_insert (CtkTextBuffer *buffer) |
2360 | { |
2361 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
2362 | |
2363 | return _ctk_text_btree_get_insert (get_btree (buffer)); |
2364 | } |
2365 | |
2366 | /** |
2367 | * ctk_text_buffer_get_selection_bound: |
2368 | * @buffer: a #CtkTextBuffer |
2369 | * |
2370 | * Returns the mark that represents the selection bound. Equivalent |
2371 | * to calling ctk_text_buffer_get_mark() to get the mark named |
2372 | * “selection_bound”, but very slightly more efficient, and involves |
2373 | * less typing. |
2374 | * |
2375 | * The currently-selected text in @buffer is the region between the |
2376 | * “selection_bound” and “insert” marks. If “selection_bound” and |
2377 | * “insert” are in the same place, then there is no current selection. |
2378 | * ctk_text_buffer_get_selection_bounds() is another convenient function |
2379 | * for handling the selection, if you just want to know whether there’s a |
2380 | * selection and what its bounds are. |
2381 | * |
2382 | * Returns: (transfer none): selection bound mark |
2383 | **/ |
2384 | CtkTextMark* |
2385 | ctk_text_buffer_get_selection_bound (CtkTextBuffer *buffer) |
2386 | { |
2387 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
2388 | |
2389 | return _ctk_text_btree_get_selection_bound (get_btree (buffer)); |
2390 | } |
2391 | |
2392 | /** |
2393 | * ctk_text_buffer_get_iter_at_child_anchor: |
2394 | * @buffer: a #CtkTextBuffer |
2395 | * @iter: (out): an iterator to be initialized |
2396 | * @anchor: a child anchor that appears in @buffer |
2397 | * |
2398 | * Obtains the location of @anchor within @buffer. |
2399 | **/ |
2400 | void |
2401 | ctk_text_buffer_get_iter_at_child_anchor (CtkTextBuffer *buffer, |
2402 | CtkTextIter *iter, |
2403 | CtkTextChildAnchor *anchor) |
2404 | { |
2405 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2406 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
2407 | g_return_if_fail (CTK_IS_TEXT_CHILD_ANCHOR (anchor))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((anchor)); GType __t = ((ctk_text_child_anchor_get_type ( ))); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "CTK_IS_TEXT_CHILD_ANCHOR (anchor)"); return ; } } while (0); |
2408 | g_return_if_fail (!ctk_text_child_anchor_get_deleted (anchor))do { if ((!ctk_text_child_anchor_get_deleted (anchor))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "!ctk_text_child_anchor_get_deleted (anchor)"); return; } } while (0); |
2409 | |
2410 | _ctk_text_btree_get_iter_at_child_anchor (get_btree (buffer), |
2411 | iter, |
2412 | anchor); |
2413 | } |
2414 | |
2415 | /** |
2416 | * ctk_text_buffer_place_cursor: |
2417 | * @buffer: a #CtkTextBuffer |
2418 | * @where: where to put the cursor |
2419 | * |
2420 | * This function moves the “insert” and “selection_bound” marks |
2421 | * simultaneously. If you move them to the same place in two steps |
2422 | * with ctk_text_buffer_move_mark(), you will temporarily select a |
2423 | * region in between their old and new locations, which can be pretty |
2424 | * inefficient since the temporarily-selected region will force stuff |
2425 | * to be recalculated. This function moves them as a unit, which can |
2426 | * be optimized. |
2427 | **/ |
2428 | void |
2429 | ctk_text_buffer_place_cursor (CtkTextBuffer *buffer, |
2430 | const CtkTextIter *where) |
2431 | { |
2432 | ctk_text_buffer_select_range (buffer, where, where); |
2433 | } |
2434 | |
2435 | /** |
2436 | * ctk_text_buffer_select_range: |
2437 | * @buffer: a #CtkTextBuffer |
2438 | * @ins: where to put the “insert” mark |
2439 | * @bound: where to put the “selection_bound” mark |
2440 | * |
2441 | * This function moves the “insert” and “selection_bound” marks |
2442 | * simultaneously. If you move them in two steps |
2443 | * with ctk_text_buffer_move_mark(), you will temporarily select a |
2444 | * region in between their old and new locations, which can be pretty |
2445 | * inefficient since the temporarily-selected region will force stuff |
2446 | * to be recalculated. This function moves them as a unit, which can |
2447 | * be optimized. |
2448 | * |
2449 | * Since: 2.4 |
2450 | **/ |
2451 | void |
2452 | ctk_text_buffer_select_range (CtkTextBuffer *buffer, |
2453 | const CtkTextIter *ins, |
2454 | const CtkTextIter *bound) |
2455 | { |
2456 | CtkTextIter real_ins; |
2457 | CtkTextIter real_bound; |
2458 | |
2459 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2460 | |
2461 | real_ins = *ins; |
2462 | real_bound = *bound; |
2463 | |
2464 | _ctk_text_btree_select_range (get_btree (buffer), &real_ins, &real_bound); |
2465 | ctk_text_buffer_mark_set (buffer, &real_ins, |
2466 | ctk_text_buffer_get_insert (buffer)); |
2467 | ctk_text_buffer_mark_set (buffer, &real_bound, |
2468 | ctk_text_buffer_get_selection_bound (buffer)); |
2469 | } |
2470 | |
2471 | /* |
2472 | * Tags |
2473 | */ |
2474 | |
2475 | /** |
2476 | * ctk_text_buffer_create_tag: |
2477 | * @buffer: a #CtkTextBuffer |
2478 | * @tag_name: (allow-none): name of the new tag, or %NULL |
2479 | * @first_property_name: (allow-none): name of first property to set, or %NULL |
2480 | * @...: %NULL-terminated list of property names and values |
2481 | * |
2482 | * Creates a tag and adds it to the tag table for @buffer. |
2483 | * Equivalent to calling ctk_text_tag_new() and then adding the |
2484 | * tag to the buffer’s tag table. The returned tag is owned by |
2485 | * the buffer’s tag table, so the ref count will be equal to one. |
2486 | * |
2487 | * If @tag_name is %NULL, the tag is anonymous. |
2488 | * |
2489 | * If @tag_name is non-%NULL, a tag called @tag_name must not already |
2490 | * exist in the tag table for this buffer. |
2491 | * |
2492 | * The @first_property_name argument and subsequent arguments are a list |
2493 | * of properties to set on the tag, as with g_object_set(). |
2494 | * |
2495 | * Returns: (transfer none): a new tag |
2496 | */ |
2497 | CtkTextTag* |
2498 | ctk_text_buffer_create_tag (CtkTextBuffer *buffer, |
2499 | const gchar *tag_name, |
2500 | const gchar *first_property_name, |
2501 | ...) |
2502 | { |
2503 | CtkTextTag *tag; |
2504 | va_list list; |
2505 | |
2506 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
2507 | |
2508 | tag = ctk_text_tag_new (tag_name); |
2509 | |
2510 | if (!ctk_text_tag_table_add (get_table (buffer), tag)) |
2511 | { |
2512 | g_object_unref (tag); |
2513 | return NULL((void*)0); |
2514 | } |
2515 | |
2516 | if (first_property_name) |
2517 | { |
2518 | va_start (list, first_property_name)__builtin_va_start(list, first_property_name); |
2519 | g_object_set_valist (G_OBJECT (tag)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((tag)), (((GType) ((20) << (2)))))))), first_property_name, list); |
2520 | va_end (list)__builtin_va_end(list); |
2521 | } |
2522 | |
2523 | g_object_unref (tag); |
2524 | |
2525 | return tag; |
2526 | } |
2527 | |
2528 | static void |
2529 | ctk_text_buffer_real_apply_tag (CtkTextBuffer *buffer, |
2530 | CtkTextTag *tag, |
2531 | const CtkTextIter *start, |
2532 | const CtkTextIter *end) |
2533 | { |
2534 | if (tag->priv->table != buffer->priv->tag_table) |
2535 | { |
2536 | g_warning ("Can only apply tags that are in the tag table for the buffer"); |
2537 | return; |
2538 | } |
2539 | |
2540 | _ctk_text_btree_tag (start, end, tag, TRUE(!(0))); |
2541 | } |
2542 | |
2543 | static void |
2544 | ctk_text_buffer_real_remove_tag (CtkTextBuffer *buffer, |
2545 | CtkTextTag *tag, |
2546 | const CtkTextIter *start, |
2547 | const CtkTextIter *end) |
2548 | { |
2549 | if (tag->priv->table != buffer->priv->tag_table) |
2550 | { |
2551 | g_warning ("Can only remove tags that are in the tag table for the buffer"); |
2552 | return; |
2553 | } |
2554 | |
2555 | _ctk_text_btree_tag (start, end, tag, FALSE(0)); |
2556 | } |
2557 | |
2558 | static void |
2559 | ctk_text_buffer_real_changed (CtkTextBuffer *buffer) |
2560 | { |
2561 | ctk_text_buffer_set_modified (buffer, TRUE(!(0))); |
2562 | |
2563 | g_object_notify_by_pspec (G_OBJECT (buffer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((buffer)), (((GType) ((20) << (2)))))))), text_buffer_props[PROP_TEXT]); |
2564 | } |
2565 | |
2566 | static void |
2567 | ctk_text_buffer_real_mark_set (CtkTextBuffer *buffer, |
2568 | const CtkTextIter *iter G_GNUC_UNUSED__attribute__ ((__unused__)), |
2569 | CtkTextMark *mark) |
2570 | { |
2571 | CtkTextMark *insert; |
2572 | |
2573 | insert = ctk_text_buffer_get_insert (buffer); |
2574 | |
2575 | if (mark == insert || mark == ctk_text_buffer_get_selection_bound (buffer)) |
2576 | { |
2577 | gboolean has_selection; |
2578 | |
2579 | update_selection_clipboards (buffer); |
2580 | |
2581 | has_selection = ctk_text_buffer_get_selection_bounds (buffer, |
2582 | NULL((void*)0), |
2583 | NULL((void*)0)); |
2584 | |
2585 | if (has_selection != buffer->priv->has_selection) |
2586 | { |
2587 | buffer->priv->has_selection = has_selection; |
2588 | g_object_notify_by_pspec (G_OBJECT (buffer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((buffer)), (((GType) ((20) << (2)))))))), text_buffer_props[PROP_HAS_SELECTION]); |
2589 | } |
2590 | } |
2591 | |
2592 | if (mark == insert) |
2593 | g_object_notify_by_pspec (G_OBJECT (buffer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((buffer)), (((GType) ((20) << (2)))))))), text_buffer_props[PROP_CURSOR_POSITION]); |
2594 | } |
2595 | |
2596 | static void |
2597 | ctk_text_buffer_emit_tag (CtkTextBuffer *buffer, |
2598 | CtkTextTag *tag, |
2599 | gboolean apply, |
2600 | const CtkTextIter *start, |
2601 | const CtkTextIter *end) |
2602 | { |
2603 | CtkTextIter start_tmp = *start; |
2604 | CtkTextIter end_tmp = *end; |
2605 | |
2606 | g_return_if_fail (tag != NULL)do { if ((tag != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "tag != NULL"); return; } } while (0); |
2607 | |
2608 | ctk_text_iter_order (&start_tmp, &end_tmp); |
2609 | |
2610 | if (apply) |
2611 | g_signal_emit (buffer, signals[APPLY_TAG], |
2612 | 0, |
2613 | tag, &start_tmp, &end_tmp); |
2614 | else |
2615 | g_signal_emit (buffer, signals[REMOVE_TAG], |
2616 | 0, |
2617 | tag, &start_tmp, &end_tmp); |
2618 | } |
2619 | |
2620 | /** |
2621 | * ctk_text_buffer_apply_tag: |
2622 | * @buffer: a #CtkTextBuffer |
2623 | * @tag: a #CtkTextTag |
2624 | * @start: one bound of range to be tagged |
2625 | * @end: other bound of range to be tagged |
2626 | * |
2627 | * Emits the “apply-tag” signal on @buffer. The default |
2628 | * handler for the signal applies @tag to the given range. |
2629 | * @start and @end do not have to be in order. |
2630 | **/ |
2631 | void |
2632 | ctk_text_buffer_apply_tag (CtkTextBuffer *buffer, |
2633 | CtkTextTag *tag, |
2634 | const CtkTextIter *start, |
2635 | const CtkTextIter *end) |
2636 | { |
2637 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2638 | g_return_if_fail (CTK_IS_TEXT_TAG (tag))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((tag)); GType __t = ((ctk_text_tag_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_TAG (tag)"); return; } } while (0); |
2639 | g_return_if_fail (start != NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ; } } while (0); |
2640 | g_return_if_fail (end != NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return; } } while (0); |
2641 | g_return_if_fail (ctk_text_iter_get_buffer (start) == buffer)do { if ((ctk_text_iter_get_buffer (start) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (start) == buffer"); return; } } while (0); |
2642 | g_return_if_fail (ctk_text_iter_get_buffer (end) == buffer)do { if ((ctk_text_iter_get_buffer (end) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (end) == buffer"); return; } } while (0); |
2643 | g_return_if_fail (tag->priv->table == buffer->priv->tag_table)do { if ((tag->priv->table == buffer->priv->tag_table )) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "tag->priv->table == buffer->priv->tag_table" ); return; } } while (0); |
2644 | |
2645 | ctk_text_buffer_emit_tag (buffer, tag, TRUE(!(0)), start, end); |
2646 | } |
2647 | |
2648 | /** |
2649 | * ctk_text_buffer_remove_tag: |
2650 | * @buffer: a #CtkTextBuffer |
2651 | * @tag: a #CtkTextTag |
2652 | * @start: one bound of range to be untagged |
2653 | * @end: other bound of range to be untagged |
2654 | * |
2655 | * Emits the “remove-tag” signal. The default handler for the signal |
2656 | * removes all occurrences of @tag from the given range. @start and |
2657 | * @end don’t have to be in order. |
2658 | **/ |
2659 | void |
2660 | ctk_text_buffer_remove_tag (CtkTextBuffer *buffer, |
2661 | CtkTextTag *tag, |
2662 | const CtkTextIter *start, |
2663 | const CtkTextIter *end) |
2664 | |
2665 | { |
2666 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2667 | g_return_if_fail (CTK_IS_TEXT_TAG (tag))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((tag)); GType __t = ((ctk_text_tag_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_TAG (tag)"); return; } } while (0); |
2668 | g_return_if_fail (start != NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ; } } while (0); |
2669 | g_return_if_fail (end != NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return; } } while (0); |
2670 | g_return_if_fail (ctk_text_iter_get_buffer (start) == buffer)do { if ((ctk_text_iter_get_buffer (start) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (start) == buffer"); return; } } while (0); |
2671 | g_return_if_fail (ctk_text_iter_get_buffer (end) == buffer)do { if ((ctk_text_iter_get_buffer (end) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (end) == buffer"); return; } } while (0); |
2672 | g_return_if_fail (tag->priv->table == buffer->priv->tag_table)do { if ((tag->priv->table == buffer->priv->tag_table )) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "tag->priv->table == buffer->priv->tag_table" ); return; } } while (0); |
2673 | |
2674 | ctk_text_buffer_emit_tag (buffer, tag, FALSE(0), start, end); |
2675 | } |
2676 | |
2677 | /** |
2678 | * ctk_text_buffer_apply_tag_by_name: |
2679 | * @buffer: a #CtkTextBuffer |
2680 | * @name: name of a named #CtkTextTag |
2681 | * @start: one bound of range to be tagged |
2682 | * @end: other bound of range to be tagged |
2683 | * |
2684 | * Calls ctk_text_tag_table_lookup() on the buffer’s tag table to |
2685 | * get a #CtkTextTag, then calls ctk_text_buffer_apply_tag(). |
2686 | **/ |
2687 | void |
2688 | ctk_text_buffer_apply_tag_by_name (CtkTextBuffer *buffer, |
2689 | const gchar *name, |
2690 | const CtkTextIter *start, |
2691 | const CtkTextIter *end) |
2692 | { |
2693 | CtkTextTag *tag; |
2694 | |
2695 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2696 | g_return_if_fail (name != NULL)do { if ((name != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "name != NULL"); return; } } while (0); |
2697 | g_return_if_fail (start != NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ; } } while (0); |
2698 | g_return_if_fail (end != NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return; } } while (0); |
2699 | g_return_if_fail (ctk_text_iter_get_buffer (start) == buffer)do { if ((ctk_text_iter_get_buffer (start) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (start) == buffer"); return; } } while (0); |
2700 | g_return_if_fail (ctk_text_iter_get_buffer (end) == buffer)do { if ((ctk_text_iter_get_buffer (end) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (end) == buffer"); return; } } while (0); |
2701 | |
2702 | tag = ctk_text_tag_table_lookup (get_table (buffer), |
2703 | name); |
2704 | |
2705 | if (tag == NULL((void*)0)) |
2706 | { |
2707 | g_warning ("Unknown tag '%s'", name); |
2708 | return; |
2709 | } |
2710 | |
2711 | ctk_text_buffer_emit_tag (buffer, tag, TRUE(!(0)), start, end); |
2712 | } |
2713 | |
2714 | /** |
2715 | * ctk_text_buffer_remove_tag_by_name: |
2716 | * @buffer: a #CtkTextBuffer |
2717 | * @name: name of a #CtkTextTag |
2718 | * @start: one bound of range to be untagged |
2719 | * @end: other bound of range to be untagged |
2720 | * |
2721 | * Calls ctk_text_tag_table_lookup() on the buffer’s tag table to |
2722 | * get a #CtkTextTag, then calls ctk_text_buffer_remove_tag(). |
2723 | **/ |
2724 | void |
2725 | ctk_text_buffer_remove_tag_by_name (CtkTextBuffer *buffer, |
2726 | const gchar *name, |
2727 | const CtkTextIter *start, |
2728 | const CtkTextIter *end) |
2729 | { |
2730 | CtkTextTag *tag; |
2731 | |
2732 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2733 | g_return_if_fail (name != NULL)do { if ((name != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "name != NULL"); return; } } while (0); |
2734 | g_return_if_fail (start != NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ; } } while (0); |
2735 | g_return_if_fail (end != NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return; } } while (0); |
2736 | g_return_if_fail (ctk_text_iter_get_buffer (start) == buffer)do { if ((ctk_text_iter_get_buffer (start) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (start) == buffer"); return; } } while (0); |
2737 | g_return_if_fail (ctk_text_iter_get_buffer (end) == buffer)do { if ((ctk_text_iter_get_buffer (end) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (end) == buffer"); return; } } while (0); |
2738 | |
2739 | tag = ctk_text_tag_table_lookup (get_table (buffer), |
2740 | name); |
2741 | |
2742 | if (tag == NULL((void*)0)) |
2743 | { |
2744 | g_warning ("Unknown tag '%s'", name); |
2745 | return; |
2746 | } |
2747 | |
2748 | ctk_text_buffer_emit_tag (buffer, tag, FALSE(0), start, end); |
2749 | } |
2750 | |
2751 | static gint |
2752 | pointer_cmp (gconstpointer a, |
2753 | gconstpointer b) |
2754 | { |
2755 | if (a < b) |
2756 | return -1; |
2757 | else if (a > b) |
2758 | return 1; |
2759 | else |
2760 | return 0; |
2761 | } |
2762 | |
2763 | /** |
2764 | * ctk_text_buffer_remove_all_tags: |
2765 | * @buffer: a #CtkTextBuffer |
2766 | * @start: one bound of range to be untagged |
2767 | * @end: other bound of range to be untagged |
2768 | * |
2769 | * Removes all tags in the range between @start and @end. Be careful |
2770 | * with this function; it could remove tags added in code unrelated to |
2771 | * the code you’re currently writing. That is, using this function is |
2772 | * probably a bad idea if you have two or more unrelated code sections |
2773 | * that add tags. |
2774 | **/ |
2775 | void |
2776 | ctk_text_buffer_remove_all_tags (CtkTextBuffer *buffer, |
2777 | const CtkTextIter *start, |
2778 | const CtkTextIter *end) |
2779 | { |
2780 | CtkTextIter first, second, tmp; |
2781 | GSList *tags; |
2782 | GSList *tmp_list; |
2783 | GSList *prev, *next; |
2784 | CtkTextTag *tag; |
2785 | |
2786 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2787 | g_return_if_fail (start != NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ; } } while (0); |
2788 | g_return_if_fail (end != NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return; } } while (0); |
2789 | g_return_if_fail (ctk_text_iter_get_buffer (start) == buffer)do { if ((ctk_text_iter_get_buffer (start) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (start) == buffer"); return; } } while (0); |
2790 | g_return_if_fail (ctk_text_iter_get_buffer (end) == buffer)do { if ((ctk_text_iter_get_buffer (end) == buffer)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "ctk_text_iter_get_buffer (end) == buffer"); return; } } while (0); |
2791 | |
2792 | first = *start; |
2793 | second = *end; |
2794 | |
2795 | ctk_text_iter_order (&first, &second); |
2796 | |
2797 | /* Get all tags turned on at the start */ |
2798 | tags = ctk_text_iter_get_tags (&first); |
2799 | |
2800 | /* Find any that are toggled on within the range */ |
2801 | tmp = first; |
2802 | while (ctk_text_iter_forward_to_tag_toggle (&tmp, NULL((void*)0))) |
2803 | { |
2804 | GSList *toggled; |
2805 | GSList *tmp_list2; |
2806 | |
2807 | if (ctk_text_iter_compare (&tmp, &second) >= 0) |
2808 | break; /* past the end of the range */ |
2809 | |
2810 | toggled = ctk_text_iter_get_toggled_tags (&tmp, TRUE(!(0))); |
2811 | |
2812 | /* We could end up with a really big-ass list here. |
2813 | * Fix it someday. |
2814 | */ |
2815 | tmp_list2 = toggled; |
2816 | while (tmp_list2 != NULL((void*)0)) |
2817 | { |
2818 | tags = g_slist_prepend (tags, tmp_list2->data); |
2819 | |
2820 | tmp_list2 = tmp_list2->next; |
2821 | } |
2822 | |
2823 | g_slist_free (toggled); |
2824 | } |
2825 | |
2826 | /* Sort the list */ |
2827 | tags = g_slist_sort (tags, pointer_cmp); |
2828 | |
2829 | /* Strip duplicates */ |
2830 | tag = NULL((void*)0); |
2831 | prev = NULL((void*)0); |
2832 | tmp_list = tags; |
2833 | while (tmp_list != NULL((void*)0)) |
2834 | { |
2835 | if (tag == tmp_list->data) |
2836 | { |
2837 | /* duplicate */ |
2838 | next = tmp_list->next; |
2839 | if (prev) |
2840 | prev->next = next; |
2841 | |
2842 | tmp_list->next = NULL((void*)0); |
2843 | |
2844 | g_slist_free (tmp_list); |
2845 | |
2846 | tmp_list = next; |
2847 | /* prev is unchanged */ |
2848 | } |
2849 | else |
2850 | { |
2851 | /* not a duplicate */ |
2852 | tag = CTK_TEXT_TAG (tmp_list->data)((((CtkTextTag*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((tmp_list->data)), ((ctk_text_tag_get_type ())))))); |
2853 | prev = tmp_list; |
2854 | tmp_list = tmp_list->next; |
2855 | } |
2856 | } |
2857 | |
2858 | g_slist_foreach (tags, (GFunc) g_object_ref, NULL((void*)0)); |
2859 | |
2860 | tmp_list = tags; |
2861 | while (tmp_list != NULL((void*)0)) |
2862 | { |
2863 | tag = CTK_TEXT_TAG (tmp_list->data)((((CtkTextTag*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((tmp_list->data)), ((ctk_text_tag_get_type ())))))); |
2864 | |
2865 | ctk_text_buffer_remove_tag (buffer, tag, &first, &second); |
2866 | |
2867 | tmp_list = tmp_list->next; |
2868 | } |
2869 | |
2870 | g_slist_free_full (tags, g_object_unref); |
2871 | } |
2872 | |
2873 | |
2874 | /* |
2875 | * Obtain various iterators |
2876 | */ |
2877 | |
2878 | /** |
2879 | * ctk_text_buffer_get_iter_at_line_offset: |
2880 | * @buffer: a #CtkTextBuffer |
2881 | * @iter: (out): iterator to initialize |
2882 | * @line_number: line number counting from 0 |
2883 | * @char_offset: char offset from start of line |
2884 | * |
2885 | * Obtains an iterator pointing to @char_offset within the given line. Note |
2886 | * characters, not bytes; UTF-8 may encode one character as multiple bytes. |
2887 | * |
2888 | * Before the 3.20 version, it was not allowed to pass an invalid location. |
2889 | * |
2890 | * Since the 3.20 version, if @line_number is greater than the number of lines |
2891 | * in the @buffer, the end iterator is returned. And if @char_offset is off the |
2892 | * end of the line, the iterator at the end of the line is returned. |
2893 | **/ |
2894 | void |
2895 | ctk_text_buffer_get_iter_at_line_offset (CtkTextBuffer *buffer, |
2896 | CtkTextIter *iter, |
2897 | gint line_number, |
2898 | gint char_offset) |
2899 | { |
2900 | CtkTextIter end_line_iter; |
2901 | |
2902 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
2903 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2904 | |
2905 | if (line_number >= ctk_text_buffer_get_line_count (buffer)) |
2906 | { |
2907 | ctk_text_buffer_get_end_iter (buffer, iter); |
2908 | return; |
2909 | } |
2910 | |
2911 | _ctk_text_btree_get_iter_at_line_char (get_btree (buffer), iter, line_number, 0); |
2912 | |
2913 | end_line_iter = *iter; |
2914 | if (!ctk_text_iter_ends_line (&end_line_iter)) |
2915 | ctk_text_iter_forward_to_line_end (&end_line_iter); |
2916 | |
2917 | if (char_offset <= ctk_text_iter_get_line_offset (&end_line_iter)) |
2918 | ctk_text_iter_set_line_offset (iter, char_offset); |
2919 | else |
2920 | *iter = end_line_iter; |
2921 | } |
2922 | |
2923 | /** |
2924 | * ctk_text_buffer_get_iter_at_line_index: |
2925 | * @buffer: a #CtkTextBuffer |
2926 | * @iter: (out): iterator to initialize |
2927 | * @line_number: line number counting from 0 |
2928 | * @byte_index: byte index from start of line |
2929 | * |
2930 | * Obtains an iterator pointing to @byte_index within the given line. |
2931 | * @byte_index must be the start of a UTF-8 character. Note bytes, not |
2932 | * characters; UTF-8 may encode one character as multiple bytes. |
2933 | * |
2934 | * Before the 3.20 version, it was not allowed to pass an invalid location. |
2935 | * |
2936 | * Since the 3.20 version, if @line_number is greater than the number of lines |
2937 | * in the @buffer, the end iterator is returned. And if @byte_index is off the |
2938 | * end of the line, the iterator at the end of the line is returned. |
2939 | **/ |
2940 | void |
2941 | ctk_text_buffer_get_iter_at_line_index (CtkTextBuffer *buffer, |
2942 | CtkTextIter *iter, |
2943 | gint line_number, |
2944 | gint byte_index) |
2945 | { |
2946 | CtkTextIter end_line_iter; |
2947 | |
2948 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
2949 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2950 | |
2951 | if (line_number >= ctk_text_buffer_get_line_count (buffer)) |
2952 | { |
2953 | ctk_text_buffer_get_end_iter (buffer, iter); |
2954 | return; |
2955 | } |
2956 | |
2957 | ctk_text_buffer_get_iter_at_line (buffer, iter, line_number); |
2958 | |
2959 | end_line_iter = *iter; |
2960 | if (!ctk_text_iter_ends_line (&end_line_iter)) |
2961 | ctk_text_iter_forward_to_line_end (&end_line_iter); |
2962 | |
2963 | if (byte_index <= ctk_text_iter_get_line_index (&end_line_iter)) |
2964 | ctk_text_iter_set_line_index (iter, byte_index); |
2965 | else |
2966 | *iter = end_line_iter; |
2967 | } |
2968 | |
2969 | /** |
2970 | * ctk_text_buffer_get_iter_at_line: |
2971 | * @buffer: a #CtkTextBuffer |
2972 | * @iter: (out): iterator to initialize |
2973 | * @line_number: line number counting from 0 |
2974 | * |
2975 | * Initializes @iter to the start of the given line. If @line_number is greater |
2976 | * than the number of lines in the @buffer, the end iterator is returned. |
2977 | **/ |
2978 | void |
2979 | ctk_text_buffer_get_iter_at_line (CtkTextBuffer *buffer, |
2980 | CtkTextIter *iter, |
2981 | gint line_number) |
2982 | { |
2983 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
2984 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
2985 | |
2986 | ctk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0); |
2987 | } |
2988 | |
2989 | /** |
2990 | * ctk_text_buffer_get_iter_at_offset: |
2991 | * @buffer: a #CtkTextBuffer |
2992 | * @iter: (out): iterator to initialize |
2993 | * @char_offset: char offset from start of buffer, counting from 0, or -1 |
2994 | * |
2995 | * Initializes @iter to a position @char_offset chars from the start |
2996 | * of the entire buffer. If @char_offset is -1 or greater than the number |
2997 | * of characters in the buffer, @iter is initialized to the end iterator, |
2998 | * the iterator one past the last valid character in the buffer. |
2999 | **/ |
3000 | void |
3001 | ctk_text_buffer_get_iter_at_offset (CtkTextBuffer *buffer, |
3002 | CtkTextIter *iter, |
3003 | gint char_offset) |
3004 | { |
3005 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
3006 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
3007 | |
3008 | _ctk_text_btree_get_iter_at_char (get_btree (buffer), iter, char_offset); |
3009 | } |
3010 | |
3011 | /** |
3012 | * ctk_text_buffer_get_start_iter: |
3013 | * @buffer: a #CtkTextBuffer |
3014 | * @iter: (out): iterator to initialize |
3015 | * |
3016 | * Initialized @iter with the first position in the text buffer. This |
3017 | * is the same as using ctk_text_buffer_get_iter_at_offset() to get |
3018 | * the iter at character offset 0. |
3019 | **/ |
3020 | void |
3021 | ctk_text_buffer_get_start_iter (CtkTextBuffer *buffer, |
3022 | CtkTextIter *iter) |
3023 | { |
3024 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
3025 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
3026 | |
3027 | _ctk_text_btree_get_iter_at_char (get_btree (buffer), iter, 0); |
3028 | } |
3029 | |
3030 | /** |
3031 | * ctk_text_buffer_get_end_iter: |
3032 | * @buffer: a #CtkTextBuffer |
3033 | * @iter: (out): iterator to initialize |
3034 | * |
3035 | * Initializes @iter with the “end iterator,” one past the last valid |
3036 | * character in the text buffer. If dereferenced with |
3037 | * ctk_text_iter_get_char(), the end iterator has a character value of 0. |
3038 | * The entire buffer lies in the range from the first position in |
3039 | * the buffer (call ctk_text_buffer_get_start_iter() to get |
3040 | * character position 0) to the end iterator. |
3041 | **/ |
3042 | void |
3043 | ctk_text_buffer_get_end_iter (CtkTextBuffer *buffer, |
3044 | CtkTextIter *iter) |
3045 | { |
3046 | g_return_if_fail (iter != NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
3047 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
3048 | |
3049 | _ctk_text_btree_get_end_iter (get_btree (buffer), iter); |
3050 | } |
3051 | |
3052 | /** |
3053 | * ctk_text_buffer_get_bounds: |
3054 | * @buffer: a #CtkTextBuffer |
3055 | * @start: (out): iterator to initialize with first position in the buffer |
3056 | * @end: (out): iterator to initialize with the end iterator |
3057 | * |
3058 | * Retrieves the first and last iterators in the buffer, i.e. the |
3059 | * entire buffer lies within the range [@start,@end). |
3060 | **/ |
3061 | void |
3062 | ctk_text_buffer_get_bounds (CtkTextBuffer *buffer, |
3063 | CtkTextIter *start, |
3064 | CtkTextIter *end) |
3065 | { |
3066 | g_return_if_fail (start != NULL)do { if ((start != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "start != NULL"); return ; } } while (0); |
3067 | g_return_if_fail (end != NULL)do { if ((end != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "end != NULL"); return; } } while (0); |
3068 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
3069 | |
3070 | _ctk_text_btree_get_iter_at_char (get_btree (buffer), start, 0); |
3071 | _ctk_text_btree_get_end_iter (get_btree (buffer), end); |
3072 | } |
3073 | |
3074 | /* |
3075 | * Modified flag |
3076 | */ |
3077 | |
3078 | /** |
3079 | * ctk_text_buffer_get_modified: |
3080 | * @buffer: a #CtkTextBuffer |
3081 | * |
3082 | * Indicates whether the buffer has been modified since the last call |
3083 | * to ctk_text_buffer_set_modified() set the modification flag to |
3084 | * %FALSE. Used for example to enable a “save” function in a text |
3085 | * editor. |
3086 | * |
3087 | * Returns: %TRUE if the buffer has been modified |
3088 | **/ |
3089 | gboolean |
3090 | ctk_text_buffer_get_modified (CtkTextBuffer *buffer) |
3091 | { |
3092 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return ((0)); } } while ( 0); |
3093 | |
3094 | return buffer->priv->modified; |
3095 | } |
3096 | |
3097 | /** |
3098 | * ctk_text_buffer_set_modified: |
3099 | * @buffer: a #CtkTextBuffer |
3100 | * @setting: modification flag setting |
3101 | * |
3102 | * Used to keep track of whether the buffer has been modified since the |
3103 | * last time it was saved. Whenever the buffer is saved to disk, call |
3104 | * ctk_text_buffer_set_modified (@buffer, FALSE). When the buffer is modified, |
3105 | * it will automatically toggled on the modified bit again. When the modified |
3106 | * bit flips, the buffer emits the #CtkTextBuffer::modified-changed signal. |
3107 | **/ |
3108 | void |
3109 | ctk_text_buffer_set_modified (CtkTextBuffer *buffer, |
3110 | gboolean setting) |
3111 | { |
3112 | gboolean fixed_setting; |
3113 | |
3114 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
3115 | |
3116 | fixed_setting = setting != FALSE(0); |
3117 | |
3118 | if (buffer->priv->modified == fixed_setting) |
3119 | return; |
3120 | else |
3121 | { |
3122 | buffer->priv->modified = fixed_setting; |
3123 | g_signal_emit (buffer, signals[MODIFIED_CHANGED], 0); |
3124 | } |
3125 | } |
3126 | |
3127 | /** |
3128 | * ctk_text_buffer_get_has_selection: |
3129 | * @buffer: a #CtkTextBuffer |
3130 | * |
3131 | * Indicates whether the buffer has some text currently selected. |
3132 | * |
3133 | * Returns: %TRUE if the there is text selected |
3134 | * |
3135 | * Since: 2.10 |
3136 | **/ |
3137 | gboolean |
3138 | ctk_text_buffer_get_has_selection (CtkTextBuffer *buffer) |
3139 | { |
3140 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return ((0)); } } while ( 0); |
3141 | |
3142 | return buffer->priv->has_selection; |
3143 | } |
3144 | |
3145 | |
3146 | /* |
3147 | * Assorted other stuff |
3148 | */ |
3149 | |
3150 | /** |
3151 | * ctk_text_buffer_get_line_count: |
3152 | * @buffer: a #CtkTextBuffer |
3153 | * |
3154 | * Obtains the number of lines in the buffer. This value is cached, so |
3155 | * the function is very fast. |
3156 | * |
3157 | * Returns: number of lines in the buffer |
3158 | **/ |
3159 | gint |
3160 | ctk_text_buffer_get_line_count (CtkTextBuffer *buffer) |
3161 | { |
3162 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (0); } } while (0); |
3163 | |
3164 | return _ctk_text_btree_line_count (get_btree (buffer)); |
3165 | } |
3166 | |
3167 | /** |
3168 | * ctk_text_buffer_get_char_count: |
3169 | * @buffer: a #CtkTextBuffer |
3170 | * |
3171 | * Gets the number of characters in the buffer; note that characters |
3172 | * and bytes are not the same, you can’t e.g. expect the contents of |
3173 | * the buffer in string form to be this many bytes long. The character |
3174 | * count is cached, so this function is very fast. |
3175 | * |
3176 | * Returns: number of characters in the buffer |
3177 | **/ |
3178 | gint |
3179 | ctk_text_buffer_get_char_count (CtkTextBuffer *buffer) |
3180 | { |
3181 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (0); } } while (0); |
3182 | |
3183 | return _ctk_text_btree_char_count (get_btree (buffer)); |
3184 | } |
3185 | |
3186 | /* Called when we lose the primary selection. |
3187 | */ |
3188 | static void |
3189 | clipboard_clear_selection_cb (CtkClipboard *clipboard G_GNUC_UNUSED__attribute__ ((__unused__)), |
3190 | gpointer data) |
3191 | { |
3192 | /* Move selection_bound to the insertion point */ |
3193 | CtkTextIter insert; |
3194 | CtkTextIter selection_bound; |
3195 | CtkTextBuffer *buffer = CTK_TEXT_BUFFER (data)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((data)), ((ctk_text_buffer_get_type ())))))); |
3196 | |
3197 | ctk_text_buffer_get_iter_at_mark (buffer, &insert, |
3198 | ctk_text_buffer_get_insert (buffer)); |
3199 | ctk_text_buffer_get_iter_at_mark (buffer, &selection_bound, |
3200 | ctk_text_buffer_get_selection_bound (buffer)); |
3201 | |
3202 | if (!ctk_text_iter_equal (&insert, &selection_bound)) |
3203 | ctk_text_buffer_move_mark (buffer, |
3204 | ctk_text_buffer_get_selection_bound (buffer), |
3205 | &insert); |
3206 | } |
3207 | |
3208 | /* Called when we have the primary selection and someone else wants our |
3209 | * data in order to paste it. |
3210 | */ |
3211 | static void |
3212 | clipboard_get_selection_cb (CtkClipboard *clipboard G_GNUC_UNUSED__attribute__ ((__unused__)), |
3213 | CtkSelectionData *selection_data, |
3214 | guint info, |
3215 | gpointer data) |
3216 | { |
3217 | CtkTextBuffer *buffer = CTK_TEXT_BUFFER (data)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((data)), ((ctk_text_buffer_get_type ())))))); |
3218 | CtkTextIter start, end; |
3219 | |
3220 | if (ctk_text_buffer_get_selection_bounds (buffer, &start, &end)) |
3221 | { |
3222 | if (info == CTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS) |
3223 | { |
3224 | /* Provide the address of the buffer; this will only be |
3225 | * used within-process |
3226 | */ |
3227 | ctk_selection_data_set (selection_data, |
3228 | ctk_selection_data_get_target (selection_data), |
3229 | 8, /* bytes */ |
3230 | (void*)&buffer, |
3231 | sizeof (buffer)); |
3232 | } |
3233 | else if (info == CTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT) |
3234 | { |
3235 | guint8 *str; |
3236 | gsize len; |
3237 | |
3238 | str = ctk_text_buffer_serialize (buffer, buffer, |
3239 | ctk_selection_data_get_target (selection_data), |
3240 | &start, &end, &len); |
3241 | |
3242 | ctk_selection_data_set (selection_data, |
3243 | ctk_selection_data_get_target (selection_data), |
3244 | 8, /* bytes */ |
3245 | str, len); |
3246 | g_free (str); |
3247 | } |
3248 | else |
3249 | { |
3250 | gchar *str; |
3251 | |
3252 | str = ctk_text_iter_get_visible_text (&start, &end); |
3253 | ctk_selection_data_set_text (selection_data, str, -1); |
3254 | g_free (str); |
3255 | } |
3256 | } |
3257 | } |
3258 | |
3259 | static CtkTextBuffer * |
3260 | create_clipboard_contents_buffer (CtkTextBuffer *buffer) |
3261 | { |
3262 | CtkTextBuffer *contents; |
3263 | |
3264 | contents = ctk_text_buffer_new (ctk_text_buffer_get_tag_table (buffer)); |
3265 | |
3266 | g_object_set_data (G_OBJECT (contents)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((contents)), (((GType) ((20) << (2)))))))), I_("ctk-text-buffer-clipboard-source")g_intern_static_string ("ctk-text-buffer-clipboard-source"), |
3267 | buffer); |
3268 | g_object_set_data (G_OBJECT (contents)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((contents)), (((GType) ((20) << (2)))))))), I_("ctk-text-buffer-clipboard")g_intern_static_string ("ctk-text-buffer-clipboard"), |
3269 | GINT_TO_POINTER (1)((gpointer) (glong) (1))); |
3270 | |
3271 | /* Ref the source buffer as long as the clipboard contents buffer |
3272 | * exists, because it's needed for serializing the contents buffer. |
3273 | * See http://bugzilla.gnome.org/show_bug.cgi?id=339195 |
3274 | */ |
3275 | g_object_ref (buffer)((__typeof__ (buffer)) (g_object_ref) (buffer)); |
3276 | g_object_weak_ref (G_OBJECT (contents)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((contents)), (((GType) ((20) << (2)))))))), (GWeakNotify) g_object_unref, buffer); |
3277 | |
3278 | return contents; |
3279 | } |
3280 | |
3281 | /* Provide cut/copied data */ |
3282 | static void |
3283 | clipboard_get_contents_cb (CtkClipboard *clipboard G_GNUC_UNUSED__attribute__ ((__unused__)), |
3284 | CtkSelectionData *selection_data, |
3285 | guint info, |
3286 | gpointer data) |
3287 | { |
3288 | CtkTextBuffer *contents = CTK_TEXT_BUFFER (data)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((data)), ((ctk_text_buffer_get_type ())))))); |
3289 | |
3290 | g_assert (contents)do { if (contents) ; else g_assertion_message_expr ("Ctk", "ctktextbuffer.c" , 3290, ((const char*) (__func__)), "contents"); } while (0); /* This should never be called unless we own the clipboard */ |
3291 | |
3292 | if (info == CTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS) |
3293 | { |
3294 | /* Provide the address of the clipboard buffer; this will only |
3295 | * be used within-process. OK to supply a NULL value for contents. |
3296 | */ |
3297 | ctk_selection_data_set (selection_data, |
3298 | ctk_selection_data_get_target (selection_data), |
3299 | 8, /* bytes */ |
3300 | (void*)&contents, |
3301 | sizeof (contents)); |
3302 | } |
3303 | else if (info == CTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT) |
3304 | { |
3305 | CtkTextBuffer *clipboard_source_buffer; |
3306 | CtkTextIter start, end; |
3307 | guint8 *str; |
3308 | gsize len; |
3309 | |
3310 | clipboard_source_buffer = g_object_get_data (G_OBJECT (contents)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((contents)), (((GType) ((20) << (2)))))))), |
3311 | "ctk-text-buffer-clipboard-source"); |
3312 | |
3313 | ctk_text_buffer_get_bounds (contents, &start, &end); |
3314 | |
3315 | str = ctk_text_buffer_serialize (clipboard_source_buffer, contents, |
3316 | ctk_selection_data_get_target (selection_data), |
3317 | &start, &end, &len); |
3318 | |
3319 | ctk_selection_data_set (selection_data, |
3320 | ctk_selection_data_get_target (selection_data), |
3321 | 8, /* bytes */ |
3322 | str, len); |
3323 | g_free (str); |
3324 | } |
3325 | else |
3326 | { |
3327 | gchar *str; |
3328 | CtkTextIter start, end; |
3329 | |
3330 | ctk_text_buffer_get_bounds (contents, &start, &end); |
3331 | |
3332 | str = ctk_text_iter_get_visible_text (&start, &end); |
3333 | ctk_selection_data_set_text (selection_data, str, -1); |
3334 | g_free (str); |
3335 | } |
3336 | } |
3337 | |
3338 | static void |
3339 | clipboard_clear_contents_cb (CtkClipboard *clipboard G_GNUC_UNUSED__attribute__ ((__unused__)), |
3340 | gpointer data) |
3341 | { |
3342 | CtkTextBuffer *contents = CTK_TEXT_BUFFER (data)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((data)), ((ctk_text_buffer_get_type ())))))); |
3343 | |
3344 | g_object_unref (contents); |
3345 | } |
3346 | |
3347 | static void |
3348 | get_paste_point (CtkTextBuffer *buffer, |
3349 | CtkTextIter *iter, |
3350 | gboolean clear_afterward) |
3351 | { |
3352 | CtkTextIter insert_point; |
3353 | CtkTextMark *paste_point_override; |
3354 | |
3355 | paste_point_override = ctk_text_buffer_get_mark (buffer, |
3356 | "ctk_paste_point_override"); |
3357 | |
3358 | if (paste_point_override != NULL((void*)0)) |
3359 | { |
3360 | ctk_text_buffer_get_iter_at_mark (buffer, &insert_point, |
3361 | paste_point_override); |
3362 | if (clear_afterward) |
3363 | ctk_text_buffer_delete_mark (buffer, paste_point_override); |
3364 | } |
3365 | else |
3366 | { |
3367 | ctk_text_buffer_get_iter_at_mark (buffer, &insert_point, |
3368 | ctk_text_buffer_get_insert (buffer)); |
3369 | } |
3370 | |
3371 | *iter = insert_point; |
3372 | } |
3373 | |
3374 | static void |
3375 | pre_paste_prep (ClipboardRequest *request_data, |
3376 | CtkTextIter *insert_point) |
3377 | { |
3378 | CtkTextBuffer *buffer = request_data->buffer; |
3379 | |
3380 | get_paste_point (buffer, insert_point, TRUE(!(0))); |
3381 | |
3382 | if (request_data->replace_selection) |
3383 | { |
3384 | CtkTextIter start, end; |
3385 | |
3386 | if (ctk_text_buffer_get_selection_bounds (buffer, &start, &end)) |
3387 | { |
3388 | if (request_data->interactive) |
3389 | ctk_text_buffer_delete_interactive (request_data->buffer, |
3390 | &start, |
3391 | &end, |
3392 | request_data->default_editable); |
3393 | else |
3394 | ctk_text_buffer_delete (request_data->buffer, &start, &end); |
3395 | |
3396 | *insert_point = start; |
3397 | } |
3398 | } |
3399 | } |
3400 | |
3401 | static void |
3402 | emit_paste_done (CtkTextBuffer *buffer, |
3403 | CtkClipboard *clipboard) |
3404 | { |
3405 | g_signal_emit (buffer, signals[PASTE_DONE], 0, clipboard); |
3406 | } |
3407 | |
3408 | static void |
3409 | free_clipboard_request (ClipboardRequest *request_data) |
3410 | { |
3411 | g_object_unref (request_data->buffer); |
3412 | g_slice_free (ClipboardRequest, request_data)do { if (1) g_slice_free1 (sizeof (ClipboardRequest), (request_data )); else (void) ((ClipboardRequest*) 0 == (request_data)); } while (0); |
3413 | } |
3414 | |
3415 | /* Called when we request a paste and receive the text data |
3416 | */ |
3417 | static void |
3418 | clipboard_text_received (CtkClipboard *clipboard, |
3419 | const gchar *str, |
3420 | gpointer data) |
3421 | { |
3422 | ClipboardRequest *request_data = data; |
3423 | CtkTextBuffer *buffer = request_data->buffer; |
3424 | |
3425 | if (str) |
3426 | { |
3427 | CtkTextIter insert_point; |
3428 | |
3429 | if (request_data->interactive) |
3430 | ctk_text_buffer_begin_user_action (buffer); |
3431 | |
3432 | pre_paste_prep (request_data, &insert_point); |
3433 | |
3434 | if (request_data->interactive) |
3435 | ctk_text_buffer_insert_interactive (buffer, &insert_point, |
3436 | str, -1, request_data->default_editable); |
3437 | else |
3438 | ctk_text_buffer_insert (buffer, &insert_point, |
3439 | str, -1); |
3440 | |
3441 | if (request_data->interactive) |
3442 | ctk_text_buffer_end_user_action (buffer); |
3443 | |
3444 | emit_paste_done (buffer, clipboard); |
3445 | } |
3446 | else |
3447 | { |
3448 | /* It may happen that we set a point override but we are not inserting |
3449 | any text, so we must remove it afterwards */ |
3450 | CtkTextMark *paste_point_override; |
3451 | |
3452 | paste_point_override = ctk_text_buffer_get_mark (buffer, |
3453 | "ctk_paste_point_override"); |
3454 | |
3455 | if (paste_point_override != NULL((void*)0)) |
3456 | ctk_text_buffer_delete_mark (buffer, paste_point_override); |
3457 | } |
3458 | |
3459 | free_clipboard_request (request_data); |
3460 | } |
3461 | |
3462 | static CtkTextBuffer* |
3463 | selection_data_get_buffer (CtkSelectionData *selection_data, |
3464 | ClipboardRequest *request_data) |
3465 | { |
3466 | CdkWindow *owner; |
3467 | CtkTextBuffer *src_buffer = NULL((void*)0); |
3468 | |
3469 | /* If we can get the owner, the selection is in-process */ |
3470 | owner = cdk_selection_owner_get_for_display (ctk_selection_data_get_display (selection_data), |
3471 | ctk_selection_data_get_selection (selection_data)); |
3472 | |
3473 | if (owner == NULL((void*)0)) |
3474 | return NULL((void*)0); |
3475 | |
3476 | if (cdk_window_get_window_type (owner) == CDK_WINDOW_FOREIGN) |
3477 | return NULL((void*)0); |
3478 | |
3479 | if (ctk_selection_data_get_data_type (selection_data) != cdk_atom_intern_static_string ("CTK_TEXT_BUFFER_CONTENTS")) |
3480 | return NULL((void*)0); |
3481 | |
3482 | if (ctk_selection_data_get_length (selection_data) != sizeof (src_buffer)) |
3483 | return NULL((void*)0); |
3484 | |
3485 | memcpy (&src_buffer, ctk_selection_data_get_data (selection_data), sizeof (src_buffer)); |
The code calls sizeof() on a pointer type. This can produce an unexpected result | |
3486 | |
3487 | if (src_buffer == NULL((void*)0)) |
3488 | return NULL((void*)0); |
3489 | |
3490 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (src_buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((src_buffer)); GType __t = ((ctk_text_buffer_get_type ()) ); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "CTK_IS_TEXT_BUFFER (src_buffer)"); return (((void*)0)); } } while (0); |
3491 | |
3492 | if (ctk_text_buffer_get_tag_table (src_buffer) != |
3493 | ctk_text_buffer_get_tag_table (request_data->buffer)) |
3494 | return NULL((void*)0); |
3495 | |
3496 | return src_buffer; |
3497 | } |
3498 | |
3499 | #if 0 |
3500 | /* These are pretty handy functions; maybe something like them |
3501 | * should be in the public API. Also, there are other places in this |
3502 | * file where they could be used. |
3503 | */ |
3504 | static gpointer |
3505 | save_iter (const CtkTextIter *iter, |
3506 | gboolean left_gravity) |
3507 | { |
3508 | return ctk_text_buffer_create_mark (ctk_text_iter_get_buffer (iter), |
3509 | NULL((void*)0), |
3510 | iter, |
3511 | TRUE(!(0))); |
3512 | } |
3513 | |
3514 | static void |
3515 | restore_iter (const CtkTextIter *iter, |
3516 | gpointer save_id) |
3517 | { |
3518 | ctk_text_buffer_get_iter_at_mark (ctk_text_mark_get_buffer (save_id), |
3519 | (CtkTextIter*) iter, |
3520 | save_id); |
3521 | ctk_text_buffer_delete_mark (ctk_text_mark_get_buffer (save_id), |
3522 | save_id); |
3523 | } |
3524 | #endif |
3525 | |
3526 | static void |
3527 | clipboard_rich_text_received (CtkClipboard *clipboard, |
3528 | CdkAtom format, |
3529 | const guint8 *text, |
3530 | gsize length, |
3531 | gpointer data) |
3532 | { |
3533 | ClipboardRequest *request_data = data; |
3534 | CtkTextIter insert_point; |
3535 | gboolean retval = TRUE(!(0)); |
3536 | GError *error = NULL((void*)0); |
3537 | |
3538 | if (text != NULL((void*)0) && length > 0) |
3539 | { |
3540 | if (request_data->interactive) |
3541 | ctk_text_buffer_begin_user_action (request_data->buffer); |
3542 | |
3543 | pre_paste_prep (request_data, &insert_point); |
3544 | |
3545 | if (!request_data->interactive || |
3546 | ctk_text_iter_can_insert (&insert_point, |
3547 | request_data->default_editable)) |
3548 | { |
3549 | retval = ctk_text_buffer_deserialize (request_data->buffer, |
3550 | request_data->buffer, |
3551 | format, |
3552 | &insert_point, |
3553 | text, length, |
3554 | &error); |
3555 | } |
3556 | |
3557 | if (!retval) |
3558 | { |
3559 | g_warning ("error pasting: %s\n", error->message); |
3560 | g_clear_error (&error); |
3561 | } |
3562 | |
3563 | if (request_data->interactive) |
3564 | ctk_text_buffer_end_user_action (request_data->buffer); |
3565 | |
3566 | emit_paste_done (request_data->buffer, clipboard); |
3567 | |
3568 | if (retval) |
3569 | return; |
3570 | } |
3571 | |
3572 | /* Request the text selection instead */ |
3573 | ctk_clipboard_request_text (clipboard, |
3574 | clipboard_text_received, |
3575 | data); |
3576 | } |
3577 | |
3578 | static void |
3579 | paste_from_buffer (CtkClipboard *clipboard, |
3580 | ClipboardRequest *request_data, |
3581 | CtkTextBuffer *src_buffer, |
3582 | const CtkTextIter *start, |
3583 | const CtkTextIter *end) |
3584 | { |
3585 | CtkTextIter insert_point; |
3586 | CtkTextBuffer *buffer = request_data->buffer; |
3587 | |
3588 | /* We're about to emit a bunch of signals, so be safe */ |
3589 | g_object_ref (src_buffer)((__typeof__ (src_buffer)) (g_object_ref) (src_buffer)); |
3590 | |
3591 | /* Replacing the selection with itself */ |
3592 | if (request_data->replace_selection && |
3593 | buffer == src_buffer) |
3594 | { |
3595 | /* Clear the paste point if needed */ |
3596 | get_paste_point (buffer, &insert_point, TRUE(!(0))); |
3597 | goto done; |
3598 | } |
3599 | |
3600 | if (request_data->interactive) |
3601 | ctk_text_buffer_begin_user_action (buffer); |
3602 | |
3603 | pre_paste_prep (request_data, &insert_point); |
3604 | |
3605 | if (!ctk_text_iter_equal (start, end)) |
3606 | { |
3607 | if (!request_data->interactive || |
3608 | (ctk_text_iter_can_insert (&insert_point, |
3609 | request_data->default_editable))) |
3610 | ctk_text_buffer_real_insert_range (buffer, |
3611 | &insert_point, |
3612 | start, |
3613 | end, |
3614 | request_data->interactive); |
3615 | } |
3616 | |
3617 | if (request_data->interactive) |
3618 | ctk_text_buffer_end_user_action (buffer); |
3619 | |
3620 | done: |
3621 | emit_paste_done (buffer, clipboard); |
3622 | |
3623 | g_object_unref (src_buffer); |
3624 | |
3625 | free_clipboard_request (request_data); |
3626 | } |
3627 | |
3628 | static void |
3629 | clipboard_clipboard_buffer_received (CtkClipboard *clipboard, |
3630 | CtkSelectionData *selection_data, |
3631 | gpointer data) |
3632 | { |
3633 | ClipboardRequest *request_data = data; |
3634 | CtkTextBuffer *src_buffer; |
3635 | |
3636 | src_buffer = selection_data_get_buffer (selection_data, request_data); |
3637 | |
3638 | if (src_buffer) |
3639 | { |
3640 | CtkTextIter start, end; |
3641 | |
3642 | if (g_object_get_data (G_OBJECT (src_buffer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((src_buffer)), (((GType) ((20) << (2)))))))), "ctk-text-buffer-clipboard")) |
3643 | { |
3644 | ctk_text_buffer_get_bounds (src_buffer, &start, &end); |
3645 | |
3646 | paste_from_buffer (clipboard, request_data, src_buffer, |
3647 | &start, &end); |
3648 | } |
3649 | else |
3650 | { |
3651 | if (ctk_text_buffer_get_selection_bounds (src_buffer, &start, &end)) |
3652 | paste_from_buffer (clipboard, request_data, src_buffer, |
3653 | &start, &end); |
3654 | } |
3655 | } |
3656 | else |
3657 | { |
3658 | if (ctk_clipboard_wait_is_rich_text_available (clipboard, |
3659 | request_data->buffer)) |
3660 | { |
3661 | /* Request rich text */ |
3662 | ctk_clipboard_request_rich_text (clipboard, |
3663 | request_data->buffer, |
3664 | clipboard_rich_text_received, |
3665 | data); |
3666 | } |
3667 | else |
3668 | { |
3669 | /* Request the text selection instead */ |
3670 | ctk_clipboard_request_text (clipboard, |
3671 | clipboard_text_received, |
3672 | data); |
3673 | } |
3674 | } |
3675 | } |
3676 | |
3677 | typedef struct |
3678 | { |
3679 | CtkClipboard *clipboard; |
3680 | guint ref_count; |
3681 | } SelectionClipboard; |
3682 | |
3683 | static void |
3684 | update_selection_clipboards (CtkTextBuffer *buffer) |
3685 | { |
3686 | CtkTextBufferPrivate *priv; |
3687 | gboolean has_selection; |
3688 | CtkTextIter start; |
3689 | CtkTextIter end; |
3690 | GSList *tmp_list; |
3691 | |
3692 | priv = buffer->priv; |
3693 | |
3694 | ctk_text_buffer_get_copy_target_list (buffer); |
3695 | has_selection = ctk_text_buffer_get_selection_bounds (buffer, &start, &end); |
3696 | tmp_list = buffer->priv->selection_clipboards; |
3697 | |
3698 | while (tmp_list) |
3699 | { |
3700 | SelectionClipboard *selection_clipboard = tmp_list->data; |
3701 | CtkClipboard *clipboard = selection_clipboard->clipboard; |
3702 | |
3703 | if (has_selection) |
3704 | { |
3705 | /* Even if we already have the selection, we need to update our |
3706 | * timestamp. |
3707 | */ |
3708 | ctk_clipboard_set_with_owner (clipboard, |
3709 | priv->copy_target_entries, |
3710 | priv->n_copy_target_entries, |
3711 | clipboard_get_selection_cb, |
3712 | clipboard_clear_selection_cb, |
3713 | G_OBJECT (buffer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((buffer)), (((GType) ((20) << (2))))))))); |
3714 | } |
3715 | else if (ctk_clipboard_get_owner (clipboard) == G_OBJECT (buffer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((buffer)), (((GType) ((20) << (2))))))))) |
3716 | ctk_clipboard_clear (clipboard); |
3717 | |
3718 | tmp_list = tmp_list->next; |
3719 | } |
3720 | } |
3721 | |
3722 | static SelectionClipboard * |
3723 | find_selection_clipboard (CtkTextBuffer *buffer, |
3724 | CtkClipboard *clipboard) |
3725 | { |
3726 | GSList *tmp_list = buffer->priv->selection_clipboards; |
3727 | while (tmp_list) |
3728 | { |
3729 | SelectionClipboard *selection_clipboard = tmp_list->data; |
3730 | if (selection_clipboard->clipboard == clipboard) |
3731 | return selection_clipboard; |
3732 | |
3733 | tmp_list = tmp_list->next; |
3734 | } |
3735 | |
3736 | return NULL((void*)0); |
3737 | } |
3738 | |
3739 | /** |
3740 | * ctk_text_buffer_add_selection_clipboard: |
3741 | * @buffer: a #CtkTextBuffer |
3742 | * @clipboard: a #CtkClipboard |
3743 | * |
3744 | * Adds @clipboard to the list of clipboards in which the selection |
3745 | * contents of @buffer are available. In most cases, @clipboard will be |
3746 | * the #CtkClipboard of type %CDK_SELECTION_PRIMARY for a view of @buffer. |
3747 | **/ |
3748 | void |
3749 | ctk_text_buffer_add_selection_clipboard (CtkTextBuffer *buffer, |
3750 | CtkClipboard *clipboard) |
3751 | { |
3752 | SelectionClipboard *selection_clipboard; |
3753 | |
3754 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
3755 | g_return_if_fail (clipboard != NULL)do { if ((clipboard != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "clipboard != NULL"); return ; } } while (0); |
3756 | |
3757 | selection_clipboard = find_selection_clipboard (buffer, clipboard); |
3758 | if (selection_clipboard) |
3759 | { |
3760 | selection_clipboard->ref_count++; |
3761 | } |
3762 | else |
3763 | { |
3764 | selection_clipboard = g_slice_new (SelectionClipboard)((SelectionClipboard*) g_slice_alloc (sizeof (SelectionClipboard ))); |
3765 | |
3766 | selection_clipboard->clipboard = clipboard; |
3767 | selection_clipboard->ref_count = 1; |
3768 | |
3769 | buffer->priv->selection_clipboards = g_slist_prepend (buffer->priv->selection_clipboards, |
3770 | selection_clipboard); |
3771 | } |
3772 | } |
3773 | |
3774 | /** |
3775 | * ctk_text_buffer_remove_selection_clipboard: |
3776 | * @buffer: a #CtkTextBuffer |
3777 | * @clipboard: a #CtkClipboard added to @buffer by |
3778 | * ctk_text_buffer_add_selection_clipboard() |
3779 | * |
3780 | * Removes a #CtkClipboard added with |
3781 | * ctk_text_buffer_add_selection_clipboard(). |
3782 | **/ |
3783 | void |
3784 | ctk_text_buffer_remove_selection_clipboard (CtkTextBuffer *buffer, |
3785 | CtkClipboard *clipboard) |
3786 | { |
3787 | SelectionClipboard *selection_clipboard; |
3788 | |
3789 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
3790 | g_return_if_fail (clipboard != NULL)do { if ((clipboard != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "clipboard != NULL"); return ; } } while (0); |
3791 | |
3792 | selection_clipboard = find_selection_clipboard (buffer, clipboard); |
3793 | g_return_if_fail (selection_clipboard != NULL)do { if ((selection_clipboard != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "selection_clipboard != NULL" ); return; } } while (0); |
3794 | |
3795 | selection_clipboard->ref_count--; |
3796 | if (selection_clipboard->ref_count == 0) |
3797 | { |
3798 | if (ctk_clipboard_get_owner (selection_clipboard->clipboard) == G_OBJECT (buffer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((buffer)), (((GType) ((20) << (2))))))))) |
3799 | ctk_clipboard_clear (selection_clipboard->clipboard); |
3800 | |
3801 | buffer->priv->selection_clipboards = g_slist_remove (buffer->priv->selection_clipboards, |
3802 | selection_clipboard); |
3803 | |
3804 | g_slice_free (SelectionClipboard, selection_clipboard)do { if (1) g_slice_free1 (sizeof (SelectionClipboard), (selection_clipboard )); else (void) ((SelectionClipboard*) 0 == (selection_clipboard )); } while (0); |
3805 | } |
3806 | } |
3807 | |
3808 | static void |
3809 | remove_all_selection_clipboards (CtkTextBuffer *buffer) |
3810 | { |
3811 | CtkTextBufferPrivate *priv = buffer->priv; |
3812 | GSList *l; |
3813 | |
3814 | for (l = priv->selection_clipboards; l != NULL((void*)0); l = l->next) |
3815 | { |
3816 | SelectionClipboard *selection_clipboard = l->data; |
3817 | g_slice_free (SelectionClipboard, selection_clipboard)do { if (1) g_slice_free1 (sizeof (SelectionClipboard), (selection_clipboard )); else (void) ((SelectionClipboard*) 0 == (selection_clipboard )); } while (0); |
3818 | } |
3819 | |
3820 | g_slist_free (priv->selection_clipboards); |
3821 | priv->selection_clipboards = NULL((void*)0); |
3822 | } |
3823 | |
3824 | /** |
3825 | * ctk_text_buffer_paste_clipboard: |
3826 | * @buffer: a #CtkTextBuffer |
3827 | * @clipboard: the #CtkClipboard to paste from |
3828 | * @override_location: (allow-none): location to insert pasted text, or %NULL |
3829 | * @default_editable: whether the buffer is editable by default |
3830 | * |
3831 | * Pastes the contents of a clipboard. If @override_location is %NULL, the |
3832 | * pasted text will be inserted at the cursor position, or the buffer selection |
3833 | * will be replaced if the selection is non-empty. |
3834 | * |
3835 | * Note: pasting is asynchronous, that is, we’ll ask for the paste data and |
3836 | * return, and at some point later after the main loop runs, the paste data will |
3837 | * be inserted. |
3838 | **/ |
3839 | void |
3840 | ctk_text_buffer_paste_clipboard (CtkTextBuffer *buffer, |
3841 | CtkClipboard *clipboard, |
3842 | CtkTextIter *override_location, |
3843 | gboolean default_editable) |
3844 | { |
3845 | ClipboardRequest *data = g_slice_new (ClipboardRequest)((ClipboardRequest*) g_slice_alloc (sizeof (ClipboardRequest) )); |
3846 | CtkTextIter paste_point; |
3847 | CtkTextIter start, end; |
3848 | |
3849 | if (override_location != NULL((void*)0)) |
3850 | ctk_text_buffer_create_mark (buffer, |
3851 | "ctk_paste_point_override", |
3852 | override_location, FALSE(0)); |
3853 | |
3854 | data->buffer = g_object_ref (buffer)((__typeof__ (buffer)) (g_object_ref) (buffer)); |
3855 | data->interactive = TRUE(!(0)); |
3856 | data->default_editable = !!default_editable; |
3857 | |
3858 | /* When pasting with the cursor inside the selection area, you |
3859 | * replace the selection with the new text, otherwise, you |
3860 | * simply insert the new text at the point where the click |
3861 | * occurred, unselecting any selected text. The replace_selection |
3862 | * flag toggles this behavior. |
3863 | */ |
3864 | data->replace_selection = FALSE(0); |
3865 | |
3866 | get_paste_point (buffer, &paste_point, FALSE(0)); |
3867 | if (ctk_text_buffer_get_selection_bounds (buffer, &start, &end) && |
3868 | (ctk_text_iter_in_range (&paste_point, &start, &end) || |
3869 | ctk_text_iter_equal (&paste_point, &end))) |
3870 | data->replace_selection = TRUE(!(0)); |
3871 | |
3872 | ctk_clipboard_request_contents (clipboard, |
3873 | cdk_atom_intern_static_string ("CTK_TEXT_BUFFER_CONTENTS"), |
3874 | clipboard_clipboard_buffer_received, data); |
3875 | } |
3876 | |
3877 | /** |
3878 | * ctk_text_buffer_delete_selection: |
3879 | * @buffer: a #CtkTextBuffer |
3880 | * @interactive: whether the deletion is caused by user interaction |
3881 | * @default_editable: whether the buffer is editable by default |
3882 | * |
3883 | * Deletes the range between the “insert” and “selection_bound” marks, |
3884 | * that is, the currently-selected text. If @interactive is %TRUE, |
3885 | * the editability of the selection will be considered (users can’t delete |
3886 | * uneditable text). |
3887 | * |
3888 | * Returns: whether there was a non-empty selection to delete |
3889 | **/ |
3890 | gboolean |
3891 | ctk_text_buffer_delete_selection (CtkTextBuffer *buffer, |
3892 | gboolean interactive, |
3893 | gboolean default_editable) |
3894 | { |
3895 | CtkTextIter start; |
3896 | CtkTextIter end; |
3897 | |
3898 | if (!ctk_text_buffer_get_selection_bounds (buffer, &start, &end)) |
3899 | { |
3900 | return FALSE(0); /* No selection */ |
3901 | } |
3902 | else |
3903 | { |
3904 | if (interactive) |
3905 | ctk_text_buffer_delete_interactive (buffer, &start, &end, default_editable); |
3906 | else |
3907 | ctk_text_buffer_delete (buffer, &start, &end); |
3908 | |
3909 | return TRUE(!(0)); /* We deleted stuff */ |
3910 | } |
3911 | } |
3912 | |
3913 | /** |
3914 | * ctk_text_buffer_backspace: |
3915 | * @buffer: a #CtkTextBuffer |
3916 | * @iter: a position in @buffer |
3917 | * @interactive: whether the deletion is caused by user interaction |
3918 | * @default_editable: whether the buffer is editable by default |
3919 | * |
3920 | * Performs the appropriate action as if the user hit the delete |
3921 | * key with the cursor at the position specified by @iter. In the |
3922 | * normal case a single character will be deleted, but when |
3923 | * combining accents are involved, more than one character can |
3924 | * be deleted, and when precomposed character and accent combinations |
3925 | * are involved, less than one character will be deleted. |
3926 | * |
3927 | * Because the buffer is modified, all outstanding iterators become |
3928 | * invalid after calling this function; however, the @iter will be |
3929 | * re-initialized to point to the location where text was deleted. |
3930 | * |
3931 | * Returns: %TRUE if the buffer was modified |
3932 | * |
3933 | * Since: 2.6 |
3934 | **/ |
3935 | gboolean |
3936 | ctk_text_buffer_backspace (CtkTextBuffer *buffer, |
3937 | CtkTextIter *iter, |
3938 | gboolean interactive, |
3939 | gboolean default_editable) |
3940 | { |
3941 | gchar *cluster_text; |
3942 | CtkTextIter start; |
3943 | CtkTextIter end; |
3944 | gboolean retval = FALSE(0); |
3945 | const PangoLogAttr *attrs; |
3946 | gint offset; |
3947 | gboolean backspace_deletes_character; |
3948 | |
3949 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return ((0)); } } while ( 0); |
3950 | g_return_val_if_fail (iter != NULL, FALSE)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "iter != NULL"); return ( (0)); } } while (0); |
3951 | |
3952 | start = *iter; |
3953 | end = *iter; |
3954 | |
3955 | attrs = _ctk_text_buffer_get_line_log_attrs (buffer, &start, NULL((void*)0)); |
3956 | offset = ctk_text_iter_get_line_offset (&start); |
3957 | backspace_deletes_character = attrs[offset].backspace_deletes_character; |
3958 | |
3959 | ctk_text_iter_backward_cursor_position (&start); |
3960 | |
3961 | if (ctk_text_iter_equal (&start, &end)) |
3962 | return FALSE(0); |
3963 | |
3964 | cluster_text = ctk_text_iter_get_text (&start, &end); |
3965 | |
3966 | if (interactive) |
3967 | ctk_text_buffer_begin_user_action (buffer); |
3968 | |
3969 | if (ctk_text_buffer_delete_interactive (buffer, &start, &end, |
3970 | default_editable)) |
3971 | { |
3972 | /* special case \r\n, since we never want to reinsert \r */ |
3973 | if (backspace_deletes_character && strcmp ("\r\n", cluster_text)) |
3974 | { |
3975 | gchar *normalized_text = g_utf8_normalize (cluster_text, |
3976 | strlen (cluster_text), |
3977 | G_NORMALIZE_NFD); |
3978 | glong len = g_utf8_strlen (normalized_text, -1); |
3979 | |
3980 | if (len > 1) |
3981 | ctk_text_buffer_insert_interactive (buffer, |
3982 | &start, |
3983 | normalized_text, |
3984 | g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text, |
3985 | default_editable); |
3986 | |
3987 | g_free (normalized_text); |
3988 | } |
3989 | |
3990 | retval = TRUE(!(0)); |
3991 | } |
3992 | |
3993 | if (interactive) |
3994 | ctk_text_buffer_end_user_action (buffer); |
3995 | |
3996 | g_free (cluster_text); |
3997 | |
3998 | /* Revalidate the users iter */ |
3999 | *iter = start; |
4000 | |
4001 | return retval; |
4002 | } |
4003 | |
4004 | static void |
4005 | cut_or_copy (CtkTextBuffer *buffer, |
4006 | CtkClipboard *clipboard, |
4007 | gboolean delete_region_after, |
4008 | gboolean interactive, |
4009 | gboolean default_editable) |
4010 | { |
4011 | CtkTextBufferPrivate *priv; |
4012 | |
4013 | /* We prefer to cut the selected region between selection_bound and |
4014 | * insertion point. If that region is empty, then we cut the region |
4015 | * between the "anchor" and the insertion point (this is for |
4016 | * C-space and M-w and other Emacs-style copy/yank keys). Note that |
4017 | * insert and selection_bound are guaranteed to exist, but the |
4018 | * anchor only exists sometimes. |
4019 | */ |
4020 | CtkTextIter start; |
4021 | CtkTextIter end; |
4022 | |
4023 | priv = buffer->priv; |
4024 | |
4025 | ctk_text_buffer_get_copy_target_list (buffer); |
4026 | |
4027 | if (!ctk_text_buffer_get_selection_bounds (buffer, &start, &end)) |
4028 | { |
4029 | /* Let's try the anchor thing */ |
4030 | CtkTextMark * anchor = ctk_text_buffer_get_mark (buffer, "anchor"); |
4031 | |
4032 | if (anchor == NULL((void*)0)) |
4033 | return; |
4034 | else |
4035 | { |
4036 | ctk_text_buffer_get_iter_at_mark (buffer, &end, anchor); |
4037 | ctk_text_iter_order (&start, &end); |
4038 | } |
4039 | } |
4040 | |
4041 | if (!ctk_text_iter_equal (&start, &end)) |
4042 | { |
4043 | CtkTextIter ins; |
4044 | CtkTextBuffer *contents; |
4045 | |
4046 | contents = create_clipboard_contents_buffer (buffer); |
4047 | |
4048 | ctk_text_buffer_get_iter_at_offset (contents, &ins, 0); |
4049 | |
4050 | ctk_text_buffer_insert_range (contents, &ins, &start, &end); |
4051 | |
4052 | if (!ctk_clipboard_set_with_data (clipboard, |
4053 | priv->copy_target_entries, |
4054 | priv->n_copy_target_entries, |
4055 | clipboard_get_contents_cb, |
4056 | clipboard_clear_contents_cb, |
4057 | contents)) |
4058 | g_object_unref (contents); |
4059 | else |
4060 | ctk_clipboard_set_can_store (clipboard, |
4061 | priv->copy_target_entries + 1, |
4062 | priv->n_copy_target_entries - 1); |
4063 | |
4064 | if (delete_region_after) |
4065 | { |
4066 | if (interactive) |
4067 | ctk_text_buffer_delete_interactive (buffer, &start, &end, |
4068 | default_editable); |
4069 | else |
4070 | ctk_text_buffer_delete (buffer, &start, &end); |
4071 | } |
4072 | } |
4073 | } |
4074 | |
4075 | /** |
4076 | * ctk_text_buffer_cut_clipboard: |
4077 | * @buffer: a #CtkTextBuffer |
4078 | * @clipboard: the #CtkClipboard object to cut to |
4079 | * @default_editable: default editability of the buffer |
4080 | * |
4081 | * Copies the currently-selected text to a clipboard, then deletes |
4082 | * said text if it’s editable. |
4083 | **/ |
4084 | void |
4085 | ctk_text_buffer_cut_clipboard (CtkTextBuffer *buffer, |
4086 | CtkClipboard *clipboard, |
4087 | gboolean default_editable) |
4088 | { |
4089 | ctk_text_buffer_begin_user_action (buffer); |
4090 | cut_or_copy (buffer, clipboard, TRUE(!(0)), TRUE(!(0)), default_editable); |
4091 | ctk_text_buffer_end_user_action (buffer); |
4092 | } |
4093 | |
4094 | /** |
4095 | * ctk_text_buffer_copy_clipboard: |
4096 | * @buffer: a #CtkTextBuffer |
4097 | * @clipboard: the #CtkClipboard object to copy to |
4098 | * |
4099 | * Copies the currently-selected text to a clipboard. |
4100 | **/ |
4101 | void |
4102 | ctk_text_buffer_copy_clipboard (CtkTextBuffer *buffer, |
4103 | CtkClipboard *clipboard) |
4104 | { |
4105 | cut_or_copy (buffer, clipboard, FALSE(0), TRUE(!(0)), TRUE(!(0))); |
4106 | } |
4107 | |
4108 | /** |
4109 | * ctk_text_buffer_get_selection_bounds: |
4110 | * @buffer: a #CtkTextBuffer a #CtkTextBuffer |
4111 | * @start: (out): iterator to initialize with selection start |
4112 | * @end: (out): iterator to initialize with selection end |
4113 | * |
4114 | * Returns %TRUE if some text is selected; places the bounds |
4115 | * of the selection in @start and @end (if the selection has length 0, |
4116 | * then @start and @end are filled in with the same value). |
4117 | * @start and @end will be in ascending order. If @start and @end are |
4118 | * NULL, then they are not filled in, but the return value still indicates |
4119 | * whether text is selected. |
4120 | * |
4121 | * Returns: whether the selection has nonzero length |
4122 | **/ |
4123 | gboolean |
4124 | ctk_text_buffer_get_selection_bounds (CtkTextBuffer *buffer, |
4125 | CtkTextIter *start, |
4126 | CtkTextIter *end) |
4127 | { |
4128 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return ((0)); } } while ( 0); |
4129 | |
4130 | return _ctk_text_btree_get_selection_bounds (get_btree (buffer), start, end); |
4131 | } |
4132 | |
4133 | /** |
4134 | * ctk_text_buffer_begin_user_action: |
4135 | * @buffer: a #CtkTextBuffer |
4136 | * |
4137 | * Called to indicate that the buffer operations between here and a |
4138 | * call to ctk_text_buffer_end_user_action() are part of a single |
4139 | * user-visible operation. The operations between |
4140 | * ctk_text_buffer_begin_user_action() and |
4141 | * ctk_text_buffer_end_user_action() can then be grouped when creating |
4142 | * an undo stack. #CtkTextBuffer maintains a count of calls to |
4143 | * ctk_text_buffer_begin_user_action() that have not been closed with |
4144 | * a call to ctk_text_buffer_end_user_action(), and emits the |
4145 | * “begin-user-action” and “end-user-action” signals only for the |
4146 | * outermost pair of calls. This allows you to build user actions |
4147 | * from other user actions. |
4148 | * |
4149 | * The “interactive” buffer mutation functions, such as |
4150 | * ctk_text_buffer_insert_interactive(), automatically call begin/end |
4151 | * user action around the buffer operations they perform, so there's |
4152 | * no need to add extra calls if you user action consists solely of a |
4153 | * single call to one of those functions. |
4154 | **/ |
4155 | void |
4156 | ctk_text_buffer_begin_user_action (CtkTextBuffer *buffer) |
4157 | { |
4158 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
4159 | |
4160 | buffer->priv->user_action_count += 1; |
4161 | |
4162 | if (buffer->priv->user_action_count == 1) |
4163 | { |
4164 | /* Outermost nested user action begin emits the signal */ |
4165 | g_signal_emit (buffer, signals[BEGIN_USER_ACTION], 0); |
4166 | } |
4167 | } |
4168 | |
4169 | /** |
4170 | * ctk_text_buffer_end_user_action: |
4171 | * @buffer: a #CtkTextBuffer |
4172 | * |
4173 | * Should be paired with a call to ctk_text_buffer_begin_user_action(). |
4174 | * See that function for a full explanation. |
4175 | **/ |
4176 | void |
4177 | ctk_text_buffer_end_user_action (CtkTextBuffer *buffer) |
4178 | { |
4179 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
4180 | g_return_if_fail (buffer->priv->user_action_count > 0)do { if ((buffer->priv->user_action_count > 0)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__) ), "buffer->priv->user_action_count > 0"); return; } } while (0); |
4181 | |
4182 | buffer->priv->user_action_count -= 1; |
4183 | |
4184 | if (buffer->priv->user_action_count == 0) |
4185 | { |
4186 | /* Ended the outermost-nested user action end, so emit the signal */ |
4187 | g_signal_emit (buffer, signals[END_USER_ACTION], 0); |
4188 | } |
4189 | } |
4190 | |
4191 | static void |
4192 | ctk_text_buffer_free_target_lists (CtkTextBuffer *buffer) |
4193 | { |
4194 | CtkTextBufferPrivate *priv = buffer->priv; |
4195 | |
4196 | if (priv->copy_target_list) |
4197 | { |
4198 | ctk_target_list_unref (priv->copy_target_list); |
4199 | priv->copy_target_list = NULL((void*)0); |
4200 | |
4201 | ctk_target_table_free (priv->copy_target_entries, |
4202 | priv->n_copy_target_entries); |
4203 | priv->copy_target_entries = NULL((void*)0); |
4204 | priv->n_copy_target_entries = 0; |
4205 | } |
4206 | |
4207 | if (priv->paste_target_list) |
4208 | { |
4209 | ctk_target_list_unref (priv->paste_target_list); |
4210 | priv->paste_target_list = NULL((void*)0); |
4211 | |
4212 | ctk_target_table_free (priv->paste_target_entries, |
4213 | priv->n_paste_target_entries); |
4214 | priv->paste_target_entries = NULL((void*)0); |
4215 | priv->n_paste_target_entries = 0; |
4216 | } |
4217 | } |
4218 | |
4219 | static CtkTargetList * |
4220 | ctk_text_buffer_get_target_list (CtkTextBuffer *buffer, |
4221 | gboolean deserializable, |
4222 | CtkTargetEntry **entries, |
4223 | gint *n_entries) |
4224 | { |
4225 | CtkTargetList *target_list; |
4226 | |
4227 | target_list = ctk_target_list_new (NULL((void*)0), 0); |
4228 | |
4229 | ctk_target_list_add (target_list, |
4230 | cdk_atom_intern_static_string ("CTK_TEXT_BUFFER_CONTENTS"), |
4231 | CTK_TARGET_SAME_APP, |
4232 | CTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS); |
4233 | |
4234 | ctk_target_list_add_rich_text_targets (target_list, |
4235 | CTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT, |
4236 | deserializable, |
4237 | buffer); |
4238 | |
4239 | ctk_target_list_add_text_targets (target_list, |
4240 | CTK_TEXT_BUFFER_TARGET_INFO_TEXT); |
4241 | |
4242 | *entries = ctk_target_table_new_from_list (target_list, n_entries); |
4243 | |
4244 | return target_list; |
4245 | } |
4246 | |
4247 | /** |
4248 | * ctk_text_buffer_get_copy_target_list: |
4249 | * @buffer: a #CtkTextBuffer |
4250 | * |
4251 | * This function returns the list of targets this text buffer can |
4252 | * provide for copying and as DND source. The targets in the list are |
4253 | * added with @info values from the #CtkTextBufferTargetInfo enum, |
4254 | * using ctk_target_list_add_rich_text_targets() and |
4255 | * ctk_target_list_add_text_targets(). |
4256 | * |
4257 | * Returns: (transfer none): the #CtkTargetList |
4258 | * |
4259 | * Since: 2.10 |
4260 | **/ |
4261 | CtkTargetList * |
4262 | ctk_text_buffer_get_copy_target_list (CtkTextBuffer *buffer) |
4263 | { |
4264 | CtkTextBufferPrivate *priv; |
4265 | |
4266 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
4267 | |
4268 | priv = buffer->priv; |
4269 | |
4270 | if (! priv->copy_target_list) |
4271 | priv->copy_target_list = |
4272 | ctk_text_buffer_get_target_list (buffer, FALSE(0), |
4273 | &priv->copy_target_entries, |
4274 | &priv->n_copy_target_entries); |
4275 | |
4276 | return priv->copy_target_list; |
4277 | } |
4278 | |
4279 | /** |
4280 | * ctk_text_buffer_get_paste_target_list: |
4281 | * @buffer: a #CtkTextBuffer |
4282 | * |
4283 | * This function returns the list of targets this text buffer supports |
4284 | * for pasting and as DND destination. The targets in the list are |
4285 | * added with @info values from the #CtkTextBufferTargetInfo enum, |
4286 | * using ctk_target_list_add_rich_text_targets() and |
4287 | * ctk_target_list_add_text_targets(). |
4288 | * |
4289 | * Returns: (transfer none): the #CtkTargetList |
4290 | * |
4291 | * Since: 2.10 |
4292 | **/ |
4293 | CtkTargetList * |
4294 | ctk_text_buffer_get_paste_target_list (CtkTextBuffer *buffer) |
4295 | { |
4296 | CtkTextBufferPrivate *priv; |
4297 | |
4298 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
4299 | |
4300 | priv = buffer->priv; |
4301 | |
4302 | if (! priv->paste_target_list) |
4303 | priv->paste_target_list = |
4304 | ctk_text_buffer_get_target_list (buffer, TRUE(!(0)), |
4305 | &priv->paste_target_entries, |
4306 | &priv->n_paste_target_entries); |
4307 | |
4308 | return priv->paste_target_list; |
4309 | } |
4310 | |
4311 | /* |
4312 | * Logical attribute cache |
4313 | */ |
4314 | |
4315 | #define ATTR_CACHE_SIZE2 2 |
4316 | |
4317 | typedef struct _CacheEntry CacheEntry; |
4318 | struct _CacheEntry |
4319 | { |
4320 | gint line; |
4321 | gint char_len; |
4322 | PangoLogAttr *attrs; |
4323 | }; |
4324 | |
4325 | struct _CtkTextLogAttrCache |
4326 | { |
4327 | gint chars_changed_stamp; |
4328 | CacheEntry entries[ATTR_CACHE_SIZE2]; |
4329 | }; |
4330 | |
4331 | static void |
4332 | free_log_attr_cache (CtkTextLogAttrCache *cache) |
4333 | { |
4334 | gint i; |
4335 | |
4336 | for (i = 0; i < ATTR_CACHE_SIZE2; i++) |
4337 | g_free (cache->entries[i].attrs); |
4338 | |
4339 | g_slice_free (CtkTextLogAttrCache, cache)do { if (1) g_slice_free1 (sizeof (CtkTextLogAttrCache), (cache )); else (void) ((CtkTextLogAttrCache*) 0 == (cache)); } while (0); |
4340 | } |
4341 | |
4342 | static void |
4343 | clear_log_attr_cache (CtkTextLogAttrCache *cache) |
4344 | { |
4345 | gint i; |
4346 | |
4347 | for (i = 0; i < ATTR_CACHE_SIZE2; i++) |
4348 | { |
4349 | g_free (cache->entries[i].attrs); |
4350 | cache->entries[i].attrs = NULL((void*)0); |
4351 | } |
4352 | } |
4353 | |
4354 | static PangoLogAttr* |
4355 | compute_log_attrs (const CtkTextIter *iter, |
4356 | gint *char_lenp) |
4357 | { |
4358 | CtkTextIter start; |
4359 | CtkTextIter end; |
4360 | gchar *paragraph; |
4361 | gint char_len, byte_len; |
4362 | PangoLogAttr *attrs = NULL((void*)0); |
4363 | |
4364 | start = *iter; |
4365 | end = *iter; |
4366 | |
4367 | ctk_text_iter_set_line_offset (&start, 0); |
4368 | ctk_text_iter_forward_line (&end); |
4369 | |
4370 | paragraph = ctk_text_iter_get_slice (&start, &end); |
4371 | char_len = g_utf8_strlen (paragraph, -1); |
4372 | byte_len = strlen (paragraph); |
4373 | |
4374 | if (char_lenp != NULL((void*)0)) |
4375 | *char_lenp = char_len; |
4376 | |
4377 | attrs = g_new (PangoLogAttr, char_len + 1)((PangoLogAttr *) g_malloc_n ((char_len + 1), sizeof (PangoLogAttr ))); |
4378 | |
4379 | /* FIXME we need to follow PangoLayout and allow different language |
4380 | * tags within the paragraph |
4381 | */ |
4382 | pango_get_log_attrs (paragraph, byte_len, -1, |
4383 | ctk_text_iter_get_language (&start), |
4384 | attrs, |
4385 | char_len + 1); |
4386 | |
4387 | g_free (paragraph); |
4388 | |
4389 | return attrs; |
4390 | } |
4391 | |
4392 | /* The return value from this is valid until you call this a second time. |
4393 | * Returns (char_len + 1) PangoLogAttr's, one for each text position. |
4394 | */ |
4395 | const PangoLogAttr * |
4396 | _ctk_text_buffer_get_line_log_attrs (CtkTextBuffer *buffer, |
4397 | const CtkTextIter *anywhere_in_line, |
4398 | gint *char_len) |
4399 | { |
4400 | CtkTextBufferPrivate *priv; |
4401 | gint line; |
4402 | CtkTextLogAttrCache *cache; |
4403 | gint i; |
4404 | |
4405 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return (((void*)0)); } } while (0); |
4406 | g_return_val_if_fail (anywhere_in_line != NULL, NULL)do { if ((anywhere_in_line != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "anywhere_in_line != NULL" ); return (((void*)0)); } } while (0); |
4407 | |
4408 | priv = buffer->priv; |
4409 | |
4410 | /* FIXME we also need to recompute log attrs if the language tag at |
4411 | * the start of a paragraph changes |
4412 | */ |
4413 | |
4414 | if (priv->log_attr_cache == NULL((void*)0)) |
4415 | { |
4416 | priv->log_attr_cache = g_slice_new0 (CtkTextLogAttrCache)((CtkTextLogAttrCache*) g_slice_alloc0 (sizeof (CtkTextLogAttrCache ))); |
4417 | priv->log_attr_cache->chars_changed_stamp = |
4418 | _ctk_text_btree_get_chars_changed_stamp (get_btree (buffer)); |
4419 | } |
4420 | else if (priv->log_attr_cache->chars_changed_stamp != |
4421 | _ctk_text_btree_get_chars_changed_stamp (get_btree (buffer))) |
4422 | { |
4423 | clear_log_attr_cache (priv->log_attr_cache); |
4424 | } |
4425 | |
4426 | cache = priv->log_attr_cache; |
4427 | line = ctk_text_iter_get_line (anywhere_in_line); |
4428 | |
4429 | for (i = 0; i < ATTR_CACHE_SIZE2; i++) |
4430 | { |
4431 | if (cache->entries[i].attrs != NULL((void*)0) && |
4432 | cache->entries[i].line == line) |
4433 | { |
4434 | if (char_len != NULL((void*)0)) |
4435 | *char_len = cache->entries[i].char_len; |
4436 | return cache->entries[i].attrs; |
4437 | } |
4438 | } |
4439 | |
4440 | /* Not in cache; open up the first cache entry */ |
4441 | g_free (cache->entries[ATTR_CACHE_SIZE2-1].attrs); |
4442 | |
4443 | memmove (cache->entries + 1, cache->entries, |
4444 | sizeof (CacheEntry) * (ATTR_CACHE_SIZE2 - 1)); |
4445 | |
4446 | cache->entries[0].line = line; |
4447 | cache->entries[0].attrs = compute_log_attrs (anywhere_in_line, |
4448 | &cache->entries[0].char_len); |
4449 | |
4450 | if (char_len != NULL((void*)0)) |
4451 | *char_len = cache->entries[0].char_len; |
4452 | |
4453 | return cache->entries[0].attrs; |
4454 | } |
4455 | |
4456 | void |
4457 | _ctk_text_buffer_notify_will_remove_tag (CtkTextBuffer *buffer, |
4458 | CtkTextTag *tag) |
4459 | { |
4460 | /* This removes tag from the buffer, but DOESN'T emit the |
4461 | * remove-tag signal, because we can't afford to have user |
4462 | * code messing things up at this point; the tag MUST be removed |
4463 | * entirely. |
4464 | */ |
4465 | if (buffer->priv->btree) |
4466 | _ctk_text_btree_notify_will_remove_tag (buffer->priv->btree, tag); |
4467 | } |
4468 | |
4469 | /* |
4470 | * Debug spew |
4471 | */ |
4472 | |
4473 | void |
4474 | _ctk_text_buffer_spew (CtkTextBuffer *buffer) |
4475 | { |
4476 | _ctk_text_btree_spew (get_btree (buffer)); |
4477 | } |
4478 | |
4479 | void |
4480 | _ctk_text_buffer_get_text_before (CtkTextBuffer *buffer, |
4481 | AtkTextBoundary boundary_type, |
4482 | CtkTextIter *position, |
4483 | CtkTextIter *start, |
4484 | CtkTextIter *end) |
4485 | { |
4486 | gint line_number; |
4487 | |
4488 | *start = *position; |
4489 | *end = *start; |
4490 | |
4491 | switch (boundary_type) |
4492 | { |
4493 | case ATK_TEXT_BOUNDARY_CHAR: |
4494 | ctk_text_iter_backward_char (start); |
4495 | break; |
4496 | |
4497 | case ATK_TEXT_BOUNDARY_WORD_START: |
4498 | if (!ctk_text_iter_starts_word (start)) |
4499 | ctk_text_iter_backward_word_start (start); |
4500 | *end = *start; |
4501 | ctk_text_iter_backward_word_start (start); |
4502 | break; |
4503 | |
4504 | case ATK_TEXT_BOUNDARY_WORD_END: |
4505 | if (ctk_text_iter_inside_word (start) && |
4506 | !ctk_text_iter_starts_word (start)) |
4507 | ctk_text_iter_backward_word_start (start); |
4508 | while (!ctk_text_iter_ends_word (start)) |
4509 | { |
4510 | if (!ctk_text_iter_backward_char (start)) |
4511 | break; |
4512 | } |
4513 | *end = *start; |
4514 | ctk_text_iter_backward_word_start (start); |
4515 | while (!ctk_text_iter_ends_word (start)) |
4516 | { |
4517 | if (!ctk_text_iter_backward_char (start)) |
4518 | break; |
4519 | } |
4520 | break; |
4521 | |
4522 | case ATK_TEXT_BOUNDARY_SENTENCE_START: |
4523 | if (!ctk_text_iter_starts_sentence (start)) |
4524 | ctk_text_iter_backward_sentence_start (start); |
4525 | *end = *start; |
4526 | ctk_text_iter_backward_sentence_start (start); |
4527 | break; |
4528 | |
4529 | case ATK_TEXT_BOUNDARY_SENTENCE_END: |
4530 | if (ctk_text_iter_inside_sentence (start) && |
4531 | !ctk_text_iter_starts_sentence (start)) |
4532 | ctk_text_iter_backward_sentence_start (start); |
4533 | while (!ctk_text_iter_ends_sentence (start)) |
4534 | { |
4535 | if (!ctk_text_iter_backward_char (start)) |
4536 | break; |
4537 | } |
4538 | *end = *start; |
4539 | ctk_text_iter_backward_sentence_start (start); |
4540 | while (!ctk_text_iter_ends_sentence (start)) |
4541 | { |
4542 | if (!ctk_text_iter_backward_char (start)) |
4543 | break; |
4544 | } |
4545 | break; |
4546 | |
4547 | case ATK_TEXT_BOUNDARY_LINE_START: |
4548 | line_number = ctk_text_iter_get_line (start); |
4549 | if (line_number == 0) |
4550 | { |
4551 | ctk_text_buffer_get_iter_at_offset (buffer, start, 0); |
4552 | } |
4553 | else |
4554 | { |
4555 | ctk_text_iter_backward_line (start); |
4556 | ctk_text_iter_forward_line (start); |
4557 | } |
4558 | *end = *start; |
4559 | ctk_text_iter_backward_line (start); |
4560 | break; |
4561 | |
4562 | case ATK_TEXT_BOUNDARY_LINE_END: |
4563 | line_number = ctk_text_iter_get_line (start); |
4564 | if (line_number == 0) |
4565 | { |
4566 | ctk_text_buffer_get_iter_at_offset (buffer, start, 0); |
4567 | *end = *start; |
4568 | } |
4569 | else |
4570 | { |
4571 | ctk_text_iter_backward_line (start); |
4572 | *end = *start; |
4573 | while (!ctk_text_iter_ends_line (start)) |
4574 | { |
4575 | if (!ctk_text_iter_backward_char (start)) |
4576 | break; |
4577 | } |
4578 | ctk_text_iter_forward_to_line_end (end); |
4579 | } |
4580 | break; |
4581 | } |
4582 | } |
4583 | |
4584 | void |
4585 | _ctk_text_buffer_get_text_at (CtkTextBuffer *buffer, |
4586 | AtkTextBoundary boundary_type, |
4587 | CtkTextIter *position, |
4588 | CtkTextIter *start, |
4589 | CtkTextIter *end) |
4590 | { |
4591 | gint line_number; |
4592 | |
4593 | *start = *position; |
4594 | *end = *start; |
4595 | |
4596 | switch (boundary_type) |
4597 | { |
4598 | case ATK_TEXT_BOUNDARY_CHAR: |
4599 | ctk_text_iter_forward_char (end); |
4600 | break; |
4601 | |
4602 | case ATK_TEXT_BOUNDARY_WORD_START: |
4603 | if (!ctk_text_iter_starts_word (start)) |
4604 | ctk_text_iter_backward_word_start (start); |
4605 | if (ctk_text_iter_inside_word (end)) |
4606 | ctk_text_iter_forward_word_end (end); |
4607 | while (!ctk_text_iter_starts_word (end)) |
4608 | { |
4609 | if (!ctk_text_iter_forward_char (end)) |
4610 | break; |
4611 | } |
4612 | break; |
4613 | |
4614 | case ATK_TEXT_BOUNDARY_WORD_END: |
4615 | if (ctk_text_iter_inside_word (start) && |
4616 | !ctk_text_iter_starts_word (start)) |
4617 | ctk_text_iter_backward_word_start (start); |
4618 | while (!ctk_text_iter_ends_word (start)) |
4619 | { |
4620 | if (!ctk_text_iter_backward_char (start)) |
4621 | break; |
4622 | } |
4623 | ctk_text_iter_forward_word_end (end); |
4624 | break; |
4625 | |
4626 | case ATK_TEXT_BOUNDARY_SENTENCE_START: |
4627 | if (!ctk_text_iter_starts_sentence (start)) |
4628 | ctk_text_iter_backward_sentence_start (start); |
4629 | if (ctk_text_iter_inside_sentence (end)) |
4630 | ctk_text_iter_forward_sentence_end (end); |
4631 | while (!ctk_text_iter_starts_sentence (end)) |
4632 | { |
4633 | if (!ctk_text_iter_forward_char (end)) |
4634 | break; |
4635 | } |
4636 | break; |
4637 | |
4638 | case ATK_TEXT_BOUNDARY_SENTENCE_END: |
4639 | if (ctk_text_iter_inside_sentence (start) && |
4640 | !ctk_text_iter_starts_sentence (start)) |
4641 | ctk_text_iter_backward_sentence_start (start); |
4642 | while (!ctk_text_iter_ends_sentence (start)) |
4643 | { |
4644 | if (!ctk_text_iter_backward_char (start)) |
4645 | break; |
4646 | } |
4647 | ctk_text_iter_forward_sentence_end (end); |
4648 | break; |
4649 | |
4650 | case ATK_TEXT_BOUNDARY_LINE_START: |
4651 | line_number = ctk_text_iter_get_line (start); |
4652 | if (line_number == 0) |
4653 | { |
4654 | ctk_text_buffer_get_iter_at_offset (buffer, start, 0); |
4655 | } |
4656 | else |
4657 | { |
4658 | ctk_text_iter_backward_line (start); |
4659 | ctk_text_iter_forward_line (start); |
4660 | } |
4661 | ctk_text_iter_forward_line (end); |
4662 | break; |
4663 | |
4664 | case ATK_TEXT_BOUNDARY_LINE_END: |
4665 | line_number = ctk_text_iter_get_line (start); |
4666 | if (line_number == 0) |
4667 | { |
4668 | ctk_text_buffer_get_iter_at_offset (buffer, start, 0); |
4669 | } |
4670 | else |
4671 | { |
4672 | ctk_text_iter_backward_line (start); |
4673 | ctk_text_iter_forward_line (start); |
4674 | } |
4675 | while (!ctk_text_iter_ends_line (start)) |
4676 | { |
4677 | if (!ctk_text_iter_backward_char (start)) |
4678 | break; |
4679 | } |
4680 | ctk_text_iter_forward_to_line_end (end); |
4681 | break; |
4682 | } |
4683 | } |
4684 | |
4685 | void |
4686 | _ctk_text_buffer_get_text_after (CtkTextBuffer *buffer G_GNUC_UNUSED__attribute__ ((__unused__)), |
4687 | AtkTextBoundary boundary_type, |
4688 | CtkTextIter *position, |
4689 | CtkTextIter *start, |
4690 | CtkTextIter *end) |
4691 | { |
4692 | *start = *position; |
4693 | *end = *start; |
4694 | |
4695 | switch (boundary_type) |
4696 | { |
4697 | case ATK_TEXT_BOUNDARY_CHAR: |
4698 | ctk_text_iter_forward_char (start); |
4699 | ctk_text_iter_forward_chars (end, 2); |
4700 | break; |
4701 | |
4702 | case ATK_TEXT_BOUNDARY_WORD_START: |
4703 | if (ctk_text_iter_inside_word (end)) |
4704 | ctk_text_iter_forward_word_end (end); |
4705 | while (!ctk_text_iter_starts_word (end)) |
4706 | { |
4707 | if (!ctk_text_iter_forward_char (end)) |
4708 | break; |
4709 | } |
4710 | *start = *end; |
4711 | if (!ctk_text_iter_is_end (end)) |
4712 | { |
4713 | ctk_text_iter_forward_word_end (end); |
4714 | while (!ctk_text_iter_starts_word (end)) |
4715 | { |
4716 | if (!ctk_text_iter_forward_char (end)) |
4717 | break; |
4718 | } |
4719 | } |
4720 | break; |
4721 | |
4722 | case ATK_TEXT_BOUNDARY_WORD_END: |
4723 | ctk_text_iter_forward_word_end (end); |
4724 | *start = *end; |
4725 | if (!ctk_text_iter_is_end (end)) |
4726 | ctk_text_iter_forward_word_end (end); |
4727 | break; |
4728 | |
4729 | case ATK_TEXT_BOUNDARY_SENTENCE_START: |
4730 | if (ctk_text_iter_inside_sentence (end)) |
4731 | ctk_text_iter_forward_sentence_end (end); |
4732 | while (!ctk_text_iter_starts_sentence (end)) |
4733 | { |
4734 | if (!ctk_text_iter_forward_char (end)) |
4735 | break; |
4736 | } |
4737 | *start = *end; |
4738 | if (!ctk_text_iter_is_end (end)) |
4739 | { |
4740 | ctk_text_iter_forward_sentence_end (end); |
4741 | while (!ctk_text_iter_starts_sentence (end)) |
4742 | { |
4743 | if (!ctk_text_iter_forward_char (end)) |
4744 | break; |
4745 | } |
4746 | } |
4747 | break; |
4748 | |
4749 | case ATK_TEXT_BOUNDARY_SENTENCE_END: |
4750 | ctk_text_iter_forward_sentence_end (end); |
4751 | *start = *end; |
4752 | if (!ctk_text_iter_is_end (end)) |
4753 | ctk_text_iter_forward_sentence_end (end); |
4754 | break; |
4755 | |
4756 | case ATK_TEXT_BOUNDARY_LINE_START: |
4757 | ctk_text_iter_forward_line (end); |
4758 | *start = *end; |
4759 | ctk_text_iter_forward_line (end); |
4760 | break; |
4761 | |
4762 | case ATK_TEXT_BOUNDARY_LINE_END: |
4763 | ctk_text_iter_forward_line (start); |
4764 | *end = *start; |
4765 | if (!ctk_text_iter_is_end (start)) |
4766 | { |
4767 | while (!ctk_text_iter_ends_line (start)) |
4768 | { |
4769 | if (!ctk_text_iter_backward_char (start)) |
4770 | break; |
4771 | } |
4772 | ctk_text_iter_forward_to_line_end (end); |
4773 | } |
4774 | break; |
4775 | } |
4776 | } |
4777 | |
4778 | static CtkTextTag * |
4779 | get_tag_for_attributes (PangoAttrIterator *iter) |
4780 | { |
4781 | PangoAttribute *attr; |
4782 | CtkTextTag *tag; |
4783 | |
4784 | tag = ctk_text_tag_new (NULL((void*)0)); |
4785 | |
4786 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_LANGUAGE); |
4787 | if (attr) |
4788 | g_object_set (tag, "language", pango_language_to_string (((PangoAttrLanguage*)attr)->value)((const char *)((PangoAttrLanguage*)attr)->value), NULL((void*)0)); |
4789 | |
4790 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_FAMILY); |
4791 | if (attr) |
4792 | g_object_set (tag, "family", ((PangoAttrString*)attr)->value, NULL((void*)0)); |
4793 | |
4794 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_STYLE); |
4795 | if (attr) |
4796 | g_object_set (tag, "style", ((PangoAttrInt*)attr)->value, NULL((void*)0)); |
4797 | |
4798 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_WEIGHT); |
4799 | if (attr) |
4800 | g_object_set (tag, "weight", ((PangoAttrInt*)attr)->value, NULL((void*)0)); |
4801 | |
4802 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_VARIANT); |
4803 | if (attr) |
4804 | g_object_set (tag, "variant", ((PangoAttrInt*)attr)->value, NULL((void*)0)); |
4805 | |
4806 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_STRETCH); |
4807 | if (attr) |
4808 | g_object_set (tag, "stretch", ((PangoAttrInt*)attr)->value, NULL((void*)0)); |
4809 | |
4810 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_SIZE); |
4811 | if (attr) |
4812 | g_object_set (tag, "size", ((PangoAttrInt*)attr)->value, NULL((void*)0)); |
4813 | |
4814 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_FONT_DESC); |
4815 | if (attr) |
4816 | g_object_set (tag, "font-desc", ((PangoAttrFontDesc*)attr)->desc, NULL((void*)0)); |
4817 | |
4818 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND); |
4819 | if (attr) |
4820 | { |
4821 | PangoColor *color; |
4822 | CdkRGBA rgba; |
4823 | |
4824 | color = &((PangoAttrColor*)attr)->color; |
4825 | rgba.red = color->red / 65535.; |
4826 | rgba.green = color->green / 65535.; |
4827 | rgba.blue = color->blue / 65535.; |
4828 | rgba.alpha = 1.; |
4829 | g_object_set (tag, "foreground-rgba", &rgba, NULL((void*)0)); |
4830 | }; |
4831 | |
4832 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_BACKGROUND); |
4833 | if (attr) |
4834 | { |
4835 | PangoColor *color; |
4836 | CdkRGBA rgba; |
4837 | |
4838 | color = &((PangoAttrColor*)attr)->color; |
4839 | rgba.red = color->red / 65535.; |
4840 | rgba.green = color->green / 65535.; |
4841 | rgba.blue = color->blue / 65535.; |
4842 | rgba.alpha = 1.; |
4843 | g_object_set (tag, "background-rgba", &rgba, NULL((void*)0)); |
4844 | }; |
4845 | |
4846 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE); |
4847 | if (attr) |
4848 | g_object_set (tag, "underline", ((PangoAttrInt*)attr)->value, NULL((void*)0)); |
4849 | |
4850 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE_COLOR); |
4851 | if (attr) |
4852 | { |
4853 | PangoColor *color; |
4854 | CdkRGBA rgba; |
4855 | |
4856 | color = &((PangoAttrColor*)attr)->color; |
4857 | rgba.red = color->red / 65535.; |
4858 | rgba.green = color->green / 65535.; |
4859 | rgba.blue = color->blue / 65535.; |
4860 | rgba.alpha = 1.; |
4861 | g_object_set (tag, "underline-rgba", &rgba, NULL((void*)0)); |
4862 | } |
4863 | |
4864 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_STRIKETHROUGH); |
4865 | if (attr) |
4866 | g_object_set (tag, "strikethrough", (gboolean) (((PangoAttrInt*)attr)->value != 0), NULL((void*)0)); |
4867 | |
4868 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_STRIKETHROUGH_COLOR); |
4869 | if (attr) |
4870 | { |
4871 | PangoColor *color; |
4872 | CdkRGBA rgba; |
4873 | |
4874 | color = &((PangoAttrColor*)attr)->color; |
4875 | rgba.red = color->red / 65535.; |
4876 | rgba.green = color->green / 65535.; |
4877 | rgba.blue = color->blue / 65535.; |
4878 | rgba.alpha = 1.; |
4879 | g_object_set (tag, "strikethrough-rgba", &rgba, NULL((void*)0)); |
4880 | } |
4881 | |
4882 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_RISE); |
4883 | if (attr) |
4884 | g_object_set (tag, "rise", ((PangoAttrInt*)attr)->value, NULL((void*)0)); |
4885 | |
4886 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_SCALE); |
4887 | if (attr) |
4888 | g_object_set (tag, "scale", ((PangoAttrFloat*)attr)->value, NULL((void*)0)); |
4889 | |
4890 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_FALLBACK); |
4891 | if (attr) |
4892 | g_object_set (tag, "fallback", (gboolean) (((PangoAttrInt*)attr)->value != 0), NULL((void*)0)); |
4893 | |
4894 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_LETTER_SPACING); |
4895 | if (attr) |
4896 | g_object_set (tag, "letter-spacing", ((PangoAttrInt*)attr)->value, NULL((void*)0)); |
4897 | |
4898 | attr = pango_attr_iterator_get (iter, PANGO_ATTR_FONT_FEATURES); |
4899 | if (attr) |
4900 | g_object_set (tag, "font-features", ((PangoAttrString*)attr)->value, NULL((void*)0)); |
4901 | |
4902 | return tag; |
4903 | } |
4904 | |
4905 | static void |
4906 | ctk_text_buffer_insert_with_attributes (CtkTextBuffer *buffer, |
4907 | CtkTextIter *iter, |
4908 | const gchar *text, |
4909 | PangoAttrList *attributes) |
4910 | { |
4911 | CtkTextMark *mark; |
4912 | PangoAttrIterator *attr; |
4913 | CtkTextTagTable *tags; |
4914 | |
4915 | g_return_if_fail (CTK_IS_TEXT_BUFFER (buffer))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__ )), "CTK_IS_TEXT_BUFFER (buffer)"); return; } } while (0); |
4916 | |
4917 | if (!attributes) |
4918 | { |
4919 | ctk_text_buffer_insert (buffer, iter, text, -1); |
4920 | return; |
4921 | } |
4922 | |
4923 | /* create mark with right gravity */ |
4924 | mark = ctk_text_buffer_create_mark (buffer, NULL((void*)0), iter, FALSE(0)); |
4925 | attr = pango_attr_list_get_iterator (attributes); |
4926 | tags = ctk_text_buffer_get_tag_table (buffer); |
4927 | |
4928 | do |
4929 | { |
4930 | CtkTextTag *tag; |
4931 | gint start, end; |
4932 | |
4933 | pango_attr_iterator_range (attr, &start, &end); |
4934 | |
4935 | if (end == G_MAXINT2147483647) /* last chunk */ |
4936 | end = start - 1; /* resulting in -1 to be passed to _insert */ |
4937 | |
4938 | tag = get_tag_for_attributes (attr); |
4939 | ctk_text_tag_table_add (tags, tag); |
4940 | |
4941 | ctk_text_buffer_insert_with_tags (buffer, iter, text + start, end - start, tag, NULL((void*)0)); |
4942 | |
4943 | ctk_text_buffer_get_iter_at_mark (buffer, iter, mark); |
4944 | } |
4945 | while (pango_attr_iterator_next (attr)); |
4946 | |
4947 | ctk_text_buffer_delete_mark (buffer, mark); |
4948 | pango_attr_iterator_destroy (attr); |
4949 | } |
4950 | |
4951 | /** |
4952 | * ctk_text_buffer_insert_markup: |
4953 | * @buffer: a #CtkTextBuffer |
4954 | * @iter: location to insert the markup |
4955 | * @markup: a nul-terminated UTF-8 string containing [Pango markup][PangoMarkupFormat] |
4956 | * @len: length of @markup in bytes, or -1 |
4957 | * |
4958 | * Inserts the text in @markup at position @iter. @markup will be inserted |
4959 | * in its entirety and must be nul-terminated and valid UTF-8. Emits the |
4960 | * #CtkTextBuffer::insert-text signal, possibly multiple times; insertion |
4961 | * actually occurs in the default handler for the signal. @iter will point |
4962 | * to the end of the inserted text on return. |
4963 | * |
4964 | * Since: 3.16 |
4965 | */ |
4966 | void |
4967 | ctk_text_buffer_insert_markup (CtkTextBuffer *buffer, |
4968 | CtkTextIter *iter, |
4969 | const gchar *markup, |
4970 | gint len) |
4971 | { |
4972 | PangoAttrList *attributes; |
4973 | gchar *text; |
4974 | GError *error = NULL((void*)0); |
4975 | |
4976 | if (!pango_parse_markup (markup, len, 0, &attributes, &text, NULL((void*)0), &error)) |
4977 | { |
4978 | g_warning ("Invalid markup string: %s", error->message); |
4979 | g_error_free (error); |
4980 | return; |
4981 | } |
4982 | |
4983 | ctk_text_buffer_insert_with_attributes (buffer, iter, text, attributes); |
4984 | |
4985 | pango_attr_list_unref (attributes); |
4986 | g_free (text); |
4987 | } |