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);
}