Is HelloWindow object deleted? - c++

I created a sample GTKMM project on GNOME Builder. The great thing was that a sample hello world code was automatically generated for my sample project. Since C++ source files are organized into three parts:
Header file
Implementation file
Main file
I've modified my sample code in a single cpp file for demonstration:
#include <iostream>
#include <gtkmm.h>
using std::cout;
using Gtk::Application;
using Gtk::Window;
using Gtk::Box;
using Gtk::Button;
using Gtk::Label;
class HelloWindow : public Window
{
Box box;
Button button;
Label label;
public:
HelloWindow();
~HelloWindow();
};
HelloWindow::HelloWindow()
: Glib::ObjectBase("HelloWindow")
, Window()
, box(Gtk::ORIENTATION_VERTICAL)
, button("Clickable button")
, label("Hello World!")
{
set_default_size(320, 240);
bool expand(true), fill(true);
box.pack_start(label, expand, fill);
box.pack_end(button, expand, fill);
add(box);
show_all();
}
HelloWindow::~HelloWindow()
{
cout << "Object successfully destructed!\n";
}
static void
on_activate(Glib::RefPtr<Application> app)
{
Window *window = app->get_active_window();
if (not window) {
window = new HelloWindow();
window->set_application(app);
app->add_window(*window);
}
window->present();
}
int main()
{
auto app = Application::create("io.test.window-state-event");
app->signal_activate().connect(sigc::bind(&on_activate, app));
return app->run();
}
One interesting part about the above code is that app is connected to on_activate signal which means the user gets to run only one instance of this program. And if he tries to run another instance the previous still running window will instead be presented.
However, there is the use of new keyword on on_activate() and that confuses me a bit. Is the object really deleted when the user closes the HelloWorld window? What I've learnt about C++ new keyword is that one must remember to delete any object allocated with the former keyword.
Moreover, the destructor message "Object successfully destructed!" isn't printed when the window is closed.

Chances are there is an intentional leak, but it's "controlled". The author knows that this method will be called only once. The author also knows the memory needs to be active the entire lifetime of the application. When the application closes, that memory will be freed one way or another (albeit the destructor will never be called, but in this case, there is nothing imperative that would need to be done)
It's perfectly fine in this scenario.
If you want to ensure the Window object gets deleted, you could keep a unique_ptr of the Window and it will dispose itself (thanks to #underscore_d comment):
#include <memory>
static std::unique_ptr<Window> window;
static void
on_activate(Glib::RefPtr<Application> app)
{
if (!window) {
window = std::make_unique<HelloWindow>();
window->set_application(app);
app->add_window(*window);
}
window->present();
}
int main()
{
auto app = Application::create("io.test.window-state-event");
app->signal_activate().connect(sigc::bind(&on_activate, app));
return app->run();
}
At the end of the day, I am sure the author wanted to keep this "Hello, World" example simple and concise and didn't want to add in some code that doesn't really need to be there in order to keep it simple and concise.

Take a look at the section about managed widgets in the GTKMM documentation. You should use some variation of Gtk::make_managed:
if (!window) {
window = Gtk::make_managed<HelloWindow>();
window->set_application(app);
app->add_window(*window);
}
This way, the window's lifetime will be managed by the application.

Related

gtkmm widgets - use smartpointers or pointers?

I am trying to learn how to use gtkmm having got a basic grasp of C++ (I like a challenge!). I have been working my way through the tutorials (as well as other reading). I am trying to use the approach of using glade to design the UI and then write the code to do the work.
So I have built a very simple UI (window and button at the moment!). I am using the GTK::Builder to load the UI from file. I am dividing the code into classes and a main caller.
Here is the main.cpp
#include "hellowindow.h"
#include <gtkmm/application.h>
int main(int argc, char *argv[]) {
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); //creates a Gtk::Application object, stored in a Glib::RefPtr smartpointer, create() method for this object initializes gtkmm.
HelloWindow hw; // Create a HelloWindow object
return app->run(hw, argc, argv); // shows the HelloWindow object and enter the gtkmm main processing loop, will then return with an appropriate success or error code
}
here is the header for the HelloWindow class
#ifndef HELLOWINDOW_H
#define HELLOWINDOW_H
#include <gtkmm/application.h>
#include <gtkmm/applicationwindow.h>
#include <gtkmm/button.h>
#include <gtkmm/box.h>
#include <gtkmm/builder.h>
#include <glibmm/fileutils.h>
/* derive the class from Gtk::ApplicationWindow base class */
class HelloWindow : public Gtk::ApplicationWindow {
public:
/* Conctructor */
HelloWindow();
/* Destructor */
~HelloWindow() override;
protected:
/* Signal handlers: */
void on_button_clicked();
/* Member widgets: */
Gtk::Box *cont; // Container
Gtk::Button *pButton; // Pointer to a Button
Glib::RefPtr<Gtk::Button> display_btn; // Smart pointer to a Button
Glib::RefPtr<Gtk::Builder> builder; // Builder
};
#endif // HELLOWINDOW_H
and here is the class code:
#include "hellowindow.h"
#include <iostream>
HelloWindow::HelloWindow() : builder(Gtk::Builder::create()){
try {
/* load window from glade file */
builder->add_from_file("glade/simple.glade");
}
catch(const Glib::FileError& ex) {
/* catch file errors */
std::cerr << "FileError: " << ex.what() << std::endl;
return;
}
/* ui builder created successfully from file */
/* add a container to the builder */
builder->get_widget<Gtk::Box>("cont", cont);
builder->get_widget<Gtk::Button>("display_button", pButton);
pButton->signal_clicked().connect(
sigc::mem_fun(*this, &HelloWindow::on_button_clicked)
);
/* add the container to the application window */
add(*cont);
/* set some parameters for the window */
set_title("Simple Gtk::Builder Demo"); // set the window title
set_default_size(500, 500); // set the window size
show_all(); // show the window and all of the enclosed widgets
}
HelloWindow::~HelloWindow(){
}
void HelloWindow::on_button_clicked(){
std::cout << "Hello World" << std::endl;
}
This all works fine and I think I understand what is happening. However, I have seen a different approach to adding widgets at runtime (https://sodocumentation.net/gtk3/topic/5579/using-glade-with-builder-api). The difference is how the button object is declared. In the code above it is declared as a pointer to a button object in the line:
builder->get_widget<Gtk::Button>("display_button", pButton);
However, the website above uses an approach of a smartpointer to the button object:
display_btn = Glib::RefPtr<Gtk::Button>::cast_dynamic(builder->get_object("display_button"));
The second way of doing it seems less clear, specifically the cast_dynamic aspect, would someone please explain the difference between the two approaches?
I hope that I have included enough information.
Thank you
Martyn
First of all, to understand the difference, and since you are new to
C++, I would recommend reading on the following topics:
Dynamic memory allocation (new/delete)
Memory leaks
Casting
Templates
First approach: get_widget
With this approach, you are getting a raw pointer (as opposed to a smart
pointer) to a widget defined from the ui file. Example:
Gtk::Grid* pGrid = nullptr;
refXml->get_widget("mygrid", pGrid);
After this, pGrid points to a Gtk::Grid widget. Notice that no
casting is required, you immediately get a Gtk::Grid. This is because
the Gtk::Builder::get_widget method is a template method:
// T_Widget is like a placeholder for some widget type,
// like Gtk::Grid for example.
template <class T_Widget >
void Gtk::Builder::get_widget(const Glib::ustring& name,
T_Widget*& widget
)
Usually in C++, such
raw pointers may be dangerous because if they point to an object
allocated on the heap (usually using new), one must remember to use
delete on them when done, otherwise memory leaks will occur. In this
case, pGrid is indeed a raw pointer to an object allocated on the
heap, but the documentation states:
Note that you are responsible for deleting top-level widgets (windows
and dialogs) instantiated by the Builder object. Other widgets are
instantiated as managed so they will be deleted automatically if you
add them to a container widget.
so most of the time (i.e. if not a toplevel widget), you do not have
to call delete, but sometimes you do. This is because Gtkmm has facilities
to automatically delete destroyed objects. See Gtk::manage for
more information on this.
When or not to use delete may become hard as code grows, especially since
you do not have to always do it (it can become easy to forget).
Second approach: get_object
With this approach, you are getting a smart pointer (a Glib::RefPtr) to
an object and casting to the right type is required, hence the
cast_dynamic
// get_object returns a Glib::RefPtr<Glib::Object>, which is not a Glib::RefPtr<Gtk::Button>
// so a cast is performed. This works because Gtk::Button is a child class of
// Glib::Object.
display_btn = Glib::RefPtr<Gtk::Button>::cast_dynamic(builder->get_object("display_button"));
The advantage of this is that once the cast is performed,
you do not have to manage the object's memory. It is managed by the
smart pointer (i.e. the smart pointer will automatically call delete
for you. This is true even for "top level" widgets.
Note: the cast used here, cast_dynamic, is a Gtkmm specific cast which wraps a dynamic_cast.
My opinion
I would personally go with the second approach because you get automatic
memory management (even for top level widgets), and hence no memory leaks.
However, the code gets harder to read as you already noticed.

Gtkmm - Proper way to close a window and then show another

I am building a gtkmm application. The program open with a setting window asking the user to specify some information, and when sanity checks are done, this window should be closed, and the maih window of the application should open.
Right now, opening the main window, and hiding the setting window completely close the application.
From the setting windows, I am doing:
MainWindow* main_window = new MainWindow();
main_window->show();
this->hide();
How can I get the behavior described above ?
Apparently, you can add and remove windows from a Gtk::App. Would it does what I described, and does it mean I would have to pass to my window the Gtk::App pointer ? Thanks.
What seems to be the proper solution is to pass to the window the application pointer (m_app), add the new window to it, show that window and hide the current one. Removing the current one from the application will let the run() function return:
MainWindow* main_window = new MainWindow(m_app);
m_app->add_window(*main_window);
main_window->show();
this->hide();
m_app->remove_window(*this);
delete->this;
This work, but this might not be the proper way of doing things.
Although the question is quite old, I will show my approach which may help someone else to deal with this task.
I use a general application object which holds all window objects: MainApplication.cpp
MainApplication::MainApplication(int argc, char **argv)
{
// Creating the main application object as first
mainApp = Gtk::Application::create(argc, argv, APPLICATION_ID);
// Create the entry window
createEntryWindow();
}
int MainApplication::run()
{
if (!isRunning) {
// Set the current window to entry window for startup
currentWindow = entryWindow;
return mainApp->run(*entryWindow);
} else {
return -1;
}
}
void MainApplication::createEntryWindow()
{
// Load the entry_window.glade layout with the Gtk::Builder Api
Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_file("../layout/entry_window.glade");
// Calls the constructor of my own derived widget class which details are specified inside the builder file
builder->get_widget_derived(WND_ENTRY, entryWindow);
// Set this main application object to the new window
entryWindow->setMainApplicationContext(this);
}
MainApplication.h
static const int WS_ENTRY = 100;
static const int WS_SOMETHING = 200;
class MainApplication {
public:
MainApplication(int argc, char* argv[]);
int run();
void switchCurrentWindow(int specifier);
private:
void createEntryWindow();
private:
Glib::RefPtr<Gtk::Application> mainApp;
Gtk::Window* currentWindow = nullptr;
EntryWindow* entryWindow = nullptr;
bool isRunning = false;
};
The MainApplication object will be created inside the main() and after that run() is called: main.cpp
int main(int argc, char* argv[])
{
// Create main application object
MainApplication mainApplication(argc, argv);
// Starts the event loop
// No events propagate until this has been called
return mainApplication.run();
}
The EntryWindow.cpp looks like this (just a simple example):
EntryWindow::EntryWindow(BaseObjectType* object, const Glib::RefPtr<Gtk::Builder>& refGlade)
: Gtk::Window(object), builder(refGlade)
{
// Set widgets to builder
builder->get_widget(btnName, btn);
// Set on click methods for signal_clicked
btn->signal_clicked().connect(sigc::mem_fun(*this, &EntryWindow::onBtnClicked));
}
void EntryWindow::onBtnClicked()
{
mainApplicationContext->switchCurrentWindow(WS_SOMETHING);
}
void EntryWindow::setMainApplicationContext(MainApplication* mainApplication)
{
this->mainApplicationContext = mainApplication;
}
EntryWindow.h:
class EntryWindow : public Gtk::Window {
public:
EntryWindow(BaseObjectType* object, const Glib::RefPtr<Gtk::Builder>& refGlade);
void setMainApplicationContext(MainApplication* mainApplication);
protected:
void onBtnClicked();
protected:
const Glib::RefPtr<Gtk::Builder> builder;
Gtk::Button* btn;
private:
MainApplication* mainApplicationContext = nullptr;
const Glib::ustring btnName = BTN_NAME;
};
So now when the button was clicked, you can switch the windows with following function inside the MainApplication class:
void MainApplication::switchCurrentWindow(int specifier)
{
// Check if the passed specifier exist
int tmpSpecifier = 0;
switch (specifier) {
case WS_ENTRY:
tmpSpecifier = WS_ENTRY;
break;
case WS_SOMETHING:
tmpSpecifier = WS_SOMETHING;
break;
default:
tmpSpecifier = 0;
}
// If the specifier exist
if (tmpSpecifier != 0) {
// Increase the use counter of the main application object
mainApp->hold();
// Hide the current window
currentWindow->hide();
// Remove the current window
mainApp->remove_window(*currentWindow);
} else {
return;
}
switch (tmpSpecifier) {
case WS_ENTRY:
currentWindow = entryWindow;
break;
case WS_SOMETHING:
currentWindow = somethingWindow;
break;
}
// Add the new current window
mainApp->add_window(*currentWindow);
// Show the new window
currentWindow->show();
// Decrease the use counter of the main application object
mainApp->release();
}
Summary: Create an Object which holds all windows. So whenever you need to have a new window, you have to create it inside this object. This main application object will be called by the main() and there it will call run() when the application is ready to start. After that you will handle which window is shown and hidden by the main application object only.
In response to your answer: delete->this is a pure syntax error, and even without ->, writing delete this is usually a code smell. Barring that, what you did seems like it will work, if perhaps not be as intuitive as it could be.
However, doing things in that sequence is not always possible. For example, you may not know what the next Window will be. Perhaps which window opens next depends on an HTTP response that may take a while to arrive.
The general solution is to call Application.hold() before removing the Window. Calling .hold() increments the use count of the GApplication, just as adding a window does. The app quits when its use count is zero. Saying its life is controlled by windows is just a quick way to approximate an explanation of that (and is obviously only relevant to GtkApplication, not the base GApplication). Removing a window decrements the use count.
So, in this case, you would now go from a use count of 2 to 1 - not 1 to 0 - so removing the 1st window would no longer make the app quit. Then, after you add the 2nd window, however much later that occurs, call .release() to remove the extra use count, so the remaining window(s) now exclusively control the application's lifetime again.

Open multiple different windows in Gtkmm

I've only just started learning how to use gtkmm, and I'm trying to create an application which can have more than one window open at the same time (think, main window and a control panel).
I decided to create the layout in Glade, if that's of any relevance to this question.
My method of displaying two bottles is more or less this:
Gtk::Window* main_window = nullptr;
Gtk::Window* servsettings = nullptr;
int main(int argc, char* argv[]) {
auto app = ...
auto builder = ... // these are exluded for brevity
builder->add_from_file("../src/design.glade");
builder->get_widget("main", main_window);
builder->get_widget("servsettings", servsettings);
app->run(*servsettings);
app->run(*main_window);
}
Instead of opening two windows, this instead opens servsettings, then segfaults when I close that.
Now forgetting about the segfault (I'm utterly confused about that,) I think I can see why it only opens servsettings - I assume this is because I'm running the app, and then that call only exits when the window dies?
The problem is, I can't think of any other way to do it. I experimented with multithreading but decided that it would be better to ask here first.
Before anyone suggests it, this answer does not help me. This is because they had a scope-based issue. I don't.
Use Gtk::Application::add_window(Gtk::Window&).
If all the windows managed by Gtk::Application are closed (hidden) or removed from the application then the call to run() will return.
#include <gtkmm.h>
Gtk::Window* window1, *window2;
int main()
{
auto app = Gtk::Application::create();
Gtk::Button button1("Quit"), button2("Quit");
window1 = new Gtk::Window();
window2 = new Gtk::Window();
button1.signal_clicked().connect(sigc::mem_fun(window1, &Gtk::Window::close));
button2.signal_clicked().connect(sigc::mem_fun(window2, &Gtk::Window::close));
window1->set_default_size(200, 200);
window1->add(button1);
window1->show_all();
window2->set_default_size(200, 200);
window2->add(button2);
window2->show_all();
app->signal_startup().connect([&]{
app->add_window(*window2);
});
return app->run(*window1);
}
I found the answer. For those wondering, I replaced the two app->runs with:
servsettings->show();
main_window->show();
app->run(*main_window);

Launching Multiple QApplication within a DLL

I have used this link to get me started, [https://stackoverflow.com/a/11056698/5609063][1]
I am trying to create an object which creates its GUI internally, and cleans itself up.
I have a call to quit() as well within lets me close the gui out if I want to force a close or I can just sit on .exec call until the main window is closed.
FooObj.h
class FooObj
{
public:
FooObj(FooObj *obj);
~FooObj();
private:
GUIApp *guiApp;
FooObj *m_fooObj;
}
FooObj.c
FooObj::FooObj()
{
guiApp = new GUIApp(this);
}
FooObj::~FooObj()
{
delete guiApp;
}
GUIApp.h
class GUIApp
{
public:
GUIApp(FooObj *obj);
~GUIApp();
private:
std::thread m_appThread;
void m_RunApp();
}
GUIApp.c
GUIApp::GUIApp(obj)
{
m_fooObj = obj;
m_appThread = std::thread ([this] {m_RunApp();});
}
GUIApp::~GUIApp()
{
if(m_appThread.joinable())
m_appThread.join();
}
void GUIApp::m_RunApp()
{
int argc = 1;
auto a = new QApplication(argc, NULL);
auto win = new FooObjGUI(m_fooObj);
win->show();
a->exec();
return;
}
In GUIApp, there is a call to FooObjGUI which uses FooObj to a gui setup to handle all the data I want to display and what actions I expose to the user.
My intention is to have the user of this code not have to worry about qt and to have it clean itself up.
This code works fine in a dll or exe when I create a single FooObj. I cannot create a second FooObj because I cannot create a second QApplication. I have tried several ideas starting the a->exec() in a separate thread, but the events are not handled and the gui sits idle.
Is there a way to call QApplication across multiple threads within a single dll? Is there a workaround to have both FooObj use the same QApplication and not block the execution of the dll? The only workaround I have for myself at the moment is use 2 copies of the dll, but that is not a good longterm solution.

gtkmm and Gtk::Builder: Lifetime of objects after calling get_widget

I think I must be "doing something wrong" here. I have a program using gtkmm. The main window for the program is a subclass of Gtk::Window and I have the bare bones of the application drawn out in Glade.
Here's an edited version of the main window's constructor:
template<class T>
static T*
get_widget (Glib::RefPtr<Gtk::Builder> builder, const Glib::ustring& name)
{
T* widget;
builder->get_widget (name, widget);
if (! widget) no_such_widget (name);
return widget;
}
app_window::app_window ()
{
Glib::RefPtr<Gtk::Builder> builder;
try {
builder = Gtk::Builder::create_from_file (installed_ui_name);
}
catch (const Glib::FileError& err) {
g_error ("Couldn't open UI definition file at %s",
installed_ui_name);
throw;
}
// main_box is a std::unique_ptr<Gtk::Widget>, a field of app_window.
//
// This works fine: the Gtk::Box gets added as the main child of this
// app_window and survives until the app_window is destroyed.
main_box.reset (get_widget <Gtk::Box> (builder, "main-box"));
add (* main_box);
auto accel_group = get_accel_group ();
// This doesn't work so well
//
// menu_quit is a Gtk::MenuItem*. The object seems to be actually
// constructed for the call to builder->get_widget, because its existence
// stops the menu item from being finalized at the end of the application.
auto menu_quit (get_widget<Gtk::MenuItem> (builder, "menu-quit"));
menu_quit->add_accelerator ("activate", accel_group,
GDK_KEY_q, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
using std::bind;
menu_quit->signal_activate ().connect (bind (& app_window::on_close, this));
show ();
}
When setting up the window, I want to register various signal handlers for menu items etc. (the menu_quit widget in the example is just one of them). To do so, I think I need to use builder->get_widget() to get hold of an object to talk about.
The problem is that I've now got an instance of (a subclass of) Gtk::Widget and I don't know what to do with it. If I call delete on the pointer, the widget doesn't appear in the application, but no other problems happen. That's a bit confusing: I would expect either no effect or a segmentation fault (depending on whether something else thought it owned the object or not).
If, on the other hand, I leak the pointer, assuming that object will be owned by the container into which main_box has been added, I get a memory leak. In particular, menu_quit's underlying gtk_image_menu_item doesn't get finalised because the reference count is one too high. (I can check easily enough that with GDB)
A "solution" is to store a pointer to each object that I get with builder->get_widget as a field in the app_window and then delete it in the destructor (automated with std::auto_ptr or std::unique_ptr). But that's really horrible: I don't want to have to write out a field for every single menu item! Avoiding that sort of nonsense was the whole point of using GtkBuilder in the first place!
Assuming that this isn't a bug (gtkmm 3.12.0, if that's relevant), I assume I'm just doing it wrong. How is an application supposed to do this?