Reputation: 550
I'm looking to execute some code just after my Gtk3 window closes. I've tried delete-event
, destroy
, and destroy-event
which seems to not fire at all.
I get that there's some difference between Gdk and Gtk, but I'm not exactly sure about what that is. I assume I'm asking about the right thing.
I'm creating the window with the node.js binding of gtk_window_new()
, and closing it with gtk_window_close()
. When doing that, and using the events mentioned above, the event handlers fire while the window is still on the screen.
edit:
As requested, some example code:
const gi = require('node-gtk')
const Gtk = gi.require('Gtk', '3.0');
gi.startLoop();
Gtk.init();
const win = new Gtk.Window();
win.on('destroy', () => Gtk.mainQuit());
win.on('delete-event', () => false);
const button = new Gtk.Button({ label: 'Do it' });
win.add(button);
button.on('clicked', function () {win.close();});
win.showAll();
Gtk.main();
shell_command("wmctrl -lG");
function shell_command(cmd_str) {
const execSync = require('child_process').execSync;
code = execSync(cmd_str);
return code.toString();
}
On my Linux Mint 19.3 system, the above code creates a small window with 1 button. Clicking the button crashes execution with the following terminal error:
Error: Command failed: wmctrl -lG
X Error of failed request: BadWindow (invalid Window parameter)
Major opcode of failed request: 20 (X_GetProperty)
Resource id in failed request: 0x6c00003
Serial number of failed request: 26
Current serial number in output stream: 26
The window id 0x6c00003
is the window id of the window created by the above code, as proven by running wmctrl after running the script, but before pressing the button.
If I simply put the the call to wmctrl
in a 50ms timer, it works without error.
setTimeout(function () {shell_command("wmctrl -lG");}, 50);
This is what leads me to believe it's a race condition. I think wmctrl
is getting window ids when my window still exists, but then further querying against those ids after my window has closed, and it causes the above error. That's my theory, and if it's correct, Gtk.main()
returns before the window is truly gone (and the same is true of the other events mentioned).
Upvotes: 0
Views: 461
Reputation: 694
#include <gtk/gtk.h>
gboolean destroy(gpointer window, gpointer testing);
void destroy1(GtkWidget *window, gpointer testing);
int main(int argc, char *argv[]) {
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_add_events(GTK_WIDGET(window), GDK_ALL_EVENTS_MASK);
gtk_widget_show(window);
g_signal_connect(window, "destroy", G_CALLBACK(destroy1), NULL);
g_signal_connect(window, "destroy-event", G_CALLBACK(destroy), NULL);
gtk_main();
printf("closing application \n");
// you could try to add the code here
//which will be only be exited after the window is destroyed
sleep(10);
return 0;
}
void destroy1(GtkWidget *window, gpointer testing) {
printf("sleeping for 5 seconds \n");
gtk_widget_destroy(GTK_WIDGET(window));
sleep(5);
gtk_main_quit();
printf("i have slept \n");
}
gboolean destroy(gpointer window, gpointer testing) {
printf("sleeping for 5 seconds \n");
sleep(5);
printf("i have slept \n");
return TRUE;
}
After the window is destroyed completely the main loop will end. so, you could try adding you code after gtk_main();
The ::destroy-event signal is emitted when a gdk-window is destroyed. You rarely get this signal, because most widgets disconnect themselves from their window before they destroy it, so no widget owns the window at destroy time. (https://www.gnu.org/software/guile-gnome/docs/gtk/html/GtkWidget.html).
Upvotes: 1