GNOME Bugzilla – Bug 151441
implement a GtkArrowToolButton widget
Last modified: 2011-02-04 16:17:01 UTC
it would be useful to consolidate into gtk an implementation for a toolbutton
which has also an arrow that drops down a menu.
Lots of gnome apps already implement it separately, among others:
- epiphany (and I suppose galeon) for the "Back" and "Forward" buttons
- gedit (and probably others) for the open + open recents button
- nautilus for back and forward
- evolution for the "New" button
epiphany already has this impemented as a widget
I haven't yet looked at the Evo and Nautilus implementations... (gedit code is
older and manually creates the arrow button)
Some subtle UI differences among the various implementations:
- gedit's one allows a different tooltip for the button itself and the arrow
button ("Open a File" vs "Open a recently used file") [I think it's useful]
- epi's and evo's ones raise both the button itself and the arrow button when
the mouse pointer is positioned over them, while nautilus and gedit only raise
one. [I'd say epi behavior is better, for what is worth Mozilla does the same]
- evo's New button is automatically pressd when clicking on the arrow button.
If you think that this kind of widget request makes sense I think it would be
pretty cool to put it in egg, so that maybe we can get some of the gnome apps
ported to it in the 2.10 timeframe
I think this makes sense.
Here is a first cut at it that basically takes the epi widget with few changes
(adding the _new and _new_from_stock functions) and moves it to the gtk coding
It's still rough, but I thought to attach it for two reasons:
- get api feedback etc
- avoid for anyone that wants to work on it the grunt work of reindenting etc
I decided to use "DropdownToolButton" instead of "ArrowToolButton" (got the name
from the evo implementation)
some of the open issues:
- should the priv->menu be created? (ephy implementation creted it, while I
chosed to have a set_menu function... looked like a more familiar api to me -
see the old OptionMenu)
- still need to figure out how to handle separate tooltips
- what happens when it's packed at the end of the toolbar, the window is
resized, and the button should end up in the overflow menu?
- should other internal stuff be implemented? (for instance in
gtktoggletoolbutton I see the menu_proxy stuff... I've no idea what it is)
Created attachment 31132 [details]
Created attachment 31133 [details]
>- should the priv->menu be created? (ephy implementation creted it, while I
>chosed to have a set_menu function... looked like a more familiar api to me -
>see the old OptionMenu)
I'd like to (and I was going to do this for ephy 1.6) make it use GtkUIManager
for the popdown menu, i.e. just have it know which ui manager to use and which
path to get the menu from it.
For use without a UI manager, set_menu looks better to me, too.
>- what happens when it's packed at the end of the toolbar, the window is
>resized, and the button should end up in the overflow menu?
IMHO the popdown menu should become the submenu of the proxy menuitem.
Can you please commit this in libegg, so that I can move ephy 1.5 to use this
from libegg instead of its own copy? Thanks.
I agree with everybody that such a widget makes sense, and I don't even think
it's inconceivable that we can get it in 2.6. Please go ahead and commit it to
One thing I thought about is how it would interact with homogeneous items.
Epiphany turns homogeneous-ness off for drop-down buttons (for good reasons),
but that is not quite the desired behavior in my opinion. Ideally, the button
part of the drop down widget would be treated as homogeneous, ie. the part of
the widget that isn't an arrow would be made the same size as other homogeneous
To do this, we could add a new signal to GtkToolItem,
void homogeneous_size_request (int *size_request),
that would allow items to report how wide they should be considered for
homogeneous-ness purposes. The default handler for this signal would just return
the size_reques.width, but the DropDownItem would override it to report the
requested width of its button instead of its total width.
I'll try to put together the required autotools stuff tomorrow and commit this
preliminary version in libegg tomorrow.
Note however that my goal with the bugreport and the first cut implementation
was to get the ball rolling, but I do not feel qualified enough to do the
I know too little about gtk+ internals and in particular about the
toolbar/UImanager parts :(
committed in libegg/dropdowntoolbutton/
I noticed one problem with the code, namely that it's based on the epiphany impl
which is GPL, not LGPL which is needed for inclusion in gtk+. Marco says he
wrote the widget, but probably had copied from galeon. So we need to track all
people involved and see if they will relicense -- or we need to start from
scratch; since it's not a big chunk of code, that might be easier ;) (?)
At marco's suggestion, CC:ing Ricardo.
that's why I cc'ed teuf: that's the one that had the (c) on the epiphany file.
looking in viewcvs it looks like successive changes to the epiphany file are
mostly oneliners so they aren't copirightable (does such a word exist?)...
I've not been able to dig the galeon version though.
 according to the evolution copiright assignment debate
I didn't write this widget, I don't know why I own the copyright on that file...
I'm generally happy to relicence code I have written from GPL to LGPL, but since
I'm not the author of that particular piece of code, that's not really useful ;)
I wrote the current widget for the galeon toolbar, but I think it is posterior
to the epiphany fork (not sure). I wrote also the previous galeon
implementation, or at least that what cvs logs seem to say.
Either way, I'm happy relicensing any of this code thay I may have written under
How does the current galeon widget differs? Does the one proposed fit your needs?
btw, can you post a link to the current galeon implementation on viewcvs?
Galeon's one is very similar to Epiphany's. If it is posterior to the fork (as I
think) it is very probable that I looked at Epiphany's and not the other way around.
Galeon's widgets add the following:
- The arrow can be hidden.
- The menu is also shown when right clicking in the button.
- You can get a pointer to the internal button (I think we needed this for dnd).
I like the idea of a manual "set_menu", or at least it should be possible to
create the menuitems manually, not only through GtkUIManager.
some updates on what is currently in libegg:
- I fixed some bugs and added a super simple test app
- I added an api to set the tooltip for the arrow button
- I made the menu show up on right click as suggested by Ricardo (since also
mozilla behaves that way)
I didn't add the possibility of hiding the arrow: why is it needed? if you don't
want the arrow to show up you should not be using this widget anyway...
With regard to the _set_menu function and memory management, currently the code
works in the following way: I unref priv->menu (if not null), set priv->menu to
the new menu and then ref it... is it right?
> With regard to the _set_menu function and memory management, currently the code
> works in the following way: I unref priv->menu (if not null), set priv->menu to
> the new menu and then ref it... is it right?
I think it should probably ref/sink the menu. See for exampe
gtk_tool_item_set_proxy_menu_item() for an example of how to do that.
yes, it already does that: chpe fixed it.
Looking a bit more detailed on it, here are some comments:
- The widget needs to have keyboard navigation.
- The arrow button should not take focus on click
- Using the keyboard to pop up the menu should probably be done like in
- The menu need to pop up in the correct position when the item is on
a vertical toolbar
wrt the keyboard and focus issues, may you be a bit more specific? I haven't
looked at gtktoolbar.c yet, but by testing with the simple
testdropdowntoolbutton I can't see any difference with the behavior of the
overflow menu of the toolbar:
- the arrow button doesn't take focus when you click on it
- the arrow button can be focused using arrow keys once the focus is in the toolbar
- the arrow button can be activate pressing the space bar key once it has the focus
with regard to the menu positioning, the menu should probably pop up on the
right when the toolbar is vertical, but should also the arrow change direction
and be packed under the main button using a vbox instead of a hbox? Is that even
possible to change on the fly? How can I query the orienatation of the toolbar?
What happens if the widget hasn't been added to a toolbar yet or if it's moved
from a toolbar to another?
You are right that the arrow can be focused with the arrow keys once the focus
is on the toolbar. Sorry about that.
What I mean about the focus is that it should act like the toolbar overflow menu.
- "pop up" being tied to the activation of the button, not just random
keypresses (which might be themed differently)
- show the button depressed when the menu is up
- select first item when the menu is shown.
- gtk_tool_item_get_orientation() will return the orientation of the toolbar,
or a default value if the item hasn't been added to a toolbar yet.
- GtkToolItemClass->toolbar_reconfigured will be called when something changes
about the toolbar, such as its orientation. The implementation for
GtkArrowToolButton will have to chain up to allow GtkToolButton to rebuild itself.
I think the best thing to do is to have a 'construct_contents' method, that
rebuilds the widget completely. And call that whenever something changes (such
as the orientation of the toolbar).
For the menu positioning I think the code in gtktoolbar.c
(gtk_toolbar_arrow_button_clicked, show_menu, menu_position_func) can be adapted
I fixed the first 3 items (tie the menu to the toggle state and select the first
item when activating with the keyboard).
Unreated question: what is the push_in param of the GtkMenuPositionFunc? should
that be set to TRUE like I saw in gtktoolbar.c? we were ignoring it before... I
cannot see any difference. It would be nice to add docs for that param in since
it is undocumented... maybe I should file a separate bug for that.
fixed menu positioning. btw, the code in toolbar.c doesn't make sure that the
overflow menu is on screen.
Well, the menu code will clamp the menu on screen and then make it scrol, but
the result is pretty weird for the toolbar currently. For the ArrowButton it
looks like the menu will just be clamped on screen which means it will show up
covering the arrow.
I think the right behavior in both cases is to do what the pull-down menus do:
allocate the menu *small* enough that it fits on the screen, then set the scrolling.
I haven't investigated how to actually do this, except wondering if some public
generic menu positioning function that would take care of all this would perhaps
be a useful addition to gtk+.
That's what "push_in" is about; I forget the exact details, but it's
something like that if position function sets it to to TRUE, then the calling
code will make the size of the menu smaller and add scrolling rather than than
displacing the menu to make it fit onscreen.
Generally, position functions don't need to worry about size, just
position. (GtkOptionMenu might be an example worth looking at.)
Ok, I have removed the clamping and as a matter of fact scrolling is
automagically added to the menu if ends out of the screen.
I've also implemented ssp's suggestion of connecting to the toolbar_reconfigured
signal and to reconstruct the widget contents so that on verical toolbars we
have the arrow_button below the real button and with a right arrow.
Since I'm not 100% confident of having got everithing right I'm attaching the
last patch here for easier review.
Created attachment 31617 [details] [review]
last patch committed to libegg, for easier review
The construct_contents part of the patch looks fine, but I am not completely
happy with the menu positioning. I think that it should position the menu
similar to how normal dropdown menus (from a menubar) are positioned. Ie.,
if there is room below the toolbutton,
position the menu there
else if there is room above to toolbutton
position the menu there
position the menu above or below, depending on
where there is more space. Set push_in to FALSE,
so that it will get scroll arrows.
The toolbar overflow menu should do the same (it doesn't currently). I don't
think this particular issue should prevent the widget from going in though.
- egg_dropdown_toolbutton_set_menu() should accept a NULL menu to mean
'no menu'. In that case the arrow button should be shown, but
- The menu needs to be a real property
- I don't think a right-click on the button should pop up the menu
- The widget should probably be renamed GtkMenuToolButton
- egg_dropdown_tool_button_new() should take label and icon parameters
In addition I am a little nervous about the button reparenting going on in
egg_dropdown_toolbutton_init() where the GtkButton ends up being a child of an
hbox. This will break code that does
on a toolbutton and expects to be able to cast the result to a GtkButton. There
is probably not much we can do about that though.
> position the menu above or below, depending on
> where there is more space. Set push_in to FALSE,
> so that it will get scroll arrows.
as far as I can tell with push_in = TRUE you get the scroll arrows, while with
push_in = false the menu is moved to stai on screen.
> - egg_dropdown_toolbutton_set_menu() should accept a NULL menu to mean
> 'no menu'. In that case the arrow button should be shown, but
> - The menu needs to be a real property
Ok, I saw OPtionMenu did the same. Can I ask what is the reason?
> - I don't think a right-click on the button should pop up the menu
Not a big issue and if you prefer this way I'll remove it, but I like the
right-click behavior. For instance the real button part offers a bigger target
for the pointer, beside you can get to the menu with fewer keyboard presses
using shift+f10. Note that mozilla and firefox show the menu on right-click.
> - The widget should probably be renamed GtkMenuToolButton
I felt dropdown_menu_tool_button a bit more descriptive, but on the other hand
it is also longer. I'm fine with the rename, anyway we should handle this when
moving to gtk+.
> - egg_dropdown_tool_button_new() should take label and icon parameters
Umh... I know very little about bindings, but I always thought that having _new
(void) constructor was a requirement. We can probably add other constructors
like new_with_label() but I didn't want add tons of differnt constructors that
are never used in practice.
> In addition I am a little nervous about the button reparenting going on in
> egg_dropdown_toolbutton_init() where the GtkButton ends up being a child of an
> hbox. This will break code that does
> GTK_BIN (dropdown_button)->child
> on a toolbutton and expects to be able to cast the result to a GtkButton.
> There is probably not much we can do about that though.
I understand your concern, but I'm out of better suggestions... maybe we should
live with it and document that such a use is illegal.
Created attachment 31943 [details] [review]
menu as property patch
Here is the patch I just committed to libegg: it implements the "menu as
property" suggestion and the ability to set a NULL menu.
Since I know very little about properties an accurate review is appreciated, to
make sure I didn't forget something.
I noticed a bug in previous patch: g_object_notify was not called when setting
menu to NULL. fixed in cvs.
> as far as I can tell with push_in = TRUE you get the scroll arrows, while with
> push_in = false the menu is moved to stai on screen.
No, it's the other way around: *push_in = TRUE means, "whoever called me should
move the button on-screen". FALSE means "don't move the menu; just it where it
is, but add scroll arrows".
> > - The menu needs to be a real property
> Ok, I saw OPtionMenu did the same. Can I ask what is the reason?
So that it can be used by language bindings and GUI builders.
> Not a big issue and if you prefer this way I'll remove it, but I like the
> right-click behavior. For instance the real button part offers a bigger
My reasons are:
- You can't tell by looking at the widget what is going to happen, and
- You can't use the right click for a context menu on the toolbar then.
Ideally I would like to have right-click reserved for context menus for
> Umh... I know very little about bindings, but I always thought that having
> _new (void) constructor was a requirement
It's not. Bindings can use g_object_new() if they want to. See GtkToolButton for
> I understand your concern, but I'm out of better suggestions... maybe
> we should live with it and document that such a use is illegal.
Well, there are examples of such use already: people wrote this
"EphyArrowToolButton", which makes use of it ;-) We can't break Epiphany and
Galeon; if we could, it would be possible to fix the problem by having
GtkToolButton put the real button into an hbox that the arrow button could
> Since I know very little about properties an accurate review is
> appreciated, to make sure I didn't forget something.
The patch looks good, except I think it is possible to simplify
egg_dropdown_tool_button_set_menu() by doing something like
if (priv->menu != menu)
priv->menu = menu;
It is okay to cast a NULL pointer with GTK_MENU().
if (priv->menu != menu)
priv->menu = menu;
this doesn't work: if the first time you set the menu to NULL, (priv->menu ==
menu) is true and the arrow button is not set insensitive.
ripped out right-click and changed new() to take icon and label.
Ok, I'm going to attach here the version proposed for gtk inclusion.
It contains all of your suggestion except for the menu positioning (which, as
you say, can be fixed later). In partular I still left *push_in = TRUE, because
setting it false and trying to popup the menu at the bottom of the screen gives
me the following warnings:
(testdropdowntoolbutton:8513): Gtk-WARNING **: gtk_widget_size_allocate():
attempt to allocate widget with width 64 and height -10
(testdropdowntoolbutton:8513): Gtk-WARNING **: gtk_widget_size_allocate():
attempt to allocate widget with width 64 and height -10
Some other minor issues that came to my mind, but important before putting this
in gtk are:
- is menu_activated the best name for the signal?
- should we include an api to programmatically popup the menu?
Created attachment 31970 [details]
Created attachment 31971 [details]
- Is the menu_activated signal needed at all? Couldn't people just connect
to "show" on the menu itself?
- I am not necessarily opposed to adding a way of showing the menu
programmatically, but I'd rather wait until there is a proven
need for it.
The final thing we need before it can go in is a brief overview documentation in
docs/reference/gtk/tmpl/gtkmenutoolbutton.sgml. That file should be generated
automatically if you build gtk+ with --enable-gtk-doc and gtkmenutoolbutton.[ch]
added to Makefile.am.
When we have that documentation, I think you should go ahead and commit the
widget to gtk+ CVS. There are some new bugs that should filed in connection with
- "Fix menu positioning for both toolbar and menu-toolbutton"
- "Simplify gtk_menu_tool_button_set_menu"
I think the pseudo-code I posted will work as long as the
initial state of the arrow button is insensitive. (As far as I
can see that is a bug in the current code as well).
- "Consider removing menu_activated signal"
Milestone: 2.6 API freeze
I don't expect to be able to look at this bug for at least a week.
Ok. I alreday have the documentation (I didn't attach it to cut down the
I'll give it a look at setting the arrow button insentive by deafult and
simplify set_menu and then I'll commit and file the bugs mentioned above.
Thanks a lot for your time and review.
IMHO, menu-activated is needed for on-deman menu building. Also maybe a program
wants to decide which one of different menus to show based on some program
state, and therefore needs to set the menu itself, not just show the previous
one? So I think a way to set the menu before it's shown is still necessary.
the gtkmenutoolbuttonwidget is now committed to gtk+ head. Including docs.
I'm closing this bug and will now open two ones as suggested by ssp (the
simplification of set menu is already solved).
I'll also remove the code from libegg and add a note saying that it's in gtk
now, it should cause any problems since the only user is epiphany head.