2009年03月08日

セレクション送信も実装

テキストのセレクション送信もほぼわかり一通り実装できた。
あとついでにxlibでwindowを出す場合、そのままwmまかせで閉じるとエラーが出るので
処理コードを入れた。
送信用にはAtom構造体の配列が必要なので昨日とは変数名を変えた。


Atom atom_wm;
Atom atom_sel[3];
XTextProperty prop_s,prop_r,ttl_prop;
XSelectionEvent sel_vnt;

int do_loop;
char *title1="セレクションの実験";
char *title2="sel-test";


一応書いておくと

Display *dpy;
Window win;
int s;
XEvent evt;

この辺はもう変えない。

selection用のAtomは


atom_sel[0] = XInternAtom (dpy, "TARGETS", False);
atom_sel[1] = XInternAtom (dpy, "COMPOUND_TEXT", False);
atom_sel[2] = XInternAtom (dpy, "__COPY_TEXT", False);

と事前に作っておく


アプリケーションがセレクションをしたとXに通知するコードがこれ

XSetSelectionOwner (dpy, XA_PRIMARY, win,CurrentTime);
if (XGetSelectionOwner (dpy, XA_PRIMARY) == win)
{
//puts("selection");
}

汎用性をみてCurrentTimeとしたが
時間はevt.xbutton.timeなどの方がパラメータなのでコストが安い。

この命令はエディターなどでマウスを動かす度にじりじり出してもいいが
マウスドラッグが終了したら一度だけ出せばいいのだろう。
putsに相当する所の処理はあまりない。

セレクションして成功するとSelectionRequestがイベントとしてやってくる。
そこでの処理は以下のようにした。

case SelectionRequest:
{
prop_s.value = NULL;
sel_vnt.type = SelectionNotify;
sel_vnt.requestor = evt.xselectionrequest.requestor;
sel_vnt.selection = evt.xselectionrequest.selection;
sel_vnt.target = evt.xselectionrequest.target;
sel_vnt.time = evt.xselectionrequest.time;
sel_vnt.property = evt.xselectionrequest.property;

if (evt.xselectionrequest.selection == XA_PRIMARY)
if (evt.xselectionrequest.target == atom_sel[0]) {

XChangeProperty (dpy, sel_vnt.requestor, sel_vnt.property, XA_ATOM,
32, PropModeReplace, atom_sel, 2);
}

else if (evt.xselectionrequest.target == atom_sel[1]) {

XmbTextListToTextProperty (dpy, &string, 1, XCompoundTextStyle,
&prop_s);
XChangeProperty (dpy, sel_vnt.requestor, sel_vnt.property, sel_vnt.target,
8, PropModeReplace, prop_s.value, prop_s.nitems);
}

else
sel_vnt.property = None;

XSendEvent (dpy, sel_vnt.requestor, False, NULL, &sel_vnt);
if (prop_s.value)
XFree (prop_s.value);
}
break;

XmbTextListToTextPropertyでchar型の文字列をXTextPropertyに変換し
XSendEventでXSelectionEventを送信するという形にしている。
XChangePropertyで使いまわしているAtom型を2つまとめた配列を送っているので
Atom型の構造体は昨日のものと替えたわけだ。

これで昨日の受信と合わせて送受信ができそうなものだがもう一つ必要なものがある。
それは自分が確保したselectionを別のプログラムを取ったことを知ることだ。

これはSelectionClearイベントとして通知される。


case SelectionClear:

if (evt.xselectionclear.window == win &&
evt.xselection.selection == XA_PRIMARY) {
// puts("selection clear");
//system("espeak -v m2 -p 100 -s 120 'selection clear'&");
}
break;


これらのコードでセレクションによるテキストのプライマリ化と送信
そしてセレクションの外部クリアと受け取りができた。

今回XTextPropertyというものを触るようになったのでWindowにタイトルを出そうと思った。


XStoreName(dpy, win, "Window Title");
XSetIconName(dpy, win, "Icon Title");

の様にできるのだがこれだと日本語が出ない。


XmbTextListToTextProperty(dpy,&title1,1,XCompoundTextStyle,&ttl_prop);
XSetWMName(dpy,win,&ttl_prop);

XmbTextListToTextProperty(dpy,&title2,1,XCompoundTextStyle,&ttl_prop);
XSetWMIconName(dpy,win,&ttl_prop);

とすることで日本語のタイトルがだせた。
もっともIconNameの方はどこに出るのか確認できていない。

次にeventループ内で終了するときちんと終わるのにWindowのメニューから終了すると

XIO: fatal IO error 35 (Resource temporarily unavailable) on X server ":0.0"


とか言われるので

atom_wm = XInternAtom( dpy, "WM_DELETE_WINDOW", True );
XSetWMProtocols( dpy, win, &atom_wm, 1 );

と宣言しておいて
イベントループに

case ClientMessage :
if ( evt.xclient.data.l[0] == atom_wm ) {

do_loop = 1;
}
break;
}

と終了フラグを立てる。

このフラグはイベントループを

do_loop = 1;
while(do_loop) {

とすることで機能する。


case KeyPress:
XLookupString( &( evt.xkey ),
NULL, 0, &key_sym, NULL );

switch ( key_sym ) {
case XK_Escape:
do_loop = 0;
break;
}


といれることでエスケープキー限定で終了することができる。
キー入力は先々日のコードを使った方が余計な処理が少ない分
多分処理は速いのだろうけれどKeyPressとKeyReleaseでフラグを立てやすい
イベントループで通常の場合は充分だろう。


posted by Xo_ox at 22:56| Comment(0) | FreeBSDアプリ | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。