gtk-all.h, util-gtk.h: cosmetix (ignore this headers if built without GTK)
[k8lowj.git] / src / manager.c
blobce11ff6a1e8e00c906766e51ad04e31084032913
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
5 */
7 #include "gtk-all.h"
8 #include <stdlib.h>
9 #include "util-gtk.h"
10 #include "account.h"
12 #include "conf.h"
13 #include "tie.h"
14 #include "checkfriends.h"
15 #include "security.h"
16 #include "groupedbox.h"
17 #include "util.h"
19 /* manager:
20 * - host
21 * - account
22 * - (entries, outbox, etc?)
25 typedef struct _ManagerUI ManagerUI;
26 typedef struct _AccountUI AccountUI;
28 struct _ManagerUI {
29 GtkWidget *win;
31 GtkTreeStore *store;
32 GtkWidget *treeview;
34 GSList *pixbuf_names;
35 GSList *pixbufs;
37 GtkWidget *add;
38 GtkWidget *edit;
39 GtkWidget *del;
41 GtkWidget *filterlabel;
42 gpointer selection;
45 enum {
46 COL_ICON,
47 COL_TEXT,
48 COL_ISHOST,
49 COL_DATA,
50 COL_COUNT
53 static GdkPixbuf*
54 get_pixbuf(ManagerUI *mui, const char *stockid) {
55 int i;
56 GSList *l;
57 GdkPixbuf *pixbuf;
59 for (i = 0, l = mui->pixbuf_names; l; i++, l = l->next) {
60 if (strcmp(l->data, stockid) == 0)
61 return g_slist_nth(mui->pixbufs, i)->data;
64 pixbuf = gtk_widget_render_icon(mui->treeview, stockid,
65 GTK_ICON_SIZE_MENU, NULL);
66 mui->pixbuf_names = g_slist_append(mui->pixbuf_names, g_strdup(stockid));
67 mui->pixbufs = g_slist_append(mui->pixbufs, pixbuf);
68 return pixbuf;
71 static GtkWidget*
72 label_list(GSList *l, gboolean friendgroups /* FIXME: hack */) {
73 GtkWidget *label;
74 label = jam_form_label_new("");
75 if (l) {
76 GString *str = g_string_sized_new(1024);
78 while (l) {
79 if (str->len > 0)
80 g_string_append(str, ", ");
81 if (friendgroups) {
82 LJFriendGroup *fg = l->data;
83 g_string_append_printf(str, "<b>%s</b>", fg->name);
84 } else {
85 g_string_append_printf(str, "<b>%s</b>", (char*)l->data);
87 l = l->next;
89 gtk_label_set_markup(GTK_LABEL(label), str->str);
90 g_string_free(str, TRUE);
91 } else {
92 gtk_label_set_markup(GTK_LABEL(label), _("<i>none</i>"));
94 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
95 return label;
98 static void
99 run_cfmask_manager_dlg(GtkWidget *b, ManagerUI *mui) {
100 JamAccountLJ *acc = mui->selection;
101 guint newmask, oldmask;
103 oldmask = jam_account_lj_get_cfmask(acc);
104 newmask = custom_security_dlg_run(GTK_WINDOW(mui->win), oldmask, acc);
105 g_assert(mui->filterlabel);
106 if (newmask != oldmask) {
107 jam_account_lj_set_cfmask(acc, newmask);
108 /* XXX how do we notify the cfmgr of this new mask?
109 * cfmgr_set_mask(cfmgr_new(acc), newmask);*/
110 gtk_label_set_text(GTK_LABEL(mui->filterlabel),
111 newmask ? _("active") : _("inactive"));
115 static GtkWidget*
116 lj_user_make_ui_identity(ManagerUI *mui, LJUser *user) {
117 GtkSizeGroup *sg;
118 GtkWidget *vbox, *epassword;
120 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
122 vbox = gtk_vbox_new(FALSE, 6);
123 gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
125 gtk_box_pack_start(GTK_BOX(vbox),
126 labelled_box_new_sg(_("_User Name:"),
127 jam_form_label_new(user->username), sg),
128 FALSE, FALSE, 0);
130 gtk_box_pack_start(GTK_BOX(vbox),
131 labelled_box_new_sg(_("_Full Name:"),
132 jam_form_label_new(user->fullname), sg),
133 FALSE, FALSE, 0);
135 epassword = gtk_entry_new();
136 gtk_entry_set_visibility(GTK_ENTRY(epassword), FALSE);
137 gtk_entry_set_text(GTK_ENTRY(epassword), user->password);
138 gtk_widget_set_usize(epassword, 100, -1);
139 gtk_box_pack_start(GTK_BOX(vbox),
140 labelled_box_new_sg(_("_Password:"), epassword, sg),
141 FALSE, FALSE, 0);
143 return vbox;
146 static void
147 account_add_ui_loginoptions(ManagerUI *mui, GtkBox *vbox, JamAccount *acc) {
148 GtkWidget *cruser, *crpassword;
149 gboolean ru, rp;
151 jam_account_get_remember(acc, &ru, &rp);
153 cruser = gtk_check_button_new_with_label(_("Remember user"));
154 tie_toggle(GTK_TOGGLE_BUTTON(cruser), &acc->remember_user);
155 gtk_box_pack_start(vbox, cruser, FALSE, FALSE, 0);
157 crpassword = gtk_check_button_new_with_label(_("Remember password"));
158 tie_toggle(GTK_TOGGLE_BUTTON(crpassword), &acc->remember_password);
159 gtk_box_pack_start(vbox, crpassword, FALSE, FALSE, 0);
162 static GtkWidget*
163 user_make_ui_pictures(ManagerUI *mui, LJUser *user) {
164 GtkWidget *box;
165 box = groupedbox_new();
166 gtk_container_set_border_width(GTK_CONTAINER(box), 12);
167 groupedbox_set_header(GROUPEDBOX(box), _("User picture keywords:"), FALSE);
168 groupedbox_pack(GROUPEDBOX(box), label_list(user->pickws, FALSE), FALSE);
169 return box;
172 static GtkWidget*
173 account_lj_make_ui_friends(ManagerUI *mui, JamAccountLJ *acc) {
174 GtkWidget *vbox, *box, *hbcff, *licff, *bcff;
175 LJUser *user = jam_account_lj_get_user(acc);
177 vbox = gtk_vbox_new(FALSE, 6);
178 gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
180 /* per-user checkfriends on/off */
181 gtk_box_pack_start(GTK_BOX(vbox),
182 tie_toggle(GTK_TOGGLE_BUTTON(gtk_check_button_new_with_mnemonic(
183 _("_Monitor this user's friends list for updates"))),
184 &user->checkfriends),
185 FALSE, FALSE, 0);
187 gtk_box_pack_start(GTK_BOX(vbox),
188 label_list(user->friendgroups, TRUE),
189 FALSE, FALSE, 0);
191 box = groupedbox_new();
192 groupedbox_set_header(GROUPEDBOX(box),
193 _("Filter for friends list monitor:"), FALSE);
195 hbcff = gtk_hbox_new(FALSE, 5);
197 licff = gtk_label_new(acc->cfmask ? _("active") : _("inactive"));
198 gtk_misc_set_alignment(GTK_MISC(licff), 0.0, 0.5);
199 gtk_box_pack_start(GTK_BOX(hbcff), licff, TRUE, TRUE, 0);
200 mui->filterlabel = licff; /* not the prettiest of hacks */
202 bcff = gtk_button_new_with_mnemonic(_("_Edit filter"));
203 /* guard against a user with no friendgroup info */
204 gtk_widget_set_sensitive(bcff, user->friendgroups != NULL);
205 gtk_box_pack_start(GTK_BOX(hbcff), bcff, FALSE, FALSE, 0);
207 groupedbox_pack(GROUPEDBOX(box), hbcff, FALSE);
209 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 0);
211 g_signal_connect(G_OBJECT(bcff), "clicked",
212 G_CALLBACK(run_cfmask_manager_dlg), mui);
214 return vbox;
217 static GtkWidget*
218 account_lj_make_ui(ManagerUI *mui, JamAccount *acc) {
219 LJUser *user;
220 GtkWidget *nb, *box;
222 nb = gtk_notebook_new();
224 user = jam_account_lj_get_user(JAM_ACCOUNT_LJ(acc));
226 box = lj_user_make_ui_identity(mui, user),
227 account_add_ui_loginoptions(mui, GTK_BOX(box), acc);
228 gtk_notebook_append_page(GTK_NOTEBOOK(nb),
229 box,
230 gtk_label_new(_("Identity")));
231 gtk_notebook_append_page(GTK_NOTEBOOK(nb),
232 user_make_ui_pictures(mui, user),
233 gtk_label_new(_("Pictures")));
234 gtk_notebook_append_page(GTK_NOTEBOOK(nb),
235 account_lj_make_ui_friends(mui, JAM_ACCOUNT_LJ(acc)),
236 gtk_label_new(_("Friends")));
237 return nb;
241 static GtkWidget*
242 account_make_ui(ManagerUI *mui, JamAccount *acc) {
243 if (JAM_ACCOUNT_IS_LJ(acc)) {
244 return account_lj_make_ui(mui, acc);
245 } else {
246 g_error("unknown account type!");
248 return NULL;
251 typedef struct {
252 GtkTreeIter iter;
253 gpointer searchdata;
254 gboolean found;
255 } SearchData;
257 static gboolean
258 search_model_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
259 gpointer data) {
260 SearchData *sd = data;
261 gpointer datacol;
262 gtk_tree_model_get(model, iter, COL_DATA, &datacol, -1);
263 if (datacol == sd->searchdata) {
264 sd->found = TRUE;
265 sd->iter = *iter;
266 return TRUE;
268 return FALSE;
271 static GtkTreeIter
272 search_model(ManagerUI *mui, gpointer data) {
273 SearchData sd;
274 sd.found = FALSE;
275 sd.searchdata = data;
276 gtk_tree_model_foreach(GTK_TREE_MODEL(mui->store),
277 search_model_cb, &sd);
278 return sd.iter;
281 static void
282 account_edit(ManagerUI *mui, GtkTreeIter *iter, JamAccount *acc) {
283 GtkWidget *dlg;
284 char *oldname;
285 const char *newname;
287 oldname = g_strdup(jam_account_get_username(acc));
289 dlg = gtk_dialog_new_with_buttons(_("User Properties"),
290 GTK_WINDOW(mui->win), GTK_DIALOG_DESTROY_WITH_PARENT,
291 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
292 NULL);
293 //gtk_window_set_default_size(GTK_WINDOW(dlg), 300, 200);
295 jam_dialog_set_contents(GTK_DIALOG(dlg), account_make_ui(mui, acc));
297 gtk_dialog_run(GTK_DIALOG(dlg));
299 gtk_widget_destroy(dlg);
301 newname = jam_account_get_username(acc);
302 if (strcmp(oldname, newname) != 0) {
303 gtk_tree_store_set(mui->store, iter,
304 COL_TEXT, newname,
305 -1);
307 g_free(oldname);
310 static void
311 account_del(ManagerUI *mui, GtkTreeIter *iter, JamAccount *acc) {
312 /*GtkTreeIter it;
313 LJUser *user = jam_account_get_user(acc);
314 it = search_model(mui, user);*/
315 g_warning("unimplemented\n");
319 static void
320 add_entry_cache(ManagerUI *mui, GtkTreeStore *ts, GtkTreeIter *parent, JamAccount *user) {
321 GtkTreeIter ientries;
323 gtk_tree_store_append(ts, &ientries, parent);
324 gtk_tree_store_set(ts, &ientries,
325 COL_TEXT, _("Entries"),
326 -1);
330 static void
331 add_account(ManagerUI *mui, GtkTreeIter *parent, JamAccount *account) {
332 GtkTreeIter iaccount;
334 gtk_tree_store_append(mui->store, &iaccount, parent);
335 gtk_tree_store_set(mui->store, &iaccount,
336 COL_ICON, NULL,
337 COL_TEXT, jam_account_get_username(account),
338 COL_ISHOST, FALSE,
339 COL_DATA, account,
340 -1);
343 add_entry_cache(mui, ts, &iuser, user);
345 gtk_tree_store_append(ts, &idrafts, &iuser);
346 gtk_tree_store_set(ts, &idrafts,
347 COL_TEXT, _("Drafts"),
348 -1);
350 gtk_tree_store_append(ts, &ioutbox, &iuser);
351 gtk_tree_store_set(ts, &ioutbox,
352 COL_TEXT, _("Outbox"),
353 -1);
357 static gboolean
358 entry_tie_cb(GtkEntry *entry, GdkEventFocus *e, char **data) {
359 string_replace(data, gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1));
360 return FALSE;
362 static void
363 entry_tie(GtkEntry *entry, char **data) {
364 if (*data)
365 gtk_entry_set_text(GTK_ENTRY(entry), *data);
366 g_signal_connect(G_OBJECT(entry), "focus-out-event",
367 G_CALLBACK(entry_tie_cb), data);
371 static gboolean
372 host_rename_cb(GtkEntry *entry, GdkEventFocus *e, JamHost *host) {
373 const char *newname;
374 GError *err = NULL;
376 newname = gtk_entry_get_text(entry);
377 if (strcmp(host->name, newname) == 0)
378 return FALSE;
379 if (!conf_rename_host(host, newname, &err)) {
380 jam_warning(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(entry))),
381 _("Unable to rename server: %s."), err->message);
382 g_error_free(err);
383 gtk_entry_set_text(entry, host->name);
384 return FALSE;
386 return FALSE;
389 static GtkWidget*
390 host_make_ui(ManagerUI *mui, JamHost *host) {
391 GtkWidget *vbox, *name;
392 GtkSizeGroup *sg;
394 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
396 vbox = gtk_vbox_new(FALSE, 6);
398 name = gtk_entry_new();
399 gtk_entry_set_text(GTK_ENTRY(name), host->name);
400 g_signal_connect_after(G_OBJECT(name), "focus-out-event",
401 G_CALLBACK(host_rename_cb), host);
402 gtk_widget_set_usize(name, 200, -1);
403 gtk_box_pack_start(GTK_BOX(vbox),
404 labelled_box_new_sg(_("_Name:"), name, sg),
405 FALSE, FALSE, 0);
407 if (JAM_HOST_IS_LJ(host)) {
408 JamHostLJ *hostlj = JAM_HOST_LJ(host);
409 LJServer *server = jam_host_lj_get_server(hostlj);
410 GtkWidget *eurl, *cprotocol;
412 eurl = gtk_entry_new();
413 entry_tie(GTK_ENTRY(eurl), &server->url);
414 gtk_widget_set_usize(eurl, 200, -1);
415 gtk_box_pack_start(GTK_BOX(vbox),
416 labelled_box_new_sg(_("_URL:"), eurl, sg),
417 FALSE, FALSE, 0);
419 cprotocol = gtk_check_button_new_with_mnemonic(
420 _("_Server supports protocol version 1"));
421 tie_toggle(GTK_TOGGLE_BUTTON(cprotocol), &server->protocolversion);
422 gtk_box_pack_start(GTK_BOX(vbox), cprotocol, FALSE, FALSE, 0);
423 } else {
424 g_error("unknown host type!");
427 return vbox;
430 static void add_host(ManagerUI *mui, JamHost *host);
432 static void
433 host_edit(ManagerUI *mui, GtkTreeIter *iter, JamHost *host) {
434 GtkWidget *dlg;
435 char *oldname;
437 oldname = g_strdup(host->name);
439 dlg = gtk_dialog_new_with_buttons(_("Server Properties"),
440 GTK_WINDOW(mui->win), GTK_DIALOG_DESTROY_WITH_PARENT,
441 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
442 NULL);
443 //gtk_window_set_default_size(GTK_WINDOW(dlg), 300, 200);
445 jam_dialog_set_contents(GTK_DIALOG(dlg), host_make_ui(mui, host));
447 gtk_dialog_run(GTK_DIALOG(dlg));
449 gtk_widget_destroy(dlg);
451 if (strcmp(host->name, oldname) != 0) {
452 gtk_tree_store_set(mui->store, iter,
453 COL_TEXT, host->name,
454 -1);
456 g_free(oldname);
459 static void
460 host_del(ManagerUI *mui, GtkTreeIter *iter, JamHost *host) {
461 GtkTreeIter it;
463 it = search_model(mui, host);
464 gtk_tree_store_remove(mui->store, &it);
466 conf.hosts = g_slist_remove(conf.hosts, host);
467 // XXX evan g_free(server);
470 static void
471 add_host(ManagerUI *mui, JamHost *host) {
472 GtkTreeIter ihost;
473 GSList *l;
475 gtk_tree_store_append(mui->store, &ihost, NULL);
476 gtk_tree_store_set(mui->store, &ihost,
477 COL_ICON, get_pixbuf(mui, jam_host_get_stock_icon(host)),
478 COL_TEXT, host->name,
479 COL_ISHOST, TRUE,
480 COL_DATA, host,
481 -1);
483 for (l = host->accounts; l; l = l->next) {
484 add_account(mui, &ihost, l->data);
488 static void
489 populate_store(ManagerUI *mui) {
490 GSList *l;
492 gtk_tree_store_clear(mui->store);
493 for (l = conf.hosts; l; l = l->next) {
494 if (l->data)
495 add_host(mui, l->data);
499 static GtkTreeStore*
500 make_model(ManagerUI *mui) {
501 mui->store = gtk_tree_store_new(COL_COUNT,
502 /* icon */ GDK_TYPE_PIXBUF,
503 /* name */ G_TYPE_STRING,
504 /* ishost */ G_TYPE_BOOLEAN,
505 /* data */ G_TYPE_POINTER);
507 populate_store(mui);
509 return mui->store;
512 static void
513 selection_changed_cb(GtkTreeSelection *ts, ManagerUI *mui) {
514 GtkTreeModel *model;
515 GtkTreeIter iter;
517 if (!gtk_tree_selection_get_selected(ts, &model, &iter)) {
518 gtk_widget_set_sensitive(mui->edit, FALSE);
519 gtk_widget_set_sensitive(mui->del, FALSE);
520 } else {
521 /* XXX gboolean ishost;
522 gtk_tree_model_get(model, &iter, COL_ISHOST, &ishost, -1);*/
523 gtk_widget_set_sensitive(mui->edit, TRUE);
524 gtk_widget_set_sensitive(mui->del, TRUE);
528 static void
529 add_lj_cb(GtkWidget *i, ManagerUI *mui) {
530 JamHost *h;
531 LJServer *s;
532 s = lj_server_new("http://hostname:port");
533 h = JAM_HOST(jam_host_lj_new(s));
534 h->name = g_strdup("New LiveJournal Server");
535 conf.hosts = g_slist_append(conf.hosts, h);
536 gtk_tree_selection_unselect_all(
537 gtk_tree_view_get_selection(GTK_TREE_VIEW(mui->treeview)));
538 add_host(mui, h);
541 static void
542 edit_cb(GtkWidget *b, ManagerUI *mui) {
543 GtkTreeSelection *ts;
544 GtkTreeModel *model;
545 GtkTreeIter iter;
546 gboolean ishost;
547 gpointer data;
549 ts = gtk_tree_view_get_selection(GTK_TREE_VIEW(mui->treeview));
550 if (!gtk_tree_selection_get_selected(ts, &model, &iter))
551 return;
552 gtk_tree_model_get(model, &iter, COL_ISHOST, &ishost, COL_DATA, &data, -1);
553 mui->selection = data;
554 if (ishost) {
555 host_edit(mui, &iter, JAM_HOST(data));
556 } else {
557 account_edit(mui, &iter, JAM_ACCOUNT(data));
561 static void
562 del_cb(GtkWidget *b, ManagerUI *mui) {
563 GtkTreeSelection *ts;
564 GtkTreeModel *model;
565 GtkTreeIter iter;
566 gboolean ishost;
567 gpointer data;
569 ts = gtk_tree_view_get_selection(GTK_TREE_VIEW(mui->treeview));
570 if (!gtk_tree_selection_get_selected(ts, &model, &iter))
571 return;
572 gtk_tree_model_get(model, &iter, COL_ISHOST, &ishost, COL_DATA, &data, -1);
574 /* XXX evan this logic is weird; we don't want to delete the "current"
575 * stuff, but there is no real "current" anymore. maybe we should
576 * just unref it?
577 if (mui->selection == c_cur_server()
578 || mui->selection == c_cur_user()) {
579 return;
582 if (ishost) {
583 host_del(mui, &iter, JAM_HOST(data));
584 } else {
585 account_del(mui, &iter, JAM_ACCOUNT(data));
589 static GtkWidget*
590 make_tree(ManagerUI *mui) {
591 GtkCellRenderer *renderer;
592 GtkTreeViewColumn *column;
593 GtkTreeSelection *sel;
594 GtkWidget *sw;
596 mui->treeview = gtk_tree_view_new();
597 gtk_tree_view_set_model(GTK_TREE_VIEW(mui->treeview),
598 GTK_TREE_MODEL(make_model(mui)));
599 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(mui->treeview));
600 g_signal_connect(G_OBJECT(sel), "changed",
601 G_CALLBACK(selection_changed_cb), mui);
602 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(mui->treeview), FALSE);
604 column = gtk_tree_view_column_new();
605 gtk_tree_view_column_set_title(column, "Node");
607 renderer = gtk_cell_renderer_pixbuf_new();
608 gtk_tree_view_column_pack_start(column, renderer, FALSE);
609 gtk_tree_view_column_add_attribute(column, renderer,
610 "pixbuf", COL_ICON);
612 renderer = gtk_cell_renderer_text_new();
613 gtk_tree_view_column_pack_start(column, renderer, FALSE);
614 gtk_tree_view_column_add_attribute(column, renderer,
615 "text", COL_TEXT);
617 gtk_tree_view_append_column(GTK_TREE_VIEW(mui->treeview), column);
619 sw = scroll_wrap(mui->treeview);
620 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
621 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
622 return sw;
625 void
626 manager_dialog(GtkWindow *parent) {
627 STACK(ManagerUI, mui);
628 GtkWidget *mainbox, *bbox;
630 mui->win = gtk_dialog_new_with_buttons(_("Servers"),
631 parent, GTK_DIALOG_DESTROY_WITH_PARENT,
632 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
633 NULL);
634 gtk_window_set_default_size(GTK_WINDOW(mui->win), 300, 200);
635 geometry_tie(mui->win, GEOM_MANAGER);
637 mainbox = gtk_hbox_new(FALSE, 6);
639 gtk_box_pack_start(GTK_BOX(mainbox), make_tree(mui), TRUE, TRUE, 0);
641 bbox = gtk_vbox_new(FALSE, 6);
642 mui->add = gtk_button_new_from_stock(GTK_STOCK_ADD);
643 g_signal_connect(G_OBJECT(mui->add), "clicked",
644 G_CALLBACK(add_lj_cb), mui);
645 gtk_box_pack_start(GTK_BOX(bbox), mui->add, FALSE, FALSE, 0);
646 mui->edit = gtk_button_new_from_stock(GTK_STOCK_PROPERTIES);
647 g_signal_connect(G_OBJECT(mui->edit), "clicked",
648 G_CALLBACK(edit_cb), mui);
649 gtk_box_pack_start(GTK_BOX(bbox), mui->edit, FALSE, FALSE, 0);
650 mui->del = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
651 g_signal_connect(G_OBJECT(mui->del), "clicked",
652 G_CALLBACK(del_cb), mui);
653 gtk_box_pack_start(GTK_BOX(bbox), mui->del, FALSE, FALSE, 0);
655 gtk_box_pack_start(GTK_BOX(mainbox), bbox, FALSE, FALSE, 0);
657 jam_dialog_set_contents(GTK_DIALOG(mui->win), mainbox);
659 gtk_dialog_run(GTK_DIALOG(mui->win));
661 conf_verify_a_host_exists();
663 gtk_widget_destroy(mui->win);
664 g_slist_foreach(mui->pixbuf_names, (GFunc)g_free, NULL);
665 g_slist_free(mui->pixbuf_names);
666 g_slist_foreach(mui->pixbufs, (GFunc)g_object_unref, NULL);
667 g_slist_free(mui->pixbufs);