月別アーカイブ: 2009年5月

Eye of GNOME プラグインは本当に面倒

おぉ! Eye of GNOME のプラグイン作りが上手くいかない理由がやっと解った。

def activate(self, window):
    self.ww = window

みたくパラメータを self のアトリビュートにした時点で終了しなくなる。
global にしてみても駄目、GtkActionGroup のユーザーデータにしても何をしても駄目。
とにかくパラメータの window ポインタは一切保存しないようにするしかない。

ということは EogImage のポインタはどうやって取得すればいいのだ?
__init__ で get_image() しても None が戻ってくるだけだ。

試しに GtkUIManager から直接 Menu を抜いてコネクトならユーザーデータにできる。
ま、FullScreen プラグインのソースを見たらそうやっていたので試したんだが。

そういえば GtkActionGroup なら window 引数が有るからそのまま使える。
ということは…

#-*- coding:utf-8 -*-

import eog
import gtk

ui_str = """<ui>
    <menubar name="MainMenu">
        <menu name="Edit" action="Edit">
            <separator/>
            <menuitem name="rename" action="rename"/>
        </menu>
    </menubar>
</ui>"""

class RenameDlgPlugin(eog.Plugin):
    def __init__(self):
        eog.Plugin.__init__(self)

    def activate(self, window):
        uimanager = window.get_ui_manager()
        # F2 キーでの処理
        accelgroup = uimanager.get_accel_group()
        accelgroup.connect_group(gtk.keysyms.F2, 0, gtk.ACCEL_VISIBLE, self.on_acc)
        # 上手くいかないけどメニューを作るためだけの処理
        action_group = gtk.ActionGroup("RenameActions")
        actions = [("rename", None, "リネーム", None, "リネーム", None)]
        action_group.add_actions(actions)
        uimanager.insert_action_group(action_group, 0)
        self._ui_id = uimanager.add_ui_from_string(ui_str)
        # メニューは普通にコネクトさせる
        m = uimanager.get_widget("/MainMenu/Edit/rename")
        m.connect("activate", self.on_rename, window)

    def update_ui(self, window):
        pass

    def deactivate(self, window):
        uimanager = window.get_ui_manager()
        uimanager.remove_ui(self._ui_id)
        # 2009.05.16 ちょっと書き換え
        accelgroup = uimanager.get_accel_group()
        accelgroup.disconnect_key(gtk.keysyms.F2, 0)
        #uimanager.remove_action_group(self._action_group)
        uimanager.ensure_update()

    def on_acc(self, accelGroup, window, keyval, modifier):
        self.on_rename(None, window)

    def on_rename(self, widget, window):
        if window == None:
            return
        img = window.get_image()
        if img == None:
            return
        print img.get_uri_for_display()

まったく別々に作ってムリムリにつじつまを合わせてやっと成功、なんじゃこりゃ。
GtkUIManager を使っている意味ネェ、、、、、、、、、、

動けばいいのさ動けば。
やっと実装コードに移れるよ、そっちでも問題バリバリな可能性は高い。

Windows でもゴミ箱

Linux ばかりに触っていたらマニアックになるので Windows を久々に。

せっかくゴミ箱について興味をもったので Windows でも色々調べてみる。
OS の仕様としてゴミ箱を持つ Windows ではコマンドとかはどうなっているのかな?

コマンドプロンプトでごみ箱へファイルを移動させるにはどうすればよいのでしょうか? -OKWave

XP では c:\recycler 以下のはずだけど…てかドライブ毎ユーザー毎に存在するんだが何時の話?
試しにやってみた、ごみ箱に残らないとか書いているけどつまりこうなっているだけだと思う。

cmd_move

アプリを紹介しているけど VC++ を持っているならの SHFileOperation を使って簡単に作(略
なんにせよ Windows でも Shell API からしかアクセスできないんだ、ふむふむ。

OS 非依存の仮想マシンであるはずの .NET Framework はどうなのかな?

ファイルをゴミ箱へ削除(C#)について – Insider.NET

やはり P/Invoke でアクセスしなさい!にしているようで。
そんな糞面倒なことをするより VC++ でラッピングした dll を作って(略
それにしても「がっかり」って人… .NET Framework が何なのか解っているのかな?

Python は…当然 gio モジュールなんか使えるはずもなく。
これも VC++ でラッピングした dll を作って(もういいよ

Windows Power Shell なら結構簡単に

Windows Script Programming: PowerShellでファイルやフォルダをごみ箱に捨てる。

全然簡単じゃネェ!デフォルトで手段を用意してくれている分マシなだけだ。

うわぁ…つまりシェルてかこの手のことをやろうとすると VC++ が必要になるわ。
ま、こんなことを書いたしせっかくなのでゴミ箱へ送る DLL の作り方を書いておこう。
Visual Studio の入っている Vista の HDD に繋ぎ替えて…メンドクサ。

VisualStudio を起動する、VC++ Exp でも同じはず。
trash という名前の新規 Win32 コンソールプロジェクトを作る。
ウイザードを進めてアプリケーションの種類を「DLL」にして完了。
そして Python から使う場合にはまずやらなきゃいけないこと。

stdcall

と呼び出し規約を __stdcall にする、意味は勝手に調べてね。
達人なら違うと言うだろうけど普通の人ならそれ以外はデフォルトのままでいい。
つまりデフォルトの UNICODE ビルドだが今はそのほうが自然だろう。

追記
忘れていた!Releace 版だけでいいんだが
コード生成のランタイムライブラリを「マルチスレッド」にして。

multi

「マルチスレッド DLL」のままだと VC9 ランタイムも配らなきゃいけなくなる。
7kb が 41kb に増えるけどこれで DLL 単体で配布できるようになる
VC++ が入っている環境だと普通に動くので忘れがちなんですよねココ。
追記おわり

stdafx.h の最後の行に下記を追記

#include <shellapi.h>

コード

#include "stdafx.h"

extern "C" __declspec(dllexport)
BOOL trash(LPCWSTR szFileName)
{
	SHFILEOPSTRUCT sfos;
	ZeroMemory(&sfos, sizeof(SHFILEOPSTRUCT));
	wchar_t szOpFile[1024];
	wcscpy_s(szOpFile, 1024, szFileName);
	szOpFile[wcslen(szOpFile) + 1] = L'?0';
	sfos.hwnd = NULL;
	sfos.wFunc = FO_DELETE;
	sfos.pFrom = szOpFile;
	sfos.fFlags = FOF_SILENT | FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
	if (!SHFileOperation(&sfos))
	{
		return TRUE;
	}
	return FALSE;
}

trash.zip

DllMain を書いて Visual Studio 2008 でビルドしたら警告になった。
分離されているのか、targetver.h といい親切なのか余計なお世話なのか。

細かいことは→の「APIで学ぶWindows徹底理解」に書いています。
ちなみに私が買ったこの本はもう読み直ししすぎてボロボロです。

後はそのままビルドで DLL の完成。
Python.exe があるディレクトリに trash.dll をコピーします。

exp

ここまでくれば python からは毎度のように ctypes を利用して

import ctypes

dll = ctypes.windll.trash
if dll.trash("C:\\Python30\\gomi.txt"):
    print("ok")
else:
    print("miss")

こんな感じであっさりゴミ箱へ捨てられます。
2.* ではファイル名を UNICODE にするのをお忘れなく。
どうしても Python でやらなきゃいけない場合以外は VC++ で作ったほうが(略

g_file_trash ってのがあった

何を今頃気がついた。
Eye of GNOME って Delete キーで「ゴミ箱へ移動」ができるんだね。

sakura241

これは…早速ソースコードを拝ませてもらわなきゃ、ダウンロード。
このポイントだけ知りたいんだから GPL 関係は大丈夫だろう。
というか Y901x はオープンソースだし。

Eye of GNOME

とにかく g_file_trash なんていう関数を使えばいいと解った。
しかしスゲェ、ゴミ箱に入れられるかどうかチェックして g_file_delete と振り分けている。
標準アプリはやはりこういう部分をキチンと考えて作っているんだなと関心する。

コレってやはり Gnome てか Nautilus に依存するのかな?
でもそんなの関係ねぇ(古い…最近マジでテレビ見ないし
つーか Y901x は D&D 処理自体から Nautilus に依存だ、わっはっはシラネ!

それよりこれって Python バインディングではどう書くのだ?
海外を探してもなーんにも見つからないんだが。

思いつくかぎりのワードで探して gio なんてモジュールがあると解った。
後は dir(gio) で gio.File を見つける、どうやらコレっぽい。

gio

あぁやっと見つかった。
何かもの凄い無駄なことをしているような気がしなくもないが私はいつもこんなだ。
ということで実験で書いてみたコード。

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

import gtk
import gio
import urllib
import os.path

class TrashWin(gtk.Window):
    """
        ドロップされたファイルをゴミ箱に捨てる
    """
    def __init__(self):
        gtk.Window.__init__(self)
        # D&D の準備
        dnd_list = [("text/uri-list", 0, 0)]
        self.drag_dest_set( gtk.DEST_DEFAULT_MOTION |
                            gtk.DEST_DEFAULT_HIGHLIGHT |
                            gtk.DEST_DEFAULT_DROP,
                            dnd_list, gtk.gdk.ACTION_MOVE )
        self.connect("drag_data_received", self.on_drop)
        # いつもの処理
        self.connect("delete-event", gtk.main_quit)
        self.resize(320, 150)
        self.show_all()

    def on_drop(self, widget, context, x, y, selection_data, info, time):
        drops = selection_data.data.split("\n")
        for drop in drops:
            name = urllib.unquote(drop)[7:-1]
            if os.path.isfile(name):
                # ゴミ箱へ Go!
                obj = gio.File(name)
                obj.trash()

if __name__ == "__main__":
    w = TrashWin()
    gtk.main()

こんなにアッサリ作れてしまった…例外や失敗の処理無しならたったの二行。
trash メソッドの引数は不要みたい、成功すると True が帰ってくる。

つーことで早速 Y901x に入れて更新!
ボタンも真似させてもらった、set_default_response で OK ボタンが選択できるのね。

Eye of GNOME プラグインは面倒

Eye of GNOME でリネームプラグインを作る。
って書いたけど本当に作れるんかいな?

Gedit/Plugins – GNOME Live!
EyeOfGnome/Plugins – GNOME Live!

gEdit とは扱いが随分違うなぁ… HowTo も何もない、勘で作れと?

Eye of GNOME Reference Manual

これ Python にバインディングされているのだろうか?

EyeOfGnome – SunagaLab

以前貼った所をよく見ると window.get_image() メソッドが使えているからできるのだろう。
ただ、9.04 付属の 2.26.1 はこの機能が標準装備、進化って悲しいなぁ。
他の Python への変換は勘でなんとかなると思う、今更 C で作りたく無いよ。

とにかく実際に書いてみるのが一番早い、とりあえず Plugins ページ一番下にあったコードは動いた。
次は gEdit プラグインを作ったのと同じように MessageBox を出すのを作って試す。

っっって

何これ、Eye of GNOME ってプラグインから例外を出すと終了してくれない!
端末から eog で起動して終了しなかったら Ctrl+C で強制終了さなきゃやってられん。
GUI アプリでコレをやるとは思いもしなかった。

eogdebug

2 と出ているのは debug 用でどこまで動いたかを print しているだけだから気にしない。
最初それが解らなくて再起動やログアウトをやるという無駄なことをしてしまった。

こんなことをやっている間に気がついた。
Ubuntu 9.04 って Ctrl+Alt+BackSpace で X の再起動ができなくなっている!

Ubuntu 9.04 Beta ctrl+alt+backspaceを有効にする。

$ sudo apt-get install dontzap
$ sudo dontzap -d

しなきゃいけないのね、何故わざわざ無効にする必要があったのか理解できない。
おいおい、そんなことをしている間に今日が終わっちゃう。
はたしてこの計画は進むのだろうか?

覚書ページをなんとかしたい

Y901x 0.1.3 公開しました。

結局トグルボタンとラジオボタンの同期は自前で行った。
どうやったかはソースコードを見てください、我ながらナイスなシグナルの逃し方だ。
本当はラジオボタンも同じメニュー選択で解除にしたいけど一般的な動作じゃないし。

boko

ツールバーにしてみたら上のようにボッコリするのと右寄せができないので気に入らなかった。
ソースコードにコメントアウトして残しています、XML のトコも外してね。

まだやることはあるけど、とにかくこれでしばらくは落ち着けるかもしれない。

プレイヤーが作りたいというより PyGtk で何か作ったものを公開したい。
Python で GUI アプリが簡単に作れ環境もデフォルトで揃っているコトを知らない人が多すぎる。
ウチへの検索ワードにヤケに mono が多い理由はソレだと思うので知ってもらいたい。
という感じでやっているのであまり複雑にしたくないし。

つか、そろそろ覚書ページをなんとかしたいんだが今やっているコトを解説は難しいぞ。
GtkUIManager はどう考えたってプログラミング初心者には敷居が高いんだが…
恐ろしく楽ができるウイジェットだけど事前知識がかなり必要になる。

かと思えば Glade もとても初心者には勧められないようなシロモノになっちまった。
個別ウイジェットの解説から始めてゼロから作り直ししたほうが良さげな感じ。

それはそうと、いいかげんに違うアプリを作りたいものだ。
Y901x のリネーム機能を Eye of GNOME のプラグインにしようかと企んでいる。
需要はシラネ、本日はお知らせのみ。