2021-12-15 18:00:28 +01:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
|
|
2021-12-21 18:57:09 +01:00
|
|
|
use crate::{
|
2024-08-05 10:18:42 -07:00
|
|
|
backend::{
|
|
|
|
|
kms::KmsState,
|
|
|
|
|
render::{GlMultiError, RendererRef},
|
|
|
|
|
winit::WinitState,
|
|
|
|
|
x11::X11State,
|
|
|
|
|
},
|
2025-03-19 13:49:28 +01:00
|
|
|
config::{Config, OutputConfig, OutputState, ScreenFilter},
|
2024-09-04 11:13:59 -05:00
|
|
|
input::{gestures::GestureState, PointerFocusState},
|
2024-04-10 15:49:08 +02:00
|
|
|
shell::{grabs::SeatMoveGrabState, CosmicSurface, SeatExt, Shell},
|
2024-04-29 15:40:29 +02:00
|
|
|
utils::prelude::OutputExt,
|
2025-02-17 20:30:26 +01:00
|
|
|
wayland::{
|
|
|
|
|
handlers::screencopy::SessionHolder,
|
|
|
|
|
protocols::{
|
|
|
|
|
a11y::A11yState,
|
|
|
|
|
atspi::AtspiState,
|
|
|
|
|
drm::WlDrmState,
|
|
|
|
|
image_source::ImageSourceState,
|
|
|
|
|
output_configuration::OutputConfigurationState,
|
|
|
|
|
output_power::OutputPowerState,
|
|
|
|
|
overlap_notify::OverlapNotifyState,
|
|
|
|
|
screencopy::ScreencopyState,
|
|
|
|
|
toplevel_info::ToplevelInfoState,
|
|
|
|
|
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
|
|
|
|
|
workspace::{WorkspaceClientState, WorkspaceState, WorkspaceUpdateGuard},
|
|
|
|
|
},
|
2022-08-05 15:09:01 +02:00
|
|
|
},
|
2024-04-10 15:49:08 +02:00
|
|
|
xwayland::XWaylandState,
|
2021-12-21 18:57:09 +01:00
|
|
|
};
|
2023-06-27 17:40:14 +02:00
|
|
|
use anyhow::Context;
|
2025-02-14 19:14:43 +01:00
|
|
|
use calloop::RegistrationToken;
|
2023-06-27 17:40:14 +02:00
|
|
|
use i18n_embed::{
|
|
|
|
|
fluent::{fluent_language_loader, FluentLanguageLoader},
|
|
|
|
|
DesktopLanguageRequester,
|
|
|
|
|
};
|
|
|
|
|
use once_cell::sync::Lazy;
|
|
|
|
|
use rust_embed::RustEmbed;
|
2021-12-21 18:57:09 +01:00
|
|
|
use smithay::{
|
2022-11-03 18:51:27 +01:00
|
|
|
backend::{
|
2024-08-05 10:18:42 -07:00
|
|
|
allocator::{dmabuf::Dmabuf, Fourcc},
|
2022-11-03 18:51:27 +01:00
|
|
|
drm::DrmNode,
|
2022-11-22 18:20:20 +01:00
|
|
|
renderer::{
|
2023-03-31 13:57:37 +02:00
|
|
|
element::{
|
|
|
|
|
default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
|
2024-11-13 12:55:08 -08:00
|
|
|
RenderElementState, RenderElementStates,
|
2023-03-31 13:57:37 +02:00
|
|
|
},
|
2023-11-22 13:27:12 -08:00
|
|
|
ImportDma,
|
2022-11-22 18:20:20 +01:00
|
|
|
},
|
2022-11-03 18:51:27 +01:00
|
|
|
},
|
2024-02-23 17:23:57 +01:00
|
|
|
desktop::{
|
|
|
|
|
layer_map_for_output,
|
|
|
|
|
utils::{
|
|
|
|
|
send_dmabuf_feedback_surface_tree, send_frames_surface_tree,
|
2024-06-07 19:44:59 +02:00
|
|
|
surface_primary_scanout_output, update_surface_primary_scanout_output,
|
|
|
|
|
with_surfaces_surface_tree,
|
2024-02-23 17:23:57 +01:00
|
|
|
},
|
2024-04-10 15:49:08 +02:00
|
|
|
PopupManager,
|
2022-11-17 20:32:54 +01:00
|
|
|
},
|
2024-04-05 13:53:35 +02:00
|
|
|
input::{pointer::CursorImageStatus, SeatState},
|
2024-10-07 12:12:40 -04:00
|
|
|
output::{Output, Scale},
|
2022-01-28 18:54:25 +01:00
|
|
|
reexports::{
|
2022-04-27 13:25:17 +02:00
|
|
|
calloop::{LoopHandle, LoopSignal},
|
2024-04-10 15:49:08 +02:00
|
|
|
wayland_protocols::xdg::shell::server::xdg_toplevel::WmCapabilities,
|
2023-01-16 20:31:43 +01:00
|
|
|
wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode,
|
2022-07-04 15:26:26 +02:00
|
|
|
wayland_server::{
|
|
|
|
|
backend::{ClientData, ClientId, DisconnectReason},
|
2024-01-17 11:34:19 +00:00
|
|
|
protocol::{wl_shm, wl_surface::WlSurface},
|
|
|
|
|
Client, DisplayHandle, Resource,
|
2022-07-04 15:26:26 +02:00
|
|
|
},
|
2022-01-28 18:54:25 +01:00
|
|
|
},
|
2024-06-26 13:05:25 +02:00
|
|
|
utils::{Clock, IsAlive, Monotonic, Point},
|
2021-12-21 18:57:09 +01:00
|
|
|
wayland::{
|
2024-06-06 14:39:55 -07:00
|
|
|
alpha_modifier::AlphaModifierState,
|
2024-06-10 20:54:13 +02:00
|
|
|
compositor::{CompositorClientState, CompositorState, SurfaceData},
|
2024-09-09 16:21:27 +02:00
|
|
|
cursor_shape::CursorShapeManagerState,
|
2023-11-22 13:27:12 -08:00
|
|
|
dmabuf::{DmabufFeedback, DmabufGlobal, DmabufState},
|
2023-06-14 14:44:36 +02:00
|
|
|
fractional_scale::{with_fractional_scale, FractionalScaleManagerState},
|
2024-04-19 14:57:17 +02:00
|
|
|
idle_inhibit::IdleInhibitManagerState,
|
|
|
|
|
idle_notify::IdleNotifierState,
|
2023-05-25 14:37:30 -07:00
|
|
|
input_method::InputMethodManagerState,
|
2023-01-16 20:31:43 +01:00
|
|
|
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
|
|
|
|
|
output::OutputManagerState,
|
2023-09-13 20:52:10 -07:00
|
|
|
pointer_constraints::PointerConstraintsState,
|
2023-09-05 13:41:21 -07:00
|
|
|
pointer_gestures::PointerGesturesState,
|
2023-01-16 20:31:43 +01:00
|
|
|
presentation::PresentationState,
|
2023-03-31 13:57:37 +02:00
|
|
|
seat::WaylandFocus,
|
2023-08-29 17:00:11 -07:00
|
|
|
security_context::{SecurityContext, SecurityContextState},
|
2023-11-14 00:47:43 +04:00
|
|
|
selection::{
|
|
|
|
|
data_device::DataDeviceState, primary_selection::PrimarySelectionState,
|
|
|
|
|
wlr_data_control::DataControlState,
|
|
|
|
|
},
|
2023-11-14 13:13:42 -08:00
|
|
|
session_lock::SessionLockManagerState,
|
2024-04-10 15:49:08 +02:00
|
|
|
shell::{
|
|
|
|
|
kde::decoration::KdeDecorationState,
|
|
|
|
|
wlr_layer::WlrLayerShellState,
|
|
|
|
|
xdg::{decoration::XdgDecorationState, XdgShellState},
|
|
|
|
|
},
|
2023-01-16 20:31:43 +01:00
|
|
|
shm::ShmState,
|
2024-08-20 11:55:08 -07:00
|
|
|
single_pixel_buffer::SinglePixelBufferState,
|
2023-12-28 13:36:59 -08:00
|
|
|
tablet_manager::TabletManagerState,
|
2023-05-25 14:37:30 -07:00
|
|
|
text_input::TextInputManagerState,
|
2022-11-17 20:32:54 +01:00
|
|
|
viewporter::ViewporterState,
|
2023-05-25 14:37:30 -07:00
|
|
|
virtual_keyboard::VirtualKeyboardManagerState,
|
2024-04-10 15:49:08 +02:00
|
|
|
xdg_activation::XdgActivationState,
|
2024-08-29 17:30:50 -07:00
|
|
|
xdg_foreign::XdgForeignState,
|
2023-08-07 16:15:19 -07:00
|
|
|
xwayland_keyboard_grab::XWaylandKeyboardGrabState,
|
2024-05-13 14:16:21 -07:00
|
|
|
xwayland_shell::XWaylandShellState,
|
2021-12-21 18:57:09 +01:00
|
|
|
},
|
2024-01-17 11:34:19 +00:00
|
|
|
xwayland::XWaylandClientData,
|
2021-12-21 18:57:09 +01:00
|
|
|
};
|
2023-12-07 19:53:41 +00:00
|
|
|
use time::UtcOffset;
|
2022-01-11 19:18:41 +01:00
|
|
|
|
2024-04-19 14:57:17 +02:00
|
|
|
use std::{
|
2024-04-24 09:34:46 -07:00
|
|
|
cell::RefCell,
|
2024-11-09 15:37:59 +01:00
|
|
|
cmp::min,
|
2024-06-10 20:41:29 +02:00
|
|
|
collections::HashSet,
|
2024-04-24 09:34:46 -07:00
|
|
|
ffi::OsString,
|
|
|
|
|
process::Child,
|
2024-06-11 17:24:46 +02:00
|
|
|
sync::{atomic::AtomicBool, Arc, Mutex, Once, RwLock},
|
2025-03-05 19:37:12 +01:00
|
|
|
time::{Duration, Instant},
|
2024-04-19 14:57:17 +02:00
|
|
|
};
|
2021-12-15 18:00:28 +01:00
|
|
|
|
2023-06-27 17:40:14 +02:00
|
|
|
#[derive(RustEmbed)]
|
|
|
|
|
#[folder = "resources/i18n"]
|
|
|
|
|
struct Localizations;
|
|
|
|
|
|
|
|
|
|
pub static LANG_LOADER: Lazy<FluentLanguageLoader> = Lazy::new(|| fluent_language_loader!());
|
|
|
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
|
macro_rules! fl {
|
|
|
|
|
($message_id:literal) => {{
|
|
|
|
|
i18n_embed_fl::fl!($crate::state::LANG_LOADER, $message_id)
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
($message_id:literal, $($args:expr),*) => {{
|
|
|
|
|
i18n_embed_fl::fl!($crate::state::LANG_LOADER, $message_id, $($args), *)
|
|
|
|
|
}};
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-04 15:26:26 +02:00
|
|
|
pub struct ClientState {
|
2023-05-12 20:01:37 +02:00
|
|
|
pub compositor_client_state: CompositorClientState,
|
2022-07-04 15:26:26 +02:00
|
|
|
pub workspace_client_state: WorkspaceClientState,
|
2024-01-17 11:34:19 +00:00
|
|
|
pub advertised_drm_node: Option<DrmNode>,
|
2022-07-04 15:26:26 +02:00
|
|
|
pub privileged: bool,
|
2023-08-01 16:50:26 +02:00
|
|
|
pub evls: LoopSignal,
|
2023-08-29 17:00:11 -07:00
|
|
|
pub security_context: Option<SecurityContext>,
|
2022-07-04 15:26:26 +02:00
|
|
|
}
|
|
|
|
|
impl ClientData for ClientState {
|
|
|
|
|
fn initialized(&self, _client_id: ClientId) {}
|
2023-08-01 16:50:26 +02:00
|
|
|
fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {
|
|
|
|
|
self.evls.wakeup();
|
|
|
|
|
}
|
2022-07-04 15:26:26 +02:00
|
|
|
}
|
|
|
|
|
|
2024-05-14 12:14:04 -07:00
|
|
|
pub fn advertised_node_for_client(client: &Client) -> Option<DrmNode> {
|
2024-01-17 11:34:19 +00:00
|
|
|
// Lets check the global drm-node the client got either through default-feedback or wl_drm
|
|
|
|
|
if let Some(normal_client) = client.get_data::<ClientState>() {
|
|
|
|
|
return normal_client.advertised_drm_node.clone();
|
|
|
|
|
}
|
|
|
|
|
// last but not least all xwayland-surfaces should also share a single node
|
|
|
|
|
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
|
|
|
|
return xwayland_client.user_data().get::<DrmNode>().cloned();
|
|
|
|
|
}
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-14 12:14:04 -07:00
|
|
|
pub fn advertised_node_for_surface(w: &WlSurface, dh: &DisplayHandle) -> Option<DrmNode> {
|
|
|
|
|
let client = dh.get_client(w.id()).ok()?;
|
|
|
|
|
advertised_node_for_client(&client)
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-05 19:37:12 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum LastRefresh {
|
|
|
|
|
None,
|
|
|
|
|
At(Instant),
|
|
|
|
|
Scheduled(RegistrationToken),
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-12 18:54:53 +02:00
|
|
|
#[derive(Debug)]
|
2021-12-15 18:00:28 +01:00
|
|
|
pub struct State {
|
2022-01-11 17:00:04 +01:00
|
|
|
pub backend: BackendData,
|
2022-03-16 19:47:39 +01:00
|
|
|
pub common: Common,
|
2024-04-24 09:34:46 -07:00
|
|
|
pub ready: Once,
|
2025-03-05 19:37:12 +01:00
|
|
|
pub last_refresh: LastRefresh,
|
2022-01-11 17:00:04 +01:00
|
|
|
}
|
|
|
|
|
|
2023-07-12 18:54:53 +02:00
|
|
|
#[derive(Debug)]
|
2022-01-11 17:00:04 +01:00
|
|
|
pub struct Common {
|
2022-03-28 23:45:30 +02:00
|
|
|
pub config: Config,
|
|
|
|
|
|
2022-02-08 17:15:24 +01:00
|
|
|
pub socket: OsString,
|
2022-08-31 13:01:23 +02:00
|
|
|
pub display_handle: DisplayHandle,
|
2023-09-29 21:33:16 +02:00
|
|
|
pub event_loop_handle: LoopHandle<'static, State>,
|
2022-04-27 13:25:17 +02:00
|
|
|
pub event_loop_signal: LoopSignal,
|
2021-12-21 18:57:09 +01:00
|
|
|
|
2024-04-10 15:49:08 +02:00
|
|
|
pub popups: PopupManager,
|
|
|
|
|
pub shell: Arc<RwLock<Shell>>,
|
2021-12-15 23:23:49 +01:00
|
|
|
|
2022-11-17 20:32:54 +01:00
|
|
|
pub clock: Clock<Monotonic>,
|
2024-06-11 17:24:46 +02:00
|
|
|
pub startup_done: Arc<AtomicBool>,
|
2021-12-15 18:00:28 +01:00
|
|
|
pub should_stop: bool,
|
2023-12-07 19:53:41 +00:00
|
|
|
pub local_offset: time::UtcOffset,
|
2024-03-07 13:14:53 -06:00
|
|
|
pub gesture_state: Option<GestureState>,
|
2022-01-11 17:22:23 +01:00
|
|
|
|
2024-04-24 09:34:46 -07:00
|
|
|
pub kiosk_child: Option<Child>,
|
2023-10-10 13:55:34 -04:00
|
|
|
pub theme: cosmic::Theme,
|
|
|
|
|
|
2022-07-04 15:26:26 +02:00
|
|
|
// wayland state
|
|
|
|
|
pub compositor_state: CompositorState,
|
|
|
|
|
pub data_device_state: DataDeviceState,
|
|
|
|
|
pub dmabuf_state: DmabufState,
|
2023-06-14 14:44:36 +02:00
|
|
|
pub fractional_scale_state: FractionalScaleManagerState,
|
2022-09-09 20:17:40 -07:00
|
|
|
pub keyboard_shortcuts_inhibit_state: KeyboardShortcutsInhibitState,
|
2022-07-04 15:26:26 +02:00
|
|
|
pub output_state: OutputManagerState,
|
|
|
|
|
pub output_configuration_state: OutputConfigurationState<State>,
|
2024-08-16 20:49:59 -07:00
|
|
|
pub output_power_state: OutputPowerState,
|
2022-11-17 20:32:54 +01:00
|
|
|
pub presentation_state: PresentationState,
|
2022-07-15 14:22:02 +02:00
|
|
|
pub primary_selection_state: PrimarySelectionState,
|
2023-11-14 00:47:43 +04:00
|
|
|
pub data_control_state: Option<DataControlState>,
|
2024-03-12 19:42:48 +01:00
|
|
|
pub image_source_state: ImageSourceState,
|
2022-11-03 21:19:41 +01:00
|
|
|
pub screencopy_state: ScreencopyState,
|
2022-07-04 15:26:26 +02:00
|
|
|
pub seat_state: SeatState<State>,
|
2023-10-16 12:28:19 -07:00
|
|
|
pub session_lock_manager_state: SessionLockManagerState,
|
2024-04-19 14:57:17 +02:00
|
|
|
pub idle_notifier_state: IdleNotifierState<State>,
|
|
|
|
|
pub idle_inhibit_manager_state: IdleInhibitManagerState,
|
|
|
|
|
pub idle_inhibiting_surfaces: HashSet<WlSurface>,
|
2022-07-04 15:26:26 +02:00
|
|
|
pub shm_state: ShmState,
|
2024-09-09 16:21:27 +02:00
|
|
|
pub cursor_shape_manager_state: CursorShapeManagerState,
|
2024-01-17 11:34:19 +00:00
|
|
|
pub wl_drm_state: WlDrmState<Option<DrmNode>>,
|
2022-07-04 15:26:26 +02:00
|
|
|
pub viewporter_state: ViewporterState,
|
2023-01-16 20:31:43 +01:00
|
|
|
pub kde_decoration_state: KdeDecorationState,
|
|
|
|
|
pub xdg_decoration_state: XdgDecorationState,
|
2024-11-22 19:10:58 -05:00
|
|
|
pub overlap_notify_state: OverlapNotifyState,
|
2025-02-17 20:30:26 +01:00
|
|
|
pub a11y_state: A11yState,
|
2024-04-10 15:49:08 +02:00
|
|
|
|
|
|
|
|
// shell-related wayland state
|
|
|
|
|
pub xdg_shell_state: XdgShellState,
|
|
|
|
|
pub layer_shell_state: WlrLayerShellState,
|
|
|
|
|
pub toplevel_info_state: ToplevelInfoState<State, CosmicSurface>,
|
|
|
|
|
pub toplevel_management_state: ToplevelManagementState,
|
|
|
|
|
pub xdg_activation_state: XdgActivationState,
|
2024-08-29 17:30:50 -07:00
|
|
|
pub xdg_foreign_state: XdgForeignState,
|
2024-04-10 15:49:08 +02:00
|
|
|
pub workspace_state: WorkspaceState<State>,
|
2024-08-23 18:26:08 +02:00
|
|
|
pub xwayland_scale: Option<i32>,
|
2024-04-10 15:49:08 +02:00
|
|
|
pub xwayland_state: Option<XWaylandState>,
|
2024-05-13 14:16:21 -07:00
|
|
|
pub xwayland_shell_state: XWaylandShellState,
|
2024-09-04 11:13:59 -05:00
|
|
|
pub pointer_focus_state: Option<PointerFocusState>,
|
2024-08-21 20:20:27 -07:00
|
|
|
|
|
|
|
|
pub atspi_state: AtspiState,
|
|
|
|
|
pub atspi_ei: crate::wayland::handlers::atspi::AtspiEiState,
|
2022-01-11 17:22:23 +01:00
|
|
|
}
|
|
|
|
|
|
2023-07-12 18:54:53 +02:00
|
|
|
#[derive(Debug)]
|
2021-12-15 23:23:49 +01:00
|
|
|
pub enum BackendData {
|
|
|
|
|
X11(X11State),
|
2022-01-18 19:42:04 +01:00
|
|
|
Winit(WinitState),
|
2022-01-20 19:51:46 +01:00
|
|
|
Kms(KmsState),
|
2021-12-15 23:23:49 +01:00
|
|
|
// TODO
|
|
|
|
|
// Wayland(WaylandState),
|
|
|
|
|
Unset,
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-31 13:57:37 +02:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct SurfaceDmabufFeedback {
|
|
|
|
|
pub render_feedback: DmabufFeedback,
|
|
|
|
|
pub scanout_feedback: DmabufFeedback,
|
2025-01-02 21:32:47 +01:00
|
|
|
pub primary_scanout_feedback: DmabufFeedback,
|
2023-03-31 13:57:37 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-10 20:54:13 +02:00
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct SurfaceFrameThrottlingState {
|
|
|
|
|
last_sent_at: RefCell<Option<(Output, usize)>>,
|
|
|
|
|
}
|
|
|
|
|
impl Default for SurfaceFrameThrottlingState {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
SurfaceFrameThrottlingState {
|
|
|
|
|
last_sent_at: RefCell::new(None),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:23:49 +01:00
|
|
|
impl BackendData {
|
2022-01-20 19:51:46 +01:00
|
|
|
pub fn kms(&mut self) -> &mut KmsState {
|
|
|
|
|
match self {
|
|
|
|
|
BackendData::Kms(ref mut kms_state) => kms_state,
|
|
|
|
|
_ => unreachable!("Called kms in non kms backend"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 23:23:49 +01:00
|
|
|
pub fn x11(&mut self) -> &mut X11State {
|
|
|
|
|
match self {
|
|
|
|
|
BackendData::X11(ref mut x11_state) => x11_state,
|
|
|
|
|
_ => unreachable!("Called x11 in non x11 backend"),
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-18 19:42:04 +01:00
|
|
|
|
|
|
|
|
pub fn winit(&mut self) -> &mut WinitState {
|
|
|
|
|
match self {
|
|
|
|
|
BackendData::Winit(ref mut winit_state) => winit_state,
|
|
|
|
|
_ => unreachable!("Called winit in non winit backend"),
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-28 18:54:25 +01:00
|
|
|
|
2024-06-07 19:10:13 +02:00
|
|
|
pub fn apply_config_for_outputs(
|
2022-04-05 16:35:58 +02:00
|
|
|
&mut self,
|
2022-04-13 22:59:14 +02:00
|
|
|
test_only: bool,
|
2024-06-07 19:10:13 +02:00
|
|
|
loop_handle: &LoopHandle<'static, State>,
|
2025-03-19 14:16:58 +01:00
|
|
|
screen_filter: &ScreenFilter,
|
2024-06-07 19:10:13 +02:00
|
|
|
shell: Arc<RwLock<Shell>>,
|
2024-04-10 15:49:08 +02:00
|
|
|
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
|
|
|
|
xdg_activation_state: &XdgActivationState,
|
2024-06-11 17:24:46 +02:00
|
|
|
startup_done: Arc<AtomicBool>,
|
2025-01-02 17:38:59 +01:00
|
|
|
clock: &Clock<Monotonic>,
|
2022-04-13 22:59:14 +02:00
|
|
|
) -> Result<(), anyhow::Error> {
|
|
|
|
|
let result = match self {
|
2025-01-02 17:38:59 +01:00
|
|
|
BackendData::Kms(ref mut state) => state.apply_config_for_outputs(
|
|
|
|
|
test_only,
|
|
|
|
|
loop_handle,
|
2025-03-19 14:16:58 +01:00
|
|
|
screen_filter,
|
2025-01-02 17:38:59 +01:00
|
|
|
shell.clone(),
|
|
|
|
|
startup_done,
|
|
|
|
|
clock,
|
|
|
|
|
),
|
2024-06-07 19:10:13 +02:00
|
|
|
BackendData::Winit(ref mut state) => state.apply_config_for_outputs(test_only),
|
|
|
|
|
BackendData::X11(ref mut state) => state.apply_config_for_outputs(test_only),
|
2022-04-13 22:59:14 +02:00
|
|
|
_ => unreachable!("No backend set when applying output config"),
|
2024-06-07 19:10:13 +02:00
|
|
|
}?;
|
2022-04-13 22:59:14 +02:00
|
|
|
|
2024-06-07 19:10:13 +02:00
|
|
|
let mut shell = shell.write().unwrap();
|
|
|
|
|
for output in result {
|
2022-04-13 22:59:14 +02:00
|
|
|
// apply to Output
|
|
|
|
|
let final_config = output
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<RefCell<OutputConfig>>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.borrow();
|
2024-04-29 15:40:29 +02:00
|
|
|
|
2024-10-07 12:12:40 -04:00
|
|
|
let mode = Some(final_config.output_mode()).filter(|m| match output.current_mode() {
|
2022-04-13 22:59:14 +02:00
|
|
|
None => true,
|
|
|
|
|
Some(c_m) => m.size != c_m.size || m.refresh != c_m.refresh,
|
|
|
|
|
});
|
|
|
|
|
let transform =
|
|
|
|
|
Some(final_config.transform.into()).filter(|x| *x != output.current_transform());
|
2022-05-03 13:37:51 +02:00
|
|
|
let scale = Some(final_config.scale)
|
|
|
|
|
.filter(|x| *x != output.current_scale().fractional_scale());
|
2024-06-26 13:05:25 +02:00
|
|
|
let location = Some(Point::from((
|
|
|
|
|
final_config.position.0 as i32,
|
|
|
|
|
final_config.position.1 as i32,
|
|
|
|
|
)))
|
|
|
|
|
.filter(|x| *x != output.current_location());
|
2022-04-20 16:06:37 +02:00
|
|
|
output.change_current_state(mode, transform, scale.map(Scale::Fractional), location);
|
2024-04-29 15:40:29 +02:00
|
|
|
|
|
|
|
|
output.set_adaptive_sync(final_config.vrr);
|
2024-04-29 19:00:39 +02:00
|
|
|
output.set_mirroring(match &final_config.enabled {
|
|
|
|
|
OutputState::Mirroring(conn) => shell
|
|
|
|
|
.outputs()
|
|
|
|
|
.find(|output| &output.name() == conn)
|
|
|
|
|
.cloned(),
|
|
|
|
|
_ => None,
|
|
|
|
|
});
|
2024-04-29 15:40:29 +02:00
|
|
|
|
2024-06-07 19:10:13 +02:00
|
|
|
match final_config.enabled {
|
2025-03-13 12:50:02 -07:00
|
|
|
OutputState::Enabled => shell.workspaces.add_output(&output, workspace_state),
|
2024-06-07 19:10:13 +02:00
|
|
|
_ => {
|
|
|
|
|
let shell = &mut *shell;
|
|
|
|
|
shell.workspaces.remove_output(
|
|
|
|
|
&output,
|
|
|
|
|
shell.seats.iter(),
|
|
|
|
|
workspace_state,
|
|
|
|
|
xdg_activation_state,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layer_map_for_output(&output).arrange();
|
|
|
|
|
|
2024-06-10 20:41:29 +02:00
|
|
|
self.schedule_render(&output);
|
2022-03-30 13:47:06 +02:00
|
|
|
}
|
2022-04-13 22:59:14 +02:00
|
|
|
|
2024-11-12 02:59:42 -08:00
|
|
|
// Update layout for changes in resolution, scale, orientation
|
|
|
|
|
shell.workspaces.recalculate();
|
|
|
|
|
|
2024-08-23 18:26:08 +02:00
|
|
|
loop_handle.insert_idle(|state| state.common.update_xwayland_scale());
|
|
|
|
|
|
2024-06-07 19:10:13 +02:00
|
|
|
Ok(())
|
2022-03-30 13:47:06 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-10 20:41:29 +02:00
|
|
|
pub fn schedule_render(&mut self, output: &Output) {
|
2022-01-28 18:54:25 +01:00
|
|
|
match self {
|
2024-03-12 19:42:48 +01:00
|
|
|
BackendData::Winit(_) => {} // We cannot do this on the winit backend.
|
2022-01-28 18:54:25 +01:00
|
|
|
// Winit has a very strict render-loop and skipping frames breaks atleast the wayland winit-backend.
|
|
|
|
|
// Swapping with damage (which should be empty on these frames) is likely good enough anyway.
|
2024-03-12 19:42:48 +01:00
|
|
|
BackendData::X11(ref mut state) => state.schedule_render(output),
|
2024-06-07 20:04:39 +02:00
|
|
|
BackendData::Kms(ref mut state) => state.schedule_render(output),
|
2022-01-28 18:54:25 +01:00
|
|
|
_ => unreachable!("No backend was initialized"),
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-22 13:27:12 -08:00
|
|
|
|
|
|
|
|
pub fn dmabuf_imported(
|
|
|
|
|
&mut self,
|
2024-01-17 11:34:19 +00:00
|
|
|
client: Option<Client>,
|
2023-11-22 13:27:12 -08:00
|
|
|
global: &DmabufGlobal,
|
|
|
|
|
dmabuf: Dmabuf,
|
2024-01-17 11:34:19 +00:00
|
|
|
) -> Result<Option<DrmNode>, anyhow::Error> {
|
2023-11-22 13:27:12 -08:00
|
|
|
match self {
|
2024-01-17 11:34:19 +00:00
|
|
|
BackendData::Kms(ref mut state) => {
|
|
|
|
|
return state
|
|
|
|
|
.dmabuf_imported(client, global, dmabuf)
|
|
|
|
|
.map(|node| Some(node))
|
|
|
|
|
}
|
2023-11-22 13:27:12 -08:00
|
|
|
BackendData::Winit(ref mut state) => {
|
|
|
|
|
state.backend.renderer().import_dmabuf(&dmabuf, None)?;
|
|
|
|
|
}
|
|
|
|
|
BackendData::X11(ref mut state) => {
|
|
|
|
|
state.renderer.import_dmabuf(&dmabuf, None)?;
|
|
|
|
|
}
|
|
|
|
|
_ => unreachable!("No backend set when importing dmabuf"),
|
2024-01-17 11:34:19 +00:00
|
|
|
};
|
|
|
|
|
Ok(None)
|
2023-11-22 13:27:12 -08:00
|
|
|
}
|
2024-08-05 10:18:42 -07:00
|
|
|
|
|
|
|
|
/// Get an offscreen renderer for screen capture / screenshot rendering
|
|
|
|
|
///
|
|
|
|
|
/// `kms_node_cb` callback use used to determine nodes to render with when using kms backend.
|
2024-08-05 11:32:42 -07:00
|
|
|
/// If this returns `None`, it will attempt to use llvmpipe, then panic if no renderer is
|
|
|
|
|
/// found.
|
2024-08-05 10:18:42 -07:00
|
|
|
pub fn offscreen_renderer<N: Into<KmsNodes>, F: FnOnce(&mut KmsState) -> Option<N>>(
|
|
|
|
|
&mut self,
|
|
|
|
|
kms_node_cb: F,
|
|
|
|
|
) -> Result<RendererRef, GlMultiError> {
|
|
|
|
|
match self {
|
|
|
|
|
BackendData::Kms(kms) => {
|
2024-08-05 11:32:42 -07:00
|
|
|
if let Some(nodes) = kms_node_cb(kms) {
|
|
|
|
|
let nodes = nodes.into();
|
|
|
|
|
Ok(RendererRef::GlMulti(kms.api.renderer(
|
|
|
|
|
&nodes.render_node,
|
|
|
|
|
&nodes.target_node,
|
|
|
|
|
nodes.copy_format,
|
|
|
|
|
)?))
|
|
|
|
|
} else {
|
|
|
|
|
Ok(RendererRef::Glow(
|
|
|
|
|
kms.software_renderer
|
|
|
|
|
.as_mut()
|
|
|
|
|
.expect("No Software Rendering"),
|
|
|
|
|
))
|
|
|
|
|
}
|
2024-08-05 10:18:42 -07:00
|
|
|
}
|
|
|
|
|
BackendData::Winit(winit) => Ok(RendererRef::Glow(winit.backend.renderer())),
|
|
|
|
|
BackendData::X11(x11) => Ok(RendererRef::Glow(&mut x11.renderer)),
|
|
|
|
|
_ => unreachable!("No backend set when getting offscreen renderer"),
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-19 13:49:28 +01:00
|
|
|
|
|
|
|
|
pub fn update_screen_filter(&mut self, screen_filter: &ScreenFilter) -> anyhow::Result<()> {
|
2025-03-19 14:16:58 +01:00
|
|
|
match self {
|
|
|
|
|
BackendData::Kms(ref mut state) => state.update_screen_filter(screen_filter),
|
2025-03-19 14:17:29 +01:00
|
|
|
BackendData::Winit(ref mut state) => state.update_screen_filter(screen_filter),
|
|
|
|
|
BackendData::X11(ref mut state) => state.update_screen_filter(screen_filter),
|
2025-03-19 14:16:58 +01:00
|
|
|
_ => unreachable!("No backend set when setting screen filters"),
|
|
|
|
|
}
|
2025-03-19 13:49:28 +01:00
|
|
|
}
|
2024-08-05 10:18:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct KmsNodes {
|
|
|
|
|
pub render_node: DrmNode,
|
|
|
|
|
pub target_node: DrmNode,
|
|
|
|
|
pub copy_format: Fourcc,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<DrmNode> for KmsNodes {
|
|
|
|
|
fn from(node: DrmNode) -> Self {
|
|
|
|
|
KmsNodes {
|
|
|
|
|
render_node: node,
|
|
|
|
|
target_node: node,
|
|
|
|
|
// Ignored if render == target
|
|
|
|
|
copy_format: Fourcc::Abgr8888,
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-15 18:00:28 +01:00
|
|
|
}
|
|
|
|
|
|
2023-11-06 18:40:52 +01:00
|
|
|
pub fn client_has_no_security_context(client: &Client) -> bool {
|
2023-08-29 17:00:11 -07:00
|
|
|
client
|
|
|
|
|
.get_data::<ClientState>()
|
|
|
|
|
.map_or(true, |client_state| client_state.security_context.is_none())
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-06 18:40:52 +01:00
|
|
|
pub fn client_is_privileged(client: &Client) -> bool {
|
|
|
|
|
client
|
|
|
|
|
.get_data::<ClientState>()
|
|
|
|
|
.map_or(false, |client_state| client_state.privileged)
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-07 16:02:12 -07:00
|
|
|
fn enable_wayland_security() -> bool {
|
2024-10-14 19:44:22 -07:00
|
|
|
crate::utils::env::bool_var("COSMIC_ENABLE_WAYLAND_SECURITY").unwrap_or(false)
|
2023-11-06 18:40:52 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-15 18:00:28 +01:00
|
|
|
impl State {
|
2022-03-16 20:01:34 +01:00
|
|
|
pub fn new(
|
2022-07-04 15:26:26 +02:00
|
|
|
dh: &DisplayHandle,
|
2022-03-16 20:01:34 +01:00
|
|
|
socket: OsString,
|
2023-09-29 21:33:16 +02:00
|
|
|
handle: LoopHandle<'static, State>,
|
2022-04-27 13:25:17 +02:00
|
|
|
signal: LoopSignal,
|
2022-03-16 20:01:34 +01:00
|
|
|
) -> State {
|
2023-06-27 17:40:14 +02:00
|
|
|
let requested_languages = DesktopLanguageRequester::requested_languages();
|
|
|
|
|
i18n_embed::select(&*LANG_LOADER, &Localizations, &requested_languages)
|
|
|
|
|
.with_context(|| "Failed to load languages")
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
2023-10-07 19:15:44 -07:00
|
|
|
#[cfg(feature = "profile-with-tracy")]
|
|
|
|
|
unsafe {
|
|
|
|
|
time::util::local_offset::set_soundness(time::util::local_offset::Soundness::Unsound);
|
|
|
|
|
}
|
2023-12-07 19:53:41 +00:00
|
|
|
let local_offset = UtcOffset::current_local_offset().expect("No yet multithreaded");
|
2023-10-07 19:15:44 -07:00
|
|
|
#[cfg(feature = "profile-with-tracy")]
|
|
|
|
|
unsafe {
|
|
|
|
|
time::util::local_offset::set_soundness(time::util::local_offset::Soundness::Sound);
|
|
|
|
|
}
|
2023-10-24 10:43:11 -07:00
|
|
|
let clock = Clock::new();
|
2023-07-28 12:54:02 -07:00
|
|
|
let config = Config::load(&handle);
|
2023-02-24 17:41:52 +01:00
|
|
|
let compositor_state = CompositorState::new::<Self>(dh);
|
|
|
|
|
let data_device_state = DataDeviceState::new::<Self>(dh);
|
2022-07-04 15:26:26 +02:00
|
|
|
let dmabuf_state = DmabufState::new();
|
2023-06-14 14:44:36 +02:00
|
|
|
let fractional_scale_state = FractionalScaleManagerState::new::<State>(dh);
|
2022-09-09 20:17:40 -07:00
|
|
|
let keyboard_shortcuts_inhibit_state = KeyboardShortcutsInhibitState::new::<Self>(dh);
|
2022-07-04 15:26:26 +02:00
|
|
|
let output_state = OutputManagerState::new_with_xdg_output::<Self>(dh);
|
2024-12-18 13:40:31 -08:00
|
|
|
let output_configuration_state =
|
|
|
|
|
OutputConfigurationState::new(dh, handle.clone(), client_is_privileged);
|
2024-08-16 20:49:59 -07:00
|
|
|
let output_power_state = OutputPowerState::new::<Self, _>(dh, client_is_privileged);
|
2024-11-22 19:10:58 -05:00
|
|
|
let overlap_notify_state =
|
|
|
|
|
OverlapNotifyState::new::<Self, _>(dh, client_has_no_security_context);
|
2022-11-17 20:32:54 +01:00
|
|
|
let presentation_state = PresentationState::new::<Self>(dh, clock.id() as u32);
|
2023-02-24 17:41:52 +01:00
|
|
|
let primary_selection_state = PrimarySelectionState::new::<Self>(dh);
|
2024-05-07 16:02:12 -07:00
|
|
|
let image_source_state = ImageSourceState::new::<Self, _>(dh, client_is_privileged);
|
|
|
|
|
let screencopy_state = ScreencopyState::new::<Self, _>(dh, client_is_privileged);
|
2023-02-24 17:41:52 +01:00
|
|
|
let shm_state =
|
|
|
|
|
ShmState::new::<Self>(dh, vec![wl_shm::Format::Xbgr8888, wl_shm::Format::Abgr8888]);
|
2024-09-09 16:21:27 +02:00
|
|
|
let cursor_shape_manager_state = CursorShapeManagerState::new::<State>(dh);
|
2022-09-28 12:01:29 +02:00
|
|
|
let seat_state = SeatState::<Self>::new();
|
2023-02-24 17:41:52 +01:00
|
|
|
let viewporter_state = ViewporterState::new::<Self>(dh);
|
2024-01-17 11:34:19 +00:00
|
|
|
let wl_drm_state = WlDrmState::<Option<DrmNode>>::default();
|
2023-02-24 17:41:52 +01:00
|
|
|
let kde_decoration_state = KdeDecorationState::new::<Self>(&dh, Mode::Client);
|
|
|
|
|
let xdg_decoration_state = XdgDecorationState::new::<Self>(&dh);
|
2023-10-16 12:28:19 -07:00
|
|
|
let session_lock_manager_state =
|
2024-05-07 16:02:12 -07:00
|
|
|
SessionLockManagerState::new::<Self, _>(&dh, client_is_privileged);
|
2023-08-07 16:15:19 -07:00
|
|
|
XWaylandKeyboardGrabState::new::<Self>(&dh);
|
2024-05-13 14:16:21 -07:00
|
|
|
let xwayland_shell_state = XWaylandShellState::new::<Self>(&dh);
|
2023-09-13 20:52:10 -07:00
|
|
|
PointerConstraintsState::new::<Self>(&dh);
|
2023-09-05 13:41:21 -07:00
|
|
|
PointerGesturesState::new::<Self>(&dh);
|
2023-12-28 13:36:59 -08:00
|
|
|
TabletManagerState::new::<Self>(&dh);
|
2023-11-06 18:40:52 +01:00
|
|
|
SecurityContextState::new::<Self, _>(&dh, client_has_no_security_context);
|
2024-05-07 16:02:12 -07:00
|
|
|
InputMethodManagerState::new::<Self, _>(&dh, client_is_privileged);
|
2023-05-25 14:37:30 -07:00
|
|
|
TextInputManagerState::new::<Self>(&dh);
|
2024-05-07 16:02:12 -07:00
|
|
|
VirtualKeyboardManagerState::new::<State, _>(&dh, client_is_privileged);
|
2024-06-06 14:39:55 -07:00
|
|
|
AlphaModifierState::new::<Self>(&dh);
|
2024-08-20 11:55:08 -07:00
|
|
|
SinglePixelBufferState::new::<Self>(&dh);
|
2022-07-04 15:26:26 +02:00
|
|
|
|
2024-04-19 14:57:17 +02:00
|
|
|
let idle_notifier_state = IdleNotifierState::<Self>::new(&dh, handle.clone());
|
|
|
|
|
let idle_inhibit_manager_state = IdleInhibitManagerState::new::<State>(&dh);
|
|
|
|
|
let idle_inhibiting_surfaces = HashSet::new();
|
|
|
|
|
|
2024-10-14 19:44:22 -07:00
|
|
|
let data_control_state = crate::utils::env::bool_var("COSMIC_DATA_CONTROL_ENABLED")
|
|
|
|
|
.unwrap_or(false)
|
2024-04-03 16:02:27 +02:00
|
|
|
.then(|| {
|
|
|
|
|
DataControlState::new::<Self, _>(dh, Some(&primary_selection_state), |_| true)
|
|
|
|
|
});
|
2023-11-14 00:47:43 +04:00
|
|
|
|
2024-04-10 15:49:08 +02:00
|
|
|
let shell = Arc::new(RwLock::new(Shell::new(&config)));
|
|
|
|
|
|
2024-05-07 16:02:12 -07:00
|
|
|
let layer_shell_state =
|
|
|
|
|
WlrLayerShellState::new_with_filter::<State, _>(dh, client_is_privileged);
|
2024-04-10 15:49:08 +02:00
|
|
|
let xdg_shell_state = XdgShellState::new_with_capabilities::<State>(
|
|
|
|
|
dh,
|
|
|
|
|
[
|
|
|
|
|
WmCapabilities::Fullscreen,
|
|
|
|
|
WmCapabilities::Maximize,
|
|
|
|
|
WmCapabilities::Minimize,
|
|
|
|
|
WmCapabilities::WindowMenu,
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
let xdg_activation_state = XdgActivationState::new::<State>(dh);
|
2024-08-29 17:30:50 -07:00
|
|
|
let xdg_foreign_state = XdgForeignState::new::<State>(dh);
|
2024-05-07 16:02:12 -07:00
|
|
|
let toplevel_info_state = ToplevelInfoState::new(dh, client_is_privileged);
|
2024-04-10 15:49:08 +02:00
|
|
|
let toplevel_management_state = ToplevelManagementState::new::<State, _>(
|
|
|
|
|
dh,
|
|
|
|
|
vec![
|
|
|
|
|
ManagementCapabilities::Close,
|
|
|
|
|
ManagementCapabilities::Activate,
|
|
|
|
|
ManagementCapabilities::Maximize,
|
|
|
|
|
ManagementCapabilities::Minimize,
|
|
|
|
|
ManagementCapabilities::MoveToWorkspace,
|
|
|
|
|
],
|
2024-05-07 16:02:12 -07:00
|
|
|
client_is_privileged,
|
2024-04-10 15:49:08 +02:00
|
|
|
);
|
2024-05-07 16:02:12 -07:00
|
|
|
let workspace_state = WorkspaceState::new(dh, client_is_privileged);
|
2021-12-21 18:57:09 +01:00
|
|
|
|
2024-02-07 13:58:44 +01:00
|
|
|
if let Err(err) = crate::dbus::init(&handle) {
|
|
|
|
|
tracing::warn!(?err, "Failed to initialize dbus handlers");
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-17 20:30:26 +01:00
|
|
|
let a11y_state = A11yState::new::<State, _>(dh, client_is_privileged);
|
|
|
|
|
|
2024-08-21 20:20:27 -07:00
|
|
|
// TODO: Restrict to only specific client?
|
2025-02-17 20:30:26 +01:00
|
|
|
let atspi_state = AtspiState::new::<State, _>(dh, |_| true);
|
2024-08-21 20:20:27 -07:00
|
|
|
|
2021-12-15 18:00:28 +01:00
|
|
|
State {
|
2022-01-11 17:00:04 +01:00
|
|
|
common: Common {
|
2022-03-29 14:41:09 +02:00
|
|
|
config,
|
2022-02-08 17:15:24 +01:00
|
|
|
socket,
|
2022-08-31 13:01:23 +02:00
|
|
|
display_handle: dh.clone(),
|
2022-01-28 18:54:25 +01:00
|
|
|
event_loop_handle: handle,
|
2022-04-27 13:25:17 +02:00
|
|
|
event_loop_signal: signal,
|
2021-12-21 18:57:09 +01:00
|
|
|
|
2024-04-10 15:49:08 +02:00
|
|
|
popups: PopupManager::default(),
|
2022-03-24 20:32:31 +01:00
|
|
|
shell,
|
2021-12-21 18:57:09 +01:00
|
|
|
|
2023-12-07 19:53:41 +00:00
|
|
|
local_offset,
|
2021-12-15 23:23:49 +01:00
|
|
|
|
2022-11-17 20:32:54 +01:00
|
|
|
clock,
|
2024-06-11 17:24:46 +02:00
|
|
|
startup_done: Arc::new(AtomicBool::new(false)),
|
2022-01-11 17:00:04 +01:00
|
|
|
should_stop: false,
|
2024-03-07 13:14:53 -06:00
|
|
|
gesture_state: None,
|
2022-01-11 17:22:23 +01:00
|
|
|
|
2024-04-24 09:34:46 -07:00
|
|
|
kiosk_child: None,
|
2023-10-10 13:55:34 -04:00
|
|
|
theme: cosmic::theme::system_preference(),
|
|
|
|
|
|
2022-07-04 15:26:26 +02:00
|
|
|
compositor_state,
|
|
|
|
|
data_device_state,
|
|
|
|
|
dmabuf_state,
|
2023-06-14 14:44:36 +02:00
|
|
|
fractional_scale_state,
|
2024-04-19 14:57:17 +02:00
|
|
|
idle_notifier_state,
|
|
|
|
|
idle_inhibit_manager_state,
|
|
|
|
|
idle_inhibiting_surfaces,
|
2024-03-12 19:42:48 +01:00
|
|
|
image_source_state,
|
2022-11-03 21:19:41 +01:00
|
|
|
screencopy_state,
|
2022-07-04 15:26:26 +02:00
|
|
|
shm_state,
|
2024-09-09 16:21:27 +02:00
|
|
|
cursor_shape_manager_state,
|
2022-07-04 15:26:26 +02:00
|
|
|
seat_state,
|
2023-10-16 12:28:19 -07:00
|
|
|
session_lock_manager_state,
|
2022-09-09 20:17:40 -07:00
|
|
|
keyboard_shortcuts_inhibit_state,
|
2022-07-04 15:26:26 +02:00
|
|
|
output_state,
|
|
|
|
|
output_configuration_state,
|
2024-08-16 20:49:59 -07:00
|
|
|
output_power_state,
|
2024-11-22 19:10:58 -05:00
|
|
|
overlap_notify_state,
|
2022-11-17 20:32:54 +01:00
|
|
|
presentation_state,
|
2022-07-15 14:22:02 +02:00
|
|
|
primary_selection_state,
|
2023-11-14 00:47:43 +04:00
|
|
|
data_control_state,
|
2022-07-04 15:26:26 +02:00
|
|
|
viewporter_state,
|
|
|
|
|
wl_drm_state,
|
2023-01-16 20:31:43 +01:00
|
|
|
kde_decoration_state,
|
|
|
|
|
xdg_decoration_state,
|
2024-04-10 15:49:08 +02:00
|
|
|
xdg_shell_state,
|
|
|
|
|
layer_shell_state,
|
|
|
|
|
toplevel_info_state,
|
|
|
|
|
toplevel_management_state,
|
|
|
|
|
xdg_activation_state,
|
2024-08-29 17:30:50 -07:00
|
|
|
xdg_foreign_state,
|
2024-04-10 15:49:08 +02:00
|
|
|
workspace_state,
|
2025-02-17 20:30:26 +01:00
|
|
|
a11y_state,
|
2024-08-23 18:26:08 +02:00
|
|
|
xwayland_scale: None,
|
2024-04-10 15:49:08 +02:00
|
|
|
xwayland_state: None,
|
2024-05-13 14:16:21 -07:00
|
|
|
xwayland_shell_state,
|
2024-09-04 11:13:59 -05:00
|
|
|
pointer_focus_state: None,
|
2024-08-21 20:20:27 -07:00
|
|
|
|
|
|
|
|
atspi_state,
|
|
|
|
|
atspi_ei: Default::default(),
|
2022-01-11 17:00:04 +01:00
|
|
|
},
|
2021-12-15 23:23:49 +01:00
|
|
|
backend: BackendData::Unset,
|
2024-04-24 09:34:46 -07:00
|
|
|
ready: Once::new(),
|
2025-03-05 19:37:12 +01:00
|
|
|
last_refresh: LastRefresh::None,
|
2021-12-15 18:00:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-03-16 19:47:39 +01:00
|
|
|
|
2022-07-04 15:26:26 +02:00
|
|
|
pub fn new_client_state(&self) -> ClientState {
|
|
|
|
|
ClientState {
|
2023-05-12 20:01:37 +02:00
|
|
|
compositor_client_state: CompositorClientState::default(),
|
2022-07-04 15:26:26 +02:00
|
|
|
workspace_client_state: WorkspaceClientState::default(),
|
2024-01-17 11:34:19 +00:00
|
|
|
advertised_drm_node: match &self.backend {
|
2024-06-07 20:04:39 +02:00
|
|
|
BackendData::Kms(kms_state) => kms_state.primary_node,
|
2022-07-04 15:26:26 +02:00
|
|
|
_ => None,
|
|
|
|
|
},
|
2024-05-07 16:02:12 -07:00
|
|
|
privileged: !enable_wayland_security(),
|
2023-08-01 16:50:26 +02:00
|
|
|
evls: self.common.event_loop_signal.clone(),
|
2023-08-29 17:00:11 -07:00
|
|
|
security_context: None,
|
2022-07-04 15:26:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-12-15 18:00:28 +01:00
|
|
|
}
|
2022-01-11 19:18:41 +01:00
|
|
|
|
2024-11-13 12:55:08 -08:00
|
|
|
fn primary_scanout_output_compare<'a>(
|
|
|
|
|
current_output: &'a Output,
|
|
|
|
|
current_state: &RenderElementState,
|
|
|
|
|
next_output: &'a Output,
|
|
|
|
|
next_state: &RenderElementState,
|
|
|
|
|
) -> &'a Output {
|
|
|
|
|
if !crate::wayland::protocols::output_configuration::head_is_enabled(current_output) {
|
|
|
|
|
return next_output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default_primary_scanout_output_compare(current_output, current_state, next_output, next_state)
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
impl Common {
|
2024-06-07 19:44:59 +02:00
|
|
|
pub fn update_primary_output(
|
2023-03-31 13:57:37 +02:00
|
|
|
&self,
|
|
|
|
|
output: &Output,
|
|
|
|
|
render_element_states: &RenderElementStates,
|
|
|
|
|
) {
|
2024-04-10 15:49:08 +02:00
|
|
|
let shell = self.shell.read().unwrap();
|
2024-08-05 17:26:49 +02:00
|
|
|
let processor = |surface: &WlSurface, states: &SurfaceData| {
|
|
|
|
|
let primary_scanout_output = update_surface_primary_scanout_output(
|
|
|
|
|
surface,
|
|
|
|
|
output,
|
|
|
|
|
states,
|
|
|
|
|
render_element_states,
|
2024-11-13 12:55:08 -08:00
|
|
|
primary_scanout_output_compare,
|
2024-08-05 17:26:49 +02:00
|
|
|
);
|
|
|
|
|
if let Some(output) = primary_scanout_output {
|
|
|
|
|
with_fractional_scale(states, |fraction_scale| {
|
|
|
|
|
fraction_scale.set_preferred_scale(output.current_scale().fractional_scale());
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// lock surface
|
|
|
|
|
if let Some(session_lock) = shell.session_lock.as_ref() {
|
|
|
|
|
if let Some(lock_surface) = session_lock.surfaces.get(output) {
|
|
|
|
|
with_surfaces_surface_tree(lock_surface.wl_surface(), processor)
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
|
2024-06-07 19:44:59 +02:00
|
|
|
for seat in shell
|
|
|
|
|
.seats
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|seat| &seat.active_output() == output)
|
|
|
|
|
{
|
2024-08-05 17:26:49 +02:00
|
|
|
let cursor_status = seat
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<Mutex<CursorImageStatus>>()
|
|
|
|
|
.map(|lock| {
|
|
|
|
|
let mut cursor_status = lock.lock().unwrap();
|
|
|
|
|
if let CursorImageStatus::Surface(ref surface) = *cursor_status {
|
|
|
|
|
if !surface.alive() {
|
|
|
|
|
*cursor_status = CursorImageStatus::default_named();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cursor_status.clone()
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(CursorImageStatus::default_named());
|
|
|
|
|
|
|
|
|
|
// cursor ...
|
|
|
|
|
if let CursorImageStatus::Surface(wl_surface) = cursor_status {
|
|
|
|
|
with_surfaces_surface_tree(&wl_surface, processor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// grabs
|
2024-06-07 19:44:59 +02:00
|
|
|
if let Some(move_grab) = seat.user_data().get::<SeatMoveGrabState>() {
|
|
|
|
|
if let Some(grab_state) = move_grab.lock().unwrap().as_ref() {
|
|
|
|
|
for (window, _) in grab_state.element().windows() {
|
2024-08-05 17:26:49 +02:00
|
|
|
window.with_surfaces(processor);
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sticky window
|
2024-06-19 20:13:14 +02:00
|
|
|
for set in shell.workspaces.sets.values() {
|
|
|
|
|
set.sticky_layer.mapped().for_each(|mapped| {
|
2024-06-07 19:44:59 +02:00
|
|
|
for (window, _) in mapped.windows() {
|
2024-08-05 17:26:49 +02:00
|
|
|
window.with_surfaces(processor);
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
|
|
|
|
});
|
2024-06-19 20:13:14 +02:00
|
|
|
}
|
2024-06-07 19:44:59 +02:00
|
|
|
|
|
|
|
|
// normal windows
|
2024-06-19 20:13:14 +02:00
|
|
|
for space in shell.workspaces.spaces() {
|
|
|
|
|
space.mapped().for_each(|mapped| {
|
|
|
|
|
for (window, _) in mapped.windows() {
|
2024-08-05 17:26:49 +02:00
|
|
|
window.with_surfaces(processor);
|
2024-06-19 20:13:14 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
space.minimized_windows.iter().for_each(|m| {
|
|
|
|
|
for (window, _) in m.window.windows() {
|
2024-08-05 17:26:49 +02:00
|
|
|
window.with_surfaces(processor);
|
2024-06-19 20:13:14 +02:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// OR windows
|
|
|
|
|
shell.override_redirect_windows.iter().for_each(|or| {
|
|
|
|
|
if let Some(wl_surface) = or.wl_surface() {
|
2024-08-05 17:26:49 +02:00
|
|
|
with_surfaces_surface_tree(&wl_surface, processor);
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2024-06-19 20:13:14 +02:00
|
|
|
// layer surfaces
|
|
|
|
|
for o in shell.outputs() {
|
|
|
|
|
let map = smithay::desktop::layer_map_for_output(o);
|
|
|
|
|
for layer_surface in map.layers() {
|
2024-08-05 17:26:49 +02:00
|
|
|
layer_surface.with_surfaces(processor);
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn send_dmabuf_feedback(
|
|
|
|
|
&self,
|
|
|
|
|
output: &Output,
|
|
|
|
|
render_element_states: &RenderElementStates,
|
|
|
|
|
mut dmabuf_feedback: impl FnMut(DrmNode) -> Option<SurfaceDmabufFeedback>,
|
|
|
|
|
) {
|
|
|
|
|
let shell = self.shell.read().unwrap();
|
|
|
|
|
|
|
|
|
|
if let Some(session_lock) = shell.session_lock.as_ref() {
|
|
|
|
|
if let Some(lock_surface) = session_lock.surfaces.get(output) {
|
2023-10-16 12:28:19 -07:00
|
|
|
if let Some(feedback) =
|
2024-01-17 11:34:19 +00:00
|
|
|
advertised_node_for_surface(lock_surface.wl_surface(), &self.display_handle)
|
2023-10-16 12:28:19 -07:00
|
|
|
.and_then(|source| dmabuf_feedback(source))
|
|
|
|
|
{
|
|
|
|
|
send_dmabuf_feedback_surface_tree(
|
|
|
|
|
&lock_surface.wl_surface(),
|
|
|
|
|
output,
|
|
|
|
|
surface_primary_scanout_output,
|
|
|
|
|
|surface, _| {
|
|
|
|
|
select_dmabuf_feedback(
|
|
|
|
|
surface,
|
|
|
|
|
render_element_states,
|
|
|
|
|
&feedback.render_feedback,
|
2025-01-02 21:32:47 +01:00
|
|
|
&feedback.primary_scanout_feedback,
|
2023-10-16 12:28:19 -07:00
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-10 15:49:08 +02:00
|
|
|
for seat in shell
|
2024-02-27 13:04:19 +01:00
|
|
|
.seats
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|seat| &seat.active_output() == output)
|
|
|
|
|
{
|
2024-06-07 19:44:59 +02:00
|
|
|
if let Some(move_grab) = seat.user_data().get::<SeatMoveGrabState>() {
|
|
|
|
|
if let Some(grab_state) = move_grab.lock().unwrap().as_ref() {
|
|
|
|
|
for (window, _) in grab_state.element().windows() {
|
|
|
|
|
if let Some(feedback) = window
|
|
|
|
|
.wl_surface()
|
|
|
|
|
.and_then(|wl_surface| {
|
|
|
|
|
advertised_node_for_surface(&wl_surface, &self.display_handle)
|
|
|
|
|
})
|
|
|
|
|
.and_then(|source| dmabuf_feedback(source))
|
|
|
|
|
{
|
|
|
|
|
window.send_dmabuf_feedback(
|
|
|
|
|
output,
|
|
|
|
|
&feedback,
|
|
|
|
|
render_element_states,
|
|
|
|
|
surface_primary_scanout_output,
|
|
|
|
|
);
|
2023-01-26 21:08:00 +01:00
|
|
|
}
|
2024-02-27 13:04:45 +01:00
|
|
|
}
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
2024-02-27 13:04:45 +01:00
|
|
|
}
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
2023-02-13 17:56:13 +01:00
|
|
|
|
2024-06-07 19:44:59 +02:00
|
|
|
shell
|
|
|
|
|
.workspaces
|
|
|
|
|
.sets
|
|
|
|
|
.get(output)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.sticky_layer
|
|
|
|
|
.mapped()
|
|
|
|
|
.for_each(|mapped| {
|
|
|
|
|
for (window, _) in mapped.windows() {
|
2024-02-27 13:04:45 +01:00
|
|
|
if let Some(feedback) = window
|
|
|
|
|
.wl_surface()
|
|
|
|
|
.and_then(|wl_surface| {
|
|
|
|
|
advertised_node_for_surface(&wl_surface, &self.display_handle)
|
|
|
|
|
})
|
|
|
|
|
.and_then(|source| dmabuf_feedback(source))
|
|
|
|
|
{
|
|
|
|
|
window.send_dmabuf_feedback(
|
|
|
|
|
output,
|
|
|
|
|
&feedback,
|
|
|
|
|
render_element_states,
|
|
|
|
|
surface_primary_scanout_output,
|
|
|
|
|
);
|
2023-02-13 17:56:13 +01:00
|
|
|
}
|
|
|
|
|
}
|
2024-06-07 19:44:59 +02:00
|
|
|
});
|
2023-12-20 19:53:27 +00:00
|
|
|
|
2025-01-06 19:23:06 +01:00
|
|
|
if let Some(active) = shell.active_space(output) {
|
|
|
|
|
active.mapped().for_each(|mapped| {
|
|
|
|
|
for (window, _) in mapped.windows() {
|
|
|
|
|
if let Some(feedback) = window
|
|
|
|
|
.wl_surface()
|
|
|
|
|
.and_then(|wl_surface| {
|
|
|
|
|
advertised_node_for_surface(&wl_surface, &self.display_handle)
|
|
|
|
|
})
|
|
|
|
|
.and_then(|source| dmabuf_feedback(source))
|
|
|
|
|
{
|
|
|
|
|
window.send_dmabuf_feedback(
|
|
|
|
|
output,
|
|
|
|
|
&feedback,
|
|
|
|
|
render_element_states,
|
|
|
|
|
surface_primary_scanout_output,
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-02-27 13:04:45 +01:00
|
|
|
}
|
2025-01-06 19:23:06 +01:00
|
|
|
});
|
|
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
|
2024-04-10 15:49:08 +02:00
|
|
|
shell.override_redirect_windows.iter().for_each(|or| {
|
2023-01-27 19:51:23 +01:00
|
|
|
if let Some(wl_surface) = or.wl_surface() {
|
2024-01-17 11:34:19 +00:00
|
|
|
if let Some(feedback) =
|
|
|
|
|
advertised_node_for_surface(&wl_surface, &self.display_handle)
|
|
|
|
|
.and_then(|source| dmabuf_feedback(source))
|
2023-03-31 13:57:37 +02:00
|
|
|
{
|
|
|
|
|
send_dmabuf_feedback_surface_tree(
|
|
|
|
|
&wl_surface,
|
|
|
|
|
output,
|
|
|
|
|
surface_primary_scanout_output,
|
|
|
|
|
|surface, _| {
|
|
|
|
|
select_dmabuf_feedback(
|
|
|
|
|
surface,
|
|
|
|
|
render_element_states,
|
|
|
|
|
&feedback.render_feedback,
|
|
|
|
|
&feedback.scanout_feedback,
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
}
|
2023-01-23 22:53:39 +01:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
let map = smithay::desktop::layer_map_for_output(output);
|
|
|
|
|
for layer_surface in map.layers() {
|
2023-03-31 13:57:37 +02:00
|
|
|
if let Some(feedback) =
|
2024-01-17 11:34:19 +00:00
|
|
|
advertised_node_for_surface(layer_surface.wl_surface(), &self.display_handle)
|
2023-03-31 13:57:37 +02:00
|
|
|
.and_then(|source| dmabuf_feedback(source))
|
|
|
|
|
{
|
|
|
|
|
layer_surface.send_dmabuf_feedback(
|
|
|
|
|
output,
|
|
|
|
|
surface_primary_scanout_output,
|
|
|
|
|
|surface, _| {
|
|
|
|
|
select_dmabuf_feedback(
|
|
|
|
|
surface,
|
|
|
|
|
render_element_states,
|
|
|
|
|
&feedback.render_feedback,
|
|
|
|
|
&feedback.scanout_feedback,
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-17 20:32:54 +01:00
|
|
|
|
2024-06-10 20:54:13 +02:00
|
|
|
pub fn send_frames(&self, output: &Output, sequence: Option<usize>) {
|
2024-06-07 19:44:59 +02:00
|
|
|
let time = self.clock.now();
|
2024-06-10 20:54:13 +02:00
|
|
|
let should_send = |surface: &WlSurface, states: &SurfaceData| {
|
|
|
|
|
// Do the standard primary scanout output check. For pointer surfaces it deduplicates
|
|
|
|
|
// the frame callbacks across potentially multiple outputs, and for regular windows and
|
|
|
|
|
// layer-shell surfaces it avoids sending frame callbacks to invisible surfaces.
|
|
|
|
|
let current_primary_output = surface_primary_scanout_output(surface, states);
|
|
|
|
|
if current_primary_output.as_ref() != Some(output) {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let Some(sequence) = sequence else {
|
|
|
|
|
return Some(output.clone());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Next, check the throttling status.
|
|
|
|
|
let frame_throttling_state = states
|
|
|
|
|
.data_map
|
|
|
|
|
.get_or_insert(SurfaceFrameThrottlingState::default);
|
|
|
|
|
let mut last_sent_at = frame_throttling_state.last_sent_at.borrow_mut();
|
|
|
|
|
|
|
|
|
|
let mut send = true;
|
|
|
|
|
|
|
|
|
|
// If we already sent a frame callback to this surface this output refresh
|
|
|
|
|
// cycle, don't send one again to prevent empty-damage commit busy loops.
|
|
|
|
|
if let Some((last_output, last_sequence)) = &*last_sent_at {
|
|
|
|
|
if last_output == output && *last_sequence == sequence {
|
|
|
|
|
send = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if send {
|
|
|
|
|
*last_sent_at = Some((output.clone(), sequence));
|
|
|
|
|
Some(output.clone())
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-11-09 15:37:59 +01:00
|
|
|
const THROTTLE: Option<Duration> = Some(Duration::from_millis(995));
|
|
|
|
|
const SCREENCOPY_THROTTLE: Option<Duration> = Some(Duration::from_nanos(16_666_666));
|
|
|
|
|
|
|
|
|
|
fn throttle(session_holder: &impl SessionHolder) -> Option<Duration> {
|
|
|
|
|
if session_holder.sessions().is_empty() && session_holder.cursor_sessions().is_empty() {
|
|
|
|
|
THROTTLE
|
|
|
|
|
} else {
|
|
|
|
|
SCREENCOPY_THROTTLE
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-10 15:49:08 +02:00
|
|
|
let shell = self.shell.read().unwrap();
|
2022-11-17 20:32:54 +01:00
|
|
|
|
2024-06-07 19:44:59 +02:00
|
|
|
if let Some(session_lock) = shell.session_lock.as_ref() {
|
|
|
|
|
if let Some(lock_surface) = session_lock.surfaces.get(output) {
|
2024-06-10 20:54:13 +02:00
|
|
|
send_frames_surface_tree(
|
|
|
|
|
lock_surface.wl_surface(),
|
|
|
|
|
output,
|
|
|
|
|
time,
|
|
|
|
|
None,
|
|
|
|
|
should_send,
|
|
|
|
|
);
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for seat in shell
|
|
|
|
|
.seats
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|seat| &seat.active_output() == output)
|
|
|
|
|
{
|
|
|
|
|
let cursor_status = seat
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<Mutex<CursorImageStatus>>()
|
|
|
|
|
.map(|lock| {
|
|
|
|
|
let mut cursor_status = lock.lock().unwrap();
|
|
|
|
|
if let CursorImageStatus::Surface(ref surface) = *cursor_status {
|
|
|
|
|
if !surface.alive() {
|
|
|
|
|
*cursor_status = CursorImageStatus::default_named();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cursor_status.clone()
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(CursorImageStatus::default_named());
|
|
|
|
|
|
|
|
|
|
if let CursorImageStatus::Surface(wl_surface) = cursor_status {
|
2024-06-10 20:54:13 +02:00
|
|
|
send_frames_surface_tree(
|
|
|
|
|
&wl_surface,
|
|
|
|
|
output,
|
|
|
|
|
time,
|
|
|
|
|
Some(Duration::ZERO),
|
|
|
|
|
should_send,
|
|
|
|
|
)
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(move_grab) = seat.user_data().get::<SeatMoveGrabState>() {
|
|
|
|
|
if let Some(grab_state) = move_grab.lock().unwrap().as_ref() {
|
|
|
|
|
for (window, _) in grab_state.element().windows() {
|
2024-11-09 15:37:59 +01:00
|
|
|
window.send_frame(output, time, throttle(&window), should_send);
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
shell
|
|
|
|
|
.workspaces
|
|
|
|
|
.sets
|
|
|
|
|
.get(output)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.sticky_layer
|
|
|
|
|
.mapped()
|
|
|
|
|
.for_each(|mapped| {
|
|
|
|
|
for (window, _) in mapped.windows() {
|
2024-11-09 15:37:59 +01:00
|
|
|
window.send_frame(output, time, throttle(&window), should_send);
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-01-06 19:23:06 +01:00
|
|
|
if let Some(active) = shell.active_space(output) {
|
|
|
|
|
active.mapped().for_each(|mapped| {
|
2024-06-07 19:44:59 +02:00
|
|
|
for (window, _) in mapped.windows() {
|
2025-01-06 19:23:06 +01:00
|
|
|
window.send_frame(output, time, throttle(&window), should_send);
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
|
|
|
|
});
|
2025-01-06 19:23:06 +01:00
|
|
|
|
|
|
|
|
// other (throttled) windows
|
|
|
|
|
active.minimized_windows.iter().for_each(|m| {
|
2024-06-07 19:44:59 +02:00
|
|
|
for (window, _) in m.window.windows() {
|
2024-11-09 15:37:59 +01:00
|
|
|
window.send_frame(output, time, throttle(&window), |_, _| None);
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
2025-01-06 19:23:06 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for space in shell
|
|
|
|
|
.workspaces
|
|
|
|
|
.spaces_for_output(output)
|
|
|
|
|
.filter(|w| w.handle != active.handle)
|
|
|
|
|
{
|
|
|
|
|
space.mapped().for_each(|mapped| {
|
|
|
|
|
for (window, _) in mapped.windows() {
|
|
|
|
|
let throttle = min(throttle(space), throttle(&window));
|
|
|
|
|
window.send_frame(output, time, throttle, |_, _| None);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
space.minimized_windows.iter().for_each(|m| {
|
|
|
|
|
for (window, _) in m.window.windows() {
|
|
|
|
|
window.send_frame(output, time, throttle(&window), |_, _| None);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
2024-06-07 19:44:59 +02:00
|
|
|
}
|
|
|
|
|
|
2024-04-10 15:49:08 +02:00
|
|
|
shell.override_redirect_windows.iter().for_each(|or| {
|
2023-01-27 19:51:23 +01:00
|
|
|
if let Some(wl_surface) = or.wl_surface() {
|
2024-11-09 15:37:59 +01:00
|
|
|
send_frames_surface_tree(&wl_surface, output, time, THROTTLE, should_send);
|
2023-01-23 22:53:39 +01:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2022-11-17 20:32:54 +01:00
|
|
|
let map = smithay::desktop::layer_map_for_output(output);
|
|
|
|
|
for layer_surface in map.layers() {
|
2024-11-09 15:37:59 +01:00
|
|
|
layer_surface.send_frame(output, time, THROTTLE, should_send);
|
2022-11-17 20:32:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|