pthom / hello_imgui

Hello, Dear ImGui: unleash your creativity in app development and prototyping
https://pthom.github.io/hello_imgui
MIT License
606 stars 91 forks source link

cannot run GUI from separate Python thread #33

Closed dcnieho closed 1 year ago

dcnieho commented 1 year ago

I am trying to run my hello_imgui gui in a separate Python thread, but it seems hello_imgui.run isn't able to do so on Mac OS. This code works fine on Windows and Linux (Ubuntu 22.04). On Mac OS, post_init is never called, the GUI is never shown, and the process spins eating all my CPU.

This is on an M1 mac, imgui_bundle 0.8.2 (compiled as part of the pip install, guess the wheel is only for the intel mac?), Mac OS 13.1, Python 3.10.9. Edit: just tested on an Intel Mac, same thing happens.

import time
import threading

from imgui_bundle import imgui, hello_imgui
import glfw

should_exit = False
def gui():
    if should_exit:
        print('requesting window close')
        hello_imgui.get_runner_params().app_shall_exit = True

    imgui.text("Bloat free code")

def post_init():
    print('post init')

def thread_fun():
    params = hello_imgui.RunnerParams()
    params.app_window_params.window_geometry.size = (100,200)
    params.app_window_params.window_title = "Hello!"
    params.fps_idling.fps_idle = 0
    params.callbacks.show_gui = gui
    params.callbacks.post_init = post_init

    print('lets go')
    hello_imgui.run(params)

if __name__ == "__main__":
    if True:
        thread = threading.Thread(target=thread_fun)
        thread.start()

        time.sleep(6)
        print('window should close')
        should_exit = True

        thread.join()
    else:
        thread_fun()
pthom commented 1 year ago

In my opinion, you'd better launch satellite threads around the main gui thread, instead of trying to launch the GUI in a satellite thread.

Here, I suspect you are fighting against Apple's recommended practices for an App. Anyhow, if you feel like exploring more, let me show you how you can do it.

  1. Method 1: debug C++ code HelloImGui is primarily a C++ project first, so it is easier to debug from C++.

  2. Method 2: debug inner C++ call from a python script

From ImGui Bundle , debug the C++ side using imgui_bundle/pybind_native_debug/

Simply edit pybind_native_debug.py so that it calls your script, and then you can debug the C++ side.

In your case, this showed me that your script raises an exception here:

int _glfwPlatformCreateWindow(_GLFWwindow* window,
                              const _GLFWwndconfig* wndconfig,
                              const _GLFWctxconfig* ctxconfig,
                              const _GLFWfbconfig* fbconfig)
{
    @autoreleasepool {

    if (!_glfw.ns.finishedLaunching)
        [NSApp run];             // this will fail
   ...

Callstack:

image

And NSApp is according to Apple, "the global variable for the shared app instance."

So, in this case, you are probably fighting against Apple's NSApplication and I don't know if it is possible to launch one of them outside of the main thread.

dcnieho commented 1 year ago

Hmm, some form of Apple knowing better again? Thank you very much for showing me how this is done as well as what you found.

I'll follow your advise and invert the logic so we have GUI in the main thread and processing in a separate thread. Its a little annoying though, the GUI in question is just a quick optional window showing output of my processing, and i run it in a separate thread so that processing is blocked as little as possible by actions for displaying the GUI. So GUI being the main thing and processing farmed out is an extra complication for an optional GUI, but alas, so be it.

Since this is not your problem, let me close this. Thanks again for the diagnosis and the great tooling you provide that makes this possible.