So for the last two weeks, I have been trying to implement this:
In an application that already use GAction and a normal GMenu for everything is quite easy.
But Nautilus is not using GAction neither GMenu for its menus. Not only that, Nautilus use GtkUIManager for managing the menus and GtkActions. And not only that, Nautilus merge parts of menus along all the code.
Also, the popover drawn in that design is not possible with GMenu because of the GtkSlider.
So my first step, when nothing was clear for me, was to just trying to create a custom GtkBox class to embed it on the popover and try to us the current architecture of nautilus.
It didn’t work, obviously. Fail 1.
Then after talking with some Gedit guys (thanks!), I understood that what I needed was to port Nautilus to GAction first. But, I will have to find a solution to merge menus.
My first week and a half was trying to find a solution on how to merge the menus, along making the port to GAction and refactoring Nautilus code to make it with sense and being used to the code of Nautilus.
The worst part was the complexity of the code, understanding it and the its intricate code paths. Making a new application test with GMenu and popovers merging menus was kinda acceptable.
To understand why I needed to merge menus recursively, this was the recursion of nautilus menus that was done with GtkUIManager along 4 levels of classes. That diagram should have more leafs (more classes injecting items) at some levels, but this was the most complex one.:
So after spending more than a week trying to make it work at all costs, I figured out that merging menus recursively in recursive sections was not working. That was kinda frustrating.
Big fail 2.
Then I decided to get another path, with the experience earned along that one week and a half.
I simplified the menu layout, to be a flat layout (still I have to merge a one-level menus, so a new way to merge menus was born), put all the management of the actions on the window instead of having multiple GtkActionGroups sparsed on the code as Nautilus had previously, make the update of menus centralized on the window, attach the menus where it makes sense (on the toolbar), and a beautiful thing, the toolbar of nautilus (aka header bar) is now on a xml gresource file, not longer making it programatically =).
That last thing required to redo a good part of the toolbar, to for example use the private bindings that GObject provides (and then be able to use gtk_widget_class_bind_template_child_private) or sync the sensitivity of some widgets that were synced directly modifying the actions on the window instead on the toolbar, etc.
And thanks to the experience earned in the fails before, it started working!
Then I became enthusiastic to add more and more part of nautilus ported. After the prototype worked this morning, all was kinda easy. And now I feel more (like a very big difference) confident with the code of Nautilus, C, GTK+ and GObject.
Here’s the results
It’s still a very early prototype, since the port to GAction is not completed. I think I have 40% of the port done. And I didn’t erased all the code that now it’s not necesary. But with a prototype working and the difficult edges solved, that doesn’t worry me at all.
Work to be done is:
* Complete the port to GAction, porting also all menus.
* Refactor to make more sense now with the current workflow of menus and actions.
* Create the public API to allow extensions to extend the menus. Luckily I was thinking on that when creating the API to merge the menus inside Nautilus, so the method will be more or less the same.
* And last but not least, make sure any regression is known (this is kinda complicated due to the possibly code paths and supported tools of Nautilus)
Hope you like the work!
PD: Work is being done in wip/gaction but please, don’t look at the code yet =)