mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-25 09:59:21 +01:00
Add builtin quit prompt
This commit is contained in:
parent
d58c8571ca
commit
d70a0abda5
6 changed files with 236 additions and 54 deletions
71
Cargo.lock
generated
71
Cargo.lock
generated
|
@ -601,7 +601,7 @@ dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
"strsim",
|
"strsim 0.11.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -937,6 +937,41 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim 0.10.0",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
@ -1219,6 +1254,27 @@ version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
|
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "from_variants"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e859c8f2057687618905dbe99fc76e836e0a69738865ef90e46fc214a41bbf2"
|
||||||
|
dependencies = [
|
||||||
|
"from_variants_impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "from_variants_impl"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55a5e644a80e6d96b2b4910fa7993301d7b7926c045b475b62202b20a36ce69e"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
|
@ -1834,6 +1890,12 @@ dependencies = [
|
||||||
"objc2 0.4.1",
|
"objc2 0.4.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.1"
|
version = "0.25.1"
|
||||||
|
@ -3614,6 +3676,7 @@ dependencies = [
|
||||||
name = "snowcap-api"
|
name = "snowcap-api"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"from_variants",
|
||||||
"futures",
|
"futures",
|
||||||
"snowcap-api-defs",
|
"snowcap-api-defs",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -3698,6 +3761,12 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|
|
@ -11,10 +11,6 @@ use pinnacle_api::{
|
||||||
input::{Mod, MouseButton, MouseEdge},
|
input::{Mod, MouseButton, MouseEdge},
|
||||||
ApiModules,
|
ApiModules,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "snowcap")]
|
|
||||||
use snowcap_api::layer::{ExclusiveZone, KeyboardInteractivity, ZLayer};
|
|
||||||
#[cfg(feature = "snowcap")]
|
|
||||||
use snowcap_api::widget::{Alignment, Column, Container, Length, Text};
|
|
||||||
|
|
||||||
// Pinnacle needs to perform some setup before and after your config.
|
// Pinnacle needs to perform some setup before and after your config.
|
||||||
// The `#[pinnacle_api::config(modules)]` attribute does so and
|
// The `#[pinnacle_api::config(modules)]` attribute does so and
|
||||||
|
@ -76,36 +72,7 @@ async fn main() {
|
||||||
// `mod_key + alt + q` quits Pinnacle
|
// `mod_key + alt + q` quits Pinnacle
|
||||||
input.keybind([mod_key, Mod::Alt], 'q', || {
|
input.keybind([mod_key, Mod::Alt], 'q', || {
|
||||||
#[cfg(feature = "snowcap")]
|
#[cfg(feature = "snowcap")]
|
||||||
{
|
snowcap.integration.quit_prompt().show();
|
||||||
let widget = Container::new(Column::new_with_children([
|
|
||||||
Text::new("Quit Pinnacle?").into(),
|
|
||||||
Text::new("Press ENTER to confirm.").into(),
|
|
||||||
]))
|
|
||||||
.with_vertical_alignment(Alignment::Center)
|
|
||||||
.with_horizontal_alignment(Alignment::Center)
|
|
||||||
.with_width(Length::Fill)
|
|
||||||
.with_height(Length::Fill)
|
|
||||||
.with_border_thickness(4.0)
|
|
||||||
.with_border_radius(16.0);
|
|
||||||
|
|
||||||
snowcap
|
|
||||||
.new_widget(
|
|
||||||
widget.into(),
|
|
||||||
200,
|
|
||||||
100,
|
|
||||||
None,
|
|
||||||
KeyboardInteractivity::Exclusive,
|
|
||||||
ExclusiveZone::Respect,
|
|
||||||
ZLayer::Overlay,
|
|
||||||
)
|
|
||||||
.on_key_press(|widget, key, _mods| {
|
|
||||||
if key == Keysym::Return {
|
|
||||||
pinnacle.quit();
|
|
||||||
} else {
|
|
||||||
widget.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "snowcap"))]
|
#[cfg(not(feature = "snowcap"))]
|
||||||
pinnacle.quit();
|
pinnacle.quit();
|
||||||
|
|
|
@ -85,6 +85,7 @@ use pinnacle::Pinnacle;
|
||||||
use process::Process;
|
use process::Process;
|
||||||
use render::Render;
|
use render::Render;
|
||||||
use signal::SignalState;
|
use signal::SignalState;
|
||||||
|
use snowcap::Snowcap;
|
||||||
use tag::Tag;
|
use tag::Tag;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
sync::{
|
sync::{
|
||||||
|
@ -98,9 +99,6 @@ use tonic::transport::{Endpoint, Uri};
|
||||||
use tower::service_fn;
|
use tower::service_fn;
|
||||||
use window::Window;
|
use window::Window;
|
||||||
|
|
||||||
#[cfg(feature = "snowcap")]
|
|
||||||
use snowcap_api::layer::Layer;
|
|
||||||
|
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
|
@ -108,6 +106,8 @@ pub mod pinnacle;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
pub mod signal;
|
pub mod signal;
|
||||||
|
#[cfg(feature = "snowcap")]
|
||||||
|
pub mod snowcap;
|
||||||
pub mod tag;
|
pub mod tag;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
|
@ -142,7 +142,7 @@ pub struct ApiModules {
|
||||||
|
|
||||||
#[cfg(feature = "snowcap")]
|
#[cfg(feature = "snowcap")]
|
||||||
/// The snowcap widget system.
|
/// The snowcap widget system.
|
||||||
pub snowcap: &'static Layer,
|
pub snowcap: &'static Snowcap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for ApiModules {
|
impl std::fmt::Debug for ApiModules {
|
||||||
|
@ -215,20 +215,21 @@ pub async fn connect() -> Result<(ApiModules, Receivers), Box<dyn std::error::Er
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "snowcap")]
|
#[cfg(feature = "snowcap")]
|
||||||
let (snowcap, snowcap_recv) = snowcap_api::connect().await.unwrap();
|
let (modules, snowcap_recv) = {
|
||||||
|
let (snowcap, snowcap_recv) = snowcap_api::connect().await.unwrap();
|
||||||
#[cfg(feature = "snowcap")]
|
let api_modules = ApiModules {
|
||||||
let modules = ApiModules {
|
pinnacle,
|
||||||
pinnacle,
|
process,
|
||||||
process,
|
window,
|
||||||
window,
|
input,
|
||||||
input,
|
output,
|
||||||
output,
|
tag,
|
||||||
tag,
|
layout,
|
||||||
layout,
|
render,
|
||||||
render,
|
signal: signal.clone(),
|
||||||
signal: signal.clone(),
|
snowcap: Box::leak(Box::new(Snowcap::new(snowcap))),
|
||||||
snowcap: Box::leak(Box::new(snowcap)),
|
};
|
||||||
|
(api_modules, snowcap_recv)
|
||||||
};
|
};
|
||||||
|
|
||||||
window.finish_init(modules.clone());
|
window.finish_init(modules.clone());
|
||||||
|
@ -236,6 +237,7 @@ pub async fn connect() -> Result<(ApiModules, Receivers), Box<dyn std::error::Er
|
||||||
tag.finish_init(modules.clone());
|
tag.finish_init(modules.clone());
|
||||||
layout.finish_init(modules.clone());
|
layout.finish_init(modules.clone());
|
||||||
signal.read().await.finish_init(modules.clone());
|
signal.read().await.finish_init(modules.clone());
|
||||||
|
modules.snowcap.finish_init(modules.clone());
|
||||||
|
|
||||||
#[cfg(feature = "snowcap")]
|
#[cfg(feature = "snowcap")]
|
||||||
let receivers = Receivers {
|
let receivers = Receivers {
|
||||||
|
|
29
api/rust/src/snowcap.rs
Normal file
29
api/rust/src/snowcap.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//! The Snowcap widget system.
|
||||||
|
//! // TODO: these docs
|
||||||
|
|
||||||
|
use integration::Integration;
|
||||||
|
use snowcap_api::layer::Layer;
|
||||||
|
|
||||||
|
use crate::ApiModules;
|
||||||
|
|
||||||
|
pub mod integration;
|
||||||
|
|
||||||
|
/// Snowcap modules and Pinnacle integration.
|
||||||
|
pub struct Snowcap {
|
||||||
|
/// Create layer surface widgets.
|
||||||
|
pub layer: &'static Layer,
|
||||||
|
pub integration: &'static Integration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Snowcap {
|
||||||
|
pub(crate) fn new(layer: Layer) -> Self {
|
||||||
|
Self {
|
||||||
|
layer: Box::leak(Box::new(layer)),
|
||||||
|
integration: Box::leak(Box::new(Integration::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn finish_init(&self, api: ApiModules) {
|
||||||
|
self.integration.finish_init(api);
|
||||||
|
}
|
||||||
|
}
|
115
api/rust/src/snowcap/integration.rs
Normal file
115
api/rust/src/snowcap/integration.rs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
//! Pinnacle-specific integrations with Snowcap.
|
||||||
|
//!
|
||||||
|
//! This module includes builtin widgets like the exit prompt and keybind list.
|
||||||
|
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
use snowcap_api::{
|
||||||
|
layer::{ExclusiveZone, KeyboardInteractivity, ZLayer},
|
||||||
|
widget::{
|
||||||
|
font::{Family, Font, Weight},
|
||||||
|
Alignment, Color, Column, Container, Length, Text,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use xkbcommon::xkb::Keysym;
|
||||||
|
|
||||||
|
use crate::ApiModules;
|
||||||
|
|
||||||
|
/// Builtin widgets for Pinnacle.
|
||||||
|
pub struct Integration {
|
||||||
|
api: OnceLock<ApiModules>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Integration {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
api: OnceLock::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn finish_init(&self, api: ApiModules) {
|
||||||
|
self.api.set(api).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create the default quit prompt.
|
||||||
|
///
|
||||||
|
/// Some of its characteristics can be changed by setting its fields.
|
||||||
|
pub fn quit_prompt(&self) -> QuitPrompt {
|
||||||
|
QuitPrompt {
|
||||||
|
api: self.api.get().cloned().unwrap(),
|
||||||
|
border_radius: 12.0,
|
||||||
|
border_thickness: 6.0,
|
||||||
|
background_color: [0.15, 0.03, 0.1, 0.65].into(),
|
||||||
|
border_color: [0.8, 0.2, 0.4].into(),
|
||||||
|
font: Font::new_with_family(Family::Name("Ubuntu".into())),
|
||||||
|
width: 220,
|
||||||
|
height: 120,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A quit prompt.
|
||||||
|
///
|
||||||
|
/// When opened, pressing ENTER will quit the compositor.
|
||||||
|
pub struct QuitPrompt {
|
||||||
|
api: ApiModules,
|
||||||
|
/// The radius of the prompt's corners.
|
||||||
|
pub border_radius: f32,
|
||||||
|
/// The thickness of the prompt border.
|
||||||
|
pub border_thickness: f32,
|
||||||
|
/// The color of the prompt background.
|
||||||
|
pub background_color: Color,
|
||||||
|
/// The color of the prompt border.
|
||||||
|
pub border_color: Color,
|
||||||
|
/// The font of the prompt.
|
||||||
|
pub font: Font,
|
||||||
|
/// The height of the prompt.
|
||||||
|
pub width: u32,
|
||||||
|
/// The width of the prompt.
|
||||||
|
pub height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QuitPrompt {
|
||||||
|
/// Show this quit prompt.
|
||||||
|
pub fn show(&self) {
|
||||||
|
let widget = Container::new(Column::new_with_children([
|
||||||
|
Text::new("Quit Pinnacle?")
|
||||||
|
.font(self.font.clone().weight(Weight::Bold))
|
||||||
|
.size(20.0)
|
||||||
|
.into(),
|
||||||
|
Text::new("").size(8.0).into(), // Spacing because I haven't impl'd that yet
|
||||||
|
Text::new("Press ENTER to confirm, or\nany other key to close this")
|
||||||
|
.font(self.font.clone())
|
||||||
|
.size(14.0)
|
||||||
|
.into(),
|
||||||
|
]))
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.vertical_alignment(Alignment::Center)
|
||||||
|
.horizontal_alignment(Alignment::Center)
|
||||||
|
.border_radius(self.border_radius)
|
||||||
|
.border_thickness(self.border_thickness)
|
||||||
|
.border_color(self.border_color)
|
||||||
|
.background_color(self.background_color);
|
||||||
|
|
||||||
|
self.api
|
||||||
|
.snowcap
|
||||||
|
.layer
|
||||||
|
.new_widget(
|
||||||
|
widget,
|
||||||
|
self.width,
|
||||||
|
self.height,
|
||||||
|
None,
|
||||||
|
KeyboardInteractivity::Exclusive,
|
||||||
|
ExclusiveZone::Respect,
|
||||||
|
ZLayer::Overlay,
|
||||||
|
)
|
||||||
|
.on_key_press(|handle, key, _mods| {
|
||||||
|
if key == Keysym::Return {
|
||||||
|
self.api.pinnacle.quit();
|
||||||
|
} else {
|
||||||
|
handle.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
2
snowcap
2
snowcap
|
@ -1 +1 @@
|
||||||
Subproject commit 81f61f7fbbec91673caf6c56df438b64eab90181
|
Subproject commit e6850779511da33bbdd4be646bcc21be39495ffa
|
Loading…
Reference in a new issue