Sysquake's ability to solve problems can be extended with the help of external applications. This requires the capability of exchanging data and triggering actions across applications. There are basically two possible situations: Sysquake initiates the communication, or it receives requests from the other application. In the first case, LME functions executed by the different handlers defined in SQ files are usually sufficient. In case the communication mechanism is not supported directly by Sysquake, it can be implemented by libraries which add communication protocol layers on top of those existing in LME (for instance an SMTP layer on top of TCP/IP for sending email), or by extensions. This chapter describes means for Sysquake to act as the target of remote requests.
The generic name for sending a command which lets another process, possibly running on another computer, execute code, is Remote Procedure Call. It typically involves the identification of the remote application, sending a procedure (or function) identifier and arguments, and receiving results.
Sysquake uses two different mechanisms: OLE Automation on Windows, and XML-RPC on Mac OS X and Linux. The servers are disabled by default; an option to enable them is located in the Preference panel "Extensions". For security reasons, the XML-RPC server accepts local connections only.
User applications can use directly these low-level mechanisms. In addition, SysquakeLink, a Java package, gives a higher-level interface, common to all platforms. It is obviously especially suited to Java applications, but can also be used from other applications using Java Native Access (JNI); please see the Sun documentation for more informations.
The main goal of RPC is to let a separate application (the client) interact with an SQ file loaded in Sysquake by reading and changing variable. Multiple variable values can be read or changed in a single command. After each change, Sysquake redraws all figures so that they show the new state.
Other RPC commands let the client application load an SQ or SQD file, execute a command as it it were typed in the command window, get the list of variables of an SQ file or defined in the context of the command window, and ge the value of variables defined in that context.
When an SQ or SQD file is loaded in Sysquake, a new SQ file instance is created, associated with a unique instance ID represented by a positive integer number. The instance ID is returned to the caller when the file is loaded; it is used to identify the instance in later calls.
All versions of Sysquake support at least the following types: real double (with support for inf and nan), int32 and logical, scalar or 2-d arrays; and character strings.
Remote Procedure Calls are always initiated by the client. An additional mechanism is provided so that Sysquake can notify the client about user actions in Sysquake. The client can provide some code which is executed whenever a variable is changed in a specified SQ file instance, i.e. when the user manipulates a figure or selects a menu entry. This code can contact back the client so that it request the new values of the variables it is interested in.
In the Java package SysquakeLink, notifications are implemented with local UDP connections. The following code is executed by Sysquake; port number port is chosen by the operating system to avoid conflicts with other services.
_fd_varChangedSQLinkNot = ... socketnew('localhost',port,socketset('Proto','udp')); _fd_varChangedSQLinkNot,'var changed'); fclose(_fd_varChangedSQLinkNot);
The list below enumerates all OLE Automation functions implemented by Sysquake. Their IDs are not specified, because they are subject to change in future versions.
Note: to change a variable in the context of the Command window, Execute should be called.
XML-RPC is a simple Remote Procedure Call protocol based on XML, a markup language similar to HTML but more flexible and with a more regular structure, and HTTP, the most common communication protocol used on the Web. XML-RPC implementations are widely available for different platforms and programming languages, including Sysquake itself. Sysquake's implementation adds support for the floating-point numbers inf and nan, represented as <double>inf</double> and <double>nan</double>, respectively.
This section describes the implementation used for controlling Sysquake from other clients, and especially to interact with SQ instances. This does not prevent other XML-RPC servers from running in the same instance of Sysquake, provided that different TCP/IP ports are selected. If Sysquake runs multiple times simultaneously on the same computer with the XML-RPC server, they must use different TCP/IP ports. A typical choice is 8900. Only priviledged users (typically user "root") can launch a server with a port below 1024.
The URL sent to the XML-RPC server (the part after the hostname and the port number) is ignored.
The following methods are implemented:
Method name: close
Arguments: instance ID (integer)
Result: true if successful, false if failed
Method name: execute
Arguments: command to execute (string)
Result: true
Method name: getLMEVariableNames
Arguments: none
Result: list of variables of the context of the command window (array of strings)
Method name: getLMEVariableValue
Arguments: variable name (string) or index (integer) or array
Result: value of the variable in the context of the command window, or array of values
Method name: getVariableNames
Arguments: instance ID (integer)
Result: list of variables of the specified instance (array of strings)
Method name: getVariableValue
Arguments: instance ID (integer), variable name (string) or index (integer) or array
Result: value of the variable, or array of values
Method name: load
Arguments: path of SQ file or SQD file (string)
Result: ID of the new instance (integer)
Method name: reload
Arguments: instance ID (integer)
Result: new instance ID
Method name: setVarChangeNotification
Arguments: instance ID (integer), code executed every time a variable of the specified instance if changed (string)
Result: true
Method name: setVariableValue
Arguments: instance ID (integer), variable name (string) or index (integer) or array, new value(s)
Result: true
Method name: version
Arguments: none
Result: Sysquake version (string)
macOS can send XML-RPC calls directly from AppleScript. For instance, running the script below in the Script Editor requests Sysquake version and displays it in a dialog box.
tell application "http://localhost:8888/" set v to call xmlrpc {method name:"version"} end tell display dialog v
Parameters are provided in a parameters property, which is itself an ordered list. The script below executes LME code.
tell application "http://localhost:8888/" set code to "plot(rand(10), rand(10), 'rgby');" call xmlrpc {method name:"execute",parameters:{code}} end tell
Please see Apple documentation on AppleScript for more informations.
SysquakeLink is a cross-platform Java package which can be used to communicate easily with Sysquake. It supports native Java types and classes, such as double and String. To exchange informations with Sysquake, it relies on native functions (JNI) which implement OLE Automation on Windows or XML-RPC on other platforms.
SQLinkTool is a simple Java command-line utility for testing all the features of SysquakeLink. It is provided as a compiled class and as source code, so that it serves as an example of how SysquakeLink can be used in a real application.
To run SQLinkTool, open a shell window. With XML-RPC, SysquakeLink sets the TCP/IP port number of the value stored in the environment variable SQLINKPORT; depending on your shell, type export SQLINKPORT=8888 with sh or bash, or setenv SQLINKPORT 8888 with csh or tcsh (change the port number so that it matches the value set in Sysquake). Then type the following command:
java -classpath path com.calerga.sysquake.SQLinkTool args
where path is the path of SysquakeLink classes and args is one or more arguments from the following list:
Values can be double or boolean, scalar or 2-d arrays; or strings. Numeric and boolean values have the same syntax as in LME, with brackets, semicolons and commas for arrays; any value whose syntax is not recognized is considered to be a string.
In the following examples, the shell prompt is displayed as %. The path which follows -classpath should be replaced with the actual class pass, i.e. the directory which contains com. Here, for the sake of simplicity, we assume the most common case where Sysquake is installed in the default application directory for the platform and we change directory so that the class path is the current directory, denoted by a single dot. On non-Windows computers, we should also set the environment variable SQLINKPORT so that it matches the value specified for Sysquake (see above).
On Windows:
% cd "C:\Program Files\Sysquake\Java\JavaClasses"
On macOS (the actual class path is displayed in Sysquake's Preferences dialog, in tab Extensions>File paths):
% cd "/Applications/Sysquake/Sysquake.app/Contents/Resources/Java" % export SQLINKPORT=8889
On Linux (type "export SQLINKPORT=8889" instead of "setenv SQLINKPORT 8889" if your shell is csh or tcsh):
% cd /usr/local/sysquake/Java/JavaClasses % export SQLINKPORT=8889
Once this is done, commands are the same on all platforms. Sysquake should be launched. Then to check that everything is set up correctly, display the version of Sysquake:
% java -classpath . com.calerga.sysquake.SQLinkTool -v Sysquake 3.5
In Sysquake, define two variables in the Command window:
M = magic(3); b = true;
In the terminal window, display the list of variables defined in the context of Sysquake command window:
% java -classpath . com.calerga.sysquake.SQLinkTool -n ans M b
Display the value of variable M:
% java -classpath . com.calerga.sysquake.SQLinkTool -g M [8.0,1.0,6.0;3.0,5.0,7.0;4.0,9.0,2.0]
Display the value of variables M and b (the end marker - is superfluous here, because there are no additional arguments):
% java -classpath . com.calerga.sysquake.SQLinkTool -G M b [8.0,1.0,6.0;3.0,5.0,7.0;4.0,9.0,2.0] true
Load SQ file approx.sq (you should specify its absolute path or a relative path with respect to the current working directory of Sysquake). The result is the ID of the new instance.
% java -classpath . com.calerga.sysquake.SQLinkTool -l approx.sq 1
Display the list of variables of SQ file instance 1:
% java -classpath . com.calerga.sysquake.SQLinkTool -i 1 -n fn x0 dx n method
Set the value of x0 to 2:
% java -classpath . com.calerga.sysquake.SQLinkTool -i 1 -s x0 2
The SysquakeLink Java package is installed with Sysquake, in the Java directory on Windows and Linux and inside the Sysquake package on Macintosh. The complete SysquakeLink package name is com.calerga.sysquake.SysquakeLink.
Here are the main design decisions of SysquakeLink:
The reference documentation of SysquakeLink has been generated from source code with the Java utility javadoc. The source code of SQLinkTool and the example below illustrate how to use it.
Here is the list of methods:
To illustrate how SysquakeLink can be used to exchange information in both directions between Sysquake and a Java application, here is an example where a Java slider is synchronized with the x0 position of the SQ file approx.sq. The application is kept as simple as possible; approx.sq should be opened in Sysquake by the user as the first instance.
Here is the complete source code of the application:
// SysquakeLink packages import com.calerga.sysquake.*; // Java and Swing packages import javax.swing.*; import javax.swing.event.*; import java.awt.*; import java.awt.event.*; import java.io.*; // a single class is defined for the whole application public class SQLinkApproxSample extends WindowAdapter // class used as window listener and... implements ChangeListener, // ...slider listener and... SQLinkVariableListener // ...Sysquake notifications listener { JSlider slider; // java slider static final int sqID = 1; // fixed SQ instance ID public SQLinkApproxSample() { // application setup slider = new JSlider(JSlider.HORIZONTAL, -5000, 5000, 0); // JSlider has integer values, x0 = 0.001 * (java value) slider.addChangeListener(this); // using this.stateChanged() JPanel panel = new JPanel(new GridLayout(0, 1)); panel.add(slider); JFrame frame = new JFrame("Sync. with approx.sq"); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(this); // using this.windowClosing() frame.setContentPane(panel); frame.pack(); frame.setVisible(true); try { SysquakeLink.connect(); SysquakeLink.setVariableChangeNotification(sqID, this); // using this.variableChange() SysquakeLink.show(); // bring Sysquake to front on platforms which support it } catch (SQLinkException e) { System.err.println(e); System.exit(1); // abort } } public void windowClosing(WindowEvent e) { // called when the window is closed SysquakeLink.disconnect(); System.exit(0); } public void stateChanged(ChangeEvent event) { // called when the Java slider is changed // -> update Sysquake's x0 try { if (event.getSource() == slider) { double x0 = slider.getValue() * 0.001; SysquakeLink.setVariableValue(sqID, "x0", x0); } } catch (SQLinkException e) { System.err.println(e); } } public void variableChange(int instanceId) { // called when the Sysquake's x0 is changed // -> update Java slider try { Object obj = SysquakeLink.variableValue(sqID, "x0"); double x0 = ((Double) obj).doubleValue(); slider.setValue((int)(1000 * x0)); } catch (Exception e) { // catch communication and conversion to double errors System.err.println(e); } } public static void main(String[] args) { // application entry point: create instance new SQLinkApproxSample(); } }