Garethmoffatt
Posts: 39
Joined: Sat Feb 25, 2017 10:11 pm

Gtk3 exiting through delete_event handler (SOLVED)

Sat Jun 23, 2018 3:43 pm

I have a gtk3 application that i have written that includes a delete_event handler.

When I click the window X, it handles a "do you want to quit?" message box and saves data if it has changed etc.

There are other places in my code where I also want to have the program terminate, but elegently through the delete_event handler... not through a g_application_quit() call for example.

I have tried using g_signal_emit_by_name and that does call the handler, and seams to work if I choose not to quit. But if I do try to quit (by returning false from the handler), I get a bunch of gtk-critical assertion failures and the program either hangs up or finally exits with segmentation fault.

Code: Select all

      g_signal_emit_by_name(parent,"delete_event");
I have delcared parent globally

Code: Select all

GtkWidget *parent;
And set it in activate()

Code: Select all

   parent = gtk_application_window_new(app);
   g_signal_connect(parent, "delete-event", G_CALLBACK(delete_event), NULL);
   g_signal_connect(parent, "destroy", G_CALLBACK(destroy), NULL);
I guess I am using the wrong parameters in the call to g_signal_emit...

Anybody give me any clues - or tell me the proper way to do what I want to do!

Thanks,

Gareth
Last edited by Garethmoffatt on Tue Jun 26, 2018 5:53 pm, edited 1 time in total.

User avatar
PeterO
Posts: 4183
Joined: Sun Jul 22, 2012 4:14 pm

Re: Gtk3 exiting through delete_event handler

Sat Jun 23, 2018 7:36 pm

Can you provide a small complete program that shows this behaviour ?

It's much easier to investigate if we can run something for ourselves that demonstrates the problem.

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

Garethmoffatt
Posts: 39
Joined: Sat Feb 25, 2017 10:11 pm

Re: Gtk3 exiting through delete_event handler

Tue Jun 26, 2018 3:50 am

Sorry it has taken a while to post code.

Here is a cut down example that responds almost like the main program I am working on.

Code: Select all

#include <gtk/gtk.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <termios.h>
#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define true TRUE
#define false FALSE

#define DOES_NOTHING_BUTTON 1
#define QUIT_BUTTON 2

GtkWidget *parent;

static void button_click_cb(GtkWidget * widget, gpointer data)
{
   gint which;

   g_print("Button Pressed\n");

   which = GPOINTER_TO_INT(data);

   switch (which) {
   case QUIT_BUTTON:
      g_signal_emit_by_name(parent,"delete_event");
      break;
   }
}

static gboolean delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
{
   gint result;

  GtkWidget *mbox;

   mbox =
       gtk_dialog_new_with_buttons("Quit?", GTK_WINDOW(widget),
               GTK_DIALOG_DESTROY_WITH_PARENT, "_Quit", 0, "_Cancel", 1, NULL);

   gtk_dialog_set_default_response(GTK_DIALOG(mbox), 1);

   result = gtk_dialog_run(GTK_DIALOG(mbox));

   gtk_widget_destroy(mbox);

   g_print("delete event occurred\n");
   /* Change TRUE to FALSE and the main window will be destroyed with
    * a "delete-event". */


   if (result == 0)
      return (false);
   else
      return (true);
}

static int destroy(GtkWidget * widget, gpointer data)
{

   return (FALSE);
}

static void activate(GtkApplication * app, gpointer user_data)
{
   /* GtkWidget is the storage type for widgets */
   GtkWidget *window;
   GtkWidget *button;
   GtkWidget *container;
   GtkWidget *topContainer;

   /* create a new window */
   window = gtk_application_window_new(app);
   parent = window;  // save this as a meaningful pointer, could so renamed window as parent...
   g_signal_connect(window, "delete-event", G_CALLBACK(delete_event), NULL);
   g_signal_connect(window, "destroy", G_CALLBACK(destroy), NULL);

   /* Sets the border width of the window. */
   gtk_container_set_border_width(GTK_CONTAINER(window), 10);
   gtk_window_set_title(GTK_WINDOW(window), "Simple test emit");

   /* Start building first column */
   topContainer = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1);
   container = gtk_box_new(GTK_ORIENTATION_VERTICAL, 1);

   // build buttons column
   button = gtk_button_new_with_label("Does Nothing");
   gtk_box_pack_start(GTK_BOX(container), button, true, true, 1);
   g_signal_connect(button, "clicked", G_CALLBACK(button_click_cb), GINT_TO_POINTER(DOES_NOTHING_BUTTON));
   button = gtk_button_new_with_label("Quit");
   gtk_box_pack_start(GTK_BOX(container), button, true, true, 1);
   g_signal_connect(button, "clicked", G_CALLBACK(button_click_cb), GINT_TO_POINTER(QUIT_BUTTON));

// put column in to top container
   gtk_box_pack_start(GTK_BOX(topContainer), container, false, false, 1);


   /* put the composite container in to the top level window */
   gtk_container_add(GTK_CONTAINER(window), topContainer);

// show all widgets
   gtk_widget_show_all(window);

}

int main(int argc, char **argv)
{
   GtkApplication *app;
   int status;

   tzset();    // call to set timezone

   app = gtk_application_new("org.gmail.mipi.gareth.simple", G_APPLICATION_FLAGS_NONE);
   g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
   status = g_application_run(G_APPLICATION(app), argc, argv);
   g_object_unref(app);

   return status;
}
Here is the make file

Code: Select all

simple : simple.o
	gcc -Wall -g -o simple simple.o `pkg-config --libs --cflags gtk+-3.0` -lm

simple.o : simple.c
	gcc -Wall -g -c simple.c `pkg-config --libs --cflags gtk+-3.0`
The similarities are that exiting using the window X works for both the small example and the larger version.

The differences are that the simple example crashes with a segmentaion fault if you press the quit button and then cancel, where as the big example does not.

Both fail with a long list is assert errors if you press the quit button and then the next quit button.

Clues would be greatly appreciated.

Thanks

Gareth

User avatar
PeterO
Posts: 4183
Joined: Sun Jul 22, 2012 4:14 pm

Re: Gtk3 exiting through delete_event handler

Tue Jun 26, 2018 8:26 am

Looking at your code, I wouldn't do it that way !

I think your code should display the dialog box from within button_clicked_cb and use the return value to decide if the delete event should be sent or not.
I think trying to display a dialog within the delete event handler is a bad idea.

However it doesn't explain the behaviour, which by the way is different on an X86-64 MINT box and a PI.

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

Garethmoffatt
Posts: 39
Joined: Sat Feb 25, 2017 10:11 pm

Re: Gtk3 exiting through delete_event handler

Tue Jun 26, 2018 11:10 am

The reason for the “ are you sure?” Message in the delete handler is because I want to ask the question and save files etc independent of why the program exits.

I can move the msg box etc in to a function that gets called from delete, but I’m not sure if that solves your concern.

Up till I wanted to call delete_event under program control, rather than just from the window manager, it has been working ok. ( I believe) the problem I think I have is the signal_emit code- but I could be wrong.

Any clues for debugging?

Thanks

Gareth

User avatar
PeterO
Posts: 4183
Joined: Sun Jul 22, 2012 4:14 pm

Re: Gtk3 exiting through delete_event handler

Tue Jun 26, 2018 12:59 pm

I've never used an "application" window so I don't know if the behaviour is due to that...

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
Paeryn
Posts: 2020
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Gtk3 exiting through delete_event handler

Tue Jun 26, 2018 3:09 pm

You don't really want to be signalling delete-event yourself, you can just tell it to close the window if you really clicked on Quit.
In your button_click_cb() function (why did you call the window "parent"?) :-

Code: Select all

   case QUIT_BUTTON:
      gtk_window_close(GTK_WINDOW(parent));
      break;
   }
If you really want to manually call the signals it's more involved, I'm a bit hazy on GTK's internals but I think :-

The delete-event signal returns a value but when you explicitly signalled it you didn't give an address to store that result, nor did you pass an event to the signal, since you didn't provide these they would take on random values (either in registers or on the stack).
You can pass NULL as the event pointer if you want since you don't use it in your delete_event. I think that since you are manually signalling the event then it is up to you to also call the destroy event if that is what you want to happen. At least that what my limited testing showed.

Code: Select all

static void button_click_cb(GtkWidget * widget, gpointer data)
{
   gint which;
   gboolean result = false;

   g_print("Button Pressed\n");

   which = GPOINTER_TO_INT(data);

   switch (which) {
   case QUIT_BUTTON:
      g_signal_emit_by_name(parent,"delete_event", NULL, &result);
      if (result == false)
          g_signal_emit_by_name(parent, "destroy");
      break;
   }
}
She who travels light — forgot something.

Garethmoffatt
Posts: 39
Joined: Sat Feb 25, 2017 10:11 pm

Re: Gtk3 exiting through delete_event handler

Tue Jun 26, 2018 5:52 pm

Paeryn,

Thanks

Code: Select all

gtk_window_close(...)
Does exactly what I want to do by calling the delete_event handler for me.

I'm pretty much self taught so was looking to Google to provide the answers and was drawing a blank. I knew I wanted to go out through the delete_event handler so that the window X and any programmatically generated exits went out through the same route and were thus subject to the same checking and graceful close out. Calling the handler seamed to be a means to that end, but was not as easy as I'd hoped.

I'd tried functions that included _quit() but that just dumped me out without the "are you sure" checks and saving files that I do in the delete_event handler.

I'm perfectly happy to avoid the calling of the signal directly as that looks like black magic to me :roll:

To answer your parenthetical question, I called it parent because I could... I suppose this is ambiguous because parent does not always mean the very top level window, and widgets have (or can have) parents that are not the top level window... In your opinion what should I call the top level window?

Thanks again,

Gareth

User avatar
Paeryn
Posts: 2020
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Gtk3 exiting through delete_event handler (SOLVED)

Tue Jun 26, 2018 10:31 pm

gtk_window_close() came in 3.10 and simulates the close request for you properly. The manual way of generating the event is this rather than emitting a signal :-

Code: Select all

          GdkEvent *event = gdk_event_new(GDK_DELETE);
          event->any.window = g_object_ref(gtk_widget_get_window(parent));
          event->any.send_event = true;
          gtk_main_do_event(event);
          gdk_event_free(event);
Basically you have to create a proper event structure and make the main loop handle it. The above is roughly what gtk_window_close() ends up doing except that it actually adds that code to the list of things to do when idle rather than immediately running it.

Oh, and as a suggestion for the name of the window rather than parent, main_window. It doesn't really matter as long as you know, it just makes it easier when you come back to the code a year from now and have to work out what you meant by parent (i.e. whose parent).
She who travels light — forgot something.

Return to “Graphics programming”

Who is online

Users browsing this forum: No registered users and 3 guests