[PATCH 1/3] Add a help button to every Anaconda screen

Martin Kolman mkolman at redhat.com
Fri Aug 15 11:16:46 UTC 2014



----- Original Message -----
> From: "David Shea" <dshea at redhat.com>
> To: anaconda-patches at lists.fedorahosted.org
> Sent: Thursday, August 14, 2014 8:30:53 PM
> Subject: Re: [PATCH 1/3] Add a help button to every Anaconda screen
> 
> On 08/14/2014 07:01 AM, Martin Kolman wrote:
> > This makes context aware help possible for every Anaconda screen by
> > providing a help button in the upper right corner of the screen.
> > Clicking the button opens the yelp help viewer with either a help page
> > tailored for the given screen, the main page of the installation guide
> > (if no help is available for the screen) or a "no help found" placeholder
> > page.
> > The new helpFile GUIObject attribute is used to specify which help
> > file to show for the given screen. If no help file is specified
> > either the main page of the Installation Guide will be shown (if
> > available) or the placeholder page will be shown.
> >
> > Signed-off-by: Martin Kolman <mkolman at redhat.com>
> > ---
> >   anaconda.spec.in                     |  1 +
> >   data/HelpPlaceholder.html            |  5 ++
> >   data/HelpPlaceholderWithLinks.html   | 13 ++++++
> >   data/Makefile.am                     |  2 +
> >   pyanaconda/constants.py              |  6 +++
> >   pyanaconda/ihelp.py                  | 90
> >   ++++++++++++++++++++++++++++++++++++
> >   pyanaconda/ui/gui/__init__.py        | 12 +++++
> >   pyanaconda/ui/gui/spokes/__init__.py |  9 ++++
> >   widgets/glade/AnacondaWidgets.xml    |  5 ++
> >   widgets/src/BaseWindow.c             | 48 +++++++++++++++++++
> >   widgets/src/BaseWindow.h             |  3 ++
> >   11 files changed, 194 insertions(+)
> >   create mode 100644 data/HelpPlaceholder.html
> >   create mode 100644 data/HelpPlaceholderWithLinks.html
> >   create mode 100644 pyanaconda/ihelp.py
> >
> > diff --git a/anaconda.spec.in b/anaconda.spec.in
> > index e23d49c..1c6828f 100644
> > --- a/anaconda.spec.in
> > +++ b/anaconda.spec.in
> > @@ -174,6 +174,7 @@ Requires: zenity
> >   %endif
> >   Requires: keybinder3
> >   Requires: NetworkManager-wifi
> > +Requires: yelp
> >   
> >   %description gui
> >   This package contains graphical user interface for the Anaconda
> >   installer.
> > diff --git a/data/HelpPlaceholder.html b/data/HelpPlaceholder.html
> > new file mode 100644
> > index 0000000..4d1781a
> > --- /dev/null
> > +++ b/data/HelpPlaceholder.html
> > @@ -0,0 +1,5 @@
> > +<body>
> > +<h1>The Anaconda built-in help</h1>
> > +<p>...is not yet available for this screen.</p>
> > +<p>You can check the Anaconda wiki page, the Fedora Installation Guide or
> > other online help resources instead.</p>
> > +</body>
> > diff --git a/data/HelpPlaceholderWithLinks.html
> > b/data/HelpPlaceholderWithLinks.html
> > new file mode 100644
> > index 0000000..5fe0485
> > --- /dev/null
> > +++ b/data/HelpPlaceholderWithLinks.html
> > @@ -0,0 +1,13 @@
> > +<body>
> > +<h1>The Anaconda built-in help</h1>
> > +<p>...is not yet available for this screen.</p>
> > +<p>You can check the Anaconda wiki page, the Fedora Installation Guide or
> > other online help resources instead:</p>
> > +<p>
> > +<ul>
> > +    <li><a
> > href="http://docs.fedoraproject.org/en-US/Fedora/20/html/Installation_Guide/">Fedora
> > Installation Guide</a></li>
> > +    <li><a href="https://fedoraproject.org/wiki/Anaconda">Anaconda
> > Wiki</a></li>
> > +    <li><a
> > href="http://fedoraproject.org/wiki/Anaconda_Boot_Options">Anaconda Boot
> > Options</a></li>
> > +    <li><a
> > href="http://fedoraproject.org/wiki/Anaconda/Kickstart">Anaconda
> > Kickstart</a></li>
> > +</ul>
> > +</p>
> > +</body>
> > diff --git a/data/Makefile.am b/data/Makefile.am
> > index bcc6bf5..17926b3 100644
> > --- a/data/Makefile.am
> > +++ b/data/Makefile.am
> > @@ -26,6 +26,8 @@ dist_pkgdata_DATA          = interactive-defaults.ks \
> >   			     anaconda-gtk.css
> >   
> >   helpdir               = $(datadir)/$(PACKAGE_NAME)
> > +docsdir               = $(datadir)/docs/$(PACKAGE_NAME)
> >   dist_help_DATA        = anaconda_options.txt
> > +dist_docs_DATA        = HelpPlaceholder.html HelpPlaceholderWithLinks.html
> >   
> >   MAINTAINERCLEANFILES = Makefile.in
> Autotools already comes with docdir, just use dist_doc_DATA.
Nice, fixing locally! :)

> 
> I'd rather see these html files in either a subdirectory of data or a
> subdirectory of docs. Also, can you add this type of file to makeupdates?
> > diff --git a/pyanaconda/constants.py b/pyanaconda/constants.py
> > index 18c2a1f..5583162 100644
> > --- a/pyanaconda/constants.py
> > +++ b/pyanaconda/constants.py
> > @@ -161,3 +161,9 @@ DEFAULT_AUTOPART_TYPE = AUTOPART_TYPE_LVM
> >   
> >   import logging
> >   LOGLVL_LOCK = logging.DEBUG-1
> > +
> > +# help
> > +HELP_FOLDER = "/usr/share/doc/anaconda"
> > +HELP_MAIN_PAGE = "Installation_Guide.xml"
> > +HELP_PLACEHOLDER = "HelpPlaceholder.html"
> > +HELP_PLACEHOLDER_WITH_LINKS = "HelpPlaceholderWithLinks.html"
> > diff --git a/pyanaconda/ihelp.py b/pyanaconda/ihelp.py
> > new file mode 100644
> > index 0000000..dffd7d8
> > --- /dev/null
> > +++ b/pyanaconda/ihelp.py
> > @@ -0,0 +1,90 @@
> > +#
> > +# Copyright (C) 2014  Red Hat, Inc.
> > +#
> > +# This copyrighted material is made available to anyone wishing to use,
> > +# modify, copy, or redistribute it subject to the terms and conditions of
> > +# the GNU General Public License v.2, or (at your option) any later
> > version.
> > +# This program is distributed in the hope that it will be useful, but
> > WITHOUT
> > +# ANY WARRANTY expressed or implied, including the implied warranties of
> > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > General
> > +# Public License for more details.  You should have received a copy of the
> > +# GNU General Public License along with this program; if not, write to the
> > +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> > MA
> > +# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
> > +# source code or documentation are not subject to the GNU General Public
> > +# License and may only be used or replicated with the express permission
> > of
> > +# Red Hat, Inc.
> > +#
> > +# Red Hat Author(s): Martin Kolman <mkolman at redhat.com>
> > +#
> > +"""
> > +Anaconda built-in help module
> > +"""
> > +import os
> > +import subprocess
> > +
> > +from pyanaconda import constants
> > +from pyanaconda.flags import flags
> > +
> > +import logging
> > +log = logging.getLogger("anaconda")
> > +
> > +yelp_process = None
> > +
> > +def get_help_path(help_file):
> > +    """Return the full path for the given help file name,
> > +    if the help file path does not exist a fallback path is returned.
> > +    There are actually two possible fallback paths that might be returned:
> > +    * first we try to return path to the main page of the installation
> > guide
> > +      (if it exists)
> > +    * if we can't find the main page of the installation page, path to a
> > +      "no help found" placeholder bundled with Anaconda is returned
> > +
> > +    :param str help_file: help file name
> > +    :return str: full path to the help file requested or to a placeholder
> > +    """
> > +    # check if the screen has any helpFile defined
> > +    if help_file:
> > +        # check if the help file exists
> > +        help_path = os.path.join(constants.HELP_FOLDER, help_file)
> > +        if os.path.isfile(help_path):
> > +            return help_path
> > +        else:
> > +            log.debug("the %s help file has been requested, but is not
> > available", help_file)
> > +
> > +    # the screen did not have a helpFile defined or the defined help file
> > +    # does not exist, so next try to check if we can find the main page
> > +    # of the installation guide and use it instead
> > +    help_path = os.path.join(constants.HELP_FOLDER,
> > constants.HELP_MAIN_PAGE)
> > +    if os.path.exists(help_path):
> > +        return help_path
> > +
> > +    # looks like the installation guide is not available, so just return
> > +    # a placeholder page that should always be available
> > +    if flags.livecdInstall:
> > +        return os.path.join(constants.HELP_FOLDER,
> > constants.HELP_PLACEHOLDER_WITH_LINKS)
> > +    else:
> > +        return os.path.join(constants.HELP_FOLDER,
> > constants.HELP_PLACEHOLDER)
> > +
> > +def start_yelp(help_path):
> > +    """Start a new yelp process and make sure to kill any existing ones
> > +
> > +    :param str help_path: path to the help file yelp should load
> > +    """
> > +
> > +    kill_yelp()
> > +    log.debug("starting yelp")
> > +    global yelp_process
> > +    yelp_process = subprocess.Popen(["yelp", help_path])
> > +
> > +def kill_yelp():
> > +    """Try to kill any existing yelp processes"""
> > +
> > +    global yelp_process
> > +    if not yelp_process:
> > +        return False
> > +
> > +    log.debug("killing yelp")
> > +    yelp_process.kill()
> > +    yelp_process = None
> > +    return True
> 
> I'm not real keen on us starting and stopping a yelp process like this.
> In non-live installs it doesn't make sense to keep a help window around
> while the user is interacting with the installer, since switching back
> to the installer will just hide the help window, and even in live
> installs we discourage that kind of thing by starting in fullscreen by
> default. I think it would make more sense to have the help run in a
> dialog that is transient for our main anaconda window.
I thing a standard dialog (centered, unmovable & lightboxed) is not a good fit for the help
content. The installation guide that will be the base for the context help for the individual
spokes contains screenshots and describes the content & features of the given spoke.
The user should be able to see a reasonable part of the unobscured spoke next to the
documentation, which already kinda works with the current approach (the window can be moved and resized)
but would not be possible with the classical dialog. Especially on big/high resolution screens there should 
be enough space for the user to tuck the help window in a corner and study it together with the content of the screen.

Thinking about it, it might not be a bad combination to make the yelp window "stay on top" somehow
so that the user can use the given screen while simultaneously consulting the documentation.
The window would then be automaticaly closed on the user leaves the screen.

Also the yelp window has a number of controls, some of them directly usable to our use case:
* full-text search field
* back/forward buttons (the installation guide consists of interlinked pages)
* option to make text bigger/smaller
* window size control & maximize button
* close button
But there are also some options that are probably not of much use:
* the bookmarks button (unless we pre-populate it with some frequently asked stuff ?)
* print support
* option to open a new window
And there are some options that are really useless/confusing/harmful considering our current setup:
* minimize button (on install media considering we don't have a task switcher)

So I'm not really against using yelp as a library in our own dialog/window, but only if it does
not mean loosing the benefits of the current solution.

> 
> The problem with this idea is that, while yelp has a library that looks
> pretty ok and seems to be one of more well-gobjected ones I've seen out
> of the GNOME family, there are no introspection bindings. So I'll play
> around with that a little and see if I can find some people to complain
> at before going further with that idea.
Yeah I've looked at it a bit too but I was hardly able to find any reasonable docs on it - well or
even on the yelp application itself. 

Please also note that the context help is also targeted to the rhel7-branch,
where the old GTK 3.8 might complicate matters a bit.

Anyway, I would really like to go forward with the current implementation (running yelp as a process) for now
so that we can get feedback, test the documentation content, etc. Once we have an alternative implementation,
it can be swapped in fairly transparently (it will still basically just get a path to a file and display it).
> 
> > diff --git a/pyanaconda/ui/gui/__init__.py b/pyanaconda/ui/gui/__init__.py
> > index 3245d3e..7188aa6 100644
> > --- a/pyanaconda/ui/gui/__init__.py
> > +++ b/pyanaconda/ui/gui/__init__.py
> > @@ -30,6 +30,7 @@ from pyanaconda import product
> >   
> >   from pyanaconda.ui import UserInterface, common
> >   from pyanaconda.ui.gui.utils import gtk_action_wait, busyCursor,
> >   unbusyCursor
> > +from pyanaconda import ihelp
> >   import os.path
> >   
> >   import logging
> > @@ -80,6 +81,10 @@ class GUIObject(common.UIObject):
> >                              that use GUI elements (Hubs & Spokes) from
> >                              Anaconda
> >                              can override the translation domain with their
> >                              own,
> >                              so that their subclasses are properly
> >                              translated.
> > +       helpFile         -- The location of the yelp-compatible help file
> > for the
> > +                           given GUI object. The default value of ""
> > indicates
> > +                           that the object has not specific help file
> > assigned
> > +                           and the default help file should be used.
> >       """
> >       builderObjects = []
> >       mainWidgetName = None
> > @@ -90,6 +95,7 @@ class GUIObject(common.UIObject):
> >       focusWidgetName = None
> >   
> >       uiFile = ""
> > +    helpFile = ""
> >       translationDomain = "anaconda"
> >   
> >       screenshots_directory = "/tmp/anaconda-screenshots"
> 
> Could helpFile be inferred from the spoke class name? Based on what you
> have in patch 2, it looks like just another place to put the same string
> again.
I have been thinking about this, but basically the only place where we have a name
for a given screen (we need to take not only normal spokes but also hubs and standalone
spojkes into account) is either the class name or the glade file name. The first one would need hacks
like calling type(self).__name__ and the second one would mean tying help files to glade files 
and would be kinda against the installation guide file naming style. 
The glade file names are all lower case and short, while the installation guide is using longer descriptive camel-cased names.

Also I think tying the documentation file names directly to class names might not be the best
idea, as changing a class name in Anaconda would require a change in the documentation package
and there might also be cases where the mapping one-screen-one-help-file might not hold and we might
want either two screens pointing to the same help file (like the summary hub pointing to the top level
of the installation guide, new spoke pointing to generic docs until a specific page is written for it, etc.).

So in short I think having the help file name not depend on implementation details feels more clean,
is similar to how we handle glade files and should give us more flexibility when needed.

> 
> > @@ -535,6 +541,7 @@ class GraphicalUserInterface(UserInterface):
> >   
> >           # Use connect_after so classes can add actions before we change
> >           screens
> >           obj.window.connect_after("continue-clicked",
> >           self._on_continue_clicked)
> > +        obj.window.connect_after("help-button-clicked",
> > self._on_help_clicked, obj)
> >           obj.window.connect_after("quit-clicked", self._on_quit_clicked)
> >   
> >           return obj
> > @@ -696,6 +703,11 @@ class GraphicalUserInterface(UserInterface):
> >           self._currentAction = nextAction
> >           self._actions.pop(0)
> >   
> > +    def _on_help_clicked(self, window, obj):
> > +        # the help button has been clicked, start the yelp viewer with
> > +        # content for the current screen
> > +        ihelp.start_yelp(ihelp.get_help_path(obj.helpFile))
> > +
> >       def _on_quit_clicked(self, win, userData=None):
> >           if not win.get_quit_button():
> >               return
> > diff --git a/pyanaconda/ui/gui/spokes/__init__.py
> > b/pyanaconda/ui/gui/spokes/__init__.py
> > index 183dc6f..5fb2714 100644
> > --- a/pyanaconda/ui/gui/spokes/__init__.py
> > +++ b/pyanaconda/ui/gui/spokes/__init__.py
> > @@ -21,6 +21,7 @@
> >   
> >   from pyanaconda.ui import common
> >   from pyanaconda.ui.gui import GUIObject
> > +from pyanaconda import ihelp
> >   
> >   __all__ = ["StandaloneSpoke", "NormalSpoke"]
> >   
> > @@ -44,6 +45,14 @@ class NormalSpoke(GUIObject, common.NormalSpoke):
> >           GUIObject.__init__(self, data)
> >           common.NormalSpoke.__init__(self, storage, payload, instclass)
> >   
> > +        # Add a help handler
> > +        self.window.connect_after("help-button-clicked",
> > self._on_help_clicked)
> > +
> > +    def _on_help_clicked(self, window):
> > +        # the help button has been clicked, start the yelp viewer with
> > +        # content for the current spoke
> > +        ihelp.start_yelp(ihelp.get_help_path(self.helpFile))
> > +
> >       def on_back_clicked(self, window):
> >           # Notify the hub that we're finished.
> >           # The hub will be the current-action of the main window.
> > diff --git a/widgets/glade/AnacondaWidgets.xml
> > b/widgets/glade/AnacondaWidgets.xml
> > index 42c4194..782d360 100644
> > --- a/widgets/glade/AnacondaWidgets.xml
> > +++ b/widgets/glade/AnacondaWidgets.xml
> > @@ -25,6 +25,11 @@
> >                   <property id="distribution" translatable="True" />
> >                   <property id="window-name" translatable="True" />
> >               </properties>
> > +
> > +            <signals>
> > +              <signal since="4.0" id="help-button-clicked" />
> > +            </signals>
> > +
> >           </glade-widget-class>
> >   
> >           <glade-widget-class title="Standalone Spoke Window"
> 
> Regarding the widgets version, I think we should use 3.1, since for once
> we're not removing any functionality. You also need to change the
> version attribute in the top-level <glade-catalog> tag and add 3.0 to
> "targetable". You should also update the version number in the AC_INIT
> argument in widgets/configure.ac, and update the -version-info libtool
> argument in widgets/src/Makefile.am, which by my interpretation should
> now be 3:0:1. It doesn't look like anyone bothers with minor revisions
> in the .gir files so leave that alone, I guess.
Thanks, will do! :)

> 
> > diff --git a/widgets/src/BaseWindow.c b/widgets/src/BaseWindow.c
> > index 5b7f337..94dee1f 100644
> > --- a/widgets/src/BaseWindow.c
> > +++ b/widgets/src/BaseWindow.c
> > @@ -28,6 +28,8 @@
> >   #include "BaseWindow.h"
> >   #include "intl.h"
> >   
> > + #include <atk/atk.h>
> > +
> >   /**
> >    * SECTION: BaseWindow
> >    * @title: AnacondaBaseWindow
> > @@ -95,6 +97,7 @@
> >   
> >   enum {
> >       SIGNAL_INFO_BAR_CLICKED,
> > +    SIGNAL_HELP_BUTTON_CLICKED,
> >       LAST_SIGNAL
> >   };
> >   
> > @@ -109,6 +112,7 @@ enum {
> >   #define DEFAULT_WINDOW_NAME   N_("SPOKE NAME")
> >   #define DEFAULT_BETA          N_("PRE-RELEASE / TESTING")
> >   #define LAYOUT_INDICATOR_LABEL_WIDTH 10
> > +#define HELP_BUTTON_LABEL _("_Help!")
> >   
> >   struct _AnacondaBaseWindowPrivate {
> >       gboolean    is_beta, info_shown;
> > @@ -117,6 +121,7 @@ struct _AnacondaBaseWindowPrivate {
> >       GtkWidget  *nav_box, *nav_area, *action_area;
> >       GtkWidget  *name_label, *distro_label, *beta_label;
> >       GtkWidget  *layout_indicator;
> > +    GtkWidget  *help_button;
> >   
> >       /* Untranslated versions of various things. */
> >       gchar *orig_name, *orig_distro, *orig_beta;
> > @@ -128,6 +133,7 @@ static void
> > anaconda_base_window_buildable_init(GtkBuildableIface *iface);
> >   static void format_beta_label(AnacondaBaseWindow *window, const char
> >   *markup);
> >   
> >   static gboolean anaconda_base_window_info_bar_clicked(GtkWidget *widget,
> >   GdkEvent *event, AnacondaBaseWindow *win);
> > +static void anaconda_base_window_help_button_clicked(GtkButton *button,
> > AnacondaBaseWindow *win);
> >   
> >   G_DEFINE_TYPE_WITH_CODE(AnacondaBaseWindow, anaconda_base_window,
> >   GTK_TYPE_BIN,
> >                           G_IMPLEMENT_INTERFACE(GTK_TYPE_BUILDABLE,
> >                           anaconda_base_window_buildable_init))
> > @@ -173,6 +179,7 @@ static void
> > anaconda_base_window_class_init(AnacondaBaseWindowClass *klass) {
> >                                                           G_PARAM_READWRITE));
> >   
> >       klass->info_bar_clicked = NULL;
> > +    klass->help_button_clicked = NULL;
> >   
> >       /**
> >        * AnacondaBaseWindow::info-bar-clicked:
> > @@ -192,6 +199,24 @@ static void
> > anaconda_base_window_class_init(AnacondaBaseWindowClass *klass) {
> >                                                              g_cclosure_marshal_VOID__VOID,
> >                                                              G_TYPE_NONE,
> >                                                              0);
> >   
> > +    /**
> > +     * AnacondaBaseWindow::help-button-clicked:
> > +     * @window: the window that received the signal
> > +     *
> > +     * Emitted when the help button in the right corner has been activated
> > +     * (pressed and released). This is commonly used to open the help view
> > with
> > +     * help content for the given spoke or hub
> > +     *
> > +     * Since: 4.0
> > +     */
> > +    window_signals[SIGNAL_HELP_BUTTON_CLICKED] =
> > g_signal_new("help-button-clicked",
> > +
> > G_TYPE_FROM_CLASS(object_class),
> > +
> > G_SIGNAL_RUN_FIRST
> > | G_SIGNAL_ACTION,
> > +
> > G_STRUCT_OFFSET(AnacondaBaseWindowClass,
> > help_button_clicked),
> > +                                                              NULL, NULL,
> > +
> > g_cclosure_marshal_VOID__VOID,
> > +                                                              G_TYPE_NONE,
> > 0);
> > +
> >       g_type_class_add_private(object_class,
> >       sizeof(AnacondaBaseWindowPrivate));
> >   }
> >   
> > @@ -210,6 +235,7 @@ GtkWidget *anaconda_base_window_new() {
> >   
> >   static void anaconda_base_window_init(AnacondaBaseWindow *win) {
> >       char *markup;
> > +    AtkObject *atk;
> >   
> >       win->priv = G_TYPE_INSTANCE_GET_PRIVATE(win,
> >                                               ANACONDA_TYPE_BASE_WINDOW,
> > @@ -325,11 +351,28 @@ G_GNUC_END_IGNORE_DEPRECATIONS
> >       gtk_widget_set_margin_top(win->priv->layout_indicator, 6);
> >       gtk_widget_set_margin_bottom(win->priv->layout_indicator, 6);
> >   
> > +    /* Create the help button. */
> > +    win->priv->help_button =
> > gtk_button_new_with_mnemonic(HELP_BUTTON_LABEL);
> > +    gtk_widget_set_halign(win->priv->help_button, GTK_ALIGN_START);
> > +    gtk_widget_set_vexpand(win->priv->help_button, FALSE);
> > +    gtk_widget_set_valign(win->priv->help_button, GTK_ALIGN_END);
> > +    gtk_widget_set_margin_bottom(win->priv->help_button, 6);
> > +
> > +    atk = gtk_widget_get_accessible(win->priv->help_button);
> > +    atk_object_set_name(atk, HELP_BUTTON_LABEL);
> > +
> > +    /* Hook up some signals for that button.  The signal handlers here
> > will
> > +     * just raise our own custom signals for the whole window.
> > +     */
> > +    g_signal_connect(win->priv->help_button, "clicked",
> > +                     G_CALLBACK(anaconda_base_window_help_button_clicked),
> > win);
> > +
> >       /* Add everything to the nav area. */
> >       gtk_grid_attach(GTK_GRID(win->priv->nav_area), win->priv->name_label,
> >       0, 0, 1, 1);
> >       gtk_grid_attach(GTK_GRID(win->priv->nav_area),
> >       win->priv->distro_label, 1, 0, 1, 1);
> >       gtk_grid_attach(GTK_GRID(win->priv->nav_area), win->priv->beta_label,
> >       1, 1, 1, 1);
> >       gtk_grid_attach(GTK_GRID(win->priv->nav_area),
> >       win->priv->layout_indicator, 1, 2, 1, 1);
> > +    gtk_grid_attach(GTK_GRID(win->priv->nav_area), win->priv->help_button,
> > 2, 1, 1, 2);
> >   }
> >   
> >   static void anaconda_base_window_get_property(GObject *object, guint
> >   prop_id, GValue *value, GParamSpec *pspec) {
> > @@ -587,6 +630,11 @@ static gboolean
> > anaconda_base_window_info_bar_clicked(GtkWidget *wiget, GdkEvent
> >       return FALSE;
> >   }
> >   
> > +static void anaconda_base_window_help_button_clicked(GtkButton *button,
> > +                                                     AnacondaBaseWindow
> > *win) {
> > +        g_signal_emit(win, window_signals[SIGNAL_HELP_BUTTON_CLICKED], 0);
> > +}
> > +
> >   /**
> >    * anaconda_base_window_clear_info:
> >    * @win: a #AnacondaBaseWindow
> > diff --git a/widgets/src/BaseWindow.h b/widgets/src/BaseWindow.hA
> > index eb6191d..19891c1 100644
> > --- a/widgets/src/BaseWindow.h
> > +++ b/widgets/src/BaseWindow.h
> > @@ -56,11 +56,14 @@ struct _AnacondaBaseWindow {
> >    *                pointer to be cast to a #GtkBin pointer.
> >    * @info_bar_clicked : Function pointer called when the
> >    #AnacondaBaseWindow::info-bar-clicked
> >    *                     signal is emitted.
> > + * @help_button_clicked: Function pointer called when the
> > #AnacondaSpokeWindow::help-button-clicked
> > + *                       signal is emitted.
> >    */
> >   struct _AnacondaBaseWindowClass {
> >       GtkBinClass parent_class;
> >   
> >       void (* info_bar_clicked) (AnacondaBaseWindow *window);
> > +    void (* help_button_clicked) (AnacondaBaseWindow *window);
> >   };
> >   
> >   GType       anaconda_base_window_get_type (void);
> 
> _______________________________________________
> anaconda-patches mailing list
> anaconda-patches at lists.fedorahosted.org
> https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
> 


More information about the anaconda-patches mailing list