月別アーカイブ: 2011年10月

Opera v12.00 alpha on Fedora 15

又しても窓の杜で発見、私は Linux ユーザーなのに…
とにかく Opera のアルファ版が凄いらしい。

窓の杜 – 【NEWS】Opera、“WebGL”に対応した「Opera」v12のアルファ版を公開

早速 Linux x86_64 版の tar.xz を落として試用。
私の AMD 880G 内蔵グラフィックでアクセラレーションはどうだ?

駄目だガクガクじゃんw
fglrx じゃなくて標準ドライバを使っているのだから当然か。
GNOME 3 の 3D 機能は標準ドライバーで充分なんだけど、うーん。

ところで Opera の UI は環境に合わせて変化するのは知っているよね。
KDE4 では Qt4 に、GNOME 2 では GTK2 にと。
GNOME 3 では見事に GTK+ 3 になるようになったようです。

GtkComboBox の矢印位置が少し上にズレているけど…
GtkScrollbar や GtkCheckButton は完璧だね、どうやっているの?
おいおい、ヒントウインドウもキチンと黒バックで出てくるよ。
狐でさえいまだに GTK2 のままなのによくやった!

でも、検索バーで日本語変換して Enter すると死ぬのは変わっていない…
私は F2 キーを使うから別にイイんだが欠陥だよな…

とりあえず今後に期待。
Linux 標準 ATI ドライバで WebGL が動くようにはならないだろうけど。

Python with GTK+3 WebKit Browser 2

いやいや。
Original Webkit Browser @ Fedora 15 | PaePoi
の最後で app.run(sys.argv) と書いていたんだが…
イザ引数を指定してみるとファイルを開けないというエラーになるじゃん。

GApplication#GApplicationFlags

GtkApplication 作成時の GApplicationFlags の指定が悪いのかも。
と HANDLES_OPEN に変更すると今度は展開できないという Warning になる。

展開できれば on_open の files 引数に GFile がリストになって…
いや引数がファイルであるとは限らない、URI や設定の可能性もあるし多分フラグの使い方が違うのだろう。
どっちにしろ app.run(None) に書き換えるしかなさそうだ。

多重起動防止処理にして引数を起動している Window に渡したいのだが…
activate シグナルの時点で GtkApplication にアトリビュートとしてくっ付けた変数値は前回起動時の値にどうしても戻される。
合体するのではなく既存の GtkApplication に転送されているのかな?
GSettings とかで他の場所に URI を一時保存するしか無いかな…

それと delete-event 処理を入れていなかった。
閉じるボタンを押すと飛んでくるシグナルね、ここで設定保存する予定なので。
メニューのハンドラからハンドラを呼べばツジツマが合う

どうでもいいけど ~/bin に入れたので拡張子を取っ払ってみたら…
[Qt Designer ファイル] になっちゃった!

#!/usr/bin/env python と先頭に書いても XML 部分を優先して認識するっぽい。
GIO による content-type 認識はイマイチであるようだ。
XML 部分を最後のほうに移動してなんとかなった。

変更箇所多すぎ…
前回書いた local アクセスの件もあるし丸ごと書き換えるとするか。
せっかくなので「進む」「戻る」「ホーム」のボタンも付けた。

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

import sys, os
from gi.repository import WebKit, Gtk, Gio, Gdk

HOME_URI = "http://palepoli.skr.jp/wp/"
APP_NAME = "wkitx"

class WebKitWindow(Gtk.Window):
    """
        WebKit PyGi Version
        from Fedora 15 x86_64
    """
    def __init__(self):
        # Window
        Gtk.Window.__init__(self)
        self.resize(640, 480)
        self.set_title(APP_NAME)
        self.connect("delete-event", self.on_delete)
        # GtkUIManager and GtkAccelGroup
        self.uimanager = Gtk.UIManager()
        accelgroup = self.uimanager.get_accel_group()
        self.add_accel_group(accelgroup)
        # GtkActionGroup
        self.actiongroup = Gtk.ActionGroup("seeme_menu")
        # GtkActionEntry
        self.ac = [ ("forward", Gtk.STOCK_GO_FORWARD, "_Forward", "<Alt>Right", "Forward", self.on_forward),
                    ("back", Gtk.STOCK_GO_BACK, "_Back", "<Alt>Left", "Back", self.on_back),
                    ("reload", Gtk.STOCK_REFRESH, "_Reload", "F5", "Reload", self.on_reload),
                    ("quit", Gtk.STOCK_QUIT, "_Quit", "<Control>Q", "Quit", self.on_quit),
                    ("file", None, "_File") ]
        self.actiongroup.add_actions(self.ac)
        self.uimanager.insert_action_group(self.actiongroup, 0)
        self.uimanager.add_ui_from_string(menu_xml)
        # menubar
        menubar = self.uimanager.get_widget("/MenuBar")
        # entry
        self.entry = Gtk.Entry()
        self.entry.connect("activate", self.on_entry_activate)
        # toolbar
        toolbar = Gtk.HBox()
        toolbar.set_border_width(3)
        back = FlatImageButton(Gtk.Image.new_from_stock(Gtk.STOCK_GO_BACK, Gtk.IconSize.BUTTON))
        back.connect("clicked", self.on_back)
        forward = FlatImageButton(Gtk.Image.new_from_stock(Gtk.STOCK_GO_FORWARD, Gtk.IconSize.BUTTON))
        forward.connect("clicked", self.on_forward)
        home = FlatImageButton(Gtk.Image.new_from_stock(Gtk.STOCK_HOME, Gtk.IconSize.BUTTON))
        home.connect("clicked", self.on_home)
        toolbar.pack_start(back, False, False, 0)
        toolbar.pack_start(forward, False, False, 0)
        toolbar.pack_end(home, False, False, 0)
        toolbar.pack_start(self.entry, True, True, 0)
        # WebKit
        self.webview = WebKit.WebView()
        self.webview.connect("load-started", self.on_load_started)
        self.webview.connect("load-finished", self.on_load_finished)
        self.webview.connect("title-changed", self.on_title_changed)
        self.webview.connect("hovering-over-link", self.on_hovering_over_link)
        # ScrollWindow
        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.add(self.webview)
        # statusbar
        self.statusbar = Gtk.Statusbar()
        # setting
        setting = self.webview.get_settings()
        setting.set_property("enable-file-access-from-file-uris", True)
        # main packing
        vbox = Gtk.VBox()
        vbox.pack_start(menubar, False, True, 0)
        vbox.pack_start(toolbar, False, True, 0)
        vbox.pack_start(sw, True, True, 0)
        vbox.pack_start(self.statusbar, False, True, 0)
        self.add(vbox)
        self.show_all()
        self.set_focus(self.webview)
        # argv
        if len(sys.argv) > 1:
            self.webview.load_uri("file://"+ os.path.abspath(sys.argv[1]))
        else:
            self.webview.load_uri(HOME_URI)

    def on_delete(self, widget, data=None):
        pass

    def on_load_started(self, webview, frame):
        self.statusbar.push(0, "Loading...")

    def on_load_finished(self, webview, frame):
        self.statusbar.push(0, "")

    def on_title_changed(self, webview, frame, title):
        self.set_title("{0} - {1}".format(title, APP_NAME))
        self.entry.set_text(webview.get_uri())

    def on_hovering_over_link(self, webview, title, uri):
        if uri:
            self.statusbar.push(0, uri)
        else:
            self.statusbar.push(0, "")

    def on_entry_activate(self, entry):
        self.webview.load_uri(entry.get_text())

    def on_back(self, widget, data=None):
        if self.webview.can_go_back():
            self.webview.go_back()

    def on_forward(self, widget, data=None):
        if self.webview.can_go_forward():
            self.webview.go_forward()

    def on_reload(self, widget, data=None):
        self.webview.reload()

    def on_home(self, widget, data=None):
        self.webview.load_uri(HOME_URI)

    def on_quit(self, widget, data=None):
        app = self.get_application()
        app.remove_window(self)
        self.on_delete(widget)

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(
                self,
                application_id="apps.wkitx.webkit",
                flags=Gio.ApplicationFlags.FLAGS_NONE)
        self.connect("activate", self.on_activate)

    def on_activate(self, app):
        l = self.get_windows()
        if l:
            # Is the sys.argv of the previous...
            #if len(sys.argv) > 1:
            #   l[0].webview.load_uri("file://"+ os.path.abspath(sys.argv[1]))
            return
        w = WebKitWindow()
        w.set_application(self)

"""
    etc...
"""

class FlatImageButton(Gtk.Button):
    def __init__(self, image, label=None, stock=None, use_underline=True):
        Gtk.Button.__init__(self, label, stock, use_underline)
        self.set_relief(Gtk.ReliefStyle.NONE)
        self.set_can_focus(False)
        if image:
            self.set_image(image)

def messagebox(parent, text, icon=Gtk.MessageType.WARNING, button=Gtk.ButtonsType.OK):
    dlg = Gtk.MessageDialog(
            parent,
            Gtk.DialogFlags.MODAL,
            icon,
            button,
            text)
    dlg.set_title(APP_NAME)  
    r = dlg.run()  
    dlg.destroy()
    return r

menu_xml = """<ui>
    <menubar name="MenuBar">
        <menu action="file">
            <menuitem action="forward"/>
            <menuitem action="back"/>
            <menuitem action="reload"/>
            <separator/>
            <menuitem action="quit"/>
        </menu>
    </menubar>
</ui>"""

if __name__ == "__main__":
    app = App()
    #app.run(sys.argv)
    app.run(None)

設定変更とかはまだ無いので HOME_URI とかサイズは自分で書き換えてね。
wkitx と仮の名前を付けているが私のことだから多分最後までこのままだろう。

多重起動防止の URI 転送はできないけどパラメータ処理とホームの振り分けは付けた。
Gedit の External Tool から利用できるようにしたかったんだもん。
今まで clipolix から起動していたけど私的にはもう利用できるレベルかなと。
本格的に作るならタブも考えるが、まず URI 転送をどうにかしなければ…

それと、せっかく GTK+3 専用なので GSettings を使おうと思ったけど…

Using GSettings with Python/PyGObject

/usr/share/glib-2.0/schemas ディレクトリに XML schema を置く必要があるんだね。
ということはインストールする前提で作ったアプリにしか使えないなこれは。
でも登録さえ行っていれば

GSettings

settings = Gio.Settings.new("apps.wkitx.conf")
widtth = settings.get_int("window-widtth")

みたく簡単に扱えるのね、後で考える。

Ubuntu 11.10 Beta 2 Screenshots | Linux, BSD, Solaris & Other OS Screenshots | The Leader in Linux, BSD, Solaris & Other OS Screenshots | Screen Shots of Linux Distributions, BSD, Solaris & Other OSes | Linux, BSD, Solaris & Other OS Screenshot Gallery

Ubuntu 11.10 の Nautilus 画像を見ると GTK+3 版になっているみたいね。
ということは 11.10 からは上記コードが動くかもしれない。
現状では Fedora 15 専用なので環境が増えるのは嬉しいよ。

HTML5 Local File Drop and Input File

HTML5 は Local ファイルの編集もできる。
一番利用されるだろうと思われるのはやはりテキストファイルの編集。
ということで今回はファイルの読み込みを勉強する。
<imput> を利用するかドラッグアンドドロップで読み取る方法を。

これは興味がある人が多いようで検索するとワラワラ見つかるね。
でも手段が結構バラバラだったりするので一番最適と思われる方法を探す。
手段は File object を得て FileReader で読み込めばいいようだ。

残念ながら Opera 11.51 はドラッグアンドドロップ未対応だ…
HTML5 の仕様に含まれているのだから今後は対応してくれるだろう。
IE はどうでもいい。

とにかく Firefox, WebKit で上手くいったコード。
Opera も Input だけなら読み込みできる。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Drop and Input</title>

<script>
function writeText(f) {
    var reader = new FileReader();
    reader.readAsText(f, "utf-8");
    var text = document.getElementById("IDTEXT");
    reader.onload = function(e) {
        text.innerHTML = e.target.result;
    }
    reader.onerror = function(e) {
        switch (e.target.error.code) {
        case 1:
            text.innerHTML = "NOT_FOUND_ERROR!";
            break;
        case 2:
            text.innerHTML = "SECURITY_ERROR!";
            break;
        case 3:
            text.innerHTML = "ABORT_ERROR!";
            break;
        case 4:
            text.innerHTML = "NOT_READABLE_ERROR!";
            break;
        case 5:
            text.innerHTML = "ENCODING_ERROR!";
            break;
        default:
            text.innerHTML = "Unknown ERROR!";
        }
    }
}
function changeInputValue(e) {
    var f = e.target.files[0];
    writeText(f);
}
function init() {
    document.addEventListener("dragover", function(e) {
        e.preventDefault();
    }, false);
    document.addEventListener("drop", function(e) {
        e.preventDefault();
        var f = e.dataTransfer.files[0];
        writeText(f);
    }, false);
}
</script>

</head>

<body onLoad="init()">
<p>Drop here</p>

<form>
<input type="file" id="IDURI" onchange="changeInputValue(event);">
</form>

<p id="IDTEXT">URI</p>

</body>
</html>

コンストラクタ(という表現は正しいのだろうか?)
init でこう書けば event object が得られるようだ。
preventDefault メソッドを呼んでブラウザのデフォルト動作を無効にする。
dataTransfer.files メソッドで File object の List が得られる。
その List から添字を使って取り出す、複数ファイルなら for 文を使う。

input は onchange でこう書けば event object 付きで関数が呼べるようだ。
target.files メソッドで File object の List が同様に得られる。

肝心なファイルを読み込んで書き出す処理は少し面倒。
C の fopen や Python の open, read みたいにはいかないようだ。
FileReader の readAsText 関数で読み込んでコールバックで処理する。
読み込みが正常終了すると onload が呼ばれるので event object の target.result プロパティからテキストを得る。

どうでもいいけど Python ばかりやっているとこういう書き方が不自然で…
IronPython の時も思ったけどイコールでの代入時に括弧が無いと変に感じる。

ところで onerror の処理をやたら丁寧に書いていますが…
Original Webkit Browser @ Fedora 15 | PaePoi
で表示できなかったから原因を調べるためである。

WebKitWebSettings

# setting
setting = self.webview.get_settings()
setting.set_property("enable-file-access-from-file-uris", True)

を __init__() のどこかに入れれば表示できるようになります。
Local のファイルアクセスは WebKit デフォルト状態では弾かれるようです。
Chrome では読み込めるようなのにとコレだけで一日悩んでしまったぞと。

書き込みは FileWriter を使う、後日。
その前にリストボックス作成と JavaSclipt で ini ファイル読み書きをやりたい。
何を作ろうとしているかはわかる人には解る。
現実として作りたいアプリが無いとプログラミングの勉強は絶対に続かないよ。

Adobe Flash 11 Linux x86_64

Adobe Flash 11 正式版が出たようです。
今回から Linux x86_64 用が正式版で手に入るようです。

窓の杜 – 【NEWS】「Adobe Flash Player 11」「Adobe AIR 3」がついに正式公開

窓の杜で知るというのも変な話だ。
しかし狐をはじめ Windows 用ブラウザ正式版は 32bit 版しか配られていなかったような…
とにかくダウンロードページへ。

Adobe – 別のバージョンのAdobe Flash Playerをインストール

Fedora なのでと YUM を選択してみたら 404 になるのだが…
rpm なら落とせたからまあいいや。もう自分で突っ込む必要は無くなったね。
しかし Ubuntu ユーザーはサルばかりなのでココまで親切に表示しないと解らないと思われているっぽい。

rpm を W クリックしてインストール。

/usr/lib64/flash-plugin
/usr/lib64/mozilla/plugins
/usr/lib64/opera/plugins

の全部にインストールされたんだが…
まあシンボリックリンクではあるんだが。
上記の所以外にも存在する?

Opera は上記のドコに入れてもデフォルトで認識するから意味無かったり。
てか私の自作 WebKit ブラウザでも何故か YouTube が観覧できるようになった。

とにかく x86_64 Linux を選ぶのに躊躇する最大の理由が無くなって嬉しい。
自作 WebKit ブラウザでも動くしコイツはもう少し改良しようかなと。
GNOME3 は枠線が細すぎてステータスバーてかリサイズグリップが無いとリサイズがやり辛いのにドレも省いてくれているんだもの…

HTML5 Keyboard and Mouse Event

HTML5 を勉強しているけど、多岐に渡りすぎてポイントが掴めない人が多いかも。
とにかく解ったことで普通に利用しそうなもの。

innerHTML 等でリロードせずとも動的にページ内容を変更可能
canvas で図形描写の動的変更が可能
css3 アニメーション等で見栄えのよい UI を構築できる
マウスイベントやキーボードイベントを利用できる
ローカルファイルの編集にも使える

つまり今までは実行ファイル形式で作っていたアプリケーションを Web ブラウザ上で動くアプリケーションにて実現できる技術ということなんだね。
JAVA や Flash 等の特定企業提供に頼らず標準仕様として確立させたわけだ。

ということで。
キーボードとマウスのイベントを捕まえて処理するコードを試す。

書くまでもなく IE はガン無視、Fedora Linux だもん私は。
少なくとも IE9 が使えない Windows XP のサポートが終了するまでは IE なんて意図的に無視したほうが賢明なくらいだ。
アクセスログを見ると IE6 がまだ沢山いて呆れるよ…

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Keyboard and Mouse Event</title>

<script>
function on_keypress(e) {
    var num = e.keyCode || e.charCode;
    var text = document.getElementById("IDTEXT");
    text.innerHTML += String.fromCharCode(num);
}
function on_mousemove(e) {
    var text = document.getElementById("IDMOVE");
    text.innerHTML = "x=" + e.clientX + " y=" + e.clientY;
}
function init() {
    document.addEventListener("keypress", on_keypress, false);
    document.addEventListener("mousemove", on_mousemove, false);
}
</script>

</head>

<body onLoad="init()">
<p id="IDMOVE">x= , y=</p>
<p id="IDTEXT">Press Keyboard Charactor.</br /></p>
</body>
</html>

addEventListener は document に指定すればフォーカスを気にする必要は無くなる。
逆にフォーカスがある時だけハンドリングしたい場合は getElementById で指定。

イベントハンドラ引数の e から詳細が得られる。
e.keyCode は Opera と WebKit のみ
e.charCode は Firefox と WebKit のみ
しかたがないからこうすることに。
mouse の e.offsetX は Opera と WebKit
e.clientX なら全部でまかなえた。

流石はアホみたく更新しまくっている WebKit が一番柔軟だ。
今後の更新でどうなるか解らないけど現時点なら上記でハンドリングできる。

ただキーボードはブラウザの割り当てというものが…
主にマウスやタッチパネルで扱うアプリが主流になるのだろう。
だからタブレットはやたら HTML5 を押しているのか、と今更な発見であった。