control-center: add input pane
This commit is contained in:
parent
db06d719dd
commit
edbdcdca32
11 changed files with 783 additions and 63 deletions
|
|
@ -478,7 +478,7 @@ impl ConfigProxyHandler {
|
|||
} else {
|
||||
Some(self.get_keymap(keymap)?)
|
||||
};
|
||||
dev.set_keymap(map);
|
||||
dev.set_keymap(&self.state, map);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -532,13 +532,13 @@ impl ConfigProxyHandler {
|
|||
) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(input_device)?;
|
||||
let output = self.get_output_node(connector)?;
|
||||
dev.set_output(Some(&output.global));
|
||||
dev.set_output(&self.state, Some(&output.global));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_remove_input_mapping(&self, input_device: InputDevice) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(input_device)?;
|
||||
dev.set_output(None);
|
||||
dev.set_output(&self.state, None);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -788,7 +788,7 @@ impl ConfigProxyHandler {
|
|||
Some(self.get_seat(seat)?)
|
||||
};
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_seat(seat);
|
||||
dev.set_seat(&self.state, seat);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -798,7 +798,7 @@ impl ConfigProxyHandler {
|
|||
left_handed: bool,
|
||||
) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_left_handed(left_handed);
|
||||
dev.set_left_handed(&self.state, left_handed);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -813,31 +813,31 @@ impl ConfigProxyHandler {
|
|||
ACCEL_PROFILE_ADAPTIVE => InputDeviceAccelProfile::Adaptive,
|
||||
_ => return Err(CphError::UnknownAccelProfile(accel_profile)),
|
||||
};
|
||||
dev.set_accel_profile(profile);
|
||||
dev.set_accel_profile(&self.state, profile);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_accel_speed(&self, device: InputDevice, speed: f64) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_accel_speed(speed);
|
||||
dev.set_accel_speed(&self.state, speed);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_px_per_wheel_scroll(&self, device: InputDevice, px: f64) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_px_per_scroll_wheel(px);
|
||||
dev.set_px_per_scroll_wheel(&self.state, px);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_tap_enabled(&self, device: InputDevice, enabled: bool) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_tap_enabled(enabled);
|
||||
dev.set_tap_enabled(&self.state, enabled);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_drag_enabled(&self, device: InputDevice, enabled: bool) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_drag_enabled(enabled);
|
||||
dev.set_drag_enabled(&self.state, enabled);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -847,7 +847,7 @@ impl ConfigProxyHandler {
|
|||
enabled: bool,
|
||||
) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_natural_scrolling_enabled(enabled);
|
||||
dev.set_natural_scrolling_enabled(&self.state, enabled);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -857,7 +857,7 @@ impl ConfigProxyHandler {
|
|||
enabled: bool,
|
||||
) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_drag_lock_enabled(enabled);
|
||||
dev.set_drag_lock_enabled(&self.state, enabled);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -867,7 +867,7 @@ impl ConfigProxyHandler {
|
|||
matrix: [[f64; 2]; 2],
|
||||
) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_transform_matrix(matrix);
|
||||
dev.set_transform_matrix(&self.state, matrix);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -877,7 +877,7 @@ impl ConfigProxyHandler {
|
|||
matrix: [[f32; 3]; 2],
|
||||
) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_calibration_matrix(matrix);
|
||||
dev.set_calibration_matrix(&self.state, matrix);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -893,7 +893,7 @@ impl ConfigProxyHandler {
|
|||
CLICK_METHOD_CLICKFINGER => InputDeviceClickMethod::Clickfinger,
|
||||
_ => return Err(CphError::UnknownClickMethod(click_method)),
|
||||
};
|
||||
dev.set_click_method(method);
|
||||
dev.set_click_method(&self.state, method);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -903,7 +903,7 @@ impl ConfigProxyHandler {
|
|||
enabled: bool,
|
||||
) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.set_middle_button_emulation_enabled(enabled);
|
||||
dev.set_middle_button_emulation_enabled(&self.state, enabled);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use {
|
|||
crate::{
|
||||
control_center::{
|
||||
cc_color_management::ColorManagementPane, cc_compositor::CompositorPane,
|
||||
cc_gpus::GpusPane, cc_idle::IdlePane, cc_outputs::OutputsPane,
|
||||
cc_gpus::GpusPane, cc_idle::IdlePane, cc_input::InputPane, cc_outputs::OutputsPane,
|
||||
cc_xwayland::XwaylandPane,
|
||||
},
|
||||
egui_adapter::egui_platform::{
|
||||
|
|
@ -38,6 +38,7 @@ mod cc_color_management;
|
|||
mod cc_compositor;
|
||||
mod cc_gpus;
|
||||
mod cc_idle;
|
||||
mod cc_input;
|
||||
mod cc_outputs;
|
||||
mod cc_sidebar;
|
||||
mod cc_xwayland;
|
||||
|
|
@ -79,6 +80,7 @@ bitflags! {
|
|||
CCI_XWAYLAND,
|
||||
CCI_OUTPUTS,
|
||||
CCI_GPUS,
|
||||
CCI_INPUT,
|
||||
}
|
||||
|
||||
pub struct ControlCenter {
|
||||
|
|
@ -125,6 +127,7 @@ enum PaneType {
|
|||
Xwayland(XwaylandPane),
|
||||
Outputs(Box<OutputsPane>),
|
||||
GPUs(GpusPane),
|
||||
Input(InputPane),
|
||||
}
|
||||
|
||||
struct CcBehavior<'a> {
|
||||
|
|
@ -149,6 +152,7 @@ impl Pane {
|
|||
PaneType::Xwayland(v) => v.title(res),
|
||||
PaneType::Outputs(v) => v.title(res),
|
||||
PaneType::GPUs(v) => v.title(res),
|
||||
PaneType::Input(v) => v.title(res),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,6 +164,7 @@ impl Pane {
|
|||
PaneType::Xwayland(p) => p.show(behavior, ui),
|
||||
PaneType::Outputs(p) => p.show(&mut self.ps, ui),
|
||||
PaneType::GPUs(p) => p.show(ui),
|
||||
PaneType::Input(p) => p.show(&mut self.ps, ui),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -173,6 +178,7 @@ impl PaneType {
|
|||
PaneType::Xwayland(_) => CCI_XWAYLAND,
|
||||
PaneType::Outputs(_) => CCI_OUTPUTS,
|
||||
PaneType::GPUs(_) => CCI_GPUS,
|
||||
PaneType::Input(_) => CCI_INPUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -442,7 +448,6 @@ fn tip(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui)) {
|
|||
icon_label(ICON_INFO).ui(ui).on_hover_ui(add_contents);
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
fn text_edit(ui: &mut Ui, v: &mut dyn TextBuffer) -> Response {
|
||||
TextEdit::singleline(v)
|
||||
.clip_text(false)
|
||||
|
|
@ -564,7 +569,6 @@ fn combo_box_ui<R, T>(
|
|||
});
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
fn drag_value<N>(
|
||||
ui: &mut Ui,
|
||||
name: &str,
|
||||
|
|
|
|||
679
src/control_center/cc_input.rs
Normal file
679
src/control_center/cc_input.rs
Normal file
|
|
@ -0,0 +1,679 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::{InputDeviceCapability, InputDeviceId},
|
||||
control_center::{
|
||||
ControlCenterInner, GridExt, PaneState, bool, bool_ui, combo_box, combo_box_ui,
|
||||
drag_value, drag_value_ui, grid, grid_label, grid_label_ui, label, text_edit, tip,
|
||||
},
|
||||
egui_adapter::egui_platform::icons::ICON_PENDING,
|
||||
ifs::{
|
||||
wl_output::WlOutputGlobal,
|
||||
wl_seat::{SeatId, WlSeatGlobal},
|
||||
},
|
||||
kbvm::KbvmMap,
|
||||
state::{DeviceHandlerData, State},
|
||||
utils::{errorfmt::ErrorFmt, static_text::StaticText},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
egui::{
|
||||
CollapsingHeader, ComboBox, DragValue, Event, Grid, Id, TextBuffer, TextFormat, Ui,
|
||||
UiBuilder, ViewportCommand, Widget, emath::Numeric, text::LayoutJob,
|
||||
},
|
||||
isnt::std_1::string::IsntStringExt,
|
||||
jay_config::keyboard::syms::KeySym,
|
||||
kbvm::Keysym,
|
||||
linearize::LinearizeExt,
|
||||
rand::random,
|
||||
std::{mem, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct InputPane {
|
||||
state: Rc<State>,
|
||||
paste_requested: Option<Id>,
|
||||
keymaps: AHashMap<Key, KeymapState>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
enum Key {
|
||||
Seat(SeatId),
|
||||
Dev(InputDeviceId),
|
||||
}
|
||||
|
||||
struct KeymapState {
|
||||
seed: u64,
|
||||
rules_default: bool,
|
||||
rules: String,
|
||||
model_default: bool,
|
||||
model: String,
|
||||
layouts: String,
|
||||
variants: String,
|
||||
options: String,
|
||||
backup: Option<Rc<KbvmMap>>,
|
||||
pointer_revert_key: Keysym,
|
||||
pointer_revert_key_str: Option<String>,
|
||||
unknown_pointer_revert_key: bool,
|
||||
}
|
||||
|
||||
impl Default for KeymapState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
seed: random(),
|
||||
rules_default: true,
|
||||
rules: Default::default(),
|
||||
model_default: true,
|
||||
model: Default::default(),
|
||||
layouts: Default::default(),
|
||||
variants: Default::default(),
|
||||
options: Default::default(),
|
||||
backup: Default::default(),
|
||||
pointer_revert_key: Default::default(),
|
||||
pointer_revert_key_str: None,
|
||||
unknown_pointer_revert_key: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControlCenterInner {
|
||||
pub fn create_input_pane(self: &Rc<Self>) -> InputPane {
|
||||
InputPane {
|
||||
state: self.state.clone(),
|
||||
paste_requested: Default::default(),
|
||||
keymaps: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputPane {
|
||||
pub fn title(&self, res: &mut String) {
|
||||
res.push_str("Input");
|
||||
}
|
||||
|
||||
pub fn show(&mut self, ps: &mut PaneState, ui: &mut Ui) {
|
||||
let state = self.state.clone();
|
||||
let seats = state.globals.seats.lock();
|
||||
let mut seats: Vec<_> = seats.values().collect();
|
||||
seats.sort_by_key(|d| d.seat_name());
|
||||
for seat in &seats {
|
||||
self.show_seat(ps, ui, seat);
|
||||
}
|
||||
let outputs = state.globals.outputs.lock();
|
||||
let mut outputs: Vec<_> = outputs.values().collect();
|
||||
outputs.sort_by_key(|o| &o.connector.name);
|
||||
let dev = &*state.input_device_handlers.borrow();
|
||||
let mut dev: Vec<_> = dev.values().collect();
|
||||
dev.sort_by_key(|d| d.data.device.name());
|
||||
for dev in dev {
|
||||
self.show_device(ps, ui, &dev.data, &seats, &outputs);
|
||||
}
|
||||
}
|
||||
|
||||
fn show_seat(&mut self, ps: &mut PaneState, ui: &mut Ui, seat: &Rc<WlSeatGlobal>) {
|
||||
let mut layout_job = LayoutJob::default();
|
||||
layout_job.append(
|
||||
"Seat",
|
||||
0.0,
|
||||
TextFormat {
|
||||
color: ui.style().visuals.widgets.inactive.text_color(),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
layout_job.append(
|
||||
seat.seat_name(),
|
||||
10.0,
|
||||
TextFormat {
|
||||
color: ui.style().visuals.widgets.active.text_color(),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
let ks = self.keymaps.entry(Key::Seat(seat.id())).or_default();
|
||||
CollapsingHeader::new(layout_job)
|
||||
.id_salt(("seat", seat.id()))
|
||||
.show(ui, |ui| {
|
||||
grid(ui, ("seat", seat.id()), |ui| {
|
||||
let mut dv = |name: &str, get: &dyn Fn(&mut (i32, i32)) -> &mut i32| {
|
||||
let ui = &mut *ui.row();
|
||||
grid_label(ui, name);
|
||||
let mut v = seat.get_rate();
|
||||
let old = v;
|
||||
ui.horizontal(|ui| {
|
||||
let v = get(&mut v);
|
||||
DragValue::new(v).range(0..=i32::MAX).ui(ui);
|
||||
if ui.button("-20").clicked() {
|
||||
*v = v.saturating_sub(20).max(0)
|
||||
}
|
||||
if ui.button("+20").clicked() {
|
||||
*v = v.saturating_add(20);
|
||||
}
|
||||
});
|
||||
if v != old {
|
||||
seat.set_rate(v.0, v.1);
|
||||
}
|
||||
};
|
||||
dv("Repeat Rate", &|v| &mut v.0);
|
||||
dv("Repeat Delay", &|v| &mut v.1);
|
||||
drag_value(
|
||||
ui,
|
||||
"Cursor Size",
|
||||
seat.cursor_group().cursor_size(),
|
||||
0..=u32::MAX,
|
||||
1.0,
|
||||
|v| seat.cursor_group().set_cursor_size(v),
|
||||
);
|
||||
bool_ui(
|
||||
ui,
|
||||
"Simple IM",
|
||||
|ui| {
|
||||
tip(ui, |ui| {
|
||||
ui.label("A simple input method based on Xcompose files.");
|
||||
ui.label(concat!(
|
||||
"If you're not using another input method, you should ",
|
||||
"leave this enabled as it will work for sandboxed ",
|
||||
"applications, which regular Xcompose will not.",
|
||||
));
|
||||
ui.label(concat!(
|
||||
"The `enable-unicode-input` action can be used to input ",
|
||||
"characters by their unicode value.",
|
||||
));
|
||||
});
|
||||
},
|
||||
seat.simple_im_enabled(),
|
||||
|b| seat.set_simple_im_enabled(b),
|
||||
);
|
||||
bool_ui(
|
||||
ui,
|
||||
"Hardware Cursor",
|
||||
|ui| {
|
||||
tip(ui, |ui| {
|
||||
ui.label(
|
||||
"Allow this seat to use the hardware cursor, if available.",
|
||||
);
|
||||
ui.label("Only one seat can use the hardware cursor at a time.");
|
||||
});
|
||||
},
|
||||
seat.cursor_group().hardware_cursor(),
|
||||
|b| seat.cursor_group().set_hardware_cursor(b),
|
||||
);
|
||||
{
|
||||
let ui = &mut *ui.row();
|
||||
let v = seat.pointer_revert_key();
|
||||
let v = Keysym(v.0);
|
||||
if mem::replace(&mut ks.pointer_revert_key, v) != v {
|
||||
ks.pointer_revert_key_str = None;
|
||||
}
|
||||
let name = ks
|
||||
.pointer_revert_key_str
|
||||
.get_or_insert_with(|| v.name().unwrap_or_default().to_string());
|
||||
grid_label_ui(ui, |ui| {
|
||||
ui.label("Pointer Revert Key");
|
||||
tip(ui, |ui| {
|
||||
ui.label(concat!(
|
||||
"Pressing this key reverts the pointer to the default state, ",
|
||||
"breaking grabs, drags, etc.",
|
||||
));
|
||||
ui.label(
|
||||
"Setting this to `NoSymbol` effectively disables this feature.",
|
||||
);
|
||||
});
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
if ui.text_edit_singleline(name).changed() {
|
||||
let v = Keysym::from_str(name);
|
||||
ks.unknown_pointer_revert_key = v.is_none();
|
||||
if let Some(v) = v {
|
||||
ks.pointer_revert_key = v;
|
||||
seat.set_pointer_revert_key(KeySym(v.0));
|
||||
}
|
||||
}
|
||||
if ks.unknown_pointer_revert_key {
|
||||
ui.label("Error: Unknown key");
|
||||
}
|
||||
});
|
||||
}
|
||||
bool(ui, "Focus Follows Mouse", seat.focus_follows_mouse(), |v| {
|
||||
seat.set_focus_follows_mouse(v);
|
||||
});
|
||||
combo_box_ui(
|
||||
ui,
|
||||
"Fallback Output Mode",
|
||||
|ui| {
|
||||
tip(ui, |ui| {
|
||||
ui.label(concat!(
|
||||
"This determines the output to use in operations where no ",
|
||||
"output is explicitly specified.",
|
||||
));
|
||||
ui.label(concat!(
|
||||
"For example, when a new window is opened, this determines ",
|
||||
"where the window will be opened.",
|
||||
));
|
||||
ui.label("`Cursor` refers to the output that contains the cursor.");
|
||||
ui.label(
|
||||
"`Focus` refers to the output that has the keyboard focus.",
|
||||
);
|
||||
});
|
||||
},
|
||||
seat.fallback_output_mode(),
|
||||
|v| seat.set_fallback_output_mode(v),
|
||||
);
|
||||
});
|
||||
ui.label("Focus History");
|
||||
ui.indent("focus-history", |ui| {
|
||||
let mut v = seat.focus_history_visible();
|
||||
if ui.checkbox(&mut v, "Only Visible").changed() {
|
||||
seat.focus_history_set_visible(v);
|
||||
}
|
||||
let mut v = seat.focus_history_same_workspace();
|
||||
if ui.checkbox(&mut v, "Same Workspace").changed() {
|
||||
seat.focus_history_set_same_workspace(v);
|
||||
}
|
||||
});
|
||||
if ui.button("Reload Simple IM").clicked() {
|
||||
seat.reload_simple_im();
|
||||
}
|
||||
show_keymap(
|
||||
&self.state,
|
||||
ps,
|
||||
&mut self.paste_requested,
|
||||
ks,
|
||||
ui,
|
||||
Some(&seat.keymap()),
|
||||
|m| seat.set_seat_keymap(m),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn show_device(
|
||||
&mut self,
|
||||
ps: &mut PaneState,
|
||||
ui: &mut Ui,
|
||||
dev: &Rc<DeviceHandlerData>,
|
||||
seats: &[&Rc<WlSeatGlobal>],
|
||||
outputs: &[&Rc<WlOutputGlobal>],
|
||||
) {
|
||||
let mut layout_job = LayoutJob::default();
|
||||
layout_job.append(
|
||||
"Device",
|
||||
0.0,
|
||||
TextFormat {
|
||||
color: ui.style().visuals.widgets.inactive.text_color(),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
layout_job.append(
|
||||
&dev.device.name(),
|
||||
10.0,
|
||||
TextFormat {
|
||||
color: ui.style().visuals.widgets.active.text_color(),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
let dev_id = dev.device.id();
|
||||
CollapsingHeader::new(layout_job)
|
||||
.id_salt(("device", dev_id))
|
||||
.show(ui, |ui| {
|
||||
grid(ui, ("device", dev_id), |ui| {
|
||||
{
|
||||
let old = dev.seat.get();
|
||||
let ui = &mut *ui.row();
|
||||
grid_label(ui, "Seat");
|
||||
let mut seat = old.as_ref();
|
||||
ui.horizontal(|ui| {
|
||||
let mut cb = ComboBox::from_id_salt("seat");
|
||||
if let Some(seat) = seat {
|
||||
cb = cb.selected_text(seat.seat_name());
|
||||
}
|
||||
cb.show_ui(ui, |ui| {
|
||||
for s in seats {
|
||||
ui.selectable_value(&mut seat, Some(s), s.seat_name());
|
||||
}
|
||||
});
|
||||
if ui.button("Detach").clicked() {
|
||||
seat = None;
|
||||
}
|
||||
});
|
||||
if seat != old.as_ref() {
|
||||
dev.set_seat(&self.state, seat.cloned());
|
||||
}
|
||||
}
|
||||
macro_rules! string {
|
||||
($field:ident, $name:expr) => {
|
||||
if let Some(v) = &dev.$field {
|
||||
label(ui, $name, v);
|
||||
}
|
||||
};
|
||||
}
|
||||
string!(syspath, "Syspath");
|
||||
string!(devnode, "Devnode");
|
||||
{
|
||||
let ui = &mut *ui.row();
|
||||
grid_label(ui, "Capabilities");
|
||||
let mut s = String::new();
|
||||
for cap in InputDeviceCapability::variants() {
|
||||
if dev.device.has_capability(cap) {
|
||||
if s.is_not_empty() {
|
||||
s.push_str(" | ");
|
||||
}
|
||||
s.push_str(cap.text());
|
||||
}
|
||||
}
|
||||
ui.label(s);
|
||||
}
|
||||
if let Some(old) = dev.device.natural_scrolling_enabled() {
|
||||
bool(ui, "Natural Scrolling", old, |v| {
|
||||
dev.set_natural_scrolling_enabled(&self.state, v)
|
||||
});
|
||||
}
|
||||
if dev.device.has_capability(InputDeviceCapability::Pointer) {
|
||||
drag_value_ui(
|
||||
ui,
|
||||
"Scroll Distance (px)",
|
||||
|ui| {
|
||||
tip(ui, |ui| {
|
||||
ui.label(concat!(
|
||||
"This only applies to applications that use the ",
|
||||
"legacy px scrolling events.",
|
||||
));
|
||||
});
|
||||
},
|
||||
dev.px_per_scroll_wheel.get(),
|
||||
-f64::INFINITY..=f64::INFINITY,
|
||||
0.1,
|
||||
|v| dev.set_px_per_scroll_wheel(&self.state, v),
|
||||
);
|
||||
}
|
||||
if let Some(old) = dev.device.accel_profile() {
|
||||
combo_box(ui, "Accel Profile", old, |v| {
|
||||
dev.set_accel_profile(&self.state, v)
|
||||
});
|
||||
}
|
||||
if let Some(old) = dev.device.accel_speed() {
|
||||
drag_value(ui, "Accel Speed", old, 0.0..=1.0, 0.01, |v| {
|
||||
dev.set_accel_speed(&self.state, v)
|
||||
});
|
||||
}
|
||||
if let Some(old) = dev.device.click_method() {
|
||||
combo_box(ui, "Click Method", old, |v| {
|
||||
dev.set_click_method(&self.state, v)
|
||||
});
|
||||
}
|
||||
if let Some(old) = dev.device.tap_enabled() {
|
||||
bool(ui, "Tap Enabled", old, |v| {
|
||||
dev.set_tap_enabled(&self.state, v)
|
||||
});
|
||||
}
|
||||
if let Some(old) = dev.device.drag_enabled() {
|
||||
bool(ui, "Tap Drag Enabled", old, |v| {
|
||||
dev.set_drag_enabled(&self.state, v)
|
||||
});
|
||||
}
|
||||
if let Some(old) = dev.device.drag_lock_enabled() {
|
||||
bool(ui, "Tap Drag Lock Enabled", old, |v| {
|
||||
dev.set_drag_lock_enabled(&self.state, v)
|
||||
});
|
||||
}
|
||||
if let Some(old) = dev.device.left_handed() {
|
||||
bool(ui, "Left Handed", old, |v| {
|
||||
dev.set_left_handed(&self.state, v)
|
||||
});
|
||||
}
|
||||
if let Some(old) = dev.device.middle_button_emulation_enabled() {
|
||||
bool(ui, "Middle Button Emulation", old, |v| {
|
||||
dev.set_middle_button_emulation_enabled(&self.state, v)
|
||||
});
|
||||
}
|
||||
{
|
||||
let ui = &mut *ui.row();
|
||||
grid_label_ui(ui, |ui| {
|
||||
ui.label("Output");
|
||||
tip(ui, |ui| {
|
||||
ui.label("This applies to touch and tablet input.");
|
||||
});
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
let old = dev.output.get().and_then(|v| v.global.get());
|
||||
let old = old.as_ref();
|
||||
let mut v = old;
|
||||
let mut cb = ComboBox::from_id_salt("output");
|
||||
if let Some(v) = v {
|
||||
cb = cb.selected_text(&*v.connector.name);
|
||||
}
|
||||
cb.show_ui(ui, |ui| {
|
||||
for &output in outputs {
|
||||
ui.selectable_value(
|
||||
&mut v,
|
||||
Some(output),
|
||||
&*output.connector.name,
|
||||
);
|
||||
}
|
||||
});
|
||||
if v != old {
|
||||
dev.set_output(&self.state, v.map(|v| &**v));
|
||||
}
|
||||
if ui.button("Detach").clicked() {
|
||||
dev.set_output(&self.state, None);
|
||||
}
|
||||
});
|
||||
}
|
||||
matrix_ui(
|
||||
ui,
|
||||
"Transform Matrix",
|
||||
|ui| {
|
||||
tip(ui, |ui| {
|
||||
ui.label("This matrix is applied to relative pointer movements.");
|
||||
});
|
||||
},
|
||||
dev.device
|
||||
.has_capability(InputDeviceCapability::Pointer)
|
||||
.then(|| {
|
||||
dev.device
|
||||
.transform_matrix()
|
||||
.unwrap_or([[1.0, 0.0], [0.0, 1.0]])
|
||||
}),
|
||||
|v| dev.set_transform_matrix(&self.state, v),
|
||||
);
|
||||
matrix(
|
||||
ui,
|
||||
"Calibration Matrix",
|
||||
dev.device.calibration_matrix(),
|
||||
|v| dev.set_calibration_matrix(&self.state, v),
|
||||
);
|
||||
});
|
||||
if dev.device.has_capability(InputDeviceCapability::Keyboard) {
|
||||
ui.collapsing("Device Keymap", |ui| {
|
||||
let ks = self.keymaps.entry(Key::Dev(dev_id)).or_default();
|
||||
let map = dev.keymap.get();
|
||||
ui.add_enabled_ui(map.is_some(), |ui| {
|
||||
if ui.button("Use Seat Keymap").clicked() {
|
||||
ks.backup(map.as_ref());
|
||||
dev.set_keymap(&self.state, None);
|
||||
}
|
||||
});
|
||||
show_keymap(
|
||||
&self.state,
|
||||
ps,
|
||||
&mut self.paste_requested,
|
||||
ks,
|
||||
ui,
|
||||
map.as_ref(),
|
||||
|m| {
|
||||
dev.set_keymap(&self.state, Some(m.clone()));
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl KeymapState {
|
||||
fn backup(&mut self, map: Option<&Rc<KbvmMap>>) {
|
||||
if self.backup.is_none()
|
||||
&& let Some(map) = map
|
||||
{
|
||||
self.backup = Some(map.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show_keymap(
|
||||
state: &State,
|
||||
ps: &mut PaneState,
|
||||
paste_requested: &mut Option<Id>,
|
||||
ks: &mut KeymapState,
|
||||
ui: &mut Ui,
|
||||
map: Option<&Rc<KbvmMap>>,
|
||||
set_map: impl Fn(&Rc<KbvmMap>),
|
||||
) {
|
||||
ui.scope_builder(UiBuilder::new().id(("keymap-settings", ks.seed)), |ui| {
|
||||
ui.add_enabled_ui(map.is_some(), |ui| {
|
||||
if ui.button("Copy Keymap").clicked()
|
||||
&& let Some(map) = map
|
||||
{
|
||||
ui.ctx().copy_text(map.map_text.clone());
|
||||
}
|
||||
});
|
||||
let backup = |ks: &mut KeymapState| {
|
||||
ks.backup(map);
|
||||
};
|
||||
if ui.button("Load Default Keymap").clicked() {
|
||||
backup(ks);
|
||||
set_map(&state.default_keymap);
|
||||
}
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_enabled_ui(map.is_some(), |ui| {
|
||||
if ui.button("Backup Keymap").clicked() {
|
||||
ks.backup = None;
|
||||
backup(ks);
|
||||
}
|
||||
});
|
||||
if let Some(backup) = &ks.backup
|
||||
&& ui.button("Restore Keymap").clicked()
|
||||
{
|
||||
set_map(backup);
|
||||
ks.backup = None;
|
||||
}
|
||||
});
|
||||
let mut label = "Load Keymap from Clipboard".to_string();
|
||||
if *paste_requested == Some(ui.id()) {
|
||||
label.push_str(" ");
|
||||
label.push_str(ICON_PENDING);
|
||||
}
|
||||
let button = ui.button(label);
|
||||
if button.clicked() {
|
||||
*paste_requested = Some(ui.id());
|
||||
button.request_focus();
|
||||
ui.ctx().send_viewport_cmd(ViewportCommand::RequestPaste);
|
||||
} else if *paste_requested == Some(ui.id()) && button.has_focus() {
|
||||
ui.input(|e| {
|
||||
let map = e
|
||||
.events
|
||||
.iter()
|
||||
.filter_map(|e| match e {
|
||||
Event::Paste(s) => Some(s),
|
||||
_ => None,
|
||||
})
|
||||
.next();
|
||||
let Some(map) = map else {
|
||||
return;
|
||||
};
|
||||
*paste_requested = None;
|
||||
let map = match state.kb_ctx.parse_keymap(map.as_bytes()) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
let error = format!("Could not parse keymap: {}", ErrorFmt(e));
|
||||
ps.errors.push(error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
backup(ks);
|
||||
set_map(&map);
|
||||
});
|
||||
} else if *paste_requested == Some(ui.id()) {
|
||||
*paste_requested = None;
|
||||
}
|
||||
ui.collapsing("Create Keymap from Names", |ui| {
|
||||
grid(ui, ("keymap-from-names", ui.id()), |ui| {
|
||||
let defaulted =
|
||||
|ui: &mut Ui, name: &str, default: &mut bool, text: &mut dyn TextBuffer| {
|
||||
let ui = &mut *ui.row();
|
||||
grid_label(ui, name);
|
||||
ui.add_enabled_ui(!*default, |ui| {
|
||||
text_edit(ui, text);
|
||||
});
|
||||
ui.checkbox(default, "Default");
|
||||
};
|
||||
let required = |ui: &mut Ui, name, text| {
|
||||
let ui = &mut *ui.row();
|
||||
grid_label(ui, name);
|
||||
text_edit(ui, text);
|
||||
};
|
||||
defaulted(ui, "Rules", &mut ks.rules_default, &mut ks.rules);
|
||||
defaulted(ui, "Model", &mut ks.model_default, &mut ks.model);
|
||||
required(ui, "Layouts", &mut ks.layouts);
|
||||
required(ui, "Variants", &mut ks.variants);
|
||||
required(ui, "Options", &mut ks.options);
|
||||
});
|
||||
if ui.button("Load").clicked() {
|
||||
'set_map: {
|
||||
let map = state.kb_ctx.keymap_from_rmlvo(
|
||||
(!ks.rules_default).then_some(&ks.rules),
|
||||
(!ks.model_default).then_some(&ks.model),
|
||||
Some(&ks.layouts),
|
||||
Some(&ks.variants),
|
||||
Some(&ks.options),
|
||||
);
|
||||
let map = match map {
|
||||
Ok(map) => map,
|
||||
Err(e) => {
|
||||
let error = format!("Could not parse keymap: {}", ErrorFmt(e));
|
||||
ps.errors.push(error);
|
||||
break 'set_map;
|
||||
}
|
||||
};
|
||||
backup(ks);
|
||||
set_map(&map);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn matrix<T, const W: usize>(
|
||||
ui: &mut Ui,
|
||||
name: &str,
|
||||
old: Option<[[T; W]; 2]>,
|
||||
set: impl FnOnce([[T; W]; 2]),
|
||||
) where
|
||||
T: Numeric,
|
||||
{
|
||||
matrix_ui(ui, name, |_| (), old, set);
|
||||
}
|
||||
|
||||
fn matrix_ui<R, T, const W: usize>(
|
||||
ui: &mut Ui,
|
||||
name: &str,
|
||||
label: impl FnOnce(&mut Ui) -> R,
|
||||
old: Option<[[T; W]; 2]>,
|
||||
set: impl FnOnce([[T; W]; 2]),
|
||||
) where
|
||||
T: Numeric,
|
||||
{
|
||||
if let Some(mut m) = old {
|
||||
let old = m;
|
||||
let ui = &mut *ui.row();
|
||||
grid_label_ui(ui, |ui| {
|
||||
ui.label(name);
|
||||
label(ui);
|
||||
});
|
||||
Grid::new(name).show(ui, |ui| {
|
||||
for row in &mut m {
|
||||
for cell in row {
|
||||
DragValue::new(cell).speed(0.01).ui(ui);
|
||||
}
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
if old != m {
|
||||
set(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ enum PaneName {
|
|||
Xwayland,
|
||||
Outputs,
|
||||
GPUs,
|
||||
Input,
|
||||
}
|
||||
|
||||
impl PaneName {
|
||||
|
|
@ -25,6 +26,7 @@ impl PaneName {
|
|||
PaneName::Xwayland => "Xwayland",
|
||||
PaneName::Outputs => "Outputs",
|
||||
PaneName::GPUs => "GPUs",
|
||||
PaneName::Input => "Input",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -63,6 +65,7 @@ impl ControlCenterInner {
|
|||
PaneType::Outputs(Box::new(self.create_outputs_pane()))
|
||||
}
|
||||
PaneName::GPUs => PaneType::GPUs(self.create_gpus_pane()),
|
||||
PaneName::Input => PaneType::Input(self.create_input_pane()),
|
||||
};
|
||||
self.open(tree, ty);
|
||||
ui.ctx().request_repaint();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::HardwareCursorUpdate,
|
||||
control_center::CCI_INPUT,
|
||||
cursor::{Cursor, DEFAULT_CURSOR_SIZE, KnownCursor},
|
||||
fixed::Fixed,
|
||||
gfx_api::{AcquireSync, ReleaseSync},
|
||||
|
|
@ -183,6 +184,7 @@ impl CursorUserGroup {
|
|||
self.remove_hardware_cursor();
|
||||
self.state.cursor_user_group_hardware_cursor.take();
|
||||
}
|
||||
self.state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn hardware_cursor(&self) -> bool {
|
||||
|
|
@ -195,10 +197,10 @@ impl CursorUserGroup {
|
|||
self.state.remove_cursor_size(old);
|
||||
self.state.add_cursor_size(size);
|
||||
self.reload_known_cursor();
|
||||
self.state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn cursor_size(&self) -> u32 {
|
||||
self.size.get()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ pub mod icons {
|
|||
pub const ICON_INFO: &str = "\u{e88e}";
|
||||
#[expect(dead_code)]
|
||||
pub const ICON_OPEN_IN_NEW: &str = "\u{e89e}";
|
||||
#[expect(dead_code)]
|
||||
pub const ICON_PENDING: &str = "\u{ef64}";
|
||||
pub const ICON_REMOVE: &str = "\u{e15b}";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use {
|
|||
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER, LIBINPUT_CONFIG_CLICK_METHOD_NONE,
|
||||
},
|
||||
object::{Object, Version},
|
||||
state::{DeviceHandlerData, InputDeviceData},
|
||||
state::{DeviceHandlerData, InputDeviceData, State},
|
||||
utils::errorfmt::ErrorFmt,
|
||||
wire::{JayInputId, jay_input::*},
|
||||
},
|
||||
|
|
@ -28,6 +28,7 @@ use {
|
|||
pub struct JayInput {
|
||||
pub id: JayInputId,
|
||||
pub client: Rc<Client>,
|
||||
pub state: Rc<State>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
}
|
||||
|
|
@ -41,6 +42,7 @@ impl JayInput {
|
|||
Self {
|
||||
id,
|
||||
client: client.clone(),
|
||||
state: client.state.clone(),
|
||||
tracker: Default::default(),
|
||||
version,
|
||||
}
|
||||
|
|
@ -309,7 +311,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE => InputDeviceAccelProfile::Adaptive,
|
||||
_ => return Err(JayInputError::UnknownAccelerationProfile(req.profile)),
|
||||
};
|
||||
dev.set_accel_profile(profile);
|
||||
dev.set_accel_profile(&self.state, profile);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -317,7 +319,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
fn set_accel_speed(&self, req: SetAccelSpeed, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_accel_speed(req.speed);
|
||||
dev.set_accel_speed(&self.state, req.speed);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -325,7 +327,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
fn set_tap_enabled(&self, req: SetTapEnabled, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_tap_enabled(req.enabled != 0);
|
||||
dev.set_tap_enabled(&self.state, req.enabled != 0);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -337,7 +339,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_drag_enabled(req.enabled != 0);
|
||||
dev.set_drag_enabled(&self.state, req.enabled != 0);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -349,7 +351,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_drag_lock_enabled(req.enabled != 0);
|
||||
dev.set_drag_lock_enabled(&self.state, req.enabled != 0);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -357,7 +359,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
fn set_left_handed(&self, req: SetLeftHanded, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_left_handed(req.enabled != 0);
|
||||
dev.set_left_handed(&self.state, req.enabled != 0);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -369,7 +371,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_natural_scrolling_enabled(req.enabled != 0);
|
||||
dev.set_natural_scrolling_enabled(&self.state, req.enabled != 0);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -381,7 +383,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_px_per_scroll_wheel(req.px);
|
||||
dev.set_px_per_scroll_wheel(&self.state, req.px);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -393,7 +395,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_transform_matrix([[req.m11, req.m12], [req.m21, req.m22]]);
|
||||
dev.set_transform_matrix(&self.state, [[req.m11, req.m12], [req.m21, req.m22]]);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -410,7 +412,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
self.or_error(|| {
|
||||
let seat = self.seat(req.seat)?;
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_seat(Some(seat));
|
||||
dev.set_seat(&self.state, Some(seat));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -418,7 +420,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
fn detach(&self, req: Detach, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_seat(None);
|
||||
dev.set_seat(&self.state, None);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -459,7 +461,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
fn set_device_keymap(&self, req: SetDeviceKeymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.set_keymap_impl(&req.keymap, req.keymap_len, |map| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_keymap(Some(map.clone()));
|
||||
dev.set_keymap(&self.state, Some(map.clone()));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -490,11 +492,11 @@ impl JayInputRequestHandler for JayInput {
|
|||
.find(|c| c.global.connector.name.to_ascii_lowercase() == namelc)
|
||||
.cloned();
|
||||
match c {
|
||||
Some(c) => dev.set_output(Some(&c.global)),
|
||||
Some(c) => dev.set_output(&self.state, Some(&c.global)),
|
||||
_ => return Err(JayInputError::OutputNotConnected),
|
||||
}
|
||||
}
|
||||
_ => dev.set_output(None),
|
||||
_ => dev.set_output(&self.state, None),
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
|
|
@ -507,7 +509,10 @@ impl JayInputRequestHandler for JayInput {
|
|||
) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_calibration_matrix([[req.m00, req.m01, req.m02], [req.m10, req.m11, req.m12]]);
|
||||
dev.set_calibration_matrix(
|
||||
&self.state,
|
||||
[[req.m00, req.m01, req.m02], [req.m10, req.m11, req.m12]],
|
||||
);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -521,7 +526,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER => InputDeviceClickMethod::Clickfinger,
|
||||
_ => return Err(JayInputError::UnknownClickMethod(req.method)),
|
||||
};
|
||||
dev.set_click_method(method);
|
||||
dev.set_click_method(&self.state, method);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -533,7 +538,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_middle_button_emulation_enabled(req.enabled != 0);
|
||||
dev.set_middle_button_emulation_enabled(&self.state, req.enabled != 0);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -594,7 +599,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
req.options,
|
||||
|map| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_keymap(Some(map.clone()));
|
||||
dev.set_keymap(&self.state, Some(map.clone()));
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ use {
|
|||
ButtonState, InputDeviceAccelProfile, InputDeviceClickMethod, Leds, TransformMatrix,
|
||||
},
|
||||
client::{Client, ClientError, ClientId},
|
||||
control_center::CCI_INPUT,
|
||||
cursor_user::{CursorUser, CursorUserGroup, CursorUserOwner},
|
||||
ei::ei_ifs::ei_seat::EiSeat,
|
||||
fixed::Fixed,
|
||||
|
|
@ -98,6 +99,7 @@ use {
|
|||
numcell::NumCell,
|
||||
rc_eq::{rc_eq, rc_weak_eq},
|
||||
smallmap::SmallMap,
|
||||
static_text::StaticText,
|
||||
},
|
||||
wire::{
|
||||
ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId, WlSeatId,
|
||||
|
|
@ -276,6 +278,15 @@ pub enum FallbackOutputMode {
|
|||
Focus,
|
||||
}
|
||||
|
||||
impl StaticText for FallbackOutputMode {
|
||||
fn text(&self) -> &'static str {
|
||||
match self {
|
||||
FallbackOutputMode::Cursor => "Cursor",
|
||||
FallbackOutputMode::Focus => "Focus",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ConfigFallbackOutputMode> for FallbackOutputMode {
|
||||
type Error = ();
|
||||
|
||||
|
|
@ -768,6 +779,7 @@ impl WlSeatGlobal {
|
|||
if let Some(grab) = self.input_method_grab.get() {
|
||||
grab.on_repeat_info();
|
||||
}
|
||||
self.state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn close(self: &Rc<Self>) {
|
||||
|
|
@ -963,18 +975,18 @@ impl WlSeatGlobal {
|
|||
|
||||
pub fn focus_history_set_visible(&self, visible: bool) {
|
||||
self.focus_history_visible_only.set(visible);
|
||||
self.state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn focus_history_visible(&self) -> bool {
|
||||
self.focus_history_visible_only.get()
|
||||
}
|
||||
|
||||
pub fn focus_history_set_same_workspace(&self, same_workspace: bool) {
|
||||
self.focus_history_same_workspace.set(same_workspace);
|
||||
self.state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn focus_history_same_workspace(&self) -> bool {
|
||||
self.focus_history_same_workspace.get()
|
||||
}
|
||||
|
|
@ -1479,18 +1491,18 @@ impl WlSeatGlobal {
|
|||
|
||||
pub fn set_focus_follows_mouse(&self, focus_follows_mouse: bool) {
|
||||
self.focus_follows_mouse.set(focus_follows_mouse);
|
||||
self.state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn focus_follows_mouse(&self) -> bool {
|
||||
self.focus_follows_mouse.get()
|
||||
}
|
||||
|
||||
pub fn set_fallback_output_mode(&self, fallback_output_mode: FallbackOutputMode) {
|
||||
self.fallback_output_mode.set(fallback_output_mode);
|
||||
self.state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn fallback_output_mode(&self) -> FallbackOutputMode {
|
||||
self.fallback_output_mode.get()
|
||||
}
|
||||
|
|
@ -1610,9 +1622,9 @@ impl WlSeatGlobal {
|
|||
|
||||
pub fn set_pointer_revert_key(&self, key: KeySym) {
|
||||
self.revert_key.set(key);
|
||||
self.state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn pointer_revert_key(&self) -> KeySym {
|
||||
self.revert_key.get()
|
||||
}
|
||||
|
|
@ -1809,7 +1821,7 @@ pub fn collect_kb_foci(node: Rc<dyn Node>) -> SmallVec<[Rc<WlSeatGlobal>; 3]> {
|
|||
}
|
||||
|
||||
impl DeviceHandlerData {
|
||||
pub fn set_seat(&self, seat: Option<Rc<WlSeatGlobal>>) {
|
||||
pub fn set_seat(&self, state: &State, seat: Option<Rc<WlSeatGlobal>>) {
|
||||
if let Some(new) = &seat {
|
||||
if let Some(old) = self.seat.get()
|
||||
&& old.id() == new.id()
|
||||
|
|
@ -1848,6 +1860,7 @@ impl DeviceHandlerData {
|
|||
}
|
||||
}
|
||||
self.attach_event_listeners();
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
fn destroy_physical_keyboard_state(&self) {
|
||||
|
|
@ -1869,13 +1882,14 @@ impl DeviceHandlerData {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn set_keymap(&self, keymap: Option<Rc<KbvmMap>>) {
|
||||
pub fn set_keymap(&self, state: &State, keymap: Option<Rc<KbvmMap>>) {
|
||||
self.destroy_physical_keyboard_state();
|
||||
self.keymap.set(keymap);
|
||||
self.attach_event_listeners();
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_output(&self, output: Option<&WlOutputGlobal>) {
|
||||
pub fn set_output(&self, state: &State, output: Option<&WlOutputGlobal>) {
|
||||
match output {
|
||||
None => {
|
||||
log::info!("Removing output mapping of {}", self.device.name());
|
||||
|
|
@ -1886,6 +1900,7 @@ impl DeviceHandlerData {
|
|||
self.output.set(Some(o.opt.clone()));
|
||||
}
|
||||
}
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn get_rect(&self, state: &State) -> Rect {
|
||||
|
|
@ -1897,52 +1912,64 @@ impl DeviceHandlerData {
|
|||
state.root.extents.get()
|
||||
}
|
||||
|
||||
pub fn set_accel_profile(&self, v: InputDeviceAccelProfile) {
|
||||
pub fn set_accel_profile(&self, state: &State, v: InputDeviceAccelProfile) {
|
||||
self.device.set_accel_profile(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_accel_speed(&self, v: f64) {
|
||||
pub fn set_accel_speed(&self, state: &State, v: f64) {
|
||||
self.device.set_accel_speed(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_tap_enabled(&self, v: bool) {
|
||||
pub fn set_tap_enabled(&self, state: &State, v: bool) {
|
||||
self.device.set_tap_enabled(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_drag_enabled(&self, v: bool) {
|
||||
pub fn set_drag_enabled(&self, state: &State, v: bool) {
|
||||
self.device.set_drag_enabled(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_drag_lock_enabled(&self, v: bool) {
|
||||
pub fn set_drag_lock_enabled(&self, state: &State, v: bool) {
|
||||
self.device.set_drag_lock_enabled(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_left_handed(&self, v: bool) {
|
||||
pub fn set_left_handed(&self, state: &State, v: bool) {
|
||||
self.device.set_left_handed(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_natural_scrolling_enabled(&self, v: bool) {
|
||||
pub fn set_natural_scrolling_enabled(&self, state: &State, v: bool) {
|
||||
self.device.set_natural_scrolling_enabled(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_px_per_scroll_wheel(&self, v: f64) {
|
||||
pub fn set_px_per_scroll_wheel(&self, state: &State, v: f64) {
|
||||
self.px_per_scroll_wheel.set(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_transform_matrix(&self, v: TransformMatrix) {
|
||||
pub fn set_transform_matrix(&self, state: &State, v: TransformMatrix) {
|
||||
self.device.set_transform_matrix(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_calibration_matrix(&self, v: [[f32; 3]; 2]) {
|
||||
pub fn set_calibration_matrix(&self, state: &State, v: [[f32; 3]; 2]) {
|
||||
self.device.set_calibration_matrix(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_click_method(&self, v: InputDeviceClickMethod) {
|
||||
pub fn set_click_method(&self, state: &State, v: InputDeviceClickMethod) {
|
||||
self.device.set_click_method(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn set_middle_button_emulation_enabled(&self, v: bool) {
|
||||
pub fn set_middle_button_emulation_enabled(&self, state: &State, v: bool) {
|
||||
self.device.set_middle_button_emulation_enabled(v);
|
||||
state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::KeyState,
|
||||
control_center::CCI_INPUT,
|
||||
ifs::{
|
||||
wl_seat::{
|
||||
WlSeatGlobal,
|
||||
|
|
@ -89,6 +90,7 @@ impl WlSeatGlobal {
|
|||
im.cancel_simple(self);
|
||||
}
|
||||
}
|
||||
self.state.trigger_cci(CCI_INPUT);
|
||||
}
|
||||
|
||||
pub fn simple_im_enabled(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ pub struct KbvmMap {
|
|||
pub id: KbvmMapId,
|
||||
pub state_machine: StateMachine,
|
||||
pub lookup_table: LookupTable,
|
||||
#[expect(dead_code)]
|
||||
pub map_text: String,
|
||||
pub map: KeymapFd,
|
||||
pub xwayland_map: KeymapFd,
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ impl DeviceHandler {
|
|||
}
|
||||
for seat in self.state.globals.seats.lock().values() {
|
||||
if seat.seat_name() == DEFAULT_SEAT_NAME {
|
||||
self.data.set_seat(Some(seat.clone()));
|
||||
self.data.set_seat(&self.state, Some(seat.clone()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -102,6 +102,6 @@ impl DeviceHandler {
|
|||
.input_device_handlers
|
||||
.borrow_mut()
|
||||
.remove(&self.dev.id());
|
||||
self.data.set_seat(None);
|
||||
self.data.set_seat(&self.state, None);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue