support resizing, start on layer shell support
This commit is contained in:
parent
9268cb0220
commit
eea1406bd4
5 changed files with 257 additions and 19 deletions
|
|
@ -1,4 +1,5 @@
|
|||
mod compositor;
|
||||
mod wlr_layer_shell;
|
||||
mod xdg_activation;
|
||||
mod xdg_decoration;
|
||||
mod xdg_icon;
|
||||
|
|
|
|||
30
src/handlers/wlr_layer_shell.rs
Normal file
30
src/handlers/wlr_layer_shell.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
use smithay::{
|
||||
desktop::{layer_map_for_output, LayerSurface},
|
||||
output::Output,
|
||||
wayland::shell::wlr_layer::WlrLayerShellHandler,
|
||||
};
|
||||
use wayland_server::protocol::wl_output::WlOutput;
|
||||
|
||||
use crate::State;
|
||||
|
||||
impl WlrLayerShellHandler for State {
|
||||
fn shell_state(&mut self) -> &mut smithay::wayland::shell::wlr_layer::WlrLayerShellState {
|
||||
&mut self.wlr_layer_shell_state
|
||||
}
|
||||
|
||||
fn new_layer_surface(
|
||||
&mut self,
|
||||
surface: smithay::wayland::shell::wlr_layer::LayerSurface,
|
||||
output: Option<WlOutput>,
|
||||
layer: smithay::wayland::shell::wlr_layer::Layer,
|
||||
namespace: String,
|
||||
) {
|
||||
let output = output
|
||||
.as_ref()
|
||||
.and_then(Output::from_resource)
|
||||
.unwrap_or_else(|| self.space.outputs().next().unwrap().clone());
|
||||
let mut map = layer_map_for_output(&output);
|
||||
map.map_layer(&LayerSurface::new(surface, namespace))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
use smithay::utils::Point;
|
||||
use smithay::wayland::seat::WaylandFocus;
|
||||
use smithay::{
|
||||
desktop::{
|
||||
find_popup_root_surface, get_popup_toplevel_coords, layer_map_for_output,
|
||||
|
|
@ -8,6 +10,7 @@ use smithay::{
|
|||
pointer::{Focus, GrabStartData as PointerGrabStartData},
|
||||
Seat,
|
||||
},
|
||||
output::Output,
|
||||
reexports::{
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||
wayland_server::{
|
||||
|
|
@ -24,6 +27,7 @@ use smithay::{
|
|||
},
|
||||
},
|
||||
};
|
||||
use wayland_server::protocol::wl_output;
|
||||
|
||||
use crate::{
|
||||
grabs::{MoveSurfaceGrab, ResizeSurfaceGrab},
|
||||
|
|
@ -82,6 +86,11 @@ impl XdgShellHandler for State {
|
|||
.find(|w| w.window.toplevel().unwrap().wl_surface() == wl_surface)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
if window.is_fullscreen() {
|
||||
return;
|
||||
}
|
||||
|
||||
let initial_window_location = self.space.element_location(&window).unwrap();
|
||||
|
||||
let grab = MoveSurfaceGrab {
|
||||
|
|
@ -115,6 +124,10 @@ impl XdgShellHandler for State {
|
|||
.find(|w| w.window.toplevel().unwrap().wl_surface() == wl_surface)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
if window.is_fullscreen() {
|
||||
return;
|
||||
}
|
||||
let initial_window_location = self.space.element_location(&window).unwrap();
|
||||
let initial_window_size = window.window.geometry().size;
|
||||
|
||||
|
|
@ -169,12 +182,7 @@ impl XdgShellHandler for State {
|
|||
}
|
||||
|
||||
fn title_changed(&mut self, surface: ToplevelSurface) {
|
||||
let window = self
|
||||
.space
|
||||
.elements()
|
||||
.filter(|w| w.window.toplevel().is_some())
|
||||
.find(|w| *w.window.toplevel().unwrap() == surface)
|
||||
.unwrap();
|
||||
let window = self.get_window_by_surface(&surface);
|
||||
|
||||
smithay::wayland::compositor::with_states(surface.wl_surface(), |states| {
|
||||
if let Some(data) = states.data_map.get::<XdgToplevelSurfaceData>() {
|
||||
|
|
@ -184,6 +192,154 @@ impl XdgShellHandler for State {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
// fn new_client(&mut self, client: smithay::wayland::shell::xdg::ShellClient) {}
|
||||
|
||||
// fn client_pong(&mut self, client: smithay::wayland::shell::xdg::ShellClient) {}
|
||||
|
||||
fn maximize_request(&mut self, surface: ToplevelSurface) {
|
||||
{
|
||||
let window = self.get_window_by_surface(&surface);
|
||||
if let Some(loc) = self.space.element_location(&window) {
|
||||
window.set_saved_location(loc);
|
||||
}
|
||||
}
|
||||
|
||||
let window = self.get_window_by_surface(&surface).clone();
|
||||
if let Some(loc) = self.space.element_location(&window) {
|
||||
window.set_saved_location(loc);
|
||||
}
|
||||
self.space.relocate_element(&window, Point::new(0, 0));
|
||||
|
||||
if let Some(output) = window.output.lock().clone() {
|
||||
let geom = self.space.output_geometry(&output).unwrap();
|
||||
|
||||
let xdg = window.window.toplevel().unwrap();
|
||||
xdg.with_pending_state(|state| {
|
||||
state.states.set(xdg_toplevel::State::Maximized);
|
||||
state.size = Some(geom.size);
|
||||
});
|
||||
}
|
||||
|
||||
surface.send_configure();
|
||||
}
|
||||
|
||||
fn unmaximize_request(&mut self, surface: ToplevelSurface) {
|
||||
let window = self.get_window_by_surface(&surface).clone();
|
||||
self.space
|
||||
.relocate_element(&window, window.saved_location());
|
||||
|
||||
if let Some(output) = window.output.lock().clone() {
|
||||
let xdg = window.window.toplevel().unwrap();
|
||||
xdg.with_pending_state(|state| {
|
||||
state.states.unset(xdg_toplevel::State::Maximized);
|
||||
state.size = None;
|
||||
});
|
||||
}
|
||||
|
||||
surface.send_configure();
|
||||
}
|
||||
|
||||
fn fullscreen_request(
|
||||
&mut self,
|
||||
surface: ToplevelSurface,
|
||||
mut wl_output: Option<wl_output::WlOutput>,
|
||||
) {
|
||||
// NOTE: This is only one part of the solution. We can set the
|
||||
// location and configure size here, but the surface should be rendered fullscreen
|
||||
// independently from its buffer size
|
||||
let wl_surface = surface.wl_surface();
|
||||
let window = self.get_window_by_surface(&surface);
|
||||
|
||||
window.set_fullscreen(true);
|
||||
|
||||
let output_geometry = wl_output
|
||||
.as_ref()
|
||||
.and_then(Output::from_resource)
|
||||
.or_else(|| {
|
||||
let w = self.space.elements().find(|window| {
|
||||
window
|
||||
.window
|
||||
.wl_surface()
|
||||
.map(|s| &*s == wl_surface)
|
||||
.unwrap_or(false)
|
||||
});
|
||||
w.and_then(|w| self.space.outputs_for_element(w).first().cloned())
|
||||
})
|
||||
.as_ref()
|
||||
.and_then(|o| self.space.output_geometry(o));
|
||||
|
||||
if let Some(geometry) = output_geometry {
|
||||
let output = wl_output
|
||||
.as_ref()
|
||||
.and_then(Output::from_resource)
|
||||
.unwrap_or_else(|| self.space.outputs().next().unwrap().clone());
|
||||
let client = match self.display_handle.get_client(wl_surface.id()) {
|
||||
Ok(client) => client,
|
||||
Err(_) => return,
|
||||
};
|
||||
for output in output.client_outputs(&client) {
|
||||
wl_output = Some(output);
|
||||
}
|
||||
|
||||
surface.with_pending_state(|state| {
|
||||
state.states.set(xdg_toplevel::State::Fullscreen);
|
||||
state.size = Some(geometry.size);
|
||||
state.fullscreen_output = wl_output;
|
||||
});
|
||||
}
|
||||
|
||||
// The protocol demands us to always reply with a configure,
|
||||
// regardless of we fulfilled the request or not
|
||||
if surface.is_initial_configure_sent() {
|
||||
surface.send_configure();
|
||||
} else {
|
||||
// Will be sent during initial configure
|
||||
}
|
||||
}
|
||||
|
||||
fn unfullscreen_request(&mut self, surface: ToplevelSurface) {
|
||||
let window = self.get_window_by_surface(&surface);
|
||||
|
||||
window.set_fullscreen(false);
|
||||
|
||||
let xdg = window.window.toplevel().unwrap();
|
||||
xdg.with_pending_state(|state| {
|
||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||
state.size = None;
|
||||
state.fullscreen_output = None;
|
||||
});
|
||||
|
||||
surface.send_configure();
|
||||
}
|
||||
|
||||
// fn minimize_request(&mut self, surface: ToplevelSurface) {}
|
||||
|
||||
// fn show_window_menu(
|
||||
// &mut self,
|
||||
// surface: ToplevelSurface,
|
||||
// seat: wl_seat::WlSeat,
|
||||
// serial: Serial,
|
||||
// location: smithay::utils::Point<i32, smithay::utils::Logical>,
|
||||
// ) {
|
||||
// }
|
||||
|
||||
// fn ack_configure(
|
||||
// &mut self,
|
||||
// surface: wl_surface::WlSurface,
|
||||
// configure: smithay::wayland::shell::xdg::Configure,
|
||||
// ) {
|
||||
// }
|
||||
|
||||
// fn client_destroyed(&mut self, client: smithay::wayland::shell::xdg::ShellClient) {}
|
||||
|
||||
// fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {}
|
||||
|
||||
// fn popup_destroyed(&mut self, surface: PopupSurface) {}
|
||||
|
||||
// fn app_id_changed(&mut self, surface: ToplevelSurface) {}
|
||||
|
||||
// fn parent_changed(&mut self, surface: ToplevelSurface) {}
|
||||
}
|
||||
|
||||
fn check_grab(
|
||||
|
|
@ -277,4 +433,12 @@ impl State {
|
|||
state.geometry = state.positioner.get_unconstrained_geometry(target);
|
||||
});
|
||||
}
|
||||
|
||||
fn get_window_by_surface(&self, surface: &ToplevelSurface) -> &DecoratedWindow {
|
||||
self.space
|
||||
.elements()
|
||||
.filter(|w| w.window.toplevel().is_some())
|
||||
.find(|w| *w.window.toplevel().unwrap() == *surface)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ use cairo::{Context, Format, ImageSurface};
|
|||
use parking_lot::Mutex;
|
||||
use smithay::backend::allocator::Fourcc;
|
||||
use smithay::backend::renderer::element::memory::MemoryRenderBuffer;
|
||||
use smithay::utils::Transform;
|
||||
use smithay::desktop::layer_map_for_output;
|
||||
use smithay::utils::{Logical, Transform};
|
||||
use smithay::wayland::commit_timing::CommitTimerBarrierStateUserData;
|
||||
use smithay::{
|
||||
backend::renderer::{
|
||||
damage::OutputDamageTracker,
|
||||
|
|
@ -36,7 +38,10 @@ const CSD_BORDER_FRAME_BOTTOM: f64 = 4.0;
|
|||
pub struct DecoratedWindow {
|
||||
pub window: Window,
|
||||
title: Mutex<String>,
|
||||
decorations: bool,
|
||||
pub output: Mutex<Option<Output>>,
|
||||
decorations: Mutex<bool>,
|
||||
fullscreen: Mutex<bool>,
|
||||
saved_location: Mutex<Point<i32, Logical>>,
|
||||
}
|
||||
|
||||
impl PartialEq for DecoratedWindow {
|
||||
|
|
@ -49,10 +54,17 @@ impl Eq for DecoratedWindow {}
|
|||
impl Clone for DecoratedWindow {
|
||||
fn clone(&self) -> Self {
|
||||
let title = self.title.lock().clone();
|
||||
let output = self.output.lock().clone();
|
||||
let decorations = self.decorations.lock().clone();
|
||||
let fullscreen = self.fullscreen.lock().clone();
|
||||
let saved_location = self.saved_location.lock().clone();
|
||||
Self {
|
||||
window: self.window.clone(),
|
||||
title: Mutex::new(title),
|
||||
decorations: self.decorations,
|
||||
output: Mutex::new(output),
|
||||
decorations: Mutex::new(decorations),
|
||||
fullscreen: Mutex::new(fullscreen),
|
||||
saved_location: Mutex::new(saved_location),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -63,12 +75,35 @@ impl DecoratedWindow {
|
|||
Self {
|
||||
window,
|
||||
title: Mutex::new(String::new()),
|
||||
decorations,
|
||||
output: Mutex::new(None),
|
||||
decorations: Mutex::new(decorations),
|
||||
fullscreen: Mutex::new(false),
|
||||
saved_location: Mutex::new(Point::new(0, 0)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn saved_location(&self) -> Point<i32, Logical> {
|
||||
self.saved_location.lock().clone()
|
||||
}
|
||||
|
||||
pub fn set_saved_location(&self, point: Point<i32, Logical>) {
|
||||
*self.saved_location.lock() = point;
|
||||
}
|
||||
pub fn set_title(&self, title: String) {
|
||||
*self.title.lock() = title;
|
||||
}
|
||||
|
||||
pub fn is_fullscreen(&self) -> bool {
|
||||
return *self.fullscreen.lock();
|
||||
}
|
||||
|
||||
pub fn set_fullscreen(&self, fs: bool) {
|
||||
// *self.decorations.lock() = !fs;
|
||||
*self.fullscreen.lock() = fs;
|
||||
}
|
||||
|
||||
fn decorated(&self) -> bool {
|
||||
let mut b = self.decorations;
|
||||
let mut b = *self.decorations.lock();
|
||||
if let Some(toplevel) = self.window.toplevel() {
|
||||
toplevel.with_pending_state(|f| {
|
||||
if let Some(decor) = f.decoration_mode {
|
||||
|
|
@ -79,10 +114,6 @@ impl DecoratedWindow {
|
|||
b
|
||||
}
|
||||
|
||||
pub fn set_title(&self, title: String) {
|
||||
*self.title.lock() = title;
|
||||
}
|
||||
|
||||
fn render_border(&self, width: i32, height: i32) -> (Vec<u8>, i32) {
|
||||
let mut surface = ImageSurface::create(Format::ARgb32, width, height).unwrap();
|
||||
let stride = surface.stride();
|
||||
|
|
@ -285,10 +316,12 @@ impl SpaceElement for DecoratedWindow {
|
|||
output: &Output,
|
||||
overlap: smithay::utils::Rectangle<i32, smithay::utils::Logical>,
|
||||
) {
|
||||
*self.output.lock() = Some(output.clone());
|
||||
self.window.output_enter(output, overlap)
|
||||
}
|
||||
|
||||
fn output_leave(&self, output: &Output) {
|
||||
*self.output.lock() = None;
|
||||
self.window.output_leave(output)
|
||||
}
|
||||
}
|
||||
|
|
@ -309,12 +342,17 @@ where
|
|||
fn render_elements<C: From<Self::RenderElement>>(
|
||||
&self,
|
||||
renderer: &mut R,
|
||||
location: Point<i32, Physical>,
|
||||
mut location: Point<i32, Physical>,
|
||||
scale: Scale<f64>,
|
||||
alpha: f32,
|
||||
) -> Vec<C> {
|
||||
let mut elements: Vec<C> = Vec::new();
|
||||
|
||||
if self.is_fullscreen() {
|
||||
location.x = 0;
|
||||
location.y = 0;
|
||||
}
|
||||
|
||||
/* Start with actual window elements */
|
||||
elements.extend(
|
||||
self.window
|
||||
|
|
@ -381,8 +419,6 @@ impl State {
|
|||
framebuffer: &mut GlesTarget,
|
||||
damage_tracker: &mut OutputDamageTracker,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// let elem = DecorationElement::
|
||||
|
||||
smithay::desktop::space::render_output::<_, OutputElement<GlesRenderer>, _, _>(
|
||||
output,
|
||||
renderer,
|
||||
|
|
@ -394,6 +430,7 @@ impl State {
|
|||
damage_tracker,
|
||||
[0.07, 0.16, 0.286, 1.0],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use smithay::{
|
|||
fixes::FixesState,
|
||||
output::OutputManagerState,
|
||||
selection::data_device::DataDeviceState,
|
||||
shell::xdg::{decoration::XdgDecorationState, XdgShellState},
|
||||
shell::{wlr_layer::WlrLayerShellState, xdg::XdgShellState},
|
||||
shm::ShmState,
|
||||
socket::ListeningSocketSource,
|
||||
xdg_activation::XdgActivationState,
|
||||
|
|
@ -59,6 +59,9 @@ pub struct State {
|
|||
pub xdg_toplevel_tag_manager_state: XdgToplevelTagManager,
|
||||
pub xdg_system_bell_state: XdgSystemBellState,
|
||||
|
||||
// the one wlroots protocol that everyone adopted
|
||||
pub wlr_layer_shell_state: WlrLayerShellState,
|
||||
|
||||
pub output_manager_state: OutputManagerState,
|
||||
|
||||
pub xwayland_state: XWaylandState,
|
||||
|
|
@ -88,6 +91,8 @@ impl State {
|
|||
let xdg_toplevel_tag_manager_state = XdgToplevelTagManager::new::<Self>(&dh);
|
||||
let xdg_system_bell_state = XdgSystemBellState::new::<Self>(&dh);
|
||||
|
||||
let wlr_layer_shell_state = WlrLayerShellState::new::<Self>(&dh);
|
||||
|
||||
let shm_state = ShmState::new::<Self>(&dh, vec![]);
|
||||
let popups = PopupManager::default();
|
||||
|
||||
|
|
@ -149,6 +154,7 @@ impl State {
|
|||
data_device_state,
|
||||
wl_fixes_state,
|
||||
output_manager_state,
|
||||
wlr_layer_shell_state,
|
||||
|
||||
// xdg_decoration_state,
|
||||
xdg_activation_state,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue