wyvern010
Topic Author
Posts: 31
Joined: 18 Apr 2019, 13:41

Custom window manager MacOS with multiple windows.

29 Sep 2021, 23:48

Hi,

I'm making an application that will use multiple windows.
I got this working on Windows with my own window manager class.
#if NOESIS
using Noesis;
using NoesisApp;
#endif

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Managers
{
    public class WindowManager
    {
#if NOESIS
        static List<Window> _windows = new List<Window>();
        static List<Display> _displays = new List<Display>();
        static List<RenderContext> _contexts = new List<RenderContext>();
        static List<DateTime> _startTime = new List<DateTime>();

        static WindowManager _instance;

        T AddWindow<T>(T window) where T : Window
        {
            _windows.Add(window);
            return window;
        }

        T AddContext<T>(T context) where T : RenderContext
        {
            _contexts.Add(context);
            return context;
        }

        T AddDisplay<T>(T display) where T : Display
        {
            _displays.Add(display);
            return display;
        }

        public static WindowManager Instance => _instance;

        public WindowManager()
        {
            _instance = this;
        }

        public int WindowCount => _displays.Count;
        public Action OnRender;

        public void EnterMessageLoop(bool RunInBackGround)
        {
            _displays[0].EnterMessageLoop(false);
        }
        
        public void CreateWindow(Window window, Display display, RenderContext context)
        {
            Window _window = AddWindow(window);

            Display _display = AddDisplay(display);
            _display.SetResizeMode(ResizeMode.CanResize);

            RenderContext _context = AddContext(context);
            _context.Init(_display.NativeHandle, _display.NativeWindow, 1, true, false);

            _window.Init(_display, _context, 1, false, true, false, 0, 0, 0, 0);

            _display.Render += Render;
            _display.Closed += OnClosed;
            _display.Show();
            _startTime.Add(DateTime.Now);
        }

        void Render(Display display)
        {
            for (int i = 0; i < _displays.Count; i++)
            {
                _windows[i].Render((DateTime.Now - _startTime[i]).TotalSeconds);
            }
            OnRender?.Invoke();
        }

        void OnClosed(Display display)
        {
            int index = _displays.IndexOf(display);
            _displays.RemoveAt(index);
            _windows.RemoveAt(index);
            _contexts.RemoveAt(index);
            _startTime.RemoveAt(index);

        }
#endif
    }
}
To use this class i initialise windows as follows:
           WindowManager winManager = new WindowManager();
           winManager.CreateWindow(new MainWindow(), new Win32Display(), new RenderContextWGL());
           winManager.CreateWindow(new MainWindow(), new Win32Display(), new RenderContextWGL());

           while (winManager.WindowCount > 0)
           {
               winManager.EnterMessageLoop(true);
           }
           GUI.Shutdown();
This way i can successfully display any window i want on the fly.

However when i try this on MacOS it doesn't work as aspected.
I initialize 1 window on MacOS like so:
winManager.CreateWindow(new MainWindow(), new AppKitDisplay(), new RenderContextNSGL());
Now when i call:
  winManager.EnterMessageLoop(true);
The "Render(Display display)" callback in WindowManager gets only invoked once.
And the screen stays black.

Also, if i try to initialise 2 windows on MacOS i get an error:
System.InvalidOperationException: Init has already been invoked; it can only be invoked once.
Init() get called multiple times on Appkit.NSApplication.Init().
 
User avatar
jsantos
Site Admin
Posts: 3905
Joined: 20 Jan 2012, 17:18
Contact:

Re: Custom window manager MacOS with multiple windows.

30 Sep 2021, 12:08

We haven't tested the application framework with multiple windows. This is something we want to do sooner or later but for now, our examples do not require that and the application framework is the minimal set of features for the examples.

The source code is available and can be modified or you can even provide a different implementation. We can help you with the changes, just inspecting the code I see a few problems:
  • Appkit.NSApplication.Init() should be invoked only once, from the static ctor instead of normal ctor
  • EnterMessageLoop will only get messages for the first window, you need a mechanism to get also messages from the others. In windows this works because the messages are shared between windows of the same thread but it seems this is different on macOS.
 
wyvern010
Topic Author
Posts: 31
Joined: 18 Apr 2019, 13:41

Re: Custom window manager MacOS with multiple windows.

01 Oct 2021, 17:35

I'm now at a point where i can properly open 2 or more windows and close them 1 by 1 and the app will shut down nicely.

AppKitDisplay.cs i added:
        private static int _windowCount = 0;
        private static NSApplication _app;
        private static bool _init = false;
in the "public AppKitDisplay()" function i added:
        public AppKitDisplay()
        {
            if (!_init)
                NSApplication.Init();
            _init = true;
            
            _windowCount++;
            ...............
        }
And in the "OnClose()":
public void OnClosed()
        {
            IsClosed = true;
            _windowCount--;
            if (_windowCount == 0)
                _app.Terminate(null);
            Closed?.Invoke(this);
        }
Regards
 
User avatar
jsantos
Site Admin
Posts: 3905
Joined: 20 Jan 2012, 17:18
Contact:

Re: Custom window manager MacOS with multiple windows.

04 Oct 2021, 13:07

Great, for the messages (EnterMessageLoop) I think you need to pull all window messages from the first window. I think one client modified the source to do that.
 
wyvern010
Topic Author
Posts: 31
Joined: 18 Apr 2019, 13:41

Re: Custom window manager MacOS with multiple windows.

04 Oct 2021, 14:25

The behaviour of messages seems to be the same on mac as it is in windows.
For instance: Only the currently active window gets the user input.

Also had to modify Window.cs to actually take ratina display scaling into account which is 2 instead of 1.

I did fork the Managed repo (Wyvernius) and changes i made are under MacOSMultiWindow

Who is online

Users browsing this forum: Google [Bot] and 71 guests