X の日本語対応


Opie でつっぱしってるさなかに 2/28 以来の X な話なのは、 X 入れるつもりで SL-C750 買っちゃったからともいう。 A300 ではシャープの手書き文字認識を捨てる気にならず Opie 使ってるが、 C750 ではハードキーもつのに何を好き好んで わざわざ手書きで入力せにゃならん? ということで、 最初から X 導入が前提になっている。

準備

  1. vendor/product = 0x4dd/0x9031 を母艦側の usbdnet.o に登録し、 USB LAN で繋ぐ。
  2. C750 に SD 経由で konsole を入れ、 /etc/inetd.conf から in.telnetd のコメントアウトを外して kill -1 ... えーと、154 だっけか。
  3. 外から入れるようになったら /etc/inittab から qt の項をコメントアウトして kill -1 1.
として Qt は止まった。この時点で echo 1 > /proc/sys/pm/suspend での suspend とパワースイッチでの resume は確認しておいた。 もちろんおっけー ... なんだが、 SIGSTOP の件で、繋いであった session は しっかり切れてるのであった。うーむ。

このあたり、SL-C700 のカーネルをつっこむという予定はあるが、 C750/760 のバッテリの容量管理が C700 から変わってるはずなんで、 そのままつっこんで大丈夫かどうかかならずしも自信はない (A と違い、C はカーネル層がバッテリの温度/電圧/容量を監視/管理している) ... が 760 ならともかく 750 で気にするほどのことはなかろ。C700 に大容量バッテリつっこんでる人達もいることだし。

X の準備のほうは、例によって母艦に作ってある Debian/arm の sarge に chroot して Xfbdev 起動。

# mount -t nfs atropos:/home/src/SUBSYSTEM/arm /mnt/net
# cd /mnt/net
# /sbin/chroot . /bin/zsh
# mount -t proc proc /proc
# PATH=/sbin:/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin
# /etc/init.d/nfs-common start
# cd
# Xfbdev -schedInterval 10 -schedMax 10 -screen 640x480@270 &
# export DISPLAY=192.168.129.201:0.0
# xengine
で xengine が動き出す ... 130rpm かい。A300 より遅いんかい -_-;;

テストしかしてないので xinit 使わず直叩きしているが、 window manager なども動かしたければ、

% Xfbdev -schedInterval 10 -schedMax 10 -screen 640x480@270 &
% export DISPLAY=192.168.129.201:0.0
% sh .xinitrc
とでもすればリモートからでもふつーの環境を立ち上げることができる (通常 xinit はリモートからの起動を阻止するようになっているはずだ)。

Xfbdev は A300 のと同じバイナリで動く。 C750 の /etc/pointercal をもってきておけば、ペンも合っていた。 libqte の /etc/pointercal 周りのコードは A と C とで変わってないんやね。

sizeof(XChar2b) == 4 という問題

日本語がうまいことでーへん、という問題と、その原因については ぴろさんのレポートにある。

X11/Xlib.h の

typedef struct {                /* normal 16 bit characters are two bytes */
    unsigned char byte1;
    unsigned char byte2;
} XChar2b;
が、arm linux の gcc では sizeof(XChar2b) == 4 になるのだが、 X server、Xlib 自身を含め多くのアプリで sizeof(XChar2b) == 2 を仮定するコードになっているために、 文字列を表示させると 1 文字おきになったり文字列の後半が欠けたりする、 というヤツだ。

かつて arm architecture ではまともに 16 bit word を扱うことができなかった ── 多少なりと使えるようになったのは thumb instruction set (16 bit 語長/命令) のサポート以後だ ── ということの名残りだろうが、迷惑な話ではある。

ここで道は 3 つ。2 にそろえるか、4 にそろえるか、 どちらにもそろえずその時々で正しく動くようにするか。 3 つ目のは論外としても、2 か 4 かはけっこう悩む。 4 にそろえると正しい作法のアプリは rebuild しなくてもいい ... Debian/arm の X 関連バイナリがそのまま使える (もちろん正しい作法のやつ限定; どんだけあるかが勝負か?) というのは魅力的だし、 物事の態度としても正しいと思うのだが、2 にそろえた。

明示的に XChar2b を使ったことで 4 になっているコードを 2 にするには ソースからコンパイルしなおせば勝手に直るが、 2 を仮定したコードを 4 に直すにはソースに手を入れなければならないからだ。 ... 堂々と胸はって言うことではないよーな気もしないでもない。

手で直すといっても、sizeof(XChar2b) が 2 でない可能性にも いちおー配慮の跡がある X server や Xlib とか、 それに krxvt, kterm 程度ならば 2 → 4 の変更につきあってもいいが、 emacs あたりになってくるとそろそろヤな予感がするだろう ... 極めつけは Qt である。 Qt では arm linux でも sizeof(QChar) == 2 になっている。 そして、sizeof(QChar) == sizeof(XChar2b) が仮定されている。 ついでに qstring.h のコメント中に堂々と明示されている。 こんなもん、どうやって直せと? ← つーか、そもそもそんなもんを C750 で動かそーとか思うなよ。

なお、gnome 方面はかなり性質が良く、 Xlib 以下さえ直せば GUI 層より上はバイナリがそのまま使えるっぽい。 てことはつまり、実装的に重いとゆーことでもあるが ... XChar2b が透過的に見えてないってことだからな。

さて。2 に pack するのだが、具体的にはこんだけ (Xlib.h.diff):

--- Xlib.h~	Thu Oct 17 05:14:38 2002
+++ Xlib.h	Tue Jun 17 01:06:01 2003
@@ -1059,7 +1059,7 @@
 typedef struct {		/* normal 16 bit characters are two bytes */
     unsigned char byte1;
     unsigned char byte2;
-} XChar2b;
+}  __attribute__ ((packed)) XChar2b;
 
 typedef struct {
     XChar2b *chars;		/* two byte characters */

裁判の判決文よろしく口上がえらい長いわりに肝心のコードはたった 1 行だったりするんだが、 パッチの場所が場所で影響範囲がしゃれにならんもんでねぇ。 もちろん arm 以外では影響はでない (定義によって出るはずはない)。

このパッチ、gcc でしか使えないよーな気がすんだが、 別売のコンパイラが出てる訳でなし、まあ、よかろ。 そもそも gcc 以外では何もせんでも 2 かもしんないし。

ちなみに sizeof(QChar) が 2 になってるのは、 むろん QChar の定義にもちゃんと __attribute__ ((packed)) がついているからである。

libX11.so.* と Xkb*

XChar2b をいじった場合、影響範囲は多岐にわたる。 従前 X server だけを build して、Xlib などはそのへんのバイナリをそのまま使って来たが、 今やそういうわけにはいかない。libX11.so.* も自前で build したものを使う必要がある。

そーなると、host.def の内容も Xlib 向けオプションをまともなものに (つまり、 Debian/arm バイナリとかと整合性がとれるように) しなければならない。

... なんか作業内容的にとおってもデジャブなんだけど 気付かなかったことにして objdump -TC libX11.so | sort して名前を比較する。 Xkb* あたりが足りなかったので 結局こーなった (host.def):

#define KDriveXServer              YES
#define KdriveServerExtraDefines -DITSY -DMAXSCREENS=2
#define CrossCompiling             YES
#define TouchScreen                YES
#define ItsyCompilerBug            YES
#undef  BuildDBE
#define BuildDBE                   YES
#undef BuildRandR
#define BuildRandR                 YES
#define BuildXInputLib             YES
#define ProjectRoot                /usr/X11R6
#define Freetype2Dir               $(TOP)/extras/freetype2
#define Freetype2LibDir            $(TOP)/exports/lib
#define BuildXTrueType             YES
#define BuildScreenSaverExt        YES
#define BuildScreenSaverLibrary    YES
#define SharedLibXss               YES
#define ServerXdmcpDefines
#define BuildLibraries          YES
#define BuildXF86MiscLibrary    YES
#define BuildXKBlib             YES
#define BuildXKBfilelib         YES
#define BuildXKBuilib           YES
#define XfbdevServer               YES
#define StandardDefines         -Dlinux -D__arm__ -D_POSIX_SOURCE \
                                -D_BSD_SOURCE -D_GNU_SOURCE
#define LinuxLocaleDefines
#define XawI18nDefines          -DHAS_WCHAR_H -DHAS_WCTYPE_H -DNO_WIDEC_H        
#define MakeLocalFontDir        YES
#define InstallXinitConfig      YES

Debian sarge の XFree86 4.2.1 のパッケージを Xlib.h だけ直したあとは SL-C750 上で dpkg-buildpackage の自力 build てのが最もコンパチなんだろーが ... 2 日で build 終ってくれるかなぁ ...?

上記ので build した X server, Xlib バイナリ一式とパッチ:

元ソースは XFree86 の cvs 20030614 時点のである。

kterm, krxvt, katerm

ターミナル三種、kterm, krxvt (rxvt 日本語対応版)、katerm (aterm 日本語対応版) のうち、 katerm は XChar2b に触っていない。このため、sizeof(XChar2b) が 2 だろうと 4 だろうと バイナリがそのまま無問題で動く。 逆に、kterm はベタで触ってるのでかならず直さなければならない。

krxvt については、-km (multibyte font) を指定しない場合は XDrawString16() 任せなので 下位層さえ整合していれば rebuild なしでもちゃんと動くように見えるが、 ~/.Xdefaults などで指定する場合には XChar2b を直接触り、 しかも中途半端に sizeof(XChar2b) == 2 を仮定するため、結局 rebuild しなければならない。 バグあり Xlib との組み合わせで krxvt が日本語が出たり出なかったりの理由もこのあたり。

いちおー make したんだが、おもいっきり glibc 2.3 依存してしまったので略。

emacs, mule

もろに XChar2b を触っている。... うぅ、X support 版は rebuild しなくてもいいと思ってたのに T_T ↑はバイナリ。ソースは without X の時のものと同じ。 ただ X が絡むためにクロスコンパイルはちと面倒で、 xemacs 風に CC=gcc で configure した後に CC だけ置き換えた。XChar2b のサイズ含めて母艦コンパチになってんだから、 これでいいはずである。... たぶん。

config は emacs21 の場合:

% ../emacs-21.2-emcws/configure  --prefix=/usr --with-canna --with-x --build=i686-linux \
   --with-jpeg --with-tiff --with-gif --with-png --with-x-toolkit=athena --target=arm-linux arm-linux-gnu

mule の場合:

% ../mule-2.3-19.34/configure  --build=i586-linux --host=arm-linux --with-terminal-face \
   --with-mcpath --srcdir=/home/src/emacs/mule/mule-2.3-19.34 --with-x --with-x-toolkit=athena --with-canna

emacs21 には prefix 付けたので /usr/ 直下に入るが、 mule は prefix 付けるの忘れたので /usr/local/ 下に入る。うぅ、ごめんよぉ (実は確信犯だ。マジすまん)。

また、without X 環境用のものと違い、両者とも canna 対応になっている。 emacs21 のほうは要するに emcws (canna 直接対応) である。 pure emacs21 は ~/.canna 見てくれないので好かん (きっぱり)。

emacs21

gimp

gimp

日本語カタログは Xlib 任せ。Xlib さえ直せば rebuild なしで動く。 ↑では Debian/arm sarge の gimp 1.2 バイナリを動かしている (fvwm のほうは日本語非対応である ... まあ rebuild もしてねーし)。 さすがにこんなの rebuild したくねーぞ、らっき〜と喜んでたら ──

Qt と konqueror

Qt/X11、KDE と konqueror/X11。Debian sid のバイナリ↓

Konqueror on X11
本体の表示はともかく、メニューやらなんやらがとってもおかしいのは Qt がおかしいのか、設定だけのことなのか ...

KDE の C750 による自前 build なんて、はたして 3 日で終るか? クロスで build するにも、Qt/X11 にクロス向けの configuration 付いてないっすけど ... もともとまともに動かすつもりないのでとりあえず pending.
swap なしでも動いてるようだが、けっこ重い。

まあ、軽い X11 な web ブラウザなら、 naorou さん家で紹介されてる dillo か w3m でよかろ。gnome が無問題っぽいので phoenix という解もありそうだが、未確認。 Debian にバイナリ入ってないから自前で build しなきゃいけないんだもん。

Xv

べつに日本語がどーこーというようなアプリではない (こともないが、 このアプリの性質から、それほど致命的ではない)。 ゆえに Debian/arm にあるやつを使えばいい ── と、のんびり構えてたら woody 以降のに入ってない。potato からソース確保して make した。 つまり、make するはめになった。あぅ。

もともとフリーではなかったので non-free セクションにあったんだが、 non-free にも置けないことになったのか。
まぁ、gqview 使えばいい話ではあるが。

Xmodmap

C750 で X 動かすとき、Ctrl キーがないのでハマる。 ぴろさん作の .Xmodmap を使わさせてもらっている。 さりげなく "/" キーが shift なしになってるとか、 微妙に使い勝手が Qtopia でのキー配列より良かったりするのがナイスである。

RandR extension

従来のXFree86 でのスクリーンサイズの切替え ( ALT- '+'/'-' ) では実画面サイズを切り替えても X が扱う「一画面」のサイズ自体は変わらなかった。

RandR extension は起動時に横倒しにするだけが能でなく、 この仮想スクリーンのサイズそのものが on-the-fly で切替えられるようになった。... ことになっている (をい)。

C750 の X の場合で言えば、

% xrandr -display odetto:0.0 -q       
 SZ:    Pixels          Physical       Refresh
*0    480 x 640    ( 163mm x 217mm )
Current rotation - normal
Current reflection - none
Rotations possible - normal left inverted right 
Reflections possible - X Axis Y Axis

xrandr というコマンドで rotate と resize が出来ることになっているが、 まだ SZ index が 0 の一通りしかサポートしかないので、resize はできない (QVGA に変えたりはできない)。 rotate のほうは

% xrandr -o left
などとすれば回る。"left" というのは左に回す、ふつーの viewstyle の向きのことである:

fvwm normal fvwm left
... このカラーリング、現物ではかなり明るいんだが、こーしてみるとなんか暗いな ...。

閑話休題。ここでいう resize の意味がちょいと不明で、 つまり inputstyle 位置で 横 640 縦 480 で使ってるのと、viewstyle 位置で 横 480 縦 640 で使う時の差は rotate だけなのか、resize 動作が入ってるのか ... というあたりのことだが。

なにぶん window manager が対応してないと画面の扱いがわけわかめになるのは容易に想像がつくと思うが、 実際に RandR に対応しているのは waimea の cvs のものしか知らない (... かったんだが、stable の 0.4.0 も対応してるみたいだな、いつのまにか ...)。 waimea 使ったことないんで、このあたり RandR の動作とどういう風にすりあわせてるのかよく分からん。

fvwm で使うと、landscape から portrait に切替えた時に画面の再配置はない (これは仕方無い) ので、 右下隅にはっつけていた pager が portrait 時に画面外に出てしまうとかいう動作をするほか、 fvwm 自身は 横 640 の縦 480 的な画面と思っているらしく、上下方向の EdgeResistance を有効にしておくと edge 上から 480 ピクセル目あたりで window 移動が EdgeResistance 的にひっかかる動作をする。

X 的には正しく横 480 の縦 640 という扱いになっていて、X の draw や mouse の pointing はちゃんと動くが、 たとえば480 ピクセル目よりも下側で fvwm のメニューを出そうとすると fvwm 的な画面最下部、つまり上から 480 ピクセル目を メニュー下端とする位置にメニューがでる。

このままでもなんとか使えるような気もするし、やっぱもうすこし対応してほしいという気もするし、ってか。

Known bugs

バグとゆーか仕様とゆーか。

みっつ目のは window manager の設定のほうでなんとかするつもりでいたが、 考えるまでもなく xv みたいに中央/右が存在することを前提にする I/F のもあるから、 押せるようにはなってないといけないやね。

追記

キーリピートは致命的にすぎたので、さくっと直す。 よーするに A300 向けに K_RAW 使ってたところを K_MEDIUMRAW に戻しただけだが。 ん〜、A と C でバイナリを共通には出来んのか ...
X server のバイナリのみ:

補足: xmkmf が必要なもののコンパイル

追記と補足でどー違うんだというのはともかく ...

kterm など xmkmf が必要なもののクロスコンパイルについては

% cd kterm-6.2.0
% xmkmf /home/src/X/xc-20030614-k4/
% make
のようにターゲットの X のソースツリーを指定すると、その中の configuration を使って xmkmf してくれるようになる。 man xmkmf すると「だれも使ってねーよ、そんなの」とか書いてあるが、使えた :-)

まぁ、ふつーはぴろさん家の 「X11のコンパイル再び」にあるように、 xc/programs/ に付け加えてしまうのだろーな。

セルフの場合は、/usr/X11R6/lib/X11/config/ にバイナリ一式のをコピーしたあと、 host.def 中の CrossCompiling の項を "NO" にしておけば、セルフでふつーに xmkmf が使えるようになる。

追記、その2

箇条書にて。


[日記へ] [目次へ]