# # # patch "AdvancedFind.pm" # from [3aeb29a81f3a8fc5109fc65a2cafa3e2f5a14e8e] # to [4514f4250c5591353fd5cebb1f398122c0a479c6] # # patch "Annotate.pm" # from [39d40e1faf8febd71ec9d2d5a312a8f92652d55b] # to [edc84764f8d6d85efdb259014f3a2660425fa679] # # patch "ChangeLog.pm" # from [96644abd5e5d421ade30b5badfee1d807e2e9c17] # to [054ad90d7efd653ff90645877fab463ad421cec1] # # patch "ComboAutoCompletion.pm" # from [2c0b4573d0d7f5ae6f51e8f58cc80fdc3b61325c] # to [6b3d8c390427cc6638b69aafcc01c1433ec543d7] # # patch "Completion.pm" # from [8bbd4fcd439fc2a24b37882223d212e7cd05a994] # to [71827654ac9917a8031920fc50bb877f660714d6] # # patch "FindText.pm" # from [e4ca03bc7058a6740a963c5dfdb66a899ebdc034] # to [d69a96eebd9fc4cee34a2c8da1d8b5e3dc09fdd4] # # patch "History.pm" # from [25ce79927ae07595a6702679f27f96f41f372237] # to [ea584ff6344617ca29c75363eaa34b15162b946f] # # patch "Preferences.pm" # from [92527102b3ae36a4abeb1b5bd901bae0c03e1333] # to [3c571963fb958609a01bc062f7a711e663479b14] # # patch "Utilities.pm" # from [0162a0665b728ecb82a1b3e880b869e3e9788f19] # to [4fb372a8b2cfc16d2b745675019155a658dcb84a] # # patch "WindowManager.pm" # from [8eb2da4972c53daad7f5a59ef5fe1f92e9b52833] # to [46e5252a4e6feeba8f7759b2b0e77f287551ee5f] # # patch "mtn-browse" # from [96fe56cb79dfe462e5d0fa65ef243ef5d3800f61] # to [86a252dfb397aeb573b472e355807b4dfd857b36] # # patch "mtn-browse.glade" # from [e108526a6ed91bc84238ac6586567a7c53b196ea] # to [9bbd76d5f466cdb2191c7f1c16cda558f4574de2] # ============================================================ --- AdvancedFind.pm 3aeb29a81f3a8fc5109fc65a2cafa3e2f5a14e8e +++ AdvancedFind.pm 4514f4250c5591353fd5cebb1f398122c0a479c6 @@ -44,7 +44,7 @@ use strict; use strict; -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Public routines. @@ -89,6 +89,7 @@ sub advanced_find($$$) my($advanced_find, $ret_val); + my $wm = WindowManager->instance(); $advanced_find = get_advanced_find_window($browser); @@ -121,11 +122,13 @@ sub advanced_find($$$) # Handle all events until the dialog is dismissed. + $wm->make_busy($advanced_find, 1, 1); $advanced_find->{done} = 0; while (! $advanced_find->{done}) { Gtk2->main_iteration(); } + $wm->make_busy($advanced_find, 0); $advanced_find->{window}->hide(); # Deal with the result. @@ -641,8 +644,8 @@ sub get_advanced_find_window($) # Register the window for management. - $wm->manage($instance, $window_type); - $wm->add_busy_widgets($instance, + $wm->manage($instance, $window_type, $instance->{window}); + $wm->add_busy_windows($instance, $instance->{details_textview}-> get_window("text")); @@ -708,7 +711,7 @@ sub update_advanced_find_state($$) $wm->make_busy($advanced_find, 1); } $advanced_find->{appbar}->push(""); - gtk2_update(); + $wm->update_gui(); # The list of available branches has changed. @@ -739,7 +742,7 @@ sub update_advanced_find_state($$) # Get the new list of branches. $advanced_find->{appbar}->set_status(__("Fetching branch list")); - gtk2_update(); + $wm->update_gui(); $advanced_find->{mtn}->branches(address@hidden) if (defined($advanced_find->{mtn})); $advanced_find->{branch_combo_details}->{list} = address@hidden; @@ -747,7 +750,7 @@ sub update_advanced_find_state($$) # Update the branch list combobox. $advanced_find->{appbar}->set_status(__("Populating branch list")); - gtk2_update(); + $wm->update_gui(); my $counter = 1; $advanced_find->{branch_comboboxentry}->get_model()->clear(); foreach my $branch (@branch_list) @@ -755,13 +758,13 @@ sub update_advanced_find_state($$) $advanced_find->{branch_comboboxentry}->append_text($branch); $advanced_find->{appbar}->set_progress_percentage ($counter ++ / scalar(@branch_list)); - gtk2_update(); + $wm->update_gui(); } $advanced_find->{branch_comboboxentry}->child()-> set_text($advanced_find->{branch_combo_details}->{value}); $advanced_find->{appbar}->set_progress_percentage(0); $advanced_find->{appbar}->set_status(""); - gtk2_update(); + $wm->update_gui(); } @@ -790,7 +793,7 @@ sub update_advanced_find_state($$) if ($advanced_find->{branch_combo_details}->{complete}) { $advanced_find->{appbar}->set_status(__("Fetching revision list")); - gtk2_update(); + $wm->update_gui(); get_branch_revisions($advanced_find->{mtn}, $advanced_find->{branch_combo_details}-> {value}, @@ -805,7 +808,7 @@ sub update_advanced_find_state($$) $advanced_find->{appbar}->set_progress_percentage(0); $advanced_find->{appbar}->set_status(__("Populating revision list")); - gtk2_update(); + $wm->update_gui(); my $counter = 1; $advanced_find->{revision_comboboxentry}->get_model()->clear(); foreach my $revision (@revision_list) @@ -813,13 +816,13 @@ sub update_advanced_find_state($$) $advanced_find->{revision_comboboxentry}->append_text($revision); $advanced_find->{appbar}->set_progress_percentage ($counter ++ / scalar(@revision_list)); - gtk2_update(); + $wm->update_gui(); } $advanced_find->{revision_comboboxentry}->child()-> set_text($advanced_find->{revision_combo_details}->{value}); $advanced_find->{appbar}->set_progress_percentage(0); $advanced_find->{appbar}->set_status(""); - gtk2_update(); + $wm->update_gui(); } @@ -839,7 +842,7 @@ sub update_advanced_find_state($$) # Get the list of matching revisions. $advanced_find->{appbar}->set_status(__("Finding revisions")); - gtk2_update(); + $wm->update_gui(); if ($advanced_find->{simple_query_radiobutton}->get_active()) { if ($advanced_find->{revision_combo_details}->{complete}) @@ -871,7 +874,7 @@ sub update_advanced_find_state($$) . __x("gave:\n{error_message}", error_message => Glib::Markup::escape_text($message))); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); die("Bad query"); }); eval @@ -896,8 +899,8 @@ sub update_advanced_find_state($$) "info", "close", __("No revisions matched your query.")); - $dialog->run(); - $dialog->destroy(); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); } $found = 0; foreach my $entry (@{$advanced_find->{query_history}}) @@ -941,14 +944,14 @@ sub update_advanced_find_state($$) 0, $item); $advanced_find->{appbar}->set_progress_percentage ($counter ++ / scalar(@revision_ids)); - gtk2_update(); + $wm->update_gui(); } $advanced_find->{revisions_treeview}->scroll_to_point(0, 0) if ($advanced_find->{revisions_treeview}->realized()); $advanced_find->{appbar}->set_progress_percentage(0); $advanced_find->{appbar}->set_status(""); - gtk2_update(); + $wm->update_gui(); } ============================================================ --- Annotate.pm 39d40e1faf8febd71ec9d2d5a312a8f92652d55b +++ Annotate.pm edc84764f8d6d85efdb259014f3a2660425fa679 @@ -44,7 +44,7 @@ use strict; use strict; -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Public routines. @@ -99,12 +99,12 @@ sub display_annotation($$$) $wm->make_busy($instance, 1); $instance->{appbar}->push(""); - gtk2_update(); + $wm->update_gui(); # Get Monotone to do the annotation. $instance->{appbar}->set_status(__("Annotating file")); - gtk2_update(); + $wm->update_gui(); mtn_annotate(address@hidden, $mtn->get_db_name(), $revision_id, $file_name); # Find the longest line for future padding and also split each line into @@ -124,7 +124,7 @@ sub display_annotation($$$) $instance->{appbar}->set_status (__("Formatting and displaying annotated file")); - gtk2_update(); + $wm->update_gui(); $padding = " " x $max_len; $prefix_tag = $text_tag = ""; for ($i = 0; $i <= $#lines; ++ $i) @@ -164,7 +164,7 @@ sub display_annotation($$$) { $instance->{appbar}->set_progress_percentage (($i + 1) / scalar(@lines)); - gtk2_update(); + $wm->update_gui(); } } @@ -184,7 +184,7 @@ sub display_annotation($$$) $instance->{annotation_scrolledwindow}->get_hadjustment()->set_value(0); $instance->{appbar}->set_progress_percentage(0); $instance->{appbar}->set_status(""); - gtk2_update(); + $wm->update_gui(); $instance->{appbar}->pop(); $wm->make_busy($instance, 0); @@ -261,7 +261,7 @@ sub get_annotation_window() # Register the window for management. $wm->manage($instance, $window_type, $instance->{window}); - $wm->add_busy_widgets($instance, + $wm->add_busy_windows($instance, $instance->{annotation_textview}-> get_window("text")); } ============================================================ --- ChangeLog.pm 96644abd5e5d421ade30b5badfee1d807e2e9c17 +++ ChangeLog.pm 054ad90d7efd653ff90645877fab463ad421cec1 @@ -44,7 +44,7 @@ use strict; use strict; -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Public routines. @@ -177,7 +177,7 @@ sub get_change_log_window() # Register the window for management. $wm->manage($instance, $window_type, $instance->{window}); - $wm->add_busy_widgets($instance, + $wm->add_busy_windows($instance, $instance->{changelog_textview}-> get_window("text")); } ============================================================ --- ComboAutoCompletion.pm 2c0b4573d0d7f5ae6f51e8f58cc80fdc3b61325c +++ ComboAutoCompletion.pm 6b3d8c390427cc6638b69aafcc01c1433ec543d7 @@ -45,7 +45,7 @@ use strict; use strict; -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Public routines. ============================================================ --- Completion.pm 8bbd4fcd439fc2a24b37882223d212e7cd05a994 +++ Completion.pm 71827654ac9917a8031920fc50bb877f660714d6 @@ -60,12 +60,12 @@ our $VERSION = 0.1; our @EXPORT_OK = qw(); our $VERSION = 0.1; -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Public methods. sub get_completion($$$$); -sub new($@); +sub new($;$); # ############################################################################## # @@ -83,19 +83,18 @@ sub new($@); -sub new($@) +sub new($;$) { - my($class, $list) = @_; - $class = ref($class) if ref($class); + my $class = (ref($_[0]) ne "") ? ref($_[0]) : $_[0]; + my $list = $_[1]; my($char, $item, $level, $this); - $this = {}; - $this->{tree} = {}; + $this = {tree => {}}; # Build up a hash tree for the list of possible items. ============================================================ --- FindText.pm e4ca03bc7058a6740a963c5dfdb66a899ebdc034 +++ FindText.pm d69a96eebd9fc4cee34a2c8da1d8b5e3dc09fdd4 @@ -50,7 +50,7 @@ my $window_type = "find_text_window"; my $window_type = "find_text_window"; -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Public routines. ============================================================ --- History.pm 25ce79927ae07595a6702679f27f96f41f372237 +++ History.pm ea584ff6344617ca29c75363eaa34b15162b946f @@ -51,7 +51,7 @@ use constant CLS_LINE_NR_COLUMN => 1; use constant CLS_NAME_COLUMN => 0; use constant CLS_LINE_NR_COLUMN => 1; -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Public routines. @@ -113,7 +113,7 @@ sub display_revision_change_history($$) $wm->make_busy($instance, 1); $instance->{appbar}->push(""); - gtk2_update(); + $wm->update_gui(); $instance->{stop_button}->set_sensitive(TRUE); @@ -122,14 +122,14 @@ sub display_revision_change_history($$) $instance->{appbar}->set_progress_percentage(0); $instance->{appbar}->set_status(__("Fetching revision list")); - gtk2_update(); + $wm->update_gui(); $history_hash{$revision_id} = 1; get_revision_history_helper($instance, \%history_hash, $revision_id); # Sort the list. $instance->{appbar}->set_status(__("Sorting revision list")); - gtk2_update(); + $wm->update_gui(); $instance->{history} = []; $instance->{mtn}->toposort($instance->{history}, keys(%history_hash)); %history_hash = (); @@ -139,7 +139,7 @@ sub display_revision_change_history($$) $instance->{appbar}->set_progress_percentage(0); $instance->{appbar}->set_status(__("Displaying revision history")); - gtk2_update(); + $wm->update_gui(); $counter = 1; $instance->{stop} = 0; $instance->{history_buffer}->set_text(""); @@ -246,7 +246,7 @@ sub display_revision_change_history($$) { $instance->{appbar}->set_progress_percentage ($counter / scalar(@{$instance->{history}})); - gtk2_update(); + $wm->update_gui(); } ++ $counter; @@ -264,7 +264,7 @@ sub display_revision_change_history($$) $instance->{history_scrolledwindow}->get_hadjustment()->set_value(0); $instance->{appbar}->set_progress_percentage(0); $instance->{appbar}->set_status(""); - gtk2_update(); + $wm->update_gui(); $instance->{appbar}->pop(); $wm->make_busy($instance, 0); @@ -315,7 +315,7 @@ sub display_file_change_history($$$) $wm->make_busy($instance, 1); $instance->{appbar}->push(""); - gtk2_update(); + $wm->update_gui(); # Get the list of file change revisions. Remember that a warning is # generated when one goes back beyond a file's addition revision, so @@ -324,7 +324,7 @@ sub display_file_change_history($$$) $instance->{appbar}->set_progress_percentage(0); $instance->{appbar}->set_status(__("Fetching revision list")); $instance->{stop_button}->set_sensitive(TRUE); - gtk2_update(); + $wm->update_gui(); Monotone::AutomateStdio->register_error_handler("warning"); get_file_history_helper($instance, \%history_hash, $revision_id); Monotone::AutomateStdio->register_error_handler("both", @@ -334,7 +334,7 @@ sub display_file_change_history($$$) # Sort the list. $instance->{appbar}->set_status(__("Sorting revision list")); - gtk2_update(); + $wm->update_gui(); $instance->{history} = []; $instance->{mtn}->toposort($instance->{history}, keys(%history_hash)); %history_hash = (); @@ -344,7 +344,7 @@ sub display_file_change_history($$$) $instance->{appbar}->set_progress_percentage(0); $instance->{appbar}->set_status(__("Displaying file history")); - gtk2_update(); + $wm->update_gui(); $counter = 1; $instance->{history_buffer}->set_text(""); for my $revision_id (@{$instance->{history}}) @@ -444,7 +444,7 @@ sub display_file_change_history($$$) $instance->{appbar}->set_progress_percentage ($counter ++ / scalar(@{$instance->{history}})); - gtk2_update(); + $wm->update_gui(); } @@ -456,7 +456,7 @@ sub display_file_change_history($$$) $instance->{history_scrolledwindow}->get_hadjustment()->set_value(0); $instance->{appbar}->set_progress_percentage(0); $instance->{appbar}->set_status(""); - gtk2_update(); + $wm->update_gui(); $instance->{appbar}->pop(); $wm->make_busy($instance, 0); @@ -704,7 +704,7 @@ sub compare_revisions($$$;$) $wm->make_busy($instance, 1); $instance->{appbar}->push(""); - gtk2_update(); + $wm->update_gui(); $instance->{mtn} = $mtn; $instance->{revision_id_1} = $revision_id_1; @@ -713,7 +713,7 @@ sub compare_revisions($$$;$) # Get Monotone to do the comparison. $instance->{appbar}->set_status(__("Calculating differences")); - gtk2_update(); + $wm->update_gui(); mtn_diff(address@hidden, $mtn->get_db_name(), $revision_id_1, @@ -737,7 +737,7 @@ sub compare_revisions($$$;$) $instance->{appbar}-> set_status(__("Formatting and displaying differences")); - gtk2_update(); + $wm->update_gui(); $padding = " " x $max_len; $line = substr(" Summary" . $padding, 0, $max_len); $instance->{comparison_buffer}->insert_with_tags_by_name @@ -866,7 +866,7 @@ sub compare_revisions($$$;$) { $instance->{appbar}->set_progress_percentage (($i + 1) / scalar(@lines)); - gtk2_update(); + $wm->update_gui(); } } @@ -882,7 +882,7 @@ sub compare_revisions($$$;$) $instance->{appbar}->set_progress_percentage(0); $instance->{appbar}->set_status(__("Populating file list")); - gtk2_update(); + $wm->update_gui(); @files = sort({ $a->{file_name} cmp $b->{file_name} } @files); $i = 1; $instance->{file_comparison_combobox}->get_model()->clear(); @@ -893,11 +893,11 @@ sub compare_revisions($$$;$) CLS_NAME_COLUMN, $file->{file_name}, CLS_LINE_NR_COLUMN, $file->{line_nr}); $instance->{appbar}->set_progress_percentage($i ++ / scalar(@files)); - gtk2_update(); + $wm->update_gui(); } $instance->{appbar}->set_progress_percentage(0); $instance->{appbar}->set_status(""); - gtk2_update(); + $wm->update_gui(); # Make sure we are at the top. @@ -1073,8 +1073,11 @@ sub get_history_window() # Register the window for management. - $wm->manage($instance, $window_type, $instance->{stop_button}); - $wm->add_busy_widgets($instance, + $wm->manage($instance, + $window_type, + $instance->{window}, + $instance->{stop_button}); + $wm->add_busy_windows($instance, $instance->{history_textview}-> get_window("text")); } @@ -1142,7 +1145,7 @@ sub get_file_history_helper($$$) $hash->{$revision} = 1; set_label_value($instance->{numbers_value_label}, scalar(keys(%$hash))); - gtk2_update(); + WindowManager->update_gui(); @parents = (); $instance->{mtn}->parents(address@hidden, $revision); foreach my $parent (@parents) @@ -1188,7 +1191,7 @@ sub get_revision_history_helper($$$) $hash->{$parent} = 1; set_label_value($instance->{numbers_value_label}, scalar(keys(%$hash))); - gtk2_update(); + WindowManager->update_gui(); get_revision_history_helper($instance, $hash, $parent); } } @@ -1303,8 +1306,11 @@ sub get_revision_comparison_window() # Register the window for management. - $wm->manage($instance, $window_type, $instance->{stop_button}); - $wm->add_busy_widgets($instance, + $wm->manage($instance, + $window_type, + $instance->{window}, + $instance->{stop_button}); + $wm->add_busy_windows($instance, $instance->{comparison_textview}-> get_window("text")); } ============================================================ --- Preferences.pm 92527102b3ae36a4abeb1b5bd901bae0c03e1333 +++ Preferences.pm 3c571963fb958609a01bc062f7a711e663479b14 @@ -114,7 +114,7 @@ my @colour_mapping_table = {widget => "revision_2_highlight_colorbutton", record => "cmp_revision_2"}); -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Public routines. @@ -163,6 +163,7 @@ sub preferences($) my($instance, $preferences); + my $wm = WindowManager->instance(); # Load in the user's preferences. @@ -190,11 +191,13 @@ sub preferences($) # Handle all events until the dialog is dismissed. + $wm->make_busy($instance, 1, 1); $instance->{done} = 0; while (! $instance->{done}) { Gtk2->main_iteration(); } + $wm->make_busy($instance, 0); $instance->{window}->hide(); # Deal with the result. ============================================================ --- Utilities.pm 0162a0665b728ecb82a1b3e880b869e3e9788f19 +++ Utilities.pm 4fb372a8b2cfc16d2b745675019155a658dcb84a @@ -44,7 +44,7 @@ use strict; use strict; -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Public routines. @@ -57,7 +57,6 @@ sub glade_signal_autoconnect($$); sub get_dir_contents($$$); sub get_revision_ids($$); sub glade_signal_autoconnect($$); -sub gtk2_update(); sub hex_dump($); sub open_database($$$); sub run_command($@); @@ -235,8 +234,7 @@ sub generate_revision_report($$$$;$) " " . $type . ":\n", $italics); %seen = (); - @unique = sort(grep { ! $seen{$_} ++ } - @{$revision_data{$type}}); + @unique = sort(grep(! $seen{$_} ++, @{$revision_data{$type}})); foreach my $line (@unique) { $text_buffer->insert_with_tags_by_name @@ -366,7 +364,7 @@ sub run_command($@) name => Glib::Markup::escape_text($args[0])) . __x("the system gave:\n{error_message}", error_message => Glib::Markup::escape_text($@))); - $dialog->run(); + WindowManager->instance()->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } @@ -421,7 +419,7 @@ sub run_command($@) "close", __x("waitpid failed with:\n{error_message}", error_message => Glib::Markup::escape_text($!))); - $dialog->run(); + WindowManager->instance()->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } @@ -441,7 +439,7 @@ sub run_command($@) . __x("{error_message}", error_message => Glib::Markup::escape_text(join("", @err)))); - $dialog->run(); + WindowManager->instance()->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } @@ -455,7 +453,7 @@ sub run_command($@) __x("The {name} subprocess was terminated by signal {number}.", name => Glib::Markup::escape_text($args[0]), number => WTERMSIG($status))); - $dialog->run(); + WindowManager->instance()->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } @@ -677,62 +675,78 @@ sub get_branch_revisions($$$$$) if ($tags) { - my(@certs, - @list, - %seen); + my(%rev_id_to_tags, + %seen, + @sorted_rev_ids, + @tags); # Get the list of revision tags. - $mtn->tags(address@hidden, $branch); + $mtn->tags(address@hidden, $branch); $appbar->set_progress_percentage(0.5) if (defined($appbar)); - gtk2_update(); + WindowManager->update_gui(); - # Dedupe it. + # Does the list need truncating (in which case we need to sort by date + # to keep the most recent tags) or does the user want to sort tags by + # date? - @list = grep({ ! $seen{$_->{tag}} ++ } @list); - - # Sort it by date if necessary (because it needs to be truncated or - # that's how the user wants it sorted). - if (($user_preferences->{query}->{tagged}->{limit} > 0 - && scalar(@list) > $user_preferences->{query}->{tagged}->{limit}) + && scalar(@tags) > $user_preferences->{query}->{tagged}->{limit}) || $user_preferences->{query}->{tagged}->{sort_cronologically}) { - @list = sort({ - foreach my $rec ($a, $b) - { - if (! exists($rec->{date})) - { - $mtn->certs(address@hidden, - $rec->{revision_id}); - foreach my $cert (@certs) - { - if ($cert->{name} eq "date") - { - $rec->{date} = $cert->{value}; - last; - } - } - } - } - $b->{date} cmp $a->{date}; - } - @list); + + # Yes tags are to be either sorted by date or need to be truncated + # (requiring them to temporarily be sorted by date). + + # Build up a hash mapping revision id to tag(s). + + foreach my $tag (@tags) + { + if (exists($rev_id_to_tags{$tag->{revision_id}})) + { + push(@{$rev_id_to_tags{$tag->{revision_id}}}, $tag->{tag}); + } + else + { + $rev_id_to_tags{$tag->{revision_id}} = [$tag->{tag}]; + } + } + + # Sort the revision ids into date order (youngest first). + + $mtn->toposort(address@hidden, keys(%rev_id_to_tags)); + @sorted_rev_ids = reverse(@sorted_rev_ids); + + # Now build up a list of tags based on this ordering, deduping + # items and stopping when we have enough tags. + + revision: foreach my $rev_id (@sorted_rev_ids) + { + foreach my $tag (sort(@{$rev_id_to_tags{$rev_id}})) + { + push(@$revisions, $tag) if (! $seen{$tag} ++); + last revision + if ($user_preferences->{query}->{tagged}->{limit} > 0 + && scalar(@$revisions) >= + $user_preferences->{query}->{tagged}->{limit}); + } + } + } + else + { - # Truncate the list if necessary. + # No tags are to be sorted by name, without truncation. - if ($user_preferences->{query}->{tagged}->{limit} > 0 - && scalar(@list) > $user_preferences->{query}->{tagged}->{limit}) - { - splice(@list, $user_preferences->{query}->{tagged}->{limit}); - } + # At this stage simply extract the tags and dedupe them. - # Extract the list of tags. + @$revisions = map($_->{tag}, grep(! $seen{$_->{tag}} ++, @tags)); - @$revisions = map({ $_->{tag} } @list); + } - # Sort alphabetically if required. + # We now have a list of tags in @$revisions of the correct size and + # sorted by date if so required by the user. So resort the list + # aplhabetically if required. @$revisions = sort(@$revisions) if (! $user_preferences->{query}->{tagged}->{sort_cronologically}); @@ -757,16 +771,16 @@ sub get_branch_revisions($$$$$) if ($user_preferences->{query}->{id}->{sort_cronologically}) { $appbar->set_progress_percentage(0.33) if (defined($appbar)); - gtk2_update(); + WindowManager->update_gui(); $mtn->toposort($revisions, @$revisions); $appbar->set_progress_percentage(0.66) if (defined($appbar)); - gtk2_update(); + WindowManager->update_gui(); @$revisions = reverse(@$revisions); } else { $appbar->set_progress_percentage(0.5) if (defined($appbar)); - gtk2_update(); + WindowManager->update_gui(); @$revisions = sort(@$revisions); } @@ -777,7 +791,7 @@ sub get_branch_revisions($$$$$) # Yes so truncate and then sort it. $appbar->set_progress_percentage(0.33) if (defined($appbar)); - gtk2_update(); + WindowManager->update_gui(); $mtn->toposort($revisions, @$revisions); $appbar->set_progress_percentage(0.66) if (defined($appbar)); splice(@$revisions, @@ -798,7 +812,7 @@ sub get_branch_revisions($$$$$) } $appbar->set_progress_percentage(1) if (defined($appbar)); - gtk2_update(); + WindowManager->update_gui(); } # @@ -1090,30 +1104,5 @@ sub glade_signal_autoconnect($$) $client_data); } -# -############################################################################## -# -# Routine - gtk2_update -# -# Description - Process all outstanding Gtk2 toolkit events. This is used -# to update the GUI whilst the application is busy doing -# something. -# -# Data - None. -# -############################################################################## - - -sub gtk2_update() -{ - - return if (Gtk2->main_level() == 0); - while (Gtk2->events_pending()) - { - Gtk2->main_iteration(); - } - -} - 1; ============================================================ --- WindowManager.pm 8eb2da4972c53daad7f5a59ef5fe1f92e9b52833 +++ WindowManager.pm 46e5252a4e6feeba8f7759b2b0e77f287551ee5f @@ -59,6 +59,13 @@ use Gtk2; # ***** GLOBAL DATA DECLARATIONS ***** +# A list of event types that are to be filtered out when updating a busy GUI. + +my @filtered_events = ("button-press", + "button-release", + "key-press", + "key-release"); + # The singleton object. my $singleton; @@ -73,17 +80,20 @@ our $VERSION = 0.1; our @EXPORT_OK = qw(); our $VERSION = 0.1; -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Public methods. -sub add_busy_widgets($$@); +sub add_busy_windows($$@); +sub allow_input($&); sub cleanup($); -sub cond_find($$$); +sub cond_find($$&); sub find_unused($$); sub instance($); -sub make_busy($$$); -sub manage($$$;$); +sub make_busy($$$;$); +sub manage($$$$;$); +sub reset_state($); +sub update_gui(); # ############################################################################## # @@ -103,14 +113,14 @@ sub instance($) sub instance($) { - my $class = ref($_[0]) ? ref($_[0]) : $_[0]; + my $class = (ref($_[0]) ne "") ? ref($_[0]) : $_[0]; if (! defined($singleton)) { - $singleton = {}; - $singleton->{windows} = []; - $singleton->{busy_cursor} = undef; - $singleton->{grab_widget_stack} = []; + $singleton = {windows => [], + busy_cursor => Gtk2::Gdk::Cursor->new("watch"), + state_stack => [], + allow_input => 0}; return bless($singleton, $class); } @@ -148,9 +158,6 @@ sub cleanup($) # Free up everything used by this object and associated window instance # records. - $this->{windows} = []; - $this->{busy_cursor} = undef; - $this->{grab_widget_stack} = []; $singleton = undef; } @@ -167,71 +174,72 @@ sub cleanup($) # $instance : A reference to the window instance record # that is to be managed. # $type : The type of window that is to be managed. -# $grab_widget : The widget that should be used with an input -# grab when making the window busy. This is -# optional but if not present then the -# instance record is expected to contain an -# `appbar' widget field. +# $window : The Gtk2::Window object for the window that +# is to be managed. +# $grab_widget : The widget that is to still remain +# responsive when making the window busy, most +# typically this will be a `stop' button. This +# is optional. # ############################################################################## -sub manage($$$;$) +sub manage($$$$;$) { - my($this, $instance, $type, $grab_widget) = @_; + my($this, $instance, $type, $window, $grab_widget) = @_; - # Check for instance record compliance. + # Simply store the details in our window list. - croak(__("No window field found")) unless (exists($instance->{window})); - croak(__("No appbar field found")) - unless (exists($instance->{appbar}) || defined($grab_widget)); - foreach my $field ("busy_widgets", "grab_widget", "type") - { - croak(__x("{field} field found - I manage this", field => $field)) - if (exists($instance->{$field})); - } - croak(__("Cannot manage unrealised windows")) - unless(defined($instance->{window}->window())); + push(@{$this->{windows}}, + {instance => $instance, + type => $type, + window => $window, + busy_windows => [$window->window()], + grab_widget => $grab_widget}); - # Ok so store what we need in the instance record. - - $instance->{type} = $type; - $instance->{busy_widgets} = [$instance->{window}->window()]; - $instance->{grab_widget} = - defined($grab_widget) ? $grab_widget : $instance->{appbar}; - - # Store the instance record in our window list. - - push(@{$this->{windows}}, $instance); - } # ############################################################################## # -# Routine - add_busy_widgets +# Routine - add_busy_windows # -# Description - Add the specified additional widgets for busy cursor +# Description - Add the specified additional windows for busy cursor # handling. # # Data - $this : The object. # $instance : A reference to the window instance record that # is to be updated. -# @widgets : The list of additional widgets that are to be -# handled. +# @windows : The list of additional Gtk2::Gdk::Window +# objects that are to be handled. # ############################################################################## -sub add_busy_widgets($$@) +sub add_busy_windows($$@) { - my($this, $instance, @widgets) = @_; + my($this, $instance, @windows) = @_; - push(@{$instance->{busy_widgets}}, @widgets); + my $entry; + # Find the relevant entry for this instance. + + foreach my $win_instance (@{$this->{windows}}) + { + if ($win_instance->{instance} == $instance) + { + $entry = $win_instance; + last; + } + } + croak(__("Called with an unmanaged instance record")) + unless (defined($entry)); + + push(@{$entry->{busy_windows}}, @windows); + } # ############################################################################## @@ -258,7 +266,7 @@ sub find_unused($$) foreach my $window (@{$this->{windows}}) { - return $window + return $window->{instance} if ($window->{type} eq $type && ! $window->{window}->mapped()); } @@ -290,15 +298,16 @@ sub find_unused($$) -sub cond_find($$$) +sub cond_find($$&) { my($this, $type, $predicate) = @_; foreach my $window (@{$this->{windows}}) { - return $window if ((! defined ($type) || $window->{type} eq $type) - && &$predicate($window)); + return $window->{instance} + if ((! defined($type) || $window->{type} eq $type) + && &$predicate($window->{instance})); } return; @@ -318,64 +327,277 @@ sub cond_find($$$) # $busy : True if the window is to be made busy, # otherwise false if the window is to be made # active. +# $exclude : True if the window referenced by $instance is +# to be excluded from the list of windows that +# are to be made busy (this is used by modal +# dialogs). # ############################################################################## -sub make_busy($$$) +sub make_busy($$$;$) { - my($this, $instance, $busy) = @_; + my($this, $instance, $busy, $exclude) = @_; - croak(__("Called with an unmanaged instance record")) - unless (exists($instance->{grab_widget})); + my($entry, + $found, + $head, + @list); - # Create and store the cursors if we haven't done so already. + $exclude = defined($exclude) ? $exclude : 0; - $this->{busy_cursor} = Gtk2::Gdk::Cursor->new("watch") - unless (defined($this->{busy_cursor})); + # Find the relevant entry for this instance. - # Do it. Make the grab widget, usually the window's application bar, grab - # the input when the window is busy, that way we gobble up keyboard and - # mouse events that could muck up the application state. + foreach my $win_instance (@{$this->{windows}}) + { + if ($win_instance->{instance} == $instance) + { + $entry = $win_instance; + last; + } + } + croak(__("Called with an unmanaged instance record")) + unless (defined($entry)); + # When making things busy filter out keyboard and mouse button events + # unless they relate to the grab widget (usually a `stop' button) and make + # the mouse cursor busy. Making things unbusy is simply the reverse. Also + # cope with nested calls. + if ($busy) { - Gtk2->grab_add($instance->{grab_widget}); + Gtk2::Gdk::Event->handler_set(\&main::window_manager_event_filter, + {singleton => $this, + grab_widget => $entry->{grab_widget}}) + if (! $exclude); foreach my $win_instance (@{$this->{windows}}) { - foreach my $window (@{$win_instance->{busy_widgets}}) + if (! $exclude || $win_instance->{instance} != $instance) { - $window->set_cursor($this->{busy_cursor}); + foreach my $window (@{$win_instance->{busy_windows}}) + { + if ($window->is_visible()) + { + $window->set_cursor($this->{busy_cursor}); + push(@list, $window); + } + } } } - push(@{$this->{grab_widget_stack}}, $instance->{grab_widget}); + push(@{$this->{state_stack}}, + {exclude => $exclude, + grab_widget => $instance->{grab_widget}, + window_list => address@hidden); } else { - my $grab_widget; - if (defined($grab_widget = pop(@{$this->{grab_widget_stack}}))) + pop(@{$this->{state_stack}}); + if (scalar(@{$this->{state_stack}}) == 0) { - Gtk2->grab_remove($grab_widget); - if ($#{$this->{grab_widget_stack}} < 0) + reset_state($this); + } + else + { + $head = + $this->{state_stack}->[$#{$this->{state_stack}}]; + foreach my $win_instance (@{$this->{windows}}) { - foreach my $win_instance (@{$this->{windows}}) + foreach my $window (@{$win_instance->{busy_windows}}) { - foreach my $window (@{$win_instance->{busy_widgets}}) + $found = 0; + foreach my $busy_window (@{$head->{window_list}}) { + if ($window == $busy_window) + { + $found = 1; + last; + } + } + if ($found) + { + $window->set_cursor($this->{busy_cursor}); + } + else + { $window->set_cursor(undef); } } } + if ($head->{exclude}) + { + Gtk2::Gdk::Event->handler_set(undef); + } else { - Gtk2->grab_add($this->{grab_widget_stack}-> - [$#{$this->{grab_widget_stack}}]); + Gtk2::Gdk::Event->handler_set + (\&main::window_manager_event_filter, + {singleton => $this, + grab_widget => $entry->{grab_widget}}); } } } } +# +############################################################################## +# +# Routine - allow_input +# +# Description - Execute the specified code block whilst allowing mouse and +# keyboard input. Used for displaying dialog windows when the +# application is busy. +# +# Data - $this : The object. +# $code : The code block to be executed. +# +############################################################################## + + +sub allow_input($&) +{ + + my($this, $code) = @_; + + my $head = $this->{state_stack}->[$#{$this->{state_stack}}]; + + local $this->{allow_input} = 1; + + &$code(); + +} +# +############################################################################## +# +# Routine - reset_state +# +# Description - Completely resets the state of all windows and input +# handling. Useful when resetting the GUI after an exception +# was raised. +# +# Data - $this : The object. +# +############################################################################## + + + +sub reset_state($) +{ + + my $this = $_[0]; + + $this->{state_stack} = []; + $this->{allow_input} = 0; + + foreach my $win_instance (@{$this->{windows}}) + { + foreach my $window (@{$win_instance->{busy_windows}}) + { + $window->set_cursor(undef); + } + } + Gtk2::Gdk::Event->handler_set(undef); + +} +# +############################################################################## +# +# Routine - update_gui +# +# Description - Process all outstanding Gtk2 toolkit events. This is used +# to update the GUI whilst the application is busy doing +# something. +# +# Data - None. +# +############################################################################## + + + +sub update_gui() +{ + + return if (Gtk2->main_level() == 0); + while (Gtk2->events_pending()) + { + Gtk2->main_iteration(); + } + +} +# +############################################################################## +# +# Package - main +# +# Description - The event filter routine has to be in the main package as +# this is assumed when constructing calling Perl callbacks. +# +############################################################################## + + + +# ***** PACKAGE DECLARATION ***** + +package main; + +# ***** DIRECTIVES ***** + +require 5.008; + +use strict; +use integer; + +# ***** REQUIRED PACKAGES ***** + +# Standard Perl and CPAN modules. + +use Gtk2; + +# ***** FUNCTIONAL PROTOTYPES ***** + +# Public methods. + +sub window_manager_event_filter($$); +# +############################################################################## +# +# Routine - window_manager_event_filter +# +# Description - Filter for getting rid of unwanted keyboard and mouse +# button events when the application is busy. +# +# Data - $event : The Gtk2::Gdk::Event object representing the +# current event. +# $client_data : The client data that was registered along +# with this event handler. +# +############################################################################## + + + +sub window_manager_event_filter($$) +{ + + my($event, $client_data) = @_; + + my $grab_widget = $client_data->{grab_widget}; + my $this = $client_data->{singleton}; + my $type = $event->type(); + + if (! $this->{allow_input}) + { + foreach my $filter_type (@filtered_events) + { + return + if ($type eq $filter_type + && (! defined($grab_widget) + || Gtk2->get_event_widget($event) != $grab_widget)); + } + } + Gtk2->main_do_event($event); + +} + 1; ============================================================ --- mtn-browse 96fe56cb79dfe462e5d0fa65ef243ef5d3800f61 +++ mtn-browse 86a252dfb397aeb573b472e355807b4dfd857b36 @@ -49,7 +49,6 @@ use lib LIB_PATH; use constant MIME_GLOB_FILE => "/usr/share/mime/globs"; } use lib LIB_PATH; -use lib "/home/aecoope/locale/lib/perl5/site_perl/5.8.5"; use strict; # ***** REQUIRED PACKAGES ***** @@ -68,7 +67,7 @@ use Gtk2::SourceView; use Gtk2::Helper; use Gtk2::Pango; use Gtk2::SourceView; -use Locale::TextDomain ("mtn-browse", "/home/aecoope/perl/locale"); +use Locale::TextDomain ("mtn-browse", LIB_PATH . "/share/locale"); use IO::File; use IPC::Open3; use POSIX qw(:errno_h :locale_h :sys_wait_h strftime); @@ -111,7 +110,7 @@ my $large_logo; my $large_logo; -# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE ***** +# ***** FUNCTIONAL PROTOTYPES ***** # Private routines. @@ -129,6 +128,7 @@ sub mtn_error_handler($$); sub manifest_browser_treeview_row_activated_cb($$$$); sub monotone_viz_button_clicked_cb($$); sub mtn_error_handler($$); +sub new_blank_menu_item_clicked_cb($$); sub new_toolbutton_clicked_cb($$); sub open_toolbutton_clicked_cb($$); sub preferences_toolbutton_clicked_cb($$); @@ -200,7 +200,7 @@ sub view_button_clicked_cb($$); eval { - $tmp_dir = File::Temp::tempdir("mtn-browse_XXXXXXXXXX", + $tmp_dir = File::Temp->tempdir("mtn-browse_XXXXXXXXXX", TMPDIR => 1, CLEANUP => 1); }; @@ -396,7 +396,7 @@ sub about_activate_cb($$) if (! defined($large_logo)); Gnome2::About->new ("mtn-browse", - "0.3b", + "0.4b", __("Copyright \xa9 2007-2009 Anthony Cooper"), __("A graphical front-end browser for Monotone VCS databases"), ["Anthony Cooper "], @@ -429,8 +429,42 @@ sub new_toolbutton_clicked_cb($$) return if ($browser->{in_cb}); local $browser->{in_cb} = 1; + my @revision_ids; + # Simply get a new/unused browser window and display it. + get_revision_ids($browser, address@hidden); + get_browser_window($browser->{mtn}, + $browser->{branch_combo_details}->{value}, + $revision_ids[0]); + +} +# +############################################################################## +# +# Routine - new_blank_menu_item_clicked_cb +# +# Description - Callback routine called when the user clicks on the new +# blank menu item in a main browser window. +# +# Data - $widget : The widget object that received the signal. +# $browser : The browser instance that is associated with +# this widget. +# +############################################################################## + + + +sub new_blank_menu_item_clicked_cb($$) +{ + + my($widget, $browser) = @_; + + return if ($browser->{in_cb}); + local $browser->{in_cb} = 1; + + # Simply get a new/unused browser window and display it. + get_browser_window(); } @@ -1587,8 +1621,8 @@ sub get_browser_window(;$$$$$) # Register the window for management. - $wm->manage($browser, $window_type); - $wm->add_busy_widgets($browser, + $wm->manage($browser, $window_type, $browser->{window}); + $wm->add_busy_windows($browser, $browser->{file_view_sv}->get_window("text")); # Update the browser's internal state. @@ -1692,7 +1726,7 @@ sub update_browser_state($$) $wm->make_busy($browser, 1); $browser->{appbar}->push(""); - gtk2_update(); + $wm->update_gui(); # The database has changed. @@ -1767,14 +1801,14 @@ sub update_browser_state($$) # Get the new list of branches. $browser->{appbar}->set_status(__("Fetching branch list")); - gtk2_update(); + $wm->update_gui(); $browser->{mtn}->branches(address@hidden) if (defined($browser->{mtn})); $browser->{branch_combo_details}->{list} = address@hidden; # Update the branch list combobox. $browser->{appbar}->set_status(__("Populating branch list")); - gtk2_update(); + $wm->update_gui(); my $counter = 1; $browser->{branch_comboboxentry}->get_model()->clear(); foreach my $branch (@branch_list) @@ -1782,13 +1816,13 @@ sub update_browser_state($$) $browser->{branch_comboboxentry}->append_text($branch); $browser->{appbar}->set_progress_percentage ($counter ++ / scalar(@branch_list)); - gtk2_update(); + $wm->update_gui(); } $browser->{branch_comboboxentry}->child()-> set_text($browser->{branch_combo_details}->{value}); $browser->{appbar}->set_progress_percentage(0); $browser->{appbar}->set_status(""); - gtk2_update(); + $wm->update_gui(); } @@ -1818,7 +1852,7 @@ sub update_browser_state($$) if ($browser->{branch_combo_details}->{complete}) { $browser->{appbar}->set_status(__("Fetching revision list")); - gtk2_update(); + $wm->update_gui(); get_branch_revisions($browser->{mtn}, $browser->{branch_combo_details}->{value}, $browser->{tagged_checkbutton}->get_active(), @@ -1831,7 +1865,7 @@ sub update_browser_state($$) $browser->{appbar}->set_progress_percentage(0); $browser->{appbar}->set_status(__("Populating revision list")); - gtk2_update(); + $wm->update_gui(); my $counter = 1; $browser->{revision_comboboxentry}->get_model()->clear(); foreach my $revision (@revision_list) @@ -1839,13 +1873,13 @@ sub update_browser_state($$) $browser->{revision_comboboxentry}->append_text($revision); $browser->{appbar}->set_progress_percentage ($counter ++ / scalar(@revision_list)); - gtk2_update(); + $wm->update_gui(); } $browser->{revision_comboboxentry}->child()-> set_text($browser->{revision_combo_details}->{value}); $browser->{appbar}->set_progress_percentage(0); $browser->{appbar}->set_status(""); - gtk2_update(); + $wm->update_gui(); } @@ -1881,7 +1915,7 @@ sub update_browser_state($$) # Get the new manifest. $browser->{appbar}->set_status(__("Fetching manifest")); - gtk2_update(); + $wm->update_gui(); if ($browser->{revision_combo_details}->{complete}) { my @revision_ids; @@ -1902,7 +1936,7 @@ sub update_browser_state($$) } my $dialog = Gtk2::MessageDialog->new_with_markup ($browser->{window}, ["modal"], "info", "close", $message); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); $browser->{revision_combo_details}->{complete} = 0; $browser->{revision_combo_details}->{value} = ""; @@ -1939,7 +1973,7 @@ sub update_browser_state($$) # Generate a simple list of directories for auto completion. $browser->{appbar}->set_progress_percentage(0.5); - gtk2_update(); + $wm->update_gui(); foreach my $item (@manifest_list) { push(@directory_list, $item->{name}) @@ -1947,13 +1981,13 @@ sub update_browser_state($$) } $browser->{directory_combo_details}->{list} = address@hidden; $browser->{appbar}->set_progress_percentage(1); - gtk2_update(); + $wm->update_gui(); # Update the directory list combobox. $browser->{appbar}->set_progress_percentage(0); $browser->{appbar}->set_status(__("Populating directory list")); - gtk2_update(); + $wm->update_gui(); my $counter = 1; $browser->{directory_comboboxentry}->get_model()->clear(); foreach my $item (@directory_list) @@ -1961,7 +1995,7 @@ sub update_browser_state($$) $browser->{directory_comboboxentry}->append_text($item); $browser->{appbar}->set_progress_percentage ($counter ++ / scalar(@directory_list)); - gtk2_update(); + $wm->update_gui(); } $browser->{directory_comboboxentry}->child()-> set_text($browser->{directory_combo_details}->{value}); @@ -1972,7 +2006,7 @@ sub update_browser_state($$) $widget-> set_sensitive($browser->{revision_combo_details}->{complete}); } - gtk2_update(); + $wm->update_gui(); } @@ -2091,7 +2125,7 @@ sub update_browser_state($$) { $browser->{appbar}->set_progress_percentage ($counter / scalar(@directory_entry_list)); - gtk2_update(); + $wm->update_gui(); } ++ $counter; @@ -2102,7 +2136,7 @@ sub update_browser_state($$) $browser->{appbar}->set_progress_percentage(0); $browser->{appbar}->set_status(""); - gtk2_update(); + $wm->update_gui(); } @@ -2412,6 +2446,7 @@ sub mtn_error_handler($$) my($severity, $message) = @_; my $dialog; + my $wm = WindowManager->instance(); if ($severity eq "warning") { @@ -2424,8 +2459,9 @@ sub mtn_error_handler($$) . __x("{error_message}\n", error_message => Glib::Markup::escape_text($message)) . __("This should not be happening!")); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); + $wm->reset_state(); die($message); } else @@ -2439,7 +2475,7 @@ sub mtn_error_handler($$) . __x("{error_message}\n", error_message => Glib::Markup::escape_text($message)) . __("This is fatal, I am going to exit.")); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); Gtk2->main_quit() unless (Gtk2->main_level() == 0); die($message); @@ -2465,6 +2501,8 @@ sub sigchld_handler() my($pid, $status); + my $wm = WindowManager->instance(); + while (($pid = waitpid(-1, WNOHANG)) > 0) { $status = $?; @@ -2503,8 +2541,9 @@ sub sigchld_handler() error_message => $message) . __("This should not be happening!\n") . __("It will be restarted when needed.")); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); + $wm->reset_state(); return 1; } return; ============================================================ --- mtn-browse.glade e108526a6ed91bc84238ac6586567a7c53b196ea +++ mtn-browse.glade 9bbd76d5f466cdb2191c7f1c16cda558f4574de2 @@ -57,6 +57,27 @@ + + True + New _Blank + True + + + + + True + gtk-new + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + True GNOMEUIINFO_MENU_OPEN_ITEM