Skip to content

Instantly share code, notes, and snippets.

@RChehowski
Created October 10, 2019 20:17
Show Gist options
  • Save RChehowski/dd69884c2cc347c9a76cf7a8e22f7f37 to your computer and use it in GitHub Desktop.
Save RChehowski/dd69884c2cc347c9a76cf7a8e22f7f37 to your computer and use it in GitHub Desktop.
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