summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci/test-msys2.sh2
-rw-r--r--demos/gtk-demo/hypertext.c10
-rw-r--r--demos/gtk-demo/tabs.c16
-rw-r--r--gdk/wayland/gdkdevice-wayland.c7
-rw-r--r--gdk/win32/gdksurface-win32.c2
-rw-r--r--gsk/gl/gskglcompiler.c29
-rw-r--r--gtk/gtkgesturestylus.c18
-rw-r--r--gtk/gtktext.c96
-rw-r--r--gtk/gtktextbtree.c35
-rw-r--r--gtk/gtktextchild.c33
-rw-r--r--gtk/gtktextchild.h14
-rw-r--r--gtk/gtktextiter.c4
-rw-r--r--gtk/gtktextlayout.c2
-rw-r--r--meson.build4
-rw-r--r--testsuite/gtk/textbuffer.c71
15 files changed, 244 insertions, 99 deletions
diff --git a/.gitlab-ci/test-msys2.sh b/.gitlab-ci/test-msys2.sh
index 8cfc30f0bd..4c59a26a9d 100644
--- a/.gitlab-ci/test-msys2.sh
+++ b/.gitlab-ci/test-msys2.sh
@@ -48,7 +48,7 @@ if ! pkg-config --atleast-version=2.66.0 glib-2.0; then
fi
pkg-config --modversion glib-2.0
-if ! pkg-config --atleast-version=1.49.3 pango; then
+if ! pkg-config --atleast-version=1.50.0 pango; then
git clone https://gitlab.gnome.org/GNOME/pango.git _pango
meson setup _pango_build _pango
meson compile -C _pango_build
diff --git a/demos/gtk-demo/hypertext.c b/demos/gtk-demo/hypertext.c
index b38f474c33..e47f691f53 100644
--- a/demos/gtk-demo/hypertext.c
+++ b/demos/gtk-demo/hypertext.c
@@ -7,7 +7,8 @@
* shows.
*
* We also demonstrate adding other things to a text view, such as
- * clickable icons.
+ * clickable icons and widgets which can also replace a character
+ * (try copying the ghost text).
*/
#include <gtk/gtk.h>
@@ -113,7 +114,12 @@ show_page (GtkTextView *text_view,
gtk_level_bar_set_value (GTK_LEVEL_BAR (child), 50);
gtk_widget_set_size_request (child, 100, -1);
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
- gtk_text_buffer_insert (buffer, &iter, ".", -1);
+ gtk_text_buffer_insert (buffer, &iter, " and labels with ", -1);
+ anchor = gtk_text_child_anchor_new_with_replacement ("👻");
+ gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
+ child = gtk_label_new ("ghost");
+ gtk_text_view_add_child_at_anchor (text_view, child, anchor);
+ gtk_text_buffer_insert (buffer, &iter, " text.", -1);
}
else if (page == 2)
{
diff --git a/demos/gtk-demo/tabs.c b/demos/gtk-demo/tabs.c
index aaa33af822..b9db82f333 100644
--- a/demos/gtk-demo/tabs.c
+++ b/demos/gtk-demo/tabs.c
@@ -1,6 +1,11 @@
/* Text View/Tabs
*
* GtkTextView can position text at fixed positions, using tabs.
+ * Tabs can specify alignment, and also allow aligning numbers
+ * on the decimal point.
+ *
+ * The example here has three tabs, with left, numeric and right
+ * alignment.
*/
#include <gtk/gtk.h>
@@ -22,7 +27,7 @@ do_tabs (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Tabs");
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
- gtk_window_set_default_size (GTK_WINDOW (window), 330, 330);
+ gtk_window_set_default_size (GTK_WINDOW (window), 330, 130);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
@@ -35,17 +40,18 @@ do_tabs (GtkWidget *do_widget)
tabs = pango_tab_array_new (3, TRUE);
pango_tab_array_set_tab (tabs, 0, PANGO_TAB_LEFT, 0);
- pango_tab_array_set_tab (tabs, 1, PANGO_TAB_LEFT, 100);
- pango_tab_array_set_tab (tabs, 2, PANGO_TAB_LEFT, 200);
+ pango_tab_array_set_tab (tabs, 1, PANGO_TAB_DECIMAL, 150);
+ pango_tab_array_set_decimal_point (tabs, 1, '.');
+ pango_tab_array_set_tab (tabs, 2, PANGO_TAB_RIGHT, 290);
gtk_text_view_set_tabs (GTK_TEXT_VIEW (view), tabs);
pango_tab_array_free (tabs);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
- gtk_text_buffer_set_text (buffer, "one\ttwo\tthree\nfour\tfive\tsix\nseven\teight\tnine", -1);
+ gtk_text_buffer_set_text (buffer, "one\t2.0\tthree\nfour\t5.555\tsix\nseven\t88.88\tnine", -1);
sw = gtk_scrolled_window_new ();
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
- GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
gtk_window_set_child (GTK_WINDOW (window), sw);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), view);
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index fdfb8968c0..8a45e911e9 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -3606,6 +3606,10 @@ tablet_tool_handle_proximity_out (void *data,
g_object_unref (tablet->pointer_info.focus);
tablet->pointer_info.focus = NULL;
+ tablet->pointer_info.button_modifiers &=
+ ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
+ GDK_BUTTON4_MASK | GDK_BUTTON5_MASK);
+
gdk_device_update_tool (tablet->stylus_device, NULL);
g_clear_object (&tablet->pointer_info.cursor);
}
@@ -3621,7 +3625,6 @@ tablet_create_button_event_frame (GdkWaylandTabletData *tablet,
GdkEventType evtype,
guint button)
{
- GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat);
GdkEvent *event;
event = gdk_button_event_new (evtype,
@@ -3629,7 +3632,7 @@ tablet_create_button_event_frame (GdkWaylandTabletData *tablet,
tablet->logical_device,
tablet->current_tool->tool,
tablet->pointer_info.time,
- device_get_modifiers (seat->logical_pointer),
+ device_get_modifiers (tablet->logical_device),
button,
tablet->pointer_info.surface_x,
tablet->pointer_info.surface_y,
diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c
index 6cfe38f679..1b4effa80f 100644
--- a/gdk/win32/gdksurface-win32.c
+++ b/gdk/win32/gdksurface-win32.c
@@ -638,6 +638,7 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
return NULL;
}
+ gdk_surface_set_egl_native_window (surface, (void *) impl->handle);
if (display_win32->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINPOINTER)
gdk_winpointer_initialize_surface (surface);
@@ -693,6 +694,7 @@ gdk_win32_surface_destroy (GdkSurface *window,
if (!foreign_destroy)
{
+ gdk_surface_set_egl_native_window (window, NULL);
window->destroyed = TRUE;
DestroyWindow (GDK_SURFACE_HWND (window));
}
diff --git a/gsk/gl/gskglcompiler.c b/gsk/gl/gskglcompiler.c
index c885df8f45..ca76c60aae 100644
--- a/gsk/gl/gskglcompiler.c
+++ b/gsk/gl/gskglcompiler.c
@@ -28,10 +28,11 @@
#include "gskglcompilerprivate.h"
#include "gskglprogramprivate.h"
-#define SHADER_VERSION_GLES 100
-#define SHADER_VERSION_GL2_LEGACY 110
-#define SHADER_VERSION_GL3_LEGACY 130
-#define SHADER_VERSION_GL3 150
+#define SHADER_VERSION_GLES "100"
+#define SHADER_VERSION_GLES3 "300 es"
+#define SHADER_VERSION_GL2_LEGACY "110"
+#define SHADER_VERSION_GL3_LEGACY "130"
+#define SHADER_VERSION_GL3 "150"
struct _GskGLCompiler
{
@@ -49,7 +50,7 @@ struct _GskGLCompiler
GArray *attrib_locations;
- int glsl_version;
+ const char *glsl_version;
guint gl3 : 1;
guint gles : 1;
@@ -98,7 +99,7 @@ gsk_gl_compiler_class_init (GskGLCompilerClass *klass)
static void
gsk_gl_compiler_init (GskGLCompiler *self)
{
- self->glsl_version = 150;
+ self->glsl_version = "150";
self->attrib_locations = g_array_new (FALSE, FALSE, sizeof (GskGLProgramAttrib));
self->all_preamble = g_bytes_ref (empty_bytes);
self->vertex_preamble = g_bytes_ref (empty_bytes);
@@ -127,8 +128,18 @@ gsk_gl_compiler_new (GskGLDriver *driver,
if (gdk_gl_context_get_use_es (context))
{
- self->glsl_version = SHADER_VERSION_GLES;
- self->gles = TRUE;
+ int maj, min;
+
+ /* for OpenGL/ES 3.0+, use "300 es" as our shader version */
+ gdk_gl_context_get_version (context, &maj, &min);
+
+ if (maj >= 3)
+ self->glsl_version = SHADER_VERSION_GLES3;
+ else
+ {
+ self->glsl_version = SHADER_VERSION_GLES;
+ self->gles = TRUE;
+ }
}
else if (gdk_gl_context_is_legacy (context))
{
@@ -546,7 +557,7 @@ gsk_gl_compiler_compile (GskGLCompiler *self,
gsk_gl_command_queue_make_current (self->driver->command_queue);
- g_snprintf (version, sizeof version, "#version %d\n", self->glsl_version);
+ g_snprintf (version, sizeof version, "#version %s\n", self->glsl_version);
if (self->debug_shaders)
debug = "#define GSK_DEBUG 1\n";
diff --git a/gtk/gtkgesturestylus.c b/gtk/gtkgesturestylus.c
index 3422a037f5..eba6848759 100644
--- a/gtk/gtkgesturestylus.c
+++ b/gtk/gtkgesturestylus.c
@@ -194,16 +194,6 @@ gtk_gesture_stylus_new (void)
NULL);
}
-static GdkEvent *
-gesture_get_current_event (GtkGestureStylus *gesture)
-{
- GdkEventSequence *sequence;
-
- sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
-
- return gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
-}
-
/**
* gtk_gesture_stylus_get_axis:
* @gesture: a `GtkGestureStylus`
@@ -230,7 +220,7 @@ gtk_gesture_stylus_get_axis (GtkGestureStylus *gesture,
g_return_val_if_fail (axis < GDK_AXIS_LAST, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
- event = gesture_get_current_event (gesture);
+ event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (gesture));
if (!event)
return FALSE;
@@ -264,7 +254,7 @@ gtk_gesture_stylus_get_axes (GtkGestureStylus *gesture,
g_return_val_if_fail (GTK_IS_GESTURE_STYLUS (gesture), FALSE);
g_return_val_if_fail (values != NULL, FALSE);
- event = gesture_get_current_event (gesture);
+ event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (gesture));
if (!event)
return FALSE;
@@ -331,7 +321,7 @@ gtk_gesture_stylus_get_backlog (GtkGestureStylus *gesture,
g_return_val_if_fail (GTK_IS_GESTURE_STYLUS (gesture), FALSE);
g_return_val_if_fail (backlog != NULL && n_elems != NULL, FALSE);
- event = gesture_get_current_event (gesture);
+ event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (gesture));
if (event && GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY))
history = gdk_event_get_history (event, &n_coords);
@@ -391,7 +381,7 @@ gtk_gesture_stylus_get_device_tool (GtkGestureStylus *gesture)
g_return_val_if_fail (GTK_IS_GESTURE_STYLUS (gesture), FALSE);
- event = gesture_get_current_event (gesture);
+ event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (gesture));
if (!event)
return NULL;
diff --git a/gtk/gtktext.c b/gtk/gtktext.c
index 43d8c52d62..b4767f7c13 100644
--- a/gtk/gtktext.c
+++ b/gtk/gtktext.c
@@ -386,9 +386,9 @@ static void gtk_text_set_editable (GtkText *self,
static void gtk_text_set_text (GtkText *self,
const char *text);
static void gtk_text_set_width_chars (GtkText *self,
- int n_chars);
+ int n_chars);
static void gtk_text_set_max_width_chars (GtkText *self,
- int n_chars);
+ int n_chars);
static void gtk_text_set_alignment (GtkText *self,
float xalign);
@@ -415,7 +415,7 @@ static void gtk_text_toggle_overwrite (GtkText *self);
static void gtk_text_insert_emoji (GtkText *self);
static void gtk_text_select_all (GtkText *self);
static void gtk_text_real_activate (GtkText *self);
-
+
static void direction_changed (GdkDevice *keyboard,
GParamSpec *pspec,
GtkText *self);
@@ -438,19 +438,19 @@ static gboolean gtk_text_delete_surrounding_cb (GtkIMContext *context,
/* Entry buffer signal handlers
*/
-static void buffer_inserted_text (GtkEntryBuffer *buffer,
+static void buffer_inserted_text (GtkEntryBuffer *buffer,
guint position,
const char *chars,
guint n_chars,
GtkText *self);
-static void buffer_deleted_text (GtkEntryBuffer *buffer,
+static void buffer_deleted_text (GtkEntryBuffer *buffer,
guint position,
guint n_chars,
GtkText *self);
-static void buffer_notify_text (GtkEntryBuffer *buffer,
+static void buffer_notify_text (GtkEntryBuffer *buffer,
GParamSpec *spec,
GtkText *self);
-static void buffer_notify_max_length (GtkEntryBuffer *buffer,
+static void buffer_notify_max_length (GtkEntryBuffer *buffer,
GParamSpec *spec,
GtkText *self);
@@ -700,7 +700,7 @@ add_move_binding (GtkWidgetClass *widget_class,
int count)
{
g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
-
+
gtk_widget_class_add_binding_signal (widget_class,
keyval, modmask,
"move-cursor",
@@ -997,7 +997,7 @@ gtk_text_class_init (GtkTextClass *class)
gtk_editable_install_properties (gobject_class, NUM_PROPERTIES);
/* Action signals */
-
+
/**
* GtkText::activate:
* @self: The widget on which the signal is emitted
@@ -1044,7 +1044,7 @@ gtk_text_class_init (GtkTextClass *class)
* - <kbd>Ctrl</kbd>-<kbd>→</kbd>, etc. move by words/paragraphs
* - <kbd>Home</kbd>, <kbd>End</kbd> move to the ends of the buffer
*/
- signals[MOVE_CURSOR] =
+ signals[MOVE_CURSOR] =
g_signal_new (I_("move-cursor"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
@@ -1068,7 +1068,7 @@ gtk_text_class_init (GtkTextClass *class)
*
* This signal has no default bindings.
*/
- signals[INSERT_AT_CURSOR] =
+ signals[INSERT_AT_CURSOR] =
g_signal_new (I_("insert-at-cursor"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
@@ -1096,7 +1096,7 @@ gtk_text_class_init (GtkTextClass *class)
* for deleting a character and <kbd>Ctrl</kbd>-<kbd>Delete</kbd>
* for deleting a word.
*/
- signals[DELETE_FROM_CURSOR] =
+ signals[DELETE_FROM_CURSOR] =
g_signal_new (I_("delete-from-cursor"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
@@ -1249,7 +1249,7 @@ gtk_text_class_init (GtkTextClass *class)
NULL, NULL,
NULL,
G_TYPE_NONE, 0);
-
+
/*
* Actions
*/
@@ -1281,7 +1281,7 @@ gtk_text_class_init (GtkTextClass *class)
/**
* GtkText|selection.delete:
*
- * Deletes the current selection.
+ * Deletes the current selection.
*/
gtk_widget_class_install_action (widget_class, "selection.delete", NULL,
gtk_text_activate_selection_delete);
@@ -1306,7 +1306,7 @@ gtk_text_class_init (GtkTextClass *class)
* GtkText|misc.toggle-visibility:
*
* Toggles the `GtkText`:visibility property.
- */
+ */
gtk_widget_class_install_property_action (widget_class,
"misc.toggle-visibility",
"visibility");
@@ -1315,7 +1315,7 @@ gtk_text_class_init (GtkTextClass *class)
* GtkText|text.undo:
*
* Undoes the last change to the contents.
- */
+ */
gtk_widget_class_install_action (widget_class, "text.undo", NULL, gtk_text_real_undo);
/**
@@ -1328,8 +1328,8 @@ gtk_text_class_init (GtkTextClass *class)
/**
* GtkText|menu.popup:
*
- * Opens the context menu.
- */
+ * Opens the context menu.
+ */
gtk_widget_class_install_action (widget_class, "menu.popup", NULL, gtk_text_popup_menu);
/*
@@ -1348,16 +1348,16 @@ gtk_text_class_init (GtkTextClass *class)
/* Moving the insertion point */
add_move_binding (widget_class, GDK_KEY_Right, 0,
GTK_MOVEMENT_VISUAL_POSITIONS, 1);
-
+
add_move_binding (widget_class, GDK_KEY_Left, 0,
GTK_MOVEMENT_VISUAL_POSITIONS, -1);
add_move_binding (widget_class, GDK_KEY_KP_Right, 0,
GTK_MOVEMENT_VISUAL_POSITIONS, 1);
-
+
add_move_binding (widget_class, GDK_KEY_KP_Left, 0,
GTK_MOVEMENT_VISUAL_POSITIONS, -1);
-
+
add_move_binding (widget_class, GDK_KEY_Right, GDK_CONTROL_MASK,
GTK_MOVEMENT_WORDS, 1);
@@ -1369,7 +1369,7 @@ gtk_text_class_init (GtkTextClass *class)
add_move_binding (widget_class, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
GTK_MOVEMENT_WORDS, -1);
-
+
add_move_binding (widget_class, GDK_KEY_Home, 0,
GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
@@ -1381,7 +1381,7 @@ gtk_text_class_init (GtkTextClass *class)
add_move_binding (widget_class, GDK_KEY_KP_End, 0,
GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
-
+
add_move_binding (widget_class, GDK_KEY_Home, GDK_CONTROL_MASK,
GTK_MOVEMENT_BUFFER_ENDS, -1);
@@ -1405,7 +1405,7 @@ gtk_text_class_init (GtkTextClass *class)
GDK_KEY_slash, GDK_CONTROL_MASK,
(GtkShortcutFunc) gtk_text_select_all,
NULL);
- /* Unselect all
+ /* Unselect all
*/
gtk_widget_class_add_binding_signal (widget_class,
GDK_KEY_backslash, GDK_CONTROL_MASK,
@@ -1427,7 +1427,7 @@ gtk_text_class_init (GtkTextClass *class)
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Enter, 0,
"activate",
NULL);
-
+
/* Deleting text */
gtk_widget_class_add_binding_signal (widget_class,
GDK_KEY_Delete, 0,
@@ -1438,7 +1438,7 @@ gtk_text_class_init (GtkTextClass *class)
GDK_KEY_KP_Delete, 0,
"delete-from-cursor",
"(ii)", GTK_DELETE_CHARS, 1);
-
+
gtk_widget_class_add_binding_signal (widget_class,
GDK_KEY_BackSpace, 0,
"backspace",
@@ -1464,7 +1464,7 @@ gtk_text_class_init (GtkTextClass *class)
GDK_KEY_KP_Delete, GDK_CONTROL_MASK,
"delete-from-cursor",
"(ii)", GTK_DELETE_WORD_ENDS, 1);
-
+
gtk_widget_class_add_binding_signal (widget_class,
GDK_KEY_BackSpace, GDK_CONTROL_MASK,
"delete-from-cursor",
@@ -2233,7 +2233,7 @@ gtk_text_unrealize (GtkWidget *widget)
GdkClipboard *clipboard;
gtk_text_reset_layout (self);
-
+
gtk_im_context_set_client_widget (priv->im_context, NULL);
clipboard = gtk_widget_get_primary_clipboard (widget);
@@ -2619,14 +2619,14 @@ gtk_text_get_pixel_ranges (GtkText *self,
if (ranges)
{
int *r = *ranges;
-
+
for (i = 0; i < real_n_ranges; ++i)
{
r[2 * i + 1] = (r[2 * i + 1] - r[2 * i]) / PANGO_SCALE;
r[2 * i] = r[2 * i] / PANGO_SCALE;
}
}
-
+
if (n_ranges)
*n_ranges = real_n_ranges;
}
@@ -3533,7 +3533,7 @@ gtk_text_update_cached_style_values (GtkText *self)
}
}
-static void
+static void
gtk_text_css_changed (GtkWidget *widget,
GtkCssStyleChange *change)
{
@@ -3811,7 +3811,7 @@ gtk_text_move_cursor (GtkText *self,
if (count <= 0)
new_pos = current_x < bound_x ? priv->current_pos : priv->selection_bound;
- else
+ else
new_pos = current_x > bound_x ? priv->current_pos : priv->selection_bound;
}
break;
@@ -3921,7 +3921,7 @@ gtk_text_move_cursor (GtkText *self,
gtk_text_set_selection_bounds (self, priv->selection_bound, new_pos);
else
gtk_text_set_selection_bounds (self, new_pos, new_pos);
-
+
gtk_text_pend_cursor_blink (self);
}
@@ -3963,7 +3963,7 @@ gtk_text_delete_from_cursor (GtkText *self,
gtk_text_delete_selection (self);
return;
}
-
+
switch (type)
{
case GTK_DELETE_CHARS:
@@ -4597,7 +4597,7 @@ get_layout_position (GtkText *self,
y_pos = 0;
else if (y_pos + logical_rect.height > area_height)
y_pos = area_height - logical_rect.height;
-
+
y_pos = y_pos / PANGO_SCALE;
if (x)
@@ -4855,7 +4855,7 @@ gtk_text_find_position (GtkText *self,
int trailing;
const char *text;
int cursor_index;
-
+
layout = gtk_text_ensure_layout (self, TRUE);
text = pango_layout_get_text (layout);
cursor_index = g_utf8_offset_to_pointer (text, priv->current_pos) - text;
@@ -4893,7 +4893,7 @@ gtk_text_get_cursor_locations (GtkText *self,
{
if (strong_x)
*strong_x = 0;
-
+
if (weak_x)
*weak_x = 0;
}
@@ -4903,14 +4903,14 @@ gtk_text_get_cursor_locations (GtkText *self,
const char *text = pango_layout_get_text (layout);
PangoRectangle strong_pos, weak_pos;
int index;
-
+
index = g_utf8_offset_to_pointer (text, priv->current_pos + priv->preedit_cursor) - text;
pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
-
+
if (strong_x)
*strong_x = strong_pos.x / PANGO_SCALE;
-
+
if (weak_x)
*weak_x = weak_pos.x / PANGO_SCALE;
}
@@ -5137,7 +5137,7 @@ gtk_text_move_logically (GtkText *self,
do
new_pos++;
while (new_pos < length && !log_attrs[new_pos].is_cursor_position);
-
+
count--;
}
while (count < 0 && new_pos > 0)
@@ -5145,7 +5145,7 @@ gtk_text_move_logically (GtkText *self,
do
new_pos--;
while (new_pos > 0 && !log_attrs[new_pos].is_cursor_position);
-
+
count++;
}
}
@@ -5210,7 +5210,7 @@ gtk_text_move_backward_word (GtkText *self,
new_pos = start - 1;
/* Find the previous word boundary */
- while (new_pos > 0 && !(log_attrs[new_pos].is_word_start ||
+ while (new_pos > 0 && !(log_attrs[new_pos].is_word_start ||
(log_attrs[new_pos].is_word_end && allow_whitespace)))
new_pos--;
}
@@ -5297,7 +5297,7 @@ paste_received (GObject *clipboard,
gtk_text_set_selection_bounds (self, pos, pos);
priv->insert_pos = -1;
}
-
+
if (priv->truncate_multiline)
length = truncate_multiline (text);
@@ -5331,7 +5331,7 @@ gtk_text_update_primary_selection (GtkText *self)
return;
clipboard = gtk_widget_get_primary_clipboard (GTK_WIDGET (self));
-
+
if (priv->selection_bound != priv->current_pos)
{
gdk_clipboard_set_content (clipboard, priv->selection_content);
@@ -5450,6 +5450,8 @@ gtk_text_set_buffer (GtkText *self,
buffer_connect_signals (self);
}
+ update_placeholder_visibility (self);
+
obj = G_OBJECT (self);
g_object_freeze_notify (obj);
g_object_notify_by_pspec (obj, text_props[PROP_BUFFER]);
@@ -5886,7 +5888,7 @@ PangoLayout *
gtk_text_get_layout (GtkText *self)
{
PangoLayout *layout;
-
+
g_return_val_if_fail (GTK_IS_TEXT (self), NULL);
layout = gtk_text_ensure_layout (self, TRUE);
@@ -6341,7 +6343,7 @@ gtk_text_drag_drop (GtkDropTarget *dest,
gtk_editable_insert_text (GTK_EDITABLE (self), str, length, &pos);
end_change (self);
}
-
+
return TRUE;
}
diff --git a/gtk/gtktextbtree.c b/gtk/gtktextbtree.c
index 91ab3351a8..d11d4300c7 100644
--- a/gtk/gtktextbtree.c
+++ b/gtk/gtktextbtree.c
@@ -2362,8 +2362,7 @@ copy_segment (GString *string,
/* printf (" :%s\n", string->str); */
}
- else if (seg->type == &gtk_text_paintable_type ||
- seg->type == &gtk_text_child_type)
+ else if (seg->type == &gtk_text_paintable_type)
{
gboolean copy = TRUE;
@@ -2382,7 +2381,27 @@ copy_segment (GString *string,
g_string_append_len (string,
_gtk_text_unknown_char_utf8,
GTK_TEXT_UNKNOWN_CHAR_UTF8_LEN);
+ }
+ }
+ else if (seg->type == &gtk_text_child_type)
+ {
+ gboolean copy = TRUE;
+ if (!include_nonchars &&
+ g_strcmp0 (_gtk_text_unknown_char_utf8, seg->body.child.obj->chars) == 0)
+ {
+ copy = FALSE;
+ }
+ else if (!include_hidden &&
+ _gtk_text_btree_char_is_invisible (start))
+ {
+ copy = FALSE;
+ }
+ if (copy)
+ {
+ g_string_append_len (string,
+ seg->body.child.obj->chars,
+ seg->byte_count);
}
}
}
@@ -7121,6 +7140,12 @@ _gtk_text_btree_spew_line_short (GtkTextLine *line, int indent)
printf ("%s chars '%s'...\n", spaces, str);
g_free (str);
}
+ else if (seg->type == &gtk_text_child_type)
+ {
+ char *str = g_strndup (seg->body.child.obj->chars, seg->byte_count);
+ printf ("%s child '%s'...\n", spaces, str);
+ g_free (str);
+ }
else if (seg->type == &gtk_text_right_mark_type)
{
printf ("%s right mark '%s' visible: %d\n",
@@ -7223,6 +7248,12 @@ _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment * seg)
printf (" '%s'\n", str);
g_free (str);
}
+ else if (seg->type == &gtk_text_child_type)
+ {
+ char *str = g_strndup (seg->body.child.obj->chars, seg->byte_count);
+ printf (" '%s'\n", str);
+ g_free (str);
+ }
else if (seg->type == &gtk_text_right_mark_type)
{
printf (" right mark '%s' visible: %d not_deleteable: %d\n",
diff --git a/gtk/gtktextchild.c b/gtk/gtktextchild.c
index f1716efb75..2976550301 100644
--- a/gtk/gtktextchild.c
+++ b/gtk/gtktextchild.c
@@ -267,9 +267,6 @@ child_segment_check_func (GtkTextLineSegment *seg,
if (seg->next == NULL)
g_error ("child segment is the last segment in a line");
- if (seg->byte_count != GTK_TEXT_UNKNOWN_CHAR_UTF8_LEN)
- g_error ("child segment has byte count of %d", seg->byte_count);
-
if (seg->char_count != 1)
g_error ("child segment has char count of %d", seg->char_count);
}
@@ -301,11 +298,8 @@ _gtk_widget_segment_new (GtkTextChildAnchor *anchor)
seg->next = NULL;
- /* We convert to the 0xFFFC "unknown character",
- * a 3-byte sequence in UTF-8.
- */
- seg->byte_count = GTK_TEXT_UNKNOWN_CHAR_UTF8_LEN;
- seg->char_count = 1;
+ seg->byte_count = strlen (anchor->chars);
+ seg->char_count = g_utf8_strlen (anchor->chars, seg->byte_count);
seg->body.child.obj = anchor;
seg->body.child.obj->segment = seg;
@@ -410,7 +404,28 @@ gtk_text_child_anchor_class_init (GtkTextChildAnchorClass *klass)
GtkTextChildAnchor*
gtk_text_child_anchor_new (void)
{
- return g_object_new (GTK_TYPE_TEXT_CHILD_ANCHOR, NULL);
+ return gtk_text_child_anchor_new_with_replacement (_gtk_text_unknown_char_utf8);
+}
+
+/**
+ * gtk_text_child_anchor_new_with_replacement:
+ *
+ * Creates a new `GtkTextChildAnchor` with the given replacement character.
+ *
+ * Usually you would then insert it into a `GtkTextBuffer` with
+ * [method@Gtk.TextBuffer.insert_child_anchor].
+ *
+ * Returns: a new `GtkTextChildAnchor`
+ **/
+GtkTextChildAnchor *
+gtk_text_child_anchor_new_with_replacement (const char *replacement_character)
+{
+ /* only a single character can be set as replacement */
+ g_return_val_if_fail (g_utf8_strlen (replacement_character, -1) == 1, NULL);
+
+ GtkTextChildAnchor *anchor = g_object_new (GTK_TYPE_TEXT_CHILD_ANCHOR, NULL);
+ anchor->chars = g_strdup (replacement_character);
+ return anchor;
}
static void
diff --git a/gtk/gtktextchild.h b/gtk/gtktextchild.h
index 65432262a1..31e8324c59 100644
--- a/gtk/gtktextchild.h
+++ b/gtk/gtktextchild.h
@@ -60,6 +60,7 @@ struct _GtkTextChildAnchor
/*< private >*/
gpointer segment;
+ char *chars; /* replacement character */
};
struct _GtkTextChildAnchorClass
@@ -74,16 +75,19 @@ struct _GtkTextChildAnchorClass
};
GDK_AVAILABLE_IN_ALL
-GType gtk_text_child_anchor_get_type (void) G_GNUC_CONST;
+GType gtk_text_child_anchor_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
-GtkTextChildAnchor* gtk_text_child_anchor_new (void);
+GtkTextChildAnchor *gtk_text_child_anchor_new (void);
+
+GDK_AVAILABLE_IN_4_6
+GtkTextChildAnchor *gtk_text_child_anchor_new_with_replacement (const char *character);
GDK_AVAILABLE_IN_ALL
-GtkWidget ** gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor,
- guint *out_len);
+GtkWidget **gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor,
+ guint *out_len);
GDK_AVAILABLE_IN_ALL
-gboolean gtk_text_child_anchor_get_deleted (GtkTextChildAnchor *anchor);
+gboolean gtk_text_child_anchor_get_deleted (GtkTextChildAnchor *anchor);
G_END_DECLS
diff --git a/gtk/gtktextiter.c b/gtk/gtktextiter.c
index 7157233641..a9e79ea51f 100644
--- a/gtk/gtktextiter.c
+++ b/gtk/gtktextiter.c
@@ -892,6 +892,10 @@ gtk_text_iter_get_char (const GtkTextIter *iter)
return g_utf8_get_char (real->segment->body.chars +
real->segment_byte_offset);
}
+ else if (real->segment->type == &gtk_text_child_type)
+ {
+ return g_utf8_get_char (real->segment->body.child.obj->chars);
+ }
else
{
/* Unicode "unknown character" 0xFFFC */
diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c
index 1873b03d74..b57cd65e50 100644
--- a/gtk/gtktextlayout.c
+++ b/gtk/gtktextlayout.c
@@ -2470,7 +2470,7 @@ gtk_text_layout_create_display (GtkTextLayout *layout,
size_only, FALSE);
add_child_attrs (layout, display, style,
seg, attrs, layout_byte_offset);
- memcpy (text + layout_byte_offset, _gtk_text_unknown_char_utf8,
+ memcpy (text + layout_byte_offset, seg->body.child.obj->chars,
seg->byte_count);
layout_byte_offset += seg->byte_count;
buffer_byte_offset += seg->byte_count;
diff --git a/meson.build b/meson.build
index c388521a0c..630ac99854 100644
--- a/meson.build
+++ b/meson.build
@@ -11,7 +11,7 @@ project('gtk', 'c',
license: 'LGPL-2.1-or-later')
glib_req = '>= 2.66.0'
-pango_req = '>= 1.49.3' # keep this in sync with .gitlab-ci/test-msys.sh
+pango_req = '>= 1.50.0' # keep this in sync with .gitlab-ci/test-msys.sh
fribidi_req = '>= 0.19.7'
cairo_req = '>= 1.14.0'
gdk_pixbuf_req = '>= 2.30.0'
@@ -292,7 +292,7 @@ elif cc.get_id() == 'gcc' or cc.get_id() == 'clang'
'-Wuninitialized',
'-Wunused',
]
-
+
extra_warnings = [
'address',
'array-bounds',
diff --git a/testsuite/gtk/textbuffer.c b/testsuite/gtk/textbuffer.c
index 3ac7643a6a..2dcb0b5fd7 100644
--- a/testsuite/gtk/textbuffer.c
+++ b/testsuite/gtk/textbuffer.c
@@ -1581,6 +1581,75 @@ test_get_iter (void)
g_object_unref (buffer);
}
+static void
+test_iter_with_anchor (void)
+{
+ GtkTextView *text_view;
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+ GtkTextChildAnchor *anchor;
+ GtkWidget *child;
+
+ text_view = GTK_TEXT_VIEW (gtk_text_view_new ());
+ buffer = gtk_text_view_get_buffer (text_view);
+
+ gtk_text_buffer_set_text (buffer, "ab\ncd\r\nef", -1);
+ g_assert_true (gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 1));
+ anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
+ child = gtk_label_new ("text");
+ gtk_text_view_add_child_at_anchor (text_view, child, anchor);
+ g_object_unref (child);
+
+ gtk_text_buffer_get_iter_at_child_anchor (buffer, &iter, anchor);
+ g_assert_cmpint (gtk_text_iter_get_char (&iter), ==, GTK_TEXT_UNKNOWN_CHAR);
+
+ g_assert_true (gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 1));
+ /* ß takes 2 bytes in UTF-8 */
+ anchor = gtk_text_child_anchor_new_with_replacement ("ß");
+ gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
+ child = gtk_label_new ("text");
+ gtk_text_view_add_child_at_anchor (text_view, child, anchor);
+
+ gtk_text_buffer_get_iter_at_child_anchor (buffer, &iter, anchor);
+ g_assert_cmpint (gtk_text_iter_get_char (&iter), ==, 223);
+
+ g_object_unref (child);
+ g_object_ref_sink (text_view);
+}
+
+static void
+test_get_text_with_anchor (void)
+{
+ GtkTextView *text_view;
+ GtkTextBuffer *buffer;
+ GtkTextIter iter, start, end;
+ GtkTextChildAnchor *anchor;
+ GtkWidget *child;
+
+ text_view = GTK_TEXT_VIEW (gtk_text_view_new ());
+ buffer = gtk_text_view_get_buffer (text_view);
+
+ gtk_text_buffer_set_text (buffer, "ab\ncd\r\nef", -1);
+ g_assert_true (gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 1));
+ anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
+ child = gtk_label_new ("text");
+ gtk_text_view_add_child_at_anchor (text_view, child, anchor);
+ g_object_unref (child);
+
+ g_assert_true (gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 1));
+ /* ß takes 2 bytes in UTF-8 */
+ anchor = gtk_text_child_anchor_new_with_replacement ("ß");
+ gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
+ child = gtk_label_new ("text");
+ gtk_text_view_add_child_at_anchor (text_view, child, anchor);
+
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+ g_assert_cmpstr (gtk_text_buffer_get_text (buffer, &start, &end, FALSE), ==, "ab\ncßd\r\nef");
+
+ g_object_unref (child);
+ g_object_ref_sink (text_view);
+}
+
/* Check that basic undo works */
static void
test_undo0 (void)
@@ -1768,6 +1837,8 @@ main (int argc, char** argv)
g_test_add_func ("/TextBuffer/Tag", test_tag);
g_test_add_func ("/TextBuffer/Clipboard", test_clipboard);
g_test_add_func ("/TextBuffer/Get iter", test_get_iter);
+ g_test_add_func ("/TextBuffer/Iter with anchor", test_iter_with_anchor);
+ g_test_add_func ("/TextBuffer/Get text with anchor", test_get_text_with_anchor);
g_test_add_func ("/TextBuffer/Undo 0", test_undo0);
g_test_add_func ("/TextBuffer/Undo 1", test_undo1);
g_test_add_func ("/TextBuffer/Undo 2", test_undo2);