GTKmm: Quit application from callback

I'm trying to expand into GUI programming using GTKmm, and am making some progress. I am beginning to understand how it works, and I can am having little to no trouble getting my callbacks to function; But I'm stuck on a couple of things.

How do I make my File > Quit callback quit the application? I have no idea what to add/change to make it quit. Here's the callback as it was:
1
2
3
4
5
void file_quit_cb(GtkImageMenuItem *self, gpointer user_data)
{
	std::cout << "Quit callback activated!\n" << std::endl;
	self->quit(); // Line 25
}
But this fails to compile with
1
2
3
4
5
6
7
// I'm actually not surprised by this one, since when I think about it,
// self is just a pointer to the object that generated the signal.
main.cc:25: error: ‘struct _GtkImageMenuItem’ has no member named ‘quit’

// But this one is just a "WTF!?" moment for me. It's still irrelevant though,
// since that still only gets me the pointer to the generating object.
/usr/include/sigc++-2.0/sigc++/adaptors/adaptor_trait.h:251: error: no match for call to ‘(sigc::pointer_functor2<GtkImageMenuItem*, void*, void>) ()’

So then I was thinking maybe something like:
1
2
3
4
5
6
7
8
9
10
11
void file_quit_cb(Gtk::Main* kit)
{
    kit->quit();
}
int main(int argc, char* argv[])
{
    Gtk::Main* kit (argc, argv);
    // assume everthing else is set up. Just showing the connection.

    // This causes "Error: invalid use of void expression"
    file_quit->signal_activate().connect(file_quit_cb(&kit));

How far off am I, and what would be the correct way to do this?

Thank you in advance,
Lupus
To quit a GTKmm program you should call Gtk::Main::quit() ( it's a static function )
Here is how to connect signal handlers: http://library.gnome.org/devel/gtkmm-tutorial/stable/sec-connecting-signal-handlers.html.en
( you need to pass the function pointer, not a function call )
OK, got that figured out. Changed the connection to file_quit->signal_activate().connect(sigc::ptr_fun(kit.quit));, and that did work. But lets say I want to customize the clean up process, IE: write some final details to a log and close it, how would I pass kit to my handler?

Something just clicked in my mind as I was writing this: what if I put everything that directly deals with the UI into a class, and set kit as a private variable in that class? Then it would be in a scope accessible to the handler, without making it a global. I'll give that a try, so don't answer yet. I wanna see if this works. :)
You can create a handler and connect it to Gtk::Main::signal_quit if you want to perform actions
( that handler should return a bool: true means continue quitting, false don't quit )
http://library.gnome.org/devel/gtkmm/stable/classGtk_1_1Main.html#ac1b6ae5b79cb84158f3caf3e9382492d
Ok, so something like this then?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool file_quit_cb()
{
    // Do my clean ups, logs, etc
    return true;
}

int main(int argc, char* argv[])
{
    // assume all stuff is set up...
    // just showing call connects agian.
    file_quit->signal_activate().connect(sigc::ptr_fun(kit.quit)); // or kit.signal_quit?
    kit.signal_quit().connect(sigc::ptr_fun(file_quit_cb)); // should these lines be reversed?
    kit.run(*main_win);
}


My class implementation is coming together, but I'm thinking that putting all the UI stuff into a class just means more work. Perhaps I should leave it in main? Which way is viewed as standard?
Last edited on
(about quit) You need to connect to file_quit->signal_activate a function which calls Gtk::Main::quit()
If you want to display something like "Are you sure?" when quitting you can put it in the bool handler connected to kit.signal_quit
(about classes) GTKmm allows you to choose whether to use classes or not, there isn't an absolute rule. A class will make you write more than everything in main but it also makes the code a bit more organised. It's up to you decide which way you prefer.
Um... Ok. Wow. I feel hopelessly lost. lol. Can you give me an example of what you mean about quitting? I really wish the GTKmm documentation was written more like the C++ documentation here. Oh well... A coder can dream, can't he? LOL. Anyway, I'll keep trying, maybe I'll figure it out by chance by the type you reply... again.

As far as the classes, thank you. I think I'll keep using classes for doing most of my UI work. It may be more work, but I much prefer clean, organized, easy-to-read code. :)
Here is an example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <gtkmm.h>

void click_button() // called when you click the button
{
    Gtk::Main::quit();
}

bool quitting () // called when Gtk::Main quits
{
    Gtk::MessageDialog("Goodbye").run();
    return true;
}

int main(int argc, char *argv[])
{
    Gtk::Main kit(argc, argv);

    Gtk::Window window;
    Gtk::Button close("Close");
    window.add(close);
    close.signal_clicked().connect(sigc::ptr_fun(&click_button));
    Gtk::Main::signal_quit().connect (sigc::ptr_fun(&quitting));

    window.show_all();
    Gtk::Main::run(window);

    return 0;
}
Hrm... I can't even try. I finished the class, but now I keep getting an error when I try to compile, and it happens before we're even down to the part we've been discussing.

main.cc:19: error: no matching function for call to ‘GraphicInterface::GraphicInterface(int&, char**&, const char [20])’

main.cc:19
1
2
#define UI_FILE "/*path to glade file*/"
GraphicInterface gi (argc, argv, UI_FILE); // inside main() 


which calls, theoretically, graphic-interface.cc
1
2
3
GraphicInterface::GraphicInterface(int argc, char* argv, const char* UI_FILE) {}
// Defined in graphic-interface.h as
GraphicInterface(int, char*, const char*);


I had similar code working before in a different project, and I tried adapting that, but it still wouldn't work. To see that code, you can search ubuntuforums for bTouch and download my source package.
Are you trying to load a Glade interface?
Yes, I am. By default, my IDE uses .ui as the extension, but I doubt that has anything to do with it. I just have no idea why I'm getting that error. But now that I've had some sleep, I realize that I didn't try taking out each one of the arguments to see specificly which one argument isn't matching. I'll try that now.

And thank you for the example. That helps ALOT! lol.
Well, after taking a break from coding for a few days and coming back to it with a clear head, I was still unable to get the classes to work. However, I was able to revert my program to just main.cc, and after getting your example adapted to my code and running it through, I now understand that Gtk::Main::quit() emits Gtk::Main:signal_quit(), which I can then connect to a function of my own to do things like clean ups, log finalizations, and maybe throw up a confirmation dialog; And once that function returns true, the process of quitting is handed back to Gtk::Main::quit().

Now that I have this understanding, I'll go back and try to implement it as a class. Something tells me that while it would be more work for me, it would be much easier to implement a GUI through classes, as that allows main.cc to be much cleaner and much more compact; Focusing more on the main logic of the program, and breaking the UI into smaller, easier to understand chunks within their own source files. This would also require less work when I start working on multiple projects, as I would no longer need to recode items that are common between all my projects.
Topic archived. No new replies allowed.