I am trying to create a window using cl-sdl2.
My code works - it creates a window for 2 seconds, and then closes it:
(defun main ()
(sdl2:with-init (:everything)
(sdl2:with-window (win :title "cl-sdl2 sample" :flags '(:shown :fullscreen))
(let ((surf (sdl2:get-window-surface win)))
(sdl2:fill-rect surf nil (sdl2:map-rgb (sdl2:surface-format surf) #xff #xff #xff))
(sdl2:update-window win)
(sdl2:delay 2000)))))
(main)
However, after the window closes, the repl (CCL) becomes stuck. I can no longer evaluate expressions. Why is this, and how do I get back to a functioning repl?
As it stands, I have to keep spawning new CCL repl processes every time I run the sample to test it, which is quickly becoming tedious.
I'm on MacOS Sierra.
It looks like this is a known issue with cl-sdl2 as seen here: https://github.com/lispgames/cl-sdl2/issues/89
The current proposed workaround is to move the repl thread off of the main thread and connect to that via swank/slime on a seperate terminal, then run the sdl program on the main thread. An example is shown below.
(bt:make-thread (lambda () (swank:create-server :port 4005 :dont-close t)))
(sdl2:make-this-thread-main (lambda () (sdl2.kit:start)))
Related
I am trying to get live-coding to work in lisp. i have the file t.cl which contains only this line: (loop(write(- 2 1))). Now, when i run the file in bash with sbcl --load t.cl --eval '(quit)', it runs the line, but when I try to edit the file in another terminal and save it while it runs, nothing changes ..
Why your example fails
When running sbcl --load t.cl --eval '(quit)' in a shell, what this does is spin-up a SBCL Lisp image in a process, compile the file and run it. You then modify the file and save it to your disk. This last action is of no concern to the already running SBCL process, which has already compiled the previous file. SBCL read the file once when you asked it to, once it has the compiled instructions to run, it has no reason to look at the file again unless you explicitly ask it to.
A 'live' example with Emacs+SLIME
In order to perform 'live' changes to your running program, you must interact with the already running Lisp image. This is easily doable with Emacs+Slime. You can, for example, have a loop like so:
(defun foo (x) (+ x 3))
(dotimes (it 20)
(format t "~A~%" (foo it))
(sleep 1))
and then recompile foo during execution within the REPL with a new definition:
(defun foo (x) (+ x 100))
Another thread will be used to recompile the function. The new function will be used for future calls as soon as its compilation is finished.
The output in the REPL will look like:
3
4
5
CL-USER> (defun foo (x) (+ x 100))
WARNING: redefining COMMON-LISP-USER::FOO in DEFUN
FOO
103
104
105
...
This would also work with the new definition of foo being compiled from another file as opposed to being entered directly in the REPL.
Working from the system shell
While you can already use the example above for development purposes, you might want to interact with a running SBCL Lisp image from the shell. I am not aware of how to do that. For your exact example, you want to get SBCL to reload eventual files that you have modified. A brief look at the SBCL manual doesn't seem to provide ways to pipe lisp code to an already running SBCL process.
I'm making a simple applet in Common Lisp and I want to control it using mouse movement. I use LTK for the window. I couldn't find any function that would retrieve the mouse location. For example, Emacs Lisp has (mouse-pixel-position). I found this on rosetta code, but there's no Common Lisp entry. What can I do?
Hints from this SO answer: Mouse Position Python Tkinter
and looking at ltk's doc: http://www.peter-herth.de/ltk/ltkdoc/node16.html
I got the following example to retrieve any event fired by the mouse movement:
(ql:quickload "ltk")
(in-package :ltk-user)
(defun motion (event)
(format t "~a~&" event))
(with-ltk ()
(bind *tk* "<Motion>" #'motion))
This opens up a little window with nothing inside. Once you put the mouse in it, you get lots of events:
#S(EVENT
:X 0
:Y 85
:KEYCODE ??
:CHAR ??
:WIDTH ??
:HEIGHT ??
:ROOT-X 700
:ROOT-Y 433
:MOUSE-BUTTON ??)
…
The #S indicates we deal with a structure, named EVENT, so we can access its slots with (event-x event), event-mouse-button, etc. See https://lispcookbook.github.io/cl-cookbook/data-structures.html#slot-access
Also you might want to join the CL community on freenode, there are some game developers there.
An event-based approach is likely to be more appropriate in most cases, but you can also query the current position directly:
(defpackage :so (:use :cl :ltk))
(in-package :so)
(with-ltk ()
(loop
(print
(multiple-value-list
(screen-mouse)))
(sleep 0.5)))
This starts a graphical toplevel and prints the current screen coordinates every 500ms, until you quit the toplevel window. The screen-mouse function accepts an optional w argument (a window).
I'm using CLX+STUMPWM+McCLIM and when I modify the keyboard layout via "setxkbmap us -variant dvorak -option ctrl:nocaps" the keyboard layout fails to update in my CLIM applications, but updates correctly for everything else (thus, to use COLEMAK I run the appropriate shell command prior to starting up CLIM for the first time).
Thoughts on why this might be?
This appears to be a bug in CLX independently affecting McCLIM and stumpwm.
For instance, I'm testing the difference between
setxkbmap -layout us
(querty) and
setxkbmap -layout fr
(azerty). Running those commands doesn't affect neither stumpwm's input bar, nor Climacs. The default querty remains in effect.
X server sends keycodes to applications. Applications may interpret these keycodes using the keymap table, which they can request from the server.
It seems that in CLX the keycode to keysym transformation is carried out by the keycode->keysym function defined in translate.lisp. It calls the display-keyboard-mapping function defined right above it:
(defun display-keyboard-mapping (display)
(declare (type display display))
(declare (clx-values (simple-array keysym (display-max-keycode keysyms-per-keycode))))
(or (display-keysym-mapping display)
(setf (display-keysym-mapping display) (keyboard-mapping display))))
Apparently, this function only requests the keymap table once and caches it. Changing it to
(defun display-keyboard-mapping (display)
(declare (type display display))
(declare (clx-values (simple-array keysym (display-max-keycode keysyms-per-keycode))))
(setf (display-keysym-mapping display) (keyboard-mapping display)))
fixes both the input bar and Climacs. CAVEAT: I don't claim this doesn't break anything else.
NB: If attempting to run a shell command from stumpwm's input bar using the French layout, mind that ! is positioned on /.
My workflow:
Hack away at an .R or test_*.R file
Save buffer.
Switch to window with *R* process
hit C-p, RET. to re-evaluate devtools::test()
To me, this seems far too arduous. Why can't I get R to run devtools::test() automatically when I save the buffer? Please help, my fingers can barely take the strain of the seven extra keystrokes!
This worked for a similar setup (switching to a shell buffer):
(defun devtools-test ()
(interactive)
(when (string-match (rx-to-string `(: ".R" eos) t) (buffer-name))
(switch-to-buffer "*R*")
(end-of-buffer)
(insert "devtools::test()")
(comint-send-input)))
(add-hook 'after-save-hook 'devtools-test)
Does that work for you?
For completeness, there are easier way to do this in recent versions of ESS.
The function/command ess-r-devtools-test now runs devtools::test.
So you could achieve this with (untested):
(add-hook 'ess-r-mode-hook
(lambda ()
(add-hook 'after-save-hook 'devtools-test nil 'local)))
In addition, there are many other useful functions under ess-r-devtools-* for build, install etc.
It's worth noting that calling ess-r-devtools-test with the universal argument will filter tests by the current file.
So calling C-u M-x ess-r-devtools from a file my-file.R will run devtools::test(filter="my-file").
This can be useful to bear in mind when choosing names for test files, or when rerunning only the current test file.
There is a ess-eval-linewise function which you can use.
Something like this (not tested):
(defun devtools-test ()
(interactive)
(when (and (equal ess-dialect "R")
(string-match "^test.*\\.[Rr]$" (buffer-name)))
(ess-eval-linewise "devtools::test()")))
(add-hook 'after-save-hook 'devtools-test)
I would not recommend this though, as for some packages tests take quite a while to run. You don't want them running on every save.
There will be a dedicated devtools functionality in ess soon. Follow this issue.
While trying to figure out CLIM, I ran into this example program. It's a simple maze game. The author claims to have tested it in LispWorks (and even has #+Genera in there, implying that this program would work on a real Lisp Machine), but I'm trying to get it working in SBCL with McCLIM.
Under SBCL/McCLIM, the window draws, but nothing visible happens when you press the movement keys. Non-movement keys cause text to be entered into the pane with the game instructions.
I figured out that the game command keys are changing the game's internal state, so the only problem is that the screen does not update.
Then I realized that you couldn't write code to redraw the maze from the scope of the code that implements the commands. All the methods that draw receive a stream argument from CLIM, which must be passed to the graphics primitives. For example:
(defun draw-stone (stream x y cell-width cell-height)
(let ((half-cell-width (/ cell-width 2))
(half-cell-height (/ cell-height 2)))
(draw-ellipse* stream
(+ (* x cell-width) half-cell-width)
(+ (* y cell-height) half-cell-height)
half-cell-width 0
0 half-cell-height
:ink +red+)))
But the code that handles keystrokes receives no stream argument:
(defmacro define-stone-move-command (name keystroke dx dy)
`(define-maze-frame-command (,name :keystroke ,keystroke) ()
(let ((maze-array (maze-array *application-frame*)))
(move-stone maze-array ,dx ,dy)
(check-for-win maze-array))))
What I ended up having to do is to save the stream argument from the first (and only) call to draw-maze-array to a global variable, so that I could add update code to the define-stone-command macro as follows:
(defmacro define-stone-move-command (name keystroke dx dy)
`(define-maze-frame-command (,name :keystroke ,keystroke) ()
(let ((maze-array (maze-array *application-frame*)))
(move-stone maze-array ,dx ,dy)
(check-for-win maze-array)
(draw-maze-array *application-frame* *maze-stream*))))
This slight alteration gives the desired behavior on SBCL with McCLIM, but this doesn't seem right, however. After all, the author claimed that the code worked fine on LispWorks. I have a few questions:
Can somebody who has LispWorks confirm that this program works as-is on LispWorks?
Does my alteration to the code make it fail on LispWorks?
What is the accepted way to handle screen updating in CLIM applications?
Drawing the maze in the command is not the right approach. Putting a maze-stream into a global variable is also bad. ;-)
The display pane has a :display-function. The idea is that after a command the whole application frame gets updated automagically. For example for :display-time :command-loop, the display pane would be updated automagically, after a command runs. There are other ways to update panes, but in this case a keystroke runs a command and then the top-level-loop would just call the display-function for each applicable pane. The default toplevel-loop reads a command (via mouse, command lines, keystrokes, ...), executes it and updates the application frame - in a loop.
The whole redisplay thing is extremely tricky/powerful. It allows from fully automagical redisplay mechanisms to extremely fine-grained control.
You can read about it here: CLIM 2 Spec. Note: there might be quite a bit difference between the spec and what implementations provide...