Fork me on GitHub
#membrane
<
2024-02-17
>
Omer ZAK17:02:13

I ran the Hello World example from the https://github.com/phronmophobic/membrane/blob/master/docs/tutorial.md#hello-world and immediately noticed the following inconveniences: 1. I was not successful in figuring out how to run it under Babashka. However, I am not sure if it is possible at all. Was anyone else successful in doing so? 2. When running under Leiningen, default window size does not seem to take into account the client area size (I use the Xfce4 Desktop Environment version 4.16, running under Debian Bullseye) so I have to manually resize it. I use version 0.14.3-beta of membrane. How to set the initial window size to the size of client area (+ decorations, if necessary)? This is different from @zspovenetsky's problem - his window was minimized and the solution he got was to set the window size to hardwired numbers using :window-start-width,:window-start-height. Also, the Hello World example uses the membrane.java2d backend and I left it unchanged. 3. In the same environment as (2) above, when I kill the window, the application does not stop - seems that the event loop continues to run, until I hit Ctrl-C. I did not find in the tutorial anything about a way to have an intent finish/exit/quit the event loop.

chucklehead20:02:55

I'm trying out membrane in a project and can confirm I ran into #2, it seems the size in :window-start-width and :window-start-height applies to the whole window instead of just the content area. When opening the same application on different platforms the initial layout ends up different because the window chrome varies in size. Probably true of same platform with different window chrome settings, but I happened to notice it switching between native windows and wsl2 with the java2d backend.

phronmophobic20:02:48

> I was not successful in figuring out how to run it under Babashka. Membrane relies on native libraries that babashka doesn't include. Membrane is graalvm compatible, so it could be possible, in theory. I doubt babashka would include the necessary native libraries in the main build, but I think it could be made available as a pod. It's not a priority for me to support babashka, but if someone was interested, I would support that effort however I can. > How to set the initial window size to the size of client area Yes, :window-start-width and :window-start-height are the main parameters for adjusting the initial window size. Depending on the target platforms and backends, I can try to provide more specific advice. > In the same environment as (2) above, when I kill the window, the application does not stop This is a feature, not a bug! Killing the app when closing windows is really annoying for repl development, which membrane strongly supports. For applications that do want the process to stop when the window is closed, the backends support run-sync . If you start your application with run-sync in main, then it will return when all the windows are closed and the app should exit if the program hasn't done anything special like create a daemon thread.

Omer ZAK21:02:00

To clarify about run-sync: if you use, for example, the java2d backend, then instead of java2d/run use java2d/run-sync if you want to terminate the event loop when you close the window. (Was written in blood: neither Google nor ChatGPT 3.5 were helpful in explaining to me which namespace has run-sync. Also, my bad is that I glossed over the statement that "the backends support run-sync".)

phronmophobic21:02:44

The event loop should stop whenever you close all the windows regardless. It won't kill the process though, but those are two different things

Omer ZAK21:02:55

About killing the app when closing windows: if the application is not killed after having closed windows, how do I get them to be re-created? I noticed that REPL started by lein repl is not terminated when the application is terminated, and I had no problem re-running the application by entering (-main).

phronmophobic21:02:09

You can always open a new window.

Omer ZAK21:02:16

"It won't kill the process though, but those are two different things" What does the process do after the event loop has stopped, if it continues to live on?

phronmophobic21:02:05

It depends on the app. Inside a repl, it will wait for more input, just like a normal repl.

phronmophobic21:02:40

If the process has no daemon threads and the thread completes, then the process will quit

Omer ZAK21:02:11

From my experimentation, the REPL continues to live on, no matter if I start the window using java2d/run or java2d/run-sync. I hope the process is not mining bitcoin or something meanwhile while continuing to live on after the event loop exits. ๐Ÿ˜‚

phronmophobic21:02:46

Yes, that was a design goal to support repl driven development

phronmophobic21:02:04

You can always call System/exit if you want the repl do exit

phronmophobic21:02:42

Or do whatever you would normally do to exit the repl.

phronmophobic21:02:17

I think implementations that kill the process when they return are broken. Are there any normal clojure functions that kill the REPL when they finish?

Omer ZAK21:02:07

When I invoke a script using lein run inside project directory, it exits when its -main finishes. Unless it invokes java2d/run. When I run lein repl inside project directory, it normally remains in the REPL after I run the script by (-main). Even when it invokes java2d/run or java2d/run-sync. I did not check REPLs started from Emacs or VS Code plugins. Since run-sync exists, I do not care if you kill the process or keep it alive after exiting rum's event loop. However, for me, it violated the principle of least surprise. This is why I am discussing it now.

phronmophobic22:02:19

> When I run lein repl inside project directory, it normally remains in the REPL after I run the script by (-main). Even when it invokes java2d/run or java2d/run-sync. This is by design.

๐Ÿ‘ 1
phronmophobic22:02:36

> When I invoke a script using lein run inside project directory, it exits when its -main finishes. Unless it invokes java2d/run. I think this is also by design and java2d/run-sync should be used for this use case.

phronmophobic22:02:53

I'm happy to think about ways to update the docs, but clojure functions that kill your process without good reason are an anti-pattern.

Omer ZAK22:02:51

Switching to a different sub-topic. About :window-start-width and :window-start-height: is there any way to specify that they are to be equal to the client area dimensions?

phronmophobic22:02:28

You're using the java2d backend?

Omer ZAK22:02:53

Yes. However if such a way exists, it had better work the same way for all backends. Or maybe I should wish for window sizes equal to client area + any decorations added by desktop manager.

phronmophobic22:02:56

If someone actually has the use case of distributing an app targeting multiple backends and needs this feature, I'm happy to spend time on it, but it's not a priority for me if it's only a hypothetical requirement. It's also not really possible to support for all backends, because not all backends will let you set the window size (eg. mobile, terminal, future backends)!

phronmophobic22:02:44

I don't think it would be a lot of work and there are simple workarounds that can be use used that are only a dozen lines of code or so.

phronmophobic22:02:50

Basically, it can be done, but it's not directly straightforward. I would be happy to think about making it easy and straightforward, but I need a problem statement and real world use case before starting work on it.

Omer ZAK22:02:44

Maybe the right way to do it is to query #(ui/label "Hello World!") for its client area size. Then I'll invoke the GUI using:

(let [ gui #(ui/label "Hello World!")
       geometry (java2d/measure-client-region-size gui) ]
     (java2d/run-sync gui :window-start-width (+ 10 (:width geometry)) :window-start-height (+ 20 (:height geometry))))
and wait for some genius to define convenient helper functions to do all in idiomatic way.

phronmophobic22:02:18

yes, that's more or less what the workaround would look like

phronmophobic22:02:57

(let [ gui #(ui/label "Hello World!")
      [width height] (ui/bounds (gui)) ]
  (java2d/run-sync gui {:window-start-width (+ 10 width) :window-start-height (+ 20 height)}))

phronmophobic22:02:36

views are data that can be measured with ui/bounds

Omer ZAK22:02:44

I have checked, the ui/bounds based workaround works. The extras to be added to width and height (10,20 in your example) will have to be tweaked according to the backend + desktop, but once tweaked, should stay the same for all work on the developer's workstation.

๐Ÿ‘ 1
phronmophobic22:02:33

itโ€™s likely that the offsets can be queried directly or indirectly from the underlying windowing library for each backend