forked from NotAShelf/beer
wayland: idle-inhibit while focused and a content-type hint
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ib25e27fc913c3af009e85496412002366a6a6964
This commit is contained in:
parent
5d132d9ac7
commit
e172d4fbb3
4 changed files with 107 additions and 0 deletions
|
|
@ -39,6 +39,11 @@ channel).
|
|||
built-in set (whitespace and common punctuation, keeping _.-/:~\__ inside
|
||||
words).
|
||||
|
||||
*idle-inhibit* = _bool_
|
||||
While the window is focused, ask the compositor not to blank the screen or
|
||||
start the screensaver (idle-inhibit-v1). A backgrounded window stops
|
||||
inhibiting. Default _false_.
|
||||
|
||||
# [colors]
|
||||
|
||||
*foreground* = _color_, *background* = _color_
|
||||
|
|
|
|||
|
|
@ -154,6 +154,9 @@ pub struct Main {
|
|||
/// Characters that break a word for double-click selection. Empty/unset
|
||||
/// keeps the built-in default.
|
||||
pub word_delimiters: Option<String>,
|
||||
/// Hold an idle inhibitor while the window is focused, so the compositor
|
||||
/// does not blank the screen or start the screensaver. Default off.
|
||||
pub idle_inhibit: bool,
|
||||
}
|
||||
|
||||
impl Default for Main {
|
||||
|
|
@ -167,6 +170,7 @@ impl Default for Main {
|
|||
pad_x: 2,
|
||||
pad_y: 2,
|
||||
word_delimiters: None,
|
||||
idle_inhibit: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ impl WindowHandler for App {
|
|||
}
|
||||
}
|
||||
self.focused = configure.is_activated();
|
||||
self.sync_idle_inhibit();
|
||||
if self.session.is_none() {
|
||||
self.spawn_session();
|
||||
} else {
|
||||
|
|
@ -188,6 +189,7 @@ impl KeyboardHandler for App {
|
|||
self.activate_keyboard(keyboard);
|
||||
self.serial = serial;
|
||||
self.focused = true;
|
||||
self.sync_idle_inhibit();
|
||||
self.report_focus(true);
|
||||
self.needs_draw = true;
|
||||
}
|
||||
|
|
@ -201,6 +203,7 @@ impl KeyboardHandler for App {
|
|||
_: u32,
|
||||
) {
|
||||
self.focused = false;
|
||||
self.sync_idle_inhibit();
|
||||
// Drop held-key state so a key released while unfocused can't leak a
|
||||
// stale kitty release event later.
|
||||
self.keys_down.clear();
|
||||
|
|
@ -634,6 +637,56 @@ impl Dispatch<WpViewport, ()> for App {
|
|||
}
|
||||
}
|
||||
|
||||
// idle-inhibit and content-type are likewise raw protocol objects; none of them
|
||||
// emit events we act on.
|
||||
impl Dispatch<ZwpIdleInhibitManagerV1, ()> for App {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &ZwpIdleInhibitManagerV1,
|
||||
_: <ZwpIdleInhibitManagerV1 as Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<ZwpIdleInhibitorV1, ()> for App {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &ZwpIdleInhibitorV1,
|
||||
_: zwp_idle_inhibitor_v1::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<WpContentTypeManagerV1, ()> for App {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &WpContentTypeManagerV1,
|
||||
_: <WpContentTypeManagerV1 as Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<WpContentTypeV1, ()> for App {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &WpContentTypeV1,
|
||||
_: wp_content_type_v1::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl ActivationHandler for App {
|
||||
type RequestData = RequestData;
|
||||
|
||||
|
|
|
|||
|
|
@ -84,10 +84,18 @@ use wayland_client::{
|
|||
wl_surface,
|
||||
},
|
||||
};
|
||||
use wayland_protocols::wp::content_type::v1::client::{
|
||||
wp_content_type_manager_v1::WpContentTypeManagerV1,
|
||||
wp_content_type_v1::{self, WpContentTypeV1},
|
||||
};
|
||||
use wayland_protocols::wp::fractional_scale::v1::client::{
|
||||
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1,
|
||||
wp_fractional_scale_v1::{self, WpFractionalScaleV1},
|
||||
};
|
||||
use wayland_protocols::wp::idle_inhibit::zv1::client::{
|
||||
zwp_idle_inhibit_manager_v1::ZwpIdleInhibitManagerV1,
|
||||
zwp_idle_inhibitor_v1::{self, ZwpIdleInhibitorV1},
|
||||
};
|
||||
use wayland_protocols::wp::text_input::zv3::client::{
|
||||
zwp_text_input_manager_v3::ZwpTextInputManagerV3,
|
||||
zwp_text_input_v3::{self, ContentHint, ContentPurpose, ZwpTextInputV3},
|
||||
|
|
@ -181,6 +189,14 @@ pub fn run(config: Config, config_path: Option<std::path::PathBuf>) -> anyhow::R
|
|||
});
|
||||
let text_input_manager = bind_global::<ZwpTextInputManagerV3>(&globals, &qh);
|
||||
let activation = ActivationState::bind(&globals, &qh).ok();
|
||||
let idle_inhibit_manager = bind_global::<ZwpIdleInhibitManagerV1>(&globals, &qh);
|
||||
// Tag the surface as plain content (a terminal is none of photo/video/game)
|
||||
// so the compositor applies no media-specific treatment. Applies on commit.
|
||||
let content_type = bind_global::<WpContentTypeManagerV1>(&globals, &qh)
|
||||
.map(|mgr| mgr.get_surface_content_type(window.wl_surface(), &qh, ()));
|
||||
if let Some(ct) = &content_type {
|
||||
ct.set_content_type(wp_content_type_v1::Type::None);
|
||||
}
|
||||
|
||||
// First commit with no buffer kicks off the initial configure.
|
||||
window.commit();
|
||||
|
|
@ -219,6 +235,9 @@ pub fn run(config: Config, config_path: Option<std::path::PathBuf>) -> anyhow::R
|
|||
cursor_shape_manager,
|
||||
text_input_manager,
|
||||
activation,
|
||||
idle_inhibit_manager,
|
||||
idle_inhibitor: None,
|
||||
content_type,
|
||||
preedit: String::new(),
|
||||
ime_preedit_pending: String::new(),
|
||||
ime_commit_pending: String::new(),
|
||||
|
|
@ -397,6 +416,17 @@ struct App {
|
|||
text_input_manager: Option<ZwpTextInputManagerV3>,
|
||||
/// xdg-activation, used to request attention on an urgent bell.
|
||||
activation: Option<ActivationState>,
|
||||
/// idle-inhibit-v1 manager; an inhibitor is held while focused when the
|
||||
/// `[main] idle-inhibit` config is on, so the screen does not blank.
|
||||
idle_inhibit_manager: Option<ZwpIdleInhibitManagerV1>,
|
||||
idle_inhibitor: Option<ZwpIdleInhibitorV1>,
|
||||
/// content-type-v1 hint object. Set once at startup; held only so the
|
||||
/// object (and thus the hint) outlives construction.
|
||||
#[allow(
|
||||
dead_code,
|
||||
reason = "kept alive to preserve the surface content-type hint"
|
||||
)]
|
||||
content_type: Option<WpContentTypeV1>,
|
||||
/// Committed IME preedit string shown inline at the cursor while composing.
|
||||
preedit: String,
|
||||
/// Preedit/commit accumulated since the last text-input `done`.
|
||||
|
|
@ -1409,6 +1439,21 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create or drop the idle inhibitor to match `[main] idle-inhibit` and the
|
||||
/// current focus: inhibit only while focused, so a backgrounded terminal
|
||||
/// still lets the screen blank. Idempotent; called on every focus change.
|
||||
fn sync_idle_inhibit(&mut self) {
|
||||
let want = self.config.main.idle_inhibit && self.focused;
|
||||
if want && self.idle_inhibitor.is_none() {
|
||||
if let Some(mgr) = &self.idle_inhibit_manager {
|
||||
self.idle_inhibitor =
|
||||
Some(mgr.create_inhibitor(self.window.wl_surface(), &self.qh, ()));
|
||||
}
|
||||
} else if !want && let Some(inhibitor) = self.idle_inhibitor.take() {
|
||||
inhibitor.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/// Write bytes to the PTY master, logging on failure.
|
||||
fn write_to_pty(&mut self, bytes: &[u8]) {
|
||||
if let Some(session) = self.session.as_mut()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue