2 * Drivers acquiring installation utility
3 * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
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
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.
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
22 #include "ui-gnome.h" /* self */
23 #include <glib/gmessages.h>
24 #include "moduriload.h"
26 #include <gtk/gtkmain.h>
27 #include <gtk/gtktreeviewcolumn.h>
28 #include <gtk/gtkbox.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>
38 #include <libgnomevfs/gnome-vfs-utils.h>
39 #include <libgnomeui/gnome-dialog.h>
41 #include <captive/macros.h>
42 #include <captive/captivemodid.h>
46 #define PROGRESS_UPDATE_USEC 200000
47 /* Although proper GTK+ locking is provided below there are some
48 * bugs with compatibility of GTK+/Gnome-VFS/GConf.
49 * The main thread executes gtk_main()->g_main_loop_run()
50 * while the working thread initializes Gnome-VFS by GConf and
51 * executes also g_main_loop_run() while sharing some poll() fds.
53 /* #define UI_GNOME_THREADS 1 */
57 static GtkTreeStore *DriversTreeStore;
58 static GtkFrame *DriversFrame;
59 static GtkFrame *ProgressFrame;
60 static GtkEntry *ProgressEntry;
61 static GnomeDruid *Druid;
62 static GtkButton *DruidButtonSkip;
63 static GtkButton *DruidButtonOK;
64 static GtkTreeView *DriversTreeView;
65 static GnomeDruidPage *PageStart;
66 static GnomeDruidPage *ScanDiskPage;
67 static GnomeDruidPage *ScanPathPage;
68 static GnomeDruidPage *MicrosoftComPage;
69 static GnomeDruidPage *PageFinish;
70 static GtkEntry *ScanPathLocationComboEntry;
71 static GtkButton *MicrosoftComConfirmButton;
72 static GtkProgressBar *MicrosoftComProgress;
74 DRIVERS_TREE_STORE_COLUMN_TYPE,
75 DRIVERS_TREE_STORE_COLUMN_ID,
76 DRIVERS_TREE_STORE_COLUMN_NUM, /* total # */
78 #define DRIVERS_TREE_STORE_COLUMN_TYPE_LIST G_TYPE_STRING,G_TYPE_STRING
81 /* map: (gchar *)type-> (GtkTreeIter *) */
82 static GHashTable *DriversTreeStore_Iter_hash;
84 static void DriversTreeStore_Iter_hash_key_destroy_func(gchar *type)
86 g_return_if_fail(type!=NULL);
91 static void DriversTreeStore_Iter_hash_init(void)
93 if (DriversTreeStore_Iter_hash)
95 DriversTreeStore_Iter_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
96 (GDestroyNotify)DriversTreeStore_Iter_hash_key_destroy_func,
97 NULL); /* value_destroy_func */
100 static GtkTreeIter *DriversTreeStore_Iter_hash_get_iter(const gchar *type)
104 g_return_val_if_fail(type!=NULL,NULL);
106 DriversTreeStore_Iter_hash_init();
107 if (!(r=g_hash_table_lookup(DriversTreeStore_Iter_hash,type))) {
109 gtk_tree_store_append(DriversTreeStore,
112 g_hash_table_insert(DriversTreeStore_Iter_hash,g_strdup(type),r);
118 static gboolean some_modules_found=FALSE;
119 static gboolean in_progress=FALSE;
120 static GnomeDruidPage *page_active;
122 static void state_changed(void)
124 /* Not yet initialized? */
128 gtk_widget_set_sensitive(GTK_WIDGET(DruidButtonSkip),
129 (page_active!=PageStart && page_active!=PageFinish));
130 gtk_widget_set_sensitive(GTK_WIDGET(DruidButtonOK),some_modules_found);
133 gtk_widget_set_sensitive(Druid->next,FALSE);
134 gtk_widget_set_sensitive(GTK_WIDGET(DruidButtonOK),some_modules_found);
135 gtk_widget_set_sensitive(GTK_WIDGET(MicrosoftComConfirmButton),FALSE);
138 /* It is checked by GTK+ whether the text changed: */
139 gtk_entry_set_text(ProgressEntry,"");
140 gtk_widget_set_sensitive(Druid->next,
141 (page_active!=PageFinish && page_active!=MicrosoftComPage));
142 gtk_widget_set_sensitive(GTK_WIDGET(MicrosoftComConfirmButton),
143 (page_active==MicrosoftComPage));
144 gtk_progress_bar_set_fraction(MicrosoftComProgress,(gdouble)0);
145 gtk_progress_bar_set_text(MicrosoftComProgress,"");
149 static void ui_gnome_module_best_priority_notify(const gchar *module_type)
153 g_return_if_fail(module_type!=NULL);
157 iter=DriversTreeStore_Iter_hash_get_iter(module_type);
158 gtk_tree_store_set(DriversTreeStore,iter,
159 DRIVERS_TREE_STORE_COLUMN_TYPE,module_type,
160 DRIVERS_TREE_STORE_COLUMN_ID ,
162 || !strcmp(module_type,"ntoskrnl.exe")
163 || !strcmp(module_type,"ntfs.sys"))
164 ? _("NOT FOUND; essential module for NTFS disks access")
165 : _("not found; optional module")),
172 static void ui_gnome_module_available_notify(struct module_available *module_available)
175 static gboolean some_module_ntoskrnl_exe_found=FALSE;
176 static gboolean some_module_ntfs_sys_found=FALSE;
178 g_return_if_fail(module_available!=NULL);
179 g_return_if_fail(module_available->module!=NULL);
183 iter=DriversTreeStore_Iter_hash_get_iter((const gchar *)module_available->module->type);
184 gtk_tree_store_set(DriversTreeStore,iter,
185 DRIVERS_TREE_STORE_COLUMN_TYPE,module_available->module->type,
186 DRIVERS_TREE_STORE_COLUMN_ID ,module_available->module->id,
189 if (!strcmp((const char *)module_available->module->type,"ntoskrnl.exe"))
190 some_module_ntoskrnl_exe_found=TRUE;
191 if (!strcmp((const char *)module_available->module->type,"ntfs.sys"))
192 some_module_ntfs_sys_found=TRUE;
194 some_modules_found=some_module_ntoskrnl_exe_found && some_module_ntfs_sys_found;
201 static gboolean all_modules_found=FALSE;
203 static void ui_gnome_all_modules_found_notify(void)
207 all_modules_found=TRUE;
214 static gboolean aborted=FALSE;
215 static gboolean aborted_back=FALSE; /* 'Back' button was clicked. */
216 static struct timeval ProgressEntry_updated_timeval;
217 static struct timeval ProgressBar_updated_timeval;
219 static void progress_start(void)
224 CAPTIVE_MEMZERO(&ProgressEntry_updated_timeval);
225 CAPTIVE_MEMZERO(&ProgressBar_updated_timeval);
229 static void progress_end(void)
235 static gboolean want_progress_update(struct timeval *timeval)
237 struct timeval now_timeval;
238 struct timeval diff_timeval;
240 g_return_val_if_fail(timeval!=NULL,FALSE);
242 gettimeofday( /* FIXME: errors ignored */
243 &now_timeval, /* tv */
245 timersub(&now_timeval,timeval,&diff_timeval);
246 if (!timeval->tv_sec || diff_timeval.tv_sec>0 || diff_timeval.tv_usec>=PROGRESS_UPDATE_USEC) {
247 *timeval=now_timeval;
253 static gboolean ui_gnome_progress(GnomeVFSURI *uri)
255 gboolean want_gdk_flush=FALSE;
257 /* 'uri' may be NULL */
262 static gchar *uri_text=NULL;
264 /* Store 'uri' on each call (not just if 'diff_timeval' permits)
265 * as we may get into long cabinet extraction phase with 'uri==NULL' calls
266 * where we want to display the currently processed 'uri'.
270 uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD);
274 if (want_progress_update(&ProgressEntry_updated_timeval)) {
275 gtk_entry_set_text(ProgressEntry,
276 uri_text+(strncmp(uri_text,"file://",strlen("file://")) ? 0 : strlen("file://")));
282 #ifndef UI_GNOME_THREADS
283 while (g_main_context_pending(NULL))
284 g_main_context_iteration(
286 FALSE); /* may_block */
287 #endif /* UI_GNOME_THREADS */
293 /* Do not: g_thread_yield();
294 * as it is TOO much expensive and we are multithreaded anyway.
299 if (all_modules_found)
305 static void ui_gnome_progress_bar(gint done,gint length)
307 g_return_if_fail(done>=0);
308 g_return_if_fail(length>=0);
310 if (!want_progress_update(&ProgressBar_updated_timeval))
316 gtk_progress_bar_pulse(MicrosoftComProgress);
317 gtk_progress_bar_set_text(MicrosoftComProgress,"");
320 gchar *length_display;
322 /* Do not format 'done' by gnome_vfs_format_file_size_for_display()
323 * as the progress would not be visible for large 'done' sizes.
325 gtk_progress_bar_set_fraction(MicrosoftComProgress,((gdouble)done)/length);
326 length_display=gnome_vfs_format_file_size_for_display(length);
327 gtk_progress_bar_set_text(MicrosoftComProgress,
328 captive_printf_alloca("%d B / %s",(int)done,length_display));
329 g_free(length_display);
336 /* FIXME: Change it to "prepare" signal. */
337 void on_Page_map(GtkWidget *vbox_widget,GtkWidget *page_widget)
339 /* Handle non-object (NULL) signal with reversed parameters? */
340 if (GNOME_IS_DRUID_PAGE(vbox_widget) && page_widget==NULL) {
341 page_widget=vbox_widget;
344 g_return_if_fail(vbox_widget==NULL || GTK_IS_VBOX(vbox_widget));
345 g_return_if_fail(GNOME_IS_DRUID_PAGE(page_widget));
347 page_active=GNOME_DRUID_PAGE(page_widget);
348 if (page_active==PageFinish) {
349 gnome_druid_set_show_finish(Druid,FALSE); /* set it each time */
350 /**/ if (!some_modules_found)
351 gnome_druid_page_edge_set_text(GNOME_DRUID_PAGE_EDGE(PageFinish),_(
352 "We need at least some version of drivers essential for this project:"
353 " ntoskrnl.exe and ntfs.sys. Please click 'Back' button to obtain them"
354 " by several methods offered by this installer."));
358 text=final_text(all_modules_found);
359 gnome_druid_page_edge_set_text(GNOME_DRUID_PAGE_EDGE(PageFinish),text);
363 if (page_active==ScanPathPage)
364 gtk_widget_grab_focus(GTK_WIDGET(ScanPathLocationComboEntry));
370 /* FIXME: 'freeze' apparently does not help 'repositioning' of
371 * 'DriversTreeView' during first 'map' of each 'Page'.
373 gtk_widget_freeze_child_notify(vbox_widget);
375 gtk_widget_reparent(GTK_WIDGET(DriversFrame),vbox_widget);
376 gtk_widget_reparent(GTK_WIDGET(ProgressFrame),vbox_widget);
378 gtk_box_reorder_child(GTK_BOX(vbox_widget),GTK_WIDGET(DriversFrame),
381 gtk_box_set_child_packing(GTK_BOX(vbox_widget),GTK_WIDGET(DriversFrame),
386 gtk_box_set_child_packing(GTK_BOX(vbox_widget),GTK_WIDGET(ProgressFrame),
392 /* FIXME: Needed to fix (0,0)-position inside parent GdkWindow. */
393 gtk_widget_queue_resize(GTK_WIDGET(DriversTreeView));
394 gtk_widget_queue_resize(GTK_WIDGET(ProgressEntry));
396 gtk_widget_thaw_child_notify(vbox_widget);
399 typedef void (*process_t)(void);
401 #ifdef UI_GNOME_THREADS
402 /* 'GThreadFunc' type. */
403 gpointer execute_process_func(process_t process /* data */)
409 gtk_main_quit(); /* Abort gtk_main() of execute_process(). */
416 #endif /* UI_GNOME_THREADS */
418 /* We are called inside gdk_threads_enter(). */
419 static void execute_process(process_t process)
421 #ifdef UI_GNOME_THREADS
423 #endif /* UI_GNOME_THREADS */
426 #ifdef UI_GNOME_THREADS
427 gthread=g_thread_create_full(
428 (GThreadFunc)execute_process_func, /* func */
430 0, /* stack_size; 0 means the default size */
432 TRUE, /* bound; use system thread */
433 G_THREAD_PRIORITY_LOW, /* priority; G_THREAD_PRIORITY_LOW is the lowest one */
435 gtk_main(); /* We are already called inside gdk_threads_enter(). */
436 /* I hope some other gtk_main_quit() did not occur as we would
437 * locked if the 'process' func did not finish yet.
439 g_thread_join(gthread);
440 #else /* UI_GNOME_THREADS */
442 #endif /* UI_GNOME_THREADS */
446 /* 'process_t' typed. */
447 static void process_scan_disk(void)
453 static GnomeVFSURI *process_scan_path_scan_path_uri;
455 /* 'process_t' typed. */
456 static void process_scan_path(void)
458 mod_uri_load_base_reporting(process_scan_path_scan_path_uri);
461 /* 'process_t' typed. */
462 static void process_microsoft_com(void)
467 gboolean on_Page_next(GnomeDruidPage *gnomedruidpage,GtkWidget *widget,gpointer user_data /* unused */)
469 g_return_val_if_fail(GNOME_IS_DRUID_PAGE(gnomedruidpage),FALSE);
471 if (in_progress) /* bogus callback - we should be non-sensitive */
472 return TRUE; /* ignore button press */
474 /**/ if (page_active==PageStart) {
475 if (all_modules_found) {
476 gnome_druid_set_page(Druid,PageFinish);
477 return TRUE; /* ignore button press */
480 else if (page_active==ScanDiskPage) {
481 execute_process(process_scan_disk);
483 gnome_druid_set_page(Druid,PageStart);
484 return TRUE; /* ignore button press */
486 if (all_modules_found) {
487 gnome_druid_set_page(Druid,PageFinish);
488 return TRUE; /* ignore button press */
490 return FALSE; /* proceed to next page */
492 else if (page_active==ScanPathPage) {
493 const gchar *scan_path_uri_text=gtk_entry_get_text(ScanPathLocationComboEntry);
495 if (scan_path_uri_text && *scan_path_uri_text) {
496 GnomeVFSURI *scan_path_uri;
498 if ((scan_path_uri=gnome_vfs_uri_new(scan_path_uri_text))) {
499 process_scan_path_scan_path_uri=scan_path_uri;
500 execute_process(process_scan_path);
501 gnome_vfs_uri_unref(scan_path_uri);
503 gnome_druid_set_page(Druid,(all_modules_found ? PageStart : ScanDiskPage));
504 return TRUE; /* ignore button press */
506 if (all_modules_found) {
507 gnome_druid_set_page(Druid,PageFinish);
508 return TRUE; /* ignore button press */
510 gtk_entry_set_text(ScanPathLocationComboEntry,"");
513 g_warning(_("Invalid URI: %s"),scan_path_uri_text);
514 gtk_widget_grab_focus(GTK_WIDGET(ScanPathLocationComboEntry));
515 return TRUE; /* ignore button press; we cleared the URI entry */
517 return FALSE; /* proceed to next page */
520 return FALSE; /* proceed to next page */
523 void on_MicrosoftComConfirmButton_clicked(GtkButton *button,gpointer user_data)
525 g_return_if_fail(GTK_IS_BUTTON(button));
527 if (in_progress) /* bogus callback */
529 if (page_active!=MicrosoftComPage) /* bogus callback */
532 execute_process(process_microsoft_com);
534 gnome_druid_set_page(Druid,(all_modules_found ? PageStart : ScanPathPage));
537 if (all_modules_found) {
538 gnome_druid_set_page(Druid,PageFinish);
542 gnome_druid_set_page(Druid,PageFinish);
545 void on_DruidButtonSkip_clicked(GtkButton *button,gpointer user_data /* unused */)
547 g_return_if_fail(GTK_IS_BUTTON(button));
554 if (all_modules_found)
555 gnome_druid_set_page(Druid,PageFinish);
556 else if (page_active==ScanDiskPage)
557 gnome_druid_set_page(Druid,ScanPathPage);
558 else if (page_active==ScanPathPage)
559 gnome_druid_set_page(Druid,MicrosoftComPage);
560 else if (page_active==MicrosoftComPage)
561 gnome_druid_set_page(Druid,PageFinish);
564 gboolean on_Page_back(GnomeDruidPage *gnomedruidpage,GtkWidget *widget,gpointer user_data)
566 g_return_val_if_fail(GNOME_IS_DRUID_PAGE(gnomedruidpage),FALSE);
569 if (all_modules_found) {
570 gnome_druid_set_page(Druid,PageStart);
571 return TRUE; /* ignore button press */
573 return FALSE; /* proceed to previous page */
580 return TRUE; /* ignore button press now; we will respect 'aborted_back' */
583 void on_Druid_cancel(GnomeDruid *gnomedruid,gpointer user_data /* unused */)
585 g_return_if_fail(GNOME_IS_DRUID(gnomedruid));
587 /* gtk_main_quit() would not abort the current operation. */
591 static void on_DruidButtonOK_clicked_dialog_callback(gint reply,gint *replyp /* data */)
593 g_return_if_fail(reply>=0);
594 g_return_if_fail(replyp!=NULL);
600 void on_DruidButtonOK_clicked(GtkButton *button,gpointer user_data /* unused */)
605 g_return_if_fail(GTK_IS_BUTTON(button));
607 if (all_modules_found)
610 /* TODO: Avoid dialog if already on Finish page. */
612 dialog=gnome_app_ok_cancel_modal(App,_(
613 "Although essential modules (\"ntoskrnl.exe\" and \"ntfs.sys\") are available "
614 "you may still want to get their better version and/or more modules. "
616 (GnomeReplyCallback)on_DruidButtonOK_clicked_dialog_callback,
618 g_signal_connect((gpointer)dialog,"close",G_CALLBACK(gtk_main_quit),NULL);
619 gnome_dialog_set_close(GNOME_DIALOG(dialog),FALSE);
620 /* Never call gtk_main() from other thread than the initial one.
621 * We would have to switch GTK+ context (g_main_context()?).
624 if (reply==0) /* 0 for 'OK', 1 for 'Cancel', left -1 for dialog close. */
626 /* It is still needed despite: gnome_dialog_set_close(,TRUE);
627 * in: libgnomeui-2.10.0-1
628 * There may be some races regarding when is ran: gtk_main_quit();
630 gtk_widget_destroy(dialog);
633 static void button_stock_set_label(GtkWidget *widget,const gchar *label_text_new /* callback_data */)
635 g_return_if_fail(GTK_IS_WIDGET(widget));
636 g_return_if_fail(label_text_new!=NULL);
638 /**/ if (GTK_IS_CONTAINER(widget))
639 gtk_container_foreach(GTK_CONTAINER(widget),
640 (GtkCallback)button_stock_set_label, /* callback */
641 (/* de-conts */ gchar *)label_text_new); /* callback_data */
642 else if (GTK_IS_LABEL(widget))
643 gtk_label_set_text_with_mnemonic(GTK_LABEL(widget),label_text_new);
646 static void PageFinish_set_label_attr(GtkWidget *widget,gpointer callback_data /* unused */)
648 g_return_if_fail(GTK_IS_WIDGET(widget));
650 /**/ if (GTK_IS_CONTAINER(widget))
651 gtk_container_foreach(GTK_CONTAINER(widget),
652 (GtkCallback)PageFinish_set_label_attr, /* callback */
653 callback_data); /* callback_data; unused */
654 else if (GTK_IS_LABEL(widget) && gtk_label_get_line_wrap(GTK_LABEL(widget)))
655 gtk_label_set_selectable(GTK_LABEL(widget),TRUE);
658 /* of "ui-gnome-interface.h": */
659 GtkWidget *create_App(void);
660 /* of "ui-gnome-support.h": */
661 GtkWidget *lookup_widget(GtkWidget *widget,const gchar *widget_name);
663 static void App_init(void)
665 GtkTreeViewColumn *column;
666 GtkCellRenderer *cell;
667 GtkBox *druid_button_box;
671 App=GNOME_APP(create_App());
673 DriversTreeView=GTK_TREE_VIEW(lookup_widget(GTK_WIDGET(App),"DriversTreeView"));
674 DriversFrame=GTK_FRAME(lookup_widget(GTK_WIDGET(App),"DriversFrame"));
675 ProgressFrame=GTK_FRAME(lookup_widget(GTK_WIDGET(App),"ProgressFrame"));
676 Druid=GNOME_DRUID(lookup_widget(GTK_WIDGET(App),"Druid"));
677 PageStart=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"PageStart"));
678 ScanDiskPage=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"ScanDiskPage"));
679 ScanPathPage=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"ScanPathPage"));
680 MicrosoftComPage=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"MicrosoftComPage"));
681 PageFinish=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"PageFinish"));
682 ScanPathLocationComboEntry=GTK_ENTRY(lookup_widget(GTK_WIDGET(App),"ScanPathLocationComboEntry"));
683 MicrosoftComConfirmButton=GTK_BUTTON(lookup_widget(GTK_WIDGET(App),"MicrosoftComConfirmButton"));
684 MicrosoftComProgress=GTK_PROGRESS_BAR(lookup_widget(GTK_WIDGET(App),"MicrosoftComProgress"));
685 ProgressEntry=GTK_ENTRY(lookup_widget(GTK_WIDGET(App),"ProgressEntry"));
687 druid_button_box=GTK_BOX(gtk_widget_get_parent(Druid->next));
689 DriversTreeStore=gtk_tree_store_new(DRIVERS_TREE_STORE_COLUMN_NUM,DRIVERS_TREE_STORE_COLUMN_TYPE_LIST);
690 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(DriversTreeStore),
691 DRIVERS_TREE_STORE_COLUMN_TYPE,GTK_SORT_ASCENDING);
692 gtk_tree_view_set_model(DriversTreeView,GTK_TREE_MODEL(DriversTreeStore));
694 column=gtk_tree_view_column_new();
695 cell=gtk_cell_renderer_text_new();
696 gtk_tree_view_column_pack_start(column,cell,
698 gtk_tree_view_column_set_attributes(column,cell,
699 "text",DRIVERS_TREE_STORE_COLUMN_TYPE,
701 gtk_tree_view_append_column(DriversTreeView,column);
703 column=gtk_tree_view_column_new();
704 cell=gtk_cell_renderer_text_new();
705 gtk_tree_view_column_pack_start(column,cell,
707 gtk_tree_view_column_set_attributes(column,cell,
708 "text",DRIVERS_TREE_STORE_COLUMN_ID,
710 gtk_tree_view_append_column(DriversTreeView,column);
712 /* gnome_druid_set_show_finish() just replaces Next<->Finish buttons displayed. */
713 gtk_widget_hide(GTK_WIDGET(Druid->finish));
715 DruidButtonSkip=GTK_BUTTON(gtk_button_new_from_stock(GTK_STOCK_REDO));
716 button_stock_set_label(
717 GTK_WIDGET(DruidButtonSkip), /* widget */
718 _("_Skip")); /* label_text_new */
719 gtk_box_pack_end(druid_button_box,GTK_WIDGET(DruidButtonSkip),FALSE,TRUE,0);
720 gtk_widget_show(GTK_WIDGET(DruidButtonSkip));
721 g_signal_connect((gpointer)DruidButtonSkip,"clicked",G_CALLBACK(on_DruidButtonSkip_clicked),NULL);
723 DruidButtonOK=GTK_BUTTON(gtk_button_new_from_stock(GTK_STOCK_OK));
724 gtk_box_pack_end(druid_button_box,GTK_WIDGET(DruidButtonOK),FALSE,TRUE,0);
725 gtk_widget_show(GTK_WIDGET(DruidButtonOK));
726 g_signal_connect((gpointer)DruidButtonOK,"clicked",G_CALLBACK(on_DruidButtonOK_clicked),NULL);
728 PageFinish_set_label_attr(
729 GTK_WIDGET(PageFinish), /* widget */
730 NULL); /* callback_data; unused */
737 static void ui_gnome_g_log_handler(const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data)
741 /* Ignore arrors by cabextract during its abortion. */
742 if (in_progress && aborted)
747 /**/ if (log_level & G_LOG_LEVEL_ERROR)
748 dialog=gnome_app_error(App,message);
749 else if (log_level & (G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING))
750 dialog=gnome_app_warning(App,message);
752 dialog=gnome_app_message(App,message);
754 gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
755 /* See also around: gnome_dialog_set_close(); */
756 gnome_dialog_set_close(GNOME_DIALOG(dialog),FALSE);
757 g_signal_connect((gpointer)dialog,"close" ,G_CALLBACK(gtk_main_quit),NULL);
758 g_signal_connect((gpointer)dialog,"clicked",G_CALLBACK(gtk_main_quit),NULL);
760 /* See also around: gnome_dialog_set_close(); */
761 gtk_widget_destroy(dialog);
767 static void ui_gnome_interactive(void)
771 /* Postpone gtk_widget_show_all() from App_init() here
772 * to have already passed all ui_gnome_module_available_notify().
774 gnome_druid_set_page(Druid,MicrosoftComPage);
775 gtk_widget_show_all(GTK_WIDGET(App));
777 /* gnome_druid_set_page(Druid,PageStart); */
778 gnome_druid_set_page(Druid,ScanDiskPage);
779 gnome_druid_set_page(Druid,ScanPathPage);
780 /* gnome_druid_set_page(Druid,MicrosoftComPage); */
781 gnome_druid_set_page(Druid,PageFinish);
783 gnome_druid_set_page(Druid,PageStart);
792 gboolean ui_gnome_init(void)
794 acquire_module_available_notify=ui_gnome_module_available_notify;
795 acquire_module_all_modules_found_notify=ui_gnome_all_modules_found_notify;
796 ui_progress=ui_gnome_progress;
797 ui_progress_bar=ui_gnome_progress_bar;
798 ui_interactive=ui_gnome_interactive;
799 captive_captivemodid_module_best_priority_notify=ui_gnome_module_best_priority_notify;
801 #ifdef UI_GNOME_THREADS
802 /* gdk_threads_init() must be called before gtk_init()!
803 * gtk_init() gets called by create_App() here.
805 if (!g_thread_supported())
807 if (!gdk_threads_mutex)
809 #endif /* UI_GNOME_THREADS */
811 /* Graphic widgets will all be hidden yet. */
813 /* ui_gnome_g_log_handler() needs 'App'. */
815 G_LOG_DOMAIN, /* log_domain; "Captive" */
816 G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL, /* log_levels */
817 ui_gnome_g_log_handler, /* log_func */
818 NULL); /* user_data */