Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
80
third-party/vendor/smithay-client-toolkit/examples/compositor_info.rs
vendored
Normal file
80
third-party/vendor/smithay-client-toolkit/examples/compositor_info.rs
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
extern crate smithay_client_toolkit as sctk;
|
||||
|
||||
use sctk::shell::Shell;
|
||||
|
||||
// This is a small program that queries the compositor for
|
||||
// various information and prints them on the console before exiting.
|
||||
|
||||
sctk::default_environment!(CompInfo, desktop);
|
||||
|
||||
fn main() -> Result<(), ()> {
|
||||
let (env, _display, _queue) = sctk::new_default_environment!(CompInfo, desktop)
|
||||
.expect("Unable to connect to a Wayland compositor");
|
||||
|
||||
println!("== Smithay's compositor info tool ==\n");
|
||||
|
||||
// print the best supported shell
|
||||
println!(
|
||||
"-> Most recent shell supported by the compositor is {}.",
|
||||
match env.get_shell() {
|
||||
Some(Shell::Wl(_)) => "the legacy wl_shell",
|
||||
Some(Shell::Zxdg(_)) => "the old unstable xdg_shell (zxdg_shell_v6)",
|
||||
Some(Shell::Xdg(_)) => "the current xdg_shell",
|
||||
None => "nothing",
|
||||
}
|
||||
);
|
||||
println!();
|
||||
|
||||
// print the outputs
|
||||
let outputs = env.get_all_outputs();
|
||||
println!("-> Compositor advertised {} outputs:", outputs.len());
|
||||
for output in outputs {
|
||||
sctk::output::with_output_info(&output, |info| {
|
||||
println!(
|
||||
" -> #{}: {} ({}), with scale factor of {}",
|
||||
info.id, info.model, info.make, info.scale_factor
|
||||
);
|
||||
println!(" Possible modes are:");
|
||||
for mode in &info.modes {
|
||||
println!(
|
||||
" -> [{}{}] {} x {} @ {}.{} Hz",
|
||||
if mode.is_preferred { "p" } else { " " },
|
||||
if mode.is_current { "c" } else { " " },
|
||||
mode.dimensions.0,
|
||||
mode.dimensions.1,
|
||||
mode.refresh_rate / 1000,
|
||||
mode.refresh_rate % 1000
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
println!();
|
||||
|
||||
// print the seats
|
||||
let seats = env.get_all_seats();
|
||||
println!("-> Compositor advertised {} seats:", seats.len());
|
||||
for seat in seats {
|
||||
sctk::seat::with_seat_data(&seat, |data| {
|
||||
print!(" -> {} with capabilities: ", data.name);
|
||||
if data.has_pointer {
|
||||
print!("pointer ");
|
||||
}
|
||||
if data.has_keyboard {
|
||||
print!("keyboard ");
|
||||
}
|
||||
if data.has_touch {
|
||||
print!("touch ");
|
||||
}
|
||||
println!();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
if env.decorations_mgr.is_some() {
|
||||
println!("-> Compositor supports server-side decorations.")
|
||||
} else {
|
||||
println!("-> Compositor does not support server-side decorations.")
|
||||
}
|
||||
*/
|
||||
Ok(())
|
||||
}
|
||||
294
third-party/vendor/smithay-client-toolkit/examples/image_viewer.rs
vendored
Normal file
294
third-party/vendor/smithay-client-toolkit/examples/image_viewer.rs
vendored
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
extern crate image;
|
||||
extern crate smithay_client_toolkit as sctk;
|
||||
|
||||
use std::env;
|
||||
|
||||
use sctk::reexports::client::protocol::{wl_shm, wl_surface};
|
||||
use sctk::shm::AutoMemPool;
|
||||
use sctk::window::{Event as WEvent, FallbackFrame, State};
|
||||
|
||||
sctk::default_environment!(ImViewerExample, desktop);
|
||||
|
||||
fn main() {
|
||||
// First of all, retrieve the path from the program arguments:
|
||||
let path = match env::args_os().nth(1) {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
println!("USAGE: ./image_wiewer <PATH>");
|
||||
return;
|
||||
}
|
||||
};
|
||||
// now, try to open the image
|
||||
// the image crate will take care of auto-detecting the file format
|
||||
let image = match image::open(&path) {
|
||||
Ok(i) => i,
|
||||
Err(e) => {
|
||||
println!("Failed to open image {}.", path.to_string_lossy());
|
||||
println!("Error was: {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
// We'll need the image in RGBA for drawing it
|
||||
let image = image.to_rgba8();
|
||||
|
||||
/*
|
||||
* Initalize the wayland connection
|
||||
*/
|
||||
let (env, _display, mut queue) = sctk::new_default_environment!(ImViewerExample, desktop)
|
||||
.expect("Unable to connect to a Wayland compositor");
|
||||
|
||||
// Use the compositor global to create a new surface
|
||||
let surface = env
|
||||
.create_surface_with_scale_callback(|dpi, _surface, _dispatch_data| {
|
||||
println!("dpi changed to {}", dpi);
|
||||
})
|
||||
.detach();
|
||||
|
||||
/*
|
||||
* Init the window
|
||||
*/
|
||||
|
||||
// First of all, this Option<WEvent> will store
|
||||
// any event from the window that we'll need to process. We
|
||||
// store them and will process them later in the event loop
|
||||
// rather that process them directly because in a batch of
|
||||
// generated events, often only the last one needs to actually
|
||||
// be processed, and some events may render other obsoletes.
|
||||
// See the closure a few lines below for details
|
||||
let mut next_action = None::<WEvent>;
|
||||
|
||||
// Now we actually create the window. The type parameter `ConceptFrame` here
|
||||
// specifies the type we want to use to draw the borders. To create your own
|
||||
// decorations you just need an object to implement the `Frame` trait.
|
||||
let mut window = env
|
||||
.create_window::<FallbackFrame, _>(
|
||||
surface, // the wl_surface that serves as the basis of this window
|
||||
None, // None for theme_manager, since we don't theme pointer outself
|
||||
image.dimensions(), // the initial internal dimensions of the window
|
||||
move |evt, mut dispatch_data| {
|
||||
// This is the closure that process the Window events.
|
||||
// There are 3 possible events:
|
||||
// - Close: the user requested the window to be closed, we'll then quit
|
||||
// - Configure: the server suggested a new state for the window (possibly
|
||||
// a new size if a resize is in progress). We'll likely need to redraw
|
||||
// our contents
|
||||
// - Refresh: the frame itself needs to be redrawn. SCTK does not do this
|
||||
// automatically because it has a cost and should only be done in periods
|
||||
// of the event loop where the client actually wants to draw
|
||||
// Here we actually only keep the last event receive according to a priority
|
||||
// order of Close > Configure > Refresh.
|
||||
// Indeed, if we received a Close, there is not point drawing anything more as
|
||||
// we will exit. A new Configure overrides a previous one, and if we received
|
||||
// a Configure we will refresh the frame anyway.
|
||||
|
||||
// We access the next_action Option via the dispatch_data provided by wayland-rs.
|
||||
let next_action = dispatch_data.get::<Option<WEvent>>().unwrap();
|
||||
// Check if we need to replace the old event by the new one
|
||||
let replace = matches!(
|
||||
(&evt, &*next_action),
|
||||
// replace if there is no old event
|
||||
(_, &None)
|
||||
// or the old event is refresh
|
||||
| (_, &Some(WEvent::Refresh))
|
||||
// or we had a configure and received a new one
|
||||
| (&WEvent::Configure { .. }, &Some(WEvent::Configure { .. }))
|
||||
// or the new event is close
|
||||
| (&WEvent::Close, _)
|
||||
);
|
||||
if replace {
|
||||
*next_action = Some(evt);
|
||||
}
|
||||
},
|
||||
// creating the window may fail if the code drawing the frame
|
||||
// fails to initialize itself. For ConceptFrame this should not happen
|
||||
// unless the system is utterly broken, though.
|
||||
)
|
||||
.expect("Failed to create a window !");
|
||||
|
||||
// Setting the windows title allows the compositor to know what your
|
||||
// window should be called and the title will be display on the header bar
|
||||
// of the windows decorations
|
||||
window.set_title("Image Viewer".to_string());
|
||||
|
||||
/*
|
||||
* Initialization of the memory pool
|
||||
*/
|
||||
let mut pool = env.create_auto_pool().expect("Failed to create the memory pool.");
|
||||
|
||||
/*
|
||||
* Event Loop preparation and running
|
||||
*/
|
||||
|
||||
// First, we initialize a few boolean flags that we'll use to track our state:
|
||||
// - the window needs to be redrawn
|
||||
let mut need_redraw = false;
|
||||
// - are we currently in the process of being resized? (to draw the image or
|
||||
// black content)
|
||||
let mut resizing = false;
|
||||
// - the size of our contents
|
||||
let mut dimensions = image.dimensions();
|
||||
|
||||
// if our shell does not need to wait for a configure event, we draw right away.
|
||||
//
|
||||
// Note that this is only the case for the old wl_shell protocol, which is now
|
||||
// deprecated. This code is only for compatibility with old server that do not
|
||||
// support the new standard xdg_shell protocol.
|
||||
//
|
||||
// But if we have fallbacked to wl_shell, we need to draw right away because we'll
|
||||
// never receive a configure event if we don't draw something...
|
||||
if !env.get_shell().unwrap().needs_configure() {
|
||||
// initial draw to bootstrap on wl_shell
|
||||
redraw(&mut pool, window.surface(), dimensions, if resizing { None } else { Some(&image) })
|
||||
.expect("Failed to draw");
|
||||
window.refresh();
|
||||
}
|
||||
|
||||
// We can now actually enter the event loop!
|
||||
loop {
|
||||
// First, check if any pending action was received by the
|
||||
// Window implementation:
|
||||
match next_action.take() {
|
||||
// We received a Close event, just break from the loop
|
||||
// and let the app quit
|
||||
Some(WEvent::Close) => break,
|
||||
// We receive a Refresh event, store that we need to refresh the
|
||||
// frame
|
||||
Some(WEvent::Refresh) => {
|
||||
window.refresh();
|
||||
window.surface().commit();
|
||||
}
|
||||
// We received a configure event, our action depends on its
|
||||
// contents
|
||||
Some(WEvent::Configure { new_size, states }) => {
|
||||
// the configure event contains a suggested size,
|
||||
// if it is different from our current size, we need to
|
||||
// update it and redraw
|
||||
if let Some((w, h)) = new_size {
|
||||
if dimensions != (w, h) {
|
||||
dimensions = (w, h);
|
||||
}
|
||||
}
|
||||
window.resize(dimensions.0, dimensions.1);
|
||||
window.refresh();
|
||||
// Are we currently resizing ?
|
||||
// We check if a resizing just started or stopped,
|
||||
// because in this case we'll swap between drawing black
|
||||
// and drawing the window (or the reverse), and thus we need to
|
||||
// redraw
|
||||
let new_resizing = states.contains(&State::Resizing);
|
||||
resizing = new_resizing;
|
||||
|
||||
need_redraw = true;
|
||||
}
|
||||
// No event, nothing new to do.
|
||||
None => {}
|
||||
}
|
||||
|
||||
if need_redraw {
|
||||
// We don't need to redraw or refresh anymore =)
|
||||
need_redraw = false;
|
||||
redraw(
|
||||
&mut pool,
|
||||
window.surface(),
|
||||
dimensions,
|
||||
if resizing { None } else { Some(&image) },
|
||||
)
|
||||
.expect("Failed to draw")
|
||||
}
|
||||
|
||||
// Finally, dispatch the event queue. This method blocks until a message
|
||||
// sends all our request to the server, then blocks until an event arrives
|
||||
// from it. It then processes all events by calling the implementation of
|
||||
// the target object for each, and only return once all pending messages
|
||||
// have been processed.
|
||||
queue.dispatch(&mut next_action, |_, _, _| {}).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// The draw function, which drawn `base_image` in the provided `MemPool`,
|
||||
// at given dimensions.
|
||||
//
|
||||
// If `base_image` is `None`, it'll just draw black contents. This is to
|
||||
// improve performance during resizing: we need to redraw the window frequently
|
||||
// so that its dimensions follow the pointer during the resizing, but resizing the
|
||||
// image is costly and long. So during an interactive resize of the window we'll
|
||||
// just draw black contents to not feel laggy.
|
||||
fn redraw(
|
||||
pool: &mut AutoMemPool,
|
||||
surface: &wl_surface::WlSurface,
|
||||
(buf_x, buf_y): (u32, u32),
|
||||
base_image: Option<&image::ImageBuffer<image::Rgba<u8>, Vec<u8>>>,
|
||||
) -> Result<(), ::std::io::Error> {
|
||||
// We allocate a new buffer from the memory pool with the appropriate dimensions
|
||||
// This function automatically finds an unused space of the correct size in the memory
|
||||
// pool and returns it as a `&mut [u8]`, as well as a `wl_buffer` matching it.
|
||||
let (canvas, new_buffer) = pool.buffer(
|
||||
buf_x as i32, // width of the buffer, in pixels
|
||||
buf_y as i32, // height of the buffer, in pixels
|
||||
4 * buf_x as i32, // stride: number of bytes between the start of two
|
||||
// consecutive rows of pixels
|
||||
wl_shm::Format::Argb8888, // the pixel format we wrote in
|
||||
)?;
|
||||
|
||||
if let Some(base_image) = base_image {
|
||||
// We have an image to draw
|
||||
|
||||
// first, resize it to the requested size. We just use the function provided
|
||||
// by the image crate here.
|
||||
let image =
|
||||
image::imageops::resize(base_image, buf_x, buf_y, image::imageops::FilterType::Nearest);
|
||||
|
||||
// Now, we'll write the pixels of the image to the MemPool.
|
||||
//
|
||||
// We do this in an horribly inefficient manner, for the sake of simplicity.
|
||||
// We'll send pixels to the server in ARGB8888 format (this is one of the only
|
||||
// formats that are guaranteed to be supported), but image provides it in
|
||||
// RGBA8888, so we need to do the conversion.
|
||||
//
|
||||
// Additionally, if the image has some transparent parts, we'll blend them into
|
||||
// a white background, otherwise the server will draw our window with a
|
||||
// transparent background!
|
||||
for (src_pixel, dst_pixel) in image.pixels().zip(canvas.chunks_exact_mut(4)) {
|
||||
// retrieve the pixel values
|
||||
let r = src_pixel.0[0] as u32;
|
||||
let g = src_pixel.0[1] as u32;
|
||||
let b = src_pixel.0[2] as u32;
|
||||
let a = src_pixel.0[3] as u32;
|
||||
// blend them
|
||||
let r = ::std::cmp::min(0xFF, (0xFF * (0xFF - a) + a * r) / 0xFF);
|
||||
let g = ::std::cmp::min(0xFF, (0xFF * (0xFF - a) + a * g) / 0xFF);
|
||||
let b = ::std::cmp::min(0xFF, (0xFF * (0xFF - a) + a * b) / 0xFF);
|
||||
// write the pixel
|
||||
let pixel: [u8; 4] = ((0xFF << 24) + (r << 16) + (g << 8) + b).to_ne_bytes();
|
||||
dst_pixel[0] = pixel[0];
|
||||
dst_pixel[1] = pixel[1];
|
||||
dst_pixel[2] = pixel[2];
|
||||
dst_pixel[3] = pixel[3];
|
||||
}
|
||||
} else {
|
||||
// We do not have any image to draw, so we draw black contents
|
||||
for dst_pixel in canvas.chunks_exact_mut(4) {
|
||||
dst_pixel[0] = 0x00;
|
||||
dst_pixel[1] = 0x00;
|
||||
dst_pixel[2] = 0x00;
|
||||
dst_pixel[3] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
surface.attach(Some(&new_buffer), 0, 0);
|
||||
// damage the surface so that the compositor knows it needs to redraw it
|
||||
if surface.as_ref().version() >= 4 {
|
||||
// If our server is recent enough and supports at least version 4 of the
|
||||
// wl_surface interface, we can specify the damage in buffer coordinates.
|
||||
// This is obviously the best and do that if possible.
|
||||
surface.damage_buffer(0, 0, buf_x as i32, buf_y as i32);
|
||||
} else {
|
||||
// Otherwise, we fallback to compatilibity mode. Here we specify damage
|
||||
// in surface coordinates, which would have been different if we had drawn
|
||||
// our buffer at HiDPI resolution. We didn't though, so it is ok.
|
||||
// Using `damage_buffer` in general is better though.
|
||||
surface.damage(0, 0, buf_x as i32, buf_y as i32);
|
||||
}
|
||||
surface.commit();
|
||||
Ok(())
|
||||
}
|
||||
226
third-party/vendor/smithay-client-toolkit/examples/kbd_input.rs
vendored
Normal file
226
third-party/vendor/smithay-client-toolkit/examples/kbd_input.rs
vendored
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
extern crate smithay_client_toolkit as sctk;
|
||||
|
||||
use std::cmp::min;
|
||||
|
||||
use sctk::reexports::calloop;
|
||||
use sctk::reexports::client::protocol::{wl_keyboard, wl_shm, wl_surface};
|
||||
use sctk::seat::keyboard::{map_keyboard_repeat, Event as KbEvent, RepeatKind};
|
||||
use sctk::shm::AutoMemPool;
|
||||
use sctk::window::{Event as WEvent, FallbackFrame};
|
||||
|
||||
sctk::default_environment!(KbdInputExample, desktop);
|
||||
|
||||
fn main() {
|
||||
/*
|
||||
* Initial setup
|
||||
*/
|
||||
let (env, display, queue) = sctk::new_default_environment!(KbdInputExample, desktop)
|
||||
.expect("Unable to connect to a Wayland compositor");
|
||||
|
||||
/*
|
||||
* Prepare a calloop event loop to handle key repetion
|
||||
*/
|
||||
// Here `Option<WEvent>` is the type of a global value that will be shared by
|
||||
// all callbacks invoked by the event loop.
|
||||
let mut event_loop = calloop::EventLoop::<Option<WEvent>>::try_new().unwrap();
|
||||
|
||||
/*
|
||||
* Create a buffer with window contents
|
||||
*/
|
||||
|
||||
let mut dimensions = (320u32, 240u32);
|
||||
|
||||
/*
|
||||
* Init wayland objects
|
||||
*/
|
||||
|
||||
let surface = env.create_surface().detach();
|
||||
|
||||
let mut window = env
|
||||
.create_window::<FallbackFrame, _>(
|
||||
surface,
|
||||
None,
|
||||
dimensions,
|
||||
move |evt, mut dispatch_data| {
|
||||
let next_action = dispatch_data.get::<Option<WEvent>>().unwrap();
|
||||
// Keep last event in priority order : Close > Configure > Refresh
|
||||
let replace = matches!(
|
||||
(&evt, &*next_action),
|
||||
(_, &None)
|
||||
| (_, &Some(WEvent::Refresh))
|
||||
| (&WEvent::Configure { .. }, &Some(WEvent::Configure { .. }))
|
||||
| (&WEvent::Close, _)
|
||||
);
|
||||
if replace {
|
||||
*next_action = Some(evt);
|
||||
}
|
||||
},
|
||||
)
|
||||
.expect("Failed to create a window !");
|
||||
|
||||
window.set_title("Kbd Input".to_string());
|
||||
|
||||
let mut pool = env.create_auto_pool().expect("Failed to create a memory pool !");
|
||||
|
||||
/*
|
||||
* Keyboard initialization
|
||||
*/
|
||||
|
||||
let mut seats = Vec::<(String, Option<wl_keyboard::WlKeyboard>)>::new();
|
||||
|
||||
// first process already existing seats
|
||||
for seat in env.get_all_seats() {
|
||||
if let Some((has_kbd, name)) = sctk::seat::with_seat_data(&seat, |seat_data| {
|
||||
(seat_data.has_keyboard && !seat_data.defunct, seat_data.name.clone())
|
||||
}) {
|
||||
if has_kbd {
|
||||
let seat_name = name.clone();
|
||||
match map_keyboard_repeat(
|
||||
event_loop.handle(),
|
||||
&seat,
|
||||
None,
|
||||
RepeatKind::System,
|
||||
move |event, _, _| print_keyboard_event(event, &seat_name),
|
||||
) {
|
||||
Ok(kbd) => {
|
||||
seats.push((name, Some(kbd)));
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to map keyboard on seat {} : {:?}.", name, e);
|
||||
seats.push((name, None));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
seats.push((name, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then setup a listener for changes
|
||||
let loop_handle = event_loop.handle();
|
||||
let _seat_listener = env.listen_for_seats(move |seat, seat_data, _| {
|
||||
// find the seat in the vec of seats, or insert it if it is unknown
|
||||
let idx = seats.iter().position(|(name, _)| name == &seat_data.name);
|
||||
let idx = idx.unwrap_or_else(|| {
|
||||
seats.push((seat_data.name.clone(), None));
|
||||
seats.len() - 1
|
||||
});
|
||||
|
||||
let (_, ref mut opt_kbd) = &mut seats[idx];
|
||||
// we should map a keyboard if the seat has the capability & is not defunct
|
||||
if seat_data.has_keyboard && !seat_data.defunct {
|
||||
if opt_kbd.is_none() {
|
||||
// we should initalize a keyboard
|
||||
let seat_name = seat_data.name.clone();
|
||||
match map_keyboard_repeat(
|
||||
loop_handle.clone(),
|
||||
&seat,
|
||||
None,
|
||||
RepeatKind::System,
|
||||
move |event, _, _| print_keyboard_event(event, &seat_name),
|
||||
) {
|
||||
Ok(kbd) => {
|
||||
*opt_kbd = Some(kbd);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to map keyboard on seat {} : {:?}.", seat_data.name, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(kbd) = opt_kbd.take() {
|
||||
// the keyboard has been removed, cleanup
|
||||
kbd.release();
|
||||
}
|
||||
});
|
||||
|
||||
if !env.get_shell().unwrap().needs_configure() {
|
||||
// initial draw to bootstrap on wl_shell
|
||||
redraw(&mut pool, window.surface(), dimensions).expect("Failed to draw");
|
||||
window.refresh();
|
||||
}
|
||||
|
||||
let mut next_action = None;
|
||||
|
||||
sctk::WaylandSource::new(queue).quick_insert(event_loop.handle()).unwrap();
|
||||
|
||||
loop {
|
||||
match next_action.take() {
|
||||
Some(WEvent::Close) => break,
|
||||
Some(WEvent::Refresh) => {
|
||||
window.refresh();
|
||||
window.surface().commit();
|
||||
}
|
||||
Some(WEvent::Configure { new_size, states }) => {
|
||||
if let Some((w, h)) = new_size {
|
||||
window.resize(w, h);
|
||||
dimensions = (w, h)
|
||||
}
|
||||
println!("Window states: {:?}", states);
|
||||
window.refresh();
|
||||
redraw(&mut pool, window.surface(), dimensions).expect("Failed to draw");
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
// always flush the connection before going to sleep waiting for events
|
||||
display.flush().unwrap();
|
||||
|
||||
event_loop.dispatch(None, &mut next_action).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn print_keyboard_event(event: KbEvent, seat_name: &str) {
|
||||
match event {
|
||||
KbEvent::Enter { keysyms, .. } => {
|
||||
println!("Gained focus on seat '{}' while {} keys pressed.", seat_name, keysyms.len(),);
|
||||
}
|
||||
KbEvent::Leave { .. } => {
|
||||
println!("Lost focus on seat '{}'.", seat_name);
|
||||
}
|
||||
KbEvent::Key { keysym, state, utf8, .. } => {
|
||||
println!("Key {:?}: {:x} on seat '{}'.", state, keysym, seat_name);
|
||||
if let Some(txt) = utf8 {
|
||||
println!(" -> Received text \"{}\".", txt);
|
||||
}
|
||||
}
|
||||
KbEvent::Modifiers { modifiers } => {
|
||||
println!("Modifiers changed to {:?} on seat '{}'.", modifiers, seat_name);
|
||||
}
|
||||
KbEvent::Repeat { keysym, utf8, .. } => {
|
||||
println!("Key repetition {:x} on seat '{}'.", keysym, seat_name);
|
||||
if let Some(txt) = utf8 {
|
||||
println!(" -> Received text \"{}\".", txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
fn redraw(
|
||||
pool: &mut AutoMemPool,
|
||||
surface: &wl_surface::WlSurface,
|
||||
(buf_x, buf_y): (u32, u32),
|
||||
) -> Result<(), ::std::io::Error> {
|
||||
let (canvas, new_buffer) =
|
||||
pool.buffer(buf_x as i32, buf_y as i32, 4 * buf_x as i32, wl_shm::Format::Argb8888)?;
|
||||
for (i, dst_pixel) in canvas.chunks_exact_mut(4).enumerate() {
|
||||
let x = i as u32 % buf_x;
|
||||
let y = i as u32 / buf_x;
|
||||
let r: u32 = min(((buf_x - x) * 0xFF) / buf_x, ((buf_y - y) * 0xFF) / buf_y);
|
||||
let g: u32 = min((x * 0xFF) / buf_x, ((buf_y - y) * 0xFF) / buf_y);
|
||||
let b: u32 = min(((buf_x - x) * 0xFF) / buf_x, (y * 0xFF) / buf_y);
|
||||
let pixel: [u8; 4] = ((0xFF << 24) + (r << 16) + (g << 8) + b).to_ne_bytes();
|
||||
dst_pixel[0] = pixel[0];
|
||||
dst_pixel[1] = pixel[1];
|
||||
dst_pixel[2] = pixel[2];
|
||||
dst_pixel[3] = pixel[3];
|
||||
}
|
||||
surface.attach(Some(&new_buffer), 0, 0);
|
||||
if surface.as_ref().version() >= 4 {
|
||||
surface.damage_buffer(0, 0, buf_x as i32, buf_y as i32);
|
||||
} else {
|
||||
surface.damage(0, 0, buf_x as i32, buf_y as i32);
|
||||
}
|
||||
surface.commit();
|
||||
Ok(())
|
||||
}
|
||||
187
third-party/vendor/smithay-client-toolkit/examples/layer_shell.rs
vendored
Normal file
187
third-party/vendor/smithay-client-toolkit/examples/layer_shell.rs
vendored
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
use smithay_client_toolkit::{
|
||||
default_environment,
|
||||
environment::SimpleGlobal,
|
||||
new_default_environment,
|
||||
output::{with_output_info, OutputInfo},
|
||||
reexports::{
|
||||
calloop,
|
||||
client::protocol::{wl_output, wl_shm, wl_surface},
|
||||
client::{Attached, Main},
|
||||
protocols::wlr::unstable::layer_shell::v1::client::{
|
||||
zwlr_layer_shell_v1, zwlr_layer_surface_v1,
|
||||
},
|
||||
},
|
||||
shm::AutoMemPool,
|
||||
WaylandSource,
|
||||
};
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
|
||||
default_environment!(Env,
|
||||
fields = [
|
||||
layer_shell: SimpleGlobal<zwlr_layer_shell_v1::ZwlrLayerShellV1>,
|
||||
],
|
||||
singles = [
|
||||
zwlr_layer_shell_v1::ZwlrLayerShellV1 => layer_shell
|
||||
],
|
||||
);
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
enum RenderEvent {
|
||||
Configure { width: u32, height: u32 },
|
||||
Closed,
|
||||
}
|
||||
|
||||
struct Surface {
|
||||
surface: wl_surface::WlSurface,
|
||||
layer_surface: Main<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1>,
|
||||
next_render_event: Rc<Cell<Option<RenderEvent>>>,
|
||||
pool: AutoMemPool,
|
||||
dimensions: (u32, u32),
|
||||
}
|
||||
|
||||
impl Surface {
|
||||
fn new(
|
||||
output: &wl_output::WlOutput,
|
||||
surface: wl_surface::WlSurface,
|
||||
layer_shell: &Attached<zwlr_layer_shell_v1::ZwlrLayerShellV1>,
|
||||
pool: AutoMemPool,
|
||||
) -> Self {
|
||||
let layer_surface = layer_shell.get_layer_surface(
|
||||
&surface,
|
||||
Some(output),
|
||||
zwlr_layer_shell_v1::Layer::Overlay,
|
||||
"example".to_owned(),
|
||||
);
|
||||
|
||||
layer_surface.set_size(32, 32);
|
||||
// Anchor to the top left corner of the output
|
||||
layer_surface
|
||||
.set_anchor(zwlr_layer_surface_v1::Anchor::Top | zwlr_layer_surface_v1::Anchor::Left);
|
||||
|
||||
let next_render_event = Rc::new(Cell::new(None::<RenderEvent>));
|
||||
let next_render_event_handle = Rc::clone(&next_render_event);
|
||||
layer_surface.quick_assign(move |layer_surface, event, _| {
|
||||
match (event, next_render_event_handle.get()) {
|
||||
(zwlr_layer_surface_v1::Event::Closed, _) => {
|
||||
next_render_event_handle.set(Some(RenderEvent::Closed));
|
||||
}
|
||||
(zwlr_layer_surface_v1::Event::Configure { serial, width, height }, next)
|
||||
if next != Some(RenderEvent::Closed) =>
|
||||
{
|
||||
layer_surface.ack_configure(serial);
|
||||
next_render_event_handle.set(Some(RenderEvent::Configure { width, height }));
|
||||
}
|
||||
(_, _) => {}
|
||||
}
|
||||
});
|
||||
|
||||
// Commit so that the server will send a configure event
|
||||
surface.commit();
|
||||
|
||||
Self { surface, layer_surface, next_render_event, pool, dimensions: (0, 0) }
|
||||
}
|
||||
|
||||
/// Handles any events that have occurred since the last call, redrawing if needed.
|
||||
/// Returns true if the surface should be dropped.
|
||||
fn handle_events(&mut self) -> bool {
|
||||
match self.next_render_event.take() {
|
||||
Some(RenderEvent::Closed) => true,
|
||||
Some(RenderEvent::Configure { width, height }) => {
|
||||
if self.dimensions != (width, height) {
|
||||
self.dimensions = (width, height);
|
||||
self.draw();
|
||||
}
|
||||
false
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&mut self) {
|
||||
let stride = 4 * self.dimensions.0 as i32;
|
||||
let width = self.dimensions.0 as i32;
|
||||
let height = self.dimensions.1 as i32;
|
||||
|
||||
// Note: unwrap() is only used here in the interest of simplicity of the example.
|
||||
// A "real" application should handle the case where both pools are still in use by the
|
||||
// compositor.
|
||||
let (canvas, buffer) =
|
||||
self.pool.buffer(width, height, stride, wl_shm::Format::Argb8888).unwrap();
|
||||
|
||||
for dst_pixel in canvas.chunks_exact_mut(4) {
|
||||
let pixel = 0xff00ff00u32.to_ne_bytes();
|
||||
dst_pixel[0] = pixel[0];
|
||||
dst_pixel[1] = pixel[1];
|
||||
dst_pixel[2] = pixel[2];
|
||||
dst_pixel[3] = pixel[3];
|
||||
}
|
||||
|
||||
// Attach the buffer to the surface and mark the entire surface as damaged
|
||||
self.surface.attach(Some(&buffer), 0, 0);
|
||||
self.surface.damage_buffer(0, 0, width as i32, height as i32);
|
||||
|
||||
// Finally, commit the surface
|
||||
self.surface.commit();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Surface {
|
||||
fn drop(&mut self) {
|
||||
self.layer_surface.destroy();
|
||||
self.surface.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let (env, display, queue) =
|
||||
new_default_environment!(Env, fields = [layer_shell: SimpleGlobal::new(),])
|
||||
.expect("Initial roundtrip failed!");
|
||||
|
||||
let surfaces = Rc::new(RefCell::new(Vec::new()));
|
||||
|
||||
let layer_shell = env.require_global::<zwlr_layer_shell_v1::ZwlrLayerShellV1>();
|
||||
|
||||
let env_handle = env.clone();
|
||||
let surfaces_handle = Rc::clone(&surfaces);
|
||||
let output_handler = move |output: wl_output::WlOutput, info: &OutputInfo| {
|
||||
if info.obsolete {
|
||||
// an output has been removed, release it
|
||||
surfaces_handle.borrow_mut().retain(|(i, _)| *i != info.id);
|
||||
output.release();
|
||||
} else {
|
||||
// an output has been created, construct a surface for it
|
||||
let surface = env_handle.create_surface().detach();
|
||||
let pool = env_handle.create_auto_pool().expect("Failed to create a memory pool!");
|
||||
(*surfaces_handle.borrow_mut())
|
||||
.push((info.id, Surface::new(&output, surface, &layer_shell.clone(), pool)));
|
||||
}
|
||||
};
|
||||
|
||||
// Process currently existing outputs
|
||||
for output in env.get_all_outputs() {
|
||||
if let Some(info) = with_output_info(&output, Clone::clone) {
|
||||
output_handler(output, &info);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup a listener for changes
|
||||
// The listener will live for as long as we keep this handle alive
|
||||
let _listner_handle =
|
||||
env.listen_for_outputs(move |output, info, _| output_handler(output, info));
|
||||
|
||||
let mut event_loop = calloop::EventLoop::<()>::try_new().unwrap();
|
||||
|
||||
WaylandSource::new(queue).quick_insert(event_loop.handle()).unwrap();
|
||||
|
||||
loop {
|
||||
{
|
||||
// Using a new scope so that `surfaces` reference gets dropped
|
||||
surfaces.borrow_mut().retain_mut(|surface| !surface.1.handle_events());
|
||||
}
|
||||
|
||||
display.flush().unwrap();
|
||||
event_loop.dispatch(None, &mut ()).unwrap();
|
||||
}
|
||||
}
|
||||
246
third-party/vendor/smithay-client-toolkit/examples/pointer_input.rs
vendored
Normal file
246
third-party/vendor/smithay-client-toolkit/examples/pointer_input.rs
vendored
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
extern crate smithay_client_toolkit as sctk;
|
||||
|
||||
use std::cmp::min;
|
||||
|
||||
use sctk::reexports::client::protocol::{wl_pointer, wl_shm, wl_surface};
|
||||
use sctk::shm::AutoMemPool;
|
||||
use sctk::window::{Event as WEvent, FallbackFrame};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum NextAction {
|
||||
Refresh,
|
||||
Redraw,
|
||||
Exit,
|
||||
}
|
||||
|
||||
struct WindowConfig {
|
||||
width: u32,
|
||||
height: u32,
|
||||
dpi_scale: i32,
|
||||
next_action: Option<NextAction>,
|
||||
has_drawn_once: bool,
|
||||
}
|
||||
|
||||
impl WindowConfig {
|
||||
pub fn new() -> Self {
|
||||
WindowConfig {
|
||||
width: 320,
|
||||
height: 240,
|
||||
dpi_scale: 1,
|
||||
next_action: None,
|
||||
has_drawn_once: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dimensions(&self) -> (u32, u32) {
|
||||
(self.width * self.dpi_scale as u32, self.height * self.dpi_scale as u32)
|
||||
}
|
||||
|
||||
pub fn handle_action(&mut self, new_action: NextAction) {
|
||||
let replace = matches!(
|
||||
(&self.next_action, &new_action),
|
||||
(&None, _)
|
||||
| (&Some(NextAction::Refresh), _)
|
||||
| (&Some(NextAction::Redraw), &NextAction::Exit)
|
||||
);
|
||||
if replace {
|
||||
self.next_action = Some(new_action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sctk::default_environment!(PtrInputExample, desktop);
|
||||
|
||||
fn main() {
|
||||
/*
|
||||
* Initial setup
|
||||
*/
|
||||
let (env, _display, mut queue) = sctk::new_default_environment!(PtrInputExample, desktop)
|
||||
.expect("Unable to connect to a Wayland compositor");
|
||||
|
||||
/*
|
||||
* Init wayland objects
|
||||
*/
|
||||
|
||||
let mut window_config = WindowConfig::new();
|
||||
|
||||
let surface = env
|
||||
.create_surface_with_scale_callback(move |dpi, surface, mut dispatch_data| {
|
||||
let config = dispatch_data.get::<WindowConfig>().unwrap();
|
||||
surface.set_buffer_scale(dpi);
|
||||
config.dpi_scale = dpi;
|
||||
config.handle_action(NextAction::Redraw);
|
||||
})
|
||||
.detach();
|
||||
|
||||
let mut window = env
|
||||
.create_window::<FallbackFrame, _>(
|
||||
surface,
|
||||
None,
|
||||
window_config.dimensions(),
|
||||
move |event, mut dispatch_data| {
|
||||
let mut config = dispatch_data.get::<WindowConfig>().unwrap();
|
||||
match event {
|
||||
WEvent::Refresh => config.handle_action(NextAction::Refresh),
|
||||
WEvent::Configure { new_size: Some((w, h)), .. } => {
|
||||
if config.dimensions() != (w, h) || !config.has_drawn_once {
|
||||
config.width = w;
|
||||
config.height = h;
|
||||
config.handle_action(NextAction::Redraw);
|
||||
} else {
|
||||
config.handle_action(NextAction::Refresh);
|
||||
}
|
||||
}
|
||||
WEvent::Configure { new_size: None, .. } => {
|
||||
if config.has_drawn_once {
|
||||
config.handle_action(NextAction::Refresh)
|
||||
} else {
|
||||
config.handle_action(NextAction::Redraw)
|
||||
}
|
||||
}
|
||||
WEvent::Close => config.handle_action(NextAction::Exit),
|
||||
}
|
||||
},
|
||||
)
|
||||
.expect("Failed to create a window !");
|
||||
|
||||
let mut pool = env.create_auto_pool().expect("Failed to create a memory pool !");
|
||||
|
||||
/*
|
||||
* Pointer initialization
|
||||
*/
|
||||
let mut seats = Vec::<(String, Option<wl_pointer::WlPointer>)>::new();
|
||||
|
||||
// first process already existing seats
|
||||
for seat in env.get_all_seats() {
|
||||
if let Some((has_ptr, name)) = sctk::seat::with_seat_data(&seat, |seat_data| {
|
||||
(seat_data.has_pointer && !seat_data.defunct, seat_data.name.clone())
|
||||
}) {
|
||||
if has_ptr {
|
||||
let seat_name = name.clone();
|
||||
let pointer = seat.get_pointer();
|
||||
let surface = window.surface().clone();
|
||||
pointer.quick_assign(move |_, event, _| {
|
||||
print_pointer_event(event, &seat_name, &surface)
|
||||
});
|
||||
} else {
|
||||
seats.push((name, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then setup a listener for changes
|
||||
let main_surface = window.surface().clone();
|
||||
let _seat_listener = env.listen_for_seats(move |seat, seat_data, _| {
|
||||
// find the seat in the vec of seats, or insert it if it is unknown
|
||||
let idx = seats.iter().position(|(name, _)| name == &seat_data.name);
|
||||
let idx = idx.unwrap_or_else(|| {
|
||||
seats.push((seat_data.name.clone(), None));
|
||||
seats.len() - 1
|
||||
});
|
||||
|
||||
let (_, ref mut opt_ptr) = &mut seats[idx];
|
||||
// we should map a keyboard if the seat has the capability & is not defunct
|
||||
if seat_data.has_keyboard && !seat_data.defunct {
|
||||
if opt_ptr.is_none() {
|
||||
// we should initalize a keyboard
|
||||
let seat_name = seat_data.name.clone();
|
||||
let pointer = seat.get_pointer();
|
||||
let surface = main_surface.clone();
|
||||
pointer.quick_assign(move |_, event, _| {
|
||||
print_pointer_event(event, &seat_name, &surface)
|
||||
});
|
||||
*opt_ptr = Some(pointer.detach());
|
||||
}
|
||||
} else if let Some(ptr) = opt_ptr.take() {
|
||||
// the pointer has been removed, cleanup
|
||||
ptr.release();
|
||||
}
|
||||
});
|
||||
|
||||
if !env.get_shell().unwrap().needs_configure() {
|
||||
window_config.handle_action(NextAction::Redraw);
|
||||
}
|
||||
|
||||
loop {
|
||||
let next_action = window_config.next_action.take();
|
||||
println!("{:?}", next_action);
|
||||
match next_action {
|
||||
Some(NextAction::Exit) => break,
|
||||
Some(NextAction::Refresh) => {
|
||||
window.refresh();
|
||||
window.surface().commit();
|
||||
}
|
||||
Some(NextAction::Redraw) => {
|
||||
window_config.has_drawn_once = true;
|
||||
let (w, h) = window_config.dimensions();
|
||||
window.resize(w, h);
|
||||
window.refresh();
|
||||
redraw(&mut pool, window.surface(), window_config.dimensions())
|
||||
.expect("Failed to draw");
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
queue.dispatch(&mut window_config, |_, _, _| {}).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
fn redraw(
|
||||
pool: &mut AutoMemPool,
|
||||
surface: &wl_surface::WlSurface,
|
||||
(buf_x, buf_y): (u32, u32),
|
||||
) -> Result<(), ::std::io::Error> {
|
||||
let (canvas, new_buffer) =
|
||||
pool.buffer(buf_x as i32, buf_y as i32, 4 * buf_x as i32, wl_shm::Format::Argb8888)?;
|
||||
for (i, dst_pixel) in canvas.chunks_exact_mut(4).enumerate() {
|
||||
let x = i as u32 % buf_x;
|
||||
let y = i as u32 / buf_x;
|
||||
let r: u32 = min(((buf_x - x) * 0xFF) / buf_x, ((buf_y - y) * 0xFF) / buf_y);
|
||||
let g: u32 = min((x * 0xFF) / buf_x, ((buf_y - y) * 0xFF) / buf_y);
|
||||
let b: u32 = min(((buf_x - x) * 0xFF) / buf_x, (y * 0xFF) / buf_y);
|
||||
let pixel: [u8; 4] = ((0xFF << 24) + (r << 16) + (g << 8) + b).to_ne_bytes();
|
||||
dst_pixel[0] = pixel[0];
|
||||
dst_pixel[1] = pixel[1];
|
||||
dst_pixel[2] = pixel[2];
|
||||
dst_pixel[3] = pixel[3];
|
||||
}
|
||||
surface.attach(Some(&new_buffer), 0, 0);
|
||||
if surface.as_ref().version() >= 4 {
|
||||
surface.damage_buffer(0, 0, buf_x as i32, buf_y as i32);
|
||||
} else {
|
||||
surface.damage(0, 0, buf_x as i32, buf_y as i32);
|
||||
}
|
||||
surface.commit();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_pointer_event(
|
||||
event: wl_pointer::Event,
|
||||
seat_name: &str,
|
||||
main_surface: &wl_surface::WlSurface,
|
||||
) {
|
||||
match event {
|
||||
wl_pointer::Event::Enter { surface, surface_x, surface_y, .. } => {
|
||||
if main_surface == &surface {
|
||||
println!(
|
||||
"Pointer of seat '{}' entered at ({}, {})",
|
||||
seat_name, surface_x, surface_y
|
||||
);
|
||||
}
|
||||
}
|
||||
wl_pointer::Event::Leave { surface, .. } => {
|
||||
if main_surface == &surface {
|
||||
println!("Pointer of seat '{}' left", seat_name);
|
||||
}
|
||||
}
|
||||
wl_pointer::Event::Button { button, state, .. } => {
|
||||
println!("Button {:?} of seat '{}' was {:?}", button, seat_name, state);
|
||||
}
|
||||
wl_pointer::Event::Motion { surface_x, surface_y, .. } => {
|
||||
println!("Pointer motion to ({}, {}) on seat '{}'", surface_x, surface_y, seat_name)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
340
third-party/vendor/smithay-client-toolkit/examples/selection.rs
vendored
Normal file
340
third-party/vendor/smithay-client-toolkit/examples/selection.rs
vendored
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
extern crate smithay_client_toolkit as sctk;
|
||||
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use sctk::{
|
||||
data_device::DataSourceEvent,
|
||||
environment::Environment,
|
||||
primary_selection::PrimarySelectionSourceEvent,
|
||||
seat::keyboard::{map_keyboard_repeat, Event as KbEvent, KeyState, RepeatKind},
|
||||
shm::AutoMemPool,
|
||||
window::{Event as WEvent, FallbackFrame},
|
||||
};
|
||||
|
||||
use sctk::reexports::{
|
||||
calloop::{LoopHandle, RegistrationToken},
|
||||
client::{
|
||||
protocol::{wl_keyboard, wl_seat, wl_shm, wl_surface},
|
||||
DispatchData,
|
||||
},
|
||||
};
|
||||
|
||||
sctk::default_environment!(SelectionExample, desktop);
|
||||
|
||||
// Here the type parameter is a global value that will be shared by
|
||||
// all callbacks invoked by the event loop.
|
||||
type DData = (Environment<SelectionExample>, Option<WEvent>, Option<RegistrationToken>);
|
||||
|
||||
fn main() {
|
||||
/*
|
||||
* Initial setup
|
||||
*/
|
||||
let (env, display, queue) = sctk::new_default_environment!(SelectionExample, desktop)
|
||||
.expect("Unable to connect to a Wayland compositor");
|
||||
|
||||
/*
|
||||
* Prepare a calloop event loop to handle clipboard reading
|
||||
*/
|
||||
let mut event_loop = sctk::reexports::calloop::EventLoop::<DData>::try_new().unwrap();
|
||||
|
||||
// we need a window to receive things actually
|
||||
let mut dimensions = (320u32, 240u32);
|
||||
let surface = env.create_surface().detach();
|
||||
|
||||
let mut window = env
|
||||
.create_window::<FallbackFrame, _>(
|
||||
surface,
|
||||
None,
|
||||
dimensions,
|
||||
move |evt, mut dispatch_data| {
|
||||
let (_, next_action, _) = dispatch_data.get::<DData>().unwrap();
|
||||
// Keep last event in priority order : Close > Configure > Refresh
|
||||
let replace = matches!(
|
||||
(&evt, &*next_action),
|
||||
(_, &None)
|
||||
| (_, &Some(WEvent::Refresh))
|
||||
| (&WEvent::Configure { .. }, &Some(WEvent::Configure { .. }))
|
||||
| (&WEvent::Close, _)
|
||||
);
|
||||
if replace {
|
||||
*next_action = Some(evt);
|
||||
}
|
||||
},
|
||||
)
|
||||
.expect("Failed to create a window !");
|
||||
window.set_title("Selection example".to_string());
|
||||
|
||||
println!("Press c/C p/P to copy/paste from selection/primary clipboard respectively.");
|
||||
|
||||
let mut pool = env.create_auto_pool().expect("Failed to create a memory pool !");
|
||||
|
||||
let mut seats = Vec::<(String, Option<wl_keyboard::WlKeyboard>)>::new();
|
||||
|
||||
// first process already existing seats
|
||||
for seat in env.get_all_seats() {
|
||||
if let Some((has_kbd, name)) = sctk::seat::with_seat_data(&seat, |seat_data| {
|
||||
(seat_data.has_keyboard && !seat_data.defunct, seat_data.name.clone())
|
||||
}) {
|
||||
if has_kbd {
|
||||
let my_seat = seat.clone();
|
||||
let handle = event_loop.handle();
|
||||
match map_keyboard_repeat(
|
||||
event_loop.handle(),
|
||||
&seat,
|
||||
None,
|
||||
RepeatKind::System,
|
||||
move |event, _, ddata| process_keyboard_event(event, &my_seat, &handle, ddata),
|
||||
) {
|
||||
Ok(kbd) => {
|
||||
seats.push((name, Some(kbd)));
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to map keyboard on seat {} : {:?}.", name, e);
|
||||
seats.push((name, None));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
seats.push((name, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then setup a listener for changes
|
||||
let loop_handle = event_loop.handle();
|
||||
let _seat_listener = env.listen_for_seats(move |seat, seat_data, _| {
|
||||
// find the seat in the vec of seats, or insert it if it is unknown
|
||||
let idx = seats.iter().position(|(name, _)| name == &seat_data.name);
|
||||
let idx = idx.unwrap_or_else(|| {
|
||||
seats.push((seat_data.name.clone(), None));
|
||||
seats.len() - 1
|
||||
});
|
||||
|
||||
let (_, ref mut opt_kbd) = &mut seats[idx];
|
||||
// we should map a keyboard if the seat has the capability & is not defunct
|
||||
if seat_data.has_keyboard && !seat_data.defunct {
|
||||
if opt_kbd.is_none() {
|
||||
// we should initalize a keyboard
|
||||
let my_seat = seat.clone();
|
||||
let handle = loop_handle.clone();
|
||||
match map_keyboard_repeat(
|
||||
handle.clone(),
|
||||
&seat,
|
||||
None,
|
||||
RepeatKind::System,
|
||||
move |event, _, ddata| process_keyboard_event(event, &my_seat, &handle, ddata),
|
||||
) {
|
||||
Ok(kbd) => {
|
||||
*opt_kbd = Some(kbd);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to map keyboard on seat {} : {:?}.", seat_data.name, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(kbd) = opt_kbd.take() {
|
||||
// the keyboard has been removed, cleanup
|
||||
kbd.release();
|
||||
}
|
||||
});
|
||||
|
||||
if !env.get_shell().unwrap().needs_configure() {
|
||||
// initial draw to bootstrap on wl_shell
|
||||
redraw(&mut pool, window.surface(), dimensions).expect("Failed to draw");
|
||||
window.refresh();
|
||||
}
|
||||
|
||||
// the data that will be shared to all callbacks
|
||||
let mut data: DData = (env, None, None);
|
||||
|
||||
sctk::WaylandSource::new(queue).quick_insert(event_loop.handle()).unwrap();
|
||||
|
||||
loop {
|
||||
match data.1.take() {
|
||||
Some(WEvent::Close) => break,
|
||||
Some(WEvent::Refresh) => {
|
||||
window.refresh();
|
||||
window.surface().commit();
|
||||
}
|
||||
Some(WEvent::Configure { new_size, .. }) => {
|
||||
if let Some((w, h)) = new_size {
|
||||
window.resize(w, h);
|
||||
dimensions = (w, h)
|
||||
}
|
||||
window.refresh();
|
||||
redraw(&mut pool, window.surface(), dimensions).expect("Failed to draw");
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
// always flush the connection before going to sleep waiting for events
|
||||
display.flush().unwrap();
|
||||
|
||||
event_loop.dispatch(None, &mut data).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn process_keyboard_event(
|
||||
event: KbEvent,
|
||||
seat: &wl_seat::WlSeat,
|
||||
handle: &LoopHandle<DData>,
|
||||
mut ddata: DispatchData,
|
||||
) {
|
||||
let (env, _, opt_source) = ddata.get::<DData>().unwrap();
|
||||
if let KbEvent::Key { state, utf8: Some(text), serial, .. } = event {
|
||||
if text == "p" && state == KeyState::Pressed {
|
||||
// pressed the 'p' key, try to read contents !
|
||||
env.with_data_device(seat, |device| {
|
||||
device.with_selection(|offer| {
|
||||
let offer = match offer {
|
||||
Some(offer) => offer,
|
||||
None => {
|
||||
println!("No current selection buffer!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let seat_name =
|
||||
sctk::seat::with_seat_data(seat, |data| data.name.clone()).unwrap();
|
||||
print!("Current selection buffer mime types on seat '{}': [ ", seat_name);
|
||||
let mut has_text = false;
|
||||
offer.with_mime_types(|types| {
|
||||
for t in types {
|
||||
print!("\"{}\", ", t);
|
||||
if t == "text/plain;charset=utf-8" {
|
||||
has_text = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
println!("]");
|
||||
if has_text {
|
||||
println!("Buffer contains text, going to read it...");
|
||||
let reader = offer.receive("text/plain;charset=utf-8".into()).unwrap();
|
||||
let src_handle = handle.clone();
|
||||
let source = handle
|
||||
.insert_source(reader, move |(), file, ddata| {
|
||||
let mut txt = String::new();
|
||||
file.read_to_string(&mut txt).unwrap();
|
||||
println!("Selection contents are: \"{}\"", txt);
|
||||
if let Some(src) = ddata.2.take() {
|
||||
src_handle.remove(src);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
*opt_source = Some(source);
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if text == "P" && state == KeyState::Pressed {
|
||||
env.with_primary_selection(seat, |primary_selection| {
|
||||
println!("In primary selection closure");
|
||||
primary_selection.with_selection(|offer| {
|
||||
let offer = match offer {
|
||||
Some(offer) => offer,
|
||||
None => {
|
||||
println!("No current primary selection buffer!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let seat_name =
|
||||
sctk::seat::with_seat_data(seat, |data| data.name.clone()).unwrap();
|
||||
print!(
|
||||
"Current primary selection buffer mime type on seat '{}': [ ",
|
||||
seat_name
|
||||
);
|
||||
|
||||
let mut has_text = false;
|
||||
offer.with_mime_types(|types| {
|
||||
for t in types {
|
||||
print!("\"{}\", ", t);
|
||||
if t == "text/plain;charset=utf-8" {
|
||||
has_text = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
println!("]");
|
||||
if has_text {
|
||||
println!("Buffer contains text, going to read it...");
|
||||
let reader = offer.receive("text/plain;charset=utf-8".into()).unwrap();
|
||||
let src_handle = handle.clone();
|
||||
let source = handle
|
||||
.insert_source(reader, move |(), file, ddata| {
|
||||
let mut txt = String::new();
|
||||
file.read_to_string(&mut txt).unwrap();
|
||||
println!("Selection contents are: \"{}\"", txt);
|
||||
if let Some(src) = ddata.2.take() {
|
||||
src_handle.remove(src);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
*opt_source = Some(source);
|
||||
}
|
||||
})
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
if text == "c" && state == KeyState::Pressed {
|
||||
let data_source =
|
||||
env.new_data_source(vec!["text/plain;charset=utf-8".into()], move |event, _| {
|
||||
if let DataSourceEvent::Send { mut pipe, .. } = event {
|
||||
let contents = "Hello from clipboard";
|
||||
println!("Setting clipboard to: {}", &contents);
|
||||
write!(pipe, "{}", contents).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
env.with_data_device(seat, |device| {
|
||||
println!("Set selection source");
|
||||
device.set_selection(&Some(data_source), serial);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if text == "C" && state == KeyState::Pressed {
|
||||
let data_source = env.new_primary_selection_source(
|
||||
vec!["text/plain;charset=utf-8".into()],
|
||||
move |event, _| {
|
||||
if let PrimarySelectionSourceEvent::Send { mut pipe, .. } = event {
|
||||
let contents = "Hello from primary selection";
|
||||
println!("Setting clipboard primary clipboard to {}", &contents);
|
||||
write!(pipe, "{}", contents).unwrap();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
env.with_primary_selection(seat, |device| {
|
||||
println!("Set primary selection source");
|
||||
device.set_selection(&Some(data_source), serial);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn redraw(
|
||||
pool: &mut AutoMemPool,
|
||||
surface: &wl_surface::WlSurface,
|
||||
(buf_x, buf_y): (u32, u32),
|
||||
) -> Result<(), ::std::io::Error> {
|
||||
let (canvas, new_buffer) =
|
||||
pool.buffer(buf_x as i32, buf_y as i32, 4 * buf_x as i32, wl_shm::Format::Argb8888)?;
|
||||
for dst_pixel in canvas.chunks_exact_mut(4) {
|
||||
dst_pixel[0] = 0x00;
|
||||
dst_pixel[1] = 0x00;
|
||||
dst_pixel[2] = 0x00;
|
||||
dst_pixel[3] = 0xFF;
|
||||
}
|
||||
surface.attach(Some(&new_buffer), 0, 0);
|
||||
if surface.as_ref().version() >= 4 {
|
||||
surface.damage_buffer(0, 0, buf_x as i32, buf_y as i32);
|
||||
} else {
|
||||
surface.damage(0, 0, buf_x as i32, buf_y as i32);
|
||||
}
|
||||
surface.commit();
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue