Split off backend and rest of State

Currently doesn't clean up anything, still need to change `impl State`s to `impl Pinnacle`s
This commit is contained in:
Ottatop 2024-04-26 18:43:18 -05:00
parent c9012cf483
commit 8aaec59452
31 changed files with 770 additions and 514 deletions

View file

@ -204,7 +204,9 @@ impl pinnacle_service_server::PinnacleService for PinnacleService {
run_unary_no_response(&self.sender, |state| {
info!("Reloading config");
state
.start_config(Some(state.config.dir(&state.xdg_base_dirs)))
.start_config(Some(
state.pinnacle.config.dir(&state.pinnacle.xdg_base_dirs),
))
.expect("failed to restart config");
})
.await
@ -220,7 +222,7 @@ impl pinnacle_service_server::PinnacleService for PinnacleService {
_request: Request<ShutdownWatchRequest>,
) -> Result<Response<Self::ShutdownWatchStream>, Status> {
run_server_streaming(&self.sender, |state, sender| {
state.config.shutdown_sender.replace(sender);
state.pinnacle.config.shutdown_sender.replace(sender);
})
}
}
@ -291,6 +293,7 @@ impl input_service_server::InputService for InputService {
run_server_streaming(&self.sender, move |state, sender| {
state
.pinnacle
.input_state
.keybinds
.insert((modifiers, keysym), sender);
@ -334,6 +337,7 @@ impl input_service_server::InputService for InputService {
run_server_streaming(&self.sender, move |state, sender| {
state
.pinnacle
.input_state
.mousebinds
.insert((modifiers, button, edge), sender);
@ -354,7 +358,7 @@ impl input_service_server::InputService for InputService {
layout: request.layout(),
options: request.options.clone(),
};
if let Some(kb) = state.seat.get_keyboard() {
if let Some(kb) = state.pinnacle.seat.get_keyboard() {
if let Err(err) = kb.set_xkb_config(state, new_config) {
error!("Failed to set xkbconfig: {err}");
}
@ -377,7 +381,7 @@ impl input_service_server::InputService for InputService {
.ok_or_else(|| Status::invalid_argument("no rate specified"))?;
run_unary_no_response(&self.sender, move |state| {
if let Some(kb) = state.seat.get_keyboard() {
if let Some(kb) = state.pinnacle.seat.get_keyboard() {
kb.change_repeat_info(rate, delay);
}
})
@ -518,11 +522,12 @@ impl input_service_server::InputService for InputService {
};
run_unary_no_response(&self.sender, move |state| {
for device in state.input_state.libinput_devices.iter_mut() {
for device in state.pinnacle.input_state.libinput_devices.iter_mut() {
apply_setting(device);
}
state
.pinnacle
.input_state
.libinput_settings
.insert(discriminant, apply_setting);
@ -562,18 +567,19 @@ impl process_service_server::ProcessService for ProcessService {
run_server_streaming(&self.sender, move |state, sender| {
if once {
state
.pinnacle
.system_processes
.refresh_processes_specifics(ProcessRefreshKind::new());
let compositor_pid = std::process::id();
let already_running =
state
.system_processes
.processes_by_exact_name(&arg0)
.any(|proc| {
proc.parent()
.is_some_and(|parent_pid| parent_pid.as_u32() == compositor_pid)
});
let already_running = state
.pinnacle
.system_processes
.processes_by_exact_name(&arg0)
.any(|proc| {
proc.parent()
.is_some_and(|parent_pid| parent_pid.as_u32() == compositor_pid)
});
if already_running {
return;
@ -743,7 +749,7 @@ impl tag_service_server::TagService for TagService {
return;
};
state.fixup_xwayland_internal_z_indices();
state.fixup_xwayland_window_layering();
state.request_layout(&output);
state.update_focus(&output);
@ -772,7 +778,7 @@ impl tag_service_server::TagService for TagService {
tag.set_active(true, state);
});
state.fixup_xwayland_internal_z_indices();
state.fixup_xwayland_window_layering();
state.request_layout(&output);
state.update_focus(&output);
@ -804,6 +810,7 @@ impl tag_service_server::TagService for TagService {
.collect::<Vec<_>>();
state
.pinnacle
.config
.connector_saved_states
.entry(output_name.clone())
@ -819,7 +826,7 @@ impl tag_service_server::TagService for TagService {
}
for tag in new_tags {
for window in state.windows.iter() {
for window in state.pinnacle.windows.iter() {
window.with_state_mut(|state| {
for win_tag in state.tags.iter_mut() {
if win_tag.id() == tag.id() {
@ -844,7 +851,7 @@ impl tag_service_server::TagService for TagService {
run_unary_no_response(&self.sender, move |state| {
let tags_to_remove = tag_ids.flat_map(|id| id.tag(state)).collect::<Vec<_>>();
for output in state.space.outputs().cloned().collect::<Vec<_>>() {
for output in state.pinnacle.space.outputs().cloned().collect::<Vec<_>>() {
// TODO: seriously, convert state.tags into a hashset
output.with_state_mut(|state| {
for tag_to_remove in tags_to_remove.iter() {
@ -856,7 +863,7 @@ impl tag_service_server::TagService for TagService {
state.schedule_render(&output);
}
for conn_saved_state in state.config.connector_saved_states.values_mut() {
for conn_saved_state in state.pinnacle.config.connector_saved_states.values_mut() {
for tag_to_remove in tags_to_remove.iter() {
conn_saved_state.tags.retain(|tag| tag != tag_to_remove);
}
@ -871,6 +878,7 @@ impl tag_service_server::TagService for TagService {
) -> Result<Response<tag::v0alpha1::GetResponse>, Status> {
run_unary(&self.sender, move |state| {
let tag_ids = state
.pinnacle
.space
.outputs()
.flat_map(|op| op.with_state(|state| state.tags.clone()))
@ -908,6 +916,7 @@ impl tag_service_server::TagService for TagService {
.as_ref()
.map(|tag| {
state
.pinnacle
.windows
.iter()
.filter_map(|win| {
@ -958,7 +967,12 @@ impl output_service_server::OutputService for OutputService {
let y = request.y;
run_unary_no_response(&self.sender, move |state| {
if let Some(saved_state) = state.config.connector_saved_states.get_mut(&output_name) {
if let Some(saved_state) = state
.pinnacle
.config
.connector_saved_states
.get_mut(&output_name)
{
if let Some(x) = x {
saved_state.loc.x = x;
}
@ -966,7 +980,7 @@ impl output_service_server::OutputService for OutputService {
saved_state.loc.y = y;
}
} else {
state.config.connector_saved_states.insert(
state.pinnacle.config.connector_saved_states.insert(
output_name.clone(),
ConnectorSavedState {
loc: (x.unwrap_or_default(), y.unwrap_or_default()).into(),
@ -1100,6 +1114,7 @@ impl output_service_server::OutputService for OutputService {
) -> Result<Response<output::v0alpha1::GetResponse>, Status> {
run_unary(&self.sender, move |state| {
let output_names = state
.pinnacle
.space
.outputs()
.map(|output| output.name())
@ -1135,7 +1150,7 @@ impl output_service_server::OutputService for OutputService {
let logical_size = output
.as_ref()
.and_then(|output| state.space.output_geometry(output))
.and_then(|output| state.pinnacle.space.output_geometry(output))
.map(|geo| (geo.size.w, geo.size.h));
let current_mode = output
@ -1267,7 +1282,7 @@ impl render_service_server::RenderService for RenderService {
run_unary_no_response(&self.sender, move |state| {
state.backend.set_upscale_filter(filter);
for output in state.space.outputs().cloned().collect::<Vec<_>>() {
for output in state.pinnacle.space.outputs().cloned().collect::<Vec<_>>() {
state.backend.reset_buffers(&output);
state.schedule_render(&output);
}
@ -1292,7 +1307,7 @@ impl render_service_server::RenderService for RenderService {
run_unary_no_response(&self.sender, move |state| {
state.backend.set_downscale_filter(filter);
for output in state.space.outputs().cloned().collect::<Vec<_>>() {
for output in state.pinnacle.space.outputs().cloned().collect::<Vec<_>>() {
state.backend.reset_buffers(&output);
state.schedule_render(&output);
}

View file

@ -64,7 +64,7 @@ impl layout_service_server::LayoutService for LayoutService {
}
},
|state, sender, _join_handle| {
state.layout_state.layout_request_sender = Some(sender);
state.pinnacle.layout_state.layout_request_sender = Some(sender);
},
)
}

View file

@ -201,7 +201,7 @@ impl signal_service_server::SignalService for SignalService {
let in_stream = request.into_inner();
start_signal_stream(self.sender.clone(), in_stream, |state| {
&mut state.signal_state.output_connect
&mut state.pinnacle.signal_state.output_connect
})
}
@ -212,7 +212,7 @@ impl signal_service_server::SignalService for SignalService {
let in_stream = request.into_inner();
start_signal_stream(self.sender.clone(), in_stream, |state| {
&mut state.signal_state.output_disconnect
&mut state.pinnacle.signal_state.output_disconnect
})
}
@ -223,7 +223,7 @@ impl signal_service_server::SignalService for SignalService {
let in_stream = request.into_inner();
start_signal_stream(self.sender.clone(), in_stream, |state| {
&mut state.signal_state.output_resize
&mut state.pinnacle.signal_state.output_resize
})
}
@ -234,7 +234,7 @@ impl signal_service_server::SignalService for SignalService {
let in_stream = request.into_inner();
start_signal_stream(self.sender.clone(), in_stream, |state| {
&mut state.signal_state.output_move
&mut state.pinnacle.signal_state.output_move
})
}
@ -245,7 +245,7 @@ impl signal_service_server::SignalService for SignalService {
let in_stream = request.into_inner();
start_signal_stream(self.sender.clone(), in_stream, |state| {
&mut state.signal_state.window_pointer_enter
&mut state.pinnacle.signal_state.window_pointer_enter
})
}
@ -256,7 +256,7 @@ impl signal_service_server::SignalService for SignalService {
let in_stream = request.into_inner();
start_signal_stream(self.sender.clone(), in_stream, |state| {
&mut state.signal_state.window_pointer_leave
&mut state.pinnacle.signal_state.window_pointer_leave
})
}
@ -267,7 +267,7 @@ impl signal_service_server::SignalService for SignalService {
let in_stream = request.into_inner();
start_signal_stream(self.sender.clone(), in_stream, |state| {
&mut state.signal_state.tag_active
&mut state.pinnacle.signal_state.tag_active
})
}
}

View file

@ -92,7 +92,11 @@ impl window_service_server::WindowService for WindowService {
let Some(window) = window_id.window(state) else { return };
// TODO: with no x or y, defaults unmapped windows to 0, 0
let mut window_loc = state.space.element_location(&window).unwrap_or_default();
let mut window_loc = state
.pinnacle
.space
.element_location(&window)
.unwrap_or_default();
window_loc.x = x.unwrap_or(window_loc.x);
window_loc.y = y.unwrap_or(window_loc.y);
@ -110,7 +114,7 @@ impl window_service_server::WindowService for WindowService {
}
});
for output in state.space.outputs_for_element(&window) {
for output in state.pinnacle.space.outputs_for_element(&window) {
state.request_layout(&output);
state.schedule_render(&output);
}
@ -293,7 +297,7 @@ impl window_service_server::WindowService for WindowService {
return;
};
for win in state.space.elements() {
for win in state.pinnacle.space.elements() {
win.set_activate(false);
}
@ -301,8 +305,8 @@ impl window_service_server::WindowService for WindowService {
SetOrToggle::Set => {
window.set_activate(true);
output.with_state_mut(|state| state.focus_stack.set_focus(window.clone()));
state.output_focus_stack.set_focus(output.clone());
if let Some(keyboard) = state.seat.get_keyboard() {
state.pinnacle.output_focus_stack.set_focus(output.clone());
if let Some(keyboard) = state.pinnacle.seat.get_keyboard() {
keyboard.set_focus(
state,
Some(KeyboardFocusTarget::Window(window)),
@ -313,7 +317,7 @@ impl window_service_server::WindowService for WindowService {
SetOrToggle::Unset => {
if state.focused_window(&output) == Some(window) {
output.with_state_mut(|state| state.focus_stack.unset_focus());
if let Some(keyboard) = state.seat.get_keyboard() {
if let Some(keyboard) = state.pinnacle.seat.get_keyboard() {
keyboard.set_focus(state, None, SERIAL_COUNTER.next_serial());
}
}
@ -321,14 +325,14 @@ impl window_service_server::WindowService for WindowService {
SetOrToggle::Toggle => {
if state.focused_window(&output).as_ref() == Some(&window) {
output.with_state_mut(|state| state.focus_stack.unset_focus());
if let Some(keyboard) = state.seat.get_keyboard() {
if let Some(keyboard) = state.pinnacle.seat.get_keyboard() {
keyboard.set_focus(state, None, SERIAL_COUNTER.next_serial());
}
} else {
window.set_activate(true);
output.with_state_mut(|state| state.focus_stack.set_focus(window.clone()));
state.output_focus_stack.set_focus(output.clone());
if let Some(keyboard) = state.seat.get_keyboard() {
state.pinnacle.output_focus_stack.set_focus(output.clone());
if let Some(keyboard) = state.pinnacle.seat.get_keyboard() {
keyboard.set_focus(
state,
Some(KeyboardFocusTarget::Window(window)),
@ -340,7 +344,7 @@ impl window_service_server::WindowService for WindowService {
SetOrToggle::Unspecified => unreachable!(),
}
for window in state.space.elements() {
for window in state.pinnacle.space.elements() {
if let Some(toplevel) = window.toplevel() {
toplevel.send_configure();
}
@ -461,7 +465,11 @@ impl window_service_server::WindowService for WindowService {
.ok_or_else(|| Status::invalid_argument("no button specified"))?;
run_unary_no_response(&self.sender, move |state| {
let Some(pointer_location) = state.seat.get_pointer().map(|ptr| ptr.current_location())
let Some(pointer_location) = state
.pinnacle
.seat
.get_pointer()
.map(|ptr| ptr.current_location())
else {
return;
};
@ -476,7 +484,7 @@ impl window_service_server::WindowService for WindowService {
let Some(wl_surf) = window.wl_surface() else {
return;
};
let seat = state.seat.clone();
let seat = state.pinnacle.seat.clone();
crate::grab::move_grab::move_request_server(
state,
@ -500,7 +508,11 @@ impl window_service_server::WindowService for WindowService {
.ok_or_else(|| Status::invalid_argument("no button specified"))?;
run_unary_no_response(&self.sender, move |state| {
let Some(pointer_loc) = state.seat.get_pointer().map(|ptr| ptr.current_location())
let Some(pointer_loc) = state
.pinnacle
.seat
.get_pointer()
.map(|ptr| ptr.current_location())
else {
return;
};
@ -557,7 +569,7 @@ impl window_service_server::WindowService for WindowService {
crate::grab::resize_grab::resize_request_server(
state,
&wl_surf,
&state.seat.clone(),
&state.pinnacle.seat.clone(),
SERIAL_COUNTER.next_serial(),
edges.into(),
button,
@ -572,6 +584,7 @@ impl window_service_server::WindowService for WindowService {
) -> Result<Response<window::v0alpha1::GetResponse>, Status> {
run_unary(&self.sender, move |state| {
let window_ids = state
.pinnacle
.windows
.iter()
.map(|win| win.with_state(|state| state.id.0))
@ -603,12 +616,12 @@ impl window_service_server::WindowService for WindowService {
let x = window
.as_ref()
.and_then(|win| state.space.element_location(win))
.and_then(|win| state.pinnacle.space.element_location(win))
.map(|loc| loc.x);
let y = window
.as_ref()
.and_then(|win| state.space.element_location(win))
.and_then(|win| state.pinnacle.space.element_location(win))
.map(|loc| loc.y);
let geometry = if width.is_none() && height.is_none() && x.is_none() && y.is_none() {
@ -691,7 +704,7 @@ impl window_service_server::WindowService for WindowService {
.into();
run_unary_no_response(&self.sender, move |state| {
state.config.window_rules.push((cond, rule));
state.pinnacle.config.window_rules.push((cond, rule));
})
.await
}

View file

@ -108,16 +108,19 @@ pub fn setup_dummy(
config_dir,
)?;
state.output_focus_stack.set_focus(output.clone());
state.pinnacle.output_focus_stack.set_focus(output.clone());
let dummy = state.backend.dummy_mut();
state.shm_state.update_formats(dummy.renderer.shm_formats());
state
.pinnacle
.shm_state
.update_formats(dummy.renderer.shm_formats());
state.space.map_output(&output, (0, 0));
state.pinnacle.space.map_output(&output, (0, 0));
if let Err(err) = state.xwayland.start(
state.loop_handle.clone(),
if let Err(err) = state.pinnacle.xwayland.start(
state.pinnacle.loop_handle.clone(),
None,
std::iter::empty::<(OsString, OsString)>(),
true,
@ -149,11 +152,11 @@ impl State {
output.set_preferred(mode);
output.create_global::<State>(&self.display_handle);
output.create_global::<State>(&self.pinnacle.display_handle);
self.space.map_output(&output, (0, 0));
self.pinnacle.space.map_output(&output, (0, 0));
self.signal_state.output_connect.signal(|buf| {
self.pinnacle.signal_state.output_connect.signal(|buf| {
buf.push_back(OutputConnectResponse {
output_name: Some(output.name()),
});
@ -161,12 +164,15 @@ impl State {
}
pub fn remove_output(&mut self, output: &Output) {
self.space.unmap_output(output);
self.pinnacle.space.unmap_output(output);
self.signal_state.output_disconnect.signal(|buffer| {
buffer.push_back(OutputDisconnectResponse {
output_name: Some(output.name()),
})
});
self.pinnacle
.signal_state
.output_disconnect
.signal(|buffer| {
buffer.push_back(OutputDisconnectResponse {
output_name: Some(output.name()),
})
});
}
}

View file

@ -432,7 +432,7 @@ pub fn setup_udev(
udev.session.clone().into(),
);
libinput_context
.udev_assign_seat(state.seat.name())
.udev_assign_seat(state.pinnacle.seat.name())
.expect("failed to assign seat to libinput");
let libinput_backend = LibinputInputBackend::new(libinput_context.clone());
@ -576,7 +576,7 @@ pub fn setup_udev(
}
}
for output in state.space.outputs().cloned().collect::<Vec<_>>() {
for output in state.pinnacle.space.outputs().cloned().collect::<Vec<_>>() {
state.schedule_render(&output);
}
}
@ -584,7 +584,7 @@ pub fn setup_udev(
})
.expect("failed to insert libinput notifier into event loop");
state.shm_state.update_formats(
state.pinnacle.shm_state.update_formats(
udev.gpu_manager
.single_renderer(&primary_gpu)?
.shm_formats(),
@ -676,8 +676,8 @@ pub fn setup_udev(
});
});
if let Err(err) = state.xwayland.start(
state.loop_handle.clone(),
if let Err(err) = state.pinnacle.xwayland.start(
state.pinnacle.loop_handle.clone(),
None,
std::iter::empty::<(OsString, OsString)>(),
true,
@ -903,6 +903,7 @@ impl State {
let gbm = GbmDevice::new(fd).map_err(DeviceAddError::GbmDevice)?;
let registration_token = self
.pinnacle
.loop_handle
.insert_source(notifier, move |event, metadata, state| match event {
DrmEvent::VBlank(crtc) => {
@ -1011,7 +1012,7 @@ impl State {
let (phys_w, phys_h) = connector.size().unwrap_or((0, 0));
if self.space.outputs().any(|op| {
if self.pinnacle.space.outputs().any(|op| {
op.user_data()
.get::<UdevOutputData>()
.is_some_and(|op_id| op_id.crtc == crtc)
@ -1034,10 +1035,10 @@ impl State {
output.set_preferred(wl_mode);
self.output_focus_stack.set_focus(output.clone());
self.pinnacle.output_focus_stack.set_focus(output.clone());
let x = self.space.outputs().fold(0, |acc, o| {
let Some(geo) = self.space.output_geometry(o) else {
let x = self.pinnacle.space.outputs().fold(0, |acc, o| {
let Some(geo) = self.pinnacle.space.output_geometry(o) else {
unreachable!()
};
acc + geo.size.w
@ -1116,6 +1117,7 @@ impl State {
// In this case, restore its tags and location.
// TODO: instead of checking the connector, check the monitor's edid info instead
if let Some(saved_state) = self
.pinnacle
.config
.connector_saved_states
.get(&OutputName(output.name()))
@ -1124,7 +1126,7 @@ impl State {
output.with_state_mut(|state| state.tags = tags.clone());
self.change_output_state(&output, None, None, *scale, Some(*loc));
} else {
self.signal_state.output_connect.signal(|buffer| {
self.pinnacle.signal_state.output_connect.signal(|buffer| {
buffer.push_back(OutputConnectResponse {
output_name: Some(output.name()),
})
@ -1152,6 +1154,7 @@ impl State {
device.surfaces.remove(&crtc);
let output = self
.pinnacle
.space
.outputs()
.find(|o| {
@ -1164,7 +1167,7 @@ impl State {
if let Some(output) = output {
// Save this output's state. It will be restored if the monitor gets replugged.
self.config.connector_saved_states.insert(
self.pinnacle.config.connector_saved_states.insert(
OutputName(output.name()),
ConnectorSavedState {
loc: output.current_location(),
@ -1172,14 +1175,19 @@ impl State {
scale: Some(output.current_scale()),
},
);
self.space.unmap_output(&output);
self.gamma_control_manager_state.output_removed(&output);
self.pinnacle.space.unmap_output(&output);
self.pinnacle
.gamma_control_manager_state
.output_removed(&output);
self.signal_state.output_disconnect.signal(|buffer| {
buffer.push_back(OutputDisconnectResponse {
output_name: Some(output.name()),
})
});
self.pinnacle
.signal_state
.output_disconnect
.signal(|buffer| {
buffer.push_back(OutputDisconnectResponse {
output_name: Some(output.name()),
})
});
}
}
@ -1241,7 +1249,9 @@ impl State {
.as_mut()
.remove_node(&backend_data.render_node);
self.loop_handle.remove(backend_data.registration_token);
self.pinnacle
.loop_handle
.remove(backend_data.registration_token);
tracing::debug!("Dropping device");
}
@ -1264,7 +1274,7 @@ impl State {
return;
};
let output = if let Some(output) = self.space.outputs().find(|o| {
let output = if let Some(output) = self.pinnacle.space.outputs().find(|o| {
let udev_op_data = o.user_data().get::<UdevOutputData>();
udev_op_data
.is_some_and(|data| data.device_id == surface.device_id && data.crtc == crtc)
@ -1299,7 +1309,10 @@ impl State {
| wp_presentation_feedback::Kind::HwCompletion,
)
} else {
(self.clock.now(), wp_presentation_feedback::Kind::Vsync)
(
self.pinnacle.clock.now(),
wp_presentation_feedback::Kind::Vsync,
)
};
feedback.presented(
@ -1330,10 +1343,13 @@ impl State {
if dirty {
self.schedule_render(&output);
} else {
for window in self.windows.iter() {
window.send_frame(&output, self.clock.now(), Some(Duration::ZERO), |_, _| {
Some(output.clone())
});
for window in self.pinnacle.windows.iter() {
window.send_frame(
&output,
self.pinnacle.clock.now(),
Some(Duration::ZERO),
|_, _| Some(output.clone()),
);
}
}
}
@ -1353,7 +1369,7 @@ impl State {
let frame = udev.pointer_image.get_image(
1,
// output.current_scale().integer_scale() as u32,
self.clock.now().into(),
self.pinnacle.clock.now().into(),
);
let render_node = surface.render_node;
@ -1398,9 +1414,10 @@ impl State {
texture
});
let windows = self.space.elements().cloned().collect::<Vec<_>>();
let windows = self.pinnacle.space.elements().cloned().collect::<Vec<_>>();
let pointer_location = self
.pinnacle
.seat
.get_pointer()
.map(|ptr| ptr.current_location())
@ -1411,21 +1428,22 @@ impl State {
// draw the cursor as relevant and
// reset the cursor if the surface is no longer alive
if let CursorImageStatus::Surface(surface) = &self.cursor_status {
if let CursorImageStatus::Surface(surface) = &self.pinnacle.cursor_status {
if !surface.alive() {
self.cursor_status = CursorImageStatus::default_named();
self.pinnacle.cursor_status = CursorImageStatus::default_named();
} else {
send_frames_surface_tree(
surface,
output,
self.clock.now(),
self.pinnacle.clock.now(),
Some(Duration::ZERO),
|_, _| None,
);
}
}
udev.pointer_element.set_status(self.cursor_status.clone());
udev.pointer_element
.set_status(self.pinnacle.cursor_status.clone());
let pending_screencopy_with_cursor =
output.with_state(|state| state.screencopy.as_ref().map(|sc| sc.overlay_cursor()));
@ -1449,10 +1467,10 @@ impl State {
let pointer_render_elements = pointer_render_elements(
output,
&mut renderer,
&self.space,
&self.pinnacle.space,
pointer_location,
&mut self.cursor_status,
self.dnd_icon.as_ref(),
&mut self.pinnacle.cursor_status,
self.pinnacle.dnd_icon.as_ref(),
&udev.pointer_element,
);
udev.pointer_element.set_element_kind(element::Kind::Cursor);
@ -1463,10 +1481,10 @@ impl State {
let pointer_render_elements = pointer_render_elements(
output,
&mut renderer,
&self.space,
&self.pinnacle.space,
pointer_location,
&mut self.cursor_status,
self.dnd_icon.as_ref(),
&mut self.pinnacle.cursor_status,
self.pinnacle.dnd_icon.as_ref(),
&udev.pointer_element,
);
output_render_elements.extend(pointer_render_elements);
@ -1476,7 +1494,7 @@ impl State {
output_render_elements.extend(crate::render::output_render_elements(
output,
&mut renderer,
&self.space,
&self.pinnacle.space,
&windows,
));
@ -1499,13 +1517,13 @@ impl State {
output,
surface,
&render_frame_result,
&self.loop_handle,
&self.pinnacle.loop_handle,
);
super::post_repaint(
output,
&render_frame_result.states,
&self.space,
&self.pinnacle.space,
surface
.dmabuf_feedback
.as_ref()
@ -1513,15 +1531,18 @@ impl State {
render_feedback: &feedback.render_feedback,
scanout_feedback: &feedback.scanout_feedback,
}),
Duration::from(self.clock.now()),
&self.cursor_status,
Duration::from(self.pinnacle.clock.now()),
&self.pinnacle.cursor_status,
);
let rendered = !render_frame_result.is_empty;
if rendered {
let output_presentation_feedback =
take_presentation_feedback(output, &self.space, &render_frame_result.states);
let output_presentation_feedback = take_presentation_feedback(
output,
&self.pinnacle.space,
&render_frame_result.states,
);
surface
.compositor

View file

@ -190,18 +190,19 @@ pub fn setup_winit(
// wl-mirror segfaults if it gets a wl-output global before the xdg output manager global
output.create_global::<State>(&display_handle);
state.output_focus_stack.set_focus(output.clone());
state.pinnacle.output_focus_stack.set_focus(output.clone());
let winit = state.backend.winit_mut();
state
.pinnacle
.shm_state
.update_formats(winit.backend.renderer().shm_formats());
state.space.map_output(&output, (0, 0));
state.pinnacle.space.map_output(&output, (0, 0));
if let Err(err) = state.xwayland.start(
state.loop_handle.clone(),
if let Err(err) = state.pinnacle.xwayland.start(
state.pinnacle.loop_handle.clone(),
None,
std::iter::empty::<(OsString, OsString)>(),
true,
@ -210,49 +211,49 @@ pub fn setup_winit(
error!("Failed to start XWayland: {err}");
}
let insert_ret =
state
.loop_handle
.insert_source(Timer::immediate(), move |_instant, _metadata, state| {
let status = winit_evt_loop.dispatch_new_events(|event| match event {
WinitEvent::Resized { size, scale_factor } => {
let mode = smithay::output::Mode {
size,
refresh: 144_000,
};
state.change_output_state(
&output,
Some(mode),
None,
Some(Scale::Fractional(scale_factor)),
None,
);
state.request_layout(&output);
let insert_ret = state.pinnacle.loop_handle.insert_source(
Timer::immediate(),
move |_instant, _metadata, state| {
let status = winit_evt_loop.dispatch_new_events(|event| match event {
WinitEvent::Resized { size, scale_factor } => {
let mode = smithay::output::Mode {
size,
refresh: 144_000,
};
state.change_output_state(
&output,
Some(mode),
None,
Some(Scale::Fractional(scale_factor)),
None,
);
state.request_layout(&output);
}
WinitEvent::Focus(focused) => {
if focused {
state.backend.winit_mut().reset_buffers(&output);
}
WinitEvent::Focus(focused) => {
if focused {
state.backend.winit_mut().reset_buffers(&output);
}
}
WinitEvent::Input(input_evt) => {
state.process_input_event(input_evt);
}
WinitEvent::Redraw => {
state.render_winit_window(&output);
}
WinitEvent::CloseRequested => {
state.shutdown();
}
});
if let PumpStatus::Exit(_) = status {
}
WinitEvent::Input(input_evt) => {
state.process_input_event(input_evt);
}
WinitEvent::Redraw => {
state.render_winit_window(&output);
}
WinitEvent::CloseRequested => {
state.shutdown();
}
state.render_winit_window(&output);
TimeoutAction::ToDuration(Duration::from_micros(((1.0 / 144.0) * 1000000.0) as u64))
});
if let PumpStatus::Exit(_) = status {
state.shutdown();
}
state.render_winit_window(&output);
TimeoutAction::ToDuration(Duration::from_micros(((1.0 / 144.0) * 1000000.0) as u64))
},
);
if let Err(err) = insert_ret {
anyhow::bail!("Failed to insert winit events into event loop: {err}");
}
@ -267,21 +268,21 @@ impl State {
let full_redraw = &mut winit.full_redraw;
*full_redraw = full_redraw.saturating_sub(1);
if let CursorImageStatus::Surface(surface) = &self.cursor_status {
if let CursorImageStatus::Surface(surface) = &self.pinnacle.cursor_status {
if !surface.alive() {
self.cursor_status = CursorImageStatus::default_named();
self.pinnacle.cursor_status = CursorImageStatus::default_named();
}
}
let cursor_visible = !matches!(self.cursor_status, CursorImageStatus::Surface(_));
let cursor_visible = !matches!(self.pinnacle.cursor_status, CursorImageStatus::Surface(_));
let mut pointer_element = PointerElement::<GlesTexture>::new();
pointer_element.set_status(self.cursor_status.clone());
pointer_element.set_status(self.pinnacle.cursor_status.clone());
// The z-index of these is determined by `state.fixup_z_layering()`, which is called at the end
// of every event loop cycle
let windows = self.space.elements().cloned().collect::<Vec<_>>();
let windows = self.pinnacle.space.elements().cloned().collect::<Vec<_>>();
let mut output_render_elements = Vec::new();
@ -299,6 +300,7 @@ impl State {
// but it shouldn't meaningfully affect anything.
if !pending_screencopy_without_cursor {
let pointer_location = self
.pinnacle
.seat
.get_pointer()
.map(|ptr| ptr.current_location())
@ -307,10 +309,10 @@ impl State {
let pointer_render_elements = pointer_render_elements(
output,
winit.backend.renderer(),
&self.space,
&self.pinnacle.space,
pointer_location,
&mut self.cursor_status,
self.dnd_icon.as_ref(),
&mut self.pinnacle.cursor_status,
self.pinnacle.dnd_icon.as_ref(),
&pointer_element,
);
output_render_elements.extend(pointer_render_elements);
@ -319,7 +321,7 @@ impl State {
output_render_elements.extend(crate::render::output_render_elements(
output,
winit.backend.renderer(),
&self.space,
&self.pinnacle.space,
&windows,
));
@ -347,7 +349,7 @@ impl State {
&mut winit.backend,
output,
&render_output_result,
&self.loop_handle,
&self.pinnacle.loop_handle,
);
let has_rendered = render_output_result.damage.is_some();
@ -359,21 +361,21 @@ impl State {
winit.backend.window().set_cursor_visible(cursor_visible);
let time = self.clock.now();
let time = self.pinnacle.clock.now();
super::post_repaint(
output,
&render_output_result.states,
&self.space,
&self.pinnacle.space,
None,
time.into(),
&self.cursor_status,
&self.pinnacle.cursor_status,
);
if has_rendered {
let mut output_presentation_feedback = take_presentation_feedback(
output,
&self.space,
&self.pinnacle.space,
&render_output_result.states,
);
output_presentation_feedback.presented(

View file

@ -80,11 +80,11 @@ pub fn setup_wlcs_dummy() -> anyhow::Result<(State, EventLoop<'static, State>)>
None,
)?;
state.output_focus_stack.set_focus(output.clone());
state.pinnacle.output_focus_stack.set_focus(output.clone());
state.shm_state.update_formats(shm_formats);
state.pinnacle.shm_state.update_formats(shm_formats);
state.space.map_output(&output, (0, 0));
state.pinnacle.space.map_output(&output, (0, 0));
Ok((state, event_loop))
}
@ -96,7 +96,7 @@ impl State {
{
// Clear state
debug!("Clearing tags");
for output in self.space.outputs() {
for output in self.pinnacle.space.outputs() {
output.with_state_mut(|state| state.tags.clear());
}
@ -104,22 +104,23 @@ impl State {
debug!("Clearing input state");
self.input_state.clear();
self.pinnacle.input_state.clear();
self.config.clear(&self.loop_handle);
self.pinnacle.config.clear(&self.pinnacle.loop_handle);
self.signal_state.clear();
self.pinnacle.signal_state.clear();
self.input_state.reload_keybind = None;
self.input_state.kill_keybind = None;
self.pinnacle.input_state.reload_keybind = None;
self.pinnacle.input_state.kill_keybind = None;
if self.grpc_server_join_handle.is_none() {
if self.pinnacle.grpc_server_join_handle.is_none() {
self.start_grpc_server(socket_dir)?;
}
let (pinger, ping_source) = calloop::ping::make_ping()?;
let token = self
.pinnacle
.loop_handle
.insert_source(ping_source, move |_, _, _state| {})?;
@ -128,7 +129,7 @@ impl State {
pinger.ping();
});
self.config.config_reload_on_crash_token = Some(token);
self.pinnacle.config.config_reload_on_crash_token = Some(token);
Ok(())
}

View file

@ -276,7 +276,7 @@ impl State {
// Clear state
debug!("Clearing tags");
for output in self.space.outputs() {
for output in self.pinnacle.space.outputs() {
output.with_state_mut(|state| state.tags.clear());
}
@ -284,11 +284,11 @@ impl State {
debug!("Clearing input state");
self.input_state.clear();
self.pinnacle.input_state.clear();
self.config.clear(&self.loop_handle);
self.pinnacle.config.clear(&self.pinnacle.loop_handle);
self.signal_state.clear();
self.pinnacle.signal_state.clear();
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| {
@ -304,7 +304,7 @@ impl State {
};
// If `--no-config` was set, still load the keybinds from the default metaconfig
if self.config.no_config {
if self.pinnacle.config.no_config {
config_dir = None;
}
@ -328,17 +328,17 @@ impl State {
let reload_keybind = (reload_mask, Keysym::from(reload_keybind.key as u32));
let kill_keybind = (kill_mask, Keysym::from(kill_keybind.key as u32));
self.input_state.reload_keybind = Some(reload_keybind);
self.input_state.kill_keybind = Some(kill_keybind);
self.pinnacle.input_state.reload_keybind = Some(reload_keybind);
self.pinnacle.input_state.kill_keybind = Some(kill_keybind);
if self.config.no_config {
if self.pinnacle.config.no_config {
info!("`--no-config` was set, not spawning config");
return Ok(());
}
// Because the grpc server is implemented to only start once,
// any updates to `socket_dir` won't be applied until restart.
if self.grpc_server_join_handle.is_none() {
if self.pinnacle.grpc_server_join_handle.is_none() {
// If a socket is provided in the metaconfig, use it.
let socket_dir = if let Some(socket_dir) = &metaconfig.socket_dir {
let Some(config_dir) = &config_dir else {
@ -356,7 +356,8 @@ impl State {
socket_dir
} else {
// Otherwise, use $XDG_RUNTIME_DIR. If that doesn't exist, use /tmp.
self.xdg_base_dirs
self.pinnacle
.xdg_base_dirs
.get_runtime_directory()
.cloned()
.unwrap_or(PathBuf::from(DEFAULT_SOCKET_DIR))
@ -448,30 +449,32 @@ impl State {
let (pinger, ping_source) = calloop::ping::make_ping()?;
let token = self
.loop_handle
.insert_source(ping_source, move |_, _, state| {
error!("Config crashed! Falling back to default config");
state
.start_config(None::<PathBuf>)
.expect("failed to start default config");
})?;
let token =
self.pinnacle
.loop_handle
.insert_source(ping_source, move |_, _, state| {
error!("Config crashed! Falling back to default config");
state
.start_config(None::<PathBuf>)
.expect("failed to start default config");
})?;
self.config.config_join_handle = Some(tokio::spawn(async move {
self.pinnacle.config.config_join_handle = Some(tokio::spawn(async move {
let _ = child.wait().await;
pinger.ping();
}));
self.config.config_reload_on_crash_token = Some(token);
self.pinnacle.config.config_reload_on_crash_token = Some(token);
}
None => {
let (pinger, ping_source) = calloop::ping::make_ping()?;
let token = self
.loop_handle
.insert_source(ping_source, move |_, _, _state| {
panic!("builtin rust config crashed; this is a bug");
})?;
let token =
self.pinnacle
.loop_handle
.insert_source(ping_source, move |_, _, _state| {
panic!("builtin rust config crashed; this is a bug");
})?;
std::thread::spawn(move || {
info!("Starting builtin Rust config");
@ -479,7 +482,7 @@ impl State {
pinger.ping();
});
self.config.config_reload_on_crash_token = Some(token);
self.pinnacle.config.config_reload_on_crash_token = Some(token);
}
}
@ -487,10 +490,12 @@ impl State {
}
pub fn start_grpc_server(&mut self, socket_dir: &Path) -> anyhow::Result<()> {
self.system_processes
self.pinnacle
.system_processes
.refresh_processes_specifics(ProcessRefreshKind::new());
let multiple_instances = self
.pinnacle
.system_processes
.processes_by_exact_name("pinnacle")
.filter(|proc| proc.thread_kind().is_none())
@ -539,13 +544,14 @@ impl State {
std::env::set_var(
"PINNACLE_PROTO_DIR",
self.xdg_base_dirs.get_data_file("protobuf"),
self.pinnacle.xdg_base_dirs.get_data_file("protobuf"),
);
let (grpc_sender, grpc_receiver) =
calloop::channel::channel::<Box<dyn FnOnce(&mut Self) + Send>>();
self.loop_handle
self.pinnacle
.loop_handle
.insert_source(grpc_receiver, |msg, _, state| match msg {
Event::Msg(f) => f(state),
Event::Closed => error!("grpc receiver was closed"),
@ -583,9 +589,9 @@ impl State {
.add_service(LayoutServiceServer::new(layout_service))
.add_service(RenderServiceServer::new(render_service));
match self.xdisplay.as_ref() {
match self.pinnacle.xdisplay.as_ref() {
Some(_) => {
self.grpc_server_join_handle = Some(tokio::spawn(async move {
self.pinnacle.grpc_server_join_handle = Some(tokio::spawn(async move {
if let Err(err) = grpc_server.serve_with_incoming(uds_stream).await {
error!("gRPC server error: {err}");
}
@ -595,9 +601,9 @@ impl State {
// | fast at startup then I think there's a chance that the gRPC server
// | could get started twice.
None => self.schedule(
|state| state.xdisplay.is_some(),
|state| state.pinnacle.xdisplay.is_some(),
move |state| {
state.grpc_server_join_handle = Some(tokio::spawn(async move {
state.pinnacle.grpc_server_join_handle = Some(tokio::spawn(async move {
if let Err(err) = grpc_server.serve_with_incoming(uds_stream).await {
error!("gRPC server error: {err}");
}

View file

@ -47,16 +47,20 @@ impl State {
}
}
self.seat.get_keyboard().expect("no keyboard").set_focus(
self,
current_focus.map(|win| win.into()),
SERIAL_COUNTER.next_serial(),
);
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) {
for win in self.z_index_stack.iter() {
self.space.raise_element(win, false);
for win in self.pinnacle.z_index_stack.iter() {
self.pinnacle.space.raise_element(win, false);
}
}
@ -64,25 +68,26 @@ impl State {
///
/// This does nothing if the window is unmapped.
pub fn raise_window(&mut self, window: WindowElement, activate: bool) {
if self.space.elements().all(|win| win != &window) {
if self.pinnacle.space.elements().all(|win| win != &window) {
warn!("Tried to raise an unmapped window");
return;
}
self.space.raise_element(&window, activate);
self.pinnacle.space.raise_element(&window, activate);
self.z_index_stack.retain(|win| win != &window);
self.z_index_stack.push(window);
self.pinnacle.z_index_stack.retain(|win| win != &window);
self.pinnacle.z_index_stack.push(window);
self.fixup_xwayland_internal_z_indices();
self.fixup_xwayland_window_layering();
}
/// Get the currently focused output, or the first mapped output if there is none, or None.
pub fn focused_output(&self) -> Option<&Output> {
self.output_focus_stack
self.pinnacle
.output_focus_stack
.stack
.last()
.or_else(|| self.space.outputs().next())
.or_else(|| self.pinnacle.space.outputs().next())
}
}

View file

@ -35,6 +35,7 @@ impl PointerFocusTarget {
pub fn window_for(&self, state: &State) -> Option<WindowElement> {
match self {
PointerFocusTarget::WlSurface(surf) => state
.pinnacle
.windows
.iter()
.find(|win| {
@ -51,6 +52,7 @@ impl PointerFocusTarget {
})
.cloned(),
PointerFocusTarget::X11Surface(surf) => state
.pinnacle
.windows
.iter()
.find(|win| win.x11_surface() == Some(surf))
@ -61,7 +63,7 @@ impl PointerFocusTarget {
pub fn layer_for(&self, state: &State) -> Option<LayerSurface> {
match self {
PointerFocusTarget::WlSurface(surf) => {
for output in state.space.outputs() {
for output in state.pinnacle.space.outputs() {
let map = layer_map_for_output(output);
for layer in map.layers() {
let mut found = false;
@ -83,7 +85,7 @@ impl PointerFocusTarget {
pub fn popup_for(&self, state: &State) -> Option<PopupKind> {
match self {
PointerFocusTarget::WlSurface(surf) => state.popup_manager.find_popup(surf),
PointerFocusTarget::WlSurface(surf) => state.pinnacle.popup_manager.find_popup(surf),
PointerFocusTarget::X11Surface(_) => None,
}
}
@ -121,7 +123,8 @@ impl PointerTarget<State> for PointerFocusTarget {
if let Some(window) = self.window_for(data) {
let window_id = Some(window.with_state(|state| state.id.0));
data.signal_state
data.pinnacle
.signal_state
.window_pointer_enter
.signal(|buffer| buffer.push_back(WindowPointerEnterResponse { window_id }));
}
@ -312,7 +315,8 @@ impl PointerTarget<State> for PointerFocusTarget {
if let Some(window) = self.window_for(data) {
let window_id = Some(window.with_state(|state| state.id.0));
data.signal_state
data.pinnacle
.signal_state
.window_pointer_leave
.signal(|buffer| buffer.push_back(WindowPointerLeaveResponse { window_id }));
}

View file

@ -56,6 +56,7 @@ impl PointerGrab<State> for MoveSurfaceGrab {
// INFO: can you raise OR windows or no idk
if !surface.is_override_redirect() {
state
.pinnacle
.xwm
.as_mut()
.expect("no xwm")
@ -72,11 +73,12 @@ impl PointerGrab<State> for MoveSurfaceGrab {
// INFO: this is being used instead of space.element_under(event.location) because that
// | uses the bounding box, which is different from the actual geometry
let window_under = state
.pinnacle
.space
.elements()
.rev()
.find(|&win| {
if let Some(loc) = state.space.element_location(win) {
if let Some(loc) = state.pinnacle.space.element_location(win) {
let size = win.geometry().size;
let rect = Rectangle { size, loc };
rect.contains(event.location.to_i32_round())
@ -87,7 +89,7 @@ impl PointerGrab<State> for MoveSurfaceGrab {
.cloned();
if let Some(window_under) = window_under {
if state.layout_state.pending_swap {
if state.pinnacle.layout_state.pending_swap {
return;
}
@ -96,10 +98,12 @@ impl PointerGrab<State> for MoveSurfaceGrab {
}
if state
.pinnacle
.space
.element_geometry(&self.window)
.is_some_and(|geo| {
state
.pinnacle
.space
.element_geometry(&window_under)
.is_some_and(|geo2| geo.overlaps(geo2))
@ -120,9 +124,13 @@ impl PointerGrab<State> for MoveSurfaceGrab {
} else {
let delta = event.location - self.start_data.location;
let new_loc = (self.initial_window_loc.to_f64() + delta).to_i32_round();
state.space.map_element(self.window.clone(), new_loc, true);
state
.pinnacle
.space
.map_element(self.window.clone(), new_loc, true);
let size = state
.pinnacle
.space
.element_geometry(&self.window)
.expect("window wasn't mapped")
@ -145,7 +153,7 @@ impl PointerGrab<State> for MoveSurfaceGrab {
}
}
let outputs = state.space.outputs_for_element(&self.window);
let outputs = state.pinnacle.space.outputs_for_element(&self.window);
for output in outputs {
state.schedule_render(&output);
}
@ -278,6 +286,7 @@ pub fn move_request_client(
};
let initial_window_loc = state
.pinnacle
.space
.element_location(&window)
.expect("move request was called on an unmapped window");
@ -309,6 +318,7 @@ pub fn move_request_server(
};
let initial_window_loc = state
.pinnacle
.space
.element_location(&window)
.expect("move request was called on an unmapped window");

View file

@ -204,6 +204,7 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
WindowSurface::X11(surface) => {
if !surface.is_override_redirect() {
let loc = data
.pinnacle
.space
.element_location(&self.window)
.expect("failed to get x11 win loc");
@ -366,7 +367,7 @@ pub fn move_surface_if_resized(state: &mut State, surface: &WlSurface) {
return;
};
let Some(mut window_loc) = state.space.element_location(&window) else {
let Some(mut window_loc) = state.pinnacle.space.element_location(&window) else {
return;
};
let geometry = window.geometry();
@ -413,6 +414,7 @@ pub fn move_surface_if_resized(state: &mut State, surface: &WlSurface) {
}
let size = state
.pinnacle
.space
.element_geometry(&window)
.expect("called element_geometry on unmapped window")
@ -426,7 +428,10 @@ pub fn move_surface_if_resized(state: &mut State, surface: &WlSurface) {
});
if new_loc.0.is_some() || new_loc.1.is_some() {
state.space.map_element(window.clone(), window_loc, false);
state
.pinnacle
.space
.map_element(window.clone(), window_loc, false);
if let Some(surface) = window.x11_surface() {
if !surface.is_override_redirect() {
@ -463,6 +468,7 @@ pub fn resize_request_client(
}
let initial_window_loc = state
.pinnacle
.space
.element_location(&window)
.expect("resize request called on unmapped window");
@ -513,6 +519,7 @@ pub fn resize_request_server(
}
let initial_window_loc = state
.pinnacle
.space
.element_location(&window)
.expect("resize request called on unmapped window");

View file

@ -76,7 +76,7 @@ impl BufferHandler for State {
impl CompositorHandler for State {
fn compositor_state(&mut self) -> &mut CompositorState {
&mut self.compositor_state
&mut self.pinnacle.compositor_state
}
fn new_surface(&mut self, surface: &WlSurface) {
@ -97,12 +97,16 @@ impl CompositorHandler for State {
let client = surface
.client()
.expect("Surface has no client/is no longer alive");
let res = state.loop_handle.insert_source(source, move |_, _, state| {
let res =
state
.client_compositor_state(&client)
.blocker_cleared(state, &state.display_handle.clone());
Ok(())
});
.pinnacle
.loop_handle
.insert_source(source, move |_, _, state| {
state
.client_compositor_state(&client)
.blocker_cleared(state, &state.pinnacle.display_handle.clone());
Ok(())
});
if res.is_ok() {
compositor::add_blocker(surface, blocker);
}
@ -129,14 +133,15 @@ impl CompositorHandler for State {
if let Some(window) = self.window_for_surface(&root) {
window.on_commit();
if let Some(loc) = window.with_state_mut(|state| state.target_loc.take()) {
self.space.map_element(window.clone(), loc, false);
self.pinnacle.space.map_element(window.clone(), loc, false);
}
}
};
self.popup_manager.commit(surface);
self.pinnacle.popup_manager.commit(surface);
if let Some(new_window) = self
.pinnacle
.new_windows
.iter()
.find(|win| win.wl_surface().as_ref() == Some(surface))
@ -149,8 +154,8 @@ impl CompositorHandler for State {
};
if is_mapped {
self.new_windows.retain(|win| win != &new_window);
self.windows.push(new_window.clone());
self.pinnacle.new_windows.retain(|win| win != &new_window);
self.pinnacle.windows.push(new_window.clone());
if let Some(output) = self.focused_output() {
tracing::debug!("Placing toplevel");
@ -161,7 +166,8 @@ impl CompositorHandler for State {
// FIXME: I'm mapping way offscreen here then sending a frame to prevent a window from
// | mapping with its default geometry then immediately resizing
// | because I don't set a target geometry before the initial configure.
self.space
self.pinnacle
.space
.map_element(new_window.clone(), (1000000, 0), true);
self.raise_window(new_window.clone(), true);
@ -172,14 +178,15 @@ impl CompositorHandler for State {
self.request_layout(&focused_output);
new_window.send_frame(
&focused_output,
self.clock.now(),
self.pinnacle.clock.now(),
Some(Duration::ZERO),
surface_primary_scanout_output,
);
}
self.loop_handle.insert_idle(move |state| {
self.pinnacle.loop_handle.insert_idle(move |state| {
state
.pinnacle
.seat
.get_keyboard()
.expect("Seat had no keyboard") // FIXME: actually handle error
@ -202,7 +209,7 @@ impl CompositorHandler for State {
crate::grab::resize_grab::move_surface_if_resized(self, surface);
let outputs = if let Some(window) = self.window_for_surface(surface) {
let mut outputs = self.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,
// so also trigger a render using the window's tags' output
@ -211,24 +218,26 @@ impl CompositorHandler for State {
}
outputs // surface is a window
} else if let Some(window) = self.window_for_surface(&root) {
let mut outputs = self.space.outputs_for_element(&window);
let mut outputs = self.pinnacle.space.outputs_for_element(&window);
if let Some(output) = window.output(self) {
outputs.push(output);
}
outputs // surface is a root window
} else if let Some(PopupKind::Xdg(surf)) = self.popup_manager.find_popup(surface) {
} else if let Some(PopupKind::Xdg(surf)) = self.pinnacle.popup_manager.find_popup(surface) {
let geo = surf.with_pending_state(|state| state.geometry);
let outputs = self
.pinnacle
.space
.outputs()
.filter_map(|output| {
let op_geo = self.space.output_geometry(output);
let op_geo = self.pinnacle.space.output_geometry(output);
op_geo.and_then(|op_geo| op_geo.overlaps_or_touches(geo).then_some(output))
})
.cloned()
.collect::<Vec<_>>();
outputs
} else if let Some(output) = self
.pinnacle
.space
.outputs()
.find(|op| {
@ -285,7 +294,7 @@ fn ensure_initial_configure(surface: &WlSurface, state: &mut State) {
return;
}
if let Some(popup) = state.popup_manager.find_popup(surface) {
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
@ -304,7 +313,7 @@ fn ensure_initial_configure(surface: &WlSurface, state: &mut State) {
return;
}
if let Some(output) = state.space.outputs().find(|op| {
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()
@ -338,11 +347,11 @@ impl ClientDndGrabHandler for State {
icon: Option<WlSurface>,
_seat: Seat<Self>,
) {
self.dnd_icon = icon;
self.pinnacle.dnd_icon = icon;
}
fn dropped(&mut self, _seat: Seat<Self>) {
self.dnd_icon = None;
self.pinnacle.dnd_icon = None;
}
}
@ -357,7 +366,7 @@ impl SelectionHandler for State {
source: Option<SelectionSource>,
_seat: Seat<Self>,
) {
if let Some(xwm) = self.xwm.as_mut() {
if let Some(xwm) = self.pinnacle.xwm.as_mut() {
if let Err(err) = xwm.new_selection(ty, source.map(|source| source.mime_types())) {
tracing::warn!(?err, ?ty, "Failed to set Xwayland selection");
}
@ -372,8 +381,10 @@ impl SelectionHandler for State {
_seat: Seat<Self>,
_user_data: &(),
) {
if let Some(xwm) = self.xwm.as_mut() {
if let Err(err) = xwm.send_selection(ty, mime_type, fd, self.loop_handle.clone()) {
if let Some(xwm) = self.pinnacle.xwm.as_mut() {
if let Err(err) =
xwm.send_selection(ty, mime_type, fd, self.pinnacle.loop_handle.clone())
{
tracing::warn!(?err, "Failed to send primary (X11 -> Wayland)");
}
}
@ -382,21 +393,21 @@ impl SelectionHandler for State {
impl DataDeviceHandler for State {
fn data_device_state(&self) -> &DataDeviceState {
&self.data_device_state
&self.pinnacle.data_device_state
}
}
delegate_data_device!(State);
impl PrimarySelectionHandler for State {
fn primary_selection_state(&self) -> &PrimarySelectionState {
&self.primary_selection_state
&self.pinnacle.primary_selection_state
}
}
delegate_primary_selection!(State);
impl DataControlHandler for State {
fn data_control_state(&self) -> &DataControlState {
&self.data_control_state
&self.pinnacle.data_control_state
}
}
delegate_data_control!(State);
@ -407,28 +418,29 @@ impl SeatHandler for State {
type TouchFocus = PointerFocusTarget;
fn seat_state(&mut self) -> &mut SeatState<Self> {
&mut self.seat_state
&mut self.pinnacle.seat_state
}
fn cursor_image(&mut self, _seat: &Seat<Self>, image: CursorImageStatus) {
self.cursor_status = image;
self.pinnacle.cursor_status = image;
}
fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&Self::KeyboardFocus>) {
let focus_client = focused.and_then(|foc_target| {
self.display_handle
self.pinnacle
.display_handle
.get_client(foc_target.wl_surface()?.id())
.ok()
});
set_data_device_focus(&self.display_handle, seat, focus_client.clone());
set_primary_focus(&self.display_handle, seat, focus_client);
set_data_device_focus(&self.pinnacle.display_handle, seat, focus_client.clone());
set_primary_focus(&self.pinnacle.display_handle, seat, focus_client);
}
}
delegate_seat!(State);
impl ShmHandler for State {
fn shm_state(&self) -> &ShmState {
&self.shm_state
&self.pinnacle.shm_state
}
}
delegate_shm!(State);
@ -466,17 +478,25 @@ impl FractionalScaleHandler for State {
desktop::utils::surface_primary_scanout_output(&root, states)
.or_else(|| {
self.window_for_surface(&root).and_then(|window| {
self.space.outputs_for_element(&window).first().cloned()
self.pinnacle
.space
.outputs_for_element(&window)
.first()
.cloned()
})
})
})
} else {
self.window_for_surface(&root).and_then(|window| {
self.space.outputs_for_element(&window).first().cloned()
self.pinnacle
.space
.outputs_for_element(&window)
.first()
.cloned()
})
}
})
.or_else(|| self.space.outputs().next().cloned());
.or_else(|| self.pinnacle.space.outputs().next().cloned());
if let Some(output) = primary_scanout_output {
fractional_scale::with_fractional_scale(states, |fractional_scale| {
fractional_scale.set_preferred_scale(output.current_scale().fractional_scale());
@ -494,7 +514,7 @@ delegate_presentation!(State);
impl WlrLayerShellHandler for State {
fn shell_state(&mut self) -> &mut WlrLayerShellState {
&mut self.layer_shell_state
&mut self.pinnacle.layer_shell_state
}
fn new_layer_surface(
@ -508,7 +528,7 @@ impl WlrLayerShellHandler for State {
let output = output
.as_ref()
.and_then(Output::from_resource)
.or_else(|| self.space.outputs().next().cloned());
.or_else(|| self.pinnacle.space.outputs().next().cloned());
let Some(output) = output else {
error!("New layer surface, but there was no output to map it on");
@ -521,14 +541,14 @@ impl WlrLayerShellHandler for State {
error!("Failed to map layer surface: {err}");
}
self.loop_handle.insert_idle(move |state| {
self.pinnacle.loop_handle.insert_idle(move |state| {
state.request_layout(&output);
});
}
fn layer_destroyed(&mut self, surface: wlr_layer::LayerSurface) {
let mut output: Option<Output> = None;
if let Some((mut map, layer, op)) = self.space.outputs().find_map(|o| {
if let Some((mut map, layer, op)) = self.pinnacle.space.outputs().find_map(|o| {
let map = layer_map_for_output(o);
let layer = map
.layers()
@ -541,7 +561,7 @@ impl WlrLayerShellHandler for State {
}
if let Some(output) = output {
self.loop_handle.insert_idle(move |state| {
self.pinnacle.loop_handle.insert_idle(move |state| {
state.request_layout(&output);
});
}
@ -567,7 +587,7 @@ delegate_screencopy!(State);
impl GammaControlHandler for State {
fn gamma_control_manager_state(&mut self) -> &mut GammaControlManagerState {
&mut self.gamma_control_manager_state
&mut self.pinnacle.gamma_control_manager_state
}
fn get_gamma_size(&mut self, output: &Output) -> Option<u32> {
@ -636,13 +656,13 @@ impl State {
}
let (root_global_loc, output) = if let Some(win) = self.window_for_surface(&root) {
let win_geo = self.space.element_geometry(&win)?;
let win_geo = self.pinnacle.space.element_geometry(&win)?;
(win_geo.loc, self.focused_output()?.clone())
} else {
self.space.outputs().find_map(|op| {
self.pinnacle.space.outputs().find_map(|op| {
let layer_map = layer_map_for_output(op);
let layer = layer_map.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)?;
let output_loc = self.space.output_geometry(op)?.loc;
let output_loc = self.pinnacle.space.output_geometry(op)?.loc;
Some((
layer_map.layer_geometry(layer)?.loc + output_loc,
op.clone(),
@ -656,7 +676,7 @@ impl State {
root_global_loc + get_popup_toplevel_coords(&PopupKind::Xdg(popup.clone()))
};
let mut output_geo = self.space.output_geometry(&output)?;
let mut output_geo = self.pinnacle.space.output_geometry(&output)?;
// Make local to parent
output_geo.loc -= parent_global_loc;

View file

@ -31,7 +31,7 @@ use crate::{
impl XdgShellHandler for State {
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
&mut self.xdg_shell_state
&mut self.pinnacle.xdg_shell_state
}
fn new_toplevel(&mut self, surface: ToplevelSurface) {
@ -43,24 +43,24 @@ impl XdgShellHandler for State {
});
let window = WindowElement::new(Window::new_wayland_window(surface.clone()));
self.new_windows.push(window);
self.pinnacle.new_windows.push(window);
}
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
tracing::debug!("toplevel destroyed");
self.windows.retain(|window| {
self.pinnacle.windows.retain(|window| {
window
.wl_surface()
.is_some_and(|surf| &surf != surface.wl_surface())
});
self.z_index_stack.retain(|window| {
self.pinnacle.z_index_stack.retain(|window| {
window
.wl_surface()
.is_some_and(|surf| &surf != surface.wl_surface())
});
for output in self.space.outputs() {
for output in self.pinnacle.space.outputs() {
output.with_state_mut(|state| {
state.focus_stack.stack.retain(|window| {
window
@ -87,7 +87,8 @@ impl XdgShellHandler for State {
toplevel.send_configure();
}
}
self.seat
self.pinnacle
.seat
.get_keyboard()
.expect("Seat had no keyboard")
.set_focus(self, focus, SERIAL_COUNTER.next_serial());
@ -101,14 +102,18 @@ impl XdgShellHandler for State {
self.position_popup(&surface);
if let Err(err) = self.popup_manager.track_popup(PopupKind::from(surface)) {
if let Err(err) = self
.pinnacle
.popup_manager
.track_popup(PopupKind::from(surface))
{
tracing::warn!("failed to track popup: {}", err);
}
}
fn popup_destroyed(&mut self, _surface: PopupSurface) {
// TODO: only schedule on the outputs the popup is on
for output in self.space.outputs().cloned().collect::<Vec<_>>() {
for output in self.pinnacle.space.outputs().cloned().collect::<Vec<_>>() {
self.schedule_render(&output);
}
}
@ -164,7 +169,7 @@ impl XdgShellHandler for State {
self.window_for_surface(&root)
.map(KeyboardFocusTarget::Window)
.or_else(|| {
self.space.outputs().find_map(|op| {
self.pinnacle.space.outputs().find_map(|op| {
layer_map_for_output(op)
.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)
.cloned()
@ -173,6 +178,7 @@ impl XdgShellHandler for State {
})
}) {
if let Ok(mut grab) = self
.pinnacle
.popup_manager
.grab_popup(root, popup_kind, &seat, serial)
{
@ -217,17 +223,23 @@ impl XdgShellHandler for State {
.as_ref()
.and_then(Output::from_resource)
.or_else(|| {
self.window_for_surface(wl_surface)
.and_then(|window| self.space.outputs_for_element(&window).first().cloned())
self.window_for_surface(wl_surface).and_then(|window| {
self.pinnacle
.space
.outputs_for_element(&window)
.first()
.cloned()
})
});
if let Some(output) = output {
let Some(geometry) = self.space.output_geometry(&output) else {
let Some(geometry) = self.pinnacle.space.output_geometry(&output) else {
surface.send_configure();
return;
};
let client = self
.pinnacle
.display_handle
.get_client(wl_surface.id())
.expect("wl_surface had no client");

View file

@ -32,7 +32,7 @@ use crate::{
impl XwmHandler for State {
fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm {
self.xwm.as_mut().expect("xwm not in state")
self.pinnacle.xwm.as_mut().expect("xwm not in state")
}
fn new_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
@ -48,15 +48,18 @@ impl XwmHandler for State {
}
let window = WindowElement::new(Window::new_x11_window(surface));
self.space.map_element(window.clone(), (0, 0), true);
self.pinnacle
.space
.map_element(window.clone(), (0, 0), true);
let bbox = self
.pinnacle
.space
.element_bbox(&window)
.expect("called element_bbox on an unmapped window");
let output_size = self
.focused_output()
.and_then(|op| self.space.output_geometry(op))
.and_then(|op| self.pinnacle.space.output_geometry(op))
.map(|geo| geo.size)
.unwrap_or((2, 2).into());
@ -78,7 +81,7 @@ impl XwmHandler for State {
unreachable!()
};
self.space.map_element(window.clone(), loc, true);
self.pinnacle.space.map_element(window.clone(), loc, true);
surface.set_mapped(true).expect("failed to map x11 window");
let bbox = Rectangle::from_loc_and_size(loc, bbox.size);
@ -100,7 +103,7 @@ impl XwmHandler for State {
}
// TODO: will an unmap -> map duplicate the window
self.windows.push(window.clone());
self.pinnacle.windows.push(window.clone());
self.raise_window(window.clone(), true);
self.apply_window_rules(&window);
@ -110,8 +113,9 @@ impl XwmHandler for State {
self.request_layout(&output);
}
self.loop_handle.insert_idle(move |state| {
self.pinnacle.loop_handle.insert_idle(move |state| {
state
.pinnacle
.seat
.get_keyboard()
.expect("Seat had no keyboard") // FIXME: actually handle error
@ -132,7 +136,7 @@ impl XwmHandler for State {
let window = WindowElement::new(Window::new_x11_window(surface));
self.windows.push(window.clone());
self.pinnacle.windows.push(window.clone());
if let Some(output) = self.focused_output() {
window.place_on_output(output);
@ -141,7 +145,7 @@ impl XwmHandler for State {
output.with_state_mut(|state| state.focus_stack.set_focus(window.clone()));
}
self.space.map_element(window.clone(), loc, true);
self.pinnacle.space.map_element(window.clone(), loc, true);
self.raise_window(window.clone(), true);
}
@ -159,7 +163,7 @@ impl XwmHandler for State {
fn unmapped_window(&mut self, _xwm: XwmId, surface: X11Surface) {
trace!("XwmHandler::unmapped_window");
for output in self.space.outputs() {
for output in self.pinnacle.space.outputs() {
output.with_state_mut(|state| {
state.focus_stack.stack.retain(|win| {
win.wl_surface()
@ -169,18 +173,21 @@ impl XwmHandler for State {
}
let win = self
.pinnacle
.space
.elements()
.find(|elem| matches!(elem.x11_surface(), Some(surf) if surf == &surface))
.cloned();
if let Some(win) = win {
self.windows
self.pinnacle
.windows
.retain(|elem| win.wl_surface() != elem.wl_surface());
self.z_index_stack
self.pinnacle
.z_index_stack
.retain(|elem| win.wl_surface() != elem.wl_surface());
self.space.unmap_elem(&win);
self.pinnacle.space.unmap_elem(&win);
if let Some(output) = win.output(self) {
self.request_layout(&output);
@ -196,7 +203,8 @@ impl XwmHandler for State {
}
}
self.seat
self.pinnacle
.seat
.get_keyboard()
.expect("Seat had no keyboard")
.set_focus(self, focus, SERIAL_COUNTER.next_serial());
@ -213,7 +221,7 @@ impl XwmHandler for State {
fn destroyed_window(&mut self, _xwm: XwmId, surface: X11Surface) {
trace!("XwmHandler::destroyed_window");
for output in self.space.outputs() {
for output in self.pinnacle.space.outputs() {
output.with_state_mut(|state| {
state.focus_stack.stack.retain(|win| {
win.wl_surface()
@ -223,6 +231,7 @@ impl XwmHandler for State {
}
let win = self
.pinnacle
.windows
.iter()
.find(|elem| {
@ -238,10 +247,12 @@ impl XwmHandler for State {
// INFO: comparing the windows doesn't work so wlsurface it is
// self.windows.retain(|elem| &win != elem);
self.windows
self.pinnacle
.windows
.retain(|elem| win.wl_surface() != elem.wl_surface());
self.z_index_stack
self.pinnacle
.z_index_stack
.retain(|elem| win.wl_surface() != elem.wl_surface());
if let Some(output) = win.output(self) {
@ -258,7 +269,8 @@ impl XwmHandler for State {
}
}
self.seat
self.pinnacle
.seat
.get_keyboard()
.expect("Seat had no keyboard")
.set_focus(self, focus, SERIAL_COUNTER.next_serial());
@ -281,6 +293,7 @@ impl XwmHandler for State {
) {
trace!("XwmHandler::configure_request");
let floating_or_override_redirect = self
.pinnacle
.windows
.iter()
.find(|win| win.x11_surface() == Some(&window))
@ -320,6 +333,7 @@ impl XwmHandler for State {
_above: Option<smithay::reexports::x11rb::protocol::xproto::Window>,
) {
let Some(win) = self
.pinnacle
.space
.elements()
.find(|elem| {
@ -331,7 +345,7 @@ impl XwmHandler for State {
return;
};
self.space.map_element(win, geometry.loc, true);
self.pinnacle.space.map_element(win, geometry.loc, true);
}
fn maximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
@ -416,7 +430,7 @@ impl XwmHandler for State {
resize_edge: smithay::xwayland::xwm::ResizeEdge,
) {
let Some(wl_surf) = window.wl_surface() else { return };
let seat = self.seat.clone();
let seat = self.pinnacle.seat.clone();
// We use the server one and not the client because windows like Steam don't provide
// GrabStartData, so we need to create it ourselves.
@ -432,7 +446,7 @@ impl XwmHandler for State {
fn move_request(&mut self, _xwm: XwmId, window: X11Surface, button: u32) {
let Some(wl_surf) = window.wl_surface() else { return };
let seat = self.seat.clone();
let seat = self.pinnacle.seat.clone();
// We use the server one and not the client because windows like Steam don't provide
// GrabStartData, so we need to create it ourselves.
@ -446,7 +460,8 @@ impl XwmHandler for State {
}
fn allow_selection_access(&mut self, xwm: XwmId, _selection: SelectionTarget) -> bool {
self.seat
self.pinnacle
.seat
.get_keyboard()
.and_then(|kb| kb.current_focus())
.is_some_and(|focus| {
@ -468,7 +483,9 @@ impl XwmHandler for State {
) {
match selection {
SelectionTarget::Clipboard => {
if let Err(err) = request_data_device_client_selection(&self.seat, mime_type, fd) {
if let Err(err) =
request_data_device_client_selection(&self.pinnacle.seat, mime_type, fd)
{
error!(
?err,
"Failed to request current wayland clipboard for XWayland"
@ -476,7 +493,9 @@ impl XwmHandler for State {
}
}
SelectionTarget::Primary => {
if let Err(err) = request_primary_client_selection(&self.seat, mime_type, fd) {
if let Err(err) =
request_primary_client_selection(&self.pinnacle.seat, mime_type, fd)
{
error!(
?err,
"Failed to request current wayland primary selection for XWayland"
@ -489,10 +508,20 @@ impl XwmHandler for State {
fn new_selection(&mut self, _xwm: XwmId, selection: SelectionTarget, mime_types: Vec<String>) {
match selection {
SelectionTarget::Clipboard => {
set_data_device_selection(&self.display_handle, &self.seat, mime_types, ());
set_data_device_selection(
&self.pinnacle.display_handle,
&self.pinnacle.seat,
mime_types,
(),
);
}
SelectionTarget::Primary => {
set_primary_selection(&self.display_handle, &self.seat, mime_types, ());
set_primary_selection(
&self.pinnacle.display_handle,
&self.pinnacle.seat,
mime_types,
(),
);
}
}
}
@ -500,13 +529,13 @@ impl XwmHandler for State {
fn cleared_selection(&mut self, _xwm: XwmId, selection: SelectionTarget) {
match selection {
SelectionTarget::Clipboard => {
if current_data_device_selection_userdata(&self.seat).is_some() {
clear_data_device_selection(&self.display_handle, &self.seat);
if current_data_device_selection_userdata(&self.pinnacle.seat).is_some() {
clear_data_device_selection(&self.pinnacle.display_handle, &self.pinnacle.seat);
}
}
SelectionTarget::Primary => {
if current_primary_selection_userdata(&self.seat).is_some() {
clear_primary_selection(&self.display_handle, &self.seat);
if current_primary_selection_userdata(&self.pinnacle.seat).is_some() {
clear_primary_selection(&self.pinnacle.display_handle, &self.pinnacle.seat);
}
}
}
@ -514,12 +543,13 @@ impl XwmHandler for State {
}
impl State {
pub fn fixup_xwayland_internal_z_indices(&mut self) {
let Some(xwm) = self.xwm.as_mut() else {
pub fn fixup_xwayland_window_layering(&mut self) {
let Some(xwm) = self.pinnacle.xwm.as_mut() else {
return;
};
let x11_wins = self
.pinnacle
.space
.elements()
.filter(|win| win.is_on_active_tag())

View file

@ -171,14 +171,16 @@ impl State {
{
let point: Point<f64, Logical> = point.into();
let output = self.space.outputs().find(|op| {
self.space
let output = self.pinnacle.space.outputs().find(|op| {
self.pinnacle
.space
.output_geometry(op)
.expect("called output_geometry on unmapped output (this shouldn't happen here)")
.contains(point.to_i32_round())
})?;
let output_geo = self
.pinnacle
.space
.output_geometry(output)
.expect("called output_geometry on unmapped output");
@ -186,6 +188,7 @@ impl State {
let mut fullscreen_and_up_split_at = 0;
for (i, win) in self
.pinnacle
.space
.elements()
.rev()
@ -223,6 +226,7 @@ impl State {
|windows: &[&WindowElement]| -> Option<(PointerFocusTarget, Point<i32, Logical>)> {
windows.iter().find_map(|win| {
let loc = self
.pinnacle
.space
.element_location(win)
.expect("called elem loc on unmapped win")
@ -246,6 +250,7 @@ impl State {
.or_else(|| {
window_under(
&self
.pinnacle
.space
.elements()
.rev()
@ -258,6 +263,7 @@ impl State {
.or_else(|| {
window_under(
&self
.pinnacle
.space
.elements()
.rev()
@ -271,7 +277,7 @@ impl State {
/// Update the pointer focus if it's different from the previous one.
pub fn update_pointer_focus(&mut self) {
let Some(pointer) = self.seat.get_pointer() else {
let Some(pointer) = self.pinnacle.seat.get_pointer() else {
return;
};
@ -291,7 +297,7 @@ impl State {
&MotionEvent {
location,
serial: SERIAL_COUNTER.next_serial(),
time: Duration::from(self.clock.now()).as_millis() as u32,
time: Duration::from(self.pinnacle.clock.now()).as_millis() as u32,
},
);
pointer.frame(self);
@ -302,10 +308,14 @@ impl State {
let time = event.time_msec();
let press_state = event.state();
let reload_keybind = self.input_state.reload_keybind;
let kill_keybind = self.input_state.kill_keybind;
let reload_keybind = self.pinnacle.input_state.reload_keybind;
let kill_keybind = self.pinnacle.input_state.kill_keybind;
let keyboard = self.seat.get_keyboard().expect("Seat has no keyboard");
let keyboard = self
.pinnacle
.seat
.get_keyboard()
.expect("Seat has no keyboard");
let modifiers = keyboard.modifier_state();
@ -318,11 +328,11 @@ impl State {
}
// FIXME: Leds only update once another key is pressed.
for device in self.input_state.libinput_devices.iter_mut() {
for device in self.pinnacle.input_state.libinput_devices.iter_mut() {
device.led_update(leds);
}
for layer in self.layer_shell_state.layer_surfaces().rev() {
for layer in self.pinnacle.layer_shell_state.layer_surfaces().rev() {
let data = compositor::with_states(layer.wl_surface(), |states| {
*states.cached_state.current::<LayerSurfaceCachedState>()
});
@ -332,18 +342,19 @@ impl State {
wlr_layer::Layer::Top | wlr_layer::Layer::Overlay
)
{
let layer_surface = self.space.outputs().find_map(|op| {
let layer_surface = self.pinnacle.space.outputs().find_map(|op| {
let map = layer_map_for_output(op);
let cloned = map.layers().find(|l| l.layer_surface() == &layer).cloned();
cloned
});
if let Some(layer_surface) = layer_surface {
match self.input_state.exclusive_layer_focus_stack.last() {
match self.pinnacle.input_state.exclusive_layer_focus_stack.last() {
Some(focus) => {
let layer_focus = KeyboardFocusTarget::LayerSurface(layer_surface);
if &layer_focus != focus {
self.input_state
self.pinnacle
.input_state
.exclusive_layer_focus_stack
.push(layer_focus);
}
@ -351,10 +362,12 @@ impl State {
// Push the previous focus on as this is the first exclusive layer surface
// on screen. This lets us restore it when that layer surface goes away.
None => {
self.input_state
self.pinnacle
.input_state
.exclusive_layer_focus_stack
.extend(keyboard.current_focus());
self.input_state
self.pinnacle
.input_state
.exclusive_layer_focus_stack
.push(KeyboardFocusTarget::LayerSurface(layer_surface));
}
@ -363,13 +376,19 @@ impl State {
}
}
while let Some(last) = self.input_state.exclusive_layer_focus_stack.pop() {
while let Some(last) = self.pinnacle.input_state.exclusive_layer_focus_stack.pop() {
if last.alive() {
// If it's not empty then there's another exclusive layer surface
// underneath. Otherwise `last` is the previous keyboard focus
// and we don't need the stack anymore.
if !self.input_state.exclusive_layer_focus_stack.is_empty() {
self.input_state
if !self
.pinnacle
.input_state
.exclusive_layer_focus_stack
.is_empty()
{
self.pinnacle
.input_state
.exclusive_layer_focus_stack
.push(last.clone());
}
@ -392,9 +411,17 @@ impl State {
let mod_sym = keysym.modified_sym();
if let (Some(sender), _) | (None, Some(sender)) = (
state.input_state.keybinds.get(&(mod_mask, mod_sym)),
state
.pinnacle
.input_state
.keybinds
.get(&(mod_mask, mod_sym)),
raw_sym.and_then(|raw_sym| {
state.input_state.keybinds.get(&(mod_mask, *raw_sym))
state
.pinnacle
.input_state
.keybinds
.get(&(mod_mask, *raw_sym))
}),
) {
return FilterResult::Intercept(KeyAction::CallCallback(sender.clone()));
@ -429,7 +456,7 @@ impl State {
}
Some(KeyAction::ReloadConfig) => {
info!("Reloading config");
self.start_config(Some(self.config.dir(&self.xdg_base_dirs)))
self.start_config(Some(self.pinnacle.config.dir(&self.pinnacle.xdg_base_dirs)))
.expect("failed to restart config");
}
None => (),
@ -437,8 +464,16 @@ impl State {
}
fn pointer_button<I: InputBackend>(&mut self, event: I::PointerButtonEvent) {
let pointer = self.seat.get_pointer().expect("Seat has no pointer"); // FIXME: handle err
let keyboard = self.seat.get_keyboard().expect("Seat has no keyboard"); // FIXME: handle err
let pointer = self
.pinnacle
.seat
.get_pointer()
.expect("Seat has no pointer"); // FIXME: handle err
let keyboard = self
.pinnacle
.seat
.get_keyboard()
.expect("Seat has no keyboard"); // FIXME: handle err
let serial = SERIAL_COUNTER.next_serial();
@ -456,6 +491,7 @@ impl State {
};
if let Some(stream) = self
.pinnacle
.input_state
.mousebinds
.get(&(mod_mask, button, mouse_edge))
@ -489,7 +525,7 @@ impl State {
keyboard.set_focus(self, focus.to_keyboard_focus_target(self), serial);
}
for window in self.space.elements() {
for window in self.pinnacle.space.elements() {
if let Some(toplevel) = window.toplevel() {
toplevel.send_configure();
}
@ -556,7 +592,11 @@ impl State {
frame = frame.stop(Axis::Vertical);
}
let pointer = self.seat.get_pointer().expect("Seat has no pointer");
let pointer = self
.pinnacle
.seat
.get_pointer()
.expect("Seat has no pointer");
pointer.axis(self, frame);
pointer.frame(self);
@ -566,14 +606,15 @@ impl State {
///
/// This returns the nearest point inside an output.
fn clamp_coords(&self, pos: Point<f64, Logical>) -> Point<f64, Logical> {
if self.space.outputs().next().is_none() {
if self.pinnacle.space.outputs().next().is_none() {
return pos;
}
let (pos_x, pos_y) = pos.into();
let nearest_points = self.space.outputs().map(|op| {
let nearest_points = self.pinnacle.space.outputs().map(|op| {
let size = self
.pinnacle
.space
.output_geometry(op)
.expect("called output_geometry on unmapped output")
@ -599,24 +640,30 @@ impl State {
/// This *should* only be generated on the winit backend.
/// Unless there's a case where it's generated on udev that I'm unaware of.
fn pointer_motion_absolute<I: InputBackend>(&mut self, event: I::PointerMotionAbsoluteEvent) {
let Some(pointer) = self.seat.get_pointer() else {
let Some(pointer) = self.pinnacle.seat.get_pointer() else {
tracing::error!("Pointer motion absolute received with no pointer on seat");
return;
};
let Some(output) = self.space.outputs().next() else {
let Some(output) = self.pinnacle.space.outputs().next() else {
return;
};
let Some(output_geo) = self.space.output_geometry(output) else {
let Some(output_geo) = self.pinnacle.space.output_geometry(output) else {
unreachable!("output should have a geometry as it was mapped");
};
let pointer_loc = event.position_transformed(output_geo.size) + output_geo.loc.to_f64();
let serial = SERIAL_COUNTER.next_serial();
if let Some(output) = self.space.output_under(pointer_loc).next().cloned() {
self.output_focus_stack.set_focus(output);
if let Some(output) = self
.pinnacle
.space
.output_under(pointer_loc)
.next()
.cloned()
{
self.pinnacle.output_focus_stack.set_focus(output);
}
let pointer_focus = self.pointer_focus_target_under(pointer_loc);
@ -635,7 +682,7 @@ impl State {
}
fn pointer_motion<I: InputBackend>(&mut self, event: I::PointerMotionEvent) {
let Some(pointer) = self.seat.get_pointer() else {
let Some(pointer) = self.pinnacle.seat.get_pointer() else {
tracing::error!("Pointer motion received with no pointer on seat");
return;
};
@ -647,8 +694,14 @@ impl State {
// this event is never generated by winit
pointer_loc = self.clamp_coords(pointer_loc);
if let Some(output) = self.space.output_under(pointer_loc).next().cloned() {
self.output_focus_stack.set_focus(output);
if let Some(output) = self
.pinnacle
.space
.output_under(pointer_loc)
.next()
.cloned()
{
self.pinnacle.output_focus_stack.set_focus(output);
}
let surface_under = self.pointer_focus_target_under(pointer_loc);

View file

@ -8,7 +8,8 @@ impl State {
let mut device = match event {
InputEvent::DeviceAdded { device } => device.clone(),
InputEvent::DeviceRemoved { device } => {
self.input_state
self.pinnacle
.input_state
.libinput_devices
.retain(|dev| dev != device);
return;
@ -16,14 +17,14 @@ impl State {
_ => return,
};
if self.input_state.libinput_devices.contains(&device) {
if self.pinnacle.input_state.libinput_devices.contains(&device) {
return;
}
for setting in self.input_state.libinput_settings.values() {
for setting in self.pinnacle.input_state.libinput_settings.values() {
setting(&mut device);
}
self.input_state.libinput_devices.push(device);
self.pinnacle.input_state.libinput_devices.push(device);
}
}

View file

@ -33,7 +33,8 @@ impl State {
) {
let windows_on_foc_tags = output.with_state(|state| {
let focused_tags = state.focused_tags().collect::<Vec<_>>();
self.windows
self.pinnacle
.windows
.iter()
.filter(|win| !win.is_x11_override_redirect())
.filter(|win| {
@ -52,7 +53,11 @@ impl State {
})
.cloned();
let output_geo = self.space.output_geometry(output).expect("no output geo");
let output_geo = self
.pinnacle
.space
.output_geometry(output)
.expect("no output geo");
let non_exclusive_geo = {
let map = layer_map_for_output(output);
@ -125,7 +130,7 @@ impl State {
WindowSurface::X11(_) => {
let loc = win.with_state_mut(|state| state.target_loc.take());
if let Some(loc) = loc {
self.space.map_element(win.clone(), loc, false);
self.pinnacle.space.map_element(win.clone(), loc, false);
}
}
}
@ -133,17 +138,20 @@ impl State {
}
for (loc, window) in non_pending_wins {
self.space.map_element(window, loc, false);
self.pinnacle.space.map_element(window, loc, false);
}
// HACK and FIXME:
// FIXME:
// We are sending frames here to get offscreen windows to commit and map.
// Obviously this is a bad way to do this but its a bandaid solution
// until decent transactional layout applications are implemented.
for (win, _serial) in pending_wins {
win.send_frame(output, self.clock.now(), Some(Duration::ZERO), |_, _| {
Some(output.clone())
});
win.send_frame(
output,
self.pinnacle.clock.now(),
Some(Duration::ZERO),
|_, _| Some(output.clone()),
);
}
self.fixup_z_layering();
@ -151,15 +159,15 @@ impl State {
/// Swaps two windows in the main window vec and updates all windows.
pub fn swap_window_positions(&mut self, win1: &WindowElement, win2: &WindowElement) {
let win1_index = self.windows.iter().position(|win| win == win1);
let win2_index = self.windows.iter().position(|win| win == win2);
let win1_index = self.pinnacle.windows.iter().position(|win| win == win1);
let win2_index = self.pinnacle.windows.iter().position(|win| win == win2);
if let (Some(first), Some(second)) = (win1_index, win2_index) {
self.windows.swap(first, second);
self.pinnacle.windows.swap(first, second);
if let Some(output) = win1.output(self) {
self.request_layout(&output);
}
self.layout_state.pending_swap = true;
self.pinnacle.layout_state.pending_swap = true;
}
}
}
@ -179,14 +187,15 @@ pub struct LayoutState {
impl State {
pub fn request_layout(&mut self, output: &Output) {
let Some(sender) = self.layout_state.layout_request_sender.as_ref() else {
let Some(sender) = self.pinnacle.layout_state.layout_request_sender.as_ref() else {
warn!("Layout requested but no client has connected to the layout service");
return;
};
let windows_on_foc_tags = output.with_state(|state| {
let focused_tags = state.focused_tags().collect::<Vec<_>>();
self.windows
self.pinnacle
.windows
.iter()
.filter(|win| !win.is_x11_override_redirect())
.filter(|win| {
@ -221,12 +230,14 @@ impl State {
output.with_state(|state| state.focused_tags().map(|tag| tag.id().0).collect());
let id = self
.pinnacle
.layout_state
.id_maps
.entry(output.clone())
.or_insert(LayoutRequestId(0));
self.layout_state
self.pinnacle
.layout_state
.pending_requests
.entry(output.clone())
.or_default()
@ -261,6 +272,7 @@ impl State {
};
let old_requests = self
.pinnacle
.layout_state
.old_requests
.entry(output.clone())
@ -271,6 +283,7 @@ impl State {
}
let pending = self
.pinnacle
.layout_state
.pending_requests
.entry(output.clone())
@ -312,7 +325,7 @@ impl State {
self.schedule_render(&output);
self.layout_state.pending_swap = false;
self.pinnacle.layout_state.pending_swap = false;
Ok(())
}

View file

@ -132,18 +132,19 @@ async fn main() -> anyhow::Result<()> {
event_loop.run(None, &mut state, |state| {
state.update_pointer_focus();
state.fixup_z_layering();
state.space.refresh();
state.popup_manager.cleanup();
state.pinnacle.space.refresh();
state.pinnacle.popup_manager.cleanup();
state
.pinnacle
.display_handle
.flush_clients()
.expect("failed to flush client buffers");
// TODO: couple these or something, this is really error-prone
assert_eq!(
state.windows.len(),
state.z_index_stack.len(),
state.pinnacle.windows.len(),
state.pinnacle.z_index_stack.len(),
"Length of `windows` and `z_index_stack` are different. \
If you see this, report it to the developer."
);
@ -157,6 +158,8 @@ async fn main() -> anyhow::Result<()> {
fn set_log_panic_hook() {
let hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
let _span = tracing::error_span!("panic");
let _span = _span.enter();
error!("Panic occurred! Attempting to log backtrace");
let buffer = gag::BufferRedirect::stderr();
if let Ok(buffer) = buffer {

View file

@ -28,6 +28,7 @@ impl OutputName {
/// Get the output with this name.
pub fn output(&self, state: &State) -> Option<Output> {
state
.pinnacle
.space
.outputs()
.find(|output| output.name() == self.0)
@ -90,8 +91,8 @@ impl State {
output.change_current_state(mode, transform, scale, location);
if let Some(location) = location {
info!(?location);
self.space.map_output(output, location);
self.signal_state.output_move.signal(|buf| {
self.pinnacle.space.map_output(output, location);
self.pinnacle.signal_state.output_move.signal(|buf| {
buf.push_back(OutputMoveResponse {
output_name: Some(output.name()),
x: Some(location.x),
@ -101,8 +102,8 @@ impl State {
}
if mode.is_some() || transform.is_some() || scale.is_some() {
layer_map_for_output(output).arrange();
self.signal_state.output_resize.signal(|buf| {
let geo = self.space.output_geometry(output);
self.pinnacle.signal_state.output_resize.signal(|buf| {
let geo = self.pinnacle.space.output_geometry(output);
buf.push_back(OutputResizeResponse {
output_name: Some(output.name()),
logical_width: geo.map(|geo| geo.size.w as u32),

View file

@ -349,7 +349,7 @@ impl State {
/// Schedule a new render. This does nothing on the winit backend.
pub fn schedule_render(&mut self, output: &Output) {
if let Backend::Udev(udev) = &mut self.backend {
udev.schedule_render(&self.loop_handle, output);
udev.schedule_render(&self.pinnacle.loop_handle, output);
}
}
}

View file

@ -53,11 +53,14 @@ use crate::input::InputState;
pub struct State {
/// Which backend is currently running
pub backend: Backend,
pub pinnacle: Pinnacle,
}
pub struct Pinnacle {
/// A loop signal used to stop the compositor
pub loop_signal: LoopSignal,
/// A handle to the event loop
pub loop_handle: LoopHandle<'static, Self>,
pub loop_handle: LoopHandle<'static, State>,
pub display_handle: DisplayHandle,
pub clock: Clock<Monotonic>,
@ -67,7 +70,7 @@ pub struct State {
pub compositor_state: CompositorState,
pub data_device_state: DataDeviceState,
pub seat_state: SeatState<Self>,
pub seat_state: SeatState<State>,
pub shm_state: ShmState,
pub output_manager_state: OutputManagerState,
pub xdg_shell_state: XdgShellState,
@ -150,8 +153,10 @@ impl State {
info!("Fd raise success!");
}
loop_handle.insert_source(socket, |stream, _metadata, data| {
data.display_handle
loop_handle.insert_source(socket, |stream, _metadata, state| {
state
.pinnacle
.display_handle
.insert_client(stream, Arc::new(ClientState::default()))
.expect("Could not insert client into loop handle");
})?;
@ -191,7 +196,7 @@ impl State {
display,
} => {
let mut wm = X11Wm::start_wm(
state.loop_handle.clone(),
state.pinnacle.loop_handle.clone(),
dh_clone.clone(),
connection,
client,
@ -209,19 +214,19 @@ impl State {
tracing::debug!("setting xwm and xdisplay");
state.xwm = Some(wm);
state.xdisplay = Some(display);
state.pinnacle.xwm = Some(wm);
state.pinnacle.xdisplay = Some(display);
std::env::set_var("DISPLAY", format!(":{display}"));
if let Err(err) =
state.start_config(Some(state.config.dir(&state.xdg_base_dirs)))
{
if let Err(err) = state.start_config(Some(
state.pinnacle.config.dir(&state.pinnacle.xdg_base_dirs),
)) {
panic!("failed to start config: {err}");
}
}
XWaylandEvent::Exited => {
state.xwm.take();
state.pinnacle.xwm.take();
}
});
if let Err(err) = res {
@ -241,69 +246,74 @@ impl State {
let state = Self {
backend,
loop_signal,
loop_handle,
display_handle: display_handle.clone(),
clock: Clock::<Monotonic>::new(),
compositor_state: CompositorState::new::<Self>(&display_handle),
data_device_state: DataDeviceState::new::<Self>(&display_handle),
seat_state,
shm_state: ShmState::new::<Self>(&display_handle, vec![]),
space: Space::<WindowElement>::default(),
cursor_status: CursorImageStatus::default_named(),
output_manager_state: OutputManagerState::new_with_xdg_output::<Self>(&display_handle),
xdg_shell_state: XdgShellState::new::<Self>(&display_handle),
viewporter_state: ViewporterState::new::<Self>(&display_handle),
fractional_scale_manager_state: FractionalScaleManagerState::new::<Self>(
&display_handle,
),
primary_selection_state,
layer_shell_state: WlrLayerShellState::new::<Self>(&display_handle),
data_control_state,
screencopy_manager_state: ScreencopyManagerState::new::<Self, _>(
&display_handle,
|_| true,
),
gamma_control_manager_state: GammaControlManagerState::new::<Self, _>(
&display_handle,
|_| true,
),
relative_pointer_manager_state: RelativePointerManagerState::new::<Self>(
&display_handle,
),
input_state: InputState::new(),
pinnacle: Pinnacle {
loop_signal,
loop_handle,
display_handle: display_handle.clone(),
clock: Clock::<Monotonic>::new(),
compositor_state: CompositorState::new::<Self>(&display_handle),
data_device_state: DataDeviceState::new::<Self>(&display_handle),
seat_state,
shm_state: ShmState::new::<Self>(&display_handle, vec![]),
space: Space::<WindowElement>::default(),
cursor_status: CursorImageStatus::default_named(),
output_manager_state: OutputManagerState::new_with_xdg_output::<Self>(
&display_handle,
),
xdg_shell_state: XdgShellState::new::<Self>(&display_handle),
viewporter_state: ViewporterState::new::<Self>(&display_handle),
fractional_scale_manager_state: FractionalScaleManagerState::new::<Self>(
&display_handle,
),
primary_selection_state,
layer_shell_state: WlrLayerShellState::new::<Self>(&display_handle),
data_control_state,
screencopy_manager_state: ScreencopyManagerState::new::<Self, _>(
&display_handle,
|_| true,
),
gamma_control_manager_state: GammaControlManagerState::new::<Self, _>(
&display_handle,
|_| true,
),
relative_pointer_manager_state: RelativePointerManagerState::new::<Self>(
&display_handle,
),
output_focus_stack: OutputFocusStack::default(),
z_index_stack: Vec::new(),
input_state: InputState::new(),
config: Config::new(no_config, config_dir),
output_focus_stack: OutputFocusStack::default(),
z_index_stack: Vec::new(),
seat,
config: Config::new(no_config, config_dir),
dnd_icon: None,
seat,
popup_manager: PopupManager::default(),
dnd_icon: None,
windows: Vec::new(),
new_windows: Vec::new(),
popup_manager: PopupManager::default(),
xwayland,
xwm: None,
xdisplay: None,
windows: Vec::new(),
new_windows: Vec::new(),
system_processes: sysinfo::System::new_with_specifics(
RefreshKind::new().with_processes(ProcessRefreshKind::new()),
),
xwayland,
xwm: None,
xdisplay: None,
grpc_server_join_handle: None,
system_processes: sysinfo::System::new_with_specifics(
RefreshKind::new().with_processes(ProcessRefreshKind::new()),
),
xdg_base_dirs: BaseDirectories::with_prefix("pinnacle")
.context("couldn't create xdg BaseDirectories")?,
grpc_server_join_handle: None,
signal_state: SignalState::default(),
xdg_base_dirs: BaseDirectories::with_prefix("pinnacle")
.context("couldn't create xdg BaseDirectories")?,
layout_state: LayoutState::default(),
signal_state: SignalState::default(),
layout_state: LayoutState::default(),
},
};
Ok(state)
@ -317,7 +327,7 @@ impl State {
F1: Fn(&mut Self) -> bool + 'static,
F2: FnOnce(&mut Self) + 'static,
{
self.loop_handle.insert_idle(|state| {
self.pinnacle.loop_handle.insert_idle(|state| {
if !condition(state) {
state.schedule(condition, run);
} else {
@ -328,11 +338,11 @@ impl State {
pub fn shutdown(&mut self) {
info!("Shutting down Pinnacle");
self.loop_signal.stop();
if let Some(join_handle) = self.config.config_join_handle.take() {
self.pinnacle.loop_signal.stop();
if let Some(join_handle) = self.pinnacle.config.config_join_handle.take() {
join_handle.abort();
}
if let Some(shutdown_sender) = self.config.shutdown_sender.take() {
if let Some(shutdown_sender) = self.pinnacle.config.shutdown_sender.take() {
if let Err(err) = shutdown_sender.send(Ok(ShutdownWatchResponse {})) {
warn!("Failed to send shutdown signal to config: {err}");
}

View file

@ -26,6 +26,7 @@ impl TagId {
/// Get the tag associated with this id.
pub fn tag(&self, state: &State) -> Option<Tag> {
state
.pinnacle
.space
.outputs()
.flat_map(|op| op.with_state(|state| state.tags.clone()))
@ -83,7 +84,7 @@ impl Tag {
pub fn set_active(&self, active: bool, state: &mut State) {
self.0.borrow_mut().active = active;
state.signal_state.tag_active.signal(|buf| {
state.pinnacle.signal_state.tag_active.signal(|buf| {
buf.push_back(
pinnacle_api_defs::pinnacle::signal::v0alpha1::TagActiveResponse {
tag_id: Some(self.id().0),
@ -108,6 +109,7 @@ impl Tag {
/// RefCell Safety: This uses RefCells on every mapped output.
pub fn output(&self, state: &State) -> Option<Output> {
state
.pinnacle
.space
.outputs()
.find(|output| output.with_state(|state| state.tags.iter().any(|tg| tg == self)))

View file

@ -212,11 +212,13 @@ impl WithState for WindowElement {
impl State {
/// Returns the [Window] associated with a given [WlSurface].
pub fn window_for_surface(&self, surface: &WlSurface) -> Option<WindowElement> {
self.space
self.pinnacle
.space
.elements()
.find(|window| window.wl_surface().map(|s| s == *surface).unwrap_or(false))
.or_else(|| {
self.windows
self.pinnacle
.windows
.iter()
.find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface))
})
@ -227,7 +229,8 @@ impl State {
///
/// Currently only used in `ensure_initial_configure` in [`handlers`][crate::handlers].
pub fn new_window_for_surface(&self, surface: &WlSurface) -> Option<WindowElement> {
self.new_windows
self.pinnacle
.new_windows
.iter()
.find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface))
.cloned()

View file

@ -170,7 +170,7 @@ pub enum FloatingOrTiled {
impl State {
pub fn apply_window_rules(&mut self, window: &WindowElement) {
tracing::debug!("Applying window rules");
for (cond, rule) in self.config.window_rules.iter() {
for (cond, rule) in self.pinnacle.config.window_rules.iter() {
if cond.is_met(self, window) {
let WindowRule {
output,
@ -253,7 +253,7 @@ impl State {
state.floating_or_tiled =
window_state::FloatingOrTiled::Floating(rect)
});
self.space.map_element(window.clone(), *loc, false);
self.pinnacle.space.map_element(window.clone(), *loc, false);
}
window_state::FloatingOrTiled::Tiled(rect) => {
// If the window is tiled, don't set the size. Instead, set

View file

@ -30,6 +30,7 @@ impl WindowId {
/// Get the window that has this WindowId.
pub fn window(&self, state: &State) -> Option<WindowElement> {
state
.pinnacle
.windows
.iter()
.find(|win| win.with_state(|state| &state.id == self))

View file

@ -55,18 +55,19 @@ where
event_loop.run(None, &mut state, |state| {
state.fixup_z_layering();
state.space.refresh();
state.popup_manager.cleanup();
state.pinnacle.space.refresh();
state.pinnacle.popup_manager.cleanup();
state
.pinnacle
.display_handle
.flush_clients()
.expect("failed to flush client buffers");
// TODO: couple these or something, this is really error-prone
assert_eq!(
state.windows.len(),
state.z_index_stack.len(),
state.pinnacle.windows.len(),
state.pinnacle.z_index_stack.len(),
"Length of `windows` and `z_index_stack` are different. \
If you see this, report it to the developer."
);
@ -77,6 +78,7 @@ where
pub fn output_for_name(state: &State, name: &str) -> Output {
state
.pinnacle
.space
.outputs()
.find(|op| op.name() == name)

View file

@ -124,8 +124,8 @@ mod process {
sleep_secs(1);
with_state(&sender, |state| {
assert_eq!(state.windows.len(), 1);
assert_eq!(state.windows[0].class(), Some("foot".to_string()));
assert_eq!(state.pinnacle.windows.len(), 1);
assert_eq!(state.pinnacle.windows[0].class(), Some("foot".to_string()));
});
Ok(())
@ -217,9 +217,9 @@ mod window {
sleep_secs(1);
with_state(&sender, |state| {
assert_eq!(state.config.window_rules.len(), 1);
assert_eq!(state.pinnacle.config.window_rules.len(), 1);
assert_eq!(
state.config.window_rules[0],
state.pinnacle.config.window_rules[0],
(
WindowRuleCondition {
class: Some(vec!["firefox".to_string()]),
@ -254,9 +254,9 @@ mod window {
sleep_secs(1);
with_state(&sender, |state| {
assert_eq!(state.config.window_rules.len(), 2);
assert_eq!(state.pinnacle.config.window_rules.len(), 2);
assert_eq!(
state.config.window_rules[1],
state.pinnacle.config.window_rules[1],
(
WindowRuleCondition {
cond_all: Some(vec![WindowRuleCondition {
@ -297,7 +297,7 @@ mod window {
sleep_secs(1);
with_state(&sender, |state| {
assert_eq!(state.windows.len(), 1);
assert_eq!(state.pinnacle.windows.len(), 1);
});
run_lua! { |Pinnacle|
@ -307,7 +307,7 @@ mod window {
sleep_secs(1);
with_state(&sender, |state| {
assert_eq!(state.windows.len(), 0);
assert_eq!(state.pinnacle.windows.len(), 0);
});
Ok(())
@ -329,7 +329,7 @@ mod window {
with_state(&sender, |state| {
assert_eq!(
state.windows[0].with_state(|st| st
state.pinnacle.windows[0].with_state(|st| st
.tags
.iter()
.map(|tag| tag.name())
@ -347,7 +347,7 @@ mod window {
with_state(&sender, |state| {
assert_eq!(
state.windows[0].with_state(|st| st
state.pinnacle.windows[0].with_state(|st| st
.tags
.iter()
.map(|tag| tag.name())
@ -365,7 +365,7 @@ mod window {
with_state(&sender, |state| {
assert_eq!(
state.windows[0].with_state(|st| st
state.pinnacle.windows[0].with_state(|st| st
.tags
.iter()
.map(|tag| tag.name())
@ -652,8 +652,8 @@ mod output {
let original_op = output_for_name(state, DUMMY_OUTPUT_NAME);
let first_op = output_for_name(state, "First");
let original_geo = state.space.output_geometry(&original_op).unwrap();
let first_geo = state.space.output_geometry(&first_op).unwrap();
let original_geo = state.pinnacle.space.output_geometry(&original_op).unwrap();
let first_geo = state.pinnacle.space.output_geometry(&first_op).unwrap();
assert_eq!(
original_geo,
@ -674,9 +674,9 @@ mod output {
let first_op = output_for_name(state, "First");
let second_op = output_for_name(state, "Second");
let original_geo = state.space.output_geometry(&original_op).unwrap();
let first_geo = state.space.output_geometry(&first_op).unwrap();
let second_geo = state.space.output_geometry(&second_op).unwrap();
let original_geo = state.pinnacle.space.output_geometry(&original_op).unwrap();
let first_geo = state.pinnacle.space.output_geometry(&first_op).unwrap();
let second_geo = state.pinnacle.space.output_geometry(&second_op).unwrap();
assert_eq!(
original_geo,
@ -727,10 +727,10 @@ mod output {
let second_op = output_for_name(state, "Second");
let third_op = output_for_name(state, "Third");
let original_geo = state.space.output_geometry(&original_op).unwrap();
let first_geo = state.space.output_geometry(&first_op).unwrap();
let second_geo = state.space.output_geometry(&second_op).unwrap();
let third_geo = state.space.output_geometry(&third_op).unwrap();
let original_geo = state.pinnacle.space.output_geometry(&original_op).unwrap();
let first_geo = state.pinnacle.space.output_geometry(&first_op).unwrap();
let second_geo = state.pinnacle.space.output_geometry(&second_op).unwrap();
let third_geo = state.pinnacle.space.output_geometry(&third_op).unwrap();
assert_eq!(
original_geo,
@ -759,9 +759,9 @@ mod output {
let first_op = output_for_name(state, "First");
let third_op = output_for_name(state, "Third");
let original_geo = state.space.output_geometry(&original_op).unwrap();
let first_geo = state.space.output_geometry(&first_op).unwrap();
let third_geo = state.space.output_geometry(&third_op).unwrap();
let original_geo = state.pinnacle.space.output_geometry(&original_op).unwrap();
let first_geo = state.pinnacle.space.output_geometry(&first_op).unwrap();
let third_geo = state.pinnacle.space.output_geometry(&third_op).unwrap();
assert_eq!(
original_geo,
@ -793,7 +793,7 @@ async fn window_count_with_tag_is_correct() -> anyhow::Result<()> {
sleep_secs(1);
with_state(&sender, |state| assert_eq!(state.windows.len(), 1));
with_state(&sender, |state| assert_eq!(state.pinnacle.windows.len(), 1));
run_lua! { |Pinnacle|
for i = 1, 20 do
@ -803,7 +803,9 @@ async fn window_count_with_tag_is_correct() -> anyhow::Result<()> {
sleep_secs(1);
with_state(&sender, |state| assert_eq!(state.windows.len(), 21));
with_state(&sender, |state| {
assert_eq!(state.pinnacle.windows.len(), 21)
});
Ok(())
})
@ -819,7 +821,7 @@ async fn window_count_without_tag_is_correct() -> anyhow::Result<()> {
sleep_secs(1);
with_state(&sender, |state| assert_eq!(state.windows.len(), 1));
with_state(&sender, |state| assert_eq!(state.pinnacle.windows.len(), 1));
Ok(())
})
@ -881,8 +883,8 @@ async fn spawned_window_has_correct_tags() -> anyhow::Result<()> {
sleep_secs(1);
with_state(&sender, |state| {
assert_eq!(state.windows.len(), 1);
assert_eq!(state.windows[0].with_state(|st| st.tags.len()), 1);
assert_eq!(state.pinnacle.windows.len(), 1);
assert_eq!(state.pinnacle.windows[0].with_state(|st| st.tags.len()), 1);
});
run_lua! { |Pinnacle|
@ -894,10 +896,10 @@ async fn spawned_window_has_correct_tags() -> anyhow::Result<()> {
sleep_secs(1);
with_state(&sender, |state| {
assert_eq!(state.windows.len(), 2);
assert_eq!(state.windows[1].with_state(|st| st.tags.len()), 2);
assert_eq!(state.pinnacle.windows.len(), 2);
assert_eq!(state.pinnacle.windows[1].with_state(|st| st.tags.len()), 2);
assert_eq!(
state.windows[1].with_state(|st| st
state.pinnacle.windows[1].with_state(|st| st
.tags
.iter()
.map(|tag| tag.name())

View file

@ -160,8 +160,8 @@ mod output {
let original_op = output_for_name(state, DUMMY_OUTPUT_NAME);
let first_op = output_for_name(state, "First");
let original_geo = state.space.output_geometry(&original_op).unwrap();
let first_geo = state.space.output_geometry(&first_op).unwrap();
let original_geo = state.pinnacle.space.output_geometry(&original_op).unwrap();
let first_geo = state.pinnacle.space.output_geometry(&first_op).unwrap();
assert_eq!(
original_geo,
@ -182,9 +182,9 @@ mod output {
let first_op = output_for_name(state, "First");
let second_op = output_for_name(state, "Second");
let original_geo = state.space.output_geometry(&original_op).unwrap();
let first_geo = state.space.output_geometry(&first_op).unwrap();
let second_geo = state.space.output_geometry(&second_op).unwrap();
let original_geo = state.pinnacle.space.output_geometry(&original_op).unwrap();
let first_geo = state.pinnacle.space.output_geometry(&first_op).unwrap();
let second_geo = state.pinnacle.space.output_geometry(&second_op).unwrap();
assert_eq!(
original_geo,
@ -262,10 +262,10 @@ mod output {
let second_op = output_for_name(state, "Second");
let third_op = output_for_name(state, "Third");
let original_geo = state.space.output_geometry(&original_op).unwrap();
let first_geo = state.space.output_geometry(&first_op).unwrap();
let second_geo = state.space.output_geometry(&second_op).unwrap();
let third_geo = state.space.output_geometry(&third_op).unwrap();
let original_geo = state.pinnacle.space.output_geometry(&original_op).unwrap();
let first_geo = state.pinnacle.space.output_geometry(&first_op).unwrap();
let second_geo = state.pinnacle.space.output_geometry(&second_op).unwrap();
let third_geo = state.pinnacle.space.output_geometry(&third_op).unwrap();
assert_eq!(
original_geo,
@ -294,9 +294,9 @@ mod output {
let first_op = output_for_name(state, "First");
let third_op = output_for_name(state, "Third");
let original_geo = state.space.output_geometry(&original_op).unwrap();
let first_geo = state.space.output_geometry(&first_op).unwrap();
let third_geo = state.space.output_geometry(&third_op).unwrap();
let original_geo = state.pinnacle.space.output_geometry(&original_op).unwrap();
let first_geo = state.pinnacle.space.output_geometry(&first_op).unwrap();
let third_geo = state.pinnacle.space.output_geometry(&third_op).unwrap();
assert_eq!(
original_geo,

View file

@ -46,11 +46,11 @@ pub(crate) fn run(channel: Channel<WlcsEvent>) {
// when xdiplay is None when starting the config, the grpc server is not
// started, until it is set; this bypasses this for now
state.xdisplay = Some(u32::MAX);
state.pinnacle.xdisplay = Some(u32::MAX);
run_config(&mut state);
// wait for the config to connect to the layout service
while state.layout_state.layout_request_sender.is_none() {
while state.pinnacle.layout_state.layout_request_sender.is_none() {
event_loop
.dispatch(Some(Duration::from_millis(10)), &mut state)
.expect("event_loop error while waiting for config");
@ -60,10 +60,11 @@ pub(crate) fn run(channel: Channel<WlcsEvent>) {
.run(None, &mut state, |state| {
state.update_pointer_focus();
state.fixup_z_layering();
state.space.refresh();
state.popup_manager.cleanup();
state.pinnacle.space.refresh();
state.pinnacle.popup_manager.cleanup();
state
.pinnacle
.display_handle
.flush_clients()
.expect("failed to flush client buffers");
@ -77,6 +78,7 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
WlcsEvent::Stop => state.shutdown(),
WlcsEvent::NewClient { stream, client_id } => {
let client: Client = state
.pinnacle
.display_handle
.insert_client(stream, Arc::new(ClientState::default()))
.expect("failed to insert new client");
@ -89,11 +91,18 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
} => {
let client = state.backend.wlcs_mut().clients.get(&client_id);
let window = state
.pinnacle
.space
.elements()
.find(|w| {
if let Some(surface) = w.wl_surface() {
state.display_handle.get_client(surface.id()).ok().as_ref() == client
state
.pinnacle
.display_handle
.get_client(surface.id())
.ok()
.as_ref()
== client
&& surface.id().protocol_id() == surface_id
} else {
false
@ -102,9 +111,13 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
.cloned();
if let Some(window) = window {
state.space.map_element(window.clone(), location, false);
state
.pinnacle
.space
.map_element(window.clone(), location, false);
let size = state
.pinnacle
.space
.element_geometry(&window)
.expect("window to be positioned was not mapped")
@ -119,7 +132,7 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
FloatingOrTiled::Floating(Rectangle::from_loc_and_size(location, size));
});
for output in state.space.outputs_for_element(&window) {
for output in state.pinnacle.space.outputs_for_element(&window) {
state.schedule_render(&output);
}
}
@ -139,7 +152,7 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
} => state.process_input_event(
WlcsPointerMotionAbsoluteEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
time: Duration::from(state.pinnacle.clock.now()).as_millis() as u64,
position,
}
.into(),
@ -147,7 +160,7 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
WlcsEvent::PointerMoveRelative { device_id, delta } => state.process_input_event(
WlcsPointerMotionEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
time: Duration::from(state.pinnacle.clock.now()).as_millis() as u64,
delta,
}
.into(),
@ -159,7 +172,7 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
} => state.process_input_event(
WlcsPointerButtonEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
time: Duration::from(state.pinnacle.clock.now()).as_millis() as u64,
button_code: button_id as u32,
state: if pressed {
ButtonState::Pressed
@ -183,7 +196,7 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
} => state.process_input_event(
WlcsTouchDownEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
time: Duration::from(state.pinnacle.clock.now()).as_millis() as u64,
position,
}
.into(),
@ -194,7 +207,7 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
} => state.process_input_event(
WlcsTouchDownEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
time: Duration::from(state.pinnacle.clock.now()).as_millis() as u64,
position,
}
.into(),
@ -202,7 +215,7 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
WlcsEvent::TouchUp { device_id } => state.process_input_event(
WlcsTouchUpEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
time: Duration::from(state.pinnacle.clock.now()).as_millis() as u64,
}
.into(),
),