Python」タグアーカイブ

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 に期待で済ませることにする…

GdkPixbuf.Pixbuf.new_from_xpm_data

いつのまにか PyGI から

GdkPixbuf.Pixbuf.new_from_xpm_data(str)

が使えるようになっていた。

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

from gi.repository import Gtk, Gdk, GLib, GdkPixbuf

ICON = [
"32 32 3 1",
" 	c None",
".	c #000000",
"+	c #FFFFFF",
"                                ",
"   ............                 ",
"   .++++++++++.                 ",
"   .++++++++++. ......          ",
"   .++++++++++. .++++.          ",
"   .++++++++++. .++++.          ",
"   .++++...+++. .++++.          ",
"   .++++....... .++++.          ",
"   .++++.       .++++.          ",
"   .++++.       .++++.          ",
"   .++++.       .++++. ......   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. ......   ",
"   .++++.       .++++.          ",
"   .++++.       .++++. ......   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++....... .++++. .++++.   ",
"   .++++...+++. .++++. .++++.   ",
"   .++++++++++. .++++. .++++.   ",
"   .++++++++++. .++++. .++++.   ",
"   .++++++++++. .++++. .++++.   ",
"   .++++++++++. .++++. .++++.   ",
"   ............ ...... ......   ",
"                                "]


class XpmWin(Gtk.Window):
    """
        XPM Data Read
    """
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("delete-event", Gtk.main_quit)
        # Icon as XPM data
        pixbuf = GdkPixbuf.Pixbuf.new_from_xpm_data(ICON)
        image = Gtk.Image.new_from_pixbuf(pixbuf)
        # ini
        self.add(image)
        self.show_all()

XpmWin()
Gtk.main()

xpmdata

Lubuntu 12.10 でも動くじゃないの。

ちなみに XPM 画像は中身はテキストデータです。
Gimp で画像を XPM にエクスポート(拡張子を xpm に指定する)してテキストエディタで開き上記のように Python の list 中に {} の中身をコピペすればどんな画像もイケる。
ただしテキスト化するのでサイズが巨大になります、アイコンサイズが限界かと。
eog や Shotwell では変換できないのね。

まあとにかく。
前回のクリップボードと合わせコレで clipolix を GTK3 化できる。
早速 GTK3 化してみると Fedora 18, Lubuntu 12.10 共問題なく動作した。

trayicon

のだが。。。

実は Fedora 18 にしてから clipolix はまったく使っていない。
メッセージトレイが GNOME 3.6 で改悪され恐ろしく使いにくくなったので。
マウスカーソルを下端に置いてもラグがあるし出てこない場合も多々ある。

ついでにこのアプリは Unity 初期状態では動かないと今頃知った。
即 Lubuntu に変更してしまったし、月刊 10 程度のアプリだしまあ。

【Ubuntu】 Unityをもっと使いやすく強化する方法 ? Libre Free Gratis! | Libre Free Gratis!

gsettings set com.canonical.Unity.Panel systray-whitelist "['all']"

でイケた。
つかマジで色々と糞だな Unity って、何故使っている人がいるのだ?

とにかく Fedora で使いにくいのはなんとかしたいのだが。
いっそ Gnome Shell エクステンションに変更とかも考えるが…
そうすると GNOME 3 でしか動かないし、Ubuntu には Gjs が入っていないし。

駄目だ、良い案が思い浮かばない。
次の Fedora と Ubuntu に期待して様子見という名の放置かな。

GtkClipboard in PyGI

GtkClipboard を PyGI で試したら PyGtk と少し違っていた。
違うというより C と同じになったというほうが正しいか。

PyGtk

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

import gtk

class ClipPyGtk(gtk.Window):
    """
        PyGtk(GTK2) Version
    """
    def __init__(self):
        """
            Copy the label of the button text
        """
        gtk.Window.__init__(self)
        self.connect("delete-event", gtk.main_quit)
        button = gtk.Button("Copy to the Clipboard in PyGtk")
        button.connect("clicked", self.on_button_clicked)
        self.add(button)
        self.show_all()

    def on_button_clicked(self, widget):
        """
            Very easy.
            gtk.Clipboard(display=gtk.gdk.display_get_default(),
                          selection="CLIPBOARD")
        """
        text = widget.get_label()
        clipboard = gtk.Clipboard()
        clipboard.set_text(text)

ClipPyGtk()
gtk.main()

PyGI

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

from gi.repository import Gtk, Gdk

class ClipPyGI(Gtk.Window):
    """
        PyGI(GTK3) Version
    """
    def __init__(self):
        """
            Copy the label of the button text
        """
        Gtk.Window.__init__(self)
        self.connect("delete-event", Gtk.main_quit)
        button = Gtk.Button.new_with_label("Copy to the Clipboard in PyGI")
        button.connect("clicked", self.on_button_clicked)
        self.add(button)
        self.show_all()

    def on_button_clicked(self, widget, data=None):
        """
            Like a C.
            gtk.Clipboard() to Gtk.Clipboard.get_for_display().
            There is no default arguments.
        """
        text = widget.get_label()
        display = self.get_display() # or Gdk.Display.get_default()
        clipboard = Gtk.Clipboard.get_for_display(display, Gdk.SELECTION_CLIPBOARD)
        clipboard.set_text(text, len(text)) # or set_text(text, -1)

ClipPyGI()
Gtk.main()

PyGtk では gtk_clipboard_get_for_display() を gtk.Clipboard() に割り当てて更にデフォルト引数を独自に用意していたってことみたい、本当に楽させてもらっていたんだなと。

PyGI は set_text に文字列のバイト長指定も必要、実は -1 でいいのだけど。
Python3 だと文字列が UCS-4 なのでエラいことになるから -1 にしよう。
うーん Python らしくないと思ったけど Vala も確認したら同じだった。
Gtk.Clipboard ? gtk+-3.0

Gtk.Clipboard.get() との違いがイマイチ解らない。
しかしキャストや破棄コードは不要とはいえ随分書くことが増えたものだ。