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

File List in Numeric Order

よく見たら TreeView にファイルリスト配置までに物凄く無駄が多かった。
os.listdir でファイルリストを作成し更に隠しファイルを取っ払って新たに作成。
ディレクトリ名までリストに含めたソートを行い配置直前にディレクトリを弾く。

なんだこの非効率さは、実用上では問題ない速度とはいえ流石に書き換えたいわ。
当時は os.listdir 以外でファイルリストを作る手段を知らなかったわけで。

今なら Gio を利用して自力でファイルリストを作れる。
ディレクトリと隠しファイルを除き、数値優先ソートまで終わったリストを戻す関数を作ればいいかな。

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

from gi.repository import GLib, Gio

def get_file_numsort_list(dirname):
    """
        param dirname: Directory Full Path Name
        return: List in Numeric Order
    """
    files = []
    d = Gio.file_new_for_path(dirname)
    enum = d.enumerate_children(
            Gio.FILE_ATTRIBUTE_STANDARD_TYPE,
            Gio.FileQueryInfoFlags.NONE,
            None )
    for info in enum:
        if info.get_file_type() == Gio.FileType.REGULAR:
            s = info.get_name()
            if not s.startswith("."):
                if not s.endswith("~"):
                    files.append(s)
    files.sort(lambda x, y : cmp(GLib.utf8_collate_key_for_filename(x, -1), GLib.utf8_collate_key_for_filename(y, -1)))
    return files

イマイチな気もするけど予定していた動作にはなった。
G_FILE_TYPE_REGULAR 判定ならディレクトリではないと解る。
隠しファイルは自力判定、not を使うと or の動作がおかしかったので階層に。

体感速度は、全然変わらないなやっぱり。

それと。
Gstreamer の Volume 調節は何故か valadoc で見つけた。

Gst.Audio.stream_volume_convert_volume ? gstreamer-audio-1.0

Namespace: Gst.Audio ということだが Gst のアトリビュートには無い。
Python では GstAudio を gir から import すれば使えるようだ。

from gi.repository import Gtk, Gst, GstAudio

class Prayer(Gtk.Window):
    ###
    # etc...
    ###
    def set_volume(self, value):
        if self.player.get_volume(GstAudio.StreamVolumeFormat.CUBIC) != value:
            self.player.set_volume(GstAudio.StreamVolumeFormat.CUBIC, value)

    def on_volume_value_changed(self, widget, event=None):
        self.set_volume(widget.get_value() / 100.0)

get_volume, set_volume は引数に GstStreamVolumeFormat が必要。
PyGtk, gst-0.10 では LINEAR からの変換が必要だったけど直でイケる。

Vala も少し勉強していて良かった!
というか、こんなにドキュメントが充実しているなら Vala で作ったほうがいいのかな。

初回再生時に上下が少し潰れる現象で現在詰まっている。
一度リサイズすれば直るのだが、0.3.9 と同じ処理をしているのに。
GtkAspectFrame ではなく自力でアスペクト比と配置調節をしたほうがいいのかな?

他細々、ということでココまでのバックアップ。
現状では Fedora 18 で Gst デコーダーを揃えた環境しか動かせないけど。
y901x-0.99.1.tar.gz

追記 @ 2013.04.24
多分コレで日本語環境なら当面は問題無いと思う、けど次 Ubuntu 公開まで様子見しますんで。
もっと弄くりたいこともあるにはあるけどメジャー更新は安定させるのが最優先なので。
GTK3, GStreamer 1.0 環境以外は弾くようにしました。
y901x-0.99.2.tar.gz
追記終わり

ついでに。

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

from gi.repository import GLib

s = "/home/oyaji/エロ画像/乳.png"

# ディレクトリ名
print GLib.path_get_dirname(s)
# ファイル名のみ
print GLib.path_get_basename(s)
# 絶対パスチェック
print GLib.path_is_absolute(s)
# URI に変換
u = GLib.filename_to_uri(s, None)
print u
# パス名に戻す
print GLib.filename_from_uri(u, None)
# フルパス作成(区切り文字の有無を自動調節)
print GLib.build_filenamev(["/home/oyaji/", "/エロ画像", "尻.png"])

なんだ GLib で日本語ファイル名もイケるんだ、os.path は使わなくていいじゃないの。
特に os.path.join と同じように使える g_build_filenamev は素晴らしい。
日本人の Python 屋って標準モジュールで止まっている人が多すぎだから少し違ったことをすると通っぽく見えて素敵かもよ。

Ubuntu 13.04 gst

第270回 Ubuntu 13.04とGNOME:Ubuntu Weekly Recipe|gihyo.jp … 技術評論社

どうやら Ubuntu 13.04 の Nautilus は 3.6 になるようだ。

ということは Ubuntu の GStreamer も 1.0 になるということだ!
Nautilus 3.6 は動画サムネイルに GStreamer 1.0 を使っている。

これは Y901x を早々に GStreamer 1.0 仕様に変更しなければ。
まだ 0.3.9 で動くからと PyGtk のまま放置のままもどうかと思うし。
作った本人、つまり筆者以外に使っている人はいないと思うけど。

Novacut/GStreamer1.0 – Ubuntu Wiki

大方はこのとおりに変更すればイケた。
playbin2 を playbin にするのを忘れないようにと。

しかし

playbin.get_property("uri") # All None

set_property(uri) は OK だが get は何をやっても None しか得られない。
既知のバグみたいなので修正を待つしかない、それまで別の手段で URI を保存しよう。

Gst.State.CHANGE_FAILURE に相当するものが見つからない。
PlayState 変更失敗はどうやって見分けるのだろう?

#self.p_position = self.player.query_position(gst.FORMAT_TIME)[0] # 0.10 PyGtk
self.p_position = self.player.query_position(Gst.Format.TIME)[1]  # 1.0 PyGI

ココでかなり苦しんだ、[0] だと bool 値だと気がつくのに時間が掛かった。
シークバーが全然動かなくて悩んだけどそういうことだった。

ボリューム変更の手段がいまだに解らない!
PyGst で gst.interfaces 以下の部分はどう変更になったのだろう?

で、
GStreamer とは関係ないところでも多々発見。

gtk.keysyms.Return が Gdk.KEY_Return と Gdk のアトリビュートになっていた。
gobject.timeout_add が GLib.timeout_add となったのも解り難い。

''' PyGtk
pixmap = gtk.gdk.Pixmap(None, 1, 1, 1)
color = gtk.gdk.Color()
blank_cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 0, 0)
'''
blank_cursor = Gdk.Cursor.new(Gdk.CursorType.BLANK_CURSOR)

透明マウスカーソルはこんなに簡単に作れるようになった、嬉しいぜ。
PyGtk でも実は同じような手段があったのかな?

何より一番困ったこと。

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

from gi.repository import Gtk, GdkPixbuf, Gdk

class CToolBox(Gtk.Box):
    """
        Inheritance GtkBox is HORIZONTAL
    """
    def __init__(self):
        Gtk.Box.__init__(self, Gtk.Orientation.VERTICAL, 0)
        self.pack_start(Gtk.Label("Orientation"), False, False, 0)
        self.pack_start(Gtk.Label("VERTICAL"), False, False, 0)

class Win(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("delete-event", Gtk.main_quit)
        self.add(CToolBox())
        self.show_all()

Win()
Gtk.main()

vertical

これができないみたい。
GtkVBox から継承ならイケるんだけど、この場合は下記みたくするしか無いかな…

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

from gi.repository import Gtk, GdkPixbuf, Gdk

class CToolBox(Gtk.Box):
    """
        OK
    """
    def __init__(self):
        Gtk.Box.__init__(self)
        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        vbox.pack_start(Gtk.Label("Orientation"), False, False, 0)
        vbox.pack_start(Gtk.Label("VERTICAL"), False, False, 0)
        self.pack_start(vbox, True, True, 0)

class Win(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("delete-event", Gtk.main_quit)
        self.add(CToolBox())
        self.show_all()

Win()
Gtk.main()

設定ダイアログは GtkTable を使っているので GtkGrid に書き換えだ。
面倒だから今度!

他にも何かあった気がするけど、気がついたら又今度書く。
とりあえずまだまともに動かないけど Blog にバックアップ。
もし明日筆者が死んでも誰かが続きをやってくれるのを期待して。
y901x-0.99.0.tar.gz

しかしやはり実際にアプリケーションを作ってみないと気がつかないことが多いと実感。
作った本人しか使わないと解っていても何か作り続けるといいことがある。

g_convert

最近の Gedit は Windows から持ってきた Shift-JIS のファイルを普通に読み込める。
ように思えますが実はチルダがバケる。

932

と秀丸で Shift-JIS 保存したものを Fedora に持ってくる。
ついでに iconv で CP932 及び SJIS 変換した例を下記に。

iconv

つまり Gedit は CP932 ではなく Shift-JIS から変換しているのですね。
Linux の持っていく場合は Windows 上で BOM 無し UTF-8 に変換しよう。
もし持ってきた後で気がついたら iconv で変換。

しかし天下の秀丸様でさえ CP932 を Shift-JIS なんて表記しているから困る。
Windows システムデフォルトのまま保存すると CP932 であるというのに。
この事実って Windows しか使えない人のほとんどが知らないという…

ということで。

Linux ユーザーにはお馴染みの iconv ですがプログラムから変換するにはどうする?
Python なら普通に文字コード変換関数があるけど Vala 等を使いたい時に困るので。

調べると、どうやら g_convert 関数で変換できるようだ。

Python

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

import sys
from gi.repository import GLib

try:
    result, contents = GLib.file_get_contents(sys.argv[1])
    if result:
        try:
            text, bytes_read, bytes_written = GLib.convert(contents, len(contents), "UTF-8", "CP932")
            print text
        except Exception, e:
            print "ConvertError: {0}".format(e)
except Exception, e:
    print "FileError: {0}".format(e)

Vala

using GLib;

public class Conv {
    public static int main(string[] args) {
        try {
            string contents;
            bool result = GLib.FileUtils.get_contents(args[1], out contents);
            if (result) {
                try {
                    string text = GLib.convert(contents, contents.length, "UTF-8", "CP932");
                    stdout.printf(text);
                } catch (GLib.ConvertError e) {
                    stdout.printf ("ConvertError: %s\n", e.message);
		            return 1;
                }
            }
        } catch (GLib.FileError e) {
		    stdout.printf ("FileError: %s\n", e.message);
		    return 1;
        }
        return 0;
    }
}

g_convert

こんな感じでいいみたい、Python でも Vala でも問題なく g_convert で変換できる。
Vala は例外処理を書かないとコンパイルで警告になるのが少し面倒だよね。
valadoc.org とニラメッコしなきゃ書けないよ。

g_file_get_contents

テキストファイルの一期読み込みに今まで Gio を利用していた。

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

from gi.repository import Gio

# Create GLocalFile
f = Gio.File.new_for_path("test.txt")
# load_contents(GCancellable)
result, contents, length = f.load_contents(None)
if result:
    print contents

のだけど g_file_get_contents という関数が GLib にあった。
File Utilities

コチラの関数なら GLocalFile を介さず一発で読み込み完了ができるみたい。
g_file_set_contents で書き込みも一発でイケるようだし便利そうだ。

ただ PyGI ではどう書く?
ということで実験。

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

import sys
from gi.repository import GLib

TEXT = """KAWASAKI
Ninja 250
Z250"""

# Text file Write
try:
    if GLib.file_test("write.txt", GLib.FileTest.EXISTS):
        print "'write.txt' is EXISTS"
        sys.exit()
    result = GLib.file_set_contents("write.txt", TEXT)
    if result:
        print "Write Success"
except Exception, e:
    print "Error @ {0}".format(e)
    sys.exit()

# Text file Read
try:
    result, contents = GLib.file_get_contents("write.txt")
    if result:
        print contents
except Exception, e:
    print "Error @ {0}".format(e)
    sys.exit()

g_file_set_contents は無条件で上書きしてしまうようです。
g_file_test 関数で存在確認を行ってから相応の処理を行ったほうがいい。

引数の GError は Python の例外として渡ってくるようです。

# Exception intentional
GLib.file_set_contents("/write.txt", TEXT)

のように root 権限位置に指定等を行うと例外が出力されることが解ります。

g_file_get_contents は存在しないファイル名指定なら例外になる。
戻り値を if で振り分ける必要は無いかも。

load_contents にある GCancellable というあまり必要を感じない指定も不要で簡単。
ストリーミング I/O で行う必要の無い少量の読み書きならコチラのほうが簡単ですね。

Python なんだから組み込みの open を使う人がほとんどなんだろうけど。
せっかく GLib が丸々使える環境なんだからもったいないじゃないか。

clipoli 2.0.0

よく考えたら半年以上もアプリの更新をしていなかった。
ということで前回の適用を行い clipolix を clipoli と名前を変えて更新!

せっかくなので PyGI 化だけでなく気になっていた部分をチマチマ。

・Windows 版と名前を変える必要は無かったということでで名前変更
・GNOME はドットファイルをヤメたいようなので ~/.config に設定位置変更
・GLib.spawn_command_line_async はチルダを展開しないので自力変換
・GTK+ 必須なのだから gvfs を遠慮なく利用

それと Python の open や subprocess ではなく全部 GLib, Gio で処理。
そうしておけば Vala,Gjs 等の gir を利用する他の言語からでも参考にできるはず。

例の Unity の糞みたいなパネル追加制限は以下のように回避

UNITY = "com.canonical.Unity.Panel"
APPNAME = "appname"

if UNITY in Gio.Settings.list_schemas():
    setting = Gio.Settings.new(UNITY)
    value = setting.get_strv("systray-whitelist")
    if not "all" in value:
        if not APPNAME in value:
            value.append(APPNAME)
            setting.set_strv("systray-whitelist", value)

GStrv は PyGI では list のごとく append で文字列を追加できるようです。
こんなにアッサリと制限突破が可能だしまったく無意味だと思う。
つか Unity のためだけにこんな処理を入れるのメンドイぞ!

ついでに。
GtkMenu って for-in 文で GtkMenuItem を取り出せるのね。

#! /usr/bin/python
# -*- encoding: utf-8 -*-

from gi.repository import Gtk

menu = Gtk.Menu()

for label in ("HAYABUSA1300", "ZZR1400", "VMAX"):
    menuitem = Gtk.MenuItem.new_with_label(label)
    menu.append(menuitem)

#for menuitem in menu.get_children():
for menuitem in menu:
    print menuitem.get_label()

menu.get_children() と結果は同じなのでそうバインドしているのだろう。
実際にアプリケーションを作ってみないと気がつかないことって多いなと。

ということで追加機能とかは何もない。
GNOME3 で使いにくいのは GNOME 3.8 に期待で済ませることにする…