ICCCM
X のデスクトップに関する、基本的なクライアント間通信の仕様は、「Inter-Client Communication Conventions Manual (ICCCM)」と「Extended Window Manager Hints (NetWM)」によって定義されています。
ウィンドウマネージャと各クライアントの双方が、この仕様に基づく方法で実装を行うことにより、拡張されたデスクトップ操作を実現することができます。
NetWM は ICCCM を拡張する形で定義されているので、まずは ICCCM について説明します。
ICCCM の仕様はこちらにあります。
https://www.x.org/releases/current/doc/xorg-docs/icccm/icccm.html
ウィンドウマネージャと各クライアントの双方が、この仕様に基づく方法で実装を行うことにより、拡張されたデスクトップ操作を実現することができます。
NetWM は ICCCM を拡張する形で定義されているので、まずは ICCCM について説明します。
ICCCM の仕様はこちらにあります。
https://www.x.org/releases/current/doc/xorg-docs/icccm/icccm.html
プロパティ
クライアントは、ICCCM が定義しているプロパティを、あらかじめウィンドウにセットしておくことで、自身が望むウィンドウ動作を、ウィンドウマネージャに通知することができます。
設定されていないプロパティに関しては、ウィンドウマネージャによって、デフォルトの値が使用されます。
この場合のプロパティは、一度の XChangeProperty() で、mode = PropModeReplace によってセットする必要があります。
大きなサイズのデータを除き、複数回に分割してデータを送るようなことは、基本的にしないでください。
(ウィンドウマネージャ側で、PropertyNotify イベントにより、プロパティの変更を監視している場合があるので、一度のプロパティ変更で、すべてのデータを取得できるようにする必要があります)
設定されていないプロパティに関しては、ウィンドウマネージャによって、デフォルトの値が使用されます。
この場合のプロパティは、一度の XChangeProperty() で、mode = PropModeReplace によってセットする必要があります。
大きなサイズのデータを除き、複数回に分割してデータを送るようなことは、基本的にしないでください。
(ウィンドウマネージャ側で、PropertyNotify イベントにより、プロパティの変更を監視している場合があるので、一度のプロパティ変更で、すべてのデータを取得できるようにする必要があります)
TEXT タイプの文字列
ウィンドウのタイトルバーに表示する文字列などでは、TEXT タイプのプロパティを設定する必要があります。
この場合、TEXT は、複数のエンコーディングに対応した、一般的な文字列を示すものです。
実際のプロパティのタイプは、エンコーディングによって、"STRING", "COMPOUND_TEXT" などになります。
TEXT タイプで設定すると明示された文字列は、XmbTextListToTextProperty() などで値をセットした XTextProperty 構造体を使って、XSetTextProperty 関数でプロパティに設定する必要があります。
以下の関数や構造体は、<X11/Xutil.h> で定義されています。
TEXT タイプ用のプロパティデータです。
解放時は、value ポインタを XFree() で解放する必要があります。
複数の文字列がある場合は、ヌル区切りになります。
エンコーディングによって、実際のデータは異なります。
Xmb は現在のロケールでのマルチバイト文字列のリストから、Xwc はワイド文字列のリストから、プロパティを設定するための XTextProperty 構造体にデータをセットします。
※Xmb の場合は、あらかじめ C ロケールをセットしている必要があります。
Xutf8 は、XFree86 による拡張で、UTF-8 文字列から変換します。X.Org の実装でも使用できますが、他の実装で使えるかはわかりません。
基本的に、通常のラテン文字しか含まれていなければ XStringStyle、日本語などを含む場合は、マルチエンコーディングに対応している XCompoundTextStyle、自動で判断させたい場合は XStdICCTextStyle を指定します。
XTextProperty 構造体の値を元に、ウィンドウのプロパティにデータをセットします。
この場合、TEXT は、複数のエンコーディングに対応した、一般的な文字列を示すものです。
実際のプロパティのタイプは、エンコーディングによって、"STRING", "COMPOUND_TEXT" などになります。
TEXT タイプで設定すると明示された文字列は、XmbTextListToTextProperty() などで値をセットした XTextProperty 構造体を使って、XSetTextProperty 関数でプロパティに設定する必要があります。
以下の関数や構造体は、<X11/Xutil.h> で定義されています。
XTextProperty 構造体
typedef struct { unsigned char *value; //プロパティデータ Atom encoding; //エンコーディング (プロパティのタイプ) int format; //8,16,32 unsigned long nitems; //データの個数 } XTextProperty;
TEXT タイプ用のプロパティデータです。
解放時は、value ポインタを XFree() で解放する必要があります。
複数の文字列がある場合は、ヌル区切りになります。
エンコーディングによって、実際のデータは異なります。
文字列から、XTextProperty 構造体にデータをセット
int XmbTextListToTextProperty(Display *display, char **list, int count, XICCEncodingStyle style, XTextProperty *text_prop_return); int XwcTextListToTextProperty(Display *display, wchar_t **list, int count, XICCEncodingStyle style, XTextProperty *text_prop_return); //XFree86 拡張 int Xutf8TextListToTextProperty(Display *display, char **list, int count, XICCEncodingStyle style, XTextProperty *text_prop_return); typedef enum { XStringStyle, // STRING (ラテン文字) XCompoundTextStyle, // COMPOUND_TEXT (マルチエンコーディング) XTextStyle, // TEXT (現在のロケール) XStdICCTextStyle, // STRING。変換できなければ COMPOUND_TEXT XUTF8StringStyle // UTF8_STRING (XFree86 による拡張) } XICCEncodingStyle; #define XNoMemory -1 #define XLocaleNotSupported -2 #define XConverterNotFound -3
Xmb は現在のロケールでのマルチバイト文字列のリストから、Xwc はワイド文字列のリストから、プロパティを設定するための XTextProperty 構造体にデータをセットします。
※Xmb の場合は、あらかじめ C ロケールをセットしている必要があります。
Xutf8 は、XFree86 による拡張で、UTF-8 文字列から変換します。X.Org の実装でも使用できますが、他の実装で使えるかはわかりません。
list | 文字列のリスト (char * の配列) |
---|---|
count | 文字列の数 |
style | 変換後のエンコーディングタイプ |
戻り値 | Success で成功。 XNoMemory でメモリが足りない。 XLocaleNotSupported で、現在のロケールが X でサポートされていない。 |
基本的に、通常のラテン文字しか含まれていなければ XStringStyle、日本語などを含む場合は、マルチエンコーディングに対応している XCompoundTextStyle、自動で判断させたい場合は XStdICCTextStyle を指定します。
XTextProperty 構造体の値をプロパティにセット
void XSetTextProperty(Display *display, Window w, XTextProperty *text_prop, Atom property);
XTextProperty 構造体の値を元に、ウィンドウのプロパティにデータをセットします。
プロパティ
ICCCM で定義されている、テキストに関するプロパティには、以下があります。
なお、Xlib には、ICCCM 用のプロパティを簡単に設定するための関数が存在します (X11/Xutil.h)。
char * で文字列を指定する場合、対応しているのはラテン文字のみ (STRING タイプ) です。
なお、Xlib には、ICCCM 用のプロパティを簡単に設定するための関数が存在します (X11/Xutil.h)。
char * で文字列を指定する場合、対応しているのはラテン文字のみ (STRING タイプ) です。
WM_NAME (TEXT)
タイトルバーなどに表示される、アプリケーションの名前。
void XSetWMName(Display *display, Window w, XTextProperty *text_prop); void XStoreName(Display *display, Window w, char *window_name);
WM_ICON_NAME (TEXT)
アイコン化されている時に表示される、アプリケーションの名前。
最小化している時に表示されるとは限りません。
最小化している時に表示されるとは限りません。
void XSetWMIconName(Display *display, Window w, XTextProperty *text_prop); void XSetIconName(Display *display, Window w, char *icon_name);
WM_CLIENT_MACHINE (TEXT)
サーバーを実行しているマシンから見た時の、クライアントを実行しているマシンの名前。
Unix 系であれば、gethostname() で取得できるホスト名を指定します。
Unix 系であれば、gethostname() で取得できるホスト名を指定します。
void XSetWMClientMachine(Display *display, Window w, XTextProperty *text_prop);
WM_CLASS (STRING)
WM_CLASS プロパティには、ヌルで終わる2つの文字列を設定します。
1つ目がアプリケーションのリソース名、2つ目がアプリケーションのクラス名です。
リソース名は、X リソースから値を取得する時に使われます。
基本的には、どちらもアプリケーション名を設定すれば問題ありません。
XSetClassHint(Display *display, Window w, XClassHint *class_hints); typedef struct { char *res_name; char *res_class; } XClassHint;
1つ目がアプリケーションのリソース名、2つ目がアプリケーションのクラス名です。
リソース名は、X リソースから値を取得する時に使われます。
基本的には、どちらもアプリケーション名を設定すれば問題ありません。
プログラム
WM_NAME と WM_ICON_NAME のテキストをセットします。
ソースコードは UTF-8 であるとみなして、Xutf8TextListToTextProperty() を使用しています。
<d02-text.c>
問題がなければ、ウィンドウのタイトルバーなどに、指定されたテキストが表示されていると思います。
NetWM の場合は、プロパティに UTF-8 の文字列をセットすることができるので、通常はそちらを使います。
ただし、NetWM を実装していないウィンドウマネージャに対応するためには、この方法でも設定しておく必要があります。
ソースコードは UTF-8 であるとみなして、Xutf8TextListToTextProperty() を使用しています。
<d02-text.c>
#include <X11/Xlib.h> #include <X11/Xutil.h> #include "util.h" /* 文字列から TEXT タイプのプロパティをセット */ static void _set_text_prop(Display *disp,Window win,Atom prop,const char *str) { XTextProperty text; if(Xutf8TextListToTextProperty(disp, (char **)&str, 1, XCompoundTextStyle, &text) == Success) { XSetTextProperty(disp, win, &text, prop); XFree(text.value); } } int main(int argc,char **argv) { Display *disp; Window win; disp = XOpenDisplay(NULL); if(!disp) return 1; win = create_test_window(disp, ButtonPressMask); _set_text_prop(disp, win, XInternAtom(disp, "WM_NAME", False), "テスト(Normal)"); _set_text_prop(disp, win, XInternAtom(disp, "WM_ICON_NAME", False), "テスト(Icon)"); //イベント XMapWindow(disp, win); eventloop_button_quit(disp); XCloseDisplay(disp); return 0; }
問題がなければ、ウィンドウのタイトルバーなどに、指定されたテキストが表示されていると思います。
NetWM の場合は、プロパティに UTF-8 の文字列をセットすることができるので、通常はそちらを使います。
ただし、NetWM を実装していないウィンドウマネージャに対応するためには、この方法でも設定しておく必要があります。