Programming」カテゴリーアーカイブ

C++/CLI FromHandle to Destroy

SHGetFileInfo API にてアイコン取得方法をエラそうに書いているんだけど

C++/CLI でアイコンと種類を取ってくる

てめえ…HICON を破棄してネェぞこのやろう!

という「え、ガベージコレクション仕様な言語なのにそんなもん必要?」な指摘が来た。

そういえばリソースの開放は必須だっけ、何故全自動な仕組みにしないのか解らないけど。
つか今の時代となってはメモリ使用量なんざジャブジャブでいいんじゃい。
Linux 版 Opera 11 のメモリリークっぷりを知っていると笑うところ。
って Ubuntu 10.10 のシステムモニタがおかしいの?マジで笑えないレベルだが。

ソレはいつもの Opera だし、ンナモンさえ割り切れないなら狐を使っとけ。
狐をあんまり使っていないから狐なら大丈夫かどうかは知らないけど…
んなことはどうでもよくて。

Icon.FromHandle メソッド (System.Drawing)

本当だ、FromHandle と Destroy はセットなんだね。
FromHandle 開放 でググったら即見つかった、解放と誤字している人多いな…
いや解放のほうが正しいのか?まあ破棄が一番正しいと思うけど…

しかたがないから書き換えた、Ubuntu から書き換えたので動作は試していない(ぉい!
とにかく、どこの誰かしらないけど指摘ありがとう。

notification area XPM Icon

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 の意味が無くなっているんだが…

GNOME notification area

clipoli の Linux 版を作ろうと思う。
GNOME でランチャなんて馬鹿馬鹿しいけどクリップボード機能は欲しいので。

Windows で言うタスクトレイは Linux では通知スペースと言うらしい。
ココにアイコンを表示させてランチャ形式にすればいいかな。

1月 ? 2011 ? ゴミ箱の中のメモ帳

方法は日本語でアッサリ見つかった。
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

世間は震災情報に釘付け、当然私もそうであります。
私自身は愛知、親族は中国地方ばかりなので混乱はありませんでした。

そんな最中で IronPython 2.7 正式版が出たようです。
ただでさえ注目度が低い言語なのにタイミングが悪すぎる…

ironpython – Release: 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 より起動は早いけど普段使うスクリプトには少しキビシイかも。

今のところこんだけ、ニュース見なきゃ。

gnomevfs to gio.File

GIO tutorial: File operations ? Johannes Sasongko’s blog

こんな Blog を見つけた。
そうか、こうやれば gio.File からファイルタイプが取得できるんだ。

これでやっと gnomevfs の呪縛から逃れられそうだ。
もうすぐというか GNOME 3.0 から使えなくなるはず。

PyGObject Reference Manual
gio Constants#gio-file-attribute-constants

上記を見れば名前空間は何を指定すればいいか解るね。
standard::type 指定だと GFileType が戻ってくるので standard::content-type かな。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
import gio

s = sys.argv[1]
f = gio.File(s)
info = f.query_info("standard::content-type")

print "name: {0}\ntype: {1}".format(s, info.get_content_type())

おぉ、これで拡張子が無くても content_type が取得できる!
MIME Type とずっと書いていたけど content_type であったみたい…

沢山の info を query するにはコンマ区切りで書くかワイルドカードを使う。
ただしコンマの前後にスペースを入れると上手くいかないのは何故だろう。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
import gio

s = sys.argv[1]
f = gio.File(s)

# Not Space
info = f.query_info("standard::type,standard::size,standard::content-type")
#info = f.query_info("*")

print info.get_file_type()
print info.get_size()
print info.get_content_type()

ついでに GStreamer から得られる uri も gio で変換できるようだ。

uri = self.player.get_property("uri")
#t = urllib.unquote(uri)[7:]
t = gio.File(uri).get_parse_name()

意図的に日本語ファイル名にしても問題なく変換できた。
というより gio.File() ってフルパスでも uri でもどっちでもいいんだね。
とにかくこれなら urllib モジュールもいらないな、gio スゲェ便利。

ということで Y901x 0.3.4 公開。

そうそう、0.3.3 で dbus を取っ払ったんで本体は gtk.Window 派生に変更した。
多重起動防止はなくなったけどやっと普通な PyGtk アプリになった感じ。
追加機能はほとんどやらずにこんなことばかりやっていていいものか…