Creating a standalone gtkmm dialog - c++

In a particular situation I need my command line based C++ application to launch a quick dialog using gtkmm 2.4. I could really use some direction here.
I tried launching the dialog as a standalone without initializing the top level window:
Gtk::Main kit( NULL,NULL );
Gtk::Window toplevel;
MyApp::myDialog d(toplevel);
int result = d.run();
This created my dialog but it doesn't close when the ok or cancel button is hit and none of quit/delete/hide api calls I could find could get rid of it. It only goes away when the program exits (even if it is created in a method which exits earlier). I'm guessing this is in part because it needs an active main window to handle some of its lifetime/visibility management. If I could make it respond normally to the ok/cancel buttons I would be all set!
Next I tried creating and launching the main window properly and launching the dialog from within the constructor of the main window. (It takes the Gtk::Main as an argument so I could try killing that directly.)
class cprompt : public Gtk::Window
{
public:
cprompt(Gtk::Main* prompt){
MyApp::myDialog* d = new MyApp::myDialog (*this);
std::cout << "ABOUT TO RUN DIALOG" << std::endl;
int result = d->run();
std::cout << "RAN DIALOG" << std::endl;
d->hide();
delete d;
std::cout << "CALLING QUIT" << std::endl;
this->hide();
Gtk::Main::quit();
prompt->quit();
//None of the above calls do anything. The empty 'top level' window hangs around and blocks until manually closed.
std::cout << "CALLED QUIT" << std::endl;
};
virtual ~cprompt(){};
};
Now the dialog works as expected, but the main window pops up after the dialog is closed (an empty gray square with an exit button) and I can't find a way to hide or exit it outside of clicking the exit button. All the calls I make to close it or quit the gtk loop automatically are inside the constructor so I'm guessing they aren't valid at that point. If I could make the whole operation shut down after the dialog returns in the window constructor, again I would be all set.
My next approach is going to be to use the top level window itself as the dialog, but I was hoping to avoid this because the dialog I need is already provided by another library and I'll have to re-implement the ui from scratch if I can't launch the dialog straight up.

Had the same problem with Gtk. To fix it, I neeeded to manually close the window and then do the gtk loop iterations. My code looks like this (for a filechooser_dialog) :
gint result = gtk_dialog_run(GTK_DIALOG(m_fileDialog));
if(result == GTK_RESPONSE_ACCEPT)
{
char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(m_fileDialog));
m_selectedFileName = std::string(filename);
g_free(filename);
}
gtk_window_close(GTK_WINDOW(m_fileDialog)); //Close the dialog manually
while (gtk_events_pending()) //until there are no more events :
gtk_main_iteration_do(false); //process the main iteration

Related

Starting/stopping function using QT GUI buttons

I am writing a simple Qt C++ GUI window for the user to input certain values for a USRP device to record (i.e. input start frequency, stop frequency, etc..). Once the user inputted the values, the "EXECUTE" button is clicked and the execute_run_usrp() function is called in its own thread (so not to block the GUI). Then the STOP button should be able to be clicked at any time to terminate the thread running the function that runs the USRP, execute_run_usrp(), thus terminating the USRP recording process.
The function run_usrp(x,y,z,etc) is defined in another *.cpp file in the Project.
The problem that I am having that the STOP button when clicked only seems to "pause" the function...doesn't actually kill it (like with CTRL-C, which works great here)
Here is my code from MainWindow.cpp for the EXECUTE button click:
// run the following when EXECUTE button is clicked
void MainWindow::on_button_EXECUTE_clicked()
{
if ( ui->calculated_StartTime->text() == "" )
{
QMessageBox messageBox;
messageBox.critical(0,"Error","Hit the \"CALCULATE SCHEDULE\" button first above!!");
messageBox.setFixedSize(500,200);
return;
}
ui->button_STOP->setVisible(true);
ui->button_EXECUTE->setVisible(false);
auto function = std::bind([this]{execute_run_usrp();});
QThread* temp = QThread::create(function);
temp->start();
connect( ui->button_STOP, SIGNAL(clicked()), temp, SLOT( terminate() ));
}
Here is the execute_run_usrp() function:
void MainWindow::execute_run_usrp()
{
float startFreq = ui->input_startFreq->text().toFloat();
float stopFreq = ui->input_stopFreq->text().toFloat();
float stepFreq = ui->input_stepFreq->text().toFloat();
int nRepeats = ui->input_numRepeats->text().toInt();
float ipp = ui->input_IPP->text().toFloat();
int sweepCadence = ui->calculated_sweepCadence->text().toInt();
int numSweeps = ui->input_numSweeps->text().toInt();
std::string schedule_run = ui->calculated_StartTime->text().toStdString();
std::cout << startFreq << std::endl;
std::cout << stopFreq << std::endl;
std::cout << stepFreq<< std::endl;
std::cout << nRepeats << std::endl;
std::cout << ipp << std::endl;
std::cout << sweepCadence << std::endl;
std::cout << numSweeps << std::endl;
run_usrp(startFreq, stopFreq, stepFreq, nRepeats, ipp, sweepCadence, numSweeps, schedule_run);
}
And here is the STOP button code:
void MainWindow::on_button_STOP_clicked()
{
ui->button_STOP->setVisible(false);
ui->button_EXECUTE->setVisible(true);
}
Clicking the STOP button only seems to pause the function, doesn't actually kill it like doing CTRL-C with the keyboard. I think the UHD library (that runs the USRPs) spwans its own thread for running.
Question: How do I 100% terminate the entire function (and including any spwaned children from UHD) when I hit the STOP button ?
Thank you very much!
How do I 100% terminate the entire function (and including any spwaned children from UHD) when I hit the STOP button ?
From the code you've shown there's no easy answer imho.
The shortest one is: by incorporating some inter-thread communication inside the USRP function, provided you want some sort of graceful exit.
As for terminate, QT's docs state:
This function is dangerous and its use is discouraged. The thread can be terminated at any point in its code path. Threads can be terminated while modifying data. There is no chance for the thread to clean up after itself, unlock any held mutexes, etc. In short, use this function only if absolutely necessary.
Alternatively, the whole USRP function can be run inside a separate process, that is then killed. Again, plain killing of the process is far from graceful, still it seems easier and safer than doing it to a thread. You may want to check QProcess for reference.

Why does SDL doesn't emit SDL_QUIT when last windows closed

I'm writing a Game Engine just for practice but I still stuck with the first chellange. The Window Manager.
https://github.com/thebenius/SDL
I've created a GitHub Repo to show you the code but don't worry. Its not much. But I absolutely don't know where is my mistake.
In the Code I create three Windows and I Manage the input for SDL_QUIT to stop the game loop and for SDL_WINDOWEVENT_CLOSE to close the windows.
Everything works fine until the last window is closed. As far as I know, now the SDL_QUIT Event must be emitted by SDL. But the Gameloop goes on.
I think I maybe have a kind of memory leak and there is still a windows saved. But I checked the window stack (Window::windows hashmap) it is empty. And also the variables in main are cleared.
I also tried to additionally clear the window and renderer variable in the hash map
Window::~Window() {
// Delete Window and Renderer
SDL_DestroyRenderer(Window::windows[this->windowID]->renderer);
SDL_DestroyWindow(Window::windows[this->windowID]->window);
Window::windows[this->windowID]->renderer = nullptr;
Window::windows[this->windowID]->window = nullptr;
// Delete Window from map
Window::windows.erase(this->windowID);
// Delete Window and Renderer
SDL_DestroyRenderer(this->renderer);
SDL_DestroyWindow(this->window);
// Reset Pointer
this->renderer = nullptr;
this->window = nullptr;
Nothing worked.
I'm new in C++ and SDL. I hope you can help me out.
Thank you o11c,
Your answer was the riddles solution.
I just put SDL_Quit() out of the Destructor. This obviously blocked the Event Handler to catch SDL_QUIT. So I put it to the constructor in atexit()
After that (don't know why before not) I got an Segfault when deleting the window pointer in main. I deleted that and just set them all to nullptr.
Now the WindowManager works properly. Thank you for your help
I think SDL_QUIT is only an hook called if you call SDL_Quit(), to give the user the opportunity to do some quit stuff, the manual:
You should call this function even if you have already shutdown each initialized subsystem with SDL_QuitSubSystem(). It is safe to call this function even in the case of errors in initialization
You can use this function with atexit() to ensure that it is run when your application is shutdown, but it is not wise to do this from a library or other dynamically loaded code
To catch a window close event see SDL_WindowEvent, SDL_WINDOWEVENT and SDL_WINDOWEVENT_CLOSE, the id of the closing window is given as argument.
* \file SDL_quit.h
*
* An ::SDL_QUIT event is generated when the user tries to close the application
* window. If it is ignored or filtered out, the window will remain open.
* If it is not ignored or filtered, it is queued normally and the window
* is allowed to close. When the window is closed, screen updates will
* complete, but have no effect.
*
* SDL_Init() installs signal handlers for SIGINT (keyboard interrupt)
* and SIGTERM (system termination request), if handlers do not already
* exist, that generate ::SDL_QUIT events as well. There is no way
* to determine the cause of an ::SDL_QUIT event, but setting a signal
* handler in your application will override the default generation of
* quit events for that signal.
*
* \sa SDL_Quit()
SDL_EventType#SDL_QUIT
An SDL_QUIT event is generated when the user clicks on the close button of the last existing window.
You shouldn't call SDL_Quit() in the destructor, but only once before leaving the application (is suggested to use it with atexit())
--- a/main.cpp
+++ b/main.cpp
## -32,17 +32,18 ## int main() {
}
-
// Delete Windows
- delete window;
- delete window2;
- delete window3;
+ // delete window;
+ // delete window2;
+ // delete window3;
// reset pointer
window = nullptr;
window2 = nullptr;
window3 = nullptr;
+ SDL_Quit();
+
// Close Program properly
return 0;
}
--- a/video/window.cpp
+++ b/video/window.cpp
## -51,7 +51,7 ## Window::~Window() {
// Shutdown if last window closed
if(this->windows.empty()) {
// Shutdown Video System
- SDL_Quit();
+ // SDL_Quit();
std::cout << "shuted down Video" << std::endl;
}
}

X11: XQueryPointer gives me fuzzy Windows

I am currently trying to find if one of my Windows is underneath the Mouse cursor. This is not done in my process that creates the window, but in another process.
What I am currently doing is finding the Window via the process PID (and I made sure _NET_WM_PID is set correctly by my program). This basically works via XQueryTree and XGetWindowProperty. This works fine and is not the problem.
The problem is that XQueryPointer gives me fuzzy Windows back. I wrote a simple test program to show what I mean. First gather an ID from any Window you like using the command xprop via bash. It will give you the Window ID.
Then run this simple test program I wrote (quick and dirty), it gives you every 0,5s the current ID from the Window underneath the mouse cursor:
#include <X11/Xlib.h>
#include <iostream>
#include <unistd.h>
#include <stdint.h>
int main()
{
Display *display = XOpenDisplay(0);
Window root = XDefaultRootWindow(display);
Window root_return;
Window child_return;
int root_x_return;
int root_y_return;
int win_x_return;
int win_y_return;
uint32_t mask_return;
while (true)
{
if (::XQueryPointer(display, root, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return) == True)
{
std::cout << "Window ID: " << child_return << std::endl;
}
usleep(500000);
}
return 0;
}
Can somebody tell me what the problem is?
And here is my example output:
My program finds Window ID 73400324
xprop finds Window ID 73400324
The test program finds Window ID 20996726
Could be child windows, or the decoration that the window manager adds to a plain window.
By the way, the normal way to detect if your window is under the mouse is by catching the XEnterWindowEvent and XLeaveWindowEvent, but this is normally done within the program itself, not externally.

Qt MainWindow crashes upon button click

I've used Qt's MainWindow class before, and I have never had any problems.
Right now, I have a button called addLocation that is supposed to create a QInputDialog and get a string from the user, and add it to a QStringList called locationList, which is a public field of my uiactions.h file, declared like this within the header:
class UiActions{
public:
QStringList locationList;
//function prototypes
};
I have a function in my mainwindow.cpp file to handle the event of my addLocation button being clicked, defined as such:
void MainWindow::on_addLocation_clicked()
{
UiActions actions;
actions.addLocation();
}
And my addLocation function is defined as follows in my uiactions.cpp file:
void UiActions::addLocation()
{
bool j; //Input Dialog Handler
QDebug debugTxt(QtDebugMsg);
locationList << QInputDialog::getText(NULL, "Add Location",
"Location Name:", QLineEdit::Normal,
NULL, &j);
}
Whenever I click the addLocation button, the program shows an input dialog, lets me type something, and then hangs for a few seconds and crashes after clicking "ok."
I added some lines under the input dialog to see if the problem was in the QInputDialog, like this:
if(j){
debugTxt << "Input dialog success";
}
else{
debugTxt << "Input failed.";
}
And it would print out "Input dialog success" to the debug console, telling me the problem is not in my use of the QInputDialog.
When it crashes, this is all the error information I get:
The program has unexpectedly finished.
[insert path to EXE here] crashed
I believe this is all of the relevant information. What would be causing the program to crash?
EDIT: I ran with the debugger (should have done this first) and I'm getting a segmentation fault. I wonder what would be causing this, as I'm not doing any pointer trickery. I have a suspicion that it has something to do with the way I'm using QStringList locationList
The highlighted assembly is 0x64942cb6 <+0x0000> cmpl $0xbab1f00d,(%edx)
EDIT 2: I made a modification to the click event for my addLocation button, which is in my mainwindow.cpp file.
void MainWindow::on_addLocation_clicked()
{
UiActions actions;
//actions.addLocation();
actions.locationList << "Test Location" << "Other Data";
}
I get the same error when I try to add something to a QStringList field in the uiactions.h file as well. I'm almost positive I'm trying to access the data in there incorrectly now. Here's the interesting thing though. I have another button which I use to save the data in locationList to a text file, defined like this in my uiactions.cpp file:
bool UiActions::saveLocationList()
{
ofstream file;
file.open ("Location List.txt");
for(int i = 0;i < locationList.size(); i++){
file << locationList[i].toUtf8().data() << "\n";
}
file.close();
return true;
}
which works fine.
EDIT 3: I added a debug line: debugTxt << "\n" << locationList[0]; to the addLocation click event to see if the data was actually getting put into locationList, and it is. I'm completely confused now, since it seems I actually am accessing locationList correctly.

FLTK Closing window

I am using FLTK. I have a window with a variety of buttons the user can click to perform some action. In my int main() i have a switch statement to handle all of these. When the user clicks exit the switch statement is setup like so:
case Exit_program:
cout << "save files and exit\n";
do_save_exit(sw);
This goes to the do_save_exit function that creates a exit confirmation window with two buttons yes (exit) and no (don't exit). I got the yes button to work, exits the program, but the no button mean i should just hide the confirmation window. This is the follow functions:
void yes(Address addr, Address)
{
exit(0);
}
void no(Address addr, Address)
{
}
void do_save_exit(Window& w)
{
Window quit(Point(w.x()+100, w.y()+100), 250, 55, "Exit confirmation");
Text conf(Point(15,15),"Do you really want to save and exit?");
Button yes(Point(60, 20),35,30,"Yes",yes);
Button no(Point(140, 20),35,30,"No",no);
quit.attach(conf);
quit.attach(yes);
quit.attach(no);
wait_for_main_window_click();
}
The problem is, when i click the no button it goes to void no, but I can't go anywhere from there. I just want to do quit.hide() but the no function doesn't have sight of the quit window (out of scope). How should I proceed? Thank you
P.S: I have thought about using a pointer to the quit window and then using the pointer to quit the window in the no function but am not sure how to do that exactly.
The Fl_Window callback is called when an attempt is made to close the window. The default callback hides the window (and if all windows are hidden, your application ends). If you set your own window callback, you can override this behaviour, so as not to hide the window:
// This window callback allows the user to save & exit, don't save, or cancel.
static void window_cb (Fl_Widget *widget, void *)
{
Fl_Window *window = (Fl_Window *)widget;
// fl_choice presents a modal dialog window with up to three choices.
int result = fl_choice("Do you want to save before quitting?",
"Don't Save", // 0
"Save", // 1
"Cancel" // 2
);
if (result == 0) { // Close without saving
window->hide();
} else if (result == 1) { // Save and close
save();
window->hide();
} else if (result == 2) { // Cancel / don't close
// don't do anything
}
}
Set your window's callback wherever you set up your Fl_Window, e.g. in your main function:
window->callback( win_cb );
You probably need to look at using a modal (i.e., dialog) window. Look at <FL/fl_ask.h>
if (fl_ask("Do you really want to save and exit?"))
save_and_exit();
The header also has functions for the popup's font, title, etc.
When you build you don't get an error or warning? The problem is probably that you have both global functions names yes and no and also local variables called just the same. Rename either the functions of the variables.
No need to use hide().
You can simply use exit(0); in a callback.