月別アーカイブ: 2012年1月

WebKit Seed imports

GNOME の JavaScript 実装は seed と gjs がある。

JavaScript – GNOME Live!

seed は WebKit の Javascript エンジン。
gjs は Spidermonkey(Firefox) の Javascript エンジン。

であるようだ。
一応書くと Google Chrome のエンジンは V8 なので違います。
ようするに普通に WebKit を GNOME で使うと Seed を利用するということかな。

Python with GTK+3 WebKit Browser 2 | PaePoi
試しに以前作った上記と Google Chrome で V8 ベンチをやってみる。
V8 Benchmark Suite

V8 はやはり早い、圧倒的な差があるのね。
まあそれはよくて、Seed なら imports が使えるはず。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>GtkWindow</title>

<script>
function test() {
    try {
        var Gtk = imports.gi.Gtk;
    }
    catch(e) {
        alert(e);
    }
}
</script>

</head>
<body>
<input type="button" onclick="test()" value="Test">
</body>
</html>

ダメじゃん、ということで。

Blogging in the wind: WebKit: Extending Javascript – Seed (V)

こんなページを見つけた。
これは面白そうだ、ヘッダを揃えてビルドしてみよう。
webkitgtk-devel, seed-devel を入れればいいかな。

環境が揃ったのでビルド、問題なく実行ファイルが作成された。
ということで、GtkWindow を作成する HTML5 ファイルを読み込ませてみる。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>GtkWindow</title>

<script>
var on_clicked = function() {
    //
};
function create() {
    try {
        var Gtk = imports.gi.Gtk;
        Gtk.init (null, null);
        var gtkwin = new Gtk.Window();
        gtkwin.signal.hide.connect(Gtk.main_quit);
        var label = new Gtk.Label({label:"Button Click -> WARNING"});
        var button = new Gtk.Button({label:"Button Clicked"});
        button.signal.clicked.connect(on_clicked);
        var vbox = new Gtk.VBox();
        vbox.pack_start(label);
        vbox.pack_start(button);
        gtkwin.add(vbox);
        gtkwin.show_all();
        Gtk.main()
    }
    catch(e) {
        alert(e);
    }
}
</script>

</head>

<body>
<div>First time an error</div>
<input type="button" onclick="create()" value="Do GtkWindow">
</body>
</html>

ボタンの初回クリックで例外を吐く。
けど2回めからは問題なく GtkWindow が作成された。
body.onLoad() で imports なんかも試してみたが同じだった。

それよりシグナルのハンドラがうまくいかない。
RangeError って意味がよく解らないんですけど…
Seed の例外は何が悪いのかが PyGI より理解し辛いのが難点だよな。

うーイマイチだ。
でもとにかくコレで WebKit から imports が使えることは解った。
利用場面があるかどうかは別の話として。

Trigraph

先日書いたように半月前に Fedora マシンを英語キーボードに変えた。
VirtualBox 仮想マシンの Windows Vista, XP も英語配列に変更。
「英語キーボード Vista」と検索すればワラワラ見つかるレジストリ書き換えで。
XP は簡単、どちらも仮想マシン状態でも方法は同じで変更できるようだ。

IME も問題ない、Windows では Alt+~ で切り替えなのね。
ホストの GNOME3 複数ウインドウ切り替え機能より優先されるようだ。
てゆーか間違えるわ、あんまり使わないからいいけど。

ついでなのでキーボードネタでも少し。

有名かもしれないけど C 言語では Trigraph という三文字表記が使える。
Digraphs and trigraphs – Wikipedia, the free encyclopedia

??=include <stdio.h>

main() ??<
    printf("%s??/n", "はろーわーるど");
??>

スッゲエ読みにくい、なんだこりゃですが使えるんです。
ただ gcc では無効になっているので -trigraphs オプションが必要。

gcc -trigraphs test.c

日本語をリテラルに使っても何も問題無い。
ついでに試したら VC++ ならオプション無しで普通にビルドできる。
もしかして C# でも使えるかな?と思ったけどダメだった。

どうでもいいが wprintf ってどんな時に使うのだ?
内部が UTF-16 で local が CP932 で .NET 読み書きが UTF-8 ってアホか。
結局コンソールを使う場合はマルチバイトビルドしか選べないわけで…
それは本当にどうでもよくて。

問題があるようで代わりに Digraph というのが C99 で既定されたようだ。
表現できるものが減っているけどコレで全世界でも問題ないと判明したのだろう。

%:include <stdio.h>

main() <%
    printf("%s\n", "はろーわーるど");
%>

gcc ならオプション無しでイケる、Visual Studio 2008 ではダメだった。
Visual Studio 2010 ならイケるのかはシラネ。
そして C#, Python は関係無かった。

つーか何故こんなもんがあるかというと。
フランス語やドイツ語キーボードにはシャープや角括弧や中括弧が無いから。
キー配列 – Wikipedia

でも実は右 Alt キーを利用して打つことはできるようです。
京都産業大学 外国語学部 フランス語学科/Windowsでのフランス語入力
ドイツ語キーボードの配列

ということで C 言語以外は三文字表記なんか気にしなかったようだ。
いや UTF-8 が普及したってのが大きいんだろうけど…
よく考えたら C# なんて # が使えないと言語名さえ変えなくてはいけないもん。
ぶっちゃけ誰もこんな表記方法は使わないだろう、と思うんだが。

ついでに。
「Gedit キーカスタマイズ」とかのワードで検索している人がいるんだな…
それ Windows の文化だから。

Gedit で検索は Ctrl+F で次を検索は Ctrl+G ですよね。
これ、たとえば devhelp もまったく同じなんです。
一つ覚えてしまえば他でも同じキーが使える環境のほうがいいと思うのだが。
そういうところが気に入って GNOME を選んでいる人って少ないのかな…

English Keyboard in japan (Fedora 16)

先月の終わりにキーボードを買った。
そう、Majestouch のチャタリングが耐えられないレベルになって…
半年くらいから T キーが少しおかしくなる、変なクセでも付いたかなと軽く思っていたが。
そのうちアレもコレもとチャタるキーが増えていって…

Majestouch Tenkeyless Keyboard | PaePoi

キータッチは最高だったのに一年しか持たなかった YO!
多分私はヘヴィに使う人だと思うので一年というのは参考値に。

買い換えるにしてもテンキーレスでないとイラッとする体になってしまって。
っってマジェを避けるならもう RealForce しか選択肢がない。
でも多分誰もが気になるあの小さすぎるスペースキー。

ん、英語キーボードにすればいいんでないの。?

無変換とか前候補とか存在理由不明なキーを取っ払うだけでこんなにデカくなる。
そういえば右の Super キーも無いな、コレも一度も押したことが無いことに気がつく。
逆に Enter は小さく長くなる、コレが実は曲者で。
ミニノートなんかのキーだと英語配列なら違和感が無いものが多すぎる。

それよりプログラマーが気になるのは記号。
記号の大半は日本語キーボードとは位置が違う、レビューの検索でもしよう。

驚いた Super キーと Menu キーがいらない人ってこんなに多いんだ。
アクティビティを開くのは Alt+F1 より Super キーのほうが楽だし Nautilus から Ctrl+A して Menu キーを叩いて tar.gz のアーカイブを作成とかフル活用している私は異端なのか?

と思ったけど Linux なんて仮想マシン上で遊んでいる人が大半だから当然だったわ。
Windows しか知らなかった頃は私も滅多に使ったことが無かったわ。

てか記号位置の違いとかのレビューなんて見つからないわ。
ソレが怖いので黒ではなく上記のキーが白とグレーの色分けされた奴を選んで購入。
見た目より少しは迷うことが少なくなるだろうことを優先でポチっと。

というわけで自分でレビュー。

地域と言語のレイアウト設定で「英語(US)」のみにしてシャットダウン。
キーボードを取り替えて起動、見事英語キーボードになる。
日本語設定を残して切り替え可能だけど日本語レイアウトが優先されてウザイ。

日本語切り替えは Super+Space で。
実は US 配列 Mac と同じ(command+space)。

キータッチは今更なので割愛。
打鍵音は家で使うと以外に大きかった、マジェの半分以下ではあるけど。
Alt+` は Alt+全角/半角同様に GNOME3 では多重ウインドウの切り替えなのね。

問題なく英語キーボードになったので打ち込んでみる。

最初に使って気がついた、テンキーレスは CapsLock インジケータが無い。
定数指定でたまに使うんだが、打ち込めば解ることだけどパッと確認できない。
秀丸作者の秀Caps ってこういうキーボードために作られたのか。
他のインジケータはいらないけど、テンキー無いし。

日本語は Enter キーの位置さえ気をつければ問題なく打ち込める。
Space キーはやはり長いほうがイイ、無変換とか前候補とかマジでいらない。

bash スクリプトや Python コードを書いてみる。
記号で間違えまくる、イコールを打つ時に無意識に Shift を押している。

アンダースコア、アスタリスク、チルダ、シングルクォートで必ず迷う。
他の記号は意外と間違えない、位置が以前と近いものは見つけやすいようだ。
@ も遠いな、メールアドレスくらいにしか使わないからいいけど。

こんな状態で早く慣れるために年末から正月にかけて memopoli の作成。

そして半月たった現在。

無意識に「全角/半角」だった位置を叩いたり Enter で \ を打つことは無くなった。
日本語のみを打ち込むことに関してはもう何も怖くない。

アプリケーションでキーボードショートカットを使う時にはむしろ重宝する。
右の BackSpace, Shift, Ctrl, Alt がデカいということは素晴らしい。

しかしいまだにアンダースコアは無意識に右下の Shift を叩いている。
スネークケースを多用する Python with GTK+ 屋には鬼門。

他の記号はかなり慣れたけどチルダとバッククォートは毎回迷う。
「全角/半角」だった位置は目で探す時に省いているんですね無意識で。
gnome-terminal で移動だけやって nautilus `pwd` とかよくやるんだが。

ということは…
GTK+ を使わない、シェルスクリプトなんて書かないという人。
つまり Windows しか使わない人なら全然迷わないんじゃないかいな。
てかプログラミングをしないなら記号なんてほとんど使わないからね。

結論。
半月も使えば慣れる、Enter キーと「全角/半角」はあまり気にする必要は無い。
これから英語キーボードに挑戦という人は最初は絶対に色分けタイプにしておけ。
真っ黒を買っていたら私は多分後悔していた。
ただラスボスがまさかアンダースコアだったとは思わなかった YO!

GtkSourceView Insert spaces instead of tabs

タブ幅とスペース切り替えで上手く行かなかった理由が解った。
indent-width を弄くっただけではなんか変な動作になるのね。

indent-width Property が -1 なら tab-width Property に従う。
デフォルトが -1 なので最初から tab-width のみで指定する、つまり
gtk_source_view_set_indent_width ではなく
gtk_source_view_set_tab_width で指定する。

ただ tab-width は困ったことに guint (unsignde int のマクロ) である。
ちなみに WindowsSDK でのマクロは UINT、なら最初から uint でいいのに…
C 言語を作った人達は何故こんな長い型名にしてしまったのやら。

Python ってつまり guint が無い。
型として記憶するようだし、旧文字列フォーマッタにも %u が何故かあるが。
しかし試してみると PyGI は guint を long として扱うようだ。
gint, guint の違いを long と扱って吸収するようだ。

int で型チェックを行っているモジュールに渡す場合は当然弾かれるのだが。
その場合は abs(int_value), int(uint_value) キャストでイケるみたい。
つまり我が自作の inifile8.py とかを使う場合、ココでしばし悩んだ。

gtk_source_view_set_insert_spaces_instead_of_tabs
の真偽値でタブかスペースかを切り替え。

gtk_source_view_set_indent_on_tab
の真偽値では Shift+Tab での動作。
False にすると Shift+Tab でもインデントしたり BackSpace でインデントが先頭まで削除されたりでワケが解らないよ。
思えばそんな動作をするエディタもある、私的に Shift+Tab は逆インデントが直感的だと思うのだが逆にそうなっているエディタのほうが少ないという現実。

更に GtkSpinButton を使うと値が float だったりする。
しかし面白いことに guint のまま値を突っ込むことができる。
そうなるようにバインドされているだけだが Python って簡単だね。
C 言語で同じことやっちゃダメだよ。

実際にアプリを作っている人でないと気がつきもしないだろうな。
こんなに簡単だとメモリ内でどうなっているかとかが勉強できないよ。

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

from gi.repository import Gtk, Gio, GtkSource, Pango

class TabTest(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        # GtkSourceView
        self.view = GtkSource.View()
        desc = Pango.font_description_from_string("Monospace 11")
        self.view.override_font(desc)
        self.view.set_show_line_numbers(True)
        self.view.set_wrap_mode(Gtk.WrapMode.CHAR)
        self.view.set_draw_spaces(GtkSource.DrawSpacesFlags.ALL)
        # Tab Width
        spin = Gtk.SpinButton.new_with_range(0.0, 100.0, 1.0)
        spin.set_value(self.view.get_tab_width()) # uint to float ?
        spin.connect("value-changed", self.on_spin_changed)
        # Indent of Tab or Space
        check = Gtk.CheckButton.new_with_mnemonic("Insert _spaces instead of tabs")
        check.set_active(self.view.get_insert_spaces_instead_of_tabs())
        check.connect("toggled", self.on_toggled)
        # Test Button
        button = Gtk.Button.new_with_label("Type is Integer ?")
        button.connect("clicked", self.on_clicked)
        # pack
        vbox = Gtk.VBox()
        vbox.pack_start(self.view, True, True, 0)
        vbox.pack_start(spin, False, True, 0)
        vbox.pack_start(check, False, True, 0)
        vbox.pack_start(button, False, False, 0)
        # self
        self.add(vbox)
        self.resize(300, 300)
        self.connect("delete-event", Gtk.main_quit)
        self.show_all()
        self.set_focus(self.view)

    def on_spin_changed(self, widget, data=None):
        """
            There is no need to UINT
            self.view.set_tab_width( abs(widget.get_value_as_int()) )
        """
        self.view.set_tab_width( widget.get_value_as_int() )

    def on_toggled(self, widget, data=None):
        self.view.set_insert_spaces_instead_of_tabs(widget.get_active())

    def on_clicked(self, widget, data=None):
        """
            tab-width Type Check
        """
        value = self.view.get_tab_width()
        widget.set_label("Type is {0}".format(type(value)))

if __name__ == "__main__":
    TabTest()
    Gtk.main()

てなわけで、なんとかなった。
memopoli 0.1.1 をめでたく公開、多分自分しか使わないと思うけど。

GtkSourceDrawSpacesFlags

あけましておめでとうございます。
ということで GtkSourceView でアプリを作っているのだが。

GtkSourceView

GtkSourceDrawSpacesFlags というのがある。
gtk_source_view_set_draw_spaces で指定するのね。
以前書いたコードに追記して試しに使ってみる。

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

from gi.repository import Gtk, Gio, GtkSource, Pango

class TextEditor(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        # GtkUIManager and GtkAccelGroup
        self.uimanager = Gtk.UIManager()
        accelgroup = self.uimanager.get_accel_group()
        self.add_accel_group(accelgroup)
        # GtkActionGroup
        self.actiongroup = Gtk.ActionGroup("editor_menu")
        # GtkActionEntry
        ae = [  ("open", Gtk.STOCK_OPEN, "_Open", "O", "open", self.on_open),
                ("save", Gtk.STOCK_SAVE, "_Save", "S", "save", self.on_save),
                ("save_as", Gtk.STOCK_SAVE_AS, "Save as...", "S", "save as", self.on_save_as),
                ("quit", Gtk.STOCK_QUIT, "Quit", "Q", "quit", self.on_quit),
                ("file", None, "_File") ]
        self.actiongroup.add_actions(ae)
        self.uimanager.insert_action_group(self.actiongroup, 0)
        self.uimanager.add_ui_from_string(menu_xml)
        # MenuBar
        menubar = self.uimanager.get_widget('/MenuBar')
        # Toolbar and Style
        toolbar = self.uimanager.get_widget('/ToolBar')
        toolbar.set_style(Gtk.ToolbarStyle.ICONS)
        style = toolbar.get_style_context()
        Gtk.StyleContext.add_class(style, Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)
        # StatusBar
        statusbar = Gtk.Statusbar()
        # GtkSourceView
        self.view = GtkSource.View()
        desc = Pango.font_description_from_string("Monospace 11")
        self.view.override_font(desc)
        self.view.set_show_line_numbers(True)
        self.view.set_wrap_mode(Gtk.WrapMode.CHAR)
        self.view.set_draw_spaces(GtkSource.DrawSpacesFlags.ALL)
        # Add
        sw = Gtk.ScrolledWindow()
        sw.add(self.view)
        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(statusbar, False, True, 0)
        self.add(vbox)
        # self
        self.open_filename = ""
        self.resize(300, 300)
        self.set_title("Text Editor")
        self.show_all()
        self.set_focus(self.view)

    def on_open(self, widget, data=None):
        dlg = Gtk.FileChooserDialog(
                "Open File",
                self,
                Gtk.FileChooserAction.OPEN,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, 
                Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT))
        r = dlg.run()
        if r == Gtk.ResponseType.ACCEPT:
            self.open_filename = dlg.get_filename()
            f = open(self.open_filename, "r")
            t = f.read()
            f.close()
            buf = self.view.get_buffer()
            buf.set_text(t)
        dlg.destroy()

    def on_save(self, widget, data=None):
        if self.open_filename == "":
            self.on_save_as(widget)
        else:
            buf = self.view.get_buffer()
            t = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), False)
            f = open(self.open_filename, "w")
            f.write(t)
            f.close()

    def on_save_as(self, widget, data=None):
        dlg = Gtk.FileChooserDialog(
                "Save File",
                self,
                Gtk.FileChooserAction.SAVE,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, 
                Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT))
        r = dlg.run()
        if r == Gtk.ResponseType.ACCEPT:
            buf = self.view.get_buffer()
            t = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), False)
            self.open_filename = dlg.get_filename()
            f = open(self.open_filename, "w")
            f.write(t)
            f.close()
        dlg.destroy()

    def on_quit(self, widget, data=None):
        self.emit("destroy")

menu_xml = """<ui>
    <menubar name="MenuBar">
        <menu action="file">
            <menuitem action="open"/>
            <menuitem action="save"/>
            <menuitem action="save_as"/>
            <separator/>
            <menuitem action="quit"/>
        </menu>
    </menubar>
    <toolbar name="ToolBar">
        <toolitem action="open"/>
        <toolitem action="save"/>
    </toolbar>
</ui>"""

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(
                self,
                application_id="apps.test.editor",
                flags=Gio.ApplicationFlags.FLAGS_NONE)
        self.connect("activate", self.on_activate)
        
    def on_activate(self, data=None):
        w = TextEditor()
        w.set_application(self)
    
if __name__ == "__main__":
    app = App()
    app.run(None)

これは、まるで秀丸ではないか。
なんだよ、GtkSourceView には改行やタブ文字表示機能があるんだ。
dconf-editor で Gedit の設定を漁ったけど無かった…

GTK_SOURCE_DRAW_SPACES_NBSP とかは試してもよく解らないのだけど。
日本語圏内では解らないことなのだろうか、うーん。

ついでに、上記コードのようにフォント指定を作っている。
いや、デフォルトに戻したくなる場合もあるわけで。

# Get Default Font
settings = Gtk.Settings.get_default()
defaultfont = settings.props.gtk_font_name
desc = Pango.font_description_from_string(defaultfont)

これでデフォルトの PangoFontDescription が得られるわけだ。

どうでもいいけど Fedora の Monospace では半角全角で幅が違う。
VL ゴシックにすればいいわけだがコレは人によるからな。

ぶっちゃけ設定は Gedit の劣化パクリである。
括弧の強調表示方法がイマイチ解らない、GtkSourceBuffer 側なのよね。

現在インデントが全部半角スペースになる現象に悩まされている…
明日には出したいな、休みは明日までだし。