I have a GTK4 Adwaita application built with GJS. I'm trying to add a PreferencesDialog
that pops up over the ApplicationWindow
but blocks interaction with the window, similar to a lot of other Adwaita applications (such as Gnome Text Editor). I dont want it to popup up within the window, as it's then confined to the window dimensions.
From what I can see, there are two options:
null
as a parameter. This sets the dialog as a sibling of the window, and is completely detached from it - the user can still interact with the application while the dialog is open, and can move the dialog independently from the window. This is not desired, either.So neither of these have the desired effect. Perhaps I'm missing some additional configuration required to match the behavior of Gnome Text Editors Preferences Dialog, or perhaps this is a limitation of GJS?
Adw.init();
const app = new Adw.Application();
app.connect("activate", () => {
const win = new Adw.ApplicationWindow({
application: app,
defaultHeight: 200,
defaultWidth: 200,
resizable: true,
});
const showDialog = new Gtk.Button({ label: "Show dialog" });
showDialog.connect("clicked", () => {
const dialog = new Adw.PreferencesDialog({
presentationMode: Adw.DialogPresentationMode.FLOATING,
});
dialog.present(null); // becomes sibling, completely detached from win ❌
// vs dialog.present(win); // becomes child, confined to win dimensions ❌
});
win.set_content(showDialog);
win.connect("close-request", () => app.quit());
win.present();
});
app.run([imports.system.programInvocationName].concat(ARGV));
I've tried to include a gif demonstrating how this works in Gnome Text Editor, but it keeps failing to upload. I've posted the example on Imgur.
The main thing I notice when inspecting the widgets of Gnome Text Editor while the PreferencesDialog is open, is that the dialog is a sibling of the window, not a child of it. Again, I havent been able to upload an image to StackOverflow showing this, so an image is included on Imgur
I'm not very familiar with C code, so I havent been able to fully understand how Gnome Text Editor implements this. Some things I notice, however:
So I'd really like to understand how Gnome Text Editor (and other GTK4 Adwaita apps) manage to create a preferences dialog pop over the window, block user interaction with the window, where moving the dialog also moves the window behind it, yet is not confined to the windows dimensions. And I'd like to understand how to implement the same behavior in my GJS app.
Thanks to StackOverflow finding a related question, the solution is:
Dont use a Adw.PreferencesDialog, use a Adw.PreferencesWindow instead
Set the dialog to be transient for on the main window
Related question: How to center a dialog window on the main window in GTK?
This doesnt seem to be how things are done in Gnome Text Editor, or Gnome Settings (they deffo use a dialog rather than windows, according to the widget inspector), but it meets my requirements.
However, note that Adw.PreferencesWindow is deprecated as of v1.6 (as per docs). While it mostly seems to work fine, I found that it wasnt being destroyed on close-request and left a bunch of hanging resources which caused critical errors when the app shut down. Because of this, I've went back to Adw.PreferencesWindow and just accept that the dialog will always be inside the window.
import Adw from "@girs/adw-1";
import Gtk from "@girs/gtk-4.0";
Adw.init();
const app = new Adw.Application();
app.connect("activate", () => {
const win = new Adw.ApplicationWindow({
application: app,
defaultHeight: 200,
defaultWidth: 200,
resizable: true,
});
const showDialog = new Gtk.Button({ label: "Show dialog" });
showDialog.connect("clicked", () => {
// CHANGE: create preferences window, transient for main window
const prefsWin = new Adw.PreferencesWindow({ transient_for: win });
// CHANGE: present with no params
prefsWin.present();
});
win.set_content(showDialog);
win.connect("close-request", () => app.quit());
win.present();
});
app.run([imports.system.programInvocationName].concat(ARGV));