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

feat: Super + Shift + Right Click or Super + Middle Click to open window context menu #1118

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
209 changes: 158 additions & 51 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
target::{KeyboardFocusTarget, PointerFocusTarget},
Stage,
},
grabs::{ReleaseMode, ResizeEdge},
grabs::{ReleaseMode, ResizeEdge, UngrabOnPointerUp},
layout::{
floating::ResizeGrabMarker,
tiling::{NodeDesc, TilingLayout},
Expand All @@ -31,7 +31,7 @@ use crate::{
};
use calloop::{
timer::{TimeoutAction, Timer},
RegistrationToken,
LoopHandle, RegistrationToken,
};
use cosmic_comp_config::workspace::WorkspaceLayout;
use cosmic_settings_config::shortcuts;
Expand All @@ -58,7 +58,8 @@ use smithay::{
},
output::Output,
reexports::{
input::Device as InputDevice, wayland_server::protocol::wl_shm::Format as ShmFormat,
input::Device as InputDevice,
wayland_server::protocol::{wl_shm::Format as ShmFormat, wl_surface::WlSurface},
},
utils::{Point, Rectangle, Serial, SERIAL_COUNTER},
wayland::{
Expand Down Expand Up @@ -677,6 +678,66 @@ impl State {
}
}

fn window_menu(
seat: Seat<State>,
evlh: &LoopHandle<State>,
surface: WlSurface,
serial: Serial,
) {
evlh.insert_idle(move |state| {
let shell = state.common.shell.write().unwrap();

let grab = if let Some(mapped) =
shell.element_for_surface(&surface).cloned()
{
let position = if let Some((output, set)) =
shell.workspaces.sets.iter().find(|(_, set)| {
set.sticky_layer
.mapped()
.any(|m| m == &mapped)
}) {
set.sticky_layer
.element_geometry(&mapped)
.unwrap()
.loc
.to_global(output)
} else if let Some(workspace) =
shell.space_for(&mapped)
{
let Some(elem_geo) =
workspace.element_geometry(&mapped)
else {
return;
};
elem_geo.loc.to_global(&workspace.output)
} else {
return;
};
let cursor = seat
.get_pointer()
.unwrap()
.current_location()
.to_i32_round();

shell.menu_request(
&surface,
&seat,
serial,
cursor - position.as_logical(),
false,
&state.common.config,
&state.common.event_loop_handle,
false,
)
} else {
None
};
drop(shell);

dispatch_grab(grab, seat, serial, state);
});
}

if let Some(mouse_button) = mouse_button {
match mouse_button {
smithay::backend::input::MouseButton::Left => {
Expand All @@ -696,63 +757,104 @@ impl State {
&state.common.xdg_activation_state,
false,
);

drop(shell);

seat_clone
.user_data()
.get_or_insert(UngrabOnPointerUp::new)
.set(true);
dispatch_grab(
res, seat_clone, serial, state,
);
},
);
}
smithay::backend::input::MouseButton::Right => {
smithay::backend::input::MouseButton::Middle => {
supress_button();
self.common.event_loop_handle.insert_idle(
move |state| {
let mut shell =
state.common.shell.write().unwrap();
let Some(target_elem) =
shell.element_for_surface(&surface)
else {
return;
};
let Some(geom) =
shell.space_for(target_elem).and_then(
|f| f.element_geometry(target_elem),
)
else {
return;
};
let geom = geom.to_f64();
let center =
geom.loc + geom.size.downscale(2.0);
let offset = center.to_global(&output)
- global_position;
let edge = match (
offset.x > 0.0,
offset.y > 0.0,
) {
(true, true) => ResizeEdge::TOP_LEFT,
(false, true) => ResizeEdge::TOP_RIGHT,
(true, false) => {
ResizeEdge::BOTTOM_LEFT
}
(false, false) => {
ResizeEdge::BOTTOM_RIGHT
}
};
let res = shell.resize_request(
&surface,
&seat_clone,
serial,
edge,
false,
);
drop(shell);
dispatch_grab(
res, seat_clone, serial, state,
);
},
window_menu(
seat_clone,
&self.common.event_loop_handle,
surface,
serial,
);
}
smithay::backend::input::MouseButton::Right => {
supress_button();
if seat
.get_keyboard()
.unwrap()
.modifier_state()
.shift
{
window_menu(
seat_clone,
&self.common.event_loop_handle,
surface,
serial,
);
} else {
self.common.event_loop_handle.insert_idle(
move |state| {
let mut shell =
state.common.shell.write().unwrap();
let Some(target_elem) =
shell.element_for_surface(&surface)
else {
return;
};
let Some(geom) = shell
.space_for(target_elem)
.and_then(|f| {
f.element_geometry(target_elem)
})
else {
return;
};
let geom = geom.to_f64();
let center =
geom.loc + geom.size.downscale(2.0);
let offset = center.to_global(&output)
- global_position;
let edge = match (
offset.x > 0.0,
offset.y > 0.0,
) {
(true, true) => {
ResizeEdge::TOP_LEFT
}
(false, true) => {
ResizeEdge::TOP_RIGHT
}
(true, false) => {
ResizeEdge::BOTTOM_LEFT
}
(false, false) => {
ResizeEdge::BOTTOM_RIGHT
}
};
let res = shell.resize_request(
&surface,
&seat_clone,
serial,
edge,
false,
);
drop(shell);

seat_clone
.user_data()
.get_or_insert(
UngrabOnPointerUp::new,
)
.set(true);
dispatch_grab(
res, seat_clone, serial, state,
);
},
);
}
}
_ => {}
}
}
Expand Down Expand Up @@ -787,7 +889,12 @@ impl State {
);
ptr.frame(self);
} else if event.state() == ButtonState::Released {
ptr.unset_grab(self, serial, event.time_msec())
if let Some(ungrab) = seat.user_data().get::<UngrabOnPointerUp>() {
if ungrab.get() {
ungrab.set(false);
ptr.unset_grab(self, serial, event.time_msec())
}
}
}
}
InputEvent::PointerAxis { event, .. } => {
Expand Down
2 changes: 2 additions & 0 deletions src/shell/element/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,7 @@ impl Program for CosmicStackInternal {
true,
&state.common.config,
&state.common.event_loop_handle,
true,
);

std::mem::drop(shell);
Expand Down Expand Up @@ -914,6 +915,7 @@ impl Program for CosmicStackInternal {
false,
&state.common.config,
&state.common.event_loop_handle,
true,
);

std::mem::drop(shell);
Expand Down
1 change: 1 addition & 0 deletions src/shell/element/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ impl Program for CosmicWindowInternal {
false,
&state.common.config,
&state.common.event_loop_handle,
true,
);

std::mem::drop(shell);
Expand Down
5 changes: 4 additions & 1 deletion src/shell/grabs/menu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@ impl Item {
}
}

/// Menu that comes up when right-clicking an application header bar
/// Menu that comes up when:
/// - Right-clicking an application header bar
/// - Super + Middle-clicking a window
/// - Super + Shift + Right-clicking a window
pub struct ContextMenu {
items: Vec<Item>,
selected: AtomicBool,
Expand Down
18 changes: 18 additions & 0 deletions src/shell/grabs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::cell::Cell;

use cosmic_settings_config::shortcuts;
use smithay::{
input::{
Expand Down Expand Up @@ -67,6 +69,22 @@ pub enum ReleaseMode {
NoMouseButtons,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UngrabOnPointerUp(Cell<bool>);
impl UngrabOnPointerUp {
pub fn new() -> Self {
Self(Cell::new(false))
}

pub fn get(&self) -> bool {
self.0.get()
}

pub fn set(&self, ungrab: bool) {
self.0.set(ungrab);
}
}

mod menu;
pub use self::menu::*;
mod moving;
Expand Down
3 changes: 2 additions & 1 deletion src/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2564,10 +2564,11 @@ impl Shell {
target_stack: bool,
config: &Config,
evlh: &LoopHandle<'static, State>,
client_initiated: bool,
) -> Option<(MenuGrab, Focus)> {
let serial = serial.into();
let Some(GrabStartData::Pointer(start_data)) =
check_grab_preconditions(&seat, surface, serial, true)
check_grab_preconditions(&seat, surface, serial, client_initiated)
else {
return None;
};
Expand Down
1 change: 1 addition & 0 deletions src/wayland/handlers/xdg_shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ impl XdgShellHandler for State {
false,
&self.common.config,
&self.common.event_loop_handle,
true,
);
if let Some((grab, focus)) = res {
std::mem::drop(shell);
Expand Down
Loading