----- Forwarded message from thhsieh -----
Date: Fri, 18 Feb 2000 12:13:38 +0800
From: thhsieh
To: [EMAIL PROTECTED]
Subject: xcin-2.5 & OverTheSpot
X-Mailer: Mutt 1.0pre3us
Very sorry, 本來打算昨天晚上 post 的,結果直到現在才寫好,請大家參考。
Sorry again, 這真是篇又臭又長的文件,如果您對 OverTheSpot 沒興趣,請直
[EMAIL PROTECTED]@下,這對於我們 developemnt
應該是有幫助的。 :-))
[EMAIL PROTECTED]|再 post 專文討論 GUI Request API。
T.H.Hsieh
========================================================================
本文討論 xcin 與 OverTheSpot input style, winlist 架構,以及目前遭遇
的困鞋、有待完成的部分等等。
1. 什麼是 OverTheSpot?
[EMAIL PROTECTED] :-))
可能寫得不好,也請大家多多指點 :-))
在 XIM [EMAIL PROTECTED] input style 的「協定」,簡單講就是
XIM server 與 XIM client 之間要以怎麼樣的使用者介面展現給使用者。
XIM 支援的 input style 有很多種,但大體上可以分成 pre_edit area
(組字區) 與 status area (輸入法狀態區) 來談: 這兩個區域可以分別
(或同時) 在輸入法視窗上、或出現在您目前的游標附近、或 XIM client
[EMAIL PROTECTED] .... [EMAIL PROTECTED] style? 通常都是
當 XIM client 與 server 搭上線時,它先向 server 詢問有那些 style
[EMAIL PROTECTED] server 說指定要使用,二者達成協議
後即可上路。
在 xcin-2.5.2-pre1 之前, xcin [EMAIL PROTECTED] input style, 傳統上稱之
為 Root, 意思是 pre_edit area 與 status area 都在 xcin 視窗中:前
者即為視窗第二行那塊紅棕色的區域 (您所敲入的字鍵碼會依續出現,等
到敲完之後才會[EMAIL PROTECTED]) ,若遇到多重
字選擇時還會[EMAIL PROTECTED]
它們顯示了目前 xcin 所處的狀態。
而自 2.5.2-pre1 起,我們嘗試替 xcin [EMAIL PROTECTED] input style,傳統上
稱之為 OverTheSpot, 它的意思是 pre-edit area 會出現在您目前打字的
游標附近,而且是由 XIM server (即 xcin) [EMAIL PROTECTED]
視窗,而將 pre_edit area 中的資料顯示在那。此 input style 最大的好
處就是 pre_edit area 是跟著游標跑的,如此當您在打字時,您就不用眼
[EMAIL PROTECTED] xcin 視窗了。
2. 如何啟動 OverTheSpot?
原則上, xcin 還是以 Root input style 為主,預設是不啟動其他 style
的。如果您要啟動 OverTheSpot, 必須修改 xcinrc 檔:
(define INPUT_STYLE '(Root OverTheSpot))
如此當您在重新啟動 xcin 時,您會見到如下的訊息:
XCIN (Chinese XIM server) version xcin 2.5.2-pre1.
(module ver: 20000110, syscin ver: 20000210).
(use "-h" option for help)
xcin: XIM server "xcin" locale "zh_TW.Big5" transport "X/"
xcin: inp_styles: Root OverTheSpot
^^^^^^^^^^^^^^^^
這樣就表示成功啟動了。然而,是否接下來就使用 OverTheSpot 來輸入,還
得由 XIM client 來決定 (目前 xcin 不主動為 client 決定), client 還
是可以指定使用 Root 來輸入。但由於 OverTheSpot [EMAIL PROTECTED] style,
因此目前絕大部分的 XIM client 在對於使用優先順序上都是 OverTheSpot
大於 Root (通常 Root 都是排在最後的)。因此,如果您在 xcin 啟動它之
[EMAIL PROTECTED] XIM client 都會指定使用它。
3. 麻煩大了:
[EMAIL PROTECTED]: 在 XFree86-3.3.X 上 xcin 似乎完全不能使用
OverTheSpot, [EMAIL PROTECTED] xcin 的 OverTheSpot 啟動後, XIM
client [EMAIL PROTECTED]@剎那
(client 呼叫 XCreateIC 時) , xcin 卻再也無法接收來自 client 的訊息,
而 client 就直接 XCreateIC 失敗 (傳回 NULL)。這看起來有點像是, client
的訊息本來是要經過 Xlib 送達 xcin, 卻在中途失敗,彈了回來,因此就無
法使用 OverTheSpot。
這會有什麼後遺症呢?除了不能用 OverTheSpot 以外,以 rxvt-2.7.x 為例,
XCreateIC [EMAIL PROTECTED] xcin [EMAIL PROTECTED] Root
style 都不會去用,也就等於完全無法輸入中文。
當然,這也許是 rxvt [EMAIL PROTECTED]: 第
[EMAIL PROTECTED] style
指定失敗,就指定第二個,直到成功為止。但我擔心,可能沒有多
少個 XIM client 有考慮到這些。例如 Netscape, 也和 rxvt [EMAIL PROTECTED]
OverTheSpot
[EMAIL PROTECTED] xcin 斷訊了。
因此,就目前情況下啟動 xcin 的 OverTheSpot 反而會陷入很糟糕的問題,既
然絕大部分的 client 預設情況下都會指定使用 OverTheSpot, 偏偏在
XFree86-3.3.X 下 xcin 無法使用 OverTheSpot, [EMAIL PROTECTED]
client 就直接與 xcin 斷訊了,這就變成了: 在預設情況下大部分的 client
都無法接受來自 xcin 的輸入。
因此,在問題未克服之前,若您的系統跑的是 XFree86-3.3.X, 請不要啟動 xcin
的 OverTheSpot。
然而, PhantomCat 兄曾經向我回報: 在 XFree86-3.9.X (即 XFree86-4 的
pre-release) 下 xcin 可以使用 OverTheSpot。因此,如果您的系統是使用
XFree86-3.9.X 的話,您不妨可以試試,看是否正常,並請您向我們回報。
但奇怪的是,若使用其他的 XIM server (例如韓國的 ami), 它們的 OverTheSpot
在 XFree86-3.3.X 下可以跑得很好。我也比較過它與 xcin 的程式碼,發現
在處理 XIM 的部分大同小異,因此我不禁有點懷疑是不是 XFree86-3.3.X
的 XIM 或 Xi18n 的部分,在我們的 locale (zh_TW.Big5) 下有些地方會有
問題 ([EMAIL PROTECTED] CLE 及 Debian 中 patch lcGen 的部分嗎)?
如果是的話,表示 Xlib [EMAIL PROTECTED] patch, 這就必須再 trace Xlib 原始
碼才會知道了。
4. Winlist 架構:
因為我的機器還是跑 XFree86-3.3.6, 因此在寫 OverTheSpot 部分時,有點半
瞎子摸象在做,故寫出來的部分可能有問題,而且沒有寫完整,這需要使用
XFree86-3.9.X [EMAIL PROTECTED]
好讓有興趣幫忙的朋友容易 follow。
先前 PhantomCat 兄已寄給我許多 xcin + OverTheSpot 的修正 ([EMAIL PROTECTED]
他 :-))[EMAIL PROTECTED] code 整合到 xcin 的
winlist 中。 xcin 處理 GUI 部分的 source 為:
include/gui.h (definition of GUI and winlist data structer)
gui.c (GUI over all structer / tool functions)
gui_main.c (xcin main window)
gui_menusel.c (GUI Request Menu Selection window)
gui_overspot.c (OverTheSpot candidate window)
就 OverTheSpot 而言,其 GUI 的部分就全部集中在 gui_overspot.c 裏頭,
而這也是我尚未完成的地方。 gui_overspot.c 的內容如下 (其實 gui_main.c
與 gui_menusel.c 也是類似):
winlist_t *
gui_overspot_init(gui_t *gui, winlist_t *main_win, IM_Context_t *imc)
它用來產生 OverTheSpot 所需的視窗,並填好 winlist 的結構 (見 gui.h):
struct winlist_s {
Window window; /* The corresponding window */
unsigned int wid, imid, reqid;
byte_t winmap; /* 1: window is mapped
0: window is unmapped
-1: window is destoryed */
int pos_x, pos_y; /* The position of the window */
unsigned int width, height; /* Window size: in unit of pixels */
unsigned int c_width, c_height; /* Window size: in unit of English
characters */
void *data; /* Data for window drawing */
void (*win_draw_func)(gui_t *, winlist_t *);
/* Function to draw the window */
void (*win_attrib_func)(gui_t *, winlist_t *, XConfigureEvent *, int);
/* Function when XConfigureEvent received */
void (*win_destroy_func)(gui_t *, winlist_t *);
/* Function to destroy window */
winlist_t *next;
};
其中 wid 是此 Window 的 type, OverTheSpot 應設為 WID_OVERSPOT。 imid
是目前此 window 相當應該 IMC 號碼 (見後述), reqid 在這裏不需要用到,
那是給 GUI Request window 用的,故在此我們不管它。
當您要 Map window (顯示視窗) 與 Unmap window (隱藏視窗) 時,請呼叫
gui_winmap_change() 函式 (定義在 gui.c), 它會連同 winmap [EMAIL PROTECTED]
更新,同時要注意,如果 winmap 的值是 -1 時,請不要再對它做任何畫圖
或 change map [EMAIL PROTECTED] window 已被 destroy, 不存在了。
以下三個 function 分別是:
win_draw_func: [EMAIL PROTECTED]
窗時,請在此呼叫 gui_winmap_change。而用來畫視
窗所需的資料就在 data pointer 所指位置。
win_attrib_func: 當此視窗接到 XConfigureEvent 時 (如視窗被滑鼠
拖動,視窗被放大縮小 .... 等),這個函式就會被呼
叫,這時我們就可以用它來設定視窗新的 pos_x, pos_y,
width, height, etc.
win_destroy_func: 當此視窗被 destroy 時會被呼叫,這時我們可以用
[EMAIL PROTECTED]@ (如果需要的話)
其中 win_attrib_func 與 win_destroy_func 可以設為 NULL, 則 xcin
會以預設的方式來處理。
就 OverTheSpot 而言,我希望它的視窗是可以跟著輸入的游標跑,也就是說
它必須隨時改變位置,而且完全不受 Window Manager 的控制。因此,我用了
XChangeWindowAttributes() 來讓它擺脫 WM 的控制,如此,我們就無法用滑
鼠來移動它的位置、改變它的大小、以及將它關閉了。
而要讓它隨著游標移動,它必須隨時知道游標目前的位置,其位置是從 IMC
structer 的 spot_loc 傳入的 (見後述) ,因此,在其 win_draw_func 中,
它必須每次都檢查 spot_loc 的值,如果發現變動了,就要做 XMoveWindow 的
[EMAIL PROTECTED] XFree86-3.9.X 的朋友可以幫忙補足。
[EMAIL PROTECTED] xcin [EMAIL PROTECTED]
[EMAIL PROTECTED]: 該視窗只用來顯示組字狀態資料,因此,每當您
[EMAIL PROTECTED]|出現該視窗,而不會出現在 xcin 主視
[EMAIL PROTECTED]
則這些字也不會出現在 xcin 主視窗,而是出現在 OverTheSpot 視窗。在做多
重字選擇時,也是在 OverTheSpot 視窗中選擇。至於其他 xcin 的狀態資訊,
如 (英數)(全形)(半形) 等,則還是留在 xcin 主視窗中。另外,在 bimsphone
的自動選字模式下,所打出來的字不會馬上跑到 XIM client, 而會暫時留在
xcin buffer 中,這些字我還是顯示在 xcin [EMAIL PROTECTED]@樣,
而不顯示在 OverTheSpot 視窗中。原因是我覺得 OverTheSpot 視窗很小,而
且在輸入過程中是「若隱若現」的,因此不適合用來顯示 cache 的字。
事時上,在 OverTheSpot 模式中, xcin 主視窗是否存在已不重要了,重要的
反而是 OverTheSpot [EMAIL PROTECTED] xcin 可
[EMAIL PROTECTED] icon, 並在 icon 中顯示 (英數)(輸入法名)(全形)(半形) 等
資訊 (我覺得這還是有必要顯示的,可以讓使用者知道目前正在中文輸入狀態)。
但若要這樣寫的話要注意: 當游標在不同 XIM clients 間切換時, client A
是使用 Root, client B 則使用 OverTheSpot, xcin 必須要能自動還原或變成
icon, 這樣才能方便使用。這部分我沒去寫,我想相關的細節可以再討論。
在進入中文輸入模式時, OverTheSpot 視窗還是不會出現,要直到您開始輸入
[EMAIL PROTECTED]|[EMAIL PROTECTED]@個字後,它馬上又隱藏起來,
[EMAIL PROTECTED]@個字鍵時,它才會再出現。事實上,它只是做 Map
與 Unmap window [EMAIL PROTECTED] destroy 再重新 create。該 Window 的生
命期是與 IMC [EMAIL PROTECTED] (見後述)。
5. IC 與 IMC:
xcin-2.5.2 與 2.5.1 [EMAIL PROTECTED] winlist 架構 (2.5.1 無法開啟多
重視窗)[EMAIL PROTECTED] IC 與 IMC 分離的設計了 (2.5.1 只有 IC 而已)。而這
兩個也是我花最多心力的地方。
IC 是指 Input Context, [EMAIL PROTECTED] XIM client [EMAIL PROTECTED] Input
Context,
而在 xcin 這邊就會[EMAIL PROTECTED] IC 來做服務。每個 IC 都是完全獨
立的,這樣才能應付 clients 各 Input Contexts [EMAIL PROTECTED]
IMC 是指 Input Method Context, 它就是輸入法的實際資料結構。以前 IMC
的部分是直接寫在 IC 裏頭的,如此當您在用滑鼠切換 client 視窗時,xcin
視窗內容 (也就是各 IC 的輸入法目前狀態) 也跟著變。
然而,在某些情況下,我們不希望這樣,特別是在 bimsphone 輸入法上,我
們往往希望在切換 clients 時,輸入法的狀態不要改變,尤其是剛剛已輸入
到 xcin buffer 裏頭的那對字。為了達到此要求,才將 IMC 部分自 IC 中分
離。
現在 xcin 有兩種 mode: XCIN_SINGLE_IMC ON 及 XCIN_SINGLE_IMC OFF。在
XCIN_SINGLE_IMC OFF 時,每個 IC 都各自會[EMAIL PROTECTED] IMC, 於是各 client
間
的輸入法狀態就完全獨立。若 XCIN_SINGLE_IMC ON 時,所有的 IC 都會分享
[EMAIL PROTECTED] IMC, 於是各 client [EMAIL PROTECTED]
IC 有它的生命週期,這與 client 的 Input Context [EMAIL PROTECTED]@個
新的 client Input Context 產生時, xcin [EMAIL PROTECTED] IC, 而當
client 的 Input Context 結束後, xcin 這邊的 IC 也結束了。
IMC 也有它的生命週期,但視 xcin 所處的 mode 而定。如果是 XCIN_SINGLE_IMC
ON 時,它的生命週期就與 xcin [EMAIL PROTECTED] XCIN_SINGLE_IMC OFF
時,它的生命週期就與 IC [EMAIL PROTECTED]
就 OverTheSpot 而言,我認為它應該是屬於 IMC 管理的,而非 IC, 例如在
XCIN_SINGLE_IMC ON 下,所有的 IC [EMAIL PROTECTED]
始在 client 視窗 A 打字, OverTheSpot window 也出現在視窗 A 的游標附
近,如果我們臨時換到視窗 B 打字時,我希望 OverTheSpot window 可以原
封不動地移位到視窗 B 的游標位置,而非視窗 A 那個 OverTheSpot window
消失,視窗 B [EMAIL PROTECTED] OverTheSpot window (這應該是在
XCIN_SINGLE_IMC OFF 的情況下)。因此,我才決定將 OverTheSpot 歸於 IMC
來管理。因此,它的生命週期要與 IMC [EMAIL PROTECTED]
但是,我剛剛才看到,目前我的寫法是不管 xcin mode 如何, OverTheSpot
的生命週期與 IC [EMAIL PROTECTED]|將它改過來 (見 xim_IC.c
ic_destroy(), 當 xccore->gui.winchange |= WIN_CHANGE_OVERSPOT_END 時,
就是通知 該 IC 底下的 IMC 底下的 OverTheSpot window 要 destroy 了)。
[EMAIL PROTECTED] IMC 的狀態: inp_state (見 include/IC.h), 這裏要很小心
處理。它可以有如下幾個狀態:
IM_CINPUT ON: 此 IMC 進入中文輸入模式
IM_CINPUT OFF: 此 IMC 處於英文輸入模式
IM_2BYTES ON: 此 IMC 進入全形輸入模式
IM_2BYTES OFF: 此 IMC 處於半形輸入模式
IM_XIMFOCUS ON: 此 IMC 所處 IC 進入 focus 狀態
IM_XIMFOCUS OFF:此 IMC 所處 IC 離開 focus 狀態
這裏討論 IM_CINPUT 與 IM_XIMFOCUS 就好,IM_2BYTES 原理與 IM_CINPUT 類
似。所謂 IC 進入 focus 狀態,是指該 IC 所對應的 XIM client 視窗被滑鼠
點選,成為前景視窗,接下來鍵盤打字就會[EMAIL PROTECTED] client 視窗上。因此:
client 為前景視窗時但處於英文輸入時,則它的 IMC 狀態就是
IM_CINPUT OFF, IM_XIMFOCUS ON
client 為前景視窗時但處於中文輸入時,則它的 IMC 狀態就是
IM_CINPUT ON, IM_XIMFOCUS ON
client 不是前景視窗時但處於中文輸入時,則它的 IMC 狀態就是
IM_CINPUT ON, IM_XIMFOCUS OFF
就 OverTheSpot 視窗而言,我希望在它所屬的 IC 是在 focus 狀態,而
且其 IMC 進入中文輸入時,它才會[EMAIL PROTECTED] focus 改變,或變回英文
輸入時,它就要隱藏起來。這就是為什麼我在 gui_overspot_draw() (見
gui_overspot.c) [EMAIL PROTECTED] check 的原因。
最後談到 spot location 的部分。前面有稍微提到, client 的游標若移
動,則它會馬上將目前的游標位置傳給 xcin, 而 xcin 就會將它放在 spot
location 中供 OverTheSpot 使用。 spot location 分別在 IC 與 IMC 中
[EMAIL PROTECTED] (見 include/IC.h):
IC->pre_attr.spot_location
IMC->spot_loc
事實上,我覺得 spot location 只要存在 IMC 裏頭就好了,但之所以這樣
做的考量如下: 在 XCIN_SINGLE_IMC ON 狀態下,我本來是 focus 在 client A,
現在改 focus 在 client B,然而 client B 在進入 focus 時並沒有通知 xcin
它目前的游標位置 (它可能認為先前已通知過了),會發生什麼事呢?結果我猜
是,該 OverTheSpot 可能還會留在 client A 的游標位置,甚至可能是: client
A [EMAIL PROTECTED] client B 因為在前景正接受輸入中,結
果 OverTheSpot window 就這樣在 client A B 之間快速地跳來跳去。
因此,目前我的設計是,當 xcin [EMAIL PROTECTED] client
新的游標位置,它就存到 IC
的 spot location 中,若目前此 IC 正處於 focus [EMAIL PROTECTED]
前它所使用的 IMC 的 spot location 去, 而 OverTheSpot window 永遠只參考
IMC 的 spot location 來移動視窗。如此,各 IC 可以隨時追蹤其 client 的
游標位置,而 OverTheSpot window 中位隨著目前 focus 中的 client 的游標
移動。
啊! [EMAIL PROTECTED] bug, 我目前的程式沒有這樣寫,當 IC [EMAIL PROTECTED]
spot
location 時,馬上會[EMAIL PROTECTED] IMC, 結果就會[EMAIL PROTECTED] IC 這
[EMAIL PROTECTED] flag, 以標示目前它是否處於 focus 狀態才行 (目前沒有),
[EMAIL PROTECTED]|改過來。
6. 結語:
我在寫 OverTheSpot 部分時,是在 Root input style 底下做的,由於 spot
location 永遠都固定,所以 OverTheSpot window 自然不會隨著游標跑,也難
以鑑別各 client 間 focus 切換對 OverTheSpot window 的影響,所以等於是
瞎子模象在寫程式。我希望使用 XFree86-3.9.X 的朋友可以幫忙完成我未完成
的部分,並幫忙測試。
同時,我也歡迎高手們幫忙追查 XFree86-3.3.X 無法使用 xcin OverTheSpot
的真正原因,必竟目前絕大部分的 GNU/Linux 與 FreeBSD 系統都還在跑
XFree86-3.3.X, 如果它不 work, 我們現在做這 OverTheSpot 也是枉然的。
我很希望大家都能輕易使用它,享受它所帶來的便利。
T.H.Hsieh
----- End forwarded message -----