2009/12/22


Go binding for GTK GoのGTKバインディングを現在作業中なのですが、ようやく簡単なTwitterクライアントくらいならば作れる程度に出来上がってきたのでご報告。
mattn's go-gtk at master - GitHub

Go binding for GTK

http://github.com/mattn/go-gtk
イベントハンドラがJavaScriptっぽく書けるので、結構見通し良いコードになります。
package main

import "gtk"
import "gdk-pixbuf"
import "unsafe"
import "http"
import "json"
import "io"
import "os"
import "strconv"
import "strings"
import "reflect"

func url2pixbuf(url string) *gdkpixbuf.GdkPixbuf {
    if r, _, err := http.Get(url); err == nil {
        n, _ := strconv.Atoi64(r.GetHeader("Content-Length"));
        t := r.GetHeader("Content-Type");
        b := make([]byte, n);
        io.ReadFull(r.Body, b);
        var loader *gdkpixbuf.GdkPixbufLoader;
        if strings.Index(t, "jpeg") >= 0 {
            loader, _ = gdkpixbuf.PixbufLoaderWithMimeType("image/jpeg");
        } else {
            loader, _ = gdkpixbuf.PixbufLoaderWithMimeType("image/png");
        }
        loader.SetSize(24, 24);
        loader.Write(b);
        loader.Close();
        return loader.GetPixbuf();
    }
    return nil;
}

func main() {
    gtk.Init(&os.Args);
    window := gtk.Window(gtk.GTK_WINDOW_TOPLEVEL);
    window.SetTitle("Twitter!");
    window.Connect("destroy", func(w *gtk.GtkWidget, args []unsafe.Pointer) {
        gtk.MainQuit();
    }, nil);

    vbox := gtk.VBox(false, 1);

    scrolledwin := gtk.ScrolledWindow(nil, nil);
    textview := gtk.TextView();
    textview.SetEditable(false);
    textview.SetCursorVisible(false);
    scrolledwin.Add(textview);
    vbox.Add(scrolledwin);

    buffer := textview.GetBuffer();

    tag := buffer.CreateTag("blue", map[string] string {
        "foreground": "#0000FF", "weight": "700" });
    button := gtk.ButtonWithLabel("Update Timeline");
    button.Clicked(func(w *gtk.GtkWidget, args []unsafe.Pointer) {
        if r, _, err := http.Get("http://twitter.com/statuses/public_timeline.json"); err == nil {
            n, _ := strconv.Atoi64(r.GetHeader("Content-Length"));
            b := make([]byte, n);
            io.ReadFull(r.Body, b);
            j, _ := json.Decode(string(b));
            arr := reflect.NewValue(j).(*reflect.SliceValue);
            for i := 0; i < arr.Len(); i++ {
                data := arr.Elem(i).(*reflect.InterfaceValue).Elem().(*reflect.MapValue);
                icon := data.Elem(reflect.NewValue("user")).(*reflect.InterfaceValue).Elem().(*reflect.MapValue).Elem(reflect.NewValue("profile_image_url")).(*reflect.InterfaceValue).Elem().(*reflect.StringValue).Get();
                var iter gtk.GtkTextIter;
                buffer.GetStartIter(&iter);
                buffer.InsertPixbuf(&iter, url2pixbuf(icon));
                name := data.Elem(reflect.NewValue("user")).(*reflect.InterfaceValue).Elem().(*reflect.MapValue).Elem(reflect.NewValue("screen_name")).(*reflect.InterfaceValue).Elem().(*reflect.StringValue).Get();
                text := data.Elem(reflect.NewValue("text")).(*reflect.InterfaceValue).Elem().(*reflect.StringValue).Get();
                buffer.Insert(&iter, " ");
                buffer.InsertWithTag(&iter, name, tag);
                buffer.Insert(&iter, ":" + text + "\n");
            }  
        }
    }, nil);
    vbox.PackEnd(button, false, false, 0);

    window.Add(vbox);
    window.SetSizeRequest(300, 400);
    window.ShowAll();
    gtk.Main();
}
実行すると以下の様な画面になります。
go-gtk-twitter-client
まだ、完成じゃないです。がんばります!
Posted at by



2009/12/10


Tatsumakiって面白そうとは思ってたけど、触った事なかったので、勉強してみた。
なるほど面白そう。と思ったのとPSGIでも動かせるんだーと感動しました。今日は勉強がてら、以前紹介した事もあるDiggのDUI Streamと混ぜて遊んでみた。
Digg the Blog » Blog Archive » DUI.Stream and MXHR

We call this technique MXHR (short for Multipart XMLHttpRequests), and we wrote an addition to our Digg User Interface library called DUI.Stream to implement it. Specifically, DUI.Stream opens and reads multipart HTTP responses piece-by-piece through an XHR, passing each chunk to a JavaScript handler as it loads.

http://blog.digg.com/?p=621
miyagawa's Tatsumaki at master - GitHub

Plack-based nonblocking Web framework for IO-bound delayed response, server push (streaming) and long-poll comet

http://github.com/miyagawa/tatsumaki
ルートとなるHTMLからjavascriptでストリームへのエンドポイントへリクエストさせ、そこからmultipart/mixedで送出されるgif画像(静止画)を断続的に送出し、DUI Streamでパースしながら1個のIMGタグを高速に切り替えます。
名前をTatsumakiSenpukyakuと名付けました。
mattn's TatsumakiSenpukyaku at master - GitHub

竜巻旋風脚

http://github.com/mattn/TatsumakiSenpukyaku
実行するとポート9999でサーバが起動し、「せーのー」と勢いを付けたあとに、高速な「竜巻旋風脚」が始まります。
竜巻旋風脚
javascriptからタイマでリクエストしているのではなく、サーバから断続的に、切断せずに送出されています。上記DUIのリンク先にある画像を使ったデモでも分かる通り、ストリーミングによりパラパラと表示されていた画像コンテンツがまるで動画の様に見せる事が出来ます。
ネタっぽい作りですが、へーこんな事出来るんだー...てな感じで動かしてみて下さい。
Posted at by



2009/12/04


GtkTreeModelとか面倒くさい部分に差し掛かってます。でもこれないとコンボボックスもツリーもリストも作れないんすよね。
go-gtk-20091204
いまんところこんな感じ。
イベントクロージャが内包出来てJavaScriptを書いているかの様にGTKプログラミングが出来ています。
    //--------------------------------------------------------
    // GtkButton
    //--------------------------------------------------------
    button := gtk.ButtonWithLabel("Button with label");
    button.Clicked(func(w *gtk.GtkWidget, args []unsafe.Pointer) {
        print("button clicked: ", button.GetLabel(), "\n");
        dialog := gtk.MessageDialog(
            button.GetTopLevelAsWindow(),
            gtk.GTK_DIALOG_MODAL,
            gtk.GTK_MESSAGE_INFO,
            gtk.GTK_BUTTONS_OK,
            entry.GetText()
        );
        dialog.Response(func(w *gtk.GtkWidget, args []unsafe.Pointer) {
            println("Dialog OK!")
        }, nil);
        dialog.Run();
        dialog.Destroy();
    }, nil);
    buttons.Add(button);
完成はまだまだ先です。頑張ります。
Posted at by