2011/12/13


unite-shimapan - C++でゲームプログラミング
http://d.hatena.ne.jp/osyo-manga/20111213/1323771066
乗るしかない!このビッグウェーブに!!!
mattn/unite-nyancat - GitHub
https://github.com/mattn/unite-nyancat
nyancat
2回目の実行でエラーが出たり、「Source:」までもがシンタックスに含まれてしまっているのは仕様です。
Posted at by




node.js の実装を司る libuv を使ってC言語のアプリケーションを書いていると、コールバック関数が増えていく。まぁこれは致し方ない事なんだけど、これで面倒なのがループを止める方法。libuv は作ったハンドルが全て閉じられると勝手に uv_run が終了する仕組みになっているんだけど、例えば処理内に2つハンドルがあって、かつ閉じようとする箇所が別のコールバック処理内にあるとハンドルをグローバル変数にするか uv_timer_t timer1;
uv_timer_t timer2;

void exit_cb(void* data) {
  uv_close(timer1);
  uv_close(timer2);
}
構造体に格納して引きずり回さなければならない。
typedef struct {
  uv_timer_t timer1;
  uv_timer_t timer2;
} THE_TIMERS;

void exit_cb(void* data) {
  THE_TIMERS* timers = (THE_TIMERS*) data;
  uv_close(timers->timer1);
  uv_close(timers->timer2);
}
どんな時に起きるかというと、libuv を GUI アプリと併用する場合。libuv はメインループを uv_run() で実行する為、GUI のメインループを回す為にアイドルを作る必要がある。

アイドルを作るだってぇ!!!

と思ったあなた、ぜひクリスマスは libuv とお過ごし下さい。
例えば、GTK だと以下の様になります。
#include <uv/uv.h>
#include <gtk/gtk.h>

void
idle_cb(uv_idle_t* idle, int status) {
  gtk_main_iteration_do(FALSE);
}

int
main(int argc, char* argv[]) {
  gtk_init(&argc, &argv);

  GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_widget_show_all(window);

  uv_idle_t idle;
  uv_idle_init(uv_default_loop(), &idle);
  uv_idle_start(&idle, idle_cb);

  uv_run(uv_default_loop());
}
この uv_run() のループを止めるには idle を uv_close() する必要があるのですが、ループ自身もハンドルで、かつ uv_run() はそのハンドルのリファレンスがある内しか回らないという仕様なので、こう書く事が出来ます。
#include <uv/uv.h>
#include <gtk/gtk.h>

void
timer_cb(uv_timer_t* timer, int status) {
  GtkWidget* label = (GtkWidget*) timer->data;
  char buf[64];
  time_t t;
  time(&t);
  strftime(buf, sizeof(buf), "%c", localtime(&t));
  gtk_label_set_text(GTK_LABEL(label), buf);
}

void
idle_cb(uv_idle_t* idle, int status) {
  gtk_main_iteration_do(FALSE);
}

void
destroy_cb(GtkWidget* w, gpointer data) {
  uv_loop_t* loop = (uv_loop_t*) data;
  uv_unref(loop); // stop idle
  uv_unref(loop); // stop timer
}

int
main(int argc, char* argv[]) {
  gtk_init(&argc, &argv);

  GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "clock");

  GtkWidget* vbox = gtk_vbox_new(FALSE, 1);
  GtkWidget* label = gtk_label_new("");
  gtk_container_add(GTK_CONTAINER(vbox), label);
  gtk_container_add(GTK_CONTAINER(window), vbox);
  gtk_window_set_default_size(GTK_WINDOW(window), 30020);
  gtk_widget_show_all(window);

  uv_timer_t timer;
  uv_timer_init(uv_default_loop(), &timer);
  timer.data = (void*) label;
  uv_timer_start(&timer, timer_cb, 10001000);

  uv_idle_t idle;
  uv_idle_init(uv_default_loop(), &idle);
  uv_idle_start(&idle, idle_cb);

  g_signal_connect(G_OBJECT(window), "destroy",
          G_CALLBACK(destroy_cb), uv_default_loop());

  uv_run(uv_default_loop());
}
もちろん、uv_close() する回数が少なければループは止まらないので、あまりちゃんとした方法では無い気もしますが。

GTKの様に iteration 動作出来るツールキットならばいいのですが、iteration 動作出来ないライブラリと併用する場合、libuv 側が回される事になる訳です。つまり libuv に1回だけループを回す手続きが必要な訳で、探しても無かったのでさっきパッチ書いて投げた。取り込まれるかどうかは知らない。
ちなみに、上記の例は libuv と gtk で作る時計なんだけど、これを perl で書くとこうなる
use strict;
use warnings;

use Encode;
use Encode::Locale;
use UV;
use Glib;
use Gtk2 -init;
use Time::Piece;

my $w = Gtk2::Window->new('toplevel');
$w->set_title("timer");
my $v = Gtk2::VBox->new(01);
my $l = Gtk2::Label->new();
$v->add($l);
$w->add($v);
$w->set_default_size(30020);
$w->show_all;

my $t = UV::timer_init();
UV::timer_start($t10001000sub {
  $l->set_label(decode(locale => localtime->strftime));
});

my $i = UV::idle_init();
UV::idle_start($isub {
  Gtk2->main_iteration_do(0);
});

$w->signal_connect(destroy => sub {
  UV::close($t);
  UV::close($i);
});

UV::run;
UV は typester さんが書いた奴。
typester/p5-UV - GitHub
https://github.com/typester/p5-UV
あと、最近書いた go言語の libuv バインディング go-uv で書くとこうなる
package main

import (
    "fmt"
    "github.com/mattn/go-uv"
    "github.com/mattn/go-gtk/gtk"
    "time"
)

func main() {
    gtk.Init(nil)
    window := gtk.Window(gtk.GTK_WINDOW_TOPLEVEL)
    window.SetTitle("Clock")
    vbox := gtk.VBox(false1)
    label := gtk.Label("")
    vbox.Add(label)
    window.Add(vbox)
    window.SetDefaultSize(30020)
    window.ShowAll()

    timer, _ := uv.TimerInit(nil)
    timer.Start(func(h *uv.Handle, status int10001000) {
        label.SetLabel(fmt.Sprintf("%v", time.Now()))
    })

    idle, _ := uv.IdleInit(nil)
    idle.Start(func(h *uv.Handle, status int) {
        gtk.MainIterationDo(false)
    })

    window.Connect("destroy"func() {
        timer.Close(nil)
        idle.Close(nil)
    })

    uv.DefaultLoop().Run()
}
mattn/go-uv - GitHub

Go binding for libuv

https://github.com/mattn/go-uv
Posted at by



2011/12/09


全国8万人の技術系Advent Calendarファンの皆さんこんばんわ。

技術系Advent Calendar見るのは好きだけど思い立った時にいちいち探すのマンドクサイ!
まとめて頂いてるサイトもあるけど、できればここはVimからアクションしたい!

そんなアナタに送ります。
mattn/unite-advent_calendar - GitHub

unite source for advent calendar 2011 in japan

https://github.com/mattn/unite-advent_calendar
:Unite advent_calendar として起動すると
unite-advent_calendar1
ドゥーーーーーーーーーン!

現状、86個のAdvent Calendarが一覧表示されます。さらにこの中の一つを選ぶと(例えばVim Advent Calendar)
unite-advent_calendar1
ズゴゴゴゴゴゴゴゴゴ....

選んだらブラウザが起動します。読みたい奴だけ読んで下さい!
インストールにはopen-browser.vimと、webapi-vimが必要です。

なお、この一覧はtt_clownさんが作った一覧から拝借させて頂きました!
よろしければドゾーーーー!

ATNDのコメント欄にエントリが書かれている物のみ表示可能です。
Posted at by