Bakulog

獏の夢日記的な何か。

D言語/DWTでWindows/Linux対応のデスクトップマスコットを作る

タイトルの通りです。ふつうにD言語でDWTを導入するまでの参考にもなるかもしれません。

 

 

本題に入る前に、「D言語でデスクトップマスコット作る」というのは私が言いだしたネタではなくてnamachanさんが宣言していた話題であることを注記させていただきます。私はデスクトップマスコット関連の話題に手広くアプローチしたいので本記事を書ける程度にはD言語に触りましたが、凝ったデスクトップマスコットを作れるほどD言語に詳しいわけではありません。その辺ご了承下さい。

 

もくじ

  • DWTというGUIフレームワーク
  • Java/SWTなら非矩形ウィンドウはこう作れる
  • DWT製のアプリをビルドする(Windows)
  • DWT製のアプリをビルドする(Ubuntu)
  • 絵の出る非矩形ウィンドウを表示するコード
  • まとめと要改善点

 

DWTというGUIフレームワーク

では本題。記事タイトルにもありますが本記事ではD言語でデスクトップマスコットを作る方法の導入を見せます。デスクトップマスコットを作るにあたり、GUIフレームワークの特性として長方形の枠を消したウィンドウ(=非矩形ウィンドウ)が出せるかどうかが重要なポイントになります。

D言語で使えるGUIフレームワークの一覧は公式ページなどで確認できますが、最初のハードルとして「非矩形ウィンドウに対応してるのはどれ?」という観点で注意深くフレームワークを選ばなければなりません。

幸いにしてD言語の場合はJava用のフレームワークSWT」のラッパーにあたるDWTというやつが非矩形ウィンドウに対応しているので、これを使ってみます。完成イメージはこんな感じ。

ubuntu_nonrec_window_dwt

 

以下ではWindows 10とUbuntu 15.10でデスクトップマスコットのひな型が出来るまでの手順を紹介します。

 

Java/SWTなら非矩形ウィンドウはこう作れる

実装の前に本記事で参考にしたJavaの記事を紹介します。

Javaで非矩形ウィンドウ(その3)」という記事があり、この記事ではJavaSWTで非矩形ウィンドウが作れるのを紹介しています。リンク先にはjarの入ったサンプルもあるため、Javaコードを普通に読んでD言語にそれっぽく置き換えれば良さそうだ、という見通しが立ちます。こういう時はフレームワークの底が共通なのは心臓に優しくていいですね。

 

DWT製のアプリをビルドする(Windows)

Qiitaに「dwtを使ってみた(Windowsインストール編)」というドンピシャな記事があるため私からは説明しません。

 

DWT製のアプリをビルドする(Ubuntu)

こっちは普通にやったらコケたので少し丁寧に。ビルドまでの手順は「DWTのインストール」と「簡単なサンプル実行」の2段階に分かれます。

前半のインストールは簡単で、これについてはGithubの解説でBuildingの節に載っているインストール手順を踏んでDWT本体をインストールしたのち、LinuxのRequirementに載ってるパッケージをかたっぱしからapt-get installでインストールすればOKです。

 

問題は後半のサンプルスクリプト実行です。サンプルスクリプト自体はGithubのハローワールドサンプルとして載ってるのを使って大丈夫です。いちおうこちらにも転記しておきます。

module main;

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

void main ()
{
    auto display = new Display;
    auto shell = new Shell;
    shell.open();

    while (!shell.isDisposed)
        if (!display.readAndDispatch())
            display.sleep();

    display.dispose();
}

 

これをビルドするのですが、Githubに載っているLinux用のビルドコマンドをそのまま試した所失敗しました。私がビルドを通すにあたっては以下のように修正しています。

dmd hoge.d -I/home/[USER]/D/dwt/imp -J/home/[USER]/D/dwt/org.eclipse.swt.gtk.linux.x86/res \
-L-L/home/[USER]/D/dwt/lib -L-l:org.eclipse.swt.gtk.linux.x86.a \
-L-l:dwt-base.a -L-lgtk-x11-2.0 -L-lgdk-x11-2.0 -L-latk-1.0 \
-L-lgdk_pixbuf-2.0 -L-lgthread-2.0 -L-lpangocairo-1.0 -L-lfontconfig -L-lXtst \
-L-lXext -L-lXrender -L-lXinerama -L-lXi -L-lXrandr -L-lXcursor -L-lXcomposite \
-L-lXdamage -L-lX11 -L-lXfixes -L-lpango-1.0 -L-lgobject-2.0 \
-L-lgmodule-2.0 -L-ldl -L-lglib-2.0 -L-lcairo -L-lgnomeui-2

ポイントはdwt-baseとswtのライブラリをリンクする所で末尾に".a"拡張子をつけるところです。コレでうまく行く理由が気になる場合は"-L-l:dwt-base.a"の手前あたりにリンカのファイル探索結果メッセージが出力されるようオプション"-L--verbose"を追記したううえで、".a"拡張子を書かずに(=Githubにあるコマンドの通りに)ビルドを試してみてください。

 

上のビルドコマンドには /home/[USER]/D/dwt というのが計3か所出てきますが、これは私がDWTをインストールしたディレクトリです。必要に応じて書き換えて下さい。ディレクトリの指定時にホームディレクトリからのパス( ~/D/dwt )を使うと失敗する場合があるのでこれについてもご注意を。

 

 

絵の出る非矩形ウィンドウを表示するコード

コード見てもらった方が速いのでそのまま貼ります。

//non-rectangular window by D Language / DWT

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;

import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Region;
import org.eclipse.swt.graphics.Rectangle;

void main()
{
    auto display = new Display;
    auto shell = new Shell(display, SWT.NO_TRIM);

    //背景
    auto img = new Image(display, "hoge.bmp");
    auto imgData = img.getImageData();
    shell.setSize(imgData.width, imgData.height);
    shell.setBackgroundImage(img);

    //左上の色を透過色とし、ピクセルごとに走査チェックする(効率悪い)
    auto region = new Region(display);
    int src = imgData.getPixel(0, 0);
    region.add(new Rectangle(0, 0, imgData.width, imgData.height));

    for (int i = 0; i < imgData.height; i++) {
        for (int j = 0; j < imgData.width; j++) {
            if (imgData.getPixel(j, i) == src) {
                region.subtract(new Rectangle(j, i, 1, 1));    
            }
        }
    }
    shell.setRegion(region);

    //右クリックで閉じる
    auto menu = new Menu(shell, SWT.POP_UP);
    auto item = new MenuItem(menu, SWT.PUSH);
    item.setText("Quit" );
    item.addListener (SWT.Selection, new class Listener {
        void handleEvent (Event event) {
            shell.dispose();
        }
    });
    shell.setMenu(menu);
    

    //普通に表示
    shell.open();
    while (!shell.isDisposed) {
        if (!display.readAndDispatch())
            display.sleep();
    }
    display.dispose();
}

上の例ではファイルの実行ディレクトリに"hoge.bmp"という画像がある想定でコードが書かれています。これをビルドすると記事冒頭に載せたようなD言語くんが表示されます。この例ではなるべく単純に動くようにしたかったためbmp画像を使ってますが、別にpngやjpgでも動作すると思います。

 

 

まとめと要改善点

今回は「非矩形ウィンドウが出た!」というだけの話題ですが以上となります。デスクトップマスコットらしい改善を行うには

  • マウスで掴んで動かせるようにする
  • 画像アニメーションさせる
  • 会話ダイアログを表示する
  • 自分で勝手に動くようにする

など必要な事がまだまだあるので、公開するデスクトップマスコットの作成に際してはそのあたりでも工夫が要求されるでしょう。

 

その際に参考にする資料ですが、DWTはSWTを素直にラップしてるのでSWTドキュメンテーションをよく読むことが必要になります。またDWTのインストールディレクトリにある"org.eclipse.swt.snippets"ディレクトリ以下には色々なGUIコントロールを使うD言語コードのサンプルが沢山入っているので、このあたりも参考にすると思い通りの実装が出来るんじゃないかなーと思います。