mirror of
https://gitlab.com/eql/lqml.git
synced 2026-01-06 01:02:10 -08:00
add QML auto reload for mobile (example 'swank-server' only); several revisions
This commit is contained in:
parent
79a5e5cc30
commit
24c2a57fa0
25 changed files with 213 additions and 86 deletions
|
|
@ -4,17 +4,17 @@
|
|||
|
||||
(in-package :qml-user)
|
||||
|
||||
(defvar *dir* *load-truename*)
|
||||
|
||||
(defun qml:view-status-changed (status)
|
||||
(when (= 1 status)
|
||||
;; any ini code goes here
|
||||
;;(app:populate-item-model))
|
||||
))
|
||||
(load (merge-pathnames "on-reloaded" *dir*))))
|
||||
|
||||
(let ((secs 0)
|
||||
files)
|
||||
(defun watch-files ()
|
||||
(unless files
|
||||
(dolist (file (directory "qml/**/*.qml"))
|
||||
(dolist (file (directory (merge-pathnames "../../qml/**/*.qml" *dir*)))
|
||||
(push file files)))
|
||||
(let ((curr 0))
|
||||
(dolist (file files)
|
||||
|
|
@ -26,3 +26,4 @@
|
|||
(qsingle-shot 250 'watch-files)))
|
||||
|
||||
(watch-files)
|
||||
|
||||
5
examples/app-template/lisp/qml-reload/on-reloaded.lisp
Normal file
5
examples/app-template/lisp/qml-reload/on-reloaded.lisp
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
;;; this file will be loaded every time QML has been reloaded
|
||||
|
||||
(in-package :qml-user)
|
||||
|
||||
;;(eval:eval-in-thread "(qml::help)")
|
||||
|
|
@ -8,7 +8,8 @@ Optionally pass `-slime` to start a Swank server, and connect from Emacs with
|
|||
`M-x slime-connect`.
|
||||
|
||||
During development you can pass `-auto`, which will releoad all QML files after
|
||||
you made a change to any of them and saved it, see `auto-reload-qml.lisp`.
|
||||
you made a change to any of them and saved it. For re-initialization after
|
||||
reloading, file `lisp/qml-reload/on-reloaded` will be loaded.
|
||||
|
||||
Closing the window quits the app. If you try to kill it with `ctrl-c`, you need
|
||||
an additional `ctrl-d` to exit from ECL. To quit from Slime, do `(qq)` which is
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
;;; trivial auto reload of all QML files after saving any change
|
||||
|
||||
(when (option "-auto")
|
||||
(load "auto-reload-qml"))
|
||||
(load "lisp/qml-reload/auto-reload"))
|
||||
|
||||
;;; for Slime after copying 'lqml-start-swank.lisp' from LQML sources
|
||||
;;; to your Slime directory, which is assumed to be '~/slime/'
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
(unless (copy-file from to)
|
||||
(error "File ~A could not be copied." to))
|
||||
#+unix
|
||||
(when (string= "sh" (pathname-type to))
|
||||
(when (find (pathname-type to) '("sh" "py") :test 'string=)
|
||||
(ext:run-program "chmod" (list "+x" to)))))))
|
||||
|
||||
(terpri)
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
;;; trivial QML auto reload during development (desktop only), see:
|
||||
;;;
|
||||
;;; lqml run.lisp -auto
|
||||
|
||||
(in-package :qml-user)
|
||||
|
||||
(defun qml:view-status-changed (status)
|
||||
(when (= 1 status)
|
||||
;; any ini code goes here
|
||||
(app:populate-item-model)))
|
||||
|
||||
(let ((secs 0)
|
||||
files)
|
||||
(defun watch-files ()
|
||||
(unless files
|
||||
(dolist (file (directory "qml/**/*.qml"))
|
||||
(push file files)))
|
||||
(let ((curr 0))
|
||||
(dolist (file files)
|
||||
(incf curr (file-write-date file)))
|
||||
(when (/= secs curr)
|
||||
(unless (zerop secs)
|
||||
(qml:reload))
|
||||
(setf secs curr)))
|
||||
(qsingle-shot 250 'watch-files)))
|
||||
|
||||
(watch-files)
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
;;;
|
||||
;;; (q! |remove| *planets* 0)
|
||||
;;; (q! |clear| *planets*)
|
||||
;;; (q! |setProperty| 0 "name" "First")
|
||||
|
||||
(defun populate-item-model ()
|
||||
(q! |clear| *planets*)
|
||||
|
|
|
|||
5
examples/planets/lisp/qml-reload/on-reloaded.lisp
Normal file
5
examples/planets/lisp/qml-reload/on-reloaded.lisp
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
;;; this file will be loaded every time QML has been reloaded
|
||||
|
||||
(in-package :qml-user)
|
||||
|
||||
(app:populate-item-model)
|
||||
|
|
@ -5,5 +5,6 @@
|
|||
(:file "lisp/ui-vars")
|
||||
(:file "lisp/swank-quicklisp")
|
||||
(:file "lisp/eval")
|
||||
(:file "lisp/qml-reload/auto-reload-mobile")
|
||||
(:file "lisp/main")))
|
||||
|
||||
|
|
|
|||
28
examples/swank-server/lisp/curl.lisp
Normal file
28
examples/swank-server/lisp/curl.lisp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
(in-package :qml)
|
||||
|
||||
(defun curl (url)
|
||||
"args: (url)
|
||||
Trivial download of UTF-8 encoded files, or binary files."
|
||||
(multiple-value-bind (response headers stream)
|
||||
(loop
|
||||
(multiple-value-bind (response headers stream)
|
||||
(ecl-curl::url-connection url)
|
||||
(unless (member response '(301 302))
|
||||
(return (values response headers stream)))
|
||||
(close stream)
|
||||
(setf url (header-value :location headers))))
|
||||
(if (>= response 400)
|
||||
(qlog "curl download error:" :url url :response response)
|
||||
(let ((byte-array (make-array 0 :adjustable t :fill-pointer t
|
||||
:element-type '(unsigned-byte 8)))
|
||||
(type (pathname-type url)))
|
||||
(x:while-it (read-byte stream nil nil)
|
||||
(vector-push-extend x:it byte-array))
|
||||
(close stream)
|
||||
(if (or (search type "txt html lisp")
|
||||
(search "/cgi-bin/" (namestring url)))
|
||||
(qfrom-utf8 byte-array)
|
||||
byte-array)))))
|
||||
|
||||
(export 'curl)
|
||||
|
||||
|
|
@ -1,2 +1,4 @@
|
|||
(in-package :app)
|
||||
|
||||
#+(or android ios)
|
||||
(qsingle-shot 1000 'auto-reload-qml)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
;;; trivial QML auto reload during development for mobile
|
||||
|
||||
(in-package :qml)
|
||||
|
||||
#+(or android ios)
|
||||
(defvar *remote-ip* #+(and (not interpreter (or ios android)))
|
||||
(format nil "http://~A:8080/"
|
||||
#.(progn
|
||||
(format *query-io* "~%Please enter WiFi IP of desktop computer: " *query-io*)
|
||||
(read-line *query-io*)))
|
||||
#-(or ios android) "http://localhost:8080/")
|
||||
|
||||
#+(or android ios)
|
||||
(defun qml:view-status-changed (status)
|
||||
(when (= 1 status)
|
||||
(load (make-string-input-stream
|
||||
(funcall (%sym 'curl :qml)
|
||||
(x:cc *remote-ip* "lisp/qml-reload/on-reloaded.lisp"))))))
|
||||
|
||||
#+(or android ios)
|
||||
(let ((load t)
|
||||
(secs 0)
|
||||
(ini t))
|
||||
(defun auto-reload-qml ()
|
||||
(when load
|
||||
(setf load nil)
|
||||
(require :ecl-curl)
|
||||
(load "curl"))
|
||||
(let ((curr (ignore-errors
|
||||
(parse-integer
|
||||
(funcall (%sym 'curl :qml)
|
||||
(x:cc *remote-ip* "cgi-bin/qml-last-modified.py"))))))
|
||||
(when (and curr (/= secs curr))
|
||||
(when (plusp secs)
|
||||
(if ini
|
||||
(progn
|
||||
(setf ini nil)
|
||||
(qset *quick-view* |source| (x:cc *remote-ip* "qml/main.qml")))
|
||||
(qml:reload)))
|
||||
(setf secs curr)))
|
||||
(qsingle-shot 250 'auto-reload-qml)))
|
||||
|
||||
#+(or android ios)
|
||||
(export 'auto-reload-qml)
|
||||
5
examples/swank-server/lisp/qml-reload/on-reloaded.lisp
Normal file
5
examples/swank-server/lisp/qml-reload/on-reloaded.lisp
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
;;; this file will be loaded every time QML has been reloaded
|
||||
|
||||
(in-package :qml-user)
|
||||
|
||||
(eval:eval-in-thread "(qml::help)") ; show help in REPL
|
||||
|
|
@ -58,7 +58,6 @@
|
|||
(princ +app-version+ s))
|
||||
(values)))
|
||||
|
||||
#+(or android ios)
|
||||
(defun %sym (symbol package)
|
||||
(intern (symbol-name symbol) package))
|
||||
|
||||
|
|
@ -67,13 +66,11 @@
|
|||
#+ios
|
||||
(defun load-asdf ()
|
||||
(unless (find-package :asdf)
|
||||
;; needed for ASDF
|
||||
;; needed for ASDF and Quicklisp
|
||||
(setf (logical-pathname-translations "SYS")
|
||||
(list (list "sys:**;*.*"
|
||||
(merge-pathnames "**/*.*" (user-homedir-pathname)))))
|
||||
;; needed for Quicklisp
|
||||
(setf (logical-pathname-translations "HOME")
|
||||
(list (list "home:**;*.*"
|
||||
(merge-pathnames "**/*.*" (user-homedir-pathname)))
|
||||
(list "home:**;*.*"
|
||||
(merge-pathnames "**/*.*" (user-homedir-pathname)))))
|
||||
(ffi:c-inline nil nil :void "ecl_init_module(NULL, init_lib_ASDF)" :one-liner t)
|
||||
(in-package :qml-user))
|
||||
|
|
|
|||
|
|
@ -93,3 +93,12 @@
|
|||
(defvar *epilogue-code* nil)
|
||||
(load "platforms/shared/make"))
|
||||
|
||||
;;; byte compile curl (delayed load)
|
||||
|
||||
#+(or android ios)
|
||||
(progn
|
||||
(require :ecl-curl)
|
||||
(ext:install-bytecodes-compiler)
|
||||
(compile-file (cc *current* "/lisp/curl.lisp")
|
||||
:output-file (cc *current* "/lisp/" *assets* "curl.fasc")))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import "ext/"
|
||||
import "ext/" as Ext
|
||||
import Lisp 1.0
|
||||
|
||||
Item {
|
||||
width: 300
|
||||
height: 500
|
||||
|
||||
Repl {}
|
||||
Ext.Repl {}
|
||||
|
||||
FontLoader { id: fontIcons; source: "fonts/fontawesome-webfont.ttf" }
|
||||
FontLoader { id: fontHack; source: "fonts/Hack-Regular.ttf" }
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ mobile device after `M-x slime-connect`. You may need to detach your device
|
|||
from USB for this to work.
|
||||
|
||||
**Quicklisp** note: it's always preferable to install Quicklisp and any library
|
||||
from Slime on the desktop connected to the mobile device. Otherwise you don't
|
||||
from Slime on the desktop connected to the mobile device. Otherwise you won't
|
||||
see the progress or any eventual problem during the process.
|
||||
|
||||
|
||||
|
|
@ -51,9 +51,25 @@ means:
|
|||
|
||||
|
||||
|
||||
TODO
|
||||
----
|
||||
QML auto reload on mobile
|
||||
-------------------------
|
||||
|
||||
* add QML auto reload on mobile (easy to implement even without Swank, a local
|
||||
trivial web server like `python3 -m http.server 8080` and periodic polling
|
||||
from the mobile device is sufficient to implement it)
|
||||
If you compile for mobile, it will ask for the **Wifi IP** of your desktop
|
||||
computer (currently hard coded into the app).
|
||||
|
||||
After installing and launching the app, just run this script from your example
|
||||
directory:
|
||||
```
|
||||
./web-server.sh
|
||||
```
|
||||
It requires Python 3 and the cgi module, which are probably already installed
|
||||
on your computer.
|
||||
|
||||
You may now edit any QML file on the desktop computer, and upon saving, all of
|
||||
QML will be reloaded automatically. After reloading, the following file will be
|
||||
loaded for eventual re-initialization on Lisp side:
|
||||
```
|
||||
lisp/qml-reload/on-reloaded.lisp
|
||||
```
|
||||
For **android**, in order to see the debug output of eventual QML errors, you
|
||||
need to run `./log.sh` in your `build-android/` directory.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
|
||||
*Please note: the below may be convenient for sketching; during development,
|
||||
the simple `-auto` option of `lqml run.lisp` may be more appropriate, because
|
||||
it allows for re-initialization (calling Lisp code) after reloading.*
|
||||
*Please note: the below may be convenient for sketching -- but during
|
||||
development, the simple `-auto` option of `lqml run.lisp` may be more
|
||||
appropriate, because it allows for re-initialization (calling Lisp code) after
|
||||
reloading QML.*
|
||||
|
||||
*The above method also works on mobile, please see example `swank-server`. It
|
||||
doesn't depend on Swank, and should therefore also be stable (it uses a local
|
||||
trivial web server).*
|
||||
|
||||
|
||||
QML Preview and Slime
|
||||
|
|
|
|||
13
readme.md
13
readme.md
|
|
@ -30,9 +30,20 @@ port still lacks significant parts of mobile (as of Qt6.2).
|
|||
TODO
|
||||
----
|
||||
|
||||
* add QML auto reload on mobile
|
||||
* add sokoban example
|
||||
* add CL REPL example
|
||||
* add Windows platform
|
||||
* port to CMake
|
||||
|
||||
|
||||
macOS note
|
||||
----------
|
||||
|
||||
Qt is (obviously) working perfectly well on Linux (and on Linux only, I dare to
|
||||
say).
|
||||
|
||||
On macOS/iOS you'll always find some subtle bug, like a QQuickView not updating
|
||||
after a property change through e.g. Slime.
|
||||
|
||||
In the above case you need to click on the QQuickView in order to update the
|
||||
view; after that, it seems to work for subsequent property changes.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
#ifndef ECL_FUN_PLUGIN
|
||||
#define ECL_FUN_PLUGIN
|
||||
|
||||
#undef SLOT
|
||||
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
#include <QObject>
|
||||
#include <ecl/ecl.h>
|
||||
|
|
@ -169,6 +172,18 @@ QByteArray toCString(cl_object l_str) {
|
|||
return ba;
|
||||
}
|
||||
|
||||
QByteArray toQByteArray(cl_object l_vec) {
|
||||
QByteArray ba;
|
||||
if (ECL_VECTORP(l_vec)) {
|
||||
int len = LEN(l_vec);
|
||||
ba.resize(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
ba[i] = toInt(ecl_aref(l_vec, i));
|
||||
}
|
||||
}
|
||||
return ba;
|
||||
}
|
||||
|
||||
QString toQString(cl_object l_str) {
|
||||
QString s;
|
||||
if (ECL_STRINGP(l_str)) {
|
||||
|
|
@ -198,9 +213,11 @@ QVariantList toQVariantList(cl_object);
|
|||
QVariant toQVariant(cl_object l_arg, int type) {
|
||||
QVariant var;
|
||||
switch (type) {
|
||||
case QMetaType::QByteArray: var = toQByteArray(l_arg); break;
|
||||
case QMetaType::QPointF: var = toQPointF(l_arg); break;
|
||||
case QMetaType::QRectF: var = toQRectF(l_arg); break;
|
||||
case QMetaType::QSizeF: var = toQSizeF(l_arg); break;
|
||||
case QMetaType::QUrl: var = QUrl(toQString(l_arg)); break;
|
||||
default:
|
||||
if (cl_integerp(l_arg) == ECL_T) { // int
|
||||
var = QVariant(toInt(l_arg));
|
||||
|
|
@ -216,10 +233,11 @@ QVariant toQVariant(cl_object l_arg, int type) {
|
|||
var = (cl_keywordp(cl_first(l_arg)) == ECL_T)
|
||||
? toQVariantMap(l_arg)
|
||||
: toQVariantList(l_arg);
|
||||
} else if (cl_vectorp(l_arg) == ECL_T) { // vector (of octets)
|
||||
var = QVariant(toQByteArray(l_arg));
|
||||
} else { // default: undefined
|
||||
var = QVariant();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
|
@ -298,7 +316,8 @@ cl_object from_qvariant(const QVariant& var) {
|
|||
case QMetaType::QPointF: l_obj = from_qpointf(var.toPointF()); break;
|
||||
case QMetaType::QRectF: l_obj = from_qrectf(var.toRectF()); break;
|
||||
case QMetaType::QSizeF: l_obj = from_qsizef(var.toSizeF()); break;
|
||||
case QMetaType::QString: l_obj = from_qstring(var.toString()); break;
|
||||
case QMetaType::QString:
|
||||
case QMetaType::QUrl: l_obj = from_qstring(var.toString()); break;
|
||||
// special case (can be nested)
|
||||
case QMetaType::QVariantList:
|
||||
QVariantList list(var.value<QVariantList>());
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include <QStringList>
|
||||
#include <QDebug>
|
||||
|
||||
const char LQML::version[] = "22.3.1"; // Mar 2022
|
||||
const char LQML::version[] = "22.3.2"; // Mar 2022
|
||||
|
||||
extern "C" void ini_LQML(cl_object);
|
||||
|
||||
|
|
@ -101,7 +101,6 @@ void LQML::ignoreIOStreams() {
|
|||
}
|
||||
|
||||
void LQML::exec(lisp_ini ini, const QByteArray& expression, const QByteArray& package) {
|
||||
// see my_app example
|
||||
ecl_init_module(NULL, ini);
|
||||
eval(QString("(in-package :%1)").arg(QString(package)));
|
||||
eval(expression);
|
||||
|
|
|
|||
|
|
@ -32,13 +32,13 @@ public:
|
|||
static LQML* me;
|
||||
static QQuickView* quickView;
|
||||
|
||||
void exec(lisp_ini, const QByteArray& = "nil", const QByteArray& = "qml-user"); // see my_app example
|
||||
void exec(lisp_ini, const QByteArray& = "nil", const QByteArray& = "qml-user");
|
||||
void ignoreIOStreams();
|
||||
|
||||
void printVersion() {
|
||||
eval("(multiple-value-bind (lqml qt)"
|
||||
" (qml:qversion)"
|
||||
" (format t \"LQML ~A (ECL ~A, Qt ~A)~%\" lqml (lisp-implementation-version) qt))");
|
||||
" (format t \"LQML ~A (ECL ~A, Qt ~A)~%~%\" lqml (lisp-implementation-version) qt))");
|
||||
}
|
||||
|
||||
Q_INVOKABLE void runOnUiThread(void*);
|
||||
|
|
|
|||
|
|
@ -65,10 +65,13 @@ int main(int argc, char* argv[]) {
|
|||
LQML lqml(argc, argv, &view);
|
||||
if (arguments.contains("-v") || arguments.contains("--version")) {
|
||||
lqml.printVersion();
|
||||
std::cout << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
lqml.ignoreIOStreams();
|
||||
#endif
|
||||
|
||||
new QQmlFileSelector(view.engine(), &view);
|
||||
QString qml("qml/main.qml");
|
||||
QUrl url;
|
||||
|
|
@ -116,15 +119,15 @@ int main(int argc, char* argv[]) {
|
|||
#endif
|
||||
|
||||
#ifdef NO_QT_RESTART
|
||||
bool slime = false;
|
||||
bool qtRestart = false;
|
||||
#else
|
||||
bool slime = true;
|
||||
bool qtRestart = true;
|
||||
#endif
|
||||
|
||||
if (arguments.contains("-slime")
|
||||
|| (arguments.indexOf(QRegularExpression(".*start-swank.*")) != -1)) {
|
||||
arguments.removeAll("-slime");
|
||||
slime = true;
|
||||
qtRestart = true;
|
||||
}
|
||||
|
||||
// load Lisp file
|
||||
|
|
@ -134,7 +137,7 @@ int main(int argc, char* argv[]) {
|
|||
LQML::eval(QString("(load \"%1\")").arg(file), true);
|
||||
}
|
||||
|
||||
if (slime) {
|
||||
if (qtRestart) {
|
||||
LQML::eval("(qml::exec-with-qt-restart)", true);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "marshal.h"
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
#include <QObject>
|
||||
|
||||
|
|
@ -142,6 +143,7 @@ QVariant toQVariant(cl_object l_arg, int type) {
|
|||
case QMetaType::QPointF: var = toQPointF(l_arg); break;
|
||||
case QMetaType::QRectF: var = toQRectF(l_arg); break;
|
||||
case QMetaType::QSizeF: var = toQSizeF(l_arg); break;
|
||||
case QMetaType::QUrl: var = QUrl(toQString(l_arg)); break;
|
||||
default:
|
||||
if (cl_integerp(l_arg) == ECL_T) { // int
|
||||
var = QVariant(toInt(l_arg));
|
||||
|
|
@ -162,7 +164,6 @@ QVariant toQVariant(cl_object l_arg, int type) {
|
|||
} else { // default: undefined
|
||||
var = QVariant();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
|
@ -276,7 +277,8 @@ cl_object from_qvariant(const QVariant& var) {
|
|||
case QMetaType::QPointF: l_obj = from_qpointf(var.toPointF()); break;
|
||||
case QMetaType::QRectF: l_obj = from_qrectf(var.toRectF()); break;
|
||||
case QMetaType::QSizeF: l_obj = from_qsizef(var.toSizeF()); break;
|
||||
case QMetaType::QString: l_obj = from_qstring(var.toString()); break;
|
||||
case QMetaType::QString:
|
||||
case QMetaType::QUrl: l_obj = from_qstring(var.toString()); break;
|
||||
// special case (can be nested)
|
||||
case QMetaType::QVariantList:
|
||||
QVariantList list(var.value<QVariantList>());
|
||||
|
|
|
|||
|
|
@ -49,12 +49,12 @@
|
|||
(format nil "%~A%" (gensym)))
|
||||
|
||||
(defun qexec (&optional ms)
|
||||
(%qexec ms))
|
||||
(qrun* (%qexec ms)))
|
||||
|
||||
(defun qsleep (seconds)
|
||||
"args: (seconds)
|
||||
Similar to SLEEP, but continuing to process Qt events."
|
||||
(%qexec (floor (* 1000 seconds)))
|
||||
(qrun* (%qexec (floor (* 1000 seconds))))
|
||||
nil)
|
||||
|
||||
(defmacro qsingle-shot (milliseconds function)
|
||||
|
|
@ -191,19 +191,19 @@
|
|||
(%qinvoke-method object function-name arguments))
|
||||
|
||||
(defmacro qget (object name)
|
||||
`(%qget ,object ,(if (symbolp name)
|
||||
`(qrun* (%qget ,object ,(if (symbolp name)
|
||||
(symbol-name name)
|
||||
name)))
|
||||
name))))
|
||||
|
||||
(defmacro qset (object &rest arguments)
|
||||
(assert (evenp (length arguments)))
|
||||
`(%qset ,object ',(let (name)
|
||||
`(qrun* (%qset ,object (list ,@(let (name)
|
||||
(mapcar (lambda (x)
|
||||
(setf name (not name))
|
||||
(if (and name (symbolp x))
|
||||
(symbol-name x)
|
||||
x))
|
||||
arguments))))
|
||||
arguments))))))
|
||||
|
||||
(defun exec-with-qt-restart ()
|
||||
;; for internal use; for conditions in Slime during Qt event loop processing
|
||||
|
|
@ -218,7 +218,7 @@
|
|||
normal program exit."
|
||||
(declare (ignore kill-all-threads)) ; only here to be equivalent to EXT:QUIT
|
||||
(assert (typep exit-status 'fixnum))
|
||||
(%qquit exit-status))
|
||||
(qrun* (%qquit exit-status)))
|
||||
|
||||
;;; android
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue