X エラー
X でエラーが出た時の処理について説明します。
X でエラーが出た場合 (引数の値が正しくないなど)、デフォルトのハンドラによってエラーメッセージが表示された後、プログラムが強制終了してしまいます。
致命的ではないエラーの場合もこのような処理になってしまうので、X のエラーはクライアント側で処理するべきです。
特に、ウィンドウマネージャが関わる部分では、致命的ではないエラーが発生することがあります。
X でエラーが出た場合 (引数の値が正しくないなど)、デフォルトのハンドラによってエラーメッセージが表示された後、プログラムが強制終了してしまいます。
致命的ではないエラーの場合もこのような処理になってしまうので、X のエラーはクライアント側で処理するべきです。
特に、ウィンドウマネージャが関わる部分では、致命的ではないエラーが発生することがあります。
エラーハンドラ
X のエラーを自分で処理したい場合は、エラーハンドラを設定します。
XSetErrorHandler() は、プロトコルエラーを処理するハンドラを設定します。
XSetIOErrorHandler() は、致命的な I/O エラーを処理するハンドラを設定します。
両方とも、以前に設定されていたハンドラのポインタが返ります。
XErrorHandler XSetErrorHandler(XErrorHandler handler); XIOErrorHandler XSetIOErrorHandler(XIOErrorHandler handler); typedef int (*XErrorHandler)(Display *display, XErrorEvent *error_event); typedef int (*XIOErrorHandler)(Display *display);
XSetErrorHandler() は、プロトコルエラーを処理するハンドラを設定します。
XSetIOErrorHandler() は、致命的な I/O エラーを処理するハンドラを設定します。
両方とも、以前に設定されていたハンドラのポインタが返ります。
XSetIOErrorHandler
XSetIOErrorHandler() で設定したハンドラは、致命的なエラーが起こった時に呼ばれるので、ハンドラ関数内で強制終了するべきです。
ハンドラ関数から戻った場合、クライアントのプロセスは終了します。
これはデフォルトのハンドラのままでも構いません。
ハンドラ関数から戻った場合、クライアントのプロセスは終了します。
これはデフォルトのハンドラのままでも構いません。
XSetErrorHandler
XSetErrorHandler() で設定したハンドラは、引数の値が正しくないなどの、致命的ではないエラーの時に呼ばれるので、ハンドラ関数から戻ってこれます。
その場合、ハンドラ関数の戻り値は無視されます。
XErrorEvent 構造体に、エラーに関する情報が入っています。
その場合、ハンドラ関数の戻り値は無視されます。
XErrorEvent 構造体に、エラーに関する情報が入っています。
typedef struct { int type; Display *display; unsigned long serial; unsigned char error_code; unsigned char request_code; unsigned char minor_code; XID resourceid; } XErrorEvent;
serial | X サーバーと接続した後、ネットワーク接続を介して送信されたリクエストの数 (1〜)。 失敗した呼び出しが行われる直前の、NextRequest(display) の値。 |
---|---|
error_code | エラーコード。以下のいずれか。 (拡張機能のエラーの場合、追加のエラーコードが存在する場合があります) BadAccess, BadAlloc, BadAtom, BadColor, BadCursor, BadDrawable BadFont, BadGC, BadIDChoice, BadImplementation, BadLength BadMatch, BadName, BadPixmap, BadRequest, BadValue, BadWindow |
request_code | <X11/Xproto.h> で定義されている、失敗したプロトコルリクエスト番号 |
minor_code | 拡張機能時のマイナー番号 |
resourceid | ウィンドウなどのリソースID |
エラー関連の文字列取得
エラーコードから文字列取得
void XGetErrorText(Display *display, int code, char *buffer_return, int length);
XErrorEvent の error_code から、説明文字列を取得します。
返されるテキストは、現在のロケールのエンコーディングです。
エラーメッセージデータベースから取得
void XGetErrorDatabaseText(Display *display, char *name, char *message, char *default_string, char *buffer_return, int length);
エラーメッセージデータベースから、error_code, request_code, minor_code の値を使って、メッセージを取得します。
name | 取得する情報を文字列で指定します。 "XlibMessage" : ライブラリによって内部的に使用されるメッセージ文字列。 "XProtoError" : message は、プロトコルエラー番号 (XGetErrorText と同じ)。 "XRequest" : コアのプロトコルリクエストの場合、message はメジャーリクエスト番号。 拡張機能の場合、message は「InitExtension によって指定される拡張名」 + 「ピリオド (.)」 + 「マイナープロトコル番号」。 |
---|---|
message | name ごとの情報を、文字列で指定します。 |
default_string | データベースに見つからなかった場合の、デフォルトのメッセージ |
プログラム
存在しないウィンドウを削除しようとして、エラーが表示されます。
<09-error.c>
XDestroyWindow() で正しくない Window 値を指定しているので、X_DestroyWindow のリクエストで、BadWindow エラーが起こっています。
<09-error.c>
#include <stdio.h> #include <X11/Xlib.h> static int _xerr_handle(Display *display,XErrorEvent *ev) { char m[256],no[16]; printf("--- X error ---\n" "type(%d) serial(%lu) error_code(%d)\n" "request_code(%d) minor_code(%d) resourceid(%lu)\n\n", ev->type, ev->serial, ev->error_code, ev->request_code, ev->minor_code, ev->resourceid); XGetErrorText(display, ev->error_code, m, 256); printf("[Error] %s\n", m); snprintf(no, 16, "%d", ev->request_code); XGetErrorDatabaseText(display, "XRequest", no, "default error", m, 256); printf("[Request] %s\n", m); return 1; } int main(int argc,char **argv) { Display *disp; disp = XOpenDisplay(NULL); if(!disp) return 1; XSetErrorHandler(_xerr_handle); XDestroyWindow(disp, 0); XCloseDisplay(disp); return 0; }
--- X error --- type(0) serial(7) error_code(3) request_code(4) minor_code(0) resourceid(0) [Error] BadWindow (invalid Window parameter) [Request] X_DestroyWindow
XDestroyWindow() で正しくない Window 値を指定しているので、X_DestroyWindow のリクエストで、BadWindow エラーが起こっています。