Search code examples
rustgtk

GTK window does not resize correctly when it contains a GLArea and another component


I am able to successfully create a GTK window with a GLArea component in it. When the GLArea is the only component in the window, the window can be resized normally.

use gtk::prelude::*;
use glium::Surface;
use std::os::raw::c_void;

// This struct taken from https://github.com/PonasKovas/gtk-glium
struct GLAreaBackend {
    glarea: gtk::GLArea,
}
unsafe impl glium::backend::Backend for GLAreaBackend {
    fn swap_buffers(&self) -> Result<(), glium::SwapBuffersError> {
        // GTK swaps the buffers after each "render" signal itself
        Ok(())
    }
    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        gl_loader::get_proc_address(symbol) as *const _
    }
    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        (self.glarea.allocated_width().try_into().unwrap(),
        self.glarea.allocated_height().try_into().unwrap())
    }
    fn is_current(&self) -> bool {
        // GTK makes it current itself on each "render" signal
        true
    }
    unsafe fn make_current(&self) {
        self.glarea.make_current();
    }
}
impl GLAreaBackend {
    fn new(glarea: gtk::GLArea) -> Self {
        Self { glarea }
    }
}

fn main() {
    let application = gtk::Application::builder().build();

    application.connect_activate(|app| {
        let window = gtk::ApplicationWindow::builder()
            .application(app)
            .title("test app")
            .default_width(640)
            .default_height(480)
            .build();

        gl_loader::init_gl();

        let gl_area = gtk::GLArea::builder()
            .expand(true)
            .halign(gtk::Align::Fill)
            .valign(gtk::Align::Fill)
            .auto_render(true)
            .has_alpha(false)
            .build();

        let button = gtk::Button::with_label("press me!");
        let container = gtk::Box::new(gtk::Orientation::Vertical, 0);
        container.pack_start(&gl_area, true, true, 0);
        //container.pack_start(&button, false, false, 0);
        window.add(&container);
        window.show_all();

        // from gtk-glium
        let gl_context = unsafe {
            glium::backend::Context::new(GLAreaBackend::new(gl_area.clone()),
                                         true,
                                         glium::debug::DebugCallbackBehavior::DebugMessageOnError).unwrap()
        };

        gl_area.connect_render(move |_, _| {
            let mut frame = glium::Frame::new(gl_context.clone(), gl_context.get_framebuffer_dimensions());
            frame.clear_color(1.0, 1.0, 0.5, 1.0);
            frame.finish().unwrap();
            Inhibit(true)
        });
    });

    application.run();
}

Window after normal resize

However, uncommenting then line //container.pack_start(&button, false, false, 0); causes the window to not render properly after being resized:

Window after glitchy resize

Does anyone know how to fix this?

EDIT: The problem persists without any OpenGL calls. The following simple example has the same issue. I am using Ubuntu 20.04.

use gtk::prelude::*;

fn main() {
    let application = gtk::Application::builder().build();

    application.connect_activate(|app| {
        let window = gtk::ApplicationWindow::builder()
            .application(app)
            .default_width(640)
            .default_height(480)
            .build();

        let gl_area = gtk::GLArea::builder()
            .auto_render(false)
            .build();

        let button = gtk::Button::with_label("press me!");
        let container = gtk::Box::new(gtk::Orientation::Vertical, 0);
        container.pack_start(&gl_area, true, true, 0);
        //container.pack_start(&button, false, false, 0);
        window.add(&container);
        window.show_all();
    });

    application.run();
}

Solution

  • The problem appears to be a minor bug in the GTK3 library, as it persists when using C and no OpenGL calls. Upgrading my project to GTK4 fixed it.

    I was able to find the solution at https://gitlab.gnome.org/GNOME/gtk/-/issues/1298, in particular the comment "it reproduces with gtk3-demo under X11, not with gtk4-demo."