Growl for Windows 用の独自のサブスクライバ(購読)プラグインを作る

けっこう前にSDKがリリースされて興味があったんだけど忙しすぎて触ってなかったので、気分転換がてら触ってみる。

SDKダウンロード

SDKのダウンロードは以下のページから、
Growl for Windows


手順

  1. クラスライブラリプロジェクトを作る
  2. プロジェクトに以下のライブラリへの参照を追加する
  3. Growl.Destinations.Subscription を継承したクラスを作る(サブスクライバの本体)
  4. Growl.Destinations.DestinationSettingsPanel を継承したクラスを作る
  5. Growl.Destinations.ISubscriptionHandler を実装したクラスを作る

実際に作ってみる

お決まりの"Hello world"プラグインを作ってみる。

Growl.Destinations.Subscriptionを継承したクラスを作成する

これが「購読」の役割を持つクラスになる。
適当に"HelloSubscription"という名前でクラスを作ってみた。
「購読」クラスといいながらも、ほんとうに実装すると面倒なので、とりあえず十秒ごとにGrowlに通知を出すような実装にした。
実用的なプラグインにするには、ここでなんらかのリソースを監視して、その監視対象の状態にしたがって通知するなどの処理にしたら良いと思う。

using System;
using System.Timers;
using Growl.Connector;
using Growl.Destinations;

namespace HelloSubscriber
{
    /// <summary>
    /// 「購読」クラス
    /// ここで「何か」定期的に監視して、必要ならGrowlへの通知を行う役割を持つ。
    /// ※[Serializable]属性は必須
    /// </summary>
    [Serializable]
    public class HelloSubscription : Subscription
    {
        private const string APP_NAME = "Hello World";
        private const string NOTIFICATION_NAME = "Notify";

        [NonSerialized]
        private Timer timer;

        /// <summary>
        /// コンストラクタ
        /// オブジェクトを初期化する
        /// </summary>
        public HelloSubscription() :
            base("Hello", true)
        {
            Initialize();
        }

        /// <summary>
        /// デシリアラズ(ファイルからのオブジェクトの再構築)されたときの処理
        /// オブジェクトを初期化する
        /// </summary>
        /// <param name="sender"></param>
        public override void OnDeserialization(object sender)
        {
            Initialize();
            base.OnDeserialization(sender);
        }

        /// <summary>
        /// オブジェクトの初期化処理
        /// </summary>
        private void Initialize()
        {
            // タイマーイベントの発生間隔を 10秒 に 
            this.timer = new Timer();
            this.timer.Interval = 10000;
            this.timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
        }

        /// <summary>
        /// タイマーイベント処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            // 通知を投げる
            Notify(new Notification(APP_NAME, NOTIFICATION_NAME, "id", "Title", "Text"));
        }

        /// <summary>
        /// 購読開始処理
        /// </summary>
        public override void Subscribe()
        {
            // すでに購読している場合もあるので、いったん購読を停止する
            Kill();
            timer.Start();

            // 自分自身を登録する
            Application m_app = new Application(APP_NAME);
            NotificationType m_notification = new NotificationType(NOTIFICATION_NAME);
            Register(m_app, new NotificationType[] { m_notification });
        }

        /// <summary>
        /// 購読停止
        /// </summary>
        public override void Kill()
        {
            timer.Stop();
        }

        /// <summary>
        /// 設定ダイアログに表示する購読対象の説明
        /// </summary>
        public override string AddressDisplay
        {
            get { return "Hello world subscription"; }
        }

        public override DestinationBase Clone()
        {
            throw new NotImplementedException();
        }
    }
}
Growl.Destinations.DestinationSettingsPanelを継承したコントロールプラグインの設定パネル)を作る

プラグインの設定パネルの実装は、Growl.Destinations.DestinationSettingsPanelを継承したユーザ定義コントロールで行う。

以下のような、HtlloSubscriptionSettings というコントロールを作成した。

using Growl.Destinations;

namespace HelloSubscriber
{
    /// <summary>
    /// プラグインの設定パネル
    /// </summary>
    public partial class HelloSubscriptionSettings : DestinationSettingsPanel 
    {
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public HelloSubscriptionSettings()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 設定パネルの初期化処理
        /// デフォルトで「保存」(Save)ボタンは非活性状態なので、
        /// 活性状態にするため OnValidChanged() を呼び出す。
        /// 現実的なプラグインでは、入力された内容の有効性をチェックした
        /// うえで、それが正しい場合のみ、OnValidChanged(true)とすべき、
        /// それ以外は false にする。
        /// </summary>
        /// <param name="isSubscription"></param>
        /// <param name="fdli"></param>
        /// <param name="db"></param>
        public override void Initialize(bool isSubscription, DestinationListItem fdli, DestinationBase db)
        {
            OnValidChanged(true);
        }

        /// <summary>
        /// 「購読」クラスの生成
        /// 「保存」(Save)したときに呼び出されるっぽい(未確認)
        /// ここで、購読クラスを生成し、購読開始した状態のオブジェクトを返す。
        /// </summary>
        /// <returns></returns>
        public override DestinationBase Create()
        {
            HelloSubscription hs = new HelloSubscription();
            hs.Subscribe();
            return hs;
        }
    }
}

デザイナで見ると以下のような感じ
特に設定する項目はないので、ただのパネルとして実装してる。

デザイナが生成したソースは以下のような感じ

namespace HelloSubscriber
{
    partial class HelloSubscriptionSettings
    {
        /// <summary> 
        /// 必要なデザイナー変数です。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// 使用中のリソースをすべてクリーンアップします。
        /// </summary>
        /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region コンポーネント デザイナーで生成されたコード

        /// <summary> 
        /// デザイナー サポートに必要なメソッドです。このメソッドの内容を 
        /// コード エディターで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.label1 = new System.Windows.Forms.Label();
            this.panelDetails.SuspendLayout();
            this.SuspendLayout();
            // 
            // panelDetails
            // 
            this.panelDetails.Controls.Add(this.label1);
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Font = new System.Drawing.Font("MS UI Gothic", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
            this.label1.Location = new System.Drawing.Point(102, 66);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(133, 15);
            this.label1.TabIndex = 0;
            this.label1.Text = "Hello subscriptions!!";
            // 
            // HelloSubscriptionSettings
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Name = "HelloSubscriptionSettings";
            this.panelDetails.ResumeLayout(false);
            this.panelDetails.PerformLayout();
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Label label1;
    }
}
Growl.Destinations.ISubscriptionHandler を実装する

最後に、プラグインの登録などの処理を担う SubscriptionHandler を実装する。

using System;
using System.Collections.Generic;
using System.Text;
using Growl.Destinations;

namespace HelloSubscriber
{
    /// <summary>
    /// 購読のハンドラクラス
    /// </summary>
    public class HelloSubscriptionHandler: ISubscriptionHandler 
    {

        #region Member of IDestinationHandler

        /// <summary>
        /// ハンドラの名前
        /// どこで使われるかは未確認...
        /// </summary>
        string IDestinationHandler.Name
        {
            get { return "Hello World!"; }
        }

        /// <summary>
        /// プラグインが公開している「購読」クラスをListで返す
        /// </summary>
        /// <returns></returns>
        List<Type> IDestinationHandler.Register()
        {
            List<Type> list = new List<Type>();
            list.Add(typeof(HelloSubscription));
            return list;
        }

        /// <summary>
        /// 一覧に表示する、アイコン・名称などをDestinationListItemのListで返す
        /// </summary>
        /// <returns></returns>
        List<DestinationListItem> IDestinationHandler.GetListItems()
        {
            SubscriptionListItem item = new SubscriptionListItem("Hello", null, this);
            List<DestinationListItem> list = new List<DestinationListItem>();
            list.Add(item);
            return list;
        }

        /// <summary>
        /// 一覧で選択した購読対象をもとにプラグインの設定パネルを返す
        /// </summary>
        /// <param name="dbli"></param>
        /// <returns></returns>
        DestinationSettingsPanel IDestinationHandler.GetSettingsPanel(DestinationListItem dbli)
        {
            return new HelloSubscriptionSettings();
        }

        DestinationSettingsPanel IDestinationHandler.GetSettingsPanel(DestinationBase db)
        {
            return new HelloSubscriptionSettings();
        }

        #endregion
    }
}

以上でソリューションをビルドすると bin\(Debug|Release)フォルダに プラグインのDllができる。

試してみる

生成された dll たちを、 (ユーザーのホーム)\AppData\Local\Growl\2.0.0.0\Subscribers\Hello に格納して。
Growl for Windows を再起動する。

Growlの設定画面を開き、ネットワークタブの「他のコンピューターからの通知を購読する」の下の+(プラス)ボタンをクリック。
「通知の購読」という画面が出てくるので、この中にさっき作った"Hello"が表示されているはず。

"Hello"を選択すると、設定パネルに切り替わる。

が、今回は何も実装していないので、そのまま「保存」をクリック。

そうすると、十秒ごとに以下のような通知が上がってくる。

これを、ちょっといじれば POP3/IMAPを監視してメールの到着通知や、TwitterAPI叩いてリプライ/DM通知とか簡単にできそうな気がする...