Support for switching to and from fullscreen mode in Windows during runtime.

This commit is contained in:
gogg 2010-01-10 16:54:09 +00:00
parent acb8427feb
commit b37d1191d5
2 changed files with 241 additions and 88 deletions

View File

@ -329,6 +329,26 @@ set_properties_now(WindowProperties &properties) {
properties.clear_foreground();
}
if (properties.has_fullscreen()) {
if (properties.get_fullscreen() && !is_fullscreen()) {
if (do_fullscreen_switch()){
_properties.set_fullscreen(true);
properties.clear_fullscreen();
} else {
windisplay_cat.warning()
<< "Switching to fullscreen mode failed!\n";
}
} else if (!properties.get_fullscreen() && is_fullscreen()){
if (do_windowed_switch()){
_properties.set_fullscreen(false);
properties.clear_fullscreen();
} else {
windisplay_cat.warning()
<< "Switching to windowed mode failed!\n";
}
}
}
}
@ -345,7 +365,7 @@ close_window() {
if (is_fullscreen()) {
// revert to default display mode.
ChangeDisplaySettings(NULL, 0x0);
do_fullscreen_disable();
}
// Remove the window handle from our global map.
@ -722,6 +742,61 @@ do_fullscreen_resize(int x_size, int y_size) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::do_fullscreen_switch
// Access: Protected, Virtual
// Description: Called in the set_properties_now function
// to switch to fullscreen.
////////////////////////////////////////////////////////////////////
bool WinGraphicsWindow::
do_fullscreen_switch() {
DWORD window_style = make_style(true);
SetWindowLong(_hWnd, GWL_STYLE, window_style);
WINDOW_METRICS metrics;
bool has_origin;
if (!calculate_metrics(true, window_style, metrics, has_origin)){
return false;
}
SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, metrics.width, metrics.height,
SWP_FRAMECHANGED | SWP_SHOWWINDOW);
do_fullscreen_enable();
return true;
}
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::do_windowed_switch
// Access: Protected, Virtual
// Description: Called in the set_properties_now function
// to switch to windowed mode.
////////////////////////////////////////////////////////////////////
bool WinGraphicsWindow::
do_windowed_switch() {
do_fullscreen_disable();
DWORD window_style = make_style(false);
SetWindowLong(_hWnd, GWL_STYLE, window_style);
WINDOW_METRICS metrics;
bool has_origin;
_properties.set_origin(-1, -1);
if (!calculate_metrics(false, window_style, metrics, has_origin)){
return false;
}
// We make an initial SetWindowPos call so that the new styles are taken into account,
// then call do_reshape_request which does the actual sizing and positioning.
SetWindowPos(_hWnd, HWND_NOTOPMOST, metrics.x, metrics.y,
metrics.width, metrics.height,
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
do_reshape_request(0, 0, false, metrics.width, metrics.height);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::reconsider_fullscreen_size
// Access: Protected, Virtual
@ -748,12 +823,13 @@ support_overlay_window(bool) {
}
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::open_graphic_window
// Function: WinGraphicsWindow::make_style
// Access: Private
// Description: Creates a regular or fullscreen window.
// Description: Constructs a dwStyle for the specified mode,
// be it windowed or fullscreen.
////////////////////////////////////////////////////////////////////
bool WinGraphicsWindow::
open_graphic_window(bool fullscreen) {
DWORD WinGraphicsWindow::
make_style(bool fullscreen) {
// from MSDN:
// An OpenGL window has its own pixel format. Because of this, only
// device contexts retrieved for the client area of an OpenGL
@ -761,8 +837,8 @@ open_graphic_window(bool fullscreen) {
// OpenGL window should be created with the WS_CLIPCHILDREN and
// WS_CLIPSIBLINGS styles. Additionally, the window class attribute
// should not include the CS_PARENTDC style.
DWORD window_style =
WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
DWORD window_style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
if (fullscreen){
window_style |= WS_SYSMENU;
@ -775,50 +851,48 @@ open_graphic_window(bool fullscreen) {
window_style |= WS_BORDER;
}
}
return window_style;
}
string title;
if (_properties.has_title()) {
title = _properties.get_title();
}
if (!_properties.has_size()) {
//Just pick a conservative default size if one isn't specified.
_properties.set_size(640, 480);
}
int x_size = _properties.get_x_size();
int y_size = _properties.get_y_size();
int x_origin = 0;
int y_origin = 0;
bool has_origin = _properties.has_origin();
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::calculate_metrics
// Access: Private
// Description: Calculates the metrics for the specified mode,
// be it windowed or fullscreen.
////////////////////////////////////////////////////////////////////
bool WinGraphicsWindow::
calculate_metrics(bool fullscreen, DWORD window_style, WINDOW_METRICS &metrics,
bool &has_origin) {
metrics.x = 0;
metrics.y = 0;
has_origin = _properties.has_origin();
if (!fullscreen && has_origin) {
x_origin = _properties.get_x_origin();
y_origin = _properties.get_y_origin();
metrics.x = _properties.get_x_origin();
metrics.y = _properties.get_y_origin();
// A coordinate of -2 means to center the window in its client area.
if (x_origin == -2) {
x_origin = 0.5 * (_pipe->get_display_width() - x_size);
if (metrics.x == -2) {
metrics.x = 0.5 * (_pipe->get_display_width() - _properties.get_x_origin());
}
if (y_origin == -2) {
y_origin = 0.5 * (_pipe->get_display_height() - y_size);
if (metrics.y == -2) {
metrics.y = 0.5 * (_pipe->get_display_height() - _properties.get_y_origin());
}
_properties.set_origin(x_origin, y_origin);
_properties.set_origin(metrics.x, metrics.y);
if (x_origin == -1 && y_origin == -1) {
x_origin = 0;
y_origin = 0;
if (metrics.x == -1 && metrics.y == -1) {
metrics.x = 0;
metrics.y = 0;
has_origin = false;
}
}
int clientAreaWidth = x_size;
int clientAreaHeight = y_size;
metrics.width = _properties.get_x_size();
metrics.height = _properties.get_y_size();
if (!fullscreen){
RECT win_rect;
SetRect(&win_rect, x_origin, y_origin,
x_origin + x_size, y_origin + y_size);
SetRect(&win_rect, metrics.x, metrics.y,
metrics.x + metrics.width, metrics.y + metrics.height);
// Compute window size based on desired client area size
if (!AdjustWindowRect(&win_rect, window_style, FALSE)) {
@ -828,14 +902,42 @@ open_graphic_window(bool fullscreen) {
}
if (has_origin) {
x_origin = win_rect.left;
y_origin = win_rect.top;
metrics.x = win_rect.left;
metrics.y = win_rect.top;
} else {
x_origin = CW_USEDEFAULT;
y_origin = CW_USEDEFAULT;
metrics.x = CW_USEDEFAULT;
metrics.y = CW_USEDEFAULT;
}
clientAreaWidth = win_rect.right - win_rect.left;
clientAreaHeight = win_rect.bottom - win_rect.top;
metrics.width = win_rect.right - win_rect.left;
metrics.height = win_rect.bottom - win_rect.top;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::open_graphic_window
// Access: Private
// Description: Creates a regular or fullscreen window.
////////////////////////////////////////////////////////////////////
bool WinGraphicsWindow::
open_graphic_window(bool fullscreen) {
DWORD window_style = make_style(fullscreen);
string title;
if (_properties.has_title()) {
title = _properties.get_title();
}
if (!_properties.has_size()) {
//Just fill in a conservative default size if one isn't specified.
_properties.set_size(640, 480);
}
WINDOW_METRICS metrics;
bool has_origin;
if (!calculate_metrics(fullscreen, window_style, metrics, has_origin)){
return false;
}
const WindowClass &wclass = register_window_class(_properties);
@ -869,13 +971,13 @@ open_graphic_window(bool fullscreen) {
if (!_hparent) { // This can be a regular window or a fullscreen window
_hWnd = CreateWindow(wclass._name.c_str(), title.c_str(), window_style,
x_origin, y_origin,
clientAreaWidth,
clientAreaHeight,
metrics.x, metrics.y,
metrics.width,
metrics.height,
NULL, NULL, hinstance, 0);
} else { // This is a regular window with a parent
x_origin = 0;
y_origin = 0;
int x_origin = 0;
int y_origin = 0;
if (!fullscreen && has_origin) {
x_origin = _properties.get_x_origin();
@ -885,7 +987,7 @@ open_graphic_window(bool fullscreen) {
_hWnd = CreateWindow(wclass._name.c_str(), title.c_str(),
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS ,
x_origin, y_origin,
x_size, y_size,
_properties.get_x_size(), _properties.get_y_size(),
_hparent, NULL, hinstance, 0);
if (_hWnd) {
@ -914,6 +1016,24 @@ open_graphic_window(bool fullscreen) {
// up the desktop during the mode change.
if (fullscreen){
if (!do_fullscreen_enable()){
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::do_fullscreen_enable
// Access: Private
// Description: This is a low-level function that just puts Windows
// in fullscreen mode. Not to confuse with
// do_fullscreen_switch().
////////////////////////////////////////////////////////////////////
bool WinGraphicsWindow::
do_fullscreen_enable() {
HWND hDesktopWindow = GetDesktopWindow();
HDC scrnDC = GetDC(hDesktopWindow);
DWORD cur_bitdepth = GetDeviceCaps(scrnDC, BITSPIXEL);
@ -952,8 +1072,25 @@ open_graphic_window(bool fullscreen) {
_properties.set_origin(0, 0);
_properties.set_size(dwWidth, dwHeight);
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::do_fullscreen_disable
// Access: Private
// Description: This is a low-level function that just gets Windows
// out of fullscreen mode. Not to confuse with
// do_windowed_switch().
////////////////////////////////////////////////////////////////////
bool WinGraphicsWindow::
do_fullscreen_disable() {
int chg_result = ChangeDisplaySettings(NULL, 0x0);
if (chg_result != DISP_CHANGE_SUCCESSFUL) {
windisplay_cat.warning()
<< "ChangeDisplaySettings failed to restore Windowed mode\n";
return false;
}
return true;
}
@ -1241,7 +1378,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
// losing the graphics context.
ShowWindow(_hWnd, SW_MINIMIZE);
GdiFlush();
ChangeDisplaySettings(NULL, 0x0);
do_fullscreen_disable();
fullscreen_minimized(properties);
}
}
@ -2165,7 +2302,7 @@ find_acceptable_display_mode(DWORD dwWidth, DWORD dwHeight, DWORD bpp,
if ((dm.dmPelsWidth == dwWidth) && (dm.dmPelsHeight == dwHeight) &&
(dm.dmBitsPerPel == bpp)) {
cout << "[FS FOUND] " << dwWidth << "x" << dwHeight << "@" << bpp << endl;
// cout << "[FS FOUND] " << dwWidth << "x" << dwHeight << "@" << bpp << endl;
// We want to modify the current DEVMODE rather than using a fresh one in order
// to work around a Windows 7 bug.
ZeroMemory(&dm, sizeof(dm));

View File

@ -28,7 +28,13 @@ class WinGraphicsPipe;
#define PM_INACTIVE (WM_APP+124)
typedef struct {
int x;
int y;
int width;
int height;
}
WINDOW_METRICS;
////////////////////////////////////////////////////////////////////
// Class : WinGraphicsWindow
@ -83,6 +89,16 @@ protected:
virtual void handle_reshape();
virtual bool do_fullscreen_resize(int x_size, int y_size);
virtual bool do_fullscreen_switch();
virtual bool do_windowed_switch();
virtual bool do_fullscreen_enable();
virtual bool do_fullscreen_disable();
virtual bool calculate_metrics(bool fullscreen, DWORD style,
WINDOW_METRICS &metrics, bool &has_origin);
virtual DWORD make_style(bool fullscreen);
virtual void reconsider_fullscreen_size(DWORD &x_size, DWORD &y_size,
DWORD &bitdepth);