Re: Creating a cairo-gl surface under Gtk.
- From: Ramesh Chandra <torc007 gmail com>
- To: gtk-list gnome org
- Subject: Re: Creating a cairo-gl surface under Gtk.
- Date: Fri, 20 May 2011 17:49:54 +0530
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]