SlideShare a Scribd company logo
1 of 39
Download to read offline
GTK Development
Using Glade 3
GTK+ is a toolkit, or a collection of libraries, which
developers can use to develop GUI applications for
Linux, OSX, Windows, and any other platform on
which GTK+ is available.


Original Article by Micah Carrick
Table of Contents
Part 1 - Designing a User Interface Using Glade 3 ___________________________________________1

  Quick Overview of GTK+ Concepts ______________________________________________________________1

  Introduction to Glade3 _________________________________________________________________________3

  Getting Familiar with the Glade Interface_______________________________________________________3

  Manipulating Widget Properties________________________________________________________________5

  Specifying Callback Functions for Signals _______________________________________________________6

  Adding Widgets to the GtkWindow _____________________________________________________________9

  How Packing Effects the Layout ______________________________________________________________ 13

  Editing the Menu (or Toolbar) ________________________________________________________________ 15

  Final Touches to the Main Window ___________________________________________________________ 18

Part 2 - Choosing a Programming Language for GT K+ Dev elopm ent _____________ 19

  Which is the BEST Language? ________________________________________________________________ 19

  Language Choice Considerations _____________________________________________________________ 19

  A Look at Python vs. C________________________________________________________________________ 20

Part 3 __________________________________________________________________________________________ 22

  Setting Up Your Development Environment___________________________________________________ 22

  GtkBuilder and LibGlade _____________________________________________________________________ 24

  The Minimal Application _____________________________________________________________________ 25

  Compiling and Running the Application ______________________________________________________ 27

  Stepping Through the Code ___________________________________________________________________    29
    Including the GTK+ Library _______________________________________________________________     29
    Initializing the GTK+ Library ______________________________________________________________   29
    Building the Interface with GtkBuilder ____________________________________________________    30
    Getting References to Widgets From GtkBuilder _________________________________________        32
    Connecting Callback Functions to Signals _______________________________________________       33
    Showing the Application Window _________________________________________________________       36
    In Summary _______________________________________________________________________________     37
Part 1| Designing a User Interface Using Glade 3

          In part 1 of the GTK+ and Glade3 GUI Programming Tutorial series, we will be
    designing the graphical user interface (GUI) for a GTK+ text editor application (shown
    left) which will be used throughout these tutorials. This GUI design will be created using
    the Glade Interface Designer and is completely independent of the programming
    language used to implement the design, which will come in subsequent tutorials.

     Quick Overview of GTK+ Concepts

           If you have no experience with GTK+, you may struggle with some of the
     concepts I am going to cover. Although I am going to attempt to teach some of these
     concepts on the fly, it would serve you well to read up on these ideas further, perhaps
     after working through part 1 of this tutorial. Understanding the fundamental concepts of
     GTK+ will be instrumental in your ability to effectively use Glade.

           First of all, GTK+ is not a programming language. GTK+ is a toolkit, or a
     collection of libraries, which developers can use to develop GUI applications for Linux,
     OSX, Windows, and any other platform on which GTK+ is available. It can be thought
     of in the same terms as MFC or the Win32 API on Windows, Swing and SWT in Java,
     or Qt (the "other" Linux GUI toolkit used by KDE).

           Although GTK+ itself is written in C, there are a multitude of language "bindings"
     allowing programmers to develop GTK+ applications in the language of their choice
     including C++, Python, Perl, PHP, Ruby, and many others.

            GTK+ is based on 3 main libraries: Glib, Pango, and ATK, however, we primarily
     work with GTK+ and let GTK+ do it's magic with those 3 libraries. GLib wraps most of
     the standard C library functions for portability (allowing your code to run on Windows
     and Linux if desired). We use GLib a lot when working in C or C++, which I will explain
     more thoroughly when implementing our design using C. Higher-level languages such
     as Python and Ruby won't have to worry about GLib as they have their own standard
     libraries which provide similar functionality.

           GTK+ and associated libraries implement an object oriented approach through
     GObject. How this works isn't important just yet, and different programming languages
     will reveal this to you differently, however, it's important to understand that GTK+
     uses object orientation (yes, even in C).

          Every piece of a GTK+ GUI is comprised of one or more "widgets" which are
     objects. All widgets will be derived from a base widget called GtkWidget. For example,
     an application's window is a widget called GtkWindow. The toolbar within that window



1
is a widget called GtkToolbar. Although a GtkWindow is also a GtkWidget, a
    GtkWidget is not neccesarily a GtkWindow. Child widgets are derived from their parent
    objects to extend the functionality of that object. These are standard OOP (object
    oriented programming) concepts (hint: Google search "object oriented programming" if
    this is a new concept).

         We can look at any widget in the GTK+ reference documentation to see which
    objects it is derived from. In the case of GtkWindow, it looks something like this:

           GObject
             +----GInitiallyUnowned
                     +----GtkObject
                           +----GtkWidget
                                   +----GtkContainer
                                          +----GtkBin
                                                 +----GtkWindow


         As you can see, a GtkWindow is derived from GtkBin which is derived from
    GtkContainer, and so on. For your first application, you don't need to worry about
    anything above the GtkWidget object. The reason this heirarchy is so important is
    because when you're looking for functions, properties, and signals for any particular
    widget, you need to realize that the functions, properties, and signals of it's parent
    objects apply to it as well. In part 2, this will become even more apparent when writing
    code for this example application.

          We also begin to see a naming convention emerge. This is pretty handy. We can
    easily tell what library an object or function is from. All objects beginning with Gtk are
    from GTK+. Later, we'll see things like GladeXML which is part of Libglade or GError
    which is part of GLib. All objects (and thus Widgets) are incamel case. The functions
    which manipulate these objects are in lower-case with underscores for spaces. For
    example, gtk_window_set_title() is a function to set the title property of a GtkWindow
    object.

          All the reference documentation you will need is available online
    from library.gnome.org/devel/references,    however,   it    is    much      easier    to
    use Devhelp which is likely available as a package for your distribution. Devhelp allows
    you to browse and search the API documentation for the libraries you have installed on
    your system (assuming you install that libraries documentation as well).

         More information on GTK+ and Glib:

          Foundations of GTK+ Development (book)

          GTK+ 2.0 Tutorial

          GTK+ - The GIMP Toolkit



2
 GLib Reference Manual

           GTK+ Reference Manual

           GTK+ 2.0 Tutorial (C Programming)

           PyGTK+ 2.0 Tutorial (Python Programming)

    Introduction to Glade3

           Glade is a RAD (Rapid Application Development) tool for designing GTK+
     applications. Glade is a GTK+ application itself. It is simply a piece of software
     developers use to simplify the process of laying out an application's interface. Glade
     creates what will hereforth be refered to a s a "glade file". A glade file is actually an
     XML file which describes the heirachy of the widgets comprising the interface.

           Glade originally generated C code to build the GUI (and you'll still find examples
     and tutorials doing this). This was later discouraged in favor of using a library,
     Libglade, to build the interface at run time. And finally, as of Glade3, the old method
     has become deprecated. That means the ONLY thing glade does is allow you to
     generate a glade file which describes how the GUI is going to be built. This allows
     more flexibility with the developer, prevents having to re-compile applications when a
     minor interface change is needed, and allows more programming languages to be
     used with Glade.

           Glade3 has had significant changes since previous versions such as Glade2.
     Glade3 has been available for some time and you shouldn't have any problems
     obtaining it. The package manager for your distribution (yum, aptitude, etc.) should
     have Glade3 available. You should note however, that the package will have 3 in it.
     Where 'glade' may be the name for the old package, 'glade-3' or 'glade3' will be the
     package name for the new version on which this tutorial is based. Glade is also
     available from source at glade.gnome.org.

    Getting Familiar with the Glade Interface

           Start up Glade and let's get familiar with it's interface. I will be referring to various
     aspects of Glade by the names described here. On the left hand side is the "Palette".
     The Palette is like that of a graphics editing application. It is a palette of GtkWidgets
     which you can use to design your application. In the middle area (which is empty when
     you first start Glade) is the "Editor". This is where you see your design in progress. On
     the right hand side is the "Inspector" on top and the widget "Properties" below that.
     The Inspector shows your design as a tree allowing you to access and view the
     heirarchy of the widgets making up your design. We manipulate various properties of
     widgets in the Properties tabs, including specifying callback functions for signals
     (explained later).




3
So, the verfy first thing we're going to do, is create a Toplevel widget and save
     our file. To do this, Click on the GtkWindow icon               in the Palette under the
     'Toplevels' section. You should notice a gray box show up inside the Editor area of
     Glade. This is the workable area of a GtkWindow. The titlebar, close button, etc. will be
     added to the widget by the window manager (ie: GNOME) so we don't see it while
     editing. We will always start with a toplevel widget in Glade, typically a GtkWindow.

    Before going further, save the file as "tutorial.glade".




    Now the file you just saved, "tutorial.glade", is an XML file. If you were to open it up in a
    text editor, it would look something like this:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
    <!--Generated with glade3 3.4.0 on Tue Nov 20 14:05:37 2007 -->
    <glade-interface>
      <widget class="GtkWindow" id="window1">
        <property name="events">GDK_POINTER_MOTION_MASK |
    GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK |
    GDK_BUTTON_RELEASE_MASK</property>
         <child>
           <placeholder/>
         </child>
      </widget>
    </glade-interface>




4
As you can see, it's just a simple XML file. In part2 we will be using C with
    Libglade to parse this XML file and generate the UI at run-time. Being XML, this could
    just as easily be parsed by a Python program or any other language. As we continue to
    work in Glade, this file will be updated to describe our interface in this XML format any
    time we save. Exit out of your text editor and return to Glade.

    Manipulating Widget Properties

          The Editor of Glade now shows an empty GtkWindow widget. We are going to
     manipulate some of the widget's properties. If you look in the Properties pane of
     Glade, you will see 4 tabs: 'General', 'Packing', 'Common', and 'Signals'. Let's talk
     about the first 2 tabs. GtkWidgets typically have various properties which manipulate
     how they function and/or how they are displayed on the screen.

           If you look at the reference documentation for a GtkWidget and scroll down to the
     "Properties" section, you'll see a list of the properties for a GtkWindow. These are
     typically the properties which appear in the 'General' tab of the Glade properties pane
     and will vary from widget to widget. The name property exists for every widget in Glade
     and is what we will use to reference the widget when it comes time to write code for
     the application. Change the 'name' property of this GtkWindow from "window1" to
     "window". Then, add the text "GTK+ Text Editor" to the 'Window Title' property.




           We'll discuss the 'Packing' tab in a bit, but first, let's look at the 'Common' tab.
     This tab also contains properties which belong to our GtkWindow, however, we don't
     see them in the reference documentation for GtkWindow. This is because this is where
     we set properties which areinherited from parent objects. Looking at the reference
     documentation for a GtkWidget in the section called "Object Hierarchy", you'll see the
     objects from which GtkWindow is derived. Click on the GtkContainer link to jump to
     the reference documentation for a GtkContainer. You'll notice that GtkContainer has a



5
property called "border-width" and we have a property in Glade for "Border width" at
     the bottom of the 'Common' tab. We'll learn more about what a container widget is
     later, however, this demonstrates how important that object heirarchy is. Since many
     widgets are derived from GtkContainer, Glade puts it's properties into the 'Common'
     tab.

           In the "Object Hierarchy" section of the reference documentation for a
     GtkContainer you'll see that it is derived from a GtkWidget. Now click the GtkWidget
     link in to jump to the reference documentation for a GtkWidget. The GtkWidget has a
     bunch of properties, many of which are also shown in the 'Common' tab of Glade's
     Properties pane. These are properties which are common to all GTK+ widgets since all
     GTK+ widgets are derivitives of GtkWidget.




    Specifying Callback Functions for Signals

           Objects emit a "signal" when something that might be useful to the programmer
     happens. These are similiar to "events" from Visual Basic. If a user does anything
     within your GUI, chances are they are emitting signals. As a programmer, you choose
     which signals you want to capture and perform a task, and connect a callback function
     to that signal.

           The first signal we'll learn, and the one which you'll use in just about every GTK+
     application you write, is the "destroy" signal emitted by GtkObject. This signal is
     emitted whenever a GtkObject is destroyed. This is important, because when the user
     closes the window through the little 'x' up in the title bar or any other means, the widget
     is destroyed. We want to capture this signal and exit our application properly. This is
     better illustrated when we write code for this GUI, however, for now, let's just specify
     the function we want to call when the "destroy" signal is emitted for our GtkWindow.




6
Look at the 'Signals' tab in the Glade Properties pane. You see a tree view where
    GtkWindow and each of the objects from which it is derived are listed. If you expand
    the GtkObject, you'll see all the signals emitted by GtkObject. These correspond to the
    reference documentation for a GtkObject in the "Signals" section.

         Under the 'Handler' column, click the gray text "<Type here>" to begin editing.
    Select 'on_window_destroy' from the drop down and then hit ENTER. We can type
    anything we want here, however, glade provides a drop-down list of some of the mroe
    common callback function naming conventions. How this value is used depends on
    how the programmer connects signals in the code, however, for this tutorial, we want
    the GtkWindow's "destroy" signal to be associated with the handler string
    "on_window_destroy". We'll look at this closer in Part 2.




          At this point, we actually have a working GUI. We could write a few lines of code
    in C, Python, Ruby, or any number of programming languages which would show our
    empty window and then properly terminate when we clicked the "x" in the titlebar. For
    this tutorial however, I will be showing you how to build the entire GUI in Glade3 before
    writing any code. However, to satisfy any possible curiosity, if you would like to see
    what a simple program looks like that would implement this Glade interface so far...

         In C

         /*
         First     run   tutorial.glade     through    gtk-builder-convert      with    this
    command:
              gtk-builder-convert tutorial.glade tutorial.xml


         Then save this file as main.c and compile it using this command
         (those are backticks, not single quotes):




7
gcc -Wall -g -o tutorial main.c `pkg-config --cflags --libs gtk+-
    2.0` -export-dynamic


         Then execute it using:
              ./tutorial
         */
         #include <gtk/gtk.h>


         void
         on_window_destroy (GtkObject *object, gpointer user_data)
         {
                gtk_main_quit ();
         }


         int
         main (int argc, char *argv[])
         {
                GtkBuilder        *builder;
                GtkWidget         *window;


                gtk_init (&argc, &argv);


                builder = gtk_builder_new ();
                gtk_builder_add_from_file (builder, "tutorial.xml", NULL);
                window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
                gtk_builder_connect_signals (builder, NULL);


                g_object_unref (G_OBJECT (builder));


                gtk_widget_show (window);
                gtk_main ();


                return 0;
         }


        In Python (note: you must set the 'visible' property of 'window' to "Yes" in the
    'Common' properties tab in Glade)

         #!/usr/bin/env python


         # First     run     tutorial.glade   through   gtk-builder-convert   with   this
    command:




8
# gtk-builder-convert tutorial.glade tutorial.xml
          # Then save this file as tutorial.py and make it executable using
     this command:
          # chmod a+x tutorial.py
          # And execute it:
          # ./tutorial.py


          import pygtk
          pygtk.require("2.0")
          import gtk


          class TutorialApp(object):
            def __init__(self):
                 builder = gtk.Builder()
                 builder.add_from_file("tutorial.xml")
                 builder.connect_signals({       "on_window_destroy"      :   gtk.main_quit
     })
                 self.window = builder.get_object("window")
                 self.window.show()


          if __name__ == "__main__":
            app = TutorialApp()
            gtk.main()


           Again, I'm not going to go over the details of the code used to implement this GUI
     in this part of the tutorial, but instead focus on using Glade3. However, you can see
     that implementing an interface designed in Glade is just a few lines of code in the
     language of your choosing!

    Adding Widgets to the GtkWindow

          If you recall from the reference documentation for a GtkWindow, the GtkWindow
     is a derivative of GtkContainer. Widgets derived from GtkContainer are container
     widgets, meaning they can contain other widgets. This is another fundamental concept
     of GTK+ programming. If you come from a Windows programming background, you
     may be expecting to just drop a bunch of widgets onto the window and drag them
     around into the position you want them. But this is not how GTK+ works --and for good
     reason.

           GTK+ widgets "packed" into various containers. Containers can be packed into
     containers into containers and so forth. There are various packing properties which
     effect how space is allocated for widgets packed into containers. Through these




9
packing properties and nesting containers, we can have complex GUI designs without
     having to write code to handler the resizing and re-positioning of our widgets.

            This is probably one of the more difficult concepts for a new GTK+ developer, so
     let's just see it in action!

          The GtkWindow is a derivative of the container GtkBin which is a container that
     contains only one child widget. But this text editor is going to have 3 main sections; a
     menu bar, a text editing area, and a status bar. Therefore, we use a fundamental
     GTK+ widget, the GtkVBox. The GtkVBox (vertical box) is a container widget which
     can contain any number of child widgets stacked up vertically like rows (GtkHBox is
     the horizontal equivelant).

           Click on the GtkVBox icon         in the Glade Palette under the 'Containers' section.
     You'll notice that the 'Select' toolbar button on the top of the Glade window is no longer
     depressed and your mouse cursor is the GtkVBox icon with a plus (+) sign when
     hovering over the Glade Editor. This means you are ready to drop the GtkVBox
     somewhere. Click in gray area of the Editor which is the empty space of the
     GtkWindow.

          A dialog box pops up asking you for the 'Number of items'. In this case we want 3
     rows, so leave it as 3 and click 'OK'.




           You should see the GtkWindow in the Editor divided into 3 rows now. These are
     the 3 empty child widgets of the GtkVBox we just added. You should also notice that
     the 'Select' toolbar at the top of Glade is once again depressed--allowing you to select
     widgets within the Editor.




10
Next, click on the GtkMenuBar icon       in the Glade Palette under 'Containers'.
     Drop this one in the top row of the GtkVBox you just added.




           Now click on the GtkScrolledWindow icon            in the Glade Palette under
     'Containers'. Drop this one in to the middle row of the GtkVBox. When you do that, it
     may not seem like anything has happened. However, you should notice that that
     middle row looks selected. It's not--the GtkScrolledWindow is.The reason you don't
     see anything, is because a GtkScrolledWindow doesn't have any initial visible
     components. It's a container which will provide scroll bars when it's child widget gets
     too large. We'll need this for our text editing widget.




11
Click the GtkTextView icon      in the Glade Palette under 'Control and Display'.
     Drop this one right on top of that GtkScrolledWindow (the middle row). We have now
     just added the GtkTextView to the GtkScrolledWindow which was added to the
     GtkVBox.




          Finally, click on the GtkStatusbar icon    in the Glade Palette under 'Control and
     Display' and drop it into the bottom row.




          And there you have it; the basic layout of our GTK+ text editor. If you look at the
     Glade Inspector you will see the parent-child relationship of our design.




           The Inspector will come in handy. You cannot always click on a widget in the
     Editor as it might not be visible. For example, you cannot click on the
     GtkScrolledWindow we added, because you can only see it's child, the GtkTextView.




12
Therefore, if you need to change the properties of "scrolledwindow1", you will have to
      select it in the Inspector.

            I mentioned earlier how "packing" is an often frustrating concept to new GTK+
      developers. Therefore, I'm going to show you first hand how various packing effects
      the layout of your design.

     How Packing Effects the Layout

             When you look at the interface we've designed so far, you may take for granted
      how "smart" Glade was. How did it know we didn't want to make the status bar taller?
      Moreover, if you resize the window, how does it know that the text editing area grows
      to fill the new vertical space? Well, Glade guessed. It applied default packing options
      which are often what we want--but not always.

            The best way to learn about packing is to play around with packing properties in
      Glade as you can see the effects in real time. First, a quick description of the
      applicable properties. Once you get a feel for GTK+, you may want to read more on
      packing and space allocation.

            homogeneous: A property of the container widget which when set, tells
             GTK+ to allocate the same amount of space for each child.
            expand: A property of the child being packed specifying if it should recieve
             extra space when the parent grows.
            fill: A property of the child being packed specifying whether any extra space
             should be given to the child or used as padding around the child.

             Let's look at the default packing for our design. The GtkScrolledWindow has
      "expand"=TRUE which means it recieves extra space when the parent grows, and it
      has "fill"=TRUE which means it uses that extra space it recieves. This is how we want
      it to work.

                     Widget                       Property                Value

               GtkVBox "vbox1"                    homogeneous             FALSE

               GtkMenuBar "menubar1"              expand                  FALSE

                                                  fill                    TRUE

               GtkScrolledWindow                  expand                  TRUE
               "scrolledwindow1"




13
fill                    TRUE

               GtkStatusbar "statusbar1"           expand                  FALSE

                                                   fill                    TRUE



           Now, let's see what homogeneous does. Select the GtkVBox in the                Glade
     Inspector and change it's "Homogeneous" property under 'General' properties         tab to
     "Yes". Now the parent, "vbox1", allocates the same amount of space to each           of it's
     children. Since all 3 child widgets have "fill"=TRUE, they fill up this extra       space
     allocated to them.




          Set the "Homogeneous" property back to "No".

            Click on the GtkScrolledWindow "scrolledwindow1" in the Glade Inspector and
     set the "Expand" property in the 'Packing' properties tab to "No". Now none of the child
     widgets will recieve the extra space when the GtkVBox grows. I've highlighted the 3
     children in the image below to illustrate this. Each of the child widgets is it's initially
     requested size. The extra space allocated to the GtkVBox is simply unused since none
     of it's children want it (but still belongs to the GtkVBox).




14
Now set the "Expand" property of the GtkScrolledWindow back to "Yes" and
      change the "Fill" property to "No" instead. This time, the extra space is allocated to the
      GtkScrolledWindow since "expand"=TRUE, however, the GtkScrolledWindow doesn't
      use the space it was allocated since "fill"=FALSE.




           Set the "Fill" property back to "Yes" to restore our original packing properties.

            I know it seems odd at first, but as you continue to work in Glade, you'll start to
      pick up on how these packing properties work and once you've conquored that part of
      the learning curve, you'll be amazed at how little work you have to do related to the
      position and size of your GUI's elements.

     Editing the Menu (or Toolbar)

            Glade3 comes with a new Menu and Toolbar editor. Although we aren't using a
      GtkToolbar in this tutorial, the process is very similar to that of the GtkMenubar. We
      will use the Glade3 Menu Editor to remove many of the items we won't be using and to
      specify signal handlers for the menu items we will be using.

           Although you can manipulate the properties and signals of GtkMenuItems from
      the standard Glade properties pane and can remove items from the Glade Inspector,
      the Glade3 menu editor provides a simpler way to edit your application's m enu.

            Select the GtkMenuBar by clicking it in the Glade Editor or in the Glade Inspector.
      Then right-click and select 'Edit...' from the popup menu. This will launch the menu
      editor.




15
The menu editor contains properties just like Glade's main Properties pane and
     signals at the bottom just like the 'Signals' tab of Glade's main Properties pane. The
     main difference in the editor is the tree view on the left. It allows you easily add and
     remove menu items and drag them around. Go ahead and remove the one labeled
     "_View". This is the only menu item which Glade generates that we won't be using in
     this tutorial.

          For the remaining menu items we will need to do a few things. We need to
     rename them so that we have a clean, legible way to reference them in our source
     code. Then, we'll make some changes as a work around to a bug that might effect
     some readers using GTK+ 2.12.9 or below (Bug #523932), and finally we'll specify
     signal handlers. The steps for each of the menu items will be the same, so I'll just walk
     you through the 'New' menu item. Remember, this is all done in the menu editor but
     can also be done using the Inspector and Properties pane in glade.

          1. Click on the new menu item 'gtk-new'
          2. Change the 'Name' property under 'Menu Item' to "new_menu_item"
          3. Change the 'Label' property under 'Properties' to "_New" (note the
             underscore, that's an accellerator)
          4. Change the 'Stock Item' property under 'Properties' to "None"
          5. Click on another menu item such as 'gtk-open' and then click back to 'gtk-
             new' to refresh the properties (Bug #533503)
          6. Change the 'Stock Image' under 'Internal Image Properties' to the 'New'
             image
          7. Specify      a     handler     for      the     "activate"   signal callled
             "on_new_menu_item_activate" (This is done just like before, where we click
             the tree view to get a drop down list of possible signal names)


16
Now repeat those steps for each of the menu items: 'gtk-open', 'gtk-save', etc.
     Below are screen shots of the before and after on the 'New' menu item:




                              Glade Menu Editor before changes




17
Glade Menu Editor after changing 'New' menu item

     Final Touches to the Main Window

            It's never very easy to understand references to things like "textview1",
      "textview2", etc. when you're coding. So now that you know how to set properties,
      change the names of the following widgets (remember, the name is in the 'General' tab
      of the Properties pane):

           1. Rename "textview1" to "text_view"
           2. Rename "statusbar1" to "statusbar"

           And just to make it look a little nicer when the scroll bars are visible, let's add a a
      border and shadow to the GtkScrolledWindow

           1. Change the "Shadow Type" to "Etched In' in the 'General' properties tab for
              "scrolledwindow1"
           2. Change the "Border Width" to 1 in the 'Common' properties tab for
              "scrolledwindow1"
           3. Change the "Left Margin" to 2 in the 'General' properties for "text_view"
           4. Change the "Right Margin" to 2 in the 'General' properties for "text_view"




18
Part 2| Choosing a Programming Language for GTK+
                     Development
           In part 1 of the GTK+ and Glade3 GUI Programming Tutorial series, we designed a
     graphical user interface (GUI) for a GTK+ text editor application. After doing so, we were
     left with an XML file (tutorial.glade) which described our application's user interface.

           In this part of the GTK+ and Glade3 GUI Programming Tutorial series I will be
     discussing the various programming languages available for GTK+ development.
     Subsequent parts of this tutorial will cover both C programming and Python
     programming. With my help, you will have to make the decision of which one you want to
     learn how to use (or both!).

     Which is the BEST Language?

             Let's get this out of your system now. This is a question for which you can spend
      the rest of your life reading answers to--and each will be different. The problem is that
      this is the wrong question to ask as the answer is different for every person in each
      different circumstance. Each language comes with it's advantages and it's drawbacks.
      The question to ask: Which language is well suited for me on this particular project?

     Language Choice Considerations

            The important thing to remember when starting in with a language, is to keep an
      open mind about other languages. You may start GTK+ programming with language X,
      and later switch to language Y once you know and understand how it's benefits are
      suited to your task. The GTK+ concepts will remain the same from language to
      language.

             1. Experience Level
                How experienced you are with programming in general as well as how
                much time, patience, and devotion you are willing to spend are important
                factors in choosing a language. People without any programming
                experience have to learn fundamental programming concepts as well as
                the syntax and features of a new language. An experienced programmer
                can pick up a new language very quickly in comparison and can focus
                more on what the language has to offer as opposed to it's learning curve.
                Furthermore, if you're already a PHP expert, perhaps starting GTK+
                development with PHP might appeal to you. Maybe you took a course on
                C++ in college and want to start there. Maybe you only worked with Visual
                Basic but are ready to take the plunge and learn C.



19
2. Activity and Community Support
               GTK+ is written in C. Other languages are available through "language
               bindings" which "wrap" the functionality. How active the project is which
               provides said bindings is an important factor. You want to choose a
               language that is up-to-date with new releases of GTK+ and bug fixes (all
               languages I've mentioned are pretty well up to date). Furthermore, a
               strong user-base and thus large community will be important as you get
               most of your support from the community. The more people using a
               particular language for GTK+, the more information there will be readily
               available.
            3. Efficient Programmer vs. Efficient Program
               There's often a trade-off between how easy the program is to use and how
               efficient the program is in terms of speed and how much you can do with it
               on a lower-level. For many applications, the difference in efficiency of any
               two languages is negligable--and a new programmer would never even
               notice. For this reason, the increase in productivity is often the deciding
               factor. As and example, if I needed to write a program which allowed me to
               simply interface with some command-line utitlity through a GUI, I would
               likely choose Python or Ruby. However, if I were going to develop a
               sophisticated, powerful IDE, I would likely choose C or C++. In fact, you
               can even use several languages in one project! You could write the
               memory or processor intensive routines in C or C++ and do the rest in
               Python or Ruby.
            4. Language Sexiness
               That's right-- how a language looks and feels is often a factor. You spend
               a lot of time staring at that code. How it flows on the screen, how it reads,
               and the overall development process in a particular language might appeal
               to you more than another. You should enjoy the programming you're
               doing. It's great having options isn't it!

     A Look at Python vs. C

           I have chosen to fork this tutorial into 2 languages based on the above criteria. It
      is my humble opinion that C and Python fit the above criteria best. Both have very,
      very strong community support and are being used for a large portion of the projects
      developed for Linux and especially GNOME. Furthermore, they sit on sort of opposite
      ends of the spectrum with regard to the efficiency vs. productivity debate. You could
      even follow this tutorial down both paths and compare the 2 languages yourself.

          If you have no programming experience, or perhaps just a little experience with
      something like Visual Basic or PHP, I recommend starting with Python. Even if you are




20
an experienced programmer with C, C++, or Java experience you may want to learn
     Python. It's an exciting modern language, fun to program with, and incredible quick to
     learn and use. For Rapid Application Development in Linux, Glade and Python make a
     great team. Learn more about the Python GTK+ binding PyGTK at www.pygtk.org.

           If you're an experienced programmer or dedicated student, it may be worth your
     while to learn C or C++ for GTK+ development--especially if you're already familiar
     with C or C++. Learning GTK+ in C makes switching to another language such as
     Python a breeze. Furthermore, you'll have more options for contributing to existing
     projects. Personally, I do the majority of my GTK+ development in C despite the extra
     time it takes.




21
Part 3| Writing a Basic Program to Implement
                       the Glade File
           In this part of the GTK+ and Glade3 GUI Programming Tutorial series, I will s how
     you a very basic program that will parse the Glade file we created in Part 1 and display
     the main window for our GTK+ text editor. In this part of the tutorial, I will be discussing
     the GTK+ concepts first and then show the code in both Python and C (in different
     colors). If you have chosen to work in one language or the other, you can opt to skip
     over the code explanation for the language you are not going to use.

     Setting Up Your Development Environment

            To work with GTK+ and complete this step of the tutorial you will need a text
      editor, a terminal window, the GTK+ development libraries, and optionally Devhelp, the
      developer's help reference. If you're new to the Linux world, welcome to lots of options.
      There isn't one particular editor or IDE that is the "standard". Most developers actually
      work with their favorite text editor and a terminal window. Although there are some "full
      featured" IDEs out there, you may want to stick with a plain text editor and terminal at
      this point so as not to be overwhelmed or tripped up by features and automated tasks
      the IDE might perform.

           I do my work using Gedit, the default GNOME text editor. There           is a plugins
      package available for Gedit which contains a terminal plugin and I have        written Gedit
      Symbol Browser Plugin which allows you to quickly jump to functions in         your source
      code. Below are Gedit screenshots from my system while working on this        tutorial (click
      to see full-size).




22
Working in C




                                    Working in Python

          The development libraries you will need depend both on your distribution and
     whether you want to work in Python or C. Although the process can vary greatly



23
depending on your platform and distribution, I can give you the information you need to
      get started. If you have problems installing any of the packages you need, post your
      problem or question at the GTK+ Forums or a forum for your distribution.

            When it comes to development libraries with Linux, you can often get all the
      packages you need using your distributions package manager to resolve
      dependencies. For example, on Ubuntu you can likely just issue the command: 'sudo
      aptitude install libgtk-2.0-dev'. This command will install the GTK+ development
      package, it's dependencies, their dependencies, and so on.

             It's important to install the "development packages". These are suffixed with "-
      dev" in Ubuntu/Debian and "-devel" in Redhat/Fedora. The development packages
      include header files and other includes that allow you to build applications which use a
      particular library. Just remember, "package" allows you to run applications using that
      library where "package-dev" or "package-devel" allows you to write applications using
      that library.

           Another prefix you will see on packages is "-doc" such as "libgtk2.0-doc". This will
      be the documentation for that library and once installed will allow you to browse the
      documentation using Devhelp: the GNOME developer's help browser.

           If you're programming with C you should install the following packages with their
      dependencies: build-essential, libgtk2.0-dev, libgtk2.0-doc, libglib2.0-doc, devhelp
      (package names may vary depending on distribution, these are for Ubuntu).

            If you're programming with Python you should install the following packages with
      their dependencies: python2.5-dev python2.5-doc, python2.5-gtk2, python-gtk2-doc,
      python-gobject-doc, devhelp (package names may vary depending on distribution,
      these are for Ubuntu).

     GtkBuilder and LibGlade

             If you recall, the file we created with Glade in part 1 of this tutorial series
      (tutorial.glade) was an XML filedescribing our GUI. The actual GUI will be built by our
      program. Therefore, the program will have to open and parse the XML file and create
      instances of the widgets described within. There is already a library written to perform
      this task--2 libraries in fact.

             LibGlade was originally the library used to parse the glade file and create the
      widgets described within. At the time of writing, this will still be the more commonplace
      method used in other tutorials and books. However, GTK+ 2.12 included an object
      called GtkBuilder which is essentially the same thing and is built right in to GTK+. As
      this is intended to eventually replace Libglade, we will be using GtkBuilder in this
      tutorial. However, as you learn and look at code elsewhere on the internet, keep in
      mind that anywhere you see LibGlade being used, GtkBuilder can be used instead.


24
Since (at the time of writing) GtkBuilder is relatively new, Glade does not yet
      support saving in the GtkBuilder format. The GtkBuilder format is still an XML file, but
      with a slightly different schema. That means that in order to use GtkBuilder on a glade
      file, we must first convert it to the GtkBuilder format. GTK+ 2.12 provides a conversion
      script for this process, and will already be installed on your system at this point.

            You can read some of the common questions                    I get    about all this
      Libglade/GtkBuilder stuff at Libglade to GtkBuilder F.A.Q..

             So we now convert the glade XML file tutorial.glade to the GtkBuilder XML file
      tutorial.xml with the following command:

           gtk-builder-convert tutorial.glade tutorial.xml


             The file 'tutorial.xml' is the file we will actually parse in our program, however, we
      still need tutorial.glade when we want to make changes using Glade. This is only
      necessary until Glade supports the GtkBuilder format in a later version (They are
      aiming to have this ready by Glade 3.6 which you can follow along Bug #490678).

     The Minimal Application

           We're finally ready to write some code! Let's just recap what we've done so far.

           1. Using Glade, we created tutorial.glade which describes our user interface.
           2. We've selected which language we will use to write our program; Python, C,
              or both.
           3. We have a text editor and a terminal window available.
           4. We have installed the development libraries we need to program GTK+
              applications.
           5. Using gtk-builder-convert, we converted tutorial.glade to tutorial.xml for use
              with GtkBuilder.

            Now, before we start digging in to all the details of what each line of code does,
      we are going to write a minimal application just to ensure everything works and get
      acquainted with the development process. So, open up your text editor and type in the
      following...

           If you're programming in C

           #include <gtk/gtk.h>


           void
           on_window_destroy (GtkObject *object, gpointer user_data)
           {



25
gtk_main_quit();
         }


         int
         main (int argc, char *argv[])
         {
                   GtkBuilder                     *builder;
                   GtkWidget                      *window;


                   gtk_init (&argc, &argv);


                   builder = gtk_builder_new ();
                   gtk_builder_add_from_file (builder, "tutorial.xml", NULL);


                   window      =    GTK_WIDGET      (gtk_builder_get_object   (builder,
     "window"));
                   gtk_builder_connect_signals (builder, NULL);
                   g_object_unref (G_OBJECT (builder));


                   gtk_widget_show (window);
                   gtk_main ();


                   return 0;
         }


         Save this file as 'main.c' in the same directory as 'tutorial.xml'

         If you're programming in Python

         import sys
         import gtk


         class TutorialTextEditor:


               def on_window_destroy(self, widget, data=None):
                   gtk.main_quit()


               def __init__(self):


                   builder = gtk.Builder()
                   builder.add_from_file("tutorial.xml")


                   self.window = builder.get_object("window")



26
builder.connect_signals(self)


           if __name__ == "__main__":
                editor = TutorialTextEditor()
                editor.window.show()
                gtk.main()


           Save this file as 'tutorial.py' in the same directory as 'tutorial.xml'

     Compiling and Running the Application

      If you're programming in C

             Since C is a compiled language, we need to use the gcc compiler to compile our
      source code into a binary application. In order for gcc to know where the GTK+
      libraries are that it needs to link to and what compiler flags to use, we use a program
      called pkg-config. When we installed the GTK+ development package, a package-
      config file named 'gtk+-2.0.pc' was installed on our system. This file tells the pkg-config
      program which version of the GTK+ libraries are installed and where the include files
      live on our system. To illustrate this, type the following command in your terminal:

           pkg-config --modversion gtk+-2.0


            The output should show the version of GTK+ you have installed. On my system it
      shows '2.12.0'. Now let's look at what compiler flags are needed to build a GTK+
      application on my system:

           pkg-config --cflags gtk+-2.0


             The output of that command shows a bunch of -I switches which are specifying
      include paths for the compiler to use. This will tell gcc where to look for include files
      when we use '#include' in our application. The very first one on my system is '-
      I/usr/include/gtk-2.0'. That means that when I use '#include <gtk/gtk.h>' in my code,
      gcc will be able to find '/usr/include/gtk-2.0/gtk/gtk.h'.

             Anytime you use a '#include <library/header.h>' style include that is not part of
      the standard C library in your code, there should be a '-I/path/to/library' style option
      passed to gcc. These libraries can be installed in different locations based on
      distribution, operating system, or user preference. Good thing we have pkg-config to
      handle all of this for us!

           Let's compile our application so far. Issue this command in the terminal (make
      sure you are in the same directory in which both 'main.c' and 'tutorial.xml' reside:




27
gcc -Wall -g -o tutorial main.c -export-dynamic `pkg-config --cflags
     --libs gtk+-2.0`


            The '-Wall' option tells gcc to show all warnings. The '-g' option will generate
     debugging information which will be useful should you have a bug in your application
     and need to step through the code using a debugger such as gdb. The option '-o
     tutorial' tell gcc to generate the output executable into a file named 'tutorial'. 'main.c' is
     the file gcc will compile. The '-export-dynamic' has to do with how we connect signals
     to callback functions which will be discussed when we step through the code. And
     finally, the pkg-config command appears.

            Notice how it is enclosed in backticks (those are not single quotes). The backtick
     is usually to the left of the '1' key on th e keyboard with the tilde character (~). This is
     telling our shell to first execute the command 'pkg-config --cflags --libs gtk+-2.0' and
     put the output of that command into the current command. So if you execute 'pkg-
     config --cflags --libs gtk+-2.0' on your system and then paste it's output onto the end of
     that gcc command, it would be virtually the same thing. By using pkg-config to append
     the include paths and library paths to our compile command, we can use the same
     command to compile our program on any system, regardless of where those libraries
     are installed.

            After your application compiles, there should be a new executable file named
     'tutorial' which you execute using:

          ./tutorial


          When you do so, you are going to see several warnings from GTK, something
     along the lines of " Gtk-WARNING **: Could not find signal handler 'xxxxxx'". Don't
     worry about those for now. Those are telling use that we specified a signal handler in
     our glade file which we did not yet write a function for. I'll address these when we step
     through the code. But you should have seen your GTK+ Text Editor window show up,
     and clicking the 'x' in the window titlebar should properly terminate the application.

          If for some reason you were not able to get the application to compile or execute,
     post your error messages and any other information in the GTK+ Forums.

          If you're programming in Python

          Since Python is an Interpreted Language we don't need to compile our program.
     We simply invoke the Python interpreter, which we actually do with the first line in our
     source code. So all we need to do to run our Python program, is change the
     permissions so that the file is executable and then run it. Change the permissions
     using:

          chmod a+x tutorial.py



28
And now you can run it using:

           ./tutorial.py


              you should have seen your GTK+ Text Editor window show up, and clicking the
      'x' in the window titlebar should properly terminate the application.

           If for some reason you were not able to get the application to compile or execute,
      post your error messages and any other information in the GTK+ Forums.

     Stepping Through the Code

           Note: You should be looking up each new function in the GTK+ reference
      documentation as I introduce them. Get to know that documentation, it will be your
      best friend. Install Devhelp, use it! I will provided a link to the online reference
      documentation each time I introduce a new function in case you were unable to install
      Devhelp.

     Including the GTK+ Library

                 If you're programming in C

                 Hopefully you know enough about C programming to understand the first
           line '#include <gtk/gtk.h>'. If you don't, you should probably go back and work
           through a basic C programming tutorial before continuing with this one. By
           including gtk.h, we are indirectly including a multitude of header files. In fact, with
           only a few exceptions, we are including all of the GTK+ library and it's
           dependencies including GLib. If you want to know exactly what is being included
           just take a look at that file! Essentially, when you're looking through the reference
           manuals, you have access to most of the functions beginning with gtk_, g_, gdk_,
           pango_, and atk_.

                 If you're programming in Python

                  Hopefully you know enough about Python programming to understand the
           first two lines '#import sys' and '#import gtk'. If you don't, you should probably go
           back and work through a basic Python programming tutorial before continuing
           with this one. We now have access to all gtk.x classes.




     Initializing the GTK+ Library

                   Python implicitly initializes the GTK+ library for you. In C however, we must
           initialize the GTK+ library before ANY call to a GTK+ function!



29
If you're programming in C

                gtk_init (&argc, &argv);


                 Looking in 'main()' we see that we initialize GTK+ before anything else using
           the gtk_init() function.

     Building the Interface with GtkBuilder

                  In a GTK+ application written entirely through code, that is, without the
           assistance of Glade or another interface designer, we would have to
           programatically create each widget, set the various properties of that widget, and
           add it to it's parent widget where applicable. Each of these steps could require
           several lines of code for each widget. That can be tedious. Just think about the
           interface we created in part 1. There are over 20 widgets defined (including all
           the menu items). To create all those widgets through pure code could exceed a
           hundred lines of lines of code once all the properties were applied!

                 Good thing we're using Glade and GtkBuilder. With just 2 lines of code,
           GtkBuilder will open and parse tutorial.xml, create all the widgets defined within,
           apply their properties, and establish the widgets' parent-child relationships. Once
           that is done we can then ask builder for the references to the widgets we want to
           further manipulate or otherwise reference.




30
If you're programming in C

          builder = gtk_builder_new ();
          gtk_builder_add_from_file (builder, "tutorial.xml", NULL);


             The first variable we declared in main() was a pointer to a GtkBuilder object. We
     initialize that pointer usinggtk_builder_new(). This function will create a new GtkBuilder
     object and return the pointer to that object which we are storing in the 'builder' variable.
     Just about all GTK+ objects will be created in this fashion.

          The builder object at this point hasn't built any UI elements yet. We can
     use gtk_builder_add_from_file() to parse our XML file 'tutorial.xml' and add it's
     contents to the builder object.

          We are passing NULL as the third parameter to gtk_builder_add_from_file()
     because we are not going to learn about GError just yet. So we do not have any error
     checking yet and if the tutorial.xml file is not found or some other error occurs, our
     program will crash, but we'll address that later.




31
You will notice that after calling gtk_builder_new() to create a new builder object,
      all the other gtk_builder_xxx functions take that builder object as the first parameter.
      This is how GTK+ implements object oriented programming in C, and will be consistent
      with all GTK+ objects (compare that with how Python, a natural OOP language
      implements the same thing below).

           If you're programming in Python

           builder = gtk.Builder()
           builder.add_from_file("tutorial.xml")


              When we initialize the TutorialTextEditor class with 'editor = TutorialTextEditor()'
      the class's initialization method, '__init__', is called. The first thing this method does is
      initialize a new gtk.Builder class withgtk.Builder(). The builder instance is local to the
      __init__ method because once we build our UI, we will no longer need the builder
      object.

            The builder object at this point hasn't built any UI elements yet. We
      use gtk.Builder.add_from_file() to parse our XML file 'tutorial.xml' and add it's contents
      to the builder object.

     Getting References to Widgets From GtkBuilder

            Once the builder has created all of our widgets we will want to get references to
      some of those widgets. We only need references to some of the widgets because
      some of them have already done their job and need no further manipulation. For
      example, the GtkVBox which holds our menu, text view, and statusbar has already
      done it's job of laying out our design and our code does not need to access it. So, we
      need to get a reference to any widget we will manipulate during the lifetime of our
      application and store it in a variable. At this point in the tutorial, we only need to
      reference the GtkWindow named "window" so that we can show it.

           If you're programming in C

           window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));


            A couple things are happening here. First, let's look at gtk_builder_get_object().
      The first parameter is the object from which we want to get an object. Again, this is
      how OOP is implemented in C. The second parameter is the name of the object we
      want to get a pointer to. This corresponds to the 'name' we specified for the widget in
      Glade during part 1. If you recall, we named the main application GtkWindow 'window'.
      So, that's what we pass to gtk_builder_get_object().

            The gtk_builder_get_object() function returns a pointer to a GObject and we are
      storing this pointer in 'window' which we declared at the beginning of main() as a


32
pointer to a GtkWidget. Moreover, we know that the object we are trying to get was a
      GtkWindow. This is why I placed so much emphasis on the 'Object Hierarchy' of
      widgets and GTK+ objects. If you look at the Object Hierarchy for a GtkWindow you
      will see that GtkWidget is one of it's ancestors as is GObject. Therefore, a
      GtkWindow is a GObject and it is a GtkWidget. This is a fundamental OOP concept
      and critical to working with GTK+.

            So, the GTK_WIDGET() wrapped around the call to gtk_builder_get_object() is a
      convenience macro used for casting. You can cast a GTK+ widget into any of it's
      ancestors using one of these casting macros. All GTK+ objects will have them
      available. So, 'GTK_WIDGET(something)' is the same as '(GtkWidget*)something'.
      We're casting the pointer to a GObject returned from the call to
      gtk_builder_get_object() to a pointer to a GtkWidget as that's what 'window' was
      declared as.

             Finally, the reason we declared window as a pointer to a GtkWidget in the
      beginning of main() rather than as a pointer to a GtkWindow is due to convention. We
      could have declared it as a GtkWindow* and that would have still been correct. All
      GTK+ widgets are derived from a GtkWidget so we can always declare a variable
      pointing to any GTK+ widget as such. Many functions take GtkWidget* as a paramter
      and many functions return GtkWidget* and thus it usually makes sense to declare your
      variables as such and simply cast them to the specific widget where applicable (which
      you'll see later).

           If you're programming in Python

           self.window = builder.get_object("window")


            We are using gtk.Builder.get_object() to get the object named "window" from the
      builder. This corresponds to the 'name' we specified for the widget in Glade during part
      1. If you recall, we named the main application's GtkWindow 'window'. So, that's what
      we pass to get_object(). We assign the returned object to self.window so that we have
      access to the application's window anywhere within the TutorialTextEditor() class.

     Connecting Callback Functions to Signals

             In part 1 we specified "handlers" for various "signals" in our interfac e. If you
      recall, GTK+ emits signals for various events that occur. This is a fundamental concept
      of GUI programming. Our application needs to know when the user does something so
      that it can respond to that action. As we'll see soon, our application just sits around in a
      loop waiting for something to happen. We will be using GtkBuilder to connect the
      signal handlers we defined using Glade with callback functions in our code. GtkBuilder
      will look at our code's symbols and connect the appropriate handlers for us.




33
In part 1 we specified a handler named 'on_window_destroy' for the "destroy"
     signal of the GtkWindow named 'window'. Therefore, GtkBuilder will expect to find a
     function or method named 'on_window_destroy'. The "destroy" signal is emitted when
     a GtkObject is destroyed. As we'll see in the next bit of code, our application is going to
     sit in an infinite loop waiting for events to happen. When the user closes the window
     (such as clicking the 'x' in the titlebar), our application will need to break out of the loop
     and terminate. By connecting a callback to the "destroy" signal of the GtkWindow we
     will know when to terminate. Therefore, this is a signal you will use in almost every
     GTK+ application you write.

           Note: The method being used to connect callbacks to signals in this example is
     equivalent to using glade_xml_signal_autoconnect() function when using LibGlade
     instead of GtkBuilder.

          If you're programming in C

          gtk_builder_connect_signals (builder, NULL);


           When we call gtk_builder_connect_signals() we pass the builder object as the
     first parameter as always. The second parameter allows us to pass user data
     (anything we want) to our callback function. This will be important later, but for now
     we'll just pass NULL. This function uses GModule, a part of GLib used to dynamically
     load modules, to look at our applications symbol table (function names, variable
     names, etc.) to find the function name that matches the handler name we specified in
     Glade.

           In Glade we specified a handler for the GtkWindow's "destroy" signal called
     'on_window_destroy'. So, gtk_builder_connect_signals() is looking for a function
     named 'on_window_destroy' that matches the signature of the callback function for the
     "destroy" signal. If you recall from part 1, the "destroy" signal belonged to GtkObject.
     Therefore, we find the prototype for the callback function in the manual for GtkObject
     under the 'signals' section: GtkObject "destroy" Signal. This tells us what the prototype
     for our callback function should look like.

          Based on the prototype specified in the manual, I wrote the following function:

          void
          on_window_destroy (GtkObject *object, gpointer user_data)
          {
                    gtk_main_quit();
          }


         So now gtk_builder_connect_signals() will find this function and see that it both
     matches the name of the handler we specified in Glade and has a compatible



34
signature (takes the same arguments) as that specified for the "destroy" signal and
     makes the connection. Now our function on_window_destroy() will be called when the
     GtkWindow 'window' is destroyed.

           In on_window_destroy() we just call gtk_main_quit() to properly terminate our
     application. This function will break out of the main loop which I will talk about more
     when we get there in just a bit.

          Right after the     call   to   gtk_builder_connect_signals()   there   was   a   call
     to g_object_unref().

          g_object_unref (G_OBJECT (builder));


           This is because we are no longer going to use the GtkBuilder object. We used it
     to construct our widgets and then we obtained pointers to the widgets we needed to
     reference. So now we can free all the memory it used up with XML stuff.

          You'll also noticed that we are using one of those casting macros to cast
     (GtkBuilder*) to (GObject*). We must do this because g_object_unref() takes a
     GObject* as a parameter. Since a GtkBuilder is derived from a GObject (as are all
     widgets) this is perfectly valid.

          If you're programming in Python

          builder.connect_signals(self)


           In Glade we specified a handler for the GtkWindow's "destroy" signal called
     'on_window_destroy'. So,gtk.Builder.connect_signals() is looking for a method named
     'on_window_destroy' that matches the signature of the callback method for the
     "destroy" signal. If you recall from part 1, the "destroy" signal belonged to GtkObject.
     Therefore, we find the prototype for the callback function in the manual for gtk.Object
     under the 'signals' section: gtk.Object "destroy" Signal. This tells us what the prototype
     for our callback method should look like.

          Based on the prototype specified in the manual, I wrote the following method:

          def on_window_destroy(self, widget, data=None):
               gtk.main_quit()


          So now builder.connect_signals() will find this method and see that it both
     matches the name of the handler we specified in Glade and has a compatible
     signature (takes the same arguments) as was specified for the "destroy" signal and
     makes the connection. Now our method on_window_destroy() will be called when the
     GtkWindow 'window' is destroyed.




35
In on_window_destroy() we just call gtk.main_quit() to properly terminate our
      application. This function will break out of the main loop which I will talk about more
      when we get there in just a bit.

     Showing the Application Window

          Before we enter the GTK+ main loop (discussed next), we want show our
      GtkWindow widget as our app doesn't do much good if it's not even visible.

           If you're programming in C

           gtk_widget_show (window);


          Calling gtk_widget_show() sets the Widget's GTK_VISIBLE flag telling GTK+ to
      show the widget (which will happen within the GTK+ main loop discussed next).

           If you're programming in Python

           editor.window.show()


            Calling gtk.Widget.show() tells GTK+ to show the widget (which will happen
      within the GTK+ main loop discussed next).

     Entering the GTK+ Main Loop

             The main loop in GTK+ is an infinite loop which performs all of the "magic". This
      is how GUI programming works. Once we build our GUI and setup our program, we
      enter the GTK+ main loop and just wait for an event to occur which we care about
      (such as closing the window). A lot is happening inside this main loop, however, for a
      beginner you can simply think of it as an infinate loop in which GTK+ checks the state
      of things, updates the UI, and emits signals for events.

            After entering the main loop, our application isn't doing anything (but GTK+ is).
      When the user resizes the window, minimizes it, clicks on it, presses keys, etc. GTK+
      is checking each of these events and emitting signals for them. However, our
      application is only connected to one signal currently, the "destroy" signal of 'window'.
      When the window is closed and the "destroy" signal is emitted, then the GTK+ main
      loop will turn over control to the handler function we have connected to that signal
      which breaks us out of the GTK+ main loop thus allowing our application to terminate.

           If you're programming in C

           gtk_main ();


           If you're programming in Python



36
gtk.main()


     In Summary

          1. Application uses GtkBuilder to create the GUI from XML file.
          2. Application gets reference to main window widget.
          3. Application connects 'on_window_destroy' handler to the "destroy" signal.
          4. Application flags the window to be shown.
          5. Application enters GTK+ main loop (window is shown).
          6. User clicks the 'x' in the titlebar as a result of which GTK+ main loop emits
             the "destroy" signal.
          7. Handler 'on_window_destroy' breaks out of GTK+ main loop.
          8. Application terminates normally.




37

More Related Content

What's hot

Linux kernel tracing
Linux kernel tracingLinux kernel tracing
Linux kernel tracingViller Hsiao
 
SR-IOV+KVM on Debian/Stable
SR-IOV+KVM on Debian/StableSR-IOV+KVM on Debian/Stable
SR-IOV+KVM on Debian/Stablejuet-y
 
MySQL Operator for Kubernetes
MySQL Operator for KubernetesMySQL Operator for Kubernetes
MySQL Operator for KubernetesKenny Gryp
 
DPDK (Data Plane Development Kit)
DPDK (Data Plane Development Kit) DPDK (Data Plane Development Kit)
DPDK (Data Plane Development Kit) ymtech
 
IntelON 2021 Processor Benchmarking
IntelON 2021 Processor BenchmarkingIntelON 2021 Processor Benchmarking
IntelON 2021 Processor BenchmarkingBrendan Gregg
 
High performance computing language,julia
High performance computing language,juliaHigh performance computing language,julia
High performance computing language,juliaAnusha sweety
 
High-Performance Networking Using eBPF, XDP, and io_uring
High-Performance Networking Using eBPF, XDP, and io_uringHigh-Performance Networking Using eBPF, XDP, and io_uring
High-Performance Networking Using eBPF, XDP, and io_uringScyllaDB
 
LISA2019 Linux Systems Performance
LISA2019 Linux Systems PerformanceLISA2019 Linux Systems Performance
LISA2019 Linux Systems PerformanceBrendan Gregg
 
Stateful Flow Table - SFT 2020 DPDK users pace summit
Stateful Flow Table - SFT 2020 DPDK users pace summitStateful Flow Table - SFT 2020 DPDK users pace summit
Stateful Flow Table - SFT 2020 DPDK users pace summitAndrey Vesnovaty
 
How Linux Processes Your Network Packet - Elazar Leibovich
How Linux Processes Your Network Packet - Elazar LeibovichHow Linux Processes Your Network Packet - Elazar Leibovich
How Linux Processes Your Network Packet - Elazar LeibovichDevOpsDays Tel Aviv
 
WALT vs PELT : Redux - SFO17-307
WALT vs PELT : Redux  - SFO17-307WALT vs PELT : Redux  - SFO17-307
WALT vs PELT : Redux - SFO17-307Linaro
 
Kernel Recipes 2017 - 20 years of Linux Virtual Memory - Andrea Arcangeli
Kernel Recipes 2017 - 20 years of Linux Virtual Memory - Andrea ArcangeliKernel Recipes 2017 - 20 years of Linux Virtual Memory - Andrea Arcangeli
Kernel Recipes 2017 - 20 years of Linux Virtual Memory - Andrea ArcangeliAnne Nicolas
 
X / DRM (Direct Rendering Manager) Architectural Overview
X / DRM (Direct Rendering Manager) Architectural OverviewX / DRM (Direct Rendering Manager) Architectural Overview
X / DRM (Direct Rendering Manager) Architectural OverviewMoriyoshi Koizumi
 
QEMU - Binary Translation
QEMU - Binary Translation QEMU - Binary Translation
QEMU - Binary Translation Jiann-Fuh Liaw
 
Performance Tuning EC2 Instances
Performance Tuning EC2 InstancesPerformance Tuning EC2 Instances
Performance Tuning EC2 InstancesBrendan Gregg
 
Async ... Await – concurrency in java script
Async ... Await – concurrency in java scriptAsync ... Await – concurrency in java script
Async ... Await – concurrency in java scriptAthman Gude
 
Kernel Process Management
Kernel Process ManagementKernel Process Management
Kernel Process Managementpradeep_tewani
 

What's hot (20)

Linux kernel tracing
Linux kernel tracingLinux kernel tracing
Linux kernel tracing
 
SR-IOV+KVM on Debian/Stable
SR-IOV+KVM on Debian/StableSR-IOV+KVM on Debian/Stable
SR-IOV+KVM on Debian/Stable
 
C Programming - Refresher - Part III
C Programming - Refresher - Part IIIC Programming - Refresher - Part III
C Programming - Refresher - Part III
 
Git hub
Git hubGit hub
Git hub
 
MySQL Operator for Kubernetes
MySQL Operator for KubernetesMySQL Operator for Kubernetes
MySQL Operator for Kubernetes
 
DPDK (Data Plane Development Kit)
DPDK (Data Plane Development Kit) DPDK (Data Plane Development Kit)
DPDK (Data Plane Development Kit)
 
IntelON 2021 Processor Benchmarking
IntelON 2021 Processor BenchmarkingIntelON 2021 Processor Benchmarking
IntelON 2021 Processor Benchmarking
 
High performance computing language,julia
High performance computing language,juliaHigh performance computing language,julia
High performance computing language,julia
 
Linux Internals - Part II
Linux Internals - Part IILinux Internals - Part II
Linux Internals - Part II
 
High-Performance Networking Using eBPF, XDP, and io_uring
High-Performance Networking Using eBPF, XDP, and io_uringHigh-Performance Networking Using eBPF, XDP, and io_uring
High-Performance Networking Using eBPF, XDP, and io_uring
 
LISA2019 Linux Systems Performance
LISA2019 Linux Systems PerformanceLISA2019 Linux Systems Performance
LISA2019 Linux Systems Performance
 
Stateful Flow Table - SFT 2020 DPDK users pace summit
Stateful Flow Table - SFT 2020 DPDK users pace summitStateful Flow Table - SFT 2020 DPDK users pace summit
Stateful Flow Table - SFT 2020 DPDK users pace summit
 
How Linux Processes Your Network Packet - Elazar Leibovich
How Linux Processes Your Network Packet - Elazar LeibovichHow Linux Processes Your Network Packet - Elazar Leibovich
How Linux Processes Your Network Packet - Elazar Leibovich
 
WALT vs PELT : Redux - SFO17-307
WALT vs PELT : Redux  - SFO17-307WALT vs PELT : Redux  - SFO17-307
WALT vs PELT : Redux - SFO17-307
 
Kernel Recipes 2017 - 20 years of Linux Virtual Memory - Andrea Arcangeli
Kernel Recipes 2017 - 20 years of Linux Virtual Memory - Andrea ArcangeliKernel Recipes 2017 - 20 years of Linux Virtual Memory - Andrea Arcangeli
Kernel Recipes 2017 - 20 years of Linux Virtual Memory - Andrea Arcangeli
 
X / DRM (Direct Rendering Manager) Architectural Overview
X / DRM (Direct Rendering Manager) Architectural OverviewX / DRM (Direct Rendering Manager) Architectural Overview
X / DRM (Direct Rendering Manager) Architectural Overview
 
QEMU - Binary Translation
QEMU - Binary Translation QEMU - Binary Translation
QEMU - Binary Translation
 
Performance Tuning EC2 Instances
Performance Tuning EC2 InstancesPerformance Tuning EC2 Instances
Performance Tuning EC2 Instances
 
Async ... Await – concurrency in java script
Async ... Await – concurrency in java scriptAsync ... Await – concurrency in java script
Async ... Await – concurrency in java script
 
Kernel Process Management
Kernel Process ManagementKernel Process Management
Kernel Process Management
 

Viewers also liked

GUI in Gtk+ con Glade & Anjuta
GUI in Gtk+ con Glade & AnjutaGUI in Gtk+ con Glade & Anjuta
GUI in Gtk+ con Glade & Anjutadelfinostefano
 
Taller Python Gtk Glade
Taller Python Gtk GladeTaller Python Gtk Glade
Taller Python Gtk Gladecampus party
 
Presentación de glade
Presentación de gladePresentación de glade
Presentación de gladejorgiux97
 
Introduction to Application Development in Python and Gtk+ / Hildon @ Maemo 5
Introduction to Application Development in Python and Gtk+ / Hildon @ Maemo 5Introduction to Application Development in Python and Gtk+ / Hildon @ Maemo 5
Introduction to Application Development in Python and Gtk+ / Hildon @ Maemo 5Amanda Lam
 
Multimedia in WebKitGTK+ (FOSDEM 2010)
Multimedia in WebKitGTK+ (FOSDEM 2010)Multimedia in WebKitGTK+ (FOSDEM 2010)
Multimedia in WebKitGTK+ (FOSDEM 2010)Igalia
 
Introduce gobject introspection
Introduce gobject introspectionIntroduce gobject introspection
Introduce gobject introspectionYoung-Ho Cha
 
SqueakGTK
SqueakGTKSqueakGTK
SqueakGTKESUG
 
نگاهی به Gtk3
نگاهی به Gtk3نگاهی به Gtk3
نگاهی به Gtk3Ali Vakilzade
 
LCA2013 : Implementing threaded accelerated compositing in WebKitGtk+
LCA2013 :  Implementing threaded accelerated compositing in WebKitGtk+LCA2013 :  Implementing threaded accelerated compositing in WebKitGtk+
LCA2013 : Implementing threaded accelerated compositing in WebKitGtk+Gwang Yoon Hwang
 
Javascript in Linux Desktop
Javascript in Linux DesktopJavascript in Linux Desktop
Javascript in Linux DesktopYuren Ju
 
GUI Programming with Perl / GTK
GUI Programming with Perl / GTKGUI Programming with Perl / GTK
GUI Programming with Perl / GTKAnuradha Weeraman
 
Hibernate architecture
Hibernate architectureHibernate architecture
Hibernate architectureAnurag
 
Integrating CC Licensing with Applications
Integrating CC Licensing with ApplicationsIntegrating CC Licensing with Applications
Integrating CC Licensing with ApplicationsNathan Yergler
 
Linux Kernel Development
Linux Kernel DevelopmentLinux Kernel Development
Linux Kernel DevelopmentPriyank Kapadia
 
Introduction to c programming
Introduction to c programmingIntroduction to c programming
Introduction to c programmingManoj Tyagi
 

Viewers also liked (17)

G T K+ 101
G T K+ 101G T K+ 101
G T K+ 101
 
GUI in Gtk+ con Glade & Anjuta
GUI in Gtk+ con Glade & AnjutaGUI in Gtk+ con Glade & Anjuta
GUI in Gtk+ con Glade & Anjuta
 
Taller Python Gtk Glade
Taller Python Gtk GladeTaller Python Gtk Glade
Taller Python Gtk Glade
 
Presentación de glade
Presentación de gladePresentación de glade
Presentación de glade
 
Introduction to Application Development in Python and Gtk+ / Hildon @ Maemo 5
Introduction to Application Development in Python and Gtk+ / Hildon @ Maemo 5Introduction to Application Development in Python and Gtk+ / Hildon @ Maemo 5
Introduction to Application Development in Python and Gtk+ / Hildon @ Maemo 5
 
Multimedia in WebKitGTK+ (FOSDEM 2010)
Multimedia in WebKitGTK+ (FOSDEM 2010)Multimedia in WebKitGTK+ (FOSDEM 2010)
Multimedia in WebKitGTK+ (FOSDEM 2010)
 
Introduce gobject introspection
Introduce gobject introspectionIntroduce gobject introspection
Introduce gobject introspection
 
SqueakGTK
SqueakGTKSqueakGTK
SqueakGTK
 
Gnome census
Gnome censusGnome census
Gnome census
 
نگاهی به Gtk3
نگاهی به Gtk3نگاهی به Gtk3
نگاهی به Gtk3
 
LCA2013 : Implementing threaded accelerated compositing in WebKitGtk+
LCA2013 :  Implementing threaded accelerated compositing in WebKitGtk+LCA2013 :  Implementing threaded accelerated compositing in WebKitGtk+
LCA2013 : Implementing threaded accelerated compositing in WebKitGtk+
 
Javascript in Linux Desktop
Javascript in Linux DesktopJavascript in Linux Desktop
Javascript in Linux Desktop
 
GUI Programming with Perl / GTK
GUI Programming with Perl / GTKGUI Programming with Perl / GTK
GUI Programming with Perl / GTK
 
Hibernate architecture
Hibernate architectureHibernate architecture
Hibernate architecture
 
Integrating CC Licensing with Applications
Integrating CC Licensing with ApplicationsIntegrating CC Licensing with Applications
Integrating CC Licensing with Applications
 
Linux Kernel Development
Linux Kernel DevelopmentLinux Kernel Development
Linux Kernel Development
 
Introduction to c programming
Introduction to c programmingIntroduction to c programming
Introduction to c programming
 

Similar to GTK Development: Designing a User Interface Using Glade 3

GTK+ 2.0 App - Desktop App Chooser
GTK+ 2.0 App - Desktop App ChooserGTK+ 2.0 App - Desktop App Chooser
GTK+ 2.0 App - Desktop App ChooserWilliam Lee
 
Javascript, the GNOME way (JSConf EU 2011)
Javascript, the GNOME way (JSConf EU 2011)Javascript, the GNOME way (JSConf EU 2011)
Javascript, the GNOME way (JSConf EU 2011)Igalia
 
How to keep Eclipse on the bleeding edge in the Linux world
How to keep Eclipse on the bleeding edge in the Linux worldHow to keep Eclipse on the bleeding edge in the Linux world
How to keep Eclipse on the bleeding edge in the Linux worldArun Kumar Thondapu
 
Introduction to git and Github
Introduction to git and GithubIntroduction to git and Github
Introduction to git and GithubWycliff1
 
Introduction to Go
Introduction to GoIntroduction to Go
Introduction to GoSimon Hewitt
 
Basics of gtk_ilugc
Basics of gtk_ilugcBasics of gtk_ilugc
Basics of gtk_ilugcilugc
 
Graphics Programming in C under GNU Linux (Ubuntu distribution)
Graphics Programming in C under GNU Linux (Ubuntu distribution)Graphics Programming in C under GNU Linux (Ubuntu distribution)
Graphics Programming in C under GNU Linux (Ubuntu distribution)Tushar B Kute
 
Porting the Source Engine to Linux: Valve's Lessons Learned
Porting the Source Engine to Linux: Valve's Lessons LearnedPorting the Source Engine to Linux: Valve's Lessons Learned
Porting the Source Engine to Linux: Valve's Lessons Learnedbasisspace
 
Introduction to Git for Network Engineers (Lab Guide)
Introduction to Git for Network Engineers (Lab Guide)Introduction to Git for Network Engineers (Lab Guide)
Introduction to Git for Network Engineers (Lab Guide)Joel W. King
 
Git, Docker, Python Package and Module
Git, Docker, Python Package and ModuleGit, Docker, Python Package and Module
Git, Docker, Python Package and ModuleNovita Sari
 
Hacking the Kinect with GAFFTA Day 1
Hacking the Kinect with GAFFTA Day 1Hacking the Kinect with GAFFTA Day 1
Hacking the Kinect with GAFFTA Day 1benDesigning
 
Grails beginners workshop
Grails beginners workshopGrails beginners workshop
Grails beginners workshopJacobAae
 
Kubernetes GitOps featuring GitHub, Kustomize and ArgoCD
Kubernetes GitOps featuring GitHub, Kustomize and ArgoCDKubernetes GitOps featuring GitHub, Kustomize and ArgoCD
Kubernetes GitOps featuring GitHub, Kustomize and ArgoCDSunnyvale
 
DevOps - Interview Question.pdf
DevOps - Interview Question.pdfDevOps - Interview Question.pdf
DevOps - Interview Question.pdfMinhTrnNht7
 
ConFoo - NuGet beyond Hello World
ConFoo - NuGet beyond Hello WorldConFoo - NuGet beyond Hello World
ConFoo - NuGet beyond Hello WorldMaarten Balliauw
 

Similar to GTK Development: Designing a User Interface Using Glade 3 (20)

GTK+ 2.0 App - Desktop App Chooser
GTK+ 2.0 App - Desktop App ChooserGTK+ 2.0 App - Desktop App Chooser
GTK+ 2.0 App - Desktop App Chooser
 
Javascript, the GNOME way (JSConf EU 2011)
Javascript, the GNOME way (JSConf EU 2011)Javascript, the GNOME way (JSConf EU 2011)
Javascript, the GNOME way (JSConf EU 2011)
 
How to keep Eclipse on the bleeding edge in the Linux world
How to keep Eclipse on the bleeding edge in the Linux worldHow to keep Eclipse on the bleeding edge in the Linux world
How to keep Eclipse on the bleeding edge in the Linux world
 
Introduction to git and Github
Introduction to git and GithubIntroduction to git and Github
Introduction to git and Github
 
Introduction to Go
Introduction to GoIntroduction to Go
Introduction to Go
 
Basics of gtk_ilugc
Basics of gtk_ilugcBasics of gtk_ilugc
Basics of gtk_ilugc
 
Opensource Software usability
Opensource Software usabilityOpensource Software usability
Opensource Software usability
 
Glade
Glade Glade
Glade
 
Graphics Programming in C under GNU Linux (Ubuntu distribution)
Graphics Programming in C under GNU Linux (Ubuntu distribution)Graphics Programming in C under GNU Linux (Ubuntu distribution)
Graphics Programming in C under GNU Linux (Ubuntu distribution)
 
02 c++g3 d (1)
02 c++g3 d (1)02 c++g3 d (1)
02 c++g3 d (1)
 
Porting the Source Engine to Linux: Valve's Lessons Learned
Porting the Source Engine to Linux: Valve's Lessons LearnedPorting the Source Engine to Linux: Valve's Lessons Learned
Porting the Source Engine to Linux: Valve's Lessons Learned
 
Introduction to Git for Network Engineers (Lab Guide)
Introduction to Git for Network Engineers (Lab Guide)Introduction to Git for Network Engineers (Lab Guide)
Introduction to Git for Network Engineers (Lab Guide)
 
Git, Docker, Python Package and Module
Git, Docker, Python Package and ModuleGit, Docker, Python Package and Module
Git, Docker, Python Package and Module
 
GUI JAVA PROG ~hmftj
GUI  JAVA PROG ~hmftjGUI  JAVA PROG ~hmftj
GUI JAVA PROG ~hmftj
 
Hacking the Kinect with GAFFTA Day 1
Hacking the Kinect with GAFFTA Day 1Hacking the Kinect with GAFFTA Day 1
Hacking the Kinect with GAFFTA Day 1
 
Qt
QtQt
Qt
 
Grails beginners workshop
Grails beginners workshopGrails beginners workshop
Grails beginners workshop
 
Kubernetes GitOps featuring GitHub, Kustomize and ArgoCD
Kubernetes GitOps featuring GitHub, Kustomize and ArgoCDKubernetes GitOps featuring GitHub, Kustomize and ArgoCD
Kubernetes GitOps featuring GitHub, Kustomize and ArgoCD
 
DevOps - Interview Question.pdf
DevOps - Interview Question.pdfDevOps - Interview Question.pdf
DevOps - Interview Question.pdf
 
ConFoo - NuGet beyond Hello World
ConFoo - NuGet beyond Hello WorldConFoo - NuGet beyond Hello World
ConFoo - NuGet beyond Hello World
 

GTK Development: Designing a User Interface Using Glade 3

  • 1. GTK Development Using Glade 3 GTK+ is a toolkit, or a collection of libraries, which developers can use to develop GUI applications for Linux, OSX, Windows, and any other platform on which GTK+ is available. Original Article by Micah Carrick
  • 2. Table of Contents Part 1 - Designing a User Interface Using Glade 3 ___________________________________________1 Quick Overview of GTK+ Concepts ______________________________________________________________1 Introduction to Glade3 _________________________________________________________________________3 Getting Familiar with the Glade Interface_______________________________________________________3 Manipulating Widget Properties________________________________________________________________5 Specifying Callback Functions for Signals _______________________________________________________6 Adding Widgets to the GtkWindow _____________________________________________________________9 How Packing Effects the Layout ______________________________________________________________ 13 Editing the Menu (or Toolbar) ________________________________________________________________ 15 Final Touches to the Main Window ___________________________________________________________ 18 Part 2 - Choosing a Programming Language for GT K+ Dev elopm ent _____________ 19 Which is the BEST Language? ________________________________________________________________ 19 Language Choice Considerations _____________________________________________________________ 19 A Look at Python vs. C________________________________________________________________________ 20 Part 3 __________________________________________________________________________________________ 22 Setting Up Your Development Environment___________________________________________________ 22 GtkBuilder and LibGlade _____________________________________________________________________ 24 The Minimal Application _____________________________________________________________________ 25 Compiling and Running the Application ______________________________________________________ 27 Stepping Through the Code ___________________________________________________________________ 29 Including the GTK+ Library _______________________________________________________________ 29 Initializing the GTK+ Library ______________________________________________________________ 29 Building the Interface with GtkBuilder ____________________________________________________ 30 Getting References to Widgets From GtkBuilder _________________________________________ 32 Connecting Callback Functions to Signals _______________________________________________ 33 Showing the Application Window _________________________________________________________ 36 In Summary _______________________________________________________________________________ 37
  • 3. Part 1| Designing a User Interface Using Glade 3 In part 1 of the GTK+ and Glade3 GUI Programming Tutorial series, we will be designing the graphical user interface (GUI) for a GTK+ text editor application (shown left) which will be used throughout these tutorials. This GUI design will be created using the Glade Interface Designer and is completely independent of the programming language used to implement the design, which will come in subsequent tutorials. Quick Overview of GTK+ Concepts If you have no experience with GTK+, you may struggle with some of the concepts I am going to cover. Although I am going to attempt to teach some of these concepts on the fly, it would serve you well to read up on these ideas further, perhaps after working through part 1 of this tutorial. Understanding the fundamental concepts of GTK+ will be instrumental in your ability to effectively use Glade. First of all, GTK+ is not a programming language. GTK+ is a toolkit, or a collection of libraries, which developers can use to develop GUI applications for Linux, OSX, Windows, and any other platform on which GTK+ is available. It can be thought of in the same terms as MFC or the Win32 API on Windows, Swing and SWT in Java, or Qt (the "other" Linux GUI toolkit used by KDE). Although GTK+ itself is written in C, there are a multitude of language "bindings" allowing programmers to develop GTK+ applications in the language of their choice including C++, Python, Perl, PHP, Ruby, and many others. GTK+ is based on 3 main libraries: Glib, Pango, and ATK, however, we primarily work with GTK+ and let GTK+ do it's magic with those 3 libraries. GLib wraps most of the standard C library functions for portability (allowing your code to run on Windows and Linux if desired). We use GLib a lot when working in C or C++, which I will explain more thoroughly when implementing our design using C. Higher-level languages such as Python and Ruby won't have to worry about GLib as they have their own standard libraries which provide similar functionality. GTK+ and associated libraries implement an object oriented approach through GObject. How this works isn't important just yet, and different programming languages will reveal this to you differently, however, it's important to understand that GTK+ uses object orientation (yes, even in C). Every piece of a GTK+ GUI is comprised of one or more "widgets" which are objects. All widgets will be derived from a base widget called GtkWidget. For example, an application's window is a widget called GtkWindow. The toolbar within that window 1
  • 4. is a widget called GtkToolbar. Although a GtkWindow is also a GtkWidget, a GtkWidget is not neccesarily a GtkWindow. Child widgets are derived from their parent objects to extend the functionality of that object. These are standard OOP (object oriented programming) concepts (hint: Google search "object oriented programming" if this is a new concept). We can look at any widget in the GTK+ reference documentation to see which objects it is derived from. In the case of GtkWindow, it looks something like this: GObject +----GInitiallyUnowned +----GtkObject +----GtkWidget +----GtkContainer +----GtkBin +----GtkWindow As you can see, a GtkWindow is derived from GtkBin which is derived from GtkContainer, and so on. For your first application, you don't need to worry about anything above the GtkWidget object. The reason this heirarchy is so important is because when you're looking for functions, properties, and signals for any particular widget, you need to realize that the functions, properties, and signals of it's parent objects apply to it as well. In part 2, this will become even more apparent when writing code for this example application. We also begin to see a naming convention emerge. This is pretty handy. We can easily tell what library an object or function is from. All objects beginning with Gtk are from GTK+. Later, we'll see things like GladeXML which is part of Libglade or GError which is part of GLib. All objects (and thus Widgets) are incamel case. The functions which manipulate these objects are in lower-case with underscores for spaces. For example, gtk_window_set_title() is a function to set the title property of a GtkWindow object. All the reference documentation you will need is available online from library.gnome.org/devel/references, however, it is much easier to use Devhelp which is likely available as a package for your distribution. Devhelp allows you to browse and search the API documentation for the libraries you have installed on your system (assuming you install that libraries documentation as well). More information on GTK+ and Glib:  Foundations of GTK+ Development (book)  GTK+ 2.0 Tutorial  GTK+ - The GIMP Toolkit 2
  • 5.  GLib Reference Manual  GTK+ Reference Manual  GTK+ 2.0 Tutorial (C Programming)  PyGTK+ 2.0 Tutorial (Python Programming) Introduction to Glade3 Glade is a RAD (Rapid Application Development) tool for designing GTK+ applications. Glade is a GTK+ application itself. It is simply a piece of software developers use to simplify the process of laying out an application's interface. Glade creates what will hereforth be refered to a s a "glade file". A glade file is actually an XML file which describes the heirachy of the widgets comprising the interface. Glade originally generated C code to build the GUI (and you'll still find examples and tutorials doing this). This was later discouraged in favor of using a library, Libglade, to build the interface at run time. And finally, as of Glade3, the old method has become deprecated. That means the ONLY thing glade does is allow you to generate a glade file which describes how the GUI is going to be built. This allows more flexibility with the developer, prevents having to re-compile applications when a minor interface change is needed, and allows more programming languages to be used with Glade. Glade3 has had significant changes since previous versions such as Glade2. Glade3 has been available for some time and you shouldn't have any problems obtaining it. The package manager for your distribution (yum, aptitude, etc.) should have Glade3 available. You should note however, that the package will have 3 in it. Where 'glade' may be the name for the old package, 'glade-3' or 'glade3' will be the package name for the new version on which this tutorial is based. Glade is also available from source at glade.gnome.org. Getting Familiar with the Glade Interface Start up Glade and let's get familiar with it's interface. I will be referring to various aspects of Glade by the names described here. On the left hand side is the "Palette". The Palette is like that of a graphics editing application. It is a palette of GtkWidgets which you can use to design your application. In the middle area (which is empty when you first start Glade) is the "Editor". This is where you see your design in progress. On the right hand side is the "Inspector" on top and the widget "Properties" below that. The Inspector shows your design as a tree allowing you to access and view the heirarchy of the widgets making up your design. We manipulate various properties of widgets in the Properties tabs, including specifying callback functions for signals (explained later). 3
  • 6. So, the verfy first thing we're going to do, is create a Toplevel widget and save our file. To do this, Click on the GtkWindow icon in the Palette under the 'Toplevels' section. You should notice a gray box show up inside the Editor area of Glade. This is the workable area of a GtkWindow. The titlebar, close button, etc. will be added to the widget by the window manager (ie: GNOME) so we don't see it while editing. We will always start with a toplevel widget in Glade, typically a GtkWindow. Before going further, save the file as "tutorial.glade". Now the file you just saved, "tutorial.glade", is an XML file. If you were to open it up in a text editor, it would look something like this: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> <!--Generated with glade3 3.4.0 on Tue Nov 20 14:05:37 2007 --> <glade-interface> <widget class="GtkWindow" id="window1"> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <child> <placeholder/> </child> </widget> </glade-interface> 4
  • 7. As you can see, it's just a simple XML file. In part2 we will be using C with Libglade to parse this XML file and generate the UI at run-time. Being XML, this could just as easily be parsed by a Python program or any other language. As we continue to work in Glade, this file will be updated to describe our interface in this XML format any time we save. Exit out of your text editor and return to Glade. Manipulating Widget Properties The Editor of Glade now shows an empty GtkWindow widget. We are going to manipulate some of the widget's properties. If you look in the Properties pane of Glade, you will see 4 tabs: 'General', 'Packing', 'Common', and 'Signals'. Let's talk about the first 2 tabs. GtkWidgets typically have various properties which manipulate how they function and/or how they are displayed on the screen. If you look at the reference documentation for a GtkWidget and scroll down to the "Properties" section, you'll see a list of the properties for a GtkWindow. These are typically the properties which appear in the 'General' tab of the Glade properties pane and will vary from widget to widget. The name property exists for every widget in Glade and is what we will use to reference the widget when it comes time to write code for the application. Change the 'name' property of this GtkWindow from "window1" to "window". Then, add the text "GTK+ Text Editor" to the 'Window Title' property. We'll discuss the 'Packing' tab in a bit, but first, let's look at the 'Common' tab. This tab also contains properties which belong to our GtkWindow, however, we don't see them in the reference documentation for GtkWindow. This is because this is where we set properties which areinherited from parent objects. Looking at the reference documentation for a GtkWidget in the section called "Object Hierarchy", you'll see the objects from which GtkWindow is derived. Click on the GtkContainer link to jump to the reference documentation for a GtkContainer. You'll notice that GtkContainer has a 5
  • 8. property called "border-width" and we have a property in Glade for "Border width" at the bottom of the 'Common' tab. We'll learn more about what a container widget is later, however, this demonstrates how important that object heirarchy is. Since many widgets are derived from GtkContainer, Glade puts it's properties into the 'Common' tab. In the "Object Hierarchy" section of the reference documentation for a GtkContainer you'll see that it is derived from a GtkWidget. Now click the GtkWidget link in to jump to the reference documentation for a GtkWidget. The GtkWidget has a bunch of properties, many of which are also shown in the 'Common' tab of Glade's Properties pane. These are properties which are common to all GTK+ widgets since all GTK+ widgets are derivitives of GtkWidget. Specifying Callback Functions for Signals Objects emit a "signal" when something that might be useful to the programmer happens. These are similiar to "events" from Visual Basic. If a user does anything within your GUI, chances are they are emitting signals. As a programmer, you choose which signals you want to capture and perform a task, and connect a callback function to that signal. The first signal we'll learn, and the one which you'll use in just about every GTK+ application you write, is the "destroy" signal emitted by GtkObject. This signal is emitted whenever a GtkObject is destroyed. This is important, because when the user closes the window through the little 'x' up in the title bar or any other means, the widget is destroyed. We want to capture this signal and exit our application properly. This is better illustrated when we write code for this GUI, however, for now, let's just specify the function we want to call when the "destroy" signal is emitted for our GtkWindow. 6
  • 9. Look at the 'Signals' tab in the Glade Properties pane. You see a tree view where GtkWindow and each of the objects from which it is derived are listed. If you expand the GtkObject, you'll see all the signals emitted by GtkObject. These correspond to the reference documentation for a GtkObject in the "Signals" section. Under the 'Handler' column, click the gray text "<Type here>" to begin editing. Select 'on_window_destroy' from the drop down and then hit ENTER. We can type anything we want here, however, glade provides a drop-down list of some of the mroe common callback function naming conventions. How this value is used depends on how the programmer connects signals in the code, however, for this tutorial, we want the GtkWindow's "destroy" signal to be associated with the handler string "on_window_destroy". We'll look at this closer in Part 2. At this point, we actually have a working GUI. We could write a few lines of code in C, Python, Ruby, or any number of programming languages which would show our empty window and then properly terminate when we clicked the "x" in the titlebar. For this tutorial however, I will be showing you how to build the entire GUI in Glade3 before writing any code. However, to satisfy any possible curiosity, if you would like to see what a simple program looks like that would implement this Glade interface so far... In C /* First run tutorial.glade through gtk-builder-convert with this command: gtk-builder-convert tutorial.glade tutorial.xml Then save this file as main.c and compile it using this command (those are backticks, not single quotes): 7
  • 10. gcc -Wall -g -o tutorial main.c `pkg-config --cflags --libs gtk+- 2.0` -export-dynamic Then execute it using: ./tutorial */ #include <gtk/gtk.h> void on_window_destroy (GtkObject *object, gpointer user_data) { gtk_main_quit (); } int main (int argc, char *argv[]) { GtkBuilder *builder; GtkWidget *window; gtk_init (&argc, &argv); builder = gtk_builder_new (); gtk_builder_add_from_file (builder, "tutorial.xml", NULL); window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); gtk_builder_connect_signals (builder, NULL); g_object_unref (G_OBJECT (builder)); gtk_widget_show (window); gtk_main (); return 0; } In Python (note: you must set the 'visible' property of 'window' to "Yes" in the 'Common' properties tab in Glade) #!/usr/bin/env python # First run tutorial.glade through gtk-builder-convert with this command: 8
  • 11. # gtk-builder-convert tutorial.glade tutorial.xml # Then save this file as tutorial.py and make it executable using this command: # chmod a+x tutorial.py # And execute it: # ./tutorial.py import pygtk pygtk.require("2.0") import gtk class TutorialApp(object): def __init__(self): builder = gtk.Builder() builder.add_from_file("tutorial.xml") builder.connect_signals({ "on_window_destroy" : gtk.main_quit }) self.window = builder.get_object("window") self.window.show() if __name__ == "__main__": app = TutorialApp() gtk.main() Again, I'm not going to go over the details of the code used to implement this GUI in this part of the tutorial, but instead focus on using Glade3. However, you can see that implementing an interface designed in Glade is just a few lines of code in the language of your choosing! Adding Widgets to the GtkWindow If you recall from the reference documentation for a GtkWindow, the GtkWindow is a derivative of GtkContainer. Widgets derived from GtkContainer are container widgets, meaning they can contain other widgets. This is another fundamental concept of GTK+ programming. If you come from a Windows programming background, you may be expecting to just drop a bunch of widgets onto the window and drag them around into the position you want them. But this is not how GTK+ works --and for good reason. GTK+ widgets "packed" into various containers. Containers can be packed into containers into containers and so forth. There are various packing properties which effect how space is allocated for widgets packed into containers. Through these 9
  • 12. packing properties and nesting containers, we can have complex GUI designs without having to write code to handler the resizing and re-positioning of our widgets. This is probably one of the more difficult concepts for a new GTK+ developer, so let's just see it in action! The GtkWindow is a derivative of the container GtkBin which is a container that contains only one child widget. But this text editor is going to have 3 main sections; a menu bar, a text editing area, and a status bar. Therefore, we use a fundamental GTK+ widget, the GtkVBox. The GtkVBox (vertical box) is a container widget which can contain any number of child widgets stacked up vertically like rows (GtkHBox is the horizontal equivelant). Click on the GtkVBox icon in the Glade Palette under the 'Containers' section. You'll notice that the 'Select' toolbar button on the top of the Glade window is no longer depressed and your mouse cursor is the GtkVBox icon with a plus (+) sign when hovering over the Glade Editor. This means you are ready to drop the GtkVBox somewhere. Click in gray area of the Editor which is the empty space of the GtkWindow. A dialog box pops up asking you for the 'Number of items'. In this case we want 3 rows, so leave it as 3 and click 'OK'. You should see the GtkWindow in the Editor divided into 3 rows now. These are the 3 empty child widgets of the GtkVBox we just added. You should also notice that the 'Select' toolbar at the top of Glade is once again depressed--allowing you to select widgets within the Editor. 10
  • 13. Next, click on the GtkMenuBar icon in the Glade Palette under 'Containers'. Drop this one in the top row of the GtkVBox you just added. Now click on the GtkScrolledWindow icon in the Glade Palette under 'Containers'. Drop this one in to the middle row of the GtkVBox. When you do that, it may not seem like anything has happened. However, you should notice that that middle row looks selected. It's not--the GtkScrolledWindow is.The reason you don't see anything, is because a GtkScrolledWindow doesn't have any initial visible components. It's a container which will provide scroll bars when it's child widget gets too large. We'll need this for our text editing widget. 11
  • 14. Click the GtkTextView icon in the Glade Palette under 'Control and Display'. Drop this one right on top of that GtkScrolledWindow (the middle row). We have now just added the GtkTextView to the GtkScrolledWindow which was added to the GtkVBox. Finally, click on the GtkStatusbar icon in the Glade Palette under 'Control and Display' and drop it into the bottom row. And there you have it; the basic layout of our GTK+ text editor. If you look at the Glade Inspector you will see the parent-child relationship of our design. The Inspector will come in handy. You cannot always click on a widget in the Editor as it might not be visible. For example, you cannot click on the GtkScrolledWindow we added, because you can only see it's child, the GtkTextView. 12
  • 15. Therefore, if you need to change the properties of "scrolledwindow1", you will have to select it in the Inspector. I mentioned earlier how "packing" is an often frustrating concept to new GTK+ developers. Therefore, I'm going to show you first hand how various packing effects the layout of your design. How Packing Effects the Layout When you look at the interface we've designed so far, you may take for granted how "smart" Glade was. How did it know we didn't want to make the status bar taller? Moreover, if you resize the window, how does it know that the text editing area grows to fill the new vertical space? Well, Glade guessed. It applied default packing options which are often what we want--but not always. The best way to learn about packing is to play around with packing properties in Glade as you can see the effects in real time. First, a quick description of the applicable properties. Once you get a feel for GTK+, you may want to read more on packing and space allocation.  homogeneous: A property of the container widget which when set, tells GTK+ to allocate the same amount of space for each child.  expand: A property of the child being packed specifying if it should recieve extra space when the parent grows.  fill: A property of the child being packed specifying whether any extra space should be given to the child or used as padding around the child. Let's look at the default packing for our design. The GtkScrolledWindow has "expand"=TRUE which means it recieves extra space when the parent grows, and it has "fill"=TRUE which means it uses that extra space it recieves. This is how we want it to work. Widget Property Value GtkVBox "vbox1" homogeneous FALSE GtkMenuBar "menubar1" expand FALSE fill TRUE GtkScrolledWindow expand TRUE "scrolledwindow1" 13
  • 16. fill TRUE GtkStatusbar "statusbar1" expand FALSE fill TRUE Now, let's see what homogeneous does. Select the GtkVBox in the Glade Inspector and change it's "Homogeneous" property under 'General' properties tab to "Yes". Now the parent, "vbox1", allocates the same amount of space to each of it's children. Since all 3 child widgets have "fill"=TRUE, they fill up this extra space allocated to them. Set the "Homogeneous" property back to "No". Click on the GtkScrolledWindow "scrolledwindow1" in the Glade Inspector and set the "Expand" property in the 'Packing' properties tab to "No". Now none of the child widgets will recieve the extra space when the GtkVBox grows. I've highlighted the 3 children in the image below to illustrate this. Each of the child widgets is it's initially requested size. The extra space allocated to the GtkVBox is simply unused since none of it's children want it (but still belongs to the GtkVBox). 14
  • 17. Now set the "Expand" property of the GtkScrolledWindow back to "Yes" and change the "Fill" property to "No" instead. This time, the extra space is allocated to the GtkScrolledWindow since "expand"=TRUE, however, the GtkScrolledWindow doesn't use the space it was allocated since "fill"=FALSE. Set the "Fill" property back to "Yes" to restore our original packing properties. I know it seems odd at first, but as you continue to work in Glade, you'll start to pick up on how these packing properties work and once you've conquored that part of the learning curve, you'll be amazed at how little work you have to do related to the position and size of your GUI's elements. Editing the Menu (or Toolbar) Glade3 comes with a new Menu and Toolbar editor. Although we aren't using a GtkToolbar in this tutorial, the process is very similar to that of the GtkMenubar. We will use the Glade3 Menu Editor to remove many of the items we won't be using and to specify signal handlers for the menu items we will be using. Although you can manipulate the properties and signals of GtkMenuItems from the standard Glade properties pane and can remove items from the Glade Inspector, the Glade3 menu editor provides a simpler way to edit your application's m enu. Select the GtkMenuBar by clicking it in the Glade Editor or in the Glade Inspector. Then right-click and select 'Edit...' from the popup menu. This will launch the menu editor. 15
  • 18. The menu editor contains properties just like Glade's main Properties pane and signals at the bottom just like the 'Signals' tab of Glade's main Properties pane. The main difference in the editor is the tree view on the left. It allows you easily add and remove menu items and drag them around. Go ahead and remove the one labeled "_View". This is the only menu item which Glade generates that we won't be using in this tutorial. For the remaining menu items we will need to do a few things. We need to rename them so that we have a clean, legible way to reference them in our source code. Then, we'll make some changes as a work around to a bug that might effect some readers using GTK+ 2.12.9 or below (Bug #523932), and finally we'll specify signal handlers. The steps for each of the menu items will be the same, so I'll just walk you through the 'New' menu item. Remember, this is all done in the menu editor but can also be done using the Inspector and Properties pane in glade. 1. Click on the new menu item 'gtk-new' 2. Change the 'Name' property under 'Menu Item' to "new_menu_item" 3. Change the 'Label' property under 'Properties' to "_New" (note the underscore, that's an accellerator) 4. Change the 'Stock Item' property under 'Properties' to "None" 5. Click on another menu item such as 'gtk-open' and then click back to 'gtk- new' to refresh the properties (Bug #533503) 6. Change the 'Stock Image' under 'Internal Image Properties' to the 'New' image 7. Specify a handler for the "activate" signal callled "on_new_menu_item_activate" (This is done just like before, where we click the tree view to get a drop down list of possible signal names) 16
  • 19. Now repeat those steps for each of the menu items: 'gtk-open', 'gtk-save', etc. Below are screen shots of the before and after on the 'New' menu item: Glade Menu Editor before changes 17
  • 20. Glade Menu Editor after changing 'New' menu item Final Touches to the Main Window It's never very easy to understand references to things like "textview1", "textview2", etc. when you're coding. So now that you know how to set properties, change the names of the following widgets (remember, the name is in the 'General' tab of the Properties pane): 1. Rename "textview1" to "text_view" 2. Rename "statusbar1" to "statusbar" And just to make it look a little nicer when the scroll bars are visible, let's add a a border and shadow to the GtkScrolledWindow 1. Change the "Shadow Type" to "Etched In' in the 'General' properties tab for "scrolledwindow1" 2. Change the "Border Width" to 1 in the 'Common' properties tab for "scrolledwindow1" 3. Change the "Left Margin" to 2 in the 'General' properties for "text_view" 4. Change the "Right Margin" to 2 in the 'General' properties for "text_view" 18
  • 21. Part 2| Choosing a Programming Language for GTK+ Development In part 1 of the GTK+ and Glade3 GUI Programming Tutorial series, we designed a graphical user interface (GUI) for a GTK+ text editor application. After doing so, we were left with an XML file (tutorial.glade) which described our application's user interface. In this part of the GTK+ and Glade3 GUI Programming Tutorial series I will be discussing the various programming languages available for GTK+ development. Subsequent parts of this tutorial will cover both C programming and Python programming. With my help, you will have to make the decision of which one you want to learn how to use (or both!). Which is the BEST Language? Let's get this out of your system now. This is a question for which you can spend the rest of your life reading answers to--and each will be different. The problem is that this is the wrong question to ask as the answer is different for every person in each different circumstance. Each language comes with it's advantages and it's drawbacks. The question to ask: Which language is well suited for me on this particular project? Language Choice Considerations The important thing to remember when starting in with a language, is to keep an open mind about other languages. You may start GTK+ programming with language X, and later switch to language Y once you know and understand how it's benefits are suited to your task. The GTK+ concepts will remain the same from language to language. 1. Experience Level How experienced you are with programming in general as well as how much time, patience, and devotion you are willing to spend are important factors in choosing a language. People without any programming experience have to learn fundamental programming concepts as well as the syntax and features of a new language. An experienced programmer can pick up a new language very quickly in comparison and can focus more on what the language has to offer as opposed to it's learning curve. Furthermore, if you're already a PHP expert, perhaps starting GTK+ development with PHP might appeal to you. Maybe you took a course on C++ in college and want to start there. Maybe you only worked with Visual Basic but are ready to take the plunge and learn C. 19
  • 22. 2. Activity and Community Support GTK+ is written in C. Other languages are available through "language bindings" which "wrap" the functionality. How active the project is which provides said bindings is an important factor. You want to choose a language that is up-to-date with new releases of GTK+ and bug fixes (all languages I've mentioned are pretty well up to date). Furthermore, a strong user-base and thus large community will be important as you get most of your support from the community. The more people using a particular language for GTK+, the more information there will be readily available. 3. Efficient Programmer vs. Efficient Program There's often a trade-off between how easy the program is to use and how efficient the program is in terms of speed and how much you can do with it on a lower-level. For many applications, the difference in efficiency of any two languages is negligable--and a new programmer would never even notice. For this reason, the increase in productivity is often the deciding factor. As and example, if I needed to write a program which allowed me to simply interface with some command-line utitlity through a GUI, I would likely choose Python or Ruby. However, if I were going to develop a sophisticated, powerful IDE, I would likely choose C or C++. In fact, you can even use several languages in one project! You could write the memory or processor intensive routines in C or C++ and do the rest in Python or Ruby. 4. Language Sexiness That's right-- how a language looks and feels is often a factor. You spend a lot of time staring at that code. How it flows on the screen, how it reads, and the overall development process in a particular language might appeal to you more than another. You should enjoy the programming you're doing. It's great having options isn't it! A Look at Python vs. C I have chosen to fork this tutorial into 2 languages based on the above criteria. It is my humble opinion that C and Python fit the above criteria best. Both have very, very strong community support and are being used for a large portion of the projects developed for Linux and especially GNOME. Furthermore, they sit on sort of opposite ends of the spectrum with regard to the efficiency vs. productivity debate. You could even follow this tutorial down both paths and compare the 2 languages yourself. If you have no programming experience, or perhaps just a little experience with something like Visual Basic or PHP, I recommend starting with Python. Even if you are 20
  • 23. an experienced programmer with C, C++, or Java experience you may want to learn Python. It's an exciting modern language, fun to program with, and incredible quick to learn and use. For Rapid Application Development in Linux, Glade and Python make a great team. Learn more about the Python GTK+ binding PyGTK at www.pygtk.org. If you're an experienced programmer or dedicated student, it may be worth your while to learn C or C++ for GTK+ development--especially if you're already familiar with C or C++. Learning GTK+ in C makes switching to another language such as Python a breeze. Furthermore, you'll have more options for contributing to existing projects. Personally, I do the majority of my GTK+ development in C despite the extra time it takes. 21
  • 24. Part 3| Writing a Basic Program to Implement the Glade File In this part of the GTK+ and Glade3 GUI Programming Tutorial series, I will s how you a very basic program that will parse the Glade file we created in Part 1 and display the main window for our GTK+ text editor. In this part of the tutorial, I will be discussing the GTK+ concepts first and then show the code in both Python and C (in different colors). If you have chosen to work in one language or the other, you can opt to skip over the code explanation for the language you are not going to use. Setting Up Your Development Environment To work with GTK+ and complete this step of the tutorial you will need a text editor, a terminal window, the GTK+ development libraries, and optionally Devhelp, the developer's help reference. If you're new to the Linux world, welcome to lots of options. There isn't one particular editor or IDE that is the "standard". Most developers actually work with their favorite text editor and a terminal window. Although there are some "full featured" IDEs out there, you may want to stick with a plain text editor and terminal at this point so as not to be overwhelmed or tripped up by features and automated tasks the IDE might perform. I do my work using Gedit, the default GNOME text editor. There is a plugins package available for Gedit which contains a terminal plugin and I have written Gedit Symbol Browser Plugin which allows you to quickly jump to functions in your source code. Below are Gedit screenshots from my system while working on this tutorial (click to see full-size). 22
  • 25. Working in C Working in Python The development libraries you will need depend both on your distribution and whether you want to work in Python or C. Although the process can vary greatly 23
  • 26. depending on your platform and distribution, I can give you the information you need to get started. If you have problems installing any of the packages you need, post your problem or question at the GTK+ Forums or a forum for your distribution. When it comes to development libraries with Linux, you can often get all the packages you need using your distributions package manager to resolve dependencies. For example, on Ubuntu you can likely just issue the command: 'sudo aptitude install libgtk-2.0-dev'. This command will install the GTK+ development package, it's dependencies, their dependencies, and so on. It's important to install the "development packages". These are suffixed with "- dev" in Ubuntu/Debian and "-devel" in Redhat/Fedora. The development packages include header files and other includes that allow you to build applications which use a particular library. Just remember, "package" allows you to run applications using that library where "package-dev" or "package-devel" allows you to write applications using that library. Another prefix you will see on packages is "-doc" such as "libgtk2.0-doc". This will be the documentation for that library and once installed will allow you to browse the documentation using Devhelp: the GNOME developer's help browser. If you're programming with C you should install the following packages with their dependencies: build-essential, libgtk2.0-dev, libgtk2.0-doc, libglib2.0-doc, devhelp (package names may vary depending on distribution, these are for Ubuntu). If you're programming with Python you should install the following packages with their dependencies: python2.5-dev python2.5-doc, python2.5-gtk2, python-gtk2-doc, python-gobject-doc, devhelp (package names may vary depending on distribution, these are for Ubuntu). GtkBuilder and LibGlade If you recall, the file we created with Glade in part 1 of this tutorial series (tutorial.glade) was an XML filedescribing our GUI. The actual GUI will be built by our program. Therefore, the program will have to open and parse the XML file and create instances of the widgets described within. There is already a library written to perform this task--2 libraries in fact. LibGlade was originally the library used to parse the glade file and create the widgets described within. At the time of writing, this will still be the more commonplace method used in other tutorials and books. However, GTK+ 2.12 included an object called GtkBuilder which is essentially the same thing and is built right in to GTK+. As this is intended to eventually replace Libglade, we will be using GtkBuilder in this tutorial. However, as you learn and look at code elsewhere on the internet, keep in mind that anywhere you see LibGlade being used, GtkBuilder can be used instead. 24
  • 27. Since (at the time of writing) GtkBuilder is relatively new, Glade does not yet support saving in the GtkBuilder format. The GtkBuilder format is still an XML file, but with a slightly different schema. That means that in order to use GtkBuilder on a glade file, we must first convert it to the GtkBuilder format. GTK+ 2.12 provides a conversion script for this process, and will already be installed on your system at this point. You can read some of the common questions I get about all this Libglade/GtkBuilder stuff at Libglade to GtkBuilder F.A.Q.. So we now convert the glade XML file tutorial.glade to the GtkBuilder XML file tutorial.xml with the following command: gtk-builder-convert tutorial.glade tutorial.xml The file 'tutorial.xml' is the file we will actually parse in our program, however, we still need tutorial.glade when we want to make changes using Glade. This is only necessary until Glade supports the GtkBuilder format in a later version (They are aiming to have this ready by Glade 3.6 which you can follow along Bug #490678). The Minimal Application We're finally ready to write some code! Let's just recap what we've done so far. 1. Using Glade, we created tutorial.glade which describes our user interface. 2. We've selected which language we will use to write our program; Python, C, or both. 3. We have a text editor and a terminal window available. 4. We have installed the development libraries we need to program GTK+ applications. 5. Using gtk-builder-convert, we converted tutorial.glade to tutorial.xml for use with GtkBuilder. Now, before we start digging in to all the details of what each line of code does, we are going to write a minimal application just to ensure everything works and get acquainted with the development process. So, open up your text editor and type in the following... If you're programming in C #include <gtk/gtk.h> void on_window_destroy (GtkObject *object, gpointer user_data) { 25
  • 28. gtk_main_quit(); } int main (int argc, char *argv[]) { GtkBuilder *builder; GtkWidget *window; gtk_init (&argc, &argv); builder = gtk_builder_new (); gtk_builder_add_from_file (builder, "tutorial.xml", NULL); window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); gtk_builder_connect_signals (builder, NULL); g_object_unref (G_OBJECT (builder)); gtk_widget_show (window); gtk_main (); return 0; } Save this file as 'main.c' in the same directory as 'tutorial.xml' If you're programming in Python import sys import gtk class TutorialTextEditor: def on_window_destroy(self, widget, data=None): gtk.main_quit() def __init__(self): builder = gtk.Builder() builder.add_from_file("tutorial.xml") self.window = builder.get_object("window") 26
  • 29. builder.connect_signals(self) if __name__ == "__main__": editor = TutorialTextEditor() editor.window.show() gtk.main() Save this file as 'tutorial.py' in the same directory as 'tutorial.xml' Compiling and Running the Application If you're programming in C Since C is a compiled language, we need to use the gcc compiler to compile our source code into a binary application. In order for gcc to know where the GTK+ libraries are that it needs to link to and what compiler flags to use, we use a program called pkg-config. When we installed the GTK+ development package, a package- config file named 'gtk+-2.0.pc' was installed on our system. This file tells the pkg-config program which version of the GTK+ libraries are installed and where the include files live on our system. To illustrate this, type the following command in your terminal: pkg-config --modversion gtk+-2.0 The output should show the version of GTK+ you have installed. On my system it shows '2.12.0'. Now let's look at what compiler flags are needed to build a GTK+ application on my system: pkg-config --cflags gtk+-2.0 The output of that command shows a bunch of -I switches which are specifying include paths for the compiler to use. This will tell gcc where to look for include files when we use '#include' in our application. The very first one on my system is '- I/usr/include/gtk-2.0'. That means that when I use '#include <gtk/gtk.h>' in my code, gcc will be able to find '/usr/include/gtk-2.0/gtk/gtk.h'. Anytime you use a '#include <library/header.h>' style include that is not part of the standard C library in your code, there should be a '-I/path/to/library' style option passed to gcc. These libraries can be installed in different locations based on distribution, operating system, or user preference. Good thing we have pkg-config to handle all of this for us! Let's compile our application so far. Issue this command in the terminal (make sure you are in the same directory in which both 'main.c' and 'tutorial.xml' reside: 27
  • 30. gcc -Wall -g -o tutorial main.c -export-dynamic `pkg-config --cflags --libs gtk+-2.0` The '-Wall' option tells gcc to show all warnings. The '-g' option will generate debugging information which will be useful should you have a bug in your application and need to step through the code using a debugger such as gdb. The option '-o tutorial' tell gcc to generate the output executable into a file named 'tutorial'. 'main.c' is the file gcc will compile. The '-export-dynamic' has to do with how we connect signals to callback functions which will be discussed when we step through the code. And finally, the pkg-config command appears. Notice how it is enclosed in backticks (those are not single quotes). The backtick is usually to the left of the '1' key on th e keyboard with the tilde character (~). This is telling our shell to first execute the command 'pkg-config --cflags --libs gtk+-2.0' and put the output of that command into the current command. So if you execute 'pkg- config --cflags --libs gtk+-2.0' on your system and then paste it's output onto the end of that gcc command, it would be virtually the same thing. By using pkg-config to append the include paths and library paths to our compile command, we can use the same command to compile our program on any system, regardless of where those libraries are installed. After your application compiles, there should be a new executable file named 'tutorial' which you execute using: ./tutorial When you do so, you are going to see several warnings from GTK, something along the lines of " Gtk-WARNING **: Could not find signal handler 'xxxxxx'". Don't worry about those for now. Those are telling use that we specified a signal handler in our glade file which we did not yet write a function for. I'll address these when we step through the code. But you should have seen your GTK+ Text Editor window show up, and clicking the 'x' in the window titlebar should properly terminate the application. If for some reason you were not able to get the application to compile or execute, post your error messages and any other information in the GTK+ Forums. If you're programming in Python Since Python is an Interpreted Language we don't need to compile our program. We simply invoke the Python interpreter, which we actually do with the first line in our source code. So all we need to do to run our Python program, is change the permissions so that the file is executable and then run it. Change the permissions using: chmod a+x tutorial.py 28
  • 31. And now you can run it using: ./tutorial.py you should have seen your GTK+ Text Editor window show up, and clicking the 'x' in the window titlebar should properly terminate the application. If for some reason you were not able to get the application to compile or execute, post your error messages and any other information in the GTK+ Forums. Stepping Through the Code Note: You should be looking up each new function in the GTK+ reference documentation as I introduce them. Get to know that documentation, it will be your best friend. Install Devhelp, use it! I will provided a link to the online reference documentation each time I introduce a new function in case you were unable to install Devhelp. Including the GTK+ Library If you're programming in C Hopefully you know enough about C programming to understand the first line '#include <gtk/gtk.h>'. If you don't, you should probably go back and work through a basic C programming tutorial before continuing with this one. By including gtk.h, we are indirectly including a multitude of header files. In fact, with only a few exceptions, we are including all of the GTK+ library and it's dependencies including GLib. If you want to know exactly what is being included just take a look at that file! Essentially, when you're looking through the reference manuals, you have access to most of the functions beginning with gtk_, g_, gdk_, pango_, and atk_. If you're programming in Python Hopefully you know enough about Python programming to understand the first two lines '#import sys' and '#import gtk'. If you don't, you should probably go back and work through a basic Python programming tutorial before continuing with this one. We now have access to all gtk.x classes. Initializing the GTK+ Library Python implicitly initializes the GTK+ library for you. In C however, we must initialize the GTK+ library before ANY call to a GTK+ function! 29
  • 32. If you're programming in C gtk_init (&argc, &argv); Looking in 'main()' we see that we initialize GTK+ before anything else using the gtk_init() function. Building the Interface with GtkBuilder In a GTK+ application written entirely through code, that is, without the assistance of Glade or another interface designer, we would have to programatically create each widget, set the various properties of that widget, and add it to it's parent widget where applicable. Each of these steps could require several lines of code for each widget. That can be tedious. Just think about the interface we created in part 1. There are over 20 widgets defined (including all the menu items). To create all those widgets through pure code could exceed a hundred lines of lines of code once all the properties were applied! Good thing we're using Glade and GtkBuilder. With just 2 lines of code, GtkBuilder will open and parse tutorial.xml, create all the widgets defined within, apply their properties, and establish the widgets' parent-child relationships. Once that is done we can then ask builder for the references to the widgets we want to further manipulate or otherwise reference. 30
  • 33. If you're programming in C builder = gtk_builder_new (); gtk_builder_add_from_file (builder, "tutorial.xml", NULL); The first variable we declared in main() was a pointer to a GtkBuilder object. We initialize that pointer usinggtk_builder_new(). This function will create a new GtkBuilder object and return the pointer to that object which we are storing in the 'builder' variable. Just about all GTK+ objects will be created in this fashion. The builder object at this point hasn't built any UI elements yet. We can use gtk_builder_add_from_file() to parse our XML file 'tutorial.xml' and add it's contents to the builder object. We are passing NULL as the third parameter to gtk_builder_add_from_file() because we are not going to learn about GError just yet. So we do not have any error checking yet and if the tutorial.xml file is not found or some other error occurs, our program will crash, but we'll address that later. 31
  • 34. You will notice that after calling gtk_builder_new() to create a new builder object, all the other gtk_builder_xxx functions take that builder object as the first parameter. This is how GTK+ implements object oriented programming in C, and will be consistent with all GTK+ objects (compare that with how Python, a natural OOP language implements the same thing below). If you're programming in Python builder = gtk.Builder() builder.add_from_file("tutorial.xml") When we initialize the TutorialTextEditor class with 'editor = TutorialTextEditor()' the class's initialization method, '__init__', is called. The first thing this method does is initialize a new gtk.Builder class withgtk.Builder(). The builder instance is local to the __init__ method because once we build our UI, we will no longer need the builder object. The builder object at this point hasn't built any UI elements yet. We use gtk.Builder.add_from_file() to parse our XML file 'tutorial.xml' and add it's contents to the builder object. Getting References to Widgets From GtkBuilder Once the builder has created all of our widgets we will want to get references to some of those widgets. We only need references to some of the widgets because some of them have already done their job and need no further manipulation. For example, the GtkVBox which holds our menu, text view, and statusbar has already done it's job of laying out our design and our code does not need to access it. So, we need to get a reference to any widget we will manipulate during the lifetime of our application and store it in a variable. At this point in the tutorial, we only need to reference the GtkWindow named "window" so that we can show it. If you're programming in C window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); A couple things are happening here. First, let's look at gtk_builder_get_object(). The first parameter is the object from which we want to get an object. Again, this is how OOP is implemented in C. The second parameter is the name of the object we want to get a pointer to. This corresponds to the 'name' we specified for the widget in Glade during part 1. If you recall, we named the main application GtkWindow 'window'. So, that's what we pass to gtk_builder_get_object(). The gtk_builder_get_object() function returns a pointer to a GObject and we are storing this pointer in 'window' which we declared at the beginning of main() as a 32
  • 35. pointer to a GtkWidget. Moreover, we know that the object we are trying to get was a GtkWindow. This is why I placed so much emphasis on the 'Object Hierarchy' of widgets and GTK+ objects. If you look at the Object Hierarchy for a GtkWindow you will see that GtkWidget is one of it's ancestors as is GObject. Therefore, a GtkWindow is a GObject and it is a GtkWidget. This is a fundamental OOP concept and critical to working with GTK+. So, the GTK_WIDGET() wrapped around the call to gtk_builder_get_object() is a convenience macro used for casting. You can cast a GTK+ widget into any of it's ancestors using one of these casting macros. All GTK+ objects will have them available. So, 'GTK_WIDGET(something)' is the same as '(GtkWidget*)something'. We're casting the pointer to a GObject returned from the call to gtk_builder_get_object() to a pointer to a GtkWidget as that's what 'window' was declared as. Finally, the reason we declared window as a pointer to a GtkWidget in the beginning of main() rather than as a pointer to a GtkWindow is due to convention. We could have declared it as a GtkWindow* and that would have still been correct. All GTK+ widgets are derived from a GtkWidget so we can always declare a variable pointing to any GTK+ widget as such. Many functions take GtkWidget* as a paramter and many functions return GtkWidget* and thus it usually makes sense to declare your variables as such and simply cast them to the specific widget where applicable (which you'll see later). If you're programming in Python self.window = builder.get_object("window") We are using gtk.Builder.get_object() to get the object named "window" from the builder. This corresponds to the 'name' we specified for the widget in Glade during part 1. If you recall, we named the main application's GtkWindow 'window'. So, that's what we pass to get_object(). We assign the returned object to self.window so that we have access to the application's window anywhere within the TutorialTextEditor() class. Connecting Callback Functions to Signals In part 1 we specified "handlers" for various "signals" in our interfac e. If you recall, GTK+ emits signals for various events that occur. This is a fundamental concept of GUI programming. Our application needs to know when the user does something so that it can respond to that action. As we'll see soon, our application just sits around in a loop waiting for something to happen. We will be using GtkBuilder to connect the signal handlers we defined using Glade with callback functions in our code. GtkBuilder will look at our code's symbols and connect the appropriate handlers for us. 33
  • 36. In part 1 we specified a handler named 'on_window_destroy' for the "destroy" signal of the GtkWindow named 'window'. Therefore, GtkBuilder will expect to find a function or method named 'on_window_destroy'. The "destroy" signal is emitted when a GtkObject is destroyed. As we'll see in the next bit of code, our application is going to sit in an infinite loop waiting for events to happen. When the user closes the window (such as clicking the 'x' in the titlebar), our application will need to break out of the loop and terminate. By connecting a callback to the "destroy" signal of the GtkWindow we will know when to terminate. Therefore, this is a signal you will use in almost every GTK+ application you write. Note: The method being used to connect callbacks to signals in this example is equivalent to using glade_xml_signal_autoconnect() function when using LibGlade instead of GtkBuilder. If you're programming in C gtk_builder_connect_signals (builder, NULL); When we call gtk_builder_connect_signals() we pass the builder object as the first parameter as always. The second parameter allows us to pass user data (anything we want) to our callback function. This will be important later, but for now we'll just pass NULL. This function uses GModule, a part of GLib used to dynamically load modules, to look at our applications symbol table (function names, variable names, etc.) to find the function name that matches the handler name we specified in Glade. In Glade we specified a handler for the GtkWindow's "destroy" signal called 'on_window_destroy'. So, gtk_builder_connect_signals() is looking for a function named 'on_window_destroy' that matches the signature of the callback function for the "destroy" signal. If you recall from part 1, the "destroy" signal belonged to GtkObject. Therefore, we find the prototype for the callback function in the manual for GtkObject under the 'signals' section: GtkObject "destroy" Signal. This tells us what the prototype for our callback function should look like. Based on the prototype specified in the manual, I wrote the following function: void on_window_destroy (GtkObject *object, gpointer user_data) { gtk_main_quit(); } So now gtk_builder_connect_signals() will find this function and see that it both matches the name of the handler we specified in Glade and has a compatible 34
  • 37. signature (takes the same arguments) as that specified for the "destroy" signal and makes the connection. Now our function on_window_destroy() will be called when the GtkWindow 'window' is destroyed. In on_window_destroy() we just call gtk_main_quit() to properly terminate our application. This function will break out of the main loop which I will talk about more when we get there in just a bit. Right after the call to gtk_builder_connect_signals() there was a call to g_object_unref(). g_object_unref (G_OBJECT (builder)); This is because we are no longer going to use the GtkBuilder object. We used it to construct our widgets and then we obtained pointers to the widgets we needed to reference. So now we can free all the memory it used up with XML stuff. You'll also noticed that we are using one of those casting macros to cast (GtkBuilder*) to (GObject*). We must do this because g_object_unref() takes a GObject* as a parameter. Since a GtkBuilder is derived from a GObject (as are all widgets) this is perfectly valid. If you're programming in Python builder.connect_signals(self) In Glade we specified a handler for the GtkWindow's "destroy" signal called 'on_window_destroy'. So,gtk.Builder.connect_signals() is looking for a method named 'on_window_destroy' that matches the signature of the callback method for the "destroy" signal. If you recall from part 1, the "destroy" signal belonged to GtkObject. Therefore, we find the prototype for the callback function in the manual for gtk.Object under the 'signals' section: gtk.Object "destroy" Signal. This tells us what the prototype for our callback method should look like. Based on the prototype specified in the manual, I wrote the following method: def on_window_destroy(self, widget, data=None): gtk.main_quit() So now builder.connect_signals() will find this method and see that it both matches the name of the handler we specified in Glade and has a compatible signature (takes the same arguments) as was specified for the "destroy" signal and makes the connection. Now our method on_window_destroy() will be called when the GtkWindow 'window' is destroyed. 35
  • 38. In on_window_destroy() we just call gtk.main_quit() to properly terminate our application. This function will break out of the main loop which I will talk about more when we get there in just a bit. Showing the Application Window Before we enter the GTK+ main loop (discussed next), we want show our GtkWindow widget as our app doesn't do much good if it's not even visible. If you're programming in C gtk_widget_show (window); Calling gtk_widget_show() sets the Widget's GTK_VISIBLE flag telling GTK+ to show the widget (which will happen within the GTK+ main loop discussed next). If you're programming in Python editor.window.show() Calling gtk.Widget.show() tells GTK+ to show the widget (which will happen within the GTK+ main loop discussed next). Entering the GTK+ Main Loop The main loop in GTK+ is an infinite loop which performs all of the "magic". This is how GUI programming works. Once we build our GUI and setup our program, we enter the GTK+ main loop and just wait for an event to occur which we care about (such as closing the window). A lot is happening inside this main loop, however, for a beginner you can simply think of it as an infinate loop in which GTK+ checks the state of things, updates the UI, and emits signals for events. After entering the main loop, our application isn't doing anything (but GTK+ is). When the user resizes the window, minimizes it, clicks on it, presses keys, etc. GTK+ is checking each of these events and emitting signals for them. However, our application is only connected to one signal currently, the "destroy" signal of 'window'. When the window is closed and the "destroy" signal is emitted, then the GTK+ main loop will turn over control to the handler function we have connected to that signal which breaks us out of the GTK+ main loop thus allowing our application to terminate. If you're programming in C gtk_main (); If you're programming in Python 36
  • 39. gtk.main() In Summary 1. Application uses GtkBuilder to create the GUI from XML file. 2. Application gets reference to main window widget. 3. Application connects 'on_window_destroy' handler to the "destroy" signal. 4. Application flags the window to be shown. 5. Application enters GTK+ main loop (window is shown). 6. User clicks the 'x' in the titlebar as a result of which GTK+ main loop emits the "destroy" signal. 7. Handler 'on_window_destroy' breaks out of GTK+ main loop. 8. Application terminates normally. 37