fltknon-modal

FLTK non_modal windows 'group' together if shown without multiple calls to Fl::wait() in between


The windows that are opened non_modally are 'grouped'. If you click on a window that is (partially) covered by another child, it will not come to the front. If you make enough wait() calls between the show() calls, this behavior changes. See the following example: The limit (on my machine) seems to be waitCount = 6. Everything below and the windows are grouped.

#include <FL/Fl.h>
#include <FL/Fl_Window.h>
#include <FL/Fl_Double_Window.h>


constexpr int windowCount = 4;
constexpr int waitCount = 8;

int main()
{
    Fl_Double_Window* mainWindow = new Fl_Double_Window(800, 600, "Main");
    mainWindow->show();
    Fl_Window* windows[windowCount];
    for (int i = 0; i < windowCount; i++)
    {
        windows[i] = new Fl_Window(300, 200, "Child");
        windows[i]->clear_modal_states();
        windows[i]->set_non_modal();
        windows[i]->show();
        for (int i = 0; i < waitCount; i++)
        {
            Fl::wait(1);
        }
    }
    return Fl::run();
}

What am I doing wrong? Is this behavior intentional or a bug in Fltk?


Solution

    1. non-modal is not the opposite of modal: it's a subset. non-modal windows are bound to their "parent" window in the same way as modal windows are, i.e. they stay on top of their "parent" window. Here "parent" is meant as the relation between the windows as the OS sees it and not a parent/child widget relation in FLTK. See https://www.fltk.org/doc-1.4/classFl__Window.html#aa95384f21fd3d1b559e116f9298e97c2

    2. Calling Fl::wait() as in the demo program is not the right way because showing windows is in parts platform dependent and can take some communication turnarounds until a window is fully shown. This is particularly true on X11. That's what Fl_Window::wait_for_expose() is designed for. It waits until a show()n window is fully displayed (and thus known to the OS). [slightly simplified]

    3. Please take care to use the correct case for #include statements in FLTK. Most of the header files use .H for C++ header files as opposed to C headers. On case sensitive file systems this is essential (unless you opt to install the FLTK compatibility headers which is not recommended).

    4. The following modified program does what FLTK would be expected to do on all platforms. All created windows are non-modal WRT their parents. To demonstrate this I added a number to the window titles.

    #include <FL/Fl.H>
    #include <FL/Fl_Double_Window.H>
    
    constexpr int windowCount = 7;
    
    int main()
    {
        Fl_Double_Window* mainWindow = new Fl_Double_Window(800, 600, "Main");
        mainWindow->show();
        Fl_Window* windows[windowCount];
        for (int i = 0; i < windowCount; i++)
        {
            char buf[20];
            sprintf(buf, "Child %2d", i+1);
            windows[i] = new Fl_Window(300, 200);
            windows[i]->copy_label(buf);
            windows[i]->clear_modal_states();
            windows[i]->set_non_modal();
            windows[i]->show();
            windows[i]->wait_for_expose();
        }
        return Fl::run();
    }
    
    1. The reason why you need to wait until a window is fully shown before you show another modal or non-modal window is that FLTK establishes the window relationship between the current top (front) window and the to-be-shown window, and this can only be done if (when) the previous window has been shown, i.e. after Fl_Window::wait_for_expose() returns.

    2. Further note to Fl::wait(time): this depends on event delivery, i.e. it returns prematurely before the time expired if any event is delivered to the program. Therefore moving the mouse or clicking can change the outcome significantly.