Making room for a menu bar to my Windows/SDL application

I want to add a normal win32 menubar to the Windows version of my SDL
application. In this I have been quite successful, but I find that SDL
will not allow me to display both the menubar and the entire display.

Specifically, my program uses a 640x512 pixel sized display when in a
non-fullscreen mode. If I use SDL_SetVideoMode as per usual then I get
my 640x512 pixels + the usual window decorations and everything works
perfectly.

If I use the win32 API function SetMenu to add a menu bar to my window
then the menu bar appears and is fully interactive, but it takes up
some of the room in my window. On XP set up as I have it, it takes up
18 pixels (although of course I derive this at runtime). The SDL
graphic output is moved down correctly, but the lowest 18 pixels are
not displayed because they would now be outside the window SDL has
created.

My intended fix would use another win32 API function, SetWindowPos to
resize the window, making it taller by the required number of pixels.
SDL seems to resist this. If I make a call to SetWindowPos straight
after adding the menu bar then any attempt to resize is ignored. If I
use the flag “SWP_NOSENDCHANGING”, withholding the
WM_WINDOWPOSCHANGING message from SDL then the window is successfully
resized.

However, if the Window is moved then it snaps back to its original
size (i.e. lacking 18 scanlines). So what seems to be happening is the
message handler in SDL responds to WM_WINDOWPOSCHANGING with an
internal recalculation of the correct window size that does not allow
for the possibility of a menu bar.

Is there some way to fix this? At present the only solution I can
think of is to get the size of the menu bar at startup and
deliberately ask for a display window increased in size by that amount
so that SDL only throws away pixels I am not using. That strikes me as
a not very neat solution which unnecessarily tangles my platform
neutral and platform specific code, so I would like to avoid it if
possible.

-Thomas

However, if the Window is moved then it snaps back to its original
size (i.e. lacking 18 scanlines). So what seems to be happening is the
message handler in SDL responds to WM_WINDOWPOSCHANGING with an
internal recalculation of the correct window size that does not allow
for the possibility of a menu bar.

You could render your graphics to an in memory SDL_Surface, then use
SDLToWin32 to blit this surface to a window that you have created yourself.

SDLToWin32 is here:

http://www.polplex.co.uk/~tigger/sdl/index.html

Cheers,

  • Tom>Is there some way to fix this? At present the only solution I can

think of is to get the size of the menu bar at startup and
deliberately ask for a display window increased in size by that amount
so that SDL only throws away pixels I am not using. That strikes me as
a not very neat solution which unnecessarily tangles my platform
neutral and platform specific code, so I would like to avoid it if
possible.

-Thomas


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

You could render your graphics to an in memory SDL_Surface, then use
SDLToWin32 to blit this surface to a window that you have created yourself.

Thankyou for the tip. I would rather not have to create the Window
myself, etc, but I will if necessary. Ideally I could just use some
sort of backdoor SDL mechanism to inform it that it’s window size
calculations need to be adjusted, or else hook some sort of platform
specific event. I guess I need to look into what SDL_SysWMEvent
provides on the Windows platform.

Looking into your (?) code, it doesn’t seem to be quite suitable for
my project but I can adapt it. In particular I note that the only
option is an entire buffer refresh, whereas my application is going
out of the way to only repaint its entire buffer when absolutely
necessary, otherwise confining changes and using UpdateRect
selectively. I doubt that makes much difference on current win32
platforms, but on OS X the difference is gigantic and I guess it will
be in Vista too.

While browsing your code, I saw this at line 169 of SDLToWin32.cpp:

BitBlt(hdc, x_pos, y_pos, client.left+client.right,
				  client.bottom+client.top,
				memdc, 0, 0, SRCCOPY);

Should that not be:

BitBlt(hdc, x_pos, y_pos, client.left-client.right,
				  client.bottom-client.top,
				memdc, 0, 0, SRCCOPY);

?

-Thomas

You could render your graphics to an in memory SDL_Surface, then
use SDLToWin32 to blit this surface to a window that you have
created yourself.

Thankyou for the tip. I would rather not have to create the Window
myself, etc, but I will if necessary.

Another possible solution I’ve toyed with, which works better with
SDL, is this. Instead of trying to install a permanent menu bar, put
your menu items in a free-floating popup menu. Display the popup menu
when the user right-clicks on your window.

There’s enough precedent for this kind of menu that it should still be
relatively intuitive for your users.

b

I believe I have found a solution, and thought I would post it in case
anybody comes to this thread in the archives in the future.

The code within SDL that resizes the Window so as to make the menu bar
a problem is that in SDL_sysevents.c at line 397 onwards that responds
to WM_GETMINMAXINFO. In order to do this, if the SDL window is not set
as resizeable it recalculates the correct size of the window using the
win32 function AdjustWindowRect. Even if SetMenu has been used to add
a menu bar to a window, AdjustWindowRect seems not to take a menu bar
into account if it was not set at the CreateWindow stage. That latter
conclusion is based on my quick experimentation and is not reflected
in the MSDN docs, although to be honest they aren’t particularly
explicit about anything.

My fix is therefore to pass SDL_RESIZABLE as a flag to
SDL_SetVideoBitmap and then at the same time as I branch into win32
specific code, adding a menu bar and resizing the whole window to fit
it, I do the following:

style = GetWindowLong(SDL_Window, GWL_STYLE) & ~(WS_THICKFRAME|WS_MAXIMIZEBOX);
SetWindowLong(SDL_Window, GWL_STYLE, style);

Which removes the window frame and maximise buttons that would allow a
user to resize the window. Hence the SDL internals think the window is
resizable and don’t interfere with any user side window size
modifications but the Windows GUI thinks the window isn’t resizable
and doesn’t allow the user to do so.

Unfortunately, as I am not able to use a Windows system again until at
least tomorrow, I haven’t tested this final step. I’m quite confident
in it though.

As I’m not a regular Windows user any more, I must ask - is there any
other way that a Window might end up resized without the user
explicitly saying “please resize this window”?

-Thomas