1

I am trying to "raise" (draw "on top" of other overlapping windows and possibly make "active") a specific window in response to an event. The official FLTK documentation seems to say that the Fl_Window::show() method is the way to do this. However, there is no corresponding WindowExt::show() (or any similar) method in fltk-rs.

There is a WidgetExt::show() method, but it does not raise a window when invoked. There is also a similarly promising but similarly disappointing DoubleWindow::platform_show() method.

What I have gotten to work is to call .hide() and then immediately call .show() on the window in question. This produces the desired effect of raising the window in question to the top of the pile. However, this

  • Seems hacky, right? Like going around one's rear to reach one's elbow.
  • Really does hide then show the window. On my Debian system running i3, this is almost unnoticeable (the flicker might just be standard window-redrawing), but under Windows this is terrible, because .hide()ing the window triggers a short (but oh-so-noticeable) fade-out animation (and .show()ing it a corresponding fade-in animation, plus there might even be a little shrink/grow action happening, too), which is bad user experience and looks like something is malfunctioning.

Here's an example:


use fltk::{
    prelude::*,
    app::App,
    enums::Color,
    frame::Frame,
    window::DoubleWindow,
    button::Button,
};

fn main() {
    let a = App::default();
    
    let mut sub_win = DoubleWindow::default()
        .with_size(128, 128)
        .with_pos(64, 64);
    sub_win.set_border(false);
    sub_win.set_color(Color::Magenta); // So you can see it clearly.
    let _ = Frame::default().with_label("Sub Window")
        .with_size(128, 128)
        .with_pos(0, 0);
    sub_win.end();
    sub_win.show();
    
    let mut main_win = DoubleWindow::default().with_label("Main Window")
        .with_size(256, 128)
        .with_pos(0, 0);
    let mut b0 = Button::default().with_label("won't work")
        .with_size(96, 64)
        .with_pos(20, 32);
    let mut b1 = Button::default().with_label("is hacky")
        .with_size(96, 64)
        .with_pos(130, 32);
    main_win.end();
    main_win.show();
    
    b0.set_callback({
        let mut sub_win = sub_win.clone();
        move |_| {
            sub_win.show();          // The FLTK docs suggest this should work.
            sub_win.platform_show(); // This also disappoints.
        }
    });

    b1.set_callback(move |_| {
        sub_win.hide();          // This combination is what
        sub_win.show();          // actually works.
    });
    
    a.run().unwrap();
}

If anybody knows the magic incantation I seek, I'd appreciate it.

Edit

I guess I didn't do enough investigation beforehand. The problem does not seem to be with fltk-rs specifically; in fact, it may not even be with FLTK; it might be specific to my X11 or window manager settings.

For example, the following C++ program exhibits the exact same behavior as the Rust one above:

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>

Fl_Window *SUB_WIN;

void b_zero_cb(Fl_Widget *b) {
    SUB_WIN->show();
    SUB_WIN->redraw();
}

void b_one_cb(Fl_Widget *b) {
    SUB_WIN->hide();
    SUB_WIN->show();
    SUB_WIN->redraw();
}

int main(int argc, char **argv) {
    SUB_WIN = new Fl_Window(64, 64, 128, 128);
    Fl_Box *sub_label = new Fl_Box(0, 0, 128, 128, "Sub Window");
    SUB_WIN->color(FL_DARK_MAGENTA);
    SUB_WIN->border(false);
    SUB_WIN->xclass("Floating");
    SUB_WIN->end();
    SUB_WIN->show();
    
    Fl_Window *win = new Fl_Window(0, 0, 256, 128, "Main Window");
    Fl_Button *b0 = new Fl_Button(20, 32, 96, 64, "won't work");
    Fl_Button *b1 = new Fl_Button(130, 32, 96, 64, "hacky?");
    win->end();
    win->xclass("Floating");
    win->show();
    
    b0->callback(b_zero_cb);
    b1->callback(b_one_cb);
    
    return Fl::run();
}

Several commenters report that the Rust version works as expected on their systems, and neither of the above programs work as expected on my system, so I'm going to assume it's an issue with my system.

If it matters, I am using X11 with the i3 tiling window manager. (I do have it configured so that the windows in these examples are all automatically placed in the floating layer and not tiled; I'm not that dense.)

I'm not sure what to do with this questions. Should I just delete it?

d2718
  • 175
  • 8
  • 1
    FWIW, `sub_win.show()` in your above example is working for me on MacOS. Do [`DoubleWindow::flush`](https://docs.rs/fltk/latest/fltk/window/struct.DoubleWindow.html#method.flush) or [`WidgetExt::redraw`](https://docs.rs/fltk/latest/fltk/window/struct.DoubleWindow.html#method.redraw) help at all? – eggyal Jan 31 '22 at 11:12
  • @eggyal Interesting that it works on MacOS. `.show()` doesn't work for me on either Windows 10 or Linux/X11. (Neither do `flush` or `redraw`; I tried them again, just to make sure. Thanks for the suggestion, though.) – d2718 Feb 01 '22 at 09:12

1 Answers1

2

On the C++ end, Fl_Widget::show() is a virtual function that should raise the window, if the variable points to a top-level window (a window with no parent). On the Rust side, I see these lines:

extern "C" {
    pub fn Fl_Window_show(arg1: *mut Fl_Window);
}

which seem to indicate that there is a direct interface for calling Fl_Window::show(), and the same for Fl_Double_Window.

  • As Matthias said, `WidgetExt::show()` for Window and DoubleWindow actually map to `Fl_Window_show()` and `Fl_Double_Window_show()` which call `Fl_Window::show()` and `Fl_Double_Window::show()`. It's done in the src/macros/widget.rs file via a Rust macro: `unsafe { [<$flname _show>](self.inner) }` where flname resolves into the FLTK type name of the widget (for DoubleWindow it's Fl_Double_Window). – mo_al_ Feb 01 '22 at 06:44
  • @mo_al_ _obviously_ you are correct. I looked through both `fltk-rs` and your [`cfltk`](https://github.com/MoAlyousef/cfltk/tree/cc9f79bbc139ca0489e00e5c8a318f4bdf9bdae7) repo, and `Fl_Double_Window::show()` sure does look like it's getting called. I suppose the next thing to do is try an actual C++ FLTK example and see whether _it_ works as advertised. Man. – d2718 Feb 01 '22 at 10:00
  • It would be interesting to know on which system sub_win.show() doesn't raise the window since I can't reproduce the problem on Windows nor KDE running X11. From what I understood is that hide then show on windows flickers, but does show not raise the window on windows? Could it be a wayland issue? – mo_al_ Feb 01 '22 at 12:00
  • @mo_al_ Okay, so `.show()` works like it should on Windows; it still doesn't work on my Debian system, but I wrote a similar C++ test program, and it _also_ doesn't work properly on my Debian system, so I'm pretty sure it's specific to some aspect of my system: Debian 11 running X (definitely Xorg and not Wayland) and the [`i3`](https://i3wm.org/) window manager. I realize that i3 is a _tiling_ window manager, but I have it set up so that the windows in these test programs get auto-set to the floating layer (I'm not _that_ dumb). – d2718 Feb 02 '22 at 13:40
  • @mo_al_ My particular case may be enough of a corner one that it I realize it may not matter to you. The flickering is just because I am calling `.hide()` and then `.show()` immediately. It's not a big deal on my system; it's way more annoying on Windows, but it looks like I don't have to do it on Windows anyway because just calling `.show()` works like it should there. Thanks for responding, though! – d2718 Feb 02 '22 at 13:46