[gtksourceview/wip/chergert/hoverers] try to port this to better gtk 4 apis
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/chergert/hoverers] try to port this to better gtk 4 apis
- Date: Wed, 10 Mar 2021 07:16:23 +0000 (UTC)
commit 8362dce3ce4258c7bc7639e8b6c9ad7dd53f15f3
Author: Christian Hergert <chergert redhat com>
Date: Tue Mar 9 23:16:16 2021 -0800
try to port this to better gtk 4 apis
gtksourceview/gtksourcehover.c | 365 ++++--------------------
gtksourceview/gtksourcehoverassistant-private.h | 12 +-
gtksourceview/gtksourcehoverassistant.c | 204 ++++++++++++-
gtksourceview/gtksourcehovercontext.c | 37 ++-
gtksourceview/gtksourcehoverdisplay-private.h | 30 ++
gtksourceview/gtksourcehoverdisplay.c | 29 +-
6 files changed, 351 insertions(+), 326 deletions(-)
---
diff --git a/gtksourceview/gtksourcehover.c b/gtksourceview/gtksourcehover.c
index a75c0e96..2b5e8abd 100644
--- a/gtksourceview/gtksourcehover.c
+++ b/gtksourceview/gtksourcehover.c
@@ -44,150 +44,14 @@ struct _GtkSourceHover
GPtrArray *providers;
- gdouble motion_x;
- gdouble motion_y;
+ double motion_x;
+ double motion_y;
- guint state;
-
- guint delay_display_source;
- guint dismiss_source;
-};
-
-enum {
- HOVER_STATE_INITIAL,
- HOVER_STATE_DISPLAY,
- HOVER_STATE_IN_POPOVER,
+ guint settle_source;
};
G_DEFINE_TYPE (GtkSourceHover, gtk_source_hover, G_TYPE_OBJECT)
-static gboolean
-gtk_source_hover_dismiss_cb (gpointer data)
-{
- GtkSourceHover *self = data;
-
- g_assert (GTK_SOURCE_IS_HOVER (self));
-
- g_print ("Hover dismiss\n");
-
- self->dismiss_source = 0;
-
- switch (self->state) {
- case HOVER_STATE_DISPLAY:
- g_assert (GTK_SOURCE_IS_HOVER_ASSISTANT (self->assistant));
-
- gtk_widget_hide (GTK_WIDGET (self->assistant));
-
- g_assert (self->state == HOVER_STATE_INITIAL);
- g_assert (self->assistant == NULL);
-
- break;
-
- case HOVER_STATE_INITIAL:
- case HOVER_STATE_IN_POPOVER:
- default:
- g_clear_handle_id (&self->delay_display_source, g_source_remove);
- break;
- }
-
- return G_SOURCE_REMOVE;
-}
-
-static void
-gtk_source_hover_queue_dismiss (GtkSourceHover *self)
-{
- g_assert (GTK_SOURCE_IS_HOVER (self));
-
- g_clear_handle_id (&self->dismiss_source, g_source_remove);
- self->dismiss_source = g_timeout_add (DISMISS_DELAY_MSEC,
- gtk_source_hover_dismiss_cb,
- self);
-}
-
-static void
-on_assistant_motion_cb (GtkSourceHover *self,
- double x,
- double y,
- GtkEventControllerMotion *controller)
-{
- GtkAllocation alloc;
- GdkSurface *surface;
- GtkRoot *toplevel;
- double abs_x, abs_y;
- double popup_x, popup_y;
-
- g_assert (GTK_SOURCE_IS_HOVER (self));
- g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (controller));
-
- if (self->assistant == NULL || self->view == NULL)
- {
- return;
- }
-
- toplevel = gtk_widget_get_root (GTK_WIDGET (self->view));
- surface = gtk_native_get_surface (GTK_NATIVE (self->assistant));
-
- /* To translate, because we are crossing surfaces, we need to
- * take the position of the popup relative to the surface of
- * the parent view.
- */
- popup_x = gdk_popup_get_position_x (GDK_POPUP (surface));
- popup_y = gdk_popup_get_position_y (GDK_POPUP (surface));
- gtk_widget_get_allocation (GTK_WIDGET (self->assistant), &alloc);
- gtk_widget_translate_coordinates (GTK_WIDGET (self->view),
- GTK_WIDGET (toplevel),
- x, y, &abs_x, &abs_y);
-
- if (abs_x < (popup_x - GRACE_X) ||
- abs_x > (popup_x + alloc.width + GRACE_X) ||
- abs_y < (popup_y - GRACE_Y) ||
- abs_y > (popup_y + alloc.height + GRACE_Y))
- {
- gtk_event_controller_reset (GTK_EVENT_CONTROLLER (controller));
- gtk_widget_hide (GTK_WIDGET (self->assistant));
-
- g_assert (self->assistant == NULL);
- g_assert (self->state == HOVER_STATE_INITIAL);
- }
-
- g_clear_handle_id (&self->dismiss_source, g_source_remove);
- g_clear_handle_id (&self->delay_display_source, g_source_remove);
-}
-
-static gboolean
-on_key_pressed_cb (GtkSourceHover *self,
- guint keyval,
- guint keycode,
- GdkModifierType state,
- GtkEventControllerKey *controller)
-{
- g_assert (GTK_SOURCE_IS_HOVER (self));
- g_assert (GTK_IS_EVENT_CONTROLLER_KEY (controller));
-
- return GDK_EVENT_PROPAGATE;
-}
-
-static void
-on_motion_enter_cb (GtkSourceHover *self,
- double x,
- double y,
- GtkEventControllerMotion *controller)
-{
- g_assert (GTK_SOURCE_IS_HOVER (self));
- g_assert (GTK_SOURCE_IS_VIEW (self->view));
- g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (controller));
-
-}
-
-static void
-on_motion_leave_cb (GtkSourceHover *self,
- GtkEventControllerMotion *controller)
-{
- g_assert (GTK_SOURCE_IS_HOVER (self));
- g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (controller));
-
-}
-
static gboolean
gtk_source_hover_get_bounds (GtkSourceHover *self,
GtkTextIter *begin,
@@ -240,176 +104,72 @@ gtk_source_hover_get_bounds (GtkSourceHover *self,
if (!_gtk_source_iter_starts_full_word (&iter))
{
- _gtk_source_iter_backward_full_word_start (&iter);
+ _gtk_source_iter_backward_extra_natural_word_start (&iter);
}
*begin = iter;
*end = iter;
- _gtk_source_iter_forward_full_word_end (end);
+ _gtk_source_iter_forward_extra_natural_word_end (end);
return TRUE;
}
-static void
-on_assistant_closed_cb (GtkSourceHover *self,
- GtkSourceHoverAssistant *assistant)
-{
- g_assert (GTK_SOURCE_IS_HOVER (self));
- g_assert (GTK_SOURCE_IS_HOVER_ASSISTANT (assistant));
-
- self->state = HOVER_STATE_INITIAL;
-
- g_clear_pointer (&self->assistant, _gtk_source_assistant_destroy);
-
- g_clear_handle_id (&self->dismiss_source, g_source_remove);
- g_clear_handle_id (&self->delay_display_source, g_source_remove);
-
- g_assert (self->assistant == NULL);
- g_assert (self->state == HOVER_STATE_INITIAL);
- g_assert (self->dismiss_source == 0);
- g_assert (self->delay_display_source == 0);
-}
-
static gboolean
-on_assistant_motion_enter_cb (GtkSourceHover *self,
- double x,
- double y,
- GtkEventControllerMotion *motion)
+gtk_source_hover_settled_cb (GtkSourceHover *self)
{
+ GtkTextIter begin;
+ GtkTextIter end;
+ GtkTextIter location;
+
g_assert (GTK_SOURCE_IS_HOVER (self));
- g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
- g_print ("Motion enter\n");
+ self->settle_source = 0;
- /* Possible with DnD dragging? */
- if (self->state != HOVER_STATE_DISPLAY)
+ if (gtk_source_hover_get_bounds (self, &begin, &end, &location))
{
- return GDK_EVENT_PROPAGATE;
+ _gtk_source_hover_assistant_display (GTK_SOURCE_HOVER_ASSISTANT (self->assistant),
+ (GtkSourceHoverProvider **)self->providers->pdata,
+ self->providers->len,
+ &begin, &end, &location);
}
- self->state = HOVER_STATE_IN_POPOVER;
- g_clear_handle_id (&self->dismiss_source, g_source_remove);
-
- return GDK_EVENT_PROPAGATE;
+ return G_SOURCE_REMOVE;
}
-static gboolean
-on_assistant_motion_leave_cb (GtkSourceHover *self,
- GtkEventControllerMotion *motion)
+static void
+gtk_source_hover_queue_settle (GtkSourceHover *self)
{
g_assert (GTK_SOURCE_IS_HOVER (self));
- g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
-
- if (self->state == HOVER_STATE_IN_POPOVER)
- {
- self->state = HOVER_STATE_DISPLAY;
- }
- gtk_source_hover_queue_dismiss (self);
-
- return GDK_EVENT_PROPAGATE;
+ g_clear_handle_id (&self->settle_source, g_source_remove);
+ self->settle_source = g_timeout_add (MOTION_SETTLE_TIMEOUT_MSEC,
+ (GSourceFunc) gtk_source_hover_settled_cb,
+ self);
}
static gboolean
-gtk_source_hover_motion_timeout_cb (gpointer data)
+gtk_source_hover_key_pressed_cb (GtkSourceHover *self,
+ guint keyval,
+ guint keycode,
+ GdkModifierType state,
+ GtkEventControllerKey *controller)
{
- GtkSourceHover *self = data;
- GdkRectangle rect;
- GdkRectangle begin_rect;
- GdkRectangle end_rect;
- GdkRectangle location_rect;
- GtkTextIter begin;
- GtkTextIter end;
- GtkTextIter location;
-
g_assert (GTK_SOURCE_IS_HOVER (self));
+ g_assert (GTK_IS_EVENT_CONTROLLER_KEY (controller));
- g_print ("Motion timeout\n");
-
- self->delay_display_source = 0;
-
- if (self->view == NULL ||
- self->state != HOVER_STATE_INITIAL ||
- !gtk_source_hover_get_bounds (self, &begin, &end, &location))
- {
- return G_SOURCE_REMOVE;
- }
-
- g_assert (GTK_SOURCE_IS_VIEW (self->view));
-
- if (self->assistant == NULL)
- {
- GtkEventController *motion;
-
- self->assistant = _gtk_source_hover_assistant_new ();
-
- gtk_popover_set_position (GTK_POPOVER (self->assistant), GTK_POS_TOP);
- gtk_popover_set_autohide (GTK_POPOVER (self->assistant), TRUE);
-
- g_signal_connect_object (self->assistant,
- "closed",
- G_CALLBACK (on_assistant_closed_cb),
- self,
- G_CONNECT_SWAPPED);
-
- motion = gtk_event_controller_motion_new ();
- gtk_event_controller_set_propagation_phase (motion, GTK_PHASE_CAPTURE);
- g_signal_connect_object (motion,
- "enter",
- G_CALLBACK (on_assistant_motion_enter_cb),
- self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (motion,
- "motion",
- G_CALLBACK (on_assistant_motion_cb),
- self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (motion,
- "leave",
- G_CALLBACK (on_assistant_motion_leave_cb),
- self,
- G_CONNECT_SWAPPED);
- gtk_widget_add_controller (GTK_WIDGET (self->assistant), motion);
-
- _gtk_source_view_add_assistant (self->view, self->assistant);
- }
-
- self->state = HOVER_STATE_DISPLAY;
-
- gtk_text_view_get_iter_location (GTK_TEXT_VIEW (self->view), &begin, &begin_rect);
- gtk_text_view_get_iter_location (GTK_TEXT_VIEW (self->view), &end, &end_rect);
- gtk_text_view_get_iter_location (GTK_TEXT_VIEW (self->view), &location, &location_rect);
- gdk_rectangle_union (&begin_rect, &end_rect, &rect);
-
- gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (self->view),
- GTK_TEXT_WINDOW_WIDGET,
- rect.x, rect.y, &rect.x, &rect.y);
-
- _gtk_source_hover_assistant_set_hovered_at (GTK_SOURCE_HOVER_ASSISTANT (self->assistant),
- &location_rect);
-
- if (gtk_text_iter_equal (&begin, &end) &&
- gtk_text_iter_starts_line (&begin))
- {
- rect.width = 1;
- gtk_popover_set_position (GTK_POPOVER (self->assistant), GTK_POS_RIGHT);
- }
- else
- {
- gtk_popover_set_position (GTK_POPOVER (self->assistant), GTK_POS_TOP);
- }
-
- gtk_widget_show (GTK_WIDGET (self->assistant));
+ g_clear_handle_id (&self->settle_source, g_source_remove);
+ _gtk_source_hover_assistant_dismiss (GTK_SOURCE_HOVER_ASSISTANT (self->assistant));
- return G_SOURCE_REMOVE;
+ return GDK_EVENT_PROPAGATE;
}
+
static void
-on_motion_cb (GtkSourceHover *self,
- double x,
- double y,
- GtkEventControllerMotion *controller)
+gtk_source_hover_motion_cb (GtkSourceHover *self,
+ double x,
+ double y,
+ GtkEventControllerMotion *controller)
{
g_assert (GTK_SOURCE_IS_HOVER (self));
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (controller));
@@ -417,26 +177,30 @@ on_motion_cb (GtkSourceHover *self,
self->motion_x = x;
self->motion_y = y;
- g_clear_handle_id (&self->dismiss_source, g_source_remove);
- g_clear_handle_id (&self->delay_display_source, g_source_remove);
+ gtk_source_hover_queue_settle (self);
+}
- g_print ("Motion cb\n");
+static void
+gtk_source_hover_leave_cb (GtkSourceHover *self,
+ GtkEventControllerMotion *controller)
+{
+ g_assert (GTK_SOURCE_IS_HOVER (self));
+ g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (controller));
- self->delay_display_source = g_timeout_add (MOTION_SETTLE_TIMEOUT_MSEC,
- gtk_source_hover_motion_timeout_cb,
- self);
+ g_clear_handle_id (&self->settle_source, g_source_remove);
}
static gboolean
-on_scroll_cb (GtkSourceHover *self,
- double dx,
- double dy,
- GtkEventControllerScroll *controller)
+gtk_source_hover_scroll_cb (GtkSourceHover *self,
+ double dx,
+ double dy,
+ GtkEventControllerScroll *controller)
{
g_assert (GTK_SOURCE_IS_HOVER (self));
g_assert (GTK_IS_EVENT_CONTROLLER_SCROLL (controller));
- g_clear_pointer (&self->assistant, _gtk_source_assistant_destroy);
+ g_clear_handle_id (&self->settle_source, g_source_remove);
+ _gtk_source_hover_assistant_dismiss (GTK_SOURCE_HOVER_ASSISTANT (self->assistant));
return GDK_EVENT_PROPAGATE;
}
@@ -446,13 +210,10 @@ gtk_source_hover_dispose (GObject *object)
{
GtkSourceHover *self = (GtkSourceHover *)object;
+ g_clear_handle_id (&self->settle_source, g_source_remove);
g_clear_pointer (&self->assistant, _gtk_source_assistant_destroy);
-
g_clear_weak_pointer (&self->view);
- g_clear_handle_id (&self->delay_display_source, g_source_remove);
- g_clear_handle_id (&self->dismiss_source, g_source_remove);
-
if (self->providers->len > 0)
{
g_ptr_array_remove_range (self->providers, 0, self->providers->len);
@@ -468,8 +229,8 @@ gtk_source_hover_finalize (GObject *object)
g_clear_pointer (&self->providers, g_ptr_array_unref);
- g_assert (self->delay_display_source == 0);
- g_assert (self->dismiss_source == 0);
+ g_assert (self->assistant == NULL);
+ g_assert (self->settle_source == 0);
G_OBJECT_CLASS (gtk_source_hover_parent_class)->finalize (object);
}
@@ -501,30 +262,26 @@ _gtk_source_hover_new (GtkSourceView *view)
self = g_object_new (GTK_SOURCE_TYPE_HOVER, NULL);
g_set_weak_pointer (&self->view, view);
+ self->assistant = _gtk_source_hover_assistant_new ();
+ _gtk_source_view_add_assistant (view, self->assistant);
key = gtk_event_controller_key_new ();
g_signal_connect_object (key,
"key-pressed",
- G_CALLBACK (on_key_pressed_cb),
+ G_CALLBACK (gtk_source_hover_key_pressed_cb),
self,
G_CONNECT_SWAPPED);
gtk_widget_add_controller (GTK_WIDGET (view), key);
motion = gtk_event_controller_motion_new ();
- gtk_event_controller_set_propagation_phase (motion, GTK_PHASE_CAPTURE);
- g_signal_connect_object (motion,
- "enter",
- G_CALLBACK (on_motion_enter_cb),
- self,
- G_CONNECT_SWAPPED);
g_signal_connect_object (motion,
"leave",
- G_CALLBACK (on_motion_leave_cb),
+ G_CALLBACK (gtk_source_hover_leave_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (motion,
"motion",
- G_CALLBACK (on_motion_cb),
+ G_CALLBACK (gtk_source_hover_motion_cb),
self,
G_CONNECT_SWAPPED);
gtk_widget_add_controller (GTK_WIDGET (view), motion);
@@ -532,7 +289,7 @@ _gtk_source_hover_new (GtkSourceView *view)
scroll = gtk_event_controller_scroll_new (GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES);
g_signal_connect_object (scroll,
"scroll",
- G_CALLBACK (on_scroll_cb),
+ G_CALLBACK (gtk_source_hover_scroll_cb),
self,
G_CONNECT_SWAPPED);
gtk_widget_add_controller (GTK_WIDGET (view), scroll);
diff --git a/gtksourceview/gtksourcehoverassistant-private.h b/gtksourceview/gtksourcehoverassistant-private.h
index 5ee90c94..7925014a 100644
--- a/gtksourceview/gtksourcehoverassistant-private.h
+++ b/gtksourceview/gtksourcehoverassistant-private.h
@@ -31,9 +31,13 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GtkSourceHoverAssistant, gtk_source_hover_assistant, GTK_SOURCE, HOVER_ASSISTANT,
GtkSourceAssistant)
-GtkSourceAssistant *_gtk_source_hover_assistant_new (void);
-GtkSourceHoverDisplay *_gtk_source_hover_assistant_get_display (GtkSourceHoverAssistant *self);
-void _gtk_source_hover_assistant_set_hovered_at (GtkSourceHoverAssistant *self,
- const GdkRectangle *rect);
+GtkSourceAssistant *_gtk_source_hover_assistant_new (void);
+void _gtk_source_hover_assistant_dismiss (GtkSourceHoverAssistant *self);
+void _gtk_source_hover_assistant_display (GtkSourceHoverAssistant *self,
+ GtkSourceHoverProvider **providers,
+ guint n_providers,
+ const GtkTextIter *begin,
+ const GtkTextIter *end,
+ const GtkTextIter *location);
G_END_DECLS
diff --git a/gtksourceview/gtksourcehoverassistant.c b/gtksourceview/gtksourcehoverassistant.c
index e54cb06a..e183734d 100644
--- a/gtksourceview/gtksourcehoverassistant.c
+++ b/gtksourceview/gtksourcehoverassistant.c
@@ -23,12 +23,18 @@
#include "gtksourceassistant-private.h"
#include "gtksourcehoverassistant-private.h"
-#include "gtksourcehoverdisplay.h"
+#include "gtksourcehovercontext-private.h"
+#include "gtksourcehoverdisplay-private.h"
+#include "gtksourceview.h"
+
+#define GRACE_X 20
+#define GRACE_Y 20
struct _GtkSourceHoverAssistant
{
GtkSourceAssistant parent_instance;
- GtkSourceHoverDisplay *display;
+ GtkSourceHoverDisplay *display;
+ GCancellable *cancellable;
GdkRectangle hovered_at;
};
@@ -41,10 +47,72 @@ gtk_source_hover_assistant_get_target_location (GtkSourceAssistant *assistant,
*rect = GTK_SOURCE_HOVER_ASSISTANT (assistant)->hovered_at;
}
+static void
+gtk_source_hover_assistant_motion_cb (GtkSourceHoverAssistant *self,
+ double x,
+ double y,
+ GtkEventControllerMotion *controller)
+{
+ GdkSurface *assistant_surface;
+ GtkWidget *parent;
+ GtkRoot *root;
+ double tx, ty;
+ int width, height;
+
+ g_assert (GTK_SOURCE_IS_HOVER_ASSISTANT (self));
+ g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (controller));
+
+ if (gtk_event_controller_motion_contains_pointer (controller))
+ {
+ return;
+ }
+
+ if (!(parent = gtk_widget_get_parent (GTK_WIDGET (self))) ||
+ !(root = gtk_widget_get_root (parent)) ||
+ !(assistant_surface = gtk_native_get_surface (GTK_NATIVE (self))))
+ {
+ return;
+ }
+
+ gtk_widget_translate_coordinates (parent, GTK_WIDGET (root), x, y, &x, &y);
+ x -= gdk_popup_get_position_x (GDK_POPUP (assistant_surface));
+ y -= gdk_popup_get_position_y (GDK_POPUP (assistant_surface));
+
+ gtk_native_get_surface_transform (GTK_NATIVE (root), &tx, &ty);
+ x += tx;
+ y += ty;
+
+ width = gdk_surface_get_width (assistant_surface);
+ height = gdk_surface_get_height (assistant_surface);
+
+ if (x < -GRACE_X ||
+ x > width + GRACE_Y ||
+ y < -GRACE_Y ||
+ y > height + GRACE_Y)
+ {
+ gtk_widget_hide (GTK_WIDGET (self));
+ }
+}
+
+static void
+gtk_source_hover_assistant_dispose (GObject *object)
+{
+ GtkSourceHoverAssistant *self = (GtkSourceHoverAssistant *)object;
+
+ self->display = NULL;
+
+ g_clear_object (&self->cancellable);
+
+ G_OBJECT_CLASS (gtk_source_hover_assistant_parent_class)->dispose (object);
+}
+
static void
gtk_source_hover_assistant_class_init (GtkSourceHoverAssistantClass *klass)
{
GtkSourceAssistantClass *assistant_class = GTK_SOURCE_ASSISTANT_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gtk_source_hover_assistant_dispose;
assistant_class->get_target_location = gtk_source_hover_assistant_get_target_location;
}
@@ -52,8 +120,24 @@ gtk_source_hover_assistant_class_init (GtkSourceHoverAssistantClass *klass)
static void
gtk_source_hover_assistant_init (GtkSourceHoverAssistant *self)
{
- self->display = g_object_new (GTK_SOURCE_TYPE_HOVER_DISPLAY, NULL);
+ GtkEventController *motion;
+
+ gtk_popover_set_autohide (GTK_POPOVER (self), TRUE);
+
+ self->display = g_object_new (GTK_SOURCE_TYPE_HOVER_DISPLAY,
+ "width-request", 100,
+ "height-request", 48,
+ NULL);
_gtk_source_assistant_set_child (GTK_SOURCE_ASSISTANT (self), GTK_WIDGET (self->display));
+
+ motion = gtk_event_controller_motion_new ();
+ gtk_event_controller_set_propagation_phase (motion, GTK_PHASE_CAPTURE);
+ g_signal_connect_object (motion,
+ "motion",
+ G_CALLBACK (gtk_source_hover_assistant_motion_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ gtk_widget_add_controller (GTK_WIDGET (self), motion);
}
GtkSourceAssistant *
@@ -62,20 +146,118 @@ _gtk_source_hover_assistant_new (void)
return g_object_new (GTK_SOURCE_TYPE_HOVER_ASSISTANT, NULL);
}
+static void
+gtk_source_hover_assistant_populate_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GtkSourceHoverContext *context = (GtkSourceHoverContext *)object;
+ GtkSourceHoverAssistant *self = user_data;
+ GError *error = NULL;
+
+ g_assert (GTK_SOURCE_IS_HOVER_CONTEXT (context));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (GTK_SOURCE_IS_HOVER_ASSISTANT (self));
+
+ if (_gtk_source_hover_context_populate_finish (context, result, &error))
+ {
+ gtk_widget_show (GTK_WIDGET (self));
+ }
+
+ g_clear_object (&self);
+ g_clear_error (&error);
+}
+
void
-_gtk_source_hover_assistant_set_hovered_at (GtkSourceHoverAssistant *self,
- const GdkRectangle *hovered_at)
+_gtk_source_hover_assistant_display (GtkSourceHoverAssistant *self,
+ GtkSourceHoverProvider **providers,
+ guint n_providers,
+ const GtkTextIter *begin,
+ const GtkTextIter *end,
+ const GtkTextIter *location)
{
+ GtkSourceHoverContext *context;
+ GtkSourceView *view;
+ GdkRectangle begin_rect;
+ GdkRectangle end_rect;
+ GdkRectangle location_rect;
+
g_return_if_fail (GTK_SOURCE_IS_HOVER_ASSISTANT (self));
- g_return_if_fail (hovered_at != NULL);
+ g_return_if_fail (n_providers == 0 || providers != NULL);
+ g_return_if_fail (begin != NULL);
+ g_return_if_fail (end != NULL);
+ g_return_if_fail (location != NULL);
+
+ if (n_providers == 0)
+ {
+ if (gtk_widget_get_visible (GTK_WIDGET (self)))
+ {
+ gtk_widget_hide (GTK_WIDGET (self));
+ }
+
+ return;
+ }
+
+ if (self->cancellable != NULL)
+ {
+ g_cancellable_cancel (self->cancellable);
+ g_clear_object (&self->cancellable);
+ }
+
+ view = GTK_SOURCE_VIEW (gtk_widget_get_parent (GTK_WIDGET (self)));
+
+ gtk_text_view_get_iter_location (GTK_TEXT_VIEW (view), begin, &begin_rect);
+ gtk_text_view_get_iter_location (GTK_TEXT_VIEW (view), end, &end_rect);
+ gtk_text_view_get_iter_location (GTK_TEXT_VIEW (view), location, &location_rect);
- self->hovered_at = *hovered_at;
+ gdk_rectangle_union (&begin_rect, &end_rect, &location_rect);
+
+ gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (view),
+ GTK_TEXT_WINDOW_WIDGET,
+ location_rect.x,
+ location_rect.y,
+ &location_rect.x,
+ &location_rect.y);
+
+ if (gtk_text_iter_equal (begin, end) &&
+ gtk_text_iter_starts_line (begin))
+ {
+ location_rect.width = 1;
+ gtk_popover_set_position (GTK_POPOVER (self), GTK_POS_RIGHT);
+ }
+ else
+ {
+ gtk_popover_set_position (GTK_POPOVER (self), GTK_POS_TOP);
+ }
+
+ self->hovered_at = location_rect;
+
+ context = _gtk_source_hover_context_new (view, begin, end, location);
+
+ for (guint i = 0; i < n_providers; i++)
+ {
+ _gtk_source_hover_context_add_provider (context, providers[i]);
+ }
+
+ self->cancellable = g_cancellable_new ();
+
+ _gtk_source_hover_display_clear (self->display);
+
+ _gtk_source_hover_context_populate_async (context,
+ self->display,
+ self->cancellable,
+ gtk_source_hover_assistant_populate_cb,
+ g_object_ref (self));
+
+ g_object_unref (context);
}
-GtkSourceHoverDisplay *
-_gtk_source_hover_assistant_get_display (GtkSourceHoverAssistant *self)
+void
+_gtk_source_hover_assistant_dismiss (GtkSourceHoverAssistant *self)
{
- g_return_val_if_fail (GTK_SOURCE_IS_HOVER_ASSISTANT (self), NULL);
+ g_return_if_fail (GTK_SOURCE_IS_HOVER_ASSISTANT (self));
- return self->display;
+ g_cancellable_cancel (self->cancellable);
+ gtk_widget_hide (GTK_WIDGET (self));
+ _gtk_source_hover_display_clear (self->display);
}
diff --git a/gtksourceview/gtksourcehovercontext.c b/gtksourceview/gtksourcehovercontext.c
index 97d5990b..e00d6e12 100644
--- a/gtksourceview/gtksourcehovercontext.c
+++ b/gtksourceview/gtksourcehovercontext.c
@@ -152,11 +152,27 @@ gtk_source_hover_context_get_buffer (GtkSourceHoverContext *self)
return GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->view)));
}
+static GtkTextMark *
+create_mark (GtkSourceHoverContext *self,
+ const GtkTextIter *iter,
+ gboolean left_gravity)
+{
+ GtkTextMark *mark;
+ GtkTextBuffer *buffer;
+
+ g_assert (GTK_SOURCE_IS_HOVER_CONTEXT (self));
+
+ buffer = GTK_TEXT_BUFFER (self->buffer);
+ mark = gtk_text_buffer_create_mark (buffer, NULL, iter, left_gravity);
+
+ return g_object_ref (mark);
+}
+
GtkSourceHoverContext *
_gtk_source_hover_context_new (GtkSourceView *view,
- const GtkTextIter *begin,
- const GtkTextIter *end,
- const GtkTextIter *location)
+ const GtkTextIter *begin,
+ const GtkTextIter *end,
+ const GtkTextIter *location)
{
GtkSourceHoverContext *self;
GtkSourceBuffer *buffer;
@@ -167,11 +183,15 @@ _gtk_source_hover_context_new (GtkSourceView *view,
g_return_val_if_fail (location != NULL, NULL);
buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
- self = g_object_new (GTK_SOURCE_TYPE_VIEW, NULL);
+ self = g_object_new (GTK_SOURCE_TYPE_HOVER_CONTEXT, NULL);
g_set_weak_pointer (&self->view, view);
g_set_weak_pointer (&self->buffer, buffer);
+ self->begin = create_mark (self, begin, TRUE);
+ self->end = create_mark (self, end, FALSE);
+ self->location = create_mark (self, location, FALSE);
+
return self;
}
@@ -231,7 +251,14 @@ _gtk_source_hover_context_populate_async (GtkSourceHoverContext *self,
g_task_set_source_tag (task, _gtk_source_hover_context_populate_async);
g_task_set_task_data (task, state, g_free);
- if (g_task_return_error_if_cancelled (task))
+ if (self->view == NULL || self->buffer == NULL)
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ "Cannot populate, view destroyed");
+ }
+ else if (g_task_return_error_if_cancelled (task))
{
/* Do nothing */
}
diff --git a/gtksourceview/gtksourcehoverdisplay-private.h b/gtksourceview/gtksourcehoverdisplay-private.h
new file mode 100644
index 00000000..3ee9fd08
--- /dev/null
+++ b/gtksourceview/gtksourcehoverdisplay-private.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2021 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 "gtksourcehoverdisplay.h"
+
+G_BEGIN_DECLS
+
+void _gtk_source_hover_display_clear (GtkSourceHoverDisplay *self);
+
+G_END_DECLS
diff --git a/gtksourceview/gtksourcehoverdisplay.c b/gtksourceview/gtksourcehoverdisplay.c
index c48ac56e..37201911 100644
--- a/gtksourceview/gtksourcehoverdisplay.c
+++ b/gtksourceview/gtksourcehoverdisplay.c
@@ -21,7 +21,7 @@
#include "config.h"
-#include "gtksourcehoverdisplay.h"
+#include "gtksourcehoverdisplay-private.h"
struct _GtkSourceHoverDisplay
{
@@ -56,7 +56,9 @@ gtk_source_hover_display_class_init (GtkSourceHoverDisplayClass *klass)
static void
gtk_source_hover_display_init (GtkSourceHoverDisplay *self)
{
- self->vbox = g_object_new (GTK_TYPE_BOX, NULL);
+ self->vbox = g_object_new (GTK_TYPE_BOX,
+ "orientation", GTK_ORIENTATION_VERTICAL,
+ NULL);
gtk_widget_set_parent (GTK_WIDGET (self->vbox), GTK_WIDGET (self));
}
@@ -66,6 +68,8 @@ gtk_source_hover_display_append (GtkSourceHoverDisplay *self,
{
g_return_if_fail (GTK_SOURCE_IS_HOVER_DISPLAY (self));
g_return_if_fail (GTK_IS_WIDGET (child));
+
+ gtk_box_append (self->vbox, child);
}
void
@@ -74,6 +78,8 @@ gtk_source_hover_display_prepend (GtkSourceHoverDisplay *self,
{
g_return_if_fail (GTK_SOURCE_IS_HOVER_DISPLAY (self));
g_return_if_fail (GTK_IS_WIDGET (child));
+
+ gtk_box_prepend (self->vbox, child);
}
void
@@ -89,6 +95,10 @@ gtk_source_hover_display_insert_after (GtkSourceHoverDisplay *self,
{
gtk_source_hover_display_append (self, child);
}
+ else
+ {
+ gtk_box_insert_child_after (self->vbox, child, sibling);
+ }
}
void
@@ -98,4 +108,19 @@ gtk_source_hover_display_remove (GtkSourceHoverDisplay *self,
g_return_if_fail (GTK_SOURCE_IS_HOVER_DISPLAY (self));
g_return_if_fail (GTK_IS_WIDGET (child));
g_return_if_fail (gtk_widget_get_parent (child) == (GtkWidget *)self->vbox);
+
+ gtk_box_remove (self->vbox, child);
+}
+
+void
+_gtk_source_hover_display_clear (GtkSourceHoverDisplay *self)
+{
+ GtkWidget *child;
+
+ g_return_if_fail (GTK_SOURCE_IS_HOVER_DISPLAY (self));
+
+ while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->vbox))))
+ {
+ gtk_box_remove (self->vbox, child);
+ }
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]