The First Milestone

Picture Credits : Bob The Builder

Meet Bob, I am sure most of us remember him from ‘Bob the Builder’. An animated series many of us would’ve watched as children.

Bob the Builder and his machine team are ready to tackle any project. Bob and the Can-Do Crew demonstrate the power of positive thinking, problem-solving, teamwork, and follow-through. The team always shows that “The Fun Is In Getting It Done!” Bob the Builder can be seen building, digging, and hauling.

Renzo null

picked from IMDb

Getting to point – If you have developed using Gtk+ before and are acquainted with the widget system it provides, you know about the kind of digging and hauling it takes to build the UI using C code. As you make each and every function call to set one among many properties of a widget, imagining and estimating how close to the desired UI is the one being built ( It’s not visible yet) with each line as you move ahead. Wondering how easy life would’ve been if there was a HTML (DOM) like interface for UI design and javascript like abilities to manipulate the DOM. That dream has come true.

Developers : (Summon GtkBuilder) GtkBuilder !

#define BobTheBuilder GtkBuilder

GTK+ supports the separation of user-interface layout from your business logic, by using UI descriptions in an XML format that can be parsed by the GtkBuilder class. So what GtkBuilder does is it processed a UI definition given in XML format and does all the heavy-lifting that needs to be done for allocating widegets, styling them ID-ing, packing etc. and than allows you to obtain a reference to the concerned widget in C code which allows for tweaking or manipulating the behaviour of the widget based on business logic. Thus importantly keeping the UI definitions seperate from the business logic. Thus very similar to what Bob The Builder does, takes a blueprint and turns it into real houses and building. GtkBuilder parses objects definitions in XML and creates real runtime objects of the same property, thus sparing us the part where we call the same functions again and again to create, destroy and style widgets.

The XML definitions can be generated by Glade, which is a drag-and-drop RAD tool which makes sure What You See Is What You Get (WYSIWYG). Enough said about GtkBuilder lets get down to business!

Nautilus Properties Window : Porting to GtkBuilder

GtkDialog vs GtkWindow ?

Dialog boxes are a convenient way to prompt the user for a small amount of input, e.g. to display a message, ask a question, or anything else that does not require extensive effort on the user’s part. GTK+ treats a dialog as a window split vertically. The top section is a GtkVBox, and is where widgets such as a GtkLabel or a GtkEntry should be packed. The bottom area is known as the “action area”. This is generally used for packing buttons into the dialog which may perform functions such as cancel, ok, or apply.

GtkWindow is a toplevel window which can contain other widgets. Windows normally have decorations that are under the control of the windowing system and allow the user to manipulate the window (resize it, move it, close it,…).

Old Implementation of the Properties Window.

Subclasses GtkDialog.

Uses Action area for Help and Close Button.
Current Implementation of the properties Window.

Subclasses GtkDialog

Doesn't Utilize Action Area

So now we know that the only reason the properties window is still a GtkDialog is because that is where it’s History has lead it to. Today It doesn’t Utilize or make use of any special feature offered by a GtkDialog over GtkWindow.

Thanks @alexm for the idea !

Commit cb706825 preserves the current behaviour of properties window and makes it Inherit GtkWindow instead of GtkDialog.

UI Building

Here Comes the part where Bob’s (aka. GtkBuilder) gonna take charge of the applications UI building and rids the code base of some huge complex thickets of UI building code.

We often find ourselves creating controller object classes when we realize that Objects offered natively do not satisfy our specific tailored needs. Be it storing information or, references to signal handlers or references to those UI components which need conditional tweaking.

gtk_widget_class_bind_template_child() binds pointers in class with widgets in the UI definition

GtkBuilder supports the use of templates, where the Class Name of the toplevel container is set same as the corresponding Controller Class name in C code. And the internal child widgets whose handles are required in the c-code are ID-ed with same identifiers as the one used for the corresponding reference variable in the Class definition.

Commits 4d312be1 and 18cfadc8 Obtain the Toplevel Container GtkWindow, GtkNotebook and Basic Page Containers from the template.

Icon Widget and Name Field Widget:

Name Field is a GtkEntry

Icon Widget is a GtkButton
Name Field is a GtkLabel

Icon Widget is a GtkImage

So what do you do when you have two widgets which are possible candidates for a given place holder in the UI.

Traditional approach calls for what (@antoniof) calls the gtk_widget_destroy() dance where the business logic determines which kind of Widget is required and packs it into the container.Further logic determines what kind of Widget has been packed and proceeds accordingly. Or alternatively handles each and every possibility of Widget Creation, replacement with if-else statements and destroys the Widget not required, with gtk_widget_destroy().

Contemporary approach with the use of GtkBuilder provides us with GtkStack which is a widget capable of containing more than one GtkWidget as its children, and makes one of these visible with gtk_stack_set_visible_child(). So an elegant solution for this problem was to create both children an packing them in the GtkStack. Than populating and setting visible the appropriate child.

Commits 2af7f424 and b41d44d1 Obtain Icon Widget and Name Row from template.

Rest of the Rows

It can be noticed that there is a different set of rows displayed based on the type of file selection the properties window is launched for! It's also notice-able that each row is a combination of GtkLabel : GtkLabel, all title:value pairs!

Handling Conditional Rows : Each and every widget which could ever find itself in the UI is defined in nautilus-properties-window.ui XML definition. However its visibility is controlled by the logical structure of the program which calls gtk_widget_show() and gtk_widget_hide() on the widgets which are supposed to be shown and hidden accordingly.

Generating each row : The existing code achieves it with the help of an over-engineered hierarchy of function calls, it requsting appednd_title_and_ellipsizing_value() for a row of particular kind which is constructed in the calls which follow that.

function call chain which generates one row of the basic page grid

While the above mechanism can be conveniently used to generate rows but anything which has to do with debugging this mechanism or imagining the UI structure anywhere midway in the function calls is very difficult, and messed up. Moreover It doesn’t allow for a granular control on the properties of a particular row, since all of them are generated by the same interface.

credits : UNIX and Linux System Administration Handbook (Nemeth, Snyder, Hein, Whaley)

Easier Solution : An easier solution is to define each and every Row GtkLabel pair in the XML definition and obtaining its reference in the NautilusPropertiesWindow struct members. The properties of these labels could be found out by tracing the execution of the row generating mechanism. The rows can be populated and be made visible/hidden based on the business logic, from the control structures of the program.

Commit 08fbb49b obtains all the rows og the basic grid from template and gets rid of the complex row generating mechanism present currently.

And this is the progress till now ! This was long post : p !

3 thoughts on “The First Milestone

  1. Pingback: GSoC final project report – cocoon

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s