Vala etc…

昔書いた Vala コードをもう少しマシなサンプルコードに。
引数で指定したテキストファイルをシングルインスタンスで読み込むように。
多重起動防止処理に startup シグナルを利用してみたけど

startup_error

チェーンアップに失敗って何よ、Google 翻訳役に立たネェ。
一応多重起動防止処理は問題なく行なわれるけど気持ち悪い。
とにかく何かがマズいのだろうと色々検索して以下を見つける。

ApplicationWindow

protected override void startup () {
    base.startup ();
    //etc...
}

startup ハンドラで base.startup を呼ぶ必要があるようです。
何故だかよく解らないけどそういうもんだと納得しておこう。
とにかくそんなこんなでこんなコードを書いてみた。

using Gtk;

/**
 * Single Instance Window
 * valac --pkg gtk+-3.0 hoge.vala
 */
public class TextReader : Window {

    private Notebook _note;

    public TextReader () {
        // Property Set
        Object ( title: "Hoge", default_width: 500, default_height: 400 );
        _note = new Notebook ();
        this.add ( _note );
        this.show_all ();
    }
    public void create_tab ( File? file = null ) {
        if ( file == null ) {
            new_contents ( "New Document", "" );
        } else {
            try {
                var fstream = file.read();
                var dstream = new DataInputStream(fstream);
                var sb = new StringBuilder();
                string line;
                while ( (line = dstream.read_line_utf8(null)) != null ) {
                    sb.append( line );
                    sb.append_c( '\n' );
                }
                new_contents ( file.get_basename(), sb.str );
            } catch ( IOError e ) {
                 messagebox ( "IOError", e.message );
                 return;
            } catch ( Error e ) {
                messagebox ( "Error", e.message );
                return;
            } 
        }
    }
    private void new_contents ( string title, string text ) {
        var view = new TextView ();
        view.show ();
        var sw = new ScrolledWindow ( null, null );
        sw.add ( view );
        sw.show ();
        var label = new Label ( title );
        label.show ();
        if ( text != "" ) {
            var buf = view.get_buffer ();
            buf.set_text ( text );
        }
        var n = _note.append_page(sw, label);
        _note.set_current_page (n);
    }
    private void messagebox ( string title, string s ) {
        var dlg = new MessageDialog( this, DialogFlags.MODAL,
                    MessageType.WARNING, ButtonsType.OK, s );
        dlg.set_title ( title ) ;
        dlg.run ();
        dlg.destroy ();
    }
}

public class App : Gtk.Application {

    private TextReader _win;

    public App () {
        Object (application_id:"apps.test.textreader", flags:ApplicationFlags.HANDLES_OPEN );
    }
    protected override void startup () {
        base.startup ();
        _win = new TextReader ();
        add_window( _win );
    }
    protected override void activate () {
        _win.create_tab ();
        _win.present();
    }
    protected override void open ( File[] files, string hint ) {
        foreach ( var file in files ) {
            _win.create_tab ( file );
        }
        _win.present();
    }
    public static int main ( string[] args ) {
        Gtk.init ( ref args );
        var app = new App ();
        return app.run ( args );
    }
}

なかなか面白いことをみつけた。

public class ClassName : Window {
    public ClassName () {
        Object ( title: "Hoge", default_width: 500, default_height: 400 );

Python

class ClassName (Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="Hoge", default_width=500, default_height=400):

Vala もこんな感じでプロパティセットが可能なんだね。
base ではなく Object なのか、何か凄く変です。
Python のほうが変という人のほうが多いという事実は置いておいて。

それより関数のパラメータをオブジェクトか NULL かで振り分けたい場合。
C ならポインタなのでそのまんま NULL かどうかを見分けできる、Python も同様。
型指定が厳密な C# の場合はオーバーロードを利用すると思います。

Vala は C に変換されるからそのままと思いきや C# と同じく型指定に厳密。
以下のようにすると見事にコンパイルエラーになってしまう。

public void create_tab ( File file ) {
    if ( file == null ) {
//etc...

// Compile Error
_win.create_tab (null);

最初は何故か全然解らず困ったけど多分 C# に合わせたということだろう。
しかし Vala はオーバーロードができないぞ、何か別の手段があるはずだ。
valadoc.org の cancellable 引数等の説明と同じように書いてみたらイケた。

public void create_tab ( File? file = null ) {
    if ( file == null ) {
//etc...

// OK
_win.create_tab ();

コレも凄く変です。
Python のほうが(以下略

後 GtkScrolledWindow は引数が必要だとか PyGI とは微妙に違うのね。
なんだかんだで勉強になった、実践的なコードを書くと色々気が付くものだ。
とにかく筆者は var と new と中括弧とセミコロンが面倒臭いです。