changeset 1959:a8bab2b60b67 default tip

swing threading
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 04 Jun 2025 18:20:40 -0600
parents 156d7e77edf6
children
files src/goodjava/rpc/Rpc.java src/luan/modules/Rpc.luan src/luan/modules/swing/Awt_container.luan src/luan/modules/swing/Launcher.luan src/luan/modules/swing/ListLuan.java src/luan/modules/swing/Scroll_pane.luan src/luan/modules/swing/Swing.luan src/luan/modules/swing/SwingLuan.java src/luan/modules/swing/Swing_runner.luan src/luan/modules/swing/UndoManagerLuan.java src/luan/modules/swing/examples/hello_world.luan
diffstat 11 files changed, 142 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/src/goodjava/rpc/Rpc.java	Fri May 30 13:16:54 2025 -0600
+++ b/src/goodjava/rpc/Rpc.java	Wed Jun 04 18:20:40 2025 -0600
@@ -13,8 +13,6 @@
 	public static final RpcCall PING = new RpcCall("ping");
 	public static final String ECHO = "echo";
 
-	public static final RpcException COMMAND_NOT_FOUND = new RpcException("command_not_found");
-
 	public static boolean handle(RpcServer server,RpcCall call)
 		throws IOException
 	{
--- a/src/luan/modules/Rpc.luan	Fri May 30 13:16:54 2025 -0600
+++ b/src/luan/modules/Rpc.luan	Wed Jun 04 18:20:40 2025 -0600
@@ -7,7 +7,6 @@
 local RpcCall = require "java:goodjava.rpc.RpcCall"
 local RpcResult = require "java:goodjava.rpc.RpcResult"
 local RpcException = require "java:goodjava.rpc.RpcException"
-local JavaRpc = require "java:goodjava.rpc.Rpc"
 local LuanJava = require "java:luan.Luan"
 local JavaUtils = require "java:luan.modules.Utils"
 local IoLuan = require "java:luan.modules.IoLuan"
@@ -17,6 +16,7 @@
 local set_metatable = Luan.set_metatable or error()
 local ipairs = Luan.ipairs or error()
 local type = Luan.type or error()
+local stringify = Luan.stringify or error()
 local Boot = require "luan:Boot.luan"
 local Io = require "luan:Io.luan"
 local Thread = require "luan:Thread.luan"
@@ -145,7 +145,7 @@
 		end_if
 		local fn = fns[cmd]
 		if fn == nil then
-			server.write(JavaRpc.COMMAND_NOT_FOUND)
+			server.write(RpcException.new("command not found: "..cmd))
 			return
 		end_if
 		local rtn
@@ -212,28 +212,30 @@
 end
 Rpc.new_server_socket = new_server_socket
 
-local function new_server_fn(socket,fns)
-	return function()
-		local responder = nil
-		try
-			responder = rpc_responder(socket,fns)
-			while not responder.is_closed() do
-				responder.respond()
-			end
-		catch e
-			logger.info(e)
-		finally
-			responder and responder.after_close and responder.after_close()
+local function server_handler(socket,fns)
+	local responder = nil
+	try
+		responder = rpc_responder(socket,fns)
+		while not responder.is_closed() do
+			responder.respond()
 		end
+	catch e
+		logger.info(e)
+	finally
+		responder and responder.after_close and responder.after_close()
 	end
 end
-Rpc.new_server_fn = new_server_fn
+Rpc.server_handler = server_handler
 
-local function server_handler(socket,fns)
-	Thread.run(new_server_fn(socket,fns))
+local function multithreaded_server_handler(socket,fns)
+	Thread.run( function()
+		server_handler(socket,fns)
+	end )
 end
+Rpc.multithreaded_server_handler = multithreaded_server_handler
 
-local function serve_socket(socket_server,fns,handler)
+local function serve_socket(socket_server,handler,fns)
+	handler or error()
 	fns = fns or Rpc.functions
 	while true do
 		try
@@ -247,7 +249,7 @@
 
 function Rpc.serve(port,fns)
 	local socket_server = new_server_socket(port)
-	serve_socket(socket_server,fns,server_handler)
+	serve_socket(socket_server,multithreaded_server_handler,fns)
 end_function
 
 return Rpc
--- a/src/luan/modules/swing/Awt_container.luan	Fri May 30 13:16:54 2025 -0600
+++ b/src/luan/modules/swing/Awt_container.luan	Wed Jun 04 18:20:40 2025 -0600
@@ -11,6 +11,7 @@
 local from_dimension = Utils.from_dimension or error()
 local to_point = Utils.to_point or error()
 local from_point = Utils.from_point or error()
+require("luan:swing/Swing_runner.luan").check()
 local Font = require "luan:swing/Font.luan"
 local get_font = Font.get or error()
 local to_java_attributes = Font.to_java_attributes or error()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/swing/Launcher.luan	Wed Jun 04 18:20:40 2025 -0600
@@ -0,0 +1,45 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local String = require "luan:String.luan"
+local contains = String.contains or error()
+local Rpc = require "luan:Rpc.luan"
+local Logging = require "luan:logging/Logging.luan"
+local logger = Logging.logger "swing/Launcher"
+
+
+local Launcher = {}
+
+Launcher.port = 56587
+
+function Launcher.launch(open,reopen,args)
+	Rpc.cipher_suites = nil
+	local server_socket
+	try
+		server_socket = Rpc.new_server_socket(Launcher.port)
+	catch e
+		--logger.info(e.get_message())
+		if not contains( e.get_message(), "java.net.BindException" ) then
+			e.throw()
+		end
+		local host = Rpc.remote("localhost",Launcher.port)
+		host.reopen(args)
+		host.close()
+		return
+	end
+
+	local Swing_runner = require "luan:swing/Swing_runner.luan"
+	local swing_run = Swing_runner.run or error()
+	local swing_run_later = Swing_runner.run_later or error()
+
+	Rpc.functions.reopen = function(args)
+		swing_run_later( function()
+			reopen(args)
+		end )
+	end
+	swing_run( function()
+		open(args)
+	end )
+	Rpc.serve_socket(server_socket,Rpc.server_handler)
+end
+
+return Launcher
--- a/src/luan/modules/swing/ListLuan.java	Fri May 30 13:16:54 2025 -0600
+++ b/src/luan/modules/swing/ListLuan.java	Wed Jun 04 18:20:40 2025 -0600
@@ -19,10 +19,10 @@
 import java.awt.datatransfer.DataFlavor;
 import goodjava.logging.Logger;
 import goodjava.logging.LoggerFactory;
-import luan.Luan;
 import luan.LuanFunction;
 import luan.LuanTable;
 import luan.LuanException;
+import luan.modules.swing.SwingLuan;
 
 
 public class ListLuan extends JList<Object> {
@@ -139,13 +139,13 @@
 		repaint();
 	}
 
-	public void addListSelectionListener(final Luan luan,final LuanFunction fn) {
+	public void addListSelectionListener(final LuanFunction fn) {
 		addListSelectionListener( new ListSelectionListener() {
 			@Override public void valueChanged(ListSelectionEvent event) {
 				if( event.getValueIsAdjusting() )
 					return;
 				try {
-					fn.call(luan,getSelectedValue());
+					fn.call(SwingLuan.luan(),getSelectedValue());
 				} catch(LuanException e) {
 					SwingLuan.exception(e);
 				}
--- a/src/luan/modules/swing/Scroll_pane.luan	Fri May 30 13:16:54 2025 -0600
+++ b/src/luan/modules/swing/Scroll_pane.luan	Wed Jun 04 18:20:40 2025 -0600
@@ -8,8 +8,8 @@
 local Component = require "luan:swing/Component.luan"
 local super_construct = Component.construct or error()
 local super_mt = Component.mt or error()
-local Swing = require "luan:swing/Swing.luan"
-local run_later = Swing.run_later or error()
+local Swing_runner = require "luan:swing/Swing_runner.luan"
+local run_later = Swing_runner.run_later or error()
 require "java"
 local JScrollPane = require "java:javax.swing.JScrollPane"
 local Logging = require "luan:logging/Logging.luan"
--- a/src/luan/modules/swing/Swing.luan	Fri May 30 13:16:54 2025 -0600
+++ b/src/luan/modules/swing/Swing.luan	Wed Jun 04 18:20:40 2025 -0600
@@ -1,23 +1,19 @@
 local Luan = require "luan:Luan.luan"
 local error = Luan.error
 local ipairs = Luan.ipairs or error()
+require("luan:swing/Swing_runner.luan").check()
 require "java"
-local System = require "java:java.lang.System"
 local URI = require "java:java.net.URI"
 local Insets = require "java:java.awt.Insets"
 local Desktop = require "java:java.awt.Desktop"
 local UIManager = require "java:javax.swing.UIManager"
 local SwingConstants = require "java:javax.swing.SwingConstants"
-local FlatLightLaf = require "java:com.formdev.flatlaf.FlatLightLaf"
-local SwingLuan = require "java:luan.modules.swing.SwingLuan"
 local Logging = require "luan:logging/Logging.luan"
 local logger = Logging.logger "swing/Swing"
 
 
 local Swing = {}
 
-System.setProperty("apple.laf.useScreenMenuBar", "true")
-UIManager.setLookAndFeel(FlatLightLaf.new())
 
 function Swing.get_installed_look_and_feels()
 	local list = {}
@@ -34,9 +30,6 @@
 Swing.ui_manager_put = UIManager.put
 Swing.set_look_and_feel = UIManager.setLookAndFeel
 
-Swing.run = SwingLuan.run
-Swing.run_later = SwingLuan.runLater
-
 Swing.new_insets = Insets.new  -- top, left, bottom, right
 Swing.no_insets = Insets.new(0,0,0,0)
 
--- a/src/luan/modules/swing/SwingLuan.java	Fri May 30 13:16:54 2025 -0600
+++ b/src/luan/modules/swing/SwingLuan.java	Wed Jun 04 18:20:40 2025 -0600
@@ -36,6 +36,21 @@
 public class SwingLuan {
 	private static final Logger logger = LoggerFactory.getLogger(SwingLuan.class);
 
+	private static Luan luan;
+	static {
+		SwingUtilities.invokeLater(new Runnable() { public void run() {
+			luan = new Luan();
+		} } );
+	}
+
+	public static Luan luan() throws LuanException {
+		if( !SwingUtilities.isEventDispatchThread() )
+			throw new LuanException("Not in swing thread");
+		if( luan==null )
+			throw new LuanException("Not initialized");
+		return luan;
+	}
+
 	static void exception(LuanException e) {
 		System.err.println(e.getLuanStackTraceString());
 		System.exit(1);
@@ -45,11 +60,11 @@
 		exception( new LuanException(msg) );
 	}
 
-	private static Runnable runnable(final Luan luan,final LuanFunction fn) {
+	private static Runnable runnable(final LuanFunction fn) {
 		return new Runnable() {
 			public void run() {
 				try {
-					fn.call(luan);
+					fn.call(luan());
 				} catch(LuanException e) {
 					exception(e);
 				} catch(LuanRuntimeException e) {
@@ -59,15 +74,15 @@
 		};
 	}
 
-	public static void run(Luan luan,LuanFunction fn) throws InterruptedException, InvocationTargetException {
-		SwingUtilities.invokeAndWait(runnable(luan,fn));
+	public static void run(LuanFunction fn) throws InterruptedException, InvocationTargetException {
+		SwingUtilities.invokeAndWait(runnable(fn));
 	}
 
-	public static void runLater(Luan luan,LuanFunction fn) throws InterruptedException, InvocationTargetException {
-		SwingUtilities.invokeLater(runnable(luan,fn));
+	public static void runLater(LuanFunction fn) throws InterruptedException, InvocationTargetException {
+		SwingUtilities.invokeLater(runnable(fn));
 	}
 
-	public static ActionListener newActionListener(final Luan luan,final LuanFunction fn) throws LuanException {
+	public static ActionListener newActionListener(final LuanFunction fn) throws LuanException {
 		if( fn == null )
 			exception("function is null");
 		if( !fn.canTake(1) )
@@ -86,7 +101,7 @@
 					String action = event.getActionCommand();
 					if( action != null )
 						t.rawPut("action",action);
-					fn.call(luan,t);
+					fn.call(luan(),t);
 				} catch(LuanException e) {
 					//throw new LuanRuntimeException(e);
 					exception(e);
@@ -95,11 +110,11 @@
 		};
 	}
 
-	public static WindowListener newCloseListener(final Luan luan,final LuanFunction fn) {
+	public static WindowListener newCloseListener(final LuanFunction fn) {
 		return new WindowAdapter() {
 			@Override public void windowClosed(WindowEvent event) {
 				try {
-					fn.call(luan);
+					fn.call(luan());
 				} catch(LuanException e) {
 					exception(e);
 				}
@@ -107,11 +122,11 @@
 		};
 	}
 
-	public static WindowListener newWindowFocusListener(final Luan luan,final LuanFunction fn) {
+	public static WindowListener newWindowFocusListener(final LuanFunction fn) {
 		return new WindowAdapter() {
 			@Override public void windowGainedFocus(WindowEvent event) {
 				try {
-					fn.call(luan);
+					fn.call(luan());
 				} catch(LuanException e) {
 					exception(e);
 				}
@@ -119,11 +134,11 @@
 		};
 	}
 
-	public static ComponentListener newResizeListener(final Luan luan,final LuanFunction fn) {
+	public static ComponentListener newResizeListener(final LuanFunction fn) {
 		return new ComponentAdapter() {
 			@Override public void componentResized(ComponentEvent event) {
 				try {
-					fn.call(luan);
+					fn.call(luan());
 				} catch(LuanException e) {
 					exception(e);
 				}
@@ -151,11 +166,11 @@
 		} );
 	}
 
-	public static ComponentListener newMoveListener(final Luan luan,final LuanFunction fn) {
+	public static ComponentListener newMoveListener(final LuanFunction fn) {
 		return new ComponentAdapter() {
 			@Override public void componentMoved(ComponentEvent event) {
 				try {
-					fn.call(luan);
+					fn.call(luan());
 				} catch(LuanException e) {
 					exception(e);
 				}
@@ -163,11 +178,11 @@
 		};
 	}
 
-	public static ChangeListener newChangeListener(final Luan luan,final LuanFunction fn) {
+	public static ChangeListener newChangeListener(final LuanFunction fn) {
 		return new ChangeListener() {
 			@Override public void stateChanged(ChangeEvent event) {
 				try {
-					fn.call(luan);
+					fn.call(luan());
 				} catch(LuanException e) {
 					exception(e);
 				}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/swing/Swing_runner.luan	Wed Jun 04 18:20:40 2025 -0600
@@ -0,0 +1,27 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+require "java"
+local System = require "java:java.lang.System"
+local UIManager = require "java:javax.swing.UIManager"
+local SwingUtilities = require "java:javax.swing.SwingUtilities"
+local isEventDispatchThread = SwingUtilities.isEventDispatchThread
+local FlatLightLaf = require "java:com.formdev.flatlaf.FlatLightLaf"
+local SwingLuan = require "java:luan.modules.swing.SwingLuan"
+local Logging = require "luan:logging/Logging.luan"
+local logger = Logging.logger "swing/Swing_runner"
+
+
+System.setProperty("apple.laf.useScreenMenuBar", "true")
+UIManager.setLookAndFeel(FlatLightLaf.new())
+
+
+local Swing_runner = {}
+
+Swing_runner.run = SwingLuan.run
+Swing_runner.run_later = SwingLuan.runLater
+
+function Swing_runner.check()
+	isEventDispatchThread() or error "Not run in Swing thread"
+end
+
+return Swing_runner
--- a/src/luan/modules/swing/UndoManagerLuan.java	Fri May 30 13:16:54 2025 -0600
+++ b/src/luan/modules/swing/UndoManagerLuan.java	Wed Jun 04 18:20:40 2025 -0600
@@ -9,10 +9,10 @@
 import javax.swing.undo.CannotUndoException;
 import javax.swing.undo.CannotRedoException;
 import goodjava.util.GoodUtils;
-import luan.Luan;
 import luan.LuanFunction;
 import luan.LuanException;
 import luan.LuanRuntimeException;
+import luan.modules.swing.SwingLuan;
 import goodjava.logging.Logger;
 import goodjava.logging.LoggerFactory;
 
@@ -21,19 +21,14 @@
 	private static final Logger logger = LoggerFactory.getLogger(UndoManagerLuan.class);
 
 	private final WeakHashMap<LuanFunction,Boolean> map = new WeakHashMap<LuanFunction,Boolean>();
-	private final Luan luan;
 	private UndoableEdit unedited = null;
 	private CompoundEdit transaction;
 	private int transactionNesting = 0;
 
-	public UndoManagerLuan(Luan luan) {
-		this.luan = luan;
-	}
-
 	private void notifyListeners() {
 		for( LuanFunction fn : map.keySet() ) {
 			try {
-				fn.call(luan);
+				fn.call(SwingLuan.luan());
 			} catch(LuanException e) {
 				throw new LuanRuntimeException(e);
 			}
--- a/src/luan/modules/swing/examples/hello_world.luan	Fri May 30 13:16:54 2025 -0600
+++ b/src/luan/modules/swing/examples/hello_world.luan	Wed Jun 04 18:20:40 2025 -0600
@@ -1,13 +1,14 @@
 local Luan = require "luan:Luan.luan"
 local error = Luan.error
-local Swing = require "luan:swing/Swing.luan"
-local new_frame = require("luan:swing/Frame.luan").new or error()
-local new_label = require("luan:swing/Label.luan").new or error()
-local Border = require "luan:swing/Border.luan"
-local create_empty_border = Border.create_empty_border or error()
+local Swing_runner = require "luan:swing/Swing_runner.luan"
 
 
-Swing.run(function()
+Swing_runner.run(function()
+	local new_frame = require("luan:swing/Frame.luan").new or error()
+	local new_label = require("luan:swing/Label.luan").new or error()
+	local Border = require "luan:swing/Border.luan"
+	local create_empty_border = Border.create_empty_border or error()
+
 	local frame = new_frame{
 		content_pane = new_label{
 			text = "Hello World"