aboutsummaryrefslogtreecommitdiff
path: root/src/handlers
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-03-19 15:20:03 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-03-19 18:29:13 +0400
commitc61361de3ca4484387f39b067eadc612908560eb (patch)
tree0fc6f30df529c3ac4f7151e314e4d9548bc934bf /src/handlers
parent3963f537a4182dbcd8e1e2f262ee105473facc56 (diff)
downloadniri-c61361de3ca4484387f39b067eadc612908560eb.tar.gz
niri-c61361de3ca4484387f39b067eadc612908560eb.tar.bz2
niri-c61361de3ca4484387f39b067eadc612908560eb.zip
Implement window rule reloading and min/max size rules
Diffstat (limited to 'src/handlers')
-rw-r--r--src/handlers/xdg_shell.rs103
1 files changed, 21 insertions, 82 deletions
diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs
index 4d31645c..7bd47717 100644
--- a/src/handlers/xdg_shell.rs
+++ b/src/handlers/xdg_shell.rs
@@ -1,4 +1,3 @@
-use niri_config::{Match, WindowRule};
use smithay::desktop::{
find_popup_root_surface, get_popup_toplevel_coords, layer_map_for_output, LayerSurface,
PopupKeyboardGrab, PopupKind, PopupManager, PopupPointerGrab, PopupUngrabStrategy, Window,
@@ -20,7 +19,7 @@ use smithay::wayland::shell::wlr_layer::Layer;
use smithay::wayland::shell::xdg::decoration::XdgDecorationHandler;
use smithay::wayland::shell::xdg::{
PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData, XdgShellHandler,
- XdgShellState, XdgToplevelSurfaceData, XdgToplevelSurfaceRoleAttributes,
+ XdgShellState, XdgToplevelSurfaceData,
};
use smithay::wayland::xdg_foreign::{XdgForeignHandler, XdgForeignState};
use smithay::{
@@ -31,82 +30,6 @@ use crate::layout::workspace::ColumnWidth;
use crate::niri::{PopupGrabState, State};
use crate::window::{InitialConfigureState, ResolvedWindowRules, Unmapped};
-fn window_matches(role: &XdgToplevelSurfaceRoleAttributes, m: &Match) -> bool {
- if let Some(app_id_re) = &m.app_id {
- let Some(app_id) = &role.app_id else {
- return false;
- };
- if !app_id_re.is_match(app_id) {
- return false;
- }
- }
-
- if let Some(title_re) = &m.title {
- let Some(title) = &role.title else {
- return false;
- };
- if !title_re.is_match(title) {
- return false;
- }
- }
-
- true
-}
-
-pub fn resolve_window_rules(
- rules: &[WindowRule],
- toplevel: &ToplevelSurface,
-) -> ResolvedWindowRules {
- let _span = tracy_client::span!("resolve_window_rules");
-
- let mut resolved = ResolvedWindowRules::default();
-
- with_states(toplevel.wl_surface(), |states| {
- let role = states
- .data_map
- .get::<XdgToplevelSurfaceData>()
- .unwrap()
- .lock()
- .unwrap();
-
- let mut open_on_output = None;
-
- for rule in rules {
- if !(rule.matches.is_empty() || rule.matches.iter().any(|m| window_matches(&role, m))) {
- continue;
- }
-
- if rule.excludes.iter().any(|m| window_matches(&role, m)) {
- continue;
- }
-
- if let Some(x) = rule
- .default_column_width
- .as_ref()
- .map(|d| d.0.map(ColumnWidth::from))
- {
- resolved.default_width = Some(x);
- }
-
- if let Some(x) = rule.open_on_output.as_deref() {
- open_on_output = Some(x);
- }
-
- if let Some(x) = rule.open_maximized {
- resolved.open_maximized = Some(x);
- }
-
- if let Some(x) = rule.open_fullscreen {
- resolved.open_fullscreen = Some(x);
- }
- }
-
- resolved.open_on_output = open_on_output.map(|x| x.to_owned());
- });
-
- resolved
-}
-
impl XdgShellHandler for State {
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
&mut self.niri.xdg_shell_state
@@ -574,7 +497,7 @@ impl State {
};
let config = self.niri.config.borrow();
- let rules = resolve_window_rules(&config.window_rules, toplevel);
+ let rules = ResolvedWindowRules::compute(&config.window_rules, toplevel);
// Pick the target monitor. First, check if we had an output set in the window rules.
let mon = rules
@@ -807,14 +730,30 @@ impl State {
}
pub fn update_window_rules(&mut self, toplevel: &ToplevelSurface) {
- let resolve = || resolve_window_rules(&self.niri.config.borrow().window_rules, toplevel);
+ let resolve =
+ || ResolvedWindowRules::compute(&self.niri.config.borrow().window_rules, toplevel);
if let Some(unmapped) = self.niri.unmapped_windows.get_mut(toplevel.wl_surface()) {
if let InitialConfigureState::Configured { rules, .. } = &mut unmapped.state {
*rules = resolve();
}
- } else if let Some(mapped) = self.niri.layout.find_window_mut(toplevel.wl_surface()) {
- mapped.rules = resolve();
+ } else if let Some((mapped, output)) = self
+ .niri
+ .layout
+ .find_window_and_output_mut(toplevel.wl_surface())
+ {
+ let new_rules = resolve();
+ if mapped.rules != new_rules {
+ mapped.rules = new_rules;
+
+ let output = output.cloned();
+ let window = mapped.window.clone();
+ self.niri.layout.update_window(&window);
+
+ if let Some(output) = output {
+ self.niri.queue_redraw(output);
+ }
+ }
}
}
}