1
0
Fork 0
forked from wry/wry

config: clean up and document theming

This commit is contained in:
Julian Orth 2022-05-15 20:10:04 +02:00
parent 4780315f50
commit 6916f03e94
17 changed files with 745 additions and 285 deletions

View file

@ -9,7 +9,8 @@ use {
config::ConfigProxy,
ifs::wl_seat::{SeatId, WlSeatGlobal},
state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State},
tree::{ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase},
theme::{Color, ThemeSized, DEFAULT_FONT},
tree::{ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase, OutputNode},
utils::{
copyhashmap::CopyHashMap,
debug_fn::debug_fn,
@ -36,6 +37,7 @@ use {
InputDevice, Seat,
},
keyboard::{keymap::Keymap, mods::Modifiers, syms::KeySym},
theme::{colors::Colorable, sized::Resizable},
Axis, Direction, LogLevel, Workspace,
},
libloading::Library,
@ -742,18 +744,6 @@ impl ConfigProxyHandler {
Ok(())
}
fn handle_get_title_height(&self) {
self.respond(Response::GetTitleHeight {
height: self.state.theme.title_height.get(),
});
}
fn handle_get_border_width(&self) {
self.respond(Response::GetBorderWidth {
width: self.state.theme.border_width.get(),
});
}
fn handle_create_split(&self, seat: Seat, axis: Axis) -> Result<(), CphError> {
let seat = self.get_seat(seat)?;
seat.create_split(axis.into());
@ -775,15 +765,27 @@ impl ConfigProxyHandler {
self.state.backend.get().switch_to(vtnr);
}
fn handle_toggle_floating(&self, seat: Seat) -> Result<(), CphError> {
fn handle_get_floating(&self, seat: Seat) -> Result<(), CphError> {
let seat = self.get_seat(seat)?;
seat.toggle_floating();
self.respond(Response::GetFloating {
floating: seat.get_floating().unwrap_or(false),
});
Ok(())
}
fn handle_set_floating(&self, seat: Seat, floating: bool) -> Result<(), CphError> {
let seat = self.get_seat(seat)?;
seat.set_floating(floating);
Ok(())
}
fn spaces_change(&self) {
struct V;
impl NodeVisitorBase for V {
fn visit_output(&mut self, node: &Rc<OutputNode>) {
node.on_spaces_changed();
node.node_visit_children(self);
}
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
node.on_spaces_changed();
node.node_visit_children(self);
@ -796,7 +798,7 @@ impl ConfigProxyHandler {
self.state.root.clone().node_visit(&mut V);
}
fn colors_change(&self) {
fn colors_changed(&self) {
struct V;
impl NodeVisitorBase for V {
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
@ -811,45 +813,95 @@ impl ConfigProxyHandler {
self.state.root.clone().node_visit(&mut V);
}
fn handle_set_title_height(&self, height: i32) -> Result<(), CphError> {
if height < 0 {
return Err(CphError::NegativeTitleHeight(height));
fn get_sized(&self, sized: Resizable) -> Result<ThemeSized, CphError> {
use jay_config::theme::sized::*;
let sized = match sized {
TITLE_HEIGHT => ThemeSized::title_height,
BORDER_WIDTH => ThemeSized::border_width,
_ => return Err(CphError::UnknownSized(sized.0)),
};
Ok(sized)
}
fn handle_get_size(&self, sized: Resizable) -> Result<(), CphError> {
let sized = self.get_sized(sized)?;
let size = sized.field(&self.state.theme).get();
self.respond(Response::GetSize { size });
Ok(())
}
fn handle_set_size(&self, sized: Resizable, size: i32) -> Result<(), CphError> {
let sized = self.get_sized(sized)?;
if size < sized.min() {
return Err(CphError::InvalidSize(size, sized));
}
if height > 1000 {
return Err(CphError::ExcessiveTitleHeight(height));
if size > sized.max() {
return Err(CphError::InvalidSize(size, sized));
}
self.state.theme.title_height.set(height);
sized.field(&self.state.theme).set(size);
self.spaces_change();
Ok(())
}
fn handle_set_border_width(&self, width: i32) -> Result<(), CphError> {
if width < 0 {
return Err(CphError::NegativeBorderWidth(width));
}
if width > 1000 {
return Err(CphError::ExcessiveBorderWidth(width));
}
self.state.theme.border_width.set(width);
fn handle_reset_colors(&self) {
self.state.theme.colors.reset();
self.colors_changed();
}
fn handle_reset_sizes(&self) {
self.state.theme.sizes.reset();
self.spaces_change();
}
fn handle_reset_font(&self) {
*self.state.theme.font.borrow_mut() = DEFAULT_FONT.to_string();
}
fn handle_set_font(&self, font: &str) {
*self.state.theme.font.borrow_mut() = font.to_string();
}
fn handle_get_font(&self) {
let font = self.state.theme.font.borrow_mut().clone();
self.respond(Response::GetFont { font });
}
fn get_color(&self, colorable: Colorable) -> Result<&Cell<Color>, CphError> {
let colors = &self.state.theme.colors;
use jay_config::theme::colors::*;
let colorable = match colorable {
UNFOCUSED_TITLE_BACKGROUND_COLOR => &colors.unfocused_title_background,
FOCUSED_TITLE_BACKGROUND_COLOR => &colors.focused_title_background,
FOCUSED_INACTIVE_TITLE_BACKGROUND_COLOR => &colors.focused_inactive_title_background,
BACKGROUND_COLOR => &colors.background,
BAR_BACKGROUND_COLOR => &colors.bar_background,
SEPARATOR_COLOR => &colors.separator,
BORDER_COLOR => &colors.border,
UNFOCUSED_TITLE_TEXT_COLOR => &colors.unfocused_title_text,
FOCUSED_TITLE_TEXT_COLOR => &colors.focused_title_text,
FOCUSED_INACTIVE_TITLE_TEXT_COLOR => &colors.focused_inactive_title_text,
BAR_STATUS_TEXT_COLOR => &colors.bar_text,
_ => return Err(CphError::UnknownColor(colorable.0)),
};
Ok(colorable)
}
fn handle_get_color(&self, colorable: Colorable) -> Result<(), CphError> {
let color = self.get_color(colorable)?.get();
let color =
jay_config::theme::Color::new_f32_premultiplied(color.r, color.g, color.b, color.a);
self.respond(Response::GetColor { color });
Ok(())
}
fn handle_set_title_color(&self, color: jay_config::theme::Color) {
self.state.theme.title_color.set(color.into());
self.colors_change();
}
fn handle_set_border_color(&self, color: jay_config::theme::Color) {
self.state.theme.border_color.set(color.into());
}
fn handle_set_background_color(&self, color: jay_config::theme::Color) {
self.state.theme.background_color.set(color.into());
}
fn handle_set_title_underline_color(&self, color: jay_config::theme::Color) {
self.state.theme.underline_color.set(color.into());
fn handle_set_color(
&self,
colorable: Colorable,
color: jay_config::theme::Color,
) -> Result<(), CphError> {
self.get_color(colorable)?.set(color.into());
self.colors_changed();
Ok(())
}
pub fn handle_request(self: &Rc<Self>, msg: &[u8]) {
@ -914,29 +966,24 @@ impl ConfigProxyHandler {
self.handle_run(prog, args, env).wrn("run")?
}
ClientMessage::GrabKb { kb, grab } => self.handle_grab(kb, grab).wrn("grab")?,
ClientMessage::SetTitleHeight { height } => self
.handle_set_title_height(height)
.wrn("set_title_height")?,
ClientMessage::SetBorderWidth { width } => self
.handle_set_border_width(width)
.wrn("set_bordre_width")?,
ClientMessage::SetTitleColor { color } => self.handle_set_title_color(color),
ClientMessage::SetTitleUnderlineColor { color } => {
self.handle_set_title_underline_color(color)
ClientMessage::SetColor { colorable, color } => {
self.handle_set_color(colorable, color).wrn("set_color")?
}
ClientMessage::GetColor { colorable } => {
self.handle_get_color(colorable).wrn("get_color")?
}
ClientMessage::SetBorderColor { color } => self.handle_set_border_color(color),
ClientMessage::SetBackgroundColor { color } => self.handle_set_background_color(color),
ClientMessage::GetTitleHeight => self.handle_get_title_height(),
ClientMessage::GetBorderWidth => self.handle_get_border_width(),
ClientMessage::CreateSplit { seat, axis } => {
self.handle_create_split(seat, axis).wrn("create_split")?
}
ClientMessage::FocusParent { seat } => {
self.handle_focus_parent(seat).wrn("focus_parent")?
}
ClientMessage::ToggleFloating { seat } => {
self.handle_toggle_floating(seat).wrn("toggle_floating")?
ClientMessage::GetFloating { seat } => {
self.handle_get_floating(seat).wrn("get_floating")?
}
ClientMessage::SetFloating { seat, floating } => self
.handle_set_floating(seat, floating)
.wrn("set_floating")?,
ClientMessage::Quit => self.handle_quit(),
ClientMessage::SwitchTo { vtnr } => self.handle_switch_to(vtnr),
ClientMessage::HasCapability { device, cap } => self
@ -1019,6 +1066,15 @@ impl ConfigProxyHandler {
ClientMessage::GetDrmDevicePciId { device } => self
.handle_get_drm_device_pci_id(device)
.wrn("get_drm_device_pci_id")?,
ClientMessage::ResetColors => self.handle_reset_colors(),
ClientMessage::ResetSizes => self.handle_reset_sizes(),
ClientMessage::GetSize { sized } => self.handle_get_size(sized).wrn("get_size")?,
ClientMessage::SetSize { sized, size } => {
self.handle_set_size(sized, size).wrn("set_size")?
}
ClientMessage::ResetFont => self.handle_reset_font(),
ClientMessage::GetFont => self.handle_get_font(),
ClientMessage::SetFont { font } => self.handle_set_font(font),
}
Ok(())
}
@ -1030,14 +1086,8 @@ enum CphError {
UnknownAccelProfile(AccelProfile),
#[error("Queried unknown capability: {}", (.0).0)]
UnknownCapability(Capability),
#[error("The height {0} is negative")]
NegativeTitleHeight(i32),
#[error("The height {0} is larger than the maximum 1000")]
ExcessiveTitleHeight(i32),
#[error("The width {0} is negative")]
NegativeBorderWidth(i32),
#[error("The width {0} is larger than the maximum 1000")]
ExcessiveBorderWidth(i32),
#[error("The sized {0} is outside the valid range [{}, {}] for component {}", .1.min(), .1.max(), .1.name())]
InvalidSize(i32, ThemeSized),
#[error("The ol' forker is not available")]
NoForker,
#[error("Repeat rate is negative")]
@ -1066,6 +1116,10 @@ enum CphError {
WorkspaceDoesNotExist(Workspace),
#[error("Keyboard {0:?} does not exist")]
KeyboardDoesNotExist(InputDevice),
#[error("Colorable element {0} is not known")]
UnknownColor(u32),
#[error("Sized element {0} is not known")]
UnknownSized(u32),
#[error("Could not parse the message")]
ParsingFailed(#[source] DecodeError),
#[error("Could not process a `{0}` request")]

View file

@ -422,7 +422,14 @@ impl WlSeatGlobal {
}
}
pub fn toggle_floating(self: &Rc<Self>) {
pub fn get_floating(self: &Rc<Self>) -> Option<bool> {
match self.keyboard_node.get().node_toplevel() {
Some(tl) => Some(tl.tl_data().is_floating.get()),
_ => None,
}
}
pub fn set_floating(self: &Rc<Self>, floating: bool) {
let tl = match self.keyboard_node.get().node_toplevel() {
Some(tl) => tl,
_ => return,
@ -431,12 +438,15 @@ impl WlSeatGlobal {
if data.is_fullscreen.get() {
return;
}
if data.is_floating.get() == floating {
return;
}
let parent = match data.parent.get() {
Some(p) => p,
_ => return,
};
if let Some(cn) = parent.clone().node_into_containing_node() {
if parent.node_is_float() {
if let Some(cn) = parent.node_into_containing_node() {
if !floating {
cn.cnode_remove_child2(tl.tl_as_node(), true);
self.state.map_tiled(tl);
} else if let Some(ws) = data.workspace.get() {

View file

@ -21,14 +21,14 @@ async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
tassert_eq!(window.tl.width.get(), 800);
tassert_eq!(
window.tl.height.get(),
600 - 2 * (run.state.theme.title_height.get() + 1)
600 - 2 * (run.state.theme.sizes.title_height.get() + 1)
);
tassert_eq!(
window.tl.server.node_absolute_position(),
Rect::new_sized(
0,
2 * (run.state.theme.title_height.get() + 1),
2 * (run.state.theme.sizes.title_height.get() + 1),
window.tl.width.get(),
window.tl.height.get(),
)

View file

@ -21,8 +21,8 @@ async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
let window2 = client.create_window().await?;
window2.map().await?;
let otop = 2 * (run.state.theme.title_height.get() + 1);
let bw = run.state.theme.border_width.get();
let otop = 2 * (run.state.theme.sizes.title_height.get() + 1);
let bw = run.state.theme.sizes.border_width.get();
tassert_eq!(
window.tl.server.node_absolute_position(),

View file

@ -108,7 +108,7 @@ impl Framebuffer {
result: &mut RenderResult,
) {
let _ = self.ctx.ctx.with_current(|| {
let c = state.theme.background_color.get();
let c = state.theme.colors.background.get();
unsafe {
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
glViewport(0, 0, self.gl.width, self.gl.height);

View file

@ -95,9 +95,9 @@ impl Renderer<'_> {
render_layer!(output.layers[0]);
render_layer!(output.layers[1]);
let theme = &self.state.theme;
let th = theme.title_height.get();
let th = theme.sizes.title_height.get();
{
let c = Color::BLACK;
let c = theme.colors.bar_background.get();
self.fill_boxes2(
slice::from_ref(&Rect::new_sized(0, 0, opos.width(), th).unwrap()),
&c,
@ -106,12 +106,12 @@ impl Renderer<'_> {
);
let rd = output.render_data.borrow_mut();
if let Some(aw) = &rd.active_workspace {
let c = theme.active_title_color.get();
let c = theme.colors.focused_title_background.get();
self.fill_boxes2(slice::from_ref(aw), &c, x, y);
}
let c = theme.underline_color.get();
let c = theme.colors.separator.get();
self.fill_boxes2(slice::from_ref(&rd.underline), &c, x, y);
let c = theme.title_color.get();
let c = theme.colors.unfocused_title_background.get();
self.fill_boxes2(&rd.inactive_workspaces, &c, x, y);
for title in &rd.titles {
self.render_texture(&title.tex, x + title.x, y + title.y, ARGB8888);
@ -208,16 +208,21 @@ impl Renderer<'_> {
pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) {
{
let rd = container.render_data.borrow_mut();
let c = self.state.theme.title_color.get();
let c = self.state.theme.colors.unfocused_title_background.get();
self.fill_boxes2(&rd.title_rects, &c, x, y);
let c = self.state.theme.active_title_color.get();
let c = self.state.theme.colors.focused_title_background.get();
self.fill_boxes2(&rd.active_title_rects, &c, x, y);
let c = self.state.theme.underline_color.get();
let c = self.state.theme.colors.separator.get();
self.fill_boxes2(&rd.underline_rects, &c, x, y);
let c = self.state.theme.border_color.get();
let c = self.state.theme.colors.border.get();
self.fill_boxes2(&rd.border_rects, &c, x, y);
if let Some(lar) = &rd.last_active_rect {
let c = self.state.theme.last_active_color.get();
let c = self
.state
.theme
.colors
.focused_inactive_title_background
.get();
self.fill_boxes2(std::slice::from_ref(lar), &c, x, y);
}
for title in &rd.titles {
@ -379,14 +384,14 @@ impl Renderer<'_> {
};
let pos = floating.position.get();
let theme = &self.state.theme;
let th = theme.title_height.get();
let bw = theme.border_width.get();
let bc = theme.border_color.get();
let th = theme.sizes.title_height.get();
let bw = theme.sizes.border_width.get();
let bc = theme.colors.border.get();
let tc = match floating.active.get() {
true => theme.active_title_color.get(),
false => theme.title_color.get(),
true => theme.colors.focused_title_background.get(),
false => theme.colors.unfocused_title_background.get(),
};
let uc = theme.underline_color.get();
let uc = theme.colors.separator.get();
let borders = [
Rect::new_sized(x, y, pos.width(), bw).unwrap(),
Rect::new_sized(x, y + bw, bw, pos.height() - bw).unwrap(),

View file

@ -345,8 +345,8 @@ impl State {
workspace: &Rc<WorkspaceNode>,
) {
node.clone().tl_set_workspace(workspace);
width += 2 * self.theme.border_width.get();
height += 2 * self.theme.border_width.get() + self.theme.title_height.get();
width += 2 * self.theme.sizes.border_width.get();
height += 2 * self.theme.sizes.border_width.get() + self.theme.sizes.title_height.get();
let output = workspace.output.get();
let output_rect = output.global.pos.get();
let position = {

View file

@ -89,7 +89,7 @@ pub fn render(
render2(ctx, 1, width, height, 1, font, text, color, true, false)
}
pub fn render2(
fn render2(
ctx: &Rc<RenderContext>,
x: i32,
width: i32,

View file

@ -8,22 +8,6 @@ pub struct Color {
pub a: f32,
}
impl Color {
pub const GREY: Self = Self {
r: 0.8,
g: 0.8,
b: 0.8,
a: 1.0,
};
pub const BLACK: Self = Self {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
};
}
fn to_f32(c: u8) -> f32 {
c as f32 / 255f32
}
@ -33,6 +17,15 @@ fn to_u8(c: f32) -> u8 {
}
impl Color {
pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
Self {
r: to_f32(r),
g: to_f32(g),
b: to_f32(b),
a: 1.0,
}
}
pub fn from_rgba_straight(r: u8, g: u8, b: u8, a: u8) -> Self {
let alpha = to_f32(a);
Self {
@ -51,39 +44,145 @@ impl Color {
impl From<jay_config::theme::Color> for Color {
fn from(f: jay_config::theme::Color) -> Self {
Self {
r: to_f32(f.r),
g: to_f32(f.g),
b: to_f32(f.b),
a: to_f32(f.a),
let [r, g, b, a] = f.to_f32_premultiplied();
Self { r, g, b, a }
}
}
macro_rules! colors {
($($name:ident = ($r:expr, $g:expr, $b:expr),)*) => {
pub struct ThemeColors {
$(
pub $name: Cell<Color>,
)*
}
impl ThemeColors {
pub fn reset(&self) {
let default = Self::default();
$(
self.$name.set(default.$name.get());
)*
}
}
impl Default for ThemeColors {
fn default() -> Self {
Self {
$(
$name: Cell::new(Color::from_rgb($r, $g, $b)),
)*
}
}
}
}
}
colors! {
background = (0x00, 0x10, 0x19),
unfocused_title_background = (0x22, 0x22, 0x22),
focused_title_background = (0x28, 0x55, 0x77),
focused_inactive_title_background = (0x5f, 0x67, 0x6a),
unfocused_title_text = (0x88, 0x88, 0x88),
focused_title_text = (0xff, 0xff, 0xff),
focused_inactive_title_text = (0xff, 0xff, 0xff),
separator = (0x33, 0x33, 0x33),
border = (0x3f, 0x47, 0x4a),
bar_background = (0x00, 0x00, 0x00),
bar_text = (0xff, 0xff, 0xff),
}
macro_rules! sizes {
($($name:ident = ($min:expr, $max:expr, $def:expr),)*) => {
pub struct ThemeSizes {
$(
pub $name: Cell<i32>,
)*
}
#[derive(Copy, Clone, Debug)]
#[allow(non_camel_case_types)]
pub enum ThemeSized {
$(
$name,
)*
}
impl ThemeSized {
pub fn min(self) -> i32 {
match self {
$(
Self::$name => $min,
)*
}
}
pub fn max(self) -> i32 {
match self {
$(
Self::$name => $max,
)*
}
}
pub fn field(self, theme: &Theme) -> &Cell<i32> {
let sizes = &theme.sizes;
match self {
$(
Self::$name => &sizes.$name,
)*
}
}
pub fn name(self) -> &'static str {
match self {
$(
Self::$name => stringify!($name),
)*
}
}
}
impl ThemeSizes {
pub fn reset(&self) {
let default = Self::default();
$(
self.$name.set(default.$name.get());
)*
}
}
impl Default for ThemeSizes {
fn default() -> Self {
Self {
$(
$name: Cell::new($def),
)*
}
}
}
}
}
sizes! {
title_height = (1, 1000, 17),
border_width = (1, 1000, 4),
}
pub const DEFAULT_FONT: &str = "monospace 8";
pub struct Theme {
pub background_color: Cell<Color>,
pub title_color: Cell<Color>,
pub active_title_color: Cell<Color>,
pub underline_color: Cell<Color>,
pub border_color: Cell<Color>,
pub last_active_color: Cell<Color>,
pub title_height: Cell<i32>,
pub border_width: Cell<i32>,
pub colors: ThemeColors,
pub sizes: ThemeSizes,
pub font: RefCell<String>,
}
impl Default for Theme {
fn default() -> Self {
Self {
background_color: Cell::new(Color::from_rgba_straight(0x00, 0x10, 0x19, 255)),
last_active_color: Cell::new(Color::from_rgba_straight(0x5f, 0x67, 0x6a, 255)),
title_color: Cell::new(Color::from_rgba_straight(0x22, 0x22, 0x22, 255)),
active_title_color: Cell::new(Color::from_rgba_straight(0x28, 0x55, 0x77, 255)),
underline_color: Cell::new(Color::from_rgba_straight(0x33, 0x33, 0x33, 255)),
border_color: Cell::new(Color::from_rgba_straight(0x3f, 0x47, 0x4a, 255)),
title_height: Cell::new(17),
border_width: Cell::new(4),
font: RefCell::new("monospace 8".to_string()),
colors: Default::default(),
sizes: Default::default(),
font: RefCell::new(DEFAULT_FONT.to_string()),
}
}
}

View file

@ -11,7 +11,6 @@ use {
render::{Renderer, Texture},
state::State,
text,
theme::Color,
tree::{
walker::NodeVisitor, ContainingNode, FindTreeResult, FoundNode, Node, NodeId,
ToplevelData, ToplevelNode, WorkspaceNode,
@ -26,7 +25,6 @@ use {
},
},
ahash::AHashMap,
isnt::std_1::vec::IsntVecExt,
jay_config::{Axis, Direction},
smallvec::SmallVec,
std::{
@ -368,8 +366,8 @@ impl ContainerNode {
self.mono_content
.set(child.content.get().at_point(mb.x1(), mb.y1()));
let th = self.state.theme.title_height.get();
let bw = self.state.theme.border_width.get();
let th = self.state.theme.sizes.title_height.get();
let bw = self.state.theme.sizes.border_width.get();
let num_children = self.num_children.get() as i32;
let content_width = self.width.get().sub(bw * (num_children - 1)).max(0);
let width_per_child = content_width / num_children;
@ -390,8 +388,8 @@ impl ContainerNode {
fn perform_split_layout(self: &Rc<Self>) {
let sum_factors = self.sum_factors.get();
let border_width = self.state.theme.border_width.get();
let title_height = self.state.theme.title_height.get();
let border_width = self.state.theme.sizes.border_width.get();
let title_height = self.state.theme.sizes.title_height.get();
let split = self.split.get();
let (content_size, other_content_size) = match split {
ContainerSplit::Horizontal => (self.content_width.get(), self.content_height.get()),
@ -476,8 +474,8 @@ impl ContainerNode {
}
fn update_content_size(&self) {
let border_width = self.state.theme.border_width.get();
let title_height = self.state.theme.title_height.get();
let border_width = self.state.theme.sizes.border_width.get();
let title_height = self.state.theme.sizes.title_height.get();
let nc = self.num_children.get();
match self.split.get() {
ContainerSplit::Horizontal => {
@ -508,7 +506,7 @@ impl ContainerNode {
}
fn pointer_move(self: &Rc<Self>, seat: &Rc<WlSeatGlobal>, mut x: i32, mut y: i32) {
let title_height = self.state.theme.title_height.get();
let title_height = self.state.theme.sizes.title_height.get();
let mut seats = self.seats.borrow_mut();
let seat_state = seats.entry(seat.id()).or_insert_with(|| SeatState {
cursor: KnownCursor::Default,
@ -630,8 +628,8 @@ impl ContainerNode {
let mut rd = self.render_data.borrow_mut();
let rd = rd.deref_mut();
let theme = &self.state.theme;
let th = theme.title_height.get();
let bw = theme.border_width.get();
let th = theme.sizes.title_height.get();
let bw = theme.sizes.border_width.get();
let font = theme.font.borrow_mut();
let cwidth = self.width.get();
let cheight = self.height.get();
@ -641,9 +639,11 @@ impl ContainerNode {
rd.active_title_rects.clear();
rd.border_rects.clear();
rd.underline_rects.clear();
rd.last_active_rect.take();
let last_active = self.focus_history.last().map(|v| v.node.node_id());
let mono = self.mono_child.get().is_some();
let split = self.split.get();
let have_active = self.children.iter().any(|c| c.active.get());
for (i, child) in self.children.iter().enumerate() {
let rect = child.title_rect.get();
if i > 0 {
@ -656,14 +656,16 @@ impl ContainerNode {
};
rd.border_rects.push(rect.unwrap());
}
if child.active.get() {
let color = if child.active.get() {
rd.active_title_rects.push(rect);
theme.colors.focused_title_text.get()
} else if !have_active && last_active == Some(child.node.node_id()) {
rd.last_active_rect = Some(rect);
theme.colors.focused_inactive_title_text.get()
} else {
rd.title_rects.push(rect);
}
if last_active == Some(child.node.node_id()) {
rd.last_active_rect = Some(rect);
}
theme.colors.unfocused_title_text.get()
};
if !mono {
let rect = Rect::new_sized(rect.x1(), rect.y2(), rect.width(), 1).unwrap();
rd.underline_rects.push(rect);
@ -674,7 +676,7 @@ impl ContainerNode {
break 'render_title;
}
if let Some(ctx) = &ctx {
match text::render(ctx, rect.width(), th, &font, title.deref(), Color::GREY) {
match text::render(ctx, rect.width(), th, &font, title.deref(), color) {
Ok(t) => rd.titles.push(ContainerTitle {
x: rect.x1(),
y: rect.y1(),
@ -691,9 +693,6 @@ impl ContainerNode {
rd.underline_rects
.push(Rect::new_sized(0, th, cwidth, 1).unwrap());
}
if rd.active_title_rects.is_not_empty() {
rd.last_active_rect.take();
}
}
fn activate_child(self: &Rc<Self>, child: &NodeRef<ContainerChild>) {
@ -1151,7 +1150,7 @@ impl Node for ContainerNode {
Some(s) => s,
_ => return,
};
if seat_data.y > self.state.theme.title_height.get() {
if seat_data.y > self.state.theme.sizes.title_height.get() {
return;
}
let cur_mc = match self.mono_child.get() {

View file

@ -8,7 +8,6 @@ use {
render::{Renderer, Texture},
state::State,
text,
theme::Color,
tree::{
walker::NodeVisitor, ContainingNode, FindTreeResult, FoundNode, Node, NodeId,
StackedNode, ToplevelNode, WorkspaceNode,
@ -144,8 +143,8 @@ impl FloatNode {
};
let pos = self.position.get();
let theme = &self.state.theme;
let bw = theme.border_width.get();
let th = theme.title_height.get();
let bw = theme.sizes.border_width.get();
let th = theme.sizes.title_height.get();
let cpos = Rect::new_sized(
pos.x1() + bw,
pos.y1() + bw + th + 1,
@ -167,8 +166,12 @@ impl FloatNode {
fn render_title(&self) {
self.render_titles_scheduled.set(false);
let theme = &self.state.theme;
let th = theme.title_height.get();
let bw = theme.border_width.get();
let th = theme.sizes.title_height.get();
let tc = match self.active.get() {
true => theme.colors.focused_title_text.get(),
false => theme.colors.unfocused_title_text.get(),
};
let bw = theme.sizes.border_width.get();
let font = theme.font.borrow_mut();
let title = self.title.borrow_mut();
self.title_texture.set(None);
@ -180,8 +183,7 @@ impl FloatNode {
Some(c) => c,
_ => return,
};
let texture = match text::render(&ctx, pos.width() - 2 * bw, th, &font, &title, Color::GREY)
{
let texture = match text::render(&ctx, pos.width() - 2 * bw, th, &font, &title, tc) {
Ok(t) => t,
Err(e) => {
log::error!("Could not render title {}: {}", title, ErrorFmt(e));
@ -193,8 +195,8 @@ impl FloatNode {
fn pointer_move(self: &Rc<Self>, seat: &Rc<WlSeatGlobal>, x: i32, y: i32) {
let theme = &self.state.theme;
let bw = theme.border_width.get();
let th = theme.title_height.get();
let bw = theme.sizes.border_width.get();
let th = theme.sizes.title_height.get();
let mut seats = self.seats.borrow_mut();
let seat_state = seats.entry(seat.id()).or_insert_with(|| SeatState {
cursor: KnownCursor::Default,
@ -370,8 +372,8 @@ impl Node for FloatNode {
fn node_find_tree_at(&self, x: i32, y: i32, tree: &mut Vec<FoundNode>) -> FindTreeResult {
let theme = &self.state.theme;
let th = theme.title_height.get();
let bw = theme.border_width.get();
let th = theme.sizes.title_height.get();
let bw = theme.sizes.border_width.get();
let pos = self.position.get();
if x < bw || x >= pos.width() - bw {
return FindTreeResult::AcceptsInput;

View file

@ -12,7 +12,6 @@ use {
render::{Renderer, Texture},
state::State,
text,
theme::Color,
tree::{walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode},
utils::{
clonecell::CloneCell, errorfmt::ErrorFmt, linkedlist::LinkedList, scroller::Scroller,
@ -53,6 +52,13 @@ impl OutputNode {
}
}
pub fn on_spaces_changed(self: &Rc<Self>) {
self.update_render_data();
if let Some(c) = self.workspace.get() {
c.change_extents(&self.workspace_rect());
}
}
pub fn update_render_data(&self) {
let mut rd = self.render_data.borrow_mut();
rd.titles.clear();
@ -61,7 +67,8 @@ impl OutputNode {
rd.status = None;
let mut pos = 0;
let font = self.state.theme.font.borrow_mut();
let th = self.state.theme.title_height.get();
let theme = &self.state.theme;
let th = theme.sizes.title_height.get();
let active_id = self.workspace.get().map(|w| w.id);
let width = self.global.pos.get().width();
rd.underline = Rect::new_sized(0, th, width, 1).unwrap();
@ -72,14 +79,17 @@ impl OutputNode {
if th == 0 || ws.name.is_empty() {
break 'create_texture;
}
let title =
match text::render_fitting(&ctx, th, &font, &ws.name, Color::GREY, false) {
Ok(t) => t,
Err(e) => {
log::error!("Could not render title {}: {}", ws.name, ErrorFmt(e));
break 'create_texture;
}
};
let tc = match active_id == Some(ws.id) {
true => theme.colors.focused_title_text.get(),
false => theme.colors.unfocused_title_text.get(),
};
let title = match text::render_fitting(&ctx, th, &font, &ws.name, tc, false) {
Ok(t) => t,
Err(e) => {
log::error!("Could not render title {}: {}", ws.name, ErrorFmt(e));
break 'create_texture;
}
};
let mut x = pos + 1;
if title.width() + 2 > title_width {
title_width = title.width() + 2;
@ -110,7 +120,8 @@ impl OutputNode {
if status.is_empty() {
break 'set_status;
}
let title = match text::render_fitting(&ctx, th, &font, &status, Color::GREY, true) {
let tc = self.state.theme.colors.bar_text.get();
let title = match text::render_fitting(&ctx, th, &font, &status, tc, true) {
Ok(t) => t,
Err(e) => {
log::error!("Could not render status {}: {}", status, ErrorFmt(e));
@ -205,7 +216,7 @@ impl OutputNode {
fn workspace_rect(&self) -> Rect {
let rect = self.global.pos.get();
let th = self.state.theme.title_height.get();
let th = self.state.theme.sizes.title_height.get();
Rect::new_sized(
rect.x1(),
rect.y1() + th + 1,
@ -384,7 +395,7 @@ impl Node for OutputNode {
}
}
}
let bar_height = self.state.theme.title_height.get() + 1;
let bar_height = self.state.theme.sizes.title_height.get() + 1;
if y >= bar_height {
y -= bar_height;
let len = tree.len();

View file

@ -8,7 +8,6 @@ use {
render::{Renderer, Texture},
state::State,
text,
theme::Color,
tree::{FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData, ToplevelNode},
utils::{clonecell::CloneCell, errorfmt::ErrorFmt},
},
@ -54,7 +53,7 @@ impl PlaceholderNode {
rect.height(),
&font,
"Fullscreen",
Color::GREY,
self.toplevel.state.theme.colors.unfocused_title_text.get(),
false,
) {
Ok(t) => {