feenkcom / gtoolkit

Glamorous Toolkit is the Moldable Development environment. It empowers you to make systems explainable through experiences tailored for each problem.
https://gtoolkit.com
MIT License
1.11k stars 48 forks source link

Image saved noninteractively doesn’t open a window when launched interactively #3901

Open Rinzwind opened 3 months ago

Rinzwind commented 3 months ago

Saving an image noninteractively seems to cause it to not open a window when launched interactively. Using Glamorous Toolkit v1.0.984 on macOS (Intel), when running the following, no window is opened at the second command:

$ ./GlamorousToolkit.app/Contents/MacOS/GlamorousToolkit-cli GlamorousToolkit.image \
     eval --save 'Smalltalk at: #Test put: DateAndTime now'
2024-07-16T00:10:49.298216+02:00
$ ./GlamorousToolkit.app/Contents/MacOS/GlamorousToolkit-cli --interactive GlamorousToolkit.image

When the first command is modified to also use --interactive (after unzipping the GToolkit download again), then a window does get opened at the second command.

Rinzwind commented 3 months ago

The following can be used to fix the image so that it opens a window again:

$ ./GlamorousToolkit.app/Contents/MacOS/GlamorousToolkit-cli --interactive GlamorousToolkit.image \
     eval --save 'GtWorld open'

Note that besides the GToolkit World opened by the above command, the image now also has another GToolkit World hosted in the Morphic World:

Edit: The above command may also cause the image to signal an AssertionFailure (“Can not create a window with invalid event loop”) when relaunched. Removing the --save option and clicking ‘Save’ instead seems better.

Rinzwind commented 1 month ago

The cause here is that when the image is run and saved noninteractively, the BlSpaceFrameHostValidationPhase changes the host of the GtWorld to a BlMorphicWindowHost. A BlWinitHost is not available while running noninteractively, but a BlMorphicWindowHost always is. Changing #isSupported for BlMorphicWindowHost to return Winit isInteractive causes the host of the GtWorld to be changed to a BlHeadlessHost instead. A BlHeadlessHost is also always available but conversely probably shouldn’t be when running interactively. Implementing #isStillAvailable on BlHeadlessHost as returning Winit isInteractive not causes the host of the GtWorld to be changed back to a BlWinitHost when running interactively again. A remaining problem then is that the GtWorld’s #extent is 0.0@0.0, which can be handled by including the following before the assignment to windowBuilder in #createWindowSpaceFor: on BlRustWindowingHost:

aSpace extent min = 0 ifTrue: [
    aSpace extent: aSpace defaultExtent ].

@girba: Could someone at feenk take a look at whether these changes can be applied and perhaps improved to not have the extent of the space reset to the default?

chisandrei commented 4 weeks ago

Currently we do not support the case of saving an interactive image as non-interactive. If you have an image that is interactive (so has a GUI) it should just be saved as interactive.

If in CI builds you need to start from a non-interative image, it would be better to use GlamorousToolkit-image-without-world.zip (every release on github has one such version of the image), and open the GUI as a last step of the build.

Rinzwind commented 4 weeks ago

Ah OK! I’m not sure I understand though. I tried the following using ‘GlamorousToolkit-image-without-world.zip’ v1.0.1139 with the corresponding macOS Intel VM. When running the saved image interactively, it opens two windows: the Morphic World and the default GToolkit World. Without the patches, only one window is opened: the Morphic World with the GToolkit World hosted within.

$ ./GlamorousToolkit.app/Contents/MacOS/GlamorousToolkit-cli GlamorousToolkit.image eval --save "
    BlMorphicWindowHost class compile: 'isSupported ^ Winit isInteractive'.
    BlHeadlessHost compile: 'isStillAvailable ^ Winit isInteractive not'.
    BlRustWindowingHost compile: ((BlRustWindowingHost sourceCodeAt: #createWindowSpaceFor:)
      copyReplaceAll: 'windowBuilder :='
      with: 'aSpace extent min = 0 ifTrue: [ aSpace extent: aSpace defaultExtent ]. windowBuilder :=').
    GtWorld openDefault"
seandenigris commented 4 weeks ago

Currently we do not support the case of saving an interactive image as non-interactive.

tl;dr: what approaches should we support in smalltalkCI and most importantly, what is the most sensible default approach?

A few things I don't understand:

seandenigris commented 4 weeks ago

tl;dr: either a) use --interactive with image including world, or b) image without world for non-interactive (can add world later)

My two questions above still stand, but here is all the various bits on info on this topic I could find:

Interactive vs. non-interactive

chisandrei commented 4 weeks ago

@Rinzwind I think there is something not right when you build the image. I think you save the GT image with the morphic world opened, and then also open a GT world.

What I tried is:

  1. start with GlamorousToolkit-image-without-world.zip and just run something headless: ./GlamorousToolkit.app/Contents/MacOS/GlamorousToolkit-cli GlamorousToolkit.image eval '1+1'

Here you could load code and save the image.

  1. Then as a last step open a GT world. You need to use GtWorld openDefault
    echo "[space := GtWorld openDefault. 5 seconds wait] on: Error do: [ :e | Smalltalk logError: e messageText inContext: e signalerContext. Smalltalk exitFailure ]. space universe snapshot: true andQuit: true." > gtworld.st
    ./GlamorousToolkit.app/Contents/MacOS/GlamorousToolkit-cli GlamorousToolkit.image st gtworld.st --interactive --no-quit

After this if you open GT with --interactive you get just a GT world.

If instead of 1. I use the script below to save the GT image when --interactive is set but no GT world is opened, we get a Morphic World.

Rinzwind commented 3 weeks ago

@chisandrei I hadn’t quite understood you meant to use --interactive on the CI as well, which I would prefer to avoid as that would seem to allow for a simpler CI setup. I tried the following, again using ‘GlamorousToolkit-image-without-world.zip’ v1.0.1139 with the corresponding macOS Intel VM. It differs from the command I gave before in the addition of the 5 seconds wait taken from your instructions. When the saved image is run interactively, it opens one window: the default GToolkit World. It would be nice if the patches to BlMorphicWindowHost, BlHeadlessHost and BlRustWindowingHost could be included in GToolkit, but I guess you see a possible problem with those?

$ ./GlamorousToolkit.app/Contents/MacOS/GlamorousToolkit-cli GlamorousToolkit.image eval --save "
    BlMorphicWindowHost class compile: 'isSupported ^ Winit isInteractive'.
    BlHeadlessHost compile: 'isStillAvailable ^ Winit isInteractive not'.
    BlRustWindowingHost compile: ((BlRustWindowingHost sourceCodeAt: #createWindowSpaceFor:)
      copyReplaceAll: 'windowBuilder :='
      with: 'aSpace extent min = 0 ifTrue: [ aSpace extent: aSpace defaultExtent ]. windowBuilder :=').
    GtWorld openDefault.
    5 seconds wait"
girba commented 3 weeks ago

@Rinzwind why do you specifically need those patches?

Rinzwind commented 3 weeks ago

@girba Not having to use --interactive would seem to allow for a simpler CI setup. Is there a reason for using it other than to avoid having the GToolkit World getting hosted in Morphic? That can be avoided instead by not supporting BlMorphicWindowHost when running noninteractively. The GToolkit World will get a BlHeadlessHost instead. Conversely, by making any BlHeadlessHost not available when running interactively, the GToolkit World’s host gets changed to a BlWinitHost when the image from the CI server is run interactively. These first two patches seem to make sense conceptually but I guess might have problems I’m not aware of. The third patch handles the GToolkit World’s width and height having been set to zero, that’s a workaround and could use improvement.

chisandrei commented 3 weeks ago

@Rinzwind Opening a GtWorld in an image not started with --interactive is not really meant to work. It is mostly undefined behaviour.

Normally you can start from GlamorousToolkit-image-without-world.zip and load code, or do any other operation without using --interactive. But if you aim for a image with a gui the last step on the CI should be a run with --interactive where you open a world. Otherwise you get a non-interactive image. That's also fine but then users downloading that image should first run that image using--interactive and open a default GtWorld. The part that will not work well is opening a gui when not running the image using using--interactive

girba commented 3 weeks ago

@Rinzwind maybe we do not quite understand what you want to achieve, but we are building images out of GT following the process described by @chisandrei above. Is that not sufficient?

Rinzwind commented 3 weeks ago

@chisandrei: I’m afraid I don’t quite understand what it means to “get a non-interactive image” other than that the host of the GtWorld is not a BlWinitHost. I understood ‘interactive’ to be more a property of the running VM than of the image.

@girba: I’d like to have our CI server build an image with our project loaded and have the image be runnable interactively. I’ll see whether I can get --interactive to work on our CI server, I haven’t figured out yet what I need to solve the “No suitable wgpu::Adapter found” error. Though I realize now that might not be necessary as the image from ‘GlamorousToolkit-image-without-world.zip’ will open the Morphic World when run interactively, given that I’d also like everyone to be able to continue working with the Morphic and Spec tools while exploring the GToolkit ones (hence also issues #3614, #3615, #3616 and #3889). Having the CI perform the send of #ensureDatabase as done by #openDefault would seem sufficient to make the world opened by the menu item built in #gtWorldMenuOn: usable.

girba commented 3 weeks ago

“No suitable wgpu::Adapter found” suggests that there is no hardware acceleration card setup for the CI server. Adding one should address the problem.

chisandrei commented 3 weeks ago

For the adapter issue if you are on a linux machine you can use xvfb-run and then you do not need to worry about the machine graphical setup. For example:

xvfb-run -a ./bin/GlamorousToolkit-cli ${ARTIFACT_FOLDER}/GlamorousToolkit.image st gtworld.st --interactive --no-quit
chisandrei commented 3 weeks ago

Also when opening the GtWorld for all things to work you might need to install EGL mesa

sudo apt-get update -y -qq
sudo apt-get install -y -qq libegl1-mesa        

#Check if EGL library exists
ldconfig -p | grep EGL
Rinzwind commented 3 weeks ago

Thanks for the hints, I’ll give that a try!

As a side note, something I thought might be interesting to post here is that I explored applying the backport of Pharo pull request #15647 and patching WinitWorldPixelsRenderer to make use of it. Here’s a screenshot of that using a Morphic-hosted GToolkit World just to show it’s GT and not standard Pharo (compare with the screenshot I posted above, click to zoom in):