X-Git-Url: http://git.jankratochvil.net/?a=blobdiff_plain;f=src%2Finstall%2Facquire%2Fui-gnome.c;h=32b2150969375cd7fbb485e991ad30e021d6f962;hb=8780f98e140b6dd2b1b382d2a23fa75508a45328;hp=12819a8f29bd91ef82ebf62a0d14277f80f4017f;hpb=2447b1aff86ff3f13a1c3cc8d2c0d6285f0346cc;p=captive.git diff --git a/src/install/acquire/ui-gnome.c b/src/install/acquire/ui-gnome.c index 12819a8..32b2150 100644 --- a/src/install/acquire/ui-gnome.c +++ b/src/install/acquire/ui-gnome.c @@ -41,7 +41,7 @@ /* Config: */ -#define PROGRESS_UPDATE_USEC 100000 +#define PROGRESS_UPDATE_USEC 200000 static GnomeApp *App; @@ -143,6 +143,8 @@ GtkTreeIter *iter; g_return_if_fail(module_type!=NULL); + gdk_threads_enter(); + iter=DriversTreeStore_Iter_hash_get_iter(module_type); gtk_tree_store_set(DriversTreeStore,iter, DRIVERS_TREE_STORE_COLUMN_TYPE,module_type, @@ -153,6 +155,9 @@ GtkTreeIter *iter; ? _("NOT FOUND; essential module for NTFS disks access") : _("not found; optional module")), -1); + + gdk_flush(); + gdk_threads_leave(); } static void ui_gnome_module_available_notify(struct module_available *module_available) @@ -164,6 +169,8 @@ static gboolean some_module_ntfs_sys_found=FALSE; g_return_if_fail(module_available!=NULL); g_return_if_fail(module_available->module!=NULL); + gdk_threads_enter(); + 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, @@ -177,19 +184,28 @@ static gboolean some_module_ntfs_sys_found=FALSE; some_modules_found=some_module_ntoskrnl_exe_found && some_module_ntfs_sys_found; state_changed(); + + gdk_flush(); + gdk_threads_leave(); } static gboolean all_modules_found=FALSE; static void ui_gnome_all_modules_found_notify(void) { + gdk_threads_enter(); + all_modules_found=TRUE; state_changed(); + + gdk_flush(); + gdk_threads_leave(); } static gboolean aborted=FALSE; static gboolean aborted_back=FALSE; /* 'Back' button was clicked. */ static struct timeval ProgressEntry_updated_timeval; +static struct timeval ProgressBar_updated_timeval; static void progress_start(void) { @@ -197,6 +213,7 @@ static void progress_start(void) aborted=FALSE; aborted_back=FALSE; CAPTIVE_MEMZERO(&ProgressEntry_updated_timeval); + CAPTIVE_MEMZERO(&ProgressBar_updated_timeval); state_changed(); } @@ -206,10 +223,30 @@ static void progress_end(void) state_changed(); } +static gboolean want_progress_update(struct timeval *timeval) +{ +struct timeval now_timeval; +struct timeval diff_timeval; + + g_return_val_if_fail(timeval!=NULL,FALSE); + + gettimeofday( /* FIXME: errors ignored */ + &now_timeval, /* tv */ + NULL); /* tz */ + timersub(&now_timeval,timeval,&diff_timeval); + if (!timeval->tv_sec || diff_timeval.tv_sec>0 || diff_timeval.tv_usec>=PROGRESS_UPDATE_USEC) { + *timeval=now_timeval; + return TRUE; + } + return FALSE; +} + static gboolean ui_gnome_progress(GnomeVFSURI *uri) { /* 'uri' may be NULL */ + gdk_threads_enter(); + if (ProgressEntry) { static gchar *uri_text=NULL; @@ -223,22 +260,18 @@ static gchar *uri_text=NULL; } 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) { + if (want_progress_update(&ProgressEntry_updated_timeval)) 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(); + + gdk_flush(); + gdk_threads_leave(); + + /* Do not: g_thread_yield(); + * as it is TOO much expensive and we are multithreaded anyway. + */ if (aborted) return TRUE; @@ -253,21 +286,30 @@ static void ui_gnome_progress_bar(gint done,gint length) g_return_if_fail(done>=0); g_return_if_fail(length>=0); + if (!want_progress_update(&ProgressBar_updated_timeval)) + return; + + gdk_threads_enter(); + if (!length) { gtk_progress_bar_pulse(MicrosoftComProgress); gtk_progress_bar_set_text(MicrosoftComProgress,""); } else { -gchar *done_display,*length_display; +gchar *length_display; + /* Do not format 'done' by gnome_vfs_format_file_size_for_display() + * as the progress would not be visible for large 'done' sizes. + */ gtk_progress_bar_set_fraction(MicrosoftComProgress,((gdouble)done)/length); - done_display=gnome_vfs_format_file_size_for_display(done); length_display=gnome_vfs_format_file_size_for_display(length); gtk_progress_bar_set_text(MicrosoftComProgress, - captive_printf_alloca("%s / %s",done_display,length_display)); - g_free(done_display); + captive_printf_alloca("%d B / %s",(int)done,length_display)); g_free(length_display); } + + gdk_flush(); + gdk_threads_leave(); } /* FIXME: Change it to "prepare" signal. */ @@ -333,6 +375,66 @@ gchar *text; gtk_widget_thaw_child_notify(vbox_widget); } +typedef void (*process_t)(void); + +/* 'GThreadFunc' type. */ +gpointer execute_process_func(process_t process /* data */) +{ + (*process)(); + + gdk_threads_enter(); + + gtk_main_quit(); /* Abort gtk_main() of execute_process(). */ + + gdk_flush(); + gdk_threads_leave(); + + return NULL; +} + +/* We are called inside gdk_threads_enter(). */ +static void execute_process(process_t process) +{ +GThread *gthread; + + progress_start(); + gthread=g_thread_create_full( + (GThreadFunc)execute_process_func, /* func */ + process, /* data */ + 0, /* stack_size; 0 means the default size */ + TRUE, /* joinable */ + TRUE, /* bound; use system thread */ + G_THREAD_PRIORITY_LOW, /* priority; G_THREAD_PRIORITY_LOW is the lowest one */ + NULL); /* error */ + gtk_main(); /* We are already called inside gdk_threads_enter(). */ + /* I hope some other gtk_main_quit() did not occur as we would + * locked if the 'process' func did not finish yet. + */ + g_thread_join(gthread); + progress_end(); +} + +/* 'process_t' typed. */ +static void process_scan_disk(void) +{ + scan_disks_quick(); + scan_disks(); +} + +static GnomeVFSURI *process_scan_path_scan_path_uri; + +/* 'process_t' typed. */ +static void process_scan_path(void) +{ + mod_uri_load(process_scan_path_scan_path_uri); +} + +/* 'process_t' typed. */ +static void process_microsoft_com(void) +{ + microsoft_com(); +} + gboolean on_Page_next(GnomeDruidPage *gnomedruidpage,GtkWidget *widget,gpointer user_data /* unused */) { g_return_val_if_fail(GNOME_IS_DRUID_PAGE(gnomedruidpage),FALSE); @@ -347,10 +449,7 @@ gboolean on_Page_next(GnomeDruidPage *gnomedruidpage,GtkWidget *widget,gpointer } } else if (page_active==ScanDiskPage) { - progress_start(); - scan_disks_quick(); - scan_disks(); - progress_end(); + execute_process(process_scan_disk); if (aborted_back) { gnome_druid_set_page(Druid,PageStart); return TRUE; /* ignore button press */ @@ -368,9 +467,8 @@ const gchar *scan_path_uri_text=gtk_entry_get_text(ScanPathLocationComboEntry); 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(); + process_scan_path_scan_path_uri=scan_path_uri; + execute_process(process_scan_path); gnome_vfs_uri_unref(scan_path_uri); if (aborted_back) { gnome_druid_set_page(Druid,(all_modules_found ? PageStart : ScanDiskPage)); @@ -402,9 +500,7 @@ void on_MicrosoftComConfirmButton_clicked(GtkButton *button,gpointer user_data) if (page_active!=MicrosoftComPage) /* bogus callback */ return; - progress_start(); - microsoft_com(); - progress_end(); + execute_process(process_microsoft_com); if (aborted_back) { gnome_druid_set_page(Druid,(all_modules_found ? PageStart : ScanPathPage)); return; @@ -490,6 +586,9 @@ gint reply; (GnomeReplyCallback)on_DruidButtonOK_clicked_dialog_callback, &reply); /* data */ g_signal_connect((gpointer)dialog,"close",G_CALLBACK(gtk_main_quit),NULL); + /* Never call gtk_main() from other thread than the initial one. + * We would have to switch GTK+ context (g_main_context()?). + */ gtk_main(); /* 'dialog' gets destroyed automatically */ if (reply==0) /* 0 for 'OK', 1 for 'Cancel', left -1 for dialog close. */ @@ -509,6 +608,18 @@ static void button_stock_set_label(GtkWidget *widget,const gchar *label_text_new gtk_label_set_text_with_mnemonic(GTK_LABEL(widget),label_text_new); } +static void PageFinish_set_label_attr(GtkWidget *widget,gpointer callback_data /* unused */) +{ + g_return_if_fail(GTK_IS_WIDGET(widget)); + + /**/ if (GTK_IS_CONTAINER(widget)) + gtk_container_foreach(GTK_CONTAINER(widget), + (GtkCallback)PageFinish_set_label_attr, /* callback */ + callback_data); /* callback_data; unused */ + else if (GTK_IS_LABEL(widget) && gtk_label_get_line_wrap(GTK_LABEL(widget))) + gtk_label_set_selectable(GTK_LABEL(widget),TRUE); +} + /* of "ui-gnome-interface.h": */ GtkWidget *create_App(void); /* of "ui-gnome-support.h": */ @@ -520,6 +631,8 @@ GtkTreeViewColumn *column; GtkCellRenderer *cell; GtkBox *druid_button_box; + gdk_threads_enter(); + App=GNOME_APP(create_App()); DriversTreeView=GTK_TREE_VIEW(lookup_widget(GTK_WIDGET(App),"DriversTreeView")); @@ -565,9 +678,9 @@ GtkBox *druid_button_box; 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 */ + button_stock_set_label( + GTK_WIDGET(DruidButtonSkip), /* widget */ + _("_Skip")); /* label_text_new */ 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); @@ -577,7 +690,13 @@ GtkBox *druid_button_box; gtk_widget_show(GTK_WIDGET(DruidButtonOK)); g_signal_connect((gpointer)DruidButtonOK,"clicked",G_CALLBACK(on_DruidButtonOK_clicked),NULL); + PageFinish_set_label_attr( + GTK_WIDGET(PageFinish), /* widget */ + NULL); /* callback_data; unused */ + state_changed(); + + gdk_threads_leave(); } static void ui_gnome_g_log_handler(const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data) @@ -588,6 +707,8 @@ GtkWidget *dialog; if (in_progress && aborted) return; + gdk_threads_enter(); + /**/ 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)) @@ -599,12 +720,33 @@ GtkWidget *dialog; g_signal_connect((gpointer)dialog,"close",G_CALLBACK(gtk_main_quit),NULL); gtk_main(); /* 'dialog' gets destroyed automatically */ + + gdk_flush(); + gdk_threads_leave(); } static void ui_gnome_interactive(void) { + gdk_threads_enter(); + + /* Postpone gtk_widget_show_all() from App_init() here + * to have already passed all ui_gnome_module_available_notify(). + */ + gnome_druid_set_page(Druid,MicrosoftComPage); gtk_widget_show_all(GTK_WIDGET(App)); +#if 0 + /* gnome_druid_set_page(Druid,PageStart); */ + gnome_druid_set_page(Druid,ScanDiskPage); + gnome_druid_set_page(Druid,ScanPathPage); + /* gnome_druid_set_page(Druid,MicrosoftComPage); */ + gnome_druid_set_page(Druid,PageFinish); +#endif + gnome_druid_set_page(Druid,PageStart); + gtk_main(); + + gdk_threads_leave(); + exit(EXIT_SUCCESS); } @@ -617,6 +759,14 @@ gboolean ui_gnome_init(void) ui_interactive=ui_gnome_interactive; captivemodid_module_best_priority_notify=ui_gnome_module_best_priority_notify; + /* gdk_threads_init() must be called before gtk_init()! + * gtk_init() gets called by create_App() here. + */ + if (!g_thread_supported()) + g_thread_init(NULL); + if (!gdk_threads_mutex) + gdk_threads_init(); + /* Graphic widgets will all be hidden yet. */ App_init(); /* ui_gnome_g_log_handler() needs 'App'. */