Hi,
I have coded in C language with GTK+ since a few months.
In the first times, I have used the usual pointer casting provided with
the library: GTK_CONTAINER (my_window) for exemple.
In my opinion, there are two disadvantages with this system:
first, the widget pointers are not "object style" written,
second, if you cast a pointer with a type which is not of one of its
parents widget, you get no error at compiling time and you get an
execution error only if you compile with widget type control.
What I suggest is to define the widget descriptors as unions of pointers
representing the hierarchy of the widgets.
The advantages are that the descriptors used in the code always carry
their types, and if you use an invalid parent type for a widget, you get
an error at compile time. And it if full interoperable with the usual
casting method.
But, there is one disadvantage. This coding style is only available in C
and C++ languages.
To demonstrate what I an talking about, I have translated in GTK+ 3 a
little example from the Andrew Krause book. The files are enclosed in
the present mail.
In the end, if you agree with this coding style, the union descriptors
could be enclosed in the widget header files of the library.
Please, do not hesitate to comment this mail.
Regards
Jean-Marie
union_test.c
#include <stdlib.h> /* Définition of EXIT_SUCCESS */
#include <gtk/gtk.h>
/* Includes for the union types déclaration */
/* These declarations of union types should be included in the regular header
files for each widget */
#include "gtkspinbutton.h"
#include "gtkscale.h"
#include "gtkcheckbutton.h"
#include "gtkwindow.h"
#include "gtkgrid.h"
#include "gtkadjustment.h"
/* structure gathering the three widgets (allow to pass a global pointer to the
callback value_changed function) */
typedef struct
{
GTKSPINBUTTON spin;
GTKSCALE scale;
GTKCHECKBUTTON check;
} Widgets;
/* Prototype of the callback function */
static void cb_value_changed (GtkWidget *, Widgets *);
/* Main function */
int main (int argc, char *argv[])
{
/* Variables declaration */
GTKWINDOW window;
GTKGRID grid;
GTKADJUSTMENT adj1, adj2;
Widgets *w = (Widgets *) g_malloc (sizeof (Widgets));
/* Initialisation of GTK+ */
gtk_init (&argc, &argv);
/* Widgets creation */
window.gtkwidget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
grid.gtkwidget = gtk_grid_new ();
adj1.gtkadjustment = gtk_adjustment_new (0.5, 0.0, 1.02, 0.01, 0.02, 0.02);
adj2.gtkadjustment = gtk_adjustment_new (0.5, 0.0, 1.02, 0.01, 0.02, 0.02);
w->spin.gtkwidget = gtk_spin_button_new (adj1.gtkadjustment, 0.01, 2);
w->scale.gtkwidget = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL,
adj2.gtkadjustment);
w->check.gtkwidget = gtk_check_button_new_with_label ("Synchronize Spin and
Scale");
/* Widgets setting */
gtk_window_set_title (window.gtkwindow, "Exercise 4-2");
gtk_container_set_border_width (window.gtkcontainer, 10);
gtk_grid_set_row_spacing (grid.gtkgrid, 5);
gtk_grid_set_column_homogeneous (grid.gtkgrid, FALSE);
gtk_grid_set_row_homogeneous (grid.gtkgrid, FALSE);
gtk_toggle_button_set_active (w->check.gtktogglebutton, TRUE);
gtk_scale_set_digits (w->scale.gtkscale, 2);
/* Widgets attachment */
gtk_grid_attach (grid.gtkgrid, w->spin.gtkwidget, 0 , 0, 1, 1);
gtk_grid_attach_next_to (grid.gtkgrid, w->scale.gtkwidget, w->spin.gtkwidget,
GTK_POS_BOTTOM, 1, 1);
gtk_grid_attach_next_to (grid.gtkgrid, w->check.gtkwidget,
w->scale.gtkwidget, GTK_POS_BOTTOM, 1, 1);
gtk_container_add (window.gtkcontainer, grid.gtkwidget);
/* Signals attachment to the widgets */
g_signal_connect (window.gobject, "destroy", G_CALLBACK (gtk_main_quit),
NULL);
g_signal_connect (w->spin.gobject, "value_changed", G_CALLBACK (cb_value_changed), (gpointer) w);
g_signal_connect (w->scale.gobject, "value_changed", G_CALLBACK
(cb_value_changed), (gpointer) w);
/* Showing the widgets */
gtk_widget_show_all (window.gtkwidget);
/* And let's go ! */
gtk_main ();
/* Freeing memory */
g_free (w);
return EXIT_SUCCESS;
}
static void cb_value_changed (GtkWidget *widget, Widgets *w)
{
/* Variables declaration */
gdouble val1, val2;
/* Gets the values of the two widgets */
val1 = gtk_spin_button_get_value (w->spin.gtkspinbutton);
val2 = gtk_range_get_value (w->scale.gtkrange);
/* If synchronisation is active */
if (gtk_toggle_button_get_active (w->check.gtktogglebutton) && val1 != val2)
{
/* Ajusts the value of the "passive" widget regarding the value of the widget
wich have activated the signal */
if (GTK_IS_SPIN_BUTTON (widget)) gtk_range_set_value (w->scale.gtkrange,
val1);
else gtk_spin_button_set_value (w->spin.gtkspinbutton, val2);
}
}
gtkadjustment.h
/* Declaration of the GTKADJUSTMENT union of pointers describing the hierarchy
of the GtkWindow widget. */
/* Should be included in the gtk/gtkwindow.h header file. */
typedef union
{
GObject *gobject;
GInitiallyUnowned *ginitiallyunowned;
GtkAdjustment *gtkadjustment;
} GTKADJUSTMENT;
gtkcheckbutton.h
/* Declaration of the GTKCHECKBUTTON union of pointers describing the hierarchy
of the GtkWindow widget. */
/* Should be included in the gtk/gtkwindow.h header file. */
typedef union
{
GObject *gobject;
GInitiallyUnowned *ginitiallyunowned;
GtkWidget *gtkwidget;
GtkContainer *gtkcontainer;
GtkBin *gtkbin;
GtkButton *gtkbutton;
GtkToggleButton *gtktogglebutton;
GtkCheckButton *gtkcheckbutton;
} GTKCHECKBUTTON;
gtkgrid.h
/* Declaration of the GTKGRID union of pointers describing the hierarchy of the
GtkWindow widget. */
/* Should be included in the gtk/gtkwindow.h header file. */
typedef union
{
GObject *gobject;
GInitiallyUnowned *ginitiallyunowned;
GtkWidget *gtkwidget;
GtkContainer *gtkcontainer;
GtkGrid *gtkgrid;
} GTKGRID;
gtkscale.h
/* Declaration of the GTKSCALE union of pointers describing the hierarchy of
the GtkWindow widget. */
/* Should be included in the gtk/gtkwindow.h header file. */
typedef union
{
GObject *gobject;
GInitiallyUnowned *ginitiallyunowned;
GtkWidget *gtkwidget;
GtkRange *gtkrange;
GtkScale *gtkscale;
} GTKSCALE;
gtkspinbutton.h
/* Declaration of the GTKSPINBUTTON union of pointers describing the hierarchy
of the GtkWindow widget. */
/* Should be included in the gtk/gtkwindow.h header file. */
typedef union
{
GObject *gobject;
GInitiallyUnowned *ginitiallyunowned;
GtkWidget *gtkwidget;
GtkEntry *gtkentry;
GtkSpinButton *gtkspinbutton;
} GTKSPINBUTTON;
gtkwindow.h
/* Declaration of the GTKWINDOW union of pointers describing the hierarchy of
the GtkWindow widget. */
/* Should be included in the gtk/gtkwindow.h header file. */
typedef union
{
GObject *gobject;
GInitiallyUnowned *ginitiallyunowned;
GtkWidget *gtkwidget;
GtkContainer *gtkcontainer;
GtkBin *gtkbin;
GtkWindow *gtkwindow;
} GTKWINDOW;
_______________________________________________
gtk-list mailing list
gtk-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-list