mimick/library/lightbox/
fullscreen.rs1use std::cell::Cell;
2use std::rc::Rc;
3use std::time::{Duration, Instant};
4
5use gtk::prelude::*;
6
7use super::Lightbox;
8
9const HIDE_DELAY: Duration = Duration::from_secs(3);
10
11pub(super) struct Chrome {
12 hover: gtk::EventControllerMotion,
13 pointer: Cell<(f64, f64)>,
14 hide_at: Cell<Instant>,
15 armed: Cell<bool>,
16}
17
18impl Chrome {
19 pub(super) fn new() -> Self {
20 Self {
21 hover: gtk::EventControllerMotion::new(),
22 pointer: Cell::new((0.0, 0.0)),
23 hide_at: Cell::new(Instant::now()),
24 armed: Cell::new(false),
25 }
26 }
27}
28
29impl Lightbox {
30 pub(super) fn connect_fullscreen(self: &Rc<Self>) {
31 let lb = Rc::downgrade(self);
32 let handler = self.ui.window.connect_fullscreened_notify(move |window| {
33 if let Some(lb) = lb.upgrade() {
34 lb.apply_fullscreen(window.is_fullscreen());
35 }
36 });
37 *self.fullscreen_handler.borrow_mut() = Some(handler);
38 let lb = Rc::downgrade(self);
39 self.header.fullscreen_btn.connect_clicked(move |_| {
40 if let Some(lb) = lb.upgrade() {
41 lb.toggle_fullscreen();
42 }
43 });
44 self.header.bar.add_controller(self.chrome.hover.clone());
45 self.connect_chrome_reveal();
46 }
47
48 pub(super) fn toggle_fullscreen(&self) {
49 let window = &self.ui.window;
50 window.set_fullscreened(!window.is_fullscreen());
51 }
52
53 pub(super) fn close_fullscreen(&self) {
54 if let Some(handler) = self.fullscreen_handler.take() {
55 self.ui.window.disconnect(handler);
56 }
57 if self.ui.window.is_fullscreen() {
58 self.ui.window.unfullscreen();
59 }
60 }
61
62 fn apply_fullscreen(&self, fullscreen: bool) {
63 let toolbar = &self.header.toolbar;
64 toolbar.set_extend_content_to_top_edge(fullscreen);
65 toolbar.set_reveal_top_bars(!fullscreen);
66 self.actions.bar.set_visible(!fullscreen);
67 super::set_viewer_margins(&self.viewer, fullscreen);
68 if fullscreen {
69 self.viewer.add_css_class("mimick-fullscreen");
70 self.header.details_btn.set_active(false);
71 } else {
72 self.viewer.remove_css_class("mimick-fullscreen");
73 }
74 let (icon, tooltip) = if fullscreen {
75 ("view-restore-symbolic", "Exit fullscreen (F11)")
76 } else {
77 ("view-fullscreen-symbolic", "Fullscreen (F11)")
78 };
79 self.header.fullscreen_btn.set_icon_name(icon);
80 self.header.fullscreen_btn.set_tooltip_text(Some(tooltip));
81 if let Some(player) = self.video.borrow().as_ref() {
82 player.set_fullscreen(fullscreen);
83 }
84 }
85
86 fn connect_chrome_reveal(self: &Rc<Self>) {
87 let motion = gtk::EventControllerMotion::new();
88 let lb = Rc::downgrade(self);
89 motion.connect_motion(move |_, x, y| {
90 if let Some(lb) = lb.upgrade()
91 && lb.chrome.pointer.replace((x, y)) != (x, y)
92 {
93 lb.reveal_chrome();
94 }
95 });
96 self.picture.overlay.add_controller(motion);
97 let tap = gtk::GestureClick::new();
98 let lb = Rc::downgrade(self);
99 tap.connect_pressed(move |_, n_press, _, _| {
100 if n_press == 1
101 && let Some(lb) = lb.upgrade()
102 {
103 lb.reveal_chrome();
104 }
105 });
106 self.picture.overlay.add_controller(tap);
107 }
108
109 fn reveal_chrome(self: &Rc<Self>) {
110 if !self.ui.window.is_fullscreen() {
111 return;
112 }
113 self.header.toolbar.set_reveal_top_bars(true);
114 self.chrome.hide_at.set(Instant::now() + HIDE_DELAY);
115 if !self.chrome.armed.replace(true) {
116 self.arm_chrome_hide(HIDE_DELAY);
117 }
118 }
119
120 fn arm_chrome_hide(self: &Rc<Self>, delay: Duration) {
121 let lb = Rc::downgrade(self);
122 glib::timeout_add_local_once(delay, move || {
123 let Some(lb) = lb.upgrade() else {
124 return;
125 };
126 let remaining = lb
127 .chrome
128 .hide_at
129 .get()
130 .saturating_duration_since(Instant::now());
131 if !remaining.is_zero() {
132 lb.arm_chrome_hide(remaining);
133 return;
134 }
135 lb.chrome.armed.set(false);
136 if lb.ui.window.is_fullscreen() && !lb.chrome.hover.contains_pointer() {
137 lb.header.toolbar.set_reveal_top_bars(false);
138 }
139 });
140 }
141}