2009/11/28


やっぱり新しい言語が出来たらGUIだよね!
って事でGTKバインディング作ります!

mattn's go-gtk at master - GitHub

gtk extension for go

http://github.com/mattn/go-gtk
Goでは継承が使えないので、例えばGtkBoxを継承したGtkVBox/GtkHBox、GtkWidgetを継承したGtkWindow/GtkButton/GtkLabel...が上手く表現出来ません。
出来ないというか、GtkButtonにGtkWidgetと同じメソッドを生やそうと思うと、同じコードを書かなければなりません。
色々と模索した結果、gtk.Window()やgtk.Button()で返すのは常にGtkWidgetとし、GtkWindowやGtkButton独自のメソッドを呼び出したい場合には
(&gtk.GtkWindow{window.Widget}).SetTitle("GTK Go!");
こういう風に型変換して貰う事にしました。まぁコンポジションぽい物?
C言語バージョンにおいても同じ処理をする時には gtk_window_set_title(GTK_WINDOW(w), "GTK Go!");
とする訳だし、似てると言えば似てる訳だし...
要は、Widget毎にGtkWidgetからGtkXXXへの変換関数なんか作ってらんねぇよ。バカ!
という訳です。

現状、コールバック(gtk_signal_connect)も動作しています。少しハマった理由としては、goroutineを勝手にスレッドだと思っていたので、スレッド間通信を想定してpipeのコードを書いていましたが、よく考えたらscheduled coroutineだし、自分のwrite pipeを自分でreadしてどうするよ...って気付いたのです。
結局変数ポーリングに変えて現状上手く動いています。
GoでGTKのプログラミングをすると、以下の様なコードになります。
package main

import (
  "os";
  "gtk";
  "unsafe";
)

func main() {
    gtk.Init(&os.Args);
    window := gtk.Window(gtk.GTK_WINDOW_TOPLEVEL);
    (&gtk.GtkWindow{window.Widget}).SetTitle("GTK Go!");

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

    label := gtk.Label("ハローワールド");
    (&gtk.GtkBox{vbox.Widget}).PackStart(label, 0, 1, 0);

    entry := gtk.Entry();
    (&gtk.GtkEntry{entry.Widget}).SetText("入力エリア!");
    vbox.Add(entry);

    button := gtk.ButtonWithLabel("こんにちわ!こんにちわ!");
    button.Connect("clicked", func(widget *gtk.GtkWidget, data unsafe.Pointer){
        println("button clicked");
        println((&gtk.GtkButton{button.Widget}).GetLabel());
    }, nil);
    vbox.Add(button);

    window.Add(vbox);

    window.ShowAll();
    gtk.Main();
}
そして実行画面。
go-gtk
まだ、GtkWindow/GtkButton/GtkLabel/GtkVBox/GtkHBox/GtkEntryのそれぞれ一部のメソッドしか動いていませんが、宜しければ遊んでみて下さい。
そしてもし「おおし!おいらも作るお!」って方が居られたら、ぜひgithubでforkして下さい。

Posted at by



2009/11/25


そろそろgoでライブラリを作る頃かなーと思って、migemo(cmigemo)を使う物を書いてみた。
mattn's go-migemo at master - GitHub

migemo extension for go

コードの中ではKoRoNさんのcmigemoを使った。コードは少ないけど実は少しハマって、今日はそれを書き記したい。

migemoでは、正規表現文字列やパターン文字列をunsigned char*で引数として扱っているんですが、cgoを使ったC言語ライブラリの取り込みを行う場合、char*と型が合わなくてコンパイルエラーが発生する。しかしC言語の様に *C.uchar(p)
等と書けない(これだとucharの参照になってしまう)Go君は、致し方なくchar*を引数に持つwrapper関数を用意するしかないんだけど、実はcgoに食わせるgoファイルでは
package migemo

/*
#include <migemo.h>
static char* _migemo_query(migemo* object, const char* query) {
  return (char*)migemo_query(object, (const unsigned char*)query);
}
static void _migemo_release(migemo* object, const char* str) {
  migemo_release(object, (unsigned char*)str);
}
*/
import "C";
と言った様に、Cのコードが書ける。ここにGoで扱い易い型のwrapperを書けば良い。今回の例だとunsigned char*の引数を持つ関数をchar*で渡せる(C.CString)関数を用意している事になる。

これにより、いちいち別ファイルにwrapper関数用意したりMakefileにwrapperをビルドする為のターゲットを書かなくても良い。

これは便利だ。

話戻してmigemo拡張ですが、現状Open/Close/Load/Queryの4メソッドを持っています。
Queryで渡したパターンによるマッチし得る複数の正規表現が得られます。
package main

import (
  "fmt";
  "regexp";
  "strings";
  "migemo";
)

func main() {
    var pattern = "goGengo";
    var match = "go言語";
    m := migemo.Open("../dict/utf-8.d/migemo-dict");
    s := migemo.Query(m, pattern);
    if (regexp.MustCompile(s).Match(strings.Bytes(match))) {
        fmt.Printf("%s は %s にマッチします!\n", pattern, match);
    } else {
        fmt.Printf("%s は %s にマッチしません!\n", pattern, match);
    }
}
実行すると goGengo は go言語 にマッチします!
と出力されます。
地味に使えるかも。

Posted at by



2009/11/24


最初Goがリリースされた時には、自分がPortingするんだーとか意気込んでましたが、google codeにホスティングされている方のほうが良い物作ってくれそうだったので、ずっと見守ってました。
hectorchu-go-windows - Project Hosting on Google Code

go for Windows

http://code.google.com/r/hectorchu-go-windows/
Windows PEのリンカも入って、適当な物ならばコンパイル&リンク出来る様になってます。
ただ一般的なWindows Portingの問題として、POSIXなAPIであるpipeやfork、ソケットディスクリプタ等といったWindowsで完全に模倣出来ない部分が残っています。例えばhttpクライアントを扱うhttpパッケージは、netパッケージに依存し、かつ内部ではos.Fdを使う為にそのままのコードではWindowsで実行出来ません。さらにgodoc等ファイルおよび外部プログラムを扱う様な物は内部でos.Pipe()、os.Fork()が呼ばれており、こちらもWindowsなAPIで置き換えなければなりません。
現在の所、src/pkg/osとは別にsrc/pkg/windows/osというフォルダで、Win32 APIを使ってosパッケージを模倣され様としています。移植という点ではこれからになりますね。Issue Trackerが開かれていないのでバグ報告出来ないですが、もし気になる事があればメーリングリストに投げようかなと思っています。

ちなみに、スレッドまわりの実装は既に入っているのでgoroutineは動きます。
ぜひ遊んでみましょう!
Posted at by