Introduce Logical/Physical Point/Rectangle

This commit is contained in:
Victor Berger 2021-07-05 19:21:15 +02:00 committed by Victor Berger
parent aa647c636e
commit 54ea0d3a74
30 changed files with 1386 additions and 649 deletions

View File

@ -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<R, E, F, T>(
renderer: &mut R,
frame: &mut F,
surface: &wl_surface::WlSurface,
(x, y): (i32, i32),
location: Point<i32, Logical>,
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<R, E, F, T>(
renderer: &mut R,
frame: &mut F,
root: &wl_surface::WlSurface,
location: (i32, i32),
location: Point<i32, Logical>,
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::<RefCell<SurfaceData>>() {
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::<Vec<_>>();
@ -136,10 +137,9 @@ where
// if yes, also process the children
if states.role == Some("subsurface") {
let current = states.cached_state.current::<SubsurfaceCachedState>();
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::<RefCell<SurfaceData>>() {
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::<SubsurfaceCachedState>();
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<R, E, F, T>(
renderer: &mut R,
frame: &mut F,
window_map: &WindowMap,
output_rect: Rectangle,
output_rect: Rectangle<i32, Logical>,
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<R, E, F, T>(
renderer: &mut R,
frame: &mut F,
surface: &wl_surface::WlSurface,
(x, y): (i32, i32),
location: Point<i32, Logical>,
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)
}

View File

@ -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<WinitData> {
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<WinitData> {
}
fn on_pointer_move_absolute<B: InputBackend>(&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<UdevData> {
.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<UdevData> {
}
fn on_pointer_move<B: InputBackend>(&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<UdevData> {
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<UdevData> {
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<UdevData> {
}
}
fn clamp_coords(&self, pos: (f64, f64)) -> (f64, f64) {
fn clamp_coords(&self, pos: Point<f64, Logical>) -> Point<f64, Logical> {
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<UdevData> {
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()
}
}
}

View File

@ -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<Global<wl_output::WlOutput>>,
geometry: Rectangle,
geometry: Rectangle<i32, Logical>,
surfaces: Vec<WlSurface>,
current_mode: Mode,
}
@ -29,7 +29,7 @@ struct Output {
impl Output {
fn new<N>(
name: N,
location: (i32, i32),
location: Point<i32, Logical>,
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<u32> {
pub fn height(&self, x: i32) -> Option<i32> {
// 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<F, T>(&self, f: F) -> Result<T, OutputNotFound>
where
F: FnOnce(&output::Output, Rectangle) -> T,
F: FnOnce(&output::Output, Rectangle<i32, Logical>) -> T,
{
let output = self.outputs.get(0).ok_or(OutputNotFound)?;
@ -235,7 +234,7 @@ impl OutputMap {
pub fn find<F, T>(&self, output: &wl_output::WlOutput, f: F) -> Result<T, OutputNotFound>
where
F: FnOnce(&output::Output, Rectangle) -> T,
F: FnOnce(&output::Output, Rectangle<i32, Logical>) -> T,
{
let output = self
.outputs
@ -249,7 +248,7 @@ impl OutputMap {
pub fn find_by_name<N, F, T>(&self, name: N, f: F) -> Result<T, OutputNotFound>
where
N: AsRef<str>,
F: FnOnce(&output::Output, Rectangle) -> T,
F: FnOnce(&output::Output, Rectangle<i32, Logical>) -> T,
{
let output = self
.outputs
@ -260,9 +259,9 @@ impl OutputMap {
Ok(f(&output.output, output.geometry))
}
pub fn find_by_position<F, T>(&self, position: (i32, i32), f: F) -> Result<T, OutputNotFound>
pub fn find_by_position<F, T>(&self, position: Point<i32, Logical>, f: F) -> Result<T, OutputNotFound>
where
F: FnOnce(&output::Output, Rectangle) -> T,
F: FnOnce(&output::Output, Rectangle<i32, Logical>) -> T,
{
let output = self
.outputs
@ -275,7 +274,7 @@ impl OutputMap {
pub fn find_by_index<F, T>(&self, index: usize, f: F) -> Result<T, OutputNotFound>
where
F: FnOnce(&output::Output, Rectangle) -> T,
F: FnOnce(&output::Output, Rectangle<i32, Logical>) -> 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::<RefCell<SurfaceData>>();
if data.is_some() {
if states.role == Some("subsurface") {
let current = states.cached_state.current::<SubsurfaceCachedState>();
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::<RefCell<SurfaceData>>();
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);

View File

@ -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<RefCell<WindowMap>>,
toplevel: SurfaceKind,
initial_window_location: (i32, i32),
initial_window_location: Point<i32, Logical>,
}
impl PointerGrab for MoveSurfaceGrab {
fn motion(
&mut self,
_handle: &mut PointerInnerHandle<'_>,
location: (f64, f64),
_focus: Option<(wl_surface::WlSurface, (f64, f64))>,
location: Point<f64, Logical>,
_focus: Option<(wl_surface::WlSurface, Point<i32, Logical>)>,
_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<i32, Logical>,
last_window_size: Size<i32, Logical>,
}
impl PointerGrab for ResizeSurfaceGrab {
fn motion(
&mut self,
handle: &mut PointerInnerHandle<'_>,
location: (f64, f64),
_focus: Option<(wl_surface::WlSurface, (f64, f64))>,
location: Point<f64, Logical>,
_focus: Option<(wl_surface::WlSurface, Point<i32, Logical>)>,
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<Rectangle> {
) -> Option<Rectangle<i32, Logical>> {
// 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<BackendData: 'static>(display: Rc<RefCell<Display>>, 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<BackendData: 'static>(display: Rc<RefCell<Display>>, 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<BackendData: 'static>(display: Rc<RefCell<Display>>, 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<BackendData: 'static>(display: Rc<RefCell<Display>>, 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<BackendData: 'static>(display: Rc<RefCell<Display>>, 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<BackendData: 'static>(display: Rc<RefCell<Display>>, 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<BackendData: 'static>(display: Rc<RefCell<Display>>, 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<BackendData: 'static>(display: Rc<RefCell<Display>>, 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<i32, Logical>,
/// The initial window size (geometry width and height).
initial_window_size: (i32, i32),
initial_window_size: Size<i32, Logical>,
}
/// State of the resize operation.
@ -847,9 +836,10 @@ impl Default for ResizeState {
pub struct SurfaceData {
pub buffer: Option<wl_buffer::WlBuffer>,
pub texture: Option<Box<dyn std::any::Any + 'static>>,
pub geometry: Option<Rectangle>,
pub geometry: Option<Rectangle<i32, Logical>>,
pub resize_state: ResizeState,
pub dimensions: Option<(i32, i32)>,
pub buffer_dimensions: Option<Size<i32, Physical>>,
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<Size<i32, Logical>> {
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<f64, Logical>) -> 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<WindowMa
}
window_map.refresh_toplevel(&toplevel);
// Get the geometry outside since it uses the token, and so would block inside.
let Rectangle { width, height, .. } = window_map.geometry(&toplevel).unwrap();
let geometry = window_map.geometry(&toplevel).unwrap();
let new_location = with_states(surface, |states| {
let mut data = states
.data_map
@ -990,10 +982,12 @@ fn surface_commit(surface: &wl_surface::WlSurface, window_map: &RefCell<WindowMa
let mut location = window_map.location(&toplevel).unwrap();
if edges.intersects(ResizeEdge::LEFT) {
location.0 = initial_window_location.0 + (initial_window_size.0 - width);
location.x =
initial_window_location.x + (initial_window_size.w - geometry.size.w);
}
if edges.intersects(ResizeEdge::TOP) {
location.1 = initial_window_location.1 + (initial_window_size.1 - height);
location.y =
initial_window_location.y + (initial_window_size.h - geometry.size.h);
}
new_location = Some(location);

View File

@ -12,6 +12,7 @@ use smithay::{
calloop::{generic::Generic, Interest, LoopHandle, Mode, PostAction},
wayland_server::{protocol::wl_surface::WlSurface, Display},
},
utils::{Logical, Point},
wayland::{
data_device::{default_action_chooser, init_data_device, set_data_device_focus, DataDeviceEvent},
seat::{CursorImageStatus, KeyboardHandle, PointerHandle, Seat, XkbConfig},
@ -39,7 +40,7 @@ pub struct AnvilState<BackendData> {
pub pointer: PointerHandle,
pub keyboard: KeyboardHandle,
pub suppressed_keys: Vec<u32>,
pub pointer_location: (f64, f64),
pub pointer_location: Point<f64, Logical>,
pub cursor_status: Arc<Mutex<CursorImageStatus>>,
pub seat_name: String,
pub seat: Seat,
@ -167,7 +168,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
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(),

View File

@ -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<UdevData> {
&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<f64, Logical>,
pointer_image: &Gles2Texture,
dnd_icon: &Option<wl_surface::WlSurface>,
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::<i32, Logical>::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::<SwapBuffersError>::into)

View File

@ -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<i32, Logical> {
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::<Mutex<XdgPopupSurfaceRoleAttributes>>()
@ -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<i32, Logical>,
/// 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<i32, Logical>,
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<f64, Logical>) -> Option<(wl_surface::WlSurface, Point<i32, Logical>)> {
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::<RefCell<SurfaceData>>();
if states.role == Some("subsurface") {
let current = states.cached_state.current::<SubsurfaceCachedState>();
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::<RefCell<SurfaceData>>();
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::<SubsurfaceCachedState>();
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<i32, Logical> {
// 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::<SurfaceCachedState>().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<i32, Logical>) {
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<f64, Logical>,
) -> Option<(wl_surface::WlSurface, Point<i32, Logical>)> {
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<f64, Logical>,
) -> Option<(wl_surface::WlSurface, Point<i32, Logical>)> {
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<Func>(&self, mut f: Func)
where
Func: FnMut(&Kind, (i32, i32), &Rectangle),
Func: FnMut(&Kind, Point<i32, Logical>, &Rectangle<i32, Logical>),
{
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<Point<i32, Logical>> {
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<i32, Logical>) {
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<Rectangle> {
pub fn geometry(&self, toplevel: &Kind) -> Option<Rectangle<i32, Logical>> {
self.windows
.iter()
.find(|w| &w.toplevel == toplevel)

View File

@ -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;
}

View File

@ -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<RustConnection>,
atoms: Atoms,
log: slog::Logger,
unpaired_surfaces: HashMap<u32, (Window, (i32, i32))>,
unpaired_surfaces: HashMap<u32, (Window, Point<i32, Logical>)>,
window_map: Rc<RefCell<WindowMap>>,
}
@ -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<i32, Logical>) {
debug!(self.log, "Matched X11 surface {:x?} to {:x?}", window, surface);
if give_role(&surface, "x11_surface").is_err() {

View File

@ -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<crate::utils::Size<i32, crate::utils::Physical>> {
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())
}
}

View File

@ -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<B: InputBackend> PointerAxisEvent<B> for UnusedEvent {
/// Trait for pointer events generated by relative device movement.
pub trait PointerMotionEvent<B: InputBackend>: Event<B> {
/// 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<f64, Logical> {
(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<B: InputBackend>: Event<B> {
/// 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<f64, Raw> {
(self.x(), self.y()).into()
}
/// Device x position in it's original coordinate space.
@ -263,11 +265,12 @@ pub trait PointerMotionAbsoluteEvent<B: InputBackend>: Event<B> {
/// 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<u32, Logical>) -> Point<f64, Logical> {
(
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<B: InputBackend>: Event<B> {
/// 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<f64, Raw> {
(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<u32, Logical>) -> Point<f64, Logical> {
(
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<B: InputBackend>: Event<B> {
/// 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<f64, Raw> {
(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<u32, Logical>) -> Point<f64, Logical> {
(
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

View File

@ -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<B: InputBackend> {
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<f64, Logical> {
(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<f64, Raw> {
(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<u32, Logical>) -> Point<f64, Logical> {
(
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

View File

@ -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<i32, Buffer>],
) -> Result<Gles2Texture, Gles2Error> {
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<F, R>(
&mut self,
width: u32,
height: u32,
size: Size<i32, Physical>,
transform: Transform,
rendering: F,
) -> Result<R, Self::Error>
@ -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::<f32>::identity();
let t = Matrix3::<f32>::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];

View File

@ -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<i32, Physical>,
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<F, R>(
&mut self,
width: u32,
height: u32,
size: Size<i32, Physical>,
transform: Transform,
rendering: F,
) -> Result<R, Self::Error>
@ -265,7 +266,7 @@ pub trait ImportShm: Renderer {
&mut self,
buffer: &wl_buffer::WlBuffer,
surface: Option<&crate::wayland::compositor::SurfaceData>,
damage: &[Rectangle],
damage: &[Rectangle<i32, Buffer>],
) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::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<i32, Buffer>],
) -> Option<Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error>>;
}
@ -420,7 +421,7 @@ impl<R: Renderer + ImportShm + ImportEgl + ImportDma> ImportAll for R {
&mut self,
buffer: &wl_buffer::WlBuffer,
surface: Option<&SurfaceData>,
damage: &[Rectangle],
damage: &[Rectangle<i32, Buffer>],
) -> Option<Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error>> {
match buffer_type(buffer) {
Some(BufferType::Shm) => Some(self.import_shm_buffer(buffer, surface, damage)),
@ -440,7 +441,7 @@ impl<R: Renderer + ImportShm + ImportDma> ImportAll for R {
&mut self,
buffer: &wl_buffer::WlBuffer,
surface: Option<&SurfaceData>,
damage: &[Rectangle],
damage: &[Rectangle<i32, Buffer>],
) -> Option<Result<<Self as Renderer>::TextureId, <Self as Renderer>::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<BufferType> {
///
/// *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<Size<i32, Physical>> {
use crate::backend::allocator::Buffer;
if let Some(buf) = buffer.as_ref().user_data().get::<Dmabuf>() {
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()
}

View File

@ -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<u32>,
pub physical_size: Size<i32, Physical>,
/// Scaling factor of the window
pub scale_factor: f64,
}
impl WindowSize {
fn logical_size(&self) -> Size<f64, Logical> {
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<EGLSurface>,
window: Rc<WinitWindow>,
size: Rc<RefCell<WindowSize>>,
resize_notification: Rc<Cell<Option<(u32, u32)>>>,
resize_notification: Rc<Cell<Option<Size<i32, Physical>>>>,
}
/// Abstracted event loop of a [`WinitWindow`] implementing the [`InputBackend`] trait
@ -100,7 +110,7 @@ pub struct WinitInputBackend {
logger: ::slog::Logger,
initialized: bool,
size: Rc<RefCell<WindowSize>>,
resize_notification: Rc<Cell<Option<(u32, u32)>>>,
resize_notification: Rc<Cell<Option<Size<i32, Physical>>>>,
}
/// 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<i32, Physical>,
/// 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<WinitInputBackend> for WinitMouseMovedEvent {
fn x_transformed(&self, width: u32) -> f64 {
let wsize = self.size.borrow();
let w_width = wsize.physical_size.to_logical::<f64>(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::<f64>(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<WinitInputBackend> for WinitMouseInputEvent {
pub struct WinitTouchStartedEvent {
size: Rc<RefCell<WindowSize>>,
time: u32,
location: (f64, f64),
location: LogicalPosition<f64>,
id: u64,
}
@ -497,24 +506,24 @@ impl TouchDownEvent<WinitInputBackend> 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::<f64>(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::<f64>(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<WinitInputBackend> for WinitTouchStartedEvent {
pub struct WinitTouchMovedEvent {
size: Rc<RefCell<WindowSize>>,
time: u32,
location: (f64, f64),
location: LogicalPosition<f64>,
id: u64,
}
@ -544,24 +553,24 @@ impl TouchMotionEvent<WinitInputBackend> 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::<f64>(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::<f64>(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,
},
});

829
src/utils/geometry.rs Normal file
View File

@ -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<Self, Output = Self> + Sub<Self, Output = Self> + 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<N, Kind> {
/// horizontal coordinate
pub x: N,
/// vertical coordinate
pub y: N,
_kind: std::marker::PhantomData<Kind>,
}
impl<N: Coordinate, Kind> Point<N, Kind> {
/// 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<N, Kind> {
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<N, Kind> {
Size {
w: self.x.abs(),
h: self.y.abs(),
_kind: std::marker::PhantomData,
}
}
}
impl<N: Coordinate, Kind> Point<N, Kind> {
/// Convert the underlying numerical type to f64 for floating point manipulations
#[inline]
pub fn to_f64(self) -> Point<f64, Kind> {
Point {
x: self.x.to_f64(),
y: self.y.to_f64(),
_kind: std::marker::PhantomData,
}
}
}
impl<Kind> Point<f64, Kind> {
/// Convert to i32 for integer-space manipulations by rounding float values
#[inline]
pub fn to_i32_round<N: Coordinate>(self) -> Point<N, Kind> {
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<N: Coordinate>(self) -> Point<N, Kind> {
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<N: Coordinate>(self) -> Point<N, Kind> {
Point {
x: N::from_f64(self.x.ceil()),
y: N::from_f64(self.y.ceil()),
_kind: std::marker::PhantomData,
}
}
}
impl<N: fmt::Debug> fmt::Debug for Point<N, Logical> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Point<Logical>")
.field("x", &self.x)
.field("y", &self.y)
.finish()
}
}
impl<N: fmt::Debug> fmt::Debug for Point<N, Physical> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Point<Physical>")
.field("x", &self.x)
.field("y", &self.y)
.finish()
}
}
impl<N: fmt::Debug> fmt::Debug for Point<N, Raw> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Point<Raw>")
.field("x", &self.x)
.field("y", &self.y)
.finish()
}
}
impl<N: fmt::Debug> fmt::Debug for Point<N, Buffer> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Point<Buffer>")
.field("x", &self.x)
.field("y", &self.y)
.finish()
}
}
impl<N: Coordinate> Point<N, Logical> {
#[inline]
/// Convert this logical point to physical coordinate space according to given scale factor
pub fn to_physical(self, scale: N) -> Point<N, Physical> {
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<N, Buffer> {
Point {
x: self.x.upscale(scale),
y: self.y.upscale(scale),
_kind: std::marker::PhantomData,
}
}
}
impl<N: Coordinate> Point<N, Physical> {
#[inline]
/// Convert this physical point to logical coordinate space according to given scale factor
pub fn to_logical(self, scale: N) -> Point<N, Logical> {
Point {
x: self.x.downscale(scale),
y: self.y.downscale(scale),
_kind: std::marker::PhantomData,
}
}
}
impl<N: Coordinate> Point<N, Buffer> {
#[inline]
/// Convert this physical point to logical coordinate space according to given scale factor
pub fn to_logical(self, scale: N) -> Point<N, Logical> {
Point {
x: self.x.downscale(scale),
y: self.y.downscale(scale),
_kind: std::marker::PhantomData,
}
}
}
impl<N, Kind> From<(N, N)> for Point<N, Kind> {
#[inline]
fn from((x, y): (N, N)) -> Point<N, Kind> {
Point {
x,
y,
_kind: std::marker::PhantomData,
}
}
}
impl<N, Kind> From<Point<N, Kind>> for (N, N) {
#[inline]
fn from(point: Point<N, Kind>) -> (N, N) {
(point.x, point.y)
}
}
impl<N: Add<Output = N>, Kind> Add for Point<N, Kind> {
type Output = Point<N, Kind>;
#[inline]
fn add(self, other: Point<N, Kind>) -> Point<N, Kind> {
Point {
x: self.x + other.x,
y: self.y + other.y,
_kind: std::marker::PhantomData,
}
}
}
impl<N: AddAssign, Kind> AddAssign for Point<N, Kind> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self.x += rhs.x;
self.y += rhs.y
}
}
impl<N: SubAssign, Kind> SubAssign for Point<N, Kind> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
self.x -= rhs.x;
self.y -= rhs.y
}
}
impl<N: Sub<Output = N>, Kind> Sub for Point<N, Kind> {
type Output = Point<N, Kind>;
#[inline]
fn sub(self, other: Point<N, Kind>) -> Point<N, Kind> {
Point {
x: self.x - other.x,
y: self.y - other.y,
_kind: std::marker::PhantomData,
}
}
}
impl<N: Clone, Kind> Clone for Point<N, Kind> {
#[inline]
fn clone(&self) -> Self {
Point {
x: self.x.clone(),
y: self.y.clone(),
_kind: std::marker::PhantomData,
}
}
}
impl<N: Copy, Kind> Copy for Point<N, Kind> {}
impl<N: PartialEq, Kind> PartialEq for Point<N, Kind> {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y
}
}
impl<N: Eq, Kind> Eq for Point<N, Kind> {}
impl<N: Default, Kind> Default for Point<N, Kind> {
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<N, Kind> {
/// horizontal coordinate
pub w: N,
/// vertical coordinate
pub h: N,
_kind: std::marker::PhantomData<Kind>,
}
impl<N: Coordinate, Kind> Size<N, Kind> {
/// Convert this [`Size`] to a [`Point`] with the same coordinates
#[inline]
pub fn to_point(self) -> Point<N, Kind> {
Point {
x: self.w,
y: self.h,
_kind: std::marker::PhantomData,
}
}
}
impl<N: Coordinate, Kind> Size<N, Kind> {
/// Convert the underlying numerical type to f64 for floating point manipulations
#[inline]
pub fn to_f64(self) -> Size<f64, Kind> {
Size {
w: self.w.to_f64(),
h: self.h.to_f64(),
_kind: std::marker::PhantomData,
}
}
}
impl<Kind> Size<f64, Kind> {
/// Convert to i32 for integer-space manipulations by rounding float values
#[inline]
pub fn to_i32_round<N: Coordinate>(self) -> Size<N, Kind> {
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<N: Coordinate>(self) -> Size<N, Kind> {
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<N: Coordinate>(self) -> Size<N, Kind> {
Size {
w: N::from_f64(self.w.ceil()),
h: N::from_f64(self.h.ceil()),
_kind: std::marker::PhantomData,
}
}
}
impl<N: fmt::Debug> fmt::Debug for Size<N, Logical> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Size<Logical>")
.field("w", &self.w)
.field("h", &self.h)
.finish()
}
}
impl<N: fmt::Debug> fmt::Debug for Size<N, Physical> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Size<Physical>")
.field("w", &self.w)
.field("h", &self.h)
.finish()
}
}
impl<N: fmt::Debug> fmt::Debug for Size<N, Raw> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Size<Raw>")
.field("w", &self.w)
.field("h", &self.h)
.finish()
}
}
impl<N: fmt::Debug> fmt::Debug for Size<N, Buffer> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Size<Buffer>")
.field("w", &self.w)
.field("h", &self.h)
.finish()
}
}
impl<N: Coordinate> Size<N, Logical> {
#[inline]
/// Convert this logical size to physical coordinate space according to given scale factor
pub fn to_physical(self, scale: N) -> Size<N, Physical> {
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<N, Buffer> {
Size {
w: self.w.upscale(scale),
h: self.h.upscale(scale),
_kind: std::marker::PhantomData,
}
}
}
impl<N: Coordinate> Size<N, Physical> {
#[inline]
/// Convert this physical point to logical coordinate space according to given scale factor
pub fn to_logical(self, scale: N) -> Size<N, Logical> {
Size {
w: self.w.downscale(scale),
h: self.h.downscale(scale),
_kind: std::marker::PhantomData,
}
}
}
impl<N: Coordinate> Size<N, Buffer> {
#[inline]
/// Convert this physical point to logical coordinate space according to given scale factor
pub fn to_logical(self, scale: N) -> Size<N, Logical> {
Size {
w: self.w.downscale(scale),
h: self.h.downscale(scale),
_kind: std::marker::PhantomData,
}
}
}
impl<N: Coordinate, Kind> From<(N, N)> for Size<N, Kind> {
#[inline]
fn from((w, h): (N, N)) -> Size<N, Kind> {
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<N, Kind> From<Size<N, Kind>> for (N, N) {
#[inline]
fn from(point: Size<N, Kind>) -> (N, N) {
(point.w, point.h)
}
}
impl<N: Add<Output = N>, Kind> Add for Size<N, Kind> {
type Output = Size<N, Kind>;
#[inline]
fn add(self, other: Size<N, Kind>) -> Size<N, Kind> {
Size {
w: self.w + other.w,
h: self.h + other.h,
_kind: std::marker::PhantomData,
}
}
}
impl<N: AddAssign, Kind> AddAssign for Size<N, Kind> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self.w += rhs.w;
self.h += rhs.h
}
}
impl<N: Clone, Kind> Clone for Size<N, Kind> {
#[inline]
fn clone(&self) -> Self {
Size {
w: self.w.clone(),
h: self.h.clone(),
_kind: std::marker::PhantomData,
}
}
}
impl<N: Copy, Kind> Copy for Size<N, Kind> {}
impl<N: PartialEq, Kind> PartialEq for Size<N, Kind> {
fn eq(&self, other: &Self) -> bool {
self.w == other.w && self.h == other.h
}
}
impl<N: Eq, Kind> Eq for Size<N, Kind> {}
impl<N: Default, Kind> Default for Size<N, Kind> {
fn default() -> Self {
Size {
w: N::default(),
h: N::default(),
_kind: std::marker::PhantomData,
}
}
}
impl<N: Add<Output = N>, Kind> Add<Size<N, Kind>> for Point<N, Kind> {
type Output = Point<N, Kind>;
#[inline]
fn add(self, other: Size<N, Kind>) -> Point<N, Kind> {
Point {
x: self.x + other.w,
y: self.y + other.h,
_kind: std::marker::PhantomData,
}
}
}
impl<N: Sub<Output = N>, Kind> Sub<Size<N, Kind>> for Point<N, Kind> {
type Output = Point<N, Kind>;
#[inline]
fn sub(self, other: Size<N, Kind>) -> Point<N, Kind> {
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<N, Kind> {
/// Location of the top-left corner of the rectangle
pub loc: Point<N, Kind>,
/// Size of the rectangle, as (width, height)
pub size: Size<N, Kind>,
}
impl<N: Coordinate, Kind> Rectangle<N, Kind> {
/// Convert the underlying numerical type to another
pub fn to_f64(self) -> Rectangle<f64, Kind> {
Rectangle {
loc: self.loc.to_f64(),
size: self.size.to_f64(),
}
}
}
impl<N: Coordinate, Kind> Rectangle<N, Kind> {
/// 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<Point<N, Kind>>, size: impl Into<Size<N, Kind>>) -> 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<Point<N, Kind>>,
bottomright: impl Into<Point<N, Kind>>,
) -> 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<P: Into<Point<N, Kind>>>(self, point: P) -> bool {
let p: Point<N, Kind> = 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<N, Kind>) -> 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<Item = Point<N, Kind>>) -> 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<N: Coordinate> Rectangle<N, Logical> {
/// Convert this logical rectangle to physical coordinate space according to given scale factor
#[inline]
pub fn to_physical(self, scale: N) -> Rectangle<N, Physical> {
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<N, Buffer> {
Rectangle {
loc: self.loc.to_buffer(scale),
size: self.size.to_buffer(scale),
}
}
}
impl<N: Coordinate> Rectangle<N, Physical> {
/// Convert this physical rectangle to logical coordinate space according to given scale factor
#[inline]
pub fn to_logical(self, scale: N) -> Rectangle<N, Logical> {
Rectangle {
loc: self.loc.to_logical(scale),
size: self.size.to_logical(scale),
}
}
}
impl<N: Coordinate> Rectangle<N, Buffer> {
/// Convert this physical rectangle to logical coordinate space according to given scale factor
#[inline]
pub fn to_logical(self, scale: N) -> Rectangle<N, Logical> {
Rectangle {
loc: self.loc.to_logical(scale),
size: self.size.to_logical(scale),
}
}
}
impl<N: fmt::Debug> fmt::Debug for Rectangle<N, Logical> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Rectangle<Logical>")
.field("x", &self.loc.x)
.field("y", &self.loc.y)
.field("width", &self.size.w)
.field("height", &self.size.h)
.finish()
}
}
impl<N: fmt::Debug> fmt::Debug for Rectangle<N, Physical> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Rectangle<Physical>")
.field("x", &self.loc.x)
.field("y", &self.loc.y)
.field("width", &self.size.w)
.field("height", &self.size.h)
.finish()
}
}
impl<N: fmt::Debug> fmt::Debug for Rectangle<N, Raw> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Rectangle<Raw>")
.field("x", &self.loc.x)
.field("y", &self.loc.y)
.field("width", &self.size.w)
.field("height", &self.size.h)
.finish()
}
}
impl<N: fmt::Debug> fmt::Debug for Rectangle<N, Buffer> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Rectangle<Buffer>")
.field("x", &self.loc.x)
.field("y", &self.loc.y)
.field("width", &self.size.w)
.field("height", &self.size.h)
.finish()
}
}
impl<N: Clone, Kind> Clone for Rectangle<N, Kind> {
#[inline]
fn clone(&self) -> Self {
Rectangle {
loc: self.loc.clone(),
size: self.size.clone(),
}
}
}
impl<N: Copy, Kind> Copy for Rectangle<N, Kind> {}
impl<N: PartialEq, Kind> PartialEq for Rectangle<N, Kind> {
fn eq(&self, other: &Self) -> bool {
self.loc == other.loc && self.size == other.size
}
}
impl<N: Eq, Kind> Eq for Rectangle<N, Kind> {}
impl<N: Default, Kind> Default for Rectangle<N, Kind> {
fn default() -> Self {
Rectangle {
loc: Default::default(),
size: Default::default(),
}
}
}

View File

@ -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)]

View File

@ -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,
}
}
}

View File

@ -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::<SurfaceAttributes>().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::<SurfaceAttributes>()
.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::<SurfaceAttributes>()
.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<i32, Logical>,
}
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::<SubsurfaceCachedState>().location = (x, y);
state.cached_state.pending::<SubsurfaceCachedState>().location = (x, y).into();
})
}
wl_subsurface::Request::PlaceAbove { sibling } => {

View File

@ -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<i32, Logical>),
/// A rectangle containing the damaged zone, in buffer coordinates
///
/// Note: Buffer scaling must be taken into consideration
Buffer(Rectangle),
Buffer(Rectangle<i32, Buffer>),
}
#[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<i32, Logical>,
},
}
@ -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<i32, Logical>)>,
}
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<P: Into<Point<i32, Logical>>>(&self, point: P) -> bool {
let point: Point<i32, Logical> = 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))),
],
};

View File

@ -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<f64, Logical>,
focus: Option<(wl_surface::WlSurface, Point<i32, Logical>)>,
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);
}
}
}

View File

@ -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<f64, Logical>,
focus: Option<(wl_surface::WlSurface, Point<i32, Logical>)>,
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);
}
}
}

View File

@ -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<i32, Physical>,
/// 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<i32, Raw>,
/// The subpixel geometry
pub subpixel: Subpixel,
/// Textual representation of the make
@ -103,7 +100,7 @@ struct Inner {
log: ::slog::Logger,
instances: Vec<WlOutput>,
physical: PhysicalProperties,
location: (i32, i32),
location: Point<i32, Logical>,
transform: Transform,
scale: i32,
modes: Vec<Mode>,
@ -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);

View File

@ -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<i32, Logical>,
}
/// Possible status of a cursor as requested by clients
@ -50,9 +52,9 @@ impl fmt::Debug for GrabStatus {
struct PointerInternal {
known_pointers: Vec<WlPointer>,
focus: Option<(WlSurface, (f64, f64))>,
pending_focus: Option<(WlSurface, (f64, f64))>,
location: (f64, f64),
focus: Option<(WlSurface, Point<i32, Logical>)>,
pending_focus: Option<(WlSurface, Point<i32, Logical>)>,
location: Point<f64, Logical>,
grab: GrabStatus,
pressed_buttons: Vec<u32>,
image_callback: Box<dyn FnMut(CursorImageStatus)>,
@ -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<f64, Logical>,
focus: Option<(WlSurface, Point<i32, Logical>)>,
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<f64, Logical> {
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<i32, Logical>)>,
/// 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<f64, Logical>,
}
/// 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<f64, Logical>,
focus: Option<(WlSurface, Point<i32, Logical>)>,
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<i32, Logical>)> {
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<f64, Logical> {
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<f64, Logical>,
focus: Option<(WlSurface, Point<i32, Logical>)>,
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<WlPointer>, 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<WlPointer>, 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<f64, Logical>,
focus: Option<(WlSurface, Point<i32, Logical>)>,
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<f64, Logical>,
_focus: Option<(WlSurface, Point<i32, Logical>)>,
serial: Serial,
time: u32,
) {

View File

@ -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<i32, Logical>, 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<i32, Logical>,
/// 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<i32, Logical>,
/// 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,

View File

@ -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),
},
},

View File

@ -62,7 +62,7 @@
//! that you are given (in an `Arc<Mutex<_>>`) 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<i32, Logical>,
/// 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<i32, Logical>,
/// Holds the pending state as set by the server.
pub server_pending: Option<ToplevelState>,
/// 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<i32, Logical>,
}
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<i32, Logical>,
/// Anchor rectangle in the parent surface coordinates
/// relative to which the surface must be positioned
pub anchor_rect: Rectangle,
pub anchor_rect: Rectangle<i32, Logical>,
/// 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<i32, Logical>,
}
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<i32, Logical> {
// 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<Size<i32, Logical>>,
/// The states for this surface
pub states: ToplevelStateSet,
@ -603,29 +585,29 @@ impl From<ToplevelStateSet> for Vec<xdg_toplevel::State> {
pub struct SurfaceCachedState {
/// Holds the double-buffered geometry that may be specified
/// by xdg_surface.set_window_geometry.
pub geometry: Option<Rectangle>,
pub geometry: Option<Rectangle<i32, Logical>>,
/// 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<i32, Logical>,
/// 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<i32, Logical>,
}
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<i32, Logical>,
},
/// A surface has acknowledged a configure serial.
AckConfigure {

View File

@ -132,7 +132,7 @@ fn implement_positioner(positioner: Main<xdg_positioner::XdgPositioner>) -> 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_positioner::XdgPositioner>) -> 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_positioner::XdgPositioner>) -> 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::XdgPositioner>) -> 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::<SurfaceCachedState>().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::<ShellSurfaceUserData>()
.unwrap();
let (width, height) = configure.state.size.unwrap_or((0, 0));
let (width, height) = configure.state.size.unwrap_or_default().into();
// convert the Vec<State> (which is really a Vec<u32>) into Vec<u8>
let states = {
let mut states: Vec<xdg_toplevel::State> = 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

View File

@ -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::<SurfaceCachedState>().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::<ShellSurfaceUserData>()
.unwrap();
let (width, height) = configure.state.size.unwrap_or((0, 0));
let (width, height) = configure.state.size.unwrap_or_default().into();
// convert the Vec<State> (which is really a Vec<u32>) into Vec<u8>
let states = {
let mut states: Vec<xdg_toplevel::State> = 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

View File

@ -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<f64, Logical>,
(focus, sloc): (WlSurface, Point<i32, Logical>),
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<f64, Logical>,
focus: Option<(WlSurface, Point<i32, Logical>)>,
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<f64, Logical>,
focus: (WlSurface, Point<i32, Logical>),
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<f64, Logical>,
focus: Option<(WlSurface, Point<i32, Logical>)>,
tablet: &TabletHandle,
serial: Serial,
time: u32,