OpenJDK / openjfx / 8u-dev / rt
changeset 6994:f29a46d66886
[Accessibility, Windows] Implement HighContrast Mode Detection
author | Joseph Andresen <joseph.andresen@oracle.com> |
---|---|
date | Mon, 12 May 2014 14:23:10 -0700 |
parents | 9a883f78c710 |
children | 5b683dba59a5 |
files | apps/toys/Hello/src/main/java/hello/HelloHighContrast.java modules/graphics/src/main/java/com/sun/glass/ui/Application.java modules/graphics/src/main/java/com/sun/glass/ui/win/WinApplication.java modules/graphics/src/main/java/com/sun/javafx/application/PlatformImpl.java modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java modules/graphics/src/main/java/com/sun/javafx/tk/quantum/QuantumToolkit.java modules/graphics/src/main/native-glass/win/GlassApplication.cpp modules/graphics/src/main/native-glass/win/GlassApplication.h modules/graphics/src/main/native-glass/win/Utils.h |
diffstat | 10 files changed, 266 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/apps/toys/Hello/src/main/java/hello/HelloHighContrast.java Mon May 12 14:23:10 2014 -0700 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package hello; + +import com.sun.javafx.css.StyleManager; +import javafx.application.Application; +import javafx.geometry.Insets; +import javafx.scene.Scene; +import javafx.scene.control.ToggleButton; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +public class HelloHighContrast extends Application { + + private static final String MODENA_PATH = "com/sun/javafx/scene/control/skin/modena/"; + private String lastStyleUsed = null; + + public static void main(String[] args) { + Application.launch(args); + } + + @Override public void start(Stage stage) { + final ToggleGroup group = new ToggleGroup(); + group.selectedToggleProperty().addListener(ov -> { + // remove old style + if (lastStyleUsed != null) { + StyleManager.getInstance().removeUserAgentStylesheet(MODENA_PATH + lastStyleUsed); + lastStyleUsed = null; + } + + // install new style + String userData = (String) group.getSelectedToggle().getUserData(); + if (userData != null) { + lastStyleUsed = userData; + StyleManager.getInstance().addUserAgentStylesheet(MODENA_PATH + userData); + } + }); + + ToggleButton disableHighContrast = new ToggleButton("Disable High Contrast"); + disableHighContrast.setMaxWidth(Double.MAX_VALUE); + disableHighContrast.setUserData(null); + disableHighContrast.setToggleGroup(group); + disableHighContrast.setSelected(true); + + ToggleButton whiteOnBlackBtn = new ToggleButton("White on black"); + whiteOnBlackBtn.setMaxWidth(Double.MAX_VALUE); + whiteOnBlackBtn.setUserData("whiteOnBlack.css"); + whiteOnBlackBtn.setToggleGroup(group); + + ToggleButton blackOnWhiteBtn = new ToggleButton("Black on white"); + blackOnWhiteBtn.setMaxWidth(Double.MAX_VALUE); + blackOnWhiteBtn.setUserData("blackOnWhite.css"); + blackOnWhiteBtn.setToggleGroup(group); + + ToggleButton yellowOnBlackBtn = new ToggleButton("Yellow on black"); + yellowOnBlackBtn.setMaxWidth(Double.MAX_VALUE); + yellowOnBlackBtn.setUserData("yellowOnBlack.css"); + yellowOnBlackBtn.setToggleGroup(group); + + VBox vbox = new VBox(10, disableHighContrast, whiteOnBlackBtn, blackOnWhiteBtn, yellowOnBlackBtn); + vbox.setPadding(new Insets(10)); + + Scene scene = new Scene(vbox); + + stage.setScene(scene); + stage.setWidth(200); + stage.setHeight(200); + stage.show(); + } +} \ No newline at end of file
--- a/modules/graphics/src/main/java/com/sun/glass/ui/Application.java Tue May 13 08:51:11 2014 +1200 +++ b/modules/graphics/src/main/java/com/sun/glass/ui/Application.java Mon May 12 14:23:10 2014 -0700 @@ -86,7 +86,10 @@ } // currently used only on Mac OS X public void handleQuitAction(Application app, long time) { - } + } + public boolean handleThemeChanged(String themeName) { + return false; + } } private EventHandler eventHandler; @@ -254,6 +257,14 @@ } } + private boolean notifyThemeChanged(String themeName) { + EventHandler handler = getEventHandler(); + if (handler != null) { + return handler.handleThemeChanged(themeName); + } + return false; + } + private void notifyDidResignActive() { EventHandler handler = getEventHandler(); if (handler != null) { @@ -660,6 +671,15 @@ protected abstract int staticView_getMultiClickMaxX(); protected abstract int staticView_getMultiClickMaxY(); + /** + * Gets the Name of the currently active high contrast theme. + * If null, then high contrast is not enabled. + */ + public String getHighContrastTheme() { + checkEventThread(); + return null; + } + protected boolean _supportsInputMethods() { // Overridden in subclasses return false;
--- a/modules/graphics/src/main/java/com/sun/glass/ui/win/WinApplication.java Tue May 13 08:51:11 2014 +1200 +++ b/modules/graphics/src/main/java/com/sun/glass/ui/win/WinApplication.java Mon May 12 14:23:10 2014 -0700 @@ -257,6 +257,12 @@ } } + private native String _getHighContrastTheme(); + @Override public String getHighContrastTheme() { + checkEventThread(); + return _getHighContrastTheme(); + } + @Override protected boolean _supportsInputMethods() { return true;
--- a/modules/graphics/src/main/java/com/sun/javafx/application/PlatformImpl.java Tue May 13 08:51:11 2014 +1200 +++ b/modules/graphics/src/main/java/com/sun/javafx/application/PlatformImpl.java Mon May 12 14:23:10 2014 -0700 @@ -537,6 +537,63 @@ } } + private static String accessibilityTheme; + public static boolean setAccessibilityTheme(String platformTheme) { + if (accessibilityTheme != null) { + StyleManager.getInstance().removeUserAgentStylesheet(accessibilityTheme); + accessibilityTheme = null; + } + + // check to see if there is an override to enable a high-contrast theme + final String userTheme = AccessController.doPrivileged( + (PrivilegedAction<String>) () -> System.getProperty("com.sun.javafx.highContrastTheme")); + + if (isCaspian()) { + if (platformTheme != null || userTheme != null) { + // caspian has only one high contrast theme, use it regardless of the user or platform theme. + accessibilityTheme = "com/sun/javafx/scene/control/skin/caspian/highcontrast.css"; + } + } else if (isModena()) { + // User-defined property takes precedence + if (userTheme != null) { + switch (userTheme.toUpperCase()) { + case "BLACKONWHITE": + accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/blackOnWhite.css"; + break; + case "WHITEONBLACK": + accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/whiteOnBlack.css"; + break; + case "YELLOWONBLACK": + accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/yellowOnBlack.css"; + break; + default: + } + } else { + if (platformTheme != null) { + // The following names are Platform specific (Windows 7 and 8) + switch (platformTheme) { + case "High Contrast White": + accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/blackOnWhite.css"; + break; + case "High Contrast Black": + accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/whiteOnBlack.css"; + break; + case "High Contrast #1": + case "High Contrast #2": //TODO #2 should be green on black + accessibilityTheme = "com/sun/javafx/scene/control/skin/modena/yellowOnBlack.css"; + break; + default: + } + } + } + } + if (accessibilityTheme != null) { + StyleManager.getInstance().addUserAgentStylesheet(accessibilityTheme); + return true; + } + return false; + } + private static void _setPlatformUserAgentStylesheet(String stylesheetUrl) { isModena = isCaspian = false; // check for command line override @@ -603,26 +660,11 @@ return null; } ); - - // check to see if there is an override to enable a high-contrast theme - final String highContrastName = AccessController.doPrivileged( - (PrivilegedAction<String>) () -> System.getProperty("com.sun.javafx.highContrastTheme")); - if (highContrastName != null) { - switch (highContrastName.toUpperCase()) { - case "BLACKONWHITE": StyleManager.getInstance().addUserAgentStylesheet( - "com/sun/javafx/scene/control/skin/modena/blackOnWhite.css"); - break; - case "WHITEONBLACK": StyleManager.getInstance().addUserAgentStylesheet( - "com/sun/javafx/scene/control/skin/modena/whiteOnBlack.css"); - break; - case "YELLOWONBLACK": StyleManager.getInstance().addUserAgentStylesheet( - "com/sun/javafx/scene/control/skin/modena/yellowOnBlack.css"); - break; - } - } } else { StyleManager.getInstance().setDefaultUserAgentStylesheet(stylesheetUrl); } + // Ensure that accessibility starts right + setAccessibilityTheme(Toolkit.getToolkit().getThemeName()); } public static void addNoTransparencyStylesheetToScene(final Scene scene) {
--- a/modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java Tue May 13 08:51:11 2014 +1200 +++ b/modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java Mon May 12 14:23:10 2014 -0700 @@ -25,6 +25,7 @@ package com.sun.javafx.css; +import javafx.application.Application; import javafx.css.Styleable; import java.io.FileNotFoundException; import java.io.FilePermission; @@ -1272,6 +1273,41 @@ CssError.setCurrentScene(null); } + + /** + * Removes the specified stylesheet from the application default user agent + * stylesheet list. + * @param url The file URL, either relative or absolute, as a String. + */ + public void removeUserAgentStylesheet(String url) { + if (url == null ) { + throw new IllegalArgumentException("null arg url"); + } + + final String fname = url.trim(); + if (fname.isEmpty()) { + return; + } + + // if we already have this stylesheet, remove it! + boolean removed = false; + for (int n = platformUserAgentStylesheetContainers.size() - 1; n >= 0; n--) { + // don't remove the platform default user agent stylesheet + if (fname.equals(Application.getUserAgentStylesheet())) { + continue; + } + + StylesheetContainer container = platformUserAgentStylesheetContainers.get(n); + if (fname.equals(container.fname)) { + platformUserAgentStylesheetContainers.remove(n); + removed = true; + } + } + + if (removed) { + userAgentStylesheetsChanged(); + } + } /** * Set the user agent stylesheet. This is the base default stylesheet for
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java Tue May 13 08:51:11 2014 +1200 +++ b/modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java Mon May 12 14:23:10 2014 -0700 @@ -922,4 +922,7 @@ return imageAccessor; } + public String getThemeName() { + return null; + } }
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/QuantumToolkit.java Tue May 13 08:51:11 2014 +1200 +++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/QuantumToolkit.java Mon May 12 14:23:10 2014 -0700 @@ -82,6 +82,7 @@ import com.sun.glass.ui.Timer; import com.sun.glass.ui.View; import com.sun.javafx.PlatformUtil; +import com.sun.javafx.application.PlatformImpl; import com.sun.javafx.embed.HostInterface; import com.sun.javafx.geom.Path2D; import com.sun.javafx.geom.PathIterator; @@ -310,6 +311,10 @@ @Override public void handleQuitAction(Application app, long time) { GlassStage.requestClosingAllWindows(); } + + @Override public boolean handleThemeChanged(String themeName) { + return PlatformImpl.setAccessibilityTheme(themeName); + } }); } launchLatch.countDown(); @@ -1487,4 +1492,9 @@ public int getMultiClickMaxY() { return View.getMultiClickMaxY(); } + + @Override + public String getThemeName() { + return Application.GetApplication().getHighContrastTheme(); + } }
--- a/modules/graphics/src/main/native-glass/win/GlassApplication.cpp Tue May 13 08:51:11 2014 +1200 +++ b/modules/graphics/src/main/native-glass/win/GlassApplication.cpp Mon May 12 14:23:10 2014 -0700 @@ -123,6 +123,18 @@ return szGlassToolkitWindow; } +jstring GlassApplication::GetThemeName(JNIEnv* env) +{ + HIGHCONTRAST contrastInfo; + contrastInfo.cbSize = sizeof(HIGHCONTRAST); + ::SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(HIGHCONTRAST), &contrastInfo, 0); + if (contrastInfo.dwFlags & HCF_HIGHCONTRASTON) { + size_t length = wcslen(contrastInfo.lpszDefaultScheme); + return env->NewString((jchar*)contrastInfo.lpszDefaultScheme, length); + } + return NULL; +} + LRESULT GlassApplication::WindowProc(UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { @@ -174,6 +186,13 @@ case WM_DISPLAYCHANGE: GlassScreen::HandleDisplayChange(); break; + case WM_THEMECHANGED: { + JNIEnv* env = GetEnv(); + jstring themeName = GlassApplication::GetThemeName(env); + jboolean result = env->CallBooleanMethod(m_grefThis, javaIDs.Application.notifyThemeChangedMID, themeName); + if (CheckAndClearException(env)) return 1; + return !result; + } } return ::DefWindowProc(GetHWND(), msg, wParam, lParam); } @@ -333,6 +352,11 @@ ASSERT(javaIDs.Application.reportExceptionMID); if (CheckAndClearException(env)) return; + javaIDs.Application.notifyThemeChangedMID = + env->GetMethodID(cls, "notifyThemeChanged", "(Ljava/lang/String;)Z"); + ASSERT(javaIDs.Application.notifyThemeChangedMID); + if (CheckAndClearException(env)) return; + //NOTE: substitute the cls cls = (jclass)env->FindClass("java/lang/Runnable"); if (CheckAndClearException(env)) return; @@ -427,6 +451,17 @@ /* * Class: com_sun_glass_ui_win_WinApplication + * Method: _getHighContrastTheme + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_sun_glass_ui_win_WinApplication__1getHighContrastTheme + (JNIEnv * env, jobject self) +{ + return GlassApplication::GetThemeName(env); +} + +/* + * Class: com_sun_glass_ui_win_WinApplication * Method: _leaveNestedEventLoopImpl * Signature: (Ljava/lang/Object;)V */
--- a/modules/graphics/src/main/native-glass/win/GlassApplication.h Tue May 13 08:51:11 2014 +1200 +++ b/modules/graphics/src/main/native-glass/win/GlassApplication.h Mon May 12 14:23:10 2014 -0700 @@ -81,6 +81,7 @@ static void ExecActionLater(Action *action); void RegisterClipboardViewer(jobject clipboard); void UnregisterClipboardViewer(); + static jstring GetThemeName(JNIEnv* env); inline static DWORD GetMainThreadId() {
--- a/modules/graphics/src/main/native-glass/win/Utils.h Tue May 13 08:51:11 2014 +1200 +++ b/modules/graphics/src/main/native-glass/win/Utils.h Mon May 12 14:23:10 2014 -0700 @@ -502,6 +502,7 @@ } Screen; struct { jmethodID reportExceptionMID; + jmethodID notifyThemeChangedMID; } Application; } JavaIDs;