1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! Session lock example (`ext-session-lock-v1`).
//!
//! **WARNING: running this locks your session.** Unlock by typing the
//! password `guido` (plus Enter) in the password field, or wait for the
//! 30-second auto-unlock safety timer.
//!
//! A small bar hosts a "Lock session" button. Locking creates one lock
//! surface per output with a password field; the compositor blanks every
//! output and routes keyboard input to the lock surfaces.
use std::time::Duration;
use guido::prelude::*;
const PASSWORD: &str = "guido";
fn lock_screen(output: OutputInfo) -> Container {
let attempt = create_signal(String::new());
let error = create_signal(false);
// Safety net for an example: never leave the user locked out.
let auto_unlock = create_signal(false);
let auto_unlock_w = auto_unlock.writer();
create_task(move |ctx| async move {
tokio::time::sleep(Duration::from_secs(30)).await;
if ctx.is_running() {
auto_unlock_w.set(true);
}
});
create_effect(move || {
if auto_unlock.get() {
unlock_session();
}
});
container()
.width(fill())
.height(fill())
.background(Color::rgb(0.07, 0.07, 0.1))
.layout(
Flex::column()
.spacing(16.0)
.main_alignment(MainAlignment::Center)
.cross_alignment(CrossAlignment::Center),
)
.child(
container().child(
text(format!(
"Locked — {}",
output.name.unwrap_or_else(|| "output".into())
))
.font_size(24.0)
.color(Color::WHITE),
),
)
.child(
container().child(
text("password: guido (auto-unlocks after 30s)")
.font_size(13.0)
.color(Color::rgb(0.6, 0.6, 0.7)),
),
)
.child(
container()
.width(at_least(280.0))
.padding(10.0)
.background(Color::rgb(0.15, 0.15, 0.2))
.corners(8.0)
.when_focused(|s| s.border(2.0, Color::rgb(0.4, 0.8, 1.0)))
.child(
text_input(attempt)
.cursor_color(Color::rgb(0.4, 0.8, 1.0))
.color(Color::WHITE)
.password(true)
.on_submit(move |s| {
if s == PASSWORD {
unlock_session();
} else {
error.set(true);
}
}),
),
)
.child(text(move || {
if error.get() {
"Wrong password".to_string()
} else {
String::new()
}
}))
}
fn main() {
env_logger::init();
App::new().run(|app| {
app.add_surface(
SurfaceConfig::new()
.height(40)
.anchor(Anchor::TOP | Anchor::LEFT | Anchor::RIGHT)
.background_color(Color::rgb(0.1, 0.1, 0.15)),
|| {
container()
.width(fill())
.layout(
Flex::row()
.spacing(12.0)
.main_alignment(MainAlignment::Center)
.cross_alignment(CrossAlignment::Center),
)
.child(
container()
.padding([6.0, 16.0])
.background(Color::rgb(0.3, 0.2, 0.2))
.corners(6.0)
.when_hovered(|s| s.lighter(0.1))
.when_pressed(|s| s.ripple())
.on_click(|| lock_session(lock_screen))
.child(text("Lock session")),
)
.child(text(move || format!("state: {:?}", lock_state().get())))
},
);
});
}