g_filename_from_uri and GFile

iPhone と Linux の接続は AFC プロトコルで繋る。
この URI を Gio と GLib の関数でフルパスに変換してみる。

#!/usr/bin/env python3
 
from gi.repository import Gtk, Gdk, GLib, Gio
 
class DWin(Gtk.Window):
    def __init__(self):
        """
            DnD Window
        """
        Gtk.Window.__init__(self)
        self.connect("delete-event", Gtk.main_quit)
        # DnD
        dnd_list = Gtk.TargetEntry.new("image/jpeg", 0, 0)
        self.drag_dest_set(
                Gtk.DestDefaults.MOTION |
                Gtk.DestDefaults.HIGHLIGHT |
                Gtk.DestDefaults.DROP,
                [dnd_list],
                Gdk.DragAction.COPY )
        self.drag_dest_add_uri_targets()
        # GtkLabel
        self.label = Gtk.Label("Please drop your files")
        self.add(self.label)
        #
        self.show_all()
 
    def do_drag_data_received(self, context, x, y, data, info, time):
        """
            URI to FullPath
            Gio or GLib
        """
        uri = data.get_uris()[0]
        try:
            # GFile
            f = Gio.File.new_for_uri(uri)
            path = f.get_path()
            s = "{0}\n".format(path)
            # GLib
            afc = GLib.filename_from_uri(uri)[0]
            s += afc
        except Exception as e:
            # Error
            s += e.message
        self.label.set_text(s)
 
DWin()
Gtk.main()

seruria

一年で 8500yen しか課金していないのにセルリアを持っていてごめんよ!
いやそれは関係なくて、ウチ姫を知らないとワカンナイし。

g_filename_from_uri 関数は AFC の URI を変換できない。
この関数はファイルが存在するかどうかは関係ないからかな。

一手間増えても素直に GFile を使ったほうが良いようです。
実際にアクセスするか変換するだけかの違いがモロにでるのね。

ところで変換されたフルパスがナンジャコリャに見えるけど。

mount

普通にマウントされているんだなぁこれが。
なのに Shotwell ではインポートがエラーになるのは何故だろう?

まあ自分は Nautilus で DnD して保存で充分なんだけどne!

cairo RSVG

GtkPixBuf は SVG 画像をもそのまま扱えて普通に描写できる。
線や図形の描写 – L’Isola di Niente
上記コードで普通に表示できると確認できます。
しかし拡大すると…

airplane

eog は綺麗に引き伸ばしされているのに対し、コッチは超ギザギザ!
MComix で試してもギザギザ、Shotwell は表示すらできない。

eog ってショボイと見せかけて実はこんなに優秀だったのかよ…
ではなく。
どうすれば綺麗に表示できるか考えて調べて色々試してみよう。

ーーーーー

自前ソースがギザギザなのは少し考えれば当然だと解る。
なにせ svg を一度 Bitmap 化して引伸す工程にしているのである。
これではベクターデータである svg での曲線が滑らかという恩恵が無い。
結果 jpeg 画像等と何も変わらないギザギザになる。

つまりベクターデータのまま拡縮して直接描写する必要がある。
メタデータを直接編集すればなんとかなる。
って、だからベクターデータの加工には面倒が付き纏うんだよ。

もしコレが特定ライブラリを使えば Easy Mode になるのだったら…
なんて誰でも考え付くよね。
いきなりそのものズバリを見つけてしまった。

RSVG Libary Reference Manual
librsvg – Wikipedia

GtkDrawingArea は GTK3 から cairo で描写している。
なので cairo から rsvg を使う方法を探す。

Cairo: A Vector Graphics Library: Cairo: A Vector Graphics Library

Fedora 21 で rsvg モジュールはデフォルトでは入っていない。
だけど gir には Rsvg が最初からあった、コレを使おう。

cairo って PostScript や PDF も扱えるのか。
面白そうだけど今回は細かいことは置いておいて。
Python 用 cairo ライブラリから SVG を描写する方法を。

Surfaces ? Pycairo v1.10.0 documentation

サーフェス(面)のサイズを変更するには Matrix を使うのか。
1,4 番目引数で x,y のサイズということみたい。
ということで、サーフェスなので paint でなくレンダリングする。

#!/usr/bin/env python3
 
from gi.repository import Gtk, Gdk, Gio, Rsvg
import cairo, sys
 
class Win(Gtk.ApplicationWindow):
    def __init__(self, app):
        """
            DnD SVG Viewer
        """
        Gtk.Window.__init__(self, application=app)
        # svg
        self.svg = None
        # DrawingArea
        self.da = Gtk.DrawingArea()
        self.da.connect("draw", self.on_draw)
        self.add(self.da)
        # DnD
        dnd_list = Gtk.TargetEntry.new("text/uri-list", 0, 0)
        self.drag_dest_set(
                Gtk.DestDefaults.MOTION |
                Gtk.DestDefaults.HIGHLIGHT |
                Gtk.DestDefaults.DROP,
                [dnd_list],
                Gdk.DragAction.MOVE )
        self.drag_dest_add_uri_targets()
        # self
        self.set_title("DnD SVG Viewer")
        self.resize(200, 200)
        self.show_all()
 
    def do_drag_data_received(self, drag_context, x, y, data, info, time):
        """
            On Drop
        """
        uris = data.get_uris()
        f = Gio.File.new_for_uri(uris[0])
        path = f.get_path()
        # Recreate svg
        self.svg = Rsvg.Handle.new_from_file(path)
        # invalidate
        self.da.queue_draw()
 
    def on_draw(self, widget, cr):
        """
            Draw x5 SVG
        """
        if self.svg:
            # x5 size
            matrix = cairo.Matrix(5, 0, 0, 5, 0, 0)
            cr.transform (matrix)
            # Render
            self.svg.render_cairo(cr)
 
class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self,
                application_id="apps.test.dnd",
                flags=Gio.ApplicationFlags.FLAGS_NONE)
         
    def do_activate(self):
        Win(app)

app = App()
app.run(sys.argv)

svg_5x

これならギザギザにならずに拡大することができる。
別途でインストールするものは何もないのに、Linux 恐るべし。
いやまあ全部 GNOME プロジェクトのおかげなんですけど。
結論、cairo って実はこんなに面白いんだyo!

D-Bus Application Launch

gnome-weather は Gjs 製。
その desktop ファイルの名前。

org.gnome.Weather.Application.desktop

これだけでも変だけど、その Exec キー。

gapplication launch org.gnome.Weather.Application

何ですかコレ?

/usr/share に org.gnome.Weather ディレクトリがある。
その中に org.gnome.Weather.Application ファイルがある。
中身は Gjs である、シバンがあるので Gjs で起動できるのは解る。

肝心の JavaScript ソースは同一ディレクトリでバイナリ化されている。
ワカガワカラナイヨ、こんなの見たことがない。

色々検索してみると、どうも DBus 関連らしい。
HowDoI/DBusApplicationLaunching – GNOME Wiki!
コレみたいだが全然ワカランぞ!

Gjs 関連は後日思い立ったら調べるとして。
とりあえず gapplication コマンドは何をしているかを試してみる。

gapplication launch org.gnome.Documents

gapp

普通に起動できるんだね、list-apps で表示されるもの以外に

/usr/share/dbus-1/services

にあるサービスなら何でも起動できるようです。
中身は普通の ini ファイルなんですけど。

ならばこんなディレクトリを作り、念の為再ログイン。

~/.local/share/dbus-1/services

org.madoka.Magika.service という名前で以下のファイルを。
残念ながら ~ や $HOME は使えないのでフルパスで。

[D-BUS Service]
Name=org.madoka.Magika
Exec=/home/sasakima-nao/test.py  --gapplication-service

起動するファイル、上記 Exec の指定位置に保存。
+x パーミッションを忘れずに。

#!/usr/bin/env python3

import sys
from gi.repository import Gtk, Gio

class App(Gtk.Application):
    """
        org.madoka.Magika App
    """
    def __init__(self):
        Gtk.Application.__init__(
                self,
                application_id="org.madoka.Magika",
                flags=Gio.ApplicationFlags.FLAGS_NONE )
 
    def do_activate(self):
        self._win = Gtk.ApplicationWindow.new(self)
        self._win.set_title(self.props.application_id)
        self._win.show()

app = App()
app.run(sys.argv)

さあどうだ。

gapplication launch org.madoka.Magika

dbus_launch

なるほど、あのコマンドで実行できる仕組みはコレか。

コマンドの処理が戻ってきているから最初から転送扱いみたい。
application_id が一致しないと起動はできるけど終了しない。
–gapplication-service 引数を書かないと何故か2つ起動する

ここまで解ったけど使わないかも。
セッションバスに追加されるようなので何か思いついたらne!

Web Application Icon for GNOME

Web アプリケーションを使っている人は多い。
タブレットではアイコン化して普通のアプリのように使えて便利。
実は GNOME 3.14 では既に同様に使えるようです。

ただタッチパネルデバイスの OS が自由にならないと宝の持ち腐れ…
は置いておいて、パソコンでも使える範囲で使う方法を。

Google Chrome は書くまでもない。

chrome

epiphany も可能。
Fedora はメニューには無いけどコマンドで起動できます。

epiphany

判り易い所で epiphany にて apple 公式サイトで試してみます。

apple

apple-touch-icon ?も普通に取得してメニューになりました。
起動してみます、最大化でサイトが表示されたはずです。
どうやら epiphany で作るものは完全にタブレット向け。

menu

メニューに追加されたのでつまり desktop ファイルが作られた。
desktop ファイルはどんな内容になっているのかを確認。
~/.local/share/applications にあるはず。

desktop

何故かシンボリックリンクになっているけど気にしない。
Exec キーを見てのとおり epiphany のサブセットで動かすようだ。
epiphany レンダリングエンジンは WebKit なので問題無し。
JavaScript エンジンが Seed であることがチョッピリ懸念。

Google Chrome で作るとウインドウになるのが解る。
コチラの Exec はもちろん Chrome になっている。
V8 でないとうまくいかない場合はこちらを利用しよう。

つまるところ。
WebApplication といっても desktop ファイルを作っているだけ。
apple-touch-icon は流石にダウンロードして適用のようです。

コレらを全部削除して再度ログインすればキレイサッパリ。
いや、epiphany で作ると gnome-softwere に登録されるけど。
[削除]を押しても上手くいかない、流石にこれはバグだよな。

しかし、パソコンならブックマークで充分なんですけど。
タブレットで普通に Linux を使う日がきたら多分便利yo!

file ext

前々回。
「g_content_type_guess だと ContentType は拡張子依存みたい」
と書いた手前、筆者的には当然の結果だけど一応試してみた。

#!/usr/bin/env python3

from gi.repository import Gio

# Doesn't exist a File.

ans = Gio.content_type_guess("Not Found.txt")
print(ans)
#=> ('text/plain', False)

# File Create (No Ext).

with open("found", "w") as f:
    f.write("#!/usr/bin/env python3\n")

# g_content_type_guess

ans = Gio.content_type_guess("found")
print(ans)
#=> ('application/octet-stream', False)

# Gio Query

obj = Gio.file_new_for_path("found")
info = obj.query_info(
    Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
    Gio.FileQueryInfoFlags.NONE )
ans = info.get_content_type()
print(ans)
#=> text/x-python

やっぱり拡張子の有無で関数の違いが出るんですね。
Gtk, GLib と付き合いが長いので結果は解っていたけどこういうこと。

つまり面倒臭い手段を使えば予定通りな結果が得られる。
GNOME プロジェクトは計画的にやっているんだろうな、と思ってしまう。
何故こうなるかは割愛、これは GNOME 関連では単純なほうだyo!