Introduction to GTK+:
This tutorial will cover tips on using Gnome GTK+ (Gimp ToolKit)
to build a GUI application for cross platform deployment.
Suggestions, tips and pitfalls are noted about the use of various GTK+ components.
GTK+ is a multi-platform GUI API library which includes the
standard interface widgets. It is a component of the GNOME desktop and
applications development environment which also includes multi-platform
API's for graphics,
video, window management, XML parsing, a thread library,
internationalization, database access and general desktop application
development.
There is a GUI interface builder, Glade which generates a GTK+ source
code
skeleton for rapid application development. The API's support the "C"
computer language. I usually encapsulate these calls within C++ objects
where convenient. There is also a C++ framework available known as
"gtkmm".
GTK is published under the GPL license and thus is free to use and redistribute.
Download/Install/Configure:
Linux:
- RPM:
Systems which are Linux based will have GTK and Gnome as part of a
regular install. The Gnome desktop and support services are NOT necessary to
write a basic GTK+ GUI application.
RedHat Linux RPMS's to install:
- gtk2
- gtk2-devel-2.XX
- gtk2-engines
- gtkhtml2-2.XX
- gtkam
- gtkam-gimp
- gtkglarea
- pango (Internationalized text handling)
- atk (Accessibility Toolkit)
- gdk-pixbuf-devel
- gdk-pixbuf-gnome
- gdk-pixbuf
- glib
- glade
- freetype
- fontconfig
- fontconfig-devel
Also requires tiff, png and jpeg libraries.
- Building GTK+ from source:
The following must be done before configuring and building:
- If installing to /opt, your PATH must include /opt/bin before
/bin and /usr/bin if conflicting versions of pkgconfig are pressent.
(export PATH=/opt/bin:$PATH)
- Set the environment variable LD_LIBRARY_PATH to include /opt/lib.
(export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH)
- Set environment variable PKG_CONFIG_PATH.
(export PKG_CONFIG_PATH=/opt/lib/pkgconfig:/usr/lib/pkgconfig)
Download the latest stable release from ftp://ftp.gtk.org/pub/gtk/. This requires downloading glib, atk, pango and gtk+ conpressed tar files.
Also download from the "dependencies/" directory pkgconfig.
Uncompress: tar -xzf pkgconfig-0.15.0.tar.gz glib-2.4.7.tar.gz pango-1.4.1.tar.gz atk-1.6.1.tar.gz gtk+-2.4.13.tar.gz
For each subdirectory created configure and make:
config-0.15.0
./configure --prefix=/opt
make
make install
cd ../glib-2.4.7
./configure --prefix=/opt
make
make install
cd ../pango-1.4.1
./configure --prefix=/opt
make
make install
cd ../atk-1.6.1
./configure --prefix=/opt
make
make install
cd ../gtk+-2.4.13
./configure --prefix=/opt
make
make install
Also see GTK+ building reference.
[Potential Pitfall]: Gtk+ configure error: "cofigure: error: Pango 1.2.0 and Xft backend is required for x11 target"
Test for problem with: pkg-config --modversion pangoxft
This command must return a version number or else this is an indication of a configuration problem.
Actual problem is in configure of pango which gives error:
...
checking for fontconfig >= 1.0.1... Package fontconfig was not found in the pkg-config search path.
Perhaps you should add the directory containing `fontconfig.pc'
to the PKG_CONFIG_PATH environment variable
No package 'fontconfig' found
configure: WARNING: No fontconfig found, skipping tests for FreeType and Xft
...
Fix:
Set environment variable PKG_CONFIG_PATH. (export PKG_CONFIG_PATH=/opt/lib/pkgconfig:/usr/lib/pkgconfig)
This is so that the file fontconfig.pc can be located.
This file is installed with the RPM fontconfig-devel. (required)
Microsoft Windows:
GTK can be compiled under
Cygwin
or Microsoft Visual C++.
MS/Windows install: I strongly recommend the GTK+ installer available from the Glade website:
MS/Windows GTK+ installer: http://gladewin32.sourceforge.net/
Two installers are available:
- gtk-win32-aio-2.4-rc16.exe:
Installs the complete GTK development environment (headers, libraries,
Glade GUI builder, GTK, GDK, Pango, etc.) Developers should use this installer to get
the latest version of Glade.
- gtk-win32-2.4.6-rc2.exe:
Installs GTK runtime environment.
GladWin32:
See:
GladWin32: GTK+ GUI builder.
VC++ 6.0 Compiler/IDE:
If creating a new Visual C++ project:
- File + New and select "Win 32 Console Application". Enter a project name.
- The next dialog box allows one to define the type of application: Select "An empty project" + "Finish".
To add default include directories which can be referenced with
<file.h> instead of "file.h": Tools + Options + select tab
"Directories" + "include files".
Note: If using VC++ 6.0, update VC++ 6.0 to SP5. Download and run to expand to subdir. Then run setupsp5.exe
Visual C++ 6.0 configuration:
- Add sockets library to support htonl(): Select "Project" + "Settings..." + "Link". Add "Object/library module": ws2_32.lib
- GTK:
VC++ compiler settings:
- Project + Settings + C++ tab:
Category: C++ Language Check "Enable exception handling".
Category: Code Generation
- Calling convention: _cdecl*
- Struct member alignment: 8 byte.
- Processor: Blend
Category: Precompiled Headers Check not using
Category: Preprocessor
Additional Include directories: C:\GTK\Win32\include,C:\libxml2\Win32\include
- Project + Settings + Link tab:
- Category: General
Object/library modules: glib-2.0.lib gobject-2.0.lib
gthread-2.0.lib gdk-win32-2.0.lib gdk_pixbuf-2.0.lib gtk-win32-2.0.lib
atk-1.0.lib pango-1.0.lib libxml2.lib
Check: "Link incrementally"
- Category: Input
Additional library path: C:\GTK\Win32\lib,C:\libxml2\Win32\lib
System configuration:
- System Properties:
- Select the "Advanced" tab.
- Select the "Environment Variables ..." button.
- In the "User Variables" frame, edit the environment variable "PATH" and add:
C:\GTK\bin
- Also set the following environment variables:
Environment Variable |
|
LIB |
c:\GTK\lib |
GTK_BASEPATH |
c:\GTK |
INCLUDE |
c:\GTK\INCLUDE;c:\GTK\GTK-2.0;c:\GTK\GLIB-2.0;
c:\GTK\PANGO-1.0; c:\GTK\ATK-1.0; c:\GTK\GTKGLEXT-1.0;
c:\GTK\GTK-2.0\INCLUDE; c:\GTK\GLIB-2.0\INCLUDE;
c:\GTK\GTKGLEXT\INCLUDE; c:\GTK\INCLUDE\LIBGLADE-2.0;
c:\GTK\INCLUDE\LIBXML2; |
Also see the YoLinux tutorial on MS/Visual C++ best practices so that the mess that this IDE can create is kept to a minimum.
Program Framework:
The basic framework of a GTK+ program requires:
- the include file: gtk/gtk.h
- callbacks used to close the principal window.
- main program.
- a call to gtk_init (&argc, &argv);
- instantiation of main window
- attach main window callbacks to main window. i.e. Callbacks to close window.
- a container widget to attach other widgets to the main window and begin the "widget tree".
- Attach widgets to parent components.
- render the widgets including the container widgets and principal window.
- a call to the main event loop: gtk_main ();
04 | static gboolean delete_event( GtkWidget *widget, |
11 | static void destroy( GtkWidget *widget, |
17 | int main( int argc, char *argv[] ) |
19 | GtkWidget *window_Widget; |
23 | gtk_init (&argc, &argv); |
27 | window_Widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
28 | gtk_window_set_title (GTK_WINDOW (window_Widget), "Example GTK Skeleton" ); |
32 | g_signal_connect (G_OBJECT (window_Widget), "delete_event" , |
33 | G_CALLBACK (delete_event), NULL); |
35 | g_signal_connect (G_OBJECT (window_Widget), "destroy" , |
36 | G_CALLBACK (destroy), NULL); |
38 | gtk_container_set_border_width (GTK_CONTAINER (window_Widget), 10); |
42 | vBox_Widget = gtk_vbox_new (.......); |
49 | gtk_box_pack_start (GTK_BOX (vBox_Widget), new_component_1_Widget, TRUE, TRUE, 0); |
55 | gtk_container_add (GTK_CONTAINER (window_Widget), vBox_Widget); |
60 | gtk_widget_show (vBox_Widget); |
61 | gtk_widget_show (window_Widget); |
GTK Objects and Widgets:
GTK is designed around a hierarchical class mechanism of
widgets and objects
of which GtkObject is the root. GtkObject provides the minimal set of
information to support the GTK signal mechanism of callbacks which
provide the functionality behind the GUI application.
GTK is written in C and thus implements this mechanism with structures,
composition and casting.
Casting allows one to view just the object info held in all objects without
knowing the details of the widget or derived object.
This principal is built-in to the GTK object and widget api.
GTK Widgets form a hierarchy of widgets joined together in a tree. Thus all
widgets must be "linked" together with container or packing widgets to
create this tree. It is this tree which is traversed for rendering of the GUI
and for signal/callback handling. Thus an object which is "destroyed" will
destroy the entire branch unless it is re-attached at some point in the hierarchy.
Widgets:
There are numerous widgets defined and available for use. One
can also generate thier own widgets and compose widgets from
combinations of other widgets.
Examples:
- Push Buttons
- Menu Widget
- Radio Button
- Check Button
- Scroll Bar
- Drawing Area
- Tree View
- Text View
- Text Entry Box
- Combo Box
- Scroll Bars (horizontal and vertical)
Signals can then be associated with a widget so that an action
(i.e. button release) on a Button widget will invoke a callback
function to be executed and perform the desired task (i.e. process or
display something or both).
Container/Packing Widgets:
Container, Alignment and Packing widgets are used to place
display widgets and other container widgets within a window frame. They
do not take any form when rendered. (invisible)
Types:
- gtk_container_add()
This will hold a single widget.
- gtk_alignment_new()
Position a widget within it's window.
Use the function gtk_alignment_set() to control layout and spacing.
- gtk_fixed_new()
Fix widget position in window relative to upper left hand corner.
Use the functions gtk_fixed_put(), gtk_fixed_move(),
gtk_fixed_set_has_window() and gtk_fixed_get_has_window() to control
layout.
- gtk_layout_new()
Layout in infinite scrolling area.
Use the functions gtk_layout_put(), gtk_layout_move(),
gtk_layout_set_size(), gtk_layout_get_hadjustment(),
gtk_layout_get_vadjustment(), gtk_layout_set_hadjustment() and
gtk_layout_set_vadjustment() to control layout and spacing.
- gtk_hbox_new()
Horizontal boxes
Use the functions gtk_box_pack_start() and gtk_box_pack() to control layout and spacing.
Also see gtk_hbutton_box_new().
- gtk_vbox_new()
Vertical Boxes
Use the functions gtk_box_pack_start() and gtk_box_pack() to control layout and spacing.
Also see gtk_vbutton_box_new().
- gtk_table_new()
Table
Use the functions gtk_table_attach(), gtk_table_attach_defaults(),
gtk_table_set_row_spacing(), gtk_table_set_col_spacing(), to control
layout and spacing.
Signals:
Signals allow for a routine to be called when a user interaction occurs.
Use the routine g_signal_connect() to attach a "callback" function
to a user interaction ("signal").
The signals have pre-defined names. Each widget has a defined list of
signals which can act on the widget. For example,
a "window" widget may have the signals:
- activate_focus
- frame_event
- move_focus
- ...
The widget also inherits the ability to receive a set of signals which all
widgets can receive:
- delete_event
- button_press_event
- button_release_event
- expose_event
- hide_event
- show
- ...
Define the callback functions:
07 | delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) |
14 | destroy(GtkWidget *widget, gpointer data) |
Associate the callback function to a user action performed on a specified widget:
08 | g_signal_connect((gpointer) mainWindow, "delete_event" , G_CALLBACK(delete_event), NULL); |
12 | g_signal_connect((gpointer) mainWindow, "destroy" , G_CALLBACK(destroy), NULL); |
The list of signals available are dependent on the widget. It is for this reason that the GUI builder Glade is very useful.
Passing C++ object to a Signal:
02 | on_applyButton_clicked(GtkWidget *button, gpointer data) |
04 | CclassDef *obj = static_cast <CclassDef *>(data); |
06 | gtk_widget_destroy((GTK_WIDGET(obj->getWindowPtr())); |
14 | g_signal_connect((gpointer) applyButton, "clicked" , |
15 | G_CALLBACK(on_applyButton_clicked), this ); |
Signal inheritance:
The object oriented nature of GTK allows a widget to inherit the ability to
receive signal types of the parents in its inheritance tree. Thus signals
inherit pre-defined behaviors already configured in the GTK GUI and components.
A signal daisy-chain is processed which executes the user defined signals
and then processes the inherited signals. One may break this chain of
events so that only your signal handlers are processed,
To prevent inheritance of predefined signal behaviors, the signal function
must return a boolean. Return "true" to break inheritance.
Return "false" to maintain the behavior of predefined parent signals such that
the chain of inherited signals are maintained and processed after your signal
is processed.
Example:
GTK predefines the behavior of the up/down arrow keys for GUI focus navigation
traversal of the interactive GUI control widgets.
If using the up/down arrow within a text entry box we would need to deactivate
the predefined navigation of the GUI by returning "true" to break the chain.
This example handles text entry and up/down arrows with two callbacks attached to the same widget.
04 | on_entry_activate(GtkWidget *widget, gpointer data) |
06 | char *string_entered = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); |
07 | if ( strlen (string_entered) > 0) |
13 | g_free(string_entered); |
19 | on_entryBox1_key_press_event (GtkWidget *widget, |
23 | gboolean breakInheritance = true ; |
28 | if (event->keyval == 65362) |
30 | gtk_entry_set_text(GTK_ENTRY(widget), text_string_prev); |
31 | gtk_editable_set_position(GTK_EDITABLE(widget), strlen (text_string_prev); |
33 | else if (event->keyval == 65364) |
37 | gtk_entry_set_text(GTK_ENTRY(widget), "" ); |
38 | gtk_editable_set_position(GTK_EDITABLE(widget), "" ); |
42 | gtk_entry_set_text(GTK_ENTRY(widget), text_string_next); |
43 | gtk_editable_set_position(GTK_EDITABLE(widget), strlen (text_string_next); |
48 | breakInheritance = false ; |
57 | g_signal_connect((gpointer) textEntryWidget, "activate" , |
58 | G_CALLBACK(on_entry_activate), NULL); |
60 | gtk_signal_connect (GTK_OBJECT (textEntryWidget), "key_press_event" , |
61 | GTK_SIGNAL_FUNC (on_entryBox1_key_press_event), |
Also see: GtkKeySnoopFunc()
Tips:
- If trying to fix a crash, don't "gtk_widget_show()" a widget until it has been attached to a parent
widget first.
The widget structure is a tree hierarchy starting from the parent window and branching to each and every widget.
Colors:
Change/assign button color:
(code snippet)
02 | GtkWidget *button_Widget; |
08 | gtk_color_button_set_color(button_Widget,colorButton); |
10 | gtk_widget_show (button_Widget); |
OR:
02 | GtkWidget *button_Widget; |
04 | gdk_color_parse ( "red" , &colorRed); |
07 | button_Widget = gtk_button_new_with_label( "Button" ); |
09 | gtk_widget_modify_base (button_Widget, GTK_STATE_NORMAL, &colorRed); |
10 | gtk_widget_modify_fg (button_Widget, GTK_STATE_NORMAL, &colorRed); |
11 | gtk_widget_modify_bg (button_Widget, GTK_STATE_NORMAL, &colorRed); |
12 | gtk_widget_modify_bg (button_Widget, GTK_STATE_PRELIGHT, &colorRed); |
14 | gtk_widget_show (button_Widget); |
Color declaration and assignment:
(code snippet)
02 | static GdkColor colorGreen; |
03 | static GdkColor colorYellow; |
04 | static GdkColor colorRed; |
05 | static GdkColor colorBlack; |
09 | gdk_color_parse( "green" , &colorGreen); |
10 | gdk_color_parse( "yellow" , &colorYellow); |
11 | gdk_color_parse( "red" , &colorRed); |
12 | gdk_color_parse( "black" , &colorBlack); |
Text Labels:
Text labels can be placed anywhere on the GUI display.
Placement is usually with a container such as "vbox" or "hbox". Note
that the text can be modified using the html/xml tag "small".
03 | GtkWidget *textLabel_Widget; |
05 | char *textLabel= "Display Label" ; |
07 | sprintf (displayLabel, "<small>%s</small>" , textLabel); |
09 | textLabel_Widget = gtk_label_new (NULL); |
10 | gtk_label_set_markup(GTK_LABEL (textLabel_Widget), displayLabel); |
11 | gtk_label_set_justify(GTK_LABEL (textLabel_Widget),GTK_JUSTIFY_LEFT); |
12 | gtk_misc_set_alignment (GTK_MISC (textLabel_Widget), 0, 0.5); |
14 | gtk_widget_show (textLabel_Widget); |
Pango:
Pango is the framework for layout and rendereing of internationalized text in
GTK+. On Linux systems the final rendering is performed by X-Windows.
Pango uses Unicode characters internally. Examples here use UTF-8
which is compatable with existing ASCII 8-bit software. Offsets in Pango
are counted in bytes and not characters.
While Pango was created to support non-Roman character languages like
Japanese, Greek and Arabic, only English UTF-8 examples are shown.
Pango also supports a simple subset of HTML/XML for text attributes:
HTML Tag |
Description |
<b> |
Bold |
<big>
or
<span size="larger"> |
Increase font size |
<small>
or
<span size="smaller"> |
Decrease font size |
<i> |
Italic |
<s> |
Strikethrough |
<subs> |
Subscript |
<sup> |
superscript |
<tt> |
Monospace Font |
<u> |
Underline |
<span> |
Use with attributes to specify rendering:
- font_desc: Shorthand label for font family, style, size, ...
- font_family: Name of font family.
- face: A font family attribute.
- size: # of thousandths of a point.
- style: normal, oblique, italic
- weight: ultralight, normal, heavy
- variant: normal, smallcaps
- stretch: ultracondensed, normal, ultraexpanded
- foreground: RGB color specification or color name. (i.e. #ff0000 or "red")
- background: RGB color specification or color name. (i.e. #0000ff or "blue")
- underline: single, double, low, none
- rise: position change in ten thousandths em. Subscript (-)ve, superscript (+)ve.
- strikethrough: true, false
- lang: Language code.
Note: This also describes the set of Pango text attributes.
|
The XML tree root element tags are <markup> and </markup> but it
is not necessary to reference or include them.
Example:
Pango converts HTML markup string into a text string and list of attributes and enables layout and rendering.
05 | gchar *stringMarkupText = "<span foreground=\"blue\"><b>Bold</b> <u>is</u> <i>beautiful</i></span>" ; |
06 | gchar *stringPlainText; |
07 | PangoAttrList *attrList; |
08 | GtkWidget *displayLabelWidget; |
11 | pango_parse_markup(stringMarkupText, -1, 0, &attrList, &stringPlainText, NULL, NULL); |
12 | displayLabelWidget = gtk_label_new(stringPlainText); |
13 | gtk_label_set_attributes(GTK_LABEL(displayLabelWidget), attrList); |
15 | gtk_widget_show(displayLabelWidget); |
This converts the HTML representation of the text in "
stringMarkupText"
into text ("
stringPlainText") and applied attributes "
attrList".
Note: One may also use the equivalent GTK+ calls to gtk_label_set_markup() and the function above in the Text Labels example.
Result:
Bold is beautiful
Links:
Text Boxes/Fonts:
The first series of examples are for the GTK text_entry
and the second set briefly cover the GTK text_view widget.
The text entry widget is preffered as it supports more features and fully supports view only functionality.
GTK Text Entry Widget:
Creates a new text entry/display widget.
3 | GtkWidget *text_entry_Widget = gtk_entry_new(); |
Set entry text box background color:
3 | gtk_widget_modify_base(text_entry_Widget, GTK_STATE_NORMAL, &colorBlack); |
See discussion of color definitions above.
Display entry text in green.
3 | gtk_widget_modify_text(text_entry_Widget, GTK_STATE_NORMAL, &colorGreen); |
See discussion of color definitions above.
Modify entry text box style so text is BOLD:
3 | GtkStyle *style = gtk_widget_get_style(text_entry_Widget); |
4 | pango_font_description_set_weight(style->font_desc, PANGO_WEIGHT_BOLD); |
5 | gtk_widget_modify_font(text_entry_Widget, style->font_desc); |
Set entry text box size:
5 | gtk_entry_set_width_chars(GTK_ENTRY(text_entry_Widget), text_width); |
Set entry text box editable(default)/not editable:
03 | bool text_is_editable = false ; |
07 | gtk_editable_set_editable(GTK_EDITABLE(text_entry_Widget), FALSE); |
08 | GTK_WIDGET_UNSET_FLAGS(text_entry_Widget, GTK_CAN_FOCUS); |
Display text in the GTK text entry box widget.
4 | char _txtBuffer = "Display Text" ; |
6 | gtk_entry_set_text(GTK_ENTRY(text_entry_Widget), _txtBuffer); |
Set display box as "insensitive". Display background as "grayed out" and disable
user interaction.
3 | gboolean _isSensitive = false ; |
5 | gtk_widget_set_sensitive(text_entry_Widget, _isSensitive); |
Sensitivity:
- Sensitive: boolean set to true
Interaction with widget (text entry widget) is allowed.
- Insensitive: boolean set to false
Interaction with widget (text entry widget) is not allowed.
Background is "grayed out".
One can also set the state to sensitive/insensitive using the routine
gtk_widget_set_state().
Display tooltip when hovering text box:
04 | char *toolTipsText = "Tool Tips Text Displayed When Mouse Hovers Text Entry Box" ; |
05 | GtkTooltips *tooltipsA; |
09 | tooltipsA = gtk_tooltips_new(); |
13 | gtk_tooltips_set_tip(tooltipsA, text_entry_Widget, toolTipsText, NULL); |
GTK.org: Tooltips tutorial
Text display box with modified background and text:
Source code to this example: gtkTextEntryBox.c
Widgets and g_Threads:
Note: If updating the text with new data from a spawned GTK thread which listens to
a socket or performs digital acquisition, one must protect the code segment
with a GTK mutex.
This must be applied to the calls in the spawned thread and not in the GUI
main thread.
This will avoid GUI update conflicts between gtk_main() and the GTK
calls invoked in the thread. Thread support and stability is significantly
improved in GTK+ 2.6.2.
4 | gtk_entry_set_text(GTK_ENTRY(text_entry_Widget), _txt); |
The widget pointer
text_entry_Widget is global to both the main
thread and the spawned thread.
The required basic gdk threads framework:
03 | if ( !g_thread_supported() ) |
07 | printf ( "g_thread supported\n" ); |
11 | printf ( "g_thread NOT supported\n" ); |
gdk_threads_enter() is simply a wrapper function that locks the
gdk_threads_mutex. Similarly, gdk_threads_leave() is a wrapper that
unlocks the mutex.
A look at the source of gtkmain.c shows that the lock is released while the main loop is running.
[Potential Pitfall]: You will create a deadlock
condition if you try to update a widget before it has been realized.
GTK Text View Widget:
This is an alternate method of displaying text in a box. I prefer using a
text entry widget as it has more available options.
03 | GtkWidget *textView_Widget; |
05 | char *txtBuffer = "Display Text" ; |
07 | textView_Widget = gtk_text_view_new (); |
08 | gtk_widget_set_usize (textView_Widget, text_width, -2); |
09 | gtk_text_view_set_editable( GTK_TEXT_VIEW (textView_Widget), FALSE); |
10 | gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW (textView_Widget), FALSE); |
11 | gtk_text_view_set_pixels_above_lines( GTK_TEXT_VIEW (textView_Widget), 5); |
12 | gtk_text_view_set_left_margin( GTK_TEXT_VIEW (textView_Widget), 3); |
14 | gtk_text_buffer_set_text(gtk_text_view_get_buffer (GTK_TEXT_VIEW (textView_Widget)), |
16 | gtk_widget_modify_text (textView_Widget, GTK_STATE_NORMAL, &colorGreen); |
17 | gtk_widget_modify_base (textView_Widget, GTK_STATE_NORMAL, &colorBlack); |
19 | gtk_widget_show (textView_Widget); |
See discussion of color definitions above.
Bitmaps:
The following code snippet shows how to embed and display an image within
software. Any bitmap image (gif, jpeg, etc) can be converted to an "xpm"
file using image manipulation software such as XV or Gimp and performing a "Save as ...".
[Potential Pitfall]:
If your application core dumps when trying to employ pixmaps, try one of these clearly opposite solutions:
- Place "gtk_widget_show(window)" near the end just before gtk_main()
- Call "gtk_widget_show(window)" after declaration and attributes are set.
(Fairly standard)
I have employed both solutions to fix a core dump.
If one does not work try the other.
Transparent xpm include file: green_DOT.xpm
01 | static char *green_DOT_xpm[] = { |
11 | "tttttttttttttttttttt" , |
12 | "ttttttt.....tttttttt" , |
13 | "ttttt#hklmlkd.tttttt" , |
Embedding the pixmap in your display:
02 | #include "green_DOT.xpm" |
11 | window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
13 | if (!window) printf ( "No window. Bad!\n" ); |
14 | style = gtk_widget_get_style( window ); |
15 | icon = gdk_pixmap_create_from_xpm_d(GTK_WIDGET(window)->window, |
17 | &style->bg[GTK_STATE_NORMAL], |
19 | image = gtk_pixmap_new(icon, icon_mask); |
21 | gtk_widget_show(image); |
22 | gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); |
24 | gtk_widget_show (window); |
26 | g_object_unref(icon_mask); |
One may also read the XPM file using the function
gtk_image_new_from_file(file-name) to generate a widget.
Using images to display status: It may be necessary to use
pixmaps to display status thus changing the display. In this example we
generate and display three color boxes (grey, red and green) but only
display one at a time
depending on which is relevant.
Generate the pixmap widgets: (See above discussion to see full source code.)
06 | greyBox = gtk_pixmap_new(_icon_grey, _icon_mask_grey); |
08 | greenBox = gtk_pixmap_new(_icon_green, _icon_mask_green); |
10 | redBox = gtk_pixmap_new(_icon_red, _icon_mask_red); |
12 | gtk_widget_show(greyBox); |
Attach all three pixmap widgets to the same location:
05 | hbox1 = gtk_hbox_new (FALSE, 0); |
06 | gtk_container_add (GTK_CONTAINER (window), hbox1); |
09 | gtk_box_pack_start(GTK_BOX(hbox1), greyBox, TRUE, TRUE, 0); |
10 | gtk_box_pack_start(GTK_BOX(hbox1), greenBox, TRUE, TRUE, 0); |
11 | gtk_box_pack_start(GTK_BOX(hbox1), redBox, TRUE, TRUE, 0); |
14 | gtk_misc_set_alignment(GTK_MISC(greyBox), 1, 0.5); |
15 | gtk_misc_set_alignment(GTK_MISC(greenBox), 1, 0.5); |
16 | gtk_misc_set_alignment(GTK_MISC(redBox), 1, 0.5); |
18 | gtk_widget_show(hbox1); |
Callbacks to switch displays:
Display green box:
2 | gtk_widget_hide(greyBox); |
3 | gtk_widget_hide(redBox); |
4 | gtk_widget_show(greenBox); |
Display red box:
2 | gtk_widget_hide(greyBox); |
3 | gtk_widget_hide(greenBox); |
4 | gtk_widget_show(redBox); |
The three images are all located in the same place but only one is displayed at a time.
Source code to this example: gtkSwapPixmaps.c
Compile:
- gcc gtkSwapPixmaps.c -o gtkSwapPixmaps `pkg-config --cflags --libs gtk+-2.0`
OR
- gcc gtkSwapPixmaps.c -o gtkSwapPixmaps
-I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include
-I/usr/include/atk-1.0 -I/usr/include/pango-1.0 -I/usr/X11R6/include
-I/usr/include/freetype2 -I/usr/include/glib-2.0
-I/usr/lib/glib-2.0/include -Wl,--export-dynamic -lgtk-x11-2.0
-lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangoxft-1.0
-lpangox-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0
Check Box:
Creates a check box button. This button is not "grayed out" when insensitive
but they are unselectable until the state is changed to
GTK_STATE_SENSITIVE (default).
03 | GtkWidget *button_Widget = gtk_check_button_new(); |
05 | GtkStyle *style = gtk_widget_get_style(button_Widget); |
06 | gtk_widget_modify_base(button_Widget, GTK_STATE_INSENSITIVE, |
07 | &style->base[GTK_STATE_NORMAL]); |
08 | gtk_widget_modify_text(button_Widget, GTK_STATE_INSENSITIVE, |
09 | &style->text[GTK_STATE_NORMAL]); |
11 | return button_Widget; OR gtk_widget_show(button_Widget); |
Using Glade Support Routines:
The GNOME GTK+ GUI builder Glade will generate a software skeleton for
an application which is compilable and executable.
Glade will also include many support routines which are useful whether you
use Glade or not in the construction of your GTK+ application.
These support routines are found in the Glade generated file src/support.c.
Glade lookup routine lookup_widget() (See Glade generated file src/support.c): Start at tree root "widget" and return "GtkWidget"
corresponding to the "widget_name" (index to lookup table). If the widget tree
root is given, then this routine can traverse the widget tree and return
the GtkWidget pointer to the widget identified by name.
This eliminates the need to pass all possible
pointers used in processing but instead just pass around one, the root
(i.e. main window) widget, and use lookup_widget() to locate all
the others. Actually any widget can be passed as the routine will traverse
the tree to first find the root ans then scan the tree.
One must assign widget names using the Glade macro GLADE_HOOKUP_OBJECT.
Glade will generate these associations in the generated file src/interface.c.
05 | #define GLADE_HOOKUP_OBJECT(component,widget,name) \ |
06 | g_object_set_data_full (G_OBJECT (component), name, \ |
07 | gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) |
09 | #define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ |
10 | g_object_set_data (G_OBJECT (component), name, widget) |
15 | GLADE_HOOKUP_OBJECT_NO_REF(mainWindow, mainWindow, "mainWindow" ); |
16 | GLADE_HOOKUP_OBJECT(mainWindow, vbox1, "vbox1" ); |
17 | GLADE_HOOKUP_OBJECT(mainWindow, mainMenuBar, "mainMenuBar" ); |
18 | GLADE_HOOKUP_OBJECT(mainWindow, fileMenuitem, "fileMenuitem" ); |
19 | GLADE_HOOKUP_OBJECT(mainWindow, fileMenuitem_menu, "fileMenuitem_menu" ); |
20 | GLADE_HOOKUP_OBJECT(mainWindow, quitMenuItem, "quitMenuItem" ); |
At the heart of the GLADE_HOOKUP_OBJECT macro is the GObject call
g_object_set_data_full.
This enables the association of text labels to widget pointers.
One may add an association directly by using this routine.
The widget pointer can then be found using the widget identifier. i.e.:
3 | GtkWidget *widgetPtrToBefound = lookup_widget(window, "name_of_widget_ie_vbox1" ); |
4 | assert (widgetPtrToBefound != NULL); |
The routine lookup_widget as generated by Glade in the file
src/support.c.
05 | lookup_widget(GtkWidget *widget, const gchar *widget_name) |
07 | GtkWidget *parent, *found_widget; |
11 | if (GTK_IS_MENU(widget)) |
12 | parent = gtk_menu_get_attach_widget(GTK_MENU(widget)); |
14 | parent = widget->parent; |
17 | parent = (GtkWidget*) g_object_get_data(G_OBJECT(widget), "GladeParentKey" ); |
25 | found_widget = (GtkWidget*) g_object_get_data(G_OBJECT(widget), widget_name); |
27 | g_warning ( "Widget not found: %s" , widget_name); |
Links:

Books: