Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 495134 - [HiDPI][Win32] Device#getDPI behaves differently between Linux and Windows with HiDPI screens
Summary: [HiDPI][Win32] Device#getDPI behaves differently between Linux and Windows wi...
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 4.6   Edit
Hardware: PC Windows All
: P3 major (vote)
Target Milestone: 4.6 RC4   Edit
Assignee: Markus Keller CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-06-01 07:05 EDT by Peter Severin CLA
Modified: 2016-06-02 08:09 EDT (History)
6 users (show)

See Also:
niraj.modi: review+
arunkumar.thondapu: review+
sravankumarl: review+


Attachments
ScalingData.java (snippet to print DPI, monitor bounds, etc.) (1.23 KB, text/plain)
2016-06-01 09:21 EDT, Markus Keller CLA
no flags Details
IssueWithCTabFolder_LatestGerrit_Patch3 (166.68 KB, image/png)
2016-06-01 11:35 EDT, Niraj Modi CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Severin CLA 2016-06-01 07:05:01 EDT
I am using Device#getDPI method to detect screen DPI and I see different results between Windows and Linux (and most probably Mac OS X). I am using this method in WireframeSketcher to do point to pixels conversion. GEF also uses this method to calculate unit spacing for rulers.

On the same screen with x2 scaling, on Linux the DPI=96, however on Windows the DPI=192. I don't see this difference documented anywhere, so I suppose that it's a bug. From my point of view, the behavior on Linux is the one that is correct, and I believe that it's the same behavior as on Mac OS X.

I'm testing this with the latest Eclipse Neon build I20160530-2000.
Comment 1 Sravan Kumar Lakkimsetti CLA 2016-06-01 07:40:43 EDT
This is existing API and it is used by all devices like screens, printers etc. We did not modify this api at all in the hidpi work. 

We did had a discussion on exposing scalefactor to the end user but we did not had a usecase where enduser needs scalefactor or needs point to pixel conversion. We ended up not exposing this. In our opinion you should not require to do these conversions from the client level

If you can give us a usecase we will consider exposing some of the internal utilities we use for pixel-point and point-pixel conversions

If you really need the scalefactor you can get from this java property org.eclipse.swt.internal.deviceZoom. This will provide the scalefactor in percentage
Comment 2 Peter Severin CLA 2016-06-01 07:50:34 EDT
I believe that we are talking about different methods. Device#getDPI method is public API that was there before the HiDPI changes introduced in Neon. The problem is that now this method behaves differently between Linux and Windows when screen scale factor is other than 1.

At this point, I can actually correct this issue in my code, by calling DPIUtil.autoScaleDown(display.getDPI().y) internal method on Windows to normalize this value. I don't have to do it on Linux, so I think that on Linux this method has the correct behavior. I believe this is also the case on Mac OS X, where the DPI always has the same value, both on normal and retina displays.

So the fix would probably involve scaling down this value in Device#getDPI() method so that this difference is not visible to API clients.

Here's an example of getDPI method being used in GEF, which I believe is on broken on Windows:

	protected double getDPU() {
		if (dpu <= 0) {
			if (getUnit() == RulerProvider.UNIT_PIXELS) {
				dpu = 1.0;
			} else {
				dpu = transposer
						.t(new Dimension(Display.getCurrent().getDPI())).height;
				if (getUnit() == RulerProvider.UNIT_CENTIMETERS) {
					dpu = dpu / 2.54;
				}
			}
			if (zoomManager != null) {
				dpu = dpu * zoomManager.getZoom();
			}
		}
		return dpu;
	}
Comment 3 Markus Keller CLA 2016-06-01 08:22:00 EDT
Looks like this is an old bug on SWT for Windows. But given that we invested so much in fixing platform differences for Neon, I think we should fix this one as well.

I only see a single caller of Display#getDPI() in the SDK, and that's in org.eclipse.swt.custom.CTabFolderRenderer.drawChevron(GC, Rectangle, int). The part tabs overflow chevron actually looks too small on Windows 200%, so this will even fix a visible bug.

Sravan is working on a fix.
Comment 4 Markus Keller CLA 2016-06-01 09:21:46 EDT
Created attachment 262161 [details]
ScalingData.java (snippet to print DPI, monitor bounds, etc.)
Comment 5 Eclipse Genie CLA 2016-06-01 09:56:38 EDT
New Gerrit change created: https://git.eclipse.org/r/74232
Comment 6 Sravan Kumar Lakkimsetti CLA 2016-06-01 10:53:11 EDT
(In reply to Eclipse Genie from comment #5)
> New Gerrit change created: https://git.eclipse.org/r/74232

The code change now is similar to linux. We get the dimensions and calculate the dpi based on the dimensions.
Comment 7 Niraj Modi CLA 2016-06-01 11:35:12 EDT
Created attachment 262167 [details]
IssueWithCTabFolder_LatestGerrit_Patch3

(In reply to Sravan Kumar Lakkimsetti from comment #6)
> (In reply to Eclipse Genie from comment #5)
> > New Gerrit change created: https://git.eclipse.org/r/74232
> 
> The code change now is similar to linux. We get the dimensions and calculate
> the dpi based on the dimensions.

Now we are getting DPI as {72, 72} on all zoom levels on Win7.

Also with latest Gerrit patch3, there is a side-effect in CTabFolder:
- The size of the number of Editors is increased, but it's getting clipped(only half drawn) Refer attachment.
Comment 8 Markus Keller CLA 2016-06-01 12:29:42 EDT
Patch Set 3 has compile errors, and the use of completely new OS APIs is a no-go at this point (RC4).

Returning {72, 72} on Windows is a no-go. It must stay {96, 96} at 100%, and it needs to become {96, 96} at 200% as well.

All OS APIs have some quirks around DPIs, and most older APIs just return a fixed "logical DPI" that is independent of the actual monitors connected. That's also the established practice of SWT's Display#getDPI() API.
Win32 & GTK: 96
Cocoa: 72

Patch Set 1 and 2 used DPIUtil.autoScaleDown (..). This produced the desired effect on Windows at 100% and 200%, and it matched the behavior on GTK and Cocoa

The only problem left with that patch is at fractional scale factors:
On Windows 7 at 125%, I get {120, 120}.
On GTK 3 at 125%, I get {96, 96}.
(On Cocoa, there are no fractional scale factors.)

The difference occurs because on GTK, we directly return values from GTK APIs, but on Windows, we pass the values through DPIUtil, which doesn't allow all scale factors by default (currently only allows integer scale factors).

For use cases like CTabFolderRenderer#drawChevron(GC, Rectangle, int) that try to use getDPI() to compute a font height, the different values at fractional scale factors are actually helpful, because the OS always scales font sizes with the exact scale factor. However, I'm pretty sure the drawChevron code is not actually accurate.


At this point (RC4), we should minimize risk and only fix the case that is actually supported but currently broken (Win32 at 200%). Let's use DPIUtil.autoScaleDown (..) for now and deal with the GTK/Win32 difference later.
Comment 9 Markus Keller CLA 2016-06-01 13:28:23 EDT
Filed bug 495203 to clean this up in 4.7.

Committers, please review https://git.eclipse.org/r/#/c/74232/5

Peter, you will get the right value on Windows at 200% (DPI=96). However, the DPI will continue to be != 96 at fractional scaling factors on Windows.

E.g. at 125% and 150% (where SWT doesn't auto-scale coordinates and images), Display#getDPI() values will be different on GTK and Windows (same as in Mars).
Comment 11 Niraj Modi CLA 2016-06-02 06:31:30 EDT
Verified fix in I20160601-2000 at 200% zoom on Win7.
Comment 12 Peter Severin CLA 2016-06-02 08:09:29 EDT
Thanks for the fix. I confirm that this fix works correctly for me in I20160601-2000. The fact that the UI is not scaled at fractional scaling factors is not ideal, however the final result is still correct. So in my case the returned DPI value is good both for 200% and for fractional scale factors.