only for RuBoard - do not distribute or recompile |
Now you re going to take apart each of the files Glade created. First, start with the .c files to see how they fit together to make a complete program. After that, you will take a quick look at HelloWorld.glade to see how it is structured. Finally, you will get a quick word on autogen .sh.
Listing 5.3 shows the main.c file that s created by Glade when the Build button is clicked. If a main.c file already exists, Glade will not overwrite it (as stated in the initial comment). In this case, to allow for a clean and quick compile from the command line, lines 28 and 29 were commented out after Glade wrote the file.
01 /* 02 * Initial main.c file generated by Glade. Edit as required. 03 * Glade will not overwrite this file. 04 */ 05 06 #ifdef HAVE_CONFIG_H 07 # include <config.h> 08 #endif 09 10 #include <gtk/gtk.h> 11 12 #include "interface.h" 13 #include "support.h" 14 15 int 16 main (int argc, char *argv[]) 17 { 18 GtkWidget *frm_main; 19 20 #ifdef ENABLE_NLS 21 bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR); 22 textdomain (PACKAGE); 23 #endif 24 25 gtk_set_locale (); 26 gtk_init (&argc, &argv); 27 28 /*add_pixmap_directory (PACKAGE_DATA_DIR "/pixmaps"); 29 add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps"); 30 */ 31 /* 32 * The following code was added by Glade to create one of each component 33 * (except popup menus), just so that you see something after building 34 * the project. Delete any components that you don't want shown initially. 35 */ 36 frm_main = create_frm_main (); 37 gtk_widget_show (frm_main); 38 39 gtk_main (); 40 return 0;
As you can see, lines 1 “4 are comments about how Glade uses this file. Note that if you add another form or other top-level widget, you will have to either remove this form and let Glade re-create it or manually edit the new parts .
On line 6, config.h has to do with library configuration information. Line 10 compiles in the GTK+ files, and lines 12 and 13 include the interface and support files for this project. Line 15 starts main() , and line 18 declares our main form. ENABLE_NLS has to do with internationalization of text strings, as does gtk_set_locale().
Line 26 initializes the GTK+ system, and lines 28 and 29 have to do with the project if compiled by autogen.sh . Lines 32 “34 contain more comment code generated by Glade, and line 36 creates frm_main with a call to create_frm_main , which is in interface.c . Line 37 makes frm_main visible, and line 39 sends the application into the main gtk loop, waiting for signals emitted from the widgets. Lastly, line 40 returns 0, indicating the program terminated normally.
interface.c is the file created by Glade that holds the code needed to instantiate the windows and widgets you ve created using Glade. Its normal mode of operation is to have a create_xxx() function call to create the windows you specify, and then call those create_xxx() functions from main.c and return a pointer to the newly instantiated window.
01 /* 02 * DO NOT EDIT THIS FILE - it is generated by Glade. 03 */ 04 #ifdef HAVE_CONFIG_H 05 # include <config.h> 06 #endif 07 08 #include <sys/types.h> 09 #include <sys/stat.h> 10 #include <unistd.h> 11 #include <string.h> 12 13 #include <gdk/gdkkeysyms.h> 14 #include <gtk/gtk.h> 15 16 #include "callbacks.h" 17 #include "interface.h" 18 #include "support.h" 19 20 GtkWidget* 21 create_frm_main (void) 22 { 23 GtkWidget *frm_main; 24 GtkWidget *cmd_main; 25 26 frm_main = gtk_window_new (GTK_WINDOW_TOPLEVEL); 27 gtk_object_set_data (GTK_OBJECT (frm_main), "frm_main", frm_main); 28 gtk_window_set_title (GTK_WINDOW (frm_main), _("HelloWorld App")); 29 30 cmd_main = gtk_button_new_with_label (_("Hello World!\nClick to close.")); 31 gtk_widget_ref (cmd_main); 32 gtk_object_set_data_full (GTK_OBJECT (frm_main), "cmd_main", cmd_main, 33 (GtkDestroyNotify) gtk_widget_unref); 34 gtk_widget_show (cmd_main); 35 gtk_container_add (GTK_CONTAINER (frm_main), cmd_main); 36 37 gtk_signal_connect (GTK_OBJECT (cmd_main), "clicked", 38 GTK_SIGNAL_FUNC (on_cmd_main_clicked), 39 NULL); 40 41 return frm_main; 42 }
Lines 1 “3 are generated by Glade. If you open HelloWorld.glade from Glade and click the Build button, this file will be overwritten.
have_config_h has already been covered (see Line 6 of Listing 5.3, as well as the commentary afterward). The include for sys/types.h has to do with primitive data type definitions, and stat.h deals with file characteristics. unistd.h has symbolic constants, and string.h deals with string handling functionality. gdkkeysyms.h contains key mapping definitions. gtk.h has already been covered also. Lines 16 “18 get the functions necessary for create_frm_main to work.
Line 20 declares the return type from create_frm_main to be a GtkWidget type. Line 23 declares a second variable named frm_main. In spite of the fact that it is named the same, it will only be used within this function. The last line (line 42) returns this local frm_main , and main.c puts it into our global frm_main . As you can see from lines 23 and 24, you only need two widgets. Line 26 s gtk_window_new has already been covered (see main.c in Listing 5.3).
Line 27 contains the gtk_object_set_data() function. This function allows GTK+ to associate any amount of information with an object. Line 28 sets the title that will appear in the title bar of frm_main . Line 30 instantiates a new command button into cmd_main , and the gtk_object_set_data_full() function associates the cmd_main widget with the frm_main widget and sets a notification when the frm_main object is destroyed .
Line 34 makes frm_main visible, and line 37 connects the clicked event of cmd_main to the function (in callbacks.c ) on_cmd_main_clicked() . (This is the function to which you had to add gtk_main_quit() to properly close the application.)
Glade creates the file support.c to provide utility functions for use in your GTK+ program. The function lookup_widget() deserves special attention because it allows you to give the window and the name of the child widget you are seeking, and it will return a pointer to that child. This is very helpful when you are referencing widgets in different windows.
001 /* 002 * DO NOT EDIT THIS FILE - it is generated by Glade. 003 */ 004 005 #ifdef HAVE_CONFIG_H 006 # include <config.h> 007 #endif 008 009 #include <sys/types.h> 010 #include <sys/stat.h> 011 #include <unistd.h> 012 #include <string.h> 013 014 #include <gtk/gtk.h> 015 016 #include "support.h" 017 018 /* This is an internally used function to see whether a pixmap file exists. */ 019 static gchar* check_file_exists (const gchar *directory, 020 const gchar *filename); 021 022 /* This is an internally used function to create pixmaps. */ 023 static GtkWidget* create_dummy_pixmap (GtkWidget *widget); 024 025 GtkWidget* 026 lookup_widget (GtkWidget *widget, 027 const gchar *widget_name) 028 { 029 GtkWidget *parent, *found_widget; 030 031 for (;;) 032 { 033 if (GTK_IS_MENU (widget)) 034 parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); 035 else 036 parent = widget->parent; 037 if (parent == NULL) 038 break; 039 widget = parent; 040 } 041 042 found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), 043 widget_name); 044 if (!found_widget) 045 g_warning ("Widget not found: %s", widget_name); 046 return found_widget; 047 } 048 049 /* This is a dummy pixmap you use when a pixmap can't be found. */ 050 static char * *dummy_pixmap_xpm[] = { 051 /* columns rows colors chars-per-pixel */ 052 "1 1 1 1", 053 " c None", 054 /* pixels */ 055 " " 056 }; 057 058 /* This is an internally used function to create pixmaps. */ 059 static GtkWidget* 060 create_dummy_pixmap (GtkWidget *widget) 061 { 062 GdkColormap *colormap; 063 GdkPixmap *gdkpixmap; 064 GdkBitmap *mask; 065 GtkWidget *pixmap; 066 067 colormap = gtk_widget_get_colormap (widget); 068 gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, 069 NULL, dummy_pixmap_xpm); 070 if (gdkpixmap == NULL) 071 g_error ("Couldn't create replacement pixmap."); 072 pixmap = gtk_pixmap_new (gdkpixmap, mask); 073 gdk_pixmap_unref (gdkpixmap); 074 gdk_bitmap_unref (mask); 075 return pixmap; 076 } 077 078 static GList *pixmaps_directories = NULL; 079 080 /* Use this function to set the directory containing installed pixmaps. */ 081 void 082 add_pixmap_directory (const gchar *directory) 083 { 084 pixmaps_directories = g_list_prepend (pixmaps_directories, 085 g_strdup (directory)); 086 } 087 088 /* This is an internally used function to create pixmaps. */ 089 GtkWidget* 090 create_pixmap (GtkWidget *widget, 091 const gchar *filename) 092 { 093 gchar *found_filename = NULL; 094 GdkColormap *colormap; 095 GdkPixmap *gdkpixmap; 096 GdkBitmap *mask; 097 GtkWidget *pixmap; 098 GList *elem; 099 100 /* You first try any pixmap directories set by the application. */ 101 elem = pixmaps_directories; 102 while (elem) 103 { 104 found_filename = check_file_exists ((gchar*)elem->data, filename); 105 if (found_filename) 106 break; 107 elem = elem->next; 108 } 109 110 /* If you haven't found the pixmap, try the source directory. */ 111 if (!found_filename) 112 { 113 found_filename = check_file_exists ("../pixmaps", filename); 114 } 115 116 if (!found_filename) 117 { 118 g_warning (_("Couldn't find pixmap file: %s"), filename); 119 return create_dummy_pixmap (widget); 120 } 121 122 colormap = gtk_widget_get_colormap (widget); 123 gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, 124 NULL, found_filename); 125 if (gdkpixmap == NULL) 126 { 127 g_warning (_("Error loading pixmap file: %s"), found_filename); 128 g_free (found_filename); 129 return create_dummy_pixmap (widget); 130 } 131 g_free (found_filename); 132 pixmap = gtk_pixmap_new (gdkpixmap, mask); 133 gdk_pixmap_unref (gdkpixmap); 134 gdk_bitmap_unref (mask); 135 return pixmap; 136 } 137 138 /* This is an internally used function to see whether a pixmap file exists. */ 139 gchar* 140 check_file_exists (const gchar *directory, 141 const gchar *filename) 142 { 143 gchar *full_filename; 144 struct stat s; 145 gint status; 146 147 full_filename = (gchar*) g_malloc (strlen (directory) + 1 148 + strlen (filename) + 1); 149 strcpy (full_filename, directory); 150 strcat (full_filename, G_DIR_SEPARATOR_S); 151 strcat (full_filename, filename); 152 153 status = stat (full_filename, &s); 154 if (status == 0 && S_ISREG (s.st_mode)) 155 return full_filename; 156 g_free (full_filename); 157 return NULL; 158 }
Lines 1 through 16 were covered previously in Listings 5.3 and 5.4 and their commentaries. Lines 18 through 23 are function prototypes for functions that come later in the file. Line 25 starts the lookup_widget function, which you will find to be extremely useful. It takes two parameters: The first is normally the top-level window, and the second is normally the name of a child widget within the top-level window parameter. Note that the child widget is passed in as a string, not a widget object. The purpose of this is to allow the project to have only the top-level windows as global variables , but to still allow access to any of the child widgets via the lookup_widget function. A full demonstration will follow at the end of this chapter. This file is smart, well-implemented, and solid from a software engineering standpoint.
The rest of the file contains some self-explanatory functions.
Finally, you come to callbacks.c . Glade creates this file with empty functions relating to the signals you specified from the Properties window when you were using Glade. Glade will not overwrite the functions you create when or if you reopen Glade and edit your project. However, I have noticed that occasionally, it may create the same function twice after editing an existing project.
01 #ifdef HAVE_CONFIG_H 02 # include <config.h> 03 #endif 04 05 #include <gtk/gtk.h> 06 07 #include "callbacks.h" 08 #include "interface.h" 09 #include "support.h" 10 11 12 void 13 on_cmd_main_clicked (GtkButton *button, 14 gpointer user_data) 15 { 16 gtk_main_quit(); 17 }
Line 16 was added as the last step for completing this program. Other than that, this is a straightforward file. It has one added callback on the clicked signal of cmd_main .
The file HelloWorld.glade is the Glade project file. It contains all the information needed to call up the project in Glade for editing. It stores the information in XML.
01 <?xml version="1.0"?> 02 <GTK-Interface> 03 04 <project> 05 <name>HelloWorld</name> 06 <program_name>helloworld</program_name> 07 <directory></directory> 08 <source_directory>src</source_directory> 09 <pixmaps_directory>pixmaps</pixmaps_directory> 10 <language>C</language> 11 <gnome_support>False</gnome_support> 12 <gettext_support>True</gettext_support> 13 <use_widget_names>False</use_widget_names> 14 <output_main_file>True</output_main_file> 15 <output_support_files>True</output_support_files> 16 <output_build_files>True</output_build_files> 17 <backup_source_files>True</backup_source_files> 18 <main_source_file>interface.c</main_source_file> 19 <main_header_file>interface.h</main_header_file> 20 <handler_source_file>callbacks.c</handler_source_file> 21 <handler_header_file>callbacks.h</handler_header_file> 22 <support_source_file>support.c</support_source_file> 23 <support_header_file>support.h</support_header_file> 24 <translatable_strings_file></translatable_strings_file> 25 </project> 26 27 <widget> 28 <class>GtkWindow</class> 29 <name>frm_main</name> 30 <title>HelloWorld</title> 31 <type>GTK_WINDOW_TOPLEVEL</type> 32 <position>GTK_WIN_POS_NONE</position> 33 <modal>False</modal> 34 <allow_shrink>False</allow_shrink> 35 <allow_grow>True</allow_grow> 36 <auto_shrink>False</auto_shrink> 37 38 <widget> 39 <class>GtkButton</class> 40 <name>cmd_main</name> 41 <can_focus>True</can_focus> 42 <signal> 43 <name>clicked</name> 44 <handler>on_cmd_main_clicked</handler> 45 <last_modification_time>Wed, 06 Sep 2000 15:41:32 GMT</last_modification_time> 46 </signal> 47 <label>HelloWorld 48 Click to Close.</label> 49 </widget> 50 </widget> 51 52 </GTK-Interface>
As you can see, this file is in XML. For those of you who don t know what XML is, here is a short explanation. By looking at the file, you can tell it is similar to HTML. (For those of you who don t know HTML, sorry, but I have to start somewhere You still should be able to pick up the main points.) The difference is that in HTML, the tags are defined for you, whereas in XML you define not only the data, but the tags as well. Look at lines 27 through 29 in Listing 5.7. Line 27, <widget> , defines a widget object. Line 29 tells the name of the object defined on line 27; the tag <name> is followed by the data frm_main , followed by the closing tag </name> . Line 50 closes out the widget object started on line 27 with the </widget> tag. Notice that a sub-widget is defined between lines 38 and 49. In this manner, an entire tree of disparate object types can be defined; to read a file like this, all you need is an XML parser. You don t need to know anything about the data, what type it is, what structure it is in, and so on.That is the strength of XML.
As to Listing 5.7, once you understand XML, it is rather self-explanatory.
only for RuBoard - do not distribute or recompile |