-
Notifications
You must be signed in to change notification settings - Fork 335
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
X11: enable dpi scaling #890
Conversation
This seems to work on my computer, where I presume it's intended that the current DPI is rounded up to the nearest integer scale which is used to calculate the geometry. I tested 96dpi (1.0x), 144dpi (1.5x) and 192dpi (2.0x) where I got the geometry scale 1x, 2x, 2x respectively. I'll chime in and say whilst this is better than no scaling at all, fractional scaling would be a lot more useful for the majority of people (myself included), so hopefully this improvement can lead to that next!
I'm not sure this would work great to be honest, see cases like 1.25x (120dpi), it would be slightly off. I think it'd be better to pass around the full scale value as a float and clamp/round it for wayland but not for X11. Either way, this is a great improvement and a good start to solving #754 fully. Thanks for the hard work @vincentbernat and @fwsmit |
Codecov Report
@@ Coverage Diff @@
## master #890 +/- ##
==========================================
+ Coverage 59.91% 60.18% +0.26%
==========================================
Files 39 39
Lines 6137 6181 +44
==========================================
+ Hits 3677 3720 +43
- Misses 2460 2461 +1
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
Thank you for the PR
That could be an option. It's mostly that the screen dpi detection was already there. I believe advantages of screen dpi include (correct me if I'm wrong)
I don't know about the other options, but I'm open to change it. Depending on which one we choose, an option in the dunst settings to overwrite the scale value may be useful.
Yes seems good to me.
Why not change
The advantage of the |
To explain the Wayland situation a bit more: the scale factor can only be an integer. The nearest integer above the scale factor is chosen, and then the image is scaled down by interpolation. I understand that non-integer scaling is very useful and also very possible for dunst, so let's look at the best way to implement it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall just a small change needed. If you want you can implement instant changing when the DPI changes by calling wake_up()
when a dpi change event is emitted (note that there's a bug that icons still don't scale instantly).
❦ 6 July 2021 15:29 -07, fwSmit:
> The scaling factor is derived from the active screen's dpi. This may
> or may not match what is expected. Other sources could be font DPI or
> Gdk/WindowScalingFactor.
That could be an option. It's mostly that the screen dpi detection was
already there. I believe advantages of screen dpi include (correct me
if I'm wrong)
- It can be updated on the fly
- It's built into an (universal) X11 extension
- It is automatically assigned (???)
I don't know about the other options, but I'm open to change it.
Depending on which one we choose, an option in the dunst settings to
overwrite the scale value may be useful.
I just mention this to document it somewhere. GTK applications are not
reacting directy to XRandR DPI, the watch for XSETTINGS changes, but
watching XRandR DPI is not unknown territory as Chromium does that too.
I don't think we need to do something now. If the issue popup, you can
search for it and find this PR ;-)
> I would also be interested to support fractional scaling. From my
> understanding, this is not possible with Wayland, right? For X11, we
> can and the change would mostly be replacing `scale` by `scale*10`
> and divide it again by 10 everywhere.
Why not change `scale` to a float? I'm trying to think of disadvantages. I can come up with
- Sizes may not end up at whole pixels. You can either round, making
thinks potentially look not aligned. Or you can alias, which results
in smooth edges.
The advantage of the `scale*10` way is that when the scale is a
multiple 10, everything will be exact, where as with a float the scale
of 1 may still result in distortion (depending on if you round).
Yes, that was the main reason. But we can also round everything and it
should be fine. As it would handle 1.25x case better, I'll do that.
|
Ok you can go ahead and make |
Done. Tested on X11 with 1, 1.25, 1.5 and 2. No issue detected! This is quite a big change due to the need to add rounding everywhere. This is not strictly necessary but it may result as an off-by-one error if we don't do that. Maybe we could live with that if you want to reduce the changeset. |
I've taken a quick look and it looks good. If I understand it correctly the |
Just tested this and it seems to work a treat on X11 with 1.0x and 1.5x scale! Thanks so much |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me the notification became blurry from this patch and it looked like it was (half a) pixel below where it should be.
Note also that a separator seems to appear in the bottom image, but I have the color set to my background color. It will probably be fixed when you address the comments
3d91183
to
071e4f9
Compare
071e4f9
to
7048e74
Compare
docs/dunst.5.pod
Outdated
=item B<scale> (default: 0) | ||
|
||
Specifies a scale factor for dimensions to adapt notifications to the | ||
screen DPI. This does not apply to text. If 0 is specified, the scale |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Screen dpi or wayland scale factor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the source of auto-detection, not really the purpose. I have pushed another tentative to not mention DPI. Otherwise, please propose the whole text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's documentation for the dpi scaling at the same time :)
The text should also be scaled with the scale factor. If that's not the case then something is wrong.
I would suggest this as text:
Specifies a scale factor for dimensions to adapt notifications to HiDPI
screens. This scales the notification geometry and it's contents.
It is not recommended to use a fractional scaling factor, as this may result in
things being one pixel off. Try to use a whole number scaling factor and adjust
the font size and other sizes as needed. If 0 is specified, the scale factor is
auto-detected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, on X11, it does not scale text. Text is handled using Xft/DPI (from XSETTINGS, with a fallback to X resource database). I don't think this is very important, unless you use the scale
settings, in this case, you don't control the whole scale.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weird I thought we controlled text size directly. The scale variable is kind of useless on X11 then. On wayland it also doesn't work currently. It doesn't scale the window dimensions, so the notification is cut off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could make it an X11 only setting. Wayland does not really need it because there is only one way to get the scaling, so we are unlikely to be wrong. And since it does not scale text, we can just have a 3-state setting: integer-scaling, integer-scaling++, fractional-scaling. I am not good with names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah but if the text size doesn't change from this scale variable it's pretty much useless. Is there a way to draw larger text independent from the X dpi?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. But if there is, I wouldn't expect Dunst to override Xft/DPI (or Xft.DPI). Text scaling is pretty much the only thing that's easy to do on Linux without much surprise.
I will test it later today, but other then the little documentation thing it looks very good |
e58e1c0
to
edb7f70
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fractional scaling does work, but there are a couple of artifacts introduced by the rounding. It's fine to have those for a first effort, but I would like to keep the default to not use fractional scaling. So could you make x_get_scale only return rounded scale factors?
edb7f70
to
f01c134
Compare
What kind of artifacts? Having to force a fractional scaling through settings only means dunst has to be restarted when the DPI change (for example, when you connect external screens). Maybe I can add -1 to autodetect and keep fractional scaling? |
If the artifacts are due to the scaling factor using non fractional values, like 1.04 because user did not set Xft.DPI (which may be possible if you don't care about HiDPI), maybe we could also whitelist 1.5 and 1.25. Linux is kind of a hell for people using HiDPI displays. The general mechanism is to get text size from Xft/DPI and interface scale from Gdk/WindowScalingFactor (which is not fractional) and to listen for changes on XSETTINGS. However, many apps fallback to various mechanisms, like monitor DPI settings or more usually Xft.DPI. So, the best we can do when using HiDPI display is to set XRandR DPI, Xft.DPI, Xft/DPI, and Gdk/WindowScalingFactor to consistent values. Most apps then just work fine or don't handle DPI at all. Having to mangle each app is cumbersome. That's why I would like to default to something working out of the box. |
I've noticed two things: Progress bar border isn't placed correctly. Note the space at the left: The second one is a regression, because the border was placed in a non-whole pixel pixel position. Cairo strokes are specified by the center of the stroke, so that's why a non-whole pixel position was needed. All in all, it's a little more complicated than rounding everything. I'm currently feeling like we will be better off not rounding and letting anti-aliassing do it's work, but I'm curious what you think
I don't think it's a problem on 1.04 scale, but it is on 1.25 as seen above. Whitelisting certain values doesn't seem like a good solution to me. I think it's better to improve the scaling just a bit more.
Agreed, I'm trying to make dunst as good out of the box as possible. One should need to do no configuration to make it work well. |
I am not familiar with Cairo at all, so I don't know what other software do. It's a bit odd the regression at 1x, since nothing has really changed. We multiply by 1 or divide by 1. Maybe using a float instead of a double is the reason? Cairo is using double. Conversion from float to double may introduce this kind of things? As for fractional scaling, that's mostly why Gnome was really reluctant to support it for anything else than text. But if you have a HiDPI screen at 1.5x scale, not scaling the interface does not give a very good result. That's why I think recent versions of Gnome started supporting fractional scaling. I think that whitelisting known ratio (1.25 and 1.5) by default and using integer ratio otherwise would be a good compromise. Setup matching one of those two ratios have most likely configured their environment for it (by opposition to people using 1x scale with no Xft.DPI set and where dunst is using computed DPI from XRandR) and are willing to live with the little imperfections. This would make the setup work out of the box for most people in the way they like it. As long as we find the regression at 1x with Cairo. |
We could round the scale to multiples of 0.25. But again, I haven't tested what happens at scales like 1.04, so let's test that first. I've explained the regression for 1x above already. It has to do with the line needing to be on a non-whole pixel for certain line widths. If the line width is 3 for example, you have to specify the location of the line by it's middle. So if the left of the line has to be on pixel 40, the middle is on pixel 41.5. |
What I don't understand is that it shouldn't be a regression as we didn't change that. We still pass the same values as before to Cairo, except instead of being int, they are floats (but rounded). From what I understand, the problem should already be present in master? |
src/draw.c
Outdated
// TODO draw_rect instead of cairo_rectangle resulted in blurry lines. Why? | ||
cairo_rectangle(c, (frame_x + half_frame_width) * scale, (frame_y + half_frame_width) * scale, (progress_width - frame_width) * scale, progress_height * scale); | ||
cairo_set_line_width(c, frame_width * scale); | ||
draw_rect(c, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regression is here. Before it was using floats directly to cairo_rectangle
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, good catch! Should we convert draw_rect to floats?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have converted it to double, but this is not enough because of rounding.
Unrelated, but I also noticed I have used float
while most of the existing code and Cairo are using double
. So, I have converted everything to double
(and use of round()
introduced a conversion to double
as well).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have converted it to double, but this is not enough because of rounding.
Yeah it's better then to leave the old cairo_rectangle line that was there. You can go ahead and leave the TODO out though.
Unrelated, but I also noticed I have used
float
while most of the existing code and Cairo are usingdouble
. So, I have converted everything todouble
(and use ofround()
introduced a conversion todouble
as well).
👍
Sorry, I am a bit low on time currently. Dunno exactly when I will get more time. |
Okay, no problem. Maybe someone else wants to finish it, or I can do it some time. |
19adc75
to
9c72d0e
Compare
Let me do it quickly. |
The scaling factor is derived from the active screen's dpi. This may or may not match what is expected. Other sources could be font DPI or Gdk/WindowScalingFactor. Currently, only integer scaling is supported. This reuses most of the code that was present for Wayland and the change is limited to compute a scaling factor and putting the window at the right position and at the right size. The code to compute the window position in `draw.c` was only used for X11, so it was moved directly in `x.c`.
On X11, we can support fractional scaling. Let's convert `scale` to a float number and round it automatically on multiplication. When scale is used, we `round()` the result.
9c72d0e
to
77f0f0e
Compare
OK, it's rebased. |
Hold on, it's crashing, I didn't test correctly... |
77f0f0e
to
996890f
Compare
OK, all good for me. |
996890f
to
ea6d042
Compare
And I have added tests too. |
ea6d042
to
8d358a8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the quick reply and fix! It works very well for me now. There's two things remaining as far as I can tell:
- The scale variable doesn't change the window size in wayland. I would suggest making
scale
a X11 only option, since sway on wayland has a better way to set scale anyways. - The text size on X11 doesn't change with a change in
scale
. Is that expected behaviour? It's not a dealbreaker for me, so it can be merged with this quirk.
❦ 10 August 2021 03:01 -07, fwSmit:
- The scale variable doesn't change the window size in wayland. I
would suggest making `scale` a X11 only option, since sway on wayland
has a better way to set scale anyways.
Is it only a matter of adding a "(X11 only)" in the description?
- The text size on X11 doesn't change with a change in `scale`. Is
that expected behaviour? It's not a dealbreaker for me, so it can be
merged with this quirk.
Yes, this is expected. We discussed a bit about this, and that's how
scaling generally work for X11. I don't think it will surprise most
people. And people should just use `scale=0` since it will match the
size of the text.
|
Yes and removing the
Okay that's fine by me. If people get confused we can always add a note in the documentation |
8d358a8
to
611796a
Compare
OK, updated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, I only have one small comment
docs/dunst.5.pod
Outdated
@@ -106,6 +106,15 @@ the notification on the left border of the screen while a horizontal offset of | |||
|
|||
=back | |||
|
|||
=item B<scale> (default: 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add (X11 only)
here as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
The default value is 0 and it makes dunst auto-detect the value from screen DPI. X11 only.
611796a
to
45ea305
Compare
Thank you for your work! |
A release with this would be great! :) |
I agree a release is due. What do you think @tsipinakis? |
The scaling factor is derived from the active screen's dpi. This may
or may not match what is expected. Other sources could be font DPI or
Gdk/WindowScalingFactor.
Currently, only integer scaling is supported.
This reuses most of the code that was present for Wayland and the
change is limited to compute a scaling factor and putting the window
at the right position and at the right size. The code to compute the
window position in
draw.c
was only used for X11, so it was moveddirectly in
x.c
.See #884 for the discussion.
I would also be interested to support fractional scaling. From my understanding, this is not possible with Wayland, right? For X11, we can and the change would mostly be replacing
scale
byscale*10
and divide it again by 10 everywhere.