Skip to content

Commit

Permalink
wayland: implement ext-tray-v1
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Oct 20, 2024
1 parent efe069f commit a367cf2
Show file tree
Hide file tree
Showing 25 changed files with 817 additions and 40 deletions.
1 change: 1 addition & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Jay supports the following wayland protocols:
| ext_output_image_capture_source_manager_v1 | 1 | |
| ext_session_lock_manager_v1 | 1 | Yes |
| ext_transient_seat_manager_v1 | 1[^ts_rejected] | Yes |
| ext_tray_v1 | 1 | |
| org_kde_kwin_server_decoration_manager | 1 | |
| wl_compositor | 6 | |
| wl_data_device_manager | 3 | |
Expand Down
1 change: 1 addition & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Fix screen sharing in zoom.
- Implement wp-fifo-v1.
- Implement wp-commit-timing-v1.
- Implement ext-tray-v1.

# 1.6.0 (2024-09-25)

Expand Down
2 changes: 2 additions & 0 deletions src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,8 @@ fn create_dummy_output(state: &Rc<State>) {
flip_margin_ns: Default::default(),
ext_copy_sessions: Default::default(),
before_latch_event: Default::default(),
tray_start_rel: Default::default(),
tray_items: Default::default(),
});
let dummy_workspace = Rc::new(WorkspaceNode {
id: state.node_ids.next(),
Expand Down
6 changes: 3 additions & 3 deletions src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,11 @@ impl Globals {
pub fn remove<T: RemovableWaylandGlobal>(
&self,
state: &State,
global: &T,
global: &Rc<T>,
) -> Result<(), GlobalsError> {
let _global = self.take(global.name(), true)?;
global.remove(self);
let replacement = global.create_replacement();
let replacement = global.clone().create_replacement();
assert_eq!(global.name(), replacement.name());
assert_eq!(global.interface().0, replacement.interface().0);
self.removed.set(global.name(), replacement);
Expand Down Expand Up @@ -360,5 +360,5 @@ pub trait WaylandGlobal: Global + 'static {
}

pub trait RemovableWaylandGlobal: WaylandGlobal {
fn create_replacement(&self) -> Rc<dyn Global>;
fn create_replacement(self: Rc<Self>) -> Rc<dyn Global>;
}
1 change: 1 addition & 0 deletions src/ifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod ext_image_copy;
pub mod ext_output_image_capture_source_manager_v1;
pub mod ext_session_lock_manager_v1;
pub mod ext_session_lock_v1;
pub mod ext_tray_v1;
pub mod ipc;
pub mod jay_compositor;
pub mod jay_damage_tracking;
Expand Down
109 changes: 109 additions & 0 deletions src/ifs/ext_tray_v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use {
crate::{
client::{Client, ClientError},
globals::{Global, GlobalName, RemovableWaylandGlobal},
ifs::{
wl_output::OutputGlobalOpt,
wl_surface::ext_tray_item_v1::{ExtTrayItemV1, ExtTrayItemV1Error},
},
leaks::Tracker,
object::{Object, Version},
wire::{ext_tray_v1::*, ExtTrayV1Id},
},
std::rc::Rc,
thiserror::Error,
};

pub struct ExtTrayV1Global {
pub name: GlobalName,
pub output: Rc<OutputGlobalOpt>,
}

pub struct ExtTrayV1 {
pub id: ExtTrayV1Id,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub version: Version,
pub output: Rc<OutputGlobalOpt>,
}

impl ExtTrayV1Global {
fn bind_(
self: Rc<Self>,
id: ExtTrayV1Id,
client: &Rc<Client>,
version: Version,
) -> Result<(), ExtTrayManagerV1Error> {
let obj = Rc::new(ExtTrayV1 {
id,
client: client.clone(),
tracker: Default::default(),
version,
output: self.output.clone(),
});
track!(client, obj);
client.add_client_obj(&obj)?;
Ok(())
}
}

global_base!(ExtTrayV1Global, ExtTrayV1, ExtTrayManagerV1Error);

impl Global for ExtTrayV1Global {
fn singleton(&self) -> bool {
false
}

fn version(&self) -> u32 {
1
}
}

simple_add_global!(ExtTrayV1Global);

impl RemovableWaylandGlobal for ExtTrayV1Global {
fn create_replacement(self: Rc<Self>) -> Rc<dyn Global> {
self
}
}

impl ExtTrayV1RequestHandler for ExtTrayV1 {
type Error = ExtTrayManagerV1Error;

fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.client.remove_obj(self)?;
Ok(())
}

fn get_tray_item(&self, req: GetTrayItem, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let surface = self.client.lookup(req.surface)?;
let fs = Rc::new(ExtTrayItemV1::new(
req.id,
self.version,
&surface,
&self.output,
));
track!(self.client, fs);
fs.install()?;
self.client.add_client_obj(&fs)?;
Ok(())
}
}

object_base! {
self = ExtTrayV1;
version = self.version;
}

impl Object for ExtTrayV1 {}

simple_add_obj!(ExtTrayV1);

#[derive(Debug, Error)]
pub enum ExtTrayManagerV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error(transparent)]
ExtTrayItemV1Error(#[from] ExtTrayItemV1Error),
}
efrom!(ExtTrayManagerV1Error, ClientError);
2 changes: 1 addition & 1 deletion src/ifs/wl_output/removed_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl Global for RemovedOutputGlobal {
simple_add_global!(RemovedOutputGlobal);

impl RemovableWaylandGlobal for WlOutputGlobal {
fn create_replacement(&self) -> Rc<dyn Global> {
fn create_replacement(self: Rc<Self>) -> Rc<dyn Global> {
Rc::new(RemovedOutputGlobal { name: self.name })
}
}
Expand Down
46 changes: 41 additions & 5 deletions src/ifs/wl_seat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub mod zwp_virtual_keyboard_v1;
use {
crate::{
async_engine::SpawnedFuture,
backend::KeyState,
client::{Client, ClientError, ClientId},
cursor_user::{CursorUser, CursorUserGroup, CursorUserOwner},
ei::ei_ifs::ei_seat::EiSeat,
Expand Down Expand Up @@ -64,7 +65,10 @@ use {
zwp_pointer_gesture_swipe_v1::ZwpPointerGestureSwipeV1,
zwp_relative_pointer_v1::ZwpRelativePointerV1,
},
wl_surface::{dnd_icon::DndIcon, WlSurface},
wl_surface::{
dnd_icon::DndIcon, ext_tray_item_v1::ExtTrayItemV1,
xdg_surface::xdg_popup::XdgPopup, WlSurface,
},
xdg_toplevel_drag_v1::XdgToplevelDragV1,
},
leaks::Tracker,
Expand All @@ -81,9 +85,9 @@ use {
rc_eq::rc_eq, smallmap::SmallMap,
},
wire::{
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
WlSeatId, WlTouchId, ZwlrDataControlDeviceV1Id, ZwpPrimarySelectionDeviceV1Id,
ZwpRelativePointerV1Id, ZwpTextInputV3Id,
wl_seat::*, ExtIdleNotificationV1Id, ExtTrayItemV1Id, WlDataDeviceId, WlKeyboardId,
WlPointerId, WlSeatId, WlTouchId, XdgPopupId, ZwlrDataControlDeviceV1Id,
ZwpPrimarySelectionDeviceV1Id, ZwpRelativePointerV1Id, ZwpTextInputV3Id,
},
wire_ei::EiSeatId,
xkbcommon::{DynKeyboardState, KeyboardState, KeymapId, XkbKeymap, XkbState},
Expand Down Expand Up @@ -201,6 +205,7 @@ pub struct WlSeatGlobal {
ei_seats: CopyHashMap<(ClientId, EiSeatId), Rc<EiSeat>>,
ui_drag_highlight: Cell<Option<Rect>>,
keyboard_node_serial: Cell<u64>,
tray_popups: CopyHashMap<(ClientId, ExtTrayItemV1Id, XdgPopupId), Rc<ExtTrayItemV1>>,
}

const CHANGE_CURSOR_MOVED: u32 = 1 << 0;
Expand Down Expand Up @@ -273,6 +278,7 @@ impl WlSeatGlobal {
tablet: Default::default(),
ei_seats: Default::default(),
ui_drag_highlight: Default::default(),
tray_popups: Default::default(),
});
slf.pointer_cursor.set_owner(slf.clone());
let seat = slf.clone();
Expand Down Expand Up @@ -1042,7 +1048,37 @@ impl WlSeatGlobal {
});
}

#[expect(dead_code)]
pub fn add_tray_item_popup(&self, item: &Rc<ExtTrayItemV1>, popup: &Rc<XdgPopup>) {
self.tray_popups
.set((item.client.id, item.id, popup.id), item.clone());
}

pub fn remove_tray_item_popup(&self, item: &Rc<ExtTrayItemV1>, popup: &Rc<XdgPopup>) {
self.tray_popups
.remove(&(item.client.id, item.id, popup.id));
}

fn handle_node_button(
self: &Rc<Self>,
node: Rc<dyn Node>,
time_usec: u64,
button: u32,
state: KeyState,
serial: u64,
) {
if self.tray_popups.is_not_empty() && state == KeyState::Pressed {
let id = node.node_tray_item().map(|t| (t.client.id, t.id));
self.tray_popups.lock().retain(|_, item| {
let retain = Some((item.client.id, item.id)) == id;
if !retain {
item.destroy_popups();
}
retain
})
}
node.node_on_button(self, time_usec, button, state, serial);
}

pub fn handle_focus_request(self: &Rc<Self>, client: &Client, node: Rc<dyn Node>, serial: u64) {
let Some(max_serial) = client.focus_stealing_serial.get() else {
return;
Expand Down
6 changes: 2 additions & 4 deletions src/ifs/wl_seat/pointer_owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ impl<T: SimplePointerOwnerUsecase> PointerOwner for SimplePointerOwner<T> {
serial,
}));
pn.node_seat_state().add_pointer_grab(seat);
pn.node_on_button(seat, time_usec, button, state, serial);
seat.handle_node_button(pn, time_usec, button, state, serial);
}

fn axis_node(&self, seat: &Rc<WlSeatGlobal>) -> Option<Rc<dyn Node>> {
Expand Down Expand Up @@ -448,9 +448,7 @@ impl<T: SimplePointerOwnerUsecase> PointerOwner for SimpleGrabPointerOwner<T> {
}
}
let serial = seat.state.next_serial(self.node.node_client().as_deref());
self.node
.clone()
.node_on_button(seat, time_usec, button, state, serial);
seat.handle_node_button(self.node.clone(), time_usec, button, state, serial);
}

fn axis_node(&self, _seat: &Rc<WlSeatGlobal>) -> Option<Rc<dyn Node>> {
Expand Down
14 changes: 14 additions & 0 deletions src/ifs/wl_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod commit_timeline;
pub mod cursor;
pub mod dnd_icon;
pub mod ext_session_lock_surface_v1;
pub mod ext_tray_item_v1;
pub mod wl_subsurface;
pub mod wp_alpha_modifier_surface_v1;
pub mod wp_commit_timer_v1;
Expand Down Expand Up @@ -46,6 +47,7 @@ use {
commit_timeline::{ClearReason, CommitTimeline, CommitTimelineError},
cursor::CursorSurface,
dnd_icon::DndIcon,
ext_tray_item_v1::ExtTrayItemV1,
wl_subsurface::{PendingSubsurfaceData, SubsurfaceId, WlSubsurface},
wp_alpha_modifier_surface_v1::WpAlphaModifierSurfaceV1,
wp_commit_timer_v1::WpCommitTimerV1,
Expand Down Expand Up @@ -126,6 +128,7 @@ pub enum SurfaceRole {
XSurface,
ExtSessionLockSurface,
InputPopup,
TrayItem,
}

impl SurfaceRole {
Expand All @@ -140,6 +143,7 @@ impl SurfaceRole {
SurfaceRole::XSurface => "xwayland surface",
SurfaceRole::ExtSessionLockSurface => "ext_session_lock_surface",
SurfaceRole::InputPopup => "input_popup_surface",
SurfaceRole::TrayItem => "tray_item",
}
}
}
Expand Down Expand Up @@ -412,6 +416,10 @@ trait SurfaceExt {
) -> Result<(), WlSurfaceError> {
surface.pending.borrow_mut().consume_child(child, consume)
}

fn tray_item(self: Rc<Self>) -> Option<Rc<ExtTrayItemV1>> {
None
}
}

pub struct NoneSurfaceExt;
Expand Down Expand Up @@ -450,6 +458,7 @@ struct PendingState {
fifo_barrier_set: bool,
fifo_barrier_wait: bool,
commit_time: Option<u64>,
tray_item_ack_serial: Option<u32>,
}

struct AttachedSubsurfaceState {
Expand Down Expand Up @@ -501,6 +510,7 @@ impl PendingState {
opt!(content_type);
opt!(alpha_multiplier);
opt!(commit_time);
opt!(tray_item_ack_serial);
{
let (dx1, dy1) = self.offset;
let (dx2, dy2) = mem::take(&mut next.offset);
Expand Down Expand Up @@ -1721,6 +1731,10 @@ impl Node for WlSurface {
self.toplevel.get()
}

fn node_tray_item(&self) -> Option<Rc<ExtTrayItemV1>> {
self.ext.get().tray_item()
}

fn node_on_key(
&self,
seat: &WlSeatGlobal,
Expand Down
Loading

0 comments on commit a367cf2

Please sign in to comment.