[Aptitude-svn-commit] r4115 - in branches/aptitude-0.3/aptitude: .
src src/cmdline src/generic
Daniel Burrows
dburrows at costa.debian.org
Mon Sep 19 20:36:19 UTC 2005
Author: dburrows
Date: Mon Sep 19 20:36:15 2005
New Revision: 4115
Added:
branches/aptitude-0.3/aptitude/src/cmdline/cmdline_spinner.cc
branches/aptitude-0.3/aptitude/src/cmdline/cmdline_spinner.h
Modified:
branches/aptitude-0.3/aptitude/ChangeLog
branches/aptitude-0.3/aptitude/src/broken_indicator.cc
branches/aptitude-0.3/aptitude/src/cmdline/Makefile.am
branches/aptitude-0.3/aptitude/src/cmdline/cmdline_resolver.cc
branches/aptitude-0.3/aptitude/src/generic/resolver_manager.cc
branches/aptitude-0.3/aptitude/src/generic/resolver_manager.h
branches/aptitude-0.3/aptitude/src/solution_dialog.cc
branches/aptitude-0.3/aptitude/src/solution_screen.cc
branches/aptitude-0.3/aptitude/src/ui.cc
Log:
Don't block the UI while the resolver is running.
Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog (original)
+++ branches/aptitude-0.3/aptitude/ChangeLog Mon Sep 19 20:36:15 2005
@@ -1,5 +1,10 @@
2005-09-19 Daniel Burrows <dburrows at debian.org>
+ * src/broken_indicator.cc, src/cmdline/cmdline_resolver.cc, src/cmdline/cmdline_spinner.cc, src/cmdline/cmdline_spinner.h, src/cmdline/Makefile.am, src/generic/resolver_manager.cc, src/generic/resolver_manager.h, src/solution_dialog.cc, src/solution_screen.cc, src/ui.cc:
+
+ Use the background thread to keep the UI responsive while the
+ resolver is running.
+
* src/vscreen/vscreen.cc:
Fix the timeout thread; it was utterly broken (whoops).
Modified: branches/aptitude-0.3/aptitude/src/broken_indicator.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/broken_indicator.cc (original)
+++ branches/aptitude-0.3/aptitude/src/broken_indicator.cc Mon Sep 19 20:36:15 2005
@@ -23,8 +23,8 @@
#include <generic/apt.h>
#include <generic/aptcache.h>
-
#include <generic/aptitude_resolver_universe.h>
+#include <generic/config_signal.h>
#include <generic/problemresolver/exceptions.h>
#include <generic/problemresolver/solution.h>
#include <generic/resolver_manager.h>
@@ -34,6 +34,7 @@
#include <vscreen/config/keybindings.h>
#include <vscreen/fragment.h>
#include <vscreen/vs_text_layout.h>
+#include <vscreen/vscreen.h>
#include <apt-pkg/pkgsystem.h>
@@ -60,25 +61,23 @@
*/
bool last_complete;
+ /** Tracks the phase of the visual "spinner". */
+ int spin_count;
+
void handle_cache_reload()
{
if(apt_cache_file)
- {
- (*apt_cache_file)->package_state_changed.connect(sigc::mem_fun(*this, &broken_indicator::update));
- resman->selected_solution_changed.connect(sigc::mem_fun(*this, &broken_indicator::update));
- }
+ resman->state_changed.connect(sigc::mem_fun(*this, &broken_indicator::post_update));
update();
}
protected:
broken_indicator()
+ :spin_count(0)
{
if(apt_cache_file)
- {
- (*apt_cache_file)->package_state_changed.connect(sigc::mem_fun(*this, &broken_indicator::update));
- resman->selected_solution_changed.connect(sigc::mem_fun(*this, &broken_indicator::update));
- }
+ resman->state_changed.connect(sigc::mem_fun(*this, &broken_indicator::post_update));
cache_closed.connect(sigc::mem_fun(*this, &broken_indicator::update));
cache_reloaded.connect(sigc::mem_fun(*this, &broken_indicator::handle_cache_reload));
@@ -86,6 +85,85 @@
set_bg_style(get_style("Error"));
update();
+
+ vscreen_addtimeout(sigc::mem_fun(this, &broken_indicator::tick_timeout),
+ aptcfg->FindI(PACKAGE "::Spin-Interval", 500));
+ }
+
+ static fragment *key_hint_fragment()
+ {
+ wstring next=global_bindings.readable_keyname("NextSolution");
+ wstring prev=global_bindings.readable_keyname("PrevSolution");
+ wstring examine=global_bindings.readable_keyname("ExamineSolution");
+ wstring apply=global_bindings.readable_keyname("ApplySolution");
+
+ vector<fragment *> key_hints;
+
+ key_hints.push_back(fragf(_("%s: Examine"),
+ examine.c_str()));
+ key_hints.push_back(fragf(_("%s: Apply"),
+ apply.c_str()));
+ key_hints.push_back(fragf(_("%s: Next"),
+ next.c_str()));
+ key_hints.push_back(fragf(_("%s: Previous"),
+ prev.c_str()));
+
+ return join_fragments(key_hints, L" ");
+ }
+
+ void tick_timeout()
+ {
+ if(resman->background_thread_active())
+ {
+ ++spin_count;
+ update();
+ vscreen_update();
+ }
+
+ vscreen_addtimeout(sigc::mem_fun(this, &broken_indicator::tick_timeout),
+ aptcfg->FindI(PACKAGE "::Spin-Interval", 500));
+ }
+
+ std::string spin_string() const
+ {
+ switch(spin_count % 4)
+ {
+ case 0:
+ return ".";
+ case 1:
+ return "o";
+ case 2:
+ return "O";
+ case 3:
+ return "o";
+ default:
+ return "?";
+ }
+ }
+
+ struct update_event : public vscreen_event
+ {
+ broken_indicator *b;
+ public:
+ update_event(broken_indicator *_b)
+ : b(_b)
+ {
+ }
+
+ void dispatch()
+ {
+ b->update();
+ }
+ };
+
+ /** Post an update to run in the main thread; needed since the
+ * selected_signal_changed signal might theoretically run from a
+ * background thread. (at the moment it shouldn't, but this will
+ * help avoid nasty surprises)
+ */
+ void post_update()
+ {
+ vscreen_post_event(new update_event(this));
}
public:
static ref_ptr<broken_indicator> create()
@@ -93,6 +171,7 @@
return new broken_indicator;
}
+ // TODO: split this monster up.
void update()
{
if((!apt_cache_file) || !resman->resolver_exists())
@@ -103,140 +182,134 @@
return;
}
- wstring next=global_bindings.readable_keyname("NextSolution");
- wstring prev=global_bindings.readable_keyname("PrevSolution");
- wstring examine=global_bindings.readable_keyname("ExamineSolution");
- wstring apply=global_bindings.readable_keyname("ApplySolution");
+ // Take a snapshot of the state.
+ resolver_manager::state state = resman->state_snapshot();
+
+ if(state.solutions_exhausted && state.generated_solutions == 0)
+ {
+ set_fragment(fragf(_("Unable to resolve dependencies.")));
+ last_sol.nullify();
+ show();
+ return;
+ }
- // try to retrieve the current solution to show information about
- // it.
- try
+ // Handle the case where the resolver is churning away.
+ if(state.selected_solution >= state.generated_solutions)
{
- aptitude_solution sol=resman->get_current_solution();
+ // TODO: add a column-generating fragment that can
+ // left/right justify stuff.
+ set_fragment(fragf(_("Resolving dependencies %s%n%F"),
+ spin_string().c_str(), key_hint_fragment()));
+ last_sol.nullify();
+ show();
+ return;
+ }
+
+ aptitude_solution sol = resman->get_solution(state.selected_solution);
- if(sol == last_sol && resman->solution_generation_complete() == last_complete)
- return;
+ // This test always fails the first time update() is called, since
+ // sol is never NULL and last_sol is initialized to NULL.
+ if(sol == last_sol && state.solutions_exhausted == last_complete)
+ return;
- last_sol = sol;
- last_complete = resman->solution_generation_complete();
+ last_sol = sol;
+ last_complete = state.solutions_exhausted;
- if(sol.get_actions().empty())
+ if(sol.get_actions().empty())
+ {
+ set_fragment(fragf("%s", _("Internal error: unexpected null solution.")));
+ show();
+ return;
+ }
+
+ int install_count=0, remove_count=0, keep_count=0, upgrade_count=0, downgrade_count=0;
+
+ for(imm::map<aptitude_universe::package, aptitude_solution::action>::const_iterator
+ i = sol.get_actions().begin();
+ i != sol.get_actions().end(); ++i)
+ {
+ pkgCache::PkgIterator pkg=i->first.get_pkg();
+ pkgCache::VerIterator curver=pkg.CurrentVer();
+ pkgCache::VerIterator instver=(*apt_cache_file)[pkg].InstVerIter(*apt_cache_file);
+ pkgCache::VerIterator newver=i->second.ver.get_ver();
+
+ // If not, we have a problem.
+ assert(instver!=newver);
+
+ if(newver == curver)
+ ++keep_count;
+ else if(curver.end())
+ ++install_count;
+ else if(newver.end())
+ ++remove_count;
+ else
{
- set_fragment(fragf("%s", _("Internal error: unexpected null solution.")));
- show();
- return;
+ int cmp=_system->VS->CmpVersion(curver.VerStr(),
+ newver.VerStr());
+
+ // The versions shouldn't be equal -- otherwise
+ // something is majorly wrong.
+ // assert(cmp!=0);
+ //
+ // The above is not true: consider, eg, the case of a
+ // locally compiled package and a standard package.
+
+ /** \todo indicate "sidegrades" separately? */
+ if(cmp<=0)
+ ++upgrade_count;
+ else if(cmp>0)
+ ++downgrade_count;
}
- int install_count=0, remove_count=0, keep_count=0, upgrade_count=0, downgrade_count=0;
+ vector<fragment *> fragments;
- for(imm::map<aptitude_universe::package, aptitude_solution::action>::const_iterator
- i = sol.get_actions().begin();
- i != sol.get_actions().end(); ++i)
- {
- pkgCache::PkgIterator pkg=i->first.get_pkg();
- pkgCache::VerIterator curver=pkg.CurrentVer();
- pkgCache::VerIterator instver=(*apt_cache_file)[pkg].InstVerIter(*apt_cache_file);
- pkgCache::VerIterator newver=i->second.ver.get_ver();
-
- // If not, we have a problem.
- assert(instver!=newver);
-
- if(newver == curver)
- ++keep_count;
- else if(curver.end())
- ++install_count;
- else if(newver.end())
- ++remove_count;
- else
- {
- int cmp=_system->VS->CmpVersion(curver.VerStr(),
- newver.VerStr());
-
- // The versions shouldn't be equal -- otherwise
- // something is majorly wrong.
- // assert(cmp!=0);
- //
- // The above is not true: consider, eg, the case of a
- // locally compiled package and a standard package.
-
- /** \todo indicate "sidegrades" separately? */
- if(cmp<=0)
- ++upgrade_count;
- else if(cmp>0)
- ++downgrade_count;
- }
-
- vector<fragment *> fragments;
-
- string countstr
- = ssprintf(resman->solution_generation_complete()?"[%d/%d]":"[%d(%d)/...]",
- resman->get_selected_solution()+1,
- resman->generated_solution_count());
- fragments.push_back(fragf("%s ", countstr.c_str()));
-
- fragments.push_back(fragf(_("Suggest ")));
-
- vector<fragment *> suggestions;
-
- if(install_count>1)
- suggestions.push_back(text_fragment(ssprintf(_("%d installs"),
- install_count)));
- else if(install_count == 1)
- suggestions.push_back(text_fragment(_("1 install")));
-
- if(remove_count>1)
- suggestions.push_back(text_fragment(ssprintf(_("%d removals"),
- remove_count)));
- else if(remove_count == 1)
- suggestions.push_back(text_fragment(_("1 removal")));
-
- if(keep_count>1)
- suggestions.push_back(text_fragment(ssprintf(_("%d keeps"),
- keep_count)));
- else if(keep_count == 1)
- suggestions.push_back(text_fragment(_("1 keep")));
-
- if(upgrade_count>1)
- suggestions.push_back(text_fragment(ssprintf(_("%d upgrades"), upgrade_count)));
- else if(upgrade_count == 1)
- suggestions.push_back(text_fragment(_("1 upgrade")));
-
- if(downgrade_count>1)
- suggestions.push_back(text_fragment(ssprintf(_("%d downgrades"), downgrade_count)));
- else if(downgrade_count == 1)
- suggestions.push_back(text_fragment(_("1 downgrade")));
-
- fragments.push_back(join_fragments(suggestions,
- L","));
-
- fragments.push_back(newline_fragment());
-
- vector<fragment *> key_hints;
-
- key_hints.push_back(fragf(_("%s: Examine"),
- examine.c_str()));
- key_hints.push_back(fragf(_("%s: Apply"),
- apply.c_str()));
- key_hints.push_back(fragf(_("%s: Next"),
- next.c_str()));
- key_hints.push_back(fragf(_("%s: Previous"),
- prev.c_str()));
+ string countstr
+ = ssprintf(state.solutions_exhausted?"[%d/%d]":"[%d(%d)/...]",
+ state.selected_solution + 1,
+ state.generated_solutions);
+ fragments.push_back(fragf("%s ", countstr.c_str()));
+
+ fragments.push_back(fragf(_("Suggest ")));
+
+ vector<fragment *> suggestions;
+
+ if(install_count>1)
+ suggestions.push_back(text_fragment(ssprintf(_("%d installs"),
+ install_count)));
+ else if(install_count == 1)
+ suggestions.push_back(text_fragment(_("1 install")));
+
+ if(remove_count>1)
+ suggestions.push_back(text_fragment(ssprintf(_("%d removals"),
+ remove_count)));
+ else if(remove_count == 1)
+ suggestions.push_back(text_fragment(_("1 removal")));
+
+ if(keep_count>1)
+ suggestions.push_back(text_fragment(ssprintf(_("%d keeps"),
+ keep_count)));
+ else if(keep_count == 1)
+ suggestions.push_back(text_fragment(_("1 keep")));
+
+ if(upgrade_count>1)
+ suggestions.push_back(text_fragment(ssprintf(_("%d upgrades"), upgrade_count)));
+ else if(upgrade_count == 1)
+ suggestions.push_back(text_fragment(_("1 upgrade")));
+
+ if(downgrade_count>1)
+ suggestions.push_back(text_fragment(ssprintf(_("%d downgrades"), downgrade_count)));
+ else if(downgrade_count == 1)
+ suggestions.push_back(text_fragment(_("1 downgrade")));
+
+ fragments.push_back(join_fragments(suggestions,
+ L","));
- fragments.push_back(join_fragments(key_hints,
- L" "));
+ fragments.push_back(newline_fragment());
- fragment *f=sequence_fragment(fragments);
- set_fragment(hardwrapbox(f));
- }
- }
- catch(NoMoreTime)
- {
- set_fragment(fragf(_("Solution search failed. %s: try harder"),
- next.c_str()));
- }
- catch(NoMoreSolutions)
- {
- set_fragment(fragf(_("Unable to resolve dependencies.")));
+ fragments.push_back(key_hint_fragment());
+
+ fragment *f=sequence_fragment(fragments);
+ set_fragment(hardwrapbox(f));
}
show();
Modified: branches/aptitude-0.3/aptitude/src/cmdline/Makefile.am
==============================================================================
--- branches/aptitude-0.3/aptitude/src/cmdline/Makefile.am (original)
+++ branches/aptitude-0.3/aptitude/src/cmdline/Makefile.am Mon Sep 19 20:36:15 2005
@@ -34,6 +34,8 @@
cmdline_show_broken.h \
cmdline_simulate.cc \
cmdline_simulate.h \
+ cmdline_spinner.cc \
+ cmdline_spinner.h \
cmdline_update.cc \
cmdline_update.h \
cmdline_upgrade.cc \
Modified: branches/aptitude-0.3/aptitude/src/cmdline/cmdline_resolver.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/cmdline/cmdline_resolver.cc (original)
+++ branches/aptitude-0.3/aptitude/src/cmdline/cmdline_resolver.cc Mon Sep 19 20:36:15 2005
@@ -24,6 +24,7 @@
#include "cmdline_prompt.h"
#include "cmdline_show.h"
#include "cmdline_show_broken.h"
+#include "cmdline_spinner.h"
#include "cmdline_util.h"
#include <aptitude.h>
@@ -332,6 +333,124 @@
}
}
+// TODO: make this generic?
+class cmdline_resolver_continuation : public resolver_manager::background_continuation
+{
+public:
+ struct resolver_result
+ {
+ /** If \b true, then NoMoreSolutions was thrown. */
+ bool out_of_solutions;
+
+ /** If \b true, then NoMoreTime was thrown. */
+ bool out_of_time;
+
+ /** If out_of_solutions and out_of_time are false, this is
+ * the result returned by the resolver.
+ */
+ aptitude_solution sol;
+
+ resolver_result()
+ : out_of_solutions(false), out_of_time(false)
+ {
+ }
+
+ resolver_result(bool _out_of_solutions, bool _out_of_time)
+ : out_of_solutions(_out_of_solutions),
+ out_of_time(_out_of_time)
+ {
+ }
+
+ resolver_result(const aptitude_solution &_sol)
+ : out_of_solutions(false), out_of_time(false), sol(_sol)
+ {
+ }
+ };
+
+private:
+ threads::box<resolver_result> &retbox;
+
+public:
+ cmdline_resolver_continuation(threads::box<resolver_result> &_retbox)
+ : retbox(_retbox)
+ {
+ }
+
+ void success(const aptitude_solution &sol)
+ {
+ retbox.put(resolver_result(sol));
+ }
+
+ void no_more_solutions()
+ {
+ retbox.put(resolver_result(true, false));
+ }
+
+ void no_more_time()
+ {
+ retbox.put(resolver_result(false, true));
+ }
+
+ void interrupted()
+ {
+ abort();
+ }
+};
+
+/** \return the resolver's current solution; if it needs to be calculated
+ * first, run the calculation in the background and display
+ * a spinner in the foreground.
+ */
+static
+aptitude_solution calculate_current_solution()
+{
+ if(resman->get_selected_solution() < resman->generated_solution_count())
+ return resman->get_solution(resman->get_selected_solution());
+
+
+ cmdline_spinner spin;
+ spin.set_msg(_("Resolving dependencies..."));
+
+ threads::box<cmdline_resolver_continuation::resolver_result> retbox;
+
+ resman->get_solution_background(resman->generated_solution_count(),
+ new cmdline_resolver_continuation(retbox));
+
+ cmdline_resolver_continuation::resolver_result res;
+ bool done = false;
+ // The number of milliseconds to step per display.
+ long spin_step = aptcfg->FindI(PACKAGE "::Spin-Interval", 500);
+
+ do
+ {
+ timeval until;
+ gettimeofday(&until, 0);
+
+ until.tv_usec += spin_step * 1000L;
+ until.tv_sec += until.tv_usec / (1000L * 1000L);
+ until.tv_usec = until.tv_usec % (1000L * 1000L);
+
+ timespec until_ts;
+ until_ts.tv_sec = until.tv_sec;
+ until_ts.tv_nsec = until.tv_usec * 1000;
+
+ done = retbox.timed_take(res, until_ts);
+
+ if(!done)
+ {
+ spin.display();
+ spin.tick();
+ }
+ } while(!done);
+
+ if(res.out_of_time)
+ throw NoMoreTime();
+ else if(res.out_of_solutions)
+ throw NoMoreSolutions();
+ else
+ return res.sol;
+}
+
bool cmdline_resolve_deps(pkgset &to_install,
pkgset &to_hold,
pkgset &to_remove,
@@ -355,7 +474,7 @@
{
try
{
- aptitude_solution sol=resman->get_current_solution();
+ aptitude_solution sol = calculate_current_solution();
if(_error->PendingError())
_error->DumpErrors();
@@ -391,17 +510,16 @@
switch(toupper(response[loc]))
{
case 'Y':
- (*apt_cache_file)->apply_solution(resman->get_current_solution(), NULL);
+ (*apt_cache_file)->apply_solution(calculate_current_solution(), NULL);
modified_pkgs=true;
break;
case 'N':
{
int curr_count = resman->generated_solution_count();
- // Move to the last cached solution.
if(curr_count>0)
- while(resman->get_selected_solution()<curr_count)
- resman->next_solution();
+ while(resman->get_selected_solution() < curr_count)
+ resman->select_next_solution();
}
break;
case 'Q':
@@ -426,11 +544,10 @@
reject_or_mandate_version(string(response, 1), false);
break;
case '.':
- resman->next_solution();
+ resman->select_next_solution();
break;
case ',':
- // As above, errors pop to the outer 'catch'
- resman->previous_solution();
+ resman->select_previous_solution();
break;
case '?':
cout << _("The following commands are available:") << endl;
@@ -488,7 +605,7 @@
case 'Y':
try
{
- resman->next_solution();
+ calculate_current_solution();
done=true;
}
catch(NoMoreTime)
@@ -517,6 +634,7 @@
{
cout << _("No more solutions.") << endl;
// Force it to re-print the last solution.
+ resman->select_previous_solution();
lastsol.nullify();
}
}
Added: branches/aptitude-0.3/aptitude/src/cmdline/cmdline_spinner.cc
==============================================================================
--- (empty file)
+++ branches/aptitude-0.3/aptitude/src/cmdline/cmdline_spinner.cc Mon Sep 19 20:36:15 2005
@@ -0,0 +1,59 @@
+// cmdline_spinner.cc -*-c++-*-
+//
+// Copyright (C) 2005 Daniel Burrows
+//
+// 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; either version 2 of
+// the License, or (at your option) any later version.
+//
+// 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; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+#include "cmdline_spinner.h"
+
+#include "cmdline_common.h"
+
+#include <iostream>
+
+cmdline_spinner::cmdline_spinner()
+ : count(0)
+{
+}
+
+char cmdline_spinner::spin_char() const
+{
+ switch(count % 4)
+ {
+ case 0:
+ return '.';
+ case 1:
+ return 'o';
+ case 2:
+ return 'O';
+ case 3:
+ return 'o';
+ default:
+ return '?';
+ }
+}
+
+void cmdline_spinner::display() const
+{
+ update_screen_width();
+
+ // Build the string to output.
+ std::string out(msg, 0, screen_width);
+ out.append(screen_width-1-out.size(), ' ');
+ if(out.size() < screen_width)
+ out += spin_char();
+
+ std::cout << '\r' << out << std::flush;
+}
Added: branches/aptitude-0.3/aptitude/src/cmdline/cmdline_spinner.h
==============================================================================
--- (empty file)
+++ branches/aptitude-0.3/aptitude/src/cmdline/cmdline_spinner.h Mon Sep 19 20:36:15 2005
@@ -0,0 +1,58 @@
+// cmdline_spinner.h -*-c++-*-
+//
+// Copyright (C) 2005 Daniel Burrows
+//
+// 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; either version 2 of
+// the License, or (at your option) any later version.
+//
+// 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; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
+// A generic spinner (for use with the background resolver).
+
+#ifndef CMDLINE_SPINNER_H
+#define CMDLINE_SPINNER_H
+
+#include <string>
+
+/** A spinner for command-line output. */
+class cmdline_spinner
+{
+ std::string msg;
+
+ /** The number of spins. */
+ int count;
+public:
+ cmdline_spinner();
+
+ /** Display the current spinner state, overwriting the current
+ * terminal line.
+ */
+ void display() const;
+
+ /** Return a spin character for the given tick count. */
+ virtual char spin_char() const;
+
+ /** Advance the spinner one position. */
+ void tick()
+ {
+ ++count;
+ }
+
+ /** Set the message displayed to the left of the spinner. */
+ void set_msg(const std::string &new_msg)
+ {
+ msg = new_msg;
+ }
+};
+
+#endif
Modified: branches/aptitude-0.3/aptitude/src/generic/resolver_manager.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/resolver_manager.cc (original)
+++ branches/aptitude-0.3/aptitude/src/generic/resolver_manager.cc Mon Sep 19 20:36:15 2005
@@ -37,7 +37,6 @@
:cache(_cache),
resolver(NULL),
selected_solution(0),
- out_of_time(false),
out_of_solutions(false),
background_thread_killed(false),
resolver_null(true),
@@ -238,6 +237,12 @@
if(resolver == NULL && cache->BrokenCount() > 0)
create_resolver();
+
+ // Always signal a state change: we are signalling for the whole
+ // discard/create pair, and even if we didn't create a new resolver
+ // we have to inform the listeners that the old one went away
+ // (maybe).
+ state_changed();
}
void resolver_manager::discard_resolver()
@@ -270,10 +275,8 @@
background_control_cond.wake_all();
}
- out_of_time.take();
out_of_solutions.take();
out_of_solutions.put(false);
- out_of_time.put(false);
}
void resolver_manager::create_resolver()
@@ -361,25 +364,43 @@
return rval;
}
-bool resolver_manager::solutions_exhausted() // const
+bool resolver_manager::solutions_at_start() const
{
threads::mutex::lock l(mutex);
if(!resolver_exists())
return true;
else
- return selected_solution+1 == generated_solution_count() &&
- solution_generation_complete();
+ return selected_solution == 0;
}
-bool resolver_manager::solutions_at_start() const
+bool resolver_manager::background_thread_active()
{
threads::mutex::lock l(mutex);
- if(!resolver_exists())
- return true;
- else
- return selected_solution == 0;
+ threads::mutex::lock ctl_l(background_control_mutex);
+
+ return !pending_jobs.empty() || background_thread_in_resolver;
+}
+
+resolver_manager::state resolver_manager::state_snapshot()
+{
+ threads::mutex::lock l(mutex);
+
+ threads::mutex::lock ctl_l(background_control_mutex);
+
+ threads::mutex::lock sol_l(solutions_mutex);
+
+ state rval;
+
+ rval.selected_solution = selected_solution;
+ rval.generated_solutions = solutions.size();
+ rval.resolver_exists = (resolver != NULL);
+ rval.solutions_exhausted = out_of_solutions.take();
+ out_of_solutions.put(rval.solutions_exhausted);
+ rval.background_thread_active = (!pending_jobs.empty() || background_thread_in_resolver);
+
+ return rval;
}
aptitude_resolver::solution *resolver_manager::do_get_solution(unsigned int max_steps, unsigned int solution_num)
@@ -400,25 +421,19 @@
solutions.push_back(new aptitude_resolver::solution(sol.clone()));
sol_l.release();
- out_of_time.take();
out_of_solutions.take();
out_of_solutions.put(false);
- out_of_time.put(false);
}
catch(NoMoreTime)
{
- out_of_time.take();
out_of_solutions.take();
out_of_solutions.put(false);
- out_of_time.put(true);
throw NoMoreTime();
}
catch(NoMoreSolutions)
{
- out_of_time.take();
out_of_solutions.take();
out_of_solutions.put(true);
- out_of_time.put(false);
throw NoMoreSolutions();
}
}
@@ -484,33 +499,12 @@
assert(resolver);
+ {
+ threads::mutex::lock l2(solutions_mutex);
+ if(solution_num < solutions.size())
+ return *solutions[solution_num];
+ }
- const generic_solution<aptitude_universe> *sol = NULL;
- bool oot = false;
- bool oos = false;
- threads::mutex m;
- threads::condition c;
-
- get_solution_background(solution_num, new solution_return_continuation(sol, oot, oos, m, c));
- threads::mutex::lock cond_l(m);
-
- while(!sol && !oot && !oos)
- c.wait(cond_l);
-
- if(oot)
- throw NoMoreTime();
- else if(oos)
- throw NoMoreSolutions();
-
- return *sol;
-}
-
-
-const aptitude_resolver::solution &resolver_manager::get_current_solution()
-{
- threads::mutex::lock l(mutex);
-
- assert(resolver);
const generic_solution<aptitude_universe> *sol = NULL;
bool oot = false;
@@ -518,7 +512,7 @@
threads::mutex m;
threads::condition c;
- get_current_solution_background(new solution_return_continuation(sol, oot, oos, m, c));
+ get_solution_background(solution_num, new solution_return_continuation(sol, oot, oos, m, c));
threads::mutex::lock cond_l(m);
while(!sol && !oot && !oos)
@@ -556,33 +550,6 @@
background_control_cond.wake_all();
}
-void resolver_manager::get_current_solution_background(background_continuation *k)
-{
- threads::mutex::lock l(mutex);
-
- assert(resolver);
-
-
- bool oot = out_of_time.take();
- bool oos = out_of_solutions.take();
-
- out_of_time.put(oot);
- out_of_solutions.put(oos);
-
- // Only throw NoMoreTime when we're trying to generate a new
- // solution.
- threads::mutex::lock sol_l(solutions_mutex);
- size_t solution_count = solutions.size();
- sol_l.release();
-
- if(oot && selected_solution >= solution_count)
- throw NoMoreTime();
- else if(oos && selected_solution >= solution_count)
- throw NoMoreSolutions();
- else
- get_solution_background(selected_solution, k);
-}
-
void resolver_manager::reject_version(const aptitude_resolver_version &ver)
{
threads::mutex::lock l(mutex);
@@ -602,12 +569,11 @@
resolver->unreject_version(ver);
- out_of_time.take();
+
out_of_solutions.take();
out_of_solutions.put(false);
- out_of_time.put(false);
- selected_solution_changed();
+ state_changed();
}
bool resolver_manager::is_rejected(const aptitude_resolver_version &ver)
@@ -637,12 +603,10 @@
resolver->unmandate_version(ver);
- out_of_time.take();
out_of_solutions.take();
out_of_solutions.put(false);
- out_of_time.put(false);
- selected_solution_changed();
+ state_changed();
}
bool resolver_manager::is_mandatory(const aptitude_resolver_version &ver)
@@ -672,12 +636,10 @@
resolver->unharden(dep);
- out_of_time.take();
out_of_solutions.take();
out_of_solutions.put(false);
- out_of_time.put(false);
- selected_solution_changed();
+ state_changed();
}
bool resolver_manager::is_hardened(const aptitude_resolver_dep &dep)
@@ -707,12 +669,10 @@
resolver->unforce_break(dep);
- selected_solution_changed();
+ state_changed();
- out_of_time.take();
out_of_solutions.take();
out_of_solutions.put(false);
- out_of_time.put(false);
}
bool resolver_manager::is_forced_broken(const aptitude_resolver_dep &dep)
@@ -723,43 +683,40 @@
return resolver->is_forced_broken(dep);
}
-void resolver_manager::select_next_solution()
+void resolver_manager::select_solution(unsigned int solnum)
{
threads::mutex::lock l(mutex);
threads::mutex::lock sol_l(solutions_mutex);
- if(selected_solution < solutions.size())
- ++selected_solution;
+ if(solnum >= 0 && solnum <= solutions.size())
+ selected_solution = solnum;
sol_l.release();
- selected_solution_changed();
+ state_changed();
}
-void resolver_manager::select_previous_solution()
+void resolver_manager::select_next_solution()
{
threads::mutex::lock l(mutex);
- if(selected_solution == 0)
- throw NoMoreSolutions();
- else
- --selected_solution;
- selected_solution_changed();
-}
-
-const aptitude_resolver::solution &resolver_manager::next_solution()
-{
- threads::mutex::lock l(mutex);
+ threads::mutex::lock sol_l(solutions_mutex);
+ if(selected_solution < solutions.size())
+ ++selected_solution;
+ sol_l.release();
- select_next_solution();
- return get_current_solution();
+ state_changed();
}
-const aptitude_resolver::solution &resolver_manager::previous_solution()
+void resolver_manager::select_previous_solution()
{
threads::mutex::lock l(mutex);
- select_previous_solution();
- return get_current_solution();
+ threads::mutex::lock sol_l(solutions_mutex);
+ if(selected_solution > 0)
+ --selected_solution;
+ sol_l.release();
+
+ state_changed();
}
void resolver_manager::tweak_score(const pkgCache::PkgIterator &pkg,
Modified: branches/aptitude-0.3/aptitude/src/generic/resolver_manager.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/resolver_manager.h (original)
+++ branches/aptitude-0.3/aptitude/src/generic/resolver_manager.h Mon Sep 19 20:36:15 2005
@@ -88,6 +88,27 @@
virtual void interrupted() = 0;
};
+ /** A snapshot of the state of the resolver. */
+ struct state
+ {
+ /** The currently selected solution. */
+ int selected_solution;
+
+ /** The number of already-generated solutions. */
+ int generated_solutions;
+
+ /** If \b true, then there are no more solutions to generate. */
+ bool solutions_exhausted;
+
+ /** If \b true, then the resolver is not \b null (i.e., it exists;
+ * i.e., there are broken packages).
+ */
+ bool resolver_exists;
+
+ /** If \b true, the background thread has jobs. */
+ bool background_thread_active;
+ };
+
private:
/** Information about a single request posted to the background
* thread.
@@ -136,14 +157,6 @@
/** The index of the currently selected solution. */
unsigned int selected_solution;
- /** If \b true, there are no solutions and the last attempt to
- * calculate one failed with NoMoreTime.
- *
- * This is used so that the return value of get_current_solution()
- * is stable.
- */
- threads::box<bool> out_of_time;
-
/** If \b true, a find_next_solution() call will terminate with
* NoMoreSolutions. (this may be the case even if it is \b false)
*
@@ -282,7 +295,7 @@
unsigned int generated_solution_count() const;
/** Get the selection location, which will be in the range
- * [0,generated_solution_count()-1). Note that this is meaningless
+ * [0,generated_solution_count()). Note that this is meaningless
* if generated_solution_count==0.
*/
unsigned int get_selected_solution() const {return selected_solution;}
@@ -292,9 +305,8 @@
* the list; will continue a search even if it ran out of time
* previously.
*
- * If solution_num < generated_solution_count, it is always safe to
- * call this from a foreground thread; otherwise, an exception will
- * be thrown if a background resolver exists.
+ * If solution_num refers to an already-generated solution, this
+ * routine returns immediately (without suspending the thread).
*
* \throw NoMoreSolutions if the list of solutions is exhausted
* \throw NoMoreTime if time is exhausted while searching for
@@ -305,18 +317,6 @@
*/
const generic_solution<aptitude_universe> &get_solution(unsigned int solution_num);
- /** Requires the resolver_exists() is \b true. Return the currently
- * selected solution, perhaps generating it; however, will not
- * continue to search if the last search ran out of time.
- *
- * \throw NoMoreSolutions if the list of solutions is exhausted
- * \throw NoMoreTime if time is exhausted while searching for the solution.
- * \throw ResolverManagerThreadClashException if a new solution
- * would be generated and a background thread exists.
- */
- const generic_solution<aptitude_universe> &get_current_solution();
-
-
/** As get_solution, but run in a background thread if necessary.
*
* \param solution_num the solution to retrieve
@@ -335,34 +335,25 @@
void get_solution_background(unsigned int solution_num,
background_continuation *k);
- /** As get_current_solution, but run in a background thread if
- * necessary. Updates to the selected solution will not alter the
- * solution being computed by the background thread.
- *
- * \param solution_num the solution to retrieve
- *
- * \param k the continuation of the background process; see
- * get_background_solution.
- *
- * \throw ResolverManagerThreadClashException if a background
- * resolver already exists.
- */
- void get_current_solution_background(background_continuation *k);
-
/** If \b true, all solutions have been generated. */
bool solution_generation_complete() /*const*/;
- /** If \b true, then either there is no resolver, or the resolver
- * has been exhausted and the solution pointer is set to the last
- * solution.
- */
- bool solutions_exhausted() /* const */;
-
/** If \b true, the solution pointer is set to the first
* solution.
*/
bool solutions_at_start() const;
+ /** If \b true, the background thread is working on a job. */
+ bool background_thread_active();
+
+ /** Get a snapshot of the current resolver state; contains the
+ * values that would be returned by get_selected_solution(),
+ * generated_solution_count(), and solutions_exhausted(); however,
+ * this snapshot is taken atomically.
+ */
+ state state_snapshot();
+
+
/** Requires that resolver_exists() is \b true. Temporarily rejects
* any solutions generated by the currently active installer that
@@ -419,6 +410,8 @@
bool is_forced_broken(const aptitude_resolver_dep &dep);
+ /** Set the selection pointer to a particular solution. */
+ void select_solution(unsigned int solnum);
/** Move the selection pointer to the next solution, without
* generating it.
@@ -432,28 +425,6 @@
*/
void select_previous_solution();
- /** Advance to the next solution.
- *
- * \return the next solution. This reference is not guaranteed to
- * persist if any other operation is performed on the cache; a
- * stack variable should be instantiated from it.
- *
- * \throws NoMoreSolutions if there are no more solutions
- * \throws NoMoreTime if a solution could not be found before the
- * cutoff time expired.
- */
- const generic_solution<aptitude_universe> &next_solution();
-
- /** Return to the previous solution.
- *
- * \return the previous solution. This reference is not guaranteed
- * to persist if any other operation is performed on the cache; a
- * stack variable should be instantiated from it.
- *
- * \throws NoMoreSolutions if solutions_at_start()
- */
- const generic_solution<aptitude_universe> &previous_solution();
-
/** Tweak the resolver score of a particular package/version. This
* requires that resolver_exists() and that the resolver is "fresh"
* (i.e., that next_solution() and current_solution() have never
@@ -472,11 +443,17 @@
*/
void dump(std::ostream &out);
- /** This signal is emitted when the selected solution changes, or
- * when the user takes an action that might change the number of
- * available solutions (such as un-rejecting a package).
+ /** This signal is emitted when the selected solution changes, when
+ * the user takes an action that might change the number of
+ * available solutions (such as un-rejecting a package), and when a
+ * new resolver is created.
+ *
+ * Note that this is NOT signalled when a new solution is added to
+ * the solution list by the background thread. You are free to
+ * manually emit the signal, but of course be aware of threading
+ * considerations if you do so.
*/
- sigc::signal0<void> selected_solution_changed;
+ sigc::signal0<void> state_changed;
};
#endif
Modified: branches/aptitude-0.3/aptitude/src/solution_dialog.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/solution_dialog.cc (original)
+++ branches/aptitude-0.3/aptitude/src/solution_dialog.cc Mon Sep 19 20:36:15 2005
@@ -32,6 +32,7 @@
#include <vscreen/vs_scrollbar.h>
#include <vscreen/vs_table.h>
#include <vscreen/vs_text_layout.h>
+#include <vscreen/vscreen.h>
#include <generic/apt.h>
#include <generic/aptitude_resolver_universe.h>
@@ -50,22 +51,37 @@
void handle_cache_reload()
{
if(apt_cache_file)
- {
- (*apt_cache_file)->package_state_changed.connect(sigc::mem_fun(*this, &solution_dialog::update));
- resman->selected_solution_changed.connect(sigc::mem_fun(*this, &solution_dialog::update));
- }
+ resman->state_changed.connect(sigc::mem_fun(*this, &solution_dialog::post_update));
update();
}
+ struct update_event : public vscreen_event
+ {
+ solution_dialog *dlg;
+
+ public:
+ update_event(solution_dialog *_dlg)
+ :dlg(_dlg)
+ {
+ }
+
+ void dispatch()
+ {
+ dlg->update();
+ }
+ };
+
+ void post_update()
+ {
+ vscreen_post_event(new update_event(this));
+ }
+
protected:
solution_dialog()
{
if(apt_cache_file)
- {
- (*apt_cache_file)->package_state_changed.connect(sigc::mem_fun(*this, &solution_dialog::update));
- resman->selected_solution_changed.connect(sigc::mem_fun(*this, &solution_dialog::update));
- }
+ resman->state_changed.connect(sigc::mem_fun(*this, &solution_dialog::post_update));
cache_closed.connect(sigc::mem_fun(*this, &solution_dialog::update));
cache_reloaded.connect(sigc::mem_fun(*this, &solution_dialog::handle_cache_reload));
@@ -96,29 +112,31 @@
return;
}
- try
- {
- aptitude_solution sol = resman->get_current_solution();
+ resolver_manager::state state = resman->state_snapshot();
- if(sol == last_sol)
- return;
-
- last_sol=sol;
-
- if(sol.get_actions().empty())
- set_fragment(fragf("%s", _("Internal error: unexpected null solution.")));
- else
- set_fragment(solution_fragment(sol));
- }
- catch(NoMoreSolutions)
+ if(state.solutions_exhausted && state.generated_solutions == 0)
{
set_fragment(fragf("%s", _("No resolution found.")));
+ return;
}
- catch(NoMoreTime)
+
+ if(state.selected_solution >= state.generated_solutions)
{
- set_fragment(fragf(_("Time exhausted while searching for a solution (you can select \"Next Solution\" or press %s to try harder)."),
- global_bindings.readable_keyname("NextSolution").c_str()));
+ set_fragment(fragf("%s", _("Resolving dependencies...")));
+ return;
}
+
+ aptitude_solution sol = resman->get_solution(state.selected_solution);
+
+ if(sol == last_sol)
+ return;
+
+ last_sol=sol;
+
+ if(sol.get_actions().empty())
+ set_fragment(fragf("%s", _("Internal error: unexpected null solution.")));
+ else
+ set_fragment(solution_fragment(sol));
}
};
Modified: branches/aptitude-0.3/aptitude/src/solution_screen.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/solution_screen.cc (original)
+++ branches/aptitude-0.3/aptitude/src/solution_screen.cc Mon Sep 19 20:36:15 2005
@@ -765,10 +765,7 @@
void attach_apt_cache_signals()
{
if(apt_cache_file)
- {
- (*apt_cache_file)->package_state_changed.connect(sigc::mem_fun(*this, &solution_screen::update));
- resman->selected_solution_changed.connect(sigc::mem_fun(*this, &solution_screen::update));
- }
+ resman->state_changed.connect(sigc::mem_fun(*this, &solution_screen::update));
}
/** Re-connects the signals attached to the apt cache file. */
@@ -832,31 +829,35 @@
return;
}
- try
- {
- aptitude_solution sol = resman->get_current_solution();
-
- if(sol == last_sol)
- return;
+ resolver_manager::state state = resman->state_snapshot();
- last_sol = sol;
-
- if(sol.get_actions().empty())
- set_static_root(transcode(_("Internal error: unexpected null solution.")));
- else
- {
- solution_tree->set_root(make_solution_tree(sol));
- story_tree->set_root(make_story_tree(sol));
- }
- }
- catch(NoMoreSolutions)
+ if(state.solutions_exhausted && state.generated_solutions == 0)
{
set_static_root(transcode(_("No resolution found.")));
+ last_sol.nullify();
+ return;
+ }
+
+ if(state.selected_solution >= state.generated_solutions)
+ {
+ set_static_root(transcode(_("Resolving dependencies...")));
+ last_sol.nullify();
+ return;
}
- catch(NoMoreTime)
+
+ aptitude_solution sol = resman->get_solution(state.selected_solution);
+
+ if(sol == last_sol)
+ return;
+
+ last_sol = sol;
+
+ if(sol.get_actions().empty())
+ set_static_root(transcode(_("Internal error: unexpected null solution.")));
+ else
{
- set_static_root(transcode(ssprintf(_("Time exhausted while searching for a solution (you can select \"Next Solution\" or press %ls to try harder)."),
- global_bindings.readable_keyname("NextSolution").c_str())));
+ solution_tree->set_root(make_solution_tree(sol));
+ story_tree->set_root(make_story_tree(sol));
}
}
};
Modified: branches/aptitude-0.3/aptitude/src/ui.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/ui.cc (original)
+++ branches/aptitude-0.3/aptitude/src/ui.cc Mon Sep 19 20:36:15 2005
@@ -1042,6 +1042,7 @@
popup_widget(w, true);
}
+// FIXME: blocks.
static void auto_fix_broken()
{
undo_group *undo=new apt_undo_group;
@@ -1051,7 +1052,7 @@
assert(resman != NULL);
assert(resman->resolver_exists());
- aptitude_solution sol = resman->get_current_solution();
+ aptitude_solution sol = resman->get_solution(resman->get_selected_solution());
(*apt_cache_file)->apply_solution(sol, undo);
show_message(fragf("%s%n%n%F",
@@ -1426,33 +1427,129 @@
}
#endif
+static void start_solution_calculation();
+
+class interactive_continuation : public resolver_manager::background_continuation
+{
+ /** The manager associated with this continuation; usually resman. */
+ resolver_manager *manager;
+
+ /** Indicate that a new solution is available by invoking the
+ * selection_changed signal.
+ */
+ class success_event : public vscreen_event
+ {
+ resolver_manager *manager;
+ public:
+ success_event(resolver_manager *_manager)
+ :manager(_manager)
+ {
+ }
+
+ void dispatch()
+ {
+ manager->state_changed();
+ }
+ };
+
+ class no_more_time_event : public vscreen_event
+ {
+ resolver_manager *manager;
+ public:
+ no_more_time_event(resolver_manager *_manager)
+ :manager(_manager)
+ {
+ }
+
+ void dispatch()
+ {
+ start_solution_calculation();
+ }
+ };
+
+ class no_more_solutions_event : public vscreen_event
+ {
+ resolver_manager *manager;
+ public:
+ no_more_solutions_event(resolver_manager *_manager)
+ :manager(_manager)
+ {
+ }
+
+ void dispatch()
+ {
+ resolver_manager::state st = manager->state_snapshot();
+
+ if(st.selected_solution == st.generated_solutions)
+ manager->select_previous_solution();
+ show_message(_("No more solutions."));
+ }
+ };
+public:
+ interactive_continuation(resolver_manager *_manager)
+ :manager(_manager)
+ {
+ }
+
+ void success(const aptitude_solution &sol)
+ {
+ vscreen_post_event(new success_event(manager));
+ }
+
+ void no_more_solutions()
+ {
+ vscreen_post_event(new no_more_solutions_event(manager));
+ }
+
+ void no_more_time()
+ {
+ vscreen_post_event(new no_more_time_event(manager));
+ }
+
+ void interrupted()
+ {
+ }
+};
+
+// If the current solution pointer is past the end of the solution
+// list, queue up a calculation for it in the background thread.
+static void start_solution_calculation()
+{
+ resolver_manager::state state = resman->state_snapshot();
+
+ if(state.resolver_exists &&
+ state.selected_solution == state.generated_solutions &&
+ !state.background_thread_active)
+ resman->get_solution_background(resman->get_selected_solution(),
+ new interactive_continuation(resman));
+}
+
+static void do_connect_resolver_callback()
+{
+ resman->state_changed.connect(sigc::ptr_fun(&start_solution_calculation));
+}
+
void do_next_solution()
{
- if(apt_cache_file && !resman->solutions_exhausted())
- try
- {
- resman->next_solution();
- }
- catch(NoMoreSolutions)
- {
- /** \todo this message is bad */
- show_message(_("All solutions exhausted."));
- }
- catch(NoMoreTime)
- {
- /** \todo this message is bad */
- show_message(_("Ran out of time while trying to find a solution."));
- }
- else
+ resolver_manager::state state = resman->state_snapshot();
+
+ if(resman == NULL ||
+ state.selected_solution >= state.generated_solutions ||
+ (state.selected_solution == state.generated_solutions - 1 &&
+ state.solutions_exhausted))
beep();
+ else
+ resman->select_next_solution();
}
void do_previous_solution()
{
- if(apt_cache_file && !resman->solutions_at_start())
- resman->previous_solution();
- else
+ resolver_manager::state state = resman->state_snapshot();
+
+ if(resman == NULL || state.selected_solution == 0)
beep();
+ else
+ resman->select_previous_solution();
}
void do_apply_solution()
@@ -1462,7 +1559,7 @@
undo_group *undo=new apt_undo_group;
try
{
- (*apt_cache_file)->apply_solution(resman->get_current_solution(),
+ (*apt_cache_file)->apply_solution(resman->get_solution(resman->get_selected_solution()),
undo);
}
catch(NoMoreSolutions)
@@ -1492,6 +1589,9 @@
void do_examine_solution()
{
+ if(resman == NULL || !resman->resolver_exists())
+ return;
+
static vs_widget_ref solver;
if(solver.valid())
@@ -1885,6 +1985,12 @@
cache_closed.connect(sigc::ptr_fun(do_show_reload_message));
cache_reloaded.connect(sigc::ptr_fun(do_hide_reload_message));
+ cache_reloaded.connect(sigc::ptr_fun(do_connect_resolver_callback));
+ if(apt_cache_file)
+ {
+ do_connect_resolver_callback();
+ start_solution_calculation();
+ }
cache_reload_failed.connect(sigc::ptr_fun(do_hide_reload_message));
add_menu(actions_menu, _("Actions"), menu_description);
More information about the Aptitude-svn-commit
mailing list