+/* $Id$
+ * Drivers acquiring installation utility
+ * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "config.h"
+
+#include "ui-gnome.h" /* self */
+#include <glib/gmessages.h>
+#include "moduriload.h"
+#include "main.h"
+#include <gtk/gtkmain.h>
+#include <gtk/gtktreeviewcolumn.h>
+#include <gtk/gtkbox.h>
+#include <sys/time.h>
+#include <libgnomeui/gnome-app.h>
+#include <gtk/gtktreestore.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtkentry.h>
+#include <libgnomeui/gnome-druid.h>
+#include <libgnomeui/gnome-app-util.h>
+#include <libgnomeui/gnome-druid-page-edge.h>
+#include "final.h"
+
+#include <captive/macros.h>
+
+
+/* Config: */
+#define PROGRESS_UPDATE_USEC 100000
+
+
+static GnomeApp *App;
+static GtkTreeStore *DriversTreeStore;
+static GtkFrame *DriversFrame;
+static GtkFrame *ProgressFrame;
+static GtkEntry *ProgressEntry;
+static GnomeDruid *Druid;
+static GtkButton *DruidButtonSkip;
+static GtkButton *DruidButtonOK;
+static GtkTreeView *DriversTreeView;
+static GnomeDruidPage *PageStart;
+static GnomeDruidPage *ScanDiskPage;
+static GnomeDruidPage *ScanPathPage;
+static GnomeDruidPage *MicrosoftComPage;
+static GnomeDruidPage *PageFinish;
+static GtkEntry *ScanPathLocationComboEntry;
+static GtkButton *MicrosoftComConfirmButton;
+enum {
+ DRIVERS_TREE_STORE_COLUMN_TYPE,
+ DRIVERS_TREE_STORE_COLUMN_ID,
+ DRIVERS_TREE_STORE_COLUMN_NUM, /* total # */
+ };
+#define DRIVERS_TREE_STORE_COLUMN_TYPE_LIST G_TYPE_STRING,G_TYPE_STRING
+
+
+/* map: (gchar *)type-> (GtkTreeIter *) */
+static GHashTable *DriversTreeStore_Iter_hash;
+
+static void DriversTreeStore_Iter_hash_key_destroy_func(gchar *type)
+{
+ g_return_if_fail(type!=NULL);
+
+ g_free(type);
+}
+
+static void DriversTreeStore_Iter_hash_init(void)
+{
+ if (DriversTreeStore_Iter_hash)
+ return;
+ DriversTreeStore_Iter_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
+ (GDestroyNotify)DriversTreeStore_Iter_hash_key_destroy_func,
+ NULL); /* value_destroy_func */
+}
+
+static GtkTreeIter *DriversTreeStore_Iter_hash_get_iter(const gchar *type)
+{
+GtkTreeIter *r;
+
+ g_return_val_if_fail(type!=NULL,NULL);
+
+ DriversTreeStore_Iter_hash_init();
+ if (!(r=g_hash_table_lookup(DriversTreeStore_Iter_hash,type))) {
+ captive_new(r);
+ gtk_tree_store_append(DriversTreeStore,
+ r, /* iter */
+ NULL); /* parent */
+ g_hash_table_insert(DriversTreeStore_Iter_hash,g_strdup(type),r);
+ }
+
+ return r;
+}
+
+static gboolean some_modules_found=FALSE;
+static gboolean in_progress=FALSE;
+static GnomeDruidPage *page_active;
+
+static void state_changed(void)
+{
+ /* Not yet initialized? */
+ if (!App)
+ return;
+
+ gtk_widget_set_sensitive(GTK_WIDGET(DruidButtonSkip),
+ (page_active!=PageStart && page_active!=PageFinish));
+ gtk_widget_set_sensitive(GTK_WIDGET(DruidButtonOK),some_modules_found);
+
+ if (in_progress) {
+ gtk_widget_set_sensitive(Druid->next,FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(DruidButtonOK),some_modules_found);
+ gtk_widget_set_sensitive(GTK_WIDGET(MicrosoftComConfirmButton),FALSE);
+ }
+ else {
+ /* It is checked by GTK+ whether the text changed: */
+ gtk_entry_set_text(ProgressEntry,"");
+ gtk_widget_set_sensitive(Druid->next,
+ (page_active!=PageFinish && page_active!=MicrosoftComPage));
+ gtk_widget_set_sensitive(GTK_WIDGET(MicrosoftComConfirmButton),
+ (page_active==MicrosoftComPage));
+ }
+}
+
+static void ui_gnome_module_best_priority_notify(const gchar *module_type)
+{
+GtkTreeIter *iter;
+
+ g_return_if_fail(module_type!=NULL);
+
+ iter=DriversTreeStore_Iter_hash_get_iter(module_type);
+ gtk_tree_store_set(DriversTreeStore,iter,
+ DRIVERS_TREE_STORE_COLUMN_TYPE,module_type,
+ DRIVERS_TREE_STORE_COLUMN_ID ,
+ ((0
+ || !strcmp(module_type,"ntoskrnl.exe")
+ || !strcmp(module_type,"ntfs.sys"))
+ ? _("NOT FOUND; essential module for NTFS disks access")
+ : _("not found; optional module")),
+ -1);
+}
+
+static void ui_gnome_module_available_notify(struct module_available *module_available)
+{
+GtkTreeIter *iter;
+static gboolean some_module_ntoskrnl_exe_found=FALSE;
+static gboolean some_module_ntfs_sys_found=FALSE;
+
+ g_return_if_fail(module_available!=NULL);
+ g_return_if_fail(module_available->module!=NULL);
+
+ iter=DriversTreeStore_Iter_hash_get_iter(module_available->module->type);
+ gtk_tree_store_set(DriversTreeStore,iter,
+ DRIVERS_TREE_STORE_COLUMN_TYPE,module_available->module->type,
+ DRIVERS_TREE_STORE_COLUMN_ID ,module_available->module->id,
+ -1);
+
+ if (!strcmp(module_available->module->type,"ntoskrnl.exe"))
+ some_module_ntoskrnl_exe_found=TRUE;
+ if (!strcmp(module_available->module->type,"ntfs.sys"))
+ some_module_ntfs_sys_found=TRUE;
+
+ some_modules_found=some_module_ntoskrnl_exe_found && some_module_ntfs_sys_found;
+ state_changed();
+}
+
+static gboolean all_modules_found=FALSE;
+
+static void ui_gnome_all_modules_found_notify(void)
+{
+ all_modules_found=TRUE;
+ state_changed();
+}
+
+static gboolean aborted=FALSE;
+static gboolean aborted_back=FALSE; /* 'Back' button was clicked. */
+static struct timeval ProgressEntry_updated_timeval;
+
+static void progress_start(void)
+{
+ in_progress=TRUE;
+ aborted=FALSE;
+ aborted_back=FALSE;
+ CAPTIVE_MEMZERO(&ProgressEntry_updated_timeval);
+ state_changed();
+}
+
+static void progress_end(void)
+{
+ in_progress=FALSE;
+ state_changed();
+}
+
+static gboolean ui_gnome_progress(GnomeVFSURI *uri)
+{
+ /* 'uri' may be NULL */
+
+ if (ProgressEntry) {
+static gchar *uri_text=NULL;
+
+ /* Store 'uri' on each call (not just if 'diff_timeval' permits)
+ * as we may get into long cabinet extraction phase with 'uri==NULL' calls
+ * where we want to display the currently processed 'uri'.
+ */
+ if (uri) {
+ g_free(uri_text);
+ uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD);
+ }
+
+ if (uri_text) {
+struct timeval now_timeval;
+struct timeval diff_timeval;
+
+ gettimeofday( /* FIXME: errors ignored */
+ &now_timeval, /* tv */
+ NULL); /* tz */
+ timersub(&now_timeval,&ProgressEntry_updated_timeval,&diff_timeval);
+ if (!ProgressEntry_updated_timeval.tv_sec || diff_timeval.tv_sec>0 || diff_timeval.tv_usec>=PROGRESS_UPDATE_USEC) {
+ gtk_entry_set_text(ProgressEntry,
+ uri_text+(strncmp(uri_text,"file://",strlen("file://")) ? 0 : strlen("file://")));
+ ProgressEntry_updated_timeval=now_timeval;
+ }
+ }
+ }
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ if (aborted)
+ return TRUE;
+ if (all_modules_found)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* FIXME: Change it to "prepare" signal. */
+void on_Page_map(GtkWidget *vbox_widget,GtkWidget *page_widget)
+{
+ g_return_if_fail(vbox_widget==NULL || GTK_IS_VBOX(vbox_widget));
+ g_return_if_fail(GNOME_IS_DRUID_PAGE(page_widget));
+
+ page_active=GNOME_DRUID_PAGE(page_widget);
+ if (page_active==PageFinish) {
+ gnome_druid_set_show_finish(Druid,FALSE); /* set it each time */
+ /**/ if (!some_modules_found)
+ gnome_druid_page_edge_set_text(GNOME_DRUID_PAGE_EDGE(PageFinish),_(
+ "We need at least some version of drivers essential for this project:"
+ "ntoskrnl.exe and ntfs.sys. Please click 'Back' button to obtain them"
+ "by several methods offered by this installer."));
+ else {
+gchar *text;
+
+ text=final_text(all_modules_found);
+ gnome_druid_page_edge_set_text(GNOME_DRUID_PAGE_EDGE(PageFinish),text);
+ g_free(text);
+ }
+ }
+ if (page_active==ScanPathPage)
+ gtk_widget_grab_focus(GTK_WIDGET(ScanPathLocationComboEntry));
+ state_changed();
+
+ if (!vbox_widget)
+ return;
+
+ /* FIXME: 'freeze' apparently does not help 'repositioning' of
+ * 'DriversTreeView' during first 'map' of each 'Page'.
+ */
+ gtk_widget_freeze_child_notify(vbox_widget);
+
+ gtk_widget_reparent(GTK_WIDGET(DriversFrame),vbox_widget);
+ gtk_widget_reparent(GTK_WIDGET(ProgressFrame),vbox_widget);
+
+ gtk_box_reorder_child(GTK_BOX(vbox_widget),GTK_WIDGET(DriversFrame),
+ 0); /* position */
+
+ gtk_box_set_child_packing(GTK_BOX(vbox_widget),GTK_WIDGET(DriversFrame),
+ FALSE, /* expand */
+ TRUE, /* fill */
+ 0, /* padding */
+ GTK_PACK_START);
+ gtk_box_set_child_packing(GTK_BOX(vbox_widget),GTK_WIDGET(ProgressFrame),
+ FALSE, /* expand */
+ TRUE, /* fill */
+ 0, /* padding */
+ GTK_PACK_START);
+
+ /* FIXME: Needed to fix (0,0)-position inside parent GdkWindow. */
+ gtk_widget_queue_resize(GTK_WIDGET(DriversTreeView));
+ gtk_widget_queue_resize(GTK_WIDGET(ProgressEntry));
+
+ gtk_widget_thaw_child_notify(vbox_widget);
+}
+
+gboolean on_Page_next(GnomeDruidPage *gnomedruidpage,GtkWidget *widget,gpointer user_data /* unused */)
+{
+ g_return_val_if_fail(GNOME_IS_DRUID_PAGE(gnomedruidpage),FALSE);
+
+ if (in_progress) /* bogus callback - we should be non-sensitive */
+ return TRUE; /* ignore button press */
+
+ /**/ if (page_active==PageStart) {
+ if (all_modules_found) {
+ gnome_druid_set_page(Druid,PageFinish);
+ return TRUE; /* ignore button press */
+ }
+ }
+ else if (page_active==ScanDiskPage) {
+ progress_start();
+ scan_disks_quick();
+ scan_disks();
+ progress_end();
+ if (aborted_back) {
+ gnome_druid_set_page(Druid,PageStart);
+ return TRUE; /* ignore button press */
+ }
+ if (all_modules_found) {
+ gnome_druid_set_page(Druid,PageFinish);
+ return TRUE; /* ignore button press */
+ }
+ return FALSE; /* proceed to next page */
+ }
+ else if (page_active==ScanPathPage) {
+const gchar *scan_path_uri_text=gtk_entry_get_text(ScanPathLocationComboEntry);
+
+ if (scan_path_uri_text && *scan_path_uri_text) {
+GnomeVFSURI *scan_path_uri;
+
+ if ((scan_path_uri=gnome_vfs_uri_new(scan_path_uri_text))) {
+ progress_start();
+ mod_uri_load(scan_path_uri);
+ progress_end();
+ gnome_vfs_uri_unref(scan_path_uri);
+ if (aborted_back) {
+ gnome_druid_set_page(Druid,(all_modules_found ? PageStart : ScanDiskPage));
+ return TRUE; /* ignore button press */
+ }
+ if (all_modules_found) {
+ gnome_druid_set_page(Druid,PageFinish);
+ return TRUE; /* ignore button press */
+ }
+ gtk_entry_set_text(ScanPathLocationComboEntry,"");
+ }
+ else
+ g_warning(_("Invalid URI: %s"),scan_path_uri_text);
+ gtk_widget_grab_focus(GTK_WIDGET(ScanPathLocationComboEntry));
+ return TRUE; /* ignore button press; we cleared the URI entry */
+ }
+ return FALSE; /* proceed to next page */
+ }
+
+ return FALSE; /* proceed to next page */
+}
+
+void on_MicrosoftComConfirmButton_clicked(GtkButton *button,gpointer user_data)
+{
+ g_return_if_fail(GTK_IS_BUTTON(button));
+
+ if (in_progress) /* bogus callback */
+ return;
+ if (page_active!=MicrosoftComPage) /* bogus callback */
+ return;
+
+ progress_start();
+ microsoft_com();
+ progress_end();
+ if (aborted_back) {
+ gnome_druid_set_page(Druid,(all_modules_found ? PageStart : ScanPathPage));
+ return;
+ }
+ if (all_modules_found) {
+ gnome_druid_set_page(Druid,PageFinish);
+ return;
+ }
+
+ gnome_druid_set_page(Druid,PageFinish);
+}
+
+void on_DruidButtonSkip_clicked(GtkButton *button,gpointer user_data /* unused */)
+{
+ g_return_if_fail(GTK_IS_BUTTON(button));
+
+ if (in_progress) {
+ aborted=TRUE;
+ state_changed();
+ return;
+ }
+ if (all_modules_found)
+ gnome_druid_set_page(Druid,PageFinish);
+ else if (page_active==ScanDiskPage)
+ gnome_druid_set_page(Druid,ScanPathPage);
+ else if (page_active==ScanPathPage)
+ gnome_druid_set_page(Druid,MicrosoftComPage);
+ else if (page_active==MicrosoftComPage)
+ gnome_druid_set_page(Druid,PageFinish);
+}
+
+gboolean on_Page_back(GnomeDruidPage *gnomedruidpage,GtkWidget *widget,gpointer user_data)
+{
+ g_return_val_if_fail(GNOME_IS_DRUID_PAGE(gnomedruidpage),FALSE);
+
+ if (!in_progress) {
+ if (all_modules_found) {
+ gnome_druid_set_page(Druid,PageStart);
+ return TRUE; /* ignore button press */
+ }
+ return FALSE; /* proceed to previous page */
+ }
+
+ aborted=TRUE;
+ aborted_back=TRUE;
+ state_changed();
+
+ return TRUE; /* ignore button press now; we will respect 'aborted_back' */
+}
+
+void on_Druid_cancel(GnomeDruid *gnomedruid,gpointer user_data /* unused */)
+{
+ g_return_if_fail(GNOME_IS_DRUID(gnomedruid));
+
+ /* gtk_main_quit() would not abort the current operation. */
+ exit(EXIT_SUCCESS);
+}
+
+static void on_DruidButtonOK_clicked_dialog_callback(gint reply,gint *replyp /* data */)
+{
+ g_return_if_fail(reply>=0);
+ g_return_if_fail(replyp!=NULL);
+
+ *replyp=reply;
+}
+
+void on_DruidButtonOK_clicked(GtkButton *button,gpointer user_data /* unused */)
+{
+GtkWidget *dialog;
+gint reply;
+
+ g_return_if_fail(GTK_IS_BUTTON(button));
+
+ if (all_modules_found)
+ exit(EXIT_SUCCESS);
+
+ /* TODO: Avoid dialog if already on Finish page. */
+ reply=-1;
+ dialog=gnome_app_ok_cancel_modal(App,_(
+ "Although essential modules (\"ntoskrnl.exe\" and \"ntfs.sys\") are available"
+ "you may still want to get their better version and/or more modules."
+ "Really quit?"),
+ (GnomeReplyCallback)on_DruidButtonOK_clicked_dialog_callback,
+ &reply); /* data */
+ g_signal_connect((gpointer)dialog,"close",G_CALLBACK(gtk_main_quit),NULL);
+ gtk_main();
+ /* 'dialog' gets destroyed automatically */
+ if (reply==0) /* 0 for 'OK', 1 for 'Cancel', left -1 for dialog close. */
+ exit(EXIT_SUCCESS);
+}
+
+static void button_stock_set_label(GtkWidget *widget,const gchar *label_text_new /* callback_data */)
+{
+ g_return_if_fail(GTK_IS_WIDGET(widget));
+ g_return_if_fail(label_text_new!=NULL);
+
+ /**/ if (GTK_IS_CONTAINER(widget))
+ gtk_container_foreach(GTK_CONTAINER(widget),
+ (GtkCallback)button_stock_set_label, /* callback */
+ (/* de-conts */ gchar *)label_text_new); /* callback_data */
+ else if (GTK_IS_LABEL(widget))
+ gtk_label_set_text_with_mnemonic(GTK_LABEL(widget),label_text_new);
+}
+
+/* of "ui-gnome-interface.h": */
+GtkWidget *create_App(void);
+/* of "ui-gnome-support.h": */
+GtkWidget *lookup_widget(GtkWidget *widget,const gchar *widget_name);
+
+static void App_init(void)
+{
+GtkTreeViewColumn *column;
+GtkCellRenderer *cell;
+GtkBox *druid_button_box;
+
+ App=GNOME_APP(create_App());
+
+ DriversTreeView=GTK_TREE_VIEW(lookup_widget(GTK_WIDGET(App),"DriversTreeView"));
+ DriversFrame=GTK_FRAME(lookup_widget(GTK_WIDGET(App),"DriversFrame"));
+ ProgressFrame=GTK_FRAME(lookup_widget(GTK_WIDGET(App),"ProgressFrame"));
+ Druid=GNOME_DRUID(lookup_widget(GTK_WIDGET(App),"Druid"));
+ PageStart=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"PageStart"));
+ ScanDiskPage=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"ScanDiskPage"));
+ ScanPathPage=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"ScanPathPage"));
+ MicrosoftComPage=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"MicrosoftComPage"));
+ PageFinish=GNOME_DRUID_PAGE(lookup_widget(GTK_WIDGET(App),"PageFinish"));
+ ScanPathLocationComboEntry=GTK_ENTRY(lookup_widget(GTK_WIDGET(App),"ScanPathLocationComboEntry"));
+ MicrosoftComConfirmButton=GTK_BUTTON(lookup_widget(GTK_WIDGET(App),"MicrosoftComConfirmButton"));
+ ProgressEntry=GTK_ENTRY(lookup_widget(GTK_WIDGET(App),"ProgressEntry"));
+
+ druid_button_box=GTK_BOX(gtk_widget_get_parent(Druid->next));
+
+ DriversTreeStore=gtk_tree_store_new(DRIVERS_TREE_STORE_COLUMN_NUM,DRIVERS_TREE_STORE_COLUMN_TYPE_LIST);
+ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(DriversTreeStore),
+ DRIVERS_TREE_STORE_COLUMN_TYPE,GTK_SORT_ASCENDING);
+ gtk_tree_view_set_model(DriversTreeView,GTK_TREE_MODEL(DriversTreeStore));
+
+ column=gtk_tree_view_column_new();
+ cell=gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(column,cell,
+ TRUE); /* expand */
+ gtk_tree_view_column_set_attributes(column,cell,
+ "text",DRIVERS_TREE_STORE_COLUMN_TYPE,
+ NULL);
+ gtk_tree_view_append_column(DriversTreeView,column);
+
+ column=gtk_tree_view_column_new();
+ cell=gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(column,cell,
+ TRUE); /* expand */
+ gtk_tree_view_column_set_attributes(column,cell,
+ "text",DRIVERS_TREE_STORE_COLUMN_ID,
+ NULL);
+ gtk_tree_view_append_column(DriversTreeView,column);
+
+ /* gnome_druid_set_show_finish() just replaces Next<->Finish buttons displayed. */
+ gtk_widget_hide(GTK_WIDGET(Druid->finish));
+
+ DruidButtonSkip=GTK_BUTTON(gtk_button_new_from_stock(GTK_STOCK_REDO));
+ gtk_container_foreach(GTK_CONTAINER(DruidButtonSkip),
+ (GtkCallback)button_stock_set_label, /* callback */
+ _("_Skip")); /* callback_data */
+ gtk_box_pack_end(druid_button_box,GTK_WIDGET(DruidButtonSkip),FALSE,TRUE,0);
+ gtk_widget_show(GTK_WIDGET(DruidButtonSkip));
+ g_signal_connect((gpointer)DruidButtonSkip,"clicked",G_CALLBACK(on_DruidButtonSkip_clicked),NULL);
+
+ DruidButtonOK=GTK_BUTTON(gtk_button_new_from_stock(GTK_STOCK_OK));
+ gtk_box_pack_end(druid_button_box,GTK_WIDGET(DruidButtonOK),FALSE,TRUE,0);
+ gtk_widget_show(GTK_WIDGET(DruidButtonOK));
+ g_signal_connect((gpointer)DruidButtonOK,"clicked",G_CALLBACK(on_DruidButtonOK_clicked),NULL);
+
+ state_changed();
+}
+
+static void ui_gnome_g_log_handler(const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data)
+{
+GtkWidget *dialog;
+
+ /* Ignore arrors by cabextract during its abortion. */
+ if (in_progress && aborted)
+ return;
+
+ /**/ if (log_level & G_LOG_LEVEL_ERROR)
+ dialog=gnome_app_error(App,message);
+ else if (log_level & (G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING))
+ dialog=gnome_app_warning(App,message);
+ else
+ dialog=gnome_app_message(App,message);
+
+ gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
+ g_signal_connect((gpointer)dialog,"close",G_CALLBACK(gtk_main_quit),NULL);
+ gtk_main();
+ /* 'dialog' gets destroyed automatically */
+}
+
+static void ui_gnome_interactive(void)
+{
+ gtk_widget_show_all(GTK_WIDGET(App));
+ gtk_main();
+ exit(EXIT_SUCCESS);
+}
+
+gboolean ui_gnome_init(void)
+{
+ acquire_module_available_notify=ui_gnome_module_available_notify;
+ acquire_module_all_modules_found_notify=ui_gnome_all_modules_found_notify;
+ ui_progress=ui_gnome_progress;
+ ui_interactive=ui_gnome_interactive;
+ captivemodid_module_best_priority_notify=ui_gnome_module_best_priority_notify;
+
+ /* Graphic widgets will all be hidden yet. */
+ App_init();
+ /* ui_gnome_g_log_handler() needs 'App'. */
+ g_log_set_handler(
+ G_LOG_DOMAIN, /* log_domain; "Captive" */
+ G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL, /* log_levels */
+ ui_gnome_g_log_handler, /* log_func */
+ NULL); /* user_data */
+
+ return TRUE;
+}