Run SDL Window (Centurion GUI lib) in other thread? - c++

I want to run a window in another thread (ie not the main thread) using Centurion (which uses SDL).
Here is how i run the thread:
auto _THR_WIN_HWND_MAINLOOP = ([&HWND_instance]() {
HWND_instance._mainloop_();
});
// starts the window thread.
std::thread _thr(_THR_WIN_HWND_MAINLOOP);
_thr.detach();
Then my _mainloop_() function:
const cen::sdl sdl;
// main loop here.
cen::window hwnd;
cen::renderer renderer = hwnd.make_renderer();
hwnd.show();
cen::event_handler handler;
while (__flag_open) {
while (handler.poll()) {
if (handler.is<cen::quit_event>()) {
__flag_open = false;
break;
}
}
renderer.clear_with(cen::colors::white);
renderer.fill_rect(cen::frect{ 25.0, 500.0, 125.0, 75.0 });
renderer.present();
}
Just a note, the cen::window constructor calls SDL_Init().
The problem is is that on the off chance i run my program, it closes after a second or so. if i JOIN the thread instead of detaching it the window stays open. However i need the window to run in the background as i have other code that must be run. Is there any way to have a background thread that fully handles the SDL window as if it was its own program?
NOTE: No errors are thrown, the window just closes after a second or so, on the off chance?!

It turns out i was not labeling my HWND_instance class variable as static, and that variable held almost everything to do with SDL. So when it got destroyed, so did the SDL instances:
before:
_CE_WINDOW_HWND HWND_instance(s.get()); // create the instance.
auto _THR_WIN_HWND_MAINLOOP = ([&]() {
HWND_instance._mainloop_();
});
// starts the window thread.
std::thread _thr(_THR_WIN_HWND_MAINLOOP);
_thr.detach();
After:
static _CE_WINDOW_HWND HWND_instance(s.get()); // create the instance.
auto _THR_WIN_HWND_MAINLOOP = ([&]() {
HWND_instance._mainloop_();
});
// starts the window thread.
std::thread _thr(_THR_WIN_HWND_MAINLOOP);
_thr.detach();
As you can see, now the variable does not get destroyed after the function ends, preserving the lifetime of SDL and the class.

Related

QT: Run a function as long as button is toggled

I want to implement a GUI that receives messages from an external device. The "advancedReceiveExample" is waiting for messages. Once it has received one, it does stuff with it, saves it and terminates.
I want to make my function wait for new messages after receiving one as long as the button is toggled.
I have tried this so far:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
This works perfectly fine but as mentioned above it only receives one message. If I do that:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
while (1)
{
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
it blocks the function because the state of the button can only be change after the function "on_pushButton_clicked()" has terminated.
Visual Studio 2019
C/C++
EDIT: Okay, I have understood the problem of blocking the thread. Multithreading might be the right option but I am very unexperienced regarding this topic. The <QThread> could be possible. How would you use it?
Do you have suggestions which other library could be used?
Note QT is event-based. If you keep your computer busy inside some function without returning to the main loop frequently, your GUI will freeze.
What you need to do is slice your action that you want to do into small bits that can repeatedly return to the main loop in order to keep the GUI responsive. (Another method yould be to swap out your action into a separate thread and handle it in parallel, killing the thread when the button is released)
Probably the simplest method to do what you want is with timers that you arm in the PushButton::clicked slot, and then check in the timer event whether the button is still pressed, and, if yes, do a bit of your action, save state and re-arm the timer to have you return.
Something along the lines of the following pseudo code should work and execute what you want to do in slices every 10ms:
MainWindow::onPushButtonClicked () {
// do the action, or, alternatively, start a
// parallel thread that does it
do_a_bit_of_action();
// sets up a timer to call onTimer after 10ms
QTimer::singleShot (10, this, SLOT(onTimer()));
}
MainWindow::onTimer () {
// check if button is still held down
if (pushButton.down) {
// re-arm timer
Timer::singleShot (10, this, SLOT(onTimer()));
// do some more action bits
do_a_bit_of_action();
}
else {
// kill optional background thread here
}
}
You can try it with:
while(ui.pushButton->isChecked()){
*your function*
}

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;
}
}

Sharing opengl resources (OpenGL ES 2.0 Multithreading)

I have developed an OpenGL ES 2.0 win32 application, that works fine in a single thread. But I also understand that UI thread and a rendering thread should be separate.
Currently my game loop looks something like that:
done = 0;
while(!done)
{
msg = GetMessage(..); // getting messages from OS
if(msg == QUIT) // the window has been closed
{
done = 1;
}
DispatchMessage(msg,..); //Calling KeyDown, KeyUp events to handle user input;
DrawCall(...); //Render a frame
Update(..); // Update
}
Please view it as a pseudo code, cause i don't want to bother you with details at this point.
So my next step was to turn done into an std::atomic_int and create a function
RenderThreadMain()
{
while(!done.load())
{
Draw(...);
}
}
and create a std::unique_ptr<std::thread> m_renderThread variable. As you can guess nothing has worked for me so far, so i made my code as stupid and simple as possible in order to make sure i don't break anything with the order i call methods in. So right now my game loop works like this.
done.store(0);
bool created = false;
while(!done)
{
msg = GetMessage(..); // getting messages from OS
if(msg == QUIT) // the window has been closed
{
done.store(1);
}
DispatchMessage(msg,..); //Calling KeyDown, KeyUp events to handle user input;
// to make sure, that my problem is not related to the fact, that i'm rendering too early.
if(!created)
{
m_renderThread = std::make_unique<std::thread>(RenderThreadMain, ...);
created = true;
}
Update(..); // Update
}
But this doesn't work. On every draw call, when i try to somehow access or use my buffers \ textures anything else, i get the GL_INVALID_OPERATION error code.
So my guess would be, that the problem is in me calling glGenBuffers(mk_bufferNumber, m_bufferIds); in the main thread during initialization and then calling glBindBuffer(GL_ARRAY_BUFFER, m_bufferIds[0]); in a render thread during the draw call. (the same applies to every openGL object i have)
But I don't now if i'm right or wrong.

gtk_widget_add_tick_callback() and gtk_main_iteration()

I have two GTK windows
Normal (main) window that runs animation, draws stuff in callback registered by gtk_widget_add_tick_callback().
At some point secondary window is created that runs modal loop:
void show_modal()
{
GtkWindow* gw = gtkwindow(this);
if( parent() )
gtk_window_set_transient_for(gw, gtkwindow( parent() ));
gtk_widget_show(GTK_WIDGET(gw));
gtk_window_set_modal(gw,TRUE);
gtk_window_set_keep_above(gw,TRUE);
this->update_window_state(gool::WINDOW_SHOWN);
while( this->is_valid_window() )
{
if(this->_window_state == WINDOW_HIDDEN) break;
if(this->_window_state == WINDOW_STATE_NA) break;
gtk_main_iteration(); // gtk_main_iteration_do(true);
}
}
Problem: Animation in main window works fine until show_modal() is invoked. It appears as gtk_main_iteration(); blocks ticks added by gtk_widget_add_tick_callback() function. As soon as I close secondary window and so while() {gtk_main_iteration();} loop exits then animations in main window start running again.
Any idea of how to make "animation friendly" modal loops in GTK?
UPDATE: it appears as gtk_main_iteration(); blocks not only ticks but any updates of any windows other than "current" - they are simply frozen. What is the reasoning of such GTK behavior?
UPDATE #2:
gtk_dialog_run(); behaves exactly as gtk_main_iteration(); - locks any updates on any window in process other than active window.
It seems to be by definition: link
gboolean gtk_main_iteration (void);
Runs a single iteration of the mainloop. If no events are waiting to be processed GTK+ will block until the next event is noticed. If you don’t want to block look at gtk_main_iteration_do() or check if any events are pending with gtk_events_pending() first.
The explanation suggests to use gtk_main_iteration_do(FALSE) if you don't want blocking:
gboolean gtk_main_iteration_do (gboolean blocking);
Runs a single iteration of the mainloop. If no events are available either return or block depending on the value of blocking:
TRUE if you want GTK+ to block if no events are pending
As for gtk_dialog_run: it also blocks by design link
gint gtk_dialog_run (GtkDialog *dialog);
Blocks in a recursive main loop until the dialog either emits the “response” signal, or is destroyed.[...]
I read about people solving this using multiple threads: handle the GUI in the main thread and do background work in another one. There's an article about it here that might be useful.
I assume that show_modal is called from a callback or other activity in main context. You could try adding your modal window into main context using invoke or signal_idle.
This way execution of show_modal will end.
#include <gtkmm.h>
#include <string>
int main()
{
auto Application = Gtk::Application::create();
Gtk::Window window;
Gtk::Window* window2;
Gtk::Button button;
window.add(button);
//I hope timeout behaves similar to ticks. I have no idea how animations in GTK work
int i=0;
Glib::MainContext::get_default()->signal_timeout().connect([&]()->bool{
button.set_label(std::to_string(i++));
return true;
}, 1000);
button.signal_clicked().connect([&]{
Glib::MainContext::get_default()->invoke([&]()->bool{
window2 = new Gtk::Window;
window2->set_modal(true);
window2->set_keep_above(true);
window2->signal_delete_event().connect([&](GdkEventAny* any_event)->bool{
delete window2;
return false;
});
window2->show_all();
return false;
});
});
window.show_all();
return Application->run(window);
}

How to prevent a long process to hangs wxwidgets window

I have a wxwindows application and in the onclick event of a button, I have a very long process, for example I have something such as this:
for(int i=1;i<100;i++)
{
sleep(1000);
gaugeProgress->SetValue(i);
*textOutput<<i;
}
Running this code, stops UI to be responsive. I add
Refresh();
Update();
just after
*textOutput<<i;
but it did not work.
is there any way that I can pump the events?
I am working on Windows using VS 20102
In those cases I use wxYield() like this:
for(int i = 1; i < 100; i++)
{
// sleep() freezes the program making it unresponsible.
// sleep(1000);
gaugeProgress->SetValue(i);
*textOutput << i;
// wxYield stops this function execution
// to process all the rest of stocked events
// including the paint event and resumes immediately.
wxYield();
}
This stops the current process and lets the application to process the message stack like the paint event.
But I think that the proper way to do this should be using threads.
You can add a wxTimer member in your wxwindows, start it in the window constructor, as such:
m_timer.Start(1000);
then capture the timer event with a function, for example:
void mywindow::OnTimer(wxTimerEvent& event)
{
Refresh();
Update();
}
Make sure you connect the event to the wxTimer member.