Commit ade2a66b37f5c67523e2766a5facabf0bc632765

Authored by Georg Hopp
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.
  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"] }
  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 +}
  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 +}}
  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