Testing: support interprocess Laf sync (enable/disable with Alt+Shift+S)

This commit is contained in:
Karl Tauber
2025-03-09 13:31:38 +01:00
parent 0bc2513c46
commit c486f695f2
4 changed files with 155 additions and 24 deletions

View File

@@ -156,6 +156,9 @@ class ControlBar
// register Alt+Shift+F1, F2, ... keys to change system scale factor
DemoPrefs.registerSystemScaleFactors( frame );
// register Alt+Shift+S to enable/disable interprocess Laf sync
DemoPrefs.initLafSync( frame );
// register ESC key to close frame
((JComponent)frame.getContentPane()).registerKeyboardAction(
e -> {

View File

@@ -16,8 +16,15 @@
package com.formdev.flatlaf.demo;
import java.awt.EventQueue;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.prefs.Preferences;
import javax.swing.JComponent;
import javax.swing.JFrame;
@@ -40,6 +47,7 @@ public class DemoPrefs
public static final String KEY_LAF_CLASS_NAME = "lafClassName";
public static final String KEY_LAF_THEME_FILE = "lafThemeFile";
public static final String KEY_SYSTEM_SCALE_FACTOR = "systemScaleFactor";
public static final String KEY_LAF_SYNC = "lafSync";
private static Preferences state;
@@ -58,7 +66,27 @@ public class DemoPrefs
try {
if( args.length > 0 )
UIManager.setLookAndFeel( args[0] );
else {
else
restoreLaf();
} catch( Throwable ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
// fallback
FlatLightLaf.setup();
}
// remember active look and feel
UIManager.addPropertyChangeListener( e -> {
if( "lookAndFeel".equals( e.getPropertyName() ) ) {
state.put( KEY_LAF_CLASS_NAME, UIManager.getLookAndFeel().getClass().getName() );
notifyLafChange();
}
} );
}
private static void restoreLaf()
throws Exception
{
String lafClassName = state.get( KEY_LAF_CLASS_NAME, FlatLightLaf.class.getName() );
if( FlatPropertiesLaf.class.getName().equals( lafClassName ) ||
IntelliJTheme.ThemeLaf.class.getName().equals( lafClassName ) )
@@ -77,25 +105,16 @@ public class DemoPrefs
} else
UIManager.setLookAndFeel( lafClassName );
}
} catch( Throwable ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
// fallback
FlatLightLaf.setup();
}
// remember active look and feel
UIManager.addPropertyChangeListener( e -> {
if( "lookAndFeel".equals( e.getPropertyName() ) )
state.put( KEY_LAF_CLASS_NAME, UIManager.getLookAndFeel().getClass().getName() );
} );
}
public static void initSystemScale() {
if( System.getProperty( "sun.java2d.uiScale" ) == null ) {
String scaleFactor = getState().get( KEY_SYSTEM_SCALE_FACTOR, null );
if( scaleFactor != null )
String scaleFactor = state.get( KEY_SYSTEM_SCALE_FACTOR, null );
if( scaleFactor != null ) {
System.setProperty( "sun.java2d.uiScale", scaleFactor );
System.out.println( "FlatLaf: setting 'sun.java2d.uiScale' to " + scaleFactor );
System.out.println( " use 'Alt+Shift+F1...12' to change it to 1x...4x" );
}
}
}
@@ -146,10 +165,113 @@ public class DemoPrefs
return;
if( scaleFactor != null )
DemoPrefs.getState().put( KEY_SYSTEM_SCALE_FACTOR, scaleFactor );
state.put( KEY_SYSTEM_SCALE_FACTOR, scaleFactor );
else
DemoPrefs.getState().remove( KEY_SYSTEM_SCALE_FACTOR );
state.remove( KEY_SYSTEM_SCALE_FACTOR );
System.exit( 0 );
}
//---- inter-process Laf change notification/synchronisation --------------
// used for FlatLaf development when running multiple testing apps
private static final String MULTICAST_ADDRESS = "224.63.31.41";
private static final int MULTICAST_PORT = 36584;
private static final long PROCESS_ID = System.nanoTime();
private static Thread thread;
private static boolean notifyEnabled = true;
public static void initLafSync( JFrame frame ) {
((JComponent)frame.getContentPane()).registerKeyboardAction(
e -> enableDisableLafSync(),
KeyStroke.getKeyStroke( "alt shift S" ),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
if( state.getBoolean( KEY_LAF_SYNC, false ) ) {
System.out.println( "FlatLaf: theme sync enabled; use Alt+Shift+S to disable it" );
listenToLafChange();
}
}
private static void enableDisableLafSync() {
boolean enabled = !state.getBoolean( KEY_LAF_SYNC, false );
state.putBoolean( KEY_LAF_SYNC, enabled );
if( enabled )
listenToLafChange();
else if( thread != null) {
thread.interrupt();
thread = null;
}
}
private static void listenToLafChange() {
if( thread != null )
return;
thread = new Thread( "FlatLaf Laf change listener" ) {
MulticastSocket socket;
@Override
public void run() {
try( MulticastSocket socket = new MulticastSocket( MULTICAST_PORT ) ) {
this.socket = socket;
socket.joinGroup( InetAddress.getByName( MULTICAST_ADDRESS ) );
byte[] buffer = new byte[Long.BYTES];
for(;;) {
DatagramPacket packet = new DatagramPacket( buffer, buffer.length );
socket.receive( packet );
long id = ByteBuffer.wrap( buffer ).getLong();
if( id == PROCESS_ID )
continue; // was sent from this process
EventQueue.invokeLater( () -> {
notifyEnabled = false;
try {
restoreLaf();
FlatLaf.updateUI();
} catch( Throwable ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
} finally {
notifyEnabled = true;
}
} );
}
} catch( IOException ex ) {
if( ex instanceof SocketException && "Socket closed".equals( ex.getMessage() ) )
return; // interrupted
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
@Override
public void interrupt() {
super.interrupt();
socket.close();
}
};
thread.setDaemon( true );
thread.start();
}
private static void notifyLafChange() {
if( thread == null || !notifyEnabled )
return;
EventQueue.invokeLater( () -> {
try( MulticastSocket socket = new MulticastSocket() ) {
InetAddress address = InetAddress.getByName( MULTICAST_ADDRESS );
byte[] buffer = ByteBuffer.wrap( new byte[Long.BYTES] ).putLong( PROCESS_ID ).array();
DatagramPacket packet = new DatagramPacket( buffer, buffer.length, address, MULTICAST_PORT );
socket.send( packet );
} catch( IOException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
} );
}
}

View File

@@ -142,6 +142,9 @@ public class FlatSingleComponentTest
// register Alt+Shift+F1, F2, ... keys to change system scale factor
DemoPrefs.registerSystemScaleFactors( this );
// register Alt+Shift+S to enable/disable interprocess Laf sync
DemoPrefs.initLafSync( this );
// register Alt+R key to toggle component orientation
registerKey( "alt R", () -> {
applyComponentOrientation( getComponentOrientation().isLeftToRight()

View File

@@ -176,6 +176,9 @@ public class FlatTestFrame
// register Alt+Shift+F1, F2, ... keys to change system scale factor
DemoPrefs.registerSystemScaleFactors( this );
// register Alt+Shift+S to enable/disable interprocess Laf sync
DemoPrefs.initLafSync( this );
// register Ctrl+0, Ctrl++ and Ctrl+- to change font size
registerKey( SystemInfo.isMacOS ? "meta 0" : "ctrl 0", () -> restoreFont() );
registerKey( SystemInfo.isMacOS ? "meta PLUS" : "ctrl PLUS", () -> incrFont() );