fix crash when handling events with stale HopSlotMap key
This commit is contained in:
parent
f261e3feec
commit
0a5dddacfd
3 changed files with 107 additions and 41 deletions
|
|
@ -328,7 +328,7 @@ impl<C: XConnection> Dispatch<WlPointer, ObjectKey> for ServerState<C> {
|
||||||
hotspot_y,
|
hotspot_y,
|
||||||
surface,
|
surface,
|
||||||
} => {
|
} => {
|
||||||
let c_surface = surface.map(|s| state.get_client_surface_from_server(s));
|
let c_surface = surface.and_then(|s| state.get_client_surface_from_server(s));
|
||||||
c_pointer.set_cursor(serial, c_surface, hotspot_x, hotspot_y);
|
c_pointer.set_cursor(serial, c_surface, hotspot_x, hotspot_y);
|
||||||
}
|
}
|
||||||
Request::<WlPointer>::Release => {
|
Request::<WlPointer>::Release => {
|
||||||
|
|
@ -786,8 +786,10 @@ impl<C: XConnection>
|
||||||
) {
|
) {
|
||||||
use s_vp::wp_viewporter;
|
use s_vp::wp_viewporter;
|
||||||
match request {
|
match request {
|
||||||
wp_viewporter::Request::GetViewport { id, surface } => {
|
wp_viewporter::Request::GetViewport { id, surface } => 'get_viewport: {
|
||||||
let c_surface = state.get_client_surface_from_server(surface);
|
let Some(c_surface) = state.get_client_surface_from_server(surface) else {
|
||||||
|
break 'get_viewport;
|
||||||
|
};
|
||||||
let c_viewport = client.get_viewport(c_surface, &state.qh, ());
|
let c_viewport = client.get_viewport(c_surface, &state.qh, ());
|
||||||
data_init.init(id, c_viewport);
|
data_init.init(id, c_viewport);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,8 +149,18 @@ impl SurfaceData {
|
||||||
let surface = &self.server;
|
let surface = &self.server;
|
||||||
simple_event_shunt! {
|
simple_event_shunt! {
|
||||||
surface, event: client::wl_surface::Event => [
|
surface, event: client::wl_surface::Event => [
|
||||||
Enter { |output| &state.get_object_from_client_object::<Output, _>(&output).server },
|
Enter { |output| {
|
||||||
Leave { |output| &state.get_object_from_client_object::<Output, _>(&output).server },
|
let Some(object) = &state.get_object_from_client_object::<Output, _>(&output) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
&object.server
|
||||||
|
}},
|
||||||
|
Leave { |output| {
|
||||||
|
let Some(object) = &state.get_object_from_client_object::<Output, _>(&output) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
&object.server
|
||||||
|
}},
|
||||||
PreferredBufferScale { factor }
|
PreferredBufferScale { factor }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -363,8 +373,11 @@ impl HandleEvent for Pointer {
|
||||||
} => {
|
} => {
|
||||||
let do_enter = || {
|
let do_enter = || {
|
||||||
debug!("entering surface ({serial})");
|
debug!("entering surface ({serial})");
|
||||||
let surface = state.get_server_surface_from_client(surface.clone());
|
if let Some(surface) = state.get_server_surface_from_client(surface.clone()) {
|
||||||
self.server.enter(serial, surface, surface_x, surface_y);
|
self.server.enter(serial, surface, surface_x, surface_y)
|
||||||
|
} else {
|
||||||
|
warn!("could not enter surface: stale surface");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let surface_key: ObjectKey = surface.data().copied().unwrap();
|
let surface_key: ObjectKey = surface.data().copied().unwrap();
|
||||||
let surface_data: &SurfaceData = state.objects[surface_key].as_ref();
|
let surface_data: &SurfaceData = state.objects[surface_key].as_ref();
|
||||||
|
|
@ -400,8 +413,11 @@ impl HandleEvent for Pointer {
|
||||||
}
|
}
|
||||||
debug!("leaving surface ({serial})");
|
debug!("leaving surface ({serial})");
|
||||||
self.pending_enter.0.take();
|
self.pending_enter.0.take();
|
||||||
self.server
|
if let Some(surface) = state.get_server_surface_from_client(surface) {
|
||||||
.leave(serial, state.get_server_surface_from_client(surface));
|
self.server.leave(serial, surface);
|
||||||
|
} else {
|
||||||
|
warn!("could not leave surface: stale surface");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
client::wl_pointer::Event::Motion {
|
client::wl_pointer::Event::Motion {
|
||||||
time,
|
time,
|
||||||
|
|
@ -434,13 +450,23 @@ impl HandleEvent for Pointer {
|
||||||
self.server, event: client::wl_pointer::Event => [
|
self.server, event: client::wl_pointer::Event => [
|
||||||
Enter {
|
Enter {
|
||||||
serial,
|
serial,
|
||||||
|surface| state.get_server_surface_from_client(surface),
|
|surface| {
|
||||||
|
let Some(surface_data) = state.get_server_surface_from_client(surface) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
surface_data
|
||||||
|
},
|
||||||
surface_x,
|
surface_x,
|
||||||
surface_y
|
surface_y
|
||||||
},
|
},
|
||||||
Leave {
|
Leave {
|
||||||
serial,
|
serial,
|
||||||
|surface| state.get_server_surface_from_client(surface)
|
|surface| {
|
||||||
|
let Some(surface_data) = state.get_server_surface_from_client(surface) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
surface_data
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Motion {
|
Motion {
|
||||||
time,
|
time,
|
||||||
|
|
@ -500,8 +526,9 @@ impl HandleEvent for Keyboard {
|
||||||
keys,
|
keys,
|
||||||
} => {
|
} => {
|
||||||
state.last_kb_serial = Some(serial);
|
state.last_kb_serial = Some(serial);
|
||||||
self.server
|
if let Some(surface_data) = state.get_server_surface_from_client(surface) {
|
||||||
.enter(serial, state.get_server_surface_from_client(surface), keys);
|
self.server.enter(serial, surface_data, keys);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => simple_event_shunt! {
|
_ => simple_event_shunt! {
|
||||||
self.server, event: client::wl_keyboard::Event => [
|
self.server, event: client::wl_keyboard::Event => [
|
||||||
|
|
@ -516,7 +543,10 @@ impl HandleEvent for Keyboard {
|
||||||
if !surface.is_alive() {
|
if !surface.is_alive() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.get_server_surface_from_client(surface)
|
let Some(surface_data) = state.get_server_surface_from_client(surface) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
surface_data
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Key {
|
Key {
|
||||||
|
|
@ -551,7 +581,12 @@ impl HandleEvent for Touch {
|
||||||
Down {
|
Down {
|
||||||
serial,
|
serial,
|
||||||
time,
|
time,
|
||||||
|surface| state.get_server_surface_from_client(surface),
|
|surface| {
|
||||||
|
let Some(surface_data) = state.get_server_surface_from_client(surface) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
surface_data
|
||||||
|
},
|
||||||
id,
|
id,
|
||||||
x,
|
x,
|
||||||
y
|
y
|
||||||
|
|
|
||||||
|
|
@ -496,13 +496,13 @@ impl<C: XConnection> ServerState<C> {
|
||||||
handle_globals::<C>(&self.dh, globals.iter());
|
handle_globals::<C>(&self.dh, globals.iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_object_from_client_object<T, P: Proxy>(&self, proxy: &P) -> &T
|
fn get_object_from_client_object<T, P: Proxy>(&self, proxy: &P) -> Option<&T>
|
||||||
where
|
where
|
||||||
for<'a> &'a T: TryFrom<&'a Object, Error = String>,
|
for<'a> &'a T: TryFrom<&'a Object, Error = String>,
|
||||||
Globals: wayland_client::Dispatch<P, ObjectKey>,
|
Globals: wayland_client::Dispatch<P, ObjectKey>,
|
||||||
{
|
{
|
||||||
let key: ObjectKey = proxy.data().copied().unwrap();
|
let key: ObjectKey = proxy.data().copied().unwrap();
|
||||||
self.objects[key].as_ref()
|
Some(self.objects.get(key)?.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_window(
|
pub fn new_window(
|
||||||
|
|
@ -539,10 +539,14 @@ impl<C: XConnection> ServerState<C> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if let Some(key) = win.surface_key {
|
if let Some(key) = win.surface_key {
|
||||||
let surface: &SurfaceData = self.objects[key].as_ref();
|
if let Some(object) = self.objects.get(key) {
|
||||||
|
let surface: &SurfaceData = object.as_ref();
|
||||||
if let Some(SurfaceRole::Toplevel(Some(data))) = &surface.role {
|
if let Some(SurfaceRole::Toplevel(Some(data))) = &surface.role {
|
||||||
data.toplevel.set_title(title.name().to_string());
|
data.toplevel.set_title(title.name().to_string());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
warn!("could not set window title: stale surface");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -551,10 +555,14 @@ impl<C: XConnection> ServerState<C> {
|
||||||
|
|
||||||
let class = win.attrs.class.insert(class);
|
let class = win.attrs.class.insert(class);
|
||||||
if let Some(key) = win.surface_key {
|
if let Some(key) = win.surface_key {
|
||||||
let surface: &SurfaceData = self.objects[key].as_ref();
|
if let Some(object) = self.objects.get(key) {
|
||||||
|
let surface: &SurfaceData = object.as_ref();
|
||||||
if let Some(SurfaceRole::Toplevel(Some(data))) = &surface.role {
|
if let Some(SurfaceRole::Toplevel(Some(data))) = &surface.role {
|
||||||
data.toplevel.set_app_id(class.to_string());
|
data.toplevel.set_app_id(class.to_string());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
warn!("could not set window class: stale surface");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -568,8 +576,9 @@ impl<C: XConnection> ServerState<C> {
|
||||||
|
|
||||||
if win.attrs.size_hints.is_none() || *win.attrs.size_hints.as_ref().unwrap() != hints {
|
if win.attrs.size_hints.is_none() || *win.attrs.size_hints.as_ref().unwrap() != hints {
|
||||||
debug!("setting {window:?} hints {hints:?}");
|
debug!("setting {window:?} hints {hints:?}");
|
||||||
if let Some(surface) = win.surface_key {
|
if let Some(key) = win.surface_key {
|
||||||
let surface: &SurfaceData = self.objects[surface].as_ref();
|
if let Some(object) = self.objects.get(key) {
|
||||||
|
let surface: &SurfaceData = object.as_ref();
|
||||||
if let Some(SurfaceRole::Toplevel(Some(data))) = &surface.role {
|
if let Some(SurfaceRole::Toplevel(Some(data))) = &surface.role {
|
||||||
if let Some(min_size) = &hints.min_size {
|
if let Some(min_size) = &hints.min_size {
|
||||||
data.toplevel.set_min_size(min_size.width, min_size.height);
|
data.toplevel.set_min_size(min_size.width, min_size.height);
|
||||||
|
|
@ -578,6 +587,9 @@ impl<C: XConnection> ServerState<C> {
|
||||||
data.toplevel.set_max_size(max_size.width, max_size.height);
|
data.toplevel.set_max_size(max_size.width, max_size.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
warn!("could not set size hint on {window:?}: stale surface")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
win.attrs.size_hints = Some(hints);
|
win.attrs.size_hints = Some(hints);
|
||||||
}
|
}
|
||||||
|
|
@ -620,7 +632,11 @@ impl<C: XConnection> ServerState<C> {
|
||||||
win.mapped = false;
|
win.mapped = false;
|
||||||
|
|
||||||
if let Some(key) = win.surface_key.take() {
|
if let Some(key) = win.surface_key.take() {
|
||||||
let surface: &mut SurfaceData = self.objects[key].as_mut();
|
let Some(object) = self.objects.get_mut(key) else {
|
||||||
|
warn!("could not unmap {window:?}: stale surface");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let surface: &mut SurfaceData = object.as_mut();
|
||||||
surface.destroy_role();
|
surface.destroy_role();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -631,7 +647,11 @@ impl<C: XConnection> ServerState<C> {
|
||||||
warn!("Tried to set window without surface fullscreen: {window:?}");
|
warn!("Tried to set window without surface fullscreen: {window:?}");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let surface: &mut SurfaceData = self.objects[key].as_mut();
|
let Some(object) = self.objects.get_mut(key) else {
|
||||||
|
warn!("Could not set fullscreen on {window:?}: stale surface");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let surface: &mut SurfaceData = object.as_mut();
|
||||||
let Some(SurfaceRole::Toplevel(Some(ref toplevel))) = surface.role else {
|
let Some(SurfaceRole::Toplevel(Some(ref toplevel))) = surface.role else {
|
||||||
warn!("Tried to set an unmapped toplevel or non toplevel fullscreen: {window:?}");
|
warn!("Tried to set an unmapped toplevel or non toplevel fullscreen: {window:?}");
|
||||||
return;
|
return;
|
||||||
|
|
@ -692,10 +712,13 @@ impl<C: XConnection> ServerState<C> {
|
||||||
|
|
||||||
let client_events = std::mem::take(&mut self.clientside.globals.events);
|
let client_events = std::mem::take(&mut self.clientside.globals.events);
|
||||||
for (key, event) in client_events {
|
for (key, event) in client_events {
|
||||||
let object = &mut self.objects[key];
|
let Some(object) = &mut self.objects.get_mut(key) else {
|
||||||
|
warn!("could not handle clientside event: stale surface");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
let mut object = object.0.take().unwrap();
|
let mut object = object.0.take().unwrap();
|
||||||
object.handle_event(event, self);
|
object.handle_event(event, self);
|
||||||
let ret = self.objects[key].0.replace(object);
|
let ret = self.objects[key].0.replace(object); // safe indexed access?
|
||||||
debug_assert!(ret.is_none());
|
debug_assert!(ret.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -884,16 +907,22 @@ impl<C: XConnection> ServerState<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_server_surface_from_client(&self, surface: client::wl_surface::WlSurface) -> &WlSurface {
|
fn get_server_surface_from_client(
|
||||||
|
&self,
|
||||||
|
surface: client::wl_surface::WlSurface,
|
||||||
|
) -> Option<&WlSurface> {
|
||||||
let key: &ObjectKey = surface.data().unwrap();
|
let key: &ObjectKey = surface.data().unwrap();
|
||||||
let surface: &SurfaceData = self.objects[*key].as_ref();
|
let surface: &SurfaceData = self.objects.get(*key)?.as_ref();
|
||||||
&surface.server
|
Some(&surface.server)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_client_surface_from_server(&self, surface: WlSurface) -> &client::wl_surface::WlSurface {
|
fn get_client_surface_from_server(
|
||||||
|
&self,
|
||||||
|
surface: WlSurface,
|
||||||
|
) -> Option<&client::wl_surface::WlSurface> {
|
||||||
let key: &ObjectKey = surface.data().unwrap();
|
let key: &ObjectKey = surface.data().unwrap();
|
||||||
let surface: &SurfaceData = self.objects[*key].as_ref();
|
let surface: &SurfaceData = self.objects.get(*key)?.as_ref();
|
||||||
&surface.client
|
Some(&surface.client)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_x_window(&mut self, window: x::Window) {
|
fn close_x_window(&mut self, window: x::Window) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue