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