diff options
-rw-r--r-- | src/generic/util/dynamic_set_transform.h | 4 | ||||
-rw-r--r-- | src/gtk/Makefile.am | 6 | ||||
-rw-r--r-- | src/gtk/SConscript | 6 | ||||
-rw-r--r-- | src/gtk/aptitude.glade | 456 | ||||
-rw-r--r-- | src/gtk/globals.cc | 176 | ||||
-rw-r--r-- | src/gtk/globals.h | 108 | ||||
-rw-r--r-- | src/gtk/init.cc | 178 | ||||
-rw-r--r-- | src/gtk/init.h | 33 | ||||
-rw-r--r-- | src/gtk/mainwindow.cc | 2 | ||||
-rw-r--r-- | src/gtk/mainwindow.h | 4 | ||||
-rw-r--r-- | src/gtk/post_event.cc | 124 | ||||
-rw-r--r-- | src/gtk/post_event.h | 55 | ||||
-rw-r--r-- | src/loggers.cc | 5 | ||||
-rw-r--r-- | src/loggers.h | 6 | ||||
-rw-r--r-- | src/main.cc | 17 |
15 files changed, 1174 insertions, 6 deletions
diff --git a/src/generic/util/dynamic_set_transform.h b/src/generic/util/dynamic_set_transform.h index 148f4cf7..19211fc9 100644 --- a/src/generic/util/dynamic_set_transform.h +++ b/src/generic/util/dynamic_set_transform.h @@ -47,8 +47,8 @@ namespace aptitude boost::shared_ptr<dynamic_set<From> > wrapped_set; boost::function<To (From)> f; - sigc::signal<To> signal_inserted; - sigc::signal<To> signal_removed; + sigc::signal<void, To> signal_inserted; + sigc::signal<void, To> signal_removed; void handle_inserted(const From &from); void handle_removed(const From &from); diff --git a/src/gtk/Makefile.am b/src/gtk/Makefile.am index 99ca5e46..02102fbe 100644 --- a/src/gtk/Makefile.am +++ b/src/gtk/Makefile.am @@ -30,12 +30,16 @@ libgtk_a_SOURCES=\ errortab.h \ filesview.cc \ filesview.h \ + globals.cc \ + globals.h \ gui.cc \ gui.h \ hyperlink.cc \ hyperlink.h \ info.cc \ info.h \ + init.cc \ + init.h \ mainwindow.cc \ mainwindow.h \ notify.cc \ @@ -46,6 +50,8 @@ libgtk_a_SOURCES=\ packagestab.h \ pkgview.cc \ pkgview.h \ + post_event.cc \ + post_event.h \ previewtab.cc \ previewtab.h \ progress.cc \ diff --git a/src/gtk/SConscript b/src/gtk/SConscript index fc3fec87..e1451680 100644 --- a/src/gtk/SConscript +++ b/src/gtk/SConscript @@ -20,12 +20,16 @@ toplevel_srcs = map(File, [ 'errortab.h', 'filesview.cc', 'filesview.h', + 'globals.cc', + 'globals.h', 'gui.cc', 'gui.h', 'hyperlink.cc', 'hyperlink.h', 'info.cc', 'info.h', + 'init.cc', + 'init.h', 'mainwindow.cc', 'mainwindow.h', 'notify.cc', @@ -36,6 +40,8 @@ toplevel_srcs = map(File, [ 'packagestab.h', 'pkgview.cc', 'pkgview.h', + 'post_event.cc', + 'post_event.h', 'previewtab.cc', 'previewtab.h', 'progress.cc', diff --git a/src/gtk/aptitude.glade b/src/gtk/aptitude.glade index 6a20f613..e3ad0e31 100644 --- a/src/gtk/aptitude.glade +++ b/src/gtk/aptitude.glade @@ -2256,4 +2256,460 @@ You can also modify the files by hand, then click "No".</property> </widget> </child> </widget> + <widget class="GtkWindow" id="main_window_2"> + <property name="title" translatable="yes">Aptitude Package Manager</property> + <property name="default_width">800</property> + <property name="default_height">600</property> + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <widget class="GtkMenuBar" id="main_menubar"> + <property name="visible">True</property> + <child> + <widget class="GtkMenuItem" id="menuitem1"> + <property name="visible">True</property> + <property name="label" translatable="yes">_File</property> + <property name="use_underline">True</property> + <child> + <widget class="GtkMenu" id="menu1"> + <property name="visible">True</property> + <child> + <widget class="GtkImageMenuItem" id="menu_do_package_run"> + <property name="label">_Install/Remove Packages</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Perform all pending installs and removals</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <accelerator key="G" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_do_update_lists"> + <property name="label">_Update Package List</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Check for new versions of packages</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <accelerator key="U" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + <child> + <widget class="GtkSeparatorMenuItem" id="separatormenuitem1"> + <property name="visible">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_do_mark_upgradable"> + <property name="label">Mark Up_gradable</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Mark all upgradable packages which are not held for upgrade</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <accelerator key="U" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_do_forget_new"> + <property name="label">_Forget New Packages</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Forget which packages are "new"</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_do_keep_all"> + <property name="label">Canc_el Pending Actions</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Cancel all pending installations, removals, holds, and upgrades.</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_do_clean"> + <property name="label">C_lean Package Cache</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Delete package files which were previously downloaded</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_do_autoclean"> + <property name="label">Clean _Obsolete Files</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Delete package files which can no longer be downloaded</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkSeparatorMenuItem" id="separatormenuitem2"> + <property name="visible">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_do_reload_cache"> + <property name="label">_Reload Package Cache</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Reload the package cache</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_do_sweep"> + <property name="label">_Play Minesweeper</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Waste time trying to find mines</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkSeparatorMenuItem" id="separatormenuitem3"> + <property name="visible">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_do_su_to_root"> + <property name="label">_Become Root</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Run 'su' to become root; this will restart the program, but your settings will be preserved</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_do_quit"> + <property name="label">_Quit</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Exit the program</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="menuitem2"> + <property name="visible">True</property> + <property name="label" translatable="yes">E_dit</property> + <property name="use_underline">True</property> + <child> + <widget class="GtkMenu" id="menu2"> + <property name="visible">True</property> + <child> + <widget class="GtkImageMenuItem" id="menu_undo_undo"> + <property name="label">gtk-undo</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Undo the last package operation or group of operations</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkSeparatorMenuItem" id="separatormenuitem4"> + <property name="visible">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="imagemenuitem6"> + <property name="label">gtk-cut</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="imagemenuitem7"> + <property name="label">gtk-copy</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="imagemenuitem8"> + <property name="label">gtk-paste</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="imagemenuitem9"> + <property name="label">gtk-delete</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="menuitem5"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Package</property> + <property name="use_underline">True</property> + <child> + <widget class="GtkMenu" id="menu_package"> + <property name="visible">True</property> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="menuitem3"> + <property name="visible">True</property> + <property name="label" translatable="yes">_View</property> + <property name="use_underline">True</property> + <child> + <widget class="GtkMenu" id="menu5"> + <property name="visible">True</property> + <child> + <widget class="GtkImageMenuItem" id="menu_view_edit_columns"> + <property name="label">_Edit Columns...</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Change which columns are visible in the currently active view.</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkSeparatorMenuItem" id="separatormenuitem5"> + <property name="visible">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_view_apt_errors"> + <property name="label">View Apt _Errors</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">View errors that have occurred in the apt system since the program was started.</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_item_find_dependency_paths"> + <property name="label">Find _Dependency Chains</property> + <property name="visible">True</property> + <property name="has_tooltip">True</property> + <property name="tooltip" translatable="yes">Find chains of dependencies linking one package to another.</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + <child> + <widget class="GtkSeparatorMenuItem" id="separatormenuitem6"> + <property name="visible">True</property> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_tab_previous"> + <property name="label">gtk-go-back</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <accelerator key="F6" signal="activate"/> + <accelerator key="Page_Up" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_tab_next"> + <property name="label">gtk-go-forward</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <accelerator key="F7" signal="activate"/> + <accelerator key="Page_Down" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_tab_close"> + <property name="label">gtk-close</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <accelerator key="Q" signal="activate" modifiers="GDK_CONTROL_MASK"/> + <accelerator key="W" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="Help"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Help</property> + <property name="use_underline">True</property> + <child> + <widget class="GtkMenu" id="menu7"> + <property name="visible">True</property> + <child> + <widget class="GtkImageMenuItem" id="imagemenuitem10"> + <property name="label">gtk-about</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkToolbar" id="main_toolbar"> + <property name="visible">True</property> + <child> + <widget class="GtkToolButton" id="main_toolbutton_dashboard"> + <property name="visible">True</property> + <property name="label" translatable="yes">Dashboard</property> + <property name="stock_id">gtk-home</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <widget class="GtkSeparatorToolItem" id="toolbutton1"> + <property name="visible">True</property> + </widget> + <packing> + <property name="expand">False</property> + </packing> + </child> + <child> + <widget class="GtkToolButton" id="main_toolbutton_update"> + <property name="visible">True</property> + <property name="label" translatable="yes">Update</property> + <property name="stock_id">gtk-refresh</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <widget class="GtkToolButton" id="main_toolbutton_packages"> + <property name="visible">True</property> + <property name="label" translatable="yes">Packages</property> + <property name="stock_id">gtk-new</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <widget class="GtkToolButton" id="main_toolbutton_preview"> + <property name="visible">True</property> + <property name="label" translatable="yes">Preview</property> + <property name="stock_id">gtk-print-preview</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <widget class="GtkToolButton" id="main_toolbutton_resolver"> + <property name="visible">True</property> + <property name="label" translatable="yes">Resolver</property> + <property name="stock_id">gtk-dialog-info</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <widget class="GtkToolButton" id="main_toolbutton_installremove"> + <property name="visible">True</property> + <property name="label" translatable="yes">Install/Remove</property> + <property name="stock_id">gtk-apply</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <widget class="GtkAlignment" id="main_bin"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="position">2</property> + </packing> + </child> + <child> + <widget class="GtkHBox" id="hbox3"> + <property name="visible">True</property> + <property name="spacing">12</property> + <child> + <widget class="GtkProgressBar" id="main_progressbar"> + <property name="width_request">250</property> + <property name="visible">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkStatusbar" id="main_statusbar"> + <property name="visible">True</property> + <property name="spacing">2</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">3</property> + </packing> + </child> + </widget> + </child> + </widget> </glade-interface> diff --git a/src/gtk/globals.cc b/src/gtk/globals.cc new file mode 100644 index 00000000..ab215c25 --- /dev/null +++ b/src/gtk/globals.cc @@ -0,0 +1,176 @@ +/** \file globals.cc */ + + +// Copyright (C) 2010 Daniel Burrows +// Copyright 2008-2009 Obey Arthur Liu +// +// 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 "globals.h" + +#include <loggers.h> + +#include <boost/make_shared.hpp> +#include <boost/ref.hpp> +#include <boost/shared_ptr.hpp> + +#include <glibmm/init.h> +#include <gtkmm/main.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +using aptitude::Loggers; + +namespace gui +{ + namespace globals + { + // The globals that have to be shared between several routines. + namespace + { + boost::shared_ptr<Gtk::Main> main_loop; + bool download_active; + } + + Glib::RefPtr<Gnome::Glade::Xml> load_glade(const std::string &argv0) + { + // The global filename: + static std::string glade_filename; + + if(!glade_filename.empty()) + { + try + { + return Gnome::Glade::Xml::create(glade_filename); + } + catch(Gnome::Glade::XmlError &err) + { + LOG_ERROR(Loggers::getAptitudeGtkGlobals(), + "Can't load " << glade_filename << ": " << err.what()); + // Try to find the glade file again anyway. + } + } + + Glib::RefPtr<Gnome::Glade::Xml> rval; + +#ifndef DISABLE_PRIVATE_GLADE_FILE + if(!argv0.empty()) + { + // Use the basename of argv0 to find the Glade file. + std::string argv0_path; + std::string::size_type last_slash = argv0.rfind('/'); + if(last_slash != std::string::npos) + { + while(last_slash > 0 && argv0[last_slash - 1] == '/') + --last_slash; + argv0_path = std::string(argv0, 0, last_slash); + } + else + argv0_path = '.'; + + //Loading the .glade file and widgets + const std::string glade_main_file = argv0_path + "/gtk/aptitude.glade"; + try + { + rval = Gnome::Glade::Xml::create(glade_main_file); + } + catch(Gnome::Glade::XmlError &err) + { + LOG_DEBUG(Loggers::getAptitudeGtkGlobals(), + "Can't load " << glade_main_file << ": " << err.what()); + } + } +#endif + + if(!rval) + { + const std::string glade_main_file = + std::string(PKGDATADIR) + "/aptitude.glade"; + + try + { + rval = Gnome::Glade::Xml::create(glade_main_file); + } + catch(Gnome::Glade::XmlError &err) + { + LOG_ERROR(Loggers::getAptitudeGtkGlobals(), + "Can't load " << glade_main_file << ": " << err.what()); + } + } + + if(rval) + { + LOG_INFO(Loggers::getAptitudeGtkGlobals(), + "UI definition loaded from " << glade_filename); + glade_filename = rval->get_filename(); + } + + return rval; + } + + Glib::RefPtr<Gnome::Glade::Xml> load_glade() + { + return load_glade(std::string()); + } + + void init_main_loop(int argc, char *argv[]) + { + main_loop = boost::make_shared<Gtk::Main>(boost::ref(argc), + boost::ref(argv)); + } + + void main_quit() + { + if(main_loop.get() != NULL) + { + LOG_TRACE(Loggers::getAptitudeGtkGlobals(), + "Telling the main loop to quit."); + + main_loop->quit(); + } + else + LOG_ERROR(Loggers::getAptitudeGtkGlobals(), + "main_quit() invoked with no main loop."); + } + + void run_main_loop() + { + LOG_TRACE(Loggers::getAptitudeGtkGlobals(), + "Entering main loop."); + + Gtk::Main::run(); + } + + bool is_a_download_active() + { + return download_active; + } + + void set_is_a_download_active(bool value) + { + if(value == download_active) + // Something wants to start a download when one is already + // running, or stop when one isn't running. + LOG_ERROR(Loggers::getAptitudeGtkGlobals(), + "Attempt to set the download_active flag to its current value (" + << download_active << ")."); + else + download_active = value; + } + } +} diff --git a/src/gtk/globals.h b/src/gtk/globals.h new file mode 100644 index 00000000..aaa98990 --- /dev/null +++ b/src/gtk/globals.h @@ -0,0 +1,108 @@ +/** \file globals.h */ // -*-c++-*- + +// Copyright (C) 2010 Daniel Burrows +// Copyright 2008-2009 Obey Arthur Liu +// +// 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. + +#ifndef APTITUDE_GTK_GLOBALS_H +#define APTITUDE_GTK_GLOBALS_H + +#include <libglademm/xml.h> + +#include <string> + +namespace gui +{ + /** \brief All the global variables used by the GTK+ gui go in this + * namespace. + * + * Please justify why each one needs to be global. If possible, + * define accessor functions instead of directly exposing the + * variables. + */ + namespace globals + { + /** \brief Find and load aptitude's glade file. + * + * The first time this is called, it saves the file name that + * worked (if one did) so it will be returned by future calls to + * get_glade_filename(). Each subsequent time, the same glade + * file is reloaded. + * + * This is global because all parts of aptitude should use the + * same glade file; it encapsulates the logic necessary to deal + * with that. + * + * \param argv0 The first entry in argv; used to try to find + * a local glade file relative to the aptitude + * executable. + * + * \return the newly loaded file, or a \b NULL pointer if the + * glade file couldn't be found. + */ + Glib::RefPtr<Gnome::Glade::Xml> load_glade(const std::string &argv0); + + /** \brief Find and load aptitude's previously loaded glade file. + * + * This routine will fail if load_glade(const std::string &) was + * not previously called. + */ + Glib::RefPtr<Gnome::Glade::Xml> load_glade(); + + /** \brief Ensure that the main loop is created. + * + * Global because aptitude has only one main loop. + * + * \param argc The number of command-line arguments. + * \param argv The array of command-line arguments. + */ + void init_main_loop(int argc, char *argv[]); + + /** \brief Exit the main loop (and thus the program). + * + * Global because aptitude has only one main loop. + */ + void main_quit(); + + /** \brief Run the main loop. + * + * Should only be invoked from the initialization code. + * + * Global because aptitude has only one main loop. + */ + void run_main_loop(); + + /** \brief Check whether a download is currently active. + * + * Used to ensure that only one download runs at once; global + * because downloads should be mutually exclusive across the + * entire program. + */ + bool is_a_download_active(); + + /** \brief Set the flag that indicates that a download is active. + * + * Global for the same reason that is_a_download_active is + * global. + * + * \param value The new value of the flag. + */ + void set_is_a_download_active(bool value); + } +} + +#endif // APTITUDE_GTK_GLOBALS_H diff --git a/src/gtk/init.cc b/src/gtk/init.cc new file mode 100644 index 00000000..b878fe18 --- /dev/null +++ b/src/gtk/init.cc @@ -0,0 +1,178 @@ +/** \file init.cc */ + +// Copyright (C) 2010 Daniel Burrows +// Copyright 2008-2009 Obey Arthur Liu +// +// 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 "init.h" + +#include "globals.h" +#include "mainwindow.h" +#include "post_event.h" +#include "resolver.h" + +#include <apt-pkg/error.h> + +#include <boost/lambda/construct.hpp> +#include <boost/lambda/lambda.hpp> + +#include <generic/apt/config_signal.h> + +#include <generic/util/dynamic_set_transform.h> +#include <generic/util/dynamic_set_union.h> + +#include <gtk/toplevel/model.h> +#include <gtk/toplevel/tabs_notebook.h> +#include <gtk/toplevel/view.h> + +using aptitude::util::dynamic_set; +using aptitude::util::dynamic_set_transform; +using aptitude::util::dynamic_set_union; +using aptitude::util::enumerator; +using boost::lambda::_1; +using boost::lambda::constructor; +using boost::shared_ptr; +using gui::toplevel::area_info; +using gui::toplevel::area_list; +using gui::toplevel::create_area_list; +using gui::toplevel::tab_display_info; +using gui::toplevel::tab_info; +using gui::toplevel::view; + +// Contains startup code for the GTK+ GUI. Would be called "main", +// but that leads to ugly namespace conflicts. + +namespace gui +{ + namespace + { + void init_style(void) + { + Gtk::RC::parse_string ( + "style \"tiny-button-style\"" + "{" + " GtkWidget::focus-padding = 0" + " xthickness = 0" + " ythickness = 0" + "}" + "widget \"*.notebook_close_button\" style \"tiny-button-style\""); + } + + shared_ptr<area_list> init_areas() + { + std::vector<shared_ptr<area_info> > areas; + return create_area_list(areas); + } + + shared_ptr<view> create_main_view(const shared_ptr<area_list> &areas) + { + shared_ptr<dynamic_set_union<shared_ptr<tab_info> > > all_tabs_set = + dynamic_set_union<shared_ptr<tab_info> >::create(); + + for(shared_ptr<enumerator<shared_ptr<area_info> > > e = areas->get_areas(); + e->advance(); ) + all_tabs_set->insert_set(e->get_current()->get_tabs()); + + + typedef dynamic_set_transform<shared_ptr<tab_info>, + shared_ptr<tab_display_info> > upcast_set; + shared_ptr<dynamic_set<shared_ptr<tab_display_info> > > all_tabs_view_set = + upcast_set::create(all_tabs_set, + constructor<boost::shared_ptr<tab_display_info> >()); + + // Use a notebook containing all the tabs in all areas for the + // time being. + // + // Eventually a better main view will be used. + return create_tabs_notebook(all_tabs_view_set); + } + + void do_apt_init() + { + // \todo Display progress somehow (maybe using the notification + // framework?) + OpProgress p; + apt_init(&p, true, NULL); + + // \todo Support update-on-startup once updating is plumbed + // through. + // + //if(getuid() == 0 && aptcfg->FindB(PACKAGE "::Update-On-Startup", true)) + //do_update(); + } + } + + bool init(int argc, char **argv) + { + // Don't crash if a subprocess breaks a pipe. + signal(SIGPIPE, SIG_IGN); + + // GTK+ provides a perfectly good routine, gtk_init_check(), to + // initialize GTK+ *and report whether the initialization + // succeeded*. gtkmm doesn't wrap it. But initializing GTK+ + // twice won't hurt, so we do that. + if(!gtk_init_check(&argc, &argv)) + return false; + + Glib::init(); + // If we don't check thread_supported() first, thread_init() + // aborts with an error on some architectures. (see Debian bug + // #555120) + if(!Glib::thread_supported()) + Glib::thread_init(); + + globals::init_post_event(); + + // We have to create the main loop object before loading the Glade + // file, or Glade goes and pouts in a corner and refuses to do + // anything. + globals::init_main_loop(argc, argv); + + Glib::RefPtr<Gnome::Glade::Xml> glade = globals::load_glade(argv[0]); + + if(!glade) + { + _error->Error(_("Unable to load the user interface definition file %s/aptitude.glade."), + PKGDATADIR); + + return false; + } + + // Set up the style for GTK+ widgets. + init_style(); + + // Set up the resolver-triggering signals. + init_resolver(); + + // Postpone apt_init until we enter the main loop, so we get a GUI + // progress bar. + Glib::signal_idle().connect(sigc::bind_return(sigc::ptr_fun(&do_apt_init), + false)); + + shared_ptr<area_list> areas = init_areas(); + + shared_ptr<view> main_win_view = create_main_view(areas); + Gtk::Window *main = create_mainwindow(glade, main_win_view); + main->signal_unmap().connect(sigc::ptr_fun(&globals::main_quit)); + main->show(); + + // Run the main loop, exiting when main_win is closed: + globals::run_main_loop(); + + return true; + } +} diff --git a/src/gtk/init.h b/src/gtk/init.h new file mode 100644 index 00000000..58320a28 --- /dev/null +++ b/src/gtk/init.h @@ -0,0 +1,33 @@ +/** \file init.h */ // -*-c++-*- + +// Copyright 1999-2010 Daniel Burrows +// Copyright 2008-2009 Obey Arthur Liu +// +// 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. + +#ifndef APTITUDE_GTK_INIT_H +#define APTITUDE_GTK_INIT_H + +namespace gui +{ + /** \brief Run the GUI frontend to aptitude. + * + * \return \b true if the GUI was able to start at all. + */ + bool init(int argc, char **argv); +} + +#endif // APTITUDE_GTK_INIT_H diff --git a/src/gtk/mainwindow.cc b/src/gtk/mainwindow.cc index a3a2b6c3..25ff3a6e 100644 --- a/src/gtk/mainwindow.cc +++ b/src/gtk/mainwindow.cc @@ -68,7 +68,7 @@ namespace gui const boost::shared_ptr<toplevel::view> &view) { main_window *rval; - glade->get_widget_derived("main_window", rval); + glade->get_widget_derived("main_window_2", rval); rval->set_view(view); return rval; diff --git a/src/gtk/mainwindow.h b/src/gtk/mainwindow.h index 18fb186f..3fa9342c 100644 --- a/src/gtk/mainwindow.h +++ b/src/gtk/mainwindow.h @@ -22,8 +22,8 @@ #include <boost/shared_ptr.hpp> -#include <gtkmm.h> -#include <libglademm.h> +#include <gtkmm/window.h> +#include <libglademm/xml.h> namespace gui { diff --git a/src/gtk/post_event.cc b/src/gtk/post_event.cc new file mode 100644 index 00000000..09bac14a --- /dev/null +++ b/src/gtk/post_event.cc @@ -0,0 +1,124 @@ +/** \file post_event.cc */ + +// Copyright (C) 2010 Daniel Burrows +// Copyright 2008-2009 Obey Arthur Liu +// +// 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 "post_event.h" + +#include <cwidget/generic/threads/threads.h> + +#include <glibmm/dispatcher.h> + +#include <deque> + +namespace gui +{ + namespace globals + { + namespace + { + // Code related to injecting events into the main loop: + + // The Glib::dispatch mechanism only allows us to wake the main + // thread up; it doesn't allow us to pass actual information + // across the channel. To hack this together, I borrow the + // event_queue abstraction from cwidget, and use a dispatcher + // for the sole purpose of waking the main thread up. + // + // I believe that putting sigc++ slots on this list should be + // OK: from the sigc++ code, it looks like they get passed by + // value, not by reference. Once the slot is safely stuck into + // the list, everything should be OK. + + cwidget::threads::mutex background_events_mutex; + // Set to "true" if the background events function is currently + // executing a thunk, in which case we don't need to invoke the + // dispatcher. This avoids trouble caused by the thunk invoking + // post_event() and filling up the queue, so it deadlocks + // itself. + bool run_background_events_active = false; + bool background_events_dispatcher_signalled = false; + std::deque<safe_slot0<void> > background_events; + Glib::Dispatcher background_events_dispatcher; + + // Used to ensure that run_background_events_active is true only + // while the inner portion of the "while" loop below is running. + class set_bool_in_scope + { + bool ⌖ + + public: + set_bool_in_scope(bool &_target) + : target(_target) + { + target = true; + } + + ~set_bool_in_scope() + { + target = false; + } + }; + + void run_background_events() + { + cwidget::threads::mutex::lock l(background_events_mutex); + while(!background_events.empty()) + { + set_bool_in_scope setter(run_background_events_active); + safe_slot0<void> f = background_events.front(); + background_events.pop_front(); + + l.release(); + f.get_slot()(); + l.acquire(); + } + background_events_dispatcher_signalled = false; + } + } + + // Interface routines to the background event code. + void post_event(const safe_slot0<void> &event) + { + // Ensure that the dispatcher is only invoked once. + cwidget::threads::mutex::lock l(background_events_mutex); + background_events.push_back(event); + if(!run_background_events_active && !background_events_dispatcher_signalled) + { + background_events_dispatcher(); + background_events_dispatcher_signalled = true; + } + } + + void post_thunk(const sigc::slot<void> &thunk) + { + post_event(make_safe_slot(thunk)); + } + + void init_post_event() + { + // Defensive programming: ensure that there's only one + // connection even if we're called multiple times. + static sigc::connection background_events_connection; + + background_events_connection.disconnect(); + background_events_connection = + background_events_dispatcher.connect(sigc::ptr_fun(&run_background_events)); + } + } +} diff --git a/src/gtk/post_event.h b/src/gtk/post_event.h new file mode 100644 index 00000000..c2b666cb --- /dev/null +++ b/src/gtk/post_event.h @@ -0,0 +1,55 @@ +/** \file post_event.h */ // -*-c++-*- + +// Copyright (C) 2010 Daniel Burrows +// Copyright 2008-2009 Obey Arthur Liu +// +// 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. + +#ifndef POST_EVENT_H +#define POST_EVENT_H + +#include <generic/util/safe_slot.h> + +namespace gui +{ + namespace globals + { + // This code is not in globals.{cc,h] because it's more involved + // than the other stuff in that file. + + /** \brief Dispatch the given safe thunk to the main loop. + * + * Global because there is only one main loop and IT DOES NOT + * SHARE POWER^W^W^W^W^Wit has only one event queue. + */ + void post_event(const safe_slot0<void> &thunk); + + /** \brief Post an event to the main loop's event queue, + * thread-safely. + * + * Global because there is only one main loop and it has only one + * event queue. + */ + void post_thunk(const sigc::slot<void> &thunk); + + /** \brief Initialize support for post_thunk() and + * post_event(). + */ + void init_post_event(); + } +} + +#endif // POST_EVENT_H diff --git a/src/loggers.cc b/src/loggers.cc index 4c905e3a..fb102407 100644 --- a/src/loggers.cc +++ b/src/loggers.cc @@ -103,6 +103,11 @@ namespace aptitude return Logger::getLogger("aptitude.gtk.dashboard.upgrade.resolver"); } + LoggerPtr Loggers::getAptitudeGtkGlobals() + { + return Logger::getLogger("aptitude.gtk.globals"); + } + LoggerPtr Loggers::getAptitudeGtkMainWindow() { return Logger::getLogger("aptitude.gtk.mainwindow"); diff --git a/src/loggers.h b/src/loggers.h index a8724507..8ae07949 100644 --- a/src/loggers.h +++ b/src/loggers.h @@ -153,6 +153,12 @@ namespace aptitude */ static logging::LoggerPtr getAptitudeGtkChangelogParse(); + /** \brief The logger for the module of globals. + * + * Name: aptitude.gtk.globals + */ + static logging::LoggerPtr getAptitudeGtkGlobals(); + /** \brief The logger for the GTK+ main window. * * Name: aptitude.gtk.mainwindow diff --git a/src/main.cc b/src/main.cc index 8ce0cdfe..1f232db2 100644 --- a/src/main.cc +++ b/src/main.cc @@ -86,6 +86,7 @@ #ifdef HAVE_GTK #include "gtk/gui.h" +#include "gtk/init.h" #endif #include "loggers.h" @@ -259,6 +260,7 @@ enum { OPTION_CLEAN_ON_STARTUP, OPTION_GROUP_BY, OPTION_SHOW_PACKAGE_NAMES, + OPTION_NEW_GUI, }; int getopt_result; @@ -312,6 +314,7 @@ option opts[]={ {"clean-on-startup", 0, &getopt_result, OPTION_CLEAN_ON_STARTUP}, {"group-by", 1, &getopt_result, OPTION_GROUP_BY}, {"show-package-names", 1, &getopt_result, OPTION_SHOW_PACKAGE_NAMES}, + {"new-gui", 0, &getopt_result, OPTION_NEW_GUI}, {0,0,0,0} }; @@ -626,6 +629,8 @@ int main(int argc, char *argv[]) #ifdef HAVE_GTK // TODO: this should be a configuration option. bool gui = aptcfg->FindB(PACKAGE "::Start-Gui", true); + // Use the in-progress new GUI harness instead of the old code. + bool use_new_gui = false; #endif int curopt; @@ -905,6 +910,10 @@ int main(int argc, char *argv[]) show_package_names_mode_string = optarg; break; + case OPTION_NEW_GUI: + use_new_gui = true; + break; + default: fprintf(stderr, "%s", _("WEIRDNESS: unknown option code received\n")); @@ -914,6 +923,7 @@ int main(int argc, char *argv[]) getopt_result=0; break; + default: fprintf(stderr, "%s", _("WEIRDNESS: unknown option code received\n")); @@ -1182,7 +1192,12 @@ int main(int argc, char *argv[]) #ifdef HAVE_GTK if(gui) { - if(gui::main(argc, argv)) + if(use_new_gui) + { + if(gui::init(argc, argv)) + return 0; + } + else if(gui::main(argc, argv)) return 0; // Otherwise, fall back to trying to start a curses interface // (assume that we can't contact the X server, or maybe that we |