Clemapfel / Mousetrap.jl

Finally, a GUI Engine made for Julia
https://clemens-cords.com/mousetrap
GNU Lesser General Public License v3.0
402 stars 9 forks source link

`gdk_x11_surface_get_xid` Segmentation Fault when initializing Mousetrap #25

Open ufechner7 opened 1 year ago

ufechner7 commented 1 year ago
julia> using Mousetrap
[ Info: Precompiling Mousetrap [5deeb4b9-6e04-4da7-8b7f-c77fb1eae65e]

[25147] signal (11.1): Segmentation fault
in expression starting at /home/ufechner/.julia/packages/Mousetrap/k0X9u/src/Mousetrap.jl:39
gdk_x11_surface_get_xid at /home/ufechner/.julia/artifacts/5498f875c31a1b3422ce1b64ef770407109eff30/lib/libgtk-4.so (unknown line)
Allocations: 815336 (Pool: 814877; Big: 459); GC: 1
ERROR: Failed to precompile Mousetrap [5deeb4b9-6e04-4da7-8b7f-c77fb1eae65e] to "/home/ufechner/.julia/compiled/v1.9/Mousetrap/jl_9p08JE".
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:35
 [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::IO, internal_stdout::IO, keep_loaded_modules::Bool)
   @ Base ./loading.jl:2300
 [3] compilecache
   @ ./loading.jl:2167 [inlined]
 [4] _require(pkg::Base.PkgId, env::String)
   @ Base ./loading.jl:1805
 [5] _require_prelocked(uuidkey::Base.PkgId, env::String)
   @ Base ./loading.jl:1660
 [6] macro expansion
   @ ./loading.jl:1648 [inlined]
 [7] macro expansion
   @ ./lock.jl:267 [inlined]
 [8] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1611

What I did: a. rename .julia to .julia.bak b. create a new project and install Mousetrap as described in the README.md

(Mouse) pkg> st
Status `~/repos/Mouse/Project.toml`
  [5deeb4b9] Mousetrap v0.2.0 `https://github.com/Clemapfel/mousetrap.jl#main`
  [7f2654e2] mousetrap_apple_jll v0.2.0+0 `https://github.com/Clemapfel/mousetrap_apple_jll#main`
  [b6bb2801] mousetrap_linux_jll v0.2.0+0 `https://github.com/Clemapfel/mousetrap_linux_jll#main`
  [1923bf96] mousetrap_windows_jll v0.2.0+0 `https://github.com/Clemapfel/mousetrap_windows_jll#main`
julia> versioninfo()
Julia Version 1.9.3
Commit bed2cd540a1 (2023-08-24 14:43 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 32 × AMD Ryzen 9 7950X 16-Core Processor
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, znver3)
  Threads: 1 on 32 virtual cores
Environment:
  LD_LIBRARY_PATH = /lib:/usr/lib:/usr/local/lib
ufechner@ufryzen:~$ uname -a
Linux ufryzen 6.2.0-32-generic #32~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug 18 10:40:13 UTC 2 x86_64 x86_64 x86_64 GNU/Linux

I tried mousetrap on a freshly installed virtual machine, and that worked. I could also install it successfully on Ubuntu 20.04.

Any idea how to debug this issue?

ufechner7 commented 1 year ago

Perhaps related: https://discourse.gnome.org/t/gdk-x11-surface-get-xid-hard-crashes-on-ubuntu-22-04/16818

Clemapfel commented 1 year ago

This time it shouldn't be a mousetrap issue, this is with the GTK backend and something about your windowing system. I can still try to help you get it working, since the GNOME forums will assume you're using C or Vala.

I can't reproduce this on my 22.04 machine, I tried Xorg and Wayland, which windowing system are you using? Could you try switching to others and see if the error persists? You can swap windowing system by choosing "log out" from the shutdown menu, then on the screen where you enter your password there's a cog in the bottom right where you can switch.

ufechner7 commented 1 year ago

Well, I am using X11, but I cannot easily switch the windowing system because I use an nvidia graphics card with the proprietary driver, and it does not support Wayland, so the selection of Wayland is disabled by default.

ufechner7 commented 1 year ago

OK, I tried with different graphic drivers. Not working: Nvidia-535 (tested by Ubuntu) Nvidia-525

Working: nouveau

Not the final solution because there is no OpenGL acceleration with the nouveau driver, but at least we know now better what works and what doesn't.

ufechner7 commented 1 year ago

Might this be related:

I am now using gdk_x11_surface_get_xid(gtk_native_get_surface(GTK_NATIVE(window))) to get an XID from a GTK window widget. – 
[Ank i zle](https://stackoverflow.com/users/10696946/ank-i-zle)
[Mar 15, 2022 at 2:10](https://stackoverflow.com/questions/71461608/gtk-window-to-gdk-surface-in-gtk4#comment126333979_71461608)
NittanyLion commented 1 year ago

fwiw: I'm getting the same error as @ufechner7 on Ubuntu 23.04 with X.

Clemapfel commented 1 year ago

fwiw: I'm getting the same error as ufechner7 on Ubuntu 23.04 with X.

Is this new in mousetrap v0.2.0 or did you have the same issue in 0.1.0?

Clemapfel commented 1 year ago

I don't have access to an nvidia graphics card and unlike with an OS I can't just spin up a VM to test it, so this might be hard for me to fix.

Just to isolate whether it's a mousetrap issue, can you install libadwaita_jll from the Julia package registry, then:

import libadwaita_jll
ccall((:adw_init, libadwaita_jll.libadwaita), Cint, ())

If that works, exit the Julia runtime, install GTK4_jll, then:

import GTK4_jll
ccall((:gtk_init, GTK4_jll.libgtk4), Cint, ())

If both work, please run:

import GTK4_jll, libadwaita_jll
begin
    ccall((:adw_init, libadwaita_jll.libadwaita), Cvoid, ())
    local window = ccall((:adw_window_new, libadwaita_jll.libadwaita), Ptr{Cvoid}, ())
    local area = ccall((:gtk_gl_area_new, GTK4_jll.libgtk4), Ptr{Cvoid}, ())
    ccall((:adw_window_set_content, libadwaita_jll.libadwaita), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), window, area)
    ccall((:gtk_window_present, GTK4_jll.libgtk4), Cvoid, (Ptr{Cvoid},), window)
    println(ccall((:gtk_widget_get_realized, GTK4_jll.libgtk4), Cint, (Ptr{Cvoid},), area) == true)
    exit()
end

It should print true to the console, with no other console output.

NittanyLion commented 1 year ago

fwiw: I'm getting the same error as ufechner7 on Ubuntu 23.04 with X.

Is this new in mousetrap v0.2.0 or did you have the same issue in 0.1.0?

First time I tried to install mousetrap.

ufechner7 commented 12 months ago

I don't have access to an nvidia graphics card and unlike with an OS I can't just spin up a VM to test it, so this might be hard for me to fix.

Just to isolate whether it's a mousetrap issue, can you install libadwaita_jll from the Julia package registry, then:

import libadwaita_jll
ccall((:adw_init, libadwaita_jll.libadwaita), Cint, ())

If that works, exit the Julia runtime, install GTK4_jll, then:

import GTK4_jll
ccall((:gtk_init, GTK4_jll.libgtk4), Cint, ())

If both work, please run:

import GTK4_jll, libadwaita_jll
begin
    ccall((:adw_init, libadwaita_jll.libadwaita), Cvoid, ())
    local window = ccall((:adw_window_new, libadwaita_jll.libadwaita), Ptr{Cvoid}, ())
    local area = ccall((:gtk_gl_area_new, GTK4_jll.libgtk4), Ptr{Cvoid}, ())
    ccall((:adw_window_set_content, libadwaita_jll.libadwaita), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), window, area)
    ccall((:gtk_window_present, GTK4_jll.libgtk4), Cvoid, (Ptr{Cvoid},), window)
    println(ccall((:gtk_widget_get_realized, GTK4_jll.libgtk4), Cint, (Ptr{Cvoid},), area) == true)
    exit()
end

It should print true to the console, with no other console output.

I tried the three tests, and all works fine, even when using the nvidia driver... Just using Moustrapfails...

But I did not try the suggestion from Tim Holy yet: https://docs.julialang.org/en/v1/devdocs/backtraces/

Clemapfel commented 12 months ago

I'm sorry you're still having trouble, I'm kinda forced to make you do the debugging since I can't test it myself, I apologize.

Could you try the following?

import libadwaita_jll, mousetrap_linux_jll
ccall((:adw_init, libadwaita_jll.libadwaita), Cvoid, ())
ccall((:_ZN9mousetrap6detail17initialize_openglEv, mousetrap_linux_jll.mousetrap_julia_binding), Cvoid, ())

Does that still crash?


If it says _ZN9mousetrap6detail17initialize_openglEv is not defined, run the following in Julia:

println(mousetrap_linux_jll.mousetrap_julia_binding)

Which will return a path, for me it's /home/clem/.julia/artifacts/2670af70bf210b40d1e852d7b5d644c76c0e7d01/lib/libmousetrap_julia_binding.so

Then, in your bash console, not in julia, run:

nm /home/clem/.julia/artifacts/2670af70bf210b40d1e852d7b5d644c76c0e7d01/lib/libmousetrap_julia_binding.so | grep initialize_opengl`

With the path you got from mousetrap_linux_jll, for me it's _ZN9mousetrap6detail17initialize_openglEv, then use that in the ccall above. You may need to install nm, it's sudo apt-get install binutils.

We're calling a mangled C++ name like a C library so we can call mousetrap::initialize_opengl directly, it's the best candidate for what could be crashing. If I knew which line in the C++ shared library called gdk_x11_surface_get_xid that would help a lot but your stacktrace doesn't say.

ufechner7 commented 12 months ago

Does that still crash?

Yes, it does:

julia> import libadwaita_jll, mousetrap_linux_jll

julia> ccall((:adw_init, libadwaita_jll.libadwaita), Cvoid, ())

julia> ccall((:_ZN9mousetrap6detail17initialize_openglEv, mousetrap_linux_jll.mousetrap_julia_binding), Cvoid, ())

[19474] signal (11.1): Segmentation fault
in expression starting at REPL[3]:1
gdk_x11_surface_get_xid at /home/ufechner/.julia/artifacts/5498f875c31a1b3422ce1b64ef770407109eff30/lib/libgtk-4.so (unknown line)
Allocations: 2998 (Pool: 2986; Big: 12); GC: 0
Segmentation fault (core dumped)
Clemapfel commented 12 months ago

Ok, perfect, I know how to work on a fix for this then. I'll try to get a hotfix out soon

Clemapfel commented 12 months ago

Hi, please run:

ENV["MOUSETRAP_DISABLE_OPENGL_COMPONENT"] = "TRUE"
import Pkg; Pkg.update("mousetrap_linux_jll")
using Mousetrap

Does that still crash?

ufechner7 commented 12 months ago

Looks better:

julia> ENV["MOUSETRAP_DISABLE_OPENGL_COMPONENT"] = "TRUE"
"TRUE"

julia> import Pkg; Pkg.update("mousetrap_linux_jll")
    Updating registry at `~/.julia/registries/General.toml`
    Updating git-repo `https://github.com/Clemapfel/mousetrap_linux_jll`
  No Changes to `~/repos/Mouse/Project.toml`
  No Changes to `~/repos/Mouse/Manifest.toml`

julia> using Mousetrap

julia> 

But the nvidia driver should support OpenGL, shouldn't it?

Clemapfel commented 12 months ago

It's not disabling OpenGL, it's just turning off everything related to the RenderArea widget. Mousetrap will still use the OpenGL backend for rendering and you still get the same performance.

The issue isn't that OpenGL isn't supported, it's that during creation of the global OpenGL state that is only used to store all the data of Shape and Texture, either GTK4 or GLEW fails to correctly access the windows surface because of some reason related to X11 with your driver. This hotfix just turns that part off so you can still use mousetrap.

If you want you can unset MOUSETRAP_DISABLE_OPENGL_COMPONENT and see if you get a new error, I made the context creation function a little bit more resilient. If yes, then we just have to wait until I can get my hands on an nvidia card so I can reproduce this and reach out to GNOME.

Clemapfel commented 12 months ago

I'll keep this open for anyone else running into this.

Solution

TL;DR: Certain NVIDIA drivers are causing an error in GTK4 when trying to initialize everything needed for the RenderArea widget to work. The current fix for this is to just turn off RenderArea, which we do by setting an environment variable.

1. Set MOUSETRAP_DISABLE_OPENGL_COMPONENT

Add the following line to your startup.jl

ENV["MOUSETRAP_DISABLE_OPENGL_COMPONENT"] = "TRUE"

If you are unsure of where startup.jl is located, you can access the path by running the following in the Julia REPL:

something(Base._global_julia_startup_file(), Base._local_julia_startup_file())

If you are unwilling or unable to modify startup.jl, you can also set the environment variable using your IDE, or, on unix, by appending the following line to your ~/.bashrc file:

export MOUSETRAP_DISABLE_OPENGL_COMPONENT=TRUE

2. Update mousetrap jlls

Open a fresh terminal session, enter the REPL, then update the mousetrap jll:

begin
   import
   Pkg.update("mousetrap_jll")
   Pkg.update("Mousetrap")
end

This should set the jll to version 0.3.0 or newer, while Mousetrap should be 0.3.0 or newer.

You should now be able to use mousetrap, with the exception of the RenderArea widget, which will print a log message when instantiated, but should not crash or otherwise affect the rest of the application:

using Mousetrap
area = RenderArea()
(process:185604): mousetrap-CRITICAL **: 14:32:36.464: In RenderArea(): trying to instantiate RenderArea, but the OpenGL component is disabled.
00krishna commented 11 months ago

I am also running into this error on Ubuntu 22.04 LTS with an Nvidia graphics card and 535 driver. I am using Moustrap version 0.3.0. Here is the entry from the manifest.

  [5deeb4b9] Mousetrap v0.3.0 `https://github.com/clemapfel/mousetrap.jl#main`

When I set ENV["MOUSETRAP_DISABLE_OPENGL_COMPONENT"] = "TRUE" at the prompt, then the basic Mousetrap gui comes up. When I tried the area = RenderArea() I get the mousetrap-CRITICAL **: 21:48:43.254: In RenderArea(): trying to instantiate RenderArea, but the OpenGL component is disabled. message.

Is there a way to test the OpenGL piece? How would I test that?

00krishna commented 11 months ago

UPDATE: This code worked. So a user can test whether OpenGL works with the complete example below. The code was taken from the Mousetrap test cases.

ENV["MOUSETRAP_DISABLE_OPENGL_COMPONENT"] = "TRUE"

module MousetrapMakie

    export GLMakieArea, create_glmakie_screen

    using Mousetrap
    using ModernGL, GLMakie, Colors, GeometryBasics, ShaderAbstractions
    using GLMakie: empty_postprocessor, fxaa_postprocessor, OIT_postprocessor, to_screen_postprocessor
    using GLMakie.GLAbstraction
    using GLMakie.Makie

    """
    ## GLMakieArea <: Widget
    `GLArea` wrapper that automatically connects all necessary callbacks in order for it to be used as a GLMakie render target. 

    Use `create_glmakie_screen` to initialize a screen you can render to using Makie from this widget. Note that `create_glmakie_screen` needs to be 
    called **after** `GLMakieArea` has been realized, as only then will the internal OpenGL context be available. See the example below.

    ## Constructors
    `GLMakieArea()`

    ## Signals
    (no unique signals)

    ## Fields
    (no public fields)

    ## Example
using Mousetrap, MousetrapMakie
main() do app::Application
    window = Window(app)
    canvas = GLMakieArea()
    set_size_request!(canvas, Vector2f(200, 200))
    set_child!(window, canvas)

    # use optional ref to delay screen allocation after `realize`
    screen = Ref{Union{Nothing, GLMakie.Screen{GLMakieArea}}}(nothing)
    connect_signal_realize!(canvas) do self
        screen[] = create_glmakie_screen(canvas)
        display(screen[], scatter(1:4))
        return nothing
    end
    present!(window)
end
```
"""
mutable struct GLMakieArea <: Widget

    glarea::GLArea              # wrapped native widget
    framebuffer_id::Ref{Int}    # set by render callback, used in MousetrapMakie.create_glmakie_screen
    framebuffer_size::Vector2i  # set by resize callback, used in GLMakie.framebuffer_size

    function GLMakieArea()
        glarea = GLArea()
        set_auto_render!(glarea, false) # should `render` be emitted everytime the widget is drawn
        connect_signal_render!(on_makie_area_render, glarea)
        connect_signal_resize!(on_makie_area_resize, glarea)
        return new(glarea, Ref{Int}(0), Vector2i(0, 0))
    end
end
Mousetrap.get_top_level_widget(x::GLMakieArea) = x.glarea

# maps hash(GLMakieArea) to GLMakie.Screen
const screens = Dict{UInt64, GLMakie.Screen}()

# maps hash(GLMakieArea) to Scene, used in `on_makie_area_resize`
const scenes = Dict{UInt64, GLMakie.Scene}()

# render callback: if screen is open, render frame to `GLMakieArea`s OpenGL context
function on_makie_area_render(self, context)
    key = Base.hash(self)
    if haskey(screens, key)
        screen = screens[key]
        if !isopen(screen) return false end
        screen.render_tick[] = nothing
        glarea = screen.glscreen
        glarea.framebuffer_id[] = glGetIntegerv(GL_FRAMEBUFFER_BINDING)
        GLMakie.render_frame(screen) 
    end
    return true
end

# resize callback: update framebuffer size, necessary for `GLMakie.framebuffer_size`
function on_makie_area_resize(self, w, h)
    key = Base.hash(self)
    if haskey(screens, key)
        screen = screens[key]
        glarea = screen.glscreen
        glarea.framebuffer_size.x = w
        glarea.framebuffer_size.y = h
        queue_render(glarea.glarea)
    end

    if haskey(scenes, key)
        scene = scenes[key]
        scene.events.window_area[] = Recti(0, 0, glarea.framebuffer_size.x, glarea.framebuffer_size.y)
        scene.events.window_dpi[] = Mousetrap.calculate_monitor_dpi(glarea)
    end
    return nothing
end

# resolution of `GLMakieArea` OpenGL framebuffer
GLMakie.framebuffer_size(self::GLMakieArea) = (self.framebuffer_size.x, self.framebuffer_size.y)

# forward retina scale factor from GTK4 back-end
GLMakie.retina_scaling_factor(w::GLMakieArea) = Mousetrap.get_scale_factor(w)

# resolution of `GLMakieArea` widget itself`
function GLMakie.window_size(w::GLMakieArea)
    size = get_natural_size(w)
    size.x = size.x * GLMakie.retina_scaling_factor(w)
    size.y = size.y * GLMakie.retina_scaling_factor(w)
    return (size.x, size.y)
end

# calculate screen size and dpi
function Makie.window_area(scene::Scene, screen::GLMakie.Screen{GLMakieArea})
    glarea = screen.glscreen
    scenes[hash(glarea)] = scene
end

# resize request by makie will be ignored
function GLMakie.resize_native!(native::GLMakieArea, resolution...)
    # noop
end

# bind `GLMakieArea` OpenGL context
ShaderAbstractions.native_switch_context!(a::GLMakieArea) = make_current(a.glarea)

# check if `GLMakieArea` OpenGL context is still valid, it is while `GLMakieArea` widget stays realized
ShaderAbstractions.native_context_alive(x::GLMakieArea) = get_is_realized(x)

# destruction callback ignored, lifetime is managed by mousetrap instead
function GLMakie.destroy!(w::GLMakieArea)
    # noop
end

# check if canvas is still realized
GLMakie.was_destroyed(window::GLMakieArea) = !get_is_realized(window)

# check if canvas should signal it is open
Base.isopen(w::GLMakieArea) = !GLMakie.was_destroyed(w)

# react to makie screen visibility request
GLMakie.set_screen_visibility!(screen::GLMakieArea, bool) = bool ? show(screen.glarea) : hide!(screen.glarea)

# apply glmakie config
function GLMakie.apply_config!(screen::GLMakie.Screen{GLMakieArea}, config::GLMakie.ScreenConfig; start_renderloop=true) 
    @warn "In MousetrapMakie: GLMakie.apply_config!: This feature is not yet implemented, ignoring config"
    # cf https://github.com/JuliaGtk/Gtk4Makie.jl/blob/main/src/screen.jl#L111
    return screen
end

# screenshot framebuffer
function Makie.colorbuffer(screen::GLMakie.Screen{GLMakieArea}, format::Makie.ImageStorageFormat = Makie.JuliaNative)
    @warn "In MousetrapMakie: GLMakie.colorbuffer: This feature is not yet implemented, returning framecache"
    # cf https://github.com/JuliaGtk/Gtk4Makie.jl/blob/main/src/screen.jl#L147
    return screen.framecache
end

# ignore makie event model, use the mousetrap event controllers instead
Makie.window_open(::Scene, ::GLMakieArea) = nothing
Makie.disconnect!(::GLMakieArea, f) = nothing
GLMakie.pollevents(::GLMakie.Screen{GLMakieArea}) = nothing
Makie.mouse_buttons(::Scene, ::GLMakieArea) = nothing
Makie.keyboard_buttons(::Scene, ::GLMakieArea) = nothing
Makie.dropped_files(::Scene, ::GLMakieArea) = nothing
Makie.unicode_input(::Scene, ::GLMakieArea) = nothing
Makie.mouse_position(::Scene, ::GLMakie.Screen{GLMakieArea}) = nothing
Makie.scroll(::Scene, ::GLMakieArea) = nothing
Makie.hasfocus(::Scene, ::GLMakieArea) = nothing
Makie.entered_window(::Scene, ::GLMakieArea) = nothing

"""
```
create_gl_makie_screen(::GLMakieArea; screen_config...) -> GLMakie.Screen{GLMakieArea}
```
For a `GLMakieArea`, create a `GLMakie.Screen` that can be used to display makie graphics
"""
function create_glmakie_screen(area::GLMakieArea; screen_config...)

    if !get_is_realized(area) 
        log_critical("MousetrapMakie", "In MousetrapMakie.create_glmakie_screen: GLMakieArea is not yet realized, it's internal OpenGL context cannot yet be accessed")
    end

    config = Makie.merge_screen_config(GLMakie.ScreenConfig, screen_config)

    set_is_visible!(area, config.visible)
    set_expand!(area, true)

    # quote from https://github.com/JuliaGtk/Gtk4Makie.jl/blob/main/src/screen.jl#L342
    shader_cache = GLAbstraction.ShaderCache(area)
    ShaderAbstractions.switch_context!(area)
    fb = GLMakie.GLFramebuffer((1, 1)) # resized on GLMakieArea realization later

    postprocessors = [
        config.ssao ? ssao_postprocessor(fb, shader_cache) : empty_postprocessor(),
        OIT_postprocessor(fb, shader_cache),
        config.fxaa ? fxaa_postprocessor(fb, shader_cache) : empty_postprocessor(),
        to_screen_postprocessor(fb, shader_cache, area.framebuffer_id)
    ]

    screen = GLMakie.Screen(
        area, shader_cache, fb,
        config, false,
        nothing,
        Dict{WeakRef, GLMakie.ScreenID}(),
        GLMakie.ScreenArea[],
        Tuple{GLMakie.ZIndex, GLMakie.ScreenID, GLMakie.RenderObject}[],
        postprocessors,
        Dict{UInt64, GLMakie.RenderObject}(),
        Dict{UInt32, Makie.AbstractPlot}(),
        false,
    )
    # end quote

    hash = Base.hash(area.glarea)
    screens[hash] = screen

    set_tick_callback!(area.glarea) do clock::FrameClock
        if GLMakie.requires_update(screen)
            queue_render(area.glarea)
        end

        if GLMakie.was_destroyed(area)
            return TICK_CALLBACK_RESULT_DISCONTINUE
        else
            return TICK_CALLBACK_RESULT_CONTINUE
        end
    end
    return screen
end

end

test

using Mousetrap, .MousetrapMakie, GLMakie main() do app::Application window = Window(app) set_title!(window, "Mousetrap x Makie") canvas = GLMakieArea() set_size_request!(canvas, Vector2f(200, 200)) set_child!(window, canvas)

# use optional ref to delay screen allocation after `realize`
screen = Ref{Union{Nothing, GLMakie.Screen{GLMakieArea}}}(nothing)
connect_signal_realize!(canvas) do self
    screen[] = create_glmakie_screen(canvas)
    display(screen[], scatter(rand(123)))
    return nothing
end
present!(window)

end