Add XWayland support (#16)
* save dev state * fix xwayland-satellite supervisor lifecycle, readiness and cleanup * remove wayland scanner protocol generated files * default xwayland enabled with path * remove jargons * address x11 review: park unconfirmed cleanup, never signal a reaped group, fix storm test and notify dir mode * fix resize tests: never build Size values from negative dimensions * add min-width/min-height window rules that replace client minimum sizes * rename effective_size_constraints to effective_minimum_size and minor cleanups
This commit is contained in:
1 parent
ed23949a95
commit
a6f83689f8
42 files changed
+7162
-1333
No files matched your search
@@ -300,16 +300,21 @@ impl Ferese {
|
||||
let constraints = window
|
||||
.toplevel()
|
||||
.map(|top| {
|
||||
with_states(top.wl_surface(), |states| {
|
||||
let (minimum, maximum) = with_states(top.wl_surface(), |states| {
|
||||
let mut cache = states.cached_state.get::<SurfaceCachedState>();
|
||||
let state = cache.current();
|
||||
SizeConstraints {
|
||||
min_width: state.min_size.w.max(1) as f64,
|
||||
min_height: state.min_size.h.max(1) as f64,
|
||||
max_width: (state.max_size.w > 0).then_some(state.max_size.w as f64),
|
||||
max_height: (state.max_size.h > 0).then_some(state.max_size.h as f64),
|
||||
}
|
||||
})
|
||||
(
|
||||
(state.min_size.w, state.min_size.h),
|
||||
(state.max_size.w, state.max_size.h),
|
||||
)
|
||||
});
|
||||
let (minimum, maximum) = self.effective_size_constraints(window, minimum, maximum);
|
||||
SizeConstraints {
|
||||
min_width: minimum.0.max(1) as f64,
|
||||
min_height: minimum.1.max(1) as f64,
|
||||
max_width: (maximum.0 > 0).then_some(maximum.0 as f64),
|
||||
max_height: (maximum.1 > 0).then_some(maximum.1 as f64),
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let stored_size = if parent_rect.is_none() {
|
||||
|
||||
@@ -574,14 +574,19 @@ impl Ferese {
|
||||
let state = cached.current();
|
||||
(state.min_size, state.max_size)
|
||||
});
|
||||
let (minimum, maximum) = self.effective_size_constraints(
|
||||
window,
|
||||
(minimum.w, minimum.h),
|
||||
(maximum.w, maximum.h),
|
||||
);
|
||||
|
||||
Some((
|
||||
*id,
|
||||
SizeConstraints {
|
||||
min_width: minimum.w.max(1) as f64,
|
||||
min_height: minimum.h.max(1) as f64,
|
||||
max_width: (maximum.w > 0).then_some(maximum.w as f64),
|
||||
max_height: (maximum.h > 0).then_some(maximum.h as f64),
|
||||
min_width: minimum.0.max(1) as f64,
|
||||
min_height: minimum.1.max(1) as f64,
|
||||
max_width: (maximum.0 > 0).then_some(maximum.0 as f64),
|
||||
max_height: (maximum.1 > 0).then_some(maximum.1 as f64),
|
||||
},
|
||||
))
|
||||
})
|
||||
|
||||
@@ -463,3 +463,41 @@ fn malformed_resize_limits_disconnect_only_the_client_and_motion_survives() {
|
||||
let (healthy, _wire) = window(&mut state, &mut events, 0xff112233);
|
||||
assert!(state.windows.ids().contains_key(&healthy));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn window_rule_minimum_size_replaces_the_client_advertised_minimum() {
|
||||
if !crate::startup_tests::private_runtime(
|
||||
"state::window_lifecycle_tests::window_rule_minimum_size_replaces_the_client_advertised_minimum",
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let (mut events, mut state, _) = fixture();
|
||||
let (window, mut wire) = window(&mut state, &mut events, 0xff112233);
|
||||
let id = state.windows.ids()[&window];
|
||||
request(&mut wire, 4, 8, &[800, 600], None);
|
||||
request(&mut wire, 2, 6, &[], None);
|
||||
dispatch(&mut events, &mut state);
|
||||
assert_eq!(state.effective_size_constraints(&window, (800, 600), (0,0)).0, (800, 600));
|
||||
assert_eq!(state.window_constraints()[&id].min_width, 800.0);
|
||||
assert_eq!(state.window_constraints()[&id].min_height, 600.0);
|
||||
|
||||
state.window_rules =
|
||||
crate::config::Config::parse_source("window-rule transient=#false min-width=500 min-height=400\n")
|
||||
.unwrap()
|
||||
.window_rules()
|
||||
.unwrap();
|
||||
assert_eq!(state.effective_size_constraints(&window, (800, 600), (0,0)).0, (500, 400));
|
||||
let constraints = state.window_constraints();
|
||||
assert_eq!(constraints[&id].min_width, 500.0);
|
||||
assert_eq!(constraints[&id].min_height, 400.0);
|
||||
|
||||
state.window_rules = crate::config::Config::parse_source("window-rule transient=#false min-height=400\n")
|
||||
.unwrap()
|
||||
.window_rules()
|
||||
.unwrap();
|
||||
assert_eq!(state.effective_size_constraints(&window, (800, 600), (0,0)).0, (800, 400));
|
||||
|
||||
state.window_rules.clear();
|
||||
assert_eq!(state.effective_size_constraints(&window, (800, 600), (0,0)).0, (800, 600));
|
||||
}
|
||||
@@ -261,8 +261,42 @@ impl Ferese {
|
||||
self.apply_window_rule_result(window, rule);
|
||||
}
|
||||
|
||||
pub(crate) fn effective_size_constraints(
|
||||
&self,
|
||||
window: &Window,
|
||||
minimum: (i32, i32),
|
||||
maximum: (i32, i32),
|
||||
) -> ((i32, i32), (i32, i32)) {
|
||||
let Some(toplevel) = window.toplevel() else {
|
||||
return (minimum, maximum);
|
||||
};
|
||||
let rules = &self.window_rules;
|
||||
with_states(toplevel.wl_surface(), |states| {
|
||||
let attributes = states
|
||||
.data_map
|
||||
.get::<XdgToplevelSurfaceData>()
|
||||
.expect("xdg toplevel state exists")
|
||||
.lock()
|
||||
.expect("xdg toplevel state is not poisoned");
|
||||
let rule = resolve_window_rules(
|
||||
rules,
|
||||
attributes.app_id.as_deref(),
|
||||
attributes.title.as_deref(),
|
||||
attributes.parent.is_some(),
|
||||
);
|
||||
(
|
||||
(
|
||||
rule.min_width.map_or(minimum.0, |width| width.ceil() as i32),
|
||||
rule.min_height.map_or(minimum.1, |height| height.ceil() as i32),
|
||||
),
|
||||
maximum,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn reapply_window_rules(&mut self, old_rules: &[WindowRule]) {
|
||||
let windows = self.windows.ids().keys().cloned().collect::<Vec<_>>();
|
||||
let mut minimums_changed = false;
|
||||
for window in windows {
|
||||
let Some(toplevel) = window.toplevel() else {
|
||||
continue;
|
||||
@@ -278,10 +312,14 @@ impl Ferese {
|
||||
});
|
||||
let old = resolve_window_rules(old_rules, app_id.as_deref(), title.as_deref(), transient);
|
||||
let new = resolve_window_rules(&self.window_rules, app_id.as_deref(), title.as_deref(), transient);
|
||||
minimums_changed |= old.min_width != new.min_width || old.min_height != new.min_height;
|
||||
if let Some(new) = crate::window_rules::live_result(old, new, transient) {
|
||||
self.apply_window_rule_result(&window, new);
|
||||
}
|
||||
}
|
||||
if minimums_changed {
|
||||
self.relayout();
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn apply_window_rule_result(&mut self, window: &Window, rule: crate::window_rules::WindowRuleResult) {
|
||||
|
||||
Reference in new issue
Block a user