Python」タグアーカイブ

gtk.Widget.allocation.height

4/18 に gtk.Widget.allocation.height が表示後でないと取得できないと書いた。
で、フルスクリーンコントローラを一旦表示するまで 50px という仮に値を入れてごまかした。

いや、よく考えたらフルスクリーンコントローラ自体のサイズを得る必要は無かった。
フルスクリーンにする前に既に toolbox, statusbar は表示されているのだから。

ということでやってみたら縦サイズが 1 に、あれ?
そうか、parent 変更すると property が消えて非表示扱いになるんだった。

ということはオブジェクト作成側で調べてパラメータで渡す…
のコードを一度書いてみたけれど何故か気に入らない、なるべくパーツ側で処理したい。
もっと上手い方法は…と考えてみたらこうすりゃいいじゃんと思いついた。

class CFullCtrl(gtk.Window):
    """
        Full Screen Controrer
    """
    def __init__(self, parent, box, parent2, bar):
        """
            GtkWindow at GTK_WINDOW_POPUP
        """
        gtk.Window.__init__(self, gtk.WINDOW_POPUP)
        # memory pointer
        self.p1 = parent
        self.p2 = parent2
        self.box = box
        self.bar = bar
        # Get Desktop Window Geometry
        root = gtk.gdk.get_default_root_window()
        x, y, w, h, d = root.get_geometry()
        # move and resize
        self.set_size_request(w, -1)
        self.y_pos = h - box.allocation.height - bar.allocation.height
        self.move(0, self.y_pos)
        # Change parent
        vbox = gtk.VBox()
        self.box.reparent(vbox)
        self.bar.reparent(vbox)
        vbox.show_all()
        self.add(vbox)
        self.connect("destroy", self.on_destroy)

    def on_destroy(self, widget, event=None):
        """
            Return Parent
        """
        self.box.reparent(self.p1)
        self.p1.set_child_packing(self.box, False, True, 0, gtk.PACK_END)
        self.bar.reparent(self.p2)
        self.p2.set_child_packing(self.bar, False, False, 0, gtk.PACK_START)
        return True

そうだよ、parent 変更する前に値を調べておけばいいじゃないの。
後はフルスクリーン切り替え時に作成や削除をやればつじつまが合うじゃないか。

def change_fullscreen(self):
    if self.fullscreen:
        self.fullscreen = False
        self.w.window.unfullscreen()
        self.w.unfullscreen()
        self.fullobj.destroy()
        self.fullobj = None
        self.w.resize(self.fullsize[0], self.fullsize[1])
    else:
        self.fullscreen = True
        cx, cy = self.w.get_size()
        self.fullsize[0] = cx
        self.fullsize[1] = cy
        self.fullobj = CFullCtrl(
                self.hbox_ctrl,
                self.toolbox,
                self.vbox_main,
                self.statusbar
            )
        self.w.fullscreen()
        self.w.window.fullscreen()

こんな感じの関数を作ればいいしパラメータも増やさずにすんだ。
しかしよく考えたらパーツ作成のパラメータは本体ポインタのみでいいような気がしてきた。
アトリビュートやメンバ関数はそのポインタから得ることができるのだから。

class CStatusBar(gtk.VBox):
    def __init__(self, owner, arg):
        self._win = owner.w
        self._owner = owner
        gtk.VBox.__init__(self)

みたいな感じで、後は self._owner 経由で本体 class のメンバを参照できる。
というか本体のコードをなるべく少なくしたいのですよ、後々のメンテナンスを考えると。
ラムダ式とかは数学系の人は好んで使うようだけどメンテが多いアプリでは怖くて使えませんわ。
ちなみに Windows 用の Y901 最終版は本体コードだけで九千行、この手では短いほうだ。

他、再生停止でマウスカーソルを表示させるのを忘れていた。
ということで Y901x-0.2.5 公開、作った本人以外に使っている人がいるかどうか知らない。

gtk.gdk.Display.get_pointer

Y901x-0.2.3 は大失敗だった。

motion-notify-event で処理しているから VideoArea 領域を外れたら認識しない。
つまり 16:9 の動画を 16:10 ディスプレイで表示した場合とかでは下に黒帯が出る。
その黒帯部分では領域外なので motion を認識なんてするはずがない。
つまりフルスクリーンでのコントローラは出ないわけだ。

んー Cinema では WM_MOUSEMOVE で計算してやっていたんだけどなぁ。
GTK+ ではレイアウタなので超ややこしいし、WindowsAPI の GetCapture みたく…
ってソレどうやるの?面倒なので Timer で処理するようにしよう。

# GetCursolPos
a, x, y, b = gtk.gdk.display_get_default().get_pointer()

で x と y にスクリーン座標で現在のマウスカーソル位置が取得できるようだ。
a は gtk.gdk.Screen、b は Shift や Ctrl の Mask、ここでは使わないのでダミー。
この値を元に処理したらとりあえずディスプレイより横長動画でも処理できた。

せっかくタイマー処理でマウスカーソル位置を取得しているんだからカーソル消去も。
只の Y901 からの伝統で通常時でも画面上は静止状態マウスカーソルを一秒後に消す。
っっって、GTK+ で WindowsAPI の ShowCursor(FALSE); ってどうするの?

gtk.gdk.Cursor

の下のほうに普通に書いていた、つまり自分で作らないといけないんだね。
これが解れば処理方法自体は同じなので Python コードにて書き換えるだけだ。
ということで細かい処理は Y901x のコードを見てもらうとして簡単に。

class Y901window(dbus.service.Object):
    def __init__(self, bus_name):
        # ...
        self.mousepoint = [0, 0]
        self.invisiblecount = 0;
        # Create invisible cursor
        pixmap = gtk.gdk.Pixmap(None, 1, 1, 1)
        color = gtk.gdk.Color()
        self.noncursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 0, 0)

省略しすぎかな、とにかくタイマーで

    def on_timer(self):
        # ...
        # GetCursolPos
        a, x, y, b = gtk.gdk.display_get_default().get_pointer()
        # FullScreen at Controler
        if self.fullobj:
            if self.fullobj.y_pos < y:
                self.fullobj.show_all()
            else:
                self.fullobj.hide()
        # Cursor Auto Invisible
        if self.mousepoint[0] == x and self.mousepoint[1] == y:
            if self.invisiblecount < 5:
                self.invisiblecount += 1
            else:
                self.video_window.window.set_cursor(self.noncursor)
        else:
            self.invisiblecount = 0;
            self.mousepoint[0] = x
            self.mousepoint[1] = y
            self.video_window.window.set_cursor(None)
        # return True is Repeat
        return self.is_playing

と時間表示とフルスクリーンコントローラとカーソル消去を全部やってみた。
とりあえずこれでつじつまが合っている、かなり Windows 用 Y901(Cinema) を再現できた。
ということで Y901x-0.2.4 公開しました。
やっぱり全然人増えねぇ、Windows 用のようにいかないわな。

gtk.Widget.reparent

いいかげんに Y901x もフルスクリーンでコントローラを出すようにしよう。

方法は色々あるんだが、一番簡単なのは show() hide() だけで済ませる方法。
しかしこれではムービー画面が拡大縮小されてみったくない。
WMP12 や Cinema のように浮き上がらせて表示させる、の方法は解らない…

オーソドックスに下からヒョッコリ出てくる方法にでもとりあえずやっとこう。
これも方法が沢山あるけど別ウインドウを作って被せるのが一番簡単だろう。

とりあえずコントローラ用の gtk.Window を gtk.WINDOW_POPUP 指定で作成。
gtk.Widget の reparent() メソッドで parent の gtk.Box をコッチに変更。
unparent() set_parent() を使うとうまくいかなかった、つか実態が消滅するんだが。

parent を変更すると property が消える、パッキング情報は Box 側が持つんだから当然か。
.NET Framework の WPF なら子オブジェクト側が持っているんだよね、色々あってややこしい。
なので set_child_packing メソッドでパッキング情報を追加するのを忘れずにと。

んでディスプレイサイズを取得して…ってどうやるのだ?

ぱぇぽぃ2 ? Blog Archive ? デスクトッププロパティ

なんだ、自分でやっていたや。
でも Python の勉強を始めたばかりな頃にやったことなんで効率悪すぎる。
wnck を使えば簡単だけど KDE 対応でまた…
ということで、何か他の方法は無いか探したら恐るべきコードを発見。

pygtkだけ でスクリーンショットをとる

何コレ、たったこれだけ(八行)で本当に全画面スクリーンショットアプリが完成!
PyGtk 恐るべし、gnome-screenshot が強力すぎて自分で作ろうとは思わないけど。

つーか画面サイズを調べるのって get_geometry() メソッドを呼ぶだけだったのか。
やはり知識が無いと無駄なコードを書くことを自分で証明した。

とにかくコレでディスプレイサイズがゲットできたので作ってしまえだ。
表示後でないと gtk.Widget.allocation.height が取れないのをどうするか悩む。

ごまかしたらイマイチなコードになっちゃった、けど開発途中なんだからいいや。
後マウスカーソルを消す処理もいれたいけど出したいからこのまんま出してしまえ(ぉい!
具体的なコードは Y901x の common.py の CFullCtrl class を見てくれ。
更新毎に少しずつマトモなコードになる、多分。

ということで Y901x-0.2.3 を公開しました、本サイトからぞうぞ。
listbox 表示状態を記憶せず毎回表示していたのも修正した、今まで何故気がつかない…

だから Linux 用を作ったところで全然金にも人気にもならないなんて解っているよ。
いいじゃないか、作りたいんだから。

Python2.6 format

知らなかったけど Python 2.6 から format メソッドが使えるんだね。
3.0 系だけだと今まで思っていたよ、IronPython 2.6 も同様。

"{0}: {1}+{2}={3}".format("calc", 1, 2, 1+2)

"%s: %d+%d=%d" % ("calc", 1, 2, 1+2)

のように値に対する書式指定がいらない、くらいしかメリットは無いけど。

引数の順番が変更できたり同一の値を参照…なんてやる人少ないだろうし。
少なくとも C# からプログラミングに入った人なら判りやすいのではないかと。
今は「どっちでもいい」なので好きなほうで書けばいいわけだ。
ただ書き方ごときにあーだこーだなら Ru…(以下略

しかし春の陽気のせいかヤル気が出ない…
Y901w はもう現行 Cinema のまんまでいいじゃないかとか…
とはいえ今になってコードを見ると自身で寒いので全部書き直したいし…
なんんてやっていたら全然進まねぇや、そろそろ Windows 用を何か作らないと干されそう。

get_user_special_dir

Linux でホームに作成されるデフォルトディレクトリ名は

~/.config/user-dirs.dirs

で指定及び確認ができることは大半の人が知っているだろう。
自分の都合で名前変更しても自動で追従する嬉しいのか迷惑なのかよく解らな(以下略

Windows も準拠してくれれば嬉しいのに…
というのは置いておいて英語表記のデフォルト名は

/etc/xdg/user-dirs.defaults

で私が知るかぎりでは確認できます、全部の Linux がそうなのかは知りません。

ということで。

アプリを自分で作るとデフォルトディレクトリ名を探したくなる場合がある。
自身が使う範囲のみであれば決め打ちでいいけど公開する場合は考える必要がある。
user-dirs.dirs を自己解析すればとも思うけどこの位置さえ決め打ちでいいのだろうか?
画像関連アプリで画像ファイルを保存しているだろう場所を指定みたいなくらいしか(以下略

glib Functions

glib に get_user_special_dir なんてメソッドがある。
コレを使えば PyGtk の GUI アプリでユーザー指定のディレクトリが見つけられそうだ。
get_user_cache_dir メソッドも後々で使いそうだし覚えておいたほうがいいかなと。

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

import glib

xdg_default = (
    "Desktop",
    "Documents",
    "Download",
    "Music",
    "Pictures",
    "Public",
    "Templates",
    "Videos"
    )

user_conf = (
    glib.USER_DIRECTORY_DESKTOP,
    glib.USER_DIRECTORY_DOCUMENTS,
    glib.USER_DIRECTORY_DOWNLOAD,
    glib.USER_DIRECTORY_MUSIC,
    glib.USER_DIRECTORY_PICTURES,
    glib.USER_DIRECTORY_PUBLIC_SHARE,
    glib.USER_DIRECTORY_TEMPLATES,
    glib.USER_DIRECTORY_VIDEOS
    )

for i in range(len(xdg_default)):
    print "%s: %s" % (xdg_default[i], glib.get_user_special_dir(user_conf[i]))

うん、これでいいんじゃない。
とにかくコレでフルパスが得られるので処理が簡単。
自身で何も指定していないなら None が戻るので処理が簡単。
よし、これで Y901x の初期選択ディレクトリを(理由はソレかい…

私が付けている名前を晒しているけど気にしない
動画の保存先名デフォルトは Videos より Movies のほうがイイと思うんだけどなぁ…