/
gui_gtkplus2.c
838 lines (688 loc) · 27.2 KB
1
2
3
4
5
6
7
/**
* MojoSetup; a portable, flexible installation application.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
8
9
// Not only does GTK+ 2.x _look_ better than 1.x, it offers a lot of basic
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// functionality, like message boxes, that you'd expect to exist in a GUI
// toolkit. In GTK+v1, you'd have to roll all that on your own!
//
// It's easier to implement in that regard, and produces a smaller DLL, but
// it has a million dependencies, so you might need to use a GTK+v1 plugin,
// too, in case they break backwards compatibility.
#if !SUPPORT_GUI_GTKPLUS2
#error Something is wrong in the build system.
#endif
#define BUILDING_EXTERNAL_PLUGIN 1
#include "gui.h"
MOJOGUI_PLUGIN(gtkplus2)
#if !GUI_STATIC_LINK_GTKPLUS2
CREATE_MOJOGUI_ENTRY_POINT(gtkplus2)
#endif
30
#undef format
31
#include <gtk/gtk.h>
32
#define format entry->format
33
34
35
typedef enum
{
36
PAGE_INTRO,
37
38
PAGE_README,
PAGE_OPTIONS,
39
PAGE_DEST,
40
PAGE_PROGRESS,
41
PAGE_FINAL
42
43
} WizardPages;
44
45
static WizardPages currentpage = PAGE_INTRO;
static gboolean canfwd = TRUE;
46
47
48
49
50
51
52
static GtkWidget *gtkwindow = NULL;
static GtkWidget *pagetitle = NULL;
static GtkWidget *notebook = NULL;
static GtkWidget *readme = NULL;
static GtkWidget *cancel = NULL;
static GtkWidget *back = NULL;
static GtkWidget *next = NULL;
53
static GtkWidget *finish = NULL;
54
static GtkWidget *msgbox = NULL;
55
56
57
static GtkWidget *destination = NULL;
static GtkWidget *progressbar = NULL;
static GtkWidget *progresslabel = NULL;
58
static GtkWidget *finallabel = NULL;
59
static GtkWidget *browse = NULL;
60
static GtkWidget *splash = NULL;
61
62
63
64
65
66
67
68
69
70
static volatile enum
{
CLICK_BACK=-1,
CLICK_CANCEL,
CLICK_NEXT,
CLICK_NONE
} click_value = CLICK_NONE;
71
static void prepare_wizard(const char *name, WizardPages page,
72
73
boolean can_back, boolean can_fwd,
boolean can_cancel)
74
{
75
76
77
78
char *markup = g_markup_printf_escaped(
"<span size='large' weight='bold'>%s</span>",
name);
79
80
81
currentpage = page;
canfwd = can_fwd;
82
gtk_label_set_markup(GTK_LABEL(pagetitle), markup);
83
g_free(markup);
84
85
86
gtk_widget_set_sensitive(back, can_back);
gtk_widget_set_sensitive(next, can_fwd);
87
gtk_widget_set_sensitive(cancel, can_cancel);
88
gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), (gint) page);
89
90
91
92
assert(click_value == CLICK_NONE);
assert(gtkwindow != NULL);
assert(msgbox == NULL);
93
} // prepare_wizard
94
95
96
static int wait_event(void)
97
98
99
{
int retval = 0;
100
101
102
// signals fired under gtk_main_iteration can change click_value.
gtk_main_iteration();
if (click_value == CLICK_CANCEL)
103
{
104
105
char *title = xstrdup(_("Cancel installation"));
char *text = xstrdup(_("Are you sure you want to cancel installation?"));
106
if (!MojoGui_gtkplus2_promptyn(title, text, false))
107
108
109
110
click_value = CLICK_NONE;
free(title);
free(text);
} // if
111
112
assert(click_value <= CLICK_NONE);
113
114
115
retval = (int) click_value;
click_value = CLICK_NONE;
return retval;
116
117
118
119
120
121
122
123
124
} // wait_event
static int pump_events(void)
{
int retval = (int) CLICK_NONE;
while ( (retval == ((int) CLICK_NONE)) && (gtk_events_pending()) )
retval = wait_event();
return retval;
125
126
127
} // pump_events
128
static int run_wizard(const char *name, WizardPages page,
129
boolean can_back, boolean can_fwd, boolean can_cancel)
130
131
{
int retval = CLICK_NONE;
132
prepare_wizard(name, page, can_back, can_fwd, can_cancel);
133
while (retval == ((int) CLICK_NONE))
134
retval = wait_event();
135
136
137
assert(retval < ((int) CLICK_NONE));
return retval;
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
} // run_wizard
static gboolean signal_delete(GtkWidget *w, GdkEvent *evt, gpointer data)
{
click_value = CLICK_CANCEL;
return TRUE; /* eat event: default handler destroys window! */
} // signal_delete
static void signal_clicked(GtkButton *_button, gpointer data)
{
GtkWidget *button = GTK_WIDGET(_button);
if (button == back)
click_value = CLICK_BACK;
else if (button == cancel)
click_value = CLICK_CANCEL;
155
else if ((button == next) || (button == finish))
156
157
158
159
160
161
162
click_value = CLICK_NEXT;
else
{
assert(0 && "Unknown click event.");
} // else
} // signal_clicked
163
164
165
static void signal_browse_clicked(GtkButton *_button, gpointer data)
{
166
GtkWidget *dialog = gtk_file_chooser_dialog_new (
167
_("Destination"),
168
169
170
171
172
173
NULL,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
174
175
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
gtk_combo_box_get_active_text(GTK_COMBO_BOX(destination)));
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
gchar *filename;
gchar *utfname;
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
utfname = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
gtk_combo_box_prepend_text(GTK_COMBO_BOX(destination), utfname);
gtk_combo_box_set_active(GTK_COMBO_BOX(destination), 0);
g_free(utfname);
g_free(filename);
}
// !!! FIXME: should append the package name to the directory they chose?
// !!! FIXME: This is annoying, they might have created the folder
// !!! FIXME: themselves in the dialog.
// !!! FIXME: Could warn when the target directory already contains files?
gtk_widget_destroy(dialog);
197
198
199
200
201
202
} // signal_browse_clicked
static void signal_dest_changed(GtkComboBox *combo, gpointer user_data)
{
// Disable the forward button when the destination entry is blank.
203
if ((currentpage == PAGE_DEST) && (canfwd))
204
205
206
207
208
209
210
{
gchar *str = gtk_combo_box_get_active_text(combo);
const gboolean filled_in = ((str != NULL) && (*str != '\0'));
g_free(str);
gtk_widget_set_sensitive(next, filled_in);
} // if
} // signal_dest_changed
211
212
213
static uint8 MojoGui_gtkplus2_priority(boolean istty)
214
{
215
// gnome-session exports this environment variable since 2002.
216
217
218
219
220
221
222
223
224
225
226
227
if (getenv("GNOME_DESKTOP_SESSION_ID") != NULL)
return MOJOGUI_PRIORITY_TRY_FIRST;
return MOJOGUI_PRIORITY_TRY_NORMAL;
} // MojoGui_gtkplus2_priority
static boolean MojoGui_gtkplus2_init(void)
{
int tmpargc = 0;
char *args[] = { NULL, NULL };
char **tmpargv = args;
228
229
if (!gtk_init_check(&tmpargc, &tmpargv))
{
230
logInfo("gtkplus2: gtk_init_check() failed, use another UI.");
231
232
233
return false;
} // if
return true;
234
235
236
237
238
239
240
241
242
} // MojoGui_gtkplus2_init
static void MojoGui_gtkplus2_deinit(void)
{
// !!! FIXME: GTK+ doesn't have a deinit function...it installs a crappy
// !!! FIXME: atexit() function!
} // MojoGui_gtkplus2_deinit
243
244
245
246
247
/**
*
* @param defbutton The response ID to use when enter is pressed, or 0
* to leave it up to GTK+.
*/
248
static gint do_msgbox(const char *title, const char *text,
249
GtkMessageType mtype, GtkButtonsType btype,
250
GtkResponseType defbutton,
251
void (*addButtonCallback)(GtkWidget *_msgbox))
252
253
{
gint retval = 0;
254
255
256
257
// Modal dialog, this will never be called recursively.
assert(msgbox == NULL);
258
259
260
261
msgbox = gtk_message_dialog_new(GTK_WINDOW(gtkwindow), GTK_DIALOG_MODAL,
mtype, btype, "%s", title);
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msgbox),
"%s", text);
262
263
264
265
if (defbutton)
gtk_dialog_set_default_response(GTK_DIALOG(msgbox), defbutton);
266
267
268
if (addButtonCallback != NULL)
addButtonCallback(msgbox);
269
270
271
retval = gtk_dialog_run(GTK_DIALOG(msgbox));
gtk_widget_destroy(msgbox);
msgbox = NULL;
272
273
274
275
276
277
278
return retval;
} // do_msgbox
static void MojoGui_gtkplus2_msgbox(const char *title, const char *text)
{
279
do_msgbox(title, text, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, 0, NULL);
280
281
282
} // MojoGui_gtkplus2_msgbox
283
284
static boolean MojoGui_gtkplus2_promptyn(const char *title, const char *text,
boolean defval)
285
{
286
gint rc = do_msgbox(title, text, GTK_MESSAGE_QUESTION,
287
288
289
290
GTK_BUTTONS_YES_NO,
defval ? GTK_RESPONSE_YES : GTK_RESPONSE_NO,
NULL);
291
292
293
294
return (rc == GTK_RESPONSE_YES);
} // MojoGui_gtkplus2_promptyn
295
296
static void promptynanButtonCallback(GtkWidget *_msgbox)
{
297
298
char *always = xstrdup(_("_Always"));
char *never = xstrdup(_("N_ever"));
299
300
301
302
303
gtk_dialog_add_buttons(GTK_DIALOG(_msgbox),
GTK_STOCK_YES, GTK_RESPONSE_YES,
GTK_STOCK_NO, GTK_RESPONSE_NO,
always, 1,
never, 0,
304
305
NULL);
306
307
308
309
310
311
free(always);
free(never);
} // promptynanButtonCallback
static MojoGuiYNAN MojoGui_gtkplus2_promptynan(const char *title,
312
313
const char *text,
boolean defval)
314
315
{
const gint rc = do_msgbox(title, text, GTK_MESSAGE_QUESTION,
316
317
318
GTK_BUTTONS_NONE,
defval ? GTK_RESPONSE_YES : GTK_RESPONSE_NO,
promptynanButtonCallback);
319
320
321
322
switch (rc)
{
case GTK_RESPONSE_YES: return MOJOGUI_YES;
case GTK_RESPONSE_NO: return MOJOGUI_NO;
323
324
case 1: return MOJOGUI_ALWAYS;
case 0: return MOJOGUI_NEVER;
325
326
} // switch
327
assert(false && "BUG: unhandled case in switch statement");
328
329
330
331
return MOJOGUI_NO; // just in case.
} // MojoGui_gtkplus2_promptynan
332
static GtkWidget *create_button(GtkWidget *box, const char *iconname,
333
334
335
const char *text,
void (*signal_callback)
(GtkButton *button, gpointer data))
336
{
337
GtkWidget *button = gtk_button_new_with_mnemonic(text);
338
GtkWidget *image = gtk_image_new_from_stock(iconname, GTK_ICON_SIZE_BUTTON);
339
gtk_button_set_image (GTK_BUTTON(button), image);
340
gtk_widget_show(button);
341
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
342
gtk_signal_connect(GTK_OBJECT(button), "clicked",
343
GTK_SIGNAL_FUNC(signal_callback), NULL);
344
345
346
347
return button;
} // create_button
348
static void free_splash(guchar *pixels, gpointer data)
349
{
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
free(pixels);
} // free_splash
static GtkWidget *build_splash(const MojoGuiSplash *splash)
{
GtkWidget *retval = NULL;
GdkPixbuf *pixbuf = NULL;
guchar *rgba = NULL;
const uint32 splashlen = splash->w * splash->h * 4;
if (splash->position == MOJOGUI_SPLASH_NONE)
return NULL;
if ((splash->rgba == NULL) || (splashlen == 0))
return NULL;
367
rgba = (guchar *) xmalloc(splashlen);
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
memcpy(rgba, splash->rgba, splashlen);
pixbuf = gdk_pixbuf_new_from_data(rgba, GDK_COLORSPACE_RGB, TRUE, 8,
splash->w, splash->h, splash->w * 4,
free_splash, NULL);
if (pixbuf == NULL)
free(rgba);
else
{
retval = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf); // retval adds a ref to pixbuf, so lose our's.
if (retval != NULL)
gtk_widget_show(retval);
} // else
return retval;
} // build_splash
static GtkWidget *create_gtkwindow(const char *title,
const MojoGuiSplash *_splash)
{
GtkWidget *splashbox = NULL;
390
391
392
GtkWidget *window;
GtkWidget *widget;
GtkWidget *box;
393
GtkWidget *alignment;
394
GtkWidget *hbox;
395
396
397
398
currentpage = PAGE_INTRO;
canfwd = TRUE;
399
400
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), title);
401
gtk_container_set_border_width(GTK_CONTAINER(window), 8);
402
403
404
405
406
407
408
GdkPixbuf *icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
"system-software-installer",
48, 0, NULL);
if (icon)
gtk_window_set_icon(GTK_WINDOW(window), icon);
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
assert(splash == NULL);
splash = build_splash(_splash);
if (splash != NULL)
{
// !!! FIXME: MOJOGUI_SPLASH_BACKGROUND?
const MojoGuiSplashPos pos = _splash->position;
if ((pos == MOJOGUI_SPLASH_LEFT) || (pos == MOJOGUI_SPLASH_RIGHT))
{
splashbox = gtk_hbox_new(FALSE, 6);
gtk_widget_show(splashbox);
gtk_container_add(GTK_CONTAINER(window), splashbox);
if (pos == MOJOGUI_SPLASH_LEFT)
gtk_box_pack_start(GTK_BOX(splashbox), splash, FALSE, FALSE, 6);
else
gtk_box_pack_end(GTK_BOX(splashbox), splash, FALSE, FALSE, 6);
} // if
else if ((pos == MOJOGUI_SPLASH_TOP) || (pos == MOJOGUI_SPLASH_BOTTOM))
{
splashbox = gtk_vbox_new(FALSE, 6);
gtk_widget_show(splashbox);
gtk_container_add(GTK_CONTAINER(window), splashbox);
if (pos == MOJOGUI_SPLASH_TOP)
gtk_box_pack_start(GTK_BOX(splashbox), splash, FALSE, FALSE, 6);
else
gtk_box_pack_end(GTK_BOX(splashbox), splash, FALSE, FALSE, 6);
} // else if
} // if
if (splashbox == NULL) // no splash, use the window for the top container.
splashbox = window;
441
box = gtk_vbox_new(FALSE, 6);
442
gtk_widget_show(box);
443
gtk_container_add(GTK_CONTAINER(splashbox), box);
444
445
446
pagetitle = gtk_label_new("");
gtk_widget_show(pagetitle);
447
gtk_box_pack_start(GTK_BOX(box), pagetitle, FALSE, TRUE, 16);
448
449
450
notebook = gtk_notebook_new();
gtk_widget_show(notebook);
451
gtk_container_set_border_width(GTK_CONTAINER(notebook), 0);
452
gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0);
453
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
454
gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
455
456
457
gtk_widget_set_size_request(notebook,
(gint) (((float) gdk_screen_width()) * 0.3),
(gint) (((float) gdk_screen_height()) * 0.3));
458
459
widget = gtk_hbutton_box_new();
460
461
gtk_widget_show(widget);
gtk_box_pack_start(GTK_BOX(box), widget, FALSE, FALSE, 0);
462
463
464
gtk_button_box_set_layout(GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_END);
gtk_button_box_set_child_ipadding(GTK_BUTTON_BOX (widget), 6, 0);
gtk_button_box_set_spacing(GTK_BUTTON_BOX (widget), 6);
465
466
box = widget;
467
468
469
470
cancel = create_button(box, "gtk-cancel", _("Cancel"), signal_clicked);
back = create_button(box, "gtk-go-back", _("Back"), signal_clicked);
next = create_button(box, "gtk-go-forward", _("Next"), signal_clicked);
finish = create_button(box, "gtk-goto-last", _("Finish"), signal_clicked);
471
gtk_widget_hide(finish);
472
473
474
475
476
477
478
// !!! FIXME: intro page.
widget = gtk_vbox_new(FALSE, 0);
gtk_widget_show(widget);
gtk_container_add(GTK_CONTAINER(notebook), widget);
// README/EULA page.
479
widget = gtk_scrolled_window_new(NULL, NULL);
480
481
482
483
484
485
gtk_scrolled_window_set_policy(
GTK_SCROLLED_WINDOW(widget),
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
gtk_scrolled_window_set_shadow_type(
GTK_SCROLLED_WINDOW(widget),
GTK_SHADOW_IN);
486
487
488
489
490
491
492
gtk_widget_show(widget);
gtk_container_add(GTK_CONTAINER(notebook), widget);
readme = gtk_text_view_new();
gtk_widget_show(readme);
gtk_container_add(GTK_CONTAINER(widget), readme);
gtk_text_view_set_editable(GTK_TEXT_VIEW(readme), FALSE);
493
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(readme), GTK_WRAP_NONE);
494
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(readme), FALSE);
495
496
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(readme), 4);
gtk_text_view_set_right_margin(GTK_TEXT_VIEW(readme), 4);
497
498
// !!! FIXME: options page.
499
500
501
box = gtk_vbox_new(FALSE, 0);
gtk_widget_show(box);
gtk_container_add(GTK_CONTAINER(notebook), box);
502
503
// Destination page
504
505
box = gtk_vbox_new(FALSE, 0);
gtk_widget_show(box);
506
507
hbox = gtk_hbox_new (FALSE, 6);
508
widget = gtk_label_new(_("Folder:"));
509
gtk_widget_show(widget);
510
gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
511
512
513
514
gtk_label_set_justify(GTK_LABEL(widget), GTK_JUSTIFY_CENTER);
gtk_label_set_line_wrap(GTK_LABEL(widget), FALSE);
alignment = gtk_alignment_new(0.5, 0.5, 1, 0);
destination = gtk_combo_box_entry_new_text();
515
516
gtk_signal_connect(GTK_OBJECT(destination), "changed",
GTK_SIGNAL_FUNC(signal_dest_changed), NULL);
517
gtk_container_add(GTK_CONTAINER(alignment), destination);
518
519
gtk_box_pack_start(GTK_BOX(hbox), alignment, TRUE, TRUE, 0);
browse = create_button(hbox, "gtk-open",
520
_("B_rowse..."), signal_browse_clicked);
521
522
523
524
525
526
gtk_widget_show_all (hbox);
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(notebook), box);
// Progress page
box = gtk_vbox_new(FALSE, 6);
527
528
529
530
531
532
533
534
535
536
537
538
539
540
gtk_widget_show(box);
alignment = gtk_alignment_new(0.5, 0.5, 1, 0);
gtk_widget_show(alignment);
progressbar = gtk_progress_bar_new();
gtk_widget_show(progressbar);
gtk_container_add(GTK_CONTAINER(alignment), progressbar);
gtk_box_pack_start(GTK_BOX(box), alignment, FALSE, TRUE, 0);
progresslabel = gtk_label_new("");
gtk_widget_show(progresslabel);
gtk_box_pack_start(GTK_BOX(box), progresslabel, FALSE, TRUE, 0);
gtk_label_set_justify(GTK_LABEL(progresslabel), GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap(GTK_LABEL(progresslabel), FALSE);
gtk_container_add(GTK_CONTAINER(notebook), box);
541
// !!! FIXME: final page.
542
543
544
widget = gtk_vbox_new(FALSE, 0);
gtk_widget_show(widget);
gtk_container_add(GTK_CONTAINER(notebook), widget);
545
546
547
548
finallabel = gtk_label_new("");
gtk_widget_show(finallabel);
gtk_box_pack_start(GTK_BOX(widget), finallabel, FALSE, TRUE, 0);
gtk_label_set_justify(GTK_LABEL(finallabel), GTK_JUSTIFY_LEFT);
549
gtk_label_set_line_wrap(GTK_LABEL(finallabel), TRUE);
550
551
552
553
gtk_signal_connect(GTK_OBJECT(window), "delete-event",
GTK_SIGNAL_FUNC(signal_delete), NULL);
554
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
555
556
557
558
559
gtk_widget_show(window);
return window;
} // create_gtkwindow
560
561
static boolean MojoGui_gtkplus2_start(const char *title,
const MojoGuiSplash *splash)
562
{
563
gtkwindow = create_gtkwindow(title, splash);
564
565
566
567
568
569
570
571
572
573
574
575
return (gtkwindow != NULL);
} // MojoGui_gtkplus2_start
static void MojoGui_gtkplus2_stop(void)
{
assert(msgbox == NULL);
if (gtkwindow != NULL)
gtk_widget_destroy(gtkwindow);
gtkwindow = NULL;
pagetitle = NULL;
576
finallabel = NULL;
577
578
579
progresslabel = NULL;
progressbar = NULL;
destination = NULL;
580
581
582
583
584
notebook = NULL;
readme = NULL;
cancel = NULL;
back = NULL;
next = NULL;
585
finish = NULL;
586
splash = NULL;
587
588
589
590
} // MojoGui_gtkplus2_stop
static int MojoGui_gtkplus2_readme(const char *name, const uint8 *data,
591
592
size_t datalen, boolean can_back,
boolean can_fwd)
593
594
595
{
GtkTextBuffer *textbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(readme));
gtk_text_buffer_set_text(textbuf, (const gchar *) data, datalen);
596
return run_wizard(name, PAGE_README, can_back, can_fwd, true);
597
598
599
} // MojoGui_gtkplus2_readme
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
static void set_option_tree_sensitivity(MojoGuiSetupOptions *opts, boolean val)
{
if (opts != NULL)
{
gtk_widget_set_sensitive((GtkWidget *) opts->guiopaque, val);
set_option_tree_sensitivity(opts->next_sibling, val);
set_option_tree_sensitivity(opts->child, val && opts->value);
} // if
} // set_option_tree_sensitivity
static void signal_option_toggled(GtkToggleButton *toggle, gpointer data)
{
MojoGuiSetupOptions *opts = (MojoGuiSetupOptions *) data;
const boolean enabled = gtk_toggle_button_get_active(toggle);
opts->value = enabled;
set_option_tree_sensitivity(opts->child, enabled);
} // signal_option_toggled
static GtkWidget *new_option_level(GtkWidget *box)
{
GtkWidget *alignment = gtk_alignment_new(0.0, 0.5, 0, 0);
GtkWidget *retval = gtk_vbox_new(FALSE, 0);
gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 15, 0);
gtk_widget_show(alignment);
gtk_widget_show(retval);
gtk_container_add(GTK_CONTAINER(alignment), retval);
gtk_box_pack_start(GTK_BOX(box), alignment, TRUE, TRUE, 0);
return retval;
} // new_option_level
633
634
635
636
637
638
639
640
641
642
643
644
645
646
// use this to generate a tooltip only as needed.
static GtkTooltips *get_tip(GtkTooltips **_tip)
{
if (*_tip == NULL)
{
GtkTooltips *tip = gtk_tooltips_new();
gtk_tooltips_enable(tip);
*_tip = tip;
} // if
return *_tip;
} // get_tip
647
648
649
650
651
static void build_options(MojoGuiSetupOptions *opts, GtkWidget *box,
gboolean sensitive)
{
if (opts != NULL)
{
652
653
GtkTooltips *tip = NULL;
GtkWidget *widget = NULL;
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
if (opts->is_group_parent)
{
MojoGuiSetupOptions *kids = opts->child;
GtkWidget *childbox = NULL;
GtkWidget *alignment = gtk_alignment_new(0.0, 0.5, 0, 0);
gtk_widget_show(alignment);
widget = gtk_label_new(opts->description);
opts->guiopaque = widget;
gtk_widget_set_sensitive(widget, sensitive);
gtk_widget_show(widget);
gtk_label_set_justify(GTK_LABEL(widget), GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap(GTK_LABEL(widget), FALSE);
gtk_container_add(GTK_CONTAINER(alignment), widget);
gtk_box_pack_start(GTK_BOX(box), alignment, FALSE, TRUE, 0);
670
671
672
if (opts->tooltip != NULL)
gtk_tooltips_set_tip(get_tip(&tip), widget, opts->tooltip, 0);
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
widget = NULL;
childbox = new_option_level(box);
while (kids)
{
widget = gtk_radio_button_new_with_label_from_widget(
GTK_RADIO_BUTTON(widget),
kids->description);
kids->guiopaque = widget;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
kids->value);
gtk_widget_set_sensitive(widget, sensitive);
gtk_widget_show(widget);
gtk_box_pack_start(GTK_BOX(childbox), widget, FALSE, TRUE, 0);
gtk_signal_connect(GTK_OBJECT(widget), "toggled",
GTK_SIGNAL_FUNC(signal_option_toggled), kids);
688
689
690
691
if (kids->tooltip != NULL)
gtk_tooltips_set_tip(get_tip(&tip),widget,kids->tooltip,0);
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
if (kids->child != NULL)
{
build_options(kids->child, new_option_level(childbox),
sensitive);
} // if
kids = kids->next_sibling;
} // while
} // if
else
{
widget = gtk_check_button_new_with_label(opts->description);
opts->guiopaque = widget;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
opts->value);
gtk_widget_set_sensitive(widget, sensitive);
gtk_widget_show(widget);
gtk_box_pack_start(GTK_BOX(box), widget, FALSE, TRUE, 0);
gtk_signal_connect(GTK_OBJECT(widget), "toggled",
GTK_SIGNAL_FUNC(signal_option_toggled), opts);
712
713
if (opts->tooltip != NULL)
714
gtk_tooltips_set_tip(get_tip(&tip), widget, opts->tooltip, 0);
715
716
717
718
719
720
721
722
723
724
725
726
727
if (opts->child != NULL)
{
build_options(opts->child, new_option_level(box),
((sensitive) && (opts->value)) );
} // if
} // else
build_options(opts->next_sibling, box, sensitive);
} // if
} // build_options
728
static int MojoGui_gtkplus2_options(MojoGuiSetupOptions *opts,
729
boolean can_back, boolean can_fwd)
730
{
731
732
733
734
735
736
737
738
739
740
int retval;
GtkWidget *box;
GtkWidget *page; // this is a vbox.
page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), PAGE_OPTIONS);
box = gtk_vbox_new(FALSE, 0);
gtk_widget_show(box);
gtk_box_pack_start(GTK_BOX(page), box, FALSE, FALSE, 0);
build_options(opts, box, TRUE);
741
retval = run_wizard(_("Options"), PAGE_OPTIONS, can_back, can_fwd, true);
742
743
gtk_widget_destroy(box);
return retval;
744
745
746
} // MojoGui_gtkplus2_options
747
748
749
static char *MojoGui_gtkplus2_destination(const char **recommends, int recnum,
int *command, boolean can_back,
boolean can_fwd)
750
{
751
752
753
754
755
756
GtkComboBox *combo = GTK_COMBO_BOX(destination);
gchar *str = NULL;
char *retval = NULL;
int i;
for (i = 0; i < recnum; i++)
757
gtk_combo_box_append_text(combo, recommends[i]);
758
gtk_combo_box_set_active (combo, 0);
759
760
*command = run_wizard(_("Destination"),PAGE_DEST,can_back,can_fwd,true);
761
762
str = gtk_combo_box_get_active_text(combo);
763
764
765
766
// shouldn't ever be empty ("next" should be disabled in that case).
assert( (*command <= 0) || ((str != NULL) && (*str != '\0')) );
767
retval = xstrdup(str);
768
g_free(str);
769
770
771
772
773
for (i = recnum-1; i >= 0; i--)
gtk_combo_box_remove_text(combo, i);
return retval;
774
775
776
777
778
} // MojoGui_gtkplus2_destination
static boolean MojoGui_gtkplus2_insertmedia(const char *medianame)
{
779
gint rc = 0;
780
781
// !!! FIXME: Use stock GTK icon for "media"?
// !!! FIXME: better text.
782
const char *title = xstrdup(_("Media change"));
783
// !!! FIXME: better text.
784
785
const char *fmt = xstrdup(_("Please insert '%0'"));
const char *text = format(fmt, medianame);
786
rc = do_msgbox(title, text, GTK_MESSAGE_WARNING,
787
GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, NULL);
788
789
790
free((void *) text);
free((void *) fmt);
free((void *) title);
791
792
793
794
return (rc == GTK_RESPONSE_OK);
} // MojoGui_gtkplus2_insertmedia
795
796
797
798
799
800
static void MojoGui_gtkplus2_progressitem(void)
{
// no-op in this UI target.
} // MojoGui_gtkplus2_progressitem
801
static boolean MojoGui_gtkplus2_progress(const char *type, const char *component,
802
803
int percent, const char *item,
boolean can_cancel)
804
{
805
static uint32 lastTicks = 0;
806
const uint32 ticks = ticks();
807
808
809
810
811
812
813
814
815
816
int rc;
if ((ticks - lastTicks) > 200) // just not to spam this...
{
GtkProgressBar *progress = GTK_PROGRESS_BAR(progressbar);
if (percent < 0)
gtk_progress_bar_pulse(progress);
else
gtk_progress_bar_set_fraction(progress, ((gdouble) percent) / 100.0);
817
gtk_progress_bar_set_text(progress, component);
818
819
820
821
gtk_label_set_text(GTK_LABEL(progresslabel), item);
lastTicks = ticks;
} // if
822
prepare_wizard(type, PAGE_PROGRESS, false, false, can_cancel);
823
824
825
rc = pump_events();
assert( (rc == ((int) CLICK_CANCEL)) || (rc == ((int) CLICK_NONE)) );
return (rc != CLICK_CANCEL);
826
827
} // MojoGui_gtkplus2_progress
828
829
830
831
832
833
static void MojoGui_gtkplus2_final(const char *msg)
{
gtk_widget_hide(next);
gtk_widget_show(finish);
gtk_label_set_text(GTK_LABEL(finallabel), msg);
834
run_wizard(_("Finish"), PAGE_FINAL, false, true, false);
835
836
} // MojoGui_gtkplus2_final
837
// end of gui_gtkplus2.c ...