1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
.TH xcb-requests 3 2011-12-11 "XCB" "XCB examples"
.ad l
.SH NAME
xcb-requests \- about request manpages
.SH DESCRIPTION
Every request in X11, like \fIMapWindow\fP, corresponds to a number of
functions and data structures in XCB. For \fIMapWindow\fP, XCB provides the
function \fIxcb_map_window\fP, which fills the \fIxcb_map_window_request_t\fP
data structure and writes that to the X11 connection. Since the \fIMapWindow\fP
request does not have a reply, this is the most simple case.
.SH REPLIES
Many requests have replies. For each reply, XCB provides at least a
corresponding data structure and a function to return a pointer to a filled
data structure. Let's take the \fIInternAtom\fP request as an example: XCB
provides the \fIxcb_intern_atom_reply_t\fP data structure and
\fIxcb_intern_atom_reply\fP function. For replies which are more complex (for
example lists, such as in \fIxcb_list_fonts\fP), accessor functions are
provided.
.SH COOKIES
XCB returns a cookie for each request you send. This is an XCB-specific data
structure containing the sequence number with which the request was sent to the
X11 server. To get any reply, you have to provide that cookie (so that XCB
knows which of the waiting replies you want). Here is an example to illustrate
the use of cookies:
.nf
.sp
void my_example(xcb_connection *conn) {
xcb_intern_atom_cookie_t cookie;
xcb_intern_atom_reply_t *reply;
cookie = xcb_intern_atom(conn, 0, strlen("_NET_WM_NAME"), "_NET_WM_NAME");
/* ... do other work here if possible ... */
if ((reply = xcb_intern_atom_reply(conn, cookie, NULL))) {
printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
}
free(reply);
}
.fi
.SH CHECKED VS. UNCHECKED
The checked and unchecked suffixes for functions determine which kind of error
handling is used for this specific request.
For requests which have no reply (for example \fIxcb_map_window\fP), errors
will be delivered to the event loop (you will receive an X11 event of type 0
when calling \fIxcb_poll_for_event\fP).
If you want to explicitly check for errors in a blocking fashion, call the
_checked version of the function (for example \fIxcb_map_window_checked\fP) and
use \fIxcb_request_check\fP.
For requests which have a reply (for example \fIxcb_intern_atom\fP), errors
will be checked when calling the reply function. To get errors in the event
loop instead, use the _unchecked version of the function (for example
\fIxcb_intern_atom_unchecked\fP).
Here is an example which illustrates the four different ways of handling errors:
.nf
.sp
/*
* Request without a reply, handling errors in the event loop (default)
*
*/
void my_example(xcb_connection *conn, xcb_window_t window) {
/* This is a request without a reply. Errors will be delivered to the event
* loop. Getting an error to xcb_map_window most likely is a bug in our
* program, so we don't need to check for that in a blocking way. */
xcb_map_window(conn, window);
/* ... of course your event loop would not be in the same function ... */
while ((event = xcb_wait_for_event(conn)) != NULL) {
if (event->response_type == 0) {
fprintf("Received X11 error %d\\n", error->error_code);
free(event);
continue;
}
/* ... handle a normal event ... */
}
}
/*
* Request without a reply, handling errors directly
*
*/
void my_example(xcb_connection *conn, xcb_window_t deco, xcb_window_t window) {
/* A reparenting window manager wants to know whether a new window was
* successfully reparented. If not (because the window got destroyed
* already, for example), it does not make sense to map an empty window
* decoration at all, so we need to know this right now. */
xcb_void_cookie_t cookie = xcb_reparent_window_checked(conn, window,
deco, 0, 0);
xcb_generic_error_t *error;
if ((error = xcb_request_check(conn, cookie))) {
fprintf(stderr, "Could not reparent the window\\n");
free(error);
return;
}
/* ... do window manager stuff here ... */
}
/*
* Request with a reply, handling errors directly (default)
*
*/
void my_example(xcb_connection *conn, xcb_window_t window) {
xcb_intern_atom_cookie_t cookie;
xcb_intern_atom_reply_t *reply;
xcb_generic_error_t *error;
cookie = xcb_intern_atom(c, 0, strlen("_NET_WM_NAME"), "_NET_WM_NAME");
/* ... do other work here if possible ... */
if ((reply = xcb_intern_atom_reply(c, cookie, &error))) {
printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
free(reply);
} else {
fprintf(stderr, "X11 Error %d\\n", error->error_code);
free(error);
}
}
/*
* Request with a reply, handling errors in the event loop
*
*/
void my_example(xcb_connection *conn, xcb_window_t window) {
xcb_intern_atom_cookie_t cookie;
xcb_intern_atom_reply_t *reply;
cookie = xcb_intern_atom_unchecked(c, 0, strlen("_NET_WM_NAME"),
"_NET_WM_NAME");
/* ... do other work here if possible ... */
if ((reply = xcb_intern_atom_reply(c, cookie, NULL))) {
printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
free(reply);
}
/* ... of course your event loop would not be in the same function ... */
while ((event = xcb_wait_for_event(conn)) != NULL) {
if (event->response_type == 0) {
fprintf("Received X11 error %d\\n", error->error_code);
free(event);
continue;
}
/* ... handle a normal event ... */
}
}
.fi
.SH SEE ALSO
.BR xcb_map_window (3),
.BR xcb_intern_atom (3),
.BR xcb_list_fonts (3),
.BR xcb_poll_for_event (3),
.BR xcb_request_check (3)
.SH AUTHOR
Michael Stapelberg <michael+xcb at stapelberg dot de>
|