fmt commit

This commit is contained in:
Victoria Brekenfeld 2022-08-30 13:28:36 +02:00
parent 352c526e9e
commit 9e0a6e1b5f
25 changed files with 787 additions and 499 deletions

View file

@ -40,7 +40,10 @@ use smithay::{
DisplayHandle, Resource, DisplayHandle, Resource,
}, },
}, },
utils::{Size, signaling::{Linkable, SignalToken, Signaler}}, utils::{
signaling::{Linkable, SignalToken, Signaler},
Size,
},
wayland::{ wayland::{
dmabuf::DmabufGlobal, dmabuf::DmabufGlobal,
output::{Mode as OutputMode, Output, PhysicalProperties}, output::{Mode as OutputMode, Output, PhysicalProperties},
@ -1023,12 +1026,15 @@ impl KmsState {
} }
pub fn capture_output(&self, output: &Output) -> Option<(DrmNode, Dmabuf, Instant)> { pub fn capture_output(&self, output: &Output) -> Option<(DrmNode, Dmabuf, Instant)> {
self.devices self.devices.values().find_map(|dev| {
.values() dev.surfaces
.find_map(|dev| dev.surfaces.values().find(|s| &s.output == output) .values()
.and_then(|s| s.last_render.clone() .find(|s| &s.output == output)
.map(|(buf, time)| (dev.render_node.clone(), buf, time)) .and_then(|s| {
) s.last_render
) .clone()
.map(|(buf, time)| (dev.render_node.clone(), buf, time))
})
})
} }
} }

View file

@ -49,7 +49,7 @@ pub fn init_backend_auto(
.with_context(|| "Backend initialized without output")? .with_context(|| "Backend initialized without output")?
.clone(); .clone();
seat.user_data() seat.user_data()
.insert_if_missing(|| crate::input::ActiveOutput(std::cell::RefCell::new(output))); .insert_if_missing(|| crate::input::ActiveOutput(std::cell::RefCell::new(output)));
} }
} }
res res

View file

@ -242,10 +242,14 @@ where
1, 1,
scale, scale,
Transform::Normal, Transform::Normal,
&damage.iter().copied().map(|mut rect| { &damage
rect.loc -= self.position.to_physical(scale).to_i32_round(); .iter()
rect .copied()
}).collect::<Vec<_>>(), .map(|mut rect| {
rect.loc -= self.position.to_physical(scale).to_i32_round();
rect
})
.collect::<Vec<_>>(),
1.0, 1.0,
)?; )?;
Ok(()) Ok(())
@ -335,7 +339,10 @@ where
Point::<i32, Logical>::from((frame.xhot as i32, frame.yhot as i32)).to_f64(); Point::<i32, Logical>::from((frame.xhot as i32, frame.yhot as i32)).to_f64();
*state.current_image.borrow_mut() = Some(frame); *state.current_image.borrow_mut() = Some(frame);
Some(PointerElement::new(seat, pointer_image.clone(), location - hotspot, new_frame).into()) Some(
PointerElement::new(seat, pointer_image.clone(), location - hotspot, new_frame)
.into(),
)
} else { } else {
None None
} }

View file

@ -1,19 +1,16 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::{
state::Common,
shell::grabs::{
SeatMoveGrabState,
MoveGrabRenderElement,
},
wayland::handlers::data_device::get_dnd_icon,
};
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
use crate::{ use crate::{
debug::{debug_ui, fps_ui, log_ui, EguiFrame}, debug::{debug_ui, fps_ui, log_ui, EguiFrame},
state::Fps, state::Fps,
utils::prelude::*, utils::prelude::*,
}; };
use crate::{
shell::grabs::{MoveGrabRenderElement, SeatMoveGrabState},
state::Common,
wayland::handlers::data_device::get_dnd_icon,
};
use slog::Logger; use slog::Logger;
use smithay::{ use smithay::{
@ -151,7 +148,7 @@ pub fn cursor_custom_elements<R>(
hardware_cursor: bool, hardware_cursor: bool,
) -> Vec<CustomElem> ) -> Vec<CustomElem>
where where
R: AsGles2Renderer R: AsGles2Renderer,
{ {
let mut custom_elements = Vec::new(); let mut custom_elements = Vec::new();
@ -164,12 +161,17 @@ where
.shell .shell
.space_relative_output_geometry(pointer.current_location().to_i32_round(), output); .space_relative_output_geometry(pointer.current_location().to_i32_round(), output);
if let Some(grab) = seat.user_data().get::<SeatMoveGrabState>().unwrap().borrow() if let Some(grab) = seat
.as_ref().and_then(|state| state.render(seat, output)) .user_data()
.get::<SeatMoveGrabState>()
.unwrap()
.borrow()
.as_ref()
.and_then(|state| state.render(seat, output))
{ {
custom_elements.push(grab); custom_elements.push(grab);
} }
if let Some(wl_surface) = get_dnd_icon(seat) { if let Some(wl_surface) = get_dnd_icon(seat) {
custom_elements.push(cursor::draw_dnd_icon(wl_surface, location.to_i32_round()).into()); custom_elements.push(cursor::draw_dnd_icon(wl_surface, location.to_i32_round()).into());
} }
@ -245,16 +247,41 @@ where
} }
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
{ {
render_fullscreen(gpu, renderer, window, state, output, hardware_cursor, fps.as_deref_mut()) render_fullscreen(
gpu,
renderer,
window,
state,
output,
hardware_cursor,
fps.as_deref_mut(),
)
} }
} else { } else {
#[cfg(not(feature = "debug"))] #[cfg(not(feature = "debug"))]
{ {
render_desktop(gpu, renderer, age, state, space_idx, output, hardware_cursor) render_desktop(
gpu,
renderer,
age,
state,
space_idx,
output,
hardware_cursor,
)
} }
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
{ {
render_desktop(gpu, renderer, age, state, space_idx, output, hardware_cursor, fps.as_deref_mut()) render_desktop(
gpu,
renderer,
age,
state,
space_idx,
output,
hardware_cursor,
fps.as_deref_mut(),
)
} }
}; };
@ -318,7 +345,12 @@ where
} }
} }
custom_elements.extend(cursor_custom_elements(renderer, state, output, hardware_cursor)); custom_elements.extend(cursor_custom_elements(
renderer,
state,
output,
hardware_cursor,
));
state.shell.spaces[space_idx].space.render_output( state.shell.spaces[space_idx].space.render_output(
renderer, renderer,
@ -364,7 +396,12 @@ where
custom_elements.push(fps_overlay.into()); custom_elements.push(fps_overlay.into());
} }
custom_elements.extend(cursor_custom_elements(renderer, state, output, hardware_cursor)); custom_elements.extend(cursor_custom_elements(
renderer,
state,
output,
hardware_cursor,
));
renderer renderer
.render(mode.size, transform, |renderer, frame| { .render(mode.size, transform, |renderer, frame| {
@ -429,14 +466,7 @@ where
let loc = elem.location(scale); let loc = elem.location(scale);
let geo = elem.geometry(scale); let geo = elem.geometry(scale);
let elem_damage = elem.accumulated_damage(scale, None); let elem_damage = elem.accumulated_damage(scale, None);
elem.draw( elem.draw(renderer, frame, scale, loc, &[geo], &slog_scope::logger())?;
renderer,
frame,
scale,
loc,
&[geo],
&slog_scope::logger(),
)?;
damage.extend(elem_damage) damage.extend(elem_damage)
} }
Ok(Some(damage)) Ok(Some(damage))

View file

@ -9,7 +9,9 @@ pub use smithay::{
utils::{Logical, Physical, Point, Size, Transform}, utils::{Logical, Physical, Point, Size, Transform},
wayland::{ wayland::{
output::{Mode, Output}, output::{Mode, Output},
seat::{keysyms as KeySyms, Keysym, ModifiersState as KeyModifiers, XkbConfig as WlXkbConfig}, seat::{
keysyms as KeySyms, Keysym, ModifiersState as KeyModifiers, XkbConfig as WlXkbConfig,
},
}, },
}; };
use xkbcommon::xkb; use xkbcommon::xkb;

View file

@ -5,7 +5,7 @@ use smithay::{
backend::drm::DrmNode, backend::drm::DrmNode,
desktop::layer_map_for_output, desktop::layer_map_for_output,
reexports::wayland_server::Resource, reexports::wayland_server::Resource,
utils::{Physical, Rectangle, IsAlive}, utils::{IsAlive, Physical, Rectangle},
}; };
pub use smithay_egui::EguiFrame; pub use smithay_egui::EguiFrame;
@ -252,15 +252,36 @@ pub fn debug_ui(
ui.collapsing("Layers:", |ui| { ui.collapsing("Layers:", |ui| {
let map = layer_map_for_output(&output); let map = layer_map_for_output(&output);
for layer in map.layers() { for layer in map.layers() {
ui.collapsing(format!("{}/{:?}", layer.wl_surface().id(), layer.wl_surface().client_id()), |ui| { ui.collapsing(
ui.label(format!("Alive: {:?} {:?} {:?}", layer.alive(), layer.layer_surface().alive(), layer.wl_surface().alive())); format!(
ui.label(format!("Layer: {:?}", layer.layer())); "{}/{:?}",
ui.label(format!("Namespace: {:?}", layer.namespace())); layer.wl_surface().id(),
ui.label(format!("Geometry: {:?}", layer.bbox())); layer.wl_surface().client_id()
ui.label(format!("Anchor: {:?}", layer.cached_state().anchor)); ),
ui.label(format!("Margin: {:?}", layer.cached_state().margin)); |ui| {
ui.label(format!("Exclusive: {:?}", layer.cached_state().exclusive_zone)); ui.label(format!(
}); "Alive: {:?} {:?} {:?}",
layer.alive(),
layer.layer_surface().alive(),
layer.wl_surface().alive()
));
ui.label(format!("Layer: {:?}", layer.layer()));
ui.label(format!("Namespace: {:?}", layer.namespace()));
ui.label(format!("Geometry: {:?}", layer.bbox()));
ui.label(format!(
"Anchor: {:?}",
layer.cached_state().anchor
));
ui.label(format!(
"Margin: {:?}",
layer.cached_state().margin
));
ui.label(format!(
"Exclusive: {:?}",
layer.cached_state().exclusive_zone
));
},
);
} }
ui.label(format!("{:?}", map)); ui.label(format!("{:?}", map));
}); });

View file

@ -2,17 +2,14 @@
use crate::{ use crate::{
config::{Action, Config}, config::{Action, Config},
shell::{ shell::{grabs::SeatMoveGrabState, Workspace},
Workspace,
grabs::SeatMoveGrabState,
},
utils::prelude::*, utils::prelude::*,
}; };
use smithay::{ use smithay::{
backend::input::{Device, DeviceCapability, InputBackend, InputEvent, KeyState}, backend::input::{Device, DeviceCapability, InputBackend, InputEvent, KeyState},
desktop::{layer_map_for_output, Kind, WindowSurfaceType}, desktop::{layer_map_for_output, Kind, WindowSurfaceType},
reexports::wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource}, reexports::wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource},
utils::{Logical, Point, Rectangle, Size, Buffer}, utils::{Buffer, Logical, Point, Rectangle, Size},
wayland::{ wayland::{
data_device::set_data_device_focus, data_device::set_data_device_focus,
output::Output, output::Output,
@ -118,21 +115,16 @@ pub fn add_seat(dh: &DisplayHandle, config: &Config, name: String) -> Seat<State
// devices appear), we have to surrender to reality and just always expose a keyboard and pointer. // devices appear), we have to surrender to reality and just always expose a keyboard and pointer.
let dh_clone = dh.clone(); let dh_clone = dh.clone();
let conf = config.xkb_config(); let conf = config.xkb_config();
let _ = seat.add_keyboard( let _ = seat.add_keyboard((&conf).into(), 200, 25, move |seat, focus| {
(&conf).into(), if let Some(client) = focus.and_then(|s| dh_clone.get_client(s.id()).ok()) {
200, set_data_device_focus(&dh_clone, seat, Some(client));
25, let client2 = focus
move |seat, focus| { .and_then(|s| dh_clone.get_client(s.id()).ok())
if let Some(client) = .unwrap();
focus.and_then(|s| dh_clone.get_client(s.id()).ok()) set_primary_focus(&dh_clone, seat, Some(client2))
{ }
set_data_device_focus(&dh_clone, seat, Some(client)); });
let client2 = focus.and_then(|s| dh_clone.get_client(s.id()).ok()).unwrap();
set_primary_focus(&dh_clone, seat, Some(client2))
}
},
);
let owned_seat = seat.clone(); let owned_seat = seat.clone();
seat.add_pointer(move |status| { seat.add_pointer(move |status| {
*owned_seat *owned_seat
@ -178,7 +170,7 @@ impl State {
for cap in devices.remove_device(&device) { for cap in devices.remove_device(&device) {
match cap { match cap {
// TODO: Handle touch, tablet // TODO: Handle touch, tablet
_ => {}, _ => {}
} }
} }
break; break;
@ -391,11 +383,16 @@ impl State {
let home = match std::env::var("HOME") { let home = match std::env::var("HOME") {
Ok(home) => home, Ok(home) => home,
Err(err) => { Err(err) => {
slog_scope::error!("$HOME is not set, can't save screenshots: {}", err); slog_scope::error!(
"$HOME is not set, can't save screenshots: {}",
err
);
break; break;
} }
}; };
let timestamp = match std::time::SystemTime::UNIX_EPOCH.elapsed() { let timestamp = match std::time::SystemTime::UNIX_EPOCH
.elapsed()
{
Ok(duration) => duration.as_secs(), Ok(duration) => duration.as_secs(),
Err(err) => { Err(err) => {
slog_scope::error!("Unable to get timestamp, can't save screenshots: {}", err); slog_scope::error!("Unable to get timestamp, can't save screenshots: {}", err);
@ -403,17 +400,35 @@ impl State {
} }
}; };
for output in self.common.shell.outputs.clone().into_iter() { for output in self.common.shell.outputs.clone().into_iter() {
match self.backend.offscreen_for_output(&output, &mut self.common) { match self
.backend
.offscreen_for_output(&output, &mut self.common)
{
Ok((buffer, size)) => { Ok((buffer, size)) => {
let mut path = std::path::PathBuf::new(); let mut path = std::path::PathBuf::new();
path.push(&home); path.push(&home);
path.push(format!("{}_{}.png", output.name(), timestamp)); path.push(format!(
"{}_{}.png",
output.name(),
timestamp
));
fn write_png(path: impl AsRef<std::path::Path>, data: Vec<u8>, size: Size<i32, Buffer>) -> anyhow::Result<()> { fn write_png(
use std::{io, fs}; path: impl AsRef<std::path::Path>,
data: Vec<u8>,
size: Size<i32, Buffer>,
) -> anyhow::Result<()>
{
use std::{fs, io};
let file = io::BufWriter::new(fs::File::create(&path)?); let file = io::BufWriter::new(
let mut encoder = png::Encoder::new(file, size.w as u32, size.h as u32); fs::File::create(&path)?,
);
let mut encoder = png::Encoder::new(
file,
size.w as u32,
size.h as u32,
);
encoder.set_color(png::ColorType::Rgba); encoder.set_color(png::ColorType::Rgba);
encoder.set_depth(png::BitDepth::Eight); encoder.set_depth(png::BitDepth::Eight);
let mut writer = encoder.write_header()?; let mut writer = encoder.write_header()?;
@ -422,10 +437,18 @@ impl State {
} }
if let Err(err) = write_png(&path, buffer, size) { if let Err(err) = write_png(&path, buffer, size) {
slog_scope::error!("Unable to save screenshot at {}: {}", path.display(), err); slog_scope::error!(
"Unable to save screenshot at {}: {}",
path.display(),
err
);
} }
}, }
Err(err) => slog_scope::error!("Could not save screenshot for output {}: {}", output.name(), err), Err(err) => slog_scope::error!(
"Could not save screenshot for output {}: {}",
output.name(),
err
),
} }
} }
} }

View file

@ -1,27 +1,31 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::utils::prelude::*;
use super::Shell; use super::Shell;
use crate::utils::prelude::*;
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::State as WState;
use smithay::{ use smithay::{
backend::renderer::{Renderer, ImportAll}, backend::renderer::{ImportAll, Renderer},
desktop::{Kind, Window, draw_window, space::{RenderElement, SpaceOutputTuple}}, desktop::{
draw_window,
space::{RenderElement, SpaceOutputTuple},
Kind, Window,
},
reexports::{ reexports::{
wayland_protocols::xdg::shell::server::xdg_toplevel::State as XdgState, wayland_protocols::xdg::shell::server::xdg_toplevel::State as XdgState,
wayland_server::DisplayHandle, wayland_server::DisplayHandle,
}, },
utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale}, utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale},
wayland::{ wayland::{
output::Output,
seat::{ seat::{
AxisFrame, ButtonEvent, MotionEvent, PointerGrab, PointerGrabStartData, AxisFrame, ButtonEvent, MotionEvent, PointerGrab, PointerGrabStartData,
PointerInnerHandle, PointerInnerHandle,
}, },
seat::{Seat, Focus}, seat::{Focus, Seat},
output::Output,
Serial, Serial,
}, },
}; };
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::State as WState;
use std::cell::RefCell; use std::cell::RefCell;
impl Shell { impl Shell {
@ -34,31 +38,37 @@ impl Shell {
) { ) {
// TODO touch grab // TODO touch grab
if let Some(pointer) = seat.get_pointer() { if let Some(pointer) = seat.get_pointer() {
let workspace = self.space_for_window_mut(window.toplevel().wl_surface()).unwrap(); let workspace = self
.space_for_window_mut(window.toplevel().wl_surface())
.unwrap();
if workspace.fullscreen.values().any(|w| w == window) { if workspace.fullscreen.values().any(|w| w == window) {
return; return;
} }
let pos = pointer.current_location(); let pos = pointer.current_location();
let output = workspace.space.outputs_for_window(&window) let output = workspace
.space
.outputs_for_window(&window)
.into_iter() .into_iter()
.find(|o| o.geometry().contains(pos.to_i32_round())) .find(|o| o.geometry().contains(pos.to_i32_round()))
.unwrap(); .unwrap();
let mut initial_window_location = workspace.space.window_location(&window).unwrap(); let mut initial_window_location = workspace.space.window_location(&window).unwrap();
let output = match &window.toplevel() { let output = match &window.toplevel() {
Kind::Xdg(surface) => { Kind::Xdg(surface) => {
// If surface is maximized then unmaximize it // If surface is maximized then unmaximize it
let current_state = surface.current_state(); let current_state = surface.current_state();
if current_state.states.contains(XdgState::Maximized) { if current_state.states.contains(XdgState::Maximized) {
workspace.floating_layer.unmaximize_request(&mut workspace.space, window); workspace
.floating_layer
.unmaximize_request(&mut workspace.space, window);
let new_size = surface.with_pending_state(|state| state.size); let new_size = surface.with_pending_state(|state| state.size);
let ratio = pos.x / output.geometry().size.w as f64; let ratio = pos.x / output.geometry().size.w as f64;
initial_window_location = new_size.map(|size| ( initial_window_location = new_size
pos.x - (size.w as f64 * ratio), .map(|size| (pos.x - (size.w as f64 * ratio), pos.y).into())
pos.y, .unwrap_or_else(|| pos)
).into()).unwrap_or_else(|| pos).to_i32_round(); .to_i32_round();
} }
output output
@ -67,8 +77,8 @@ impl Shell {
let was_tiled = if workspace.tiling_layer.windows.contains(&window) { let was_tiled = if workspace.tiling_layer.windows.contains(&window) {
workspace workspace
.tiling_layer .tiling_layer
.unmap_window(&mut workspace.space, &window); .unmap_window(&mut workspace.space, &window);
true true
} else { } else {
workspace workspace
@ -76,19 +86,20 @@ impl Shell {
.unmap_window(&mut workspace.space, &window); .unmap_window(&mut workspace.space, &window);
false false
}; };
let workspace_handle = workspace.handle; let workspace_handle = workspace.handle;
let workspace_is_empty = workspace.space.windows().next().is_none(); let workspace_is_empty = workspace.space.windows().next().is_none();
if workspace_is_empty { if workspace_is_empty {
self.workspace_state.update().add_workspace_state(&workspace_handle, WState::Hidden); self.workspace_state
.update()
.add_workspace_state(&workspace_handle, WState::Hidden);
} }
self.toplevel_info_state self.toplevel_info_state
.toplevel_leave_workspace(&window, &workspace_handle); .toplevel_leave_workspace(&window, &workspace_handle);
self.toplevel_info_state self.toplevel_info_state
.toplevel_leave_output(&window, &output); .toplevel_leave_output(&window, &output);
let state = MoveGrabState { let state = MoveGrabState {
window: window.clone(), window: window.clone(),
was_tiled, was_tiled,
@ -97,25 +108,30 @@ impl Shell {
}; };
let grab = MoveSurfaceGrab::new(start_data, window.clone(), seat); let grab = MoveSurfaceGrab::new(start_data, window.clone(), seat);
*seat.user_data().get::<SeatMoveGrabState>().unwrap().borrow_mut() = Some(state); *seat
.user_data()
.get::<SeatMoveGrabState>()
.unwrap()
.borrow_mut() = Some(state);
pointer.set_grab(grab, serial, Focus::Clear); pointer.set_grab(grab, serial, Focus::Clear);
} }
} }
fn drop_move( fn drop_move(&mut self, dh: &DisplayHandle, seat: &Seat<State>, output: &Output) {
&mut self, if let Some(move_state) = seat
dh: &DisplayHandle, .user_data()
seat: &Seat<State>, .get::<SeatMoveGrabState>()
.unwrap()
output: &Output, .borrow_mut()
) { .take()
if let Some(move_state) = seat.user_data().get::<SeatMoveGrabState>().unwrap().borrow_mut().take() { {
let pointer = seat.get_pointer().unwrap(); let pointer = seat.get_pointer().unwrap();
let window = move_state.window; let window = move_state.window;
if window.alive() { if window.alive() {
let delta = pointer.current_location() - move_state.initial_cursor_location; let delta = pointer.current_location() - move_state.initial_cursor_location;
let window_location = (move_state.initial_window_location.to_f64() + delta).to_i32_round(); let window_location =
(move_state.initial_window_location.to_f64() + delta).to_i32_round();
let surface = window.toplevel().wl_surface().clone(); let surface = window.toplevel().wl_surface().clone();
let workspace_handle = self.active_space(output).handle; let workspace_handle = self.active_space(output).handle;
@ -137,9 +153,12 @@ impl Shell {
focus_stack.iter(), focus_stack.iter(),
); );
} else { } else {
workspace workspace.floating_layer.map_window(
.floating_layer &mut workspace.space,
.map_window(&mut workspace.space, window, &seat, window_location); window,
&seat,
window_location,
);
} }
self.set_focus(dh, Some(&surface), &seat, None); self.set_focus(dh, Some(&surface), &seat, None);
@ -175,14 +194,15 @@ where
fn id(&self) -> usize { fn id(&self) -> usize {
self.seat_id self.seat_id
} }
fn location(&self, scale: impl Into<Scale<f64>>) -> Point<f64, Physical> { fn location(&self, scale: impl Into<Scale<f64>>) -> Point<f64, Physical> {
(self.window_location - self.window.geometry().loc.to_f64()).to_physical(scale) (self.window_location - self.window.geometry().loc.to_f64()).to_physical(scale)
} }
fn geometry(&self, scale: impl Into<Scale<f64>>) -> Rectangle<i32, Physical> { fn geometry(&self, scale: impl Into<Scale<f64>>) -> Rectangle<i32, Physical> {
let scale = scale.into(); let scale = scale.into();
self.window.physical_bbox_with_popups(RenderElement::<R>::location(self, scale), scale) self.window
.physical_bbox_with_popups(RenderElement::<R>::location(self, scale), scale)
} }
fn accumulated_damage( fn accumulated_damage(
@ -191,15 +211,20 @@ where
for_values: Option<SpaceOutputTuple<'_, '_>>, for_values: Option<SpaceOutputTuple<'_, '_>>,
) -> Vec<Rectangle<i32, Physical>> { ) -> Vec<Rectangle<i32, Physical>> {
let scale = scale.into(); let scale = scale.into();
self.window.accumulated_damage(RenderElement::<R>::location(self, scale), scale, for_values.map(|t| (t.0, t.1))) self.window.accumulated_damage(
RenderElement::<R>::location(self, scale),
scale,
for_values.map(|t| (t.0, t.1)),
)
} }
fn opaque_regions( fn opaque_regions(
&self, &self,
scale: impl Into<Scale<f64>>, scale: impl Into<Scale<f64>>,
) -> Option<Vec<Rectangle<i32, Physical>>> { ) -> Option<Vec<Rectangle<i32, Physical>>> {
let scale = scale.into(); let scale = scale.into();
self.window.opaque_regions(RenderElement::<R>::location(self, scale), scale) self.window
.opaque_regions(RenderElement::<R>::location(self, scale), scale)
} }
fn draw( fn draw(
@ -218,19 +243,20 @@ where
impl MoveGrabState { impl MoveGrabState {
pub fn render<I>(&self, seat: &Seat<State>, output: &Output) -> Option<I> pub fn render<I>(&self, seat: &Seat<State>, output: &Output) -> Option<I>
where where
I: From<MoveGrabRenderElement> I: From<MoveGrabRenderElement>,
{ {
let cursor_at = seat.get_pointer().unwrap().current_location(); let cursor_at = seat.get_pointer().unwrap().current_location();
let delta = cursor_at - self.initial_cursor_location; let delta = cursor_at - self.initial_cursor_location;
let mut window_geo = self.window.bbox(); let mut window_geo = self.window.bbox();
window_geo.loc += (self.initial_window_location.to_f64() + delta).to_i32_round(); window_geo.loc += (self.initial_window_location.to_f64() + delta).to_i32_round();
if !output.geometry().intersection(window_geo).is_some() { if !output.geometry().intersection(window_geo).is_some() {
return None; return None;
} }
let delta = cursor_at - self.initial_cursor_location; let delta = cursor_at - self.initial_cursor_location;
let window_location = self.initial_window_location.to_f64() + delta - output.geometry().loc.to_f64(); let window_location =
self.initial_window_location.to_f64() + delta - output.geometry().loc.to_f64();
Some(I::from(MoveGrabRenderElement { Some(I::from(MoveGrabRenderElement {
seat_id: seat.id(), seat_id: seat.id(),
window: self.window.clone(), window: self.window.clone(),

View file

@ -5,7 +5,7 @@ use smithay::{
reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::{ reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::{
ResizeEdge, State as XdgState, ResizeEdge, State as XdgState,
}, },
utils::{IsAlive, Rectangle, Point, Logical}, utils::{IsAlive, Logical, Point, Rectangle},
wayland::{ wayland::{
compositor::with_states, compositor::with_states,
output::Output, output::Output,
@ -40,7 +40,13 @@ impl FloatingLayout {
Default::default() Default::default()
} }
pub fn map_window(&mut self, space: &mut Space, window: Window, seat: &Seat<State>, position: impl Into<Option<Point<i32, Logical>>>) { pub fn map_window(
&mut self,
space: &mut Space,
window: Window,
seat: &Seat<State>,
position: impl Into<Option<Point<i32, Logical>>>,
) {
if let Some(output) = super::output_from_seat(Some(seat), space) { if let Some(output) = super::output_from_seat(Some(seat), space) {
self.map_window_internal(space, window, &output, position.into()); self.map_window_internal(space, window, &output, position.into());
} else { } else {
@ -58,8 +64,17 @@ impl FloatingLayout {
// TODO make sure all windows are still visible on any output or move them // TODO make sure all windows are still visible on any output or move them
} }
fn map_window_internal(&mut self, space: &mut Space, window: Window, output: &Output, position: Option<Point<i32, Logical>>) { fn map_window_internal(
let last_geometry = window.user_data().get::<WindowUserData>().map(|u| u.lock().unwrap().last_geometry); &mut self,
space: &mut Space,
window: Window,
output: &Output,
position: Option<Point<i32, Logical>>,
) {
let last_geometry = window
.user_data()
.get::<WindowUserData>()
.map(|u| u.lock().unwrap().last_geometry);
let mut win_geo = window.geometry(); let mut win_geo = window.geometry();
let layers = layer_map_for_output(&output); let layers = layer_map_for_output(&output);
@ -112,10 +127,15 @@ impl FloatingLayout {
} }
} }
let position = position.or_else(|| last_geometry.map(|g| g.loc)).unwrap_or_else(|| ( let position = position
geometry.loc.x + (geometry.size.w / 2) - (win_geo.size.w / 2) + win_geo.loc.x, .or_else(|| last_geometry.map(|g| g.loc))
geometry.loc.y + (geometry.size.h / 2) - (win_geo.size.h / 2) + win_geo.loc.y, .unwrap_or_else(|| {
).into()); (
geometry.loc.x + (geometry.size.w / 2) - (win_geo.size.w / 2) + win_geo.loc.x,
geometry.loc.y + (geometry.size.h / 2) - (win_geo.size.h / 2) + win_geo.loc.y,
)
.into()
});
#[allow(irrefutable_let_patterns)] #[allow(irrefutable_let_patterns)]
if let Kind::Xdg(xdg) = &window.toplevel() { if let Kind::Xdg(xdg) = &window.toplevel() {
@ -138,19 +158,21 @@ impl FloatingLayout {
pub fn unmap_window(&mut self, space: &mut Space, window: &Window) { pub fn unmap_window(&mut self, space: &mut Space, window: &Window) {
#[allow(irrefutable_let_patterns)] #[allow(irrefutable_let_patterns)]
let is_maximized = match &window.toplevel() { let is_maximized = match &window.toplevel() {
Kind::Xdg(surface) => surface.with_pending_state(|state| { Kind::Xdg(surface) => {
state.states.contains(XdgState::Maximized) surface.with_pending_state(|state| state.states.contains(XdgState::Maximized))
}) }
}; };
if !is_maximized { if !is_maximized {
if let Some(location) = space.window_location(window) { if let Some(location) = space.window_location(window) {
let user_data = window.user_data(); let user_data = window.user_data();
user_data.insert_if_missing(|| WindowUserData::default()); user_data.insert_if_missing(|| WindowUserData::default());
user_data.get::<WindowUserData>().unwrap().lock().unwrap().last_geometry = Rectangle::from_loc_and_size( user_data
location, .get::<WindowUserData>()
window.geometry().size, .unwrap()
); .lock()
.unwrap()
.last_geometry = Rectangle::from_loc_and_size(location, window.geometry().size);
} }
} }
@ -162,16 +184,18 @@ impl FloatingLayout {
pub fn maximize_request(&mut self, space: &mut Space, window: &Window, output: &Output) { pub fn maximize_request(&mut self, space: &mut Space, window: &Window, output: &Output) {
let layers = layer_map_for_output(&output); let layers = layer_map_for_output(&output);
let geometry = layers.non_exclusive_zone(); let geometry = layers.non_exclusive_zone();
if let Some(location) = space.window_location(window) { if let Some(location) = space.window_location(window) {
let user_data = window.user_data(); let user_data = window.user_data();
user_data.insert_if_missing(|| WindowUserData::default()); user_data.insert_if_missing(|| WindowUserData::default());
user_data.get::<WindowUserData>().unwrap().lock().unwrap().last_geometry = Rectangle::from_loc_and_size( user_data
location, .get::<WindowUserData>()
window.geometry().size, .unwrap()
); .lock()
.unwrap()
.last_geometry = Rectangle::from_loc_and_size(location, window.geometry().size);
} }
space.map_window( space.map_window(
&window, &window,
(geometry.loc.x, geometry.loc.y), (geometry.loc.x, geometry.loc.y),
@ -189,7 +213,10 @@ impl FloatingLayout {
} }
pub fn unmaximize_request(&mut self, space: &mut Space, window: &Window) { pub fn unmaximize_request(&mut self, space: &mut Space, window: &Window) {
let last_geometry = window.user_data().get::<WindowUserData>().map(|u| u.lock().unwrap().last_geometry); let last_geometry = window
.user_data()
.get::<WindowUserData>()
.map(|u| u.lock().unwrap().last_geometry);
match window.toplevel() { match window.toplevel() {
Kind::Xdg(toplevel) => { Kind::Xdg(toplevel) => {
toplevel.with_pending_state(|state| { toplevel.with_pending_state(|state| {
@ -200,12 +227,7 @@ impl FloatingLayout {
} }
} }
if let Some(last_location) = last_geometry.map(|g| g.loc) { if let Some(last_location) = last_geometry.map(|g| g.loc) {
space.map_window( space.map_window(&window, last_location, FLOATING_INDEX, true);
&window,
last_location,
FLOATING_INDEX,
true,
);
} }
} }

View file

@ -26,7 +26,7 @@ use crate::{
utils::prelude::*, utils::prelude::*,
wayland::protocols::{ wayland::protocols::{
toplevel_info::ToplevelInfoState, toplevel_info::ToplevelInfoState,
toplevel_management::{ToplevelManagementState, ManagementCapabilities}, toplevel_management::{ManagementCapabilities, ToplevelManagementState},
workspace::{ workspace::{
WorkspaceCapabilities, WorkspaceGroupHandle, WorkspaceHandle, WorkspaceState, WorkspaceCapabilities, WorkspaceGroupHandle, WorkspaceHandle, WorkspaceState,
WorkspaceUpdateGuard, WorkspaceUpdateGuard,
@ -36,8 +36,8 @@ use crate::{
pub const MAX_WORKSPACES: usize = 10; pub const MAX_WORKSPACES: usize = 10;
pub mod focus; pub mod focus;
pub mod layout;
pub mod grabs; pub mod grabs;
pub mod layout;
mod workspace; mod workspace;
pub use self::workspace::*; pub use self::workspace::*;
@ -90,10 +90,14 @@ impl Shell {
let toplevel_info_state = ToplevelInfoState::new( let toplevel_info_state = ToplevelInfoState::new(
dh, dh,
//|client| client.get_data::<ClientState>().unwrap().privileged, //|client| client.get_data::<ClientState>().unwrap().privileged,
|_| true); |_| true,
);
let toplevel_management_state = ToplevelManagementState::new::<State, _>( let toplevel_management_state = ToplevelManagementState::new::<State, _>(
dh, dh,
vec![ManagementCapabilities::Close, ManagementCapabilities::Activate], vec![
ManagementCapabilities::Close,
ManagementCapabilities::Activate,
],
//|client| client.get_data::<ClientState>().unwrap().privileged, //|client| client.get_data::<ClientState>().unwrap().privileged,
|_| true, |_| true,
); );
@ -461,20 +465,32 @@ impl Shell {
} }
} }
pub fn outputs_for_surface<'a>(&'a self, surface: &'a WlSurface) -> impl Iterator<Item = Output> + 'a { pub fn outputs_for_surface<'a>(
&'a self,
surface: &'a WlSurface,
) -> impl Iterator<Item = Output> + 'a {
match self.outputs.iter().find(|o| { match self.outputs.iter().find(|o| {
let map = layer_map_for_output(o); let map = layer_map_for_output(o);
map.layer_for_surface(surface, WindowSurfaceType::ALL).is_some() map.layer_for_surface(surface, WindowSurfaceType::ALL)
.is_some()
}) { }) {
Some(output) => Box::new(std::iter::once(output.clone())) as Box<dyn Iterator<Item = Output>>, Some(output) => {
None => Box::new(self.spaces.iter().filter_map(|w| { Box::new(std::iter::once(output.clone())) as Box<dyn Iterator<Item = Output>>
if let Some(window) = w.space.window_for_surface(surface, WindowSurfaceType::ALL) { }
Some(w.space.outputs_for_window(&window).into_iter()) None => Box::new(
} else { self.spaces
None .iter()
} .filter_map(|w| {
}) if let Some(window) =
.flatten()), w.space.window_for_surface(surface, WindowSurfaceType::ALL)
{
Some(w.space.outputs_for_window(&window).into_iter())
} else {
None
}
})
.flatten(),
),
} }
} }
@ -541,20 +557,31 @@ impl Shell {
let workspace = &mut self.spaces[active]; let workspace = &mut self.spaces[active];
workspace.refresh(dh); workspace.refresh(dh);
if workspace.space.windows().next().is_none() if workspace.space.windows().next().is_none()
&& !self.workspace_state.workspace_states(&workspace.handle).map(|mut i| i.any(|s| s == &WState::Hidden)).unwrap_or(true) && !self
.workspace_state
.workspace_states(&workspace.handle)
.map(|mut i| i.any(|s| s == &WState::Hidden))
.unwrap_or(true)
{ {
self.workspace_state.update().add_workspace_state(&workspace.handle, WState::Hidden); self.workspace_state
.update()
.add_workspace_state(&workspace.handle, WState::Hidden);
} }
} }
} }
WorkspaceMode::Global { active, .. } => { WorkspaceMode::Global { active, .. } => {
let workspace = &mut self.spaces[*active]; let workspace = &mut self.spaces[*active];
workspace.refresh(dh); workspace.refresh(dh);
if workspace.space.windows().next().is_none() if workspace.space.windows().next().is_none()
&& !self.workspace_state.workspace_states(&workspace.handle).map(|mut i| i.any(|s| s == &WState::Hidden)).unwrap_or(true) && !self
.workspace_state
.workspace_states(&workspace.handle)
.map(|mut i| i.any(|s| s == &WState::Hidden))
.unwrap_or(true)
{ {
self.workspace_state.update().add_workspace_state(&workspace.handle, WState::Hidden); self.workspace_state
.update()
.add_workspace_state(&workspace.handle, WState::Hidden);
} }
} }
}; };
@ -682,9 +709,12 @@ impl Shell {
.toplevel_enter_workspace(&window, &new_workspace.handle); .toplevel_enter_workspace(&window, &new_workspace.handle);
let focus_stack = new_workspace.focus_stack(&seat); let focus_stack = new_workspace.focus_stack(&seat);
if layout::should_be_floating(&window) { if layout::should_be_floating(&window) {
new_workspace new_workspace.floating_layer.map_window(
.floating_layer &mut new_workspace.space,
.map_window(&mut new_workspace.space, window, &seat, None); window,
&seat,
None,
);
} else { } else {
new_workspace.tiling_layer.map_window( new_workspace.tiling_layer.map_window(
&mut new_workspace.space, &mut new_workspace.space,

View file

@ -69,7 +69,7 @@ impl Workspace {
.maximize_request(&mut self.space, window, output); .maximize_request(&mut self.space, window, output);
} }
} }
pub fn unmaximize_request(&mut self, window: &Window) { pub fn unmaximize_request(&mut self, window: &Window) {
if self.fullscreen.values().any(|w| w == window) { if self.fullscreen.values().any(|w| w == window) {
return self.unfullscreen_request(window); return self.unfullscreen_request(window);
@ -173,14 +173,16 @@ impl Workspace {
if self.tiling_enabled { if self.tiling_enabled {
for window in self.tiling_layer.windows.clone().into_iter() { for window in self.tiling_layer.windows.clone().into_iter() {
self.tiling_layer.unmap_window(&mut self.space, &window); self.tiling_layer.unmap_window(&mut self.space, &window);
self.floating_layer.map_window(&mut self.space, window, seat, None); self.floating_layer
.map_window(&mut self.space, window, seat, None);
} }
self.tiling_enabled = false; self.tiling_enabled = false;
} else { } else {
let focus_stack = self.focus_stack(seat); let focus_stack = self.focus_stack(seat);
for window in self.floating_layer.windows.clone().into_iter() { for window in self.floating_layer.windows.clone().into_iter() {
self.floating_layer.unmap_window(&mut self.space, &window); self.floating_layer.unmap_window(&mut self.space, &window);
self.tiling_layer.map_window(&mut self.space, window, seat, focus_stack.iter()) self.tiling_layer
.map_window(&mut self.space, window, seat, focus_stack.iter())
} }
self.tiling_enabled = true; self.tiling_enabled = true;
} }
@ -191,11 +193,13 @@ impl Workspace {
if let Some(window) = self.focus_stack(seat).iter().next().cloned() { if let Some(window) = self.focus_stack(seat).iter().next().cloned() {
if self.tiling_layer.windows.contains(&window) { if self.tiling_layer.windows.contains(&window) {
self.tiling_layer.unmap_window(&mut self.space, &window); self.tiling_layer.unmap_window(&mut self.space, &window);
self.floating_layer.map_window(&mut self.space, window, seat, None); self.floating_layer
.map_window(&mut self.space, window, seat, None);
} else if self.floating_layer.windows.contains(&window) { } else if self.floating_layer.windows.contains(&window) {
let focus_stack = self.focus_stack(seat); let focus_stack = self.focus_stack(seat);
self.floating_layer.unmap_window(&mut self.space, &window); self.floating_layer.unmap_window(&mut self.space, &window);
self.tiling_layer.map_window(&mut self.space, window, seat, focus_stack.iter()) self.tiling_layer
.map_window(&mut self.space, window, seat, focus_stack.iter())
} }
} }
} }

View file

@ -5,13 +5,11 @@ use crate::{
config::{Config, OutputConfig}, config::{Config, OutputConfig},
logger::LogState, logger::LogState,
shell::Shell, shell::Shell,
wayland::protocols::{
drm::WlDrmState,
export_dmabuf::ExportDmabufState,
output_configuration::OutputConfigurationState,
workspace::WorkspaceClientState,
},
utils::prelude::*, utils::prelude::*,
wayland::protocols::{
drm::WlDrmState, export_dmabuf::ExportDmabufState,
output_configuration::OutputConfigurationState, workspace::WorkspaceClientState,
},
}; };
use smithay::{ use smithay::{
backend::drm::DrmNode, backend::drm::DrmNode,
@ -22,6 +20,7 @@ use smithay::{
Display, DisplayHandle, Display, DisplayHandle,
}, },
}, },
utils::{Buffer, Size},
wayland::{ wayland::{
compositor::CompositorState, compositor::CompositorState,
data_device::DataDeviceState, data_device::DataDeviceState,
@ -32,7 +31,6 @@ use smithay::{
shm::ShmState, shm::ShmState,
viewporter::ViewporterState, viewporter::ViewporterState,
}, },
utils::{Size, Buffer},
}; };
use std::{ use std::{
@ -210,20 +208,17 @@ impl BackendData {
output: &Output, output: &Output,
state: &mut Common, state: &mut Common,
) -> anyhow::Result<(Vec<u8>, Size<i32, Buffer>)> { ) -> anyhow::Result<(Vec<u8>, Size<i32, Buffer>)> {
use crate::backend::render::{render_output, AsGles2Renderer, CustomElem};
use anyhow::Context; use anyhow::Context;
use smithay::backend::renderer::{ImportAll, Renderer};
use smithay::desktop::space::RenderElement;
use smithay::{ use smithay::{
backend::{ backend::{
drm::NodeType, drm::NodeType,
renderer::{ renderer::{gles2::Gles2Renderbuffer, Bind, ExportMem, Offscreen},
Bind, Offscreen, ExportMem,
gles2::Gles2Renderbuffer,
},
}, },
utils::Rectangle, utils::Rectangle,
}; };
use crate::backend::render::{render_output, AsGles2Renderer, CustomElem};
use smithay::backend::renderer::{Renderer, ImportAll};
use smithay::desktop::space::RenderElement;
fn capture<E, T, R>( fn capture<E, T, R>(
gpu: Option<DrmNode>, gpu: Option<DrmNode>,
@ -234,18 +229,23 @@ impl BackendData {
where where
E: std::error::Error + Send + Sync + 'static, E: std::error::Error + Send + Sync + 'static,
T: Clone + 'static, T: Clone + 'static,
R: Renderer<Error=E, TextureId=T> R: Renderer<Error = E, TextureId = T>
+ ImportAll + ImportAll
+ AsGles2Renderer + AsGles2Renderer
+ Offscreen<Gles2Renderbuffer> + Offscreen<Gles2Renderbuffer>
+ Bind<Gles2Renderbuffer> + Bind<Gles2Renderbuffer>
+ ExportMem, + ExportMem,
CustomElem: RenderElement<R>, CustomElem: RenderElement<R>,
{ {
let size = output.geometry().size.to_f64().to_buffer( let size = output
output.current_scale().fractional_scale(), .geometry()
output.current_transform().into() .size
).to_i32_round(); .to_f64()
.to_buffer(
output.current_scale().fractional_scale(),
output.current_transform().into(),
)
.to_i32_round();
let buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size)?; let buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size)?;
renderer.bind(buffer)?; renderer.bind(buffer)?;
render_output( render_output(
@ -257,7 +257,8 @@ impl BackendData {
false, false,
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
None, None,
).map_err(|err| anyhow::anyhow!("Failed to render output: {:?}", err))?; // lifetime issue, grrr )
.map_err(|err| anyhow::anyhow!("Failed to render output: {:?}", err))?; // lifetime issue, grrr
let mapping = renderer.copy_framebuffer(Rectangle::from_loc_and_size((0, 0), size))?; let mapping = renderer.copy_framebuffer(Rectangle::from_loc_and_size((0, 0), size))?;
let data = Vec::from(renderer.map_texture(&mapping)?); let data = Vec::from(renderer.map_texture(&mapping)?);
@ -268,12 +269,18 @@ impl BackendData {
BackendData::Winit(winit) => capture(None, winit.backend.renderer(), output, state), BackendData::Winit(winit) => capture(None, winit.backend.renderer(), output, state),
BackendData::X11(x11) => capture(None, &mut x11.renderer, output, state), BackendData::X11(x11) => capture(None, &mut x11.renderer, output, state),
BackendData::Kms(kms) => { BackendData::Kms(kms) => {
let node = kms.target_node_for_output(output) let node = kms
.target_node_for_output(output)
.unwrap_or(kms.primary) .unwrap_or(kms.primary)
.node_with_type(NodeType::Render) .node_with_type(NodeType::Render)
.with_context(|| "Unable to find node")??; .with_context(|| "Unable to find node")??;
capture(Some(node), &mut kms.api.renderer::<Gles2Renderbuffer>(&node, &node)?, output, state) capture(
}, Some(node),
&mut kms.api.renderer::<Gles2Renderbuffer>(&node, &node)?,
output,
state,
)
}
BackendData::Unset => unreachable!(), BackendData::Unset => unreachable!(),
} }
} }
@ -365,15 +372,17 @@ impl State {
drm_node: match &self.backend { drm_node: match &self.backend {
BackendData::Kms(kms_state) => { BackendData::Kms(kms_state) => {
match std::env::var("COSMIC_RENDER_AUTO_ASSIGN").map(|val| val.to_lowercase()) { match std::env::var("COSMIC_RENDER_AUTO_ASSIGN").map(|val| val.to_lowercase()) {
Ok(val) if val == "y" || val == "yes" || val == "true" => Ok(val) if val == "y" || val == "yes" || val == "true" => Some(
Some( kms_state
kms_state.target_node_for_output( .target_node_for_output(&active_output(
&active_output(&self.common.last_active_seat, &self.common) &self.common.last_active_seat,
).unwrap_or(kms_state.primary) &self.common,
), ))
.unwrap_or(kms_state.primary),
),
_ => Some(kms_state.primary), _ => Some(kms_state.primary),
} }
}, }
_ => None, _ => None,
}, },
privileged: false, privileged: false,

View file

@ -1,4 +1,7 @@
use crate::{input::{ActiveOutput, SeatId}, state::Common}; use crate::{
input::{ActiveOutput, SeatId},
state::Common,
};
use smithay::{ use smithay::{
utils::{Logical, Rectangle, Transform}, utils::{Logical, Rectangle, Transform},
wayland::{output::Output, seat::Seat}, wayland::{output::Output, seat::Seat},

View file

@ -207,7 +207,8 @@ impl CompositorHandler for State {
// schedule a new render // schedule a new render
for output in self.common.shell.outputs_for_surface(surface) { for output in self.common.shell.outputs_for_surface(surface) {
self.backend.schedule_render(&self.common.event_loop_handle, &output); self.backend
.schedule_render(&self.common.event_loop_handle, &output);
} }
} }
} }

View file

@ -4,13 +4,13 @@ use crate::state::State;
use smithay::{ use smithay::{
delegate_data_device, delegate_data_device,
reexports::wayland_server::protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface}, reexports::wayland_server::protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface},
utils::IsAlive,
wayland::{ wayland::{
data_device::{ data_device::{
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
}, },
seat::Seat, seat::Seat,
}, },
utils::IsAlive
}; };
use std::cell::RefCell; use std::cell::RefCell;

View file

@ -2,66 +2,65 @@
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use std::{ use std::{cell::RefCell, time::Instant};
cell::RefCell,
time::Instant,
};
use smithay::{ use smithay::{
backend::{ backend::{
drm::{DrmNode, NodeType}, drm::{DrmNode, NodeType},
egl::EGLDevice, egl::EGLDevice,
renderer::{ renderer::{
Bind, gles2::{Gles2Error, Gles2Renderbuffer, Gles2Renderer},
Offscreen,
ExportDma,
ImportAll,
Renderer,
gles2::{Gles2Renderer, Gles2Renderbuffer, Gles2Error},
utils::with_renderer_surface_state, utils::with_renderer_surface_state,
Bind, ExportDma, ImportAll, Offscreen, Renderer,
}, },
}, },
desktop::{space::RenderElement, Kind, Window, draw_window, draw_window_popups}, desktop::{draw_window, draw_window_popups, space::RenderElement, Kind, Window},
reexports::wayland_server::{protocol::wl_output::WlOutput, DisplayHandle, Resource},
utils::{IsAlive, Size, Transform},
wayland::{ wayland::{
compositor::{get_children, with_states, SurfaceAttributes}, compositor::{get_children, with_states, SurfaceAttributes},
dmabuf::get_dmabuf, dmabuf::get_dmabuf,
output::Output, output::Output,
seat::CursorImageStatus, seat::CursorImageStatus,
}, },
reexports::{
wayland_server::{DisplayHandle, Resource, protocol::wl_output::WlOutput},
},
utils::{IsAlive, Size, Transform},
}; };
use crate::{ use crate::{
backend::render::{render_output, render_workspace, cursor::draw_cursor, AsGles2Renderer, CustomElem}, backend::render::{
cursor::draw_cursor, render_output, render_workspace, AsGles2Renderer, CustomElem,
},
state::{BackendData, ClientState, Common}, state::{BackendData, ClientState, Common},
utils::prelude::*, utils::prelude::*,
wayland::protocols::{ wayland::protocols::{
export_dmabuf::{ export_dmabuf::{delegate_export_dmabuf, Capture, CaptureError, ExportDmabufHandler},
delegate_export_dmabuf, ExportDmabufHandler, Capture, CaptureError,
},
workspace::WorkspaceHandle, workspace::WorkspaceHandle,
}, },
}; };
impl ExportDmabufHandler for State { impl ExportDmabufHandler for State {
fn capture_output(&mut self, _dh: &DisplayHandle, output: WlOutput, overlay_cursor: bool) -> Result<Capture, CaptureError> { fn capture_output(
&mut self,
_dh: &DisplayHandle,
output: WlOutput,
overlay_cursor: bool,
) -> Result<Capture, CaptureError> {
let output = Output::from_resource(&output) let output = Output::from_resource(&output)
.ok_or(CaptureError::Permanent(anyhow!("Output is gone").into()))?; .ok_or(CaptureError::Permanent(anyhow!("Output is gone").into()))?;
let renderer = match self.backend { let renderer = match self.backend {
BackendData::Kms(ref mut kms) => { BackendData::Kms(ref mut kms) => {
// the kms backend just keeps its dmabufs easily accessible for capture. // the kms backend just keeps its dmabufs easily accessible for capture.
return kms.capture_output(&output) return kms
.capture_output(&output)
.map(|(device, dmabuf, presentation_time)| Capture { .map(|(device, dmabuf, presentation_time)| Capture {
device, device,
dmabuf, dmabuf,
presentation_time, presentation_time,
}) })
.ok_or(CaptureError::Temporary(anyhow!("Surface not initialized yet").into())); .ok_or(CaptureError::Temporary(
}, anyhow!("Surface not initialized yet").into(),
));
}
BackendData::Winit(ref mut winit) => winit.backend.renderer(), BackendData::Winit(ref mut winit) => winit.backend.renderer(),
BackendData::X11(ref mut x11) => &mut x11.renderer, BackendData::X11(ref mut x11) => &mut x11.renderer,
_ => unreachable!(), _ => unreachable!(),
@ -70,14 +69,20 @@ impl ExportDmabufHandler for State {
.context("Failed to find DrmNode") .context("Failed to find DrmNode")
.map_err(|err| CaptureError::Permanent(err.into()))?; .map_err(|err| CaptureError::Permanent(err.into()))?;
let size = output.geometry().size.to_f64().to_buffer( let size = output
output.current_scale().fractional_scale(), .geometry()
output.current_transform().into() .size
).to_i32_round(); .to_f64()
.to_buffer(
output.current_scale().fractional_scale(),
output.current_transform().into(),
)
.to_i32_round();
let buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size) let buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size)
.context("Failed to create render buffer for offscreen capture") .context("Failed to create render buffer for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
renderer.bind(buffer) renderer
.bind(buffer)
.context("Failed to bind render buffer for offscreen capture") .context("Failed to bind render buffer for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
render_output( render_output(
@ -90,9 +95,10 @@ impl ExportDmabufHandler for State {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
None, None,
) )
.context("Failed to render desktop for offscreen capture") .context("Failed to render desktop for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
let dmabuf = renderer.export_framebuffer(size) let dmabuf = renderer
.export_framebuffer(size)
.context("Failed to export buffer for offscreen capture") .context("Failed to export buffer for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
@ -103,10 +109,21 @@ impl ExportDmabufHandler for State {
}) })
} }
fn capture_workspace(&mut self, _dh: &DisplayHandle, workspace: WorkspaceHandle, wl_output: WlOutput, overlay_cursor: bool) -> Result<Capture, CaptureError> { fn capture_workspace(
&mut self,
_dh: &DisplayHandle,
workspace: WorkspaceHandle,
wl_output: WlOutput,
overlay_cursor: bool,
) -> Result<Capture, CaptureError> {
let output = Output::from_resource(&wl_output) let output = Output::from_resource(&wl_output)
.ok_or(CaptureError::Permanent(anyhow!("Output is gone").into()))?; .ok_or(CaptureError::Permanent(anyhow!("Output is gone").into()))?;
let workspace = self.common.shell.spaces.iter().find(|w| w.handle == workspace) let workspace = self
.common
.shell
.spaces
.iter()
.find(|w| w.handle == workspace)
.ok_or(CaptureError::Permanent(anyhow!("Workspace is gone").into()))? .ok_or(CaptureError::Permanent(anyhow!("Workspace is gone").into()))?
.idx; .idx;
if self.common.shell.active_space(&output).idx == workspace { if self.common.shell.active_space(&output).idx == workspace {
@ -117,50 +134,66 @@ impl ExportDmabufHandler for State {
let device = device_from_renderer(winit.backend.renderer()) let device = device_from_renderer(winit.backend.renderer())
.context("Failed to find DrmNode") .context("Failed to find DrmNode")
.map_err(|err| CaptureError::Permanent(err.into()))?; .map_err(|err| CaptureError::Permanent(err.into()))?;
capture_workspace(device, winit.backend.renderer(), &output, workspace, &mut self.common) capture_workspace(
}, device,
winit.backend.renderer(),
&output,
workspace,
&mut self.common,
)
}
BackendData::X11(ref mut x11) => { BackendData::X11(ref mut x11) => {
let device = device_from_renderer(&x11.renderer) let device = device_from_renderer(&x11.renderer)
.context("Failed to find DrmNode") .context("Failed to find DrmNode")
.map_err(|err| CaptureError::Permanent(err.into()))?; .map_err(|err| CaptureError::Permanent(err.into()))?;
capture_workspace(device, &mut x11.renderer, &output, workspace, &mut self.common) capture_workspace(
}, device,
&mut x11.renderer,
&output,
workspace,
&mut self.common,
)
}
BackendData::Kms(ref mut kms) => { BackendData::Kms(ref mut kms) => {
let node = kms.target_node_for_output(&output) let node = kms
.target_node_for_output(&output)
.unwrap_or(kms.primary) .unwrap_or(kms.primary)
.node_with_type(NodeType::Render) .node_with_type(NodeType::Render)
.with_context(|| "Unable to find node") .with_context(|| "Unable to find node")
.map_err(|x| CaptureError::Permanent(x.into()))? .map_err(|x| CaptureError::Permanent(x.into()))?
.map_err(|x| CaptureError::Permanent(x.into()))?; .map_err(|x| CaptureError::Permanent(x.into()))?;
let mut renderer = kms.api.renderer::<Gles2Renderbuffer>(&node, &node) let mut renderer = kms
.api
.renderer::<Gles2Renderbuffer>(&node, &node)
.with_context(|| format!("Failed to optain renderer for {:?}", node)) .with_context(|| format!("Failed to optain renderer for {:?}", node))
.map_err(|x| CaptureError::Permanent(x.into()))?; .map_err(|x| CaptureError::Permanent(x.into()))?;
capture_workspace( capture_workspace(node, &mut renderer, &output, workspace, &mut self.common)
node, }
&mut renderer,
&output,
workspace,
&mut self.common,
)
},
BackendData::Unset => unreachable!(), BackendData::Unset => unreachable!(),
} }
} }
} }
fn capture_toplevel(&mut self, dh: &DisplayHandle, window: Window, overlay_cursor: bool) -> Result<Capture, CaptureError> { fn capture_toplevel(
&mut self,
dh: &DisplayHandle,
window: Window,
overlay_cursor: bool,
) -> Result<Capture, CaptureError> {
let Kind::Xdg(xdg) = window.toplevel(); let Kind::Xdg(xdg) = window.toplevel();
let surface = xdg.wl_surface(); let surface = xdg.wl_surface();
let window_transform = with_states(surface, |states| states let window_transform = with_states(surface, |states| {
.cached_state states
.current::<SurfaceAttributes>() .cached_state
.buffer_transform .current::<SurfaceAttributes>()
.into() .buffer_transform
); .into()
});
let workspace = self.common.shell.space_for_window(surface); let workspace = self.common.shell.space_for_window(surface);
let pointers = if overlay_cursor && workspace.is_some() { let pointers = if overlay_cursor && workspace.is_some() {
self.common.seats self.common
.seats
.iter() .iter()
.filter_map(|seat| { .filter_map(|seat| {
let cursor_status = seat let cursor_status = seat
@ -181,14 +214,22 @@ impl ExportDmabufHandler for State {
let workspace = workspace.as_deref()?; let workspace = workspace.as_deref()?;
let loc = seat.get_pointer().map(|ptr| ptr.current_location())?; let loc = seat.get_pointer().map(|ptr| ptr.current_location())?;
let output = active_output(seat, &self.common); let output = active_output(seat, &self.common);
if self.common.shell.active_space(&output).idx == workspace.idx { if self.common.shell.active_space(&output).idx == workspace.idx {
let relative = self.common.shell.space_relative_output_geometry(loc, &output); let relative = self
.common
.shell
.space_relative_output_geometry(loc, &output);
// unwrap is safe, because we got this workspace from `space_for_window`. It has to contain the window. // unwrap is safe, because we got this workspace from `space_for_window`. It has to contain the window.
let bbox = workspace.space.window_bbox(&window).unwrap(); let bbox = workspace.space.window_bbox(&window).unwrap();
bbox.contains(relative.to_i32_round()).then_some((seat, (relative - bbox.loc.to_f64()).to_i32_round())) bbox.contains(relative.to_i32_round())
} else { None } .then_some((seat, (relative - bbox.loc.to_f64()).to_i32_round()))
} else { None } } else {
None
}
} else {
None
}
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
} else { } else {
@ -198,7 +239,8 @@ impl ExportDmabufHandler for State {
let device = match self.backend { let device = match self.backend {
BackendData::Winit(ref mut winit) => device_from_renderer(winit.backend.renderer()), BackendData::Winit(ref mut winit) => device_from_renderer(winit.backend.renderer()),
BackendData::X11(ref x11) => device_from_renderer(&x11.renderer), BackendData::X11(ref x11) => device_from_renderer(&x11.renderer),
BackendData::Kms(ref kms) => Ok(dh.get_client(window.toplevel().wl_surface().id()) BackendData::Kms(ref kms) => Ok(dh
.get_client(window.toplevel().wl_surface().id())
.ok() .ok()
.with_context(|| "Unable to find matching wayland client") .with_context(|| "Unable to find matching wayland client")
.map_err(|x| CaptureError::Permanent(x.into()))? .map_err(|x| CaptureError::Permanent(x.into()))?
@ -209,12 +251,18 @@ impl ExportDmabufHandler for State {
.unwrap_or_else(|| kms.primary.clone())), .unwrap_or_else(|| kms.primary.clone())),
_ => unreachable!(), _ => unreachable!(),
} }
.context("Failed to find DrmNode") .context("Failed to find DrmNode")
.map_err(|err| CaptureError::Permanent(err.into()))?; .map_err(|err| CaptureError::Permanent(err.into()))?;
// first lets check, if we can just send a dmabuf from the client directly // first lets check, if we can just send a dmabuf from the client directly
if pointers.is_empty() && window_transform == Transform::Normal && get_children(surface).is_empty() && self.common.shell.popups.find_popup(surface).is_none() { if pointers.is_empty()
let dmabuf = with_renderer_surface_state(surface, |state| state.wl_buffer().and_then(|buf| get_dmabuf(buf).ok())); && window_transform == Transform::Normal
&& get_children(surface).is_empty()
&& self.common.shell.popups.find_popup(surface).is_none()
{
let dmabuf = with_renderer_surface_state(surface, |state| {
state.wl_buffer().and_then(|buf| get_dmabuf(buf).ok())
});
if let Some(dmabuf) = dmabuf { if let Some(dmabuf) = dmabuf {
return Ok(Capture { return Ok(Capture {
device, device,
@ -230,47 +278,77 @@ impl ExportDmabufHandler for State {
BackendData::Winit(ref mut winit) => winit.backend.renderer(), BackendData::Winit(ref mut winit) => winit.backend.renderer(),
BackendData::X11(ref mut x11) => &mut x11.renderer, BackendData::X11(ref mut x11) => &mut x11.renderer,
BackendData::Kms(ref mut kms) => { BackendData::Kms(ref mut kms) => {
_tmp_multirenderer = Some(kms.api.renderer::<Gles2Renderbuffer>(&device, &device) _tmp_multirenderer = Some(
.with_context(|| format!("Failed to optain renderer for {:?}", device)) kms.api
.map_err(|x| CaptureError::Permanent(x.into()))?); .renderer::<Gles2Renderbuffer>(&device, &device)
.with_context(|| format!("Failed to optain renderer for {:?}", device))
.map_err(|x| CaptureError::Permanent(x.into()))?,
);
_tmp_multirenderer.as_mut().unwrap().as_gles2() _tmp_multirenderer.as_mut().unwrap().as_gles2()
}, }
BackendData::Unset => unreachable!(), BackendData::Unset => unreachable!(),
}; };
let bbox = window.bbox_with_popups(); let bbox = window.bbox_with_popups();
let size = bbox.size + Size::from((-bbox.loc.x, -bbox.loc.y)); let size = bbox.size + Size::from((-bbox.loc.x, -bbox.loc.y));
let buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size.to_buffer(1, window_transform)) let buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(
.context("Failed to create render buffer for offscreen capture") renderer,
.map_err(|err| CaptureError::Temporary(err.into()))?; size.to_buffer(1, window_transform),
renderer.bind(buffer) )
.context("Failed to create render buffer for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?;
renderer
.bind(buffer)
.context("Failed to bind render buffer for offscreen capture") .context("Failed to bind render buffer for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
renderer.render(size.to_physical(1), Transform::Normal, |renderer, frame| { renderer
let log = slog_scope::logger(); .render(size.to_physical(1), Transform::Normal, |renderer, frame| {
let damage = &[window.physical_bbox_with_popups((0.0, 0.0), 1.0)]; let log = slog_scope::logger();
draw_window(renderer, frame, &window, 1.0, (0.0, 0.0), damage, &log)?; let damage = &[window.physical_bbox_with_popups((0.0, 0.0), 1.0)];
draw_window_popups(renderer, frame, &window, 1.0, (0.0, 0.0), damage, &log)?; draw_window(renderer, frame, &window, 1.0, (0.0, 0.0), damage, &log)?;
for (seat, loc) in pointers.into_iter() { draw_window_popups(renderer, frame, &window, 1.0, (0.0, 0.0), damage, &log)?;
if let Some(cursor_elem) = draw_cursor::<_, CustomElem>(renderer, seat, loc, &self.common.start_time, true) { for (seat, loc) in pointers.into_iter() {
let damage = RenderElement::<Gles2Renderer>::accumulated_damage(&cursor_elem, 1.0, None); if let Some(cursor_elem) = draw_cursor::<_, CustomElem>(
cursor_elem.draw(renderer, frame, 1.0, loc.to_physical(1.0), &damage, &log)?; renderer,
seat,
loc,
&self.common.start_time,
true,
) {
let damage = RenderElement::<Gles2Renderer>::accumulated_damage(
&cursor_elem,
1.0,
None,
);
cursor_elem.draw(
renderer,
frame,
1.0,
loc.to_physical(1.0),
&damage,
&log,
)?;
}
} }
} Result::<(), Gles2Error>::Ok(())
Result::<(), Gles2Error>::Ok(()) })
})
.context("Failed to render window for offscreen capture") .context("Failed to render window for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))? .map_err(|err| CaptureError::Temporary(err.into()))?
.context("Failed to render window for offscreen capture") .context("Failed to render window for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
let dmabuf = renderer.export_framebuffer(size.to_buffer(1, window_transform)) let dmabuf = renderer
.export_framebuffer(size.to_buffer(1, window_transform))
.context("Failed to export buffer for offscreen capture") .context("Failed to export buffer for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
Ok(Capture { device, dmabuf, presentation_time: Instant::now() }) Ok(Capture {
device,
dmabuf,
presentation_time: Instant::now(),
})
} }
fn start_time(&mut self) -> Instant { fn start_time(&mut self) -> Instant {
self.common.start_time self.common.start_time
} }
@ -286,22 +364,28 @@ fn capture_workspace<E, T, R>(
where where
E: std::error::Error + Send + Sync + 'static, E: std::error::Error + Send + Sync + 'static,
T: Clone + 'static, T: Clone + 'static,
R: Renderer<Error=E, TextureId=T> R: Renderer<Error = E, TextureId = T>
+ ImportAll + ImportAll
+ AsGles2Renderer + AsGles2Renderer
+ Offscreen<Gles2Renderbuffer> + Offscreen<Gles2Renderbuffer>
+ Bind<Gles2Renderbuffer> + Bind<Gles2Renderbuffer>
+ ExportDma, + ExportDma,
CustomElem: RenderElement<R>, CustomElem: RenderElement<R>,
{ {
let size = output.geometry().size.to_f64().to_buffer( let size = output
output.current_scale().fractional_scale(), .geometry()
output.current_transform().into() .size
).to_i32_round(); .to_f64()
.to_buffer(
output.current_scale().fractional_scale(),
output.current_transform().into(),
)
.to_i32_round();
let buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size) let buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size)
.context("Failed to create render buffer for offscreen capture") .context("Failed to create render buffer for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
renderer.bind(buffer) renderer
.bind(buffer)
.context("Failed to bind render buffer for offscreen capture") .context("Failed to bind render buffer for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
render_workspace( render_workspace(
@ -315,19 +399,26 @@ where
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
None, None,
) )
.map_err(|err| anyhow!("Failed to render desktop for offscreen capture: {:?}", err)) // meh.. .map_err(|err| anyhow!("Failed to render desktop for offscreen capture: {:?}", err)) // meh..
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
let dmabuf = renderer.export_framebuffer(size) let dmabuf = renderer
.export_framebuffer(size)
.context("Failed to export buffer for offscreen capture") .context("Failed to export buffer for offscreen capture")
.map_err(|err| CaptureError::Temporary(err.into()))?; .map_err(|err| CaptureError::Temporary(err.into()))?;
Ok(Capture { device: gpu, dmabuf, presentation_time: Instant::now() }) Ok(Capture {
device: gpu,
dmabuf,
presentation_time: Instant::now(),
})
} }
fn device_from_renderer(renderer: &Gles2Renderer) -> Result<DrmNode> { fn device_from_renderer(renderer: &Gles2Renderer) -> Result<DrmNode> {
EGLDevice::device_for_display(renderer.egl_context().display())? EGLDevice::device_for_display(renderer.egl_context().display())?
.try_get_render_node()? .try_get_render_node()?
.ok_or(anyhow!("No node associated with context (software context?)")) .ok_or(anyhow!(
"No node associated with context (software context?)"
))
} }
delegate_export_dmabuf!(State); delegate_export_dmabuf!(State);

View file

@ -19,18 +19,19 @@ impl ToplevelManagementHandler for State {
} }
fn activate(&mut self, dh: &DisplayHandle, window: &Window, seat: Option<Seat<Self>>) { fn activate(&mut self, dh: &DisplayHandle, window: &Window, seat: Option<Seat<Self>>) {
if let Some(idx) = self.common.shell.space_for_window(window.toplevel().wl_surface()).map(|w| w.idx) { if let Some(idx) = self
.common
.shell
.space_for_window(window.toplevel().wl_surface())
.map(|w| w.idx)
{
let seat = seat.unwrap_or(self.common.last_active_seat.clone()); let seat = seat.unwrap_or(self.common.last_active_seat.clone());
let output = active_output(&seat, &self.common); let output = active_output(&seat, &self.common);
if self.common.shell.active_space(&output).idx != idx { if self.common.shell.active_space(&output).idx != idx {
self.common.shell.activate(&seat, &output, idx as usize); self.common.shell.activate(&seat, &output, idx as usize);
} }
self.common.set_focus( self.common
dh, .set_focus(dh, Some(window.toplevel().wl_surface()), &seat, None);
Some(window.toplevel().wl_surface()),
&seat,
None,
);
} }
} }

View file

@ -181,7 +181,9 @@ impl XdgShellHandler for State {
.unwrap() .unwrap()
.clone(); .clone();
self.common.shell.move_request(&window, &seat, serial, start_data); self.common
.shell
.move_request(&window, &seat, serial, start_data);
} }
} }

View file

@ -87,7 +87,12 @@ fn unconstrain_xdg_popup(
if let Some(output_rect) = space if let Some(output_rect) = space
.outputs_for_window(window) .outputs_for_window(window)
.into_iter() .into_iter()
.find(|o| space.output_geometry(o).map(|rect| rect.contains(anchor_point)).unwrap_or(false)) .find(|o| {
space
.output_geometry(o)
.map(|rect| rect.contains(anchor_point))
.unwrap_or(false)
})
.map(|o| space.output_geometry(&o).unwrap()) .map(|o| space.output_geometry(&o).unwrap())
{ {
// the output_rect represented relative to the parents coordinate system // the output_rect represented relative to the parents coordinate system

View file

@ -26,8 +26,8 @@ use smithay::{
Format, Fourcc, Modifier, Format, Fourcc, Modifier,
}, },
reexports::wayland_server::{ reexports::wayland_server::{
backend::GlobalId, protocol::wl_buffer::WlBuffer, Client, DataInit, backend::GlobalId, protocol::wl_buffer::WlBuffer, Client, DataInit, Dispatch,
Dispatch, DisplayHandle, GlobalDispatch, New, Resource, DisplayHandle, GlobalDispatch, New, Resource,
}, },
wayland::{ wayland::{
buffer::BufferHandler, buffer::BufferHandler,

View file

@ -1,46 +1,33 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use smithay::{
backend::{
allocator::{dmabuf::Dmabuf, Buffer},
drm::DrmNode,
},
desktop::Window,
reexports::wayland_server::{
self, backend::GlobalId, protocol::wl_output::WlOutput, Client, Dispatch, DisplayHandle,
GlobalDispatch,
},
};
use std::{ use std::{
fs::File, fs::File,
io::{Seek, SeekFrom}, io::{Seek, SeekFrom},
os::unix::io::{FromRawFd, IntoRawFd}, os::unix::io::{FromRawFd, IntoRawFd},
time::Instant, time::Instant,
}; };
use smithay::{
backend::{
allocator::{
Buffer,
dmabuf::Dmabuf,
},
drm::DrmNode,
},
desktop::Window,
reexports::{
wayland_server::{
self,
Client,
Dispatch,
GlobalDispatch,
DisplayHandle,
backend::GlobalId,
protocol::wl_output::WlOutput,
},
},
};
use cosmic_protocols::{ use cosmic_protocols::export_dmabuf::v1::server::{
export_dmabuf::v1::server::{ zcosmic_export_dmabuf_frame_v1::{self, CancelReason, Flags, ZcosmicExportDmabufFrameV1},
zcosmic_export_dmabuf_manager_v1::{self, ZcosmicExportDmabufManagerV1}, zcosmic_export_dmabuf_manager_v1::{self, ZcosmicExportDmabufManagerV1},
zcosmic_export_dmabuf_frame_v1::{self, CancelReason, Flags, ZcosmicExportDmabufFrameV1},
},
}; };
use crate::wayland::protocols::{ use crate::wayland::protocols::{
toplevel_info::{ToplevelInfoHandler, window_from_handle}, toplevel_info::{window_from_handle, ToplevelInfoHandler},
workspace::{WorkspaceHandle, WorkspaceHandler}, workspace::{WorkspaceHandle, WorkspaceHandler},
}; };
/// Export Dmabuf global state /// Export Dmabuf global state
#[derive(Debug)] #[derive(Debug)]
pub struct ExportDmabufState { pub struct ExportDmabufState {
@ -63,9 +50,12 @@ impl ExportDmabufState {
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static, F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
{ {
ExportDmabufState { ExportDmabufState {
global: display.create_global::<D, ZcosmicExportDmabufManagerV1, _>(1, ExportDmabufGlobalData { global: display.create_global::<D, ZcosmicExportDmabufManagerV1, _>(
filter: Box::new(client_filter), 1,
}), ExportDmabufGlobalData {
filter: Box::new(client_filter),
},
),
} }
} }
@ -88,18 +78,35 @@ pub struct Capture {
} }
pub trait ExportDmabufHandler { pub trait ExportDmabufHandler {
fn capture_output(&mut self, dh: &DisplayHandle, output: WlOutput, overlay_cursor: bool) -> Result<Capture, CaptureError>; fn capture_output(
fn capture_workspace(&mut self, dh: &DisplayHandle, workspace: WorkspaceHandle, output: WlOutput, overlay_cursor: bool) -> Result<Capture, CaptureError>; &mut self,
fn capture_toplevel(&mut self, dh: &DisplayHandle, toplevel: Window, overlay_cursor: bool) -> Result<Capture, CaptureError>; dh: &DisplayHandle,
output: WlOutput,
overlay_cursor: bool,
) -> Result<Capture, CaptureError>;
fn capture_workspace(
&mut self,
dh: &DisplayHandle,
workspace: WorkspaceHandle,
output: WlOutput,
overlay_cursor: bool,
) -> Result<Capture, CaptureError>;
fn capture_toplevel(
&mut self,
dh: &DisplayHandle,
toplevel: Window,
overlay_cursor: bool,
) -> Result<Capture, CaptureError>;
fn start_time(&mut self) -> Instant; fn start_time(&mut self) -> Instant;
} }
impl<D> GlobalDispatch<ZcosmicExportDmabufManagerV1, ExportDmabufGlobalData, D> for ExportDmabufState impl<D> GlobalDispatch<ZcosmicExportDmabufManagerV1, ExportDmabufGlobalData, D>
for ExportDmabufState
where where
D: GlobalDispatch<ZcosmicExportDmabufManagerV1, ExportDmabufGlobalData> D: GlobalDispatch<ZcosmicExportDmabufManagerV1, ExportDmabufGlobalData>
+ Dispatch<ZcosmicExportDmabufManagerV1, ()> + Dispatch<ZcosmicExportDmabufManagerV1, ()>
+ Dispatch<ZcosmicExportDmabufFrameV1, ()> + Dispatch<ZcosmicExportDmabufFrameV1, ()>
+ ExportDmabufHandler, + ExportDmabufHandler,
{ {
fn bind( fn bind(
_state: &mut D, _state: &mut D,
@ -120,11 +127,11 @@ where
impl<D> Dispatch<ZcosmicExportDmabufManagerV1, (), D> for ExportDmabufState impl<D> Dispatch<ZcosmicExportDmabufManagerV1, (), D> for ExportDmabufState
where where
D: GlobalDispatch<ZcosmicExportDmabufManagerV1, ExportDmabufGlobalData> D: GlobalDispatch<ZcosmicExportDmabufManagerV1, ExportDmabufGlobalData>
+ Dispatch<ZcosmicExportDmabufManagerV1, ()> + Dispatch<ZcosmicExportDmabufManagerV1, ()>
+ Dispatch<ZcosmicExportDmabufFrameV1, ()> + Dispatch<ZcosmicExportDmabufFrameV1, ()>
+ ExportDmabufHandler + ExportDmabufHandler
+ WorkspaceHandler + WorkspaceHandler
+ ToplevelInfoHandler + ToplevelInfoHandler,
{ {
fn request( fn request(
state: &mut D, state: &mut D,
@ -147,7 +154,7 @@ where
Ok(capture) => handle_capture(capture, frame, start_time), Ok(capture) => handle_capture(capture, frame, start_time),
Err(err) => frame.cancel(err.into()), Err(err) => frame.cancel(err.into()),
} }
}, }
zcosmic_export_dmabuf_manager_v1::Request::CaptureWorkspace { zcosmic_export_dmabuf_manager_v1::Request::CaptureWorkspace {
frame, frame,
overlay_cursor, overlay_cursor,
@ -157,14 +164,19 @@ where
let frame = data_init.init(frame, ()); let frame = data_init.init(frame, ());
match state.workspace_state().workspace_handle(&workspace) { match state.workspace_state().workspace_handle(&workspace) {
Some(workspace) => { Some(workspace) => {
match state.capture_workspace(dhandle, workspace, output, overlay_cursor != 0) { match state.capture_workspace(
dhandle,
workspace,
output,
overlay_cursor != 0,
) {
Ok(capture) => handle_capture(capture, frame, start_time), Ok(capture) => handle_capture(capture, frame, start_time),
Err(err) => frame.cancel(err.into()), Err(err) => frame.cancel(err.into()),
} }
}, }
None => frame.cancel(CancelReason::Permanent), None => frame.cancel(CancelReason::Permanent),
} }
}, }
zcosmic_export_dmabuf_manager_v1::Request::CaptureToplevel { zcosmic_export_dmabuf_manager_v1::Request::CaptureToplevel {
frame, frame,
overlay_cursor, overlay_cursor,
@ -177,36 +189,38 @@ where
Ok(capture) => handle_capture(capture, frame, start_time), Ok(capture) => handle_capture(capture, frame, start_time),
Err(err) => frame.cancel(err.into()), Err(err) => frame.cancel(err.into()),
} }
}, }
None => frame.cancel(CancelReason::Permanent), None => frame.cancel(CancelReason::Permanent),
} }
}, }
zcosmic_export_dmabuf_manager_v1::Request::Destroy => {}, zcosmic_export_dmabuf_manager_v1::Request::Destroy => {}
_ => {}, _ => {}
} }
} }
} }
impl From<CaptureError> for CancelReason { impl From<CaptureError> for CancelReason {
fn from(err: CaptureError) -> Self { fn from(err: CaptureError) -> Self {
match err { match err {
CaptureError::Temporary(err) => { CaptureError::Temporary(err) => {
slog_scope::debug!("Temporary Capture Error: {}", err); slog_scope::debug!("Temporary Capture Error: {}", err);
CancelReason::Temporary CancelReason::Temporary
}, }
CaptureError::Permanent(err) => { CaptureError::Permanent(err) => {
slog_scope::warn!("Permanent Capture Error: {}", err); slog_scope::warn!("Permanent Capture Error: {}", err);
CancelReason::Permanent CancelReason::Permanent
},
CaptureError::Resizing => {
CancelReason::Resizing
} }
} CaptureError::Resizing => CancelReason::Resizing,
}
} }
} }
fn handle_capture(capture: Capture, frame: ZcosmicExportDmabufFrameV1, start_time: Instant) { fn handle_capture(capture: Capture, frame: ZcosmicExportDmabufFrameV1, start_time: Instant) {
let Capture { device, dmabuf, presentation_time } = capture; let Capture {
device,
dmabuf,
presentation_time,
} = capture;
let format = dmabuf.format(); let format = dmabuf.format();
let modifier: u64 = format.modifier.into(); let modifier: u64 = format.modifier.into();
@ -224,7 +238,11 @@ fn handle_capture(capture: Capture, frame: ZcosmicExportDmabufFrameV1, start_tim
dmabuf.num_planes() as u32, dmabuf.num_planes() as u32,
); );
for (i, (handle, (offset, stride))) in dmabuf.handles().zip(dmabuf.offsets().zip(dmabuf.strides())).enumerate() { for (i, (handle, (offset, stride))) in dmabuf
.handles()
.zip(dmabuf.offsets().zip(dmabuf.strides()))
.enumerate()
{
let mut file = unsafe { File::from_raw_fd(handle) }; let mut file = unsafe { File::from_raw_fd(handle) };
let size = match file.seek(SeekFrom::End(0)) { let size = match file.seek(SeekFrom::End(0)) {
Ok(size) => size, Ok(size) => size,
@ -240,31 +258,20 @@ fn handle_capture(capture: Capture, frame: ZcosmicExportDmabufFrameV1, start_tim
return; return;
} }
let handle = file.into_raw_fd(); let handle = file.into_raw_fd();
frame.object( frame.object(i as u32, handle, size as u32, offset, stride, i as u32);
i as u32,
handle,
size as u32,
offset,
stride,
i as u32,
);
} }
let duration = presentation_time.duration_since(start_time); let duration = presentation_time.duration_since(start_time);
let (tv_sec, tv_nsec) = (duration.as_secs(), duration.subsec_nanos()); let (tv_sec, tv_nsec) = (duration.as_secs(), duration.subsec_nanos());
frame.ready( frame.ready((tv_sec >> 32) as u32, (tv_sec & 0xFFFFFFFF) as u32, tv_nsec);
(tv_sec >> 32) as u32,
(tv_sec & 0xFFFFFFFF) as u32,
tv_nsec,
);
} }
impl<D> Dispatch<ZcosmicExportDmabufFrameV1, (), D> for ExportDmabufState impl<D> Dispatch<ZcosmicExportDmabufFrameV1, (), D> for ExportDmabufState
where where
D: GlobalDispatch<ZcosmicExportDmabufManagerV1, ExportDmabufGlobalData> D: GlobalDispatch<ZcosmicExportDmabufManagerV1, ExportDmabufGlobalData>
+ Dispatch<ZcosmicExportDmabufManagerV1, ()> + Dispatch<ZcosmicExportDmabufManagerV1, ()>
+ Dispatch<ZcosmicExportDmabufFrameV1, ()> + Dispatch<ZcosmicExportDmabufFrameV1, ()>
+ ExportDmabufHandler, + ExportDmabufHandler,
{ {
fn request( fn request(
_state: &mut D, _state: &mut D,
@ -276,8 +283,8 @@ where
_data_init: &mut wayland_server::DataInit<'_, D>, _data_init: &mut wayland_server::DataInit<'_, D>,
) { ) {
match request { match request {
zcosmic_export_dmabuf_frame_v1::Request::Destroy => {}, zcosmic_export_dmabuf_frame_v1::Request::Destroy => {}
_ => {}, _ => {}
} }
} }
} }

View file

@ -12,8 +12,7 @@ use smithay::{
wayland_server::{ wayland_server::{
backend::{ClientId, GlobalId, ObjectId}, backend::{ClientId, GlobalId, ObjectId},
protocol::wl_output::WlOutput, protocol::wl_output::WlOutput,
Client, DataInit, Dispatch, DisplayHandle, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
GlobalDispatch, New, Resource,
}, },
}, },
utils::{Logical, Physical, Point, Size, Transform}, utils::{Logical, Physical, Point, Size, Transform},
@ -133,8 +132,7 @@ struct OutputStateInner {
} }
type OutputState = Mutex<OutputStateInner>; type OutputState = Mutex<OutputStateInner>;
impl<D> GlobalDispatch<ZwlrOutputManagerV1, OutputMngrGlobalData, D> impl<D> GlobalDispatch<ZwlrOutputManagerV1, OutputMngrGlobalData, D> for OutputConfigurationState<D>
for OutputConfigurationState<D>
where where
D: GlobalDispatch<ZwlrOutputManagerV1, OutputMngrGlobalData> D: GlobalDispatch<ZwlrOutputManagerV1, OutputMngrGlobalData>
+ Dispatch<ZwlrOutputManagerV1, OutputMngrInstanceData> + Dispatch<ZwlrOutputManagerV1, OutputMngrInstanceData>
@ -176,8 +174,7 @@ where
} }
} }
impl<D> Dispatch<ZwlrOutputManagerV1, OutputMngrInstanceData, D> impl<D> Dispatch<ZwlrOutputManagerV1, OutputMngrInstanceData, D> for OutputConfigurationState<D>
for OutputConfigurationState<D>
where where
D: GlobalDispatch<ZwlrOutputManagerV1, OutputMngrGlobalData> D: GlobalDispatch<ZwlrOutputManagerV1, OutputMngrGlobalData>
+ Dispatch<ZwlrOutputManagerV1, OutputMngrInstanceData> + Dispatch<ZwlrOutputManagerV1, OutputMngrInstanceData>
@ -279,8 +276,7 @@ where
} }
} }
impl<D> Dispatch<ZwlrOutputConfigurationV1, PendingConfiguration, D> impl<D> Dispatch<ZwlrOutputConfigurationV1, PendingConfiguration, D> for OutputConfigurationState<D>
for OutputConfigurationState<D>
where where
D: GlobalDispatch<ZwlrOutputManagerV1, OutputMngrGlobalData> D: GlobalDispatch<ZwlrOutputManagerV1, OutputMngrGlobalData>
+ Dispatch<ZwlrOutputManagerV1, OutputMngrInstanceData> + Dispatch<ZwlrOutputManagerV1, OutputMngrInstanceData>

View file

@ -1,9 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use std::{ use std::{collections::HashMap, sync::Mutex};
collections::HashMap,
sync::Mutex,
};
use smithay::{ use smithay::{
desktop::Window, desktop::Window,
@ -12,11 +9,10 @@ use smithay::{
wayland_server::{ wayland_server::{
backend::{ClientId, GlobalId, ObjectId}, backend::{ClientId, GlobalId, ObjectId},
protocol::wl_surface::WlSurface, protocol::wl_surface::WlSurface,
Client, DataInit, Dispatch, DisplayHandle, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
GlobalDispatch, New, Resource,
}, },
}, },
utils::{IsAlive, Rectangle, Logical}, utils::{IsAlive, Logical, Rectangle},
wayland::{ wayland::{
compositor::with_states, output::Output, shell::xdg::XdgToplevelSurfaceRoleAttributes, compositor::with_states, output::Output, shell::xdg::XdgToplevelSurfaceRoleAttributes,
}, },
@ -68,21 +64,18 @@ pub type ToplevelHandleState = Mutex<ToplevelHandleStateInner>;
impl ToplevelHandleStateInner { impl ToplevelHandleStateInner {
fn from_window(window: &Window) -> ToplevelHandleState { fn from_window(window: &Window) -> ToplevelHandleState {
ToplevelHandleState::new( ToplevelHandleState::new(ToplevelHandleStateInner {
ToplevelHandleStateInner { outputs: Vec::new(),
outputs: Vec::new(), workspaces: Vec::new(),
workspaces: Vec::new(), title: String::new(),
title: String::new(), app_id: String::new(),
app_id: String::new(), states: Vec::new(),
states: Vec::new(), window: window.clone(),
window: window.clone(), })
}
)
} }
} }
impl<D> GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData, D> impl<D> GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData, D> for ToplevelInfoState<D>
for ToplevelInfoState<D>
where where
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData> D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
+ Dispatch<ZcosmicToplevelInfoV1, ()> + Dispatch<ZcosmicToplevelInfoV1, ()>
@ -256,8 +249,7 @@ where
.unwrap() .unwrap()
.lock() .lock()
.unwrap(); .unwrap();
state.rectangles state.rectangles.retain(|_, (surface, _)| surface.alive());
.retain(|_, (surface, _)| surface.alive());
if window.alive() { if window.alive() {
std::mem::drop(state); std::mem::drop(state);
for instance in &self.instances { for instance in &self.instances {
@ -476,13 +468,7 @@ fn send_toplevel_to_client<D>(
pub fn window_from_handle(handle: ZcosmicToplevelHandleV1) -> Option<Window> { pub fn window_from_handle(handle: ZcosmicToplevelHandleV1) -> Option<Window> {
handle handle
.data::<ToplevelHandleState>() .data::<ToplevelHandleState>()
.map(|state| .map(|state| state.lock().unwrap().window.clone())
state
.lock()
.unwrap()
.window
.clone()
)
} }
macro_rules! delegate_toplevel_info { macro_rules! delegate_toplevel_info {

View file

@ -2,29 +2,21 @@
use smithay::{ use smithay::{
desktop::Window, desktop::Window,
reexports::{ reexports::wayland_server::{
wayland_server::{ backend::{ClientId, GlobalId, ObjectId},
backend::{ClientId, GlobalId, ObjectId}, protocol::wl_surface::WlSurface,
protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
Client, DataInit, Dispatch, DisplayHandle,
GlobalDispatch, New, Resource,
},
}, },
utils::{Logical, Rectangle}, utils::{Logical, Rectangle},
wayland::{ wayland::{output::Output, seat::Seat},
output::Output,
seat::Seat,
},
}; };
use cosmic_protocols::toplevel_management::v1::server::{
zcosmic_toplevel_manager_v1::{self, ZcosmicToplevelManagerV1},
};
pub use cosmic_protocols::toplevel_management::v1::server::zcosmic_toplevel_manager_v1::ZcosmicToplelevelManagementCapabilitiesV1 as ManagementCapabilities; pub use cosmic_protocols::toplevel_management::v1::server::zcosmic_toplevel_manager_v1::ZcosmicToplelevelManagementCapabilitiesV1 as ManagementCapabilities;
use cosmic_protocols::toplevel_management::v1::server::zcosmic_toplevel_manager_v1::{
self, ZcosmicToplevelManagerV1,
};
use super::toplevel_info::{ToplevelInfoHandler, ToplevelState, window_from_handle}; use super::toplevel_info::{window_from_handle, ToplevelInfoHandler, ToplevelState};
pub struct ToplevelManagementState { pub struct ToplevelManagementState {
instances: Vec<ZcosmicToplevelManagerV1>, instances: Vec<ZcosmicToplevelManagerV1>,
@ -52,13 +44,17 @@ pub struct ToplevelManagerGlobalData {
} }
impl ToplevelManagementState { impl ToplevelManagementState {
pub fn new<D, F>(dh: &DisplayHandle, capabilities: Vec<ManagementCapabilities>, client_filter: F) -> ToplevelManagementState pub fn new<D, F>(
dh: &DisplayHandle,
capabilities: Vec<ManagementCapabilities>,
client_filter: F,
) -> ToplevelManagementState
where where
D: GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData> D: GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData>
+ Dispatch<ZcosmicToplevelManagerV1, ()> + Dispatch<ZcosmicToplevelManagerV1, ()>
+ ToplevelManagementHandler + ToplevelManagementHandler
+ 'static, + 'static,
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
{ {
let global = dh.create_global::<D, ZcosmicToplevelManagerV1, _>( let global = dh.create_global::<D, ZcosmicToplevelManagerV1, _>(
1, 1,
@ -73,7 +69,11 @@ impl ToplevelManagementState {
} }
} }
pub fn rectangle_for(&mut self, window: &Window, client: &ClientId) -> Option<(WlSurface, Rectangle<i32, Logical>)> { pub fn rectangle_for(
&mut self,
window: &Window,
client: &ClientId,
) -> Option<(WlSurface, Rectangle<i32, Logical>)> {
if let Some(state) = window.user_data().get::<ToplevelState>() { if let Some(state) = window.user_data().get::<ToplevelState>() {
state.lock().unwrap().rectangles.get(client).cloned() state.lock().unwrap().rectangles.get(client).cloned()
} else { } else {
@ -86,12 +86,13 @@ impl ToplevelManagementState {
} }
} }
impl<D> GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData, D> for ToplevelManagementState impl<D> GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData, D>
for ToplevelManagementState
where where
D: GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData> D: GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData>
+ Dispatch<ZcosmicToplevelManagerV1, ()> + Dispatch<ZcosmicToplevelManagerV1, ()>
+ ToplevelManagementHandler + ToplevelManagementHandler
+ 'static + 'static,
{ {
fn bind( fn bind(
state: &mut D, state: &mut D,
@ -120,13 +121,12 @@ where
} }
} }
impl<D> Dispatch<ZcosmicToplevelManagerV1, (), D> for ToplevelManagementState impl<D> Dispatch<ZcosmicToplevelManagerV1, (), D> for ToplevelManagementState
where where
D: GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData> D: GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData>
+ Dispatch<ZcosmicToplevelManagerV1, ()> + Dispatch<ZcosmicToplevelManagerV1, ()>
+ ToplevelManagementHandler + ToplevelManagementHandler
+ 'static + 'static,
{ {
fn request( fn request(
state: &mut D, state: &mut D,
@ -141,36 +141,43 @@ where
zcosmic_toplevel_manager_v1::Request::Activate { toplevel, seat } => { zcosmic_toplevel_manager_v1::Request::Activate { toplevel, seat } => {
let window = window_from_handle(toplevel).unwrap(); let window = window_from_handle(toplevel).unwrap();
state.activate(dh, &window, Seat::from_resource(&seat)); state.activate(dh, &window, Seat::from_resource(&seat));
}, }
zcosmic_toplevel_manager_v1::Request::Close { toplevel } => { zcosmic_toplevel_manager_v1::Request::Close { toplevel } => {
let window = window_from_handle(toplevel).unwrap(); let window = window_from_handle(toplevel).unwrap();
state.close(dh, &window); state.close(dh, &window);
}, }
zcosmic_toplevel_manager_v1::Request::SetFullscreen { toplevel, output } => { zcosmic_toplevel_manager_v1::Request::SetFullscreen { toplevel, output } => {
let window = window_from_handle(toplevel).unwrap(); let window = window_from_handle(toplevel).unwrap();
state.fullscreen(dh, &window, output.as_ref().and_then(Output::from_resource)) state.fullscreen(dh, &window, output.as_ref().and_then(Output::from_resource))
}, }
zcosmic_toplevel_manager_v1::Request::UnsetFullscreen { toplevel } => { zcosmic_toplevel_manager_v1::Request::UnsetFullscreen { toplevel } => {
let window = window_from_handle(toplevel).unwrap(); let window = window_from_handle(toplevel).unwrap();
state.unfullscreen(dh, &window); state.unfullscreen(dh, &window);
}, }
zcosmic_toplevel_manager_v1::Request::SetMaximized { toplevel } => { zcosmic_toplevel_manager_v1::Request::SetMaximized { toplevel } => {
let window = window_from_handle(toplevel).unwrap(); let window = window_from_handle(toplevel).unwrap();
state.maximize(dh, &window); state.maximize(dh, &window);
}, }
zcosmic_toplevel_manager_v1::Request::UnsetMaximized { toplevel } => { zcosmic_toplevel_manager_v1::Request::UnsetMaximized { toplevel } => {
let window = window_from_handle(toplevel).unwrap(); let window = window_from_handle(toplevel).unwrap();
state.unmaximize(dh, &window); state.unmaximize(dh, &window);
}, }
zcosmic_toplevel_manager_v1::Request::SetMinimized { toplevel } => { zcosmic_toplevel_manager_v1::Request::SetMinimized { toplevel } => {
let window = window_from_handle(toplevel).unwrap(); let window = window_from_handle(toplevel).unwrap();
state.minimize(dh, &window); state.minimize(dh, &window);
}, }
zcosmic_toplevel_manager_v1::Request::UnsetMinimized { toplevel } => { zcosmic_toplevel_manager_v1::Request::UnsetMinimized { toplevel } => {
let window = window_from_handle(toplevel).unwrap(); let window = window_from_handle(toplevel).unwrap();
state.unminimize(dh, &window); state.unminimize(dh, &window);
}, }
zcosmic_toplevel_manager_v1::Request::SetRectangle { toplevel, surface, x, y, width, height } => { zcosmic_toplevel_manager_v1::Request::SetRectangle {
toplevel,
surface,
x,
y,
width,
height,
} => {
let window = window_from_handle(toplevel).unwrap(); let window = window_from_handle(toplevel).unwrap();
if let Some(toplevel_state) = window.user_data().get::<ToplevelState>() { if let Some(toplevel_state) = window.user_data().get::<ToplevelState>() {
let mut toplevel_state = toplevel_state.lock().unwrap(); let mut toplevel_state = toplevel_state.lock().unwrap();
@ -178,11 +185,17 @@ where
if width == 0 && height == 0 { if width == 0 && height == 0 {
toplevel_state.rectangles.remove(&client); toplevel_state.rectangles.remove(&client);
} else { } else {
toplevel_state.rectangles.insert(client, (surface, Rectangle::from_loc_and_size((x, y), (width, height)))); toplevel_state.rectangles.insert(
client,
(
surface,
Rectangle::from_loc_and_size((x, y), (width, height)),
),
);
} }
} }
} }
}, }
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -190,7 +203,11 @@ where
fn destroyed(state: &mut D, client: ClientId, resource: ObjectId, _data: &()) { fn destroyed(state: &mut D, client: ClientId, resource: ObjectId, _data: &()) {
let mng_state = state.toplevel_management_state(); let mng_state = state.toplevel_management_state();
mng_state.instances.retain(|i| i.id() != resource); mng_state.instances.retain(|i| i.id() != resource);
if !mng_state.instances.iter().any(|i| i.client_id().map(|c| c == client).unwrap_or(false)) { if !mng_state
.instances
.iter()
.any(|i| i.client_id().map(|c| c == client).unwrap_or(false))
{
for toplevel in state.toplevel_info_state_mut().toplevels.iter() { for toplevel in state.toplevel_info_state_mut().toplevels.iter() {
if let Some(toplevel_state) = toplevel.user_data().get::<ToplevelState>() { if let Some(toplevel_state) = toplevel.user_data().get::<ToplevelState>() {
toplevel_state.lock().unwrap().rectangles.remove(&client); toplevel_state.lock().unwrap().rectangles.remove(&client);

View file

@ -1,15 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use std::{ use std::{collections::HashSet, sync::Mutex};
collections::HashSet,
sync::Mutex,
};
use smithay::{ use smithay::{
reexports::wayland_server::{ reexports::wayland_server::{
backend::{ClientData, ClientId, GlobalId, ObjectId}, backend::{ClientData, ClientId, GlobalId, ObjectId},
Client, DataInit, Dispatch, DisplayHandle, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
GlobalDispatch, New, Resource,
}, },
wayland::output::Output, wayland::output::Output,
}; };
@ -142,8 +138,7 @@ pub trait WorkspaceClientHandler {
fn workspace_state(&self) -> &WorkspaceClientState; fn workspace_state(&self) -> &WorkspaceClientState;
} }
impl<D> GlobalDispatch<ZcosmicWorkspaceManagerV1, WorkspaceGlobalData, D> impl<D> GlobalDispatch<ZcosmicWorkspaceManagerV1, WorkspaceGlobalData, D> for WorkspaceState<D>
for WorkspaceState<D>
where where
D: GlobalDispatch<ZcosmicWorkspaceManagerV1, WorkspaceGlobalData> D: GlobalDispatch<ZcosmicWorkspaceManagerV1, WorkspaceGlobalData>
+ Dispatch<ZcosmicWorkspaceManagerV1, ()> + Dispatch<ZcosmicWorkspaceManagerV1, ()>
@ -477,7 +472,7 @@ where
.map(|w| w.states.iter()) .map(|w| w.states.iter())
}) })
} }
pub fn group_handle( pub fn group_handle(
&self, &self,
group: &ZcosmicWorkspaceGroupHandleV1, group: &ZcosmicWorkspaceGroupHandleV1,
@ -493,7 +488,11 @@ where
) -> Option<WorkspaceHandle> { ) -> Option<WorkspaceHandle> {
self.groups self.groups
.iter() .iter()
.find_map(|g| g.workspaces.iter().find(|w| w.instances.contains(workspace))) .find_map(|g| {
g.workspaces
.iter()
.find(|w| w.instances.contains(workspace))
})
.map(|w| WorkspaceHandle { id: w.id }) .map(|w| WorkspaceHandle { id: w.id })
} }