Fixed various memory leaks in GUI
authorJohn Darrington <john@darrington.wattle.id.au>
Sun, 3 Feb 2008 12:09:24 +0000 (12:09 +0000)
committerJohn Darrington <john@darrington.wattle.id.au>
Sun, 3 Feb 2008 12:09:24 +0000 (12:09 +0000)
lib/gtksheet/gtksheet.c
src/ui/gui/ChangeLog
src/ui/gui/compute-dialog.c
src/ui/gui/data-editor.c
src/ui/gui/psppire-case-file.c
src/ui/gui/psppire-case-file.h
src/ui/gui/psppire-data-store.c
src/ui/gui/psppire-data-store.h
src/ui/gui/psppire-dialog.c

index 409c2369ea8337c8ac5dcea752764a4269704702..2e5351191490e54a0d2f36dc14056f9055d06c69 100644 (file)
@@ -136,10 +136,13 @@ guint DEFAULT_ROW_HEIGHT (GtkWidget *widget)
        pango_context_get_metrics (context,
                                   widget->style->font_desc,
                                   pango_context_get_language (context));
+
       guint val = pango_font_metrics_get_descent (metrics) +
        pango_font_metrics_get_ascent (metrics);
+
       pango_font_metrics_unref (metrics);
-      return PANGO_PIXELS (val)+2 * CELLOFFSET;
+
+      return PANGO_PIXELS (val) + 2 * CELLOFFSET;
     }
 }
 
@@ -6702,7 +6705,7 @@ gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column)
 {
   GdkWindow *window = NULL;
   GdkRectangle allocation;
-  GtkSheetButton *button = NULL;
+
   gboolean is_sensitive = FALSE;
 
   if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
@@ -6731,7 +6734,7 @@ gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column)
     }
   else
     {
-      button = xxx_column_button (sheet, column);
+      GtkSheetButton *button = xxx_column_button (sheet, column);
       allocation.x = COLUMN_LEFT_XPIXEL (sheet, column) + CELL_SPACING;
       if (sheet->row_titles_visible)
        allocation.x -= sheet->row_title_area.width;
@@ -6741,6 +6744,12 @@ gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column)
       is_sensitive = xxx_column_is_sensitive (sheet, column);
       gtk_sheet_button_draw (sheet, window, button,
                             is_sensitive, allocation);
+
+      /* FIXME: Not freeing this button is correct (sort of),
+      because in PSPP the model always returns a static copy */
+
+      /* gtk_sheet_button_free (button); */
+
     }
 }
 
@@ -7640,11 +7649,14 @@ gtk_sheet_column_size_request (GtkSheet *sheet,
 {
   GtkRequisition button_requisition;
   GList *children;
+  GtkSheetButton *button = xxx_column_button (sheet, col);
 
   gtk_sheet_button_size_request (sheet,
-                                xxx_column_button (sheet, col),
+                                button,
                                 &button_requisition);
 
+  gtk_sheet_button_free (button);
+
   *requisition = button_requisition.width;
 
   children = sheet->children;
index 91a21e9d72589c98d1af92fd750619c95c9dee82..81a8544480c4da76aa8cba85c6c910a9bab5ae9f 100644 (file)
@@ -1,3 +1,11 @@
+2008-02-03  John Darrington <john@darrington.wattle.id.au>
+
+        * psppire-case-file.c psppire-case-file.h: Dont clone the casereader
+       before creating datasheet.  Add properties instead of direct code 
+        in _new function.
+
+        * psppire-data-store.c:  Implement proper dispose function.
+
 2008-01-29  John Darrington <john@darrington.wattle.id.au>
 
        * psppire-var-ptr.c psppire-var-ptr.h: New files
index 2dd1b8f628eacd41168adee33f2f127d15cc2e50..3e8677ba48fd95863555e9bb84de59ef30b7146f 100644 (file)
@@ -153,7 +153,7 @@ generate_syntax (const struct compute_dialog *cd)
   gchar *text;
   GString *string ;
   const gchar *target_name ;
-  const gchar *expression;
+  gchar *expression;
   const gchar *label;
   GtkTextIter start, end;
   GtkWidget *target = get_widget_assert   (cd->xml, "compute-entry1");
@@ -208,6 +208,9 @@ generate_syntax (const struct compute_dialog *cd)
 
   g_string_append (string, "EXECUTE.\n");
 
+
+  g_free (expression);
+
   text = string->str;
 
   g_string_free (string, FALSE);
index 6f279e8f1c7b9121cba66c355cb31f0e3d7c2e54..6e05d27183b254815bc85d99bf751b7997c3fa1f 100644 (file)
@@ -1201,6 +1201,7 @@ toggle_value_labels (GtkToggleAction *ta, gpointer data)
                                  gtk_toggle_action_get_active (ta));
 }
 
+extern PsppireDataStore *the_data_store ;
 
 static void
 file_quit (GtkCheckMenuItem *menuitem, gpointer data)
@@ -1208,6 +1209,7 @@ file_quit (GtkCheckMenuItem *menuitem, gpointer data)
   /* FIXME: Need to be more intelligent here.
      Give the user the opportunity to save any unsaved data.
   */
+  g_object_unref (the_data_store);
   gtk_main_quit ();
 }
 
index e08c0ac17d31f9073e3b5806ee6fb1731fb89364..0e5bfb4e2106540749e58432f9196d2b8350812b 100644 (file)
@@ -80,16 +80,91 @@ psppire_case_file_get_type (void)
   return object_type;
 }
 
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_DATASHEET,
+  PROP_READER
+};
+
+
+
+
+static void
+psppire_case_file_set_property (GObject         *object,
+                               guint            prop_id,
+                               const GValue    *value,
+                               GParamSpec      *pspec)
+
+{
+  PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
+
+  switch (prop_id)
+    {
+    case PROP_READER:
+      cf->datasheet = datasheet_create (g_value_get_pointer (value));
+      cf->accessible = TRUE;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+}
+
+static void
+psppire_case_file_get_property (GObject         *object,
+                               guint            prop_id,
+                               GValue          *value,
+                               GParamSpec      *pspec)
+{
+  PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
+
+  switch (prop_id)
+    {
+    case PROP_DATASHEET:
+      g_value_set_pointer (value, cf->datasheet);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+}
+
 
 static void
 psppire_case_file_class_init (PsppireCaseFileClass *class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GParamSpec *datasheet_spec ;
+  GParamSpec *reader_spec ;
 
   parent_class = g_type_class_peek_parent (class);
 
   object_class->finalize = psppire_case_file_finalize;
 
+  datasheet_spec =
+    g_param_spec_pointer ("datasheet",
+                         "Datasheet",
+                         "A pointer to the datasheet belonging to this object",
+                         G_PARAM_READABLE );
+  reader_spec =
+    g_param_spec_pointer ("casereader",
+                         "CaseReader",
+                         "A pointer to the case reader from which this object is constructed",
+                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE );
+
+  object_class->set_property = psppire_case_file_set_property;
+  object_class->get_property = psppire_case_file_get_property;
+
+  g_object_class_install_property (object_class,
+                                   PROP_DATASHEET,
+                                   datasheet_spec);
+
+  g_object_class_install_property (object_class,
+                                   PROP_READER,
+                                   reader_spec);
+
   signals [CASE_CHANGED] =
     g_signal_new ("case-changed",
                  G_TYPE_FROM_CLASS (class),
@@ -152,14 +227,11 @@ psppire_case_file_init (PsppireCaseFile *cf)
  * Creates a new #PsppireCaseFile.
  */
 PsppireCaseFile*
-psppire_case_file_new (const struct casereader *reader)
+psppire_case_file_new (struct casereader *reader)
 {
-  PsppireCaseFile *cf = g_object_new (G_TYPE_PSPPIRE_CASE_FILE, NULL);
-
-  cf->datasheet = datasheet_create (casereader_clone (reader));
-  cf->accessible = TRUE;
-
-  return cf;
+  return g_object_new (G_TYPE_PSPPIRE_CASE_FILE,
+                      "casereader", reader,
+                      NULL);
 }
 
 
@@ -343,7 +415,7 @@ psppire_case_file_insert_values (PsppireCaseFile *cf,
   {
     union value *values = xcalloc (n_values, sizeof *values);
     datasheet_insert_columns (cf->datasheet, values, n_values, where);
-  free (values);
+    free (values);
   }
 
   return TRUE;
index ff00cb800f680135275d58222f142c4b6a81ba68..13cc08d4b7279d1c56f4357981ec61f112dffc65 100644 (file)
@@ -67,7 +67,7 @@ struct _PsppireCaseFileClass
 /* -- PsppireCaseFile --- */
 GType          psppire_case_file_get_type (void);
 
-PsppireCaseFile *psppire_case_file_new (const struct casereader *);
+PsppireCaseFile *psppire_case_file_new (struct casereader *);
 
 gboolean psppire_case_file_insert_case (PsppireCaseFile *cf, struct ccase *c, casenumber row);
 
index fc5cdf9287d4eea11cbd0fb7833fa7e47edd0e0c..4f548605f3dd008e6d56b903993df2a2cb502c58 100644 (file)
@@ -48,6 +48,7 @@ static void psppire_data_store_sheet_column_init (GSheetColumnIface *iface);
 static void psppire_data_store_sheet_row_init (GSheetRowIface *iface);
 
 static void psppire_data_store_finalize        (GObject           *object);
+static void psppire_data_store_dispose        (GObject           *object);
 
 static gboolean psppire_data_store_clear_datum (GSheetModel *model,
                                          glong row, glong column);
@@ -137,6 +138,7 @@ psppire_data_store_class_init (PsppireDataStoreClass *class)
   object_class = (GObjectClass*) class;
 
   object_class->finalize = psppire_data_store_finalize;
+  object_class->dispose = psppire_data_store_dispose;
 
   signals [FONT_CHANGED] =
     g_signal_new ("font_changed",
@@ -182,10 +184,9 @@ static void
 psppire_data_store_init (PsppireDataStore *data_store)
 {
   data_store->dict = 0;
-  data_store->case_file = 0;
+  data_store->case_file = NULL;
   data_store->width_of_m = 10;
-
-
+  data_store->dispose_has_run = FALSE;
 }
 
 const PangoFontDescription *
@@ -396,10 +397,8 @@ psppire_data_store_set_case_file (PsppireDataStore *ds,
                                  PsppireCaseFile *cf)
 {
   gint i;
-  if ( ds->case_file)
-    {
-      g_object_unref (ds->case_file);
-    }
+  if ( ds->case_file)  g_object_unref (ds->case_file);
+
 
   ds->case_file = cf;
 
@@ -515,6 +514,24 @@ psppire_data_store_finalize (GObject *object)
   (* parent_class->finalize) (object);
 }
 
+
+static void
+psppire_data_store_dispose (GObject *object)
+{
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
+
+  if (ds->dispose_has_run)
+    return;
+
+  if (ds->case_file) g_object_unref (ds->case_file);
+
+  /* must chain up */
+  (* parent_class->dispose) (object);
+
+  ds->dispose_has_run = TRUE;
+}
+
+
 gboolean
 psppire_data_store_delete_cases (PsppireDataStore *ds,
                                 casenumber first, casenumber count)
index 7d1e242ee4a5dac1aa155dbff9705c383bd278de..f916ded883bbccb843b196f027dafd607e00767d 100644 (file)
@@ -81,6 +81,7 @@ struct _PsppireDataStore
   GObject parent;
 
   /*< private >*/
+  gboolean dispose_has_run ;
   PsppireDict *dict;
   PsppireCaseFile *case_file;
   const PangoFontDescription *font_desc;
index 25af04c9ae110d9759f2478136f428e2906d1f76..24d9089698fddeeb2ca098b1d146c844ecec413d 100644 (file)
@@ -428,6 +428,8 @@ psppire_dialog_run (PsppireDialog *dialog)
 
   g_main_loop_run (dialog->loop);
 
+  g_main_loop_unref (dialog->loop);
+
   return dialog->response;
 }