Sunday, November 6, 2011

Event Driven programming in C

Having understood the mechanism of signal processing let us now see how signaling is used by Linux – based libraries to create event driven GUI programs. As you know, in a GUI program events occur typically when we click on the window, type a character, close the window, repaint the window, etc. We have chosen the GTK library version 2.0 to create the GUI applications. Here, GTK stands for Gimp’s Tool Kit. Refer Appendix H for installation of this toolkit. Given below is the first program that uses this toolkit to create a window on the screen.

/* mywindow.c */
# include <gtk/gtk.h>
int main ( int argc, char *argv[ ] )
{
GtkWidget *p ;
gtk_init ( &argc, &argv ) ;
p = gtk_window_new ( GTK_WINDOW_TOPLEVEL ) ;
gtk_window_set_title ( p , "Sample Window" ) ;
g_signal_connect ( p, "destroy", gtk_main_quit, NULL ) ;
gtk_widget_set_size_request ( p, 300, 300 ) ;
gtk_widget_show ( p ) ;
gtk_main( ) ;
return 0 ;
}

We need to compile this program as follows:

gcc mywindow.c `pkg-config gtk+-2.0 - -cflags - -libs`

Here we are compiling the program ‘mywindow.c’ and then linking it with the necessary libraries from GTK toolkit. Note the quotes that we have used in the command.

Here is the output of the program…




The GTK library provides a large number of functions that makes it very easy for us to create GUI programs
. Every window under GTK is known as a widget. To create a simple window we have to carry out the 
following steps:

(a) Initialize the GTK library with a call to gtk_init( ) function. This function requires the addresses of the command line arguments received in main( ).

(b) Next, call the gtk_window_new( ) function to create a top level window. The only parameter this function takes is the type of windows to be created. A top level window can be created by specifying the GTK_WINDOW_TOPLEVEL value. This call creates a window in memory and returns a pointer to the widget object. The widget object is a structure (GtkWidget) variable that stores lots of information including the attributes of window it represents. We have collected this pointer in a GtkWidget structure pointer called p.

(c) Set the title for the window by making a call to gtk_window_set_title( ) function. The first parameter of this function is a pointer to the GtkWidget structure representing the window for which the title has to be set. 
The second parameter is a string describing the text to be displayed in the title of the window.

(d) Register a signal handler for the destroy signal. The destroy signal is received whenever we try to close the window. The handler for the destroy signal should perform clean up activities and then shutdown the application. GTK provides a ready-made function called gtk_main_quit( ) that does this job. We only need to associate this function with the destroy signal. This can be achieved using the g_signal_connect( ) function. 

(e) The first parameter of this function is the pointer to the widget for which destroy signal handler has to be registered. The second parameter is a string that specifies the name of the signal. The third parameter is the address of the signal handler routine. We have not used the fourth parameter.
Resize the window to the desired size using the gtk_widget_set_size_request( ) function. The second and the

third parameters specify the height and the width of the window respectively. (f)
(g)
Display the window on the screen using the function gtk_widget_show( ).
Wait in a loop to receive events for the window. This can be accomplished using the gtk_main( ) function.
How about another program that draws a few shapes in the window? Here is the program…

/* myshapes.c */
# include <gtk/gtk.h>
int expose_event ( GtkWidget *widget, GdkEventExpose *event )
{
GdkGC* p ;
GdkPoint arr [ 5] = { 250, 150, 250, 300, 300, 350, 400, 300, 320, 190 } ;
p = gdk_gc_new ( widget -> window ) ;
gdk_draw_line ( widget -> window, p, 10, 10, 200, 10 ) ;
gdk_draw_rectangle ( widget -> window, p, TRUE, 10, 20, 200, 100 ) ;
gdk_draw_arc ( widget -> window, p, TRUE, 200, 10, 200, 200,
2880, -2880*2 ) ;
gdk_draw_polygon ( widget -> window, p, TRUE , arr, 5 ) ;
gdk_gc_unref ( p ) ;
return TRUE ;
}
int main( int argc, char *argv[ ] )
{
GtkWidget *p ;
gtk_init ( &argc, &argv ) 
p = gtk_window_new ( GTK_WINDOW_TOPLEVEL ) ;
gtk_window_set_title ( p, "Sample Window" ) ;
g_signal_connect ( p, "destroy", gtk_main_quit, NULL ) ;
g_signal_connect ( p , "expose_event", expose_event, NULL ) ;
gtk_widget_set_size_request ( p, 500, 500 ) ;
gtk_widget_show ( p ) ;
gtk_main( ) ;
return 0 ;
}
Given below is the output of the program.;







 because a expose_event signal would be sent to our application which would immediately redraw the shapes in our window.
The way in Windows we have a device context, under Linux we have a graphics context. In order to draw in the window we need to obtain a graphics context for the window using the gdk_gc_new( ) function. This function returns a pointer to the graphics context structure. This pointer must be passed to the drawing functions like gdk_draw_line( ), gdk_draw_rectangle(), gdk_draw_arc( ), gdk_draw_polygon( ), etc. Once we are through with drawing we should release the graphics context using the gdk_gc_unref( ) function.


This program is similar to the first one. The only difference is that in addition to the destroy signal we have registered a signal handler for the expose_event using the g_signal_connect( ) function. This signal is sent to our process whenever the window needs to be redrawn. By writing the code for drawing shapes in the handler for this signal we are assured that the drawing would never vanish if the windows is dragged outside the screen and then brought back in, or some other window uncovers a portion of our window which was previously overlapped, and so on. This is

No comments:

Post a Comment