Search code examples
c++gtkwxwidgetsz-order

Modeless, parentless wxDialog still always above wxFrame window in z-order?


My program opens a wxFrame-based window and multiple modeless and parentless wxDialog-based windows. It all works beautifully, except that the wxDialog-based windows insist on always being on top of the wxFrame-based one.

I know about wxDIALOG_NO_PARENT, and I'm using it. The dialogs stay open when I close the wxFrame, so they definitely don't have the wxFrame window as a parent.

(If it matters, I'm using C++, wxWidgets 2.8.something, and running it on Ubuntu Linux. My program isn't ready to compile on any other platform, so I haven't tested it on others yet.)

I want all the windows to operate entirely independently, so the user can use the wxFrame window as well as the wxDialog ones. Can anyone point me in the right direction?


Solution

  • It seems that this behavior comes from a difference in how Gnome handles windows with different "type hints"...it puts them into their own z-index groupings:

    https://developer.gnome.org/gdk3/stable/gdk3-Windows.html#GdkWindowTypeHint

    The dialog is created with GDK_WINDOW_TYPE_HINT_DIALOG while your other window is most likely created with GDK_WINDOW_TYPE_HINT_NORMAL. The point where this decision is made is in gtk/toplevel.cpp and it's being cued by the fact that the "extra" style flags contain wxTOPLEVEL_EX_DIALOG:

    toplevel.cpp#L594

    Those are the only two calls to gtk_window_set_type_hint in the wxWidgets GTK codebase, except for in the splash screen code. So changing the "extra" style bits after the fact isn't going to help. (The "correct" solution would be to patch wxWidgets so that adjusting wxTOPLEVEL_EX_DIALOG in the extra styles would do the proper adjustment to the window type hint.)

    You can't use the wxDialog class without running through its constructor, which calls the non-virtual method wxDialog::Create, which sets the extra style to wxTOPLEVEL_EX_DIALOG and then goes directly to top level window creation:

    dialog.cpp#L54

    So I guess you have the option of trying this, which works if you haven't shown the dialog window yet:

    #ifdef __WXGTK__
    gtk_window_set_type_hint(
        GTK_WINDOW(iShouldBeUsingQtDialog->GetHandle()),
        GDK_WINDOW_TYPE_HINT_NORMAL);
    #endif
    

    ...and if you have shown the dialog already, you need to use this for it to work:

    #ifdef __WXGTK__
    gdk_window_set_type_hint(
        iShouldBeUsingQtDialog->GetHandle()->window,
        GDK_WINDOW_TYPE_HINT_NORMAL);
    #endif
    

    Both cases will require you to add an include file into your source:

    #ifdef __WXGTK__
    #include "gtk/gtkwindow.h"
    #endif
    

    ...and you'll have to update your build to find the GTK includes. On the command line for G++ I tried this and it worked:

    pkg-config --cflags --libs gtk+-2.0