xwayland: Add initial support
This commit is contained in:
parent
78ffe3a93d
commit
1d28574088
23 changed files with 781 additions and 185 deletions
24
Cargo.lock
generated
24
Cargo.lock
generated
|
|
@ -1561,7 +1561,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced"
|
name = "iced"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"iced_futures",
|
"iced_futures",
|
||||||
|
|
@ -1577,7 +1577,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_core"
|
name = "iced_core"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"palette",
|
"palette",
|
||||||
|
|
@ -1587,7 +1587,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_futures"
|
name = "iced_futures"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -1598,7 +1598,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_glow"
|
name = "iced_glow"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"euclid",
|
"euclid",
|
||||||
|
|
@ -1613,7 +1613,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_graphics"
|
name = "iced_graphics"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
@ -1633,7 +1633,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_lazy"
|
name = "iced_lazy"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_native",
|
"iced_native",
|
||||||
"ouroboros 0.13.0",
|
"ouroboros 0.13.0",
|
||||||
|
|
@ -1642,7 +1642,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_native"
|
name = "iced_native"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"iced_futures",
|
"iced_futures",
|
||||||
|
|
@ -1655,7 +1655,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_softbuffer"
|
name = "iced_softbuffer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmic-text",
|
"cosmic-text",
|
||||||
"iced_graphics",
|
"iced_graphics",
|
||||||
|
|
@ -1670,7 +1670,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_style"
|
name = "iced_style"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -1680,7 +1680,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_wgpu"
|
name = "iced_wgpu"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
@ -1882,7 +1882,7 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcosmic"
|
name = "libcosmic"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
source = "git+https://github.com/pop-os/libcosmic#abf8fc96c2eb8c3ed25d90c4538e29c3a12029fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"apply",
|
"apply",
|
||||||
"cosmic-theme",
|
"cosmic-theme",
|
||||||
|
|
@ -3273,7 +3273,7 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay"
|
name = "smithay"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/pop-os/smithay?rev=2a05d8cd64#2a05d8cd648bc9689491ff5a996fd7713f23aa77"
|
source = "git+https://github.com/pop-os/smithay?rev=b6742bfc5d#b6742bfc5d164826d9a6584a62e6012b778081ec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"appendlist",
|
"appendlist",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ libsystemd = "0.5"
|
||||||
wayland-backend = "0.1.0"
|
wayland-backend = "0.1.0"
|
||||||
wayland-scanner = "0.30.0"
|
wayland-scanner = "0.30.0"
|
||||||
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"] }
|
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"] }
|
||||||
libcosmic = { git = "https://github.com/pop-os/libcosmic", branch = "ci_add_without_shell", default-features = false, features = ["softbuffer"] }
|
libcosmic = { git = "https://github.com/pop-os/libcosmic", ref = "abf8fc96c", default-features = false, features = ["softbuffer"] }
|
||||||
iced_softbuffer = { git = "https://github.com/pop-os/libcosmic", branch = "ci_add_without_shell" }
|
iced_softbuffer = { git = "https://github.com/pop-os/libcosmic", ref = "abf8fc96c" }
|
||||||
ordered-float = "3.0"
|
ordered-float = "3.0"
|
||||||
|
|
||||||
[dependencies.smithay]
|
[dependencies.smithay]
|
||||||
|
|
@ -70,4 +70,4 @@ debug = true
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
|
|
||||||
[patch."https://github.com/Smithay/smithay.git"]
|
[patch."https://github.com/Smithay/smithay.git"]
|
||||||
smithay = { git = "https://github.com/pop-os/smithay", rev = "2a05d8cd64" }
|
smithay = { git = "https://github.com/pop-os/smithay", rev = "b6742bfc5d" }
|
||||||
|
|
|
||||||
|
|
@ -301,6 +301,9 @@ pub fn init_backend(
|
||||||
devices: HashMap::new(),
|
devices: HashMap::new(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: Do multiple Xwaylands for better multigpu
|
||||||
|
state.launch_xwayland(Some(primary));
|
||||||
|
|
||||||
for (dev, path) in udev_dispatcher.as_source_ref().device_list() {
|
for (dev, path) in udev_dispatcher.as_source_ref().device_list() {
|
||||||
state
|
state
|
||||||
.device_added(dev, path.into(), dh)
|
.device_added(dev, path.into(), dh)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use smithay::{
|
||||||
wayland_server::{backend::GlobalId, Client, DisplayHandle},
|
wayland_server::{backend::GlobalId, Client, DisplayHandle},
|
||||||
},
|
},
|
||||||
wayland::{dmabuf::DmabufGlobal, socket::ListeningSocketSource},
|
wayland::{dmabuf::DmabufGlobal, socket::ListeningSocketSource},
|
||||||
|
xwayland::XWaylandClientData,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|
@ -46,8 +47,15 @@ impl State {
|
||||||
|
|
||||||
// initialize globals
|
// initialize globals
|
||||||
let filter = move |client: &Client| {
|
let filter = move |client: &Client| {
|
||||||
let dev_id = client.get_data::<ClientState>().unwrap().drm_node.unwrap();
|
if let Some(normal_client) = client.get_data::<ClientState>() {
|
||||||
dev_id == render_node
|
let dev_id = normal_client.drm_node.unwrap();
|
||||||
|
return dev_id == render_node;
|
||||||
|
}
|
||||||
|
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
||||||
|
let dev_id = xwayland_client.user_data().get::<DrmNode>().unwrap();
|
||||||
|
return *dev_id == render_node;
|
||||||
|
}
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
let dmabuf_global = self
|
let dmabuf_global = self
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,7 @@ pub fn init_backend(
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
fps,
|
fps,
|
||||||
});
|
});
|
||||||
|
|
||||||
state
|
state
|
||||||
.common
|
.common
|
||||||
.output_configuration_state
|
.output_configuration_state
|
||||||
|
|
@ -255,6 +256,8 @@ pub fn init_backend(
|
||||||
&state.common.event_loop_handle,
|
&state.common.event_loop_handle,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
state.launch_xwayland(None);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -305,6 +305,8 @@ pub fn init_backend(
|
||||||
&state.common.event_loop_handle,
|
&state.common.event_loop_handle,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
state.launch_xwayland(None);
|
||||||
|
|
||||||
event_loop
|
event_loop
|
||||||
.handle()
|
.handle()
|
||||||
.insert_source(backend, move |event, _, data| match event {
|
.insert_source(backend, move |event, _, data| match event {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ use std::{ffi::OsString, os::unix::prelude::AsRawFd, sync::Arc};
|
||||||
|
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub mod debug;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
mod logger;
|
mod logger;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
|
|
@ -21,9 +23,7 @@ pub mod state;
|
||||||
pub mod systemd;
|
pub mod systemd;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod wayland;
|
pub mod wayland;
|
||||||
|
pub mod xwayland;
|
||||||
#[cfg(feature = "debug")]
|
|
||||||
pub mod debug;
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// setup logger
|
// setup logger
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ use smithay::{
|
||||||
compositor::{with_surface_tree_downward, TraversalAction},
|
compositor::{with_surface_tree_downward, TraversalAction},
|
||||||
seat::WaylandFocus,
|
seat::WaylandFocus,
|
||||||
},
|
},
|
||||||
|
xwayland::{xwm::X11Relatable, X11Surface},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
|
@ -483,6 +484,15 @@ impl SpaceElement for CosmicMapped {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl X11Relatable for CosmicMapped {
|
||||||
|
fn is_window(&self, window: &X11Surface) -> bool {
|
||||||
|
match self.active_window() {
|
||||||
|
CosmicSurface::X11(surface) => &surface == window,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl KeyboardTarget<State> for CosmicMapped {
|
impl KeyboardTarget<State> for CosmicMapped {
|
||||||
fn enter(
|
fn enter(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ use smithay::{
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{with_states, SurfaceData},
|
compositor::{with_states, SurfaceData},
|
||||||
seat::WaylandFocus,
|
seat::WaylandFocus,
|
||||||
shell::xdg::XdgToplevelSurfaceData,
|
shell::xdg::{ToplevelSurface, XdgToplevelSurfaceData},
|
||||||
},
|
},
|
||||||
xwayland::X11Surface,
|
xwayland::{xwm::X11Relatable, X11Surface},
|
||||||
};
|
};
|
||||||
|
|
||||||
space_elements! {
|
space_elements! {
|
||||||
|
|
@ -41,6 +41,24 @@ space_elements! {
|
||||||
X11=X11Surface,
|
X11=X11Surface,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ToplevelSurface> for CosmicSurface {
|
||||||
|
fn from(s: ToplevelSurface) -> Self {
|
||||||
|
CosmicSurface::Wayland(Window::new(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Window> for CosmicSurface {
|
||||||
|
fn from(w: Window) -> Self {
|
||||||
|
CosmicSurface::Wayland(w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<X11Surface> for CosmicSurface {
|
||||||
|
fn from(s: X11Surface) -> Self {
|
||||||
|
CosmicSurface::X11(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const SSD_HEIGHT: i32 = 48;
|
pub const SSD_HEIGHT: i32 = 48;
|
||||||
|
|
||||||
impl CosmicSurface {
|
impl CosmicSurface {
|
||||||
|
|
@ -577,3 +595,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl X11Relatable for CosmicSurface {
|
||||||
|
fn is_window(&self, window: &X11Surface) -> bool {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::X11(surface) => surface == window,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
shell::Shell,
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
iced::{IcedElement, Program},
|
iced::{IcedElement, Program},
|
||||||
|
|
@ -30,13 +31,14 @@ use smithay::{
|
||||||
output::Output,
|
output::Output,
|
||||||
render_elements,
|
render_elements,
|
||||||
utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size},
|
utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size},
|
||||||
|
wayland::seat::WaylandFocus,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU8, Ordering},
|
atomic::{AtomicU8, Ordering},
|
||||||
Arc,
|
Arc, Mutex,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -55,10 +57,23 @@ impl fmt::Debug for CosmicWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CosmicWindowInternal {
|
pub struct CosmicWindowInternal {
|
||||||
pub(super) window: CosmicSurface,
|
pub(super) window: CosmicSurface,
|
||||||
|
/// TODO: This needs to be per seat
|
||||||
pointer_entered: Arc<AtomicU8>,
|
pointer_entered: Arc<AtomicU8>,
|
||||||
|
last_seat: Arc<Mutex<Option<(Seat<State>, Serial)>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for CosmicWindowInternal {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("CosmicWindowInternal")
|
||||||
|
.field("window", &self.window)
|
||||||
|
.field("pointer_entered", &self.pointer_entered)
|
||||||
|
// skip seat to avoid loop
|
||||||
|
.field("last_seat", &"...")
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
|
@ -98,6 +113,7 @@ impl CosmicWindow {
|
||||||
CosmicWindowInternal {
|
CosmicWindowInternal {
|
||||||
window,
|
window,
|
||||||
pointer_entered: Arc::new(AtomicU8::new(Focus::None as u8)),
|
pointer_entered: Arc::new(AtomicU8::new(Focus::None as u8)),
|
||||||
|
last_seat: Arc::new(Mutex::new(None)),
|
||||||
},
|
},
|
||||||
(width, SSD_HEIGHT),
|
(width, SSD_HEIGHT),
|
||||||
handle,
|
handle,
|
||||||
|
|
@ -136,18 +152,49 @@ pub enum Message {
|
||||||
impl Program for CosmicWindowInternal {
|
impl Program for CosmicWindowInternal {
|
||||||
type Message = Message;
|
type Message = Message;
|
||||||
|
|
||||||
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
fn update(
|
||||||
/*
|
&mut self,
|
||||||
|
message: Self::Message,
|
||||||
|
loop_handle: &LoopHandle<'static, crate::state::Data>,
|
||||||
|
) -> Command<Self::Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::DragStart => match &self.window {
|
Message::DragStart => {
|
||||||
CosmicWindowSurface::Wayland(window) => self
|
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
|
||||||
.with_program(|internal| internal.loop_handle())
|
if let Some(surface) = self.window.wl_surface() {
|
||||||
.insert_idle(|data| {}),
|
loop_handle.insert_idle(move |data| {
|
||||||
CosmicWindowSurface::X11(surface) => {}
|
Shell::move_request(&mut data.state, &surface, &seat, serial);
|
||||||
_ => unreachable!(),
|
});
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::Maximize => {
|
||||||
|
if let Some((seat, _serial)) = self.last_seat.lock().unwrap().clone() {
|
||||||
|
if let Some(surface) = self.window.wl_surface() {
|
||||||
|
loop_handle.insert_idle(move |data| {
|
||||||
|
if let Some(mapped) = data
|
||||||
|
.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.element_for_wl_surface(&surface)
|
||||||
|
.cloned()
|
||||||
|
{
|
||||||
|
if let Some(workspace) =
|
||||||
|
data.state.common.shell.space_for_mut(&mapped)
|
||||||
|
{
|
||||||
|
let output = seat.active_output();
|
||||||
|
let (window, _) = mapped
|
||||||
|
.windows()
|
||||||
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(&surface))
|
||||||
|
.unwrap();
|
||||||
|
workspace.maximize_request(&window, &output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::Close => self.window.close(),
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
Command::none()
|
Command::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,21 +202,23 @@ impl Program for CosmicWindowInternal {
|
||||||
let radius = 8.;
|
let radius = 8.;
|
||||||
let (w, h) = (target.width() as f32, target.height() as f32);
|
let (w, h) = (target.width() as f32, target.height() as f32);
|
||||||
|
|
||||||
let mut pb = PathBuilder::new();
|
if !(self.window.is_maximized() || self.window.is_fullscreen()) {
|
||||||
pb.move_to(0., h); // lower-left
|
let mut pb = PathBuilder::new();
|
||||||
|
pb.move_to(0., h); // lower-left
|
||||||
|
|
||||||
// upper-left rounded corner
|
// upper-left rounded corner
|
||||||
pb.line_to(0., radius);
|
pb.line_to(0., radius);
|
||||||
pb.quad_to(0., 0., radius, 0.);
|
pb.quad_to(0., 0., radius, 0.);
|
||||||
|
|
||||||
// upper-right rounded corner
|
// upper-right rounded corner
|
||||||
pb.line_to(w - radius, 0.);
|
pb.line_to(w - radius, 0.);
|
||||||
pb.quad_to(w, 0., w, radius);
|
pb.quad_to(w, 0., w, radius);
|
||||||
|
|
||||||
pb.line_to(w, h); // lower-right
|
pb.line_to(w, h); // lower-right
|
||||||
|
|
||||||
let path = pb.finish();
|
let path = pb.finish();
|
||||||
target.push_clip(&path);
|
target.push_clip(&path);
|
||||||
|
}
|
||||||
|
|
||||||
if self.window.is_activated() {
|
if self.window.is_activated() {
|
||||||
target.clear(SolidSource::from_unpremultiplied_argb(u8::MAX, 30, 30, 30));
|
target.clear(SolidSource::from_unpremultiplied_argb(u8::MAX, 30, 30, 30));
|
||||||
|
|
@ -387,7 +436,12 @@ impl PointerTarget<State> for CosmicWindow {
|
||||||
|
|
||||||
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
||||||
match self.0.with_program(|p| p.current_focus()) {
|
match self.0.with_program(|p| p.current_focus()) {
|
||||||
Focus::Header => PointerTarget::button(&self.0, seat, data, event),
|
Focus::Header => {
|
||||||
|
self.0.with_program(|p| {
|
||||||
|
*p.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
|
||||||
|
});
|
||||||
|
PointerTarget::button(&self.0, seat, data, event)
|
||||||
|
}
|
||||||
Focus::Window => self
|
Focus::Window => self
|
||||||
.0
|
.0
|
||||||
.with_program(|p| PointerTarget::button(&p.window, seat, data, event)),
|
.with_program(|p| PointerTarget::button(&p.window, seat, data, event)),
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
reexports::wayland_protocols::xdg::shell::server::xdg_toplevel,
|
reexports::wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||||
utils::{Logical, Point},
|
utils::{Logical, Point},
|
||||||
|
xwayland::xwm,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
|
|
@ -43,6 +44,22 @@ impl From<ResizeEdge> for xdg_toplevel::ResizeEdge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<xwm::ResizeEdge> for ResizeEdge {
|
||||||
|
#[inline]
|
||||||
|
fn from(x: xwm::ResizeEdge) -> Self {
|
||||||
|
match x {
|
||||||
|
xwm::ResizeEdge::Top => ResizeEdge::TOP,
|
||||||
|
xwm::ResizeEdge::Bottom => ResizeEdge::BOTTOM,
|
||||||
|
xwm::ResizeEdge::Left => ResizeEdge::LEFT,
|
||||||
|
xwm::ResizeEdge::Right => ResizeEdge::RIGHT,
|
||||||
|
xwm::ResizeEdge::TopLeft => ResizeEdge::TOP_LEFT,
|
||||||
|
xwm::ResizeEdge::BottomLeft => ResizeEdge::BOTTOM_LEFT,
|
||||||
|
xwm::ResizeEdge::TopRight => ResizeEdge::TOP_RIGHT,
|
||||||
|
xwm::ResizeEdge::BottomRight => ResizeEdge::BOTTOM_RIGHT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum ResizeGrab {
|
pub enum ResizeGrab {
|
||||||
Floating(ResizeSurfaceGrab),
|
Floating(ResizeSurfaceGrab),
|
||||||
Tiling(ResizeForkGrab),
|
Tiling(ResizeForkGrab),
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use smithay::{
|
||||||
desktop::{layer_map_for_output, space::SpaceElement, Space},
|
desktop::{layer_map_for_output, space::SpaceElement, Space},
|
||||||
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{Logical, Point, Rectangle, Serial, Size},
|
utils::{Logical, Point, Rectangle, Size},
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -196,7 +196,6 @@ impl FloatingLayout {
|
||||||
&mut self,
|
&mut self,
|
||||||
mapped: &CosmicMapped,
|
mapped: &CosmicMapped,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
_serial: Serial,
|
|
||||||
start_data: PointerGrabStartData<State>,
|
start_data: PointerGrabStartData<State>,
|
||||||
edges: ResizeEdge,
|
edges: ResizeEdge,
|
||||||
) -> Option<ResizeSurfaceGrab> {
|
) -> Option<ResizeSurfaceGrab> {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ use smithay::{
|
||||||
desktop::{layer_map_for_output, space::SpaceElement, PopupKind},
|
desktop::{layer_map_for_output, space::SpaceElement, PopupKind},
|
||||||
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{IsAlive, Logical, Point, Rectangle, Scale, Serial},
|
utils::{IsAlive, Logical, Point, Rectangle, Scale},
|
||||||
wayland::seat::WaylandFocus,
|
wayland::seat::WaylandFocus,
|
||||||
};
|
};
|
||||||
use std::{borrow::Borrow, collections::HashMap, hash::Hash, sync::Arc};
|
use std::{borrow::Borrow, collections::HashMap, hash::Hash, sync::Arc};
|
||||||
|
|
@ -928,7 +928,6 @@ impl TilingLayout {
|
||||||
&self,
|
&self,
|
||||||
mapped: &CosmicMapped,
|
mapped: &CosmicMapped,
|
||||||
_seat: &Seat<State>,
|
_seat: &Seat<State>,
|
||||||
_serial: Serial,
|
|
||||||
start_data: PointerGrabStartData<State>,
|
start_data: PointerGrabStartData<State>,
|
||||||
edges: ResizeEdge,
|
edges: ResizeEdge,
|
||||||
) -> Option<ResizeForkGrab> {
|
) -> Option<ResizeForkGrab> {
|
||||||
|
|
|
||||||
170
src/shell/mod.rs
170
src/shell/mod.rs
|
|
@ -4,12 +4,19 @@ use std::{cell::RefCell, collections::HashMap};
|
||||||
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::State as WState;
|
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::State as WState;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::{layer_map_for_output, LayerSurface, PopupManager, WindowSurfaceType},
|
desktop::{layer_map_for_output, LayerSurface, PopupManager, WindowSurfaceType},
|
||||||
input::Seat,
|
input::{
|
||||||
|
pointer::{Focus, GrabStartData as PointerGrabStartData},
|
||||||
|
Seat,
|
||||||
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle},
|
reexports::{
|
||||||
utils::{Logical, Point, Rectangle},
|
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle},
|
||||||
|
x11rb::protocol::xproto::Window as X11Window,
|
||||||
|
},
|
||||||
|
utils::{Logical, Point, Rectangle, Serial, SERIAL_COUNTER},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::with_states,
|
compositor::with_states,
|
||||||
|
seat::WaylandFocus,
|
||||||
shell::{
|
shell::{
|
||||||
wlr_layer::{
|
wlr_layer::{
|
||||||
KeyboardInteractivity, Layer, LayerSurfaceCachedState, WlrLayerShellState,
|
KeyboardInteractivity, Layer, LayerSurfaceCachedState, WlrLayerShellState,
|
||||||
|
|
@ -17,6 +24,7 @@ use smithay::{
|
||||||
xdg::XdgShellState,
|
xdg::XdgShellState,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
xwayland::X11Surface,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -42,6 +50,7 @@ pub use self::workspace::*;
|
||||||
use self::{
|
use self::{
|
||||||
element::CosmicWindow,
|
element::CosmicWindow,
|
||||||
focus::target::KeyboardFocusTarget,
|
focus::target::KeyboardFocusTarget,
|
||||||
|
grabs::ResizeEdge,
|
||||||
layout::{floating::FloatingLayout, tiling::TilingLayout},
|
layout::{floating::FloatingLayout, tiling::TilingLayout},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -52,6 +61,7 @@ pub struct Shell {
|
||||||
pub floating_default: bool,
|
pub floating_default: bool,
|
||||||
pub pending_windows: Vec<(CosmicSurface, Seat<State>)>,
|
pub pending_windows: Vec<(CosmicSurface, Seat<State>)>,
|
||||||
pub pending_layers: Vec<(LayerSurface, Output, Seat<State>)>,
|
pub pending_layers: Vec<(LayerSurface, Output, Seat<State>)>,
|
||||||
|
pub override_redirect_windows: Vec<OverrideRedirectWindow>,
|
||||||
|
|
||||||
// wayland_state
|
// wayland_state
|
||||||
pub layer_shell_state: WlrLayerShellState,
|
pub layer_shell_state: WlrLayerShellState,
|
||||||
|
|
@ -61,6 +71,11 @@ pub struct Shell {
|
||||||
pub workspace_state: WorkspaceState<State>,
|
pub workspace_state: WorkspaceState<State>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct OverrideRedirectWindow {
|
||||||
|
pub surface: X11Surface,
|
||||||
|
pub above: Option<X11Window>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WorkspaceSet {
|
pub struct WorkspaceSet {
|
||||||
active: usize,
|
active: usize,
|
||||||
|
|
@ -431,6 +446,7 @@ impl Shell {
|
||||||
|
|
||||||
pending_windows: Vec::new(),
|
pending_windows: Vec::new(),
|
||||||
pending_layers: Vec::new(),
|
pending_layers: Vec::new(),
|
||||||
|
override_redirect_windows: Vec::new(),
|
||||||
|
|
||||||
layer_shell_state,
|
layer_shell_state,
|
||||||
toplevel_info_state,
|
toplevel_info_state,
|
||||||
|
|
@ -871,12 +887,18 @@ impl Shell {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn element_for_surface(&self, surface: &WlSurface) -> Option<&CosmicMapped> {
|
pub fn element_for_surface(&self, surface: &CosmicSurface) -> Option<&CosmicMapped> {
|
||||||
self.workspaces
|
self.workspaces
|
||||||
.spaces()
|
.spaces()
|
||||||
.find_map(|w| w.element_for_surface(surface))
|
.find_map(|w| w.element_for_surface(surface))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn element_for_wl_surface(&self, surface: &WlSurface) -> Option<&CosmicMapped> {
|
||||||
|
self.workspaces
|
||||||
|
.spaces()
|
||||||
|
.find_map(|w| w.element_for_wl_surface(surface))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn space_for(&self, mapped: &CosmicMapped) -> Option<&Workspace> {
|
pub fn space_for(&self, mapped: &CosmicMapped) -> Option<&Workspace> {
|
||||||
self.workspaces
|
self.workspaces
|
||||||
.spaces()
|
.spaces()
|
||||||
|
|
@ -996,6 +1018,24 @@ impl Shell {
|
||||||
.map(mapped.clone(), &seat, focus_stack.iter());
|
.map(mapped.clone(), &seat, focus_stack.iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let CosmicSurface::X11(surface) = window {
|
||||||
|
let geometry = workspace.element_geometry(&mapped);
|
||||||
|
if let Err(err) = surface.configure(geometry) {
|
||||||
|
slog_scope::warn!("Failed to configure X11 surface ({:?}): {}", surface, err);
|
||||||
|
};
|
||||||
|
if let Some(xwm) = state
|
||||||
|
.common
|
||||||
|
.xwayland_state
|
||||||
|
.values_mut()
|
||||||
|
.flat_map(|state| state.xwm.as_mut())
|
||||||
|
.find(|xwm| Some(xwm.id()) == surface.xwm_id())
|
||||||
|
{
|
||||||
|
if let Err(err) = xwm.update_stacking_order_downwards(workspace.mapped()) {
|
||||||
|
slog_scope::warn!("Failed to update Xwayland stacking order: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Shell::set_focus(state, Some(&KeyboardFocusTarget::from(mapped)), &seat, None);
|
Shell::set_focus(state, Some(&KeyboardFocusTarget::from(mapped)), &seat, None);
|
||||||
|
|
||||||
let active_space = state.common.shell.active_space(output);
|
let active_space = state.common.shell.active_space(output);
|
||||||
|
|
@ -1004,6 +1044,28 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn map_override_redirect(state: &mut State, window: X11Surface) {
|
||||||
|
let seat = state.common.last_active_seat().clone();
|
||||||
|
let mut pos = window.geometry().loc;
|
||||||
|
let output = state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.outputs()
|
||||||
|
.find(|o| o.geometry().contains(pos))
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| seat.active_output());
|
||||||
|
pos -= output.geometry().loc;
|
||||||
|
|
||||||
|
state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.override_redirect_windows
|
||||||
|
.push(OverrideRedirectWindow {
|
||||||
|
surface: window,
|
||||||
|
above: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn map_layer(state: &mut State, layer_surface: &LayerSurface) {
|
pub fn map_layer(state: &mut State, layer_surface: &LayerSurface) {
|
||||||
let pos = state
|
let pos = state
|
||||||
.common
|
.common
|
||||||
|
|
@ -1125,6 +1187,71 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn move_request(
|
||||||
|
state: &mut State,
|
||||||
|
surface: &WlSurface,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
serial: impl Into<Option<Serial>>,
|
||||||
|
) {
|
||||||
|
let serial = serial.into();
|
||||||
|
if let Some(start_data) = check_grab_preconditions(&seat, surface, serial) {
|
||||||
|
if let Some(mapped) = state.common.shell.element_for_wl_surface(surface).cloned() {
|
||||||
|
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
|
||||||
|
let output = seat.active_output();
|
||||||
|
let (window, _) = mapped
|
||||||
|
.windows()
|
||||||
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface))
|
||||||
|
.unwrap();
|
||||||
|
if let Some(grab) = workspace.move_request(&window, &seat, &output, start_data)
|
||||||
|
{
|
||||||
|
let handle = workspace.handle;
|
||||||
|
state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.toplevel_info_state
|
||||||
|
.toplevel_leave_workspace(&window, &handle);
|
||||||
|
state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.toplevel_info_state
|
||||||
|
.toplevel_leave_output(&window, &output);
|
||||||
|
seat.get_pointer().unwrap().set_grab(
|
||||||
|
state,
|
||||||
|
grab,
|
||||||
|
serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()),
|
||||||
|
Focus::Clear,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize_request(
|
||||||
|
state: &mut State,
|
||||||
|
surface: &WlSurface,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
serial: impl Into<Option<Serial>>,
|
||||||
|
edges: ResizeEdge,
|
||||||
|
) {
|
||||||
|
let serial = serial.into();
|
||||||
|
if let Some(start_data) = check_grab_preconditions(&seat, surface, serial) {
|
||||||
|
if let Some(mapped) = state.common.shell.element_for_wl_surface(surface).cloned() {
|
||||||
|
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
|
||||||
|
if let Some(grab) = workspace.resize_request(&mapped, &seat, start_data, edges)
|
||||||
|
{
|
||||||
|
seat.get_pointer().unwrap().set_grab(
|
||||||
|
state,
|
||||||
|
grab,
|
||||||
|
serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()),
|
||||||
|
Focus::Clear,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_set_idx<'a>(
|
fn workspace_set_idx<'a>(
|
||||||
|
|
@ -1136,3 +1263,38 @@ fn workspace_set_idx<'a>(
|
||||||
state.set_workspace_name(&handle, format!("{}", idx));
|
state.set_workspace_name(&handle, format!("{}", idx));
|
||||||
state.set_workspace_coordinates(&handle, [Some(idx as u32), Some(output_pos as u32), None]);
|
state.set_workspace_coordinates(&handle, [Some(idx as u32), Some(output_pos as u32), None]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_grab_preconditions(
|
||||||
|
seat: &Seat<State>,
|
||||||
|
surface: &WlSurface,
|
||||||
|
serial: Option<Serial>,
|
||||||
|
) -> Option<PointerGrabStartData<State>> {
|
||||||
|
use smithay::reexports::wayland_server::Resource;
|
||||||
|
|
||||||
|
// TODO: touch resize.
|
||||||
|
let pointer = seat.get_pointer().unwrap();
|
||||||
|
|
||||||
|
// Check that this surface has a click grab.
|
||||||
|
if !match serial {
|
||||||
|
Some(serial) => pointer.has_grab(serial),
|
||||||
|
None => pointer.is_grabbed(),
|
||||||
|
} {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let start_data = pointer.grab_start_data().unwrap();
|
||||||
|
|
||||||
|
// If the focus was for a different surface, ignore the request.
|
||||||
|
if start_data.focus.is_none()
|
||||||
|
|| !start_data
|
||||||
|
.focus
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.0
|
||||||
|
.same_client_as(&surface.id())
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(start_data)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,8 @@ use smithay::{
|
||||||
desktop::{layer_map_for_output, space::SpaceElement, LayerSurface},
|
desktop::{layer_map_for_output, space::SpaceElement, LayerSurface},
|
||||||
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge,
|
utils::{Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Size},
|
||||||
wayland_server::protocol::wl_surface::WlSurface,
|
|
||||||
},
|
|
||||||
utils::{
|
|
||||||
Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size,
|
|
||||||
},
|
|
||||||
wayland::{seat::WaylandFocus, shell::wlr_layer::Layer},
|
wayland::{seat::WaylandFocus, shell::wlr_layer::Layer},
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -38,7 +33,7 @@ use std::collections::HashMap;
|
||||||
use super::{
|
use super::{
|
||||||
element::CosmicMapped,
|
element::CosmicMapped,
|
||||||
focus::{FocusStack, FocusStackMut},
|
focus::{FocusStack, FocusStackMut},
|
||||||
grabs::ResizeGrab,
|
grabs::{ResizeEdge, ResizeGrab},
|
||||||
CosmicMappedRenderElement, CosmicSurface,
|
CosmicMappedRenderElement, CosmicSurface,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -84,7 +79,7 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit(&mut self, surface: &WlSurface) {
|
pub fn commit(&mut self, surface: &WlSurface) {
|
||||||
if let Some(mapped) = self.element_for_surface(surface) {
|
if let Some(mapped) = self.element_for_wl_surface(surface) {
|
||||||
mapped
|
mapped
|
||||||
.windows()
|
.windows()
|
||||||
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface))
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface))
|
||||||
|
|
@ -127,7 +122,14 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn element_for_surface(&self, surface: &WlSurface) -> Option<&CosmicMapped> {
|
pub fn element_for_surface(&self, surface: &CosmicSurface) -> Option<&CosmicMapped> {
|
||||||
|
self.floating_layer
|
||||||
|
.mapped()
|
||||||
|
.chain(self.tiling_layer.mapped().map(|(_, w, _)| w))
|
||||||
|
.find(|e| e.windows().any(|(w, _)| &w == surface))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn element_for_wl_surface(&self, surface: &WlSurface) -> Option<&CosmicMapped> {
|
||||||
self.floating_layer
|
self.floating_layer
|
||||||
.mapped()
|
.mapped()
|
||||||
.chain(self.tiling_layer.mapped().map(|(_, w, _)| w))
|
.chain(self.tiling_layer.mapped().map(|(_, w, _)| w))
|
||||||
|
|
@ -270,7 +272,6 @@ impl Workspace {
|
||||||
&mut self,
|
&mut self,
|
||||||
mapped: &CosmicMapped,
|
mapped: &CosmicMapped,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
serial: Serial,
|
|
||||||
start_data: PointerGrabStartData<State>,
|
start_data: PointerGrabStartData<State>,
|
||||||
edges: ResizeEdge,
|
edges: ResizeEdge,
|
||||||
) -> Option<ResizeGrab> {
|
) -> Option<ResizeGrab> {
|
||||||
|
|
@ -278,14 +279,13 @@ impl Workspace {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let edges = edges.into();
|
|
||||||
if self.floating_layer.mapped().any(|m| m == mapped) {
|
if self.floating_layer.mapped().any(|m| m == mapped) {
|
||||||
self.floating_layer
|
self.floating_layer
|
||||||
.resize_request(mapped, seat, serial, start_data.clone(), edges)
|
.resize_request(mapped, seat, start_data.clone(), edges)
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
} else if self.tiling_layer.mapped().any(|(_, m, _)| m == mapped) {
|
} else if self.tiling_layer.mapped().any(|(_, m, _)| m == mapped) {
|
||||||
self.tiling_layer
|
self.tiling_layer
|
||||||
.resize_request(mapped, seat, serial, start_data, edges)
|
.resize_request(mapped, seat, start_data, edges)
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -297,13 +297,12 @@ impl Workspace {
|
||||||
window: &CosmicSurface,
|
window: &CosmicSurface,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
_serial: Serial,
|
|
||||||
start_data: PointerGrabStartData<State>,
|
start_data: PointerGrabStartData<State>,
|
||||||
) -> Option<MoveSurfaceGrab> {
|
) -> Option<MoveSurfaceGrab> {
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
let pos = pointer.current_location();
|
let pos = pointer.current_location();
|
||||||
|
|
||||||
let mapped = self.element_for_surface(&window.wl_surface()?)?.clone();
|
let mapped = self.element_for_surface(&window)?.clone();
|
||||||
let mut initial_window_location = self.element_geometry(&mapped).unwrap().loc;
|
let mut initial_window_location = self.element_geometry(&mapped).unwrap().loc;
|
||||||
|
|
||||||
if mapped.is_fullscreen() || mapped.is_maximized() {
|
if mapped.is_fullscreen() || mapped.is_maximized() {
|
||||||
|
|
@ -390,6 +389,10 @@ impl Workspace {
|
||||||
.chain(self.tiling_layer.windows().map(|(_, w, _)| w))
|
.chain(self.tiling_layer.windows().map(|(_, w, _)| w))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_floating(&self, mapped: &CosmicMapped) -> bool {
|
||||||
|
self.floating_layer.mapped().any(|m| m == mapped)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render_output<R>(
|
pub fn render_output<R>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
screencopy::{BufferParams, ScreencopyState, Session as ScreencopySession},
|
screencopy::{BufferParams, ScreencopyState, Session as ScreencopySession},
|
||||||
workspace::WorkspaceClientState,
|
workspace::WorkspaceClientState,
|
||||||
},
|
},
|
||||||
|
xwayland::XWaylandState,
|
||||||
};
|
};
|
||||||
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_manager_v1::CursorMode;
|
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_manager_v1::CursorMode;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
|
@ -51,7 +52,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{cell::RefCell, ffi::OsString, time::Duration};
|
use std::{cell::RefCell, collections::HashMap, ffi::OsString, time::Duration};
|
||||||
use std::{collections::VecDeque, time::Instant};
|
use std::{collections::VecDeque, time::Instant};
|
||||||
|
|
||||||
pub struct ClientState {
|
pub struct ClientState {
|
||||||
|
|
@ -110,6 +111,9 @@ pub struct Common {
|
||||||
pub viewporter_state: ViewporterState,
|
pub viewporter_state: ViewporterState,
|
||||||
pub kde_decoration_state: KdeDecorationState,
|
pub kde_decoration_state: KdeDecorationState,
|
||||||
pub xdg_decoration_state: XdgDecorationState,
|
pub xdg_decoration_state: XdgDecorationState,
|
||||||
|
|
||||||
|
// xwayland state
|
||||||
|
pub xwayland_state: HashMap<Option<DrmNode>, XWaylandState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BackendData {
|
pub enum BackendData {
|
||||||
|
|
@ -277,6 +281,8 @@ impl State {
|
||||||
wl_drm_state,
|
wl_drm_state,
|
||||||
kde_decoration_state,
|
kde_decoration_state,
|
||||||
xdg_decoration_state,
|
xdg_decoration_state,
|
||||||
|
|
||||||
|
xwayland_state: HashMap::new(),
|
||||||
},
|
},
|
||||||
backend: BackendData::Unset,
|
backend: BackendData::Unset,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,12 @@ impl<P: Program + Send + 'static> Hash for IcedElement<P> {
|
||||||
|
|
||||||
pub trait Program {
|
pub trait Program {
|
||||||
type Message: std::fmt::Debug + Send;
|
type Message: std::fmt::Debug + Send;
|
||||||
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
fn update(
|
||||||
let _ = message;
|
&mut self,
|
||||||
|
message: Self::Message,
|
||||||
|
loop_handle: &LoopHandle<'static, crate::state::Data>,
|
||||||
|
) -> Command<Self::Message> {
|
||||||
|
let _ = (message, loop_handle);
|
||||||
Command::none()
|
Command::none()
|
||||||
}
|
}
|
||||||
fn view(&self) -> Element<'_, Self::Message>;
|
fn view(&self) -> Element<'_, Self::Message>;
|
||||||
|
|
@ -91,13 +95,13 @@ pub trait Program {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProgramWrapper<P: Program>(P);
|
struct ProgramWrapper<P: Program>(P, LoopHandle<'static, crate::state::Data>);
|
||||||
impl<P: Program> IcedProgram for ProgramWrapper<P> {
|
impl<P: Program> IcedProgram for ProgramWrapper<P> {
|
||||||
type Message = <P as Program>::Message;
|
type Message = <P as Program>::Message;
|
||||||
type Renderer = IcedRenderer;
|
type Renderer = IcedRenderer;
|
||||||
|
|
||||||
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
||||||
self.0.update(message)
|
self.0.update(message, &self.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<'_, Self::Message> {
|
fn view(&self) -> Element<'_, Self::Message> {
|
||||||
|
|
@ -161,7 +165,7 @@ impl<P: Program + Send + 'static> IcedElement<P> {
|
||||||
let mut debug = Debug::new();
|
let mut debug = Debug::new();
|
||||||
|
|
||||||
let state = State::new(
|
let state = State::new(
|
||||||
ProgramWrapper(program),
|
ProgramWrapper(program, handle.clone()),
|
||||||
IcedSize::new(size.w as f32, size.h as f32),
|
IcedSize::new(size.w as f32, size.h as f32),
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&mut debug,
|
&mut debug,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
xwayland::X11Wm,
|
||||||
};
|
};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
|
@ -108,6 +109,7 @@ impl CompositorHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit(&mut self, surface: &WlSurface) {
|
fn commit(&mut self, surface: &WlSurface) {
|
||||||
|
X11Wm::commit_hook(surface);
|
||||||
// first load the buffer for various smithay helper functions
|
// first load the buffer for various smithay helper functions
|
||||||
on_commit_buffer_handler(surface);
|
on_commit_buffer_handler(surface);
|
||||||
|
|
||||||
|
|
@ -134,10 +136,7 @@ impl CompositorHandler for State {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CosmicSurface::X11(_) => {
|
CosmicSurface::X11(_) => {}
|
||||||
let output = seat.active_output();
|
|
||||||
Shell::map_window(self, &window, &output);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +163,7 @@ impl CompositorHandler for State {
|
||||||
// If we would re-position the window inside the grab we would get a weird jittery animation.
|
// If we would re-position the window inside the grab we would get a weird jittery animation.
|
||||||
// We only want to resize once the client has acknoledged & commited the new size,
|
// We only want to resize once the client has acknoledged & commited the new size,
|
||||||
// so we need to carefully track the state through different handlers.
|
// so we need to carefully track the state through different handlers.
|
||||||
if let Some(element) = self.common.shell.element_for_surface(surface).cloned() {
|
if let Some(element) = self.common.shell.element_for_wl_surface(surface).cloned() {
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&element) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&element) {
|
||||||
crate::shell::layout::floating::ResizeSurfaceGrab::apply_resize_to_location(
|
crate::shell::layout::floating::ResizeSurfaceGrab::apply_resize_to_location(
|
||||||
element.clone(),
|
element.clone(),
|
||||||
|
|
|
||||||
|
|
@ -76,13 +76,21 @@ impl State {
|
||||||
|
|
||||||
impl XdgDecorationHandler for State {
|
impl XdgDecorationHandler for State {
|
||||||
fn new_decoration(&mut self, toplevel: ToplevelSurface) {
|
fn new_decoration(&mut self, toplevel: ToplevelSurface) {
|
||||||
if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) {
|
if let Some(mapped) = self
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.element_for_wl_surface(toplevel.wl_surface())
|
||||||
|
{
|
||||||
State::new_decoration(mapped, toplevel.wl_surface());
|
State::new_decoration(mapped, toplevel.wl_surface());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_mode(&mut self, toplevel: ToplevelSurface, mode: XdgMode) {
|
fn request_mode(&mut self, toplevel: ToplevelSurface, mode: XdgMode) {
|
||||||
if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) {
|
if let Some(mapped) = self
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.element_for_wl_surface(toplevel.wl_surface())
|
||||||
|
{
|
||||||
State::request_mode(mapped, toplevel.wl_surface(), mode);
|
State::request_mode(mapped, toplevel.wl_surface(), mode);
|
||||||
} else {
|
} else {
|
||||||
toplevel.with_pending_state(|state| state.decoration_mode = Some(mode));
|
toplevel.with_pending_state(|state| state.decoration_mode = Some(mode));
|
||||||
|
|
@ -90,7 +98,11 @@ impl XdgDecorationHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unset_mode(&mut self, toplevel: ToplevelSurface) {
|
fn unset_mode(&mut self, toplevel: ToplevelSurface) {
|
||||||
if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) {
|
if let Some(mapped) = self
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.element_for_wl_surface(toplevel.wl_surface())
|
||||||
|
{
|
||||||
State::unset_mode(mapped, toplevel.wl_surface())
|
State::unset_mode(mapped, toplevel.wl_surface())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +114,7 @@ impl KdeDecorationHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_decoration(&mut self, surface: &WlSurface, decoration: &OrgKdeKwinServerDecoration) {
|
fn new_decoration(&mut self, surface: &WlSurface, decoration: &OrgKdeKwinServerDecoration) {
|
||||||
if let Some(mapped) = self.common.shell.element_for_surface(surface) {
|
if let Some(mapped) = self.common.shell.element_for_wl_surface(surface) {
|
||||||
let mode = State::new_decoration(mapped, surface);
|
let mode = State::new_decoration(mapped, surface);
|
||||||
decoration.mode(mode);
|
decoration.mode(mode);
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +128,7 @@ impl KdeDecorationHandler for State {
|
||||||
) {
|
) {
|
||||||
if let WEnum::Value(mode) = mode {
|
if let WEnum::Value(mode) = mode {
|
||||||
// TODO: We need to store this value until it gets mapped and apply it then, if it is not mapped yet.
|
// TODO: We need to store this value until it gets mapped and apply it then, if it is not mapped yet.
|
||||||
if let Some(mapped) = self.common.shell.element_for_surface(surface) {
|
if let Some(mapped) = self.common.shell.element_for_wl_surface(surface) {
|
||||||
State::request_mode(
|
State::request_mode(
|
||||||
mapped,
|
mapped,
|
||||||
surface,
|
surface,
|
||||||
|
|
@ -131,7 +143,7 @@ impl KdeDecorationHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release(&mut self, _decoration: &OrgKdeKwinServerDecoration, surface: &WlSurface) {
|
fn release(&mut self, _decoration: &OrgKdeKwinServerDecoration, surface: &WlSurface) {
|
||||||
if let Some(mapped) = self.common.shell.element_for_surface(surface) {
|
if let Some(mapped) = self.common.shell.element_for_wl_surface(surface) {
|
||||||
State::unset_mode(mapped, surface)
|
State::unset_mode(mapped, surface)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -890,10 +890,7 @@ pub fn render_window_to_buffer(
|
||||||
for seat in common.seats() {
|
for seat in common.seats() {
|
||||||
if let Some(location) = {
|
if let Some(location) = {
|
||||||
// we need to find the mapped element in that case
|
// we need to find the mapped element in that case
|
||||||
if let Some(mapped) = window
|
if let Some(mapped) = common.shell.element_for_surface(&window) {
|
||||||
.wl_surface()
|
|
||||||
.and_then(|surf| common.shell.element_for_surface(&surf))
|
|
||||||
{
|
|
||||||
mapped.cursor_position(seat).and_then(|mut p| {
|
mapped.cursor_position(seat).and_then(|mut p| {
|
||||||
p -= mapped.active_window_offset().to_f64();
|
p -= mapped.active_window_offset().to_f64();
|
||||||
if p.x < 0. || p.y < 0. {
|
if p.x < 0. || p.y < 0. {
|
||||||
|
|
@ -1100,7 +1097,10 @@ impl UserdataExt for CosmicSurface {
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn schedule_window_session(&mut self, surface: &WlSurface) {
|
pub fn schedule_window_session(&mut self, surface: &WlSurface) {
|
||||||
if let Some(element) = self.common.shell.element_for_surface(surface).cloned() {
|
if let Some(element) = surface
|
||||||
|
.wl_surface()
|
||||||
|
.and_then(|surface| self.common.shell.element_for_wl_surface(&surface).cloned())
|
||||||
|
{
|
||||||
let active = element.active_window();
|
let active = element.active_window();
|
||||||
if active.wl_surface().as_ref() == Some(surface) {
|
if active.wl_surface().as_ref() == Some(surface) {
|
||||||
for (session, params) in active.pending_buffers() {
|
for (session, params) in active.pending_buffers() {
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,11 @@ use smithay::{
|
||||||
find_popup_root_surface, PopupGrab, PopupKeyboardGrab, PopupKind, PopupPointerGrab,
|
find_popup_root_surface, PopupGrab, PopupKeyboardGrab, PopupKind, PopupPointerGrab,
|
||||||
PopupUngrabStrategy, Window,
|
PopupUngrabStrategy, Window,
|
||||||
},
|
},
|
||||||
input::{
|
input::{pointer::Focus, Seat},
|
||||||
pointer::{Focus, GrabStartData as PointerGrabStartData},
|
|
||||||
Seat,
|
|
||||||
},
|
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::{
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||||
wayland_server::protocol::{wl_output::WlOutput, wl_seat::WlSeat, wl_surface::WlSurface},
|
wayland_server::protocol::{wl_output::WlOutput, wl_seat::WlSeat},
|
||||||
},
|
},
|
||||||
utils::Serial,
|
utils::Serial,
|
||||||
wayland::{
|
wayland::{
|
||||||
|
|
@ -70,7 +67,7 @@ impl XdgShellHandler for State {
|
||||||
let kind = PopupKind::Xdg(surface);
|
let kind = PopupKind::Xdg(surface);
|
||||||
if let Some(root) = find_popup_root_surface(&kind)
|
if let Some(root) = find_popup_root_surface(&kind)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|root| self.common.shell.element_for_surface(&root))
|
.and_then(|root| self.common.shell.element_for_wl_surface(&root))
|
||||||
{
|
{
|
||||||
let target = root.clone().into();
|
let target = root.clone().into();
|
||||||
let ret = self
|
let ret = self
|
||||||
|
|
@ -138,38 +135,7 @@ impl XdgShellHandler for State {
|
||||||
|
|
||||||
fn move_request(&mut self, surface: ToplevelSurface, seat: WlSeat, serial: Serial) {
|
fn move_request(&mut self, surface: ToplevelSurface, seat: WlSeat, serial: Serial) {
|
||||||
let seat = Seat::from_resource(&seat).unwrap();
|
let seat = Seat::from_resource(&seat).unwrap();
|
||||||
if let Some(start_data) = check_grab_preconditions(&seat, surface.wl_surface(), serial) {
|
Shell::move_request(self, surface.wl_surface(), &seat, serial)
|
||||||
if let Some(mapped) = self
|
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.element_for_surface(surface.wl_surface())
|
|
||||||
.cloned()
|
|
||||||
{
|
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
|
||||||
let output = seat.active_output();
|
|
||||||
let (window, _) = mapped
|
|
||||||
.windows()
|
|
||||||
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
|
|
||||||
.unwrap();
|
|
||||||
if let Some(grab) =
|
|
||||||
workspace.move_request(&window, &seat, &output, serial, start_data)
|
|
||||||
{
|
|
||||||
let handle = workspace.handle;
|
|
||||||
self.common
|
|
||||||
.shell
|
|
||||||
.toplevel_info_state
|
|
||||||
.toplevel_leave_workspace(&window, &handle);
|
|
||||||
self.common
|
|
||||||
.shell
|
|
||||||
.toplevel_info_state
|
|
||||||
.toplevel_leave_output(&window, &output);
|
|
||||||
seat.get_pointer()
|
|
||||||
.unwrap()
|
|
||||||
.set_grab(self, grab, serial, Focus::Clear);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resize_request(
|
fn resize_request(
|
||||||
|
|
@ -180,24 +146,7 @@ impl XdgShellHandler for State {
|
||||||
edges: xdg_toplevel::ResizeEdge,
|
edges: xdg_toplevel::ResizeEdge,
|
||||||
) {
|
) {
|
||||||
let seat = Seat::from_resource(&seat).unwrap();
|
let seat = Seat::from_resource(&seat).unwrap();
|
||||||
if let Some(start_data) = check_grab_preconditions(&seat, surface.wl_surface(), serial) {
|
Shell::resize_request(self, surface.wl_surface(), &seat, serial, edges.into())
|
||||||
if let Some(mapped) = self
|
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.element_for_surface(surface.wl_surface())
|
|
||||||
.cloned()
|
|
||||||
{
|
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
|
||||||
if let Some(grab) =
|
|
||||||
workspace.resize_request(&mapped, &seat, serial, start_data, edges)
|
|
||||||
{
|
|
||||||
seat.get_pointer()
|
|
||||||
.unwrap()
|
|
||||||
.set_grab(self, grab, serial, Focus::Clear);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximize_request(&mut self, surface: ToplevelSurface) {
|
fn maximize_request(&mut self, surface: ToplevelSurface) {
|
||||||
|
|
@ -207,7 +156,7 @@ impl XdgShellHandler for State {
|
||||||
if let Some(mapped) = self
|
if let Some(mapped) = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.element_for_surface(surface.wl_surface())
|
.element_for_wl_surface(surface.wl_surface())
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
||||||
|
|
@ -224,7 +173,7 @@ impl XdgShellHandler for State {
|
||||||
if let Some(mapped) = self
|
if let Some(mapped) = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.element_for_surface(surface.wl_surface())
|
.element_for_wl_surface(surface.wl_surface())
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
||||||
|
|
@ -249,7 +198,7 @@ impl XdgShellHandler for State {
|
||||||
if let Some(mapped) = self
|
if let Some(mapped) = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.element_for_surface(surface.wl_surface())
|
.element_for_wl_surface(surface.wl_surface())
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
||||||
|
|
@ -266,7 +215,7 @@ impl XdgShellHandler for State {
|
||||||
if let Some(mapped) = self
|
if let Some(mapped) = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.element_for_surface(surface.wl_surface())
|
.element_for_wl_surface(surface.wl_surface())
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
||||||
|
|
@ -319,36 +268,4 @@ impl XdgShellHandler for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_grab_preconditions(
|
|
||||||
seat: &Seat<State>,
|
|
||||||
surface: &WlSurface,
|
|
||||||
serial: Serial,
|
|
||||||
) -> Option<PointerGrabStartData<State>> {
|
|
||||||
use smithay::reexports::wayland_server::Resource;
|
|
||||||
|
|
||||||
// TODO: touch resize.
|
|
||||||
let pointer = seat.get_pointer().unwrap();
|
|
||||||
|
|
||||||
// Check that this surface has a click grab.
|
|
||||||
if !pointer.has_grab(serial) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let start_data = pointer.grab_start_data().unwrap();
|
|
||||||
|
|
||||||
// If the focus was for a different surface, ignore the request.
|
|
||||||
if start_data.focus.is_none()
|
|
||||||
|| !start_data
|
|
||||||
.focus
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.0
|
|
||||||
.same_client_as(&surface.id())
|
|
||||||
{
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(start_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate_xdg_shell!(State);
|
delegate_xdg_shell!(State);
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ use std::sync::Mutex;
|
||||||
impl Shell {
|
impl Shell {
|
||||||
pub fn unconstrain_popup(&self, surface: &PopupSurface, positioner: &PositionerState) {
|
pub fn unconstrain_popup(&self, surface: &PopupSurface, positioner: &PositionerState) {
|
||||||
if let Some(parent) = get_popup_toplevel(&surface) {
|
if let Some(parent) = get_popup_toplevel(&surface) {
|
||||||
if let Some(elem) = self.element_for_surface(&parent) {
|
if let Some(elem) = self.element_for_wl_surface(&parent) {
|
||||||
let workspace = self.space_for(elem).unwrap();
|
let workspace = self.space_for(elem).unwrap();
|
||||||
let element_geo = workspace.element_geometry(elem).unwrap();
|
let element_geo = workspace.element_geometry(elem).unwrap();
|
||||||
let (window, offset) = elem
|
let (window, offset) = elem
|
||||||
|
|
|
||||||
371
src/xwayland.rs
Normal file
371
src/xwayland.rs
Normal file
|
|
@ -0,0 +1,371 @@
|
||||||
|
use crate::{
|
||||||
|
backend::render::cursor::Cursor,
|
||||||
|
shell::{CosmicSurface, Shell},
|
||||||
|
state::{Data, State},
|
||||||
|
utils::prelude::SeatExt,
|
||||||
|
wayland::{handlers::screencopy::PendingScreencopyBuffers, protocols::screencopy::SessionType},
|
||||||
|
};
|
||||||
|
use smithay::{
|
||||||
|
backend::drm::DrmNode,
|
||||||
|
reexports::x11rb::protocol::xproto::Window as X11Window,
|
||||||
|
utils::{Logical, Point, Rectangle, Size},
|
||||||
|
xwayland::{
|
||||||
|
xwm::{Reorder, XwmId},
|
||||||
|
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct XWaylandState {
|
||||||
|
pub xwm: Option<X11Wm>,
|
||||||
|
pub display: Option<u32>,
|
||||||
|
#[allow(unused)]
|
||||||
|
xwayland: XWayland,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn launch_xwayland(&mut self, drm_node: Option<DrmNode>) {
|
||||||
|
if self.common.xwayland_state.contains_key(&drm_node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (xwayland, source) = XWayland::new(None, &self.common.display_handle);
|
||||||
|
let token =
|
||||||
|
match self
|
||||||
|
.common
|
||||||
|
.event_loop_handle
|
||||||
|
.insert_source(source, move |event, _, data| match event {
|
||||||
|
XWaylandEvent::Ready {
|
||||||
|
connection,
|
||||||
|
client,
|
||||||
|
client_fd: _,
|
||||||
|
display,
|
||||||
|
} => {
|
||||||
|
let mut wm = match X11Wm::start_wm(
|
||||||
|
data.state.common.event_loop_handle.clone(),
|
||||||
|
data.state.common.display_handle.clone(),
|
||||||
|
connection,
|
||||||
|
client,
|
||||||
|
None,
|
||||||
|
) {
|
||||||
|
Ok(wm) => wm,
|
||||||
|
Err(err) => {
|
||||||
|
slog_scope::error!("Failed to start Xwayland WM: {}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let cursor = Cursor::load();
|
||||||
|
let image = cursor.get_image(1, 0);
|
||||||
|
if let Err(err) = wm.set_cursor(
|
||||||
|
&image.pixels_rgba,
|
||||||
|
Size::from((image.width as u16, image.height as u16)),
|
||||||
|
Point::from((image.xhot as u16, image.yhot as u16)),
|
||||||
|
) {
|
||||||
|
slog_scope::warn!(
|
||||||
|
"Failed to set default cursor for Xwayland WM ({:?}): {}",
|
||||||
|
wm.id(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut xwayland_state =
|
||||||
|
data.state.common.xwayland_state.get_mut(&drm_node).unwrap();
|
||||||
|
xwayland_state.xwm = Some(wm);
|
||||||
|
xwayland_state.display = Some(display);
|
||||||
|
}
|
||||||
|
XWaylandEvent::Exited => {
|
||||||
|
if let Some(mut xwayland_state) =
|
||||||
|
data.state.common.xwayland_state.remove(&drm_node)
|
||||||
|
{
|
||||||
|
xwayland_state.xwm = None;
|
||||||
|
xwayland_state.display = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Ok(token) => token,
|
||||||
|
Err(err) => {
|
||||||
|
slog_scope::error!("Failed to listen for Xwayland: {}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match xwayland.start(self.common.event_loop_handle.clone()) {
|
||||||
|
Ok(_) => {
|
||||||
|
self.common.xwayland_state.insert(
|
||||||
|
drm_node,
|
||||||
|
XWaylandState {
|
||||||
|
xwayland,
|
||||||
|
xwm: None,
|
||||||
|
display: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
slog_scope::error!("Failed to start Xwayland: {}", err);
|
||||||
|
self.common.event_loop_handle.remove(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XwmHandler for Data {
|
||||||
|
fn xwm_state(&mut self, xwm: XwmId) -> &mut X11Wm {
|
||||||
|
self.state
|
||||||
|
.common
|
||||||
|
.xwayland_state
|
||||||
|
.values_mut()
|
||||||
|
.flat_map(|state| &mut state.xwm)
|
||||||
|
.find(|wm| wm.id() == xwm)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
|
||||||
|
fn new_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
|
||||||
|
fn destroyed_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
|
||||||
|
|
||||||
|
fn map_window_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
if let Err(err) = window.set_mapped(true) {
|
||||||
|
slog_scope::warn!(
|
||||||
|
"Failed to send Xwayland Mapped-Event (for window {:?}): {}",
|
||||||
|
window,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let window = CosmicSurface::X11(window);
|
||||||
|
self.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.toplevel_info_state
|
||||||
|
.new_toplevel(&window);
|
||||||
|
|
||||||
|
let seat = self.state.common.last_active_seat().clone();
|
||||||
|
let output = seat.active_output();
|
||||||
|
self.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.pending_windows
|
||||||
|
.push((window.clone(), seat));
|
||||||
|
Shell::map_window(&mut self.state, &window, &output);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
Shell::map_override_redirect(&mut self.state, window)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmapped_window(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
if let Some((element, space)) = self
|
||||||
|
.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.element_for_surface(&CosmicSurface::X11(window.clone()))
|
||||||
|
.cloned()
|
||||||
|
.and_then(|element| {
|
||||||
|
self.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.space_for_mut(&element)
|
||||||
|
.map(|space| (element, space))
|
||||||
|
})
|
||||||
|
{
|
||||||
|
space.unmap(&element);
|
||||||
|
}
|
||||||
|
|
||||||
|
let outputs = if let Some(wl_surface) = window.wl_surface() {
|
||||||
|
self.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.visible_outputs_for_surface(&wl_surface)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
} else {
|
||||||
|
self.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.outputs()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
};
|
||||||
|
for output in outputs.iter() {
|
||||||
|
self.state.common.shell.active_space_mut(output).refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
// screencopy
|
||||||
|
let mut scheduled_sessions = window
|
||||||
|
.wl_surface()
|
||||||
|
.map(|wl_surface| self.state.schedule_workspace_sessions(&wl_surface))
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
for output in outputs.into_iter() {
|
||||||
|
if let Some(sessions) = output.user_data().get::<PendingScreencopyBuffers>() {
|
||||||
|
scheduled_sessions
|
||||||
|
.get_or_insert_with(Vec::new)
|
||||||
|
.extend(sessions.borrow_mut().drain(..));
|
||||||
|
}
|
||||||
|
self.state.backend.schedule_render(
|
||||||
|
&self.state.common.event_loop_handle,
|
||||||
|
&output,
|
||||||
|
scheduled_sessions.as_ref().map(|sessions| {
|
||||||
|
sessions
|
||||||
|
.iter()
|
||||||
|
.filter(|(s, _)| match s.session_type() {
|
||||||
|
SessionType::Output(o) | SessionType::Workspace(o, _)
|
||||||
|
if o == output =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_request(
|
||||||
|
&mut self,
|
||||||
|
_xwm: XwmId,
|
||||||
|
window: X11Surface,
|
||||||
|
_x: Option<i32>,
|
||||||
|
_y: Option<i32>,
|
||||||
|
w: Option<u32>,
|
||||||
|
h: Option<u32>,
|
||||||
|
_reorder: Option<Reorder>,
|
||||||
|
) {
|
||||||
|
// We only allow floating X11 windows to resize themselves. Nothing else
|
||||||
|
let current_size = window.geometry().size;
|
||||||
|
if let Some(mapped) = self
|
||||||
|
.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.element_for_surface(&CosmicSurface::X11(window))
|
||||||
|
{
|
||||||
|
let space = self.state.common.shell.space_for(mapped).unwrap();
|
||||||
|
if space.is_floating(mapped) {
|
||||||
|
mapped.set_size(
|
||||||
|
(
|
||||||
|
w.map(|w| w as i32).unwrap_or(current_size.w),
|
||||||
|
h.map(|h| h as i32).unwrap_or(current_size.h),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_notify(
|
||||||
|
&mut self,
|
||||||
|
_xwm: XwmId,
|
||||||
|
window: X11Surface,
|
||||||
|
_geometry: Rectangle<i32, Logical>,
|
||||||
|
above: Option<X11Window>,
|
||||||
|
) {
|
||||||
|
if window.is_override_redirect() {
|
||||||
|
if let Some(or) = self
|
||||||
|
.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.override_redirect_windows
|
||||||
|
.iter_mut()
|
||||||
|
.find(|or| or.surface == window)
|
||||||
|
{
|
||||||
|
or.above = above;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize_request(
|
||||||
|
&mut self,
|
||||||
|
_xwm: XwmId,
|
||||||
|
window: X11Surface,
|
||||||
|
_button: u32,
|
||||||
|
resize_edge: smithay::xwayland::xwm::ResizeEdge,
|
||||||
|
) {
|
||||||
|
if let Some(wl_surface) = window.wl_surface() {
|
||||||
|
let seat = self.state.common.last_active_seat().clone();
|
||||||
|
Shell::resize_request(
|
||||||
|
&mut self.state,
|
||||||
|
&wl_surface,
|
||||||
|
&seat,
|
||||||
|
None,
|
||||||
|
resize_edge.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_request(&mut self, _xwm: XwmId, window: X11Surface, _button: u32) {
|
||||||
|
if let Some(wl_surface) = window.wl_surface() {
|
||||||
|
let seat = self.state.common.last_active_seat().clone();
|
||||||
|
Shell::move_request(&mut self.state, &wl_surface, &seat, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
let seat = self.state.common.last_active_seat();
|
||||||
|
let output = seat.active_output();
|
||||||
|
let surface = CosmicSurface::X11(window);
|
||||||
|
|
||||||
|
if let Some(mapped) = self
|
||||||
|
.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.element_for_surface(&surface)
|
||||||
|
.cloned()
|
||||||
|
{
|
||||||
|
if let Some(workspace) = self.state.common.shell.space_for_mut(&mapped) {
|
||||||
|
let (window, _) = mapped.windows().find(|(w, _)| w == &surface).unwrap();
|
||||||
|
workspace.maximize_request(&window, &output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmaximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
let surface = CosmicSurface::X11(window);
|
||||||
|
if let Some(mapped) = self
|
||||||
|
.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.element_for_surface(&surface)
|
||||||
|
.cloned()
|
||||||
|
{
|
||||||
|
if let Some(workspace) = self.state.common.shell.space_for_mut(&mapped) {
|
||||||
|
let (window, _) = mapped.windows().find(|(w, _)| w == &surface).unwrap();
|
||||||
|
workspace.unmaximize_request(&window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
let seat = self.state.common.last_active_seat();
|
||||||
|
let output = seat.active_output();
|
||||||
|
let surface = CosmicSurface::X11(window);
|
||||||
|
|
||||||
|
if let Some(mapped) = self
|
||||||
|
.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.element_for_surface(&surface)
|
||||||
|
.cloned()
|
||||||
|
{
|
||||||
|
if let Some(workspace) = self.state.common.shell.space_for_mut(&mapped) {
|
||||||
|
let (window, _) = mapped.windows().find(|(w, _)| w == &surface).unwrap();
|
||||||
|
workspace.fullscreen_request(&window, &output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unfullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
let surface = CosmicSurface::X11(window);
|
||||||
|
if let Some(mapped) = self
|
||||||
|
.state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.element_for_surface(&surface)
|
||||||
|
.cloned()
|
||||||
|
{
|
||||||
|
if let Some(workspace) = self.state.common.shell.space_for_mut(&mapped) {
|
||||||
|
let (window, _) = mapped.windows().find(|(w, _)| w == &surface).unwrap();
|
||||||
|
workspace.unfullscreen_request(&window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue