Merge pull request #449 from khyperia/relative-behavior-mode
implement new setting: fallback output mode
This commit is contained in:
commit
2f4543912b
29 changed files with 306 additions and 55 deletions
|
|
@ -728,6 +728,7 @@ fn create_dummy_output(state: &Rc<State>) {
|
|||
bar_rect: Default::default(),
|
||||
bar_rect_rel: Default::default(),
|
||||
bar_rect_with_separator: Default::default(),
|
||||
bar_separator_rect: Default::default(),
|
||||
bar_separator_rect_rel: Default::default(),
|
||||
non_exclusive_rect: Default::default(),
|
||||
render_data: Default::default(),
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ use {
|
|||
Axis, Direction, Workspace,
|
||||
client::{Client as ConfigClient, ClientCapabilities, ClientMatcher},
|
||||
input::{
|
||||
FocusFollowsMouseMode, InputDevice, LayerDirection, Seat, Timeline,
|
||||
FallbackOutputMode, FocusFollowsMouseMode, InputDevice, LayerDirection, Seat, Timeline,
|
||||
acceleration::{ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT, AccelProfile},
|
||||
capability::{
|
||||
CAP_GESTURE, CAP_KEYBOARD, CAP_POINTER, CAP_SWITCH, CAP_TABLET_PAD,
|
||||
|
|
@ -518,6 +518,16 @@ impl ConfigProxyHandler {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_fallback_output_mode(
|
||||
&self,
|
||||
seat: Seat,
|
||||
mode: FallbackOutputMode,
|
||||
) -> Result<(), CphError> {
|
||||
let seat = self.get_seat(seat)?;
|
||||
seat.set_fallback_output_mode(mode);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_window_management_enabled(
|
||||
&self,
|
||||
seat: Seat,
|
||||
|
|
@ -1012,16 +1022,16 @@ impl ConfigProxyHandler {
|
|||
self.state.double_click_distance.set(dist);
|
||||
}
|
||||
|
||||
fn handle_get_seat_workspace(&self, seat: Seat) -> Result<(), CphError> {
|
||||
fn handle_get_seat_cursor_workspace(&self, seat: Seat) -> Result<(), CphError> {
|
||||
let seat = self.get_seat(seat)?;
|
||||
let output = seat.get_output();
|
||||
let output = seat.get_cursor_output();
|
||||
let mut workspace = Workspace(0);
|
||||
if !output.is_dummy
|
||||
&& let Some(ws) = output.workspace.get()
|
||||
{
|
||||
workspace = self.get_workspace_by_name(&ws.name);
|
||||
}
|
||||
self.respond(Response::GetSeatWorkspace { workspace });
|
||||
self.respond(Response::GetSeatCursorWorkspace { workspace });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1056,7 +1066,7 @@ impl ConfigProxyHandler {
|
|||
let name = self.get_workspace(ws)?;
|
||||
let workspace = match self.state.workspaces.get(name.deref()) {
|
||||
Some(ws) => ws,
|
||||
_ => seat.get_output().create_workspace(name.deref()),
|
||||
_ => seat.get_fallback_output().create_workspace(name.deref()),
|
||||
};
|
||||
seat.set_workspace(&workspace);
|
||||
Ok(())
|
||||
|
|
@ -1112,10 +1122,12 @@ impl ConfigProxyHandler {
|
|||
Some(ws) => ws,
|
||||
_ => return Ok(()),
|
||||
},
|
||||
WorkspaceSource::Seat(s) => match self.get_seat(s)?.get_output().workspace.get() {
|
||||
Some(ws) => ws,
|
||||
_ => return Ok(()),
|
||||
},
|
||||
WorkspaceSource::Seat(s) => {
|
||||
match self.get_seat(s)?.get_fallback_output().workspace.get() {
|
||||
Some(ws) => ws,
|
||||
_ => return Ok(()),
|
||||
}
|
||||
}
|
||||
};
|
||||
self.state.move_ws_to_output(&ws, &output);
|
||||
Ok(())
|
||||
|
|
@ -2935,9 +2947,9 @@ impl ConfigProxyHandler {
|
|||
ClientMessage::MakeRenderDevice { device } => self
|
||||
.handle_make_render_device(device)
|
||||
.wrn("make_render_device")?,
|
||||
ClientMessage::GetSeatWorkspace { seat } => self
|
||||
.handle_get_seat_workspace(seat)
|
||||
.wrn("get_seat_workspace")?,
|
||||
ClientMessage::GetSeatCursorWorkspace { seat } => self
|
||||
.handle_get_seat_cursor_workspace(seat)
|
||||
.wrn("get_seat_cursor_workspace")?,
|
||||
ClientMessage::GetSeatKeyboardWorkspace { seat } => self
|
||||
.handle_get_seat_keyboard_workspace(seat)
|
||||
.wrn("get_seat_keyboard_workspace")?,
|
||||
|
|
@ -3354,6 +3366,9 @@ impl ConfigProxyHandler {
|
|||
} => self
|
||||
.handle_keymap_from_names(rules, model, groups, options)
|
||||
.wrn("keymap_from_names")?,
|
||||
ClientMessage::SetFallbackOutputMode { seat, mode } => self
|
||||
.handle_set_fallback_output_mode(seat, mode)
|
||||
.wrn("set_fallback_output_mode")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,10 @@ use {
|
|||
wire_ei::EiSeatId,
|
||||
},
|
||||
ahash::AHashMap,
|
||||
jay_config::keyboard::syms::{KeySym, SYM_Escape},
|
||||
jay_config::{
|
||||
input::FallbackOutputMode,
|
||||
keyboard::syms::{KeySym, SYM_Escape},
|
||||
},
|
||||
kbvm::Keycode,
|
||||
smallvec::SmallVec,
|
||||
std::{
|
||||
|
|
@ -226,6 +229,7 @@ pub struct WlSeatGlobal {
|
|||
input_method_grab: CloneCell<Option<Rc<dyn InputMethodKeyboardGrab>>>,
|
||||
forward: Cell<bool>,
|
||||
focus_follows_mouse: Cell<bool>,
|
||||
fallback_output_mode: Cell<FallbackOutputMode>,
|
||||
swipe_bindings: PerClientBindings<ZwpPointerGestureSwipeV1>,
|
||||
pinch_bindings: PerClientBindings<ZwpPointerGesturePinchV1>,
|
||||
hold_bindings: PerClientBindings<ZwpPointerGestureHoldV1>,
|
||||
|
|
@ -325,6 +329,7 @@ impl WlSeatGlobal {
|
|||
input_method_grab: Default::default(),
|
||||
forward: Cell::new(false),
|
||||
focus_follows_mouse: Cell::new(true),
|
||||
fallback_output_mode: Cell::new(FallbackOutputMode::Cursor),
|
||||
swipe_bindings: Default::default(),
|
||||
pinch_bindings: Default::default(),
|
||||
hold_bindings: Default::default(),
|
||||
|
|
@ -457,7 +462,7 @@ impl WlSeatGlobal {
|
|||
self.data_control_devices.remove(&device.id());
|
||||
}
|
||||
|
||||
pub fn get_output(&self) -> Rc<OutputNode> {
|
||||
pub fn get_cursor_output(&self) -> Rc<OutputNode> {
|
||||
self.cursor_user_group.latest_output()
|
||||
}
|
||||
|
||||
|
|
@ -469,6 +474,15 @@ impl WlSeatGlobal {
|
|||
self.keyboard_node.get().node_output()
|
||||
}
|
||||
|
||||
pub fn get_fallback_output(&self) -> Rc<OutputNode> {
|
||||
if self.fallback_output_mode.get() == FallbackOutputMode::Focus
|
||||
&& let Some(output) = self.get_keyboard_output()
|
||||
{
|
||||
return output;
|
||||
}
|
||||
self.get_cursor_output()
|
||||
}
|
||||
|
||||
pub fn set_workspace(&self, ws: &Rc<WorkspaceNode>) {
|
||||
let tl = match self.keyboard_node.get().node_toplevel() {
|
||||
Some(tl) => tl,
|
||||
|
|
@ -726,7 +740,16 @@ impl WlSeatGlobal {
|
|||
pub fn move_focus(self: &Rc<Self>, direction: Direction) {
|
||||
let tl = match self.keyboard_node.get().node_toplevel() {
|
||||
Some(tl) => tl,
|
||||
_ => return,
|
||||
_ => {
|
||||
if let Some(ws) = self.keyboard_node.get().node_into_workspace()
|
||||
&& let Some(target) = self
|
||||
.state
|
||||
.find_output_in_direction(&ws.output.get(), direction)
|
||||
{
|
||||
target.take_keyboard_navigation_focus(self, direction);
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
if direction == Direction::Down && tl.node_is_container() {
|
||||
tl.node_do_focus(self, direction);
|
||||
|
|
@ -748,6 +771,13 @@ impl WlSeatGlobal {
|
|||
pub fn move_focused(self: &Rc<Self>, direction: Direction) {
|
||||
let kb_node = self.keyboard_node.get();
|
||||
let Some(tl) = kb_node.node_toplevel() else {
|
||||
if let Some(ws) = self.keyboard_node.get().node_into_workspace()
|
||||
&& let Some(target) = self
|
||||
.state
|
||||
.find_output_in_direction(&ws.output.get(), direction)
|
||||
{
|
||||
self.state.move_ws_to_output(&ws, &target);
|
||||
}
|
||||
return;
|
||||
};
|
||||
let data = tl.tl_data();
|
||||
|
|
@ -981,7 +1011,15 @@ impl WlSeatGlobal {
|
|||
NodeLayer::Layer0 => handle_layer_shell(&output.layers[0]),
|
||||
NodeLayer::Layer1 => handle_layer_shell(&output.layers[1]),
|
||||
NodeLayer::Output => None,
|
||||
NodeLayer::Workspace => None,
|
||||
NodeLayer::Workspace => {
|
||||
if let Some(ws) = &ws
|
||||
&& ws.container_visible()
|
||||
{
|
||||
self.focus_node(ws.clone());
|
||||
return;
|
||||
}
|
||||
None
|
||||
}
|
||||
NodeLayer::Tiled => ws
|
||||
.as_ref()
|
||||
.and_then(|w| w.container.get())
|
||||
|
|
@ -1393,6 +1431,10 @@ impl WlSeatGlobal {
|
|||
self.focus_follows_mouse.set(focus_follows_mouse);
|
||||
}
|
||||
|
||||
pub fn set_fallback_output_mode(&self, fallback_output_mode: FallbackOutputMode) {
|
||||
self.fallback_output_mode.set(fallback_output_mode);
|
||||
}
|
||||
|
||||
pub fn set_window_management_enabled(self: &Rc<Self>, enabled: bool) {
|
||||
self.pointer_owner
|
||||
.set_window_management_enabled(self, enabled);
|
||||
|
|
|
|||
|
|
@ -213,12 +213,12 @@ impl NodeSeatState {
|
|||
fn release_kb_focus2(&self, focus_last: bool) {
|
||||
self.release_kb_grab();
|
||||
while let Some((_, seat)) = self.kb_foci.pop() {
|
||||
let output = seat.get_fallback_output();
|
||||
seat.kb_owner
|
||||
.set_kb_node(&seat, seat.state.root.clone(), seat.state.next_serial(None));
|
||||
// log::info!("keyboard_node = root");
|
||||
if focus_last {
|
||||
seat.get_output()
|
||||
.node_do_focus(&seat, Direction::Unspecified);
|
||||
output.node_do_focus(&seat, Direction::Unspecified);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -486,7 +486,7 @@ impl XdgToplevel {
|
|||
if should_be_mapped {
|
||||
if !self.is_mapped.replace(true) {
|
||||
if let Some(seat) = drag.source.data.seat.get() {
|
||||
self.xdg.set_output(&seat.get_output());
|
||||
self.xdg.set_output(&seat.get_cursor_output());
|
||||
}
|
||||
self.toplevel_data.broadcast(self.clone());
|
||||
self.tl_set_visible(self.state.root_visible());
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ impl XdgToplevelDragV1 {
|
|||
if self.source.data.was_used()
|
||||
&& let Some(tl) = self.toplevel.get()
|
||||
{
|
||||
let output = seat.get_output();
|
||||
let output = seat.get_cursor_output();
|
||||
let (x, y) = seat.pointer_cursor().position();
|
||||
tl.drag.take();
|
||||
tl.after_toplevel_drag(
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ impl ZwlrLayerShellV1RequestHandler for ZwlrLayerShellV1 {
|
|||
self.client.lookup(req.output)?.global.clone()
|
||||
} else {
|
||||
for seat in self.client.state.seat_queue.rev_iter() {
|
||||
let output = seat.get_output();
|
||||
let output = seat.get_fallback_output();
|
||||
if !output.is_dummy {
|
||||
break 'get_output output.global.opt.clone();
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -18,6 +18,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
win1.set_color(255, 0, 0, 255);
|
||||
win1.map2().await?;
|
||||
run.cfg.set_floating(ds.seat.id(), true)?;
|
||||
client.sync().await;
|
||||
|
||||
for i in ["1", "2"] {
|
||||
let (x, y) = win1.tl.server.node_absolute_position().position();
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -85,6 +85,7 @@ impl Renderer<'_> {
|
|||
} else {
|
||||
render_layer!(output.layers[0]);
|
||||
render_layer!(output.layers[1]);
|
||||
let ws = output.workspace.get();
|
||||
if self.state.show_bar.get() {
|
||||
let non_exclusive_rect_rel = output.non_exclusive_rect_rel.get();
|
||||
let (mut x, mut y) = non_exclusive_rect_rel.translate_inv(x, y);
|
||||
|
|
@ -109,7 +110,12 @@ impl Renderer<'_> {
|
|||
self.base
|
||||
.fill_boxes2(slice::from_ref(&aw.rect), &c, srgb, x, y);
|
||||
}
|
||||
let c = theme.colors.separator.get();
|
||||
let mut c = theme.colors.separator.get();
|
||||
if let Some(ws) = &ws
|
||||
&& ws.seat_state.is_active()
|
||||
{
|
||||
c = theme.colors.focused_title_background.get();
|
||||
}
|
||||
self.base
|
||||
.fill_boxes2(slice::from_ref(&rd.bar_separator), &c, srgb, x, y);
|
||||
let c = theme.colors.unfocused_title_background.get();
|
||||
|
|
@ -172,7 +178,7 @@ impl Renderer<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if let Some(ws) = output.workspace.get() {
|
||||
if let Some(ws) = &ws {
|
||||
let ws_rect = output.workspace_rect_rel.get();
|
||||
let (x, y) = ws_rect.translate_inv(x, y);
|
||||
self.render_workspace(&ws, x, y);
|
||||
|
|
|
|||
|
|
@ -780,7 +780,7 @@ impl State {
|
|||
pub fn ensure_map_workspace(&self, seat: Option<&Rc<WlSeatGlobal>>) -> Rc<WorkspaceNode> {
|
||||
seat.cloned()
|
||||
.or_else(|| self.seat_queue.last().map(|s| s.deref().clone()))
|
||||
.map(|s| s.get_output())
|
||||
.map(|s| s.get_fallback_output())
|
||||
.or_else(|| self.root.outputs.lock().values().next().cloned())
|
||||
.or_else(|| self.dummy_output.get())
|
||||
.unwrap()
|
||||
|
|
@ -916,7 +916,7 @@ impl State {
|
|||
let ws = match self.workspaces.get(name) {
|
||||
Some(ws) => ws,
|
||||
_ => {
|
||||
let output = output.unwrap_or_else(|| seat.get_output());
|
||||
let output = output.unwrap_or_else(|| seat.get_fallback_output());
|
||||
if output.is_dummy {
|
||||
log::warn!("Not showing workspace because seat is on dummy output");
|
||||
return;
|
||||
|
|
@ -929,7 +929,7 @@ impl State {
|
|||
|
||||
pub fn float_map_ws(&self) -> Rc<WorkspaceNode> {
|
||||
if let Some(seat) = self.seat_queue.last() {
|
||||
let output = seat.get_output();
|
||||
let output = seat.get_fallback_output();
|
||||
if !output.is_dummy {
|
||||
return output.ensure_workspace();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@ impl ConnectorHandler {
|
|||
bar_rect: Default::default(),
|
||||
bar_rect_rel: Default::default(),
|
||||
bar_rect_with_separator: Default::default(),
|
||||
bar_separator_rect: Default::default(),
|
||||
bar_separator_rect_rel: Default::default(),
|
||||
render_data: Default::default(),
|
||||
state: self.state.clone(),
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ pub struct OutputNode {
|
|||
pub bar_rect: Cell<Rect>,
|
||||
pub bar_rect_rel: Cell<Rect>,
|
||||
pub bar_rect_with_separator: Cell<Rect>,
|
||||
pub bar_separator_rect: Cell<Rect>,
|
||||
pub bar_separator_rect_rel: Cell<Rect>,
|
||||
pub render_data: RefCell<OutputRenderData>,
|
||||
pub state: Rc<State>,
|
||||
|
|
@ -775,11 +776,11 @@ impl OutputNode {
|
|||
let mut bar_rect = Rect::default();
|
||||
let mut bar_rect_rel = Rect::default();
|
||||
let mut bar_rect_with_separator = Rect::default();
|
||||
let mut bar_separator_rect = Rect::default();
|
||||
let mut bar_separator_rect_rel = Rect::default();
|
||||
let mut workspace_rect = non_exclusive_rect;
|
||||
let mut workspace_rect_rel = non_exclusive_rect_rel;
|
||||
if self.state.show_bar.get() {
|
||||
let bar_separator_rect;
|
||||
match self.state.theme.bar_position.get() {
|
||||
BarPosition::Bottom => {
|
||||
workspace_rect = Rect::new_sized_saturating(x1, y1, width, height - bh - bsw);
|
||||
|
|
@ -806,6 +807,7 @@ impl OutputNode {
|
|||
self.bar_rect.set(bar_rect);
|
||||
self.bar_rect_rel.set(bar_rect_rel);
|
||||
self.bar_rect_with_separator.set(bar_rect_with_separator);
|
||||
self.bar_separator_rect.set(bar_separator_rect);
|
||||
self.bar_separator_rect_rel.set(bar_separator_rect_rel);
|
||||
self.workspace_rect.set(workspace_rect);
|
||||
self.workspace_rect_rel.set(workspace_rect_rel);
|
||||
|
|
@ -1148,20 +1150,13 @@ impl OutputNode {
|
|||
set_layer_visible!(self.layers[3], visible);
|
||||
}
|
||||
|
||||
fn button(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, id: PointerType) {
|
||||
fn bar_button(self: &Rc<Self>, seat: &Rc<WlSeatGlobal>, x: i32, y: i32) -> bool {
|
||||
if !self.state.show_bar.get() {
|
||||
return;
|
||||
}
|
||||
let (x, y) = match self.pointer_positions.get(&id) {
|
||||
Some(p) => p,
|
||||
_ => return,
|
||||
};
|
||||
if let PointerType::Seat(s) = id {
|
||||
self.pointer_down.set(s, (x, y));
|
||||
return false;
|
||||
}
|
||||
let bar_rect_rel = self.bar_rect_rel.get();
|
||||
if bar_rect_rel.not_contains(x, y) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
let (x, _) = bar_rect_rel.translate(x, y);
|
||||
let ws = 'ws: {
|
||||
|
|
@ -1171,9 +1166,25 @@ impl OutputNode {
|
|||
break 'ws title.ws.clone();
|
||||
}
|
||||
}
|
||||
return;
|
||||
return true;
|
||||
};
|
||||
self.state.show_workspace2(Some(seat), &self, &ws);
|
||||
self.state.show_workspace2(Some(seat), self, &ws);
|
||||
true
|
||||
}
|
||||
|
||||
fn button(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, id: PointerType) {
|
||||
let (x, y) = match self.pointer_positions.get(&id) {
|
||||
Some(p) => p,
|
||||
_ => return,
|
||||
};
|
||||
if let PointerType::Seat(s) = id {
|
||||
self.pointer_down.set(s, (x, y));
|
||||
}
|
||||
if self.bar_button(seat, x, y) {
|
||||
return;
|
||||
}
|
||||
let ws = self.ensure_workspace();
|
||||
seat.focus_node(ws);
|
||||
}
|
||||
|
||||
pub fn update_presentation_type(&self) {
|
||||
|
|
@ -1490,6 +1501,10 @@ impl OutputNode {
|
|||
if c.node_visible() {
|
||||
c.node_do_focus(seat, direction);
|
||||
}
|
||||
} else {
|
||||
if ws.node_visible() {
|
||||
seat.focus_node(ws);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -366,17 +366,23 @@ impl Node for WorkspaceNode {
|
|||
seat.focus_node(last);
|
||||
} else if let Some(container) = self.container.get() {
|
||||
container.node_do_focus(seat, direction);
|
||||
} else if let Some(float) = self
|
||||
} else if let Some(child) = self
|
||||
.stacked
|
||||
.rev_iter()
|
||||
.find_map(|node| (*node).clone().node_into_float())
|
||||
.filter_map(|node| (*node).clone().node_into_float())
|
||||
.find_map(|float| float.child.get())
|
||||
{
|
||||
if let Some(child) = float.child.get() {
|
||||
child.node_do_focus(seat, direction);
|
||||
}
|
||||
child.node_do_focus(seat, direction);
|
||||
} else {
|
||||
seat.focus_node(self);
|
||||
}
|
||||
}
|
||||
|
||||
fn node_active_changed(&self, _active: bool) {
|
||||
let output = self.output.get();
|
||||
self.state.damage(output.bar_separator_rect.get());
|
||||
}
|
||||
|
||||
fn node_find_tree_at(
|
||||
&self,
|
||||
x: i32,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue