parent
8892570093
commit
cf439000a5
6 changed files with 284 additions and 83 deletions
|
|
@ -815,9 +815,9 @@ impl<C: XConnection> Dispatch<XdgOutputServer, ObjectKey> for ServerState<C> {
|
|||
unreachable!();
|
||||
};
|
||||
|
||||
let output: &XdgOutput = state.objects[*key].as_ref();
|
||||
output.client.destroy();
|
||||
state.objects.remove(*key);
|
||||
let output: &mut Output = state.objects[*key].as_mut();
|
||||
let xdg_output = output.xdg.take().unwrap();
|
||||
xdg_output.client.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -836,14 +836,10 @@ impl<C: XConnection> Dispatch<OutputManServer, ClientGlobalWrapper<OutputManClie
|
|||
match request {
|
||||
s_output_man::Request::GetXdgOutput { id, output } => {
|
||||
let output_key: ObjectKey = output.data().copied().unwrap();
|
||||
state
|
||||
.objects
|
||||
.insert_from_other_objects([output_key], |[output_obj], key| {
|
||||
let output: &Output = output_obj.try_into().unwrap();
|
||||
let client = client.get_xdg_output(&output.client, &state.qh, key);
|
||||
let server = data_init.init(id, key);
|
||||
XdgOutput { server, client }.into()
|
||||
});
|
||||
let output: &mut Output = state.objects[output_key].as_mut();
|
||||
let client = client.get_xdg_output(&output.client, &state.qh, output_key);
|
||||
let server = data_init.init(id, output_key);
|
||||
output.xdg = Some(XdgOutput { client, server });
|
||||
}
|
||||
s_output_man::Request::Destroy => {}
|
||||
_ => unreachable!(),
|
||||
|
|
|
|||
|
|
@ -162,12 +162,13 @@ impl SurfaceData {
|
|||
.as_ref()
|
||||
.map(|win| state.windows.get_mut(&win).unwrap())
|
||||
{
|
||||
let (x, y) = match output.position {
|
||||
OutputPosition::Xdg { x, y } => (x, y),
|
||||
OutputPosition::Wl { x, y } => (x, y),
|
||||
};
|
||||
win_data.update_output_offset(
|
||||
key,
|
||||
WindowOutputOffset {
|
||||
x: output.x,
|
||||
y: output.y,
|
||||
},
|
||||
WindowOutputOffset { x, y },
|
||||
state.connection.as_mut().unwrap(),
|
||||
);
|
||||
output.windows.insert(win_data.window);
|
||||
|
|
@ -326,22 +327,6 @@ impl HandleEvent for Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub type XdgOutput = GenericObject<ServerXdgOutput, ClientXdgOutput>;
|
||||
impl HandleEvent for XdgOutput {
|
||||
type Event = zxdg_output_v1::Event;
|
||||
fn handle_event<C: XConnection>(&mut self, event: Self::Event, _: &mut ServerState<C>) {
|
||||
simple_event_shunt! {
|
||||
self.server, event: zxdg_output_v1::Event => [
|
||||
LogicalPosition { x, y },
|
||||
LogicalSize { width, height },
|
||||
Done,
|
||||
Name { name },
|
||||
Description { description }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Seat = GenericObject<WlSeat, client::wl_seat::WlSeat>;
|
||||
impl HandleEvent for Seat {
|
||||
type Event = client::wl_seat::Event;
|
||||
|
|
@ -647,12 +632,23 @@ impl HandleEvent for Touch {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct XdgOutput {
|
||||
pub client: ClientXdgOutput,
|
||||
pub server: ServerXdgOutput,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum OutputPosition {
|
||||
Wl { x: i32, y: i32 },
|
||||
Xdg { x: i32, y: i32 },
|
||||
}
|
||||
|
||||
pub struct Output {
|
||||
pub client: client::wl_output::WlOutput,
|
||||
pub server: WlOutput,
|
||||
pub windows: HashSet<x::Window>,
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub xdg: Option<XdgOutput>,
|
||||
windows: HashSet<x::Window>,
|
||||
position: OutputPosition,
|
||||
}
|
||||
|
||||
impl Output {
|
||||
|
|
@ -660,21 +656,60 @@ impl Output {
|
|||
Self {
|
||||
client,
|
||||
server,
|
||||
xdg: None,
|
||||
windows: HashSet::new(),
|
||||
x: 0,
|
||||
y: 0,
|
||||
position: OutputPosition::Wl { x: 0, y: 0 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutputEvent {
|
||||
Wl(client::wl_output::Event),
|
||||
Xdg(zxdg_output_v1::Event),
|
||||
}
|
||||
|
||||
impl From<client::wl_output::Event> for ObjectEvent {
|
||||
fn from(value: client::wl_output::Event) -> Self {
|
||||
Self::Output(OutputEvent::Wl(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<zxdg_output_v1::Event> for ObjectEvent {
|
||||
fn from(value: zxdg_output_v1::Event) -> Self {
|
||||
Self::Output(OutputEvent::Xdg(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl HandleEvent for Output {
|
||||
type Event = client::wl_output::Event;
|
||||
type Event = OutputEvent;
|
||||
|
||||
fn handle_event<C: XConnection>(&mut self, event: Self::Event, state: &mut ServerState<C>) {
|
||||
if let client::wl_output::Event::Geometry { x, y, .. } = event {
|
||||
debug!("moving {} to {x}x{y}", self.server.id());
|
||||
self.x = x;
|
||||
self.y = y;
|
||||
match event {
|
||||
OutputEvent::Xdg(event) => self.xdg_event(event, state),
|
||||
OutputEvent::Wl(event) => self.wl_event(event, state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Output {
|
||||
fn update_offset<C: XConnection>(
|
||||
&mut self,
|
||||
offset: OutputPosition,
|
||||
state: &mut ServerState<C>,
|
||||
) {
|
||||
if matches!(offset, OutputPosition::Wl { .. })
|
||||
&& matches!(self.position, OutputPosition::Xdg { .. })
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self.position = offset;
|
||||
let (x, y, id) = match offset {
|
||||
OutputPosition::Xdg { x, y } => (x, y, self.xdg.as_ref().unwrap().server.id()),
|
||||
OutputPosition::Wl { x, y } => (x, y, self.server.id()),
|
||||
};
|
||||
debug!("moving {id} to {x}x{y}");
|
||||
self.windows.retain(|window| {
|
||||
let Some(data): Option<&mut WindowData> = state.windows.get_mut(window) else {
|
||||
return false;
|
||||
|
|
@ -682,16 +717,21 @@ impl HandleEvent for Output {
|
|||
|
||||
data.update_output_offset(
|
||||
self.server.data().copied().unwrap(),
|
||||
WindowOutputOffset {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
},
|
||||
WindowOutputOffset { x, y },
|
||||
state.connection.as_mut().unwrap(),
|
||||
);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
fn wl_event<C: XConnection>(
|
||||
&mut self,
|
||||
event: client::wl_output::Event,
|
||||
state: &mut ServerState<C>,
|
||||
) {
|
||||
if let client::wl_output::Event::Geometry { x, y, .. } = event {
|
||||
self.update_offset(OutputPosition::Wl { x, y }, state);
|
||||
}
|
||||
|
||||
simple_event_shunt! {
|
||||
self.server, event: client::wl_output::Event => [
|
||||
|
|
@ -718,6 +758,26 @@ impl HandleEvent for Output {
|
|||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn xdg_event<C: XConnection>(
|
||||
&mut self,
|
||||
event: zxdg_output_v1::Event,
|
||||
state: &mut ServerState<C>,
|
||||
) {
|
||||
if let zxdg_output_v1::Event::LogicalPosition { x, y } = event {
|
||||
self.update_offset(OutputPosition::Xdg { x, y }, state);
|
||||
}
|
||||
let xdg = &self.xdg.as_ref().unwrap().server;
|
||||
simple_event_shunt! {
|
||||
xdg, event: zxdg_output_v1::Event => [
|
||||
LogicalPosition { x, y },
|
||||
LogicalSize { width, height },
|
||||
Done,
|
||||
Name { name },
|
||||
Description { description }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Drm = GenericObject<WlDrmServer, WlDrmClient>;
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ impl WindowData {
|
|||
offset: WindowOutputOffset,
|
||||
connection: &mut C,
|
||||
) {
|
||||
debug!("offset: {offset:?}");
|
||||
log::trace!("offset: {offset:?}");
|
||||
if self.output_key != Some(output_key) {
|
||||
self.output_key = Some(output_key);
|
||||
}
|
||||
|
|
@ -360,7 +360,6 @@ pub(crate) enum Object {
|
|||
RelativePointer(RelativePointer),
|
||||
DmabufFeedback(DmabufFeedback),
|
||||
Drm(Drm),
|
||||
XdgOutput(XdgOutput),
|
||||
Touch(Touch),
|
||||
ConfinedPointer(ConfinedPointer),
|
||||
LockedPointer(LockedPointer)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,10 @@ use wayland_protocols::{
|
|||
},
|
||||
xdg::{
|
||||
shell::server::{xdg_positioner, xdg_toplevel},
|
||||
xdg_output::zv1::client::zxdg_output_manager_v1::ZxdgOutputManagerV1,
|
||||
xdg_output::zv1::client::{
|
||||
zxdg_output_manager_v1::{self, ZxdgOutputManagerV1},
|
||||
zxdg_output_v1::ZxdgOutputV1,
|
||||
},
|
||||
},
|
||||
xwayland::shell::v1::client::{
|
||||
xwayland_shell_v1::XwaylandShellV1, xwayland_surface_v1::XwaylandSurfaceV1,
|
||||
|
|
@ -371,7 +374,14 @@ impl TestFixture {
|
|||
}
|
||||
}
|
||||
|
||||
fn new_output(&mut self, x: i32, y: i32) -> wayland_server::protocol::wl_output::WlOutput {
|
||||
fn new_output(
|
||||
&mut self,
|
||||
x: i32,
|
||||
y: i32,
|
||||
) -> (
|
||||
TestObject<WlOutput>,
|
||||
wayland_server::protocol::wl_output::WlOutput,
|
||||
) {
|
||||
self.testwl.new_output(x, y);
|
||||
self.run();
|
||||
self.run();
|
||||
|
|
@ -388,7 +398,7 @@ impl TestFixture {
|
|||
};
|
||||
|
||||
assert_eq!(interface, WlOutput::interface().name);
|
||||
TestObject::<WlOutput>::from_request(
|
||||
let output = TestObject::<WlOutput>::from_request(
|
||||
&self.registry.obj,
|
||||
Req::<WlRegistry>::Bind {
|
||||
name,
|
||||
|
|
@ -396,7 +406,49 @@ impl TestFixture {
|
|||
},
|
||||
);
|
||||
self.run();
|
||||
self.testwl.last_created_output()
|
||||
(output, self.testwl.last_created_output())
|
||||
}
|
||||
|
||||
fn enable_xdg_output(&mut self) -> TestObject<ZxdgOutputManagerV1> {
|
||||
self.testwl.enable_xdg_output_manager();
|
||||
self.run();
|
||||
self.run();
|
||||
|
||||
let mut events = std::mem::take(&mut *self.registry.data.events.lock().unwrap());
|
||||
assert_eq!(
|
||||
events.len(),
|
||||
1,
|
||||
"Unexpected number of global events after enabling xdg output"
|
||||
);
|
||||
let event = events.pop().unwrap();
|
||||
let Ev::<WlRegistry>::Global {
|
||||
name,
|
||||
interface,
|
||||
version,
|
||||
} = event
|
||||
else {
|
||||
panic!("Unexpected event: {event:?}");
|
||||
};
|
||||
|
||||
assert_eq!(interface, ZxdgOutputManagerV1::interface().name);
|
||||
let man = TestObject::<ZxdgOutputManagerV1>::from_request(
|
||||
&self.registry.obj,
|
||||
Req::<WlRegistry>::Bind {
|
||||
name,
|
||||
id: (ZxdgOutputManagerV1::interface(), version),
|
||||
},
|
||||
);
|
||||
self.run();
|
||||
man
|
||||
}
|
||||
|
||||
fn create_xdg_output(&mut self, man: &TestObject<ZxdgOutputManagerV1>, output: WlOutput) {
|
||||
TestObject::<ZxdgOutputV1>::from_request(
|
||||
&man.obj,
|
||||
zxdg_output_manager_v1::Request::GetXdgOutput { output },
|
||||
);
|
||||
self.run();
|
||||
self.run();
|
||||
}
|
||||
|
||||
fn register_window(&mut self, window: Window, data: WindowData) {
|
||||
|
|
@ -744,6 +796,8 @@ fn pass_through_globals() {
|
|||
|
||||
let mut f = TestFixture::new();
|
||||
f.testwl.new_output(0, 0);
|
||||
f.testwl.enable_xdg_output_manager();
|
||||
f.run();
|
||||
f.run();
|
||||
|
||||
const fn check<T: Proxy>() {}
|
||||
|
|
@ -1214,7 +1268,11 @@ fn override_redirect_choose_hover_window() {
|
|||
#[test]
|
||||
fn output_offset() {
|
||||
let (mut f, comp) = TestFixture::new_with_compositor();
|
||||
let output = f.new_output(500, 100);
|
||||
let (output_obj, output) = f.new_output(0, 0);
|
||||
let man = f.enable_xdg_output();
|
||||
f.create_xdg_output(&man, output_obj.obj);
|
||||
f.testwl.move_xdg_output(&output, 500, 100);
|
||||
f.run();
|
||||
let window = unsafe { Window::new(1) };
|
||||
|
||||
{
|
||||
|
|
@ -1285,22 +1343,38 @@ fn output_offset() {
|
|||
#[test]
|
||||
fn output_offset_change() {
|
||||
let (mut f, comp) = TestFixture::new_with_compositor();
|
||||
let output = f.new_output(500, 100);
|
||||
|
||||
let (output_obj, output) = f.new_output(500, 100);
|
||||
let window = unsafe { Window::new(1) };
|
||||
let (_, id) = f.create_toplevel(&comp, window);
|
||||
f.testwl.move_surface_to_output(id, &output);
|
||||
f.run();
|
||||
|
||||
let test_position = |f: &TestFixture, x, y| {
|
||||
let data = &f.connection().windows[&window];
|
||||
assert_eq!(data.dims.x, 500);
|
||||
assert_eq!(data.dims.y, 100);
|
||||
assert_eq!(data.dims.x, x);
|
||||
assert_eq!(data.dims.y, y);
|
||||
};
|
||||
test_position(&f, 500, 100);
|
||||
|
||||
f.testwl.move_output(&output, 600, 200);
|
||||
f.run();
|
||||
f.run();
|
||||
let data = &f.connection().windows[&window];
|
||||
assert_eq!(data.dims.x, 600);
|
||||
assert_eq!(data.dims.y, 200);
|
||||
test_position(&f, 600, 200);
|
||||
|
||||
let man = f.enable_xdg_output();
|
||||
f.create_xdg_output(&man, output_obj.obj);
|
||||
// testwl inits xdg output position to 0, and it should take priority over wl_output position
|
||||
test_position(&f, 0, 0);
|
||||
|
||||
f.testwl.move_xdg_output(&output, 1000, 22);
|
||||
f.run();
|
||||
test_position(&f, 1000, 22);
|
||||
|
||||
f.testwl.move_output(&output, 600, 200);
|
||||
f.run();
|
||||
f.run();
|
||||
test_position(&f, 1000, 22);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -829,6 +829,7 @@ fn copy_from_wayland() {
|
|||
#[test]
|
||||
fn different_output_position() {
|
||||
let mut f = Fixture::new();
|
||||
//f.testwl.enable_xdg_output_manager();
|
||||
let mut connection = Connection::new(&f.display);
|
||||
|
||||
let window = connection.new_window(connection.root, 0, 0, 200, 200, false);
|
||||
|
|
@ -854,6 +855,7 @@ fn different_output_position() {
|
|||
f.testwl.new_output(100, 0);
|
||||
f.wait_and_dispatch();
|
||||
let output = f.testwl.last_created_output();
|
||||
//f.testwl.move_xdg_output(&output, 100, 0);
|
||||
f.testwl.move_surface_to_output(surface, &output);
|
||||
f.testwl.move_pointer_to(surface, 150.0, 12.0);
|
||||
f.wait_and_dispatch();
|
||||
|
|
@ -986,12 +988,7 @@ fn funny_window_title() {
|
|||
let mut f = Fixture::new();
|
||||
let mut connection = Connection::new(&f.display);
|
||||
let window = connection.new_window(connection.root, 0, 0, 20, 20, false);
|
||||
connection.set_property(
|
||||
window,
|
||||
x::ATOM_STRING,
|
||||
x::ATOM_WM_NAME,
|
||||
b"title\0\0\0\0",
|
||||
);
|
||||
connection.set_property(window, x::ATOM_STRING, x::ATOM_WM_NAME, b"title\0\0\0\0");
|
||||
connection.map_window(window);
|
||||
f.wait_and_dispatch();
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ use wayland_protocols::{
|
|||
xdg_toplevel::{self, XdgToplevel},
|
||||
xdg_wm_base::{self, XdgWmBase},
|
||||
},
|
||||
xdg_output::zv1::server::zxdg_output_manager_v1::ZxdgOutputManagerV1,
|
||||
xdg_output::zv1::server::{
|
||||
zxdg_output_manager_v1::{self, ZxdgOutputManagerV1},
|
||||
zxdg_output_v1::{self, ZxdgOutputV1},
|
||||
},
|
||||
},
|
||||
};
|
||||
use wayland_server::{
|
||||
|
|
@ -153,13 +156,19 @@ struct DataSourceData {
|
|||
mimes: Vec<String>,
|
||||
}
|
||||
|
||||
struct Output {
|
||||
wl: WlOutput,
|
||||
xdg: Option<ZxdgOutputV1>,
|
||||
}
|
||||
|
||||
struct State {
|
||||
surfaces: HashMap<SurfaceId, SurfaceData>,
|
||||
outputs: Vec<WlOutput>,
|
||||
outputs: HashMap<WlOutput, Output>,
|
||||
positioners: HashMap<PositionerId, PositionerState>,
|
||||
buffers: HashSet<WlBuffer>,
|
||||
begin: Instant,
|
||||
last_surface_id: Option<SurfaceId>,
|
||||
last_output: Option<WlOutput>,
|
||||
callbacks: Vec<WlCallback>,
|
||||
pointer: Option<WlPointer>,
|
||||
keyboard: Option<WlKeyboard>,
|
||||
|
|
@ -178,6 +187,7 @@ impl Default for State {
|
|||
positioners: Default::default(),
|
||||
begin: Instant::now(),
|
||||
last_surface_id: None,
|
||||
last_output: None,
|
||||
callbacks: Vec::new(),
|
||||
pointer: None,
|
||||
keyboard: None,
|
||||
|
|
@ -302,7 +312,6 @@ impl Server {
|
|||
dh.create_global::<State, WlDataDeviceManager, _>(3, ());
|
||||
global_noop!(ZwpLinuxDmabufV1);
|
||||
global_noop!(ZwpRelativePointerManagerV1);
|
||||
global_noop!(ZxdgOutputManagerV1);
|
||||
global_noop!(WpViewporter);
|
||||
global_noop!(ZwpPointerConstraintsV1);
|
||||
|
||||
|
|
@ -397,8 +406,8 @@ impl Server {
|
|||
#[track_caller]
|
||||
pub fn last_created_output(&self) -> WlOutput {
|
||||
self.state
|
||||
.outputs
|
||||
.last()
|
||||
.last_output
|
||||
.as_ref()
|
||||
.expect("No outputs created!")
|
||||
.clone()
|
||||
}
|
||||
|
|
@ -525,6 +534,22 @@ impl Server {
|
|||
data.surface.enter(output);
|
||||
self.display.flush_clients().unwrap();
|
||||
}
|
||||
|
||||
pub fn enable_xdg_output_manager(&mut self) {
|
||||
self.dh
|
||||
.create_global::<State, ZxdgOutputManagerV1, _>(3, ());
|
||||
self.display.flush_clients().unwrap();
|
||||
}
|
||||
|
||||
pub fn move_xdg_output(&mut self, output: &WlOutput, x: i32, y: i32) {
|
||||
let xdg = self.state.outputs[output]
|
||||
.xdg
|
||||
.as_ref()
|
||||
.expect("Output doesn't have an xdg output");
|
||||
xdg.logical_position(x, y);
|
||||
xdg.done();
|
||||
self.display.flush_clients().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PasteDataResolver {
|
||||
|
|
@ -575,6 +600,49 @@ pub struct PasteData {
|
|||
simple_global_dispatch!(WlShm);
|
||||
simple_global_dispatch!(WlCompositor);
|
||||
simple_global_dispatch!(XdgWmBase);
|
||||
simple_global_dispatch!(ZxdgOutputManagerV1);
|
||||
|
||||
impl Dispatch<ZxdgOutputManagerV1, ()> for State {
|
||||
fn request(
|
||||
state: &mut Self,
|
||||
_: &Client,
|
||||
_: &ZxdgOutputManagerV1,
|
||||
request: <ZxdgOutputManagerV1 as Resource>::Request,
|
||||
_: &(),
|
||||
_: &DisplayHandle,
|
||||
data_init: &mut wayland_server::DataInit<'_, Self>,
|
||||
) {
|
||||
match request {
|
||||
zxdg_output_manager_v1::Request::GetXdgOutput { id, output } => {
|
||||
let xdg = data_init.init(id, output.clone());
|
||||
xdg.logical_position(0, 0);
|
||||
xdg.logical_size(1000, 1000);
|
||||
xdg.done();
|
||||
state.outputs.get_mut(&output).unwrap().xdg = Some(xdg);
|
||||
}
|
||||
other => todo!("unhandled request: {other:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<ZxdgOutputV1, WlOutput> for State {
|
||||
fn request(
|
||||
state: &mut Self,
|
||||
_: &Client,
|
||||
_: &ZxdgOutputV1,
|
||||
request: <ZxdgOutputV1 as Resource>::Request,
|
||||
output: &WlOutput,
|
||||
_: &DisplayHandle,
|
||||
_: &mut wayland_server::DataInit<'_, Self>,
|
||||
) {
|
||||
match request {
|
||||
zxdg_output_v1::Request::Destroy => {
|
||||
state.outputs.get_mut(output).unwrap().xdg = None;
|
||||
}
|
||||
other => todo!("unhandled request: {other:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GlobalDispatch<WlOutput, (i32, i32)> for State {
|
||||
fn bind(
|
||||
|
|
@ -598,7 +666,14 @@ impl GlobalDispatch<WlOutput, (i32, i32)> for State {
|
|||
);
|
||||
output.mode(wl_output::Mode::Current, 1000, 1000, 0);
|
||||
output.done();
|
||||
state.outputs.push(output);
|
||||
state.outputs.insert(
|
||||
output.clone(),
|
||||
Output {
|
||||
wl: output.clone(),
|
||||
xdg: None,
|
||||
},
|
||||
);
|
||||
state.last_output = Some(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue