Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hidpi support? #1

Closed
nabijaczleweli opened this issue Nov 29, 2020 · 8 comments
Closed

hidpi support? #1

nabijaczleweli opened this issue Nov 29, 2020 · 8 comments
Assignees
Labels
enhancement New feature or request

Comments

@nabijaczleweli
Copy link

Is your feature request related to a problem? Please describe.
I have a 2K (2560x1600px) screen 181x113 in size (8.4" diagonal). That's tiny and very very dense (primitive calculation says 360ish DPI or 14px/mm but I'm not sure if I'm counting right).

The default X DPI is 96 and XDrawString() doesn't respect the Xft.dpi resource that I use to offset the incredible minusculity of the text at default size for reasons I assume obvious. The text with the resolution at the centre is, quite literally, unreadable from more than a hand's width away from the screen.

Describe the solution you'd like
The solution is probably fontconfig?

Describe alternatives you've considered
I've tried to convince XDrawString() to use a different or bigger font via XSetFont(), but haven't had much success; this might be because it's too arcane for me, or I might be holding it wrong.

Additional context
Confer this YouTube video, resize to 113x181 for optimum viewing experience: https://youtu.be/D2xb2ijuxeQ (frankly, I'm having trouble on my 27" display).

I'm very much not opposed to implementing this myself, but, well, I might need a suggestion or two on how to proceed.

@nabijaczleweli nabijaczleweli added the enhancement New feature or request label Nov 29, 2020
@orhun
Copy link
Owner

orhun commented Nov 30, 2020

Hey,
It's good to see people discovering this project and the first issue being created :)
Actually this was on my TODO list for like a few weeks since I realized font being too small while recording GIFs for README.md. About the XSetFont() approach, you're basically right. That's one way of setting the font size. (the font, actually) So I've played around with it a little bit in get_gc function which is responsible for the main graphics context:

fn get_gc(&self, fg_color: u64) -> xlib::GC {
    let font = "-*-dejavu sans-*-*-*-*-17-*-*-*-*-*-*-*"; // font description
    let font = CString::new(font).expect("Failed to create CString");
    let xfont =
        unsafe { xlib::XLoadQueryFont(self.display.inner, font.as_ptr()) }; // load font
    unsafe {
        let gc =
            xlib::XCreateGC(self.display.inner, self.xid, 0, ptr::null_mut());
        xlib::XSetForeground(self.display.inner, gc, fg_color);
        if !xfont.is_null() {
            xlib::XSetFont(self.display.inner, gc, (*xfont).fid); // set font
        } else {
            warn!("Invalid font!"); // TODO: do this somewhere else, get_gc is called for every new window
        }
        gc
    }
}

Result:

cap

Turns out it can indeed set the font but the only problem being finding the correct font query/description. In this case, I generated the -*-dejavu sans-*-*-*-*-17-*-*-*-*-*-*-* description with using xfontsel utility:

cap

Give xfontsel utility a try. Not all of the fonts support a specific size so format!(-*-*-*-*-*-*-{}-*-*-*-*-*-*-*, font_size) might not load a font at all. (thinking aloud)

So my plan is to implement a separate font handler function/module and adding the --font flag to general settings for letting user to set a font according to the X11 font descriptions. (e.g. menyoki --font "-*-*-*-*-*-*-17-*-*-*-*-*-*-*")

Tell me what you think :)

@nabijaczleweli
Copy link
Author

nabijaczleweli commented Nov 30, 2020

It's not exactly easy to find fonts that are actually big enough on my system, but this does in fact work.

It's also revealed that Window leaks an astounding amount of GCs; they're 176 bytes each, so it's not a giagnti deal memory-wise and I was gonna say that "it makes menyoki use 5% of my CPU" when idling, but applying the diff below reveals that removing overhead from the continuous allocations actually makes the program use 9% instead, as it spins in polls and redraws. This probably explains why it's so weird and flickery?

diff --git a/Cargo.lock b/Cargo.lock
index f976f92..8713a39 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -717,6 +717,7 @@ dependencies = [
  "image 0.23.12",
  "imgref",
  "kamadak-exif",
+ "lazy_static",
  "log",
  "natord",
  "png 0.16.7",
diff --git a/Cargo.toml b/Cargo.toml
index f5562c9..2ff0915 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -52,6 +52,7 @@ natord = "1.0.9"
 colored = "2.0.0"
 log = "0.4.11"
 fern_colored = { version = "0.6.1", features = ["colored"] }
+lazy_static = "1.4.0"
 
 [dependencies.clap]
 version = "2.33.3"
diff --git a/src/main.rs b/src/main.rs
index 184cc92..ac1e8e4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,6 +3,8 @@
 
 #[macro_use]
 extern crate log;
+#[macro_use]
+extern crate lazy_static;
 
 mod analyze;
 mod anim;
diff --git a/src/x11/window.rs b/src/x11/window.rs
index 1eeb01d..aec0639 100644
--- a/src/x11/window.rs
+++ b/src/x11/window.rs
@@ -5,12 +5,14 @@ use crate::window::Capture;
 use crate::x11::display::Display;
 use image::Bgra;
 use std::convert::{TryFrom, TryInto};
+use std::sync::Mutex;
 use std::ffi::CString;
 use std::fmt;
 use std::io::{self, Write};
 use std::mem::MaybeUninit;
 use std::ptr;
 use std::slice;
+use std::collections::BTreeMap;
 use textwidth::Context;
 use x11::xlib;
 
@@ -19,6 +21,12 @@ const MAX_TEXT_HEIGHT: u32 = 30;
 /* Offset for placing the text on the corner of window */
 const TEXT_CORNER_OFFSET: i32 = 20;
 
+struct GcWrapper(xlib::GC);
+unsafe impl Send for GcWrapper {}
+lazy_static! {
+	static ref GC_CACHE: Mutex<BTreeMap<u64, GcWrapper>> = Mutex::new(BTreeMap::new());
+}
+
 /* X11 window id, geometric properties and its display */
 #[derive(Clone, Copy, Debug)]
 pub struct Window {
@@ -26,6 +34,7 @@ pub struct Window {
 	display: Display,
 	pub geometry: Geometry,
 	pub area: Geometry,
+	gc: xlib::GC,
 }
 
 /* Implementations for thread-safe usage */
@@ -60,6 +69,7 @@ impl Window {
 				display,
 				geometry: Geometry::default(),
 				area: Geometry::default(),
+				gc: ptr::null_mut(),
 			}
 			.set_geometry()
 		}
@@ -132,12 +142,13 @@ impl Window {
 	 * @return GC
 	 */
 	fn get_gc(&self, fg_color: u64) -> xlib::GC {
-		unsafe {
-			let gc =
-				xlib::XCreateGC(self.display.inner, self.xid, 0, ptr::null_mut());
-			xlib::XSetForeground(self.display.inner, gc, fg_color);
-			gc
-		}
+		GC_CACHE.lock().unwrap().entry(self.xid).or_insert_with(|| {
+			unsafe {
+				let gc = xlib::XCreateGC(self.display.inner, self.xid, 0, ptr::null_mut());
+				xlib::XSetForeground(self.display.inner, gc, fg_color);
+				GcWrapper(gc)
+			}
+		}).0
 	}
 
 	/* Draw a rectangle inside the window. */

@orhun
Copy link
Owner

orhun commented Nov 30, 2020

It's not exactly easy to find fonts that are actually big enough on my system, but this does in fact work.

I'm thinking of adding a --font argument to record and capture for setting the font. (If that partly solves your issue.) Better than nothing I guess.
Besides, I don't know what else we can do about this.

It's also revealed that Window leaks an astounding amount of GCs; they're 176 bytes each, so it's not a giagnti deal memory-wise and I was gonna say that "it makes menyoki use 5% of my CPU" when idling, but applying the diff below reveals that removing overhead from the continuous allocations actually makes the program use 9% instead, as it spins in polls and redraws. This probably explains why it's so weird and flickery?

Flickering happens because it attemps to clear the window area when the selection (rectangle) moved or resized (also window content affects it as well I guess.) And yeah, creating GCs continuously is the reason of that CPU usage. I should re-evaluate the select_window function some time.
What's the weird part? I might be blind enough to not see that since I've been using menyoki for months.

@nabijaczleweli
Copy link
Author

Yeah, being able to specify the font in the config would definitely solve this.

The weirdness got a little less weird when I killed my compositor, since my wallpaper shone through the green rectangle edges (and text, funnily enough, when moving the selection) otherwise, but combined with the screen tearing it does look quite odd as it redraws over the course of a few frames after blinking off when hovering over a link in firefox.

@orhun
Copy link
Owner

orhun commented Nov 30, 2020

Yeah, being able to specify the font in the config would definitely solve this.

Great!

The weirdness got a little less weird when I killed my compositor, since my wallpaper shone through the green rectangle edges (and text, funnily enough, when moving the selection) otherwise, but combined with the screen tearing it does look quite odd as it redraws over the course of a few frames after blinking off when hovering over a link in firefox.

Hmm, I'd like to look into that and solve it (if it's possible) if you can provide something visual.

@nabijaczleweli
Copy link
Author

In https://youtu.be/pHBuUCFsEeA, note how the text is partially white as it moves around and as short lines shine through the borders as they come in, matching what's behind them in the root window (https://nabijaczleweli.xyz/content/maths/wiggly-circle.html#r0_sngllines2_flagpan_1600x900_60).

@orhun
Copy link
Owner

orhun commented Dec 1, 2020

With the latest release (v0.1.4), you can specify the font (--font) and border width (--border) while using record or capture. (also they are available in config file and as environment variables)

Test it out. You can close the issue if there's nothing else to do :)

@nabijaczleweli
Copy link
Author

nabijaczleweli commented Dec 2, 2020

Yep, that works; thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants