Re: Creating a cairo-gl surface under Gtk.



Hi all,

Update: I commented the code which I think was collecting the clipping region and now I can see the clock on the window, but still the events for draw are not coming continuously, so all I get is a static image of a clock, which changes if the redraw event occurs when I resize the window. Below is the Code which I commented:
static void
egg_clock_face_redraw_canvas (EggClockFace *clock)
{
    GtkWidget *widget;
    //cairo_region_t *region; //commented this

    widget = GTK_WIDGET (clock);

    if (!gtk_widget_get_window(widget)) return;

    //region = gdk_window_get_clip_region (gtk_widget_get_window(widget)); //this too

    /* redraw the cairo canvas completely by exposing it */
    //gdk_window_invalidate_region (gtk_widget_get_window(widget), region, TRUE); //this one also
    gdk_window_process_updates (gtk_widget_get_window(widget), TRUE);

    //cairo_region_destroy(region); //and this, after this I can see the clock :) its 5:50pm over here!!!
}

Ramesh.
On Fri, May 20, 2011 at 4:41 PM, Ramesh Chandra <torc007 gmail com> wrote:
Hi all,

I'm new to linux, Gtk and cairo. Now I want to create a window using Gtk and then draw on it a rectangle using Cairo with a surface of type cairo-gl, how should I go about it. I'm using Eclipse (c/c++)as the development IDE, and I have Gtk3.0 installed, I'm able to create simple widgets using Gtk, like buttons and all. I have tried starting with a simple eggclock code that I found on the net, since it was written with th older Gtk(2+), I migrated it to version 3, it got build successfully, but when I execute it, all I get is an empty Gtk window. Below is the code for this sample:

clock.h:
#ifndef __EGG_CLOCK_FACE_H__
#define __EGG_CLOCK_FACE_H__

#include <gtk/gtk.h>

G_BEGIN_DECLS

#define EGG_TYPE_CLOCK_FACE        (egg_clock_face_get_type ())
#define EGG_CLOCK_FACE(obj)        (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_CLOCK_FACE, EggClockFace))
#define EGG_CLOCK_FACE_CLASS(obj)    (G_TYPE_CHECK_CLASS_CAST ((obj), EGG_CLOCK_FACE, EggClockFaceClass))
#define EGG_IS_CLOCK_FACE(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_CLOCK_FACE))
#define EGG_IS_CLOCK_FACE_CLASS(obj)    (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_CLOCK_FACE))
#define EGG_CLOCK_FACE_GET_CLASS    (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_CLOCK_FACE, EggClockFaceClass))

typedef struct _EggClockFace        EggClockFace;
typedef struct _EggClockFaceClass    EggClockFaceClass;

struct _EggClockFace
{
    GtkDrawingArea parent;

    /* < private > */
};

struct _EggClockFaceClass
{
    GtkDrawingAreaClass parent_class;

    void    (* time_changed)    (EggClockFace *clock,
                     int hours, int minutes);
};

GtkWidget *egg_clock_face_new (void);

G_END_DECLS

#endif

clock.c:
#include <gtk/gtk.h>
#include <math.h>
#include <time.h>

#include "clock.h"
#include "clock-marshallers.h"

#define EGG_CLOCK_FACE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EGG_TYPE_CLOCK_FACE, EggClockFacePrivate))

G_DEFINE_TYPE (EggClockFace, egg_clock_face, GTK_TYPE_DRAWING_AREA);

static gboolean egg_clock_face_expose (GtkWidget *clock, GdkEventExpose *event);
static gboolean egg_clock_face_button_press (GtkWidget *clock,
                         GdkEventButton *event);
static gboolean egg_clock_face_button_release (GtkWidget *clock,
                           GdkEventButton *event);
static gboolean egg_clock_face_motion_notify (GtkWidget *clock,
                          GdkEventMotion *event);
static gboolean egg_clock_face_update (gpointer data);

typedef struct _EggClockFacePrivate EggClockFacePrivate;

struct _EggClockFacePrivate
{
    struct tm time;    /* the time on the clock face */
    int minute_offset; /* the offset of the minutes hand */

    gboolean dragging; /* true if the interface is being dragged */
};

enum
{
    TIME_CHANGED,
    LAST_SIGNAL
};

static guint egg_clock_face_signals[LAST_SIGNAL] = { 0 };

static void
egg_clock_face_class_init (EggClockFaceClass *class)
{
    GObjectClass *obj_class;
    GtkWidgetClass *widget_class;

    obj_class = G_OBJECT_CLASS (class);
    widget_class = GTK_WIDGET_CLASS (class);

    /* GtkWidget signals */
    widget_class->draw = egg_clock_face_expose;
    widget_class->button_press_event = egg_clock_face_button_press;
    widget_class->button_release_event = egg_clock_face_button_release;
    widget_class->motion_notify_event = egg_clock_face_motion_notify;

    /* EggClockFace signals */
    egg_clock_face_signals[TIME_CHANGED] = g_signal_new (
            "time-changed",
            G_OBJECT_CLASS_TYPE (obj_class),
            G_SIGNAL_RUN_FIRST,
            G_STRUCT_OFFSET (EggClockFaceClass, time_changed),
            NULL, NULL,
            _clock_marshal_VOID__INT_INT,
            G_TYPE_NONE, 2,
            G_TYPE_INT,
            G_TYPE_INT);

    g_type_class_add_private (obj_class, sizeof (EggClockFacePrivate));
}

static void
egg_clock_face_init (EggClockFace *clock)
{
    gtk_widget_add_events (GTK_WIDGET (clock),
            GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
            GDK_POINTER_MOTION_MASK);

    egg_clock_face_update (clock);

    /* update the clock once a second */
    g_timeout_add (1000, egg_clock_face_update, clock);
}

static void
draw_me (GtkWidget *clock, cairo_t *cr)
{
    EggClockFacePrivate *priv;
    double x, y;
    double radius;
    int i;
    int hours, minutes, seconds;

    priv = EGG_CLOCK_FACE_GET_PRIVATE (clock);

    GtkAllocation allocation;

    gtk_widget_get_allocation(clock, &allocation);
    //X = allocation.X

    x = allocation.width / 2;
    y = allocation.height / 2;
    radius = MIN (allocation.width / 2,
              allocation.height / 2) - 5;

    /* clock back */
    cairo_arc (cr, x, y, radius, 0, 2 * M_PI);
    cairo_set_source_rgb (cr, 1, 1, 1);
    cairo_fill_preserve (cr);
    cairo_set_source_rgb (cr, 0, 0, 0);
    cairo_stroke (cr);

    /* clock ticks */
    for (i = 0; i < 12; i++)
    {
        int inset;

        cairo_save (cr); /* stack-pen-size */

        if (i % 3 == 0)
        {
            inset = 0.2 * radius;
        }
        else
        {
            inset = 0.1 * radius;
            cairo_set_line_width (cr, 0.5 *
                    cairo_get_line_width (cr));
        }

        cairo_move_to (cr,
                x + (radius - inset) * cos (i * M_PI / 6),
                y + (radius - inset) * sin (i * M_PI / 6));
        cairo_line_to (cr,
                x + radius * cos (i * M_PI / 6),
                y + radius * sin (i * M_PI / 6));
        cairo_stroke (cr);
        cairo_restore (cr); /* stack-pen-size */
    }

    /* clock hands */
    hours = priv->time.tm_hour;
    minutes = priv->time.tm_min + priv->minute_offset;
    seconds = priv->time.tm_sec;
    /* hour hand:
     * the hour hand is rotated 30 degrees (pi/6 r) per hour +
     * 1/2 a degree (pi/360 r) per minute
     */
    cairo_save (cr);
    cairo_set_line_width (cr, 2.5 * cairo_get_line_width (cr));
    cairo_move_to (cr, x, y);
    cairo_line_to (cr, x + radius / 2 * sin (M_PI / 6 * hours +
                         M_PI / 360 * minutes),
               y + radius / 2 * -cos (M_PI / 6 * hours +
                            M_PI / 360 * minutes));
    cairo_stroke (cr);
    cairo_restore (cr);
    /* minute hand:
     * the minute hand is rotated 6 degrees (pi/30 r) per minute
     */
    cairo_move_to (cr, x, y);
    cairo_line_to (cr, x + radius * 0.75 * sin (M_PI / 30 * minutes),
               y + radius * 0.75 * -cos (M_PI / 30 * minutes));
    cairo_stroke (cr);
    /* seconds hand:
     * operates identically to the minute hand
     */
    cairo_save (cr);
    cairo_set_source_rgb (cr, 1, 0, 0); /* red */
    cairo_move_to (cr, x, y);
    cairo_line_to (cr, x + radius * 0.7 * sin (M_PI / 30 * seconds),
               y + radius * 0.7 * -cos (M_PI / 30 * seconds));
    cairo_stroke (cr);
    cairo_restore (cr);
}

static gboolean
egg_clock_face_expose (GtkWidget *clock, GdkEventExpose *event)
{
    cairo_t *cr;

    /* get a cairo_t */
    cr = gdk_cairo_create (gtk_widget_get_window(clock));//clock->window);

    cairo_rectangle (cr,
            event->area.x, event->area.y,
            event->area.width, event->area.height);
    cairo_clip (cr);

    draw_me (clock, cr);

    cairo_destroy (cr);

    return FALSE;
}

static gboolean
egg_clock_face_button_press (GtkWidget *clock, GdkEventButton *event)
{
    EggClockFacePrivate *priv;
    int minutes;
    double lx, ly;
    double px, py;
    double u, d2;

    priv = EGG_CLOCK_FACE_GET_PRIVATE (clock);

    minutes = priv->time.tm_min + priv->minute_offset;

    /* From
     * http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
     */
    GtkAllocation allocation;

    gtk_widget_get_allocation(clock, &allocation);
    px = event->x - allocation.width / 2;
    py = allocation.height / 2 - event->y;
    lx = sin (M_PI / 30 * minutes); ly = cos (M_PI / 30 * minutes);
    u = lx * px + ly * py;

    /* on opposite side of origin */
    if (u < 0) return FALSE;

    d2 = pow (px - u * lx, 2) + pow (py - u * ly, 2);

    if (d2 < 25) /* 5 pixels away from the line */
    {
        priv->dragging = TRUE;
        g_print ("got minute hand\n");
    }

    return FALSE;
}

static void
egg_clock_face_redraw_canvas (EggClockFace *clock)
{
    GtkWidget *widget;
    cairo_region_t *region;

    widget = GTK_WIDGET (clock);

    if (!gtk_widget_get_window(widget)) return;

    region = gdk_window_get_clip_region (gtk_widget_get_window(widget));

    /* redraw the cairo canvas completely by exposing it */
    gdk_window_invalidate_region (gtk_widget_get_window(widget), region, TRUE);
    gdk_window_process_updates (gtk_widget_get_window(widget), TRUE);

    cairo_region_destroy(region);
    //gdk_region_destroy (region);
}

static emit_time_changed_signal (EggClockFace *clock, int x, int y)
{
    EggClockFacePrivate *priv;
    double phi;
    int hour, minute;

    priv = EGG_CLOCK_FACE_GET_PRIVATE (clock);

    /* decode the minute hand */
    /* normalise the coordinates around the origin */
    GtkAllocation allocation;

    gtk_widget_get_allocation(clock, &allocation);
    x -= allocation.width / 2;
    y -= allocation.height / 2;

    /* phi is a bearing from north clockwise, use the same geometry as we
     * did to position the minute hand originally */
    phi = atan2 (x, -y);
    if (phi < 0)
        phi += M_PI * 2;

    hour = priv->time.tm_hour;
    minute = phi * 30 / M_PI;

    /* update the offset */
    priv->minute_offset = minute - priv->time.tm_min;
    egg_clock_face_redraw_canvas (clock);

    g_signal_emit (clock,
            egg_clock_face_signals[TIME_CHANGED],
            0,
            hour, minute);
}

static gboolean
egg_clock_face_motion_notify (GtkWidget *clock, GdkEventMotion *event)
{
    EggClockFacePrivate *priv;
    int x, y;

    priv = EGG_CLOCK_FACE_GET_PRIVATE (clock);

    if (priv->dragging)
    {
        emit_time_changed_signal (EGG_CLOCK_FACE (clock),
                event->x, event->y);
    }
}

static gboolean
egg_clock_face_button_release (GtkWidget *clock, GdkEventButton *event)
{
    EggClockFacePrivate *priv;

    priv = EGG_CLOCK_FACE_GET_PRIVATE (clock);

    if (priv->dragging)
    {
        priv = EGG_CLOCK_FACE_GET_PRIVATE (clock);
        priv->dragging = FALSE;
        emit_time_changed_signal (EGG_CLOCK_FACE (clock),
                event->x, event->y);
    }

    return FALSE;
}

static gboolean
egg_clock_face_update (gpointer data)
{
    EggClockFace *clock;
    EggClockFacePrivate *priv;
    time_t timet;

    clock = EGG_CLOCK_FACE (data);
    priv = EGG_CLOCK_FACE_GET_PRIVATE (clock);

    /* update the time */
    time (&timet);
    localtime_r (&timet, &priv->time);

    egg_clock_face_redraw_canvas (clock);

    return TRUE; /* keep running this event */
}

GtkWidget *
egg_clock_face_new (void)
{
    return g_object_new (EGG_TYPE_CLOCK_FACE, NULL);
}

cloock-marshallers.h:
#ifndef ___clock_marshal_MARSHAL_H__
#define ___clock_marshal_MARSHAL_H__

#include    <glib-object.h>

G_BEGIN_DECLS

/* VOID:INT,INT (clock-marshallers.list:2) */
extern void _clock_marshal_VOID__INT_INT (GClosure     *closure,
                                          GValue       *return_value,
                                          guint         n_param_values,
                                          const GValue *param_values,
                                          gpointer      invocation_hint,
                                          gpointer      marshal_data);

G_END_DECLS

#endif /* ___clock_marshal_MARSHAL_H__ */


clock-marshallers.c:

#include    <glib-object.h>


#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
#define g_marshal_value_peek_char(v)     g_value_get_char (v)
#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
#define g_marshal_value_peek_int(v)      g_value_get_int (v)
#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
#define g_marshal_value_peek_long(v)     g_value_get_long (v)
#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
#define g_marshal_value_peek_float(v)    g_value_get_float (v)
#define g_marshal_value_peek_double(v)   g_value_get_double (v)
#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
#define g_marshal_value_peek_param(v)    g_value_get_param (v)
#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
#define g_marshal_value_peek_object(v)   g_value_get_object (v)
#define g_marshal_value_peek_variant(v)  g_value_get_variant (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
 *          Do not access GValues directly in your code. Instead, use the
 *          g_value_get_*() functions
 */
#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
#define g_marshal_value_peek_variant(v)  (v)->data[0].v_pointer
#endif /* !G_ENABLE_DEBUG */


/* VOID:INT,INT (clock-marshallers.list:2) */
void
_clock_marshal_VOID__INT_INT (GClosure     *closure,
                              GValue       *return_value G_GNUC_UNUSED,
                              guint         n_param_values,
                              const GValue *param_values,
                              gpointer      invocation_hint G_GNUC_UNUSED,
                              gpointer      marshal_data)
{
  typedef void (*GMarshalFunc_VOID__INT_INT) (gpointer     data1,
                                              gint         arg_1,
                                              gint         arg_2,
                                              gpointer     data2);
  register GMarshalFunc_VOID__INT_INT callback;
  register GCClosure *cc = (GCClosure*) closure;
  register gpointer data1, data2;

  g_return_if_fail (n_param_values == 3);

  if (G_CCLOSURE_SWAP_DATA (closure))
    {
      data1 = closure->data;
      data2 = g_value_peek_pointer (param_values + 0);
    }
  else
    {
      data1 = g_value_peek_pointer (param_values + 0);
      data2 = closure->data;
    }
  callback = (GMarshalFunc_VOID__INT_INT) (marshal_data ? marshal_data : cc->callback);

  callback (data1,
            g_marshal_value_peek_int (param_values + 1),
            g_marshal_value_peek_int (param_values + 2),
            data2);
}


main.c:
#include <gtk/gtk.h>

#include "clock.h"

static void
time_changed_cb (EggClockFace *clock, int hours, int minutes, gpointer data)
{
    g_print ("::time-changed - %02i:%02i\n", hours, minutes);
}

int
main (int argc, char **argv)
{
    GtkWidget *window;
    GtkWidget *clock;

    gtk_init (&argc, &argv);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

    clock = egg_clock_face_new ();
    gtk_container_add (GTK_CONTAINER (window), clock);

    g_signal_connect (window, "destroy",
            G_CALLBACK (gtk_main_quit), NULL);

    g_signal_connect (clock, "time-changed",
            G_CALLBACK (time_changed_cb), NULL);

    gtk_widget_show_all (window);

    gtk_main ();
}

Thanks in advance.

Ramesh.



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