From 6882ff1359de0c4812a62e1bfcdfbf8e68474de5 Mon Sep 17 00:00:00 2001 From: John Darrington Date: Sun, 3 Feb 2008 12:09:24 +0000 Subject: [PATCH] Fixed various memory leaks in GUI --- lib/gtksheet/gtksheet.c | 20 ++++++-- src/ui/gui/ChangeLog | 8 +++ src/ui/gui/compute-dialog.c | 5 +- src/ui/gui/data-editor.c | 2 + src/ui/gui/psppire-case-file.c | 88 ++++++++++++++++++++++++++++++--- src/ui/gui/psppire-case-file.h | 2 +- src/ui/gui/psppire-data-store.c | 31 +++++++++--- src/ui/gui/psppire-data-store.h | 1 + src/ui/gui/psppire-dialog.c | 2 + 9 files changed, 138 insertions(+), 21 deletions(-) diff --git a/lib/gtksheet/gtksheet.c b/lib/gtksheet/gtksheet.c index 409c2369..2e535119 100644 --- a/lib/gtksheet/gtksheet.c +++ b/lib/gtksheet/gtksheet.c @@ -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; diff --git a/src/ui/gui/ChangeLog b/src/ui/gui/ChangeLog index 91a21e9d..81a85444 100644 --- a/src/ui/gui/ChangeLog +++ b/src/ui/gui/ChangeLog @@ -1,3 +1,11 @@ +2008-02-03 John Darrington + + * 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 * psppire-var-ptr.c psppire-var-ptr.h: New files diff --git a/src/ui/gui/compute-dialog.c b/src/ui/gui/compute-dialog.c index 2dd1b8f6..3e8677ba 100644 --- a/src/ui/gui/compute-dialog.c +++ b/src/ui/gui/compute-dialog.c @@ -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); diff --git a/src/ui/gui/data-editor.c b/src/ui/gui/data-editor.c index 6f279e8f..6e05d271 100644 --- a/src/ui/gui/data-editor.c +++ b/src/ui/gui/data-editor.c @@ -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 (); } diff --git a/src/ui/gui/psppire-case-file.c b/src/ui/gui/psppire-case-file.c index e08c0ac1..0e5bfb4e 100644 --- a/src/ui/gui/psppire-case-file.c +++ b/src/ui/gui/psppire-case-file.c @@ -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; diff --git a/src/ui/gui/psppire-case-file.h b/src/ui/gui/psppire-case-file.h index ff00cb80..13cc08d4 100644 --- a/src/ui/gui/psppire-case-file.h +++ b/src/ui/gui/psppire-case-file.h @@ -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); diff --git a/src/ui/gui/psppire-data-store.c b/src/ui/gui/psppire-data-store.c index fc5cdf92..4f548605 100644 --- a/src/ui/gui/psppire-data-store.c +++ b/src/ui/gui/psppire-data-store.c @@ -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) diff --git a/src/ui/gui/psppire-data-store.h b/src/ui/gui/psppire-data-store.h index 7d1e242e..f916ded8 100644 --- a/src/ui/gui/psppire-data-store.h +++ b/src/ui/gui/psppire-data-store.h @@ -81,6 +81,7 @@ struct _PsppireDataStore GObject parent; /*< private >*/ + gboolean dispose_has_run ; PsppireDict *dict; PsppireCaseFile *case_file; const PangoFontDescription *font_desc; diff --git a/src/ui/gui/psppire-dialog.c b/src/ui/gui/psppire-dialog.c index 25af04c9..24d90896 100644 --- a/src/ui/gui/psppire-dialog.c +++ b/src/ui/gui/psppire-dialog.c @@ -428,6 +428,8 @@ psppire_dialog_run (PsppireDialog *dialog) g_main_loop_run (dialog->loop); + g_main_loop_unref (dialog->loop); + return dialog->response; } -- 2.30.2