Commit ade2a66b37f5c67523e2766a5facabf0bc632765
1 parent
e433cb13
Add some xcb examples.
Include a shm example which I created by analyse the C exmaples and try to reproduce with rust libc and rust-xcb.
Showing
4 changed files
with
647 additions
and
0 deletions
xcb-test/Cargo.toml
0 → 100644
1 | +[package] | |
2 | +name = "xcb-test" | |
3 | +version = "0.1.0" | |
4 | +authors = ["Georg Hopp <georg@steffers.org>"] | |
5 | +edition = "2018" | |
6 | + | |
7 | +[dependencies] | |
8 | +libc = "0.2" | |
9 | +gl = "0.5.2" | |
10 | +x11 = { version = "2.3", features = ["glx"] } | |
11 | +xcb = { version = "0.8", features = ["dri2", "randr", "thread", "xlib_xcb", "shm"] } | ... | ... |
xcb-test/alternatives/info.rs
0 → 100644
1 | +extern crate xcb; | |
2 | + | |
3 | +use std::iter::{Iterator}; | |
4 | +use xcb::randr; | |
5 | + | |
6 | +fn main() { | |
7 | + | |
8 | + let dpy = ":0"; | |
9 | + let (conn, screen_num) = xcb::Connection::connect(Some(&dpy)).unwrap(); | |
10 | + | |
11 | + let setup = conn.get_setup(); | |
12 | + let screen = setup.roots().nth(screen_num as usize).unwrap(); | |
13 | + | |
14 | + println!(""); | |
15 | + println!("Informations of screen {}:", screen.root()); | |
16 | + println!(" width..........: {}", screen.width_in_pixels()); | |
17 | + println!(" height.........: {}", screen.height_in_pixels()); | |
18 | + println!(" white pixel....: {:x}", screen.white_pixel()); | |
19 | + println!(" black pixel....: {:x}", screen.black_pixel()); | |
20 | + | |
21 | + let window_dummy = conn.generate_id(); | |
22 | + xcb::create_window( | |
23 | + &conn, 0, window_dummy, screen.root() | |
24 | + , 0, 0, 1, 1, 0, 0, 0, &[]); | |
25 | + | |
26 | + conn.flush(); | |
27 | + | |
28 | + let cookie = randr::get_screen_info(&conn, window_dummy); | |
29 | + let reply = cookie.get_reply().unwrap(); | |
30 | + let sizes = reply.sizes(); | |
31 | + | |
32 | + for (i, size) in sizes.enumerate() { | |
33 | + if i != 0 { println!(""); } | |
34 | + println!("size of screen {}:", i+1); | |
35 | + println!(" {} x {} ({}mm x {}mm)", size.width(), size.height(), | |
36 | + size.mwidth(), size.mheight()); | |
37 | + } | |
38 | + | |
39 | + // ==== | |
40 | + | |
41 | + let window = conn.generate_id(); | |
42 | + | |
43 | + let values = [ | |
44 | + (xcb::CW_BACK_PIXEL, screen.white_pixel()), | |
45 | + (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS), | |
46 | + ]; | |
47 | + | |
48 | + xcb::create_window(&conn, | |
49 | + xcb::COPY_FROM_PARENT as u8, | |
50 | + window, | |
51 | + screen.root(), | |
52 | + 0, 0, | |
53 | + 150, 150, | |
54 | + 10, | |
55 | + xcb::WINDOW_CLASS_INPUT_OUTPUT as u16, | |
56 | + screen.root_visual(), | |
57 | + &values); | |
58 | + | |
59 | + xcb::map_window(&conn, window); | |
60 | + | |
61 | + let title = "Basic Window"; | |
62 | + // setting title | |
63 | + xcb::change_property(&conn, xcb::PROP_MODE_REPLACE as u8, window, | |
64 | + xcb::ATOM_WM_NAME, xcb::ATOM_STRING, 8, title.as_bytes()); | |
65 | + | |
66 | + conn.flush(); | |
67 | + | |
68 | + // retrieving title | |
69 | + let cookie = xcb::get_property(&conn, false, window, xcb::ATOM_WM_NAME, | |
70 | + xcb::ATOM_STRING, 0, 1024); | |
71 | + if let Ok(reply) = cookie.get_reply() { | |
72 | + assert_eq!(std::str::from_utf8(reply.value()).unwrap(), title); | |
73 | + } else { | |
74 | + panic!("could not retrieve window title!"); | |
75 | + } | |
76 | + | |
77 | + // retrieving a few atoms | |
78 | + let (wm_state, wm_state_maxv, wm_state_maxh) = { | |
79 | + let cook = xcb::intern_atom(&conn, true, "_NET_WM_STATE"); | |
80 | + let cook_maxv = xcb::intern_atom(&conn, true, "_NET_WM_STATE_MAXIMIZED_VERT"); | |
81 | + let cook_maxh = xcb::intern_atom(&conn, true, "_NET_WM_STATE_MAXIMIZED_HORZ"); | |
82 | + | |
83 | + (cook.get_reply().unwrap().atom(), | |
84 | + cook_maxv.get_reply().unwrap().atom(), | |
85 | + cook_maxh.get_reply().unwrap().atom()) | |
86 | + }; | |
87 | + | |
88 | + let mut maximized = false; | |
89 | + | |
90 | + loop { | |
91 | + let event = conn.wait_for_event(); | |
92 | + match event { | |
93 | + None => { break; } | |
94 | + Some(event) => { | |
95 | + let r = event.response_type(); | |
96 | + if r == xcb::KEY_PRESS as u8 { | |
97 | + let key_press : &xcb::KeyPressEvent = unsafe { | |
98 | + xcb::cast_event(&event) | |
99 | + }; | |
100 | + | |
101 | + println!("Key '{}' pressed", key_press.detail()); | |
102 | + | |
103 | + if key_press.detail() == 0x3a { // M (on qwerty) | |
104 | + | |
105 | + // toggle maximized | |
106 | + println!("toggle maximized: {} {}", wm_state_maxv, wm_state_maxh); | |
107 | + | |
108 | + // ClientMessageData is a memory safe untagged union | |
109 | + let data = xcb::ClientMessageData::from_data32([ | |
110 | + if maximized { 0 } else { 1 }, | |
111 | + wm_state_maxv, wm_state_maxh, | |
112 | + 0, 0 | |
113 | + ]); | |
114 | + | |
115 | + let ev = xcb::ClientMessageEvent::new(32, window, | |
116 | + wm_state, data); | |
117 | + | |
118 | + xcb::send_event(&conn, false, screen.root(), | |
119 | + xcb::EVENT_MASK_STRUCTURE_NOTIFY, &ev); | |
120 | + | |
121 | + conn.flush(); | |
122 | + | |
123 | + maximized = !maximized; | |
124 | + } | |
125 | + else if key_press.detail() == 0x18 { // Q (on qwerty) | |
126 | + break; | |
127 | + } | |
128 | + } | |
129 | + } | |
130 | + } | |
131 | + } | |
132 | +} | ... | ... |
xcb-test/alternatives/opengl.rs
0 → 100644
1 | + | |
2 | +extern crate x11; | |
3 | +extern crate xcb; | |
4 | +extern crate gl; | |
5 | +extern crate libc; | |
6 | + | |
7 | +use xcb::dri2; | |
8 | + | |
9 | +use x11::xlib; | |
10 | +use x11::glx::*; | |
11 | + | |
12 | +use std::ptr::null_mut; | |
13 | +use std::ffi::{CStr, CString}; | |
14 | +use std::os::raw::{c_int, c_void}; | |
15 | + | |
16 | + | |
17 | +const GLX_CONTEXT_MAJOR_VERSION_ARB: u32 = 0x2091; | |
18 | +const GLX_CONTEXT_MINOR_VERSION_ARB: u32 = 0x2092; | |
19 | + | |
20 | +type GlXCreateContextAttribsARBProc = | |
21 | + unsafe extern "C" fn (dpy: *mut xlib::Display, fbc: GLXFBConfig, | |
22 | + share_context: GLXContext, direct: xlib::Bool, | |
23 | + attribs: *const c_int) -> GLXContext; | |
24 | + | |
25 | + | |
26 | +unsafe fn load_gl_func (name: &str) -> *mut c_void { | |
27 | + let cname = CString::new(name).unwrap(); | |
28 | + let ptr: *mut c_void = std::mem::transmute(glXGetProcAddress( | |
29 | + cname.as_ptr() as *const u8 | |
30 | + )); | |
31 | + if ptr.is_null() { | |
32 | + panic!("could not load {}", name); | |
33 | + } | |
34 | + ptr | |
35 | +} | |
36 | + | |
37 | +fn check_glx_extension(glx_exts: &str, ext_name: &str) -> bool { | |
38 | + for glx_ext in glx_exts.split(" ") { | |
39 | + if glx_ext == ext_name { | |
40 | + return true; | |
41 | + } | |
42 | + } | |
43 | + false | |
44 | +} | |
45 | + | |
46 | +static mut ctx_error_occurred: bool = false; | |
47 | +unsafe extern "C" fn ctx_error_handler( | |
48 | + _dpy: *mut xlib::Display, | |
49 | + _ev: *mut xlib::XErrorEvent) -> i32 { | |
50 | + ctx_error_occurred = true; | |
51 | + 0 | |
52 | +} | |
53 | + | |
54 | + | |
55 | +unsafe fn check_gl_error() { | |
56 | + let err = gl::GetError(); | |
57 | + if err != gl::NO_ERROR { | |
58 | + println!("got gl error {}", err); | |
59 | + } | |
60 | +} | |
61 | + | |
62 | +// returns the glx version in a decimal form | |
63 | +// eg. 1.3 => 13 | |
64 | +fn glx_dec_version(dpy: *mut xlib::Display) -> i32 { | |
65 | + let mut maj: c_int = 0; | |
66 | + let mut min: c_int = 0; | |
67 | + unsafe { | |
68 | + if glXQueryVersion(dpy, | |
69 | + &mut maj as *mut c_int, | |
70 | + &mut min as *mut c_int) == 0 { | |
71 | + panic!("cannot get glx version"); | |
72 | + } | |
73 | + } | |
74 | + (maj*10 + min) as i32 | |
75 | +} | |
76 | + | |
77 | + | |
78 | +fn get_glxfbconfig(dpy: *mut xlib::Display, screen_num: i32, | |
79 | + visual_attribs: &[i32]) -> GLXFBConfig { | |
80 | + unsafe { | |
81 | + let mut fbcount: c_int = 0; | |
82 | + let fbcs = glXChooseFBConfig(dpy, screen_num, | |
83 | + visual_attribs.as_ptr(), | |
84 | + &mut fbcount as *mut c_int); | |
85 | + | |
86 | + if fbcount == 0 { | |
87 | + panic!("could not find compatible fb config"); | |
88 | + } | |
89 | + // we pick the first from the list | |
90 | + let fbc = *fbcs; | |
91 | + xlib::XFree(fbcs as *mut c_void); | |
92 | + fbc | |
93 | + } | |
94 | +} | |
95 | + | |
96 | + | |
97 | +fn main() { unsafe { | |
98 | + let (conn, screen_num) = xcb::Connection::connect_with_xlib_display().unwrap(); | |
99 | + conn.set_event_queue_owner(xcb::EventQueueOwner::Xcb); | |
100 | + | |
101 | + if glx_dec_version(conn.get_raw_dpy()) < 13 { | |
102 | + panic!("glx-1.3 is not supported"); | |
103 | + } | |
104 | + | |
105 | + let fbc = get_glxfbconfig(conn.get_raw_dpy(), screen_num, &[ | |
106 | + GLX_X_RENDERABLE , 1, | |
107 | + GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, | |
108 | + GLX_RENDER_TYPE , GLX_RGBA_BIT, | |
109 | + GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, | |
110 | + GLX_RED_SIZE , 8, | |
111 | + GLX_GREEN_SIZE , 8, | |
112 | + GLX_BLUE_SIZE , 8, | |
113 | + GLX_ALPHA_SIZE , 8, | |
114 | + GLX_DEPTH_SIZE , 24, | |
115 | + GLX_STENCIL_SIZE , 8, | |
116 | + GLX_DOUBLEBUFFER , 1, | |
117 | + 0 | |
118 | + ]); | |
119 | + | |
120 | + let vi: *const xlib::XVisualInfo = | |
121 | + glXGetVisualFromFBConfig(conn.get_raw_dpy(), fbc); | |
122 | + | |
123 | + let dri2_ev = { | |
124 | + conn.prefetch_extension_data(dri2::id()); | |
125 | + match conn.get_extension_data(dri2::id()) { | |
126 | + None => { panic!("could not load dri2 extension") }, | |
127 | + Some(r) => { r.first_event() } | |
128 | + } | |
129 | + }; | |
130 | + | |
131 | + let (wm_protocols, wm_delete_window) = { | |
132 | + let pc = xcb::intern_atom(&conn, false, "WM_PROTOCOLS"); | |
133 | + let dwc = xcb::intern_atom(&conn, false, "WM_DELETE_WINDOW"); | |
134 | + | |
135 | + let p = match pc.get_reply() { | |
136 | + Ok(p) => p.atom(), | |
137 | + Err(_) => panic!("could not load WM_PROTOCOLS atom") | |
138 | + }; | |
139 | + let dw = match dwc.get_reply() { | |
140 | + Ok(dw) => dw.atom(), | |
141 | + Err(_) => panic!("could not load WM_DELETE_WINDOW atom") | |
142 | + }; | |
143 | + (p, dw) | |
144 | + }; | |
145 | + | |
146 | + let setup = conn.get_setup(); | |
147 | + let screen = setup.roots().nth((*vi).screen as usize).unwrap(); | |
148 | + | |
149 | + let cmap = conn.generate_id(); | |
150 | + let win = conn.generate_id(); | |
151 | + | |
152 | + xcb::create_colormap(&conn, xcb::COLORMAP_ALLOC_NONE as u8, | |
153 | + cmap, screen.root(), (*vi).visualid as u32); | |
154 | + | |
155 | + let cw_values = [ | |
156 | + (xcb::CW_BACK_PIXEL, screen.white_pixel()), | |
157 | + (xcb::CW_BORDER_PIXEL, screen.black_pixel()), | |
158 | + (xcb::CW_EVENT_MASK, | |
159 | + xcb::EVENT_MASK_KEY_PRESS | xcb::EVENT_MASK_EXPOSURE), | |
160 | + (xcb::CW_COLORMAP, cmap) | |
161 | + ]; | |
162 | + | |
163 | + xcb::create_window(&conn, (*vi).depth as u8, win, screen.root(), 0, 0, 640, 480, | |
164 | + 0, xcb::WINDOW_CLASS_INPUT_OUTPUT as u16, | |
165 | + (*vi).visualid as u32, &cw_values); | |
166 | + | |
167 | + xlib::XFree(vi as *mut c_void); | |
168 | + | |
169 | + let title = "XCB OpenGL"; | |
170 | + xcb::change_property(&conn, | |
171 | + xcb::PROP_MODE_REPLACE as u8, | |
172 | + win, | |
173 | + xcb::ATOM_WM_NAME, | |
174 | + xcb::ATOM_STRING, | |
175 | + 8, title.as_bytes()); | |
176 | + | |
177 | + let protocols = [wm_delete_window]; | |
178 | + xcb::change_property(&conn, xcb::PROP_MODE_REPLACE as u8, | |
179 | + win, wm_protocols, xcb::ATOM_ATOM, 32, &protocols); | |
180 | + | |
181 | + xcb::map_window(&conn, win); | |
182 | + conn.flush(); | |
183 | + xlib::XSync(conn.get_raw_dpy(), xlib::False); | |
184 | + | |
185 | + let glx_exts = CStr::from_ptr( | |
186 | + glXQueryExtensionsString(conn.get_raw_dpy(), screen_num)) | |
187 | + .to_str().unwrap(); | |
188 | + | |
189 | + if !check_glx_extension(&glx_exts, "GLX_ARB_create_context") { | |
190 | + panic!("could not find GLX extension GLX_ARB_create_context"); | |
191 | + } | |
192 | + | |
193 | + // with glx, no need of a current context is needed to load symbols | |
194 | + // otherwise we would need to create a temporary legacy GL context | |
195 | + // for loading symbols (at least glXCreateContextAttribsARB) | |
196 | + let glx_create_context_attribs: GlXCreateContextAttribsARBProc = | |
197 | + std::mem::transmute(load_gl_func("glXCreateContextAttribsARB")); | |
198 | + | |
199 | + // loading all other symbols | |
200 | + gl::load_with(|n| load_gl_func(&n)); | |
201 | + | |
202 | + if !gl::GenVertexArrays::is_loaded() { | |
203 | + panic!("no GL3 support available!"); | |
204 | + } | |
205 | + | |
206 | + // installing an event handler to check if error is generated | |
207 | + ctx_error_occurred = false; | |
208 | + let old_handler = xlib::XSetErrorHandler(Some(ctx_error_handler)); | |
209 | + | |
210 | + let context_attribs: [c_int; 5] = [ | |
211 | + GLX_CONTEXT_MAJOR_VERSION_ARB as c_int, 3, | |
212 | + GLX_CONTEXT_MINOR_VERSION_ARB as c_int, 0, | |
213 | + 0 | |
214 | + ]; | |
215 | + let ctx = glx_create_context_attribs(conn.get_raw_dpy(), fbc, null_mut(), | |
216 | + xlib::True, &context_attribs[0] as *const c_int); | |
217 | + | |
218 | + conn.flush(); | |
219 | + xlib::XSync(conn.get_raw_dpy(), xlib::False); | |
220 | + xlib::XSetErrorHandler(std::mem::transmute(old_handler)); | |
221 | + | |
222 | + if ctx.is_null() || ctx_error_occurred { | |
223 | + panic!("error when creating gl-3.0 context"); | |
224 | + } | |
225 | + | |
226 | + if glXIsDirect(conn.get_raw_dpy(), ctx) == 0 { | |
227 | + panic!("obtained indirect rendering context") | |
228 | + } | |
229 | + | |
230 | + loop { | |
231 | + if let Some(ev) = conn.wait_for_event() { | |
232 | + let ev_type = ev.response_type() & !0x80; | |
233 | + match ev_type { | |
234 | + xcb::EXPOSE => { | |
235 | + glXMakeCurrent(conn.get_raw_dpy(), win as xlib::XID, ctx); | |
236 | + gl::ClearColor(0.5f32, 0.5f32, 1.0f32, 1.0f32); | |
237 | + gl::Clear(gl::COLOR_BUFFER_BIT); | |
238 | + gl::Flush(); | |
239 | + check_gl_error(); | |
240 | + glXSwapBuffers(conn.get_raw_dpy(), win as xlib::XID); | |
241 | + glXMakeCurrent(conn.get_raw_dpy(), 0, null_mut()); | |
242 | + }, | |
243 | + xcb::KEY_PRESS => { | |
244 | + break; | |
245 | + }, | |
246 | + xcb::CLIENT_MESSAGE => { | |
247 | + let cmev = unsafe { | |
248 | + xcb::cast_event::<xcb::ClientMessageEvent>(&ev) | |
249 | + }; | |
250 | + if cmev.type_() == wm_protocols && cmev.format() == 32 { | |
251 | + let protocol = cmev.data().data32()[0]; | |
252 | + if protocol == wm_delete_window { | |
253 | + break; | |
254 | + } | |
255 | + } | |
256 | + }, | |
257 | + _ => { | |
258 | + // following stuff is not obvious at all, but is necessary | |
259 | + // to handle GL when XCB owns the event queue | |
260 | + if ev_type == dri2_ev || ev_type == dri2_ev+1 { | |
261 | + // these are libgl dri2 event that need special handling | |
262 | + // see https://bugs.freedesktop.org/show_bug.cgi?id=35945#c4 | |
263 | + // and mailing thread starting here: | |
264 | + // http://lists.freedesktop.org/archives/xcb/2015-November/010556.html | |
265 | + | |
266 | + if let Some(proc_) = | |
267 | + xlib::XESetWireToEvent(conn.get_raw_dpy(), | |
268 | + ev_type as i32, None) { | |
269 | + xlib::XESetWireToEvent(conn.get_raw_dpy(), | |
270 | + ev_type as i32, Some(proc_)); | |
271 | + let raw_ev = ev.ptr; | |
272 | + (*raw_ev).sequence = | |
273 | + xlib::XLastKnownRequestProcessed( | |
274 | + conn.get_raw_dpy()) as u16; | |
275 | + let mut dummy: xlib::XEvent = std::mem::zeroed(); | |
276 | + proc_(conn.get_raw_dpy(), | |
277 | + &mut dummy as *mut xlib::XEvent, | |
278 | + raw_ev as *mut xlib::xEvent); | |
279 | + } | |
280 | + | |
281 | + } | |
282 | + } | |
283 | + } | |
284 | + conn.flush(); | |
285 | + } | |
286 | + else { | |
287 | + break; | |
288 | + } | |
289 | + } | |
290 | + | |
291 | + // only to make sure that rs_client generate correct names for DRI2 | |
292 | + // (used to be "*_DRI_2_*") | |
293 | + // should be in a "compile tests" section instead of example | |
294 | + let _ = xcb::ffi::dri2::XCB_DRI2_ATTACHMENT_BUFFER_ACCUM; | |
295 | + | |
296 | + glXDestroyContext(conn.get_raw_dpy(), ctx); | |
297 | + | |
298 | + xcb::unmap_window(&conn, win); | |
299 | + xcb::destroy_window(&conn, win); | |
300 | + xcb::free_colormap(&conn, cmap); | |
301 | + conn.flush(); | |
302 | +}} | ... | ... |
xcb-test/src/main.rs
0 → 100644
1 | +extern crate xcb; | |
2 | + | |
3 | +use std::iter::{Iterator}; | |
4 | +use std::{thread, time}; | |
5 | +use std::sync::Arc; | |
6 | +use std::ptr::{null, null_mut}; | |
7 | +use std::slice::from_raw_parts_mut; | |
8 | + | |
9 | +pub fn getshm<'a>(size :usize) -> (i32, &'a mut [u32]) { | |
10 | + unsafe { | |
11 | + let id = libc::shmget( libc::IPC_PRIVATE | |
12 | + , size * 4 | |
13 | + , libc::IPC_CREAT | 0o744 ); | |
14 | + let ptr = libc::shmat(id, null(), 0); | |
15 | + (id as i32, from_raw_parts_mut(ptr as *mut u32, size)) | |
16 | + } | |
17 | +} | |
18 | + | |
19 | +fn main() { | |
20 | + let points: &[xcb::Point] = &[ xcb::Point::new(10, 10) | |
21 | + , xcb::Point::new(10, 20) | |
22 | + , xcb::Point::new(20, 10) | |
23 | + , xcb::Point::new(20, 20) ]; | |
24 | + let polyline: &[xcb::Point] = &[ xcb::Point::new(50, 10 ) | |
25 | + // rest of points are relative | |
26 | + , xcb::Point::new( 5, 20 ) | |
27 | + , xcb::Point::new(25, -20) | |
28 | + , xcb::Point::new(10, 10 ) ]; | |
29 | + let segments: &[xcb::Segment] = &[ xcb::Segment::new(100, 10, 140, 30) | |
30 | + , xcb::Segment::new(110, 25, 130, 60) ]; | |
31 | + let rectangles: &[xcb::Rectangle] | |
32 | + = &[ xcb::Rectangle::new(10, 50, 40, 20) | |
33 | + , xcb::Rectangle::new(80, 50, 10, 40) ]; | |
34 | + let arcs: &[xcb::Arc] = &[ xcb::Arc::new(10, 100, 60, 40, 0, 90 << 6) | |
35 | + , xcb::Arc::new(90, 100, 55, 40, 0, 270 << 6) ]; | |
36 | + | |
37 | + let (conn, screen_num) = { | |
38 | + let (conn, screen_num) = xcb::Connection::connect(None).unwrap(); | |
39 | + (Arc::new(conn), screen_num) | |
40 | + }; | |
41 | + let setup = conn.get_setup(); | |
42 | + let screen = setup.roots().nth(screen_num as usize).unwrap(); | |
43 | + | |
44 | + let (shmid, shm) = getshm(150 * 150); | |
45 | + let shmseg = conn.generate_id(); | |
46 | + xcb::shm::attach(&conn, shmseg, shmid as u32, false); | |
47 | + unsafe { libc::shmctl(shmid, libc::IPC_RMID, null_mut()); } | |
48 | + | |
49 | + let foreground = conn.generate_id(); | |
50 | + let pix = conn.generate_id(); | |
51 | + | |
52 | + xcb::create_gc( &conn | |
53 | + , foreground | |
54 | + , screen.root() | |
55 | + , &[ (xcb::GC_FOREGROUND, screen.black_pixel()) | |
56 | + , (xcb::GC_GRAPHICS_EXPOSURES, 0) ] ); | |
57 | + | |
58 | + let window = conn.generate_id(); | |
59 | + let values = [ ( xcb::CW_BACK_PIXEL, screen.white_pixel() ) | |
60 | + , ( xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | |
61 | + | xcb::EVENT_MASK_KEY_PRESS | |
62 | + | xcb::EVENT_MASK_STRUCTURE_NOTIFY | |
63 | + | xcb::EVENT_MASK_PROPERTY_CHANGE ) ]; | |
64 | + xcb::create_window( &conn | |
65 | + , xcb::COPY_FROM_PARENT as u8 | |
66 | + , window | |
67 | + , screen.root() | |
68 | + , 0, 0, 150, 150, 0 | |
69 | + , xcb::WINDOW_CLASS_INPUT_OUTPUT as u16 | |
70 | + , screen.root_visual() | |
71 | + , &values); | |
72 | + | |
73 | + xcb::shm::create_pixmap( &conn | |
74 | + , pix | |
75 | + , window | |
76 | + , 150, 150 | |
77 | + , screen.root_depth() | |
78 | + , shmseg | |
79 | + , 0 ); | |
80 | + | |
81 | + xcb::map_window(&conn, window); | |
82 | + | |
83 | + { | |
84 | + let conn = conn.clone(); | |
85 | + | |
86 | + thread::spawn(move || { | |
87 | + let mut blink = false; | |
88 | + | |
89 | + let mut i = 0; | |
90 | + loop { | |
91 | + let title = if blink { | |
92 | + "Basic Threaded Window ;-)" | |
93 | + } else { | |
94 | + "Basic Threaded Window :-)" | |
95 | + }; | |
96 | + | |
97 | + shm[i] = 0xFFFFFF; | |
98 | + i = (i + 1) % (150 * 150); | |
99 | + | |
100 | + let c = xcb::change_property_checked( | |
101 | + &conn | |
102 | + , xcb::PROP_MODE_REPLACE as u8 | |
103 | + , window | |
104 | + , xcb::ATOM_WM_NAME | |
105 | + , xcb::ATOM_STRING | |
106 | + , 8 | |
107 | + , title.as_bytes() ); | |
108 | + | |
109 | + xcb::copy_area( &conn | |
110 | + , pix | |
111 | + , window | |
112 | + , foreground | |
113 | + , 0, 0, 0, 0 | |
114 | + , 150, 150); | |
115 | + | |
116 | + if conn.has_error().is_err() || c.request_check().is_err() { | |
117 | + break; | |
118 | + } | |
119 | + | |
120 | + blink = !blink; | |
121 | + thread::sleep(time::Duration::from_millis(500)); | |
122 | + } | |
123 | + }); | |
124 | + } | |
125 | + | |
126 | + conn.flush(); | |
127 | + | |
128 | + loop { | |
129 | + let event = conn.wait_for_event(); | |
130 | + | |
131 | + match event { | |
132 | + None => break, | |
133 | + Some(event) => { | |
134 | + match event.response_type() & !0x80 { | |
135 | + xcb::PROPERTY_NOTIFY => { | |
136 | + let prop_notify: &xcb::PropertyNotifyEvent = unsafe { | |
137 | + xcb::cast_event(&event) | |
138 | + }; | |
139 | + | |
140 | + if prop_notify.atom() == xcb::ATOM_WM_NAME { | |
141 | + // retrieving title | |
142 | + let cookie = xcb::get_property( &conn | |
143 | + , false | |
144 | + , window | |
145 | + , xcb::ATOM_WM_NAME | |
146 | + , xcb::ATOM_STRING | |
147 | + , 0, 1024); | |
148 | + | |
149 | + if let Ok(reply) = cookie.get_reply() { | |
150 | + let r = reply.value(); | |
151 | + let r = std::str::from_utf8(r).unwrap(); | |
152 | + | |
153 | + println!( "title changed to \"{}\"", r); | |
154 | + } | |
155 | + } | |
156 | + }, | |
157 | + | |
158 | + xcb::EXPOSE => { | |
159 | + xcb::poly_point( &conn | |
160 | + , xcb::COORD_MODE_ORIGIN as u8 | |
161 | + , window | |
162 | + , foreground | |
163 | + , &points ); | |
164 | + xcb::poly_line( &conn | |
165 | + , xcb::COORD_MODE_PREVIOUS as u8 | |
166 | + , window | |
167 | + , foreground | |
168 | + , &polyline ); | |
169 | + xcb::poly_segment( &conn | |
170 | + , window | |
171 | + , foreground | |
172 | + , &segments ); | |
173 | + xcb::poly_rectangle( &conn | |
174 | + , window | |
175 | + , foreground | |
176 | + , &rectangles ); | |
177 | + xcb::poly_arc( &conn | |
178 | + , window | |
179 | + , foreground | |
180 | + , &arcs ); | |
181 | + | |
182 | + conn.flush(); | |
183 | + }, | |
184 | + | |
185 | + xcb::KEY_PRESS => { | |
186 | + let key_press: &xcb::KeyPressEvent = unsafe { | |
187 | + xcb::cast_event(&event) | |
188 | + }; | |
189 | + | |
190 | + println!("Key '{}' pressed", key_press.detail()); | |
191 | + | |
192 | + if key_press.detail() == 0x18 { // Q (on qwerty) | |
193 | + break; | |
194 | + } | |
195 | + }, | |
196 | + | |
197 | + _ => {}, | |
198 | + } | |
199 | + } | |
200 | + } | |
201 | + } | |
202 | +} | ... | ... |
Please
register
or
login
to post a comment