Created
October 10, 2019 20:17
-
-
Save RChehowski/dd69884c2cc347c9a76cf7a8e22f7f37 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.vizor; | |
import com.sun.jna.Pointer; | |
import com.sun.jna.platform.win32.User32; | |
import com.sun.jna.platform.win32.WinNT.HANDLE; | |
import com.sun.jna.platform.win32.WinUser; | |
import javafx.stage.Stage; | |
import java.lang.invoke.MethodHandle; | |
import java.lang.invoke.MethodHandles; | |
import java.lang.invoke.MethodType; | |
import java.util.List; | |
import java.util.Optional; | |
import static com.sun.jna.platform.win32.WinUser.FLASHW_ALL; | |
import static com.sun.jna.platform.win32.WinUser.FLASHW_TIMERNOFG; | |
public class WindowsFlash | |
{ | |
/** | |
* This check greatly increases the probability to retrieve exactly the same window that you've required | |
* since the JavaFX stage title must be exactly the same string as the one from the glass window. | |
* Otherwise we might get the wrong window with exactly the same name. | |
* | |
* @param stageWindowName JavaFX Stage window name. | |
* @param glassWindowName Native glass window name. | |
* | |
* @return Whether the two strings are identical. | |
*/ | |
@SuppressWarnings("StringEquality") | |
private static boolean stringsAreIdentical(final String stageWindowName, final String glassWindowName) | |
{ | |
return stageWindowName == glassWindowName; | |
} | |
/** | |
* Returns the JavaFX Stage native window handle for Windows. | |
* | |
* @param stage The JavaFX stage. | |
* | |
* @return An optional value containing the native window handle. | |
*/ | |
private static Optional<HANDLE> getStageHandle(final Stage stage) | |
{ | |
try | |
{ | |
final Class<?> glassWindowClass = Class.forName("com.sun.glass.ui.Window"); | |
final MethodHandle getTitleMethodHandle = MethodHandles.lookup() | |
.findVirtual(glassWindowClass, "getTitle", MethodType.methodType(String.class)); | |
final MethodHandle getNativeHandleMethodHandle = MethodHandles.lookup() | |
.findVirtual(glassWindowClass, "getNativeHandle", MethodType.methodType(long.class)); | |
final MethodHandle getWindows = MethodHandles.lookup() | |
.findStatic(glassWindowClass, "getWindows", MethodType.methodType(List.class)); | |
// Iterate through glass windows and find the right one | |
final List<?> glassWindows = (List<?>) getWindows.invoke(); | |
for (final Object glassWindow : glassWindows) | |
{ | |
final String stageWindowName = stage.getTitle(); | |
final String glassWindowName = (String) getTitleMethodHandle.invoke(glassWindow); | |
// Check strings identity, don't compare them | |
if (stringsAreIdentical(stageWindowName, glassWindowName)) | |
{ | |
final long nativeHandle = (long)getNativeHandleMethodHandle.invoke(glassWindow); | |
return Optional.of(new HANDLE(new Pointer(nativeHandle))); | |
} | |
} | |
// Unable to find the correct window | |
return Optional.empty(); | |
} | |
catch (Throwable throwable) | |
{ | |
// This may be a NPE, a reflective operation exception or a security exception | |
return Optional.empty(); | |
} | |
} | |
/** | |
* Flashes the specified window. It does not change the active state of the window. | |
* Silently does nothing if any error occurred. | |
* | |
* @param stage JavaFX stage to flash. | |
*/ | |
public static void flashWindowIcon(final Stage stage) | |
{ | |
getStageHandle(stage).ifPresent(windowHandle -> { | |
WinUser.FLASHWINFO info = new WinUser.FLASHWINFO(); | |
info.hWnd = windowHandle; | |
info.dwFlags = FLASHW_ALL | FLASHW_TIMERNOFG; | |
info.uCount = Integer.MAX_VALUE; | |
info.dwTimeout = 0; | |
User32.INSTANCE.FlashWindowEx(info); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment