Code:
#include <stdio.h> /* for error-messages in stderr */
#include <stdlib.h> /* strtol() */
#include <errno.h>
#include <gtk/gtk.h>
#define TXTF_RESULT "Result: %ld"
/* our GUI (bare) abstraction */
typedef struct {
GtkWidget *window; /* main window */
GtkWidget *op1, *op2; /* text-entry widgets for the operands */
GtkWidget *ok; /* button widget */
GtkWidget *result; /* label-widget for the result */
} Gui;
/* -------------------------------------------------
* Convert the text of the specified GtkEntry widget (te)
* to a long int. Return FALSE on error, TRUE otherwise.
* On success, the long int gets back to the caller via
* the (ref) pointer.
*
* NOTE: On failure, the GtkEntry widget gets input focus,
* with all its contents selected.
* -------------------------------------------------
*/
gboolean te_get_long_int( GtkEntry *te, long int *ref )
{
long int temp = 0L;
char *txt = NULL; /* for getting widget's text */
char *tailptr = NULL; /* for strtol() */
/* sanity chekcs */
if ( NULL == te || NULL == ref ) {
fprintf( stderr, "%s: NULL pointer argument ", __func__ );
return FALSE;
}
/* get widget's text */
txt = g_strdup( gtk_entry_get_text(te) );
/* validate it as long int */
errno = 0;
temp = strtol( txt, &tailptr, 10 );
if ( ERANGE == errno || '\0' != *tailptr ) {
gtk_widget_grab_focus( GTK_WIDGET(te) );
gtk_editable_select_region( GTK_EDITABLE(te), 0, -1 );
g_free( txt );
return FALSE;
}
g_free( txt );
/* update ref & exit */
*ref = temp;
return TRUE;
}
/* -------------------------------------------------
* Callback function connected to the "clicked"
* signal for the OK button.
* -------------------------------------------------
*/
void on_clicked_button_ok(
GtkWidget *button,
Gui *gui
)
{
long int op1, op2;
/* avoid compiler warnings for unused arg*/
(void)button;
/* sanity check */
if ( NULL == gui ) {
fprintf( stderr, "%s: NULL pointer argument!\n", __func__ );
return;
}
/* get & validate operands */
if ( !te_get_long_int( GTK_ENTRY(gui->op1), &op1 )
|| !te_get_long_int( GTK_ENTRY(gui->op2), &op2 )
){
goto ret_failure;
}
/* Calc & display the result */
char *txt = g_strdup_printf( TXTF_RESULT, op1 + op2 );
gtk_label_set_text( GTK_LABEL( gui->result ), txt );
g_free( txt );
return;
ret_failure:
gtk_label_set_text(
GTK_LABEL( gui->result ),
"Invalid operand detected"
);
}
/* -------------------------------------------------
*
* -------------------------------------------------
*/
int main( int argc, char *argv[] )
{
GtkBuilder *builder = NULL;
GError *error = NULL;
Gui *gui = g_slice_alloc0( sizeof(*gui) );
if ( NULL == gui ) {
fputs( "gui allocation failed, bye...\n", stderr );
return 1;
}
gtk_init( &argc, &argv );
/*
* Read glade file into builder
*/
builder = gtk_builder_new();
if( !gtk_builder_add_from_file( builder, "zub.glade", &error ) ) {
g_warning( "%s", error->message );
g_free( error );
g_object_unref( G_OBJECT(builder) );
return 1;
}
/*
* Populate our GUI from builder (unref builder when done)
*/
gui->window = GTK_WIDGET(
gtk_builder_get_object( builder, "windMain" )
);
gui->op1 = GTK_WIDGET(
gtk_builder_get_object( builder, "teOp1" )
);
gui->op2 = GTK_WIDGET(
gtk_builder_get_object( builder, "teOp2" )
);
gui->ok = GTK_WIDGET(
gtk_builder_get_object( builder, "buttonOk" )
);
gui->result = GTK_WIDGET(
gtk_builder_get_object( builder, "labelResult" )
);
g_object_unref( G_OBJECT( builder ) );
/*
* Connect callback functions to signals
*/
g_signal_connect(
gui->window,
"destroy",
G_CALLBACK( gtk_main_quit ), /* provided by GTK+2 */
NULL
);
g_signal_connect(
gui->ok,
"clicked",
G_CALLBACK( on_clicked_button_ok ),
gui
);
/*
* Prepare some visuals before drawing the main window
*/
gtk_window_set_title(
GTK_WINDOW(gui->window),
"GTK+2 sample for zub"
);
gtk_window_set_position(
GTK_WINDOW( gui->window ),
GTK_WIN_POS_CENTER
);
gchar *txt = g_strdup_printf( TXTF_RESULT, 0L );
gtk_label_set_text( GTK_LABEL( gui->result ), txt );
g_free( txt );
/*
* All set... go
*/
gtk_widget_show( gui->window );
gtk_main();
/*
* Cleanup & exit
*/
g_slice_free1( sizeof(*gui), gui );
return 0;
}