2025, Oct 04 15:00

Gtk.FileChooserDialog opens at the wrong size? Make it stick using show + resize(width, height)

Troubleshooting Gtk.FileChooserDialog sizing on Ubuntu 24.04: prevent remembered geometry by calling resize(width,height) on show and avoid -1 dimensions.

Gtk.FileChooserDialog that refuses to stick to the requested size can be confusing, especially when everything looks correct on paper. If your dialog opens taller than asked, jumps to a tiny view on the first manual resize, or keeps resurrecting an old geometry, you are running into a mix of remembered window size and when exactly the size is applied.

Problem demo

The following minimal example shows a file chooser that should open at a specific height, yet it appears larger and behaves oddly on first manual resize. It also tries to enforce a smaller minimum size and a default size with -1 for width.

import sys
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GLib, Gtk
class Picker(Gtk.FileChooserDialog):
    def __init__(self, title=None, parent=None):
        super().__init__(
            title=title,
            parent=parent,
            action=Gtk.FileChooserAction.OPEN,
            default_height=500,
        )
        self.set_default_size(-1, 500)
        self.set_size_request(-1, 300)
        self.add_buttons(
            Gtk.STOCK_CANCEL,
            Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN,
            Gtk.ResponseType.OK,
        )
        self._install_filters()
        self._run_dialog()
    def _install_filters(self):
        txt_filter = Gtk.FileFilter()
        txt_filter.set_name(".txt files")
        txt_filter.add_mime_type("text")
        self.add_filter(txt_filter)
    def _run_dialog(self):
        result = self.run()
        self.destroy()
class DemoApp(Gtk.Application):
    def __init__(self):
        super().__init__(application_id="com.gnome.test")
        GLib.set_application_name("test")
    def do_activate(self):
        self.win = Gtk.ApplicationWindow(application=self, title="App")
        grid = Gtk.Grid()
        self.win.add(grid)
        btn = Gtk.Button(label="From")
        grid.attach(btn, 0, 0, 1, 1)
        grid.set_row_homogeneous(True)
        grid.set_column_homogeneous(True)
        btn.connect("clicked", self._on_pick)
        self.win.set_default_size(width=500, height=34)
        self.win.show_all()
    def _on_pick(self, _widget):
        picker = Picker(title="Chooser", parent=self.win)
        picker.set_default_size(-1, 400)
app = DemoApp()
code = app.run(sys.argv)
sys.exit(code)

What’s going on

There are two key observations. First, on systems based on Ubuntu 24.04 the dialog can remember its previous size and run() can apply that stored geometry, overriding the dimensions you asked for earlier. Second, using -1 for one of the dimensions interferes with the expected outcome in this case. This combination explains why the dialog opens taller than requested and why the first manual resize may jump to an unexpected tiny view that looks like only a child widget is visible.

Forcing a fixed size with set_resizable(False) produces the expected geometry, but manual resizing becomes impossible, which is rarely desirable for a file chooser.

There is also an environment-specific twist. When running with MATE on Linux Mint based on Ubuntu 24.04, the system remembers the dialog size across script runs and brings it back, which may change the size after you set it.

Solution

Make the size decision as late as possible and avoid -1 for dimensions in this scenario. Connecting to the show signal and calling resize(width, height) with both values explicitly ensures the dialog takes your size after any previously remembered geometry is applied. This avoids the first-resize glitch and gives you a resizable window. The calls to set_default_size and set_size_request are not needed here.

import sys
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GLib, Gtk
class PickerFixed(Gtk.FileChooserDialog):
    def __init__(self, title=None, parent=None):
        super().__init__(
            title=title,
            parent=parent,
            action=Gtk.FileChooserAction.OPEN,
        )
        self.add_buttons(
            Gtk.STOCK_CANCEL,
            Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN,
            Gtk.ResponseType.OK,
        )
        self._apply_filters()
        self.connect("show", self._on_show)
        self._open()
    def _apply_filters(self):
        txt_filter = Gtk.FileFilter()
        txt_filter.set_name(".txt files")
        txt_filter.add_mime_type("text")
        self.add_filter(txt_filter)
    def _on_show(self, *_args):
        self.resize(800, 500)
    def _open(self):
        result = self.run()
        self.destroy()
class DemoApp(Gtk.Application):
    def __init__(self):
        super().__init__(application_id="com.gnome.test")
        GLib.set_application_name("test")
    def do_activate(self):
        self.win = Gtk.ApplicationWindow(application=self, title="App")
        grid = Gtk.Grid()
        self.win.add(grid)
        btn = Gtk.Button(label="From")
        grid.attach(btn, 0, 0, 1, 1)
        grid.set_row_homogeneous(True)
        grid.set_column_homogeneous(True)
        btn.connect("clicked", self._trigger")
        self.win.set_default_size(width=500, height=34)
        self.win.show_all()
    def _trigger(self, _w):
        PickerFixed(title="Chooser", parent=self.win)
app = DemoApp()
exit_code = app.run(sys.argv)
sys.exit(exit_code)

Why it matters

File pickers are muscle-memory UI. Users expect predictable sizes and responsive resizing, especially on modern desktops with varying themes and DE policies. Handing size control at the right moment prevents jarring jumps, honors user intent, and sidesteps environment-level geometry recall that would otherwise surprise you on the first resize or across runs.

Takeaways

If the dialog opens at the wrong height or snaps unpredictably on the first resize, assume a previously remembered size is being enforced by run(). Apply your geometry on show and specify both width and height in resize to get deterministic behavior. Avoid -1 for dimensions in this case. Using set_resizable(False) will force the size but removes manual resizing, so reserve it for scenarios where a fixed dialog is acceptable.

The article is based on a question from StackOverflow by Sun Bear and an answer by furas.