Skip to content

Commit 5906717

Browse files
committed
implement context menu grab on inputs
1 parent 9dddead commit 5906717

File tree

6 files changed

+148
-53
lines changed

6 files changed

+148
-53
lines changed

src/input/mod.rs

Lines changed: 138 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::{
3131
};
3232
use calloop::{
3333
timer::{TimeoutAction, Timer},
34-
RegistrationToken,
34+
LoopHandle, RegistrationToken,
3535
};
3636
use cosmic_comp_config::workspace::WorkspaceLayout;
3737
use cosmic_settings_config::shortcuts;
@@ -58,7 +58,8 @@ use smithay::{
5858
},
5959
output::Output,
6060
reexports::{
61-
input::Device as InputDevice, wayland_server::protocol::wl_shm::Format as ShmFormat,
61+
input::Device as InputDevice,
62+
wayland_server::protocol::{wl_shm::Format as ShmFormat, wl_surface::WlSurface},
6263
},
6364
utils::{Point, Rectangle, Serial, SERIAL_COUNTER},
6465
wayland::{
@@ -677,6 +678,66 @@ impl State {
677678
}
678679
}
679680

681+
fn window_menu(
682+
seat: Seat<State>,
683+
evlh: &LoopHandle<State>,
684+
surface: WlSurface,
685+
serial: Serial,
686+
) {
687+
evlh.insert_idle(move |state| {
688+
let shell = state.common.shell.write().unwrap();
689+
690+
let grab = if let Some(mapped) =
691+
shell.element_for_surface(&surface).cloned()
692+
{
693+
let position = if let Some((output, set)) =
694+
shell.workspaces.sets.iter().find(|(_, set)| {
695+
set.sticky_layer
696+
.mapped()
697+
.any(|m| m == &mapped)
698+
}) {
699+
set.sticky_layer
700+
.element_geometry(&mapped)
701+
.unwrap()
702+
.loc
703+
.to_global(output)
704+
} else if let Some(workspace) =
705+
shell.space_for(&mapped)
706+
{
707+
let Some(elem_geo) =
708+
workspace.element_geometry(&mapped)
709+
else {
710+
return;
711+
};
712+
elem_geo.loc.to_global(&workspace.output)
713+
} else {
714+
return;
715+
};
716+
let cursor = seat
717+
.get_pointer()
718+
.unwrap()
719+
.current_location()
720+
.to_i32_round();
721+
722+
shell.menu_request(
723+
&surface,
724+
&seat,
725+
serial,
726+
cursor - position.as_logical(),
727+
false,
728+
&state.common.config,
729+
&state.common.event_loop_handle,
730+
false,
731+
)
732+
} else {
733+
None
734+
};
735+
drop(shell);
736+
737+
dispatch_grab(grab, seat, serial, state);
738+
});
739+
}
740+
680741
if let Some(mouse_button) = mouse_button {
681742
match mouse_button {
682743
smithay::backend::input::MouseButton::Left => {
@@ -703,56 +764,84 @@ impl State {
703764
},
704765
);
705766
}
706-
smithay::backend::input::MouseButton::Right => {
767+
smithay::backend::input::MouseButton::Middle => {
707768
supress_button();
708-
self.common.event_loop_handle.insert_idle(
709-
move |state| {
710-
let mut shell =
711-
state.common.shell.write().unwrap();
712-
let Some(target_elem) =
713-
shell.element_for_surface(&surface)
714-
else {
715-
return;
716-
};
717-
let Some(geom) =
718-
shell.space_for(target_elem).and_then(
719-
|f| f.element_geometry(target_elem),
720-
)
721-
else {
722-
return;
723-
};
724-
let geom = geom.to_f64();
725-
let center =
726-
geom.loc + geom.size.downscale(2.0);
727-
let offset = center.to_global(&output)
728-
- global_position;
729-
let edge = match (
730-
offset.x > 0.0,
731-
offset.y > 0.0,
732-
) {
733-
(true, true) => ResizeEdge::TOP_LEFT,
734-
(false, true) => ResizeEdge::TOP_RIGHT,
735-
(true, false) => {
736-
ResizeEdge::BOTTOM_LEFT
737-
}
738-
(false, false) => {
739-
ResizeEdge::BOTTOM_RIGHT
740-
}
741-
};
742-
let res = shell.resize_request(
743-
&surface,
744-
&seat_clone,
745-
serial,
746-
edge,
747-
false,
748-
);
749-
drop(shell);
750-
dispatch_grab(
751-
res, seat_clone, serial, state,
752-
);
753-
},
769+
window_menu(
770+
seat_clone,
771+
&self.common.event_loop_handle,
772+
surface,
773+
serial,
754774
);
755775
}
776+
smithay::backend::input::MouseButton::Right => {
777+
supress_button();
778+
if seat
779+
.get_keyboard()
780+
.unwrap()
781+
.modifier_state()
782+
.shift
783+
{
784+
window_menu(
785+
seat_clone,
786+
&self.common.event_loop_handle,
787+
surface,
788+
serial,
789+
);
790+
} else {
791+
self.common.event_loop_handle.insert_idle(
792+
move |state| {
793+
let mut shell =
794+
state.common.shell.write().unwrap();
795+
let Some(target_elem) =
796+
shell.element_for_surface(&surface)
797+
else {
798+
return;
799+
};
800+
let Some(geom) = shell
801+
.space_for(target_elem)
802+
.and_then(|f| {
803+
f.element_geometry(target_elem)
804+
})
805+
else {
806+
return;
807+
};
808+
let geom = geom.to_f64();
809+
let center =
810+
geom.loc + geom.size.downscale(2.0);
811+
let offset = center.to_global(&output)
812+
- global_position;
813+
let edge = match (
814+
offset.x > 0.0,
815+
offset.y > 0.0,
816+
) {
817+
(true, true) => {
818+
ResizeEdge::TOP_LEFT
819+
}
820+
(false, true) => {
821+
ResizeEdge::TOP_RIGHT
822+
}
823+
(true, false) => {
824+
ResizeEdge::BOTTOM_LEFT
825+
}
826+
(false, false) => {
827+
ResizeEdge::BOTTOM_RIGHT
828+
}
829+
};
830+
let res = shell.resize_request(
831+
&surface,
832+
&seat_clone,
833+
serial,
834+
edge,
835+
false,
836+
);
837+
drop(shell);
838+
dispatch_grab(
839+
res, seat_clone, serial, state,
840+
);
841+
},
842+
);
843+
}
844+
}
756845
_ => {}
757846
}
758847
}
@@ -786,8 +875,6 @@ impl State {
786875
},
787876
);
788877
ptr.frame(self);
789-
} else if event.state() == ButtonState::Released {
790-
ptr.unset_grab(self, serial, event.time_msec())
791878
}
792879
}
793880
InputEvent::PointerAxis { event, .. } => {

src/shell/element/stack.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,7 @@ impl Program for CosmicStackInternal {
872872
true,
873873
&state.common.config,
874874
&state.common.event_loop_handle,
875+
true,
875876
);
876877

877878
std::mem::drop(shell);
@@ -914,6 +915,7 @@ impl Program for CosmicStackInternal {
914915
false,
915916
&state.common.config,
916917
&state.common.event_loop_handle,
918+
true,
917919
);
918920

919921
std::mem::drop(shell);

src/shell/element/window.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ impl Program for CosmicWindowInternal {
515515
false,
516516
&state.common.config,
517517
&state.common.event_loop_handle,
518+
true,
518519
);
519520

520521
std::mem::drop(shell);

src/shell/grabs/menu/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,10 @@ impl Item {
161161
}
162162
}
163163

164-
/// Menu that comes up when right-clicking an application header bar
164+
/// Menu that comes up when:
165+
/// - Right-clicking an application header bar
166+
/// - Super + Middle-clicking a window
167+
/// - Super + Shift + Right-clicking a window
165168
pub struct ContextMenu {
166169
items: Vec<Item>,
167170
selected: AtomicBool,

src/shell/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2564,10 +2564,11 @@ impl Shell {
25642564
target_stack: bool,
25652565
config: &Config,
25662566
evlh: &LoopHandle<'static, State>,
2567+
client_initiated: bool,
25672568
) -> Option<(MenuGrab, Focus)> {
25682569
let serial = serial.into();
25692570
let Some(GrabStartData::Pointer(start_data)) =
2570-
check_grab_preconditions(&seat, surface, serial, true)
2571+
check_grab_preconditions(&seat, surface, serial, client_initiated)
25712572
else {
25722573
return None;
25732574
};

src/wayland/handlers/xdg_shell/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ impl XdgShellHandler for State {
439439
false,
440440
&self.common.config,
441441
&self.common.event_loop_handle,
442+
true,
442443
);
443444
if let Some((grab, focus)) = res {
444445
std::mem::drop(shell);

0 commit comments

Comments
 (0)