blob: af9711585b87b0244f58fd7b28b4a96e94d63323 [file] [log] [blame] [edit]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use log::debug;
use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
use crate::exo;
use crate::ffi;
use crate::move_resize::{MoveGrab, ResizeGrab};
use crate::protocol;
use crate::remote_shell;
use crate::server;
use crate::Compositor;
use crate::{Position, Size, Geometry};
use nix::sys::signal;
pub struct Shell {
pub compositor: Rc<RefCell<Compositor>>,
pub fullscreen_layer: ffi::weston_layer,
pub workspace_layer: ffi::weston_layer,
pub background_layer: ffi::weston_layer,
pub binding_modifier: u32,
pub minimized_layer: ffi::weston_layer,
// We never read these, but hold on to them so they'll get dropped
// when the Shell is dropped. Silence the warning about never
// reading for now, but eventually we'll want signals to be a
// little more rust friendly.
#[allow(unused)]
idle_listener: Box<dyn Any>,
#[allow(unused)]
wake_listener: Box<dyn Any>,
#[allow(unused)]
activate_listener: Box<dyn Any>,
}
impl Shell {
pub fn new(rc: &Rc<RefCell<Compositor>>) -> Rc<RefCell<Self>> {
let rc = {
let compositor = &mut rc.borrow_mut();
Rc::new(RefCell::new(Shell {
compositor: Rc::clone(rc),
fullscreen_layer: ffi::weston_layer::zeroed(),
workspace_layer: ffi::weston_layer::zeroed(),
background_layer: ffi::weston_layer::zeroed(),
binding_modifier: ffi::weston_keyboard_modifier::MODIFIER_SUPER.0,
minimized_layer: ffi::weston_layer::zeroed(),
idle_listener: ffi::WlListener::new(&mut compositor.native.idle_signal, |_| {
debug!("-------------------- idle signal fired")
}),
wake_listener: ffi::WlListener::new(&mut compositor.native.wake_signal, |_| {
debug!("-------------------- wake signal fired")
}),
activate_listener: ffi::WlListener::new(
&mut compositor.native.activate_signal,
move |data| unsafe {
let data = *(data as *mut ffi::weston_surface_activation_data);
tokio::task::spawn_local(async move {
if let Some(shsurf) = Surface::get(data.surface) {
shsurf.borrow_mut().activate(data.seat, data.prev_focus)
}
});
},
),
}))
};
rc.borrow_mut().init();
rc
}
fn init_layers(&mut self) {
let compositor = &mut self.compositor.borrow_mut().native as *mut _;
self.fullscreen_layer.init(compositor);
self.fullscreen_layer
.set_position(ffi::weston_layer_position::WESTON_LAYER_POSITION_FULLSCREEN);
self.workspace_layer.init(compositor);
self.workspace_layer
.set_position(ffi::weston_layer_position::WESTON_LAYER_POSITION_FULLSCREEN);
self.background_layer.init(compositor);
self.background_layer
.set_position(ffi::weston_layer_position::WESTON_LAYER_POSITION_BACKGROUND);
self.minimized_layer.init(compositor);
}
fn init_bindings(&mut self) {
use crate::ffi::evdev::*;
let mut compositor = self.compositor.borrow_mut();
let rc = Rc::clone(&self.compositor);
compositor.bind_key(
KEY_BACKSPACE,
ffi::weston_keyboard_modifier::MODIFIER_CTRL
| ffi::weston_keyboard_modifier::MODIFIER_ALT,
move |_, _, _| {
let mut compositor = rc.borrow_mut();
compositor.server.terminate();
},
);
let no_mods = ffi::weston_keyboard_modifier(0);
let mods = ffi::weston_keyboard_modifier(self.binding_modifier);
let mods_with_shift = ffi::weston_keyboard_modifier(self.binding_modifier)
| ffi::weston_keyboard_modifier::MODIFIER_SHIFT;
let pointer_activate_binding = move |pointer: &mut ffi::weston_pointer, _, _| {
if pointer.grab != &mut pointer.default_grab as *mut _ {
return;
}
if let Some(view) = unsafe { pointer.focus.as_mut() } {
view.activate(pointer.seat, 0)
}
};
let touch_activate_binding = move |touch: &mut ffi::weston_touch, _| {
if touch.grab != &mut touch.default_grab as *mut _ {
return;
}
if let Some(view) = unsafe { touch.focus.as_mut() } {
view.activate(touch.seat, 0)
}
};
compositor.bind_button(BTN_LEFT, no_mods, pointer_activate_binding);
compositor.bind_button(BTN_RIGHT, no_mods, pointer_activate_binding);
compositor.bind_touch(no_mods, touch_activate_binding);
compositor.bind_key(KEY_M, mods_with_shift, move |keyboard, _, _| {
if let Some(shsurf) = Surface::get(keyboard.focus) {
let mut shsurf = shsurf.borrow_mut();
let enable = !shsurf.state.maximized;
shsurf.set_maximized(enable);
}
});
compositor.bind_key(KEY_F, mods_with_shift, move |keyboard, _, _| {
if let Some(shsurf) = Surface::get(keyboard.focus) {
let mut shsurf = shsurf.borrow_mut();
let enable = !shsurf.state.fullscreen;
shsurf.set_fullscreen(enable, std::ptr::null_mut());
}
});
compositor.bind_key(KEY_K, mods_with_shift, move |keyboard, _, _| {
if let Some(surface) = unsafe { keyboard.focus.as_ref() } {
let resource = server::Resource::<protocol::wl_surface::WlSurface>::from_c_ptr(
surface.resource,
);
let client = unsafe { &mut *resource.client() };
let (pid, _, _) = client.get_credentials();
signal::kill(nix::unistd::Pid::from_raw(pid), signal::SIGTERM).unwrap();
}
});
let rc = Rc::clone(&self.compositor);
let backlight_binding =
move |_: &mut ffi::weston_keyboard, _: *const ffi::timespec, key: u32| {
let mut compositor = rc.borrow_mut();
let mut output = match compositor.default_output() {
Some(o) => o,
_ => return,
};
let backlight = (output.backlight_current
+ match key {
KEY_F9 | KEY_BRIGHTNESSDOWN => -25,
KEY_F10 | KEY_BRIGHTNESSUP => 25,
_ => return,
})
.min(255)
.max(5);
output.backlight_current = backlight;
if let Some(set_backlight) = output.set_backlight {
unsafe { set_backlight(output, backlight as u32) }
}
};
compositor.bind_key(KEY_BRIGHTNESSDOWN, no_mods, backlight_binding.clone());
compositor.bind_key(KEY_BRIGHTNESSUP, no_mods, backlight_binding.clone());
compositor.bind_key(KEY_F9, mods, backlight_binding.clone());
compositor.bind_key(KEY_F10, mods, backlight_binding.clone());
compositor.bind_button(BTN_LEFT, mods, |pointer, _, _| {
Surface::from_view(pointer.focus)
.borrow_mut()
.r#move(pointer, false)
});
let resize_binding = |pointer: &mut ffi::weston_pointer, _, _| {
if !pointer.focus.is_null() {
let view = unsafe { &mut *pointer.focus };
let surface = unsafe { &mut *view.surface };
let (x, y) = view.from_global::<_, f32>(pointer.grab_x, pointer.grab_y);
let (x, y) = (x as i32, y as i32);
let hmargin = surface.width / 3;
let vmargin = surface.height / 3;
let edges = ResizeEdge {
left: x < hmargin,
right: x > surface.width - hmargin,
top: y < vmargin,
bottom: y > surface.height - vmargin
};
Surface::from_view(pointer.focus)
.borrow_mut()
.resize(pointer, edges)
}
};
compositor.bind_button(BTN_RIGHT, mods, resize_binding);
compositor.bind_button(BTN_LEFT, mods_with_shift, resize_binding);
unsafe {
ffi::weston_install_debug_key_binding(&mut compositor.native as *mut _, mods.0)
}
}
fn init(&mut self) {
self.init_layers();
self.init_bindings();
self.create_background_surface();
}
pub fn finish_init(rc: &Rc<RefCell<crate::Shell>>) {
unsafe {
let shell = &rc.borrow();
ffi::weston_compositor_init_input(&mut shell.compositor.borrow_mut().native);
}
exo::init(rc);
remote_shell::init(rc);
}
fn create_background_surface(&mut self) {
let compositor = self.compositor.borrow_mut();
let mut surface = unsafe { &mut (*compositor.create_surface()) };
surface.committed = None;
// xx set label func
surface.set_size(1024 * 1024, 1024 * 1024);
surface.set_color(0.2, 0.1, 0.1, 1.0);
surface.damage();
let view = unsafe { &mut *surface.create_view() };
view.set_position(0.0, 0.0);
view.geometry_dirty();
view.is_mapped = true;
unsafe {
ffi::weston_layer_entry_insert(
&mut self.background_layer.view_list,
&mut view.layer_link,
);
}
}
}
impl Drop for Shell {
fn drop(&mut self) {
debug!("-------------------- drop Shell");
}
}
fn get_work_area(output: *const ffi::weston_output) -> Geometry {
// Should be accounting for panels here or other UI elements that
// limit the maximized size.
let output = unsafe { output.as_ref().unwrap() };
Geometry {
x: output.x,
y: output.y,
width: output.width,
height: output.height,
}
}
fn get_focused_output(compositor: &mut Compositor) -> *mut ffi::weston_output {
for seat in compositor.native.seat_iter_mut() {
unsafe {
if let Some(touch) = seat.get_touch() {
if let Some(focus) = touch.focus.as_ref() {
if !focus.output.is_null() {
return focus.output;
}
}
}
if let Some(pointer) = seat.get_pointer() {
if let Some(focus) = pointer.focus.as_ref() {
if !focus.output.is_null() {
return focus.output;
}
}
}
if let Some(keyboard) = seat.get_keyboard() {
if let Some(focus) = keyboard.focus.as_ref() {
if !focus.output.is_null() {
return focus.output;
}
}
}
}
}
std::ptr::null_mut()
}
#[derive(Debug, Copy, Clone)]
pub struct SurfaceState {
pub fullscreen: bool,
pub maximized: bool,
pub lowered: bool,
pub activated: bool,
}
#[derive(Debug, Copy, Clone)]
pub struct ResizeEdge {
// Only one of top/bottom and left/right can be true, but both can
// be false, if we're not resizing in that direction.
pub top: bool,
pub bottom: bool,
pub left: bool,
pub right: bool,
}
impl ResizeEdge {
pub fn none() -> ResizeEdge {
ResizeEdge { top: false, bottom: false, left: false, right: false }
}
pub fn from_u32(bits: u32) -> Option<ResizeEdge> {
pub const LEFT: u32 = 1;
pub const RIGHT: u32 = 2;
pub const TOP: u32 = 4;
pub const BOTTOM: u32 = 8;
if bits == 0
|| bits & (TOP | BOTTOM) == (TOP | BOTTOM)
|| bits & (LEFT | RIGHT) == (LEFT | RIGHT)
{
None
} else {
Some(ResizeEdge {
left: (bits & LEFT) != 0,
right: (bits & RIGHT) != 0,
top: (bits & TOP) != 0,
bottom: (bits & BOTTOM) != 0,
})
}
}
}
#[derive(Debug)]
pub struct Surface {
pub destroy_signal: ffi::wl_signal,
pub state_change_signal: ffi::wl_signal,
pub view: *mut ffi::weston_view,
pub surface: *mut ffi::weston_surface,
pub last_size: Size,
pub shell: *mut Shell,
pub children_list: ffi::wl_list,
pub children_link: ffi::wl_list,
pub saved_position: Option<Position>,
pub unresponsive: bool,
pub grabbed: bool,
pub resize_edges: ResizeEdge,
pub fullscreen_output: *mut ffi::weston_output,
pub output: *mut ffi::weston_output,
pub output_destroy_listener: ffi::wl_listener,
pub pending_state: SurfaceState,
pub state: SurfaceState,
pub pending_size: Size,
pub geometry: Geometry,
pub focus_count: u32,
pub destroying: bool,
}
impl SurfaceState {
pub fn new() -> SurfaceState {
SurfaceState {
fullscreen: false,
maximized: false,
lowered: false,
activated: false,
}
}
}
pub fn lower_fullscreen_layer(
shell: &mut Shell,
_lowering_output: *mut ffi::weston_output,
) {
for view in wl_list_iter_mut!(&mut shell.fullscreen_layer.view_list.link, ffi::weston_view, layer_link.link) {
unsafe {
ffi::weston_layer_entry_remove(&mut view.layer_link);
ffi::weston_layer_entry_insert(
&mut shell.workspace_layer.view_list,
&mut view.layer_link,
);
view.damage_below();
let surface = &mut *view.surface;
surface.damage();
}
}
}
impl Surface {
pub fn new(
shell: &mut Shell,
surface: *mut ffi::weston_surface,
view: *mut ffi::weston_view,
) -> Rc<RefCell<Self>> {
let shsurf = Rc::new(RefCell::new(Self {
destroy_signal: ffi::wl_signal::zeroed(),
state_change_signal: ffi::wl_signal::zeroed(),
view,
surface,
last_size: Size { width: 0, height: 0 },
shell: shell as *mut _,
children_list: ffi::wl_list::zeroed(),
children_link: ffi::wl_list::zeroed(),
saved_position: None,
unresponsive: false,
grabbed: false,
resize_edges: ResizeEdge::none(),
fullscreen_output: 0 as *mut _,
output: 0 as *mut _,
output_destroy_listener: ffi::wl_listener::zeroed(),
pending_state: SurfaceState::new(),
state: SurfaceState::new(),
pending_size: Size { width: 0, height: 0 },
geometry: Geometry { x: 0, y: 0, width: 0, height: 0 },
focus_count: 0,
destroying: false,
}));
{
let mut shsurf = shsurf.borrow_mut();
shsurf.destroy_signal.init();
shsurf.state_change_signal.init();
shsurf.children_list.init();
shsurf.children_link.init();
}
if let Some(surface) = unsafe { surface.as_mut() } {
surface.committed = Some(Surface::committed);
surface.committed_private = Rc::into_raw(Rc::clone(&shsurf)) as *mut _;
}
shsurf
}
pub fn configure_fullscreen(&mut self) {
let view = unsafe { &mut *self.view };
let shell = unsafe { &mut *self.shell };
unsafe {
ffi::weston_layer_entry_remove(&mut view.layer_link);
ffi::weston_layer_entry_insert(
&mut shell.fullscreen_layer.view_list,
&mut view.layer_link,
);
}
if let Some(output) = unsafe { self.fullscreen_output.as_mut() } {
let x = output.x + (output.width - self.geometry.width) / 2 - self.geometry.x;
let y = output.y + (output.height - self.geometry.height) / 2 - self.geometry.y;
view.set_position(x as f32, y as f32);
} else {
view.set_position(0.0, 0.0);
}
}
pub fn configure_maximized(&mut self) {
let output = unsafe { &mut *self.output };
let work_area = get_work_area(output);
let view = unsafe { &mut *self.view };
view.set_position(
work_area.x as f32 - view.geometry.x,
work_area.y as f32 - view.geometry.y,
);
}
pub fn center_on_output(&mut self, output: *const ffi::weston_output) {
let view = unsafe { &mut *self.view };
if let Some(output) = unsafe { output.as_ref() } {
let geometry = self.geometry;
let x = output.x - geometry.x + (output.width - geometry.width) / 2;
let y = output.y - geometry.y + (output.height - geometry.height) / 2;
view.set_position(x as f32, y as f32);
} else {
view.set_position(0.0, 0.0);
}
}
pub fn set_initial_position(&mut self) {
let view = unsafe { &mut *self.view };
let shell = unsafe { &mut *self.shell };
let origin = unsafe {
get_focused_output(&mut shell.compositor.borrow_mut())
.as_ref()
.map(|output| (output.x as f32, output.y as f32))
.unwrap_or((0.0, 0.0))
};
// todo: random placement within work area.
view.set_position(origin.0 + 20.0, origin.1 + 20.0);
}
#[allow(dead_code)]
pub fn child_iter_mut<'a>(&'a mut self) -> ffi::WlListIterMut<'a, Surface> {
wl_list_iter_mut!(&mut self.children_list, Surface, children_link)
}
#[allow(dead_code)]
pub fn get_last_child<'a>(&'a mut self) -> Option<&'a mut Surface> {
self.child_iter_mut()
.rev()
.find(|shsurf| unsafe { shsurf.view.as_ref().map_or(false, |view| view.is_mapped()) })
}
pub fn from_view<'a>(view: *mut ffi::weston_view) -> Rc<RefCell<Surface>> {
let view = unsafe { &mut *view };
let surface = unsafe { &mut *view.surface };
Surface::get(surface.get_main_surface()).unwrap()
}
pub fn emit_state_changed(&mut self) {
self.state_change_signal.emit(&mut ())
}
fn raise_or_insert(&mut self) {
unsafe {
let shell = &mut *self.shell;
let view = &mut *self.view;
ffi::weston_layer_entry_remove(&mut view.layer_link);
if self.state.fullscreen {
ffi::weston_layer_entry_insert(
&mut shell.fullscreen_layer.view_list,
&mut view.layer_link,
);
} else {
ffi::weston_layer_entry_insert(
&mut shell.workspace_layer.view_list,
&mut view.layer_link,
);
}
}
}
fn activate(&mut self, _seat: *mut ffi::weston_seat, prev: *mut ffi::weston_surface) {
if self.state.activated || self.pending_state.activated {
return;
}
if !self.output.is_null() {
let shell = unsafe { &mut *self.shell };
lower_fullscreen_layer(shell, self.output);
}
if let Some(shsurf) = Surface::get(prev) {
let mut shsurf = shsurf.borrow_mut();
shsurf.focus_count = shsurf.focus_count - 1;
if shsurf.focus_count == 0 {
shsurf.pending_state.activated = false;
shsurf.emit_state_changed();
}
}
self.focus_count = self.focus_count + 1;
if self.focus_count == 1 {
self.pending_state.activated = true;
self.emit_state_changed();
}
self.raise_or_insert()
}
pub fn map(&mut self, _sx: i32, _sy: i32) {
let shell = unsafe { &mut *self.shell };
let view = unsafe { &mut *self.view };
let surface = unsafe { &mut *self.surface };
if self.state.fullscreen {
self.center_on_output(self.fullscreen_output)
} else if self.state.maximized {
self.configure_maximized()
} else {
self.set_initial_position()
}
self.raise_or_insert();
view.update_transform();
view.is_mapped = true;
if self.state.maximized {
surface.output = self.output;
view.set_output(self.output);
}
// This is terrible, but the problem was always here. Before
// we'd get away with it as we got a compositor reference form
// a pointer. Now that we're using the RefCell, we get an
// "already borrowed" as the activate callback tries to borrow
// the compositor again to schedule an idle callback.
//
// For now, map the seats into an array of seat pointers, then
// loop through that and call activate.
let seats: Vec<_> =
shell.compositor.borrow_mut().native.seat_iter_mut().map(|seat| seat as *mut _).collect();
for seat in seats {
view.activate(seat, 0)
}
}
extern "C" fn committed(surface: *mut ffi::weston_surface, sx: i32, sy: i32) {
let surface = unsafe { &mut *surface };
let rc = Surface::get(surface).unwrap();
let mut shsurf = rc.borrow_mut();
let view = unsafe { &mut *shsurf.view };
if surface.width == 0 {
return;
}
let was_fullscreen = shsurf.state.fullscreen;
let was_maximized = shsurf.state.maximized;
shsurf.state = shsurf.pending_state;
if !surface.is_mapped() {
shsurf.map(sx, sy);
surface.is_mapped = true;
return;
}
if sx == 0
&& sy == 0
&& shsurf.last_size.width == surface.width
&& shsurf.last_size.height == surface.height
&& was_fullscreen == shsurf.state.fullscreen
&& was_maximized == shsurf.state.maximized
{
return;
}
if was_fullscreen {
let view = unsafe { &mut *shsurf.view };
if let Some(pos) = shsurf.saved_position.take() {
view.set_position(pos.x as f32, pos.y as f32);
} else {
shsurf.set_initial_position();
}
}
if was_maximized {
let shell = unsafe { &mut *shsurf.shell };
shsurf.set_output(get_focused_output(&mut shell.compositor.borrow_mut()));
if let Some(pos) = shsurf.saved_position.take() {
view.set_position(pos.x as f32, pos.y as f32);
} else {
shsurf.set_initial_position();
}
}
if shsurf.state.fullscreen || shsurf.state.maximized {
shsurf.saved_position.get_or_insert(Position {
x: view.geometry.x as i32,
y: view.geometry.y as i32
});
}
if shsurf.state.fullscreen {
shsurf.configure_fullscreen();
} else if shsurf.state.maximized {
shsurf.configure_maximized();
surface.output = shsurf.output;
} else {
let resize_dx = if shsurf.resize_edges.left {
shsurf.last_size.width - surface.height
} else {
0
};
let resize_dy = if shsurf.resize_edges.top {
shsurf.last_size.height - surface.height
} else {
0
};
let from: (f32, _) = view.to_global(0.0, 0.0);
let to: (f32, _) = view.to_global((sx + resize_dx) as f32, (sy + resize_dy) as f32);
let x = view.geometry.x + to.0 - from.0;
let y = view.geometry.y + to.1 - from.1;
view.set_position(x, y);
}
shsurf.last_size = Size { width: surface.width, height: surface.height };
if !surface.output.is_null() {
for view in surface.view_iter_mut() {
view.update_transform()
}
}
}
pub fn set_output(&mut self, output: *mut ffi::weston_output) {
// todo: We need to use weak references in places like this
// where the C code hooks the destroy listener. We need to
// handle an output going away at a higher level and then move
// the surfaces, but each surface doesn't need to hook the
// output destroy signal.
self.output = output;
}
pub fn get(surface: *mut ffi::weston_surface) -> Option<Rc<RefCell<Surface>>> {
unsafe {
let surface = surface.as_mut()?;
if surface.committed == Some(Surface::committed) {
let ptr = surface.committed_private as *const _;
Rc::increment_strong_count(ptr);
Some(Rc::from_raw(ptr))
} else {
None
}
}
}
pub fn r#move(&mut self, pointer: &mut ffi::weston_pointer, _client_initiated: bool) {
MoveGrab::start(pointer, self)
}
pub fn resize(
&mut self,
pointer: &mut ffi::weston_pointer,
edges: ResizeEdge,
) {
ResizeGrab::start(pointer, self, edges);
}
pub fn set_size(&mut self, width: i32, height: i32) {
self.pending_size = ffi::weston_size { width, height };
self.emit_state_changed()
}
pub fn set_resizing(&mut self, edges: ResizeEdge) {
self.resize_edges = edges;
self.emit_state_changed()
}
pub fn get_geometry(&self) -> ffi::weston_geometry {
self.geometry
}
pub fn get_maximized_size(&self) -> ffi::weston_size {
let output = unsafe { &mut *self.output };
let work_area = get_work_area(output);
ffi::weston_size {
width: work_area.width,
height: work_area.height,
}
}
pub fn set_maximized(&mut self, enable: bool) {
self.pending_state.maximized = enable;
self.pending_size = if enable {
let surface = unsafe { &mut *self.surface };
let output = if surface.is_mapped() {
surface.output
} else {
let shell = unsafe { &mut *self.shell };
get_focused_output(&mut shell.compositor.borrow_mut())
};
self.set_output(output);
self.get_maximized_size()
} else {
ffi::weston_size { width: 0, height: 0 }
};
self.emit_state_changed();
}
pub fn set_fullscreen(&mut self, enable: bool, output: *mut ffi::weston_output) {
self.pending_state.fullscreen = enable;
self.pending_size = if enable {
let surface = unsafe { &mut *self.surface };
let output = if output.is_null() && !surface.is_mapped() {
let shell = unsafe { &mut *self.shell };
get_focused_output(&mut shell.compositor.borrow_mut())
} else {
output
};
self.set_output(output);
self.fullscreen_output = output;
if let Some(output) = unsafe { self.output.as_ref() } {
ffi::weston_size {
width: output.width,
height: output.height,
}
} else {
ffi::weston_size { width: 0, height: 0 }
}
} else if self.state.maximized {
self.get_maximized_size()
} else {
ffi::weston_size { width: 0, height: 0 }
};
self.emit_state_changed();
}
pub fn set_minimized(&mut self) {
let view = unsafe { &mut *self.view };
let shell = unsafe { &mut *self.shell };
unsafe {
ffi::weston_layer_entry_remove(&mut view.layer_link);
ffi::weston_layer_entry_insert(
&mut shell.minimized_layer.view_list,
&mut view.layer_link,
);
}
for keyboard in shell.compositor.borrow_mut().native.seat_iter_mut()
.filter_map(|seat| seat.get_keyboard())
.filter(|keyboard| keyboard.focus == self.surface) {
keyboard.set_focus(0 as *mut _)
}
view.damage_below();
}
}
impl Drop for Surface {
fn drop(&mut self) {
self.children_list.remove();
self.children_link.remove();
}
}