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