Skip to content

Commit ccd9892

Browse files
Font configuration
1 parent b179508 commit ccd9892

7 files changed

Lines changed: 179 additions & 9 deletions

File tree

Cargo.lock

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repository = "https://github.com/WhatAmISupposedToPutHere/tiny-dfr"
1010
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1111

1212
[dependencies]
13-
cairo-rs = { version = "0.18", default-features = false }
13+
cairo-rs = { version = "0.18", default-features = false, features = ["freetype"] }
1414
librsvg = "2.56.0"
1515
drm = "0.10.0"
1616
anyhow = "1"
@@ -23,3 +23,7 @@ privdrop = "0.5.3"
2323
serde = { version = "1", features = ["derive"] }
2424
toml = "0.8"
2525
rand = "0.8"
26+
freetype-rs = "0.32"
27+
28+
[build-dependencies]
29+
pkg-config = "0.3"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ The most basic dynamic function row daemon possible
33

44

55
## Dependencies
6-
pango, libinput, uinput enabled in kernel config
6+
cairo, libinput, freetype, fontconfig, uinput enabled in kernel config
77

88
## License
99

build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
pkg_config::probe_library("fontconfig").unwrap();
3+
}

share/tiny-dfr/config.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,12 @@ ShowButtonOutlines = true
1414
# In theory this helps with screen longevity, but macos does not bother doint it
1515
# Disabling ShowButtonOutlines will make this effect less noticeable to the eye
1616
EnablePixelShift = false
17+
18+
# Set this to the fontconfig pattern to be used to pick a font for text labels
19+
# Some examples are:
20+
# "" - default regular sans-serif font
21+
# ":bold" - default regular sans-serif font
22+
# For full reference on accepted values see the fontconfig user guide,
23+
# section "Font Names"
24+
# https://www.freedesktop.org/software/fontconfig/fontconfig-user.html
25+
FontTemplate = ":bold"

src/fonts.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
use std::ffi::{c_char, c_int, CStr, CString};
2+
use std::ptr;
3+
4+
#[repr(C)]
5+
struct FcPattern {
6+
_data: [u8; 0]
7+
}
8+
#[repr(C)]
9+
struct FcConfig {
10+
_data: [u8; 0]
11+
}
12+
type FcResult = c_int;
13+
type FcMatchKind = c_int;
14+
#[allow(non_upper_case_globals)]
15+
const FcMatchPattern: FcMatchKind = 0;
16+
17+
pub struct FontConfig {
18+
config: *const FcConfig
19+
}
20+
21+
impl FontConfig {
22+
pub fn new() -> FontConfig {
23+
let config = unsafe {
24+
FcInitLoadConfigAndFonts()
25+
};
26+
FontConfig {
27+
config
28+
}
29+
}
30+
pub fn match_pattern(&self, pattern: &Pattern) -> Pattern {
31+
let mut result: FcResult = 0;
32+
let match_ = unsafe {
33+
FcFontMatch(self.config, pattern.pattern, &mut result)
34+
};
35+
Pattern {
36+
pattern: match_
37+
}
38+
}
39+
pub fn perform_substitutions(&self, pattern: &mut Pattern) {
40+
unsafe {
41+
FcConfigSubstitute(self.config, pattern.pattern, FcMatchPattern);
42+
FcDefaultSubstitute(pattern.pattern);
43+
}
44+
}
45+
}
46+
47+
impl Drop for FontConfig {
48+
fn drop(&mut self) {
49+
unsafe {
50+
FcConfigDestroy(self.config)
51+
}
52+
}
53+
}
54+
55+
pub struct Pattern {
56+
pattern: *const FcPattern
57+
}
58+
59+
impl Pattern {
60+
pub fn new(st: &str) -> Pattern {
61+
let cstr = CString::new(st).unwrap();
62+
let pattern = unsafe {
63+
FcNameParse(cstr.as_ptr())
64+
};
65+
Pattern {
66+
pattern
67+
}
68+
}
69+
pub fn get_file_name(&self) -> &str {
70+
let name = b"file\0";
71+
unsafe {
72+
let mut file_name = ptr::null();
73+
FcPatternGetString(self.pattern, name.as_ptr(), 0, &mut file_name);
74+
CStr::from_ptr(file_name).to_str().unwrap()
75+
}
76+
}
77+
pub fn get_font_index(&self) -> isize {
78+
let name = b"index\0";
79+
unsafe {
80+
let mut index = 0;
81+
FcPatternGetInteger(self.pattern, name.as_ptr(), 0, &mut index);
82+
index as isize
83+
}
84+
}
85+
}
86+
87+
impl Drop for Pattern {
88+
fn drop(&mut self) {
89+
unsafe {
90+
FcPatternDestroy(self.pattern)
91+
}
92+
}
93+
}
94+
95+
extern "C" {
96+
fn FcInitLoadConfigAndFonts() -> *const FcConfig;
97+
fn FcConfigDestroy(_: *const FcConfig) -> ();
98+
fn FcNameParse(_: *const c_char) -> *const FcPattern;
99+
fn FcPatternDestroy(_: *const FcPattern) -> ();
100+
fn FcFontMatch(_: *const FcConfig, _: *const FcPattern, _: *mut FcResult) -> *mut FcPattern;
101+
fn FcPatternGetString(_: *const FcPattern, _: *const c_char, _: c_int, _: *mut *const c_char) -> FcResult;
102+
fn FcPatternGetInteger(_: *const FcPattern, _: *const c_char, _: c_int, _: *mut c_int) -> FcResult;
103+
fn FcConfigSubstitute(_: *const FcConfig, _: *const FcPattern, _: FcMatchKind) -> c_int;
104+
fn FcDefaultSubstitute(_: *const FcPattern);
105+
}

src/main.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ use std::{
99
cmp::min
1010
};
1111
use std::os::fd::AsFd;
12-
use cairo::{
13-
ImageSurface, Format, Context, Surface,
14-
FontSlant, FontWeight, Rectangle
15-
};
12+
use cairo::{ImageSurface, Format, Context, Surface, Rectangle, FontFace};
1613
use rsvg::{Loader, CairoRenderer, SvgHandle};
1714
use drm::control::ClipRect;
1815
use anyhow::{Error, Result};
@@ -30,15 +27,18 @@ use input_linux_sys::{uinput_setup, input_id, timeval, input_event};
3027
use nix::poll::{poll, PollFd, PollFlags};
3128
use privdrop::PrivDrop;
3229
use serde::Deserialize;
30+
use freetype::Library as FtLibrary;
3331

3432
mod backlight;
3533
mod display;
3634
mod pixel_shift;
35+
mod fonts;
3736

3837
use backlight::BacklightManager;
3938
use display::DrmBackend;
4039
use pixel_shift::PixelShiftManager;
4140
use pixel_shift::PIXEL_SHIFT_WIDTH_PX;
41+
use fonts::{FontConfig, Pattern};
4242

4343
const DFR_WIDTH: i32 = 2008;
4444
const DFR_HEIGHT: i32 = 64;
@@ -53,13 +53,15 @@ const TIMEOUT_MS: i32 = 10 * 1000;
5353
struct ConfigProxy {
5454
media_layer_default: Option<bool>,
5555
show_button_outlines: Option<bool>,
56-
enable_pixel_shift: Option<bool>
56+
enable_pixel_shift: Option<bool>,
57+
font_template: Option<String>
5758
}
5859

5960
struct Config {
6061
media_layer_default: bool,
6162
show_button_outlines: bool,
62-
enable_pixel_shift: bool
63+
enable_pixel_shift: bool,
64+
font_face: FontFace
6365
}
6466

6567
enum ButtonImage {
@@ -124,7 +126,7 @@ impl FunctionLayer {
124126

125127
c.set_source_rgb(0.0, 0.0, 0.0);
126128
c.paint().unwrap();
127-
c.select_font_face("sans-serif", FontSlant::Normal, FontWeight::Bold);
129+
c.set_font_face(&config.font_face);
128130
c.set_font_size(32.0);
129131
for (i, button) in self.buttons.iter().enumerate() {
130132
let left_edge = (i as f64 * (button_width + BUTTON_SPACING_PX as f64)).floor() + pixel_shift_x + (PIXEL_SHIFT_WIDTH_PX / 2) as f64;
@@ -223,6 +225,18 @@ fn toggle_key<F>(uinput: &mut UInputHandle<F>, code: Key, value: i32) where F: A
223225
emit(uinput, EventKind::Synchronize, SynchronizeKind::Report as u16, 0);
224226
}
225227

228+
fn load_font(name: &str) -> FontFace {
229+
let fontconfig = FontConfig::new();
230+
let mut pattern = Pattern::new(name);
231+
fontconfig.perform_substitutions(&mut pattern);
232+
let pat_match = fontconfig.match_pattern(&pattern);
233+
let file_name = pat_match.get_file_name();
234+
let file_idx = pat_match.get_font_index();
235+
let ft_library = FtLibrary::init().unwrap();
236+
let face = ft_library.new_face(file_name, file_idx).unwrap();
237+
FontFace::create_from_ft(&face).unwrap()
238+
}
239+
226240
fn load_config() -> Config {
227241
let mut base = toml::from_str::<ConfigProxy>(&read_to_string("/usr/share/tiny-dfr/config.toml").unwrap()).unwrap();
228242
let user = read_to_string("/etc/tiny-dfr/config.toml").map_err::<Error, _>(|e| e.into())
@@ -231,11 +245,13 @@ fn load_config() -> Config {
231245
base.media_layer_default = user.media_layer_default.or(base.media_layer_default);
232246
base.show_button_outlines = user.show_button_outlines.or(base.show_button_outlines);
233247
base.enable_pixel_shift = user.enable_pixel_shift.or(base.enable_pixel_shift);
248+
base.font_template = user.font_template.or(base.font_template);
234249
};
235250
Config {
236251
media_layer_default: base.media_layer_default.unwrap(),
237252
show_button_outlines: base.show_button_outlines.unwrap(),
238253
enable_pixel_shift: base.enable_pixel_shift.unwrap(),
254+
font_face: load_font(&base.font_template.unwrap())
239255
}
240256
}
241257

0 commit comments

Comments
 (0)