From 54ea0d3a7437d242d1462d0b893b7bcc216dc694 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Mon, 5 Jul 2021 19:21:15 +0200 Subject: [PATCH] Introduce Logical/Physical Point/Rectangle --- anvil/src/drawing.rs | 49 +- anvil/src/input_handler.rs | 44 +- anvil/src/output_map.rs | 75 +- anvil/src/shell.rs | 160 ++-- anvil/src/state.rs | 5 +- anvil/src/udev.rs | 45 +- anvil/src/window_map.rs | 81 +- anvil/src/winit.rs | 14 +- anvil/src/xwayland/mod.rs | 9 +- src/backend/egl/display.rs | 7 +- src/backend/input.rs | 39 +- src/backend/input/tablet.rs | 16 +- src/backend/renderer/gles2/mod.rs | 26 +- src/backend/renderer/mod.rs | 33 +- src/backend/winit.rs | 113 +-- src/utils/geometry.rs | 829 +++++++++++++++++++++ src/utils/mod.rs | 4 +- src/utils/rectangle.rs | 46 -- src/wayland/compositor/handlers.rs | 36 +- src/wayland/compositor/mod.rs | 90 +-- src/wayland/data_device/dnd_grab.rs | 23 +- src/wayland/data_device/server_dnd_grab.rs | 21 +- src/wayland/output/mod.rs | 41 +- src/wayland/seat/pointer.rs | 63 +- src/wayland/shell/legacy/mod.rs | 13 +- src/wayland/shell/legacy/wl_handlers.rs | 4 +- src/wayland/shell/xdg/mod.rs | 78 +- src/wayland/shell/xdg/xdg_handlers.rs | 20 +- src/wayland/shell/xdg/zxdgv6_handlers.rs | 20 +- src/wayland/tablet_manager/tablet_tool.rs | 31 +- 30 files changed, 1386 insertions(+), 649 deletions(-) create mode 100644 src/utils/geometry.rs delete mode 100644 src/utils/rectangle.rs diff --git a/anvil/src/drawing.rs b/anvil/src/drawing.rs index 0cf2ab2..1e202c7 100644 --- a/anvil/src/drawing.rs +++ b/anvil/src/drawing.rs @@ -9,7 +9,7 @@ use smithay::{ SwapBuffersError, }, reexports::wayland_server::protocol::{wl_buffer, wl_surface}, - utils::Rectangle, + utils::{Logical, Point, Rectangle}, wayland::{ compositor::{ get_role, with_states, with_surface_tree_upward, Damage, SubsurfaceCachedState, @@ -38,7 +38,7 @@ pub fn draw_cursor( renderer: &mut R, frame: &mut F, surface: &wl_surface::WlSurface, - (x, y): (i32, i32), + location: Point, log: &Logger, ) -> Result<(), SwapBuffersError> where @@ -59,24 +59,24 @@ where ) }) .unwrap_or(None); - let (dx, dy) = match ret { + let delta = match ret { Some(h) => h, None => { warn!( log, "Trying to display as a cursor a surface that does not have the CursorImage role." ); - (0, 0) + (0, 0).into() } }; - draw_surface_tree(renderer, frame, surface, (x - dx, y - dy), log) + draw_surface_tree(renderer, frame, surface, location - delta, log) } fn draw_surface_tree( renderer: &mut R, frame: &mut F, root: &wl_surface::WlSurface, - location: (i32, i32), + location: Point, log: &Logger, ) -> Result<(), SwapBuffersError> where @@ -90,7 +90,8 @@ where with_surface_tree_upward( root, location, - |_surface, states, &(mut x, mut y)| { + |_surface, states, location| { + let mut location = *location; // Pull a new buffer if available if let Some(data) = states.data_map.get::>() { let mut data = data.borrow_mut(); @@ -103,7 +104,7 @@ where .map(|dmg| match dmg { Damage::Buffer(rect) => *rect, // TODO also apply transformations - Damage::Surface(rect) => rect.scale(attributes.buffer_scale), + Damage::Surface(rect) => rect.to_buffer(attributes.buffer_scale), }) .collect::>(); @@ -136,10 +137,9 @@ where // if yes, also process the children if states.role == Some("subsurface") { let current = states.cached_state.current::(); - x += current.location.0; - y += current.location.1; + location += current.location; } - TraversalAction::DoChildren((x, y)) + TraversalAction::DoChildren(location) } else { // we are not displayed, so our children are neither TraversalAction::SkipChildren @@ -149,7 +149,8 @@ where TraversalAction::SkipChildren } }, - |_surface, states, &(mut x, mut y)| { + |_surface, states, location| { + let mut location = *location; if let Some(ref data) = states.data_map.get::>() { let mut data = data.borrow_mut(); if let Some(texture) = data @@ -161,13 +162,12 @@ where // only passes it to our children if states.role == Some("subsurface") { let current = states.cached_state.current::(); - x += current.location.0; - y += current.location.1; + location += current.location; } if let Err(err) = frame.render_texture_at( &texture.texture, - (x, y), - Transform::Normal, /* TODO */ + location.to_physical(1), // TODO: handle output scaling factor + Transform::Normal, /* TODO */ 1.0, ) { result = Err(err.into()); @@ -185,7 +185,7 @@ pub fn draw_windows( renderer: &mut R, frame: &mut F, window_map: &WindowMap, - output_rect: Rectangle, + output_rect: Rectangle, log: &::slog::Logger, ) -> Result<(), SwapBuffersError> where @@ -197,12 +197,12 @@ where let mut result = Ok(()); // redraw the frame, in a simple but inneficient way - window_map.with_windows_from_bottom_to_top(|toplevel_surface, mut initial_place, bounding_box| { + window_map.with_windows_from_bottom_to_top(|toplevel_surface, mut initial_place, &bounding_box| { // skip windows that do not overlap with a given output if !output_rect.overlaps(bounding_box) { return; } - initial_place.0 -= output_rect.x; + initial_place.x -= output_rect.loc.x; if let Some(wl_surface) = toplevel_surface.get_surface() { // this surface is a root of a subsurface tree that needs to be drawn if let Err(err) = draw_surface_tree(renderer, frame, &wl_surface, initial_place, log) { @@ -211,14 +211,11 @@ where // furthermore, draw its popups let toplevel_geometry_offset = window_map .geometry(toplevel_surface) - .map(|g| (g.x, g.y)) + .map(|g| g.loc) .unwrap_or_default(); window_map.with_child_popups(&wl_surface, |popup| { let location = popup.location(); - let draw_location = ( - initial_place.0 + location.0 + toplevel_geometry_offset.0, - initial_place.1 + location.1 + toplevel_geometry_offset.1, - ); + let draw_location = initial_place + location + toplevel_geometry_offset; if let Some(wl_surface) = popup.get_surface() { if let Err(err) = draw_surface_tree(renderer, frame, &wl_surface, draw_location, log) { result = Err(err); @@ -235,7 +232,7 @@ pub fn draw_dnd_icon( renderer: &mut R, frame: &mut F, surface: &wl_surface::WlSurface, - (x, y): (i32, i32), + location: Point, log: &::slog::Logger, ) -> Result<(), SwapBuffersError> where @@ -250,5 +247,5 @@ where "Trying to display as a dnd icon a surface that does not have the DndIcon role." ); } - draw_surface_tree(renderer, frame, surface, (x, y), log) + draw_surface_tree(renderer, frame, surface, location, log) } diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index 07a07c0..0b7b07f 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -13,6 +13,7 @@ use smithay::{ TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, }, reexports::wayland_server::protocol::wl_pointer, + utils::{Logical, Point}, wayland::{ output::Mode, seat::{keysyms as xkb, AxisFrame, Keysym, ModifiersState}, @@ -174,8 +175,7 @@ impl AnvilState { self.output_map.borrow_mut().update_mode( crate::winit::OUTPUT_NAME, Mode { - width: size.0 as i32, - height: size.1 as i32, + size, refresh: 60_000, }, ); @@ -187,12 +187,16 @@ impl AnvilState { } fn on_pointer_move_absolute(&mut self, evt: B::PointerMotionAbsoluteEvent) { - // different cases depending on the context: - let (x, y) = evt.position(); - self.pointer_location = (x, y); + let output_size = self + .output_map + .borrow() + .with_primary(|_, rect| (rect.size.w as u32, rect.size.h as u32).into()) + .unwrap(); + let pos = evt.position_transformed(output_size); + self.pointer_location = pos; let serial = SCOUNTER.next_serial(); - let under = self.window_map.borrow().get_surface_under((x as f64, y as f64)); - self.pointer.motion((x, y), under, serial, evt.time()); + let under = self.window_map.borrow().get_surface_under(pos); + self.pointer.motion(pos, under, serial, evt.time()); } } @@ -231,9 +235,9 @@ impl AnvilState { .ok(); if let Some(geometry) = geometry { - let x = geometry.x as f64 + geometry.width as f64 / 2.0; - let y = geometry.height as f64 / 2.0; - self.pointer_location = (x, y) + let x = geometry.loc.x as f64 + geometry.size.w as f64 / 2.0; + let y = geometry.size.h as f64 / 2.0; + self.pointer_location = (x, y).into() } } }, @@ -270,10 +274,8 @@ impl AnvilState { } fn on_pointer_move(&mut self, evt: B::PointerMotionEvent) { - let (x, y) = (evt.delta_x(), evt.delta_y()); let serial = SCOUNTER.next_serial(); - self.pointer_location.0 += x as f64; - self.pointer_location.1 += y as f64; + self.pointer_location += evt.delta(); // clamp to screen limits // this event is never generated by winit @@ -292,8 +294,8 @@ impl AnvilState { output_map .with_primary(|_, rect| { - pointer_location.0 = evt.x_transformed(rect.width as u32) + rect.x as f64; - pointer_location.1 = evt.y_transformed(rect.height as u32) + rect.y as f64; + let rect_size = (rect.size.w as u32, rect.size.h as u32).into(); + *pointer_location = evt.position_transformed(rect_size) + rect.loc.to_f64(); let under = window_map.get_surface_under(*pointer_location); let tablet = tablet_seat.get_tablet(&TabletDescriptor::from(&evt.device())); @@ -342,8 +344,8 @@ impl AnvilState { let tool = evt.tool(); tablet_seat.add_tool(&tool); - pointer_location.0 = evt.x_transformed(rect.width as u32) + rect.x as f64; - pointer_location.1 = evt.y_transformed(rect.height as u32) + rect.y as f64; + let rect_size = (rect.size.h as u32, rect.size.w as u32).into(); + *pointer_location = evt.position_transformed(rect_size) + rect.loc.to_f64(); let under = window_map.get_surface_under(*pointer_location); let tablet = tablet_seat.get_tablet(&TabletDescriptor::from(&evt.device())); @@ -405,12 +407,12 @@ impl AnvilState { } } - fn clamp_coords(&self, pos: (f64, f64)) -> (f64, f64) { + fn clamp_coords(&self, pos: Point) -> Point { if self.output_map.borrow().is_empty() { return pos; } - let (pos_x, pos_y) = pos; + let (pos_x, pos_y) = pos.into(); let output_map = self.output_map.borrow(); let max_x = output_map.width(); let clamped_x = pos_x.max(0.0).min(max_x as f64); @@ -419,9 +421,9 @@ impl AnvilState { if let Some(max_y) = max_y { let clamped_y = pos_y.max(0.0).min(max_y as f64); - (clamped_x, clamped_y) + (clamped_x, clamped_y).into() } else { - (clamped_x, pos_y) + (clamped_x, pos_y).into() } } } diff --git a/anvil/src/output_map.rs b/anvil/src/output_map.rs index 00027da..c0515db 100644 --- a/anvil/src/output_map.rs +++ b/anvil/src/output_map.rs @@ -8,7 +8,7 @@ use smithay::{ Display, Global, }, }, - utils::Rectangle, + utils::{Logical, Point, Rectangle}, wayland::{ compositor::{with_surface_tree_downward, SubsurfaceCachedState, TraversalAction}, output::{self, Mode, PhysicalProperties}, @@ -21,7 +21,7 @@ struct Output { name: String, output: output::Output, global: Option>, - geometry: Rectangle, + geometry: Rectangle, surfaces: Vec, current_mode: Mode, } @@ -29,7 +29,7 @@ struct Output { impl Output { fn new( name: N, - location: (i32, i32), + location: Point, display: &mut Display, physical: PhysicalProperties, mode: Mode, @@ -48,10 +48,9 @@ impl Output { global: Some(global), output, geometry: Rectangle { - x: location.0, - y: location.1, - width: mode.width, - height: mode.height, + loc: location, + // TODO: handle scaling factor + size: mode.size.to_logical(1), }, surfaces: Vec::new(), current_mode: mode, @@ -101,9 +100,9 @@ impl OutputMap { // First recalculate the outputs location let mut output_x = 0; for output in self.outputs.iter_mut() { - output.geometry.x = output_x; - output.geometry.y = 0; - output_x += output.geometry.width; + output.geometry.loc.x = output_x; + output.geometry.loc.y = 0; + output_x += output.geometry.loc.x; } // Check if any windows are now out of outputs range @@ -111,13 +110,13 @@ impl OutputMap { let primary_output_location = self .with_primary(|_, geometry| geometry) .ok() - .map(|o| (o.x, o.y)) + .map(|o| o.loc) .unwrap_or_default(); let mut window_map = self.window_map.borrow_mut(); // TODO: This is a bit unfortunate, we save the windows in a temp vector // cause we can not call window_map.set_location within the closure. let mut windows_to_move = Vec::new(); - window_map.with_windows_from_bottom_to_top(|kind, _, bbox| { + window_map.with_windows_from_bottom_to_top(|kind, _, &bbox| { let within_outputs = self.outputs.iter().any(|o| o.geometry.overlaps(bbox)); if !within_outputs { @@ -142,12 +141,12 @@ impl OutputMap { }; if let Some(geometry) = output_geometry { - if location != (geometry.x, geometry.y) { - windows_to_move.push((kind.to_owned(), (geometry.x, geometry.y))); + if location != geometry.loc { + windows_to_move.push((kind.to_owned(), geometry.loc)); } let res = xdg.with_pending_state(|pending_state| { - pending_state.size = Some((geometry.width, geometry.height)); + pending_state.size = Some(geometry.size); }); if res.is_ok() { @@ -174,7 +173,7 @@ impl OutputMap { let output = Output::new( name, - location, + location.into(), &mut *self.display.borrow_mut(), physical, mode, @@ -204,20 +203,20 @@ impl OutputMap { self.arrange(); } - pub fn width(&self) -> u32 { + pub fn width(&self) -> i32 { // This is a simplification, we only arrange the outputs on the y axis side-by-side // so that the total width is simply the sum of all output widths. self.outputs .iter() - .fold(0u32, |acc, output| acc + output.geometry.width as u32) + .fold(0, |acc, output| acc + output.geometry.size.w) } - pub fn height(&self, x: i32) -> Option { + pub fn height(&self, x: i32) -> Option { // This is a simplification, we only arrange the outputs on the y axis side-by-side self.outputs .iter() - .find(|output| x >= output.geometry.x && x < (output.geometry.x + output.geometry.width)) - .map(|output| output.geometry.height as u32) + .find(|output| x >= output.geometry.loc.x && x < (output.geometry.loc.x + output.geometry.size.w)) + .map(|output| output.geometry.size.h) } pub fn is_empty(&self) -> bool { @@ -226,7 +225,7 @@ impl OutputMap { pub fn with_primary(&self, f: F) -> Result where - F: FnOnce(&output::Output, Rectangle) -> T, + F: FnOnce(&output::Output, Rectangle) -> T, { let output = self.outputs.get(0).ok_or(OutputNotFound)?; @@ -235,7 +234,7 @@ impl OutputMap { pub fn find(&self, output: &wl_output::WlOutput, f: F) -> Result where - F: FnOnce(&output::Output, Rectangle) -> T, + F: FnOnce(&output::Output, Rectangle) -> T, { let output = self .outputs @@ -249,7 +248,7 @@ impl OutputMap { pub fn find_by_name(&self, name: N, f: F) -> Result where N: AsRef, - F: FnOnce(&output::Output, Rectangle) -> T, + F: FnOnce(&output::Output, Rectangle) -> T, { let output = self .outputs @@ -260,9 +259,9 @@ impl OutputMap { Ok(f(&output.output, output.geometry)) } - pub fn find_by_position(&self, position: (i32, i32), f: F) -> Result + pub fn find_by_position(&self, position: Point, f: F) -> Result where - F: FnOnce(&output::Output, Rectangle) -> T, + F: FnOnce(&output::Output, Rectangle) -> T, { let output = self .outputs @@ -275,7 +274,7 @@ impl OutputMap { pub fn find_by_index(&self, index: usize, f: F) -> Result where - F: FnOnce(&output::Output, Rectangle) -> T, + F: FnOnce(&output::Output, Rectangle) -> T, { let output = self.outputs.get(index).ok_or(OutputNotFound)?; @@ -293,8 +292,8 @@ impl OutputMap { // the output width decreased the refresh method will take // care and will send enter for the output. if let Some(output) = output { - output.geometry.width = mode.width; - output.geometry.height = mode.height; + // TODO: handle scale factors + output.geometry.size = mode.size.to_logical(1); output.output.delete_mode(output.current_mode); output.output.change_current_state(Some(mode), None, None); @@ -316,7 +315,7 @@ impl OutputMap { window_map .borrow() - .with_windows_from_bottom_to_top(|kind, location, bbox| { + .with_windows_from_bottom_to_top(|kind, location, &bbox| { for output in self.outputs.iter_mut() { // Check if the bounding box of the toplevel intersects with // the output, if not no surface in the tree can intersect with @@ -343,30 +342,30 @@ impl OutputMap { with_surface_tree_downward( surface, location, - |_, states, &(mut x, mut y)| { + |_, states, location| { + let mut location = *location; let data = states.data_map.get::>(); if data.is_some() { if states.role == Some("subsurface") { let current = states.cached_state.current::(); - x += current.location.0; - y += current.location.1; + location += current.location; } - TraversalAction::DoChildren((x, y)) + TraversalAction::DoChildren(location) } else { // If the parent surface is unmapped, then the child surfaces are hidden as // well, no need to consider them here. TraversalAction::SkipChildren } }, - |wl_surface, states, &(x, y)| { + |wl_surface, states, &loc| { let data = states.data_map.get::>(); - if let Some((width, height)) = data.and_then(|d| d.borrow().size()) { - let surface_rectangle = Rectangle { x, y, width, height }; + if let Some(size) = data.and_then(|d| d.borrow().size()) { + let surface_rectangle = Rectangle { loc, size }; - if output.geometry.overlaps(&surface_rectangle) { + if output.geometry.overlaps(surface_rectangle) { // We found a matching output, check if we already sent enter if !output.surfaces.contains(wl_surface) { output.output.enter(wl_surface); diff --git a/anvil/src/shell.rs b/anvil/src/shell.rs index f5b09ef..9803aad 100644 --- a/anvil/src/shell.rs +++ b/anvil/src/shell.rs @@ -13,7 +13,7 @@ use smithay::{ Display, }, }, - utils::Rectangle, + utils::{Logical, Physical, Point, Rectangle, Size}, wayland::{ compositor::{ compositor_init, is_sync_subsurface, with_states, with_surface_tree_upward, BufferAssignment, @@ -41,26 +41,25 @@ struct MoveSurfaceGrab { start_data: GrabStartData, window_map: Rc>, toplevel: SurfaceKind, - initial_window_location: (i32, i32), + initial_window_location: Point, } impl PointerGrab for MoveSurfaceGrab { fn motion( &mut self, _handle: &mut PointerInnerHandle<'_>, - location: (f64, f64), - _focus: Option<(wl_surface::WlSurface, (f64, f64))>, + location: Point, + _focus: Option<(wl_surface::WlSurface, Point)>, _serial: Serial, _time: u32, ) { - let dx = location.0 - self.start_data.location.0; - let dy = location.1 - self.start_data.location.1; - let new_window_x = (self.initial_window_location.0 as f64 + dx) as i32; - let new_window_y = (self.initial_window_location.1 as f64 + dy) as i32; + let delta = location - self.start_data.location; + let new_location = self.initial_window_location.to_f64() + delta; - self.window_map - .borrow_mut() - .set_location(&self.toplevel, (new_window_x, new_window_y)); + self.window_map.borrow_mut().set_location( + &self.toplevel, + (new_location.x as i32, new_location.y as i32).into(), + ); } fn button( @@ -133,16 +132,16 @@ struct ResizeSurfaceGrab { start_data: GrabStartData, toplevel: SurfaceKind, edges: ResizeEdge, - initial_window_size: (i32, i32), - last_window_size: (i32, i32), + initial_window_size: Size, + last_window_size: Size, } impl PointerGrab for ResizeSurfaceGrab { fn motion( &mut self, handle: &mut PointerInnerHandle<'_>, - location: (f64, f64), - _focus: Option<(wl_surface::WlSurface, (f64, f64))>, + location: Point, + _focus: Option<(wl_surface::WlSurface, Point)>, serial: Serial, time: u32, ) { @@ -152,11 +151,10 @@ impl PointerGrab for ResizeSurfaceGrab { return; } - let mut dx = location.0 - self.start_data.location.0; - let mut dy = location.1 - self.start_data.location.1; + let (mut dx, mut dy) = (location - self.start_data.location).into(); - let mut new_window_width = self.initial_window_size.0; - let mut new_window_height = self.initial_window_size.1; + let mut new_window_width = self.initial_window_size.w; + let mut new_window_height = self.initial_window_size.h; let left_right = ResizeEdge::LEFT | ResizeEdge::RIGHT; let top_bottom = ResizeEdge::TOP | ResizeEdge::BOTTOM; @@ -166,7 +164,7 @@ impl PointerGrab for ResizeSurfaceGrab { dx = -dx; } - new_window_width = (self.initial_window_size.0 as f64 + dx) as i32; + new_window_width = (self.initial_window_size.w as f64 + dx) as i32; } if self.edges.intersects(top_bottom) { @@ -174,7 +172,7 @@ impl PointerGrab for ResizeSurfaceGrab { dy = -dy; } - new_window_height = (self.initial_window_size.1 as f64 + dy) as i32; + new_window_height = (self.initial_window_size.h as f64 + dy) as i32; } let (min_size, max_size) = with_states(self.toplevel.get_surface().unwrap(), |states| { @@ -183,23 +181,23 @@ impl PointerGrab for ResizeSurfaceGrab { }) .unwrap(); - let min_width = min_size.0.max(1); - let min_height = min_size.1.max(1); - let max_width = if max_size.0 == 0 { + let min_width = min_size.w.max(1); + let min_height = min_size.h.max(1); + let max_width = if max_size.w == 0 { i32::max_value() } else { - max_size.0 + max_size.w }; - let max_height = if max_size.1 == 0 { + let max_height = if max_size.h == 0 { i32::max_value() } else { - max_size.1 + max_size.h }; new_window_width = new_window_width.max(min_width).min(max_width); new_window_height = new_window_height.max(min_height).min(max_height); - self.last_window_size = (new_window_width, new_window_height); + self.last_window_size = (new_window_width, new_window_height).into(); match &self.toplevel { SurfaceKind::Xdg(xdg) => { @@ -211,10 +209,7 @@ impl PointerGrab for ResizeSurfaceGrab { xdg.send_configure(); } } - SurfaceKind::Wl(wl) => wl.send_configure( - (self.last_window_size.0 as u32, self.last_window_size.1 as u32), - self.edges.into(), - ), + SurfaceKind::Wl(wl) => wl.send_configure(self.last_window_size, self.edges.into()), #[cfg(feature = "xwayland")] SurfaceKind::X11(_) => { // TODO: What to do here? Send the update via X11? @@ -302,7 +297,7 @@ fn fullscreen_output_geometry( wl_output: Option<&wl_output::WlOutput>, window_map: &WindowMap, output_map: &OutputMap, -) -> Option { +) -> Option> { // First test if a specific output has been requested // if the requested output is not found ignore the request if let Some(wl_output) = wl_output { @@ -362,15 +357,11 @@ pub fn init_shell(display: Rc>, log: ::sl .borrow() .with_primary(|_, geometry| geometry) .ok() - .unwrap_or_else(|| Rectangle { - width: 800, - height: 800, - ..Default::default() - }); - let max_x = output_geometry.x + (((output_geometry.width as f32) / 3.0) * 2.0) as i32; - let max_y = output_geometry.y + (((output_geometry.height as f32) / 3.0) * 2.0) as i32; - let x_range = Uniform::new(output_geometry.x, max_x); - let y_range = Uniform::new(output_geometry.y, max_y); + .unwrap_or_else(|| Rectangle::from_loc_and_size((0, 0), (800, 800))); + let max_x = output_geometry.loc.x + (((output_geometry.size.w as f32) / 3.0) * 2.0) as i32; + let max_y = output_geometry.loc.y + (((output_geometry.size.h as f32) / 3.0) * 2.0) as i32; + let x_range = Uniform::new(output_geometry.loc.x, max_x); + let y_range = Uniform::new(output_geometry.loc.y, max_y); let mut rng = rand::thread_rng(); let x = x_range.sample(&mut rng); let y = y_range.sample(&mut rng); @@ -379,7 +370,7 @@ pub fn init_shell(display: Rc>, log: ::sl // the surface is not already configured xdg_window_map .borrow_mut() - .insert(SurfaceKind::Xdg(surface), (x, y)); + .insert(SurfaceKind::Xdg(surface), (x, y).into()); } XdgRequest::NewPopup { surface } => { // Do not send a configure here, the initial configure @@ -461,7 +452,7 @@ pub fn init_shell(display: Rc>, log: ::sl let toplevel = SurfaceKind::Xdg(surface.clone()); let initial_window_location = xdg_window_map.borrow().location(&toplevel).unwrap(); let geometry = xdg_window_map.borrow().geometry(&toplevel).unwrap(); - let initial_window_size = (geometry.width, geometry.height); + let initial_window_size = geometry.size; with_states(surface.get_surface().unwrap(), move |states| { states @@ -566,13 +557,13 @@ pub fn init_shell(display: Rc>, log: ::sl if let Some(surface) = surface.get_surface() { let mut xdg_window_map = xdg_window_map.borrow_mut(); if let Some(kind) = xdg_window_map.find(surface) { - xdg_window_map.set_location(&kind, (geometry.x, geometry.y)); + xdg_window_map.set_location(&kind, geometry.loc); } } let ret = surface.with_pending_state(|state| { state.states.set(xdg_toplevel::State::Fullscreen); - state.size = Some((geometry.width, geometry.height)); + state.size = Some(geometry.size); state.fullscreen_output = output; }); if ret.is_ok() { @@ -611,12 +602,12 @@ pub fn init_shell(display: Rc>, log: ::sl if let Some(surface) = surface.get_surface() { let mut xdg_window_map = xdg_window_map.borrow_mut(); if let Some(kind) = xdg_window_map.find(surface) { - xdg_window_map.set_location(&kind, (geometry.x, geometry.y)); + xdg_window_map.set_location(&kind, geometry.loc); } } let ret = surface.with_pending_state(|state| { state.states.set(xdg_toplevel::State::Maximized); - state.size = Some((geometry.width, geometry.height)); + state.size = Some(geometry.size); }); if ret.is_ok() { surface.send_configure(); @@ -656,21 +647,19 @@ pub fn init_shell(display: Rc>, log: ::sl .borrow() .with_primary(|_, geometry| geometry) .ok() - .unwrap_or_else(|| Rectangle { - width: 800, - height: 800, - ..Default::default() - }); - let max_x = output_geometry.x + (((output_geometry.width as f32) / 3.0) * 2.0) as i32; - let max_y = output_geometry.y + (((output_geometry.height as f32) / 3.0) * 2.0) as i32; - let x_range = Uniform::new(output_geometry.x, max_x); - let y_range = Uniform::new(output_geometry.y, max_y); + .unwrap_or_else(|| Rectangle::from_loc_and_size((0, 0), (800, 800))); + let max_x = + output_geometry.loc.x + (((output_geometry.size.w as f32) / 3.0) * 2.0) as i32; + let max_y = + output_geometry.loc.y + (((output_geometry.size.h as f32) / 3.0) * 2.0) as i32; + let x_range = Uniform::new(output_geometry.loc.x, max_x); + let y_range = Uniform::new(output_geometry.loc.y, max_y); let mut rng = rand::thread_rng(); let x = x_range.sample(&mut rng); let y = y_range.sample(&mut rng); shell_window_map .borrow_mut() - .insert(SurfaceKind::Wl(surface), (x, y)); + .insert(SurfaceKind::Wl(surface), (x, y).into()); } ShellRequest::SetKind { surface, @@ -696,7 +685,7 @@ pub fn init_shell(display: Rc>, log: ::sl if let Some(geometry) = output_geometry { shell_window_map .borrow_mut() - .insert(SurfaceKind::Wl(surface), (geometry.x, geometry.y)); + .insert(SurfaceKind::Wl(surface), geometry.loc); } } ShellRequest::Move { @@ -773,7 +762,7 @@ pub fn init_shell(display: Rc>, log: ::sl let toplevel = SurfaceKind::Wl(surface.clone()); let initial_window_location = shell_window_map.borrow().location(&toplevel).unwrap(); let geometry = shell_window_map.borrow().geometry(&toplevel).unwrap(); - let initial_window_size = (geometry.width, geometry.height); + let initial_window_size = geometry.size; with_states(surface.get_surface().unwrap(), move |states| { states @@ -819,9 +808,9 @@ pub struct ResizeData { /// The edges the surface is being resized with. edges: ResizeEdge, /// The initial window location. - initial_window_location: (i32, i32), + initial_window_location: Point, /// The initial window size (geometry width and height). - initial_window_size: (i32, i32), + initial_window_size: Size, } /// State of the resize operation. @@ -847,9 +836,10 @@ impl Default for ResizeState { pub struct SurfaceData { pub buffer: Option, pub texture: Option>, - pub geometry: Option, + pub geometry: Option>, pub resize_state: ResizeState, - pub dimensions: Option<(i32, i32)>, + pub buffer_dimensions: Option>, + pub buffer_scale: i32, } impl SurfaceData { @@ -857,7 +847,8 @@ impl SurfaceData { match attrs.buffer.take() { Some(BufferAssignment::NewBuffer { buffer, .. }) => { // new contents - self.dimensions = buffer_dimensions(&buffer); + self.buffer_dimensions = buffer_dimensions(&buffer); + self.buffer_scale = attrs.buffer_scale; if let Some(old_buffer) = std::mem::replace(&mut self.buffer, Some(buffer)) { old_buffer.release(); } @@ -866,7 +857,7 @@ impl SurfaceData { Some(BufferAssignment::Removed) => { // remove the contents self.buffer = None; - self.dimensions = None; + self.buffer_dimensions = None; self.texture = None; } None => {} @@ -874,25 +865,23 @@ impl SurfaceData { } /// Returns the size of the surface. - pub fn size(&self) -> Option<(i32, i32)> { - self.dimensions + pub fn size(&self) -> Option> { + self.buffer_dimensions + .map(|dims| dims.to_logical(self.buffer_scale)) } /// Checks if the surface's input region contains the point. - pub fn contains_point(&self, attrs: &SurfaceAttributes, point: (f64, f64)) -> bool { - let (w, h) = match self.size() { + pub fn contains_point(&self, attrs: &SurfaceAttributes, point: Point) -> bool { + let size = match self.size() { None => return false, // If the surface has no size, it can't have an input region. - Some(wh) => wh, + Some(size) => size, }; let rect = Rectangle { - x: 0, - y: 0, - width: w, - height: h, - }; - - let point = (point.0 as i32, point.1 as i32); + loc: (0, 0).into(), + size, + } + .to_f64(); // The input region is always within the surface itself, so if the surface itself doesn't contain the // point we can return false. @@ -905,7 +894,11 @@ impl SurfaceData { return true; } - attrs.input_region.as_ref().unwrap().contains(point) + attrs + .input_region + .as_ref() + .unwrap() + .contains(point.to_i32_floor()) } /// Send the frame callback if it had been requested @@ -962,9 +955,8 @@ fn surface_commit(surface: &wl_surface::WlSurface, window_map: &RefCell { pub pointer: PointerHandle, pub keyboard: KeyboardHandle, pub suppressed_keys: Vec, - pub pointer_location: (f64, f64), + pub pointer_location: Point, pub cursor_status: Arc>, pub seat_name: String, pub seat: Seat, @@ -167,7 +168,7 @@ impl AnvilState { keyboard, suppressed_keys: Vec::new(), cursor_status, - pointer_location: (0.0, 0.0), + pointer_location: (0.0, 0.0).into(), seat_name, seat, start_time: std::time::Instant::now(), diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index ac7d75c..f8bbb61 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -48,7 +48,10 @@ use smithay::{ Display, }, }, - utils::signaling::{Linkable, SignalToken, Signaler}, + utils::{ + signaling::{Linkable, SignalToken, Signaler}, + Logical, Point, + }, wayland::{ output::{Mode, PhysicalProperties}, seat::CursorImageStatus, @@ -335,8 +338,7 @@ fn scan_connectors( let mode = connector_info.modes()[0]; let size = mode.size(); let mode = Mode { - width: size.0 as i32, - height: size.1 as i32, + size: (size.0 as i32, size.1 as i32).into(), refresh: (mode.vrefresh() * 1000) as i32, }; @@ -346,11 +348,11 @@ fn scan_connectors( connector_info.interface_id() ); + let (phys_w, phys_h) = connector_info.size().unwrap_or((0, 0)); output_map.add( &output_name, PhysicalProperties { - width: connector_info.size().unwrap_or((0, 0)).0 as i32, - height: connector_info.size().unwrap_or((0, 0)).1 as i32, + size: (phys_w as i32, phys_h as i32).into(), subpixel: wl_output::Subpixel::Unknown, make: "Smithay".into(), model: "Generic DRM".into(), @@ -618,7 +620,7 @@ impl AnvilState { &mut *self.window_map.borrow_mut(), &self.backend_data.output_map, &*self.output_map.borrow(), - &self.pointer_location, + self.pointer_location, &device_backend.pointer_image, &*self.dnd_icon.lock().unwrap(), &mut *self.cursor_status.lock().unwrap(), @@ -666,7 +668,7 @@ fn render_surface( window_map: &mut WindowMap, backend_output_map: &[UdevOutputMap], output_map: &crate::output_map::OutputMap, - pointer_location: &(f64, f64), + pointer_location: Point, pointer_image: &Gles2Texture, dnd_icon: &Option, cursor_status: &mut CursorImageStatus, @@ -692,27 +694,24 @@ fn render_surface( // and draw to our buffer match renderer .render( - output_geometry.width as u32, - output_geometry.height as u32, + // TODO: handle scale factor + output_geometry.size.to_physical(1), Transform::Flipped180, // Scanout is rotated |renderer, frame| { frame.clear([0.8, 0.8, 0.9, 1.0])?; // draw the surfaces draw_windows(renderer, frame, window_map, output_geometry, logger)?; - // get pointer coordinates - let (ptr_x, ptr_y) = *pointer_location; - let ptr_x = ptr_x.trunc().abs() as i32 - output_geometry.x; - let ptr_y = ptr_y.trunc().abs() as i32 - output_geometry.y; - // set cursor - if ptr_x >= 0 && ptr_x < output_geometry.width && ptr_y >= 0 && ptr_y < output_geometry.height - { + if output_geometry.to_f64().contains(pointer_location) { + let (ptr_x, ptr_y) = pointer_location.into(); + let relative_ptr_location = + Point::::from((ptr_x as i32, ptr_y as i32)) - output_geometry.loc; // draw the dnd icon if applicable { if let Some(ref wl_surface) = dnd_icon.as_ref() { if wl_surface.as_ref().is_alive() { - draw_dnd_icon(renderer, frame, wl_surface, (ptr_x, ptr_y), logger)?; + draw_dnd_icon(renderer, frame, wl_surface, relative_ptr_location, logger)?; } } } @@ -728,9 +727,15 @@ fn render_surface( } if let CursorImageStatus::Image(ref wl_surface) = *cursor_status { - draw_cursor(renderer, frame, wl_surface, (ptr_x, ptr_y), logger)?; + draw_cursor(renderer, frame, wl_surface, relative_ptr_location, logger)?; } else { - frame.render_texture_at(pointer_image, (ptr_x, ptr_y), Transform::Normal, 1.0)?; + // TODO: handle output scale factor + frame.render_texture_at( + pointer_image, + relative_ptr_location.to_physical(1), + Transform::Normal, + 1.0, + )?; } } } @@ -776,7 +781,7 @@ fn initial_render(surface: &mut RenderSurface, renderer: &mut Gles2Renderer) -> renderer.bind(dmabuf)?; // Does not matter if we render an empty frame renderer - .render(1, 1, Transform::Normal, |_, frame| { + .render((1, 1).into(), Transform::Normal, |_, frame| { frame .clear([0.8, 0.8, 0.9, 1.0]) .map_err(Into::::into) diff --git a/anvil/src/window_map.rs b/anvil/src/window_map.rs index b45bdee..6f70ae3 100644 --- a/anvil/src/window_map.rs +++ b/anvil/src/window_map.rs @@ -3,7 +3,7 @@ use std::sync::Mutex; use smithay::{ reexports::{wayland_protocols::xdg_shell::server::xdg_toplevel, wayland_server::protocol::wl_surface}, - utils::Rectangle, + utils::{Logical, Point, Rectangle}, wayland::{ compositor::{with_states, with_surface_tree_downward, SubsurfaceCachedState, TraversalAction}, shell::{ @@ -98,12 +98,12 @@ impl PopupKind { .flatten() } - pub fn location(&self) -> (i32, i32) { + pub fn location(&self) -> Point { let wl_surface = match self.get_surface() { Some(s) => s, - None => return (0, 0), + None => return (0, 0).into(), }; - let geometry = with_states(wl_surface, |states| { + with_states(wl_surface, |states| { states .data_map .get::>() @@ -113,26 +113,26 @@ impl PopupKind { .current .geometry }) - .unwrap_or_default(); - (geometry.x, geometry.y) + .unwrap_or_default() + .loc } } struct Window { - location: (i32, i32), + location: Point, /// A bounding box over this window and its children. /// /// Used for the fast path of the check in `matching`, and as the fall-back for the window /// geometry if that's not set explicitly. - bbox: Rectangle, + bbox: Rectangle, toplevel: Kind, } impl Window { /// Finds the topmost surface under this point if any and returns it together with the location of this /// surface. - fn matching(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> { - if !self.bbox.contains((point.0 as i32, point.1 as i32)) { + fn matching(&self, point: Point) -> Option<(wl_surface::WlSurface, Point)> { + if !self.bbox.to_f64().contains(point) { return None; } // need to check more carefully @@ -141,27 +141,26 @@ impl Window { with_surface_tree_downward( wl_surface, self.location, - |wl_surface, states, &(mut x, mut y)| { + |wl_surface, states, location| { + let mut location = *location; let data = states.data_map.get::>(); if states.role == Some("subsurface") { let current = states.cached_state.current::(); - x += current.location.0; - y += current.location.1; + location += current.location; } - let surface_local_point = (point.0 - x as f64, point.1 - y as f64); let contains_the_point = data .map(|data| { data.borrow() - .contains_point(&*states.cached_state.current(), surface_local_point) + .contains_point(&*states.cached_state.current(), point - location.to_f64()) }) .unwrap_or(false); if contains_the_point { - *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64))); + *found.borrow_mut() = Some((wl_surface.clone(), location)); } - TraversalAction::DoChildren((x, y)) + TraversalAction::DoChildren(location) }, |_, _, _| {}, |_, _, _| { @@ -174,29 +173,25 @@ impl Window { } fn self_update(&mut self) { - let (base_x, base_y) = self.location; - let (mut min_x, mut min_y, mut max_x, mut max_y) = (base_x, base_y, base_x, base_y); + let mut bounding_box = Rectangle::from_loc_and_size(self.location, (0, 0)); if let Some(wl_surface) = self.toplevel.get_surface() { with_surface_tree_downward( wl_surface, - (base_x, base_y), - |_, states, &(mut x, mut y)| { + self.location, + |_, states, &loc| { + let mut loc = loc; let data = states.data_map.get::>(); - if let Some((w, h)) = data.and_then(|d| d.borrow().size()) { + if let Some(size) = data.and_then(|d| d.borrow().size()) { if states.role == Some("subsurface") { let current = states.cached_state.current::(); - x += current.location.0; - y += current.location.1; + loc += current.location; } // Update the bounding box. - min_x = min_x.min(x); - min_y = min_y.min(y); - max_x = max_x.max(x + w); - max_y = max_y.max(y + h); + bounding_box = bounding_box.merge(Rectangle::from_loc_and_size(loc, size)); - TraversalAction::DoChildren((x, y)) + TraversalAction::DoChildren(loc) } else { // If the parent surface is unmapped, then the child surfaces are hidden as // well, no need to consider them here. @@ -207,16 +202,11 @@ impl Window { |_, _, _| true, ); } - self.bbox = Rectangle { - x: min_x, - y: min_y, - width: max_x - min_x, - height: max_y - min_y, - }; + self.bbox = bounding_box; } /// Returns the geometry of this window. - pub fn geometry(&self) -> Rectangle { + pub fn geometry(&self) -> Rectangle { // It's the set geometry with the full bounding box as the fallback. with_states(self.toplevel.get_surface().unwrap(), |states| { states.cached_state.current::().geometry @@ -261,7 +251,7 @@ impl WindowMap { } } - pub fn insert(&mut self, toplevel: Kind, location: (i32, i32)) { + pub fn insert(&mut self, toplevel: Kind, location: Point) { let mut window = Window { location, bbox: Rectangle::default(), @@ -276,7 +266,10 @@ impl WindowMap { self.popups.push(popup); } - pub fn get_surface_under(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> { + pub fn get_surface_under( + &self, + point: Point, + ) -> Option<(wl_surface::WlSurface, Point)> { for w in &self.windows { if let Some(surface) = w.matching(point) { return Some(surface); @@ -287,8 +280,8 @@ impl WindowMap { pub fn get_surface_and_bring_to_top( &mut self, - point: (f64, f64), - ) -> Option<(wl_surface::WlSurface, (f64, f64))> { + point: Point, + ) -> Option<(wl_surface::WlSurface, Point)> { let mut found = None; for (i, w) in self.windows.iter().enumerate() { if let Some(surface) = w.matching(point) { @@ -316,7 +309,7 @@ impl WindowMap { pub fn with_windows_from_bottom_to_top(&self, mut f: Func) where - Func: FnMut(&Kind, (i32, i32), &Rectangle), + Func: FnMut(&Kind, Point, &Rectangle), { for w in self.windows.iter().rev() { f(&w.toplevel, w.location, &w.bbox) @@ -386,7 +379,7 @@ impl WindowMap { } /// Returns the location of the toplevel, if it exists. - pub fn location(&self, toplevel: &Kind) -> Option<(i32, i32)> { + pub fn location(&self, toplevel: &Kind) -> Option> { self.windows .iter() .find(|w| &w.toplevel == toplevel) @@ -394,7 +387,7 @@ impl WindowMap { } /// Sets the location of the toplevel, if it exists. - pub fn set_location(&mut self, toplevel: &Kind, location: (i32, i32)) { + pub fn set_location(&mut self, toplevel: &Kind, location: Point) { if let Some(w) = self.windows.iter_mut().find(|w| &w.toplevel == toplevel) { w.location = location; w.self_update(); @@ -402,7 +395,7 @@ impl WindowMap { } /// Returns the geometry of the toplevel, if it exists. - pub fn geometry(&self, toplevel: &Kind) -> Option { + pub fn geometry(&self, toplevel: &Kind) -> Option> { self.windows .iter() .find(|w| &w.toplevel == toplevel) diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index f3dd1da..93484b4 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -65,7 +65,7 @@ pub fn run_winit( ); }; - let (w, h): (u32, u32) = renderer.borrow().window_size().physical_size.into(); + let size = renderer.borrow().window_size().physical_size; /* * Initialize the globals @@ -74,16 +74,14 @@ pub fn run_winit( let mut state = AnvilState::init(display.clone(), event_loop.handle(), WinitData, log.clone()); let mode = Mode { - width: w as i32, - height: h as i32, + size, refresh: 60_000, }; state.output_map.borrow_mut().add( OUTPUT_NAME, PhysicalProperties { - width: 0, - height: 0, + size: (0, 0).into(), subpixel: wl_output::Subpixel::Unknown, make: "Smithay".into(), model: "Winit".into(), @@ -132,13 +130,13 @@ pub fn run_winit( &log, )?; - let (x, y) = state.pointer_location; + let (x, y) = state.pointer_location.into(); // draw the dnd icon if any { let guard = state.dnd_icon.lock().unwrap(); if let Some(ref surface) = *guard { if surface.as_ref().is_alive() { - draw_dnd_icon(renderer, frame, surface, (x as i32, y as i32), &log)?; + draw_dnd_icon(renderer, frame, surface, (x as i32, y as i32).into(), &log)?; } } } @@ -157,7 +155,7 @@ pub fn run_winit( // draw as relevant if let CursorImageStatus::Image(ref surface) = *guard { cursor_visible = false; - draw_cursor(renderer, frame, surface, (x as i32, y as i32), &log)?; + draw_cursor(renderer, frame, surface, (x as i32, y as i32).into(), &log)?; } else { cursor_visible = true; } diff --git a/anvil/src/xwayland/mod.rs b/anvil/src/xwayland/mod.rs index aae48e2..3102ccc 100644 --- a/anvil/src/xwayland/mod.rs +++ b/anvil/src/xwayland/mod.rs @@ -2,6 +2,7 @@ use std::{cell::RefCell, collections::HashMap, convert::TryFrom, os::unix::net:: use smithay::{ reexports::wayland_server::{protocol::wl_surface::WlSurface, Client}, + utils::{Logical, Point}, wayland::compositor::give_role, }; @@ -67,7 +68,7 @@ struct X11State { conn: Rc, atoms: Atoms, log: slog::Logger, - unpaired_surfaces: HashMap, + unpaired_surfaces: HashMap)>, window_map: Rc>, } @@ -169,7 +170,7 @@ impl X11State { let location = { match self.conn.get_geometry(msg.window)?.reply() { - Ok(geo) => (geo.x.into(), geo.y.into()), + Ok(geo) => (geo.x as i32, geo.y as i32).into(), Err(err) => { error!( self.log, @@ -177,7 +178,7 @@ impl X11State { msg.window; "err" => format!("{:?}", err), ); - (0, 0) + (0, 0).into() } } }; @@ -201,7 +202,7 @@ impl X11State { Ok(()) } - fn new_window(&mut self, window: Window, surface: WlSurface, location: (i32, i32)) { + fn new_window(&mut self, window: Window, surface: WlSurface, location: Point) { debug!(self.log, "Matched X11 surface {:x?} to {:x?}", window, surface); if give_role(&surface, "x11_surface").is_err() { diff --git a/src/backend/egl/display.rs b/src/backend/egl/display.rs index 8ed4074..8a7da5a 100644 --- a/src/backend/egl/display.rs +++ b/src/backend/egl/display.rs @@ -822,7 +822,10 @@ impl EGLBufferReader { /// /// In case the buffer is not managed by EGL (but e.g. the [`wayland::shm` module](crate::wayland::shm)) or the /// context has been lost, `None` is returned. - pub fn egl_buffer_dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> { + pub fn egl_buffer_dimensions( + &self, + buffer: &WlBuffer, + ) -> Option> { let mut width: i32 = 0; if unsafe { ffi::egl::QueryWaylandBufferWL( @@ -847,7 +850,7 @@ impl EGLBufferReader { return None; } - Some((width, height)) + Some((width, height).into()) } } diff --git a/src/backend/input.rs b/src/backend/input.rs index 7def5a8..be58533 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -9,6 +9,8 @@ pub use tablet::{ TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TabletToolType, }; +use crate::utils::{Logical, Point, Raw}; + /// Trait for generic functions every input device does provide pub trait Device: PartialEq + Eq + std::hash::Hash { /// Unique id of a single device at a point in time. @@ -222,8 +224,8 @@ impl PointerAxisEvent for UnusedEvent { /// Trait for pointer events generated by relative device movement. pub trait PointerMotionEvent: Event { /// Delta between the last and new pointer device position interpreted as pixel movement - fn delta(&self) -> (f64, f64) { - (self.delta_x(), self.delta_y()) + fn delta(&self) -> Point { + (self.delta_x(), self.delta_y()).into() } /// Delta on the x axis between the last and new pointer device position interpreted as pixel movement @@ -247,8 +249,8 @@ pub trait PointerMotionAbsoluteEvent: Event { /// Device position in it's original coordinate space. /// /// The format is defined by the backend implementation. - fn position(&self) -> (f64, f64) { - (self.x(), self.y()) + fn position(&self) -> Point { + (self.x(), self.y()).into() } /// Device x position in it's original coordinate space. @@ -263,11 +265,12 @@ pub trait PointerMotionAbsoluteEvent: Event { /// Device position converted to the targets coordinate space. /// E.g. the focused output's resolution. - fn position_transformed(&self, coordinate_space: (u32, u32)) -> (f64, f64) { + fn position_transformed(&self, coordinate_space: Point) -> Point { ( - self.x_transformed(coordinate_space.0), - self.y_transformed(coordinate_space.1), + self.x_transformed(coordinate_space.x), + self.y_transformed(coordinate_space.y), ) + .into() } /// Device x position converted to the targets coordinate space's width. @@ -322,17 +325,18 @@ pub trait TouchDownEvent: Event { /// Touch position in the device's native coordinate space /// /// The actual format is defined by the implementation. - fn position(&self) -> (f64, f64) { - (self.x(), self.y()) + fn position(&self) -> Point { + (self.x(), self.y()).into() } /// Touch position converted into the target coordinate space. /// E.g. the focused output's resolution. - fn position_transformed(&self, coordinate_space: (u32, u32)) -> (f64, f64) { + fn position_transformed(&self, coordinate_space: Point) -> Point { ( - self.x_transformed(coordinate_space.0), - self.y_transformed(coordinate_space.1), + self.x_transformed(coordinate_space.x), + self.y_transformed(coordinate_space.y), ) + .into() } /// Touch event's x-coordinate in the device's native coordinate space @@ -384,17 +388,18 @@ pub trait TouchMotionEvent: Event { /// Touch position in the device's native coordinate space /// /// The actual format is defined by the implementation. - fn position(&self) -> (f64, f64) { - (self.x(), self.y()) + fn position(&self) -> Point { + (self.x(), self.y()).into() } /// Touch position converted into the target coordinate space. /// E.g. the focused output's resolution. - fn position_transformed(&self, coordinate_space: (u32, u32)) -> (f64, f64) { + fn position_transformed(&self, coordinate_space: Point) -> Point { ( - self.x_transformed(coordinate_space.0), - self.y_transformed(coordinate_space.1), + self.x_transformed(coordinate_space.x), + self.y_transformed(coordinate_space.y), ) + .into() } /// Touch event's x-coordinate in the device's native coordinate space diff --git a/src/backend/input/tablet.rs b/src/backend/input/tablet.rs index 91813c7..85e2659 100644 --- a/src/backend/input/tablet.rs +++ b/src/backend/input/tablet.rs @@ -1,4 +1,5 @@ use super::{ButtonState, Event, InputBackend, UnusedEvent}; +use crate::utils::{Logical, Point, Raw}; use bitflags::bitflags; /// Description of physical tablet tool @@ -62,21 +63,22 @@ pub trait TabletToolEvent { fn tool(&self) -> TabletToolDescriptor; /// Delta between the last and new pointer device position interpreted as pixel movement - fn delta(&self) -> (f64, f64) { - (self.delta_x(), self.delta_y()) + fn delta(&self) -> Point { + (self.delta_x(), self.delta_y()).into() } /// Tool position in the device's native coordinate space - fn position(&self) -> (f64, f64) { - (self.x(), self.y()) + fn position(&self) -> Point { + (self.x(), self.y()).into() } /// Tool position converted into the target coordinate space. - fn position_transformed(&self, coordinate_space: (u32, u32)) -> (f64, f64) { + fn position_transformed(&self, coordinate_space: Point) -> Point { ( - self.x_transformed(coordinate_space.0), - self.y_transformed(coordinate_space.1), + self.x_transformed(coordinate_space.x), + self.y_transformed(coordinate_space.y), ) + .into() } /// Returns the current tilt along the (X,Y) axis of the tablet's current logical diff --git a/src/backend/renderer/gles2/mod.rs b/src/backend/renderer/gles2/mod.rs index 1187782..9b3fbf8 100644 --- a/src/backend/renderer/gles2/mod.rs +++ b/src/backend/renderer/gles2/mod.rs @@ -26,6 +26,7 @@ use crate::backend::egl::{ EGLContext, EGLSurface, MakeCurrentError, }; use crate::backend::SwapBuffersError; +use crate::utils::{Physical, Size}; #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] use super::ImportEgl; @@ -34,7 +35,7 @@ use super::{ImportDma, ImportShm}; #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] use crate::backend::egl::{display::EGLBufferReader, Format as EGLFormat}; #[cfg(feature = "wayland_frontend")] -use crate::utils::Rectangle; +use crate::utils::{Buffer, Rectangle}; #[cfg(feature = "wayland_frontend")] use wayland_server::protocol::{wl_buffer, wl_shm}; @@ -514,7 +515,7 @@ impl ImportShm for Gles2Renderer { &mut self, buffer: &wl_buffer::WlBuffer, surface: Option<&crate::wayland::compositor::SurfaceData>, - damage: &[Rectangle], + damage: &[Rectangle], ) -> Result { use crate::wayland::shm::with_buffer_contents; @@ -591,15 +592,15 @@ impl ImportShm for Gles2Renderer { } else { for region in damage.iter() { trace!(self.logger, "Uploading partial shm texture for {:?}", buffer); - self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, region.x); - self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, region.y); + self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, region.loc.x); + self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, region.loc.y); self.gl.TexSubImage2D( ffi::TEXTURE_2D, 0, - region.x, - region.y, - region.width, - region.height, + region.loc.x, + region.loc.y, + region.size.w, + region.size.h, gl_format, ffi::UNSIGNED_BYTE as u32, slice.as_ptr().offset(offset as isize) as *const _, @@ -1014,8 +1015,7 @@ impl Renderer for Gles2Renderer { fn render( &mut self, - width: u32, - height: u32, + size: Size, transform: Transform, rendering: F, ) -> Result @@ -1027,7 +1027,7 @@ impl Renderer for Gles2Renderer { self.cleanup()?; unsafe { - self.gl.Viewport(0, 0, width as i32, height as i32); + self.gl.Viewport(0, 0, size.w, size.h); self.gl.Enable(ffi::BLEND); self.gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA); @@ -1037,8 +1037,8 @@ impl Renderer for Gles2Renderer { // glOrtho(0, width, 0, height, 1, 1); let mut renderer = Matrix3::::identity(); let t = Matrix3::::identity(); - let x = 2.0 / (width as f32); - let y = 2.0 / (height as f32); + let x = 2.0 / (size.w as f32); + let y = 2.0 / (size.h as f32); // Rotation & Reflection renderer[0][0] = x * t[0][0]; diff --git a/src/backend/renderer/mod.rs b/src/backend/renderer/mod.rs index 462e248..60aebbe 100644 --- a/src/backend/renderer/mod.rs +++ b/src/backend/renderer/mod.rs @@ -10,6 +10,8 @@ use std::collections::HashSet; use std::error::Error; +use crate::utils::{Buffer, Physical, Point, Size}; + #[cfg(feature = "wayland_frontend")] use crate::{utils::Rectangle, wayland::compositor::SurfaceData}; use cgmath::{prelude::*, Matrix3, Vector2}; @@ -178,7 +180,7 @@ pub trait Frame { fn render_texture_at( &mut self, texture: &Self::TextureId, - pos: (i32, i32), + pos: Point, transform: Transform, alpha: f32, ) -> Result<(), Self::Error> { @@ -186,7 +188,7 @@ pub trait Frame { // position and scale let size = texture.size(); - mat = mat * Matrix3::from_translation(Vector2::new(pos.0 as f32, pos.1 as f32)); + mat = mat * Matrix3::from_translation(Vector2::new(pos.x as f32, pos.y as f32)); mat = mat * Matrix3::from_nonuniform_scale(size.0 as f32, size.1 as f32); //apply surface transformation @@ -234,8 +236,7 @@ pub trait Renderer { /// - (Renderers not implementing `Bind` always have a default target.) fn render( &mut self, - width: u32, - height: u32, + size: Size, transform: Transform, rendering: F, ) -> Result @@ -265,7 +266,7 @@ pub trait ImportShm: Renderer { &mut self, buffer: &wl_buffer::WlBuffer, surface: Option<&crate::wayland::compositor::SurfaceData>, - damage: &[Rectangle], + damage: &[Rectangle], ) -> Result<::TextureId, ::Error>; /// Returns supported formats for shared memory buffers. @@ -405,7 +406,7 @@ pub trait ImportAll: Renderer { &mut self, buffer: &wl_buffer::WlBuffer, surface: Option<&crate::wayland::compositor::SurfaceData>, - damage: &[Rectangle], + damage: &[Rectangle], ) -> Option::TextureId, ::Error>>; } @@ -420,7 +421,7 @@ impl ImportAll for R { &mut self, buffer: &wl_buffer::WlBuffer, surface: Option<&SurfaceData>, - damage: &[Rectangle], + damage: &[Rectangle], ) -> Option::TextureId, ::Error>> { match buffer_type(buffer) { Some(BufferType::Shm) => Some(self.import_shm_buffer(buffer, surface, damage)), @@ -440,7 +441,7 @@ impl ImportAll for R { &mut self, buffer: &wl_buffer::WlBuffer, surface: Option<&SurfaceData>, - damage: &[Rectangle], + damage: &[Rectangle], ) -> Option::TextureId, ::Error>> { match buffer_type(buffer) { Some(BufferType::Shm) => Some(self.import_shm_buffer(buffer, surface, damage)), @@ -497,29 +498,23 @@ pub fn buffer_type(buffer: &wl_buffer::WlBuffer) -> Option { /// /// *Note*: This will only return dimensions for buffer types known to smithay (see [`buffer_type`]) #[cfg(feature = "wayland_frontend")] -pub fn buffer_dimensions(buffer: &wl_buffer::WlBuffer) -> Option<(i32, i32)> { +pub fn buffer_dimensions(buffer: &wl_buffer::WlBuffer) -> Option> { use crate::backend::allocator::Buffer; if let Some(buf) = buffer.as_ref().user_data().get::() { - return Some((buf.width() as i32, buf.height() as i32)); + return Some((buf.width() as i32, buf.height() as i32).into()); } #[cfg(all(feature = "backend_egl", feature = "use_system_lib"))] - if let Some((w, h)) = BUFFER_READER + if let Some(dim) = BUFFER_READER .lock() .unwrap() .as_ref() .and_then(|x| x.upgrade()) .and_then(|x| x.egl_buffer_dimensions(&buffer)) { - return Some((w, h)); + return Some(dim); } - if let Ok((w, h)) = - crate::wayland::shm::with_buffer_contents(&buffer, |_, data| (data.width, data.height)) - { - return Some((w, h)); - } - - None + crate::wayland::shm::with_buffer_contents(&buffer, |_, data| (data.width, data.height).into()).ok() } diff --git a/src/backend/winit.rs b/src/backend/winit.rs index b88b7c3..f71f092 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -19,24 +19,28 @@ //! The other types in this module are the instances of the associated types of these //! two traits for the winit backend. -use crate::backend::egl::display::EGLDisplay; -use crate::backend::{ - egl::{context::GlAttributes, native, EGLContext, EGLSurface, Error as EGLError}, - input::{ - Axis, AxisSource, ButtonState, Device, DeviceCapability, Event as BackendEvent, InputBackend, - InputEvent, KeyState, KeyboardKeyEvent, MouseButton, PointerAxisEvent, PointerButtonEvent, - PointerMotionAbsoluteEvent, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, - TouchUpEvent, UnusedEvent, - }, - renderer::{ - gles2::{Gles2Error, Gles2Frame, Gles2Renderer}, - Bind, Renderer, Transform, Unbind, +use crate::{ + backend::{ + egl::{ + context::GlAttributes, display::EGLDisplay, native, EGLContext, EGLSurface, Error as EGLError, + }, + input::{ + Axis, AxisSource, ButtonState, Device, DeviceCapability, Event as BackendEvent, InputBackend, + InputEvent, KeyState, KeyboardKeyEvent, MouseButton, PointerAxisEvent, PointerButtonEvent, + PointerMotionAbsoluteEvent, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, + TouchUpEvent, UnusedEvent, + }, + renderer::{ + gles2::{Gles2Error, Gles2Frame, Gles2Renderer}, + Bind, Renderer, Transform, Unbind, + }, }, + utils::{Logical, Physical, Size}, }; use std::{cell::RefCell, path::PathBuf, rc::Rc, time::Instant}; use wayland_egl as wegl; use winit::{ - dpi::{LogicalPosition, LogicalSize, PhysicalSize}, + dpi::{LogicalPosition, LogicalSize}, event::{ ElementState, Event, KeyboardInput, MouseButton as WinitMouseButton, MouseScrollDelta, Touch, TouchPhase, WindowEvent, @@ -71,11 +75,17 @@ pub enum Error { #[derive(Debug, Clone)] pub struct WindowSize { /// Pixel side of the window - pub physical_size: PhysicalSize, + pub physical_size: Size, /// Scaling factor of the window pub scale_factor: f64, } +impl WindowSize { + fn logical_size(&self) -> Size { + self.physical_size.to_f64().to_logical(self.scale_factor) + } +} + /// Window with an active EGL Context created by `winit`. Implements the [`Renderer`] trait #[derive(Debug)] pub struct WinitGraphicsBackend { @@ -84,7 +94,7 @@ pub struct WinitGraphicsBackend { egl: Rc, window: Rc, size: Rc>, - resize_notification: Rc>>, + resize_notification: Rc>>>, } /// Abstracted event loop of a [`WinitWindow`] implementing the [`InputBackend`] trait @@ -100,7 +110,7 @@ pub struct WinitInputBackend { logger: ::slog::Logger, initialized: bool, size: Rc>, - resize_notification: Rc>>, + resize_notification: Rc>>>, } /// Create a new [`WinitGraphicsBackend`], which implements the [`Renderer`] trait and a corresponding [`WinitInputBackend`], @@ -196,8 +206,9 @@ where (display, context, surface) }; + let (w, h): (u32, u32) = winit_window.inner_size().into(); let size = Rc::new(RefCell::new(WindowSize { - physical_size: winit_window.inner_size(), // TODO: original code check if window is alive or not using inner_size().expect() + physical_size: (w as i32, h as i32).into(), scale_factor: winit_window.scale_factor(), })); @@ -234,7 +245,7 @@ pub enum WinitEvent { /// The window has been resized Resized { /// The new physical size (in pixels) - size: (f64, f64), + size: Size, /// The new scale factor scale_factor: f64, }, @@ -267,19 +278,17 @@ impl WinitGraphicsBackend { F: FnOnce(&mut Gles2Renderer, &mut Gles2Frame) -> R, { // Were we told to resize? - if let Some((width, height)) = self.resize_notification.take() { - self.egl.resize(width as i32, height as i32, 0, 0); + if let Some(size) = self.resize_notification.take() { + self.egl.resize(size.w, size.h, 0, 0); } - let (width, height) = { + let size = { let size = self.size.borrow(); - size.physical_size.into() + size.physical_size }; self.renderer.bind(self.egl.clone())?; - let result = self - .renderer - .render(width, height, Transform::Normal, rendering)?; + let result = self.renderer.render(size, Transform::Normal, rendering)?; self.egl.swap_buffers()?; self.renderer.unbind()?; Ok(result) @@ -390,13 +399,13 @@ impl PointerMotionAbsoluteEvent for WinitMouseMovedEvent { fn x_transformed(&self, width: u32) -> f64 { let wsize = self.size.borrow(); - let w_width = wsize.physical_size.to_logical::(wsize.scale_factor).width; + let w_width = wsize.logical_size().w; f64::max(self.logical_position.x * width as f64 / w_width, 0.0) } fn y_transformed(&self, height: u32) -> f64 { let wsize = self.size.borrow(); - let w_height = wsize.physical_size.to_logical::(wsize.scale_factor).height; + let w_height = wsize.logical_size().h; f64::max(self.logical_position.y * height as f64 / w_height, 0.0) } } @@ -476,7 +485,7 @@ impl PointerButtonEvent for WinitMouseInputEvent { pub struct WinitTouchStartedEvent { size: Rc>, time: u32, - location: (f64, f64), + location: LogicalPosition, id: u64, } @@ -497,24 +506,24 @@ impl TouchDownEvent for WinitTouchStartedEvent { fn x(&self) -> f64 { let wsize = self.size.borrow(); - self.location.0 * wsize.scale_factor + self.location.x * wsize.scale_factor } fn y(&self) -> f64 { let wsize = self.size.borrow(); - self.location.1 * wsize.scale_factor + self.location.y * wsize.scale_factor } fn x_transformed(&self, width: u32) -> f64 { let wsize = self.size.borrow(); - let w_width = wsize.physical_size.to_logical::(wsize.scale_factor).width; - f64::max(self.location.0 * width as f64 / w_width, 0.0) + let w_width = wsize.logical_size().w; + f64::max(self.location.x * width as f64 / w_width, 0.0) } fn y_transformed(&self, height: u32) -> f64 { let wsize = self.size.borrow(); - let w_height = wsize.physical_size.to_logical::(wsize.scale_factor).height; - f64::max(self.location.1 * height as f64 / w_height, 0.0) + let w_height = wsize.logical_size().h; + f64::max(self.location.y * height as f64 / w_height, 0.0) } } @@ -523,7 +532,7 @@ impl TouchDownEvent for WinitTouchStartedEvent { pub struct WinitTouchMovedEvent { size: Rc>, time: u32, - location: (f64, f64), + location: LogicalPosition, id: u64, } @@ -544,24 +553,24 @@ impl TouchMotionEvent for WinitTouchMovedEvent { fn x(&self) -> f64 { let wsize = self.size.borrow(); - self.location.0 * wsize.scale_factor + self.location.x * wsize.scale_factor } fn y(&self) -> f64 { let wsize = self.size.borrow(); - self.location.1 * wsize.scale_factor + self.location.y * wsize.scale_factor } fn x_transformed(&self, width: u32) -> f64 { let wsize = self.size.borrow(); - let w_width = wsize.physical_size.to_logical::(wsize.scale_factor).width; - f64::max(self.location.0 * width as f64 / w_width, 0.0) + let w_width = wsize.logical_size().w; + f64::max(self.location.x * width as f64 / w_width, 0.0) } fn y_transformed(&self, height: u32) -> f64 { let wsize = self.size.borrow(); - let w_height = wsize.physical_size.to_logical::(wsize.scale_factor).height; - f64::max(self.location.1 * height as f64 / w_height, 0.0) + let w_height = wsize.logical_size().h; + f64::max(self.location.y * height as f64 / w_height, 0.0) } } @@ -687,13 +696,14 @@ impl InputBackend for WinitInputBackend { trace!(logger, "Resizing window to {:?}", psize); let scale_factor = window.scale_factor(); let mut wsize = window_size.borrow_mut(); - wsize.physical_size = psize; + let (pw, ph): (u32, u32) = psize.into(); + wsize.physical_size = (pw as i32, ph as i32).into(); wsize.scale_factor = scale_factor; - resize_notification.set(Some((psize.width, psize.height))); + resize_notification.set(Some(wsize.physical_size)); callback(InputEvent::Special(WinitEvent::Resized { - size: psize.into(), + size: wsize.physical_size, scale_factor, })); } @@ -708,11 +718,11 @@ impl InputBackend for WinitInputBackend { let mut wsize = window_size.borrow_mut(); wsize.scale_factor = scale_factor; - resize_notification.set(Some((new_psize.width, new_psize.height))); + let (pw, ph): (u32, u32) = (*new_psize).into(); + resize_notification.set(Some((pw as i32, ph as i32).into())); - let psize_f64: (f64, f64) = (new_psize.width.into(), new_psize.height.into()); callback(InputEvent::Special(WinitEvent::Resized { - size: psize_f64, + size: (pw as i32, ph as i32).into(), scale_factor: wsize.scale_factor, })); } @@ -761,11 +771,12 @@ impl InputBackend for WinitInputBackend { id, .. }) => { + let location = location.to_logical(window_size.borrow().scale_factor); callback(InputEvent::TouchDown { event: WinitTouchStartedEvent { size: window_size.clone(), time, - location: location.into(), + location, id, }, }); @@ -776,11 +787,12 @@ impl InputBackend for WinitInputBackend { id, .. }) => { + let location = location.to_logical(window_size.borrow().scale_factor); callback(InputEvent::TouchMotion { event: WinitTouchMovedEvent { size: window_size.clone(), time, - location: location.into(), + location, id, }, }); @@ -792,11 +804,12 @@ impl InputBackend for WinitInputBackend { id, .. }) => { + let location = location.to_logical(window_size.borrow().scale_factor); callback(InputEvent::TouchMotion { event: WinitTouchMovedEvent { size: window_size.clone(), time, - location: location.into(), + location, id, }, }); diff --git a/src/utils/geometry.rs b/src/utils/geometry.rs new file mode 100644 index 0000000..7f3cb2e --- /dev/null +++ b/src/utils/geometry.rs @@ -0,0 +1,829 @@ +use std::fmt; +use std::ops::{Add, AddAssign, Sub, SubAssign}; + +/// Type-level marker for the logical coordinate space +#[derive(Debug)] +pub struct Logical; + +/// Type-level marker for the physical coordinate space +#[derive(Debug)] +pub struct Physical; + +/// Type-level marker for the buffer coordinate space +#[derive(Debug)] +pub struct Buffer; + +/// Type-level marker for raw coordinate space, provided by input devices +#[derive(Debug)] +pub struct Raw; + +pub trait Coordinate: + Sized + Add + Sub + PartialOrd + Default + Copy + std::fmt::Debug +{ + fn downscale(self, scale: Self) -> Self; + fn upscale(self, scale: Self) -> Self; + fn to_f64(self) -> f64; + fn from_f64(v: f64) -> Self; + fn non_negative(self) -> bool; + fn abs(self) -> Self; +} + +impl Coordinate for f64 { + #[inline] + fn downscale(self, scale: f64) -> f64 { + self / scale + } + #[inline] + fn upscale(self, scale: f64) -> f64 { + self * scale + } + #[inline] + fn to_f64(self) -> f64 { + self + } + #[inline] + fn from_f64(v: f64) -> f64 { + v + } + #[inline] + fn non_negative(self) -> bool { + self >= 0.0 + } + #[inline] + fn abs(self) -> f64 { + self.abs() + } +} + +impl Coordinate for i32 { + #[inline] + fn downscale(self, scale: i32) -> i32 { + self / scale + } + #[inline] + fn upscale(self, scale: i32) -> i32 { + self.saturating_mul(scale) + } + #[inline] + fn to_f64(self) -> f64 { + self as f64 + } + #[inline] + fn from_f64(v: f64) -> i32 { + v as i32 + } + #[inline] + fn non_negative(self) -> bool { + self >= 0 + } + #[inline] + fn abs(self) -> i32 { + self.abs() + } +} + +/* + * Point + */ + +/// A point as defined by its x and y coordinates +pub struct Point { + /// horizontal coordinate + pub x: N, + /// vertical coordinate + pub y: N, + _kind: std::marker::PhantomData, +} + +impl Point { + /// Convert this [`Point`] to a [`Size`] with the same coordinates + /// + /// Checks that the coordinates are positive with a `debug_assert!()`. + #[inline] + pub fn to_size(self) -> Size { + debug_assert!( + self.x.non_negative() && self.y.non_negative(), + "Attempting to create a `Size` of negative size: {:?}", + (self.x, self.y) + ); + Size { + w: self.x, + h: self.y, + _kind: std::marker::PhantomData, + } + } + + /// Convert this [`Point`] to a [`Size`] with the same coordinates + /// + /// Ensures that the coordinates are positive by taking their absolute value + #[inline] + pub fn to_size_abs(self) -> Size { + Size { + w: self.x.abs(), + h: self.y.abs(), + _kind: std::marker::PhantomData, + } + } +} + +impl Point { + /// Convert the underlying numerical type to f64 for floating point manipulations + #[inline] + pub fn to_f64(self) -> Point { + Point { + x: self.x.to_f64(), + y: self.y.to_f64(), + _kind: std::marker::PhantomData, + } + } +} + +impl Point { + /// Convert to i32 for integer-space manipulations by rounding float values + #[inline] + pub fn to_i32_round(self) -> Point { + Point { + x: N::from_f64(self.x.round()), + y: N::from_f64(self.y.round()), + _kind: std::marker::PhantomData, + } + } + + /// Convert to i32 for integer-space manipulations by flooring float values + #[inline] + pub fn to_i32_floor(self) -> Point { + Point { + x: N::from_f64(self.x.floor()), + y: N::from_f64(self.y.floor()), + _kind: std::marker::PhantomData, + } + } + + /// Convert to i32 for integer-space manipulations by ceiling float values + #[inline] + pub fn to_i32_ceil(self) -> Point { + Point { + x: N::from_f64(self.x.ceil()), + y: N::from_f64(self.y.ceil()), + _kind: std::marker::PhantomData, + } + } +} + +impl fmt::Debug for Point { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Point") + .field("x", &self.x) + .field("y", &self.y) + .finish() + } +} + +impl fmt::Debug for Point { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Point") + .field("x", &self.x) + .field("y", &self.y) + .finish() + } +} + +impl fmt::Debug for Point { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Point") + .field("x", &self.x) + .field("y", &self.y) + .finish() + } +} + +impl fmt::Debug for Point { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Point") + .field("x", &self.x) + .field("y", &self.y) + .finish() + } +} + +impl Point { + #[inline] + /// Convert this logical point to physical coordinate space according to given scale factor + pub fn to_physical(self, scale: N) -> Point { + Point { + x: self.x.upscale(scale), + y: self.y.upscale(scale), + _kind: std::marker::PhantomData, + } + } + + #[inline] + /// Convert this logical point to buffer coordinate space according to given scale factor + pub fn to_buffer(self, scale: N) -> Point { + Point { + x: self.x.upscale(scale), + y: self.y.upscale(scale), + _kind: std::marker::PhantomData, + } + } +} + +impl Point { + #[inline] + /// Convert this physical point to logical coordinate space according to given scale factor + pub fn to_logical(self, scale: N) -> Point { + Point { + x: self.x.downscale(scale), + y: self.y.downscale(scale), + _kind: std::marker::PhantomData, + } + } +} + +impl Point { + #[inline] + /// Convert this physical point to logical coordinate space according to given scale factor + pub fn to_logical(self, scale: N) -> Point { + Point { + x: self.x.downscale(scale), + y: self.y.downscale(scale), + _kind: std::marker::PhantomData, + } + } +} + +impl From<(N, N)> for Point { + #[inline] + fn from((x, y): (N, N)) -> Point { + Point { + x, + y, + _kind: std::marker::PhantomData, + } + } +} + +impl From> for (N, N) { + #[inline] + fn from(point: Point) -> (N, N) { + (point.x, point.y) + } +} + +impl, Kind> Add for Point { + type Output = Point; + #[inline] + fn add(self, other: Point) -> Point { + Point { + x: self.x + other.x, + y: self.y + other.y, + _kind: std::marker::PhantomData, + } + } +} + +impl AddAssign for Point { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x += rhs.x; + self.y += rhs.y + } +} + +impl SubAssign for Point { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + self.x -= rhs.x; + self.y -= rhs.y + } +} + +impl, Kind> Sub for Point { + type Output = Point; + #[inline] + fn sub(self, other: Point) -> Point { + Point { + x: self.x - other.x, + y: self.y - other.y, + _kind: std::marker::PhantomData, + } + } +} + +impl Clone for Point { + #[inline] + fn clone(&self) -> Self { + Point { + x: self.x.clone(), + y: self.y.clone(), + _kind: std::marker::PhantomData, + } + } +} + +impl Copy for Point {} + +impl PartialEq for Point { + fn eq(&self, other: &Self) -> bool { + self.x == other.x && self.y == other.y + } +} + +impl Eq for Point {} + +impl Default for Point { + fn default() -> Self { + Point { + x: N::default(), + y: N::default(), + _kind: std::marker::PhantomData, + } + } +} + +/* + * Size + */ + +/// A size as defined by its width and height +/// +/// Constructors of this type ensure that the values are always positive via +/// `debug_assert!()`, however manually changing the values of the fields +/// can break this invariant. +pub struct Size { + /// horizontal coordinate + pub w: N, + /// vertical coordinate + pub h: N, + _kind: std::marker::PhantomData, +} + +impl Size { + /// Convert this [`Size`] to a [`Point`] with the same coordinates + #[inline] + pub fn to_point(self) -> Point { + Point { + x: self.w, + y: self.h, + _kind: std::marker::PhantomData, + } + } +} + +impl Size { + /// Convert the underlying numerical type to f64 for floating point manipulations + #[inline] + pub fn to_f64(self) -> Size { + Size { + w: self.w.to_f64(), + h: self.h.to_f64(), + _kind: std::marker::PhantomData, + } + } +} + +impl Size { + /// Convert to i32 for integer-space manipulations by rounding float values + #[inline] + pub fn to_i32_round(self) -> Size { + Size { + w: N::from_f64(self.w.round()), + h: N::from_f64(self.h.round()), + _kind: std::marker::PhantomData, + } + } + + /// Convert to i32 for integer-space manipulations by flooring float values + #[inline] + pub fn to_i32_floor(self) -> Size { + Size { + w: N::from_f64(self.w.floor()), + h: N::from_f64(self.h.floor()), + _kind: std::marker::PhantomData, + } + } + + /// Convert to i32 for integer-space manipulations by ceiling float values + #[inline] + pub fn to_i32_ceil(self) -> Size { + Size { + w: N::from_f64(self.w.ceil()), + h: N::from_f64(self.h.ceil()), + _kind: std::marker::PhantomData, + } + } +} + +impl fmt::Debug for Size { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Size") + .field("w", &self.w) + .field("h", &self.h) + .finish() + } +} + +impl fmt::Debug for Size { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Size") + .field("w", &self.w) + .field("h", &self.h) + .finish() + } +} + +impl fmt::Debug for Size { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Size") + .field("w", &self.w) + .field("h", &self.h) + .finish() + } +} + +impl fmt::Debug for Size { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Size") + .field("w", &self.w) + .field("h", &self.h) + .finish() + } +} + +impl Size { + #[inline] + /// Convert this logical size to physical coordinate space according to given scale factor + pub fn to_physical(self, scale: N) -> Size { + Size { + w: self.w.upscale(scale), + h: self.h.upscale(scale), + _kind: std::marker::PhantomData, + } + } + + #[inline] + /// Convert this logical size to buffer coordinate space according to given scale factor + pub fn to_buffer(self, scale: N) -> Size { + Size { + w: self.w.upscale(scale), + h: self.h.upscale(scale), + _kind: std::marker::PhantomData, + } + } +} + +impl Size { + #[inline] + /// Convert this physical point to logical coordinate space according to given scale factor + pub fn to_logical(self, scale: N) -> Size { + Size { + w: self.w.downscale(scale), + h: self.h.downscale(scale), + _kind: std::marker::PhantomData, + } + } +} + +impl Size { + #[inline] + /// Convert this physical point to logical coordinate space according to given scale factor + pub fn to_logical(self, scale: N) -> Size { + Size { + w: self.w.downscale(scale), + h: self.h.downscale(scale), + _kind: std::marker::PhantomData, + } + } +} + +impl From<(N, N)> for Size { + #[inline] + fn from((w, h): (N, N)) -> Size { + debug_assert!( + w.non_negative() && h.non_negative(), + "Attempting to create a `Size` of negative size: {:?}", + (w, h) + ); + Size { + w, + h, + _kind: std::marker::PhantomData, + } + } +} + +impl From> for (N, N) { + #[inline] + fn from(point: Size) -> (N, N) { + (point.w, point.h) + } +} + +impl, Kind> Add for Size { + type Output = Size; + #[inline] + fn add(self, other: Size) -> Size { + Size { + w: self.w + other.w, + h: self.h + other.h, + _kind: std::marker::PhantomData, + } + } +} + +impl AddAssign for Size { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.w += rhs.w; + self.h += rhs.h + } +} + +impl Clone for Size { + #[inline] + fn clone(&self) -> Self { + Size { + w: self.w.clone(), + h: self.h.clone(), + _kind: std::marker::PhantomData, + } + } +} + +impl Copy for Size {} + +impl PartialEq for Size { + fn eq(&self, other: &Self) -> bool { + self.w == other.w && self.h == other.h + } +} + +impl Eq for Size {} + +impl Default for Size { + fn default() -> Self { + Size { + w: N::default(), + h: N::default(), + _kind: std::marker::PhantomData, + } + } +} + +impl, Kind> Add> for Point { + type Output = Point; + #[inline] + fn add(self, other: Size) -> Point { + Point { + x: self.x + other.w, + y: self.y + other.h, + _kind: std::marker::PhantomData, + } + } +} + +impl, Kind> Sub> for Point { + type Output = Point; + #[inline] + fn sub(self, other: Size) -> Point { + Point { + x: self.x - other.w, + y: self.y - other.h, + _kind: std::marker::PhantomData, + } + } +} + +/// A rectangle defined by its top-left corner and dimensions +pub struct Rectangle { + /// Location of the top-left corner of the rectangle + pub loc: Point, + /// Size of the rectangle, as (width, height) + pub size: Size, +} + +impl Rectangle { + /// Convert the underlying numerical type to another + pub fn to_f64(self) -> Rectangle { + Rectangle { + loc: self.loc.to_f64(), + size: self.size.to_f64(), + } + } +} + +impl Rectangle { + /// Create a new [`Rectangle`] from the coordinates of its top-left corner and its dimensions + #[inline] + pub fn from_loc_and_size(loc: impl Into>, size: impl Into>) -> Self { + Rectangle { + loc: loc.into(), + size: size.into(), + } + } + + /// Create a new [`Rectangle`] from the coordinates of its top-left corner and its dimensions + #[inline] + pub fn from_extemities( + topleft: impl Into>, + bottomright: impl Into>, + ) -> Self { + let topleft = topleft.into(); + let bottomright = bottomright.into(); + Rectangle { + loc: topleft, + size: (bottomright - topleft).to_size(), + } + } + + /// Checks whether given [`Point`] is inside the rectangle + #[inline] + pub fn contains>>(self, point: P) -> bool { + let p: Point = point.into(); + (p.x >= self.loc.x) + && (p.x < self.loc.x + self.size.w) + && (p.y >= self.loc.y) + && (p.y < self.loc.y + self.size.h) + } + + /// Checks whether a given [`Rectangle`] overlaps with this one + #[inline] + pub fn overlaps(self, other: Rectangle) -> bool { + // if the rectangle is not outside of the other + // they must overlap + !( + // self is left of other + self.loc.x + self.size.w < other.loc.x + // self is right of other + || self.loc.x > other.loc.x + other.size.w + // self is above of other + || self.loc.y + self.size.h < other.loc.y + // self is below of other + || self.loc.y > other.loc.y + other.size.h + ) + } + + /// Compute the bounding box of a given set of points + pub fn bounding_box(points: impl IntoIterator>) -> Self { + let ret = points.into_iter().fold(None, |acc, point| { + match acc { + None => Some((point, point)), + // we don't have cmp::{min,max} for f64 :( + Some((min_point, max_point)) => Some(( + ( + if min_point.x > point.x { + point.x + } else { + min_point.x + }, + if min_point.y > point.y { + point.y + } else { + min_point.y + }, + ) + .into(), + ( + if max_point.x < point.x { + point.x + } else { + max_point.x + }, + if max_point.y < point.y { + point.y + } else { + max_point.y + }, + ) + .into(), + )), + } + }); + + match ret { + None => Rectangle::default(), + Some((min_point, max_point)) => Rectangle::from_extemities(min_point, max_point), + } + } + + /// Merge two [`Rectangle`] by producing the smallest rectangle that contains both + #[inline] + pub fn merge(self, other: Self) -> Self { + Self::bounding_box([self.loc, self.loc + self.size, other.loc, other.loc + other.size]) + } +} + +impl Rectangle { + /// Convert this logical rectangle to physical coordinate space according to given scale factor + #[inline] + pub fn to_physical(self, scale: N) -> Rectangle { + Rectangle { + loc: self.loc.to_physical(scale), + size: self.size.to_physical(scale), + } + } + + /// Convert this logical rectangle to buffer coordinate space according to given scale factor + #[inline] + pub fn to_buffer(self, scale: N) -> Rectangle { + Rectangle { + loc: self.loc.to_buffer(scale), + size: self.size.to_buffer(scale), + } + } +} + +impl Rectangle { + /// Convert this physical rectangle to logical coordinate space according to given scale factor + #[inline] + pub fn to_logical(self, scale: N) -> Rectangle { + Rectangle { + loc: self.loc.to_logical(scale), + size: self.size.to_logical(scale), + } + } +} + +impl Rectangle { + /// Convert this physical rectangle to logical coordinate space according to given scale factor + #[inline] + pub fn to_logical(self, scale: N) -> Rectangle { + Rectangle { + loc: self.loc.to_logical(scale), + size: self.size.to_logical(scale), + } + } +} + +impl fmt::Debug for Rectangle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Rectangle") + .field("x", &self.loc.x) + .field("y", &self.loc.y) + .field("width", &self.size.w) + .field("height", &self.size.h) + .finish() + } +} + +impl fmt::Debug for Rectangle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Rectangle") + .field("x", &self.loc.x) + .field("y", &self.loc.y) + .field("width", &self.size.w) + .field("height", &self.size.h) + .finish() + } +} + +impl fmt::Debug for Rectangle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Rectangle") + .field("x", &self.loc.x) + .field("y", &self.loc.y) + .field("width", &self.size.w) + .field("height", &self.size.h) + .finish() + } +} + +impl fmt::Debug for Rectangle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Rectangle") + .field("x", &self.loc.x) + .field("y", &self.loc.y) + .field("width", &self.size.w) + .field("height", &self.size.h) + .finish() + } +} + +impl Clone for Rectangle { + #[inline] + fn clone(&self) -> Self { + Rectangle { + loc: self.loc.clone(), + size: self.size.clone(), + } + } +} + +impl Copy for Rectangle {} + +impl PartialEq for Rectangle { + fn eq(&self, other: &Self) -> bool { + self.loc == other.loc && self.size == other.size + } +} + +impl Eq for Rectangle {} + +impl Default for Rectangle { + fn default() -> Self { + Rectangle { + loc: Default::default(), + size: Default::default(), + } + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 01276ff..1d09421 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,9 +1,9 @@ //! Various utilities functions and types -mod rectangle; +mod geometry; pub mod signaling; -pub use self::rectangle::Rectangle; +pub use self::geometry::{Buffer, Logical, Physical, Point, Raw, Rectangle, Size}; /// This resource is not managed by Smithay #[derive(Debug)] diff --git a/src/utils/rectangle.rs b/src/utils/rectangle.rs deleted file mode 100644 index 6ae2c7e..0000000 --- a/src/utils/rectangle.rs +++ /dev/null @@ -1,46 +0,0 @@ -/// A rectangle defined by its top-left corner and dimensions -#[derive(Copy, Clone, Debug, Default, PartialEq)] -pub struct Rectangle { - /// horizontal position of the top-left corner of the rectangle, in surface coordinates - pub x: i32, - /// vertical position of the top-left corner of the rectangle, in surface coordinates - pub y: i32, - /// width of the rectangle - pub width: i32, - /// height of the rectangle - pub height: i32, -} - -impl Rectangle { - /// Checks whether given point is inside a rectangle - pub fn contains(self, point: (i32, i32)) -> bool { - let (x, y) = point; - (x >= self.x) && (x < self.x + self.width) && (y >= self.y) && (y < self.y + self.height) - } - - /// Checks whether a given rectangle overlaps with this one - pub fn overlaps(self, other: &Rectangle) -> bool { - // if the rectangle is not outside of the other - // they must overlap - !( - // self is left of other - self.x + self.width < other.x - // self is right of other - || self.x > other.x + other.width - // self is above of other - || self.y + self.height < other.y - // self is below of other - || self.y > other.y + other.height - ) - } - - /// Scales the dimensions of this rectangle by given factor - pub fn scale(self, factor: i32) -> Rectangle { - Rectangle { - x: self.x * factor, - y: self.y * factor, - width: self.width * factor, - height: self.height * factor, - } - } -} diff --git a/src/wayland/compositor/handlers.rs b/src/wayland/compositor/handlers.rs index f0ba2e6..8118a67 100644 --- a/src/wayland/compositor/handlers.rs +++ b/src/wayland/compositor/handlers.rs @@ -13,6 +13,8 @@ use wayland_server::{ DispatchData, Filter, Main, }; +use crate::utils::{Logical, Point}; + use super::{ cache::Cacheable, tree::{Location, PrivateSurfaceData}, @@ -81,7 +83,7 @@ impl SurfaceImplem { states.cached_state.pending::().buffer = Some(match buffer { Some(buffer) => BufferAssignment::NewBuffer { buffer, - delta: (x, y), + delta: (x, y).into(), }, None => BufferAssignment::Removed, }) @@ -93,7 +95,10 @@ impl SurfaceImplem { .cached_state .pending::() .damage - .push(Damage::Surface(Rectangle { x, y, width, height })); + .push(Damage::Surface(Rectangle::from_loc_and_size( + (x, y), + (width, height), + ))); }); } wl_surface::Request::Frame { callback } => { @@ -153,7 +158,10 @@ impl SurfaceImplem { .cached_state .pending::() .damage - .push(Damage::Buffer(Rectangle { x, y, width, height })) + .push(Damage::Buffer(Rectangle::from_loc_and_size( + (x, y), + (width, height), + ))) }); } wl_surface::Request::Destroy => { @@ -226,12 +234,14 @@ fn region_implem(request: wl_region::Request, region: wl_region::WlRegion) { .unwrap(); let mut guard = attributes_mutex.lock().unwrap(); match request { - wl_region::Request::Add { x, y, width, height } => guard - .rects - .push((RectangleKind::Add, Rectangle { x, y, width, height })), - wl_region::Request::Subtract { x, y, width, height } => guard - .rects - .push((RectangleKind::Subtract, Rectangle { x, y, width, height })), + wl_region::Request::Add { x, y, width, height } => guard.rects.push(( + RectangleKind::Add, + Rectangle::from_loc_and_size((x, y), (width, height)), + )), + wl_region::Request::Subtract { x, y, width, height } => guard.rects.push(( + RectangleKind::Subtract, + Rectangle::from_loc_and_size((x, y), (width, height)), + )), wl_region::Request::Destroy => { // all is handled by our destructor } @@ -281,12 +291,14 @@ pub(crate) fn implement_subcompositor( pub struct SubsurfaceCachedState { /// Location of the top-left corner of this subsurface /// relative to its parent coordinate space - pub location: (i32, i32), + pub location: Point, } impl Default for SubsurfaceCachedState { fn default() -> Self { - SubsurfaceCachedState { location: (0, 0) } + SubsurfaceCachedState { + location: (0, 0).into(), + } } } @@ -342,7 +354,7 @@ fn implement_subsurface( match request { wl_subsurface::Request::SetPosition { x, y } => { PrivateSurfaceData::with_states(&surface, |state| { - state.cached_state.pending::().location = (x, y); + state.cached_state.pending::().location = (x, y).into(); }) } wl_subsurface::Request::PlaceAbove { sibling } => { diff --git a/src/wayland/compositor/mod.rs b/src/wayland/compositor/mod.rs index 35d6840..658576d 100644 --- a/src/wayland/compositor/mod.rs +++ b/src/wayland/compositor/mod.rs @@ -93,7 +93,7 @@ pub use self::cache::{Cacheable, MultiCache}; pub use self::handlers::SubsurfaceCachedState; use self::tree::PrivateSurfaceData; pub use self::tree::{AlreadyHasRole, TraversalAction}; -use crate::utils::{DeadResource, Rectangle}; +use crate::utils::{Buffer, DeadResource, Logical, Point, Rectangle}; use wayland_server::{ protocol::{ wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor, wl_surface::WlSurface, @@ -106,11 +106,11 @@ use wayland_server::{ #[derive(Debug)] pub enum Damage { /// A rectangle containing the damaged zone, in surface coordinates - Surface(Rectangle), + Surface(Rectangle), /// A rectangle containing the damaged zone, in buffer coordinates /// /// Note: Buffer scaling must be taken into consideration - Buffer(Rectangle), + Buffer(Rectangle), } #[derive(Debug, Copy, Clone, Default)] @@ -155,7 +155,7 @@ pub enum BufferAssignment { /// The buffer object buffer: wl_buffer::WlBuffer, /// location of the new buffer relative to the previous one - delta: (i32, i32), + delta: Point, }, } @@ -227,29 +227,6 @@ impl Default for SurfaceAttributes { } } -/// Attributes defining the behaviour of a sub-surface relative to its parent -#[derive(Copy, Clone, Debug)] -pub struct SubsurfaceRole { - /// Location of the top-left corner of this sub-surface relative to - /// the top-left corner of its parent - pub location: (i32, i32), - /// Sync status of this sub-surface - /// - /// If `true`, this surface should be repainted synchronously with its parent - /// if `false`, it should be considered independent of its parent regarding - /// repaint timings. - pub sync: bool, -} - -impl Default for SubsurfaceRole { - fn default() -> SubsurfaceRole { - SubsurfaceRole { - location: (0, 0), - sync: true, - } - } -} - /// Kind of a rectangle part of a region #[derive(Copy, Clone, Debug)] pub enum RectangleKind { @@ -270,7 +247,7 @@ pub enum RectangleKind { #[derive(Clone, Debug)] pub struct RegionAttributes { /// List of rectangle part of this region - pub rects: Vec<(RectangleKind, Rectangle)>, + pub rects: Vec<(RectangleKind, Rectangle)>, } impl Default for RegionAttributes { @@ -281,7 +258,8 @@ impl Default for RegionAttributes { impl RegionAttributes { /// Checks whether given point is inside the region. - pub fn contains(&self, point: (i32, i32)) -> bool { + pub fn contains>>(&self, point: P) -> bool { + let point: Point = point.into(); let mut contains = false; for (kind, rect) in &self.rects { if rect.contains(point) { @@ -483,15 +461,7 @@ mod tests { #[test] fn region_attributes_add() { let region = RegionAttributes { - rects: vec![( - RectangleKind::Add, - Rectangle { - x: 0, - y: 0, - width: 10, - height: 10, - }, - )], + rects: vec![(RectangleKind::Add, Rectangle::from_loc_and_size((0, 0), (10, 10)))], }; assert_eq!(region.contains((0, 0)), true); @@ -501,23 +471,10 @@ mod tests { fn region_attributes_add_subtract() { let region = RegionAttributes { rects: vec![ - ( - RectangleKind::Add, - Rectangle { - x: 0, - y: 0, - width: 10, - height: 10, - }, - ), + (RectangleKind::Add, Rectangle::from_loc_and_size((0, 0), (10, 10))), ( RectangleKind::Subtract, - Rectangle { - x: 0, - y: 0, - width: 5, - height: 5, - }, + Rectangle::from_loc_and_size((0, 0), (5, 5)), ), ], }; @@ -530,33 +487,12 @@ mod tests { fn region_attributes_add_subtract_add() { let region = RegionAttributes { rects: vec![ - ( - RectangleKind::Add, - Rectangle { - x: 0, - y: 0, - width: 10, - height: 10, - }, - ), + (RectangleKind::Add, Rectangle::from_loc_and_size((0, 0), (10, 10))), ( RectangleKind::Subtract, - Rectangle { - x: 0, - y: 0, - width: 5, - height: 5, - }, - ), - ( - RectangleKind::Add, - Rectangle { - x: 2, - y: 2, - width: 2, - height: 2, - }, + Rectangle::from_loc_and_size((0, 0), (5, 5)), ), + (RectangleKind::Add, Rectangle::from_loc_and_size((2, 2), (2, 2))), ], }; diff --git a/src/wayland/data_device/dnd_grab.rs b/src/wayland/data_device/dnd_grab.rs index 26c5de8..c46e822 100644 --- a/src/wayland/data_device/dnd_grab.rs +++ b/src/wayland/data_device/dnd_grab.rs @@ -5,9 +5,12 @@ use wayland_server::{ Main, }; -use crate::wayland::{ - seat::{AxisFrame, GrabStartData, PointerGrab, PointerInnerHandle, Seat}, - Serial, +use crate::{ + utils::{Logical, Point}, + wayland::{ + seat::{AxisFrame, GrabStartData, PointerGrab, PointerInnerHandle, Seat}, + Serial, + }, }; use super::{with_source_metadata, DataDeviceData, SeatData}; @@ -51,12 +54,11 @@ impl PointerGrab for DnDGrab { fn motion( &mut self, _handle: &mut PointerInnerHandle<'_>, - location: (f64, f64), - focus: Option<(wl_surface::WlSurface, (f64, f64))>, + location: Point, + focus: Option<(wl_surface::WlSurface, Point)>, serial: Serial, time: u32, ) { - let (x, y) = location; let seat_data = self .seat .user_data() @@ -81,12 +83,13 @@ impl PointerGrab for DnDGrab { } } } - if let Some((surface, (sx, sy))) = focus { + if let Some((surface, surface_location)) = focus { // early return if the surface is no longer valid let client = match surface.as_ref().client() { Some(c) => c, None => return, }; + let (x, y) = (location - surface_location.to_f64()).into(); if self.current_focus.is_none() { // We entered a new surface, send the data offer if appropriate if let Some(ref source) = self.data_source { @@ -129,7 +132,7 @@ impl PointerGrab for DnDGrab { offer.source_actions(meta.dnd_action); }) .unwrap(); - device.enter(serial.into(), &surface, x - sx, y - sy, Some(&offer)); + device.enter(serial.into(), &surface, x, y, Some(&offer)); self.pending_offers.push(offer); } self.offer_data = Some(offer_data); @@ -138,7 +141,7 @@ impl PointerGrab for DnDGrab { if self.origin.as_ref().same_client_as(&surface.as_ref()) { for device in &seat_data.known_devices { if device.as_ref().same_client_as(&surface.as_ref()) { - device.enter(serial.into(), &surface, x - sx, y - sy, None); + device.enter(serial.into(), &surface, x, y, None); } } } @@ -149,7 +152,7 @@ impl PointerGrab for DnDGrab { if self.data_source.is_some() || self.origin.as_ref().same_client_as(&surface.as_ref()) { for device in &seat_data.known_devices { if device.as_ref().same_client_as(&surface.as_ref()) { - device.motion(time, x - sx, y - sy); + device.motion(time, x, y); } } } diff --git a/src/wayland/data_device/server_dnd_grab.rs b/src/wayland/data_device/server_dnd_grab.rs index 22af98f..d81709e 100644 --- a/src/wayland/data_device/server_dnd_grab.rs +++ b/src/wayland/data_device/server_dnd_grab.rs @@ -5,8 +5,13 @@ use wayland_server::{ Main, }; -use crate::wayland::seat::{AxisFrame, GrabStartData, PointerGrab, PointerInnerHandle, Seat}; -use crate::wayland::Serial; +use crate::{ + utils::{Logical, Point}, + wayland::{ + seat::{AxisFrame, GrabStartData, PointerGrab, PointerInnerHandle, Seat}, + Serial, + }, +}; use super::{DataDeviceData, SeatData}; @@ -72,12 +77,11 @@ where fn motion( &mut self, _handle: &mut PointerInnerHandle<'_>, - location: (f64, f64), - focus: Option<(wl_surface::WlSurface, (f64, f64))>, + location: Point, + focus: Option<(wl_surface::WlSurface, Point)>, serial: Serial, time: u32, ) { - let (x, y) = location; let seat_data = self .seat .user_data() @@ -99,12 +103,13 @@ where } } } - if let Some((surface, (sx, sy))) = focus { + if let Some((surface, surface_location)) = focus { // early return if the surface is no longer valid let client = match surface.as_ref().client() { Some(c) => c, None => return, }; + let (x, y) = (location - surface_location.to_f64()).into(); if self.current_focus.is_none() { // We entered a new surface, send the data offer let offer_data = Rc::new(RefCell::new(OfferData { @@ -144,7 +149,7 @@ where offer.offer(mime_type); } offer.source_actions(self.metadata.dnd_action); - device.enter(serial.into(), &surface, x - sx, y - sy, Some(&offer)); + device.enter(serial.into(), &surface, x, y, Some(&offer)); self.pending_offers.push(offer); } self.offer_data = Some(offer_data); @@ -153,7 +158,7 @@ where // make a move for device in &seat_data.known_devices { if device.as_ref().same_client_as(&surface.as_ref()) { - device.motion(time, x - sx, y - sy); + device.motion(time, x, y); } } } diff --git a/src/wayland/output/mod.rs b/src/wayland/output/mod.rs index 676b5bc..bbb313e 100644 --- a/src/wayland/output/mod.rs +++ b/src/wayland/output/mod.rs @@ -27,8 +27,7 @@ //! &mut display, // the display //! "output-0".into(), // the name of this output, //! PhysicalProperties { -//! width: 200, // width in mm -//! height: 150, // height in mm, +//! size: (200, 150).into(), // dimensions (width, height) in mm //! subpixel: wl_output::Subpixel::HorizontalRgb, // subpixel information //! make: "Screens Inc".into(), // make of the monitor //! model: "Monitor Ultra".into(), // model of the monitor @@ -37,15 +36,15 @@ //! ); //! // Now you can configure it //! output.change_current_state( -//! Some(Mode { width: 1902, height: 1080, refresh: 60000 }), // the resolution mode, +//! Some(Mode { size: (1920, 1080).into(), refresh: 60000 }), // the resolution mode, //! Some(wl_output::Transform::Normal), // global screen transformation //! Some(1), // global screen scaling factor //! ); //! // set the preferred mode -//! output.set_preferred(Mode { width: 1920, height: 1080, refresh: 60000 }); +//! output.set_preferred(Mode { size: (1920, 1080).into(), refresh: 60000 }); //! // add other supported modes -//! output.add_mode(Mode { width: 800, height: 600, refresh: 60000 }); -//! output.add_mode(Mode { width: 1024, height: 768, refresh: 60000 }); +//! output.add_mode(Mode { size: (800, 600).into(), refresh: 60000 }); +//! output.add_mode(Mode { size: (1024, 768).into(), refresh: 60000 }); //! ``` use std::{ @@ -64,6 +63,8 @@ use wayland_server::{ use slog::{info, o, trace, warn}; +use crate::utils::{Logical, Physical, Point, Raw, Size}; + /// An output mode /// /// A possible combination of dimensions and refresh rate for an output. @@ -72,10 +73,8 @@ use slog::{info, o, trace, warn}; /// not taking into account any global scaling. #[derive(Debug, Copy, Clone, PartialEq)] pub struct Mode { - /// The width in pixels - pub width: i32, - /// The height in pixels - pub height: i32, + /// The size of the mode, in pixels + pub size: Size, /// The refresh rate in millihertz /// /// `1000` is one fps (frame per second), `2000` is 2 fps, etc... @@ -85,10 +84,8 @@ pub struct Mode { /// The physical properties of an output #[derive(Debug)] pub struct PhysicalProperties { - /// The width in millimeters - pub width: i32, - /// The height in millimeters - pub height: i32, + /// The size of the monitor, in millimeters + pub size: Size, /// The subpixel geometry pub subpixel: Subpixel, /// Textual representation of the make @@ -103,7 +100,7 @@ struct Inner { log: ::slog::Logger, instances: Vec, physical: PhysicalProperties, - location: (i32, i32), + location: Point, transform: Transform, scale: i32, modes: Vec, @@ -134,7 +131,7 @@ impl Inner { if Some(mode) == self.preferred_mode { flags |= WMode::Preferred; } - output.mode(flags, mode.width, mode.height, mode.refresh); + output.mode(flags, mode.size.w, mode.size.h, mode.refresh); } if output.as_ref().version() >= 2 { output.scale(self.scale); @@ -146,10 +143,10 @@ impl Inner { fn send_geometry(&self, output: &WlOutput) { output.geometry( - self.location.0, - self.location.1, - self.physical.width, - self.physical.height, + self.location.x, + self.location.y, + self.physical.size.w, + self.physical.size.h, self.physical.subpixel, self.physical.make.clone(), self.physical.model.clone(), @@ -191,7 +188,7 @@ impl Output { log, instances: Vec::new(), physical, - location: (0, 0), + location: (0, 0).into(), transform: Transform::Normal, scale: 1, modes: Vec::new(), @@ -292,7 +289,7 @@ impl Output { } for output in &inner.instances { if let Some(mode) = new_mode { - output.mode(flags, mode.width, mode.height, mode.refresh); + output.mode(flags, mode.size.w, mode.size.h, mode.refresh); } if new_transform.is_some() { inner.send_geometry(output); diff --git a/src/wayland/seat/pointer.rs b/src/wayland/seat/pointer.rs index 3e13159..89e19c0 100644 --- a/src/wayland/seat/pointer.rs +++ b/src/wayland/seat/pointer.rs @@ -8,8 +8,10 @@ use wayland_server::{ Filter, Main, }; -use crate::wayland::compositor; -use crate::wayland::Serial; +use crate::{ + utils::{Logical, Point}, + wayland::{compositor, Serial}, +}; static CURSOR_IMAGE_ROLE: &str = "cursor_image"; @@ -17,7 +19,7 @@ static CURSOR_IMAGE_ROLE: &str = "cursor_image"; #[derive(Debug, Default, Copy, Clone)] pub struct CursorImageAttributes { /// Location of the hotspot of the pointer in the surface - pub hotspot: (i32, i32), + pub hotspot: Point, } /// Possible status of a cursor as requested by clients @@ -50,9 +52,9 @@ impl fmt::Debug for GrabStatus { struct PointerInternal { known_pointers: Vec, - focus: Option<(WlSurface, (f64, f64))>, - pending_focus: Option<(WlSurface, (f64, f64))>, - location: (f64, f64), + focus: Option<(WlSurface, Point)>, + pending_focus: Option<(WlSurface, Point)>, + location: Point, grab: GrabStatus, pressed_buttons: Vec, image_callback: Box, @@ -82,7 +84,7 @@ impl PointerInternal { known_pointers: Vec::new(), focus: None, pending_focus: None, - location: (0.0, 0.0), + location: (0.0, 0.0).into(), grab: GrabStatus::None, pressed_buttons: Vec::new(), image_callback: Box::new(cb) as Box<_>, @@ -201,8 +203,8 @@ impl PointerHandle { /// of enter/motion/leave events. pub fn motion( &self, - location: (f64, f64), - focus: Option<(WlSurface, (f64, f64))>, + location: Point, + focus: Option<(WlSurface, Point)>, serial: Serial, time: u32, ) { @@ -243,7 +245,7 @@ impl PointerHandle { } /// Access the current location of this pointer in the global space - pub fn current_location(&self) -> (f64, f64) { + pub fn current_location(&self) -> Point { self.inner.borrow().location } } @@ -254,11 +256,11 @@ pub struct GrabStartData { /// The focused surface and its location, if any, at the start of the grab. /// /// The location coordinates are in the global compositor space. - pub focus: Option<(WlSurface, (f64, f64))>, + pub focus: Option<(WlSurface, Point)>, /// The button that initiated the grab. pub button: u32, /// The location of the click that initiated the grab, in the global compositor space. - pub location: (f64, f64), + pub location: Point, } /// A trait to implement a pointer grab @@ -281,8 +283,8 @@ pub trait PointerGrab { fn motion( &mut self, handle: &mut PointerInnerHandle<'_>, - location: (f64, f64), - focus: Option<(WlSurface, (f64, f64))>, + location: Point, + focus: Option<(WlSurface, Point)>, serial: Serial, time: u32, ); @@ -328,12 +330,12 @@ impl<'a> PointerInnerHandle<'a> { } /// Access the current focus of this pointer - pub fn current_focus(&self) -> Option<&(WlSurface, (f64, f64))> { + pub fn current_focus(&self) -> Option<&(WlSurface, Point)> { self.inner.focus.as_ref() } /// Access the current location of this pointer in the global space - pub fn current_location(&self) -> (f64, f64) { + pub fn current_location(&self) -> Point { self.inner.location } @@ -358,14 +360,14 @@ impl<'a> PointerInnerHandle<'a> { /// of enter/motion/leave events. pub fn motion( &mut self, - (x, y): (f64, f64), - focus: Option<(WlSurface, (f64, f64))>, + location: Point, + focus: Option<(WlSurface, Point)>, serial: Serial, time: u32, ) { // do we leave a surface ? let mut leave = true; - self.inner.location = (x, y); + self.inner.location = location; if let Some((ref current_focus, _)) = self.inner.focus { if let Some((ref surface, _)) = focus { if current_focus.as_ref().equals(surface.as_ref()) { @@ -385,14 +387,15 @@ impl<'a> PointerInnerHandle<'a> { } // do we enter one ? - if let Some((surface, (sx, sy))) = focus { + if let Some((surface, surface_location)) = focus { let entered = self.inner.focus.is_none(); // in all cases, update the focus, the coordinates of the surface // might have changed - self.inner.focus = Some((surface, (sx, sy))); + self.inner.focus = Some((surface, surface_location)); + let (x, y) = (location - surface_location.to_f64()).into(); if entered { self.inner.with_focused_pointers(|pointer, surface| { - pointer.enter(serial.into(), &surface, x - sx, y - sy); + pointer.enter(serial.into(), &surface, x, y); if pointer.as_ref().version() >= 5 { pointer.frame(); } @@ -400,7 +403,7 @@ impl<'a> PointerInnerHandle<'a> { } else { // we were on top of a surface and remained on it self.inner.with_focused_pointers(|pointer, _| { - pointer.motion(time, x - sx, y - sy); + pointer.motion(time, x, y); if pointer.as_ref().version() >= 5 { pointer.frame(); } @@ -600,7 +603,9 @@ pub(crate) fn implement_pointer(pointer: Main, handle: Option<&Pointe } compositor::with_states(&surface, |states| { states.data_map.insert_if_missing_threadsafe(|| { - Mutex::new(CursorImageAttributes { hotspot: (0, 0) }) + Mutex::new(CursorImageAttributes { + hotspot: (0, 0).into(), + }) }); states .data_map @@ -608,7 +613,7 @@ pub(crate) fn implement_pointer(pointer: Main, handle: Option<&Pointe .unwrap() .lock() .unwrap() - .hotspot = (hotspot_x, hotspot_y); + .hotspot = (hotspot_x, hotspot_y).into(); }) .unwrap(); @@ -653,8 +658,8 @@ impl PointerGrab for DefaultGrab { fn motion( &mut self, handle: &mut PointerInnerHandle<'_>, - location: (f64, f64), - focus: Option<(WlSurface, (f64, f64))>, + location: Point, + focus: Option<(WlSurface, Point)>, serial: Serial, time: u32, ) { @@ -701,8 +706,8 @@ impl PointerGrab for ClickGrab { fn motion( &mut self, handle: &mut PointerInnerHandle<'_>, - location: (f64, f64), - _focus: Option<(WlSurface, (f64, f64))>, + location: Point, + _focus: Option<(WlSurface, Point)>, serial: Serial, time: u32, ) { diff --git a/src/wayland/shell/legacy/mod.rs b/src/wayland/shell/legacy/mod.rs index a87f04f..8385704 100644 --- a/src/wayland/shell/legacy/mod.rs +++ b/src/wayland/shell/legacy/mod.rs @@ -49,7 +49,10 @@ use std::{ sync::{Arc, Mutex}, }; -use crate::wayland::{compositor, Serial}; +use crate::{ + utils::{Logical, Point, Size}, + wayland::{compositor, Serial}, +}; use wayland_server::{ protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface}, @@ -132,8 +135,8 @@ impl ShellSurface { } /// Send a configure event to this toplevel surface to suggest it a new configuration - pub fn send_configure(&self, size: (u32, u32), edges: wl_shell_surface::Resize) { - self.shell_surface.configure(edges, size.0 as i32, size.1 as i32) + pub fn send_configure(&self, size: Size, edges: wl_shell_surface::Resize) { + self.shell_surface.configure(edges, size.w, size.h) } /// Signal a popup surface that it has lost focus @@ -155,7 +158,7 @@ pub enum ShellSurfaceKind { /// The surface considered as parent parent: wl_surface::WlSurface, /// Location relative to the parent - location: (i32, i32), + location: Point, /// Wether this window should be marked as inactive inactive: bool, }, @@ -181,7 +184,7 @@ pub enum ShellSurfaceKind { /// Wether this popup should be marked as inactive inactive: bool, /// Location of the popup relative to its parent - location: (i32, i32), + location: Point, /// Seat associated this the input that triggered the creation of the /// popup. Used to define when the "popup done" event is sent. seat: wl_seat::WlSeat, diff --git a/src/wayland/shell/legacy/wl_handlers.rs b/src/wayland/shell/legacy/wl_handlers.rs index b5a568e..0d96226 100644 --- a/src/wayland/shell/legacy/wl_handlers.rs +++ b/src/wayland/shell/legacy/wl_handlers.rs @@ -157,7 +157,7 @@ where surface: make_handle(&shell_surface), kind: ShellSurfaceKind::Transient { parent, - location: (x, y), + location: (x, y).into(), inactive: flags.contains(wl_shell_surface::Transient::Inactive), }, }, @@ -194,7 +194,7 @@ where parent, serial, seat, - location: (x, y), + location: (x, y).into(), inactive: flags.contains(wl_shell_surface::Transient::Inactive), }, }, diff --git a/src/wayland/shell/xdg/mod.rs b/src/wayland/shell/xdg/mod.rs index 5a1fae2..657172a 100644 --- a/src/wayland/shell/xdg/mod.rs +++ b/src/wayland/shell/xdg/mod.rs @@ -62,7 +62,7 @@ //! that you are given (in an `Arc>`) as return value of the `init` function. use crate::utils::DeadResource; -use crate::utils::Rectangle; +use crate::utils::{Logical, Point, Rectangle, Size}; use crate::wayland::compositor; use crate::wayland::compositor::Cacheable; use crate::wayland::{Serial, SERIAL_COUNTER}; @@ -220,11 +220,11 @@ xdg_role!( /// Minimum size requested for this surface /// /// A value of 0 on an axis means this axis is not constrained - pub min_size: (i32, i32), + pub min_size: Size, /// Maximum size requested for this surface /// /// A value of 0 on an axis means this axis is not constrained - pub max_size: (i32, i32), + pub max_size: Size, /// Holds the pending state as set by the server. pub server_pending: Option, /// Holds the last server_pending state that has been acknowledged @@ -315,7 +315,7 @@ pub struct PopupState { /// `Rectangle::x` and `Rectangle::y` holds the position of the popup /// The position is relative to the window geometry as defined by /// xdg_surface.set_window_geometry of the parent surface. - pub geometry: Rectangle, + pub geometry: Rectangle, } impl Default for PopupState { @@ -330,10 +330,10 @@ impl Default for PopupState { /// The state of a positioner, as set by the client pub struct PositionerState { /// Size of the rectangle that needs to be positioned - pub rect_size: (i32, i32), + pub rect_size: Size, /// Anchor rectangle in the parent surface coordinates /// relative to which the surface must be positioned - pub anchor_rect: Rectangle, + pub anchor_rect: Rectangle, /// Edges defining the anchor point pub anchor_edges: xdg_positioner::Anchor, /// Gravity direction for positioning the child surface @@ -343,7 +343,7 @@ pub struct PositionerState { /// surface pub constraint_adjustment: xdg_positioner::ConstraintAdjustment, /// Offset placement relative to the anchor point - pub offset: (i32, i32), + pub offset: Point, } impl Default for PositionerState { @@ -353,29 +353,13 @@ impl Default for PositionerState { anchor_rect: Default::default(), constraint_adjustment: xdg_positioner::ConstraintAdjustment::empty(), gravity: xdg_positioner::Gravity::None, - offset: (0, 0), - rect_size: (0, 0), + offset: Default::default(), + rect_size: Default::default(), } } } impl PositionerState { - pub(crate) fn new() -> PositionerState { - PositionerState { - rect_size: (0, 0), - anchor_rect: Rectangle { - x: 0, - y: 0, - width: 0, - height: 0, - }, - anchor_edges: xdg_positioner::Anchor::None, - gravity: xdg_positioner::Gravity::None, - constraint_adjustment: xdg_positioner::ConstraintAdjustment::None, - offset: (0, 0), - } - } - pub(crate) fn anchor_has_edge(&self, edge: xdg_positioner::Anchor) -> bool { match edge { xdg_positioner::Anchor::Top => { @@ -440,7 +424,7 @@ impl PositionerState { /// The `constraint_adjustment` will not be considered by this /// implementation and the position and size should be re-calculated /// in the compositor if the compositor implements `constraint_adjustment` - pub(crate) fn get_geometry(&self) -> Rectangle { + pub(crate) fn get_geometry(&self) -> Rectangle { // From the `xdg_shell` prococol specification: // // set_offset: @@ -451,10 +435,8 @@ impl PositionerState { // has the gravity bottom|right, and the offset is (ox, oy), the calculated // surface position will be (x + ox, y + oy) let mut geometry = Rectangle { - x: self.offset.0, - y: self.offset.1, - width: self.rect_size.0, - height: self.rect_size.1, + loc: self.offset, + size: self.rect_size, }; // Defines the anchor point for the anchor rectangle. The specified anchor @@ -464,19 +446,19 @@ impl PositionerState { // otherwise, the derived anchor point will be centered on the specified // edge, or in the center of the anchor rectangle if no edge is specified. if self.anchor_has_edge(xdg_positioner::Anchor::Top) { - geometry.y += self.anchor_rect.y; + geometry.loc.y += self.anchor_rect.loc.y; } else if self.anchor_has_edge(xdg_positioner::Anchor::Bottom) { - geometry.y += self.anchor_rect.y + self.anchor_rect.height; + geometry.loc.y += self.anchor_rect.loc.y + self.anchor_rect.size.h; } else { - geometry.y += self.anchor_rect.y + self.anchor_rect.height / 2; + geometry.loc.y += self.anchor_rect.loc.y + self.anchor_rect.size.h / 2; } if self.anchor_has_edge(xdg_positioner::Anchor::Left) { - geometry.x += self.anchor_rect.x; + geometry.loc.x += self.anchor_rect.loc.x; } else if self.anchor_has_edge(xdg_positioner::Anchor::Right) { - geometry.x += self.anchor_rect.x + self.anchor_rect.width; + geometry.loc.x += self.anchor_rect.loc.x + self.anchor_rect.size.w; } else { - geometry.x += self.anchor_rect.x + self.anchor_rect.width / 2; + geometry.loc.x += self.anchor_rect.loc.x + self.anchor_rect.size.w / 2; } // Defines in what direction a surface should be positioned, relative to @@ -486,15 +468,15 @@ impl PositionerState { // surface will be centered over the anchor point on any axis that had no // gravity specified. if self.gravity_has_edge(xdg_positioner::Gravity::Top) { - geometry.y -= geometry.height; + geometry.loc.y -= geometry.size.h; } else if !self.gravity_has_edge(xdg_positioner::Gravity::Bottom) { - geometry.y -= geometry.height / 2; + geometry.loc.y -= geometry.size.h / 2; } if self.gravity_has_edge(xdg_positioner::Gravity::Left) { - geometry.x -= geometry.width; + geometry.loc.x -= geometry.size.w; } else if !self.gravity_has_edge(xdg_positioner::Gravity::Right) { - geometry.x -= geometry.width / 2; + geometry.loc.x -= geometry.size.w / 2; } geometry @@ -505,7 +487,7 @@ impl PositionerState { #[derive(Debug, PartialEq)] pub struct ToplevelState { /// The suggested size of the surface - pub size: Option<(i32, i32)>, + pub size: Option>, /// The states for this surface pub states: ToplevelStateSet, @@ -603,29 +585,29 @@ impl From for Vec { pub struct SurfaceCachedState { /// Holds the double-buffered geometry that may be specified /// by xdg_surface.set_window_geometry. - pub geometry: Option, + pub geometry: Option>, /// Minimum size requested for this surface /// /// A value of 0 on an axis means this axis is not constrained /// /// This is only relevant for xdg_toplevel, and will always be /// `(0, 0)` for xdg_popup. - pub min_size: (i32, i32), + pub min_size: Size, /// Maximum size requested for this surface /// /// A value of 0 on an axis means this axis is not constrained /// /// This is only relevant for xdg_toplevel, and will always be /// `(0, 0)` for xdg_popup. - pub max_size: (i32, i32), + pub max_size: Size, } impl Default for SurfaceCachedState { fn default() -> Self { Self { geometry: None, - min_size: (0, 0), - max_size: (0, 0), + min_size: Default::default(), + max_size: Default::default(), } } } @@ -1593,8 +1575,8 @@ pub enum XdgRequest { seat: wl_seat::WlSeat, /// the grab serial serial: Serial, - /// location of the menu request - location: (i32, i32), + /// location of the menu request relative to the surface geometry + location: Point, }, /// A surface has acknowledged a configure serial. AckConfigure { diff --git a/src/wayland/shell/xdg/xdg_handlers.rs b/src/wayland/shell/xdg/xdg_handlers.rs index 637e7f7..661fdb2 100644 --- a/src/wayland/shell/xdg/xdg_handlers.rs +++ b/src/wayland/shell/xdg/xdg_handlers.rs @@ -132,7 +132,7 @@ fn implement_positioner(positioner: Main) -> xdg_ "Invalid size for positioner.".into(), ); } else { - state.rect_size = (width, height); + state.rect_size = (width, height).into(); } } xdg_positioner::Request::SetAnchorRect { x, y, width, height } => { @@ -142,7 +142,7 @@ fn implement_positioner(positioner: Main) -> xdg_ "Invalid size for positioner's anchor rectangle.".into(), ); } else { - state.anchor_rect = Rectangle { x, y, width, height }; + state.anchor_rect = Rectangle::from_loc_and_size((x, y), (width, height)); } } xdg_positioner::Request::SetAnchor { anchor } => { @@ -159,7 +159,7 @@ fn implement_positioner(positioner: Main) -> xdg_ state.constraint_adjustment = constraint_adjustment; } xdg_positioner::Request::SetOffset { x, y } => { - state.offset = (x, y); + state.offset = (x, y).into(); } _ => unreachable!(), } @@ -167,7 +167,7 @@ fn implement_positioner(positioner: Main) -> xdg_ positioner .as_ref() .user_data() - .set(|| RefCell::new(PositionerState::new())); + .set(|| RefCell::new(PositionerState::default())); positioner.deref().clone() } @@ -363,7 +363,7 @@ fn xdg_surface_implementation( compositor::with_states(surface, |states| { states.cached_state.pending::().geometry = - Some(Rectangle { x, y, width, height }); + Some(Rectangle::from_loc_and_size((x, y), (width, height))); }) .unwrap(); } @@ -501,7 +501,7 @@ pub fn send_toplevel_configure(resource: &xdg_toplevel::XdgToplevel, configure: .get::() .unwrap(); - let (width, height) = configure.state.size.unwrap_or((0, 0)); + let (width, height) = configure.state.size.unwrap_or_default().into(); // convert the Vec (which is really a Vec) into Vec let states = { let mut states: Vec = configure.state.states.into(); @@ -583,7 +583,7 @@ fn toplevel_implementation( surface: handle, seat, serial, - location: (x, y), + location: (x, y).into(), }, dispatch_data, ); @@ -619,12 +619,12 @@ fn toplevel_implementation( } xdg_toplevel::Request::SetMaxSize { width, height } => { with_toplevel_pending_state(&toplevel, |toplevel_data| { - toplevel_data.max_size = (width, height); + toplevel_data.max_size = (width, height).into(); }); } xdg_toplevel::Request::SetMinSize { width, height } => { with_toplevel_pending_state(&toplevel, |toplevel_data| { - toplevel_data.min_size = (width, height); + toplevel_data.min_size = (width, height).into(); }); } xdg_toplevel::Request::SetMaximized => { @@ -697,7 +697,7 @@ pub(crate) fn send_popup_configure(resource: &xdg_popup::XdgPopup, configure: Po let geometry = configure.state.geometry; // Send the popup configure - resource.configure(geometry.x, geometry.y, geometry.width, geometry.height); + resource.configure(geometry.loc.x, geometry.loc.y, geometry.size.w, geometry.size.h); // Send the base xdg_surface configure event to mark // the configure as finished diff --git a/src/wayland/shell/xdg/zxdgv6_handlers.rs b/src/wayland/shell/xdg/zxdgv6_handlers.rs index 4ec11e0..1728d9b 100644 --- a/src/wayland/shell/xdg/zxdgv6_handlers.rs +++ b/src/wayland/shell/xdg/zxdgv6_handlers.rs @@ -132,7 +132,7 @@ fn implement_positioner( "Invalid size for positioner.".into(), ); } else { - state.rect_size = (width, height); + state.rect_size = (width, height).into(); } } zxdg_positioner_v6::Request::SetAnchorRect { x, y, width, height } => { @@ -142,7 +142,7 @@ fn implement_positioner( "Invalid size for positioner's anchor rectangle.".into(), ); } else { - state.anchor_rect = Rectangle { x, y, width, height }; + state.anchor_rect = Rectangle::from_loc_and_size((x, y), (width, height)); } } zxdg_positioner_v6::Request::SetAnchor { anchor } => { @@ -173,7 +173,7 @@ fn implement_positioner( state.constraint_adjustment = zxdg_constraints_adg_to_xdg(constraint_adjustment); } zxdg_positioner_v6::Request::SetOffset { x, y } => { - state.offset = (x, y); + state.offset = (x, y).into(); } _ => unreachable!(), } @@ -181,7 +181,7 @@ fn implement_positioner( positioner .as_ref() .user_data() - .set(|| RefCell::new(PositionerState::new())); + .set(|| RefCell::new(PositionerState::default())); positioner.deref().clone() } @@ -377,7 +377,7 @@ fn xdg_surface_implementation( compositor::with_states(surface, |states| { states.cached_state.pending::().geometry = - Some(Rectangle { x, y, width, height }); + Some(Rectangle::from_loc_and_size((x, y), (width, height))); }) .unwrap(); } @@ -516,7 +516,7 @@ pub fn send_toplevel_configure(resource: &zxdg_toplevel_v6::ZxdgToplevelV6, conf .get::() .unwrap(); - let (width, height) = configure.state.size.unwrap_or((0, 0)); + let (width, height) = configure.state.size.unwrap_or_default().into(); // convert the Vec (which is really a Vec) into Vec let states = { let mut states: Vec = configure.state.states.into(); @@ -595,7 +595,7 @@ fn toplevel_implementation( surface: handle, seat, serial, - location: (x, y), + location: (x, y).into(), }, dispatch_data, ); @@ -631,12 +631,12 @@ fn toplevel_implementation( } zxdg_toplevel_v6::Request::SetMaxSize { width, height } => { with_toplevel_pending_state(&toplevel, |toplevel_data| { - toplevel_data.max_size = (width, height); + toplevel_data.max_size = (width, height).into(); }); } zxdg_toplevel_v6::Request::SetMinSize { width, height } => { with_toplevel_pending_state(&toplevel, |toplevel_data| { - toplevel_data.min_size = (width, height); + toplevel_data.min_size = (width, height).into(); }); } zxdg_toplevel_v6::Request::SetMaximized => { @@ -709,7 +709,7 @@ pub(crate) fn send_popup_configure(resource: &zxdg_popup_v6::ZxdgPopupV6, config let geometry = configure.state.geometry; // Send the popup configure - resource.configure(geometry.x, geometry.y, geometry.width, geometry.height); + resource.configure(geometry.loc.x, geometry.loc.y, geometry.size.w, geometry.size.h); // Send the base xdg_surface configure event to mark // the configure as finished diff --git a/src/wayland/tablet_manager/tablet_tool.rs b/src/wayland/tablet_manager/tablet_tool.rs index 19cb770..46bd6a8 100644 --- a/src/wayland/tablet_manager/tablet_tool.rs +++ b/src/wayland/tablet_manager/tablet_tool.rs @@ -3,6 +3,7 @@ use std::sync::Mutex; use std::{cell::RefCell, rc::Rc}; use crate::backend::input::{ButtonState, TabletToolCapabilitys, TabletToolDescriptor, TabletToolType}; +use crate::utils::{Logical, Point}; use crate::wayland::seat::{CursorImageAttributes, CursorImageStatus}; use wayland_protocols::unstable::tablet::v2::server::{ zwp_tablet_seat_v2::ZwpTabletSeatV2, @@ -35,8 +36,8 @@ struct TabletTool { impl TabletTool { fn proximity_in( &mut self, - (x, y): (f64, f64), - (focus, (sx, sy)): (WlSurface, (f64, f64)), + loc: Point, + (focus, sloc): (WlSurface, Point), tablet: &TabletHandle, serial: Serial, time: u32, @@ -50,7 +51,8 @@ impl TabletTool { tablet.with_focused_tablet(&focus, |wl_tablet| { wl_tool.proximity_in(serial.into(), wl_tablet, &focus); // proximity_in has to be followed by motion event (required by protocol) - wl_tool.motion(x - sx, y - sy); + let srel_loc = loc - sloc.to_f64(); + wl_tool.motion(srel_loc.x, srel_loc.y); wl_tool.frame(time); }); } @@ -114,8 +116,8 @@ impl TabletTool { fn motion( &mut self, - pos: (f64, f64), - focus: Option<(WlSurface, (f64, f64))>, + pos: Point, + focus: Option<(WlSurface, Point)>, tablet: &TabletHandle, serial: Serial, time: u32, @@ -128,9 +130,8 @@ impl TabletTool { .iter() .find(|i| i.as_ref().same_client_as(focus.0.as_ref())) { - let (x, y) = pos; - let (sx, sy) = focus.1; - wl_tool.motion(x - sx, y - sy); + let srel_loc = pos - focus.1.to_f64(); + wl_tool.motion(srel_loc.x, srel_loc.y); if let Some(pressure) = self.pending_pressure.take() { wl_tool.pressure((pressure * 65535.0).round() as u32); @@ -271,7 +272,9 @@ impl TabletToolHandle { compositor::with_states(&surface, |states| { states.data_map.insert_if_missing_threadsafe(|| { - Mutex::new(CursorImageAttributes { hotspot: (0, 0) }) + Mutex::new(CursorImageAttributes { + hotspot: (0, 0).into(), + }) }); states .data_map @@ -279,7 +282,7 @@ impl TabletToolHandle { .unwrap() .lock() .unwrap() - .hotspot = (hotspot_x, hotspot_y); + .hotspot = (hotspot_x, hotspot_y).into(); }) .unwrap(); @@ -356,8 +359,8 @@ impl TabletToolHandle { /// origin in the global compositor space. pub fn proximity_in( &self, - pos: (f64, f64), - focus: (WlSurface, (f64, f64)), + pos: Point, + focus: (WlSurface, Point), tablet: &TabletHandle, serial: Serial, time: u32, @@ -395,8 +398,8 @@ impl TabletToolHandle { /// of proximity_in/proximity_out events. pub fn motion( &self, - pos: (f64, f64), - focus: Option<(WlSurface, (f64, f64))>, + pos: Point, + focus: Option<(WlSurface, Point)>, tablet: &TabletHandle, serial: Serial, time: u32,