Skip to content

Commit

Permalink
window: add client side decorations interface
Browse files Browse the repository at this point in the history
While the new decorations look the same as the ones before, the
approach in drawing them was changed, and now decorations are more
instant mode, meaning that you create and drop them when needed.

Fixes #273.
  • Loading branch information
kchibisov committed Mar 2, 2023
1 parent 94c261b commit b287561
Show file tree
Hide file tree
Showing 8 changed files with 870 additions and 37 deletions.
2 changes: 1 addition & 1 deletion examples/generic_simple_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ impl<T: Test + 'static> KeyboardHandler for SimpleWindow<T> {
keysyms: &[u32],
) {
if self.window.wl_surface() == surface {
println!("Keyboard focus on window with pressed syms: {:?}", keysyms);
println!("Keyboard focus on window with pressed syms: {keysyms:?}");
self.keyboard_focus = true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ impl KeyboardHandler for SimpleLayer {
keysyms: &[u32],
) {
if self.layer.wl_surface() == surface {
println!("Keyboard focus on window with pressed syms: {:?}", keysyms);
println!("Keyboard focus on window with pressed syms: {keysyms:?}");
self.keyboard_focus = true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ impl KeyboardHandler for SimpleWindow {
keysyms: &[u32],
) {
if self.window.wl_surface() == surface {
println!("Keyboard focus on window with pressed syms: {:?}", keysyms);
println!("Keyboard focus on window with pressed syms: {keysyms:?}");
self.keyboard_focus = true;
}
}
Expand Down
175 changes: 143 additions & 32 deletions examples/pointer_theme_window.rs → examples/themed_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,36 @@ use std::convert::TryInto;
use smithay_client_toolkit::{
compositor::{CompositorHandler, CompositorState},
delegate_compositor, delegate_keyboard, delegate_output, delegate_pointer, delegate_registry,
delegate_seat, delegate_shm, delegate_xdg_shell, delegate_xdg_window,
delegate_seat, delegate_shm, delegate_subcompositor, delegate_xdg_shell, delegate_xdg_window,
output::{OutputHandler, OutputState},
registry::{ProvidesRegistryState, RegistryState},
registry_handlers,
seat::{
keyboard::{KeyEvent, KeyboardHandler, Modifiers},
pointer::{PointerEvent, PointerEventKind, PointerHandler, ThemeSpec, ThemedPointer},
pointer::{
PointerData, PointerEvent, PointerEventKind, PointerHandler, ThemeSpec, ThemedPointer,
},
Capability, SeatHandler, SeatState,
},
shell::{
xdg::{
window::{Window, WindowConfigure, WindowDecorations, WindowHandler},
XdgShell,
frame::fallback_frame::FallbackFrame,
frame::{DecorationsFrame, FrameAction, FrameClick},
window::{DecorationMode, Window, WindowConfigure, WindowDecorations, WindowHandler},
XdgShell, XdgSurface,
},
WaylandSurface,
},
shm::{
slot::{Buffer, SlotPool},
Shm, ShmHandler,
},
subcompositor::SubcompositorState,
};
use wayland_client::{
globals::registry_queue_init,
protocol::{wl_keyboard, wl_output, wl_pointer, wl_seat, wl_shm, wl_surface},
Connection, QueueHandle,
Connection, Proxy, QueueHandle,
};

fn main() {
Expand All @@ -42,6 +47,9 @@ fn main() {
let output_state = OutputState::new(&globals, &qh);
let compositor_state =
CompositorState::bind(&globals, &qh).expect("wl_compositor not available");
let subcompositor_state =
SubcompositorState::bind(compositor_state.wl_compositor().clone(), &globals, &qh)
.expect("wl_subcompositor not available");
let shm_state = Shm::bind(&globals, &qh).expect("wl_shm not available");
let xdg_shell_state = XdgShell::bind(&globals, &qh).expect("xdg shell not available");

Expand Down Expand Up @@ -72,6 +80,7 @@ fn main() {
seat_state,
output_state,
_compositor_state: compositor_state,
subcompositor_state,
shm_state,
_xdg_shell_state: xdg_shell_state,

Expand All @@ -83,11 +92,13 @@ fn main() {
shift: None,
buffer: None,
window,
window_frame: None,
pointer_surface,
keyboard: None,
keyboard_focus: false,
themed_pointer: None,
set_cursor: false,
cursor_icon: String::from("diamond_cross"),
};

// We don't draw immediately, the configure will notify us when to first draw.
Expand All @@ -107,6 +118,7 @@ struct SimpleWindow {
seat_state: SeatState,
output_state: OutputState,
_compositor_state: CompositorState,
subcompositor_state: SubcompositorState,
shm_state: Shm,
_xdg_shell_state: XdgShell,

Expand All @@ -118,11 +130,13 @@ struct SimpleWindow {
shift: Option<u32>,
buffer: Option<Buffer>,
window: Window,
window_frame: Option<FallbackFrame>,
pointer_surface: wl_surface::WlSurface,
keyboard: Option<wl_keyboard::WlKeyboard>,
keyboard_focus: bool,
themed_pointer: Option<ThemedPointer>,
set_cursor: bool,
cursor_icon: String,
}

impl CompositorHandler for SimpleWindow {
Expand Down Expand Up @@ -186,22 +200,60 @@ impl WindowHandler for SimpleWindow {
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
_window: &Window,
window: &Window,
configure: WindowConfigure,
_serial: u32,
) {
match configure.new_size {
Some(size) => {
self.width = size.0;
self.height = size.1;
self.buffer = None;
}
None => {
self.width = 256;
self.height = 256;
self.buffer = None;
}
}
self.buffer = None;

println!(
"Configure size {:?}, decorations: {:?}",
configure.new_size, configure.decoration_mode
);

let (width, height) = if configure.decoration_mode == DecorationMode::Client {
let window_frame = self.window_frame.get_or_insert_with(|| {
FallbackFrame::new(&self.window, &self.shm_state, &self.subcompositor_state, qh)
.expect("failed to create client side decorations frame.")
});

// Configure state before touching any resizing.
window_frame.configure_state(&configure.states);

let (width, height) = match configure.new_size {
Some((width, height)) => {
// The size could be 0.
window_frame.subtract_borders(width, height)
}
None => {
// You might want to consider checking for configure bounds.
(self.width, self.height)
}
};

println!("{width}, {height}");
window_frame.resize(width, height);

let (x, y) = window_frame.location();
let outer_size = window_frame.add_borders(width, height);
window.xdg_surface().set_window_geometry(
x,
y,
outer_size.0 as i32,
outer_size.1 as i32,
);

(width, height)
} else {
self.window_frame = None;
let (width, height) = configure.new_size.unwrap_or((self.width, self.height));
self.window.xdg_surface().set_window_geometry(0, 0, width as i32, height as i32);
(width, height)
};

// Update new width and height;
self.width = width;
self.height = height;

// Initiate the first draw.
if self.first_configure {
Expand Down Expand Up @@ -334,38 +386,89 @@ impl PointerHandler for SimpleWindow {
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_pointer: &wl_pointer::WlPointer,
pointer: &wl_pointer::WlPointer,
events: &[PointerEvent],
) {
use PointerEventKind::*;
for event in events {
// Ignore events for other surfaces
if &event.surface != self.window.wl_surface() {
continue;
}
let (x, y) = event.position;
match event.kind {
Enter { .. } => {
println!("Pointer entered @{:?}", event.position);
self.set_cursor = true;
self.cursor_icon = self
.window_frame
.as_mut()
.and_then(|frame| frame.click_point_moved(&event.surface, x, y))
.unwrap_or("diamond_cross")
.to_owned();

if &event.surface == self.window.wl_surface() {
println!("Pointer entered @{:?}", event.position);
}
}
Leave { .. } => {
if &event.surface != self.window.wl_surface() {
if let Some(window_frame) = self.window_frame.as_mut() {
window_frame.click_point_left();
}
}
println!("Pointer left");
}
Motion { .. } => {}
Press { button, .. } => {
println!("Press {:x} @ {:?}", button, event.position);
self.shift = self.shift.xor(Some(0));
Motion { .. } => {
if let Some(new_cursor) = self
.window_frame
.as_mut()
.and_then(|frame| frame.click_point_moved(&event.surface, x, y))
{
self.set_cursor = true;
self.cursor_icon = new_cursor.to_owned();
}
}
Release { button, .. } => {
println!("Release {:x} @ {:?}", button, event.position);
Press { button, serial, .. } | Release { button, serial, .. } => {
let pressed = if matches!(event.kind, Press { .. }) { true } else { false };
if &event.surface != self.window.wl_surface() {
let click = match button {
0x110 => FrameClick::Normal,
0x111 => FrameClick::Alternate,
_ => continue,
};

if let Some(action) = self
.window_frame
.as_mut()
.and_then(|frame| frame.on_click(click, pressed))
{
self.frame_action(pointer, serial, action);
}
} else if pressed {
println!("Press {:x} @ {:?}", button, event.position);
self.shift = self.shift.xor(Some(0));
}
}
Axis { horizontal, vertical, .. } => {
println!("Scroll H:{horizontal:?}, V:{vertical:?}");
if &event.surface == self.window.wl_surface() {
println!("Scroll H:{horizontal:?}, V:{vertical:?}");
}
}
}
}
}
}
impl SimpleWindow {
fn frame_action(&mut self, pointer: &wl_pointer::WlPointer, serial: u32, action: FrameAction) {
let pointer_data = pointer.data::<PointerData>().unwrap();
let seat = pointer_data.seat();
match action {
FrameAction::Close => self.exit = true,
FrameAction::Minimize => self.window.set_minimized(),
FrameAction::Maximize => self.window.set_maximized(),
FrameAction::UnMaximize => self.window.unset_maximized(),
FrameAction::ShowMenu(x, y) => self.window.show_window_menu(seat, serial, (x, y)),
FrameAction::Resize(edge) => self.window.resize(seat, serial, edge),
FrameAction::Move => self.window.r#move(seat, serial),
}
}
}

impl ShmHandler for SimpleWindow {
fn shm_state(&mut self) -> &mut Shm {
Expand All @@ -378,7 +481,7 @@ impl SimpleWindow {
if self.set_cursor {
let _ = self.themed_pointer.as_mut().unwrap().set_cursor(
conn,
"diamond_cross",
&self.cursor_icon,
self.shm_state.wl_shm(),
&self.pointer_surface,
1,
Expand Down Expand Up @@ -438,6 +541,13 @@ impl SimpleWindow {
}
}

// Draw the decorations frame.
self.window_frame.as_mut().map(|frame| {
if frame.is_dirty() {
frame.redraw();
}
});

// Damage the entire window
self.window.wl_surface().damage_buffer(0, 0, self.width as i32, self.height as i32);

Expand All @@ -451,6 +561,7 @@ impl SimpleWindow {
}

delegate_compositor!(SimpleWindow);
delegate_subcompositor!(SimpleWindow);
delegate_output!(SimpleWindow);
delegate_shm!(SimpleWindow);

Expand Down
Loading

0 comments on commit b287561

Please sign in to comment.