Vala」タグアーカイブ

Gtk SetForegroundWindow

年末年始の空き時間を使って覚書ページまとめと Tips 追加をやっている。
ついでに HDD 内の古いサンプルコードを整理。

ほぼ PyGtk コード、ほとんどもう役に立たない…
GTK3 には Pixmap なんてもう無いっつーのとか。
千以上あったけどやっと 2/3 くらいに減らした。

でも中には今まで気がつかなかったコードも見つかる。
多重起動防止でアプリを最前面にもっていく方法が今まで解らなかった。

gtk_window_activate_focus ()
gtk_window_present ()

どうやらこの二つを呼べばアクティブ化できるようだ。
以前書いた GtkApplication を使った Vala コードを書き換えて実験。

using Gtk;

/*
 * Prevent multiple window Sample
**/
public class TestWin : Window {

    private Notebook note;
    private TextView[] view;

    public TestWin ( Gtk.Application app ) {
        this.set_application ( app );
        this.set_title( "TestWin" );
        note = new Notebook ();
        this.add ( note );
        this.resize ( 320, 240 );
        this.show_all ();
    }
    public void CreateNew () {
        var tab_label = new Label ( "new.txt" );
        var text_view = new TextView ();
        view += text_view;
        note.append_page (text_view, tab_label);
        this.show_all ();
        // New Page Activate
        note.set_current_page ( view.length - 1 );
    }
    public void CreateTab ( File[] files ) {
        foreach ( var file in files ) {
            var tab_label = new Label( file.get_basename () );
            var text_view = new TextView ();
            view += text_view;
            note.append_page(text_view, tab_label);
        }
        this.show_all();
        // Last Page Activate
        note.set_current_page ( view.length - 1 );
    }
}

public class App : Gtk.Application {

    private TestWin win = null;

    public App () {
        Object (application_id:"apps.test.helloworld", flags:ApplicationFlags.HANDLES_OPEN );
    }
    public override void activate () {
        if ( win == null ) {
            win = new TestWin( this );
        }
        win.CreateNew ();
        // SetForegroundWindow
        win.activate_focus();
        win.present();
    }
    public override void open ( File[] files, string hint ) {
        if ( win == null ) {
            win = new TestWin( this );
        }
        win.CreateTab ( files );
        // SetForegroundWindow
        win.activate_focus();
        win.present();
    }
}

public class Main {
    public static int main ( string[] args ) {
        Gtk.init ( ref args );
        var app = new App ();
        app.run ( args );
        return 0;
    }
}

ついでに追加タブもアクティブにするコードも入れてみた。
うん、今のところこれでいけるようだ。
多重起動防止アプリ以外ではどうでもいいことなんだけどね。

コンパイルするの面倒くさいよ、早く PyGI で使えるようになってくれ。

Vala GtkDrawingArea

古いコンテンツの覚書のページ書き換えをヤルヤル詐欺していた。
放置しすぎてもう古さ全開なのでと先週から地味に整理中。
この年末年始休暇の内になんとか整理を終わらせたい。

ウインドウを作る – L’Isola di Niente
ダイアログを作る – L’Isola di Niente

コレのために Glade を何年かぶりに入れたりしたけど特にネタも無かった。
Glade を使ったページは削除で済ませることにしよう。

次は DrawingArea を、PyGtk と共通点がゼロなんだよなココ。
expose-event が draw に変わって cairo_t を使えだもんな。

しかし困った、Fedora 17 では下記 PyGI コードが動かない。
というか draw のシグナルが発生しない。

原因判明、同一ディレクトリに cairo.py なんて名前のファイルを入れていたので上書き扱いになり cairo.Context が見つからず変換できないエラーでシグナルが作成できなかっただけだった…
消したら普通に動いた…

Python with GTK+3.0 Create GtkPixbuf | PaePoi

GTK+ 3.4 自体がおかしいのか gir がおかしいのかな。
Boxes 上の仮想 Ubuntu は GTK+3.6 なのでソッチで動かしてみる。

gtk3_6

問題なく動く、こりゃココの整理は Fedora 18 待ちか。
せっかくなので Vala で同じコードを書いてみた。

PyGI では入れていなかった画像が無かった場合の例外処理も入れて。
以前書いた MessageBox.Show() の使い方サンプルも兼ねて。

using Gtk;
using Gdk; //Pixbuf

/*
 * build command
 * valac --pkg gtk+-3.0 test.vala
 * `--pkg gdk-2.0` Not required
 */

public class Win : Gtk.Window {

    private Pixbuf pixbuf;
    private DrawingArea drawing_area;

    public Win () {
        this.set_title("draw test");
        this.destroy.connect (Gtk.main_quit);
        // DrawingArea
        drawing_area = new DrawingArea();
        drawing_area.draw.connect(on_drawing_area_draw);
        try {
            pixbuf = new Pixbuf.from_file("madoka.jpg");
        } catch (Error e) {
            MessageBox.Show(e.message);
        }
        this.add(drawing_area);
        this.show_all();
    }

    private bool on_drawing_area_draw(Cairo.Context cr) {
        // set picture
        if (pixbuf != null)
            Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
        // Arc
        int width = drawing_area.get_allocated_width();
        int height = drawing_area.get_allocated_height();
        cr.arc( width / 2.0,
                height / 2.0,
                int.min(width, height) / 2.0,
                0,
                2 * Math.PI);
        cr.fill();
        return false;
    }
 
    public static int main (string[] args) {
        Gtk.init(ref args);
        new Win();
        Gtk.main();
        return 0;
    }
}

public class MessageBox {
    public static ResponseType Show (string text) {
        var dlg = new MessageDialog(
                null,
                DialogFlags.MODAL,
                MessageType.ERROR,
                ButtonsType.OK,
                text );
        dlg.set_title("Message");  
        var res = dlg.run();
        dlg.destroy();
        return (ResponseType)res;
    }
}

gtk3_4_vala

Vala では GdkPixbuf.Pixbuf ではなく Gdk.Pixbuf なんだね。
gir って実はよく解っていないけど動的と静的で違うのか。
PyGI では GLib.PI だったのが GLib.Math.PI だったりとか思ったより迷う。
min 関数は int.min() とかって何だよ…
ほとんど同じだけど実は細かく違うのね。

このコードは PyGI っぽくハンドラを書いたけどハンドラに GtkWidget 部を入れられないのでクラス変数を使うしかなく少し面倒、公式サンプルのように書いた方がローカル変数が使えて楽かと。
pkg 指定が Gtk+-3.0 だけでイケたのがちょっと奇妙。

とりあえず GTK+ 3.4 環境でも Vala なら問題なく draw シグナルが使えるってことですね。

しかし古いページはたった三年前に書いたとは思えない古臭さだ。
又あと三年たったら…考えないようにしよう。
最近の Linux は進化が早すぎて怖い。

アプリケーションの.NET Framework 4.5への移行: 廃止された型と新しい型

とはいえ .NET に比べたら楽なもんだ。
969 の新しい public 型なんて吐き気しかしない、Linux へ早めに逃げて良かった。
.NET 関連の tips も削除しといたほうがいいのかも。

mono vala

Ubuntu で mono がデフォルトで入らなくなったので覚書ページを書き換える
と随分前に書いて放置していたので本日シコシコと。
Ubuntu 以外を使う人なら説明不要だろうから Ubuntu ページに入れた。

Ubuntu で Vala – L’Isola di Niente
Ubuntu で C# – L’Isola di Niente

Vala をおすすめしているだけ、私はどんだけ mono が嫌いなんだw

つか Vala ってドキュメントのサンプルコードが充実しているにも程があるので私が新たに描くことなんてほとんど無いや。

valadoc.org

ついでに気がついたけど Gtk# って gtk_init() 等を Application.Init() みたくバインドしているが。
Windows に合わせたのだろうけどコレって GtkApplication と勘違いしないだろうか?
つか GTK3 のバインドを作るとしたらどうすんだコレw
やっちまったなぁという感じ。

どうでもいいけど他にもチマチマと覚書を追記。

Windows 7 とのデュアルブート – L’Isola di Niente

ミニノートは結局 Windows 7 に戻した。
起動まで三分はもう体が耐えられないし、タマに Windows を使う時にしか使わないし。
ならばと Ubuntu をと入れてみたらブートすらしない…

というわけで blog はお知らせのみでした。

Vala Array +=

前回の Vala コードでウッカリしていたことがある。
配列に += しているって何よ…

なんだけど valac は何のエラーも吐かなかった、どういうことだ?
C# では ArrayList か generic を使わないかぎり配列数は固定である。

Python ばかりやっていたので配列の長さは可変だと思い込んでいたわけで。
いや、Python では append() なんだけど、何故か += でイケると思った次第で。
わけがわからないよ。

とにかく何故コンパイルが成功したか確かめる。

前回のコードを -C オプションして C コードを見ると g_renew() で配列を新たに作り直ししている。
C の配列に展開ではなくポインタのポインタに展開するのか、なるほどコレなら動的に増やせる。
つまり Python みたいに可変個数で使えるということなの?
ドキュメントを漁るが見当たらず、自分で実験だ。

ローカル変数で試すと普通にエラー、サンプルコードは必要無いね。
メンバ変数にしているからだろうか。

ところでメンバ変数を参照するコードは main 関数内に書いてはいけないよ。
static 関数からは同じく static 宣言をしたものか定数しか参照できない。
vala は C 言語に展開する言語なのに class の制約はしっかりチェックするのね。

// Error
public class ArrayTest {

    public int[] integer;

    public ArrayTest () {
        integer += 1;
    }
}

public class Main {
    public static int main ( string[] args ) {
        new ArrayTest();
        return 0;
    }
}

駄目ジャン!
どうしてエラーにならなかったのだろう…

まてよ、GtkTextView は GtkWidget で構造体だ。
class や struct の配列ならどうなるのだろう。

// Success

public class TestClass {
    public int x;
    public int y;
    public TestClass (int _x, int _y ) {
        x = _x;
        y = _y;
    }
}

public struct TestStruct {
    int x;
    int y;
}

public class ArrayTest {

    private TestClass[] class_array;
    private TestStruct[] struct_array;

    public ArrayTest () {
        // class +=
        var ca = new TestClass(2, 4);
        var cb = new TestClass(92, 777);
        class_array += ca;
        class_array += cb;
        foreach ( var obj in class_array ) {
            stdout.printf ( "%d,%d\n", obj.x, obj.y );
        }
        // struct +=
        TestStruct sa = { 123, 654 };
        TestStruct sb = { 69, 8888 };
        struct_array += sa;
        struct_array += sb;
        foreach ( var obj in struct_array ) {
            stdout.printf ( "%d,%d\n", obj.x, obj.y );
        }
    }
}

public class Main {
    public static int main ( string[] args ) {
        new ArrayTest();
        return 0;
    }
}

マジかよ、普通に += できてしまった、foreach も使える。
つまり構造体という GLib のオブジェクトもどきの配列ならあの _vala_array_add というコードを作成するということなのか。
C# は配列ではこんなことできないよ。

でも配列の一部を取り除く方法は見つからない、できないっぽい。
-= を試すと「配列に算術演算子は使えないよ」ってエラーが出るが += は使えるジャンとツッコミたくなる、だからウッカリしたんだし。
解ったうえで使えば便利かも。

というか、実用では素直に以下のどちらかを使ったほうがいいと思う。
GLib.Array ? glib-2.0
GLib.List ? glib-2.0

Vala GtkApplication

Vala という言語は C# っぽい文法で C 言語ソースコードを作る言語。
だとしたら GtkApplication はどうなるのだろう。

GtkApplication

Python で G_APPLICATION_HANDLES_OPEN を指定して GtkApplication を作成してもエラーになり Gio.File[] 引数が空配列で渡される現象(バグ?)があり困っていたけど C ソースに展開する Vala でなら使えそうだ。
使いたかったけど今までこんな状況だったので。

G_APPLICATION_HANDLES_OPEN @ C, PyGI, Seed | PaePoi

直感で書いてみても上手くいかなかったのでサンプルコードを探す。

Gtk.Application ? gtk+-3.0
GLib.Application ? gio-2.0

こんなにアッサリ、公式ドキュメントがあるというのはやはり楽だ。
GLib.Application というのもあるけど多分 GApplication のことだろう。

しかしサンプルはコードは protected ではエラーになってしまう。
public に書き換えれば問題なく動いた、override って普通はそうするし。

g_signal_connect ではなく override させるのか。
しかしクラスの概念が無い C 言語で override っていったいどう変換しているのだろう。
-C オプションで展開してみると G_APPLICATION_CLASS に代入する C のサンプルコードと似たようなコードを吐いていた、かなり無駄な関数を辿っているような気がするけど。
結果は connect と同じはずなんだけど Vala では connect だとエラーになる。
交わした約束忘れな…いや何でもない。

//public override void open(File[] files, int n_file, string hint) {
public override void open(File[] files, string hint) {

上のように書きたい所だが配列数は length メソッドで調べろらしい。
C# っぽくしたかったのだろうか、よくワカラン。

とにかく GtkApplication は G_APPLICATION_HANDLES_OPEN 指定で問題なく使えるようだ。
アプリ開発者なら涙がちょちょぎれるくらい嬉しい機能なのに日本語で検索してもウチしか引っかからないって何だよ…
どんだけ嬉しいかサンプルコードを書いてみる。

using Gtk;

public class TestWin : Window {

    private Notebook note;
    private TextView[] view;

    public TestWin ( Gtk.Application app ) {
        this.set_application(app);
        this.set_title("TestWin");
        note = new Notebook();
        this.add ( note );
        this.resize ( 320, 240 );
        this.show_all();
    }
    public void CreateNew () {
        var tab_label = new Label("new.txt");
        var text_view = new TextView();
        view += text_view;
        note.append_page(text_view, tab_label);
        this.show_all();
    }
    public void CreateTab ( File[] files ) {
        foreach ( var file in files ) {
            var tab_label = new Label( file.get_basename () );
            var text_view = new TextView ();
            view += text_view;
            note.append_page(text_view, tab_label);
        }
        this.show_all();
    }
}

public class App : Gtk.Application {

    private TestWin win = null;

    public App () {
        Object (application_id:"apps.test.helloworld", flags:ApplicationFlags.HANDLES_OPEN );
    }
    public override void activate () {
        if ( win == null ) {
            win = new TestWin( this );
        }
        win.CreateNew ();
    }
    public override void open ( File[] files, string hint ) {
        if ( win == null ) {
            win = new TestWin( this );
        }
        win.CreateTab ( files );
    }
}

public class Main {
    public static int main ( string[] args ) {
        Gtk.init ( ref args );
        var app = new App ();
        app.run ( args );
        return 0;
    }
}

vala_gtkapplication.tar.gz

完璧な多重起動防止アプリがこんなにアッサリ作れる。
自力でやるなら DBus 通信処理が必要だがマジでこれだけだ。

libunique なんて便利そうなライブラリも一応あるけど。

LibUnique – GNOME Live!

とにかく GtkApplication を使えば DBus 処理も必要なく別個でライブラリを入れてもらう必要もなく、あの面倒極まりない多重起動防止処理が完結できる。
GtkApplication が管理してくれるので delete-event の処理も必要無い。

と解っていたけど PyGI からでは使えなかったんだよね。
んーやっぱり Vala をメイン言語にするかなと、C は面倒くさいし。