org-mode で clock-in したタスクをデスクトップに常時表示(Windows)

[ブログ記事](http://ichiroc.hatenablog.com/entry/2013/09/05/183649)からの移行
### 今やってることを忘れないよう目立たせたい

![20130905181115.png](https://qiita-image-store.s3.amazonaws.com/0/10012/dda11f01-2a79-da9b-4ed7-f29fb1d578ff.png "20130905181115.png")

普段、org-mode の ```org-clock-in``` で、今、取り掛かっている仕事を管理している。
しかし、横ヤリが入ったり、単純に忘れたりして、脱線する事が度々ある。

タスクは mode-line に表示されているのだが、必ずしも Emacs 上での仕事ばかりではない。
それにそもそも小さくて目立たない。

そこで、```org-clock-in``` したタスクを、コンパクトなウィンドウでデスクトップ最前面に表示されるようにしたい。

### 完成イメージ

こんなのを常時右下に表示したい。
場所は設定可能。

![20130905181115.png](https://qiita-image-store.s3.amazonaws.com/0/10012/dda11f01-2a79-da9b-4ed7-f29fb1d578ff.png "20130905181115.png")

### 設計方針

- とりあえず Windows の事だけ考える
- タスクを表示するシンプルなアプリを開発する
- それを Emacs から操る


### C#.NET で生まれて初めてアプリケーションを開発

実現には、常に全面に表示されるアプリケーションを開発する必要が有る。

モチはモチ屋に、Windows のアプリ開発はMicrosoftに。
生まれて初めてだが.NETで開発する事にした。
言語はどれも初めてになるが、 C# が Java に似ていると聞いた事が有るのでC#を選択。ただ Java も別に経験無い。

できるだろうか。

#### 結果

取り掛かり、デフォルトの名称(Form1とか)を駆使して、すごい適当に作るが、 **30分くらいで完了** 。
MSすげえ。

#### 仕様

- コマンドライン引数で制御
    - 第1引数 表示する文字列
    - 第2引数 ウィンドウのY位置( Webでいう top  )
    - 第3引数 ウィンドウのX位置( Webでいう left )

#### TaskViewer.exe 

一応成果物。多分 .NET Framework の何かが必要。

[TaskViewer](https://www.dropbox.com/s/9gue4e9phpi43ps/TaskViewer.exe)

これのソースコードはジョークのレベル。

#### ソースコード

フォームは Designer でペペペッと作った。基本的には Form1 に label1 を配置しただけ。
まるごとをGitHub とかに上げておきたかったけど、入れちゃいかん情報を勝手にIDEがいれてたら恐いので、今はやめておく。

メインのソースはこんな感じ。やっつけ、超やっつけ。

```csharp
// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;


namespace TaskViewer
{
    static class Program
    {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.SetCompatibleTextRenderingDefault(false);

            Form1 myForm = new Form1();
            myForm.TopMost = true;
            Control[] labels = myForm.Controls.Find("label1",false);
            
            if (labels.Length == 1)
            {
                Label label = (Label)labels[0];
                String[] args = System.Environment.GetCommandLineArgs();
                if (args.Length > 1)
                {
                    label.Text = args[1];
                    myForm.AutoSize = true;
                }
                Point location = new Point();
                if (args.Length > 2)
                {
                    // top
                    location.Y = int.Parse(args[2]);
                }
                if (args.Length > 3)
                {
                    //left
                    
                    location.X = int.Parse(args[3]);                   
                }
                myForm.StartPosition = FormStartPosition.Manual;
                myForm.Location = location;
            }
            Application.Run(myForm);
        }
    }
}
```


### org-clock-in-hook , org-clock-out-hook を設定

```org-clock-in``` , ```org-clock-out``` した際に TaskViewer.exe を起動、終了するように設定。

```lisp
;; task viewer 
(defvar my-org-clock-in-shell-buffer-name "*ORG-CLOCK-IN-BUFFER*")
(add-hook 'org-clock-in-hook '(lambda () (interactive)
                                (async-shell-command (concat "taskviewer"
                                                             " \""
                                                             (format-time-string "[%H:%M] " org-clock-start-time)
                                                             org-clock-heading
                                                             "\" "
                                                             (number-to-string (- (display-pixel-height) 160))
                                                             " "
                                                             (number-to-string (- (display-pixel-width)  420)))
                                                     (get-buffer-create my-org-clock-in-shell-buffer-name))
                                (delete-other-windows)))
(add-hook 'org-clock-out-hook '(lambda () (interactive)
                                 (shell-command "taskkill /im:taskviewer.exe")
                                 (let ((clock-process-buffer (get-buffer my-org-clock-in-shell-buffer-name)))
                                   (while (process-live-p
                                           (get-buffer-process clock-process-buffer))
                                     (sleep-for 1))
                                   (kill-buffer clock-process-buffer))))
```                                   

大体良んだけど、 ```org-clock-in``` して、 ```org-clock-out``` せずに別のタスクに ```org-clock-in```すると、clock-in に失敗する。
その場合は ```org-clock-in``` を2回する必要が有る。そのうち改善する。

### 開発まとめ

C# 生まれて初めてでも開発できた。MSすげえ。

Microsoft の開発力と情報量、 Visual Studio のクォリティに恐れ入った。
Visual Studio は補完が強力で、そこは大変気持よかった。

今回は MS 万歳。

### 全体まとめ

適当に作った割りに、なかなか仕事環境が良くなった。