CinnamonのデスクレットでHello World!

![image.png](https://qiita-image-store.s3.amazonaws.com/0/102207/4296e920-398b-89bc-52a6-0744e74400d2.png)
#デスクレットとは
デスクレットはいわゆるCinnamonのデスクトップウィジェットのこと。
時計やカレンダーなどのデスクトップに貼り付けるタイプの小さなアプリケーションです。
デスクレットはCJSというJavascriptベースの言語で書かれており、意外と簡単に作ることが出来ます。
CJS自体はGJSというGnome Shell Extensionsに使われているものがベースです。


#シンプルなデスクレットを作ってみよう
デスクレットに最低限必要なファイルは以下の２つのファイルです。
**``desklet.js``**
**``metadata.json``**
``desklet.js``はプログラム本体で、``metadata.json``はデスクレットについての情報や設定などが書き込まれています。

また、48×48ピクセルの画像ファイルを用意すると、デスクレットの管理画面にアイコン表示されます。
**``icon.png``**

その他に、スタイルシート``stylesheet.css``、設定ファイル``settings-schema.json``なども利用できます。
今回は``stylesheet.css``を含めた構成で作成したいと思います。

##構成ファイルの準備
ホームディレクトリ内のデスクレットのディレクトリに構成ファイルを作成します。
ディレクトリ名は**デスクレットの名前＠作者名**の固有IDで作成します。
今回は``mydesklet@urushibara``を使ってみました。適宜書き換えてください。

```bash:フォルダの作成
mkdir -p ~/.local/share/cinnamon/desklets/mydesklet@urushibara
```
```bash:構成ファイルの生成
cd ~/.local/share/cinnamon/desklets/mydesklet@urushibara
touch desklet.js metadata.json stylesheet.css
```

##ファイル内容の追加
出来たファイルをエディタで開いて以下の内容を書き込みます。

```json:metadata.json
{
    "uuid": "mydesklet@urushibara",
    "name": "Hello, world! desklet",
    "description": "Displays Hello, World!",
    "prevent-decorations": false
}
```

```css:stylesheet.css
.my-desklet-label {
	font-size: 96px;
}
```

```javascript:desklet.js
const Desklet = imports.ui.desklet;
const St = imports.gi.St; //Shell Toolkitのインポート

//デスクレットクラスを定義
class HelloWorld extends Desklet.Desklet {

    constructor(metadata, desklet_id) {
        super(metadata, desklet_id);

        this.window = new St.Bin(); //コンテナの作成
        this.text = new St.Label({style_class: "my-desklet-label"}); //cssのクラス名を指定してラベルを初期化
        this.text.set_text("Hello world!"); //表示するテキストをセット
        this.window.add_actor(this.text); //ラベルをコンテナに追加

        this.setHeader(_("Hello world"));
        this.setContent(this.window);
    }
}

//エントリーポイント
function main(metadata, desklet_id) {
    return new HelloWorld(metadata, desklet_id);
}
```

extend classを使って**``ui.desklet.Desklet``**クラスを継承しています。
ここへGtk+ Shell Extensionの``St(Shell Toolkit)``に含まれている様々な``actor``と呼ばれるUIを追加することが出来ます。
(``actor``と呼ばれるのはDeskletが[Clutter](https://developer.gnome.org/clutter/stable/)を使用している為ですがめんどくさいので省きます＞＜)
今回は使用していませんが、たくさんの``actor``を追加したい場合、[StBoxLayout](https://developer.gnome.org/st/stable/st-st-box-layout.html)コンテナを使うと配置が楽になります。


ちなみに上記ソースコードはCinnamonのデフォルトの「Clock」のソースコードを参考にしています。みたところECMAscript2015準拠なのかJavascriptというよりもJavaに似た書き方となっています。古いデスクレットのソースコードや公式のサンプルコードを見るとprototype宣言を使ってクラス定義を行っていますが、どちらの書き方でも良いようです。ただしおそらく上記の書き方が今後は主流になるのかなと思います。

##デスクレットの起動
メニューから設定→デスクレットを開き、無事に自分のデスクレットがリストに表示されていたら実際に表示させてみましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/102207/26552184-93d7-93aa-b0e5-ee47d47030dd.png)
上のように表示されれば成功です！

もしエラーが発生していたりデスクレットが起動しない場合は、``[Super]``+``[L]``でMelangeでlogを見ると原因が解るかもしれません。
ファイルを修正したら``[ALT]``+``[F2]``を押して、``r``と入力してEnterでCinnamonをリブートして下さい。
リブートをしないままだとCinnamonにキャッシュされてしまい、ファイルを更新しただけでは再読込してくれません。

##イベントハンドラ
今回は使用していませんが[ui.desklet.Desklet](https://github.com/linuxmint/Cinnamon/blob/master/js/ui/desklet.js)クラスにはCinnamonがデスクレットを追加したり削除したりするときに必要なイベントが用意されています。

```Javascript
    on_desklet_clicked() {
        //クリックイベント
    }

    on_desklet_added_to_desktop() {
        //デスクトップに追加された時、deskletManagerによって呼び出されます。
    }

    on_desklet_removed() {
        //デスクトップから削除されたときに呼び出されます。
        //タイマーや無限ループ処理がある場合、ここで必ず終了処理を行う必要があります。
        //※deskletManagerで終了やアンインストールを行って非表示に見えていても
        //　Cinnamonが終了しない限り非同期なスレッドは破棄されずに残り続けます。
    }
```

右クリック時は``Desklet``クラスのプロパティ``_menu``がデフォルトで[ui.PopupMenu](https://github.com/linuxmint/Cinnamon/blob/master/js/ui/popupMenu.js)のactorを格納しており、標準でポップアップメニューが開きます。
項目を追加したい場合は、``this._menu.addAction("text", func)``とやれば項目を追加することが出来ます。

##デスクレットの設定画面
ポップアップメニューの[設定]やデスクレット管理画面の[設定]ボタンで表示されるGUIはどのように作成するのか気になると思います。しかし実は最初に必要な構成ファイルのところで書いていた``settings-schema.json``を追加するだけでGUI表示してくれます。

[設定項目の型の一覧 - Linux Mint Development Center](http://developer.linuxmint.com/reference/git/cinnamon-tutorials/xlet-settings-ref.html)

しかしながら、deskletManagerはあなたのデスクレットクラスの``settings``プロパティを参照してGUIを作成します。したがって以下のようにコンストラクタ内で``settings``プロパティを**new**する必要があります。

```javascript
const Settings = imports.ui.settings; //インポートを忘れずに
                ・
                ・
                ・
        //settingsの初期化
        this.settings = new Settings.DeskletSettings(this, this.metadata["uuid"], desklet_id);
```
[この設定内容が](https://pastebin.com/L0aQyFzR)こんなふうに表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/102207/347a9d66-3697-13f2-32fa-ddeee57ada6e.png)

##設定の反映

普通の設定の取り出し方

```javascript
let font_size = this.settings.getValue("font-size");
```

静的な設定を取り出したいときはこの方法でも構いませんが、設定画面から即時に内容を反映させたい場合は、次のようにイベントハンドラをバインドさせます。

```javascript
this.settings.bind("font-size", "size", this._onSettingsChanged);
```

#おわりに
基本的にアプレットも同じように作成することが出来ます。
設定ファイルの書き出しや読み込みなど、機能的に至れり尽くせりなので、本格的なデスクレットやアプレットも簡単に作れそうですね。


#参考サイト
[Linux Mint Development Center - Writing applets](http://developer.linuxmint.com/reference/git/cinnamon-tutorials/write-applet.html)
[Gnome wiki - GnomeShell Development](https://wiki.gnome.org/Projects/GnomeShell/Development)
[Cinnamon Javascript Reference Manual - Desklet.Desklet](http://lira.epac.to:8080/doc/cinnamon/cinnamon-js/cinnamon-js-ui-desklet-Desklet.html)

この記事はこちらのサイトをベースに、最新のLinux Mintの標準デスクレット「clock」のソースを参考に書きました。
[Tutorial: Hello, world! Cinnamon desklet - OrangeShark](http://www.erikedrosa.com/2014/12/31/hello-world-desklet-tutorial.html)