SDL: Window freezes - c++

I wanted to start working on SDL. I got a sample code to see if it worked fine. When compiling I get no errors, but when I run it the window shows up but the program freezes until the delay time is over.
I'm new to this so I would really appreciate some help.
int main(int argc, char* argv[]) {
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = 0;
window = SDL_CreateWindow("Hello World!",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
640, 480,
SDL_WINDOW_SHOWN);
SDL_Delay(10000);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

As mentioned by #HolyBlackCat, you need an event loop :
https://wiki.libsdl.org/SDL_PollEvent
It should look something like this :
while (true) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
/* handle your event here */
}
/* do some other stuff here -- draw your app, etc. */
}
Edit
You will need to replace your delay with the event loop.
Instead, you can close the application on an event. The least you can/should do, is handle the SDL_QUIT event, which is sent when the user try to close the window:
while (!quit) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
/* handle your event here */
//User requests quit
if( event.type == SDL_QUIT )
quit = true;
}
/* do some other stuff here -- draw your app, etc. */
}

Related

GUI app on MacOSX not showing window? SDL/C++ [duplicate]

This is my code:
#include <iostream>
#include <SDL2/SDL.h>
int main(int argc, const char * argv[]) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *_window;
_window = SDL_CreateWindow("Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 700, 500, SDL_WINDOW_RESIZABLE);
SDL_Delay(20000);
SDL_DestroyWindow(_window);
SDL_Quit();
return 0;
}
Im working in Xcode. I've downloaded SDL2 and imported the library to the projects build phases. I've tested that the SDL2 works correctly.
The problem is that window never shows up. I just get a "spinning-mac-wheel" and then the program quits after the delay. I've made sure that the window is not hidden behind somewhere.
Ideas?
You have to give the system a chance to have it's event loop run.
easiest is to poll for events yourself:
SDL_Event e;
bool quit = false;
while (!quit){
while (SDL_PollEvent(&e)){
if (e.type == SDL_QUIT){
quit = true;
}
if (e.type == SDL_KEYDOWN){
quit = true;
}
if (e.type == SDL_MOUSEBUTTONDOWN){
quit = true;
}
}
}
instead of the wait loop
--- Addendum
Since this answer is still helping people maybe it's nice if I also add a bit more info on why this works instead of just posting the solution.
When on the Mac (same for Windows actually) a program starts, it starts with just the 'main thread'. This is the thread which is used to set up UI stuff. The 'main thead' differs from other threads in that it comes with an event handling system. This system catches events like mouse moves, key presses, button clicks and then queues these and lets your code respond to it. All the UI things on Mac (and Windows) rely on this event pump being there and running. This is the reason why if you do anything UI related in your code you need to make sure you are not on a different thread.
Now, in your code you initialise the window and the UI, but then you do a SDL_Delay. This just blocks the thread and halts it for 20 seconds so nothing is done. And since you do that on the main thread, even the handling of the queue with the events is blocked. So on the Mac that shows as the spinning macwheel.
So the solution I posted actually keeps on polling for events and handles them. This way you are effectively also 'idling', but the moment events are posted (like mouse clicks and keys) the thread will wake up again and stuff will be processed.
You have to load a bitmap image, or display something on the window, for Xcode to start displaying the window.
#include <SDL2/SDL.h>
#include <iostream>
using namespace std;
int main() {
SDL_Window * window = nullptr;
SDL_Surface * window_surface = nullptr;
SDL_Surface * image_surface = nullptr;
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
window_surface = SDL_GetWindowSurface(window);
image_surface = SDL_LoadBMP("image.bmp");
SDL_BlitSurface(image_surface, NULL, window_surface, NULL);
SDL_UpdateWindowSurface(window);
SDL_Delay(5000);
SDL_DestroyWindow(window);
SDL_FreeSurface(image_surface);
SDL_Quit();
}
You need to initialize SDL with SDL_Init(SDL_INIT_VIDEO) before creating the window.
Please remove the sdl_delay() and replace it with the below mentioned code. I don't have any reason for it but I tried on my own and it works
bool isquit = false;
SDL_Event event;
while (!isquit) {
if (SDL_PollEvent( & event)) {
if (event.type == SDL_QUIT) {
isquit = true;
}
}
}

Program still running after return 0; with SDL_Renderer

I'm doing Lazy Foo's tutorial on SDL (I'm using SDL2-2.0.9), and at the texture rendering part I encountered the following problem: the program compiles and runs as expected, no issue here, but when I close the window, the console doesn't close and the process continues running, so I have to close the console separately.
When I tried to debug it, I found out that the program indeed leaves the main cycle and reaches the "return 0" line in the main function successfully, but then it just hangs like that until I close the console.
The issue is only present when I use the SDL renderer with any option other than SDL_RENDERER_SOFTWARE. If I use SDL_RENDERER_SOFTWARE - the program closes as expected. With other options it stays at "return 0" running other threads (crypt32.dll, ntdll.dll and nvd3dum, in this order in the thread view, meaning that the process is stuck in crypt32).
I'm aware that my main function is not the "real main" as it has been hijacked by SDL, so exit(0) works fine as an ad-hoc solution. But I want to know, why exactly does that happen and is there any other way to fix this, so that I don't have to use exit(0) ?
Here is an example (simplified) code, which demonstrates this issue for me:
#include "SDL.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
SDL_Window *win = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *bitmapTex = NULL;
SDL_Surface *bitmapSurface = NULL;
int width = 640, height = 480;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("Could not initialize SDL");
return 1;
}
win = SDL_CreateWindow("Hello World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0);
renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
bitmapSurface = SDL_LoadBMP("res/x.bmp");
bitmapTex = SDL_CreateTextureFromSurface(renderer, bitmapSurface);
SDL_FreeSurface(bitmapSurface);
bool quit = false;
while (!quit) {
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = true;
}
}
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, bitmapTex, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(bitmapTex);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
printf("REACHED RETURN 0");
return 0;
}
Works as intended, but after closing the window I see "REACHED RETURN 0" printed in console and that's it, the console stays there. The code can be simplified further, the issue will be present as long as there is an instance of SDL_Renderer created.
UPD: The callstack during the hanging:
> ntdll.dll!_NtWaitForMultipleObjects#20()
KernelBase.dll!_WaitForMultipleObjectsEx#20()
crypt32.dll!ILS_WaitForThreadProc()
kernel32.dll!#BaseThreadInitThunk#12()
ntdll.dll!__RtlUserThreadStart()
ntdll.dll!__RtlUserThreadStart#8()
UPD2: The problem is not with the loop at all, I created the simplest application where I just create a window and a renderer and then return 0, it still gives me a hanging console. Like this:
#include <SDL.h>
int main(int argc, char* args[])
{
if (SDL_Init(SDL_INIT_VIDEO) < 0) return 1;
SDL_Window* window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
return 0;
}
Same thing when I destroy them properly. The problem is in the renderer.
UPD3: Here is the Parallel Stack window during the "hanging". There is no "main" thread since I close it successfully, these are the threads which stop the program from closing properly. Other than that, it doesn't give me any understanding of the problem.

SDL Window pops up, but it's blank and totally irresponsive

I am 100% sure I have set the SDL library to work properly
#include <iostream>
#include <SDL.h>
using namespace std;
int main(int argc, char* argv\[\]) {
// Initializing SDL
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = 0;
// Creating the window
window = SDL_CreateWindow("Hello World", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, 640, 480,SDL_WINDOW_SHOWN);
// Just so I can see the window because it goes away immediately.
SDL_Delay(5000);
SDL_Quit();
return 0;
}
After you create the window, you need to handle events using SDL_PollEvent. Instead of SDL_Delay(5000), do something like this:
// ... setup (SDL_Init, SDL_CreateWindow, etc.)
SDL_Event event;
for(;;) {
while(SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_QUIT:
goto done;
}
}
}
done:
SDL_Quit();
return 0;

SDL_MOUSEBUTTONUP occurring even before releasing mouse button?

I'm trying to make a video player using SDL and ffmpeg in C++. I've created two separate threads, one that renders the video on the SDL window and one that handles window events. When the user clicks and releases on the video I want it to toggle playback/pause. However, it fires multiple times and the event occurs even before I release the mouse which results in unpredictable behavior.
My code:
SDL_Event event;
while (1)
{
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
SDL_DestroyWindow(screen);
SDL_Quit();
break;
case SDL_MOUSEBUTTONUP:
if (event.button.state == SDL_RELEASED)
{
printf("Mouse released\n");
}
break;
}
}
When I click the window and hold down I would expect it wouldn't print Mouse released until I release the button. However, it prints Mouse released the entire time I hold down the mouse button. I don't know if maybe this has to do with me using a touchpad on my laptop.
SDL_PollEvent has a return value, you are ignoring.
[It] returns 1 if there are any pending events, or 0 if there are none available.
Given your code logic, whenever there is no pending event, you keep handling the previous event over and over again, until a new event arrives. This leads to the observed behavior.
The easiest fix would be to wrap the entire event handling inside an if (SDL_PollEvent(&event)) { /* Event handling */ } conditional.
EDIT: My answer is wrong, check IInspectable's answer.
Your error is that you're not checking all the pending events given by pollEvent, just one. Try this code and tell me how many button ups you get.
#include <SDL2/SDL.h>
#include <iostream>
int main(int argc, char *argv[]) {
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
throw std::runtime_error("SDL failed to initialize.\n");
}
SDL_Window *window = SDL_CreateWindow("App", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, NULL);
bool done = false;
while(!done) {
SDL_Event event;
while(SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT) {
done = true;
}
if (event.type == SDL_MOUSEBUTTONUP) {
if (event.button.state == SDL_RELEASED) {
printf("Mouse released\n");
}
}
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

SDL window does not show

This is my code:
#include <iostream>
#include <SDL2/SDL.h>
int main(int argc, const char * argv[]) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *_window;
_window = SDL_CreateWindow("Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 700, 500, SDL_WINDOW_RESIZABLE);
SDL_Delay(20000);
SDL_DestroyWindow(_window);
SDL_Quit();
return 0;
}
Im working in Xcode. I've downloaded SDL2 and imported the library to the projects build phases. I've tested that the SDL2 works correctly.
The problem is that window never shows up. I just get a "spinning-mac-wheel" and then the program quits after the delay. I've made sure that the window is not hidden behind somewhere.
Ideas?
You have to give the system a chance to have it's event loop run.
easiest is to poll for events yourself:
SDL_Event e;
bool quit = false;
while (!quit){
while (SDL_PollEvent(&e)){
if (e.type == SDL_QUIT){
quit = true;
}
if (e.type == SDL_KEYDOWN){
quit = true;
}
if (e.type == SDL_MOUSEBUTTONDOWN){
quit = true;
}
}
}
instead of the wait loop
--- Addendum
Since this answer is still helping people maybe it's nice if I also add a bit more info on why this works instead of just posting the solution.
When on the Mac (same for Windows actually) a program starts, it starts with just the 'main thread'. This is the thread which is used to set up UI stuff. The 'main thead' differs from other threads in that it comes with an event handling system. This system catches events like mouse moves, key presses, button clicks and then queues these and lets your code respond to it. All the UI things on Mac (and Windows) rely on this event pump being there and running. This is the reason why if you do anything UI related in your code you need to make sure you are not on a different thread.
Now, in your code you initialise the window and the UI, but then you do a SDL_Delay. This just blocks the thread and halts it for 20 seconds so nothing is done. And since you do that on the main thread, even the handling of the queue with the events is blocked. So on the Mac that shows as the spinning macwheel.
So the solution I posted actually keeps on polling for events and handles them. This way you are effectively also 'idling', but the moment events are posted (like mouse clicks and keys) the thread will wake up again and stuff will be processed.
You have to load a bitmap image, or display something on the window, for Xcode to start displaying the window.
#include <SDL2/SDL.h>
#include <iostream>
using namespace std;
int main() {
SDL_Window * window = nullptr;
SDL_Surface * window_surface = nullptr;
SDL_Surface * image_surface = nullptr;
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
window_surface = SDL_GetWindowSurface(window);
image_surface = SDL_LoadBMP("image.bmp");
SDL_BlitSurface(image_surface, NULL, window_surface, NULL);
SDL_UpdateWindowSurface(window);
SDL_Delay(5000);
SDL_DestroyWindow(window);
SDL_FreeSurface(image_surface);
SDL_Quit();
}
You need to initialize SDL with SDL_Init(SDL_INIT_VIDEO) before creating the window.
Please remove the sdl_delay() and replace it with the below mentioned code. I don't have any reason for it but I tried on my own and it works
bool isquit = false;
SDL_Event event;
while (!isquit) {
if (SDL_PollEvent( & event)) {
if (event.type == SDL_QUIT) {
isquit = true;
}
}
}