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 のプラグインにしようかと企んでいる。
需要はシラネ、本日はお知らせのみ。

ラジオメニューとトグルボタンの同期

Y901x 0.1.2 公開しました。
こんな Windows 用のノリでやっていても良いものかと思い始めた今日この頃。

っっって…指定倍率変更の計算が間違えているのに今気がついた!
せっかくまとめて listbox クラスにしたのにセパレータサイズを足していた。
あーあ明日もごまかすために更新だ、更新が特定期間に集中する原因はコレです。

ところで。

ラジオメニューとトグルボタンは UIManager から同期させられないっぽい。
と以前書いたけどツールバーならあっさりできるようで。

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

import gtk

ui_str = """<ui>
    <menubar name="MenuBar">
        <menu action="Rep">
            <menuitem action="non"/>
            <menuitem action="one"/>
            <menuitem action="all"/>
            <menuitem action="rdm"/>
        </menu>
    </menubar>
    <toolbar name="Toolbar">
        <toolitem action="one"/>
        <toolitem action="all"/>
        <toolitem action="rdm"/>
    </toolbar>
</ui>"""

class BtnBox(gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self)
        #
        # GtkUIManager 作成
        self.uimanager = gtk.UIManager()
        #
        # GtkActionGroup 作成
        self.actiongroup = gtk.ActionGroup("sasakimamenu")
        #
        # GtkAccelGroup を得てウインドウに突っ込む
        # 何もグループを作らなくてもコレやらないと後のアクセラレータ指定が効かない
        accelgroup = self.uimanager.get_accel_group()
        self.add_accel_group(accelgroup)
        #
        # GtkActionEntry を作成して突っ込む
        # 得にグループにしないものはココでまとめて作成
        # name, stock_id, label, accelerator, tooltip, callback
        self.ac0 = [("Rep", None, "リピート(_R)")]
        self.actiongroup.add_actions(self.ac0)
        #
        # GtkRadioActionEntry の List を作成
        # name, stock_id, label, accelerator, tooltip, value
        self.ac1 = [("non", None, "無し", "0", "無し", 0),
                    ("one", None, "シングル", "1", "シングル", 1),
                    ("all", None, "オール", "2", "オール", 2),
                    ("rdm", None, "ランダム", "3", "ランダム", 3) ]
        # GtkRadioAction を突っ込む
        # entries, value=0, on_change=None, user_data=None
        self.actiongroup.add_radio_actions(self.ac1, 0, self.on_loop_change)
        #
        # GtkUIManager の更新
        self.uimanager.insert_action_group(self.actiongroup, 0)
        self.uimanager.add_ui_from_string(ui_str)
        self.uimanager.ensure_update()
        # menubar を抜き出す
        menubar = self.uimanager.get_widget("/MenuBar")
        # toolbar を抜き出す
        toolbar = self.uimanager.get_widget('/Toolbar')
        # pack
        vbox = gtk.VBox()
        vbox.pack_start(menubar, False)
        vbox.pack_start(toolbar, False,False)
        self.add(vbox)
        self.connect("delete-event", gtk.main_quit)
        self.resize(320, 150)
        self.show_all()
        self.val = 0

    def on_loop_change(self, action, current):
        # コレは無理だった
        num = action.get_current_value()
        if num == self.val:
            action.set_current_value(0)
        else:
            self.val = num

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

repeat

得に何をするわけでもなく action を共通にすれば同期してくれるわ。
だけどアクティブなボタンを再度押すとオフにするといった処理は無理か。
ボタンオブジェクトを抜いて clicked シグナルを処理すればよさげだけど。

コレ上手く使えないかな?いまここ。

Linux のゴミ箱

Y901x 0.1.1 バグ修正を公開しました。
ココにリネーム方法を書いたのに少し書き換えた私がアホだった…

ところで

何を今頃気がついたが os.remove でファイル削除するとゴミ箱に入らずに消滅する。
そういえば UNIX には元々ゴミ箱なんて無かった、つーか rm で削除すると消滅ですがな。

何か Nautilus に慣れてしまってゴミ箱に入るものだとうっかりしていた。
Windows ShellAPI の SHFileOperation みたいな方法は無いのだろうか?

ちなみに Ubuntu のゴミ箱に捨てたファイルは以下にある。

~/.local/share/Trash/files

しかし調べてみるとディストリビューションによって下記もあるようで。

~/.Trash
~/.Trash-0

ゴミ箱 – Wikipedia

規格の範囲でファイルマネージャ毎に決めているっぽい。
FreeDesktop.org での規格なら xdg-trash とか、無いか…

Ubuntu — Details of package xdg-utils in jaunty

ついでに、メニューのインストールには xdg-desktop-menu を本当は使わなきゃいけないのね。
make や dpkg は勝手にそれをやってくれるということでいいのかな。
Y901x のインストールスクリプトは言うまでもなく直で突っ込んでいる、知らなかったよ。
Ubuntu 限定に近いから別にイイんだが真似しないほうがいいよあの方法は。

Ubuntu日本語フォーラム / HOWTO: CLIからゴミ箱を使う

こういうのがあるのか。
端末からゴミ箱利用はかなり微妙だけど保険にはなるかも。
間違えて Blog の画像を全部消したコトがある私はそう思う。
でもレンタルサーバーで FTP ソフトを使ったら全く意味が無いとも。

コレをインストールしてもらえば…だからソレはやりたくない。
よし決めた、面倒だから当面は消滅のままでいいや!これが私の(略

GTK+ はキーの長押しを認識できないようで

Y901 というアプリは上下矢印キーの長押しでリスト選択位置の移動のみを行っていた。
キーを離し WM_KEYUP メッセージを捕まえた所で選択位置のファイルを再生開始していた。
当然 Y901x でもそうしたいわけだ。

しかし…とにかくコレを動かして上下どちらかの矢印キーを押しっ放しにしてみる。

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

import gtk

class KeyUpDown(gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self)
        self.tv = gtk.TextView()
        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        sw.add(self.tv)
        self.add(sw)
        # GDK イベントの有効化を行っておく
        self.set_events(gtk.gdk.KEY_PRESS_MASK | gtk.gdk.KEY_RELEASE_MASK)
        self.connect("key_press_event", self.on_key_press)
        self.connect("key_release_event", self.on_key_release)
        self.connect("delete-event", gtk.main_quit)
        self.resize(300, 400)
        self.show_all()

    def on_key_press(self, widget, event):
        if event.keyval == 65362 or event.keyval == 65364:
            buf = self.tv.get_buffer()
            s = "押した\n"
            it = buf.get_end_iter()
            buf.insert(it, s, len(s))

    def on_key_release(self, widget, event):
        if event.keyval == 65362 or event.keyval == 65364:
            buf = self.tv.get_buffer()
            s = "離した\n"
            it = buf.get_end_iter()
            buf.insert(it, s, len(s))

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

updown

つまり key_press_event シグナルは必ず key_release_event シグナルと交互に発生する。
Windows のように WM_KEYDOWN イベントのみが起こるというわけではないようだ。
キーを離し WM_KEYUP メッセージを捕まえるように key_release_event を…

できない!

まいった、何か方法を見つけるまで今までどうり一つ上下移動のみにするしかない。
つーかこの現実が解るまで「あれぇ?なんで???」と苦しんだ私であった。

それとラジオメニューとトグルボタンは UIManager から同期させられないっぽい。
しかたがないのでリピート用のトグルボタンを排除するという暴挙で解決!
パッと見て状態が解ればいいんだからステータスバーに表示、これが私のクオリティ。

追記、長押し判定する方法がありました
GTK+ Cancel Long Keypress | PaePoi