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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
// MIT/Apache2 License
//! [In the last tutorial](../intro/index.html), we reached an elementary understanding of how the X protocol works. In this
//! tutorial, we'll open a connection to the X server and create a window.
//!
//! # Setting up the Environment
//!
//! We'll use a basic Rust executable environment to build our examples. First, we create the project folder
//! by running the following command:
//!
//! ```bash
//! $ cargo new --bin example
//! $ cd example
//! ```
//!
//! Then, we configure the `Cargo.toml` file to automatically download `breadx` and its dependencies. Under the
//! `[dependencies]` header in the `Cargo.toml` file, add:
//!
//! ```plaintext
//! breadx = "0.1.0"
//! ```
//!
//! # Writing the Program
//!
//! With this current setup, anything we write in `src/main.rs` will be executed whenever the crate is compiled
//! and run. Let's see what we have to do.
//!
//! The [`DisplayConnection`](../../display/type.DisplayConnection.html) object is the liason to the X11 server.
//! Not only does it create and manage the connection, it stores information regarding the hardware and server.
//! To create the object, one must call [`DisplayConnection::create`](../../display/type.DisplayConnection.html#method.create).
//!
//! *In src/main.rs*
//!
//! ```no_run
//! use breadx::{BreadError, DisplayConnection};
//!
//! fn main() -> Result<(), BreadError> {
//! let mut conn = DisplayConnection::create(None, None)?;
//!
//! Ok(())
//! }
//! ```
//!
//! <div class="dissecting">
//! <h2>Dissecting `DisplayConnection::create`</h2>
//!
//! Above, we pass in two `None` parameters to `DisplayConnection::create`. In most cases, this should work
//! properly. However, it does do some good to know what, exactly, each parameter is doing.
//!
//! The first parameter is the **server name**. This is an address pointing to the X11 server that the program
//! should connect to. It has the following format:
//!
//! ```plaintext
//! [protocol/][host]:display[.screen]
//! ```
//!
//! The default system server name is stored in the `DISPLAY` environment variable. On most systems, it should
//! just be `:0`, representing the first display server. `None` tells `breadx` to read from the `DISPLAY`
//! variable and use that value as the server name. You shouldn't ever have to change this.
//!
//! The second parameter is the authentication info. **TODO: EXPLAIN**
//! </div>
//!
//! <div class="another-perspective">
//! <h2>Another Perspective on `DisplayConnection`</h2>
//!
//! Shrewd programmers will check the documentation and realize that `DisplayConnection` is actually a
//! type alias.
//!
//! ```rust,no_compile
//! type DisplayConnection = Display<NameConnection>;
//! ```
//!
//! [`Display`](../../display/struct.Display.html) is a general purpose wrapper around any type of connection.
//! This allows X connections to be held across every type of byte stream. Most of the time, programmers
//! will simply use the [`NameConnection`](display/name/enum.NameConnection.html) connection, which is a wrapper
//! around TCP Streams or Unix sockets on compatible systems. However, the option remains to run X on any
//! object that implements [`Connection`](../../display/trait.Connection.html).
//! </div>
//!
//! Running this program opens the X connection, then immediately closes it. This isn't that useful. With our
//! connection, we can open a window using the `create_simple_window` method.
//!
//! ```no_run
//! use breadx::{BreadError, DisplayConnection};
//!
//! fn main() -> Result<(), BreadError> {
//! let mut conn = DisplayConnection::create(None, None)?;
//!
//! // the root, or parent, refers to the overall screen
//! let root = conn.default_root();
//!
//! // represents the colors black and white, respectively
//! let black = conn.default_black_pixel();
//! let white = conn.default_white_pixel();
//!
//! // creates a 640x400 window with a black border and a white background
//! let window = conn.create_simple_window(root, 0, 0, 640, 400, 0, black, white)?;
//!
//! // ensure the window is mapped to the screen. this operation is equivalent to the
//! // "show" function in other GUI toolkits
//! window.map(&mut conn)?;
//!
//! Ok(())
//! }
//! ```
//!
//! <div class="dissecting">
//! <h2>Dissecting <a href="../../display/struct.Display.html#method.create_simple_window">`Display::create_simple_window`</a></h2>
//!
//! The `create_simple_window` method acts as a wrapper around the [`Display::create_window`](../../display/struct.Display.html#method.create_window) method, that passes in some defaults that assume values based on the parent
//! window. You may have to use `Display::create_window` for cases where the visual type or depth of the window
//! won't be the same as its parent.
//! </div>
//!
//! If you compile and run this program, you will see a window breifly appear on your screen before vanishing
//! in a second. This is because it creates the window, maps the window, but then immediately ends the program.
//! In order to ensure the window persists, you need to create an event loop.
//!
//! # The Event Loop
//!
//! Event loops should be familiar concept to those who've used GTK+ or Node.js. In X, it's a lot more literal:
//! it's just a loop that reads in events, processes them, and then waits for the next event. To provide an
//! analogy, consider the following Rust program:
//!
//! ```no_run
//! use std::{error::Error, io::{prelude::*, stdin, stdout}};
//!
//! fn main() -> Result<(), Box<dyn Error>> {
//! // hold a lock on Stdin and Stdout for convenience
//! let ins = stdin();
//! let outs = stdout();
//! let mut buffer = String::with_capacity(10);
//!
//! loop {
//! // write a prompt to the user
//! outs.write_all(b"Input your favorite number: ")?;
//! outs.flush();
//!
//! // read in user input
//! ins.read_line(&mut buffer)?;
//!
//! // pop off the newline at the end
//! buffer.pop();
//!
//! // try to parse it into something we can understand
//! // assume that a failed number parse is a sentinel to close
//! let input = match buffer.parse::<i32>() {
//! Err(_) => {
//! outs.write_all(b"Exiting...\n")?;
//! break Ok(());
//! }
//! Ok(input) => input,
//! };
//!
//! // write interpretation of input to user
//! if input & 1 == 0 {
//! outs.write_all(b"Number is even.\n")?;
//! } else {
//! outs.write_all(b"Number is odd.\n")?;
//! }
//!
//! // loop back around and do it again
//! }
//! }
//! ```
//!
//! This is a relatively standard program that reads in a number from the user, and determines whether it's
//! odd or even. The key point here is that is runs indefinitely; even after just one input, it keeps going.
//!
//! Now, consider:
//!
//! * Replacing the prompt to the user with the creation of the window and the connection, and moving it
//! outside of the loop (we've already done this!).
//! * Replacing reading in the user input with reading in the event from the connection.
//! * Replacing the parsing of the input with the parsing of the event.
//! * Replacing writing the interpretation of the inputs of the user with modifying the window setup.
//!
//! This, in a nutshell, is the X event loop.
//!
//! ```no_run
//! use breadx::{BreadError, DisplayConnection};
//!
//! fn main() -> Result<(), BreadError> {
//! // simplified form of the above
//! let mut conn = DisplayConnection::create(None, None)?;
//! let window = conn.create_simple_window(
//! conn.default_root(),
//! 0,
//! 0,
//! 640,
//! 400,
//! 0,
//! conn.default_black_pixel(),
//! conn.default_white_pixel(),
//! )?;
//!
//! window.map(&mut conn)?;
//!
//! // begin the event loop
//! loop {
//! let _ev = conn.wait_for_event()?;
//! // TODO: do things with the event
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! You should now see a blank window. Depending on your WM and GUI environment, it may look like this:
//!
//! <img src="https://raw.githubusercontent.com/not-a-seagull/breadx/master/images/basics_window.png" />
//!
//! Congratulations! You should be able to move it around, resize it, and what have you. It's a bit bare at
//! the moment, however. Let's see if we can fix that.
//!
//! # Adding a window title
//!
//! The [`Window::set_title`](../../auto/xproto/struct.Window.html#method.set_title) function allows
//! the user to set the window's title.
//!
//! ```no_run
//! use breadx::{BreadError, DisplayConnection};
//!
//! fn main() -> Result<(), BreadError> {
//! // simplified form of the above
//! let mut conn = DisplayConnection::create(None, None)?;
//! let window = conn.create_simple_window(
//! conn.default_root(),
//! 0,
//! 0,
//! 640,
//! 400,
//! 0,
//! conn.default_black_pixel(),
//! conn.default_white_pixel(),
//! )?;
//!
//! // NEW: set the window's title
//! window.set_title(&mut conn, "Hello World!")?;
//!
//! window.map(&mut conn)?;
//!
//! // begin the event loop
//! loop {
//! let _ev = conn.wait_for_event()?;
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! <div class="note">
//! <h2>Note</h2>
//!
//! You may notice that most functions rely on a mutable reference to the connection. This is because all data
//! coming in and out of the client must go through the connection.
//! </div>
//!
//! Running this program adds a title to your window:
//!
//! <img src="https://raw.githubusercontent.com/not-a-seagull/breadx/master/images/basics_title.png" />
//!
//! # Setting the exit protocol
//!
//! At this point, you may have noticed that pressing the "x" button on the window does not close the window.
//! The only way to close it is to kill the process. This is because X predates the concept of a window
//! manager. We have to register the idea of a WM deletion process with the client, and use that to close the
//! program. **TODO: explain this better**
//!
//! We do this by registering the `WM_DELETE_WINDOW` atom and checking for it in every iteration of the event
//! loop.
//!
//! ```no_run
//! use breadx::{BreadError, Event, DisplayConnection};
//!
//! fn main() -> Result<(), BreadError> {
//! // simplified form of the above
//! let mut conn = DisplayConnection::create(None, None)?;
//! let window = conn.create_simple_window(
//! conn.default_root(),
//! 0,
//! 0,
//! 640,
//! 400,
//! 0,
//! conn.default_black_pixel(),
//! conn.default_white_pixel(),
//! )?;
//! window.set_title(&mut conn, "Hello World!")?;
//! window.map(&mut conn)?;
//!
//! // NEW: intern an atom and set it to the window's WM protocol
//! let wm_delete_window = conn
//! .intern_atom_immediate("WM_DELETE_WINDOW".to_owned(), false)?;
//! window.set_wm_protocols(&mut conn, &[wm_delete_window])?;
//!
//! loop {
//! let ev = conn.wait_for_event()?;
//!
//! // NEW: match the event, see if it's a ClientMessageEvent, and
//! // exit the program if it holds the delete window atom
//! // interned above
//! match ev {
//! Event::ClientMessage(cme) => {
//! if cme.data.longs()[0] == wm_delete_window.xid() {
//! break;
//! }
//! }
//! _ => (),
//! }
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! <div class="another-perspective">
//! <h2>Another Perspective on the `_immediate` suffix</h2>
//!
//! You may notice that several functions in this library have alternatives with the `_immediate` suffix.
//! `_immediate` means that this function resolves its result immediately, which means it:
//!
//! 1). Sends a request to the server.
//!
//! 2). Waits for a reply from the server.
//!
//! 3). Parses the reply from the server.
//!
//! This may seem like the obvious thing to do, and the question is: "why isn't every function in the library
//! immediate?" The answer to that lies in a subtlety of how X's asynchronous nature works. Consider if we
//! didn't have to intern just one atom, as above, but several.
//!
//! ```no_run
//! # use breadx::{Atom, BreadError, DisplayConnection};
//! # fn main() -> Result<(), BreadError> {
//! # let mut conn = DisplayConnection::create(None, None)?;
//! let atom_names: Vec<String> = vec![ /* ... */ ];
//! let mut atoms: Vec<Atom> = Vec::with_capacity(atom_names.len());
//!
//! for aton_name in atom_names {
//! atoms.push(conn.intern_atom_immediate(atom_name, false)?);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! Consider the workflow for the above program. It would:
//!
//! * Send `InternAtomRequest` #1 to the server.
//! * Wait for reply #1.
//! * Send `InternAtomRequest` #2 to the server.
//! * Wait for reply #2.
//! * and so on and so forth.
//!
//! Although this is an *acceptable* solution, we can do better. We could send all of the requests in a batch,
//! and then wait for replies after the requests have been sent. This would look like:
//!
//! ```no_run
//! # use breadx::{Atom, BreadError, DisplayConnection};
//! # fn main() -> Result<(), BreadError> {
//! # let mut conn = DisplayConnection::create(None, None)?;
//! use breadx::{auto::xproto::InternAtomRequest, RequestCookie};
//!
//! let atom_names: Vec<String> = vec![ /* ... */ ];
//! let mut atom_cookies: Vec<RequestCookie<InternAtomRequest>> = Vec::with_capacity(atom_names.len());
//! let mut atoms: Vec<Atom> = Vec::with_capacity(atom_names.len());
//!
//! for atom_name in atom_names {
//! // send the request to the server
//! atom_cookies.push(conn.intern_atom(atom_name, false)?);
//! }
//!
//! for atom_cookie in atom_cookies {
//! // resolve the request from the server.
//! atoms.push(conn.resolve_request(atom_cookie)?.atom);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! The above workflow is now:
//!
//! * Send `InternAtomRequest` #1 to the server.
//! * Send `InternAtomRequest` #2 to the server.
//! * and so on and so forth.
//! * Wait for reply #1.
//! * Wait for reply #2.
//! * and so on and so forth.
//!
//! This tends to be much more efficient. Of course, if you're only interning one atom, then
//! `intern_atom_immediate` if preferred.
//! </div>
//!
//! You should notice that the window now closes when the "x" button is clicked. Splendid!
//!
//! [Next time, we'll take a closer look at events and how we can use them to implement functionality in
//! our program.](../event/index.html)