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
|
built-in set (whitespace and common punctuation, keeping _.-/:~\__ inside
|
||||||
words).
|
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]
|
# [colors]
|
||||||
|
|
||||||
*foreground* = _color_, *background* = _color_
|
*foreground* = _color_, *background* = _color_
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,9 @@ pub struct Main {
|
||||||
/// Characters that break a word for double-click selection. Empty/unset
|
/// Characters that break a word for double-click selection. Empty/unset
|
||||||
/// keeps the built-in default.
|
/// keeps the built-in default.
|
||||||
pub word_delimiters: Option<String>,
|
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 {
|
impl Default for Main {
|
||||||
|
|
@ -167,6 +170,7 @@ impl Default for Main {
|
||||||
pad_x: 2,
|
pad_x: 2,
|
||||||
pad_y: 2,
|
pad_y: 2,
|
||||||
word_delimiters: None,
|
word_delimiters: None,
|
||||||
|
idle_inhibit: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ impl WindowHandler for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.focused = configure.is_activated();
|
self.focused = configure.is_activated();
|
||||||
|
self.sync_idle_inhibit();
|
||||||
if self.session.is_none() {
|
if self.session.is_none() {
|
||||||
self.spawn_session();
|
self.spawn_session();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -188,6 +189,7 @@ impl KeyboardHandler for App {
|
||||||
self.activate_keyboard(keyboard);
|
self.activate_keyboard(keyboard);
|
||||||
self.serial = serial;
|
self.serial = serial;
|
||||||
self.focused = true;
|
self.focused = true;
|
||||||
|
self.sync_idle_inhibit();
|
||||||
self.report_focus(true);
|
self.report_focus(true);
|
||||||
self.needs_draw = true;
|
self.needs_draw = true;
|
||||||
}
|
}
|
||||||
|
|
@ -201,6 +203,7 @@ impl KeyboardHandler for App {
|
||||||
_: u32,
|
_: u32,
|
||||||
) {
|
) {
|
||||||
self.focused = false;
|
self.focused = false;
|
||||||
|
self.sync_idle_inhibit();
|
||||||
// Drop held-key state so a key released while unfocused can't leak a
|
// Drop held-key state so a key released while unfocused can't leak a
|
||||||
// stale kitty release event later.
|
// stale kitty release event later.
|
||||||
self.keys_down.clear();
|
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 {
|
impl ActivationHandler for App {
|
||||||
type RequestData = RequestData;
|
type RequestData = RequestData;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,10 +84,18 @@ use wayland_client::{
|
||||||
wl_surface,
|
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::{
|
use wayland_protocols::wp::fractional_scale::v1::client::{
|
||||||
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1,
|
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1,
|
||||||
wp_fractional_scale_v1::{self, WpFractionalScaleV1},
|
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::{
|
use wayland_protocols::wp::text_input::zv3::client::{
|
||||||
zwp_text_input_manager_v3::ZwpTextInputManagerV3,
|
zwp_text_input_manager_v3::ZwpTextInputManagerV3,
|
||||||
zwp_text_input_v3::{self, ContentHint, ContentPurpose, ZwpTextInputV3},
|
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 text_input_manager = bind_global::<ZwpTextInputManagerV3>(&globals, &qh);
|
||||||
let activation = ActivationState::bind(&globals, &qh).ok();
|
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.
|
// First commit with no buffer kicks off the initial configure.
|
||||||
window.commit();
|
window.commit();
|
||||||
|
|
@ -219,6 +235,9 @@ pub fn run(config: Config, config_path: Option<std::path::PathBuf>) -> anyhow::R
|
||||||
cursor_shape_manager,
|
cursor_shape_manager,
|
||||||
text_input_manager,
|
text_input_manager,
|
||||||
activation,
|
activation,
|
||||||
|
idle_inhibit_manager,
|
||||||
|
idle_inhibitor: None,
|
||||||
|
content_type,
|
||||||
preedit: String::new(),
|
preedit: String::new(),
|
||||||
ime_preedit_pending: String::new(),
|
ime_preedit_pending: String::new(),
|
||||||
ime_commit_pending: String::new(),
|
ime_commit_pending: String::new(),
|
||||||
|
|
@ -397,6 +416,17 @@ struct App {
|
||||||
text_input_manager: Option<ZwpTextInputManagerV3>,
|
text_input_manager: Option<ZwpTextInputManagerV3>,
|
||||||
/// xdg-activation, used to request attention on an urgent bell.
|
/// xdg-activation, used to request attention on an urgent bell.
|
||||||
activation: Option<ActivationState>,
|
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.
|
/// Committed IME preedit string shown inline at the cursor while composing.
|
||||||
preedit: String,
|
preedit: String,
|
||||||
/// Preedit/commit accumulated since the last text-input `done`.
|
/// 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.
|
/// Write bytes to the PTY master, logging on failure.
|
||||||
fn write_to_pty(&mut self, bytes: &[u8]) {
|
fn write_to_pty(&mut self, bytes: &[u8]) {
|
||||||
if let Some(session) = self.session.as_mut()
|
if let Some(session) = self.session.as_mut()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue