Labels are used a lot in GTK, and are relatively simple. Labels emit
no signals as they do not have an associated X window. If you need to
catch signals, or do clipping, place it inside a
EventBox widget or a Button widget.
To create a new label, use:
GtkWidget *gtk_label_new( char *str );
The sole argument is the string you wish the label to display.
To change the label's text after creation, use the function:
The first argument is the label you created previously (cast
using the GTK_LABEL() macro), and the second is the new string.
The space needed for the new string will be automatically adjusted if
needed. You can produce multi-line labels by putting line breaks in
the label string.
The first argument is the label you've created, and the second,
the return for the string. Do not free the return string, as it is
used internally by GTK.
The pattern argument indicates how the underlining should look. It
consists of a string of underscore and space characters. An underscore
indicates that the corresponding character in the label should be
underlined. For example, the string
"__ __"
would underline the
first two characters and eight and ninth characters.
Below is a short example to illustrate these functions. This example
makes use of the Frame widget to better demonstrate the label
styles. You can ignore this for now as the
Frame widget is explained later on.
/* example-start label label.c */
#include <gtk/gtk.h>
int main( int argc,
char *argv[] )
{
static GtkWidget *window = NULL;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *label;
/* Initialise GTK */
gtk_init(&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC(gtk_main_quit),
NULL);
gtk_window_set_title (GTK_WINDOW (window), "Label");
vbox = gtk_vbox_new (FALSE, 5);
hbox = gtk_hbox_new (FALSE, 5);
gtk_container_add (GTK_CONTAINER (window), hbox);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (window), 5);
frame = gtk_frame_new ("Normal Label");
label = gtk_label_new ("This is a Normal label");
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
frame = gtk_frame_new ("Multi-line Label");
label = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
"Third line");
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
frame = gtk_frame_new ("Left Justified Label");
label = gtk_label_new ("This is a Left-Justified\n" \
"Multi-line label.\nThird line");
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
frame = gtk_frame_new ("Right Justified Label");
label = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
"Fourth line, (j/k)");
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
vbox = gtk_vbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
frame = gtk_frame_new ("Line wrapped label");
label = gtk_label_new ("This is an example of a line-wrapped label. It " \
"should not be taking up the entire " /* big space to test spacing */\
"width allocated to it, but automatically " \
"wraps the words to fit. " \
"The time has come, for all good men, to come to " \
"the aid of their party. " \
"The sixth sheik's six sheep's sick.\n" \
" It supports multiple paragraphs correctly, " \
"and correctly adds "\
"many extra spaces. ");
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
frame = gtk_frame_new ("Filled, wrapped label");
label = gtk_label_new ("This is an example of a line-wrapped, filled label. " \
"It should be taking "\
"up the entire width allocated to it. " \
"Here is a sentence to prove "\
"my point. Here is another sentence. "\
"Here comes the sun, do de do de do.\n"\
" This is a new paragraph.\n"\
" This is another newer, longer, better " \
"paragraph. It is coming to an end, "\
"unfortunately.");
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
frame = gtk_frame_new ("Underlined label");
label = gtk_label_new ("This label is underlined!\n"
"This one is underlined in quite a funky fashion");
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
gtk_label_set_pattern (GTK_LABEL (label),
"_________________________ _ _________ _ ______ __ _______ ___");
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show_all (window);
gtk_main ();
return(0);
}
/* example-end */
The Arrow widget draws an arrowhead, facing in a number of possible
directions and having a number of possible styles. It can be very
useful when placed on a button in many applications. Like the Label
widget, it emits no signals.
There are only two functions for manipulating an Arrow widget:
The first creates a new arrow widget with the indicated type and
appearance. The second allows these values to be altered
retrospectively. The arrow_type argument may take one of the
following values:
These are the little text strings that pop up when you leave your
pointer over a button or other widget for a few seconds. They are easy
to use, so I will just explain them without giving an example. If you
want to see some code, take a look at the testgtk.c program
distributed with GTK.
Widgets that do not receive events (widgets that do not have their
own window) will not work with tooltips.
The first call you will use creates a new tooltip. You only need to do
this once for a set of tooltips as the GtkTooltips object this
function returns can be used to create multiple tooltips.
GtkTooltips *gtk_tooltips_new( void );
Once you have created a new tooltip, and the widget you wish to use it
on, simply use this call to set it:
The first argument is the tooltip you've already created, followed by
the widget you wish to have this tooltip pop up for, and the text you
wish it to say. The last argument is a text string that can be used as
an identifier when using GtkTipsQuery to implement context sensitive
help. For now, you can set it to NULL.
Sets how many milliseconds you have to hold your pointer over the
widget before the tooltip will pop up. The default is 500
milliseconds (half a second).
Progress bars are used to show the status of an operation. They are
pretty easy to use, as you will see with the code below. But first
lets start out with the calls to create a new progress bar.
There are two ways to create a progress bar, one simple that takes
no arguments, and one that takes an Adjustment object as an
argument. If the former is used, the progress bar creates its own
adjustment object.
The first argument is the progress bar you wish to operate on, and the
second argument is the amount "completed", meaning the amount the
progress bar has been filled from 0-100%. This is passed to the
function as a real number ranging from 0 to 1.
GTK v1.2 has added new functionality to the progress bar that enables
it to display its value in different ways, and to inform the user of
its current value and its range.
A progress bar may be set to one of a number of orientations using the
function
When used as a measure of how far a process has progressed, the
ProgressBar can be set to display its value in either a continuous
or discrete mode. In continuous mode, the progress bar is updated for
each value. In discrete mode, the progress bar is updated in a number
of discrete blocks. The number of blocks is also configurable.
The style of a progress bar can be set using the following function.
As well as indicating the amount of progress that has occured, the
progress bar may be set to just indicate that there is some
activity. This can be useful in situations where progress cannot be
measured against a value range. Activity mode is not effected by the
bar style that is described above, and overrides it. This mode is
either TRUE or FALSE, and is selected by the following function.
The x_align and y_align arguments take values between 0.0
and 1.0. Their values indicate the position of the text string within
the trough. Values of 0.0 for both would place the string in the top
left hand corner; values of 0.5 (the default) centres the text, and
values of 1.0 places the text in the lower right hand corner.
The current text setting of a progress object can be retrieved using
the current or a specified adjustment value using the following two
functions. The character string returned by these functions should be
freed by the application (using the g_free() function). These
functions return the formatted string that would be displayed within
the trough.
These functions are pretty self explanatory. The last function uses
the the adjustment of the specified progess object to compute the
percentage value of the given range value.
Progress Bars are usually used with timeouts or other such functions
(see section on
Timeouts, I/O and Idle Functions) to give the illusion of multitasking. All will employ the
gtk_progress_bar_update function in the same manner.
Here is an example of the progress bar, updated using timeouts. This
code also shows you how to reset the Progress Bar.
/* example-start progressbar progressbar.c */
#include <gtk/gtk.h>
typedef struct _ProgressData {
GtkWidget *window;
GtkWidget *pbar;
int timer;
} ProgressData;
/* Update the value of the progress bar so that we get
* some movement */
gint progress_timeout( gpointer data )
{
gfloat new_val;
GtkAdjustment *adj;
/* Calculate the value of the progress bar using the
* value range set in the adjustment object */
new_val = gtk_progress_get_value( GTK_PROGRESS(data) ) + 1;
adj = GTK_PROGRESS (data)->adjustment;
if (new_val > adj->upper)
new_val = adj->lower;
/* Set the new value */
gtk_progress_set_value (GTK_PROGRESS (data), new_val);
/* As this is a timeout function, return TRUE so that it
* continues to get called */
return(TRUE);
}
/* Callback that toggles the text display within the progress
* bar trough */
void toggle_show_text( GtkWidget *widget,
ProgressData *pdata )
{
gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
GTK_TOGGLE_BUTTON (widget)->active);
}
/* Callback that toggles the activity mode of the progress
* bar */
void toggle_activity_mode( GtkWidget *widget,
ProgressData *pdata )
{
gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
GTK_TOGGLE_BUTTON (widget)->active);
}
/* Callback that toggles the continuous mode of the progress
* bar */
void set_continuous_mode( GtkWidget *widget,
ProgressData *pdata )
{
gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
GTK_PROGRESS_CONTINUOUS);
}
/* Callback that toggles the discrete mode of the progress
* bar */
void set_discrete_mode( GtkWidget *widget,
ProgressData *pdata )
{
gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
GTK_PROGRESS_DISCRETE);
}
/* Clean up allocated memory and remove the timer */
void destroy_progress( GtkWidget *widget,
ProgressData *pdata)
{
gtk_timeout_remove (pdata->timer);
pdata->timer = 0;
pdata->window = NULL;
g_free(pdata);
gtk_main_quit();
}
int main( int argc,
char *argv[])
{
ProgressData *pdata;
GtkWidget *align;
GtkWidget *separator;
GtkWidget *table;
GtkAdjustment *adj;
GtkWidget *button;
GtkWidget *check;
GtkWidget *vbox;
gtk_init (&argc, &argv);
/* Allocate memory for the data that is passwd to the callbacks */
pdata = g_malloc( sizeof(ProgressData) );
pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_policy (GTK_WINDOW (pdata->window), FALSE, FALSE, TRUE);
gtk_signal_connect (GTK_OBJECT (pdata->window), "destroy",
GTK_SIGNAL_FUNC (destroy_progress),
pdata);
gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 0);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
gtk_widget_show(vbox);
/* Create a centering alignment object */
align = gtk_alignment_new (0.5, 0.5, 0, 0);
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
gtk_widget_show(align);
/* Create a Adjusment object to hold the range of the
* progress bar */
adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
/* Create the GtkProgressBar using the adjustment */
pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
/* Set the format of the string that can be displayed in the
* trough of the progress bar:
* %p - percentage
* %v - value
* %l - lower range value
* %u - upper range value */
gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
"%v from [%l-%u] (=%p%%)");
gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
gtk_widget_show(pdata->pbar);
/* Add a timer callback to update the value of the progress bar */
pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
separator = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
gtk_widget_show(separator);
/* rows, columns, homogeneous */
table = gtk_table_new (2, 3, FALSE);
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
gtk_widget_show(table);
/* Add a check button to select displaying of the trough text */
check = gtk_check_button_new_with_label ("Show text");
gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
5, 5);
gtk_signal_connect (GTK_OBJECT (check), "clicked",
GTK_SIGNAL_FUNC (toggle_show_text),
pdata);
gtk_widget_show(check);
/* Add a check button to toggle activity mode */
check = gtk_check_button_new_with_label ("Activity mode");
gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
5, 5);
gtk_signal_connect (GTK_OBJECT (check), "clicked",
GTK_SIGNAL_FUNC (toggle_activity_mode),
pdata);
gtk_widget_show(check);
separator = gtk_vseparator_new ();
gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
5, 5);
gtk_widget_show(separator);
/* Add a radio button to select continuous display mode */
button = gtk_radio_button_new_with_label (NULL, "Continuous");
gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
5, 5);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (set_continuous_mode),
pdata);
gtk_widget_show (button);
/* Add a radio button to select discrete display mode */
button = gtk_radio_button_new_with_label(
gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
"Discrete");
gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
5, 5);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (set_discrete_mode),
pdata);
gtk_widget_show (button);
separator = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
gtk_widget_show(separator);
/* Add a button to exit the program */
button = gtk_button_new_with_label ("close");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_widget_destroy,
GTK_OBJECT (pdata->window));
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
/* This makes it so the button is the default. */
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
/* This grabs this button to be the default button. Simply hitting
* the "Enter" key will cause this button to activate. */
gtk_widget_grab_default (button);
gtk_widget_show(button);
gtk_widget_show (pdata->window);
gtk_main ();
return(0);
}
/* example-end */
So you see, it simply creates a window, and then packs a vbox into the
top, which contains a separator and then an hbox called the
"action_area".
The Dialog widget can be used for pop-up messages to the user, and
other similar tasks. It is really basic, and there is only one
function for the dialog box, which is:
GtkWidget *gtk_dialog_new( void );
So to create a new dialog box, use,
GtkWidget *window;
window = gtk_dialog_new ();
This will create the dialog box, and it is now up to you to use it.
You could pack a button in the action_area by doing something like this:
As an example in using the dialog box, you could put two buttons in
the action_area, a Cancel button and an Ok button, and a label in the
vbox area, asking the user a question or giving an error etc. Then
you could attach a different signal to each of the buttons and perform
the operation the user selects.
If the simple functionality provided by the default vertical and
horizontal boxes in the two areas doesn't give you enough control for
your application, then you can simply pack another layout widget into
the boxes provided. For example, you could pack a table into the
vertical box.
Pixmaps are data structures that contain pictures. These pictures can
be used in various places, but most commonly as icons on the X
desktop, or as cursors.
A pixmap which only has 2 colors is called a bitmap, and there are a
few additional routines for handling this common special case.
To understand pixmaps, it would help to understand how X window
system works. Under X, applications do not need to be running on the
same computer that is interacting with the user. Instead, the various
applications, called "clients", all communicate with a program which
displays the graphics and handles the keyboard and mouse. This
program which interacts directly with the user is called a "display
server" or "X server." Since the communication might take place over
a network, it's important to keep some information with the X server.
Pixmaps, for example, are stored in the memory of the X server. This
means that once pixmap values are set, they don't need to keep getting
transmitted over the network; instead a command is sent to "display
pixmap number XYZ here." Even if you aren't using X with GTK
currently, using constructs such as Pixmaps will make your programs
work acceptably under X.
To use pixmaps in GTK, we must first build a GdkPixmap structure using
routines from the GDK layer. Pixmaps can either be created from
in-memory data, or from data read from a file. We'll go through each
of the calls to create a pixmap.
This routine is used to create a single-plane pixmap (2 colors) from
data in memory. Each bit of the data represents whether that pixel is
off or on. Width and height are in pixels. The GdkWindow pointer is to
the current window, since a pixmap's resources are meaningful only in
the context of the screen where it is to be displayed.
This is used to create a pixmap of the given depth (number of colors) from
the bitmap data specified. fg and bg are the foreground and
background color to use.
XPM format is a readable pixmap representation for the X Window
System. It is widely used and many different utilities are available
for creating image files in this format. The file specified by
filename must contain an image in that format and it is loaded into
the pixmap structure. The mask specifies which bits of the pixmap are
opaque. All other bits are colored using the color specified by
transparent_color. An example using this follows below.
Small images can be incorporated into a program as data in the XPM
format. A pixmap is created using this data, instead of reading it
from a file. An example of such data is
When we're done using a pixmap and not likely to reuse it again soon,
it is a good idea to release the resource using
gdk_pixmap_unref(). Pixmaps should be considered a precious resource,
because they take up memory in the end-user's X server process. Even
though the X client you write may run on a powerful "server" computer,
the user may be running the X server on a small personal computer.
Once we've created a pixmap, we can display it as a GTK widget. We
must create a GTK pixmap widget to contain the GDK pixmap. This is
done using
gtk_pixmap_set is used to change the pixmap that the widget is currently
managing. Val is the pixmap created using GDK.
The following is an example of using a pixmap in a button.
/* example-start pixmap pixmap.c */
#include <gtk/gtk.h>
/* XPM data of Open-File icon */
static const char * xpm_data[] = {
"16 16 3 1",
" c None",
". c #000000000000",
"X c #FFFFFFFFFFFF",
" ",
" ...... ",
" .XXX.X. ",
" .XXX.XX. ",
" .XXX.XXX. ",
" .XXX..... ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" ......... ",
" ",
" "};
/* when invoked (via signal delete_event), terminates the application.
*/
gint close_application( GtkWidget *widget,
GdkEvent *event,
gpointer data )
{
gtk_main_quit();
return(FALSE);
}
/* is invoked when the button is clicked. It just prints a message.
*/
void button_clicked( GtkWidget *widget,
gpointer data ) {
g_print( "button clicked\n" );
}
int main( int argc,
char *argv[] )
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window, *pixmapwid, *button;
GdkPixmap *pixmap;
GdkBitmap *mask;
GtkStyle *style;
/* create the main window, and attach delete_event signal to terminating
the application */
gtk_init( &argc, &argv );
window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
gtk_signal_connect( GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (close_application), NULL );
gtk_container_set_border_width( GTK_CONTAINER (window), 10 );
gtk_widget_show( window );
/* now for the pixmap from gdk */
style = gtk_widget_get_style( window );
pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
&style->bg[GTK_STATE_NORMAL],
(gchar **)xpm_data );
/* a pixmap widget to contain the pixmap */
pixmapwid = gtk_pixmap_new( pixmap, mask );
gtk_widget_show( pixmapwid );
/* a button to contain the pixmap widget */
button = gtk_button_new();
gtk_container_add( GTK_CONTAINER(button), pixmapwid );
gtk_container_add( GTK_CONTAINER(window), button );
gtk_widget_show( button );
gtk_signal_connect( GTK_OBJECT(button), "clicked",
GTK_SIGNAL_FUNC(button_clicked), NULL );
/* show the window */
gtk_main ();
return 0;
}
/* example-end */
To load a file from an XPM data file called icon0.xpm in the current
directory, we would have created the pixmap thus
/* load a pixmap from a file */
pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
&style->bg[GTK_STATE_NORMAL],
"./icon0.xpm" );
pixmapwid = gtk_pixmap_new( pixmap, mask );
gtk_widget_show( pixmapwid );
gtk_container_add( GTK_CONTAINER(window), pixmapwid );
A disadvantage of using pixmaps is that the displayed object is always
rectangular, regardless of the image. We would like to create desktops
and applications with icons that have more natural shapes. For
example, for a game interface, we would like to have round buttons to
push. The way to do this is using shaped windows.
A shaped window is simply a pixmap where the background pixels are
transparent. This way, when the background image is multi-colored, we
don't overwrite it with a rectangular, non-matching border around our
icon. The following example displays a full wheelbarrow image on the
desktop.
/* example-start wheelbarrow wheelbarrow.c */
#include <gtk/gtk.h>
/* XPM */
static char * WheelbarrowFull_xpm[] = {
"48 48 64 1",
" c None",
". c #DF7DCF3CC71B",
"X c #965875D669A6",
"o c #71C671C671C6",
"O c #A699A289A699",
"+ c #965892489658",
"@ c #8E38410330C2",
"# c #D75C7DF769A6",
"$ c #F7DECF3CC71B",
"% c #96588A288E38",
"& c #A69992489E79",
"* c #8E3886178E38",
"= c #104008200820",
"- c #596510401040",
"; c #C71B30C230C2",
": c #C71B9A699658",
"> c #618561856185",
", c #20811C712081",
"< c #104000000000",
"1 c #861720812081",
"2 c #DF7D4D344103",
"3 c #79E769A671C6",
"4 c #861782078617",
"5 c #41033CF34103",
"6 c #000000000000",
"7 c #49241C711040",
"8 c #492445144924",
"9 c #082008200820",
"0 c #69A618611861",
"q c #B6DA71C65144",
"w c #410330C238E3",
"e c #CF3CBAEAB6DA",
"r c #71C6451430C2",
"t c #EFBEDB6CD75C",
"y c #28A208200820",
"u c #186110401040",
"i c #596528A21861",
"p c #71C661855965",
"a c #A69996589658",
"s c #30C228A230C2",
"d c #BEFBA289AEBA",
"f c #596545145144",
"g c #30C230C230C2",
"h c #8E3882078617",
"j c #208118612081",
"k c #38E30C300820",
"l c #30C2208128A2",
"z c #38E328A238E3",
"x c #514438E34924",
"c c #618555555965",
"v c #30C2208130C2",
"b c #38E328A230C2",
"n c #28A228A228A2",
"m c #41032CB228A2",
"M c #104010401040",
"N c #492438E34103",
"B c #28A2208128A2",
"V c #A699596538E3",
"C c #30C21C711040",
"Z c #30C218611040",
"A c #965865955965",
"S c #618534D32081",
"D c #38E31C711040",
"F c #082000000820",
" ",
" .XoO ",
" +@#$%o& ",
" *=-;#::o+ ",
" >,<12#:34 ",
" 45671#:X3 ",
" +89<02qwo ",
"e* >,67;ro ",
"ty> 459@>+&& ",
"$2u+ ><ipas8* ",
"%$;=* *3:.Xa.dfg> ",
"Oh$;ya *3d.a8j,Xe.d3g8+ ",
" Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
" Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
" Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
" Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
" Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
" Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
" OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
" 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
" :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
" +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
" *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
" p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
" OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
" 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
" @26MvzxNzvlbwfpdettttttttttt.c,n& ",
" *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
" p;<69BvwwsszslllbBlllllllu<5+ ",
" OS0y6FBlvvvzvzss,u=Blllj=54 ",
" c1-699Blvlllllu7k96MMMg4 ",
" *10y8n6FjvllllB<166668 ",
" S-kg+>666<M<996-y6n<8* ",
" p71=4 m69996kD8Z-66698&& ",
" &i0ycm6n4 ogk17,0<6666g ",
" N-k-<> >=01-kuu666> ",
" ,6ky& &46-10ul,66, ",
" Ou0<> o66y<ulw<66& ",
" *kk5 >66By7=xu664 ",
" <<M4 466lj<Mxu66o ",
" *>> +66uv,zN666* ",
" 566,xxj669 ",
" 4666FF666> ",
" >966666M ",
" oM6668+ ",
" *4 ",
" ",
" "};
/* When invoked (via signal delete_event), terminates the application */
gint close_application( GtkWidget *widget,
GdkEvent *event,
gpointer data )
{
gtk_main_quit();
return(FALSE);
}
int main (int argc,
char *argv[] )
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window, *pixmap, *fixed;
GdkPixmap *gdk_pixmap;
GdkBitmap *mask;
GtkStyle *style;
GdkGC *gc;
/* Create the main window, and attach delete_event signal to terminate
* the application. Note that the main window will not have a titlebar
* since we're making it a popup. */
gtk_init (&argc, &argv);
window = gtk_window_new( GTK_WINDOW_POPUP );
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (close_application), NULL);
gtk_widget_show (window);
/* Now for the pixmap and the pixmap widget */
style = gtk_widget_get_default_style();
gc = style->black_gc;
gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
&style->bg[GTK_STATE_NORMAL],
WheelbarrowFull_xpm );
pixmap = gtk_pixmap_new( gdk_pixmap, mask );
gtk_widget_show( pixmap );
/* To display the pixmap, we use a fixed widget to place the pixmap */
fixed = gtk_fixed_new();
gtk_widget_set_usize( fixed, 200, 200 );
gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
gtk_container_add( GTK_CONTAINER(window), fixed );
gtk_widget_show( fixed );
/* This masks out everything except for the image itself */
gtk_widget_shape_combine_mask( window, mask, 0, 0 );
/* show the window */
gtk_widget_set_uposition( window, 20, 400 );
gtk_widget_show( window );
gtk_main ();
return(0);
}
/* example-end */
To make the wheelbarrow image sensitive, we could attach the button
press event signal to make it do something. The following few lines
would make the picture sensitive to a mouse button being pressed which
makes the application terminate.
Ruler widgets are used to indicate the location of the mouse pointer
in a given window. A window can have a vertical ruler spanning across
the width and a horizontal ruler spanning down the height. A small
triangular indicator on the ruler shows the exact location of the
pointer relative to the ruler.
A ruler must first be created. Horizontal and vertical rulers are
created using
Once a ruler is created, we can define the unit of measurement. Units
of measure for rulers can beGTK_PIXELS, GTK_INCHES or
GTK_CENTIMETERS. This is set using
Other important characteristics of a ruler are how to mark the units
of scale and where the position indicator is initially placed. These
are set for a ruler using
The lower and upper arguments define the extent of the ruler, and
max_size is the largest possible number that will be displayed.
Position defines the initial position of the pointer indicator within
the ruler.
A vertical ruler can span an 800 pixel wide window thus
The markings displayed on the ruler will be from 0 to 800, with a
number for every 100 pixels. If instead we wanted the ruler to range
from 7 to 16, we would code
The indicator on the ruler is a small triangular mark that indicates
the position of the pointer relative to the ruler. If the ruler is
used to follow the mouse pointer, the motion_notify_event signal
should be connected to the motion_notify_event method of the ruler.
To follow all mouse movements within a window area, we would use
The following example creates a drawing area with a horizontal ruler
above it and a vertical ruler to the left of it. The size of the
drawing area is 600 pixels wide by 400 pixels high. The horizontal
ruler spans from 7 to 13 with a mark every 100 pixels, while the
vertical ruler spans from 0 to 400 with a mark every 100 pixels.
Placement of the drawing area and the rulers is done using a table.
/* example-start rulers rulers.c */
#include <gtk/gtk.h>
#define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
#define XSIZE 600
#define YSIZE 400
/* This routine gets control when the close button is clicked */
gint close_application( GtkWidget *widget,
GdkEvent *event,
gpointer data )
{
gtk_main_quit();
return(FALSE);
}
/* The main routine */
int main( int argc,
char *argv[] ) {
GtkWidget *window, *table, *area, *hrule, *vrule;
/* Initialize GTK and create the main window */
gtk_init( &argc, &argv );
window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC( close_application ), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Create a table for placing the ruler and the drawing area */
table = gtk_table_new( 3, 2, FALSE );
gtk_container_add( GTK_CONTAINER(window), table );
area = gtk_drawing_area_new();
gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK );
/* The horizontal ruler goes on top. As the mouse moves across the
* drawing area, a motion_notify_event is passed to the
* appropriate event handler for the ruler. */
hrule = gtk_hruler_new();
gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
(GtkSignalFunc)EVENT_METHOD(hrule,
motion_notify_event),
GTK_OBJECT(hrule) );
/* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
/* The vertical ruler goes on the left. As the mouse moves across
* the drawing area, a motion_notify_event is passed to the
* appropriate event handler for the ruler. */
vrule = gtk_vruler_new();
gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
(GtkSignalFunc)
GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->
motion_notify_event,
GTK_OBJECT(vrule) );
gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
/* Now show everything */
gtk_widget_show( area );
gtk_widget_show( hrule );
gtk_widget_show( vrule );
gtk_widget_show( table );
gtk_widget_show( window );
gtk_main();
return(0);
}
/* example-end */
Statusbars are simple widgets used to display a text message. They
keep a stack of the messages pushed onto them, so that popping the
current message will re-display the previous text message.
In order to allow different parts of an application to use the same
statusbar to display messages, the statusbar widget issues Context
Identifiers which are used to identify different "users". The message
on top of the stack is the one displayed, no matter what context it is
in. Messages are stacked in last-in-first-out order, not context
identifier order.
A statusbar is created with a call to:
GtkWidget *gtk_statusbar_new( void );
A new Context Identifier is requested using a call to the following
function with a short textual description of the context:
The first, gtk_statusbar_push, is used to add a new message to the
statusbar. It returns a Message Identifier, which can be passed later
to the function gtk_statusbar_remove to remove the message with the
given Message and Context Identifiers from the statusbar's stack.
The function gtk_statusbar_pop removes the message highest in the
stack with the given Context Identifier.
The following example creates a statusbar and two buttons, one for
pushing items onto the statusbar, and one for popping the last item
back off.
The Entry widget allows text to be typed and displayed in a single line
text box. The text may be set with function calls that allow new text
to replace, prepend or append the current contents of the Entry widget.
There are two functions for creating Entry widgets:
GtkWidget *gtk_entry_new( void );
GtkWidget *gtk_entry_new_with_max_length( guint16 max );
The first just creates a new Entry widget, whilst the second creates a
new Entry and sets a limit on the length of the text within the Entry.
There are several functions for altering the text which is currently
within the Entry widget.
The function gtk_entry_set_text sets the contents of the Entry widget,
replacing the current contents. The functions gtk_entry_append_text
and gtk_entry_prepend_text allow the current contents to be appended
and prepended to.
The next function allows the current insertion point to be set.
void gtk_entry_set_position( GtkEntry *entry,
gint position );
The contents of the Entry can be retrieved by using a call to the
following function. This is useful in the callback functions described below.
gchar *gtk_entry_get_text( GtkEntry *entry );
The value returned by this function is used internally, and must not
be freed using either free() or g_free()
If we don't want the contents of the Entry to be changed by someone typing
into it, we can change its editable state.
The function above allows us to toggle the editable state of the
Entry widget by passing in a TRUE or FALSE value for the editable
argument.
If we are using the Entry where we don't want the text entered to be
visible, for example when a password is being entered, we can use the
following function, which also takes a boolean flag.
A region of the text may be set as selected by using the following
function. This would most often be used after setting some default
text in an Entry, making it easy for the user to remove it.
void gtk_entry_select_region( GtkEntry *entry,
gint start,
gint end );
If we want to catch when the user has entered text, we can connect to
the activate or changed signal. Activate is raised when the
user hits the enter key within the Entry widget. Changed is raised
when the text changes at all, e.g., for every character entered or
removed.
The following code is an example of using an Entry widget.
The Spin Button widget is generally used to allow the user to select a
value from a range of numeric values. It consists of a text
entry box with up and down arrow buttons attached to the
side. Selecting one of the buttons causes the value to "spin" up and
down the range of possible values. The entry box may also be edited
directly to enter a specific value.
The Spin Button allows the value to have zero or a number of decimal
places and to be incremented/decremented in configurable steps. The
action of holding down one of the buttons optionally results in an
acceleration of change in the value according to how long it is
depressed.
The Spin Button uses an
Adjustment
object to hold information about the range of values that the spin
button can take. This makes for a powerful Spin Button widget.
Recall that an adjustment widget is created with the following
function, which illustrates the information that it holds:
These attributes of an Adjustment are used by the Spin Button in the
following way:
value: initial value for the Spin Button
lower: lower range value
upper: upper range value
step_increment: value to increment/decrement when pressing
mouse button 1 on a button
page_increment: value to increment/decrement when pressing
mouse button 2 on a button
page_size: unused
Additionally, mouse button 3 can be used to jump directly to the
upper or lower values when used to select one of the
buttons. Lets look at how to create a Spin Button:
The climb_rate argument take a value between 0.0 and 1.0 and
indicates the amount of acceleration that the Spin Button has. The
digits argument specifies the number of decimal places to which
the value will be displayed.
A Spin Button can be reconfigured after creation using the following
function:
This function packs in quite a bit of functionality, which I will
attempt to clearly explain. Many of these settings use values from the
Adjustment object that is associated with a Spin Button.
GTK_SPIN_STEP_FORWARD and GTK_SPIN_STEP_BACKWARD change the
value of the Spin Button by the amount specified by increment,
unless increment is equal to 0, in which case the value is
changed by the value of step_increment in theAdjustment.
GTK_SPIN_PAGE_FORWARD and GTK_SPIN_PAGE_BACKWARD simply
alter the value of the Spin Button by increment.
GTK_SPIN_HOME sets the value of the Spin Button to the bottom of
the Adjustments range.
GTK_SPIN_END sets the value of the Spin Button to the top of the
Adjustments range.
GTK_SPIN_USER_DEFINED simply alters the value of the Spin Button
by the specified amount.
We move away from functions for setting and retreving the range attributes
of the Spin Button now, and move onto functions that effect the
appearance and behaviour of the Spin Button widget itself.
The first of these functions is used to constrain the text box of the
Spin Button such that it may only contain a numeric value. This
prevents a user from typing anything other than numeric values into
the text box of a Spin Button:
You can set a Spin Button to round the value to the nearest
step_increment, which is set within the Adjustment object used
with the Spin Button. This is accomplished with the following
function:
The possible values of policy are either GTK_UPDATE_ALWAYS or
GTK_UPDATE_IF_VALID.
These policies affect the behavior of a Spin Button when parsing
inserted text and syncing its value with the values of the
Adjustment.
In the case of GTK_UPDATE_IF_VALID the Spin Button only value
gets changed if the text input is a numeric value that is within the
range specified by the Adjustment. Otherwise the text is reset to the
current value.
In case of GTK_UPDATE_ALWAYS we ignore errors while converting
text into a numeric value.
The appearance of the buttons used in a Spin Button can be changed
using the following function:
The combo box is another fairly simple widget that is really just a
collection of other widgets. From the user's point of view, the widget
consists of a text entry box and a pull down menu from which the user
can select one of a set of predefined entries. Alternatively, the user
can type a different option directly into the text box.
The following extract from the structure that defines a Combo Box
identifies several of the components:
Before you can do this, you have to assemble a GList of the strings
that you want. GList is a linked list implementation that is part of
GLib, a library supporing GTK. For the
moment, the quick and dirty explanation is that you need to set up a
GList pointer, set it equal to NULL, then append strings to it with
GList *g_list_append( GList *glist,
gpointer data );
It is important that you set the initial GList pointer to NULL. The
value returned from the g_list_append function must be used as the new
pointer to the GList.
Here's a typical code segment for creating a set of options:
The combo widget makes a copy of the strings passed to it in the glist
structure. As a result, you need to make sure you free the memory used
by the list if that is appropriate for your application.
At this point you have a working combo box that has been set up.
There are a few aspects of its behavior that you can change. These
are accomplished with the functions:
void gtk_combo_set_use_arrows( GtkCombo *combo,
gint val );
void gtk_combo_set_use_arrows_always( GtkCombo *combo,
gint val );
void gtk_combo_set_case_sensitive( GtkCombo *combo,
gint val );
gtk_combo_set_use_arrows() lets the user change the value in the
entry using the up/down arrow keys. This doesn't bring up the list, but
rather replaces the current text in the entry with the next list entry
(up or down, as your key choice indicates). It does this by searching
in the list for the item corresponding to the current value in the
entry and selecting the previous/next item accordingly. Usually in an
entry the arrow keys are used to change focus (you can do that anyway
using TAB). Note that when the current item is the last of the list
and you press arrow-down it changes the focus (the same applies with
the first item and arrow-up).
If the current value in the entry is not in the list, then the
function of gtk_combo_set_use_arrows() is disabled.
gtk_combo_set_use_arrows_always() similarly allows the use the
the up/down arrow keys to cycle through the choices in the dropdown
list, except that it wraps around the values in the list, completely
disabling the use of the up and down arrow keys for changing focus.
gtk_combo_set_case_sensitive() toggles whether or not GTK
searches for entries in a case sensitive manner. This is used when the
Combo widget is asked to find a value from the list using the current
entry in the text box. This completion can be performed in either a
case sensitive or insensitive manner, depending upon the use of this
function. The Combo widget can also simply complete the current entry
if the user presses the key combination MOD-1 and "Tab". MOD-1 is
often mapped to the "Alt" key, by the xmodmap utility. Note,
however that some window managers also use this key combination, which
will override its use within GTK.
Now that we have a combo box, tailored to look and act how we want it,
all that remains is being able to get data from the combo box. This is
relatively straightforward. The majority of the time, all you are
going to care about getting data from is the entry. The entry is
accessed simply by GTK_ENTRY(GTK_COMBO(combo)->entry). The
two principal things that you are going to want to do with it are
attach to the activate signal, which indicates that the user has
pressed the Return or Enter key, and read the text. The first is
accomplished using something like:
The Calendar widget is an effective way to display and retrieve
monthly date related information. It is a very simple widget to create
and work with.
Creating a GtkCalendar widget is a simple as:
GtkWidget *gtk_calendar_new();
There might be times where you need to change a lot of information
within this widget and the following functions allow you to make
multiple change to a Calendar widget without the user seeing multiple
on-screen updates.
The flags argument can be formed by combining either of the
following five options using the logical bitwise OR (|) operation:
GTK_CALENDAR_SHOW_HEADING - this option specifies that
the month and year should be shown when drawing the calendar.
GTK_CALENDAR_SHOW_DAY_NAMES - this option specifies that the
three letter descriptions should be displayed for each day (eg
MON,TUE...).
GTK_CALENDAR_NO_MONTH_CHANGE - this option states that the user
should not and can not change the currently displayed month. This can
be good if you only need to display a particular month such as if you
are displaying 12 calendar widgets for every month in a particular
year.
GTK_CALENDAR_SHOW_WEEK_NUMBERS - this option specifies that the
number for each week should be displayed down the left side of the
calendar. (eg. Jan 1 = Week 1,Dec 31 = Week 52).
GTK_CALENDAR_WEEK_START_MONDAY - this option states that the
calander week will start on Monday instead of Sunday which is the
default. This only affects the order in which days are displayed from
left to right.
The following functions are used to set the the currently displayed
date:
gint gtk_calendar_select_month( GtkCalendar *calendar,
guint month,
guint year );
void gtk_calendar_select_day( GtkCalendar *calendar,
guint day );
The return value from gtk_calendar_select_month() is a boolean
value indicating whether the selection was successful.
With gtk_calendar_select_day() the specified day number is
selected within the current month, if that is possible. A
day value of 0 will deselect any current selection.
In addition to having a day selected, any number of days in the month
may be "marked". A marked day is highlighted within the calendar
display. The following functions are provided to manipulate marked
days:
The currently marked days are stored within an array within the
GtkCalendar structure. This array is 31 elements long so to test
whether a particular day is currently marked, you need to access the
corresponding element of the array (don't forget in C that array
elements are numbered 0 to n-1). For example:
GtkCalendar *calendar;
calendar = gtk_calendar_new();
...
/* Is day 7 marked? */
if (calendar->marked_date[7-1])
/* day is marked */
Note that marks are persistent across month and year changes.
The final Calendar widget function is used to retrieve the currently
selected date, month and/or year.
This function requires you to pass the addresses of guint
variables, into which the result will be placed. Passing NULL as
a value will result in the corresponding value not being returned.
The Calendar widget can generate a number of signals indicating date
selection and change. The names of these signals are self explanatory,
and are:
month_changed
day_selected
day_selected_double_click
prev_month
next_month
prev_year
next_year
That just leaves us with the need to put all of this together into
example code.
The color selection widget is, not surprisingly, a widget for
interactive selection of colors. This composite widget lets the user
select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
Saturation, Value) triples. This is done either by adjusting single
values with sliders or entries, or by picking the desired color from a
hue-saturation wheel/value bar. Optionally, the opacity of the color
can also be set.
The color selection widget currently emits only one signal,
"color_changed", which is emitted whenever the current color in the
widget changes, either when the user changes it or if it's set
explicitly through gtk_color_selection_set_color().
Lets have a look at what the color selection widget has to offer
us. The widget comes in two flavours: gtk_color_selection and
gtk_color_selection_dialog.
GtkWidget *gtk_color_selection_new( void );
You'll probably not be using this constructor directly. It creates an
orphan ColorSelection widget which you'll have to parent
yourself. The ColorSelection widget inherits from the VBox
widget.
This is the most common color selection constructor. It creates a
ColorSelectionDialog. It consists of a Frame containing a
ColorSelection widget, an HSeparator and an HBox with three buttons,
"Ok", "Cancel" and "Help". You can reach these buttons by accessing
the "ok_button", "cancel_button" and "help_button" widgets in the
ColorSelectionDialog structure,
(i.e., GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button)).
This function sets the update policy. The default policy is
GTK_UPDATE_CONTINUOUS which means that the current color is
updated continuously when the user drags the sliders or presses the
mouse and drags in the hue-saturation wheel or value bar. If you
experience performance problems, you may want to set the policy to
GTK_UPDATE_DISCONTINUOUS or GTK_UPDATE_DELAYED.
The color selection widget supports adjusting the opacity of a color
(also known as the alpha channel). This is disabled by
default. Calling this function with use_opacity set to TRUE enables
opacity. Likewise, use_opacity set to FALSE will disable opacity.
You can set the current color explicitly by calling this function with
a pointer to an array of colors (gdouble). The length of the array
depends on whether opacity is enabled or not. Position 0 contains the
red component, 1 is green, 2 is blue and opacity is at position 3
(only if opacity is enabled, see
gtk_color_selection_set_opacity()). All values are between 0.0 and
1.0.
When you need to query the current color, typically when you've
received a "color_changed" signal, you use this function. Color is a
pointer to the array of colors to fill in. See the
gtk_color_selection_set_color() function for the description of this
array.
Here's a simple example demonstrating the use of the
ColorSelectionDialog. The program displays a window containing a
drawing area. Clicking on it opens a color selection dialog, and
changing the color in the color selection dialog changes the
background color.
/* example-start colorsel colorsel.c */
#include <glib.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
GtkWidget *colorseldlg = NULL;
GtkWidget *drawingarea = NULL;
/* Color changed handler */
void color_changed_cb( GtkWidget *widget,
GtkColorSelection *colorsel )
{
gdouble color[3];
GdkColor gdk_color;
GdkColormap *colormap;
/* Get drawingarea colormap */
colormap = gdk_window_get_colormap (drawingarea->window);
/* Get current color */
gtk_color_selection_get_color (colorsel,color);
/* Fit to a unsigned 16 bit integer (0..65535) and
* insert into the GdkColor structure */
gdk_color.red = (guint16)(color[0]*65535.0);
gdk_color.green = (guint16)(color[1]*65535.0);
gdk_color.blue = (guint16)(color[2]*65535.0);
/* Allocate color */
gdk_color_alloc (colormap, &gdk_color);
/* Set window background color */
gdk_window_set_background (drawingarea->window, &gdk_color);
/* Clear window */
gdk_window_clear (drawingarea->window);
}
/* Drawingarea event handler */
gint area_event( GtkWidget *widget,
GdkEvent *event,
gpointer client_data )
{
gint handled = FALSE;
GtkWidget *colorsel;
/* Check if we've received a button pressed event */
if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
{
/* Yes, we have an event and there's no colorseldlg yet! */
handled = TRUE;
/* Create color selection dialog */
colorseldlg = gtk_color_selection_dialog_new("Select background color");
/* Get the ColorSelection widget */
colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
/* Connect to the "color_changed" signal, set the client-data
* to the colorsel widget */
gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
(GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
/* Show the dialog */
gtk_widget_show(colorseldlg);
}
return handled;
}
/* Close down and exit handler */
gint destroy_window( GtkWidget *widget,
GdkEvent *event,
gpointer client_data )
{
gtk_main_quit ();
return(TRUE);
}
/* Main */
gint main( gint argc,
gchar *argv[] )
{
GtkWidget *window;
/* Initialize the toolkit, remove gtk-related commandline stuff */
gtk_init (&argc,&argv);
/* Create toplevel window, set title and policies */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW(window), "Color selection test");
gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, TRUE);
/* Attach to the "delete" and "destroy" events so we can exit */
gtk_signal_connect (GTK_OBJECT(window), "delete_event",
(GtkSignalFunc)destroy_window, (gpointer)window);
/* Create drawingarea, set size and catch button events */
drawingarea = gtk_drawing_area_new ();
gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
gtk_signal_connect (GTK_OBJECT(drawingarea), "event",
(GtkSignalFunc)area_event, (gpointer)drawingarea);
/* Add drawingarea to window, then show them both */
gtk_container_add (GTK_CONTAINER(window), drawingarea);
gtk_widget_show (drawingarea);
gtk_widget_show (window);
/* Enter the gtk main loop (this never returns) */
gtk_main ();
/* Satisfy grumpy compilers */
return(0);
}
/* example-end */
The file selection widget is a quick and simple way to display a File
dialog box. It comes complete with Ok, Cancel, and Help buttons, a
great way to cut down on programming time.
Most likely you will want to use the ok_button, cancel_button, and
help_button pointers in signaling their use.
Included here is an example stolen from testgtk.c, modified to run on
its own. As you will see, there is nothing much to creating a file
selection widget. While in this example the Help button appears on the
screen, it does nothing as there is not a signal attached to it.
/* example-start filesel filesel.c */
#include <gtk/gtk.h>
/* Get the selected filename and print it to the console */
void file_ok_sel( GtkWidget *w,
GtkFileSelection *fs )
{
g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
}
void destroy( GtkWidget *widget,
gpointer data )
{
gtk_main_quit ();
}
int main( int argc,
char *argv[] )
{
GtkWidget *filew;
gtk_init (&argc, &argv);
/* Create a new file selection widget */
filew = gtk_file_selection_new ("File selection");
gtk_signal_connect (GTK_OBJECT (filew), "destroy",
(GtkSignalFunc) destroy, &filew);
/* Connect the ok_button to file_ok_sel function */
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
"clicked", (GtkSignalFunc) file_ok_sel, filew );
/* Connect the cancel_button to destroy the widget */
gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION
(filew)->cancel_button),
"clicked", (GtkSignalFunc) gtk_widget_destroy,
GTK_OBJECT (filew));
/* Lets set the filename, as if this were a save dialog, and we are giving
a default filename */
gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
"penguin.png");
gtk_widget_show(filew);
gtk_main ();
return 0;
}
/* example-end */