Sign in to follow this  
Snake45

Win32 API Fullscreen mode

Recommended Posts

Hi, I'm writing a small game on windows using VC++ and OpenGL and I noticed a strange behavior when using a fullscreen window. Whenever I switch to fullscreen mode and changing the screen resolution using ChangeDisplaySettings and then go back to the original resolution, every opened window on the desktop "snap" in the lower right corner. That is if a window is not maximised and its corner is near but not touching the desktop corner it will be moved in the corner of the desktop when coming back from fullscreen mode. I tried several tutorials and demos from the internet and they all seems to behave that way. Even NeHe's famous tutorials have all this bug. I searched around on the internet for an explanation or a way to correct this but didn't find anything. However if I do the same test with a commercial game, the windows are in the correct position when exiting the game so there must be a way to fix it. Here is a simple piece of code that I use for switching resolution :
static void WinSetVideoMode(int iWidth, int iHeight, int iBpp)
{
  DEVMODE Mode;
  EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &Mode);
  Mode.dmBitsPerPel = iBpp; 
  Mode.dmPelsWidth = iWidth;
  Mode.dmPelsHeight = iHeight;
  Mode.dmSize = sizeof(Mode);
  Mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
  
  ChangeDisplaySettings(&Mode, CDS_FULLSCREEN);
};

// Restore le mode vidéo d'origine
static void WinRestoreVideoMode(void)
{
  ChangeDisplaySettings(NULL, 0);
};


If someone has an example of code which simply create a fullscreen window then switch back to normal mode, destroy the window without moving other windows that would be nice. Note that for the bug to happen you have to set another window (windows explorer for example) not maximised but covering almost all of the desktop so that the lower right corner of the window is near the corner of the desktop. Lets say 20-30 pixels. Then the program switch to a lower resolution and go back to its original resolution. Thanks! [Edited by - ApochPiQ on June 5, 2009 9:14:26 PM]

Share this post


Link to post
Share on other sites
I use something like this :) (note not with opengl)

bool GoFullscreen()
{
// turn off window region without redraw
SetWindowRgn(m_hWindow, 0, false);

DEVMODE newSettings;

// request current screen settings
EnumDisplaySettings(0, 0, &newSettings);

// set desired screen size/res
newSettings.dmPelsWidth = GetWidth();
newSettings.dmPelsHeight = GetHeight();
newSettings.dmBitsPerPel = 32;

//specify which aspects of the screen settings we wish to change
newSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

// attempt to apply the new settings
long result = ChangeDisplaySettings(&newSettings, CDS_FULLSCREEN);

// exit if failure, else set datamember to fullscreen and return true
if ( result != DISP_CHANGE_SUCCESSFUL ) return false;
else
{
// store the location of the window
m_oldLoc = GetLocation();

// switch off the title bar
DWORD dwstyle = GetWindowLong(m_hWindow, GWL_style);
dwstyle &= ~WS_CAPTION;
SetWindowLong(m_hWindow, GWL_style, dwstyle);

// move the window to (0,0)
SetWindowPos(m_hWindow, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
InvalidateRect(m_hWindow, 0, true);

return true;
}
}

bool GoWindowedMode()
{
// this resets the screen to the registry-stored values
ChangeDisplaySettings(0, 0);

// replace the title bar
DWORD dwstyle = GetWindowLong(m_hWindow, GWL_style);
dwstyle = dwstyle | WS_CAPTION;
SetWindowLong(m_hWindow, GWL_style, dwstyle);

// move the window back to its old position
SetWindowPos(m_hWindow, 0, m_oldLoc.x, m_oldLoc.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
InvalidateRect(m_hWindow, 0, true);

return true;
}


[Edited by - ApochPiQ on June 3, 2009 8:49:23 PM]

Share this post


Link to post
Share on other sites
Thanks but that this will save and restore the position of the current window which I don't care because when I exit the game I destroy this window (program termination). The problem is with all the other windows on screen.

I tried to save the position of every single window on screen to restore them when the program exits and I have everything working except for one thing : I need the handle of each window that I want to save/restore. How do I get them is not an easy task... The window manager has a hierarchy of windows with the desktop handle at its root. I can get the desktop handle with GetDesktopWindow() and then Enumerating every child window but I get like 1000+ window handles! I have only 4-5 visible windows on screen (they are on the taskbar) and I don't need to save more than that. I could even skip those that are minimized. How can I get the handles of the actual visible windows on screen ?

Maybe I should get a good book on Windows programming... Any suggestions?

Share this post


Link to post
Share on other sites
I finally solved it. I'll post the solution here for those who want to Save/Restore window positions.

typedef struct
{
HWND hWnd;
WINDOWPLACEMENT Placement;
} WININFO;

std::vector <WININFO> WinInfos;

BOOL CALLBACK MyEnumWindowsProc(HWND hwnd, LPARAM lParam)
{
WININFO WinInfo;

if(IsWindowVisible(hwnd))
{
WinInfo.hWnd = hwnd;
GetWindowPlacement(hwnd, &WinInfo.Placement);
WinInfos.push_back(WinInfo);
}

return TRUE;
}

void SaveWindowPositions()
{
EnumWindows(MyEnumWindowsProc, 0);
}

void RestoreWinPositions(void)
{
WININFO WinInfo;

while(!WinInfos.empty())
{
WinInfo = WinInfos.back();
WinInfos.pop_back();
SetWindowPlacement(WinInfo.hWnd, &WinInfo.Placement);
}
}

So all you have to do is call SaveWindowPosition before going fullscreen and call RestoreWinPositions after switching back to the original desktop resolution. I don't know if this is the best way to do it but at least it works.

Share this post


Link to post
Share on other sites
It's just the way Windows is, you can observe the same behaviour by changing the resolution or colour depth in the Display Properties dialog. When the settings are updated dynamically, windows beyond a certain threshold of visibility are rejigged into the corner of the new resolution, probably so that users don't lose access to windows that would otherwise be beyond reach with the mouse.

Anyway, the quickest and easiest way to circumvent this is to pass the horribly misnamed CDS_FULLSCREEN flag on both changes. The flag tells Windows the resolution change is temporary so it doesn't bother with repositioning. Well, not on my XP at least.

Share this post


Link to post
Share on other sites
I was using CDS_FULLSCREEN when going fullscreen so that my icons keep their positions and the windows stay the same size but the windows were still moving. So I tried CDS_FULLSCREEN on both calls to ChangeDisplaySettings like you said and tadadaaaam! It worked. That is much easier than the other way. Im on Vista so we can assume it works on both OS. I wonder why this trick isn't in every fullscreen window creation tutorial we can find around. Thanks a lot!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this