Move impls to Pinnacle

This commit is contained in:
Ottatop 2024-04-26 19:58:02 -05:00
parent 8aaec59452
commit b99cc8ffce
29 changed files with 665 additions and 647 deletions

View file

@ -192,7 +192,7 @@ impl pinnacle_service_server::PinnacleService for PinnacleService {
trace!("PinnacleService.quit"); trace!("PinnacleService.quit");
run_unary_no_response(&self.sender, |state| { run_unary_no_response(&self.sender, |state| {
state.shutdown(); state.pinnacle.shutdown();
}) })
.await .await
} }
@ -204,6 +204,7 @@ impl pinnacle_service_server::PinnacleService for PinnacleService {
run_unary_no_response(&self.sender, |state| { run_unary_no_response(&self.sender, |state| {
info!("Reloading config"); info!("Reloading config");
state state
.pinnacle
.start_config(Some( .start_config(Some(
state.pinnacle.config.dir(&state.pinnacle.xdg_base_dirs), state.pinnacle.config.dir(&state.pinnacle.xdg_base_dirs),
)) ))
@ -734,7 +735,7 @@ impl tag_service_server::TagService for TagService {
} }
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(tag) = tag_id.tag(state) else { let Some(tag) = tag_id.tag(&state.pinnacle) else {
return; return;
}; };
@ -745,13 +746,13 @@ impl tag_service_server::TagService for TagService {
SetOrToggle::Unspecified => unreachable!(), SetOrToggle::Unspecified => unreachable!(),
} }
let Some(output) = tag.output(state) else { let Some(output) = tag.output(&state.pinnacle) else {
return; return;
}; };
state.fixup_xwayland_window_layering(); state.pinnacle.fixup_xwayland_window_layering();
state.request_layout(&output); state.pinnacle.request_layout(&output);
state.update_focus(&output); state.update_focus(&output);
state.schedule_render(&output); state.schedule_render(&output);
}) })
@ -768,8 +769,10 @@ impl tag_service_server::TagService for TagService {
); );
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(tag) = tag_id.tag(state) else { return }; let Some(tag) = tag_id.tag(&state.pinnacle) else { return };
let Some(output) = tag.output(state) else { return }; let Some(output) = tag.output(&state.pinnacle) else {
return;
};
output.with_state_mut(|op_state| { output.with_state_mut(|op_state| {
for op_tag in op_state.tags.iter_mut() { for op_tag in op_state.tags.iter_mut() {
@ -778,9 +781,9 @@ impl tag_service_server::TagService for TagService {
tag.set_active(true, state); tag.set_active(true, state);
}); });
state.fixup_xwayland_window_layering(); state.pinnacle.fixup_xwayland_window_layering();
state.request_layout(&output); state.pinnacle.request_layout(&output);
state.update_focus(&output); state.update_focus(&output);
state.schedule_render(&output); state.schedule_render(&output);
}) })
@ -818,7 +821,7 @@ impl tag_service_server::TagService for TagService {
.tags .tags
.extend(new_tags.clone()); .extend(new_tags.clone());
if let Some(output) = output_name.output(state) { if let Some(output) = output_name.output(&state.pinnacle) {
output.with_state_mut(|state| { output.with_state_mut(|state| {
state.tags.extend(new_tags.clone()); state.tags.extend(new_tags.clone());
debug!("tags added, are now {:?}", state.tags); debug!("tags added, are now {:?}", state.tags);
@ -849,7 +852,9 @@ impl tag_service_server::TagService for TagService {
let tag_ids = request.tag_ids.into_iter().map(TagId); let tag_ids = request.tag_ids.into_iter().map(TagId);
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let tags_to_remove = tag_ids.flat_map(|id| id.tag(state)).collect::<Vec<_>>(); let tags_to_remove = tag_ids
.flat_map(|id| id.tag(&state.pinnacle))
.collect::<Vec<_>>();
for output in state.pinnacle.space.outputs().cloned().collect::<Vec<_>>() { for output in state.pinnacle.space.outputs().cloned().collect::<Vec<_>>() {
// TODO: seriously, convert state.tags into a hashset // TODO: seriously, convert state.tags into a hashset
@ -859,7 +864,7 @@ impl tag_service_server::TagService for TagService {
} }
}); });
state.request_layout(&output); state.pinnacle.request_layout(&output);
state.schedule_render(&output); state.schedule_render(&output);
} }
@ -904,11 +909,11 @@ impl tag_service_server::TagService for TagService {
); );
run_unary(&self.sender, move |state| { run_unary(&self.sender, move |state| {
let tag = tag_id.tag(state); let tag = tag_id.tag(&state.pinnacle);
let output_name = tag let output_name = tag
.as_ref() .as_ref()
.and_then(|tag| tag.output(state)) .and_then(|tag| tag.output(&state.pinnacle))
.map(|output| output.name()); .map(|output| output.name());
let active = tag.as_ref().map(|tag| tag.active()); let active = tag.as_ref().map(|tag| tag.active());
let name = tag.as_ref().map(|tag| tag.name()); let name = tag.as_ref().map(|tag| tag.name());
@ -989,7 +994,7 @@ impl output_service_server::OutputService for OutputService {
); );
} }
let Some(output) = output_name.output(state) else { let Some(output) = output_name.output(&state.pinnacle) else {
return; return;
}; };
let mut loc = output.current_location(); let mut loc = output.current_location();
@ -999,9 +1004,11 @@ impl output_service_server::OutputService for OutputService {
if let Some(y) = y { if let Some(y) = y {
loc.y = y; loc.y = y;
} }
state.change_output_state(&output, None, None, None, Some(loc)); state
.pinnacle
.change_output_state(&output, None, None, None, Some(loc));
debug!("Mapping output {} to {loc:?}", output.name()); debug!("Mapping output {} to {loc:?}", output.name());
state.request_layout(&output); state.pinnacle.request_layout(&output);
}) })
.await .await
} }
@ -1014,7 +1021,7 @@ impl output_service_server::OutputService for OutputService {
.output_name .output_name
.clone() .clone()
.map(OutputName) .map(OutputName)
.and_then(|name| name.output(state)) .and_then(|name| name.output(&state.pinnacle))
else { else {
return; return;
}; };
@ -1046,7 +1053,7 @@ impl output_service_server::OutputService for OutputService {
}; };
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(output) = OutputName(output_name).output(state) else { let Some(output) = OutputName(output_name).output(&state.pinnacle) else {
return; return;
}; };
@ -1059,14 +1066,14 @@ impl output_service_server::OutputService for OutputService {
current_scale = f64::max(current_scale, 0.25); current_scale = f64::max(current_scale, 0.25);
state.change_output_state( state.pinnacle.change_output_state(
&output, &output,
None, None,
None, None,
Some(Scale::Fractional(current_scale)), Some(Scale::Fractional(current_scale)),
None, None,
); );
state.request_layout(&output); state.pinnacle.request_layout(&output);
state.schedule_render(&output); state.schedule_render(&output);
}) })
.await .await
@ -1097,12 +1104,14 @@ impl output_service_server::OutputService for OutputService {
}; };
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(output) = OutputName(output_name).output(state) else { let Some(output) = OutputName(output_name).output(&state.pinnacle) else {
return; return;
}; };
state.change_output_state(&output, None, Some(smithay_transform), None, None); state
state.request_layout(&output); .pinnacle
.change_output_state(&output, None, Some(smithay_transform), None, None);
state.pinnacle.request_layout(&output);
state.schedule_render(&output); state.schedule_render(&output);
}) })
.await .await
@ -1146,7 +1155,7 @@ impl output_service_server::OutputService for OutputService {
}; };
run_unary(&self.sender, move |state| { run_unary(&self.sender, move |state| {
let output = output_name.output(state); let output = output_name.output(&state.pinnacle);
let logical_size = output let logical_size = output
.as_ref() .as_ref()
@ -1193,6 +1202,7 @@ impl output_service_server::OutputService for OutputService {
let y = output.as_ref().map(|output| output.current_location().y); let y = output.as_ref().map(|output| output.current_location().y);
let focused = state let focused = state
.pinnacle
.focused_output() .focused_output()
.and_then(|foc_op| output.as_ref().map(|op| op == foc_op)); .and_then(|foc_op| output.as_ref().map(|op| op == foc_op));

View file

@ -44,10 +44,10 @@ impl layout_service_server::LayoutService for LayoutService {
layout_request::Body::Layout(ExplicitLayout { output_name }) => { layout_request::Body::Layout(ExplicitLayout { output_name }) => {
if let Some(output) = output_name if let Some(output) = output_name
.map(OutputName) .map(OutputName)
.and_then(|name| name.output(state)) .and_then(|name| name.output(&state.pinnacle))
.or_else(|| state.focused_output().cloned()) .or_else(|| state.pinnacle.focused_output().cloned())
{ {
state.request_layout(&output); state.pinnacle.request_layout(&output);
} }
} }
} }

View file

@ -50,7 +50,9 @@ impl window_service_server::WindowService for WindowService {
); );
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(window) = window_id.window(state) else { return }; let Some(window) = window_id.window(&state.pinnacle) else {
return;
};
match window.underlying_surface() { match window.underlying_surface() {
WindowSurface::Wayland(toplevel) => toplevel.send_close(), WindowSurface::Wayland(toplevel) => toplevel.send_close(),
@ -89,7 +91,9 @@ impl window_service_server::WindowService for WindowService {
let height = geometry.height; let height = geometry.height;
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(window) = window_id.window(state) else { return }; let Some(window) = window_id.window(&state.pinnacle) else {
return;
};
// TODO: with no x or y, defaults unmapped windows to 0, 0 // TODO: with no x or y, defaults unmapped windows to 0, 0
let mut window_loc = state let mut window_loc = state
@ -115,7 +119,7 @@ impl window_service_server::WindowService for WindowService {
}); });
for output in state.pinnacle.space.outputs_for_element(&window) { for output in state.pinnacle.space.outputs_for_element(&window) {
state.request_layout(&output); state.pinnacle.request_layout(&output);
state.schedule_render(&output); state.schedule_render(&output);
} }
}) })
@ -141,7 +145,8 @@ impl window_service_server::WindowService for WindowService {
} }
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(window) = window_id.window(state) else { let pinnacle = &mut state.pinnacle;
let Some(window) = window_id.window(pinnacle) else {
return; return;
}; };
@ -160,11 +165,11 @@ impl window_service_server::WindowService for WindowService {
SetOrToggle::Unspecified => unreachable!(), SetOrToggle::Unspecified => unreachable!(),
} }
let Some(output) = window.output(state) else { let Some(output) = window.output(pinnacle) else {
return; return;
}; };
state.request_layout(&output); pinnacle.request_layout(&output);
state.schedule_render(&output); state.schedule_render(&output);
}) })
.await .await
@ -189,7 +194,8 @@ impl window_service_server::WindowService for WindowService {
} }
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(window) = window_id.window(state) else { let pinnacle = &mut state.pinnacle;
let Some(window) = window_id.window(pinnacle) else {
return; return;
}; };
@ -208,11 +214,11 @@ impl window_service_server::WindowService for WindowService {
SetOrToggle::Unspecified => unreachable!(), SetOrToggle::Unspecified => unreachable!(),
} }
let Some(output) = window.output(state) else { let Some(output) = window.output(pinnacle) else {
return; return;
}; };
state.request_layout(&output); pinnacle.request_layout(&output);
state.schedule_render(&output); state.schedule_render(&output);
}) })
.await .await
@ -237,7 +243,8 @@ impl window_service_server::WindowService for WindowService {
} }
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(window) = window_id.window(state) else { let pinnacle = &mut state.pinnacle;
let Some(window) = window_id.window(pinnacle) else {
return; return;
}; };
@ -256,11 +263,11 @@ impl window_service_server::WindowService for WindowService {
SetOrToggle::Unspecified => unreachable!(), SetOrToggle::Unspecified => unreachable!(),
} }
let Some(output) = window.output(state) else { let Some(output) = window.output(pinnacle) else {
return; return;
}; };
state.request_layout(&output); pinnacle.request_layout(&output);
state.schedule_render(&output); state.schedule_render(&output);
}) })
.await .await
@ -285,7 +292,7 @@ impl window_service_server::WindowService for WindowService {
} }
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(window) = window_id.window(state) else { let Some(window) = window_id.window(&state.pinnacle) else {
return; return;
}; };
@ -293,7 +300,7 @@ impl window_service_server::WindowService for WindowService {
return; return;
} }
let Some(output) = window.output(state) else { let Some(output) = window.output(&state.pinnacle) else {
return; return;
}; };
@ -315,7 +322,7 @@ impl window_service_server::WindowService for WindowService {
} }
} }
SetOrToggle::Unset => { SetOrToggle::Unset => {
if state.focused_window(&output) == Some(window) { if state.pinnacle.focused_window(&output) == Some(window) {
output.with_state_mut(|state| state.focus_stack.unset_focus()); output.with_state_mut(|state| state.focus_stack.unset_focus());
if let Some(keyboard) = state.pinnacle.seat.get_keyboard() { if let Some(keyboard) = state.pinnacle.seat.get_keyboard() {
keyboard.set_focus(state, None, SERIAL_COUNTER.next_serial()); keyboard.set_focus(state, None, SERIAL_COUNTER.next_serial());
@ -323,7 +330,7 @@ impl window_service_server::WindowService for WindowService {
} }
} }
SetOrToggle::Toggle => { SetOrToggle::Toggle => {
if state.focused_window(&output).as_ref() == Some(&window) { if state.pinnacle.focused_window(&output).as_ref() == Some(&window) {
output.with_state_mut(|state| state.focus_stack.unset_focus()); output.with_state_mut(|state| state.focus_stack.unset_focus());
if let Some(keyboard) = state.pinnacle.seat.get_keyboard() { if let Some(keyboard) = state.pinnacle.seat.get_keyboard() {
keyboard.set_focus(state, None, SERIAL_COUNTER.next_serial()); keyboard.set_focus(state, None, SERIAL_COUNTER.next_serial());
@ -374,13 +381,16 @@ impl window_service_server::WindowService for WindowService {
); );
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(window) = window_id.window(state) else { return }; let pinnacle = &mut state.pinnacle;
let Some(tag) = tag_id.tag(state) else { return }; let Some(window) = window_id.window(pinnacle) else {
return;
};
let Some(tag) = tag_id.tag(pinnacle) else { return };
window.with_state_mut(|state| { window.with_state_mut(|state| {
state.tags = vec![tag.clone()]; state.tags = vec![tag.clone()];
}); });
let Some(output) = tag.output(state) else { return }; let Some(output) = tag.output(pinnacle) else { return };
state.request_layout(&output); pinnacle.request_layout(&output);
state.schedule_render(&output); state.schedule_render(&output);
}) })
.await .await
@ -408,8 +418,11 @@ impl window_service_server::WindowService for WindowService {
} }
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(window) = window_id.window(state) else { return }; let pinnacle = &mut state.pinnacle;
let Some(tag) = tag_id.tag(state) else { return }; let Some(window) = window_id.window(pinnacle) else {
return;
};
let Some(tag) = tag_id.tag(pinnacle) else { return };
// TODO: turn state.tags into a hashset // TODO: turn state.tags into a hashset
match set_or_toggle { match set_or_toggle {
@ -430,8 +443,8 @@ impl window_service_server::WindowService for WindowService {
SetOrToggle::Unspecified => unreachable!(), SetOrToggle::Unspecified => unreachable!(),
} }
let Some(output) = tag.output(state) else { return }; let Some(output) = tag.output(pinnacle) else { return };
state.request_layout(&output); pinnacle.request_layout(&output);
state.schedule_render(&output); state.schedule_render(&output);
}) })
.await .await
@ -447,12 +460,13 @@ impl window_service_server::WindowService for WindowService {
); );
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(window) = window_id.window(state) else { let pinnacle = &mut state.pinnacle;
let Some(window) = window_id.window(pinnacle) else {
warn!("`raise` was called on a nonexistent window"); warn!("`raise` was called on a nonexistent window");
return; return;
}; };
state.raise_window(window, false); pinnacle.raise_window(window, false);
}) })
.await .await
} }
@ -486,13 +500,7 @@ impl window_service_server::WindowService for WindowService {
}; };
let seat = state.pinnacle.seat.clone(); let seat = state.pinnacle.seat.clone();
crate::grab::move_grab::move_request_server( state.move_request_server(&wl_surf, &seat, SERIAL_COUNTER.next_serial(), button);
state,
&wl_surf,
&seat,
SERIAL_COUNTER.next_serial(),
button,
);
}) })
.await .await
} }
@ -566,8 +574,7 @@ impl window_service_server::WindowService for WindowService {
_ => server::xdg_toplevel::ResizeEdge::None, _ => server::xdg_toplevel::ResizeEdge::None,
}; };
crate::grab::resize_grab::resize_request_server( state.resize_request_server(
state,
&wl_surf, &wl_surf,
&state.pinnacle.seat.clone(), &state.pinnacle.seat.clone(),
SERIAL_COUNTER.next_serial(), SERIAL_COUNTER.next_serial(),
@ -608,7 +615,8 @@ impl window_service_server::WindowService for WindowService {
); );
run_unary(&self.sender, move |state| { run_unary(&self.sender, move |state| {
let window = window_id.window(state); let pinnacle = &state.pinnacle;
let window = window_id.window(pinnacle);
let width = window.as_ref().map(|win| win.geometry().size.w); let width = window.as_ref().map(|win| win.geometry().size.w);
@ -639,9 +647,9 @@ impl window_service_server::WindowService for WindowService {
let title = window.as_ref().and_then(|win| win.title()); let title = window.as_ref().and_then(|win| win.title());
let focused = window.as_ref().and_then(|win| { let focused = window.as_ref().and_then(|win| {
state pinnacle
.focused_output() .focused_output()
.and_then(|output| state.focused_window(output)) .and_then(|output| pinnacle.focused_window(output))
.map(|foc_win| win == &foc_win) .map(|foc_win| win == &foc_win)
}); });

View file

@ -14,7 +14,7 @@ use smithay::{
utils::Transform, utils::Transform,
}; };
use crate::state::State; use crate::state::{Pinnacle, State};
#[cfg(feature = "wlcs")] #[cfg(feature = "wlcs")]
use super::wlcs::Wlcs; use super::wlcs::Wlcs;
@ -132,7 +132,7 @@ pub fn setup_dummy(
Ok((state, event_loop)) Ok((state, event_loop))
} }
impl State { impl Pinnacle {
pub fn new_output(&mut self, name: impl std::fmt::Display, size: Size<i32, Physical>) { pub fn new_output(&mut self, name: impl std::fmt::Display, size: Size<i32, Physical>) {
let mode = smithay::output::Mode { let mode = smithay::output::Mode {
size, size,
@ -152,11 +152,11 @@ impl State {
output.set_preferred(mode); output.set_preferred(mode);
output.create_global::<State>(&self.pinnacle.display_handle); output.create_global::<State>(&self.display_handle);
self.pinnacle.space.map_output(&output, (0, 0)); self.space.map_output(&output, (0, 0));
self.pinnacle.signal_state.output_connect.signal(|buf| { self.signal_state.output_connect.signal(|buf| {
buf.push_back(OutputConnectResponse { buf.push_back(OutputConnectResponse {
output_name: Some(output.name()), output_name: Some(output.name()),
}); });
@ -164,15 +164,12 @@ impl State {
} }
pub fn remove_output(&mut self, output: &Output) { pub fn remove_output(&mut self, output: &Output) {
self.pinnacle.space.unmap_output(output); self.space.unmap_output(output);
self.pinnacle self.signal_state.output_disconnect.signal(|buffer| {
.signal_state buffer.push_back(OutputDisconnectResponse {
.output_disconnect output_name: Some(output.name()),
.signal(|buffer| { })
buffer.push_back(OutputDisconnectResponse { });
output_name: Some(output.name()),
})
});
} }
} }

View file

@ -271,18 +271,20 @@ impl State {
{ {
match render_surface.compositor.use_mode(drm_mode) { match render_surface.compositor.use_mode(drm_mode) {
Ok(()) => { Ok(()) => {
self.change_output_state(output, Some(mode), None, None, None); self.pinnacle
.change_output_state(output, Some(mode), None, None, None);
} }
Err(err) => error!("Failed to resize output: {err}"), Err(err) => error!("Failed to resize output: {err}"),
} }
} }
} }
} else { } else {
self.change_output_state(output, Some(mode), None, None, None); self.pinnacle
.change_output_state(output, Some(mode), None, None, None);
} }
self.pinnacle.request_layout(output);
self.schedule_render(output); self.schedule_render(output);
self.request_layout(output);
} }
} }
@ -441,7 +443,7 @@ pub fn setup_udev(
let insert_ret = event_loop let insert_ret = event_loop
.handle() .handle()
.insert_source(libinput_backend, move |event, _, state| { .insert_source(libinput_backend, move |event, _, state| {
state.apply_libinput_settings(&event); state.pinnacle.apply_libinput_settings(&event);
state.process_input_event(event); state.process_input_event(event);
}); });
@ -1111,7 +1113,8 @@ impl State {
device.surfaces.insert(crtc, surface); device.surfaces.insert(crtc, surface);
self.change_output_state(&output, Some(wl_mode), None, None, Some(position)); self.pinnacle
.change_output_state(&output, Some(wl_mode), None, None, Some(position));
// If there is saved connector state, the connector was previously plugged in. // If there is saved connector state, the connector was previously plugged in.
// In this case, restore its tags and location. // In this case, restore its tags and location.
@ -1124,7 +1127,8 @@ impl State {
{ {
let ConnectorSavedState { loc, tags, scale } = saved_state; let ConnectorSavedState { loc, tags, scale } = saved_state;
output.with_state_mut(|state| state.tags = tags.clone()); output.with_state_mut(|state| state.tags = tags.clone());
self.change_output_state(&output, None, None, *scale, Some(*loc)); self.pinnacle
.change_output_state(&output, None, None, *scale, Some(*loc));
} else { } else {
self.pinnacle.signal_state.output_connect.signal(|buffer| { self.pinnacle.signal_state.output_connect.signal(|buffer| {
buffer.push_back(OutputConnectResponse { buffer.push_back(OutputConnectResponse {

View file

@ -220,14 +220,14 @@ pub fn setup_winit(
size, size,
refresh: 144_000, refresh: 144_000,
}; };
state.change_output_state( state.pinnacle.change_output_state(
&output, &output,
Some(mode), Some(mode),
None, None,
Some(Scale::Fractional(scale_factor)), Some(Scale::Fractional(scale_factor)),
None, None,
); );
state.request_layout(&output); state.pinnacle.request_layout(&output);
} }
WinitEvent::Focus(focused) => { WinitEvent::Focus(focused) => {
if focused { if focused {
@ -241,12 +241,12 @@ pub fn setup_winit(
state.render_winit_window(&output); state.render_winit_window(&output);
} }
WinitEvent::CloseRequested => { WinitEvent::CloseRequested => {
state.shutdown(); state.pinnacle.shutdown();
} }
}); });
if let PumpStatus::Exit(_) = status { if let PumpStatus::Exit(_) = status {
state.shutdown(); state.pinnacle.shutdown();
} }
state.render_winit_window(&output); state.render_winit_window(&output);

View file

@ -12,7 +12,7 @@ use smithay::{
use tracing::debug; use tracing::debug;
use crate::{ use crate::{
state::{State, WithState}, state::{Pinnacle, State, WithState},
tag::TagId, tag::TagId,
}; };
@ -89,14 +89,14 @@ pub fn setup_wlcs_dummy() -> anyhow::Result<(State, EventLoop<'static, State>)>
Ok((state, event_loop)) Ok((state, event_loop))
} }
impl State { impl Pinnacle {
pub fn start_wlcs_config<F>(&mut self, socket_dir: &Path, run_config: F) -> anyhow::Result<()> pub fn start_wlcs_config<F>(&mut self, socket_dir: &Path, run_config: F) -> anyhow::Result<()>
where where
F: FnOnce() + Send + 'static, F: FnOnce() + Send + 'static,
{ {
// Clear state // Clear state
debug!("Clearing tags"); debug!("Clearing tags");
for output in self.pinnacle.space.outputs() { for output in self.space.outputs() {
output.with_state_mut(|state| state.tags.clear()); output.with_state_mut(|state| state.tags.clear());
} }
@ -104,23 +104,22 @@ impl State {
debug!("Clearing input state"); debug!("Clearing input state");
self.pinnacle.input_state.clear(); self.input_state.clear();
self.pinnacle.config.clear(&self.pinnacle.loop_handle); self.config.clear(&self.loop_handle);
self.pinnacle.signal_state.clear(); self.signal_state.clear();
self.pinnacle.input_state.reload_keybind = None; self.input_state.reload_keybind = None;
self.pinnacle.input_state.kill_keybind = None; self.input_state.kill_keybind = None;
if self.pinnacle.grpc_server_join_handle.is_none() { if self.grpc_server_join_handle.is_none() {
self.start_grpc_server(socket_dir)?; self.start_grpc_server(socket_dir)?;
} }
let (pinger, ping_source) = calloop::ping::make_ping()?; let (pinger, ping_source) = calloop::ping::make_ping()?;
let token = self let token = self
.pinnacle
.loop_handle .loop_handle
.insert_source(ping_source, move |_, _, _state| {})?; .insert_source(ping_source, move |_, _, _state| {})?;
@ -129,7 +128,7 @@ impl State {
pinger.ping(); pinger.ping();
}); });
self.pinnacle.config.config_reload_on_crash_token = Some(token); self.config.config_reload_on_crash_token = Some(token);
Ok(()) Ok(())
} }

View file

@ -5,6 +5,7 @@ use crate::{
}, },
input::ModifierMask, input::ModifierMask,
output::OutputName, output::OutputName,
state::Pinnacle,
tag::Tag, tag::Tag,
window::rules::{WindowRule, WindowRuleCondition}, window::rules::{WindowRule, WindowRuleCondition},
}; };
@ -266,7 +267,7 @@ fn get_config_dir(xdg_base_dirs: &BaseDirectories) -> PathBuf {
config_dir.unwrap_or(xdg_base_dirs.get_config_home()) config_dir.unwrap_or(xdg_base_dirs.get_config_home())
} }
impl State { impl Pinnacle {
/// Start the config in `config_dir`. /// Start the config in `config_dir`.
/// ///
/// If this method is called while a config is already running, it will be replaced. /// If this method is called while a config is already running, it will be replaced.
@ -276,7 +277,7 @@ impl State {
// Clear state // Clear state
debug!("Clearing tags"); debug!("Clearing tags");
for output in self.pinnacle.space.outputs() { for output in self.space.outputs() {
output.with_state_mut(|state| state.tags.clear()); output.with_state_mut(|state| state.tags.clear());
} }
@ -284,14 +285,14 @@ impl State {
debug!("Clearing input state"); debug!("Clearing input state");
self.pinnacle.input_state.clear(); self.input_state.clear();
self.pinnacle.config.clear(&self.pinnacle.loop_handle); self.config.clear(&self.loop_handle);
self.pinnacle.signal_state.clear(); self.signal_state.clear();
let config_dir_clone = config_dir.as_ref().map(|dir| dir.as_ref().to_path_buf()); let config_dir_clone = config_dir.as_ref().map(|dir| dir.as_ref().to_path_buf());
let load_default_config = |state: &mut State, reason: &str| { let load_default_config = |pinnacle: &mut Pinnacle, reason: &str| {
match &config_dir_clone { match &config_dir_clone {
Some(dir) => warn!("Unable to load config at {}: {reason}", dir.display()), Some(dir) => warn!("Unable to load config at {}: {reason}", dir.display()),
None => panic!( None => panic!(
@ -300,11 +301,11 @@ impl State {
} }
info!("Falling back to builtin Rust config"); info!("Falling back to builtin Rust config");
state.start_config(None::<PathBuf>) pinnacle.start_config(None::<PathBuf>)
}; };
// If `--no-config` was set, still load the keybinds from the default metaconfig // If `--no-config` was set, still load the keybinds from the default metaconfig
if self.pinnacle.config.no_config { if self.config.no_config {
config_dir = None; config_dir = None;
} }
@ -328,17 +329,17 @@ impl State {
let reload_keybind = (reload_mask, Keysym::from(reload_keybind.key as u32)); let reload_keybind = (reload_mask, Keysym::from(reload_keybind.key as u32));
let kill_keybind = (kill_mask, Keysym::from(kill_keybind.key as u32)); let kill_keybind = (kill_mask, Keysym::from(kill_keybind.key as u32));
self.pinnacle.input_state.reload_keybind = Some(reload_keybind); self.input_state.reload_keybind = Some(reload_keybind);
self.pinnacle.input_state.kill_keybind = Some(kill_keybind); self.input_state.kill_keybind = Some(kill_keybind);
if self.pinnacle.config.no_config { if self.config.no_config {
info!("`--no-config` was set, not spawning config"); info!("`--no-config` was set, not spawning config");
return Ok(()); return Ok(());
} }
// Because the grpc server is implemented to only start once, // Because the grpc server is implemented to only start once,
// any updates to `socket_dir` won't be applied until restart. // any updates to `socket_dir` won't be applied until restart.
if self.pinnacle.grpc_server_join_handle.is_none() { if self.grpc_server_join_handle.is_none() {
// If a socket is provided in the metaconfig, use it. // If a socket is provided in the metaconfig, use it.
let socket_dir = if let Some(socket_dir) = &metaconfig.socket_dir { let socket_dir = if let Some(socket_dir) = &metaconfig.socket_dir {
let Some(config_dir) = &config_dir else { let Some(config_dir) = &config_dir else {
@ -356,8 +357,7 @@ impl State {
socket_dir socket_dir
} else { } else {
// Otherwise, use $XDG_RUNTIME_DIR. If that doesn't exist, use /tmp. // Otherwise, use $XDG_RUNTIME_DIR. If that doesn't exist, use /tmp.
self.pinnacle self.xdg_base_dirs
.xdg_base_dirs
.get_runtime_directory() .get_runtime_directory()
.cloned() .cloned()
.unwrap_or(PathBuf::from(DEFAULT_SOCKET_DIR)) .unwrap_or(PathBuf::from(DEFAULT_SOCKET_DIR))
@ -449,32 +449,31 @@ impl State {
let (pinger, ping_source) = calloop::ping::make_ping()?; let (pinger, ping_source) = calloop::ping::make_ping()?;
let token = let token = self
self.pinnacle .loop_handle
.loop_handle .insert_source(ping_source, move |_, _, state| {
.insert_source(ping_source, move |_, _, state| { error!("Config crashed! Falling back to default config");
error!("Config crashed! Falling back to default config"); state
state .pinnacle
.start_config(None::<PathBuf>) .start_config(None::<PathBuf>)
.expect("failed to start default config"); .expect("failed to start default config");
})?; })?;
self.pinnacle.config.config_join_handle = Some(tokio::spawn(async move { self.config.config_join_handle = Some(tokio::spawn(async move {
let _ = child.wait().await; let _ = child.wait().await;
pinger.ping(); pinger.ping();
})); }));
self.pinnacle.config.config_reload_on_crash_token = Some(token); self.config.config_reload_on_crash_token = Some(token);
} }
None => { None => {
let (pinger, ping_source) = calloop::ping::make_ping()?; let (pinger, ping_source) = calloop::ping::make_ping()?;
let token = let token = self
self.pinnacle .loop_handle
.loop_handle .insert_source(ping_source, move |_, _, _state| {
.insert_source(ping_source, move |_, _, _state| { panic!("builtin rust config crashed; this is a bug");
panic!("builtin rust config crashed; this is a bug"); })?;
})?;
std::thread::spawn(move || { std::thread::spawn(move || {
info!("Starting builtin Rust config"); info!("Starting builtin Rust config");
@ -482,7 +481,7 @@ impl State {
pinger.ping(); pinger.ping();
}); });
self.pinnacle.config.config_reload_on_crash_token = Some(token); self.config.config_reload_on_crash_token = Some(token);
} }
} }
@ -490,12 +489,10 @@ impl State {
} }
pub fn start_grpc_server(&mut self, socket_dir: &Path) -> anyhow::Result<()> { pub fn start_grpc_server(&mut self, socket_dir: &Path) -> anyhow::Result<()> {
self.pinnacle self.system_processes
.system_processes
.refresh_processes_specifics(ProcessRefreshKind::new()); .refresh_processes_specifics(ProcessRefreshKind::new());
let multiple_instances = self let multiple_instances = self
.pinnacle
.system_processes .system_processes
.processes_by_exact_name("pinnacle") .processes_by_exact_name("pinnacle")
.filter(|proc| proc.thread_kind().is_none()) .filter(|proc| proc.thread_kind().is_none())
@ -544,14 +541,13 @@ impl State {
std::env::set_var( std::env::set_var(
"PINNACLE_PROTO_DIR", "PINNACLE_PROTO_DIR",
self.pinnacle.xdg_base_dirs.get_data_file("protobuf"), self.xdg_base_dirs.get_data_file("protobuf"),
); );
let (grpc_sender, grpc_receiver) = let (grpc_sender, grpc_receiver) =
calloop::channel::channel::<Box<dyn FnOnce(&mut Self) + Send>>(); calloop::channel::channel::<Box<dyn FnOnce(&mut State) + Send>>();
self.pinnacle self.loop_handle
.loop_handle
.insert_source(grpc_receiver, |msg, _, state| match msg { .insert_source(grpc_receiver, |msg, _, state| match msg {
Event::Msg(f) => f(state), Event::Msg(f) => f(state),
Event::Closed => error!("grpc receiver was closed"), Event::Closed => error!("grpc receiver was closed"),
@ -589,9 +585,9 @@ impl State {
.add_service(LayoutServiceServer::new(layout_service)) .add_service(LayoutServiceServer::new(layout_service))
.add_service(RenderServiceServer::new(render_service)); .add_service(RenderServiceServer::new(render_service));
match self.pinnacle.xdisplay.as_ref() { match self.xdisplay.as_ref() {
Some(_) => { Some(_) => {
self.pinnacle.grpc_server_join_handle = Some(tokio::spawn(async move { self.grpc_server_join_handle = Some(tokio::spawn(async move {
if let Err(err) = grpc_server.serve_with_incoming(uds_stream).await { if let Err(err) = grpc_server.serve_with_incoming(uds_stream).await {
error!("gRPC server error: {err}"); error!("gRPC server error: {err}");
} }

View file

@ -4,7 +4,7 @@ use smithay::{output::Output, utils::SERIAL_COUNTER};
use tracing::warn; use tracing::warn;
use crate::{ use crate::{
state::{State, WithState}, state::{Pinnacle, State, WithState},
window::WindowElement, window::WindowElement,
}; };
@ -12,6 +12,31 @@ pub mod keyboard;
pub mod pointer; pub mod pointer;
impl State { impl State {
/// Update the keyboard focus.
pub fn update_focus(&mut self, output: &Output) {
let current_focus = self.pinnacle.focused_window(output);
if let Some(win) = &current_focus {
assert!(!win.is_x11_override_redirect());
if let Some(toplevel) = win.toplevel() {
toplevel.send_configure();
}
}
self.pinnacle
.seat
.get_keyboard()
.expect("no keyboard")
.set_focus(
self,
current_focus.map(|win| win.into()),
SERIAL_COUNTER.next_serial(),
);
}
}
impl Pinnacle {
/// Get the currently focused window on `output`. /// Get the currently focused window on `output`.
/// ///
/// This returns the topmost window on the keyboard focus stack that is on an active tag. /// This returns the topmost window on the keyboard focus stack that is on an active tag.
@ -35,32 +60,9 @@ impl State {
.flatten() .flatten()
} }
/// Update the keyboard focus.
pub fn update_focus(&mut self, output: &Output) {
let current_focus = self.focused_window(output);
if let Some(win) = &current_focus {
assert!(!win.is_x11_override_redirect());
if let Some(toplevel) = win.toplevel() {
toplevel.send_configure();
}
}
self.pinnacle
.seat
.get_keyboard()
.expect("no keyboard")
.set_focus(
self,
current_focus.map(|win| win.into()),
SERIAL_COUNTER.next_serial(),
);
}
pub fn fixup_z_layering(&mut self) { pub fn fixup_z_layering(&mut self) {
for win in self.pinnacle.z_index_stack.iter() { for win in self.z_index_stack.iter() {
self.pinnacle.space.raise_element(win, false); self.space.raise_element(win, false);
} }
} }
@ -68,26 +70,25 @@ impl State {
/// ///
/// This does nothing if the window is unmapped. /// This does nothing if the window is unmapped.
pub fn raise_window(&mut self, window: WindowElement, activate: bool) { pub fn raise_window(&mut self, window: WindowElement, activate: bool) {
if self.pinnacle.space.elements().all(|win| win != &window) { if self.space.elements().all(|win| win != &window) {
warn!("Tried to raise an unmapped window"); warn!("Tried to raise an unmapped window");
return; return;
} }
self.pinnacle.space.raise_element(&window, activate); self.space.raise_element(&window, activate);
self.pinnacle.z_index_stack.retain(|win| win != &window); self.z_index_stack.retain(|win| win != &window);
self.pinnacle.z_index_stack.push(window); self.z_index_stack.push(window);
self.fixup_xwayland_window_layering(); self.fixup_xwayland_window_layering();
} }
/// Get the currently focused output, or the first mapped output if there is none, or None. /// Get the currently focused output, or the first mapped output if there is none, or None.
pub fn focused_output(&self) -> Option<&Output> { pub fn focused_output(&self) -> Option<&Output> {
self.pinnacle self.output_focus_stack
.output_focus_stack
.stack .stack
.last() .last()
.or_else(|| self.pinnacle.space.outputs().next()) .or_else(|| self.space.outputs().next())
} }
} }

View file

@ -50,7 +50,7 @@ impl PointerGrab<State> for MoveSurfaceGrab {
return; return;
} }
state.raise_window(self.window.clone(), false); state.pinnacle.raise_window(self.window.clone(), false);
if let Some(surface) = self.window.x11_surface() { if let Some(surface) = self.window.x11_surface() {
// INFO: can you raise OR windows or no idk // INFO: can you raise OR windows or no idk
@ -119,7 +119,9 @@ impl PointerGrab<State> for MoveSurfaceGrab {
} }
debug!("Swapping window positions"); debug!("Swapping window positions");
state.swap_window_positions(&self.window, &window_under); state
.pinnacle
.swap_window_positions(&self.window, &window_under);
} }
} else { } else {
let delta = event.location - self.start_data.location; let delta = event.location - self.start_data.location;
@ -271,71 +273,68 @@ impl PointerGrab<State> for MoveSurfaceGrab {
} }
} }
/// The application initiated a move grab e.g. when you drag a titlebar. impl State {
pub fn move_request_client( /// The application initiated a move grab e.g. when you drag a titlebar.
state: &mut State, pub fn move_request_client(&mut self, surface: &WlSurface, seat: &Seat<State>, serial: Serial) {
surface: &WlSurface, let pointer = seat.get_pointer().expect("seat had no pointer");
seat: &Seat<State>, if let Some(start_data) = crate::grab::pointer_grab_start_data(&pointer, surface, serial) {
serial: Serial, let Some(window) = self.pinnacle.window_for_surface(surface) else {
) { warn!("Surface had no window, cancelling move request");
let pointer = seat.get_pointer().expect("seat had no pointer"); return;
if let Some(start_data) = crate::grab::pointer_grab_start_data(&pointer, surface, serial) { };
let Some(window) = state.window_for_surface(surface) else {
let initial_window_loc = self
.pinnacle
.space
.element_location(&window)
.expect("move request was called on an unmapped window");
let grab = MoveSurfaceGrab {
start_data,
window,
initial_window_loc,
};
pointer.set_grab(self, grab, serial, Focus::Clear);
} else {
debug!("No grab start data for grab, cancelling");
}
}
/// The compositor initiated a move grab e.g. you hold the mod key and drag.
pub fn move_request_server(
&mut self,
surface: &WlSurface,
seat: &Seat<State>,
serial: Serial,
button_used: u32,
) {
let pointer = seat.get_pointer().expect("seat had no pointer");
let Some(window) = self.pinnacle.window_for_surface(surface) else {
warn!("Surface had no window, cancelling move request"); warn!("Surface had no window, cancelling move request");
return; return;
}; };
let initial_window_loc = state let initial_window_loc = self
.pinnacle .pinnacle
.space .space
.element_location(&window) .element_location(&window)
.expect("move request was called on an unmapped window"); .expect("move request was called on an unmapped window");
let start_data = smithay::input::pointer::GrabStartData {
focus: pointer
.current_focus()
.map(|focus| (focus, initial_window_loc)),
button: button_used,
location: pointer.current_location(),
};
let grab = MoveSurfaceGrab { let grab = MoveSurfaceGrab {
start_data, start_data,
window, window,
initial_window_loc, initial_window_loc,
}; };
pointer.set_grab(state, grab, serial, Focus::Clear); pointer.set_grab(self, grab, serial, Focus::Clear);
} else {
debug!("No grab start data for grab, cancelling");
} }
} }
/// The compositor initiated a move grab e.g. you hold the mod key and drag.
pub fn move_request_server(
state: &mut State,
surface: &WlSurface,
seat: &Seat<State>,
serial: Serial,
button_used: u32,
) {
let pointer = seat.get_pointer().expect("seat had no pointer");
let Some(window) = state.window_for_surface(surface) else {
warn!("Surface had no window, cancelling move request");
return;
};
let initial_window_loc = state
.pinnacle
.space
.element_location(&window)
.expect("move request was called on an unmapped window");
let start_data = smithay::input::pointer::GrabStartData {
focus: pointer
.current_focus()
.map(|focus| (focus, initial_window_loc)),
button: button_used,
location: pointer.current_location(),
};
let grab = MoveSurfaceGrab {
start_data,
window,
initial_window_loc,
};
pointer.set_grab(state, grab, serial, Focus::Clear);
}

View file

@ -21,7 +21,7 @@ use smithay::{
}; };
use crate::{ use crate::{
state::{State, WithState}, state::{Pinnacle, State, WithState},
window::{window_state::FloatingOrTiled, WindowElement}, window::{window_state::FloatingOrTiled, WindowElement},
}; };
@ -362,119 +362,171 @@ impl ResizeSurfaceState {
} }
} }
pub fn move_surface_if_resized(state: &mut State, surface: &WlSurface) { impl Pinnacle {
let Some(window) = state.window_for_surface(surface) else { pub fn move_surface_if_resized(&mut self, surface: &WlSurface) {
return; let Some(window) = self.window_for_surface(surface) else {
}; return;
};
let Some(mut window_loc) = state.pinnacle.space.element_location(&window) else { let Some(mut window_loc) = self.space.element_location(&window) else {
return; return;
}; };
let geometry = window.geometry(); let geometry = window.geometry();
let new_loc: Option<(Option<i32>, Option<i32>)> = surface.with_state_mut(|state| { let new_loc: Option<(Option<i32>, Option<i32>)> = surface.with_state_mut(|state| {
state state
.resize_state .resize_state
.on_commit() .on_commit()
.map(|(edges, initial_window_rect)| { .map(|(edges, initial_window_rect)| {
let mut new_x: Option<i32> = None; let mut new_x: Option<i32> = None;
let mut new_y: Option<i32> = None; let mut new_y: Option<i32> = None;
if let xdg_toplevel::ResizeEdge::Left if let xdg_toplevel::ResizeEdge::Left
| xdg_toplevel::ResizeEdge::TopLeft | xdg_toplevel::ResizeEdge::TopLeft
| xdg_toplevel::ResizeEdge::BottomLeft = edges.0 | xdg_toplevel::ResizeEdge::BottomLeft = edges.0
{ {
new_x = Some( new_x = Some(
initial_window_rect.loc.x + (initial_window_rect.size.w - geometry.size.w), initial_window_rect.loc.x
); + (initial_window_rect.size.w - geometry.size.w),
} );
if let xdg_toplevel::ResizeEdge::Top }
| xdg_toplevel::ResizeEdge::TopLeft if let xdg_toplevel::ResizeEdge::Top
| xdg_toplevel::ResizeEdge::TopRight = edges.0 | xdg_toplevel::ResizeEdge::TopLeft
{ | xdg_toplevel::ResizeEdge::TopRight = edges.0
new_y = Some( {
initial_window_rect.loc.y + (initial_window_rect.size.h - geometry.size.h), new_y = Some(
); initial_window_rect.loc.y
} + (initial_window_rect.size.h - geometry.size.h),
);
}
(new_x, new_y) (new_x, new_y)
}) })
}); });
if window.with_state(|state| state.floating_or_tiled.is_tiled()) { if window.with_state(|state| state.floating_or_tiled.is_tiled()) {
return; return;
}
let Some(new_loc) = new_loc else { return };
if let Some(new_x) = new_loc.0 {
window_loc.x = new_x;
}
if let Some(new_y) = new_loc.1 {
window_loc.y = new_y;
}
let size = state
.pinnacle
.space
.element_geometry(&window)
.expect("called element_geometry on unmapped window")
.size;
window.with_state_mut(|state| {
if state.floating_or_tiled.is_floating() {
state.floating_or_tiled =
FloatingOrTiled::Floating(Rectangle::from_loc_and_size(window_loc, size));
} }
});
if new_loc.0.is_some() || new_loc.1.is_some() { let Some(new_loc) = new_loc else { return };
state
.pinnacle if let Some(new_x) = new_loc.0 {
window_loc.x = new_x;
}
if let Some(new_y) = new_loc.1 {
window_loc.y = new_y;
}
let size = self
.space .space
.map_element(window.clone(), window_loc, false); .element_geometry(&window)
.expect("called element_geometry on unmapped window")
.size;
if let Some(surface) = window.x11_surface() { window.with_state_mut(|state| {
if !surface.is_override_redirect() { if state.floating_or_tiled.is_floating() {
let geo = surface.geometry(); state.floating_or_tiled =
let new_geo = Rectangle::from_loc_and_size(window_loc, geo.size); FloatingOrTiled::Floating(Rectangle::from_loc_and_size(window_loc, size));
surface }
.configure(new_geo) });
.expect("failed to configure x11 win");
if new_loc.0.is_some() || new_loc.1.is_some() {
self.space.map_element(window.clone(), window_loc, false);
if let Some(surface) = window.x11_surface() {
if !surface.is_override_redirect() {
let geo = surface.geometry();
let new_geo = Rectangle::from_loc_and_size(window_loc, geo.size);
surface
.configure(new_geo)
.expect("failed to configure x11 win");
}
} }
} }
} }
} }
/// The application requests a resize e.g. when you drag the edges of a window. impl State {
pub fn resize_request_client( /// The application requests a resize e.g. when you drag the edges of a window.
state: &mut State, pub fn resize_request_client(
surface: &WlSurface, &mut self,
seat: &Seat<State>, surface: &WlSurface,
serial: smithay::utils::Serial, seat: &Seat<State>,
edges: self::ResizeEdge, serial: smithay::utils::Serial,
button_used: u32, edges: self::ResizeEdge,
) { button_used: u32,
let pointer = seat.get_pointer().expect("seat had no pointer"); ) {
let pointer = seat.get_pointer().expect("seat had no pointer");
if let Some(start_data) = crate::grab::pointer_grab_start_data(&pointer, surface, serial) { if let Some(start_data) = crate::grab::pointer_grab_start_data(&pointer, surface, serial) {
let Some(window) = state.window_for_surface(surface) else { let Some(window) = self.pinnacle.window_for_surface(surface) else {
tracing::error!("Surface had no window, cancelling resize request");
return;
};
// TODO: check for fullscreen/maximized (probably shouldn't matter)
if window.with_state(|state| state.floating_or_tiled.is_tiled()) {
return;
}
let initial_window_loc = self
.pinnacle
.space
.element_location(&window)
.expect("resize request called on unmapped window");
let initial_window_size = window.geometry().size;
if let Some(window) = self.pinnacle.window_for_surface(surface) {
if let Some(toplevel) = window.toplevel() {
toplevel.with_pending_state(|state| {
state.states.set(xdg_toplevel::State::Resizing);
});
toplevel.send_pending_configure();
}
}
let grab = ResizeSurfaceGrab::start(
start_data,
window,
edges,
Rectangle::from_loc_and_size(initial_window_loc, initial_window_size),
button_used,
);
if let Some(grab) = grab {
pointer.set_grab(self, grab, serial, Focus::Clear);
}
}
}
/// The compositor requested a resize e.g. you hold the mod key and right-click drag.
pub fn resize_request_server(
&mut self,
surface: &WlSurface,
seat: &Seat<State>,
serial: smithay::utils::Serial,
edges: self::ResizeEdge,
button_used: u32,
) {
let pointer = seat.get_pointer().expect("seat had no pointer");
let Some(window) = self.pinnacle.window_for_surface(surface) else {
tracing::error!("Surface had no window, cancelling resize request"); tracing::error!("Surface had no window, cancelling resize request");
return; return;
}; };
// TODO: check for fullscreen/maximized (probably shouldn't matter)
if window.with_state(|state| state.floating_or_tiled.is_tiled()) { if window.with_state(|state| state.floating_or_tiled.is_tiled()) {
return; return;
} }
let initial_window_loc = state let initial_window_loc = self
.pinnacle .pinnacle
.space .space
.element_location(&window) .element_location(&window)
.expect("resize request called on unmapped window"); .expect("resize request called on unmapped window");
let initial_window_size = window.geometry().size; let initial_window_size = window.geometry().size;
if let Some(window) = state.window_for_surface(surface) { if let Some(window) = self.pinnacle.window_for_surface(surface) {
if let Some(toplevel) = window.toplevel() { if let Some(toplevel) = window.toplevel() {
toplevel.with_pending_state(|state| { toplevel.with_pending_state(|state| {
state.states.set(xdg_toplevel::State::Resizing); state.states.set(xdg_toplevel::State::Resizing);
@ -484,6 +536,14 @@ pub fn resize_request_client(
} }
} }
let start_data = smithay::input::pointer::GrabStartData {
focus: pointer
.current_focus()
.map(|focus| (focus, initial_window_loc)),
button: button_used,
location: pointer.current_location(),
};
let grab = ResizeSurfaceGrab::start( let grab = ResizeSurfaceGrab::start(
start_data, start_data,
window, window,
@ -493,65 +553,7 @@ pub fn resize_request_client(
); );
if let Some(grab) = grab { if let Some(grab) = grab {
pointer.set_grab(state, grab, serial, Focus::Clear); pointer.set_grab(self, grab, serial, Focus::Clear);
} }
} }
} }
/// The compositor requested a resize e.g. you hold the mod key and right-click drag.
pub fn resize_request_server(
state: &mut State,
surface: &WlSurface,
seat: &Seat<State>,
serial: smithay::utils::Serial,
edges: self::ResizeEdge,
button_used: u32,
) {
let pointer = seat.get_pointer().expect("seat had no pointer");
let Some(window) = state.window_for_surface(surface) else {
tracing::error!("Surface had no window, cancelling resize request");
return;
};
if window.with_state(|state| state.floating_or_tiled.is_tiled()) {
return;
}
let initial_window_loc = state
.pinnacle
.space
.element_location(&window)
.expect("resize request called on unmapped window");
let initial_window_size = window.geometry().size;
if let Some(window) = state.window_for_surface(surface) {
if let Some(toplevel) = window.toplevel() {
toplevel.with_pending_state(|state| {
state.states.set(xdg_toplevel::State::Resizing);
});
toplevel.send_pending_configure();
}
}
let start_data = smithay::input::pointer::GrabStartData {
focus: pointer
.current_focus()
.map(|focus| (focus, initial_window_loc)),
button: button_used,
location: pointer.current_location(),
};
let grab = ResizeSurfaceGrab::start(
start_data,
window,
edges,
Rectangle::from_loc_and_size(initial_window_loc, initial_window_size),
button_used,
);
if let Some(grab) = grab {
pointer.set_grab(state, grab, serial, Focus::Clear);
}
}

View file

@ -67,7 +67,7 @@ use crate::{
gamma_control::{GammaControlHandler, GammaControlManagerState}, gamma_control::{GammaControlHandler, GammaControlManagerState},
screencopy::{Screencopy, ScreencopyHandler}, screencopy::{Screencopy, ScreencopyHandler},
}, },
state::{ClientState, State, WithState}, state::{ClientState, Pinnacle, State, WithState},
}; };
impl BufferHandler for State { impl BufferHandler for State {
@ -130,7 +130,7 @@ impl CompositorHandler for State {
} }
if !compositor::is_sync_subsurface(surface) { if !compositor::is_sync_subsurface(surface) {
if let Some(window) = self.window_for_surface(&root) { if let Some(window) = self.pinnacle.window_for_surface(&root) {
window.on_commit(); window.on_commit();
if let Some(loc) = window.with_state_mut(|state| state.target_loc.take()) { if let Some(loc) = window.with_state_mut(|state| state.target_loc.take()) {
self.pinnacle.space.map_element(window.clone(), loc, false); self.pinnacle.space.map_element(window.clone(), loc, false);
@ -157,7 +157,7 @@ impl CompositorHandler for State {
self.pinnacle.new_windows.retain(|win| win != &new_window); self.pinnacle.new_windows.retain(|win| win != &new_window);
self.pinnacle.windows.push(new_window.clone()); self.pinnacle.windows.push(new_window.clone());
if let Some(output) = self.focused_output() { if let Some(output) = self.pinnacle.focused_output() {
tracing::debug!("Placing toplevel"); tracing::debug!("Placing toplevel");
new_window.place_on_output(output); new_window.place_on_output(output);
output.with_state_mut(|state| state.focus_stack.set_focus(new_window.clone())); output.with_state_mut(|state| state.focus_stack.set_focus(new_window.clone()));
@ -170,12 +170,12 @@ impl CompositorHandler for State {
.space .space
.map_element(new_window.clone(), (1000000, 0), true); .map_element(new_window.clone(), (1000000, 0), true);
self.raise_window(new_window.clone(), true); self.pinnacle.raise_window(new_window.clone(), true);
self.apply_window_rules(&new_window); self.pinnacle.apply_window_rules(&new_window);
if let Some(focused_output) = self.focused_output().cloned() { if let Some(focused_output) = self.pinnacle.focused_output().cloned() {
self.request_layout(&focused_output); self.pinnacle.request_layout(&focused_output);
new_window.send_frame( new_window.send_frame(
&focused_output, &focused_output,
self.pinnacle.clock.now(), self.pinnacle.clock.now(),
@ -198,28 +198,28 @@ impl CompositorHandler for State {
}); });
} else if new_window.toplevel().is_some() { } else if new_window.toplevel().is_some() {
new_window.on_commit(); new_window.on_commit();
ensure_initial_configure(surface, self); self.pinnacle.ensure_initial_configure(surface);
} }
return; return;
} }
ensure_initial_configure(surface, self); self.pinnacle.ensure_initial_configure(surface);
crate::grab::resize_grab::move_surface_if_resized(self, surface); self.pinnacle.move_surface_if_resized(surface);
let outputs = if let Some(window) = self.window_for_surface(surface) { let outputs = if let Some(window) = self.pinnacle.window_for_surface(surface) {
let mut outputs = self.pinnacle.space.outputs_for_element(&window); let mut outputs = self.pinnacle.space.outputs_for_element(&window);
// When the window hasn't been mapped `outputs` is empty, // When the window hasn't been mapped `outputs` is empty,
// so also trigger a render using the window's tags' output // so also trigger a render using the window's tags' output
if let Some(output) = window.output(self) { if let Some(output) = window.output(&self.pinnacle) {
outputs.push(output); outputs.push(output);
} }
outputs // surface is a window outputs // surface is a window
} else if let Some(window) = self.window_for_surface(&root) { } else if let Some(window) = self.pinnacle.window_for_surface(&root) {
let mut outputs = self.pinnacle.space.outputs_for_element(&window); let mut outputs = self.pinnacle.space.outputs_for_element(&window);
if let Some(output) = window.output(self) { if let Some(output) = window.output(&self.pinnacle) {
outputs.push(output); outputs.push(output);
} }
outputs // surface is a root window outputs // surface is a root window
@ -270,73 +270,75 @@ impl CompositorHandler for State {
} }
delegate_compositor!(State); delegate_compositor!(State);
fn ensure_initial_configure(surface: &WlSurface, state: &mut State) { impl Pinnacle {
if let (Some(window), _) | (None, Some(window)) = ( fn ensure_initial_configure(&mut self, surface: &WlSurface) {
state.window_for_surface(surface), if let (Some(window), _) | (None, Some(window)) = (
state.new_window_for_surface(surface), self.window_for_surface(surface),
) { self.new_window_for_surface(surface),
if let Some(toplevel) = window.toplevel() { ) {
if let Some(toplevel) = window.toplevel() {
let initial_configure_sent = compositor::with_states(surface, |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
.lock()
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
.initial_configure_sent
});
if !initial_configure_sent {
tracing::debug!("Initial configure");
toplevel.send_configure();
}
}
return;
}
if let Some(popup) = self.popup_manager.find_popup(surface) {
let PopupKind::Xdg(popup) = &popup else { return };
let initial_configure_sent = compositor::with_states(surface, |states| { let initial_configure_sent = compositor::with_states(surface, |states| {
states states
.data_map .data_map
.get::<XdgToplevelSurfaceData>() .get::<XdgPopupSurfaceData>()
.expect("XdgToplevelSurfaceData wasn't in surface's data map") .expect("XdgPopupSurfaceData wasn't in popup's data map")
.lock() .lock()
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>") .expect("Failed to lock Mutex<XdgPopupSurfaceData>")
.initial_configure_sent
});
if !initial_configure_sent {
popup
.send_configure()
.expect("popup initial configure failed");
}
return;
}
if let Some(output) = self.space.outputs().find(|op| {
let map = layer_map_for_output(op);
map.layer_for_surface(surface, WindowSurfaceType::TOPLEVEL)
.is_some()
}) {
layer_map_for_output(output).arrange();
let initial_configure_sent = compositor::with_states(surface, |states| {
states
.data_map
.get::<LayerSurfaceData>()
.expect("no LayerSurfaceData")
.lock()
.expect("failed to lock data")
.initial_configure_sent .initial_configure_sent
}); });
if !initial_configure_sent { if !initial_configure_sent {
tracing::debug!("Initial configure"); layer_map_for_output(output)
toplevel.send_configure(); .layer_for_surface(surface, WindowSurfaceType::TOPLEVEL)
.expect("no layer for surface")
.layer_surface()
.send_configure();
} }
} }
return;
}
if let Some(popup) = state.pinnacle.popup_manager.find_popup(surface) {
let PopupKind::Xdg(popup) = &popup else { return };
let initial_configure_sent = compositor::with_states(surface, |states| {
states
.data_map
.get::<XdgPopupSurfaceData>()
.expect("XdgPopupSurfaceData wasn't in popup's data map")
.lock()
.expect("Failed to lock Mutex<XdgPopupSurfaceData>")
.initial_configure_sent
});
if !initial_configure_sent {
popup
.send_configure()
.expect("popup initial configure failed");
}
return;
}
if let Some(output) = state.pinnacle.space.outputs().find(|op| {
let map = layer_map_for_output(op);
map.layer_for_surface(surface, WindowSurfaceType::TOPLEVEL)
.is_some()
}) {
layer_map_for_output(output).arrange();
let initial_configure_sent = compositor::with_states(surface, |states| {
states
.data_map
.get::<LayerSurfaceData>()
.expect("no LayerSurfaceData")
.lock()
.expect("failed to lock data")
.initial_configure_sent
});
if !initial_configure_sent {
layer_map_for_output(output)
.layer_for_surface(surface, WindowSurfaceType::TOPLEVEL)
.expect("no layer for surface")
.layer_surface()
.send_configure();
}
} }
} }
@ -477,7 +479,7 @@ impl FractionalScaleHandler for State {
compositor::with_states(&root, |states| { compositor::with_states(&root, |states| {
desktop::utils::surface_primary_scanout_output(&root, states) desktop::utils::surface_primary_scanout_output(&root, states)
.or_else(|| { .or_else(|| {
self.window_for_surface(&root).and_then(|window| { self.pinnacle.window_for_surface(&root).and_then(|window| {
self.pinnacle self.pinnacle
.space .space
.outputs_for_element(&window) .outputs_for_element(&window)
@ -487,7 +489,7 @@ impl FractionalScaleHandler for State {
}) })
}) })
} else { } else {
self.window_for_surface(&root).and_then(|window| { self.pinnacle.window_for_surface(&root).and_then(|window| {
self.pinnacle self.pinnacle
.space .space
.outputs_for_element(&window) .outputs_for_element(&window)
@ -542,7 +544,7 @@ impl WlrLayerShellHandler for State {
} }
self.pinnacle.loop_handle.insert_idle(move |state| { self.pinnacle.loop_handle.insert_idle(move |state| {
state.request_layout(&output); state.pinnacle.request_layout(&output);
}); });
} }
@ -562,14 +564,14 @@ impl WlrLayerShellHandler for State {
if let Some(output) = output { if let Some(output) = output {
self.pinnacle.loop_handle.insert_idle(move |state| { self.pinnacle.loop_handle.insert_idle(move |state| {
state.request_layout(&output); state.pinnacle.request_layout(&output);
}); });
} }
} }
fn new_popup(&mut self, _parent: wlr_layer::LayerSurface, popup: PopupSurface) { fn new_popup(&mut self, _parent: wlr_layer::LayerSurface, popup: PopupSurface) {
trace!("WlrLayerShellHandler::new_popup"); trace!("WlrLayerShellHandler::new_popup");
self.position_popup(&popup); self.pinnacle.position_popup(&popup);
} }
} }
delegate_layer_shell!(State); delegate_layer_shell!(State);
@ -636,7 +638,7 @@ impl GammaControlHandler for State {
} }
delegate_gamma_control!(State); delegate_gamma_control!(State);
impl State { impl Pinnacle {
fn position_popup(&self, popup: &PopupSurface) { fn position_popup(&self, popup: &PopupSurface) {
trace!("State::position_popup"); trace!("State::position_popup");
let Ok(root) = find_popup_root_surface(&PopupKind::Xdg(popup.clone())) else { let Ok(root) = find_popup_root_surface(&PopupKind::Xdg(popup.clone())) else {
@ -656,13 +658,13 @@ impl State {
} }
let (root_global_loc, output) = if let Some(win) = self.window_for_surface(&root) { let (root_global_loc, output) = if let Some(win) = self.window_for_surface(&root) {
let win_geo = self.pinnacle.space.element_geometry(&win)?; let win_geo = self.space.element_geometry(&win)?;
(win_geo.loc, self.focused_output()?.clone()) (win_geo.loc, self.focused_output()?.clone())
} else { } else {
self.pinnacle.space.outputs().find_map(|op| { self.space.outputs().find_map(|op| {
let layer_map = layer_map_for_output(op); let layer_map = layer_map_for_output(op);
let layer = layer_map.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)?; let layer = layer_map.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)?;
let output_loc = self.pinnacle.space.output_geometry(op)?.loc; let output_loc = self.space.output_geometry(op)?.loc;
Some(( Some((
layer_map.layer_geometry(layer)?.loc + output_loc, layer_map.layer_geometry(layer)?.loc + output_loc,
op.clone(), op.clone(),
@ -676,7 +678,7 @@ impl State {
root_global_loc + get_popup_toplevel_coords(&PopupKind::Xdg(popup.clone())) root_global_loc + get_popup_toplevel_coords(&PopupKind::Xdg(popup.clone()))
}; };
let mut output_geo = self.pinnacle.space.output_geometry(&output)?; let mut output_geo = self.space.output_geometry(&output)?;
// Make local to parent // Make local to parent
output_geo.loc -= parent_global_loc; output_geo.loc -= parent_global_loc;

View file

@ -70,19 +70,20 @@ impl XdgShellHandler for State {
}); });
} }
let Some(window) = self.window_for_surface(surface.wl_surface()) else { let Some(window) = self.pinnacle.window_for_surface(surface.wl_surface()) else {
return; return;
}; };
if let Some(output) = window.output(self) { if let Some(output) = window.output(&self.pinnacle) {
self.request_layout(&output); self.pinnacle.request_layout(&output);
let focus = self let focus = self
.pinnacle
.focused_window(&output) .focused_window(&output)
.map(KeyboardFocusTarget::Window); .map(KeyboardFocusTarget::Window);
if let Some(KeyboardFocusTarget::Window(window)) = &focus { if let Some(KeyboardFocusTarget::Window(window)) = &focus {
tracing::debug!("Focusing on prev win"); tracing::debug!("Focusing on prev win");
// TODO: // TODO:
self.raise_window(window.clone(), true); self.pinnacle.raise_window(window.clone(), true);
if let Some(toplevel) = window.toplevel() { if let Some(toplevel) = window.toplevel() {
toplevel.send_configure(); toplevel.send_configure();
} }
@ -100,7 +101,7 @@ impl XdgShellHandler for State {
fn new_popup(&mut self, surface: PopupSurface, _positioner: PositionerState) { fn new_popup(&mut self, surface: PopupSurface, _positioner: PositionerState) {
trace!("XdgShellHandler::new_popup"); trace!("XdgShellHandler::new_popup");
self.position_popup(&surface); self.pinnacle.position_popup(&surface);
if let Err(err) = self if let Err(err) = self
.pinnacle .pinnacle
@ -120,8 +121,7 @@ impl XdgShellHandler for State {
fn move_request(&mut self, surface: ToplevelSurface, seat: WlSeat, serial: Serial) { fn move_request(&mut self, surface: ToplevelSurface, seat: WlSeat, serial: Serial) {
tracing::debug!("move_request_client"); tracing::debug!("move_request_client");
crate::grab::move_grab::move_request_client( self.move_request_client(
self,
surface.wl_surface(), surface.wl_surface(),
&Seat::from_resource(&seat).expect("couldn't get seat from WlSeat"), &Seat::from_resource(&seat).expect("couldn't get seat from WlSeat"),
serial, serial,
@ -136,8 +136,7 @@ impl XdgShellHandler for State {
edges: ResizeEdge, edges: ResizeEdge,
) { ) {
const BUTTON_LEFT: u32 = 0x110; const BUTTON_LEFT: u32 = 0x110;
crate::grab::resize_grab::resize_request_client( self.resize_request_client(
self,
surface.wl_surface(), surface.wl_surface(),
&Seat::from_resource(&seat).expect("couldn't get seat from WlSeat"), &Seat::from_resource(&seat).expect("couldn't get seat from WlSeat"),
serial, serial,
@ -158,7 +157,7 @@ impl XdgShellHandler for State {
state.geometry = positioner.get_geometry(); state.geometry = positioner.get_geometry();
state.positioner = positioner; state.positioner = positioner;
}); });
self.position_popup(&surface); self.pinnacle.position_popup(&surface);
surface.send_repositioned(token); surface.send_repositioned(token);
} }
@ -166,7 +165,8 @@ impl XdgShellHandler for State {
let seat: Seat<Self> = Seat::from_resource(&seat).expect("couldn't get seat from WlSeat"); let seat: Seat<Self> = Seat::from_resource(&seat).expect("couldn't get seat from WlSeat");
let popup_kind = PopupKind::Xdg(surface); let popup_kind = PopupKind::Xdg(surface);
if let Some(root) = find_popup_root_surface(&popup_kind).ok().and_then(|root| { if let Some(root) = find_popup_root_surface(&popup_kind).ok().and_then(|root| {
self.window_for_surface(&root) self.pinnacle
.window_for_surface(&root)
.map(KeyboardFocusTarget::Window) .map(KeyboardFocusTarget::Window)
.or_else(|| { .or_else(|| {
self.pinnacle.space.outputs().find_map(|op| { self.pinnacle.space.outputs().find_map(|op| {
@ -223,13 +223,15 @@ impl XdgShellHandler for State {
.as_ref() .as_ref()
.and_then(Output::from_resource) .and_then(Output::from_resource)
.or_else(|| { .or_else(|| {
self.window_for_surface(wl_surface).and_then(|window| { self.pinnacle
self.pinnacle .window_for_surface(wl_surface)
.space .and_then(|window| {
.outputs_for_element(&window) self.pinnacle
.first() .space
.cloned() .outputs_for_element(&window)
}) .first()
.cloned()
})
}); });
if let Some(output) = output { if let Some(output) = output {
@ -253,14 +255,14 @@ impl XdgShellHandler for State {
state.fullscreen_output = wl_output; state.fullscreen_output = wl_output;
}); });
let Some(window) = self.window_for_surface(wl_surface) else { let Some(window) = self.pinnacle.window_for_surface(wl_surface) else {
tracing::error!("wl_surface had no window"); tracing::error!("wl_surface had no window");
return; return;
}; };
if !window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) { if !window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
window.toggle_fullscreen(); window.toggle_fullscreen();
self.request_layout(&output); self.pinnacle.request_layout(&output);
} }
} }
@ -284,21 +286,21 @@ impl XdgShellHandler for State {
surface.send_pending_configure(); surface.send_pending_configure();
let Some(window) = self.window_for_surface(surface.wl_surface()) else { let Some(window) = self.pinnacle.window_for_surface(surface.wl_surface()) else {
tracing::error!("wl_surface had no window"); tracing::error!("wl_surface had no window");
return; return;
}; };
if window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) { if window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
window.toggle_fullscreen(); window.toggle_fullscreen();
if let Some(output) = window.output(self) { if let Some(output) = window.output(&self.pinnacle) {
self.request_layout(&output); self.pinnacle.request_layout(&output);
} }
} }
} }
fn maximize_request(&mut self, surface: ToplevelSurface) { fn maximize_request(&mut self, surface: ToplevelSurface) {
let Some(window) = self.window_for_surface(surface.wl_surface()) else { let Some(window) = self.pinnacle.window_for_surface(surface.wl_surface()) else {
return; return;
}; };
@ -306,12 +308,14 @@ impl XdgShellHandler for State {
window.toggle_maximized(); window.toggle_maximized();
} }
let Some(output) = window.output(self) else { return }; let Some(output) = window.output(&self.pinnacle) else {
self.request_layout(&output); return;
};
self.pinnacle.request_layout(&output);
} }
fn unmaximize_request(&mut self, surface: ToplevelSurface) { fn unmaximize_request(&mut self, surface: ToplevelSurface) {
let Some(window) = self.window_for_surface(surface.wl_surface()) else { let Some(window) = self.pinnacle.window_for_surface(surface.wl_surface()) else {
return; return;
}; };
@ -319,8 +323,10 @@ impl XdgShellHandler for State {
window.toggle_maximized(); window.toggle_maximized();
} }
let Some(output) = window.output(self) else { return }; let Some(output) = window.output(&self.pinnacle) else {
self.request_layout(&output); return;
};
self.pinnacle.request_layout(&output);
} }
fn minimize_request(&mut self, _surface: ToplevelSurface) { fn minimize_request(&mut self, _surface: ToplevelSurface) {

View file

@ -26,7 +26,7 @@ use tracing::{debug, error, trace, warn};
use crate::{ use crate::{
focus::keyboard::KeyboardFocusTarget, focus::keyboard::KeyboardFocusTarget,
state::{State, WithState}, state::{Pinnacle, State, WithState},
window::{window_state::FloatingOrTiled, WindowElement}, window::{window_state::FloatingOrTiled, WindowElement},
}; };
@ -58,12 +58,14 @@ impl XwmHandler for State {
.expect("called element_bbox on an unmapped window"); .expect("called element_bbox on an unmapped window");
let output_size = self let output_size = self
.pinnacle
.focused_output() .focused_output()
.and_then(|op| self.pinnacle.space.output_geometry(op)) .and_then(|op| self.pinnacle.space.output_geometry(op))
.map(|geo| geo.size) .map(|geo| geo.size)
.unwrap_or((2, 2).into()); .unwrap_or((2, 2).into());
let output_loc = self let output_loc = self
.pinnacle
.focused_output() .focused_output()
.map(|op| op.current_location()) .map(|op| op.current_location())
.unwrap_or((0, 0).into()); .unwrap_or((0, 0).into());
@ -92,7 +94,7 @@ impl XwmHandler for State {
.expect("failed to configure x11 window"); .expect("failed to configure x11 window");
// TODO: ssd // TODO: ssd
if let Some(output) = self.focused_output() { if let Some(output) = self.pinnacle.focused_output() {
window.place_on_output(output); window.place_on_output(output);
} }
@ -104,13 +106,13 @@ impl XwmHandler for State {
// TODO: will an unmap -> map duplicate the window // TODO: will an unmap -> map duplicate the window
self.pinnacle.windows.push(window.clone()); self.pinnacle.windows.push(window.clone());
self.raise_window(window.clone(), true); self.pinnacle.raise_window(window.clone(), true);
self.apply_window_rules(&window); self.pinnacle.apply_window_rules(&window);
if let Some(output) = window.output(self) { if let Some(output) = window.output(&self.pinnacle) {
output.with_state_mut(|state| state.focus_stack.set_focus(window.clone())); output.with_state_mut(|state| state.focus_stack.set_focus(window.clone()));
self.request_layout(&output); self.pinnacle.request_layout(&output);
} }
self.pinnacle.loop_handle.insert_idle(move |state| { self.pinnacle.loop_handle.insert_idle(move |state| {
@ -138,7 +140,7 @@ impl XwmHandler for State {
self.pinnacle.windows.push(window.clone()); self.pinnacle.windows.push(window.clone());
if let Some(output) = self.focused_output() { if let Some(output) = self.pinnacle.focused_output() {
window.place_on_output(output); window.place_on_output(output);
// FIXME: setting focus here may possibly muck things up // FIXME: setting focus here may possibly muck things up
// | or maybe they won't idk // | or maybe they won't idk
@ -146,15 +148,15 @@ impl XwmHandler for State {
} }
self.pinnacle.space.map_element(window.clone(), loc, true); self.pinnacle.space.map_element(window.clone(), loc, true);
self.raise_window(window.clone(), true); self.pinnacle.raise_window(window.clone(), true);
} }
fn map_window_notify(&mut self, _xwm: XwmId, window: X11Surface) { fn map_window_notify(&mut self, _xwm: XwmId, window: X11Surface) {
trace!("XwmHandler::map_window_notify"); trace!("XwmHandler::map_window_notify");
let Some(output) = window let Some(output) = window
.wl_surface() .wl_surface()
.and_then(|s| self.window_for_surface(&s)) .and_then(|s| self.pinnacle.window_for_surface(&s))
.and_then(|win| win.output(self)) .and_then(|win| win.output(&self.pinnacle))
else { else {
return; return;
}; };
@ -189,15 +191,16 @@ impl XwmHandler for State {
self.pinnacle.space.unmap_elem(&win); self.pinnacle.space.unmap_elem(&win);
if let Some(output) = win.output(self) { if let Some(output) = win.output(&self.pinnacle) {
self.request_layout(&output); self.pinnacle.request_layout(&output);
let focus = self let focus = self
.pinnacle
.focused_window(&output) .focused_window(&output)
.map(KeyboardFocusTarget::Window); .map(KeyboardFocusTarget::Window);
if let Some(KeyboardFocusTarget::Window(win)) = &focus { if let Some(KeyboardFocusTarget::Window(win)) = &focus {
self.raise_window(win.clone(), true); self.pinnacle.raise_window(win.clone(), true);
if let Some(toplevel) = win.toplevel() { if let Some(toplevel) = win.toplevel() {
toplevel.send_configure(); toplevel.send_configure();
} }
@ -255,15 +258,16 @@ impl XwmHandler for State {
.z_index_stack .z_index_stack
.retain(|elem| win.wl_surface() != elem.wl_surface()); .retain(|elem| win.wl_surface() != elem.wl_surface());
if let Some(output) = win.output(self) { if let Some(output) = win.output(&self.pinnacle) {
self.request_layout(&output); self.pinnacle.request_layout(&output);
let focus = self let focus = self
.pinnacle
.focused_window(&output) .focused_window(&output)
.map(KeyboardFocusTarget::Window); .map(KeyboardFocusTarget::Window);
if let Some(KeyboardFocusTarget::Window(win)) = &focus { if let Some(KeyboardFocusTarget::Window(win)) = &focus {
self.raise_window(win.clone(), true); self.pinnacle.raise_window(win.clone(), true);
if let Some(toplevel) = win.toplevel() { if let Some(toplevel) = win.toplevel() {
toplevel.send_configure(); toplevel.send_configure();
} }
@ -355,7 +359,7 @@ impl XwmHandler for State {
let Some(window) = window let Some(window) = window
.wl_surface() .wl_surface()
.and_then(|surf| self.window_for_surface(&surf)) .and_then(|surf| self.pinnacle.window_for_surface(&surf))
else { else {
return; return;
}; };
@ -372,7 +376,7 @@ impl XwmHandler for State {
let Some(window) = window let Some(window) = window
.wl_surface() .wl_surface()
.and_then(|surf| self.window_for_surface(&surf)) .and_then(|surf| self.pinnacle.window_for_surface(&surf))
else { else {
return; return;
}; };
@ -389,15 +393,15 @@ impl XwmHandler for State {
let Some(window) = window let Some(window) = window
.wl_surface() .wl_surface()
.and_then(|surf| self.window_for_surface(&surf)) .and_then(|surf| self.pinnacle.window_for_surface(&surf))
else { else {
return; return;
}; };
if !window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) { if !window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
window.toggle_fullscreen(); window.toggle_fullscreen();
if let Some(output) = window.output(self) { if let Some(output) = window.output(&self.pinnacle) {
self.request_layout(&output); self.pinnacle.request_layout(&output);
} }
} }
} }
@ -409,15 +413,15 @@ impl XwmHandler for State {
let Some(window) = window let Some(window) = window
.wl_surface() .wl_surface()
.and_then(|surf| self.window_for_surface(&surf)) .and_then(|surf| self.pinnacle.window_for_surface(&surf))
else { else {
return; return;
}; };
if window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) { if window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
window.toggle_fullscreen(); window.toggle_fullscreen();
if let Some(output) = window.output(self) { if let Some(output) = window.output(&self.pinnacle) {
self.request_layout(&output); self.pinnacle.request_layout(&output);
} }
} }
} }
@ -434,8 +438,7 @@ impl XwmHandler for State {
// We use the server one and not the client because windows like Steam don't provide // We use the server one and not the client because windows like Steam don't provide
// GrabStartData, so we need to create it ourselves. // GrabStartData, so we need to create it ourselves.
crate::grab::resize_grab::resize_request_server( self.resize_request_server(
self,
&wl_surf, &wl_surf,
&seat, &seat,
SERIAL_COUNTER.next_serial(), SERIAL_COUNTER.next_serial(),
@ -450,13 +453,7 @@ impl XwmHandler for State {
// We use the server one and not the client because windows like Steam don't provide // We use the server one and not the client because windows like Steam don't provide
// GrabStartData, so we need to create it ourselves. // GrabStartData, so we need to create it ourselves.
crate::grab::move_grab::move_request_server( self.move_request_server(&wl_surf, &seat, SERIAL_COUNTER.next_serial(), button);
self,
&wl_surf,
&seat,
SERIAL_COUNTER.next_serial(),
button,
);
} }
fn allow_selection_access(&mut self, xwm: XwmId, _selection: SelectionTarget) -> bool { fn allow_selection_access(&mut self, xwm: XwmId, _selection: SelectionTarget) -> bool {
@ -542,14 +539,13 @@ impl XwmHandler for State {
} }
} }
impl State { impl Pinnacle {
pub fn fixup_xwayland_window_layering(&mut self) { pub fn fixup_xwayland_window_layering(&mut self) {
let Some(xwm) = self.pinnacle.xwm.as_mut() else { let Some(xwm) = self.xwm.as_mut() else {
return; return;
}; };
let x11_wins = self let x11_wins = self
.pinnacle
.space .space
.elements() .elements()
.filter(|win| win.is_on_active_tag()) .filter(|win| win.is_on_active_tag())

View file

@ -452,11 +452,12 @@ impl State {
self.switch_vt(vt); self.switch_vt(vt);
} }
Some(KeyAction::Quit) => { Some(KeyAction::Quit) => {
self.shutdown(); self.pinnacle.shutdown();
} }
Some(KeyAction::ReloadConfig) => { Some(KeyAction::ReloadConfig) => {
info!("Reloading config"); info!("Reloading config");
self.start_config(Some(self.pinnacle.config.dir(&self.pinnacle.xdg_base_dirs))) self.pinnacle
.start_config(Some(self.pinnacle.config.dir(&self.pinnacle.xdg_base_dirs)))
.expect("failed to restart config"); .expect("failed to restart config");
} }
None => (), None => (),
@ -511,8 +512,8 @@ impl State {
// TODO: use update_keyboard_focus from anvil // TODO: use update_keyboard_focus from anvil
if let Some(window) = focus.window_for(self) { if let Some(window) = focus.window_for(self) {
self.raise_window(window.clone(), true); self.pinnacle.raise_window(window.clone(), true);
if let Some(output) = window.output(self) { if let Some(output) = window.output(&self.pinnacle) {
output.with_state_mut(|state| state.focus_stack.set_focus(window.clone())); output.with_state_mut(|state| state.focus_stack.set_focus(window.clone()));
} }
} }
@ -531,7 +532,7 @@ impl State {
} }
} }
} else { } else {
if let Some(focused_op) = self.focused_output() { if let Some(focused_op) = self.pinnacle.focused_output() {
focused_op.with_state_mut(|state| { focused_op.with_state_mut(|state| {
state.focus_stack.unset_focus(); state.focus_stack.unset_focus();
for window in state.focus_stack.stack.iter() { for window in state.focus_stack.stack.iter() {
@ -728,7 +729,7 @@ impl State {
pointer.frame(self); pointer.frame(self);
if let Some(output) = self.focused_output().cloned() { if let Some(output) = self.pinnacle.focused_output().cloned() {
self.schedule_render(&output); self.schedule_render(&output);
} }
} }

View file

@ -1,15 +1,14 @@
use smithay::backend::{input::InputEvent, libinput::LibinputInputBackend}; use smithay::backend::{input::InputEvent, libinput::LibinputInputBackend};
use crate::state::State; use crate::state::Pinnacle;
impl State { impl Pinnacle {
/// Apply current libinput settings to new devices. /// Apply current libinput settings to new devices.
pub fn apply_libinput_settings(&mut self, event: &InputEvent<LibinputInputBackend>) { pub fn apply_libinput_settings(&mut self, event: &InputEvent<LibinputInputBackend>) {
let mut device = match event { let mut device = match event {
InputEvent::DeviceAdded { device } => device.clone(), InputEvent::DeviceAdded { device } => device.clone(),
InputEvent::DeviceRemoved { device } => { InputEvent::DeviceRemoved { device } => {
self.pinnacle self.input_state
.input_state
.libinput_devices .libinput_devices
.retain(|dev| dev != device); .retain(|dev| dev != device);
return; return;
@ -17,14 +16,14 @@ impl State {
_ => return, _ => return,
}; };
if self.pinnacle.input_state.libinput_devices.contains(&device) { if self.input_state.libinput_devices.contains(&device) {
return; return;
} }
for setting in self.pinnacle.input_state.libinput_settings.values() { for setting in self.input_state.libinput_settings.values() {
setting(&mut device); setting(&mut device);
} }
self.pinnacle.input_state.libinput_devices.push(device); self.input_state.libinput_devices.push(device);
} }
} }

View file

@ -18,14 +18,14 @@ use tracing::warn;
use crate::{ use crate::{
output::OutputName, output::OutputName,
state::{State, WithState}, state::{Pinnacle, State, WithState},
window::{ window::{
window_state::{FloatingOrTiled, FullscreenOrMaximized}, window_state::{FloatingOrTiled, FullscreenOrMaximized},
WindowElement, WindowElement,
}, },
}; };
impl State { impl Pinnacle {
fn update_windows_with_geometries( fn update_windows_with_geometries(
&mut self, &mut self,
output: &Output, output: &Output,
@ -33,8 +33,7 @@ impl State {
) { ) {
let windows_on_foc_tags = output.with_state(|state| { let windows_on_foc_tags = output.with_state(|state| {
let focused_tags = state.focused_tags().collect::<Vec<_>>(); let focused_tags = state.focused_tags().collect::<Vec<_>>();
self.pinnacle self.windows
.windows
.iter() .iter()
.filter(|win| !win.is_x11_override_redirect()) .filter(|win| !win.is_x11_override_redirect())
.filter(|win| { .filter(|win| {
@ -53,11 +52,7 @@ impl State {
}) })
.cloned(); .cloned();
let output_geo = self let output_geo = self.space.output_geometry(output).expect("no output geo");
.pinnacle
.space
.output_geometry(output)
.expect("no output geo");
let non_exclusive_geo = { let non_exclusive_geo = {
let map = layer_map_for_output(output); let map = layer_map_for_output(output);
@ -130,7 +125,7 @@ impl State {
WindowSurface::X11(_) => { WindowSurface::X11(_) => {
let loc = win.with_state_mut(|state| state.target_loc.take()); let loc = win.with_state_mut(|state| state.target_loc.take());
if let Some(loc) = loc { if let Some(loc) = loc {
self.pinnacle.space.map_element(win.clone(), loc, false); self.space.map_element(win.clone(), loc, false);
} }
} }
} }
@ -138,7 +133,7 @@ impl State {
} }
for (loc, window) in non_pending_wins { for (loc, window) in non_pending_wins {
self.pinnacle.space.map_element(window, loc, false); self.space.map_element(window, loc, false);
} }
// FIXME: // FIXME:
@ -146,12 +141,9 @@ impl State {
// Obviously this is a bad way to do this but its a bandaid solution // Obviously this is a bad way to do this but its a bandaid solution
// until decent transactional layout applications are implemented. // until decent transactional layout applications are implemented.
for (win, _serial) in pending_wins { for (win, _serial) in pending_wins {
win.send_frame( win.send_frame(output, self.clock.now(), Some(Duration::ZERO), |_, _| {
output, Some(output.clone())
self.pinnacle.clock.now(), });
Some(Duration::ZERO),
|_, _| Some(output.clone()),
);
} }
self.fixup_z_layering(); self.fixup_z_layering();
@ -159,15 +151,15 @@ impl State {
/// Swaps two windows in the main window vec and updates all windows. /// Swaps two windows in the main window vec and updates all windows.
pub fn swap_window_positions(&mut self, win1: &WindowElement, win2: &WindowElement) { pub fn swap_window_positions(&mut self, win1: &WindowElement, win2: &WindowElement) {
let win1_index = self.pinnacle.windows.iter().position(|win| win == win1); let win1_index = self.windows.iter().position(|win| win == win1);
let win2_index = self.pinnacle.windows.iter().position(|win| win == win2); let win2_index = self.windows.iter().position(|win| win == win2);
if let (Some(first), Some(second)) = (win1_index, win2_index) { if let (Some(first), Some(second)) = (win1_index, win2_index) {
self.pinnacle.windows.swap(first, second); self.windows.swap(first, second);
if let Some(output) = win1.output(self) { if let Some(output) = win1.output(self) {
self.request_layout(&output); self.request_layout(&output);
} }
self.pinnacle.layout_state.pending_swap = true; self.layout_state.pending_swap = true;
} }
} }
} }
@ -185,17 +177,16 @@ pub struct LayoutState {
old_requests: HashMap<Output, HashSet<LayoutRequestId>>, old_requests: HashMap<Output, HashSet<LayoutRequestId>>,
} }
impl State { impl Pinnacle {
pub fn request_layout(&mut self, output: &Output) { pub fn request_layout(&mut self, output: &Output) {
let Some(sender) = self.pinnacle.layout_state.layout_request_sender.as_ref() else { let Some(sender) = self.layout_state.layout_request_sender.as_ref() else {
warn!("Layout requested but no client has connected to the layout service"); warn!("Layout requested but no client has connected to the layout service");
return; return;
}; };
let windows_on_foc_tags = output.with_state(|state| { let windows_on_foc_tags = output.with_state(|state| {
let focused_tags = state.focused_tags().collect::<Vec<_>>(); let focused_tags = state.focused_tags().collect::<Vec<_>>();
self.pinnacle self.windows
.windows
.iter() .iter()
.filter(|win| !win.is_x11_override_redirect()) .filter(|win| !win.is_x11_override_redirect())
.filter(|win| { .filter(|win| {
@ -230,14 +221,12 @@ impl State {
output.with_state(|state| state.focused_tags().map(|tag| tag.id().0).collect()); output.with_state(|state| state.focused_tags().map(|tag| tag.id().0).collect());
let id = self let id = self
.pinnacle
.layout_state .layout_state
.id_maps .id_maps
.entry(output.clone()) .entry(output.clone())
.or_insert(LayoutRequestId(0)); .or_insert(LayoutRequestId(0));
self.pinnacle self.layout_state
.layout_state
.pending_requests .pending_requests
.entry(output.clone()) .entry(output.clone())
.or_default() .or_default()
@ -255,7 +244,9 @@ impl State {
*id = LayoutRequestId(id.0 + 1); *id = LayoutRequestId(id.0 + 1);
} }
}
impl State {
pub fn apply_layout(&mut self, geometries: Geometries) -> anyhow::Result<()> { pub fn apply_layout(&mut self, geometries: Geometries) -> anyhow::Result<()> {
let Geometries { let Geometries {
request_id: Some(request_id), request_id: Some(request_id),
@ -267,7 +258,7 @@ impl State {
}; };
let request_id = LayoutRequestId(request_id); let request_id = LayoutRequestId(request_id);
let Some(output) = OutputName(output_name).output(self) else { let Some(output) = OutputName(output_name).output(&self.pinnacle) else {
anyhow::bail!("Output was invalid"); anyhow::bail!("Output was invalid");
}; };
@ -321,7 +312,8 @@ impl State {
anyhow::bail!("Attempted to layout but one or more dimensions were null"); anyhow::bail!("Attempted to layout but one or more dimensions were null");
}; };
self.update_windows_with_geometries(&output, geometries); self.pinnacle
.update_windows_with_geometries(&output, geometries);
self.schedule_render(&output); self.schedule_render(&output);

View file

@ -131,7 +131,7 @@ async fn main() -> anyhow::Result<()> {
event_loop.run(None, &mut state, |state| { event_loop.run(None, &mut state, |state| {
state.update_pointer_focus(); state.update_pointer_focus();
state.fixup_z_layering(); state.pinnacle.fixup_z_layering();
state.pinnacle.space.refresh(); state.pinnacle.space.refresh();
state.pinnacle.popup_manager.cleanup(); state.pinnacle.popup_manager.cleanup();

View file

@ -13,7 +13,7 @@ use tracing::info;
use crate::{ use crate::{
focus::WindowKeyboardFocusStack, focus::WindowKeyboardFocusStack,
protocol::screencopy::Screencopy, protocol::screencopy::Screencopy,
state::{State, WithState}, state::{Pinnacle, WithState},
tag::Tag, tag::Tag,
}; };
@ -26,9 +26,8 @@ pub struct OutputName(pub String);
impl OutputName { impl OutputName {
/// Get the output with this name. /// Get the output with this name.
pub fn output(&self, state: &State) -> Option<Output> { pub fn output(&self, pinnacle: &Pinnacle) -> Option<Output> {
state pinnacle
.pinnacle
.space .space
.outputs() .outputs()
.find(|output| output.name() == self.0) .find(|output| output.name() == self.0)
@ -77,7 +76,7 @@ impl OutputState {
} }
} }
impl State { impl Pinnacle {
/// A wrapper around [`Output::change_current_state`] that additionally sends an output /// A wrapper around [`Output::change_current_state`] that additionally sends an output
/// geometry signal. /// geometry signal.
pub fn change_output_state( pub fn change_output_state(
@ -91,8 +90,8 @@ impl State {
output.change_current_state(mode, transform, scale, location); output.change_current_state(mode, transform, scale, location);
if let Some(location) = location { if let Some(location) = location {
info!(?location); info!(?location);
self.pinnacle.space.map_output(output, location); self.space.map_output(output, location);
self.pinnacle.signal_state.output_move.signal(|buf| { self.signal_state.output_move.signal(|buf| {
buf.push_back(OutputMoveResponse { buf.push_back(OutputMoveResponse {
output_name: Some(output.name()), output_name: Some(output.name()),
x: Some(location.x), x: Some(location.x),
@ -102,8 +101,8 @@ impl State {
} }
if mode.is_some() || transform.is_some() || scale.is_some() { if mode.is_some() || transform.is_some() || scale.is_some() {
layer_map_for_output(output).arrange(); layer_map_for_output(output).arrange();
self.pinnacle.signal_state.output_resize.signal(|buf| { self.signal_state.output_resize.signal(|buf| {
let geo = self.pinnacle.space.output_geometry(output); let geo = self.space.output_geometry(output);
buf.push_back(OutputResizeResponse { buf.push_back(OutputResizeResponse {
output_name: Some(output.name()), output_name: Some(output.name()),
logical_width: geo.map(|geo| geo.size.w as u32), logical_width: geo.map(|geo| geo.size.w as u32),

View file

@ -219,7 +219,7 @@ impl State {
std::env::set_var("DISPLAY", format!(":{display}")); std::env::set_var("DISPLAY", format!(":{display}"));
if let Err(err) = state.start_config(Some( if let Err(err) = state.pinnacle.start_config(Some(
state.pinnacle.config.dir(&state.pinnacle.xdg_base_dirs), state.pinnacle.config.dir(&state.pinnacle.xdg_base_dirs),
)) { )) {
panic!("failed to start config: {err}"); panic!("failed to start config: {err}");
@ -318,18 +318,20 @@ impl State {
Ok(state) Ok(state)
} }
}
impl Pinnacle {
/// Schedule `run` to run when `condition` returns true. /// Schedule `run` to run when `condition` returns true.
/// ///
/// This will continually reschedule `run` in the event loop if `condition` returns false. /// This will continually reschedule `run` in the event loop if `condition` returns false.
pub fn schedule<F1, F2>(&self, condition: F1, run: F2) pub fn schedule<F1, F2>(&self, condition: F1, run: F2)
where where
F1: Fn(&mut Self) -> bool + 'static, F1: Fn(&mut State) -> bool + 'static,
F2: FnOnce(&mut Self) + 'static, F2: FnOnce(&mut State) + 'static,
{ {
self.pinnacle.loop_handle.insert_idle(|state| { self.loop_handle.insert_idle(|state| {
if !condition(state) { if !condition(state) {
state.schedule(condition, run); state.pinnacle.schedule(condition, run);
} else { } else {
run(state); run(state);
} }
@ -338,11 +340,11 @@ impl State {
pub fn shutdown(&mut self) { pub fn shutdown(&mut self) {
info!("Shutting down Pinnacle"); info!("Shutting down Pinnacle");
self.pinnacle.loop_signal.stop(); self.loop_signal.stop();
if let Some(join_handle) = self.pinnacle.config.config_join_handle.take() { if let Some(join_handle) = self.config.config_join_handle.take() {
join_handle.abort(); join_handle.abort();
} }
if let Some(shutdown_sender) = self.pinnacle.config.shutdown_sender.take() { if let Some(shutdown_sender) = self.config.shutdown_sender.take() {
if let Err(err) = shutdown_sender.send(Ok(ShutdownWatchResponse {})) { if let Err(err) = shutdown_sender.send(Ok(ShutdownWatchResponse {})) {
warn!("Failed to send shutdown signal to config: {err}"); warn!("Failed to send shutdown signal to config: {err}");
} }

View file

@ -9,7 +9,7 @@ use std::{
use smithay::output::Output; use smithay::output::Output;
use crate::state::{State, WithState}; use crate::state::{Pinnacle, State, WithState};
static TAG_ID_COUNTER: AtomicU32 = AtomicU32::new(0); static TAG_ID_COUNTER: AtomicU32 = AtomicU32::new(0);
@ -24,9 +24,8 @@ impl TagId {
} }
/// Get the tag associated with this id. /// Get the tag associated with this id.
pub fn tag(&self, state: &State) -> Option<Tag> { pub fn tag(&self, pinnacle: &Pinnacle) -> Option<Tag> {
state pinnacle
.pinnacle
.space .space
.outputs() .outputs()
.flat_map(|op| op.with_state(|state| state.tags.clone())) .flat_map(|op| op.with_state(|state| state.tags.clone()))
@ -107,9 +106,8 @@ impl Tag {
/// Get the output this tag is on. /// Get the output this tag is on.
/// ///
/// RefCell Safety: This uses RefCells on every mapped output. /// RefCell Safety: This uses RefCells on every mapped output.
pub fn output(&self, state: &State) -> Option<Output> { pub fn output(&self, pinnacle: &Pinnacle) -> Option<Output> {
state pinnacle
.pinnacle
.space .space
.outputs() .outputs()
.find(|output| output.with_state(|state| state.tags.iter().any(|tg| tg == self))) .find(|output| output.with_state(|state| state.tags.iter().any(|tg| tg == self)))

View file

@ -12,7 +12,7 @@ use smithay::{
wayland::{compositor, seat::WaylandFocus, shell::xdg::XdgToplevelSurfaceData}, wayland::{compositor, seat::WaylandFocus, shell::xdg::XdgToplevelSurfaceData},
}; };
use crate::state::{State, WithState}; use crate::state::{Pinnacle, WithState};
use self::window_state::WindowElementState; use self::window_state::WindowElementState;
@ -103,8 +103,8 @@ impl WindowElement {
/// This method gets the first tag the window has and returns its output. /// This method gets the first tag the window has and returns its output.
/// ///
/// RefCell Safety: This method uses a [`RefCell`] on this window and every mapped output. /// RefCell Safety: This method uses a [`RefCell`] on this window and every mapped output.
pub fn output(&self, state: &State) -> Option<Output> { pub fn output(&self, pinnacle: &Pinnacle) -> Option<Output> {
self.with_state(|st| st.tags.first().and_then(|tag| tag.output(state))) self.with_state(|st| st.tags.first().and_then(|tag| tag.output(pinnacle)))
} }
/// Returns whether or not this window has an active tag. /// Returns whether or not this window has an active tag.
@ -209,16 +209,14 @@ impl WithState for WindowElement {
} }
} }
impl State { impl Pinnacle {
/// Returns the [Window] associated with a given [WlSurface]. /// Returns the [Window] associated with a given [WlSurface].
pub fn window_for_surface(&self, surface: &WlSurface) -> Option<WindowElement> { pub fn window_for_surface(&self, surface: &WlSurface) -> Option<WindowElement> {
self.pinnacle self.space
.space
.elements() .elements()
.find(|window| window.wl_surface().map(|s| s == *surface).unwrap_or(false)) .find(|window| window.wl_surface().map(|s| s == *surface).unwrap_or(false))
.or_else(|| { .or_else(|| {
self.pinnacle self.windows
.windows
.iter() .iter()
.find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface)) .find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface))
}) })
@ -229,8 +227,7 @@ impl State {
/// ///
/// Currently only used in `ensure_initial_configure` in [`handlers`][crate::handlers]. /// Currently only used in `ensure_initial_configure` in [`handlers`][crate::handlers].
pub fn new_window_for_surface(&self, surface: &WlSurface) -> Option<WindowElement> { pub fn new_window_for_surface(&self, surface: &WlSurface) -> Option<WindowElement> {
self.pinnacle self.new_windows
.new_windows
.iter() .iter()
.find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface)) .find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface))
.cloned() .cloned()

View file

@ -4,7 +4,7 @@ use smithay::{
}; };
use crate::{ use crate::{
state::{State, WithState}, state::{Pinnacle, WithState},
window::window_state, window::window_state,
}; };
@ -41,11 +41,16 @@ enum AllOrAny {
impl WindowRuleCondition { impl WindowRuleCondition {
/// RefCell Safety: This method uses RefCells on `window`. /// RefCell Safety: This method uses RefCells on `window`.
pub fn is_met(&self, state: &State, window: &WindowElement) -> bool { pub fn is_met(&self, pinnacle: &Pinnacle, window: &WindowElement) -> bool {
Self::is_met_inner(self, state, window, AllOrAny::All) Self::is_met_inner(self, pinnacle, window, AllOrAny::All)
} }
fn is_met_inner(&self, state: &State, window: &WindowElement, all_or_any: AllOrAny) -> bool { fn is_met_inner(
&self,
pinnacle: &Pinnacle,
window: &WindowElement,
all_or_any: AllOrAny,
) -> bool {
tracing::debug!("{self:#?}"); tracing::debug!("{self:#?}");
let WindowRuleCondition { let WindowRuleCondition {
@ -61,14 +66,14 @@ impl WindowRuleCondition {
let cond_any = if let Some(cond_any) = cond_any { let cond_any = if let Some(cond_any) = cond_any {
cond_any cond_any
.iter() .iter()
.any(|cond| Self::is_met_inner(cond, state, window, AllOrAny::Any)) .any(|cond| Self::is_met_inner(cond, pinnacle, window, AllOrAny::Any))
} else { } else {
true true
}; };
let cond_all = if let Some(cond_all) = cond_all { let cond_all = if let Some(cond_all) = cond_all {
cond_all cond_all
.iter() .iter()
.all(|cond| Self::is_met_inner(cond, state, window, AllOrAny::All)) .all(|cond| Self::is_met_inner(cond, pinnacle, window, AllOrAny::All))
} else { } else {
true true
}; };
@ -87,7 +92,7 @@ impl WindowRuleCondition {
true true
}; };
let tags = if let Some(tag_ids) = tag { let tags = if let Some(tag_ids) = tag {
let mut tags = tag_ids.iter().filter_map(|tag_id| tag_id.tag(state)); let mut tags = tag_ids.iter().filter_map(|tag_id| tag_id.tag(pinnacle));
tags.all(|tag| window.with_state(|state| state.tags.contains(&tag))) tags.all(|tag| window.with_state(|state| state.tags.contains(&tag)))
} else { } else {
true true
@ -100,14 +105,14 @@ impl WindowRuleCondition {
let cond_any = if let Some(cond_any) = cond_any { let cond_any = if let Some(cond_any) = cond_any {
cond_any cond_any
.iter() .iter()
.any(|cond| Self::is_met_inner(cond, state, window, AllOrAny::Any)) .any(|cond| Self::is_met_inner(cond, pinnacle, window, AllOrAny::Any))
} else { } else {
false false
}; };
let cond_all = if let Some(cond_all) = cond_all { let cond_all = if let Some(cond_all) = cond_all {
cond_all cond_all
.iter() .iter()
.all(|cond| Self::is_met_inner(cond, state, window, AllOrAny::All)) .all(|cond| Self::is_met_inner(cond, pinnacle, window, AllOrAny::All))
} else { } else {
false false
}; };
@ -126,7 +131,7 @@ impl WindowRuleCondition {
false false
}; };
let tags = if let Some(tag_ids) = tag { let tags = if let Some(tag_ids) = tag {
let mut tags = tag_ids.iter().filter_map(|tag_id| tag_id.tag(state)); let mut tags = tag_ids.iter().filter_map(|tag_id| tag_id.tag(pinnacle));
tags.any(|tag| window.with_state(|state| state.tags.contains(&tag))) tags.any(|tag| window.with_state(|state| state.tags.contains(&tag)))
} else { } else {
false false
@ -167,10 +172,10 @@ pub enum FloatingOrTiled {
Tiled, Tiled,
} }
impl State { impl Pinnacle {
pub fn apply_window_rules(&mut self, window: &WindowElement) { pub fn apply_window_rules(&mut self, window: &WindowElement) {
tracing::debug!("Applying window rules"); tracing::debug!("Applying window rules");
for (cond, rule) in self.pinnacle.config.window_rules.iter() { for (cond, rule) in self.config.window_rules.iter() {
if cond.is_met(self, window) { if cond.is_met(self, window) {
let WindowRule { let WindowRule {
output, output,
@ -253,7 +258,7 @@ impl State {
state.floating_or_tiled = state.floating_or_tiled =
window_state::FloatingOrTiled::Floating(rect) window_state::FloatingOrTiled::Floating(rect)
}); });
self.pinnacle.space.map_element(window.clone(), *loc, false); self.space.map_element(window.clone(), *loc, false);
} }
window_state::FloatingOrTiled::Tiled(rect) => { window_state::FloatingOrTiled::Tiled(rect) => {
// If the window is tiled, don't set the size. Instead, set // If the window is tiled, don't set the size. Instead, set

View file

@ -9,7 +9,7 @@ use smithay::{
}; };
use crate::{ use crate::{
state::{State, WithState}, state::{Pinnacle, WithState},
tag::Tag, tag::Tag,
}; };
@ -28,9 +28,8 @@ impl WindowId {
} }
/// Get the window that has this WindowId. /// Get the window that has this WindowId.
pub fn window(&self, state: &State) -> Option<WindowElement> { pub fn window(&self, pinnacle: &Pinnacle) -> Option<WindowElement> {
state pinnacle
.pinnacle
.windows .windows
.iter() .iter()
.find(|win| win.with_state(|state| &state.id == self)) .find(|win| win.with_state(|state| &state.id == self))

View file

@ -43,7 +43,7 @@ where
let tempdir = tempfile::tempdir()?; let tempdir = tempfile::tempdir()?;
state.start_grpc_server(tempdir.path())?; state.pinnacle.start_grpc_server(tempdir.path())?;
let loop_signal = event_loop.get_signal(); let loop_signal = event_loop.get_signal();
@ -54,7 +54,7 @@ where
}); });
event_loop.run(None, &mut state, |state| { event_loop.run(None, &mut state, |state| {
state.fixup_z_layering(); state.pinnacle.fixup_z_layering();
state.pinnacle.space.refresh(); state.pinnacle.space.refresh();
state.pinnacle.popup_manager.cleanup(); state.pinnacle.popup_manager.cleanup();

View file

@ -456,7 +456,7 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
let op = state.focused_output().unwrap(); let op = state.pinnacle.focused_output().unwrap();
assert_eq!(op.current_transform(), smithay::utils::Transform::Flipped90); assert_eq!(op.current_transform(), smithay::utils::Transform::Flipped90);
}); });
@ -467,7 +467,7 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
let op = state.focused_output().unwrap(); let op = state.pinnacle.focused_output().unwrap();
assert_eq!(op.current_transform(), smithay::utils::Transform::Normal); assert_eq!(op.current_transform(), smithay::utils::Transform::Normal);
}); });
@ -538,9 +538,9 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
state.new_output("First", (300, 200).into()); state.pinnacle.new_output("First", (300, 200).into());
state.new_output("Second", (300, 200).into()); state.pinnacle.new_output("Second", (300, 200).into());
state.new_output("Test Third", (300, 200).into()); state.pinnacle.new_output("Test Third", (300, 200).into());
}); });
sleep_secs(1); sleep_secs(1);
@ -608,7 +608,7 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
state.new_output("First", (300, 200).into()); state.pinnacle.new_output("First", (300, 200).into());
}); });
sleep_secs(1); sleep_secs(1);
@ -643,7 +643,7 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
state.new_output("First", (300, 200).into()); state.pinnacle.new_output("First", (300, 200).into());
}); });
sleep_secs(1); sleep_secs(1);
@ -664,7 +664,7 @@ mod output {
Rectangle::from_loc_and_size((1920, 0), (300, 200)) Rectangle::from_loc_and_size((1920, 0), (300, 200))
); );
state.new_output("Second", (500, 500).into()); state.pinnacle.new_output("Second", (500, 500).into());
}); });
sleep_secs(1); sleep_secs(1);
@ -714,9 +714,9 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
state.new_output("First", (300, 200).into()); state.pinnacle.new_output("First", (300, 200).into());
state.new_output("Second", (300, 700).into()); state.pinnacle.new_output("Second", (300, 700).into());
state.new_output("Third", (300, 400).into()); state.pinnacle.new_output("Third", (300, 400).into());
}); });
sleep_secs(1); sleep_secs(1);
@ -749,7 +749,7 @@ mod output {
Rectangle::from_loc_and_size((0, 1080 + 200 + 700), (300, 400)) Rectangle::from_loc_and_size((0, 1080 + 200 + 700), (300, 400))
); );
state.remove_output(&second_op); state.pinnacle.remove_output(&second_op);
}); });
sleep_secs(1); sleep_secs(1);
@ -841,7 +841,8 @@ async fn spawned_window_on_active_tag_has_keyboard_focus() -> anyhow::Result<()>
with_state(&sender, |state| { with_state(&sender, |state| {
assert_eq!( assert_eq!(
state state
.focused_window(state.focused_output().unwrap()) .pinnacle
.focused_window(state.pinnacle.focused_output().unwrap())
.unwrap() .unwrap()
.class(), .class(),
Some("foot".to_string()) Some("foot".to_string())
@ -864,7 +865,12 @@ async fn spawned_window_on_inactive_tag_does_not_have_keyboard_focus() -> anyhow
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
assert_eq!(state.focused_window(state.focused_output().unwrap()), None); assert_eq!(
state
.pinnacle
.focused_window(state.pinnacle.focused_output().unwrap()),
None
);
}); });
Ok(()) Ok(())

View file

@ -69,9 +69,9 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
state.new_output("First", (300, 200).into()); state.pinnacle.new_output("First", (300, 200).into());
state.new_output("Second", (300, 200).into()); state.pinnacle.new_output("Second", (300, 200).into());
state.new_output("Test Third", (300, 200).into()); state.pinnacle.new_output("Test Third", (300, 200).into());
}); });
sleep_secs(1); sleep_secs(1);
@ -151,7 +151,7 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
state.new_output("First", (300, 200).into()); state.pinnacle.new_output("First", (300, 200).into());
}); });
sleep_secs(1); sleep_secs(1);
@ -172,7 +172,7 @@ mod output {
Rectangle::from_loc_and_size((1920, 0), (300, 200)) Rectangle::from_loc_and_size((1920, 0), (300, 200))
); );
state.new_output("Second", (500, 500).into()); state.pinnacle.new_output("Second", (500, 500).into());
}); });
sleep_secs(1); sleep_secs(1);
@ -249,9 +249,9 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
state.new_output("First", (300, 200).into()); state.pinnacle.new_output("First", (300, 200).into());
state.new_output("Second", (300, 700).into()); state.pinnacle.new_output("Second", (300, 700).into());
state.new_output("Third", (300, 400).into()); state.pinnacle.new_output("Third", (300, 400).into());
}); });
sleep_secs(1); sleep_secs(1);
@ -284,7 +284,7 @@ mod output {
Rectangle::from_loc_and_size((0, 1080 + 200 + 700), (300, 400)) Rectangle::from_loc_and_size((0, 1080 + 200 + 700), (300, 400))
); );
state.remove_output(&second_op); state.pinnacle.remove_output(&second_op);
}); });
sleep_secs(1); sleep_secs(1);
@ -335,7 +335,7 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
let op = state.focused_output().unwrap(); let op = state.pinnacle.focused_output().unwrap();
assert_eq!( assert_eq!(
op.current_transform(), op.current_transform(),
smithay::utils::Transform::Flipped270 smithay::utils::Transform::Flipped270
@ -352,7 +352,7 @@ mod output {
sleep_secs(1); sleep_secs(1);
with_state(&sender, |state| { with_state(&sender, |state| {
let op = state.focused_output().unwrap(); let op = state.pinnacle.focused_output().unwrap();
assert_eq!(op.current_transform(), smithay::utils::Transform::_180); assert_eq!(op.current_transform(), smithay::utils::Transform::_180);
}); });

View file

@ -1,4 +1,4 @@
use pinnacle::state::State; use pinnacle::state::Pinnacle;
mod inner { mod inner {
use pinnacle_api::layout::{CyclingLayoutManager, MasterStackLayout}; use pinnacle_api::layout::{CyclingLayoutManager, MasterStackLayout};
use pinnacle_api::window::rules::{WindowRule, WindowRuleCondition}; use pinnacle_api::window::rules::{WindowRule, WindowRuleCondition};
@ -24,10 +24,10 @@ mod inner {
} }
} }
pub fn run_config(state: &mut State) { pub fn run_config(pinnacle: &mut Pinnacle) {
let temp_dir = tempfile::tempdir().expect("failed to setup temp dir for socket"); let temp_dir = tempfile::tempdir().expect("failed to setup temp dir for socket");
let socket_dir = temp_dir.path().to_owned(); let socket_dir = temp_dir.path().to_owned();
state pinnacle
.start_wlcs_config(&socket_dir, move || { .start_wlcs_config(&socket_dir, move || {
inner::start_config(); inner::start_config();
drop(temp_dir); drop(temp_dir);

View file

@ -47,7 +47,7 @@ pub(crate) fn run(channel: Channel<WlcsEvent>) {
// when xdiplay is None when starting the config, the grpc server is not // when xdiplay is None when starting the config, the grpc server is not
// started, until it is set; this bypasses this for now // started, until it is set; this bypasses this for now
state.pinnacle.xdisplay = Some(u32::MAX); state.pinnacle.xdisplay = Some(u32::MAX);
run_config(&mut state); run_config(&mut state.pinnacle);
// wait for the config to connect to the layout service // wait for the config to connect to the layout service
while state.pinnacle.layout_state.layout_request_sender.is_none() { while state.pinnacle.layout_state.layout_request_sender.is_none() {
@ -59,7 +59,7 @@ pub(crate) fn run(channel: Channel<WlcsEvent>) {
event_loop event_loop
.run(None, &mut state, |state| { .run(None, &mut state, |state| {
state.update_pointer_focus(); state.update_pointer_focus();
state.fixup_z_layering(); state.pinnacle.fixup_z_layering();
state.pinnacle.space.refresh(); state.pinnacle.space.refresh();
state.pinnacle.popup_manager.cleanup(); state.pinnacle.popup_manager.cleanup();
@ -75,7 +75,7 @@ pub(crate) fn run(channel: Channel<WlcsEvent>) {
fn handle_event(event: WlcsEvent, state: &mut State) { fn handle_event(event: WlcsEvent, state: &mut State) {
tracing::debug!("handle_event {:?}", event); tracing::debug!("handle_event {:?}", event);
match event { match event {
WlcsEvent::Stop => state.shutdown(), WlcsEvent::Stop => state.pinnacle.shutdown(),
WlcsEvent::NewClient { stream, client_id } => { WlcsEvent::NewClient { stream, client_id } => {
let client: Client = state let client: Client = state
.pinnacle .pinnacle