Bug 480639 - [HiDPI][API] Provide monitor-specific DPI scaling / zoom level
Summary: [HiDPI][API] Provide monitor-specific DPI scaling / zoom level
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 4.5   Edit
Hardware: All All
: P3 enhancement with 5 votes (vote)
Target Milestone: 4.8 M7   Edit
Assignee: Lakshmi P Shanmugam CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 533138
Blocks: 509534 514307
  Show dependency tree
 
Reported: 2015-10-26 08:46 EDT by Thomas Singer CLA
Modified: 2018-05-17 10:13 EDT (History)
14 users (show)

See Also:
Lars.Vogel: pmc_approved+


Attachments
(partial) fix (43.79 KB, patch)
2018-01-16 02:10 EST, S. Schulz CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Thomas Singer CLA 2015-10-26 08:46:43 EDT
Please take a look at

<https://msdn.microsoft.com/en-us/library/windows/desktop/dd464646(v=vs.85).aspx>

Since Windows 10 each monitor can have its own scaling factor. While you are at implementing HiDPI support, better do it right from current state of the art. Currently, Monitor lacks a getDpi() function.
Comment 1 Markus Keller CLA 2017-03-28 13:50:58 EDT
I agree we need monitor-specific scaling support, but I think this would be a better API in the Monitor class:

int getZoom()

The returned value would be the zoom level that is used in ImageDataProvider#getImageData(int) callbacks on that monitor. As long as SWT or the underlying platform doesn't support per-monitor zoom levels, this API would return the internal DPIUtil#deviceZoom for all monitors.

We already have a "logical" DPI value at Display#getDPI() that never returned actual dots per inch, and that has been kept stable when the HiDPI Image constructors were added. I wouldn't use the term "DPI" in new APIs.
Comment 2 S. Schulz CLA 2018-01-16 02:10:14 EST
Created attachment 272273 [details]
(partial) fix

- added a field "zoom" to the Device and used that to implement Transform, GC and FontMetrics
- Since the device zoom cannot be a static field anymore, the DPIUtil was changed drastically (not sure if API-compatibility is necessary for internal classes, though)
- the scaling for a Printer should always be 100 (which means getDeviceZoom() should probably be abstract in Device and only implemented in its subclasses, but yet again I was going for API-compatibility)
Comment 3 Niraj Modi CLA 2018-02-01 08:02:18 EST
(In reply to S. Schulz from comment #2)
> Created attachment 272273 [details]
> (partial) fix
> 
> - added a field "zoom" to the Device and used that to implement Transform,
> GC and FontMetrics
> - Since the device zoom cannot be a static field anymore, the DPIUtil was
> changed drastically (not sure if API-compatibility is necessary for internal
> classes, though)
> - the scaling for a Printer should always be 100 (which means
> getDeviceZoom() should probably be abstract in Device and only implemented
> in its subclasses, but yet again I was going for API-compatibility)

Thanks for proposing this patch. Since Monitor doesn't extend from Device this patch won't solve the use-case of per monitor specific zoom use-case.

Also, please share a real use-case of Monitor#getZoom() API, so it will help us in coming with a better designed API.
Comment 4 S. Schulz CLA 2018-02-05 02:59:18 EST
(In reply to Niraj Modi from comment #3)
> (In reply to S. Schulz from comment #2)
> > Created attachment 272273 [details]
> > (partial) fix
> > 
> > - added a field "zoom" to the Device and used that to implement Transform,
> > GC and FontMetrics
> > - Since the device zoom cannot be a static field anymore, the DPIUtil was
> > changed drastically (not sure if API-compatibility is necessary for internal
> > classes, though)
> > - the scaling for a Printer should always be 100 (which means
> > getDeviceZoom() should probably be abstract in Device and only implemented
> > in its subclasses, but yet again I was going for API-compatibility)
> 
> Thanks for proposing this patch. Since Monitor doesn't extend from Device
> this patch won't solve the use-case of per monitor specific zoom use-case.
> 
> Also, please share a real use-case of Monitor#getZoom() API, so it will help
> us in coming with a better designed API.

That's true, it's only for multiple Devices, not Monitors. However I'm not sure how to implement that on a per-monitor-basis. Everything that uses the Device zoom  (Image, GC & Transform at last) only ever use the device, the class Monitor is hardly ever used (hence why I thought the class Display was representing a single monitor). 

I assume you guys have a better understanding of the API, but IMHO the zoom should not be used to create any resources at all. Only when the controls / images are displayed should the zoom factor in. But that's an enormous change...

I'm willing to work on this issue, but I don't know how to proceed. Any advice?
Comment 5 Niraj Modi CLA 2018-02-16 05:49:36 EST
(In reply to S. Schulz from comment #4)
> (In reply to Niraj Modi from comment #3)
> > (In reply to S. Schulz from comment #2)
> > > Created attachment 272273 [details]
> > > (partial) fix
> > > 
> > > - added a field "zoom" to the Device and used that to implement Transform,
> > > GC and FontMetrics
> > > - Since the device zoom cannot be a static field anymore, the DPIUtil was
> > > changed drastically (not sure if API-compatibility is necessary for internal
> > > classes, though)
> > > - the scaling for a Printer should always be 100 (which means
> > > getDeviceZoom() should probably be abstract in Device and only implemented
> > > in its subclasses, but yet again I was going for API-compatibility)
> > 
> > Thanks for proposing this patch. Since Monitor doesn't extend from Device
> > this patch won't solve the use-case of per monitor specific zoom use-case.
> > 
> > Also, please share a real use-case of Monitor#getZoom() API, so it will help
> > us in coming with a better designed API.
> 
> That's true, it's only for multiple Devices, not Monitors. However I'm not
> sure how to implement that on a per-monitor-basis. Everything that uses the
> Device zoom  (Image, GC & Transform at last) only ever use the device, the
> class Monitor is hardly ever used (hence why I thought the class Display was
> representing a single monitor). 
> 
> I assume you guys have a better understanding of the API, but IMHO the zoom
> should not be used to create any resources at all. Only when the controls /
> images are displayed should the zoom factor in. But that's an enormous
> change...
Ok, we were more interested on the exact use-case(s) that you are targeting.
To have a better understanding of the requirement, you can also share SWT Snippets or JUnit test cases that you see is breaking and shall work once we have your patch changes in.

> I'm willing to work on this issue, but I don't know how to proceed. Any
> advice?
Thanks for you interest, currently we use Gerrit for code sharing/review.
Once we have clear understanding on the use-case front we can short it out.
Comment 6 Eclipse Genie CLA 2018-03-27 05:51:11 EDT
New Gerrit change created: https://git.eclipse.org/r/120240
Comment 7 Alexander Kurtakov CLA 2018-03-29 06:29:39 EDT
gdk_monitor_get_scale_factor  in GTK 3.22 should satisfy this need.
Comment 8 Alexander Kurtakov CLA 2018-03-29 06:30:10 EDT
Eric, would you please handle the GTK side?
Comment 9 Lakshmi P Shanmugam CLA 2018-03-29 06:39:25 EDT
Thanks Alex! I've a WIP progress patch for GTK with the new APIs, but still requires testing with the HiDPI monitor. Will post the patch shortly.
Comment 10 Eclipse Genie CLA 2018-04-04 07:06:32 EDT
New Gerrit change created: https://git.eclipse.org/r/120695
Comment 11 Lakshmi P Shanmugam CLA 2018-04-04 09:45:56 EDT
(In reply to Eclipse Genie from comment #10)
> New Gerrit change created: https://git.eclipse.org/r/120695

The gtk patch uses gdk_monitor_get_scale_factor for GTK >= 3.22 and gdk_screen_get_monitor_scale_factor for older versions, but both the APIs return scale factor 1 even for a HiDPI monitor with 200% scaling.

In OS.java, the GDK_SCALE is set to 1. If GDK_SCALE is set to 2 in OS.java, then the GTK APIs return the scale factor as 2. But, removing the code doesn't have any effect. Looks like GDK_SCALE is getting the correct value automatically.

I think the launcher code also sets GDK_SCALE=1, but removing that too doesn't have effect on the GTK APIs.

Alex/Eric any ideas on how to get the correct scale factor?
Comment 12 Eclipse Genie CLA 2018-04-06 08:00:12 EDT
New Gerrit change created: https://git.eclipse.org/r/120847
Comment 13 Lakshmi P Shanmugam CLA 2018-04-09 04:37:47 EDT
(In reply to Eclipse Genie from comment #6)
> New Gerrit change created: https://git.eclipse.org/r/120240

This patch has the Windows and Mac implementation of the Monitor.getZoom() API. 

To enable dynamic DPI on Windows 10 and above, dpiAwareness setting has to be enabled using java.exe.manifest as mentioned here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=533135#c5
Comment 14 Lakshmi P Shanmugam CLA 2018-04-09 04:47:59 EDT
Snippet to test the new API - https://bugs.eclipse.org/bugs/attachment.cgi?id=273491
Comment 16 Lakshmi P Shanmugam CLA 2018-04-12 07:30:04 EDT
(In reply to Lakshmi Shanmugam from comment #11)
> (In reply to Eclipse Genie from comment #10)
> > New Gerrit change created: https://git.eclipse.org/r/120695
> 
> The gtk patch uses gdk_monitor_get_scale_factor for GTK >= 3.22 and
> gdk_screen_get_monitor_scale_factor for older versions, but both the APIs
> return scale factor 1 even for a HiDPI monitor with 200% scaling.
> 
> In OS.java, the GDK_SCALE is set to 1. If GDK_SCALE is set to 2 in OS.java,
> then the GTK APIs return the scale factor as 2. But, removing the code
> doesn't have any effect. Looks like GDK_SCALE is getting the correct value
> automatically.
> 
> I think the launcher code also sets GDK_SCALE=1, but removing that too
> doesn't have effect on the GTK APIs.
> 
> Alex/Eric any ideas on how to get the correct scale factor?

Hi Alex, any ideas?
What I'm trying to find out is, does gdk_monitor_get_scale_factor() return the correct scale factor? I tested the patch with Fedora 27 and it doesn't give scale factor 2 on HiDPI monitor.
Comment 17 Alexander Kurtakov CLA 2018-04-13 07:54:48 EDT
(In reply to Lakshmi Shanmugam from comment #16)
> (In reply to Lakshmi Shanmugam from comment #11)
> > (In reply to Eclipse Genie from comment #10)
> > > New Gerrit change created: https://git.eclipse.org/r/120695
> > 
> > The gtk patch uses gdk_monitor_get_scale_factor for GTK >= 3.22 and
> > gdk_screen_get_monitor_scale_factor for older versions, but both the APIs
> > return scale factor 1 even for a HiDPI monitor with 200% scaling.
> > 
> > In OS.java, the GDK_SCALE is set to 1. If GDK_SCALE is set to 2 in OS.java,
> > then the GTK APIs return the scale factor as 2. But, removing the code
> > doesn't have any effect. Looks like GDK_SCALE is getting the correct value
> > automatically.
> > 
> > I think the launcher code also sets GDK_SCALE=1, but removing that too
> > doesn't have effect on the GTK APIs.
> > 
> > Alex/Eric any ideas on how to get the correct scale factor?
> 
> Hi Alex, any ideas?
> What I'm trying to find out is, does gdk_monitor_get_scale_factor() return
> the correct scale factor? I tested the patch with Fedora 27 and it doesn't
> give scale factor 2 on HiDPI monitor.

Look at the latest patch. After changing Display scale to 200% in gnome settings I can see getZoom properly giving me 200%. Seems to be working fine to me.
Comment 18 Alexander Kurtakov CLA 2018-04-13 07:55:59 EDT
Just for the record in the default case it gives me 100.
Comment 19 Lakshmi P Shanmugam CLA 2018-04-16 09:15:56 EDT
(In reply to Alexander Kurtakov from comment #17)
> Look at the latest patch. After changing Display scale to 200% in gnome
> settings I can see getZoom properly giving me 200%. Seems to be working fine
> to me.
Thanks for looking into this, Alex.

This is strange, I tried the latest patch but getZoom() still gives me 100.
I tried Fedora 27 with both setups: single standard resolution monitor and standard + hidpi monitor. I changed the scale factor from the command line using:
gsettings set org.gnome.desktop.interface scaling-factor 2

What is your setup? how do you set the scale factor?
Comment 20 Alexander Kurtakov CLA 2018-04-16 09:31:05 EDT
(In reply to Lakshmi Shanmugam from comment #19)
> (In reply to Alexander Kurtakov from comment #17)
> > Look at the latest patch. After changing Display scale to 200% in gnome
> > settings I can see getZoom properly giving me 200%. Seems to be working fine
> > to me.
> Thanks for looking into this, Alex.
> 
> This is strange, I tried the latest patch but getZoom() still gives me 100.
> I tried Fedora 27 with both setups: single standard resolution monitor and
> standard + hidpi monitor. I changed the scale factor from the command line
> using:
> gsettings set org.gnome.desktop.interface scaling-factor 2
> 
> What is your setup? how do you set the scale factor?

Fedora 28

1. setting app
2. Devices
3. Display
4. Change Scale to 200%
Comment 21 Lakshmi P Shanmugam CLA 2018-04-17 01:29:04 EDT
Sravan, can you please test the patch on your linux box?
Comment 22 Lakshmi P Shanmugam CLA 2018-04-17 08:39:05 EDT
(In reply to Lakshmi Shanmugam from comment #21)
> Sravan, can you please test the patch on your linux box?
I tested on Sravan's VM with Fedora 27 and I get scale factor as 2.
May be the difference is because the snippet is running on X11 on his setup.
On my system it doesn't seem to run on X11 (OS.isX11() returns false) even if I set GDK_BACKEND=x11.
Comment 23 Alexander Kurtakov CLA 2018-04-18 06:57:54 EDT
(In reply to Lakshmi Shanmugam from comment #22)
> (In reply to Lakshmi Shanmugam from comment #21)
> > Sravan, can you please test the patch on your linux box?
> I tested on Sravan's VM with Fedora 27 and I get scale factor as 2.
> May be the difference is because the snippet is running on X11 on his setup.
> On my system it doesn't seem to run on X11 (OS.isX11() returns false) even
> if I set GDK_BACKEND=x11.

I run on wayland and still see correct value.
Comment 24 Lakshmi P Shanmugam CLA 2018-04-23 07:34:46 EDT
(In reply to Alexander Kurtakov from comment #23)
> (In reply to Lakshmi Shanmugam from comment #22)
> > (In reply to Lakshmi Shanmugam from comment #21)
> > > Sravan, can you please test the patch on your linux box?
> > I tested on Sravan's VM with Fedora 27 and I get scale factor as 2.
> > May be the difference is because the snippet is running on X11 on his setup.
> > On my system it doesn't seem to run on X11 (OS.isX11() returns false) even
> > if I set GDK_BACKEND=x11.
> 
> I run on wayland and still see correct value.

Ok, I'm not sure what is wrong in my setup.

Eric/Leo, can one of you please try out the new API? I just want to make sure the code works on another system before I commit the changes and that the problem is specific to my setup.
Comment 25 Leo Ufimtsev CLA 2018-04-24 14:17:40 EDT
I tried the snippet attached to this bug with Alex's latest patch (v14) on Gtk/Wayland, works well.

Environment:
- 4 monitor setup
- Fedora 27, Gtk3.22  Wayland 
- 1 monitor has 200% HiDpi

The snippet reports 200-100-100-100 correctly and when I move the snippet onto the screen with hiDpi, it makes it self bigger. When I move it back onto a regular screen, it makes itself smaller again. 

Kinda cool. This is similar to what gnome does with it's native apps as well.

Made a little video (a bit blurry unfortunately, but you get the idea):
https://www.youtube.com/watch?v=Xixj1UoLslg&feature=youtu.be
Comment 28 Eclipse Genie CLA 2018-04-25 03:59:27 EDT
New Gerrit change created: https://git.eclipse.org/r/121709
Comment 30 Niraj Modi CLA 2018-04-26 08:56:48 EDT
(In reply to Eclipse Genie from comment #29)
> Gerrit change https://git.eclipse.org/r/121709 was merged to [master].
> Commit:
> http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/
> ?id=cdc67cbff3fb701108f19e6dbec01306872e31dc

Thanks Nikita for the patch, it refactors the code related to new API and primarily simplifies the Windows implementation.
Comment 31 Niraj Modi CLA 2018-05-09 04:39:26 EDT
Resolving.
Comment 32 Niraj Modi CLA 2018-05-09 04:55:54 EDT
Verified in I20180507-2205 on Win10.