Live-resize of an SDL window

Is there any way of getting an event while the window is resizing to say that the window is, in fact, resizing ? :slight_smile:

The current ones in SDL3 seem to be SDL_EVENT_WINDOW_RESIZED and SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED. Both of these get sent after the resize is completed.

The problem is that the current resize action does a ‘stretch’ of the window as you’re resizing it, but in my UI framework I have constraints to figure out how the various part of the window should resize themselves. In the example below, the right and left margins from the view to its parent (in this case the window’s content-view) are constrained to be fixed and the view-width itself is unconstrained, so resizing the window will commensurately resize the view.

All well and good, but the stretch effect doesn’t know about my constraints so there’s a s…t…r…e…t…c…h then SNAP! effect going on, which just looks … weird.

I tried using the event-watcher approach, registering for events on the window…

static BOOL resizingEventWatcher(void* data, SDL_Event* e)
	{
	if (e->type == SDL_EVENT_WINDOW_RESIZED)
		{
		SDL_Window* win = SDL_GetWindowFromID(e->window.windowID);
		if (win == (SDL_Window*)data)
			{
			AZView *cv = [AZView contentViewForWindow:win];
			int w = e->window.data1;
			int h = e->window.data2;

			NSNotificationCenter *nc = NSNotificationCenter.defaultCenter;
			[nc postNotificationName:AZRootViewWillResizeNotification object:cv];
			[cv setFrame:NSMakeRect(0,0,w,h)];
			}
		}
	return 0;
	}

… and I do indeed get the resize events as they happen, but taking the same actions as in the event-loop for SDL_EVENT_WINDOW_RESIZED doesn’t have any effect - I’m assuming the routine doing the s…t…r…e…t…c…h effect has grabbed the display output or something similar. My own redraws don’t happen, anyway, so the visual effect remains the same:

So, any ideas on how I could get a prettier resize ?

On a positive note, after a whole lot of boiler-plate framework setup code, I got my first widget yesterday evening… Drum roll please for … AZButton! :slight_smile:

Use the SDL_App* callbacks instead of main()

I am actually using those, but I still don’t get any callbacks while the resize is happening :frowning:

Oh! I read your OP properly this time. Is the problem is with your framework? It’s the stretching and the events are being lost at the top somewhere?

With SDL_App callbacks, why do you have a watcher? SDL_AppResult SDL_AppEvent(void * win, SDL_Event* event) will catch all live events coming in.

Which platform is this?

I tried the watcher because I don’t get the events when resizing :slight_smile:

I mean, I might be doing something wrong in the framework - SDL3 is still new to me :slight_smile: but the code seems fairly straightforward… The appEvent call looks like:

/*****************************************************************************\
|* Callback: This function runs when a new event occurs
\*****************************************************************************/
SDL_AppResult SDL_AppEvent(void *appState, SDL_Event *event)
	{
	return [AZApp.sharedInstance handleEvent:event withAppState:appState];
	}

and the entirety of the handleEvent method looks like:

/*****************************************************************************\
|* Handle events
\*****************************************************************************/
- (SDL_AppResult) handleEvent:(SDL_Event *)e withAppState:(void *)state
	{
	SDL_AppResult result 	= SDL_APP_CONTINUE;
	AZView *cv 				= [AZWindow contentViewForWindow:_window];
	NSPoint p				= (NSPoint){-1,-1};

	switch (e->type)
		{
		/*********************************************************************\
		|* Tell the OS that we successfully quit
		\*********************************************************************/
		case SDL_EVENT_QUIT:
			result = SDL_APP_SUCCESS;
			break;

		/*********************************************************************\
		|* Handle mouse events
		\*********************************************************************/
		case SDL_EVENT_MOUSE_BUTTON_DOWN:
		case SDL_EVENT_MOUSE_BUTTON_UP:
			p.x = ((SDL_MouseButtonEvent *)e)->x;
			p.y = ((SDL_MouseButtonEvent *)e)->y;
			[cv processMouseButtonEvent:e atPoint:p];
			break;

		case SDL_EVENT_MOUSE_MOTION:
			p.x = ((SDL_MouseMotionEvent *)e)->x;
			p.y = ((SDL_MouseMotionEvent *)e)->y;
			[cv processMouseMotionEvent:e atPoint:p];
			break;

		case SDL_EVENT_MOUSE_WHEEL:
			p.x = ((SDL_MouseMotionEvent *)e)->x;
			p.y = ((SDL_MouseMotionEvent *)e)->y;
			[cv processMouseWheelEvent:e atPoint:p];
			break;

		/*********************************************************************\
		|* Keyboard
		\*********************************************************************/
		case SDL_EVENT_TEXT_EDITING_CANDIDATES:
			if (_window.firstResponder)
				[_window.firstResponder textEditingCandidates:e];
			break;

		case SDL_EVENT_TEXT_EDITING:
			if (_window.firstResponder)
				[_window.firstResponder textEditing:&(e->edit)];
			break;

		case SDL_EVENT_TEXT_INPUT:
			if (_window.firstResponder)
				[_window.firstResponder textInput:&(e->text)];
			break;

		case SDL_EVENT_KEY_DOWN:
			if (_window.firstResponder)
				[_window.firstResponder keyDown:&(e->key)];
			break;

		/*********************************************************************\
		|* Handle resize events
		\*********************************************************************/
		case SDL_EVENT_WINDOW_RESIZED:
			{
			int w = e->window.data1;
			int h = e->window.data2;

			NSNotificationCenter *nc = NSNotificationCenter.defaultCenter;
			[nc postNotificationName:AZRootViewWillResizeNotification object:cv];
			
			[cv setFrame:NSMakeRect(0,0,w,h)];
			break;
			}
		}

	/* carry on with the program! */
	return result;
	}

If I add to the window-resized event case…

		case SDL_EVENT_WINDOW_RESIZED:
			{
			static int i=0;
			fprintf(stderr, "%d", i++);
			i %=20;

… and then start resizing the window, I see it all stretching around as I resize, and then right at the end (when I release the mouse button and the view redraws itself properly) I see a ‘0’ in the console, do it again and I get a ‘1’ after the mouse is released, etc. No feedback in the event-case block while the dragging is happening, so it certainly seems like there’s no resize events happening while the I’m dragging the window frame itself.

This is on a Mac, btw.

It could be your flow that’s the problem, I’m having a hard time understanding the code - is that Objective-C? I’ve no experience with it.

Look at this minimal example in C (you should be able to adapt from it). This is SDL’s endorsed flow you should be aiming for, and is 100% robust - no need to over-engineer it. Rendering generally isn’t done on events being triggered. The resize event triggers a redraw in this case. Hopefully you can grab the latest SDL source, so you have access to the new SDL_RenderDebugTextFormat.

#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL_main.h>
#include <SDL3/SDL.h>

typedef struct {
	SDL_Window* win;
	SDL_Renderer* ren;
	bool redraw;
} AppState;

SDL_AppResult SDL_AppInit(void** s, int, char**) {
	if(!(*s = SDL_malloc(sizeof AppState)))
		return SDL_APP_FAILURE;
	AppState* state = (AppState*)*s;
	if(!SDL_Init(SDL_INIT_EVENTS))
		return SDL_APP_FAILURE;
	if (!(state->win = SDL_CreateWindow(nullptr, 500, 500, SDL_WINDOW_RESIZABLE)))
		return SDL_APP_FAILURE;
	if (!(state->ren = SDL_CreateRenderer(state->win, NULL)))
		return SDL_APP_FAILURE;
	SDL_SetRenderVSync(state->ren, 1);
	return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppIterate(void* s) {
	AppState* state = (AppState*)s;
	if (state->redraw) {
		SDL_SetRenderDrawColor(state->ren, 16, 16, 16, SDL_ALPHA_OPAQUE);
		SDL_RenderClear(state->ren);
		int x, y;
		SDL_GetRenderOutputSize(state->ren, &x, &y);
		SDL_SetRenderDrawColor(state->ren, 0, 255, 0, SDL_ALPHA_OPAQUE);
		SDL_RenderDebugTextFormat(state->ren, 5, 5, "Window size %d x %d", x, y);
		SDL_RenderPresent(state->ren);
		state->redraw = false;
	}
	SDL_Delay(1);
	return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppEvent(void* s, SDL_Event* event) {
	AppState* state = (AppState*)s;
	switch (event->type) {
	case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
		state->redraw = true;
		break;
	case SDL_EVENT_QUIT:
		return SDL_APP_SUCCESS;
	}
	return SDL_APP_CONTINUE;
}

void SDL_AppQuit(void* s, SDL_AppResult result) {
	AppState* state = (AppState*)s;
	if (result == SDL_APP_FAILURE)
		SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), s ? state->win : NULL);
	SDL_free(s);
}

If this example still blocks the resize events, and instead stretches the debug text, then the blocking must be done on the operating-system level?

Well, I get the same effect when I use your code (with a couple of very minor changes - your source is C2x and clang is only C17, and I reduced the window size to make the video smaller in terms of MB)…

Clearly it can be done because all Mac apps do this live-resizing with redraw happening as the resize takes place. I guess SDL doesn’t handle the native Mac window resize events then. Bummer :frowning:

I didn’t use the latest source version (I just sprintf’d the text and used the non-format version of the debug-text) so maybe I’ll try downloading that and recompiling. I think the version of SDL3 I have is just the latest release.

1 Like

I’m experiencing the same issue on the very latest version of SDL3 on MacOS only. I am using the callbacks, and the issue does not exist on Windows.

You can reproduce this issue in any of the SDL examples, by adding the SDL_WINDOW_RESIZABLE flag to SDL_CreateWindowAndRenderer.

For example, the gif below is render_geometry:
resize

1 Like

@ AntTheAlchemist

I tested it and apart from the two syntax errors that I fixed, it works perfectly.

$ gcc main.c -o main -lSDL3
main.c: In function ‘SDL_AppInit’:
main.c:12:37: error: expected expression before ‘AppState’
12 | if(!(*s = SDL_malloc(sizeof AppState)))
| ^~~~~~~~
main.c:17:45: error: ‘nullptr’ undeclared (first use in this function); did you mean ‘nullptr_t’?
17 | if (!(state->win = SDL_CreateWindow(nullptr, 500, 500, SDL_WINDOW_RESIZABLE)))
| ^~~~~~~
| nullptr_t
main.c:17:45: note: each undeclared identifier is reported only once for each function it appears in

@Mathias Sorry about that, I used a bit of C++ syntax in there by habit.

You said it worked, was that on MacOS?

I forgot to say that. I tried it with Linux Mint with X11.

@eyalamir & @SpacedCowboy, This sounds like an SDL bug. Are either of you able to raise an issue on github for it?

So I was going to write an issue about it, but in a rare bout of development efficiency, I did a search first, and found it was already in the list.

Looks like Sam has made it a candidate for the 3.2 milestone :slight_smile:

Heh, looks like the streams just crossed @AntTheAlchemist :slight_smile:

1 Like

So just to follow up, Sam’s latest fix means the live-resize works properly now :slight_smile:

1 Like