implement fractional HiDPI scaling
expose output from output map and return a reference in find change scale with keyboard shortcut scale input coordinates and render location according to output_scale scale buffers during rendering adapt window locations on output scale change to that the location will appear to be stable scale udev pointer location on output scale change to make the pointer location appear stable Use a UserDataMap to store the udev output id Short names for udev outputs for easier output scale configuration
This commit is contained in:
parent
e60374a459
commit
72e4d910fe
|
@ -39,6 +39,7 @@ pub fn draw_cursor<R, E, F, T>(
|
||||||
frame: &mut F,
|
frame: &mut F,
|
||||||
surface: &wl_surface::WlSurface,
|
surface: &wl_surface::WlSurface,
|
||||||
location: Point<i32, Logical>,
|
location: Point<i32, Logical>,
|
||||||
|
output_scale: f32,
|
||||||
log: &Logger,
|
log: &Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
|
@ -69,7 +70,7 @@ where
|
||||||
(0, 0).into()
|
(0, 0).into()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
draw_surface_tree(renderer, frame, surface, location - delta, log)
|
draw_surface_tree(renderer, frame, surface, location - delta, output_scale, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_surface_tree<R, E, F, T>(
|
fn draw_surface_tree<R, E, F, T>(
|
||||||
|
@ -77,6 +78,7 @@ fn draw_surface_tree<R, E, F, T>(
|
||||||
frame: &mut F,
|
frame: &mut F,
|
||||||
root: &wl_surface::WlSurface,
|
root: &wl_surface::WlSurface,
|
||||||
location: Point<i32, Logical>,
|
location: Point<i32, Logical>,
|
||||||
|
output_scale: f32,
|
||||||
log: &Logger,
|
log: &Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
|
@ -153,6 +155,7 @@ where
|
||||||
let mut location = *location;
|
let mut location = *location;
|
||||||
if let Some(ref data) = states.data_map.get::<RefCell<SurfaceData>>() {
|
if let Some(ref data) = states.data_map.get::<RefCell<SurfaceData>>() {
|
||||||
let mut data = data.borrow_mut();
|
let mut data = data.borrow_mut();
|
||||||
|
let buffer_scale = data.buffer_scale as f32;
|
||||||
if let Some(texture) = data
|
if let Some(texture) = data
|
||||||
.texture
|
.texture
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -164,10 +167,12 @@ where
|
||||||
let current = states.cached_state.current::<SubsurfaceCachedState>();
|
let current = states.cached_state.current::<SubsurfaceCachedState>();
|
||||||
location += current.location;
|
location += current.location;
|
||||||
}
|
}
|
||||||
|
let render_scale = output_scale as f32 / buffer_scale;
|
||||||
if let Err(err) = frame.render_texture_at(
|
if let Err(err) = frame.render_texture_at(
|
||||||
&texture.texture,
|
&texture.texture,
|
||||||
location.to_physical(1), // TODO: handle output scaling factor
|
location.to_f64().to_physical(output_scale as f64).to_i32_round(),
|
||||||
Transform::Normal, /* TODO */
|
Transform::Normal, /* TODO */
|
||||||
|
render_scale,
|
||||||
1.0,
|
1.0,
|
||||||
) {
|
) {
|
||||||
result = Err(err.into());
|
result = Err(err.into());
|
||||||
|
@ -186,6 +191,7 @@ pub fn draw_windows<R, E, F, T>(
|
||||||
frame: &mut F,
|
frame: &mut F,
|
||||||
window_map: &WindowMap,
|
window_map: &WindowMap,
|
||||||
output_rect: Rectangle<i32, Logical>,
|
output_rect: Rectangle<i32, Logical>,
|
||||||
|
output_scale: f32,
|
||||||
log: &::slog::Logger,
|
log: &::slog::Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
|
@ -205,7 +211,9 @@ where
|
||||||
initial_place.x -= output_rect.loc.x;
|
initial_place.x -= output_rect.loc.x;
|
||||||
if let Some(wl_surface) = toplevel_surface.get_surface() {
|
if let Some(wl_surface) = toplevel_surface.get_surface() {
|
||||||
// this surface is a root of a subsurface tree that needs to be drawn
|
// 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) {
|
if let Err(err) =
|
||||||
|
draw_surface_tree(renderer, frame, &wl_surface, initial_place, output_scale, log)
|
||||||
|
{
|
||||||
result = Err(err);
|
result = Err(err);
|
||||||
}
|
}
|
||||||
// furthermore, draw its popups
|
// furthermore, draw its popups
|
||||||
|
@ -217,7 +225,9 @@ where
|
||||||
let location = popup.location();
|
let location = popup.location();
|
||||||
let draw_location = initial_place + location + toplevel_geometry_offset;
|
let draw_location = initial_place + location + toplevel_geometry_offset;
|
||||||
if let Some(wl_surface) = popup.get_surface() {
|
if let Some(wl_surface) = popup.get_surface() {
|
||||||
if let Err(err) = draw_surface_tree(renderer, frame, &wl_surface, draw_location, log) {
|
if let Err(err) =
|
||||||
|
draw_surface_tree(renderer, frame, &wl_surface, draw_location, output_scale, log)
|
||||||
|
{
|
||||||
result = Err(err);
|
result = Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,6 +243,7 @@ pub fn draw_dnd_icon<R, E, F, T>(
|
||||||
frame: &mut F,
|
frame: &mut F,
|
||||||
surface: &wl_surface::WlSurface,
|
surface: &wl_surface::WlSurface,
|
||||||
location: Point<i32, Logical>,
|
location: Point<i32, Logical>,
|
||||||
|
output_scale: f32,
|
||||||
log: &::slog::Logger,
|
log: &::slog::Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
|
@ -247,5 +258,5 @@ where
|
||||||
"Trying to display as a dnd icon a surface that does not have the DndIcon role."
|
"Trying to display as a dnd icon a surface that does not have the DndIcon role."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
draw_surface_tree(renderer, frame, surface, location, log)
|
draw_surface_tree(renderer, frame, surface, location, output_scale, log)
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,32 @@ impl AnvilState<WinitData> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
KeyAction::ScaleUp => {
|
||||||
|
let current_scale = {
|
||||||
|
self.output_map
|
||||||
|
.borrow()
|
||||||
|
.find_by_name(crate::winit::OUTPUT_NAME)
|
||||||
|
.map(|o| o.scale())
|
||||||
|
.unwrap_or(1.0)
|
||||||
|
};
|
||||||
|
self.output_map
|
||||||
|
.borrow_mut()
|
||||||
|
.update_scale_by_name(current_scale + 0.25f32, crate::winit::OUTPUT_NAME);
|
||||||
|
}
|
||||||
|
KeyAction::ScaleDown => {
|
||||||
|
let current_scale = {
|
||||||
|
self.output_map
|
||||||
|
.borrow()
|
||||||
|
.find_by_name(crate::winit::OUTPUT_NAME)
|
||||||
|
.map(|o| o.scale())
|
||||||
|
.unwrap_or(1.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.output_map.borrow_mut().update_scale_by_name(
|
||||||
|
f32::max(1.0f32, current_scale - 0.25f32),
|
||||||
|
crate::winit::OUTPUT_NAME,
|
||||||
|
);
|
||||||
|
}
|
||||||
action => {
|
action => {
|
||||||
warn!(self.log, "Key action {:?} unsupported on winit backend.", action);
|
warn!(self.log, "Key action {:?} unsupported on winit backend.", action);
|
||||||
}
|
}
|
||||||
|
@ -172,12 +198,12 @@ impl AnvilState<WinitData> {
|
||||||
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event),
|
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event),
|
||||||
InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::<B>(event),
|
InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::<B>(event),
|
||||||
InputEvent::Special(WinitEvent::Resized { size, .. }) => {
|
InputEvent::Special(WinitEvent::Resized { size, .. }) => {
|
||||||
self.output_map.borrow_mut().update_mode(
|
self.output_map.borrow_mut().update_mode_by_name(
|
||||||
crate::winit::OUTPUT_NAME,
|
|
||||||
Mode {
|
Mode {
|
||||||
size,
|
size,
|
||||||
refresh: 60_000,
|
refresh: 60_000,
|
||||||
},
|
},
|
||||||
|
crate::winit::OUTPUT_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -190,7 +216,8 @@ impl AnvilState<WinitData> {
|
||||||
let output_size = self
|
let output_size = self
|
||||||
.output_map
|
.output_map
|
||||||
.borrow()
|
.borrow()
|
||||||
.with_primary(|_, rect| (rect.size.w as u32, rect.size.h as u32).into())
|
.find_by_name(crate::winit::OUTPUT_NAME)
|
||||||
|
.map(|o| (o.size().w as u32, o.size().h as u32).into())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let pos = evt.position_transformed(output_size);
|
let pos = evt.position_transformed(output_size);
|
||||||
self.pointer_location = pos;
|
self.pointer_location = pos;
|
||||||
|
@ -228,11 +255,7 @@ impl AnvilState<UdevData> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyAction::Screen(num) => {
|
KeyAction::Screen(num) => {
|
||||||
let geometry = self
|
let geometry = self.output_map.borrow().find_by_index(num).map(|o| o.geometry());
|
||||||
.output_map
|
|
||||||
.borrow()
|
|
||||||
.find_by_index(num, |_, geometry| geometry)
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
if let Some(geometry) = geometry {
|
if let Some(geometry) = geometry {
|
||||||
let x = geometry.loc.x as f64 + geometry.size.w as f64 / 2.0;
|
let x = geometry.loc.x as f64 + geometry.size.w as f64 / 2.0;
|
||||||
|
@ -240,6 +263,53 @@ impl AnvilState<UdevData> {
|
||||||
self.pointer_location = (x, y).into()
|
self.pointer_location = (x, y).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
KeyAction::ScaleUp => {
|
||||||
|
let mut output_map = self.output_map.borrow_mut();
|
||||||
|
|
||||||
|
let output = output_map
|
||||||
|
.find_by_position(self.pointer_location.to_i32_round())
|
||||||
|
.map(|o| (o.name().to_owned(), o.location(), o.scale()));
|
||||||
|
|
||||||
|
if let Some((name, output_location, scale)) = output {
|
||||||
|
let new_scale = scale + 0.25;
|
||||||
|
|
||||||
|
output_map.update_scale_by_name(new_scale, name);
|
||||||
|
|
||||||
|
let rescale = scale as f64 / new_scale as f64;
|
||||||
|
let output_location = output_location.to_f64();
|
||||||
|
let mut pointer_output_location = self.pointer_location - output_location;
|
||||||
|
pointer_output_location.x *= rescale;
|
||||||
|
pointer_output_location.y *= rescale;
|
||||||
|
self.pointer_location = output_location + pointer_output_location;
|
||||||
|
|
||||||
|
let under = self.window_map.borrow().get_surface_under(self.pointer_location);
|
||||||
|
self.pointer
|
||||||
|
.motion(self.pointer_location, under, SCOUNTER.next_serial(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyAction::ScaleDown => {
|
||||||
|
let mut output_map = self.output_map.borrow_mut();
|
||||||
|
|
||||||
|
let output = output_map
|
||||||
|
.find_by_position(self.pointer_location.to_i32_round())
|
||||||
|
.map(|o| (o.name().to_owned(), o.location(), o.scale()));
|
||||||
|
|
||||||
|
if let Some((name, output_location, scale)) = output {
|
||||||
|
let new_scale = f32::max(1.0, scale - 0.25);
|
||||||
|
output_map.update_scale_by_name(new_scale, name);
|
||||||
|
|
||||||
|
let rescale = scale as f64 / new_scale as f64;
|
||||||
|
let output_location = output_location.to_f64();
|
||||||
|
let mut pointer_output_location = self.pointer_location - output_location;
|
||||||
|
pointer_output_location.x *= rescale;
|
||||||
|
pointer_output_location.y *= rescale;
|
||||||
|
self.pointer_location = output_location + pointer_output_location;
|
||||||
|
|
||||||
|
let under = self.window_map.borrow().get_surface_under(self.pointer_location);
|
||||||
|
self.pointer
|
||||||
|
.motion(self.pointer_location, under, SCOUNTER.next_serial(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
InputEvent::PointerMotion { event, .. } => self.on_pointer_move::<B>(event),
|
InputEvent::PointerMotion { event, .. } => self.on_pointer_move::<B>(event),
|
||||||
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event),
|
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event),
|
||||||
|
@ -292,45 +362,45 @@ impl AnvilState<UdevData> {
|
||||||
let tablet_seat = self.seat.tablet_seat();
|
let tablet_seat = self.seat.tablet_seat();
|
||||||
let window_map = self.window_map.borrow();
|
let window_map = self.window_map.borrow();
|
||||||
|
|
||||||
output_map
|
let output_geometry = output_map.with_primary().map(|o| o.geometry());
|
||||||
.with_primary(|_, rect| {
|
|
||||||
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);
|
if let Some(rect) = output_geometry {
|
||||||
let tablet = tablet_seat.get_tablet(&TabletDescriptor::from(&evt.device()));
|
let rect_size = (rect.size.w as u32, rect.size.h as u32).into();
|
||||||
let tool = tablet_seat.get_tool(&evt.tool());
|
*pointer_location = evt.position_transformed(rect_size) + rect.loc.to_f64();
|
||||||
|
|
||||||
if let (Some(tablet), Some(tool)) = (tablet, tool) {
|
let under = window_map.get_surface_under(*pointer_location);
|
||||||
if evt.pressure_has_changed() {
|
let tablet = tablet_seat.get_tablet(&TabletDescriptor::from(&evt.device()));
|
||||||
tool.pressure(evt.pressure());
|
let tool = tablet_seat.get_tool(&evt.tool());
|
||||||
}
|
|
||||||
if evt.distance_has_changed() {
|
|
||||||
tool.distance(evt.distance());
|
|
||||||
}
|
|
||||||
if evt.tilt_has_changed() {
|
|
||||||
tool.tilt(evt.tilt());
|
|
||||||
}
|
|
||||||
if evt.slider_has_changed() {
|
|
||||||
tool.slider_position(evt.slider_position());
|
|
||||||
}
|
|
||||||
if evt.rotation_has_changed() {
|
|
||||||
tool.rotation(evt.rotation());
|
|
||||||
}
|
|
||||||
if evt.wheel_has_changed() {
|
|
||||||
tool.wheel(evt.wheel_delta(), evt.wheel_delta_discrete());
|
|
||||||
}
|
|
||||||
|
|
||||||
tool.motion(
|
if let (Some(tablet), Some(tool)) = (tablet, tool) {
|
||||||
*pointer_location,
|
if evt.pressure_has_changed() {
|
||||||
under,
|
tool.pressure(evt.pressure());
|
||||||
&tablet,
|
|
||||||
SCOUNTER.next_serial(),
|
|
||||||
evt.time(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
})
|
if evt.distance_has_changed() {
|
||||||
.unwrap();
|
tool.distance(evt.distance());
|
||||||
|
}
|
||||||
|
if evt.tilt_has_changed() {
|
||||||
|
tool.tilt(evt.tilt());
|
||||||
|
}
|
||||||
|
if evt.slider_has_changed() {
|
||||||
|
tool.slider_position(evt.slider_position());
|
||||||
|
}
|
||||||
|
if evt.rotation_has_changed() {
|
||||||
|
tool.rotation(evt.rotation());
|
||||||
|
}
|
||||||
|
if evt.wheel_has_changed() {
|
||||||
|
tool.wheel(evt.wheel_delta(), evt.wheel_delta_discrete());
|
||||||
|
}
|
||||||
|
|
||||||
|
tool.motion(
|
||||||
|
*pointer_location,
|
||||||
|
under,
|
||||||
|
&tablet,
|
||||||
|
SCOUNTER.next_serial(),
|
||||||
|
evt.time(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_tablet_tool_proximity<B: InputBackend>(&mut self, evt: B::TabletToolProximityEvent) {
|
fn on_tablet_tool_proximity<B: InputBackend>(&mut self, evt: B::TabletToolProximityEvent) {
|
||||||
|
@ -339,32 +409,32 @@ impl AnvilState<UdevData> {
|
||||||
let tablet_seat = self.seat.tablet_seat();
|
let tablet_seat = self.seat.tablet_seat();
|
||||||
let window_map = self.window_map.borrow();
|
let window_map = self.window_map.borrow();
|
||||||
|
|
||||||
output_map
|
let output_geometry = output_map.with_primary().map(|o| o.geometry());
|
||||||
.with_primary(|_, rect| {
|
|
||||||
let tool = evt.tool();
|
|
||||||
tablet_seat.add_tool(&tool);
|
|
||||||
|
|
||||||
let rect_size = (rect.size.h as u32, rect.size.w as u32).into();
|
if let Some(rect) = output_geometry {
|
||||||
*pointer_location = evt.position_transformed(rect_size) + rect.loc.to_f64();
|
let tool = evt.tool();
|
||||||
|
tablet_seat.add_tool(&tool);
|
||||||
|
|
||||||
let under = window_map.get_surface_under(*pointer_location);
|
let rect_size = (rect.size.h as u32, rect.size.w as u32).into();
|
||||||
let tablet = tablet_seat.get_tablet(&TabletDescriptor::from(&evt.device()));
|
*pointer_location = evt.position_transformed(rect_size) + rect.loc.to_f64();
|
||||||
let tool = tablet_seat.get_tool(&tool);
|
|
||||||
|
|
||||||
if let (Some(under), Some(tablet), Some(tool)) = (under, tablet, tool) {
|
let under = window_map.get_surface_under(*pointer_location);
|
||||||
match evt.state() {
|
let tablet = tablet_seat.get_tablet(&TabletDescriptor::from(&evt.device()));
|
||||||
ProximityState::In => tool.proximity_in(
|
let tool = tablet_seat.get_tool(&tool);
|
||||||
*pointer_location,
|
|
||||||
under,
|
if let (Some(under), Some(tablet), Some(tool)) = (under, tablet, tool) {
|
||||||
&tablet,
|
match evt.state() {
|
||||||
SCOUNTER.next_serial(),
|
ProximityState::In => tool.proximity_in(
|
||||||
evt.time(),
|
*pointer_location,
|
||||||
),
|
under,
|
||||||
ProximityState::Out => tool.proximity_out(evt.time()),
|
&tablet,
|
||||||
}
|
SCOUNTER.next_serial(),
|
||||||
|
evt.time(),
|
||||||
|
),
|
||||||
|
ProximityState::Out => tool.proximity_out(evt.time()),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.unwrap();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_tablet_tool_tip<B: InputBackend>(&mut self, evt: B::TabletToolTipEvent) {
|
fn on_tablet_tool_tip<B: InputBackend>(&mut self, evt: B::TabletToolTipEvent) {
|
||||||
|
@ -439,6 +509,8 @@ enum KeyAction {
|
||||||
Run(String),
|
Run(String),
|
||||||
/// Switch the current screen
|
/// Switch the current screen
|
||||||
Screen(usize),
|
Screen(usize),
|
||||||
|
ScaleUp,
|
||||||
|
ScaleDown,
|
||||||
/// Forward the key to the client
|
/// Forward the key to the client
|
||||||
Forward,
|
Forward,
|
||||||
/// Do nothing more
|
/// Do nothing more
|
||||||
|
@ -460,6 +532,10 @@ fn process_keyboard_shortcut(modifiers: ModifiersState, keysym: Keysym) -> KeyAc
|
||||||
KeyAction::Run("weston-terminal".into())
|
KeyAction::Run("weston-terminal".into())
|
||||||
} else if modifiers.logo && keysym >= xkb::KEY_1 && keysym <= xkb::KEY_9 {
|
} else if modifiers.logo && keysym >= xkb::KEY_1 && keysym <= xkb::KEY_9 {
|
||||||
KeyAction::Screen((keysym - xkb::KEY_1) as usize)
|
KeyAction::Screen((keysym - xkb::KEY_1) as usize)
|
||||||
|
} else if modifiers.logo && modifiers.shift && keysym == xkb::KEY_M {
|
||||||
|
KeyAction::ScaleDown
|
||||||
|
} else if modifiers.logo && modifiers.shift && keysym == xkb::KEY_P {
|
||||||
|
KeyAction::ScaleUp
|
||||||
} else {
|
} else {
|
||||||
KeyAction::Forward
|
KeyAction::Forward
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,10 @@ use smithay::{
|
||||||
wayland_protocols::xdg_shell::server::xdg_toplevel,
|
wayland_protocols::xdg_shell::server::xdg_toplevel,
|
||||||
wayland_server::{
|
wayland_server::{
|
||||||
protocol::{wl_output, wl_surface::WlSurface},
|
protocol::{wl_output, wl_surface::WlSurface},
|
||||||
Display, Global,
|
Display, Global, UserDataMap,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
utils::{Logical, Point, Rectangle},
|
utils::{Logical, Point, Rectangle, Size},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{with_surface_tree_downward, SubsurfaceCachedState, TraversalAction},
|
compositor::{with_surface_tree_downward, SubsurfaceCachedState, TraversalAction},
|
||||||
output::{self, Mode, PhysicalProperties},
|
output::{self, Mode, PhysicalProperties},
|
||||||
|
@ -17,13 +17,16 @@ use smithay::{
|
||||||
|
|
||||||
use crate::shell::SurfaceData;
|
use crate::shell::SurfaceData;
|
||||||
|
|
||||||
struct Output {
|
pub struct Output {
|
||||||
name: String,
|
name: String,
|
||||||
output: output::Output,
|
output: output::Output,
|
||||||
global: Option<Global<wl_output::WlOutput>>,
|
global: Option<Global<wl_output::WlOutput>>,
|
||||||
geometry: Rectangle<i32, Logical>,
|
|
||||||
surfaces: Vec<WlSurface>,
|
surfaces: Vec<WlSurface>,
|
||||||
current_mode: Mode,
|
current_mode: Mode,
|
||||||
|
scale: f32,
|
||||||
|
output_scale: i32,
|
||||||
|
location: Point<i32, Logical>,
|
||||||
|
userdata: UserDataMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output {
|
impl Output {
|
||||||
|
@ -40,22 +43,64 @@ impl Output {
|
||||||
{
|
{
|
||||||
let (output, global) = output::Output::new(display, name.as_ref().into(), physical, logger);
|
let (output, global) = output::Output::new(display, name.as_ref().into(), physical, logger);
|
||||||
|
|
||||||
output.change_current_state(Some(mode), None, None);
|
let scale = std::env::var(format!("ANVIL_SCALE_{}", name.as_ref()))
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s.parse::<f32>().ok())
|
||||||
|
.unwrap_or(1.0)
|
||||||
|
.max(1.0);
|
||||||
|
|
||||||
|
let output_scale = scale.round() as i32;
|
||||||
|
|
||||||
|
output.change_current_state(Some(mode), None, Some(output_scale));
|
||||||
output.set_preferred(mode);
|
output.set_preferred(mode);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
name: name.as_ref().to_owned(),
|
name: name.as_ref().to_owned(),
|
||||||
global: Some(global),
|
global: Some(global),
|
||||||
output,
|
output,
|
||||||
geometry: Rectangle {
|
location,
|
||||||
loc: location,
|
|
||||||
// TODO: handle scaling factor
|
|
||||||
size: mode.size.to_logical(1),
|
|
||||||
},
|
|
||||||
surfaces: Vec::new(),
|
surfaces: Vec::new(),
|
||||||
current_mode: mode,
|
current_mode: mode,
|
||||||
|
scale,
|
||||||
|
output_scale,
|
||||||
|
userdata: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn userdata(&self) -> &UserDataMap {
|
||||||
|
&self.userdata
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn geometry(&self) -> Rectangle<i32, Logical> {
|
||||||
|
let loc = self.location();
|
||||||
|
let size = self.size();
|
||||||
|
|
||||||
|
Rectangle { loc, size }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> Size<i32, Logical> {
|
||||||
|
self.current_mode
|
||||||
|
.size
|
||||||
|
.to_f64()
|
||||||
|
.to_logical(self.scale as f64)
|
||||||
|
.to_i32_round()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn location(&self) -> Point<i32, Logical> {
|
||||||
|
self.location
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale(&self) -> f32 {
|
||||||
|
self.scale
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
self.name.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_mode(&self) -> Mode {
|
||||||
|
self.current_mode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Output {
|
impl Drop for Output {
|
||||||
|
@ -64,17 +109,6 @@ impl Drop for Output {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct OutputNotFound;
|
|
||||||
|
|
||||||
impl std::fmt::Display for OutputNotFound {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.write_str("The output could not be found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for OutputNotFound {}
|
|
||||||
|
|
||||||
pub struct OutputMap {
|
pub struct OutputMap {
|
||||||
display: Rc<RefCell<Display>>,
|
display: Rc<RefCell<Display>>,
|
||||||
outputs: Vec<Output>,
|
outputs: Vec<Output>,
|
||||||
|
@ -100,24 +134,43 @@ impl OutputMap {
|
||||||
// First recalculate the outputs location
|
// First recalculate the outputs location
|
||||||
let mut output_x = 0;
|
let mut output_x = 0;
|
||||||
for output in self.outputs.iter_mut() {
|
for output in self.outputs.iter_mut() {
|
||||||
output.geometry.loc.x = output_x;
|
let output_x_shift = output_x - output.location.x;
|
||||||
output.geometry.loc.y = 0;
|
|
||||||
output_x += output.geometry.loc.x;
|
// If the scale changed we shift all windows on that output
|
||||||
|
// so that the location of the window will stay the same on screen
|
||||||
|
if output_x_shift != 0 {
|
||||||
|
let mut window_map = self.window_map.borrow_mut();
|
||||||
|
|
||||||
|
for surface in output.surfaces.iter() {
|
||||||
|
let toplevel = window_map.find(surface);
|
||||||
|
|
||||||
|
if let Some(toplevel) = toplevel {
|
||||||
|
let current_location = window_map.location(&toplevel);
|
||||||
|
|
||||||
|
if let Some(mut location) = current_location {
|
||||||
|
if output.geometry().contains(location) {
|
||||||
|
location.x += output_x_shift;
|
||||||
|
window_map.set_location(&toplevel, location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output.location.x = output_x;
|
||||||
|
output.location.y = 0;
|
||||||
|
output_x += output.size().w;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if any windows are now out of outputs range
|
// Check if any windows are now out of outputs range
|
||||||
// and move them to the primary output
|
// and move them to the primary output
|
||||||
let primary_output_location = self
|
let primary_output_location = self.with_primary().map(|o| o.location()).unwrap_or_default();
|
||||||
.with_primary(|_, geometry| geometry)
|
|
||||||
.ok()
|
|
||||||
.map(|o| o.loc)
|
|
||||||
.unwrap_or_default();
|
|
||||||
let mut window_map = self.window_map.borrow_mut();
|
let mut window_map = self.window_map.borrow_mut();
|
||||||
// TODO: This is a bit unfortunate, we save the windows in a temp vector
|
// 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.
|
// cause we can not call window_map.set_location within the closure.
|
||||||
let mut windows_to_move = Vec::new();
|
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));
|
let within_outputs = self.outputs.iter().any(|o| o.geometry().overlaps(bbox));
|
||||||
|
|
||||||
if !within_outputs {
|
if !within_outputs {
|
||||||
windows_to_move.push((kind.to_owned(), primary_output_location));
|
windows_to_move.push((kind.to_owned(), primary_output_location));
|
||||||
|
@ -135,9 +188,9 @@ impl OutputMap {
|
||||||
|| state.states.contains(xdg_toplevel::State::Fullscreen)
|
|| state.states.contains(xdg_toplevel::State::Fullscreen)
|
||||||
{
|
{
|
||||||
let output_geometry = if let Some(output) = state.fullscreen_output.as_ref() {
|
let output_geometry = if let Some(output) = state.fullscreen_output.as_ref() {
|
||||||
self.find(output, |_, geometry| geometry).ok()
|
self.find_by_output(output).map(|o| o.geometry())
|
||||||
} else {
|
} else {
|
||||||
self.find_by_position(location, |_, geometry| geometry).ok()
|
self.find_by_position(location).map(|o| o.geometry())
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(geometry) = output_geometry {
|
if let Some(geometry) = output_geometry {
|
||||||
|
@ -162,14 +215,14 @@ impl OutputMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add<N>(&mut self, name: N, physical: PhysicalProperties, mode: Mode)
|
pub fn add<N>(&mut self, name: N, physical: PhysicalProperties, mode: Mode) -> &Output
|
||||||
where
|
where
|
||||||
N: AsRef<str>,
|
N: AsRef<str>,
|
||||||
{
|
{
|
||||||
// Append the output to the end of the existing
|
// Append the output to the end of the existing
|
||||||
// outputs by placing it after the current overall
|
// outputs by placing it after the current overall
|
||||||
// width
|
// width
|
||||||
let location = (self.width() as i32, 0);
|
let location = (self.width(), 0);
|
||||||
|
|
||||||
let output = Output::new(
|
let output = Output::new(
|
||||||
name,
|
name,
|
||||||
|
@ -186,123 +239,143 @@ impl OutputMap {
|
||||||
// this would not affect windows, but arrange could re-organize
|
// this would not affect windows, but arrange could re-organize
|
||||||
// outputs from a configuration.
|
// outputs from a configuration.
|
||||||
self.arrange();
|
self.arrange();
|
||||||
|
|
||||||
|
self.outputs.last().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove<N: AsRef<str>>(&mut self, name: N) {
|
pub fn retain<F>(&mut self, f: F)
|
||||||
let removed_outputs = self.outputs.iter_mut().filter(|o| o.name == name.as_ref());
|
where
|
||||||
|
F: FnMut(&Output) -> bool,
|
||||||
|
{
|
||||||
|
self.outputs.retain(f);
|
||||||
|
|
||||||
for output in removed_outputs {
|
|
||||||
for surface in output.surfaces.drain(..) {
|
|
||||||
output.output.leave(&surface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.outputs.retain(|o| o.name != name.as_ref());
|
|
||||||
|
|
||||||
// Re-arrange outputs cause one or more outputs have
|
|
||||||
// been removed
|
|
||||||
self.arrange();
|
self.arrange();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn width(&self) -> i32 {
|
pub fn width(&self) -> i32 {
|
||||||
// This is a simplification, we only arrange the outputs on the y axis side-by-side
|
// 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.
|
// so that the total width is simply the sum of all output widths.
|
||||||
self.outputs
|
self.outputs.iter().fold(0, |acc, output| acc + output.size().w)
|
||||||
.iter()
|
|
||||||
.fold(0, |acc, output| acc + output.geometry.size.w)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn height(&self, x: i32) -> Option<i32> {
|
pub fn height(&self, x: i32) -> Option<i32> {
|
||||||
// This is a simplification, we only arrange the outputs on the y axis side-by-side
|
// This is a simplification, we only arrange the outputs on the y axis side-by-side
|
||||||
self.outputs
|
self.outputs
|
||||||
.iter()
|
.iter()
|
||||||
.find(|output| x >= output.geometry.loc.x && x < (output.geometry.loc.x + output.geometry.size.w))
|
.find(|output| {
|
||||||
.map(|output| output.geometry.size.h)
|
let geometry = output.geometry();
|
||||||
|
x >= geometry.loc.x && x < (geometry.loc.x + geometry.size.w)
|
||||||
|
})
|
||||||
|
.map(|output| output.size().h)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.outputs.is_empty()
|
self.outputs.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_primary<F, T>(&self, f: F) -> Result<T, OutputNotFound>
|
pub fn with_primary(&self) -> Option<&Output> {
|
||||||
where
|
self.outputs.get(0)
|
||||||
F: FnOnce(&output::Output, Rectangle<i32, Logical>) -> T,
|
|
||||||
{
|
|
||||||
let output = self.outputs.get(0).ok_or(OutputNotFound)?;
|
|
||||||
|
|
||||||
Ok(f(&output.output, output.geometry))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find<F, T>(&self, output: &wl_output::WlOutput, f: F) -> Result<T, OutputNotFound>
|
pub fn find<F>(&self, f: F) -> Option<&Output>
|
||||||
where
|
where
|
||||||
F: FnOnce(&output::Output, Rectangle<i32, Logical>) -> T,
|
F: FnMut(&&Output) -> bool,
|
||||||
{
|
{
|
||||||
let output = self
|
self.outputs.iter().find(f)
|
||||||
.outputs
|
|
||||||
.iter()
|
|
||||||
.find(|o| o.output.owns(output))
|
|
||||||
.ok_or(OutputNotFound)?;
|
|
||||||
|
|
||||||
Ok(f(&output.output, output.geometry))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_by_name<N, F, T>(&self, name: N, f: F) -> Result<T, OutputNotFound>
|
pub fn find_by_output(&self, output: &wl_output::WlOutput) -> Option<&Output> {
|
||||||
|
self.find(|o| o.output.owns(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_by_name<N>(&self, name: N) -> Option<&Output>
|
||||||
where
|
where
|
||||||
N: AsRef<str>,
|
N: AsRef<str>,
|
||||||
F: FnOnce(&output::Output, Rectangle<i32, Logical>) -> T,
|
|
||||||
{
|
{
|
||||||
let output = self
|
self.find(|o| o.name == name.as_ref())
|
||||||
.outputs
|
|
||||||
.iter()
|
|
||||||
.find(|o| o.name == name.as_ref())
|
|
||||||
.ok_or(OutputNotFound)?;
|
|
||||||
|
|
||||||
Ok(f(&output.output, output.geometry))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_by_position<F, T>(&self, position: Point<i32, Logical>, f: F) -> Result<T, OutputNotFound>
|
pub fn find_by_position(&self, position: Point<i32, Logical>) -> Option<&Output> {
|
||||||
|
self.find(|o| o.geometry().contains(position))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_by_index(&self, index: usize) -> Option<&Output> {
|
||||||
|
self.outputs.get(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update<F>(&mut self, mode: Option<Mode>, scale: Option<f32>, mut f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(&output::Output, Rectangle<i32, Logical>) -> T,
|
F: FnMut(&Output) -> bool,
|
||||||
{
|
{
|
||||||
let output = self
|
let output = self.outputs.iter_mut().find(|o| f(&**o));
|
||||||
.outputs
|
|
||||||
.iter()
|
|
||||||
.find(|o| o.geometry.contains(position))
|
|
||||||
.ok_or(OutputNotFound)?;
|
|
||||||
|
|
||||||
Ok(f(&output.output, output.geometry))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_by_index<F, T>(&self, index: usize, f: F) -> Result<T, OutputNotFound>
|
|
||||||
where
|
|
||||||
F: FnOnce(&output::Output, Rectangle<i32, Logical>) -> T,
|
|
||||||
{
|
|
||||||
let output = self.outputs.get(index).ok_or(OutputNotFound)?;
|
|
||||||
|
|
||||||
Ok(f(&output.output, output.geometry))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_mode<N: AsRef<str>>(&mut self, name: N, mode: Mode) {
|
|
||||||
let output = self.outputs.iter_mut().find(|o| o.name == name.as_ref());
|
|
||||||
|
|
||||||
// NOTE: This will just simply shift all outputs after
|
|
||||||
// the output who's mode has changed left or right depending
|
|
||||||
// on if the mode width increased or decreased.
|
|
||||||
// We could also re-configure toplevels here.
|
|
||||||
// If a surface is now visible on an additional output because
|
|
||||||
// the output width decreased the refresh method will take
|
|
||||||
// care and will send enter for the output.
|
|
||||||
if let Some(output) = output {
|
if let Some(output) = output {
|
||||||
// TODO: handle scale factors
|
if let Some(mode) = mode {
|
||||||
output.geometry.size = mode.size.to_logical(1);
|
output.output.delete_mode(output.current_mode);
|
||||||
|
output
|
||||||
|
.output
|
||||||
|
.change_current_state(Some(mode), None, Some(output.output_scale));
|
||||||
|
output.output.set_preferred(mode);
|
||||||
|
output.current_mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
output.output.delete_mode(output.current_mode);
|
if let Some(scale) = scale {
|
||||||
output.output.change_current_state(Some(mode), None, None);
|
// Calculate in which direction the scale changed
|
||||||
output.output.set_preferred(mode);
|
let rescale = output.scale() / scale;
|
||||||
output.current_mode = mode;
|
|
||||||
|
|
||||||
// Re-arrange outputs cause the size of one output changed
|
{
|
||||||
self.arrange();
|
// We take the current location of our toplevels and move them
|
||||||
|
// to the same location using the new scale
|
||||||
|
let mut window_map = self.window_map.borrow_mut();
|
||||||
|
for surface in output.surfaces.iter() {
|
||||||
|
let toplevel = window_map.find(surface);
|
||||||
|
|
||||||
|
if let Some(toplevel) = toplevel {
|
||||||
|
let current_location = window_map.location(&toplevel);
|
||||||
|
|
||||||
|
if let Some(location) = current_location {
|
||||||
|
let output_geometry = output.geometry();
|
||||||
|
|
||||||
|
if output_geometry.contains(location) {
|
||||||
|
let mut toplevel_output_location =
|
||||||
|
(location - output_geometry.loc).to_f64();
|
||||||
|
toplevel_output_location.x *= rescale as f64;
|
||||||
|
toplevel_output_location.y *= rescale as f64;
|
||||||
|
window_map.set_location(
|
||||||
|
&toplevel,
|
||||||
|
output_geometry.loc + toplevel_output_location.to_i32_round(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let output_scale = scale.round() as i32;
|
||||||
|
output.scale = scale;
|
||||||
|
|
||||||
|
if output.output_scale != output_scale {
|
||||||
|
output.output_scale = output_scale;
|
||||||
|
output
|
||||||
|
.output
|
||||||
|
.change_current_state(Some(output.current_mode), None, Some(output_scale));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.arrange();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_by_name<N: AsRef<str>>(&mut self, mode: Option<Mode>, scale: Option<f32>, name: N) {
|
||||||
|
self.update(mode, scale, |o| o.name() == name.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_scale_by_name<N: AsRef<str>>(&mut self, scale: f32, name: N) {
|
||||||
|
self.update_by_name(None, Some(scale), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_mode_by_name<N: AsRef<str>>(&mut self, mode: Mode, name: N) {
|
||||||
|
self.update_by_name(Some(mode), None, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh(&mut self) {
|
pub fn refresh(&mut self) {
|
||||||
|
@ -320,7 +393,7 @@ impl OutputMap {
|
||||||
// Check if the bounding box of the toplevel intersects with
|
// Check if the bounding box of the toplevel intersects with
|
||||||
// the output, if not no surface in the tree can intersect with
|
// the output, if not no surface in the tree can intersect with
|
||||||
// the output.
|
// the output.
|
||||||
if !output.geometry.overlaps(bbox) {
|
if !output.geometry().overlaps(bbox) {
|
||||||
if let Some(surface) = kind.get_surface() {
|
if let Some(surface) = kind.get_surface() {
|
||||||
with_surface_tree_downward(
|
with_surface_tree_downward(
|
||||||
surface,
|
surface,
|
||||||
|
@ -365,7 +438,7 @@ impl OutputMap {
|
||||||
if let Some(size) = data.and_then(|d| d.borrow().size()) {
|
if let Some(size) = data.and_then(|d| d.borrow().size()) {
|
||||||
let surface_rectangle = Rectangle { loc, 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
|
// We found a matching output, check if we already sent enter
|
||||||
if !output.surfaces.contains(wl_surface) {
|
if !output.surfaces.contains(wl_surface) {
|
||||||
output.output.enter(wl_surface);
|
output.output.enter(wl_surface);
|
||||||
|
|
|
@ -301,7 +301,7 @@ fn fullscreen_output_geometry(
|
||||||
// First test if a specific output has been requested
|
// First test if a specific output has been requested
|
||||||
// if the requested output is not found ignore the request
|
// if the requested output is not found ignore the request
|
||||||
if let Some(wl_output) = wl_output {
|
if let Some(wl_output) = wl_output {
|
||||||
return output_map.find(&wl_output, |_, geometry| geometry).ok();
|
return output_map.find_by_output(&wl_output).map(|o| o.geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is no output preference, try to find the output
|
// There is no output preference, try to find the output
|
||||||
|
@ -311,7 +311,7 @@ fn fullscreen_output_geometry(
|
||||||
.and_then(|kind| window_map.location(&kind));
|
.and_then(|kind| window_map.location(&kind));
|
||||||
|
|
||||||
if let Some(location) = window_location {
|
if let Some(location) = window_location {
|
||||||
let window_output = output_map.find_by_position(location, |_, geometry| geometry).ok();
|
let window_output = output_map.find_by_position(location).map(|o| o.geometry());
|
||||||
|
|
||||||
if let Some(result) = window_output {
|
if let Some(result) = window_output {
|
||||||
return Some(result);
|
return Some(result);
|
||||||
|
@ -319,7 +319,7 @@ fn fullscreen_output_geometry(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to primary output
|
// Fallback to primary output
|
||||||
output_map.with_primary(|_, geometry| geometry).ok()
|
output_map.with_primary().map(|o| o.geometry())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::slog::Logger) -> ShellHandles {
|
pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::slog::Logger) -> ShellHandles {
|
||||||
|
@ -355,8 +355,8 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
|
||||||
|
|
||||||
let output_geometry = xdg_output_map
|
let output_geometry = xdg_output_map
|
||||||
.borrow()
|
.borrow()
|
||||||
.with_primary(|_, geometry| geometry)
|
.with_primary()
|
||||||
.ok()
|
.map(|o| o.geometry())
|
||||||
.unwrap_or_else(|| Rectangle::from_loc_and_size((0, 0), (800, 800)));
|
.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_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 max_y = output_geometry.loc.y + (((output_geometry.size.h as f32) / 3.0) * 2.0) as i32;
|
||||||
|
@ -593,8 +593,8 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
|
||||||
.and_then(|position| {
|
.and_then(|position| {
|
||||||
xdg_output_map
|
xdg_output_map
|
||||||
.borrow()
|
.borrow()
|
||||||
.find_by_position(position, |_, geometry| geometry)
|
.find_by_position(position)
|
||||||
.ok()
|
.map(|o| o.geometry())
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -645,8 +645,8 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
|
||||||
|
|
||||||
let output_geometry = shell_output_map
|
let output_geometry = shell_output_map
|
||||||
.borrow()
|
.borrow()
|
||||||
.with_primary(|_, geometry| geometry)
|
.with_primary()
|
||||||
.ok()
|
.map(|o| o.geometry())
|
||||||
.unwrap_or_else(|| Rectangle::from_loc_and_size((0, 0), (800, 800)));
|
.unwrap_or_else(|| Rectangle::from_loc_and_size((0, 0), (800, 800)));
|
||||||
let max_x =
|
let max_x =
|
||||||
output_geometry.loc.x + (((output_geometry.size.w as f32) / 3.0) * 2.0) as i32;
|
output_geometry.loc.x + (((output_geometry.size.w as f32) / 3.0) * 2.0) as i32;
|
||||||
|
|
|
@ -78,14 +78,13 @@ impl AsRawFd for SessionFd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UdevOutputMap {
|
#[derive(Debug, PartialEq)]
|
||||||
pub device_id: dev_t,
|
struct UdevOutputId {
|
||||||
pub crtc: crtc::Handle,
|
device_id: dev_t,
|
||||||
pub output_name: String,
|
crtc: crtc::Handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UdevData {
|
pub struct UdevData {
|
||||||
output_map: Vec<UdevOutputMap>,
|
|
||||||
pub session: AutoSession,
|
pub session: AutoSession,
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
primary_gpu: Option<PathBuf>,
|
primary_gpu: Option<PathBuf>,
|
||||||
|
@ -132,7 +131,6 @@ pub fn run_udev(
|
||||||
|
|
||||||
let data = UdevData {
|
let data = UdevData {
|
||||||
session,
|
session,
|
||||||
output_map: Vec::new(),
|
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
primary_gpu,
|
primary_gpu,
|
||||||
backends: HashMap::new(),
|
backends: HashMap::new(),
|
||||||
|
@ -272,7 +270,6 @@ fn scan_connectors(
|
||||||
device: &mut DrmDevice<SessionFd>,
|
device: &mut DrmDevice<SessionFd>,
|
||||||
gbm: &GbmDevice<SessionFd>,
|
gbm: &GbmDevice<SessionFd>,
|
||||||
renderer: &mut Gles2Renderer,
|
renderer: &mut Gles2Renderer,
|
||||||
backend_output_map: &mut Vec<UdevOutputMap>,
|
|
||||||
output_map: &mut crate::output_map::OutputMap,
|
output_map: &mut crate::output_map::OutputMap,
|
||||||
signaler: &Signaler<SessionSignal>,
|
signaler: &Signaler<SessionSignal>,
|
||||||
logger: &::slog::Logger,
|
logger: &::slog::Logger,
|
||||||
|
@ -342,14 +339,26 @@ fn scan_connectors(
|
||||||
refresh: (mode.vrefresh() * 1000) as i32,
|
refresh: (mode.vrefresh() * 1000) as i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
let output_name = format!(
|
let other_short_name;
|
||||||
"{:?}-{}",
|
let interface_short_name = match connector_info.interface() {
|
||||||
connector_info.interface(),
|
drm::control::connector::Interface::DVII => "DVI-I",
|
||||||
connector_info.interface_id()
|
drm::control::connector::Interface::DVID => "DVI-D",
|
||||||
);
|
drm::control::connector::Interface::DVIA => "DVI-A",
|
||||||
|
drm::control::connector::Interface::SVideo => "S-VIDEO",
|
||||||
|
drm::control::connector::Interface::DisplayPort => "DP",
|
||||||
|
drm::control::connector::Interface::HDMIA => "HDMI-A",
|
||||||
|
drm::control::connector::Interface::HDMIB => "HDMI-B",
|
||||||
|
drm::control::connector::Interface::EmbeddedDisplayPort => "eDP",
|
||||||
|
other => {
|
||||||
|
other_short_name = format!("{:?}", other);
|
||||||
|
&other_short_name
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let output_name = format!("{}-{}", interface_short_name, connector_info.interface_id());
|
||||||
|
|
||||||
let (phys_w, phys_h) = connector_info.size().unwrap_or((0, 0));
|
let (phys_w, phys_h) = connector_info.size().unwrap_or((0, 0));
|
||||||
output_map.add(
|
let output = output_map.add(
|
||||||
&output_name,
|
&output_name,
|
||||||
PhysicalProperties {
|
PhysicalProperties {
|
||||||
size: (phys_w as i32, phys_h as i32).into(),
|
size: (phys_w as i32, phys_h as i32).into(),
|
||||||
|
@ -360,10 +369,9 @@ fn scan_connectors(
|
||||||
mode,
|
mode,
|
||||||
);
|
);
|
||||||
|
|
||||||
backend_output_map.push(UdevOutputMap {
|
output.userdata().insert_if_missing(|| UdevOutputId {
|
||||||
crtc,
|
crtc,
|
||||||
device_id: device.device_id(),
|
device_id: device.device_id(),
|
||||||
output_name,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
entry.insert(Rc::new(RefCell::new(renderer)));
|
entry.insert(Rc::new(RefCell::new(renderer)));
|
||||||
|
@ -456,7 +464,6 @@ impl AnvilState<UdevData> {
|
||||||
&mut device,
|
&mut device,
|
||||||
&gbm,
|
&gbm,
|
||||||
&mut *renderer.borrow_mut(),
|
&mut *renderer.borrow_mut(),
|
||||||
&mut self.backend_data.output_map,
|
|
||||||
&mut *self.output_map.borrow_mut(),
|
&mut *self.output_map.borrow_mut(),
|
||||||
&self.backend_data.signaler,
|
&self.backend_data.signaler,
|
||||||
&self.log,
|
&self.log,
|
||||||
|
@ -517,20 +524,14 @@ impl AnvilState<UdevData> {
|
||||||
let logger = self.log.clone();
|
let logger = self.log.clone();
|
||||||
let loop_handle = self.handle.clone();
|
let loop_handle = self.handle.clone();
|
||||||
let signaler = self.backend_data.signaler.clone();
|
let signaler = self.backend_data.signaler.clone();
|
||||||
let removed_outputs = self
|
|
||||||
.backend_data
|
|
||||||
.output_map
|
|
||||||
.iter()
|
|
||||||
.filter(|o| o.device_id == device)
|
|
||||||
.map(|o| o.output_name.as_str());
|
|
||||||
|
|
||||||
for output in removed_outputs {
|
self.output_map.borrow_mut().retain(|output| {
|
||||||
self.output_map.borrow_mut().remove(output);
|
output
|
||||||
}
|
.userdata()
|
||||||
|
.get::<UdevOutputId>()
|
||||||
self.backend_data
|
.map(|id| id.device_id != device)
|
||||||
.output_map
|
.unwrap_or(true)
|
||||||
.retain(|output| output.device_id != device);
|
});
|
||||||
|
|
||||||
let mut source = backend_data.event_dispatcher.as_source_mut();
|
let mut source = backend_data.event_dispatcher.as_source_mut();
|
||||||
let mut backends = backend_data.surfaces.borrow_mut();
|
let mut backends = backend_data.surfaces.borrow_mut();
|
||||||
|
@ -538,7 +539,6 @@ impl AnvilState<UdevData> {
|
||||||
&mut *source,
|
&mut *source,
|
||||||
&backend_data.gbm,
|
&backend_data.gbm,
|
||||||
&mut *backend_data.renderer.borrow_mut(),
|
&mut *backend_data.renderer.borrow_mut(),
|
||||||
&mut self.backend_data.output_map,
|
|
||||||
&mut *self.output_map.borrow_mut(),
|
&mut *self.output_map.borrow_mut(),
|
||||||
&signaler,
|
&signaler,
|
||||||
&logger,
|
&logger,
|
||||||
|
@ -563,16 +563,14 @@ impl AnvilState<UdevData> {
|
||||||
// drop surfaces
|
// drop surfaces
|
||||||
backend_data.surfaces.borrow_mut().clear();
|
backend_data.surfaces.borrow_mut().clear();
|
||||||
debug!(self.log, "Surfaces dropped");
|
debug!(self.log, "Surfaces dropped");
|
||||||
let removed_outputs = self
|
|
||||||
.backend_data
|
self.output_map.borrow_mut().retain(|output| {
|
||||||
.output_map
|
output
|
||||||
.iter()
|
.userdata()
|
||||||
.filter(|o| o.device_id == device)
|
.get::<UdevOutputId>()
|
||||||
.map(|o| o.output_name.as_str());
|
.map(|id| id.device_id != device)
|
||||||
for output_id in removed_outputs {
|
.unwrap_or(true)
|
||||||
self.output_map.borrow_mut().remove(output_id);
|
});
|
||||||
}
|
|
||||||
self.backend_data.output_map.retain(|o| o.device_id != device);
|
|
||||||
|
|
||||||
let _device = self.handle.remove(backend_data.registration_token);
|
let _device = self.handle.remove(backend_data.registration_token);
|
||||||
let _device = backend_data.event_dispatcher.into_source_inner();
|
let _device = backend_data.event_dispatcher.into_source_inner();
|
||||||
|
@ -618,7 +616,6 @@ impl AnvilState<UdevData> {
|
||||||
device_backend.dev_id,
|
device_backend.dev_id,
|
||||||
crtc,
|
crtc,
|
||||||
&mut *self.window_map.borrow_mut(),
|
&mut *self.window_map.borrow_mut(),
|
||||||
&self.backend_data.output_map,
|
|
||||||
&*self.output_map.borrow(),
|
&*self.output_map.borrow(),
|
||||||
self.pointer_location,
|
self.pointer_location,
|
||||||
&device_backend.pointer_image,
|
&device_backend.pointer_image,
|
||||||
|
@ -666,7 +663,6 @@ fn render_surface(
|
||||||
device_id: dev_t,
|
device_id: dev_t,
|
||||||
crtc: crtc::Handle,
|
crtc: crtc::Handle,
|
||||||
window_map: &mut WindowMap,
|
window_map: &mut WindowMap,
|
||||||
backend_output_map: &[UdevOutputMap],
|
|
||||||
output_map: &crate::output_map::OutputMap,
|
output_map: &crate::output_map::OutputMap,
|
||||||
pointer_location: Point<f64, Logical>,
|
pointer_location: Point<f64, Logical>,
|
||||||
pointer_image: &Gles2Texture,
|
pointer_image: &Gles2Texture,
|
||||||
|
@ -676,14 +672,12 @@ fn render_surface(
|
||||||
) -> Result<(), SwapBuffersError> {
|
) -> Result<(), SwapBuffersError> {
|
||||||
surface.frame_submitted()?;
|
surface.frame_submitted()?;
|
||||||
|
|
||||||
let output_geometry = backend_output_map
|
let output = output_map
|
||||||
.iter()
|
.find(|o| o.userdata().get::<UdevOutputId>() == Some(&UdevOutputId { device_id, crtc }))
|
||||||
.find(|o| o.device_id == device_id && o.crtc == crtc)
|
.map(|output| (output.geometry(), output.scale(), output.current_mode()));
|
||||||
.map(|o| o.output_name.as_str())
|
|
||||||
.and_then(|name| output_map.find_by_name(name, |_, geometry| geometry).ok());
|
|
||||||
|
|
||||||
let output_geometry = if let Some(geometry) = output_geometry {
|
let (output_geometry, output_scale, mode) = if let Some((geometry, scale, mode)) = output {
|
||||||
geometry
|
(geometry, scale, mode)
|
||||||
} else {
|
} else {
|
||||||
// Somehow we got called with a non existing output
|
// Somehow we got called with a non existing output
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -694,13 +688,12 @@ fn render_surface(
|
||||||
// and draw to our buffer
|
// and draw to our buffer
|
||||||
match renderer
|
match renderer
|
||||||
.render(
|
.render(
|
||||||
// TODO: handle scale factor
|
mode.size,
|
||||||
output_geometry.size.to_physical(1),
|
|
||||||
Transform::Flipped180, // Scanout is rotated
|
Transform::Flipped180, // Scanout is rotated
|
||||||
|renderer, frame| {
|
|renderer, frame| {
|
||||||
frame.clear([0.8, 0.8, 0.9, 1.0])?;
|
frame.clear([0.8, 0.8, 0.9, 1.0])?;
|
||||||
// draw the surfaces
|
// draw the surfaces
|
||||||
draw_windows(renderer, frame, window_map, output_geometry, logger)?;
|
draw_windows(renderer, frame, window_map, output_geometry, output_scale, logger)?;
|
||||||
|
|
||||||
// set cursor
|
// set cursor
|
||||||
if output_geometry.to_f64().contains(pointer_location) {
|
if output_geometry.to_f64().contains(pointer_location) {
|
||||||
|
@ -711,7 +704,14 @@ fn render_surface(
|
||||||
{
|
{
|
||||||
if let Some(ref wl_surface) = dnd_icon.as_ref() {
|
if let Some(ref wl_surface) = dnd_icon.as_ref() {
|
||||||
if wl_surface.as_ref().is_alive() {
|
if wl_surface.as_ref().is_alive() {
|
||||||
draw_dnd_icon(renderer, frame, wl_surface, relative_ptr_location, logger)?;
|
draw_dnd_icon(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
wl_surface,
|
||||||
|
relative_ptr_location,
|
||||||
|
output_scale,
|
||||||
|
logger,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -727,13 +727,23 @@ fn render_surface(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let CursorImageStatus::Image(ref wl_surface) = *cursor_status {
|
if let CursorImageStatus::Image(ref wl_surface) = *cursor_status {
|
||||||
draw_cursor(renderer, frame, wl_surface, relative_ptr_location, logger)?;
|
draw_cursor(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
wl_surface,
|
||||||
|
relative_ptr_location,
|
||||||
|
output_scale,
|
||||||
|
logger,
|
||||||
|
)?;
|
||||||
} else {
|
} else {
|
||||||
// TODO: handle output scale factor
|
|
||||||
frame.render_texture_at(
|
frame.render_texture_at(
|
||||||
pointer_image,
|
pointer_image,
|
||||||
relative_ptr_location.to_physical(1),
|
relative_ptr_location
|
||||||
|
.to_f64()
|
||||||
|
.to_physical(output_scale as f64)
|
||||||
|
.to_i32_round(),
|
||||||
Transform::Normal,
|
Transform::Normal,
|
||||||
|
output_scale,
|
||||||
1.0,
|
1.0,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,11 +110,11 @@ pub fn run_winit(
|
||||||
{
|
{
|
||||||
let mut renderer = renderer.borrow_mut();
|
let mut renderer = renderer.borrow_mut();
|
||||||
// This is safe to do as with winit we are guaranteed to have exactly one output
|
// This is safe to do as with winit we are guaranteed to have exactly one output
|
||||||
let output_geometry = state
|
let (output_geometry, output_scale) = state
|
||||||
.output_map
|
.output_map
|
||||||
.borrow()
|
.borrow()
|
||||||
.find_by_name(OUTPUT_NAME, |_, geometry| geometry)
|
.find_by_name(OUTPUT_NAME)
|
||||||
.ok()
|
.map(|output| (output.geometry(), output.scale()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = renderer
|
let result = renderer
|
||||||
|
@ -127,6 +127,7 @@ pub fn run_winit(
|
||||||
frame,
|
frame,
|
||||||
&*state.window_map.borrow(),
|
&*state.window_map.borrow(),
|
||||||
output_geometry,
|
output_geometry,
|
||||||
|
output_scale,
|
||||||
&log,
|
&log,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -136,7 +137,14 @@ pub fn run_winit(
|
||||||
let guard = state.dnd_icon.lock().unwrap();
|
let guard = state.dnd_icon.lock().unwrap();
|
||||||
if let Some(ref surface) = *guard {
|
if let Some(ref surface) = *guard {
|
||||||
if surface.as_ref().is_alive() {
|
if surface.as_ref().is_alive() {
|
||||||
draw_dnd_icon(renderer, frame, surface, (x as i32, y as i32).into(), &log)?;
|
draw_dnd_icon(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
surface,
|
||||||
|
(x as i32, y as i32).into(),
|
||||||
|
output_scale,
|
||||||
|
&log,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,7 +163,14 @@ pub fn run_winit(
|
||||||
// draw as relevant
|
// draw as relevant
|
||||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||||
cursor_visible = false;
|
cursor_visible = false;
|
||||||
draw_cursor(renderer, frame, surface, (x as i32, y as i32).into(), &log)?;
|
draw_cursor(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
surface,
|
||||||
|
(x as i32, y as i32).into(),
|
||||||
|
output_scale,
|
||||||
|
&log,
|
||||||
|
)?;
|
||||||
} else {
|
} else {
|
||||||
cursor_visible = true;
|
cursor_visible = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,6 +185,7 @@ pub trait Frame {
|
||||||
texture: &Self::TextureId,
|
texture: &Self::TextureId,
|
||||||
pos: Point<i32, Physical>,
|
pos: Point<i32, Physical>,
|
||||||
transform: Transform,
|
transform: Transform,
|
||||||
|
scale: f32,
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let mut mat = Matrix3::<f32>::identity();
|
let mut mat = Matrix3::<f32>::identity();
|
||||||
|
@ -192,7 +193,7 @@ pub trait Frame {
|
||||||
// position and scale
|
// position and scale
|
||||||
let size = texture.size();
|
let size = texture.size();
|
||||||
mat = mat * Matrix3::from_translation(Vector2::new(pos.x as f32, pos.y 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);
|
mat = mat * Matrix3::from_nonuniform_scale(size.0 as f32 * scale, size.1 as f32 * scale);
|
||||||
|
|
||||||
//apply surface transformation
|
//apply surface transformation
|
||||||
mat = mat * Matrix3::from_translation(Vector2::new(0.5, 0.5));
|
mat = mat * Matrix3::from_translation(Vector2::new(0.5, 0.5));
|
||||||
|
|
Loading…
Reference in New Issue