Bug Summary

File:ctk/ctktextview.c
Warning:line 7844, column 8
2nd function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctktextview.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-172241-43638-1 -x c ctktextview.c
1/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2/* CTK - The GIMP Toolkit
3 * ctktextview.c Copyright (C) 2000 Red Hat, Inc.
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
28#include <string.h>
29
30#define CTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
31#include "ctkadjustmentprivate.h"
32#include "ctkbindings.h"
33#include "ctkdnd.h"
34#include "ctkdebug.h"
35#include "ctkintl.h"
36#include "ctkmain.h"
37#include "ctkmarshalers.h"
38#include "ctkmenu.h"
39#include "ctkmenuitem.h"
40#include "ctkrenderbackgroundprivate.h"
41#include "ctkseparatormenuitem.h"
42#include "ctksettings.h"
43#include "ctkselectionprivate.h"
44#include "ctktextbufferrichtext.h"
45#include "ctktextdisplay.h"
46#include "ctktextview.h"
47#include "ctkimmulticontext.h"
48#include "ctkprivate.h"
49#include "ctktextutil.h"
50#include "ctkwidgetprivate.h"
51#include "ctkwindow.h"
52#include "ctkscrollable.h"
53#include "ctktypebuiltins.h"
54#include "ctktexthandleprivate.h"
55#include "ctkcssstylepropertyprivate.h"
56#include "ctkpopover.h"
57#include "ctktoolbar.h"
58#include "ctkpixelcacheprivate.h"
59#include "ctkmagnifierprivate.h"
60#include "ctkemojichooser.h"
61#include "ctkpango.h"
62
63#include "a11y/ctktextviewaccessibleprivate.h"
64
65/**
66 * SECTION:ctktextview
67 * @Short_description: Widget that displays a CtkTextBuffer
68 * @Title: CtkTextView
69 * @See_also: #CtkTextBuffer, #CtkTextIter
70 *
71 * You may wish to begin by reading the
72 * [text widget conceptual overview][TextWidget]
73 * which gives an overview of all the objects and data
74 * types related to the text widget and how they work together.
75 *
76 * # CSS nodes
77 *
78 * |[<!-- language="plain" -->
79 * textview.view
80 * ├── border.top
81 * ├── border.left
82 * ├── text
83 * │ ╰── [selection]
84 * ├── border.right
85 * ├── border.bottom
86 * ╰── [window.popup]
87 * ]|
88 *
89 * CtkTextView has a main css node with name textview and style class .view,
90 * and subnodes for each of the border windows, and the main text area,
91 * with names border and text, respectively. The border nodes each get
92 * one of the style classes .left, .right, .top or .bottom.
93 *
94 * A node representing the selection will appear below the text node.
95 *
96 * If a context menu is opened, the window node will appear as a subnode
97 * of the main node.
98 */
99
100
101/* How scrolling, validation, exposes, etc. work.
102 *
103 * The expose_event handler has the invariant that the onscreen lines
104 * have been validated.
105 *
106 * There are two ways that onscreen lines can become invalid. The first
107 * is to change which lines are onscreen. This happens when the value
108 * of a scroll adjustment changes. So the code path begins in
109 * ctk_text_view_value_changed() and goes like this:
110 * - cdk_window_scroll() to reflect the new adjustment value
111 * - validate the lines that were moved onscreen
112 * - cdk_window_process_updates() to handle the exposes immediately
113 *
114 * The second way is that you get the “invalidated” signal from the layout,
115 * indicating that lines have become invalid. This code path begins in
116 * invalidated_handler() and goes like this:
117 * - install high-priority idle which does the rest of the steps
118 * - if a scroll is pending from scroll_to_mark(), do the scroll,
119 * jumping to the ctk_text_view_value_changed() code path
120 * - otherwise, validate the onscreen lines
121 * - DO NOT process updates
122 *
123 * In both cases, validating the onscreen lines can trigger a scroll
124 * due to maintaining the first_para on the top of the screen.
125 * If validation triggers a scroll, we jump to the top of the code path
126 * for value_changed, and bail out of the current code path.
127 *
128 * Also, in size_allocate, if we invalidate some lines from changing
129 * the layout width, we need to go ahead and run the high-priority idle,
130 * because CTK sends exposes right after doing the size allocates without
131 * returning to the main loop. This is also why the high-priority idle
132 * is at a higher priority than resizing.
133 *
134 */
135
136#if 0
137#define DEBUG_VALIDATION_AND_SCROLLING
138#endif
139
140#ifdef DEBUG_VALIDATION_AND_SCROLLING
141#define DV(x) (x)
142#else
143#define DV(x)
144#endif
145
146#define SCREEN_WIDTH(widget)text_window_get_width (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_text_view_get_type ())))
)))->priv->text_window)
text_window_get_width (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->priv->text_window)
147#define SCREEN_HEIGHT(widget)text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_text_view_get_type ())))
)))->priv->text_window)
text_window_get_height (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->priv->text_window)
148
149#define SPACE_FOR_CURSOR1 1
150
151#define CTK_TEXT_VIEW_GET_PRIVATE(obj)(((CtkTextViewPrivate*) g_type_instance_get_private ((GTypeInstance
*) ((obj)), ((ctk_text_view_get_type ())))) GCC warning "Deprecated pre-processor symbol: replace with \"G_ADD_PRIVATE\""
)
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CTK_TYPE_TEXT_VIEW, CtkTextViewPrivate)((CtkTextViewPrivate*) g_type_instance_get_private ((GTypeInstance
*) ((obj)), ((ctk_text_view_get_type ())))) GCC warning "Deprecated pre-processor symbol: replace with \"G_ADD_PRIVATE\""
)
152
153typedef struct _CtkTextWindow CtkTextWindow;
154typedef struct _CtkTextPendingScroll CtkTextPendingScroll;
155
156struct _CtkTextViewPrivate
157{
158 CtkTextLayout *layout;
159 CtkTextBuffer *buffer;
160
161 guint blink_time; /* time in msec the cursor has blinked since last user event */
162 guint im_spot_idle;
163 gchar *im_module;
164
165 gint dnd_x;
166 gint dnd_y;
167
168 CtkTextHandle *text_handle;
169 CtkWidget *selection_bubble;
170 guint selection_bubble_timeout_id;
171
172 CtkWidget *magnifier_popover;
173 CtkWidget *magnifier;
174
175 CtkTextWindow *text_window;
176 CtkTextWindow *left_window;
177 CtkTextWindow *right_window;
178 CtkTextWindow *top_window;
179 CtkTextWindow *bottom_window;
180
181 CtkAdjustment *hadjustment;
182 CtkAdjustment *vadjustment;
183
184 /* X offset between widget coordinates and buffer coordinates
185 * taking left_padding in account
186 */
187 gint xoffset;
188
189 /* Y offset between widget coordinates and buffer coordinates
190 * taking top_padding and top_margin in account
191 */
192 gint yoffset;
193
194 /* Width and height of the buffer */
195 gint width;
196 gint height;
197
198 /* This is used to monitor the overall size request
199 * and decide whether we need to queue resizes when
200 * the buffer content changes.
201 *
202 * FIXME: This could be done in a simpler way by
203 * consulting the above width/height of the buffer + some
204 * padding values, however all of this request code needs
205 * to be changed to use CtkWidget Iface and deserves
206 * more attention.
207 */
208 CtkRequisition cached_size_request;
209
210 /* The virtual cursor position is normally the same as the
211 * actual (strong) cursor position, except in two circumstances:
212 *
213 * a) When the cursor is moved vertically with the keyboard
214 * b) When the text view is scrolled with the keyboard
215 *
216 * In case a), virtual_cursor_x is preserved, but not virtual_cursor_y
217 * In case b), both virtual_cursor_x and virtual_cursor_y are preserved.
218 */
219 gint virtual_cursor_x; /* -1 means use actual cursor position */
220 gint virtual_cursor_y; /* -1 means use actual cursor position */
221
222 CtkTextMark *first_para_mark; /* Mark at the beginning of the first onscreen paragraph */
223 gint first_para_pixels; /* Offset of top of screen in the first onscreen paragraph */
224
225 guint blink_timeout;
226 guint scroll_timeout;
227
228 guint first_validate_idle; /* Idle to revalidate onscreen portion, runs before resize */
229 guint incremental_validate_idle; /* Idle to revalidate offscreen portions, runs after redraw */
230
231 CtkTextMark *dnd_mark;
232
233 CtkIMContext *im_context;
234 CtkWidget *popup_menu;
235
236 GSList *children;
237
238 CtkTextPendingScroll *pending_scroll;
239
240 CtkPixelCache *pixel_cache;
241
242 CtkGesture *multipress_gesture;
243 CtkGesture *drag_gesture;
244
245 CtkCssNode *selection_node;
246
247 /* Default style settings */
248 gint pixels_above_lines;
249 gint pixels_below_lines;
250 gint pixels_inside_wrap;
251 CtkWrapMode wrap_mode;
252 CtkJustification justify;
253
254 gint left_margin;
255 gint right_margin;
256 gint top_margin;
257 gint bottom_margin;
258 gint left_padding;
259 gint right_padding;
260 gint top_padding;
261 gint bottom_padding;
262 gint top_border;
263 gint bottom_border;
264 gint left_border;
265 gint right_border;
266
267 gint indent;
268 gint64 handle_place_time;
269 PangoTabArray *tabs;
270 guint editable : 1;
271
272 guint overwrite_mode : 1;
273 guint cursor_visible : 1;
274
275 /* if we have reset the IM since the last character entered */
276 guint need_im_reset : 1;
277
278 guint accepts_tab : 1;
279
280 guint width_changed : 1;
281
282 /* debug flag - means that we've validated onscreen since the
283 * last "invalidate" signal from the layout
284 */
285 guint onscreen_validated : 1;
286
287 guint mouse_cursor_obscured : 1;
288
289 guint scroll_after_paste : 1;
290
291 /* CtkScrollablePolicy needs to be checked when
292 * driving the scrollable adjustment values */
293 guint hscroll_policy : 1;
294 guint vscroll_policy : 1;
295 guint cursor_handle_dragged : 1;
296 guint selection_handle_dragged : 1;
297 guint populate_all : 1;
298
299 guint in_scroll : 1;
300 guint handling_key_event : 1;
301};
302
303struct _CtkTextPendingScroll
304{
305 CtkTextMark *mark;
306 gdouble within_margin;
307 gboolean use_align;
308 gdouble xalign;
309 gdouble yalign;
310};
311
312typedef enum
313{
314 SELECT_CHARACTERS,
315 SELECT_WORDS,
316 SELECT_LINES
317} SelectionGranularity;
318
319enum
320{
321 POPULATE_POPUP,
322 MOVE_CURSOR,
323 PAGE_HORIZONTALLY,
324 SET_ANCHOR,
325 INSERT_AT_CURSOR,
326 DELETE_FROM_CURSOR,
327 BACKSPACE,
328 CUT_CLIPBOARD,
329 COPY_CLIPBOARD,
330 PASTE_CLIPBOARD,
331 TOGGLE_OVERWRITE,
332 MOVE_VIEWPORT,
333 SELECT_ALL,
334 TOGGLE_CURSOR_VISIBLE,
335 PREEDIT_CHANGED,
336 EXTEND_SELECTION,
337 INSERT_EMOJI,
338 LAST_SIGNAL
339};
340
341enum
342{
343 PROP_0,
344 PROP_PIXELS_ABOVE_LINES,
345 PROP_PIXELS_BELOW_LINES,
346 PROP_PIXELS_INSIDE_WRAP,
347 PROP_EDITABLE,
348 PROP_WRAP_MODE,
349 PROP_JUSTIFICATION,
350 PROP_LEFT_MARGIN,
351 PROP_RIGHT_MARGIN,
352 PROP_TOP_MARGIN,
353 PROP_BOTTOM_MARGIN,
354 PROP_INDENT,
355 PROP_TABS,
356 PROP_CURSOR_VISIBLE,
357 PROP_BUFFER,
358 PROP_OVERWRITE,
359 PROP_ACCEPTS_TAB,
360 PROP_IM_MODULE,
361 PROP_HADJUSTMENT,
362 PROP_VADJUSTMENT,
363 PROP_HSCROLL_POLICY,
364 PROP_VSCROLL_POLICY,
365 PROP_INPUT_PURPOSE,
366 PROP_INPUT_HINTS,
367 PROP_POPULATE_ALL,
368 PROP_MONOSPACE
369};
370
371static GQuark quark_text_selection_data = 0;
372static GQuark quark_ctk_signal = 0;
373static GQuark quark_text_view_child = 0;
374
375static void ctk_text_view_finalize (GObject *object);
376static void ctk_text_view_set_property (GObject *object,
377 guint prop_id,
378 const GValue *value,
379 GParamSpec *pspec);
380static void ctk_text_view_get_property (GObject *object,
381 guint prop_id,
382 GValue *value,
383 GParamSpec *pspec);
384static void ctk_text_view_destroy (CtkWidget *widget);
385static void ctk_text_view_size_request (CtkWidget *widget,
386 CtkRequisition *requisition);
387static void ctk_text_view_get_preferred_width (CtkWidget *widget,
388 gint *minimum,
389 gint *natural);
390static void ctk_text_view_get_preferred_height (CtkWidget *widget,
391 gint *minimum,
392 gint *natural);
393static void ctk_text_view_size_allocate (CtkWidget *widget,
394 CtkAllocation *allocation);
395static void ctk_text_view_map (CtkWidget *widget);
396static void ctk_text_view_unmap (CtkWidget *widget);
397static void ctk_text_view_realize (CtkWidget *widget);
398static void ctk_text_view_unrealize (CtkWidget *widget);
399static void ctk_text_view_style_updated (CtkWidget *widget);
400static void ctk_text_view_direction_changed (CtkWidget *widget,
401 CtkTextDirection previous_direction);
402static void ctk_text_view_state_flags_changed (CtkWidget *widget,
403 CtkStateFlags previous_state);
404
405static void ctk_text_view_multipress_gesture_pressed (CtkGestureMultiPress *gesture,
406 gint n_press,
407 gdouble x,
408 gdouble y,
409 CtkTextView *text_view);
410static void ctk_text_view_drag_gesture_update (CtkGestureDrag *gesture,
411 gdouble offset_x,
412 gdouble offset_y,
413 CtkTextView *text_view);
414static void ctk_text_view_drag_gesture_end (CtkGestureDrag *gesture,
415 gdouble offset_x,
416 gdouble offset_y,
417 CtkTextView *text_view);
418
419static gint ctk_text_view_event (CtkWidget *widget,
420 CdkEvent *event);
421static gint ctk_text_view_key_press_event (CtkWidget *widget,
422 CdkEventKey *event);
423static gint ctk_text_view_key_release_event (CtkWidget *widget,
424 CdkEventKey *event);
425static gint ctk_text_view_focus_in_event (CtkWidget *widget,
426 CdkEventFocus *event);
427static gint ctk_text_view_focus_out_event (CtkWidget *widget,
428 CdkEventFocus *event);
429static gint ctk_text_view_motion_event (CtkWidget *widget,
430 CdkEventMotion *event);
431static gint ctk_text_view_draw (CtkWidget *widget,
432 cairo_t *cr);
433static gboolean ctk_text_view_focus (CtkWidget *widget,
434 CtkDirectionType direction);
435static void ctk_text_view_select_all (CtkWidget *widget,
436 gboolean select);
437static gboolean get_middle_click_paste (CtkTextView *text_view);
438
439static CtkTextBuffer* ctk_text_view_create_buffer (CtkTextView *text_view);
440
441/* Source side drag signals */
442static void ctk_text_view_drag_begin (CtkWidget *widget,
443 CdkDragContext *context);
444static void ctk_text_view_drag_end (CtkWidget *widget,
445 CdkDragContext *context);
446static void ctk_text_view_drag_data_get (CtkWidget *widget,
447 CdkDragContext *context,
448 CtkSelectionData *selection_data,
449 guint info,
450 guint time);
451static void ctk_text_view_drag_data_delete (CtkWidget *widget,
452 CdkDragContext *context);
453
454/* Target side drag signals */
455static void ctk_text_view_drag_leave (CtkWidget *widget,
456 CdkDragContext *context,
457 guint time);
458static gboolean ctk_text_view_drag_motion (CtkWidget *widget,
459 CdkDragContext *context,
460 gint x,
461 gint y,
462 guint time);
463static gboolean ctk_text_view_drag_drop (CtkWidget *widget,
464 CdkDragContext *context,
465 gint x,
466 gint y,
467 guint time);
468static void ctk_text_view_drag_data_received (CtkWidget *widget,
469 CdkDragContext *context,
470 gint x,
471 gint y,
472 CtkSelectionData *selection_data,
473 guint info,
474 guint time);
475
476static gboolean ctk_text_view_popup_menu (CtkWidget *widget);
477
478static void ctk_text_view_move_cursor (CtkTextView *text_view,
479 CtkMovementStep step,
480 gint count,
481 gboolean extend_selection);
482static void ctk_text_view_move_viewport (CtkTextView *text_view,
483 CtkScrollStep step,
484 gint count);
485static void ctk_text_view_set_anchor (CtkTextView *text_view);
486static gboolean ctk_text_view_scroll_pages (CtkTextView *text_view,
487 gint count,
488 gboolean extend_selection);
489static gboolean ctk_text_view_scroll_hpages(CtkTextView *text_view,
490 gint count,
491 gboolean extend_selection);
492static void ctk_text_view_insert_at_cursor (CtkTextView *text_view,
493 const gchar *str);
494static void ctk_text_view_delete_from_cursor (CtkTextView *text_view,
495 CtkDeleteType type,
496 gint count);
497static void ctk_text_view_backspace (CtkTextView *text_view);
498static void ctk_text_view_cut_clipboard (CtkTextView *text_view);
499static void ctk_text_view_copy_clipboard (CtkTextView *text_view);
500static void ctk_text_view_paste_clipboard (CtkTextView *text_view);
501static void ctk_text_view_toggle_overwrite (CtkTextView *text_view);
502static void ctk_text_view_toggle_cursor_visible (CtkTextView *text_view);
503
504static void ctk_text_view_unselect (CtkTextView *text_view);
505
506static void ctk_text_view_validate_onscreen (CtkTextView *text_view);
507static void ctk_text_view_get_first_para_iter (CtkTextView *text_view,
508 CtkTextIter *iter);
509static void ctk_text_view_update_layout_width (CtkTextView *text_view);
510static void ctk_text_view_set_attributes_from_style (CtkTextView *text_view,
511 CtkTextAttributes *values);
512static void ctk_text_view_ensure_layout (CtkTextView *text_view);
513static void ctk_text_view_destroy_layout (CtkTextView *text_view);
514static void ctk_text_view_check_keymap_direction (CtkTextView *text_view);
515static void ctk_text_view_start_selection_drag (CtkTextView *text_view,
516 const CtkTextIter *iter,
517 SelectionGranularity granularity,
518 gboolean extends);
519static gboolean ctk_text_view_end_selection_drag (CtkTextView *text_view);
520static void ctk_text_view_start_selection_dnd (CtkTextView *text_view,
521 const CtkTextIter *iter,
522 const CdkEvent *event,
523 gint x,
524 gint y);
525static void ctk_text_view_check_cursor_blink (CtkTextView *text_view);
526static void ctk_text_view_pend_cursor_blink (CtkTextView *text_view);
527static void ctk_text_view_stop_cursor_blink (CtkTextView *text_view);
528static void ctk_text_view_reset_blink_time (CtkTextView *text_view);
529
530static void ctk_text_view_value_changed (CtkAdjustment *adjustment,
531 CtkTextView *view);
532static void ctk_text_view_commit_handler (CtkIMContext *context,
533 const gchar *str,
534 CtkTextView *text_view);
535static void ctk_text_view_commit_text (CtkTextView *text_view,
536 const gchar *text);
537static void ctk_text_view_preedit_changed_handler (CtkIMContext *context,
538 CtkTextView *text_view);
539static gboolean ctk_text_view_retrieve_surrounding_handler (CtkIMContext *context,
540 CtkTextView *text_view);
541static gboolean ctk_text_view_delete_surrounding_handler (CtkIMContext *context,
542 gint offset,
543 gint n_chars,
544 CtkTextView *text_view);
545
546static void ctk_text_view_mark_set_handler (CtkTextBuffer *buffer,
547 const CtkTextIter *location,
548 CtkTextMark *mark,
549 gpointer data);
550static void ctk_text_view_target_list_notify (CtkTextBuffer *buffer,
551 const GParamSpec *pspec,
552 gpointer data);
553static void ctk_text_view_paste_done_handler (CtkTextBuffer *buffer,
554 CtkClipboard *clipboard,
555 gpointer data);
556static void ctk_text_view_buffer_changed_handler (CtkTextBuffer *buffer,
557 gpointer data);
558static void ctk_text_view_get_virtual_cursor_pos (CtkTextView *text_view,
559 CtkTextIter *cursor,
560 gint *x,
561 gint *y);
562static void ctk_text_view_set_virtual_cursor_pos (CtkTextView *text_view,
563 gint x,
564 gint y);
565
566static void ctk_text_view_do_popup (CtkTextView *text_view,
567 const CdkEvent *event);
568
569static void cancel_pending_scroll (CtkTextView *text_view);
570static void ctk_text_view_queue_scroll (CtkTextView *text_view,
571 CtkTextMark *mark,
572 gdouble within_margin,
573 gboolean use_align,
574 gdouble xalign,
575 gdouble yalign);
576
577static gboolean ctk_text_view_flush_scroll (CtkTextView *text_view);
578static void ctk_text_view_update_adjustments (CtkTextView *text_view);
579static void ctk_text_view_invalidate (CtkTextView *text_view);
580static void ctk_text_view_flush_first_validate (CtkTextView *text_view);
581
582static void ctk_text_view_set_hadjustment (CtkTextView *text_view,
583 CtkAdjustment *adjustment);
584static void ctk_text_view_set_vadjustment (CtkTextView *text_view,
585 CtkAdjustment *adjustment);
586static void ctk_text_view_set_hadjustment_values (CtkTextView *text_view);
587static void ctk_text_view_set_vadjustment_values (CtkTextView *text_view);
588
589static void ctk_text_view_update_im_spot_location (CtkTextView *text_view);
590static void ctk_text_view_insert_emoji (CtkTextView *text_view);
591
592/* Container methods */
593static void ctk_text_view_add (CtkContainer *container,
594 CtkWidget *child);
595static void ctk_text_view_remove (CtkContainer *container,
596 CtkWidget *child);
597static void ctk_text_view_forall (CtkContainer *container,
598 gboolean include_internals,
599 CtkCallback callback,
600 gpointer callback_data);
601
602/* CtkTextHandle handlers */
603static void ctk_text_view_handle_drag_started (CtkTextHandle *handle,
604 CtkTextHandlePosition pos,
605 CtkTextView *text_view);
606static void ctk_text_view_handle_dragged (CtkTextHandle *handle,
607 CtkTextHandlePosition pos,
608 gint x,
609 gint y,
610 CtkTextView *text_view);
611static void ctk_text_view_handle_drag_finished (CtkTextHandle *handle,
612 CtkTextHandlePosition pos,
613 CtkTextView *text_view);
614static void ctk_text_view_update_handles (CtkTextView *text_view,
615 CtkTextHandleMode mode);
616
617static void ctk_text_view_selection_bubble_popup_unset (CtkTextView *text_view);
618static void ctk_text_view_selection_bubble_popup_set (CtkTextView *text_view);
619
620static void ctk_text_view_queue_draw_region (CtkWidget *widget,
621 const cairo_region_t *region);
622
623static void ctk_text_view_get_rendered_rect (CtkTextView *text_view,
624 CdkRectangle *rect);
625
626static gboolean ctk_text_view_extend_selection (CtkTextView *text_view,
627 CtkTextExtendSelection granularity,
628 const CtkTextIter *location,
629 CtkTextIter *start,
630 CtkTextIter *end);
631static void extend_selection (CtkTextView *text_view,
632 SelectionGranularity granularity,
633 const CtkTextIter *location,
634 CtkTextIter *start,
635 CtkTextIter *end);
636
637
638
639/* FIXME probably need the focus methods. */
640
641typedef struct _CtkTextViewChild CtkTextViewChild;
642
643struct _CtkTextViewChild
644{
645 CtkWidget *widget;
646
647 CtkTextChildAnchor *anchor;
648
649 gint from_top_of_line;
650 gint from_left_of_buffer;
651
652 /* These are ignored if anchor != NULL */
653 CtkTextWindowType type;
654 gint x;
655 gint y;
656};
657
658static CtkTextViewChild* text_view_child_new_anchored (CtkWidget *child,
659 CtkTextChildAnchor *anchor,
660 CtkTextLayout *layout);
661static CtkTextViewChild* text_view_child_new_window (CtkWidget *child,
662 CtkTextWindowType type,
663 gint x,
664 gint y);
665static void text_view_child_free (CtkTextViewChild *child);
666static void text_view_child_set_parent_window (CtkTextView *text_view,
667 CtkTextViewChild *child);
668
669struct _CtkTextWindow
670{
671 CtkTextWindowType type;
672 CtkWidget *widget;
673 CdkWindow *window;
674 CdkWindow *bin_window;
675 CtkCssNode *css_node;
676 CtkRequisition requisition;
677 CdkRectangle allocation;
678};
679
680static CtkTextWindow *text_window_new (CtkTextWindowType type,
681 CtkWidget *widget,
682 gint width_request,
683 gint height_request);
684static void text_window_free (CtkTextWindow *win);
685static void text_window_realize (CtkTextWindow *win,
686 CtkWidget *widget);
687static void text_window_unrealize (CtkTextWindow *win);
688static void text_window_size_allocate (CtkTextWindow *win,
689 CdkRectangle *rect);
690static void text_window_scroll (CtkTextWindow *win,
691 gint dx,
692 gint dy);
693static void text_window_invalidate_rect (CtkTextWindow *win,
694 CdkRectangle *rect);
695static void text_window_invalidate_cursors (CtkTextWindow *win);
696
697static gint text_window_get_width (CtkTextWindow *win);
698static gint text_window_get_height (CtkTextWindow *win);
699
700
701static guint signals[LAST_SIGNAL] = { 0 };
702
703G_DEFINE_TYPE_WITH_CODE (CtkTextView, ctk_text_view, CTK_TYPE_CONTAINER,static void ctk_text_view_init (CtkTextView *self); static void
ctk_text_view_class_init (CtkTextViewClass *klass); static GType
ctk_text_view_get_type_once (void); static gpointer ctk_text_view_parent_class
= ((void*)0); static gint CtkTextView_private_offset; static
void ctk_text_view_class_intern_init (gpointer klass) { ctk_text_view_parent_class
= g_type_class_peek_parent (klass); if (CtkTextView_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkTextView_private_offset
); ctk_text_view_class_init ((CtkTextViewClass*) klass); } __attribute__
((__unused__)) static inline gpointer ctk_text_view_get_instance_private
(CtkTextView *self) { return (((gpointer) ((guint8*) (self) +
(glong) (CtkTextView_private_offset)))); } GType ctk_text_view_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_view_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_view_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
ctk_container_get_type ()), g_intern_static_string ("CtkTextView"
), sizeof (CtkTextViewClass), (GClassInitFunc)(void (*)(void)
) ctk_text_view_class_intern_init, sizeof (CtkTextView), (GInstanceInitFunc
)(void (*)(void)) ctk_text_view_init, (GTypeFlags) 0); { {{ CtkTextView_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (CtkTextViewPrivate
)); } { const GInterfaceInfo g_implement_interface_info = { (
GInterfaceInitFunc)(void (*)(void)) ((void*)0), ((void*)0), (
(void*)0) }; g_type_add_interface_static (g_define_type_id, (
ctk_scrollable_get_type ()), &g_implement_interface_info)
; };} } return g_define_type_id; }
704 G_ADD_PRIVATE (CtkTextView)static void ctk_text_view_init (CtkTextView *self); static void
ctk_text_view_class_init (CtkTextViewClass *klass); static GType
ctk_text_view_get_type_once (void); static gpointer ctk_text_view_parent_class
= ((void*)0); static gint CtkTextView_private_offset; static
void ctk_text_view_class_intern_init (gpointer klass) { ctk_text_view_parent_class
= g_type_class_peek_parent (klass); if (CtkTextView_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkTextView_private_offset
); ctk_text_view_class_init ((CtkTextViewClass*) klass); } __attribute__
((__unused__)) static inline gpointer ctk_text_view_get_instance_private
(CtkTextView *self) { return (((gpointer) ((guint8*) (self) +
(glong) (CtkTextView_private_offset)))); } GType ctk_text_view_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_view_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_view_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
ctk_container_get_type ()), g_intern_static_string ("CtkTextView"
), sizeof (CtkTextViewClass), (GClassInitFunc)(void (*)(void)
) ctk_text_view_class_intern_init, sizeof (CtkTextView), (GInstanceInitFunc
)(void (*)(void)) ctk_text_view_init, (GTypeFlags) 0); { {{ CtkTextView_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (CtkTextViewPrivate
)); } { const GInterfaceInfo g_implement_interface_info = { (
GInterfaceInitFunc)(void (*)(void)) ((void*)0), ((void*)0), (
(void*)0) }; g_type_add_interface_static (g_define_type_id, (
ctk_scrollable_get_type ()), &g_implement_interface_info)
; };} } return g_define_type_id; }
705 G_IMPLEMENT_INTERFACE (CTK_TYPE_SCROLLABLE, NULL))static void ctk_text_view_init (CtkTextView *self); static void
ctk_text_view_class_init (CtkTextViewClass *klass); static GType
ctk_text_view_get_type_once (void); static gpointer ctk_text_view_parent_class
= ((void*)0); static gint CtkTextView_private_offset; static
void ctk_text_view_class_intern_init (gpointer klass) { ctk_text_view_parent_class
= g_type_class_peek_parent (klass); if (CtkTextView_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkTextView_private_offset
); ctk_text_view_class_init ((CtkTextViewClass*) klass); } __attribute__
((__unused__)) static inline gpointer ctk_text_view_get_instance_private
(CtkTextView *self) { return (((gpointer) ((guint8*) (self) +
(glong) (CtkTextView_private_offset)))); } GType ctk_text_view_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_view_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_view_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
ctk_container_get_type ()), g_intern_static_string ("CtkTextView"
), sizeof (CtkTextViewClass), (GClassInitFunc)(void (*)(void)
) ctk_text_view_class_intern_init, sizeof (CtkTextView), (GInstanceInitFunc
)(void (*)(void)) ctk_text_view_init, (GTypeFlags) 0); { {{ CtkTextView_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (CtkTextViewPrivate
)); } { const GInterfaceInfo g_implement_interface_info = { (
GInterfaceInitFunc)(void (*)(void)) ((void*)0), ((void*)0), (
(void*)0) }; g_type_add_interface_static (g_define_type_id, (
ctk_scrollable_get_type ()), &g_implement_interface_info)
; };} } return g_define_type_id; }
706
707static void
708add_move_binding (CtkBindingSet *binding_set,
709 guint keyval,
710 guint modmask,
711 CtkMovementStep step,
712 gint count)
713{
714 g_assert ((modmask & CDK_SHIFT_MASK) == 0)do { if ((modmask & CDK_SHIFT_MASK) == 0) ; else g_assertion_message_expr
("Ctk", "ctktextview.c", 714, ((const char*) (__func__)), "(modmask & CDK_SHIFT_MASK) == 0"
); } while (0)
;
715
716 ctk_binding_entry_add_signal (binding_set, keyval, modmask,
717 "move-cursor", 3,
718 G_TYPE_ENUM((GType) ((12) << (2))), step,
719 G_TYPE_INT((GType) ((6) << (2))), count,
720 G_TYPE_BOOLEAN((GType) ((5) << (2))), FALSE(0));
721
722 /* Selection-extending version */
723 ctk_binding_entry_add_signal (binding_set, keyval, modmask | CDK_SHIFT_MASK,
724 "move-cursor", 3,
725 G_TYPE_ENUM((GType) ((12) << (2))), step,
726 G_TYPE_INT((GType) ((6) << (2))), count,
727 G_TYPE_BOOLEAN((GType) ((5) << (2))), TRUE(!(0)));
728}
729
730static void
731ctk_text_view_class_init (CtkTextViewClass *klass)
732{
733 GObjectClass *gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
734 CtkWidgetClass *widget_class = CTK_WIDGET_CLASS (klass)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((ctk_widget_get_type ()))))))
;
735 CtkContainerClass *container_class = CTK_CONTAINER_CLASS (klass)((((CtkContainerClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((ctk_container_get_type ()))))))
;
736 CtkBindingSet *binding_set;
737
738 /* Default handlers and virtual methods
739 */
740 gobject_class->set_property = ctk_text_view_set_property;
741 gobject_class->get_property = ctk_text_view_get_property;
742 gobject_class->finalize = ctk_text_view_finalize;
743
744 widget_class->destroy = ctk_text_view_destroy;
745 widget_class->map = ctk_text_view_map;
746 widget_class->unmap = ctk_text_view_unmap;
747 widget_class->realize = ctk_text_view_realize;
748 widget_class->unrealize = ctk_text_view_unrealize;
749 widget_class->style_updated = ctk_text_view_style_updated;
750 widget_class->direction_changed = ctk_text_view_direction_changed;
751 widget_class->state_flags_changed = ctk_text_view_state_flags_changed;
752 widget_class->get_preferred_width = ctk_text_view_get_preferred_width;
753 widget_class->get_preferred_height = ctk_text_view_get_preferred_height;
754 widget_class->size_allocate = ctk_text_view_size_allocate;
755 widget_class->event = ctk_text_view_event;
756 widget_class->key_press_event = ctk_text_view_key_press_event;
757 widget_class->key_release_event = ctk_text_view_key_release_event;
758 widget_class->focus_in_event = ctk_text_view_focus_in_event;
759 widget_class->focus_out_event = ctk_text_view_focus_out_event;
760 widget_class->motion_notify_event = ctk_text_view_motion_event;
761 widget_class->draw = ctk_text_view_draw;
762 widget_class->focus = ctk_text_view_focus;
763 widget_class->drag_begin = ctk_text_view_drag_begin;
764 widget_class->drag_end = ctk_text_view_drag_end;
765 widget_class->drag_data_get = ctk_text_view_drag_data_get;
766 widget_class->drag_data_delete = ctk_text_view_drag_data_delete;
767
768 widget_class->drag_leave = ctk_text_view_drag_leave;
769 widget_class->drag_motion = ctk_text_view_drag_motion;
770 widget_class->drag_drop = ctk_text_view_drag_drop;
771 widget_class->drag_data_received = ctk_text_view_drag_data_received;
772
773 widget_class->popup_menu = ctk_text_view_popup_menu;
774
775 widget_class->queue_draw_region = ctk_text_view_queue_draw_region;
776
777 container_class->add = ctk_text_view_add;
778 container_class->remove = ctk_text_view_remove;
779 container_class->forall = ctk_text_view_forall;
780
781 klass->move_cursor = ctk_text_view_move_cursor;
782 klass->set_anchor = ctk_text_view_set_anchor;
783 klass->insert_at_cursor = ctk_text_view_insert_at_cursor;
784 klass->delete_from_cursor = ctk_text_view_delete_from_cursor;
785 klass->backspace = ctk_text_view_backspace;
786 klass->cut_clipboard = ctk_text_view_cut_clipboard;
787 klass->copy_clipboard = ctk_text_view_copy_clipboard;
788 klass->paste_clipboard = ctk_text_view_paste_clipboard;
789 klass->toggle_overwrite = ctk_text_view_toggle_overwrite;
790 klass->create_buffer = ctk_text_view_create_buffer;
791 klass->extend_selection = ctk_text_view_extend_selection;
792 klass->insert_emoji = ctk_text_view_insert_emoji;
793
794 /*
795 * Properties
796 */
797
798 g_object_class_install_property (gobject_class,
799 PROP_PIXELS_ABOVE_LINES,
800 g_param_spec_int ("pixels-above-lines",
801 P_("Pixels Above Lines")g_dgettext("ctk30" "-properties","Pixels Above Lines"),
802 P_("Pixels of blank space above paragraphs")g_dgettext("ctk30" "-properties","Pixels of blank space above paragraphs"
)
,
803 0, G_MAXINT2147483647, 0,
804 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
805
806 g_object_class_install_property (gobject_class,
807 PROP_PIXELS_BELOW_LINES,
808 g_param_spec_int ("pixels-below-lines",
809 P_("Pixels Below Lines")g_dgettext("ctk30" "-properties","Pixels Below Lines"),
810 P_("Pixels of blank space below paragraphs")g_dgettext("ctk30" "-properties","Pixels of blank space below paragraphs"
)
,
811 0, G_MAXINT2147483647, 0,
812 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
813
814 g_object_class_install_property (gobject_class,
815 PROP_PIXELS_INSIDE_WRAP,
816 g_param_spec_int ("pixels-inside-wrap",
817 P_("Pixels Inside Wrap")g_dgettext("ctk30" "-properties","Pixels Inside Wrap"),
818 P_("Pixels of blank space between wrapped lines in a paragraph")g_dgettext("ctk30" "-properties","Pixels of blank space between wrapped lines in a paragraph"
)
,
819 0, G_MAXINT2147483647, 0,
820 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
821
822 g_object_class_install_property (gobject_class,
823 PROP_EDITABLE,
824 g_param_spec_boolean ("editable",
825 P_("Editable")g_dgettext("ctk30" "-properties","Editable"),
826 P_("Whether the text can be modified by the user")g_dgettext("ctk30" "-properties","Whether the text can be modified by the user"
)
,
827 TRUE(!(0)),
828 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
829
830 g_object_class_install_property (gobject_class,
831 PROP_WRAP_MODE,
832 g_param_spec_enum ("wrap-mode",
833 P_("Wrap Mode")g_dgettext("ctk30" "-properties","Wrap Mode"),
834 P_("Whether to wrap lines never, at word boundaries, or at character boundaries")g_dgettext("ctk30" "-properties","Whether to wrap lines never, at word boundaries, or at character boundaries"
)
,
835 CTK_TYPE_WRAP_MODE(ctk_wrap_mode_get_type ()),
836 CTK_WRAP_NONE,
837 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
838
839 g_object_class_install_property (gobject_class,
840 PROP_JUSTIFICATION,
841 g_param_spec_enum ("justification",
842 P_("Justification")g_dgettext("ctk30" "-properties","Justification"),
843 P_("Left, right, or center justification")g_dgettext("ctk30" "-properties","Left, right, or center justification"
)
,
844 CTK_TYPE_JUSTIFICATION(ctk_justification_get_type ()),
845 CTK_JUSTIFY_LEFT,
846 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
847
848 /**
849 * CtkTextView:left-margin:
850 *
851 * The default left margin for text in the text view.
852 * Tags in the buffer may override the default.
853 *
854 * Note that this property is confusingly named. In CSS terms,
855 * the value set here is padding, and it is applied in addition
856 * to the padding from the theme.
857 *
858 * Don't confuse this property with #CtkWidget:margin-left.
859 */
860 g_object_class_install_property (gobject_class,
861 PROP_LEFT_MARGIN,
862 g_param_spec_int ("left-margin",
863 P_("Left Margin")g_dgettext("ctk30" "-properties","Left Margin"),
864 P_("Width of the left margin in pixels")g_dgettext("ctk30" "-properties","Width of the left margin in pixels"
)
,
865 0, G_MAXINT2147483647, 0,
866 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
867
868 /**
869 * CtkTextView:right-margin:
870 *
871 * The default right margin for text in the text view.
872 * Tags in the buffer may override the default.
873 *
874 * Note that this property is confusingly named. In CSS terms,
875 * the value set here is padding, and it is applied in addition
876 * to the padding from the theme.
877 *
878 * Don't confuse this property with #CtkWidget:margin-right.
879 */
880 g_object_class_install_property (gobject_class,
881 PROP_RIGHT_MARGIN,
882 g_param_spec_int ("right-margin",
883 P_("Right Margin")g_dgettext("ctk30" "-properties","Right Margin"),
884 P_("Width of the right margin in pixels")g_dgettext("ctk30" "-properties","Width of the right margin in pixels"
)
,
885 0, G_MAXINT2147483647, 0,
886 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
887
888 /**
889 * CtkTextView:top-margin:
890 *
891 * The top margin for text in the text view.
892 *
893 * Note that this property is confusingly named. In CSS terms,
894 * the value set here is padding, and it is applied in addition
895 * to the padding from the theme.
896 *
897 * Don't confuse this property with #CtkWidget:margin-top.
898 *
899 * Since: 3.18
900 */
901 g_object_class_install_property (gobject_class,
902 PROP_TOP_MARGIN,
903 g_param_spec_int ("top-margin",
904 P_("Top Margin")g_dgettext("ctk30" "-properties","Top Margin"),
905 P_("Height of the top margin in pixels")g_dgettext("ctk30" "-properties","Height of the top margin in pixels"
)
,
906 0, G_MAXINT2147483647, 0,
907 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
908
909 /**
910 * CtkTextView:bottom-margin:
911 *
912 * The bottom margin for text in the text view.
913 *
914 * Note that this property is confusingly named. In CSS terms,
915 * the value set here is padding, and it is applied in addition
916 * to the padding from the theme.
917 *
918 * Don't confuse this property with #CtkWidget:margin-bottom.
919 *
920 * Since: 3.18
921 */
922 g_object_class_install_property (gobject_class,
923 PROP_BOTTOM_MARGIN,
924 g_param_spec_int ("bottom-margin",
925 P_("Bottom Margin")g_dgettext("ctk30" "-properties","Bottom Margin"),
926 P_("Height of the bottom margin in pixels")g_dgettext("ctk30" "-properties","Height of the bottom margin in pixels"
)
,
927 0, G_MAXINT2147483647, 0,
928 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
929
930 g_object_class_install_property (gobject_class,
931 PROP_INDENT,
932 g_param_spec_int ("indent",
933 P_("Indent")g_dgettext("ctk30" "-properties","Indent"),
934 P_("Amount to indent the paragraph, in pixels")g_dgettext("ctk30" "-properties","Amount to indent the paragraph, in pixels"
)
,
935 G_MININT(-2147483647 -1), G_MAXINT2147483647, 0,
936 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
937
938 g_object_class_install_property (gobject_class,
939 PROP_TABS,
940 g_param_spec_boxed ("tabs",
941 P_("Tabs")g_dgettext("ctk30" "-properties","Tabs"),
942 P_("Custom tabs for this text")g_dgettext("ctk30" "-properties","Custom tabs for this text"),
943 PANGO_TYPE_TAB_ARRAY(pango_tab_array_get_type ()),
944 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
945
946 g_object_class_install_property (gobject_class,
947 PROP_CURSOR_VISIBLE,
948 g_param_spec_boolean ("cursor-visible",
949 P_("Cursor Visible")g_dgettext("ctk30" "-properties","Cursor Visible"),
950 P_("If the insertion cursor is shown")g_dgettext("ctk30" "-properties","If the insertion cursor is shown"
)
,
951 TRUE(!(0)),
952 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
953
954 g_object_class_install_property (gobject_class,
955 PROP_BUFFER,
956 g_param_spec_object ("buffer",
957 P_("Buffer")g_dgettext("ctk30" "-properties","Buffer"),
958 P_("The buffer which is displayed")g_dgettext("ctk30" "-properties","The buffer which is displayed"
)
,
959 CTK_TYPE_TEXT_BUFFER(ctk_text_buffer_get_type ()),
960 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
961
962 g_object_class_install_property (gobject_class,
963 PROP_OVERWRITE,
964 g_param_spec_boolean ("overwrite",
965 P_("Overwrite mode")g_dgettext("ctk30" "-properties","Overwrite mode"),
966 P_("Whether entered text overwrites existing contents")g_dgettext("ctk30" "-properties","Whether entered text overwrites existing contents"
)
,
967 FALSE(0),
968 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
969
970 g_object_class_install_property (gobject_class,
971 PROP_ACCEPTS_TAB,
972 g_param_spec_boolean ("accepts-tab",
973 P_("Accepts tab")g_dgettext("ctk30" "-properties","Accepts tab"),
974 P_("Whether Tab will result in a tab character being entered")g_dgettext("ctk30" "-properties","Whether Tab will result in a tab character being entered"
)
,
975 TRUE(!(0)),
976 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
977
978 /**
979 * CtkTextView:im-module:
980 *
981 * Which IM (input method) module should be used for this text_view.
982 * See #CtkIMContext.
983 *
984 * Setting this to a non-%NULL value overrides the
985 * system-wide IM module setting. See the CtkSettings
986 * #CtkSettings:ctk-im-module property.
987 *
988 * Since: 2.16
989 */
990 g_object_class_install_property (gobject_class,
991 PROP_IM_MODULE,
992 g_param_spec_string ("im-module",
993 P_("IM module")g_dgettext("ctk30" "-properties","IM module"),
994 P_("Which IM module should be used")g_dgettext("ctk30" "-properties","Which IM module should be used"
)
,
995 NULL((void*)0),
996 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
997
998 /**
999 * CtkTextView:input-purpose:
1000 *
1001 * The purpose of this text field.
1002 *
1003 * This property can be used by on-screen keyboards and other input
1004 * methods to adjust their behaviour.
1005 *
1006 * Since: 3.6
1007 */
1008 g_object_class_install_property (gobject_class,
1009 PROP_INPUT_PURPOSE,
1010 g_param_spec_enum ("input-purpose",
1011 P_("Purpose")g_dgettext("ctk30" "-properties","Purpose"),
1012 P_("Purpose of the text field")g_dgettext("ctk30" "-properties","Purpose of the text field"),
1013 CTK_TYPE_INPUT_PURPOSE(ctk_input_purpose_get_type ()),
1014 CTK_INPUT_PURPOSE_FREE_FORM,
1015 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
1016
1017
1018 /**
1019 * CtkTextView:input-hints:
1020 *
1021 * Additional hints (beyond #CtkTextView:input-purpose) that
1022 * allow input methods to fine-tune their behaviour.
1023 *
1024 * Since: 3.6
1025 */
1026 g_object_class_install_property (gobject_class,
1027 PROP_INPUT_HINTS,
1028 g_param_spec_flags ("input-hints",
1029 P_("hints")g_dgettext("ctk30" "-properties","hints"),
1030 P_("Hints for the text field behaviour")g_dgettext("ctk30" "-properties","Hints for the text field behaviour"
)
,
1031 CTK_TYPE_INPUT_HINTS(ctk_input_hints_get_type ()),
1032 CTK_INPUT_HINT_NONE,
1033 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
1034
1035 /**
1036 * CtkTextView:populate-all:
1037 *
1038 * If :populate-all is %TRUE, the #CtkTextView::populate-popup
1039 * signal is also emitted for touch popups.
1040 *
1041 * Since: 3.8
1042 */
1043 g_object_class_install_property (gobject_class,
1044 PROP_POPULATE_ALL,
1045 g_param_spec_boolean ("populate-all",
1046 P_("Populate all")g_dgettext("ctk30" "-properties","Populate all"),
1047 P_("Whether to emit ::populate-popup for touch popups")g_dgettext("ctk30" "-properties","Whether to emit ::populate-popup for touch popups"
)
,
1048 FALSE(0),
1049 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
1050
1051 /**
1052 * CtkTextview:monospace:
1053 *
1054 * If %TRUE, set the %CTK_STYLE_CLASS_MONOSPACE style class on the
1055 * text view to indicate that a monospace font is desired.
1056 *
1057 * Since: 3.16
1058 */
1059 g_object_class_install_property (gobject_class,
1060 PROP_MONOSPACE,
1061 g_param_spec_boolean ("monospace",
1062 P_("Monospace")g_dgettext("ctk30" "-properties","Monospace"),
1063 P_("Whether to use a monospace font")g_dgettext("ctk30" "-properties","Whether to use a monospace font"
)
,
1064 FALSE(0),
1065 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB|G_PARAM_EXPLICIT_NOTIFY));
1066
1067
1068
1069 /* CtkScrollable interface */
1070 g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment");
1071 g_object_class_override_property (gobject_class, PROP_VADJUSTMENT, "vadjustment");
1072 g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
1073 g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");
1074
1075 /*
1076 * Style properties
1077 */
1078 ctk_widget_class_install_style_property (widget_class,
1079 g_param_spec_boxed ("error-underline-color",
1080 P_("Error underline color")g_dgettext("ctk30" "-properties","Error underline color"),
1081 P_("Color with which to draw error-indication underlines")g_dgettext("ctk30" "-properties","Color with which to draw error-indication underlines"
)
,
1082 CDK_TYPE_COLOR(cdk_color_get_type ()),
1083 CTK_PARAM_READABLEG_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
1084
1085 /*
1086 * Signals
1087 */
1088
1089 /**
1090 * CtkTextView::move-cursor:
1091 * @text_view: the object which received the signal
1092 * @step: the granularity of the move, as a #CtkMovementStep
1093 * @count: the number of @step units to move
1094 * @extend_selection: %TRUE if the move should extend the selection
1095 *
1096 * The ::move-cursor signal is a
1097 * [keybinding signal][CtkBindingSignal]
1098 * which gets emitted when the user initiates a cursor movement.
1099 * If the cursor is not visible in @text_view, this signal causes
1100 * the viewport to be moved instead.
1101 *
1102 * Applications should not connect to it, but may emit it with
1103 * g_signal_emit_by_name() if they need to control the cursor
1104 * programmatically.
1105 *
1106 * The default bindings for this signal come in two variants,
1107 * the variant with the Shift modifier extends the selection,
1108 * the variant without the Shift modifer does not.
1109 * There are too many key combinations to list them all here.
1110 * - Arrow keys move by individual characters/lines
1111 * - Ctrl-arrow key combinations move by words/paragraphs
1112 * - Home/End keys move to the ends of the buffer
1113 * - PageUp/PageDown keys move vertically by pages
1114 * - Ctrl-PageUp/PageDown keys move horizontally by pages
1115 */
1116 signals[MOVE_CURSOR] =
1117 g_signal_new (I_("move-cursor")g_intern_static_string ("move-cursor"),
1118 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1119 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1120 G_STRUCT_OFFSET (CtkTextViewClass, move_cursor)((glong) __builtin_offsetof(CtkTextViewClass, move_cursor)),
1121 NULL((void*)0), NULL((void*)0),
1122 _ctk_marshal_VOID__ENUM_INT_BOOLEAN,
1123 G_TYPE_NONE((GType) ((1) << (2))), 3,
1124 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()),
1125 G_TYPE_INT((GType) ((6) << (2))),
1126 G_TYPE_BOOLEAN((GType) ((5) << (2))));
1127 g_signal_set_va_marshaller (signals[MOVE_CURSOR],
1128 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1129 _ctk_marshal_VOID__ENUM_INT_BOOLEANv);
1130
1131 /**
1132 * CtkTextView::move-viewport:
1133 * @text_view: the object which received the signal
1134 * @step: the granularity of the movement, as a #CtkScrollStep
1135 * @count: the number of @step units to move
1136 *
1137 * The ::move-viewport signal is a
1138 * [keybinding signal][CtkBindingSignal]
1139 * which can be bound to key combinations to allow the user
1140 * to move the viewport, i.e. change what part of the text view
1141 * is visible in a containing scrolled window.
1142 *
1143 * There are no default bindings for this signal.
1144 */
1145 signals[MOVE_VIEWPORT] =
1146 g_signal_new_class_handler (I_("move-viewport")g_intern_static_string ("move-viewport"),
1147 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1148 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1149 G_CALLBACK (ctk_text_view_move_viewport)((GCallback) (ctk_text_view_move_viewport)),
1150 NULL((void*)0), NULL((void*)0),
1151 _ctk_marshal_VOID__ENUM_INT,
1152 G_TYPE_NONE((GType) ((1) << (2))), 2,
1153 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()),
1154 G_TYPE_INT((GType) ((6) << (2))));
1155 g_signal_set_va_marshaller (signals[MOVE_VIEWPORT],
1156 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1157 _ctk_marshal_VOID__ENUM_INTv);
1158
1159 /**
1160 * CtkTextView::set-anchor:
1161 * @text_view: the object which received the signal
1162 *
1163 * The ::set-anchor signal is a
1164 * [keybinding signal][CtkBindingSignal]
1165 * which gets emitted when the user initiates setting the "anchor"
1166 * mark. The "anchor" mark gets placed at the same position as the
1167 * "insert" mark.
1168 *
1169 * This signal has no default bindings.
1170 */
1171 signals[SET_ANCHOR] =
1172 g_signal_new (I_("set-anchor")g_intern_static_string ("set-anchor"),
1173 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1174 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1175 G_STRUCT_OFFSET (CtkTextViewClass, set_anchor)((glong) __builtin_offsetof(CtkTextViewClass, set_anchor)),
1176 NULL((void*)0), NULL((void*)0),
1177 NULL((void*)0),
1178 G_TYPE_NONE((GType) ((1) << (2))), 0);
1179
1180 /**
1181 * CtkTextView::insert-at-cursor:
1182 * @text_view: the object which received the signal
1183 * @string: the string to insert
1184 *
1185 * The ::insert-at-cursor signal is a
1186 * [keybinding signal][CtkBindingSignal]
1187 * which gets emitted when the user initiates the insertion of a
1188 * fixed string at the cursor.
1189 *
1190 * This signal has no default bindings.
1191 */
1192 signals[INSERT_AT_CURSOR] =
1193 g_signal_new (I_("insert-at-cursor")g_intern_static_string ("insert-at-cursor"),
1194 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1195 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1196 G_STRUCT_OFFSET (CtkTextViewClass, insert_at_cursor)((glong) __builtin_offsetof(CtkTextViewClass, insert_at_cursor
))
,
1197 NULL((void*)0), NULL((void*)0),
1198 NULL((void*)0),
1199 G_TYPE_NONE((GType) ((1) << (2))), 1,
1200 G_TYPE_STRING((GType) ((16) << (2))));
1201
1202 /**
1203 * CtkTextView::delete-from-cursor:
1204 * @text_view: the object which received the signal
1205 * @type: the granularity of the deletion, as a #CtkDeleteType
1206 * @count: the number of @type units to delete
1207 *
1208 * The ::delete-from-cursor signal is a
1209 * [keybinding signal][CtkBindingSignal]
1210 * which gets emitted when the user initiates a text deletion.
1211 *
1212 * If the @type is %CTK_DELETE_CHARS, CTK+ deletes the selection
1213 * if there is one, otherwise it deletes the requested number
1214 * of characters.
1215 *
1216 * The default bindings for this signal are
1217 * Delete for deleting a character, Ctrl-Delete for
1218 * deleting a word and Ctrl-Backspace for deleting a word
1219 * backwords.
1220 */
1221 signals[DELETE_FROM_CURSOR] =
1222 g_signal_new (I_("delete-from-cursor")g_intern_static_string ("delete-from-cursor"),
1223 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1224 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1225 G_STRUCT_OFFSET (CtkTextViewClass, delete_from_cursor)((glong) __builtin_offsetof(CtkTextViewClass, delete_from_cursor
))
,
1226 NULL((void*)0), NULL((void*)0),
1227 _ctk_marshal_VOID__ENUM_INT,
1228 G_TYPE_NONE((GType) ((1) << (2))), 2,
1229 CTK_TYPE_DELETE_TYPE(ctk_delete_type_get_type ()),
1230 G_TYPE_INT((GType) ((6) << (2))));
1231 g_signal_set_va_marshaller (signals[DELETE_FROM_CURSOR],
1232 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1233 _ctk_marshal_VOID__ENUM_INTv);
1234
1235 /**
1236 * CtkTextView::backspace:
1237 * @text_view: the object which received the signal
1238 *
1239 * The ::backspace signal is a
1240 * [keybinding signal][CtkBindingSignal]
1241 * which gets emitted when the user asks for it.
1242 *
1243 * The default bindings for this signal are
1244 * Backspace and Shift-Backspace.
1245 */
1246 signals[BACKSPACE] =
1247 g_signal_new (I_("backspace")g_intern_static_string ("backspace"),
1248 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1249 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1250 G_STRUCT_OFFSET (CtkTextViewClass, backspace)((glong) __builtin_offsetof(CtkTextViewClass, backspace)),
1251 NULL((void*)0), NULL((void*)0),
1252 NULL((void*)0),
1253 G_TYPE_NONE((GType) ((1) << (2))), 0);
1254
1255 /**
1256 * CtkTextView::cut-clipboard:
1257 * @text_view: the object which received the signal
1258 *
1259 * The ::cut-clipboard signal is a
1260 * [keybinding signal][CtkBindingSignal]
1261 * which gets emitted to cut the selection to the clipboard.
1262 *
1263 * The default bindings for this signal are
1264 * Ctrl-x and Shift-Delete.
1265 */
1266 signals[CUT_CLIPBOARD] =
1267 g_signal_new (I_("cut-clipboard")g_intern_static_string ("cut-clipboard"),
1268 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1269 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1270 G_STRUCT_OFFSET (CtkTextViewClass, cut_clipboard)((glong) __builtin_offsetof(CtkTextViewClass, cut_clipboard)),
1271 NULL((void*)0), NULL((void*)0),
1272 NULL((void*)0),
1273 G_TYPE_NONE((GType) ((1) << (2))), 0);
1274
1275 /**
1276 * CtkTextView::copy-clipboard:
1277 * @text_view: the object which received the signal
1278 *
1279 * The ::copy-clipboard signal is a
1280 * [keybinding signal][CtkBindingSignal]
1281 * which gets emitted to copy the selection to the clipboard.
1282 *
1283 * The default bindings for this signal are
1284 * Ctrl-c and Ctrl-Insert.
1285 */
1286 signals[COPY_CLIPBOARD] =
1287 g_signal_new (I_("copy-clipboard")g_intern_static_string ("copy-clipboard"),
1288 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1289 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1290 G_STRUCT_OFFSET (CtkTextViewClass, copy_clipboard)((glong) __builtin_offsetof(CtkTextViewClass, copy_clipboard)
)
,
1291 NULL((void*)0), NULL((void*)0),
1292 NULL((void*)0),
1293 G_TYPE_NONE((GType) ((1) << (2))), 0);
1294
1295 /**
1296 * CtkTextView::paste-clipboard:
1297 * @text_view: the object which received the signal
1298 *
1299 * The ::paste-clipboard signal is a
1300 * [keybinding signal][CtkBindingSignal]
1301 * which gets emitted to paste the contents of the clipboard
1302 * into the text view.
1303 *
1304 * The default bindings for this signal are
1305 * Ctrl-v and Shift-Insert.
1306 */
1307 signals[PASTE_CLIPBOARD] =
1308 g_signal_new (I_("paste-clipboard")g_intern_static_string ("paste-clipboard"),
1309 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1310 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1311 G_STRUCT_OFFSET (CtkTextViewClass, paste_clipboard)((glong) __builtin_offsetof(CtkTextViewClass, paste_clipboard
))
,
1312 NULL((void*)0), NULL((void*)0),
1313 NULL((void*)0),
1314 G_TYPE_NONE((GType) ((1) << (2))), 0);
1315
1316 /**
1317 * CtkTextView::toggle-overwrite:
1318 * @text_view: the object which received the signal
1319 *
1320 * The ::toggle-overwrite signal is a
1321 * [keybinding signal][CtkBindingSignal]
1322 * which gets emitted to toggle the overwrite mode of the text view.
1323 *
1324 * The default bindings for this signal is Insert.
1325 */
1326 signals[TOGGLE_OVERWRITE] =
1327 g_signal_new (I_("toggle-overwrite")g_intern_static_string ("toggle-overwrite"),
1328 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1329 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1330 G_STRUCT_OFFSET (CtkTextViewClass, toggle_overwrite)((glong) __builtin_offsetof(CtkTextViewClass, toggle_overwrite
))
,
1331 NULL((void*)0), NULL((void*)0),
1332 NULL((void*)0),
1333 G_TYPE_NONE((GType) ((1) << (2))), 0);
1334
1335 /**
1336 * CtkTextView::populate-popup:
1337 * @text_view: The text view on which the signal is emitted
1338 * @popup: the container that is being populated
1339 *
1340 * The ::populate-popup signal gets emitted before showing the
1341 * context menu of the text view.
1342 *
1343 * If you need to add items to the context menu, connect
1344 * to this signal and append your items to the @popup, which
1345 * will be a #CtkMenu in this case.
1346 *
1347 * If #CtkTextView:populate-all is %TRUE, this signal will
1348 * also be emitted to populate touch popups. In this case,
1349 * @popup will be a different container, e.g. a #CtkToolbar.
1350 *
1351 * The signal handler should not make assumptions about the
1352 * type of @widget, but check whether @popup is a #CtkMenu
1353 * or #CtkToolbar or another kind of container.
1354 */
1355 signals[POPULATE_POPUP] =
1356 g_signal_new (I_("populate-popup")g_intern_static_string ("populate-popup"),
1357 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1358 G_SIGNAL_RUN_LAST,
1359 G_STRUCT_OFFSET (CtkTextViewClass, populate_popup)((glong) __builtin_offsetof(CtkTextViewClass, populate_popup)
)
,
1360 NULL((void*)0), NULL((void*)0),
1361 NULL((void*)0),
1362 G_TYPE_NONE((GType) ((1) << (2))), 1,
1363 CTK_TYPE_WIDGET(ctk_widget_get_type ()));
1364
1365 /**
1366 * CtkTextView::select-all:
1367 * @text_view: the object which received the signal
1368 * @select: %TRUE to select, %FALSE to unselect
1369 *
1370 * The ::select-all signal is a
1371 * [keybinding signal][CtkBindingSignal]
1372 * which gets emitted to select or unselect the complete
1373 * contents of the text view.
1374 *
1375 * The default bindings for this signal are Ctrl-a and Ctrl-/
1376 * for selecting and Shift-Ctrl-a and Ctrl-\ for unselecting.
1377 */
1378 signals[SELECT_ALL] =
1379 g_signal_new_class_handler (I_("select-all")g_intern_static_string ("select-all"),
1380 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1381 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1382 G_CALLBACK (ctk_text_view_select_all)((GCallback) (ctk_text_view_select_all)),
1383 NULL((void*)0), NULL((void*)0),
1384 NULL((void*)0),
1385 G_TYPE_NONE((GType) ((1) << (2))), 1, G_TYPE_BOOLEAN((GType) ((5) << (2))));
1386
1387 /**
1388 * CtkTextView::toggle-cursor-visible:
1389 * @text_view: the object which received the signal
1390 *
1391 * The ::toggle-cursor-visible signal is a
1392 * [keybinding signal][CtkBindingSignal]
1393 * which gets emitted to toggle the #CtkTextView:cursor-visible
1394 * property.
1395 *
1396 * The default binding for this signal is F7.
1397 */
1398 signals[TOGGLE_CURSOR_VISIBLE] =
1399 g_signal_new_class_handler (I_("toggle-cursor-visible")g_intern_static_string ("toggle-cursor-visible"),
1400 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1401 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1402 G_CALLBACK (ctk_text_view_toggle_cursor_visible)((GCallback) (ctk_text_view_toggle_cursor_visible)),
1403 NULL((void*)0), NULL((void*)0),
1404 NULL((void*)0),
1405 G_TYPE_NONE((GType) ((1) << (2))), 0);
1406
1407 /**
1408 * CtkTextView::preedit-changed:
1409 * @text_view: the object which received the signal
1410 * @preedit: the current preedit string
1411 *
1412 * If an input method is used, the typed text will not immediately
1413 * be committed to the buffer. So if you are interested in the text,
1414 * connect to this signal.
1415 *
1416 * This signal is only emitted if the text at the given position
1417 * is actually editable.
1418 *
1419 * Since: 2.20
1420 */
1421 signals[PREEDIT_CHANGED] =
1422 g_signal_new_class_handler (I_("preedit-changed")g_intern_static_string ("preedit-changed"),
1423 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1424 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1425 NULL((void*)0),
1426 NULL((void*)0), NULL((void*)0),
1427 NULL((void*)0),
1428 G_TYPE_NONE((GType) ((1) << (2))), 1,
1429 G_TYPE_STRING((GType) ((16) << (2))));
1430
1431 /**
1432 * CtkTextView::extend-selection:
1433 * @text_view: the object which received the signal
1434 * @granularity: the granularity type
1435 * @location: the location where to extend the selection
1436 * @start: where the selection should start
1437 * @end: where the selection should end
1438 *
1439 * The ::extend-selection signal is emitted when the selection needs to be
1440 * extended at @location.
1441 *
1442 * Returns: %CDK_EVENT_STOP to stop other handlers from being invoked for the
1443 * event. %CDK_EVENT_PROPAGATE to propagate the event further.
1444 * Since: 3.16
1445 */
1446 signals[EXTEND_SELECTION] =
1447 g_signal_new (I_("extend-selection")g_intern_static_string ("extend-selection"),
1448 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1449 G_SIGNAL_RUN_LAST,
1450 G_STRUCT_OFFSET (CtkTextViewClass, extend_selection)((glong) __builtin_offsetof(CtkTextViewClass, extend_selection
))
,
1451 _ctk_boolean_handled_accumulator, NULL((void*)0),
1452 _ctk_marshal_BOOLEAN__ENUM_BOXED_BOXED_BOXED,
1453 G_TYPE_BOOLEAN((GType) ((5) << (2))), 4,
1454 CTK_TYPE_TEXT_EXTEND_SELECTION(ctk_text_extend_selection_get_type ()),
1455 CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()) | G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))),
1456 CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()) | G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))),
1457 CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()) | G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))));
1458 g_signal_set_va_marshaller (signals[EXTEND_SELECTION],
1459 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
1460 _ctk_marshal_BOOLEAN__ENUM_BOXED_BOXED_BOXEDv);
1461
1462 /**
1463 * CtkTextView::insert-emoji:
1464 * @text_view: the object which received the signal
1465 *
1466 * The ::insert-emoji signal is a
1467 * [keybinding signal][CtkBindingSignal]
1468 * which gets emitted to present the Emoji chooser for the @text_view.
1469 *
1470 * The default bindings for this signal are Ctrl-. and Ctrl-;
1471 *
1472 * Since: 3.22.27
1473 */
1474 signals[INSERT_EMOJI] =
1475 g_signal_new (I_("insert-emoji")g_intern_static_string ("insert-emoji"),
1476 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
1477 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1478 G_STRUCT_OFFSET (CtkTextViewClass, insert_emoji)((glong) __builtin_offsetof(CtkTextViewClass, insert_emoji)),
1479 NULL((void*)0), NULL((void*)0),
1480 NULL((void*)0),
1481 G_TYPE_NONE((GType) ((1) << (2))), 0);
1482
1483 /*
1484 * Key bindings
1485 */
1486
1487 binding_set = ctk_binding_set_by_class (klass);
1488
1489 /* Moving the insertion point */
1490 add_move_binding (binding_set, CDK_KEY_Right0xff53, 0,
1491 CTK_MOVEMENT_VISUAL_POSITIONS, 1);
1492
1493 add_move_binding (binding_set, CDK_KEY_KP_Right0xff98, 0,
1494 CTK_MOVEMENT_VISUAL_POSITIONS, 1);
1495
1496 add_move_binding (binding_set, CDK_KEY_Left0xff51, 0,
1497 CTK_MOVEMENT_VISUAL_POSITIONS, -1);
1498
1499 add_move_binding (binding_set, CDK_KEY_KP_Left0xff96, 0,
1500 CTK_MOVEMENT_VISUAL_POSITIONS, -1);
1501
1502 add_move_binding (binding_set, CDK_KEY_Right0xff53, CDK_CONTROL_MASK,
1503 CTK_MOVEMENT_WORDS, 1);
1504
1505 add_move_binding (binding_set, CDK_KEY_KP_Right0xff98, CDK_CONTROL_MASK,
1506 CTK_MOVEMENT_WORDS, 1);
1507
1508 add_move_binding (binding_set, CDK_KEY_Left0xff51, CDK_CONTROL_MASK,
1509 CTK_MOVEMENT_WORDS, -1);
1510
1511 add_move_binding (binding_set, CDK_KEY_KP_Left0xff96, CDK_CONTROL_MASK,
1512 CTK_MOVEMENT_WORDS, -1);
1513
1514 add_move_binding (binding_set, CDK_KEY_Up0xff52, 0,
1515 CTK_MOVEMENT_DISPLAY_LINES, -1);
1516
1517 add_move_binding (binding_set, CDK_KEY_KP_Up0xff97, 0,
1518 CTK_MOVEMENT_DISPLAY_LINES, -1);
1519
1520 add_move_binding (binding_set, CDK_KEY_Down0xff54, 0,
1521 CTK_MOVEMENT_DISPLAY_LINES, 1);
1522
1523 add_move_binding (binding_set, CDK_KEY_KP_Down0xff99, 0,
1524 CTK_MOVEMENT_DISPLAY_LINES, 1);
1525
1526 add_move_binding (binding_set, CDK_KEY_Up0xff52, CDK_CONTROL_MASK,
1527 CTK_MOVEMENT_PARAGRAPHS, -1);
1528
1529 add_move_binding (binding_set, CDK_KEY_KP_Up0xff97, CDK_CONTROL_MASK,
1530 CTK_MOVEMENT_PARAGRAPHS, -1);
1531
1532 add_move_binding (binding_set, CDK_KEY_Down0xff54, CDK_CONTROL_MASK,
1533 CTK_MOVEMENT_PARAGRAPHS, 1);
1534
1535 add_move_binding (binding_set, CDK_KEY_KP_Down0xff99, CDK_CONTROL_MASK,
1536 CTK_MOVEMENT_PARAGRAPHS, 1);
1537
1538 add_move_binding (binding_set, CDK_KEY_Home0xff50, 0,
1539 CTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1540
1541 add_move_binding (binding_set, CDK_KEY_KP_Home0xff95, 0,
1542 CTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1543
1544 add_move_binding (binding_set, CDK_KEY_End0xff57, 0,
1545 CTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1546
1547 add_move_binding (binding_set, CDK_KEY_KP_End0xff9c, 0,
1548 CTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1549
1550 add_move_binding (binding_set, CDK_KEY_Home0xff50, CDK_CONTROL_MASK,
1551 CTK_MOVEMENT_BUFFER_ENDS, -1);
1552
1553 add_move_binding (binding_set, CDK_KEY_KP_Home0xff95, CDK_CONTROL_MASK,
1554 CTK_MOVEMENT_BUFFER_ENDS, -1);
1555
1556 add_move_binding (binding_set, CDK_KEY_End0xff57, CDK_CONTROL_MASK,
1557 CTK_MOVEMENT_BUFFER_ENDS, 1);
1558
1559 add_move_binding (binding_set, CDK_KEY_KP_End0xff9c, CDK_CONTROL_MASK,
1560 CTK_MOVEMENT_BUFFER_ENDS, 1);
1561
1562 add_move_binding (binding_set, CDK_KEY_Page_Up0xff55, 0,
1563 CTK_MOVEMENT_PAGES, -1);
1564
1565 add_move_binding (binding_set, CDK_KEY_KP_Page_Up0xff9a, 0,
1566 CTK_MOVEMENT_PAGES, -1);
1567
1568 add_move_binding (binding_set, CDK_KEY_Page_Down0xff56, 0,
1569 CTK_MOVEMENT_PAGES, 1);
1570
1571 add_move_binding (binding_set, CDK_KEY_KP_Page_Down0xff9b, 0,
1572 CTK_MOVEMENT_PAGES, 1);
1573
1574 add_move_binding (binding_set, CDK_KEY_Page_Up0xff55, CDK_CONTROL_MASK,
1575 CTK_MOVEMENT_HORIZONTAL_PAGES, -1);
1576
1577 add_move_binding (binding_set, CDK_KEY_KP_Page_Up0xff9a, CDK_CONTROL_MASK,
1578 CTK_MOVEMENT_HORIZONTAL_PAGES, -1);
1579
1580 add_move_binding (binding_set, CDK_KEY_Page_Down0xff56, CDK_CONTROL_MASK,
1581 CTK_MOVEMENT_HORIZONTAL_PAGES, 1);
1582
1583 add_move_binding (binding_set, CDK_KEY_KP_Page_Down0xff9b, CDK_CONTROL_MASK,
1584 CTK_MOVEMENT_HORIZONTAL_PAGES, 1);
1585
1586 /* Select all */
1587 ctk_binding_entry_add_signal (binding_set, CDK_KEY_a0x061, CDK_CONTROL_MASK,
1588 "select-all", 1,
1589 G_TYPE_BOOLEAN((GType) ((5) << (2))), TRUE(!(0)));
1590
1591 ctk_binding_entry_add_signal (binding_set, CDK_KEY_slash0x02f, CDK_CONTROL_MASK,
1592 "select-all", 1,
1593 G_TYPE_BOOLEAN((GType) ((5) << (2))), TRUE(!(0)));
1594
1595 /* Unselect all */
1596 ctk_binding_entry_add_signal (binding_set, CDK_KEY_backslash0x05c, CDK_CONTROL_MASK,
1597 "select-all", 1,
1598 G_TYPE_BOOLEAN((GType) ((5) << (2))), FALSE(0));
1599
1600 ctk_binding_entry_add_signal (binding_set, CDK_KEY_a0x061, CDK_SHIFT_MASK | CDK_CONTROL_MASK,
1601 "select-all", 1,
1602 G_TYPE_BOOLEAN((GType) ((5) << (2))), FALSE(0));
1603
1604 /* Deleting text */
1605 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Delete0xffff, 0,
1606 "delete-from-cursor", 2,
1607 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DELETE_CHARS,
1608 G_TYPE_INT((GType) ((6) << (2))), 1);
1609
1610 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Delete0xff9f, 0,
1611 "delete-from-cursor", 2,
1612 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DELETE_CHARS,
1613 G_TYPE_INT((GType) ((6) << (2))), 1);
1614
1615 ctk_binding_entry_add_signal (binding_set, CDK_KEY_BackSpace0xff08, 0,
1616 "backspace", 0);
1617
1618 /* Make this do the same as Backspace, to help with mis-typing */
1619 ctk_binding_entry_add_signal (binding_set, CDK_KEY_BackSpace0xff08, CDK_SHIFT_MASK,
1620 "backspace", 0);
1621
1622 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Delete0xffff, CDK_CONTROL_MASK,
1623 "delete-from-cursor", 2,
1624 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DELETE_WORD_ENDS,
1625 G_TYPE_INT((GType) ((6) << (2))), 1);
1626
1627 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Delete0xff9f, CDK_CONTROL_MASK,
1628 "delete-from-cursor", 2,
1629 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DELETE_WORD_ENDS,
1630 G_TYPE_INT((GType) ((6) << (2))), 1);
1631
1632 ctk_binding_entry_add_signal (binding_set, CDK_KEY_BackSpace0xff08, CDK_CONTROL_MASK,
1633 "delete-from-cursor", 2,
1634 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DELETE_WORD_ENDS,
1635 G_TYPE_INT((GType) ((6) << (2))), -1);
1636
1637 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Delete0xffff, CDK_SHIFT_MASK | CDK_CONTROL_MASK,
1638 "delete-from-cursor", 2,
1639 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DELETE_PARAGRAPH_ENDS,
1640 G_TYPE_INT((GType) ((6) << (2))), 1);
1641
1642 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Delete0xff9f, CDK_SHIFT_MASK | CDK_CONTROL_MASK,
1643 "delete-from-cursor", 2,
1644 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DELETE_PARAGRAPH_ENDS,
1645 G_TYPE_INT((GType) ((6) << (2))), 1);
1646
1647 ctk_binding_entry_add_signal (binding_set, CDK_KEY_BackSpace0xff08, CDK_SHIFT_MASK | CDK_CONTROL_MASK,
1648 "delete-from-cursor", 2,
1649 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DELETE_PARAGRAPH_ENDS,
1650 G_TYPE_INT((GType) ((6) << (2))), -1);
1651
1652 /* Cut/copy/paste */
1653
1654 ctk_binding_entry_add_signal (binding_set, CDK_KEY_x0x078, CDK_CONTROL_MASK,
1655 "cut-clipboard", 0);
1656 ctk_binding_entry_add_signal (binding_set, CDK_KEY_c0x063, CDK_CONTROL_MASK,
1657 "copy-clipboard", 0);
1658 ctk_binding_entry_add_signal (binding_set, CDK_KEY_v0x076, CDK_CONTROL_MASK,
1659 "paste-clipboard", 0);
1660
1661 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Delete0xff9f, CDK_SHIFT_MASK,
1662 "cut-clipboard", 0);
1663 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Insert0xff9e, CDK_CONTROL_MASK,
1664 "copy-clipboard", 0);
1665 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Insert0xff9e, CDK_SHIFT_MASK,
1666 "paste-clipboard", 0);
1667
1668 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Delete0xffff, CDK_SHIFT_MASK,
1669 "cut-clipboard", 0);
1670 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Insert0xff63, CDK_CONTROL_MASK,
1671 "copy-clipboard", 0);
1672 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Insert0xff63, CDK_SHIFT_MASK,
1673 "paste-clipboard", 0);
1674
1675 /* Overwrite */
1676 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Insert0xff63, 0,
1677 "toggle-overwrite", 0);
1678 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Insert0xff9e, 0,
1679 "toggle-overwrite", 0);
1680
1681 /* Emoji */
1682 ctk_binding_entry_add_signal (binding_set, CDK_KEY_period0x02e, CDK_CONTROL_MASK,
1683 "insert-emoji", 0);
1684 ctk_binding_entry_add_signal (binding_set, CDK_KEY_semicolon0x03b, CDK_CONTROL_MASK,
1685 "insert-emoji", 0);
1686
1687 /* Caret mode */
1688 ctk_binding_entry_add_signal (binding_set, CDK_KEY_F70xffc4, 0,
1689 "toggle-cursor-visible", 0);
1690
1691 /* Control-tab focus motion */
1692 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Tab0xff09, CDK_CONTROL_MASK,
1693 "move-focus", 1,
1694 CTK_TYPE_DIRECTION_TYPE(ctk_direction_type_get_type ()), CTK_DIR_TAB_FORWARD);
1695 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Tab0xff89, CDK_CONTROL_MASK,
1696 "move-focus", 1,
1697 CTK_TYPE_DIRECTION_TYPE(ctk_direction_type_get_type ()), CTK_DIR_TAB_FORWARD);
1698
1699 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Tab0xff09, CDK_SHIFT_MASK | CDK_CONTROL_MASK,
1700 "move-focus", 1,
1701 CTK_TYPE_DIRECTION_TYPE(ctk_direction_type_get_type ()), CTK_DIR_TAB_BACKWARD);
1702 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Tab0xff89, CDK_SHIFT_MASK | CDK_CONTROL_MASK,
1703 "move-focus", 1,
1704 CTK_TYPE_DIRECTION_TYPE(ctk_direction_type_get_type ()), CTK_DIR_TAB_BACKWARD);
1705
1706 ctk_widget_class_set_accessible_type (widget_class, CTK_TYPE_TEXT_VIEW_ACCESSIBLE(ctk_text_view_accessible_get_type ()));
1707 ctk_widget_class_set_css_name (widget_class, "textview");
1708
1709 quark_text_selection_data = g_quark_from_static_string ("ctk-text-view-text-selection-data");
1710 quark_ctk_signal = g_quark_from_static_string ("ctk-signal");
1711 quark_text_view_child = g_quark_from_static_string ("ctk-text-view-child");
1712}
1713
1714static void
1715ctk_text_view_init (CtkTextView *text_view)
1716{
1717 CtkWidget *widget = CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
;
1718 CtkTargetList *target_list;
1719 CtkTextViewPrivate *priv;
1720 CtkStyleContext *context;
1721
1722 text_view->priv = ctk_text_view_get_instance_private (text_view);
1723 priv = text_view->priv;
1724
1725 ctk_widget_set_can_focus (widget, TRUE(!(0)));
1726
1727 priv->pixel_cache = _ctk_pixel_cache_new ();
1728
1729 context = ctk_widget_get_style_context (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
1730 ctk_style_context_add_class (context, CTK_STYLE_CLASS_VIEW"view");
1731
1732 /* Set up default style */
1733 priv->wrap_mode = CTK_WRAP_NONE;
1734 priv->pixels_above_lines = 0;
1735 priv->pixels_below_lines = 0;
1736 priv->pixels_inside_wrap = 0;
1737 priv->justify = CTK_JUSTIFY_LEFT;
1738 priv->indent = 0;
1739 priv->tabs = NULL((void*)0);
1740 priv->editable = TRUE(!(0));
1741
1742 priv->scroll_after_paste = FALSE(0);
1743
1744 ctk_drag_dest_set (widget, 0, NULL((void*)0), 0,
1745 CDK_ACTION_COPY | CDK_ACTION_MOVE);
1746
1747 target_list = ctk_target_list_new (NULL((void*)0), 0);
1748 ctk_drag_dest_set_target_list (widget, target_list);
1749 ctk_target_list_unref (target_list);
1750
1751 priv->virtual_cursor_x = -1;
1752 priv->virtual_cursor_y = -1;
1753
1754 /* This object is completely private. No external entity can gain a reference
1755 * to it; so we create it here and destroy it in finalize ().
1756 */
1757 priv->im_context = ctk_im_multicontext_new ();
1758
1759 g_signal_connect (priv->im_context, "commit",g_signal_connect_data ((priv->im_context), ("commit"), (((
GCallback) (ctk_text_view_commit_handler))), (text_view), ((void
*)0), (GConnectFlags) 0)
1760 G_CALLBACK (ctk_text_view_commit_handler), text_view)g_signal_connect_data ((priv->im_context), ("commit"), (((
GCallback) (ctk_text_view_commit_handler))), (text_view), ((void
*)0), (GConnectFlags) 0)
;
1761 g_signal_connect (priv->im_context, "preedit-changed",g_signal_connect_data ((priv->im_context), ("preedit-changed"
), (((GCallback) (ctk_text_view_preedit_changed_handler))), (
text_view), ((void*)0), (GConnectFlags) 0)
1762 G_CALLBACK (ctk_text_view_preedit_changed_handler), text_view)g_signal_connect_data ((priv->im_context), ("preedit-changed"
), (((GCallback) (ctk_text_view_preedit_changed_handler))), (
text_view), ((void*)0), (GConnectFlags) 0)
;
1763 g_signal_connect (priv->im_context, "retrieve-surrounding",g_signal_connect_data ((priv->im_context), ("retrieve-surrounding"
), (((GCallback) (ctk_text_view_retrieve_surrounding_handler)
)), (text_view), ((void*)0), (GConnectFlags) 0)
1764 G_CALLBACK (ctk_text_view_retrieve_surrounding_handler), text_view)g_signal_connect_data ((priv->im_context), ("retrieve-surrounding"
), (((GCallback) (ctk_text_view_retrieve_surrounding_handler)
)), (text_view), ((void*)0), (GConnectFlags) 0)
;
1765 g_signal_connect (priv->im_context, "delete-surrounding",g_signal_connect_data ((priv->im_context), ("delete-surrounding"
), (((GCallback) (ctk_text_view_delete_surrounding_handler)))
, (text_view), ((void*)0), (GConnectFlags) 0)
1766 G_CALLBACK (ctk_text_view_delete_surrounding_handler), text_view)g_signal_connect_data ((priv->im_context), ("delete-surrounding"
), (((GCallback) (ctk_text_view_delete_surrounding_handler)))
, (text_view), ((void*)0), (GConnectFlags) 0)
;
1767
1768 priv->cursor_visible = TRUE(!(0));
1769
1770 priv->accepts_tab = TRUE(!(0));
1771
1772 priv->text_window = text_window_new (CTK_TEXT_WINDOW_TEXT,
1773 widget, 200, 200);
1774
1775 priv->multipress_gesture = ctk_gesture_multi_press_new (widget);
1776 ctk_gesture_single_set_button (CTK_GESTURE_SINGLE (priv->multipress_gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((priv->multipress_gesture)), ((ctk_gesture_single_get_type
()))))))
, 0);
1777 g_signal_connect (priv->multipress_gesture, "pressed",g_signal_connect_data ((priv->multipress_gesture), ("pressed"
), (((GCallback) (ctk_text_view_multipress_gesture_pressed)))
, (widget), ((void*)0), (GConnectFlags) 0)
1778 G_CALLBACK (ctk_text_view_multipress_gesture_pressed),g_signal_connect_data ((priv->multipress_gesture), ("pressed"
), (((GCallback) (ctk_text_view_multipress_gesture_pressed)))
, (widget), ((void*)0), (GConnectFlags) 0)
1779 widget)g_signal_connect_data ((priv->multipress_gesture), ("pressed"
), (((GCallback) (ctk_text_view_multipress_gesture_pressed)))
, (widget), ((void*)0), (GConnectFlags) 0)
;
1780
1781 priv->drag_gesture = ctk_gesture_drag_new (widget);
1782 g_signal_connect (priv->drag_gesture, "drag-update",g_signal_connect_data ((priv->drag_gesture), ("drag-update"
), (((GCallback) (ctk_text_view_drag_gesture_update))), (widget
), ((void*)0), (GConnectFlags) 0)
1783 G_CALLBACK (ctk_text_view_drag_gesture_update),g_signal_connect_data ((priv->drag_gesture), ("drag-update"
), (((GCallback) (ctk_text_view_drag_gesture_update))), (widget
), ((void*)0), (GConnectFlags) 0)
1784 widget)g_signal_connect_data ((priv->drag_gesture), ("drag-update"
), (((GCallback) (ctk_text_view_drag_gesture_update))), (widget
), ((void*)0), (GConnectFlags) 0)
;
1785 g_signal_connect (priv->drag_gesture, "drag-end",g_signal_connect_data ((priv->drag_gesture), ("drag-end"),
(((GCallback) (ctk_text_view_drag_gesture_end))), (widget), (
(void*)0), (GConnectFlags) 0)
1786 G_CALLBACK (ctk_text_view_drag_gesture_end),g_signal_connect_data ((priv->drag_gesture), ("drag-end"),
(((GCallback) (ctk_text_view_drag_gesture_end))), (widget), (
(void*)0), (GConnectFlags) 0)
1787 widget)g_signal_connect_data ((priv->drag_gesture), ("drag-end"),
(((GCallback) (ctk_text_view_drag_gesture_end))), (widget), (
(void*)0), (GConnectFlags) 0)
;
1788
1789 priv->selection_node = ctk_css_node_new ();
1790 ctk_css_node_set_name (priv->selection_node, I_("selection")g_intern_static_string ("selection"));
1791 ctk_css_node_set_parent (priv->selection_node, priv->text_window->css_node);
1792 ctk_css_node_set_state (priv->selection_node,
1793 ctk_css_node_get_state (priv->text_window->css_node) & ~CTK_STATE_FLAG_DROP_ACTIVE);
1794 ctk_css_node_set_visible (priv->selection_node, FALSE(0));
1795 g_object_unref (priv->selection_node);
1796}
1797
1798CtkCssNode *
1799ctk_text_view_get_text_node (CtkTextView *text_view)
1800{
1801 return text_view->priv->text_window->css_node;
1802}
1803
1804CtkCssNode *
1805ctk_text_view_get_selection_node (CtkTextView *text_view)
1806{
1807 return text_view->priv->selection_node;
1808}
1809
1810static void
1811_ctk_text_view_ensure_text_handles (CtkTextView *text_view)
1812{
1813 CtkTextViewPrivate *priv = text_view->priv;
1814
1815 if (priv->text_handle)
1816 return;
1817
1818 priv->text_handle = _ctk_text_handle_new (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
1819 g_signal_connect (priv->text_handle, "drag-started",g_signal_connect_data ((priv->text_handle), ("drag-started"
), (((GCallback) (ctk_text_view_handle_drag_started))), (text_view
), ((void*)0), (GConnectFlags) 0)
1820 G_CALLBACK (ctk_text_view_handle_drag_started), text_view)g_signal_connect_data ((priv->text_handle), ("drag-started"
), (((GCallback) (ctk_text_view_handle_drag_started))), (text_view
), ((void*)0), (GConnectFlags) 0)
;
1821 g_signal_connect (priv->text_handle, "handle-dragged",g_signal_connect_data ((priv->text_handle), ("handle-dragged"
), (((GCallback) (ctk_text_view_handle_dragged))), (text_view
), ((void*)0), (GConnectFlags) 0)
1822 G_CALLBACK (ctk_text_view_handle_dragged), text_view)g_signal_connect_data ((priv->text_handle), ("handle-dragged"
), (((GCallback) (ctk_text_view_handle_dragged))), (text_view
), ((void*)0), (GConnectFlags) 0)
;
1823 g_signal_connect (priv->text_handle, "drag-finished",g_signal_connect_data ((priv->text_handle), ("drag-finished"
), (((GCallback) (ctk_text_view_handle_drag_finished))), (text_view
), ((void*)0), (GConnectFlags) 0)
1824 G_CALLBACK (ctk_text_view_handle_drag_finished), text_view)g_signal_connect_data ((priv->text_handle), ("drag-finished"
), (((GCallback) (ctk_text_view_handle_drag_finished))), (text_view
), ((void*)0), (GConnectFlags) 0)
;
1825}
1826
1827static void
1828_ctk_text_view_ensure_magnifier (CtkTextView *text_view)
1829{
1830 CtkTextViewPrivate *priv = text_view->priv;
1831
1832 if (priv->magnifier_popover)
1833 return;
1834
1835 priv->magnifier = _ctk_magnifier_new (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
1836 _ctk_magnifier_set_magnification (CTK_MAGNIFIER (priv->magnifier)((((CtkMagnifier*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->magnifier)), ((_ctk_magnifier_get_type ()))))))
, 2.0);
1837 priv->magnifier_popover = ctk_popover_new (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
1838 ctk_style_context_add_class (ctk_widget_get_style_context (priv->magnifier_popover),
1839 "magnifier");
1840 ctk_popover_set_modal (CTK_POPOVER (priv->magnifier_popover)((((CtkPopover*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->magnifier_popover)), ((ctk_popover_get_type ())
)))))
, FALSE(0));
1841 ctk_container_add (CTK_CONTAINER (priv->magnifier_popover)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->magnifier_popover)), ((ctk_container_get_type (
)))))))
,
1842 priv->magnifier);
1843 ctk_container_set_border_width (CTK_CONTAINER (priv->magnifier_popover)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->magnifier_popover)), ((ctk_container_get_type (
)))))))
, 4);
1844 ctk_widget_show (priv->magnifier);
1845}
1846
1847/**
1848 * ctk_text_view_new:
1849 *
1850 * Creates a new #CtkTextView. If you don’t call ctk_text_view_set_buffer()
1851 * before using the text view, an empty default buffer will be created
1852 * for you. Get the buffer with ctk_text_view_get_buffer(). If you want
1853 * to specify your own buffer, consider ctk_text_view_new_with_buffer().
1854 *
1855 * Returns: a new #CtkTextView
1856 **/
1857CtkWidget*
1858ctk_text_view_new (void)
1859{
1860 return g_object_new (CTK_TYPE_TEXT_VIEW(ctk_text_view_get_type ()), NULL((void*)0));
1861}
1862
1863/**
1864 * ctk_text_view_new_with_buffer:
1865 * @buffer: a #CtkTextBuffer
1866 *
1867 * Creates a new #CtkTextView widget displaying the buffer
1868 * @buffer. One buffer can be shared among many widgets.
1869 * @buffer may be %NULL to create a default buffer, in which case
1870 * this function is equivalent to ctk_text_view_new(). The
1871 * text view adds its own reference count to the buffer; it does not
1872 * take over an existing reference.
1873 *
1874 * Returns: a new #CtkTextView.
1875 **/
1876CtkWidget*
1877ctk_text_view_new_with_buffer (CtkTextBuffer *buffer)
1878{
1879 CtkTextView *text_view;
1880
1881 text_view = (CtkTextView*)ctk_text_view_new ();
1882
1883 ctk_text_view_set_buffer (text_view, buffer);
1884
1885 return CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
;
1886}
1887
1888/**
1889 * ctk_text_view_set_buffer:
1890 * @text_view: a #CtkTextView
1891 * @buffer: (allow-none): a #CtkTextBuffer
1892 *
1893 * Sets @buffer as the buffer being displayed by @text_view. The previous
1894 * buffer displayed by the text view is unreferenced, and a reference is
1895 * added to @buffer. If you owned a reference to @buffer before passing it
1896 * to this function, you must remove that reference yourself; #CtkTextView
1897 * will not “adopt” it.
1898 **/
1899void
1900ctk_text_view_set_buffer (CtkTextView *text_view,
1901 CtkTextBuffer *buffer)
1902{
1903 CtkTextViewPrivate *priv;
1904 CtkTextBuffer *old_buffer;
1905
1906 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
1907 g_return_if_fail (buffer == NULL || CTK_IS_TEXT_BUFFER (buffer))do { if ((buffer == ((void*)0) || (((__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__)), "buffer == NULL || CTK_IS_TEXT_BUFFER (buffer)"
); return; } } while (0)
;
1908
1909 priv = text_view->priv;
1910
1911 if (priv->buffer == buffer)
1912 return;
1913
1914 old_buffer = priv->buffer;
1915 if (priv->buffer != NULL((void*)0))
1916 {
1917 /* Destroy all anchored children */
1918 GSList *tmp_list;
1919 GSList *copy;
1920
1921 copy = g_slist_copy (priv->children);
1922 tmp_list = copy;
1923 while (tmp_list != NULL((void*)0))
1924 {
1925 CtkTextViewChild *vc = tmp_list->data;
1926
1927 if (vc->anchor)
1928 {
1929 ctk_widget_destroy (vc->widget);
1930 /* vc may now be invalid! */
1931 }
1932
1933 tmp_list = tmp_list->next;
1934 }
1935
1936 g_slist_free (copy);
1937
1938 g_signal_handlers_disconnect_by_func (priv->buffer,g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_mark_set_handler), (text_view))
1939 ctk_text_view_mark_set_handler,g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_mark_set_handler), (text_view))
1940 text_view)g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_mark_set_handler), (text_view))
;
1941 g_signal_handlers_disconnect_by_func (priv->buffer,g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_target_list_notify), (text_view))
1942 ctk_text_view_target_list_notify,g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_target_list_notify), (text_view))
1943 text_view)g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_target_list_notify), (text_view))
;
1944 g_signal_handlers_disconnect_by_func (priv->buffer,g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_paste_done_handler), (text_view))
1945 ctk_text_view_paste_done_handler,g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_paste_done_handler), (text_view))
1946 text_view)g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_paste_done_handler), (text_view))
;
1947 g_signal_handlers_disconnect_by_func (priv->buffer,g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_buffer_changed_handler), (text_view))
1948 ctk_text_view_buffer_changed_handler,g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_buffer_changed_handler), (text_view))
1949 text_view)g_signal_handlers_disconnect_matched ((priv->buffer), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ctk_text_view_buffer_changed_handler), (text_view))
;
1950
1951 if (ctk_widget_get_realized (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
1952 {
1953 CtkClipboard *clipboard = ctk_widget_get_clipboard (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
1954 CDK_SELECTION_PRIMARY((CdkAtom)((gpointer) (gulong) (1))));
1955 ctk_text_buffer_remove_selection_clipboard (priv->buffer, clipboard);
1956 }
1957
1958 if (priv->layout)
1959 ctk_text_layout_set_buffer (priv->layout, NULL((void*)0));
1960
1961 priv->dnd_mark = NULL((void*)0);
1962 priv->first_para_mark = NULL((void*)0);
1963 cancel_pending_scroll (text_view);
1964 }
1965
1966 priv->buffer = buffer;
1967
1968 if (priv->layout)
1969 ctk_text_layout_set_buffer (priv->layout, buffer);
1970
1971 if (buffer != NULL((void*)0))
1972 {
1973 CtkTextIter start;
1974
1975 g_object_ref (buffer)((__typeof__ (buffer)) (g_object_ref) (buffer));
1976
1977 ctk_text_buffer_get_iter_at_offset (priv->buffer, &start, 0);
1978
1979 priv->dnd_mark = ctk_text_buffer_create_mark (priv->buffer,
1980 "ctk_drag_target",
1981 &start, FALSE(0));
1982
1983 priv->first_para_mark = ctk_text_buffer_create_mark (priv->buffer,
1984 NULL((void*)0),
1985 &start, TRUE(!(0)));
1986
1987 priv->first_para_pixels = 0;
1988
1989
1990 g_signal_connect (priv->buffer, "mark-set",g_signal_connect_data ((priv->buffer), ("mark-set"), (((GCallback
) (ctk_text_view_mark_set_handler))), (text_view), ((void*)0)
, (GConnectFlags) 0)
1991 G_CALLBACK (ctk_text_view_mark_set_handler),g_signal_connect_data ((priv->buffer), ("mark-set"), (((GCallback
) (ctk_text_view_mark_set_handler))), (text_view), ((void*)0)
, (GConnectFlags) 0)
1992 text_view)g_signal_connect_data ((priv->buffer), ("mark-set"), (((GCallback
) (ctk_text_view_mark_set_handler))), (text_view), ((void*)0)
, (GConnectFlags) 0)
;
1993 g_signal_connect (priv->buffer, "notify::paste-target-list",g_signal_connect_data ((priv->buffer), ("notify::paste-target-list"
), (((GCallback) (ctk_text_view_target_list_notify))), (text_view
), ((void*)0), (GConnectFlags) 0)
1994 G_CALLBACK (ctk_text_view_target_list_notify),g_signal_connect_data ((priv->buffer), ("notify::paste-target-list"
), (((GCallback) (ctk_text_view_target_list_notify))), (text_view
), ((void*)0), (GConnectFlags) 0)
1995 text_view)g_signal_connect_data ((priv->buffer), ("notify::paste-target-list"
), (((GCallback) (ctk_text_view_target_list_notify))), (text_view
), ((void*)0), (GConnectFlags) 0)
;
1996 g_signal_connect (priv->buffer, "paste-done",g_signal_connect_data ((priv->buffer), ("paste-done"), (((
GCallback) (ctk_text_view_paste_done_handler))), (text_view),
((void*)0), (GConnectFlags) 0)
1997 G_CALLBACK (ctk_text_view_paste_done_handler),g_signal_connect_data ((priv->buffer), ("paste-done"), (((
GCallback) (ctk_text_view_paste_done_handler))), (text_view),
((void*)0), (GConnectFlags) 0)
1998 text_view)g_signal_connect_data ((priv->buffer), ("paste-done"), (((
GCallback) (ctk_text_view_paste_done_handler))), (text_view),
((void*)0), (GConnectFlags) 0)
;
1999 g_signal_connect (priv->buffer, "changed",g_signal_connect_data ((priv->buffer), ("changed"), (((GCallback
) (ctk_text_view_buffer_changed_handler))), (text_view), ((void
*)0), (GConnectFlags) 0)
2000 G_CALLBACK (ctk_text_view_buffer_changed_handler),g_signal_connect_data ((priv->buffer), ("changed"), (((GCallback
) (ctk_text_view_buffer_changed_handler))), (text_view), ((void
*)0), (GConnectFlags) 0)
2001 text_view)g_signal_connect_data ((priv->buffer), ("changed"), (((GCallback
) (ctk_text_view_buffer_changed_handler))), (text_view), ((void
*)0), (GConnectFlags) 0)
;
2002
2003 ctk_text_view_target_list_notify (priv->buffer, NULL((void*)0), text_view);
2004
2005 if (ctk_widget_get_realized (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
2006 {
2007 CtkClipboard *clipboard = ctk_widget_get_clipboard (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
2008 CDK_SELECTION_PRIMARY((CdkAtom)((gpointer) (gulong) (1))));
2009 ctk_text_buffer_add_selection_clipboard (priv->buffer, clipboard);
2010 }
2011
2012 if (priv->text_handle)
2013 ctk_text_view_update_handles (text_view, CTK_TEXT_HANDLE_MODE_NONE);
2014 }
2015
2016 _ctk_text_view_accessible_set_buffer (text_view, old_buffer);
2017 if (old_buffer)
2018 g_object_unref (old_buffer);
2019
2020 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "buffer");
2021
2022 if (ctk_widget_get_visible (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
2023 ctk_widget_queue_draw (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
2024
2025 DV(g_print ("Invalidating due to set_buffer\n"));
2026 ctk_text_view_invalidate (text_view);
2027}
2028
2029static CtkTextBuffer*
2030ctk_text_view_create_buffer (CtkTextView *text_view G_GNUC_UNUSED__attribute__ ((__unused__)))
2031{
2032 return ctk_text_buffer_new (NULL((void*)0));
2033}
2034
2035static CtkTextBuffer*
2036get_buffer (CtkTextView *text_view)
2037{
2038 if (text_view->priv->buffer == NULL((void*)0))
2039 {
2040 CtkTextBuffer *b;
2041 b = CTK_TEXT_VIEW_GET_CLASS (text_view)((((CtkTextViewClass*) (((GTypeInstance*) ((text_view)))->
g_class))))
->create_buffer (text_view);
2042 ctk_text_view_set_buffer (text_view, b);
2043 g_object_unref (b);
2044 }
2045
2046 return text_view->priv->buffer;
2047}
2048
2049/**
2050 * ctk_text_view_get_buffer:
2051 * @text_view: a #CtkTextView
2052 *
2053 * Returns the #CtkTextBuffer being displayed by this text view.
2054 * The reference count on the buffer is not incremented; the caller
2055 * of this function won’t own a new reference.
2056 *
2057 * Returns: (transfer none): a #CtkTextBuffer
2058 **/
2059CtkTextBuffer*
2060ctk_text_view_get_buffer (CtkTextView *text_view)
2061{
2062 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (((void*)0)); } }
while (0)
;
2063
2064 return get_buffer (text_view);
2065}
2066
2067/**
2068 * ctk_text_view_get_cursor_locations:
2069 * @text_view: a #CtkTextView
2070 * @iter: (allow-none): a #CtkTextIter
2071 * @strong: (out) (allow-none): location to store the strong
2072 * cursor position (may be %NULL)
2073 * @weak: (out) (allow-none): location to store the weak
2074 * cursor position (may be %NULL)
2075 *
2076 * Given an @iter within a text layout, determine the positions of the
2077 * strong and weak cursors if the insertion point is at that
2078 * iterator. The position of each cursor is stored as a zero-width
2079 * rectangle. The strong cursor location is the location where
2080 * characters of the directionality equal to the base direction of the
2081 * paragraph are inserted. The weak cursor location is the location
2082 * where characters of the directionality opposite to the base
2083 * direction of the paragraph are inserted.
2084 *
2085 * If @iter is %NULL, the actual cursor position is used.
2086 *
2087 * Note that if @iter happens to be the actual cursor position, and
2088 * there is currently an IM preedit sequence being entered, the
2089 * returned locations will be adjusted to account for the preedit
2090 * cursor’s offset within the preedit sequence.
2091 *
2092 * The rectangle position is in buffer coordinates; use
2093 * ctk_text_view_buffer_to_window_coords() to convert these
2094 * coordinates to coordinates for one of the windows in the text view.
2095 *
2096 * Since: 3.0
2097 **/
2098void
2099ctk_text_view_get_cursor_locations (CtkTextView *text_view,
2100 const CtkTextIter *iter,
2101 CdkRectangle *strong,
2102 CdkRectangle *weak)
2103{
2104 CtkTextIter insert;
2105
2106 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
2107 g_return_if_fail (iter == NULL ||do { if ((iter == ((void*)0) || ctk_text_iter_get_buffer (iter
) == get_buffer (text_view))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "iter == NULL || ctk_text_iter_get_buffer (iter) == get_buffer (text_view)"
); return; } } while (0)
2108 ctk_text_iter_get_buffer (iter) == get_buffer (text_view))do { if ((iter == ((void*)0) || ctk_text_iter_get_buffer (iter
) == get_buffer (text_view))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "iter == NULL || ctk_text_iter_get_buffer (iter) == get_buffer (text_view)"
); return; } } while (0)
;
2109
2110 ctk_text_view_ensure_layout (text_view);
2111
2112 if (iter)
2113 insert = *iter;
2114 else
2115 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
2116 ctk_text_buffer_get_insert (get_buffer (text_view)));
2117
2118 ctk_text_layout_get_cursor_locations (text_view->priv->layout, &insert,
2119 strong, weak);
2120}
2121
2122/**
2123 * ctk_text_view_get_iter_at_location:
2124 * @text_view: a #CtkTextView
2125 * @iter: (out): a #CtkTextIter
2126 * @x: x position, in buffer coordinates
2127 * @y: y position, in buffer coordinates
2128 *
2129 * Retrieves the iterator at buffer coordinates @x and @y. Buffer
2130 * coordinates are coordinates for the entire buffer, not just the
2131 * currently-displayed portion. If you have coordinates from an
2132 * event, you have to convert those to buffer coordinates with
2133 * ctk_text_view_window_to_buffer_coords().
2134 *
2135 * Returns: %TRUE if the position is over text
2136 */
2137gboolean
2138ctk_text_view_get_iter_at_location (CtkTextView *text_view,
2139 CtkTextIter *iter,
2140 gint x,
2141 gint y)
2142{
2143 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
2144 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)
;
2145
2146 ctk_text_view_ensure_layout (text_view);
2147
2148 return ctk_text_layout_get_iter_at_pixel (text_view->priv->layout, iter, x, y);
2149}
2150
2151/**
2152 * ctk_text_view_get_iter_at_position:
2153 * @text_view: a #CtkTextView
2154 * @iter: (out): a #CtkTextIter
2155 * @trailing: (out) (allow-none): if non-%NULL, location to store an integer indicating where
2156 * in the grapheme the user clicked. It will either be
2157 * zero, or the number of characters in the grapheme.
2158 * 0 represents the trailing edge of the grapheme.
2159 * @x: x position, in buffer coordinates
2160 * @y: y position, in buffer coordinates
2161 *
2162 * Retrieves the iterator pointing to the character at buffer
2163 * coordinates @x and @y. Buffer coordinates are coordinates for
2164 * the entire buffer, not just the currently-displayed portion.
2165 * If you have coordinates from an event, you have to convert
2166 * those to buffer coordinates with
2167 * ctk_text_view_window_to_buffer_coords().
2168 *
2169 * Note that this is different from ctk_text_view_get_iter_at_location(),
2170 * which returns cursor locations, i.e. positions between
2171 * characters.
2172 *
2173 * Returns: %TRUE if the position is over text
2174 *
2175 * Since: 2.6
2176 **/
2177gboolean
2178ctk_text_view_get_iter_at_position (CtkTextView *text_view,
2179 CtkTextIter *iter,
2180 gint *trailing,
2181 gint x,
2182 gint y)
2183{
2184 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
2185 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)
;
2186
2187 ctk_text_view_ensure_layout (text_view);
2188
2189 return ctk_text_layout_get_iter_at_position (text_view->priv->layout, iter, trailing, x, y);
2190}
2191
2192/**
2193 * ctk_text_view_get_iter_location:
2194 * @text_view: a #CtkTextView
2195 * @iter: a #CtkTextIter
2196 * @location: (out): bounds of the character at @iter
2197 *
2198 * Gets a rectangle which roughly contains the character at @iter.
2199 * The rectangle position is in buffer coordinates; use
2200 * ctk_text_view_buffer_to_window_coords() to convert these
2201 * coordinates to coordinates for one of the windows in the text view.
2202 **/
2203void
2204ctk_text_view_get_iter_location (CtkTextView *text_view,
2205 const CtkTextIter *iter,
2206 CdkRectangle *location)
2207{
2208 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
2209 g_return_if_fail (ctk_text_iter_get_buffer (iter) == get_buffer (text_view))do { if ((ctk_text_iter_get_buffer (iter) == get_buffer (text_view
))) { } else { g_return_if_fail_warning ("Ctk", ((const char*
) (__func__)), "ctk_text_iter_get_buffer (iter) == get_buffer (text_view)"
); return; } } while (0)
;
2210
2211 ctk_text_view_ensure_layout (text_view);
2212
2213 ctk_text_layout_get_iter_location (text_view->priv->layout, iter, location);
2214}
2215
2216/**
2217 * ctk_text_view_get_line_yrange:
2218 * @text_view: a #CtkTextView
2219 * @iter: a #CtkTextIter
2220 * @y: (out): return location for a y coordinate
2221 * @height: (out): return location for a height
2222 *
2223 * Gets the y coordinate of the top of the line containing @iter,
2224 * and the height of the line. The coordinate is a buffer coordinate;
2225 * convert to window coordinates with ctk_text_view_buffer_to_window_coords().
2226 **/
2227void
2228ctk_text_view_get_line_yrange (CtkTextView *text_view,
2229 const CtkTextIter *iter,
2230 gint *y,
2231 gint *height)
2232{
2233 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
2234 g_return_if_fail (ctk_text_iter_get_buffer (iter) == get_buffer (text_view))do { if ((ctk_text_iter_get_buffer (iter) == get_buffer (text_view
))) { } else { g_return_if_fail_warning ("Ctk", ((const char*
) (__func__)), "ctk_text_iter_get_buffer (iter) == get_buffer (text_view)"
); return; } } while (0)
;
2235
2236 ctk_text_view_ensure_layout (text_view);
2237
2238 ctk_text_layout_get_line_yrange (text_view->priv->layout,
2239 iter,
2240 y,
2241 height);
2242}
2243
2244/**
2245 * ctk_text_view_get_line_at_y:
2246 * @text_view: a #CtkTextView
2247 * @target_iter: (out): a #CtkTextIter
2248 * @y: a y coordinate
2249 * @line_top: (out): return location for top coordinate of the line
2250 *
2251 * Gets the #CtkTextIter at the start of the line containing
2252 * the coordinate @y. @y is in buffer coordinates, convert from
2253 * window coordinates with ctk_text_view_window_to_buffer_coords().
2254 * If non-%NULL, @line_top will be filled with the coordinate of the top
2255 * edge of the line.
2256 **/
2257void
2258ctk_text_view_get_line_at_y (CtkTextView *text_view,
2259 CtkTextIter *target_iter,
2260 gint y,
2261 gint *line_top)
2262{
2263 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
2264
2265 ctk_text_view_ensure_layout (text_view);
2266
2267 ctk_text_layout_get_line_at_y (text_view->priv->layout,
2268 target_iter,
2269 y,
2270 line_top);
2271}
2272
2273/* Same as ctk_text_view_scroll_to_iter but deal with
2274 * (top_margin / top_padding) and (bottom_margin / bottom_padding).
2275 * When with_border == TRUE and you scroll on the edges,
2276 * all borders are shown for the corresponding edge.
2277 * When with_border == FALSE, only left margin and right_margin
2278 * can be seen because they can be can be overwritten by tags.
2279 */
2280static gboolean
2281_ctk_text_view_scroll_to_iter (CtkTextView *text_view,
2282 CtkTextIter *iter,
2283 gdouble within_margin,
2284 gboolean use_align,
2285 gdouble xalign,
2286 gdouble yalign,
2287 gboolean with_border)
2288{
2289 CtkTextViewPrivate *priv = text_view->priv;
2290 CtkWidget *widget;
2291
2292 CdkRectangle cursor;
2293 gint cursor_bottom;
2294 gint cursor_right;
2295
2296 CdkRectangle screen;
2297 CdkRectangle screen_dest;
2298
2299 gint screen_inner_left;
2300 gint screen_inner_right;
2301 gint screen_inner_top;
2302 gint screen_inner_bottom;
2303
2304 gint border_xoffset = 0;
2305 gint border_yoffset = 0;
2306 gint within_margin_xoffset;
2307 gint within_margin_yoffset;
2308
2309 gint buffer_bottom;
2310 gint buffer_right;
2311
2312 gboolean retval = FALSE(0);
2313
2314 /* FIXME why don't we do the validate-at-scroll-destination thing
2315 * from flush_scroll in this function? I think it wasn't done before
2316 * because changed_handler was screwed up, but I could be wrong.
2317 */
2318
2319 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
2320 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)
;
2321 g_return_val_if_fail (within_margin >= 0.0 && within_margin < 0.5, FALSE)do { if ((within_margin >= 0.0 && within_margin <
0.5)) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "within_margin >= 0.0 && within_margin < 0.5"
); return ((0)); } } while (0)
;
2322 g_return_val_if_fail (xalign >= 0.0 && xalign <= 1.0, FALSE)do { if ((xalign >= 0.0 && xalign <= 1.0)) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "xalign >= 0.0 && xalign <= 1.0"); return ((
0)); } } while (0)
;
2323 g_return_val_if_fail (yalign >= 0.0 && yalign <= 1.0, FALSE)do { if ((yalign >= 0.0 && yalign <= 1.0)) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "yalign >= 0.0 && yalign <= 1.0"); return ((
0)); } } while (0)
;
2324
2325 widget = CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
;
2326
2327 DV(g_print(G_STRLOC"\n"));
2328
2329 ctk_text_layout_get_iter_location (priv->layout,
2330 iter,
2331 &cursor);
2332
2333 DV (g_print (" target cursor %d,%d %d x %d\n", cursor.x, cursor.y, cursor.width, cursor.height));
2334
2335 /* In each direction, *_border are the addition of *_padding and *_margin
2336 *
2337 * Vadjustment value:
2338 * (-priv->top_border) [top padding][top margin] (0) [text][bottom margin][bottom padding]
2339 *
2340 * Hadjustment value:
2341 * (-priv->left_padding) [left padding] (0) [left margin][text][right margin][right padding]
2342 *
2343 * Buffer coordinates:
2344 * on x: (0) [left margin][text][right margin]
2345 * on y: (0) [text]
2346 *
2347 * left margin and right margin are part of the x buffer coordinate
2348 * because they are part of the pango layout so that they can be
2349 * overwritten by tags.
2350 *
2351 * Canvas coordinates:
2352 * (the canvas is the virtual window where the content of the buffer is drawn )
2353 *
2354 * on x: (-priv->left_padding) [left padding] (0) [left margin][text][right margin][right padding]
2355 * on y: (-priv->top_border) [top margin][top padding] (0) [text][bottom margin][bottom padding]
2356 *
2357 * (priv->xoffset, priv->yoffset) is the origin of the view (visible part of the canvas)
2358 * in canvas coordinates.
2359 * As you can see, canvas coordinates and buffer coordinates are compatible but the canvas
2360 * can be larger than the buffer depending of the border size.
2361 */
2362
2363 cursor_bottom = cursor.y + cursor.height;
2364 cursor_right = cursor.x + cursor.width;
2365
2366 /* Current position of the view in canvas coordinates */
2367 screen.x = priv->xoffset;
2368 screen.y = priv->yoffset;
2369 screen.width = SCREEN_WIDTH (widget)text_window_get_width (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_text_view_get_type ())))
)))->priv->text_window)
;
2370 screen.height = SCREEN_HEIGHT (widget)text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_text_view_get_type ())))
)))->priv->text_window)
;
2371
2372 within_margin_xoffset = screen.width * within_margin;
2373 within_margin_yoffset = screen.height * within_margin;
2374
2375 screen_inner_left = screen.x + within_margin_xoffset;
2376 screen_inner_top = screen.y + within_margin_yoffset;
2377 screen_inner_right = screen.x + screen.width - within_margin_xoffset;
2378 screen_inner_bottom = screen.y + screen.height - within_margin_yoffset;
2379
2380 buffer_bottom = priv->height - priv->bottom_border;
2381 buffer_right = priv->width - priv->right_margin - priv->left_padding - 1;
2382
2383 screen_dest.x = screen.x;
2384 screen_dest.y = screen.y;
2385 screen_dest.width = screen.width - within_margin_xoffset * 2;
2386 screen_dest.height = screen.height - within_margin_yoffset * 2;
2387
2388 /* Minimum authorised size check */
2389 if (screen_dest.width < 1)
2390 screen_dest.width = 1;
2391 if (screen_dest.height < 1)
2392 screen_dest.height = 1;
2393
2394 /* The alignment affects the point in the target character that we
2395 * choose to align. If we're doing right/bottom alignment, we align
2396 * the right/bottom edge of the character the mark is at; if we're
2397 * doing left/top we align the left/top edge of the character; if
2398 * we're doing center alignment we align the center of the
2399 * character.
2400 *
2401 * The differents cases handle on each direction:
2402 * 1. cursor outside of the inner area define by within_margin
2403 * 2. if use_align == TRUE, alignment with xalign and yalign
2404 * 3. scrolling on the edges dependent of with_border
2405 */
2406
2407 /* Vertical scroll */
2408 if (use_align)
2409 {
2410 gint cursor_y_alignment_offset;
2411
2412 cursor_y_alignment_offset = (cursor.height * yalign) - (screen_dest.height * yalign);
2413 screen_dest.y = cursor.y + cursor_y_alignment_offset - within_margin_yoffset;
2414 }
2415 else
2416 {
2417 /* move minimum to get onscreen, showing the
2418 * top_border or bottom_border when necessary
2419 */
2420 if (cursor.y < screen_inner_top)
2421 {
2422 if (cursor.y == 0)
2423 border_yoffset = (with_border) ? priv->top_padding : 0;
2424
2425 screen_dest.y = cursor.y - MAX (within_margin_yoffset, border_yoffset)(((within_margin_yoffset) > (border_yoffset)) ? (within_margin_yoffset
) : (border_yoffset))
;
2426 }
2427 else if (cursor_bottom > screen_inner_bottom)
2428 {
2429 if (cursor_bottom == buffer_bottom - priv->top_border)
2430 border_yoffset = (with_border) ? priv->bottom_padding : 0;
2431
2432 screen_dest.y = cursor_bottom - screen_dest.height +
2433 MAX (within_margin_yoffset, border_yoffset)(((within_margin_yoffset) > (border_yoffset)) ? (within_margin_yoffset
) : (border_yoffset))
;
2434 }
2435 }
2436
2437 if (screen_dest.y != screen.y)
2438 {
2439 ctk_adjustment_animate_to_value (priv->vadjustment, screen_dest.y + priv->top_border);
2440
2441 DV (g_print (" vert increment %d\n", screen_dest.y - screen.y));
2442 }
2443
2444 /* Horizontal scroll */
2445
2446 if (use_align)
2447 {
2448 gint cursor_x_alignment_offset;
2449
2450 cursor_x_alignment_offset = (cursor.width * xalign) - (screen_dest.width * xalign);
2451 screen_dest.x = cursor.x + cursor_x_alignment_offset - within_margin_xoffset;
2452 }
2453 else
2454 {
2455 /* move minimum to get onscreen, showing the
2456 * left_border or right_border when necessary
2457 */
2458 if (cursor.x < screen_inner_left)
2459 {
2460 if (cursor.x == priv->left_margin)
2461 border_xoffset = (with_border) ? priv->left_padding : 0;
2462
2463 screen_dest.x = cursor.x - MAX (within_margin_xoffset, border_xoffset)(((within_margin_xoffset) > (border_xoffset)) ? (within_margin_xoffset
) : (border_xoffset))
;
2464 }
2465 else if (cursor_right >= screen_inner_right - 1)
2466 {
2467 if (cursor.x >= buffer_right - priv->right_padding)
2468 border_xoffset = (with_border) ? priv->right_padding : 0;
2469
2470 screen_dest.x = cursor_right - screen_dest.width +
2471 MAX (within_margin_xoffset, border_xoffset)(((within_margin_xoffset) > (border_xoffset)) ? (within_margin_xoffset
) : (border_xoffset))
+ 1;
2472 }
2473 }
2474
2475 if (screen_dest.x != screen.x)
2476 {
2477 ctk_adjustment_animate_to_value (priv->hadjustment, screen_dest.x + priv->left_padding);
2478
2479 DV (g_print (" horiz increment %d\n", screen_dest.x - screen.x));
2480 }
2481
2482 retval = (screen.y != screen_dest.y) || (screen.x != screen_dest.x);
2483
2484 DV(g_print (">%s ("G_STRLOC")\n", retval ? "Actually scrolled" : "Didn't end up scrolling"));
2485
2486 return retval;
2487}
2488
2489/**
2490 * ctk_text_view_scroll_to_iter:
2491 * @text_view: a #CtkTextView
2492 * @iter: a #CtkTextIter
2493 * @within_margin: margin as a [0.0,0.5) fraction of screen size
2494 * @use_align: whether to use alignment arguments (if %FALSE,
2495 * just get the mark onscreen)
2496 * @xalign: horizontal alignment of mark within visible area
2497 * @yalign: vertical alignment of mark within visible area
2498 *
2499 * Scrolls @text_view so that @iter is on the screen in the position
2500 * indicated by @xalign and @yalign. An alignment of 0.0 indicates
2501 * left or top, 1.0 indicates right or bottom, 0.5 means center.
2502 * If @use_align is %FALSE, the text scrolls the minimal distance to
2503 * get the mark onscreen, possibly not scrolling at all. The effective
2504 * screen for purposes of this function is reduced by a margin of size
2505 * @within_margin.
2506 *
2507 * Note that this function uses the currently-computed height of the
2508 * lines in the text buffer. Line heights are computed in an idle
2509 * handler; so this function may not have the desired effect if it’s
2510 * called before the height computations. To avoid oddness, consider
2511 * using ctk_text_view_scroll_to_mark() which saves a point to be
2512 * scrolled to after line validation.
2513 *
2514 * Returns: %TRUE if scrolling occurred
2515 **/
2516gboolean
2517ctk_text_view_scroll_to_iter (CtkTextView *text_view,
2518 CtkTextIter *iter,
2519 gdouble within_margin,
2520 gboolean use_align,
2521 gdouble xalign,
2522 gdouble yalign)
2523{
2524 return _ctk_text_view_scroll_to_iter (text_view,
2525 iter,
2526 within_margin,
2527 use_align,
2528 xalign,
2529 yalign,
2530 FALSE(0));
2531}
2532
2533static void
2534free_pending_scroll (CtkTextPendingScroll *scroll)
2535{
2536 if (!ctk_text_mark_get_deleted (scroll->mark))
2537 ctk_text_buffer_delete_mark (ctk_text_mark_get_buffer (scroll->mark),
2538 scroll->mark);
2539 g_object_unref (scroll->mark);
2540 g_slice_free (CtkTextPendingScroll, scroll)do { if (1) g_slice_free1 (sizeof (CtkTextPendingScroll), (scroll
)); else (void) ((CtkTextPendingScroll*) 0 == (scroll)); } while
(0)
;
2541}
2542
2543static void
2544cancel_pending_scroll (CtkTextView *text_view)
2545{
2546 if (text_view->priv->pending_scroll)
2547 {
2548 free_pending_scroll (text_view->priv->pending_scroll);
2549 text_view->priv->pending_scroll = NULL((void*)0);
2550 }
2551}
2552
2553static void
2554ctk_text_view_queue_scroll (CtkTextView *text_view,
2555 CtkTextMark *mark,
2556 gdouble within_margin,
2557 gboolean use_align,
2558 gdouble xalign,
2559 gdouble yalign)
2560{
2561 CtkTextIter iter;
2562 CtkTextPendingScroll *scroll;
2563
2564 DV(g_print(G_STRLOC"\n"));
2565
2566 scroll = g_slice_new (CtkTextPendingScroll)((CtkTextPendingScroll*) g_slice_alloc (sizeof (CtkTextPendingScroll
)))
;
2567
2568 scroll->within_margin = within_margin;
2569 scroll->use_align = use_align;
2570 scroll->xalign = xalign;
2571 scroll->yalign = yalign;
2572
2573 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
2574
2575 scroll->mark = ctk_text_buffer_create_mark (get_buffer (text_view),
2576 NULL((void*)0),
2577 &iter,
2578 ctk_text_mark_get_left_gravity (mark));
2579
2580 g_object_ref (scroll->mark)((__typeof__ (scroll->mark)) (g_object_ref) (scroll->mark
))
;
2581
2582 cancel_pending_scroll (text_view);
2583
2584 text_view->priv->pending_scroll = scroll;
2585}
2586
2587static gboolean
2588ctk_text_view_flush_scroll (CtkTextView *text_view)
2589{
2590 CtkAllocation allocation;
2591 CtkTextIter iter;
2592 CtkTextPendingScroll *scroll;
2593 gboolean retval;
2594 CtkWidget *widget;
2595
2596 widget = CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
;
2597
2598 DV(g_print(G_STRLOC"\n"));
2599
2600 if (text_view->priv->pending_scroll == NULL((void*)0))
2601 {
2602 DV (g_print ("in flush scroll, no pending scroll\n"));
2603 return FALSE(0);
2604 }
2605
2606 scroll = text_view->priv->pending_scroll;
2607
2608 /* avoid recursion */
2609 text_view->priv->pending_scroll = NULL((void*)0);
2610
2611 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, scroll->mark);
2612
2613 /* Validate area around the scroll destination, so the adjustment
2614 * can meaningfully point into that area. We must validate
2615 * enough area to be sure that after we scroll, everything onscreen
2616 * is valid; otherwise, validation will maintain the first para
2617 * in one place, but may push the target iter off the bottom of
2618 * the screen.
2619 */
2620 DV(g_print (">Validating scroll destination ("G_STRLOC")\n"));
2621 ctk_widget_get_allocation (widget, &allocation);
2622 ctk_text_layout_validate_yrange (text_view->priv->layout, &iter,
2623 -(allocation.height * 2),
2624 allocation.height * 2);
2625
2626 DV(g_print (">Done validating scroll destination ("G_STRLOC")\n"));
2627
2628 /* Ensure we have updated width/height */
2629 ctk_text_view_update_adjustments (text_view);
2630
2631 retval = _ctk_text_view_scroll_to_iter (text_view,
2632 &iter,
2633 scroll->within_margin,
2634 scroll->use_align,
2635 scroll->xalign,
2636 scroll->yalign,
2637 TRUE(!(0)));
2638
2639 if (text_view->priv->text_handle)
2640 ctk_text_view_update_handles (text_view,
2641 _ctk_text_handle_get_mode (text_view->priv->text_handle));
2642
2643 free_pending_scroll (scroll);
2644
2645 return retval;
2646}
2647
2648static void
2649ctk_text_view_update_adjustments (CtkTextView *text_view)
2650{
2651 CtkTextViewPrivate *priv;
2652 gint width = 0, height = 0;
2653
2654 DV(g_print(">Updating adjustments ("G_STRLOC")\n"));
2655
2656 priv = text_view->priv;
2657
2658 if (priv->layout)
2659 ctk_text_layout_get_size (priv->layout, &width, &height);
2660
2661 /* Make room for the cursor after the last character in the widest line */
2662 width += SPACE_FOR_CURSOR1;
2663 height += priv->top_border + priv->bottom_border;
2664
2665 if (priv->width != width || priv->height != height)
2666 {
2667 if (priv->width != width)
2668 priv->width_changed = TRUE(!(0));
2669
2670 priv->width = width;
2671 priv->height = height;
2672
2673 ctk_text_view_set_hadjustment_values (text_view);
2674 ctk_text_view_set_vadjustment_values (text_view);
2675 }
2676}
2677
2678static void
2679ctk_text_view_update_layout_width (CtkTextView *text_view)
2680{
2681 DV(g_print(">Updating layout width ("G_STRLOC")\n"));
2682
2683 ctk_text_view_ensure_layout (text_view);
2684
2685 ctk_text_layout_set_screen_width (text_view->priv->layout,
2686 MAX (1, SCREEN_WIDTH (text_view) - SPACE_FOR_CURSOR)(((1) > (text_window_get_width (((((CtkTextView*) (void *)
g_type_check_instance_cast ((GTypeInstance*) ((text_view)), (
(ctk_text_view_get_type ()))))))->priv->text_window) - 1
)) ? (1) : (text_window_get_width (((((CtkTextView*) (void *)
g_type_check_instance_cast ((GTypeInstance*) ((text_view)), (
(ctk_text_view_get_type ()))))))->priv->text_window) - 1
))
);
2687}
2688
2689static void
2690ctk_text_view_update_im_spot_location (CtkTextView *text_view)
2691{
2692 CdkRectangle area;
2693
2694 if (text_view->priv->layout == NULL((void*)0))
2695 return;
2696
2697 ctk_text_view_get_cursor_locations (text_view, NULL((void*)0), &area, NULL((void*)0));
2698
2699 area.x -= text_view->priv->xoffset;
2700 area.y -= text_view->priv->yoffset;
2701
2702 /* Width returned by Pango indicates direction of cursor,
2703 * by its sign more than the size of cursor.
2704 */
2705 area.width = 0;
2706
2707 ctk_im_context_set_cursor_location (text_view->priv->im_context, &area);
2708}
2709
2710static gboolean
2711do_update_im_spot_location (gpointer text_view)
2712{
2713 CtkTextViewPrivate *priv;
2714
2715 priv = CTK_TEXT_VIEW (text_view)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_text_view_get_type ()))))))
->priv;
2716 priv->im_spot_idle = 0;
2717
2718 ctk_text_view_update_im_spot_location (text_view);
2719 return FALSE(0);
2720}
2721
2722static void
2723queue_update_im_spot_location (CtkTextView *text_view)
2724{
2725 CtkTextViewPrivate *priv;
2726
2727 priv = text_view->priv;
2728
2729 /* Use priority a little higher than CTK_TEXT_VIEW_PRIORITY_VALIDATE,
2730 * so we don't wait until the entire buffer has been validated. */
2731 if (!priv->im_spot_idle)
2732 {
2733 priv->im_spot_idle = cdk_threads_add_idle_full (CTK_TEXT_VIEW_PRIORITY_VALIDATE((100 + 20) + 5) - 1,
2734 do_update_im_spot_location,
2735 text_view,
2736 NULL((void*)0));
2737 g_source_set_name_by_id (priv->im_spot_idle, "[ctk+] do_update_im_spot_location");
2738 }
2739}
2740
2741static void
2742flush_update_im_spot_location (CtkTextView *text_view)
2743{
2744 CtkTextViewPrivate *priv;
2745
2746 priv = text_view->priv;
2747
2748 if (priv->im_spot_idle)
2749 {
2750 g_source_remove (priv->im_spot_idle);
2751 priv->im_spot_idle = 0;
2752 ctk_text_view_update_im_spot_location (text_view);
2753 }
2754}
2755
2756/**
2757 * ctk_text_view_scroll_to_mark:
2758 * @text_view: a #CtkTextView
2759 * @mark: a #CtkTextMark
2760 * @within_margin: margin as a [0.0,0.5) fraction of screen size
2761 * @use_align: whether to use alignment arguments (if %FALSE, just
2762 * get the mark onscreen)
2763 * @xalign: horizontal alignment of mark within visible area
2764 * @yalign: vertical alignment of mark within visible area
2765 *
2766 * Scrolls @text_view so that @mark is on the screen in the position
2767 * indicated by @xalign and @yalign. An alignment of 0.0 indicates
2768 * left or top, 1.0 indicates right or bottom, 0.5 means center.
2769 * If @use_align is %FALSE, the text scrolls the minimal distance to
2770 * get the mark onscreen, possibly not scrolling at all. The effective
2771 * screen for purposes of this function is reduced by a margin of size
2772 * @within_margin.
2773 **/
2774void
2775ctk_text_view_scroll_to_mark (CtkTextView *text_view,
2776 CtkTextMark *mark,
2777 gdouble within_margin,
2778 gboolean use_align,
2779 gdouble xalign,
2780 gdouble yalign)
2781{
2782 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
2783 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)
;
2784 g_return_if_fail (within_margin >= 0.0 && within_margin < 0.5)do { if ((within_margin >= 0.0 && within_margin <
0.5)) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "within_margin >= 0.0 && within_margin < 0.5"
); return; } } while (0)
;
2785 g_return_if_fail (xalign >= 0.0 && xalign <= 1.0)do { if ((xalign >= 0.0 && xalign <= 1.0)) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "xalign >= 0.0 && xalign <= 1.0"); return; }
} while (0)
;
2786 g_return_if_fail (yalign >= 0.0 && yalign <= 1.0)do { if ((yalign >= 0.0 && yalign <= 1.0)) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "yalign >= 0.0 && yalign <= 1.0"); return; }
} while (0)
;
2787
2788 /* We need to verify that the buffer contains the mark, otherwise this
2789 * can lead to data structure corruption later on.
2790 */
2791 g_return_if_fail (get_buffer (text_view) == ctk_text_mark_get_buffer (mark))do { if ((get_buffer (text_view) == ctk_text_mark_get_buffer (
mark))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "get_buffer (text_view) == ctk_text_mark_get_buffer (mark)"
); return; } } while (0)
;
2792
2793 ctk_text_view_queue_scroll (text_view, mark,
2794 within_margin,
2795 use_align,
2796 xalign,
2797 yalign);
2798
2799 /* If no validation is pending, we need to go ahead and force an
2800 * immediate scroll.
2801 */
2802 if (text_view->priv->layout &&
2803 ctk_text_layout_is_valid (text_view->priv->layout))
2804 ctk_text_view_flush_scroll (text_view);
2805}
2806
2807/**
2808 * ctk_text_view_scroll_mark_onscreen:
2809 * @text_view: a #CtkTextView
2810 * @mark: a mark in the buffer for @text_view
2811 *
2812 * Scrolls @text_view the minimum distance such that @mark is contained
2813 * within the visible area of the widget.
2814 **/
2815void
2816ctk_text_view_scroll_mark_onscreen (CtkTextView *text_view,
2817 CtkTextMark *mark)
2818{
2819 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
2820 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)
;
2821
2822 /* We need to verify that the buffer contains the mark, otherwise this
2823 * can lead to data structure corruption later on.
2824 */
2825 g_return_if_fail (get_buffer (text_view) == ctk_text_mark_get_buffer (mark))do { if ((get_buffer (text_view) == ctk_text_mark_get_buffer (
mark))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "get_buffer (text_view) == ctk_text_mark_get_buffer (mark)"
); return; } } while (0)
;
2826
2827 ctk_text_view_scroll_to_mark (text_view, mark, 0.0, FALSE(0), 0.0, 0.0);
2828}
2829
2830static gboolean
2831clamp_iter_onscreen (CtkTextView *text_view, CtkTextIter *iter)
2832{
2833 CdkRectangle visible_rect;
2834 ctk_text_view_get_visible_rect (text_view, &visible_rect);
2835
2836 return ctk_text_layout_clamp_iter_to_vrange (text_view->priv->layout, iter,
2837 visible_rect.y,
2838 visible_rect.y + visible_rect.height);
2839}
2840
2841/**
2842 * ctk_text_view_move_mark_onscreen:
2843 * @text_view: a #CtkTextView
2844 * @mark: a #CtkTextMark
2845 *
2846 * Moves a mark within the buffer so that it's
2847 * located within the currently-visible text area.
2848 *
2849 * Returns: %TRUE if the mark moved (wasn’t already onscreen)
2850 **/
2851gboolean
2852ctk_text_view_move_mark_onscreen (CtkTextView *text_view,
2853 CtkTextMark *mark)
2854{
2855 CtkTextIter iter;
2856
2857 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
2858 g_return_val_if_fail (mark != NULL, FALSE)do { if ((mark != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "mark != NULL"); return (
(0)); } } while (0)
;
2859
2860 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
2861
2862 if (clamp_iter_onscreen (text_view, &iter))
2863 {
2864 ctk_text_buffer_move_mark (get_buffer (text_view), mark, &iter);
2865 return TRUE(!(0));
2866 }
2867 else
2868 return FALSE(0);
2869}
2870
2871/**
2872 * ctk_text_view_get_visible_rect:
2873 * @text_view: a #CtkTextView
2874 * @visible_rect: (out): rectangle to fill
2875 *
2876 * Fills @visible_rect with the currently-visible
2877 * region of the buffer, in buffer coordinates. Convert to window coordinates
2878 * with ctk_text_view_buffer_to_window_coords().
2879 **/
2880void
2881ctk_text_view_get_visible_rect (CtkTextView *text_view,
2882 CdkRectangle *visible_rect)
2883{
2884 CtkWidget *widget;
2885
2886 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
2887
2888 widget = CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
;
2889
2890 if (visible_rect)
2891 {
2892 visible_rect->x = text_view->priv->xoffset;
2893 visible_rect->y = text_view->priv->yoffset;
2894 visible_rect->width = SCREEN_WIDTH (widget)text_window_get_width (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_text_view_get_type ())))
)))->priv->text_window)
;
2895 visible_rect->height = SCREEN_HEIGHT (widget)text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_text_view_get_type ())))
)))->priv->text_window)
;
2896
2897 DV(g_print(" visible rect: %d,%d %d x %d\n",
2898 visible_rect->x,
2899 visible_rect->y,
2900 visible_rect->width,
2901 visible_rect->height));
2902 }
2903}
2904
2905/**
2906 * ctk_text_view_set_wrap_mode:
2907 * @text_view: a #CtkTextView
2908 * @wrap_mode: a #CtkWrapMode
2909 *
2910 * Sets the line wrapping for the view.
2911 **/
2912void
2913ctk_text_view_set_wrap_mode (CtkTextView *text_view,
2914 CtkWrapMode wrap_mode)
2915{
2916 CtkTextViewPrivate *priv;
2917
2918 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
2919
2920 priv = text_view->priv;
2921
2922 if (priv->wrap_mode != wrap_mode)
2923 {
2924 priv->wrap_mode = wrap_mode;
2925
2926 if (priv->layout && priv->layout->default_style)
2927 {
2928 priv->layout->default_style->wrap_mode = wrap_mode;
2929 ctk_text_layout_default_style_changed (priv->layout);
2930 }
2931 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "wrap-mode");
2932 }
2933}
2934
2935/**
2936 * ctk_text_view_get_wrap_mode:
2937 * @text_view: a #CtkTextView
2938 *
2939 * Gets the line wrapping for the view.
2940 *
2941 * Returns: the line wrap setting
2942 **/
2943CtkWrapMode
2944ctk_text_view_get_wrap_mode (CtkTextView *text_view)
2945{
2946 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), CTK_WRAP_NONE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (CTK_WRAP_NONE); }
} while (0)
;
2947
2948 return text_view->priv->wrap_mode;
2949}
2950
2951/**
2952 * ctk_text_view_set_editable:
2953 * @text_view: a #CtkTextView
2954 * @setting: whether it’s editable
2955 *
2956 * Sets the default editability of the #CtkTextView. You can override
2957 * this default setting with tags in the buffer, using the “editable”
2958 * attribute of tags.
2959 **/
2960void
2961ctk_text_view_set_editable (CtkTextView *text_view,
2962 gboolean setting)
2963{
2964 CtkTextViewPrivate *priv;
2965
2966 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
2967
2968 priv = text_view->priv;
2969 setting = setting != FALSE(0);
2970
2971 if (priv->editable != setting)
2972 {
2973 if (!setting)
2974 {
2975 ctk_text_view_reset_im_context(text_view);
2976 if (ctk_widget_has_focus (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
2977 ctk_im_context_focus_out (priv->im_context);
2978 }
2979
2980 priv->editable = setting;
2981
2982 if (setting && ctk_widget_has_focus (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
2983 ctk_im_context_focus_in (priv->im_context);
2984
2985 if (priv->layout && priv->layout->default_style)
2986 {
2987 ctk_text_layout_set_overwrite_mode (priv->layout,
2988 priv->overwrite_mode && priv->editable);
2989 priv->layout->default_style->editable = priv->editable;
2990 ctk_text_layout_default_style_changed (priv->layout);
2991 }
2992
2993 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "editable");
2994 }
2995}
2996
2997/**
2998 * ctk_text_view_get_editable:
2999 * @text_view: a #CtkTextView
3000 *
3001 * Returns the default editability of the #CtkTextView. Tags in the
3002 * buffer may override this setting for some ranges of text.
3003 *
3004 * Returns: whether text is editable by default
3005 **/
3006gboolean
3007ctk_text_view_get_editable (CtkTextView *text_view)
3008{
3009 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
3010
3011 return text_view->priv->editable;
3012}
3013
3014/**
3015 * ctk_text_view_set_pixels_above_lines:
3016 * @text_view: a #CtkTextView
3017 * @pixels_above_lines: pixels above paragraphs
3018 *
3019 * Sets the default number of blank pixels above paragraphs in @text_view.
3020 * Tags in the buffer for @text_view may override the defaults.
3021 **/
3022void
3023ctk_text_view_set_pixels_above_lines (CtkTextView *text_view,
3024 gint pixels_above_lines)
3025{
3026 CtkTextViewPrivate *priv;
3027
3028 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3029
3030 priv = text_view->priv;
3031
3032 if (priv->pixels_above_lines != pixels_above_lines)
3033 {
3034 priv->pixels_above_lines = pixels_above_lines;
3035
3036 if (priv->layout && priv->layout->default_style)
3037 {
3038 priv->layout->default_style->pixels_above_lines = pixels_above_lines;
3039 ctk_text_layout_default_style_changed (priv->layout);
3040 }
3041
3042 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "pixels-above-lines");
3043 }
3044}
3045
3046/**
3047 * ctk_text_view_get_pixels_above_lines:
3048 * @text_view: a #CtkTextView
3049 *
3050 * Gets the default number of pixels to put above paragraphs.
3051 * Adding this function with ctk_text_view_get_pixels_below_lines()
3052 * is equal to the line space between each paragraph.
3053 *
3054 * Returns: default number of pixels above paragraphs
3055 **/
3056gint
3057ctk_text_view_get_pixels_above_lines (CtkTextView *text_view)
3058{
3059 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (0); } } while (0
)
;
3060
3061 return text_view->priv->pixels_above_lines;
3062}
3063
3064/**
3065 * ctk_text_view_set_pixels_below_lines:
3066 * @text_view: a #CtkTextView
3067 * @pixels_below_lines: pixels below paragraphs
3068 *
3069 * Sets the default number of pixels of blank space
3070 * to put below paragraphs in @text_view. May be overridden
3071 * by tags applied to @text_view’s buffer.
3072 **/
3073void
3074ctk_text_view_set_pixels_below_lines (CtkTextView *text_view,
3075 gint pixels_below_lines)
3076{
3077 CtkTextViewPrivate *priv;
3078
3079 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3080
3081 priv = text_view->priv;
3082
3083 if (priv->pixels_below_lines != pixels_below_lines)
3084 {
3085 priv->pixels_below_lines = pixels_below_lines;
3086
3087 if (priv->layout && priv->layout->default_style)
3088 {
3089 priv->layout->default_style->pixels_below_lines = pixels_below_lines;
3090 ctk_text_layout_default_style_changed (priv->layout);
3091 }
3092
3093 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "pixels-below-lines");
3094 }
3095}
3096
3097/**
3098 * ctk_text_view_get_pixels_below_lines:
3099 * @text_view: a #CtkTextView
3100 *
3101 * Gets the value set by ctk_text_view_set_pixels_below_lines().
3102 *
3103 * The line space is the sum of the value returned by this function and the
3104 * value returned by ctk_text_view_get_pixels_above_lines().
3105 *
3106 * Returns: default number of blank pixels below paragraphs
3107 **/
3108gint
3109ctk_text_view_get_pixels_below_lines (CtkTextView *text_view)
3110{
3111 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (0); } } while (0
)
;
3112
3113 return text_view->priv->pixels_below_lines;
3114}
3115
3116/**
3117 * ctk_text_view_set_pixels_inside_wrap:
3118 * @text_view: a #CtkTextView
3119 * @pixels_inside_wrap: default number of pixels between wrapped lines
3120 *
3121 * Sets the default number of pixels of blank space to leave between
3122 * display/wrapped lines within a paragraph. May be overridden by
3123 * tags in @text_view’s buffer.
3124 **/
3125void
3126ctk_text_view_set_pixels_inside_wrap (CtkTextView *text_view,
3127 gint pixels_inside_wrap)
3128{
3129 CtkTextViewPrivate *priv;
3130
3131 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3132
3133 priv = text_view->priv;
3134
3135 if (priv->pixels_inside_wrap != pixels_inside_wrap)
3136 {
3137 priv->pixels_inside_wrap = pixels_inside_wrap;
3138
3139 if (priv->layout && priv->layout->default_style)
3140 {
3141 priv->layout->default_style->pixels_inside_wrap = pixels_inside_wrap;
3142 ctk_text_layout_default_style_changed (priv->layout);
3143 }
3144
3145 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "pixels-inside-wrap");
3146 }
3147}
3148
3149/**
3150 * ctk_text_view_get_pixels_inside_wrap:
3151 * @text_view: a #CtkTextView
3152 *
3153 * Gets the value set by ctk_text_view_set_pixels_inside_wrap().
3154 *
3155 * Returns: default number of pixels of blank space between wrapped lines
3156 **/
3157gint
3158ctk_text_view_get_pixels_inside_wrap (CtkTextView *text_view)
3159{
3160 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (0); } } while (0
)
;
3161
3162 return text_view->priv->pixels_inside_wrap;
3163}
3164
3165/**
3166 * ctk_text_view_set_justification:
3167 * @text_view: a #CtkTextView
3168 * @justification: justification
3169 *
3170 * Sets the default justification of text in @text_view.
3171 * Tags in the view’s buffer may override the default.
3172 *
3173 **/
3174void
3175ctk_text_view_set_justification (CtkTextView *text_view,
3176 CtkJustification justification)
3177{
3178 CtkTextViewPrivate *priv;
3179
3180 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3181
3182 priv = text_view->priv;
3183
3184 if (priv->justify != justification)
3185 {
3186 priv->justify = justification;
3187
3188 if (priv->layout && priv->layout->default_style)
3189 {
3190 priv->layout->default_style->justification = justification;
3191 ctk_text_layout_default_style_changed (priv->layout);
3192 }
3193
3194 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "justification");
3195 }
3196}
3197
3198/**
3199 * ctk_text_view_get_justification:
3200 * @text_view: a #CtkTextView
3201 *
3202 * Gets the default justification of paragraphs in @text_view.
3203 * Tags in the buffer may override the default.
3204 *
3205 * Returns: default justification
3206 **/
3207CtkJustification
3208ctk_text_view_get_justification (CtkTextView *text_view)
3209{
3210 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), CTK_JUSTIFY_LEFT)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (CTK_JUSTIFY_LEFT
); } } while (0)
;
3211
3212 return text_view->priv->justify;
3213}
3214
3215/**
3216 * ctk_text_view_set_left_margin:
3217 * @text_view: a #CtkTextView
3218 * @left_margin: left margin in pixels
3219 *
3220 * Sets the default left margin for text in @text_view.
3221 * Tags in the buffer may override the default.
3222 *
3223 * Note that this function is confusingly named.
3224 * In CSS terms, the value set here is padding.
3225 */
3226void
3227ctk_text_view_set_left_margin (CtkTextView *text_view,
3228 gint left_margin)
3229{
3230 CtkTextViewPrivate *priv = text_view->priv;
3231
3232 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3233
3234 if (priv->left_margin != left_margin)
3235 {
3236 priv->left_margin = left_margin;
3237 priv->left_border = left_margin + priv->left_padding;
3238
3239 if (priv->layout && priv->layout->default_style)
3240 {
3241 priv->layout->default_style->left_margin = left_margin;
3242 ctk_text_layout_default_style_changed (priv->layout);
3243 }
3244
3245 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "left-margin");
3246 }
3247}
3248
3249/**
3250 * ctk_text_view_get_left_margin:
3251 * @text_view: a #CtkTextView
3252 *
3253 * Gets the default left margin size of paragraphs in the @text_view.
3254 * Tags in the buffer may override the default.
3255 *
3256 * Returns: left margin in pixels
3257 */
3258gint
3259ctk_text_view_get_left_margin (CtkTextView *text_view)
3260{
3261 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (0); } } while (0
)
;
3262
3263 return text_view->priv->left_margin;
3264}
3265
3266/**
3267 * ctk_text_view_set_right_margin:
3268 * @text_view: a #CtkTextView
3269 * @right_margin: right margin in pixels
3270 *
3271 * Sets the default right margin for text in the text view.
3272 * Tags in the buffer may override the default.
3273 *
3274 * Note that this function is confusingly named.
3275 * In CSS terms, the value set here is padding.
3276 */
3277void
3278ctk_text_view_set_right_margin (CtkTextView *text_view,
3279 gint right_margin)
3280{
3281 CtkTextViewPrivate *priv = text_view->priv;
3282
3283 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3284
3285 if (priv->right_margin != right_margin)
3286 {
3287 priv->right_margin = right_margin;
3288 priv->right_border = right_margin + priv->right_padding;
3289
3290 if (priv->layout && priv->layout->default_style)
3291 {
3292 priv->layout->default_style->right_margin = right_margin;
3293 ctk_text_layout_default_style_changed (priv->layout);
3294 }
3295
3296 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "right-margin");
3297 }
3298}
3299
3300/**
3301 * ctk_text_view_get_right_margin:
3302 * @text_view: a #CtkTextView
3303 *
3304 * Gets the default right margin for text in @text_view. Tags
3305 * in the buffer may override the default.
3306 *
3307 * Returns: right margin in pixels
3308 */
3309gint
3310ctk_text_view_get_right_margin (CtkTextView *text_view)
3311{
3312 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (0); } } while (0
)
;
3313
3314 return text_view->priv->right_margin;
3315}
3316
3317/**
3318 * ctk_text_view_set_top_margin:
3319 * @text_view: a #CtkTextView
3320 * @top_margin: top margin in pixels
3321 *
3322 * Sets the top margin for text in @text_view.
3323 *
3324 * Note that this function is confusingly named.
3325 * In CSS terms, the value set here is padding.
3326 *
3327 * Since: 3.18
3328 */
3329void
3330ctk_text_view_set_top_margin (CtkTextView *text_view,
3331 gint top_margin)
3332{
3333 CtkTextViewPrivate *priv = text_view->priv;
3334
3335 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3336
3337 if (priv->top_margin != top_margin)
3338 {
3339 priv->yoffset += priv->top_margin - top_margin;
3340
3341 priv->top_margin = top_margin;
3342 priv->top_border = top_margin + priv->top_padding;
3343
3344 if (priv->layout && priv->layout->default_style)
3345 ctk_text_layout_default_style_changed (priv->layout);
3346
3347 ctk_text_view_invalidate (text_view);
3348
3349 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "top-margin");
3350 }
3351}
3352
3353/**
3354 * ctk_text_view_get_top_margin:
3355 * @text_view: a #CtkTextView
3356 *
3357 * Gets the top margin for text in the @text_view.
3358 *
3359 * Returns: top margin in pixels
3360 *
3361 * Since: 3.18
3362 **/
3363gint
3364ctk_text_view_get_top_margin (CtkTextView *text_view)
3365{
3366 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (0); } } while (0
)
;
3367
3368 return text_view->priv->top_margin;
3369}
3370
3371/**
3372 * ctk_text_view_set_bottom_margin:
3373 * @text_view: a #CtkTextView
3374 * @bottom_margin: bottom margin in pixels
3375 *
3376 * Sets the bottom margin for text in @text_view.
3377 *
3378 * Note that this function is confusingly named.
3379 * In CSS terms, the value set here is padding.
3380 *
3381 * Since: 3.18
3382 */
3383void
3384ctk_text_view_set_bottom_margin (CtkTextView *text_view,
3385 gint bottom_margin)
3386{
3387 CtkTextViewPrivate *priv = text_view->priv;
3388
3389 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3390
3391 if (priv->bottom_margin != bottom_margin)
3392 {
3393 priv->bottom_margin = bottom_margin;
3394 priv->bottom_border = bottom_margin + priv->bottom_padding;
3395
3396 if (priv->layout && priv->layout->default_style)
3397 ctk_text_layout_default_style_changed (priv->layout);
3398
3399 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "bottom-margin");
3400 }
3401}
3402
3403/**
3404 * ctk_text_view_get_bottom_margin:
3405 * @text_view: a #CtkTextView
3406 *
3407 * Gets the bottom margin for text in the @text_view.
3408 *
3409 * Returns: bottom margin in pixels
3410 *
3411 * Since: 3.18
3412 */
3413gint
3414ctk_text_view_get_bottom_margin (CtkTextView *text_view)
3415{
3416 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (0); } } while (0
)
;
3417
3418 return text_view->priv->bottom_margin;
3419}
3420
3421/**
3422 * ctk_text_view_set_indent:
3423 * @text_view: a #CtkTextView
3424 * @indent: indentation in pixels
3425 *
3426 * Sets the default indentation for paragraphs in @text_view.
3427 * Tags in the buffer may override the default.
3428 **/
3429void
3430ctk_text_view_set_indent (CtkTextView *text_view,
3431 gint indent)
3432{
3433 CtkTextViewPrivate *priv;
3434
3435 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3436
3437 priv = text_view->priv;
3438
3439 if (priv->indent != indent)
3440 {
3441 priv->indent = indent;
3442
3443 if (priv->layout && priv->layout->default_style)
3444 {
3445 priv->layout->default_style->indent = indent;
3446 ctk_text_layout_default_style_changed (priv->layout);
3447 }
3448
3449 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "indent");
3450 }
3451}
3452
3453/**
3454 * ctk_text_view_get_indent:
3455 * @text_view: a #CtkTextView
3456 *
3457 * Gets the default indentation of paragraphs in @text_view.
3458 * Tags in the view’s buffer may override the default.
3459 * The indentation may be negative.
3460 *
3461 * Returns: number of pixels of indentation
3462 **/
3463gint
3464ctk_text_view_get_indent (CtkTextView *text_view)
3465{
3466 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (0); } } while (0
)
;
3467
3468 return text_view->priv->indent;
3469}
3470
3471/**
3472 * ctk_text_view_set_tabs:
3473 * @text_view: a #CtkTextView
3474 * @tabs: tabs as a #PangoTabArray
3475 *
3476 * Sets the default tab stops for paragraphs in @text_view.
3477 * Tags in the buffer may override the default.
3478 **/
3479void
3480ctk_text_view_set_tabs (CtkTextView *text_view,
3481 PangoTabArray *tabs)
3482{
3483 CtkTextViewPrivate *priv;
3484
3485 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3486
3487 priv = text_view->priv;
3488
3489 if (priv->tabs)
3490 pango_tab_array_free (priv->tabs);
3491
3492 priv->tabs = tabs ? pango_tab_array_copy (tabs) : NULL((void*)0);
3493
3494 if (priv->layout && priv->layout->default_style)
3495 {
3496 /* some unkosher futzing in internal struct details... */
3497 if (priv->layout->default_style->tabs)
3498 pango_tab_array_free (priv->layout->default_style->tabs);
3499
3500 priv->layout->default_style->tabs =
3501 priv->tabs ? pango_tab_array_copy (priv->tabs) : NULL((void*)0);
3502
3503 ctk_text_layout_default_style_changed (priv->layout);
3504 }
3505
3506 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "tabs");
3507}
3508
3509/**
3510 * ctk_text_view_get_tabs:
3511 * @text_view: a #CtkTextView
3512 *
3513 * Gets the default tabs for @text_view. Tags in the buffer may
3514 * override the defaults. The returned array will be %NULL if
3515 * “standard” (8-space) tabs are used. Free the return value
3516 * with pango_tab_array_free().
3517 *
3518 * Returns: (nullable) (transfer full): copy of default tab array, or %NULL if
3519 * “standard" tabs are used; must be freed with pango_tab_array_free().
3520 **/
3521PangoTabArray*
3522ctk_text_view_get_tabs (CtkTextView *text_view)
3523{
3524 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (((void*)0)); } }
while (0)
;
3525
3526 return text_view->priv->tabs ? pango_tab_array_copy (text_view->priv->tabs) : NULL((void*)0);
3527}
3528
3529static void
3530ctk_text_view_toggle_cursor_visible (CtkTextView *text_view)
3531{
3532 ctk_text_view_set_cursor_visible (text_view, !text_view->priv->cursor_visible);
3533}
3534
3535/**
3536 * ctk_text_view_set_cursor_visible:
3537 * @text_view: a #CtkTextView
3538 * @setting: whether to show the insertion cursor
3539 *
3540 * Toggles whether the insertion point should be displayed. A buffer with
3541 * no editable text probably shouldn’t have a visible cursor, so you may
3542 * want to turn the cursor off.
3543 *
3544 * Note that this property may be overridden by the
3545 * #CtkSettings:ctk-keynave-use-caret settings.
3546 */
3547void
3548ctk_text_view_set_cursor_visible (CtkTextView *text_view,
3549 gboolean setting)
3550{
3551 CtkTextViewPrivate *priv;
3552
3553 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3554
3555 priv = text_view->priv;
3556 setting = (setting != FALSE(0));
3557
3558 if (priv->cursor_visible != setting)
3559 {
3560 priv->cursor_visible = setting;
3561
3562 if (ctk_widget_has_focus (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
3563 {
3564 if (priv->layout)
3565 {
3566 ctk_text_layout_set_cursor_visible (priv->layout, setting);
3567 ctk_text_view_check_cursor_blink (text_view);
3568 }
3569 }
3570
3571 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "cursor-visible");
3572 }
3573}
3574
3575/**
3576 * ctk_text_view_get_cursor_visible:
3577 * @text_view: a #CtkTextView
3578 *
3579 * Find out whether the cursor should be displayed.
3580 *
3581 * Returns: whether the insertion mark is visible
3582 */
3583gboolean
3584ctk_text_view_get_cursor_visible (CtkTextView *text_view)
3585{
3586 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
3587
3588 return text_view->priv->cursor_visible;
3589}
3590
3591/**
3592 * ctk_text_view_reset_cursor_blink:
3593 * @text_view: a #CtkTextView
3594 *
3595 * Ensures that the cursor is shown (i.e. not in an 'off' blink
3596 * interval) and resets the time that it will stay blinking (or
3597 * visible, in case blinking is disabled).
3598 *
3599 * This function should be called in response to user input
3600 * (e.g. from derived classes that override the textview's
3601 * #CtkWidget::key-press-event handler).
3602 *
3603 * Since: 3.20
3604 */
3605void
3606ctk_text_view_reset_cursor_blink (CtkTextView *text_view)
3607{
3608 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
3609
3610 ctk_text_view_reset_blink_time (text_view);
3611 ctk_text_view_pend_cursor_blink (text_view);
3612}
3613
3614/**
3615 * ctk_text_view_place_cursor_onscreen:
3616 * @text_view: a #CtkTextView
3617 *
3618 * Moves the cursor to the currently visible region of the
3619 * buffer, it it isn’t there already.
3620 *
3621 * Returns: %TRUE if the cursor had to be moved.
3622 **/
3623gboolean
3624ctk_text_view_place_cursor_onscreen (CtkTextView *text_view)
3625{
3626 CtkTextIter insert;
3627
3628 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
3629
3630 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
3631 ctk_text_buffer_get_insert (get_buffer (text_view)));
3632
3633 if (clamp_iter_onscreen (text_view, &insert))
3634 {
3635 ctk_text_buffer_place_cursor (get_buffer (text_view), &insert);
3636 return TRUE(!(0));
3637 }
3638 else
3639 return FALSE(0);
3640}
3641
3642static void
3643ctk_text_view_remove_validate_idles (CtkTextView *text_view)
3644{
3645 CtkTextViewPrivate *priv = text_view->priv;
3646
3647 if (priv->first_validate_idle != 0)
3648 {
3649 DV (g_print ("Removing first validate idle: %s\n", G_STRLOC));
3650 g_source_remove (priv->first_validate_idle);
3651 priv->first_validate_idle = 0;
3652 }
3653
3654 if (priv->incremental_validate_idle != 0)
3655 {
3656 g_source_remove (priv->incremental_validate_idle);
3657 priv->incremental_validate_idle = 0;
3658 }
3659}
3660
3661static void
3662ctk_text_view_destroy (CtkWidget *widget)
3663{
3664 CtkTextView *text_view;
3665 CtkTextViewPrivate *priv;
3666
3667 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
3668 priv = text_view->priv;
3669
3670 ctk_text_view_remove_validate_idles (text_view);
3671 ctk_text_view_set_buffer (text_view, NULL((void*)0));
3672 ctk_text_view_destroy_layout (text_view);
3673
3674 if (text_view->priv->scroll_timeout)
3675 {
3676 g_source_remove (text_view->priv->scroll_timeout);
3677 text_view->priv->scroll_timeout = 0;
3678 }
3679
3680 if (priv->im_spot_idle)
3681 {
3682 g_source_remove (priv->im_spot_idle);
3683 priv->im_spot_idle = 0;
3684 }
3685
3686 if (priv->pixel_cache)
3687 {
3688 _ctk_pixel_cache_free (priv->pixel_cache);
3689 priv->pixel_cache = NULL((void*)0);
3690 }
3691
3692 if (priv->magnifier)
3693 _ctk_magnifier_set_inspected (CTK_MAGNIFIER (priv->magnifier)((((CtkMagnifier*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->magnifier)), ((_ctk_magnifier_get_type ()))))))
, NULL((void*)0));
3694
3695 CTK_WIDGET_CLASS (ctk_text_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), ((ctk_widget_get_type ()))
))))
->destroy (widget);
3696}
3697
3698static void
3699ctk_text_view_finalize (GObject *object)
3700{
3701 CtkTextView *text_view;
3702 CtkTextViewPrivate *priv;
3703
3704 text_view = CTK_TEXT_VIEW (object)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_text_view_get_type ()))))))
;
3705 priv = text_view->priv;
3706
3707 ctk_text_view_destroy_layout (text_view);
3708 ctk_text_view_set_buffer (text_view, NULL((void*)0));
3709
3710 /* at this point, no "notify::buffer" handler should recreate the buffer. */
3711 g_assert (priv->buffer == NULL)do { if (priv->buffer == ((void*)0)) ; else g_assertion_message_expr
("Ctk", "ctktextview.c", 3711, ((const char*) (__func__)), "priv->buffer == NULL"
); } while (0)
;
3712
3713 cancel_pending_scroll (text_view);
3714
3715 g_object_unref (priv->multipress_gesture);
3716 g_object_unref (priv->drag_gesture);
3717
3718 if (priv->tabs)
3719 pango_tab_array_free (priv->tabs);
3720
3721 if (priv->hadjustment)
3722 g_object_unref (priv->hadjustment);
3723 if (priv->vadjustment)
3724 g_object_unref (priv->vadjustment);
3725
3726 text_window_free (priv->text_window);
3727
3728 if (priv->left_window)
3729 text_window_free (priv->left_window);
3730
3731 if (priv->top_window)
3732 text_window_free (priv->top_window);
3733
3734 if (priv->right_window)
3735 text_window_free (priv->right_window);
3736
3737 if (priv->bottom_window)
3738 text_window_free (priv->bottom_window);
3739
3740 if (priv->selection_bubble)
3741 ctk_widget_destroy (priv->selection_bubble);
3742
3743 if (priv->magnifier_popover)
3744 ctk_widget_destroy (priv->magnifier_popover);
3745 if (priv->text_handle)
3746 g_object_unref (priv->text_handle);
3747 g_object_unref (priv->im_context);
3748
3749 g_free (priv->im_module);
3750
3751 G_OBJECT_CLASS (ctk_text_view_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), (((GType) ((20) << (
2))))))))
->finalize (object);
3752}
3753
3754static void
3755ctk_text_view_set_property (GObject *object,
3756 guint prop_id,
3757 const GValue *value,
3758 GParamSpec *pspec)
3759{
3760 CtkTextView *text_view;
3761 CtkTextViewPrivate *priv;
3762
3763 text_view = CTK_TEXT_VIEW (object)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_text_view_get_type ()))))))
;
3764 priv = text_view->priv;
3765
3766 switch (prop_id)
3767 {
3768 case PROP_PIXELS_ABOVE_LINES:
3769 ctk_text_view_set_pixels_above_lines (text_view, g_value_get_int (value));
3770 break;
3771
3772 case PROP_PIXELS_BELOW_LINES:
3773 ctk_text_view_set_pixels_below_lines (text_view, g_value_get_int (value));
3774 break;
3775
3776 case PROP_PIXELS_INSIDE_WRAP:
3777 ctk_text_view_set_pixels_inside_wrap (text_view, g_value_get_int (value));
3778 break;
3779
3780 case PROP_EDITABLE:
3781 ctk_text_view_set_editable (text_view, g_value_get_boolean (value));
3782 break;
3783
3784 case PROP_WRAP_MODE:
3785 ctk_text_view_set_wrap_mode (text_view, g_value_get_enum (value));
3786 break;
3787
3788 case PROP_JUSTIFICATION:
3789 ctk_text_view_set_justification (text_view, g_value_get_enum (value));
3790 break;
3791
3792 case PROP_LEFT_MARGIN:
3793 ctk_text_view_set_left_margin (text_view, g_value_get_int (value));
3794 break;
3795
3796 case PROP_RIGHT_MARGIN:
3797 ctk_text_view_set_right_margin (text_view, g_value_get_int (value));
3798 break;
3799
3800 case PROP_TOP_MARGIN:
3801 ctk_text_view_set_top_margin (text_view, g_value_get_int (value));
3802 break;
3803
3804 case PROP_BOTTOM_MARGIN:
3805 ctk_text_view_set_bottom_margin (text_view, g_value_get_int (value));
3806 break;
3807
3808 case PROP_INDENT:
3809 ctk_text_view_set_indent (text_view, g_value_get_int (value));
3810 break;
3811
3812 case PROP_TABS:
3813 ctk_text_view_set_tabs (text_view, g_value_get_boxed (value));
3814 break;
3815
3816 case PROP_CURSOR_VISIBLE:
3817 ctk_text_view_set_cursor_visible (text_view, g_value_get_boolean (value));
3818 break;
3819
3820 case PROP_OVERWRITE:
3821 ctk_text_view_set_overwrite (text_view, g_value_get_boolean (value));
3822 break;
3823
3824 case PROP_BUFFER:
3825 ctk_text_view_set_buffer (text_view, CTK_TEXT_BUFFER (g_value_get_object (value))((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_value_get_object (value))), ((ctk_text_buffer_get_type
()))))))
);
3826 break;
3827
3828 case PROP_ACCEPTS_TAB:
3829 ctk_text_view_set_accepts_tab (text_view, g_value_get_boolean (value));
3830 break;
3831
3832 case PROP_IM_MODULE:
3833 g_free (priv->im_module);
3834 priv->im_module = g_value_dup_string (value);
3835 if (CTK_IS_IM_MULTICONTEXT (priv->im_context)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(priv->im_context)); GType __t = ((ctk_im_multicontext_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; }))))
)
3836 ctk_im_multicontext_set_context_id (CTK_IM_MULTICONTEXT (priv->im_context)((((CtkIMMulticontext*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((priv->im_context)), ((ctk_im_multicontext_get_type
()))))))
, priv->im_module);
3837 break;
3838
3839 case PROP_HADJUSTMENT:
3840 ctk_text_view_set_hadjustment (text_view, g_value_get_object (value));
3841 break;
3842
3843 case PROP_VADJUSTMENT:
3844 ctk_text_view_set_vadjustment (text_view, g_value_get_object (value));
3845 break;
3846
3847 case PROP_HSCROLL_POLICY:
3848 if (priv->hscroll_policy != g_value_get_enum (value))
3849 {
3850 priv->hscroll_policy = g_value_get_enum (value);
3851 ctk_widget_queue_resize (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
3852 g_object_notify_by_pspec (object, pspec);
3853 }
3854 break;
3855
3856 case PROP_VSCROLL_POLICY:
3857 if (priv->vscroll_policy != g_value_get_enum (value))
3858 {
3859 priv->vscroll_policy = g_value_get_enum (value);
3860 ctk_widget_queue_resize (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
3861 g_object_notify_by_pspec (object, pspec);
3862 }
3863 break;
3864
3865 case PROP_INPUT_PURPOSE:
3866 ctk_text_view_set_input_purpose (text_view, g_value_get_enum (value));
3867 break;
3868
3869 case PROP_INPUT_HINTS:
3870 ctk_text_view_set_input_hints (text_view, g_value_get_flags (value));
3871 break;
3872
3873 case PROP_POPULATE_ALL:
3874 if (text_view->priv->populate_all != g_value_get_boolean (value))
3875 {
3876 text_view->priv->populate_all = g_value_get_boolean (value);
3877 g_object_notify_by_pspec (object, pspec);
3878 }
3879 break;
3880 case PROP_MONOSPACE:
3881 ctk_text_view_set_monospace (text_view, g_value_get_boolean (value));
3882 break;
3883
3884 default:
3885 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'"
, "ctktextview.c", 3885, ("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)
;
3886 break;
3887 }
3888}
3889
3890static void
3891ctk_text_view_get_property (GObject *object,
3892 guint prop_id,
3893 GValue *value,
3894 GParamSpec *pspec)
3895{
3896 CtkTextView *text_view;
3897 CtkTextViewPrivate *priv;
3898
3899 text_view = CTK_TEXT_VIEW (object)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_text_view_get_type ()))))))
;
3900 priv = text_view->priv;
3901
3902 switch (prop_id)
3903 {
3904 case PROP_PIXELS_ABOVE_LINES:
3905 g_value_set_int (value, priv->pixels_above_lines);
3906 break;
3907
3908 case PROP_PIXELS_BELOW_LINES:
3909 g_value_set_int (value, priv->pixels_below_lines);
3910 break;
3911
3912 case PROP_PIXELS_INSIDE_WRAP:
3913 g_value_set_int (value, priv->pixels_inside_wrap);
3914 break;
3915
3916 case PROP_EDITABLE:
3917 g_value_set_boolean (value, priv->editable);
3918 break;
3919
3920 case PROP_WRAP_MODE:
3921 g_value_set_enum (value, priv->wrap_mode);
3922 break;
3923
3924 case PROP_JUSTIFICATION:
3925 g_value_set_enum (value, priv->justify);
3926 break;
3927
3928 case PROP_LEFT_MARGIN:
3929 g_value_set_int (value, priv->left_margin);
3930 break;
3931
3932 case PROP_RIGHT_MARGIN:
3933 g_value_set_int (value, priv->right_margin);
3934 break;
3935
3936 case PROP_TOP_MARGIN:
3937 g_value_set_int (value, priv->top_margin);
3938 break;
3939
3940 case PROP_BOTTOM_MARGIN:
3941 g_value_set_int (value, priv->bottom_margin);
3942 break;
3943
3944 case PROP_INDENT:
3945 g_value_set_int (value, priv->indent);
3946 break;
3947
3948 case PROP_TABS:
3949 g_value_set_boxed (value, priv->tabs);
3950 break;
3951
3952 case PROP_CURSOR_VISIBLE:
3953 g_value_set_boolean (value, priv->cursor_visible);
3954 break;
3955
3956 case PROP_BUFFER:
3957 g_value_set_object (value, get_buffer (text_view));
3958 break;
3959
3960 case PROP_OVERWRITE:
3961 g_value_set_boolean (value, priv->overwrite_mode);
3962 break;
3963
3964 case PROP_ACCEPTS_TAB:
3965 g_value_set_boolean (value, priv->accepts_tab);
3966 break;
3967
3968 case PROP_IM_MODULE:
3969 g_value_set_string (value, priv->im_module);
3970 break;
3971
3972 case PROP_HADJUSTMENT:
3973 g_value_set_object (value, priv->hadjustment);
3974 break;
3975
3976 case PROP_VADJUSTMENT:
3977 g_value_set_object (value, priv->vadjustment);
3978 break;
3979
3980 case PROP_HSCROLL_POLICY:
3981 g_value_set_enum (value, priv->hscroll_policy);
3982 break;
3983
3984 case PROP_VSCROLL_POLICY:
3985 g_value_set_enum (value, priv->vscroll_policy);
3986 break;
3987
3988 case PROP_INPUT_PURPOSE:
3989 g_value_set_enum (value, ctk_text_view_get_input_purpose (text_view));
3990 break;
3991
3992 case PROP_INPUT_HINTS:
3993 g_value_set_flags (value, ctk_text_view_get_input_hints (text_view));
3994 break;
3995
3996 case PROP_POPULATE_ALL:
3997 g_value_set_boolean (value, priv->populate_all);
3998 break;
3999
4000 case PROP_MONOSPACE:
4001 g_value_set_boolean (value, ctk_text_view_get_monospace (text_view));
4002 break;
4003
4004 default:
4005 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'"
, "ctktextview.c", 4005, ("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)
;
4006 break;
4007 }
4008}
4009
4010static void
4011ctk_text_view_size_request (CtkWidget *widget,
4012 CtkRequisition *requisition)
4013{
4014 CtkTextView *text_view;
4015 CtkTextViewPrivate *priv;
4016 GSList *tmp_list;
4017 guint border_width;
4018
4019 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
4020 priv = text_view->priv;
4021
4022 if (priv->layout)
4023 {
4024 priv->text_window->requisition.width = priv->layout->width;
4025 priv->text_window->requisition.height = priv->layout->height;
4026 }
4027 else
4028 {
4029 priv->text_window->requisition.width = 0;
4030 priv->text_window->requisition.height = 0;
4031 }
4032
4033 requisition->width = priv->text_window->requisition.width;
4034 requisition->height = priv->text_window->requisition.height;
4035
4036 if (priv->left_window)
4037 requisition->width += priv->left_window->requisition.width;
4038
4039 if (priv->right_window)
4040 requisition->width += priv->right_window->requisition.width;
4041
4042 if (priv->top_window)
4043 requisition->height += priv->top_window->requisition.height;
4044
4045 if (priv->bottom_window)
4046 requisition->height += priv->bottom_window->requisition.height;
4047
4048 border_width = ctk_container_get_border_width (CTK_CONTAINER (text_view)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_container_get_type ()))))))
);
4049 requisition->width += border_width * 2;
4050 requisition->height += border_width * 2;
4051
4052 requisition->height += priv->top_border + priv->bottom_border;
4053
4054 tmp_list = priv->children;
4055 while (tmp_list != NULL((void*)0))
4056 {
4057 CtkTextViewChild *child = tmp_list->data;
4058
4059 if (child->anchor)
4060 {
4061 CtkRequisition child_req;
4062 CtkRequisition old_req;
4063
4064 ctk_widget_get_preferred_size (child->widget, &old_req, NULL((void*)0));
4065
4066 ctk_widget_get_preferred_size (child->widget, &child_req, NULL((void*)0));
4067
4068 /* Invalidate layout lines if required */
4069 if (priv->layout &&
4070 (old_req.width != child_req.width ||
4071 old_req.height != child_req.height))
4072 ctk_text_child_anchor_queue_resize (child->anchor,
4073 priv->layout);
4074 }
4075 else
4076 {
4077 CtkRequisition child_req;
4078
4079 ctk_widget_get_preferred_size (child->widget,
4080 &child_req, NULL((void*)0));
4081 }
4082
4083 tmp_list = tmp_list->next;
4084 }
4085
4086 /* Cache the requested size of the text view so we can
4087 * compare it in the changed_handler() */
4088 priv->cached_size_request = *requisition;
4089}
4090
4091static void
4092ctk_text_view_get_preferred_width (CtkWidget *widget,
4093 gint *minimum,
4094 gint *natural)
4095{
4096 CtkRequisition requisition;
4097
4098 ctk_text_view_size_request (widget, &requisition);
4099
4100 *minimum = *natural = requisition.width;
4101}
4102
4103static void
4104ctk_text_view_get_preferred_height (CtkWidget *widget,
4105 gint *minimum,
4106 gint *natural)
4107{
4108 CtkRequisition requisition;
4109
4110 ctk_text_view_size_request (widget, &requisition);
4111
4112 *minimum = *natural = requisition.height;
4113}
4114
4115
4116static void
4117ctk_text_view_compute_child_allocation (CtkTextView *text_view,
4118 CtkTextViewChild *vc,
4119 CtkAllocation *allocation)
4120{
4121 gint buffer_y;
4122 CtkTextIter iter;
4123 CtkRequisition req;
4124
4125 ctk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
4126 &iter,
4127 vc->anchor);
4128
4129 ctk_text_layout_get_line_yrange (text_view->priv->layout, &iter,
4130 &buffer_y, NULL((void*)0));
4131
4132 buffer_y += vc->from_top_of_line;
4133
4134 allocation->x = vc->from_left_of_buffer - text_view->priv->xoffset;
4135 allocation->y = buffer_y - text_view->priv->yoffset;
4136
4137 ctk_widget_get_preferred_size (vc->widget, &req, NULL((void*)0));
4138 allocation->width = req.width;
4139 allocation->height = req.height;
4140}
4141
4142static void
4143ctk_text_view_update_child_allocation (CtkTextView *text_view,
4144 CtkTextViewChild *vc)
4145{
4146 CtkAllocation allocation;
4147
4148 ctk_text_view_compute_child_allocation (text_view, vc, &allocation);
4149
4150 ctk_widget_size_allocate (vc->widget, &allocation);
4151
4152#if 0
4153 g_print ("allocation for %p allocated to %d,%d yoffset = %d\n",
4154 vc->widget,
4155 vc->widget->allocation.x,
4156 vc->widget->allocation.y,
4157 text_view->priv->yoffset);
4158#endif
4159}
4160
4161static void
4162ctk_text_view_child_allocated (CtkTextLayout *layout G_GNUC_UNUSED__attribute__ ((__unused__)),
4163 CtkWidget *child,
4164 gint x,
4165 gint y,
4166 gpointer data)
4167{
4168 CtkTextViewChild *vc = NULL((void*)0);
4169 CtkTextView *text_view = data;
4170
4171 /* x,y is the position of the child from the top of the line, and
4172 * from the left of the buffer. We have to translate that into text
4173 * window coordinates, then size_allocate the child.
4174 */
4175
4176 vc = g_object_get_qdata (G_OBJECT (child)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), (((GType) ((20) << (2))))))))
, quark_text_view_child);
4177
4178 g_assert (vc != NULL)do { if (vc != ((void*)0)) ; else g_assertion_message_expr ("Ctk"
, "ctktextview.c", 4178, ((const char*) (__func__)), "vc != NULL"
); } while (0)
;
4179
4180 DV (g_print ("child allocated at %d,%d\n", x, y));
4181
4182 vc->from_left_of_buffer = x;
4183 vc->from_top_of_line = y;
4184
4185 ctk_text_view_update_child_allocation (text_view, vc);
4186}
4187
4188static void
4189ctk_text_view_allocate_children (CtkTextView *text_view)
4190{
4191 GSList *tmp_list;
4192
4193 DV(g_print(G_STRLOC"\n"));
4194
4195 tmp_list = text_view->priv->children;
4196 while (tmp_list != NULL((void*)0))
4197 {
4198 CtkTextViewChild *child = tmp_list->data;
4199
4200 g_assert (child != NULL)do { if (child != ((void*)0)) ; else g_assertion_message_expr
("Ctk", "ctktextview.c", 4200, ((const char*) (__func__)), "child != NULL"
); } while (0)
;
4201
4202 if (child->anchor)
4203 {
4204 /* We need to force-validate the regions containing
4205 * children.
4206 */
4207 CtkTextIter child_loc;
4208 ctk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
4209 &child_loc,
4210 child->anchor);
4211
4212 /* Since anchored children are only ever allocated from
4213 * ctk_text_layout_get_line_display() we have to make sure
4214 * that the display line caching in the layout doesn't
4215 * get in the way. Invalidating the layout around the anchor
4216 * achieves this.
4217 */
4218 if (_ctk_widget_get_alloc_needed (child->widget))
4219 {
4220 CtkTextIter end = child_loc;
4221 ctk_text_iter_forward_char (&end);
4222 ctk_text_layout_invalidate (text_view->priv->layout, &child_loc, &end);
4223 }
4224
4225 ctk_text_layout_validate_yrange (text_view->priv->layout,
4226 &child_loc,
4227 0, 1);
4228 }
4229 else
4230 {
4231 CtkAllocation allocation;
4232 CtkRequisition child_req;
4233
4234 allocation.x = child->x;
4235 allocation.y = child->y;
4236
4237 if (child->type == CTK_TEXT_WINDOW_TEXT ||
4238 child->type == CTK_TEXT_WINDOW_LEFT ||
4239 child->type == CTK_TEXT_WINDOW_RIGHT)
4240 allocation.y -= text_view->priv->yoffset;
4241 if (child->type == CTK_TEXT_WINDOW_TEXT ||
4242 child->type == CTK_TEXT_WINDOW_TOP ||
4243 child->type == CTK_TEXT_WINDOW_BOTTOM)
4244 allocation.x -= text_view->priv->xoffset;
4245
4246 ctk_widget_get_preferred_size (child->widget, &child_req, NULL((void*)0));
4247
4248 allocation.width = child_req.width;
4249 allocation.height = child_req.height;
4250
4251 ctk_widget_size_allocate (child->widget, &allocation);
4252 }
4253
4254 tmp_list = tmp_list->next;
4255 }
4256}
4257
4258static void
4259ctk_text_view_size_allocate (CtkWidget *widget,
4260 CtkAllocation *allocation)
4261{
4262 CtkAllocation widget_allocation;
4263 CtkTextView *text_view;
4264 CtkTextViewPrivate *priv;
4265 gint width, height;
4266 CdkRectangle text_rect;
4267 CdkRectangle left_rect;
4268 CdkRectangle right_rect;
4269 CdkRectangle top_rect;
4270 CdkRectangle bottom_rect;
4271 guint border_width;
4272 gboolean size_changed;
4273
4274 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
4275 priv = text_view->priv;
4276
4277 DV(g_print(G_STRLOC"\n"));
4278
4279 _ctk_pixel_cache_set_extra_size (priv->pixel_cache, 64,
4280 allocation->height / 2 + priv->top_border);
4281
4282 ctk_widget_get_allocation (widget, &widget_allocation);
4283 size_changed =
4284 widget_allocation.width != allocation->width ||
4285 widget_allocation.height != allocation->height;
4286
4287 border_width = ctk_container_get_border_width (CTK_CONTAINER (text_view)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_container_get_type ()))))))
);
4288
4289 ctk_widget_set_allocation (widget, allocation);
4290
4291 if (ctk_widget_get_realized (widget))
4292 {
4293 cdk_window_move_resize (ctk_widget_get_window (widget),
4294 allocation->x, allocation->y,
4295 allocation->width, allocation->height);
4296 }
4297
4298 /* distribute width/height among child windows. Ensure all
4299 * windows get at least a 1x1 allocation.
4300 */
4301
4302 width = allocation->width - border_width * 2;
4303
4304 if (priv->left_window)
4305 left_rect.width = priv->left_window->requisition.width;
4306 else
4307 left_rect.width = 0;
4308
4309 width -= left_rect.width;
4310
4311 if (priv->right_window)
4312 right_rect.width = priv->right_window->requisition.width;
4313 else
4314 right_rect.width = 0;
4315
4316 width -= right_rect.width;
4317
4318 text_rect.width = MAX (1, width)(((1) > (width)) ? (1) : (width));
4319
4320 top_rect.width = text_rect.width;
4321 bottom_rect.width = text_rect.width;
4322
4323 height = allocation->height - border_width * 2;
4324
4325 if (priv->top_window)
4326 top_rect.height = priv->top_window->requisition.height;
4327 else
4328 top_rect.height = 0;
4329
4330 height -= top_rect.height;
4331
4332 if (priv->bottom_window)
4333 bottom_rect.height = priv->bottom_window->requisition.height;
4334 else
4335 bottom_rect.height = 0;
4336
4337 height -= bottom_rect.height;
4338
4339 text_rect.height = MAX (1, height)(((1) > (height)) ? (1) : (height));
4340
4341 left_rect.height = text_rect.height;
4342 right_rect.height = text_rect.height;
4343
4344 /* Origins */
4345 left_rect.x = border_width;
4346 top_rect.y = border_width;
4347
4348 text_rect.x = left_rect.x + left_rect.width;
4349 text_rect.y = top_rect.y + top_rect.height;
4350
4351 left_rect.y = text_rect.y;
4352 right_rect.y = text_rect.y;
4353
4354 top_rect.x = text_rect.x;
4355 bottom_rect.x = text_rect.x;
4356
4357 right_rect.x = text_rect.x + text_rect.width;
4358 bottom_rect.y = text_rect.y + text_rect.height;
4359
4360 text_window_size_allocate (priv->text_window,
4361 &text_rect);
4362
4363 if (priv->left_window)
4364 text_window_size_allocate (priv->left_window,
4365 &left_rect);
4366
4367 if (priv->right_window)
4368 text_window_size_allocate (priv->right_window,
4369 &right_rect);
4370
4371 if (priv->top_window)
4372 text_window_size_allocate (priv->top_window,
4373 &top_rect);
4374
4375 if (priv->bottom_window)
4376 text_window_size_allocate (priv->bottom_window,
4377 &bottom_rect);
4378
4379 ctk_text_view_update_layout_width (text_view);
4380
4381 /* Note that this will do some layout validation */
4382 ctk_text_view_allocate_children (text_view);
4383
4384 /* Update adjustments */
4385 if (!ctk_adjustment_is_animating (priv->hadjustment))
4386 ctk_text_view_set_hadjustment_values (text_view);
4387 if (!ctk_adjustment_is_animating (priv->vadjustment))
4388 ctk_text_view_set_vadjustment_values (text_view);
4389
4390 /* The CTK resize loop processes all the pending exposes right
4391 * after doing the resize stuff, so the idle sizer won't have a
4392 * chance to run. So we do the work here.
4393 */
4394 ctk_text_view_flush_first_validate (text_view);
4395
4396 /* widget->window doesn't get auto-redrawn as the layout is computed, so has to
4397 * be invalidated
4398 */
4399 if (size_changed && ctk_widget_get_realized (widget))
4400 cdk_window_invalidate_rect (ctk_widget_get_window (widget), NULL((void*)0), FALSE(0));
4401}
4402
4403static void
4404ctk_text_view_get_first_para_iter (CtkTextView *text_view,
4405 CtkTextIter *iter)
4406{
4407 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), iter,
4408 text_view->priv->first_para_mark);
4409}
4410
4411static void
4412ctk_text_view_validate_onscreen (CtkTextView *text_view)
4413{
4414 CtkWidget *widget;
4415 CtkTextViewPrivate *priv;
4416
4417 widget = CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
;
4418 priv = text_view->priv;
4419
4420 DV(g_print(">Validating onscreen ("G_STRLOC")\n"));
4421
4422 if (SCREEN_HEIGHT (widget)text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_text_view_get_type ())))
)))->priv->text_window)
> 0)
4423 {
4424 CtkTextIter first_para;
4425
4426 /* Be sure we've validated the stuff onscreen; if we
4427 * scrolled, these calls won't have any effect, because
4428 * they were called in the recursive validate_onscreen
4429 */
4430 ctk_text_view_get_first_para_iter (text_view, &first_para);
4431
4432 ctk_text_layout_validate_yrange (priv->layout,
4433 &first_para,
4434 0,
4435 priv->first_para_pixels +
4436 SCREEN_HEIGHT (widget)text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_text_view_get_type ())))
)))->priv->text_window)
);
4437 }
4438
4439 priv->onscreen_validated = TRUE(!(0));
4440
4441 DV(g_print(">Done validating onscreen, onscreen_validated = TRUE ("G_STRLOC")\n"));
4442
4443 /* This can have the odd side effect of triggering a scroll, which should
4444 * flip "onscreen_validated" back to FALSE, but should also get us
4445 * back into this function to turn it on again.
4446 */
4447 ctk_text_view_update_adjustments (text_view);
4448
4449 g_assert (priv->onscreen_validated)do { if (priv->onscreen_validated) ; else g_assertion_message_expr
("Ctk", "ctktextview.c", 4449, ((const char*) (__func__)), "priv->onscreen_validated"
); } while (0)
;
4450}
4451
4452static void
4453ctk_text_view_flush_first_validate (CtkTextView *text_view)
4454{
4455 CtkTextViewPrivate *priv = text_view->priv;
4456
4457 if (priv->first_validate_idle == 0)
4458 return;
4459
4460 /* Do this first, which means that if an "invalidate"
4461 * occurs during any of this process, a new first_validate_callback
4462 * will be installed, and we'll start again.
4463 */
4464 DV (g_print ("removing first validate in %s\n", G_STRLOC));
4465 g_source_remove (priv->first_validate_idle);
4466 priv->first_validate_idle = 0;
4467
4468 /* be sure we have up-to-date screen size set on the
4469 * layout.
4470 */
4471 ctk_text_view_update_layout_width (text_view);
4472
4473 /* Bail out if we invalidated stuff; scrolling right away will just
4474 * confuse the issue.
4475 */
4476 if (priv->first_validate_idle != 0)
4477 {
4478 DV(g_print(">Width change forced requeue ("G_STRLOC")\n"));
4479 }
4480 else
4481 {
4482 /* scroll to any marks, if that's pending. This can jump us to
4483 * the validation codepath used for scrolling onscreen, if so we
4484 * bail out. It won't jump if already in that codepath since
4485 * value_changed is not recursive, so also validate if
4486 * necessary.
4487 */
4488 if (!ctk_text_view_flush_scroll (text_view) ||
4489 !priv->onscreen_validated)
4490 ctk_text_view_validate_onscreen (text_view);
4491
4492 DV(g_print(">Leaving first validate idle ("G_STRLOC")\n"));
4493
4494 g_assert (priv->onscreen_validated)do { if (priv->onscreen_validated) ; else g_assertion_message_expr
("Ctk", "ctktextview.c", 4494, ((const char*) (__func__)), "priv->onscreen_validated"
); } while (0)
;
4495 }
4496}
4497
4498static gboolean
4499first_validate_callback (gpointer data)
4500{
4501 CtkTextView *text_view = data;
4502
4503 /* Note that some of this code is duplicated at the end of size_allocate,
4504 * keep in sync with that.
4505 */
4506
4507 DV(g_print(G_STRLOC"\n"));
4508
4509 ctk_text_view_flush_first_validate (text_view);
4510
4511 return FALSE(0);
4512}
4513
4514static gboolean
4515incremental_validate_callback (gpointer data)
4516{
4517 CtkTextView *text_view = data;
4518 gboolean result = TRUE(!(0));
4519
4520 DV(g_print(G_STRLOC"\n"));
4521
4522 ctk_text_layout_validate (text_view->priv->layout, 2000);
4523
4524 ctk_text_view_update_adjustments (text_view);
4525
4526 if (ctk_text_layout_is_valid (text_view->priv->layout))
4527 {
4528 text_view->priv->incremental_validate_idle = 0;
4529 result = FALSE(0);
4530 }
4531
4532 return result;
4533}
4534
4535static void
4536ctk_text_view_invalidate (CtkTextView *text_view)
4537{
4538 CtkTextViewPrivate *priv = text_view->priv;
4539
4540 DV (g_print (">Invalidate, onscreen_validated = %d now FALSE ("G_STRLOC")\n",
4541 priv->onscreen_validated));
4542
4543 priv->onscreen_validated = FALSE(0);
4544
4545 /* We'll invalidate when the layout is created */
4546 if (priv->layout == NULL((void*)0))
4547 return;
4548
4549 if (!priv->first_validate_idle)
4550 {
4551 priv->first_validate_idle = cdk_threads_add_idle_full (CTK_PRIORITY_RESIZE(100 + 10) - 2, first_validate_callback, text_view, NULL((void*)0));
4552 g_source_set_name_by_id (priv->first_validate_idle, "[ctk+] first_validate_callback");
4553 DV (g_print (G_STRLOC": adding first validate idle %d\n",
4554 priv->first_validate_idle));
4555 }
4556
4557 if (!priv->incremental_validate_idle)
4558 {
4559 priv->incremental_validate_idle = cdk_threads_add_idle_full (CTK_TEXT_VIEW_PRIORITY_VALIDATE((100 + 20) + 5), incremental_validate_callback, text_view, NULL((void*)0));
4560 g_source_set_name_by_id (priv->incremental_validate_idle, "[ctk+] incremental_validate_callback");
4561 DV (g_print (G_STRLOC": adding incremental validate idle %d\n",
4562 priv->incremental_validate_idle));
4563 }
4564}
4565
4566static void
4567invalidated_handler (CtkTextLayout *layout G_GNUC_UNUSED__attribute__ ((__unused__)),
4568 gpointer data)
4569{
4570 CtkTextView *text_view;
4571
4572 text_view = CTK_TEXT_VIEW (data)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ctk_text_view_get_type ()))))))
;
4573
4574 DV (g_print ("Invalidating due to layout invalidate signal\n"));
4575 ctk_text_view_invalidate (text_view);
4576}
4577
4578static void
4579changed_handler (CtkTextLayout *layout,
4580 gint start_y,
4581 gint old_height,
4582 gint new_height,
4583 gpointer data)
4584{
4585 CtkTextView *text_view;
4586 CtkTextViewPrivate *priv;
4587 CtkWidget *widget;
4588 CdkRectangle visible_rect;
4589 CdkRectangle redraw_rect;
4590
4591 text_view = CTK_TEXT_VIEW (data)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ctk_text_view_get_type ()))))))
;
4592 priv = text_view->priv;
4593 widget = CTK_WIDGET (data)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ctk_widget_get_type ()))))))
;
4594
4595 DV(g_print(">Lines Validated ("G_STRLOC")\n"));
4596
4597 if (ctk_widget_get_realized (widget))
4598 {
4599 ctk_text_view_get_rendered_rect (text_view, &visible_rect);
4600
4601 redraw_rect.x = visible_rect.x;
4602 redraw_rect.width = visible_rect.width;
4603 redraw_rect.y = start_y;
4604
4605 if (old_height == new_height)
4606 redraw_rect.height = old_height;
4607 else if (start_y + old_height > visible_rect.y)
4608 redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y)(((0) > (visible_rect.y + visible_rect.height - start_y)) ?
(0) : (visible_rect.y + visible_rect.height - start_y))
;
4609 else
4610 redraw_rect.height = 0;
4611
4612 if (cdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
4613 {
4614 /* text_window_invalidate_rect() takes buffer coordinates */
4615 text_window_invalidate_rect (priv->text_window,
4616 &redraw_rect);
4617
4618 DV(g_print(" invalidated rect: %d,%d %d x %d\n",
4619 redraw_rect.x,
4620 redraw_rect.y,
4621 redraw_rect.width,
4622 redraw_rect.height));
4623
4624 if (priv->left_window)
4625 text_window_invalidate_rect (priv->left_window,
4626 &redraw_rect);
4627 if (priv->right_window)
4628 text_window_invalidate_rect (priv->right_window,
4629 &redraw_rect);
4630 if (priv->top_window)
4631 text_window_invalidate_rect (priv->top_window,
4632 &redraw_rect);
4633 if (priv->bottom_window)
4634 text_window_invalidate_rect (priv->bottom_window,
4635 &redraw_rect);
4636
4637 queue_update_im_spot_location (text_view);
4638 }
4639 }
4640
4641 if (old_height != new_height)
4642 {
4643 GSList *tmp_list;
4644 int new_first_para_top;
4645 int old_first_para_top;
4646 CtkTextIter first;
4647
4648 /* If the bottom of the old area was above the top of the
4649 * screen, we need to scroll to keep the current top of the
4650 * screen in place. Remember that first_para_pixels is the
4651 * position of the top of the screen in coordinates relative to
4652 * the first paragraph onscreen.
4653 *
4654 * In short we are adding the height delta of the portion of the
4655 * changed region above first_para_mark to priv->yoffset.
4656 */
4657 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &first,
4658 priv->first_para_mark);
4659
4660 ctk_text_layout_get_line_yrange (layout, &first, &new_first_para_top, NULL((void*)0));
4661
4662 old_first_para_top = priv->yoffset - priv->first_para_pixels + priv->top_border;
4663
4664 if (new_first_para_top != old_first_para_top)
4665 {
4666 priv->yoffset += new_first_para_top - old_first_para_top;
4667
4668 ctk_adjustment_set_value (text_view->priv->vadjustment, priv->yoffset);
4669
4670 /* If the height changed above our current position, then we
4671 * need to discard the pixelcache because things wont line nup
4672 * anymore (even if we adjust the vadjustment).
4673 *
4674 * Generally this doesn't happen interactively because we keep
4675 * the insert cursor on screen when making changes. It can
4676 * happen when code changes the first line, for example, in an
4677 * automated fashion.
4678 *
4679 * There is one case where this could be optimized out such as
4680 * when delete-range is followed by insert-text and whole lines
4681 * are removed. API consumers can always work around that by
4682 * avoiding the removal of a \n so no effort is made here to
4683 * handle that.
4684 */
4685 if (ctk_widget_get_realized (widget))
4686 _ctk_pixel_cache_invalidate (text_view->priv->pixel_cache, NULL((void*)0));
4687 }
4688
4689 /* FIXME be smarter about which anchored widgets we update */
4690
4691 tmp_list = priv->children;
4692 while (tmp_list != NULL((void*)0))
4693 {
4694 CtkTextViewChild *child = tmp_list->data;
4695
4696 if (child->anchor)
4697 ctk_text_view_update_child_allocation (text_view, child);
4698
4699 tmp_list = tmp_list->next;
4700 }
4701 }
4702
4703 {
4704 CtkRequisition old_req = priv->cached_size_request;
4705 CtkRequisition new_req;
4706
4707 /* Use this instead of ctk_widget_size_request wrapper
4708 * to avoid the optimization which just returns widget->requisition
4709 * if a resize hasn't been queued.
4710 */
4711 ctk_text_view_size_request (widget, &new_req);
4712
4713 if (old_req.width != new_req.width ||
4714 old_req.height != new_req.height)
4715 {
4716 ctk_widget_queue_resize_no_redraw (widget);
4717 }
4718 }
4719}
4720
4721static void
4722ctk_text_view_realize (CtkWidget *widget)
4723{
4724 CtkAllocation allocation;
4725 CtkTextView *text_view;
4726 CtkTextViewPrivate *priv;
4727 CdkWindow *window;
4728 CdkWindowAttr attributes;
4729 gint attributes_mask;
4730 GSList *tmp_list;
4731
4732 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
4733 priv = text_view->priv;
4734
4735 ctk_widget_set_realized (widget, TRUE(!(0)));
4736
4737 ctk_widget_get_allocation (widget, &allocation);
4738
4739 attributes.window_type = CDK_WINDOW_CHILD;
4740 attributes.x = allocation.x;
4741 attributes.y = allocation.y;
4742 attributes.width = allocation.width;
4743 attributes.height = allocation.height;
4744 attributes.wclass = CDK_INPUT_OUTPUT;
4745 attributes.visual = ctk_widget_get_visual (widget);
4746 attributes.event_mask = CDK_VISIBILITY_NOTIFY_MASK;
4747
4748 attributes_mask = CDK_WA_X | CDK_WA_Y | CDK_WA_VISUAL;
4749
4750 window = cdk_window_new (ctk_widget_get_parent_window (widget),
4751 &attributes, attributes_mask);
4752 ctk_widget_set_window (widget, window);
4753 ctk_widget_register_window (widget, window);
4754
4755 text_window_realize (priv->text_window, widget);
4756
4757 if (priv->left_window)
4758 text_window_realize (priv->left_window, widget);
4759
4760 if (priv->top_window)
4761 text_window_realize (priv->top_window, widget);
4762
4763 if (priv->right_window)
4764 text_window_realize (priv->right_window, widget);
4765
4766 if (priv->bottom_window)
4767 text_window_realize (priv->bottom_window, widget);
4768
4769 ctk_text_view_ensure_layout (text_view);
4770 ctk_text_view_invalidate (text_view);
4771
4772 if (priv->buffer)
4773 {
4774 CtkClipboard *clipboard = ctk_widget_get_clipboard (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
4775 CDK_SELECTION_PRIMARY((CdkAtom)((gpointer) (gulong) (1))));
4776 ctk_text_buffer_add_selection_clipboard (priv->buffer, clipboard);
4777 }
4778
4779 tmp_list = priv->children;
4780 while (tmp_list != NULL((void*)0))
4781 {
4782 CtkTextViewChild *vc = tmp_list->data;
4783
4784 text_view_child_set_parent_window (text_view, vc);
4785
4786 tmp_list = tmp_list->next;
4787 }
4788
4789 /* Ensure updating the spot location. */
4790 ctk_text_view_update_im_spot_location (text_view);
4791}
4792
4793static void
4794ctk_text_view_unrealize (CtkWidget *widget)
4795{
4796 CtkTextView *text_view;
4797 CtkTextViewPrivate *priv;
4798
4799 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
4800 priv = text_view->priv;
4801
4802 if (priv->buffer)
4803 {
4804 CtkClipboard *clipboard = ctk_widget_get_clipboard (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
4805 CDK_SELECTION_PRIMARY((CdkAtom)((gpointer) (gulong) (1))));
4806 ctk_text_buffer_remove_selection_clipboard (priv->buffer, clipboard);
4807 }
4808
4809 ctk_text_view_remove_validate_idles (text_view);
4810
4811 if (priv->popup_menu)
4812 {
4813 ctk_widget_destroy (priv->popup_menu);
4814 priv->popup_menu = NULL((void*)0);
4815 }
4816
4817 text_window_unrealize (priv->text_window);
4818
4819 if (priv->left_window)
4820 text_window_unrealize (priv->left_window);
4821
4822 if (priv->top_window)
4823 text_window_unrealize (priv->top_window);
4824
4825 if (priv->right_window)
4826 text_window_unrealize (priv->right_window);
4827
4828 if (priv->bottom_window)
4829 text_window_unrealize (priv->bottom_window);
4830
4831 CTK_WIDGET_CLASS (ctk_text_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), ((ctk_widget_get_type ()))
))))
->unrealize (widget);
4832}
4833
4834static void
4835ctk_text_view_map (CtkWidget *widget)
4836{
4837 CtkTextView *text_view;
4838 CtkTextViewPrivate *priv;
4839
4840 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
4841 priv = text_view->priv;
4842
4843 _ctk_pixel_cache_map (priv->pixel_cache);
4844
4845 CTK_WIDGET_CLASS (ctk_text_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), ((ctk_widget_get_type ()))
))))
->map (widget);
4846}
4847
4848static void
4849ctk_text_view_unmap (CtkWidget *widget)
4850{
4851 CtkTextView *text_view;
4852 CtkTextViewPrivate *priv;
4853
4854 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
4855 priv = text_view->priv;
4856
4857 CTK_WIDGET_CLASS (ctk_text_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), ((ctk_widget_get_type ()))
))))
->unmap (widget);
4858
4859 _ctk_pixel_cache_unmap (priv->pixel_cache);
4860}
4861
4862static void
4863text_window_set_padding (CtkTextView *text_view,
4864 CtkStyleContext *context)
4865{
4866 CtkTextViewPrivate *priv;
4867 CtkBorder padding, border;
4868
4869 priv = text_view->priv;
4870
4871 ctk_style_context_get_padding (context, ctk_style_context_get_state (context), &padding);
4872 ctk_style_context_get_border (context, ctk_style_context_get_state (context), &border);
4873 padding.left += border.left;
4874 padding.right += border.right;
4875 padding.top += border.top;
4876 padding.bottom += border.bottom;
4877
4878 if (padding.left != priv->left_padding ||
4879 padding.right != priv->right_padding ||
4880 padding.top != priv->top_padding ||
4881 padding.bottom != priv->bottom_padding)
4882 {
4883 priv->xoffset += priv->left_padding - padding.left;
4884 priv->yoffset += priv->top_padding - padding.top;
4885
4886 priv->left_padding = padding.left;
4887 priv->right_padding = padding.right;
4888 priv->top_padding = padding.top;
4889 priv->bottom_padding = padding.bottom;
4890
4891 priv->top_border = padding.top + priv->top_margin;
4892 priv->bottom_border = padding.bottom + priv->bottom_margin;
4893 priv->left_border = padding.left + priv->left_margin;
4894 priv->right_border = padding.right + priv->right_margin;
4895
4896 if (priv->layout && priv->layout->default_style)
4897 {
4898 priv->layout->right_padding = priv->right_padding;
4899 priv->layout->left_padding = priv->left_padding;
4900
4901 ctk_text_layout_default_style_changed (priv->layout);
4902 }
4903 }
4904}
4905
4906static void
4907ctk_text_view_style_updated (CtkWidget *widget)
4908{
4909 CtkTextView *text_view;
4910 CtkTextViewPrivate *priv;
4911 PangoContext *ltr_context, *rtl_context;
4912 CtkStyleContext *style_context;
4913 CtkCssStyleChange *change;
4914
4915 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
4916 priv = text_view->priv;
4917
4918 CTK_WIDGET_CLASS (ctk_text_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), ((ctk_widget_get_type ()))
))))
->style_updated (widget);
4919
4920 style_context = ctk_widget_get_style_context (widget);
4921 change = ctk_style_context_get_change (style_context);
4922
4923 if ((change == NULL((void*)0) || ctk_css_style_change_affects (change, CTK_CSS_AFFECTS_FONT)) &&
4924 priv->layout && priv->layout->default_style)
4925 {
4926 ctk_text_view_set_attributes_from_style (text_view,
4927 priv->layout->default_style);
4928
4929 ltr_context = ctk_widget_create_pango_context (widget);
4930 pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
4931 rtl_context = ctk_widget_create_pango_context (widget);
4932 pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
4933
4934 ctk_text_layout_set_contexts (priv->layout, ltr_context, rtl_context);
4935
4936 g_object_unref (ltr_context);
4937 g_object_unref (rtl_context);
4938 }
4939}
4940
4941static void
4942ctk_text_view_direction_changed (CtkWidget *widget,
4943 CtkTextDirection previous_direction G_GNUC_UNUSED__attribute__ ((__unused__)))
4944{
4945 CtkTextViewPrivate *priv = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->priv;
4946
4947 if (priv->layout && priv->layout->default_style)
4948 {
4949 priv->layout->default_style->direction = ctk_widget_get_direction (widget);
4950
4951 ctk_text_layout_default_style_changed (priv->layout);
4952 }
4953}
4954
4955static void
4956ctk_text_view_state_flags_changed (CtkWidget *widget,
4957 CtkStateFlags previous_state G_GNUC_UNUSED__attribute__ ((__unused__)))
4958{
4959 CtkTextView *text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
4960 CtkTextViewPrivate *priv = text_view->priv;
4961 CdkCursor *cursor;
4962 CtkStateFlags state;
4963
4964 if (ctk_widget_get_realized (widget))
4965 {
4966 if (ctk_widget_is_sensitive (widget))
4967 cursor = cdk_cursor_new_from_name (ctk_widget_get_display (widget), "text");
4968 else
4969 cursor = NULL((void*)0);
4970
4971 cdk_window_set_cursor (priv->text_window->bin_window, cursor);
4972
4973 if (cursor)
4974 g_object_unref (cursor);
4975
4976 priv->mouse_cursor_obscured = FALSE(0);
4977 }
4978
4979 if (!ctk_widget_is_sensitive (widget))
4980 {
4981 /* Clear any selection */
4982 ctk_text_view_unselect (text_view);
4983 }
4984
4985 state = ctk_widget_get_state_flags (widget);
4986 ctk_css_node_set_state (priv->text_window->css_node, state);
4987
4988 state &= ~CTK_STATE_FLAG_DROP_ACTIVE;
4989
4990 ctk_css_node_set_state (priv->selection_node, state);
4991 if (priv->left_window)
4992 ctk_css_node_set_state (priv->left_window->css_node, state);
4993 if (priv->right_window)
4994 ctk_css_node_set_state (priv->right_window->css_node, state);
4995 if (priv->top_window)
4996 ctk_css_node_set_state (priv->top_window->css_node, state);
4997 if (priv->bottom_window)
4998 ctk_css_node_set_state (priv->bottom_window->css_node, state);
4999
5000 ctk_widget_queue_draw (widget);
5001}
5002
5003static void
5004set_invisible_cursor (CdkWindow *window)
5005{
5006 CdkDisplay *display;
5007 CdkCursor *cursor;
5008
5009 display = cdk_window_get_display (window);
5010 cursor = cdk_cursor_new_from_name (display, "none");
5011
5012 cdk_window_set_cursor (window, cursor);
5013
5014 g_clear_object (&cursor)do { _Static_assert (sizeof *((&cursor)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&cursor
))) _pp = ((&cursor)); __typeof__ (*((&cursor))) _ptr
= *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr)
; } while (0)
;
5015}
5016
5017static void
5018ctk_text_view_obscure_mouse_cursor (CtkTextView *text_view)
5019{
5020 if (text_view->priv->mouse_cursor_obscured)
5021 return;
5022
5023 set_invisible_cursor (text_view->priv->text_window->bin_window);
5024
5025 text_view->priv->mouse_cursor_obscured = TRUE(!(0));
5026}
5027
5028static void
5029ctk_text_view_unobscure_mouse_cursor (CtkTextView *text_view)
5030{
5031 if (text_view->priv->mouse_cursor_obscured)
5032 {
5033 CdkDisplay *display;
5034 CdkCursor *cursor;
5035
5036 display = ctk_widget_get_display (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
5037 cursor = cdk_cursor_new_from_name (display, "text");
5038 cdk_window_set_cursor (text_view->priv->text_window->bin_window, cursor);
5039 g_object_unref (cursor);
5040 text_view->priv->mouse_cursor_obscured = FALSE(0);
5041 }
5042}
5043
5044/*
5045 * Events
5046 */
5047
5048static gboolean
5049get_event_coordinates (CdkEvent *event, gint *x, gint *y)
5050{
5051 if (event)
5052 switch (event->type)
5053 {
5054 case CDK_MOTION_NOTIFY:
5055 *x = event->motion.x;
5056 *y = event->motion.y;
5057 return TRUE(!(0));
5058 break;
5059
5060 case CDK_BUTTON_PRESS:
5061 case CDK_2BUTTON_PRESS:
5062 case CDK_3BUTTON_PRESS:
5063 case CDK_BUTTON_RELEASE:
5064 *x = event->button.x;
5065 *y = event->button.y;
5066 return TRUE(!(0));
5067 break;
5068
5069 case CDK_KEY_PRESS:
5070 case CDK_KEY_RELEASE:
5071 case CDK_ENTER_NOTIFY:
5072 case CDK_LEAVE_NOTIFY:
5073 case CDK_PROPERTY_NOTIFY:
5074 case CDK_SELECTION_CLEAR:
5075 case CDK_SELECTION_REQUEST:
5076 case CDK_SELECTION_NOTIFY:
5077 case CDK_PROXIMITY_IN:
5078 case CDK_PROXIMITY_OUT:
5079 case CDK_DRAG_ENTER:
5080 case CDK_DRAG_LEAVE:
5081 case CDK_DRAG_MOTION:
5082 case CDK_DRAG_STATUS:
5083 case CDK_DROP_START:
5084 case CDK_DROP_FINISHED:
5085 default:
5086 return FALSE(0);
5087 break;
5088 }
5089
5090 return FALSE(0);
5091}
5092
5093static gint
5094emit_event_on_tags (CtkWidget *widget,
5095 CdkEvent *event,
5096 CtkTextIter *iter)
5097{
5098 GSList *tags;
5099 GSList *tmp;
5100 gboolean retval = FALSE(0);
5101
5102 tags = ctk_text_iter_get_tags (iter);
5103
5104 tmp = tags;
5105 while (tmp != NULL((void*)0))
5106 {
5107 CtkTextTag *tag = tmp->data;
5108
5109 if (ctk_text_tag_event (tag, G_OBJECT (widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), (((GType) ((20) << (2))))))))
, event, iter))
5110 {
5111 retval = TRUE(!(0));
5112 break;
5113 }
5114
5115 tmp = tmp->next;
5116 }
5117
5118 g_slist_free (tags);
5119
5120 return retval;
5121}
5122
5123static void
5124_text_window_to_widget_coords (CtkTextView *text_view,
5125 gint *x,
5126 gint *y)
5127{
5128 CtkTextViewPrivate *priv = text_view->priv;
5129 gint border_width = ctk_container_get_border_width (CTK_CONTAINER (text_view)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_container_get_type ()))))))
);
5130
5131 *x += border_width;
5132 *y += border_width;
5133
5134 if (priv->top_window)
5135 (*y) += priv->top_window->requisition.height;
5136 if (priv->left_window)
5137 (*x) += priv->left_window->requisition.width;
5138}
5139
5140static void
5141_widget_to_text_window_coords (CtkTextView *text_view,
5142 gint *x,
5143 gint *y)
5144{
5145 CtkTextViewPrivate *priv = text_view->priv;
5146 gint border_width = ctk_container_get_border_width (CTK_CONTAINER (text_view)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_container_get_type ()))))))
);
5147
5148 *x -= border_width;
5149 *y -= border_width;
5150
5151 if (priv->top_window)
5152 (*y) -= priv->top_window->requisition.height;
5153 if (priv->left_window)
5154 (*x) -= priv->left_window->requisition.width;
5155}
5156
5157static void
5158ctk_text_view_set_handle_position (CtkTextView *text_view,
5159 CtkTextIter *iter,
5160 CtkTextHandlePosition pos)
5161{
5162 CtkTextViewPrivate *priv;
5163 CdkRectangle rect;
5164 gint x, y;
5165
5166 priv = text_view->priv;
5167 ctk_text_view_get_cursor_locations (text_view, iter, &rect, NULL((void*)0));
5168
5169 x = rect.x - priv->xoffset;
5170 y = rect.y - priv->yoffset;
5171
5172 if (!_ctk_text_handle_get_is_dragged (priv->text_handle, pos) &&
5173 (x < 0 || x > SCREEN_WIDTH (text_view)text_window_get_width (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)
||
5174 y < 0 || y > SCREEN_HEIGHT (text_view)text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)
))
5175 {
5176 /* Hide the handle if it's not being manipulated
5177 * and fell outside of the visible text area.
5178 */
5179 _ctk_text_handle_set_visible (priv->text_handle, pos, FALSE(0));
5180 }
5181 else
5182 {
5183 CtkTextDirection dir = CTK_TEXT_DIR_LTR;
5184 CtkTextAttributes attributes = { 0 };
5185
5186 _ctk_text_handle_set_visible (priv->text_handle, pos, TRUE(!(0)));
5187
5188 rect.x = CLAMP (x, 0, SCREEN_WIDTH (text_view))(((x) > (text_window_get_width (((((CtkTextView*) (void *)
g_type_check_instance_cast ((GTypeInstance*) ((text_view)), (
(ctk_text_view_get_type ()))))))->priv->text_window))) ?
(text_window_get_width (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)) : (((x) < (0)) ? (0) : (
x)))
;
5189 rect.y = CLAMP (y, 0, SCREEN_HEIGHT (text_view))(((y) > (text_window_get_height (((((CtkTextView*) (void *
) g_type_check_instance_cast ((GTypeInstance*) ((text_view)),
((ctk_text_view_get_type ()))))))->priv->text_window))
) ? (text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)) : (((y) < (0)) ? (0) : (
y)))
;
5190 _text_window_to_widget_coords (text_view, &rect.x, &rect.y);
5191
5192 _ctk_text_handle_set_position (priv->text_handle, pos, &rect);
5193
5194 if (ctk_text_iter_get_attributes (iter, &attributes))
5195 dir = attributes.direction;
5196
5197 _ctk_text_handle_set_direction (priv->text_handle, pos, dir);
5198 }
5199}
5200
5201static void
5202ctk_text_view_show_magnifier (CtkTextView *text_view,
5203 CtkTextIter *iter,
5204 gint x,
5205 gint y G_GNUC_UNUSED__attribute__ ((__unused__)))
5206{
5207 cairo_rectangle_int_t rect;
5208 CtkTextViewPrivate *priv;
5209 CtkAllocation allocation;
5210 CtkRequisition req;
5211
5212#define N_LINES 1
5213
5214 ctk_widget_get_allocation (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
, &allocation);
5215
5216 priv = text_view->priv;
5217 _ctk_text_view_ensure_magnifier (text_view);
5218
5219 /* Set size/content depending on iter rect */
5220 ctk_text_view_get_iter_location (text_view, iter,
5221 (CdkRectangle *) &rect);
5222 rect.x = x + priv->xoffset;
5223 ctk_text_view_buffer_to_window_coords (text_view, CTK_TEXT_WINDOW_TEXT,
5224 rect.x, rect.y, &rect.x, &rect.y);
5225 _text_window_to_widget_coords (text_view, &rect.x, &rect.y);
5226 req.height = rect.height * N_LINES *
5227 _ctk_magnifier_get_magnification (CTK_MAGNIFIER (priv->magnifier)((((CtkMagnifier*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->magnifier)), ((_ctk_magnifier_get_type ()))))))
);
5228 req.width = MAX ((req.height * 4) / 3, 80)((((req.height * 4) / 3) > (80)) ? ((req.height * 4) / 3) :
(80))
;
5229 ctk_widget_set_size_request (priv->magnifier, req.width, req.height);
5230
5231 _ctk_magnifier_set_coords (CTK_MAGNIFIER (priv->magnifier)((((CtkMagnifier*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->magnifier)), ((_ctk_magnifier_get_type ()))))))
,
5232 rect.x, rect.y + rect.height / 2);
5233
5234 rect.x = CLAMP (rect.x, 0, allocation.width)(((rect.x) > (allocation.width)) ? (allocation.width) : ((
(rect.x) < (0)) ? (0) : (rect.x)))
;
5235 rect.y += rect.height / 4;
5236 rect.height -= rect.height / 4;
5237 ctk_popover_set_pointing_to (CTK_POPOVER (priv->magnifier_popover)((((CtkPopover*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->magnifier_popover)), ((ctk_popover_get_type ())
)))))
,
5238 &rect);
5239
5240 ctk_popover_popup (CTK_POPOVER (priv->magnifier_popover)((((CtkPopover*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->magnifier_popover)), ((ctk_popover_get_type ())
)))))
);
5241
5242#undef N_LINES
5243}
5244
5245static void
5246ctk_text_view_handle_dragged (CtkTextHandle *handle,
5247 CtkTextHandlePosition pos,
5248 gint x,
5249 gint y,
5250 CtkTextView *text_view)
5251{
5252 CtkTextViewPrivate *priv;
5253 CtkTextIter old_cursor, old_bound;
5254 CtkTextIter cursor, bound, iter;
5255 CtkTextIter *min, *max;
5256 CtkTextHandleMode mode;
5257 CtkTextBuffer *buffer;
5258 CtkTextHandlePosition cursor_pos;
5259
5260 priv = text_view->priv;
5261 buffer = get_buffer (text_view);
5262 mode = _ctk_text_handle_get_mode (handle);
5263
5264 _widget_to_text_window_coords (text_view, &x, &y);
5265
5266 ctk_text_view_selection_bubble_popup_unset (text_view);
5267 ctk_text_layout_get_iter_at_pixel (priv->layout, &iter,
5268 x + priv->xoffset,
5269 y + priv->yoffset);
5270 ctk_text_buffer_get_iter_at_mark (buffer, &old_cursor,
5271 ctk_text_buffer_get_insert (buffer));
5272 ctk_text_buffer_get_iter_at_mark (buffer, &old_bound,
5273 ctk_text_buffer_get_selection_bound (buffer));
5274 cursor = old_cursor;
5275 bound = old_bound;
5276
5277 if (mode == CTK_TEXT_HANDLE_MODE_CURSOR ||
5278 ctk_text_iter_compare (&cursor, &bound) >= 0)
5279 {
5280 cursor_pos = CTK_TEXT_HANDLE_POSITION_CURSOR;
5281 max = &cursor;
5282 min = &bound;
5283 }
5284 else
5285 {
5286 cursor_pos = CTK_TEXT_HANDLE_POSITION_SELECTION_START;
5287 max = &bound;
5288 min = &cursor;
5289 }
5290
5291 if (pos == CTK_TEXT_HANDLE_POSITION_SELECTION_END)
5292 {
5293 if (mode == CTK_TEXT_HANDLE_MODE_SELECTION &&
5294 ctk_text_iter_compare (&iter, min) <= 0)
5295 {
5296 iter = *min;
5297 ctk_text_iter_forward_char (&iter);
5298 }
5299
5300 *max = iter;
5301 ctk_text_view_set_handle_position (text_view, &iter, pos);
5302 }
5303 else
5304 {
5305 if (mode == CTK_TEXT_HANDLE_MODE_SELECTION &&
5306 ctk_text_iter_compare (&iter, max) >= 0)
5307 {
5308 iter = *max;
5309 ctk_text_iter_backward_char (&iter);
5310 }
5311
5312 *min = iter;
5313 ctk_text_view_set_handle_position (text_view, &iter, pos);
5314 }
5315
5316 if (ctk_text_iter_compare (&old_cursor, &cursor) != 0 ||
5317 ctk_text_iter_compare (&old_bound, &bound) != 0)
5318 {
5319 if (mode == CTK_TEXT_HANDLE_MODE_CURSOR)
5320 ctk_text_buffer_place_cursor (buffer, &cursor);
5321 else
5322 ctk_text_buffer_select_range (buffer, &cursor, &bound);
5323
5324 if (_ctk_text_handle_get_is_dragged (priv->text_handle, cursor_pos))
5325 {
5326 text_view->priv->cursor_handle_dragged = TRUE(!(0));
5327 ctk_text_view_scroll_mark_onscreen (text_view,
5328 ctk_text_buffer_get_insert (buffer));
5329 }
5330 else
5331 {
5332 text_view->priv->selection_handle_dragged = TRUE(!(0));
5333 ctk_text_view_scroll_mark_onscreen (text_view,
5334 ctk_text_buffer_get_selection_bound (buffer));
5335 }
5336 }
5337
5338 if (_ctk_text_handle_get_is_dragged (priv->text_handle, cursor_pos))
5339 ctk_text_view_show_magnifier (text_view, &cursor, x, y);
5340 else
5341 ctk_text_view_show_magnifier (text_view, &bound, x, y);
5342}
5343
5344static void
5345ctk_text_view_handle_drag_started (CtkTextHandle *handle G_GNUC_UNUSED__attribute__ ((__unused__)),
5346 CtkTextHandlePosition pos G_GNUC_UNUSED__attribute__ ((__unused__)),
5347 CtkTextView *text_view)
5348{
5349 text_view->priv->cursor_handle_dragged = FALSE(0);
5350 text_view->priv->selection_handle_dragged = FALSE(0);
5351}
5352
5353static void
5354ctk_text_view_handle_drag_finished (CtkTextHandle *handle G_GNUC_UNUSED__attribute__ ((__unused__)),
5355 CtkTextHandlePosition pos G_GNUC_UNUSED__attribute__ ((__unused__)),
5356 CtkTextView *text_view)
5357{
5358 CtkTextViewPrivate *priv = text_view->priv;
5359
5360 if (!priv->cursor_handle_dragged && !priv->selection_handle_dragged)
5361 {
5362 CtkTextBuffer *buffer;
5363 CtkTextIter cursor, start, end;
5364 CtkSettings *settings;
5365 guint double_click_time;
5366
5367 settings = ctk_widget_get_settings (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
5368 g_object_get (settings, "ctk-double-click-time", &double_click_time, NULL((void*)0));
5369 if (g_get_monotonic_time() - priv->handle_place_time < double_click_time * 1000)
5370 {
5371 buffer = get_buffer (text_view);
5372 ctk_text_buffer_get_iter_at_mark (buffer, &cursor,
5373 ctk_text_buffer_get_insert (buffer));
5374 extend_selection (text_view, SELECT_WORDS, &cursor, &start, &end);
5375 ctk_text_buffer_select_range (buffer, &start, &end);
5376
5377 ctk_text_view_update_handles (text_view, CTK_TEXT_HANDLE_MODE_SELECTION);
5378 }
5379 else
5380 ctk_text_view_selection_bubble_popup_set (text_view);
5381 }
5382
5383 if (priv->magnifier_popover)
5384 ctk_popover_popdown (CTK_POPOVER (priv->magnifier_popover)((((CtkPopover*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->magnifier_popover)), ((ctk_popover_get_type ())
)))))
);
5385}
5386
5387static gboolean cursor_visible (CtkTextView *text_view);
5388
5389static void
5390ctk_text_view_update_handles (CtkTextView *text_view,
5391 CtkTextHandleMode mode)
5392{
5393 CtkTextViewPrivate *priv = text_view->priv;
5394 CtkTextIter cursor, bound, min, max;
5395 CtkTextBuffer *buffer;
5396
5397 buffer = get_buffer (text_view);
5398
5399 ctk_text_buffer_get_iter_at_mark (buffer, &cursor,
5400 ctk_text_buffer_get_insert (buffer));
5401 ctk_text_buffer_get_iter_at_mark (buffer, &bound,
5402 ctk_text_buffer_get_selection_bound (buffer));
5403
5404 if (mode == CTK_TEXT_HANDLE_MODE_SELECTION &&
5405 ctk_text_iter_compare (&cursor, &bound) == 0)
5406 {
5407 mode = CTK_TEXT_HANDLE_MODE_CURSOR;
5408 }
5409
5410 if (mode == CTK_TEXT_HANDLE_MODE_CURSOR &&
5411 (!ctk_widget_is_sensitive (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
) || !cursor_visible (text_view)))
5412 {
5413 mode = CTK_TEXT_HANDLE_MODE_NONE;
5414 }
5415
5416 _ctk_text_handle_set_mode (priv->text_handle, mode);
5417
5418 if (ctk_text_iter_compare (&cursor, &bound) >= 0)
5419 {
5420 min = bound;
5421 max = cursor;
5422 }
5423 else
5424 {
5425 min = cursor;
5426 max = bound;
5427 }
5428
5429 if (mode != CTK_TEXT_HANDLE_MODE_NONE)
5430 ctk_text_view_set_handle_position (text_view, &max,
5431 CTK_TEXT_HANDLE_POSITION_SELECTION_END);
5432
5433 if (mode == CTK_TEXT_HANDLE_MODE_SELECTION)
5434 ctk_text_view_set_handle_position (text_view, &min,
5435 CTK_TEXT_HANDLE_POSITION_SELECTION_START);
5436}
5437
5438static gint
5439ctk_text_view_event (CtkWidget *widget, CdkEvent *event)
5440{
5441 CtkTextView *text_view;
5442 CtkTextViewPrivate *priv;
5443 gint x = 0, y = 0;
5444
5445 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
5446 priv = text_view->priv;
5447
5448 if (priv->layout == NULL((void*)0) ||
5449 get_buffer (text_view) == NULL((void*)0))
5450 return FALSE(0);
5451
5452 if (event->any.window != priv->text_window->bin_window)
5453 return FALSE(0);
5454
5455 if (get_event_coordinates (event, &x, &y))
5456 {
5457 CtkTextIter iter;
5458
5459 x += priv->xoffset;
5460 y += priv->yoffset;
5461
5462 /* FIXME this is slow and we do it twice per event.
5463 * My favorite solution is to have CtkTextLayout cache
5464 * the last couple lookups.
5465 */
5466 ctk_text_layout_get_iter_at_pixel (priv->layout,
5467 &iter,
5468 x, y);
5469
5470 return emit_event_on_tags (widget, event, &iter);
5471 }
5472 else if (event->type == CDK_KEY_PRESS ||
5473 event->type == CDK_KEY_RELEASE)
5474 {
5475 CtkTextIter iter;
5476
5477 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter,
5478 ctk_text_buffer_get_insert (get_buffer (text_view)));
5479
5480 return emit_event_on_tags (widget, event, &iter);
5481 }
5482 else
5483 return FALSE(0);
5484}
5485
5486static gint
5487ctk_text_view_key_press_event (CtkWidget *widget, CdkEventKey *event)
5488{
5489 CtkTextView *text_view;
5490 CtkTextViewPrivate *priv;
5491 CtkTextMark *insert;
5492 CtkTextIter iter;
5493 gboolean can_insert;
5494 gboolean retval = FALSE(0);
5495
5496 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
5497 priv = text_view->priv;
5498
5499 if (priv->layout == NULL((void*)0) || get_buffer (text_view) == NULL((void*)0))
5500 return FALSE(0);
5501
5502 priv->handling_key_event = TRUE(!(0));
5503
5504 /* Make sure input method knows where it is */
5505 flush_update_im_spot_location (text_view);
5506
5507 insert = ctk_text_buffer_get_insert (get_buffer (text_view));
5508 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
5509 can_insert = ctk_text_iter_can_insert (&iter, priv->editable);
5510 if (ctk_im_context_filter_keypress (priv->im_context, event))
5511 {
5512 priv->need_im_reset = TRUE(!(0));
5513 if (!can_insert)
5514 ctk_text_view_reset_im_context (text_view);
5515 retval = TRUE(!(0));
5516 }
5517 /* Binding set */
5518 else if (CTK_WIDGET_CLASS (ctk_text_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), ((ctk_widget_get_type ()))
))))
->key_press_event (widget, event))
5519 {
5520 retval = TRUE(!(0));
5521 }
5522 /* use overall editability not can_insert, more predictable for users */
5523 else if (priv->editable &&
5524 (event->keyval == CDK_KEY_Return0xff0d ||
5525 event->keyval == CDK_KEY_ISO_Enter0xfe34 ||
5526 event->keyval == CDK_KEY_KP_Enter0xff8d))
5527 {
5528 /* this won't actually insert the newline if the cursor isn't
5529 * editable
5530 */
5531 ctk_text_view_reset_im_context (text_view);
5532 ctk_text_view_commit_text (text_view, "\n");
5533 retval = TRUE(!(0));
5534 }
5535 /* Pass through Tab as literal tab, unless Control is held down */
5536 else if ((event->keyval == CDK_KEY_Tab0xff09 ||
5537 event->keyval == CDK_KEY_KP_Tab0xff89 ||
5538 event->keyval == CDK_KEY_ISO_Left_Tab0xfe20) &&
5539 !(event->state & CDK_CONTROL_MASK))
5540 {
5541 /* If the text widget isn't editable overall, or if the application
5542 * has turned off "accepts_tab", move the focus instead
5543 */
5544 if (priv->accepts_tab && priv->editable)
5545 {
5546 ctk_text_view_reset_im_context (text_view);
5547 ctk_text_view_commit_text (text_view, "\t");
5548 }
5549 else
5550 g_signal_emit_by_name (text_view, "move-focus",
5551 (event->state & CDK_SHIFT_MASK) ?
5552 CTK_DIR_TAB_BACKWARD : CTK_DIR_TAB_FORWARD);
5553
5554 retval = TRUE(!(0));
5555 }
5556 else
5557 retval = FALSE(0);
5558
5559 ctk_text_view_reset_blink_time (text_view);
5560 ctk_text_view_pend_cursor_blink (text_view);
5561
5562 if (!event->send_event && priv->text_handle)
5563 _ctk_text_handle_set_mode (priv->text_handle,
5564 CTK_TEXT_HANDLE_MODE_NONE);
5565
5566 ctk_text_view_selection_bubble_popup_unset (text_view);
5567
5568 priv->handling_key_event = FALSE(0);
5569
5570 return retval;
5571}
5572
5573static gint
5574ctk_text_view_key_release_event (CtkWidget *widget, CdkEventKey *event)
5575{
5576 CtkTextView *text_view;
5577 CtkTextViewPrivate *priv;
5578 CtkTextMark *insert;
5579 CtkTextIter iter;
5580 gboolean retval = FALSE(0);
5581
5582 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
5583 priv = text_view->priv;
5584
5585 if (priv->layout == NULL((void*)0) || get_buffer (text_view) == NULL((void*)0))
5586 return FALSE(0);
5587
5588 priv->handling_key_event = TRUE(!(0));
5589
5590 insert = ctk_text_buffer_get_insert (get_buffer (text_view));
5591 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
5592 if (ctk_text_iter_can_insert (&iter, priv->editable) &&
5593 ctk_im_context_filter_keypress (priv->im_context, event))
5594 {
5595 priv->need_im_reset = TRUE(!(0));
5596 retval = TRUE(!(0));
5597 }
5598 else
5599 retval = CTK_WIDGET_CLASS (ctk_text_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), ((ctk_widget_get_type ()))
))))
->key_release_event (widget, event);
5600
5601 priv->handling_key_event = FALSE(0);
5602
5603 return retval;
5604}
5605
5606static gboolean
5607get_iter_from_gesture (CtkTextView *text_view,
5608 CtkGesture *gesture,
5609 CtkTextIter *iter,
5610 gint *x,
5611 gint *y)
5612{
5613 CdkEventSequence *sequence;
5614 CtkTextViewPrivate *priv;
5615 gint xcoord, ycoord;
5616 gdouble px, py;
5617
5618 priv = text_view->priv;
5619 sequence =
5620 ctk_gesture_single_get_current_sequence (CTK_GESTURE_SINGLE (gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gesture)), ((ctk_gesture_single_get_type ()
))))))
);
5621
5622 if (!ctk_gesture_get_point (gesture, sequence, &px, &py))
5623 return FALSE(0);
5624
5625 xcoord = px + priv->xoffset;
5626 ycoord = py + priv->yoffset;
5627 _widget_to_text_window_coords (text_view, &xcoord, &ycoord);
5628 ctk_text_layout_get_iter_at_pixel (priv->layout, iter, xcoord, ycoord);
5629
5630 if (x)
5631 *x = xcoord;
5632 if (y)
5633 *y = ycoord;
5634
5635 return TRUE(!(0));
5636}
5637
5638static void
5639ctk_text_view_multipress_gesture_pressed (CtkGestureMultiPress *gesture,
5640 gint n_press,
5641 gdouble x G_GNUC_UNUSED__attribute__ ((__unused__)),
5642 gdouble y G_GNUC_UNUSED__attribute__ ((__unused__)),
5643 CtkTextView *text_view)
5644{
5645 CdkEventSequence *sequence;
5646 CtkTextViewPrivate *priv;
5647 const CdkEvent *event;
5648 gboolean is_touchscreen;
5649 CdkDevice *device;
5650 CtkTextIter iter;
5651 guint button;
5652
5653 priv = text_view->priv;
5654 sequence = ctk_gesture_single_get_current_sequence (CTK_GESTURE_SINGLE (gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gesture)), ((ctk_gesture_single_get_type ()
))))))
);
5655 button = ctk_gesture_single_get_current_button (CTK_GESTURE_SINGLE (gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gesture)), ((ctk_gesture_single_get_type ()
))))))
);
5656 event = ctk_gesture_get_last_event (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, sequence);
5657
5658 ctk_widget_grab_focus (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
5659
5660 if (cdk_event_get_window (event) != priv->text_window->bin_window)
5661 {
5662 /* Remove selection if any. */
5663 ctk_text_view_unselect (text_view);
5664 return;
5665 }
5666
5667 ctk_gesture_set_sequence_state (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, sequence,
5668 CTK_EVENT_SEQUENCE_CLAIMED);
5669 ctk_text_view_reset_blink_time (text_view);
5670
5671#if 0
5672 /* debug hack */
5673 if (event->button == CDK_BUTTON_SECONDARY(3) && (event->state & CDK_CONTROL_MASK) != 0)
5674 _ctk_text_buffer_spew (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->buffer);
5675 else if (event->button == CDK_BUTTON_SECONDARY(3))
5676 ctk_text_layout_spew (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->layout);
5677#endif
5678
5679 device = cdk_event_get_source_device ((CdkEvent *) event);
5680 is_touchscreen = ctk_simulate_touchscreen () ||
5681 cdk_device_get_source (device) == CDK_SOURCE_TOUCHSCREEN;
5682
5683 if (n_press == 1)
5684 ctk_text_view_reset_im_context (text_view);
5685
5686 if (n_press == 1 &&
5687 cdk_event_triggers_context_menu (event))
5688 {
5689 ctk_text_view_do_popup (text_view, event);
5690 }
5691 else if (button == CDK_BUTTON_MIDDLE(2) &&
5692 get_middle_click_paste (text_view))
5693 {
5694 get_iter_from_gesture (text_view, priv->multipress_gesture,
5695 &iter, NULL((void*)0), NULL((void*)0));
5696 ctk_text_buffer_paste_clipboard (get_buffer (text_view),
5697 ctk_widget_get_clipboard (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
5698 CDK_SELECTION_PRIMARY((CdkAtom)((gpointer) (gulong) (1)))),
5699 &iter,
5700 priv->editable);
5701 }
5702 else if (button == CDK_BUTTON_PRIMARY(1))
5703 {
5704 CtkTextHandleMode handle_mode = CTK_TEXT_HANDLE_MODE_NONE;
5705 gboolean extends = FALSE(0);
5706 CdkModifierType state;
5707
5708 cdk_event_get_state (event, &state);
5709
5710 if (state &
5711 ctk_widget_get_modifier_mask (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
5712 CDK_MODIFIER_INTENT_EXTEND_SELECTION))
5713 extends = TRUE(!(0));
5714
5715 switch (n_press)
5716 {
5717 case 1:
5718 {
5719 /* If we're in the selection, start a drag copy/move of the
5720 * selection; otherwise, start creating a new selection.
5721 */
5722 CtkTextIter start, end;
5723
5724 if (is_touchscreen)
5725 handle_mode = CTK_TEXT_HANDLE_MODE_CURSOR;
5726
5727 get_iter_from_gesture (text_view, priv->multipress_gesture,
5728 &iter, NULL((void*)0), NULL((void*)0));
5729
5730 if (ctk_text_buffer_get_selection_bounds (get_buffer (text_view),
5731 &start, &end) &&
5732 ctk_text_iter_in_range (&iter, &start, &end) && !extends)
5733 {
5734 if (is_touchscreen)
5735 {
5736 if (!priv->selection_bubble ||
5737 !ctk_widget_get_visible (priv->selection_bubble))
5738 {
5739 ctk_text_view_selection_bubble_popup_set (text_view);
5740 handle_mode = CTK_TEXT_HANDLE_MODE_NONE;
5741 }
5742 else
5743 {
5744 ctk_text_view_selection_bubble_popup_unset (text_view);
5745 handle_mode = CTK_TEXT_HANDLE_MODE_SELECTION;
5746 }
5747 }
5748 else
5749 {
5750 /* Claim the sequence on the drag gesture, but attach no
5751 * selection data, this is a special case to start DnD.
5752 */
5753 ctk_gesture_set_state (priv->drag_gesture,
5754 CTK_EVENT_SEQUENCE_CLAIMED);
5755 }
5756 break;
5757 }
5758 else
5759 {
5760 ctk_text_view_selection_bubble_popup_unset (text_view);
5761
5762 if (is_touchscreen)
5763 {
5764 ctk_text_buffer_place_cursor (get_buffer (text_view), &iter);
5765 priv->handle_place_time = g_get_monotonic_time ();
5766 }
5767 else
5768 ctk_text_view_start_selection_drag (text_view, &iter,
5769 SELECT_CHARACTERS, extends);
5770 }
5771 break;
5772 }
5773 case 2:
5774 case 3:
5775 if (is_touchscreen)
5776 {
5777 handle_mode = CTK_TEXT_HANDLE_MODE_SELECTION;
5778 break;
5779 }
5780 ctk_text_view_end_selection_drag (text_view);
5781
5782 get_iter_from_gesture (text_view, priv->multipress_gesture,
5783 &iter, NULL((void*)0), NULL((void*)0));
5784 ctk_text_view_start_selection_drag (text_view, &iter,
5785 n_press == 2 ? SELECT_WORDS : SELECT_LINES,
5786 extends);
5787 break;
5788 default:
5789 break;
5790 }
5791
5792 _ctk_text_view_ensure_text_handles (text_view);
5793 ctk_text_view_update_handles (text_view, handle_mode);
5794 }
5795
5796 if (n_press >= 3)
5797 ctk_event_controller_reset (CTK_EVENT_CONTROLLER (gesture)((((CtkEventController*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((gesture)), ((ctk_event_controller_get_type
()))))))
);
5798}
5799
5800static void
5801keymap_direction_changed (CdkKeymap *keymap G_GNUC_UNUSED__attribute__ ((__unused__)),
5802 CtkTextView *text_view)
5803{
5804 ctk_text_view_check_keymap_direction (text_view);
5805}
5806
5807static gint
5808ctk_text_view_focus_in_event (CtkWidget *widget,
5809 CdkEventFocus *event G_GNUC_UNUSED__attribute__ ((__unused__)))
5810{
5811 CtkTextView *text_view;
5812 CtkTextViewPrivate *priv;
5813
5814 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
5815 priv = text_view->priv;
5816
5817 ctk_widget_queue_draw (widget);
5818
5819 DV(g_print (G_STRLOC": focus_in_event\n"));
5820
5821 ctk_text_view_reset_blink_time (text_view);
5822
5823 if (cursor_visible (text_view) && priv->layout)
5824 {
5825 ctk_text_layout_set_cursor_visible (priv->layout, TRUE(!(0)));
5826 ctk_text_view_check_cursor_blink (text_view);
5827 }
5828
5829 g_signal_connect (cdk_keymap_get_for_display (ctk_widget_get_display (widget)),g_signal_connect_data ((cdk_keymap_get_for_display (ctk_widget_get_display
(widget))), ("direction-changed"), (((GCallback) (keymap_direction_changed
))), (text_view), ((void*)0), (GConnectFlags) 0)
5830 "direction-changed",g_signal_connect_data ((cdk_keymap_get_for_display (ctk_widget_get_display
(widget))), ("direction-changed"), (((GCallback) (keymap_direction_changed
))), (text_view), ((void*)0), (GConnectFlags) 0)
5831 G_CALLBACK (keymap_direction_changed), text_view)g_signal_connect_data ((cdk_keymap_get_for_display (ctk_widget_get_display
(widget))), ("direction-changed"), (((GCallback) (keymap_direction_changed
))), (text_view), ((void*)0), (GConnectFlags) 0)
;
5832 ctk_text_view_check_keymap_direction (text_view);
5833
5834 if (priv->editable)
5835 {
5836 priv->need_im_reset = TRUE(!(0));
5837 ctk_im_context_focus_in (priv->im_context);
5838 }
5839
5840 return FALSE(0);
5841}
5842
5843static gint
5844ctk_text_view_focus_out_event (CtkWidget *widget,
5845 CdkEventFocus *event G_GNUC_UNUSED__attribute__ ((__unused__)))
5846{
5847 CtkTextView *text_view;
5848 CtkTextViewPrivate *priv;
5849
5850 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
5851 priv = text_view->priv;
5852
5853 ctk_text_view_end_selection_drag (text_view);
5854
5855 ctk_widget_queue_draw (widget);
5856
5857 DV(g_print (G_STRLOC": focus_out_event\n"));
5858
5859 if (cursor_visible (text_view) && priv->layout)
5860 {
5861 ctk_text_view_check_cursor_blink (text_view);
5862 ctk_text_layout_set_cursor_visible (priv->layout, FALSE(0));
5863 }
5864
5865 g_signal_handlers_disconnect_by_func (cdk_keymap_get_for_display (ctk_widget_get_display (widget)),g_signal_handlers_disconnect_matched ((cdk_keymap_get_for_display
(ctk_widget_get_display (widget))), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC
| G_SIGNAL_MATCH_DATA), 0, 0, ((void*)0), (keymap_direction_changed
), (text_view))
5866 keymap_direction_changed,g_signal_handlers_disconnect_matched ((cdk_keymap_get_for_display
(ctk_widget_get_display (widget))), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC
| G_SIGNAL_MATCH_DATA), 0, 0, ((void*)0), (keymap_direction_changed
), (text_view))
5867 text_view)g_signal_handlers_disconnect_matched ((cdk_keymap_get_for_display
(ctk_widget_get_display (widget))), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC
| G_SIGNAL_MATCH_DATA), 0, 0, ((void*)0), (keymap_direction_changed
), (text_view))
;
5868 ctk_text_view_selection_bubble_popup_unset (text_view);
5869
5870 if (priv->text_handle)
5871 _ctk_text_handle_set_mode (priv->text_handle,
5872 CTK_TEXT_HANDLE_MODE_NONE);
5873
5874 if (priv->editable)
5875 {
5876 priv->need_im_reset = TRUE(!(0));
5877 ctk_im_context_focus_out (priv->im_context);
5878 }
5879
5880 return FALSE(0);
5881}
5882
5883static gboolean
5884ctk_text_view_motion_event (CtkWidget *widget, CdkEventMotion *event)
5885{
5886 CtkTextView *text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
5887
5888 ctk_text_view_unobscure_mouse_cursor (text_view);
5889
5890 return CTK_WIDGET_CLASS (ctk_text_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), ((ctk_widget_get_type ()))
))))
->motion_notify_event (widget, event);
5891}
5892
5893static void
5894ctk_text_view_paint (CtkWidget *widget,
5895 cairo_t *cr)
5896{
5897 CtkTextView *text_view;
5898 CtkTextViewPrivate *priv;
5899
5900 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
5901 priv = text_view->priv;
5902
5903 g_return_if_fail (priv->layout != NULL)do { if ((priv->layout != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "priv->layout != NULL"
); return; } } while (0)
;
5904 g_return_if_fail (priv->xoffset >= - priv->left_padding)do { if ((priv->xoffset >= - priv->left_padding)) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "priv->xoffset >= - priv->left_padding"); return
; } } while (0)
;
5905 g_return_if_fail (priv->yoffset >= - priv->top_border)do { if ((priv->yoffset >= - priv->top_border)) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "priv->yoffset >= - priv->top_border"); return; }
} while (0)
;
5906
5907 while (priv->first_validate_idle != 0)
5908 {
5909 DV (g_print (G_STRLOC": first_validate_idle: %d\n",
5910 priv->first_validate_idle));
5911 ctk_text_view_flush_first_validate (text_view);
5912 }
5913
5914 if (!priv->onscreen_validated)
5915 {
5916 g_warning (G_STRLOC"ctktextview.c" ":" "5916" ": somehow some text lines were modified or scrolling occurred since the last validation of lines on the screen - may be a text widget bug.");
5917 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctktextview.c", 5917, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5918 }
5919
5920#if 0
5921 printf ("painting %d,%d %d x %d\n",
5922 area->x, area->y,
5923 area->width, area->height);
5924#endif
5925
5926 cairo_save (cr);
5927 cairo_translate (cr, -priv->xoffset, -priv->yoffset);
5928
5929 ctk_text_layout_draw (priv->layout,
5930 widget,
5931 cr,
5932 NULL((void*)0));
5933
5934 cairo_restore (cr);
5935}
5936
5937static void
5938draw_text (cairo_t *cr,
5939 gpointer user_data)
5940{
5941 CtkWidget *widget = user_data;
5942 CtkTextView *text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
5943 CtkTextViewPrivate *priv = text_view->priv;
5944 CtkStyleContext *context;
5945
5946 context = ctk_widget_get_style_context (widget);
5947 ctk_style_context_save_to_node (context, text_view->priv->text_window->css_node);
5948 ctk_render_background (context, cr,
5949 -priv->xoffset, -priv->yoffset - priv->top_border,
5950 MAX (SCREEN_WIDTH (text_view), priv->width)(((text_window_get_width (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)) > (priv->width)) ? (text_window_get_width
(((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_text_view_get_type ()))))))->priv->
text_window)) : (priv->width))
,
5951 MAX (SCREEN_HEIGHT (text_view), priv->height)(((text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)) > (priv->height)) ? (
text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)) : (priv->height))
);
5952 ctk_render_frame (context, cr,
5953 -priv->xoffset, -priv->yoffset - priv->top_border,
5954 MAX (SCREEN_WIDTH (text_view), priv->width)(((text_window_get_width (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)) > (priv->width)) ? (text_window_get_width
(((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_text_view_get_type ()))))))->priv->
text_window)) : (priv->width))
,
5955 MAX (SCREEN_HEIGHT (text_view), priv->height)(((text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)) > (priv->height)) ? (
text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)) : (priv->height))
);
5956 ctk_style_context_restore (context);
5957
5958 if (CTK_TEXT_VIEW_GET_CLASS (text_view)((((CtkTextViewClass*) (((GTypeInstance*) ((text_view)))->
g_class))))
->draw_layer != NULL((void*)0))
5959 {
5960 cairo_save (cr);
5961 CTK_TEXT_VIEW_GET_CLASS (text_view)((((CtkTextViewClass*) (((GTypeInstance*) ((text_view)))->
g_class))))
->draw_layer (text_view, CTK_TEXT_VIEW_LAYER_BELOW, cr);
5962 cairo_restore (cr);
5963
5964 cairo_save (cr);
5965 cairo_translate (cr, -priv->xoffset, -priv->yoffset);
5966 CTK_TEXT_VIEW_GET_CLASS (text_view)((((CtkTextViewClass*) (((GTypeInstance*) ((text_view)))->
g_class))))
->draw_layer (text_view, CTK_TEXT_VIEW_LAYER_BELOW_TEXT, cr);
5967 cairo_restore (cr);
5968 }
5969
5970 ctk_text_view_paint (widget, cr);
5971
5972 if (CTK_TEXT_VIEW_GET_CLASS (text_view)((((CtkTextViewClass*) (((GTypeInstance*) ((text_view)))->
g_class))))
->draw_layer != NULL((void*)0))
5973 {
5974 cairo_save (cr);
5975 CTK_TEXT_VIEW_GET_CLASS (text_view)((((CtkTextViewClass*) (((GTypeInstance*) ((text_view)))->
g_class))))
->draw_layer (text_view, CTK_TEXT_VIEW_LAYER_ABOVE, cr);
5976 cairo_restore (cr);
5977
5978 cairo_save (cr);
5979 cairo_translate (cr, -priv->xoffset, -priv->yoffset);
5980 CTK_TEXT_VIEW_GET_CLASS (text_view)((((CtkTextViewClass*) (((GTypeInstance*) ((text_view)))->
g_class))))
->draw_layer (text_view, CTK_TEXT_VIEW_LAYER_ABOVE_TEXT, cr);
5981 cairo_restore (cr);
5982 }
5983}
5984
5985static void
5986paint_border_window (CtkTextView *text_view,
5987 cairo_t *cr,
5988 CtkTextWindow *text_window,
5989 CtkStyleContext *context)
5990{
5991 CdkWindow *window;
5992
5993 if (text_window == NULL((void*)0))
5994 return;
5995
5996 window = ctk_text_view_get_window (text_view, text_window->type);
5997 if (ctk_cairo_should_draw_window (cr, window))
5998 {
5999 gint w, h;
6000
6001 ctk_style_context_save_to_node (context, text_window->css_node);
6002
6003 w = cdk_window_get_width (window);
6004 h = cdk_window_get_height (window);
6005
6006 cairo_save (cr);
6007 ctk_cairo_transform_to_window (cr, CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
, window);
6008 ctk_render_background (context, cr, 0, 0, w, h);
6009 cairo_restore (cr);
6010
6011 ctk_style_context_restore (context);
6012 }
6013}
6014
6015static gboolean
6016ctk_text_view_draw (CtkWidget *widget,
6017 cairo_t *cr)
6018{
6019 CtkTextViewPrivate *priv = ((CtkTextView *)widget)->priv;
6020 GSList *tmp_list;
6021 CdkWindow *window;
6022 CtkStyleContext *context;
6023
6024 context = ctk_widget_get_style_context (widget);
6025
6026 text_window_set_padding (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
, context);
6027
6028 if (ctk_cairo_should_draw_window (cr, ctk_widget_get_window (widget)))
6029 {
6030 ctk_render_background (context, cr,
6031 0, 0,
6032 ctk_widget_get_allocated_width (widget),
6033 ctk_widget_get_allocated_height (widget));
6034 }
6035
6036 window = ctk_text_view_get_window (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
,
6037 CTK_TEXT_WINDOW_TEXT);
6038 if (ctk_cairo_should_draw_window (cr, window))
6039 {
6040 cairo_rectangle_int_t view_rect;
6041 cairo_rectangle_int_t canvas_rect;
6042 CtkAllocation alloc;
6043
6044 DV(g_print (">Exposed ("G_STRLOC")\n"));
6045
6046 ctk_widget_get_allocation (widget, &alloc);
6047
6048 view_rect.x = 0;
6049 view_rect.y = 0;
6050 view_rect.width = cdk_window_get_width (window);
6051 view_rect.height = cdk_window_get_height (window);
6052
6053 canvas_rect.x = -ctk_adjustment_get_value (priv->hadjustment);
6054 canvas_rect.y = -ctk_adjustment_get_value (priv->vadjustment);
6055 canvas_rect.width = priv->width;
6056 canvas_rect.height = priv->height;
6057
6058 cairo_save (cr);
6059 ctk_cairo_transform_to_window (cr, widget, window);
6060 _ctk_pixel_cache_draw (priv->pixel_cache, cr, window,
6061 &view_rect, &canvas_rect,
6062 draw_text, widget);
6063 cairo_restore (cr);
6064 }
6065
6066 paint_border_window (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
, cr, priv->left_window, context);
6067 paint_border_window (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
, cr, priv->right_window, context);
6068 paint_border_window (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
, cr, priv->top_window, context);
6069 paint_border_window (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
, cr, priv->bottom_window, context);
6070
6071 /* Propagate exposes to all unanchored children.
6072 * Anchored children are handled in ctk_text_view_paint().
6073 */
6074 tmp_list = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->priv->children;
6075 while (tmp_list != NULL((void*)0))
6076 {
6077 CtkTextViewChild *vc = tmp_list->data;
6078
6079 /* propagate_draw checks that event->window matches
6080 * child->window
6081 */
6082 ctk_container_propagate_draw (CTK_CONTAINER (widget)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_container_get_type ()))))))
,
6083 vc->widget,
6084 cr);
6085
6086 tmp_list = tmp_list->next;
6087 }
6088
6089 return FALSE(0);
6090}
6091
6092static gboolean
6093ctk_text_view_focus (CtkWidget *widget,
6094 CtkDirectionType direction)
6095{
6096 CtkContainer *container;
6097 gboolean result;
6098
6099 container = CTK_CONTAINER (widget)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_container_get_type ()))))))
;
6100
6101 if (!ctk_widget_is_focus (widget) &&
6102 ctk_container_get_focus_child (container) == NULL((void*)0))
6103 {
6104 if (ctk_widget_get_can_focus (widget))
6105 {
6106 ctk_widget_grab_focus (widget);
6107 return TRUE(!(0));
6108 }
6109
6110 return FALSE(0);
6111 }
6112 else
6113 {
6114 gboolean can_focus;
6115 /*
6116 * Unset CAN_FOCUS flag so that ctk_container_focus() allows
6117 * children to get the focus
6118 */
6119 can_focus = ctk_widget_get_can_focus (widget);
6120 ctk_widget_set_can_focus (widget, FALSE(0));
6121 result = CTK_WIDGET_CLASS (ctk_text_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), ((ctk_widget_get_type ()))
))))
->focus (widget, direction);
6122 ctk_widget_set_can_focus (widget, can_focus);
6123
6124 return result;
6125 }
6126}
6127
6128/*
6129 * Container
6130 */
6131
6132static void
6133ctk_text_view_add (CtkContainer *container,
6134 CtkWidget *child)
6135{
6136 /* This is pretty random. */
6137 ctk_text_view_add_child_in_window (CTK_TEXT_VIEW (container)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_text_view_get_type ()))))))
,
6138 child,
6139 CTK_TEXT_WINDOW_WIDGET,
6140 0, 0);
6141}
6142
6143static void
6144ctk_text_view_remove (CtkContainer *container,
6145 CtkWidget *child)
6146{
6147 CtkTextView *text_view;
6148 CtkTextViewPrivate *priv;
6149 CtkTextViewChild *vc;
6150 GSList *iter;
6151
6152 text_view = CTK_TEXT_VIEW (container)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_text_view_get_type ()))))))
;
6153 priv = text_view->priv;
6154
6155 vc = NULL((void*)0);
6156 iter = priv->children;
6157
6158 while (iter != NULL((void*)0))
6159 {
6160 vc = iter->data;
6161
6162 if (vc->widget == child)
6163 break;
6164
6165 iter = iter->next;
6166 }
6167
6168 g_assert (iter != NULL)do { if (iter != ((void*)0)) ; else g_assertion_message_expr (
"Ctk", "ctktextview.c", 6168, ((const char*) (__func__)), "iter != NULL"
); } while (0)
; /* be sure we had the child in the list */
6169
6170 priv->children = g_slist_remove (priv->children, vc);
6171
6172 ctk_widget_unparent (vc->widget);
6173
6174 text_view_child_free (vc);
6175}
6176
6177static void
6178ctk_text_view_forall (CtkContainer *container,
6179 gboolean include_internals G_GNUC_UNUSED__attribute__ ((__unused__)),
6180 CtkCallback callback,
6181 gpointer callback_data)
6182{
6183 GSList *iter;
6184 CtkTextView *text_view;
6185 GSList *copy;
6186
6187 g_return_if_fail (CTK_IS_TEXT_VIEW (container))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((container)); GType __t = ((ctk_text_view_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_VIEW (container)"); return; } } while (0)
;
6188 g_return_if_fail (callback != NULL)do { if ((callback != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "callback != NULL"); return
; } } while (0)
;
6189
6190 text_view = CTK_TEXT_VIEW (container)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_text_view_get_type ()))))))
;
6191
6192 copy = g_slist_copy (text_view->priv->children);
6193 iter = copy;
6194
6195 while (iter != NULL((void*)0))
6196 {
6197 CtkTextViewChild *vc = iter->data;
6198
6199 (* callback) (vc->widget, callback_data);
6200
6201 iter = iter->next;
6202 }
6203
6204 g_slist_free (copy);
6205}
6206
6207#define CURSOR_ON_MULTIPLIER2 2
6208#define CURSOR_OFF_MULTIPLIER1 1
6209#define CURSOR_PEND_MULTIPLIER3 3
6210#define CURSOR_DIVIDER3 3
6211
6212static gboolean
6213cursor_blinks (CtkTextView *text_view)
6214{
6215 CtkSettings *settings = ctk_widget_get_settings (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
6216 gboolean blink;
6217
6218#ifdef DEBUG_VALIDATION_AND_SCROLLING
6219 return FALSE(0);
6220#endif
6221#ifdef G_ENABLE_DEBUG1
6222 if (CTK_DEBUG_CHECK (UPDATES)(ctk_get_debug_flags () & CTK_DEBUG_UPDATES))
6223 return FALSE(0);
6224#endif
6225
6226 g_object_get (settings, "ctk-cursor-blink", &blink, NULL((void*)0));
6227
6228 if (!blink)
6229 return FALSE(0);
6230
6231 if (text_view->priv->editable)
6232 {
6233 CtkTextMark *insert;
6234 CtkTextIter iter;
6235
6236 insert = ctk_text_buffer_get_insert (get_buffer (text_view));
6237 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
6238
6239 if (ctk_text_iter_editable (&iter, text_view->priv->editable))
6240 return blink;
6241 }
6242
6243 return FALSE(0);
6244}
6245
6246static gboolean
6247cursor_visible (CtkTextView *text_view)
6248{
6249 CtkSettings *settings = ctk_widget_get_settings (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
6250 gboolean use_caret;
6251
6252 g_object_get (settings, "ctk-keynav-use-caret", &use_caret, NULL((void*)0));
6253
6254 return use_caret || text_view->priv->cursor_visible;
6255}
6256
6257static gboolean
6258get_middle_click_paste (CtkTextView *text_view)
6259{
6260 CtkSettings *settings;
6261 gboolean paste;
6262
6263 settings = ctk_widget_get_settings (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
6264 g_object_get (settings, "ctk-enable-primary-paste", &paste, NULL((void*)0));
6265
6266 return paste;
6267}
6268
6269static gint
6270get_cursor_time (CtkTextView *text_view)
6271{
6272 CtkSettings *settings = ctk_widget_get_settings (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
6273 gint time;
6274
6275 g_object_get (settings, "ctk-cursor-blink-time", &time, NULL((void*)0));
6276
6277 return time;
6278}
6279
6280static gint
6281get_cursor_blink_timeout (CtkTextView *text_view)
6282{
6283 CtkSettings *settings = ctk_widget_get_settings (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
6284 gint time;
6285
6286 g_object_get (settings, "ctk-cursor-blink-timeout", &time, NULL((void*)0));
6287
6288 return time;
6289}
6290
6291
6292/*
6293 * Blink!
6294 */
6295
6296static gint
6297blink_cb (gpointer data)
6298{
6299 CtkTextView *text_view;
6300 CtkTextViewPrivate *priv;
6301 gboolean visible;
6302 gint blink_timeout;
6303
6304 text_view = CTK_TEXT_VIEW (data)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ctk_text_view_get_type ()))))))
;
6305 priv = text_view->priv;
6306
6307 if (!ctk_widget_has_focus (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
6308 {
6309 g_warning ("CtkTextView - did not receive focus-out-event. If you\n"
6310 "connect a handler to this signal, it must return\n"
6311 "FALSE so the text view gets the event as well");
6312
6313 ctk_text_view_check_cursor_blink (text_view);
6314
6315 return FALSE(0);
6316 }
6317
6318 g_assert (priv->layout)do { if (priv->layout) ; else g_assertion_message_expr ("Ctk"
, "ctktextview.c", 6318, ((const char*) (__func__)), "priv->layout"
); } while (0)
;
6319 g_assert (cursor_visible (text_view))do { if (cursor_visible (text_view)) ; else g_assertion_message_expr
("Ctk", "ctktextview.c", 6319, ((const char*) (__func__)), "cursor_visible (text_view)"
); } while (0)
;
6320
6321 visible = ctk_text_layout_get_cursor_visible (priv->layout);
6322
6323 blink_timeout = get_cursor_blink_timeout (text_view);
6324 if (priv->blink_time > 1000 * blink_timeout &&
6325 blink_timeout < G_MAXINT2147483647/1000)
6326 {
6327 /* we've blinked enough without the user doing anything, stop blinking */
6328 visible = 0;
6329 priv->blink_timeout = 0;
6330 }
6331 else if (visible)
6332 {
6333 priv->blink_timeout = cdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER1 / CURSOR_DIVIDER3,
6334 blink_cb,
6335 text_view);
6336 g_source_set_name_by_id (priv->blink_timeout, "[ctk+] blink_cb");
6337 }
6338 else
6339 {
6340 priv->blink_timeout = cdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER2 / CURSOR_DIVIDER3,
6341 blink_cb,
6342 text_view);
6343 g_source_set_name_by_id (priv->blink_timeout, "[ctk+] blink_cb");
6344 priv->blink_time += get_cursor_time (text_view);
6345 }
6346
6347 /* Block changed_handler while changing the layout's cursor visibility
6348 * because it would expose the whole paragraph. Instead, we expose
6349 * the cursor's area(s) manually below.
6350 */
6351 g_signal_handlers_block_by_func (priv->layout,g_signal_handlers_block_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (changed_handler), (text_view))
6352 changed_handler,g_signal_handlers_block_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (changed_handler), (text_view))
6353 text_view)g_signal_handlers_block_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (changed_handler), (text_view))
;
6354 ctk_text_layout_set_cursor_visible (priv->layout, !visible);
6355 g_signal_handlers_unblock_by_func (priv->layout,g_signal_handlers_unblock_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (changed_handler), (text_view))
6356 changed_handler,g_signal_handlers_unblock_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (changed_handler), (text_view))
6357 text_view)g_signal_handlers_unblock_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (changed_handler), (text_view))
;
6358
6359 text_window_invalidate_cursors (priv->text_window);
6360
6361 /* Remove ourselves */
6362 return FALSE(0);
6363}
6364
6365
6366static void
6367ctk_text_view_stop_cursor_blink (CtkTextView *text_view)
6368{
6369 if (text_view->priv->blink_timeout)
6370 {
6371 g_source_remove (text_view->priv->blink_timeout);
6372 text_view->priv->blink_timeout = 0;
6373 }
6374}
6375
6376static void
6377ctk_text_view_check_cursor_blink (CtkTextView *text_view)
6378{
6379 CtkTextViewPrivate *priv = text_view->priv;
6380
6381 if (priv->layout != NULL((void*)0) &&
6382 cursor_visible (text_view) &&
6383 ctk_widget_has_focus (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
6384 {
6385 if (cursor_blinks (text_view))
6386 {
6387 if (priv->blink_timeout == 0)
6388 {
6389 ctk_text_layout_set_cursor_visible (priv->layout, TRUE(!(0)));
6390
6391 priv->blink_timeout = cdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER1 / CURSOR_DIVIDER3,
6392 blink_cb,
6393 text_view);
6394 g_source_set_name_by_id (priv->blink_timeout, "[ctk+] blink_cb");
6395 }
6396 }
6397 else
6398 {
6399 ctk_text_view_stop_cursor_blink (text_view);
6400 ctk_text_layout_set_cursor_visible (priv->layout, TRUE(!(0)));
6401 }
6402 }
6403 else
6404 {
6405 ctk_text_view_stop_cursor_blink (text_view);
6406 ctk_text_layout_set_cursor_visible (priv->layout, FALSE(0));
6407 }
6408}
6409
6410static void
6411ctk_text_view_pend_cursor_blink (CtkTextView *text_view)
6412{
6413 CtkTextViewPrivate *priv = text_view->priv;
6414
6415 if (priv->layout != NULL((void*)0) &&
6416 cursor_visible (text_view) &&
6417 ctk_widget_has_focus (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
) &&
6418 cursor_blinks (text_view))
6419 {
6420 ctk_text_view_stop_cursor_blink (text_view);
6421 ctk_text_layout_set_cursor_visible (priv->layout, TRUE(!(0)));
6422
6423 priv->blink_timeout = cdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER3 / CURSOR_DIVIDER3,
6424 blink_cb,
6425 text_view);
6426 g_source_set_name_by_id (priv->blink_timeout, "[ctk+] blink_cb");
6427 }
6428}
6429
6430static void
6431ctk_text_view_reset_blink_time (CtkTextView *text_view)
6432{
6433 CtkTextViewPrivate *priv = text_view->priv;
6434
6435 priv->blink_time = 0;
6436}
6437
6438
6439/*
6440 * Key binding handlers
6441 */
6442
6443static gboolean
6444ctk_text_view_move_iter_by_lines (CtkTextView *text_view,
6445 CtkTextIter *newplace,
6446 gint count)
6447{
6448 gboolean ret = TRUE(!(0));
6449
6450 while (count < 0)
6451 {
6452 ret = ctk_text_layout_move_iter_to_previous_line (text_view->priv->layout, newplace);
6453 count++;
6454 }
6455
6456 while (count > 0)
6457 {
6458 ret = ctk_text_layout_move_iter_to_next_line (text_view->priv->layout, newplace);
6459 count--;
6460 }
6461
6462 return ret;
6463}
6464
6465static void
6466move_cursor (CtkTextView *text_view,
6467 const CtkTextIter *new_location,
6468 gboolean extend_selection)
6469{
6470 if (extend_selection)
6471 ctk_text_buffer_move_mark_by_name (get_buffer (text_view),
6472 "insert",
6473 new_location);
6474 else
6475 ctk_text_buffer_place_cursor (get_buffer (text_view),
6476 new_location);
6477 ctk_text_view_check_cursor_blink (text_view);
6478}
6479
6480static gboolean
6481iter_line_is_rtl (const CtkTextIter *iter)
6482{
6483 CtkTextIter start, end;
6484 char *text;
6485 PangoDirection direction;
6486
6487 start = end = *iter;
6488 ctk_text_iter_set_line_offset (&start, 0);
6489 ctk_text_iter_forward_line (&end);
6490 text = ctk_text_iter_get_visible_text (&start, &end);
6491 direction = _ctk_pango_find_base_dir (text, -1);
6492
6493 g_free (text);
6494
6495 return direction == PANGO_DIRECTION_RTL;
6496}
6497
6498static void
6499ctk_text_view_move_cursor (CtkTextView *text_view,
6500 CtkMovementStep step,
6501 gint count,
6502 gboolean extend_selection)
6503{
6504 CtkTextViewPrivate *priv;
6505 CtkTextIter insert;
6506 CtkTextIter newplace;
6507 gboolean cancel_selection = FALSE(0);
6508 gint cursor_x_pos = 0;
6509 CtkDirectionType leave_direction = -1;
6510
6511 priv = text_view->priv;
6512
6513 if (!cursor_visible (text_view))
6514 {
6515 CtkScrollStep scroll_step;
6516 gdouble old_xpos, old_ypos;
6517
6518 switch (step)
6519 {
6520 case CTK_MOVEMENT_VISUAL_POSITIONS:
6521 leave_direction = count > 0 ? CTK_DIR_RIGHT : CTK_DIR_LEFT;
6522 /* fall through */
6523 case CTK_MOVEMENT_LOGICAL_POSITIONS:
6524 case CTK_MOVEMENT_WORDS:
6525 scroll_step = CTK_SCROLL_HORIZONTAL_STEPS;
6526 break;
6527 case CTK_MOVEMENT_DISPLAY_LINE_ENDS:
6528 scroll_step = CTK_SCROLL_HORIZONTAL_ENDS;
6529 break;
6530 case CTK_MOVEMENT_DISPLAY_LINES:
6531 leave_direction = count > 0 ? CTK_DIR_DOWN : CTK_DIR_UP;
6532 /* fall through */
6533 case CTK_MOVEMENT_PARAGRAPHS:
6534 case CTK_MOVEMENT_PARAGRAPH_ENDS:
6535 scroll_step = CTK_SCROLL_STEPS;
6536 break;
6537 case CTK_MOVEMENT_PAGES:
6538 scroll_step = CTK_SCROLL_PAGES;
6539 break;
6540 case CTK_MOVEMENT_HORIZONTAL_PAGES:
6541 scroll_step = CTK_SCROLL_HORIZONTAL_PAGES;
6542 break;
6543 case CTK_MOVEMENT_BUFFER_ENDS:
6544 scroll_step = CTK_SCROLL_ENDS;
6545 break;
6546 default:
6547 scroll_step = CTK_SCROLL_PAGES;
6548 break;
6549 }
6550
6551 old_xpos = ctk_adjustment_get_value (priv->hadjustment);
6552 old_ypos = ctk_adjustment_get_value (priv->vadjustment);
6553 ctk_text_view_move_viewport (text_view, scroll_step, count);
6554 if ((old_xpos == ctk_adjustment_get_target_value (priv->hadjustment) &&
6555 old_ypos == ctk_adjustment_get_target_value (priv->vadjustment)) &&
6556 leave_direction != (CtkDirectionType)-1 &&
6557 !ctk_widget_keynav_failed (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
6558 leave_direction))
6559 {
6560 g_signal_emit_by_name (text_view, "move-focus", leave_direction);
6561 }
6562
6563 return;
6564 }
6565
6566 ctk_text_view_reset_im_context (text_view);
6567
6568 if (step == CTK_MOVEMENT_PAGES)
6569 {
6570 if (!ctk_text_view_scroll_pages (text_view, count, extend_selection))
6571 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
6572
6573 ctk_text_view_check_cursor_blink (text_view);
6574 ctk_text_view_pend_cursor_blink (text_view);
6575 return;
6576 }
6577 else if (step == CTK_MOVEMENT_HORIZONTAL_PAGES)
6578 {
6579 if (!ctk_text_view_scroll_hpages (text_view, count, extend_selection))
6580 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
6581
6582 ctk_text_view_check_cursor_blink (text_view);
6583 ctk_text_view_pend_cursor_blink (text_view);
6584 return;
6585 }
6586
6587 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
6588 ctk_text_buffer_get_insert (get_buffer (text_view)));
6589
6590 if (! extend_selection)
6591 {
6592 gboolean move_forward = count > 0;
6593 CtkTextIter sel_bound;
6594
6595 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &sel_bound,
6596 ctk_text_buffer_get_selection_bound (get_buffer (text_view)));
6597
6598 if (iter_line_is_rtl (&insert))
6599 move_forward = !move_forward;
6600
6601 /* if we move forward, assume the cursor is at the end of the selection;
6602 * if we move backward, assume the cursor is at the start
6603 */
6604 if (move_forward)
6605 ctk_text_iter_order (&sel_bound, &insert);
6606 else
6607 ctk_text_iter_order (&insert, &sel_bound);
6608
6609 /* if we actually have a selection, just move *to* the beginning/end
6610 * of the selection and not *from* there on LOGICAL_POSITIONS
6611 * and VISUAL_POSITIONS movement
6612 */
6613 if (! ctk_text_iter_equal (&sel_bound, &insert))
6614 cancel_selection = TRUE(!(0));
6615 }
6616
6617 newplace = insert;
6618
6619 if (step == CTK_MOVEMENT_DISPLAY_LINES)
6620 ctk_text_view_get_virtual_cursor_pos (text_view, &insert, &cursor_x_pos, NULL((void*)0));
6621
6622 switch (step)
6623 {
6624 case CTK_MOVEMENT_LOGICAL_POSITIONS:
6625 if (! cancel_selection)
6626 ctk_text_iter_forward_visible_cursor_positions (&newplace, count);
6627 break;
6628
6629 case CTK_MOVEMENT_VISUAL_POSITIONS:
6630 if (! cancel_selection)
6631 ctk_text_layout_move_iter_visually (priv->layout,
6632 &newplace, count);
6633 break;
6634
6635 case CTK_MOVEMENT_WORDS:
6636 if (iter_line_is_rtl (&newplace))
6637 count *= -1;
6638
6639 if (count < 0)
6640 ctk_text_iter_backward_visible_word_starts (&newplace, -count);
6641 else if (count > 0)
6642 {
6643 if (!ctk_text_iter_forward_visible_word_ends (&newplace, count))
6644 ctk_text_iter_forward_to_line_end (&newplace);
6645 }
6646 break;
6647
6648 case CTK_MOVEMENT_DISPLAY_LINES:
6649 if (count < 0)
6650 {
6651 leave_direction = CTK_DIR_UP;
6652
6653 if (ctk_text_view_move_iter_by_lines (text_view, &newplace, count))
6654 ctk_text_layout_move_iter_to_x (priv->layout, &newplace, cursor_x_pos);
6655 else
6656 ctk_text_iter_set_line_offset (&newplace, 0);
6657 }
6658 if (count > 0)
6659 {
6660 leave_direction = CTK_DIR_DOWN;
6661
6662 if (ctk_text_view_move_iter_by_lines (text_view, &newplace, count))
6663 ctk_text_layout_move_iter_to_x (priv->layout, &newplace, cursor_x_pos);
6664 else
6665 ctk_text_iter_forward_to_line_end (&newplace);
6666 }
6667 break;
6668
6669 case CTK_MOVEMENT_DISPLAY_LINE_ENDS:
6670 if (count > 1)
6671 ctk_text_view_move_iter_by_lines (text_view, &newplace, --count);
6672 else if (count < -1)
6673 ctk_text_view_move_iter_by_lines (text_view, &newplace, ++count);
6674
6675 if (count != 0)
6676 ctk_text_layout_move_iter_to_line_end (priv->layout, &newplace, count);
6677 break;
6678
6679 case CTK_MOVEMENT_PARAGRAPHS:
6680 if (count > 0)
6681 {
6682 if (!ctk_text_iter_ends_line (&newplace))
6683 {
6684 ctk_text_iter_forward_to_line_end (&newplace);
6685 --count;
6686 }
6687 ctk_text_iter_forward_visible_lines (&newplace, count);
6688 ctk_text_iter_forward_to_line_end (&newplace);
6689 }
6690 else if (count < 0)
6691 {
6692 if (ctk_text_iter_get_line_offset (&newplace) > 0)
6693 ctk_text_iter_set_line_offset (&newplace, 0);
6694 ctk_text_iter_forward_visible_lines (&newplace, count);
6695 ctk_text_iter_set_line_offset (&newplace, 0);
6696 }
6697 break;
6698
6699 case CTK_MOVEMENT_PARAGRAPH_ENDS:
6700 if (count > 0)
6701 {
6702 if (!ctk_text_iter_ends_line (&newplace))
6703 ctk_text_iter_forward_to_line_end (&newplace);
6704 }
6705 else if (count < 0)
6706 {
6707 ctk_text_iter_set_line_offset (&newplace, 0);
6708 }
6709 break;
6710
6711 case CTK_MOVEMENT_BUFFER_ENDS:
6712 if (count > 0)
6713 ctk_text_buffer_get_end_iter (get_buffer (text_view), &newplace);
6714 else if (count < 0)
6715 ctk_text_buffer_get_iter_at_offset (get_buffer (text_view), &newplace, 0);
6716 break;
6717
6718 default:
6719 break;
6720 }
6721
6722 /* call move_cursor() even if the cursor hasn't moved, since it
6723 cancels the selection
6724 */
6725 move_cursor (text_view, &newplace, extend_selection);
6726
6727 if (!ctk_text_iter_equal (&insert, &newplace))
6728 {
6729 DV(g_print (G_STRLOC": scrolling onscreen\n"));
6730 ctk_text_view_scroll_mark_onscreen (text_view,
6731 ctk_text_buffer_get_insert (get_buffer (text_view)));
6732
6733 if (step == CTK_MOVEMENT_DISPLAY_LINES)
6734 ctk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
6735 }
6736 else if (leave_direction != (CtkDirectionType)-1)
6737 {
6738 if (!ctk_widget_keynav_failed (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
6739 leave_direction))
6740 {
6741 g_signal_emit_by_name (text_view, "move-focus", leave_direction);
6742 }
6743 }
6744 else if (! cancel_selection)
6745 {
6746 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
6747 }
6748
6749 ctk_text_view_check_cursor_blink (text_view);
6750 ctk_text_view_pend_cursor_blink (text_view);
6751}
6752
6753static void
6754ctk_text_view_move_viewport (CtkTextView *text_view,
6755 CtkScrollStep step,
6756 gint count)
6757{
6758 CtkAdjustment *adjustment;
6759 gdouble increment;
6760
6761 switch (step)
6762 {
6763 case CTK_SCROLL_STEPS:
6764 case CTK_SCROLL_PAGES:
6765 case CTK_SCROLL_ENDS:
6766 adjustment = text_view->priv->vadjustment;
6767 break;
6768 case CTK_SCROLL_HORIZONTAL_STEPS:
6769 case CTK_SCROLL_HORIZONTAL_PAGES:
6770 case CTK_SCROLL_HORIZONTAL_ENDS:
6771 adjustment = text_view->priv->hadjustment;
6772 break;
6773 default:
6774 adjustment = text_view->priv->vadjustment;
6775 break;
6776 }
6777
6778 switch (step)
6779 {
6780 case CTK_SCROLL_STEPS:
6781 case CTK_SCROLL_HORIZONTAL_STEPS:
6782 increment = ctk_adjustment_get_step_increment (adjustment);
6783 break;
6784 case CTK_SCROLL_PAGES:
6785 case CTK_SCROLL_HORIZONTAL_PAGES:
6786 increment = ctk_adjustment_get_page_increment (adjustment);
6787 break;
6788 case CTK_SCROLL_ENDS:
6789 case CTK_SCROLL_HORIZONTAL_ENDS:
6790 increment = ctk_adjustment_get_upper (adjustment) - ctk_adjustment_get_lower (adjustment);
6791 break;
6792 default:
6793 increment = 0.0;
6794 break;
6795 }
6796
6797 ctk_adjustment_animate_to_value (adjustment, ctk_adjustment_get_value (adjustment) + count * increment);
6798}
6799
6800static void
6801ctk_text_view_set_anchor (CtkTextView *text_view)
6802{
6803 CtkTextIter insert;
6804
6805 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
6806 ctk_text_buffer_get_insert (get_buffer (text_view)));
6807
6808 ctk_text_buffer_create_mark (get_buffer (text_view), "anchor", &insert, TRUE(!(0)));
6809}
6810
6811static gboolean
6812ctk_text_view_scroll_pages (CtkTextView *text_view,
6813 gint count,
6814 gboolean extend_selection)
6815{
6816 CtkTextViewPrivate *priv;
6817 CtkAdjustment *adjustment;
6818 gint cursor_x_pos, cursor_y_pos;
6819 CtkTextMark *insert_mark;
6820 CtkTextIter old_insert;
6821 CtkTextIter new_insert;
6822 CtkTextIter anchor;
6823 gdouble newval;
6824 gdouble oldval;
6825 gint y0, y1;
6826
6827 priv = text_view->priv;
6828
6829 g_return_val_if_fail (priv->vadjustment != NULL, FALSE)do { if ((priv->vadjustment != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "priv->vadjustment != NULL"
); return ((0)); } } while (0)
;
6830
6831 adjustment = priv->vadjustment;
6832
6833 insert_mark = ctk_text_buffer_get_insert (get_buffer (text_view));
6834
6835 /* Make sure we start from the current cursor position, even
6836 * if it was offscreen, but don't queue more scrolls if we're
6837 * already behind.
6838 */
6839 if (priv->pending_scroll)
6840 cancel_pending_scroll (text_view);
6841 else
6842 ctk_text_view_scroll_mark_onscreen (text_view, insert_mark);
6843
6844 /* Validate the region that will be brought into view by the cursor motion
6845 */
6846 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view),
6847 &old_insert, insert_mark);
6848
6849 if (count < 0)
6850 {
6851 ctk_text_view_get_first_para_iter (text_view, &anchor);
6852 y0 = ctk_adjustment_get_page_size (adjustment);
6853 y1 = ctk_adjustment_get_page_size (adjustment) + count * ctk_adjustment_get_page_increment (adjustment);
6854 }
6855 else
6856 {
6857 ctk_text_view_get_first_para_iter (text_view, &anchor);
6858 y0 = count * ctk_adjustment_get_page_increment (adjustment) + ctk_adjustment_get_page_size (adjustment);
6859 y1 = 0;
6860 }
6861
6862 ctk_text_layout_validate_yrange (priv->layout, &anchor, y0, y1);
6863 /* FIXME do we need to update the adjustment ranges here? */
6864
6865 new_insert = old_insert;
6866
6867 if (count < 0 && ctk_adjustment_get_value (adjustment) <= (ctk_adjustment_get_lower (adjustment) + 1e-12))
6868 {
6869 /* already at top, just be sure we are at offset 0 */
6870 ctk_text_buffer_get_start_iter (get_buffer (text_view), &new_insert);
6871 move_cursor (text_view, &new_insert, extend_selection);
6872 }
6873 else if (count > 0 && ctk_adjustment_get_value (adjustment) >= (ctk_adjustment_get_upper (adjustment) - ctk_adjustment_get_page_size (adjustment) - 1e-12))
6874 {
6875 /* already at bottom, just be sure we are at the end */
6876 ctk_text_buffer_get_end_iter (get_buffer (text_view), &new_insert);
6877 move_cursor (text_view, &new_insert, extend_selection);
6878 }
6879 else
6880 {
6881 ctk_text_view_get_virtual_cursor_pos (text_view, NULL((void*)0), &cursor_x_pos, &cursor_y_pos);
6882
6883 oldval = newval = ctk_adjustment_get_target_value (adjustment);
6884 newval += count * ctk_adjustment_get_page_increment (adjustment);
6885
6886 ctk_adjustment_animate_to_value (adjustment, newval);
6887 cursor_y_pos += newval - oldval;
6888
6889 ctk_text_layout_get_iter_at_pixel (priv->layout, &new_insert, cursor_x_pos, cursor_y_pos);
6890
6891 move_cursor (text_view, &new_insert, extend_selection);
6892
6893 ctk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
6894 }
6895
6896 /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
6897 * only guarantees 1 pixel onscreen.
6898 */
6899 DV(g_print (G_STRLOC": scrolling onscreen\n"));
6900
6901 return !ctk_text_iter_equal (&old_insert, &new_insert);
6902}
6903
6904static gboolean
6905ctk_text_view_scroll_hpages (CtkTextView *text_view,
6906 gint count,
6907 gboolean extend_selection)
6908{
6909 CtkTextViewPrivate *priv;
6910 CtkAdjustment *adjustment;
6911 gint cursor_x_pos, cursor_y_pos;
6912 CtkTextMark *insert_mark;
6913 CtkTextIter old_insert;
6914 CtkTextIter new_insert;
6915 gdouble newval;
6916 gdouble oldval;
6917 gint y, height;
6918
6919 priv = text_view->priv;
6920
6921 g_return_val_if_fail (priv->hadjustment != NULL, FALSE)do { if ((priv->hadjustment != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "priv->hadjustment != NULL"
); return ((0)); } } while (0)
;
6922
6923 adjustment = priv->hadjustment;
6924
6925 insert_mark = ctk_text_buffer_get_insert (get_buffer (text_view));
6926
6927 /* Make sure we start from the current cursor position, even
6928 * if it was offscreen, but don't queue more scrolls if we're
6929 * already behind.
6930 */
6931 if (priv->pending_scroll)
6932 cancel_pending_scroll (text_view);
6933 else
6934 ctk_text_view_scroll_mark_onscreen (text_view, insert_mark);
6935
6936 /* Validate the line that we're moving within.
6937 */
6938 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view),
6939 &old_insert, insert_mark);
6940
6941 ctk_text_layout_get_line_yrange (priv->layout, &old_insert, &y, &height);
6942 ctk_text_layout_validate_yrange (priv->layout, &old_insert, y, y + height);
6943 /* FIXME do we need to update the adjustment ranges here? */
6944
6945 new_insert = old_insert;
6946
6947 if (count < 0 && ctk_adjustment_get_value (adjustment) <= (ctk_adjustment_get_lower (adjustment) + 1e-12))
6948 {
6949 /* already at far left, just be sure we are at offset 0 */
6950 ctk_text_iter_set_line_offset (&new_insert, 0);
6951 move_cursor (text_view, &new_insert, extend_selection);
6952 }
6953 else if (count > 0 && ctk_adjustment_get_value (adjustment) >= (ctk_adjustment_get_upper (adjustment) - ctk_adjustment_get_page_size (adjustment) - 1e-12))
6954 {
6955 /* already at far right, just be sure we are at the end */
6956 if (!ctk_text_iter_ends_line (&new_insert))
6957 ctk_text_iter_forward_to_line_end (&new_insert);
6958 move_cursor (text_view, &new_insert, extend_selection);
6959 }
6960 else
6961 {
6962 ctk_text_view_get_virtual_cursor_pos (text_view, NULL((void*)0), &cursor_x_pos, &cursor_y_pos);
6963
6964 oldval = newval = ctk_adjustment_get_target_value (adjustment);
6965 newval += count * ctk_adjustment_get_page_increment (adjustment);
6966
6967 ctk_adjustment_animate_to_value (adjustment, newval);
6968 cursor_x_pos += newval - oldval;
6969
6970 ctk_text_layout_get_iter_at_pixel (priv->layout, &new_insert, cursor_x_pos, cursor_y_pos);
6971 move_cursor (text_view, &new_insert, extend_selection);
6972
6973 ctk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
6974 }
6975
6976 /* FIXME for lines shorter than the overall widget width, this results in a
6977 * "bounce" effect as we scroll to the right of the widget, then scroll
6978 * back to get the end of the line onscreen.
6979 * http://bugzilla.gnome.org/show_bug.cgi?id=68963
6980 */
6981
6982 /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
6983 * only guarantees 1 pixel onscreen.
6984 */
6985 DV(g_print (G_STRLOC": scrolling onscreen\n"));
6986
6987 return !ctk_text_iter_equal (&old_insert, &new_insert);
6988}
6989
6990static gboolean
6991whitespace (gunichar ch,
6992 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
6993{
6994 return (ch == ' ' || ch == '\t');
6995}
6996
6997static gboolean
6998not_whitespace (gunichar ch, gpointer user_data)
6999{
7000 return !whitespace (ch, user_data);
7001}
7002
7003static gboolean
7004find_whitepace_region (const CtkTextIter *center,
7005 CtkTextIter *start, CtkTextIter *end)
7006{
7007 *start = *center;
7008 *end = *center;
7009
7010 if (ctk_text_iter_backward_find_char (start, not_whitespace, NULL((void*)0), NULL((void*)0)))
7011 ctk_text_iter_forward_char (start); /* we want the first whitespace... */
7012 if (whitespace (ctk_text_iter_get_char (end), NULL((void*)0)))
7013 ctk_text_iter_forward_find_char (end, not_whitespace, NULL((void*)0), NULL((void*)0));
7014
7015 return !ctk_text_iter_equal (start, end);
7016}
7017
7018static void
7019ctk_text_view_insert_at_cursor (CtkTextView *text_view,
7020 const gchar *str)
7021{
7022 if (!ctk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
7023 text_view->priv->editable))
7024 {
7025 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
7026 }
7027}
7028
7029static void
7030ctk_text_view_delete_from_cursor (CtkTextView *text_view,
7031 CtkDeleteType type,
7032 gint count)
7033{
7034 CtkTextViewPrivate *priv;
7035 CtkTextIter insert;
7036 CtkTextIter start;
7037 CtkTextIter end;
7038 gboolean leave_one = FALSE(0);
7039
7040 priv = text_view->priv;
7041
7042 ctk_text_view_reset_im_context (text_view);
7043
7044 if (type == CTK_DELETE_CHARS)
7045 {
7046 /* Char delete deletes the selection, if one exists */
7047 if (ctk_text_buffer_delete_selection (get_buffer (text_view), TRUE(!(0)),
7048 priv->editable))
7049 return;
7050 }
7051
7052 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
7053 ctk_text_buffer_get_insert (get_buffer (text_view)));
7054
7055 start = insert;
7056 end = insert;
7057
7058 switch (type)
7059 {
7060 case CTK_DELETE_CHARS:
7061 ctk_text_iter_forward_cursor_positions (&end, count);
7062 break;
7063
7064 case CTK_DELETE_WORD_ENDS:
7065 if (count > 0)
7066 ctk_text_iter_forward_word_ends (&end, count);
7067 else if (count < 0)
7068 ctk_text_iter_backward_word_starts (&start, 0 - count);
7069 break;
7070
7071 case CTK_DELETE_WORDS:
7072 break;
7073
7074 case CTK_DELETE_DISPLAY_LINE_ENDS:
7075 break;
7076
7077 case CTK_DELETE_DISPLAY_LINES:
7078 break;
7079
7080 case CTK_DELETE_PARAGRAPH_ENDS:
7081 if (count > 0)
7082 {
7083 /* If we're already at a newline, we need to
7084 * simply delete that newline, instead of
7085 * moving to the next one.
7086 */
7087 if (ctk_text_iter_ends_line (&end))
7088 {
7089 ctk_text_iter_forward_line (&end);
7090 --count;
7091 }
7092
7093 while (count > 0)
7094 {
7095 if (!ctk_text_iter_forward_to_line_end (&end))
7096 break;
7097
7098 --count;
7099 }
7100 }
7101 else if (count < 0)
7102 {
7103 if (ctk_text_iter_starts_line (&start))
7104 {
7105 ctk_text_iter_backward_line (&start);
7106 if (!ctk_text_iter_ends_line (&end))
7107 ctk_text_iter_forward_to_line_end (&start);
7108 }
7109 else
7110 {
7111 ctk_text_iter_set_line_offset (&start, 0);
7112 }
7113 ++count;
7114
7115 ctk_text_iter_backward_lines (&start, -count);
7116 }
7117 break;
7118
7119 case CTK_DELETE_PARAGRAPHS:
7120 if (count > 0)
7121 {
7122 ctk_text_iter_set_line_offset (&start, 0);
7123 ctk_text_iter_forward_to_line_end (&end);
7124
7125 /* Do the lines beyond the first. */
7126 while (count > 1)
7127 {
7128 ctk_text_iter_forward_to_line_end (&end);
7129
7130 --count;
7131 }
7132 }
7133
7134 /* FIXME negative count? */
7135
7136 break;
7137
7138 case CTK_DELETE_WHITESPACE:
7139 {
7140 find_whitepace_region (&insert, &start, &end);
7141 }
7142 break;
7143
7144 default:
7145 break;
7146 }
7147
7148 if (!ctk_text_iter_equal (&start, &end))
7149 {
7150 ctk_text_buffer_begin_user_action (get_buffer (text_view));
7151
7152 if (ctk_text_buffer_delete_interactive (get_buffer (text_view), &start, &end,
7153 priv->editable))
7154 {
7155 if (leave_one)
7156 ctk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view),
7157 " ", 1,
7158 priv->editable);
7159 }
7160 else
7161 {
7162 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
7163 }
7164
7165 ctk_text_buffer_end_user_action (get_buffer (text_view));
7166 ctk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
7167
7168 DV(g_print (G_STRLOC": scrolling onscreen\n"));
7169 ctk_text_view_scroll_mark_onscreen (text_view,
7170 ctk_text_buffer_get_insert (get_buffer (text_view)));
7171 }
7172 else
7173 {
7174 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
7175 }
7176}
7177
7178static void
7179ctk_text_view_backspace (CtkTextView *text_view)
7180{
7181 CtkTextViewPrivate *priv;
7182 CtkTextIter insert;
7183
7184 priv = text_view->priv;
7185
7186 ctk_text_view_reset_im_context (text_view);
7187
7188 /* Backspace deletes the selection, if one exists */
7189 if (ctk_text_buffer_delete_selection (get_buffer (text_view), TRUE(!(0)),
7190 priv->editable))
7191 return;
7192
7193 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7194 &insert,
7195 ctk_text_buffer_get_insert (get_buffer (text_view)));
7196
7197 if (ctk_text_buffer_backspace (get_buffer (text_view), &insert,
7198 TRUE(!(0)), priv->editable))
7199 {
7200 ctk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
7201 DV(g_print (G_STRLOC": scrolling onscreen\n"));
7202 ctk_text_view_scroll_mark_onscreen (text_view,
7203 ctk_text_buffer_get_insert (get_buffer (text_view)));
7204 }
7205 else
7206 {
7207 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
7208 }
7209}
7210
7211static void
7212ctk_text_view_cut_clipboard (CtkTextView *text_view)
7213{
7214 CtkClipboard *clipboard = ctk_widget_get_clipboard (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
7215 CDK_SELECTION_CLIPBOARD((CdkAtom)((gpointer) (gulong) (69))));
7216
7217 ctk_text_buffer_cut_clipboard (get_buffer (text_view),
7218 clipboard,
7219 text_view->priv->editable);
7220 DV(g_print (G_STRLOC": scrolling onscreen\n"));
7221 ctk_text_view_scroll_mark_onscreen (text_view,
7222 ctk_text_buffer_get_insert (get_buffer (text_view)));
7223 ctk_text_view_selection_bubble_popup_unset (text_view);
7224}
7225
7226static void
7227ctk_text_view_copy_clipboard (CtkTextView *text_view)
7228{
7229 CtkClipboard *clipboard = ctk_widget_get_clipboard (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
7230 CDK_SELECTION_CLIPBOARD((CdkAtom)((gpointer) (gulong) (69))));
7231
7232 ctk_text_buffer_copy_clipboard (get_buffer (text_view),
7233 clipboard);
7234
7235 /* on copy do not scroll, we are already onscreen */
7236}
7237
7238static void
7239ctk_text_view_paste_clipboard (CtkTextView *text_view)
7240{
7241 CtkClipboard *clipboard = ctk_widget_get_clipboard (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
7242 CDK_SELECTION_CLIPBOARD((CdkAtom)((gpointer) (gulong) (69))));
7243
7244 text_view->priv->scroll_after_paste = TRUE(!(0));
7245
7246 ctk_text_buffer_paste_clipboard (get_buffer (text_view),
7247 clipboard,
7248 NULL((void*)0),
7249 text_view->priv->editable);
7250}
7251
7252static void
7253ctk_text_view_paste_done_handler (CtkTextBuffer *buffer,
7254 CtkClipboard *clipboard G_GNUC_UNUSED__attribute__ ((__unused__)),
7255 gpointer data)
7256{
7257 CtkTextView *text_view = data;
7258 CtkTextViewPrivate *priv;
7259
7260 priv = text_view->priv;
7261
7262 if (priv->scroll_after_paste)
7263 {
7264 DV(g_print (G_STRLOC": scrolling onscreen\n"));
7265 ctk_text_view_scroll_mark_onscreen (text_view, ctk_text_buffer_get_insert (buffer));
7266 }
7267
7268 priv->scroll_after_paste = FALSE(0);
7269}
7270
7271static void
7272ctk_text_view_buffer_changed_handler (CtkTextBuffer *buffer G_GNUC_UNUSED__attribute__ ((__unused__)),
7273 gpointer data)
7274{
7275 CtkTextView *text_view = data;
7276 CtkTextViewPrivate *priv = text_view->priv;
7277
7278 if (priv->handling_key_event)
7279 ctk_text_view_obscure_mouse_cursor (text_view);
7280
7281 if (priv->text_handle)
7282 ctk_text_view_update_handles (text_view,
7283 _ctk_text_handle_get_mode (priv->text_handle));
7284}
7285
7286static void
7287ctk_text_view_toggle_overwrite (CtkTextView *text_view)
7288{
7289 CtkTextViewPrivate *priv = text_view->priv;
7290
7291 if (priv->text_window)
7292 text_window_invalidate_cursors (priv->text_window);
7293
7294 priv->overwrite_mode = !priv->overwrite_mode;
7295
7296 if (priv->layout)
7297 ctk_text_layout_set_overwrite_mode (priv->layout,
7298 priv->overwrite_mode && priv->editable);
7299
7300 if (priv->text_window)
7301 text_window_invalidate_cursors (priv->text_window);
7302
7303 ctk_text_view_pend_cursor_blink (text_view);
7304
7305 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "overwrite");
7306}
7307
7308/**
7309 * ctk_text_view_get_overwrite:
7310 * @text_view: a #CtkTextView
7311 *
7312 * Returns whether the #CtkTextView is in overwrite mode or not.
7313 *
7314 * Returns: whether @text_view is in overwrite mode or not.
7315 *
7316 * Since: 2.4
7317 **/
7318gboolean
7319ctk_text_view_get_overwrite (CtkTextView *text_view)
7320{
7321 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
7322
7323 return text_view->priv->overwrite_mode;
7324}
7325
7326/**
7327 * ctk_text_view_set_overwrite:
7328 * @text_view: a #CtkTextView
7329 * @overwrite: %TRUE to turn on overwrite mode, %FALSE to turn it off
7330 *
7331 * Changes the #CtkTextView overwrite mode.
7332 *
7333 * Since: 2.4
7334 **/
7335void
7336ctk_text_view_set_overwrite (CtkTextView *text_view,
7337 gboolean overwrite)
7338{
7339 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
7340 overwrite = overwrite != FALSE(0);
7341
7342 if (text_view->priv->overwrite_mode != overwrite)
7343 ctk_text_view_toggle_overwrite (text_view);
7344}
7345
7346/**
7347 * ctk_text_view_set_accepts_tab:
7348 * @text_view: A #CtkTextView
7349 * @accepts_tab: %TRUE if pressing the Tab key should insert a tab
7350 * character, %FALSE, if pressing the Tab key should move the
7351 * keyboard focus.
7352 *
7353 * Sets the behavior of the text widget when the Tab key is pressed.
7354 * If @accepts_tab is %TRUE, a tab character is inserted. If @accepts_tab
7355 * is %FALSE the keyboard focus is moved to the next widget in the focus
7356 * chain.
7357 *
7358 * Since: 2.4
7359 **/
7360void
7361ctk_text_view_set_accepts_tab (CtkTextView *text_view,
7362 gboolean accepts_tab)
7363{
7364 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
7365
7366 accepts_tab = accepts_tab != FALSE(0);
7367
7368 if (text_view->priv->accepts_tab != accepts_tab)
7369 {
7370 text_view->priv->accepts_tab = accepts_tab;
7371
7372 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "accepts-tab");
7373 }
7374}
7375
7376/**
7377 * ctk_text_view_get_accepts_tab:
7378 * @text_view: A #CtkTextView
7379 *
7380 * Returns whether pressing the Tab key inserts a tab characters.
7381 * ctk_text_view_set_accepts_tab().
7382 *
7383 * Returns: %TRUE if pressing the Tab key inserts a tab character,
7384 * %FALSE if pressing the Tab key moves the keyboard focus.
7385 *
7386 * Since: 2.4
7387 **/
7388gboolean
7389ctk_text_view_get_accepts_tab (CtkTextView *text_view)
7390{
7391 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
7392
7393 return text_view->priv->accepts_tab;
7394}
7395
7396/*
7397 * Selections
7398 */
7399
7400static void
7401ctk_text_view_unselect (CtkTextView *text_view)
7402{
7403 CtkTextIter insert;
7404
7405 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
7406 ctk_text_buffer_get_insert (get_buffer (text_view)));
7407
7408 ctk_text_buffer_move_mark (get_buffer (text_view),
7409 ctk_text_buffer_get_selection_bound (get_buffer (text_view)),
7410 &insert);
7411}
7412
7413static void
7414move_mark_to_pointer_and_scroll (CtkTextView *text_view,
7415 const gchar *mark_name)
7416{
7417 CtkTextIter newplace;
7418 CtkTextBuffer *buffer;
7419 CtkTextMark *mark;
7420
7421 buffer = get_buffer (text_view);
7422 get_iter_from_gesture (text_view, text_view->priv->drag_gesture,
7423 &newplace, NULL((void*)0), NULL((void*)0));
7424
7425 mark = ctk_text_buffer_get_mark (buffer, mark_name);
7426
7427 /* This may invalidate the layout */
7428 DV(g_print (G_STRLOC": move mark\n"));
7429
7430 ctk_text_buffer_move_mark (buffer, mark, &newplace);
7431
7432 DV(g_print (G_STRLOC": scrolling onscreen\n"));
7433 ctk_text_view_scroll_mark_onscreen (text_view, mark);
7434
7435 DV (g_print ("first validate idle leaving %s is %d\n",
7436 G_STRLOC, text_view->priv->first_validate_idle));
7437}
7438
7439static gboolean
7440selection_scan_timeout (gpointer data)
7441{
7442 CtkTextView *text_view;
7443
7444 text_view = CTK_TEXT_VIEW (data)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ctk_text_view_get_type ()))))))
;
7445
7446 ctk_text_view_scroll_mark_onscreen (text_view,
7447 ctk_text_buffer_get_insert (get_buffer (text_view)));
7448
7449 return TRUE(!(0)); /* remain installed. */
7450}
7451
7452#define UPPER_OFFSET_ANCHOR0.8 0.8
7453#define LOWER_OFFSET_ANCHOR0.2 0.2
7454
7455static gboolean
7456check_scroll (gdouble offset, CtkAdjustment *adjustment)
7457{
7458 if ((offset > UPPER_OFFSET_ANCHOR0.8 &&
7459 ctk_adjustment_get_value (adjustment) + ctk_adjustment_get_page_size (adjustment) < ctk_adjustment_get_upper (adjustment)) ||
7460 (offset < LOWER_OFFSET_ANCHOR0.2 &&
7461 ctk_adjustment_get_value (adjustment) > ctk_adjustment_get_lower (adjustment)))
7462 return TRUE(!(0));
7463
7464 return FALSE(0);
7465}
7466
7467static gint
7468drag_scan_timeout (gpointer data)
7469{
7470 CtkTextView *text_view;
7471 CtkTextViewPrivate *priv;
7472 CtkTextIter newplace;
7473 gdouble pointer_xoffset, pointer_yoffset;
7474
7475 text_view = CTK_TEXT_VIEW (data)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ctk_text_view_get_type ()))))))
;
7476 priv = text_view->priv;
7477
7478 ctk_text_layout_get_iter_at_pixel (priv->layout,
7479 &newplace,
7480 priv->dnd_x + priv->xoffset,
7481 priv->dnd_y + priv->yoffset);
7482
7483 ctk_text_buffer_move_mark (get_buffer (text_view),
7484 priv->dnd_mark,
7485 &newplace);
7486
7487 pointer_xoffset = (gdouble) priv->dnd_x / cdk_window_get_width (priv->text_window->bin_window);
7488 pointer_yoffset = (gdouble) priv->dnd_y / cdk_window_get_height (priv->text_window->bin_window);
7489
7490 if (check_scroll (pointer_xoffset, priv->hadjustment) ||
7491 check_scroll (pointer_yoffset, priv->vadjustment))
7492 {
7493 /* do not make offsets surpass lower nor upper anchors, this makes
7494 * scrolling speed relative to the distance of the pointer to the
7495 * anchors when it moves beyond them.
7496 */
7497 pointer_xoffset = CLAMP (pointer_xoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR)(((pointer_xoffset) > (0.8)) ? (0.8) : (((pointer_xoffset)
< (0.2)) ? (0.2) : (pointer_xoffset)))
;
7498 pointer_yoffset = CLAMP (pointer_yoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR)(((pointer_yoffset) > (0.8)) ? (0.8) : (((pointer_yoffset)
< (0.2)) ? (0.2) : (pointer_yoffset)))
;
7499
7500 ctk_text_view_scroll_to_mark (text_view,
7501 priv->dnd_mark,
7502 0., TRUE(!(0)), pointer_xoffset, pointer_yoffset);
7503 }
7504
7505 return TRUE(!(0));
7506}
7507
7508static void
7509extend_selection (CtkTextView *text_view,
7510 SelectionGranularity granularity,
7511 const CtkTextIter *location,
7512 CtkTextIter *start,
7513 CtkTextIter *end)
7514{
7515 CtkTextExtendSelection extend_selection_granularity;
7516 gboolean handled = FALSE(0);
7517
7518 switch (granularity)
7519 {
7520 case SELECT_CHARACTERS:
7521 *start = *location;
7522 *end = *location;
7523 return;
7524
7525 case SELECT_WORDS:
7526 extend_selection_granularity = CTK_TEXT_EXTEND_SELECTION_WORD;
7527 break;
7528
7529 case SELECT_LINES:
7530 extend_selection_granularity = CTK_TEXT_EXTEND_SELECTION_LINE;
7531 break;
7532
7533 default:
7534 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctktextview.c", 7534, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7535 }
7536
7537 g_signal_emit (text_view,
7538 signals[EXTEND_SELECTION], 0,
7539 extend_selection_granularity,
7540 location,
7541 start,
7542 end,
7543 &handled);
7544
7545 if (!handled)
7546 {
7547 *start = *location;
7548 *end = *location;
7549 }
7550}
7551
7552static gboolean
7553ctk_text_view_extend_selection (CtkTextView *text_view,
7554 CtkTextExtendSelection granularity,
7555 const CtkTextIter *location,
7556 CtkTextIter *start,
7557 CtkTextIter *end)
7558{
7559 *start = *location;
7560 *end = *location;
7561
7562 switch (granularity)
7563 {
7564 case CTK_TEXT_EXTEND_SELECTION_WORD:
7565 if (ctk_text_iter_inside_word (start))
7566 {
7567 if (!ctk_text_iter_starts_word (start))
7568 ctk_text_iter_backward_visible_word_start (start);
7569
7570 if (!ctk_text_iter_ends_word (end))
7571 {
7572 if (!ctk_text_iter_forward_visible_word_end (end))
7573 ctk_text_iter_forward_to_end (end);
7574 }
7575 }
7576 else
7577 {
7578 CtkTextIter tmp;
7579
7580 /* @start is not contained in a word: the selection is extended to all
7581 * the white spaces between the end of the word preceding @start and
7582 * the start of the one following.
7583 */
7584
7585 tmp = *start;
7586 if (ctk_text_iter_backward_visible_word_start (&tmp))
7587 ctk_text_iter_forward_visible_word_end (&tmp);
7588
7589 if (ctk_text_iter_get_line (&tmp) == ctk_text_iter_get_line (start))
7590 *start = tmp;
7591 else
7592 ctk_text_iter_set_line_offset (start, 0);
7593
7594 tmp = *end;
7595 if (!ctk_text_iter_forward_visible_word_end (&tmp))
7596 ctk_text_iter_forward_to_end (&tmp);
7597
7598 if (ctk_text_iter_ends_word (&tmp))
7599 ctk_text_iter_backward_visible_word_start (&tmp);
7600
7601 if (ctk_text_iter_get_line (&tmp) == ctk_text_iter_get_line (end))
7602 *end = tmp;
7603 else
7604 ctk_text_iter_forward_to_line_end (end);
7605 }
7606 break;
7607
7608 case CTK_TEXT_EXTEND_SELECTION_LINE:
7609 if (ctk_text_view_starts_display_line (text_view, start))
7610 {
7611 /* If on a display line boundary, we assume the user
7612 * clicked off the end of a line and we therefore select
7613 * the line before the boundary.
7614 */
7615 ctk_text_view_backward_display_line_start (text_view, start);
7616 }
7617 else
7618 {
7619 /* start isn't on the start of a line, so we move it to the
7620 * start, and move end to the end unless it's already there.
7621 */
7622 ctk_text_view_backward_display_line_start (text_view, start);
7623
7624 if (!ctk_text_view_starts_display_line (text_view, end))
7625 ctk_text_view_forward_display_line_end (text_view, end);
7626 }
7627 break;
7628
7629 default:
7630 g_return_val_if_reached (CDK_EVENT_STOP)do { g_log ("Ctk", G_LOG_LEVEL_CRITICAL, "file %s: line %d (%s): should not be reached"
, "ctktextview.c", 7630, ((const char*) (__func__))); return (
((!(0)))); } while (0)
;
7631 }
7632
7633 return CDK_EVENT_STOP((!(0)));
7634}
7635
7636typedef struct
7637{
7638 SelectionGranularity granularity;
7639 CtkTextMark *orig_start;
7640 CtkTextMark *orig_end;
7641 CtkTextBuffer *buffer;
7642} SelectionData;
7643
7644static void
7645selection_data_free (SelectionData *data)
7646{
7647 if (data->orig_start != NULL((void*)0))
7648 ctk_text_buffer_delete_mark (data->buffer, data->orig_start);
7649
7650 if (data->orig_end != NULL((void*)0))
7651 ctk_text_buffer_delete_mark (data->buffer, data->orig_end);
7652
7653 g_object_unref (data->buffer);
7654
7655 g_slice_free (SelectionData, data)do { if (1) g_slice_free1 (sizeof (SelectionData), (data)); else
(void) ((SelectionData*) 0 == (data)); } while (0)
;
7656}
7657
7658static gboolean
7659drag_gesture_get_text_window_coords (CtkGestureDrag *gesture,
7660 CtkTextView *text_view,
7661 gint *start_x,
7662 gint *start_y,
7663 gint *x,
7664 gint *y)
7665{
7666 gdouble sx, sy, ox, oy;
7667
7668 if (!ctk_gesture_drag_get_start_point (gesture, &sx, &sy) ||
3
Assuming the condition is true
7669 !ctk_gesture_drag_get_offset (gesture, &ox, &oy))
7670 return FALSE(0);
4
Returning without writing to '*start_x'
7671
7672 *start_x = sx;
7673 *start_y = sy;
7674 _widget_to_text_window_coords (text_view, start_x, start_y);
7675
7676 *x = sx + ox;
7677 *y = sy + oy;
7678 _widget_to_text_window_coords (text_view, x, y);
7679
7680 return TRUE(!(0));
7681}
7682
7683static void
7684ctk_text_view_drag_gesture_update (CtkGestureDrag *gesture,
7685 gdouble offset_x G_GNUC_UNUSED__attribute__ ((__unused__)),
7686 gdouble offset_y G_GNUC_UNUSED__attribute__ ((__unused__)),
7687 CtkTextView *text_view)
7688{
7689 gint start_x, start_y, x, y;
7690 CdkEventSequence *sequence;
7691 gboolean is_touchscreen;
7692 const CdkEvent *event;
7693 SelectionData *data;
7694 CdkDevice *device;
7695 CtkTextIter cursor;
7696
7697 data = g_object_get_qdata (G_OBJECT (gesture)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), (((GType) ((20) << (2))))))))
, quark_text_selection_data);
7698 sequence = ctk_gesture_single_get_current_sequence (CTK_GESTURE_SINGLE (gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gesture)), ((ctk_gesture_single_get_type ()
))))))
);
7699 event = ctk_gesture_get_last_event (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, sequence);
7700 drag_gesture_get_text_window_coords (gesture, text_view,
7701 &start_x, &start_y, &x, &y);
7702
7703 device = cdk_event_get_source_device (event);
7704
7705 is_touchscreen = ctk_simulate_touchscreen () ||
7706 cdk_device_get_source (device) == CDK_SOURCE_TOUCHSCREEN;
7707
7708 get_iter_from_gesture (text_view, text_view->priv->drag_gesture,
7709 &cursor, NULL((void*)0), NULL((void*)0));
7710
7711 if (!data)
7712 {
7713 /* If no data is attached, the initial press happened within the current
7714 * text selection, check for drag and drop to be initiated.
7715 */
7716 if (ctk_drag_check_threshold (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
7717 start_x, start_y, x, y))
7718 {
7719 if (!is_touchscreen)
7720 {
7721 CtkTextIter iter;
7722 gint buffer_x, buffer_y;
7723
7724 ctk_text_view_window_to_buffer_coords (text_view,
7725 CTK_TEXT_WINDOW_TEXT,
7726 start_x, start_y,
7727 &buffer_x,
7728 &buffer_y);
7729
7730 ctk_text_layout_get_iter_at_pixel (text_view->priv->layout,
7731 &iter, buffer_x, buffer_y);
7732
7733 ctk_text_view_start_selection_dnd (text_view, &iter, event,
7734 start_x, start_y);
7735 return;
7736 }
7737 else
7738 {
7739 ctk_text_view_start_selection_drag (text_view, &cursor,
7740 SELECT_WORDS, TRUE(!(0)));
7741 data = g_object_get_qdata (G_OBJECT (gesture)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), (((GType) ((20) << (2))))))))
, quark_text_selection_data);
7742 }
7743 }
7744 else
7745 return;
7746 }
7747
7748 /* Text selection */
7749 if (data->granularity == SELECT_CHARACTERS)
7750 {
7751 move_mark_to_pointer_and_scroll (text_view, "insert");
7752 }
7753 else
7754 {
7755 CtkTextIter start, end;
7756 CtkTextIter orig_start, orig_end;
7757 CtkTextBuffer *buffer;
7758
7759 buffer = get_buffer (text_view);
7760
7761 ctk_text_buffer_get_iter_at_mark (buffer, &orig_start, data->orig_start);
7762 ctk_text_buffer_get_iter_at_mark (buffer, &orig_end, data->orig_end);
7763
7764 get_iter_from_gesture (text_view, text_view->priv->drag_gesture,
7765 &cursor, NULL((void*)0), NULL((void*)0));
7766
7767 extend_selection (text_view, data->granularity, &cursor, &start, &end);
7768
7769 /* either the selection extends to the front, or end (or not) */
7770 if (ctk_text_iter_compare (&orig_start, &start) < 0)
7771 start = orig_start;
7772 if (ctk_text_iter_compare (&orig_end, &end) > 0)
7773 end = orig_end;
7774 ctk_text_buffer_select_range (buffer, &start, &end);
7775
7776 ctk_text_view_scroll_mark_onscreen (text_view,
7777 ctk_text_buffer_get_insert (buffer));
7778 }
7779
7780 /* If we had to scroll offscreen, insert a timeout to do so
7781 * again. Note that in the timeout, even if the mouse doesn't
7782 * move, due to this scroll xoffset/yoffset will have changed
7783 * and we'll need to scroll again.
7784 */
7785 if (text_view->priv->scroll_timeout != 0) /* reset on every motion event */
7786 g_source_remove (text_view->priv->scroll_timeout);
7787
7788 text_view->priv->scroll_timeout =
7789 cdk_threads_add_timeout (50, selection_scan_timeout, text_view);
7790 g_source_set_name_by_id (text_view->priv->scroll_timeout, "[ctk+] selection_scan_timeout");
7791
7792 ctk_text_view_selection_bubble_popup_unset (text_view);
7793
7794 if (is_touchscreen)
7795 {
7796 _ctk_text_view_ensure_text_handles (text_view);
7797 ctk_text_view_update_handles (text_view, CTK_TEXT_HANDLE_MODE_SELECTION);
7798 ctk_text_view_show_magnifier (text_view, &cursor, x, y);
7799 }
7800}
7801
7802static void
7803ctk_text_view_drag_gesture_end (CtkGestureDrag *gesture,
7804 gdouble offset_x G_GNUC_UNUSED__attribute__ ((__unused__)),
7805 gdouble offset_y G_GNUC_UNUSED__attribute__ ((__unused__)),
7806 CtkTextView *text_view)
7807{
7808 gboolean is_touchscreen, clicked_in_selection;
7809 gint start_x, start_y, x, y;
1
'start_x' declared without an initial value
7810 CdkEventSequence *sequence;
7811 CtkTextViewPrivate *priv;
7812 const CdkEvent *event;
7813 CdkDevice *device;
7814
7815 priv = text_view->priv;
7816 sequence = ctk_gesture_single_get_current_sequence (CTK_GESTURE_SINGLE (gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gesture)), ((ctk_gesture_single_get_type ()
))))))
);
7817 drag_gesture_get_text_window_coords (gesture, text_view,
2
Calling 'drag_gesture_get_text_window_coords'
5
Returning from 'drag_gesture_get_text_window_coords'
7818 &start_x, &start_y, &x, &y);
7819
7820 clicked_in_selection =
7821 g_object_get_qdata (G_OBJECT (gesture)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), (((GType) ((20) << (2))))))))
, quark_text_selection_data) == NULL((void*)0)
;
6
Assuming the condition is true
7822 g_object_set_qdata (G_OBJECT (gesture)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), (((GType) ((20) << (2))))))))
, quark_text_selection_data, NULL((void*)0));
7823 ctk_text_view_unobscure_mouse_cursor (text_view);
7824
7825 if (priv->scroll_timeout != 0)
7
Assuming field 'scroll_timeout' is equal to 0
8
Taking false branch
7826 {
7827 g_source_remove (priv->scroll_timeout);
7828 priv->scroll_timeout = 0;
7829 }
7830
7831 if (priv->magnifier_popover)
9
Assuming field 'magnifier_popover' is null
10
Taking false branch
7832 ctk_widget_hide (priv->magnifier_popover);
7833
7834 /* Check whether the drag was cancelled rather than finished */
7835 if (!ctk_gesture_handles_sequence (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, sequence)
)
11
Assuming the condition is false
12
Taking false branch
7836 return;
7837
7838 event = ctk_gesture_get_last_event (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, sequence);
7839 device = cdk_event_get_source_device (event);
7840 is_touchscreen = ctk_simulate_touchscreen () ||
13
Assuming the condition is false
7841 cdk_device_get_source (device) == CDK_SOURCE_TOUCHSCREEN;
14
Assuming the condition is false
7842
7843 if (!is_touchscreen
14.1
'is_touchscreen' is 0
&& clicked_in_selection
14.2
'clicked_in_selection' is 1
&&
7844 !ctk_drag_check_threshold (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
, start_x, start_y, x, y))
15
2nd function call argument is an uninitialized value
7845 {
7846 CtkTextHandleMode mode = CTK_TEXT_HANDLE_MODE_NONE;
7847 CtkTextIter iter;
7848
7849 /* Unselect everything; we clicked inside selection, but
7850 * didn't move by the drag threshold, so just clear selection
7851 * and place cursor.
7852 */
7853 ctk_text_layout_get_iter_at_pixel (priv->layout, &iter,
7854 x + priv->xoffset, y + priv->yoffset);
7855
7856 ctk_text_buffer_place_cursor (get_buffer (text_view), &iter);
7857 ctk_text_view_check_cursor_blink (text_view);
7858
7859 if (priv->text_handle)
7860 {
7861 if (is_touchscreen)
7862 mode = CTK_TEXT_HANDLE_MODE_CURSOR;
7863
7864 ctk_text_view_update_handles (text_view, mode);
7865 }
7866 }
7867}
7868
7869static void
7870ctk_text_view_start_selection_drag (CtkTextView *text_view,
7871 const CtkTextIter *iter,
7872 SelectionGranularity granularity,
7873 gboolean extend)
7874{
7875 CtkTextViewPrivate *priv;
7876 CtkTextIter cursor, ins, bound;
7877 CtkTextIter orig_start, orig_end;
7878 CtkTextBuffer *buffer;
7879 SelectionData *data;
7880
7881 priv = text_view->priv;
7882 data = g_slice_new0 (SelectionData)((SelectionData*) g_slice_alloc0 (sizeof (SelectionData)));
7883 data->granularity = granularity;
7884
7885 buffer = get_buffer (text_view);
7886
7887 cursor = *iter;
7888 extend_selection (text_view, data->granularity, &cursor, &ins, &bound);
7889
7890 orig_start = ins;
7891 orig_end = bound;
7892
7893 if (extend)
7894 {
7895 /* Extend selection */
7896 CtkTextIter old_ins, old_bound;
7897 CtkTextIter old_start, old_end;
7898
7899 ctk_text_buffer_get_iter_at_mark (buffer, &old_ins, ctk_text_buffer_get_insert (buffer));
7900 ctk_text_buffer_get_iter_at_mark (buffer, &old_bound, ctk_text_buffer_get_selection_bound (buffer));
7901 old_start = old_ins;
7902 old_end = old_bound;
7903 ctk_text_iter_order (&old_start, &old_end);
7904
7905 /* move the front cursor, if the mouse is in front of the selection. Should the
7906 * cursor however be inside the selection (this happens on tripple click) then we
7907 * move the side which was last moved (current insert mark) */
7908 if (ctk_text_iter_compare (&cursor, &old_start) <= 0 ||
7909 (ctk_text_iter_compare (&cursor, &old_end) < 0 &&
7910 ctk_text_iter_compare (&old_ins, &old_bound) <= 0))
7911 {
7912 bound = old_end;
7913 }
7914 else
7915 {
7916 ins = bound;
7917 bound = old_start;
7918 }
7919
7920 /* Store any previous selection */
7921 if (ctk_text_iter_compare (&old_start, &old_end) != 0)
7922 {
7923 orig_start = old_ins;
7924 orig_end = old_bound;
7925 }
7926 }
7927
7928 ctk_text_buffer_select_range (buffer, &ins, &bound);
7929
7930 ctk_text_iter_order (&orig_start, &orig_end);
7931 data->orig_start = ctk_text_buffer_create_mark (buffer, NULL((void*)0),
7932 &orig_start, TRUE(!(0)));
7933 data->orig_end = ctk_text_buffer_create_mark (buffer, NULL((void*)0),
7934 &orig_end, TRUE(!(0)));
7935 data->buffer = g_object_ref (buffer)((__typeof__ (buffer)) (g_object_ref) (buffer));
7936 ctk_text_view_check_cursor_blink (text_view);
7937
7938 g_object_set_qdata_full (G_OBJECT (priv->drag_gesture)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->drag_gesture)), (((GType) ((20) << (2))))
))))
,
7939 quark_text_selection_data,
7940 data, (GDestroyNotify) selection_data_free);
7941 ctk_gesture_set_state (priv->drag_gesture,
7942 CTK_EVENT_SEQUENCE_CLAIMED);
7943}
7944
7945/* returns whether we were really dragging */
7946static gboolean
7947ctk_text_view_end_selection_drag (CtkTextView *text_view)
7948{
7949 CtkTextViewPrivate *priv;
7950
7951 priv = text_view->priv;
7952
7953 if (!ctk_gesture_is_active (priv->drag_gesture))
7954 return FALSE(0);
7955
7956 if (priv->scroll_timeout != 0)
7957 {
7958 g_source_remove (priv->scroll_timeout);
7959 priv->scroll_timeout = 0;
7960 }
7961
7962 if (priv->magnifier_popover)
7963 ctk_widget_hide (priv->magnifier_popover);
7964
7965 return TRUE(!(0));
7966}
7967
7968/*
7969 * Layout utils
7970 */
7971
7972static void
7973ctk_text_view_set_attributes_from_style (CtkTextView *text_view,
7974 CtkTextAttributes *values)
7975{
7976 CtkStyleContext *context;
7977 CdkRGBA bg_color, fg_color;
7978 CtkStateFlags state;
7979
7980 context = ctk_widget_get_style_context (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
7981 state = ctk_style_context_get_state (context);
7982
7983 ctk_style_context_get_background_color (context, state, &bg_color);
7984 ctk_style_context_get_color (context, state, &fg_color);
7985
7986 values->appearance.bg_color.red = CLAMP (bg_color.red * 65535. + 0.5, 0, 65535)(((bg_color.red * 65535. + 0.5) > (65535)) ? (65535) : (((
bg_color.red * 65535. + 0.5) < (0)) ? (0) : (bg_color.red *
65535. + 0.5)))
;
7987 values->appearance.bg_color.green = CLAMP (bg_color.green * 65535. + 0.5, 0, 65535)(((bg_color.green * 65535. + 0.5) > (65535)) ? (65535) : (
((bg_color.green * 65535. + 0.5) < (0)) ? (0) : (bg_color.
green * 65535. + 0.5)))
;
7988 values->appearance.bg_color.blue = CLAMP (bg_color.blue * 65535. + 0.5, 0, 65535)(((bg_color.blue * 65535. + 0.5) > (65535)) ? (65535) : ((
(bg_color.blue * 65535. + 0.5) < (0)) ? (0) : (bg_color.blue
* 65535. + 0.5)))
;
7989
7990 values->appearance.fg_color.red = CLAMP (fg_color.red * 65535. + 0.5, 0, 65535)(((fg_color.red * 65535. + 0.5) > (65535)) ? (65535) : (((
fg_color.red * 65535. + 0.5) < (0)) ? (0) : (fg_color.red *
65535. + 0.5)))
;
7991 values->appearance.fg_color.green = CLAMP (fg_color.green * 65535. + 0.5, 0, 65535)(((fg_color.green * 65535. + 0.5) > (65535)) ? (65535) : (
((fg_color.green * 65535. + 0.5) < (0)) ? (0) : (fg_color.
green * 65535. + 0.5)))
;
7992 values->appearance.fg_color.blue = CLAMP (fg_color.blue * 65535. + 0.5, 0, 65535)(((fg_color.blue * 65535. + 0.5) > (65535)) ? (65535) : ((
(fg_color.blue * 65535. + 0.5) < (0)) ? (0) : (fg_color.blue
* 65535. + 0.5)))
;
7993
7994 if (values->font)
7995 pango_font_description_free (values->font);
7996
7997 ctk_style_context_get (context, state, "font", &values->font, NULL((void*)0));
7998}
7999
8000static void
8001ctk_text_view_check_keymap_direction (CtkTextView *text_view)
8002{
8003 CtkTextViewPrivate *priv = text_view->priv;
8004
8005 if (priv->layout)
8006 {
8007 CtkSettings *settings = ctk_widget_get_settings (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
8008 CdkKeymap *keymap = cdk_keymap_get_for_display (ctk_widget_get_display (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
));
8009 CtkTextDirection new_cursor_dir;
8010 CtkTextDirection new_keyboard_dir;
8011 gboolean split_cursor;
8012
8013 g_object_get (settings,
8014 "ctk-split-cursor", &split_cursor,
8015 NULL((void*)0));
8016
8017 if (cdk_keymap_get_direction (keymap) == PANGO_DIRECTION_RTL)
8018 new_keyboard_dir = CTK_TEXT_DIR_RTL;
8019 else
8020 new_keyboard_dir = CTK_TEXT_DIR_LTR;
8021
8022 if (split_cursor)
8023 new_cursor_dir = CTK_TEXT_DIR_NONE;
8024 else
8025 new_cursor_dir = new_keyboard_dir;
8026
8027 ctk_text_layout_set_cursor_direction (priv->layout, new_cursor_dir);
8028 ctk_text_layout_set_keyboard_direction (priv->layout, new_keyboard_dir);
8029 }
8030}
8031
8032static void
8033ctk_text_view_ensure_layout (CtkTextView *text_view)
8034{
8035 CtkWidget *widget;
8036 CtkTextViewPrivate *priv;
8037
8038 widget = CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
;
8039 priv = text_view->priv;
8040
8041 if (priv->layout == NULL((void*)0))
8042 {
8043 CtkTextAttributes *style;
8044 PangoContext *ltr_context, *rtl_context;
8045 GSList *tmp_list;
8046
8047 DV(g_print(G_STRLOC"\n"));
8048
8049 priv->layout = ctk_text_layout_new ();
8050
8051 g_signal_connect (priv->layout,g_signal_connect_data ((priv->layout), ("invalidated"), ((
(GCallback) (invalidated_handler))), (text_view), ((void*)0),
(GConnectFlags) 0)
8052 "invalidated",g_signal_connect_data ((priv->layout), ("invalidated"), ((
(GCallback) (invalidated_handler))), (text_view), ((void*)0),
(GConnectFlags) 0)
8053 G_CALLBACK (invalidated_handler),g_signal_connect_data ((priv->layout), ("invalidated"), ((
(GCallback) (invalidated_handler))), (text_view), ((void*)0),
(GConnectFlags) 0)
8054 text_view)g_signal_connect_data ((priv->layout), ("invalidated"), ((
(GCallback) (invalidated_handler))), (text_view), ((void*)0),
(GConnectFlags) 0)
;
8055
8056 g_signal_connect (priv->layout,g_signal_connect_data ((priv->layout), ("changed"), (((GCallback
) (changed_handler))), (text_view), ((void*)0), (GConnectFlags
) 0)
8057 "changed",g_signal_connect_data ((priv->layout), ("changed"), (((GCallback
) (changed_handler))), (text_view), ((void*)0), (GConnectFlags
) 0)
8058 G_CALLBACK (changed_handler),g_signal_connect_data ((priv->layout), ("changed"), (((GCallback
) (changed_handler))), (text_view), ((void*)0), (GConnectFlags
) 0)
8059 text_view)g_signal_connect_data ((priv->layout), ("changed"), (((GCallback
) (changed_handler))), (text_view), ((void*)0), (GConnectFlags
) 0)
;
8060
8061 g_signal_connect (priv->layout,g_signal_connect_data ((priv->layout), ("allocate-child"),
(((GCallback) (ctk_text_view_child_allocated))), (text_view)
, ((void*)0), (GConnectFlags) 0)
8062 "allocate-child",g_signal_connect_data ((priv->layout), ("allocate-child"),
(((GCallback) (ctk_text_view_child_allocated))), (text_view)
, ((void*)0), (GConnectFlags) 0)
8063 G_CALLBACK (ctk_text_view_child_allocated),g_signal_connect_data ((priv->layout), ("allocate-child"),
(((GCallback) (ctk_text_view_child_allocated))), (text_view)
, ((void*)0), (GConnectFlags) 0)
8064 text_view)g_signal_connect_data ((priv->layout), ("allocate-child"),
(((GCallback) (ctk_text_view_child_allocated))), (text_view)
, ((void*)0), (GConnectFlags) 0)
;
8065
8066 if (get_buffer (text_view))
8067 ctk_text_layout_set_buffer (priv->layout, get_buffer (text_view));
8068
8069 if ((ctk_widget_has_focus (widget) && cursor_visible (text_view)))
8070 ctk_text_view_pend_cursor_blink (text_view);
8071 else
8072 ctk_text_layout_set_cursor_visible (priv->layout, FALSE(0));
8073
8074 ctk_text_layout_set_overwrite_mode (priv->layout,
8075 priv->overwrite_mode && priv->editable);
8076
8077 ltr_context = ctk_widget_create_pango_context (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
8078 pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
8079 rtl_context = ctk_widget_create_pango_context (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
8080 pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
8081
8082 ctk_text_layout_set_contexts (priv->layout, ltr_context, rtl_context);
8083
8084 g_object_unref (ltr_context);
8085 g_object_unref (rtl_context);
8086
8087 ctk_text_view_check_keymap_direction (text_view);
8088
8089 style = ctk_text_attributes_new ();
8090
8091 ctk_text_view_set_attributes_from_style (text_view, style);
8092
8093 style->pixels_above_lines = priv->pixels_above_lines;
8094 style->pixels_below_lines = priv->pixels_below_lines;
8095 style->pixels_inside_wrap = priv->pixels_inside_wrap;
8096
8097 style->left_margin = priv->left_margin;
8098 style->right_margin = priv->right_margin;
8099 priv->layout->right_padding = priv->right_padding;
8100 priv->layout->left_padding = priv->left_padding;
8101
8102 style->indent = priv->indent;
8103 style->tabs = priv->tabs ? pango_tab_array_copy (priv->tabs) : NULL((void*)0);
8104
8105 style->wrap_mode = priv->wrap_mode;
8106 style->justification = priv->justify;
8107 style->direction = ctk_widget_get_direction (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
8108
8109 ctk_text_layout_set_default_style (priv->layout, style);
8110
8111 ctk_text_attributes_unref (style);
8112
8113 /* Set layout for all anchored children */
8114
8115 tmp_list = priv->children;
8116 while (tmp_list != NULL((void*)0))
8117 {
8118 CtkTextViewChild *vc = tmp_list->data;
8119
8120 if (vc->anchor)
8121 {
8122 ctk_text_anchored_child_set_layout (vc->widget,
8123 priv->layout);
8124 /* vc may now be invalid! */
8125 }
8126
8127 tmp_list = tmp_list->next;
8128 }
8129 }
8130}
8131
8132/**
8133 * ctk_text_view_get_default_attributes:
8134 * @text_view: a #CtkTextView
8135 *
8136 * Obtains a copy of the default text attributes. These are the
8137 * attributes used for text unless a tag overrides them.
8138 * You’d typically pass the default attributes in to
8139 * ctk_text_iter_get_attributes() in order to get the
8140 * attributes in effect at a given text position.
8141 *
8142 * The return value is a copy owned by the caller of this function,
8143 * and should be freed with ctk_text_attributes_unref().
8144 *
8145 * Returns: a new #CtkTextAttributes
8146 **/
8147CtkTextAttributes*
8148ctk_text_view_get_default_attributes (CtkTextView *text_view)
8149{
8150 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (((void*)0)); } }
while (0)
;
8151
8152 ctk_text_view_ensure_layout (text_view);
8153
8154 return ctk_text_attributes_copy (text_view->priv->layout->default_style);
8155}
8156
8157static void
8158ctk_text_view_destroy_layout (CtkTextView *text_view)
8159{
8160 CtkTextViewPrivate *priv = text_view->priv;
8161
8162 if (priv->layout)
8163 {
8164 GSList *tmp_list;
8165
8166 ctk_text_view_remove_validate_idles (text_view);
8167
8168 g_signal_handlers_disconnect_by_func (priv->layout,g_signal_handlers_disconnect_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (invalidated_handler), (text_view))
8169 invalidated_handler,g_signal_handlers_disconnect_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (invalidated_handler), (text_view))
8170 text_view)g_signal_handlers_disconnect_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (invalidated_handler), (text_view))
;
8171 g_signal_handlers_disconnect_by_func (priv->layout,g_signal_handlers_disconnect_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (changed_handler), (text_view))
8172 changed_handler,g_signal_handlers_disconnect_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (changed_handler), (text_view))
8173 text_view)g_signal_handlers_disconnect_matched ((priv->layout), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (changed_handler), (text_view))
;
8174
8175 /* Remove layout from all anchored children */
8176 tmp_list = priv->children;
8177 while (tmp_list != NULL((void*)0))
8178 {
8179 CtkTextViewChild *vc = tmp_list->data;
8180
8181 if (vc->anchor)
8182 {
8183 ctk_text_anchored_child_set_layout (vc->widget, NULL((void*)0));
8184 /* vc may now be invalid! */
8185 }
8186
8187 tmp_list = tmp_list->next;
8188 }
8189
8190 ctk_text_view_stop_cursor_blink (text_view);
8191 ctk_text_view_end_selection_drag (text_view);
8192
8193 g_object_unref (priv->layout);
8194 priv->layout = NULL((void*)0);
8195 }
8196}
8197
8198/**
8199 * ctk_text_view_reset_im_context:
8200 * @text_view: a #CtkTextView
8201 *
8202 * Reset the input method context of the text view if needed.
8203 *
8204 * This can be necessary in the case where modifying the buffer
8205 * would confuse on-going input method behavior.
8206 *
8207 * Since: 2.22
8208 */
8209void
8210ctk_text_view_reset_im_context (CtkTextView *text_view)
8211{
8212 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
8213
8214 if (text_view->priv->need_im_reset)
8215 {
8216 text_view->priv->need_im_reset = FALSE(0);
8217 ctk_im_context_reset (text_view->priv->im_context);
8218 }
8219}
8220
8221/**
8222 * ctk_text_view_im_context_filter_keypress:
8223 * @text_view: a #CtkTextView
8224 * @event: the key event
8225 *
8226 * Allow the #CtkTextView input method to internally handle key press
8227 * and release events. If this function returns %TRUE, then no further
8228 * processing should be done for this key event. See
8229 * ctk_im_context_filter_keypress().
8230 *
8231 * Note that you are expected to call this function from your handler
8232 * when overriding key event handling. This is needed in the case when
8233 * you need to insert your own key handling between the input method
8234 * and the default key event handling of the #CtkTextView.
8235 *
8236 * |[<!-- language="C" -->
8237 * static gboolean
8238 * ctk_foo_bar_key_press_event (CtkWidget *widget,
8239 * CdkEventKey *event)
8240 * {
8241 * guint keyval;
8242 *
8243 * cdk_event_get_keyval ((CdkEvent*)event, &keyval);
8244 *
8245 * if (keyval == CDK_KEY_Return || keyval == CDK_KEY_KP_Enter)
8246 * {
8247 * if (ctk_text_view_im_context_filter_keypress (CTK_TEXT_VIEW (widget), event))
8248 * return TRUE;
8249 * }
8250 *
8251 * // Do some stuff
8252 *
8253 * return CTK_WIDGET_CLASS (ctk_foo_bar_parent_class)->key_press_event (widget, event);
8254 * }
8255 * ]|
8256 *
8257 * Returns: %TRUE if the input method handled the key event.
8258 *
8259 * Since: 2.22
8260 */
8261gboolean
8262ctk_text_view_im_context_filter_keypress (CtkTextView *text_view,
8263 CdkEventKey *event)
8264{
8265 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
8266
8267 return ctk_im_context_filter_keypress (text_view->priv->im_context, event);
8268}
8269
8270/*
8271 * DND feature
8272 */
8273
8274static void
8275drag_begin_cb (CtkWidget *widget,
8276 CdkDragContext *context,
8277 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
8278{
8279 CtkTextView *text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
8280 CtkTextBuffer *buffer = ctk_text_view_get_buffer (text_view);
8281 CtkTextIter start;
8282 CtkTextIter end;
8283 cairo_surface_t *surface = NULL((void*)0);
8284
8285 g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL)g_signal_handlers_disconnect_matched ((widget), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (drag_begin_cb), (((void*)0)))
;
8286
8287 if (ctk_text_buffer_get_selection_bounds (buffer, &start, &end))
8288 surface = _ctk_text_util_create_rich_drag_icon (widget, buffer, &start, &end);
8289
8290 if (surface)
8291 {
8292 ctk_drag_set_icon_surface (context, surface);
8293 cairo_surface_destroy (surface);
8294 }
8295 else
8296 {
8297 ctk_drag_set_icon_default (context);
8298 }
8299}
8300
8301static void
8302ctk_text_view_start_selection_dnd (CtkTextView *text_view,
8303 const CtkTextIter *iter G_GNUC_UNUSED__attribute__ ((__unused__)),
8304 const CdkEvent *event,
8305 gint x,
8306 gint y)
8307{
8308 CtkTargetList *target_list;
8309
8310 target_list = ctk_text_buffer_get_copy_target_list (get_buffer (text_view));
8311
8312 g_signal_connect (text_view, "drag-begin",g_signal_connect_data ((text_view), ("drag-begin"), (((GCallback
) (drag_begin_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
8313 G_CALLBACK (drag_begin_cb), NULL)g_signal_connect_data ((text_view), ("drag-begin"), (((GCallback
) (drag_begin_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
8314 ctk_drag_begin_with_coordinates (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
, target_list,
8315 CDK_ACTION_COPY | CDK_ACTION_MOVE,
8316 1, (CdkEvent*) event, x, y);
8317}
8318
8319static void
8320ctk_text_view_drag_begin (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
8321 CdkDragContext *context G_GNUC_UNUSED__attribute__ ((__unused__)))
8322{
8323 /* do nothing */
8324}
8325
8326static void
8327ctk_text_view_drag_end (CtkWidget *widget,
8328 CdkDragContext *context G_GNUC_UNUSED__attribute__ ((__unused__)))
8329{
8330 CtkTextView *text_view;
8331
8332 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
8333 text_view->priv->dnd_x = text_view->priv->dnd_y = -1;
8334}
8335
8336static void
8337ctk_text_view_drag_data_get (CtkWidget *widget,
8338 CdkDragContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
8339 CtkSelectionData *selection_data,
8340 guint info,
8341 guint time G_GNUC_UNUSED__attribute__ ((__unused__)))
8342{
8343 CtkTextView *text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
8344 CtkTextBuffer *buffer = ctk_text_view_get_buffer (text_view);
8345
8346 if (info == CTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
8347 {
8348 ctk_selection_data_set (selection_data,
8349 cdk_atom_intern_static_string ("CTK_TEXT_BUFFER_CONTENTS"),
8350 8, /* bytes */
8351 (void*)&buffer,
8352 sizeof (buffer));
8353 }
8354 else if (info == CTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
8355 {
8356 CtkTextIter start;
8357 CtkTextIter end;
8358 guint8 *str = NULL((void*)0);
8359 gsize len;
8360
8361 if (ctk_text_buffer_get_selection_bounds (buffer, &start, &end))
8362 {
8363 /* Extract the selected text */
8364 str = ctk_text_buffer_serialize (buffer, buffer,
8365 ctk_selection_data_get_target (selection_data),
8366 &start, &end,
8367 &len);
8368 }
8369
8370 if (str)
8371 {
8372 ctk_selection_data_set (selection_data,
8373 ctk_selection_data_get_target (selection_data),
8374 8, /* bytes */
8375 (guchar *) str, len);
8376 g_free (str);
8377 }
8378 }
8379 else
8380 {
8381 CtkTextIter start;
8382 CtkTextIter end;
8383 gchar *str = NULL((void*)0);
8384
8385 if (ctk_text_buffer_get_selection_bounds (buffer, &start, &end))
8386 {
8387 /* Extract the selected text */
8388 str = ctk_text_iter_get_visible_text (&start, &end);
8389 }
8390
8391 if (str)
8392 {
8393 ctk_selection_data_set_text (selection_data, str, -1);
8394 g_free (str);
8395 }
8396 }
8397}
8398
8399static void
8400ctk_text_view_drag_data_delete (CtkWidget *widget,
8401 CdkDragContext *context G_GNUC_UNUSED__attribute__ ((__unused__)))
8402{
8403 ctk_text_buffer_delete_selection (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->priv->buffer,
8404 TRUE(!(0)), CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->priv->editable);
8405}
8406
8407static void
8408ctk_text_view_drag_leave (CtkWidget *widget,
8409 CdkDragContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
8410 guint time G_GNUC_UNUSED__attribute__ ((__unused__)))
8411{
8412 CtkTextView *text_view;
8413 CtkTextViewPrivate *priv;
8414
8415 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
8416 priv = text_view->priv;
8417
8418 ctk_text_mark_set_visible (priv->dnd_mark, FALSE(0));
8419
8420 priv->dnd_x = priv->dnd_y = -1;
8421
8422 if (priv->scroll_timeout != 0)
8423 g_source_remove (priv->scroll_timeout);
8424
8425 priv->scroll_timeout = 0;
8426
8427 ctk_drag_unhighlight (widget);
8428}
8429
8430static gboolean
8431ctk_text_view_drag_motion (CtkWidget *widget,
8432 CdkDragContext *context,
8433 gint x,
8434 gint y,
8435 guint time)
8436{
8437 CtkTextIter newplace;
8438 CtkTextView *text_view;
8439 CtkTextViewPrivate *priv;
8440 CtkTextIter start;
8441 CtkTextIter end;
8442 CdkRectangle target_rect;
8443 gint bx, by;
8444 CdkAtom target;
8445 CdkDragAction suggested_action = 0;
8446
8447 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
8448 priv = text_view->priv;
8449
8450 target_rect = priv->text_window->allocation;
8451
8452 if (x < target_rect.x ||
8453 y < target_rect.y ||
8454 x > (target_rect.x + target_rect.width) ||
8455 y > (target_rect.y + target_rect.height))
8456 return FALSE(0); /* outside the text window, allow parent widgets to handle event */
8457
8458 ctk_text_view_window_to_buffer_coords (text_view,
8459 CTK_TEXT_WINDOW_WIDGET,
8460 x, y,
8461 &bx, &by);
8462
8463 ctk_text_layout_get_iter_at_pixel (priv->layout,
8464 &newplace,
8465 bx, by);
8466
8467 target = ctk_drag_dest_find_target (widget, context,
8468 ctk_drag_dest_get_target_list (widget));
8469
8470 if (target == CDK_NONE((CdkAtom)((gpointer) (gulong) (0))))
8471 {
8472 /* can't accept any of the offered targets */
8473 }
8474 else if (ctk_text_buffer_get_selection_bounds (get_buffer (text_view),
8475 &start, &end) &&
8476 ctk_text_iter_compare (&newplace, &start) >= 0 &&
8477 ctk_text_iter_compare (&newplace, &end) <= 0)
8478 {
8479 /* We're inside the selection. */
8480 }
8481 else
8482 {
8483 if (ctk_text_iter_can_insert (&newplace, priv->editable))
8484 {
8485 CtkWidget *source_widget;
8486
8487 suggested_action = cdk_drag_context_get_suggested_action (context);
8488
8489 source_widget = ctk_drag_get_source_widget (context);
8490
8491 if (source_widget == widget)
8492 {
8493 /* Default to MOVE, unless the user has
8494 * pressed ctrl or alt to affect available actions
8495 */
8496 if ((cdk_drag_context_get_actions (context) & CDK_ACTION_MOVE) != 0)
8497 suggested_action = CDK_ACTION_MOVE;
8498 }
8499 }
8500 else
8501 {
8502 /* Can't drop here. */
8503 }
8504 }
8505
8506 if (suggested_action != 0)
8507 {
8508 ctk_text_mark_set_visible (priv->dnd_mark, cursor_visible (text_view));
8509 cdk_drag_status (context, suggested_action, time);
8510 }
8511 else
8512 {
8513 cdk_drag_status (context, 0, time);
8514 ctk_text_mark_set_visible (priv->dnd_mark, FALSE(0));
8515 }
8516
8517 /* DnD uses text window coords, so subtract extra widget
8518 * coords that happen e.g. when displaying line numbers.
8519 */
8520 priv->dnd_x = x - target_rect.x;
8521 priv->dnd_y = y - target_rect.y;
8522
8523 if (!priv->scroll_timeout)
8524 {
8525 priv->scroll_timeout =
8526 cdk_threads_add_timeout (100, drag_scan_timeout, text_view);
8527 g_source_set_name_by_id (text_view->priv->scroll_timeout, "[ctk+] drag_scan_timeout");
8528 }
8529
8530 ctk_drag_highlight (widget);
8531
8532 /* TRUE return means don't propagate the drag motion to parent
8533 * widgets that may also be drop sites.
8534 */
8535 return TRUE(!(0));
8536}
8537
8538static gboolean
8539ctk_text_view_drag_drop (CtkWidget *widget,
8540 CdkDragContext *context,
8541 gint x G_GNUC_UNUSED__attribute__ ((__unused__)),
8542 gint y G_GNUC_UNUSED__attribute__ ((__unused__)),
8543 guint time)
8544{
8545 CtkTextView *text_view;
8546 CtkTextViewPrivate *priv;
8547 CtkTextIter drop_point;
8548 CdkAtom target = CDK_NONE((CdkAtom)((gpointer) (gulong) (0)));
8549
8550 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
8551 priv = text_view->priv;
8552
8553 if (priv->scroll_timeout != 0)
8554 g_source_remove (priv->scroll_timeout);
8555
8556 priv->scroll_timeout = 0;
8557
8558 ctk_text_mark_set_visible (priv->dnd_mark, FALSE(0));
8559
8560 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view),
8561 &drop_point,
8562 priv->dnd_mark);
8563
8564 if (ctk_text_iter_can_insert (&drop_point, priv->editable))
8565 target = ctk_drag_dest_find_target (widget, context, NULL((void*)0));
8566
8567 if (target != CDK_NONE((CdkAtom)((gpointer) (gulong) (0))))
8568 ctk_drag_get_data (widget, context, target, time);
8569 else
8570 ctk_drag_finish (context, FALSE(0), FALSE(0), time);
8571
8572 return TRUE(!(0));
8573}
8574
8575static void
8576insert_text_data (CtkTextView *text_view,
8577 CtkTextIter *drop_point,
8578 CtkSelectionData *selection_data)
8579{
8580 guchar *str;
8581
8582 str = ctk_selection_data_get_text (selection_data);
8583
8584 if (str)
8585 {
8586 if (!ctk_text_buffer_insert_interactive (get_buffer (text_view),
8587 drop_point, (gchar *) str, -1,
8588 text_view->priv->editable))
8589 {
8590 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
8591 }
8592
8593 g_free (str);
8594 }
8595}
8596
8597static void
8598ctk_text_view_drag_data_received (CtkWidget *widget,
8599 CdkDragContext *context,
8600 gint x G_GNUC_UNUSED__attribute__ ((__unused__)),
8601 gint y G_GNUC_UNUSED__attribute__ ((__unused__)),
8602 CtkSelectionData *selection_data,
8603 guint info,
8604 guint time)
8605{
8606 CtkTextIter drop_point;
8607 CtkTextView *text_view;
8608 CtkTextViewPrivate *priv;
8609 gboolean success = FALSE(0);
8610 CtkTextBuffer *buffer = NULL((void*)0);
8611
8612 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
8613 priv = text_view->priv;
8614
8615 if (!priv->dnd_mark)
8616 goto done;
8617
8618 buffer = get_buffer (text_view);
8619
8620 ctk_text_buffer_get_iter_at_mark (buffer,
8621 &drop_point,
8622 priv->dnd_mark);
8623
8624 if (!ctk_text_iter_can_insert (&drop_point, priv->editable))
8625 goto done;
8626
8627 success = TRUE(!(0));
8628
8629 ctk_text_buffer_begin_user_action (buffer);
8630
8631 if (info == CTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
8632 {
8633 CtkTextBuffer *src_buffer = NULL((void*)0);
8634 CtkTextIter start, end;
8635 gboolean copy_tags = TRUE(!(0));
8636
8637 if (ctk_selection_data_get_length (selection_data) != sizeof (src_buffer))
8638 return;
8639
8640 memcpy (&src_buffer, ctk_selection_data_get_data (selection_data), sizeof (src_buffer));
8641
8642 if (src_buffer == NULL((void*)0))
8643 return;
8644
8645 g_return_if_fail (CTK_IS_TEXT_BUFFER (src_buffer))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
; } } while (0)
;
8646
8647 if (ctk_text_buffer_get_tag_table (src_buffer) !=
8648 ctk_text_buffer_get_tag_table (buffer))
8649 {
8650 /* try to find a suitable rich text target instead */
8651 CdkAtom *atoms;
8652 gint n_atoms;
8653 GList *list;
8654 CdkAtom target = CDK_NONE((CdkAtom)((gpointer) (gulong) (0)));
8655
8656 copy_tags = FALSE(0);
8657
8658 atoms = ctk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
8659
8660 for (list = cdk_drag_context_list_targets (context); list; list = list->next)
8661 {
8662 gint i;
8663
8664 for (i = 0; i < n_atoms; i++)
8665 if (GUINT_TO_POINTER (atoms[i])((gpointer) (gulong) (atoms[i])) == list->data)
8666 {
8667 target = atoms[i];
8668 break;
8669 }
8670 }
8671
8672 g_free (atoms);
8673
8674 if (target != CDK_NONE((CdkAtom)((gpointer) (gulong) (0))))
8675 {
8676 ctk_drag_get_data (widget, context, target, time);
8677 ctk_text_buffer_end_user_action (buffer);
8678 return;
8679 }
8680 }
8681
8682 if (ctk_text_buffer_get_selection_bounds (src_buffer,
8683 &start,
8684 &end))
8685 {
8686 if (copy_tags)
8687 ctk_text_buffer_insert_range_interactive (buffer,
8688 &drop_point,
8689 &start,
8690 &end,
8691 priv->editable);
8692 else
8693 {
8694 gchar *str;
8695
8696 str = ctk_text_iter_get_visible_text (&start, &end);
8697 ctk_text_buffer_insert_interactive (buffer,
8698 &drop_point, str, -1,
8699 priv->editable);
8700 g_free (str);
8701 }
8702 }
8703 }
8704 else if (ctk_selection_data_get_length (selection_data) > 0 &&
8705 info == CTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
8706 {
8707 gboolean retval;
8708 GError *error = NULL((void*)0);
8709
8710 retval = ctk_text_buffer_deserialize (buffer, buffer,
8711 ctk_selection_data_get_target (selection_data),
8712 &drop_point,
8713 (guint8 *) ctk_selection_data_get_data (selection_data),
8714 ctk_selection_data_get_length (selection_data),
8715 &error);
8716
8717 if (!retval)
8718 {
8719 g_warning ("error pasting: %s", error->message);
8720 g_clear_error (&error);
8721 }
8722 }
8723 else
8724 insert_text_data (text_view, &drop_point, selection_data);
8725
8726 done:
8727 ctk_drag_finish (context, success,
8728 success && cdk_drag_context_get_selected_action (context) == CDK_ACTION_MOVE,
8729 time);
8730
8731 if (success)
8732 {
8733 ctk_text_buffer_get_iter_at_mark (buffer,
8734 &drop_point,
8735 priv->dnd_mark);
8736 ctk_text_buffer_place_cursor (buffer, &drop_point);
8737
8738 ctk_text_buffer_end_user_action (buffer);
8739 }
8740}
8741
8742/**
8743 * ctk_text_view_get_hadjustment:
8744 * @text_view: a #CtkTextView
8745 *
8746 * Gets the horizontal-scrolling #CtkAdjustment.
8747 *
8748 * Returns: (transfer none): pointer to the horizontal #CtkAdjustment
8749 *
8750 * Since: 2.22
8751 *
8752 * Deprecated: 3.0: Use ctk_scrollable_get_hadjustment()
8753 **/
8754CtkAdjustment*
8755ctk_text_view_get_hadjustment (CtkTextView *text_view)
8756{
8757 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (((void*)0)); } }
while (0)
;
8758
8759 return text_view->priv->hadjustment;
8760}
8761
8762static void
8763ctk_text_view_set_hadjustment (CtkTextView *text_view,
8764 CtkAdjustment *adjustment)
8765{
8766 CtkTextViewPrivate *priv = text_view->priv;
8767
8768 if (adjustment && priv->hadjustment == adjustment)
8769 return;
8770
8771 if (priv->hadjustment != NULL((void*)0))
8772 {
8773 g_signal_handlers_disconnect_by_func (priv->hadjustment,g_signal_handlers_disconnect_matched ((priv->hadjustment),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (ctk_text_view_value_changed), (text_view
))
8774 ctk_text_view_value_changed,g_signal_handlers_disconnect_matched ((priv->hadjustment),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (ctk_text_view_value_changed), (text_view
))
8775 text_view)g_signal_handlers_disconnect_matched ((priv->hadjustment),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (ctk_text_view_value_changed), (text_view
))
;
8776 g_object_unref (priv->hadjustment);
8777 }
8778
8779 if (adjustment == NULL((void*)0))
8780 adjustment = ctk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
8781
8782 g_signal_connect (adjustment, "value-changed",g_signal_connect_data ((adjustment), ("value-changed"), (((GCallback
) (ctk_text_view_value_changed))), (text_view), ((void*)0), (
GConnectFlags) 0)
8783 G_CALLBACK (ctk_text_view_value_changed), text_view)g_signal_connect_data ((adjustment), ("value-changed"), (((GCallback
) (ctk_text_view_value_changed))), (text_view), ((void*)0), (
GConnectFlags) 0)
;
8784 priv->hadjustment = g_object_ref_sink (adjustment)((__typeof__ (adjustment)) (g_object_ref_sink) (adjustment));
8785 ctk_text_view_set_hadjustment_values (text_view);
8786
8787 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "hadjustment");
8788}
8789
8790/**
8791 * ctk_text_view_get_vadjustment:
8792 * @text_view: a #CtkTextView
8793 *
8794 * Gets the vertical-scrolling #CtkAdjustment.
8795 *
8796 * Returns: (transfer none): pointer to the vertical #CtkAdjustment
8797 *
8798 * Since: 2.22
8799 *
8800 * Deprecated: 3.0: Use ctk_scrollable_get_vadjustment()
8801 **/
8802CtkAdjustment*
8803ctk_text_view_get_vadjustment (CtkTextView *text_view)
8804{
8805 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (((void*)0)); } }
while (0)
;
8806
8807 return text_view->priv->vadjustment;
8808}
8809
8810static void
8811ctk_text_view_set_vadjustment (CtkTextView *text_view,
8812 CtkAdjustment *adjustment)
8813{
8814 CtkTextViewPrivate *priv = text_view->priv;
8815
8816 if (adjustment && priv->vadjustment == adjustment)
8817 return;
8818
8819 if (priv->vadjustment != NULL((void*)0))
8820 {
8821 g_signal_handlers_disconnect_by_func (priv->vadjustment,g_signal_handlers_disconnect_matched ((priv->vadjustment),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (ctk_text_view_value_changed), (text_view
))
8822 ctk_text_view_value_changed,g_signal_handlers_disconnect_matched ((priv->vadjustment),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (ctk_text_view_value_changed), (text_view
))
8823 text_view)g_signal_handlers_disconnect_matched ((priv->vadjustment),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (ctk_text_view_value_changed), (text_view
))
;
8824 g_object_unref (priv->vadjustment);
8825 }
8826
8827 if (adjustment == NULL((void*)0))
8828 adjustment = ctk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
8829
8830 g_signal_connect (adjustment, "value-changed",g_signal_connect_data ((adjustment), ("value-changed"), (((GCallback
) (ctk_text_view_value_changed))), (text_view), ((void*)0), (
GConnectFlags) 0)
8831 G_CALLBACK (ctk_text_view_value_changed), text_view)g_signal_connect_data ((adjustment), ("value-changed"), (((GCallback
) (ctk_text_view_value_changed))), (text_view), ((void*)0), (
GConnectFlags) 0)
;
8832 priv->vadjustment = g_object_ref_sink (adjustment)((__typeof__ (adjustment)) (g_object_ref_sink) (adjustment));
8833 ctk_text_view_set_vadjustment_values (text_view);
8834
8835 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "vadjustment");
8836}
8837
8838static void
8839ctk_text_view_set_hadjustment_values (CtkTextView *text_view)
8840{
8841 CtkTextViewPrivate *priv;
8842 gint screen_width;
8843 gdouble old_value;
8844 gdouble new_value;
8845 gdouble new_upper;
8846
8847 priv = text_view->priv;
8848
8849 screen_width = SCREEN_WIDTH (text_view)text_window_get_width (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)
;
8850 old_value = ctk_adjustment_get_value (priv->hadjustment);
8851 new_upper = MAX (screen_width, priv->width)(((screen_width) > (priv->width)) ? (screen_width) : (priv
->width))
;
8852
8853 g_object_set (priv->hadjustment,
8854 "lower", 0.0,
8855 "upper", new_upper,
8856 "page-size", (gdouble)screen_width,
8857 "step-increment", screen_width * 0.1,
8858 "page-increment", screen_width * 0.9,
8859 NULL((void*)0));
8860
8861 new_value = CLAMP (old_value, 0, new_upper - screen_width)(((old_value) > (new_upper - screen_width)) ? (new_upper -
screen_width) : (((old_value) < (0)) ? (0) : (old_value))
)
;
8862 if (new_value != old_value)
8863 ctk_adjustment_set_value (priv->hadjustment, new_value);
8864}
8865
8866static void
8867ctk_text_view_set_vadjustment_values (CtkTextView *text_view)
8868{
8869 CtkTextViewPrivate *priv;
8870 CtkTextIter first_para;
8871 gint screen_height;
8872 gint y;
8873 gdouble old_value;
8874 gdouble new_value;
8875 gdouble new_upper;
8876
8877 priv = text_view->priv;
8878
8879 screen_height = SCREEN_HEIGHT (text_view)text_window_get_height (((((CtkTextView*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), ((ctk_text_view_get_type ()
))))))->priv->text_window)
;
8880 old_value = ctk_adjustment_get_value (priv->vadjustment);
8881 new_upper = MAX (screen_height, priv->height)(((screen_height) > (priv->height)) ? (screen_height) :
(priv->height))
;
8882
8883 g_object_set (priv->vadjustment,
8884 "lower", 0.0,
8885 "upper", new_upper,
8886 "page-size", (gdouble)screen_height,
8887 "step-increment", screen_height * 0.1,
8888 "page-increment", screen_height * 0.9,
8889 NULL((void*)0));
8890
8891 /* Now adjust the value of the adjustment to keep the cursor at the
8892 * same place in the buffer */
8893 ctk_text_view_ensure_layout (text_view);
8894 ctk_text_view_get_first_para_iter (text_view, &first_para);
8895 ctk_text_layout_get_line_yrange (priv->layout, &first_para, &y, NULL((void*)0));
8896
8897 y += priv->first_para_pixels;
8898
8899 new_value = CLAMP (y, 0, new_upper - screen_height)(((y) > (new_upper - screen_height)) ? (new_upper - screen_height
) : (((y) < (0)) ? (0) : (y)))
;
8900 if (new_value != old_value)
8901 ctk_adjustment_set_value (priv->vadjustment, new_value);
8902 }
8903
8904static void
8905adjust_allocation (CtkWidget *widget,
8906 int dx,
8907 int dy)
8908{
8909 CtkAllocation allocation;
8910
8911 if (!ctk_widget_is_drawable (widget))
8912 return;
8913
8914 ctk_widget_get_allocation (widget, &allocation);
8915 allocation.x += dx;
8916 allocation.y += dy;
8917 ctk_widget_size_allocate (widget, &allocation);
8918}
8919
8920static void
8921ctk_text_view_value_changed (CtkAdjustment *adjustment,
8922 CtkTextView *text_view)
8923{
8924 CtkTextViewPrivate *priv;
8925 CtkTextIter iter;
8926 gint line_top;
8927 gint dx = 0;
8928 gint dy = 0;
8929
8930 priv = text_view->priv;
8931
8932 /* Note that we oddly call this function with adjustment == NULL
8933 * sometimes
8934 */
8935
8936 priv->onscreen_validated = FALSE(0);
8937
8938 DV(g_print(">Scroll offset changed %s/%g, onscreen_validated = FALSE ("G_STRLOC")\n",
8939 adjustment == priv->hadjustment ? "hadjustment" : adjustment == priv->vadjustment ? "vadjustment" : "none",
8940 adjustment ? ctk_adjustment_get_value (adjustment) : 0.0));
8941
8942 if (adjustment == priv->hadjustment)
8943 {
8944 dx = priv->xoffset - (gint)ctk_adjustment_get_value (adjustment);
8945 priv->xoffset = (gint)ctk_adjustment_get_value (adjustment) - priv->left_padding;
8946
8947 /* If the change is due to a size change we need
8948 * to invalidate the entire text window because there might be
8949 * right-aligned or centered text
8950 */
8951 if (priv->width_changed)
8952 {
8953 if (ctk_widget_get_realized (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
8954 cdk_window_invalidate_rect (priv->text_window->bin_window, NULL((void*)0), FALSE(0));
8955
8956 priv->width_changed = FALSE(0);
8957 }
8958 }
8959 else if (adjustment == priv->vadjustment)
8960 {
8961 dy = priv->yoffset - (gint)ctk_adjustment_get_value (adjustment) + priv->top_border ;
8962 priv->yoffset -= dy;
8963
8964 if (priv->layout)
8965 {
8966 ctk_text_layout_get_line_at_y (priv->layout, &iter, ctk_adjustment_get_value (adjustment), &line_top);
8967
8968 ctk_text_buffer_move_mark (get_buffer (text_view), priv->first_para_mark, &iter);
8969
8970 priv->first_para_pixels = ctk_adjustment_get_value (adjustment) - line_top;
8971 }
8972 }
8973
8974 if (dx != 0 || dy != 0)
8975 {
8976 GSList *tmp_list;
8977
8978 if (ctk_widget_get_realized (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
8979 {
8980 if (dy != 0)
8981 {
8982 if (priv->left_window)
8983 text_window_scroll (priv->left_window, 0, dy);
8984 if (priv->right_window)
8985 text_window_scroll (priv->right_window, 0, dy);
8986 }
8987
8988 if (dx != 0)
8989 {
8990 if (priv->top_window)
8991 text_window_scroll (priv->top_window, dx, 0);
8992 if (priv->bottom_window)
8993 text_window_scroll (priv->bottom_window, dx, 0);
8994 }
8995
8996 /* It looks nicer to scroll the main area last, because
8997 * it takes a while, and making the side areas update
8998 * afterward emphasizes the slowness of scrolling the
8999 * main area.
9000 */
9001 text_window_scroll (priv->text_window, dx, dy);
9002 }
9003
9004 /* Children are now "moved" in the text window, poke
9005 * into widget->allocation for each child
9006 */
9007 tmp_list = priv->children;
9008 while (tmp_list != NULL((void*)0))
9009 {
9010 CtkTextViewChild *child = tmp_list->data;
9011 gint child_dx = 0, child_dy = 0;
9012
9013 if (child->anchor)
9014 {
9015 child_dx = dx;
9016 child_dy = dy;
9017 }
9018 else
9019 {
9020 if (child->type == CTK_TEXT_WINDOW_TEXT ||
9021 child->type == CTK_TEXT_WINDOW_LEFT ||
9022 child->type == CTK_TEXT_WINDOW_RIGHT)
9023 child_dy = dy;
9024 if (child->type == CTK_TEXT_WINDOW_TEXT ||
9025 child->type == CTK_TEXT_WINDOW_TOP ||
9026 child->type == CTK_TEXT_WINDOW_BOTTOM)
9027 child_dx = dx;
9028 }
9029
9030 if (child_dx != 0 || child_dy != 0)
9031 adjust_allocation (child->widget, child_dx, child_dy);
9032
9033 tmp_list = tmp_list->next;
9034 }
9035 }
9036
9037 /* This could result in invalidation, which would install the
9038 * first_validate_idle, which would validate onscreen;
9039 * but we're going to go ahead and validate here, so
9040 * first_validate_idle shouldn't have anything to do.
9041 */
9042 ctk_text_view_update_layout_width (text_view);
9043
9044 /* We also update the IM spot location here, since the IM context
9045 * might do something that leads to validation.
9046 */
9047 ctk_text_view_update_im_spot_location (text_view);
9048
9049 /* note that validation of onscreen could invoke this function
9050 * recursively, by scrolling to maintain first_para, or in response
9051 * to updating the layout width, however there is no problem with
9052 * that, or shouldn't be.
9053 */
9054 ctk_text_view_validate_onscreen (text_view);
9055
9056 /* If this got installed, get rid of it, it's just a waste of time. */
9057 if (priv->first_validate_idle != 0)
9058 {
9059 g_source_remove (priv->first_validate_idle);
9060 priv->first_validate_idle = 0;
9061 }
9062
9063 /* Allow to extend selection with mouse scrollwheel. Bug 710612 */
9064 if (ctk_gesture_is_active (priv->drag_gesture))
9065 {
9066 CdkEvent *current_event;
9067 current_event = ctk_get_current_event ();
9068 if (current_event != NULL((void*)0))
9069 {
9070 if (current_event->type == CDK_SCROLL)
9071 move_mark_to_pointer_and_scroll (text_view, "insert");
9072
9073 cdk_event_free (current_event);
9074 }
9075 }
9076
9077 /* Finally we update the IM cursor location again, to ensure any
9078 * changes made by the validation are pushed through.
9079 */
9080 ctk_text_view_update_im_spot_location (text_view);
9081
9082 if (priv->text_handle)
9083 ctk_text_view_update_handles (text_view,
9084 _ctk_text_handle_get_mode (priv->text_handle));
9085
9086 DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
9087}
9088
9089static void
9090ctk_text_view_commit_handler (CtkIMContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
9091 const gchar *str,
9092 CtkTextView *text_view)
9093{
9094 ctk_text_view_commit_text (text_view, str);
9095}
9096
9097static void
9098ctk_text_view_commit_text (CtkTextView *text_view,
9099 const gchar *str)
9100{
9101 CtkTextViewPrivate *priv;
9102 gboolean had_selection;
9103
9104 priv = text_view->priv;
9105
9106 ctk_text_buffer_begin_user_action (get_buffer (text_view));
9107
9108 had_selection = ctk_text_buffer_get_selection_bounds (get_buffer (text_view),
9109 NULL((void*)0), NULL((void*)0));
9110
9111 ctk_text_buffer_delete_selection (get_buffer (text_view), TRUE(!(0)),
9112 priv->editable);
9113
9114 if (!strcmp (str, "\n"))
9115 {
9116 if (!ctk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
9117 priv->editable))
9118 {
9119 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
9120 }
9121 }
9122 else
9123 {
9124 if (!had_selection && priv->overwrite_mode)
9125 {
9126 CtkTextIter insert;
9127
9128 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view),
9129 &insert,
9130 ctk_text_buffer_get_insert (get_buffer (text_view)));
9131 if (!ctk_text_iter_ends_line (&insert))
9132 ctk_text_view_delete_from_cursor (text_view, CTK_DELETE_CHARS, 1);
9133 }
9134
9135 if (!ctk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
9136 priv->editable))
9137 {
9138 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
9139 }
9140 }
9141
9142 ctk_text_buffer_end_user_action (get_buffer (text_view));
9143
9144 ctk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
9145 DV(g_print (G_STRLOC": scrolling onscreen\n"));
9146 ctk_text_view_scroll_mark_onscreen (text_view,
9147 ctk_text_buffer_get_insert (get_buffer (text_view)));
9148}
9149
9150static void
9151ctk_text_view_preedit_changed_handler (CtkIMContext *context,
9152 CtkTextView *text_view)
9153{
9154 CtkTextViewPrivate *priv;
9155 gchar *str;
9156 PangoAttrList *attrs;
9157 gint cursor_pos;
9158 CtkTextIter iter;
9159
9160 priv = text_view->priv;
9161
9162 ctk_text_buffer_get_iter_at_mark (priv->buffer, &iter,
9163 ctk_text_buffer_get_insert (priv->buffer));
9164
9165 /* Keypress events are passed to input method even if cursor position is
9166 * not editable; so beep here if it's multi-key input sequence, input
9167 * method will be reset in key-press-event handler.
9168 */
9169 ctk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
9170
9171 if (str && str[0] && !ctk_text_iter_can_insert (&iter, priv->editable))
9172 {
9173 ctk_widget_error_bell (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
9174 goto out;
9175 }
9176
9177 g_signal_emit (text_view, signals[PREEDIT_CHANGED], 0, str);
9178
9179 if (priv->layout)
9180 ctk_text_layout_set_preedit_string (priv->layout, str, attrs, cursor_pos);
9181 if (ctk_widget_has_focus (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
9182 ctk_text_view_scroll_mark_onscreen (text_view,
9183 ctk_text_buffer_get_insert (get_buffer (text_view)));
9184
9185out:
9186 pango_attr_list_unref (attrs);
9187 g_free (str);
9188}
9189
9190static gboolean
9191ctk_text_view_retrieve_surrounding_handler (CtkIMContext *context,
9192 CtkTextView *text_view)
9193{
9194 CtkTextIter start;
9195 CtkTextIter end;
9196 gint pos;
9197 gchar *text;
9198
9199 ctk_text_buffer_get_iter_at_mark (text_view->priv->buffer, &start,
9200 ctk_text_buffer_get_insert (text_view->priv->buffer));
9201 end = start;
9202
9203 pos = ctk_text_iter_get_line_index (&start);
9204 ctk_text_iter_set_line_offset (&start, 0);
9205 ctk_text_iter_forward_to_line_end (&end);
9206
9207 text = ctk_text_iter_get_slice (&start, &end);
9208 ctk_im_context_set_surrounding (context, text, -1, pos);
9209 g_free (text);
9210
9211 return TRUE(!(0));
9212}
9213
9214static gboolean
9215ctk_text_view_delete_surrounding_handler (CtkIMContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
9216 gint offset,
9217 gint n_chars,
9218 CtkTextView *text_view)
9219{
9220 CtkTextViewPrivate *priv;
9221 CtkTextIter start;
9222 CtkTextIter end;
9223
9224 priv = text_view->priv;
9225
9226 ctk_text_buffer_get_iter_at_mark (priv->buffer, &start,
9227 ctk_text_buffer_get_insert (priv->buffer));
9228 end = start;
9229
9230 ctk_text_iter_forward_chars (&start, offset);
9231 ctk_text_iter_forward_chars (&end, offset + n_chars);
9232
9233 ctk_text_buffer_delete_interactive (priv->buffer, &start, &end,
9234 priv->editable);
9235
9236 return TRUE(!(0));
9237}
9238
9239static void
9240ctk_text_view_mark_set_handler (CtkTextBuffer *buffer,
9241 const CtkTextIter *location G_GNUC_UNUSED__attribute__ ((__unused__)),
9242 CtkTextMark *mark,
9243 gpointer data)
9244{
9245 CtkTextView *text_view = CTK_TEXT_VIEW (data)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ctk_text_view_get_type ()))))))
;
9246 gboolean need_reset = FALSE(0);
9247 gboolean has_selection;
9248
9249 if (mark == ctk_text_buffer_get_insert (buffer))
9250 {
9251 text_view->priv->virtual_cursor_x = -1;
9252 text_view->priv->virtual_cursor_y = -1;
9253 ctk_text_view_update_im_spot_location (text_view);
9254 need_reset = TRUE(!(0));
9255 }
9256 else if (mark == ctk_text_buffer_get_selection_bound (buffer))
9257 {
9258 need_reset = TRUE(!(0));
9259 }
9260
9261 if (need_reset)
9262 {
9263 ctk_text_view_reset_im_context (text_view);
9264 if (text_view->priv->text_handle)
9265 ctk_text_view_update_handles (text_view,
9266 _ctk_text_handle_get_mode (text_view->priv->text_handle));
9267
9268 has_selection = ctk_text_buffer_get_selection_bounds (get_buffer (text_view), NULL((void*)0), NULL((void*)0));
9269 ctk_css_node_set_visible (text_view->priv->selection_node, has_selection);
9270 }
9271}
9272
9273static void
9274ctk_text_view_target_list_notify (CtkTextBuffer *buffer,
9275 const GParamSpec *pspec G_GNUC_UNUSED__attribute__ ((__unused__)),
9276 gpointer data)
9277{
9278 CtkWidget *widget = CTK_WIDGET (data)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ctk_widget_get_type ()))))))
;
9279 CtkTargetList *view_list;
9280 CtkTargetList *buffer_list;
9281 GList *list;
9282
9283 view_list = ctk_drag_dest_get_target_list (widget);
9284 buffer_list = ctk_text_buffer_get_paste_target_list (buffer);
9285
9286 if (view_list)
9287 ctk_target_list_ref (view_list);
9288 else
9289 view_list = ctk_target_list_new (NULL((void*)0), 0);
9290
9291 list = view_list->list;
9292 while (list)
9293 {
9294 CtkTargetPair *pair = list->data;
9295
9296 list = list->next; /* get next element before removing */
9297
9298 if (pair->info >= CTK_TEXT_BUFFER_TARGET_INFO_TEXT &&
9299 pair->info <= CTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
9300 {
9301 ctk_target_list_remove (view_list, pair->target);
9302 }
9303 }
9304
9305 for (list = buffer_list->list; list; list = list->next)
9306 {
9307 CtkTargetPair *pair = list->data;
9308
9309 ctk_target_list_add (view_list, pair->target, pair->flags, pair->info);
9310 }
9311
9312 ctk_drag_dest_set_target_list (widget, view_list);
9313 ctk_target_list_unref (view_list);
9314}
9315
9316static void
9317ctk_text_view_get_virtual_cursor_pos (CtkTextView *text_view,
9318 CtkTextIter *cursor,
9319 gint *x,
9320 gint *y)
9321{
9322 CtkTextViewPrivate *priv;
9323 CtkTextIter insert;
9324 CdkRectangle pos;
9325
9326 priv = text_view->priv;
9327
9328 if (cursor)
9329 insert = *cursor;
9330 else
9331 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
9332 ctk_text_buffer_get_insert (get_buffer (text_view)));
9333
9334 if ((x && priv->virtual_cursor_x == -1) ||
9335 (y && priv->virtual_cursor_y == -1))
9336 ctk_text_layout_get_cursor_locations (priv->layout, &insert, &pos, NULL((void*)0));
9337
9338 if (x)
9339 {
9340 if (priv->virtual_cursor_x != -1)
9341 *x = priv->virtual_cursor_x;
9342 else
9343 *x = pos.x;
9344 }
9345
9346 if (y)
9347 {
9348 if (priv->virtual_cursor_y != -1)
9349 *y = priv->virtual_cursor_y;
9350 else
9351 *y = pos.y + pos.height / 2;
9352 }
9353}
9354
9355static void
9356ctk_text_view_set_virtual_cursor_pos (CtkTextView *text_view,
9357 gint x,
9358 gint y)
9359{
9360 CdkRectangle pos;
9361
9362 if (!text_view->priv->layout)
9363 return;
9364
9365 if (x == -1 || y == -1)
9366 ctk_text_view_get_cursor_locations (text_view, NULL((void*)0), &pos, NULL((void*)0));
9367
9368 text_view->priv->virtual_cursor_x = (x == -1) ? pos.x : x;
9369 text_view->priv->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
9370}
9371
9372/* Quick hack of a popup menu
9373 */
9374static void
9375activate_cb (CtkWidget *menuitem,
9376 CtkTextView *text_view)
9377{
9378 const gchar *signal;
9379
9380 signal = g_object_get_qdata (G_OBJECT (menuitem)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menuitem)), (((GType) ((20) << (2))))))))
, quark_ctk_signal);
9381 g_signal_emit_by_name (text_view, signal);
9382}
9383
9384static void
9385append_action_signal (CtkTextView *text_view,
9386 CtkWidget *menu,
9387 const gchar *label,
9388 const gchar *signal,
9389 gboolean sensitive)
9390{
9391 CtkWidget *menuitem = ctk_menu_item_new_with_mnemonic (label);
9392
9393 g_object_set_qdata (G_OBJECT (menuitem)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menuitem)), (((GType) ((20) << (2))))))))
, quark_ctk_signal, (char *)signal);
9394 g_signal_connect (menuitem, "activate",g_signal_connect_data ((menuitem), ("activate"), (((GCallback
) (activate_cb))), (text_view), ((void*)0), (GConnectFlags) 0
)
9395 G_CALLBACK (activate_cb), text_view)g_signal_connect_data ((menuitem), ("activate"), (((GCallback
) (activate_cb))), (text_view), ((void*)0), (GConnectFlags) 0
)
;
9396
9397 ctk_widget_set_sensitive (menuitem, sensitive);
9398
9399 ctk_widget_show (menuitem);
9400 ctk_menu_shell_append (CTK_MENU_SHELL (menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_shell_get_type ()))))))
, menuitem);
9401}
9402
9403static void
9404ctk_text_view_select_all (CtkWidget *widget,
9405 gboolean select)
9406{
9407 CtkTextView *text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
9408 CtkTextBuffer *buffer;
9409 CtkTextIter start_iter, end_iter, insert;
9410
9411 buffer = text_view->priv->buffer;
9412 if (select)
9413 {
9414 ctk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
9415 ctk_text_buffer_select_range (buffer, &start_iter, &end_iter);
9416 }
9417 else
9418 {
9419 ctk_text_buffer_get_iter_at_mark (buffer, &insert,
9420 ctk_text_buffer_get_insert (buffer));
9421 ctk_text_buffer_move_mark_by_name (buffer, "selection_bound", &insert);
9422 }
9423}
9424
9425static void
9426select_all_cb (CtkWidget *menuitem G_GNUC_UNUSED__attribute__ ((__unused__)),
9427 CtkTextView *text_view)
9428{
9429 ctk_text_view_select_all (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
, TRUE(!(0)));
9430}
9431
9432static void
9433delete_cb (CtkTextView *text_view)
9434{
9435 ctk_text_buffer_delete_selection (get_buffer (text_view), TRUE(!(0)),
9436 text_view->priv->editable);
9437}
9438
9439static void
9440popup_menu_detach (CtkWidget *attach_widget,
9441 CtkMenu *menu G_GNUC_UNUSED__attribute__ ((__unused__)))
9442{
9443 CTK_TEXT_VIEW (attach_widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((attach_widget)), ((ctk_text_view_get_type ()))))))
->priv->popup_menu = NULL((void*)0);
9444}
9445
9446typedef struct
9447{
9448 CtkTextView *text_view;
9449 CdkEvent *trigger_event;
9450} PopupInfo;
9451
9452static gboolean
9453range_contains_editable_text (const CtkTextIter *start,
9454 const CtkTextIter *end,
9455 gboolean default_editability)
9456{
9457 CtkTextIter iter = *start;
9458
9459 while (ctk_text_iter_compare (&iter, end) < 0)
9460 {
9461 if (ctk_text_iter_editable (&iter, default_editability))
9462 return TRUE(!(0));
9463
9464 ctk_text_iter_forward_to_tag_toggle (&iter, NULL((void*)0));
9465 }
9466
9467 return FALSE(0);
9468}
9469
9470static void
9471popup_targets_received (CtkClipboard *clipboard G_GNUC_UNUSED__attribute__ ((__unused__)),
9472 CtkSelectionData *data,
9473 gpointer user_data)
9474{
9475 PopupInfo *info = user_data;
9476 CtkTextView *text_view;
9477 CtkTextViewPrivate *priv;
9478
9479 text_view = info->text_view;
9480 priv = text_view->priv;
9481
9482 if (ctk_widget_get_realized (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
9483 {
9484 /* We implicitely rely here on the fact that if we are pasting ourself, we'll
9485 * have text targets as well as the private CTK_TEXT_BUFFER_CONTENTS target.
9486 */
9487 gboolean clipboard_contains_text;
9488 CtkWidget *menuitem;
9489 gboolean have_selection;
9490 gboolean can_insert;
9491 CtkTextIter iter;
9492 CtkTextIter sel_start, sel_end;
9493 CdkRectangle iter_location;
9494 CdkRectangle visible_rect;
9495 gboolean is_visible;
9496
9497 clipboard_contains_text = ctk_selection_data_targets_include_text (data);
9498
9499 if (priv->popup_menu)
9500 ctk_widget_destroy (priv->popup_menu);
9501
9502 priv->popup_menu = ctk_menu_new ();
9503 ctk_style_context_add_class (ctk_widget_get_style_context (priv->popup_menu),
9504 CTK_STYLE_CLASS_CONTEXT_MENU"context-menu");
9505
9506 ctk_menu_attach_to_widget (CTK_MENU (priv->popup_menu)((((CtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_get_type ()))))))
,
9507 CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
9508 popup_menu_detach);
9509
9510 have_selection = ctk_text_buffer_get_selection_bounds (get_buffer (text_view),
9511 &sel_start, &sel_end);
9512
9513 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view),
9514 &iter,
9515 ctk_text_buffer_get_insert (get_buffer (text_view)));
9516
9517 can_insert = ctk_text_iter_can_insert (&iter, priv->editable);
9518
9519 append_action_signal (text_view, priv->popup_menu, _("Cu_t")((char *) g_dgettext ("ctk30", "Cu_t")), "cut-clipboard",
9520 have_selection &&
9521 range_contains_editable_text (&sel_start, &sel_end,
9522 priv->editable));
9523 append_action_signal (text_view, priv->popup_menu, _("_Copy")((char *) g_dgettext ("ctk30", "_Copy")), "copy-clipboard",
9524 have_selection);
9525 append_action_signal (text_view, priv->popup_menu, _("_Paste")((char *) g_dgettext ("ctk30", "_Paste")), "paste-clipboard",
9526 can_insert && clipboard_contains_text);
9527
9528 menuitem = ctk_menu_item_new_with_mnemonic (_("_Delete")((char *) g_dgettext ("ctk30", "_Delete")));
9529 ctk_widget_set_sensitive (menuitem,
9530 have_selection &&
9531 range_contains_editable_text (&sel_start, &sel_end,
9532 priv->editable));
9533 g_signal_connect_swapped (menuitem, "activate",g_signal_connect_data ((menuitem), ("activate"), (((GCallback
) (delete_cb))), (text_view), ((void*)0), G_CONNECT_SWAPPED)
9534 G_CALLBACK (delete_cb), text_view)g_signal_connect_data ((menuitem), ("activate"), (((GCallback
) (delete_cb))), (text_view), ((void*)0), G_CONNECT_SWAPPED)
;
9535 ctk_widget_show (menuitem);
9536 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, menuitem);
9537
9538 menuitem = ctk_separator_menu_item_new ();
9539 ctk_widget_show (menuitem);
9540 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, menuitem);
9541
9542 menuitem = ctk_menu_item_new_with_mnemonic (_("Select _All")((char *) g_dgettext ("ctk30", "Select _All")));
9543 ctk_widget_set_sensitive (menuitem,
9544 ctk_text_buffer_get_char_count (priv->buffer) > 0);
9545 g_signal_connect (menuitem, "activate",g_signal_connect_data ((menuitem), ("activate"), (((GCallback
) (select_all_cb))), (text_view), ((void*)0), (GConnectFlags)
0)
9546 G_CALLBACK (select_all_cb), text_view)g_signal_connect_data ((menuitem), ("activate"), (((GCallback
) (select_all_cb))), (text_view), ((void*)0), (GConnectFlags)
0)
;
9547 ctk_widget_show (menuitem);
9548 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, menuitem);
9549
9550 if ((ctk_text_view_get_input_hints (text_view) & CTK_INPUT_HINT_NO_EMOJI) == 0)
9551 {
9552 menuitem = ctk_menu_item_new_with_mnemonic (_("Insert _Emoji")((char *) g_dgettext ("ctk30", "Insert _Emoji")));
9553 ctk_widget_set_sensitive (menuitem, can_insert);
9554 g_signal_connect_swapped (menuitem, "activate",g_signal_connect_data ((menuitem), ("activate"), (((GCallback
) (ctk_text_view_insert_emoji))), (text_view), ((void*)0), G_CONNECT_SWAPPED
)
9555 G_CALLBACK (ctk_text_view_insert_emoji), text_view)g_signal_connect_data ((menuitem), ("activate"), (((GCallback
) (ctk_text_view_insert_emoji))), (text_view), ((void*)0), G_CONNECT_SWAPPED
)
;
9556 ctk_widget_show (menuitem);
9557 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, menuitem);
9558 }
9559
9560 g_signal_emit (text_view, signals[POPULATE_POPUP],
9561 0, priv->popup_menu);
9562
9563 if (info->trigger_event && cdk_event_triggers_context_menu (info->trigger_event))
9564 ctk_menu_popup_at_pointer (CTK_MENU (priv->popup_menu)((((CtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_get_type ()))))))
, info->trigger_event);
9565 else
9566 {
9567 ctk_text_view_get_iter_location (text_view, &iter, &iter_location);
9568 ctk_text_view_get_visible_rect (text_view, &visible_rect);
9569
9570 is_visible = (iter_location.x + iter_location.width > visible_rect.x &&
9571 iter_location.x < visible_rect.x + visible_rect.width &&
9572 iter_location.y + iter_location.height > visible_rect.y &&
9573 iter_location.y < visible_rect.y + visible_rect.height);
9574
9575 if (is_visible)
9576 {
9577 ctk_text_view_buffer_to_window_coords (text_view,
9578 CTK_TEXT_WINDOW_WIDGET,
9579 iter_location.x,
9580 iter_location.y,
9581 &iter_location.x,
9582 &iter_location.y);
9583
9584 ctk_menu_popup_at_rect (CTK_MENU (priv->popup_menu)((((CtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_get_type ()))))))
,
9585 ctk_widget_get_window (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
),
9586 &iter_location,
9587 CDK_GRAVITY_SOUTH_EAST,
9588 CDK_GRAVITY_NORTH_WEST,
9589 info->trigger_event);
9590 }
9591 else
9592 ctk_menu_popup_at_widget (CTK_MENU (priv->popup_menu)((((CtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_get_type ()))))))
,
9593 CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
9594 CDK_GRAVITY_CENTER,
9595 CDK_GRAVITY_CENTER,
9596 info->trigger_event);
9597
9598 ctk_menu_shell_select_first (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, FALSE(0));
9599 }
9600 }
9601
9602 g_clear_pointer (&info->trigger_event, cdk_event_free)do { _Static_assert (sizeof *(&info->trigger_event) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&info->trigger_event)) _pp = (&info->trigger_event
); __typeof__ (*(&info->trigger_event)) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (cdk_event_free) (_ptr); } while (
0)
;
9603 g_object_unref (text_view);
9604 g_slice_free (PopupInfo, info)do { if (1) g_slice_free1 (sizeof (PopupInfo), (info)); else (
void) ((PopupInfo*) 0 == (info)); } while (0)
;
9605}
9606
9607static void
9608ctk_text_view_do_popup (CtkTextView *text_view,
9609 const CdkEvent *event)
9610{
9611 PopupInfo *info = g_slice_new (PopupInfo)((PopupInfo*) g_slice_alloc (sizeof (PopupInfo)));
9612
9613 /* In order to know what entries we should make sensitive, we
9614 * ask for the current targets of the clipboard, and when
9615 * we get them, then we actually pop up the menu.
9616 */
9617 info->text_view = g_object_ref (text_view)((__typeof__ (text_view)) (g_object_ref) (text_view));
9618 info->trigger_event = event ? cdk_event_copy (event) : ctk_get_current_event ();
9619
9620 ctk_clipboard_request_contents (ctk_widget_get_clipboard (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
9621 CDK_SELECTION_CLIPBOARD((CdkAtom)((gpointer) (gulong) (69)))),
9622 cdk_atom_intern_static_string ("TARGETS"),
9623 popup_targets_received,
9624 info);
9625}
9626
9627static gboolean
9628ctk_text_view_popup_menu (CtkWidget *widget)
9629{
9630 ctk_text_view_do_popup (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
, NULL((void*)0));
9631 return TRUE(!(0));
9632}
9633
9634static void
9635ctk_text_view_get_selection_rect (CtkTextView *text_view,
9636 cairo_rectangle_int_t *rect)
9637{
9638 cairo_rectangle_int_t rect_cursor, rect_bound;
9639 CtkTextIter cursor, bound;
9640 CtkTextBuffer *buffer;
9641 gint x1, y1, x2, y2;
9642
9643 buffer = get_buffer (text_view);
9644 ctk_text_buffer_get_iter_at_mark (buffer, &cursor,
9645 ctk_text_buffer_get_insert (buffer));
9646 ctk_text_buffer_get_iter_at_mark (buffer, &bound,
9647 ctk_text_buffer_get_selection_bound (buffer));
9648
9649 ctk_text_view_get_cursor_locations (text_view, &cursor, &rect_cursor, NULL((void*)0));
9650 ctk_text_view_get_cursor_locations (text_view, &bound, &rect_bound, NULL((void*)0));
9651
9652 x1 = MIN (rect_cursor.x, rect_bound.x)(((rect_cursor.x) < (rect_bound.x)) ? (rect_cursor.x) : (rect_bound
.x))
;
9653 x2 = MAX (rect_cursor.x, rect_bound.x)(((rect_cursor.x) > (rect_bound.x)) ? (rect_cursor.x) : (rect_bound
.x))
;
9654 y1 = MIN (rect_cursor.y, rect_bound.y)(((rect_cursor.y) < (rect_bound.y)) ? (rect_cursor.y) : (rect_bound
.y))
;
9655 y2 = MAX (rect_cursor.y + rect_cursor.height, rect_bound.y + rect_bound.height)(((rect_cursor.y + rect_cursor.height) > (rect_bound.y + rect_bound
.height)) ? (rect_cursor.y + rect_cursor.height) : (rect_bound
.y + rect_bound.height))
;
9656
9657 rect->x = x1;
9658 rect->y = y1;
9659 rect->width = x2 - x1;
9660 rect->height = y2 - y1;
9661}
9662
9663static void
9664show_or_hide_handles (CtkWidget *popover,
9665 GParamSpec *pspec G_GNUC_UNUSED__attribute__ ((__unused__)),
9666 CtkTextView *text_view)
9667{
9668 gboolean visible;
9669 CtkTextHandle *handle;
9670 CtkTextHandleMode mode;
9671
9672 visible = ctk_widget_get_visible (popover);
9673
9674 handle = text_view->priv->text_handle;
9675 mode = _ctk_text_handle_get_mode (handle);
9676
9677 if (!visible)
9678 ctk_text_view_update_handles (text_view, mode);
9679 else
9680 {
9681 _ctk_text_handle_set_visible (handle, CTK_TEXT_HANDLE_POSITION_SELECTION_START, FALSE(0));
9682 _ctk_text_handle_set_visible (handle, CTK_TEXT_HANDLE_POSITION_SELECTION_END, FALSE(0));
9683 }
9684}
9685
9686static void
9687activate_bubble_cb (CtkWidget *item,
9688 CtkTextView *text_view)
9689{
9690 const gchar *signal;
9691
9692 signal = g_object_get_qdata (G_OBJECT (item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), (((GType) ((20) << (2))))))))
, quark_ctk_signal);
9693 ctk_widget_hide (text_view->priv->selection_bubble);
9694
9695 if (strcmp (signal, "select-all") == 0)
9696 g_signal_emit_by_name (text_view, "select-all", TRUE(!(0)));
9697 else
9698 g_signal_emit_by_name (text_view, signal);
9699}
9700
9701static void
9702append_bubble_action (CtkTextView *text_view,
9703 CtkWidget *toolbar,
9704 const gchar *label,
9705 const gchar *icon_name,
9706 const gchar *signal,
9707 gboolean sensitive)
9708{
9709 CtkWidget *item;
9710
9711 item = ctk_button_new_from_icon_name (icon_name, CTK_ICON_SIZE_MENU);
9712 ctk_widget_set_focus_on_click (item, FALSE(0));
9713 ctk_widget_set_tooltip_text (item, label);
9714 g_object_set_qdata (G_OBJECT (item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), (((GType) ((20) << (2))))))))
, quark_ctk_signal, (char *)signal);
9715 g_signal_connect (item, "clicked", G_CALLBACK (activate_bubble_cb), text_view)g_signal_connect_data ((item), ("clicked"), (((GCallback) (activate_bubble_cb
))), (text_view), ((void*)0), (GConnectFlags) 0)
;
9716 ctk_widget_set_sensitive (CTK_WIDGET (item)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((ctk_widget_get_type ()))))))
, sensitive);
9717 ctk_widget_show (item);
9718 ctk_container_add (CTK_CONTAINER (toolbar)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((ctk_container_get_type ()))))))
, item);
9719}
9720
9721static void
9722bubble_targets_received (CtkClipboard *clipboard G_GNUC_UNUSED__attribute__ ((__unused__)),
9723 CtkSelectionData *data,
9724 gpointer user_data)
9725{
9726 CtkTextView *text_view = user_data;
9727 CtkTextViewPrivate *priv = text_view->priv;
9728 cairo_rectangle_int_t rect;
9729 gboolean has_selection;
9730 gboolean has_clipboard;
9731 gboolean can_insert;
9732 gboolean all_selected;
9733 CtkTextIter iter;
9734 CtkTextIter sel_start, sel_end;
9735 CtkTextIter start, end;
9736 CtkWidget *box;
9737 CtkWidget *toolbar;
9738
9739 has_selection = ctk_text_buffer_get_selection_bounds (get_buffer (text_view),
9740 &sel_start, &sel_end);
9741 ctk_text_buffer_get_bounds (get_buffer (text_view), &start, &end);
9742
9743 all_selected = ctk_text_iter_equal (&start, &sel_start) &&
9744 ctk_text_iter_equal (&end, &sel_end);
9745
9746 if (!priv->editable && !has_selection)
9747 {
9748 priv->selection_bubble_timeout_id = 0;
9749 return;
9750 }
9751
9752 if (priv->selection_bubble)
9753 ctk_widget_destroy (priv->selection_bubble);
9754
9755 priv->selection_bubble = ctk_popover_new (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
9756 ctk_style_context_add_class (ctk_widget_get_style_context (priv->selection_bubble),
9757 CTK_STYLE_CLASS_TOUCH_SELECTION"touch-selection");
9758 ctk_popover_set_position (CTK_POPOVER (priv->selection_bubble)((((CtkPopover*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->selection_bubble)), ((ctk_popover_get_type ()))
))))
, CTK_POS_BOTTOM);
9759 ctk_popover_set_modal (CTK_POPOVER (priv->selection_bubble)((((CtkPopover*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->selection_bubble)), ((ctk_popover_get_type ()))
))))
, FALSE(0));
9760 g_signal_connect (priv->selection_bubble, "notify::visible",g_signal_connect_data ((priv->selection_bubble), ("notify::visible"
), (((GCallback) (show_or_hide_handles))), (text_view), ((void
*)0), (GConnectFlags) 0)
9761 G_CALLBACK (show_or_hide_handles), text_view)g_signal_connect_data ((priv->selection_bubble), ("notify::visible"
), (((GCallback) (show_or_hide_handles))), (text_view), ((void
*)0), (GConnectFlags) 0)
;
9762
9763 box = ctk_box_new (CTK_ORIENTATION_VERTICAL, 5);
9764 g_object_set (box, "margin", 10, NULL((void*)0));
9765 ctk_widget_show (box);
9766 toolbar = ctk_box_new (CTK_ORIENTATION_HORIZONTAL, 5);
9767 ctk_widget_show (toolbar);
9768 ctk_container_add (CTK_CONTAINER (priv->selection_bubble)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->selection_bubble)), ((ctk_container_get_type ()
))))))
, box);
9769 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, toolbar);
9770
9771 ctk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter,
9772 ctk_text_buffer_get_insert (get_buffer (text_view)));
9773 can_insert = ctk_text_iter_can_insert (&iter, priv->editable);
9774 has_clipboard = ctk_selection_data_targets_include_text (data);
9775
9776 append_bubble_action (text_view, toolbar, _("Select all")((char *) g_dgettext ("ctk30", "Select all")), "edit-select-all-symbolic", "select-all", !all_selected);
9777
9778 if (range_contains_editable_text (&sel_start, &sel_end, priv->editable) && has_selection)
9779 append_bubble_action (text_view, toolbar, _("Cut")((char *) g_dgettext ("ctk30", "Cut")), "edit-cut-symbolic", "cut-clipboard", TRUE(!(0)));
9780
9781 if (has_selection)
9782 append_bubble_action (text_view, toolbar, _("Copy")((char *) g_dgettext ("ctk30", "Copy")), "edit-copy-symbolic", "copy-clipboard", TRUE(!(0)));
9783
9784 if (can_insert)
9785 append_bubble_action (text_view, toolbar, _("Paste")((char *) g_dgettext ("ctk30", "Paste")), "edit-paste-symbolic", "paste-clipboard", has_clipboard);
9786
9787 if (priv->populate_all)
9788 g_signal_emit (text_view, signals[POPULATE_POPUP], 0, box);
9789
9790 ctk_text_view_get_selection_rect (text_view, &rect);
9791 rect.x -= priv->xoffset;
9792 rect.y -= priv->yoffset;
9793
9794 _text_window_to_widget_coords (text_view, &rect.x, &rect.y);
9795
9796 rect.x -= 5;
9797 rect.y -= 5;
9798 rect.width += 10;
9799 rect.height += 10;
9800
9801 ctk_popover_set_pointing_to (CTK_POPOVER (priv->selection_bubble)((((CtkPopover*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->selection_bubble)), ((ctk_popover_get_type ()))
))))
, &rect);
9802 ctk_widget_show (priv->selection_bubble);
9803}
9804
9805static gboolean
9806ctk_text_view_selection_bubble_popup_show (gpointer user_data)
9807{
9808 CtkTextView *text_view = user_data;
9809 ctk_clipboard_request_contents (ctk_widget_get_clipboard (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
,
9810 CDK_SELECTION_CLIPBOARD((CdkAtom)((gpointer) (gulong) (69)))),
9811 cdk_atom_intern_static_string ("TARGETS"),
9812 bubble_targets_received,
9813 text_view);
9814 text_view->priv->selection_bubble_timeout_id = 0;
9815
9816 return G_SOURCE_REMOVE(0);
9817}
9818
9819static void
9820ctk_text_view_selection_bubble_popup_unset (CtkTextView *text_view)
9821{
9822 CtkTextViewPrivate *priv;
9823
9824 priv = text_view->priv;
9825
9826 if (priv->selection_bubble)
9827 ctk_widget_hide (priv->selection_bubble);
9828
9829 if (priv->selection_bubble_timeout_id)
9830 {
9831 g_source_remove (priv->selection_bubble_timeout_id);
9832 priv->selection_bubble_timeout_id = 0;
9833 }
9834}
9835
9836static void
9837ctk_text_view_selection_bubble_popup_set (CtkTextView *text_view)
9838{
9839 CtkTextViewPrivate *priv;
9840
9841 priv = text_view->priv;
9842
9843 if (priv->selection_bubble_timeout_id)
9844 g_source_remove (priv->selection_bubble_timeout_id);
9845
9846 priv->selection_bubble_timeout_id =
9847 cdk_threads_add_timeout (50, ctk_text_view_selection_bubble_popup_show,
9848 text_view);
9849 g_source_set_name_by_id (priv->selection_bubble_timeout_id, "[ctk+] ctk_text_view_selection_bubble_popup_cb");
9850}
9851
9852/* Child CdkWindows */
9853
9854static void
9855node_style_changed_cb (CtkCssNode *node,
9856 CtkCssStyleChange *change,
9857 CtkWidget *widget)
9858{
9859 CtkTextViewPrivate *priv = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->priv;
9860
9861 if (ctk_css_style_change_affects (change, CTK_CSS_AFFECTS_SIZE | CTK_CSS_AFFECTS_CLIP))
9862 ctk_widget_queue_resize (widget);
9863 else
9864 ctk_widget_queue_draw (widget);
9865
9866 if (node == priv->text_window->css_node)
9867 {
9868 CtkCssStyle *style = ctk_css_style_change_get_new_style (change);
9869 ctk_pixel_cache_set_is_opaque (priv->pixel_cache, ctk_css_style_render_background_is_opaque (style));
9870 }
9871}
9872
9873static void
9874update_node_ordering (CtkWidget *widget)
9875{
9876 CtkTextViewPrivate *priv = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->priv;
9877 CtkCssNode *widget_node, *sibling;
9878
9879 if (priv->text_window == NULL((void*)0))
9880 return;
9881
9882 widget_node = ctk_widget_get_css_node (widget);
9883 sibling = priv->text_window->css_node;
9884
9885 if (priv->left_window)
9886 {
9887 ctk_css_node_insert_before (widget_node, priv->left_window->css_node, sibling);
9888 sibling = priv->left_window->css_node;
9889 }
9890 if (priv->top_window)
9891 {
9892 ctk_css_node_insert_before (widget_node, priv->top_window->css_node, sibling);
9893 }
9894
9895 sibling = priv->text_window->css_node;
9896 if (priv->right_window)
9897 {
9898 ctk_css_node_insert_after (widget_node, priv->right_window->css_node, sibling);
9899 sibling = priv->right_window->css_node;
9900 }
9901 if (priv->bottom_window)
9902 {
9903 ctk_css_node_insert_after (widget_node, priv->bottom_window->css_node, sibling);
9904 }
9905}
9906
9907static CtkTextWindow*
9908text_window_new (CtkTextWindowType type,
9909 CtkWidget *widget,
9910 gint width_request,
9911 gint height_request)
9912{
9913 CtkTextWindow *win;
9914 CtkCssNode *widget_node;
9915
9916 win = g_slice_new (CtkTextWindow)((CtkTextWindow*) g_slice_alloc (sizeof (CtkTextWindow)));
9917
9918 win->type = type;
9919 win->widget = widget;
9920 win->window = NULL((void*)0);
9921 win->bin_window = NULL((void*)0);
9922 win->requisition.width = width_request;
9923 win->requisition.height = height_request;
9924 win->allocation.width = width_request;
9925 win->allocation.height = height_request;
9926 win->allocation.x = 0;
9927 win->allocation.y = 0;
9928
9929 widget_node = ctk_widget_get_css_node (widget);
9930 win->css_node = ctk_css_node_new ();
9931 ctk_css_node_set_parent (win->css_node, widget_node);
9932 ctk_css_node_set_state (win->css_node, ctk_css_node_get_state (widget_node));
9933 g_signal_connect_object (win->css_node, "style-changed", G_CALLBACK (node_style_changed_cb)((GCallback) (node_style_changed_cb)), widget, 0);
9934 if (type == CTK_TEXT_WINDOW_TEXT)
9935 {
9936 ctk_css_node_set_name (win->css_node, I_("text")g_intern_static_string ("text"));
9937 }
9938 else
9939 {
9940 ctk_css_node_set_name (win->css_node, I_("border")g_intern_static_string ("border"));
9941 switch (type)
9942 {
9943 case CTK_TEXT_WINDOW_LEFT:
9944 ctk_css_node_add_class (win->css_node, g_quark_from_static_string (CTK_STYLE_CLASS_LEFT"left"));
9945 break;
9946 case CTK_TEXT_WINDOW_RIGHT:
9947 ctk_css_node_add_class (win->css_node, g_quark_from_static_string (CTK_STYLE_CLASS_RIGHT"right"));
9948 break;
9949 case CTK_TEXT_WINDOW_TOP:
9950 ctk_css_node_add_class (win->css_node, g_quark_from_static_string (CTK_STYLE_CLASS_TOP"top"));
9951 break;
9952 case CTK_TEXT_WINDOW_BOTTOM:
9953 ctk_css_node_add_class (win->css_node, g_quark_from_static_string (CTK_STYLE_CLASS_BOTTOM"bottom"));
9954 break;
9955 default: /* no extra style class */ ;
9956 }
9957 }
9958 g_object_unref (win->css_node);
9959
9960 return win;
9961}
9962
9963static void
9964text_window_free (CtkTextWindow *win)
9965{
9966 if (win->window)
9967 text_window_unrealize (win);
9968
9969 ctk_css_node_set_parent (win->css_node, NULL((void*)0));
9970
9971 g_slice_free (CtkTextWindow, win)do { if (1) g_slice_free1 (sizeof (CtkTextWindow), (win)); else
(void) ((CtkTextWindow*) 0 == (win)); } while (0)
;
9972}
9973
9974static void
9975ctk_text_view_get_rendered_rect (CtkTextView *text_view,
9976 CdkRectangle *rect)
9977{
9978 CtkTextViewPrivate *priv = text_view->priv;
9979 CdkWindow *window;
9980 guint extra_w;
9981 guint extra_h;
9982
9983 _ctk_pixel_cache_get_extra_size (priv->pixel_cache, &extra_w, &extra_h);
9984
9985 window = ctk_text_view_get_window (text_view, CTK_TEXT_WINDOW_TEXT);
9986
9987 rect->x = ctk_adjustment_get_value (priv->hadjustment) - extra_w;
9988 rect->y = ctk_adjustment_get_value (priv->vadjustment) - extra_h - priv->top_border;
9989
9990 rect->height = cdk_window_get_height (window) + (extra_h * 2);
9991 rect->width = cdk_window_get_width (window) + (extra_w * 2);
9992}
9993
9994static void
9995ctk_text_view_queue_draw_region (CtkWidget *widget,
9996 const cairo_region_t *region)
9997{
9998 CtkTextView *text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
9999
10000 /* There is no way we can know if a region targets the
10001 not-currently-visible but in pixel cache region, so we
10002 always just invalidate the whole thing whenever the
10003 text view gets a queue draw. This doesn't normally happen
10004 in normal scrolling cases anyway. */
10005 _ctk_pixel_cache_invalidate (text_view->priv->pixel_cache, NULL((void*)0));
10006
10007 CTK_WIDGET_CLASS (ctk_text_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_text_view_parent_class)), ((ctk_widget_get_type ()))
))))
->queue_draw_region (widget, region);
10008}
10009
10010static void
10011text_window_invalidate_handler (CdkWindow *window,
10012 cairo_region_t *region)
10013{
10014 gpointer widget;
10015 CtkTextView *text_view;
10016 CtkTextViewPrivate *priv;
10017 int x, y;
10018
10019 cdk_window_get_user_data (window, &widget);
10020 text_view = CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
;
10021 priv = text_view->priv;
10022
10023 /* Scrolling will invalidate everything in the bin window,
10024 * but we already have it in the cache, so we can ignore that */
10025 if (priv->in_scroll)
10026 return;
10027
10028 x = priv->xoffset;
10029 y = priv->yoffset + priv->top_border;
10030
10031 cairo_region_translate (region, x, y);
10032 _ctk_pixel_cache_invalidate (priv->pixel_cache, region);
10033 cairo_region_translate (region, -x, -y);
10034}
10035
10036static void
10037text_window_realize (CtkTextWindow *win,
10038 CtkWidget *widget)
10039{
10040 CdkWindow *window;
10041 CdkWindowAttr attributes;
10042 gint attributes_mask;
10043 CdkDisplay *display;
10044 CdkCursor *cursor;
10045
10046 attributes.window_type = CDK_WINDOW_CHILD;
10047 attributes.x = win->allocation.x;
10048 attributes.y = win->allocation.y;
10049 attributes.width = win->allocation.width;
10050 attributes.height = win->allocation.height;
10051 attributes.wclass = CDK_INPUT_OUTPUT;
10052 attributes.visual = ctk_widget_get_visual (win->widget);
10053 attributes.event_mask = CDK_VISIBILITY_NOTIFY_MASK;
10054
10055 attributes_mask = CDK_WA_X | CDK_WA_Y | CDK_WA_VISUAL;
10056
10057 window = ctk_widget_get_window (widget);
10058
10059 win->window = cdk_window_new (window,
10060 &attributes, attributes_mask);
10061
10062 cdk_window_show (win->window);
10063 ctk_widget_register_window (win->widget, win->window);
10064 cdk_window_lower (win->window);
10065
10066 attributes.x = 0;
10067 attributes.y = 0;
10068 attributes.width = win->allocation.width;
10069 attributes.height = win->allocation.height;
10070 attributes.event_mask = ctk_widget_get_events (win->widget)
10071 | CDK_SCROLL_MASK
10072 | CDK_SMOOTH_SCROLL_MASK
10073 | CDK_KEY_PRESS_MASK
10074 | CDK_BUTTON_PRESS_MASK
10075 | CDK_BUTTON_RELEASE_MASK
10076 | CDK_POINTER_MOTION_MASK;
10077
10078 win->bin_window = cdk_window_new (win->window,
10079 &attributes,
10080 attributes_mask);
10081
10082 ctk_widget_register_window (win->widget, win->bin_window);
10083
10084 if (win->type == CTK_TEXT_WINDOW_TEXT)
10085 cdk_window_set_invalidate_handler (win->bin_window,
10086 text_window_invalidate_handler);
10087
10088 cdk_window_show (win->bin_window);
10089
10090 switch (win->type)
10091 {
10092 case CTK_TEXT_WINDOW_TEXT:
10093 if (ctk_widget_is_sensitive (widget))
10094 {
10095 display = cdk_window_get_display (window);
10096 cursor = cdk_cursor_new_from_name (display, "text");
10097 cdk_window_set_cursor (win->bin_window, cursor);
10098 g_clear_object (&cursor)do { _Static_assert (sizeof *((&cursor)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&cursor
))) _pp = ((&cursor)); __typeof__ (*((&cursor))) _ptr
= *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr)
; } while (0)
;
10099 }
10100
10101 ctk_im_context_set_client_window (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_view_get_type ()))))))
->priv->im_context,
10102 win->window);
10103 break;
10104 default:
10105 break;
10106 }
10107
10108 g_object_set_qdata (G_OBJECT (win->window)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win->window)), (((GType) ((20) << (2))))))))
,
10109 g_quark_from_static_string ("ctk-text-view-text-window"),
10110 win);
10111
10112 g_object_set_qdata (G_OBJECT (win->bin_window)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win->bin_window)), (((GType) ((20) << (2)))))))
)
,
10113 g_quark_from_static_string ("ctk-text-view-text-window"),
10114 win);
10115}
10116
10117static void
10118text_window_unrealize (CtkTextWindow *win)
10119{
10120 if (win->type == CTK_TEXT_WINDOW_TEXT)
10121 {
10122 ctk_im_context_set_client_window (CTK_TEXT_VIEW (win->widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win->widget)), ((ctk_text_view_get_type ()))))))
->priv->im_context,
10123 NULL((void*)0));
10124 }
10125
10126 ctk_widget_unregister_window (win->widget, win->window);
10127 ctk_widget_unregister_window (win->widget, win->bin_window);
10128 cdk_window_destroy (win->bin_window);
10129 cdk_window_destroy (win->window);
10130 win->window = NULL((void*)0);
10131 win->bin_window = NULL((void*)0);
10132}
10133
10134static void
10135text_window_size_allocate (CtkTextWindow *win,
10136 CdkRectangle *rect)
10137{
10138 win->allocation = *rect;
10139
10140 if (win->window)
10141 {
10142 cdk_window_move_resize (win->window,
10143 rect->x, rect->y,
10144 rect->width, rect->height);
10145
10146 cdk_window_resize (win->bin_window,
10147 rect->width, rect->height);
10148 }
10149}
10150
10151static void
10152text_window_scroll (CtkTextWindow *win,
10153 gint dx,
10154 gint dy)
10155{
10156 CtkTextView *view = CTK_TEXT_VIEW (win->widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win->widget)), ((ctk_text_view_get_type ()))))))
;
10157 CtkTextViewPrivate *priv = view->priv;
10158
10159 if (dx != 0 || dy != 0)
10160 {
10161 if (priv->selection_bubble)
10162 ctk_widget_hide (priv->selection_bubble);
10163 view->priv->in_scroll = TRUE(!(0));
10164 cdk_window_scroll (win->bin_window, dx, dy);
10165 view->priv->in_scroll = FALSE(0);
10166 }
10167}
10168
10169static void
10170text_window_invalidate_rect (CtkTextWindow *win,
10171 CdkRectangle *rect)
10172{
10173 CdkRectangle window_rect;
10174
10175 if (!win->bin_window)
10176 return;
10177
10178 ctk_text_view_buffer_to_window_coords (CTK_TEXT_VIEW (win->widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win->widget)), ((ctk_text_view_get_type ()))))))
,
10179 win->type,
10180 rect->x,
10181 rect->y,
10182 &window_rect.x,
10183 &window_rect.y);
10184
10185 window_rect.width = rect->width;
10186 window_rect.height = rect->height;
10187
10188 /* Adjust the rect as appropriate */
10189
10190 switch (win->type)
10191 {
10192 case CTK_TEXT_WINDOW_TEXT:
10193 break;
10194
10195 case CTK_TEXT_WINDOW_LEFT:
10196 case CTK_TEXT_WINDOW_RIGHT:
10197 window_rect.x = 0;
10198 window_rect.width = win->allocation.width;
10199 break;
10200
10201 case CTK_TEXT_WINDOW_TOP:
10202 case CTK_TEXT_WINDOW_BOTTOM:
10203 window_rect.y = 0;
10204 window_rect.height = win->allocation.height;
10205 break;
10206
10207 default:
10208 g_warning ("%s: bug!", G_STRFUNC((const char*) (__func__)));
10209 return;
10210 break;
10211 }
10212
10213 cdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE(0));
10214
10215#if 0
10216 {
10217 cairo_t *cr = cdk_cairo_create (win->bin_window);
10218 cdk_cairo_rectangle (cr, &window_rect);
10219 cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); /* red */
10220 cairo_fill (cr);
10221 cairo_destroy (cr);
10222 }
10223#endif
10224}
10225
10226static void
10227text_window_invalidate_cursors (CtkTextWindow *win)
10228{
10229 CtkTextView *text_view;
10230 CtkTextViewPrivate *priv;
10231 CtkTextIter iter;
10232 CdkRectangle strong;
10233 CdkRectangle weak;
10234 gboolean draw_arrow;
10235 gfloat cursor_aspect_ratio;
10236 gint stem_width;
10237 gint arrow_width;
10238
10239 text_view = CTK_TEXT_VIEW (win->widget)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win->widget)), ((ctk_text_view_get_type ()))))))
;
10240 priv = text_view->priv;
10241
10242 ctk_text_buffer_get_iter_at_mark (priv->buffer, &iter,
10243 ctk_text_buffer_get_insert (priv->buffer));
10244
10245 if (_ctk_text_layout_get_block_cursor (priv->layout, &strong))
10246 {
10247 text_window_invalidate_rect (win, &strong);
10248 return;
10249 }
10250
10251 ctk_text_layout_get_cursor_locations (priv->layout, &iter,
10252 &strong, &weak);
10253
10254 /* cursor width calculation as in ctkstylecontext.c:draw_insertion_cursor(),
10255 * ignoring the text direction be exposing both sides of the cursor
10256 */
10257
10258 draw_arrow = (strong.x != weak.x || strong.y != weak.y);
10259
10260 ctk_widget_style_get (win->widget,
10261 "cursor-aspect-ratio", &cursor_aspect_ratio,
10262 NULL((void*)0));
10263
10264 stem_width = strong.height * cursor_aspect_ratio + 1;
10265 arrow_width = stem_width + 1;
10266
10267 strong.width = stem_width;
10268
10269 /* round up to the next even number */
10270 if (stem_width & 1)
10271 stem_width++;
10272
10273 strong.x -= stem_width / 2;
10274 strong.width += stem_width;
10275
10276 if (draw_arrow)
10277 {
10278 strong.x -= arrow_width;
10279 strong.width += arrow_width * 2;
10280 }
10281
10282 text_window_invalidate_rect (win, &strong);
10283
10284 if (draw_arrow) /* == have weak */
10285 {
10286 stem_width = weak.height * cursor_aspect_ratio + 1;
10287 arrow_width = stem_width + 1;
10288
10289 weak.width = stem_width;
10290
10291 /* round up to the next even number */
10292 if (stem_width & 1)
10293 stem_width++;
10294
10295 weak.x -= stem_width / 2;
10296 weak.width += stem_width;
10297
10298 weak.x -= arrow_width;
10299 weak.width += arrow_width * 2;
10300
10301 text_window_invalidate_rect (win, &weak);
10302 }
10303}
10304
10305static gint
10306text_window_get_width (CtkTextWindow *win)
10307{
10308 return win->allocation.width;
10309}
10310
10311static gint
10312text_window_get_height (CtkTextWindow *win)
10313{
10314 return win->allocation.height;
10315}
10316
10317/* Windows */
10318
10319
10320/**
10321 * ctk_text_view_get_window:
10322 * @text_view: a #CtkTextView
10323 * @win: window to get
10324 *
10325 * Retrieves the #CdkWindow corresponding to an area of the text view;
10326 * possible windows include the overall widget window, child windows
10327 * on the left, right, top, bottom, and the window that displays the
10328 * text buffer. Windows are %NULL and nonexistent if their width or
10329 * height is 0, and are nonexistent before the widget has been
10330 * realized.
10331 *
10332 * Returns: (nullable) (transfer none): a #CdkWindow, or %NULL
10333 **/
10334CdkWindow*
10335ctk_text_view_get_window (CtkTextView *text_view,
10336 CtkTextWindowType win)
10337{
10338 CtkTextViewPrivate *priv = text_view->priv;
10339
10340 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (((void*)0)); } }
while (0)
;
10341
10342 switch (win)
10343 {
10344 case CTK_TEXT_WINDOW_WIDGET:
10345 return ctk_widget_get_window (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
10346 break;
10347
10348 case CTK_TEXT_WINDOW_TEXT:
10349 return priv->text_window->bin_window;
10350 break;
10351
10352 case CTK_TEXT_WINDOW_LEFT:
10353 if (priv->left_window)
10354 return priv->left_window->bin_window;
10355 else
10356 return NULL((void*)0);
10357 break;
10358
10359 case CTK_TEXT_WINDOW_RIGHT:
10360 if (priv->right_window)
10361 return priv->right_window->bin_window;
10362 else
10363 return NULL((void*)0);
10364 break;
10365
10366 case CTK_TEXT_WINDOW_TOP:
10367 if (priv->top_window)
10368 return priv->top_window->bin_window;
10369 else
10370 return NULL((void*)0);
10371 break;
10372
10373 case CTK_TEXT_WINDOW_BOTTOM:
10374 if (priv->bottom_window)
10375 return priv->bottom_window->bin_window;
10376 else
10377 return NULL((void*)0);
10378 break;
10379
10380 case CTK_TEXT_WINDOW_PRIVATE:
10381 g_warning ("%s: You can't get CTK_TEXT_WINDOW_PRIVATE, it has \"PRIVATE\" in the name because it is private.", G_STRFUNC((const char*) (__func__)));
10382 return NULL((void*)0);
10383 break;
10384 }
10385
10386 g_warning ("%s: Unknown CtkTextWindowType", G_STRFUNC((const char*) (__func__)));
10387 return NULL((void*)0);
10388}
10389
10390static CtkCssNode *
10391ctk_text_view_get_css_node (CtkTextView *text_view,
10392 CtkTextWindowType win)
10393{
10394 CtkTextViewPrivate *priv = text_view->priv;
10395
10396 switch (win)
10397 {
10398 case CTK_TEXT_WINDOW_WIDGET:
10399 return ctk_widget_get_css_node (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
10400
10401 case CTK_TEXT_WINDOW_TEXT:
10402 return priv->text_window->css_node;
10403
10404 case CTK_TEXT_WINDOW_LEFT:
10405 if (priv->left_window)
10406 return priv->left_window->css_node;
10407 break;
10408
10409 case CTK_TEXT_WINDOW_RIGHT:
10410 if (priv->right_window)
10411 return priv->right_window->css_node;
10412 break;
10413
10414 case CTK_TEXT_WINDOW_TOP:
10415 if (priv->top_window)
10416 return priv->top_window->css_node;
10417 break;
10418
10419 case CTK_TEXT_WINDOW_BOTTOM:
10420 if (priv->bottom_window)
10421 return priv->bottom_window->css_node;
10422 break;
10423
10424 default:
10425 break;
10426 }
10427
10428 return NULL((void*)0);
10429}
10430
10431/**
10432 * ctk_text_view_get_window_type:
10433 * @text_view: a #CtkTextView
10434 * @window: a window type
10435 *
10436 * Usually used to find out which window an event corresponds to.
10437 *
10438 * If you connect to an event signal on @text_view, this function
10439 * should be called on `event->window` to see which window it was.
10440 *
10441 * Returns: the window type.
10442 **/
10443CtkTextWindowType
10444ctk_text_view_get_window_type (CtkTextView *text_view,
10445 CdkWindow *window)
10446{
10447 CtkTextWindow *win;
10448
10449 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), CTK_TEXT_WINDOW_PRIVATE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (CTK_TEXT_WINDOW_PRIVATE
); } } while (0)
;
10450 g_return_val_if_fail (CDK_IS_WINDOW (window), CTK_TEXT_WINDOW_PRIVATE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((window)); GType __t = ((cdk_window_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__
)), "CDK_IS_WINDOW (window)"); return (CTK_TEXT_WINDOW_PRIVATE
); } } while (0)
;
10451
10452 if (window == ctk_widget_get_window (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
10453 return CTK_TEXT_WINDOW_WIDGET;
10454
10455 win = g_object_get_qdata (G_OBJECT (window)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), (((GType) ((20) << (2))))))))
,
10456 g_quark_try_string ("ctk-text-view-text-window"));
10457
10458 if (win)
10459 return win->type;
10460
10461 return CTK_TEXT_WINDOW_PRIVATE;
10462}
10463
10464static void
10465buffer_to_widget (CtkTextView *text_view,
10466 gint buffer_x,
10467 gint buffer_y,
10468 gint *window_x,
10469 gint *window_y)
10470{
10471 CtkTextViewPrivate *priv = text_view->priv;
10472
10473 if (window_x)
10474 {
10475 *window_x = buffer_x - priv->xoffset;
10476 *window_x += priv->text_window->allocation.x;
10477 }
10478
10479 if (window_y)
10480 {
10481 *window_y = buffer_y - priv->yoffset;
10482 *window_y += priv->text_window->allocation.y;
10483 }
10484}
10485
10486static void
10487widget_to_text_window (CtkTextWindow *win,
10488 gint widget_x,
10489 gint widget_y,
10490 gint *window_x,
10491 gint *window_y)
10492{
10493 if (window_x)
10494 *window_x = widget_x - win->allocation.x;
10495
10496 if (window_y)
10497 *window_y = widget_y - win->allocation.y;
10498}
10499
10500static void
10501buffer_to_text_window (CtkTextView *text_view,
10502 CtkTextWindow *win,
10503 gint buffer_x,
10504 gint buffer_y,
10505 gint *window_x,
10506 gint *window_y)
10507{
10508 if (win == NULL((void*)0))
10509 {
10510 g_warning ("Attempt to convert text buffer coordinates to coordinates "
10511 "for a nonexistent or private child window of CtkTextView");
10512 return;
10513 }
10514
10515 buffer_to_widget (text_view,
10516 buffer_x, buffer_y,
10517 window_x, window_y);
10518
10519 widget_to_text_window (win,
10520 window_x ? *window_x : 0,
10521 window_y ? *window_y : 0,
10522 window_x,
10523 window_y);
10524}
10525
10526/**
10527 * ctk_text_view_buffer_to_window_coords:
10528 * @text_view: a #CtkTextView
10529 * @win: a #CtkTextWindowType, except %CTK_TEXT_WINDOW_PRIVATE
10530 * @buffer_x: buffer x coordinate
10531 * @buffer_y: buffer y coordinate
10532 * @window_x: (out) (allow-none): window x coordinate return location or %NULL
10533 * @window_y: (out) (allow-none): window y coordinate return location or %NULL
10534 *
10535 * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
10536 * @win, and stores the result in (@window_x, @window_y).
10537 *
10538 * Note that you can’t convert coordinates for a nonexisting window (see
10539 * ctk_text_view_set_border_window_size()).
10540 **/
10541void
10542ctk_text_view_buffer_to_window_coords (CtkTextView *text_view,
10543 CtkTextWindowType win,
10544 gint buffer_x,
10545 gint buffer_y,
10546 gint *window_x,
10547 gint *window_y)
10548{
10549 CtkTextViewPrivate *priv = text_view->priv;
10550
10551 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
10552 g_return_if_fail (win != CTK_TEXT_WINDOW_PRIVATE)do { if ((win != CTK_TEXT_WINDOW_PRIVATE)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "win != CTK_TEXT_WINDOW_PRIVATE"
); return; } } while (0)
;
10553
10554 switch (win)
10555 {
10556 case CTK_TEXT_WINDOW_WIDGET:
10557 buffer_to_widget (text_view,
10558 buffer_x, buffer_y,
10559 window_x, window_y);
10560 break;
10561
10562 case CTK_TEXT_WINDOW_TEXT:
10563 if (window_x)
10564 *window_x = buffer_x - priv->xoffset;
10565 if (window_y)
10566 *window_y = buffer_y - priv->yoffset;
10567 break;
10568
10569 case CTK_TEXT_WINDOW_LEFT:
10570 buffer_to_text_window (text_view,
10571 priv->left_window,
10572 buffer_x, buffer_y,
10573 window_x, window_y);
10574 break;
10575
10576 case CTK_TEXT_WINDOW_RIGHT:
10577 buffer_to_text_window (text_view,
10578 priv->right_window,
10579 buffer_x, buffer_y,
10580 window_x, window_y);
10581 break;
10582
10583 case CTK_TEXT_WINDOW_TOP:
10584 buffer_to_text_window (text_view,
10585 priv->top_window,
10586 buffer_x, buffer_y,
10587 window_x, window_y);
10588 break;
10589
10590 case CTK_TEXT_WINDOW_BOTTOM:
10591 buffer_to_text_window (text_view,
10592 priv->bottom_window,
10593 buffer_x, buffer_y,
10594 window_x, window_y);
10595 break;
10596
10597 case CTK_TEXT_WINDOW_PRIVATE:
10598 g_warning ("%s: can't get coords for private windows", G_STRFUNC((const char*) (__func__)));
10599 break;
10600
10601 default:
10602 g_warning ("%s: Unknown CtkTextWindowType", G_STRFUNC((const char*) (__func__)));
10603 break;
10604 }
10605}
10606
10607static void
10608widget_to_buffer (CtkTextView *text_view,
10609 gint widget_x,
10610 gint widget_y,
10611 gint *buffer_x,
10612 gint *buffer_y)
10613{
10614 CtkTextViewPrivate *priv = text_view->priv;
10615
10616 if (buffer_x)
10617 {
10618 *buffer_x = widget_x + priv->xoffset;
10619 *buffer_x -= priv->text_window->allocation.x;
10620 }
10621
10622 if (buffer_y)
10623 {
10624 *buffer_y = widget_y + priv->yoffset;
10625 *buffer_y -= priv->text_window->allocation.y;
10626 }
10627}
10628
10629static void
10630text_window_to_widget (CtkTextWindow *win,
10631 gint window_x,
10632 gint window_y,
10633 gint *widget_x,
10634 gint *widget_y)
10635{
10636 if (widget_x)
10637 *widget_x = window_x + win->allocation.x;
10638
10639 if (widget_y)
10640 *widget_y = window_y + win->allocation.y;
10641}
10642
10643static void
10644text_window_to_buffer (CtkTextView *text_view,
10645 CtkTextWindow *win,
10646 gint window_x,
10647 gint window_y,
10648 gint *buffer_x,
10649 gint *buffer_y)
10650{
10651 if (win == NULL((void*)0))
10652 {
10653 g_warning ("Attempt to convert CtkTextView buffer coordinates into "
10654 "coordinates for a nonexistent child window.");
10655 return;
10656 }
10657
10658 text_window_to_widget (win,
10659 window_x,
10660 window_y,
10661 buffer_x,
10662 buffer_y);
10663
10664 widget_to_buffer (text_view,
10665 buffer_x ? *buffer_x : 0,
10666 buffer_y ? *buffer_y : 0,
10667 buffer_x,
10668 buffer_y);
10669}
10670
10671/**
10672 * ctk_text_view_window_to_buffer_coords:
10673 * @text_view: a #CtkTextView
10674 * @win: a #CtkTextWindowType except %CTK_TEXT_WINDOW_PRIVATE
10675 * @window_x: window x coordinate
10676 * @window_y: window y coordinate
10677 * @buffer_x: (out) (allow-none): buffer x coordinate return location or %NULL
10678 * @buffer_y: (out) (allow-none): buffer y coordinate return location or %NULL
10679 *
10680 * Converts coordinates on the window identified by @win to buffer
10681 * coordinates, storing the result in (@buffer_x,@buffer_y).
10682 *
10683 * Note that you can’t convert coordinates for a nonexisting window (see
10684 * ctk_text_view_set_border_window_size()).
10685 **/
10686void
10687ctk_text_view_window_to_buffer_coords (CtkTextView *text_view,
10688 CtkTextWindowType win,
10689 gint window_x,
10690 gint window_y,
10691 gint *buffer_x,
10692 gint *buffer_y)
10693{
10694 CtkTextViewPrivate *priv = text_view->priv;
10695
10696 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
10697 g_return_if_fail (win != CTK_TEXT_WINDOW_PRIVATE)do { if ((win != CTK_TEXT_WINDOW_PRIVATE)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "win != CTK_TEXT_WINDOW_PRIVATE"
); return; } } while (0)
;
10698
10699 switch (win)
10700 {
10701 case CTK_TEXT_WINDOW_WIDGET:
10702 widget_to_buffer (text_view,
10703 window_x, window_y,
10704 buffer_x, buffer_y);
10705 break;
10706
10707 case CTK_TEXT_WINDOW_TEXT:
10708 if (buffer_x)
10709 *buffer_x = window_x + priv->xoffset;
10710 if (buffer_y)
10711 *buffer_y = window_y + priv->yoffset;
10712 break;
10713
10714 case CTK_TEXT_WINDOW_LEFT:
10715 text_window_to_buffer (text_view,
10716 priv->left_window,
10717 window_x, window_y,
10718 buffer_x, buffer_y);
10719 break;
10720
10721 case CTK_TEXT_WINDOW_RIGHT:
10722 text_window_to_buffer (text_view,
10723 priv->right_window,
10724 window_x, window_y,
10725 buffer_x, buffer_y);
10726 break;
10727
10728 case CTK_TEXT_WINDOW_TOP:
10729 text_window_to_buffer (text_view,
10730 priv->top_window,
10731 window_x, window_y,
10732 buffer_x, buffer_y);
10733 break;
10734
10735 case CTK_TEXT_WINDOW_BOTTOM:
10736 text_window_to_buffer (text_view,
10737 priv->bottom_window,
10738 window_x, window_y,
10739 buffer_x, buffer_y);
10740 break;
10741
10742 case CTK_TEXT_WINDOW_PRIVATE:
10743 g_warning ("%s: can't get coords for private windows", G_STRFUNC((const char*) (__func__)));
10744 break;
10745
10746 default:
10747 g_warning ("%s: Unknown CtkTextWindowType", G_STRFUNC((const char*) (__func__)));
10748 break;
10749 }
10750}
10751
10752static void
10753set_window_width (CtkTextView *text_view,
10754 gint width,
10755 CtkTextWindowType type,
10756 CtkTextWindow **winp)
10757{
10758 if (width == 0)
10759 {
10760 if (*winp)
10761 {
10762 text_window_free (*winp);
10763 *winp = NULL((void*)0);
10764 ctk_widget_queue_resize (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
10765 }
10766 }
10767 else
10768 {
10769 if (*winp == NULL((void*)0))
10770 {
10771 *winp = text_window_new (type, CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
, width, 0);
10772 /* if the widget is already realized we need to realize the child manually */
10773 if (ctk_widget_get_realized (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
10774 text_window_realize (*winp, CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
10775 update_node_ordering (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
10776 }
10777 else
10778 {
10779 if ((*winp)->requisition.width == width)
10780 return;
10781
10782 (*winp)->requisition.width = width;
10783 }
10784
10785 ctk_widget_queue_resize (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
10786 }
10787}
10788
10789
10790static void
10791set_window_height (CtkTextView *text_view,
10792 gint height,
10793 CtkTextWindowType type,
10794 CtkTextWindow **winp)
10795{
10796 if (height == 0)
10797 {
10798 if (*winp)
10799 {
10800 text_window_free (*winp);
10801 *winp = NULL((void*)0);
10802 ctk_widget_queue_resize (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
10803 }
10804 }
10805 else
10806 {
10807 if (*winp == NULL((void*)0))
10808 {
10809 *winp = text_window_new (type, CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
, 0, height);
10810
10811 /* if the widget is already realized we need to realize the child manually */
10812 if (ctk_widget_get_realized (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
10813 text_window_realize (*winp, CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
10814 update_node_ordering (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
10815 }
10816 else
10817 {
10818 if ((*winp)->requisition.height == height)
10819 return;
10820
10821 (*winp)->requisition.height = height;
10822 }
10823
10824 ctk_widget_queue_resize (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
10825 }
10826}
10827
10828/**
10829 * ctk_text_view_set_border_window_size:
10830 * @text_view: a #CtkTextView
10831 * @type: window to affect
10832 * @size: width or height of the window
10833 *
10834 * Sets the width of %CTK_TEXT_WINDOW_LEFT or %CTK_TEXT_WINDOW_RIGHT,
10835 * or the height of %CTK_TEXT_WINDOW_TOP or %CTK_TEXT_WINDOW_BOTTOM.
10836 * Automatically destroys the corresponding window if the size is set
10837 * to 0, and creates the window if the size is set to non-zero. This
10838 * function can only be used for the “border windows”, and it won’t
10839 * work with %CTK_TEXT_WINDOW_WIDGET, %CTK_TEXT_WINDOW_TEXT, or
10840 * %CTK_TEXT_WINDOW_PRIVATE.
10841 **/
10842void
10843ctk_text_view_set_border_window_size (CtkTextView *text_view,
10844 CtkTextWindowType type,
10845 gint size)
10846{
10847 CtkTextViewPrivate *priv = text_view->priv;
10848
10849 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
10850 g_return_if_fail (type != CTK_TEXT_WINDOW_PRIVATE)do { if ((type != CTK_TEXT_WINDOW_PRIVATE)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "type != CTK_TEXT_WINDOW_PRIVATE"
); return; } } while (0)
;
10851 g_return_if_fail (size >= 0)do { if ((size >= 0)) { } else { g_return_if_fail_warning (
"Ctk", ((const char*) (__func__)), "size >= 0"); return; }
} while (0)
;
10852
10853 switch (type)
10854 {
10855 case CTK_TEXT_WINDOW_LEFT:
10856 set_window_width (text_view, size, CTK_TEXT_WINDOW_LEFT,
10857 &priv->left_window);
10858 break;
10859
10860 case CTK_TEXT_WINDOW_RIGHT:
10861 set_window_width (text_view, size, CTK_TEXT_WINDOW_RIGHT,
10862 &priv->right_window);
10863 break;
10864
10865 case CTK_TEXT_WINDOW_TOP:
10866 set_window_height (text_view, size, CTK_TEXT_WINDOW_TOP,
10867 &priv->top_window);
10868 break;
10869
10870 case CTK_TEXT_WINDOW_BOTTOM:
10871 set_window_height (text_view, size, CTK_TEXT_WINDOW_BOTTOM,
10872 &priv->bottom_window);
10873 break;
10874
10875 default:
10876 g_warning ("Can only set size of left/right/top/bottom border windows with ctk_text_view_set_border_window_size()");
10877 break;
10878 }
10879}
10880
10881/**
10882 * ctk_text_view_get_border_window_size:
10883 * @text_view: a #CtkTextView
10884 * @type: window to return size from
10885 *
10886 * Gets the width of the specified border window. See
10887 * ctk_text_view_set_border_window_size().
10888 *
10889 * Returns: width of window
10890 **/
10891gint
10892ctk_text_view_get_border_window_size (CtkTextView *text_view,
10893 CtkTextWindowType type)
10894{
10895 CtkTextViewPrivate *priv = text_view->priv;
10896
10897 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (0); } } while (0
)
;
10898
10899 switch (type)
10900 {
10901 case CTK_TEXT_WINDOW_LEFT:
10902 if (priv->left_window)
10903 return priv->left_window->requisition.width;
10904 break;
10905
10906 case CTK_TEXT_WINDOW_RIGHT:
10907 if (priv->right_window)
10908 return priv->right_window->requisition.width;
10909 break;
10910
10911 case CTK_TEXT_WINDOW_TOP:
10912 if (priv->top_window)
10913 return priv->top_window->requisition.height;
10914 break;
10915
10916 case CTK_TEXT_WINDOW_BOTTOM:
10917 if (priv->bottom_window)
10918 return priv->bottom_window->requisition.height;
10919 break;
10920
10921 default:
10922 g_warning ("Can only get size of left/right/top/bottom border windows with ctk_text_view_get_border_window_size()");
10923 break;
10924 }
10925
10926 return 0;
10927}
10928
10929/*
10930 * Child widgets
10931 */
10932
10933static CtkTextViewChild*
10934text_view_child_new_anchored (CtkWidget *child,
10935 CtkTextChildAnchor *anchor,
10936 CtkTextLayout *layout)
10937{
10938 CtkTextViewChild *vc;
10939
10940 vc = g_slice_new (CtkTextViewChild)((CtkTextViewChild*) g_slice_alloc (sizeof (CtkTextViewChild)
))
;
10941
10942 vc->type = CTK_TEXT_WINDOW_PRIVATE;
10943 vc->widget = child;
10944 vc->anchor = anchor;
10945
10946 vc->from_top_of_line = 0;
10947 vc->from_left_of_buffer = 0;
10948
10949 g_object_ref (vc->widget)((__typeof__ (vc->widget)) (g_object_ref) (vc->widget));
10950 g_object_ref (vc->anchor)((__typeof__ (vc->anchor)) (g_object_ref) (vc->anchor));
10951
10952 g_object_set_qdata (G_OBJECT (child)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), (((GType) ((20) << (2))))))))
, quark_text_view_child, vc);
10953
10954 ctk_text_child_anchor_register_child (anchor, child, layout);
10955
10956 return vc;
10957}
10958
10959static CtkTextViewChild*
10960text_view_child_new_window (CtkWidget *child,
10961 CtkTextWindowType type,
10962 gint x,
10963 gint y)
10964{
10965 CtkTextViewChild *vc;
10966
10967 vc = g_slice_new (CtkTextViewChild)((CtkTextViewChild*) g_slice_alloc (sizeof (CtkTextViewChild)
))
;
10968
10969 vc->widget = child;
10970 vc->anchor = NULL((void*)0);
10971
10972 vc->from_top_of_line = 0;
10973 vc->from_left_of_buffer = 0;
10974
10975 g_object_ref (vc->widget)((__typeof__ (vc->widget)) (g_object_ref) (vc->widget));
10976
10977 vc->type = type;
10978 vc->x = x;
10979 vc->y = y;
10980
10981 g_object_set_qdata (G_OBJECT (child)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), (((GType) ((20) << (2))))))))
, quark_text_view_child, vc);
10982
10983 return vc;
10984}
10985
10986static void
10987text_view_child_free (CtkTextViewChild *child)
10988{
10989 g_object_set_qdata (G_OBJECT (child->widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child->widget)), (((GType) ((20) << (2))))))))
, quark_text_view_child, NULL((void*)0));
10990
10991 if (child->anchor)
10992 {
10993 ctk_text_child_anchor_unregister_child (child->anchor,
10994 child->widget);
10995 g_object_unref (child->anchor);
10996 }
10997
10998 g_object_unref (child->widget);
10999
11000 g_slice_free (CtkTextViewChild, child)do { if (1) g_slice_free1 (sizeof (CtkTextViewChild), (child)
); else (void) ((CtkTextViewChild*) 0 == (child)); } while (0
)
;
11001}
11002
11003static void
11004text_view_child_set_parent_window (CtkTextView *text_view,
11005 CtkTextViewChild *vc)
11006{
11007 if (vc->anchor)
11008 ctk_widget_set_parent_window (vc->widget,
11009 text_view->priv->text_window->bin_window);
11010 else
11011 {
11012 CdkWindow *window;
11013 window = ctk_text_view_get_window (text_view,
11014 vc->type);
11015 ctk_widget_set_parent_window (vc->widget, window);
11016 }
11017}
11018
11019static void
11020add_child (CtkTextView *text_view,
11021 CtkTextViewChild *vc)
11022{
11023 CtkCssNode *parent;
11024
11025 text_view->priv->children = g_slist_prepend (text_view->priv->children, vc);
11026
11027 if (ctk_widget_get_realized (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
11028 text_view_child_set_parent_window (text_view, vc);
11029
11030 parent = ctk_text_view_get_css_node (text_view, vc->type);
11031 if (parent == NULL((void*)0))
11032 parent = ctk_widget_get_css_node (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
11033
11034 ctk_css_node_set_parent (ctk_widget_get_css_node (vc->widget), parent);
11035
11036 ctk_widget_set_parent (vc->widget, CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
11037}
11038
11039/**
11040 * ctk_text_view_add_child_at_anchor:
11041 * @text_view: a #CtkTextView
11042 * @child: a #CtkWidget
11043 * @anchor: a #CtkTextChildAnchor in the #CtkTextBuffer for @text_view
11044 *
11045 * Adds a child widget in the text buffer, at the given @anchor.
11046 **/
11047void
11048ctk_text_view_add_child_at_anchor (CtkTextView *text_view,
11049 CtkWidget *child,
11050 CtkTextChildAnchor *anchor)
11051{
11052 CtkTextViewChild *vc;
11053
11054 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
11055 g_return_if_fail (CTK_IS_WIDGET (child))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((child)); GType __t = ((ctk_widget_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_WIDGET (child)"); return; } } while (0)
;
11056 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)
;
11057 g_return_if_fail (ctk_widget_get_parent (child) == NULL)do { if ((ctk_widget_get_parent (child) == ((void*)0))) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "ctk_widget_get_parent (child) == NULL"); return; } } while
(0)
;
11058
11059 ctk_text_view_ensure_layout (text_view);
11060
11061 vc = text_view_child_new_anchored (child, anchor,
11062 text_view->priv->layout);
11063
11064 add_child (text_view, vc);
11065
11066 g_assert (vc->widget == child)do { if (vc->widget == child) ; else g_assertion_message_expr
("Ctk", "ctktextview.c", 11066, ((const char*) (__func__)), "vc->widget == child"
); } while (0)
;
11067 g_assert (ctk_widget_get_parent (child) == CTK_WIDGET (text_view))do { if (ctk_widget_get_parent (child) == ((((CtkWidget*) (void
*) g_type_check_instance_cast ((GTypeInstance*) ((text_view)
), ((ctk_widget_get_type ()))))))) ; else g_assertion_message_expr
("Ctk", "ctktextview.c", 11067, ((const char*) (__func__)), "ctk_widget_get_parent (child) == CTK_WIDGET (text_view)"
); } while (0)
;
11068}
11069
11070/**
11071 * ctk_text_view_add_child_in_window:
11072 * @text_view: a #CtkTextView
11073 * @child: a #CtkWidget
11074 * @which_window: which window the child should appear in
11075 * @xpos: X position of child in window coordinates
11076 * @ypos: Y position of child in window coordinates
11077 *
11078 * Adds a child at fixed coordinates in one of the text widget's
11079 * windows.
11080 *
11081 * The window must have nonzero size (see
11082 * ctk_text_view_set_border_window_size()). Note that the child
11083 * coordinates are given relative to scrolling. When
11084 * placing a child in #CTK_TEXT_WINDOW_WIDGET, scrolling is
11085 * irrelevant, the child floats above all scrollable areas. But when
11086 * placing a child in one of the scrollable windows (border windows or
11087 * text window) it will move with the scrolling as needed.
11088 */
11089void
11090ctk_text_view_add_child_in_window (CtkTextView *text_view,
11091 CtkWidget *child,
11092 CtkTextWindowType which_window,
11093 gint xpos,
11094 gint ypos)
11095{
11096 CtkTextViewChild *vc;
11097
11098 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
11099 g_return_if_fail (CTK_IS_WIDGET (child))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((child)); GType __t = ((ctk_widget_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_WIDGET (child)"); return; } } while (0)
;
11100 g_return_if_fail (ctk_widget_get_parent (child) == NULL)do { if ((ctk_widget_get_parent (child) == ((void*)0))) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "ctk_widget_get_parent (child) == NULL"); return; } } while
(0)
;
11101
11102 vc = text_view_child_new_window (child, which_window,
11103 xpos, ypos);
11104
11105 add_child (text_view, vc);
11106
11107 g_assert (vc->widget == child)do { if (vc->widget == child) ; else g_assertion_message_expr
("Ctk", "ctktextview.c", 11107, ((const char*) (__func__)), "vc->widget == child"
); } while (0)
;
11108 g_assert (ctk_widget_get_parent (child) == CTK_WIDGET (text_view))do { if (ctk_widget_get_parent (child) == ((((CtkWidget*) (void
*) g_type_check_instance_cast ((GTypeInstance*) ((text_view)
), ((ctk_widget_get_type ()))))))) ; else g_assertion_message_expr
("Ctk", "ctktextview.c", 11108, ((const char*) (__func__)), "ctk_widget_get_parent (child) == CTK_WIDGET (text_view)"
); } while (0)
;
11109}
11110
11111/**
11112 * ctk_text_view_move_child:
11113 * @text_view: a #CtkTextView
11114 * @child: child widget already added to the text view
11115 * @xpos: new X position in window coordinates
11116 * @ypos: new Y position in window coordinates
11117 *
11118 * Updates the position of a child, as for ctk_text_view_add_child_in_window().
11119 **/
11120void
11121ctk_text_view_move_child (CtkTextView *text_view,
11122 CtkWidget *child,
11123 gint xpos,
11124 gint ypos)
11125{
11126 CtkTextViewChild *vc;
11127
11128 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
11129 g_return_if_fail (CTK_IS_WIDGET (child))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((child)); GType __t = ((ctk_widget_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_WIDGET (child)"); return; } } while (0)
;
11130 g_return_if_fail (ctk_widget_get_parent (child) == CTK_WIDGET (text_view))do { if ((ctk_widget_get_parent (child) == ((((CtkWidget*) (void
*) g_type_check_instance_cast ((GTypeInstance*) ((text_view)
), ((ctk_widget_get_type ())))))))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "ctk_widget_get_parent (child) == CTK_WIDGET (text_view)"
); return; } } while (0)
;
11131
11132 vc = g_object_get_qdata (G_OBJECT (child)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), (((GType) ((20) << (2))))))))
, quark_text_view_child);
11133
11134 g_assert (vc != NULL)do { if (vc != ((void*)0)) ; else g_assertion_message_expr ("Ctk"
, "ctktextview.c", 11134, ((const char*) (__func__)), "vc != NULL"
); } while (0)
;
11135
11136 if (vc->x == xpos &&
11137 vc->y == ypos)
11138 return;
11139
11140 vc->x = xpos;
11141 vc->y = ypos;
11142
11143 if (ctk_widget_get_visible (child) &&
11144 ctk_widget_get_visible (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
))
11145 ctk_widget_queue_resize (child);
11146}
11147
11148
11149/* Iterator operations */
11150
11151/**
11152 * ctk_text_view_forward_display_line:
11153 * @text_view: a #CtkTextView
11154 * @iter: a #CtkTextIter
11155 *
11156 * Moves the given @iter forward by one display (wrapped) line.
11157 * A display line is different from a paragraph. Paragraphs are
11158 * separated by newlines or other paragraph separator characters.
11159 * Display lines are created by line-wrapping a paragraph. If
11160 * wrapping is turned off, display lines and paragraphs will be the
11161 * same. Display lines are divided differently for each view, since
11162 * they depend on the view’s width; paragraphs are the same in all
11163 * views, since they depend on the contents of the #CtkTextBuffer.
11164 *
11165 * Returns: %TRUE if @iter was moved and is not on the end iterator
11166 **/
11167gboolean
11168ctk_text_view_forward_display_line (CtkTextView *text_view,
11169 CtkTextIter *iter)
11170{
11171 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
11172 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)
;
11173
11174 ctk_text_view_ensure_layout (text_view);
11175
11176 return ctk_text_layout_move_iter_to_next_line (text_view->priv->layout, iter);
11177}
11178
11179/**
11180 * ctk_text_view_backward_display_line:
11181 * @text_view: a #CtkTextView
11182 * @iter: a #CtkTextIter
11183 *
11184 * Moves the given @iter backward by one display (wrapped) line.
11185 * A display line is different from a paragraph. Paragraphs are
11186 * separated by newlines or other paragraph separator characters.
11187 * Display lines are created by line-wrapping a paragraph. If
11188 * wrapping is turned off, display lines and paragraphs will be the
11189 * same. Display lines are divided differently for each view, since
11190 * they depend on the view’s width; paragraphs are the same in all
11191 * views, since they depend on the contents of the #CtkTextBuffer.
11192 *
11193 * Returns: %TRUE if @iter was moved and is not on the end iterator
11194 **/
11195gboolean
11196ctk_text_view_backward_display_line (CtkTextView *text_view,
11197 CtkTextIter *iter)
11198{
11199 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
11200 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)
;
11201
11202 ctk_text_view_ensure_layout (text_view);
11203
11204 return ctk_text_layout_move_iter_to_previous_line (text_view->priv->layout, iter);
11205}
11206
11207/**
11208 * ctk_text_view_forward_display_line_end:
11209 * @text_view: a #CtkTextView
11210 * @iter: a #CtkTextIter
11211 *
11212 * Moves the given @iter forward to the next display line end.
11213 * A display line is different from a paragraph. Paragraphs are
11214 * separated by newlines or other paragraph separator characters.
11215 * Display lines are created by line-wrapping a paragraph. If
11216 * wrapping is turned off, display lines and paragraphs will be the
11217 * same. Display lines are divided differently for each view, since
11218 * they depend on the view’s width; paragraphs are the same in all
11219 * views, since they depend on the contents of the #CtkTextBuffer.
11220 *
11221 * Returns: %TRUE if @iter was moved and is not on the end iterator
11222 **/
11223gboolean
11224ctk_text_view_forward_display_line_end (CtkTextView *text_view,
11225 CtkTextIter *iter)
11226{
11227 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
11228 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)
;
11229
11230 ctk_text_view_ensure_layout (text_view);
11231
11232 return ctk_text_layout_move_iter_to_line_end (text_view->priv->layout, iter, 1);
11233}
11234
11235/**
11236 * ctk_text_view_backward_display_line_start:
11237 * @text_view: a #CtkTextView
11238 * @iter: a #CtkTextIter
11239 *
11240 * Moves the given @iter backward to the next display line start.
11241 * A display line is different from a paragraph. Paragraphs are
11242 * separated by newlines or other paragraph separator characters.
11243 * Display lines are created by line-wrapping a paragraph. If
11244 * wrapping is turned off, display lines and paragraphs will be the
11245 * same. Display lines are divided differently for each view, since
11246 * they depend on the view’s width; paragraphs are the same in all
11247 * views, since they depend on the contents of the #CtkTextBuffer.
11248 *
11249 * Returns: %TRUE if @iter was moved and is not on the end iterator
11250 **/
11251gboolean
11252ctk_text_view_backward_display_line_start (CtkTextView *text_view,
11253 CtkTextIter *iter)
11254{
11255 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
11256 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)
;
11257
11258 ctk_text_view_ensure_layout (text_view);
11259
11260 return ctk_text_layout_move_iter_to_line_end (text_view->priv->layout, iter, -1);
11261}
11262
11263/**
11264 * ctk_text_view_starts_display_line:
11265 * @text_view: a #CtkTextView
11266 * @iter: a #CtkTextIter
11267 *
11268 * Determines whether @iter is at the start of a display line.
11269 * See ctk_text_view_forward_display_line() for an explanation of
11270 * display lines vs. paragraphs.
11271 *
11272 * Returns: %TRUE if @iter begins a wrapped line
11273 **/
11274gboolean
11275ctk_text_view_starts_display_line (CtkTextView *text_view,
11276 const CtkTextIter *iter)
11277{
11278 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
11279 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)
;
11280
11281 ctk_text_view_ensure_layout (text_view);
11282
11283 return ctk_text_layout_iter_starts_line (text_view->priv->layout, iter);
11284}
11285
11286/**
11287 * ctk_text_view_move_visually:
11288 * @text_view: a #CtkTextView
11289 * @iter: a #CtkTextIter
11290 * @count: number of characters to move (negative moves left,
11291 * positive moves right)
11292 *
11293 * Move the iterator a given number of characters visually, treating
11294 * it as the strong cursor position. If @count is positive, then the
11295 * new strong cursor position will be @count positions to the right of
11296 * the old cursor position. If @count is negative then the new strong
11297 * cursor position will be @count positions to the left of the old
11298 * cursor position.
11299 *
11300 * In the presence of bi-directional text, the correspondence
11301 * between logical and visual order will depend on the direction
11302 * of the current run, and there may be jumps when the cursor
11303 * is moved off of the end of a run.
11304 *
11305 * Returns: %TRUE if @iter moved and is not on the end iterator
11306 **/
11307gboolean
11308ctk_text_view_move_visually (CtkTextView *text_view,
11309 CtkTextIter *iter,
11310 gint count)
11311{
11312 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
11313 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)
;
11314
11315 ctk_text_view_ensure_layout (text_view);
11316
11317 return ctk_text_layout_move_iter_visually (text_view->priv->layout, iter, count);
11318}
11319
11320/**
11321 * ctk_text_view_set_input_purpose:
11322 * @text_view: a #CtkTextView
11323 * @purpose: the purpose
11324 *
11325 * Sets the #CtkTextView:input-purpose property which
11326 * can be used by on-screen keyboards and other input
11327 * methods to adjust their behaviour.
11328 *
11329 * Since: 3.6
11330 */
11331
11332void
11333ctk_text_view_set_input_purpose (CtkTextView *text_view,
11334 CtkInputPurpose purpose)
11335
11336{
11337 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
11338
11339 if (ctk_text_view_get_input_purpose (text_view) != purpose)
11340 {
11341 g_object_set (G_OBJECT (text_view->priv->im_context)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view->priv->im_context)), (((GType) ((20) <<
(2))))))))
,
11342 "input-purpose", purpose,
11343 NULL((void*)0));
11344
11345 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "input-purpose");
11346 }
11347}
11348
11349/**
11350 * ctk_text_view_get_input_purpose:
11351 * @text_view: a #CtkTextView
11352 *
11353 * Gets the value of the #CtkTextView:input-purpose property.
11354 *
11355 * Since: 3.6
11356 */
11357
11358CtkInputPurpose
11359ctk_text_view_get_input_purpose (CtkTextView *text_view)
11360{
11361 CtkInputPurpose purpose;
11362
11363 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), CTK_INPUT_PURPOSE_FREE_FORM)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (CTK_INPUT_PURPOSE_FREE_FORM
); } } while (0)
;
11364
11365 g_object_get (G_OBJECT (text_view->priv->im_context)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view->priv->im_context)), (((GType) ((20) <<
(2))))))))
,
11366 "input-purpose", &purpose,
11367 NULL((void*)0));
11368
11369 return purpose;
11370}
11371
11372/**
11373 * ctk_text_view_set_input_hints:
11374 * @text_view: a #CtkTextView
11375 * @hints: the hints
11376 *
11377 * Sets the #CtkTextView:input-hints property, which
11378 * allows input methods to fine-tune their behaviour.
11379 *
11380 * Since: 3.6
11381 */
11382
11383void
11384ctk_text_view_set_input_hints (CtkTextView *text_view,
11385 CtkInputHints hints)
11386
11387{
11388 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
11389
11390 if (ctk_text_view_get_input_hints (text_view) != hints)
11391 {
11392 g_object_set (G_OBJECT (text_view->priv->im_context)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view->priv->im_context)), (((GType) ((20) <<
(2))))))))
,
11393 "input-hints", hints,
11394 NULL((void*)0));
11395
11396 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "input-hints");
11397 }
11398}
11399
11400/**
11401 * ctk_text_view_get_input_hints:
11402 * @text_view: a #CtkTextView
11403 *
11404 * Gets the value of the #CtkTextView:input-hints property.
11405 *
11406 * Since: 3.6
11407 */
11408
11409CtkInputHints
11410ctk_text_view_get_input_hints (CtkTextView *text_view)
11411{
11412 CtkInputHints hints;
11413
11414 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), CTK_INPUT_HINT_NONE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return (CTK_INPUT_HINT_NONE
); } } while (0)
;
11415
11416 g_object_get (G_OBJECT (text_view->priv->im_context)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view->priv->im_context)), (((GType) ((20) <<
(2))))))))
,
11417 "input-hints", &hints,
11418 NULL((void*)0));
11419
11420 return hints;
11421}
11422
11423/**
11424 * ctk_text_view_set_monospace:
11425 * @text_view: a #CtkTextView
11426 * @monospace: %TRUE to request monospace styling
11427 *
11428 * Sets the #CtkTextView:monospace property, which
11429 * indicates that the text view should use monospace
11430 * fonts.
11431 *
11432 * Since: 3.16
11433 */
11434void
11435ctk_text_view_set_monospace (CtkTextView *text_view,
11436 gboolean monospace)
11437{
11438 CtkStyleContext *context;
11439 gboolean has_monospace;
11440
11441 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return; } } while (0)
;
11442
11443 context = ctk_widget_get_style_context (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
11444 has_monospace = ctk_style_context_has_class (context, CTK_STYLE_CLASS_MONOSPACE"monospace");
11445
11446 if (has_monospace != monospace)
11447 {
11448 if (monospace)
11449 ctk_style_context_add_class (context, CTK_STYLE_CLASS_MONOSPACE"monospace");
11450 else
11451 ctk_style_context_remove_class (context, CTK_STYLE_CLASS_MONOSPACE"monospace");
11452 g_object_notify (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "monospace");
11453 }
11454}
11455
11456/**
11457 * ctk_text_view_get_monospace:
11458 * @text_view: a #CtkTextView
11459 *
11460 * Gets the value of the #CtkTextView:monospace property.
11461 *
11462 * Return: %TRUE if monospace fonts are desired
11463 *
11464 * Since: 3.16
11465 */
11466gboolean
11467ctk_text_view_get_monospace (CtkTextView *text_view)
11468{
11469 CtkStyleContext *context;
11470
11471 g_return_val_if_fail (CTK_IS_TEXT_VIEW (text_view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_VIEW (text_view)"); return ((0)); } } while (
0)
;
11472
11473 context = ctk_widget_get_style_context (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
11474
11475 return ctk_style_context_has_class (context, CTK_STYLE_CLASS_MONOSPACE"monospace");
11476}
11477
11478static void
11479ctk_text_view_insert_emoji (CtkTextView *text_view)
11480{
11481 CtkWidget *chooser;
11482 CtkTextIter iter;
11483 CdkRectangle rect;
11484 CtkTextBuffer *buffer;
11485
11486 if (ctk_text_view_get_input_hints (text_view) & CTK_INPUT_HINT_NO_EMOJI)
11487 return;
11488
11489 if (ctk_widget_get_ancestor (CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
, CTK_TYPE_EMOJI_CHOOSER(ctk_emoji_chooser_get_type ())) != NULL((void*)0))
11490 return;
11491
11492 chooser = CTK_WIDGET (g_object_get_data (G_OBJECT (text_view), "ctk-emoji-chooser"))((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_get_data (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((text_view)), (((GType) ((20) << (2
)))))))), "ctk-emoji-chooser"))), ((ctk_widget_get_type ())))
)))
;
11493 if (!chooser)
11494 {
11495 chooser = ctk_emoji_chooser_new ();
11496 g_object_set_data (G_OBJECT (text_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), (((GType) ((20) << (2))))))))
, "ctk-emoji-chooser", chooser);
11497
11498 ctk_popover_set_relative_to (CTK_POPOVER (chooser)((((CtkPopover*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((chooser)), ((ctk_popover_get_type ()))))))
, CTK_WIDGET (text_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text_view)), ((ctk_widget_get_type ()))))))
);
11499 g_signal_connect_swapped (chooser, "emoji-picked",g_signal_connect_data ((chooser), ("emoji-picked"), (((GCallback
) (ctk_text_view_insert_at_cursor))), (text_view), ((void*)0)
, G_CONNECT_SWAPPED)
11500 G_CALLBACK (ctk_text_view_insert_at_cursor), text_view)g_signal_connect_data ((chooser), ("emoji-picked"), (((GCallback
) (ctk_text_view_insert_at_cursor))), (text_view), ((void*)0)
, G_CONNECT_SWAPPED)
;
11501 }
11502
11503 buffer = get_buffer (text_view);
11504 ctk_text_buffer_get_iter_at_mark (buffer, &iter,
11505 ctk_text_buffer_get_insert (buffer));
11506
11507 ctk_text_view_get_iter_location (text_view, &iter, (CdkRectangle *) &rect);
11508 ctk_text_view_buffer_to_window_coords (text_view, CTK_TEXT_WINDOW_TEXT,
11509 rect.x, rect.y, &rect.x, &rect.y);
11510 _text_window_to_widget_coords (text_view, &rect.x, &rect.y);
11511
11512 ctk_popover_set_pointing_to (CTK_POPOVER (chooser)((((CtkPopover*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((chooser)), ((ctk_popover_get_type ()))))))
, &rect);
11513
11514 ctk_popover_popup (CTK_POPOVER (chooser)((((CtkPopover*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((chooser)), ((ctk_popover_get_type ()))))))
);
11515}