JDK-7045370 : Java Statically Determines Display Size on Linux platforms
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 7
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2011-05-16
  • Updated: 2014-09-24
  • Resolved: 2011-12-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8 b17Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
SYNOPSIS
--------
Java Statically Determines Display Size on Linux platforms

OPERATING SYSTEM
----------------
Linux (tested on RHEL)

JDK VERSION
-----------
Reproducible with JDK 6u25
Reproducible with JDK 7b142

PROBLEM DESCRIPTION
-------------------
java.awt.Toolkit provides a getScreenSize() method that returns a java.awt.Dimension. The width and height of that Dimension are always the desktop resolution at the time the JVM is started. If the resolution changes while the JVM is running, the values in Dimension returned from getScreenSize() do not change.
                                         
java.awt.DisplayMode exhibits similar behavior. It provides a getWidth() method and getHeight() and the values do not change after a desktop resolution change.

REPRODUCTION INSTRUCTIONS
-------------------------
Testcases are attached.

Example Problem 1:
1. javac -d popup *.java
2. java popup.GE
3. Click 'Print Graphics info' to display current java graphics
   information including display width and height.
4. Change dispaly screen resolution.
5. Click 'Print Graphics info'again. It can be noticed that the graphics
   information displayed are not having updated display width and
   height.

Example Problem 2:
1. Change screen resolution to some lower value (say 1920x1200)
2. java popup.GE
3. PopupTest displays another window with a button. The button will
   display a JPopupMenu above the button when clicked.
4. Change screen resolution to some higher value (say 5760x1200).
5. Move the window past 1920, then click the button again. The popup
   menu wont paint past 1920 so it appears to float to the left of the
   window.

Comments
AWT_Graphics/Manual/LinuxGraphicsParamsTest/LinuxGraphicsParamsTest AWT_Graphics/Manual/LinuxScreenSizePopupTest/LinuxScreenSizePopupTest AWT_Graphics/Automated/LinuxDisplayResolutionTest/LinuxDisplayResolutionTest
12-08-2013

EVALUATION The DisplayChanged event should be generated whenever we receive a ConfigureNotify for the root window of the display. This way we get notiifed when the root window's geometry changes which actually means the display resolution change.
27-09-2011

SUGGESTED FIX --- old/src/solaris/classes/sun/awt/X11/XToolkit.java 2011-09-27 17:04:18.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XToolkit.java 2011-09-27 17:04:18.000000000 +0400 @@ -51,6 +51,7 @@ import sun.awt.*; import sun.font.FontConfigManager; import sun.font.FontManager; +import sun.java2d.SunGraphicsEnvironment; import sun.misc.PerformanceLogger; import sun.print.PrintJob2D; import sun.security.action.GetBooleanAction; @@ -109,7 +110,7 @@ static int awt_multiclick_time; static boolean securityWarningEnabled; - private static int screenWidth = -1, screenHeight = -1; // Dimensions of default screen + private static volatile int screenWidth = -1, screenHeight = -1; // Dimensions of default screen static long awt_defaultFg; // Pixel private static XMouseInfoPeer xPeer; private static Method m_removeSourceEvents; @@ -310,6 +311,19 @@ System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled); saved_error_handler = XlibWrapper.SetToolkitErrorHandler(); + + // Detect display mode changes + XlibWrapper.XSelectInput(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), XConstants.StructureNotifyMask); + XToolkit.addEventDispatcher(XToolkit.getDefaultRootWindow(), new XEventDispatcher() { + @Override + public void dispatchEvent(XEvent ev) { + if (ev.get_type() == XConstants.ConfigureNotify) { + ((X11GraphicsEnvironment)GraphicsEnvironment. + getLocalGraphicsEnvironment()). + displayChanged(); + } + } + }); } finally { awtUnlock(); } @@ -684,12 +698,36 @@ } } + static { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + if (ge instanceof SunGraphicsEnvironment) { + ((SunGraphicsEnvironment)ge).addDisplayChangedListener( + new DisplayChangedListener() { + @Override + public void displayChanged() { + // 7045370: Reset the cached values + XToolkit.screenWidth = -1; + XToolkit.screenHeight = -1; + } + + @Override + public void paletteChanged() {} + }); + } + } + static int getDefaultScreenWidth() { if (screenWidth == -1) { long display = getDisplay(); awtLock(); try { - screenWidth = (int) XlibWrapper.DisplayWidth(display, XlibWrapper.DefaultScreen(display)); + XWindowAttributes pattr = new XWindowAttributes(); + try { + XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), pattr.pData); + screenWidth = (int) pattr.get_width(); + } finally { + pattr.dispose(); + } } finally { awtUnlock(); } @@ -702,7 +740,13 @@ long display = getDisplay(); awtLock(); try { - screenHeight = (int) XlibWrapper.DisplayHeight(display, XlibWrapper.DefaultScreen(display)); + XWindowAttributes pattr = new XWindowAttributes(); + try { + XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), pattr.pData); + screenHeight = (int) pattr.get_height(); + } finally { + pattr.dispose(); + } } finally { awtUnlock(); } --- old/src/solaris/classes/sun/awt/X11GraphicsDevice.java 2011-09-27 17:04:19.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11GraphicsDevice.java 2011-09-27 17:04:19.000000000 +0400 @@ -487,14 +487,9 @@ * X11GraphicsEnvironment when the display mode has been changed. */ public synchronized void displayChanged() { - // reset the list of configs (and default config) - defaultConfig = null; - configs = null; - doubleBufferVisuals = null; - - // reset the native data structures associated with this device (they - // will be reinitialized when the GraphicsConfigs are configured) - resetNativeData(screen); + // On X11 the visuals do not change, and therefore we don't need + // to reset the defaultConfig, config, doubleBufferVisuals, + // neither do we need to reset the native data. // pass on to all top-level windows on this screen topLevels.notifyListeners(); --- old/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java 2011-09-27 17:04:20.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java 2011-09-27 17:04:20.000000000 +0400 @@ -430,6 +430,14 @@ return unionRect; } + @Override + public void displayChanged() { + // notify SunDisplayChanger list (e.g. VolatileSurfaceManagers and + // CachingSurfaceManagers) about the display change event + displayChanger.notifyListeners(); + // note: do not call super.displayChanged, we've already done everything + } + /** * From the DisplayChangedListener interface; devices do not need * to react to this event. --- old/src/solaris/native/sun/awt/awt_GraphicsEnv.c 2011-09-27 17:04:21.000000000 +0400 +++ new/src/solaris/native/sun/awt/awt_GraphicsEnv.c 2011-09-27 17:04:21.000000000 +0400 @@ -1434,11 +1434,17 @@ fbrects[screen].height); } else { + XWindowAttributes xwa; + memset(&xwa, 0, sizeof(xwa)); + + AWT_LOCK (); + XGetWindowAttributes(awt_display, + RootWindow(awt_display, adata->awt_visInfo.screen), + &xwa); + AWT_UNLOCK (); + bounds = (*env)->NewObject(env, clazz, mid, 0, 0, - DisplayWidth(awt_display, - adata->awt_visInfo.screen), - DisplayHeight(awt_display, - adata->awt_visInfo.screen)); + xwa.width, xwa.height); } if ((*env)->ExceptionOccurred(env)) {
27-09-2011

EVALUATION Interestingly, the DisplayHeight/XDeisplayHeight won't return a new height of the screen even after changing the current resolution. Looks like they return values cached in the Display structure which are not updated even after the disaply mode changes. We have to request the root window geometry instead.
22-09-2011

EVALUATION The XToolkit.getScreenWidth()/getScreenHeight() methods return cached values for the properties, hence we always get the same screen resolution. We could simply eliminate caching and always retrieve the up to date values from the native system. However, I expect that this may cause a significant performance regression on X11 systems. A more appropriate fix would probably involve a DisplayChanged listener and resetting the cached values whenever the display configuration changes.
13-09-2011