more fixes from Gogg: Windows 7 fullscreen workaround

This commit is contained in:
David Rose 2009-11-18 22:14:05 +00:00
parent 6a5dcc40e8
commit c172d80a41
4 changed files with 139 additions and 152 deletions

View File

@ -13,7 +13,7 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: TextFont::get_face
// Function: FreetypeFace::get_face
// Access: Published
// Description: Retrieves the internal freetype face.
////////////////////////////////////////////////////////////////////
@ -23,11 +23,14 @@ get_face() {
}
////////////////////////////////////////////////////////////////////
// Function: TextFont::set_face
// Function: FreetypeFace::set_face
// Access: Published
// Description: Sets the internal freetype face.
////////////////////////////////////////////////////////////////////
INLINE void FreetypeFace::
set_face(FT_Face face) {
if (_face != NULL){
FT_Done_Face(_face);
}
_face = face;
}

View File

@ -42,7 +42,7 @@ FreetypeFont::
FreetypeFont() {
_font_loaded = false;
_face = new FreetypeFace();
_face = NULL;
_point_size = text_point_size;
_requested_pixels_per_unit = text_pixels_per_unit;
@ -91,6 +91,7 @@ load_font(const Filename &font_filename, int face_index) {
(const FT_Byte *)_raw_font_data.data(),
_raw_font_data.length(),
face_index, &face);
_face = new FreetypeFace();
_face->set_face(face);
}
@ -135,6 +136,7 @@ load_font(const char *font_data, int data_length, int face_index) {
error = FT_New_Memory_Face(_ft_library,
(const FT_Byte *)font_data, data_length,
face_index, &face);
_face = new FreetypeFace();
_face->set_face(face);
if (error == FT_Err_Unknown_File_Format) {

View File

@ -379,12 +379,7 @@ open_window() {
// even before it gives us a handle. Warning: this is not thread
// safe!
_creating_window = this;
bool opened;
if (is_fullscreen()) {
opened = open_fullscreen_window();
} else {
opened = open_regular_window();
}
bool opened = open_graphic_window(is_fullscreen());
_creating_window = (WinGraphicsWindow *)NULL;
if (!opened) {
@ -737,96 +732,12 @@ support_overlay_window(bool) {
}
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::open_fullscreen_window
// Function: WinGraphicsWindow::open_graphic_window
// Access: Private
// Description: Creates a fullscreen-style window.
// Description: Creates a regular or fullscreen window.
////////////////////////////////////////////////////////////////////
bool WinGraphicsWindow::
open_fullscreen_window()
{
// from MSDN:
// An OpenGL window has its own pixel format. Because of this, only
// device contexts retrieved for the client area of an OpenGL
// window are allowed to draw into the window. As a result, an
// 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_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
if (!_properties.has_size()) {
// Just pick a stupid default size if one isn't specified.
_properties.set_size(640, 480);
}
// No parent window for a fullscreen window.
_parent_window_handle = NULL;
HWND hDesktopWindow = GetDesktopWindow();
HDC scrnDC = GetDC(hDesktopWindow);
DWORD cur_bitdepth = GetDeviceCaps(scrnDC, BITSPIXEL);
// DWORD drvr_ver = GetDeviceCaps(scrnDC, DRIVERVERSION);
// DWORD cur_scrnwidth = GetDeviceCaps(scrnDC, HORZRES);
// DWORD cur_scrnheight = GetDeviceCaps(scrnDC, VERTRES);
ReleaseDC(hDesktopWindow, scrnDC);
DWORD dwWidth = _properties.get_x_size();
DWORD dwHeight = _properties.get_y_size();
DWORD dwFullScreenBitDepth = cur_bitdepth;
reconsider_fullscreen_size(dwWidth, dwHeight, dwFullScreenBitDepth);
if (!find_acceptable_display_mode(dwWidth, dwHeight, dwFullScreenBitDepth,
_fullscreen_display_mode)) {
windisplay_cat.error()
<< "Videocard has no supported display resolutions at specified res ("
<< dwWidth << " x " << dwHeight << " x " << dwFullScreenBitDepth <<")\n";
return false;
}
string title;
if (_properties.has_title()) {
title = _properties.get_title();
}
// I'd prefer to CreateWindow after DisplayChange in case it messes
// up GL somehow, but I need the window's black background to cover
// up the desktop during the mode change
const WindowClass &wclass = register_window_class(_properties);
HINSTANCE hinstance = GetModuleHandle(NULL);
_hWnd = CreateWindow(wclass._name.c_str(), title.c_str(), window_style,
0, 0, dwWidth, dwHeight,
hDesktopWindow, NULL, hinstance, 0);
if (!_hWnd) {
windisplay_cat.error()
<< "CreateWindow() failed!" << endl;
show_error_message();
return false;
}
int chg_result = ChangeDisplaySettings(&_fullscreen_display_mode,
CDS_FULLSCREEN);
if (chg_result != DISP_CHANGE_SUCCESSFUL) {
windisplay_cat.error()
<< "ChangeDisplaySettings failed (error code: "
<< chg_result << ") for specified res (" << dwWidth
<< " x " << dwHeight << " x " << dwFullScreenBitDepth
<< "), " << _fullscreen_display_mode.dmDisplayFrequency << "Hz\n";
return false;
}
_properties.set_origin(0, 0);
_properties.set_size(dwWidth, dwHeight);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::open_regular_window
// Access: Private
// Description: Creates a non-fullscreen window, on the desktop.
////////////////////////////////////////////////////////////////////
bool WinGraphicsWindow::
open_regular_window() {
open_graphic_window(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
@ -837,7 +748,9 @@ open_regular_window() {
DWORD window_style =
WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
if (!_properties.get_undecorated()) {
if (fullscreen){
window_style |= WS_SYSMENU;
} else if (!_properties.get_undecorated()) {
window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
if (!_properties.get_fixed_size()) {
@ -846,44 +759,52 @@ open_regular_window() {
window_style |= WS_BORDER;
}
}
int x_origin = 0;
int y_origin = 0;
if (_properties.has_origin()) {
x_origin = _properties.get_x_origin();
y_origin = _properties.get_y_origin();
}
int x_size = 100;
int y_size = 100;
if (_properties.has_size()) {
x_size = _properties.get_x_size();
y_size = _properties.get_y_size();
}
RECT win_rect;
SetRect(&win_rect, x_origin, y_origin,
x_origin + x_size, y_origin + y_size);
// compute window size based on desired client area size
if (!AdjustWindowRect(&win_rect, window_style, FALSE)) {
windisplay_cat.error()
<< "AdjustWindowRect failed!" << endl;
return false;
}
string title;
if (_properties.has_title()) {
title = _properties.get_title();
}
if (_properties.has_origin()) {
x_origin = win_rect.left;
y_origin = win_rect.top;
if (!_properties.has_size()) {
//Just pick a conservative default size if one isn't specified.
_properties.set_size(640, 480);
}
} else {
x_origin = CW_USEDEFAULT;
y_origin = CW_USEDEFAULT;
int x_origin = 0;
int y_origin = 0;
if (!fullscreen && _properties.has_origin()) {
x_origin = _properties.get_x_origin();
y_origin = _properties.get_y_origin();
}
int x_size = _properties.get_x_size();
int y_size = _properties.get_y_size();
int clientAreaWidth = x_size;
int clientAreaHeight = y_size;
if (!fullscreen){
RECT win_rect;
SetRect(&win_rect, x_origin, y_origin,
x_origin + x_size, y_origin + y_size);
// compute window size based on desired client area size
if (!AdjustWindowRect(&win_rect, window_style, FALSE)) {
windisplay_cat.error()
<< "AdjustWindowRect failed!" << endl;
return false;
}
if (_properties.has_origin()) {
x_origin = win_rect.left;
y_origin = win_rect.top;
} else {
x_origin = CW_USEDEFAULT;
y_origin = CW_USEDEFAULT;
}
clientAreaWidth = win_rect.right - win_rect.left;
clientAreaHeight = win_rect.bottom - win_rect.top;
}
const WindowClass &wclass = register_window_class(_properties);
@ -891,38 +812,41 @@ open_regular_window() {
_hparent = NULL;
WindowHandle *window_handle = _properties.get_parent_window();
if (window_handle != NULL) {
windisplay_cat.info()
<< "Got parent_window " << *window_handle << "\n";
WindowHandle::OSHandle *os_handle = window_handle->get_os_handle();
if (os_handle != NULL) {
if (!fullscreen){
WindowHandle *window_handle = _properties.get_parent_window();
if (window_handle != NULL) {
windisplay_cat.info()
<< "os_handle type " << os_handle->get_type() << "\n";
if (os_handle->is_of_type(NativeWindowHandle::WinHandle::get_class_type())) {
NativeWindowHandle::WinHandle *win_handle = DCAST(NativeWindowHandle::WinHandle, os_handle);
_hparent = win_handle->get_handle();
} else if (os_handle->is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
NativeWindowHandle::IntHandle *int_handle = DCAST(NativeWindowHandle::IntHandle, os_handle);
_hparent = (HWND)int_handle->get_handle();
<< "Got parent_window " << *window_handle << "\n";
WindowHandle::OSHandle *os_handle = window_handle->get_os_handle();
if (os_handle != NULL) {
windisplay_cat.info()
<< "os_handle type " << os_handle->get_type() << "\n";
if (os_handle->is_of_type(NativeWindowHandle::WinHandle::get_class_type())) {
NativeWindowHandle::WinHandle *win_handle = DCAST(NativeWindowHandle::WinHandle, os_handle);
_hparent = win_handle->get_handle();
} else if (os_handle->is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
NativeWindowHandle::IntHandle *int_handle = DCAST(NativeWindowHandle::IntHandle, os_handle);
_hparent = (HWND)int_handle->get_handle();
}
}
}
_parent_window_handle = window_handle;
} else {
_parent_window_handle = NULL;
}
_parent_window_handle = window_handle;
if (!_hparent) {
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,
win_rect.right - win_rect.left,
win_rect.bottom - win_rect.top,
clientAreaWidth,
clientAreaHeight,
NULL, NULL, hinstance, 0);
} else {
} else { // This is a regular window with a parent
x_origin = 0;
y_origin = 0;
if (_properties.has_origin()) {
if (!fullscreen && _properties.has_origin()) {
x_origin = _properties.get_x_origin();
y_origin = _properties.get_y_origin();
}
@ -954,6 +878,51 @@ open_regular_window() {
return false;
}
// I'd prefer to CreateWindow after DisplayChange in case it messes
// up GL somehow, but I need the window's black background to cover
// up the desktop during the mode change.
if (fullscreen){
HWND hDesktopWindow = GetDesktopWindow();
HDC scrnDC = GetDC(hDesktopWindow);
DWORD cur_bitdepth = GetDeviceCaps(scrnDC, BITSPIXEL);
// DWORD drvr_ver = GetDeviceCaps(scrnDC, DRIVERVERSION);
// DWORD cur_scrnwidth = GetDeviceCaps(scrnDC, HORZRES);
// DWORD cur_scrnheight = GetDeviceCaps(scrnDC, VERTRES);
ReleaseDC(hDesktopWindow, scrnDC);
DWORD dwWidth = _properties.get_x_size();
DWORD dwHeight = _properties.get_y_size();
DWORD dwFullScreenBitDepth = cur_bitdepth;
DEVMODE dm;
reconsider_fullscreen_size(dwWidth, dwHeight, dwFullScreenBitDepth);
if (!find_acceptable_display_mode(dwWidth, dwHeight, dwFullScreenBitDepth, dm)) {
windisplay_cat.error()
<< "Videocard has no supported display resolutions at specified res ("
<< dwWidth << " x " << dwHeight << " x " << dwFullScreenBitDepth <<")\n";
return false;
}
dm.dmPelsWidth = dwWidth;
dm.dmPelsHeight = dwHeight;
dm.dmBitsPerPel = dwFullScreenBitDepth;
int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
if (chg_result != DISP_CHANGE_SUCCESSFUL) {
windisplay_cat.error()
<< "ChangeDisplaySettings failed (error code: "
<< chg_result << ") for specified res (" << dwWidth
<< " x " << dwHeight << " x " << dwFullScreenBitDepth
<< "), " << _fullscreen_display_mode.dmDisplayFrequency << "Hz\n";
return false;
}
_properties.set_origin(0, 0);
_properties.set_size(dwWidth, dwHeight);
}
return true;
}
@ -2165,7 +2134,21 @@ find_acceptable_display_mode(DWORD dwWidth, DWORD dwHeight, DWORD bpp,
if ((dm.dmPelsWidth == dwWidth) && (dm.dmPelsHeight == dwHeight) &&
(dm.dmBitsPerPel == bpp)) {
return true;
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));
dm.dmSize = sizeof(dm);
if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)){
dm.dmPelsWidth = dwWidth;
dm.dmPelsHeight = dwHeight;
dm.dmBitsPerPel = bpp;
return true;
} else {
windisplay_cat.error()
<< "Couldn't retrieve active device mode.\n";
return false;
}
}
modenum++;
}

View File

@ -89,8 +89,7 @@ protected:
virtual void support_overlay_window(bool flag);
private:
bool open_fullscreen_window();
bool open_regular_window();
bool open_graphic_window(bool fullscreen);
void adjust_z_order();
void adjust_z_order(WindowProperties::ZOrder last_z_order,
WindowProperties::ZOrder this_z_order);