any1 / wlvncc

A Wayland Native VNC Client

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

high DPI support

retrotails opened this issue · comments

currently with 2x wayland scale on the client, the wlvncc window is pixelated.
I managed to hack together something that hard-codes 2x scale and works for me for now, though it only really works when the window isn't scaled; anything not 1:1 scale has some glitching on the left side and the cursor position is all wrong.
I was expecting setting a flag somewhere would be enough to render at whatever the native res was, but I guess wayland wants you to read the monitor's scale, tell the wayland you want the same scale, then divide/multiply a bunch of coordinates, just for wayland to do the opposite? seems simpler if you could ask wayland "give me the native res and let me figure it out".
terrible hack:

diff --git a/src/main.c b/src/main.c
index 9f4d207..b29ced3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -371,7 +371,7 @@ static void window_resize(struct window* w, int width, int height)
 static void xdg_toplevel_configure(void* data, struct xdg_toplevel* toplevel,
 		int32_t width, int32_t height, struct wl_array* state)
 {
-	window_resize(data, width, height);
+	window_resize(data, width*2, height*2);
 }

 static void xdg_toplevel_close(void* data, struct xdg_toplevel* toplevel)
@@ -411,6 +411,7 @@ static struct window* window_create(const char* app_id, const char* title)
 	xdg_toplevel_set_app_id(w->xdg_toplevel, app_id);
 	xdg_toplevel_set_title(w->xdg_toplevel, title);
 	wl_surface_commit(w->wl_surface);
+	wl_surface_set_buffer_scale(w->wl_surface, 2);

 	return w;

@@ -445,8 +446,8 @@ void on_pointer_event(struct pointer_collection* collection,
 	int x_pos, y_pos;
 	window_calculate_transform(window, &scale, &x_pos, &y_pos);

-	int x = round((wl_fixed_to_double(pointer->x) - (double)x_pos) / scale);
-	int y = round((wl_fixed_to_double(pointer->y) - (double)y_pos) / scale);
+	int x = round((wl_fixed_to_double(pointer->x) - (double)x_pos) / (scale/2) );
+	int y = round((wl_fixed_to_double(pointer->y) - (double)y_pos) / (scale/2) );

 	enum pointer_button_mask pressed = pointer->pressed;
 	int vertical_steps = pointer->vertical_scroll_steps;

I haven't delved into scaling deeply, but at a glance, it looks like we can have the compositor do whole number scaling using this: https://wayland.app/protocols/wayland#wl_surface:request:set_buffer_scale

So, instead of shrinking an image by an integer factor plus change, wlvncc should be sending the integer part to the compositor to handle and do the fractional part itself.

Could you try out wl_surface::set_buffer_scale and maybe whip up a PR for it?

Edit: The morning coffee just kicked in and I realised that you're already using wl_surface::set_buffer_scale. What's missing is to find out the integer part of the scale and use that instead of two. Also, you need to adjust the cursor position scaling. Just look into the pointer_event function. It also needs scale adjusted.

I think it needs to read the scale factor of the output the window is displayed on (no idea how to do that), and it needs to tell wayland it wants the same scale factor to avoid getting pixelated. another issue is, that scale factor can change as the window gets dragged to another output with a different scale.
I'm afraid I'm quite unfamiliar with wayland, and C, my skill level is such that I just managed to figure out enough from documentation to fix my specific use case.

The description in the protocol is misleading. The buffer scale can be set to any number and the compositor will cope. Otherwise, what do you think would happen if you had the window split across two outputs with different scaling? Besides, reading the scale from the outputs would be overly bothersome and a useless micro-optimisation at that.

the simplest thing, avoiding any pixelation, is to get whatever the highest scale factor is from all the outputs and set it to that. or many people are probably fine with a command line flag for it, since 99% of people only need 1x or 2x (until fractional scaling is standardized)
otherwise, not reading the output scale at all might lead to rendering to an 8k surface for no reason, which is not insignificant.

This looks fairly easy to implement. No need for a command line argument to confuse users. We'll see about getting the output scale.