Fixed another compatibility-related warning wrt 'GTK_OBJECT(NULL)'.
[captive.git] / src / install / acquire / ui-gnome.c
1 /* $Id$
2  * Drivers acquiring installation utility
3  * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include "ui-gnome.h"   /* self */
23 #include <glib/gmessages.h>
24 #include "moduriload.h"
25 #include "main.h"
26 #include <gtk/gtkmain.h>
27 #include <gtk/gtktreeviewcolumn.h>
28 #include <gtk/gtkbox.h>
29 #include <sys/time.h>
30 #include <libgnomeui/gnome-app.h>
31 #include <gtk/gtktreestore.h>
32 #include <gtk/gtkframe.h>
33 #include <gtk/gtkentry.h>
34 #include <libgnomeui/gnome-druid.h>
35 #include <libgnomeui/gnome-app-util.h>
36 #include <libgnomeui/gnome-druid-page-edge.h>
37 #include "final.h"
38 #include <libgnomevfs/gnome-vfs-utils.h>
39
40 #include <captive/macros.h>
41
42
43 /* Config: */
44 #define PROGRESS_UPDATE_USEC 100000
45
46
47 static GnomeApp *App;
48 static GtkTreeStore *DriversTreeStore;
49 static GtkFrame *DriversFrame;
50 static GtkFrame *ProgressFrame;
51 static GtkEntry *ProgressEntry;
52 static GnomeDruid *Druid;
53 static GtkButton *DruidButtonSkip;
54 static GtkButton *DruidButtonOK;
55 static GtkTreeView *DriversTreeView;
56 static GnomeDruidPage *PageStart;
57 static GnomeDruidPage *ScanDiskPage;
58 static GnomeDruidPage *ScanPathPage;
59 static GnomeDruidPage *MicrosoftComPage;
60 static GnomeDruidPage *PageFinish;
61 static GtkEntry *ScanPathLocationComboEntry;
62 static GtkButton *MicrosoftComConfirmButton;
63 static GtkProgressBar *MicrosoftComProgress;
64 enum {
65                 DRIVERS_TREE_STORE_COLUMN_TYPE,
66                 DRIVERS_TREE_STORE_COLUMN_ID,
67                 DRIVERS_TREE_STORE_COLUMN_NUM,  /* total # */
68                 };
69 #define DRIVERS_TREE_STORE_COLUMN_TYPE_LIST G_TYPE_STRING,G_TYPE_STRING
70
71
72 /* map: (gchar *)type-> (GtkTreeIter *) */
73 static GHashTable *DriversTreeStore_Iter_hash;
74
75 static void DriversTreeStore_Iter_hash_key_destroy_func(gchar *type)
76 {
77         g_return_if_fail(type!=NULL);
78
79         g_free(type);
80 }
81
82 static void DriversTreeStore_Iter_hash_init(void)
83 {
84         if (DriversTreeStore_Iter_hash)
85                 return;
86         DriversTreeStore_Iter_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
87                         (GDestroyNotify)DriversTreeStore_Iter_hash_key_destroy_func,
88                         NULL);  /* value_destroy_func */
89 }
90
91 static GtkTreeIter *DriversTreeStore_Iter_hash_get_iter(const gchar *type)
92 {
93 GtkTreeIter *r;
94
95         g_return_val_if_fail(type!=NULL,NULL);
96
97         DriversTreeStore_Iter_hash_init();
98         if (!(r=g_hash_table_lookup(DriversTreeStore_Iter_hash,type))) {
99                 captive_new(r);
100                 gtk_tree_store_append(DriversTreeStore,
101                                 r,      /* iter */
102                                 NULL);  /* parent */
103                 g_hash_table_insert(DriversTreeStore_Iter_hash,g_strdup(type),r);
104                 }
105
106         return r;
107 }
108
109 static gboolean some_modules_found=FALSE;
110 static gboolean in_progress=FALSE;
111 static GnomeDruidPage *page_active;
112
113 static void state_changed(void)
114 {
115         /* Not yet initialized? */
116         if (!App)
117                 return;
118
119         gtk_widget_set_sensitive(GTK_WIDGET(DruidButtonSkip),
120                         (page_active!=PageStart && page_active!=PageFinish));
121         gtk_widget_set_sensitive(GTK_WIDGET(DruidButtonOK),some_modules_found);
122
123         if (in_progress) {
124                 gtk_widget_set_sensitive(Druid->next,FALSE);
125                 gtk_widget_set_sensitive(GTK_WIDGET(DruidButtonOK),some_modules_found);
126                 gtk_widget_set_sensitive(GTK_WIDGET(MicrosoftComConfirmButton),FALSE);
127                 }
128         else {
129                 /* It is checked by GTK+ whether the text changed: */
130                 gtk_entry_set_text(ProgressEntry,"");
131                 gtk_widget_set_sensitive(Druid->next,
132                                 (page_active!=PageFinish && page_active!=MicrosoftComPage));
133                 gtk_widget_set_sensitive(GTK_WIDGET(MicrosoftComConfirmButton),
134                                 (page_active==MicrosoftComPage));
135                 gtk_progress_bar_set_fraction(MicrosoftComProgress,(gdouble)0);
136                 gtk_progress_bar_set_text(MicrosoftComProgress,"");
137                 }
138 }
139
140 static void ui_gnome_module_best_priority_notify(const gchar *module_type)
141 {
142 GtkTreeIter *iter;
143
144         g_return_if_fail(module_type!=NULL);
145
146         iter=DriversTreeStore_Iter_hash_get_iter(module_type);
147         gtk_tree_store_set(DriversTreeStore,iter,
148                         DRIVERS_TREE_STORE_COLUMN_TYPE,module_type,
149                         DRIVERS_TREE_STORE_COLUMN_ID  ,
150                                         ((0
151                                                                         || !strcmp(module_type,"ntoskrnl.exe")
152                                                                         || !strcmp(module_type,"ntfs.sys"))
153                                                         ? _("NOT FOUND; essential module for NTFS disks access")
154                                                         : _("not found; optional module")),
155                         -1);
156 }
157
158 static void ui_gnome_module_available_notify(struct module_available *module_available)
159 {
160 GtkTreeIter *iter;
161 static gboolean some_module_ntoskrnl_exe_found=FALSE;
162 static gboolean some_module_ntfs_sys_found=FALSE;
163
164         g_return_if_fail(module_available!=NULL);
165         g_return_if_fail(module_available->module!=NULL);
166
167         iter=DriversTreeStore_Iter_hash_get_iter(module_available->module->type);
168         gtk_tree_store_set(DriversTreeStore,iter,
169                         DRIVERS_TREE_STORE_COLUMN_TYPE,module_available->module->type,
170                         DRIVERS_TREE_STORE_COLUMN_ID  ,module_available->module->id,
171                         -1);
172
173         if (!strcmp(module_available->module->type,"ntoskrnl.exe"))
174                 some_module_ntoskrnl_exe_found=TRUE;
175         if (!strcmp(module_available->module->type,"ntfs.sys"))
176                 some_module_ntfs_sys_found=TRUE;
177
178         some_modules_found=some_module_ntoskrnl_exe_found && some_module_ntfs_sys_found;
179         state_changed();
180 }
181
182 static gboolean all_modules_found=FALSE;
183
184 static void ui_gnome_all_modules_found_notify(void)
185 {
186         all_modules_found=TRUE;
187         state_changed();
188 }
189
190 static gboolean aborted=FALSE;
191 static gboolean aborted_back=FALSE;     /* 'Back' button was clicked. */
192 static struct timeval ProgressEntry_updated_timeval;
193
194 static void progress_start(void)
195 {
196         in_progress=TRUE;
197         aborted=FALSE;
198         aborted_back=FALSE;
199         CAPTIVE_MEMZERO(&ProgressEntry_updated_timeval);
200         state_changed();
201 }
202
203 static void progress_end(void)
204 {
205         in_progress=FALSE;
206         state_changed();
207 }
208
209 static gboolean ui_gnome_progress(GnomeVFSURI *uri)
210 {
211         /* 'uri' may be NULL */
212
213         if (ProgressEntry) {
214 static gchar *uri_text=NULL;
215
216                 /* Store 'uri' on each call (not just if 'diff_timeval' permits)
217                  * as we may get into long cabinet extraction phase with 'uri==NULL' calls
218                  * where we want to display the currently processed 'uri'.
219                  */
220                 if (uri) {
221                         g_free(uri_text);
222                         uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD);
223                         }
224
225                 if (uri_text) {
226 struct timeval now_timeval;
227 struct timeval diff_timeval;
228
229                         gettimeofday(   /* FIXME: errors ignored */
230                                         &now_timeval,   /* tv */
231                                         NULL);  /* tz */
232                         timersub(&now_timeval,&ProgressEntry_updated_timeval,&diff_timeval);
233                         if (!ProgressEntry_updated_timeval.tv_sec || diff_timeval.tv_sec>0 || diff_timeval.tv_usec>=PROGRESS_UPDATE_USEC) {
234                                 gtk_entry_set_text(ProgressEntry,
235                                                 uri_text+(strncmp(uri_text,"file://",strlen("file://")) ? 0 : strlen("file://")));
236                                 ProgressEntry_updated_timeval=now_timeval;
237                                 }
238                         }
239                 }
240         while (gtk_events_pending())
241                 gtk_main_iteration();
242
243         if (aborted)
244                 return TRUE;
245         if (all_modules_found)
246                 return TRUE;
247
248         return FALSE;
249 }
250
251 static void ui_gnome_progress_bar(gint done,gint length)
252 {
253         g_return_if_fail(done>=0);
254         g_return_if_fail(length>=0);
255
256         if (!length) {
257                 gtk_progress_bar_pulse(MicrosoftComProgress);
258                 gtk_progress_bar_set_text(MicrosoftComProgress,"");
259                 }
260         else {
261 gchar *done_display,*length_display;
262
263                 gtk_progress_bar_set_fraction(MicrosoftComProgress,((gdouble)done)/length);
264                 done_display=gnome_vfs_format_file_size_for_display(done);
265                 length_display=gnome_vfs_format_file_size_for_display(length);
266                 gtk_progress_bar_set_text(MicrosoftComProgress,
267                                 captive_printf_alloca("%s / %s",done_display,length_display));
268                 g_free(done_display);
269                 g_free(length_display);
270                 }
271 }
272
273 /* FIXME: Change it to "prepare" signal. */
274 void on_Page_map(GtkWidget *vbox_widget,GtkWidget *page_widget)
275 {
276         /* Handle non-object (NULL) signal with reversed parameters? */
277         if (GNOME_IS_DRUID_PAGE(vbox_widget) && page_widget==NULL) {
278                 page_widget=vbox_widget;
279                 vbox_widget=NULL;
280                 }
281         g_return_if_fail(vbox_widget==NULL || GTK_IS_VBOX(vbox_widget));
282         g_return_if_fail(GNOME_IS_DRUID_PAGE(page_widget));
283
284         page_active=GNOME_DRUID_PAGE(page_widget);
285         if (page_active==PageFinish) {
286                 gnome_druid_set_show_finish(Druid,FALSE);       /* set it each time */
287                 /**/ if (!some_modules_found)
288                         gnome_druid_page_edge_set_text(GNOME_DRUID_PAGE_EDGE(PageFinish),_(
289                                         "We need at least some version of drivers essential for this project:"
290                                         " ntoskrnl.exe and ntfs.sys. Please click 'Back' button to obtain them"
291                                         " by several methods offered by this installer."));
292                 else {
293 gchar *text;
294
295                         text=final_text(all_modules_found);
296                         gnome_druid_page_edge_set_text(GNOME_DRUID_PAGE_EDGE(PageFinish),text);
297                         g_free(text);
298                         }
299                 }
300         if (page_active==ScanPathPage)
301                 gtk_widget_grab_focus(GTK_WIDGET(ScanPathLocationComboEntry));
302         state_changed();
303
304         if (!vbox_widget)
305                 return;
306
307         /* FIXME: 'freeze' apparently does not help 'repositioning' of
308          * 'DriversTreeView' during first 'map' of each 'Page'.
309          */
310         gtk_widget_freeze_child_notify(vbox_widget);
311
312         gtk_widget_reparent(GTK_WIDGET(DriversFrame),vbox_widget);
313         gtk_widget_reparent(GTK_WIDGET(ProgressFrame),vbox_widget);
314
315         gtk_box_reorder_child(GTK_BOX(vbox_widget),GTK_WIDGET(DriversFrame),
316                         0);     /* position */
317
318         gtk_box_set_child_packing(GTK_BOX(vbox_widget),GTK_WIDGET(DriversFrame),
319                         FALSE,  /* expand */
320                         TRUE,   /* fill */
321                         0,      /* padding */
322                         GTK_PACK_START);
323         gtk_box_set_child_packing(GTK_BOX(vbox_widget),GTK_WIDGET(ProgressFrame),
324                         FALSE,  /* expand */
325                         TRUE,   /* fill */
326                         0,      /* padding */
327                         GTK_PACK_START);
328
329         /* FIXME: Needed to fix (0,0)-position inside parent GdkWindow. */
330         gtk_widget_queue_resize(GTK_WIDGET(DriversTreeView));
331         gtk_widget_queue_resize(GTK_WIDGET(ProgressEntry));
332
333         gtk_widget_thaw_child_notify(vbox_widget);
334 }
335
336 gboolean on_Page_next(GnomeDruidPage *gnomedruidpage,GtkWidget *widget,gpointer user_data /* unused */)
337 {
338         g_return_val_if_fail(GNOME_IS_DRUID_PAGE(gnomedruidpage),FALSE);
339
340         if (in_progress)        /* bogus callback - we should be non-sensitive */
341                 return TRUE;    /* ignore button press */
342
343         /**/ if (page_active==PageStart) {
344                 if (all_modules_found) {
345                         gnome_druid_set_page(Druid,PageFinish);
346                         return TRUE;    /* ignore button press */
347                         }
348                 }
349         else if (page_active==ScanDiskPage) {
350                 progress_start();
351                 scan_disks_quick();
352                 scan_disks();
353                 progress_end();
354                 if (aborted_back) {
355                         gnome_druid_set_page(Druid,PageStart);
356                         return TRUE;    /* ignore button press */
357                         }
358                 if (all_modules_found) {
359                         gnome_druid_set_page(Druid,PageFinish);
360                         return TRUE;    /* ignore button press */
361                         }
362                 return FALSE;   /* proceed to next page */
363                 }
364         else if (page_active==ScanPathPage) {
365 const gchar *scan_path_uri_text=gtk_entry_get_text(ScanPathLocationComboEntry);
366
367                 if (scan_path_uri_text && *scan_path_uri_text) {
368 GnomeVFSURI *scan_path_uri;
369
370                         if ((scan_path_uri=gnome_vfs_uri_new(scan_path_uri_text))) {
371                                 progress_start();
372                                 mod_uri_load(scan_path_uri);
373                                 progress_end();
374                                 gnome_vfs_uri_unref(scan_path_uri);
375                                 if (aborted_back) {
376                                         gnome_druid_set_page(Druid,(all_modules_found ? PageStart : ScanDiskPage));
377                                         return TRUE;    /* ignore button press */
378                                         }
379                                 if (all_modules_found) {
380                                         gnome_druid_set_page(Druid,PageFinish);
381                                         return TRUE;    /* ignore button press */
382                                         }
383                                 gtk_entry_set_text(ScanPathLocationComboEntry,"");
384                                 }
385                         else
386                                 g_warning(_("Invalid URI: %s"),scan_path_uri_text);
387                         gtk_widget_grab_focus(GTK_WIDGET(ScanPathLocationComboEntry));
388                         return TRUE;    /* ignore button press; we cleared the URI entry */
389                         }
390                 return FALSE;   /* proceed to next page */
391                 }
392
393         return FALSE;   /* proceed to next page */
394 }
395
396 void on_MicrosoftComConfirmButton_clicked(GtkButton *button,gpointer user_data)
397 {
398         g_return_if_fail(GTK_IS_BUTTON(button));
399
400         if (in_progress)        /* bogus callback */
401                 return;
402         if (page_active!=MicrosoftComPage)      /* bogus callback */
403                 return;
404
405         progress_start();
406         microsoft_com();
407         progress_end();
408         if (aborted_back) {
409                 gnome_druid_set_page(Druid,(all_modules_found ? PageStart : ScanPathPage));
410                 return;
411                 }
412         if (all_modules_found) {
413                 gnome_druid_set_page(Druid,PageFinish);
414                 return;
415                 }
416
417         gnome_druid_set_page(Druid,PageFinish);
418 }
419
420 void on_DruidButtonSkip_clicked(GtkButton *button,gpointer user_data /* unused */)
421 {
422         g_return_if_fail(GTK_IS_BUTTON(button));
423
424         if (in_progress) {
425                 aborted=TRUE;
426                 state_changed();
427                 return;
428                 }
429         if (all_modules_found)
430                 gnome_druid_set_page(Druid,PageFinish);
431         else if (page_active==ScanDiskPage)
432                 gnome_druid_set_page(Druid,ScanPathPage);
433         else if (page_active==ScanPathPage)
434                 gnome_druid_set_page(Druid,MicrosoftComPage);
435         else if (page_active==MicrosoftComPage)
436                 gnome_druid_set_page(Druid,PageFinish);
437 }
438
439 gboolean on_Page_back(GnomeDruidPage *gnomedruidpage,GtkWidget *widget,gpointer user_data)
440 {
441         g_return_val_if_fail(GNOME_IS_DRUID_PAGE(gnomedruidpage),FALSE);
442
443         if (!in_progress) {
444                 if (all_modules_found) {
445                         gnome_druid_set_page(Druid,PageStart);
446                         return TRUE;    /* ignore button press */
447                         }
448                 return FALSE;   /* proceed to previous page */
449                 }
450
451         aborted=TRUE;
452         aborted_back=TRUE;
453         state_changed();
454
455         return TRUE;    /* ignore button press now; we will respect 'aborted_back' */
456 }
457
458 void on_Druid_cancel(GnomeDruid *gnomedruid,gpointer user_data /* unused */)
459 {
460         g_return_if_fail(GNOME_IS_DRUID(gnomedruid));
461
462         /* gtk_main_quit() would not abort the current operation. */
463         exit(EXIT_SUCCESS);
464 }
465
466 static void on_DruidButtonOK_clicked_dialog_callback(gint reply,gint *replyp /* data */)
467 {
468         g_return_if_fail(reply>=0);
469         g_return_if_fail(replyp!=NULL);
470
471         *replyp=reply;
472 }
473
474 void on_DruidButtonOK_clicked(GtkButton *button,gpointer user_data /* unused */)
475 {
476 GtkWidget *dialog;
477 gint reply;
478
479         g_return_if_fail(GTK_IS_BUTTON(button));
480
481         if (all_modules_found)
482                 exit(EXIT_SUCCESS);
483
484         /* TODO: Avoid dialog if already on Finish page. */
485         reply=-1;
486         dialog=gnome_app_ok_cancel_modal(App,_(
487                         "Although essential modules (\"ntoskrnl.exe\" and \"ntfs.sys\") are available "
488                         "you may still want to get their better version and/or more modules. "
489                         "Really quit?"),
490                         (GnomeReplyCallback)on_DruidButtonOK_clicked_dialog_callback,
491                         &reply);        /* data */
492         g_signal_connect((gpointer)dialog,"close",G_CALLBACK(gtk_main_quit),NULL);
493         gtk_main();
494         /* 'dialog' gets destroyed automatically */
495         if (reply==0)   /* 0 for 'OK', 1 for 'Cancel', left -1 for dialog close. */
496                 exit(EXIT_SUCCESS);
497 }
498
499 static void button_stock_set_label(GtkWidget *widget,const gchar *label_text_new /* callback_data */)
500 {
501         g_return_if_fail(GTK_IS_WIDGET(widget));
502         g_return_if_fail(label_text_new!=NULL);
503
504         /**/ if (GTK_IS_CONTAINER(widget))
505                 gtk_container_foreach(GTK_CONTAINER(widget),
506                                 (GtkCallback)button_stock_set_label,    /* callback */
507                                 (/* de-conts */ gchar *)label_text_new);        /* callback_data */
508         else if (GTK_IS_LABEL(widget))
509                 gtk_label_set_text_with_mnemonic(GTK_LABEL(widget),label_text_new);
510 }
511
512 /* of "ui-gnome-interface.h": */
513 GtkWidget *create_App(void);
514 /* of "ui-gnome-support.h": */
515 GtkWidget *lookup_widget(GtkWidget *widget,const gchar *widget_name);
516
517 static void App_init(void)
518 {
519 GtkTreeViewColumn *column;
520 GtkCellRenderer *cell;
521 GtkBox *druid_button_box;
522
523         App=GNOME_APP(create_App());
524
525         DriversTreeView=GTK_TREE_VIEW(lookup_widget(GTK_WIDGET(App),"DriversTreeView"));
526         DriversFrame=GTK_FRAME(lookup_widget(GTK_WIDGET(App),"DriversFrame"));
527         ProgressFrame=GTK_FRAME(lookup_widget(GTK_WIDGET(App),"ProgressFrame"));
528         Druid=GNOME_DRUID(lookup_widget(GTK_WIDGET(App),"Druid"));
529         PageStart=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"PageStart"));
530         ScanDiskPage=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"ScanDiskPage"));
531         ScanPathPage=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"ScanPathPage"));
532         MicrosoftComPage=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"MicrosoftComPage"));
533         PageFinish=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"PageFinish"));
534         ScanPathLocationComboEntry=GTK_ENTRY(lookup_widget(GTK_WIDGET(App),"ScanPathLocationComboEntry"));
535         MicrosoftComConfirmButton=GTK_BUTTON(lookup_widget(GTK_WIDGET(App),"MicrosoftComConfirmButton"));
536         MicrosoftComProgress=GTK_PROGRESS_BAR(lookup_widget(GTK_WIDGET(App),"MicrosoftComProgress"));
537         ProgressEntry=GTK_ENTRY(lookup_widget(GTK_WIDGET(App),"ProgressEntry"));
538
539         druid_button_box=GTK_BOX(gtk_widget_get_parent(Druid->next));
540
541         DriversTreeStore=gtk_tree_store_new(DRIVERS_TREE_STORE_COLUMN_NUM,DRIVERS_TREE_STORE_COLUMN_TYPE_LIST);
542         gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(DriversTreeStore),
543                         DRIVERS_TREE_STORE_COLUMN_TYPE,GTK_SORT_ASCENDING);
544         gtk_tree_view_set_model(DriversTreeView,GTK_TREE_MODEL(DriversTreeStore));
545
546         column=gtk_tree_view_column_new();
547         cell=gtk_cell_renderer_text_new();
548         gtk_tree_view_column_pack_start(column,cell,
549                         TRUE);  /* expand */
550         gtk_tree_view_column_set_attributes(column,cell,
551                         "text",DRIVERS_TREE_STORE_COLUMN_TYPE,
552                         NULL);
553         gtk_tree_view_append_column(DriversTreeView,column);
554
555         column=gtk_tree_view_column_new();
556         cell=gtk_cell_renderer_text_new();
557         gtk_tree_view_column_pack_start(column,cell,
558                         TRUE);  /* expand */
559         gtk_tree_view_column_set_attributes(column,cell,
560                         "text",DRIVERS_TREE_STORE_COLUMN_ID,
561                         NULL);
562         gtk_tree_view_append_column(DriversTreeView,column);
563
564         /* gnome_druid_set_show_finish() just replaces Next<->Finish buttons displayed. */
565         gtk_widget_hide(GTK_WIDGET(Druid->finish));
566
567         DruidButtonSkip=GTK_BUTTON(gtk_button_new_from_stock(GTK_STOCK_REDO));
568         gtk_container_foreach(GTK_CONTAINER(DruidButtonSkip),
569                         (GtkCallback)button_stock_set_label,    /* callback */
570                         _("_Skip"));    /* callback_data */
571         gtk_box_pack_end(druid_button_box,GTK_WIDGET(DruidButtonSkip),FALSE,TRUE,0);
572         gtk_widget_show(GTK_WIDGET(DruidButtonSkip));
573         g_signal_connect((gpointer)DruidButtonSkip,"clicked",G_CALLBACK(on_DruidButtonSkip_clicked),NULL);
574
575         DruidButtonOK=GTK_BUTTON(gtk_button_new_from_stock(GTK_STOCK_OK));
576         gtk_box_pack_end(druid_button_box,GTK_WIDGET(DruidButtonOK),FALSE,TRUE,0);
577         gtk_widget_show(GTK_WIDGET(DruidButtonOK));
578         g_signal_connect((gpointer)DruidButtonOK,"clicked",G_CALLBACK(on_DruidButtonOK_clicked),NULL);
579
580         state_changed();
581 }
582
583 static void ui_gnome_g_log_handler(const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data)
584 {
585 GtkWidget *dialog;
586
587         /* Ignore arrors by cabextract during its abortion. */
588         if (in_progress && aborted)
589                 return;
590
591         /**/ if (log_level & G_LOG_LEVEL_ERROR)
592                 dialog=gnome_app_error(App,message);
593         else if (log_level & (G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING))
594                 dialog=gnome_app_warning(App,message);
595         else
596                 dialog=gnome_app_message(App,message);
597
598         gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
599         g_signal_connect((gpointer)dialog,"close",G_CALLBACK(gtk_main_quit),NULL);
600         gtk_main();
601         /* 'dialog' gets destroyed automatically */
602 }
603
604 static void ui_gnome_interactive(void)
605 {
606         gtk_widget_show_all(GTK_WIDGET(App));
607         gtk_main();
608         exit(EXIT_SUCCESS);
609 }
610
611 gboolean ui_gnome_init(void)
612 {
613         acquire_module_available_notify=ui_gnome_module_available_notify;
614         acquire_module_all_modules_found_notify=ui_gnome_all_modules_found_notify;
615         ui_progress=ui_gnome_progress;
616         ui_progress_bar=ui_gnome_progress_bar;
617         ui_interactive=ui_gnome_interactive;
618         captivemodid_module_best_priority_notify=ui_gnome_module_best_priority_notify;
619
620         /* Graphic widgets will all be hidden yet. */
621         App_init();
622         /* ui_gnome_g_log_handler() needs 'App'. */
623         g_log_set_handler(
624                         G_LOG_DOMAIN,   /* log_domain; "Captive" */
625                         G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL,    /* log_levels */
626                         ui_gnome_g_log_handler, /* log_func */
627                         NULL);  /* user_data */
628
629         return TRUE;
630 }