Bug Summary

File:_build/../ctksourceview/ctksourceview.c
Warning:line 3634, column 44
Division by zero

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 ctksourceview.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=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/_build -fcoverage-compilation-dir=/rootdir/_build -resource-dir /usr/lib/llvm-19/lib/clang/19 -I ctksourceview/libctksourceview-4core.a.p -I ctksourceview -I ../ctksourceview -I . -I .. -I /usr/include/fribidi -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/libmount -I /usr/include/blkid -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -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/libxml2 -D _FILE_OFFSET_BITS=64 -D G_DISABLE_DEPRECATED -D CDK_DISABLE_DEPRECATED -D CTK_DISABLE_DEPRECATED -D GDK_PIXBUF_DISABLE_DEPRECATED -D CDK_VERSION_MIN_REQUIRED=CDK_VERSION_3_24 -D CDK_VERSION_MAX_ALLOWED=CDK_VERSION_3_24 -D GLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_48 -D GLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_48 -D HAVE_CONFIG_H -D CTK_SOURCE_COMPILATION -D G_LOG_DOMAIN="CtkSourceView" -internal-isystem /usr/lib/llvm-19/lib/clang/19/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 -O2 -Wno-cast-function-type -Wno-missing-field-initializers -Wno-sign-compare -Wno-unused-parameter -std=gnu99 -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -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.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/2025-07-25-104022-13980-1 -x c ../ctksourceview/ctksourceview.c
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
2/*
3 * This file is part of CtkSourceView
4 *
5 * Copyright (C) 2001 - Mikael Hermansson <tyan@linux.se> and
6 * Chris Phelps <chicane@reninet.com>
7 * Copyright (C) 2002 - Jeroen Zwartepoorte
8 * Copyright (C) 2003 - Gustavo Giráldez and Paolo Maggi
9 *
10 * CtkSourceView is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * CtkSourceView is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24#ifdef HAVE_CONFIG_H1
25#include <config.h>
26#endif
27
28#include "ctksourceview.h"
29
30#include <string.h> /* For strlen */
31#include <fribidi.h>
32#include <ctk/ctk.h>
33#include <cdk/cdkkeysyms.h>
34#include <pango/pango-tabs.h>
35#include <glib/gi18n-lib.h>
36
37#include "ctksourcebuffer.h"
38#include "ctksourcebuffer-private.h"
39#include "ctksourcebufferinternal.h"
40#include "ctksource-enumtypes.h"
41#include "ctksourcemark.h"
42#include "ctksourcemarkattributes.h"
43#include "ctksource-marshal.h"
44#include "ctksourcestylescheme.h"
45#include "ctksourcecompletion.h"
46#include "ctksourcecompletion-private.h"
47#include "ctksourcecompletionprovider.h"
48#include "ctksourcegutter.h"
49#include "ctksourcegutter-private.h"
50#include "ctksourcegutterrendererlines.h"
51#include "ctksourcegutterrenderermarks.h"
52#include "ctksourceiter.h"
53#include "ctksourcesearchcontext.h"
54#include "ctksourcespacedrawer.h"
55#include "ctksourcespacedrawer-private.h"
56
57/**
58 * SECTION:view
59 * @Short_description: Subclass of #CtkTextView
60 * @Title: CtkSourceView
61 * @See_also: #CtkTextView, #CtkSourceBuffer
62 *
63 * #CtkSourceView is the main class of the CtkSourceView library.
64 * Use a #CtkSourceBuffer to display text with a #CtkSourceView.
65 *
66 * This class provides:
67 * - Show the line numbers;
68 * - Show a right margin;
69 * - Highlight the current line;
70 * - Indentation settings;
71 * - Configuration for the Home and End keyboard keys;
72 * - Configure and show line marks;
73 * - And a few other things.
74 *
75 * An easy way to test all these features is to use the test-widget mini-program
76 * provided in the CtkSourceView repository, in the tests/ directory.
77 *
78 * # CtkSourceView as CtkBuildable
79 *
80 * The CtkSourceView implementation of the #CtkBuildable interface exposes the
81 * #CtkSourceView:completion object with the internal-child "completion".
82 *
83 * An example of a UI definition fragment with CtkSourceView:
84 * |[
85 * <object class="CtkSourceView" id="source_view">
86 * <property name="tab_width">4</property>
87 * <property name="auto_indent">True</property>
88 * <child internal-child="completion">
89 * <object class="CtkSourceCompletion">
90 * <property name="select_on_show">False</property>
91 * </object>
92 * </child>
93 * </object>
94 * ]|
95 *
96 * # Changing the Font
97 *
98 * Ctk CSS provides the best way to change the font for a #CtkSourceView in a
99 * manner that allows for components like #CtkSourceMap to scale the desired
100 * font.
101 *
102 * |[
103 * CtkCssProvider *provider = ctk_css_provider_new ();
104 * ctk_css_provider_load_from_data (provider,
105 * "textview { font-family: Monospace; font-size: 8pt; }",
106 * -1,
107 * NULL);
108 * ctk_style_context_add_provider (ctk_widget_get_style_context (view),
109 * CTK_STYLE_PROVIDER (provider),
110 * CTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
111 * g_object_unref (provider);
112 * ]|
113 *
114 * If you need to adjust the font or size of font within a portion of the
115 * document only, you should use a #CtkTextTag with the #CtkTextTag:family or
116 * #CtkTextTag:scale set so that the font size may be scaled relative to
117 * the default font set in CSS.
118 */
119
120/*
121#define ENABLE_DEBUG
122*/
123#undef ENABLE_DEBUG
124
125/*
126#define ENABLE_PROFILE
127*/
128#undef ENABLE_PROFILE
129
130#ifdef ENABLE_DEBUG
131#define DEBUG(x) (x)
132#else
133#define DEBUG(x)
134#endif
135
136#ifdef ENABLE_PROFILE
137#define PROFILE(x) (x)
138#else
139#define PROFILE(x)
140#endif
141
142#define GUTTER_PIXMAP16 16
143#define DEFAULT_TAB_WIDTH8 8
144#define MAX_TAB_WIDTH32 32
145#define MAX_INDENT_WIDTH32 32
146
147#define DEFAULT_RIGHT_MARGIN_POSITION80 80
148#define MAX_RIGHT_MARGIN_POSITION1000 1000
149
150#define RIGHT_MARGIN_LINE_ALPHA40 40
151#define RIGHT_MARGIN_OVERLAY_ALPHA15 15
152
153enum
154{
155 UNDO,
156 REDO,
157 SHOW_COMPLETION,
158 LINE_MARK_ACTIVATED,
159 MOVE_LINES,
160 MOVE_WORDS,
161 SMART_HOME_END,
162 MOVE_TO_MATCHING_BRACKET,
163 CHANGE_NUMBER,
164 CHANGE_CASE,
165 JOIN_LINES,
166 N_SIGNALS
167};
168
169enum
170{
171 PROP_0,
172 PROP_COMPLETION,
173 PROP_SHOW_LINE_NUMBERS,
174 PROP_SHOW_LINE_MARKS,
175 PROP_TAB_WIDTH,
176 PROP_INDENT_WIDTH,
177 PROP_AUTO_INDENT,
178 PROP_INSERT_SPACES,
179 PROP_SHOW_RIGHT_MARGIN,
180 PROP_RIGHT_MARGIN_POSITION,
181 PROP_SMART_HOME_END,
182 PROP_HIGHLIGHT_CURRENT_LINE,
183 PROP_INDENT_ON_TAB,
184 PROP_BACKGROUND_PATTERN,
185 PROP_SMART_BACKSPACE,
186 PROP_SPACE_DRAWER
187};
188
189struct _CtkSourceViewPrivate
190{
191 CtkSourceStyleScheme *style_scheme;
192 CdkRGBA *right_margin_line_color;
193 CdkRGBA *right_margin_overlay_color;
194
195 CtkSourceSpaceDrawer *space_drawer;
196
197 GHashTable *mark_categories;
198
199 CtkSourceBuffer *source_buffer;
200
201 CtkSourceGutter *left_gutter;
202 CtkSourceGutter *right_gutter;
203
204 CtkSourceGutterRenderer *line_renderer;
205 CtkSourceGutterRenderer *marks_renderer;
206
207 CdkRGBA current_line_color;
208
209 CtkSourceCompletion *completion;
210
211 guint right_margin_pos;
212 gint cached_right_margin_pos;
213 guint tab_width;
214 gint indent_width;
215 CtkSourceSmartHomeEndType smart_home_end;
216 CtkSourceBackgroundPatternType background_pattern;
217 CdkRGBA background_pattern_color;
218
219 guint tabs_set : 1;
220 guint show_line_numbers : 1;
221 guint show_line_marks : 1;
222 guint auto_indent : 1;
223 guint insert_spaces : 1;
224 guint highlight_current_line : 1;
225 guint indent_on_tab : 1;
226 guint show_right_margin : 1;
227 guint current_line_color_set : 1;
228 guint background_pattern_color_set : 1;
229 guint smart_backspace : 1;
230};
231
232typedef struct _MarkCategory MarkCategory;
233
234struct _MarkCategory
235{
236 CtkSourceMarkAttributes *attributes;
237 gint priority;
238};
239
240static guint signals[N_SIGNALS];
241
242static void ctk_source_view_buildable_interface_init (CtkBuildableIface *iface);
243
244G_DEFINE_TYPE_WITH_CODE (CtkSourceView, ctk_source_view, CTK_TYPE_TEXT_VIEW,static void ctk_source_view_init (CtkSourceView *self); static
void ctk_source_view_class_init (CtkSourceViewClass *klass);
static GType ctk_source_view_get_type_once (void); static gpointer
ctk_source_view_parent_class = ((void*)0); static gint CtkSourceView_private_offset
; static void ctk_source_view_class_intern_init (gpointer klass
) { ctk_source_view_parent_class = g_type_class_peek_parent (
klass); if (CtkSourceView_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkSourceView_private_offset); ctk_source_view_class_init
((CtkSourceViewClass*) klass); } __attribute__ ((__unused__)
) static inline gpointer ctk_source_view_get_instance_private
(CtkSourceView *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkSourceView_private_offset)))); } GType ctk_source_view_get_type
(void) { static gsize 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 (&static_g_define_type_id
)); }))) { GType g_define_type_id = ctk_source_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 ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType ctk_source_view_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((ctk_text_view_get_type ()), g_intern_static_string ("CtkSourceView"
), sizeof (CtkSourceViewClass), (GClassInitFunc)(void (*)(void
)) ctk_source_view_class_intern_init, sizeof (CtkSourceView),
(GInstanceInitFunc)(void (*)(void)) ctk_source_view_init, (GTypeFlags
) 0); { {{ CtkSourceView_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkSourceViewPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) ctk_source_view_buildable_interface_init, (
(void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
245 G_ADD_PRIVATE (CtkSourceView)static void ctk_source_view_init (CtkSourceView *self); static
void ctk_source_view_class_init (CtkSourceViewClass *klass);
static GType ctk_source_view_get_type_once (void); static gpointer
ctk_source_view_parent_class = ((void*)0); static gint CtkSourceView_private_offset
; static void ctk_source_view_class_intern_init (gpointer klass
) { ctk_source_view_parent_class = g_type_class_peek_parent (
klass); if (CtkSourceView_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkSourceView_private_offset); ctk_source_view_class_init
((CtkSourceViewClass*) klass); } __attribute__ ((__unused__)
) static inline gpointer ctk_source_view_get_instance_private
(CtkSourceView *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkSourceView_private_offset)))); } GType ctk_source_view_get_type
(void) { static gsize 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 (&static_g_define_type_id
)); }))) { GType g_define_type_id = ctk_source_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 ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType ctk_source_view_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((ctk_text_view_get_type ()), g_intern_static_string ("CtkSourceView"
), sizeof (CtkSourceViewClass), (GClassInitFunc)(void (*)(void
)) ctk_source_view_class_intern_init, sizeof (CtkSourceView),
(GInstanceInitFunc)(void (*)(void)) ctk_source_view_init, (GTypeFlags
) 0); { {{ CtkSourceView_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkSourceViewPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) ctk_source_view_buildable_interface_init, (
(void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
246 G_IMPLEMENT_INTERFACE (CTK_TYPE_BUILDABLE,static void ctk_source_view_init (CtkSourceView *self); static
void ctk_source_view_class_init (CtkSourceViewClass *klass);
static GType ctk_source_view_get_type_once (void); static gpointer
ctk_source_view_parent_class = ((void*)0); static gint CtkSourceView_private_offset
; static void ctk_source_view_class_intern_init (gpointer klass
) { ctk_source_view_parent_class = g_type_class_peek_parent (
klass); if (CtkSourceView_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkSourceView_private_offset); ctk_source_view_class_init
((CtkSourceViewClass*) klass); } __attribute__ ((__unused__)
) static inline gpointer ctk_source_view_get_instance_private
(CtkSourceView *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkSourceView_private_offset)))); } GType ctk_source_view_get_type
(void) { static gsize 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 (&static_g_define_type_id
)); }))) { GType g_define_type_id = ctk_source_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 ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType ctk_source_view_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((ctk_text_view_get_type ()), g_intern_static_string ("CtkSourceView"
), sizeof (CtkSourceViewClass), (GClassInitFunc)(void (*)(void
)) ctk_source_view_class_intern_init, sizeof (CtkSourceView),
(GInstanceInitFunc)(void (*)(void)) ctk_source_view_init, (GTypeFlags
) 0); { {{ CtkSourceView_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkSourceViewPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) ctk_source_view_buildable_interface_init, (
(void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
247 ctk_source_view_buildable_interface_init))static void ctk_source_view_init (CtkSourceView *self); static
void ctk_source_view_class_init (CtkSourceViewClass *klass);
static GType ctk_source_view_get_type_once (void); static gpointer
ctk_source_view_parent_class = ((void*)0); static gint CtkSourceView_private_offset
; static void ctk_source_view_class_intern_init (gpointer klass
) { ctk_source_view_parent_class = g_type_class_peek_parent (
klass); if (CtkSourceView_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkSourceView_private_offset); ctk_source_view_class_init
((CtkSourceViewClass*) klass); } __attribute__ ((__unused__)
) static inline gpointer ctk_source_view_get_instance_private
(CtkSourceView *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkSourceView_private_offset)))); } GType ctk_source_view_get_type
(void) { static gsize 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 (&static_g_define_type_id
)); }))) { GType g_define_type_id = ctk_source_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 ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType ctk_source_view_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((ctk_text_view_get_type ()), g_intern_static_string ("CtkSourceView"
), sizeof (CtkSourceViewClass), (GClassInitFunc)(void (*)(void
)) ctk_source_view_class_intern_init, sizeof (CtkSourceView),
(GInstanceInitFunc)(void (*)(void)) ctk_source_view_init, (GTypeFlags
) 0); { {{ CtkSourceView_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkSourceViewPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) ctk_source_view_buildable_interface_init, (
(void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
248
249/* Implement DnD for application/x-color drops */
250typedef enum _CtkSourceViewDropTypes {
251 TARGET_COLOR = 200
252} CtkSourceViewDropTypes;
253
254static const CtkTargetEntry drop_types[] = {
255 {(gchar *)"application/x-color", 0, TARGET_COLOR}
256};
257
258/* Prototypes. */
259static void ctk_source_view_dispose (GObject *object);
260static void ctk_source_view_finalize (GObject *object);
261static void ctk_source_view_undo (CtkSourceView *view);
262static void ctk_source_view_redo (CtkSourceView *view);
263static void ctk_source_view_show_completion_real (CtkSourceView *view);
264static CtkTextBuffer * ctk_source_view_create_buffer (CtkTextView *view);
265static void remove_source_buffer (CtkSourceView *view);
266static void set_source_buffer (CtkSourceView *view,
267 CtkTextBuffer *buffer);
268static void ctk_source_view_populate_popup (CtkTextView *view,
269 CtkWidget *popup);
270static void ctk_source_view_move_cursor (CtkTextView *text_view,
271 CtkMovementStep step,
272 gint count,
273 gboolean extend_selection);
274static void ctk_source_view_delete_from_cursor (CtkTextView *text_view,
275 CtkDeleteType type,
276 gint count);
277static gboolean ctk_source_view_extend_selection (CtkTextView *text_view,
278 CtkTextExtendSelection granularity,
279 const CtkTextIter *location,
280 CtkTextIter *start,
281 CtkTextIter *end);
282static void ctk_source_view_get_lines (CtkTextView *text_view,
283 gint first_y,
284 gint last_y,
285 GArray *buffer_coords,
286 GArray *line_heights,
287 GArray *numbers,
288 gint *countp);
289static gboolean ctk_source_view_draw (CtkWidget *widget,
290 cairo_t *cr);
291static void ctk_source_view_move_lines (CtkSourceView *view,
292 gboolean down);
293static void ctk_source_view_move_words (CtkSourceView *view,
294 gint step);
295static gboolean ctk_source_view_key_press_event (CtkWidget *widget,
296 CdkEventKey *event);
297static void view_dnd_drop (CtkTextView *view,
298 CdkDragContext *context,
299 gint x,
300 gint y,
301 CtkSelectionData *selection_data,
302 guint info,
303 guint timestamp,
304 gpointer data);
305static gint calculate_real_tab_width (CtkSourceView *view,
306 guint tab_size,
307 gchar c);
308static void ctk_source_view_set_property (GObject *object,
309 guint prop_id,
310 const GValue *value,
311 GParamSpec *pspec);
312static void ctk_source_view_get_property (GObject *object,
313 guint prop_id,
314 GValue *value,
315 GParamSpec *pspec);
316static void ctk_source_view_style_updated (CtkWidget *widget);
317static void ctk_source_view_update_style_scheme (CtkSourceView *view);
318static void ctk_source_view_draw_layer (CtkTextView *view,
319 CtkTextViewLayer layer,
320 cairo_t *cr);
321
322static MarkCategory *mark_category_new (CtkSourceMarkAttributes *attributes,
323 gint priority);
324static void mark_category_free (MarkCategory *category);
325
326static void
327ctk_source_view_constructed (GObject *object)
328{
329 CtkSourceView *view = CTK_SOURCE_VIEW (object)((((CtkSourceView*) (void *) ((object)))));
330
331 set_source_buffer (view, ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))))));
332
333 G_OBJECT_CLASS (ctk_source_view_parent_class)((((GObjectClass*) (void *) ((ctk_source_view_parent_class)))
))
->constructed (object);
334}
335
336static void
337ctk_source_view_move_to_matching_bracket (CtkSourceView *view,
338 gboolean extend_selection)
339{
340 CtkTextView *text_view = CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))));
341 CtkTextBuffer *buffer;
342 CtkTextMark *insert_mark;
343 CtkTextIter insert;
344 CtkTextIter bracket_match;
345 CtkSourceBracketMatchType result;
346
347 buffer = ctk_text_view_get_buffer (text_view);
348 insert_mark = ctk_text_buffer_get_insert (buffer);
349 ctk_text_buffer_get_iter_at_mark (buffer, &insert, insert_mark);
350
351 result = _ctk_source_buffer_find_bracket_match (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer))))),
352 &insert,
353 NULL((void*)0),
354 &bracket_match);
355
356 if (result == CTK_SOURCE_BRACKET_MATCH_FOUND)
357 {
358 if (extend_selection)
359 {
360 ctk_text_buffer_move_mark (buffer, insert_mark, &bracket_match);
361 }
362 else
363 {
364 ctk_text_buffer_place_cursor (buffer, &bracket_match);
365 }
366
367 ctk_text_view_scroll_mark_onscreen (text_view, insert_mark);
368 }
369}
370
371static void
372ctk_source_view_change_number (CtkSourceView *view,
373 gint count)
374{
375 CtkTextView *text_view = CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))));
376 CtkTextBuffer *buffer;
377 CtkTextIter start, end;
378 gchar *str;
379
380 buffer = ctk_text_view_get_buffer (text_view);
381 if (!CTK_SOURCE_IS_BUFFER (buffer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(buffer)); GType __t = ((ctk_source_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; }))))
)
382 {
383 return;
384 }
385
386 if (!ctk_text_buffer_get_selection_bounds (buffer, &start, &end))
387 {
388 if (!ctk_text_iter_starts_word (&start))
389 {
390 CtkTextIter prev;
391
392 ctk_text_iter_backward_word_start (&start);
393
394 /* Include the negative sign if there is one.
395 * https://gitlab.gnome.org/GNOME/ctksourceview/-/issues/117
396 */
397 prev = start;
398 if (ctk_text_iter_backward_char (&prev) && ctk_text_iter_get_char (&prev) == '-')
399 {
400 start = prev;
401 }
402 }
403
404 if (!ctk_text_iter_ends_word (&end))
405 {
406 ctk_text_iter_forward_word_end (&end);
407 }
408 }
409
410 str = ctk_text_buffer_get_text (buffer, &start, &end, FALSE(0));
411
412 if (str != NULL((void*)0) && *str != '\0')
413 {
414 gchar *p;
415 gint64 n;
416 glong len;
417
418 len = ctk_text_iter_get_offset (&end) - ctk_text_iter_get_offset (&start);
419 g_assert (len > 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_63
= 0; if (len > 0) _g_boolean_var_63 = 1; _g_boolean_var_63
; }), 1)) ; else g_assertion_message_expr ("CtkSourceView", "../ctksourceview/ctksourceview.c"
, 419, ((const char*) (__func__)), "len > 0"); } while (0)
;
420
421 n = g_ascii_strtoll (str, &p, 10);
422
423 /* do the action only if strtoll succeeds (p != str) and
424 * the whole string is the number, e.g. not 123abc
425 */
426 if ((p - str) == len)
427 {
428 gchar *newstr;
429
430 newstr = g_strdup_printf ("%"G_GINT64_FORMAT"li", (n + count));
431
432 ctk_text_buffer_begin_user_action (buffer);
433 ctk_text_buffer_delete (buffer, &start, &end);
434 ctk_text_buffer_insert (buffer, &start, newstr, -1);
435 ctk_text_buffer_end_user_action (buffer);
436
437 g_free (newstr);
438 }
439
440 g_free (str);
441 }
442}
443
444static void
445ctk_source_view_change_case (CtkSourceView *view,
446 CtkSourceChangeCaseType case_type)
447{
448 CtkSourceBuffer *buffer;
449 CtkTextIter start, end;
450
451 buffer = CTK_SOURCE_BUFFER (ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)))((((CtkSourceBuffer*) (void *) ((ctk_text_view_get_buffer (((
((CtkTextView*) (void *) ((view)))))))))))
;
452
453 ctk_text_view_reset_im_context (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
454
455 if (!ctk_text_buffer_get_selection_bounds (CTK_TEXT_BUFFER (buffer)((((CtkTextBuffer*) (void *) ((buffer))))), &start, &end))
456 {
457 /* if no selection, change the current char */
458 ctk_text_iter_forward_char (&end);
459 }
460
461 ctk_source_buffer_change_case (buffer, case_type, &start, &end);
462}
463
464static void
465ctk_source_view_join_lines (CtkSourceView *view)
466{
467 CtkSourceBuffer *buffer;
468 CtkTextIter start;
469 CtkTextIter end;
470
471 buffer = CTK_SOURCE_BUFFER (ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)))((((CtkSourceBuffer*) (void *) ((ctk_text_view_get_buffer (((
((CtkTextView*) (void *) ((view)))))))))))
;
472
473 ctk_text_view_reset_im_context (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
474
475 ctk_text_buffer_get_selection_bounds (CTK_TEXT_BUFFER (buffer)((((CtkTextBuffer*) (void *) ((buffer))))), &start, &end);
476
477 ctk_source_buffer_join_lines (buffer, &start, &end);
478}
479
480static void
481ctk_source_view_class_init (CtkSourceViewClass *klass)
482{
483 GObjectClass *object_class;
484 CtkTextViewClass *textview_class;
485 CtkBindingSet *binding_set;
486 CtkWidgetClass *widget_class;
487
488 object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) ((klass)))));
489 textview_class = CTK_TEXT_VIEW_CLASS (klass)((((CtkTextViewClass*) (void *) ((klass)))));
490 widget_class = CTK_WIDGET_CLASS (klass)((((CtkWidgetClass*) (void *) ((klass)))));
491
492 object_class->constructed = ctk_source_view_constructed;
493 object_class->dispose = ctk_source_view_dispose;
494 object_class->finalize = ctk_source_view_finalize;
495 object_class->get_property = ctk_source_view_get_property;
496 object_class->set_property = ctk_source_view_set_property;
497
498 widget_class->key_press_event = ctk_source_view_key_press_event;
499 widget_class->draw = ctk_source_view_draw;
500 widget_class->style_updated = ctk_source_view_style_updated;
501
502 textview_class->populate_popup = ctk_source_view_populate_popup;
503 textview_class->move_cursor = ctk_source_view_move_cursor;
504 textview_class->delete_from_cursor = ctk_source_view_delete_from_cursor;
505 textview_class->extend_selection = ctk_source_view_extend_selection;
506 textview_class->create_buffer = ctk_source_view_create_buffer;
507 textview_class->draw_layer = ctk_source_view_draw_layer;
508
509 klass->undo = ctk_source_view_undo;
510 klass->redo = ctk_source_view_redo;
511 klass->show_completion = ctk_source_view_show_completion_real;
512 klass->move_lines = ctk_source_view_move_lines;
513 klass->move_words = ctk_source_view_move_words;
514
515 /**
516 * CtkSourceView:completion:
517 *
518 * The completion object associated with the view
519 */
520 g_object_class_install_property (object_class,
521 PROP_COMPLETION,
522 g_param_spec_object ("completion",
523 "Completion",
524 "The completion object associated with the view",
525 CTK_SOURCE_TYPE_COMPLETION(ctk_source_completion_get_type()),
526 G_PARAM_READABLE |
527 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
528
529 /**
530 * CtkSourceView:show-line-numbers:
531 *
532 * Whether to display line numbers
533 */
534 g_object_class_install_property (object_class,
535 PROP_SHOW_LINE_NUMBERS,
536 g_param_spec_boolean ("show-line-numbers",
537 "Show Line Numbers",
538 "Whether to display line numbers",
539 FALSE(0),
540 G_PARAM_READWRITE |
541 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
542 /**
543 * CtkSourceView:show-line-marks:
544 *
545 * Whether to display line mark pixbufs
546 */
547 g_object_class_install_property (object_class,
548 PROP_SHOW_LINE_MARKS,
549 g_param_spec_boolean ("show-line-marks",
550 "Show Line Marks",
551 "Whether to display line mark pixbufs",
552 FALSE(0),
553 G_PARAM_READWRITE |
554 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
555
556 /**
557 * CtkSourceView:tab-width:
558 *
559 * Width of a tab character expressed in number of spaces.
560 */
561 g_object_class_install_property (object_class,
562 PROP_TAB_WIDTH,
563 g_param_spec_uint ("tab-width",
564 "Tab Width",
565 "Width of a tab character expressed in spaces",
566 1,
567 MAX_TAB_WIDTH32,
568 DEFAULT_TAB_WIDTH8,
569 G_PARAM_READWRITE |
570 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
571
572 /**
573 * CtkSourceView:indent-width:
574 *
575 * Width of an indentation step expressed in number of spaces.
576 */
577 g_object_class_install_property (object_class,
578 PROP_INDENT_WIDTH,
579 g_param_spec_int ("indent-width",
580 "Indent Width",
581 "Number of spaces to use for each step of indent",
582 -1,
583 MAX_INDENT_WIDTH32,
584 -1,
585 G_PARAM_READWRITE |
586 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
587
588 g_object_class_install_property (object_class,
589 PROP_AUTO_INDENT,
590 g_param_spec_boolean ("auto-indent",
591 "Auto Indentation",
592 "Whether to enable auto indentation",
593 FALSE(0),
594 G_PARAM_READWRITE |
595 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
596
597 g_object_class_install_property (object_class,
598 PROP_INSERT_SPACES,
599 g_param_spec_boolean ("insert-spaces-instead-of-tabs",
600 "Insert Spaces Instead of Tabs",
601 "Whether to insert spaces instead of tabs",
602 FALSE(0),
603 G_PARAM_READWRITE |
604 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
605
606 /**
607 * CtkSourceView:show-right-margin:
608 *
609 * Whether to display the right margin.
610 */
611 g_object_class_install_property (object_class,
612 PROP_SHOW_RIGHT_MARGIN,
613 g_param_spec_boolean ("show-right-margin",
614 "Show Right Margin",
615 "Whether to display the right margin",
616 FALSE(0),
617 G_PARAM_READWRITE |
618 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
619
620 /**
621 * CtkSourceView:right-margin-position:
622 *
623 * Position of the right margin.
624 */
625 g_object_class_install_property (object_class,
626 PROP_RIGHT_MARGIN_POSITION,
627 g_param_spec_uint ("right-margin-position",
628 "Right Margin Position",
629 "Position of the right margin",
630 1,
631 MAX_RIGHT_MARGIN_POSITION1000,
632 DEFAULT_RIGHT_MARGIN_POSITION80,
633 G_PARAM_READWRITE |
634 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
635
636 /**
637 * CtkSourceView:smart-home-end:
638 *
639 * Set the behavior of the HOME and END keys.
640 *
641 * Since: 2.0
642 */
643 g_object_class_install_property (object_class,
644 PROP_SMART_HOME_END,
645 g_param_spec_enum ("smart-home-end",
646 "Smart Home/End",
647 "HOME and END keys move to first/last "
648 "non whitespace characters on line before going "
649 "to the start/end of the line",
650 CTK_SOURCE_TYPE_SMART_HOME_END_TYPE(ctk_source_smart_home_end_type_get_type()),
651 CTK_SOURCE_SMART_HOME_END_DISABLED,
652 G_PARAM_READWRITE |
653 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
654
655 g_object_class_install_property (object_class,
656 PROP_HIGHLIGHT_CURRENT_LINE,
657 g_param_spec_boolean ("highlight-current-line",
658 "Highlight current line",
659 "Whether to highlight the current line",
660 FALSE(0),
661 G_PARAM_READWRITE |
662 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
663
664 g_object_class_install_property (object_class,
665 PROP_INDENT_ON_TAB,
666 g_param_spec_boolean ("indent-on-tab",
667 "Indent on tab",
668 "Whether to indent the selected text when the tab key is pressed",
669 TRUE(!(0)),
670 G_PARAM_READWRITE |
671 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
672
673 /**
674 * CtkSourceView:background-pattern:
675 *
676 * Draw a specific background pattern on the view.
677 *
678 * Since: 3.16
679 */
680 g_object_class_install_property (object_class,
681 PROP_BACKGROUND_PATTERN,
682 g_param_spec_enum ("background-pattern",
683 "Background pattern",
684 "Draw a specific background pattern on the view",
685 CTK_SOURCE_TYPE_BACKGROUND_PATTERN_TYPE(ctk_source_background_pattern_type_get_type()),
686 CTK_SOURCE_BACKGROUND_PATTERN_TYPE_NONE,
687 G_PARAM_READWRITE |
688 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
689
690 /**
691 * CtkSourceView:smart-backspace:
692 *
693 * Whether smart Backspace should be used.
694 *
695 * Since: 3.18
696 */
697 g_object_class_install_property (object_class,
698 PROP_SMART_BACKSPACE,
699 g_param_spec_boolean ("smart-backspace",
700 "Smart Backspace",
701 "",
702 FALSE(0),
703 G_PARAM_READWRITE |
704 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
705
706 /**
707 * CtkSourceView:space-drawer:
708 *
709 * The #CtkSourceSpaceDrawer object associated with the view.
710 *
711 * Since: 3.24
712 */
713 g_object_class_install_property (object_class,
714 PROP_SPACE_DRAWER,
715 g_param_spec_object ("space-drawer",
716 "Space Drawer",
717 "",
718 CTK_SOURCE_TYPE_SPACE_DRAWER(ctk_source_space_drawer_get_type ()),
719 G_PARAM_READABLE |
720 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
721
722 signals[UNDO] =
723 g_signal_new ("undo",
724 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
725 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
726 G_STRUCT_OFFSET (CtkSourceViewClass, undo)((glong) __builtin_offsetof(CtkSourceViewClass, undo)),
727 NULL((void*)0), NULL((void*)0),
728 g_cclosure_marshal_VOID__VOID,
729 G_TYPE_NONE((GType) ((1) << (2))), 0);
730 g_signal_set_va_marshaller (signals[UNDO],
731 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
732 g_cclosure_marshal_VOID__VOIDv);
733
734 signals[REDO] =
735 g_signal_new ("redo",
736 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
737 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
738 G_STRUCT_OFFSET (CtkSourceViewClass, redo)((glong) __builtin_offsetof(CtkSourceViewClass, redo)),
739 NULL((void*)0), NULL((void*)0),
740 g_cclosure_marshal_VOID__VOID,
741 G_TYPE_NONE((GType) ((1) << (2))), 0);
742 g_signal_set_va_marshaller (signals[REDO],
743 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
744 g_cclosure_marshal_VOID__VOIDv);
745
746 /**
747 * CtkSourceView::show-completion:
748 * @view: The #CtkSourceView who emits the signal
749 *
750 * The ::show-completion signal is a key binding signal which gets
751 * emitted when the user requests a completion, by pressing
752 * <keycombo><keycap>Control</keycap><keycap>space</keycap></keycombo>.
753 *
754 * This will create a #CtkSourceCompletionContext with the activation
755 * type as %CTK_SOURCE_COMPLETION_ACTIVATION_USER_REQUESTED.
756 *
757 * Applications should not connect to it, but may emit it with
758 * g_signal_emit_by_name() if they need to activate the completion by
759 * another means, for example with another key binding or a menu entry.
760 */
761 signals[SHOW_COMPLETION] =
762 g_signal_new ("show-completion",
763 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
764 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
765 G_STRUCT_OFFSET (CtkSourceViewClass, show_completion)((glong) __builtin_offsetof(CtkSourceViewClass, show_completion
))
,
766 NULL((void*)0), NULL((void*)0),
767 g_cclosure_marshal_VOID__VOID,
768 G_TYPE_NONE((GType) ((1) << (2))), 0);
769 g_signal_set_va_marshaller (signals[SHOW_COMPLETION],
770 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
771 g_cclosure_marshal_VOID__VOIDv);
772
773 /**
774 * CtkSourceView::line-mark-activated:
775 * @view: the #CtkSourceView
776 * @iter: a #CtkTextIter
777 * @event: the #CdkEvent that activated the event
778 *
779 * Emitted when a line mark has been activated (for instance when there
780 * was a button press in the line marks gutter). You can use @iter to
781 * determine on which line the activation took place.
782 */
783 signals[LINE_MARK_ACTIVATED] =
784 g_signal_new ("line-mark-activated",
785 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
786 G_SIGNAL_RUN_LAST,
787 G_STRUCT_OFFSET (CtkSourceViewClass, line_mark_activated)((glong) __builtin_offsetof(CtkSourceViewClass, line_mark_activated
))
,
788 NULL((void*)0), NULL((void*)0),
789 _ctk_source_marshal_VOID__BOXED_BOXED,
790 G_TYPE_NONE((GType) ((1) << (2))),
791 2,
792 CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()),
793 CDK_TYPE_EVENT(cdk_event_get_type ()) | G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))));
794 g_signal_set_va_marshaller (signals[LINE_MARK_ACTIVATED],
795 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
796 _ctk_source_marshal_VOID__BOXED_BOXEDv);
797
798 /**
799 * CtkSourceView::move-lines:
800 * @view: the #CtkSourceView which received the signal.
801 * @down: %TRUE to move down, %FALSE to move up.
802 *
803 * The ::move-lines signal is a keybinding which gets emitted
804 * when the user initiates moving a line. The default binding key
805 * is Alt+Up/Down arrow. And moves the currently selected lines,
806 * or the current line up or down by one line.
807 */
808 signals[MOVE_LINES] =
809 g_signal_new ("move-lines",
810 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
811 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
812 G_STRUCT_OFFSET (CtkSourceViewClass, move_lines)((glong) __builtin_offsetof(CtkSourceViewClass, move_lines)),
813 NULL((void*)0), NULL((void*)0),
814 g_cclosure_marshal_VOID__BOOLEAN,
815 G_TYPE_NONE((GType) ((1) << (2))), 1,
816 G_TYPE_BOOLEAN((GType) ((5) << (2))));
817 g_signal_set_va_marshaller (signals[MOVE_LINES],
818 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
819 g_cclosure_marshal_VOID__BOOLEANv);
820
821 /**
822 * CtkSourceView::move-words:
823 * @view: the #CtkSourceView which received the signal
824 * @count: the number of words to move over
825 *
826 * The ::move-words signal is a keybinding which gets emitted
827 * when the user initiates moving a word. The default binding key
828 * is Alt+Left/Right Arrow and moves the current selection, or the current
829 * word by one word.
830 *
831 * Since: 3.0
832 */
833 signals[MOVE_WORDS] =
834 g_signal_new ("move-words",
835 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
836 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
837 G_STRUCT_OFFSET (CtkSourceViewClass, move_words)((glong) __builtin_offsetof(CtkSourceViewClass, move_words)),
838 NULL((void*)0), NULL((void*)0),
839 g_cclosure_marshal_VOID__INT,
840 G_TYPE_NONE((GType) ((1) << (2))), 1,
841 G_TYPE_INT((GType) ((6) << (2))));
842 g_signal_set_va_marshaller (signals[MOVE_WORDS],
843 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
844 g_cclosure_marshal_VOID__INTv);
845
846 /**
847 * CtkSourceView::smart-home-end:
848 * @view: the #CtkSourceView
849 * @iter: a #CtkTextIter
850 * @count: the count
851 *
852 * Emitted when a the cursor was moved according to the smart home
853 * end setting. The signal is emitted after the cursor is moved, but
854 * during the CtkTextView::move-cursor action. This can be used to find
855 * out whether the cursor was moved by a normal home/end or by a smart
856 * home/end.
857 *
858 * Since: 3.0
859 */
860 signals[SMART_HOME_END] =
861 g_signal_new ("smart-home-end",
862 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
863 G_SIGNAL_RUN_LAST,
864 0,
865 NULL((void*)0), NULL((void*)0),
866 _ctk_source_marshal_VOID__BOXED_INT,
867 G_TYPE_NONE((GType) ((1) << (2))),
868 2,
869 CTK_TYPE_TEXT_ITER(ctk_text_iter_get_type ()),
870 G_TYPE_INT((GType) ((6) << (2))));
871 g_signal_set_va_marshaller (signals[SMART_HOME_END],
872 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
873 _ctk_source_marshal_VOID__BOXED_INTv);
874
875 /**
876 * CtkSourceView::move-to-matching-bracket:
877 * @view: the #CtkSourceView
878 * @extend_selection: %TRUE if the move should extend the selection
879 *
880 * Keybinding signal to move the cursor to the matching bracket.
881 *
882 * Since: 3.16
883 */
884 signals[MOVE_TO_MATCHING_BRACKET] =
885 /* we have to do it this way since we do not have any more vfunc slots */
886 g_signal_new_class_handler ("move-to-matching-bracket",
887 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
888 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
889 G_CALLBACK (ctk_source_view_move_to_matching_bracket)((GCallback) (ctk_source_view_move_to_matching_bracket)),
890 NULL((void*)0), NULL((void*)0),
891 g_cclosure_marshal_VOID__BOOLEAN,
892 G_TYPE_NONE((GType) ((1) << (2))),
893 1,
894 G_TYPE_BOOLEAN((GType) ((5) << (2))));
895 g_signal_set_va_marshaller (signals[MOVE_TO_MATCHING_BRACKET],
896 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
897 g_cclosure_marshal_VOID__BOOLEANv);
898
899 /**
900 * CtkSourceView::change-number:
901 * @view: the #CtkSourceView
902 * @count: the number to add to the number at the current position
903 *
904 * Keybinding signal to edit a number at the current cursor position.
905 *
906 * Since: 3.16
907 */
908 signals[CHANGE_NUMBER] =
909 g_signal_new_class_handler ("change-number",
910 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
911 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
912 G_CALLBACK (ctk_source_view_change_number)((GCallback) (ctk_source_view_change_number)),
913 NULL((void*)0), NULL((void*)0),
914 g_cclosure_marshal_VOID__INT,
915 G_TYPE_NONE((GType) ((1) << (2))),
916 1,
917 G_TYPE_INT((GType) ((6) << (2))));
918 g_signal_set_va_marshaller (signals[CHANGE_NUMBER],
919 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
920 g_cclosure_marshal_VOID__INTv);
921
922 /**
923 * CtkSourceView::change-case:
924 * @view: the #CtkSourceView
925 * @case_type: the case to use
926 *
927 * Keybinding signal to change case of the text at the current cursor position.
928 *
929 * Since: 3.16
930 */
931 signals[CHANGE_CASE] =
932 g_signal_new_class_handler ("change-case",
933 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
934 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
935 G_CALLBACK (ctk_source_view_change_case)((GCallback) (ctk_source_view_change_case)),
936 NULL((void*)0), NULL((void*)0),
937 g_cclosure_marshal_VOID__ENUM,
938 G_TYPE_NONE((GType) ((1) << (2))),
939 1,
940 CTK_SOURCE_TYPE_CHANGE_CASE_TYPE(ctk_source_change_case_type_get_type()));
941 g_signal_set_va_marshaller (signals[CHANGE_CASE],
942 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
943 g_cclosure_marshal_VOID__ENUMv);
944
945 /**
946 * CtkSourceView::join-lines:
947 * @view: the #CtkSourceView
948 *
949 * Keybinding signal to join the lines currently selected.
950 *
951 * Since: 3.16
952 */
953 signals[JOIN_LINES] =
954 g_signal_new_class_handler ("join-lines",
955 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
956 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
957 G_CALLBACK (ctk_source_view_join_lines)((GCallback) (ctk_source_view_join_lines)),
958 NULL((void*)0), NULL((void*)0),
959 g_cclosure_marshal_VOID__VOID,
960 G_TYPE_NONE((GType) ((1) << (2))),
961 0);
962 g_signal_set_va_marshaller (signals[JOIN_LINES],
963 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
964 g_cclosure_marshal_VOID__VOIDv);
965
966 binding_set = ctk_binding_set_by_class (klass);
967
968 ctk_binding_entry_add_signal (binding_set,
969 CDK_KEY_z0x07a,
970 CDK_CONTROL_MASK,
971 "undo", 0);
972 ctk_binding_entry_add_signal (binding_set,
973 CDK_KEY_z0x07a,
974 CDK_CONTROL_MASK | CDK_SHIFT_MASK,
975 "redo", 0);
976 ctk_binding_entry_add_signal (binding_set,
977 CDK_KEY_F140xffcb,
978 0,
979 "undo", 0);
980 ctk_binding_entry_add_signal (binding_set,
981 CDK_KEY_space0x020,
982 CDK_CONTROL_MASK,
983 "show-completion", 0);
984
985 ctk_binding_entry_add_signal (binding_set,
986 CDK_KEY_Up0xff52,
987 CDK_MOD1_MASK,
988 "move-lines", 1,
989 G_TYPE_BOOLEAN((GType) ((5) << (2))), FALSE(0));
990 ctk_binding_entry_add_signal (binding_set,
991 CDK_KEY_KP_Up0xff97,
992 CDK_MOD1_MASK,
993 "move-lines", 1,
994 G_TYPE_BOOLEAN((GType) ((5) << (2))), FALSE(0));
995 ctk_binding_entry_add_signal (binding_set,
996 CDK_KEY_Down0xff54,
997 CDK_MOD1_MASK,
998 "move-lines", 1,
999 G_TYPE_BOOLEAN((GType) ((5) << (2))), TRUE(!(0)));
1000 ctk_binding_entry_add_signal (binding_set,
1001 CDK_KEY_KP_Down0xff99,
1002 CDK_MOD1_MASK,
1003 "move-lines", 1,
1004 G_TYPE_BOOLEAN((GType) ((5) << (2))), TRUE(!(0)));
1005
1006 ctk_binding_entry_add_signal (binding_set,
1007 CDK_KEY_Left0xff51,
1008 CDK_MOD1_MASK,
1009 "move-words", 1,
1010 G_TYPE_INT((GType) ((6) << (2))), -1);
1011 ctk_binding_entry_add_signal (binding_set,
1012 CDK_KEY_KP_Left0xff96,
1013 CDK_MOD1_MASK,
1014 "move-words", 1,
1015 G_TYPE_INT((GType) ((6) << (2))), -1);
1016 ctk_binding_entry_add_signal (binding_set,
1017 CDK_KEY_Right0xff53,
1018 CDK_MOD1_MASK,
1019 "move-words", 1,
1020 G_TYPE_INT((GType) ((6) << (2))), 1);
1021 ctk_binding_entry_add_signal (binding_set,
1022 CDK_KEY_KP_Right0xff98,
1023 CDK_MOD1_MASK,
1024 "move-words", 1,
1025 G_TYPE_INT((GType) ((6) << (2))), 1);
1026
1027 ctk_binding_entry_add_signal (binding_set,
1028 CDK_KEY_Up0xff52,
1029 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1030 "move-viewport", 2,
1031 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_STEPS,
1032 G_TYPE_INT((GType) ((6) << (2))), -1);
1033
1034 ctk_binding_entry_add_signal (binding_set,
1035 CDK_KEY_KP_Up0xff97,
1036 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1037 "move-viewport", 2,
1038 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_STEPS,
1039 G_TYPE_INT((GType) ((6) << (2))), -1);
1040
1041 ctk_binding_entry_add_signal (binding_set,
1042 CDK_KEY_Down0xff54,
1043 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1044 "move-viewport", 2,
1045 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_STEPS,
1046 G_TYPE_INT((GType) ((6) << (2))), 1);
1047
1048 ctk_binding_entry_add_signal (binding_set,
1049 CDK_KEY_KP_Down0xff99,
1050 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1051 "move-viewport", 2,
1052 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_STEPS,
1053 G_TYPE_INT((GType) ((6) << (2))), 1);
1054
1055 ctk_binding_entry_add_signal (binding_set,
1056 CDK_KEY_Page_Up0xff55,
1057 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1058 "move-viewport", 2,
1059 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_PAGES,
1060 G_TYPE_INT((GType) ((6) << (2))), -1);
1061
1062 ctk_binding_entry_add_signal (binding_set,
1063 CDK_KEY_KP_Page_Up0xff9a,
1064 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1065 "move-viewport", 2,
1066 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_PAGES,
1067 G_TYPE_INT((GType) ((6) << (2))), -1);
1068
1069 ctk_binding_entry_add_signal (binding_set,
1070 CDK_KEY_Page_Down0xff56,
1071 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1072 "move-viewport", 2,
1073 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_PAGES,
1074 G_TYPE_INT((GType) ((6) << (2))), 1);
1075
1076 ctk_binding_entry_add_signal (binding_set,
1077 CDK_KEY_KP_Page_Down0xff9b,
1078 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1079 "move-viewport", 2,
1080 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_PAGES,
1081 G_TYPE_INT((GType) ((6) << (2))), 1);
1082
1083 ctk_binding_entry_add_signal (binding_set,
1084 CDK_KEY_Home0xff50,
1085 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1086 "move-viewport", 2,
1087 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_ENDS,
1088 G_TYPE_INT((GType) ((6) << (2))), -1);
1089
1090 ctk_binding_entry_add_signal (binding_set,
1091 CDK_KEY_KP_Home0xff95,
1092 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1093 "move-viewport", 2,
1094 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_ENDS,
1095 G_TYPE_INT((GType) ((6) << (2))), -1);
1096
1097 ctk_binding_entry_add_signal (binding_set,
1098 CDK_KEY_End0xff57,
1099 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1100 "move-viewport", 2,
1101 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_ENDS,
1102 G_TYPE_INT((GType) ((6) << (2))), 1);
1103
1104 ctk_binding_entry_add_signal (binding_set,
1105 CDK_KEY_KP_End0xff9c,
1106 CDK_MOD1_MASK | CDK_SHIFT_MASK,
1107 "move-viewport", 2,
1108 CTK_TYPE_SCROLL_STEP(ctk_scroll_step_get_type ()), CTK_SCROLL_ENDS,
1109 G_TYPE_INT((GType) ((6) << (2))), 1);
1110
1111 ctk_binding_entry_add_signal (binding_set,
1112 CDK_KEY_percent0x025,
1113 CDK_CONTROL_MASK,
1114 "move-to-matching-bracket", 1,
1115 G_TYPE_BOOLEAN((GType) ((5) << (2))), FALSE(0));
1116
1117 ctk_binding_entry_add_signal (binding_set,
1118 CDK_KEY_a0x061,
1119 CDK_CONTROL_MASK | CDK_SHIFT_MASK,
1120 "change-number", 1,
1121 G_TYPE_INT((GType) ((6) << (2))), 1);
1122
1123 ctk_binding_entry_add_signal (binding_set,
1124 CDK_KEY_x0x078,
1125 CDK_CONTROL_MASK | CDK_SHIFT_MASK,
1126 "change-number", 1,
1127 G_TYPE_INT((GType) ((6) << (2))), -1);
1128}
1129
1130static GObject *
1131ctk_source_view_buildable_get_internal_child (CtkBuildable *buildable,
1132 CtkBuilder *builder,
1133 const gchar *childname)
1134{
1135 CtkSourceView *view = CTK_SOURCE_VIEW (buildable)((((CtkSourceView*) (void *) ((buildable)))));
1136
1137 if (g_strcmp0 (childname, "completion") == 0)
1138 {
1139 return G_OBJECT (ctk_source_view_get_completion (view))((((GObject*) (void *) ((ctk_source_view_get_completion (view
))))))
;
1140 }
1141
1142 return NULL((void*)0);
1143}
1144
1145static void
1146ctk_source_view_buildable_interface_init (CtkBuildableIface *iface)
1147{
1148 iface->get_internal_child = ctk_source_view_buildable_get_internal_child;
1149}
1150
1151static void
1152ctk_source_view_set_property (GObject *object,
1153 guint prop_id,
1154 const GValue *value,
1155 GParamSpec *pspec)
1156{
1157 CtkSourceView *view;
1158
1159 g_return_if_fail (CTK_SOURCE_IS_VIEW (object))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_64
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((object)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_64
= 1; _g_boolean_var_64; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (object)"
); return; } } while (0)
;
1160
1161 view = CTK_SOURCE_VIEW (object)((((CtkSourceView*) (void *) ((object)))));
1162
1163 switch (prop_id)
1164 {
1165 case PROP_SHOW_LINE_NUMBERS:
1166 ctk_source_view_set_show_line_numbers (view, g_value_get_boolean (value));
1167 break;
1168
1169 case PROP_SHOW_LINE_MARKS:
1170 ctk_source_view_set_show_line_marks (view, g_value_get_boolean (value));
1171 break;
1172
1173 case PROP_TAB_WIDTH:
1174 ctk_source_view_set_tab_width (view, g_value_get_uint (value));
1175 break;
1176
1177 case PROP_INDENT_WIDTH:
1178 ctk_source_view_set_indent_width (view, g_value_get_int (value));
1179 break;
1180
1181 case PROP_AUTO_INDENT:
1182 ctk_source_view_set_auto_indent (view, g_value_get_boolean (value));
1183 break;
1184
1185 case PROP_INSERT_SPACES:
1186 ctk_source_view_set_insert_spaces_instead_of_tabs (view, g_value_get_boolean (value));
1187 break;
1188
1189 case PROP_SHOW_RIGHT_MARGIN:
1190 ctk_source_view_set_show_right_margin (view, g_value_get_boolean (value));
1191 break;
1192
1193 case PROP_RIGHT_MARGIN_POSITION:
1194 ctk_source_view_set_right_margin_position (view, g_value_get_uint (value));
1195 break;
1196
1197 case PROP_SMART_HOME_END:
1198 ctk_source_view_set_smart_home_end (view, g_value_get_enum (value));
1199 break;
1200
1201 case PROP_HIGHLIGHT_CURRENT_LINE:
1202 ctk_source_view_set_highlight_current_line (view, g_value_get_boolean (value));
1203 break;
1204
1205 case PROP_INDENT_ON_TAB:
1206 ctk_source_view_set_indent_on_tab (view, g_value_get_boolean (value));
1207 break;
1208
1209 case PROP_BACKGROUND_PATTERN:
1210 ctk_source_view_set_background_pattern (view, g_value_get_enum (value));
1211 break;
1212
1213 case PROP_SMART_BACKSPACE:
1214 ctk_source_view_set_smart_backspace (view, g_value_get_boolean (value));
1215 break;
1216
1217 default:
1218 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'"
, "../ctksourceview/ctksourceview.c", 1218, ("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)
;
1219 break;
1220 }
1221}
1222
1223static void
1224ctk_source_view_get_property (GObject *object,
1225 guint prop_id,
1226 GValue *value,
1227 GParamSpec *pspec)
1228{
1229 CtkSourceView *view;
1230
1231 g_return_if_fail (CTK_SOURCE_IS_VIEW (object))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_65
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((object)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_65
= 1; _g_boolean_var_65; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (object)"
); return; } } while (0)
;
1232
1233 view = CTK_SOURCE_VIEW (object)((((CtkSourceView*) (void *) ((object)))));
1234
1235 switch (prop_id)
1236 {
1237 case PROP_COMPLETION:
1238 g_value_set_object (value, ctk_source_view_get_completion (view));
1239 break;
1240
1241 case PROP_SHOW_LINE_NUMBERS:
1242 g_value_set_boolean (value, ctk_source_view_get_show_line_numbers (view));
1243 break;
1244
1245 case PROP_SHOW_LINE_MARKS:
1246 g_value_set_boolean (value, ctk_source_view_get_show_line_marks (view));
1247 break;
1248
1249 case PROP_TAB_WIDTH:
1250 g_value_set_uint (value, ctk_source_view_get_tab_width (view));
1251 break;
1252
1253 case PROP_INDENT_WIDTH:
1254 g_value_set_int (value, ctk_source_view_get_indent_width (view));
1255 break;
1256
1257 case PROP_AUTO_INDENT:
1258 g_value_set_boolean (value, ctk_source_view_get_auto_indent (view));
1259 break;
1260
1261 case PROP_INSERT_SPACES:
1262 g_value_set_boolean (value, ctk_source_view_get_insert_spaces_instead_of_tabs (view));
1263 break;
1264
1265 case PROP_SHOW_RIGHT_MARGIN:
1266 g_value_set_boolean (value, ctk_source_view_get_show_right_margin (view));
1267 break;
1268
1269 case PROP_RIGHT_MARGIN_POSITION:
1270 g_value_set_uint (value, ctk_source_view_get_right_margin_position (view));
1271 break;
1272
1273 case PROP_SMART_HOME_END:
1274 g_value_set_enum (value, ctk_source_view_get_smart_home_end (view));
1275 break;
1276
1277 case PROP_HIGHLIGHT_CURRENT_LINE:
1278 g_value_set_boolean (value, ctk_source_view_get_highlight_current_line (view));
1279 break;
1280
1281 case PROP_INDENT_ON_TAB:
1282 g_value_set_boolean (value, ctk_source_view_get_indent_on_tab (view));
1283 break;
1284
1285 case PROP_BACKGROUND_PATTERN:
1286 g_value_set_enum (value, ctk_source_view_get_background_pattern (view));
1287 break;
1288
1289 case PROP_SMART_BACKSPACE:
1290 g_value_set_boolean (value, ctk_source_view_get_smart_backspace (view));
1291 break;
1292
1293 case PROP_SPACE_DRAWER:
1294 g_value_set_object (value, ctk_source_view_get_space_drawer (view));
1295 break;
1296
1297 default:
1298 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'"
, "../ctksourceview/ctksourceview.c", 1298, ("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)
;
1299 break;
1300 }
1301}
1302
1303static void
1304space_drawer_notify_cb (CtkSourceSpaceDrawer *space_drawer,
1305 GParamSpec *pspec,
1306 CtkSourceView *view)
1307{
1308 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))));
1309}
1310
1311static void
1312notify_buffer_cb (CtkSourceView *view)
1313{
1314 set_source_buffer (view, ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))))));
1315}
1316
1317static void
1318ctk_source_view_init (CtkSourceView *view)
1319{
1320 CtkStyleContext *context;
1321
1322 CtkTargetList *target_list;
1323
1324 view->priv = ctk_source_view_get_instance_private (view);
1325
1326 view->priv->tab_width = DEFAULT_TAB_WIDTH8;
1327 view->priv->tabs_set = FALSE(0);
1328 view->priv->indent_width = -1;
1329 view->priv->indent_on_tab = TRUE(!(0));
1330 view->priv->smart_home_end = CTK_SOURCE_SMART_HOME_END_DISABLED;
1331 view->priv->right_margin_pos = DEFAULT_RIGHT_MARGIN_POSITION80;
1332 view->priv->cached_right_margin_pos = -1;
1333
1334 ctk_text_view_set_left_margin (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))), 2);
1335 ctk_text_view_set_right_margin (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))), 2);
1336
1337 view->priv->right_margin_line_color = NULL((void*)0);
1338 view->priv->right_margin_overlay_color = NULL((void*)0);
1339
1340 view->priv->space_drawer = ctk_source_space_drawer_new ();
1341 g_signal_connect_object (view->priv->space_drawer,
1342 "notify",
1343 G_CALLBACK (space_drawer_notify_cb)((GCallback) (space_drawer_notify_cb)),
1344 view,
1345 0);
1346
1347 view->priv->mark_categories = g_hash_table_new_full (g_str_hash,
1348 g_str_equal,
1349 (GDestroyNotify) g_free,
1350 (GDestroyNotify) mark_category_free);
1351
1352 target_list = ctk_drag_dest_get_target_list (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))));
1353 g_return_if_fail (target_list != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_66
= 0; if (target_list != ((void*)0)) _g_boolean_var_66 = 1; _g_boolean_var_66
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "target_list != NULL"); return;
} } while (0)
;
1354
1355 ctk_target_list_add_table (target_list, drop_types, G_N_ELEMENTS (drop_types)(sizeof (drop_types) / sizeof ((drop_types)[0])));
1356
1357 ctk_widget_set_has_tooltip (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))), TRUE(!(0)));
1358
1359 g_signal_connect (view,g_signal_connect_data ((view), ("drag_data_received"), (((GCallback
) (view_dnd_drop))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1360 "drag_data_received",g_signal_connect_data ((view), ("drag_data_received"), (((GCallback
) (view_dnd_drop))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1361 G_CALLBACK (view_dnd_drop),g_signal_connect_data ((view), ("drag_data_received"), (((GCallback
) (view_dnd_drop))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1362 NULL)g_signal_connect_data ((view), ("drag_data_received"), (((GCallback
) (view_dnd_drop))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
1363
1364 g_signal_connect (view,g_signal_connect_data ((view), ("notify::buffer"), (((GCallback
) (notify_buffer_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1365 "notify::buffer",g_signal_connect_data ((view), ("notify::buffer"), (((GCallback
) (notify_buffer_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1366 G_CALLBACK (notify_buffer_cb),g_signal_connect_data ((view), ("notify::buffer"), (((GCallback
) (notify_buffer_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1367 NULL)g_signal_connect_data ((view), ("notify::buffer"), (((GCallback
) (notify_buffer_cb))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
1368
1369 context = ctk_widget_get_style_context (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))));
1370 ctk_style_context_add_class (context, "sourceview");
1371}
1372
1373static void
1374ctk_source_view_dispose (GObject *object)
1375{
1376 CtkSourceView *view = CTK_SOURCE_VIEW (object)((((CtkSourceView*) (void *) ((object)))));
1377
1378 g_clear_object (&view->priv->completion)do { _Static_assert (sizeof *((&view->priv->completion
)) == sizeof (gpointer), "Expression evaluates to false"); union
{ char *in; gpointer *out; } _pp; gpointer _p; GDestroyNotify
_destroy = (GDestroyNotify) (g_object_unref); _pp.in = (char
*) ((&view->priv->completion)); _p = *_pp.out; if (
_p) { *_pp.out = ((void*)0); _destroy (_p); } } while (0)
;
1379 g_clear_object (&view->priv->left_gutter)do { _Static_assert (sizeof *((&view->priv->left_gutter
)) == sizeof (gpointer), "Expression evaluates to false"); union
{ char *in; gpointer *out; } _pp; gpointer _p; GDestroyNotify
_destroy = (GDestroyNotify) (g_object_unref); _pp.in = (char
*) ((&view->priv->left_gutter)); _p = *_pp.out; if
(_p) { *_pp.out = ((void*)0); _destroy (_p); } } while (0)
;
1380 g_clear_object (&view->priv->right_gutter)do { _Static_assert (sizeof *((&view->priv->right_gutter
)) == sizeof (gpointer), "Expression evaluates to false"); union
{ char *in; gpointer *out; } _pp; gpointer _p; GDestroyNotify
_destroy = (GDestroyNotify) (g_object_unref); _pp.in = (char
*) ((&view->priv->right_gutter)); _p = *_pp.out; if
(_p) { *_pp.out = ((void*)0); _destroy (_p); } } while (0)
;
1381 g_clear_object (&view->priv->style_scheme)do { _Static_assert (sizeof *((&view->priv->style_scheme
)) == sizeof (gpointer), "Expression evaluates to false"); union
{ char *in; gpointer *out; } _pp; gpointer _p; GDestroyNotify
_destroy = (GDestroyNotify) (g_object_unref); _pp.in = (char
*) ((&view->priv->style_scheme)); _p = *_pp.out; if
(_p) { *_pp.out = ((void*)0); _destroy (_p); } } while (0)
;
1382 g_clear_object (&view->priv->space_drawer)do { _Static_assert (sizeof *((&view->priv->space_drawer
)) == sizeof (gpointer), "Expression evaluates to false"); union
{ char *in; gpointer *out; } _pp; gpointer _p; GDestroyNotify
_destroy = (GDestroyNotify) (g_object_unref); _pp.in = (char
*) ((&view->priv->space_drawer)); _p = *_pp.out; if
(_p) { *_pp.out = ((void*)0); _destroy (_p); } } while (0)
;
1383
1384 remove_source_buffer (view);
1385
1386 /* Disconnect notify buffer because the destroy of the textview will set
1387 * the buffer to NULL, and we call get_buffer in the notify which would
1388 * reinstate a buffer which we don't want.
1389 * There is no problem calling g_signal_handlers_disconnect_by_func()
1390 * several times (if dispose() is called several times).
1391 */
1392 g_signal_handlers_disconnect_by_func (view, notify_buffer_cb, NULL)g_signal_handlers_disconnect_matched ((view), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (notify_buffer_cb), (((void*)0)))
;
1393
1394 G_OBJECT_CLASS (ctk_source_view_parent_class)((((GObjectClass*) (void *) ((ctk_source_view_parent_class)))
))
->dispose (object);
1395}
1396
1397static void
1398ctk_source_view_finalize (GObject *object)
1399{
1400 CtkSourceView *view = CTK_SOURCE_VIEW (object)((((CtkSourceView*) (void *) ((object)))));
1401
1402 if (view->priv->right_margin_line_color != NULL((void*)0))
1403 {
1404 cdk_rgba_free (view->priv->right_margin_line_color);
1405 }
1406
1407 if (view->priv->right_margin_overlay_color != NULL((void*)0))
1408 {
1409 cdk_rgba_free (view->priv->right_margin_overlay_color);
1410 }
1411
1412 if (view->priv->mark_categories)
1413 {
1414 g_hash_table_destroy (view->priv->mark_categories);
1415 }
1416
1417 G_OBJECT_CLASS (ctk_source_view_parent_class)((((GObjectClass*) (void *) ((ctk_source_view_parent_class)))
))
->finalize (object);
1418}
1419
1420static void
1421get_visible_region (CtkTextView *text_view,
1422 CtkTextIter *start,
1423 CtkTextIter *end)
1424{
1425 CdkRectangle visible_rect;
1426
1427 ctk_text_view_get_visible_rect (text_view, &visible_rect);
1428
1429 ctk_text_view_get_line_at_y (text_view,
1430 start,
1431 visible_rect.y,
1432 NULL((void*)0));
1433
1434 ctk_text_view_get_line_at_y (text_view,
1435 end,
1436 visible_rect.y + visible_rect.height,
1437 NULL((void*)0));
1438
1439 ctk_text_iter_backward_line (start);
1440 ctk_text_iter_forward_line (end);
1441}
1442
1443static void
1444highlight_updated_cb (CtkSourceBuffer *buffer,
1445 CtkTextIter *_start,
1446 CtkTextIter *_end,
1447 CtkTextView *text_view)
1448{
1449 CtkTextIter start;
1450 CtkTextIter end;
1451 CtkTextIter visible_start;
1452 CtkTextIter visible_end;
1453 CtkTextIter intersect_start;
1454 CtkTextIter intersect_end;
1455
1456#if 0
1457 {
1458 static gint nth_call = 0;
1459
1460 g_message ("%s(view=%p) %d [%d-%d]",
1461 G_STRFUNC((const char*) (__func__)),
1462 text_view,
1463 ++nth_call,
1464 ctk_text_iter_get_offset (_start),
1465 ctk_text_iter_get_offset (_end));
1466 }
1467#endif
1468
1469 start = *_start;
1470 end = *_end;
1471 ctk_text_iter_order (&start, &end);
1472
1473 get_visible_region (text_view, &visible_start, &visible_end);
1474
1475 if (ctk_text_iter_compare (&end, &visible_start) < 0 ||
1476 ctk_text_iter_compare (&visible_end, &start) < 0)
1477 {
1478 return;
1479 }
1480
1481 if (ctk_text_iter_compare (&start, &visible_start) < 0)
1482 {
1483 intersect_start = visible_start;
1484 }
1485 else
1486 {
1487 intersect_start = start;
1488 }
1489
1490 if (ctk_text_iter_compare (&visible_end, &end) < 0)
1491 {
1492 intersect_end = visible_end;
1493 }
1494 else
1495 {
1496 intersect_end = end;
1497 }
1498
1499 /* CtkSourceContextEngine sends the highlight-updated signal to notify
1500 * the view, and in the view (here) we tell the ContextEngine to update
1501 * the highlighting, but only in the visible area. It seems that the
1502 * purpose is to reduce the number of tags that the ContextEngine
1503 * applies to the buffer.
1504 *
1505 * A previous implementation of this signal handler queued a redraw on
1506 * the view with ctk_widget_queue_draw_area(), instead of calling
1507 * directly _ctk_source_buffer_update_syntax_highlight(). The ::draw
1508 * handler also calls _ctk_source_buffer_update_syntax_highlight(), so
1509 * this had the desired effect, but it was less clear.
1510 * See the Git commit 949cd128064201935f90d999544e6a19f8e3baa6.
1511 * And: https://bugzilla.gnome.org/show_bug.cgi?id=767565
1512 */
1513 _ctk_source_buffer_update_syntax_highlight (buffer,
1514 &intersect_start,
1515 &intersect_end,
1516 FALSE(0));
1517}
1518
1519static void
1520search_start_cb (CtkSourceBufferInternal *buffer_internal,
1521 CtkSourceSearchContext *search_context,
1522 CtkSourceView *view)
1523{
1524 CtkTextIter visible_start;
1525 CtkTextIter visible_end;
1526
1527 get_visible_region (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))), &visible_start, &visible_end);
1528
1529#ifndef G_DISABLE_ASSERT
1530 {
1531 CtkSourceBuffer *buffer_search = ctk_source_search_context_get_buffer (search_context);
1532 g_assert (buffer_search == view->priv->source_buffer)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_67
= 0; if (buffer_search == view->priv->source_buffer) _g_boolean_var_67
= 1; _g_boolean_var_67; }), 1)) ; else g_assertion_message_expr
("CtkSourceView", "../ctksourceview/ctksourceview.c", 1532, (
(const char*) (__func__)), "buffer_search == view->priv->source_buffer"
); } while (0)
;
1533 }
1534#endif
1535
1536 _ctk_source_search_context_update_highlight (search_context,
1537 &visible_start,
1538 &visible_end,
1539 FALSE(0));
1540}
1541
1542static void
1543source_mark_updated_cb (CtkSourceBuffer *buffer,
1544 CtkSourceMark *mark,
1545 CtkTextView *text_view)
1546{
1547 /* TODO do something more intelligent here, namely
1548 * invalidate only the area under the mark if possible */
1549 ctk_widget_queue_draw (CTK_WIDGET (text_view)((((CtkWidget*) (void *) ((text_view))))));
1550}
1551
1552static void
1553buffer_style_scheme_changed_cb (CtkSourceBuffer *buffer,
1554 GParamSpec *pspec,
1555 CtkSourceView *view)
1556{
1557 ctk_source_view_update_style_scheme (view);
1558}
1559
1560static void
1561implicit_trailing_newline_changed_cb (CtkSourceBuffer *buffer,
1562 GParamSpec *pspec,
1563 CtkSourceView *view)
1564{
1565 /* For drawing or not a trailing newline. */
1566 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))));
1567}
1568
1569static void
1570remove_source_buffer (CtkSourceView *view)
1571{
1572 if (view->priv->source_buffer != NULL((void*)0))
1573 {
1574 CtkSourceBufferInternal *buffer_internal;
1575
1576 g_signal_handlers_disconnect_by_func (view->priv->source_buffer,g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (highlight_updated_cb), (view))
1577 highlight_updated_cb,g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (highlight_updated_cb), (view))
1578 view)g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (highlight_updated_cb), (view))
;
1579
1580 g_signal_handlers_disconnect_by_func (view->priv->source_buffer,g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (source_mark_updated_cb), (view))
1581 source_mark_updated_cb,g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (source_mark_updated_cb), (view))
1582 view)g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (source_mark_updated_cb), (view))
;
1583
1584 g_signal_handlers_disconnect_by_func (view->priv->source_buffer,g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (buffer_style_scheme_changed_cb), (view)
)
1585 buffer_style_scheme_changed_cb,g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (buffer_style_scheme_changed_cb), (view)
)
1586 view)g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (buffer_style_scheme_changed_cb), (view)
)
;
1587
1588 g_signal_handlers_disconnect_by_func (view->priv->source_buffer,g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (implicit_trailing_newline_changed_cb), (
view))
1589 implicit_trailing_newline_changed_cb,g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (implicit_trailing_newline_changed_cb), (
view))
1590 view)g_signal_handlers_disconnect_matched ((view->priv->source_buffer
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (implicit_trailing_newline_changed_cb), (
view))
;
1591
1592 buffer_internal = _ctk_source_buffer_internal_get_from_buffer (view->priv->source_buffer);
1593
1594 g_signal_handlers_disconnect_by_func (buffer_internal,g_signal_handlers_disconnect_matched ((buffer_internal), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (search_start_cb), (view))
1595 search_start_cb,g_signal_handlers_disconnect_matched ((buffer_internal), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (search_start_cb), (view))
1596 view)g_signal_handlers_disconnect_matched ((buffer_internal), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (search_start_cb), (view))
;
1597
1598 g_object_unref (view->priv->source_buffer);
1599 view->priv->source_buffer = NULL((void*)0);
1600 }
1601}
1602
1603static void
1604set_source_buffer (CtkSourceView *view,
1605 CtkTextBuffer *buffer)
1606{
1607 if (buffer == (CtkTextBuffer*) view->priv->source_buffer)
1608 {
1609 return;
1610 }
1611
1612 remove_source_buffer (view);
1613
1614 if (CTK_SOURCE_IS_BUFFER (buffer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(buffer)); GType __t = ((ctk_source_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; }))))
)
1615 {
1616 CtkSourceBufferInternal *buffer_internal;
1617
1618 view->priv->source_buffer = g_object_ref (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer))))));
1619
1620 g_signal_connect (buffer,g_signal_connect_data ((buffer), ("highlight-updated"), (((GCallback
) (highlight_updated_cb))), (view), ((void*)0), (GConnectFlags
) 0)
1621 "highlight-updated",g_signal_connect_data ((buffer), ("highlight-updated"), (((GCallback
) (highlight_updated_cb))), (view), ((void*)0), (GConnectFlags
) 0)
1622 G_CALLBACK (highlight_updated_cb),g_signal_connect_data ((buffer), ("highlight-updated"), (((GCallback
) (highlight_updated_cb))), (view), ((void*)0), (GConnectFlags
) 0)
1623 view)g_signal_connect_data ((buffer), ("highlight-updated"), (((GCallback
) (highlight_updated_cb))), (view), ((void*)0), (GConnectFlags
) 0)
;
1624
1625 g_signal_connect (buffer,g_signal_connect_data ((buffer), ("source-mark-updated"), (((
GCallback) (source_mark_updated_cb))), (view), ((void*)0), (GConnectFlags
) 0)
1626 "source-mark-updated",g_signal_connect_data ((buffer), ("source-mark-updated"), (((
GCallback) (source_mark_updated_cb))), (view), ((void*)0), (GConnectFlags
) 0)
1627 G_CALLBACK (source_mark_updated_cb),g_signal_connect_data ((buffer), ("source-mark-updated"), (((
GCallback) (source_mark_updated_cb))), (view), ((void*)0), (GConnectFlags
) 0)
1628 view)g_signal_connect_data ((buffer), ("source-mark-updated"), (((
GCallback) (source_mark_updated_cb))), (view), ((void*)0), (GConnectFlags
) 0)
;
1629
1630 g_signal_connect (buffer,g_signal_connect_data ((buffer), ("notify::style-scheme"), ((
(GCallback) (buffer_style_scheme_changed_cb))), (view), ((void
*)0), (GConnectFlags) 0)
1631 "notify::style-scheme",g_signal_connect_data ((buffer), ("notify::style-scheme"), ((
(GCallback) (buffer_style_scheme_changed_cb))), (view), ((void
*)0), (GConnectFlags) 0)
1632 G_CALLBACK (buffer_style_scheme_changed_cb),g_signal_connect_data ((buffer), ("notify::style-scheme"), ((
(GCallback) (buffer_style_scheme_changed_cb))), (view), ((void
*)0), (GConnectFlags) 0)
1633 view)g_signal_connect_data ((buffer), ("notify::style-scheme"), ((
(GCallback) (buffer_style_scheme_changed_cb))), (view), ((void
*)0), (GConnectFlags) 0)
;
1634
1635 g_signal_connect (buffer,g_signal_connect_data ((buffer), ("notify::implicit-trailing-newline"
), (((GCallback) (implicit_trailing_newline_changed_cb))), (view
), ((void*)0), (GConnectFlags) 0)
1636 "notify::implicit-trailing-newline",g_signal_connect_data ((buffer), ("notify::implicit-trailing-newline"
), (((GCallback) (implicit_trailing_newline_changed_cb))), (view
), ((void*)0), (GConnectFlags) 0)
1637 G_CALLBACK (implicit_trailing_newline_changed_cb),g_signal_connect_data ((buffer), ("notify::implicit-trailing-newline"
), (((GCallback) (implicit_trailing_newline_changed_cb))), (view
), ((void*)0), (GConnectFlags) 0)
1638 view)g_signal_connect_data ((buffer), ("notify::implicit-trailing-newline"
), (((GCallback) (implicit_trailing_newline_changed_cb))), (view
), ((void*)0), (GConnectFlags) 0)
;
1639
1640 buffer_internal = _ctk_source_buffer_internal_get_from_buffer (view->priv->source_buffer);
1641
1642 g_signal_connect (buffer_internal,g_signal_connect_data ((buffer_internal), ("search-start"), (
((GCallback) (search_start_cb))), (view), ((void*)0), (GConnectFlags
) 0)
1643 "search-start",g_signal_connect_data ((buffer_internal), ("search-start"), (
((GCallback) (search_start_cb))), (view), ((void*)0), (GConnectFlags
) 0)
1644 G_CALLBACK (search_start_cb),g_signal_connect_data ((buffer_internal), ("search-start"), (
((GCallback) (search_start_cb))), (view), ((void*)0), (GConnectFlags
) 0)
1645 view)g_signal_connect_data ((buffer_internal), ("search-start"), (
((GCallback) (search_start_cb))), (view), ((void*)0), (GConnectFlags
) 0)
;
1646 }
1647
1648 ctk_source_view_update_style_scheme (view);
1649}
1650
1651static void
1652scroll_to_insert (CtkSourceView *view,
1653 CtkTextBuffer *buffer)
1654{
1655 CtkTextMark *insert;
1656 CtkTextIter iter;
1657 CdkRectangle visible, location;
1658
1659 insert = ctk_text_buffer_get_insert (buffer);
1660 ctk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
1661
1662 ctk_text_view_get_visible_rect (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))), &visible);
1663 ctk_text_view_get_iter_location (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))), &iter, &location);
1664
1665 if (location.y < visible.y || visible.y + visible.height < location.y)
1666 {
1667 ctk_text_view_scroll_to_mark (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))),
1668 insert,
1669 0.0,
1670 TRUE(!(0)),
1671 0.5, 0.5);
1672 }
1673 else if (location.x < visible.x || visible.x + visible.width < location.x)
1674 {
1675 gdouble position;
1676 CtkAdjustment *adjustment;
1677
1678 /* We revert the vertical position of the view because
1679 * _scroll_to_iter will cause it to move and the
1680 * insert mark is already visible vertically. */
1681
1682 adjustment = ctk_scrollable_get_vadjustment (CTK_SCROLLABLE (view)((((CtkScrollable*) (void *) ((view))))));
1683 position = ctk_adjustment_get_value (adjustment);
1684
1685 /* Must use _to_iter as _to_mark scrolls in an
1686 * idle handler and would prevent use from
1687 * reverting the vertical position of the view. */
1688 ctk_text_view_scroll_to_iter (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))),
1689 &iter,
1690 0.0,
1691 TRUE(!(0)),
1692 0.5, 0.0);
1693
1694 ctk_adjustment_set_value (adjustment, position);
1695 }
1696}
1697
1698static void
1699ctk_source_view_undo (CtkSourceView *view)
1700{
1701 CtkTextBuffer *buffer;
1702
1703 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_68
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_68
= 1; _g_boolean_var_68; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
1704
1705 buffer = ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
1706
1707 if (ctk_text_view_get_editable (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))))) &&
1708 CTK_SOURCE_IS_BUFFER (buffer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(buffer)); GType __t = ((ctk_source_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; }))))
&&
1709 ctk_source_buffer_can_undo (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer)))))))
1710 {
1711 ctk_source_buffer_undo (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer))))));
1712 scroll_to_insert (view, buffer);
1713 }
1714}
1715
1716static void
1717ctk_source_view_redo (CtkSourceView *view)
1718{
1719 CtkTextBuffer *buffer;
1720
1721 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_69
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_69
= 1; _g_boolean_var_69; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
1722
1723 buffer = ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
1724
1725 if (ctk_text_view_get_editable (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))))) &&
1726 CTK_SOURCE_IS_BUFFER (buffer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(buffer)); GType __t = ((ctk_source_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; }))))
&&
1727 ctk_source_buffer_can_redo (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer)))))))
1728 {
1729 ctk_source_buffer_redo (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer))))));
1730 scroll_to_insert (view, buffer);
1731 }
1732}
1733
1734static void
1735ctk_source_view_show_completion_real (CtkSourceView *view)
1736{
1737 CtkSourceCompletion *completion;
1738 CtkSourceCompletionContext *context;
1739
1740 completion = ctk_source_view_get_completion (view);
1741 context = ctk_source_completion_create_context (completion, NULL((void*)0));
1742
1743 ctk_source_completion_start (completion,
1744 ctk_source_completion_get_providers (completion),
1745 context);
1746}
1747
1748static void
1749menu_item_activate_change_case_cb (CtkWidget *menu_item,
1750 CtkTextView *text_view)
1751{
1752 CtkTextBuffer *buffer;
1753 CtkTextIter start, end;
1754
1755 buffer = ctk_text_view_get_buffer (text_view);
1756 if (!CTK_SOURCE_IS_BUFFER (buffer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(buffer)); GType __t = ((ctk_source_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; }))))
)
1757 {
1758 return;
1759 }
1760
1761 if (ctk_text_buffer_get_selection_bounds (buffer, &start, &end))
1762 {
1763 CtkSourceChangeCaseType case_type;
1764
1765 case_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "change-case"))((gint) (glong) (g_object_get_data (((((GObject*) (void *) ((
menu_item))))), "change-case")))
;
1766 ctk_source_buffer_change_case (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer))))), case_type, &start, &end);
1767 }
1768}
1769
1770static void
1771menu_item_activate_cb (CtkWidget *menu_item,
1772 CtkTextView *text_view)
1773{
1774 const gchar *ctksignal;
1775
1776 ctksignal = g_object_get_data (G_OBJECT (menu_item)((((GObject*) (void *) ((menu_item))))), "ctk-signal");
1777 g_signal_emit_by_name (G_OBJECT (text_view)((((GObject*) (void *) ((text_view))))), ctksignal);
1778}
1779
1780static void
1781ctk_source_view_populate_popup (CtkTextView *text_view,
1782 CtkWidget *popup)
1783{
1784 CtkTextBuffer *buffer;
1785 CtkMenuShell *menu;
1786 CtkWidget *menu_item;
1787 CtkMenuShell *case_menu;
1788
1789 buffer = ctk_text_view_get_buffer (text_view);
1790 if (!CTK_SOURCE_IS_BUFFER (buffer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(buffer)); GType __t = ((ctk_source_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; }))))
)
1791 {
1792 return;
1793 }
1794
1795 if (!CTK_IS_MENU_SHELL (popup)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(popup)); GType __t = ((ctk_menu_shell_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; }))))
)
1796 {
1797 return;
1798 }
1799
1800 menu = CTK_MENU_SHELL (popup)((((CtkMenuShell*) (void *) ((popup)))));
1801
1802 if (_ctk_source_buffer_is_undo_redo_enabled (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer)))))))
1803 {
1804 /* separator */
1805 menu_item = ctk_separator_menu_item_new ();
1806 ctk_menu_shell_prepend (menu, menu_item);
1807 ctk_widget_show (menu_item);
1808
1809 /* create redo menu_item. */
1810 menu_item = ctk_menu_item_new_with_mnemonic (_("_Redo")((char *) g_dgettext ("ctksourceview-4", "_Redo")));
1811 g_object_set_data (G_OBJECT (menu_item)((((GObject*) (void *) ((menu_item))))), "ctk-signal", (gpointer)"redo");
1812 g_signal_connect (G_OBJECT (menu_item), "activate",g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_cb))), (
text_view), ((void*)0), (GConnectFlags) 0)
1813 G_CALLBACK (menu_item_activate_cb), text_view)g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_cb))), (
text_view), ((void*)0), (GConnectFlags) 0)
;
1814 ctk_menu_shell_prepend (menu, menu_item);
1815 ctk_widget_set_sensitive (menu_item,
1816 (ctk_text_view_get_editable (text_view) &&
1817 ctk_source_buffer_can_redo (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer))))))));
1818 ctk_widget_show (menu_item);
1819
1820 /* create undo menu_item. */
1821 menu_item = ctk_menu_item_new_with_mnemonic (_("_Undo")((char *) g_dgettext ("ctksourceview-4", "_Undo")));
1822 g_object_set_data (G_OBJECT (menu_item)((((GObject*) (void *) ((menu_item))))), "ctk-signal", (gpointer)"undo");
1823 g_signal_connect (G_OBJECT (menu_item), "activate",g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_cb))), (
text_view), ((void*)0), (GConnectFlags) 0)
1824 G_CALLBACK (menu_item_activate_cb), text_view)g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_cb))), (
text_view), ((void*)0), (GConnectFlags) 0)
;
1825 ctk_menu_shell_prepend (menu, menu_item);
1826 ctk_widget_set_sensitive (menu_item,
1827 (ctk_text_view_get_editable (text_view) &&
1828 ctk_source_buffer_can_undo (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer))))))));
1829 ctk_widget_show (menu_item);
1830 }
1831
1832 /* separator */
1833 menu_item = ctk_separator_menu_item_new ();
1834 ctk_menu_shell_append (menu, menu_item);
1835 ctk_widget_show (menu_item);
1836
1837 /* create change case menu */
1838 case_menu = CTK_MENU_SHELL (ctk_menu_new ())((((CtkMenuShell*) (void *) ((ctk_menu_new ())))));
1839
1840 menu_item = ctk_menu_item_new_with_mnemonic (_("All _Upper Case")((char *) g_dgettext ("ctksourceview-4", "All _Upper Case")));
1841 g_object_set_data (G_OBJECT (menu_item)((((GObject*) (void *) ((menu_item))))), "change-case", GINT_TO_POINTER(CTK_SOURCE_CHANGE_CASE_UPPER)((gpointer) (glong) (CTK_SOURCE_CHANGE_CASE_UPPER)));
1842 g_signal_connect (G_OBJECT (menu_item), "activate",g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_change_case_cb
))), (text_view), ((void*)0), (GConnectFlags) 0)
1843 G_CALLBACK (menu_item_activate_change_case_cb), text_view)g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_change_case_cb
))), (text_view), ((void*)0), (GConnectFlags) 0)
;
1844 ctk_menu_shell_append (case_menu, menu_item);
1845 ctk_widget_set_sensitive (menu_item,
1846 (ctk_text_view_get_editable (text_view) &&
1847 ctk_text_buffer_get_has_selection (buffer)));
1848 ctk_widget_show (menu_item);
1849
1850 menu_item = ctk_menu_item_new_with_mnemonic (_("All _Lower Case")((char *) g_dgettext ("ctksourceview-4", "All _Lower Case")));
1851 g_object_set_data (G_OBJECT (menu_item)((((GObject*) (void *) ((menu_item))))), "change-case", GINT_TO_POINTER(CTK_SOURCE_CHANGE_CASE_LOWER)((gpointer) (glong) (CTK_SOURCE_CHANGE_CASE_LOWER)));
1852 g_signal_connect (G_OBJECT (menu_item), "activate",g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_change_case_cb
))), (text_view), ((void*)0), (GConnectFlags) 0)
1853 G_CALLBACK (menu_item_activate_change_case_cb), text_view)g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_change_case_cb
))), (text_view), ((void*)0), (GConnectFlags) 0)
;
1854 ctk_menu_shell_append (case_menu, menu_item);
1855 ctk_widget_set_sensitive (menu_item,
1856 (ctk_text_view_get_editable (text_view) &&
1857 ctk_text_buffer_get_has_selection (buffer)));
1858 ctk_widget_show (menu_item);
1859
1860 menu_item = ctk_menu_item_new_with_mnemonic (_("_Invert Case")((char *) g_dgettext ("ctksourceview-4", "_Invert Case")));
1861 g_object_set_data (G_OBJECT (menu_item)((((GObject*) (void *) ((menu_item))))), "change-case", GINT_TO_POINTER(CTK_SOURCE_CHANGE_CASE_TOGGLE)((gpointer) (glong) (CTK_SOURCE_CHANGE_CASE_TOGGLE)));
1862 g_signal_connect (G_OBJECT (menu_item), "activate",g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_change_case_cb
))), (text_view), ((void*)0), (GConnectFlags) 0)
1863 G_CALLBACK (menu_item_activate_change_case_cb), text_view)g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_change_case_cb
))), (text_view), ((void*)0), (GConnectFlags) 0)
;
1864 ctk_menu_shell_append (case_menu, menu_item);
1865 ctk_widget_set_sensitive (menu_item,
1866 (ctk_text_view_get_editable (text_view) &&
1867 ctk_text_buffer_get_has_selection (buffer)));
1868 ctk_widget_show (menu_item);
1869
1870 menu_item = ctk_menu_item_new_with_mnemonic (_("_Title Case")((char *) g_dgettext ("ctksourceview-4", "_Title Case")));
1871 g_object_set_data (G_OBJECT (menu_item)((((GObject*) (void *) ((menu_item))))), "change-case", GINT_TO_POINTER(CTK_SOURCE_CHANGE_CASE_TITLE)((gpointer) (glong) (CTK_SOURCE_CHANGE_CASE_TITLE)));
1872 g_signal_connect (G_OBJECT (menu_item), "activate",g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_change_case_cb
))), (text_view), ((void*)0), (GConnectFlags) 0)
1873 G_CALLBACK (menu_item_activate_change_case_cb), text_view)g_signal_connect_data ((((((GObject*) (void *) ((menu_item)))
))), ("activate"), (((GCallback) (menu_item_activate_change_case_cb
))), (text_view), ((void*)0), (GConnectFlags) 0)
;
1874 ctk_menu_shell_append (case_menu, menu_item);
1875 ctk_widget_set_sensitive (menu_item,
1876 (ctk_text_view_get_editable (text_view) &&
1877 ctk_text_buffer_get_has_selection (buffer)));
1878 ctk_widget_show (menu_item);
1879
1880 menu_item = ctk_menu_item_new_with_mnemonic (_("C_hange Case")((char *) g_dgettext ("ctksourceview-4", "C_hange Case")));
1881 ctk_menu_item_set_submenu (CTK_MENU_ITEM (menu_item)((((CtkMenuItem*) (void *) ((menu_item))))), CTK_WIDGET (case_menu)((((CtkWidget*) (void *) ((case_menu))))));
1882 ctk_menu_shell_append (menu, menu_item);
1883 ctk_widget_set_sensitive (menu_item,
1884 (ctk_text_view_get_editable (text_view) &&
1885 ctk_text_buffer_get_has_selection (buffer)));
1886 ctk_widget_show (menu_item);
1887}
1888
1889static void
1890move_cursor (CtkTextView *text_view,
1891 const CtkTextIter *new_location,
1892 gboolean extend_selection)
1893{
1894 CtkTextBuffer *buffer = ctk_text_view_get_buffer (text_view);
1895 CtkTextMark *insert = ctk_text_buffer_get_insert (buffer);
1896
1897 if (extend_selection)
1898 {
1899 ctk_text_buffer_move_mark (buffer, insert, new_location);
1900 }
1901 else
1902 {
1903 ctk_text_buffer_place_cursor (buffer, new_location);
1904 }
1905
1906 ctk_text_view_scroll_mark_onscreen (text_view, insert);
1907}
1908
1909static void
1910move_to_first_char (CtkTextView *text_view,
1911 CtkTextIter *iter,
1912 gboolean display_line)
1913{
1914 CtkTextIter last;
1915
1916 last = *iter;
1917
1918 if (display_line)
1919 {
1920 ctk_text_view_backward_display_line_start (text_view, iter);
1921 ctk_text_view_forward_display_line_end (text_view, &last);
1922 }
1923 else
1924 {
1925 ctk_text_iter_set_line_offset (iter, 0);
1926
1927 if (!ctk_text_iter_ends_line (&last))
1928 {
1929 ctk_text_iter_forward_to_line_end (&last);
1930 }
1931 }
1932
1933
1934 while (ctk_text_iter_compare (iter, &last) < 0)
1935 {
1936 gunichar c;
1937
1938 c = ctk_text_iter_get_char (iter);
1939
1940 if (g_unichar_isspace (c))
1941 {
1942 if (!ctk_text_iter_forward_visible_cursor_position (iter))
1943 {
1944 break;
1945 }
1946 }
1947 else
1948 {
1949 break;
1950 }
1951 }
1952}
1953
1954static void
1955move_to_last_char (CtkTextView *text_view,
1956 CtkTextIter *iter,
1957 gboolean display_line)
1958{
1959 CtkTextIter first;
1960
1961 first = *iter;
1962
1963 if (display_line)
1964 {
1965 ctk_text_view_forward_display_line_end (text_view, iter);
1966 ctk_text_view_backward_display_line_start (text_view, &first);
1967 }
1968 else
1969 {
1970 if (!ctk_text_iter_ends_line (iter))
1971 {
1972 ctk_text_iter_forward_to_line_end (iter);
1973 }
1974
1975 ctk_text_iter_set_line_offset (&first, 0);
1976 }
1977
1978 while (ctk_text_iter_compare (iter, &first) > 0)
1979 {
1980 gunichar c;
1981
1982 if (!ctk_text_iter_backward_visible_cursor_position (iter))
1983 {
1984 break;
1985 }
1986
1987 c = ctk_text_iter_get_char (iter);
1988
1989 if (!g_unichar_isspace (c))
1990 {
1991 /* We've gone one cursor position too far. */
1992 ctk_text_iter_forward_visible_cursor_position (iter);
1993 break;
1994 }
1995 }
1996}
1997
1998static void
1999do_cursor_move_home_end (CtkTextView *text_view,
2000 CtkTextIter *cur,
2001 CtkTextIter *iter,
2002 gboolean extend_selection,
2003 gint count)
2004{
2005 /* if we are clearing selection, we need to move_cursor even
2006 * if we are at proper iter because selection_bound may need
2007 * to be moved */
2008 if (!ctk_text_iter_equal (cur, iter) || !extend_selection)
2009 {
2010 move_cursor (text_view, iter, extend_selection);
2011 g_signal_emit (text_view, signals[SMART_HOME_END], 0, iter, count);
2012 }
2013}
2014
2015/* Returns %TRUE if handled. */
2016static gboolean
2017move_cursor_smart_home_end (CtkTextView *text_view,
2018 CtkMovementStep step,
2019 gint count,
2020 gboolean extend_selection)
2021{
2022 CtkSourceView *source_view = CTK_SOURCE_VIEW (text_view)((((CtkSourceView*) (void *) ((text_view)))));
2023 CtkTextBuffer *buffer = ctk_text_view_get_buffer (text_view);
2024 gboolean move_display_line;
2025 CtkTextMark *mark;
2026 CtkTextIter cur;
2027 CtkTextIter iter;
2028
2029 g_assert (step == CTK_MOVEMENT_DISPLAY_LINE_ENDS ||do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_70
= 0; if (step == CTK_MOVEMENT_DISPLAY_LINE_ENDS || step == CTK_MOVEMENT_PARAGRAPH_ENDS
) _g_boolean_var_70 = 1; _g_boolean_var_70; }), 1)) ; else g_assertion_message_expr
("CtkSourceView", "../ctksourceview/ctksourceview.c", 2030, (
(const char*) (__func__)), "step == CTK_MOVEMENT_DISPLAY_LINE_ENDS || step == CTK_MOVEMENT_PARAGRAPH_ENDS"
); } while (0)
2030 step == CTK_MOVEMENT_PARAGRAPH_ENDS)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_70
= 0; if (step == CTK_MOVEMENT_DISPLAY_LINE_ENDS || step == CTK_MOVEMENT_PARAGRAPH_ENDS
) _g_boolean_var_70 = 1; _g_boolean_var_70; }), 1)) ; else g_assertion_message_expr
("CtkSourceView", "../ctksourceview/ctksourceview.c", 2030, (
(const char*) (__func__)), "step == CTK_MOVEMENT_DISPLAY_LINE_ENDS || step == CTK_MOVEMENT_PARAGRAPH_ENDS"
); } while (0)
;
2031
2032 move_display_line = step == CTK_MOVEMENT_DISPLAY_LINE_ENDS;
2033
2034 mark = ctk_text_buffer_get_insert (buffer);
2035 ctk_text_buffer_get_iter_at_mark (buffer, &cur, mark);
2036 iter = cur;
2037
2038 if (count == -1)
2039 {
2040 gboolean at_home;
2041
2042 move_to_first_char (text_view, &iter, move_display_line);
2043
2044 if (move_display_line)
2045 {
2046 at_home = ctk_text_view_starts_display_line (text_view, &cur);
2047 }
2048 else
2049 {
2050 at_home = ctk_text_iter_starts_line (&cur);
2051 }
2052
2053 switch (source_view->priv->smart_home_end)
2054 {
2055 case CTK_SOURCE_SMART_HOME_END_BEFORE:
2056 if (!ctk_text_iter_equal (&cur, &iter) || at_home)
2057 {
2058 do_cursor_move_home_end (text_view,
2059 &cur,
2060 &iter,
2061 extend_selection,
2062 count);
2063 return TRUE(!(0));
2064 }
2065 break;
2066
2067 case CTK_SOURCE_SMART_HOME_END_AFTER:
2068 if (at_home)
2069 {
2070 do_cursor_move_home_end (text_view,
2071 &cur,
2072 &iter,
2073 extend_selection,
2074 count);
2075 return TRUE(!(0));
2076 }
2077 break;
2078
2079 case CTK_SOURCE_SMART_HOME_END_ALWAYS:
2080 do_cursor_move_home_end (text_view,
2081 &cur,
2082 &iter,
2083 extend_selection,
2084 count);
2085 return TRUE(!(0));
2086
2087 case CTK_SOURCE_SMART_HOME_END_DISABLED:
2088 default:
2089 break;
2090 }
2091 }
2092 else if (count == 1)
2093 {
2094 gboolean at_end;
2095
2096 move_to_last_char (text_view, &iter, move_display_line);
2097
2098 if (move_display_line)
2099 {
2100 CtkTextIter display_end;
2101 display_end = cur;
2102
2103 ctk_text_view_forward_display_line_end (text_view, &display_end);
2104 at_end = ctk_text_iter_equal (&cur, &display_end);
2105 }
2106 else
2107 {
2108 at_end = ctk_text_iter_ends_line (&cur);
2109 }
2110
2111 switch (source_view->priv->smart_home_end)
2112 {
2113 case CTK_SOURCE_SMART_HOME_END_BEFORE:
2114 if (!ctk_text_iter_equal (&cur, &iter) || at_end)
2115 {
2116 do_cursor_move_home_end (text_view,
2117 &cur,
2118 &iter,
2119 extend_selection,
2120 count);
2121 return TRUE(!(0));
2122 }
2123 break;
2124
2125 case CTK_SOURCE_SMART_HOME_END_AFTER:
2126 if (at_end)
2127 {
2128 do_cursor_move_home_end (text_view,
2129 &cur,
2130 &iter,
2131 extend_selection,
2132 count);
2133 return TRUE(!(0));
2134 }
2135 break;
2136
2137 case CTK_SOURCE_SMART_HOME_END_ALWAYS:
2138 do_cursor_move_home_end (text_view,
2139 &cur,
2140 &iter,
2141 extend_selection,
2142 count);
2143 return TRUE(!(0));
2144
2145 case CTK_SOURCE_SMART_HOME_END_DISABLED:
2146 default:
2147 break;
2148 }
2149 }
2150
2151 return FALSE(0);
2152}
2153
2154static void
2155move_cursor_words (CtkTextView *text_view,
2156 gint count,
2157 gboolean extend_selection)
2158{
2159 CtkTextBuffer *buffer;
2160 CtkTextIter insert;
2161 CtkTextIter newplace;
2162 CtkTextIter line_start;
2163 CtkTextIter line_end;
2164 const gchar *ptr;
2165 gchar *line_text;
2166
2167 buffer = ctk_text_view_get_buffer (text_view);
2168
2169 ctk_text_buffer_get_iter_at_mark (buffer,
2170 &insert,
2171 ctk_text_buffer_get_insert (buffer));
2172
2173 line_start = line_end = newplace = insert;
2174
2175 /* Get the text of the current line for RTL analysis */
2176 ctk_text_iter_set_line_offset (&line_start, 0);
2177 ctk_text_iter_forward_line (&line_end);
2178 line_text = ctk_text_iter_get_visible_text (&line_start, &line_end);
2179
2180 /* Swap direction for RTL to maintain visual cursor movement.
2181 * Otherwise, cursor will move in opposite direction which is counter
2182 * intuitve and causes confusion for RTL users.
2183 *
2184 * You would think we could iterate using the textiter, but we cannot
2185 * since there is no way in CtkTextIter to check if it is visible (as
2186 * that is not exposed by CtkTextBTree). So we use the allocated string
2187 * contents instead.
2188 */
2189 for (ptr = line_text; *ptr; ptr = g_utf8_next_char (ptr)((ptr) + g_utf8_skip[*(const guchar *)(ptr)]))
2190 {
2191 gunichar ch = g_utf8_get_char (ptr);
2192 FriBidiCharType ch_type = fribidi_get_bidi_type (ch);
2193
2194 if (FRIBIDI_IS_STRONG (ch_type)((ch_type) & 0x00000010L))
2195 {
2196 if (FRIBIDI_IS_RTL (ch_type)((ch_type) & 0x00000001L))
2197 {
2198 count *= -1;
2199 }
2200
2201 break;
2202 }
2203 }
2204
2205 g_free (line_text);
2206
2207 if (count < 0)
2208 {
2209 if (!_ctk_source_iter_backward_visible_word_starts (&newplace, -count))
2210 {
2211 ctk_text_iter_set_line_offset (&newplace, 0);
2212 }
2213 }
2214 else if (count > 0)
2215 {
2216 if (!_ctk_source_iter_forward_visible_word_ends (&newplace, count))
2217 {
2218 ctk_text_iter_forward_to_line_end (&newplace);
2219 }
2220 }
2221
2222 move_cursor (text_view, &newplace, extend_selection);
2223}
2224
2225static void
2226ctk_source_view_move_cursor (CtkTextView *text_view,
2227 CtkMovementStep step,
2228 gint count,
2229 gboolean extend_selection)
2230{
2231 if (!ctk_text_view_get_cursor_visible (text_view))
2232 {
2233 goto chain_up;
2234 }
2235
2236 ctk_text_view_reset_im_context (text_view);
2237
2238 switch (step)
2239 {
2240 case CTK_MOVEMENT_DISPLAY_LINE_ENDS:
2241 case CTK_MOVEMENT_PARAGRAPH_ENDS:
2242 if (move_cursor_smart_home_end (text_view, step, count, extend_selection))
2243 {
2244 return;
2245 }
2246 break;
2247
2248 case CTK_MOVEMENT_WORDS:
2249 move_cursor_words (text_view, count, extend_selection);
2250 return;
2251
2252 case CTK_MOVEMENT_LOGICAL_POSITIONS:
2253 case CTK_MOVEMENT_VISUAL_POSITIONS:
2254 case CTK_MOVEMENT_DISPLAY_LINES:
2255 case CTK_MOVEMENT_PARAGRAPHS:
2256 case CTK_MOVEMENT_PAGES:
2257 case CTK_MOVEMENT_BUFFER_ENDS:
2258 case CTK_MOVEMENT_HORIZONTAL_PAGES:
2259 default:
2260 break;
2261 }
2262
2263chain_up:
2264 CTK_TEXT_VIEW_CLASS (ctk_source_view_parent_class)((((CtkTextViewClass*) (void *) ((ctk_source_view_parent_class
)))))
->move_cursor (text_view,
2265 step,
2266 count,
2267 extend_selection);
2268}
2269
2270static void
2271ctk_source_view_delete_from_cursor (CtkTextView *text_view,
2272 CtkDeleteType type,
2273 gint count)
2274{
2275 CtkTextBuffer *buffer = ctk_text_view_get_buffer (text_view);
2276 CtkTextIter insert;
2277 CtkTextIter start;
2278 CtkTextIter end;
2279
2280 if (type != CTK_DELETE_WORD_ENDS)
2281 {
2282 CTK_TEXT_VIEW_CLASS (ctk_source_view_parent_class)((((CtkTextViewClass*) (void *) ((ctk_source_view_parent_class
)))))
->delete_from_cursor (text_view,
2283 type,
2284 count);
2285 return;
2286 }
2287
2288 ctk_text_view_reset_im_context (text_view);
2289
2290 ctk_text_buffer_get_iter_at_mark (buffer,
2291 &insert,
2292 ctk_text_buffer_get_insert (buffer));
2293
2294 start = insert;
2295 end = insert;
2296
2297 if (count > 0)
2298 {
2299 if (!_ctk_source_iter_forward_visible_word_ends (&end, count))
2300 {
2301 ctk_text_iter_forward_to_line_end (&end);
2302 }
2303 }
2304 else
2305 {
2306 if (!_ctk_source_iter_backward_visible_word_starts (&start, -count))
2307 {
2308 ctk_text_iter_set_line_offset (&start, 0);
2309 }
2310 }
2311
2312 ctk_text_buffer_delete_interactive (buffer, &start, &end,
2313 ctk_text_view_get_editable (text_view));
2314}
2315
2316static gboolean
2317ctk_source_view_extend_selection (CtkTextView *text_view,
2318 CtkTextExtendSelection granularity,
2319 const CtkTextIter *location,
2320 CtkTextIter *start,
2321 CtkTextIter *end)
2322{
2323 if (granularity == CTK_TEXT_EXTEND_SELECTION_WORD)
2324 {
2325 _ctk_source_iter_extend_selection_word (location, start, end);
2326 return CDK_EVENT_STOP((!(0)));
2327 }
2328
2329 return CTK_TEXT_VIEW_CLASS (ctk_source_view_parent_class)((((CtkTextViewClass*) (void *) ((ctk_source_view_parent_class
)))))
->extend_selection (text_view,
2330 granularity,
2331 location,
2332 start,
2333 end);
2334}
2335
2336static void
2337ctk_source_view_ensure_redrawn_rect_is_highlighted (CtkSourceView *view,
2338 cairo_t *cr)
2339{
2340 CdkRectangle clip;
2341 CtkTextIter iter1, iter2;
2342
2343 if (view->priv->source_buffer == NULL((void*)0) ||
2344 !cdk_cairo_get_clip_rectangle (cr, &clip))
2345 {
2346 return;
2347 }
2348
2349 ctk_text_view_get_line_at_y (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))), &iter1, clip.y, NULL((void*)0));
2350 ctk_text_iter_backward_line (&iter1);
2351 ctk_text_view_get_line_at_y (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))), &iter2, clip.y + clip.height, NULL((void*)0));
2352 ctk_text_iter_forward_line (&iter2);
2353
2354 DEBUG ({
2355 g_print (" draw area: %d - %d\n", clip.y, clip.y + clip.height);
2356 g_print (" lines to update: %d - %d\n",
2357 ctk_text_iter_get_line (&iter1),
2358 ctk_text_iter_get_line (&iter2));
2359 });
2360
2361 _ctk_source_buffer_update_syntax_highlight (view->priv->source_buffer,
2362 &iter1, &iter2, FALSE(0));
2363 _ctk_source_buffer_update_search_highlight (view->priv->source_buffer,
2364 &iter1, &iter2, FALSE(0));
2365}
2366
2367/* This function is taken from ctk+/tests/testtext.c */
2368static void
2369ctk_source_view_get_lines (CtkTextView *text_view,
2370 gint first_y,
2371 gint last_y,
2372 GArray *buffer_coords,
2373 GArray *line_heights,
2374 GArray *numbers,
2375 gint *countp)
2376{
2377 CtkTextIter iter;
2378 gint count;
2379 gint last_line_num = -1;
2380
2381 g_array_set_size (buffer_coords, 0);
2382 g_array_set_size (numbers, 0);
2383 if (line_heights != NULL((void*)0))
2384 g_array_set_size (line_heights, 0);
2385
2386 /* Get iter at first y */
2387 ctk_text_view_get_line_at_y (text_view, &iter, first_y, NULL((void*)0));
2388
2389 /* For each iter, get its location and add it to the arrays.
2390 * Stop when we pass last_y */
2391 count = 0;
2392
2393 while (!ctk_text_iter_is_end (&iter))
2394 {
2395 gint y, height;
2396
2397 ctk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2398
2399 g_array_append_val (buffer_coords, y)g_array_append_vals (buffer_coords, &(y), 1);
2400 if (line_heights)
2401 {
2402 g_array_append_val (line_heights, height)g_array_append_vals (line_heights, &(height), 1);
2403 }
2404
2405 last_line_num = ctk_text_iter_get_line (&iter);
2406 g_array_append_val (numbers, last_line_num)g_array_append_vals (numbers, &(last_line_num), 1);
2407
2408 ++count;
2409
2410 if ((y + height) >= last_y)
2411 break;
2412
2413 ctk_text_iter_forward_line (&iter);
2414 }
2415
2416 if (ctk_text_iter_is_end (&iter))
2417 {
2418 gint y, height;
2419 gint line_num;
2420
2421 ctk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2422
2423 line_num = ctk_text_iter_get_line (&iter);
2424
2425 if (line_num != last_line_num)
2426 {
2427 g_array_append_val (buffer_coords, y)g_array_append_vals (buffer_coords, &(y), 1);
2428 if (line_heights)
2429 g_array_append_val (line_heights, height)g_array_append_vals (line_heights, &(height), 1);
2430 g_array_append_val (numbers, line_num)g_array_append_vals (numbers, &(line_num), 1);
2431 ++count;
2432 }
2433 }
2434
2435 *countp = count;
2436}
2437
2438/* Another solution to paint the line background is to use the
2439 * CtkTextTag:paragraph-background property. But there are several issues:
2440 * - CtkTextTags are per buffer, not per view. It's better to keep the line
2441 * highlighting per view.
2442 * - There is a problem for empty lines: a text tag can not be applied to an
2443 * empty region. And it can not be worked around easily for the last line.
2444 *
2445 * See https://bugzilla.gnome.org/show_bug.cgi?id=310847 for more details.
2446 */
2447static void
2448ctk_source_view_paint_line_background (CtkTextView *text_view,
2449 cairo_t *cr,
2450 int y, /* in buffer coordinates */
2451 int height,
2452 const CdkRGBA *color)
2453{
2454 gdouble x1, y1, x2, y2;
2455
2456 cairo_save (cr);
2457 cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
2458
2459 cdk_cairo_set_source_rgba (cr, (CdkRGBA *)color);
2460 cairo_set_line_width (cr, 1);
2461 cairo_rectangle (cr, x1 + .5, y + .5, x2 - x1 - 1, height - 1);
2462 cairo_stroke_preserve (cr);
2463 cairo_fill (cr);
2464 cairo_restore (cr);
2465}
2466
2467static void
2468ctk_source_view_paint_marks_background (CtkSourceView *view,
2469 cairo_t *cr)
2470{
2471 CtkTextView *text_view;
2472 CdkRectangle clip;
2473 GArray *numbers;
2474 GArray *pixels;
2475 GArray *heights;
2476 gint y1, y2;
2477 gint count;
2478 gint i;
2479
2480 if (view->priv->source_buffer == NULL((void*)0) ||
2481 !_ctk_source_buffer_has_source_marks (view->priv->source_buffer) ||
2482 !cdk_cairo_get_clip_rectangle (cr, &clip))
2483 {
2484 return;
2485 }
2486
2487 text_view = CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))));
2488
2489 y1 = clip.y;
2490 y2 = y1 + clip.height;
2491
2492 numbers = g_array_new (FALSE(0), FALSE(0), sizeof (gint));
2493 pixels = g_array_new (FALSE(0), FALSE(0), sizeof (gint));
2494 heights = g_array_new (FALSE(0), FALSE(0), sizeof (gint));
2495
2496 /* get the line numbers and y coordinates. */
2497 ctk_source_view_get_lines (text_view,
2498 y1,
2499 y2,
2500 pixels,
2501 heights,
2502 numbers,
2503 &count);
2504
2505 if (count == 0)
2506 {
2507 gint n = 0;
2508 gint y;
2509 gint height;
2510 CtkTextIter iter;
2511
2512 ctk_text_buffer_get_start_iter (ctk_text_view_get_buffer (text_view), &iter);
2513 ctk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2514
2515 g_array_append_val (pixels, y)g_array_append_vals (pixels, &(y), 1);
2516 g_array_append_val (pixels, height)g_array_append_vals (pixels, &(height), 1);
2517 g_array_append_val (numbers, n)g_array_append_vals (numbers, &(n), 1);
2518 count = 1;
2519 }
2520
2521 DEBUG ({
2522 g_print (" Painting marks background for line numbers %d - %d\n",
2523 g_array_index (numbers, gint, 0),
2524 g_array_index (numbers, gint, count - 1));
2525 });
2526
2527 for (i = 0; i < count; ++i)
2528 {
2529 gint line_to_paint;
2530 GSList *marks;
2531 CdkRGBA background;
2532 int priority;
2533
2534 line_to_paint = g_array_index (numbers, gint, i)(((gint*) (void *) (numbers)->data) [(i)]);
2535
2536 marks = ctk_source_buffer_get_source_marks_at_line (view->priv->source_buffer,
2537 line_to_paint,
2538 NULL((void*)0));
2539
2540 priority = -1;
2541
2542 while (marks != NULL((void*)0))
2543 {
2544 CtkSourceMarkAttributes *attrs;
2545 gint prio;
2546 CdkRGBA bg;
2547
2548 attrs = ctk_source_view_get_mark_attributes (view,
2549 ctk_source_mark_get_category (marks->data),
2550 &prio);
2551
2552 if (attrs != NULL((void*)0) &&
2553 prio > priority &&
2554 ctk_source_mark_attributes_get_background (attrs, &bg))
2555 {
2556 priority = prio;
2557 background = bg;
2558 }
2559
2560 marks = g_slist_delete_link (marks, marks);
2561 }
2562
2563 if (priority != -1)
2564 {
2565 ctk_source_view_paint_line_background (text_view,
2566 cr,
2567 g_array_index (pixels, gint, i)(((gint*) (void *) (pixels)->data) [(i)]),
2568 g_array_index (heights, gint, i)(((gint*) (void *) (heights)->data) [(i)]),
2569 &background);
2570 }
2571 }
2572
2573 g_array_free (heights, TRUE(!(0)));
2574 g_array_free (pixels, TRUE(!(0)));
2575 g_array_free (numbers, TRUE(!(0)));
2576}
2577
2578static void
2579ctk_source_view_paint_right_margin (CtkSourceView *view,
2580 cairo_t *cr)
2581{
2582 CdkRectangle clip;
2583 gdouble x;
2584
2585 CtkTextView *text_view = CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))));
2586
2587#ifdef ENABLE_PROFILE
2588 static GTimer *timer = NULL((void*)0);
2589
2590 if (timer == NULL((void*)0))
2591 {
2592 timer = g_timer_new ();
2593 }
2594
2595 g_timer_start (timer);
2596#endif
2597
2598 g_return_if_fail (view->priv->right_margin_line_color != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_71
= 0; if (view->priv->right_margin_line_color != ((void
*)0)) _g_boolean_var_71 = 1; _g_boolean_var_71; }), 1))) { } else
{ g_return_if_fail_warning ("CtkSourceView", ((const char*) (
__func__)), "view->priv->right_margin_line_color != NULL"
); return; } } while (0)
;
2599
2600 if (!cdk_cairo_get_clip_rectangle (cr, &clip))
2601 {
2602 return;
2603 }
2604
2605 if (view->priv->cached_right_margin_pos < 0)
2606 {
2607 view->priv->cached_right_margin_pos =
2608 calculate_real_tab_width (view,
2609 view->priv->right_margin_pos,
2610 '_');
2611 }
2612
2613 x = view->priv->cached_right_margin_pos + ctk_text_view_get_left_margin (text_view);
2614
2615 cairo_save (cr);
2616 cairo_set_line_width (cr, 1.0);
2617
2618 if (x + 1 >= clip.x && x <= clip.x + clip.width)
2619 {
2620 cairo_move_to (cr, x + 0.5, clip.y);
2621 cairo_line_to (cr, x + 0.5, clip.y + clip.height);
2622
2623 cdk_cairo_set_source_rgba (cr, view->priv->right_margin_line_color);
2624 cairo_stroke (cr);
2625 }
2626
2627 /* Only draw the overlay when the style scheme explicitly sets it. */
2628 if (view->priv->right_margin_overlay_color != NULL((void*)0) && clip.x + clip.width > x + 1)
2629 {
2630 /* Draw the rectangle next to the line (x+1). */
2631 cairo_rectangle (cr,
2632 x + 1, clip.y,
2633 clip.x + clip.width - (x + 1), clip.height);
2634
2635 cdk_cairo_set_source_rgba (cr, view->priv->right_margin_overlay_color);
2636 cairo_fill (cr);
2637 }
2638
2639 cairo_restore (cr);
2640
2641 PROFILE ({
2642 g_timer_stop (timer);
2643 g_print (" ctk_source_view_paint_right_margin time: "
2644 "%g (sec * 1000)\n",
2645 g_timer_elapsed (timer, NULL) * 1000);
2646 });
2647}
2648
2649static gint
2650realign (gint offset,
2651 guint align)
2652{
2653 if (offset > 0 && align > 0)
2654 {
2655 gint padding;
2656
2657 padding = (align - (offset % align)) % align;
2658 return offset + padding;
2659 }
2660
2661 return 0;
2662}
2663
2664static void
2665ctk_source_view_paint_background_pattern_grid (CtkSourceView *view,
2666 cairo_t *cr)
2667{
2668 CdkRectangle clip;
2669 gint x, y, x2, y2;
2670 PangoContext *context;
2671 PangoLayout *layout;
2672 gint grid_width = 16;
2673 gint grid_height = 16;
2674
2675 context = ctk_widget_get_pango_context (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))));
2676 layout = pango_layout_new (context);
2677 pango_layout_set_text (layout, "X", 1);
2678 pango_layout_get_pixel_size (layout, &grid_width, &grid_height);
2679 g_object_unref (layout);
2680
2681 /* each character becomes 2 stacked boxes. */
2682 grid_height = MAX (1, grid_height / 2)(((1) > (grid_height / 2)) ? (1) : (grid_height / 2));
2683 grid_width = MAX (1, grid_width)(((1) > (grid_width)) ? (1) : (grid_width));
2684
2685 cairo_save (cr);
2686
2687 cdk_cairo_get_clip_rectangle (cr, &clip);
2688
2689 cairo_set_line_width (cr, 1.0);
2690 cdk_cairo_set_source_rgba (cr, &view->priv->background_pattern_color);
2691
2692 /* Align our drawing position with a multiple of the grid size. */
2693 x = realign (clip.x - grid_width, grid_width);
2694 y = realign (clip.y - grid_height, grid_height);
2695 x2 = realign (x + clip.width + grid_width * 2, grid_width);
2696 y2 = realign (y + clip.height + grid_height * 2, grid_height);
2697
2698 for (; x <= x2; x += grid_width)
2699 {
2700 cairo_move_to (cr, x + .5, clip.y - .5);
2701 cairo_line_to (cr, x + .5, clip.y + clip.height - .5);
2702 }
2703
2704 for (; y <= y2; y += grid_height)
2705 {
2706 cairo_move_to (cr, clip.x + .5, y - .5);
2707 cairo_line_to (cr, clip.x + clip.width + .5, y - .5);
2708 }
2709
2710 cairo_stroke (cr);
2711 cairo_restore (cr);
2712}
2713
2714static void
2715ctk_source_view_paint_current_line_highlight (CtkSourceView *view,
2716 cairo_t *cr)
2717{
2718 CtkTextBuffer *buffer;
2719 CtkTextIter cur;
2720 gint y;
2721 gint height;
2722
2723 buffer = ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
2724 ctk_text_buffer_get_iter_at_mark (buffer,
2725 &cur,
2726 ctk_text_buffer_get_insert (buffer));
2727 ctk_text_view_get_line_yrange (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))), &cur, &y, &height);
2728
2729 ctk_source_view_paint_line_background (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))),
2730 cr,
2731 y, height,
2732 &view->priv->current_line_color);
2733}
2734
2735static void
2736ctk_source_view_draw_layer (CtkTextView *text_view,
2737 CtkTextViewLayer layer,
2738 cairo_t *cr)
2739{
2740 CtkSourceView *view;
2741
2742 view = CTK_SOURCE_VIEW (text_view)((((CtkSourceView*) (void *) ((text_view)))));
2743
2744 cairo_save (cr);
2745
2746 if (layer == CTK_TEXT_VIEW_LAYER_BELOW_TEXT)
2747 {
2748 ctk_source_view_ensure_redrawn_rect_is_highlighted (view, cr);
2749
2750 if (view->priv->background_pattern == CTK_SOURCE_BACKGROUND_PATTERN_TYPE_GRID &&
2751 view->priv->background_pattern_color_set)
2752 {
2753 ctk_source_view_paint_background_pattern_grid (view, cr);
2754 }
2755
2756 if (ctk_widget_is_sensitive (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view)))))) &&
2757 view->priv->highlight_current_line &&
2758 view->priv->current_line_color_set)
2759 {
2760 ctk_source_view_paint_current_line_highlight (view, cr);
2761 }
2762
2763 ctk_source_view_paint_marks_background (view, cr);
2764 }
2765 else if (layer == CTK_TEXT_VIEW_LAYER_ABOVE_TEXT)
2766 {
2767 /* Draw the right margin vertical line + overlay. */
2768 if (view->priv->show_right_margin)
2769 {
2770 ctk_source_view_paint_right_margin (view, cr);
2771 }
2772
2773 if (view->priv->space_drawer != NULL((void*)0))
2774 {
2775 _ctk_source_space_drawer_draw (view->priv->space_drawer, view, cr);
2776 }
2777 }
2778
2779 cairo_restore (cr);
2780}
2781
2782static gboolean
2783ctk_source_view_draw (CtkWidget *widget,
2784 cairo_t *cr)
2785{
2786 CtkSourceView *view = CTK_SOURCE_VIEW (widget)((((CtkSourceView*) (void *) ((widget)))));
2787 gboolean event_handled;
2788
2789#ifdef ENABLE_PROFILE
2790 static GTimer *timer = NULL((void*)0);
2791 if (timer == NULL((void*)0))
2792 {
2793 timer = g_timer_new ();
2794 }
2795
2796 g_timer_start (timer);
2797#endif
2798
2799 DEBUG ({
2800 g_print ("> ctk_source_view_draw start\n");
2801 });
2802
2803 event_handled = CTK_WIDGET_CLASS (ctk_source_view_parent_class)((((CtkWidgetClass*) (void *) ((ctk_source_view_parent_class)
))))
->draw (widget, cr);
2804
2805 if (view->priv->left_gutter != NULL((void*)0))
2806 {
2807 _ctk_source_gutter_draw (view->priv->left_gutter, view, cr);
2808 }
2809
2810 if (view->priv->right_gutter != NULL((void*)0))
2811 {
2812 _ctk_source_gutter_draw (view->priv->right_gutter, view, cr);
2813 }
2814
2815 PROFILE ({
2816 g_timer_stop (timer);
2817 g_print (" ctk_source_view_draw time: %g (sec * 1000)\n",
2818 g_timer_elapsed (timer, NULL) * 1000);
2819 });
2820 DEBUG ({
2821 g_print ("> ctk_source_view_draw end\n");
2822 });
2823
2824 return event_handled;
2825}
2826
2827/* This is a pretty important function... We call it when the tab_stop is changed,
2828 * and when the font is changed.
2829 * NOTE: You must change this with the default font for now...
2830 * It may be a good idea to set the tab_width for each CtkTextTag as well
2831 * based on the font that we set at creation time
2832 * something like style_cache_set_tabs_from_font or the like.
2833 * Now, this *may* not be necessary because most tabs wont be inside of another highlight,
2834 * except for things like multi-line comments (which will usually have an italic font which
2835 * may or may not be a different size than the standard one), or if some random language
2836 * definition decides that it would be spiffy to have a bg color for "start of line" whitespace
2837 * "^\(\t\| \)+" would probably do the trick for that.
2838 */
2839static gint
2840calculate_real_tab_width (CtkSourceView *view, guint tab_size, gchar c)
2841{
2842 PangoLayout *layout;
2843 gchar *tab_string;
2844 gint tab_width = 0;
2845
2846 if (tab_size == 0)
2847 {
2848 return -1;
2849 }
2850
2851 tab_string = g_strnfill (tab_size, c);
2852 layout = ctk_widget_create_pango_layout (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))), tab_string);
2853 g_free (tab_string);
2854
2855 if (layout != NULL((void*)0))
2856 {
2857 pango_layout_get_pixel_size (layout, &tab_width, NULL((void*)0));
2858 g_object_unref (G_OBJECT (layout)((((GObject*) (void *) ((layout))))));
2859 }
2860 else
2861 {
2862 tab_width = -1;
2863 }
2864
2865 return tab_width;
2866}
2867
2868static CtkTextBuffer *
2869ctk_source_view_create_buffer (CtkTextView *text_view)
2870{
2871 return CTK_TEXT_BUFFER (ctk_source_buffer_new (NULL))((((CtkTextBuffer*) (void *) ((ctk_source_buffer_new (((void*
)0)))))))
;
2872}
2873
2874
2875/* ----------------------------------------------------------------------
2876 * Public interface
2877 * ----------------------------------------------------------------------
2878 */
2879
2880/**
2881 * ctk_source_view_new:
2882 *
2883 * Creates a new #CtkSourceView.
2884 *
2885 * By default, an empty #CtkSourceBuffer will be lazily created and can be
2886 * retrieved with ctk_text_view_get_buffer().
2887 *
2888 * If you want to specify your own buffer, either override the
2889 * #CtkTextViewClass create_buffer factory method, or use
2890 * ctk_source_view_new_with_buffer().
2891 *
2892 * Returns: a new #CtkSourceView.
2893 */
2894CtkWidget *
2895ctk_source_view_new (void)
2896{
2897 return g_object_new (CTK_SOURCE_TYPE_VIEW(ctk_source_view_get_type ()), NULL((void*)0));
2898}
2899
2900/**
2901 * ctk_source_view_new_with_buffer:
2902 * @buffer: a #CtkSourceBuffer.
2903 *
2904 * Creates a new #CtkSourceView widget displaying the buffer
2905 * @buffer. One buffer can be shared among many widgets.
2906 *
2907 * Returns: a new #CtkSourceView.
2908 */
2909CtkWidget *
2910ctk_source_view_new_with_buffer (CtkSourceBuffer *buffer)
2911{
2912 g_return_val_if_fail (CTK_SOURCE_IS_BUFFER (buffer), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_72
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((buffer)); GType __t = ((ctk_source_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; }
))))) _g_boolean_var_72 = 1; _g_boolean_var_72; }), 1))) { } else
{ g_return_if_fail_warning ("CtkSourceView", ((const char*) (
__func__)), "CTK_SOURCE_IS_BUFFER (buffer)"); return (((void*
)0)); } } while (0)
;
2913
2914 return g_object_new (CTK_SOURCE_TYPE_VIEW(ctk_source_view_get_type ()),
2915 "buffer", buffer,
2916 NULL((void*)0));
2917}
2918
2919/**
2920 * ctk_source_view_get_show_line_numbers:
2921 * @view: a #CtkSourceView.
2922 *
2923 * Returns whether line numbers are displayed beside the text.
2924 *
2925 * Return value: %TRUE if the line numbers are displayed.
2926 */
2927gboolean
2928ctk_source_view_get_show_line_numbers (CtkSourceView *view)
2929{
2930 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_73
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_73
= 1; _g_boolean_var_73; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return ((0)); } } while (0)
;
2931
2932 return view->priv->show_line_numbers;
2933}
2934
2935/**
2936 * ctk_source_view_set_show_line_numbers:
2937 * @view: a #CtkSourceView.
2938 * @show: whether line numbers should be displayed.
2939 *
2940 * If %TRUE line numbers will be displayed beside the text.
2941 */
2942void
2943ctk_source_view_set_show_line_numbers (CtkSourceView *view,
2944 gboolean show)
2945{
2946 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_74
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_74
= 1; _g_boolean_var_74; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
2947
2948 show = show != FALSE(0);
2949
2950 if (show == view->priv->show_line_numbers)
2951 {
2952 return;
2953 }
2954
2955 if (view->priv->line_renderer == NULL((void*)0))
2956 {
2957 CtkSourceGutter *gutter;
2958
2959 gutter = ctk_source_view_get_gutter (view, CTK_TEXT_WINDOW_LEFT);
2960
2961 view->priv->line_renderer = ctk_source_gutter_renderer_lines_new ();
2962 g_object_set (view->priv->line_renderer,
2963 "alignment-mode", CTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_FIRST,
2964 "yalign", 0.5,
2965 "xalign", 1.0,
2966 "xpad", 3,
2967 NULL((void*)0));
2968
2969 ctk_source_gutter_insert (gutter,
2970 view->priv->line_renderer,
2971 CTK_SOURCE_VIEW_GUTTER_POSITION_LINES);
2972 }
2973
2974 ctk_source_gutter_renderer_set_visible (view->priv->line_renderer, show);
2975 view->priv->show_line_numbers = show;
2976
2977 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "show_line_numbers");
2978}
2979
2980/**
2981 * ctk_source_view_get_show_line_marks:
2982 * @view: a #CtkSourceView.
2983 *
2984 * Returns whether line marks are displayed beside the text.
2985 *
2986 * Return value: %TRUE if the line marks are displayed.
2987 *
2988 * Since: 2.2
2989 */
2990gboolean
2991ctk_source_view_get_show_line_marks (CtkSourceView *view)
2992{
2993 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_75
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_75
= 1; _g_boolean_var_75; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return ((0)); } } while (0)
;
2994
2995 return view->priv->show_line_marks;
2996}
2997
2998static void
2999gutter_renderer_marks_activate (CtkSourceGutterRenderer *renderer,
3000 CtkTextIter *iter,
3001 const CdkRectangle *area,
3002 CdkEvent *event,
3003 CtkSourceView *view)
3004{
3005 g_signal_emit (view,
3006 signals[LINE_MARK_ACTIVATED],
3007 0,
3008 iter,
3009 event);
3010}
3011
3012/**
3013 * ctk_source_view_set_show_line_marks:
3014 * @view: a #CtkSourceView.
3015 * @show: whether line marks should be displayed.
3016 *
3017 * If %TRUE line marks will be displayed beside the text.
3018 *
3019 * Since: 2.2
3020 */
3021void
3022ctk_source_view_set_show_line_marks (CtkSourceView *view,
3023 gboolean show)
3024{
3025 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_76
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_76
= 1; _g_boolean_var_76; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
3026
3027 show = show != FALSE(0);
3028
3029 if (show == view->priv->show_line_marks)
3030 {
3031 return;
3032 }
3033
3034 if (view->priv->marks_renderer == NULL((void*)0))
3035 {
3036 CtkSourceGutter *gutter;
3037
3038 gutter = ctk_source_view_get_gutter (view, CTK_TEXT_WINDOW_LEFT);
3039
3040 view->priv->marks_renderer = ctk_source_gutter_renderer_marks_new ();
3041
3042 ctk_source_gutter_insert (gutter,
3043 view->priv->marks_renderer,
3044 CTK_SOURCE_VIEW_GUTTER_POSITION_MARKS);
3045
3046 g_signal_connect (view->priv->marks_renderer,g_signal_connect_data ((view->priv->marks_renderer), ("activate"
), (((GCallback) (gutter_renderer_marks_activate))), (view), (
(void*)0), (GConnectFlags) 0)
3047 "activate",g_signal_connect_data ((view->priv->marks_renderer), ("activate"
), (((GCallback) (gutter_renderer_marks_activate))), (view), (
(void*)0), (GConnectFlags) 0)
3048 G_CALLBACK (gutter_renderer_marks_activate),g_signal_connect_data ((view->priv->marks_renderer), ("activate"
), (((GCallback) (gutter_renderer_marks_activate))), (view), (
(void*)0), (GConnectFlags) 0)
3049 view)g_signal_connect_data ((view->priv->marks_renderer), ("activate"
), (((GCallback) (gutter_renderer_marks_activate))), (view), (
(void*)0), (GConnectFlags) 0)
;
3050 }
3051
3052 ctk_source_gutter_renderer_set_visible (view->priv->marks_renderer, show);
3053 view->priv->show_line_marks = show;
3054
3055 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "show_line_marks");
3056}
3057
3058static gboolean
3059set_tab_stops_internal (CtkSourceView *view)
3060{
3061 PangoTabArray *tab_array;
3062 gint real_tab_width;
3063
3064 real_tab_width = calculate_real_tab_width (view, view->priv->tab_width, ' ');
3065
3066 if (real_tab_width < 0)
3067 {
3068 return FALSE(0);
3069 }
3070
3071 tab_array = pango_tab_array_new (1, TRUE(!(0)));
3072 pango_tab_array_set_tab (tab_array, 0, PANGO_TAB_LEFT, real_tab_width);
3073
3074 ctk_text_view_set_tabs (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))),
3075 tab_array);
3076 view->priv->tabs_set = TRUE(!(0));
3077
3078 pango_tab_array_free (tab_array);
3079
3080 return TRUE(!(0));
3081}
3082
3083/**
3084 * ctk_source_view_set_tab_width:
3085 * @view: a #CtkSourceView.
3086 * @width: width of tab in characters.
3087 *
3088 * Sets the width of tabulation in characters. The #CtkTextBuffer still contains
3089 * \t characters, but they can take a different visual width in a #CtkSourceView
3090 * widget.
3091 */
3092void
3093ctk_source_view_set_tab_width (CtkSourceView *view,
3094 guint width)
3095{
3096 guint save_width;
3097
3098 g_return_if_fail (CTK_SOURCE_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_77
= 0; if (((((CtkSourceView*) (void *) ((view)))))) _g_boolean_var_77
= 1; _g_boolean_var_77; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_VIEW (view)"
); return; } } while (0)
;
3099 g_return_if_fail (0 < width && width <= MAX_TAB_WIDTH)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_78
= 0; if (0 < width && width <= 32) _g_boolean_var_78
= 1; _g_boolean_var_78; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "0 < width && width <= MAX_TAB_WIDTH"
); return; } } while (0)
;
3100
3101 if (view->priv->tab_width == width)
3102 {
3103 return;
3104 }
3105
3106 save_width = view->priv->tab_width;
3107 view->priv->tab_width = width;
3108 if (set_tab_stops_internal (view))
3109 {
3110 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "tab-width");
3111 }
3112 else
3113 {
3114 g_warning ("Impossible to set tab width.");
3115 view->priv->tab_width = save_width;
3116 }
3117}
3118
3119/**
3120 * ctk_source_view_get_tab_width:
3121 * @view: a #CtkSourceView.
3122 *
3123 * Returns the width of tabulation in characters.
3124 *
3125 * Return value: width of tab.
3126 */
3127guint
3128ctk_source_view_get_tab_width (CtkSourceView *view)
3129{
3130 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), DEFAULT_TAB_WIDTH)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_79
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_79
= 1; _g_boolean_var_79; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return (8); } } while (0)
;
3131
3132 return view->priv->tab_width;
3133}
3134
3135/**
3136 * ctk_source_view_set_indent_width:
3137 * @view: a #CtkSourceView.
3138 * @width: indent width in characters.
3139 *
3140 * Sets the number of spaces to use for each step of indent when the tab key is
3141 * pressed. If @width is -1, the value of the #CtkSourceView:tab-width property
3142 * will be used.
3143 *
3144 * The #CtkSourceView:indent-width interacts with the
3145 * #CtkSourceView:insert-spaces-instead-of-tabs property and
3146 * #CtkSourceView:tab-width. An example will be clearer: if the
3147 * #CtkSourceView:indent-width is 4 and
3148 * #CtkSourceView:tab-width is 8 and
3149 * #CtkSourceView:insert-spaces-instead-of-tabs is %FALSE, then pressing the tab
3150 * key at the beginning of a line will insert 4 spaces. So far so good. Pressing
3151 * the tab key a second time will remove the 4 spaces and insert a \t character
3152 * instead (since #CtkSourceView:tab-width is 8). On the other hand, if
3153 * #CtkSourceView:insert-spaces-instead-of-tabs is %TRUE, the second tab key
3154 * pressed will insert 4 more spaces for a total of 8 spaces in the
3155 * #CtkTextBuffer.
3156 *
3157 * The test-widget program (available in the CtkSourceView repository) may be
3158 * useful to better understand the indentation settings (enable the space
3159 * drawing!).
3160 */
3161void
3162ctk_source_view_set_indent_width (CtkSourceView *view,
3163 gint width)
3164{
3165 g_return_if_fail (CTK_SOURCE_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_80
= 0; if (((((CtkSourceView*) (void *) ((view)))))) _g_boolean_var_80
= 1; _g_boolean_var_80; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_VIEW (view)"
); return; } } while (0)
;
3166 g_return_if_fail (width == -1 || (0 < width && width <= MAX_INDENT_WIDTH))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_81
= 0; if (width == -1 || (0 < width && width <=
32)) _g_boolean_var_81 = 1; _g_boolean_var_81; }), 1))) { } else
{ g_return_if_fail_warning ("CtkSourceView", ((const char*) (
__func__)), "width == -1 || (0 < width && width <= MAX_INDENT_WIDTH)"
); return; } } while (0)
;
3167
3168 if (view->priv->indent_width != width)
3169 {
3170 view->priv->indent_width = width;
3171 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "indent-width");
3172 }
3173}
3174
3175/**
3176 * ctk_source_view_get_indent_width:
3177 * @view: a #CtkSourceView.
3178 *
3179 * Returns the number of spaces to use for each step of indent.
3180 * See ctk_source_view_set_indent_width() for details.
3181 *
3182 * Return value: indent width.
3183 */
3184gint
3185ctk_source_view_get_indent_width (CtkSourceView *view)
3186{
3187 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), 0)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_82
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_82
= 1; _g_boolean_var_82; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return (0); } } while (0)
;
3188
3189 return view->priv->indent_width;
3190}
3191
3192static gchar *
3193compute_indentation (CtkSourceView *view,
3194 CtkTextIter *cur)
3195{
3196 CtkTextIter start;
3197 CtkTextIter end;
3198 gunichar ch;
3199
3200 start = *cur;
3201 ctk_text_iter_set_line_offset (&start, 0);
3202
3203 end = start;
3204
3205 ch = ctk_text_iter_get_char (&end);
3206
3207 while (g_unichar_isspace (ch) &&
3208 (ch != '\n') &&
3209 (ch != '\r') &&
3210 (ctk_text_iter_compare (&end, cur) < 0))
3211 {
3212 if (!ctk_text_iter_forward_char (&end))
3213 {
3214 break;
3215 }
3216
3217 ch = ctk_text_iter_get_char (&end);
3218 }
3219
3220 if (ctk_text_iter_equal (&start, &end))
3221 {
3222 return NULL((void*)0);
3223 }
3224
3225 return ctk_text_iter_get_slice (&start, &end);
3226}
3227
3228static guint
3229get_real_indent_width (CtkSourceView *view)
3230{
3231 return view->priv->indent_width < 0 ?
3232 view->priv->tab_width :
3233 (guint) view->priv->indent_width;
3234}
3235
3236static gchar *
3237get_indent_string (guint tabs,
3238 guint spaces)
3239{
3240 gchar *str;
3241
3242 str = g_malloc (tabs + spaces + 1);
3243
3244 if (tabs > 0)
3245 {
3246 memset (str, '\t', tabs);
3247 }
3248
3249 if (spaces > 0)
3250 {
3251 memset (str + tabs, ' ', spaces);
3252 }
3253
3254 str[tabs + spaces] = '\0';
3255
3256 return str;
3257}
3258
3259/**
3260 * ctk_source_view_indent_lines:
3261 * @view: a #CtkSourceView.
3262 * @start: #CtkTextIter of the first line to indent
3263 * @end: #CtkTextIter of the last line to indent
3264 *
3265 * Inserts one indentation level at the beginning of the specified lines. The
3266 * empty lines are not indented.
3267 *
3268 * Since: 3.16
3269 */
3270void
3271ctk_source_view_indent_lines (CtkSourceView *view,
3272 CtkTextIter *start,
3273 CtkTextIter *end)
3274{
3275 CtkTextBuffer *buf;
3276 gboolean bracket_hl;
3277 CtkTextMark *start_mark, *end_mark;
3278 gint start_line, end_line;
3279 gchar *tab_buffer = NULL((void*)0);
3280 guint tabs = 0;
3281 guint spaces = 0;
3282 gint i;
3283
3284 if (view->priv->completion != NULL((void*)0))
3285 {
3286 ctk_source_completion_block_interactive (view->priv->completion);
3287 }
3288
3289 buf = ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
3290
3291 bracket_hl = ctk_source_buffer_get_highlight_matching_brackets (CTK_SOURCE_BUFFER (buf)((((CtkSourceBuffer*) (void *) ((buf))))));
3292 ctk_source_buffer_set_highlight_matching_brackets (CTK_SOURCE_BUFFER (buf)((((CtkSourceBuffer*) (void *) ((buf))))), FALSE(0));
3293
3294 start_mark = ctk_text_buffer_create_mark (buf, NULL((void*)0), start, FALSE(0));
3295 end_mark = ctk_text_buffer_create_mark (buf, NULL((void*)0), end, FALSE(0));
3296
3297 start_line = ctk_text_iter_get_line (start);
3298 end_line = ctk_text_iter_get_line (end);
3299
3300 if ((ctk_text_iter_get_visible_line_offset (end) == 0) &&
3301 (end_line > start_line))
3302 {
3303 end_line--;
3304 }
3305
3306 if (view->priv->insert_spaces)
3307 {
3308 spaces = get_real_indent_width (view);
3309
3310 tab_buffer = g_strnfill (spaces, ' ');
3311 }
3312 else if (view->priv->indent_width > 0 &&
3313 view->priv->indent_width != (gint)view->priv->tab_width)
3314 {
3315 guint indent_width;
3316
3317 indent_width = get_real_indent_width (view);
3318 spaces = indent_width % view->priv->tab_width;
3319 tabs = indent_width / view->priv->tab_width;
3320
3321 tab_buffer = get_indent_string (tabs, spaces);
3322 }
3323 else
3324 {
3325 tabs = 1;
3326 tab_buffer = g_strdup ("\t")g_strdup_inline ("\t");
3327 }
3328
3329 ctk_text_buffer_begin_user_action (buf);
3330
3331 for (i = start_line; i <= end_line; i++)
3332 {
3333 CtkTextIter iter;
3334 CtkTextIter iter2;
3335 guint replaced_spaces = 0;
3336
3337 ctk_text_buffer_get_iter_at_line (buf, &iter, i);
3338
3339 /* Don't add indentation on completely empty lines, to not add
3340 * trailing spaces.
3341 * Note that non-empty lines containing only whitespaces are
3342 * indented like any other non-empty line, because those lines
3343 * already contain trailing spaces, some users use those
3344 * whitespaces to more easily insert text at the right place
3345 * without the need to insert the indentation each time.
3346 */
3347 if (ctk_text_iter_ends_line (&iter))
3348 {
3349 continue;
3350 }
3351
3352 /* add spaces always after tabs, to avoid the case
3353 * where "\t" becomes " \t" with no visual difference */
3354 while (ctk_text_iter_get_char (&iter) == '\t')
3355 {
3356 ctk_text_iter_forward_char (&iter);
3357 }
3358
3359 /* if tabs are allowed try to merge the spaces
3360 * with the tab we are going to insert (if any) */
3361 iter2 = iter;
3362 while (!view->priv->insert_spaces &&
3363 (ctk_text_iter_get_char (&iter2) == ' ') &&
3364 replaced_spaces < view->priv->tab_width)
3365 {
3366 ++replaced_spaces;
3367
3368 ctk_text_iter_forward_char (&iter2);
3369 }
3370
3371 if (replaced_spaces > 0)
3372 {
3373 gchar *indent_buf;
3374 guint t, s;
3375
3376 t = tabs + (spaces + replaced_spaces) / view->priv->tab_width;
3377 s = (spaces + replaced_spaces) % view->priv->tab_width;
3378 indent_buf = get_indent_string (t, s);
3379
3380 ctk_text_buffer_delete (buf, &iter, &iter2);
3381 ctk_text_buffer_insert (buf, &iter, indent_buf, -1);
3382
3383 g_free (indent_buf);
3384 }
3385 else
3386 {
3387 ctk_text_buffer_insert (buf, &iter, tab_buffer, -1);
3388 }
3389 }
3390
3391 ctk_text_buffer_end_user_action (buf);
3392
3393 g_free (tab_buffer);
3394
3395 ctk_source_buffer_set_highlight_matching_brackets (CTK_SOURCE_BUFFER (buf)((((CtkSourceBuffer*) (void *) ((buf))))), bracket_hl);
3396
3397 if (view->priv->completion != NULL((void*)0))
3398 {
3399 ctk_source_completion_unblock_interactive (view->priv->completion);
3400 }
3401
3402 ctk_text_view_scroll_mark_onscreen (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))),
3403 ctk_text_buffer_get_insert (buf));
3404
3405 /* revalidate iters */
3406 ctk_text_buffer_get_iter_at_mark (buf, start, start_mark);
3407 ctk_text_buffer_get_iter_at_mark (buf, end, end_mark);
3408
3409 ctk_text_buffer_delete_mark (buf, start_mark);
3410 ctk_text_buffer_delete_mark (buf, end_mark);
3411}
3412
3413/**
3414 * ctk_source_view_unindent_lines:
3415 * @view: a #CtkSourceView.
3416 * @start: #CtkTextIter of the first line to indent
3417 * @end: #CtkTextIter of the last line to indent
3418 *
3419 * Removes one indentation level at the beginning of the
3420 * specified lines.
3421 *
3422 * Since: 3.16
3423 */
3424void
3425ctk_source_view_unindent_lines (CtkSourceView *view,
3426 CtkTextIter *start,
3427 CtkTextIter *end)
3428{
3429 CtkTextBuffer *buf;
3430 gboolean bracket_hl;
3431 CtkTextMark *start_mark, *end_mark;
3432 gint start_line, end_line;
3433 gint tab_width;
3434 gint indent_width;
3435 gint i;
3436
3437 if (view->priv->completion != NULL((void*)0))
3438 {
3439 ctk_source_completion_block_interactive (view->priv->completion);
3440 }
3441
3442 buf = ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
3443
3444 bracket_hl = ctk_source_buffer_get_highlight_matching_brackets (CTK_SOURCE_BUFFER (buf)((((CtkSourceBuffer*) (void *) ((buf))))));
3445 ctk_source_buffer_set_highlight_matching_brackets (CTK_SOURCE_BUFFER (buf)((((CtkSourceBuffer*) (void *) ((buf))))), FALSE(0));
3446
3447 start_mark = ctk_text_buffer_create_mark (buf, NULL((void*)0), start, FALSE(0));
3448 end_mark = ctk_text_buffer_create_mark (buf, NULL((void*)0), end, FALSE(0));
3449
3450 start_line = ctk_text_iter_get_line (start);
3451 end_line = ctk_text_iter_get_line (end);
3452
3453 if ((ctk_text_iter_get_visible_line_offset (end) == 0) &&
3454 (end_line > start_line))
3455 {
3456 end_line--;
3457 }
3458
3459 tab_width = view->priv->tab_width;
3460 indent_width = get_real_indent_width (view);
3461
3462 ctk_text_buffer_begin_user_action (buf);
3463
3464 for (i = start_line; i <= end_line; i++)
3465 {
3466 CtkTextIter iter, iter2;
3467 gint to_delete = 0;
3468 gint to_delete_equiv = 0;
3469
3470 ctk_text_buffer_get_iter_at_line (buf, &iter, i);
3471
3472 iter2 = iter;
3473
3474 while (!ctk_text_iter_ends_line (&iter2) &&
3475 to_delete_equiv < indent_width)
3476 {
3477 gunichar c;
3478
3479 c = ctk_text_iter_get_char (&iter2);
3480 if (c == '\t')
3481 {
3482 to_delete_equiv += tab_width - to_delete_equiv % tab_width;
3483 ++to_delete;
3484 }
3485 else if (c == ' ')
3486 {
3487 ++to_delete_equiv;
3488 ++to_delete;
3489 }
3490 else
3491 {
3492 break;
3493 }
3494
3495 ctk_text_iter_forward_char (&iter2);
3496 }
3497
3498 if (to_delete > 0)
3499 {
3500 ctk_text_iter_set_line_offset (&iter2, to_delete);
3501 ctk_text_buffer_delete (buf, &iter, &iter2);
3502 }
3503 }
3504
3505 ctk_text_buffer_end_user_action (buf);
3506
3507 ctk_source_buffer_set_highlight_matching_brackets (CTK_SOURCE_BUFFER (buf)((((CtkSourceBuffer*) (void *) ((buf))))), bracket_hl);
3508
3509 if (view->priv->completion != NULL((void*)0))
3510 {
3511 ctk_source_completion_unblock_interactive (view->priv->completion);
3512 }
3513
3514 ctk_text_view_scroll_mark_onscreen (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))),
3515 ctk_text_buffer_get_insert (buf));
3516
3517 /* revalidate iters */
3518 ctk_text_buffer_get_iter_at_mark (buf, start, start_mark);
3519 ctk_text_buffer_get_iter_at_mark (buf, end, end_mark);
3520
3521 ctk_text_buffer_delete_mark (buf, start_mark);
3522 ctk_text_buffer_delete_mark (buf, end_mark);
3523}
3524
3525static gint
3526get_line_offset_in_equivalent_spaces (CtkSourceView *view,
3527 CtkTextIter *iter)
3528{
3529 CtkTextIter i;
3530 gint tab_width;
3531 gint n = 0;
3532
3533 tab_width = view->priv->tab_width;
3534
3535 i = *iter;
3536 ctk_text_iter_set_line_offset (&i, 0);
3537
3538 while (!ctk_text_iter_equal (&i, iter))
3539 {
3540 gunichar c;
3541
3542 c = ctk_text_iter_get_char (&i);
3543 if (c == '\t')
3544 {
3545 n += tab_width - n % tab_width;
3546 }
3547 else
3548 {
3549 ++n;
3550 }
3551
3552 ctk_text_iter_forward_char (&i);
3553 }
3554
3555 return n;
3556}
3557
3558static void
3559insert_tab_or_spaces (CtkSourceView *view,
3560 CtkTextIter *start,
3561 CtkTextIter *end)
3562{
3563 CtkTextBuffer *buf;
3564 gchar *tab_buf;
3565 gint cursor_offset = 0;
3566
3567 if (view->priv->insert_spaces)
11
Assuming field 'insert_spaces' is 0
3568 {
3569 gint indent_width;
3570 gint pos;
3571 gint spaces;
3572
3573 indent_width = get_real_indent_width (view);
3574
3575 /* CHECK: is this a performance problem? */
3576 pos = get_line_offset_in_equivalent_spaces (view, start);
3577 spaces = indent_width - pos % indent_width;
3578
3579 tab_buf = g_strnfill (spaces, ' ');
3580 }
3581 else if (view->priv->indent_width > 0 &&
12
Assuming field 'indent_width' is > 0
14
Taking true branch
3582 view->priv->indent_width != (gint)view->priv->tab_width)
13
Assuming field 'indent_width' is not equal to field 'tab_width'
3583 {
3584 CtkTextIter iter;
3585 gint i;
3586 gint tab_width;
3587 gint indent_width;
3588 gint from;
3589 gint to;
3590 gint preceding_spaces = 0;
3591 gint following_tabs = 0;
3592 gint equiv_spaces;
3593 gint tabs;
3594 gint spaces;
3595
3596 tab_width = view->priv->tab_width;
15
Value assigned to 'tab_width'
3597 indent_width = get_real_indent_width (view);
3598
3599 /* CHECK: is this a performance problem? */
3600 from = get_line_offset_in_equivalent_spaces (view, start);
3601 to = indent_width * (1 + from / indent_width);
3602 equiv_spaces = to - from;
3603
3604 /* extend the selection to include
3605 * preceding spaces so that if indentation
3606 * width < tab width, two conseutive indentation
3607 * width units get compressed into a tab */
3608 iter = *start;
3609 for (i = 0; i < tab_width; ++i)
16
Assuming 'i' is >= 'tab_width'
17
Loop condition is false. Execution continues on line 3623
3610 {
3611 ctk_text_iter_backward_char (&iter);
3612
3613 if (ctk_text_iter_get_char (&iter) == ' ')
3614 {
3615 ++preceding_spaces;
3616 }
3617 else
3618 {
3619 break;
3620 }
3621 }
3622
3623 ctk_text_iter_backward_chars (start, preceding_spaces);
3624
3625 /* now also extend the selection to the following tabs
3626 * since we do not want to insert spaces before a tab
3627 * since it may have no visual effect */
3628 while (ctk_text_iter_get_char (end) == '\t')
18
Assuming the condition is false
19
Loop condition is false. Execution continues on line 3634
3629 {
3630 ++following_tabs;
3631 ctk_text_iter_forward_char (end);
3632 }
3633
3634 tabs = (preceding_spaces + equiv_spaces) / tab_width;
20
Division by zero
3635 spaces = (preceding_spaces + equiv_spaces) % tab_width;
3636
3637 tab_buf = get_indent_string (tabs + following_tabs, spaces);
3638
3639 cursor_offset = ctk_text_iter_get_offset (start) +
3640 tabs +
3641 (following_tabs > 0 ? 1 : spaces);
3642 }
3643 else
3644 {
3645 tab_buf = g_strdup ("\t")g_strdup_inline ("\t");
3646 }
3647
3648 buf = ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
3649
3650 ctk_text_buffer_begin_user_action (buf);
3651
3652 ctk_text_buffer_delete (buf, start, end);
3653 ctk_text_buffer_insert (buf, start, tab_buf, -1);
3654
3655 /* adjust cursor position if needed */
3656 if (cursor_offset > 0)
3657 {
3658 CtkTextIter iter;
3659
3660 ctk_text_buffer_get_iter_at_offset (buf, &iter, cursor_offset);
3661 ctk_text_buffer_place_cursor (buf, &iter);
3662 }
3663
3664 ctk_text_buffer_end_user_action (buf);
3665
3666 g_free (tab_buf);
3667}
3668
3669static void
3670ctk_source_view_move_words (CtkSourceView *view,
3671 gint step)
3672{
3673 CtkTextBuffer *buf;
3674 CtkTextIter s, e, ns, ne;
3675 CtkTextMark *nsmark, *nemark;
3676 gchar *old_text, *new_text;
3677
3678 buf = ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
3679
3680 if (step == 0 || ctk_text_view_get_editable (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))))) == FALSE(0))
3681 {
3682 return;
3683 }
3684
3685 ctk_text_buffer_get_selection_bounds (buf, &s, &e);
3686
3687 if (ctk_text_iter_compare (&s, &e) == 0)
3688 {
3689 if (!ctk_text_iter_starts_word (&s))
3690 {
3691 if (!ctk_text_iter_inside_word (&s) && !ctk_text_iter_ends_word (&s))
3692 {
3693 return;
3694 }
3695 else
3696 {
3697 ctk_text_iter_backward_word_start (&s);
3698 }
3699 }
3700
3701 if (!ctk_text_iter_starts_word (&s))
3702 {
3703 return;
3704 }
3705
3706 e = s;
3707
3708 if (!ctk_text_iter_ends_word (&e))
3709 {
3710 if (!ctk_text_iter_forward_word_end (&e))
3711 {
3712 ctk_text_iter_forward_to_end (&e);
3713 }
3714
3715 if (!ctk_text_iter_ends_word (&e))
3716 {
3717 return;
3718 }
3719 }
3720 }
3721
3722 /* Swap the selection with the next or previous word, based on step */
3723 if (step > 0)
3724 {
3725 ne = e;
3726
3727 if (!ctk_text_iter_forward_word_ends (&ne, step))
3728 {
3729 ctk_text_iter_forward_to_end (&ne);
3730 }
3731
3732 if (!ctk_text_iter_ends_word (&ne) || ctk_text_iter_equal (&ne, &e))
3733 {
3734 return;
3735 }
3736
3737 ns = ne;
3738
3739 if (!ctk_text_iter_backward_word_start (&ns))
3740 {
3741 return;
3742 }
3743 }
3744 else
3745 {
3746 ns = s;
3747
3748 if (!ctk_text_iter_backward_word_starts (&ns, -step))
3749 {
3750 return;
3751 }
3752
3753 ne = ns;
3754
3755 if (!ctk_text_iter_forward_word_end (&ne))
3756 {
3757 return;
3758 }
3759 }
3760
3761 if (ctk_text_iter_in_range (&ns, &s, &e) ||
3762 (!ctk_text_iter_equal (&s, &ne) &&
3763 ctk_text_iter_in_range (&ne, &s, &e)))
3764 {
3765 return;
3766 }
3767
3768 old_text = ctk_text_buffer_get_text (buf, &s, &e, TRUE(!(0)));
3769 new_text = ctk_text_buffer_get_text (buf, &ns, &ne, TRUE(!(0)));
3770
3771 ctk_text_buffer_begin_user_action (buf);
3772
3773 nsmark = ctk_text_buffer_create_mark (buf, NULL((void*)0), &ns, step < 0);
3774 nemark = ctk_text_buffer_create_mark (buf, NULL((void*)0), &ne, step < 0);
3775
3776 ctk_text_buffer_delete (buf, &s, &e);
3777 ctk_text_buffer_insert (buf, &s, new_text, -1);
3778
3779 ctk_text_buffer_get_iter_at_mark (buf, &ns, nsmark);
3780 ctk_text_buffer_get_iter_at_mark (buf, &ne, nemark);
3781
3782 ctk_text_buffer_delete (buf, &ns, &ne);
3783 ctk_text_buffer_insert (buf, &ns, old_text, -1);
3784
3785 ne = ns;
3786 ctk_text_buffer_get_iter_at_mark (buf, &ns, nsmark);
3787
3788 ctk_text_buffer_select_range (buf, &ns, &ne);
3789
3790 ctk_text_buffer_delete_mark (buf, nsmark);
3791 ctk_text_buffer_delete_mark (buf, nemark);
3792
3793 ctk_text_buffer_end_user_action (buf);
3794
3795 ctk_text_view_scroll_mark_onscreen (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))),
3796 ctk_text_buffer_get_insert (buf));
3797
3798 g_free (old_text);
3799 g_free (new_text);
3800}
3801
3802static gboolean
3803buffer_contains_trailing_newline (CtkTextBuffer *buffer)
3804{
3805 CtkTextIter iter;
3806 gunichar ch;
3807
3808 ctk_text_buffer_get_end_iter (buffer, &iter);
3809 ctk_text_iter_backward_char (&iter);
3810 ch = ctk_text_iter_get_char (&iter);
3811
3812 return (ch == '\n' || ch == '\r');
3813}
3814
3815/* FIXME could be a function of CtkSourceBuffer, it's also useful for the
3816 * FileLoader.
3817 */
3818static void
3819remove_trailing_newline (CtkTextBuffer *buffer)
3820{
3821 CtkTextIter start;
3822 CtkTextIter end;
3823
3824 ctk_text_buffer_get_end_iter (buffer, &end);
3825 start = end;
3826
3827 ctk_text_iter_set_line_offset (&start, 0);
3828
3829 if (ctk_text_iter_ends_line (&start) &&
3830 ctk_text_iter_backward_line (&start))
3831 {
3832 if (!ctk_text_iter_ends_line (&start))
3833 {
3834 ctk_text_iter_forward_to_line_end (&start);
3835 }
3836
3837 ctk_text_buffer_delete (buffer, &start, &end);
3838 }
3839}
3840
3841static void
3842ctk_source_view_move_lines (CtkSourceView *view,
3843 gboolean down)
3844{
3845 CtkTextBuffer *buffer;
3846 CtkTextIter start;
3847 CtkTextIter end;
3848 CtkTextIter insert_pos;
3849 CtkTextMark *start_mark;
3850 CtkTextMark *end_mark;
3851 gchar *text;
3852 gboolean initially_contains_trailing_newline;
3853
3854 buffer = ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
3855
3856 if (!ctk_text_view_get_editable (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))))))
3857 {
3858 return;
3859 }
3860
3861 ctk_text_buffer_get_selection_bounds (buffer, &start, &end);
3862
3863 /* Get the entire lines, including the paragraph terminator. */
3864 ctk_text_iter_set_line_offset (&start, 0);
3865 if (!ctk_text_iter_starts_line (&end) ||
3866 ctk_text_iter_get_line (&start) == ctk_text_iter_get_line (&end))
3867 {
3868 ctk_text_iter_forward_line (&end);
3869 }
3870
3871 if ((!down && ctk_text_iter_is_start (&start)) ||
3872 (down && ctk_text_iter_is_end (&end)))
3873 {
3874 /* Nothing to do, and the undo/redo history must remain
3875 * unchanged.
3876 */
3877 return;
3878 }
3879
3880 start_mark = ctk_text_buffer_create_mark (buffer, NULL((void*)0), &start, TRUE(!(0)));
3881 end_mark = ctk_text_buffer_create_mark (buffer, NULL((void*)0), &end, FALSE(0));
3882
3883 ctk_text_buffer_begin_user_action (buffer);
3884
3885 initially_contains_trailing_newline = buffer_contains_trailing_newline (buffer);
3886
3887 if (!initially_contains_trailing_newline)
3888 {
3889 /* Insert a trailing newline. */
3890 ctk_text_buffer_get_end_iter (buffer, &end);
3891 ctk_text_buffer_insert (buffer, &end, "\n", -1);
3892 }
3893
3894 /* At this point all lines finish with a newline or carriage return, so
3895 * there are no special cases for the last line.
3896 */
3897
3898 ctk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
3899 ctk_text_buffer_get_iter_at_mark (buffer, &end, end_mark);
3900 ctk_text_buffer_delete_mark (buffer, start_mark);
3901 ctk_text_buffer_delete_mark (buffer, end_mark);
3902 start_mark = NULL((void*)0);
3903 end_mark = NULL((void*)0);
3904
3905 text = ctk_text_buffer_get_text (buffer, &start, &end, TRUE(!(0)));
3906
3907 ctk_text_buffer_delete (buffer, &start, &end);
3908
3909 if (down)
3910 {
3911 insert_pos = end;
3912 ctk_text_iter_forward_line (&insert_pos);
3913 }
3914 else
3915 {
3916 insert_pos = start;
3917 ctk_text_iter_backward_line (&insert_pos);
3918 }
3919
3920 start_mark = ctk_text_buffer_create_mark (buffer, NULL((void*)0), &insert_pos, TRUE(!(0)));
3921
3922 ctk_text_buffer_insert (buffer, &insert_pos, text, -1);
3923 g_free (text);
3924
3925 /* Select the moved text. */
3926 ctk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
3927 ctk_text_buffer_delete_mark (buffer, start_mark);
3928
3929 ctk_text_buffer_select_range (buffer, &start, &insert_pos);
3930
3931 if (!initially_contains_trailing_newline)
3932 {
3933 remove_trailing_newline (buffer);
3934 }
3935
3936 ctk_text_buffer_end_user_action (buffer);
3937
3938 ctk_text_view_scroll_mark_onscreen (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))),
3939 ctk_text_buffer_get_insert (buffer));
3940}
3941
3942static gboolean
3943do_smart_backspace (CtkSourceView *view)
3944{
3945 CtkTextBuffer *buffer;
3946 gboolean default_editable;
3947 CtkTextIter insert;
3948 CtkTextIter end;
3949 CtkTextIter leading_end;
3950 guint visual_column;
3951 gint indent_width;
3952
3953 buffer = CTK_TEXT_BUFFER (view->priv->source_buffer)((((CtkTextBuffer*) (void *) ((view->priv->source_buffer
)))))
;
3954 default_editable = ctk_text_view_get_editable (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
3955
3956 if (ctk_text_buffer_get_selection_bounds (buffer, &insert, &end))
3957 {
3958 return FALSE(0);
3959 }
3960
3961 /* If the line isn't empty up to our cursor, ignore. */
3962 _ctk_source_iter_get_leading_spaces_end_boundary (&insert, &leading_end);
3963 if (ctk_text_iter_compare (&leading_end, &insert) < 0)
3964 {
3965 return FALSE(0);
3966 }
3967
3968 visual_column = ctk_source_view_get_visual_column (view, &insert);
3969 indent_width = view->priv->indent_width;
3970 if (indent_width <= 0)
3971 {
3972 indent_width = view->priv->tab_width;
3973 }
3974
3975 g_return_val_if_fail (indent_width > 0, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_83
= 0; if (indent_width > 0) _g_boolean_var_83 = 1; _g_boolean_var_83
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "indent_width > 0"); return (
(0)); } } while (0)
;
3976
3977 /* If the cursor is not at an indent_width boundary, it probably means
3978 * that we want to adjust the spaces.
3979 */
3980 if ((gint)visual_column < indent_width)
3981 {
3982 return FALSE(0);
3983 }
3984
3985 if ((visual_column % indent_width) == 0)
3986 {
3987 guint target_column;
3988
3989 g_assert ((gint)visual_column >= indent_width)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_84
= 0; if ((gint)visual_column >= indent_width) _g_boolean_var_84
= 1; _g_boolean_var_84; }), 1)) ; else g_assertion_message_expr
("CtkSourceView", "../ctksourceview/ctksourceview.c", 3989, (
(const char*) (__func__)), "(gint)visual_column >= indent_width"
); } while (0)
;
3990 target_column = visual_column - indent_width;
3991
3992 while (ctk_source_view_get_visual_column (view, &insert) > target_column)
3993 {
3994 ctk_text_iter_backward_cursor_position (&insert);
3995 }
3996
3997 ctk_text_buffer_begin_user_action (buffer);
3998 ctk_text_buffer_delete_interactive (buffer, &insert, &end, default_editable);
3999 while (ctk_source_view_get_visual_column (view, &insert) < target_column)
4000 {
4001 if (!ctk_text_buffer_insert_interactive (buffer, &insert, " ", 1, default_editable))
4002 {
4003 break;
4004 }
4005 }
4006 ctk_text_buffer_end_user_action (buffer);
4007
4008 return TRUE(!(0));
4009 }
4010
4011 return FALSE(0);
4012}
4013
4014static gboolean
4015do_ctrl_backspace (CtkSourceView *view)
4016{
4017 CtkTextBuffer *buffer;
4018 CtkTextIter insert;
4019 CtkTextIter end;
4020 CtkTextIter leading_end;
4021 gboolean default_editable;
4022
4023 buffer = CTK_TEXT_BUFFER (view->priv->source_buffer)((((CtkTextBuffer*) (void *) ((view->priv->source_buffer
)))))
;
4024 default_editable = ctk_text_view_get_editable (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
4025
4026 if (ctk_text_buffer_get_selection_bounds (buffer, &insert, &end))
4027 {
4028 return FALSE(0);
4029 }
4030
4031 /* A <Control>BackSpace at the beginning of the line should only move us to the
4032 * end of the previous line. Anything more than that is non-obvious because it requires
4033 * looking in a position other than where the cursor is.
4034 */
4035 if ((ctk_text_iter_get_line_offset (&insert) == 0) &&
4036 (ctk_text_iter_get_line (&insert) > 0))
4037 {
4038 ctk_text_iter_backward_cursor_position (&insert);
4039 ctk_text_buffer_delete_interactive (buffer, &insert, &end, default_editable);
4040 return TRUE(!(0));
4041 }
4042
4043 /* If only leading whitespaces are on the left of the cursor, delete up
4044 * to the zero position.
4045 */
4046 _ctk_source_iter_get_leading_spaces_end_boundary (&insert, &leading_end);
4047 if (ctk_text_iter_compare (&insert, &leading_end) <= 0)
4048 {
4049 ctk_text_iter_set_line_offset (&insert, 0);
4050 ctk_text_buffer_delete_interactive (buffer, &insert, &end, default_editable);
4051 return TRUE(!(0));
4052 }
4053
4054 return FALSE(0);
4055}
4056
4057static gboolean
4058ctk_source_view_key_press_event (CtkWidget *widget,
4059 CdkEventKey *event)
4060{
4061 CtkSourceView *view;
4062 CtkTextBuffer *buf;
4063 CtkTextIter cur;
4064 CtkTextMark *mark;
4065 guint modifiers;
4066 gint key;
4067 gboolean editable;
4068
4069 view = CTK_SOURCE_VIEW (widget)((((CtkSourceView*) (void *) ((widget)))));
4070 buf = ctk_text_view_get_buffer (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) ((widget))))));
4071
4072 editable = ctk_text_view_get_editable (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) ((widget))))));
4073
4074 /* Be careful when testing for modifier state equality:
4075 * caps lock, num lock,etc need to be taken into account */
4076 modifiers = ctk_accelerator_get_default_mod_mask ();
4077
4078 key = event->keyval;
4079
4080 mark = ctk_text_buffer_get_insert (buf);
4081 ctk_text_buffer_get_iter_at_mark (buf, &cur, mark);
4082
4083 if ((key == CDK_KEY_Return0xff0d || key == CDK_KEY_KP_Enter0xff8d) &&
1
Assuming 'key' is not equal to CDK_KEY_Return
2
Assuming 'key' is not equal to CDK_KEY_KP_Enter
4084 !(event->state & CDK_SHIFT_MASK) &&
4085 view->priv->auto_indent)
4086 {
4087 /* Auto-indent means that when you press ENTER at the end of a
4088 * line, the new line is automatically indented at the same
4089 * level as the previous line.
4090 * SHIFT+ENTER allows to avoid autoindentation.
4091 */
4092 gchar *indent = NULL((void*)0);
4093
4094 /* Calculate line indentation and create indent string. */
4095 indent = compute_indentation (view, &cur);
4096
4097 if (indent != NULL((void*)0))
4098 {
4099 /* Allow input methods to internally handle a key press event.
4100 * If this function returns TRUE, then no further processing should be done
4101 * for this keystroke. */
4102 if (ctk_text_view_im_context_filter_keypress (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))), event))
4103 {
4104 g_free (indent);
4105 return CDK_EVENT_STOP((!(0)));
4106 }
4107
4108 /* Delete any selected text to preserve behavior without auto-indent */
4109 ctk_text_buffer_delete_selection (buf,
4110 TRUE(!(0)),
4111 ctk_text_view_get_editable (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))))));
4112
4113 /* If an input method or deletion has inserted some text while handling the
4114 * key press event, the cur iterm may be invalid, so get the iter again
4115 */
4116 ctk_text_buffer_get_iter_at_mark (buf, &cur, mark);
4117
4118 /* Insert new line and auto-indent. */
4119 ctk_text_buffer_begin_user_action (buf);
4120 ctk_text_buffer_insert (buf, &cur, "\n", 1);
4121 ctk_text_buffer_insert (buf, &cur, indent, strlen (indent));
4122 g_free (indent);
4123 ctk_text_buffer_end_user_action (buf);
4124 ctk_text_view_scroll_mark_onscreen (CTK_TEXT_VIEW (widget)((((CtkTextView*) (void *) ((widget))))),
4125 mark);
4126 return CDK_EVENT_STOP((!(0)));
4127 }
4128 }
4129
4130 /* if tab or shift+tab:
4131 * with shift+tab key is CDK_ISO_Left_Tab (yay! on win32 and mac too!)
4132 */
4133 if ((key == CDK_KEY_Tab0xff09 || key == CDK_KEY_KP_Tab0xff89 || key == CDK_KEY_ISO_Left_Tab0xfe20) &&
3
Assuming 'key' is equal to CDK_KEY_Tab
7
Taking true branch
4134 ((event->state & modifiers) == 0 ||
4
Assuming the condition is true
4135 (event->state & modifiers) == CDK_SHIFT_MASK) &&
4136 editable &&
5
Assuming 'editable' is not equal to 0
4137 ctk_text_view_get_accepts_tab (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view)))))))
6
Assuming the condition is true
4138 {
4139 CtkTextIter s, e;
4140 gboolean has_selection;
4141
4142 has_selection = ctk_text_buffer_get_selection_bounds (buf, &s, &e);
4143
4144 if (view->priv->indent_on_tab)
8
Assuming field 'indent_on_tab' is 0
9
Taking false branch
4145 {
4146 /* shift+tab: always unindent */
4147 if (event->state & CDK_SHIFT_MASK)
4148 {
4149 _ctk_source_buffer_save_and_clear_selection (CTK_SOURCE_BUFFER (buf)((((CtkSourceBuffer*) (void *) ((buf))))));
4150 ctk_source_view_unindent_lines (view, &s, &e);
4151 _ctk_source_buffer_restore_selection (CTK_SOURCE_BUFFER (buf)((((CtkSourceBuffer*) (void *) ((buf))))));
4152 return CDK_EVENT_STOP((!(0)));
4153 }
4154
4155 /* tab: if we have a selection which spans one whole line
4156 * or more, we mass indent, if the selection spans less then
4157 * the full line just replace the text with \t
4158 */
4159 if (has_selection &&
4160 ((ctk_text_iter_starts_line (&s) && ctk_text_iter_ends_line (&e)) ||
4161 (ctk_text_iter_get_line (&s) != ctk_text_iter_get_line (&e))))
4162 {
4163 _ctk_source_buffer_save_and_clear_selection (CTK_SOURCE_BUFFER (buf)((((CtkSourceBuffer*) (void *) ((buf))))));
4164 ctk_source_view_indent_lines (view, &s, &e);
4165 _ctk_source_buffer_restore_selection (CTK_SOURCE_BUFFER (buf)((((CtkSourceBuffer*) (void *) ((buf))))));
4166 return CDK_EVENT_STOP((!(0)));
4167 }
4168 }
4169
4170 insert_tab_or_spaces (view, &s, &e);
10
Calling 'insert_tab_or_spaces'
4171 return CDK_EVENT_STOP((!(0)));
4172 }
4173
4174 if (key == CDK_KEY_BackSpace0xff08)
4175 {
4176 if ((event->state & modifiers) == 0)
4177 {
4178 if (view->priv->smart_backspace && do_smart_backspace (view))
4179 {
4180 return CDK_EVENT_STOP((!(0)));
4181 }
4182 }
4183 else if ((event->state & modifiers) == CDK_CONTROL_MASK)
4184 {
4185 if (do_ctrl_backspace (view))
4186 {
4187 return CDK_EVENT_STOP((!(0)));
4188 }
4189 }
4190 }
4191
4192 return CTK_WIDGET_CLASS (ctk_source_view_parent_class)((((CtkWidgetClass*) (void *) ((ctk_source_view_parent_class)
))))
->key_press_event (widget, event);
4193}
4194
4195/**
4196 * ctk_source_view_get_auto_indent:
4197 * @view: a #CtkSourceView.
4198 *
4199 * Returns whether auto-indentation of text is enabled.
4200 *
4201 * Returns: %TRUE if auto indentation is enabled.
4202 */
4203gboolean
4204ctk_source_view_get_auto_indent (CtkSourceView *view)
4205{
4206 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_85
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_85
= 1; _g_boolean_var_85; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return ((0)); } } while (0)
;
4207
4208 return view->priv->auto_indent;
4209}
4210
4211/**
4212 * ctk_source_view_set_auto_indent:
4213 * @view: a #CtkSourceView.
4214 * @enable: whether to enable auto indentation.
4215 *
4216 * If %TRUE auto-indentation of text is enabled.
4217 *
4218 * When Enter is pressed to create a new line, the auto-indentation inserts the
4219 * same indentation as the previous line. This is <emphasis>not</emphasis> a
4220 * "smart indentation" where an indentation level is added or removed depending
4221 * on the context.
4222 */
4223void
4224ctk_source_view_set_auto_indent (CtkSourceView *view,
4225 gboolean enable)
4226{
4227 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_86
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_86
= 1; _g_boolean_var_86; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
4228
4229 enable = enable != FALSE(0);
4230
4231 if (view->priv->auto_indent != enable)
4232 {
4233 view->priv->auto_indent = enable;
4234 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "auto_indent");
4235 }
4236}
4237
4238/**
4239 * ctk_source_view_get_insert_spaces_instead_of_tabs:
4240 * @view: a #CtkSourceView.
4241 *
4242 * Returns whether when inserting a tabulator character it should
4243 * be replaced by a group of space characters.
4244 *
4245 * Returns: %TRUE if spaces are inserted instead of tabs.
4246 */
4247gboolean
4248ctk_source_view_get_insert_spaces_instead_of_tabs (CtkSourceView *view)
4249{
4250 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_87
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_87
= 1; _g_boolean_var_87; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return ((0)); } } while (0)
;
4251
4252 return view->priv->insert_spaces;
4253}
4254
4255/**
4256 * ctk_source_view_set_insert_spaces_instead_of_tabs:
4257 * @view: a #CtkSourceView.
4258 * @enable: whether to insert spaces instead of tabs.
4259 *
4260 * If %TRUE a tab key pressed is replaced by a group of space characters. Of
4261 * course it is still possible to insert a real \t programmatically with the
4262 * #CtkTextBuffer API.
4263 */
4264void
4265ctk_source_view_set_insert_spaces_instead_of_tabs (CtkSourceView *view,
4266 gboolean enable)
4267{
4268 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_88
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_88
= 1; _g_boolean_var_88; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
4269
4270 enable = enable != FALSE(0);
4271
4272 if (view->priv->insert_spaces != enable)
4273 {
4274 view->priv->insert_spaces = enable;
4275 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "insert_spaces_instead_of_tabs");
4276 }
4277}
4278
4279/**
4280 * ctk_source_view_get_indent_on_tab:
4281 * @view: a #CtkSourceView.
4282 *
4283 * Returns whether when the tab key is pressed the current selection
4284 * should get indented instead of replaced with the \t character.
4285 *
4286 * Return value: %TRUE if the selection is indented when tab is pressed.
4287 */
4288gboolean
4289ctk_source_view_get_indent_on_tab (CtkSourceView *view)
4290{
4291 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_89
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_89
= 1; _g_boolean_var_89; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return ((0)); } } while (0)
;
4292
4293 return view->priv->indent_on_tab;
4294}
4295
4296/**
4297 * ctk_source_view_set_indent_on_tab:
4298 * @view: a #CtkSourceView.
4299 * @enable: whether to indent a block when tab is pressed.
4300 *
4301 * If %TRUE, when the tab key is pressed when several lines are selected, the
4302 * selected lines are indented of one level instead of being replaced with a \t
4303 * character. Shift+Tab unindents the selection.
4304 *
4305 * If the first or last line is not selected completely, it is also indented or
4306 * unindented.
4307 *
4308 * When the selection doesn't span several lines, the tab key always replaces
4309 * the selection with a normal \t character.
4310 */
4311void
4312ctk_source_view_set_indent_on_tab (CtkSourceView *view,
4313 gboolean enable)
4314{
4315 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_90
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_90
= 1; _g_boolean_var_90; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
4316
4317 enable = enable != FALSE(0);
4318
4319 if (view->priv->indent_on_tab != enable)
4320 {
4321 view->priv->indent_on_tab = enable;
4322 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "indent_on_tab");
4323 }
4324}
4325
4326static void
4327view_dnd_drop (CtkTextView *view,
4328 CdkDragContext *context,
4329 gint x,
4330 gint y,
4331 CtkSelectionData *selection_data,
4332 guint info,
4333 guint timestamp,
4334 gpointer data)
4335{
4336
4337 CtkTextIter iter;
4338
4339 if (info == TARGET_COLOR)
4340 {
4341 CdkRGBA rgba;
4342 gchar string[] = "#000000";
4343 gint buffer_x;
4344 gint buffer_y;
4345 gint length = ctk_selection_data_get_length (selection_data);
4346 guint format;
4347
4348 if (length < 0)
4349 {
4350 return;
4351 }
4352
4353 format = ctk_selection_data_get_format (selection_data);
4354
4355 if (format == 8 && length == 4)
4356 {
4357 guint8 *vals;
4358
4359 vals = (gpointer) ctk_selection_data_get_data (selection_data);
4360
4361 rgba.red = vals[0] / 256.0;
4362 rgba.green = vals[1] / 256.0;
4363 rgba.blue = vals[2] / 256.0;
4364 rgba.alpha = 1.0;
4365 }
4366 else if (format == 16 && length == 8)
4367 {
4368 guint16 *vals;
4369
4370 vals = (gpointer) ctk_selection_data_get_data (selection_data);
4371
4372 rgba.red = vals[0] / 65535.0;
4373 rgba.green = vals[1] / 65535.0;
4374 rgba.blue = vals[2] / 65535.0;
4375 rgba.alpha = 1.0;
4376 }
4377 else
4378 {
4379 g_warning ("Received invalid color data\n");
4380 return;
4381 }
4382
4383 g_snprintf (string, sizeof string, "#%02X%02X%02X",
4384 (gint)(rgba.red * 256),
4385 (gint)(rgba.green * 256),
4386 (gint)(rgba.blue * 256));
4387
4388 ctk_text_view_window_to_buffer_coords (view,
4389 CTK_TEXT_WINDOW_TEXT,
4390 x,
4391 y,
4392 &buffer_x,
4393 &buffer_y);
4394 ctk_text_view_get_iter_at_location (view, &iter, buffer_x, buffer_y);
4395
4396 if (ctk_text_view_get_editable (view))
4397 {
4398 ctk_text_buffer_insert (ctk_text_view_get_buffer (view),
4399 &iter,
4400 string,
4401 strlen (string));
4402 ctk_text_buffer_place_cursor (ctk_text_view_get_buffer (view),
4403 &iter);
4404 }
4405
4406 /*
4407 * FIXME: Check if the iter is inside a selection
4408 * If it is, remove the selection and then insert at
4409 * the cursor position - Paolo
4410 */
4411
4412 return;
4413 }
4414}
4415
4416/**
4417 * ctk_source_view_get_highlight_current_line:
4418 * @view: a #CtkSourceView.
4419 *
4420 * Returns whether the current line is highlighted.
4421 *
4422 * Return value: %TRUE if the current line is highlighted.
4423 */
4424gboolean
4425ctk_source_view_get_highlight_current_line (CtkSourceView *view)
4426{
4427 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_91
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_91
= 1; _g_boolean_var_91; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return ((0)); } } while (0)
;
4428
4429 return view->priv->highlight_current_line;
4430}
4431
4432/**
4433 * ctk_source_view_set_highlight_current_line:
4434 * @view: a #CtkSourceView.
4435 * @highlight: whether to highlight the current line.
4436 *
4437 * If @highlight is %TRUE the current line will be highlighted.
4438 */
4439void
4440ctk_source_view_set_highlight_current_line (CtkSourceView *view,
4441 gboolean highlight)
4442{
4443 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_92
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_92
= 1; _g_boolean_var_92; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
4444
4445 highlight = highlight != FALSE(0);
4446
4447 if (view->priv->highlight_current_line != highlight)
4448 {
4449 view->priv->highlight_current_line = highlight;
4450
4451 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))));
4452
4453 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "highlight_current_line");
4454 }
4455}
4456
4457/**
4458 * ctk_source_view_get_show_right_margin:
4459 * @view: a #CtkSourceView.
4460 *
4461 * Returns whether a right margin is displayed.
4462 *
4463 * Return value: %TRUE if the right margin is shown.
4464 */
4465gboolean
4466ctk_source_view_get_show_right_margin (CtkSourceView *view)
4467{
4468 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_93
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_93
= 1; _g_boolean_var_93; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return ((0)); } } while (0)
;
4469
4470 return view->priv->show_right_margin;
4471}
4472
4473/**
4474 * ctk_source_view_set_show_right_margin:
4475 * @view: a #CtkSourceView.
4476 * @show: whether to show a right margin.
4477 *
4478 * If %TRUE a right margin is displayed.
4479 */
4480void
4481ctk_source_view_set_show_right_margin (CtkSourceView *view,
4482 gboolean show)
4483{
4484 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_94
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_94
= 1; _g_boolean_var_94; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
4485
4486 show = show != FALSE(0);
4487
4488 if (view->priv->show_right_margin != show)
4489 {
4490 view->priv->show_right_margin = show;
4491
4492 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))));
4493
4494 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "show-right-margin");
4495 }
4496}
4497
4498/**
4499 * ctk_source_view_get_right_margin_position:
4500 * @view: a #CtkSourceView.
4501 *
4502 * Gets the position of the right margin in the given @view.
4503 *
4504 * Return value: the position of the right margin.
4505 */
4506guint
4507ctk_source_view_get_right_margin_position (CtkSourceView *view)
4508{
4509 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), DEFAULT_RIGHT_MARGIN_POSITION)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_95
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_95
= 1; _g_boolean_var_95; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return (80); } } while (0)
;
4510
4511 return view->priv->right_margin_pos;
4512}
4513
4514/**
4515 * ctk_source_view_set_right_margin_position:
4516 * @view: a #CtkSourceView.
4517 * @pos: the width in characters where to position the right margin.
4518 *
4519 * Sets the position of the right margin in the given @view.
4520 */
4521void
4522ctk_source_view_set_right_margin_position (CtkSourceView *view,
4523 guint pos)
4524{
4525 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_96
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_96
= 1; _g_boolean_var_96; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
4526 g_return_if_fail (1 <= pos && pos <= MAX_RIGHT_MARGIN_POSITION)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_97
= 0; if (1 <= pos && pos <= 1000) _g_boolean_var_97
= 1; _g_boolean_var_97; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "1 <= pos && pos <= MAX_RIGHT_MARGIN_POSITION"
); return; } } while (0)
;
4527
4528 if (view->priv->right_margin_pos != pos)
4529 {
4530 view->priv->right_margin_pos = pos;
4531 view->priv->cached_right_margin_pos = -1;
4532
4533 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))));
4534
4535 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "right-margin-position");
4536 }
4537}
4538
4539/**
4540 * ctk_source_view_set_smart_backspace:
4541 * @view: a #CtkSourceView.
4542 * @smart_backspace: whether to enable smart Backspace handling.
4543 *
4544 * When set to %TRUE, pressing the Backspace key will try to delete spaces
4545 * up to the previous tab stop.
4546 *
4547 * Since: 3.18
4548 */
4549void
4550ctk_source_view_set_smart_backspace (CtkSourceView *view,
4551 gboolean smart_backspace)
4552{
4553 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_98
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_98
= 1; _g_boolean_var_98; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
4554
4555 smart_backspace = smart_backspace != FALSE(0);
4556
4557 if (smart_backspace != view->priv->smart_backspace)
4558 {
4559 view->priv->smart_backspace = smart_backspace;
4560 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "smart-backspace");
4561 }
4562}
4563
4564/**
4565 * ctk_source_view_get_smart_backspace:
4566 * @view: a #CtkSourceView.
4567 *
4568 * Returns %TRUE if pressing the Backspace key will try to delete spaces
4569 * up to the previous tab stop.
4570 *
4571 * Returns: %TRUE if smart Backspace handling is enabled.
4572 *
4573 * Since: 3.18
4574 */
4575gboolean
4576ctk_source_view_get_smart_backspace (CtkSourceView *view)
4577{
4578 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_99
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_99
= 1; _g_boolean_var_99; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return ((0)); } } while (0)
;
4579
4580 return view->priv->smart_backspace;
4581}
4582
4583/**
4584 * ctk_source_view_set_smart_home_end:
4585 * @view: a #CtkSourceView.
4586 * @smart_home_end: the desired behavior among #CtkSourceSmartHomeEndType.
4587 *
4588 * Set the desired movement of the cursor when HOME and END keys
4589 * are pressed.
4590 */
4591void
4592ctk_source_view_set_smart_home_end (CtkSourceView *view,
4593 CtkSourceSmartHomeEndType smart_home_end)
4594{
4595 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_100
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_100
= 1; _g_boolean_var_100; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
4596
4597 if (view->priv->smart_home_end != smart_home_end)
4598 {
4599 view->priv->smart_home_end = smart_home_end;
4600 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "smart_home_end");
4601 }
4602}
4603
4604/**
4605 * ctk_source_view_get_smart_home_end:
4606 * @view: a #CtkSourceView.
4607 *
4608 * Returns a #CtkSourceSmartHomeEndType end value specifying
4609 * how the cursor will move when HOME and END keys are pressed.
4610 *
4611 * Returns: a #CtkSourceSmartHomeEndType value.
4612 */
4613CtkSourceSmartHomeEndType
4614ctk_source_view_get_smart_home_end (CtkSourceView *view)
4615{
4616 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_101
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_101
= 1; _g_boolean_var_101; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return ((0)); } } while (0)
;
4617
4618 return view->priv->smart_home_end;
4619}
4620
4621/**
4622 * ctk_source_view_get_visual_column:
4623 * @view: a #CtkSourceView.
4624 * @iter: a position in @view.
4625 *
4626 * Determines the visual column at @iter taking into consideration the
4627 * #CtkSourceView:tab-width of @view.
4628 *
4629 * Returns: the visual column at @iter.
4630 */
4631guint
4632ctk_source_view_get_visual_column (CtkSourceView *view,
4633 const CtkTextIter *iter)
4634{
4635 CtkTextIter position;
4636 guint column;
4637 guint tab_width;
4638
4639 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), 0)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_102
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_102
= 1; _g_boolean_var_102; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return (0); } } while (0)
;
4640 g_return_val_if_fail (iter != NULL, 0)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_103
= 0; if (iter != ((void*)0)) _g_boolean_var_103 = 1; _g_boolean_var_103
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "iter != NULL"); return (0); } }
while (0)
;
4641
4642 column = 0;
4643 tab_width = view->priv->tab_width;
4644
4645 position = *iter;
4646 ctk_text_iter_set_line_offset (&position, 0);
4647
4648 while (!ctk_text_iter_equal (&position, iter))
4649 {
4650 if (ctk_text_iter_get_char (&position) == '\t')
4651 {
4652 column += (tab_width - (column % tab_width));
4653 }
4654 else
4655 {
4656 ++column;
4657 }
4658
4659 /* FIXME: this does not handle invisible text correctly, but
4660 * ctk_text_iter_forward_visible_cursor_position is too slow */
4661 if (!ctk_text_iter_forward_char (&position))
4662 {
4663 break;
4664 }
4665 }
4666
4667 return column;
4668}
4669
4670static void
4671update_background_pattern_color (CtkSourceView *view)
4672{
4673 if (view->priv->style_scheme == NULL((void*)0))
4674 {
4675 view->priv->background_pattern_color_set = FALSE(0);
4676 return;
4677 }
4678
4679 view->priv->background_pattern_color_set =
4680 _ctk_source_style_scheme_get_background_pattern_color (view->priv->style_scheme,
4681 &view->priv->background_pattern_color);
4682}
4683
4684static void
4685update_current_line_color (CtkSourceView *view)
4686{
4687 if (view->priv->style_scheme == NULL((void*)0))
4688 {
4689 view->priv->current_line_color_set = FALSE(0);
4690 return;
4691 }
4692
4693 view->priv->current_line_color_set =
4694 _ctk_source_style_scheme_get_current_line_color (view->priv->style_scheme,
4695 &view->priv->current_line_color);
4696}
4697
4698static void
4699update_right_margin_colors (CtkSourceView *view)
4700{
4701 CtkWidget *widget = CTK_WIDGET (view)((((CtkWidget*) (void *) ((view)))));
4702
4703 if (view->priv->right_margin_line_color != NULL((void*)0))
4704 {
4705 cdk_rgba_free (view->priv->right_margin_line_color);
4706 view->priv->right_margin_line_color = NULL((void*)0);
4707 }
4708
4709 if (view->priv->right_margin_overlay_color != NULL((void*)0))
4710 {
4711 cdk_rgba_free (view->priv->right_margin_overlay_color);
4712 view->priv->right_margin_overlay_color = NULL((void*)0);
4713 }
4714
4715 if (view->priv->style_scheme != NULL((void*)0))
4716 {
4717 CtkSourceStyle *style;
4718
4719 style = _ctk_source_style_scheme_get_right_margin_style (view->priv->style_scheme);
4720
4721 if (style != NULL((void*)0))
4722 {
4723 gchar *color_str = NULL((void*)0);
4724 gboolean color_set;
4725 CdkRGBA color;
4726
4727 g_object_get (style,
4728 "foreground", &color_str,
4729 "foreground-set", &color_set,
4730 NULL((void*)0));
4731
4732 if (color_set &&
4733 color_str != NULL((void*)0) &&
4734 cdk_rgba_parse (&color, color_str))
4735 {
4736 view->priv->right_margin_line_color = cdk_rgba_copy (&color);
4737 view->priv->right_margin_line_color->alpha =
4738 RIGHT_MARGIN_LINE_ALPHA40 / 255.;
4739 }
4740
4741 g_free (color_str);
4742 color_str = NULL((void*)0);
4743
4744 g_object_get (style,
4745 "background", &color_str,
4746 "background-set", &color_set,
4747 NULL((void*)0));
4748
4749 if (color_set &&
4750 color_str != NULL((void*)0) &&
4751 cdk_rgba_parse (&color, color_str))
4752 {
4753 view->priv->right_margin_overlay_color = cdk_rgba_copy (&color);
4754 view->priv->right_margin_overlay_color->alpha =
4755 RIGHT_MARGIN_OVERLAY_ALPHA15 / 255.;
4756 }
4757
4758 g_free (color_str);
4759 }
4760 }
4761
4762 if (view->priv->right_margin_line_color == NULL((void*)0))
4763 {
4764 CtkStyleContext *context;
4765 CdkRGBA color;
4766
4767 context = ctk_widget_get_style_context (widget);
4768 ctk_style_context_save (context);
4769 ctk_style_context_set_state (context, CTK_STATE_FLAG_NORMAL);
4770 ctk_style_context_get_color (context,
4771 ctk_style_context_get_state (context),
4772 &color);
4773 ctk_style_context_restore (context);
4774
4775 view->priv->right_margin_line_color = cdk_rgba_copy (&color);
4776 view->priv->right_margin_line_color->alpha =
4777 RIGHT_MARGIN_LINE_ALPHA40 / 255.;
4778 }
4779}
4780
4781static void
4782update_style (CtkSourceView *view)
4783{
4784 update_background_pattern_color (view);
4785 update_current_line_color (view);
4786 update_right_margin_colors (view);
4787
4788 if (view->priv->space_drawer != NULL((void*)0))
4789 {
4790 _ctk_source_space_drawer_update_color (view->priv->space_drawer, view);
4791 }
4792
4793 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))));
4794}
4795
4796static void
4797ctk_source_view_update_style_scheme (CtkSourceView *view)
4798{
4799 CtkTextBuffer *buffer;
4800 CtkSourceStyleScheme *new_scheme = NULL((void*)0);
4801
4802 buffer = ctk_text_view_get_buffer (CTK_TEXT_VIEW (view)((((CtkTextView*) (void *) ((view))))));
4803
4804 if (CTK_SOURCE_IS_BUFFER (buffer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(buffer)); GType __t = ((ctk_source_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; }))))
)
4805 {
4806 new_scheme = ctk_source_buffer_get_style_scheme (CTK_SOURCE_BUFFER (buffer)((((CtkSourceBuffer*) (void *) ((buffer))))));
4807 }
4808
4809 if (view->priv->style_scheme == new_scheme)
4810 {
4811 return;
4812 }
4813
4814 if (view->priv->style_scheme != NULL((void*)0))
4815 {
4816 _ctk_source_style_scheme_unapply (view->priv->style_scheme, view);
4817 }
4818
4819 g_set_object (&view->priv->style_scheme, new_scheme)(__extension__ ({ _Static_assert (sizeof *(&view->priv
->style_scheme) == sizeof (new_scheme), "Expression evaluates to false"
); union { char *in; GObject **out; } _object_ptr; _object_ptr
.in = (char *) (&view->priv->style_scheme); (void) (
0 ? *(&view->priv->style_scheme) = (new_scheme), (0
) : (0)); (g_set_object) (_object_ptr.out, (GObject *) new_scheme
); }))
;
4820
4821 if (view->priv->style_scheme != NULL((void*)0))
4822 {
4823 _ctk_source_style_scheme_apply (view->priv->style_scheme, view);
4824 }
4825
4826 update_style (view);
4827}
4828
4829static void
4830ctk_source_view_style_updated (CtkWidget *widget)
4831{
4832 CtkSourceView *view = CTK_SOURCE_VIEW (widget)((((CtkSourceView*) (void *) ((widget)))));
4833
4834 /* Call default handler first. */
4835 if (CTK_WIDGET_CLASS (ctk_source_view_parent_class)((((CtkWidgetClass*) (void *) ((ctk_source_view_parent_class)
))))
->style_updated != NULL((void*)0))
4836 {
4837 CTK_WIDGET_CLASS (ctk_source_view_parent_class)((((CtkWidgetClass*) (void *) ((ctk_source_view_parent_class)
))))
->style_updated (widget);
4838 }
4839
4840 /* Re-set tab stops, but only if we already modified them, i.e.
4841 * do nothing with good old 8-space tabs.
4842 */
4843 if (view->priv->tabs_set)
4844 {
4845 set_tab_stops_internal (view);
4846 }
4847
4848 /* Make sure the margin position is recalculated on next redraw. */
4849 view->priv->cached_right_margin_pos = -1;
4850
4851 update_style (view);
4852}
4853
4854static MarkCategory *
4855mark_category_new (CtkSourceMarkAttributes *attributes,
4856 gint priority)
4857{
4858 MarkCategory* category = g_slice_new (MarkCategory)((MarkCategory*) g_slice_alloc (sizeof (MarkCategory)));
4859
4860 category->attributes = g_object_ref (attributes);
4861 category->priority = priority;
4862
4863 return category;
4864}
4865
4866static void
4867mark_category_free (MarkCategory *category)
4868{
4869 if (category != NULL((void*)0))
4870 {
4871 g_object_unref (category->attributes);
4872 g_slice_free (MarkCategory, category)do { if (1) g_slice_free1 (sizeof (MarkCategory), (category))
; else (void) ((MarkCategory*) 0 == (category)); } while (0)
;
4873 }
4874}
4875
4876/**
4877 * ctk_source_view_get_completion:
4878 * @view: a #CtkSourceView.
4879 *
4880 * Gets the #CtkSourceCompletion associated with @view. The returned object is
4881 * guaranteed to be the same for the lifetime of @view. Each #CtkSourceView
4882 * object has a different #CtkSourceCompletion.
4883 *
4884 * Returns: (transfer none): the #CtkSourceCompletion associated with @view.
4885 */
4886CtkSourceCompletion *
4887ctk_source_view_get_completion (CtkSourceView *view)
4888{
4889 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_104
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_104
= 1; _g_boolean_var_104; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return (((void*)0)); } } while (0)
;
4890
4891 if (view->priv->completion == NULL((void*)0))
4892 {
4893 view->priv->completion = ctk_source_completion_new (view);
4894 }
4895
4896 return view->priv->completion;
4897}
4898
4899/**
4900 * ctk_source_view_get_gutter:
4901 * @view: a #CtkSourceView.
4902 * @window_type: the gutter window type.
4903 *
4904 * Returns the #CtkSourceGutter object associated with @window_type for @view.
4905 * Only CTK_TEXT_WINDOW_LEFT and CTK_TEXT_WINDOW_RIGHT are supported,
4906 * respectively corresponding to the left and right gutter. The line numbers
4907 * and mark category icons are rendered in the left gutter.
4908 *
4909 * Since: 2.8
4910 *
4911 * Returns: (transfer none): the #CtkSourceGutter.
4912 */
4913CtkSourceGutter *
4914ctk_source_view_get_gutter (CtkSourceView *view,
4915 CtkTextWindowType window_type)
4916{
4917 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_105
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_105
= 1; _g_boolean_var_105; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return (((void*)0)); } } while (0)
;
4918 g_return_val_if_fail (window_type == CTK_TEXT_WINDOW_LEFT ||do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_106
= 0; if (window_type == CTK_TEXT_WINDOW_LEFT || window_type ==
CTK_TEXT_WINDOW_RIGHT) _g_boolean_var_106 = 1; _g_boolean_var_106
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "window_type == CTK_TEXT_WINDOW_LEFT || window_type == CTK_TEXT_WINDOW_RIGHT"
); return (((void*)0)); } } while (0)
4919 window_type == CTK_TEXT_WINDOW_RIGHT, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_106
= 0; if (window_type == CTK_TEXT_WINDOW_LEFT || window_type ==
CTK_TEXT_WINDOW_RIGHT) _g_boolean_var_106 = 1; _g_boolean_var_106
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "window_type == CTK_TEXT_WINDOW_LEFT || window_type == CTK_TEXT_WINDOW_RIGHT"
); return (((void*)0)); } } while (0)
;
4920
4921 if (window_type == CTK_TEXT_WINDOW_LEFT)
4922 {
4923 if (view->priv->left_gutter == NULL((void*)0))
4924 {
4925 view->priv->left_gutter = _ctk_source_gutter_new (view, window_type);
4926 }
4927
4928 return view->priv->left_gutter;
4929 }
4930 else
4931 {
4932 if (view->priv->right_gutter == NULL((void*)0))
4933 {
4934 view->priv->right_gutter = _ctk_source_gutter_new (view, window_type);
4935 }
4936
4937 return view->priv->right_gutter;
4938 }
4939}
4940
4941/**
4942 * ctk_source_view_set_mark_attributes:
4943 * @view: a #CtkSourceView.
4944 * @category: the category.
4945 * @attributes: mark attributes.
4946 * @priority: priority of the category.
4947 *
4948 * Sets attributes and priority for the @category.
4949 */
4950void
4951ctk_source_view_set_mark_attributes (CtkSourceView *view,
4952 const gchar *category,
4953 CtkSourceMarkAttributes *attributes,
4954 gint priority)
4955{
4956 MarkCategory *mark_category;
4957
4958 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_107
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_107
= 1; _g_boolean_var_107; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
4959 g_return_if_fail (category != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_108
= 0; if (category != ((void*)0)) _g_boolean_var_108 = 1; _g_boolean_var_108
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "category != NULL"); return; } }
while (0)
;
4960 g_return_if_fail (CTK_SOURCE_IS_MARK_ATTRIBUTES (attributes))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_109
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((attributes)); GType __t = ((ctk_source_mark_attributes_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; }))))) _g_boolean_var_109 = 1; _g_boolean_var_109; }), 1
))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const
char*) (__func__)), "CTK_SOURCE_IS_MARK_ATTRIBUTES (attributes)"
); return; } } while (0)
;
4961 g_return_if_fail (priority >= 0)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_110
= 0; if (priority >= 0) _g_boolean_var_110 = 1; _g_boolean_var_110
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "priority >= 0"); return; } }
while (0)
;
4962
4963 mark_category = mark_category_new (attributes, priority);
4964 g_hash_table_replace (view->priv->mark_categories,
4965 g_strdup (category)g_strdup_inline (category),
4966 mark_category);
4967}
4968
4969/**
4970 * ctk_source_view_get_mark_attributes:
4971 * @view: a #CtkSourceView.
4972 * @category: the category.
4973 * @priority: place where priority of the category will be stored.
4974 *
4975 * Gets attributes and priority for the @category.
4976 *
4977 * Returns: (transfer none): #CtkSourceMarkAttributes for the @category.
4978 * The object belongs to @view, so it must not be unreffed.
4979 */
4980CtkSourceMarkAttributes *
4981ctk_source_view_get_mark_attributes (CtkSourceView *view,
4982 const gchar *category,
4983 gint *priority)
4984{
4985 MarkCategory *mark_category;
4986
4987 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_111
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_111
= 1; _g_boolean_var_111; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return (((void*)0)); } } while (0)
;
4988 g_return_val_if_fail (category != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_112
= 0; if (category != ((void*)0)) _g_boolean_var_112 = 1; _g_boolean_var_112
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "category != NULL"); return (((
void*)0)); } } while (0)
;
4989
4990 mark_category = g_hash_table_lookup (view->priv->mark_categories,
4991 category);
4992
4993 if (mark_category != NULL((void*)0))
4994 {
4995 if (priority != NULL((void*)0))
4996 {
4997 *priority = mark_category->priority;
4998 }
4999
5000 return mark_category->attributes;
5001 }
5002
5003 return NULL((void*)0);
5004}
5005
5006/**
5007 * ctk_source_view_set_background_pattern:
5008 * @view: a #CtkSourceView.
5009 * @background_pattern: the #CtkSourceBackgroundPatternType.
5010 *
5011 * Set if and how the background pattern should be displayed.
5012 *
5013 * Since: 3.16
5014 */
5015void
5016ctk_source_view_set_background_pattern (CtkSourceView *view,
5017 CtkSourceBackgroundPatternType background_pattern)
5018{
5019 g_return_if_fail (CTK_SOURCE_IS_VIEW (view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_113
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_113
= 1; _g_boolean_var_113; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return; } } while (0)
;
5020
5021 if (view->priv->background_pattern != background_pattern)
5022 {
5023 view->priv->background_pattern = background_pattern;
5024
5025 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) ((view))))));
5026
5027 g_object_notify (G_OBJECT (view)((((GObject*) (void *) ((view))))), "background-pattern");
5028 }
5029}
5030
5031/**
5032 * ctk_source_view_get_background_pattern:
5033 * @view: a #CtkSourceView
5034 *
5035 * Returns the #CtkSourceBackgroundPatternType specifying if and how
5036 * the background pattern should be displayed for this @view.
5037 *
5038 * Returns: the #CtkSourceBackgroundPatternType.
5039 * Since: 3.16
5040 */
5041CtkSourceBackgroundPatternType
5042ctk_source_view_get_background_pattern (CtkSourceView *view)
5043{
5044 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), CTK_SOURCE_BACKGROUND_PATTERN_TYPE_NONE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_114
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_114
= 1; _g_boolean_var_114; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return (CTK_SOURCE_BACKGROUND_PATTERN_TYPE_NONE); } } while
(0)
;
5045
5046 return view->priv->background_pattern;
5047}
5048
5049/**
5050 * ctk_source_view_get_space_drawer:
5051 * @view: a #CtkSourceView.
5052 *
5053 * Gets the #CtkSourceSpaceDrawer associated with @view. The returned object is
5054 * guaranteed to be the same for the lifetime of @view. Each #CtkSourceView
5055 * object has a different #CtkSourceSpaceDrawer.
5056 *
5057 * Returns: (transfer none): the #CtkSourceSpaceDrawer associated with @view.
5058 * Since: 3.24
5059 */
5060CtkSourceSpaceDrawer *
5061ctk_source_view_get_space_drawer (CtkSourceView *view)
5062{
5063 g_return_val_if_fail (CTK_SOURCE_IS_VIEW (view), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_115
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ctk_source_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; }))))) _g_boolean_var_115
= 1; _g_boolean_var_115; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_VIEW (view)"
); return (((void*)0)); } } while (0)
;
5064
5065 return view->priv->space_drawer;
5066}