Rust · 3967 bytes Raw Blame History
1 //! SLS event registration and dispatch.
2
3 use crate::skylight::*;
4 use std::sync::OnceLock;
5 use std::sync::atomic::{AtomicI32, Ordering};
6 use std::sync::mpsc;
7
8 pub const EVENT_WINDOW_CLOSE: u32 = 804;
9 pub const EVENT_WINDOW_MOVE: u32 = 806;
10 pub const EVENT_WINDOW_RESIZE: u32 = 807;
11 pub const EVENT_WINDOW_REORDER: u32 = 808;
12 pub const EVENT_WINDOW_UNHIDE: u32 = 815;
13 pub const EVENT_WINDOW_HIDE: u32 = 816;
14 pub const EVENT_WINDOW_CREATE: u32 = 1325;
15 pub const EVENT_WINDOW_DESTROY: u32 = 1326;
16 pub const EVENT_SPACE_CHANGE: u32 = 1401;
17 pub const EVENT_FRONT_CHANGE: u32 = 1508;
18
19 #[derive(Debug)]
20 pub enum Event {
21 Move(u32),
22 Resize(u32),
23 Close(u32),
24 Hide(u32),
25 Unhide(u32),
26 Create(u32),
27 Destroy(u32),
28 SpaceChange,
29 FrontChange,
30 }
31
32 static TX: OnceLock<mpsc::Sender<Event>> = OnceLock::new();
33 static OWN_PID: AtomicI32 = AtomicI32::new(0);
34
35 pub fn init(tx: mpsc::Sender<Event>, own_pid: i32) {
36 let _ = TX.set(tx);
37 OWN_PID.store(own_pid, Ordering::Relaxed);
38 }
39
40 fn send(event: Event) {
41 if let Some(tx) = TX.get() {
42 let _ = tx.send(event);
43 }
44 }
45
46 fn is_own_window(cid: CGSConnectionID, wid: u32) -> bool {
47 unsafe {
48 let mut wid_cid: CGSConnectionID = 0;
49 SLSGetWindowOwner(cid, wid, &mut wid_cid);
50 let mut pid: i32 = 0;
51 SLSConnectionGetPID(wid_cid, &mut pid);
52 pid == OWN_PID.load(Ordering::Relaxed)
53 }
54 }
55
56 unsafe extern "C" fn window_handler(
57 event: u32,
58 data: *const u8,
59 _data_len: usize,
60 context: *mut std::ffi::c_void,
61 ) {
62 unsafe {
63 let wid = std::ptr::read_unaligned(data as *const u32);
64 let cid = context as isize as CGSConnectionID;
65 if wid == 0 || is_own_window(cid, wid) {
66 return;
67 }
68
69 match event {
70 EVENT_WINDOW_MOVE => send(Event::Move(wid)),
71 EVENT_WINDOW_RESIZE => send(Event::Resize(wid)),
72 EVENT_WINDOW_CLOSE => send(Event::Close(wid)),
73 EVENT_WINDOW_REORDER => {
74 send(Event::Move(wid));
75 send(Event::FrontChange); // reorder may be intra-app focus change
76 }
77 EVENT_WINDOW_HIDE => send(Event::Hide(wid)),
78 EVENT_WINDOW_UNHIDE => send(Event::Unhide(wid)),
79 _ => {}
80 }
81 }
82 }
83
84 unsafe extern "C" fn spawn_handler(
85 event: u32,
86 data: *const u8,
87 _data_len: usize,
88 context: *mut std::ffi::c_void,
89 ) {
90 unsafe {
91 let _sid = std::ptr::read_unaligned(data as *const u64);
92 let wid = std::ptr::read_unaligned(data.add(8) as *const u32);
93 let cid = context as isize as CGSConnectionID;
94 if wid == 0 || is_own_window(cid, wid) {
95 return;
96 }
97
98 match event {
99 EVENT_WINDOW_CREATE => send(Event::Create(wid)),
100 EVENT_WINDOW_DESTROY => send(Event::Destroy(wid)),
101 _ => {}
102 }
103 }
104 }
105
106 unsafe extern "C" fn space_handler(
107 _event: u32,
108 _data: *const u8,
109 _len: usize,
110 _ctx: *mut std::ffi::c_void,
111 ) {
112 send(Event::SpaceChange);
113 }
114
115 unsafe extern "C" fn front_handler(
116 _event: u32,
117 _data: *const u8,
118 _len: usize,
119 _ctx: *mut std::ffi::c_void,
120 ) {
121 send(Event::FrontChange);
122 }
123
124 pub fn register(cid: CGSConnectionID) {
125 let ctx = cid as isize as *mut std::ffi::c_void;
126 unsafe {
127 for &ev in &[
128 EVENT_WINDOW_CLOSE,
129 EVENT_WINDOW_MOVE,
130 EVENT_WINDOW_RESIZE,
131 EVENT_WINDOW_REORDER,
132 EVENT_WINDOW_HIDE,
133 EVENT_WINDOW_UNHIDE,
134 ] {
135 SLSRegisterNotifyProc(window_handler as *const _, ev, ctx);
136 }
137 SLSRegisterNotifyProc(spawn_handler as *const _, EVENT_WINDOW_CREATE, ctx);
138 SLSRegisterNotifyProc(spawn_handler as *const _, EVENT_WINDOW_DESTROY, ctx);
139 SLSRegisterNotifyProc(space_handler as *const _, EVENT_SPACE_CHANGE, ctx);
140 SLSRegisterNotifyProc(front_handler as *const _, EVENT_FRONT_CHANGE, ctx);
141 }
142 }
143