xdg-popup: implement jay-popup-ext-v1
This commit is contained in:
parent
15e6ab2b8a
commit
1d3dfa8b3a
12 changed files with 473 additions and 8 deletions
|
|
@ -163,6 +163,7 @@ Jay supports the following wayland protocols:
|
||||||
| ext_session_lock_manager_v1 | 1 | Yes |
|
| ext_session_lock_manager_v1 | 1 | Yes |
|
||||||
| ext_transient_seat_manager_v1 | 1[^ts_rejected] | Yes |
|
| ext_transient_seat_manager_v1 | 1[^ts_rejected] | Yes |
|
||||||
| ext_workspace_manager_v1 | 1 | Yes |
|
| ext_workspace_manager_v1 | 1 | Yes |
|
||||||
|
| jay_popup_ext_manager_v1 | 1 | |
|
||||||
| jay_tray_v1 | 1 | |
|
| jay_tray_v1 | 1 | |
|
||||||
| org_kde_kwin_server_decoration_manager | 1 | |
|
| org_kde_kwin_server_decoration_manager | 1 | |
|
||||||
| wl_compositor | 6 | |
|
| wl_compositor | 6 | |
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ use {
|
||||||
},
|
},
|
||||||
jay_compositor::JayCompositorGlobal,
|
jay_compositor::JayCompositorGlobal,
|
||||||
jay_damage_tracking::JayDamageTrackingGlobal,
|
jay_damage_tracking::JayDamageTrackingGlobal,
|
||||||
|
jay_popup_ext_manager_v1::JayPopupExtManagerV1Global,
|
||||||
org_kde_kwin_server_decoration_manager::OrgKdeKwinServerDecorationManagerGlobal,
|
org_kde_kwin_server_decoration_manager::OrgKdeKwinServerDecorationManagerGlobal,
|
||||||
wl_compositor::WlCompositorGlobal,
|
wl_compositor::WlCompositorGlobal,
|
||||||
wl_fixes::WlFixesGlobal,
|
wl_fixes::WlFixesGlobal,
|
||||||
|
|
@ -231,6 +232,7 @@ impl Globals {
|
||||||
add_singleton!(XdgToplevelTagManagerV1Global);
|
add_singleton!(XdgToplevelTagManagerV1Global);
|
||||||
add_singleton!(JayHeadManagerV1Global);
|
add_singleton!(JayHeadManagerV1Global);
|
||||||
add_singleton!(WpPointerWarpV1Global);
|
add_singleton!(WpPointerWarpV1Global);
|
||||||
|
add_singleton!(JayPopupExtManagerV1Global);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ pub mod jay_input;
|
||||||
pub mod jay_log_file;
|
pub mod jay_log_file;
|
||||||
pub mod jay_output;
|
pub mod jay_output;
|
||||||
pub mod jay_pointer;
|
pub mod jay_pointer;
|
||||||
|
pub mod jay_popup_ext_manager_v1;
|
||||||
pub mod jay_randr;
|
pub mod jay_randr;
|
||||||
pub mod jay_reexec;
|
pub mod jay_reexec;
|
||||||
pub mod jay_render_ctx;
|
pub mod jay_render_ctx;
|
||||||
|
|
|
||||||
107
src/ifs/jay_popup_ext_manager_v1.rs
Normal file
107
src/ifs/jay_popup_ext_manager_v1.rs
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientError},
|
||||||
|
globals::{Global, GlobalName},
|
||||||
|
ifs::wl_surface::xdg_surface::xdg_popup::jay_popup_ext_v1::{
|
||||||
|
JayPopupExtV1, JayPopupExtV1Error,
|
||||||
|
},
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
wire::{JayPopupExtManagerV1Id, jay_popup_ext_manager_v1::*},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct JayPopupExtManagerV1Global {
|
||||||
|
pub name: GlobalName,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JayPopupExtManagerV1 {
|
||||||
|
pub id: JayPopupExtManagerV1Id,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayPopupExtManagerV1Global {
|
||||||
|
pub fn new(name: GlobalName) -> Self {
|
||||||
|
Self { name }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_(
|
||||||
|
self: Rc<Self>,
|
||||||
|
id: JayPopupExtManagerV1Id,
|
||||||
|
client: &Rc<Client>,
|
||||||
|
version: Version,
|
||||||
|
) -> Result<(), JayPopupExtManagerV1Error> {
|
||||||
|
let obj = Rc::new(JayPopupExtManagerV1 {
|
||||||
|
id,
|
||||||
|
client: client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version,
|
||||||
|
});
|
||||||
|
track!(client, obj);
|
||||||
|
client.add_client_obj(&obj)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_base!(
|
||||||
|
JayPopupExtManagerV1Global,
|
||||||
|
JayPopupExtManagerV1,
|
||||||
|
JayPopupExtManagerV1Error
|
||||||
|
);
|
||||||
|
|
||||||
|
impl Global for JayPopupExtManagerV1Global {
|
||||||
|
fn singleton(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_add_global!(JayPopupExtManagerV1Global);
|
||||||
|
|
||||||
|
impl JayPopupExtManagerV1RequestHandler for JayPopupExtManagerV1 {
|
||||||
|
type Error = JayPopupExtManagerV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ext(&self, req: GetExt, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let popup = self.client.lookup(req.popup)?;
|
||||||
|
let obj = Rc::new(JayPopupExtV1::new(
|
||||||
|
req.id,
|
||||||
|
&self.client,
|
||||||
|
self.version,
|
||||||
|
&popup,
|
||||||
|
));
|
||||||
|
track!(self.client, obj);
|
||||||
|
self.client.add_client_obj(&obj)?;
|
||||||
|
obj.install()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = JayPopupExtManagerV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for JayPopupExtManagerV1 {}
|
||||||
|
|
||||||
|
simple_add_obj!(JayPopupExtManagerV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum JayPopupExtManagerV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
#[error(transparent)]
|
||||||
|
JayPopupExtV1Error(#[from] JayPopupExtV1Error),
|
||||||
|
}
|
||||||
|
efrom!(JayPopupExtManagerV1Error, ClientError);
|
||||||
|
|
@ -69,7 +69,7 @@ use {
|
||||||
WlSurface,
|
WlSurface,
|
||||||
dnd_icon::DndIcon,
|
dnd_icon::DndIcon,
|
||||||
tray::{DynTrayItem, TrayItemId},
|
tray::{DynTrayItem, TrayItemId},
|
||||||
xdg_surface::xdg_popup::XdgPopup,
|
xdg_surface::{xdg_popup::XdgPopup, xdg_toplevel::ResizeEdges},
|
||||||
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
||||||
},
|
},
|
||||||
xdg_toplevel_drag_v1::XdgToplevelDragV1,
|
xdg_toplevel_drag_v1::XdgToplevelDragV1,
|
||||||
|
|
@ -1146,6 +1146,20 @@ impl WlSeatGlobal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn start_popup_move(self: &Rc<Self>, popup: &Rc<XdgPopup>, serial: u64) {
|
||||||
|
self.pointer_owner.start_popup_move(self, popup, serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_popup_resize(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
popup: &Rc<XdgPopup>,
|
||||||
|
edges: ResizeEdges,
|
||||||
|
serial: u64,
|
||||||
|
) {
|
||||||
|
self.pointer_owner
|
||||||
|
.start_popup_resize(self, popup, edges, serial);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cancel_popup_move(self: &Rc<Self>) {
|
pub fn cancel_popup_move(self: &Rc<Self>) {
|
||||||
self.pointer_owner.grab_node_removed(self);
|
self.pointer_owner.grab_node_removed(self);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,14 @@ impl NodeSeatState {
|
||||||
self.pointer_foci.remove(&seat.id);
|
self.pointer_foci.remove(&seat.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pointer_inside(&self, seat: &WlSeatGlobal) -> bool {
|
||||||
|
self.pointer_foci.contains(&seat.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pointer_not_inside(&self, seat: &WlSeatGlobal) -> bool {
|
||||||
|
!self.pointer_inside(seat)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn disable_focus_history(&self) {
|
pub fn disable_focus_history(&self) {
|
||||||
self.no_focus_history.set(true);
|
self.no_focus_history.set(true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,22 @@ impl PointerOwnerHolder {
|
||||||
pub fn start_workspace_drag(&self, seat: &Rc<WlSeatGlobal>, ws: &Rc<WorkspaceNode>) {
|
pub fn start_workspace_drag(&self, seat: &Rc<WlSeatGlobal>, ws: &Rc<WorkspaceNode>) {
|
||||||
self.owner.get().start_workspace_drag(seat, ws);
|
self.owner.get().start_workspace_drag(seat, ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn start_popup_move(&self, seat: &Rc<WlSeatGlobal>, popup: &Rc<XdgPopup>, serial: u64) {
|
||||||
|
self.owner.get().start_popup_move(seat, popup, serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_popup_resize(
|
||||||
|
&self,
|
||||||
|
seat: &Rc<WlSeatGlobal>,
|
||||||
|
popup: &Rc<XdgPopup>,
|
||||||
|
edges: ResizeEdges,
|
||||||
|
serial: u64,
|
||||||
|
) {
|
||||||
|
self.owner
|
||||||
|
.get()
|
||||||
|
.start_popup_resize(seat, popup, edges, serial);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PointerOwner {
|
trait PointerOwner {
|
||||||
|
|
@ -281,6 +297,25 @@ trait PointerOwner {
|
||||||
let _ = seat;
|
let _ = seat;
|
||||||
let _ = ws;
|
let _ = ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_popup_move(&self, seat: &Rc<WlSeatGlobal>, popup: &Rc<XdgPopup>, serial: u64) {
|
||||||
|
let _ = seat;
|
||||||
|
let _ = popup;
|
||||||
|
let _ = serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_popup_resize(
|
||||||
|
&self,
|
||||||
|
seat: &Rc<WlSeatGlobal>,
|
||||||
|
popup: &Rc<XdgPopup>,
|
||||||
|
edges: ResizeEdges,
|
||||||
|
serial: u64,
|
||||||
|
) {
|
||||||
|
let _ = seat;
|
||||||
|
let _ = popup;
|
||||||
|
let _ = edges;
|
||||||
|
let _ = serial;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SimplePointerOwner<T> {
|
struct SimplePointerOwner<T> {
|
||||||
|
|
@ -289,7 +324,7 @@ struct SimplePointerOwner<T> {
|
||||||
|
|
||||||
struct SimpleGrabPointerOwner<T> {
|
struct SimpleGrabPointerOwner<T> {
|
||||||
usecase: T,
|
usecase: T,
|
||||||
buttons: SmallMap<u32, (), 1>,
|
buttons: SmallMap<u32, u64, 1>,
|
||||||
node: Rc<dyn Node>,
|
node: Rc<dyn Node>,
|
||||||
serial: u64,
|
serial: u64,
|
||||||
}
|
}
|
||||||
|
|
@ -338,7 +373,7 @@ impl<T: SimplePointerOwnerUsecase> PointerOwner for SimplePointerOwner<T> {
|
||||||
.owner
|
.owner
|
||||||
.set(Rc::new(SimpleGrabPointerOwner {
|
.set(Rc::new(SimpleGrabPointerOwner {
|
||||||
usecase: self.usecase.clone(),
|
usecase: self.usecase.clone(),
|
||||||
buttons: SmallMap::new_with(button, ()),
|
buttons: SmallMap::new_with(button, serial),
|
||||||
node: pn.clone(),
|
node: pn.clone(),
|
||||||
serial,
|
serial,
|
||||||
}));
|
}));
|
||||||
|
|
@ -439,8 +474,20 @@ impl<T: SimplePointerOwnerUsecase> PointerOwner for SimplePointerOwner<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: SimplePointerOwnerUsecase> SimpleGrabPointerOwner<T> {
|
||||||
|
fn find_button(&self, serial: u64) -> Option<u32> {
|
||||||
|
for (button, s) in self.buttons.iter() {
|
||||||
|
if s == serial {
|
||||||
|
return Some(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: SimplePointerOwnerUsecase> PointerOwner for SimpleGrabPointerOwner<T> {
|
impl<T: SimplePointerOwnerUsecase> PointerOwner for SimpleGrabPointerOwner<T> {
|
||||||
fn button(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, button: u32, state: ButtonState) {
|
fn button(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, button: u32, state: ButtonState) {
|
||||||
|
let serial = seat.state.next_serial(self.node.node_client().as_deref());
|
||||||
match state {
|
match state {
|
||||||
ButtonState::Released => {
|
ButtonState::Released => {
|
||||||
if self.buttons.remove(&button).is_none() {
|
if self.buttons.remove(&button).is_none() {
|
||||||
|
|
@ -454,12 +501,11 @@ impl<T: SimplePointerOwnerUsecase> PointerOwner for SimpleGrabPointerOwner<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ButtonState::Pressed => {
|
ButtonState::Pressed => {
|
||||||
if self.buttons.insert(button, ()).is_some() {
|
if self.buttons.insert(button, serial).is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let serial = seat.state.next_serial(self.node.node_client().as_deref());
|
|
||||||
seat.handle_node_button(self.node.clone(), time_usec, button, state, serial);
|
seat.handle_node_button(self.node.clone(), time_usec, button, state, serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -512,6 +558,27 @@ impl<T: SimplePointerOwnerUsecase> PointerOwner for SimpleGrabPointerOwner<T> {
|
||||||
fn start_workspace_drag(&self, seat: &Rc<WlSeatGlobal>, ws: &Rc<WorkspaceNode>) {
|
fn start_workspace_drag(&self, seat: &Rc<WlSeatGlobal>, ws: &Rc<WorkspaceNode>) {
|
||||||
self.usecase.start_workspace_drag(self, seat, ws);
|
self.usecase.start_workspace_drag(self, seat, ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_popup_move(&self, seat: &Rc<WlSeatGlobal>, popup: &Rc<XdgPopup>, serial: u64) {
|
||||||
|
let Some(button) = self.find_button(serial) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.usecase.start_popup_move(self, seat, popup, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_popup_resize(
|
||||||
|
&self,
|
||||||
|
seat: &Rc<WlSeatGlobal>,
|
||||||
|
popup: &Rc<XdgPopup>,
|
||||||
|
edges: ResizeEdges,
|
||||||
|
serial: u64,
|
||||||
|
) {
|
||||||
|
let Some(button) = self.find_button(serial) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.usecase
|
||||||
|
.start_popup_resize(self, seat, popup, edges, button);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointerOwner for DndPointerOwner {
|
impl PointerOwner for DndPointerOwner {
|
||||||
|
|
@ -680,6 +747,34 @@ trait SimplePointerOwnerUsecase: Sized + Clone + 'static {
|
||||||
let _ = seat;
|
let _ = seat;
|
||||||
let _ = ws;
|
let _ = ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_popup_move(
|
||||||
|
&self,
|
||||||
|
grab: &SimpleGrabPointerOwner<Self>,
|
||||||
|
seat: &Rc<WlSeatGlobal>,
|
||||||
|
popup: &Rc<XdgPopup>,
|
||||||
|
button: u32,
|
||||||
|
) {
|
||||||
|
let _ = grab;
|
||||||
|
let _ = seat;
|
||||||
|
let _ = popup;
|
||||||
|
let _ = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_popup_resize(
|
||||||
|
&self,
|
||||||
|
grab: &SimpleGrabPointerOwner<Self>,
|
||||||
|
seat: &Rc<WlSeatGlobal>,
|
||||||
|
popup: &Rc<XdgPopup>,
|
||||||
|
edges: ResizeEdges,
|
||||||
|
button: u32,
|
||||||
|
) {
|
||||||
|
let _ = grab;
|
||||||
|
let _ = seat;
|
||||||
|
let _ = popup;
|
||||||
|
let _ = edges;
|
||||||
|
let _ = button;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefaultPointerUsecase {
|
impl DefaultPointerUsecase {
|
||||||
|
|
@ -706,6 +801,25 @@ impl DefaultPointerUsecase {
|
||||||
seat.pointer_owner.owner.set(pointer_owner.clone());
|
seat.pointer_owner.owner.set(pointer_owner.clone());
|
||||||
pointer_owner.apply_changes(seat);
|
pointer_owner.apply_changes(seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_popup_usecase<U: PopupPointerOwnerUsecase>(
|
||||||
|
&self,
|
||||||
|
grab: &SimpleGrabPointerOwner<Self>,
|
||||||
|
seat: &Rc<WlSeatGlobal>,
|
||||||
|
popup: &Rc<XdgPopup>,
|
||||||
|
button: u32,
|
||||||
|
usecase: U,
|
||||||
|
) {
|
||||||
|
self.prepare_new_usecase(grab, seat);
|
||||||
|
seat.pointer_owner.owner.set(Rc::new(PopupPointerOwner {
|
||||||
|
popup: popup.clone(),
|
||||||
|
window_management: false,
|
||||||
|
button,
|
||||||
|
usecase,
|
||||||
|
}));
|
||||||
|
popup.node_seat_state().add_pointer_grab(seat);
|
||||||
|
popup.add_interactive_move(seat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimplePointerOwnerUsecase for DefaultPointerUsecase {
|
impl SimplePointerOwnerUsecase for DefaultPointerUsecase {
|
||||||
|
|
@ -812,6 +926,65 @@ impl SimplePointerOwnerUsecase for DefaultPointerUsecase {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_popup_move(
|
||||||
|
&self,
|
||||||
|
grab: &SimpleGrabPointerOwner<Self>,
|
||||||
|
seat: &Rc<WlSeatGlobal>,
|
||||||
|
popup: &Rc<XdgPopup>,
|
||||||
|
button: u32,
|
||||||
|
) {
|
||||||
|
let (x, y) = seat.pointer_cursor.position();
|
||||||
|
let (dx, dy) = popup
|
||||||
|
.node_absolute_position()
|
||||||
|
.translate(x.round_down(), y.round_down());
|
||||||
|
self.start_popup_usecase(
|
||||||
|
grab,
|
||||||
|
seat,
|
||||||
|
popup,
|
||||||
|
button,
|
||||||
|
PopupPointerOwnerMoveUsecase { dx, dy },
|
||||||
|
);
|
||||||
|
seat.pointer_cursor.set_known(KnownCursor::Move);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_popup_resize(
|
||||||
|
&self,
|
||||||
|
grab: &SimpleGrabPointerOwner<Self>,
|
||||||
|
seat: &Rc<WlSeatGlobal>,
|
||||||
|
popup: &Rc<XdgPopup>,
|
||||||
|
edges: ResizeEdges,
|
||||||
|
button: u32,
|
||||||
|
) {
|
||||||
|
let cursor = match (edges.top, edges.left, edges.right, edges.bottom) {
|
||||||
|
(true, false, false, false) => KnownCursor::NsResize,
|
||||||
|
(false, false, false, true) => KnownCursor::NsResize,
|
||||||
|
(false, true, false, false) => KnownCursor::EwResize,
|
||||||
|
(false, false, true, false) => KnownCursor::EwResize,
|
||||||
|
(true, true, false, false) => KnownCursor::NwseResize,
|
||||||
|
(false, false, true, true) => KnownCursor::NwseResize,
|
||||||
|
(false, true, false, true) => KnownCursor::NeswResize,
|
||||||
|
(true, false, true, false) => KnownCursor::NeswResize,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let (x, y) = seat.pointer_cursor.position();
|
||||||
|
let pos = popup.node_absolute_position();
|
||||||
|
let (mut dx, mut dy) = pos.translate(x.round_down(), y.round_down());
|
||||||
|
if edges.right {
|
||||||
|
dx = pos.width() - dx;
|
||||||
|
}
|
||||||
|
if edges.bottom {
|
||||||
|
dy = pos.height() - dy;
|
||||||
|
}
|
||||||
|
self.start_popup_usecase(
|
||||||
|
grab,
|
||||||
|
seat,
|
||||||
|
popup,
|
||||||
|
button,
|
||||||
|
PopupPointerOwnerResizeUsecase { edges, dx, dy },
|
||||||
|
);
|
||||||
|
seat.pointer_cursor.set_known(cursor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait NodeSelectorUsecase: Sized + 'static {
|
trait NodeSelectorUsecase: Sized + 'static {
|
||||||
|
|
@ -989,6 +1162,7 @@ impl SimplePointerOwnerUsecase for WindowManagementUsecase {
|
||||||
seat.pointer_cursor.set_known(KnownCursor::Move);
|
seat.pointer_cursor.set_known(KnownCursor::Move);
|
||||||
Rc::new(PopupPointerOwner {
|
Rc::new(PopupPointerOwner {
|
||||||
popup,
|
popup,
|
||||||
|
window_management: true,
|
||||||
button,
|
button,
|
||||||
usecase: PopupPointerOwnerMoveUsecase { dx, dy },
|
usecase: PopupPointerOwnerMoveUsecase { dx, dy },
|
||||||
})
|
})
|
||||||
|
|
@ -1037,6 +1211,7 @@ impl SimplePointerOwnerUsecase for WindowManagementUsecase {
|
||||||
seat.pointer_cursor.set_known(cursor);
|
seat.pointer_cursor.set_known(cursor);
|
||||||
Rc::new(PopupPointerOwner {
|
Rc::new(PopupPointerOwner {
|
||||||
popup,
|
popup,
|
||||||
|
window_management: true,
|
||||||
button,
|
button,
|
||||||
usecase: PopupPointerOwnerResizeUsecase {
|
usecase: PopupPointerOwnerResizeUsecase {
|
||||||
edges: ResizeEdges {
|
edges: ResizeEdges {
|
||||||
|
|
@ -1495,6 +1670,7 @@ impl UiDragUsecase for WorkspaceDragUsecase {
|
||||||
|
|
||||||
struct PopupPointerOwner<T> {
|
struct PopupPointerOwner<T> {
|
||||||
popup: Rc<XdgPopup>,
|
popup: Rc<XdgPopup>,
|
||||||
|
window_management: bool,
|
||||||
button: u32,
|
button: u32,
|
||||||
usecase: T,
|
usecase: T,
|
||||||
}
|
}
|
||||||
|
|
@ -1519,7 +1695,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn revert_to_previous(&self, seat: &Rc<WlSeatGlobal>) {
|
fn revert_to_previous(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
self.revert_to_window_management(seat);
|
if self.window_management {
|
||||||
|
self.revert_to_window_management(seat);
|
||||||
|
} else {
|
||||||
|
self.revert_to_default(seat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1553,7 +1733,9 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable_window_management(&self, seat: &Rc<WlSeatGlobal>) {
|
fn disable_window_management(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
self.revert_to_default(seat);
|
if self.window_management {
|
||||||
|
self.revert_to_default(seat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
pub mod jay_popup_ext_v1;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
|
|
@ -7,7 +9,9 @@ use {
|
||||||
wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, tablet::TabletTool},
|
wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, tablet::TabletTool},
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
tray::TrayItemId,
|
tray::TrayItemId,
|
||||||
xdg_surface::{XdgSurface, XdgSurfaceExt},
|
xdg_surface::{
|
||||||
|
XdgSurface, XdgSurfaceExt, xdg_popup::jay_popup_ext_v1::JayPopupExtV1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
xdg_positioner::{
|
xdg_positioner::{
|
||||||
CA_FLIP_X, CA_FLIP_Y, CA_RESIZE_X, CA_RESIZE_Y, CA_SLIDE_X, CA_SLIDE_Y,
|
CA_FLIP_X, CA_FLIP_Y, CA_RESIZE_X, CA_RESIZE_Y, CA_SLIDE_X, CA_SLIDE_Y,
|
||||||
|
|
@ -65,6 +69,7 @@ pub struct XdgPopup {
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
seat_state: NodeSeatState,
|
seat_state: NodeSeatState,
|
||||||
set_visible_prepared: Cell<bool>,
|
set_visible_prepared: Cell<bool>,
|
||||||
|
jay_popup_ext: CloneCell<Option<Rc<JayPopupExtV1>>>,
|
||||||
interactive_moves: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
interactive_moves: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,6 +99,7 @@ impl XdgPopup {
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
set_visible_prepared: Cell::new(false),
|
set_visible_prepared: Cell::new(false),
|
||||||
|
jay_popup_ext: Default::default(),
|
||||||
interactive_moves: Default::default(),
|
interactive_moves: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -267,6 +273,9 @@ impl XdgPopupRequestHandler for XdgPopup {
|
||||||
type Error = XdgPopupError;
|
type Error = XdgPopupError;
|
||||||
|
|
||||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if self.jay_popup_ext.is_some() {
|
||||||
|
return Err(XdgPopupError::HasJayPopupExt);
|
||||||
|
}
|
||||||
self.destroy_node();
|
self.destroy_node();
|
||||||
self.xdg.unset_ext();
|
self.xdg.unset_ext();
|
||||||
self.xdg.surface.client.remove_obj(self)?;
|
self.xdg.surface.client.remove_obj(self)?;
|
||||||
|
|
@ -328,6 +337,7 @@ object_base! {
|
||||||
|
|
||||||
impl Object for XdgPopup {
|
impl Object for XdgPopup {
|
||||||
fn break_loops(&self) {
|
fn break_loops(&self) {
|
||||||
|
self.jay_popup_ext.take();
|
||||||
self.destroy_node();
|
self.destroy_node();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -518,5 +528,7 @@ pub enum XdgPopupError {
|
||||||
Incomplete,
|
Incomplete,
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ClientError(Box<ClientError>),
|
ClientError(Box<ClientError>),
|
||||||
|
#[error("The popup still has a jay_popup_ext_v1 extension object")]
|
||||||
|
HasJayPopupExt,
|
||||||
}
|
}
|
||||||
efrom!(XdgPopupError, ClientError);
|
efrom!(XdgPopupError, ClientError);
|
||||||
|
|
|
||||||
101
src/ifs/wl_surface/xdg_surface/xdg_popup/jay_popup_ext_v1.rs
Normal file
101
src/ifs/wl_surface/xdg_surface/xdg_popup/jay_popup_ext_v1.rs
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientError},
|
||||||
|
ifs::wl_surface::xdg_surface::{xdg_popup::XdgPopup, xdg_toplevel::map_resize_edges},
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
wire::{JayPopupExtV1Id, jay_popup_ext_v1::*},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct JayPopupExtV1 {
|
||||||
|
id: JayPopupExtV1Id,
|
||||||
|
client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
version: Version,
|
||||||
|
popup: Rc<XdgPopup>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayPopupExtV1 {
|
||||||
|
pub fn new(
|
||||||
|
id: JayPopupExtV1Id,
|
||||||
|
client: &Rc<Client>,
|
||||||
|
version: Version,
|
||||||
|
popup: &Rc<XdgPopup>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
tracker: Default::default(),
|
||||||
|
version,
|
||||||
|
client: client.clone(),
|
||||||
|
popup: popup.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn install(self: &Rc<Self>) -> Result<(), JayPopupExtV1Error> {
|
||||||
|
if self.popup.jay_popup_ext.is_some() {
|
||||||
|
return Err(JayPopupExtV1Error::HasExt);
|
||||||
|
}
|
||||||
|
self.popup.jay_popup_ext.set(Some(self.clone()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayPopupExtV1RequestHandler for JayPopupExtV1 {
|
||||||
|
type Error = JayPopupExtV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.popup.jay_popup_ext.take();
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_(&self, req: Move, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let seat = self.client.lookup(req.seat)?;
|
||||||
|
let Some(serial) = self.client.map_serial(req.serial) else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
if self.popup.seat_state.pointer_not_inside(&seat.global) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
seat.global.start_popup_move(&self.popup, serial);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&self, req: Resize, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let Some(edges) = map_resize_edges(req.edges) else {
|
||||||
|
return Err(JayPopupExtV1Error::UnknownResizeEdges(req.edges));
|
||||||
|
};
|
||||||
|
let seat = self.client.lookup(req.seat)?;
|
||||||
|
let Some(serial) = self.client.map_serial(req.serial) else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
if self.popup.seat_state.pointer_not_inside(&seat.global) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
seat.global.start_popup_resize(&self.popup, edges, serial);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = JayPopupExtV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for JayPopupExtV1 {}
|
||||||
|
|
||||||
|
simple_add_obj!(JayPopupExtV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum JayPopupExtV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
#[error("The xdg_popup already has a jay_popup_ext_v1 extension")]
|
||||||
|
HasExt,
|
||||||
|
#[error("The resize edge {0} is unknown")]
|
||||||
|
UnknownResizeEdges(u32),
|
||||||
|
}
|
||||||
|
efrom!(JayPopupExtV1Error, ClientError);
|
||||||
|
|
@ -79,6 +79,11 @@ pub const SUSPENDED_SINCE: Version = Version(6);
|
||||||
pub const TILED_SINCE: Version = Version(2);
|
pub const TILED_SINCE: Version = Version(2);
|
||||||
pub const CONSTRAINTS_SINCE: Version = Version(7);
|
pub const CONSTRAINTS_SINCE: Version = Version(7);
|
||||||
|
|
||||||
|
const RESIZE_EDGE_TOP: u32 = 1;
|
||||||
|
const RESIZE_EDGE_BOTTOM: u32 = 2;
|
||||||
|
const RESIZE_EDGE_LEFT: u32 = 4;
|
||||||
|
const RESIZE_EDGE_RIGHT: u32 = 8;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
pub enum Decoration {
|
pub enum Decoration {
|
||||||
#[expect(dead_code)]
|
#[expect(dead_code)]
|
||||||
|
|
@ -834,6 +839,18 @@ pub enum XdgToplevelError {
|
||||||
}
|
}
|
||||||
efrom!(XdgToplevelError, ClientError);
|
efrom!(XdgToplevelError, ClientError);
|
||||||
|
|
||||||
|
pub fn map_resize_edges(edge: u32) -> Option<ResizeEdges> {
|
||||||
|
if !matches!(edge, 0 | 1 | 2 | 4 | 5 | 6 | 8 | 9 | 10) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ResizeEdges {
|
||||||
|
top: edge.contains(RESIZE_EDGE_TOP),
|
||||||
|
left: edge.contains(RESIZE_EDGE_LEFT),
|
||||||
|
right: edge.contains(RESIZE_EDGE_RIGHT),
|
||||||
|
bottom: edge.contains(RESIZE_EDGE_BOTTOM),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct ResizeEdges {
|
pub struct ResizeEdges {
|
||||||
pub top: bool,
|
pub top: bool,
|
||||||
|
|
|
||||||
7
wire/jay_popup_ext_manager_v1.txt
Normal file
7
wire/jay_popup_ext_manager_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
}
|
||||||
|
|
||||||
|
request get_ext {
|
||||||
|
id: id(jay_popup_ext_v1) (new),
|
||||||
|
popup: id(xdg_popup),
|
||||||
|
}
|
||||||
13
wire/jay_popup_ext_v1.txt
Normal file
13
wire/jay_popup_ext_v1.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
}
|
||||||
|
|
||||||
|
request move {
|
||||||
|
seat: id(wl_seat),
|
||||||
|
serial: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
request resize {
|
||||||
|
seat: id(wl_seat),
|
||||||
|
serial: u32,
|
||||||
|
edges: u32,
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue