Skip to content

Commit 1f27a90

Browse files
committed
Add ability to hide titlebar, and draw only the frame
1 parent f5401f6 commit 1f27a90

File tree

2 files changed

+114
-35
lines changed

2 files changed

+114
-35
lines changed

src/lib.rs

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ pub struct AdwaitaFrame<State> {
8989
title: Option<String>,
9090
title_text: Option<TitleText>,
9191
shadow: Shadow,
92+
93+
/// Draw decorations but without the titlebar
94+
hide_titlebar: bool,
9295
}
9396

9497
impl<State> AdwaitaFrame<State>
@@ -111,6 +114,7 @@ where
111114
&base_surface,
112115
&subcompositor,
113116
&queue_handle,
117+
frame_config.hide_titlebar,
114118
));
115119

116120
let theme = frame_config.theme;
@@ -134,6 +138,7 @@ where
134138
wm_capabilities: WindowManagerCapabilities::all(),
135139
resizable: true,
136140
shadow: Shadow::default(),
141+
hide_titlebar: frame_config.hide_titlebar,
137142
})
138143
}
139144

@@ -210,6 +215,12 @@ where
210215
if self.state.contains(WindowState::FULLSCREEN) {
211216
decorations.hide();
212217
return Some(true);
218+
} else {
219+
decorations.show();
220+
}
221+
222+
if self.hide_titlebar {
223+
decorations.hide_titlebar();
213224
}
214225

215226
let colors = if self.state.contains(WindowState::ACTIVATED) {
@@ -228,10 +239,7 @@ where
228239
let border_paint = colors.border_paint();
229240

230241
// Draw the borders.
231-
for (idx, part) in decorations
232-
.parts()
233-
.filter(|(idx, _)| *idx == DecorationParts::HEADER || draw_borders)
234-
{
242+
for (idx, part) in decorations.parts().filter(|(_, part)| !part.hide) {
235243
let scale = self.scale_factor;
236244

237245
let mut rect = part.surface_rect;
@@ -329,6 +337,21 @@ where
329337
visible_border_size as f32,
330338
)
331339
}
340+
// Unless titlebar is disabled
341+
DecorationParts::TOP if self.hide_titlebar => {
342+
let x = rect.x.unsigned_abs() * scale;
343+
let x = x.saturating_sub(visible_border_size);
344+
345+
let y = rect.y.unsigned_abs() * scale;
346+
let y = y.saturating_sub(visible_border_size);
347+
348+
Rect::from_xywh(
349+
x as f32,
350+
y as f32,
351+
(rect.width - 2 * x) as f32,
352+
visible_border_size as f32,
353+
)
354+
}
332355
_ => None,
333356
};
334357

@@ -407,6 +430,7 @@ where
407430
&self.base_surface,
408431
&self.subcompositor,
409432
&self.queue_handle,
433+
self.hide_titlebar,
410434
));
411435
self.dirty = true;
412436
self.should_sync = true;
@@ -440,7 +464,10 @@ where
440464
width: NonZeroU32,
441465
height: NonZeroU32,
442466
) -> (Option<NonZeroU32>, Option<NonZeroU32>) {
443-
if self.decorations.is_none() || self.state.contains(WindowState::FULLSCREEN) {
467+
if self.decorations.is_none()
468+
|| self.state.contains(WindowState::FULLSCREEN)
469+
|| self.hide_titlebar
470+
{
444471
(Some(width), Some(height))
445472
} else {
446473
(
@@ -451,15 +478,21 @@ where
451478
}
452479

453480
fn add_borders(&self, width: u32, height: u32) -> (u32, u32) {
454-
if self.decorations.is_none() || self.state.contains(WindowState::FULLSCREEN) {
481+
if self.decorations.is_none()
482+
|| self.state.contains(WindowState::FULLSCREEN)
483+
|| self.hide_titlebar
484+
{
455485
(width, height)
456486
} else {
457487
(width, height + HEADER_SIZE)
458488
}
459489
}
460490

461491
fn location(&self) -> (i32, i32) {
462-
if self.decorations.is_none() || self.state.contains(WindowState::FULLSCREEN) {
492+
if self.decorations.is_none()
493+
|| self.state.contains(WindowState::FULLSCREEN)
494+
|| self.hide_titlebar
495+
{
463496
(0, 0)
464497
} else {
465498
(0, -(HEADER_SIZE as i32))
@@ -545,39 +578,44 @@ where
545578
#[derive(Debug, Clone)]
546579
pub struct FrameConfig {
547580
pub theme: ColorTheme,
581+
/// Draw decorations but without the titlebar
582+
pub hide_titlebar: bool,
548583
}
549584

550585
impl FrameConfig {
551586
/// Create the new configuration with the given `theme`.
552587
pub fn new(theme: ColorTheme) -> Self {
553-
Self { theme }
588+
Self {
589+
theme,
590+
hide_titlebar: false,
591+
}
554592
}
555593

556594
/// This is equivalent of calling `FrameConfig::new(ColorTheme::auto())`.
557595
///
558596
/// For details see [`ColorTheme::auto`].
559597
pub fn auto() -> Self {
560-
Self {
561-
theme: ColorTheme::auto(),
562-
}
598+
Self::new(ColorTheme::auto())
563599
}
564600

565601
/// This is equivalent of calling `FrameConfig::new(ColorTheme::light())`.
566602
///
567603
/// For details see [`ColorTheme::light`].
568604
pub fn light() -> Self {
569-
Self {
570-
theme: ColorTheme::light(),
571-
}
605+
Self::new(ColorTheme::light())
572606
}
573607

574608
/// This is equivalent of calling `FrameConfig::new(ColorTheme::dark())`.
575609
///
576610
/// For details see [`ColorTheme::dark`].
577611
pub fn dark() -> Self {
578-
Self {
579-
theme: ColorTheme::dark(),
580-
}
612+
Self::new(ColorTheme::dark())
613+
}
614+
615+
/// Draw decorations but without the titlebar
616+
pub fn hide_titlebar(mut self, hide: bool) -> Self {
617+
self.hide_titlebar = hide;
618+
self
581619
}
582620
}
583621

src/parts.rs

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::{pointer::Location, wl_typed::WlTyped};
1616
#[derive(Debug)]
1717
pub struct DecorationParts {
1818
parts: [Part; 5],
19+
hide_titlebar: bool,
1920
}
2021

2122
impl DecorationParts {
@@ -32,10 +33,13 @@ impl DecorationParts {
3233
base_surface: &WlTyped<WlSurface, SurfaceData>,
3334
subcompositor: &SubcompositorState,
3435
queue_handle: &QueueHandle<State>,
36+
hide_titlebar: bool,
3537
) -> Self
3638
where
3739
State: Dispatch<WlSurface, SurfaceData> + Dispatch<WlSubsurface, SubsurfaceData> + 'static,
3840
{
41+
let header_offset = if hide_titlebar { 0 } else { HEADER_SIZE };
42+
3943
// XXX the order must be in sync with associated constants.
4044
let parts = [
4145
// Top.
@@ -45,7 +49,7 @@ impl DecorationParts {
4549
queue_handle,
4650
Rect {
4751
x: -(BORDER_SIZE as i32),
48-
y: -(HEADER_SIZE as i32 + BORDER_SIZE as i32),
52+
y: -(header_offset as i32 + BORDER_SIZE as i32),
4953
width: 0, // Defined by `Self::resize`.
5054
height: BORDER_SIZE,
5155
},
@@ -63,7 +67,7 @@ impl DecorationParts {
6367
queue_handle,
6468
Rect {
6569
x: -(BORDER_SIZE as i32),
66-
y: -(HEADER_SIZE as i32),
70+
y: -(header_offset as i32),
6771
width: BORDER_SIZE,
6872
height: 0, // Defined by `Self::resize`.
6973
},
@@ -81,7 +85,7 @@ impl DecorationParts {
8185
queue_handle,
8286
Rect {
8387
x: 0, // Defined by `Self::resize`.
84-
y: -(HEADER_SIZE as i32),
88+
y: -(header_offset as i32),
8589
width: BORDER_SIZE,
8690
height: 0, // Defined by `Self::resize`.
8791
},
@@ -125,32 +129,72 @@ impl DecorationParts {
125129
),
126130
];
127131

128-
Self { parts }
132+
Self {
133+
parts,
134+
hide_titlebar,
135+
}
129136
}
130137

131138
pub fn parts(&self) -> std::iter::Enumerate<std::slice::Iter<Part>> {
132139
self.parts.iter().enumerate()
133140
}
134141

135-
pub fn hide(&self) {
136-
for part in self.parts.iter() {
142+
pub fn parts_mut(&mut self) -> std::iter::Enumerate<std::slice::IterMut<Part>> {
143+
self.parts.iter_mut().enumerate()
144+
}
145+
146+
pub fn borders_mut(&mut self) -> impl Iterator<Item = &mut Part> {
147+
self.parts_mut()
148+
.filter(|(idx, _)| *idx != Self::HEADER)
149+
.map(|(_, p)| p)
150+
}
151+
152+
pub fn header(&self) -> &Part {
153+
&self.parts[Self::HEADER]
154+
}
155+
156+
pub fn header_mut(&mut self) -> &mut Part {
157+
&mut self.parts[Self::HEADER]
158+
}
159+
160+
pub fn hide(&mut self) {
161+
for part in self.parts.iter_mut() {
162+
part.hide = true;
137163
part.subsurface.set_sync();
138164
part.surface.attach(None, 0, 0);
139165
part.surface.commit();
140166
}
141167
}
142168

143-
pub fn hide_borders(&self) {
144-
for (_, part) in self.parts().filter(|(idx, _)| *idx != Self::HEADER) {
169+
pub fn show(&mut self) {
170+
for part in self.parts.iter_mut() {
171+
part.hide = false;
172+
}
173+
}
174+
175+
pub fn hide_borders(&mut self) {
176+
for part in self.borders_mut() {
177+
part.hide = true;
145178
part.surface.attach(None, 0, 0);
146179
part.surface.commit();
147180
}
148181
}
149182

183+
pub fn hide_titlebar(&mut self) {
184+
let part = self.header_mut();
185+
part.hide = true;
186+
part.surface.attach(None, 0, 0);
187+
part.surface.commit();
188+
}
189+
150190
// These unwraps are guaranteed to succeed because the affected options are filled above
151191
// and then never emptied afterwards.
152192
#[allow(clippy::unwrap_used)]
153193
pub fn resize(&mut self, width: u32, height: u32) {
194+
let header_size = if self.hide_titlebar { 0 } else { HEADER_SIZE };
195+
196+
let height_with_header = height + header_size;
197+
154198
self.parts[Self::HEADER].surface_rect.width = width;
155199

156200
self.parts[Self::BOTTOM].surface_rect.width = width + 2 * BORDER_SIZE;
@@ -163,18 +207,12 @@ impl DecorationParts {
163207
self.parts[Self::TOP].input_rect.as_mut().unwrap().width =
164208
self.parts[Self::TOP].surface_rect.width - (BORDER_SIZE * 2) + (RESIZE_HANDLE_SIZE * 2);
165209

166-
self.parts[Self::LEFT].surface_rect.height = height + HEADER_SIZE;
167-
self.parts[Self::LEFT].input_rect.as_mut().unwrap().height =
168-
self.parts[Self::LEFT].surface_rect.height;
210+
self.parts[Self::LEFT].surface_rect.height = height_with_header;
211+
self.parts[Self::LEFT].input_rect.as_mut().unwrap().height = height_with_header;
169212

170-
self.parts[Self::RIGHT].surface_rect.height = self.parts[Self::LEFT].surface_rect.height;
213+
self.parts[Self::RIGHT].surface_rect.height = height_with_header;
171214
self.parts[Self::RIGHT].surface_rect.x = width as i32;
172-
self.parts[Self::RIGHT].input_rect.as_mut().unwrap().height =
173-
self.parts[Self::RIGHT].surface_rect.height;
174-
}
175-
176-
pub fn header(&self) -> &Part {
177-
&self.parts[Self::HEADER]
215+
self.parts[Self::RIGHT].input_rect.as_mut().unwrap().height = height_with_header;
178216
}
179217

180218
pub fn side_height(&self) -> u32 {
@@ -221,6 +259,8 @@ pub struct Part {
221259
///
222260
/// `None` if it fully covers `surface_rect`.
223261
pub input_rect: Option<Rect>,
262+
263+
pub hide: bool,
224264
}
225265

226266
impl Part {
@@ -248,6 +288,7 @@ impl Part {
248288
subsurface,
249289
surface_rect,
250290
input_rect,
291+
hide: false,
251292
}
252293
}
253294
}

0 commit comments

Comments
 (0)