diff options
-rw-r--r-- | .gitlab-ci/test-msys2.sh | 2 | ||||
-rw-r--r-- | demos/gtk-demo/hypertext.c | 10 | ||||
-rw-r--r-- | demos/gtk-demo/tabs.c | 16 | ||||
-rw-r--r-- | gdk/wayland/gdkdevice-wayland.c | 7 | ||||
-rw-r--r-- | gdk/win32/gdksurface-win32.c | 2 | ||||
-rw-r--r-- | gsk/gl/gskglcompiler.c | 29 | ||||
-rw-r--r-- | gtk/gtkgesturestylus.c | 18 | ||||
-rw-r--r-- | gtk/gtktext.c | 96 | ||||
-rw-r--r-- | gtk/gtktextbtree.c | 35 | ||||
-rw-r--r-- | gtk/gtktextchild.c | 33 | ||||
-rw-r--r-- | gtk/gtktextchild.h | 14 | ||||
-rw-r--r-- | gtk/gtktextiter.c | 4 | ||||
-rw-r--r-- | gtk/gtktextlayout.c | 2 | ||||
-rw-r--r-- | meson.build | 4 | ||||
-rw-r--r-- | testsuite/gtk/textbuffer.c | 71 |
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 == >k_text_paintable_type || - seg->type == >k_text_child_type) + else if (seg->type == >k_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 == >k_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 == >k_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 == >k_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 == >k_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 == >k_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 == >k_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); |