Browse Source
Add some xcb examples.
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.master
4 changed files with 647 additions and 0 deletions
-
11xcb-test/Cargo.toml
-
132xcb-test/alternatives/info.rs
-
302xcb-test/alternatives/opengl.rs
-
202xcb-test/src/main.rs
@ -0,0 +1,11 @@ |
|||
[package] |
|||
name = "xcb-test" |
|||
version = "0.1.0" |
|||
authors = ["Georg Hopp <georg@steffers.org>"] |
|||
edition = "2018" |
|||
|
|||
[dependencies] |
|||
libc = "0.2" |
|||
gl = "0.5.2" |
|||
x11 = { version = "2.3", features = ["glx"] } |
|||
xcb = { version = "0.8", features = ["dri2", "randr", "thread", "xlib_xcb", "shm"] } |
|||
@ -0,0 +1,132 @@ |
|||
extern crate xcb;
|
|||
|
|||
use std::iter::{Iterator};
|
|||
use xcb::randr;
|
|||
|
|||
fn main() {
|
|||
|
|||
let dpy = ":0";
|
|||
let (conn, screen_num) = xcb::Connection::connect(Some(&dpy)).unwrap();
|
|||
|
|||
let setup = conn.get_setup();
|
|||
let screen = setup.roots().nth(screen_num as usize).unwrap();
|
|||
|
|||
println!("");
|
|||
println!("Informations of screen {}:", screen.root());
|
|||
println!(" width..........: {}", screen.width_in_pixels());
|
|||
println!(" height.........: {}", screen.height_in_pixels());
|
|||
println!(" white pixel....: {:x}", screen.white_pixel());
|
|||
println!(" black pixel....: {:x}", screen.black_pixel());
|
|||
|
|||
let window_dummy = conn.generate_id();
|
|||
xcb::create_window(
|
|||
&conn, 0, window_dummy, screen.root()
|
|||
, 0, 0, 1, 1, 0, 0, 0, &[]);
|
|||
|
|||
conn.flush();
|
|||
|
|||
let cookie = randr::get_screen_info(&conn, window_dummy);
|
|||
let reply = cookie.get_reply().unwrap();
|
|||
let sizes = reply.sizes();
|
|||
|
|||
for (i, size) in sizes.enumerate() {
|
|||
if i != 0 { println!(""); }
|
|||
println!("size of screen {}:", i+1);
|
|||
println!(" {} x {} ({}mm x {}mm)", size.width(), size.height(),
|
|||
size.mwidth(), size.mheight());
|
|||
}
|
|||
|
|||
// ====
|
|||
|
|||
let window = conn.generate_id();
|
|||
|
|||
let values = [
|
|||
(xcb::CW_BACK_PIXEL, screen.white_pixel()),
|
|||
(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS),
|
|||
];
|
|||
|
|||
xcb::create_window(&conn,
|
|||
xcb::COPY_FROM_PARENT as u8,
|
|||
window,
|
|||
screen.root(),
|
|||
0, 0,
|
|||
150, 150,
|
|||
10,
|
|||
xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
|
|||
screen.root_visual(),
|
|||
&values);
|
|||
|
|||
xcb::map_window(&conn, window);
|
|||
|
|||
let title = "Basic Window";
|
|||
// setting title
|
|||
xcb::change_property(&conn, xcb::PROP_MODE_REPLACE as u8, window,
|
|||
xcb::ATOM_WM_NAME, xcb::ATOM_STRING, 8, title.as_bytes());
|
|||
|
|||
conn.flush();
|
|||
|
|||
// retrieving title
|
|||
let cookie = xcb::get_property(&conn, false, window, xcb::ATOM_WM_NAME,
|
|||
xcb::ATOM_STRING, 0, 1024);
|
|||
if let Ok(reply) = cookie.get_reply() {
|
|||
assert_eq!(std::str::from_utf8(reply.value()).unwrap(), title);
|
|||
} else {
|
|||
panic!("could not retrieve window title!");
|
|||
}
|
|||
|
|||
// retrieving a few atoms
|
|||
let (wm_state, wm_state_maxv, wm_state_maxh) = {
|
|||
let cook = xcb::intern_atom(&conn, true, "_NET_WM_STATE");
|
|||
let cook_maxv = xcb::intern_atom(&conn, true, "_NET_WM_STATE_MAXIMIZED_VERT");
|
|||
let cook_maxh = xcb::intern_atom(&conn, true, "_NET_WM_STATE_MAXIMIZED_HORZ");
|
|||
|
|||
(cook.get_reply().unwrap().atom(),
|
|||
cook_maxv.get_reply().unwrap().atom(),
|
|||
cook_maxh.get_reply().unwrap().atom())
|
|||
};
|
|||
|
|||
let mut maximized = false;
|
|||
|
|||
loop {
|
|||
let event = conn.wait_for_event();
|
|||
match event {
|
|||
None => { break; }
|
|||
Some(event) => {
|
|||
let r = event.response_type();
|
|||
if r == xcb::KEY_PRESS as u8 {
|
|||
let key_press : &xcb::KeyPressEvent = unsafe {
|
|||
xcb::cast_event(&event)
|
|||
};
|
|||
|
|||
println!("Key '{}' pressed", key_press.detail());
|
|||
|
|||
if key_press.detail() == 0x3a { // M (on qwerty)
|
|||
|
|||
// toggle maximized
|
|||
println!("toggle maximized: {} {}", wm_state_maxv, wm_state_maxh);
|
|||
|
|||
// ClientMessageData is a memory safe untagged union
|
|||
let data = xcb::ClientMessageData::from_data32([
|
|||
if maximized { 0 } else { 1 },
|
|||
wm_state_maxv, wm_state_maxh,
|
|||
0, 0
|
|||
]);
|
|||
|
|||
let ev = xcb::ClientMessageEvent::new(32, window,
|
|||
wm_state, data);
|
|||
|
|||
xcb::send_event(&conn, false, screen.root(),
|
|||
xcb::EVENT_MASK_STRUCTURE_NOTIFY, &ev);
|
|||
|
|||
conn.flush();
|
|||
|
|||
maximized = !maximized;
|
|||
}
|
|||
else if key_press.detail() == 0x18 { // Q (on qwerty)
|
|||
break;
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
@ -0,0 +1,302 @@ |
|||
|
|||
extern crate x11;
|
|||
extern crate xcb;
|
|||
extern crate gl;
|
|||
extern crate libc;
|
|||
|
|||
use xcb::dri2;
|
|||
|
|||
use x11::xlib;
|
|||
use x11::glx::*;
|
|||
|
|||
use std::ptr::null_mut;
|
|||
use std::ffi::{CStr, CString};
|
|||
use std::os::raw::{c_int, c_void};
|
|||
|
|||
|
|||
const GLX_CONTEXT_MAJOR_VERSION_ARB: u32 = 0x2091;
|
|||
const GLX_CONTEXT_MINOR_VERSION_ARB: u32 = 0x2092;
|
|||
|
|||
type GlXCreateContextAttribsARBProc =
|
|||
unsafe extern "C" fn (dpy: *mut xlib::Display, fbc: GLXFBConfig,
|
|||
share_context: GLXContext, direct: xlib::Bool,
|
|||
attribs: *const c_int) -> GLXContext;
|
|||
|
|||
|
|||
unsafe fn load_gl_func (name: &str) -> *mut c_void {
|
|||
let cname = CString::new(name).unwrap();
|
|||
let ptr: *mut c_void = std::mem::transmute(glXGetProcAddress(
|
|||
cname.as_ptr() as *const u8
|
|||
));
|
|||
if ptr.is_null() {
|
|||
panic!("could not load {}", name);
|
|||
}
|
|||
ptr
|
|||
}
|
|||
|
|||
fn check_glx_extension(glx_exts: &str, ext_name: &str) -> bool {
|
|||
for glx_ext in glx_exts.split(" ") {
|
|||
if glx_ext == ext_name {
|
|||
return true;
|
|||
}
|
|||
}
|
|||
false
|
|||
}
|
|||
|
|||
static mut ctx_error_occurred: bool = false;
|
|||
unsafe extern "C" fn ctx_error_handler(
|
|||
_dpy: *mut xlib::Display,
|
|||
_ev: *mut xlib::XErrorEvent) -> i32 {
|
|||
ctx_error_occurred = true;
|
|||
0
|
|||
}
|
|||
|
|||
|
|||
unsafe fn check_gl_error() {
|
|||
let err = gl::GetError();
|
|||
if err != gl::NO_ERROR {
|
|||
println!("got gl error {}", err);
|
|||
}
|
|||
}
|
|||
|
|||
// returns the glx version in a decimal form
|
|||
// eg. 1.3 => 13
|
|||
fn glx_dec_version(dpy: *mut xlib::Display) -> i32 {
|
|||
let mut maj: c_int = 0;
|
|||
let mut min: c_int = 0;
|
|||
unsafe {
|
|||
if glXQueryVersion(dpy,
|
|||
&mut maj as *mut c_int,
|
|||
&mut min as *mut c_int) == 0 {
|
|||
panic!("cannot get glx version");
|
|||
}
|
|||
}
|
|||
(maj*10 + min) as i32
|
|||
}
|
|||
|
|||
|
|||
fn get_glxfbconfig(dpy: *mut xlib::Display, screen_num: i32,
|
|||
visual_attribs: &[i32]) -> GLXFBConfig {
|
|||
unsafe {
|
|||
let mut fbcount: c_int = 0;
|
|||
let fbcs = glXChooseFBConfig(dpy, screen_num,
|
|||
visual_attribs.as_ptr(),
|
|||
&mut fbcount as *mut c_int);
|
|||
|
|||
if fbcount == 0 {
|
|||
panic!("could not find compatible fb config");
|
|||
}
|
|||
// we pick the first from the list
|
|||
let fbc = *fbcs;
|
|||
xlib::XFree(fbcs as *mut c_void);
|
|||
fbc
|
|||
}
|
|||
}
|
|||
|
|||
|
|||
fn main() { unsafe {
|
|||
let (conn, screen_num) = xcb::Connection::connect_with_xlib_display().unwrap();
|
|||
conn.set_event_queue_owner(xcb::EventQueueOwner::Xcb);
|
|||
|
|||
if glx_dec_version(conn.get_raw_dpy()) < 13 {
|
|||
panic!("glx-1.3 is not supported");
|
|||
}
|
|||
|
|||
let fbc = get_glxfbconfig(conn.get_raw_dpy(), screen_num, &[
|
|||
GLX_X_RENDERABLE , 1,
|
|||
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
|
|||
GLX_RENDER_TYPE , GLX_RGBA_BIT,
|
|||
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
|
|||
GLX_RED_SIZE , 8,
|
|||
GLX_GREEN_SIZE , 8,
|
|||
GLX_BLUE_SIZE , 8,
|
|||
GLX_ALPHA_SIZE , 8,
|
|||
GLX_DEPTH_SIZE , 24,
|
|||
GLX_STENCIL_SIZE , 8,
|
|||
GLX_DOUBLEBUFFER , 1,
|
|||
0
|
|||
]);
|
|||
|
|||
let vi: *const xlib::XVisualInfo =
|
|||
glXGetVisualFromFBConfig(conn.get_raw_dpy(), fbc);
|
|||
|
|||
let dri2_ev = {
|
|||
conn.prefetch_extension_data(dri2::id());
|
|||
match conn.get_extension_data(dri2::id()) {
|
|||
None => { panic!("could not load dri2 extension") },
|
|||
Some(r) => { r.first_event() }
|
|||
}
|
|||
};
|
|||
|
|||
let (wm_protocols, wm_delete_window) = {
|
|||
let pc = xcb::intern_atom(&conn, false, "WM_PROTOCOLS");
|
|||
let dwc = xcb::intern_atom(&conn, false, "WM_DELETE_WINDOW");
|
|||
|
|||
let p = match pc.get_reply() {
|
|||
Ok(p) => p.atom(),
|
|||
Err(_) => panic!("could not load WM_PROTOCOLS atom")
|
|||
};
|
|||
let dw = match dwc.get_reply() {
|
|||
Ok(dw) => dw.atom(),
|
|||
Err(_) => panic!("could not load WM_DELETE_WINDOW atom")
|
|||
};
|
|||
(p, dw)
|
|||
};
|
|||
|
|||
let setup = conn.get_setup();
|
|||
let screen = setup.roots().nth((*vi).screen as usize).unwrap();
|
|||
|
|||
let cmap = conn.generate_id();
|
|||
let win = conn.generate_id();
|
|||
|
|||
xcb::create_colormap(&conn, xcb::COLORMAP_ALLOC_NONE as u8,
|
|||
cmap, screen.root(), (*vi).visualid as u32);
|
|||
|
|||
let cw_values = [
|
|||
(xcb::CW_BACK_PIXEL, screen.white_pixel()),
|
|||
(xcb::CW_BORDER_PIXEL, screen.black_pixel()),
|
|||
(xcb::CW_EVENT_MASK,
|
|||
xcb::EVENT_MASK_KEY_PRESS | xcb::EVENT_MASK_EXPOSURE),
|
|||
(xcb::CW_COLORMAP, cmap)
|
|||
];
|
|||
|
|||
xcb::create_window(&conn, (*vi).depth as u8, win, screen.root(), 0, 0, 640, 480,
|
|||
0, xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
|
|||
(*vi).visualid as u32, &cw_values);
|
|||
|
|||
xlib::XFree(vi as *mut c_void);
|
|||
|
|||
let title = "XCB OpenGL";
|
|||
xcb::change_property(&conn,
|
|||
xcb::PROP_MODE_REPLACE as u8,
|
|||
win,
|
|||
xcb::ATOM_WM_NAME,
|
|||
xcb::ATOM_STRING,
|
|||
8, title.as_bytes());
|
|||
|
|||
let protocols = [wm_delete_window];
|
|||
xcb::change_property(&conn, xcb::PROP_MODE_REPLACE as u8,
|
|||
win, wm_protocols, xcb::ATOM_ATOM, 32, &protocols);
|
|||
|
|||
xcb::map_window(&conn, win);
|
|||
conn.flush();
|
|||
xlib::XSync(conn.get_raw_dpy(), xlib::False);
|
|||
|
|||
let glx_exts = CStr::from_ptr(
|
|||
glXQueryExtensionsString(conn.get_raw_dpy(), screen_num))
|
|||
.to_str().unwrap();
|
|||
|
|||
if !check_glx_extension(&glx_exts, "GLX_ARB_create_context") {
|
|||
panic!("could not find GLX extension GLX_ARB_create_context");
|
|||
}
|
|||
|
|||
// with glx, no need of a current context is needed to load symbols
|
|||
// otherwise we would need to create a temporary legacy GL context
|
|||
// for loading symbols (at least glXCreateContextAttribsARB)
|
|||
let glx_create_context_attribs: GlXCreateContextAttribsARBProc =
|
|||
std::mem::transmute(load_gl_func("glXCreateContextAttribsARB"));
|
|||
|
|||
// loading all other symbols
|
|||
gl::load_with(|n| load_gl_func(&n));
|
|||
|
|||
if !gl::GenVertexArrays::is_loaded() {
|
|||
panic!("no GL3 support available!");
|
|||
}
|
|||
|
|||
// installing an event handler to check if error is generated
|
|||
ctx_error_occurred = false;
|
|||
let old_handler = xlib::XSetErrorHandler(Some(ctx_error_handler));
|
|||
|
|||
let context_attribs: [c_int; 5] = [
|
|||
GLX_CONTEXT_MAJOR_VERSION_ARB as c_int, 3,
|
|||
GLX_CONTEXT_MINOR_VERSION_ARB as c_int, 0,
|
|||
0
|
|||
];
|
|||
let ctx = glx_create_context_attribs(conn.get_raw_dpy(), fbc, null_mut(),
|
|||
xlib::True, &context_attribs[0] as *const c_int);
|
|||
|
|||
conn.flush();
|
|||
xlib::XSync(conn.get_raw_dpy(), xlib::False);
|
|||
xlib::XSetErrorHandler(std::mem::transmute(old_handler));
|
|||
|
|||
if ctx.is_null() || ctx_error_occurred {
|
|||
panic!("error when creating gl-3.0 context");
|
|||
}
|
|||
|
|||
if glXIsDirect(conn.get_raw_dpy(), ctx) == 0 {
|
|||
panic!("obtained indirect rendering context")
|
|||
}
|
|||
|
|||
loop {
|
|||
if let Some(ev) = conn.wait_for_event() {
|
|||
let ev_type = ev.response_type() & !0x80;
|
|||
match ev_type {
|
|||
xcb::EXPOSE => {
|
|||
glXMakeCurrent(conn.get_raw_dpy(), win as xlib::XID, ctx);
|
|||
gl::ClearColor(0.5f32, 0.5f32, 1.0f32, 1.0f32);
|
|||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
|||
gl::Flush();
|
|||
check_gl_error();
|
|||
glXSwapBuffers(conn.get_raw_dpy(), win as xlib::XID);
|
|||
glXMakeCurrent(conn.get_raw_dpy(), 0, null_mut());
|
|||
},
|
|||
xcb::KEY_PRESS => {
|
|||
break;
|
|||
},
|
|||
xcb::CLIENT_MESSAGE => {
|
|||
let cmev = unsafe {
|
|||
xcb::cast_event::<xcb::ClientMessageEvent>(&ev)
|
|||
};
|
|||
if cmev.type_() == wm_protocols && cmev.format() == 32 {
|
|||
let protocol = cmev.data().data32()[0];
|
|||
if protocol == wm_delete_window {
|
|||
break;
|
|||
}
|
|||
}
|
|||
},
|
|||
_ => {
|
|||
// following stuff is not obvious at all, but is necessary
|
|||
// to handle GL when XCB owns the event queue
|
|||
if ev_type == dri2_ev || ev_type == dri2_ev+1 {
|
|||
// these are libgl dri2 event that need special handling
|
|||
// see https://bugs.freedesktop.org/show_bug.cgi?id=35945#c4
|
|||
// and mailing thread starting here:
|
|||
// http://lists.freedesktop.org/archives/xcb/2015-November/010556.html
|
|||
|
|||
if let Some(proc_) =
|
|||
xlib::XESetWireToEvent(conn.get_raw_dpy(),
|
|||
ev_type as i32, None) {
|
|||
xlib::XESetWireToEvent(conn.get_raw_dpy(),
|
|||
ev_type as i32, Some(proc_));
|
|||
let raw_ev = ev.ptr;
|
|||
(*raw_ev).sequence =
|
|||
xlib::XLastKnownRequestProcessed(
|
|||
conn.get_raw_dpy()) as u16;
|
|||
let mut dummy: xlib::XEvent = std::mem::zeroed();
|
|||
proc_(conn.get_raw_dpy(),
|
|||
&mut dummy as *mut xlib::XEvent,
|
|||
raw_ev as *mut xlib::xEvent);
|
|||
}
|
|||
|
|||
}
|
|||
}
|
|||
}
|
|||
conn.flush();
|
|||
}
|
|||
else {
|
|||
break;
|
|||
}
|
|||
}
|
|||
|
|||
// only to make sure that rs_client generate correct names for DRI2
|
|||
// (used to be "*_DRI_2_*")
|
|||
// should be in a "compile tests" section instead of example
|
|||
let _ = xcb::ffi::dri2::XCB_DRI2_ATTACHMENT_BUFFER_ACCUM;
|
|||
|
|||
glXDestroyContext(conn.get_raw_dpy(), ctx);
|
|||
|
|||
xcb::unmap_window(&conn, win);
|
|||
xcb::destroy_window(&conn, win);
|
|||
xcb::free_colormap(&conn, cmap);
|
|||
conn.flush();
|
|||
}}
|
|||
@ -0,0 +1,202 @@ |
|||
extern crate xcb;
|
|||
|
|||
use std::iter::{Iterator};
|
|||
use std::{thread, time};
|
|||
use std::sync::Arc;
|
|||
use std::ptr::{null, null_mut};
|
|||
use std::slice::from_raw_parts_mut;
|
|||
|
|||
pub fn getshm<'a>(size :usize) -> (i32, &'a mut [u32]) {
|
|||
unsafe {
|
|||
let id = libc::shmget( libc::IPC_PRIVATE
|
|||
, size * 4
|
|||
, libc::IPC_CREAT | 0o744 );
|
|||
let ptr = libc::shmat(id, null(), 0);
|
|||
(id as i32, from_raw_parts_mut(ptr as *mut u32, size))
|
|||
}
|
|||
}
|
|||
|
|||
fn main() {
|
|||
let points: &[xcb::Point] = &[ xcb::Point::new(10, 10)
|
|||
, xcb::Point::new(10, 20)
|
|||
, xcb::Point::new(20, 10)
|
|||
, xcb::Point::new(20, 20) ];
|
|||
let polyline: &[xcb::Point] = &[ xcb::Point::new(50, 10 )
|
|||
// rest of points are relative
|
|||
, xcb::Point::new( 5, 20 )
|
|||
, xcb::Point::new(25, -20)
|
|||
, xcb::Point::new(10, 10 ) ];
|
|||
let segments: &[xcb::Segment] = &[ xcb::Segment::new(100, 10, 140, 30)
|
|||
, xcb::Segment::new(110, 25, 130, 60) ];
|
|||
let rectangles: &[xcb::Rectangle]
|
|||
= &[ xcb::Rectangle::new(10, 50, 40, 20)
|
|||
, xcb::Rectangle::new(80, 50, 10, 40) ];
|
|||
let arcs: &[xcb::Arc] = &[ xcb::Arc::new(10, 100, 60, 40, 0, 90 << 6)
|
|||
, xcb::Arc::new(90, 100, 55, 40, 0, 270 << 6) ];
|
|||
|
|||
let (conn, screen_num) = {
|
|||
let (conn, screen_num) = xcb::Connection::connect(None).unwrap();
|
|||
(Arc::new(conn), screen_num)
|
|||
};
|
|||
let setup = conn.get_setup();
|
|||
let screen = setup.roots().nth(screen_num as usize).unwrap();
|
|||
|
|||
let (shmid, shm) = getshm(150 * 150);
|
|||
let shmseg = conn.generate_id();
|
|||
xcb::shm::attach(&conn, shmseg, shmid as u32, false);
|
|||
unsafe { libc::shmctl(shmid, libc::IPC_RMID, null_mut()); }
|
|||
|
|||
let foreground = conn.generate_id();
|
|||
let pix = conn.generate_id();
|
|||
|
|||
xcb::create_gc( &conn
|
|||
, foreground
|
|||
, screen.root()
|
|||
, &[ (xcb::GC_FOREGROUND, screen.black_pixel())
|
|||
, (xcb::GC_GRAPHICS_EXPOSURES, 0) ] );
|
|||
|
|||
let window = conn.generate_id();
|
|||
let values = [ ( xcb::CW_BACK_PIXEL, screen.white_pixel() )
|
|||
, ( xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE
|
|||
| xcb::EVENT_MASK_KEY_PRESS
|
|||
| xcb::EVENT_MASK_STRUCTURE_NOTIFY
|
|||
| xcb::EVENT_MASK_PROPERTY_CHANGE ) ];
|
|||
xcb::create_window( &conn
|
|||
, xcb::COPY_FROM_PARENT as u8
|
|||
, window
|
|||
, screen.root()
|
|||
, 0, 0, 150, 150, 0
|
|||
, xcb::WINDOW_CLASS_INPUT_OUTPUT as u16
|
|||
, screen.root_visual()
|
|||
, &values);
|
|||
|
|||
xcb::shm::create_pixmap( &conn
|
|||
, pix
|
|||
, window
|
|||
, 150, 150
|
|||
, screen.root_depth()
|
|||
, shmseg
|
|||
, 0 );
|
|||
|
|||
xcb::map_window(&conn, window);
|
|||
|
|||
{
|
|||
let conn = conn.clone();
|
|||
|
|||
thread::spawn(move || {
|
|||
let mut blink = false;
|
|||
|
|||
let mut i = 0;
|
|||
loop {
|
|||
let title = if blink {
|
|||
"Basic Threaded Window ;-)"
|
|||
} else {
|
|||
"Basic Threaded Window :-)"
|
|||
};
|
|||
|
|||
shm[i] = 0xFFFFFF;
|
|||
i = (i + 1) % (150 * 150);
|
|||
|
|||
let c = xcb::change_property_checked(
|
|||
&conn
|
|||
, xcb::PROP_MODE_REPLACE as u8
|
|||
, window
|
|||
, xcb::ATOM_WM_NAME
|
|||
, xcb::ATOM_STRING
|
|||
, 8
|
|||
, title.as_bytes() );
|
|||
|
|||
xcb::copy_area( &conn
|
|||
, pix
|
|||
, window
|
|||
, foreground
|
|||
, 0, 0, 0, 0
|
|||
, 150, 150);
|
|||
|
|||
if conn.has_error().is_err() || c.request_check().is_err() {
|
|||
break;
|
|||
}
|
|||
|
|||
blink = !blink;
|
|||
thread::sleep(time::Duration::from_millis(500));
|
|||
}
|
|||
});
|
|||
}
|
|||
|
|||
conn.flush();
|
|||
|
|||
loop {
|
|||
let event = conn.wait_for_event();
|
|||
|
|||
match event {
|
|||
None => break,
|
|||
Some(event) => {
|
|||
match event.response_type() & !0x80 {
|
|||
xcb::PROPERTY_NOTIFY => {
|
|||
let prop_notify: &xcb::PropertyNotifyEvent = unsafe {
|
|||
xcb::cast_event(&event)
|
|||
};
|
|||
|
|||
if prop_notify.atom() == xcb::ATOM_WM_NAME {
|
|||
// retrieving title
|
|||
let cookie = xcb::get_property( &conn
|
|||
, false
|
|||
, window
|
|||
, xcb::ATOM_WM_NAME
|
|||
, xcb::ATOM_STRING
|
|||
, 0, 1024);
|
|||
|
|||
if let Ok(reply) = cookie.get_reply() {
|
|||
let r = reply.value();
|
|||
let r = std::str::from_utf8(r).unwrap();
|
|||
|
|||
println!( "title changed to \"{}\"", r);
|
|||
}
|
|||
}
|
|||
},
|
|||
|
|||
xcb::EXPOSE => {
|
|||
xcb::poly_point( &conn
|
|||
, xcb::COORD_MODE_ORIGIN as u8
|
|||
, window
|
|||
, foreground
|
|||
, &points );
|
|||
xcb::poly_line( &conn
|
|||
, xcb::COORD_MODE_PREVIOUS as u8
|
|||
, window
|
|||
, foreground
|
|||
, &polyline );
|
|||
xcb::poly_segment( &conn
|
|||
, window
|
|||
, foreground
|
|||
, &segments );
|
|||
xcb::poly_rectangle( &conn
|
|||
, window
|
|||
, foreground
|
|||
, &rectangles );
|
|||
xcb::poly_arc( &conn
|
|||
, window
|
|||
, foreground
|
|||
, &arcs );
|
|||
|
|||
conn.flush();
|
|||
},
|
|||
|
|||
xcb::KEY_PRESS => {
|
|||
let key_press: &xcb::KeyPressEvent = unsafe {
|
|||
xcb::cast_event(&event)
|
|||
};
|
|||
|
|||
println!("Key '{}' pressed", key_press.detail());
|
|||
|
|||
if key_press.detail() == 0x18 { // Q (on qwerty)
|
|||
break;
|
|||
}
|
|||
},
|
|||
|
|||
_ => {},
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue