[gthumb/gthumb-3-4] fixed possible crash when switch from the image viewer to another viewer



commit 686106944410fa6b536c5dd28a07b58c9cd03bfb
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Mon Apr 3 19:21:10 2017 +0200

    fixed possible crash when switch from the image viewer to another viewer
    
    check if the viewer is still available after a callback

 extensions/image_viewer/gth-image-viewer-page.c |  102 ++++++++++++++------
 gthumb/gth-image-dragger.c                      |   16 ++-
 gthumb/gth-image-overview.c                     |  117 ++++++++++++++++-------
 3 files changed, 162 insertions(+), 73 deletions(-)
---
diff --git a/extensions/image_viewer/gth-image-viewer-page.c b/extensions/image_viewer/gth-image-viewer-page.c
index eb42d57..94a9d38 100644
--- a/extensions/image_viewer/gth-image-viewer-page.c
+++ b/extensions/image_viewer/gth-image-viewer-page.c
@@ -196,6 +196,44 @@ _gth_image_preloader_get_requested_size_for_current_image (GthImageViewerPage *s
 
 
 static void
+_gth_image_viewer_page_load_with_preloader (GthImageViewerPage  *self,
+                                           GthFileData         *file_data,
+                                           int                  requested_size,
+                                           GCancellable        *cancellable,
+                                           GAsyncReadyCallback  callback,
+                                           gpointer             user_data)
+{
+       if (self->priv->apply_icc_profile)
+               gth_image_preloader_set_out_profile (self->priv->preloader, gth_browser_get_screen_profile 
(self->priv->browser));
+       else
+               gth_image_preloader_set_out_profile (self->priv->preloader, NULL);
+
+       g_object_ref (self);
+       gth_image_preloader_load (self->priv->preloader,
+                                 file_data,
+                                 requested_size,
+                                 cancellable,
+                                 callback,
+                                 user_data,
+                                 N_FORWARD_PRELOADERS + N_BACKWARD_PRELOADERS,
+                                 self->priv->next_file_data[0],
+                                 self->priv->next_file_data[1],
+                                 self->priv->prev_file_data[0],
+                                 self->priv->prev_file_data[1]);
+}
+
+
+static gboolean
+_gth_image_viewer_page_load_with_preloader_finish (GthImageViewerPage  *self)
+{
+       gboolean active = self->priv->active;
+       g_object_unref (self);
+
+       return active;
+}
+
+
+static void
 different_quality_ready_cb (GObject            *source_object,
                            GAsyncResult        *result,
                            gpointer             user_data)
@@ -212,6 +250,9 @@ different_quality_ready_cb (GObject         *source_object,
        int                 w1, h1, w2, h2;
        gboolean            got_better_quality;
 
+       if (! _gth_image_viewer_page_load_with_preloader_finish (self))
+               return;
+
        if (! gth_image_preloader_load_finish (GTH_IMAGE_PRELOADER (source_object),
                                               result,
                                               &requested,
@@ -292,33 +333,6 @@ _g_mime_type_can_load_different_quality (const char *mime_type)
 }
 
 
-static void
-_gth_image_viewer_page_load_with_preloader (GthImageViewerPage  *self,
-                                           GthFileData         *file_data,
-                                           int                  requested_size,
-                                           GCancellable        *cancellable,
-                                           GAsyncReadyCallback  callback,
-                                           gpointer             user_data)
-{
-       if (self->priv->apply_icc_profile)
-               gth_image_preloader_set_out_profile (self->priv->preloader, gth_browser_get_screen_profile 
(self->priv->browser));
-       else
-               gth_image_preloader_set_out_profile (self->priv->preloader, NULL);
-
-       gth_image_preloader_load (self->priv->preloader,
-                                 file_data,
-                                 requested_size,
-                                 cancellable,
-                                 callback,
-                                 user_data,
-                                 N_FORWARD_PRELOADERS + N_BACKWARD_PRELOADERS,
-                                 self->priv->next_file_data[0],
-                                 self->priv->next_file_data[1],
-                                 self->priv->prev_file_data[0],
-                                 self->priv->prev_file_data[1]);
-}
-
-
 static gboolean
 update_quality_cb (gpointer user_data)
 {
@@ -329,6 +343,12 @@ update_quality_cb (gpointer user_data)
                self->priv->update_quality_id = 0;
        }
 
+       if (! self->priv->active)
+               return FALSE;
+
+       if (self->priv->viewer == NULL)
+               return FALSE;
+
        if (self->priv->loading_image)
                return FALSE;
 
@@ -565,7 +585,7 @@ viewer_realize_cb (GtkWidget *widget,
        GthImageViewerPage *self = user_data;
        GtkClipboard       *clipboard;
 
-       clipboard = gtk_widget_get_clipboard (self->priv->viewer, GDK_SELECTION_CLIPBOARD);
+       clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
        g_signal_connect (clipboard,
                          "owner_change",
                          G_CALLBACK (clipboard_owner_change_cb),
@@ -580,7 +600,7 @@ viewer_unrealize_cb (GtkWidget *widget,
        GthImageViewerPage *self = user_data;
        GtkClipboard       *clipboard;
 
-       clipboard = gtk_widget_get_clipboard (self->priv->viewer, GDK_SELECTION_CLIPBOARD);
+       clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
        g_signal_handlers_disconnect_by_func (clipboard,
                                              G_CALLBACK (clipboard_owner_change_cb),
                                              self);
@@ -653,6 +673,9 @@ pref_zoom_quality_changed (GSettings *settings,
 {
        GthImageViewerPage *self = user_data;
 
+       if (! self->priv->active || (self->priv->viewer == NULL))
+               return;
+
        gth_image_viewer_set_zoom_quality (GTH_IMAGE_VIEWER (self->priv->viewer),
                                           g_settings_get_enum (self->priv->settings, 
PREF_IMAGE_VIEWER_ZOOM_QUALITY));
        gtk_widget_queue_draw (self->priv->viewer);
@@ -666,6 +689,9 @@ pref_zoom_change_changed (GSettings *settings,
 {
        GthImageViewerPage *self = user_data;
 
+       if (! self->priv->active || (self->priv->viewer == NULL))
+               return;
+
        gth_image_viewer_set_zoom_change (GTH_IMAGE_VIEWER (self->priv->viewer),
                                          g_settings_get_enum (self->priv->settings, 
PREF_IMAGE_VIEWER_ZOOM_CHANGE));
        gtk_widget_queue_draw (self->priv->viewer);
@@ -679,6 +705,9 @@ pref_reset_scrollbars_changed (GSettings *settings,
 {
        GthImageViewerPage *self = user_data;
 
+       if (! self->priv->active || (self->priv->viewer == NULL))
+               return;
+
        gth_image_viewer_set_reset_scrollbars (GTH_IMAGE_VIEWER (self->priv->viewer),
                                               g_settings_get_boolean (self->priv->settings, 
PREF_IMAGE_VIEWER_RESET_SCROLLBARS));
 }
@@ -886,6 +915,7 @@ gth_image_viewer_page_real_activate (GthViewerPage *base,
        self->priv->preloader = gth_browser_get_image_preloader (browser);
 
        self->priv->viewer = gth_image_viewer_new ();
+       g_object_add_weak_pointer (G_OBJECT (self->priv->viewer), &self->priv->viewer);
        gtk_widget_add_events (self->priv->viewer, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
        gth_image_viewer_page_reset_viewer_tool (self);
        gtk_widget_show (self->priv->viewer);
@@ -1043,6 +1073,8 @@ preloader_load_ready_cb (GObject  *source_object,
        GError             *error = NULL;
 
        self->priv->loading_image = FALSE;
+       if (! _gth_image_viewer_page_load_with_preloader_finish (self))
+               return;
 
        if (! gth_image_preloader_load_finish (GTH_IMAGE_PRELOADER (source_object),
                                               result,
@@ -1938,6 +1970,7 @@ get_original_data_free (OriginalImageData *data)
        if (data == NULL)
                return;
 
+       _g_object_unref (data->viewer_page);
        _g_object_unref (data->cancellable);
        _g_object_unref (data->result);
        g_free (data);
@@ -1950,8 +1983,13 @@ original_image_ready_cb (GObject *source_object,
                         gpointer        user_data)
 {
        OriginalImageData *data = user_data;
-       GthImage        *image = NULL;
-       GError          *error = NULL;
+       GthImage          *image = NULL;
+       GError            *error = NULL;
+
+       if (! _gth_image_viewer_page_load_with_preloader_finish (data->viewer_page)) {
+               get_original_data_free (data);
+               return;
+       }
 
        if (! gth_image_preloader_load_finish (GTH_IMAGE_PRELOADER (source_object),
                                               result,
@@ -1983,7 +2021,7 @@ gth_image_viewer_page_get_original (GthImageViewerPage     *self,
        OriginalImageData *data;
 
        data = get_original_data_new ();
-       data->viewer_page = self;
+       data->viewer_page = g_object_ref (self);
        data->result = g_simple_async_result_new (G_OBJECT (self),
                                                  ready_callback,
                                                  user_data,
diff --git a/gthumb/gth-image-dragger.c b/gthumb/gth-image-dragger.c
index 304d4dd..8e7e291 100644
--- a/gthumb/gth-image-dragger.c
+++ b/gthumb/gth-image-dragger.c
@@ -166,7 +166,9 @@ gth_image_dragger_set_viewer (GthImageViewerTool *base,
                              GthImageViewer     *image_viewer)
 {
        GthImageDragger *self = GTH_IMAGE_DRAGGER (base);
+
        self->priv->viewer = image_viewer;
+       g_object_add_weak_pointer (G_OBJECT (image_viewer), &self->priv->viewer);
        if (self->priv->show_frame)
                gth_image_viewer_show_frame (self->priv->viewer, FRAME_BORDER);
 }
@@ -180,6 +182,7 @@ gth_image_dragger_unset_viewer (GthImageViewerTool *base,
 
        if ((self->priv->viewer != NULL) && self->priv->show_frame)
                gth_image_viewer_hide_frame (self->priv->viewer);
+       g_object_remove_weak_pointer (G_OBJECT (image_viewer), &self->priv->viewer);
        self->priv->viewer = NULL;
 }
 
@@ -400,6 +403,7 @@ scale_data_free (ScaleData *scale_data)
                return;
        cairo_surface_destroy (scale_data->image);
        cairo_surface_destroy (scale_data->scaled);
+       g_object_unref (scale_data->dragger);
        g_free (scale_data);
 }
 
@@ -430,10 +434,12 @@ _gth_image_dragger_scale_after (GthAsyncTask *task,
        if (error == NULL) {
                GthImageDragger *dragger = scale_data->dragger;
 
-               _cairo_clear_surface (&dragger->priv->scaled);
-               dragger->priv->scaled = cairo_surface_reference (scale_data->scaled);
-               if (dragger->priv->viewer != NULL)
-                       gtk_widget_queue_draw (GTK_WIDGET (dragger->priv->viewer));
+               if ((scale_data->scaled != NULL) && (dragger->priv->viewer != NULL)) {
+                       _cairo_clear_surface (&dragger->priv->scaled);
+                       dragger->priv->scaled = cairo_surface_reference (scale_data->scaled);
+                       if (dragger->priv->viewer != NULL)
+                               gtk_widget_queue_draw (GTK_WIDGET (dragger->priv->viewer));
+               }
 
                if (GTH_TASK (task) == dragger->priv->scale_task)
                        dragger->priv->scale_task = NULL;
@@ -456,7 +462,7 @@ _gth_image_dragger_create_scaled_high_quality (GthImageDragger *self,
                gth_task_cancel (self->priv->scale_task);
 
        scale_data = g_new0 (ScaleData, 1);
-       scale_data->dragger = self;
+       scale_data->dragger = g_object_ref (self);
        scale_data->image = cairo_surface_reference (image);
        scale_data->new_width = new_width;
        scale_data->new_height = new_height;
diff --git a/gthumb/gth-image-overview.c b/gthumb/gth-image-overview.c
index 5803002..b91fc6b 100644
--- a/gthumb/gth-image-overview.c
+++ b/gthumb/gth-image-overview.c
@@ -23,6 +23,7 @@
 #include <math.h>
 #include <gdk/gdkkeysyms.h>
 #include "cairo-scale.h"
+#include "cairo-utils.h"
 #include "gth-image-overview.h"
 #include "gth-image-utils.h"
 #include "gth-image-viewer.h"
@@ -107,6 +108,11 @@ _gth_image_overviewer_disconnect_from_viewer (GthImageOverview *self)
                        g_signal_handler_disconnect (self->priv->viewer->hadj, self->priv->hadj_changed_id);
                self->priv->hadj_changed_id = 0;
        }
+
+       if (self->priv->viewer != NULL) {
+               g_object_remove_weak_pointer (G_OBJECT (self->priv->viewer), &self->priv->viewer);
+               self->priv->viewer = NULL;
+       }
 }
 
 
@@ -128,33 +134,69 @@ gth_image_overview_finalize (GObject *object)
 }
 
 
-static void
-_gth_image_overview_update_zoom_info (GthImageOverview *self)
+static gboolean
+_gth_image_overview_calc_preview_size (GthImageOverview *self,
+                                      int              *out_width,
+                                      int              *out_height,
+                                      double           *out_zoom_factor)
+{
+       int    width, height;
+       double zoom;
+       int    preview_width, preview_height;
+
+       if (self->priv->viewer == NULL)
+               return FALSE;
+
+       gth_image_viewer_get_original_size (self->priv->viewer, &width, &height);
+       zoom = gth_image_viewer_get_zoom (self->priv->viewer);
+       width = width * zoom;
+       height = height * zoom;
+
+       preview_width = width;
+       preview_height = height;
+       scale_keeping_ratio (&preview_width, &preview_height, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE, TRUE);
+
+       if (out_width) *out_width = preview_width;
+       if (out_height) *out_height = preview_height;
+       if (out_zoom_factor) *out_zoom_factor = MIN ((double) (preview_width) / width,
+                                                    (double) (preview_height) / height);
+
+       return TRUE;
+}
+
+
+static double
+_gth_image_overview_calc_quality_zoom (GthImageOverview *self)
 {
        cairo_surface_t *image;
        int              width, height;
-       double           zoom;
+
+       if (self->priv->viewer == NULL)
+               return 0.0;
 
        image = gth_image_viewer_get_current_image (self->priv->viewer);
        if (image == NULL)
-               return;
+               return 0.0;
+
+       if (cairo_image_surface_get_width (image) == 0)
+               return 0.0;
 
        gth_image_viewer_get_original_size (self->priv->viewer, &width, &height);
-       self->priv->quality_zoom = (double) width / cairo_image_surface_get_width (image);
-       zoom = gth_image_viewer_get_zoom (self->priv->viewer);
-       width = width * zoom;
-       height = height * zoom;
+       return (double) width / cairo_image_surface_get_width (image);
+}
 
-       self->priv->preview_width = width;
-       self->priv->preview_height = height;
-       scale_keeping_ratio (&self->priv->preview_width,
-                            &self->priv->preview_height,
-                            MAX_IMAGE_SIZE,
-                            MAX_IMAGE_SIZE,
-                            TRUE);
 
-       self->priv->zoom_factor = MIN ((double) (self->priv->preview_width) / width,
-                                      (double) (self->priv->preview_height) / height);
+static void
+_gth_image_overview_update_zoom_info (GthImageOverview *self)
+{
+       self->priv->quality_zoom = _gth_image_overview_calc_quality_zoom (self);
+       if (self->priv->quality_zoom == 0.0)
+               return;
+
+       _gth_image_overview_calc_preview_size (self,
+                                              &self->priv->preview_width,
+                                              &self->priv->preview_height,
+                                              &self->priv->zoom_factor);
 
        self->priv->preview_area.x = IMAGE_BORDER;
        self->priv->preview_area.y = IMAGE_BORDER;
@@ -168,7 +210,10 @@ _gth_image_overview_update_zoom_info (GthImageOverview *self)
 
 typedef struct {
        GthImageOverview *overview;
+       cairo_surface_t  *image;
        cairo_surface_t  *scaled;
+       int               width;
+       int               height;
 } ScaleData;
 
 
@@ -178,6 +223,7 @@ scale_data_free (ScaleData *scale_data)
        if (scale_data == NULL)
                return;
        cairo_surface_destroy (scale_data->scaled);
+       cairo_surface_destroy (scale_data->image);
        g_object_unref (scale_data->overview);
        g_free (scale_data);
 }
@@ -187,18 +233,13 @@ static gpointer
 _gth_image_overview_scale_exec (GthAsyncTask *task,
                                gpointer      user_data)
 {
-       ScaleData        *scale_data = user_data;
-       GthImageOverview *overview = scale_data->overview;
-       cairo_surface_t  *image;
+       ScaleData *scale_data = user_data;
 
-       _gth_image_overview_update_zoom_info (overview);
-       image = gth_image_viewer_get_current_image (scale_data->overview->priv->viewer);
-       if (image != NULL)
-               scale_data->scaled = _cairo_image_surface_scale (image,
-                                                                overview->priv->preview_area.width,
-                                                                overview->priv->preview_area.height,
-                                                                SCALE_FILTER_GOOD,
-                                                                task);
+       scale_data->scaled = _cairo_image_surface_scale (scale_data->image,
+                                                        scale_data->width,
+                                                        scale_data->height,
+                                                        SCALE_FILTER_GOOD,
+                                                        task);
 
        return NULL;
 }
@@ -214,10 +255,13 @@ _gth_image_overview_scale_after (GthAsyncTask *task,
        if (error == NULL) {
                GthImageOverview *overview = scale_data->overview;
 
-               _cairo_clear_surface (&overview->priv->preview);
-               if (scale_data->scaled != NULL)
-                       overview->priv->preview = cairo_surface_reference (scale_data->scaled);
-               gtk_widget_queue_resize (GTK_WIDGET (overview));
+               if (overview->priv->viewer != NULL) {
+                       _gth_image_overview_update_zoom_info (overview);
+                       _cairo_clear_surface (&overview->priv->preview);
+                       if (scale_data->scaled != NULL)
+                               overview->priv->preview = cairo_surface_reference (scale_data->scaled);
+                       gtk_widget_queue_resize (GTK_WIDGET (overview));
+               }
 
                if (GTH_TASK (task) == overview->priv->scale_task)
                        overview->priv->scale_task = NULL;
@@ -261,6 +305,11 @@ _gth_image_overview_update_preview (GthImageOverview *self)
 
        scale_data = g_new0 (ScaleData, 1);
        scale_data->overview = g_object_ref (self);
+       scale_data->image = cairo_surface_reference (image);
+       _gth_image_overview_calc_preview_size (self,
+                                              &scale_data->width,
+                                              &scale_data->height,
+                                              NULL);
 
        self->priv->scale_task = gth_async_task_new (NULL,
                                                     _gth_image_overview_scale_exec,
@@ -347,10 +396,6 @@ _gth_image_overview_set_viewer (GthImageOverview *self,
                return;
 
        _gth_image_overviewer_disconnect_from_viewer (self);
-       if (self->priv->viewer != NULL) {
-               g_object_remove_weak_pointer (G_OBJECT (viewer), (gpointer*) &self->priv->viewer);
-               self->priv->viewer = NULL;
-       }
 
        if (viewer == NULL)
                return;


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