[snow-cvs] r36 - in trunk: docs src/java/snow/swing src/lisp/snow src/lisp/snow/swing

Alessio Stalla astalla at common-lisp.net
Sat Dec 12 09:58:52 UTC 2009


Author: astalla
Date: Sat Dec 12 04:58:51 2009
New Revision: 36

Log:
Fixed some dynamic environment handling
Updated tutorial


Modified:
   trunk/docs/tutorial.html
   trunk/src/java/snow/swing/ConsoleDocument.java
   trunk/src/lisp/snow/snow.lisp
   trunk/src/lisp/snow/swing/swing.lisp

Modified: trunk/docs/tutorial.html
==============================================================================
--- trunk/docs/tutorial.html	(original)
+++ trunk/docs/tutorial.html	Sat Dec 12 04:58:51 2009
@@ -23,7 +23,7 @@
   <li><h4>Java applications:</h4>simply make sure snow.jar and all the jars in the lib/ folder are in the classpath of your application. Snow uses JSR-223 and is built with Java 1.6, so that's the minimum Java version you can use. However, it should be possible to run Snow on 1.5 as well, but you'll need to recompile both Snow and ABCL from sources with a JSR-223 implementation in your classpath. See the <a href="#embedding">Embedding Snow</a> section below for details about using Snow inside your Java application.</li>
   <li><h4>Lisp applications:</h4>
     <ul>
-      <li>Snow come prepackaged with ABCL 0.16, and it wraps the ABCL launcher with its own, that makes sure to load Snow prior to your application. So you can just follow the procedure for Java applications above, and use the snow.Snow class in place of org.armedbear.lisp.Main as the main Java class to launch, e.g. via a shell script. The only difference is that, when launched with no command-line switches, Snow will pop up a GUI repl. You can pass a dummy --no-gui-repl switch to inhibit that. If you are new to Java, the classpath is a list of search places that the JVM uses to resolve classes (think asdf:*central-registry* if you will). It can be set with the environment variable CLASSPATH or with the -classpath command line switch to the java bytecode interpreter (the 'java' command). It is a list of directories and/or .jar files, separated by a platform-dependent character (':' on Linux, ';' on Windows, I don't know about Macs). So for example, you can launch Snow on Linux with '<code>java -classpath snow.jar:lib/abcl.jar:lib/binding-2.0.6.jar:lib/commons-logging.jar:lib/miglayout-3.6.2.jar snow.Snow</code>'.</li>
+      <li>Snow comes prepackaged with ABCL 0.17, and it wraps the ABCL launcher with its own, that makes sure to load Snow prior to your application. So you can just follow the procedure for Java applications above, and use the snow.Snow class in place of org.armedbear.lisp.Main as the main Java class to launch, e.g. via a shell script. The only difference is that, when launched with no command-line switches, Snow will pop up a GUI repl. You can pass a dummy --no-gui-repl switch to inhibit that. If you are new to Java, the classpath is a list of search places that the JVM uses to resolve classes (think asdf:*central-registry* if you will). It can be set with the environment variable CLASSPATH or with the -classpath command line switch to the java bytecode interpreter (the 'java' command). It is a list of directories and/or .jar files, separated by a platform-dependent character (':' on Linux, ';' on Windows, I don't know about Macs). So for example, you can launch Snow on Linux with '<code>java -classpath snow.jar:lib/abcl.jar:lib/binding-2.0.6.jar:lib/commons-logging.jar:lib/miglayout-3.7.1.jar snow.Snow</code>'.</li>
       <li>Also, Snow has its own version of Cells built in. It is a random, but fairly recent version from CVS, with some fixes to make it run on ABCL. I'm looking forward to having those fixes merged with trunk, so you'll be able to freely update Cells independently.</li>
       <li>Last but not least, Snow is built with ASDF, so if you are brave enough you can extract the contents of snow.jar (it is a regular zip file), it will create a directory tree full of .lisp source files, fasls and compiled Java classes (.class files). You will then be able to load Snow with ASDF using your own version of ABCL and/or Cells, provided you still meet the requirements about the classpath for Java applications. (there are two .asd files, one in snow/ and one in snow/swing).</li>
     </ul>
@@ -46,7 +46,7 @@
   (pack self)
   (show self))
 </pre>
-Evaluating this will show a window containing a single button which, when pressed, will output "Hello, world!". The terminology should be familiar to Swing developers. Actually, the output from the button will NOT go to the REPL, but to the OS console instead; I'll explain this later, please ignore it for now. <br />
+Evaluating this will show a window containing a single button which, when pressed, will output "Hello, world!". The terminology should be familiar to Swing developers.<br />
 The REPL is great for experimenting: the code you input is immediately executed by an interpreter. You can also compile your code, either on the fly in the REPL or from a file; this is outside the scope of this tutorial, but you can find more information in any decent tutorial or book about Common Lisp (I suggest the free ebook Practical Common Lisp by Peter Seibel, available at <a href="http://gigamonkeys.com/book/">http://gigamonkeys.com/book/</a>). However, experiments sometimes go wrong; if you make a mistake - for example, evaluating an unexisting function - you will end in the debugger. Try typing the function call
 <pre class="paste-area">
 (oh-no!)
@@ -78,7 +78,29 @@
 <h4>How does this work?</h4>
 The Snow API consists of a set of macros that can be used to declaratively construct a tree of widgets. These macros are designed in such a way to make the tree structure of Lisp source code closely mirror the GUI widget tree structure (in the general case). The macros expand to code that uses a functional interface to create widgets, however it is not recommended to use this functional API directly since it depends on the context established by the macros.
 
-The aspects of such context of interest to the user are:
+The main user-level aspects of the Snow API are:
+
+<h4>macro <code>with-gui</code></h4>
+
+The macro <code>with-gui (&rest args) &body body</code> is used to run Snow code in the appropriate context (i.e., in a GUI-backend-specific thread, with some special bindings established). All Snow code must be run in the dynamic scope of a with-gui invocation; consequences are undefined if this rule is violated. This usually means that you should only use with-gui in the top-level function(s) that create the GUI. Moreover, if you write code that dinamically changes your GUI after it has been created independently on event handling you should wrap that code in with-gui too.<br /> 
+Snow automatically takes care of setting up the right environment inside event-handling callbacks, so you're not required to use with-gui there, even if you modify the GUI. Code run from the Snow REPL is also automatically evaluated in the right context.<br />
+<strong>Examples:</strong>
+<pre class="paste-area">
+<span class="lisp-comment">;; This function presumably is called to initialize the GUI so with-gui is required.</span>
+(<span class="lisp-cl-macro">defun</span> make-main-frame (title)
+  (with-gui ()
+    (frame (<span class="lisp-keyword">:title</span> title)
+      (make-some-button))))
+
+<span class="lisp-comment">;; This function is meant to be only called by GUI-making functions: it can assume that with-gui has been called by some other function higher on the call stack, and can avoid using it.</span>
+(<span class="lisp-cl-macro">defun</span> make-some-button ()
+  (button <span class="lisp-keyword">:text</span> <span class="lisp-string">"Some"</span> :on-action #'handle-some-action))
+
+<span class="lisp-comment">;; This function is an event handler: Snow will automatically run it in the proper context, so with-gui is not required</span>
+(<span class="lisp-cl-macro">defun</span> handle-some-action ()
+  (print <span class="lisp-string">"Hooray!"</span>))
+</pre>
+
 
 <h4>lexical variable <code>self</code></h4>
 

Modified: trunk/src/java/snow/swing/ConsoleDocument.java
==============================================================================
--- trunk/src/java/snow/swing/ConsoleDocument.java	(original)
+++ trunk/src/java/snow/swing/ConsoleDocument.java	Sat Dec 12 04:58:51 2009
@@ -35,6 +35,7 @@
 import java.awt.Window;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.IOException;
@@ -272,6 +273,7 @@
 		    LispThread.currentThread().bindSpecial(Symbol.DEBUGGER_HOOK, debuggerHook);
 		    LispThread.currentThread().bindSpecial(Symbol.STANDARD_INPUT, in);
 		    LispThread.currentThread().bindSpecial(Symbol.STANDARD_OUTPUT, out);
+		    LispThread.currentThread().bindSpecial(Symbol.ERROR_OUTPUT, out);
 		    LispThread.currentThread().bindSpecial(Symbol.TERMINAL_IO, ioStream);
 		    LispThread.currentThread().bindSpecial(Symbol.DEBUG_IO, ioStream);
 		    LispThread.currentThread().bindSpecial(Symbol.QUERY_IO, ioStream);
@@ -284,11 +286,12 @@
 	};
     }
 	
-    public void disposeOnClose(Window parent) {
+    public void disposeOnClose(final Window parent) {
 	parent.addWindowListener(new WindowAdapter() {
 		@Override
 		public void windowClosing(WindowEvent e) {
 		    dispose();
+		    parent.removeWindowListener(this);
 		}
 	    });
     }

Modified: trunk/src/lisp/snow/snow.lisp
==============================================================================
--- trunk/src/lisp/snow/snow.lisp	(original)
+++ trunk/src/lisp/snow/snow.lisp	Sat Dec 12 04:58:51 2009
@@ -63,18 +63,25 @@
 (defvar *dynamic-environment* nil)
 
 (defmacro with-snow-dynamic-environment (&body body)
-  (with-unique-names (gui-backend-var package-var terminal-io-var)
+  (with-unique-names (gui-backend-var package-var terminal-io-var
+		      standard-input-var standard-output-var error-output-var)
     `(if *dynamic-environment*
 	 (with-dynamic-environment (*dynamic-environment*)
 	   , at body)
 	 (let* ((,gui-backend-var *gui-backend*)
 		(,package-var *package*)
-		(,terminal-io-var *terminal-io*)) ;;Etc...
+		(,terminal-io-var *terminal-io*)
+		(,standard-input-var *standard-input*)
+		(,standard-output-var *standard-output*)
+		(,error-output-var *error-output*)) ;;Etc...
        (dynamic-wind
 	(let ((*gui-backend* ,gui-backend-var)
 	      (*package* ,package-var)
 	      (*debugger-hook* *graphical-debugger-hook*)
-	      (*terminal-io* ,terminal-io-var))
+	      (*terminal-io* ,terminal-io-var)
+	      (*standard-input* ,standard-input-var)
+	      (*standard-output* ,standard-output-var)
+	      (*error-output* ,error-output-var))
 	  (proceed
 	   (let ((*dynamic-environment* (capture-dynamic-environment)))
 	     (with-dynamic-environment (*dynamic-environment*)

Modified: trunk/src/lisp/snow/swing/swing.lisp
==============================================================================
--- trunk/src/lisp/snow/swing/swing.lisp	(original)
+++ trunk/src/lisp/snow/swing/swing.lisp	Sat Dec 12 04:58:51 2009
@@ -41,13 +41,15 @@
 (defun make-action-listener (obj)
   (if (or (functionp obj) (symbolp obj))
       (jmake-proxy "java.awt.event.ActionListener"
-		   (let ((env (or snow::*dynamic-environment*
-				  (snow::capture-dynamic-environment))))
-		     (lambda (this method-name event)
-		       (declare (ignore this method-name))
-		       (snow::with-dynamic-environment (env)
-			 (let ((snow::*dynamic-environment* env))
-			   (funcall obj event))))))
+		   (snow::lambda/dynamic-environment (this method-name event)
+		     (funcall obj event)))
+;		   (let ((env (or snow::*dynamic-environment*
+;				  (snow::capture-dynamic-environment))))
+;		     (lambda (this method-name event)
+;		       (declare (ignore this method-name))
+;		       (snow::with-dynamic-environment (env)
+;			 (let ((snow::*dynamic-environment* env))
+;			   (funcall obj event))))))
       obj)) ;This allows to use a native Java action listener
 
 (defimpl make-layout-manager (widget layout &rest args)
@@ -310,10 +312,9 @@
 	(repl-doc (new "snow.swing.ConsoleDocument"
 		       (compile nil
 				`(lambda ()
-				   (let (, at environment)
-				     ;;safe: *debugger-hook* is rebound
-				     (install-graphical-debugger)
-				     (top-level::top-level-loop)))))))
+				   (snow::with-snow-dynamic-environment
+				     (let (, at environment)
+				       (top-level::top-level-loop))))))))
     (setf (widget-property text-area :document) repl-doc)
     (invoke "setupTextComponent" repl-doc text-area)
     (when dispose-on-close




More information about the snow-cvs mailing list