1 /*
2 * TilEm II
3 *
4 * Copyright (c) 2010-2011 Thibault Duponchelle
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <gtk/gtk.h>
29 #include <glib/gstdio.h>
30 #include <ticalcs.h>
31 #include <ticonv.h>
32 #include <tilem.h>
33 #include <tilemdb.h>
34 #include <scancodes.h>
35
36 #include "gui.h"
37 #include "disasmview.h"
38 #include "memmodel.h"
39 #include "files.h"
40 #include "filedlg.h"
41 #include "msgbox.h"
42 #include "fixedtreeview.h"
43
44 static GtkTreeModel* fill_varlist(TilemReceiveDialog *rcvdialog);
45 TilemReceiveDialog* create_receive_menu(TilemCalcEmulator *emu);
46
47 /* Columns */
48 enum
49 {
50 COL_ENTRY = 0,
51 COL_SLOT_STR,
52 COL_NAME_STR,
53 COL_TYPE_STR,
54 COL_SIZE_STR,
55 COL_SIZE,
56 NUM_COLS
57 };
58
59 #define RESPONSE_REFRESH 1
60
61 /* Prompt to overwrite a list of files. */
prompt_overwrite(GtkWindow * win,const char * dirname,char ** filenames)62 static gboolean prompt_overwrite(GtkWindow *win, const char *dirname,
63 char **filenames)
64 {
65 int i;
66 char *dname;
67 GString *conflicts = NULL;
68 int nconflicts = 0;
69 GtkWidget *dlg, *btn;
70 int response;
71
72 for (i = 0; filenames[i]; i++) {
73 if (g_file_test(filenames[i], G_FILE_TEST_EXISTS)) {
74 if (conflicts)
75 g_string_append_c(conflicts, '\n');
76 else
77 conflicts = g_string_new(NULL);
78 dname = g_filename_display_basename(filenames[i]);
79 g_string_append(conflicts, dname);
80 g_free(dname);
81 nconflicts++;
82 }
83 }
84
85 if (!conflicts)
86 return TRUE;
87
88 dname = g_filename_display_basename(dirname);
89
90 dlg = gtk_message_dialog_new
91 (win, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
92 (nconflicts == 1
93 ? "Replace existing file?"
94 : "Replace existing files?"));
95
96 gtk_message_dialog_format_secondary_text
97 (GTK_MESSAGE_DIALOG(dlg),
98 (nconflicts == 1
99 ? "The file \"%2$s\" already exists in \"%1$s\"."
100 " Replacing it will overwrite its contents."
101 : "The following files already exist in \"%s\"."
102 " Replacing them will overwrite their contents:\n%s"),
103 dname, conflicts->str);
104
105 g_free(dname);
106 g_string_free(conflicts, TRUE);
107
108 gtk_dialog_add_button(GTK_DIALOG(dlg),
109 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
110
111 btn = gtk_button_new_with_mnemonic("_Replace");
112 gtk_button_set_image(GTK_BUTTON(btn),
113 gtk_image_new_from_stock(GTK_STOCK_SAVE,
114 GTK_ICON_SIZE_BUTTON));
115 gtk_widget_show(btn);
116 gtk_dialog_add_action_widget(GTK_DIALOG(dlg), btn,
117 GTK_RESPONSE_ACCEPT);
118
119 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg),
120 GTK_RESPONSE_ACCEPT,
121 GTK_RESPONSE_CANCEL,
122 -1);
123
124 response = gtk_dialog_run(GTK_DIALOG(dlg));
125 gtk_widget_destroy(dlg);
126 return (response == GTK_RESPONSE_ACCEPT);
127 }
128
129 /* #### SIGNALS CALLBACK #### */
130
131 /* Prompt to save a single file. */
prompt_save_single(TilemReceiveDialog * rcvdialog,TilemVarEntry * tve)132 static gboolean prompt_save_single(TilemReceiveDialog *rcvdialog, TilemVarEntry *tve)
133 {
134 char *dir, *default_filename, *default_filename_r, *filename, *pattern;
135
136 default_filename = get_default_filename(tve);
137 default_filename_r = utf8_to_restricted_utf8(default_filename);
138 g_free(default_filename);
139
140 tilem_config_get("download", "receivefile_recentdir/f", &dir, NULL);
141 if (!dir) dir = g_get_current_dir();
142
143 pattern = g_strconcat("*.", tve->file_ext, NULL);
144
145 filename = prompt_save_file("Save File", GTK_WINDOW(rcvdialog->window),
146 default_filename_r, dir,
147 tve->filetype_desc, pattern,
148 "All files", "*",
149 NULL);
150 g_free(default_filename_r);
151 g_free(pattern);
152 g_free(dir);
153
154 if (!filename)
155 return FALSE;
156
157 dir = g_path_get_dirname(filename);
158 tilem_config_set("download", "receivefile_recentdir/f", dir, NULL);
159 g_free(dir);
160
161 tilem_link_receive_file(rcvdialog->emu, tve, filename);
162 g_free(filename);
163 return TRUE;
164 }
165
166 /* Prompt to save a list of variables as a group file. */
prompt_save_group(TilemReceiveDialog * rcvdialog,GList * rows)167 static gboolean prompt_save_group(TilemReceiveDialog *rcvdialog, GList *rows)
168 {
169 char *dir, *default_filename, *pattern_desc, *pattern, *filename, *fext;
170 int tfmodel;
171 gboolean can_group = TRUE;
172 const char *model_str;
173 GList *l;
174 GtkTreePath *path;
175 GtkTreeIter iter;
176 TilemVarEntry *tve;
177 GSList *velist = NULL;
178
179 tilem_config_get("download", "receivefile_recentdir/f", &dir, NULL);
180 if (!dir) dir = g_get_current_dir();
181
182 for (l = rows; l; l = l->next) {
183 path = (GtkTreePath*) l->data;
184 gtk_tree_model_get_iter(rcvdialog->model, &iter, path);
185 gtk_tree_model_get(rcvdialog->model, &iter, COL_ENTRY, &tve, -1);
186 velist = g_slist_prepend(velist, tve);
187 if (!tve->can_group)
188 can_group = FALSE;
189 }
190
191 velist = g_slist_reverse(velist);
192
193 tfmodel = get_calc_model(rcvdialog->emu->calc);
194
195 fext = g_ascii_strdown(tifiles_fext_of_group(tfmodel), -1);
196 pattern = g_strconcat("*.", fext, NULL);
197 default_filename = g_strdup_printf("untitled.%s",
198 (can_group ? fext : "tig"));
199 g_free(fext);
200
201 model_str = tifiles_model_to_string(tfmodel);
202 pattern_desc = g_strdup_printf("%s group files", model_str);
203
204 filename = prompt_save_file("Save File", GTK_WINDOW(rcvdialog->window),
205 default_filename, dir,
206 pattern_desc, (can_group ? pattern : ""),
207 "TIGroup files", "*.tig",
208 "All files", "*",
209 NULL);
210
211 g_free(default_filename);
212 g_free(dir);
213 g_free(pattern_desc);
214 g_free(pattern);
215
216 if (!filename) {
217 g_slist_free(velist);
218 return FALSE;
219 }
220
221 dir = g_path_get_dirname(filename);
222 tilem_config_set("download",
223 "receivefile_recentdir/f", dir,
224 "save_as_group/b", TRUE,
225 NULL);
226 g_free(dir);
227
228 tilem_link_receive_group(rcvdialog->emu, velist, filename);
229
230 g_free(filename);
231 g_slist_free(velist);
232 return TRUE;
233 }
234
235 /* Prompt to save a list of files. Input is a list of GtkTreePaths */
prompt_save_multiple(TilemReceiveDialog * rcvdialog,GList * rows)236 static gboolean prompt_save_multiple(TilemReceiveDialog *rcvdialog, GList *rows)
237 {
238 char *dir, *dir_selected, *default_filename, *default_filename_f;
239 GList *l;
240 GtkTreePath *path;
241 GtkTreeIter iter;
242 TilemVarEntry *tve, **vars;
243 char **names;
244 gboolean is_81, use_group;
245 int i;
246
247 is_81 = (rcvdialog->emu->calc->hw.model_id == TILEM_CALC_TI81);
248 use_group = gtk_toggle_button_get_active
249 (GTK_TOGGLE_BUTTON(rcvdialog->group_rb));
250
251 if (use_group && !is_81)
252 return prompt_save_group(rcvdialog, rows);
253
254 tilem_config_get("download", "receivefile_recentdir/f", &dir, NULL);
255 if (!dir) dir = g_get_current_dir();
256
257 dir_selected = prompt_select_dir("Save Files to Directory",
258 GTK_WINDOW(rcvdialog->window),
259 dir);
260 g_free(dir);
261
262 if (!dir_selected)
263 return FALSE;
264
265 tilem_config_set("download",
266 "receivefile_recentdir/f", dir_selected,
267 "save_as_group/b", use_group,
268 NULL);
269
270 vars = g_new(TilemVarEntry *, g_list_length(rows) + 1);
271 names = g_new(char *, g_list_length(rows) + 1);
272
273 for (l = rows, i = 0; l; l = l->next, i++) {
274 path = (GtkTreePath*) l->data;
275 gtk_tree_model_get_iter(rcvdialog->model, &iter, path);
276 gtk_tree_model_get(rcvdialog->model, &iter, COL_ENTRY, &tve, -1);
277
278 vars[i] = tve;
279
280 default_filename = get_default_filename(tve);
281 default_filename_f = utf8_to_filename(default_filename);
282 names[i] = g_build_filename(dir_selected,
283 default_filename_f, NULL);
284 g_free(default_filename);
285 g_free(default_filename_f);
286 }
287
288 vars[i] = NULL;
289 names[i] = NULL;
290
291 if (!prompt_overwrite(GTK_WINDOW(rcvdialog->window),
292 dir_selected, names)) {
293 g_free(vars);
294 g_strfreev(names);
295 g_free(dir_selected);
296 return FALSE;
297 }
298
299 for (i = 0; vars[i]; i++)
300 tilem_link_receive_file(rcvdialog->emu, vars[i], names[i]);
301
302 g_free(vars);
303 g_strfreev(names);
304 g_free(dir_selected);
305 return TRUE;
306 }
307
308 /* Event called on Send button click. Get the selected var/app and save it. */
prompt_save(TilemReceiveDialog * rcvdialog)309 static gboolean prompt_save(TilemReceiveDialog *rcvdialog)
310 {
311 TilemVarEntry *tve; /* Variable entry */
312 GtkTreeSelection* selection = NULL; /* GtkTreeSelection */
313 GtkTreeModel *model;
314 GtkTreeIter iter;
315 GList *rows, *l;
316 GtkTreePath *path;
317 gboolean status;
318
319 /* Get the selected entry */
320 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(rcvdialog->treeview));
321 rows = gtk_tree_selection_get_selected_rows(selection, &model);
322
323 if (!rows)
324 return FALSE;
325
326 if (!rows->next) {
327 path = (GtkTreePath*) rows->data;
328 gtk_tree_model_get_iter(model, &iter, path);
329 gtk_tree_model_get(model, &iter, COL_ENTRY, &tve, -1);
330 status = prompt_save_single(rcvdialog, tve);
331 }
332 else {
333 status = prompt_save_multiple(rcvdialog, rows);
334 }
335
336 for (l = rows; l; l = l->next)
337 gtk_tree_path_free(l->data);
338 g_list_free(rows);
339 return status;
340 }
341
342 /* Dialog response button clicked */
dialog_response(GtkDialog * dlg,gint response,gpointer data)343 static void dialog_response(GtkDialog *dlg, gint response, gpointer data)
344 {
345 TilemReceiveDialog* rcvdialog = (TilemReceiveDialog*) data;
346
347 switch (response) {
348 case RESPONSE_REFRESH:
349 if (!rcvdialog->refresh_pending) {
350 rcvdialog->refresh_pending = TRUE;
351 tilem_link_get_dirlist(rcvdialog->emu);
352 }
353 break;
354
355 case GTK_RESPONSE_ACCEPT:
356 if (!prompt_save(rcvdialog))
357 break;
358 default:
359 gtk_widget_hide(GTK_WIDGET(dlg));
360 }
361 }
362
363 /* Selection changed */
selection_changed(GtkTreeSelection * sel,gpointer data)364 static void selection_changed(GtkTreeSelection *sel, gpointer data)
365 {
366 TilemReceiveDialog* rcvdialog = data;
367 int n = gtk_tree_selection_count_selected_rows(sel);
368
369 gtk_dialog_set_response_sensitive(GTK_DIALOG(rcvdialog->window),
370 GTK_RESPONSE_ACCEPT, (n > 0));
371 gtk_widget_set_sensitive(rcvdialog->mode_box, (n > 1));
372 }
373
374 /* Row activated in tree view */
row_activated(G_GNUC_UNUSED GtkTreeView * treeview,G_GNUC_UNUSED GtkTreePath * path,G_GNUC_UNUSED GtkTreeViewColumn * col,gpointer data)375 static void row_activated(G_GNUC_UNUSED GtkTreeView *treeview,
376 G_GNUC_UNUSED GtkTreePath *path,
377 G_GNUC_UNUSED GtkTreeViewColumn *col,
378 gpointer data)
379 {
380 TilemReceiveDialog* rcvdialog = (TilemReceiveDialog*) data;
381 gtk_dialog_response(GTK_DIALOG(rcvdialog->window), GTK_RESPONSE_ACCEPT);
382 }
383
384 /* #### WIDGET CREATION #### */
385
386 /* Create a new scrolled window with sensible default settings. */
new_scrolled_window(GtkWidget * contents)387 static GtkWidget *new_scrolled_window(GtkWidget *contents)
388 {
389 GtkWidget *sw;
390 sw = gtk_scrolled_window_new(NULL, NULL);
391 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
392 GTK_POLICY_NEVER,
393 GTK_POLICY_AUTOMATIC);
394 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
395 GTK_SHADOW_IN);
396 gtk_container_add(GTK_CONTAINER(sw), contents);
397 return sw;
398 }
399
400 /* Create the (empty) GtkTreeView to show the vars list */
create_varlist(TilemReceiveDialog * rcvdialog)401 static GtkWidget *create_varlist(TilemReceiveDialog *rcvdialog)
402 {
403 GtkCellRenderer *renderer;
404 GtkWidget *treeview;
405 GtkTreeSelection *sel;
406 GtkTreeViewColumn *c1, *c2, *c3, *c4;
407 gboolean is_81;
408
409 g_return_val_if_fail(rcvdialog->emu != NULL, NULL);
410 g_return_val_if_fail(rcvdialog->emu->calc != NULL, NULL);
411
412 is_81 = (rcvdialog->emu->calc->hw.model_id == TILEM_CALC_TI81);
413
414 /* Create the stack list tree view and set title invisible */
415 treeview = gtk_tree_view_new();
416 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
417 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview), TRUE);
418 gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), TRUE);
419
420 /* Allow multiple selection */
421 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
422 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
423
424 /* Create the columns */
425 renderer = gtk_cell_renderer_text_new();
426
427 if (is_81) {
428 c1 = gtk_tree_view_column_new_with_attributes
429 ("Slot", renderer, "text", COL_SLOT_STR, NULL);
430
431 gtk_tree_view_column_set_sizing(c1, GTK_TREE_VIEW_COLUMN_FIXED);
432 gtk_tree_view_column_set_sort_column_id(c1, COL_SLOT_STR);
433 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), c1);
434 }
435
436 c2 = gtk_tree_view_column_new_with_attributes
437 ("Name", renderer, "text", COL_NAME_STR, NULL);
438
439 gtk_tree_view_column_set_sizing(c2, GTK_TREE_VIEW_COLUMN_FIXED);
440 gtk_tree_view_column_set_sort_column_id(c2, COL_NAME_STR);
441 gtk_tree_view_column_set_expand(c2, TRUE);
442 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), c2);
443
444 if (!is_81) {
445 c3 = gtk_tree_view_column_new_with_attributes
446 ("Type", renderer, "text", COL_TYPE_STR, NULL);
447
448 gtk_tree_view_column_set_sizing(c3, GTK_TREE_VIEW_COLUMN_FIXED);
449 gtk_tree_view_column_set_sort_column_id(c3, COL_TYPE_STR);
450 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), c3);
451 }
452
453 renderer = gtk_cell_renderer_text_new();
454 g_object_set(renderer, "xalign", 1.0, NULL);
455 c4 = gtk_tree_view_column_new_with_attributes
456 ("Size", renderer, "text", COL_SIZE_STR, NULL);
457
458 gtk_tree_view_column_set_sizing(c4, GTK_TREE_VIEW_COLUMN_FIXED);
459 gtk_tree_view_column_set_sort_column_id(c4, COL_SIZE);
460 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), c4);
461
462 g_signal_connect(sel, "changed",
463 G_CALLBACK(selection_changed), rcvdialog);
464
465 g_signal_connect(treeview, "row-activated",
466 G_CALLBACK(row_activated), rcvdialog);
467
468 return treeview;
469 }
470
471 /* Fill the list of vars. In fact, add all vars from list to a GtkListStore */
fill_varlist(TilemReceiveDialog * rcvdialog)472 static GtkTreeModel* fill_varlist(TilemReceiveDialog *rcvdialog)
473 {
474 GSList *l;
475 TilemVarEntry *tve;
476 GtkListStore *store;
477 GtkTreeIter iter;
478 char *size_str;
479
480 store = gtk_list_store_new(6,
481 G_TYPE_POINTER,
482 G_TYPE_STRING,
483 G_TYPE_STRING,
484 G_TYPE_STRING,
485 G_TYPE_STRING,
486 G_TYPE_INT);
487
488 for (l = rcvdialog->vars; l; l = l->next) {
489 tve = l->data;
490 gtk_list_store_append(store, &iter);
491 #ifdef G_OS_WIN32
492 size_str = g_strdup_printf("%d", tve->size);
493 #else
494 size_str = g_strdup_printf("%'d", tve->size);
495 #endif
496 gtk_list_store_set(store, &iter,
497 COL_ENTRY, tve,
498 COL_SLOT_STR, tve->slot_str,
499 COL_NAME_STR, tve->name_str,
500 COL_TYPE_STR, tve->type_str,
501 COL_SIZE_STR, size_str,
502 COL_SIZE, tve->size,
503 -1);
504 g_free(size_str);
505 }
506
507 return GTK_TREE_MODEL(store);
508 }
509
510 /* Create a new menu for receiving vars. */
511 /* Previous allocated and filled varlist is needed */
tilem_receive_dialog_new(TilemCalcEmulator * emu)512 TilemReceiveDialog* tilem_receive_dialog_new(TilemCalcEmulator *emu)
513 {
514 TilemReceiveDialog* rcvdialog = g_slice_new0(TilemReceiveDialog);
515 GtkWidget *scroll, *btn, *vbox, *lbl, *rb, *vbox2;
516 int defheight = 300;
517 gboolean is_81;
518 gboolean use_group;
519
520 g_return_val_if_fail(emu != NULL, NULL);
521 g_return_val_if_fail(emu->ewin != NULL, NULL);
522 g_return_val_if_fail(emu->calc != NULL, NULL);
523
524 rcvdialog->emu = emu;
525 emu->rcvdlg = rcvdialog;
526
527 is_81 = (emu->calc->hw.model_id == TILEM_CALC_TI81);
528
529 rcvdialog->window = gtk_dialog_new();
530 gtk_window_set_transient_for(GTK_WINDOW(rcvdialog->window),
531 GTK_WINDOW(emu->ewin->window));
532
533 gtk_window_set_title(GTK_WINDOW(rcvdialog->window), "Receive File");
534
535 btn = gtk_dialog_add_button(GTK_DIALOG(rcvdialog->window),
536 GTK_STOCK_REFRESH, RESPONSE_REFRESH);
537
538 if (is_81)
539 gtk_widget_hide(btn);
540
541 gtk_dialog_add_button(GTK_DIALOG(rcvdialog->window),
542 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
543 gtk_dialog_add_button(GTK_DIALOG(rcvdialog->window),
544 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
545
546 gtk_dialog_set_default_response(GTK_DIALOG(rcvdialog->window),
547 GTK_RESPONSE_ACCEPT);
548 gtk_dialog_set_alternative_button_order(GTK_DIALOG(rcvdialog->window),
549 RESPONSE_REFRESH,
550 GTK_RESPONSE_ACCEPT,
551 GTK_RESPONSE_CANCEL,
552 -1);
553
554 /* Set the size of the dialog */
555 gtk_window_set_default_size(GTK_WINDOW(rcvdialog->window), -1, defheight);
556
557 /* Create and fill tree view */
558 rcvdialog->treeview = create_varlist(rcvdialog);
559
560 /* Allow scrolling the list because we can't know how many vars the calc contains */
561 scroll = new_scrolled_window(rcvdialog->treeview);
562
563 vbox = gtk_vbox_new(FALSE, 6);
564 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
565 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(scroll), TRUE, TRUE, 0);
566
567 rcvdialog->mode_box = gtk_hbox_new(FALSE, 6);
568 lbl = gtk_label_new("Save as:");
569 gtk_box_pack_start(GTK_BOX(rcvdialog->mode_box), lbl, FALSE, FALSE, 0);
570
571 rb = gtk_radio_button_new_with_mnemonic(NULL, "S_eparate files");
572 gtk_box_pack_start(GTK_BOX(rcvdialog->mode_box), rb, FALSE, FALSE, 0);
573 rcvdialog->multiple_rb = rb;
574
575 rb = gtk_radio_button_new_with_mnemonic_from_widget
576 (GTK_RADIO_BUTTON(rb), "_Group file");
577 gtk_box_pack_start(GTK_BOX(rcvdialog->mode_box), rb, FALSE, FALSE, 0);
578 rcvdialog->group_rb = rb;
579
580 tilem_config_get("download", "save_as_group/b=1", &use_group, NULL);
581 if (use_group)
582 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), TRUE);
583
584 if (is_81)
585 gtk_widget_set_no_show_all(rcvdialog->mode_box, TRUE);
586
587 gtk_box_pack_start(GTK_BOX(vbox), rcvdialog->mode_box, FALSE, FALSE, 0);
588 vbox2 = gtk_dialog_get_content_area(GTK_DIALOG(rcvdialog->window));
589 gtk_box_pack_start(GTK_BOX(vbox2), vbox, TRUE, TRUE, 0);
590
591 /* Signals callback */
592 g_signal_connect(rcvdialog->window, "response",
593 G_CALLBACK(dialog_response), rcvdialog);
594 g_signal_connect(rcvdialog->window, "delete-event",
595 G_CALLBACK(gtk_widget_hide_on_delete), NULL);
596
597 gtk_widget_show_all(vbox);
598
599 return rcvdialog;
600 }
601
602 /* Destroy a TilemReceiveDialog */
tilem_receive_dialog_free(TilemReceiveDialog * rcvdialog)603 void tilem_receive_dialog_free(TilemReceiveDialog *rcvdialog)
604 {
605 GSList *l;
606
607 g_return_if_fail(rcvdialog != NULL);
608
609 gtk_widget_destroy(rcvdialog->window);
610
611 for (l = rcvdialog->vars; l; l = l->next)
612 tilem_var_entry_free(l->data);
613 g_slist_free(rcvdialog->vars);
614
615 g_slice_free(TilemReceiveDialog, rcvdialog);
616 }
617
tilem_receive_dialog_update(TilemReceiveDialog * rcvdialog,GSList * varlist)618 void tilem_receive_dialog_update(TilemReceiveDialog *rcvdialog, GSList *varlist)
619 {
620 GSList *l;
621
622 g_return_if_fail(rcvdialog != NULL);
623
624 rcvdialog->refresh_pending = FALSE;
625
626 for (l = rcvdialog->vars; l; l = l->next)
627 tilem_var_entry_free(l->data);
628 g_slist_free(rcvdialog->vars);
629
630 rcvdialog->vars = varlist;
631 rcvdialog->model = fill_varlist(rcvdialog);
632 gtk_tree_view_set_model(GTK_TREE_VIEW(rcvdialog->treeview), rcvdialog->model);
633
634 fixed_tree_view_init(rcvdialog->treeview, 0,
635 COL_SLOT_STR, "PrgmM ",
636 COL_NAME_STR, "MMMMMMMMM ",
637 COL_TYPE_STR, "MMMMMM ",
638 COL_SIZE_STR, "00,000,000",
639 -1);
640
641 gtk_widget_grab_focus(rcvdialog->treeview);
642 gtk_window_present(GTK_WINDOW(rcvdialog->window));
643 }
644
645 /* Popup the receive window */
646 /* This is the entry point */
popup_receive_menu(TilemEmulatorWindow * ewin)647 void popup_receive_menu(TilemEmulatorWindow *ewin)
648 {
649 g_return_if_fail(ewin != NULL);
650 g_return_if_fail(ewin->emu != NULL);
651 g_return_if_fail(ewin->emu->calc != NULL);
652
653 if (ewin->emu->rcvdlg && ewin->emu->rcvdlg->refresh_pending)
654 return;
655
656 /* TI-81 takes no time to refresh, so do it automatically */
657 if (!ewin->emu->rcvdlg
658 || ewin->emu->calc->hw.model_id == TILEM_CALC_TI81) {
659 tilem_link_get_dirlist(ewin->emu);
660 }
661 else {
662 gtk_widget_grab_focus(ewin->emu->rcvdlg->treeview);
663 gtk_window_present(GTK_WINDOW(ewin->emu->rcvdlg->window));
664 }
665 }
666