Widget descriptors as unions



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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]