[gtksourceview/wip/chergert/gsv-gtk4: 193/259] assistants: add new assistants subsystem
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/chergert/gsv-gtk4: 193/259] assistants: add new assistants subsystem
- Date: Mon, 21 Sep 2020 23:27:47 +0000 (UTC)
commit 6608a724e134f7d18d7f38fac368d0c90a686830
Author: Christian Hergert <chergert redhat com>
Date: Sat Aug 29 08:43:59 2020 -0700
assistants: add new assistants subsystem
This subsystem is meant to be a base for popup based tooling around a
GtkSourceView. It can be used for the underlying layer of completion,
interactive tooltips, error bubbles, snippet tooltips, and more.
A new completion engine will land first using this subsystem, but will
keep the GtkSourceAssistant type private similar to how GDK does for
internal (but exposed) types.
gtksourceview/gtksourceassistant-private.h | 59 ++++
gtksourceview/gtksourceassistant.c | 386 ++++++++++++++++++++++++
gtksourceview/gtksourceassistantchild-private.h | 44 +++
gtksourceview/gtksourceassistantchild.c | 186 ++++++++++++
gtksourceview/gtksourceview-assistants.c | 171 +++++++++++
gtksourceview/gtksourceview-private.h | 56 ++++
gtksourceview/gtksourceview.c | 30 +-
gtksourceview/meson.build | 3 +
8 files changed, 934 insertions(+), 1 deletion(-)
---
diff --git a/gtksourceview/gtksourceassistant-private.h b/gtksourceview/gtksourceassistant-private.h
new file mode 100644
index 00000000..7bc6d55f
--- /dev/null
+++ b/gtksourceview/gtksourceassistant-private.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView 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.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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 <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "gtksourcetypes-private.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_ASSISTANT (_gtk_source_assistant_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (GtkSourceAssistant, _gtk_source_assistant, GTK_SOURCE, ASSISTANT, GtkPopover)
+
+struct _GtkSourceAssistantClass
+{
+ GtkPopoverClass parent_class;
+
+ void (*get_offset) (GtkSourceAssistant *assistant,
+ int *x_offset,
+ int *y_offset);
+ void (*get_target_location) (GtkSourceAssistant *assistant,
+ GdkRectangle *rect);
+};
+
+GtkSourceAssistant *_gtk_source_assistant_new (void);
+void _gtk_source_assistant_attach (GtkSourceAssistant *assistant,
+ GtkSourceAssistant *attached_to);
+void _gtk_source_assistant_detach (GtkSourceAssistant *assistant);
+void _gtk_source_assistant_get_offset (GtkSourceAssistant *assistant,
+ int *x,
+ int *y);
+GtkTextMark *_gtk_source_assistant_get_mark (GtkSourceAssistant *assistant);
+void _gtk_source_assistant_set_mark (GtkSourceAssistant *assistant,
+ GtkTextMark *mark);
+void _gtk_source_assistant_set_child (GtkSourceAssistant *assistant,
+ GtkWidget *child);
+void _gtk_source_assistant_destroy (GtkSourceAssistant *assistant);
+
+G_END_DECLS
diff --git a/gtksourceview/gtksourceassistant.c b/gtksourceview/gtksourceassistant.c
new file mode 100644
index 00000000..9471ae42
--- /dev/null
+++ b/gtksourceview/gtksourceassistant.c
@@ -0,0 +1,386 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView 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.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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 <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gtksourceassistant-private.h"
+#include "gtksourceassistantchild-private.h"
+#include "gtksourceview-private.h"
+
+typedef struct
+{
+ GtkTextMark *mark;
+ GtkSourceAssistantChild *child;
+} GtkSourceAssistantPrivate;
+
+static void buildable_iface_init (GtkBuildableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtkSourceAssistant, _gtk_source_assistant, GTK_TYPE_POPOVER,
+ G_ADD_PRIVATE (GtkSourceAssistant)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
+
+static GtkSourceView *
+_gtk_source_assistant_get_view (GtkSourceAssistant *assistant)
+{
+ GtkWidget *widget;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (assistant));
+
+ widget = gtk_widget_get_ancestor (GTK_WIDGET (assistant), GTK_SOURCE_TYPE_VIEW);
+
+ g_return_val_if_fail (!widget || GTK_SOURCE_IS_VIEW (widget), NULL);
+
+ return GTK_SOURCE_VIEW (widget);
+}
+
+static void
+_gtk_source_assistant_hide_action (GtkWidget *widget,
+ const gchar *action_name,
+ GVariant *parameter)
+{
+ g_assert (GTK_SOURCE_IS_ASSISTANT (widget));
+
+ gtk_popover_popdown (GTK_POPOVER (widget));
+}
+
+static void
+_gtk_source_assistant_real_get_target_location (GtkSourceAssistant *assistant,
+ GdkRectangle *location)
+{
+ GtkSourceAssistantPrivate *priv = _gtk_source_assistant_get_instance_private (assistant);
+ GtkSourceView *view;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (assistant));
+ g_assert (location != NULL);
+
+ view = _gtk_source_assistant_get_view (assistant);
+
+ if (view != NULL)
+ {
+ GtkTextBuffer *buffer;
+ GtkTextMark *mark;
+ GtkTextIter iter;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+ mark = priv->mark ? priv->mark : gtk_text_buffer_get_insert (buffer);
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
+ gtk_text_view_get_iter_location (GTK_TEXT_VIEW (view), &iter, location);
+ }
+ else
+ {
+ location->x = 0;
+ location->y = 0;
+ location->width = 0;
+ location->height = 0;
+ }
+}
+
+static void
+_gtk_source_assistant_get_target_location (GtkSourceAssistant *assistant,
+ GdkRectangle *location)
+{
+ g_assert (GTK_SOURCE_IS_ASSISTANT (assistant));
+ g_assert (location != NULL);
+
+ GTK_SOURCE_ASSISTANT_GET_CLASS (assistant)->get_target_location (assistant, location);
+}
+
+static void
+_gtk_source_assistant_update_position (GtkSourceAssistant *assistant)
+{
+ GtkSourceAssistantPrivate *priv = _gtk_source_assistant_get_instance_private (assistant);
+ const GList *children = NULL;
+ GtkWidget *parent;
+ GdkRectangle rect;
+ int x = 0;
+ int y = 0;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (assistant));
+
+ parent = gtk_widget_get_parent (GTK_WIDGET (assistant));
+
+ if (GTK_SOURCE_IS_VIEW (parent))
+ {
+ _gtk_source_assistant_get_offset (assistant, &x, &y);
+ _gtk_source_assistant_get_target_location (assistant, &rect);
+
+ gtk_popover_set_offset (GTK_POPOVER (assistant), x, y);
+ gtk_popover_set_pointing_to (GTK_POPOVER (assistant), &rect);
+ }
+
+ if (priv->child != NULL)
+ {
+ children = _gtk_source_assistant_child_get_attached (priv->child);
+ }
+
+ for (const GList *iter = children; iter; iter = iter->next)
+ {
+ GtkSourceAssistant *child = iter->data;
+
+ _gtk_source_assistant_get_offset (child, &x, &y);
+ gtk_popover_set_offset (GTK_POPOVER (child), x, y);
+
+ if (gtk_widget_get_visible (GTK_WIDGET (child)))
+ {
+ gtk_native_check_resize (GTK_NATIVE (child));
+ }
+ }
+}
+
+static void
+_gtk_source_assistant_show (GtkWidget *widget)
+{
+ GtkSourceAssistant *assistant = (GtkSourceAssistant *)widget;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (assistant));
+
+ _gtk_source_assistant_update_position (assistant);
+
+ GTK_WIDGET_CLASS (_gtk_source_assistant_parent_class)->show (widget);
+}
+
+static void
+_gtk_source_assistant_hide (GtkWidget *widget)
+{
+ GtkSourceAssistant *assistant = (GtkSourceAssistant *)widget;
+ GtkSourceAssistantPrivate *priv = _gtk_source_assistant_get_instance_private (assistant);
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (assistant));
+
+ _gtk_source_assistant_child_hide (priv->child);
+
+ GTK_WIDGET_CLASS (_gtk_source_assistant_parent_class)->hide (widget);
+}
+
+static void
+_gtk_source_assistant_real_get_offset (GtkSourceAssistant *assistant,
+ int *x,
+ int *y)
+{
+ GtkStyleContext *style_context;
+ GtkBorder margin;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (assistant));
+ g_assert (x != NULL);
+ g_assert (y != NULL);
+
+ style_context = gtk_widget_get_style_context (GTK_WIDGET (assistant));
+ gtk_style_context_get_margin (style_context, &margin);
+
+ *x = -margin.left;
+ *y = -margin.top + 1;
+}
+
+static void
+_gtk_source_assistant_dispose (GObject *object)
+{
+ GtkSourceAssistant *self = (GtkSourceAssistant *)object;
+ GtkSourceAssistantPrivate *priv = _gtk_source_assistant_get_instance_private (self);
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (self));
+
+ _gtk_source_assistant_detach (self);
+ g_clear_object (&priv->mark);
+
+ G_OBJECT_CLASS (_gtk_source_assistant_parent_class)->dispose (object);
+}
+
+static void
+_gtk_source_assistant_class_init (GtkSourceAssistantClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = _gtk_source_assistant_dispose;
+
+ widget_class->hide = _gtk_source_assistant_hide;
+ widget_class->show = _gtk_source_assistant_show;
+
+ klass->get_offset = _gtk_source_assistant_real_get_offset;
+ klass->get_target_location = _gtk_source_assistant_real_get_target_location;
+
+ gtk_widget_class_install_action (widget_class, "assistant.hide", NULL,
_gtk_source_assistant_hide_action);
+ gtk_widget_class_add_binding_action (widget_class, GDK_KEY_Escape, 0, "assistant.hide", NULL);
+ gtk_widget_class_set_css_name (widget_class, "GtkSourceAssistant");
+}
+
+static void
+_gtk_source_assistant_init (GtkSourceAssistant *self)
+{
+ GtkSourceAssistantPrivate *priv = _gtk_source_assistant_get_instance_private (self);
+
+ gtk_widget_set_halign (GTK_WIDGET (self), GTK_ALIGN_START);
+ gtk_widget_set_valign (GTK_WIDGET (self), GTK_ALIGN_START);
+ gtk_popover_set_position (GTK_POPOVER (self), GTK_POS_BOTTOM);
+ gtk_popover_set_has_arrow (GTK_POPOVER (self), FALSE);
+ gtk_popover_set_autohide (GTK_POPOVER (self), TRUE);
+
+ priv->child = _gtk_source_assistant_child_new ();
+ gtk_popover_set_child (GTK_POPOVER (self), GTK_WIDGET (priv->child));
+}
+
+GtkSourceAssistant *
+_gtk_source_assistant_new (void)
+{
+ return g_object_new (GTK_SOURCE_TYPE_ASSISTANT, NULL);
+}
+
+void
+_gtk_source_assistant_set_mark (GtkSourceAssistant *assistant,
+ GtkTextMark *mark)
+{
+ GtkSourceAssistantPrivate *priv = _gtk_source_assistant_get_instance_private (assistant);
+
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT (assistant));
+ g_return_if_fail (GTK_IS_TEXT_MARK (mark));
+
+ if (g_set_object (&priv->mark, mark))
+ {
+ _gtk_source_assistant_update_position (assistant);
+ }
+}
+
+GtkTextMark *
+_gtk_source_assistant_get_mark (GtkSourceAssistant *assistant)
+{
+ GtkSourceAssistantPrivate *priv = _gtk_source_assistant_get_instance_private (assistant);
+
+ g_return_val_if_fail (GTK_SOURCE_IS_ASSISTANT (assistant), NULL);
+
+ return priv->mark;
+}
+
+void
+_gtk_source_assistant_get_offset (GtkSourceAssistant *assistant,
+ int *x,
+ int *y)
+{
+ int dummy_x;
+ int dummy_y;
+
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT (assistant));
+
+ if (x == NULL)
+ x = &dummy_x;
+
+ if (y == NULL)
+ y = &dummy_y;
+
+ *x = 0;
+ *y = 0;
+
+ GTK_SOURCE_ASSISTANT_GET_CLASS (assistant)->get_offset (assistant, x, y);
+}
+
+void
+_gtk_source_assistant_detach (GtkSourceAssistant *assistant)
+{
+ GtkWidget *parent;
+
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT (assistant));
+
+ parent = gtk_widget_get_parent (GTK_WIDGET (assistant));
+
+ if (GTK_SOURCE_IS_ASSISTANT_CHILD (parent))
+ {
+ _gtk_source_assistant_child_detach (GTK_SOURCE_ASSISTANT_CHILD (parent),
+ assistant);
+ }
+}
+
+void
+_gtk_source_assistant_attach (GtkSourceAssistant *assistant,
+ GtkSourceAssistant *attach_to)
+{
+ GtkSourceAssistantPrivate *priv;
+
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT (assistant));
+ g_return_if_fail (!attach_to || GTK_SOURCE_IS_ASSISTANT (attach_to));
+
+ if (attach_to == NULL)
+ {
+ _gtk_source_assistant_detach (assistant);
+ }
+ else
+ {
+ priv = _gtk_source_assistant_get_instance_private (attach_to);
+ _gtk_source_assistant_child_attach (priv->child, assistant);
+ }
+}
+
+void
+_gtk_source_assistant_set_child (GtkSourceAssistant *assistant,
+ GtkWidget *child)
+{
+ GtkSourceAssistantPrivate *priv = _gtk_source_assistant_get_instance_private (assistant);
+
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT (assistant));
+ g_return_if_fail (!child || GTK_IS_WIDGET (child));
+
+ _gtk_source_assistant_child_set_child (priv->child, child);
+}
+
+static void
+_gtk_source_assistant_add_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const char *type)
+{
+ GtkSourceAssistant *self = (GtkSourceAssistant *)buildable;
+
+ if (GTK_IS_WIDGET (child))
+ {
+ _gtk_source_assistant_set_child (self, GTK_WIDGET (child));
+ }
+}
+
+static void
+buildable_iface_init (GtkBuildableIface *iface)
+{
+ iface->add_child = _gtk_source_assistant_add_child;
+}
+
+void
+_gtk_source_assistant_destroy (GtkSourceAssistant *self)
+{
+ GtkWidget *parent;
+
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT (self));
+
+ parent = gtk_widget_get_parent (GTK_WIDGET (self));
+
+ if (parent == NULL)
+ return;
+
+ if (GTK_SOURCE_IS_VIEW (parent))
+ {
+ _gtk_source_view_remove_assistant (GTK_SOURCE_VIEW (parent), self);
+ }
+ else if (GTK_SOURCE_IS_ASSISTANT_CHILD (parent))
+ {
+ _gtk_source_assistant_child_detach (GTK_SOURCE_ASSISTANT_CHILD (parent), self);
+ }
+ else
+ {
+ g_warning ("Cannot remove assistant from type %s",
+ G_OBJECT_TYPE_NAME (parent));
+ }
+}
diff --git a/gtksourceview/gtksourceassistantchild-private.h b/gtksourceview/gtksourceassistantchild-private.h
new file mode 100644
index 00000000..cf271834
--- /dev/null
+++ b/gtksourceview/gtksourceassistantchild-private.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView 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.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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 <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "gtksourcetypes-private.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_ASSISTANT_CHILD (_gtk_source_assistant_child_get_type())
+
+G_DECLARE_FINAL_TYPE (GtkSourceAssistantChild, _gtk_source_assistant_child, GTK_SOURCE, ASSISTANT_CHILD,
GtkWidget)
+
+GtkSourceAssistantChild *_gtk_source_assistant_child_new (void);
+void _gtk_source_assistant_child_hide (GtkSourceAssistantChild *self);
+void _gtk_source_assistant_child_set_child (GtkSourceAssistantChild *self,
+ GtkWidget *child);
+void _gtk_source_assistant_child_attach (GtkSourceAssistantChild *self,
+ GtkSourceAssistant *child);
+void _gtk_source_assistant_child_detach (GtkSourceAssistantChild *self,
+ GtkSourceAssistant *child);
+const GList *_gtk_source_assistant_child_get_attached (GtkSourceAssistantChild *self);
+
+G_END_DECLS
diff --git a/gtksourceview/gtksourceassistantchild.c b/gtksourceview/gtksourceassistantchild.c
new file mode 100644
index 00000000..1981d251
--- /dev/null
+++ b/gtksourceview/gtksourceassistantchild.c
@@ -0,0 +1,186 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView 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.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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 <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gtksourceassistant-private.h"
+#include "gtksourceassistantchild-private.h"
+
+struct _GtkSourceAssistantChild
+{
+ GtkWidget parent_instance;
+ GtkWidget *child;
+ GQueue attached;
+};
+
+G_DEFINE_TYPE (GtkSourceAssistantChild, _gtk_source_assistant_child, GTK_TYPE_WIDGET)
+
+static void
+_gtk_source_assistant_child_size_allocate (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ GtkSourceAssistantChild *child = (GtkSourceAssistantChild *)widget;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT_CHILD (child));
+
+ GTK_WIDGET_CLASS (_gtk_source_assistant_child_parent_class)->size_allocate (widget, width, height,
baseline);
+
+ for (const GList *iter = child->attached.head; iter; iter = iter->next)
+ {
+ GtkSourceAssistant *attached = iter->data;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (attached));
+ g_assert (GTK_IS_NATIVE (attached));
+
+ if (gtk_widget_get_visible (GTK_WIDGET (attached)))
+ {
+ gtk_native_check_resize (GTK_NATIVE (attached));
+ }
+ }
+}
+
+static void
+_gtk_source_assistant_child_dispose (GObject *object)
+{
+ GtkSourceAssistantChild *self = (GtkSourceAssistantChild *)object;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT_CHILD (self));
+
+ while (self->attached.head != NULL)
+ {
+ GtkSourceAssistant *attached = self->attached.head->data;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (attached));
+
+ _gtk_source_assistant_child_detach (self, attached);
+ }
+
+ g_clear_pointer (&self->child, gtk_widget_unparent);
+
+ G_OBJECT_CLASS (_gtk_source_assistant_child_parent_class)->dispose (object);
+}
+
+static void
+_gtk_source_assistant_child_class_init (GtkSourceAssistantChildClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = _gtk_source_assistant_child_dispose;
+
+ widget_class->size_allocate = _gtk_source_assistant_child_size_allocate;
+
+ gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+}
+
+static void
+_gtk_source_assistant_child_init (GtkSourceAssistantChild *self)
+{
+}
+
+GtkSourceAssistantChild *
+_gtk_source_assistant_child_new (void)
+{
+ return g_object_new (GTK_SOURCE_TYPE_ASSISTANT_CHILD, NULL);
+}
+
+void
+_gtk_source_assistant_child_hide (GtkSourceAssistantChild *self)
+{
+ g_assert (GTK_SOURCE_IS_ASSISTANT_CHILD (self));
+
+ for (const GList *iter = self->attached.head; iter; iter = iter->next)
+ {
+ GtkSourceAssistant *attached = iter->data;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (attached));
+ g_assert (GTK_IS_POPOVER (attached));
+
+ gtk_popover_popdown (GTK_POPOVER (attached));
+ }
+}
+
+void
+_gtk_source_assistant_child_detach (GtkSourceAssistantChild *self,
+ GtkSourceAssistant *child)
+{
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT_CHILD (self));
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT (child));
+
+ if (g_queue_remove (&self->attached, child))
+ {
+ gtk_widget_unparent (GTK_WIDGET (child));
+ g_object_unref (child);
+ }
+}
+
+void
+_gtk_source_assistant_child_attach (GtkSourceAssistantChild *self,
+ GtkSourceAssistant *child)
+{
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT_CHILD (self));
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT (child));
+ g_return_if_fail (gtk_widget_get_parent (GTK_WIDGET (child)) == NULL);
+
+ g_queue_push_tail (&self->attached, g_object_ref_sink (child));
+ gtk_widget_set_parent (GTK_WIDGET (child), GTK_WIDGET (self));
+
+ if (GTK_IS_NATIVE (child))
+ {
+ if (gtk_widget_get_visible (GTK_WIDGET (child)))
+ {
+ gtk_native_check_resize (GTK_NATIVE (child));
+ }
+ }
+}
+
+void
+_gtk_source_assistant_child_set_child (GtkSourceAssistantChild *self,
+ GtkWidget *child)
+{
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT_CHILD (self));
+ g_return_if_fail (GTK_IS_WIDGET (child));
+
+ if (child == self->child)
+ {
+ return;
+ }
+
+ g_clear_pointer (&self->child, gtk_widget_unparent);
+
+ if (child != NULL)
+ {
+ self->child = child;
+ gtk_widget_set_parent (child, GTK_WIDGET (self));
+ }
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+const GList *
+_gtk_source_assistant_child_get_attached (GtkSourceAssistantChild *self)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_ASSISTANT_CHILD (self), NULL);
+
+ return self->attached.head;
+}
diff --git a/gtksourceview/gtksourceview-assistants.c b/gtksourceview/gtksourceview-assistants.c
new file mode 100644
index 00000000..0422edec
--- /dev/null
+++ b/gtksourceview/gtksourceview-assistants.c
@@ -0,0 +1,171 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView 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.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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 <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gtksourceview-private.h"
+
+void
+_gtk_source_view_assistants_init (GtkSourceViewAssistants *assistants,
+ GtkSourceView *view)
+{
+ g_assert (assistants != NULL);
+ g_assert (assistants->view == NULL);
+
+ assistants->view = view;
+ g_queue_init (&assistants->queue);
+}
+
+void
+_gtk_source_view_assistants_shutdown (GtkSourceViewAssistants *assistants)
+{
+ g_assert (assistants != NULL);
+ g_assert (assistants->view != NULL);
+
+ while (assistants->queue.length > 0)
+ {
+ GtkSourceAssistant*assistant = g_queue_peek_head (&assistants->queue);
+ _gtk_source_view_assistants_remove (assistants, assistant);
+ }
+
+ assistants->view = NULL;
+
+ g_assert (assistants->view == NULL);
+ g_assert (g_queue_is_empty (&assistants->queue));
+}
+
+void
+_gtk_source_view_assistants_add (GtkSourceViewAssistants *assistants,
+ GtkSourceAssistant *assistant)
+{
+ g_assert (assistants != NULL);
+ g_assert (assistants->view != NULL);
+
+ if (gtk_widget_get_parent (GTK_WIDGET (assistant)))
+ {
+ g_warning ("Cannot add assistant, it already has a parent");
+ return;
+ }
+
+ g_queue_push_tail (&assistants->queue, g_object_ref_sink (assistant));
+ gtk_widget_set_parent (GTK_WIDGET (assistant), GTK_WIDGET (assistants->view));
+}
+
+void
+_gtk_source_view_assistants_remove (GtkSourceViewAssistants *assistants,
+ GtkSourceAssistant *assistant)
+{
+ GList *link;
+
+ g_assert (assistants != NULL);
+ g_assert (assistants->view != NULL);
+ g_assert (assistants->queue.length > 0);
+
+ link = g_queue_find (&assistants->queue, assistant);
+
+ if (link != NULL)
+ {
+ g_queue_delete_link (&assistants->queue, link);
+ gtk_widget_unparent (GTK_WIDGET (assistant));
+ g_object_unref (assistant);
+ }
+}
+
+void
+_gtk_source_view_assistants_size_allocate (GtkSourceViewAssistants *assistants,
+ int width,
+ int height,
+ int baseline)
+{
+ g_assert (assistants != NULL);
+
+ for (const GList *iter = assistants->queue.head; iter; iter = iter->next)
+ {
+ GtkSourceAssistant *assistant = iter->data;
+ int assistant_width;
+ int assistant_height;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (assistant));
+
+ gtk_widget_measure (GTK_WIDGET (assistant),
+ GTK_ORIENTATION_HORIZONTAL,
+ -1,
+ NULL,
+ &assistant_width,
+ NULL,
+ NULL);
+ gtk_widget_measure (GTK_WIDGET (assistant),
+ GTK_ORIENTATION_VERTICAL,
+ assistant_width,
+ NULL,
+ &assistant_height,
+ NULL,
+ NULL);
+
+ gtk_widget_set_size_request (GTK_WIDGET (assistant),
+ assistant_width,
+ assistant_height);
+
+ gtk_native_check_resize (GTK_NATIVE (assistant));
+ }
+}
+
+static gboolean
+_gtk_source_view_assistants_hide_all (GtkSourceViewAssistants *assistants)
+{
+ gboolean ret = FALSE;
+
+ g_assert (assistants != NULL);
+
+ for (const GList *iter = assistants->queue.head; iter; iter = iter->next)
+ {
+ GtkSourceAssistant *assistant = iter->data;
+
+ g_assert (GTK_SOURCE_IS_ASSISTANT (assistant));
+
+ if (gtk_widget_get_visible (GTK_WIDGET (assistant)))
+ {
+ gtk_popover_popdown (GTK_POPOVER (assistant));
+ ret = TRUE;
+ }
+ }
+
+ return ret;
+}
+
+gboolean
+_gtk_source_view_assistants_handle_key (GtkSourceViewAssistants *assistants,
+ guint keyval,
+ GdkModifierType state)
+{
+ g_assert (assistants != NULL);
+
+ if (keyval == GDK_KEY_Escape)
+ {
+ if (_gtk_source_view_assistants_hide_all (assistants))
+ {
+ gtk_widget_grab_focus (GTK_WIDGET (assistants->view));
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/gtksourceview/gtksourceview-private.h b/gtksourceview/gtksourceview-private.h
new file mode 100644
index 00000000..515e1eb3
--- /dev/null
+++ b/gtksourceview/gtksourceview-private.h
@@ -0,0 +1,56 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView 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.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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 <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include "gtksourceview.h"
+#include "gtksourceassistant-private.h"
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+ GtkSourceView *view;
+ GQueue queue;
+} GtkSourceViewAssistants;
+
+void _gtk_source_view_add_assistant (GtkSourceView *view,
+ GtkSourceAssistant *assistant);
+void _gtk_source_view_remove_assistant (GtkSourceView *view,
+ GtkSourceAssistant *assistant);
+void _gtk_source_view_assistants_init (GtkSourceViewAssistants *assistants,
+ GtkSourceView *view);
+void _gtk_source_view_assistants_add (GtkSourceViewAssistants *assistants,
+ GtkSourceAssistant *assistant);
+void _gtk_source_view_assistants_remove (GtkSourceViewAssistants *assistants,
+ GtkSourceAssistant *assistant);
+void _gtk_source_view_assistants_remove (GtkSourceViewAssistants *assistants,
+ GtkSourceAssistant *assistant);
+void _gtk_source_view_assistants_shutdown (GtkSourceViewAssistants *assistants);
+void _gtk_source_view_assistants_size_allocate (GtkSourceViewAssistants *assistants,
+ int width,
+ int height,
+ int baseline);
+gboolean _gtk_source_view_assistants_handle_key (GtkSourceViewAssistants *assistant,
+ guint keyval,
+ GdkModifierType state);
+
+G_END_DECLS
diff --git a/gtksourceview/gtksourceview.c b/gtksourceview/gtksourceview.c
index 38c8c42d..95a8b292 100644
--- a/gtksourceview/gtksourceview.c
+++ b/gtksourceview/gtksourceview.c
@@ -22,7 +22,7 @@
#include "config.h"
-#include "gtksourceview.h"
+#include "gtksourceview-private.h"
#include <string.h>
#include <fribidi.h>
@@ -214,6 +214,8 @@ typedef struct
GtkSourceSmartHomeEndType smart_home_end;
GtkSourceBackgroundPatternType background_pattern;
+ GtkSourceViewAssistants assistants;
+
guint background_pattern_color_set : 1;
guint current_line_color_set : 1;
guint right_margin_line_color_set : 1;
@@ -1357,6 +1359,8 @@ gtk_source_view_init (GtkSourceView *view)
gtk_style_context_add_class (context, "sourceview");
gtk_source_view_populate_extra_menu (view);
+
+ _gtk_source_view_assistants_init (&priv->assistants, view);
}
static void
@@ -4919,3 +4923,27 @@ gtk_source_view_queue_draw (GtkSourceView *view)
_gtk_source_gutter_queue_draw (priv->right_gutter);
}
}
+
+void
+_gtk_source_view_add_assistant (GtkSourceView *view,
+ GtkSourceAssistant *assistant)
+{
+ GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
+
+ g_return_if_fail (GTK_SOURCE_IS_VIEW (view));
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT (assistant));
+
+ _gtk_source_view_assistants_add (&priv->assistants, assistant);
+}
+
+void
+_gtk_source_view_remove_assistant (GtkSourceView *view,
+ GtkSourceAssistant *assistant)
+{
+ GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
+
+ g_return_if_fail (GTK_SOURCE_IS_VIEW (view));
+ g_return_if_fail (GTK_SOURCE_IS_ASSISTANT (assistant));
+
+ _gtk_source_view_assistants_remove (&priv->assistants, assistant);
+}
diff --git a/gtksourceview/meson.build b/gtksourceview/meson.build
index 9d3d26ba..fc3a9cba 100644
--- a/gtksourceview/meson.build
+++ b/gtksourceview/meson.build
@@ -85,6 +85,8 @@ core_public_c = files([
])
core_private_c = files([
+ 'gtksourceassistant.c',
+ 'gtksourceassistantchild.c',
'gtksourcebindinggroup.c',
'gtksourcebufferinputstream.c',
'gtksourcebufferinternal.c',
@@ -101,6 +103,7 @@ core_private_c = files([
'gtksourcepixbufhelper.c',
'gtksourceregex.c',
'gtksourcesignalgroup.c',
+ 'gtksourceview-assistants.c',
])
core_c_args = [
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]