Re: GMenu, GAction and GtkBuilder



On Tue, 2013-10-01 at 12:15 +0200, Murray Cumming wrote:
Here is a description of the gtkmm menu API that should replace
GtkUIManager. I'll reply with some opinions about the API and reasons
why I don't think we should actually deprecate UIManager yet.

For a fairly complete example, just look here:
https://git.gnome.org/browse/gtkmm-documentation/tree/examples/book/menus/main_menu/examplewindow.cc

* Actions:

We can replace Gtk::Action/Gtk::ToggleAction/Gtk::RadioAction instances
with Gio::Action. You'll actually want to use Gio::SimpleAction in most
cases, because it has useful API.
See
https://developer.gnome.org/glibmm/unstable/classGio_1_1SimpleAction.html

We replace Gtk::ActionGroup with Gio::ActionGroup, though you'll want to
actually use Gio::SimpleActionGroup because you can add actions to it.
See
https://developer.gnome.org/glibmm/unstable/classGio_1_1SimpleActionGroup.html

I find it annoying that the classes we actually use in applications have
this "Simple" in their name, cluttering up our application code. It
feels like GAction should be GActionBase and GSimpleAction should be
GAction. GSimpleAction feel like "GGoodEnoughToActuallyUseAction".

We replace calls to
  Gtk::ActionGroup::add("action-name", "Action Title", signal_handler)
with
  Gio::SimpleActionGroup::add_action("action-name", signal_handler)

See
https://developer.gnome.org/glibmm/2.37/classGio_1_1ActionMap.html#a784dfa4573e994ac452d5e2dd56a5909

The Action Title now becomes just a menu item title and is specified in
the XML.

Notice that this means you'll need to put that XML in an external file
so that it can be translated by intltools (now yelp-tools). That's not
so bad though. You probably already have external .glade (or .ui) files
that you can add the <menu> to.

However, watch out. Glade doesn't yet support the <menu> syntax. If you
open and save your .glade file in Glade then it will silently remove
your <menu> nodes.
This Glade bug might track that:
https://bugzilla.gnome.org/show_bug.cgi?id=692669


We replace GtkUIManager with GtkBuilder, using its <menu> syntax instead
of the old <ui> syntax.


* Toggle and Radio items:

Toggle items and Radio items are a bit strange. Both are demonstrated
here, and are not as simple as the old GtkToggleAction and
GtkRadioAction:
https://git.gnome.org/browse/gtkmm-documentation/tree/examples/book/menus/main_menu/examplewindow.cc


** Toggle items:
For a toggle item we add a "bool" action, which is just a regular
GAction with a boolean "state". For instance, with gtkmm:
  m_refToggle = refActionGroup->add_action_bool("sometoggle",
    sigc::mem_fun(*this, &ExampleWindow::on_menu_toggle),
    false); //false is the default value

Notice that this is nicer in gtkmm than in GTK+. In this bug (now a
duplicate) I described the nasty C API for it:
https://bugzilla.gnome.org/show_bug.cgi?id=705655

We added similar convenience API in TreeView. For instance,
append_column_numeric():
https://developer.gnome.org/gtkmm/stable/classGtk_1_1TreeView.html#a8affe8dc5cf35c8c4df0c8ec666661d8

We also hide the "parameter" parameter from the signal handler in the
common case, because it's an unusual and confusing thing that you
usually won't need. There's add_action_with_parameter() if you need it:
https://developer.gnome.org/glibmm/2.37/classGio_1_1ActionMap.html#a3548d329e7abda0d6325c1f75a799da6

But I still find our API a bit strange. We could add our own
Gio::SimpleToggleAction and Gio::SimpleRadioAction classes to make the
API nicer, but I'd rather delay that because I suspect that they might
appear in the C API itself sometime:
https://bugzilla.gnome.org/show_bug.cgi?id=667973
 
And we would lay that out in the glade file like any other menu item.

Unlike with GtkAction, in the signal handler, we must now explicitly
toggle that state. Otherwise clicking the menu item won't change it's
appearance at all. For instance:
  void ExampleWindow::on_menu_toggle()
  {
    bool active = false;
    m_refToggle->get_state(active);
    m_refToggle->change_state(!active);

Obviously, it's good that this gives you the chance to reject the change
and complain to the user, though I feel that that's the unusual case and
shouldn't be the default.

Maybe we could add some code in gtkmm to change the state automatically,
making auto_state_change an extra boolean parameter to add_action_bool()
and Action::create_bool(). We do much the same thing in the TreeView
API, by providing append_column_editable().
https://developer.gnome.org/gtkmm/stable/classGtk_1_1TreeView.html#a2b7e3001fa1bb1aa415da76be91dc65f

** Radio items:

Radio items are even stranger. Unlike GtkRadioAction, we now have just
one GAction to represent, for instance, 3 radio menu items. That GAction
has a state, whose type you must choose. gtkmm has convenience methods
to create string-based or integer-based radio actions. For instance:
  m_refChoice = refActionGroup->add_action_radio_string("choice",
    sigc::mem_fun(*this, &ExampleWindow::on_menu_choices),
    "a"); //"a" is the default value.

Unlike with toggle items, we get the chosen state via the action's
"parameter". Like toggle items, we need to actually set the state to see
any visual effect. For instance:
   void ExampleWindow::on_menu_choices(const Glib::ustring& parameter)
   {
     m_refChoice->change_state(parameter);

Again, I find this a bit tedious.

We specify the possible states in the XML, as "target" values for an
<item>. Several radio items can have the same action name, but different
target values.

I think this confusion/conflation of "state", "parameter" and "target"
is a big mistake, made worse by the different use of state and parameter
depending on whether it's a toggle or radio item, or just a regular
action with a parameter. I complained about that here, but it seems far
too late to fix it now:
https://bugzilla.gnome.org/show_bug.cgi?id=704392#c11
See also
https://bugzilla.gnome.org/show_bug.cgi?id=705133#c4

I also don't like duplicating these magic state values across both the
code and the XML file. If we could use enums then it would at least be
more structured. See bug
  https://bugzilla.gnome.org/show_bug.cgi?id=705483

* Summary

As a complete porting example, this commit replaces the use of UIManager
+GtkMenu with Builder+GMenu in one of our examples:
https://git.gnome.org/browse/gtkmm-documentation/commit/?id=9ce75deddf75822fe06406f1b86123661c64b02d
And this one adds back the toolbar:
https://git.gnome.org/browse/gtkmm-documentation/commit/?id=8ffa9a16fc773a472f6fa13d262cc20a9a31c318

There are some other issues that remain unresolved or unclear to me:

1. The accelerators in a main menu will not work unless you also use
Gtk::Application, Gtk::ApplicationWindow and
Gtk::Applicatin::add_accelerator(). It's been suggested that building a
GtkMenuBar from a GMenu, as we do in our examples, should not be done.
https://bugzilla.gnome.org/show_bug.cgi?id=708905
1.1 But the alternative, using Gtk::Application::set_menu_bar(), as
shown in one of our examples, does not seem to allow for separate menu
bars in separate windows, while also taking the menu-creating code away
from the window's implementation.

https://git.gnome.org/browse/gtkmm-documentation/tree/examples/book/application/app_and_win_menus/exampleapplication.cc#n52

1.2 Those "accel" attributes in the XML are not well documented anyway,
and will soon be deprecated:
https://bugzilla.gnome.org/show_bug.cgi?id=708908#c3


2. I don't understand when or why we should use the standard "app" and
"win" action groups instead of custom action groups such as our
"example" ones. I asked here:
  https://mail.gnome.org/archives/gtk-list/2013-September/msg00033.html


3. There is no replacement for GtkRecentAction:
  https://bugzilla.gnome.org/show_bug.cgi?id=707422
though there is some suggestion that there shouldn't be:

https://mail.gnome.org/archives/gtk-devel-list/2013-September/msg00022.html


4. There is no similar XML markup for toolbars, to replace the <toolbar>
markup with GtkUIManager. So our examples just create the Gtk::Toolbar
in code and call 
  gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE
(button->gobj()), "example.quit");
For instance, in our example:
https://git.gnome.org/browse/gtkmm-documentation/tree/examples/book/menus/main_menu/examplewindow.cc#n201
We can't use just
  button->set_detailed_action_name("example.quit");
because we'd have to break ABI to add a new base class.


Overall, I think we should take the unusual step of undeprecating
Gtk::UIManager and friends in gtkmm before our stable release, even
though the underlying C API is deprecated. Many C developers also seem
to feel that the deprecation in GTK+ was rushed, but we had no response
to requests to delay it. Hopefully things will be clearer for gtkmm
3.12.

-- 
Murray Cumming
murrayc murrayc com
www.murrayc.com
www.openismus.com



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]