Paepoi

Paepoi » Gjs Tips » Gjs とは

Gjs とは

最終更新日 2020.08.02

概要
Gjs は GObjectIntrospection の JavaScript バインディングです。
スクリプト言語用は Runtime 版、つまりダイナミックリンクライブラリを使う。
略して Gir と呼ばれます。

Gir に対応した他のスクリプト言語 (PyGObject 等) とできることはほぼ同様。
GNOME3 基本部品の一つなので GNOME3 には必ず入っています。

JavaScript エンジンは Spidermonkey を使います。
同様なものに JavaScriptCore を使う seed がありましたが現在は更新停止状態です。
GTK2 時代に乱立した Python バインディングが PyGtk に一本化されたのと同様。

このページでは GNOME 3.36 標準の gjs 1.64.4 を基に作成しています。
ES2019 をフル対応版です、古いバージョンでは動かない場合があります。
バージョンの確認は以下のコマンドで。
gjs --version

macOS の JXA との違い
JXA では iTunes 等のアプリで行う定型処理を自動化するのが主な使い方。
そもそもが独特すぎて敷居が高い AppleScript の普及言語版みたいな位置付けである。
Cocoa や libc を取り込めるみたいな拡張はされていますが基本はソレ。

Cocoa を使って Objective-c 同様にも使えます、但し情報が極端に少なく至難の技。
本格的アプリなら Objective-c や Swift で作ったほうが楽なのであまり使われない。

Gjs はまったく違います、完全にアプリを作る部品として Gir が提供されています。
/usr/lib64/girepository-1.0 (環境によっては /usr/lib/girepository-1.0)
にあるライブラリを見てのとおり、カーネル以外なんでもアリに近い状態です。

事実 GNOME3 本体でも使われまくっています。
gnome-weather も sushi も GNOME の拡張すらも Gjs で作成されています。
厳密には違うけど .NET Framework のリファレンスとして C# があるように
Gir のリファレンスとして Gjs を提供していると考えたほうが自然。

インポート
JavaScript は言語だけでは計算くらいしかできません。
ウエブブラウザが提供しているオブジェクトを使う等々のように
何かをインポートして取り込む必要があります。
#!/usr/bin/gjs

/**
 * Gir や他の *.js をインポートする時に Gjs は
 * imports.searchPath 配列で指定されているパスを参照する
 * 具体的には下記で出力されるパス
 */
for (let s of imports.searchPath) print(s);

/**
 * 同一ディレクトリを参照に加える場合 bash 等と同様にドットが使える
 * 配列の先頭から順に探すので push, unshift にて都合の良い順番にする
 * 同一ディレクトリの mytool.js なら以下のように拡張子を外して
 */
imports.searchPath.unshift('.');
const Tool = imports.mytool;

/**
 * リソースからも普通に取り込める
 * Gir は gi を挟む
 */
const System = imports.system;
const Gio = imports.gi.Gio;

コードの書き方
#!/usr/bin/gjs
/**
 * 一行目にシバンを入れれば実行パーミッションでアプリとして使える
 * # は JavaScript のコメントではありませんが無視して実行してくれます
 */

/**
 * 必要な Gir をインポートする
 * Gtk のように複数のバージョンがある場合は指定が必要
 * GLib のように一つしか無いものは書かなくていい
 */
imports.gi.versions.Gtk = '3.0';

const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const ByteArray = imports.byteArray;

/**
 * g_get_current_dir
 * のような関数は以下のように書いて使う
 */
let dir = GLib.get_current_dir();

/**
 * gboolean result;
 * gchar* contents;
 * result = g_file_get_contents("hoge.txt", &contents, NULL, NULL);
 *
 * のような C では引数で値を得る関数は以下のように配列で戻ってくる
 * ぶっちゃけ PyGObject の真似ですね
 */
let [result, contents] = GLib.file_get_contents('hoge.txt');

/**
 * 引数に GError が含まれる関数は try 文にします
 * gboolean g_file_get_contents (  const gchar *filename,
 *                                 gchar **contents,
 *                                 gsize *length,
 *                                 GError **error);
 */
try {
    let [result, contents] = GLib.file_get_contents('存在しないファイル.txt');
    if (result) print(ByteArray.toString(contents))
} catch(e) {
    print(`FileError: ${e}`)
}

/*
 * Gtk の widget 作成はプロパティをオブジェクトで指定、new で作成する
 */
let vbox = Gtk.Box({
    orientation: Gtk.Orientation.VERTICAL
});

参考
Projects/Gjs - GNOME Wiki!
GitHub - GNOME/gjs
GNOME JavaScript Docs URL が変わりました

公式デモ、ただし Lang.Class の古い手段なので注意
Tutorials, code samples and platform demos in JavaScript
Copyright(C) sasakima-nao All rights reserved 2002 --- 2023.