Toggling windowed <-> full screen

Hi SDL guys,

I have some code which toggles windowed <-> full screen and usually
works in Linux, Mac and Windows. It’s as follows :

    void SDLVideoDriver::toggleFullScreen (void)
    {
    	bool bWasFullScreen = getFullScreen();
    
    	int nOldFlags = m_pScreenSurf->flags;
    	int nOldW = m_pScreenSurf->w;
    	int nOldH = m_pScreenSurf->h;
    	SDL_Surface* pNewSurf = SDL_SetVideoMode(m_pScreenSurf->w,
    m_pScreenSurf->h, 0, m_pScreenSurf->flags ^ SDL_FULLSCREEN);
    
    	if (!pNewSurf)
    	{
    		GameApp::writeToLog(String::fromFormat("S: Toggle failed (%d)
    [%s]\n", bWasFullScreen, SDL_GetError()));
    		pNewSurf = SDL_SetVideoMode(nOldW, nOldH, 0, nOldFlags);
    
    		if (!pNewSurf)
    			GFC_FATAL(String::fromFormat("S: Couldn't restore old video
    mode, aborting [%s]", SDL_GetError()));
    	}
    
    	[...more stuff follows...]
    }

As you can see, it tries to toggle, and if the toggle fails, it tries to
restore the old video mode.

The problem is that, while it usually works, sometimes it doesn’t - and
the error messages I get are

S: Toggle failed (0) [DirectDraw2::SetCooperativeLevel: Exclusive mode

was already set]

and when it tries to restore the old video mode,

S: Couldn't restore old video mode, aborting

[DirectDraw2::CreateSurface(PRIMARY): Not in exclusive access mode]

So I can’t go from windowed to full screen because “exclusive mode is
already set”, and I can’t recreate the window because it says “not in
exclusive access mode”.

I’m not very knowledgeable in DirectDraw; does anyone know what this
means, and more importantly, how should I deal with it? What do you do
if toggling the video mode fails?

Thanks,
–Gabriel

I have some code which toggles windowed <-> full screen and usually
works in Linux, Mac and Windows.

What has worked best for me is releasing the video subsystem and re-
initializing it instead of just setting a new video mode. You may want
to try this, it might solve your problem. Just do this before you set
the new video mode:

SDL_QuitSubSystem(SDL_INIT_VIDEO);
SDL_InitSubSystem(SDL_INIT_VIDEO);

Not releasing the video subsystem may be the reason DirectX is staying
in exclusive mode. I think I had problems before I did this too.

Ilya

What has worked best for me is releasing the video subsystem and re-
initializing it instead of just setting a new video mode. You may want
to try this, it might solve your problem. Just do this before you set
the new video mode:

SDL_QuitSubSystem(SDL_INIT_VIDEO);
SDL_InitSubSystem(SDL_INIT_VIDEO);

Not releasing the video subsystem may be the reason DirectX is staying
in exclusive mode. I think I had problems before I did this too.

Sounds… scary :\ Do you have to reload images or something like that?

I can’t answer that question (“do you have to?”), but I can see one
reason why you might want to… If your new video mode is a different
format (e.g., bitdepth) than your old, you might want to reload everything
so you can run them through SDL_DisplayFormat() again…

-bill!On Tue, May 03, 2005 at 09:34:00PM -0300, Gabriel wrote:

What has worked best for me is releasing the video subsystem and re-
initializing it instead of just setting a new video mode. You may want
to try this, it might solve your problem. Just do this before you set
the new video mode:

SDL_QuitSubSystem(SDL_INIT_VIDEO);
SDL_InitSubSystem(SDL_INIT_VIDEO);

Not releasing the video subsystem may be the reason DirectX is staying
in exclusive mode. I think I had problems before I did this too.

Sounds… scary :\ Do you have to reload images or something like that?

Sounds… scary :\ Do you have to reload images or something like that?

Well yeah, I thought that even changing the video mode makes you lose
your surfaces. Either way, it’s always a good idea to have support for
reloading your images so you can properly support alt-tab. It’s not
that difficult if you set up a resource manager that hangs on to the
actual surface pointers, and assigns an integer handle to each of them.
You can then make use of the handle throughout your code, and only
dereference it when the surface needs to be drawn. This way if you lose
your surfaces, the resource manager can transparently reload them. If
you only dereference the handles at drawing time, you will always get
back a valid pointer. This adds a tiny bit of overhead since you’re
calling an extra (dereferencing) function, but since the function is so
small you can make it inline if you wish. This has worked very well for
me.

Ilya