RSS フィード
惰性でM18からmozillaを使ってきた惰性のままFirefoxを使わずにseamonkeyを使っていたんだが、seamonkeyの個人的な不満はRSSリーダが使えない事だった。そんなわけでwebベースのRSS feed リーダであるbloglines を使ってみる。
惰性でM18からmozillaを使ってきた惰性のままFirefoxを使わずにseamonkeyを使っていたんだが、seamonkeyの個人的な不満はRSSリーダが使えない事だった。そんなわけでwebベースのRSS feed リーダであるbloglines を使ってみる。
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がこのコード。
M+ OUTLINE FONT ML
さて step.2 expose イベント(隠れていたwindow が再描画される時)のシグナルハンドラとして時計の背景を描写する。ここのclock-ex1.cから始めるのが楽。gtk+-2.8が入っているから、コンパイルに必要なフラグは‘pkg-config --cflags gtk+-2.0‘、 リンクは‘pkg-config --libs gtk+-2.0‘ -lm でよい。ここで背景を描写するのはexpose シグナルハンドラとして呼ばれる関数 egg_clock_face_expose です。これは
これだけでいい。後は絵を書く関数 draw を作れば絵が書ける。
static gboolean
egg_clock_face_expose (GtkWidget *clock, GdkEventExpose *event)
{
cairo_t *cr;
/* get a cairo_t */
cr = gdk_cairo_create (clock->window);
/*ここで絵を書く。*/
draw (clock, cr);
cairo_destroy (cr);
return FALSE;
}
draw関数の定義はこれ。っと、元のサンプルはその前に高速化のために隠れた所だけを再描画するように、drawの前に
static void
draw (GtkWidget *clock, cairo_t *cr)
を追加している。これは絵を書くだけならば必要ではない。
cairo_rectangle (cr,
event->area.x, event->area.y,
event->area.width, event->area.height);
cairo_clip(cr);
それでは始めに時計の背景として円を描く。draw関数に、
で書ける。
double x, y;/*中心座標*/
x = clock->allocation.x + clock->allocation.width / 2;
y = clock->allocation.y + clock->allocation.height / 2;
double radius;
radius = MIN (clock->allocation.width / 2,
clock->allocation.height / 2) - 5;
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);/*円を描く*/
四角な時計がいいなら、
double x,y ;
x = clock->allocation.x + clock->allocation.width * 0.05;
y = clock->allocation.y + clock->allocation.height * 0.05 ;
cairo_rectangle( cr , x ,y ,clock->allocation.width*0.9,clock->allocation.height * 0.9 );
cairo_set_source_rgb( cr , 1, 1, 1);
cairo_fill_preserve (cr);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_stroke (cr);
cairo で線を書くのは、ペンで描くようなイメージか(postscript言語に似ている。)。
まず、cairo_move_to でペンを持っていく場所(線の最初の点)を指定。(ペンを空中で持っていくようなイメージ。)次にcairo_line_to でペンを動かす目標を決める(線の最後の点)。んでcairo_strokeで実際に線を書く。(x0,y0)から (x1,y1)へ線を引くには、
となる。時計の細かい線の書きかたは元のページを見てね。
cairo_move_to (cr,x0,y0);
cairo_line_to (cr,x1,y1);
cairo_stroke (cr);
余談、expose_eventを追加するには、このクラスのinit関数の中で、
static void
egg_clock_face_class_init (EggClockFaceClass *class)
{
GtkWidgetClass *widget_class;
widget_class = GTK_WIDGET_CLASS (class);
widget_class->expose_event = egg_clock_face_expose;
}
とexpose_eventにegg_clock_face_exposeを追加したらよい。
gtk+2.8以降に使えるcairoの詳細を読んでいく。以下のコードはこの Writing a Widget Using Cairo and GTK+2.8から来ています。cairoで描写する時計を描くプログラムを作っていく。コードそのものはここで手にはいる。
始めに概念や全体の説明があるけど斜め読みしてstep.1へ。いきなり、main関数を見てみましょうか。
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);
gtk_widget_show_all (window);
gtk_main ();
}
とってもシンプル。この中で特殊なのがegg_clock_face_new()だけ。他はgtk では良く有る話なのでとりあえず無視。このegg_clock_face_newは EggClockFace というGTK_TYPE_DRAWING_AREA なGTK_OBJECT をnewして返す関数であり、
GtkWidget *
egg_clock_face_new (void)
{
return g_object_new (EGG_TYPE_CLOCK_FACE, NULL);
}
となっている。EggClockFace は新しく定義した GTK_OBJECT なんで、
G_DEFINE_TYPE (EggClockFace, egg_clock_face, GTK_TYPE_DRAWING_AREA);
から下に定義しているコードがつづいている。GTK_TYPE_DRAWING オブジェクト はいろいろ便利な機能がそろっているので、これをベースに cairo な clock 用の オブジェクト を作っているらしい。詳細は本文を見てください。
これで準備が終ったので、step.2へ
http://www.gnomejournal.org/article/34/writing-a-widget-using-cairo-and-gtk28