clipolix 1.0.0 公開しました。
何も難しくはなかったけどメニューのリロードで迷った。
一度 gtk.Menu.remove() で全削除して作り替えたら消えるし…
なんてことはない、show() させていなかっただけだった。
GTK+ のウィジェットはデフォルトが非表示なのよね、逆に面倒くさいよ。
他シグナルのハンドラを on_* にしたり細々。
ま、こまかいことは GPL なのでということで。
clipolix 1.0.0 公開しました。
何も難しくはなかったけどメニューのリロードで迷った。
一度 gtk.Menu.remove() で全削除して作り替えたら消えるし…
なんてことはない、show() させていなかっただけだった。
GTK+ のウィジェットはデフォルトが非表示なのよね、逆に面倒くさいよ。
他シグナルのハンドラを on_* にしたり細々。
ま、こまかいことは GPL なのでということで。
SHGetFileInfo API にてアイコン取得方法をエラそうに書いているんだけど
てめえ…HICON を破棄してネェぞこのやろう!
という「え、ガベージコレクション仕様な言語なのにそんなもん必要?」な指摘が来た。
そういえばリソースの開放は必須だっけ、何故全自動な仕組みにしないのか解らないけど。
つか今の時代となってはメモリ使用量なんざジャブジャブでいいんじゃい。
Linux 版 Opera 11 のメモリリークっぷりを知っていると笑うところ。
って Ubuntu 10.10 のシステムモニタがおかしいの?マジで笑えないレベルだが。
ソレはいつもの Opera だし、ンナモンさえ割り切れないなら狐を使っとけ。
狐をあんまり使っていないから狐なら大丈夫かどうかは知らないけど…
んなことはどうでもよくて。
Icon.FromHandle メソッド (System.Drawing)
本当だ、FromHandle と Destroy はセットなんだね。
FromHandle 開放 でググったら即見つかった、解放と誤字している人多いな…
いや解放のほうが正しいのか?まあ破棄が一番正しいと思うけど…
しかたがないから書き換えた、Ubuntu から書き換えたので動作は試していない(ぉい!
とにかく、どこの誰かしらないけど指摘ありがとう。
clipoli の Linux 版作成の続き。
C# ソースコードで配布の Windows 版と同様に変なことがやりたい。
このアプリを使ってもらいたいという理由で作っているわけじゃないのよ。
Windows も Linux も他に何もインストールせずこんなことができる!を伝えたい。
Linux 版はたった一つの Python スクリプトで全部まかなうという方向でいく。
とりあえず通知スペース用アイコンをオリジナルに。
/usr/share/pixmaps に XPM を放り込んで…
をやりたくないのでコードに埋め込む。
Windows から clipoli 用に作ったアイコンを持ってくる。
Gimp で開いて XPM に変換保存、拡張子を xpm で保存するだけの全自動。
XPM ファイルを Gedit で開き Python スクリプトにコピペ。
static char 配列を List に書き換える。
#static char * icon_xpm[] = { #}; # ↓ icon = [ ] ### tray = gtk.StatusIcon() xpm = gtk.gdk.pixbuf_new_from_xpm_data(icon) tray.set_from_pixbuf(xpm)
これだけでオリジナルアイコン処理は完成。
INI ファイル読み込みは下記の lead_lines 関数で。
C# で以前作ったのと比較にならないほど短い!
やっぱり構造体を用意する必要が無いって素晴らしい。
[Launcher] メモ帳=gedit 端末=gnome-terminal localhost=xdg-open http://localhost/ [Clipboard] 黒=ほむほむ 赤=あんこ 私ってほんとバカ=こんなの絶対おかしいよ
なんて test.ini を用意して実験。
#! /usr/bin/python # -*- encoding: utf-8 -*- import pygtk pygtk.require("2.0") import gtk import os icon = [ "32 32 3 1", " c None", ". c #000000", "+ c #FFFFFF", " ", " ............ ", " .++++++++++. ", " .++++++++++. ...... ", " .++++++++++. .++++. ", " .++++++++++. .++++. ", " .++++...+++. .++++. ", " .++++....... .++++. ", " .++++. .++++. ", " .++++. .++++. ", " .++++. .++++. ...... ", " .++++. .++++. .++++. ", " .++++. .++++. .++++. ", " .++++. .++++. .++++. ", " .++++. .++++. ...... ", " .++++. .++++. ", " .++++. .++++. ...... ", " .++++. .++++. .++++. ", " .++++. .++++. .++++. ", " .++++. .++++. .++++. ", " .++++. .++++. .++++. ", " .++++. .++++. .++++. ", " .++++. .++++. .++++. ", " .++++. .++++. .++++. ", " .++++....... .++++. .++++. ", " .++++...+++. .++++. .++++. ", " .++++++++++. .++++. .++++. ", " .++++++++++. .++++. .++++. ", " .++++++++++. .++++. .++++. ", " .++++++++++. .++++. .++++. ", " ............ ...... ...... ", " "] def read_lines(filename): if os.path.exists(filename): f = open(filename) x = f.read() f.close() lines = x.split("\n") section = "" for line in lines: if line == "": continue if line[0] == ";": continue if len(line) > 2 and line[0] =="[" and line[-1] == "]": section = line[1:-1] elif section == "": pass # Nothing elif "=" in line: pos = line.index("=") yield (section, line[:pos], line[pos+1:]) class TrayItem(gtk.Menu): def __init__( self, trayIcon): gtk.Menu.__init__( self) self.tray = trayIcon # ini filename = os.path.join(os.path.dirname(__file__), "test.ini") for section, key, value in read_lines(filename): m = gtk.MenuItem(key) m.set_name(value) if section == "Launcher": m.connect("activate", self.on_launcher) elif section == "Clipboard": m.connect("activate", self.on_clipboard) self.append(m) self.append(gtk.SeparatorMenuItem()) q = gtk.MenuItem("終了(_X)") q.connect("activate", self.on_quit) self.append(q) self.show_all() def on_launcher(self, widget): l = widget.get_name() os.system("%s &" % l) def on_clipboard(self, widget): c = gtk.Clipboard() c.set_text(widget.get_name()) def on_quit(self, widget): gtk.main_quit() def show_menu(self, widget, button, time): self.popup( None, None, gtk.status_icon_position_menu, 0, time, self.tray) def show_menu_act(self, widget): self.popup( None, None, gtk.status_icon_position_menu, 0, 0, self.tray) if __name__ == '__main__': # Create GtkStatusIcon and GtkMenu tray = gtk.StatusIcon() trayMenu = TrayItem(tray) # Icon as XPM data xpm = gtk.gdk.pixbuf_new_from_xpm_data(icon) tray.set_from_pixbuf(xpm) # Left and Right Click tray.connect( "popup-menu", trayMenu.show_menu) tray.connect( "activate", trayMenu.show_menu_act) gtk.main()
それっぽくなってきた。
KDE でも使える、ランチャするアプリは KDE に合わせなきゃいけないけど。
下は Mandriva で試してみた画像。
てかアプリ名はいかに、clipolix と又 x のサフィックス付きにするつもりだが。
SeeMe for Linux も次回から SeeMex にしよう、名前が長くて面倒だし。
てゆーか今の Opera ではあんまり SeeMe の意味が無くなっているんだが…
clipoli の Linux 版を作ろうと思う。
GNOME でランチャなんて馬鹿馬鹿しいけどクリップボード機能は欲しいので。
Windows で言うタスクトレイは Linux では通知スペースと言うらしい。
ココにアイコンを表示させてランチャ形式にすればいいかな。
方法は日本語でアッサリ見つかった。
GtkStatusIcon というのを作ってメニューを突っ込めばいいのね。
ini 読み込みコードは後で作るとして。
yield でタプルを戻すだけでいいから C# より簡単だ。
次にクリップボードとランチャの振り分け。
まあ実験段階なのでこんな感じで実験してみよう。
#! /usr/bin/python # -*- encoding: utf-8 -*- import pygtk pygtk.require("2.0") import gtk import os class TrayItem(gtk.Menu): def __init__( self, trayIcon): gtk.Menu.__init__( self) self.tray = trayIcon labels = [ ("Launcher", "Totem", "totem"), ("Launcher", "Firefox", "firefox"), ("Launcher", "sasakima site", "xdg-open http://palepoli.skr.jp/"), ("Clipboard", "Clip", "てきすと") ] for l in labels: m = gtk.MenuItem(l[1]) m.set_name(l[2]) if l[0] == "Launcher": m.connect("activate", self.on_launcher) elif l[0] == "Clipboard": m.connect("activate", self.on_clipboard) self.append(m) self.append(gtk.SeparatorMenuItem()) q = gtk.MenuItem("終了") q.connect("activate", self.on_quit) self.append(q) self.show_all() def on_launcher(self, widget): l = widget.get_name() os.system("%s &" % l) def on_clipboard(self, widget): c = gtk.Clipboard() c.set_text(widget.get_name()) def on_quit(self, widget): gtk.main_quit() def show_menu(self, widget, button, time): self.popup( None, None, gtk.status_icon_position_menu, 0, time, self.tray) def show_menu_act(self, widget): self.popup( None, None, gtk.status_icon_position_menu, 0, 0, self.tray) tray = gtk.StatusIcon() trayMenu = TrayItem( tray) tray.set_from_stock( gtk.STOCK_DIALOG_INFO) tray.connect( "popup-menu", trayMenu.show_menu) tray.connect( "activate", trayMenu.show_menu_act) gtk.main()
GtkWidget も Name に文字列を突っ込むという無茶が可能なのね。
こんなことをしようと考えてしまうのは私くらいだろうけど。
.NET の Process.Start() みたく URL なら全自動ってならないや。
xdg-open に渡すしかないか、ちょっといまいちかも。
それとランチャはバックグラウンドで動かす用の & 指定も忘れずに。
gtk.status_icon_position_menu を指定すればこうなるのか。
None だと普通にカーソルがあった位置に出るんだよね。
えらく簡単にココまで作れてしまったなぁ。
やっぱり Linux のほうが何をするにも便利だよ。
世間は震災情報に釘付け、当然私もそうであります。
私自身は愛知、親族は中国地方ばかりなので混乱はありませんでした。
そんな最中で IronPython 2.7 正式版が出たようです。
ただでさえ注目度が低い言語なのにタイミングが悪すぎる…
どうやら 2.7 から .NET 4.0 専用になったみたい。
.NET 4.0 を導入していないと使えないので注意。
インストーラ版は一つしかないので 64bit では今回も (x86) ディレクトリに入る。
デフォルトでは 2.6 とは違う場所にインストールされた。
又しても環境変数の書き換えか、Windows はコレが面倒くさい。
2.6 が完全に残るので比較するには楽でいいのだけれど。
構成ファイルは結構違う。
chm ヘルプが同梱された、CPython に合わせたのだろうけど chm は古い…
IronPython.Wpf.dll とかは何だろう?
と思ったけど情報が見つからないのでテキトーに試した。
# -*- coding: UTF-8 -*- import clr import wpf # IronPython 2.7 """ clr.AddReferenceByPartialName("PresentationCore") clr.AddReferenceByPartialName("PresentationFramework") clr.AddReferenceByPartialName("WindowsBase")""" from System.Windows import * w = Window() w.Title = "Titlebar" w.Show() a = Application() a.Run(w)
reference 指定が import wpf だけでよくなった、簡単になって嬉しい。
他にも何か進歩があるだろうけど今はよくわからない。
2.6 には無かった gzip モジュールが有った。
残念ながら bz2 モジュールは無いみたいだがこれで tar.gz は展開できる。
2.7 互換なので collections.OrderedDict なんかも使える。
起動速度が 10% 早くなったらしい、もう少し早くならんかったのか…
たしかに 2.6 より起動は早いけど普段使うスクリプトには少しキビシイかも。
今のところこんだけ、ニュース見なきゃ。