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!

Virtual Terminal Emulator

VTE といってもホンダのバイクじゃありません。
Virtual Terminal Emulator の略であります。

Gedit 標準プラグインに Python コンソールがありますが全然違う。
gnome-terminal そのものみたいなエミュレーターです。

GNOME wiki の VTE Terminal Widget Library ページ。
Apps/Terminal/VTE – GNOME Wiki!

バージョンがややこいけど 2.91=0.39 のようだ。
例によって GNOME プロジェクト作だから合わせたかったのかな。
vte291-devel-0.39.90-1.fc22.armv7hl.rpm | RPM Info | koji

vte01

Fedora にはしっかり gir で入っていますね。
多分 gnome-terminal 採用のディストリなら大抵あると思う。
2.91 は見当たらないので 0.39 のドキュメントを見ればいいだろう。
VTE Reference Manual: VTE Reference Manual

参考が欲しいのでサンプルコードを探す。

c – gtk+ vte scrollback not working – Stack Overflow
python – How to add vte terminal widget in GTK3? – Ask Ubuntu

C や Python から使う方法は海外でアッサリ見つかった。
日本語情報は今のところ皆無、いつものことだ。

しかし古いようで vte_terminal_fork_command 関数は 2.91 で使えない。
どうやら現行は vte_terminal_spawn_sync 関数を使うようだ。

ということで。
早速 Python バインディングにて書いてみよう。

#!/usr/bin/env python3

from gi.repository import Gtk, Vte, GLib

class VteWindow(Gtk.Window):
    """
        Vte Sample (v2.91)
    """
    def __init__(self):
        Gtk.Window.__init__(self)
        # Create a virtual terminal 
        terminal = Vte.Terminal.new()
        # Exit of Ctrl+D
        terminal.connect("child-exited", self.on_terminal_child_exited)
        # Sync
        terminal.spawn_sync(
                Vte.PtyFlags.DEFAULT,
                GLib.get_home_dir(),
                #["/bin/sh"], @ List of Execute Command
                ["/usr/bin/python3"],
                None,
                GLib.SpawnFlags.DO_NOT_REAP_CHILD,
                None,
                None,
                None)
        self.add(terminal)
        self.set_title("Virtual Terminal")
        self.connect("delete-event", Gtk.main_quit)
        self.show_all()

    def on_terminal_child_exited(self, vteterminal, status):
        Gtk.main_quit()

VteWindow()
Gtk.main()

vte02

spawn_sync の引数については devhelp で詳しく。
三番目引数を sh や perl に変更すれば当然それらが起動する。
それと上記は起動したコマンドの終了を検知して自分も終了させている。
後はお好みで弄ってみてください。
今後バージョンで変わると思うので 2.91 と念を押して。

/bin/sh で起動してソコから Python を始めるとかも可能。
Ctrl+D で Python を終了すると sh に戻る、マジで普通の端末。

しかし自分で試して驚いた、こんなにアッサリ実装できるとは。
自分好みに拡張したオリジナル端末を作るだけでも面白そう。
ただ一言、日本語の情報がまったく無いのはキビシイze!