Changeset - r24878:fb3a0559b42f
[Not reviewed]
master
0 2 0
Michael Lutz - 3 years ago 2021-01-16 15:43:03
michi@icosahedron.de
Codechange: [Win32] Move common initialization and finalization to the video driver base class.
2 files changed with 49 insertions and 39 deletions:
0 comments (0 inline, 0 general)
src/video/win32_v.cpp
Show inline comments
 
@@ -37,25 +37,24 @@
 
#endif
 

	
 
#ifndef PM_QS_INPUT
 
#define PM_QS_INPUT 0x20000
 
#endif
 

	
 
static struct {
 
	void *buffer_bits;    ///< Internal rendering buffer.
 
	int width;            ///< Width in pixels of our display surface.
 
	int height;           ///< Height in pixels of our display surface.
 
	int width_org;        ///< Original monitor resolution width, before we changed it.
 
	int height_org;       ///< Original monitor resolution height, before we changed it.
 
	bool fullscreen;      ///< Whether to use (true) fullscreen mode.
 
	bool has_focus;       ///< Does our window have system focus?
 
	bool running;         ///< Is the main loop running?
 
} _wnd;
 

	
 
bool _window_maximize;
 
static Dimension _bck_resolution;
 
DWORD _imm_props;
 

	
 
/** Whether the drawing is/may be done in a separate thread. */
 
static bool _draw_threaded;
 
/** Mutex to keep the access to the shared memory controlled. */
 
static std::recursive_mutex *_draw_mutex = nullptr;
 
@@ -133,91 +132,97 @@ static uint MapWindowsKey(uint sym)
 
		if ((uint)(sym - map->vk_from) <= map->vk_count) {
 
			key = sym - map->vk_from + map->map_to;
 
			break;
 
		}
 
	}
 

	
 
	if (GetAsyncKeyState(VK_SHIFT)   < 0) key |= WKC_SHIFT;
 
	if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL;
 
	if (GetAsyncKeyState(VK_MENU)    < 0) key |= WKC_ALT;
 
	return key;
 
}
 

	
 
/** Colour depth to use for fullscreen display modes. */
 
uint8 VideoDriver_Win32Base::GetFullscreenBpp()
 
{
 
	/* Check modes for the relevant fullscreen bpp */
 
	return _support8bpp != S8BPP_HARDWARE ? 32 : BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
 
}
 

	
 
/**
 
 * Instantiate a new window.
 
 * @param full_screen Whether to make a full screen window or not.
 
 * @return True if the window could be created.
 
 */
 
bool VideoDriver_Win32Base::MakeWindow(bool full_screen)
 
{
 
	/* full_screen is whether the new window should be fullscreen,
 
	 * _wnd.fullscreen is whether the current window is. */
 
	_fullscreen = full_screen;
 

	
 
	/* recreate window? */
 
	if ((full_screen || _wnd.fullscreen) && this->main_wnd) {
 
	if ((full_screen || this->fullscreen) && this->main_wnd) {
 
		DestroyWindow(this->main_wnd);
 
		this->main_wnd = 0;
 
	}
 

	
 
	if (full_screen) {
 
		DEVMODE settings;
 

	
 
		memset(&settings, 0, sizeof(settings));
 
		settings.dmSize = sizeof(settings);
 
		settings.dmFields =
 
			DM_BITSPERPEL |
 
			DM_PELSWIDTH |
 
			DM_PELSHEIGHT;
 
		settings.dmBitsPerPel = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
 
		settings.dmBitsPerPel = this->GetFullscreenBpp();
 
		settings.dmPelsWidth  = _wnd.width_org;
 
		settings.dmPelsHeight = _wnd.height_org;
 

	
 
		/* Check for 8 bpp support. */
 
		if (settings.dmBitsPerPel == 8 &&
 
				(_support8bpp != S8BPP_HARDWARE || ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)) {
 
		if (settings.dmBitsPerPel == 8 && ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
 
			settings.dmBitsPerPel = 32;
 
		}
 

	
 
		/* Test fullscreen with current resolution, if it fails use desktop resolution. */
 
		if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
 
			RECT r;
 
			GetWindowRect(GetDesktopWindow(), &r);
 
			/* Guard against recursion. If we already failed here once, just fall through to
 
			 * the next ChangeDisplaySettings call which will fail and error out appropriately. */
 
			if ((int)settings.dmPelsWidth != r.right - r.left || (int)settings.dmPelsHeight != r.bottom - r.top) {
 
				return this->ChangeResolution(r.right - r.left, r.bottom - r.top);
 
			}
 
		}
 

	
 
		if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
 
			this->MakeWindow(false);  // don't care about the result
 
			return false;  // the request failed
 
		}
 
	} else if (_wnd.fullscreen) {
 
	} else if (this->fullscreen) {
 
		/* restore display? */
 
		ChangeDisplaySettings(nullptr, 0);
 
		/* restore the resolution */
 
		_wnd.width = _bck_resolution.width;
 
		_wnd.height = _bck_resolution.height;
 
	}
 

	
 
	{
 
		RECT r;
 
		DWORD style, showstyle;
 
		int w, h;
 

	
 
		showstyle = SW_SHOWNORMAL;
 
		_wnd.fullscreen = full_screen;
 
		if (_wnd.fullscreen) {
 
		this->fullscreen = full_screen;
 
		if (this->fullscreen) {
 
			style = WS_POPUP;
 
			SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org);
 
		} else {
 
			style = WS_OVERLAPPEDWINDOW;
 
			/* On window creation, check if we were in maximize mode before */
 
			if (_window_maximize) showstyle = SW_SHOWMAXIMIZED;
 
			SetRect(&r, 0, 0, _wnd.width, _wnd.height);
 
		}
 

	
 
		AdjustWindowRect(&r, style, FALSE);
 
		w = r.right - r.left;
 
		h = r.bottom - r.top;
 
@@ -652,25 +657,25 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, U
 
			/* IMEs and other input methods sometimes send a WM_CHAR without a WM_KEYDOWN,
 
			 * clear the keycode so a previous WM_KEYDOWN doesn't become 'stuck'. */
 
			uint cur_keycode = keycode;
 
			keycode = 0;
 

	
 
			return HandleCharMsg(cur_keycode, LOWORD(charcode));
 
		}
 

	
 
		case WM_SYSKEYDOWN: // user presses F10 or Alt, both activating the title-menu
 
			switch (wParam) {
 
				case VK_RETURN:
 
				case 'F': // Full Screen on ALT + ENTER/F
 
					ToggleFullScreen(!_wnd.fullscreen);
 
					ToggleFullScreen(!video_driver->fullscreen);
 
					return 0;
 

	
 
				case VK_MENU: // Just ALT
 
					return 0; // do nothing
 

	
 
				case VK_F10: // F10, ignore activation of menu
 
					HandleKeypress(MapWindowsKey(wParam), 0);
 
					return 0;
 

	
 
				default: // ALT in combination with something else
 
					HandleKeypress(MapWindowsKey(wParam), 0);
 
					break;
 
@@ -771,25 +776,25 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, U
 
			break;
 

	
 
		case WM_KILLFOCUS:
 
			_wnd.has_focus = false;
 
			break;
 

	
 
		case WM_ACTIVATE: {
 
			/* Don't do anything if we are closing openttd */
 
			if (_exit_game) break;
 

	
 
			bool active = (LOWORD(wParam) != WA_INACTIVE);
 
			bool minimized = (HIWORD(wParam) != 0);
 
			if (_wnd.fullscreen) {
 
			if (video_driver->fullscreen) {
 
				if (active && minimized) {
 
					/* Restore the game window */
 
					ShowWindow(hwnd, SW_RESTORE);
 
					video_driver->MakeWindow(true);
 
				} else if (!active && !minimized) {
 
					/* Minimise the window and restore desktop */
 
					ShowWindow(hwnd, SW_MINIMIZE);
 
					ChangeDisplaySettings(nullptr, 0);
 
				}
 
			}
 
			break;
 
		}
 
@@ -827,51 +832,66 @@ static const Dimension default_resolutio
 
	{  800,  600 },
 
	{ 1024,  768 },
 
	{ 1152,  864 },
 
	{ 1280,  800 },
 
	{ 1280,  960 },
 
	{ 1280, 1024 },
 
	{ 1400, 1050 },
 
	{ 1600, 1200 },
 
	{ 1680, 1050 },
 
	{ 1920, 1200 }
 
};
 

	
 
static void FindResolutions()
 
static void FindResolutions(uint8 bpp)
 
{
 
	uint i;
 
	DEVMODEA dm;
 

	
 
	/* Check modes for the relevant fullscreen bpp */
 
	uint bpp = _support8bpp != S8BPP_HARDWARE ? 32 : BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
 

	
 
	_resolutions.clear();
 

	
 
	/* XXX - EnumDisplaySettingsW crashes with unicows.dll on Windows95
 
	 * Doesn't really matter since we don't pass a string anyways, but still
 
	 * a letdown */
 
	for (i = 0; EnumDisplaySettingsA(nullptr, i, &dm) != 0; i++) {
 
	DEVMODE dm;
 
	for (uint i = 0; EnumDisplaySettings(nullptr, i, &dm) != 0; i++) {
 
		if (dm.dmBitsPerPel != bpp || dm.dmPelsWidth < 640 || dm.dmPelsHeight < 480) continue;
 
		if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(dm.dmPelsWidth, dm.dmPelsHeight)) != _resolutions.end()) continue;
 
		_resolutions.emplace_back(dm.dmPelsWidth, dm.dmPelsHeight);
 
	}
 

	
 
	/* We have found no resolutions, show the default list */
 
	if (_resolutions.empty()) {
 
		_resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions));
 
	}
 

	
 
	SortResolutions();
 
}
 

	
 
void VideoDriver_Win32Base::Initialize()
 
{
 
	this->UpdateAutoResolution();
 

	
 
	memset(&_wnd, 0, sizeof(_wnd));
 

	
 
	RegisterWndClass();
 
	FindResolutions(this->GetFullscreenBpp());
 

	
 
	/* fullscreen uses those */
 
	_wnd.width  = _wnd.width_org  = _cur_resolution.width;
 
	_wnd.height = _wnd.height_org = _cur_resolution.height;
 

	
 
	DEBUG(driver, 2, "Resolution for display: %ux%u", _cur_resolution.width, _cur_resolution.height);
 
}
 

	
 
void VideoDriver_Win32Base::Stop()
 
{
 
	DestroyWindow(this->main_wnd);
 

	
 
	if (this->fullscreen) ChangeDisplaySettings(nullptr, 0);
 
	MyShowCursor(true);
 
}
 
void VideoDriver_Win32Base::MakeDirty(int left, int top, int width, int height)
 
{
 
	Rect r = {left, top, left + width, top + height};
 
	_dirty_rect = BoundingRect(_dirty_rect, r);
 
}
 

	
 
void VideoDriver_Win32Base::CheckPaletteAnim()
 
{
 
	if (_cur_palette.count_dirty == 0) return;
 

	
 
	_local_palette = _cur_palette;
 
	this->MakeDirty(0, 0, _screen.width, _screen.height);
 
@@ -1100,58 +1120,43 @@ bool VideoDriver_Win32Base::LockVideoBuf
 
void VideoDriver_Win32Base::UnlockVideoBuffer()
 
{
 
	if (_draw_threaded) this->draw_lock.unlock();
 
}
 

	
 

	
 
static FVideoDriver_Win32GDI iFVideoDriver_Win32GDI;
 

	
 
const char *VideoDriver_Win32GDI::Start(const StringList &param)
 
{
 
	if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) return "Only real blitters supported";
 

	
 
	this->UpdateAutoResolution();
 

	
 
	memset(&_wnd, 0, sizeof(_wnd));
 

	
 
	RegisterWndClass();
 
	this->Initialize();
 

	
 
	this->MakePalette();
 

	
 
	FindResolutions();
 

	
 
	DEBUG(driver, 2, "Resolution for display: %ux%u", _cur_resolution.width, _cur_resolution.height);
 

	
 
	/* fullscreen uses those */
 
	_wnd.width_org = _cur_resolution.width;
 
	_wnd.height_org = _cur_resolution.height;
 

	
 
	this->AllocateBackingStore(_cur_resolution.width, _cur_resolution.height);
 
	this->MakeWindow(_fullscreen);
 

	
 
	MarkWholeScreenDirty();
 

	
 
	_draw_threaded = !GetDriverParam(param, "no_threads") && !GetDriverParam(param, "no_thread") && std::thread::hardware_concurrency() > 1;
 

	
 
	return nullptr;
 
}
 

	
 
void VideoDriver_Win32GDI::Stop()
 
{
 
	DeleteObject(this->gdi_palette);
 
	DeleteObject(this->dib_sect);
 
	DestroyWindow(this->main_wnd);
 

	
 
	if (_wnd.fullscreen) ChangeDisplaySettings(nullptr, 0);
 
	MyShowCursor(true);
 
	this->VideoDriver_Win32Base::Stop();
 
}
 

	
 
bool VideoDriver_Win32GDI::AllocateBackingStore(int w, int h, bool force)
 
{
 
	uint bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
 

	
 
	w = std::max(w, 64);
 
	h = std::max(h, 64);
 

	
 
	if (!force && w == _screen.width && h == _screen.height) return false;
 

	
 
	BITMAPINFO *bi = (BITMAPINFO *)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
src/video/win32_v.h
Show inline comments
 
@@ -6,53 +6,58 @@
 
 */
 

	
 
/** @file win32_v.h Base of the Windows video driver. */
 

	
 
#ifndef VIDEO_WIN32_H
 
#define VIDEO_WIN32_H
 

	
 
#include "video_driver.hpp"
 

	
 
/** Base class for Windows video drivers. */
 
class VideoDriver_Win32Base : public VideoDriver {
 
public:
 
	VideoDriver_Win32Base() : main_wnd(nullptr) {}
 
	VideoDriver_Win32Base() : main_wnd(nullptr), fullscreen(false) {}
 

	
 
	void Stop() override;
 

	
 
	void MakeDirty(int left, int top, int width, int height) override;
 

	
 
	void MainLoop() override;
 

	
 
	bool ChangeResolution(int w, int h) override;
 

	
 
	bool ToggleFullscreen(bool fullscreen) override;
 

	
 
	void AcquireBlitterLock() override;
 

	
 
	void ReleaseBlitterLock() override;
 

	
 
	bool ClaimMousePointer() override;
 

	
 
	void EditBoxLostFocus() override;
 

	
 
protected:
 
	HWND    main_wnd;      ///< Handle to system window.
 
	bool    fullscreen;    ///< Whether to use (true) fullscreen mode.
 

	
 
	Dimension GetScreenSize() const override;
 
	float GetDPIScale() override;
 
	void InputLoop() override;
 
	bool LockVideoBuffer() override;
 
	void UnlockVideoBuffer() override;
 
	void CheckPaletteAnim() override;
 

	
 
	void Initialize();
 
	bool MakeWindow(bool full_screen);
 
	virtual uint8 GetFullscreenBpp();
 

	
 
	/** (Re-)create the backing store. */
 
	virtual bool AllocateBackingStore(int w, int h, bool force = false) = 0;
 
	/** Palette of the window has changed. */
 
	virtual void PaletteChanged(HWND hWnd) = 0;
 

	
 
private:
 
	std::unique_lock<std::recursive_mutex> draw_lock;
 

	
 
	void ClientSizeChanged(int w, int h);
 

	
 
	static void PaintThreadThunk(VideoDriver_Win32Base *drv);
0 comments (0 inline, 0 general)