Paepoi

Paepoi » Gjs Tips » C 言語から Gjs への変換

C 言語から Gjs への変換

# 最終更新日 2023.11.19

関数
基本的に import した Gir オブジェクトからドットで繋ぐだけ。
#!/usr/bin/gjs -m

import GLib from 'gi://GLib';

/**
 * 戻り値がある関数は以下のようにする
 */
let dire = GLib.get_current_dir();
print(dire);

/**
 * C にて引数で値を得る関数は配列で戻ってくる、ぶっちゃけ PyGObject の真似
 *
 * gchar* filename;
 * gchar* hostname;
 * filename = g_filename_from_uri("file://localhost/home/sasakima-nao", &hostname, NULL);
 */
let [filename, hostname] = GLib.filename_from_uri('file://localhost/home/sasakima-nao');
print(filename);
print(hostname);

/**
 * 引数に GError が含まれる関数は try 文にします
 *
 * gboolean g_file_get_contents (  const gchar *filename,
 *                                 gchar **contents,
 *                                 gsize *length,
 *                                 GError **error);
 */
try {
    // length は contents.length にまとめられる
    let [result, contents] = GLib.file_get_contents('存在しないファイル.txt');
    if (result) {
        // TextDecoder はグローバル関数なのでそのまま使える
        let dec = new TextDecoder();
        let text = dec.decode(contents);
        print(text.trim());
    }
} catch(e) {
    print(`FileError: ${e}`)
}

オブジェクト作成
オブジェクトも C 言語とほぼ同様に作成できます、ただし gir では推奨されない。
オブジェクト作成時の引数にプロパティをオブジェクト形式で指定する。
/** C
    GtkButton *button;

    button = gtk_button_new_with_label("new");
*/
/**
 * この書き方でも作成できるけど gir では推奨されない
 * てか JavaScript なんだから new 使わないと変だよね
 * とばっちりが PyGObject での Python らしくない表記なんですけど
 */
let buttonFun = Gtk.Button.new_with_label('new');

/*
 * 下記のように label プロパティを Javascript Object 形式で指定
 */
let buttonObj = new Gtk.Button({
    label='label プロパティに代入しています'
});

メソッド
関数を使ってオブジェクトに命令を出す場合はオブジェクトのメソッドで指定できます。
C の関数で第一引数を除いたものを指定します。
/** C
    gtk_window_set_default_size (mywindow, 300, 400);
*/
mywindow.set_default_size(300, 400);

戻り値、引数
引数で値を得る形式の関数は配列として戻り値となる。
関数自体に戻り値がある場合は最初に戻り値を含んだ配列になる。
/** C
    int width;
    int height;

    gtk_window_get_default_size (window, &width, &height);
*/
let {width, height] = window.get_default_size();

プロパティ
プロパティに関しては実は PyGObject との最大の違いかもしれません、筆者が戸惑ったし。
PyGObject ではプロパティを読み書きする方法に props メソッドを通す必要ががあります。
Gjs では普通に object のメソッドと同一です。
/**C
    g_object_set_property(button, "use-underline", FALSE);
*/
/**
 * ハイフンはアンダーラインに変換して指定
 * ちなみに PyGObject は props メソッドを挟む
 * button.props.use_underline = True;
 */
button.use_underline = true;

列挙体
列挙体は大体こんな感じで変換できます。
/** C
    typedef enum {
      GTK_ORIENTATION_HORIZONTAL,
      GTK_ORIENTATION_VERTICAL
    } GtkOrientation;
*/
Gtk.Orientation.HORIZONTAL

クラス
サブクラスは GObject.registerClass にて登録します。
PyGObject とは違い自前で行う必要があります。
export const RedLabel = GObject.registerClass({
    GTypeName: 'RedLabel'
}, class RedLabel extends Gtk.Label {
    _init() {
        super._init({use_markup: true});
    }
    set_red_text(text) {
        this.label = `<span fgcolor="red">${text}</span>`
    }
});

let warn = new RedLabel()
warn.set_red_text('Warnning!')

シグナル
シグナルは「アプリがアクティブ化した」や「サイズが変更された」等の通知。
又は「ボタンを押した」等をユーザーが行った場合に発生するメッセージ。
そのシグナルに対応するハンドラを作成して処理を行います。
クラスにした場合は vfunc_ のプレフィックスでオーバーライドもできます。
export const App = GObject.registerClass({
    GTypeName: 'App'
}, class App extends Gtk.Application {
    /**
     * このアプリはウインドウを作らないので即終了します
     */
    _init() {
        super._init();
        /* C
            g_signal_connect(G_OBJECT(app), "startup",
                G_CALLBACK(startup_cb), NULL);
        */
        this.connect('startup', this.startup_cb)
    }
    /**
     * connect したシグナルの受信
     */
    startup_cb(app) {
        print('startup 受信');
    }
    /**
     * vfunc でオーバーライド
     */
    vfunc_activate() {
        print('activate 受信');
    }
});

const app = new App();
app.run(null);

Copyright(C) sasakima-nao All rights reserved 2002 --- 2024.