1 extern crate x11rb;
2 
3 use x11rb::connection::Connection;
4 use x11rb::cursor::Handle as CursorHandle;
5 use x11rb::protocol::xproto::*;
6 use x11rb::protocol::Event;
7 use x11rb::resource_manager::Database;
8 use x11rb::wrapper::ConnectionExt as _;
9 
10 fn main() {
11     let (conn, screen_num) = x11rb::connect(None).unwrap();
12 
13     // The following is only needed for start_timeout_thread(), which is used for 'tests'
14     let conn1 = std::sync::Arc::new(conn);
15     let conn = &*conn1;
16 
17     let screen = &conn.setup().roots[screen_num];
18     let win_id = conn.generate_id().unwrap();
19     let gc_id = conn.generate_id().unwrap();
20     let resource_db = Database::new_from_default(conn).unwrap();
21     let cursor_handle = CursorHandle::new(conn, screen_num, &resource_db).unwrap();
22 
23     let wm_protocols = conn.intern_atom(false, b"WM_PROTOCOLS").unwrap();
24     let wm_delete_window = conn.intern_atom(false, b"WM_DELETE_WINDOW").unwrap();
25     let net_wm_name = conn.intern_atom(false, b"_NET_WM_NAME").unwrap();
26     let utf8_string = conn.intern_atom(false, b"UTF8_STRING").unwrap();
27     let wm_protocols = wm_protocols.reply().unwrap().atom;
28     let wm_delete_window = wm_delete_window.reply().unwrap().atom;
29     let net_wm_name = net_wm_name.reply().unwrap().atom;
30     let utf8_string = utf8_string.reply().unwrap().atom;
31     let cursor_handle = cursor_handle.reply().unwrap();
32 
33     let win_aux = CreateWindowAux::new()
34         .event_mask(EventMask::EXPOSURE | EventMask::STRUCTURE_NOTIFY | EventMask::NO_EVENT)
35         .background_pixel(screen.white_pixel)
36         .win_gravity(Gravity::NORTH_WEST)
37         // Just because, we set the cursor to "wait"
38         .cursor(cursor_handle.load_cursor(conn, "wait").unwrap());
39 
40     let gc_aux = CreateGCAux::new().foreground(screen.black_pixel);
41 
42     let (mut width, mut height) = (100, 100);
43 
44     conn.create_window(
45         screen.root_depth,
46         win_id,
47         screen.root,
48         0,
49         0,
50         width,
51         height,
52         0,
53         WindowClass::INPUT_OUTPUT,
54         0,
55         &win_aux,
56     )
57     .unwrap();
58 
59     util::start_timeout_thread(conn1.clone(), win_id);
60 
61     let title = "Simple Window";
62     conn.change_property8(
63         PropMode::REPLACE,
64         win_id,
65         AtomEnum::WM_NAME,
66         AtomEnum::STRING,
67         title.as_bytes(),
68     )
69     .unwrap();
70     conn.change_property8(
71         PropMode::REPLACE,
72         win_id,
73         net_wm_name,
74         utf8_string,
75         title.as_bytes(),
76     )
77     .unwrap();
78     conn.change_property32(
79         PropMode::REPLACE,
80         win_id,
81         wm_protocols,
82         AtomEnum::ATOM,
83         &[wm_delete_window],
84     )
85     .unwrap();
86     conn.change_property8(
87         PropMode::REPLACE,
88         win_id,
89         AtomEnum::WM_CLASS,
90         AtomEnum::STRING,
91         b"simple_window\0simple_window\0",
92     )
main(int argc,char * argv[])93     .unwrap();
94     conn.change_property8(
95         PropMode::REPLACE,
96         win_id,
97         AtomEnum::WM_CLIENT_MACHINE,
98         AtomEnum::STRING,
99         // Text encoding in X11 is complicated. Let's use UTF-8 and hope for the best.
100         gethostname::gethostname()
101             .to_str()
102             .unwrap_or("[Invalid]")
103             .as_bytes(),
104     )
105     .unwrap();
106 
107     let reply = conn
108         .get_property(false, win_id, AtomEnum::WM_NAME, AtomEnum::STRING, 0, 1024)
109         .unwrap();
110     let reply = reply.reply().unwrap();
111     assert_eq!(reply.value, title.as_bytes());
112 
113     conn.create_gc(gc_id, win_id, &gc_aux).unwrap();
114 
115     conn.map_window(win_id).unwrap();
116 
117     conn.flush().unwrap();
118 
119     loop {
120         let event = conn.wait_for_event().unwrap();
121         println!("{:?})", event);
122         match event {
123             Event::Expose(event) => {
124                 if event.count == 0 {
125                     // There already is a white background because we set background_pixel to white
126                     // when creating the window.
127                     let (width, height): (i16, i16) = (width as _, height as _);
128                     let points = [
129                         Point {
130                             x: width,
131                             y: height,
132                         },
133                         Point { x: -10, y: -10 },
134                         Point {
135                             x: -10,
136                             y: height + 10,
137                         },
138                         Point {
139                             x: width + 10,
140                             y: -10,
141                         },
142                     ];
143                     conn.poly_line(CoordMode::ORIGIN, win_id, gc_id, &points)
144                         .unwrap();
145                     conn.flush().unwrap();
146                 }
147             }
148             Event::ConfigureNotify(event) => {
149                 width = event.width;
150                 height = event.height;
151             }
152             Event::ClientMessage(event) => {
153                 let data = event.data.as_data32();
154                 if event.format == 32 && event.window == win_id && data[0] == wm_delete_window {
155                     println!("Window was asked to close");
156                     return;
157                 }
158             }
159             Event::Error(_) => println!("Got an unexpected error"),
160             _ => println!("Got an unknown event"),
161         }
162     }
163 }
164 
165 include!("integration_test_util/util.rs");
166