[goffice] Optimize GtkWidget embedding in the canvas. See #465.



commit 40e1716493b484c573f49945a60be071a6c875ba
Author: Jean Brefort <jean brefort normalesup org>
Date:   Mon Jun 1 17:49:49 2020 +0200

    Optimize GtkWidget embedding in the canvas. See #465.

 ChangeLog                   |   8 +++
 NEWS                        |   1 +
 goffice/canvas/goc-canvas.c |   3 ++
 goffice/canvas/goc-widget.c | 122 ++++++++++++++++++++++++++------------------
 4 files changed, 83 insertions(+), 51 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index e8a1b528..55456034 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2020-06-01  Jean Brefort  <jean brefort normalesup org>
+
+       * goffice/canvas/goc-canvas.c (size_changed_cb): optimize GtkWidget
+       embedding in the canvas. See #465.
+       * goffice/canvas/goc-widget.c (goc_widget_connect_signals),
+       (goc_widget_notify_scrolled), (cb_canvas_changed),
+       (goc_widget_set_widget), (goc_widget_draw):
+
 2020-05-27  Jean Brefort  <jean brefort normalesup org>
 
        * plugins/reg_logfit/gog-logfit.c (gog_log_fit_curve_update): don't emit a
diff --git a/NEWS b/NEWS
index 01a76d89..1812d90f 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ Jean:
        * Avoid serializing empty graph data. [#46]
        * Clip data labels in XY plots. [#47]
        * Don't emit a critical for invalid series in Logarithmic fit. [#49]
+       * Optimize GtkWidget embedding in the canvas. See #465.
 
 --------------------------------------------------------------------------
 goffice 0.10.47:
diff --git a/goffice/canvas/goc-canvas.c b/goffice/canvas/goc-canvas.c
index eac4c93b..31443b00 100644
--- a/goffice/canvas/goc-canvas.c
+++ b/goffice/canvas/goc-canvas.c
@@ -271,8 +271,11 @@ leave_notify_cb (GocCanvas *canvas, GdkEventCrossing* event, G_GNUC_UNUSED gpoin
 static void
 size_changed_cb (GocCanvas *canvas, GtkAllocation *alloc, G_GNUC_UNUSED gpointer data)
 {
+       GocItemClass *klass = GOC_ITEM_GET_CLASS (canvas->root);
        canvas->width = alloc->width;
        canvas->height = alloc->height;
+       /* we need to call notify_scroll() to show or hide widgets if necessary */
+       klass->notify_scrolled (GOC_ITEM (canvas->root));
 }
 
 static void
diff --git a/goffice/canvas/goc-widget.c b/goffice/canvas/goc-widget.c
index 9edb865a..009b6925 100644
--- a/goffice/canvas/goc-widget.c
+++ b/goffice/canvas/goc-widget.c
@@ -503,6 +503,33 @@ goc_widget_update_bounds (GocItem *item)
        item->y1 = widget->y + widget->h;
 }
 
+static void
+goc_widget_connect_signals (GtkWidget *widget, GocWidget *item,
+                           gboolean do_connect)
+{
+               if (GTK_IS_CONTAINER (widget)) {
+                       GList *children = gtk_container_get_children (GTK_CONTAINER (widget));
+                       GList *ptr;
+                       for (ptr = children; ptr; ptr = ptr->next) {
+                               GtkWidget *child = ptr->data;
+                               goc_widget_connect_signals (child, item, do_connect);
+                       }
+                       g_list_free (children);
+               }
+
+               if (do_connect) {
+                       g_signal_connect (widget, "enter-notify-event",
+                                         G_CALLBACK (enter_notify_cb), item);
+                       g_signal_connect (widget, "button-press-event",
+                                         G_CALLBACK (button_press_cb), item);
+               } else {
+                       g_signal_handlers_disconnect_by_func
+                               (widget, G_CALLBACK (enter_notify_cb), item);
+                       g_signal_handlers_disconnect_by_func
+                               (widget, G_CALLBACK (button_press_cb), item);
+               }
+}
+
 static void
 goc_widget_notify_scrolled (GocItem *item)
 {
@@ -546,9 +573,6 @@ goc_widget_notify_scrolled (GocItem *item)
        }
        y0 = (y0 - item->canvas->scroll_y1) * item->canvas->pixels_per_unit;
        y1 = (y1 - item->canvas->scroll_y1) * item->canvas->pixels_per_unit;
-       goc_offscreen_box_set_scale (GOC_OFFSCREEN_BOX (widget->ofbox),
-                                    item->canvas->pixels_per_unit * widget->scale);
-       gtk_widget_set_size_request (widget->ofbox, go_fake_floor (x1 - x0), go_fake_floor (y1 - y0));
        /* ensure we don't wrap throught he infinite */
        if (x0 < G_MININT)
                x0 = G_MININT;
@@ -558,58 +582,62 @@ goc_widget_notify_scrolled (GocItem *item)
                y0 = G_MININT;
        else if (y1 > G_MAXINT)
                y0 -= y1 - G_MAXINT;
-       gtk_layout_move (GTK_LAYOUT (item->canvas), widget->ofbox, x0, y0);
+       if (x1 >= 0 && x0 <= item->canvas->width && y1 >= 0 && y0 <= item->canvas->height) {
+               if (widget->ofbox) {
+                       goc_offscreen_box_set_scale (GOC_OFFSCREEN_BOX (widget->ofbox),
+                                                            item->canvas->pixels_per_unit * widget->scale);
+                       gtk_widget_set_size_request (widget->ofbox, go_fake_floor (x1 - x0), go_fake_floor 
(y1 - y0));
+                       gtk_layout_move (GTK_LAYOUT (item->canvas), widget->ofbox, x0, y0);
+               } else {
+                       gtk_widget_show (widget->widget);
+                       widget->ofbox = GTK_WIDGET (g_object_new (GOC_TYPE_OFFSCREEN_BOX, NULL));
+                       gtk_container_add (GTK_CONTAINER (widget->ofbox), widget->widget);
+                       gtk_widget_show (widget->ofbox);
+                       g_object_ref (widget->ofbox);
+                       goc_offscreen_box_set_scale (GOC_OFFSCREEN_BOX (widget->ofbox),
+                                                            item->canvas->pixels_per_unit * widget->scale);
+                       gtk_widget_set_size_request (widget->ofbox, go_fake_floor (x1 - x0), go_fake_floor 
(y1 - y0));
+                       gtk_layout_put (GTK_LAYOUT (item->canvas),
+                                       widget->ofbox, x0, y0);
+                       /* we need to propagate some signals to the parent item */
+                       goc_widget_connect_signals (widget->widget, widget, TRUE);
+               }
+       } else if (widget->ofbox) {
+               GtkWidget *parent = gtk_widget_get_parent (widget->ofbox);
+               if (parent) {
+                       gtk_container_remove (GTK_CONTAINER (widget->ofbox), widget->widget);
+                       goc_widget_connect_signals (widget->widget, widget, FALSE);
+                       gtk_widget_hide (widget->widget);
+                       gtk_container_remove (GTK_CONTAINER (parent), widget->ofbox);
+               }
+               g_object_unref (widget->ofbox);
+               widget->ofbox = NULL;
+       }
 }
 
 static void
 cb_canvas_changed (GocWidget *item, G_GNUC_UNUSED GParamSpec *pspec,
                   G_GNUC_UNUSED gpointer user)
 {
-       GtkWidget *parent, *w = item->ofbox;
+       GtkWidget *parent, *box = item->ofbox, *w = item->widget;
        GocItem *gitem = (GocItem *)item;
 
-       if (!w || !GTK_IS_WIDGET (w))
+       if (!box || !GTK_IS_WIDGET (box))
                return;
 
-       parent = gtk_widget_get_parent (w);
+       parent = gtk_widget_get_parent (box);
        if (parent == (GtkWidget *)gitem->canvas)
                return;
 
-       g_object_ref (w);
-       if (parent)
-               gtk_container_remove (GTK_CONTAINER (parent), w);
-       if (gitem->canvas)
-               gtk_layout_put (GTK_LAYOUT (gitem->canvas), w,
-                               item->x, item->y);
+       if (parent) {
+               gtk_container_remove (GTK_CONTAINER (box), w);
+               goc_widget_connect_signals (w, item, FALSE);
+               gtk_widget_hide (w);
+               gtk_container_remove (GTK_CONTAINER (parent), box);
+               g_object_unref (box);
+               item->ofbox = NULL;
+       }
        goc_widget_notify_scrolled (GOC_ITEM (item));
-       g_object_unref (w);
-}
-
-static void
-goc_widget_connect_signals (GtkWidget *widget, GocWidget *item,
-                           gboolean do_connect)
-{
-               if (GTK_IS_CONTAINER (widget)) {
-                       GList *children = gtk_container_get_children (GTK_CONTAINER (widget));
-                       GList *ptr;
-                       for (ptr = children; ptr; ptr = ptr->next) {
-                               GtkWidget *child = ptr->data;
-                               goc_widget_connect_signals (child, item, do_connect);
-                       }
-                       g_list_free (children);
-               }
-
-               if (do_connect) {
-                       g_signal_connect (widget, "enter-notify-event",
-                                         G_CALLBACK (enter_notify_cb), item);
-                       g_signal_connect (widget, "button-press-event",
-                                         G_CALLBACK (button_press_cb), item);
-               } else {
-                       g_signal_handlers_disconnect_by_func
-                               (widget, G_CALLBACK (enter_notify_cb), item);
-                       g_signal_handlers_disconnect_by_func
-                               (widget, G_CALLBACK (button_press_cb), item);
-               }
 }
 
 static void
@@ -636,17 +664,7 @@ goc_widget_set_widget (GocWidget *item, GtkWidget *widget)
 
        if (widget) {
                g_object_ref (widget);
-               gtk_widget_show (widget);
-               item->ofbox = GTK_WIDGET (g_object_new (GOC_TYPE_OFFSCREEN_BOX, NULL));
-               gtk_container_add (GTK_CONTAINER (item->ofbox), widget);
-               gtk_widget_show (item->ofbox);
-               g_object_ref (item->ofbox);
-               if (GOC_ITEM (item)->canvas)
-                       gtk_layout_put (GTK_LAYOUT (GOC_ITEM (item)->canvas),
-                                       item->ofbox, item->x, item->y);
                goc_widget_notify_scrolled (GOC_ITEM (item));
-               /* we need to propagate some signals to the parent item */
-               goc_widget_connect_signals (widget, item, TRUE);
        }
 }
 
@@ -749,6 +767,8 @@ goc_widget_draw (GocItem const *item, cairo_t *cr)
        GocWidget *widget = GOC_WIDGET (item);
        GocOffscreenBox *ofbox = GOC_OFFSCREEN_BOX (widget->ofbox);
        int x, y;
+       if (!widget->ofbox)
+               return; /* the widget has no allocation */
        gtk_container_child_get (GTK_CONTAINER (item->canvas), widget->ofbox,
                                 "x", &x, "y", &y, NULL);
        cairo_save (cr);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]