Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Close tab on middle mouse click. #814

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions cosmic-comp-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub struct CosmicCompConfig {
/// If set to Global, autotile applies to all windows in all workspaces
/// If set to PerWorkspace, autotile only applies to new windows, and new workspaces
pub autotile_behavior: TileBehavior,
/// Configure behavior of the stack layout.
pub stack_behavior: StackBehavior,
/// Active hint enabled
pub active_hint: bool,
/// Enables changing keyboard focus to windows when the cursor passes into them
Expand Down Expand Up @@ -55,6 +57,7 @@ impl Default for CosmicCompConfig {
xkb_config: Default::default(),
autotile: Default::default(),
autotile_behavior: Default::default(),
stack_behavior: StackBehavior::default(),
active_hint: true,
focus_follows_cursor: false,
cursor_follows_focus: false,
Expand Down Expand Up @@ -105,3 +108,16 @@ fn default_repeat_rate() -> u32 {
fn default_repeat_delay() -> u32 {
600
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StackBehavior {
pub close_tab_on_middle_click: bool,
}

impl Default for StackBehavior {
fn default() -> Self {
Self {
close_tab_on_middle_click: true,
}
}
}
15 changes: 14 additions & 1 deletion src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ mod types;
pub use self::types::*;
use cosmic::config::CosmicTk;
use cosmic_comp_config::{
input::InputConfig, workspace::WorkspaceConfig, CosmicCompConfig, TileBehavior, XkbConfig,
input::InputConfig, workspace::WorkspaceConfig, CosmicCompConfig, StackBehavior, TileBehavior,
XkbConfig,
};

#[derive(Debug)]
Expand Down Expand Up @@ -690,6 +691,18 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
);
}
}
"stack_behavior" => {
let new = get_config::<StackBehavior>(&config, "stack_behavior");
if new != state.common.config.cosmic_conf.stack_behavior {
state.common.config.cosmic_conf.stack_behavior = new.clone();

let mut shell = state.common.shell.write().unwrap();
let shell_ref = &mut *shell;
shell_ref
.workspaces
.update_stack_behavior(new, shell_ref.seats.iter())
}
}
"active_hint" => {
let new = get_config::<bool>(&config, "active_hint");
if new != state.common.config.cosmic_conf.active_hint {
Expand Down
11 changes: 10 additions & 1 deletion src/shell/element/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
utils::{iced::IcedElementInternal, prelude::*},
};
use calloop::LoopHandle;
use cosmic_comp_config::StackBehavior;
use id_tree::NodeId;
use smithay::{
backend::{
Expand Down Expand Up @@ -592,14 +593,15 @@ impl CosmicMapped {
&mut self,
(output, overlap): (&Output, Rectangle<i32, Logical>),
theme: cosmic::Theme,
config: StackBehavior,
) {
match &self.element {
CosmicMappedInternal::Window(window) => {
let surface = window.surface();
let activated = surface.is_activated(true);
let handle = window.loop_handle();

let stack = CosmicStack::new(std::iter::once(surface), handle, theme);
let stack = CosmicStack::new(std::iter::once(surface), handle, theme, config);
if let Some(geo) = self.last_geometry.lock().unwrap().clone() {
stack.set_geometry(geo.to_global(&output));
}
Expand Down Expand Up @@ -893,6 +895,13 @@ impl CosmicMapped {
_ => unreachable!(),
})
}

pub fn update_stack_behavior(&mut self, behavior: &StackBehavior) {
if let CosmicMappedInternal::Stack(stack) = &mut self.element {
let mut inner = stack.0 .0.lock().unwrap();
inner.program_mut().update_behavior(behavior.clone());
}
}
}

impl IsAlive for CosmicMapped {
Expand Down
19 changes: 17 additions & 2 deletions src/shell/element/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use cosmic::{
iced_widget::scrollable::AbsoluteOffset,
theme, widget as cosmic_widget, Apply, Element as CosmicElement, Theme,
};
use cosmic_comp_config::StackBehavior;
use cosmic_settings_config::shortcuts;
use once_cell::sync::Lazy;
use shortcuts::action::{Direction, FocusDirection};
Expand Down Expand Up @@ -102,6 +103,8 @@ pub struct CosmicStackInternal {
last_seat: Arc<Mutex<Option<(Seat<State>, Serial)>>>,
geometry: Arc<Mutex<Option<Rectangle<i32, Global>>>>,
mask: Arc<Mutex<Option<tiny_skia::Mask>>>,

behavior: StackBehavior,
}

impl CosmicStackInternal {
Expand All @@ -113,6 +116,10 @@ impl CosmicStackInternal {
pub fn current_focus(&self) -> Option<Focus> {
unsafe { Focus::from_u8(self.pointer_entered.load(Ordering::SeqCst)) }
}

pub fn update_behavior(&mut self, behavior: StackBehavior) {
self.behavior = behavior;
}
}

pub const TAB_HEIGHT: i32 = 24;
Expand All @@ -129,6 +136,7 @@ impl CosmicStack {
windows: impl Iterator<Item = I>,
handle: LoopHandle<'static, crate::state::State>,
theme: cosmic::Theme,
behavior: StackBehavior,
) -> CosmicStack {
let windows = windows.map(Into::into).collect::<Vec<_>>();
assert!(!windows.is_empty());
Expand All @@ -155,6 +163,7 @@ impl CosmicStack {
last_seat: Arc::new(Mutex::new(None)),
geometry: Arc::new(Mutex::new(None)),
mask: Arc::new(Mutex::new(None)),
behavior,
},
(width, TAB_HEIGHT),
handle,
Expand Down Expand Up @@ -890,14 +899,20 @@ impl Program for CosmicStackInternal {
windows.iter().enumerate().map(|(i, w)| {
let user_data = w.user_data();
user_data.insert_if_missing(Id::unique);
Tab::new(
let mut tab = Tab::new(
w.title(),
w.app_id(),
user_data.get::<Id>().unwrap().clone(),
)
.on_press(Message::PotentialTabDragStart(i))
.on_right_click(Message::TabMenu(i))
.on_close(Message::Close(i))
.on_close(Message::Close(i));

if self.behavior.close_tab_on_middle_click {
tab = tab.on_middle_click(Message::Close(i));
}

tab
}),
active,
windows[active].is_activated(false),
Expand Down
19 changes: 19 additions & 0 deletions src/shell/element/stack/tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ pub struct Tab<Message: TabMessage> {
close_message: Option<Message>,
press_message: Option<Message>,
right_click_message: Option<Message>,
middle_click_message: Option<Message>,
rule_theme: TabRuleTheme,
background_theme: TabBackgroundTheme,
active: bool,
Expand All @@ -162,6 +163,7 @@ impl<Message: TabMessage + 'static> Tab<Message> {
close_message: None,
press_message: None,
right_click_message: None,
middle_click_message: None,
rule_theme: TabRuleTheme::Default,
background_theme: TabBackgroundTheme::Default,
active: false,
Expand All @@ -178,6 +180,11 @@ impl<Message: TabMessage + 'static> Tab<Message> {
self
}

pub fn on_middle_click(mut self, message: Message) -> Self {
self.middle_click_message = Some(message);
self
}

pub fn on_close(mut self, message: Message) -> Self {
self.close_message = Some(message);
self
Expand Down Expand Up @@ -254,6 +261,7 @@ impl<Message: TabMessage + 'static> Tab<Message> {
elements: items,
press_message: self.press_message,
right_click_message: self.right_click_message,
middle_click_message: self.middle_click_message,
}
}
}
Expand All @@ -273,6 +281,7 @@ pub(super) struct TabInternal<'a, Message: TabMessage> {
elements: Vec<cosmic::Element<'a, Message>>,
press_message: Option<Message>,
right_click_message: Option<Message>,
middle_click_message: Option<Message>,
}

impl<'a, Message> Widget<Message, cosmic::Theme, cosmic::Renderer> for TabInternal<'a, Message>
Expand Down Expand Up @@ -418,6 +427,16 @@ where
shell.publish(Message::activate(self.idx));
return event::Status::Captured;
}

if matches!(
event,
event::Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Middle))
) {
if let Some(message) = self.middle_click_message.clone() {
shell.publish(message);
return event::Status::Captured;
}
}
}

status
Expand Down
11 changes: 9 additions & 2 deletions src/shell/layout/floating/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{
time::{Duration, Instant},
};

use cosmic_comp_config::StackBehavior;
use cosmic_settings_config::shortcuts::action::ResizeDirection;
use keyframe::{ease, functions::EaseInOutCubic};
use smithay::{
Expand Down Expand Up @@ -886,6 +887,7 @@ impl FloatingLayout {
&mut self,
mapped: &CosmicMapped,
mut focus_stack: FocusStackMut,
stack_behavior: &StackBehavior,
) -> Option<KeyboardFocusTarget> {
if !self.space.elements().any(|m| m == mapped) {
return None;
Expand All @@ -899,7 +901,11 @@ impl FloatingLayout {
if mapped.is_window() {
// if it is just a window
self.space.unmap_elem(&mapped);
mapped.convert_to_stack((&output, mapped.bbox()), self.theme.clone());
mapped.convert_to_stack(
(&output, mapped.bbox()),
self.theme.clone(),
stack_behavior.clone(),
);
self.map_internal(
mapped.clone(),
Some(location.as_local()),
Expand Down Expand Up @@ -957,13 +963,14 @@ impl FloatingLayout {
&mut self,
seat: &Seat<State>,
focus_stack: FocusStackMut,
stack_behavior: &StackBehavior,
) -> Option<KeyboardFocusTarget> {
let Some(KeyboardFocusTarget::Element(elem)) = seat.get_keyboard().unwrap().current_focus()
else {
return None;
};

self.toggle_stacking(&elem, focus_stack)
self.toggle_stacking(&elem, focus_stack, stack_behavior)
}

pub fn move_element(
Expand Down
32 changes: 27 additions & 5 deletions src/shell/layout/tiling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use crate::{
},
};

use cosmic_comp_config::StackBehavior;
use cosmic_settings_config::shortcuts::action::{FocusDirection, ResizeDirection};
use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBehavior, Tree};
use keyframe::{
Expand Down Expand Up @@ -135,6 +136,7 @@ pub struct TilingLayout {
swapping_stack_surface_id: Id,
last_overview_hover: Option<(Option<Instant>, TargetZone)>,
pub theme: cosmic::Theme,
pub stack_behavior: StackBehavior,
}

#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -342,7 +344,11 @@ pub struct MinimizedTilingState {
}

impl TilingLayout {
pub fn new(theme: cosmic::Theme, output: &Output) -> TilingLayout {
pub fn new(
theme: cosmic::Theme,
output: &Output,
stack_behavior: StackBehavior,
) -> TilingLayout {
TilingLayout {
queue: TreeQueue {
trees: {
Expand All @@ -358,6 +364,7 @@ impl TilingLayout {
swapping_stack_surface_id: Id::new(),
last_overview_hover: None,
theme,
stack_behavior,
}
}

Expand Down Expand Up @@ -2121,6 +2128,7 @@ impl TilingLayout {
&mut self,
mapped: &CosmicMapped,
mut focus_stack: FocusStackMut,
stack_behavior: &StackBehavior,
) -> Option<KeyboardFocusTarget> {
let gaps = self.gaps();

Expand All @@ -2137,7 +2145,11 @@ impl TilingLayout {
// if it is just a window
match tree.get_mut(&node_id).unwrap().data_mut() {
Data::Mapped { mapped, .. } => {
mapped.convert_to_stack((&self.output, mapped.bbox()), self.theme.clone());
mapped.convert_to_stack(
(&self.output, mapped.bbox()),
self.theme.clone(),
stack_behavior.clone(),
);
focus_stack.append(&mapped);
KeyboardFocusTarget::Element(mapped.clone())
}
Expand Down Expand Up @@ -2238,6 +2250,7 @@ impl TilingLayout {
&mut self,
seat: &Seat<State>,
mut focus_stack: FocusStackMut,
stack_behavior: &StackBehavior,
) -> Option<KeyboardFocusTarget> {
let gaps = self.gaps();

Expand All @@ -2251,7 +2264,7 @@ impl TilingLayout {
{
match last_active_data {
FocusedNodeData::Window(mapped) => {
return self.toggle_stacking(&mapped, focus_stack);
return self.toggle_stacking(&mapped, focus_stack, stack_behavior);
}
FocusedNodeData::Group(_, _) => {
let mut handle = None;
Expand All @@ -2274,7 +2287,12 @@ impl TilingLayout {
return None;
}
let handle = handle.unwrap();
let stack = CosmicStack::new(surfaces.into_iter(), handle, self.theme.clone());
let stack = CosmicStack::new(
surfaces.into_iter(),
handle,
self.theme.clone(),
stack_behavior.clone(),
);

for child in tree
.children_ids(&last_active)
Expand Down Expand Up @@ -2741,7 +2759,11 @@ impl TilingLayout {
Some(TargetZone::WindowStack(window_id, _)) if tree.get(&window_id).is_ok() => {
match tree.get_mut(window_id).unwrap().data_mut() {
Data::Mapped { mapped, .. } => {
mapped.convert_to_stack((&self.output, mapped.bbox()), self.theme.clone());
mapped.convert_to_stack(
(&self.output, mapped.bbox()),
self.theme.clone(),
self.stack_behavior.clone(),
);
let Some(stack) = mapped.stack_ref_mut() else {
unreachable!()
};
Expand Down
Loading