diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index cfd069216b..87948ae035 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -3085,8 +3085,10 @@ GtkTextChildAnchor gtk_text_child_anchor_new gtk_text_child_anchor_get_widgets gtk_text_child_anchor_get_deleted -gtk_text_view_add_child_in_window -gtk_text_view_move_child +gtk_text_view_get_gutter +gtk_text_view_set_gutter +gtk_text_view_add_overlay +gtk_text_view_move_overlay gtk_text_view_set_wrap_mode gtk_text_view_get_wrap_mode gtk_text_view_set_editable diff --git a/gtk/gtktextutil.c b/gtk/gtktextutil.c index 200f87285c..fa10328d46 100644 --- a/gtk/gtktextutil.c +++ b/gtk/gtktextutil.c @@ -158,6 +158,19 @@ set_attributes_from_style (GtkStyleContext *context, gtk_style_context_get (context, "font", &values->font, NULL); } +static gint +get_border_window_size (GtkTextView *text_view, + GtkTextWindowType window_type) +{ + GtkWidget *gutter; + + gutter = gtk_text_view_get_gutter (text_view, window_type); + if (gutter != NULL) + return gtk_widget_get_width (gutter); + + return 0; +} + GdkPaintable * gtk_text_util_create_rich_drag_icon (GtkWidget *widget, GtkTextBuffer *buffer, @@ -208,8 +221,8 @@ gtk_text_util_create_rich_drag_icon (GtkWidget *widget, if (GTK_IS_TEXT_VIEW (widget)) { layout_width = layout_width - - gtk_text_view_get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_LEFT) - - gtk_text_view_get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_RIGHT); + - get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_LEFT) + - get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_RIGHT); } style->direction = gtk_widget_get_direction (widget); diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 38e7e10356..c82fcf792e 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -47,6 +47,7 @@ #include "gtkwindow.h" #include "gtkscrollable.h" #include "gtktypebuiltins.h" +#include "gtktextviewchildprivate.h" #include "gtktexthandleprivate.h" #include "gtkcssstylepropertyprivate.h" #include "gtkpopover.h" @@ -170,10 +171,14 @@ struct _GtkTextViewPrivate GtkBorder border_window_size; GtkTextWindow *text_window; - GtkTextWindow *left_window; - GtkTextWindow *right_window; - GtkTextWindow *top_window; - GtkTextWindow *bottom_window; + + GQueue anchored_children; + + GtkTextViewChild *left_child; + GtkTextViewChild *right_child; + GtkTextViewChild *top_child; + GtkTextViewChild *bottom_child; + GtkTextViewChild *center_child; GtkAdjustment *hadjustment; GtkAdjustment *vadjustment; @@ -222,8 +227,6 @@ struct _GtkTextViewPrivate GtkWidget *popup_menu; GMenuModel *extra_menu; - GSList *children; - GtkTextPendingScroll *pending_scroll; GtkGesture *drag_gesture; @@ -562,6 +565,7 @@ static void gtk_text_view_remove (GtkContainer *container, static void gtk_text_view_forall (GtkContainer *container, GtkCallback callback, gpointer callback_data); +static void update_node_ordering (GtkWidget *widget); /* GtkTextHandle handlers */ static void gtk_text_view_handle_drag_started (GtkTextHandle *handle, @@ -618,31 +622,19 @@ static void gtk_text_view_activate_misc_insert_emoji (GtkWidget *widget, /* FIXME probably need the focus methods. */ -typedef struct _GtkTextViewChild GtkTextViewChild; - -struct _GtkTextViewChild +typedef struct { - GtkWidget *widget; - + GList link; + GtkWidget *widget; GtkTextChildAnchor *anchor; + int from_top_of_line; + int from_left_of_buffer; +} AnchoredChild; - gint from_top_of_line; - gint from_left_of_buffer; - - /* These are ignored if anchor != NULL */ - GtkTextWindowType type; - gint x; - gint y; -}; - -static GtkTextViewChild* text_view_child_new_anchored (GtkWidget *child, - GtkTextChildAnchor *anchor, - GtkTextLayout *layout); -static GtkTextViewChild* text_view_child_new_window (GtkWidget *child, - GtkTextWindowType type, - gint x, - gint y); -static void text_view_child_free (GtkTextViewChild *child); +static AnchoredChild *anchored_child_new (GtkWidget *child, + GtkTextChildAnchor *anchor, + GtkTextLayout *layout); +static void anchored_child_free (AnchoredChild *child); struct _GtkTextWindow { @@ -652,15 +644,10 @@ struct _GtkTextWindow GdkRectangle allocation; }; -static GtkTextWindow *text_window_new (GtkTextWindowType type, - GtkWidget *widget); +static GtkTextWindow *text_window_new (GtkWidget *widget); static void text_window_free (GtkTextWindow *win); static void text_window_size_allocate (GtkTextWindow *win, GdkRectangle *rect); -static void text_window_invalidate (GtkTextWindow *win); - -static gint text_window_get_x (GtkTextWindow *win); -static gint text_window_get_y (GtkTextWindow *win); static gint text_window_get_width (GtkTextWindow *win); static gint text_window_get_height (GtkTextWindow *win); @@ -669,7 +656,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE_WITH_CODE (GtkTextView, gtk_text_view, GTK_TYPE_CONTAINER, G_ADD_PRIVATE (GtkTextView) - G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)) + G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)) static void add_move_binding (GtkBindingSet *binding_set, @@ -1676,7 +1663,7 @@ gtk_text_view_init (GtkTextView *text_view) priv->accepts_tab = TRUE; - priv->text_window = text_window_new (GTK_TEXT_WINDOW_TEXT, widget); + priv->text_window = text_window_new (widget); gesture = gtk_gesture_click_new (); gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 0); @@ -1840,29 +1827,16 @@ gtk_text_view_set_buffer (GtkTextView *text_view, return; old_buffer = priv->buffer; - if (priv->buffer != NULL) + + if (old_buffer != NULL) { - /* Destroy all anchored children */ - GSList *tmp_list; - GSList *copy; - - copy = g_slist_copy (priv->children); - tmp_list = copy; - while (tmp_list != NULL) + while (priv->anchored_children.length) { - GtkTextViewChild *vc = tmp_list->data; - - if (vc->anchor) - { - gtk_widget_destroy (vc->widget); - /* vc may now be invalid! */ - } - - tmp_list = tmp_list->next; + AnchoredChild *ac = g_queue_peek_head (&priv->anchored_children); + gtk_widget_destroy (ac->widget); + /* ac is now invalid! */ } - g_slist_free (copy); - g_signal_handlers_disconnect_by_func (priv->buffer, gtk_text_view_mark_set_handler, text_view); @@ -3607,6 +3581,14 @@ gtk_text_view_finalize (GObject *object) /* at this point, no "notify::buffer" handler should recreate the buffer. */ g_assert (priv->buffer == NULL); + + /* Ensure all children were removed */ + g_assert (priv->anchored_children.length == 0); + g_assert (priv->left_child == NULL); + g_assert (priv->right_child == NULL); + g_assert (priv->top_child == NULL); + g_assert (priv->bottom_child == NULL); + g_assert (priv->center_child == NULL); cancel_pending_scroll (text_view); @@ -3620,18 +3602,6 @@ gtk_text_view_finalize (GObject *object) text_window_free (priv->text_window); - if (priv->left_window) - text_window_free (priv->left_window); - - if (priv->top_window) - text_window_free (priv->top_window); - - if (priv->right_window) - text_window_free (priv->right_window); - - if (priv->bottom_window) - text_window_free (priv->bottom_window); - g_clear_pointer (&priv->selection_bubble, gtk_widget_unparent); if (priv->magnifier_popover) @@ -3901,6 +3871,42 @@ gtk_text_view_get_property (GObject *object, } } +static void +gtk_text_view_measure_borders (GtkTextView *text_view, + GtkBorder *border) +{ + GtkTextViewPrivate *priv = text_view->priv; + int left = 0; + int right = 0; + int top = 0; + int bottom = 0; + + if (priv->left_child) + gtk_widget_measure (GTK_WIDGET (priv->left_child), + GTK_ORIENTATION_HORIZONTAL, -1, + &left, NULL, NULL, NULL); + + if (priv->right_child) + gtk_widget_measure (GTK_WIDGET (priv->right_child), + GTK_ORIENTATION_HORIZONTAL, -1, + &right, NULL, NULL, NULL); + + if (priv->top_child) + gtk_widget_measure (GTK_WIDGET (priv->top_child), + GTK_ORIENTATION_VERTICAL, -1, + &top, NULL, NULL, NULL); + + if (priv->bottom_child) + gtk_widget_measure (GTK_WIDGET (priv->bottom_child), + GTK_ORIENTATION_VERTICAL, -1, + &bottom, NULL, NULL, NULL); + + border->left = left; + border->right = right; + border->top = top; + border->bottom = bottom; +} + static void gtk_text_view_measure (GtkWidget *widget, GtkOrientation orientation, @@ -3910,50 +3916,52 @@ gtk_text_view_measure (GtkWidget *widget, int *minimum_baseline, int *natural_baseline) { - GtkTextViewPrivate *priv = GTK_TEXT_VIEW (widget)->priv; - int min = 0, nat = 0; - GSList *tmp_list; + GtkTextView *text_view = GTK_TEXT_VIEW (widget); + GtkTextViewPrivate *priv = text_view->priv; + const GList *list; + GtkBorder borders; + int min = 0; + int nat = 0; + int extra; - if (orientation == GTK_ORIENTATION_HORIZONTAL) + gtk_text_view_measure_borders (text_view, &borders); + + if (priv->center_child) + gtk_widget_measure (GTK_WIDGET (priv->center_child), + orientation, for_size, + &min, &nat, NULL, NULL); + + for (list = priv->anchored_children.head; list; list = list->next) { - min += priv->border_window_size.left + priv->border_window_size.right; - min += priv->left_margin + priv->right_margin; - } - else /* orientation == VERTICAL */ - { - min += priv->border_window_size.top + priv->border_window_size.bottom; - min += priv->height; - } + const AnchoredChild *child = list->data; + int child_min = 0; + int child_nat = 0; - nat = min; - - tmp_list = priv->children; - while (tmp_list != NULL) - { - GtkTextViewChild *child = tmp_list->data; - int child_min = 0, child_nat = 0; - - gtk_widget_measure (child->widget, orientation, for_size, &child_min, &child_nat, NULL, NULL); + gtk_widget_measure (child->widget, orientation, for_size, + &child_min, &child_nat, + NULL, NULL); /* Invalidate layout lines if required */ if (child->anchor && priv->layout) - gtk_text_child_anchor_queue_resize (child->anchor, - priv->layout); + gtk_text_child_anchor_queue_resize (child->anchor, priv->layout); min = MAX (min, child_min); nat = MAX (nat, child_nat); - - tmp_list = tmp_list->next; } - *minimum = min; - *natural = nat; + if (orientation == GTK_ORIENTATION_HORIZONTAL) + extra = borders.left + priv->left_margin + priv->right_margin + borders.right; + else + extra = borders.top + priv->height + borders.bottom; + + *minimum = min + extra; + *natural = nat + extra; } static void -gtk_text_view_compute_child_allocation (GtkTextView *text_view, - GtkTextViewChild *vc, - GtkAllocation *allocation) +gtk_text_view_compute_child_allocation (GtkTextView *text_view, + const AnchoredChild *vc, + GtkAllocation *allocation) { gint buffer_y; GtkTextIter iter; @@ -3977,8 +3985,8 @@ gtk_text_view_compute_child_allocation (GtkTextView *text_view, } static void -gtk_text_view_update_child_allocation (GtkTextView *text_view, - GtkTextViewChild *vc) +gtk_text_view_update_child_allocation (GtkTextView *text_view, + const AnchoredChild *vc) { GtkAllocation allocation; @@ -3996,13 +4004,13 @@ gtk_text_view_update_child_allocation (GtkTextView *text_view, } static void -gtk_text_view_child_allocated (GtkTextLayout *layout, - GtkWidget *child, - gint x, - gint y, - gpointer data) +gtk_anchored_child_allocated (GtkTextLayout *layout, + GtkWidget *child, + gint x, + gint y, + gpointer data) { - GtkTextViewChild *vc = NULL; + AnchoredChild *vc = NULL; GtkTextView *text_view = data; /* x,y is the position of the child from the top of the line, and @@ -4025,73 +4033,144 @@ gtk_text_view_child_allocated (GtkTextLayout *layout, static void gtk_text_view_allocate_children (GtkTextView *text_view) { - GSList *tmp_list; + GtkTextViewPrivate *priv = text_view->priv; + const GList *iter; DV(g_print(G_STRLOC"\n")); - - tmp_list = text_view->priv->children; - while (tmp_list != NULL) + + for (iter = priv->anchored_children.head; iter; iter = iter->next) { - GtkTextViewChild *child = tmp_list->data; + const AnchoredChild *child = iter->data; + GtkTextIter child_loc; - g_assert (child != NULL); - - if (child->anchor) + /* We need to force-validate the regions containing children. */ + gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view), + &child_loc, + child->anchor); + + /* Since anchored children are only ever allocated from + * gtk_text_layout_get_line_display() we have to make sure + * that the display line caching in the layout doesn't + * get in the way. Invalidating the layout around the anchor + * achieves this. + */ + if (_gtk_widget_get_alloc_needed (child->widget)) { - /* We need to force-validate the regions containing - * children. - */ - GtkTextIter child_loc; - gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view), - &child_loc, - child->anchor); - - /* Since anchored children are only ever allocated from - * gtk_text_layout_get_line_display() we have to make sure - * that the display line caching in the layout doesn't - * get in the way. Invalidating the layout around the anchor - * achieves this. - */ - if (_gtk_widget_get_alloc_needed (child->widget)) - { - GtkTextIter end = child_loc; - gtk_text_iter_forward_char (&end); - gtk_text_layout_invalidate (text_view->priv->layout, &child_loc, &end); - } - - gtk_text_layout_validate_yrange (text_view->priv->layout, - &child_loc, - 0, 1); - } - else - { - GtkAllocation allocation; - GtkRequisition child_req; - - allocation.x = child->x; - allocation.y = child->y; - - if (child->type == GTK_TEXT_WINDOW_TEXT || - child->type == GTK_TEXT_WINDOW_LEFT || - child->type == GTK_TEXT_WINDOW_RIGHT) - allocation.y -= text_view->priv->yoffset; - if (child->type == GTK_TEXT_WINDOW_TEXT || - child->type == GTK_TEXT_WINDOW_TOP || - child->type == GTK_TEXT_WINDOW_BOTTOM) - allocation.x -= text_view->priv->xoffset; - - gtk_widget_get_preferred_size (child->widget, &child_req, NULL); - - allocation.width = child_req.width; - allocation.height = child_req.height; - - gtk_widget_size_allocate (child->widget, &allocation, -1); + GtkTextIter end = child_loc; + gtk_text_iter_forward_char (&end); + gtk_text_layout_invalidate (priv->layout, &child_loc, &end); } - tmp_list = tmp_list->next; + gtk_text_layout_validate_yrange (priv->layout, &child_loc, 0, 1); } } +static GtkTextViewChild ** +find_child_for_window_type (GtkTextView *text_view, + GtkTextWindowType window_type) +{ + switch (window_type) + { + case GTK_TEXT_WINDOW_LEFT: + return &text_view->priv->left_child; + case GTK_TEXT_WINDOW_RIGHT: + return &text_view->priv->right_child; + case GTK_TEXT_WINDOW_TOP: + return &text_view->priv->top_child; + case GTK_TEXT_WINDOW_BOTTOM: + return &text_view->priv->bottom_child; + case GTK_TEXT_WINDOW_TEXT: + return &text_view->priv->center_child; + case GTK_TEXT_WINDOW_WIDGET: + default: + return NULL; + } +} + +/** + * gtk_text_view_get_gutter: + * @text_view: a #GtkTextView + * @win: a #GtkWindowType + * + * Gets a #GtkWidget that has previously been set with + * gtk_text_view_set_gutter(). + * + * @win must be one of %GTK_TEXT_WINDOW_LEFT, %GTK_TEXT_WINDOW_RIGHT, + * %GTK_TEXT_WINDOW_TOP, or %GTK_TEXT_WINDOW_BOTTOM. + * + * Returns: (transfer none) (nullable): a #GtkWidget or %NULL + */ +GtkWidget * +gtk_text_view_get_gutter (GtkTextView *text_view, + GtkTextWindowType win) +{ + GtkTextViewChild **childp; + + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL); + g_return_val_if_fail (win == GTK_TEXT_WINDOW_LEFT || + win == GTK_TEXT_WINDOW_RIGHT || + win == GTK_TEXT_WINDOW_TOP || + win == GTK_TEXT_WINDOW_BOTTOM, NULL); + + childp = find_child_for_window_type (text_view, win); + + if (*childp != NULL) + return GTK_WIDGET (*childp); + + return NULL; +} + +/** + * gtk_text_view_set_gutter: + * @text_view: a #GtkTextView + * @win: a #GtkTextWindowType + * @widget: (nullable): a #GtkWidget or %NULL + * + * Places @widget into the gutter specified by @win. + * + * @win must be one of %GTK_TEXT_WINDOW_LEFT, %GTK_TEXT_WINDOW_RIGHT, + * %GTK_TEXT_WINDOW_TOP, or %GTK_TEXT_WINDOW_BOTTOM. + */ +void +gtk_text_view_set_gutter (GtkTextView *text_view, + GtkTextWindowType win, + GtkWidget *widget) +{ + GtkTextViewChild **childp; + GtkTextViewChild *old_child; + GtkTextViewChild *new_child; + + g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); + g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget)); + g_return_if_fail (win == GTK_TEXT_WINDOW_LEFT || + win == GTK_TEXT_WINDOW_RIGHT || + win == GTK_TEXT_WINDOW_TOP || + win == GTK_TEXT_WINDOW_BOTTOM); + + childp = find_child_for_window_type (text_view, win); + old_child = *childp; + + if ((GtkWidget *)old_child == widget) + return; + + if (old_child != NULL) + { + *childp = NULL; + gtk_widget_unparent (GTK_WIDGET (old_child)); + g_object_unref (old_child); + } + + if (widget == NULL) + return; + + new_child = GTK_TEXT_VIEW_CHILD (gtk_text_view_child_new (win)); + gtk_container_add (GTK_CONTAINER (new_child), widget); + + *childp = g_object_ref (new_child); + gtk_widget_set_parent (GTK_WIDGET (new_child), GTK_WIDGET (text_view)); + update_node_ordering (GTK_WIDGET (text_view)); +} + static void gtk_text_view_size_allocate (GtkWidget *widget, int widget_width, @@ -4115,6 +4194,8 @@ gtk_text_view_size_allocate (GtkWidget *widget, DV(g_print(G_STRLOC"\n")); + gtk_text_view_measure_borders (text_view, &priv->border_window_size); + /* distribute width/height among child windows. Ensure all * windows get at least a 1x1 allocation. */ @@ -4148,24 +4229,37 @@ gtk_text_view_size_allocate (GtkWidget *widget, right_rect.x = text_rect.x + text_rect.width; bottom_rect.y = text_rect.y + text_rect.height; - text_window_size_allocate (priv->text_window, - &text_rect); + text_window_size_allocate (priv->text_window, &text_rect); - if (priv->left_window) - text_window_size_allocate (priv->left_window, - &left_rect); + if (priv->center_child) + { + gtk_text_view_child_set_offset (priv->center_child, priv->xoffset, priv->yoffset); + gtk_widget_size_allocate (GTK_WIDGET (priv->center_child), &text_rect, -1); + } - if (priv->right_window) - text_window_size_allocate (priv->right_window, - &right_rect); + if (priv->left_child) + { + gtk_text_view_child_set_offset (priv->left_child, priv->xoffset, priv->yoffset); + gtk_widget_size_allocate (GTK_WIDGET (priv->left_child), &left_rect, -1); + } - if (priv->top_window) - text_window_size_allocate (priv->top_window, - &top_rect); + if (priv->right_child) + { + gtk_text_view_child_set_offset (priv->right_child, priv->xoffset, priv->yoffset); + gtk_widget_size_allocate (GTK_WIDGET (priv->right_child), &right_rect, -1); + } - if (priv->bottom_window) - text_window_size_allocate (priv->bottom_window, - &bottom_rect); + if (priv->top_child) + { + gtk_text_view_child_set_offset (priv->top_child, priv->xoffset, priv->yoffset); + gtk_widget_size_allocate (GTK_WIDGET (priv->top_child), &top_rect, -1); + } + + if (priv->bottom_child) + { + gtk_text_view_child_set_offset (priv->bottom_child, priv->xoffset, priv->yoffset); + gtk_widget_size_allocate (GTK_WIDGET (priv->bottom_child), &bottom_rect, -1); + } gtk_text_view_update_layout_width (text_view); @@ -4398,33 +4492,24 @@ changed_handler (GtkTextLayout *layout, DV(g_print(">Lines Validated ("G_STRLOC")\n")); if (gtk_widget_get_realized (widget)) - { - text_window_invalidate (priv->text_window); + { + gtk_widget_queue_draw (widget); DV(g_print(" invalidated rect: %d,%d %d x %d\n", redraw_rect.x, redraw_rect.y, redraw_rect.width, redraw_rect.height)); - - if (priv->left_window) - text_window_invalidate (priv->left_window); - if (priv->right_window) - text_window_invalidate (priv->right_window); - if (priv->top_window) - text_window_invalidate (priv->top_window); - if (priv->bottom_window) - text_window_invalidate (priv->bottom_window); queue_update_im_spot_location (text_view); } if (old_height != new_height) { - GSList *tmp_list; + const GList *iter; + GtkTextIter first; int new_first_para_top; int old_first_para_top; - GtkTextIter first; /* If the bottom of the old area was above the top of the * screen, we need to scroll to keep the current top of the @@ -4451,17 +4536,13 @@ changed_handler (GtkTextLayout *layout, /* FIXME be smarter about which anchored widgets we update */ - tmp_list = priv->children; - while (tmp_list != NULL) + for (iter = priv->anchored_children.head; iter; iter = iter->next) { - GtkTextViewChild *child = tmp_list->data; - - if (child->anchor) - gtk_text_view_update_child_allocation (text_view, child); - - tmp_list = tmp_list->next; + const AnchoredChild *ac = iter->data; + gtk_text_view_update_child_allocation (text_view, ac); } - gtk_widget_queue_resize(widget); + + gtk_widget_queue_resize (widget); } } @@ -4527,45 +4608,6 @@ gtk_text_view_map (GtkWidget *widget) GTK_WIDGET_CLASS (gtk_text_view_parent_class)->map (widget); } -static void -text_window_set_padding (GtkTextView *text_view, - GtkStyleContext *context) -{ - GtkTextViewPrivate *priv; - GtkBorder padding, border; - - priv = text_view->priv; - - gtk_style_context_get_padding (context, &padding); - gtk_style_context_get_border (context, &border); - padding.left += border.left; - padding.right += border.right; - padding.top += border.top; - padding.bottom += border.bottom; - - if (padding.left != priv->left_padding || - padding.right != priv->right_padding || - padding.top != priv->top_padding || - padding.bottom != priv->bottom_padding) - { - priv->xoffset += priv->left_padding; - priv->yoffset += priv->top_padding; - - priv->top_margin = priv->top_margin; - priv->bottom_margin = priv->bottom_margin; - priv->left_margin = priv->left_margin; - priv->right_margin = priv->right_margin; - - if (priv->layout && priv->layout->default_style) - { - priv->layout->right_padding = priv->right_padding; - priv->layout->left_padding = priv->left_padding; - - gtk_text_layout_default_style_changed (priv->layout); - } - } -} - static void gtk_text_view_style_updated (GtkWidget *widget) { @@ -4639,14 +4681,6 @@ gtk_text_view_state_flags_changed (GtkWidget *widget, state &= ~GTK_STATE_FLAG_DROP_ACTIVE; gtk_css_node_set_state (priv->selection_node, state); - if (priv->left_window) - gtk_css_node_set_state (priv->left_window->css_node, state); - if (priv->right_window) - gtk_css_node_set_state (priv->right_window->css_node, state); - if (priv->top_window) - gtk_css_node_set_state (priv->top_window->css_node, state); - if (priv->bottom_window) - gtk_css_node_set_state (priv->bottom_window->css_node, state); gtk_widget_queue_draw (widget); } @@ -5388,17 +5422,15 @@ draw_text (GtkWidget *widget, GtkTextView *text_view = GTK_TEXT_VIEW (widget); GtkTextViewPrivate *priv = text_view->priv; GtkStyleContext *context; - graphene_point_t translate = {0}; + gboolean did_save = FALSE; - if (priv->left_window) - translate.x = priv->left_window->allocation.width; - if (priv->top_window) - translate.y = priv->top_window->allocation.height; - - if (translate.x || translate.y) + if (priv->border_window_size.left || priv->border_window_size.top) { + did_save = TRUE; gtk_snapshot_save (snapshot); - gtk_snapshot_translate (snapshot, &translate); + gtk_snapshot_translate (snapshot, + &GRAPHENE_POINT_INIT (priv->border_window_size.left, + priv->border_window_size.top)); } gtk_snapshot_push_clip (snapshot, @@ -5439,64 +5471,44 @@ draw_text (GtkWidget *widget, gtk_snapshot_pop (snapshot); - if (translate.x || translate.y) + if (did_save) gtk_snapshot_restore (snapshot); } -static void -paint_border_window (GtkTextView *text_view, - GtkSnapshot *snapshot, - GtkTextWindow *text_window, - GtkStyleContext *context) +static inline void +snapshot_text_view_child (GtkWidget *widget, + GtkTextViewChild *child, + GtkSnapshot *snapshot) { - gint x, y, w, h; - - if (text_window == NULL) - return; - - x = text_window_get_x (text_window); - y = text_window_get_y (text_window); - w = text_window_get_width (text_window); - h = text_window_get_height (text_window); - - gtk_style_context_save_to_node (context, text_window->css_node); - - gtk_snapshot_render_background (snapshot, context, x, y, w, h); - - gtk_style_context_restore (context); + if (child != NULL) + gtk_widget_snapshot_child (widget, GTK_WIDGET (child), snapshot); } static void gtk_text_view_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { - GtkTextViewPrivate *priv = ((GtkTextView *)widget)->priv; - GSList *tmp_list; - GtkStyleContext *context; - - context = gtk_widget_get_style_context (widget); - - text_window_set_padding (GTK_TEXT_VIEW (widget), context); + GtkTextView *text_view = GTK_TEXT_VIEW (widget); + GtkTextViewPrivate *priv = text_view->priv; + const GList *iter; DV(g_print (">Exposed ("G_STRLOC")\n")); draw_text (widget, snapshot); - paint_border_window (GTK_TEXT_VIEW (widget), snapshot, priv->left_window, context); - paint_border_window (GTK_TEXT_VIEW (widget), snapshot, priv->right_window, context); - paint_border_window (GTK_TEXT_VIEW (widget), snapshot, priv->top_window, context); - paint_border_window (GTK_TEXT_VIEW (widget), snapshot, priv->bottom_window, context); + snapshot_text_view_child (widget, priv->left_child, snapshot); + snapshot_text_view_child (widget, priv->right_child, snapshot); + snapshot_text_view_child (widget, priv->top_child, snapshot); + snapshot_text_view_child (widget, priv->bottom_child, snapshot); + snapshot_text_view_child (widget, priv->center_child, snapshot); /* Propagate exposes to all unanchored children. * Anchored children are handled in gtk_text_view_paint(). */ - tmp_list = GTK_TEXT_VIEW (widget)->priv->children; - while (tmp_list != NULL) + for (iter = priv->anchored_children.head; iter; iter = iter->next) { - GtkTextViewChild *vc = tmp_list->data; - + const AnchoredChild *vc = iter->data; gtk_widget_snapshot_child (widget, vc->widget, snapshot); - tmp_list = tmp_list->next; } } @@ -5541,45 +5553,61 @@ static void gtk_text_view_add (GtkContainer *container, GtkWidget *child) { - /* This is pretty random. */ - gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (container), - child, - GTK_TEXT_WINDOW_WIDGET, - 0, 0); + /* There isn't really a good default for what to do when + * using gtk_container_add() for @child. So we default to + * placing it at 0,0 in the text window. + */ + gtk_text_view_add_overlay (GTK_TEXT_VIEW (container), child, 0, 0); } static void gtk_text_view_remove (GtkContainer *container, GtkWidget *child) { - GtkTextView *text_view; - GtkTextViewPrivate *priv; - GtkTextViewChild *vc; - GSList *iter; + GtkTextView *text_view = GTK_TEXT_VIEW (container); + GtkTextViewPrivate *priv = text_view->priv; + AnchoredChild *ac; - text_view = GTK_TEXT_VIEW (container); - priv = text_view->priv; - - vc = NULL; - iter = priv->children; - - while (iter != NULL) + if (GTK_IS_TEXT_VIEW_CHILD (child)) { - vc = iter->data; + GtkTextViewChild *vc = GTK_TEXT_VIEW_CHILD (child); + GtkTextViewChild **vcp; - if (vc->widget == child) - break; + if (vc == priv->left_child) + vcp = &priv->left_child; + else if (vc == priv->left_child) + vcp = &priv->left_child; + else if (vc == priv->top_child) + vcp = &priv->top_child; + else if (vc == priv->bottom_child) + vcp = &priv->bottom_child; + else if (vc == priv->center_child) + vcp = &priv->center_child; + else + vcp = NULL; - iter = iter->next; + if (vcp) + { + *vcp = NULL; + gtk_widget_unparent (child); + g_object_unref (child); + return; + } } - g_assert (iter != NULL); /* be sure we had the child in the list */ + ac = g_object_get_qdata (G_OBJECT (child), quark_text_view_child); - priv->children = g_slist_remove (priv->children, vc); + if (ac == NULL) + { + g_warning ("%s is not a child of %s", + G_OBJECT_TYPE_NAME (child), + G_OBJECT_TYPE_NAME (text_view)); + return; + } - gtk_widget_unparent (vc->widget); - - text_view_child_free (vc); + g_queue_unlink (&priv->anchored_children, &ac->link); + gtk_widget_unparent (ac->widget); + anchored_child_free (ac); } static void @@ -5587,28 +5615,34 @@ gtk_text_view_forall (GtkContainer *container, GtkCallback callback, gpointer callback_data) { - GSList *iter; + const GList *iter; GtkTextView *text_view; - GSList *copy; + GtkTextViewPrivate *priv; g_return_if_fail (GTK_IS_TEXT_VIEW (container)); g_return_if_fail (callback != NULL); text_view = GTK_TEXT_VIEW (container); + priv = text_view->priv; - copy = g_slist_copy (text_view->priv->children); - iter = copy; + if (priv->left_child) + callback (GTK_WIDGET (priv->left_child), callback_data); + if (priv->right_child) + callback (GTK_WIDGET (priv->right_child), callback_data); + if (priv->top_child) + callback (GTK_WIDGET (priv->top_child), callback_data); + if (priv->bottom_child) + callback (GTK_WIDGET (priv->bottom_child), callback_data); + if (priv->center_child) + callback (GTK_WIDGET (priv->center_child), callback_data); + iter = priv->anchored_children.head; while (iter != NULL) { - GtkTextViewChild *vc = iter->data; - - (* callback) (vc->widget, callback_data); - + const AnchoredChild *ac = iter->data; iter = iter->next; + callback (ac->widget, callback_data); } - - g_slist_free (copy); } #define CURSOR_ON_MULTIPLIER 2 @@ -6708,8 +6742,7 @@ gtk_text_view_toggle_overwrite (GtkTextView *text_view) gtk_text_layout_set_overwrite_mode (priv->layout, priv->overwrite_mode && priv->editable); - if (priv->text_window) - text_window_invalidate (priv->text_window); + gtk_widget_queue_draw (GTK_WIDGET (text_view)); gtk_text_view_pend_cursor_blink (text_view); @@ -7442,7 +7475,7 @@ gtk_text_view_ensure_layout (GtkTextView *text_view) { GtkTextAttributes *style; PangoContext *ltr_context, *rtl_context; - GSList *tmp_list; + const GList *iter; DV(g_print(G_STRLOC"\n")); @@ -7460,7 +7493,7 @@ gtk_text_view_ensure_layout (GtkTextView *text_view) g_signal_connect (priv->layout, "allocate-child", - G_CALLBACK (gtk_text_view_child_allocated), + G_CALLBACK (gtk_anchored_child_allocated), text_view); if (get_buffer (text_view)) @@ -7512,19 +7545,13 @@ gtk_text_view_ensure_layout (GtkTextView *text_view) /* Set layout for all anchored children */ - tmp_list = priv->children; - while (tmp_list != NULL) + iter = priv->anchored_children.head; + while (iter != NULL) { - GtkTextViewChild *vc = tmp_list->data; - - if (vc->anchor) - { - gtk_text_anchored_child_set_layout (vc->widget, - priv->layout); - /* vc may now be invalid! */ - } - - tmp_list = tmp_list->next; + const AnchoredChild *ac = iter->data; + iter = iter->next; + gtk_text_anchored_child_set_layout (ac->widget, priv->layout); + /* ac may now be invalid! */ } } } @@ -7546,7 +7573,7 @@ gtk_text_view_destroy_layout (GtkTextView *text_view) if (priv->layout) { - GSList *tmp_list; + const GList *iter; gtk_text_view_remove_validate_idles (text_view); @@ -7557,19 +7584,13 @@ gtk_text_view_destroy_layout (GtkTextView *text_view) changed_handler, text_view); - /* Remove layout from all anchored children */ - tmp_list = priv->children; - while (tmp_list != NULL) + iter = priv->anchored_children.head; + while (iter != NULL) { - GtkTextViewChild *vc = tmp_list->data; - - if (vc->anchor) - { - gtk_text_anchored_child_set_layout (vc->widget, NULL); - /* vc may now be invalid! */ - } - - tmp_list = tmp_list->next; + const AnchoredChild *ac = iter->data; + iter = iter->next; + gtk_text_anchored_child_set_layout (ac->widget, NULL); + /* vc may now be invalid! */ } gtk_text_view_stop_cursor_blink (text_view); @@ -8162,7 +8183,7 @@ gtk_text_view_set_vadjustment_values (GtkTextView *text_view) new_value = CLAMP (y, 0, new_upper - screen_height); if (new_value != old_value) gtk_adjustment_set_value (priv->vadjustment, new_value); - } +} static void gtk_text_view_value_changed (GtkAdjustment *adjustment, @@ -8264,7 +8285,7 @@ gtk_text_view_value_changed (GtkAdjustment *adjustment, gtk_text_view_update_handles (text_view, _gtk_text_handle_get_mode (priv->text_handle)); - if (priv->children) + if (priv->anchored_children.length > 0) gtk_widget_queue_allocate (GTK_WIDGET (text_view)); else gtk_widget_queue_draw (GTK_WIDGET (text_view)); @@ -9037,7 +9058,7 @@ static void update_node_ordering (GtkWidget *widget) { GtkTextViewPrivate *priv = GTK_TEXT_VIEW (widget)->priv; - GtkCssNode *widget_node, *sibling; + GtkCssNode *widget_node, *sibling, *child_node; if (priv->text_window == NULL) return; @@ -9045,38 +9066,44 @@ update_node_ordering (GtkWidget *widget) widget_node = gtk_widget_get_css_node (widget); sibling = priv->text_window->css_node; - if (priv->left_window) + if (priv->left_child) { - gtk_css_node_insert_before (widget_node, priv->left_window->css_node, sibling); - sibling = priv->left_window->css_node; + child_node = gtk_widget_get_css_node (GTK_WIDGET (priv->left_child)); + gtk_css_node_insert_before (widget_node, child_node, sibling); + sibling = child_node; } - if (priv->top_window) + + if (priv->top_child) { - gtk_css_node_insert_before (widget_node, priv->top_window->css_node, sibling); + child_node = gtk_widget_get_css_node (GTK_WIDGET (priv->top_child)); + gtk_css_node_insert_before (widget_node, child_node, sibling); } sibling = priv->text_window->css_node; - if (priv->right_window) + + if (priv->right_child) { - gtk_css_node_insert_after (widget_node, priv->right_window->css_node, sibling); - sibling = priv->right_window->css_node; + child_node = gtk_widget_get_css_node (GTK_WIDGET (priv->right_child)); + gtk_css_node_insert_after (widget_node, child_node, sibling); + sibling = child_node; } - if (priv->bottom_window) + + if (priv->bottom_child) { - gtk_css_node_insert_after (widget_node, priv->bottom_window->css_node, sibling); + child_node = gtk_widget_get_css_node (GTK_WIDGET (priv->bottom_child)); + gtk_css_node_insert_after (widget_node, child_node, sibling); } } static GtkTextWindow* -text_window_new (GtkTextWindowType type, - GtkWidget *widget) +text_window_new (GtkWidget *widget) { GtkTextWindow *win; GtkCssNode *widget_node; win = g_slice_new (GtkTextWindow); - win->type = type; + win->type = GTK_TEXT_WINDOW_TEXT; win->widget = widget; win->allocation.width = 0; win->allocation.height = 0; @@ -9088,35 +9115,8 @@ text_window_new (GtkTextWindowType type, gtk_css_node_set_parent (win->css_node, widget_node); gtk_css_node_set_state (win->css_node, gtk_css_node_get_state (widget_node)); g_signal_connect_object (win->css_node, "style-changed", G_CALLBACK (node_style_changed_cb), widget, 0); - if (type == GTK_TEXT_WINDOW_TEXT) - { - gtk_css_node_set_name (win->css_node, I_("text")); - } - else - { - gtk_css_node_set_name (win->css_node, I_("border")); - switch (type) - { - case GTK_TEXT_WINDOW_LEFT: - gtk_css_node_add_class (win->css_node, g_quark_from_static_string (GTK_STYLE_CLASS_LEFT)); - break; - case GTK_TEXT_WINDOW_RIGHT: - gtk_css_node_add_class (win->css_node, g_quark_from_static_string (GTK_STYLE_CLASS_RIGHT)); - break; - case GTK_TEXT_WINDOW_TOP: - gtk_css_node_add_class (win->css_node, g_quark_from_static_string (GTK_STYLE_CLASS_TOP)); - break; - case GTK_TEXT_WINDOW_BOTTOM: - gtk_css_node_add_class (win->css_node, g_quark_from_static_string (GTK_STYLE_CLASS_BOTTOM)); - break; - case GTK_TEXT_WINDOW_PRIVATE: - case GTK_TEXT_WINDOW_WIDGET: - case GTK_TEXT_WINDOW_TEXT: - default: - /* no extra style class */ - break; - } - } + gtk_css_node_set_name (win->css_node, I_("text")); + g_object_unref (win->css_node); return win; @@ -9137,24 +9137,6 @@ text_window_size_allocate (GtkTextWindow *win, win->allocation = *rect; } -static void -text_window_invalidate (GtkTextWindow *win) -{ - gtk_widget_queue_draw (win->widget); -} - -static gint -text_window_get_x (GtkTextWindow *win) -{ - return win->allocation.x; -} - -static gint -text_window_get_y (GtkTextWindow *win) -{ - return win->allocation.y; -} - static gint text_window_get_width (GtkTextWindow *win) { @@ -9169,53 +9151,10 @@ text_window_get_height (GtkTextWindow *win) /* Windows */ - -static GtkCssNode * -gtk_text_view_get_css_node (GtkTextView *text_view, - GtkTextWindowType win) -{ - GtkTextViewPrivate *priv = text_view->priv; - - switch (win) - { - case GTK_TEXT_WINDOW_WIDGET: - return gtk_widget_get_css_node (GTK_WIDGET (text_view)); - - case GTK_TEXT_WINDOW_TEXT: - return priv->text_window->css_node; - - case GTK_TEXT_WINDOW_LEFT: - if (priv->left_window) - return priv->left_window->css_node; - break; - - case GTK_TEXT_WINDOW_RIGHT: - if (priv->right_window) - return priv->right_window->css_node; - break; - - case GTK_TEXT_WINDOW_TOP: - if (priv->top_window) - return priv->top_window->css_node; - break; - - case GTK_TEXT_WINDOW_BOTTOM: - if (priv->bottom_window) - return priv->bottom_window->css_node; - break; - - case GTK_TEXT_WINDOW_PRIVATE: - default: - break; - } - - return NULL; -} - /** * gtk_text_view_buffer_to_window_coords: * @text_view: a #GtkTextView - * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE + * @win: a #GtkTextWindowType * @buffer_x: buffer x coordinate * @buffer_y: buffer y coordinate * @window_x: (out) (allow-none): window x coordinate return location or %NULL @@ -9268,10 +9207,6 @@ gtk_text_view_buffer_to_window_coords (GtkTextView *text_view, buffer_y -= text_window_get_height (priv->text_window); break; - case GTK_TEXT_WINDOW_PRIVATE: - g_warning ("%s: can't get coords for private windows", G_STRFUNC); - break; - default: g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC); break; @@ -9286,7 +9221,7 @@ gtk_text_view_buffer_to_window_coords (GtkTextView *text_view, /** * gtk_text_view_window_to_buffer_coords: * @text_view: a #GtkTextView - * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE + * @win: a #GtkTextWindowType * @window_x: window x coordinate * @window_y: window y coordinate * @buffer_x: (out) (allow-none): buffer x coordinate return location or %NULL @@ -9336,10 +9271,6 @@ gtk_text_view_window_to_buffer_coords (GtkTextView *text_view, window_y += text_window_get_height (priv->text_window); break; - case GTK_TEXT_WINDOW_PRIVATE: - g_warning ("%s: can't get coords for private windows", G_STRFUNC); - break; - default: g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC); break; @@ -9351,156 +9282,23 @@ gtk_text_view_window_to_buffer_coords (GtkTextView *text_view, *buffer_y = window_y + priv->yoffset; } -static void -set_window_size (GtkTextView *text_view, - gint size, - GtkTextWindowType type, - GtkTextWindow **winp, - gint16 *sizep) -{ - if (*sizep == size) - return; - - if (size == 0) - { - text_window_free (*winp); - *winp = NULL; - } - else - { - if (*winp == NULL) - { - *winp = text_window_new (type, GTK_WIDGET (text_view)); - /* if the widget is already realized we need to realize the child manually */ - update_node_ordering (GTK_WIDGET (text_view)); - } - } - - *sizep = size; - - gtk_widget_queue_resize (GTK_WIDGET (text_view)); -} - -/** - * gtk_text_view_set_border_window_size: - * @text_view: a #GtkTextView - * @type: window to affect - * @size: width or height of the window - * - * Sets the width of %GTK_TEXT_WINDOW_LEFT or %GTK_TEXT_WINDOW_RIGHT, - * or the height of %GTK_TEXT_WINDOW_TOP or %GTK_TEXT_WINDOW_BOTTOM. - * Automatically destroys the corresponding window if the size is set - * to 0, and creates the window if the size is set to non-zero. This - * function can only be used for the “border windows,” it doesn’t work - * with #GTK_TEXT_WINDOW_WIDGET, #GTK_TEXT_WINDOW_TEXT, or - * #GTK_TEXT_WINDOW_PRIVATE. - **/ -void -gtk_text_view_set_border_window_size (GtkTextView *text_view, - GtkTextWindowType type, - gint size) -{ - GtkTextViewPrivate *priv = text_view->priv; - - g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); - g_return_if_fail (size >= 0); - - switch (type) - { - case GTK_TEXT_WINDOW_LEFT: - set_window_size (text_view, size, GTK_TEXT_WINDOW_LEFT, - &priv->left_window, &priv->border_window_size.left); - break; - - case GTK_TEXT_WINDOW_RIGHT: - set_window_size (text_view, size, GTK_TEXT_WINDOW_RIGHT, - &priv->right_window, &priv->border_window_size.right); - break; - - case GTK_TEXT_WINDOW_TOP: - set_window_size (text_view, size, GTK_TEXT_WINDOW_TOP, - &priv->top_window, &priv->border_window_size.top); - break; - - case GTK_TEXT_WINDOW_BOTTOM: - set_window_size (text_view, size, GTK_TEXT_WINDOW_BOTTOM, - &priv->bottom_window, &priv->border_window_size.bottom); - break; - - case GTK_TEXT_WINDOW_PRIVATE: - case GTK_TEXT_WINDOW_WIDGET: - case GTK_TEXT_WINDOW_TEXT: - default: - g_warning ("Can only set size of left/right/top/bottom border windows with gtk_text_view_set_border_window_size()"); - break; - } -} - -/** - * gtk_text_view_get_border_window_size: - * @text_view: a #GtkTextView - * @type: window to return size from - * - * Gets the width of the specified border window. See - * gtk_text_view_set_border_window_size(). - * - * Returns: width of window - **/ -gint -gtk_text_view_get_border_window_size (GtkTextView *text_view, - GtkTextWindowType type) -{ - GtkTextViewPrivate *priv = text_view->priv; - - g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0); - - switch (type) - { - case GTK_TEXT_WINDOW_LEFT: - return priv->border_window_size.left; - - case GTK_TEXT_WINDOW_RIGHT: - return priv->border_window_size.right; - - case GTK_TEXT_WINDOW_TOP: - return priv->border_window_size.top; - - case GTK_TEXT_WINDOW_BOTTOM: - return priv->border_window_size.bottom; - - case GTK_TEXT_WINDOW_PRIVATE: - case GTK_TEXT_WINDOW_WIDGET: - case GTK_TEXT_WINDOW_TEXT: - default: - g_warning ("Can only get size of left/right/top/bottom border windows with gtk_text_view_get_border_window_size()"); - break; - } - - return 0; -} - /* * Child widgets */ -static GtkTextViewChild* -text_view_child_new_anchored (GtkWidget *child, - GtkTextChildAnchor *anchor, - GtkTextLayout *layout) +static AnchoredChild * +anchored_child_new (GtkWidget *child, + GtkTextChildAnchor *anchor, + GtkTextLayout *layout) { - GtkTextViewChild *vc; - - vc = g_slice_new (GtkTextViewChild); - - vc->type = GTK_TEXT_WINDOW_PRIVATE; - vc->widget = child; - vc->anchor = anchor; + AnchoredChild *vc; + vc = g_slice_new (AnchoredChild); + vc->link.data = vc; + vc->widget = g_object_ref (child); + vc->anchor = g_object_ref (anchor); vc->from_top_of_line = 0; vc->from_left_of_buffer = 0; - - g_object_ref (vc->widget); - g_object_ref (vc->anchor); g_object_set_qdata (G_OBJECT (child), quark_text_view_child, vc); @@ -9509,64 +9307,31 @@ text_view_child_new_anchored (GtkWidget *child, return vc; } -static GtkTextViewChild* -text_view_child_new_window (GtkWidget *child, - GtkTextWindowType type, - gint x, - gint y) -{ - GtkTextViewChild *vc; - - vc = g_slice_new (GtkTextViewChild); - - vc->widget = child; - vc->anchor = NULL; - - vc->from_top_of_line = 0; - vc->from_left_of_buffer = 0; - - g_object_ref (vc->widget); - - vc->type = type; - vc->x = x; - vc->y = y; - - g_object_set_qdata (G_OBJECT (child), quark_text_view_child, vc); - - return vc; -} - static void -text_view_child_free (GtkTextViewChild *child) +anchored_child_free (AnchoredChild *child) { + g_assert (child->link.prev == NULL); + g_assert (child->link.next == NULL); + g_object_set_qdata (G_OBJECT (child->widget), quark_text_view_child, NULL); - if (child->anchor) - { - gtk_text_child_anchor_unregister_child (child->anchor, - child->widget); - g_object_unref (child->anchor); - } + gtk_text_child_anchor_unregister_child (child->anchor, child->widget); + g_object_unref (child->anchor); g_object_unref (child->widget); - g_slice_free (GtkTextViewChild, child); + g_slice_free (AnchoredChild, child); } static void -add_child (GtkTextView *text_view, - GtkTextViewChild *vc) +add_child (GtkTextView *text_view, + AnchoredChild *vc) { - GtkCssNode *parent; - - text_view->priv->children = g_slist_prepend (text_view->priv->children, vc); - - parent = gtk_text_view_get_css_node (text_view, vc->type); - if (parent == NULL) - parent = gtk_widget_get_css_node (GTK_WIDGET (text_view)); - - gtk_css_node_set_parent (gtk_widget_get_css_node (vc->widget), parent); + GtkTextViewPrivate *priv = text_view->priv; + g_queue_push_head_link (&priv->anchored_children, &vc->link); + gtk_css_node_set_parent (gtk_widget_get_css_node (vc->widget), + priv->text_window->css_node); gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view)); } @@ -9583,7 +9348,7 @@ gtk_text_view_add_child_at_anchor (GtkTextView *text_view, GtkWidget *child, GtkTextChildAnchor *anchor) { - GtkTextViewChild *vc; + AnchoredChild *vc; g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); g_return_if_fail (GTK_IS_WIDGET (child)); @@ -9592,8 +9357,7 @@ gtk_text_view_add_child_at_anchor (GtkTextView *text_view, gtk_text_view_ensure_layout (text_view); - vc = text_view_child_new_anchored (child, anchor, - text_view->priv->layout); + vc = anchored_child_new (child, anchor, text_view->priv->layout); add_child (text_view, vc); @@ -9601,82 +9365,81 @@ gtk_text_view_add_child_at_anchor (GtkTextView *text_view, g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view)); } +static void +ensure_child (GtkTextView *text_view, + GtkTextViewChild **child, + GtkTextWindowType window_type) +{ + GtkCssNode *css_node; + GtkWidget *new_child; + + if (*child != NULL) + return; + + new_child = gtk_text_view_child_new (window_type); + css_node = gtk_widget_get_css_node (new_child); + gtk_css_node_set_parent (css_node, + gtk_widget_get_css_node (GTK_WIDGET (text_view))); + *child = g_object_ref (GTK_TEXT_VIEW_CHILD (new_child)); + gtk_widget_set_parent (GTK_WIDGET (new_child), GTK_WIDGET (text_view)); +} + /** - * gtk_text_view_add_child_in_window: + * gtk_text_view_add_overlay: * @text_view: a #GtkTextView * @child: a #GtkWidget - * @which_window: which window the child should appear in * @xpos: X position of child in window coordinates * @ypos: Y position of child in window coordinates * - * Adds a child at fixed coordinates in one of the text widget's - * windows. + * Adds @child at a fixed coordinate in the #GtkTextView's text window. The + * @xpos and @ypos must be in buffer coordinates (see + * gtk_text_view_get_iter_location() to conver to buffer coordinates). * - * The window must have nonzero size (see - * gtk_text_view_set_border_window_size()). Note that the child - * coordinates are given relative to scrolling. When - * placing a child in #GTK_TEXT_WINDOW_WIDGET, scrolling is - * irrelevant, the child floats above all scrollable areas. But when - * placing a child in one of the scrollable windows (border windows or - * text window) it will move with the scrolling as needed. + * @child will scroll with the text view. + * + * If instead you want a widget that will not move with the #GtkTextView + * contents see #GtkOverlay. */ void -gtk_text_view_add_child_in_window (GtkTextView *text_view, - GtkWidget *child, - GtkTextWindowType which_window, - gint xpos, - gint ypos) +gtk_text_view_add_overlay (GtkTextView *text_view, + GtkWidget *child, + gint xpos, + gint ypos) { - GtkTextViewChild *vc; - g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); g_return_if_fail (GTK_IS_WIDGET (child)); g_return_if_fail (gtk_widget_get_parent (child) == NULL); - vc = text_view_child_new_window (child, which_window, - xpos, ypos); + ensure_child (text_view, + &text_view->priv->center_child, + GTK_TEXT_WINDOW_TEXT); - add_child (text_view, vc); - - g_assert (vc->widget == child); - g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view)); + gtk_text_view_child_add_overlay (text_view->priv->center_child, + child, xpos, ypos); } /** - * gtk_text_view_move_child: + * gtk_text_view_move_overlay: * @text_view: a #GtkTextView - * @child: child widget already added to the text view - * @xpos: new X position in window coordinates - * @ypos: new Y position in window coordinates + * @child: a widget already added with gtk_text_view_add_overlay() + * @xpos: new X position in buffer coordinates + * @ypos: new Y position in buffer coordinates * - * Updates the position of a child, as for gtk_text_view_add_child_in_window(). + * Updates the position of a child, as for gtk_text_view_add_overlay(). **/ void -gtk_text_view_move_child (GtkTextView *text_view, - GtkWidget *child, - gint xpos, - gint ypos) +gtk_text_view_move_overlay (GtkTextView *text_view, + GtkWidget *child, + gint xpos, + gint ypos) { - GtkTextViewChild *vc; - g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); g_return_if_fail (GTK_IS_WIDGET (child)); g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (text_view)); - vc = g_object_get_qdata (G_OBJECT (child), quark_text_view_child); - - g_assert (vc != NULL); - - if (vc->x == xpos && - vc->y == ypos) - return; - - vc->x = xpos; - vc->y = ypos; - - if (gtk_widget_get_visible (child) && - gtk_widget_get_visible (GTK_WIDGET (text_view))) - gtk_widget_queue_resize (child); + if (text_view->priv->center_child == NULL) + gtk_text_view_child_move_overlay (text_view->priv->center_child, + child, xpos, ypos); } diff --git a/gtk/gtktextview.h b/gtk/gtktextview.h index 489b5ebf1f..d386aebf70 100644 --- a/gtk/gtktextview.h +++ b/gtk/gtktextview.h @@ -44,7 +44,6 @@ G_BEGIN_DECLS /** * GtkTextWindowType: - * @GTK_TEXT_WINDOW_PRIVATE: Private value, used internally * @GTK_TEXT_WINDOW_WIDGET: Window that floats over scrolling areas. * @GTK_TEXT_WINDOW_TEXT: Scrollable text window. * @GTK_TEXT_WINDOW_LEFT: Left side border window. @@ -56,8 +55,7 @@ G_BEGIN_DECLS */ typedef enum { - GTK_TEXT_WINDOW_PRIVATE, - GTK_TEXT_WINDOW_WIDGET, + GTK_TEXT_WINDOW_WIDGET = 1, GTK_TEXT_WINDOW_TEXT, GTK_TEXT_WINDOW_LEFT, GTK_TEXT_WINDOW_RIGHT, @@ -280,14 +278,6 @@ void gtk_text_view_window_to_buffer_coords (GtkTextView *text_view, gint *buffer_x, gint *buffer_y); -GDK_AVAILABLE_IN_ALL -void gtk_text_view_set_border_window_size (GtkTextView *text_view, - GtkTextWindowType type, - gint size); -GDK_AVAILABLE_IN_ALL -gint gtk_text_view_get_border_window_size (GtkTextView *text_view, - GtkTextWindowType type); - GDK_AVAILABLE_IN_ALL gboolean gtk_text_view_forward_display_line (GtkTextView *text_view, GtkTextIter *iter); @@ -316,24 +306,28 @@ void gtk_text_view_reset_im_context (GtkTextView /* Adding child widgets */ GDK_AVAILABLE_IN_ALL -void gtk_text_view_add_child_at_anchor (GtkTextView *text_view, - GtkWidget *child, - GtkTextChildAnchor *anchor); +GtkWidget *gtk_text_view_get_gutter (GtkTextView *text_view, + GtkTextWindowType win); +GDK_AVAILABLE_IN_ALL +void gtk_text_view_set_gutter (GtkTextView *text_view, + GtkTextWindowType win, + GtkWidget *widget); +GDK_AVAILABLE_IN_ALL +void gtk_text_view_add_child_at_anchor (GtkTextView *text_view, + GtkWidget *child, + GtkTextChildAnchor *anchor); GDK_AVAILABLE_IN_ALL -void gtk_text_view_add_child_in_window (GtkTextView *text_view, - GtkWidget *child, - GtkTextWindowType which_window, - /* window coordinates */ - gint xpos, - gint ypos); +void gtk_text_view_add_overlay (GtkTextView *text_view, + GtkWidget *child, + gint xpos, + gint ypos); GDK_AVAILABLE_IN_ALL -void gtk_text_view_move_child (GtkTextView *text_view, - GtkWidget *child, - /* window coordinates */ - gint xpos, - gint ypos); +void gtk_text_view_move_overlay (GtkTextView *text_view, + GtkWidget *child, + gint xpos, + gint ypos); /* Default style settings (fallbacks if no tag affects the property) */ diff --git a/gtk/gtktextviewchild.c b/gtk/gtktextviewchild.c new file mode 100644 index 0000000000..062424d341 --- /dev/null +++ b/gtk/gtktextviewchild.c @@ -0,0 +1,516 @@ +/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */ +/* GTK - The GIMP Toolkit + * gtk_text_view_child.c Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gtkcssnodeprivate.h" +#include "gtkintl.h" +#include "gtkprivate.h" +#include "gtkstylecontext.h" +#include "gtktextview.h" +#include "gtktextviewchildprivate.h" +#include "gtktypebuiltins.h" +#include "gtkwidgetprivate.h" + +typedef struct +{ + GList link; + GtkWidget *widget; + int x; + int y; +} Overlay; + +struct _GtkTextViewChild +{ + GtkContainer parent_instance; + GtkTextWindowType window_type; + GQueue overlays; + int xoffset; + int yoffset; + GtkWidget *child; +}; + +enum { + PROP_0, + PROP_WINDOW_TYPE, + N_PROPS +}; + +G_DEFINE_TYPE (GtkTextViewChild, gtk_text_view_child, GTK_TYPE_CONTAINER) + +static GParamSpec *properties[N_PROPS]; + +static Overlay * +overlay_new (GtkWidget *widget, + int x, + int y) +{ + Overlay *overlay; + + overlay = g_slice_new0 (Overlay); + overlay->link.data = overlay; + overlay->widget = g_object_ref (widget); + overlay->x = x; + overlay->y = y; + + return overlay; +} + +static void +overlay_free (Overlay *overlay) +{ + g_assert (overlay->link.prev == NULL); + g_assert (overlay->link.next == NULL); + + g_object_unref (overlay->widget); + g_slice_free (Overlay, overlay); +} + +static void +gtk_text_view_child_remove_overlay (GtkTextViewChild *self, + Overlay *overlay) +{ + g_queue_unlink (&self->overlays, &overlay->link); + gtk_widget_unparent (overlay->widget); + overlay_free (overlay); +} + +static Overlay * +gtk_text_view_child_get_overlay (GtkTextViewChild *self, + GtkWidget *widget) +{ + GList *iter; + + for (iter = self->overlays.head; iter; iter = iter->next) + { + Overlay *overlay = iter->data; + + if (overlay->widget == widget) + return overlay; + } + + return NULL; +} + +static void +gtk_text_view_child_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (container); + + if (self->child != NULL) + { + g_warning ("%s allows a single child and already contains a %s", + G_OBJECT_TYPE_NAME (self), + G_OBJECT_TYPE_NAME (widget)); + return; + } + + self->child = g_object_ref (widget); + gtk_widget_set_parent (widget, GTK_WIDGET (self)); +} + +static void +gtk_text_view_child_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (container); + + if (widget == self->child) + { + self->child = NULL; + gtk_widget_unparent (widget); + g_object_unref (widget); + } + else + { + Overlay *overlay = gtk_text_view_child_get_overlay (self, widget); + + if (overlay != NULL) + gtk_text_view_child_remove_overlay (self, overlay); + } +} + +static void +gtk_text_view_child_forall (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (container); + const GList *iter; + + if (self->child != NULL) + callback (self->child, callback_data); + + iter = self->overlays.head; + while (iter != NULL) + { + Overlay *overlay = iter->data; + iter = iter->next; + callback (overlay->widget, callback_data); + } +} + +static void +gtk_text_view_child_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *min_size, + int *nat_size, + int *min_baseline, + int *nat_baseline) +{ + GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (widget); + const GList *iter; + int real_min_size = 0; + int real_nat_size = 0; + + if (self->child != NULL) + gtk_widget_measure (self->child, + orientation, + for_size, + &real_min_size, + &real_nat_size, + NULL, + NULL); + + for (iter = self->overlays.head; iter; iter = iter->next) + { + Overlay *overlay = iter->data; + int child_min_size = 0; + int child_nat_size = 0; + + gtk_widget_measure (overlay->widget, + orientation, + for_size, + &child_min_size, + &child_nat_size, + NULL, + NULL); + + if (child_min_size > real_min_size) + real_min_size = child_min_size; + + if (child_nat_size > real_nat_size) + real_nat_size = child_nat_size; + } + + if (min_size) + *min_size = real_min_size; + + if (nat_size) + *nat_size = real_nat_size; + + if (min_baseline) + *min_baseline = -1; + + if (nat_baseline) + *nat_baseline = -1; +} + +static void +gtk_text_view_child_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (widget); + GtkRequisition min_req; + GdkRectangle rect; + const GList *iter; + + GTK_WIDGET_CLASS (gtk_text_view_child_parent_class)->size_allocate (widget, width, height, baseline); + + if (self->child != NULL) + { + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + + gtk_widget_size_allocate (self->child, &rect, baseline); + } + + for (iter = self->overlays.head; iter; iter = iter->next) + { + Overlay *overlay = iter->data; + + gtk_widget_get_preferred_size (overlay->widget, &min_req, NULL); + + rect.width = min_req.width; + rect.height = min_req.height; + + if (self->window_type == GTK_TEXT_WINDOW_TEXT || + self->window_type == GTK_TEXT_WINDOW_TOP || + self->window_type == GTK_TEXT_WINDOW_BOTTOM) + rect.x = overlay->x - self->xoffset; + else + rect.x = overlay->x; + + if (self->window_type == GTK_TEXT_WINDOW_TEXT || + self->window_type == GTK_TEXT_WINDOW_RIGHT || + self->window_type == GTK_TEXT_WINDOW_LEFT) + rect.y = overlay->y - self->yoffset; + else + rect.y = overlay->y; + + gtk_widget_size_allocate (overlay->widget, &rect, -1); + } +} + +static void +gtk_text_view_child_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot) +{ + GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (widget); + const GList *iter; + + GTK_WIDGET_CLASS (gtk_text_view_child_parent_class)->snapshot (widget, snapshot); + + if (self->child) + gtk_widget_snapshot_child (widget, self->child, snapshot); + + for (iter = self->overlays.head; iter; iter = iter->next) + { + Overlay *overlay = iter->data; + + gtk_widget_snapshot_child (widget, overlay->widget, snapshot); + } +} + +static void +gtk_text_view_child_constructed (GObject *object) +{ + GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (object); + GtkCssNode *css_node; + + G_OBJECT_CLASS (gtk_text_view_child_parent_class)->constructed (object); + + css_node = gtk_widget_get_css_node (GTK_WIDGET (self)); + + switch (self->window_type) + { + case GTK_TEXT_WINDOW_LEFT: + gtk_css_node_set_name (css_node, "border"); + gtk_css_node_add_class (css_node, g_quark_from_static_string (GTK_STYLE_CLASS_LEFT)); + break; + + case GTK_TEXT_WINDOW_RIGHT: + gtk_css_node_set_name (css_node, "border"); + gtk_css_node_add_class (css_node, g_quark_from_static_string (GTK_STYLE_CLASS_RIGHT)); + break; + + case GTK_TEXT_WINDOW_TOP: + gtk_css_node_set_name (css_node, "border"); + gtk_css_node_add_class (css_node, g_quark_from_static_string (GTK_STYLE_CLASS_TOP)); + break; + + case GTK_TEXT_WINDOW_BOTTOM: + gtk_css_node_set_name (css_node, "border"); + gtk_css_node_add_class (css_node, g_quark_from_static_string (GTK_STYLE_CLASS_BOTTOM)); + break; + + case GTK_TEXT_WINDOW_TEXT: + gtk_css_node_set_name (css_node, "text"); + break; + + case GTK_TEXT_WINDOW_WIDGET: + default: + break; + } +} + +static void +gtk_text_view_child_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (object); + + switch (prop_id) + { + case PROP_WINDOW_TYPE: + g_value_set_enum (value, self->window_type); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtk_text_view_child_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (object); + + switch (prop_id) + { + case PROP_WINDOW_TYPE: + self->window_type = g_value_get_enum (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtk_text_view_child_class_init (GtkTextViewChildClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + + object_class->constructed = gtk_text_view_child_constructed; + object_class->get_property = gtk_text_view_child_get_property; + object_class->set_property = gtk_text_view_child_set_property; + + widget_class->measure = gtk_text_view_child_measure; + widget_class->size_allocate = gtk_text_view_child_size_allocate; + widget_class->snapshot = gtk_text_view_child_snapshot; + + container_class->add = gtk_text_view_child_add; + container_class->remove = gtk_text_view_child_remove; + container_class->forall = gtk_text_view_child_forall; + + /** + * GtkTextViewChild:window-type: + * + * The "window-type" property is the #GtkTextWindowType of the + * #GtkTextView that the child is attached. + */ + properties[PROP_WINDOW_TYPE] = + g_param_spec_enum ("window-type", + P_("Window Type"), + P_("The GtkTextWindowType"), + GTK_TYPE_TEXT_WINDOW_TYPE, + GTK_TEXT_WINDOW_TEXT, + GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +gtk_text_view_child_init (GtkTextViewChild *self) +{ + self->window_type = GTK_TEXT_WINDOW_TEXT; + + gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN); +} + +GtkWidget * +gtk_text_view_child_new (GtkTextWindowType window_type) +{ + g_return_val_if_fail (window_type == GTK_TEXT_WINDOW_LEFT || + window_type == GTK_TEXT_WINDOW_RIGHT || + window_type == GTK_TEXT_WINDOW_TOP || + window_type == GTK_TEXT_WINDOW_BOTTOM || + window_type == GTK_TEXT_WINDOW_TEXT, + NULL); + + return g_object_new (GTK_TYPE_TEXT_VIEW_CHILD, + "window-type", window_type, + NULL); +} + +void +gtk_text_view_child_add_overlay (GtkTextViewChild *self, + GtkWidget *widget, + int xpos, + int ypos) +{ + Overlay *overlay; + + g_return_if_fail (GTK_IS_TEXT_VIEW_CHILD (self)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + overlay = overlay_new (widget, xpos, ypos); + g_queue_push_tail (&self->overlays, &overlay->link); + gtk_widget_set_parent (widget, GTK_WIDGET (self)); +} + +void +gtk_text_view_child_move_overlay (GtkTextViewChild *self, + GtkWidget *widget, + int xpos, + int ypos) +{ + Overlay *overlay; + + g_return_if_fail (GTK_IS_TEXT_VIEW_CHILD (self)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + overlay = gtk_text_view_child_get_overlay (self, widget); + + if (overlay != NULL) + { + overlay->x = xpos; + overlay->y = ypos; + + if (gtk_widget_get_visible (GTK_WIDGET (self)) && + gtk_widget_get_visible (widget)) + gtk_widget_queue_allocate (GTK_WIDGET (self)); + } +} + +GtkTextWindowType +gtk_text_view_child_get_window_type (GtkTextViewChild *self) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW_CHILD (self), 0); + + return self->window_type; +} + +void +gtk_text_view_child_set_offset (GtkTextViewChild *self, + int xoffset, + int yoffset) +{ + gboolean changed = FALSE; + + g_return_if_fail (GTK_IS_TEXT_VIEW_CHILD (self)); + + if (self->window_type == GTK_TEXT_WINDOW_TEXT || + self->window_type == GTK_TEXT_WINDOW_TOP || + self->window_type == GTK_TEXT_WINDOW_BOTTOM) + { + if (self->xoffset != xoffset) + { + self->xoffset = xoffset; + changed = TRUE; + } + } + + if (self->window_type == GTK_TEXT_WINDOW_TEXT || + self->window_type == GTK_TEXT_WINDOW_LEFT || + self->window_type == GTK_TEXT_WINDOW_RIGHT) + { + if (self->yoffset != yoffset) + { + self->yoffset = yoffset; + changed = TRUE; + } + } + + if (changed) + gtk_widget_queue_draw (GTK_WIDGET (self)); +} diff --git a/gtk/gtktextviewchildprivate.h b/gtk/gtktextviewchildprivate.h new file mode 100644 index 0000000000..a7396a48d3 --- /dev/null +++ b/gtk/gtktextviewchildprivate.h @@ -0,0 +1,48 @@ +/* GTK - The GIMP Toolkit + * gtktextviewchild-private.h Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __GTK_TEXT_VIEW_CHILD_PRIVATE_H__ +#define __GTK_TEXT_VIEW_CHILD_PRIVATE_H__ + +#include +#include + +#define GTK_TYPE_TEXT_VIEW_CHILD (gtk_text_view_child_get_type()) + +G_GNUC_INTERNAL +G_DECLARE_FINAL_TYPE (GtkTextViewChild, gtk_text_view_child, GTK, TEXT_VIEW_CHILD, GtkContainer) + +G_GNUC_INTERNAL +GtkWidget *gtk_text_view_child_new (GtkTextWindowType window_type); +G_GNUC_INTERNAL +GtkTextWindowType gtk_text_view_child_get_window_type (GtkTextViewChild *self); +G_GNUC_INTERNAL +void gtk_text_view_child_add_overlay (GtkTextViewChild *self, + GtkWidget *widget, + int xpos, + int ypos); +G_GNUC_INTERNAL +void gtk_text_view_child_move_overlay (GtkTextViewChild *self, + GtkWidget *widget, + int xpos, + int ypos); +G_GNUC_INTERNAL +void gtk_text_view_child_set_offset (GtkTextViewChild *child, + int xoffset, + int yoffset); + +#endif /* __GTK_TEXT_VIEW_CHILD_PRIVATE_H__ */ diff --git a/gtk/meson.build b/gtk/meson.build index 0cb3fbb9af..ae399247b6 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -145,6 +145,7 @@ gtk_private_sources = files([ 'gtkstylecascade.c', 'gtkstyleproperty.c', 'gtktextbtree.c', + 'gtktextviewchild.c', 'gtktrashmonitor.c', 'gtktreedatalist.c', ]) diff --git a/tests/testtextview.c b/tests/testtextview.c index d746ec2419..c0458e2dd9 100644 --- a/tests/testtextview.c +++ b/tests/testtextview.c @@ -193,10 +193,9 @@ main (int argc, char **argv) gtk_container_add (GTK_CONTAINER (window), sw); gtk_container_add (GTK_CONTAINER (sw), textview); - gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (textview), - button, - GTK_TEXT_WINDOW_TEXT, - 50, 150); + gtk_text_view_add_overlay (GTK_TEXT_VIEW (textview), + button, + 50, 150); gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (textview), button2, anchor); diff --git a/testsuite/reftests/textview-border-windows.c b/testsuite/reftests/textview-border-windows.c index 019b654907..7a6646393a 100644 --- a/testsuite/reftests/textview-border-windows.c +++ b/testsuite/reftests/textview-border-windows.c @@ -17,12 +17,23 @@ #include +static void +set_border_window_size (GtkTextView *text_view, + GtkTextWindowType win, + gint size) +{ + GtkWidget *label; + + label = gtk_label_new (NULL); + gtk_widget_set_size_request (label, size, size); + gtk_text_view_set_gutter (text_view, win, label); +} G_MODULE_EXPORT void add_border_windows (GtkTextView *text_view) { - gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT, 30); - gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_RIGHT, 30); - gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_TOP, 30); - gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_BOTTOM, 30); + set_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT, 30); + set_border_window_size (text_view, GTK_TEXT_WINDOW_RIGHT, 30); + set_border_window_size (text_view, GTK_TEXT_WINDOW_TOP, 30); + set_border_window_size (text_view, GTK_TEXT_WINDOW_BOTTOM, 30); }