今月の19日ぐらいにUbuntu 17.10がリリースされます。17.10の最大の変更点はUnityからGNOME Shellへの移行でしょう。そのGNOME Shell、実はUIコンポーネントの多くをJavaScriptで実装しています。JavaScriptの知識さえあれば容易に機能拡張できるようになっているのです。今回はそんなGNOME Shellの拡張機能の作り方を紹介します。
GNOME ShellとJavaScript
今回のリリースはGNOME Shellを抜きにしても、ここ数年で最大の変更点がごろごろ転がっています。ただ、いかんせん「GNOME Shellへの移行」のインパクトが大きすぎて、デスクトップ関連だと「まずGNOME Shellの話」をするだけでお腹いっぱいになってしまう状況になっています。もっとも影響が大きいであろうGNOME Shellに関しては、細かい問題はいくつかあるものの、なんとか今回のリリースで移行を完了できそうな見込みです。おそらく18.04の開発期間は、移行後のブラッシュアップに費やされることでしょう。
さてそんなGNOME Shellについて。これまで採用してきたUnityに対する最大のアドバンテージはその「拡張機能」でしょう。ウェブブラウザーのようにユーザーは自由に拡張機能を追加することで、ただのテーマを超えたUIのカスタマイズが可能になっているのです。いわゆるGNOME 2時代のアプレットやウィジェットがひとつにまとまったようなものだと思ってください。GNOME Shellの拡張機能については過去にも第254回や第258回などで、さまざまな拡張機能を紹介していますし、最近だと第490回にてUbuntuのUIを実現するためにUbuntu 17.10で採用される標準の拡張機能の解説が掲載されています。
GNOME Shellの拡張機能はJavaScriptとCSSで構成されています。つまりウェブ開発の経験があれば比較的かんたんに拡張機能を作成できるのです。実はGNOME Shell本体も、そのシェル部分の多くがJavaScriptとCSSで構築されています。/usr/lib/gnome-shell/libgnome-shell.soの中身も、ほぼJavaScriptの関数だったりします。
ちなみにGNOME ShellではJavaScriptエンジンとして、Firefoxでも利用されているSpiderMonkeyを採用しています。MozillaのソースツリーからSpiderMonkey部分のみがmozjsパッケージとして切り出されているので、それをベースにしたGObject introspectionのJavaScriptバインディングがgjsです。GHOME Shellでは、gjsを用いてUIエレメントを操作できるようになっています。
たとえばGNOME Shell上で「Alt+F2」を押すと、コマンド実行ダイアログが表示されます。そこで「lg」を入力すると「Looking Glass」と呼ばれるデバッグシェルが起動します。Looking GlassのシェルではJavaScriptの文法に従ったコードを書くことでUIの要素を調査したり、コードスニペットの動作確認を行えるのです。
GNOME Shell Extension
さっそくGNOME Shellの拡張機能を作ってみましょう。今回はまだ開発版であるUbuntu 17.10で作業をしていますが、GNOME Shell環境であればUbuntu GNOMEの古いリリースや他のディストリビューションでも同じような結果になるはずです。
GNOME Shellには拡張機能の管理コマンドである「gnome-shell-extension-tool
」が同梱されています。このコマンドを使うと、拡張機能の雛形も生成してくれるのです。
適当なディレクトリで「--create-extension
」オプションを付けて実行し、いくつかの質問に答えていきます。
決めなければならない項目は次の3つです。
- 名前(Name)
- 概要(Description)
- UUID
名前と概要は自由に設定してください。UUIDはユニークなIDをつけますが、何か決まった指定方法があるわけではありません。他の拡張機能と名前がかぶらないことが重要です。コマンドの説明にもあるように、「(拡張機能の名前)@(作成者のメールアドレスで@を.に変更したもの)」あたりが無難でしょう。
設定が完了するとエディターが起動し、メインコードである「extension.js
」が表示されます[1]。実際に作られるファイルは次の3つです。
- extension.js
- metadata.json
- stylesheet.css
「extension.js
」が実際にロジックを記述し、「metadata.json
」には拡張機能の情報を記録します。「stylesheet.css
」は作成するUI部分のレイアウトを記述するCSSファイルです。
作成されたファイルはユーザー固有の拡張機能ディレクトリ(~/.local/share/gnome-shell/extensions/
)に保存されます。
一般的にGNOME Shellの拡張機能をインストールしたときは、このディレクトリに展開されます。Ubuntu DockやAppIndicatorsのようなシステムグローバルな拡張機能は「/usr/share/gnome-shell/extensions
」に保存されます。
サンプル拡張機能の有効化
拡張機能をインストールしただけでは機能は有効になっていません。第490回でも説明しているように、ウェブブラウザーのアドオンやGNOME Tweak Toolなどとして実装されている拡張機能の管理ツールを使って有効化する必要があります。
余計なものをインストールしたくないのであれば、標準でインストールされている「gnome-shell-extension-prefs
」コマンドを使うと良いでしょう。
このコマンドはインストール済みの拡張機能をリストアップして個別に有効化・無効化を設定できます。注意しなくてはならないのは、システムグローバルな拡張機能自体は表示するものの、有効化・無効化の状態は正しく取得できないということです。有効化・無効化の状態はgsettings側の設定を読んでいるらしく、Ubuntu DockやAppIndicatorsのようなシステムグローバルに有効化されている拡張機能は「無効化されている」と誤判定してしまっています。
よって有効化・無効化する際は誤って他の拡張機能を操作しないように気をつけましょう。ちなみにgsettingsコマンドで有効になっている拡張機能のリストを確認したい場合は、次のように実行します。
環境によっては有効化前もしくは有効化後にGNOME Shellを再読込する必要があるようです。「Alt+F2」でコマンド実行ダイアログを表示したあとに「r」を入力という方法もありますが、この方法はWaylandセッションでは動作しないので注意してください。もっとも確実な方法は一度ログアウトすることです。
サンプルの拡張機能が有効化されたら、トップパネルに歯車のアイコンが表示されます。それをクリックすると画面中央に「Hello, world!」とメッセージが表示されます。
extension.jsの中身
拡張機能の本体であるextension.jsの中身を見ていきましょう。基本的に「拡張機能ロード時に呼び出されるinit()
関数」「拡張機能有効化時のenable()
」「拡張機能無効化時のdisable()
」が存在し、拡張機能ごとにそれ以外の関数を実装・呼び出していくことになります。
ファイルの冒頭は必要な機能のインポートとグローバル変数の設定です。Stは「Shell Toolkit」と呼ばれるUIエレメントを操作するツールキットです[2]。実際はClutterのJavaScriptバインディングなので、Clutterのドキュメントも参考になるでしょう。MainはStで作成したUIエレメントを登録し管理するインスタンスです。Tweenerはアニメーションフレームワークです。UIエレメントを動的に変化させたい場合に使います。
textやbuttonはこのサンプル拡張機能で使用しているブロックスコープの変数です。
先にinit()
の中を見てみましょう。前述したとおり、この関数はロード時に一度だけ呼び出されます。拡張機能としては必須の関数です。有効無効に関わらずロード時に呼び出されるため、この関数の中でUIの変更(つまりMain
オブジェクトに対する変更)を行ってはいけません。
今回のサンプルではトップパネルに表示するボタン(UIコンテナー)とアイコンを作成し、それらを紐付けた上で、ボタン上でマウスを押した時のイベントハンドラーを登録しています。
init()
以外に必須の関数が、拡張機能を有効化・無効化されたときに呼び出されるenable()
とdisable()
です。
ここまででボタンの作成、ボタンを押された時のイベントハンドラーの登録までを行えました。あとはイベントハンドラーを実装するだけです。
今回のハンドラーは、メインディスプレイの中央に一定期間メッセージダイアログを表示するというものです。
これがサンプルコードのすべてです。
拡張機能のデバッグ方法
拡張機能の中でもlog()
関数を使ってデバッグログを記録できます。これがどこに出力されるかと言うと、GNOME Shell本体のログ出力先です。Ubuntu 17.10の場合、journalctl
コマンドを使えば特定のプロセスのログを取得できます。よって次のコマンドを実行するとGNOME Shell本体のログを表示できることでしょう。
「-f
」オプションを付けることで、ログが追加されるたびに表示が更新されます。過去も遡って見たい場合「-f
」を外してください。
標準設定だとページャーとしてlessを使うのですが、「-S
」オプションが付いているため長い行は端末の横幅サイズで見えないようになっています。表示する場合はカーソルキーで左右を移動しましょう。
単に右端で折り返したいなら、以下の方法が使えます。
好みに合わせて選択すると良いでしょう。
Looking Glassを開いて、左上のスポイトをクリックすると、マウスを用いて個々のUIエレメントのオブジェクトを選択できます。あとは選択したオブジェクトをLooking Glass上で評価すれば、より深いデバッグが可能になることでしょう。