Demo-1  <<--BACK            HOME            UP --^           NEXT-->>  Demo-3
side4linux, a simple integrated development environment!

GNOMEC Demo-2  Connect up the visuals from the 'Sample' project so that it actually does something.


Purpose:  To provide a basic introduction to visual programming in the GNOME environment using 'side4linux' and 'Glade2'.
If you have Glade-3 installed start at Demo-3 instead!

We will build a visual program that has two buttons, one to display 'Hello World!' in a text window and one to erase the message from the text window. We will do this by first copying the 'Sample1' Project provided into a copy called 'Test2' and then 'connect' the visuals produced in 'Demo1' to 'callback' actions. This will complete the project started in 'Demo1'.

Requirements: Make sure that the 'GNOME' build environment is installed correctly, if not then read 'setup C build environment.txt' and also
'setup GNOME build environment.txt'. Make sure that you have suffered 'Demo-1'.

  1. Open 'side4linux' and click on Project>Open Project in the Main Menue.
  2. Double click on the 'DEMOS' Product Area,
  3. Double click on the 'SIDEdemos' Product,
  4. In the file dialog double click the  'GNOMEC' folder, this takes you to where 'GNOME' visual 'C' language projects are kept.
  5. Double click on 'Sample1', this opens the 'Sample1' project folder ( we are kindly providing your 'Sample' fixed and ready to go! )
  6. Double click on 'sample1.prf', this opens the 'Sample1' project file.
  7. Now click on Project>Save Project As and save the 'Sample1' Project as 'Test2'.
  8. Close the current Project by clicking on Project>Close Project.
  9. As in Step 1 open your 'Test2' project.
  10. Notice that project names are set to be an upper case letter followed by lower case letters (easier on the IDE's Project management routines).
  11. Notice that the left bottom status bar window says 'Project: Test2' which is the Project Name.
  12. Notice that the next window says 'Ptype: GNOMEC' which is the Project Type.
  13. Now click on the 'Autogen' toolbar button  followed after a while by the 'Build' button and you should be ready to continue.
  14. Change to another workspace and run the 'test2' binary in the 'src' folder using Nautilus.
  15. Notice that when maximised the buttons get stretched. I think we had better fix this now!
  16. From the Main Menue open Glade with Project>Edit Project>Edit Project Visuals with Glade
  17. Double click on the 'mainWindow' widget in the 'GNOME' window to bring up the program visual.
  18. Click on the 'Hello' button and in the 'PROPERTIES' window click the 'Packing' tab and set 'Expand' and 'Fill' to 'No' by clicking on the toggle bar.
  19. Do the same for the 'Erase' button and then click next to the buttons on the right to bring up 'hbox1' in the 'PROPERTIES' window and repeat.
  20. Click 'Build' in the 'GLADE" window and close and click 'Build' in the IDE to complete the job.
  21. Notice that you 'build' twice! Once for the visuals in Glade2 and once for the 'C' compiler in the side4linux IDE.
  22. Try running the test2 binary again, It should now look like this with little buttons in the lower left.
Screenshot-1

The reason for all this is that visuals do not know what size the screen will expand to hence the ability for you to decide what should expand e.g. the text window and what should not e.g. the buttons.


Excercise -1  -- Add a 'shutdown' handler in Glade and connect it to a callback function in 'callbacks.c"

Now let us finally make some visuals do something! But first a little discussion about event driven graphical user interfaces ( GUI's ). If you open 'main.c' you will see the following code,

/*
 * Initial main.c file generated by Glade. Edit as required.
 * Glade will not overwrite this file.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gnome.h>

#include "interface.h"
#include "support.h"

int main (int argc, char *argv[])
{
  GtkWidget *mainWindow;

#ifdef ENABLE_NLS
  bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);
#endif

  gnome_program_init (PACKAGE, VERSION, LIBGNOMEUI_MODULE,
                      argc, argv,
                      GNOME_PARAM_APP_DATADIR, PACKAGE_DATA_DIR,
                      NULL);

  /*
   * The following code was added by Glade to create one of each component
   * (except popup menus), just so that you see something after building
   * the project. Delete any components that you don't want shown initially.
   */
  mainWindow = create_mainWindow ();
  gtk_widget_show (mainWindow);

  gtk_main ();
  return 0;
}

Before we do anything we will need to remove the pointer to 'mainWindow' (our program window) and put it in a 'header' file so that we can use the window pointer in our 'callbacks.c' callback functions. so.. Open a new file and save as 'main.h'. Now cut and paste the line '
GtkWidget *mainWindow;' from 'main.c' into the main.h file and save main.h. Put in the line of,

#include "main.h"

into both the top of 'main.c' file and 'callbacks.c' so that we can now reference the main window in our program. We will need this pointer to alter the text in our text window etc.
So 'main.c' now looks like,

/*
 * Initial main.c file generated by Glade. Edit as required.
 * Glade will not overwrite this file.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gnome.h>

#include "interface.h"
#include "support.h"

#include "main.h"

int main (int argc, char *argv[])
{

#ifdef ENABLE_NLS
  bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);
#endif

  gnome_program_init (PACKAGE, VERSION, LIBGNOMEUI_MODULE,
                      argc, argv,
                      GNOME_PARAM_APP_DATADIR, PACKAGE_DATA_DIR,
                      NULL);

  /*
   * The following code was added by Glade to create one of each component
   * (except popup menus), just so that you see something after building
   * the project. Delete any components that you don't want shown initially.
   */
  mainWindow = create_mainWindow ();
  gtk_widget_show (mainWindow);

  gtk_main ();
  return 0;
}

Now 'mainWindow' is indeed of type 'GtkWidget' so it is a pointer to a 'widget' and the function 'create_mainWindow ();' creates the widget after which it is assigned to the pointer 'mainWindow' but becuase this is visual code you must then 'show' it. You could also 'hide' it or even 'destroy' it, waiting on 'create' for the next valid pointer. The really different bit is the next line of code 'gtk_main ();'. This function locks the program into an 'event loop' where nothing happens at all until there is some external 'trigger' like a mouse click or keypress. When this happens a 'signal' is 'emitted'. This means nothing of course until you 'connect' that signal with a function (called a 'callback' ) that will actually do something. Now Glade has already provided some of these 'callbacks' and has 'connected' them, have a look now in 'callbacks.c' by opening it into the Notebook. An example of the 'callbacks' is presented below,

void on_new1_activate(GtkMenuItem  *menuitem, gpointer  user_data)
{

}

So as you might guess this 'callback' function is connected to the 'new file' signal that is 'emitted' when you click on 'New' in the Main Menue of your program 'Test2'. The reason that nothing has happened is that there is no code within that function! From this you can see where we are going, the rest of 'Demo-2' is about generating the 'callback' code and allowing Glade to 'connect' them to
'signals'. Take it for granted that Glade will trash 'interface.c' and 'support.c' and will also append any new callback functions to the end of 'callbacks.c'. This means that you can edit with 'main.c' and 'callbacks.c' but not the other two! Note that 'callbacks.c',interface.c' and 'support.c' must be closed while Glade is working, that is why the IDE will close these three files if they are open before launching Glade.

So, now we get to do something! Open Glade, select the 'mainWindow' visual widget ( double click on it in the 'GLADE' window,  where the title bar shows 'Glade: test2' ) and look in the 'PROPERTIES' window. The title bar should say 'Properties: mainWindow' Click on the 'Signals' tab, Click on the little box at the end of the 'Signal: bar ' ( above 'Handler:' ). A little box opens with 'Select Signal' in the title bar. From this, scroll down until you see 'delete_event'. Click on it to highlight it then click on 'OK'.

In the 'Signal' bar you should now see 'delete_event' and in the 'Handler' bar should be 'on_mainWindow_delete_event'. Click on 'Add'. which will add a 'handler' fuction to 'callbacks.c' and generate the signal which is 'emitted' on program closure.

Now 'Build' and quit Glade to return to the IDE and open 'callbacks.c'. You should see the following function tacked onto the bottom of the file (you may need to edit the presentation to match the coding style of your own preference).

gboolean on_mainWindow_delete_event(GtkWidget   *widget, GdkEvent  *event, gpointer  user_data)
{

  return FALSE;
}

Put the following line into the function, 'gtk_main_quit();'

It now reads,

gboolean on_mainWindow_delete_event(GtkWidget   *widget, GdkEvent  *event, gpointer  user_data)
{
  
gtk_main_quit();
  return FALSE;
}

Now that fixes the orderly shutdown of the program by breaking the 'main event loop'.
 


Excercise -2  -- Add a 'startup' handler in Glade and connect it to a callback function in 'callbacks.c"

Now that we have fixed the shutdown of the program by breaking the 'main event loop' we will also put in something to allow startup initialisation. We will tack a callback onto that function we came across earlier in 'main.c', namely,

'gtk_widget_show (mainWindow);'

Repeating the procedure in Excercise-1, open Glade from the IDE, select the 'mainWindow' visual widget ( double click on it in the 'GLADE' window )  and add the handler  'on_mainWindow_show'


After clicking on 'Build' in the 'GLADE' window and closing Glade, open 'callbacks.c' into the Notebook to add the following global string below the file includes at the top and before ,

'void on_new1_activate(GtkMenuItem  *menuitem, gpointer  user_data)' as shown below,

static gchar *msg;       // general use glib string that is global only within this file because of the 'static' declaration

Now add the following line to the callback handler function
'void on_mainWindow_show(GtkWidget *widget,  gpointer user_data)' as follows,

msg = g_strdup_printf("Hello World!");

and the callback.c file should now look something like,

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gnome.h>

#include "callbacks.h"
#include "interface.h"
#include "support.h"

static gchar *msg;       // general use string that is global only within this file

void on_new1_activate(GtkMenuItem *menuitem,  gpointer user_data)
{

}
.
.
etc., etc.,
.
.
gboolean on_mainWindow_delete_event(GtkWidget   *widget, GdkEvent  *event, gpointer  user_data)
{
  
gtk_main_quit();
  return FALSE;
}

void on_mainWindow_show(GtkWidget *widget,  gpointer user_data)
{
  msg = g_strdup_printf("Hello World!");
}

Note: You can add other intialisation routines here as well that your own code may need at program start.


Excercise - 3  -- Add 'button' handlers in Glade and connect them to callback functions in 'callbacks.c"

We are now going to complete the original object of the Demo-1 & 2 that is,

'We will build a visual program that has two buttons, one to display 'Hello World!' in a text window and one to erase the message from the text window'.


Re-open the Glade visual editor and bring up our 'mainWindow' widget and click on the 'Hello' button to bring it up in the 'PROPERTIES' window as in the following graphic,

Highlight Hello Button Notice the black band around the 'Hello' button which shows that it is selected, we will now add the signal and callback.

I
n the 'PROPERTIES' window Click on the 'Signals' tab, Click on the little box at the end of the 'Signal: bar ' ( above 'Handler:' ). A little box opens with 'Select Signal' in the title bar. From this, scroll down until you see 'clicked' (second option from the top). Click on it to highlight it then click on 'OK'. Now click on 'Add' at bottom left to add the signal and handler. Do the same for the 'Erase' button. Then do the double 'Builds' mentioned earlier to add them to 'callbacks.c'. We are now in a position to re-open 'callbacks.c' and add the action code to complete the Project ready for testing.


Excercise - 4  -- Complete callback functions in 'callbacks.c" by adding action code

Add the following code to the two new callback functions at the bottom of 'callbacks.c'.

void on_Hellobutton_clicked(GtkButton *button, gpointer user_data)
{
  GtkWidget *textWindow;        // pointer to our text window
  GtkTextBuffer *text_buffer;   // pointer to the text buffer inside our text window

  textWindow = lookup_widget(GTK_WIDGET(mainWindow),"textview1"); // get pointer to our text window
  text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textWindow)); // get pointer to text buffer inside
  gtk_text_buffer_set_text(text_buffer,msg,12);
}

void on_Erasebutton_clicked(GtkButton *button, gpointer user_data)
{
  GtkWidget *textWindow;        // pointer to our text window
  GtkTextBuffer *text_buffer;   // pointer to the text buffer inside our text window

  textWindow = lookup_widget(GTK_WIDGET(mainWindow),"textview1"); // get pointer to our text window
  text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textWindow)); // get pointer to text buffer inside

  msg = g_strdup_printf(" ");
  gtk_text_buffer_set_text(text_buffer,msg,1);
  msg = g_strdup_printf("Hello World!");
}

Click on the 'Build' toolbar button and build the Project. Change to the Project's 'src' directory with 'Nautilus' and click on the 'test2' binary and try your buttons!

If the project did not build then check over your code against the Excercises above, you can also open another invocation of 'side4linux' on a separate workspace and open the 'Sample2' Project which is a conpleted and tested copy of your 'Test2' and check for differences.

Now you may be wondering about the code we have just added. It comes from the GTK library which is linked in automatically by the IDE.

Click on Help>Help Browser>Coding Help>GNOMEC project (GNOMEC)>GTK functions (local)>MultiLinedTextEditor for reference.

You may be wondering about how we obtained the pointers to textWindow and text_buffer. What we did was use the GTK widget look up function to find them. Open 'interface.c' and search on  

/* Store pointers to all widgets, for use by lookup_widget(). */ 

in the function 'GtkWidget* create_mainWindow (void)' to see what pointers are available. Note that you can use this method as well to reference all the visual pointers that Glade produces. ( Tools>Search in File )

OK, I have had enough! Time to do something else! This project introduced the concept of visual programming using the GTK libraries. There is more to understand but not much! We will cover some aspects of visual programming in the next Demo. Until then, click on Project>Close Project from the Main Menue and now close down the IDE by clicking the 'X' in the top right corner.



We will provide other demos as 'side4linux' develops to cover GNOME visual programming and integration into a real world machine controller.


GUI interface made with Gtk and Glade GUI demo built with Glade