Commit 62e67d83660fa6d4281db743004811353982f7ed

Authored by Perry Werneck
1 parent 337c00ca
Exists in master and in 1 other branch develop

Working on FT worker widget.

src/dialogs/tools.c
@@ -82,5 +82,16 @@ @@ -82,5 +82,16 @@
82 return child; 82 return child;
83 } 83 }
84 84
  85 + void gtk_entry_set_text_printf(GtkEntry *entry, const gchar *fmt, ...)
  86 + {
  87 + va_list arg_ptr;
  88 + va_start(arg_ptr, fmt);
  89 + gchar *text = g_strdup_vprintf(fmt,arg_ptr);
  90 + va_end(arg_ptr);
  91 +
  92 + gtk_entry_set_text(entry,text);
85 93
  94 + g_free(text);
  95 +
  96 + }
86 97
src/filetransfer/activity.c
@@ -298,3 +298,22 @@ @@ -298,3 +298,22 @@
298 g_markup_parse_context_push(context,&parser,activity); 298 g_markup_parse_context_push(context,&parser,activity);
299 299
300 } 300 }
  301 +
  302 + LIB3270_EXPORT H3270FT * v3270_ft_activity_begin_transfer(GObject * object, H3270 *hSession, const char **message)
  303 + {
  304 + V3270FTActivity * activity = G_V3270_FT_ACTIVITY(object);
  305 +
  306 + return lib3270_ft_new(
  307 + hSession,
  308 + activity->options,
  309 + activity->file.local,
  310 + activity->file.remote,
  311 + activity->values[LIB3270_FT_VALUE_LRECL],
  312 + activity->values[LIB3270_FT_VALUE_BLKSIZE],
  313 + activity->values[LIB3270_FT_VALUE_PRIMSPACE],
  314 + activity->values[LIB3270_FT_VALUE_SECSPACE],
  315 + activity->values[LIB3270_FT_VALUE_DFT],
  316 + message
  317 + );
  318 +
  319 + }
src/filetransfer/marshal
1 VOID:POINTER,POINTER 1 VOID:POINTER,POINTER
2 VOID:VOID,BOOLEAN 2 VOID:VOID,BOOLEAN
3 VOID:VOID,OBJECT 3 VOID:VOID,OBJECT
  4 +VOID:UINT,POINTER
4 5
src/filetransfer/set.c
@@ -182,7 +182,7 @@ void v3270ftprogress_set_session(GtkWidget *widget, H3270 *session) { @@ -182,7 +182,7 @@ void v3270ftprogress_set_session(GtkWidget *widget, H3270 *session) {
182 v3270ftprogress * dialog = GTK_V3270FTPROGRESS(widget); 182 v3270ftprogress * dialog = GTK_V3270FTPROGRESS(widget);
183 183
184 if(dialog->session) { 184 if(dialog->session) {
185 - lib3270_ft_destroy(dialog->session); 185 + lib3270_ft_destroy(dialog->session,NULL);
186 } 186 }
187 187
188 dialog->session = session; 188 dialog->session = session;
src/filetransfer/v3270ftprogress.c
@@ -247,7 +247,7 @@ gboolean v3270ftprogress_cleanup(v3270ftprogress * dialog) { @@ -247,7 +247,7 @@ gboolean v3270ftprogress_cleanup(v3270ftprogress * dialog) {
247 if(dialog->session) { 247 if(dialog->session) {
248 debug("%s: FT session was destroyed",__FUNCTION__); 248 debug("%s: FT session was destroyed",__FUNCTION__);
249 lib3270_ft_set_user_data(dialog->session,NULL); 249 lib3270_ft_set_user_data(dialog->session,NULL);
250 - lib3270_ft_destroy(dialog->session); 250 + lib3270_ft_destroy(dialog->session,NULL);
251 } 251 }
252 252
253 return FALSE; 253 return FALSE;
@@ -282,7 +282,7 @@ static void dialog_response(GtkDialog *widget, gint response_id) { @@ -282,7 +282,7 @@ static void dialog_response(GtkDialog *widget, gint response_id) {
282 282
283 // Removo do objeto para evitar a geração de sinais e destruo. 283 // Removo do objeto para evitar a geração de sinais e destruo.
284 lib3270_ft_set_user_data(dialog->session,NULL); 284 lib3270_ft_set_user_data(dialog->session,NULL);
285 - lib3270_ft_destroy(dialog->session); 285 + lib3270_ft_destroy(dialog->session,NULL);
286 286
287 } 287 }
288 288
@@ -298,7 +298,7 @@ static void dialog_close(GtkDialog *object) { @@ -298,7 +298,7 @@ static void dialog_close(GtkDialog *object) {
298 debug("%s",__FUNCTION__); 298 debug("%s",__FUNCTION__);
299 299
300 // Se tem sessão e conseguiu cancelar. 300 // Se tem sessão e conseguiu cancelar.
301 - if(dialog->session && lib3270_ft_cancel(dialog->session,0) == 0) 301 + if(dialog->session && lib3270_ft_cancel(dialog->session,0,NULL) == 0)
302 return; 302 return;
303 303
304 GTK_DIALOG_CLASS(v3270ftprogress_parent_class)->close(object); 304 GTK_DIALOG_CLASS(v3270ftprogress_parent_class)->close(object);
@@ -367,7 +367,7 @@ static void cancel_clicked(G_GNUC_UNUSED GtkButton *button,v3270ftprogress *dial @@ -367,7 +367,7 @@ static void cancel_clicked(G_GNUC_UNUSED GtkButton *button,v3270ftprogress *dial
367 debug("%s",__FUNCTION__); 367 debug("%s",__FUNCTION__);
368 368
369 if(dialog->session) { 369 if(dialog->session) {
370 - lib3270_ft_cancel(dialog->session,1); 370 + lib3270_ft_cancel(dialog->session,1,NULL);
371 } 371 }
372 } 372 }
373 373
@@ -540,7 +540,7 @@ gboolean send_delayed_signal(struct delayed_signal *sig) { @@ -540,7 +540,7 @@ gboolean send_delayed_signal(struct delayed_signal *sig) {
540 void * userdata = lib3270_ft_get_user_data(sig->hSession); 540 void * userdata = lib3270_ft_get_user_data(sig->hSession);
541 541
542 lib3270_ft_set_user_data(sig->hSession,NULL); 542 lib3270_ft_set_user_data(sig->hSession,NULL);
543 - lib3270_ft_destroy(sig->hSession); 543 + lib3270_ft_destroy(sig->hSession,NULL);
544 544
545 if(userdata) { 545 if(userdata) {
546 g_signal_emit(GTK_WIDGET(userdata),v3270ftprogress_signal[sig->signal], 0, sig->msg, sig->text); 546 g_signal_emit(GTK_WIDGET(userdata),v3270ftprogress_signal[sig->signal], 0, sig->msg, sig->text);
@@ -679,10 +679,10 @@ static void ft_running(G_GNUC_UNUSED H3270 *hSession, G_GNUC_UNUSED int is_cut, @@ -679,10 +679,10 @@ static void ft_running(G_GNUC_UNUSED H3270 *hSession, G_GNUC_UNUSED int is_cut,
679 GTK_V3270FTPROGRESS(widget)->timeout = time(NULL)+10; 679 GTK_V3270FTPROGRESS(widget)->timeout = time(NULL)+10;
680 } 680 }
681 681
682 -static void ft_aborting(G_GNUC_UNUSED H3270 *hSession, void *widget) { 682 +static void ft_aborting(G_GNUC_UNUSED H3270 *hSession, const char *reason, void *widget) {
683 683
684 if(widget) { 684 if(widget) {
685 - v3270ftprogress_set_header(GTK_WIDGET(widget),_("Aborting transfer")); 685 + v3270ftprogress_set_header(GTK_WIDGET(widget),reason);
686 } 686 }
687 687
688 } 688 }
@@ -714,7 +714,7 @@ static gboolean do_timer(v3270ftprogress *dialog) { @@ -714,7 +714,7 @@ static gboolean do_timer(v3270ftprogress *dialog) {
714 714
715 if(dialog->session) { 715 if(dialog->session) {
716 lib3270_ft_set_user_data(dialog->session,NULL); 716 lib3270_ft_set_user_data(dialog->session,NULL);
717 - lib3270_ft_destroy(dialog->session); 717 + lib3270_ft_destroy(dialog->session,NULL);
718 } 718 }
719 719
720 g_signal_emit(GTK_WIDGET(dialog),v3270ftprogress_signal[V3270FTPROGRESS_SIGNAL_FAILED], 0, _( "Transfer failed" ), strerror(ETIMEDOUT)); 720 g_signal_emit(GTK_WIDGET(dialog),v3270ftprogress_signal[V3270FTPROGRESS_SIGNAL_FAILED], 0, _( "Transfer failed" ), strerror(ETIMEDOUT));
@@ -768,7 +768,7 @@ void v3270ftprogress_start_transfer(GtkWidget *widget) { @@ -768,7 +768,7 @@ void v3270ftprogress_start_transfer(GtkWidget *widget) {
768 768
769 if(!cbk) { 769 if(!cbk) {
770 770
771 - lib3270_ft_destroy(dialog->session); 771 + lib3270_ft_destroy(dialog->session,NULL);
772 g_signal_emit(GTK_WIDGET(widget),v3270ftprogress_signal[V3270FTPROGRESS_SIGNAL_FAILED], 0, _( "Can't set callback table" ), NULL); 772 g_signal_emit(GTK_WIDGET(widget),v3270ftprogress_signal[V3270FTPROGRESS_SIGNAL_FAILED], 0, _( "Can't set callback table" ), NULL);
773 773
774 return; 774 return;
src/filetransfer/worker.c
@@ -35,21 +35,20 @@ @@ -35,21 +35,20 @@
35 35
36 /*--[ Widget definition ]----------------------------------------------------------------------------*/ 36 /*--[ Widget definition ]----------------------------------------------------------------------------*/
37 37
38 - enum _SIGNALS 38 + typedef enum _V3270_WORKER_SIGNAL
39 { 39 {
40 - V3270_WORKER_ACTIVITY_SIGNAL, ///< @brief Indicates if the list has an activity set. 40 + V3270_WORKER_ACTIVITY_SIGNAL, ///< @brief Indicates if the list has an activity set.
  41 + V3270_WORKER_TRANSFER_FAILED_SIGNAL, ///< @brief Transfer has failed.
  42 + V3270_WORKER_TRANSFER_SUCCESS_SIGNAL, ///< @brief Transfer complete.
  43 + V3270_WORKER_TRANSFER_STATE_SIGNAL, ///< @brief Transfer state has changed.
41 44
42 V3270_WORKER_LAST_SIGNAL 45 V3270_WORKER_LAST_SIGNAL
43 - }; 46 + } V3270_WORKER_SIGNAL;
44 47
45 struct _V3270FTWorkerClass 48 struct _V3270FTWorkerClass
46 { 49 {
47 GtkGridClass parent_class; 50 GtkGridClass parent_class;
48 51
49 - struct  
50 - {  
51 - void (*activity)(GtkWidget *, GObject *);  
52 - } signal;  
53 52
54 }; 53 };
55 54
@@ -57,10 +56,20 @@ @@ -57,10 +56,20 @@
57 { 56 {
58 GtkGrid parent; 57 GtkGrid parent;
59 58
  59 + H3270 * hSession;
  60 +
60 GtkProgressBar * pbar; ///< @brief Progress bar. 61 GtkProgressBar * pbar; ///< @brief Progress bar.
61 GObject * activity; ///< @brief File transfer activity. 62 GObject * activity; ///< @brief File transfer activity.
62 GSource * pulse; ///< @brief Process pulse. 63 GSource * pulse; ///< @brief Process pulse.
63 64
  65 + struct
  66 + {
  67 + GSource * timer; ///< @brief Timeout timer.
  68 + time_t limit; ///< @brief Timestamp for timeout transfer.
  69 + time_t value; ///< @brief Timeout value.
  70 +
  71 + } timeout;
  72 +
64 GtkEntry * field[PROGRESS_FIELD_COUNT]; ///< @brief Transfer information widgets. 73 GtkEntry * field[PROGRESS_FIELD_COUNT]; ///< @brief Transfer information widgets.
65 74
66 }; 75 };
@@ -96,13 +105,30 @@ @@ -96,13 +105,30 @@
96 } 105 }
97 } 106 }
98 107
  108 + static void timer_stop(V3270FTWorker *worker)
  109 + {
  110 + if(worker->timeout.timer)
  111 + {
  112 + g_source_destroy(worker->timeout.timer);
  113 + worker->timeout.timer = NULL;
  114 + }
  115 + }
  116 +
99 static void finalize(GObject *object) 117 static void finalize(GObject *object)
100 { 118 {
101 debug("%s",__FUNCTION__); 119 debug("%s",__FUNCTION__);
102 120
103 V3270FTWorker * worker = GTK_V3270_FT_WORKER(object); 121 V3270FTWorker * worker = GTK_V3270_FT_WORKER(object);
104 122
  123 + if(worker->hSession)
  124 + {
  125 + lib3270_ft_set_user_data(worker->hSession,NULL);
  126 + lib3270_ft_destroy(worker->hSession,NULL);
  127 + worker->hSession = NULL;
  128 + }
  129 +
105 pulse_stop(worker); 130 pulse_stop(worker);
  131 + timer_stop(worker);
106 132
107 if(worker->activity) 133 if(worker->activity)
108 { 134 {
@@ -114,27 +140,45 @@ @@ -114,27 +140,45 @@
114 140
115 } 141 }
116 142
117 - static void V3270FTWorker_activity(GtkWidget G_GNUC_UNUSED(*widget), GObject G_GNUC_UNUSED(*activity))  
118 - {  
119 - debug("%s",__FUNCTION__);  
120 - }  
121 -  
122 static void V3270FTWorker_class_init(G_GNUC_UNUSED V3270FTWorkerClass *klass) 143 static void V3270FTWorker_class_init(G_GNUC_UNUSED V3270FTWorkerClass *klass)
123 { 144 {
124 GObjectClass * gobject_class = G_OBJECT_CLASS(klass); 145 GObjectClass * gobject_class = G_OBJECT_CLASS(klass);
125 146
126 gobject_class->finalize = finalize; 147 gobject_class->finalize = finalize;
127 148
128 - klass->signal.activity = V3270FTWorker_activity;  
129 -  
130 v3270_worker_signals[V3270_WORKER_ACTIVITY_SIGNAL] = 149 v3270_worker_signals[V3270_WORKER_ACTIVITY_SIGNAL] =
131 - g_signal_new( "activity",  
132 - G_OBJECT_CLASS_TYPE (gobject_class),  
133 - G_SIGNAL_RUN_FIRST,  
134 - G_STRUCT_OFFSET (V3270FTWorkerClass, signal.activity),  
135 - NULL, NULL,  
136 - v3270ft_VOID__VOID_OBJECT,  
137 - G_TYPE_NONE, 1, G_TYPE_OBJECT); 150 + g_signal_new(
  151 + "activity",
  152 + G_OBJECT_CLASS_TYPE (gobject_class),
  153 + G_SIGNAL_RUN_FIRST,
  154 + 0,
  155 + NULL, NULL,
  156 + v3270ft_VOID__VOID_OBJECT,
  157 + G_TYPE_NONE, 1, G_TYPE_OBJECT
  158 + );
  159 +
  160 + v3270_worker_signals[V3270_WORKER_TRANSFER_FAILED_SIGNAL] =
  161 + g_signal_new(
  162 + "failed",
  163 + G_OBJECT_CLASS_TYPE (gobject_class),
  164 + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
  165 + 0,
  166 + NULL, NULL,
  167 + v3270ft_VOID__POINTER_POINTER,
  168 + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER
  169 + );
  170 +
  171 + v3270_worker_signals[V3270_WORKER_TRANSFER_STATE_SIGNAL] =
  172 + g_signal_new(
  173 + "ft-state-changed",
  174 + G_OBJECT_CLASS_TYPE (gobject_class),
  175 + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
  176 + 0,
  177 + NULL, NULL,
  178 + v3270ft_VOID__UINT_POINTER,
  179 + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER
  180 + );
  181 +
138 182
139 } 183 }
140 184
@@ -162,6 +206,7 @@ @@ -162,6 +206,7 @@
162 gtk_grid_attach(GTK_GRID(grid),label,0,top,1,1); 206 gtk_grid_attach(GTK_GRID(grid),label,0,top,1,1);
163 207
164 widget->field[id] = GTK_ENTRY(gtk_entry_new()); 208 widget->field[id] = GTK_ENTRY(gtk_entry_new());
  209 + gtk_entry_set_alignment(widget->field[id],1);
165 210
166 gtk_grid_attach(GTK_GRID(grid),GTK_WIDGET(widget->field[id]),1,top,1,1); 211 gtk_grid_attach(GTK_GRID(grid),GTK_WIDGET(widget->field[id]),1,top,1,1);
167 212
@@ -169,6 +214,9 @@ @@ -169,6 +214,9 @@
169 214
170 static void V3270FTWorker_init(V3270FTWorker *widget) 215 static void V3270FTWorker_init(V3270FTWorker *widget)
171 { 216 {
  217 + // Set defaults.
  218 + widget->timeout.value = 10;
  219 +
172 // https://developer.gnome.org/hig/stable/visual-layout.html.en 220 // https://developer.gnome.org/hig/stable/visual-layout.html.en
173 gtk_grid_set_row_spacing(GTK_GRID(widget),6); 221 gtk_grid_set_row_spacing(GTK_GRID(widget),6);
174 gtk_grid_set_column_spacing(GTK_GRID(widget),12); 222 gtk_grid_set_column_spacing(GTK_GRID(widget),12);
@@ -240,6 +288,11 @@ @@ -240,6 +288,11 @@
240 288
241 V3270FTWorker * worker = GTK_V3270_FT_WORKER(widget); 289 V3270FTWorker * worker = GTK_V3270_FT_WORKER(widget);
242 290
  291 + if(worker->hSession)
  292 + {
  293 + lib3270_ft_destroy(worker->hSession,NULL);
  294 + }
  295 +
243 if(worker->activity) 296 if(worker->activity)
244 { 297 {
245 g_object_unref(worker->activity); 298 g_object_unref(worker->activity);
@@ -254,11 +307,16 @@ @@ -254,11 +307,16 @@
254 gtk_entry_set_text(worker->field[PROGRESS_FIELD_LOCAL],v3270_ft_activity_get_local_filename(activity)); 307 gtk_entry_set_text(worker->field[PROGRESS_FIELD_LOCAL],v3270_ft_activity_get_local_filename(activity));
255 gtk_entry_set_text(worker->field[PROGRESS_FIELD_REMOTE],v3270_ft_activity_get_remote_filename(activity)); 308 gtk_entry_set_text(worker->field[PROGRESS_FIELD_REMOTE],v3270_ft_activity_get_remote_filename(activity));
256 309
  310 + gtk_progress_bar_set_text(worker->pbar,_("Starting transfer"));
  311 + pulse_start(worker);
  312 +
257 } 313 }
258 else 314 else
259 { 315 {
260 gtk_entry_set_text(worker->field[PROGRESS_FIELD_LOCAL],""); 316 gtk_entry_set_text(worker->field[PROGRESS_FIELD_LOCAL],"");
261 gtk_entry_set_text(worker->field[PROGRESS_FIELD_REMOTE],""); 317 gtk_entry_set_text(worker->field[PROGRESS_FIELD_REMOTE],"");
  318 + pulse_stop(worker);
  319 +
262 } 320 }
263 321
264 for(ix = PROGRESS_FIELD_TOTAL; ix < PROGRESS_FIELD_COUNT; ix++) 322 for(ix = PROGRESS_FIELD_TOTAL; ix < PROGRESS_FIELD_COUNT; ix++)
@@ -266,10 +324,321 @@ @@ -266,10 +324,321 @@
266 gtk_entry_set_text(worker->field[ix],""); 324 gtk_entry_set_text(worker->field[ix],"");
267 } 325 }
268 326
269 - gtk_progress_bar_set_text(worker->pbar,_("Starting transfer"));  
270 - pulse_start(worker);  
271 -  
272 g_signal_emit(widget, v3270_worker_signals[V3270_WORKER_ACTIVITY_SIGNAL], 0, worker->activity); 327 g_signal_emit(widget, v3270_worker_signals[V3270_WORKER_ACTIVITY_SIGNAL], 0, worker->activity);
273 328
274 } 329 }
275 330
  331 + LIB3270_EXPORT void v3270_ft_worker_set_session(GtkWidget *widget, H3270 *hSession)
  332 + {
  333 + V3270FTWorker * worker = GTK_V3270_FT_WORKER(widget);
  334 + worker->hSession = hSession;
  335 +
  336 + }
  337 +
  338 + struct bg_complete
  339 + {
  340 + V3270FTWorker * worker;
  341 + V3270_WORKER_SIGNAL signal;
  342 + unsigned long length;
  343 + double kbytes_sec;
  344 + char msg[1];
  345 + };
  346 +
  347 + static gboolean bg_emit_complete(struct bg_complete * cfg)
  348 + {
  349 + // Try to get more detailed info.
  350 + const gchar * description = NULL;
  351 +
  352 + if(cfg->length)
  353 + {
  354 + gtk_entry_set_text_printf(cfg->worker->field[PROGRESS_FIELD_TOTAL],"%lu",cfg->length);
  355 + }
  356 + else
  357 + {
  358 + gtk_entry_set_text(cfg->worker->field[PROGRESS_FIELD_TOTAL],"");
  359 + }
  360 +
  361 + gtk_entry_set_text(cfg->worker->field[PROGRESS_FIELD_ETA],"");
  362 +
  363 +
  364 + const LIB3270_FT_MESSAGE * ftMessage = lib3270_translate_ft_message(cfg->msg);
  365 +
  366 + if(ftMessage)
  367 + {
  368 + description = ftMessage->description;
  369 + if(ftMessage->failed)
  370 + cfg->signal = V3270_WORKER_TRANSFER_FAILED_SIGNAL;
  371 +
  372 + }
  373 +
  374 + gtk_progress_bar_set_text(cfg->worker->pbar,cfg->msg);
  375 +
  376 + g_signal_emit(
  377 + GTK_WIDGET(cfg->worker),
  378 + v3270_worker_signals[cfg->signal],
  379 + 0,
  380 + cfg->msg,
  381 + description
  382 + );
  383 +
  384 + return FALSE;
  385 +
  386 + }
  387 +
  388 + static void ft_complete(H3270 G_GNUC_UNUSED(*hSession), unsigned long length, double kbytes_sec, const char *msg, void *widget)
  389 + {
  390 + struct bg_complete * state = g_malloc0(sizeof(struct bg_complete)+strlen(msg)+1);
  391 +
  392 + state->worker = GTK_V3270_FT_WORKER(widget);
  393 + state->signal = V3270_WORKER_TRANSFER_SUCCESS_SIGNAL;
  394 + state->length = length;
  395 + state->kbytes_sec = kbytes_sec;
  396 +
  397 + strcpy(state->msg,msg);
  398 +
  399 + pulse_stop(state->worker);
  400 + timer_stop(state->worker);
  401 +
  402 + gdk_threads_add_idle_full(G_PRIORITY_LOW,(GSourceFunc) bg_emit_complete, state, g_free);
  403 +
  404 + }
  405 +
  406 + static void ft_failed(H3270 G_GNUC_UNUSED(*hSession), unsigned long length, double kbytes_sec, const char *msg, void *widget)
  407 + {
  408 + debug("%s(%p,%s)",__FUNCTION__,widget,msg);
  409 +
  410 + struct bg_complete * state = g_malloc0(sizeof(struct bg_complete)+strlen(msg));
  411 + strcpy(state->msg,msg);
  412 +
  413 + state->worker = GTK_V3270_FT_WORKER(widget);
  414 + state->signal = V3270_WORKER_TRANSFER_FAILED_SIGNAL;
  415 + state->length = length;
  416 + state->kbytes_sec = kbytes_sec;
  417 +
  418 + gdk_threads_add_idle_full(G_PRIORITY_LOW,(GSourceFunc) bg_emit_complete, state, g_free);
  419 +
  420 + }
  421 +
  422 + static void ft_message(G_GNUC_UNUSED H3270 *hSession, const char *msg, void *widget)
  423 + {
  424 + V3270FTWorker * worker = GTK_V3270_FT_WORKER(widget);
  425 + debug("%s(%p,%s)",__FUNCTION__,worker,msg);
  426 +
  427 + gtk_progress_bar_set_text(worker->pbar,msg);
  428 +
  429 + }
  430 +
  431 + struct bg_update
  432 + {
  433 + V3270FTWorker * worker;
  434 + unsigned long current;
  435 + unsigned long total;
  436 + double kbytes_sec;
  437 + };
  438 +
  439 + static gboolean bg_emit_update(struct bg_update * update)
  440 + {
  441 + // Update values
  442 + gtk_entry_set_text_printf(update->worker->field[PROGRESS_FIELD_CURRENT],"%lu",update->current);
  443 + gtk_entry_set_text_printf(update->worker->field[PROGRESS_FIELD_TOTAL],"%lu",update->total);
  444 +
  445 + if(update->total)
  446 + {
  447 + // Calculate ETA
  448 + double remaining = ((double) (update->total - update->current))/1024.0;
  449 +
  450 + if(remaining > 0 && update->kbytes_sec > 0) {
  451 +
  452 + char buffer[40];
  453 + double seconds = ((double) remaining) / update->kbytes_sec;
  454 + time_t eta = time(NULL) + ((time_t) seconds);
  455 + strftime(buffer, 39, "%H:%M:%S", localtime(&eta));
  456 +
  457 + gtk_entry_set_text(update->worker->field[PROGRESS_FIELD_ETA],buffer);
  458 +
  459 + } else {
  460 +
  461 + gtk_entry_set_text(update->worker->field[PROGRESS_FIELD_ETA],"");
  462 +
  463 + }
  464 +
  465 + if(update->current)
  466 + {
  467 + // Update progress bar
  468 + pulse_stop(update->worker);
  469 + gtk_progress_bar_set_fraction(update->worker->pbar, ((gdouble) update->current) / ((gdouble) update->total));
  470 + }
  471 +
  472 + gtk_entry_set_text_printf(update->worker->field[PROGRESS_FIELD_ETA],"%lu",update->total);
  473 +
  474 + }
  475 +
  476 + return FALSE;
  477 + }
  478 +
  479 + static void ft_update(G_GNUC_UNUSED H3270 *hSession, unsigned long current, unsigned long total, double kbytes_sec, void *widget)
  480 + {
  481 + debug("%s(%p,%p)",__FUNCTION__,widget,widget);
  482 +
  483 + struct bg_update * update = g_new0(struct bg_update,1);
  484 +
  485 + update->worker = GTK_V3270_FT_WORKER(widget);
  486 + update->current = current;
  487 + update->total = total;
  488 + update->kbytes_sec = kbytes_sec;
  489 +
  490 + gdk_threads_add_idle_full(G_PRIORITY_LOW,(GSourceFunc) bg_emit_update, update, g_free);
  491 +
  492 + }
  493 +
  494 + static void ft_running(G_GNUC_UNUSED H3270 *hSession, G_GNUC_UNUSED int is_cut, void *widget)
  495 + {
  496 + V3270FTWorker * worker = GTK_V3270_FT_WORKER(widget);
  497 + debug("%s(%p,%p)",__FUNCTION__,worker,widget);
  498 +
  499 + // Reset timeout.
  500 + worker->timeout.limit = time(NULL) + worker->timeout.value;
  501 +
  502 + }
  503 +
  504 + static void ft_aborting(G_GNUC_UNUSED H3270 *hSession, const char *reason, void *widget)
  505 + {
  506 + V3270FTWorker * worker = GTK_V3270_FT_WORKER(widget);
  507 + debug("%s(%p,%p)",__FUNCTION__,worker,widget);
  508 +
  509 + gtk_progress_bar_set_text(worker->pbar,reason);
  510 +
  511 + }
  512 +
  513 + struct bg_state_changed
  514 + {
  515 + V3270FTWorker * worker;
  516 + LIB3270_FT_STATE st;
  517 + char msg[1];
  518 + };
  519 +
  520 + static gboolean bg_emit_state_changed(struct bg_state_changed * cfg)
  521 + {
  522 + g_signal_emit(cfg->worker, v3270_worker_signals[V3270_WORKER_TRANSFER_STATE_SIGNAL], 0, (guint) cfg->st, cfg->msg);
  523 + return FALSE;
  524 + }
  525 +
  526 + static void ft_state_changed(G_GNUC_UNUSED H3270 *hSession, LIB3270_FT_STATE st, const char *msg, void *widget)
  527 + {
  528 + debug("%s(%p,%s)",__FUNCTION__,widget,msg);
  529 +
  530 + struct bg_state_changed * state = g_malloc0(sizeof(struct bg_state_changed)+strlen(msg)+1);
  531 + state->worker = GTK_V3270_FT_WORKER(widget);
  532 + state->st = st;
  533 + strcpy(state->msg,msg);
  534 +
  535 + gdk_threads_add_idle_full(G_PRIORITY_LOW,(GSourceFunc) bg_emit_state_changed, state, g_free);
  536 +
  537 + }
  538 +
  539 +static gboolean do_timer(V3270FTWorker *worker) {
  540 +
  541 + debug("%d",(int) worker->timeout.limit - time(NULL));
  542 +
  543 + if(time(NULL) > worker->timeout.limit) {
  544 +
  545 + // Timeout.
  546 + debug("%s: Transfer timeout",__FUNCTION__);
  547 +
  548 + pulse_stop(worker);
  549 + timer_stop(worker);
  550 +
  551 + const gchar * message = _("Transfer operation has timed out");
  552 +
  553 + if(worker->hSession)
  554 + {
  555 + lib3270_ft_destroy(worker->hSession, message);
  556 + }
  557 + else
  558 + {
  559 + gtk_progress_bar_set_text(worker->pbar,message);
  560 +
  561 + g_signal_emit(
  562 + GTK_WIDGET(worker),
  563 + v3270_worker_signals[V3270_WORKER_TRANSFER_FAILED_SIGNAL],
  564 + 0,
  565 + _( "Transfer failed" ),
  566 + message
  567 + );
  568 +
  569 + }
  570 + }
  571 +
  572 + return TRUE;
  573 + }
  574 +
  575 + LIB3270_EXPORT int v3270_ft_worker_start(GtkWidget *widget)
  576 + {
  577 + V3270FTWorker * worker = GTK_V3270_FT_WORKER(widget);
  578 +
  579 + if(!(worker->hSession && worker->activity))
  580 + return errno = EINVAL;
  581 +
  582 + const char *message = NULL;
  583 + H3270FT * ft = v3270_ft_activity_begin_transfer(worker->activity, worker->hSession, &message);
  584 +
  585 + if(!ft)
  586 + {
  587 + if(!message)
  588 + message = N_("Can't start file transfer session");
  589 +
  590 + gtk_progress_bar_set_text(worker->pbar,gettext(message));
  591 +
  592 + pulse_stop(worker);
  593 + g_signal_emit(GTK_WIDGET(widget),v3270_worker_signals[V3270_WORKER_TRANSFER_FAILED_SIGNAL], 0, gettext(message), NULL);
  594 +
  595 + return -1;
  596 + }
  597 +
  598 + struct lib3270_ft_callbacks * cbk = lib3270_get_ft_callbacks(worker->hSession, sizeof(struct lib3270_ft_callbacks));
  599 +
  600 + if(!cbk) {
  601 +
  602 + gchar *message = _( "Can't set callback table" );
  603 +
  604 + lib3270_ft_destroy(worker->hSession,message);
  605 +
  606 + gtk_progress_bar_set_text(worker->pbar,message);
  607 + pulse_stop(worker);
  608 +
  609 + g_signal_emit(
  610 + GTK_WIDGET(widget),
  611 + v3270_worker_signals[V3270_WORKER_TRANSFER_FAILED_SIGNAL],
  612 + 0,
  613 + message,
  614 + _("The callback table for file transfer was rejected, possible version mismatch on lib3270")
  615 + );
  616 +
  617 + return -1;
  618 + }
  619 +
  620 + debug("*************************************worker=%p",widget);
  621 + lib3270_ft_set_user_data(worker->hSession,widget);
  622 +
  623 + cbk->complete = ft_complete;
  624 + cbk->failed = ft_failed;
  625 + cbk->update = ft_update;
  626 + cbk->running = ft_running;
  627 + cbk->aborting = ft_aborting;
  628 + cbk->state_changed = ft_state_changed;
  629 + cbk->message = ft_message;
  630 +
  631 + worker->timeout.limit = time(NULL) + worker->timeout.value;
  632 +
  633 + if(!worker->timeout.timer)
  634 + {
  635 + worker->timeout.timer = g_timeout_source_new_seconds(1);
  636 + g_source_set_callback(worker->timeout.timer,(GSourceFunc) do_timer,worker,NULL);
  637 + g_source_attach(worker->timeout.timer,NULL);
  638 + }
  639 +
  640 + lib3270_ft_start(worker->hSession);
  641 +
  642 + return 0;
  643 + }
  644 +
src/include/internals.h
@@ -78,6 +78,8 @@ @@ -78,6 +78,8 @@
78 G_GNUC_INTERNAL void v3270_activity_list_save(GtkWidget *widget); 78 G_GNUC_INTERNAL void v3270_activity_list_save(GtkWidget *widget);
79 G_GNUC_INTERNAL void v3270_activity_list_save_as(GtkWidget *widget); 79 G_GNUC_INTERNAL void v3270_activity_list_save_as(GtkWidget *widget);
80 80
  81 + G_GNUC_INTERNAL void gtk_entry_set_text_printf(GtkEntry *entry, const gchar *fmt, ...);
  82 +
81 G_END_DECLS 83 G_END_DECLS
82 84
83 #endif // V3270_INTERNALS_H_INCLUDED 85 #endif // V3270_INTERNALS_H_INCLUDED
src/include/v3270/filetransfer.h
@@ -129,6 +129,7 @@ @@ -129,6 +129,7 @@
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);
130 LIB3270_EXPORT void v3270_ft_activity_set_options(GObject * object, LIB3270_FT_OPTION options); 130 LIB3270_EXPORT void v3270_ft_activity_set_options(GObject * object, LIB3270_FT_OPTION options);
131 LIB3270_EXPORT void v3270_ft_activity_set_value(GObject * object, LIB3270_FT_VALUE id, guint value); 131 LIB3270_EXPORT void v3270_ft_activity_set_value(GObject * object, LIB3270_FT_VALUE id, guint value);
  132 + LIB3270_EXPORT H3270FT * v3270_ft_activity_begin_transfer(GObject * object, H3270 *hSession, const char **message);
132 133
133 // FT Dialog widget 134 // FT Dialog widget
134 #define GTK_TYPE_V3270_FT_DIALOG (V3270FTDialog_get_type ()) 135 #define GTK_TYPE_V3270_FT_DIALOG (V3270FTDialog_get_type ())
@@ -159,5 +160,7 @@ @@ -159,5 +160,7 @@
159 160
160 LIB3270_EXPORT GtkWidget * v3270_ft_worker_new(); 161 LIB3270_EXPORT GtkWidget * v3270_ft_worker_new();
161 LIB3270_EXPORT void v3270_ft_worker_set_activity(GtkWidget *widget, GObject *activity); 162 LIB3270_EXPORT void v3270_ft_worker_set_activity(GtkWidget *widget, GObject *activity);
  163 + LIB3270_EXPORT void v3270_ft_worker_set_session(GtkWidget *widget, H3270 *hSession);
  164 + LIB3270_EXPORT int v3270_ft_worker_start(GtkWidget *widget);
162 165
163 #endif // V3270FT_H_INCLUDED 166 #endif // V3270FT_H_INCLUDED
src/testprogram/testprogram.c
@@ -153,12 +153,17 @@ static void ft_clicked(GtkButton G_GNUC_UNUSED(*button), GtkWidget *terminal) @@ -153,12 +153,17 @@ static void ft_clicked(GtkButton G_GNUC_UNUSED(*button), GtkWidget *terminal)
153 GtkWidget * worker = v3270_ft_worker_new(); 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); 154 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),worker,TRUE,TRUE,2);
155 155
  156 + v3270_ft_worker_set_session(worker,v3270_get_session(terminal));
  157 +
156 GObject * activity = v3270_ft_activity_new(); 158 GObject * activity = v3270_ft_activity_new();
157 - v3270_ft_activity_set_local_filename(activity,"local_file");  
158 - v3270_ft_activity_set_remote_filename(activity,"remove_file"); 159 + v3270_ft_activity_set_local_filename(activity,"/tmp/test.txt");
  160 + 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_worker_set_activity(worker,activity); 162 v3270_ft_worker_set_activity(worker,activity);
160 g_object_unref(activity); 163 g_object_unref(activity);
161 164
  165 + v3270_ft_worker_start(worker);
  166 +
162 // GtkWidget * dialog = v3270ftprogress_new(); 167 // GtkWidget * dialog = v3270ftprogress_new();
163 // GtkWidget * dialog = v3270_ft_dialog_new(terminal); 168 // GtkWidget * dialog = v3270_ft_dialog_new(terminal);
164 169