Commit 91ae35bb8c6418ccce439e9a1b42c1c5835b8850
1 parent
b8be8f94
Exists in
master
and in
1 other branch
Fixing memory leaks in FT Activity management.
Showing
6 changed files
with
112 additions
and
32 deletions
Show diff stats
src/filetransfer/activity.c
| @@ -65,7 +65,7 @@ | @@ -65,7 +65,7 @@ | ||
| 65 | PROP_REMOTE | 65 | PROP_REMOTE |
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | - G_DEFINE_TYPE(V3270FTActivity, V3270FTActivity, G_TYPE_OBJECT); | 68 | + G_DEFINE_TYPE(V3270FTActivity, V3270FTActivity, G_TYPE_INITIALLY_UNOWNED); |
| 69 | 69 | ||
| 70 | /*--[ Implement ]------------------------------------------------------------------------------------*/ | 70 | /*--[ Implement ]------------------------------------------------------------------------------------*/ |
| 71 | 71 | ||
| @@ -148,16 +148,16 @@ | @@ -148,16 +148,16 @@ | ||
| 148 | return g_object_new(G_TYPE_V3270_FT_ACTIVITY, NULL); | 148 | return g_object_new(G_TYPE_V3270_FT_ACTIVITY, NULL); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | - LIB3270_EXPORT const gchar * v3270_ft_activity_get_local_filename(GObject *object) | 151 | + LIB3270_EXPORT const gchar * v3270_ft_activity_get_local_filename(const GObject *object) |
| 152 | { | 152 | { |
| 153 | - gchar **ptr = & G_V3270_FT_ACTIVITY(object)->file.local; | ||
| 154 | - return(*ptr ? *ptr : ""); | 153 | + const gchar *ptr = G_V3270_FT_ACTIVITY(object)->file.local; |
| 154 | + return (ptr ? ptr : ""); | ||
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | - LIB3270_EXPORT const gchar * v3270_ft_activity_get_remote_filename(GObject *object) | 157 | + LIB3270_EXPORT const gchar * v3270_ft_activity_get_remote_filename(const GObject *object) |
| 158 | { | 158 | { |
| 159 | - gchar **ptr = & G_V3270_FT_ACTIVITY(object)->file.remote; | ||
| 160 | - return(*ptr ? *ptr : ""); | 159 | + const gchar *ptr = G_V3270_FT_ACTIVITY(object)->file.remote; |
| 160 | + return(ptr ? ptr : ""); | ||
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | LIB3270_EXPORT void v3270_ft_activity_set_local_filename(GObject *object, const gchar *filename) | 163 | LIB3270_EXPORT void v3270_ft_activity_set_local_filename(GObject *object, const gchar *filename) |
| @@ -181,12 +181,12 @@ | @@ -181,12 +181,12 @@ | ||
| 181 | G_V3270_FT_ACTIVITY(object)->options = options; | 181 | G_V3270_FT_ACTIVITY(object)->options = options; |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | - LIB3270_EXPORT LIB3270_FT_OPTION v3270_ft_activity_get_options(GObject *object) | 184 | + LIB3270_EXPORT LIB3270_FT_OPTION v3270_ft_activity_get_options(const GObject *object) |
| 185 | { | 185 | { |
| 186 | return G_V3270_FT_ACTIVITY(object)->options; | 186 | return G_V3270_FT_ACTIVITY(object)->options; |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | - guint v3270_ft_activity_get_value(GObject * object, LIB3270_FT_VALUE id) | 189 | + guint v3270_ft_activity_get_value(const GObject * object, LIB3270_FT_VALUE id) |
| 190 | { | 190 | { |
| 191 | return G_V3270_FT_ACTIVITY(object)->values[id]; | 191 | return G_V3270_FT_ACTIVITY(object)->values[id]; |
| 192 | } | 192 | } |
src/filetransfer/activitylist.c
| @@ -40,6 +40,11 @@ | @@ -40,6 +40,11 @@ | ||
| 40 | V3270_ACTIVITY_LIST_LAST_SIGNAL | 40 | V3270_ACTIVITY_LIST_LAST_SIGNAL |
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | + typedef struct _activities | ||
| 44 | + { | ||
| 45 | + | ||
| 46 | + } Activities; | ||
| 47 | + | ||
| 43 | struct _V3270FTActivityListClass | 48 | struct _V3270FTActivityListClass |
| 44 | { | 49 | { |
| 45 | GtkTreeViewClass parent_class; | 50 | GtkTreeViewClass parent_class; |
| @@ -65,14 +70,31 @@ | @@ -65,14 +70,31 @@ | ||
| 65 | 70 | ||
| 66 | static void dispose(GObject *object) | 71 | static void dispose(GObject *object) |
| 67 | { | 72 | { |
| 68 | - debug("%s",__FUNCTION__); | 73 | + debug("%s (model=%p)",__FUNCTION__,gtk_tree_view_get_model(GTK_TREE_VIEW(object))); |
| 69 | 74 | ||
| 70 | V3270FTActivityList * list = GTK_V3270_FT_ACTIVITY_LIST(object); | 75 | V3270FTActivityList * list = GTK_V3270_FT_ACTIVITY_LIST(object); |
| 71 | 76 | ||
| 77 | + // Release filename | ||
| 72 | debug("Freeing %s",list->filename); | 78 | debug("Freeing %s",list->filename); |
| 73 | g_free(list->filename); | 79 | g_free(list->filename); |
| 74 | list->filename = NULL; | 80 | list->filename = NULL; |
| 75 | 81 | ||
| 82 | + GtkTreeIter iter; | ||
| 83 | + GtkTreeModel * model = gtk_tree_view_get_model(GTK_TREE_VIEW(object)); | ||
| 84 | + | ||
| 85 | + while(model && gtk_tree_model_get_iter_first(model,&iter)) | ||
| 86 | + { | ||
| 87 | + GObject * activity = NULL; | ||
| 88 | + gtk_tree_model_get(model, &iter, 0, &activity, -1); | ||
| 89 | + | ||
| 90 | + gtk_list_store_remove(GTK_LIST_STORE(model),&iter); | ||
| 91 | + debug("Disposing activity %p",activity); | ||
| 92 | + | ||
| 93 | + g_clear_object(&activity); | ||
| 94 | + | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + | ||
| 76 | G_OBJECT_CLASS(V3270FTActivityList_parent_class)->dispose(object); | 98 | G_OBJECT_CLASS(V3270FTActivityList_parent_class)->dispose(object); |
| 77 | 99 | ||
| 78 | } | 100 | } |
| @@ -118,7 +140,7 @@ | @@ -118,7 +140,7 @@ | ||
| 118 | 140 | ||
| 119 | static void V3270FTActivityList_init(V3270FTActivityList *widget) | 141 | static void V3270FTActivityList_init(V3270FTActivityList *widget) |
| 120 | { | 142 | { |
| 121 | - GtkTreeModel * model = GTK_TREE_MODEL(gtk_list_store_new(1,G_TYPE_OBJECT)); | 143 | + GtkTreeModel * model = GTK_TREE_MODEL(gtk_list_store_new(1,G_TYPE_POINTER)); // Using pointer type because I take care of refcounts. |
| 122 | 144 | ||
| 123 | widget->filename = NULL; | 145 | widget->filename = NULL; |
| 124 | 146 | ||
| @@ -157,6 +179,8 @@ | @@ -157,6 +179,8 @@ | ||
| 157 | GtkTreeIter iter; | 179 | GtkTreeIter iter; |
| 158 | gtk_list_store_append((GtkListStore *) model,&iter); | 180 | gtk_list_store_append((GtkListStore *) model,&iter); |
| 159 | gtk_list_store_set((GtkListStore *) model, &iter, 0, activity, -1); | 181 | gtk_list_store_set((GtkListStore *) model, &iter, 0, activity, -1); |
| 182 | + g_object_ref_sink(activity); | ||
| 183 | + | ||
| 160 | } | 184 | } |
| 161 | 185 | ||
| 162 | void v3270_activity_list_remove(GtkWidget *widget, GObject *activity) | 186 | void v3270_activity_list_remove(GtkWidget *widget, GObject *activity) |
| @@ -176,7 +200,9 @@ | @@ -176,7 +200,9 @@ | ||
| 176 | 200 | ||
| 177 | if(stored == activity) | 201 | if(stored == activity) |
| 178 | { | 202 | { |
| 203 | + debug("Removing activity %p",activity); | ||
| 179 | gtk_list_store_remove(GTK_LIST_STORE(model),&iter); | 204 | gtk_list_store_remove(GTK_LIST_STORE(model),&iter); |
| 205 | + g_object_unref(stored); | ||
| 180 | return; | 206 | return; |
| 181 | } | 207 | } |
| 182 | 208 |
src/filetransfer/dialog.c
| @@ -155,6 +155,50 @@ static void begin_clicked(GtkButton G_GNUC_UNUSED(*button), V3270FTDialog *widge | @@ -155,6 +155,50 @@ static void begin_clicked(GtkButton G_GNUC_UNUSED(*button), V3270FTDialog *widge | ||
| 155 | gtk_dialog_response(GTK_DIALOG(widget),GTK_RESPONSE_ACCEPT); | 155 | gtk_dialog_response(GTK_DIALOG(widget),GTK_RESPONSE_ACCEPT); |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | +static gboolean v3270_activity_compare_filenames(const GObject *a, const GObject *b) | ||
| 159 | +{ | ||
| 160 | + if(strcmp(v3270_ft_activity_get_local_filename(a),v3270_ft_activity_get_local_filename(b))) | ||
| 161 | + return FALSE; | ||
| 162 | + | ||
| 163 | + if(strcmp(v3270_ft_activity_get_remote_filename(a),v3270_ft_activity_get_remote_filename(b))) | ||
| 164 | + return FALSE; | ||
| 165 | + | ||
| 166 | + return TRUE; | ||
| 167 | +} | ||
| 168 | + | ||
| 169 | +int v3270_ft_dialog_append_activity(GtkWidget *widget, GObject *activity, GError **error) | ||
| 170 | +{ | ||
| 171 | + V3270FTDialog *dialog = GTK_V3270_FT_DIALOG(widget); | ||
| 172 | + | ||
| 173 | + GtkTreeIter iter; | ||
| 174 | + GtkTreeModel * model = gtk_tree_view_get_model(GTK_TREE_VIEW(dialog->queue.view)); | ||
| 175 | + | ||
| 176 | + if(gtk_tree_model_get_iter_first(model,&iter)) | ||
| 177 | + { | ||
| 178 | + do | ||
| 179 | + { | ||
| 180 | + GObject * a = NULL; | ||
| 181 | + gtk_tree_model_get(model, &iter, 0, &a, -1); | ||
| 182 | + | ||
| 183 | + if(a && v3270_activity_compare_filenames(activity, a)) | ||
| 184 | + { | ||
| 185 | + // Activity already exist | ||
| 186 | + if(error && !*error) | ||
| 187 | + *error = g_error_new_literal(g_quark_from_static_string(PACKAGE_NAME),EPERM,_("Activity already on the queue")); | ||
| 188 | + | ||
| 189 | + return -1; | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + } | ||
| 193 | + while(gtk_tree_model_iter_next(model,&iter)); | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + // Not found, insert it. | ||
| 197 | + v3270_activity_list_append(dialog->queue.view,activity); | ||
| 198 | + | ||
| 199 | + return 0; | ||
| 200 | +} | ||
| 201 | + | ||
| 158 | static void insert_clicked(GtkWidget *button, V3270FTDialog *widget) | 202 | static void insert_clicked(GtkWidget *button, V3270FTDialog *widget) |
| 159 | { | 203 | { |
| 160 | GtkTreeIter iter; | 204 | GtkTreeIter iter; |
src/filetransfer/worker.c
| @@ -131,11 +131,15 @@ | @@ -131,11 +131,15 @@ | ||
| 131 | pulse_stop(worker); | 131 | pulse_stop(worker); |
| 132 | timer_stop(worker); | 132 | timer_stop(worker); |
| 133 | 133 | ||
| 134 | + g_clear_object(&worker->activity); | ||
| 135 | + | ||
| 136 | + /* | ||
| 134 | if(worker->activity) | 137 | if(worker->activity) |
| 135 | { | 138 | { |
| 136 | g_object_unref(worker->activity); | 139 | g_object_unref(worker->activity); |
| 137 | worker->activity = NULL; | 140 | worker->activity = NULL; |
| 138 | } | 141 | } |
| 142 | + */ | ||
| 139 | 143 | ||
| 140 | G_OBJECT_CLASS(V3270FTWorker_parent_class)->finalize(object); | 144 | G_OBJECT_CLASS(V3270FTWorker_parent_class)->finalize(object); |
| 141 | 145 | ||
| @@ -294,16 +298,12 @@ | @@ -294,16 +298,12 @@ | ||
| 294 | lib3270_ft_destroy(worker->hSession,NULL); | 298 | lib3270_ft_destroy(worker->hSession,NULL); |
| 295 | } | 299 | } |
| 296 | 300 | ||
| 297 | - if(worker->activity) | ||
| 298 | - { | ||
| 299 | - g_object_unref(worker->activity); | ||
| 300 | - worker->activity = NULL; | ||
| 301 | - } | 301 | + g_clear_object(&worker->activity); |
| 302 | 302 | ||
| 303 | if(activity) | 303 | if(activity) |
| 304 | { | 304 | { |
| 305 | worker->activity = activity; | 305 | worker->activity = activity; |
| 306 | - g_object_ref(worker->activity); | 306 | + g_object_ref_sink(activity); |
| 307 | 307 | ||
| 308 | gtk_entry_set_text(worker->field[PROGRESS_FIELD_LOCAL],v3270_ft_activity_get_local_filename(activity)); | 308 | gtk_entry_set_text(worker->field[PROGRESS_FIELD_LOCAL],v3270_ft_activity_get_local_filename(activity)); |
| 309 | gtk_entry_set_text(worker->field[PROGRESS_FIELD_REMOTE],v3270_ft_activity_get_remote_filename(activity)); | 309 | gtk_entry_set_text(worker->field[PROGRESS_FIELD_REMOTE],v3270_ft_activity_get_remote_filename(activity)); |
src/include/v3270/filetransfer.h
| @@ -120,10 +120,10 @@ | @@ -120,10 +120,10 @@ | ||
| 120 | 120 | ||
| 121 | LIB3270_EXPORT void v3270_ft_activity_set_from_context(GObject * activity, GMarkupParseContext * context); | 121 | LIB3270_EXPORT void v3270_ft_activity_set_from_context(GObject * activity, GMarkupParseContext * context); |
| 122 | 122 | ||
| 123 | - LIB3270_EXPORT const gchar * v3270_ft_activity_get_local_filename(GObject *object); | ||
| 124 | - LIB3270_EXPORT const gchar * v3270_ft_activity_get_remote_filename(GObject *object); | ||
| 125 | - LIB3270_EXPORT LIB3270_FT_OPTION v3270_ft_activity_get_options(GObject *object); | ||
| 126 | - LIB3270_EXPORT guint v3270_ft_activity_get_value(GObject * object, LIB3270_FT_VALUE id); | 123 | + LIB3270_EXPORT const gchar * v3270_ft_activity_get_local_filename(const GObject *object); |
| 124 | + LIB3270_EXPORT const gchar * v3270_ft_activity_get_remote_filename(const GObject *object); | ||
| 125 | + LIB3270_EXPORT LIB3270_FT_OPTION v3270_ft_activity_get_options(const GObject *object); | ||
| 126 | + LIB3270_EXPORT guint v3270_ft_activity_get_value(const GObject * object, LIB3270_FT_VALUE id); | ||
| 127 | 127 | ||
| 128 | LIB3270_EXPORT void v3270_ft_activity_set_local_filename(GObject *object, const gchar *filename); | 128 | LIB3270_EXPORT void v3270_ft_activity_set_local_filename(GObject *object, const gchar *filename); |
| 129 | LIB3270_EXPORT void v3270_ft_activity_set_remote_filename(GObject *object, const gchar *filename); | 129 | LIB3270_EXPORT void v3270_ft_activity_set_remote_filename(GObject *object, const gchar *filename); |
| @@ -144,6 +144,7 @@ | @@ -144,6 +144,7 @@ | ||
| 144 | 144 | ||
| 145 | LIB3270_EXPORT GtkWidget * v3270_ft_dialog_new(GtkWidget *parent); | 145 | LIB3270_EXPORT GtkWidget * v3270_ft_dialog_new(GtkWidget *parent); |
| 146 | LIB3270_EXPORT void v3270_ft_dialog_set_session(GtkWidget *widget, H3270 *hSession); | 146 | LIB3270_EXPORT void v3270_ft_dialog_set_session(GtkWidget *widget, H3270 *hSession); |
| 147 | + LIB3270_EXPORT int v3270_ft_dialog_append_activity(GtkWidget *widget, GObject *activity, GError **error); | ||
| 147 | 148 | ||
| 148 | G_END_DECLS | 149 | G_END_DECLS |
| 149 | 150 |
src/testprogram/testprogram.c
| @@ -149,23 +149,32 @@ static void disconnect_clicked(GtkButton G_GNUC_UNUSED(*button), GtkWidget *term | @@ -149,23 +149,32 @@ static void disconnect_clicked(GtkButton G_GNUC_UNUSED(*button), GtkWidget *term | ||
| 149 | 149 | ||
| 150 | static void ft_clicked(GtkButton G_GNUC_UNUSED(*button), GtkWidget *terminal) | 150 | static void ft_clicked(GtkButton G_GNUC_UNUSED(*button), GtkWidget *terminal) |
| 151 | { | 151 | { |
| 152 | - GtkWidget * dialog = v3270_dialog_new(terminal, _("test"), _("test")); | ||
| 153 | - GtkWidget * worker = v3270_ft_worker_new(); | ||
| 154 | - gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),worker,TRUE,TRUE,2); | ||
| 155 | - | ||
| 156 | - v3270_ft_worker_set_session(worker,v3270_get_session(terminal)); | ||
| 157 | - | 152 | + // |
| 153 | + // Test activity | ||
| 154 | + // | ||
| 158 | GObject * activity = v3270_ft_activity_new(); | 155 | GObject * activity = v3270_ft_activity_new(); |
| 156 | + debug("Activity %p is %s",activity,(g_object_is_floating(activity) ? "floating" : "non floating")); | ||
| 159 | v3270_ft_activity_set_local_filename(activity,"/tmp/test.txt"); | 157 | v3270_ft_activity_set_local_filename(activity,"/tmp/test.txt"); |
| 160 | v3270_ft_activity_set_remote_filename(activity,"remote_file"); | 158 | v3270_ft_activity_set_remote_filename(activity,"remote_file"); |
| 161 | v3270_ft_activity_set_options(activity,LIB3270_FT_OPTION_RECEIVE|LIB3270_FT_OPTION_ASCII|LIB3270_FT_OPTION_REMAP); | 159 | v3270_ft_activity_set_options(activity,LIB3270_FT_OPTION_RECEIVE|LIB3270_FT_OPTION_ASCII|LIB3270_FT_OPTION_REMAP); |
| 162 | - v3270_ft_worker_set_activity(worker,activity); | ||
| 163 | - g_object_unref(activity); | ||
| 164 | 160 | ||
| 165 | - v3270_ft_worker_start(worker); | 161 | + /* |
| 162 | + // | ||
| 163 | + // Test settings dialog | ||
| 164 | + // | ||
| 165 | + GtkWidget * dialog = v3270_ft_dialog_new(terminal); | ||
| 166 | + v3270_ft_dialog_append_activity(dialog,activity,NULL); | ||
| 167 | + */ | ||
| 166 | 168 | ||
| 167 | - // GtkWidget * dialog = v3270ftprogress_new(); | ||
| 168 | - // GtkWidget * dialog = v3270_ft_dialog_new(terminal); | 169 | + // |
| 170 | + // Test worker widget | ||
| 171 | + // | ||
| 172 | + GtkWidget * dialog = v3270_dialog_new(terminal, _("test"), _("test")); | ||
| 173 | + GtkWidget * worker = v3270_ft_worker_new(); | ||
| 174 | + gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),worker,TRUE,TRUE,2); | ||
| 175 | + v3270_ft_worker_set_session(worker,v3270_get_session(terminal)); | ||
| 176 | + v3270_ft_worker_set_activity(worker,activity); | ||
| 177 | + v3270_ft_worker_start(worker); | ||
| 169 | 178 | ||
| 170 | gtk_widget_show_all(dialog); | 179 | gtk_widget_show_all(dialog); |
| 171 | gtk_dialog_run(GTK_DIALOG(dialog)); | 180 | gtk_dialog_run(GTK_DIALOG(dialog)); |