git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

src/server/pointer_binding.rs (5K)

  1 // SPDX-FileCopyrightText: © 2026 The River Developers
  2 // SPDX-License-Identifier: GPL-3.0-only
  3 
  4 use crate::ffi;
  5 use crate::seat::Seat;
  6 
  7 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  8 pub enum PointerBindingStateChange {
  9     None,
 10     Pressed,
 11     Released,
 12 }
 13 
 14 pub struct PointerBindingScheduled {
 15     pub state_changes: Vec<PointerBindingStateChange>,
 16 }
 17 
 18 pub struct PointerBindingRequested {
 19     pub enabled: bool,
 20 }
 21 
 22 pub struct PointerBinding {
 23     pub seat: *mut Seat,
 24     pub object: *mut ffi::wl_resource,
 25     pub button: u32,
 26     pub modifiers: u32,
 27     pub wm_scheduled: PointerBindingScheduled,
 28     pub wm_requested: PointerBindingRequested,
 29     pub sent_pressed: bool,
 30     pub link: ffi::wl_list,
 31 }
 32 
 33 impl PointerBinding {
 34     pub unsafe fn create(
 35         seat: *mut Seat,
 36         client: *mut ffi::wl_client,
 37         version: u32,
 38         id: u32,
 39         button: u32,
 40         modifiers: u32,
 41     ) -> Result<(), &'static str> {
 42         let binding_ptr = Box::into_raw(Box::new(Self {
 43             seat,
 44             object: std::ptr::null_mut(),
 45             button,
 46             modifiers,
 47             wm_scheduled: PointerBindingScheduled {
 48                 state_changes: Vec::new(),
 49             },
 50             wm_requested: PointerBindingRequested {
 51                 enabled: false,
 52             },
 53             sent_pressed: false,
 54             link: std::mem::zeroed(),
 55         }));
 56 
 57         let resource = ffi::wl_resource_create(client, &ffi::zcce_pointer_binding_v1_interface, version as i32, id);
 58         if resource.is_null() {
 59             let _ = Box::from_raw(binding_ptr);
 60             return Err("wl_resource_create failed");
 61         }
 62 
 63         (*binding_ptr).object = resource;
 64         ffi::wl_resource_set_implementation(
 65             resource,
 66             &POINTER_BINDING_INTERFACE as *const _ as *const _,
 67             binding_ptr as *mut _,
 68             Some(handle_binding_resource_destroy),
 69         );
 70 
 71         let pointer_bindings_list = &mut (*seat).pointer_bindings as *mut ffi::wl_list as *mut crate::server::WlList;
 72         crate::server::wl_list_insert((*pointer_bindings_list).prev, &mut (*binding_ptr).link as *mut ffi::wl_list as *mut crate::server::WlList);
 73 
 74         log::debug!(
 75             "new zcce_pointer_binding_v1: button: {} modifiers: {}",
 76             button,
 77             modifiers
 78         );
 79 
 80         Ok(())
 81     }
 82 
 83     pub unsafe fn destroy(binding: *mut Self) {
 84         ffi::wl_resource_set_implementation(
 85             (*binding).object,
 86             std::ptr::null(),
 87             std::ptr::null_mut(),
 88             None,
 89         );
 90         handle_binding_resource_destroy((*binding).object);
 91     }
 92 
 93     pub unsafe fn pressed(&mut self) {
 94         self.wm_scheduled.state_changes.push(PointerBindingStateChange::Pressed);
 95         (*(*self.seat).server).wm.dirty_windowing();
 96     }
 97 
 98     pub unsafe fn released(&mut self) {
 99         self.wm_scheduled.state_changes.push(PointerBindingStateChange::Released);
100         (*(*self.seat).server).wm.dirty_windowing();
101     }
102 
103     pub fn match_binding(&self, button: u32, modifiers: u32) -> bool {
104         if !self.wm_requested.enabled {
105             return false;
106         }
107         button == self.button && modifiers == self.modifiers
108     }
109 }
110 
111 unsafe extern "C" fn handle_binding_resource_destroy(resource: *mut ffi::wl_resource) {
112     let binding = ffi::wl_resource_get_user_data(resource) as *mut PointerBinding;
113     if !binding.is_null() {
114         // It is possible for the window manager to create duplicate pointer bindings.
115         let cursor = &mut (*(*binding).seat).cursor;
116         if let Some(val) = cursor.pressed.get_mut(&(*binding).button) {
117             if *val == Some(binding) {
118                 *val = None;
119             }
120         }
121 
122         crate::server::wl_list_remove(&mut (*binding).link as *mut ffi::wl_list as *mut crate::server::WlList);
123         let _ = Box::from_raw(binding);
124     }
125 }
126 
127 static POINTER_BINDING_INTERFACE: ffi::zcce_pointer_binding_v1_interface = ffi::zcce_pointer_binding_v1_interface {
128     destroy: Some(pointer_binding_destroy),
129     enable: Some(pointer_binding_enable),
130     disable: Some(pointer_binding_disable),
131 };
132 
133 unsafe extern "C" fn pointer_binding_destroy(
134     _client: *mut ffi::wl_client,
135     resource: *mut ffi::wl_resource,
136 ) {
137     ffi::wl_resource_destroy(resource);
138 }
139 
140 unsafe extern "C" fn pointer_binding_enable(
141     _client: *mut ffi::wl_client,
142     resource: *mut ffi::wl_resource,
143 ) {
144     let binding = ffi::wl_resource_get_user_data(resource) as *mut PointerBinding;
145     if binding.is_null() {
146         return;
147     }
148     let server = (*(*binding).seat).server;
149     if !(*server).wm.ensure_windowing() {
150         return;
151     }
152     (*binding).wm_requested.enabled = true;
153 }
154 
155 unsafe extern "C" fn pointer_binding_disable(
156     _client: *mut ffi::wl_client,
157     resource: *mut ffi::wl_resource,
158 ) {
159     let binding = ffi::wl_resource_get_user_data(resource) as *mut PointerBinding;
160     if binding.is_null() {
161         return;
162     }
163     let server = (*(*binding).seat).server;
164     if !(*server).wm.ensure_windowing() {
165         return;
166     }
167     (*binding).wm_requested.enabled = false;
168 }