1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
//! Test application to list all available outputs.
use std::error::Error;
use smithay_client_toolkit::{
delegate_output, delegate_registry,
output::{OutputHandler, OutputInfo, OutputState},
registry::{ProvidesRegistryState, RegistryState},
registry_handlers,
};
use wayland_client::{globals::registry_queue_init, protocol::wl_output, Connection, QueueHandle};
fn main() -> Result<(), Box<dyn Error>> {
// We initialize the logger for the purpose of debugging.
// Set `RUST_LOG=debug` to see extra debug information.
env_logger::init();
// Try to connect to the Wayland server.
let conn = Connection::connect_to_env()?;
// Now create an event queue and a handle to the queue so we can create objects.
let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
let qh = event_queue.handle();
// Initialize the registry handling so other parts of Smithay's client toolkit may bind
// globals.
let registry_state = RegistryState::new(&globals);
// Initialize the delegate we will use for outputs.
let output_delegate = OutputState::new(&globals, &qh);
// Set up application state.
//
// This is where you will store your delegates and any data you wish to access/mutate while the
// application is running.
let mut list_outputs = ListOutputs { registry_state, output_state: output_delegate };
// `OutputState::new()` binds the output globals found in `registry_queue_init()`.
//
// After the globals are bound, we need to dispatch again so that events may be sent to the newly
// created objects.
event_queue.roundtrip(&mut list_outputs)?;
// Now our outputs have been initialized with data, we may access what outputs exist and information about
// said outputs using the output delegate.
for output in list_outputs.output_state.outputs() {
print_output(
&list_outputs
.output_state
.info(&output)
.ok_or_else(|| "output has no info".to_owned())?,
);
}
Ok(())
}
/// Application data.
///
/// This type is where the delegates for some parts of the protocol and any application specific data will
/// live.
struct ListOutputs {
registry_state: RegistryState,
output_state: OutputState,
}
// In order to use OutputDelegate, we must implement this trait to indicate when something has happened to an
// output and to provide an instance of the output state to the delegate when dispatching events.
impl OutputHandler for ListOutputs {
// First we need to provide a way to access the delegate.
//
// This is needed because delegate implementations for handling events use the application data type in
// their function signatures. This allows the implementation to access an instance of the type.
fn output_state(&mut self) -> &mut OutputState {
&mut self.output_state
}
// Then there exist these functions that indicate the lifecycle of an output.
// These will be called as appropriate by the delegate implementation.
fn new_output(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
}
fn update_output(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
}
fn output_destroyed(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
}
}
// Now we need to say we are delegating the responsibility of output related events for our application data
// type to the requisite delegate.
delegate_output!(ListOutputs);
// In order for our delegate to know of the existence of globals, we need to implement registry
// handling for the program. This trait will forward events to the RegistryHandler trait
// implementations.
delegate_registry!(ListOutputs);
// In order for delegate_registry to work, our application data type needs to provide a way for the
// implementation to access the registry state.
//
// We also need to indicate which delegates will get told about globals being created. We specify
// the types of the delegates inside the array.
impl ProvidesRegistryState for ListOutputs {
fn registry(&mut self) -> &mut RegistryState {
&mut self.registry_state
}
registry_handlers! {
// Here we specify that OutputState needs to receive events regarding the creation and destruction of
// globals.
OutputState,
}
}
/// Prints some [`OutputInfo`].
fn print_output(info: &OutputInfo) {
println!("{}", info.model);
if let Some(name) = info.name.as_ref() {
println!("\tname: {name}");
}
if let Some(description) = info.description.as_ref() {
println!("\tdescription: {description}");
}
println!("\tmake: {}", info.make);
println!("\tx: {}, y: {}", info.location.0, info.location.1);
println!("\tsubpixel: {:?}", info.subpixel);
println!("\tphysical_size: {}×{}mm", info.physical_size.0, info.physical_size.1);
if let Some((x, y)) = info.logical_position.as_ref() {
println!("\tlogical x: {x}, y: {y}");
}
if let Some((width, height)) = info.logical_size.as_ref() {
println!("\tlogical width: {width}, height: {height}");
}
println!("\tmodes:");
for mode in &info.modes {
println!("\t\t{mode}");
}
}
|