2006/03/21

gtk+-2.8なwidgetの中にcairoを使って絵を書こう(3)

Step 3. いよいよ秒針です。
timer callbackを使って秒針を変えていく。時計の時間を自由にセットできるように時刻をクラス内部でもつために、EggClockFace オブジェクトにプライベート変数を追加する。
C言語でオブジェクト指向をするgtk+らしい違和感ありまくりなコードがいっぱい。


clock.c (clock_face オブジェクトを書いたファイル。)にプライベート変数を定義。
typedef struct _EggClockFacePrivate EggClockFacePrivate;

struct _EggClockFacePrivate
{
struct tm time; /* the time on the clock face */
};

プライベート変数にアクセスするためのマクロ。
#define EGG_CLOCK_FACE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EGG_TYPE_CLOCK_FACE, EggClockFacePrivate))
最後にクラスの init 関数に、プライベート変数を追加するコードを入れる。
g_type_class_add_private (obj_class, sizeof (EggClockFacePrivate));
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);

widget_class->expose_event = egg_clock_face_expose;

g_type_class_add_private (obj_class, sizeof (EggClockFacePrivate));
}

ここまですれば、EggClockFace オブジェクトのプライベート変数にアクセスする方法は、
static void
egg_clock_face_example_function (EggClockFace *clock)
{
EggClockFacePrivate *priv;

priv = EGG_CLOCK_FACE_GET_PRIVATE (clock);
}
となります。めんどくせー。


時刻を更新する関数は
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 */
}

この関数をg_timeout_add 関数を使って一定のインターバルで関数を呼ぶことができる。g_timeout_add は呼ぶ関数が FALSE を返すまでタイムアウトの間隔で呼び続ける。

あとは秒針の描写関数egg_clock_face_redraw_canvas (clock);なのだか、基本的な手順はexpose イベントを一定間隔で起し、再描画する時に背景といっしょに時計の針を更新する。
expose イベントを発行するのがgdk_window_process_updates ()
参考としてgdk_window_invalidate_region ()も。
static void
egg_clock_face_redraw_canvas (EggClockFace *clock)
{
GtkWidget *widget;
GdkRegion *region;

widget = GTK_WIDGET (clock);

if (!widget->window) return;

region = gdk_drawable_get_clip_region (widget->window);
/* redraw the cairo canvas completely by exposing it */
gdk_window_invalidate_region (widget->window, region, TRUE);
gdk_window_process_updates (widget->window, TRUE);

gdk_region_destroy (region);
}

あとは時計の針を描写する所をexpose イベント用の関数egg_clock_face_expose というか draw 関数に追加すれば時計になる。clock-ex4.cがこのコード。