Emacs25に導入されたXWidgetに関して理解を深める
この記事は、Emacs Advent Calendar 2016の3日目の記事です。
はじめに
emacs25.1が2016年9月17日にリリースされました。
なかでも注目を(個人的に)浴びていたのが、もともとブランチして開発されていたものがマージされたXWidgetsです。
XWidgetsは、リリースノートを見てみると、
Xwidgets: a new feature for embedding native widgets inside Emacs buffers.
https://www.gnu.org/software/emacs/news/NEWS.25.1
と、ネイティブなウィジェットをemacsのバッファに埋め込めるらしいです。
実際なにができるか用途がぱっとは思い浮ばないものの、可能性としてはおもしろいと思います。
EmacsWikiの記事を見てみると、emacsの中にemacsを埋め込むという、よくわからない状況になっています。
ただ、実際のところ、巷のブログ等見てみても、xwidget-webkit-browse-urlコマンドを使ってみた、程度の記事しかみつからず、ウィジェットの挿入方法がよくわかなかったので、ウィジェットの挿入方法を調べてみました。
(結論から書いておくと、emacs 25.1では、任意のウィジェットを挿入することはできません。M-x xwidget-webkit-browse-urlでネイティブブラウザをバッファに表示するぐらいしかできません)
ビルド
Xwidgetsはどのemacsでも利用できるわけではなく、ビルド時に、--with-xwidgetをつけた場合のみ利用することができます。
Xwidgetsが使えるかどうかは、M-x xwidget-webkit-browse-urlを実行してみるのがてっとりばやいと思います。有効でない場合は、
Your Emacs was not compiled with xwidgets support
と優しく教えてくれます。なお、xwidget-webkit-browse-urlの使い方は巷にあふれているので、そちらに譲ることにして、ここでは割愛します。
--with-xwidgetオプションを利用できるのは、今のところLinux(Unix)、Mac OS、WindowsのCygwin上のみのようです。Bash On Ubuntu On Windows上やmsys上でできないか調べたり、いろいろ試したりしてみたのですが、X Serverが無いので駄目のようです。残念。
サンプルコード
任意のWidgetとして、ボタンを挿入する超簡単なサンプルコードです。
(require 'xwidget) (xwidget-insert (point-min) 'Button "Click me" 100 100)
これを評価すれば、
な感じでボタンが表示されます。ボタンだったら、M-x customizeでも表示されるじゃんと思ってそちらのボタンも見てみたのですが、ちょっと見た目が違いますね。
もちろんボタンだけでなく、スライダーや他のGtkのWidgetを挿入することもできます。
(xwidget-insert (point) 'slider "slide me" 300 50) (xwgir-require-namespace "Gtk" "3.0") (put 'ColorButton1 :xwgir-class '("Gtk" "ColorSelection")) (xwidget-insert (point) 'ColorButton1 "xwgir-color-button " 500 300)
(put 'ColorButton1 :xwgir-class '("Gtk" "ColorSelection"))
で、デフォルトでは設定されていないwidgetを設定できるようなのですが、
https://developer.gnome.org/gtk3/stable/GtkWidget.html
配下にあるクラスをセットしても、表示されるものと表示されないものがあるので、なにかしら表示できるwidgetに条件があるようなのですが、そこは残念ながらわかっていません。
苦しんだところ
実はこのサンプルコード、emacs 25.1では動作しません。
評価するとセグフォでコアを吐いてemacsが死んでしまいます。ビルドミスかと思って調べたら、emacs 25.1の方には制限をかけてあってxwidget-webkit-browse-url以外の用途では使えないようになっているようです。
Xwidgetブランチのコードにあるsrc/xwidget.c
http://bzr.savannah.gnu.org/lh/emacs/xwidget/files
DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, 7, 8, 0, doc: /* Make an xwidget from BEG to END of TYPE. If BUFFER is nil it uses the current buffer. If BUFFER is a string and no such buffer exists, it is created. TYPE is a symbol which can take one of the following values: - Button - ToggleButton - slider - socket - socket-osr - cairo */ (中略) if (EQ(xw->type, Qwebkit_osr)|| EQ(xw->type, Qsocket_osr)|| (!NILP (Fget(xw->type, QCxwgir_class)))) { block_input(); xw->widgetwindow_osr = gtk_offscreen_window_new (); (後略)
emacs 25.1のコードにあるsrc/xwidget.c
https://github.com/emacs-mirror/emacs/tree/emacs-25
DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, 5, 6, 0, doc: /* Make an xwidget of TYPE. If BUFFER is nil, use the current buffer. If BUFFER is a string and no such buffer exists, create it. TYPE is a symbol which can take one of the following values: - webkit (中略) if (EQ (xw->type, Qwebkit)) { block_input (); xw->widgetwindow_osr = gtk_offscreen_window_new (); (後略)
記事としてまとめるために、もう一度ソース読んでたら、冒頭のコメントにばっちり書いてあったorz
ひさしぶりにCのソースを読んだせいで、いきなりコードの方を読むという冒険をしてしまったのが敗因です。