Assigning Spotify window to a group in StumpWM - common-lisp

I am currently starting to set up stumpwm, and I would like to assign a specific window to a particular group.
So far I have this:
(define-frame-preference "Spotify"
(0 t t :class "Spotify")
)
So essentially, I would expect that that would set the windows with the class Spotify to the group Spotify, this however does not happen.
Can anybody help me on this?
Thank you!

The relationship between X11 windows and Linux processes is thin: things are asynchronous, you start a process and some time later zero, one or more windows are created.
You have to work with callbacks, there is no easy way to create a process and synchronously have all its windows in return.
Some processes are nice enough to set the _NET_WM_PID property on windows (it looks like the "Spotify" application does it). You can retrieve this property as follows:
(first (xlib:get-property (window-xwin w) :_net_wm_pid))
Placement rules cannot help here, given how Spotify fails to set the class property early enough (see comments and other answer). But you can use a custom hook:
STUMPWM-USER> (let ((out *standard-output*))
(push (lambda (&rest args) (print args out))
*new-window-hook*))
(#<CLOSURE (LAMBDA (&REST ARGS)) {101A92388B}>)
Notice how I first evaluate *standard-output* to bind it lexically to out, so that the function can use it as a stream when printing informations. This is because the hook might be run in another thread, where the dynamic binding of the standard output might not be the one I want here (this ensures debugging in done in the Slime REPL, in my case).
When I start for example xclock, the following is printed in the REPL:
(#S(TILE-WINDOW "xclock" #x380000A))
So I can change the hook so that instead if does other things. This is a bit experimental but for example, you can temporarily modify the *new-window-hook* to react on a particular window event:
(in-package :stumpwm-user)
(let ((process (sb-ext:run-program "xclock" () :search t :wait nil))
(hook))
(sb-ext:process-kill process sb-unix:sigstop)
(flet ((hook (w)
(when (find
(sb-ext:process-pid process)
(xlib:get-property (window-xwin w) :_net_wm_pid))
(move-window-to-group w (add-group (current-screen) "XCLOCK"))
(setf *new-window-hook* (remove hook *new-window-hook*)))))
(setf hook #'hook)
(push #'hook *new-window-hook*))
(sb-ext:process-kill process sb-unix:sigcont))
Basically: create a process, stop it to minimize race conditions, define a hook that checks if the PID associated in the client matches the one of the process, execute some rules, then remove the hook from the list of hooks. This is fragile, since if the hook is never run, it stays in the list, and in case of errors, it also stays in the list. At the end of the expression, the hook is added and the process resumes execution.

So it seems like, as pointed out by coredump, the are issues in the way the Spotify window is defined.
As an alternative, there are fortunately plenty of ways to control spotify via Third Party Clients (ArchWiki)
Personally, I found that you can control spotify via Ivy on Emacs thanks to this project
Ivy Spotify and this will probably be what I will use.

Related

If generic functions work well alone, what is the value of defclass?

I read a lot about generic functions in CL. I get it. And I get why they are valuable.
Mainly, I use them for when I want to execute a similar action with different data types, like this:
(defgeneric build-url (account-key)
(:documentation "Create hunter api urls"))
(defmethod build-url ((key number))
"Build lead api url"
(do-something...))
(defmethod build-url ((key string))
"build campaign api url"
(do-somthing... ))
In this example, campaign-url and lead-url are structures (defstruct).
My question is, at a high level, how do classes add value to the way generic functions + structures work together?
Structures historically predate classes, are more restricted and more "static" than classes: once a structure is defined, the compiler can generate code that accesses its slots efficiently, can assume their layout is fixed, etc. There is a lot of inlining or macro-expansion done that makes it necessary to rebuild everything from scratch when the structure changes. Being able to redefine a struct at runtime is not something defined by the standard, it is merely implementations trying to be nice.
On the other hand, classes have more features and are easier to manipulate at runtime. Suppose you write this class:
(defclass person ()
((name :initarg :name :reader .name)))
And you instantiate it:
(defparameter *someone* (make-instance 'person :name "Julia O'Caml"))
It is possible now to update the class definition:
(defparameter *id-counter* 0)
(defun generate-id ()
(incf *id-counter*))
(defclass person ()
((name :initarg :name :reader .name)
(dob :initarg :date-of-birth :reader .date-of-birth)
(%id :reader .id :initform (generate-id))))
And now, *someone*, which existed already, has two additional fields, dob that is unbound, and %id that is automatically initialized to 1. There is a whole section about Object Creation and Initialization (7.1) that defines how objects can be redefined, change class, etc.
Moreover, this mechanism is not fixed, a lot of the steps described above rely on generic functions. It is possible to define how an object is allocated, initialized, etc. The concept was standardized as what is known as the Meta-Object Protocol, which also introduces the concept of metaobject, the object representing a class: usually a class has a name, parent classes, slots, etc. but you can add new members to a class, or change how instance slots are organized (maybe your just need a global handle and a connection, and the actual instance slots are stored in another process?).
Note also that once CLOS/MOP was defined, it was also eventually possible to define structures in this framework: in the standard , defstruct (without a :type option) defines classes with a structure-class metaclass. Still, they do not behave like standard-class because as said above they are more restricted, and as such are subject to more aggressive compilation optimizations (in general).
Structures are nice if you need to program like in C and you are ok with recompiling all your code when the structure changes. It is however premature optimization to use them in all cases. It is possible to use a lot of standard objects without noticing much slowness nowadays (a bit like Python).

What is an alternative to <!! in cljs?

a go block returns a channel and not the return value, so how can one extract the return value in a go block, when cljs doesn't have <!!?
For example, given the following code:
(go (let [response (<! (http/get "https://api.github.com/users"
{:with-credentials? false
:query-params {"since" 135}}))]
(:status response)))
will return a channel but not (:status response). How to make this go block return a (:status response)?
<!! doesn't exist in javascript because the runtime does not support it. Javascript is single-threaded and <!! is a blocking operation. Blocking the main thread in a browser-based environment is a bad idea as it would simply freeze all javascript actions (and potentially freeze the whole page) until unblocked.
Instead, consider using clojure.core.async/take! like so:
(take! channel (fn [value] (do-something-with value)))

is it possible to get mouse event directly without on-mouse in racket?

I am badly in a need to use mouse-events directly
Is it possible to get the mouse-event without using big bang ?
i.e I want to build a function like the following:
(define (check-if-button-down mev) (mouse=? mev "button-down"))
But for getting mev, the input is being fed from on-mouse of bigbang
About me :
I am new to racket programming
Short answer: not really.
However: the big bang model calls your mouse event handler when a mouse event occurs, so if you want to know whether the mouse button is pressed, your world state should include a boolean indicating whether the mouse button is pressed, and your mouse event handler should return a world state that updates this boolean correctly.
Is there some reason this architecture doesn't work for you?
If this is a student project, you may have to stick with what big-bang offers (see John Clements' answer).
But if you can use racket/gui (either as a language #lang racket/gui or as an additional (require racket/gui)), then you are looking for get-current-mouse-state.
For example
#lang racket
(require racket/gui)
(define (mouse-button-down?)
(define-values (pt state)
(get-current-mouse-state))
(if (or (memq 'left state)
(memq 'right state)
(memq 'middle state))
#t
#f))

Creating a JavaFX proxy causes a UnsupportedOperationException

I'm trying to write a JavaFX app in Clojure. As a simple test, I wanted to try to just launch a Hello World. To extend Application, I decided to try using proxy instead of :gen-class. I wanted to be able to create a bare-bones function that creates an Application, instead of requiring me to write the boilerplate every time.
The simple example I came up with was:
(let [^Application app
(proxy [Application] []
(start [self stage] (println "Hello World")))]
(Application/launch ^Class (.getClass app)
(into-array String [])))
The problem is, this causes an UnsupportedOperationException:
UnsupportedOperationException start chat.graphics_tests.javafx_wrapper.proxy$javafx.application.Application$ff19274a.start (:-1)
It seems like it can't find the start method that I implemented. My first thought was that the arguments to start were wrong. They seem correct though. The first argument it receives is "this", then the primary stage. I tried different numbers of arguments though, and I still get the same error. According to the docs:
If a method fn is not provided for an interface method, an
UnsupportedOperationException will be thrown should it be
called.
Which further my this suspicion.
The errors quite vague. Does anyone see what the problem is?
When writing proxy class definitions in Clojure you do not need the explicit self parameter in the method signature. The current instance will be implicitly bound to this which you will be able to use inside the methods.
Therefore your proxy call should look like this:
(proxy [Application] []
(start [stage] (println "Hello World")))
This appears to be because Application/launch requires a named class, which proxy doesn't create. (see the comment at the bottom of the answer. I'm trusting #Sam here).
I ended up caving and using :gen-class, and got it working after some fiddling.

Do continuation record the PC and register states?

currently, when I am experimenting the continuation in functional languages, my understanding is that a continuation records the current program counter and register files, and when a continuation is returned, then the PC and the registered files will be restored to the values it has recorded.
So in the following dumb example from Might's blog post,
; right-now : -> moment
(define (right-now)
(call-with-current-continuation
(lambda (cc)
(cc cc))))
; go-when : moment -> ...
(define (go-when then)
(then then))
; An infinite loop:
(let ((the-beginning (right-now)))
(display "Hello, world!")
(newline)
(go-when the-beginning)) ; here the-beginning continuation passed to go-when, which ultimately will have an continuation applied to an continuation, that returns a continuation, which will cause the the program point resumed to the PC and registers states recorded in it.
I am not sure my understanding right.. Please correct me if you think it is not.....
Program counter and register files are not what the continuation records.
The best way to describe the meaning of call-with-current-continuation is that it records the program context. For instance, suppose you're evaluating the program
(+ 3 (f (call-with-current-continuation g)))
In this case, the context of the call-with-current-continuation expression would be
(+ 3 (f [hole]))
That is, the stuff surrounding the current expression.
Call-with-current-continuation captures one of these contexts. Invoking a continuation causes the replacement of the current context with the one stored in the continuation.
The idea of a context is a lot like that of a stack, except that there's nothing special about function calls in contexts.
This is a very brief treatment. I strongly urge you to take a look at Shriram Krishnamurthi's (free, online) book PLAI, in particular Part VII, for a more detailed and careful look at this topic.

Resources