ubuntu C# matome

とりあえず Ubuntu での C# をまとめてみた。
Ubuntu で C# – L’Isola di Niente

-pkg 指定で pkg-config 展開ができるはずなんだが方法が見つからない。
MonoDevelop 使えで済ませようか、とも思うけどインストールするかどうかも迷っている。
というか見ての通りコッソリと Python を勧めているわけでw

とりあえずこんな感じで覚書ページを小分けで移植していこうと思う。

AMD 690G to 880G for Ubuntu

AMD 880G マザーボードを買ってきた、これに Ubuntu 10.10 を入れる。
AMD 690G と Athron64 x2 2.2GHz にそろそろ限界を感じてきたので。
コイツの内蔵グラフィックで fglrx は大丈夫なのかな?

ついでに Phenom II X4 955 と DDR3 4G メモリ。
今まで Duron とかしか買わなかった私なのに 4 コア CPU とはなんてリッチ。
全部で二万円ちょっとだったけど、安くなったもんだ。

三年前のドスパラマシンの中身を全とっかえ、自分で組むのも三年ぶり。
LED 配線のプラスマイナスを間違えた以外は問題なく終了。
余っている HDD に Ubuntu をインストール、これも問題無しで再起動。

流石は CPU パワーが 1.5 倍かつ 4 コア、体感速度も超早くなった。

fglrx は普通に有効になった、標準ドライバもよくできているけど一応。
とにかくコレで動画の CPU 負荷は減るはず。
標準ドライバの時と違ってスクリーンショットのラインが解りにくい…

後はいつものように旧 HDD をスレーブ接続してデータコピー。
Gedit プラグインや Nautilus スクリプト、Opera の設定はコピーだけで使える。

ところで Ubuntu 関連を探すとディレクトリ名変更に変なことしている人が多いけど

コレを off にして F2 キーで普通に変名するだけなんだが…
~.config/user-dirs.dirs も連動して書き換えしてくれるし。

後は必要なアプリを日本語セットアップヘルパと追加と削除から。
Opera を追加と削除にデフォルトで入れてくれないかなぁ…

Opera
Y901x
Gimp
VirtualBox ose
Sylpheed
Ghex
KeepassX
Apache2
PHP
Gjot2
Gnote

再構築完了まで四時間、旧 HDD はそのまんまバックアップになるので一石二鳥。
問題はコピーした VirtualBox 仮想マシンな Vista はアクチが通るかだ。
Vista を買った時に使っていた DVD-R は同じなのでライセンスは間違っていないが。

問題なかった、数値はあまり変わらないけど明らかに快適さが違う。
CPU を 2 に割り当てしたけどタスクマネージャは一つ、何故だろう。
ついでに起動時のサウンドが歪んでいたのも良くなった。

ま、仮想マシン上での Visual Studio が重すぎるのでパワーアップしたんだが。
それと Y901x とかの動画ファイル切り替えで落ちなくなると嬉しいんだが様子見。

やはり Linux もなるべく新しいハードで使わなければ快適にはならないや。
とにかく AMD 880G + SB710 なら Ubuntu 10.10 は問題無いみたい。

よし動画を見まくるぞ!
いや、サイト整理は地味にやっているけどちっとも進まないんで…

clipoli 1.0.0

clipoli を正式公開。
それとトップページのレイアウト変更、ついでに幾つかのアプリを公開終了をした。
vector に放置している奴も公開停止以来を、何を今ごろだが…

コンパイルしないで Blog と同じようにビルドバッチ付きソースコード配布にした。
これでイケそうだったので、一応オンラインヘルプにビルド方法は書いた。
というかソレがやりたいから作ったといっても過言ではないわけで。

アイコンは Windows 7 のデザインに合わせたつもり、XP だとカッチョワルイ。

WindowsForm を使いたくなかったのでバージョン情報はヒントウインドウで。
レイアウタという概念が無い化石 GUI なんて早くサポートを終了してください。
Forms 名前空間を使わないでトレイが使えるようにならないかな。

INI の読み直し機能を付けた、この機能以外は全部 INI でまかなう方向にした。
つまり作者サイトへのランチャも default.ini を開く機能も消せるという凄い仕様…

ソースコードに <summary> も書いた、あんまり意味ネェ。
今気がついたけどコンストラクタの param name 間違えた!次で直そう。
そういえば readme.txt を付けていない…まあいいか、ソースコード配布だし。

とりあえずこんな仕様になった、初版なんだから何だっていいや!
本日はお知らせのみ。

Clipoli 0.0.2

Clipoli で読み込む ini ファイルはどこに置くか。
exe と同じ位置では昔の古い考え方バリバリなアプリになってしまう。
やはり環境変数 %APPDATA% に置くべきだろう。

echo %APPDATA%

と cmd.exe で打てばそれが何なのか解らない人も理解できるだろう。
Opera や Firefox の設定もココにありますね。

ということで書いてみる。
C# では Environment を使わないと環境変数展開は無理みたい、まぁ ini 側はイケるだろう。
SeeMe の設定で sasakima というディレクトリを作るので同じ所に置くように。

string appdata = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "sasakima");
if (!Directory.Exists(appdata))
{
	Directory.CreateDirectory(appdata);
}
appdata = Path.Combine(appdata, "clipoli");
if (!Directory.Exists(appdata))
{
	Directory.CreateDirectory(appdata);
}
appdata = Path.Combine(appdata, "default.ini");
if (!File.Exists(appdata))
{
	string s = "[Launcher]\r\ndefault.ini を開く=notepad %APPDATA%\\sasakima\\clipoli\\default.in";
	var sw = new StreamWriter(appdata);
	sw.Write(s);
	sw.Close();
}
var app = new TrayIcon(appdata);
Application.Run();

んでコンストラクタ引数に default.ini 位置を渡してコレを読み込むと。
こんな感じでいいかな、やってみる。

Process.Start じゃ環境変数の %APPDATA% を展開してくれない…

引数を半角スペースではなく別オーバーロード引数で渡さないと駄目みたい…

Linux に慣れすぎたのでコマンドラインと GUI の区別が付かなくなってしまった。
だって Linux はどちらも同じだもん、Windows では別物なんだよね。

えっと、%APPDATA% は自前で展開するしかないみたいなので Format するか。
コマンドを引数と分離するには、とりあえずファイル名に使えない | でも利用してみよう。

string appdata = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "sasakima");
if (!Directory.Exists(appdata))
{
	Directory.CreateDirectory(appdata);
}
appdata = Path.Combine(appdata, "clipoli");
if (!Directory.Exists(appdata))
{
	Directory.CreateDirectory(appdata);
}
appdata = Path.Combine(appdata, "default.ini");
if (!File.Exists(appdata))
{
	string s = "[Launcher]\r\ndefault.ini を開く=notepad|{0}";
	s = string.Format(s, appdata);
	var sw = new StreamWriter(appdata);
	sw.Write(s);
	sw.Close();
}
var app = new TrayIcon(appdata);
Application.Run();

これで

private void on_launcher(object sender, EventArgs e)
{
	try
	{
		string s = (sender as ToolStripMenuItem).Name;// MessageBox.Show(s);
		int lPos = s.IndexOf('|');
		if (lPos == -1)
		{
			System.Diagnostics.Process.Start(s);
		}
		else
		{
			string name = s.Substring(0, lPos);
			string args = s.Substring(lPos + 1, s.Length - lPos - 1);
			System.Diagnostics.Process.Start(name, args);
		}
	}
	catch (Exception ex)
	{
		MessageBox.Show(ex.Message);
	}
}

と分離して Process.Start する、意外に面倒な処理になっちまったなぁ。
後は多重起動防止させて、えっとそれから…
あぁアイコンを作る時間も無かった、つか十二時過ぎた、とりあえずバックアップ。

clipoli002.zip

今日は日経平均株価は上がってくれるだろうか…
木金で今月の稼ぎが吹っ飛んでもーたんだが…

Clipoli 0.0.1

Windows アプリ作りの為に新しいノートを買うか迷っている。
が、よく考えたら VirtualBox 仮想マシンの Vista があるじゃないか。
Aero が使えず遅いので全然使わなかったから存在を忘れる所だった。

これを使えばホストの Ubuntu で使っているマジェスタッチで打てる。
あぁキーボード入力が楽々!

しかもコイツには Visual Studio 2008 pro をインストールしてある。
Debug が楽々、コード保管で楽々、リファクタで楽々、何もかもが楽々!
流石はアップグレードに六万円も払っただけはある、これぞ統合開発環境。
テキストエディタだけで開発をしばらくやった後で触るとマジで神アプリ。

でも基本的にこんなものをインストールしないで作れるアプリにしたい。
ので bat の W クリックだけでビルドできるようにアプリ作成を続ける。

とにかく clipoli というタスクトレイ常駐するアプリだ。
当面はランチャとクリップボードにテキストを入れる機能を本格的に。
カスタマイズが簡単にできるように何かのファイルからデータを入れる。

よし、INI ファイルだ。

あぁ Opera 使いの性。

Opera 屋以外はアドオンと考えそう…

ま、仕様をアッサリ決められるかどうかがプロと凡人の違い。
なんだけど後悔することのほうが多いのは書くまでもない。

[Launcher]
メモ帳=C:\Windows\notepad.exe
端末=C:\Windows\System32\cmd.exe
MSDN=http://msdn.microsoft.com/ja-jp/library/

[Clipboard]
けいおん=あずにゃん
俺妹=きりの
えむえむ=みおたん
声優=全部同じ人だった...

みたく INI を作り読み込んでメニューの作成という流れでとりあえずいこう。
C# での INI 読み書きは以前作っているから簡単だ。

UTF-8 の ini 読み書き

と思ったけど今見ると書いていることが少々古い…
てか MessageBox をココで使うと WindowsForm だと using が足らない。
Python で作ったの同様に間違いは例外を投げるように変更して書き換えなきゃ。

そんなことより、このアプリの場合はこんな複雑なコードいらないヤン…

iniread.cs

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

namespace IniFile
{
	public struct Ini
	{
		public string section {get; set;}
		public string key {get; set;}
		public string value {get; set;}
	}
	public static class IniReader
	{
		public static IEnumerable<Ini> ReadLines(string path)
		{
			if (File.Exists(path))
			{
				string section = "";
				using (var sr = new StreamReader(path, Encoding.UTF8))
				{
					string buf;
					while ((buf = sr.ReadLine()) != null)
					{
						if (buf == "") continue;
						if (buf[0] == ';') continue;
						int len = buf.Length;
						if (len > 2 && buf[0] == '[' && buf[len - 1] == ']')
						{
							section = buf.Substring(1, len - 2);
						}
						else if (section == "")
						{
							//何もしない
						}
						else
						{
							int lPos = buf.IndexOf('='); //見つからない場合は -1
							if (lPos > 0)
							{
								Ini ini = new Ini();
								ini.section = section;
								ini.key = buf.Substring(0, lPos);
								ini.value = buf.Substring(lPos + 1, len - lPos - 1);
								yield return ini;
							}
						}
					}
				}
			}
		}
	}
}

これで十分だった、struct を yield で戻せば必要な値は取れるし。
んでコレを展開するコードを。

mainsrc.cs

using System;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection; // MethodInfo
using IniFile;

namespace Clipoli
{
	class TrayIcon
	{
		private NotifyIcon _icon;
		private ContextMenuStrip _menu;
		public TrayIcon()
		{
			_menu = new ContextMenuStrip();
			int i = 0;
			foreach (var ini in IniReader.ReadLines("default.ini"))
			{
				// Load Launcher
				if (ini.section == "Launcher")
				{
					_menu.Items.Add(ini.key, null, on_launcher);
					_menu.Items[i].Name = ini.value;
					i++;
				}
				// Load Clipboard
				else if (ini.section == "Clipboard")
				{
					_menu.Items.Add(ini.key, null, on_clipboard);
					_menu.Items[i].Name = ini.value;
					i++;
				}
				else
				{
					MessageBox.Show("現在 Launcher と Clipboard 以外のセクションは無効です");
				}
			}
			_menu.Items.Add("-");
			_menu.Items.Add("バージョン情報", null, on_about);
			_menu.Items.Add("-");
			_menu.Items.Add("終了", null, on_exit);
			// create tray icon
			_icon = new NotifyIcon();
			_icon.ContextMenuStrip = _menu;
			_icon.Icon = Icon.ExtractAssociatedIcon("clipoli.exe");
			_icon.Text = "Description Text";
			_icon.Visible = true;
			_icon.MouseUp += on_click;
		}

		private void on_click(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Left)
			{
				MethodInfo mi = typeof(NotifyIcon).GetMethod("ShowContextMenu",
								BindingFlags.Instance | BindingFlags.NonPublic);
				mi.Invoke(_icon, null);
			}
		}
		private void on_launcher(object sender, EventArgs e)
		{
			try
			{
				string s = (sender as ToolStripMenuItem).Name;
				System.Diagnostics.Process.Start(s);
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}
		private void on_clipboard(object sender, EventArgs e)
		{
			try
			{
				string s = (sender as ToolStripMenuItem).Name;
				Clipboard.SetText(s);
				System.Media.SystemSounds.Beep.Play();
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}
		private void on_about(object sender, EventArgs e)
		{
			var about = new About(_icon.Icon);
			about.ShowDialog();
		}
		private void on_exit(object sender, EventArgs e)
		{
			_icon.Visible = false;
			Application.Exit();
		}
	}
	class __main__
	{
		[STAThread]
		public static void Main(string[] args)
		{
			var n = new TrayIcon();
			Application.Run();
		}
	}
}

ContextMenu は ContextMenuStrip に変更したほうが扱いやすいみたいだったので。

その ContextMenuStrip.Name プロパティに文字列を入れるというウソみたいなことをやった。
だってこれで動くもの、sender から簡単に文字列が得られるし。

トレイアイコンの左クリックでメニューを出す方法は下記をパクった。
NotifyIconの左クリックでコンテキストメニューを表示させる:Gushwell’s C# Dev Notes

見えない Form をアクティブにするなんて方法も見つけたけど上手くいかなかった。
というか、こんなに強引なのに一番簡単かつ短いコードで終わるという。

想像していたより遥かに短いコードでこれだけ実装できてしまった。
私的にはもうコレで十分、ini の書き方が解らない人なんていないだろうし。
後は何を付けよう、というわけでまとめて zip

clipoli001.zip

しかしマジで Windows マシンはどうしよう?
キーボードでノートを選ぶなら東芝 R730 か Lenovo X201s がよさそうだが…
11.6 型の今でも持ち運びする時に少々大きいし…
1366×768 は正直狭いのでせめて 1600×900 以上にしたいけど…
かといってデスクトップでは使用歩度から考えて邪魔だし…
ブルーレイの再生をしたくなったら動画再生支援機能に問題が無い Windows のほうが…
結局決まらないのでミニノート 7 と仮想マシンの XP, Vista のままになりそう。