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 | 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 | 70 | /*--[ Implement ]------------------------------------------------------------------------------------*/ |
| 71 | 71 | |
| ... | ... | @@ -148,16 +148,16 @@ |
| 148 | 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 | 163 | LIB3270_EXPORT void v3270_ft_activity_set_local_filename(GObject *object, const gchar *filename) |
| ... | ... | @@ -181,12 +181,12 @@ |
| 181 | 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 | 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 | 191 | return G_V3270_FT_ACTIVITY(object)->values[id]; |
| 192 | 192 | } | ... | ... |
src/filetransfer/activitylist.c
| ... | ... | @@ -40,6 +40,11 @@ |
| 40 | 40 | V3270_ACTIVITY_LIST_LAST_SIGNAL |
| 41 | 41 | }; |
| 42 | 42 | |
| 43 | + typedef struct _activities | |
| 44 | + { | |
| 45 | + | |
| 46 | + } Activities; | |
| 47 | + | |
| 43 | 48 | struct _V3270FTActivityListClass |
| 44 | 49 | { |
| 45 | 50 | GtkTreeViewClass parent_class; |
| ... | ... | @@ -65,14 +70,31 @@ |
| 65 | 70 | |
| 66 | 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 | 75 | V3270FTActivityList * list = GTK_V3270_FT_ACTIVITY_LIST(object); |
| 71 | 76 | |
| 77 | + // Release filename | |
| 72 | 78 | debug("Freeing %s",list->filename); |
| 73 | 79 | g_free(list->filename); |
| 74 | 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 | 98 | G_OBJECT_CLASS(V3270FTActivityList_parent_class)->dispose(object); |
| 77 | 99 | |
| 78 | 100 | } |
| ... | ... | @@ -118,7 +140,7 @@ |
| 118 | 140 | |
| 119 | 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 | 145 | widget->filename = NULL; |
| 124 | 146 | |
| ... | ... | @@ -157,6 +179,8 @@ |
| 157 | 179 | GtkTreeIter iter; |
| 158 | 180 | gtk_list_store_append((GtkListStore *) model,&iter); |
| 159 | 181 | gtk_list_store_set((GtkListStore *) model, &iter, 0, activity, -1); |
| 182 | + g_object_ref_sink(activity); | |
| 183 | + | |
| 160 | 184 | } |
| 161 | 185 | |
| 162 | 186 | void v3270_activity_list_remove(GtkWidget *widget, GObject *activity) |
| ... | ... | @@ -176,7 +200,9 @@ |
| 176 | 200 | |
| 177 | 201 | if(stored == activity) |
| 178 | 202 | { |
| 203 | + debug("Removing activity %p",activity); | |
| 179 | 204 | gtk_list_store_remove(GTK_LIST_STORE(model),&iter); |
| 205 | + g_object_unref(stored); | |
| 180 | 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 | 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 | 202 | static void insert_clicked(GtkWidget *button, V3270FTDialog *widget) |
| 159 | 203 | { |
| 160 | 204 | GtkTreeIter iter; | ... | ... |
src/filetransfer/worker.c
| ... | ... | @@ -131,11 +131,15 @@ |
| 131 | 131 | pulse_stop(worker); |
| 132 | 132 | timer_stop(worker); |
| 133 | 133 | |
| 134 | + g_clear_object(&worker->activity); | |
| 135 | + | |
| 136 | + /* | |
| 134 | 137 | if(worker->activity) |
| 135 | 138 | { |
| 136 | 139 | g_object_unref(worker->activity); |
| 137 | 140 | worker->activity = NULL; |
| 138 | 141 | } |
| 142 | + */ | |
| 139 | 143 | |
| 140 | 144 | G_OBJECT_CLASS(V3270FTWorker_parent_class)->finalize(object); |
| 141 | 145 | |
| ... | ... | @@ -294,16 +298,12 @@ |
| 294 | 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 | 303 | if(activity) |
| 304 | 304 | { |
| 305 | 305 | worker->activity = activity; |
| 306 | - g_object_ref(worker->activity); | |
| 306 | + g_object_ref_sink(activity); | |
| 307 | 307 | |
| 308 | 308 | gtk_entry_set_text(worker->field[PROGRESS_FIELD_LOCAL],v3270_ft_activity_get_local_filename(activity)); |
| 309 | 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 | 120 | |
| 121 | 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 | 128 | LIB3270_EXPORT void v3270_ft_activity_set_local_filename(GObject *object, const gchar *filename); |
| 129 | 129 | LIB3270_EXPORT void v3270_ft_activity_set_remote_filename(GObject *object, const gchar *filename); |
| ... | ... | @@ -144,6 +144,7 @@ |
| 144 | 144 | |
| 145 | 145 | LIB3270_EXPORT GtkWidget * v3270_ft_dialog_new(GtkWidget *parent); |
| 146 | 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 | 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 | 149 | |
| 150 | 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 | 155 | GObject * activity = v3270_ft_activity_new(); |
| 156 | + debug("Activity %p is %s",activity,(g_object_is_floating(activity) ? "floating" : "non floating")); | |
| 159 | 157 | v3270_ft_activity_set_local_filename(activity,"/tmp/test.txt"); |
| 160 | 158 | v3270_ft_activity_set_remote_filename(activity,"remote_file"); |
| 161 | 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 | 179 | gtk_widget_show_all(dialog); |
| 171 | 180 | gtk_dialog_run(GTK_DIALOG(dialog)); | ... | ... |